All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] Add initial support for DA9150 Charger & Fuel-Gauge IC
@ 2014-08-28 10:48 ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

This patch set adds initial support for the Dialog DA9150 Integrated Charger &
Fuel-Gauge IC. The device also provides GPIO and GPADC functionality.

In this patch set the following is provided:
 - MFD Core support and DT bindings documentation.
 - IIO GPADC support and DT bindings documentation.
 - Power Supply Charger support and DT bindings documentation.
 - Update to MAINTAINERS file to add DA9150 files to Dialog support list.

To keep patch submission from being too large, support for GPIO and Fuel-Gauge
will come after initial support patches are accepted.

This patch set is baselined against the v3.17-rc2 kernel version.


Changes in v2:
 - Drop devicetree prefix patch as this is being dealt with separately.
 - IIO framework fix patch removed from set, has already been accepted/merged.
 - Use __ instead of _ for protecting #ifdefs in headers.
 - Moved private data & definitions to source files and remove unwanted headers.
 - Bug fix to EXPORT_SYMBOL for common functions in MFD core used by
   sub-devices, so they can be correctly built as kernel modules.
 - Removed unnecessary channels from GPADC IIO driver to simplify code.
 - For GPADC IIO driver, VBAT reading now provides scale and offset values as it
   is a linear scale.
 - GPADC read code refactored to make it tidier.
 - Remove use of flag to indicate GPADC availability. IIO framework should
   indicate need to defer if it's not yet instantiated.
 - Unwanted comments removed.
 - Removed conditional shutdown of device (Charger/MFD) as this is not needed.
 - Removed AC type supply from charger as device cannot differentiate. Now just
   uses USB supply type.
 - Removed use of invalid-tbat flag from platform data as it doesn't really add
   anything to the driver except forcing battery present status.
 - Bug fix for checking of usb_phy validity in Charger probe() function.
 - Addition of common IRQ release function to allow sub-devices to explicitly
   tidy up IRQs when devm clean up is too late.
 - Improved tidy up of resources in charger.
 - Fix location of IIO GPADC related devicetree binding document so it now
   resides correctly under 'adc' directory.
 - Add update to MAINTAINERS file to include these files in Dialog support list.

Adam Thomson (7):
  mfd: Add support for DA9150 combined charger & fuel-gauge device
  mfd: da9150: Add DT binding documentation for core
  iio: Add support for DA9150 GPADC
  iio: da9150: Add DT binding documentation for GPADC
  power: Add support for DA9150 Charger
  power: da9150: Add DT binding documentation for charger
  MAINTAINERS: Include DA9150 files in Dialog Semiconductor support
    list.

 .../devicetree/bindings/iio/adc/da9150-gpadc.txt   |   16 +
 Documentation/devicetree/bindings/mfd/da9150.txt   |   41 +
 .../devicetree/bindings/power/da9150-charger.txt   |   26 +
 MAINTAINERS                                        |    4 +
 drivers/iio/adc/Kconfig                            |    9 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/da9150-gpadc.c                     |  430 ++++++++
 drivers/mfd/Kconfig                                |   12 +
 drivers/mfd/Makefile                               |    2 +
 drivers/mfd/da9150-core.c                          |  332 ++++++
 drivers/mfd/da9150-i2c.c                           |  176 +++
 drivers/power/Kconfig                              |   12 +
 drivers/power/Makefile                             |    1 +
 drivers/power/da9150-charger.c                     |  715 ++++++++++++
 include/linux/mfd/da9150/core.h                    |   80 ++
 include/linux/mfd/da9150/pdata.h                   |   21 +
 include/linux/mfd/da9150/registers.h               | 1153 ++++++++++++++++++++
 17 files changed, 3031 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/da9150.txt
 create mode 100644 Documentation/devicetree/bindings/power/da9150-charger.txt
 create mode 100644 drivers/iio/adc/da9150-gpadc.c
 create mode 100644 drivers/mfd/da9150-core.c
 create mode 100644 drivers/mfd/da9150-i2c.c
 create mode 100644 drivers/power/da9150-charger.c
 create mode 100644 include/linux/mfd/da9150/core.h
 create mode 100644 include/linux/mfd/da9150/pdata.h
 create mode 100644 include/linux/mfd/da9150/registers.h

--
1.9.3


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

* [PATCH v2 0/7] Add initial support for DA9150 Charger & Fuel-Gauge IC
@ 2014-08-28 10:48 ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

This patch set adds initial support for the Dialog DA9150 Integrated Charger &
Fuel-Gauge IC. The device also provides GPIO and GPADC functionality.

In this patch set the following is provided:
 - MFD Core support and DT bindings documentation.
 - IIO GPADC support and DT bindings documentation.
 - Power Supply Charger support and DT bindings documentation.
 - Update to MAINTAINERS file to add DA9150 files to Dialog support list.

To keep patch submission from being too large, support for GPIO and Fuel-Gauge
will come after initial support patches are accepted.

This patch set is baselined against the v3.17-rc2 kernel version.


Changes in v2:
 - Drop devicetree prefix patch as this is being dealt with separately.
 - IIO framework fix patch removed from set, has already been accepted/merged.
 - Use __ instead of _ for protecting #ifdefs in headers.
 - Moved private data & definitions to source files and remove unwanted headers.
 - Bug fix to EXPORT_SYMBOL for common functions in MFD core used by
   sub-devices, so they can be correctly built as kernel modules.
 - Removed unnecessary channels from GPADC IIO driver to simplify code.
 - For GPADC IIO driver, VBAT reading now provides scale and offset values as it
   is a linear scale.
 - GPADC read code refactored to make it tidier.
 - Remove use of flag to indicate GPADC availability. IIO framework should
   indicate need to defer if it's not yet instantiated.
 - Unwanted comments removed.
 - Removed conditional shutdown of device (Charger/MFD) as this is not needed.
 - Removed AC type supply from charger as device cannot differentiate. Now just
   uses USB supply type.
 - Removed use of invalid-tbat flag from platform data as it doesn't really add
   anything to the driver except forcing battery present status.
 - Bug fix for checking of usb_phy validity in Charger probe() function.
 - Addition of common IRQ release function to allow sub-devices to explicitly
   tidy up IRQs when devm clean up is too late.
 - Improved tidy up of resources in charger.
 - Fix location of IIO GPADC related devicetree binding document so it now
   resides correctly under 'adc' directory.
 - Add update to MAINTAINERS file to include these files in Dialog support list.

Adam Thomson (7):
  mfd: Add support for DA9150 combined charger & fuel-gauge device
  mfd: da9150: Add DT binding documentation for core
  iio: Add support for DA9150 GPADC
  iio: da9150: Add DT binding documentation for GPADC
  power: Add support for DA9150 Charger
  power: da9150: Add DT binding documentation for charger
  MAINTAINERS: Include DA9150 files in Dialog Semiconductor support
    list.

 .../devicetree/bindings/iio/adc/da9150-gpadc.txt   |   16 +
 Documentation/devicetree/bindings/mfd/da9150.txt   |   41 +
 .../devicetree/bindings/power/da9150-charger.txt   |   26 +
 MAINTAINERS                                        |    4 +
 drivers/iio/adc/Kconfig                            |    9 +
 drivers/iio/adc/Makefile                           |    1 +
 drivers/iio/adc/da9150-gpadc.c                     |  430 ++++++++
 drivers/mfd/Kconfig                                |   12 +
 drivers/mfd/Makefile                               |    2 +
 drivers/mfd/da9150-core.c                          |  332 ++++++
 drivers/mfd/da9150-i2c.c                           |  176 +++
 drivers/power/Kconfig                              |   12 +
 drivers/power/Makefile                             |    1 +
 drivers/power/da9150-charger.c                     |  715 ++++++++++++
 include/linux/mfd/da9150/core.h                    |   80 ++
 include/linux/mfd/da9150/pdata.h                   |   21 +
 include/linux/mfd/da9150/registers.h               | 1153 ++++++++++++++++++++
 17 files changed, 3031 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/da9150.txt
 create mode 100644 Documentation/devicetree/bindings/power/da9150-charger.txt
 create mode 100644 drivers/iio/adc/da9150-gpadc.c
 create mode 100644 drivers/mfd/da9150-core.c
 create mode 100644 drivers/mfd/da9150-i2c.c
 create mode 100644 drivers/power/da9150-charger.c
 create mode 100644 include/linux/mfd/da9150/core.h
 create mode 100644 include/linux/mfd/da9150/pdata.h
 create mode 100644 include/linux/mfd/da9150/registers.h

--
1.9.3


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

* [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-08-28 10:48 ` Adam Thomson
@ 2014-08-28 10:48   ` Adam Thomson
  -1 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

DA9150 is a combined Charger and Fuel-Gauge IC, with additional
GPIO and GPADC functionality.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 drivers/mfd/Kconfig                  |   12 +
 drivers/mfd/Makefile                 |    2 +
 drivers/mfd/da9150-core.c            |  332 ++++++++++
 drivers/mfd/da9150-i2c.c             |  176 ++++++
 include/linux/mfd/da9150/core.h      |   80 +++
 include/linux/mfd/da9150/pdata.h     |   21 +
 include/linux/mfd/da9150/registers.h | 1153 ++++++++++++++++++++++++++++++++++
 7 files changed, 1776 insertions(+)
 create mode 100644 drivers/mfd/da9150-core.c
 create mode 100644 drivers/mfd/da9150-i2c.c
 create mode 100644 include/linux/mfd/da9150/core.h
 create mode 100644 include/linux/mfd/da9150/pdata.h
 create mode 100644 include/linux/mfd/da9150/registers.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index de5abf2..76adb2c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -183,6 +183,18 @@ config MFD_DA9063
 	  Additional drivers must be enabled in order to use the functionality
 	  of the device.

+config MFD_DA9150
+	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
+	depends on I2C=y
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	help
+	  This adds support for the DA9150 integrated charger and fuel-gauge
+	  chip. This driver provides common support for accessing the device.
+	  Additional drivers must be enabled in order to use the specific
+	  features of the device.
+
 config MFD_MC13XXX
 	tristate
 	depends on (SPI_MASTER || I2C)
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f001487..098dfa1 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
 da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
 obj-$(CONFIG_MFD_DA9063)	+= da9063.o

+obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
+
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
 obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
new file mode 100644
index 0000000..029a30b
--- /dev/null
+++ b/drivers/mfd/da9150-core.c
@@ -0,0 +1,332 @@
+/*
+ * DA9150 Core MFD Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/registers.h>
+#include <linux/mfd/da9150/pdata.h>
+
+u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
+{
+	int val, ret;
+
+	ret = regmap_read(da9150->regmap, reg, &val);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
+			reg, ret);
+
+	return (u8) val;
+}
+EXPORT_SYMBOL_GPL(da9150_reg_read);
+
+int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
+{
+	int ret;
+
+	ret = regmap_write(da9150->regmap, reg, val);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_reg_write);
+
+int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
+{
+	int ret;
+
+	ret = regmap_update_bits(da9150->regmap, reg, mask, val);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_set_bits);
+
+int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
+{
+	int ret;
+
+	ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_bulk_read);
+
+int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
+{
+	int ret;
+
+	ret = regmap_raw_write(da9150->regmap, reg, buf, count);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_bulk_write);
+
+static struct regmap_irq da9150_irqs[] = {
+	[DA9150_IRQ_VBUS] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_VBUS_MASK,
+	},
+	[DA9150_IRQ_CHG] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_CHG_MASK,
+	},
+	[DA9150_IRQ_TCLASS] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_TCLASS_MASK,
+	},
+	[DA9150_IRQ_TJUNC] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_TJUNC_MASK,
+	},
+	[DA9150_IRQ_VFAULT] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_VFAULT_MASK,
+	},
+	[DA9150_IRQ_CONF] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_CONF_MASK,
+	},
+	[DA9150_IRQ_DAT] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_DAT_MASK,
+	},
+	[DA9150_IRQ_DTYPE] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_DTYPE_MASK,
+	},
+	[DA9150_IRQ_ID] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_ID_MASK,
+	},
+	[DA9150_IRQ_ADP] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_ADP_MASK,
+	},
+	[DA9150_IRQ_SESS_END] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_SESS_END_MASK,
+	},
+	[DA9150_IRQ_SESS_VLD] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_SESS_VLD_MASK,
+	},
+	[DA9150_IRQ_FG] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_FG_MASK,
+	},
+	[DA9150_IRQ_GP] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GP_MASK,
+	},
+	[DA9150_IRQ_TBAT] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_TBAT_MASK,
+	},
+	[DA9150_IRQ_GPIOA] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOA_MASK,
+	},
+	[DA9150_IRQ_GPIOB] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOB_MASK,
+	},
+	[DA9150_IRQ_GPIOC] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOC_MASK,
+	},
+	[DA9150_IRQ_GPIOD] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOD_MASK,
+	},
+	[DA9150_IRQ_GPADC] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPADC_MASK,
+	},
+	[DA9150_IRQ_WKUP] = {
+		.reg_offset = 3,
+		.mask = DA9150_E_WKUP_MASK,
+	},
+};
+
+static struct regmap_irq_chip da9150_regmap_irq_chip = {
+	.name = "da9150_irq",
+	.status_base = DA9150_EVENT_E,
+	.mask_base = DA9150_IRQ_MASK_E,
+	.ack_base = DA9150_EVENT_E,
+	.num_regs = DA9150_NUM_IRQ_REGS,
+	.irqs = da9150_irqs,
+	.num_irqs = ARRAY_SIZE(da9150_irqs),
+};
+
+/* Helper functions for sub-devices to request/free IRQs */
+int da9150_register_irq(struct platform_device *pdev, void *dev_id,
+			irq_handler_t handler, const char *name)
+{
+	int irq, ret;
+
+	irq = platform_get_irq_byname(pdev, name);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
+					IRQF_ONESHOT, name, dev_id);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_register_irq);
+
+void da9150_release_irq(struct platform_device *pdev, void *dev_id,
+		       const char *name)
+{
+	int irq;
+
+	irq = platform_get_irq_byname(pdev, name);
+	if (irq < 0)
+		return;
+
+	devm_free_irq(&pdev->dev, irq, dev_id);
+}
+EXPORT_SYMBOL_GPL(da9150_release_irq);
+
+static struct resource da9150_gpadc_resources[] = {
+	{
+		.name = "GPADC",
+		.start = DA9150_IRQ_GPADC,
+		.end = DA9150_IRQ_GPADC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource da9150_charger_resources[] = {
+	{
+		.name = "CHG_STATUS",
+		.start = DA9150_IRQ_CHG,
+		.end = DA9150_IRQ_CHG,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "CHG_TJUNC",
+		.start = DA9150_IRQ_TJUNC,
+		.end = DA9150_IRQ_TJUNC,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "CHG_VFAULT",
+		.start = DA9150_IRQ_VFAULT,
+		.end = DA9150_IRQ_VFAULT,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "CHG_VBUS",
+		.start = DA9150_IRQ_VBUS,
+		.end = DA9150_IRQ_VBUS,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell da9150_devs[] = {
+	{
+		.name = "da9150-gpadc",
+		.of_compatible = "dlg,da9150-gpadc",
+		.resources = da9150_gpadc_resources,
+		.num_resources = ARRAY_SIZE(da9150_gpadc_resources),
+	},
+	{
+		.name = "da9150-charger",
+		.of_compatible = "dlg,da9150-charger",
+		.resources = da9150_charger_resources,
+		.num_resources = ARRAY_SIZE(da9150_charger_resources),
+	},
+};
+
+int da9150_device_init(struct da9150 *da9150)
+{
+	struct da9150_pdata *pdata = da9150->dev->platform_data;
+	int ret;
+
+	/* Handle platform data */
+	if (pdata)
+		da9150->irq_base = pdata->irq_base;
+	else
+		da9150->irq_base = -1;
+
+	/* Init IRQs */
+	ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
+				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				  da9150->irq_base, &da9150_regmap_irq_chip,
+				  &da9150->regmap_irq_data);
+	if (ret < 0)
+		goto err_irq;
+
+	da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
+
+	/* Make the IRQ line a wake source */
+	enable_irq_wake(da9150->irq);
+
+	/* Add MFD Devices */
+	ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
+			      ARRAY_SIZE(da9150_devs), NULL,
+			      da9150->irq_base, NULL);
+	if (ret < 0) {
+		dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
+		goto err_mfd;
+	}
+
+	return 0;
+
+err_mfd:
+	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+err_irq:
+	return ret;
+}
+
+void da9150_device_exit(struct da9150 *da9150)
+{
+	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+	mfd_remove_devices(da9150->dev);
+}
+
+void da9150_device_shutdown(struct da9150 *da9150)
+{
+	/* Make sure we have a wakup source for the device */
+	da9150_set_bits(da9150, DA9150_CONFIG_D,
+			DA9150_WKUP_PM_EN_MASK,
+			DA9150_WKUP_PM_EN_MASK);
+
+	/* Set device to DISABLED mode */
+	da9150_set_bits(da9150, DA9150_CONTROL_C,
+			DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
+}
+
+MODULE_DESCRIPTION("MFD Core Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/da9150-i2c.c b/drivers/mfd/da9150-i2c.c
new file mode 100644
index 0000000..a02525c
--- /dev/null
+++ b/drivers/mfd/da9150-i2c.c
@@ -0,0 +1,176 @@
+/*
+ * DA9150 I2C Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/registers.h>
+
+static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA9150_PAGE_CON:
+	case DA9150_STATUS_A:
+	case DA9150_STATUS_B:
+	case DA9150_STATUS_C:
+	case DA9150_STATUS_D:
+	case DA9150_STATUS_E:
+	case DA9150_STATUS_F:
+	case DA9150_STATUS_G:
+	case DA9150_STATUS_H:
+	case DA9150_STATUS_I:
+	case DA9150_STATUS_J:
+	case DA9150_STATUS_K:
+	case DA9150_STATUS_L:
+	case DA9150_STATUS_N:
+	case DA9150_FAULT_LOG_A:
+	case DA9150_FAULT_LOG_B:
+	case DA9150_EVENT_E:
+	case DA9150_EVENT_F:
+	case DA9150_EVENT_G:
+	case DA9150_EVENT_H:
+	case DA9150_CONTROL_B:
+	case DA9150_CONTROL_C:
+	case DA9150_GPADC_MAN:
+	case DA9150_GPADC_RES_A:
+	case DA9150_GPADC_RES_B:
+	case DA9150_ADETVB_CFG_C:
+	case DA9150_ADETD_STAT:
+	case DA9150_ADET_CMPSTAT:
+	case DA9150_ADET_CTRL_A:
+	case DA9150_PPR_TCTR_B:
+	case DA9150_COREBTLD_STAT_A:
+	case DA9150_CORE_DATA_A:
+	case DA9150_CORE_DATA_B:
+	case DA9150_CORE_DATA_C:
+	case DA9150_CORE_DATA_D:
+	case DA9150_CORE2WIRE_STAT_A:
+	case DA9150_FW_CTRL_C:
+	case DA9150_FG_CTRL_B:
+	case DA9150_FW_CTRL_B:
+	case DA9150_GPADC_CMAN:
+	case DA9150_GPADC_CRES_A:
+	case DA9150_GPADC_CRES_B:
+	case DA9150_CC_ICHG_RES_A:
+	case DA9150_CC_ICHG_RES_B:
+	case DA9150_CC_IAVG_RES_A:
+	case DA9150_CC_IAVG_RES_B:
+	case DA9150_TAUX_CTRL_A:
+	case DA9150_TAUX_VALUE_H:
+	case DA9150_TAUX_VALUE_L:
+	case DA9150_TBAT_RES_A:
+	case DA9150_TBAT_RES_B:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_range_cfg da9150_range_cfg[] = {
+	{
+		.range_min = DA9150_PAGE_CON,
+		.range_max = DA9150_TBAT_RES_B,
+		.selector_reg = DA9150_PAGE_CON,
+		.selector_mask = DA9150_I2C_PAGE_MASK,
+		.selector_shift = DA9150_I2C_PAGE_SHIFT,
+		.window_start = 0,
+		.window_len = 256,
+	},
+};
+
+static struct regmap_config da9150_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.ranges = da9150_range_cfg,
+	.num_ranges = ARRAY_SIZE(da9150_range_cfg),
+	.max_register = DA9150_TBAT_RES_B,
+
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = da9150_volatile_reg,
+};
+
+static int da9150_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct da9150 *da9150;
+	int ret;
+
+	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
+	if (da9150 == NULL)
+		return -ENOMEM;
+	da9150->dev = &client->dev;
+	da9150->irq = client->irq;
+	i2c_set_clientdata(client, da9150);
+	dev_set_drvdata(da9150->dev, da9150);
+
+	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
+	if (IS_ERR(da9150->regmap)) {
+		ret = PTR_ERR(da9150->regmap);
+		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	return da9150_device_init(da9150);
+}
+
+static int da9150_remove(struct i2c_client *client)
+{
+	struct da9150 *da9150 = i2c_get_clientdata(client);
+
+	da9150_device_exit(da9150);
+
+	return 0;
+}
+
+static void da9150_shutdown(struct i2c_client *client)
+{
+	struct da9150 *da9150 = i2c_get_clientdata(client);
+
+	da9150_device_shutdown(da9150);
+}
+
+static const struct i2c_device_id da9150_i2c_id[] = {
+	{ "da9150", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
+
+static const struct of_device_id da9150_of_match[] = {
+	{ .compatible = "dlg,da9150", },
+	{ }
+};
+
+static struct i2c_driver da9150_driver = {
+	.driver	= {
+		.name	= "da9150",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(da9150_of_match),
+	},
+	.probe		= da9150_probe,
+	.remove		= da9150_remove,
+	.shutdown	= da9150_shutdown,
+	.id_table	= da9150_i2c_id,
+};
+
+module_i2c_driver(da9150_driver);
+
+MODULE_DESCRIPTION("I2C Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/da9150/core.h b/include/linux/mfd/da9150/core.h
new file mode 100644
index 0000000..d23c500
--- /dev/null
+++ b/include/linux/mfd/da9150/core.h
@@ -0,0 +1,80 @@
+/*
+ * DA9150 MFD Driver - Core Data
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
+ */
+
+#ifndef __DA9150_CORE_H
+#define __DA9150_CORE_H
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/mutex.h>
+
+/* I2C address paging */
+#define DA9150_REG_PAGE_SHIFT	8
+#define DA9150_REG_PAGE_MASK	0xFF
+
+/* IRQs */
+#define DA9150_NUM_IRQ_REGS	4
+#define DA9150_IRQ_VBUS		0
+#define DA9150_IRQ_CHG		1
+#define DA9150_IRQ_TCLASS	2
+#define DA9150_IRQ_TJUNC	3
+#define DA9150_IRQ_VFAULT	4
+#define DA9150_IRQ_CONF		5
+#define DA9150_IRQ_DAT		6
+#define DA9150_IRQ_DTYPE	7
+#define DA9150_IRQ_ID		8
+#define DA9150_IRQ_ADP		9
+#define DA9150_IRQ_SESS_END	10
+#define DA9150_IRQ_SESS_VLD	11
+#define DA9150_IRQ_FG		12
+#define DA9150_IRQ_GP		13
+#define DA9150_IRQ_TBAT		14
+#define DA9150_IRQ_GPIOA	15
+#define DA9150_IRQ_GPIOB	16
+#define DA9150_IRQ_GPIOC	17
+#define DA9150_IRQ_GPIOD	18
+#define DA9150_IRQ_GPADC	19
+#define DA9150_IRQ_WKUP		20
+
+struct da9150 {
+	struct device *dev;
+
+	struct regmap *regmap;
+
+	struct regmap_irq_chip_data *regmap_irq_data;
+	int irq;
+	int irq_base;
+};
+
+/* Device I/O */
+u8 da9150_reg_read(struct da9150 *da9150, u16 reg);
+int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val);
+int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val);
+
+int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf);
+int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf);
+
+/* IRQ helper functions */
+int da9150_register_irq(struct platform_device *pdev, void *dev_id,
+			irq_handler_t handler, const char *name);
+void da9150_release_irq(struct platform_device *pdev, void *dev_id,
+			const char *name);
+
+/* Init/Exit */
+int da9150_device_init(struct da9150 *da9150);
+void da9150_device_exit(struct da9150 *da9150);
+void da9150_device_shutdown(struct da9150 *da9150);
+
+#endif /* __DA9150_CORE_H */
diff --git a/include/linux/mfd/da9150/pdata.h b/include/linux/mfd/da9150/pdata.h
new file mode 100644
index 0000000..e2b37f1
--- /dev/null
+++ b/include/linux/mfd/da9150/pdata.h
@@ -0,0 +1,21 @@
+/*
+ * DA9150 MFD Driver - Platform Data
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
+ */
+
+#ifndef __DA9150_PDATA_H
+#define __DA9150_PDATA_H
+
+struct da9150_pdata {
+	int irq_base;
+};
+
+#endif /* __DA9150_PDATA_H */
diff --git a/include/linux/mfd/da9150/registers.h b/include/linux/mfd/da9150/registers.h
new file mode 100644
index 0000000..ef4826d
--- /dev/null
+++ b/include/linux/mfd/da9150/registers.h
@@ -0,0 +1,1153 @@
+/*
+ * DA9150 MFD Driver - Registers
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
+ */
+
+#ifndef __DA9150_REGISTERS_H
+#define __DA9150_REGISTERS_H
+
+/* Registers */
+#define DA9150_PAGE_CON			0x000
+#define DA9150_STATUS_A			0x068
+#define DA9150_STATUS_B			0x069
+#define DA9150_STATUS_C			0x06A
+#define DA9150_STATUS_D			0x06B
+#define DA9150_STATUS_E			0x06C
+#define DA9150_STATUS_F			0x06D
+#define DA9150_STATUS_G			0x06E
+#define DA9150_STATUS_H			0x06F
+#define DA9150_STATUS_I			0x070
+#define DA9150_STATUS_J			0x071
+#define DA9150_STATUS_K			0x072
+#define DA9150_STATUS_L			0x073
+#define DA9150_STATUS_N			0x074
+#define DA9150_FAULT_LOG_A		0x076
+#define DA9150_FAULT_LOG_B		0x077
+#define DA9150_EVENT_E			0x078
+#define DA9150_EVENT_F			0x079
+#define DA9150_EVENT_G			0x07A
+#define DA9150_EVENT_H			0x07B
+#define DA9150_IRQ_MASK_E		0x07C
+#define DA9150_IRQ_MASK_F		0x07D
+#define DA9150_IRQ_MASK_G		0x07E
+#define DA9150_IRQ_MASK_H		0x07F
+#define DA9150_PAGE_CON_1		0x080
+#define DA9150_CONFIG_A			0x0E0
+#define DA9150_CONFIG_B			0x0E1
+#define DA9150_CONFIG_C			0x0E2
+#define DA9150_CONFIG_D			0x0E3
+#define DA9150_CONFIG_E			0x0E4
+#define DA9150_CONTROL_A		0x0E5
+#define DA9150_CONTROL_B		0x0E6
+#define DA9150_CONTROL_C		0x0E7
+#define DA9150_GPIO_A_B			0x0E8
+#define DA9150_GPIO_C_D			0x0E9
+#define DA9150_GPIO_MODE_CONT		0x0EA
+#define DA9150_GPIO_CTRL_B		0x0EB
+#define DA9150_GPIO_CTRL_A		0x0EC
+#define DA9150_GPIO_CTRL_C		0x0ED
+#define DA9150_GPIO_CFG_A		0x0EE
+#define DA9150_GPIO_CFG_B		0x0EF
+#define DA9150_GPIO_CFG_C		0x0F0
+#define DA9150_GPADC_MAN		0x0F2
+#define DA9150_GPADC_RES_A		0x0F4
+#define DA9150_GPADC_RES_B		0x0F5
+#define DA9150_PAGE_CON_2		0x100
+#define DA9150_OTP_CONT_SHARED		0x101
+#define DA9150_INTERFACE_SHARED		0x105
+#define DA9150_CONFIG_A_SHARED		0x106
+#define DA9150_CONFIG_D_SHARED		0x109
+#define DA9150_ADETVB_CFG_C		0x150
+#define DA9150_ADETD_STAT		0x151
+#define DA9150_ADET_CMPSTAT		0x152
+#define DA9150_ADET_CTRL_A		0x153
+#define DA9150_ADETVB_CFG_B		0x154
+#define DA9150_ADETVB_CFG_A		0x155
+#define DA9150_ADETAC_CFG_A		0x156
+#define DA9150_ADDETAC_CFG_B		0x157
+#define DA9150_ADETAC_CFG_C		0x158
+#define DA9150_ADETAC_CFG_D		0x159
+#define DA9150_ADETVB_CFG_D		0x15A
+#define DA9150_ADETID_CFG_A		0x15B
+#define DA9150_ADET_RID_PT_CHG_H	0x15C
+#define DA9150_ADET_RID_PT_CHG_L	0x15D
+#define DA9150_PPR_TCTR_B		0x160
+#define DA9150_PPR_BKCTRL_A		0x163
+#define DA9150_PPR_BKCFG_A		0x164
+#define DA9150_PPR_BKCFG_B		0x165
+#define DA9150_PPR_CHGCTRL_A		0x166
+#define DA9150_PPR_CHGCTRL_B		0x167
+#define DA9150_PPR_CHGCTRL_C		0x168
+#define DA9150_PPR_TCTR_A		0x169
+#define DA9150_PPR_CHGCTRL_D		0x16A
+#define DA9150_PPR_CHGCTRL_E		0x16B
+#define DA9150_PPR_CHGCTRL_F		0x16C
+#define DA9150_PPR_CHGCTRL_G		0x16D
+#define DA9150_PPR_CHGCTRL_H		0x16E
+#define DA9150_PPR_CHGCTRL_I		0x16F
+#define DA9150_PPR_CHGCTRL_J		0x170
+#define DA9150_PPR_CHGCTRL_K		0x171
+#define DA9150_PPR_CHGCTRL_L		0x172
+#define DA9150_PPR_CHGCTRL_M		0x173
+#define DA9150_PPR_THYST_A		0x174
+#define DA9150_PPR_THYST_B		0x175
+#define DA9150_PPR_THYST_C		0x176
+#define DA9150_PPR_THYST_D		0x177
+#define DA9150_PPR_THYST_E		0x178
+#define DA9150_PPR_THYST_F		0x179
+#define DA9150_PPR_THYST_G		0x17A
+#define DA9150_PAGE_CON_3		0x180
+#define DA9150_PAGE_CON_4		0x200
+#define DA9150_PAGE_CON_5		0x280
+#define DA9150_PAGE_CON_6		0x300
+#define DA9150_COREBTLD_STAT_A		0x302
+#define DA9150_COREBTLD_CTRL_A		0x303
+#define DA9150_CORE_CONFIG_A		0x304
+#define DA9150_CORE_CONFIG_C		0x305
+#define DA9150_CORE_CONFIG_B		0x306
+#define DA9150_CORE_CFG_DATA_A		0x307
+#define DA9150_CORE_CFG_DATA_B		0x308
+#define DA9150_CORE_CMD_A		0x309
+#define DA9150_CORE_DATA_A		0x30A
+#define DA9150_CORE_DATA_B		0x30B
+#define DA9150_CORE_DATA_C		0x30C
+#define DA9150_CORE_DATA_D		0x30D
+#define DA9150_CORE2WIRE_STAT_A		0x310
+#define DA9150_CORE2WIRE_CTRL_A		0x311
+#define DA9150_FW_CTRL_A		0x312
+#define DA9150_FW_CTRL_C		0x313
+#define DA9150_FW_CTRL_D		0x314
+#define DA9150_FG_CTRL_A		0x315
+#define DA9150_FG_CTRL_B		0x316
+#define DA9150_FW_CTRL_E		0x317
+#define DA9150_FW_CTRL_B		0x318
+#define DA9150_GPADC_CMAN		0x320
+#define DA9150_GPADC_CRES_A		0x322
+#define DA9150_GPADC_CRES_B		0x323
+#define DA9150_CC_CFG_A			0x328
+#define DA9150_CC_CFG_B			0x329
+#define DA9150_CC_ICHG_RES_A		0x32A
+#define DA9150_CC_ICHG_RES_B		0x32B
+#define DA9150_CC_IAVG_RES_A		0x32C
+#define DA9150_CC_IAVG_RES_B		0x32D
+#define DA9150_TAUX_CTRL_A		0x330
+#define DA9150_TAUX_RELOAD_H		0x332
+#define DA9150_TAUX_RELOAD_L		0x333
+#define DA9150_TAUX_VALUE_H		0x334
+#define DA9150_TAUX_VALUE_L		0x335
+#define DA9150_AUX_DATA_0		0x338
+#define DA9150_AUX_DATA_1		0x339
+#define DA9150_AUX_DATA_2		0x33A
+#define DA9150_AUX_DATA_3		0x33B
+#define DA9150_BIF_CTRL			0x340
+#define DA9150_TBAT_CTRL_A		0x342
+#define DA9150_TBAT_CTRL_B		0x343
+#define DA9150_TBAT_RES_A		0x344
+#define DA9150_TBAT_RES_B		0x345
+
+/* DA9150_PAGE_CON = 0x000 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_I2C_PAGE_SHIFT			1
+#define DA9150_I2C_PAGE_MASK			(0x1f << 1)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_STATUS_A = 0x068 */
+#define DA9150_WKUP_STAT_SHIFT			2
+#define DA9150_WKUP_STAT_MASK			(0x0f << 2)
+#define DA9150_SLEEP_STAT_SHIFT			6
+#define DA9150_SLEEP_STAT_MASK			(0x03 << 6)
+
+/* DA9150_STATUS_B = 0x069 */
+#define DA9150_VFAULT_STAT_SHIFT		0
+#define DA9150_VFAULT_STAT_MASK			(0x01 << 0)
+#define DA9150_TFAULT_STAT_SHIFT		1
+#define DA9150_TFAULT_STAT_MASK			(0x01 << 1)
+
+/* DA9150_STATUS_C = 0x06A */
+#define DA9150_VDD33_STAT_SHIFT			0
+#define DA9150_VDD33_STAT_MASK			(0x01 << 0)
+#define DA9150_VDD33_SLEEP_SHIFT		1
+#define DA9150_VDD33_SLEEP_MASK			(0x01 << 1)
+#define DA9150_LFOSC_STAT_SHIFT			7
+#define DA9150_LFOSC_STAT_MASK			(0x01 << 7)
+
+/* DA9150_STATUS_D = 0x06B */
+#define DA9150_GPIOA_STAT_SHIFT			0
+#define DA9150_GPIOA_STAT_MASK			(0x01 << 0)
+#define DA9150_GPIOB_STAT_SHIFT			1
+#define DA9150_GPIOB_STAT_MASK			(0x01 << 1)
+#define DA9150_GPIOC_STAT_SHIFT			2
+#define DA9150_GPIOC_STAT_MASK			(0x01 << 2)
+#define DA9150_GPIOD_STAT_SHIFT			3
+#define DA9150_GPIOD_STAT_MASK			(0x01 << 3)
+
+/* DA9150_STATUS_E = 0x06C */
+#define DA9150_DTYPE_SHIFT			0
+#define DA9150_DTYPE_MASK			(0x1f << 0)
+#define DA9150_DTYPE_DT_NIL			(0x00 << 0)
+#define DA9150_DTYPE_DT_USB_OTG			(0x01 << 0)
+#define DA9150_DTYPE_DT_USB_STD			(0x02 << 0)
+#define DA9150_DTYPE_DT_USB_CHG			(0x03 << 0)
+#define DA9150_DTYPE_DT_ACA_CHG			(0x04 << 0)
+#define DA9150_DTYPE_DT_ACA_OTG			(0x05 << 0)
+#define DA9150_DTYPE_DT_ACA_DOC			(0x06 << 0)
+#define DA9150_DTYPE_DT_DED_CHG			(0x07 << 0)
+#define DA9150_DTYPE_DT_CR5_CHG			(0x08 << 0)
+#define DA9150_DTYPE_DT_CR4_CHG			(0x0c << 0)
+#define DA9150_DTYPE_DT_PT_CHG			(0x11 << 0)
+#define DA9150_DTYPE_DT_NN_ACC			(0x16 << 0)
+#define DA9150_DTYPE_DT_NN_CHG			(0x17 << 0)
+
+/* DA9150_STATUS_F = 0x06D */
+#define DA9150_SESS_VLD_SHIFT			0
+#define DA9150_SESS_VLD_MASK			(0x01 << 0)
+#define DA9150_ID_ERR_SHIFT			1
+#define DA9150_ID_ERR_MASK			(0x01 << 1)
+#define DA9150_PT_CHG_SHIFT			2
+#define DA9150_PT_CHG_MASK			(0x01 << 2)
+
+/* DA9150_STATUS_G = 0x06E */
+#define DA9150_RID_SHIFT			0
+#define DA9150_RID_MASK				(0xff << 0)
+
+/* DA9150_STATUS_H = 0x06F */
+#define DA9150_VBUS_STAT_SHIFT			0
+#define DA9150_VBUS_STAT_MASK			(0x07 << 0)
+#define DA9150_VBUS_STAT_OFF			(0x00 << 0)
+#define DA9150_VBUS_STAT_WAIT			(0x01 << 0)
+#define DA9150_VBUS_STAT_CHG			(0x02 << 0)
+#define DA9150_VBUS_TRED_SHIFT			3
+#define DA9150_VBUS_TRED_MASK			(0x01 << 3)
+#define DA9150_VBUS_DROP_STAT_SHIFT		4
+#define DA9150_VBUS_DROP_STAT_MASK		(0x0f << 4)
+
+/* DA9150_STATUS_I = 0x070 */
+#define DA9150_VBUS_ISET_STAT_SHIFT		0
+#define DA9150_VBUS_ISET_STAT_MASK		(0x1f << 0)
+#define DA9150_VBUS_OT_SHIFT			7
+#define DA9150_VBUS_OT_MASK			(0x01 << 7)
+
+/* DA9150_STATUS_J = 0x071 */
+#define DA9150_CHG_STAT_SHIFT			0
+#define DA9150_CHG_STAT_MASK			(0x0f << 0)
+#define DA9150_CHG_STAT_OFF			(0x00 << 0)
+#define DA9150_CHG_STAT_SUSP			(0x01 << 0)
+#define DA9150_CHG_STAT_ACT			(0x02 << 0)
+#define DA9150_CHG_STAT_PRE			(0x03 << 0)
+#define DA9150_CHG_STAT_CC			(0x04 << 0)
+#define DA9150_CHG_STAT_CV			(0x05 << 0)
+#define DA9150_CHG_STAT_FULL			(0x06 << 0)
+#define DA9150_CHG_STAT_TEMP			(0x07 << 0)
+#define DA9150_CHG_STAT_TIME			(0x08 << 0)
+#define DA9150_CHG_STAT_BAT			(0x09 << 0)
+#define DA9150_CHG_TEMP_SHIFT			4
+#define DA9150_CHG_TEMP_MASK			(0x07 << 4)
+#define DA9150_CHG_TEMP_UNDER			(0x06 << 4)
+#define DA9150_CHG_TEMP_OVER			(0x07 << 4)
+#define DA9150_CHG_IEND_STAT_SHIFT		7
+#define DA9150_CHG_IEND_STAT_MASK		(0x01 << 7)
+
+/* DA9150_STATUS_K = 0x072 */
+#define DA9150_CHG_IAV_H_SHIFT			0
+#define DA9150_CHG_IAV_H_MASK			(0xff << 0)
+
+/* DA9150_STATUS_L = 0x073 */
+#define DA9150_CHG_IAV_L_SHIFT			5
+#define DA9150_CHG_IAV_L_MASK			(0x07 << 5)
+
+/* DA9150_STATUS_N = 0x074 */
+#define DA9150_CHG_TIME_SHIFT			1
+#define DA9150_CHG_TIME_MASK			(0x01 << 1)
+#define DA9150_CHG_TRED_SHIFT			2
+#define DA9150_CHG_TRED_MASK			(0x01 << 2)
+#define DA9150_CHG_TJUNC_CLASS_SHIFT		3
+#define DA9150_CHG_TJUNC_CLASS_MASK		(0x07 << 3)
+#define DA9150_CHG_TJUNC_CLASS_6		(0x06 << 3)
+#define DA9150_EBS_STAT_SHIFT			6
+#define DA9150_EBS_STAT_MASK			(0x01 << 6)
+#define DA9150_CHG_BAT_REMOVED_SHIFT		7
+#define DA9150_CHG_BAT_REMOVED_MASK		(0x01 << 7)
+
+/* DA9150_FAULT_LOG_A = 0x076 */
+#define DA9150_TEMP_FAULT_SHIFT			0
+#define DA9150_TEMP_FAULT_MASK			(0x01 << 0)
+#define DA9150_VSYS_FAULT_SHIFT			1
+#define DA9150_VSYS_FAULT_MASK			(0x01 << 1)
+#define DA9150_START_FAULT_SHIFT		2
+#define DA9150_START_FAULT_MASK			(0x01 << 2)
+#define DA9150_EXT_FAULT_SHIFT			3
+#define DA9150_EXT_FAULT_MASK			(0x01 << 3)
+#define DA9150_POR_FAULT_SHIFT			4
+#define DA9150_POR_FAULT_MASK			(0x01 << 4)
+
+/* DA9150_FAULT_LOG_B = 0x077 */
+#define DA9150_VBUS_FAULT_SHIFT			0
+#define DA9150_VBUS_FAULT_MASK			(0x01 << 0)
+#define DA9150_OTG_FAULT_SHIFT			1
+#define DA9150_OTG_FAULT_MASK			(0x01 << 1)
+
+/* DA9150_EVENT_E = 0x078 */
+#define DA9150_E_VBUS_SHIFT			0
+#define DA9150_E_VBUS_MASK			(0x01 << 0)
+#define DA9150_E_CHG_SHIFT			1
+#define DA9150_E_CHG_MASK			(0x01 << 1)
+#define DA9150_E_TCLASS_SHIFT			2
+#define DA9150_E_TCLASS_MASK			(0x01 << 2)
+#define DA9150_E_TJUNC_SHIFT			3
+#define DA9150_E_TJUNC_MASK			(0x01 << 3)
+#define DA9150_E_VFAULT_SHIFT			4
+#define DA9150_E_VFAULT_MASK			(0x01 << 4)
+#define DA9150_EVENTS_H_SHIFT			5
+#define DA9150_EVENTS_H_MASK			(0x01 << 5)
+#define DA9150_EVENTS_G_SHIFT			6
+#define DA9150_EVENTS_G_MASK			(0x01 << 6)
+#define DA9150_EVENTS_F_SHIFT			7
+#define DA9150_EVENTS_F_MASK			(0x01 << 7)
+
+/* DA9150_EVENT_F = 0x079 */
+#define DA9150_E_CONF_SHIFT			0
+#define DA9150_E_CONF_MASK			(0x01 << 0)
+#define DA9150_E_DAT_SHIFT			1
+#define DA9150_E_DAT_MASK			(0x01 << 1)
+#define DA9150_E_DTYPE_SHIFT			3
+#define DA9150_E_DTYPE_MASK			(0x01 << 3)
+#define DA9150_E_ID_SHIFT			4
+#define DA9150_E_ID_MASK			(0x01 << 4)
+#define DA9150_E_ADP_SHIFT			5
+#define DA9150_E_ADP_MASK			(0x01 << 5)
+#define DA9150_E_SESS_END_SHIFT			6
+#define DA9150_E_SESS_END_MASK			(0x01 << 6)
+#define DA9150_E_SESS_VLD_SHIFT			7
+#define DA9150_E_SESS_VLD_MASK			(0x01 << 7)
+
+/* DA9150_EVENT_G = 0x07A */
+#define DA9150_E_FG_SHIFT			0
+#define DA9150_E_FG_MASK			(0x01 << 0)
+#define DA9150_E_GP_SHIFT			1
+#define DA9150_E_GP_MASK			(0x01 << 1)
+#define DA9150_E_TBAT_SHIFT			2
+#define DA9150_E_TBAT_MASK			(0x01 << 2)
+#define DA9150_E_GPIOA_SHIFT			3
+#define DA9150_E_GPIOA_MASK			(0x01 << 3)
+#define DA9150_E_GPIOB_SHIFT			4
+#define DA9150_E_GPIOB_MASK			(0x01 << 4)
+#define DA9150_E_GPIOC_SHIFT			5
+#define DA9150_E_GPIOC_MASK			(0x01 << 5)
+#define DA9150_E_GPIOD_SHIFT			6
+#define DA9150_E_GPIOD_MASK			(0x01 << 6)
+#define DA9150_E_GPADC_SHIFT			7
+#define DA9150_E_GPADC_MASK			(0x01 << 7)
+
+/* DA9150_EVENT_H = 0x07B */
+#define DA9150_E_WKUP_SHIFT			0
+#define DA9150_E_WKUP_MASK			(0x01 << 0)
+
+/* DA9150_IRQ_MASK_E = 0x07C */
+#define DA9150_M_VBUS_SHIFT			0
+#define DA9150_M_VBUS_MASK			(0x01 << 0)
+#define DA9150_M_CHG_SHIFT			1
+#define DA9150_M_CHG_MASK			(0x01 << 1)
+#define DA9150_M_TJUNC_SHIFT			3
+#define DA9150_M_TJUNC_MASK			(0x01 << 3)
+#define DA9150_M_VFAULT_SHIFT			4
+#define DA9150_M_VFAULT_MASK			(0x01 << 4)
+
+/* DA9150_IRQ_MASK_F = 0x07D */
+#define DA9150_M_CONF_SHIFT			0
+#define DA9150_M_CONF_MASK			(0x01 << 0)
+#define DA9150_M_DAT_SHIFT			1
+#define DA9150_M_DAT_MASK			(0x01 << 1)
+#define DA9150_M_DTYPE_SHIFT			3
+#define DA9150_M_DTYPE_MASK			(0x01 << 3)
+#define DA9150_M_ID_SHIFT			4
+#define DA9150_M_ID_MASK			(0x01 << 4)
+#define DA9150_M_ADP_SHIFT			5
+#define DA9150_M_ADP_MASK			(0x01 << 5)
+#define DA9150_M_SESS_END_SHIFT			6
+#define DA9150_M_SESS_END_MASK			(0x01 << 6)
+#define DA9150_M_SESS_VLD_SHIFT			7
+#define DA9150_M_SESS_VLD_MASK			(0x01 << 7)
+
+/* DA9150_IRQ_MASK_G = 0x07E */
+#define DA9150_M_FG_SHIFT			0
+#define DA9150_M_FG_MASK			(0x01 << 0)
+#define DA9150_M_GP_SHIFT			1
+#define DA9150_M_GP_MASK			(0x01 << 1)
+#define DA9150_M_TBAT_SHIFT			2
+#define DA9150_M_TBAT_MASK			(0x01 << 2)
+#define DA9150_M_GPIOA_SHIFT			3
+#define DA9150_M_GPIOA_MASK			(0x01 << 3)
+#define DA9150_M_GPIOB_SHIFT			4
+#define DA9150_M_GPIOB_MASK			(0x01 << 4)
+#define DA9150_M_GPIOC_SHIFT			5
+#define DA9150_M_GPIOC_MASK			(0x01 << 5)
+#define DA9150_M_GPIOD_SHIFT			6
+#define DA9150_M_GPIOD_MASK			(0x01 << 6)
+#define DA9150_M_GPADC_SHIFT			7
+#define DA9150_M_GPADC_MASK			(0x01 << 7)
+
+/* DA9150_IRQ_MASK_H = 0x07F */
+#define DA9150_M_WKUP_SHIFT			0
+#define DA9150_M_WKUP_MASK			(0x01 << 0)
+
+/* DA9150_PAGE_CON_1 = 0x080 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_CONFIG_A = 0x0E0 */
+#define DA9150_RESET_DUR_SHIFT			0
+#define DA9150_RESET_DUR_MASK			(0x03 << 0)
+#define DA9150_RESET_EXT_SHIFT			2
+#define DA9150_RESET_EXT_MASK			(0x03 << 2)
+#define DA9150_START_MAX_SHIFT			4
+#define DA9150_START_MAX_MASK			(0x03 << 4)
+#define DA9150_PS_WAIT_EN_SHIFT			6
+#define DA9150_PS_WAIT_EN_MASK			(0x01 << 6)
+#define DA9150_PS_DISABLE_DIRECT_SHIFT		7
+#define DA9150_PS_DISABLE_DIRECT_MASK		(0x01 << 7)
+
+/* DA9150_CONFIG_B = 0x0E1 */
+#define DA9150_VFAULT_ADJ_SHIFT			0
+#define DA9150_VFAULT_ADJ_MASK			(0x0f << 0)
+#define DA9150_VFAULT_HYST_SHIFT		4
+#define DA9150_VFAULT_HYST_MASK			(0x07 << 4)
+#define DA9150_VFAULT_EN_SHIFT			7
+#define DA9150_VFAULT_EN_MASK			(0x01 << 7)
+
+/* DA9150_CONFIG_C = 0x0E2 */
+#define DA9150_VSYS_MIN_SHIFT			3
+#define DA9150_VSYS_MIN_MASK			(0x1f << 3)
+
+/* DA9150_CONFIG_D = 0x0E3 */
+#define DA9150_LFOSC_EXT_SHIFT			0
+#define DA9150_LFOSC_EXT_MASK			(0x01 << 0)
+#define DA9150_VDD33_DWN_SHIFT			1
+#define DA9150_VDD33_DWN_MASK			(0x01 << 1)
+#define DA9150_WKUP_PM_EN_SHIFT			2
+#define DA9150_WKUP_PM_EN_MASK			(0x01 << 2)
+#define DA9150_WKUP_CE_SEL_SHIFT		3
+#define DA9150_WKUP_CE_SEL_MASK			(0x03 << 3)
+#define DA9150_WKUP_CLK32K_EN_SHIFT		5
+#define DA9150_WKUP_CLK32K_EN_MASK		(0x01 << 5)
+#define DA9150_DISABLE_DEL_SHIFT		7
+#define DA9150_DISABLE_DEL_MASK			(0x01 << 7)
+
+/* DA9150_CONFIG_E = 0x0E4 */
+#define DA9150_PM_SPKSUP_DIS_SHIFT		0
+#define DA9150_PM_SPKSUP_DIS_MASK		(0x01 << 0)
+#define DA9150_PM_MERGE_SHIFT			1
+#define DA9150_PM_MERGE_MASK			(0x01 << 1)
+#define DA9150_PM_SR_OFF_SHIFT			2
+#define DA9150_PM_SR_OFF_MASK			(0x01 << 2)
+#define DA9150_PM_TIMEOUT_EN_SHIFT		3
+#define DA9150_PM_TIMEOUT_EN_MASK		(0x01 << 3)
+#define DA9150_PM_DLY_SEL_SHIFT			4
+#define DA9150_PM_DLY_SEL_MASK			(0x07 << 4)
+#define DA9150_PM_OUT_DLY_SEL_SHIFT		7
+#define DA9150_PM_OUT_DLY_SEL_MASK		(0x01 << 7)
+
+/* DA9150_CONTROL_A = 0x0E5 */
+#define DA9150_VDD33_SL_SHIFT			0
+#define DA9150_VDD33_SL_MASK			(0x01 << 0)
+#define DA9150_VDD33_LPM_SHIFT			1
+#define DA9150_VDD33_LPM_MASK			(0x03 << 1)
+#define DA9150_VDD33_EN_SHIFT			3
+#define DA9150_VDD33_EN_MASK			(0x01 << 3)
+#define DA9150_GPI_LPM_SHIFT			6
+#define DA9150_GPI_LPM_MASK			(0x01 << 6)
+#define DA9150_PM_IF_LPM_SHIFT			7
+#define DA9150_PM_IF_LPM_MASK			(0x01 << 7)
+
+/* DA9150_CONTROL_B = 0x0E6 */
+#define DA9150_LPM_SHIFT			0
+#define DA9150_LPM_MASK				(0x01 << 0)
+#define DA9150_RESET_SHIFT			1
+#define DA9150_RESET_MASK			(0x01 << 1)
+#define DA9150_RESET_USRCONF_EN_SHIFT		2
+#define DA9150_RESET_USRCONF_EN_MASK		(0x01 << 2)
+
+/* DA9150_CONTROL_C = 0x0E7 */
+#define DA9150_DISABLE_SHIFT			0
+#define DA9150_DISABLE_MASK			(0x01 << 0)
+
+/* DA9150_GPIO_A_B = 0x0E8 */
+#define DA9150_GPIOA_PIN_SHIFT			0
+#define DA9150_GPIOA_PIN_MASK			(0x07 << 0)
+#define DA9150_GPIOA_PIN_GPI			(0x00 << 0)
+#define DA9150_GPIOA_PIN_GPO_OD			(0x01 << 0)
+#define DA9150_GPIOA_TYPE_SHIFT			3
+#define DA9150_GPIOA_TYPE_MASK			(0x01 << 3)
+#define DA9150_GPIOB_PIN_SHIFT			4
+#define DA9150_GPIOB_PIN_MASK			(0x07 << 4)
+#define DA9150_GPIOB_PIN_GPI			(0x00 << 4)
+#define DA9150_GPIOB_PIN_GPO_OD			(0x01 << 4)
+#define DA9150_GPIOB_TYPE_SHIFT			7
+#define DA9150_GPIOB_TYPE_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_C_D = 0x0E9 */
+#define DA9150_GPIOC_PIN_SHIFT			0
+#define DA9150_GPIOC_PIN_MASK			(0x07 << 0)
+#define DA9150_GPIOC_PIN_GPI			(0x00 << 0)
+#define DA9150_GPIOC_PIN_GPO_OD			(0x01 << 0)
+#define DA9150_GPIOC_TYPE_SHIFT			3
+#define DA9150_GPIOC_TYPE_MASK			(0x01 << 3)
+#define DA9150_GPIOD_PIN_SHIFT			4
+#define DA9150_GPIOD_PIN_MASK			(0x07 << 4)
+#define DA9150_GPIOD_PIN_GPI			(0x00 << 4)
+#define DA9150_GPIOD_PIN_GPO_OD			(0x01 << 4)
+#define DA9150_GPIOD_TYPE_SHIFT			7
+#define DA9150_GPIOD_TYPE_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_MODE_CONT = 0x0EA */
+#define DA9150_GPIOA_MODE_SHIFT			0
+#define DA9150_GPIOA_MODE_MASK			(0x01 << 0)
+#define DA9150_GPIOB_MODE_SHIFT			1
+#define DA9150_GPIOB_MODE_MASK			(0x01 << 1)
+#define DA9150_GPIOC_MODE_SHIFT			2
+#define DA9150_GPIOC_MODE_MASK			(0x01 << 2)
+#define DA9150_GPIOD_MODE_SHIFT			3
+#define DA9150_GPIOD_MODE_MASK			(0x01 << 3)
+#define DA9150_GPIOA_CONT_SHIFT			4
+#define DA9150_GPIOA_CONT_MASK			(0x01 << 4)
+#define DA9150_GPIOB_CONT_SHIFT			5
+#define DA9150_GPIOB_CONT_MASK			(0x01 << 5)
+#define DA9150_GPIOC_CONT_SHIFT			6
+#define DA9150_GPIOC_CONT_MASK			(0x01 << 6)
+#define DA9150_GPIOD_CONT_SHIFT			7
+#define DA9150_GPIOD_CONT_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_CTRL_B = 0x0EB */
+#define DA9150_WAKE_PIN_SHIFT			0
+#define DA9150_WAKE_PIN_MASK			(0x03 << 0)
+#define DA9150_WAKE_MODE_SHIFT			2
+#define DA9150_WAKE_MODE_MASK			(0x01 << 2)
+#define DA9150_WAKE_CONT_SHIFT			3
+#define DA9150_WAKE_CONT_MASK			(0x01 << 3)
+#define DA9150_WAKE_DLY_SHIFT			4
+#define DA9150_WAKE_DLY_MASK			(0x01 << 4)
+
+/* DA9150_GPIO_CTRL_A = 0x0EC */
+#define DA9150_GPIOA_ANAEN_SHIFT		0
+#define DA9150_GPIOA_ANAEN_MASK			(0x01 << 0)
+#define DA9150_GPIOB_ANAEN_SHIFT		1
+#define DA9150_GPIOB_ANAEN_MASK			(0x01 << 1)
+#define DA9150_GPIOC_ANAEN_SHIFT		2
+#define DA9150_GPIOC_ANAEN_MASK			(0x01 << 2)
+#define DA9150_GPIOD_ANAEN_SHIFT		3
+#define DA9150_GPIOD_ANAEN_MASK			(0x01 << 3)
+#define DA9150_GPIO_ANAEN			0x01
+#define DA9150_GPIO_ANAEN_MASK			0x0F
+#define DA9150_CHGLED_PIN_SHIFT			5
+#define DA9150_CHGLED_PIN_MASK			(0x07 << 5)
+
+/* DA9150_GPIO_CTRL_C = 0x0ED */
+#define DA9150_CHGBL_DUR_SHIFT			0
+#define DA9150_CHGBL_DUR_MASK			(0x03 << 0)
+#define DA9150_CHGBL_DBL_SHIFT			2
+#define DA9150_CHGBL_DBL_MASK			(0x01 << 2)
+#define DA9150_CHGBL_FRQ_SHIFT			3
+#define DA9150_CHGBL_FRQ_MASK			(0x03 << 3)
+#define DA9150_CHGBL_FLKR_SHIFT			5
+#define DA9150_CHGBL_FLKR_MASK			(0x01 << 5)
+
+/* DA9150_GPIO_CFG_A = 0x0EE */
+#define DA9150_CE_LPM_DEB_SHIFT			0
+#define DA9150_CE_LPM_DEB_MASK			(0x07 << 0)
+
+/* DA9150_GPIO_CFG_B = 0x0EF */
+#define DA9150_GPIOA_PUPD_SHIFT			0
+#define DA9150_GPIOA_PUPD_MASK			(0x01 << 0)
+#define DA9150_GPIOB_PUPD_SHIFT			1
+#define DA9150_GPIOB_PUPD_MASK			(0x01 << 1)
+#define DA9150_GPIOC_PUPD_SHIFT			2
+#define DA9150_GPIOC_PUPD_MASK			(0x01 << 2)
+#define DA9150_GPIOD_PUPD_SHIFT			3
+#define DA9150_GPIOD_PUPD_MASK			(0x01 << 3)
+#define DA9150_GPIO_PUPD_MASK			(0xF << 0)
+#define DA9150_GPI_DEB_SHIFT			4
+#define DA9150_GPI_DEB_MASK			(0x07 << 4)
+#define DA9150_LPM_EN_SHIFT			7
+#define DA9150_LPM_EN_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_CFG_C = 0x0F0 */
+#define DA9150_GPI_V_SHIFT			0
+#define DA9150_GPI_V_MASK			(0x01 << 0)
+#define DA9150_VDDIO_INT_SHIFT			1
+#define DA9150_VDDIO_INT_MASK			(0x01 << 1)
+#define DA9150_FAULT_PIN_SHIFT			3
+#define DA9150_FAULT_PIN_MASK			(0x07 << 3)
+#define DA9150_FAULT_TYPE_SHIFT			6
+#define DA9150_FAULT_TYPE_MASK			(0x01 << 6)
+#define DA9150_NIRQ_PUPD_SHIFT			7
+#define DA9150_NIRQ_PUPD_MASK			(0x01 << 7)
+
+/* DA9150_GPADC_MAN = 0x0F2 */
+#define DA9150_GPADC_EN_SHIFT			0
+#define DA9150_GPADC_EN_MASK			(0x01 << 0)
+#define DA9150_GPADC_MUX_SHIFT			1
+#define DA9150_GPADC_MUX_MASK			(0x1f << 1)
+
+/* DA9150_GPADC_RES_A = 0x0F4 */
+#define DA9150_GPADC_RES_H_SHIFT		0
+#define DA9150_GPADC_RES_H_MASK			(0xff << 0)
+
+/* DA9150_GPADC_RES_B = 0x0F5 */
+#define DA9150_GPADC_RUN_SHIFT			0
+#define DA9150_GPADC_RUN_MASK			(0x01 << 0)
+#define DA9150_GPADC_RES_L_SHIFT		6
+#define DA9150_GPADC_RES_L_MASK			(0x03 << 6)
+#define DA9150_GPADC_RES_L_BITS			2
+
+/* DA9150_PAGE_CON_2 = 0x100 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_OTP_CONT_SHARED = 0x101 */
+#define DA9150_PC_DONE_SHIFT			3
+#define DA9150_PC_DONE_MASK			(0x01 << 3)
+
+/* DA9150_INTERFACE_SHARED = 0x105 */
+#define DA9150_IF_BASE_ADDR_SHIFT		4
+#define DA9150_IF_BASE_ADDR_MASK		(0x0f << 4)
+
+/* DA9150_CONFIG_A_SHARED = 0x106 */
+#define DA9150_NIRQ_VDD_SHIFT			1
+#define DA9150_NIRQ_VDD_MASK			(0x01 << 1)
+#define DA9150_NIRQ_PIN_SHIFT			2
+#define DA9150_NIRQ_PIN_MASK			(0x01 << 2)
+#define DA9150_NIRQ_TYPE_SHIFT			3
+#define DA9150_NIRQ_TYPE_MASK			(0x01 << 3)
+#define DA9150_PM_IF_V_SHIFT			4
+#define DA9150_PM_IF_V_MASK			(0x01 << 4)
+#define DA9150_PM_IF_FMP_SHIFT			5
+#define DA9150_PM_IF_FMP_MASK			(0x01 << 5)
+#define DA9150_PM_IF_HSM_SHIFT			6
+#define DA9150_PM_IF_HSM_MASK			(0x01 << 6)
+
+/* DA9150_CONFIG_D_SHARED = 0x109 */
+#define DA9150_NIRQ_MODE_SHIFT			1
+#define DA9150_NIRQ_MODE_MASK			(0x01 << 1)
+
+/* DA9150_ADETVB_CFG_C = 0x150 */
+#define DA9150_TADP_RISE_SHIFT			0
+#define DA9150_TADP_RISE_MASK			(0xff << 0)
+
+/* DA9150_ADETD_STAT = 0x151 */
+#define DA9150_DCD_STAT_SHIFT			0
+#define DA9150_DCD_STAT_MASK			(0x01 << 0)
+#define DA9150_PCD_STAT_SHIFT			1
+#define DA9150_PCD_STAT_MASK			(0x03 << 1)
+#define DA9150_SCD_STAT_SHIFT			3
+#define DA9150_SCD_STAT_MASK			(0x03 << 3)
+#define DA9150_DP_STAT_SHIFT			5
+#define DA9150_DP_STAT_MASK			(0x01 << 5)
+#define DA9150_DM_STAT_SHIFT			6
+#define DA9150_DM_STAT_MASK			(0x01 << 6)
+
+/* DA9150_ADET_CMPSTAT = 0x152 */
+#define DA9150_DP_COMP_SHIFT			1
+#define DA9150_DP_COMP_MASK			(0x01 << 1)
+#define DA9150_DM_COMP_SHIFT			2
+#define DA9150_DM_COMP_MASK			(0x01 << 2)
+#define DA9150_ADP_SNS_COMP_SHIFT		3
+#define DA9150_ADP_SNS_COMP_MASK		(0x01 << 3)
+#define DA9150_ADP_PRB_COMP_SHIFT		4
+#define DA9150_ADP_PRB_COMP_MASK		(0x01 << 4)
+#define DA9150_ID_COMP_SHIFT			5
+#define DA9150_ID_COMP_MASK			(0x01 << 5)
+
+/* DA9150_ADET_CTRL_A = 0x153 */
+#define DA9150_AID_DAT_SHIFT			0
+#define DA9150_AID_DAT_MASK			(0x01 << 0)
+#define DA9150_AID_ID_SHIFT			1
+#define DA9150_AID_ID_MASK			(0x01 << 1)
+#define DA9150_AID_TRIG_SHIFT			2
+#define DA9150_AID_TRIG_MASK			(0x01 << 2)
+
+/* DA9150_ADETVB_CFG_B = 0x154 */
+#define DA9150_VB_MODE_SHIFT			0
+#define DA9150_VB_MODE_MASK			(0x03 << 0)
+#define DA9150_VB_MODE_VB_SESS			(0x01 << 0)
+
+#define DA9150_TADP_PRB_SHIFT			2
+#define DA9150_TADP_PRB_MASK			(0x01 << 2)
+#define DA9150_DAT_RPD_EXT_SHIFT		5
+#define DA9150_DAT_RPD_EXT_MASK			(0x01 << 5)
+#define DA9150_CONF_RPD_SHIFT			6
+#define DA9150_CONF_RPD_MASK			(0x01 << 6)
+#define DA9150_CONF_SRP_SHIFT			7
+#define DA9150_CONF_SRP_MASK			(0x01 << 7)
+
+/* DA9150_ADETVB_CFG_A = 0x155 */
+#define DA9150_AID_MODE_SHIFT			0
+#define DA9150_AID_MODE_MASK			(0x03 << 0)
+#define DA9150_AID_EXT_POL_SHIFT		2
+#define DA9150_AID_EXT_POL_MASK			(0x01 << 2)
+
+/* DA9150_ADETAC_CFG_A = 0x156 */
+#define DA9150_ISET_CDP_SHIFT			0
+#define DA9150_ISET_CDP_MASK			(0x1f << 0)
+#define DA9150_CONF_DBP_SHIFT			5
+#define DA9150_CONF_DBP_MASK			(0x01 << 5)
+
+/* DA9150_ADDETAC_CFG_B = 0x157 */
+#define DA9150_ISET_DCHG_SHIFT			0
+#define DA9150_ISET_DCHG_MASK			(0x1f << 0)
+#define DA9150_CONF_GPIOA_SHIFT			5
+#define DA9150_CONF_GPIOA_MASK			(0x01 << 5)
+#define DA9150_CONF_GPIOB_SHIFT			6
+#define DA9150_CONF_GPIOB_MASK			(0x01 << 6)
+#define DA9150_AID_VB_SHIFT			7
+#define DA9150_AID_VB_MASK			(0x01 << 7)
+
+/* DA9150_ADETAC_CFG_C = 0x158 */
+#define DA9150_ISET_DEF_SHIFT			0
+#define DA9150_ISET_DEF_MASK			(0x1f << 0)
+#define DA9150_CONF_MODE_SHIFT			5
+#define DA9150_CONF_MODE_MASK			(0x03 << 5)
+#define DA9150_AID_CR_DIS_SHIFT			7
+#define DA9150_AID_CR_DIS_MASK			(0x01 << 7)
+
+/* DA9150_ADETAC_CFG_D = 0x159 */
+#define DA9150_ISET_UNIT_SHIFT			0
+#define DA9150_ISET_UNIT_MASK			(0x1f << 0)
+#define DA9150_AID_UNCLAMP_SHIFT		5
+#define DA9150_AID_UNCLAMP_MASK			(0x01 << 5)
+
+/* DA9150_ADETVB_CFG_D = 0x15A */
+#define DA9150_ID_MODE_SHIFT			0
+#define DA9150_ID_MODE_MASK			(0x03 << 0)
+#define DA9150_DAT_MODE_SHIFT			2
+#define DA9150_DAT_MODE_MASK			(0x0f << 2)
+#define DA9150_DAT_SWP_SHIFT			6
+#define DA9150_DAT_SWP_MASK			(0x01 << 6)
+#define DA9150_DAT_CLAMP_EXT_SHIFT		7
+#define DA9150_DAT_CLAMP_EXT_MASK		(0x01 << 7)
+
+/* DA9150_ADETID_CFG_A = 0x15B */
+#define DA9150_TID_POLL_SHIFT			0
+#define DA9150_TID_POLL_MASK			(0x07 << 0)
+#define DA9150_RID_CONV_SHIFT			3
+#define DA9150_RID_CONV_MASK			(0x01 << 3)
+
+/* DA9150_ADET_RID_PT_CHG_H = 0x15C */
+#define DA9150_RID_PT_CHG_H_SHIFT		0
+#define DA9150_RID_PT_CHG_H_MASK		(0xff << 0)
+
+/* DA9150_ADET_RID_PT_CHG_L = 0x15D */
+#define DA9150_RID_PT_CHG_L_SHIFT		6
+#define DA9150_RID_PT_CHG_L_MASK		(0x03 << 6)
+
+/* DA9150_PPR_TCTR_B = 0x160 */
+#define DA9150_CHG_TCTR_VAL_SHIFT		0
+#define DA9150_CHG_TCTR_VAL_MASK		(0xff << 0)
+
+/* DA9150_PPR_BKCTRL_A = 0x163 */
+#define DA9150_VBUS_MODE_SHIFT			0
+#define DA9150_VBUS_MODE_MASK			(0x03 << 0)
+#define DA9150_VBUS_MODE_CHG			(0x01 << 0)
+#define DA9150_VBUS_MODE_OTG			(0x02 << 0)
+#define DA9150_VBUS_LPM_SHIFT			2
+#define DA9150_VBUS_LPM_MASK			(0x03 << 2)
+#define DA9150_VBUS_SUSP_SHIFT			4
+#define DA9150_VBUS_SUSP_MASK			(0x01 << 4)
+#define DA9150_VBUS_PWM_SHIFT			5
+#define DA9150_VBUS_PWM_MASK			(0x01 << 5)
+#define DA9150_VBUS_ISO_SHIFT			6
+#define DA9150_VBUS_ISO_MASK			(0x01 << 6)
+#define DA9150_VBUS_LDO_SHIFT			7
+#define DA9150_VBUS_LDO_MASK			(0x01 << 7)
+
+/* DA9150_PPR_BKCFG_A = 0x164 */
+#define DA9150_VBUS_ISET_SHIFT			0
+#define DA9150_VBUS_ISET_MASK			(0x1f << 0)
+#define DA9150_VBUS_IMAX_SHIFT			5
+#define DA9150_VBUS_IMAX_MASK			(0x01 << 5)
+#define DA9150_VBUS_IOTG_SHIFT			6
+#define DA9150_VBUS_IOTG_MASK			(0x03 << 6)
+
+/* DA9150_PPR_BKCFG_B = 0x165 */
+#define DA9150_VBUS_DROP_SHIFT			0
+#define DA9150_VBUS_DROP_MASK			(0x0f << 0)
+#define DA9150_VBUS_FAULT_DIS_SHIFT		6
+#define DA9150_VBUS_FAULT_DIS_MASK		(0x01 << 6)
+#define DA9150_OTG_FAULT_DIS_SHIFT		7
+#define DA9150_OTG_FAULT_DIS_MASK		(0x01 << 7)
+
+/* DA9150_PPR_CHGCTRL_A = 0x166 */
+#define DA9150_CHG_EN_SHIFT			0
+#define DA9150_CHG_EN_MASK			(0x01 << 0)
+
+/* DA9150_PPR_CHGCTRL_B = 0x167 */
+#define DA9150_CHG_VBAT_SHIFT			0
+#define DA9150_CHG_VBAT_MASK			(0x1f << 0)
+#define DA9150_CHG_VDROP_SHIFT			6
+#define DA9150_CHG_VDROP_MASK			(0x03 << 6)
+
+/* DA9150_PPR_CHGCTRL_C = 0x168 */
+#define DA9150_CHG_VFAULT_SHIFT			0
+#define DA9150_CHG_VFAULT_MASK			(0x0f << 0)
+#define DA9150_CHG_IPRE_SHIFT			4
+#define DA9150_CHG_IPRE_MASK			(0x03 << 4)
+
+/* DA9150_PPR_TCTR_A = 0x169 */
+#define DA9150_CHG_TCTR_SHIFT			0
+#define DA9150_CHG_TCTR_MASK			(0x07 << 0)
+#define DA9150_CHG_TCTR_MODE_SHIFT		4
+#define DA9150_CHG_TCTR_MODE_MASK		(0x01 << 4)
+
+/* DA9150_PPR_CHGCTRL_D = 0x16A */
+#define DA9150_CHG_IBAT_SHIFT			0
+#define DA9150_CHG_IBAT_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_E = 0x16B */
+#define DA9150_CHG_IEND_SHIFT			0
+#define DA9150_CHG_IEND_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_F = 0x16C */
+#define DA9150_CHG_VCOLD_SHIFT			0
+#define DA9150_CHG_VCOLD_MASK			(0x1f << 0)
+#define DA9150_TBAT_TQA_EN_SHIFT		6
+#define DA9150_TBAT_TQA_EN_MASK			(0x01 << 6)
+#define DA9150_TBAT_TDP_EN_SHIFT		7
+#define DA9150_TBAT_TDP_EN_MASK			(0x01 << 7)
+
+/* DA9150_PPR_CHGCTRL_G = 0x16D */
+#define DA9150_CHG_VWARM_SHIFT			0
+#define DA9150_CHG_VWARM_MASK			(0x1f << 0)
+
+/* DA9150_PPR_CHGCTRL_H = 0x16E */
+#define DA9150_CHG_VHOT_SHIFT			0
+#define DA9150_CHG_VHOT_MASK			(0x1f << 0)
+
+/* DA9150_PPR_CHGCTRL_I = 0x16F */
+#define DA9150_CHG_ICOLD_SHIFT			0
+#define DA9150_CHG_ICOLD_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_J = 0x170 */
+#define DA9150_CHG_IWARM_SHIFT			0
+#define DA9150_CHG_IWARM_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_K = 0x171 */
+#define DA9150_CHG_IHOT_SHIFT			0
+#define DA9150_CHG_IHOT_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_L = 0x172 */
+#define DA9150_CHG_IBAT_TRED_SHIFT		0
+#define DA9150_CHG_IBAT_TRED_MASK		(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_M = 0x173 */
+#define DA9150_CHG_VFLOAT_SHIFT			0
+#define DA9150_CHG_VFLOAT_MASK			(0x0f << 0)
+#define DA9150_CHG_LPM_SHIFT			5
+#define DA9150_CHG_LPM_MASK			(0x01 << 5)
+#define DA9150_CHG_NBLO_SHIFT			6
+#define DA9150_CHG_NBLO_MASK			(0x01 << 6)
+#define DA9150_EBS_EN_SHIFT			7
+#define DA9150_EBS_EN_MASK			(0x01 << 7)
+
+/* DA9150_PPR_THYST_A = 0x174 */
+#define DA9150_TBAT_T1_SHIFT			0
+#define DA9150_TBAT_T1_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_B = 0x175 */
+#define DA9150_TBAT_T2_SHIFT			0
+#define DA9150_TBAT_T2_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_C = 0x176 */
+#define DA9150_TBAT_T3_SHIFT			0
+#define DA9150_TBAT_T3_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_D = 0x177 */
+#define DA9150_TBAT_T4_SHIFT			0
+#define DA9150_TBAT_T4_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_E = 0x178 */
+#define DA9150_TBAT_T5_SHIFT			0
+#define DA9150_TBAT_T5_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_F = 0x179 */
+#define DA9150_TBAT_H1_SHIFT			0
+#define DA9150_TBAT_H1_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_G = 0x17A */
+#define DA9150_TBAT_H5_SHIFT			0
+#define DA9150_TBAT_H5_MASK			(0xff << 0)
+
+/* DA9150_PAGE_CON_3 = 0x180 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_PAGE_CON_4 = 0x200 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_PAGE_CON_5 = 0x280 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_PAGE_CON_6 = 0x300 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_COREBTLD_STAT_A = 0x302 */
+#define DA9150_BOOTLD_STAT_SHIFT		0
+#define DA9150_BOOTLD_STAT_MASK			(0x03 << 0)
+#define DA9150_CORE_LOCKUP_SHIFT		2
+#define DA9150_CORE_LOCKUP_MASK			(0x01 << 2)
+
+/* DA9150_COREBTLD_CTRL_A = 0x303 */
+#define DA9150_CORE_RESET_SHIFT			0
+#define DA9150_CORE_RESET_MASK			(0x01 << 0)
+#define DA9150_CORE_STOP_SHIFT			1
+#define DA9150_CORE_STOP_MASK			(0x01 << 1)
+
+/* DA9150_CORE_CONFIG_A = 0x304 */
+#define DA9150_CORE_MEMMUX_SHIFT		0
+#define DA9150_CORE_MEMMUX_MASK			(0x03 << 0)
+#define DA9150_WDT_AUTO_START_SHIFT		2
+#define DA9150_WDT_AUTO_START_MASK		(0x01 << 2)
+#define DA9150_WDT_AUTO_LOCK_SHIFT		3
+#define DA9150_WDT_AUTO_LOCK_MASK		(0x01 << 3)
+#define DA9150_WDT_HLT_NO_CLK_SHIFT		4
+#define DA9150_WDT_HLT_NO_CLK_MASK		(0x01 << 4)
+
+/* DA9150_CORE_CONFIG_C = 0x305 */
+#define DA9150_CORE_SW_SIZE_SHIFT		0
+#define DA9150_CORE_SW_SIZE_MASK		(0xff << 0)
+
+/* DA9150_CORE_CONFIG_B = 0x306 */
+#define DA9150_BOOTLD_EN_SHIFT			0
+#define DA9150_BOOTLD_EN_MASK			(0x01 << 0)
+#define DA9150_CORE_EN_SHIFT			2
+#define DA9150_CORE_EN_MASK			(0x01 << 2)
+#define DA9150_CORE_SW_SRC_SHIFT		3
+#define DA9150_CORE_SW_SRC_MASK			(0x07 << 3)
+#define DA9150_DEEP_SLEEP_EN_SHIFT		7
+#define DA9150_DEEP_SLEEP_EN_MASK		(0x01 << 7)
+
+/* DA9150_CORE_CFG_DATA_A = 0x307 */
+#define DA9150_CORE_CFG_DT_A_SHIFT		0
+#define DA9150_CORE_CFG_DT_A_MASK		(0xff << 0)
+
+/* DA9150_CORE_CFG_DATA_B = 0x308 */
+#define DA9150_CORE_CFG_DT_B_SHIFT		0
+#define DA9150_CORE_CFG_DT_B_MASK		(0xff << 0)
+
+/* DA9150_CORE_CMD_A = 0x309 */
+#define DA9150_CORE_CMD_SHIFT			0
+#define DA9150_CORE_CMD_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_A = 0x30A */
+#define DA9150_CORE_DATA_0_SHIFT		0
+#define DA9150_CORE_DATA_0_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_B = 0x30B */
+#define DA9150_CORE_DATA_1_SHIFT		0
+#define DA9150_CORE_DATA_1_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_C = 0x30C */
+#define DA9150_CORE_DATA_2_SHIFT		0
+#define DA9150_CORE_DATA_2_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_D = 0x30D */
+#define DA9150_CORE_DATA_3_SHIFT		0
+#define DA9150_CORE_DATA_3_MASK			(0xff << 0)
+
+/* DA9150_CORE2WIRE_STAT_A = 0x310 */
+#define DA9150_FW_FWDL_ERR_SHIFT		7
+#define DA9150_FW_FWDL_ERR_MASK			(0x01 << 7)
+
+/* DA9150_CORE2WIRE_CTRL_A = 0x311 */
+#define DA9150_FW_FWDL_EN_SHIFT			0
+#define DA9150_FW_FWDL_EN_MASK			(0x01 << 0)
+#define DA9150_FG_QIF_EN_SHIFT			1
+#define DA9150_FG_QIF_EN_MASK			(0x01 << 1)
+#define DA9150_CORE_BASE_ADDR_SHIFT		4
+#define DA9150_CORE_BASE_ADDR_MASK		(0x0f << 4)
+
+/* DA9150_FW_CTRL_A = 0x312 */
+#define DA9150_FW_SEAL_SHIFT			0
+#define DA9150_FW_SEAL_MASK			(0xff << 0)
+
+/* DA9150_FW_CTRL_C = 0x313 */
+#define DA9150_FW_FWDL_CRC_SHIFT		0
+#define DA9150_FW_FWDL_CRC_MASK			(0xff << 0)
+
+/* DA9150_FW_CTRL_D = 0x314 */
+#define DA9150_FW_FWDL_BASE_SHIFT		0
+#define DA9150_FW_FWDL_BASE_MASK		(0x0f << 0)
+
+/* DA9150_FG_CTRL_A = 0x315 */
+#define DA9150_FG_QIF_CODE_SHIFT		0
+#define DA9150_FG_QIF_CODE_MASK			(0xff << 0)
+
+/* DA9150_FG_CTRL_B = 0x316 */
+#define DA9150_FG_QIF_VALUE_SHIFT		0
+#define DA9150_FG_QIF_VALUE_MASK		(0xff << 0)
+
+/* DA9150_FW_CTRL_E = 0x317 */
+#define DA9150_FW_FWDL_SEG_SHIFT		0
+#define DA9150_FW_FWDL_SEG_MASK			(0xff << 0)
+
+/* DA9150_FW_CTRL_B = 0x318 */
+#define DA9150_FW_FWDL_VALUE_SHIFT		0
+#define DA9150_FW_FWDL_VALUE_MASK		(0xff << 0)
+
+/* DA9150_GPADC_CMAN = 0x320 */
+#define DA9150_GPADC_CEN_SHIFT			0
+#define DA9150_GPADC_CEN_MASK			(0x01 << 0)
+#define DA9150_GPADC_CMUX_SHIFT			1
+#define DA9150_GPADC_CMUX_MASK			(0x1f << 1)
+
+/* DA9150_GPADC_CRES_A = 0x322 */
+#define DA9150_GPADC_CRES_H_SHIFT		0
+#define DA9150_GPADC_CRES_H_MASK		(0xff << 0)
+
+/* DA9150_GPADC_CRES_B = 0x323 */
+#define DA9150_GPADC_CRUN_SHIFT			0
+#define DA9150_GPADC_CRUN_MASK			(0x01 << 0)
+#define DA9150_GPADC_CRES_L_SHIFT		6
+#define DA9150_GPADC_CRES_L_MASK		(0x03 << 6)
+
+/* DA9150_CC_CFG_A = 0x328 */
+#define DA9150_CC_EN_SHIFT			0
+#define DA9150_CC_EN_MASK			(0x01 << 0)
+#define DA9150_CC_TIMEBASE_SHIFT		1
+#define DA9150_CC_TIMEBASE_MASK			(0x03 << 1)
+#define DA9150_CC_CFG_SHIFT			5
+#define DA9150_CC_CFG_MASK			(0x03 << 5)
+#define DA9150_CC_ENDLESS_MODE_SHIFT		7
+#define DA9150_CC_ENDLESS_MODE_MASK		(0x01 << 7)
+
+/* DA9150_CC_CFG_B = 0x329 */
+#define DA9150_CC_OPT_SHIFT			0
+#define DA9150_CC_OPT_MASK			(0x03 << 0)
+#define DA9150_CC_PREAMP_SHIFT			2
+#define DA9150_CC_PREAMP_MASK			(0x03 << 2)
+
+/* DA9150_CC_ICHG_RES_A = 0x32A */
+#define DA9150_CC_ICHG_RES_H_SHIFT		0
+#define DA9150_CC_ICHG_RES_H_MASK		(0xff << 0)
+
+/* DA9150_CC_ICHG_RES_B = 0x32B */
+#define DA9150_CC_ICHG_RES_L_SHIFT		3
+#define DA9150_CC_ICHG_RES_L_MASK		(0x1f << 3)
+
+/* DA9150_CC_IAVG_RES_A = 0x32C */
+#define DA9150_CC_IAVG_RES_H_SHIFT		0
+#define DA9150_CC_IAVG_RES_H_MASK		(0xff << 0)
+
+/* DA9150_CC_IAVG_RES_B = 0x32D */
+#define DA9150_CC_IAVG_RES_L_SHIFT		0
+#define DA9150_CC_IAVG_RES_L_MASK		(0xff << 0)
+
+/* DA9150_TAUX_CTRL_A = 0x330 */
+#define DA9150_TAUX_EN_SHIFT			0
+#define DA9150_TAUX_EN_MASK			(0x01 << 0)
+#define DA9150_TAUX_MOD_SHIFT			1
+#define DA9150_TAUX_MOD_MASK			(0x01 << 1)
+#define DA9150_TAUX_UPDATE_SHIFT		2
+#define DA9150_TAUX_UPDATE_MASK			(0x01 << 2)
+
+/* DA9150_TAUX_RELOAD_H = 0x332 */
+#define DA9150_TAUX_RLD_H_SHIFT			0
+#define DA9150_TAUX_RLD_H_MASK			(0xff << 0)
+
+/* DA9150_TAUX_RELOAD_L = 0x333 */
+#define DA9150_TAUX_RLD_L_SHIFT			3
+#define DA9150_TAUX_RLD_L_MASK			(0x1f << 3)
+
+/* DA9150_TAUX_VALUE_H = 0x334 */
+#define DA9150_TAUX_VAL_H_SHIFT			0
+#define DA9150_TAUX_VAL_H_MASK			(0xff << 0)
+
+/* DA9150_TAUX_VALUE_L = 0x335 */
+#define DA9150_TAUX_VAL_L_SHIFT			3
+#define DA9150_TAUX_VAL_L_MASK			(0x1f << 3)
+
+/* DA9150_AUX_DATA_0 = 0x338 */
+#define DA9150_AUX_DAT_0_SHIFT			0
+#define DA9150_AUX_DAT_0_MASK			(0xff << 0)
+
+/* DA9150_AUX_DATA_1 = 0x339 */
+#define DA9150_AUX_DAT_1_SHIFT			0
+#define DA9150_AUX_DAT_1_MASK			(0xff << 0)
+
+/* DA9150_AUX_DATA_2 = 0x33A */
+#define DA9150_AUX_DAT_2_SHIFT			0
+#define DA9150_AUX_DAT_2_MASK			(0xff << 0)
+
+/* DA9150_AUX_DATA_3 = 0x33B */
+#define DA9150_AUX_DAT_3_SHIFT			0
+#define DA9150_AUX_DAT_3_MASK			(0xff << 0)
+
+/* DA9150_BIF_CTRL = 0x340 */
+#define DA9150_BIF_ISRC_EN_SHIFT		0
+#define DA9150_BIF_ISRC_EN_MASK			(0x01 << 0)
+
+/* DA9150_TBAT_CTRL_A = 0x342 */
+#define DA9150_TBAT_EN_SHIFT			0
+#define DA9150_TBAT_EN_MASK			(0x01 << 0)
+#define DA9150_TBAT_SW1_SHIFT			1
+#define DA9150_TBAT_SW1_MASK			(0x01 << 1)
+#define DA9150_TBAT_SW2_SHIFT			2
+#define DA9150_TBAT_SW2_MASK			(0x01 << 2)
+
+/* DA9150_TBAT_CTRL_B = 0x343 */
+#define DA9150_TBAT_SW_FRC_SHIFT		0
+#define DA9150_TBAT_SW_FRC_MASK			(0x01 << 0)
+#define DA9150_TBAT_STAT_SW1_SHIFT		1
+#define DA9150_TBAT_STAT_SW1_MASK		(0x01 << 1)
+#define DA9150_TBAT_STAT_SW2_SHIFT		2
+#define DA9150_TBAT_STAT_SW2_MASK		(0x01 << 2)
+#define DA9150_TBAT_HIGH_CURR_SHIFT		3
+#define DA9150_TBAT_HIGH_CURR_MASK		(0x01 << 3)
+
+/* DA9150_TBAT_RES_A = 0x344 */
+#define DA9150_TBAT_RES_H_SHIFT			0
+#define DA9150_TBAT_RES_H_MASK			(0xff << 0)
+
+/* DA9150_TBAT_RES_B = 0x345 */
+#define DA9150_TBAT_RES_DIS_SHIFT		0
+#define DA9150_TBAT_RES_DIS_MASK		(0x01 << 0)
+#define DA9150_TBAT_RES_L_SHIFT			6
+#define DA9150_TBAT_RES_L_MASK			(0x03 << 6)
+
+#endif /* __DA9150_REGISTERS_H */
--
1.9.3


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

* [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-08-28 10:48   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

DA9150 is a combined Charger and Fuel-Gauge IC, with additional
GPIO and GPADC functionality.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 drivers/mfd/Kconfig                  |   12 +
 drivers/mfd/Makefile                 |    2 +
 drivers/mfd/da9150-core.c            |  332 ++++++++++
 drivers/mfd/da9150-i2c.c             |  176 ++++++
 include/linux/mfd/da9150/core.h      |   80 +++
 include/linux/mfd/da9150/pdata.h     |   21 +
 include/linux/mfd/da9150/registers.h | 1153 ++++++++++++++++++++++++++++++++++
 7 files changed, 1776 insertions(+)
 create mode 100644 drivers/mfd/da9150-core.c
 create mode 100644 drivers/mfd/da9150-i2c.c
 create mode 100644 include/linux/mfd/da9150/core.h
 create mode 100644 include/linux/mfd/da9150/pdata.h
 create mode 100644 include/linux/mfd/da9150/registers.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index de5abf2..76adb2c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -183,6 +183,18 @@ config MFD_DA9063
 	  Additional drivers must be enabled in order to use the functionality
 	  of the device.

+config MFD_DA9150
+	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
+	depends on I2C=y
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	help
+	  This adds support for the DA9150 integrated charger and fuel-gauge
+	  chip. This driver provides common support for accessing the device.
+	  Additional drivers must be enabled in order to use the specific
+	  features of the device.
+
 config MFD_MC13XXX
 	tristate
 	depends on (SPI_MASTER || I2C)
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f001487..098dfa1 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
 da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
 obj-$(CONFIG_MFD_DA9063)	+= da9063.o

+obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
+
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
 obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
new file mode 100644
index 0000000..029a30b
--- /dev/null
+++ b/drivers/mfd/da9150-core.c
@@ -0,0 +1,332 @@
+/*
+ * DA9150 Core MFD Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/registers.h>
+#include <linux/mfd/da9150/pdata.h>
+
+u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
+{
+	int val, ret;
+
+	ret = regmap_read(da9150->regmap, reg, &val);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
+			reg, ret);
+
+	return (u8) val;
+}
+EXPORT_SYMBOL_GPL(da9150_reg_read);
+
+int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
+{
+	int ret;
+
+	ret = regmap_write(da9150->regmap, reg, val);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_reg_write);
+
+int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
+{
+	int ret;
+
+	ret = regmap_update_bits(da9150->regmap, reg, mask, val);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_set_bits);
+
+int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
+{
+	int ret;
+
+	ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_bulk_read);
+
+int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
+{
+	int ret;
+
+	ret = regmap_raw_write(da9150->regmap, reg, buf, count);
+	if (ret < 0)
+		dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
+			reg, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_bulk_write);
+
+static struct regmap_irq da9150_irqs[] = {
+	[DA9150_IRQ_VBUS] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_VBUS_MASK,
+	},
+	[DA9150_IRQ_CHG] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_CHG_MASK,
+	},
+	[DA9150_IRQ_TCLASS] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_TCLASS_MASK,
+	},
+	[DA9150_IRQ_TJUNC] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_TJUNC_MASK,
+	},
+	[DA9150_IRQ_VFAULT] = {
+		.reg_offset = 0,
+		.mask = DA9150_E_VFAULT_MASK,
+	},
+	[DA9150_IRQ_CONF] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_CONF_MASK,
+	},
+	[DA9150_IRQ_DAT] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_DAT_MASK,
+	},
+	[DA9150_IRQ_DTYPE] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_DTYPE_MASK,
+	},
+	[DA9150_IRQ_ID] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_ID_MASK,
+	},
+	[DA9150_IRQ_ADP] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_ADP_MASK,
+	},
+	[DA9150_IRQ_SESS_END] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_SESS_END_MASK,
+	},
+	[DA9150_IRQ_SESS_VLD] = {
+		.reg_offset = 1,
+		.mask = DA9150_E_SESS_VLD_MASK,
+	},
+	[DA9150_IRQ_FG] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_FG_MASK,
+	},
+	[DA9150_IRQ_GP] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GP_MASK,
+	},
+	[DA9150_IRQ_TBAT] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_TBAT_MASK,
+	},
+	[DA9150_IRQ_GPIOA] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOA_MASK,
+	},
+	[DA9150_IRQ_GPIOB] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOB_MASK,
+	},
+	[DA9150_IRQ_GPIOC] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOC_MASK,
+	},
+	[DA9150_IRQ_GPIOD] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPIOD_MASK,
+	},
+	[DA9150_IRQ_GPADC] = {
+		.reg_offset = 2,
+		.mask = DA9150_E_GPADC_MASK,
+	},
+	[DA9150_IRQ_WKUP] = {
+		.reg_offset = 3,
+		.mask = DA9150_E_WKUP_MASK,
+	},
+};
+
+static struct regmap_irq_chip da9150_regmap_irq_chip = {
+	.name = "da9150_irq",
+	.status_base = DA9150_EVENT_E,
+	.mask_base = DA9150_IRQ_MASK_E,
+	.ack_base = DA9150_EVENT_E,
+	.num_regs = DA9150_NUM_IRQ_REGS,
+	.irqs = da9150_irqs,
+	.num_irqs = ARRAY_SIZE(da9150_irqs),
+};
+
+/* Helper functions for sub-devices to request/free IRQs */
+int da9150_register_irq(struct platform_device *pdev, void *dev_id,
+			irq_handler_t handler, const char *name)
+{
+	int irq, ret;
+
+	irq = platform_get_irq_byname(pdev, name);
+	if (irq < 0)
+		return irq;
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
+					IRQF_ONESHOT, name, dev_id);
+	if (ret)
+		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(da9150_register_irq);
+
+void da9150_release_irq(struct platform_device *pdev, void *dev_id,
+		       const char *name)
+{
+	int irq;
+
+	irq = platform_get_irq_byname(pdev, name);
+	if (irq < 0)
+		return;
+
+	devm_free_irq(&pdev->dev, irq, dev_id);
+}
+EXPORT_SYMBOL_GPL(da9150_release_irq);
+
+static struct resource da9150_gpadc_resources[] = {
+	{
+		.name = "GPADC",
+		.start = DA9150_IRQ_GPADC,
+		.end = DA9150_IRQ_GPADC,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct resource da9150_charger_resources[] = {
+	{
+		.name = "CHG_STATUS",
+		.start = DA9150_IRQ_CHG,
+		.end = DA9150_IRQ_CHG,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "CHG_TJUNC",
+		.start = DA9150_IRQ_TJUNC,
+		.end = DA9150_IRQ_TJUNC,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "CHG_VFAULT",
+		.start = DA9150_IRQ_VFAULT,
+		.end = DA9150_IRQ_VFAULT,
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.name = "CHG_VBUS",
+		.start = DA9150_IRQ_VBUS,
+		.end = DA9150_IRQ_VBUS,
+		.flags = IORESOURCE_IRQ,
+	},
+};
+
+static struct mfd_cell da9150_devs[] = {
+	{
+		.name = "da9150-gpadc",
+		.of_compatible = "dlg,da9150-gpadc",
+		.resources = da9150_gpadc_resources,
+		.num_resources = ARRAY_SIZE(da9150_gpadc_resources),
+	},
+	{
+		.name = "da9150-charger",
+		.of_compatible = "dlg,da9150-charger",
+		.resources = da9150_charger_resources,
+		.num_resources = ARRAY_SIZE(da9150_charger_resources),
+	},
+};
+
+int da9150_device_init(struct da9150 *da9150)
+{
+	struct da9150_pdata *pdata = da9150->dev->platform_data;
+	int ret;
+
+	/* Handle platform data */
+	if (pdata)
+		da9150->irq_base = pdata->irq_base;
+	else
+		da9150->irq_base = -1;
+
+	/* Init IRQs */
+	ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
+				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+				  da9150->irq_base, &da9150_regmap_irq_chip,
+				  &da9150->regmap_irq_data);
+	if (ret < 0)
+		goto err_irq;
+
+	da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
+
+	/* Make the IRQ line a wake source */
+	enable_irq_wake(da9150->irq);
+
+	/* Add MFD Devices */
+	ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
+			      ARRAY_SIZE(da9150_devs), NULL,
+			      da9150->irq_base, NULL);
+	if (ret < 0) {
+		dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
+		goto err_mfd;
+	}
+
+	return 0;
+
+err_mfd:
+	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+err_irq:
+	return ret;
+}
+
+void da9150_device_exit(struct da9150 *da9150)
+{
+	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+	mfd_remove_devices(da9150->dev);
+}
+
+void da9150_device_shutdown(struct da9150 *da9150)
+{
+	/* Make sure we have a wakup source for the device */
+	da9150_set_bits(da9150, DA9150_CONFIG_D,
+			DA9150_WKUP_PM_EN_MASK,
+			DA9150_WKUP_PM_EN_MASK);
+
+	/* Set device to DISABLED mode */
+	da9150_set_bits(da9150, DA9150_CONTROL_C,
+			DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
+}
+
+MODULE_DESCRIPTION("MFD Core Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/da9150-i2c.c b/drivers/mfd/da9150-i2c.c
new file mode 100644
index 0000000..a02525c
--- /dev/null
+++ b/drivers/mfd/da9150-i2c.c
@@ -0,0 +1,176 @@
+/*
+ * DA9150 I2C Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/registers.h>
+
+static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
+{
+	switch (reg) {
+	case DA9150_PAGE_CON:
+	case DA9150_STATUS_A:
+	case DA9150_STATUS_B:
+	case DA9150_STATUS_C:
+	case DA9150_STATUS_D:
+	case DA9150_STATUS_E:
+	case DA9150_STATUS_F:
+	case DA9150_STATUS_G:
+	case DA9150_STATUS_H:
+	case DA9150_STATUS_I:
+	case DA9150_STATUS_J:
+	case DA9150_STATUS_K:
+	case DA9150_STATUS_L:
+	case DA9150_STATUS_N:
+	case DA9150_FAULT_LOG_A:
+	case DA9150_FAULT_LOG_B:
+	case DA9150_EVENT_E:
+	case DA9150_EVENT_F:
+	case DA9150_EVENT_G:
+	case DA9150_EVENT_H:
+	case DA9150_CONTROL_B:
+	case DA9150_CONTROL_C:
+	case DA9150_GPADC_MAN:
+	case DA9150_GPADC_RES_A:
+	case DA9150_GPADC_RES_B:
+	case DA9150_ADETVB_CFG_C:
+	case DA9150_ADETD_STAT:
+	case DA9150_ADET_CMPSTAT:
+	case DA9150_ADET_CTRL_A:
+	case DA9150_PPR_TCTR_B:
+	case DA9150_COREBTLD_STAT_A:
+	case DA9150_CORE_DATA_A:
+	case DA9150_CORE_DATA_B:
+	case DA9150_CORE_DATA_C:
+	case DA9150_CORE_DATA_D:
+	case DA9150_CORE2WIRE_STAT_A:
+	case DA9150_FW_CTRL_C:
+	case DA9150_FG_CTRL_B:
+	case DA9150_FW_CTRL_B:
+	case DA9150_GPADC_CMAN:
+	case DA9150_GPADC_CRES_A:
+	case DA9150_GPADC_CRES_B:
+	case DA9150_CC_ICHG_RES_A:
+	case DA9150_CC_ICHG_RES_B:
+	case DA9150_CC_IAVG_RES_A:
+	case DA9150_CC_IAVG_RES_B:
+	case DA9150_TAUX_CTRL_A:
+	case DA9150_TAUX_VALUE_H:
+	case DA9150_TAUX_VALUE_L:
+	case DA9150_TBAT_RES_A:
+	case DA9150_TBAT_RES_B:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static const struct regmap_range_cfg da9150_range_cfg[] = {
+	{
+		.range_min = DA9150_PAGE_CON,
+		.range_max = DA9150_TBAT_RES_B,
+		.selector_reg = DA9150_PAGE_CON,
+		.selector_mask = DA9150_I2C_PAGE_MASK,
+		.selector_shift = DA9150_I2C_PAGE_SHIFT,
+		.window_start = 0,
+		.window_len = 256,
+	},
+};
+
+static struct regmap_config da9150_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.ranges = da9150_range_cfg,
+	.num_ranges = ARRAY_SIZE(da9150_range_cfg),
+	.max_register = DA9150_TBAT_RES_B,
+
+	.cache_type = REGCACHE_RBTREE,
+
+	.volatile_reg = da9150_volatile_reg,
+};
+
+static int da9150_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct da9150 *da9150;
+	int ret;
+
+	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
+	if (da9150 == NULL)
+		return -ENOMEM;
+	da9150->dev = &client->dev;
+	da9150->irq = client->irq;
+	i2c_set_clientdata(client, da9150);
+	dev_set_drvdata(da9150->dev, da9150);
+
+	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
+	if (IS_ERR(da9150->regmap)) {
+		ret = PTR_ERR(da9150->regmap);
+		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	return da9150_device_init(da9150);
+}
+
+static int da9150_remove(struct i2c_client *client)
+{
+	struct da9150 *da9150 = i2c_get_clientdata(client);
+
+	da9150_device_exit(da9150);
+
+	return 0;
+}
+
+static void da9150_shutdown(struct i2c_client *client)
+{
+	struct da9150 *da9150 = i2c_get_clientdata(client);
+
+	da9150_device_shutdown(da9150);
+}
+
+static const struct i2c_device_id da9150_i2c_id[] = {
+	{ "da9150", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
+
+static const struct of_device_id da9150_of_match[] = {
+	{ .compatible = "dlg,da9150", },
+	{ }
+};
+
+static struct i2c_driver da9150_driver = {
+	.driver	= {
+		.name	= "da9150",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(da9150_of_match),
+	},
+	.probe		= da9150_probe,
+	.remove		= da9150_remove,
+	.shutdown	= da9150_shutdown,
+	.id_table	= da9150_i2c_id,
+};
+
+module_i2c_driver(da9150_driver);
+
+MODULE_DESCRIPTION("I2C Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/da9150/core.h b/include/linux/mfd/da9150/core.h
new file mode 100644
index 0000000..d23c500
--- /dev/null
+++ b/include/linux/mfd/da9150/core.h
@@ -0,0 +1,80 @@
+/*
+ * DA9150 MFD Driver - Core Data
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
+ */
+
+#ifndef __DA9150_CORE_H
+#define __DA9150_CORE_H
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/mutex.h>
+
+/* I2C address paging */
+#define DA9150_REG_PAGE_SHIFT	8
+#define DA9150_REG_PAGE_MASK	0xFF
+
+/* IRQs */
+#define DA9150_NUM_IRQ_REGS	4
+#define DA9150_IRQ_VBUS		0
+#define DA9150_IRQ_CHG		1
+#define DA9150_IRQ_TCLASS	2
+#define DA9150_IRQ_TJUNC	3
+#define DA9150_IRQ_VFAULT	4
+#define DA9150_IRQ_CONF		5
+#define DA9150_IRQ_DAT		6
+#define DA9150_IRQ_DTYPE	7
+#define DA9150_IRQ_ID		8
+#define DA9150_IRQ_ADP		9
+#define DA9150_IRQ_SESS_END	10
+#define DA9150_IRQ_SESS_VLD	11
+#define DA9150_IRQ_FG		12
+#define DA9150_IRQ_GP		13
+#define DA9150_IRQ_TBAT		14
+#define DA9150_IRQ_GPIOA	15
+#define DA9150_IRQ_GPIOB	16
+#define DA9150_IRQ_GPIOC	17
+#define DA9150_IRQ_GPIOD	18
+#define DA9150_IRQ_GPADC	19
+#define DA9150_IRQ_WKUP		20
+
+struct da9150 {
+	struct device *dev;
+
+	struct regmap *regmap;
+
+	struct regmap_irq_chip_data *regmap_irq_data;
+	int irq;
+	int irq_base;
+};
+
+/* Device I/O */
+u8 da9150_reg_read(struct da9150 *da9150, u16 reg);
+int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val);
+int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val);
+
+int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf);
+int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf);
+
+/* IRQ helper functions */
+int da9150_register_irq(struct platform_device *pdev, void *dev_id,
+			irq_handler_t handler, const char *name);
+void da9150_release_irq(struct platform_device *pdev, void *dev_id,
+			const char *name);
+
+/* Init/Exit */
+int da9150_device_init(struct da9150 *da9150);
+void da9150_device_exit(struct da9150 *da9150);
+void da9150_device_shutdown(struct da9150 *da9150);
+
+#endif /* __DA9150_CORE_H */
diff --git a/include/linux/mfd/da9150/pdata.h b/include/linux/mfd/da9150/pdata.h
new file mode 100644
index 0000000..e2b37f1
--- /dev/null
+++ b/include/linux/mfd/da9150/pdata.h
@@ -0,0 +1,21 @@
+/*
+ * DA9150 MFD Driver - Platform Data
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
+ */
+
+#ifndef __DA9150_PDATA_H
+#define __DA9150_PDATA_H
+
+struct da9150_pdata {
+	int irq_base;
+};
+
+#endif /* __DA9150_PDATA_H */
diff --git a/include/linux/mfd/da9150/registers.h b/include/linux/mfd/da9150/registers.h
new file mode 100644
index 0000000..ef4826d
--- /dev/null
+++ b/include/linux/mfd/da9150/registers.h
@@ -0,0 +1,1153 @@
+/*
+ * DA9150 MFD Driver - Registers
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
+ */
+
+#ifndef __DA9150_REGISTERS_H
+#define __DA9150_REGISTERS_H
+
+/* Registers */
+#define DA9150_PAGE_CON			0x000
+#define DA9150_STATUS_A			0x068
+#define DA9150_STATUS_B			0x069
+#define DA9150_STATUS_C			0x06A
+#define DA9150_STATUS_D			0x06B
+#define DA9150_STATUS_E			0x06C
+#define DA9150_STATUS_F			0x06D
+#define DA9150_STATUS_G			0x06E
+#define DA9150_STATUS_H			0x06F
+#define DA9150_STATUS_I			0x070
+#define DA9150_STATUS_J			0x071
+#define DA9150_STATUS_K			0x072
+#define DA9150_STATUS_L			0x073
+#define DA9150_STATUS_N			0x074
+#define DA9150_FAULT_LOG_A		0x076
+#define DA9150_FAULT_LOG_B		0x077
+#define DA9150_EVENT_E			0x078
+#define DA9150_EVENT_F			0x079
+#define DA9150_EVENT_G			0x07A
+#define DA9150_EVENT_H			0x07B
+#define DA9150_IRQ_MASK_E		0x07C
+#define DA9150_IRQ_MASK_F		0x07D
+#define DA9150_IRQ_MASK_G		0x07E
+#define DA9150_IRQ_MASK_H		0x07F
+#define DA9150_PAGE_CON_1		0x080
+#define DA9150_CONFIG_A			0x0E0
+#define DA9150_CONFIG_B			0x0E1
+#define DA9150_CONFIG_C			0x0E2
+#define DA9150_CONFIG_D			0x0E3
+#define DA9150_CONFIG_E			0x0E4
+#define DA9150_CONTROL_A		0x0E5
+#define DA9150_CONTROL_B		0x0E6
+#define DA9150_CONTROL_C		0x0E7
+#define DA9150_GPIO_A_B			0x0E8
+#define DA9150_GPIO_C_D			0x0E9
+#define DA9150_GPIO_MODE_CONT		0x0EA
+#define DA9150_GPIO_CTRL_B		0x0EB
+#define DA9150_GPIO_CTRL_A		0x0EC
+#define DA9150_GPIO_CTRL_C		0x0ED
+#define DA9150_GPIO_CFG_A		0x0EE
+#define DA9150_GPIO_CFG_B		0x0EF
+#define DA9150_GPIO_CFG_C		0x0F0
+#define DA9150_GPADC_MAN		0x0F2
+#define DA9150_GPADC_RES_A		0x0F4
+#define DA9150_GPADC_RES_B		0x0F5
+#define DA9150_PAGE_CON_2		0x100
+#define DA9150_OTP_CONT_SHARED		0x101
+#define DA9150_INTERFACE_SHARED		0x105
+#define DA9150_CONFIG_A_SHARED		0x106
+#define DA9150_CONFIG_D_SHARED		0x109
+#define DA9150_ADETVB_CFG_C		0x150
+#define DA9150_ADETD_STAT		0x151
+#define DA9150_ADET_CMPSTAT		0x152
+#define DA9150_ADET_CTRL_A		0x153
+#define DA9150_ADETVB_CFG_B		0x154
+#define DA9150_ADETVB_CFG_A		0x155
+#define DA9150_ADETAC_CFG_A		0x156
+#define DA9150_ADDETAC_CFG_B		0x157
+#define DA9150_ADETAC_CFG_C		0x158
+#define DA9150_ADETAC_CFG_D		0x159
+#define DA9150_ADETVB_CFG_D		0x15A
+#define DA9150_ADETID_CFG_A		0x15B
+#define DA9150_ADET_RID_PT_CHG_H	0x15C
+#define DA9150_ADET_RID_PT_CHG_L	0x15D
+#define DA9150_PPR_TCTR_B		0x160
+#define DA9150_PPR_BKCTRL_A		0x163
+#define DA9150_PPR_BKCFG_A		0x164
+#define DA9150_PPR_BKCFG_B		0x165
+#define DA9150_PPR_CHGCTRL_A		0x166
+#define DA9150_PPR_CHGCTRL_B		0x167
+#define DA9150_PPR_CHGCTRL_C		0x168
+#define DA9150_PPR_TCTR_A		0x169
+#define DA9150_PPR_CHGCTRL_D		0x16A
+#define DA9150_PPR_CHGCTRL_E		0x16B
+#define DA9150_PPR_CHGCTRL_F		0x16C
+#define DA9150_PPR_CHGCTRL_G		0x16D
+#define DA9150_PPR_CHGCTRL_H		0x16E
+#define DA9150_PPR_CHGCTRL_I		0x16F
+#define DA9150_PPR_CHGCTRL_J		0x170
+#define DA9150_PPR_CHGCTRL_K		0x171
+#define DA9150_PPR_CHGCTRL_L		0x172
+#define DA9150_PPR_CHGCTRL_M		0x173
+#define DA9150_PPR_THYST_A		0x174
+#define DA9150_PPR_THYST_B		0x175
+#define DA9150_PPR_THYST_C		0x176
+#define DA9150_PPR_THYST_D		0x177
+#define DA9150_PPR_THYST_E		0x178
+#define DA9150_PPR_THYST_F		0x179
+#define DA9150_PPR_THYST_G		0x17A
+#define DA9150_PAGE_CON_3		0x180
+#define DA9150_PAGE_CON_4		0x200
+#define DA9150_PAGE_CON_5		0x280
+#define DA9150_PAGE_CON_6		0x300
+#define DA9150_COREBTLD_STAT_A		0x302
+#define DA9150_COREBTLD_CTRL_A		0x303
+#define DA9150_CORE_CONFIG_A		0x304
+#define DA9150_CORE_CONFIG_C		0x305
+#define DA9150_CORE_CONFIG_B		0x306
+#define DA9150_CORE_CFG_DATA_A		0x307
+#define DA9150_CORE_CFG_DATA_B		0x308
+#define DA9150_CORE_CMD_A		0x309
+#define DA9150_CORE_DATA_A		0x30A
+#define DA9150_CORE_DATA_B		0x30B
+#define DA9150_CORE_DATA_C		0x30C
+#define DA9150_CORE_DATA_D		0x30D
+#define DA9150_CORE2WIRE_STAT_A		0x310
+#define DA9150_CORE2WIRE_CTRL_A		0x311
+#define DA9150_FW_CTRL_A		0x312
+#define DA9150_FW_CTRL_C		0x313
+#define DA9150_FW_CTRL_D		0x314
+#define DA9150_FG_CTRL_A		0x315
+#define DA9150_FG_CTRL_B		0x316
+#define DA9150_FW_CTRL_E		0x317
+#define DA9150_FW_CTRL_B		0x318
+#define DA9150_GPADC_CMAN		0x320
+#define DA9150_GPADC_CRES_A		0x322
+#define DA9150_GPADC_CRES_B		0x323
+#define DA9150_CC_CFG_A			0x328
+#define DA9150_CC_CFG_B			0x329
+#define DA9150_CC_ICHG_RES_A		0x32A
+#define DA9150_CC_ICHG_RES_B		0x32B
+#define DA9150_CC_IAVG_RES_A		0x32C
+#define DA9150_CC_IAVG_RES_B		0x32D
+#define DA9150_TAUX_CTRL_A		0x330
+#define DA9150_TAUX_RELOAD_H		0x332
+#define DA9150_TAUX_RELOAD_L		0x333
+#define DA9150_TAUX_VALUE_H		0x334
+#define DA9150_TAUX_VALUE_L		0x335
+#define DA9150_AUX_DATA_0		0x338
+#define DA9150_AUX_DATA_1		0x339
+#define DA9150_AUX_DATA_2		0x33A
+#define DA9150_AUX_DATA_3		0x33B
+#define DA9150_BIF_CTRL			0x340
+#define DA9150_TBAT_CTRL_A		0x342
+#define DA9150_TBAT_CTRL_B		0x343
+#define DA9150_TBAT_RES_A		0x344
+#define DA9150_TBAT_RES_B		0x345
+
+/* DA9150_PAGE_CON = 0x000 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_I2C_PAGE_SHIFT			1
+#define DA9150_I2C_PAGE_MASK			(0x1f << 1)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_STATUS_A = 0x068 */
+#define DA9150_WKUP_STAT_SHIFT			2
+#define DA9150_WKUP_STAT_MASK			(0x0f << 2)
+#define DA9150_SLEEP_STAT_SHIFT			6
+#define DA9150_SLEEP_STAT_MASK			(0x03 << 6)
+
+/* DA9150_STATUS_B = 0x069 */
+#define DA9150_VFAULT_STAT_SHIFT		0
+#define DA9150_VFAULT_STAT_MASK			(0x01 << 0)
+#define DA9150_TFAULT_STAT_SHIFT		1
+#define DA9150_TFAULT_STAT_MASK			(0x01 << 1)
+
+/* DA9150_STATUS_C = 0x06A */
+#define DA9150_VDD33_STAT_SHIFT			0
+#define DA9150_VDD33_STAT_MASK			(0x01 << 0)
+#define DA9150_VDD33_SLEEP_SHIFT		1
+#define DA9150_VDD33_SLEEP_MASK			(0x01 << 1)
+#define DA9150_LFOSC_STAT_SHIFT			7
+#define DA9150_LFOSC_STAT_MASK			(0x01 << 7)
+
+/* DA9150_STATUS_D = 0x06B */
+#define DA9150_GPIOA_STAT_SHIFT			0
+#define DA9150_GPIOA_STAT_MASK			(0x01 << 0)
+#define DA9150_GPIOB_STAT_SHIFT			1
+#define DA9150_GPIOB_STAT_MASK			(0x01 << 1)
+#define DA9150_GPIOC_STAT_SHIFT			2
+#define DA9150_GPIOC_STAT_MASK			(0x01 << 2)
+#define DA9150_GPIOD_STAT_SHIFT			3
+#define DA9150_GPIOD_STAT_MASK			(0x01 << 3)
+
+/* DA9150_STATUS_E = 0x06C */
+#define DA9150_DTYPE_SHIFT			0
+#define DA9150_DTYPE_MASK			(0x1f << 0)
+#define DA9150_DTYPE_DT_NIL			(0x00 << 0)
+#define DA9150_DTYPE_DT_USB_OTG			(0x01 << 0)
+#define DA9150_DTYPE_DT_USB_STD			(0x02 << 0)
+#define DA9150_DTYPE_DT_USB_CHG			(0x03 << 0)
+#define DA9150_DTYPE_DT_ACA_CHG			(0x04 << 0)
+#define DA9150_DTYPE_DT_ACA_OTG			(0x05 << 0)
+#define DA9150_DTYPE_DT_ACA_DOC			(0x06 << 0)
+#define DA9150_DTYPE_DT_DED_CHG			(0x07 << 0)
+#define DA9150_DTYPE_DT_CR5_CHG			(0x08 << 0)
+#define DA9150_DTYPE_DT_CR4_CHG			(0x0c << 0)
+#define DA9150_DTYPE_DT_PT_CHG			(0x11 << 0)
+#define DA9150_DTYPE_DT_NN_ACC			(0x16 << 0)
+#define DA9150_DTYPE_DT_NN_CHG			(0x17 << 0)
+
+/* DA9150_STATUS_F = 0x06D */
+#define DA9150_SESS_VLD_SHIFT			0
+#define DA9150_SESS_VLD_MASK			(0x01 << 0)
+#define DA9150_ID_ERR_SHIFT			1
+#define DA9150_ID_ERR_MASK			(0x01 << 1)
+#define DA9150_PT_CHG_SHIFT			2
+#define DA9150_PT_CHG_MASK			(0x01 << 2)
+
+/* DA9150_STATUS_G = 0x06E */
+#define DA9150_RID_SHIFT			0
+#define DA9150_RID_MASK				(0xff << 0)
+
+/* DA9150_STATUS_H = 0x06F */
+#define DA9150_VBUS_STAT_SHIFT			0
+#define DA9150_VBUS_STAT_MASK			(0x07 << 0)
+#define DA9150_VBUS_STAT_OFF			(0x00 << 0)
+#define DA9150_VBUS_STAT_WAIT			(0x01 << 0)
+#define DA9150_VBUS_STAT_CHG			(0x02 << 0)
+#define DA9150_VBUS_TRED_SHIFT			3
+#define DA9150_VBUS_TRED_MASK			(0x01 << 3)
+#define DA9150_VBUS_DROP_STAT_SHIFT		4
+#define DA9150_VBUS_DROP_STAT_MASK		(0x0f << 4)
+
+/* DA9150_STATUS_I = 0x070 */
+#define DA9150_VBUS_ISET_STAT_SHIFT		0
+#define DA9150_VBUS_ISET_STAT_MASK		(0x1f << 0)
+#define DA9150_VBUS_OT_SHIFT			7
+#define DA9150_VBUS_OT_MASK			(0x01 << 7)
+
+/* DA9150_STATUS_J = 0x071 */
+#define DA9150_CHG_STAT_SHIFT			0
+#define DA9150_CHG_STAT_MASK			(0x0f << 0)
+#define DA9150_CHG_STAT_OFF			(0x00 << 0)
+#define DA9150_CHG_STAT_SUSP			(0x01 << 0)
+#define DA9150_CHG_STAT_ACT			(0x02 << 0)
+#define DA9150_CHG_STAT_PRE			(0x03 << 0)
+#define DA9150_CHG_STAT_CC			(0x04 << 0)
+#define DA9150_CHG_STAT_CV			(0x05 << 0)
+#define DA9150_CHG_STAT_FULL			(0x06 << 0)
+#define DA9150_CHG_STAT_TEMP			(0x07 << 0)
+#define DA9150_CHG_STAT_TIME			(0x08 << 0)
+#define DA9150_CHG_STAT_BAT			(0x09 << 0)
+#define DA9150_CHG_TEMP_SHIFT			4
+#define DA9150_CHG_TEMP_MASK			(0x07 << 4)
+#define DA9150_CHG_TEMP_UNDER			(0x06 << 4)
+#define DA9150_CHG_TEMP_OVER			(0x07 << 4)
+#define DA9150_CHG_IEND_STAT_SHIFT		7
+#define DA9150_CHG_IEND_STAT_MASK		(0x01 << 7)
+
+/* DA9150_STATUS_K = 0x072 */
+#define DA9150_CHG_IAV_H_SHIFT			0
+#define DA9150_CHG_IAV_H_MASK			(0xff << 0)
+
+/* DA9150_STATUS_L = 0x073 */
+#define DA9150_CHG_IAV_L_SHIFT			5
+#define DA9150_CHG_IAV_L_MASK			(0x07 << 5)
+
+/* DA9150_STATUS_N = 0x074 */
+#define DA9150_CHG_TIME_SHIFT			1
+#define DA9150_CHG_TIME_MASK			(0x01 << 1)
+#define DA9150_CHG_TRED_SHIFT			2
+#define DA9150_CHG_TRED_MASK			(0x01 << 2)
+#define DA9150_CHG_TJUNC_CLASS_SHIFT		3
+#define DA9150_CHG_TJUNC_CLASS_MASK		(0x07 << 3)
+#define DA9150_CHG_TJUNC_CLASS_6		(0x06 << 3)
+#define DA9150_EBS_STAT_SHIFT			6
+#define DA9150_EBS_STAT_MASK			(0x01 << 6)
+#define DA9150_CHG_BAT_REMOVED_SHIFT		7
+#define DA9150_CHG_BAT_REMOVED_MASK		(0x01 << 7)
+
+/* DA9150_FAULT_LOG_A = 0x076 */
+#define DA9150_TEMP_FAULT_SHIFT			0
+#define DA9150_TEMP_FAULT_MASK			(0x01 << 0)
+#define DA9150_VSYS_FAULT_SHIFT			1
+#define DA9150_VSYS_FAULT_MASK			(0x01 << 1)
+#define DA9150_START_FAULT_SHIFT		2
+#define DA9150_START_FAULT_MASK			(0x01 << 2)
+#define DA9150_EXT_FAULT_SHIFT			3
+#define DA9150_EXT_FAULT_MASK			(0x01 << 3)
+#define DA9150_POR_FAULT_SHIFT			4
+#define DA9150_POR_FAULT_MASK			(0x01 << 4)
+
+/* DA9150_FAULT_LOG_B = 0x077 */
+#define DA9150_VBUS_FAULT_SHIFT			0
+#define DA9150_VBUS_FAULT_MASK			(0x01 << 0)
+#define DA9150_OTG_FAULT_SHIFT			1
+#define DA9150_OTG_FAULT_MASK			(0x01 << 1)
+
+/* DA9150_EVENT_E = 0x078 */
+#define DA9150_E_VBUS_SHIFT			0
+#define DA9150_E_VBUS_MASK			(0x01 << 0)
+#define DA9150_E_CHG_SHIFT			1
+#define DA9150_E_CHG_MASK			(0x01 << 1)
+#define DA9150_E_TCLASS_SHIFT			2
+#define DA9150_E_TCLASS_MASK			(0x01 << 2)
+#define DA9150_E_TJUNC_SHIFT			3
+#define DA9150_E_TJUNC_MASK			(0x01 << 3)
+#define DA9150_E_VFAULT_SHIFT			4
+#define DA9150_E_VFAULT_MASK			(0x01 << 4)
+#define DA9150_EVENTS_H_SHIFT			5
+#define DA9150_EVENTS_H_MASK			(0x01 << 5)
+#define DA9150_EVENTS_G_SHIFT			6
+#define DA9150_EVENTS_G_MASK			(0x01 << 6)
+#define DA9150_EVENTS_F_SHIFT			7
+#define DA9150_EVENTS_F_MASK			(0x01 << 7)
+
+/* DA9150_EVENT_F = 0x079 */
+#define DA9150_E_CONF_SHIFT			0
+#define DA9150_E_CONF_MASK			(0x01 << 0)
+#define DA9150_E_DAT_SHIFT			1
+#define DA9150_E_DAT_MASK			(0x01 << 1)
+#define DA9150_E_DTYPE_SHIFT			3
+#define DA9150_E_DTYPE_MASK			(0x01 << 3)
+#define DA9150_E_ID_SHIFT			4
+#define DA9150_E_ID_MASK			(0x01 << 4)
+#define DA9150_E_ADP_SHIFT			5
+#define DA9150_E_ADP_MASK			(0x01 << 5)
+#define DA9150_E_SESS_END_SHIFT			6
+#define DA9150_E_SESS_END_MASK			(0x01 << 6)
+#define DA9150_E_SESS_VLD_SHIFT			7
+#define DA9150_E_SESS_VLD_MASK			(0x01 << 7)
+
+/* DA9150_EVENT_G = 0x07A */
+#define DA9150_E_FG_SHIFT			0
+#define DA9150_E_FG_MASK			(0x01 << 0)
+#define DA9150_E_GP_SHIFT			1
+#define DA9150_E_GP_MASK			(0x01 << 1)
+#define DA9150_E_TBAT_SHIFT			2
+#define DA9150_E_TBAT_MASK			(0x01 << 2)
+#define DA9150_E_GPIOA_SHIFT			3
+#define DA9150_E_GPIOA_MASK			(0x01 << 3)
+#define DA9150_E_GPIOB_SHIFT			4
+#define DA9150_E_GPIOB_MASK			(0x01 << 4)
+#define DA9150_E_GPIOC_SHIFT			5
+#define DA9150_E_GPIOC_MASK			(0x01 << 5)
+#define DA9150_E_GPIOD_SHIFT			6
+#define DA9150_E_GPIOD_MASK			(0x01 << 6)
+#define DA9150_E_GPADC_SHIFT			7
+#define DA9150_E_GPADC_MASK			(0x01 << 7)
+
+/* DA9150_EVENT_H = 0x07B */
+#define DA9150_E_WKUP_SHIFT			0
+#define DA9150_E_WKUP_MASK			(0x01 << 0)
+
+/* DA9150_IRQ_MASK_E = 0x07C */
+#define DA9150_M_VBUS_SHIFT			0
+#define DA9150_M_VBUS_MASK			(0x01 << 0)
+#define DA9150_M_CHG_SHIFT			1
+#define DA9150_M_CHG_MASK			(0x01 << 1)
+#define DA9150_M_TJUNC_SHIFT			3
+#define DA9150_M_TJUNC_MASK			(0x01 << 3)
+#define DA9150_M_VFAULT_SHIFT			4
+#define DA9150_M_VFAULT_MASK			(0x01 << 4)
+
+/* DA9150_IRQ_MASK_F = 0x07D */
+#define DA9150_M_CONF_SHIFT			0
+#define DA9150_M_CONF_MASK			(0x01 << 0)
+#define DA9150_M_DAT_SHIFT			1
+#define DA9150_M_DAT_MASK			(0x01 << 1)
+#define DA9150_M_DTYPE_SHIFT			3
+#define DA9150_M_DTYPE_MASK			(0x01 << 3)
+#define DA9150_M_ID_SHIFT			4
+#define DA9150_M_ID_MASK			(0x01 << 4)
+#define DA9150_M_ADP_SHIFT			5
+#define DA9150_M_ADP_MASK			(0x01 << 5)
+#define DA9150_M_SESS_END_SHIFT			6
+#define DA9150_M_SESS_END_MASK			(0x01 << 6)
+#define DA9150_M_SESS_VLD_SHIFT			7
+#define DA9150_M_SESS_VLD_MASK			(0x01 << 7)
+
+/* DA9150_IRQ_MASK_G = 0x07E */
+#define DA9150_M_FG_SHIFT			0
+#define DA9150_M_FG_MASK			(0x01 << 0)
+#define DA9150_M_GP_SHIFT			1
+#define DA9150_M_GP_MASK			(0x01 << 1)
+#define DA9150_M_TBAT_SHIFT			2
+#define DA9150_M_TBAT_MASK			(0x01 << 2)
+#define DA9150_M_GPIOA_SHIFT			3
+#define DA9150_M_GPIOA_MASK			(0x01 << 3)
+#define DA9150_M_GPIOB_SHIFT			4
+#define DA9150_M_GPIOB_MASK			(0x01 << 4)
+#define DA9150_M_GPIOC_SHIFT			5
+#define DA9150_M_GPIOC_MASK			(0x01 << 5)
+#define DA9150_M_GPIOD_SHIFT			6
+#define DA9150_M_GPIOD_MASK			(0x01 << 6)
+#define DA9150_M_GPADC_SHIFT			7
+#define DA9150_M_GPADC_MASK			(0x01 << 7)
+
+/* DA9150_IRQ_MASK_H = 0x07F */
+#define DA9150_M_WKUP_SHIFT			0
+#define DA9150_M_WKUP_MASK			(0x01 << 0)
+
+/* DA9150_PAGE_CON_1 = 0x080 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_CONFIG_A = 0x0E0 */
+#define DA9150_RESET_DUR_SHIFT			0
+#define DA9150_RESET_DUR_MASK			(0x03 << 0)
+#define DA9150_RESET_EXT_SHIFT			2
+#define DA9150_RESET_EXT_MASK			(0x03 << 2)
+#define DA9150_START_MAX_SHIFT			4
+#define DA9150_START_MAX_MASK			(0x03 << 4)
+#define DA9150_PS_WAIT_EN_SHIFT			6
+#define DA9150_PS_WAIT_EN_MASK			(0x01 << 6)
+#define DA9150_PS_DISABLE_DIRECT_SHIFT		7
+#define DA9150_PS_DISABLE_DIRECT_MASK		(0x01 << 7)
+
+/* DA9150_CONFIG_B = 0x0E1 */
+#define DA9150_VFAULT_ADJ_SHIFT			0
+#define DA9150_VFAULT_ADJ_MASK			(0x0f << 0)
+#define DA9150_VFAULT_HYST_SHIFT		4
+#define DA9150_VFAULT_HYST_MASK			(0x07 << 4)
+#define DA9150_VFAULT_EN_SHIFT			7
+#define DA9150_VFAULT_EN_MASK			(0x01 << 7)
+
+/* DA9150_CONFIG_C = 0x0E2 */
+#define DA9150_VSYS_MIN_SHIFT			3
+#define DA9150_VSYS_MIN_MASK			(0x1f << 3)
+
+/* DA9150_CONFIG_D = 0x0E3 */
+#define DA9150_LFOSC_EXT_SHIFT			0
+#define DA9150_LFOSC_EXT_MASK			(0x01 << 0)
+#define DA9150_VDD33_DWN_SHIFT			1
+#define DA9150_VDD33_DWN_MASK			(0x01 << 1)
+#define DA9150_WKUP_PM_EN_SHIFT			2
+#define DA9150_WKUP_PM_EN_MASK			(0x01 << 2)
+#define DA9150_WKUP_CE_SEL_SHIFT		3
+#define DA9150_WKUP_CE_SEL_MASK			(0x03 << 3)
+#define DA9150_WKUP_CLK32K_EN_SHIFT		5
+#define DA9150_WKUP_CLK32K_EN_MASK		(0x01 << 5)
+#define DA9150_DISABLE_DEL_SHIFT		7
+#define DA9150_DISABLE_DEL_MASK			(0x01 << 7)
+
+/* DA9150_CONFIG_E = 0x0E4 */
+#define DA9150_PM_SPKSUP_DIS_SHIFT		0
+#define DA9150_PM_SPKSUP_DIS_MASK		(0x01 << 0)
+#define DA9150_PM_MERGE_SHIFT			1
+#define DA9150_PM_MERGE_MASK			(0x01 << 1)
+#define DA9150_PM_SR_OFF_SHIFT			2
+#define DA9150_PM_SR_OFF_MASK			(0x01 << 2)
+#define DA9150_PM_TIMEOUT_EN_SHIFT		3
+#define DA9150_PM_TIMEOUT_EN_MASK		(0x01 << 3)
+#define DA9150_PM_DLY_SEL_SHIFT			4
+#define DA9150_PM_DLY_SEL_MASK			(0x07 << 4)
+#define DA9150_PM_OUT_DLY_SEL_SHIFT		7
+#define DA9150_PM_OUT_DLY_SEL_MASK		(0x01 << 7)
+
+/* DA9150_CONTROL_A = 0x0E5 */
+#define DA9150_VDD33_SL_SHIFT			0
+#define DA9150_VDD33_SL_MASK			(0x01 << 0)
+#define DA9150_VDD33_LPM_SHIFT			1
+#define DA9150_VDD33_LPM_MASK			(0x03 << 1)
+#define DA9150_VDD33_EN_SHIFT			3
+#define DA9150_VDD33_EN_MASK			(0x01 << 3)
+#define DA9150_GPI_LPM_SHIFT			6
+#define DA9150_GPI_LPM_MASK			(0x01 << 6)
+#define DA9150_PM_IF_LPM_SHIFT			7
+#define DA9150_PM_IF_LPM_MASK			(0x01 << 7)
+
+/* DA9150_CONTROL_B = 0x0E6 */
+#define DA9150_LPM_SHIFT			0
+#define DA9150_LPM_MASK				(0x01 << 0)
+#define DA9150_RESET_SHIFT			1
+#define DA9150_RESET_MASK			(0x01 << 1)
+#define DA9150_RESET_USRCONF_EN_SHIFT		2
+#define DA9150_RESET_USRCONF_EN_MASK		(0x01 << 2)
+
+/* DA9150_CONTROL_C = 0x0E7 */
+#define DA9150_DISABLE_SHIFT			0
+#define DA9150_DISABLE_MASK			(0x01 << 0)
+
+/* DA9150_GPIO_A_B = 0x0E8 */
+#define DA9150_GPIOA_PIN_SHIFT			0
+#define DA9150_GPIOA_PIN_MASK			(0x07 << 0)
+#define DA9150_GPIOA_PIN_GPI			(0x00 << 0)
+#define DA9150_GPIOA_PIN_GPO_OD			(0x01 << 0)
+#define DA9150_GPIOA_TYPE_SHIFT			3
+#define DA9150_GPIOA_TYPE_MASK			(0x01 << 3)
+#define DA9150_GPIOB_PIN_SHIFT			4
+#define DA9150_GPIOB_PIN_MASK			(0x07 << 4)
+#define DA9150_GPIOB_PIN_GPI			(0x00 << 4)
+#define DA9150_GPIOB_PIN_GPO_OD			(0x01 << 4)
+#define DA9150_GPIOB_TYPE_SHIFT			7
+#define DA9150_GPIOB_TYPE_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_C_D = 0x0E9 */
+#define DA9150_GPIOC_PIN_SHIFT			0
+#define DA9150_GPIOC_PIN_MASK			(0x07 << 0)
+#define DA9150_GPIOC_PIN_GPI			(0x00 << 0)
+#define DA9150_GPIOC_PIN_GPO_OD			(0x01 << 0)
+#define DA9150_GPIOC_TYPE_SHIFT			3
+#define DA9150_GPIOC_TYPE_MASK			(0x01 << 3)
+#define DA9150_GPIOD_PIN_SHIFT			4
+#define DA9150_GPIOD_PIN_MASK			(0x07 << 4)
+#define DA9150_GPIOD_PIN_GPI			(0x00 << 4)
+#define DA9150_GPIOD_PIN_GPO_OD			(0x01 << 4)
+#define DA9150_GPIOD_TYPE_SHIFT			7
+#define DA9150_GPIOD_TYPE_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_MODE_CONT = 0x0EA */
+#define DA9150_GPIOA_MODE_SHIFT			0
+#define DA9150_GPIOA_MODE_MASK			(0x01 << 0)
+#define DA9150_GPIOB_MODE_SHIFT			1
+#define DA9150_GPIOB_MODE_MASK			(0x01 << 1)
+#define DA9150_GPIOC_MODE_SHIFT			2
+#define DA9150_GPIOC_MODE_MASK			(0x01 << 2)
+#define DA9150_GPIOD_MODE_SHIFT			3
+#define DA9150_GPIOD_MODE_MASK			(0x01 << 3)
+#define DA9150_GPIOA_CONT_SHIFT			4
+#define DA9150_GPIOA_CONT_MASK			(0x01 << 4)
+#define DA9150_GPIOB_CONT_SHIFT			5
+#define DA9150_GPIOB_CONT_MASK			(0x01 << 5)
+#define DA9150_GPIOC_CONT_SHIFT			6
+#define DA9150_GPIOC_CONT_MASK			(0x01 << 6)
+#define DA9150_GPIOD_CONT_SHIFT			7
+#define DA9150_GPIOD_CONT_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_CTRL_B = 0x0EB */
+#define DA9150_WAKE_PIN_SHIFT			0
+#define DA9150_WAKE_PIN_MASK			(0x03 << 0)
+#define DA9150_WAKE_MODE_SHIFT			2
+#define DA9150_WAKE_MODE_MASK			(0x01 << 2)
+#define DA9150_WAKE_CONT_SHIFT			3
+#define DA9150_WAKE_CONT_MASK			(0x01 << 3)
+#define DA9150_WAKE_DLY_SHIFT			4
+#define DA9150_WAKE_DLY_MASK			(0x01 << 4)
+
+/* DA9150_GPIO_CTRL_A = 0x0EC */
+#define DA9150_GPIOA_ANAEN_SHIFT		0
+#define DA9150_GPIOA_ANAEN_MASK			(0x01 << 0)
+#define DA9150_GPIOB_ANAEN_SHIFT		1
+#define DA9150_GPIOB_ANAEN_MASK			(0x01 << 1)
+#define DA9150_GPIOC_ANAEN_SHIFT		2
+#define DA9150_GPIOC_ANAEN_MASK			(0x01 << 2)
+#define DA9150_GPIOD_ANAEN_SHIFT		3
+#define DA9150_GPIOD_ANAEN_MASK			(0x01 << 3)
+#define DA9150_GPIO_ANAEN			0x01
+#define DA9150_GPIO_ANAEN_MASK			0x0F
+#define DA9150_CHGLED_PIN_SHIFT			5
+#define DA9150_CHGLED_PIN_MASK			(0x07 << 5)
+
+/* DA9150_GPIO_CTRL_C = 0x0ED */
+#define DA9150_CHGBL_DUR_SHIFT			0
+#define DA9150_CHGBL_DUR_MASK			(0x03 << 0)
+#define DA9150_CHGBL_DBL_SHIFT			2
+#define DA9150_CHGBL_DBL_MASK			(0x01 << 2)
+#define DA9150_CHGBL_FRQ_SHIFT			3
+#define DA9150_CHGBL_FRQ_MASK			(0x03 << 3)
+#define DA9150_CHGBL_FLKR_SHIFT			5
+#define DA9150_CHGBL_FLKR_MASK			(0x01 << 5)
+
+/* DA9150_GPIO_CFG_A = 0x0EE */
+#define DA9150_CE_LPM_DEB_SHIFT			0
+#define DA9150_CE_LPM_DEB_MASK			(0x07 << 0)
+
+/* DA9150_GPIO_CFG_B = 0x0EF */
+#define DA9150_GPIOA_PUPD_SHIFT			0
+#define DA9150_GPIOA_PUPD_MASK			(0x01 << 0)
+#define DA9150_GPIOB_PUPD_SHIFT			1
+#define DA9150_GPIOB_PUPD_MASK			(0x01 << 1)
+#define DA9150_GPIOC_PUPD_SHIFT			2
+#define DA9150_GPIOC_PUPD_MASK			(0x01 << 2)
+#define DA9150_GPIOD_PUPD_SHIFT			3
+#define DA9150_GPIOD_PUPD_MASK			(0x01 << 3)
+#define DA9150_GPIO_PUPD_MASK			(0xF << 0)
+#define DA9150_GPI_DEB_SHIFT			4
+#define DA9150_GPI_DEB_MASK			(0x07 << 4)
+#define DA9150_LPM_EN_SHIFT			7
+#define DA9150_LPM_EN_MASK			(0x01 << 7)
+
+/* DA9150_GPIO_CFG_C = 0x0F0 */
+#define DA9150_GPI_V_SHIFT			0
+#define DA9150_GPI_V_MASK			(0x01 << 0)
+#define DA9150_VDDIO_INT_SHIFT			1
+#define DA9150_VDDIO_INT_MASK			(0x01 << 1)
+#define DA9150_FAULT_PIN_SHIFT			3
+#define DA9150_FAULT_PIN_MASK			(0x07 << 3)
+#define DA9150_FAULT_TYPE_SHIFT			6
+#define DA9150_FAULT_TYPE_MASK			(0x01 << 6)
+#define DA9150_NIRQ_PUPD_SHIFT			7
+#define DA9150_NIRQ_PUPD_MASK			(0x01 << 7)
+
+/* DA9150_GPADC_MAN = 0x0F2 */
+#define DA9150_GPADC_EN_SHIFT			0
+#define DA9150_GPADC_EN_MASK			(0x01 << 0)
+#define DA9150_GPADC_MUX_SHIFT			1
+#define DA9150_GPADC_MUX_MASK			(0x1f << 1)
+
+/* DA9150_GPADC_RES_A = 0x0F4 */
+#define DA9150_GPADC_RES_H_SHIFT		0
+#define DA9150_GPADC_RES_H_MASK			(0xff << 0)
+
+/* DA9150_GPADC_RES_B = 0x0F5 */
+#define DA9150_GPADC_RUN_SHIFT			0
+#define DA9150_GPADC_RUN_MASK			(0x01 << 0)
+#define DA9150_GPADC_RES_L_SHIFT		6
+#define DA9150_GPADC_RES_L_MASK			(0x03 << 6)
+#define DA9150_GPADC_RES_L_BITS			2
+
+/* DA9150_PAGE_CON_2 = 0x100 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_OTP_CONT_SHARED = 0x101 */
+#define DA9150_PC_DONE_SHIFT			3
+#define DA9150_PC_DONE_MASK			(0x01 << 3)
+
+/* DA9150_INTERFACE_SHARED = 0x105 */
+#define DA9150_IF_BASE_ADDR_SHIFT		4
+#define DA9150_IF_BASE_ADDR_MASK		(0x0f << 4)
+
+/* DA9150_CONFIG_A_SHARED = 0x106 */
+#define DA9150_NIRQ_VDD_SHIFT			1
+#define DA9150_NIRQ_VDD_MASK			(0x01 << 1)
+#define DA9150_NIRQ_PIN_SHIFT			2
+#define DA9150_NIRQ_PIN_MASK			(0x01 << 2)
+#define DA9150_NIRQ_TYPE_SHIFT			3
+#define DA9150_NIRQ_TYPE_MASK			(0x01 << 3)
+#define DA9150_PM_IF_V_SHIFT			4
+#define DA9150_PM_IF_V_MASK			(0x01 << 4)
+#define DA9150_PM_IF_FMP_SHIFT			5
+#define DA9150_PM_IF_FMP_MASK			(0x01 << 5)
+#define DA9150_PM_IF_HSM_SHIFT			6
+#define DA9150_PM_IF_HSM_MASK			(0x01 << 6)
+
+/* DA9150_CONFIG_D_SHARED = 0x109 */
+#define DA9150_NIRQ_MODE_SHIFT			1
+#define DA9150_NIRQ_MODE_MASK			(0x01 << 1)
+
+/* DA9150_ADETVB_CFG_C = 0x150 */
+#define DA9150_TADP_RISE_SHIFT			0
+#define DA9150_TADP_RISE_MASK			(0xff << 0)
+
+/* DA9150_ADETD_STAT = 0x151 */
+#define DA9150_DCD_STAT_SHIFT			0
+#define DA9150_DCD_STAT_MASK			(0x01 << 0)
+#define DA9150_PCD_STAT_SHIFT			1
+#define DA9150_PCD_STAT_MASK			(0x03 << 1)
+#define DA9150_SCD_STAT_SHIFT			3
+#define DA9150_SCD_STAT_MASK			(0x03 << 3)
+#define DA9150_DP_STAT_SHIFT			5
+#define DA9150_DP_STAT_MASK			(0x01 << 5)
+#define DA9150_DM_STAT_SHIFT			6
+#define DA9150_DM_STAT_MASK			(0x01 << 6)
+
+/* DA9150_ADET_CMPSTAT = 0x152 */
+#define DA9150_DP_COMP_SHIFT			1
+#define DA9150_DP_COMP_MASK			(0x01 << 1)
+#define DA9150_DM_COMP_SHIFT			2
+#define DA9150_DM_COMP_MASK			(0x01 << 2)
+#define DA9150_ADP_SNS_COMP_SHIFT		3
+#define DA9150_ADP_SNS_COMP_MASK		(0x01 << 3)
+#define DA9150_ADP_PRB_COMP_SHIFT		4
+#define DA9150_ADP_PRB_COMP_MASK		(0x01 << 4)
+#define DA9150_ID_COMP_SHIFT			5
+#define DA9150_ID_COMP_MASK			(0x01 << 5)
+
+/* DA9150_ADET_CTRL_A = 0x153 */
+#define DA9150_AID_DAT_SHIFT			0
+#define DA9150_AID_DAT_MASK			(0x01 << 0)
+#define DA9150_AID_ID_SHIFT			1
+#define DA9150_AID_ID_MASK			(0x01 << 1)
+#define DA9150_AID_TRIG_SHIFT			2
+#define DA9150_AID_TRIG_MASK			(0x01 << 2)
+
+/* DA9150_ADETVB_CFG_B = 0x154 */
+#define DA9150_VB_MODE_SHIFT			0
+#define DA9150_VB_MODE_MASK			(0x03 << 0)
+#define DA9150_VB_MODE_VB_SESS			(0x01 << 0)
+
+#define DA9150_TADP_PRB_SHIFT			2
+#define DA9150_TADP_PRB_MASK			(0x01 << 2)
+#define DA9150_DAT_RPD_EXT_SHIFT		5
+#define DA9150_DAT_RPD_EXT_MASK			(0x01 << 5)
+#define DA9150_CONF_RPD_SHIFT			6
+#define DA9150_CONF_RPD_MASK			(0x01 << 6)
+#define DA9150_CONF_SRP_SHIFT			7
+#define DA9150_CONF_SRP_MASK			(0x01 << 7)
+
+/* DA9150_ADETVB_CFG_A = 0x155 */
+#define DA9150_AID_MODE_SHIFT			0
+#define DA9150_AID_MODE_MASK			(0x03 << 0)
+#define DA9150_AID_EXT_POL_SHIFT		2
+#define DA9150_AID_EXT_POL_MASK			(0x01 << 2)
+
+/* DA9150_ADETAC_CFG_A = 0x156 */
+#define DA9150_ISET_CDP_SHIFT			0
+#define DA9150_ISET_CDP_MASK			(0x1f << 0)
+#define DA9150_CONF_DBP_SHIFT			5
+#define DA9150_CONF_DBP_MASK			(0x01 << 5)
+
+/* DA9150_ADDETAC_CFG_B = 0x157 */
+#define DA9150_ISET_DCHG_SHIFT			0
+#define DA9150_ISET_DCHG_MASK			(0x1f << 0)
+#define DA9150_CONF_GPIOA_SHIFT			5
+#define DA9150_CONF_GPIOA_MASK			(0x01 << 5)
+#define DA9150_CONF_GPIOB_SHIFT			6
+#define DA9150_CONF_GPIOB_MASK			(0x01 << 6)
+#define DA9150_AID_VB_SHIFT			7
+#define DA9150_AID_VB_MASK			(0x01 << 7)
+
+/* DA9150_ADETAC_CFG_C = 0x158 */
+#define DA9150_ISET_DEF_SHIFT			0
+#define DA9150_ISET_DEF_MASK			(0x1f << 0)
+#define DA9150_CONF_MODE_SHIFT			5
+#define DA9150_CONF_MODE_MASK			(0x03 << 5)
+#define DA9150_AID_CR_DIS_SHIFT			7
+#define DA9150_AID_CR_DIS_MASK			(0x01 << 7)
+
+/* DA9150_ADETAC_CFG_D = 0x159 */
+#define DA9150_ISET_UNIT_SHIFT			0
+#define DA9150_ISET_UNIT_MASK			(0x1f << 0)
+#define DA9150_AID_UNCLAMP_SHIFT		5
+#define DA9150_AID_UNCLAMP_MASK			(0x01 << 5)
+
+/* DA9150_ADETVB_CFG_D = 0x15A */
+#define DA9150_ID_MODE_SHIFT			0
+#define DA9150_ID_MODE_MASK			(0x03 << 0)
+#define DA9150_DAT_MODE_SHIFT			2
+#define DA9150_DAT_MODE_MASK			(0x0f << 2)
+#define DA9150_DAT_SWP_SHIFT			6
+#define DA9150_DAT_SWP_MASK			(0x01 << 6)
+#define DA9150_DAT_CLAMP_EXT_SHIFT		7
+#define DA9150_DAT_CLAMP_EXT_MASK		(0x01 << 7)
+
+/* DA9150_ADETID_CFG_A = 0x15B */
+#define DA9150_TID_POLL_SHIFT			0
+#define DA9150_TID_POLL_MASK			(0x07 << 0)
+#define DA9150_RID_CONV_SHIFT			3
+#define DA9150_RID_CONV_MASK			(0x01 << 3)
+
+/* DA9150_ADET_RID_PT_CHG_H = 0x15C */
+#define DA9150_RID_PT_CHG_H_SHIFT		0
+#define DA9150_RID_PT_CHG_H_MASK		(0xff << 0)
+
+/* DA9150_ADET_RID_PT_CHG_L = 0x15D */
+#define DA9150_RID_PT_CHG_L_SHIFT		6
+#define DA9150_RID_PT_CHG_L_MASK		(0x03 << 6)
+
+/* DA9150_PPR_TCTR_B = 0x160 */
+#define DA9150_CHG_TCTR_VAL_SHIFT		0
+#define DA9150_CHG_TCTR_VAL_MASK		(0xff << 0)
+
+/* DA9150_PPR_BKCTRL_A = 0x163 */
+#define DA9150_VBUS_MODE_SHIFT			0
+#define DA9150_VBUS_MODE_MASK			(0x03 << 0)
+#define DA9150_VBUS_MODE_CHG			(0x01 << 0)
+#define DA9150_VBUS_MODE_OTG			(0x02 << 0)
+#define DA9150_VBUS_LPM_SHIFT			2
+#define DA9150_VBUS_LPM_MASK			(0x03 << 2)
+#define DA9150_VBUS_SUSP_SHIFT			4
+#define DA9150_VBUS_SUSP_MASK			(0x01 << 4)
+#define DA9150_VBUS_PWM_SHIFT			5
+#define DA9150_VBUS_PWM_MASK			(0x01 << 5)
+#define DA9150_VBUS_ISO_SHIFT			6
+#define DA9150_VBUS_ISO_MASK			(0x01 << 6)
+#define DA9150_VBUS_LDO_SHIFT			7
+#define DA9150_VBUS_LDO_MASK			(0x01 << 7)
+
+/* DA9150_PPR_BKCFG_A = 0x164 */
+#define DA9150_VBUS_ISET_SHIFT			0
+#define DA9150_VBUS_ISET_MASK			(0x1f << 0)
+#define DA9150_VBUS_IMAX_SHIFT			5
+#define DA9150_VBUS_IMAX_MASK			(0x01 << 5)
+#define DA9150_VBUS_IOTG_SHIFT			6
+#define DA9150_VBUS_IOTG_MASK			(0x03 << 6)
+
+/* DA9150_PPR_BKCFG_B = 0x165 */
+#define DA9150_VBUS_DROP_SHIFT			0
+#define DA9150_VBUS_DROP_MASK			(0x0f << 0)
+#define DA9150_VBUS_FAULT_DIS_SHIFT		6
+#define DA9150_VBUS_FAULT_DIS_MASK		(0x01 << 6)
+#define DA9150_OTG_FAULT_DIS_SHIFT		7
+#define DA9150_OTG_FAULT_DIS_MASK		(0x01 << 7)
+
+/* DA9150_PPR_CHGCTRL_A = 0x166 */
+#define DA9150_CHG_EN_SHIFT			0
+#define DA9150_CHG_EN_MASK			(0x01 << 0)
+
+/* DA9150_PPR_CHGCTRL_B = 0x167 */
+#define DA9150_CHG_VBAT_SHIFT			0
+#define DA9150_CHG_VBAT_MASK			(0x1f << 0)
+#define DA9150_CHG_VDROP_SHIFT			6
+#define DA9150_CHG_VDROP_MASK			(0x03 << 6)
+
+/* DA9150_PPR_CHGCTRL_C = 0x168 */
+#define DA9150_CHG_VFAULT_SHIFT			0
+#define DA9150_CHG_VFAULT_MASK			(0x0f << 0)
+#define DA9150_CHG_IPRE_SHIFT			4
+#define DA9150_CHG_IPRE_MASK			(0x03 << 4)
+
+/* DA9150_PPR_TCTR_A = 0x169 */
+#define DA9150_CHG_TCTR_SHIFT			0
+#define DA9150_CHG_TCTR_MASK			(0x07 << 0)
+#define DA9150_CHG_TCTR_MODE_SHIFT		4
+#define DA9150_CHG_TCTR_MODE_MASK		(0x01 << 4)
+
+/* DA9150_PPR_CHGCTRL_D = 0x16A */
+#define DA9150_CHG_IBAT_SHIFT			0
+#define DA9150_CHG_IBAT_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_E = 0x16B */
+#define DA9150_CHG_IEND_SHIFT			0
+#define DA9150_CHG_IEND_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_F = 0x16C */
+#define DA9150_CHG_VCOLD_SHIFT			0
+#define DA9150_CHG_VCOLD_MASK			(0x1f << 0)
+#define DA9150_TBAT_TQA_EN_SHIFT		6
+#define DA9150_TBAT_TQA_EN_MASK			(0x01 << 6)
+#define DA9150_TBAT_TDP_EN_SHIFT		7
+#define DA9150_TBAT_TDP_EN_MASK			(0x01 << 7)
+
+/* DA9150_PPR_CHGCTRL_G = 0x16D */
+#define DA9150_CHG_VWARM_SHIFT			0
+#define DA9150_CHG_VWARM_MASK			(0x1f << 0)
+
+/* DA9150_PPR_CHGCTRL_H = 0x16E */
+#define DA9150_CHG_VHOT_SHIFT			0
+#define DA9150_CHG_VHOT_MASK			(0x1f << 0)
+
+/* DA9150_PPR_CHGCTRL_I = 0x16F */
+#define DA9150_CHG_ICOLD_SHIFT			0
+#define DA9150_CHG_ICOLD_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_J = 0x170 */
+#define DA9150_CHG_IWARM_SHIFT			0
+#define DA9150_CHG_IWARM_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_K = 0x171 */
+#define DA9150_CHG_IHOT_SHIFT			0
+#define DA9150_CHG_IHOT_MASK			(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_L = 0x172 */
+#define DA9150_CHG_IBAT_TRED_SHIFT		0
+#define DA9150_CHG_IBAT_TRED_MASK		(0xff << 0)
+
+/* DA9150_PPR_CHGCTRL_M = 0x173 */
+#define DA9150_CHG_VFLOAT_SHIFT			0
+#define DA9150_CHG_VFLOAT_MASK			(0x0f << 0)
+#define DA9150_CHG_LPM_SHIFT			5
+#define DA9150_CHG_LPM_MASK			(0x01 << 5)
+#define DA9150_CHG_NBLO_SHIFT			6
+#define DA9150_CHG_NBLO_MASK			(0x01 << 6)
+#define DA9150_EBS_EN_SHIFT			7
+#define DA9150_EBS_EN_MASK			(0x01 << 7)
+
+/* DA9150_PPR_THYST_A = 0x174 */
+#define DA9150_TBAT_T1_SHIFT			0
+#define DA9150_TBAT_T1_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_B = 0x175 */
+#define DA9150_TBAT_T2_SHIFT			0
+#define DA9150_TBAT_T2_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_C = 0x176 */
+#define DA9150_TBAT_T3_SHIFT			0
+#define DA9150_TBAT_T3_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_D = 0x177 */
+#define DA9150_TBAT_T4_SHIFT			0
+#define DA9150_TBAT_T4_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_E = 0x178 */
+#define DA9150_TBAT_T5_SHIFT			0
+#define DA9150_TBAT_T5_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_F = 0x179 */
+#define DA9150_TBAT_H1_SHIFT			0
+#define DA9150_TBAT_H1_MASK			(0xff << 0)
+
+/* DA9150_PPR_THYST_G = 0x17A */
+#define DA9150_TBAT_H5_SHIFT			0
+#define DA9150_TBAT_H5_MASK			(0xff << 0)
+
+/* DA9150_PAGE_CON_3 = 0x180 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_PAGE_CON_4 = 0x200 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_PAGE_CON_5 = 0x280 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_PAGE_CON_6 = 0x300 */
+#define DA9150_PAGE_SHIFT			0
+#define DA9150_PAGE_MASK			(0x3f << 0)
+#define DA9150_WRITE_MODE_SHIFT			6
+#define DA9150_WRITE_MODE_MASK			(0x01 << 6)
+#define DA9150_REVERT_SHIFT			7
+#define DA9150_REVERT_MASK			(0x01 << 7)
+
+/* DA9150_COREBTLD_STAT_A = 0x302 */
+#define DA9150_BOOTLD_STAT_SHIFT		0
+#define DA9150_BOOTLD_STAT_MASK			(0x03 << 0)
+#define DA9150_CORE_LOCKUP_SHIFT		2
+#define DA9150_CORE_LOCKUP_MASK			(0x01 << 2)
+
+/* DA9150_COREBTLD_CTRL_A = 0x303 */
+#define DA9150_CORE_RESET_SHIFT			0
+#define DA9150_CORE_RESET_MASK			(0x01 << 0)
+#define DA9150_CORE_STOP_SHIFT			1
+#define DA9150_CORE_STOP_MASK			(0x01 << 1)
+
+/* DA9150_CORE_CONFIG_A = 0x304 */
+#define DA9150_CORE_MEMMUX_SHIFT		0
+#define DA9150_CORE_MEMMUX_MASK			(0x03 << 0)
+#define DA9150_WDT_AUTO_START_SHIFT		2
+#define DA9150_WDT_AUTO_START_MASK		(0x01 << 2)
+#define DA9150_WDT_AUTO_LOCK_SHIFT		3
+#define DA9150_WDT_AUTO_LOCK_MASK		(0x01 << 3)
+#define DA9150_WDT_HLT_NO_CLK_SHIFT		4
+#define DA9150_WDT_HLT_NO_CLK_MASK		(0x01 << 4)
+
+/* DA9150_CORE_CONFIG_C = 0x305 */
+#define DA9150_CORE_SW_SIZE_SHIFT		0
+#define DA9150_CORE_SW_SIZE_MASK		(0xff << 0)
+
+/* DA9150_CORE_CONFIG_B = 0x306 */
+#define DA9150_BOOTLD_EN_SHIFT			0
+#define DA9150_BOOTLD_EN_MASK			(0x01 << 0)
+#define DA9150_CORE_EN_SHIFT			2
+#define DA9150_CORE_EN_MASK			(0x01 << 2)
+#define DA9150_CORE_SW_SRC_SHIFT		3
+#define DA9150_CORE_SW_SRC_MASK			(0x07 << 3)
+#define DA9150_DEEP_SLEEP_EN_SHIFT		7
+#define DA9150_DEEP_SLEEP_EN_MASK		(0x01 << 7)
+
+/* DA9150_CORE_CFG_DATA_A = 0x307 */
+#define DA9150_CORE_CFG_DT_A_SHIFT		0
+#define DA9150_CORE_CFG_DT_A_MASK		(0xff << 0)
+
+/* DA9150_CORE_CFG_DATA_B = 0x308 */
+#define DA9150_CORE_CFG_DT_B_SHIFT		0
+#define DA9150_CORE_CFG_DT_B_MASK		(0xff << 0)
+
+/* DA9150_CORE_CMD_A = 0x309 */
+#define DA9150_CORE_CMD_SHIFT			0
+#define DA9150_CORE_CMD_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_A = 0x30A */
+#define DA9150_CORE_DATA_0_SHIFT		0
+#define DA9150_CORE_DATA_0_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_B = 0x30B */
+#define DA9150_CORE_DATA_1_SHIFT		0
+#define DA9150_CORE_DATA_1_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_C = 0x30C */
+#define DA9150_CORE_DATA_2_SHIFT		0
+#define DA9150_CORE_DATA_2_MASK			(0xff << 0)
+
+/* DA9150_CORE_DATA_D = 0x30D */
+#define DA9150_CORE_DATA_3_SHIFT		0
+#define DA9150_CORE_DATA_3_MASK			(0xff << 0)
+
+/* DA9150_CORE2WIRE_STAT_A = 0x310 */
+#define DA9150_FW_FWDL_ERR_SHIFT		7
+#define DA9150_FW_FWDL_ERR_MASK			(0x01 << 7)
+
+/* DA9150_CORE2WIRE_CTRL_A = 0x311 */
+#define DA9150_FW_FWDL_EN_SHIFT			0
+#define DA9150_FW_FWDL_EN_MASK			(0x01 << 0)
+#define DA9150_FG_QIF_EN_SHIFT			1
+#define DA9150_FG_QIF_EN_MASK			(0x01 << 1)
+#define DA9150_CORE_BASE_ADDR_SHIFT		4
+#define DA9150_CORE_BASE_ADDR_MASK		(0x0f << 4)
+
+/* DA9150_FW_CTRL_A = 0x312 */
+#define DA9150_FW_SEAL_SHIFT			0
+#define DA9150_FW_SEAL_MASK			(0xff << 0)
+
+/* DA9150_FW_CTRL_C = 0x313 */
+#define DA9150_FW_FWDL_CRC_SHIFT		0
+#define DA9150_FW_FWDL_CRC_MASK			(0xff << 0)
+
+/* DA9150_FW_CTRL_D = 0x314 */
+#define DA9150_FW_FWDL_BASE_SHIFT		0
+#define DA9150_FW_FWDL_BASE_MASK		(0x0f << 0)
+
+/* DA9150_FG_CTRL_A = 0x315 */
+#define DA9150_FG_QIF_CODE_SHIFT		0
+#define DA9150_FG_QIF_CODE_MASK			(0xff << 0)
+
+/* DA9150_FG_CTRL_B = 0x316 */
+#define DA9150_FG_QIF_VALUE_SHIFT		0
+#define DA9150_FG_QIF_VALUE_MASK		(0xff << 0)
+
+/* DA9150_FW_CTRL_E = 0x317 */
+#define DA9150_FW_FWDL_SEG_SHIFT		0
+#define DA9150_FW_FWDL_SEG_MASK			(0xff << 0)
+
+/* DA9150_FW_CTRL_B = 0x318 */
+#define DA9150_FW_FWDL_VALUE_SHIFT		0
+#define DA9150_FW_FWDL_VALUE_MASK		(0xff << 0)
+
+/* DA9150_GPADC_CMAN = 0x320 */
+#define DA9150_GPADC_CEN_SHIFT			0
+#define DA9150_GPADC_CEN_MASK			(0x01 << 0)
+#define DA9150_GPADC_CMUX_SHIFT			1
+#define DA9150_GPADC_CMUX_MASK			(0x1f << 1)
+
+/* DA9150_GPADC_CRES_A = 0x322 */
+#define DA9150_GPADC_CRES_H_SHIFT		0
+#define DA9150_GPADC_CRES_H_MASK		(0xff << 0)
+
+/* DA9150_GPADC_CRES_B = 0x323 */
+#define DA9150_GPADC_CRUN_SHIFT			0
+#define DA9150_GPADC_CRUN_MASK			(0x01 << 0)
+#define DA9150_GPADC_CRES_L_SHIFT		6
+#define DA9150_GPADC_CRES_L_MASK		(0x03 << 6)
+
+/* DA9150_CC_CFG_A = 0x328 */
+#define DA9150_CC_EN_SHIFT			0
+#define DA9150_CC_EN_MASK			(0x01 << 0)
+#define DA9150_CC_TIMEBASE_SHIFT		1
+#define DA9150_CC_TIMEBASE_MASK			(0x03 << 1)
+#define DA9150_CC_CFG_SHIFT			5
+#define DA9150_CC_CFG_MASK			(0x03 << 5)
+#define DA9150_CC_ENDLESS_MODE_SHIFT		7
+#define DA9150_CC_ENDLESS_MODE_MASK		(0x01 << 7)
+
+/* DA9150_CC_CFG_B = 0x329 */
+#define DA9150_CC_OPT_SHIFT			0
+#define DA9150_CC_OPT_MASK			(0x03 << 0)
+#define DA9150_CC_PREAMP_SHIFT			2
+#define DA9150_CC_PREAMP_MASK			(0x03 << 2)
+
+/* DA9150_CC_ICHG_RES_A = 0x32A */
+#define DA9150_CC_ICHG_RES_H_SHIFT		0
+#define DA9150_CC_ICHG_RES_H_MASK		(0xff << 0)
+
+/* DA9150_CC_ICHG_RES_B = 0x32B */
+#define DA9150_CC_ICHG_RES_L_SHIFT		3
+#define DA9150_CC_ICHG_RES_L_MASK		(0x1f << 3)
+
+/* DA9150_CC_IAVG_RES_A = 0x32C */
+#define DA9150_CC_IAVG_RES_H_SHIFT		0
+#define DA9150_CC_IAVG_RES_H_MASK		(0xff << 0)
+
+/* DA9150_CC_IAVG_RES_B = 0x32D */
+#define DA9150_CC_IAVG_RES_L_SHIFT		0
+#define DA9150_CC_IAVG_RES_L_MASK		(0xff << 0)
+
+/* DA9150_TAUX_CTRL_A = 0x330 */
+#define DA9150_TAUX_EN_SHIFT			0
+#define DA9150_TAUX_EN_MASK			(0x01 << 0)
+#define DA9150_TAUX_MOD_SHIFT			1
+#define DA9150_TAUX_MOD_MASK			(0x01 << 1)
+#define DA9150_TAUX_UPDATE_SHIFT		2
+#define DA9150_TAUX_UPDATE_MASK			(0x01 << 2)
+
+/* DA9150_TAUX_RELOAD_H = 0x332 */
+#define DA9150_TAUX_RLD_H_SHIFT			0
+#define DA9150_TAUX_RLD_H_MASK			(0xff << 0)
+
+/* DA9150_TAUX_RELOAD_L = 0x333 */
+#define DA9150_TAUX_RLD_L_SHIFT			3
+#define DA9150_TAUX_RLD_L_MASK			(0x1f << 3)
+
+/* DA9150_TAUX_VALUE_H = 0x334 */
+#define DA9150_TAUX_VAL_H_SHIFT			0
+#define DA9150_TAUX_VAL_H_MASK			(0xff << 0)
+
+/* DA9150_TAUX_VALUE_L = 0x335 */
+#define DA9150_TAUX_VAL_L_SHIFT			3
+#define DA9150_TAUX_VAL_L_MASK			(0x1f << 3)
+
+/* DA9150_AUX_DATA_0 = 0x338 */
+#define DA9150_AUX_DAT_0_SHIFT			0
+#define DA9150_AUX_DAT_0_MASK			(0xff << 0)
+
+/* DA9150_AUX_DATA_1 = 0x339 */
+#define DA9150_AUX_DAT_1_SHIFT			0
+#define DA9150_AUX_DAT_1_MASK			(0xff << 0)
+
+/* DA9150_AUX_DATA_2 = 0x33A */
+#define DA9150_AUX_DAT_2_SHIFT			0
+#define DA9150_AUX_DAT_2_MASK			(0xff << 0)
+
+/* DA9150_AUX_DATA_3 = 0x33B */
+#define DA9150_AUX_DAT_3_SHIFT			0
+#define DA9150_AUX_DAT_3_MASK			(0xff << 0)
+
+/* DA9150_BIF_CTRL = 0x340 */
+#define DA9150_BIF_ISRC_EN_SHIFT		0
+#define DA9150_BIF_ISRC_EN_MASK			(0x01 << 0)
+
+/* DA9150_TBAT_CTRL_A = 0x342 */
+#define DA9150_TBAT_EN_SHIFT			0
+#define DA9150_TBAT_EN_MASK			(0x01 << 0)
+#define DA9150_TBAT_SW1_SHIFT			1
+#define DA9150_TBAT_SW1_MASK			(0x01 << 1)
+#define DA9150_TBAT_SW2_SHIFT			2
+#define DA9150_TBAT_SW2_MASK			(0x01 << 2)
+
+/* DA9150_TBAT_CTRL_B = 0x343 */
+#define DA9150_TBAT_SW_FRC_SHIFT		0
+#define DA9150_TBAT_SW_FRC_MASK			(0x01 << 0)
+#define DA9150_TBAT_STAT_SW1_SHIFT		1
+#define DA9150_TBAT_STAT_SW1_MASK		(0x01 << 1)
+#define DA9150_TBAT_STAT_SW2_SHIFT		2
+#define DA9150_TBAT_STAT_SW2_MASK		(0x01 << 2)
+#define DA9150_TBAT_HIGH_CURR_SHIFT		3
+#define DA9150_TBAT_HIGH_CURR_MASK		(0x01 << 3)
+
+/* DA9150_TBAT_RES_A = 0x344 */
+#define DA9150_TBAT_RES_H_SHIFT			0
+#define DA9150_TBAT_RES_H_MASK			(0xff << 0)
+
+/* DA9150_TBAT_RES_B = 0x345 */
+#define DA9150_TBAT_RES_DIS_SHIFT		0
+#define DA9150_TBAT_RES_DIS_MASK		(0x01 << 0)
+#define DA9150_TBAT_RES_L_SHIFT			6
+#define DA9150_TBAT_RES_L_MASK			(0x03 << 6)
+
+#endif /* __DA9150_REGISTERS_H */
--
1.9.3

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

* [PATCH v2 2/7] mfd: da9150: Add DT binding documentation for core
  2014-08-28 10:48 ` Adam Thomson
@ 2014-08-28 10:48   ` Adam Thomson
  -1 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 Documentation/devicetree/bindings/mfd/da9150.txt | 41 ++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/da9150.txt

diff --git a/Documentation/devicetree/bindings/mfd/da9150.txt b/Documentation/devicetree/bindings/mfd/da9150.txt
new file mode 100644
index 0000000..d7de150
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/da9150.txt
@@ -0,0 +1,41 @@
+Dialog Semiconductor DA9150 Combined Charger/Fuel-Gauge MFD bindings
+
+DA9150 consists of a group of sub-devices (I2C Only):
+
+Device			 Description
+------			 -----------
+da9150-gpadc		: IIO - GPADC
+da9150-charger		: Power Supply (Charger)
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da9150"
+- reg: Specifies the I2C slave address
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the IRQs from da9150 are delivered to.
+- interrupts: IRQ line info for da9150 chip.
+- interrupt-controller: da9150 has internal IRQs (own IRQ domain).
+
+Sub-devices:
+- da9150-gpadc: See Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
+- da9150-charger: See Documentation/devicetree/bindings/power/da9150-charger.txt
+
+
+Example:
+
+	charger_fg: da9150@58 {
+		compatible = "dlg,da9150";
+		reg = <0x58>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-controller;
+
+		gpadc: da9150-gpadc {
+			...
+		};
+
+		da9150-charger {
+			...
+		};
+	};
--
1.9.3


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

* [PATCH v2 2/7] mfd: da9150: Add DT binding documentation for core
@ 2014-08-28 10:48   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 Documentation/devicetree/bindings/mfd/da9150.txt | 41 ++++++++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/da9150.txt

diff --git a/Documentation/devicetree/bindings/mfd/da9150.txt b/Documentation/devicetree/bindings/mfd/da9150.txt
new file mode 100644
index 0000000..d7de150
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/da9150.txt
@@ -0,0 +1,41 @@
+Dialog Semiconductor DA9150 Combined Charger/Fuel-Gauge MFD bindings
+
+DA9150 consists of a group of sub-devices (I2C Only):
+
+Device			 Description
+------			 -----------
+da9150-gpadc		: IIO - GPADC
+da9150-charger		: Power Supply (Charger)
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da9150"
+- reg: Specifies the I2C slave address
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the IRQs from da9150 are delivered to.
+- interrupts: IRQ line info for da9150 chip.
+- interrupt-controller: da9150 has internal IRQs (own IRQ domain).
+
+Sub-devices:
+- da9150-gpadc: See Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
+- da9150-charger: See Documentation/devicetree/bindings/power/da9150-charger.txt
+
+
+Example:
+
+	charger_fg: da9150@58 {
+		compatible = "dlg,da9150";
+		reg = <0x58>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
+		interrupt-controller;
+
+		gpadc: da9150-gpadc {
+			...
+		};
+
+		da9150-charger {
+			...
+		};
+	};
--
1.9.3

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

* [PATCH v2 3/7] iio: Add support for DA9150 GPADC
  2014-08-28 10:48 ` Adam Thomson
@ 2014-08-28 10:48   ` Adam Thomson
  -1 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

This patch adds support for DA9150 Charger & Fuel-Gauge IC GPADC.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 drivers/iio/adc/Kconfig        |   9 +
 drivers/iio/adc/Makefile       |   1 +
 drivers/iio/adc/da9150-gpadc.c | 430 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 440 insertions(+)
 create mode 100644 drivers/iio/adc/da9150-gpadc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 11b048a..8041347 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -127,6 +127,15 @@ config AT91_ADC
 	help
 	  Say yes here to build support for Atmel AT91 ADC.

+config DA9150_GPADC
+	tristate "Dialog DA9150 GPADC driver support"
+	depends on MFD_DA9150
+	help
+	  Say yes here to build support for Dialog DA9150 GPADC.
+
+	  This driver can also be built as a module. If chosen, the module name
+	  will be da9150-gpadc.
+
 config EXYNOS_ADC
 	tristate "Exynos ADC driver support"
 	depends on ARCH_EXYNOS || (OF && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ad81b51..48413d2 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
 obj-$(CONFIG_AD7887) += ad7887.o
 obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
+obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1027) += max1027.o
diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
new file mode 100644
index 0000000..21a21a9
--- /dev/null
+++ b/drivers/iio/adc/da9150-gpadc.c
@@ -0,0 +1,430 @@
+/*
+ * DA9150 GPADC Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/pdata.h>
+#include <linux/mfd/da9150/registers.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+
+/* Channels */
+enum da9150_gpadc_hw_channel {
+	DA9150_GPADC_HW_CHAN_GPIOA_2V = 0,
+	DA9150_GPADC_HW_CHAN_GPIOA_2V_,
+	DA9150_GPADC_HW_CHAN_GPIOB_2V,
+	DA9150_GPADC_HW_CHAN_GPIOB_2V_,
+	DA9150_GPADC_HW_CHAN_GPIOC_2V,
+	DA9150_GPADC_HW_CHAN_GPIOC_2V_,
+	DA9150_GPADC_HW_CHAN_GPIOD_2V,
+	DA9150_GPADC_HW_CHAN_GPIOD_2V_,
+	DA9150_GPADC_HW_CHAN_IBUS_SENSE,
+	DA9150_GPADC_HW_CHAN_IBUS_SENSE_,
+	DA9150_GPADC_HW_CHAN_VBUS_DIV,
+	DA9150_GPADC_HW_CHAN_VBUS_DIV_,
+	DA9150_GPADC_HW_CHAN_ID,
+	DA9150_GPADC_HW_CHAN_ID_,
+	DA9150_GPADC_HW_CHAN_VSYS,
+	DA9150_GPADC_HW_CHAN_VSYS_,
+	DA9150_GPADC_HW_CHAN_GPIOA_5V,
+	DA9150_GPADC_HW_CHAN_GPIOA_5V_,
+	DA9150_GPADC_HW_CHAN_GPIOB_5V,
+	DA9150_GPADC_HW_CHAN_GPIOB_5V_,
+	DA9150_GPADC_HW_CHAN_GPIOC_5V,
+	DA9150_GPADC_HW_CHAN_GPIOC_5V_,
+	DA9150_GPADC_HW_CHAN_GPIOD_5V,
+	DA9150_GPADC_HW_CHAN_GPIOD_5V_,
+	DA9150_GPADC_HW_CHAN_VBAT,
+	DA9150_GPADC_HW_CHAN_VBAT_,
+	DA9150_GPADC_HW_CHAN_TBAT,
+	DA9150_GPADC_HW_CHAN_TBAT_,
+	DA9150_GPADC_HW_CHAN_TJUNC_CORE,
+	DA9150_GPADC_HW_CHAN_TJUNC_CORE_,
+	DA9150_GPADC_HW_CHAN_TJUNC_OVP,
+	DA9150_GPADC_HW_CHAN_TJUNC_OVP_,
+};
+
+enum da9150_gpadc_channel {
+	DA9150_GPADC_CHAN_GPIOA = 0,
+	DA9150_GPADC_CHAN_GPIOB,
+	DA9150_GPADC_CHAN_GPIOC,
+	DA9150_GPADC_CHAN_GPIOD,
+	DA9150_GPADC_CHAN_IBUS,
+	DA9150_GPADC_CHAN_VBUS,
+	DA9150_GPADC_CHAN_ID,
+	DA9150_GPADC_CHAN_VSYS,
+	DA9150_GPADC_CHAN_VBAT,
+	DA9150_GPADC_CHAN_TBAT,
+	DA9150_GPADC_CHAN_TJUNC_CORE,
+	DA9150_GPADC_CHAN_TJUNC_OVP,
+};
+
+/* Private data */
+struct da9150_gpadc {
+	struct da9150 *da9150;
+	struct device *dev;
+
+	struct mutex lock;
+	struct completion complete;
+};
+
+
+static irqreturn_t da9150_gpadc_irq(int irq, void *data)
+{
+
+	struct da9150_gpadc *gpadc = data;
+
+	complete(&gpadc->complete);
+
+	return IRQ_HANDLED;
+}
+
+int da9150_gpadc_read_adc(struct da9150_gpadc *gpadc, int hw_chan)
+{
+	u8 result_regs[2];
+	int result;
+
+	mutex_lock(&gpadc->lock);
+
+	/* Set channel & enable measurement */
+	da9150_reg_write(gpadc->da9150, DA9150_GPADC_MAN,
+			 (DA9150_GPADC_EN_MASK |
+			  hw_chan << DA9150_GPADC_MUX_SHIFT));
+
+	/* Consume left-over completion from a previous timeout */
+	try_wait_for_completion(&gpadc->complete);
+
+	/* Check for actual completion */
+	wait_for_completion_timeout(&gpadc->complete, msecs_to_jiffies(5));
+
+	/* Read result and status from device */
+	da9150_bulk_read(gpadc->da9150, DA9150_GPADC_RES_A, 2, result_regs);
+
+	mutex_unlock(&gpadc->lock);
+
+	/* Check to make sure device really has completed reading */
+	if (result_regs[1] & DA9150_GPADC_RUN_MASK) {
+		dev_err(gpadc->dev, "Timeout on channel %d of GP-ADC\n",
+			hw_chan);
+		return -ETIMEDOUT;
+	}
+
+	/* LSBs - 2 bits */
+	result = (result_regs[1] & DA9150_GPADC_RES_L_MASK) >>
+		 DA9150_GPADC_RES_L_SHIFT;
+	/* MSBs - 8 bits */
+	result |= result_regs[0] << DA9150_GPADC_RES_L_BITS;
+
+	return result;
+}
+
+static inline int da9150_gpadc_gpio_5v_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return (((6 * ((raw_val * 1000) + 500)) / 1024) * 1000);
+}
+
+static inline int da9150_gpadc_ibus_current_avg(int raw_val)
+{
+	/* Convert to uA */
+	return (((4 * ((raw_val * 1000) + 500)) / 2048) * 1000);
+}
+
+static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return (((21 * ((raw_val * 1000) + 500)) / 1024) * 1000);
+}
+
+static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return (((3 * ((raw_val * 1000) + 500)) / 512) * 1000);
+}
+
+static inline int da9150_gpadc_tjunc_temp(int raw_val)
+{
+	/* Convert to 0.1 degrees C */
+	return (((879 - (1023 - raw_val)) * 10000) / 4420);
+}
+
+static inline int da9150_gpadc_vbat_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return ((2932 * raw_val) + 1500000);
+}
+
+int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
+				int hw_chan)
+{
+	int raw_val, ret;
+
+	raw_val = da9150_gpadc_read_adc(gpadc, hw_chan);
+	if (raw_val < 0)
+		return raw_val;
+
+	switch (channel) {
+	case DA9150_GPADC_CHAN_GPIOA:
+	case DA9150_GPADC_CHAN_GPIOB:
+	case DA9150_GPADC_CHAN_GPIOC:
+	case DA9150_GPADC_CHAN_GPIOD:
+		ret = da9150_gpadc_gpio_5v_voltage_now(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_IBUS:
+		ret = da9150_gpadc_ibus_current_avg(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_VBUS:
+		ret = da9150_gpadc_vbus_21v_voltage_now(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_VSYS:
+		ret = da9150_gpadc_vsys_6v_voltage_now(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_TJUNC_CORE:
+	case DA9150_GPADC_CHAN_TJUNC_OVP:
+		ret = da9150_gpadc_tjunc_temp(raw_val);
+		break;
+	default:
+		/* No processing for other channels so return raw value */
+		ret = raw_val;
+		break;
+	}
+
+	return ret;
+}
+
+int da9150_gpadc_read_scale(int channel)
+{
+	int ret;
+
+	switch (channel) {
+	case DA9150_GPADC_CHAN_VBAT:
+		ret = 2932;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int da9150_gpadc_read_offset(int channel)
+{
+	int ret;
+
+	switch (channel) {
+	case DA9150_GPADC_CHAN_VBAT:
+		ret = 1500000 / 2932;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int da9150_gpadc_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan,
+			  int *val, int *val2, long mask)
+{
+	struct da9150_gpadc *gpadc = iio_priv(indio_dev);
+	int ret;
+
+	if ((chan->channel < DA9150_GPADC_CHAN_GPIOA) ||
+	    (chan->channel > DA9150_GPADC_CHAN_TJUNC_OVP))
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
+		ret = da9150_gpadc_read_processed(gpadc, chan->channel,
+						  chan->address);
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		ret = da9150_gpadc_read_scale(chan->channel);
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		ret = da9150_gpadc_read_offset(chan->channel);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+
+	return IIO_VAL_INT;
+}
+
+static const struct iio_info da9150_gpadc_info = {
+	.read_raw = &da9150_gpadc_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define GPADC_CHANNEL(_id, _hw_id, _type, chan_info, _ext_name) {	\
+	.type = _type,							\
+	.indexed = 1,							\
+	.channel = DA9150_GPADC_CHAN_##_id,				\
+	.address = DA9150_GPADC_HW_CHAN_##_hw_id,			\
+	.info_mask_separate = chan_info,				\
+	.extend_name = _ext_name,					\
+	.datasheet_name = #_id,						\
+}
+
+#define GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name)	\
+	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_RAW), _ext_name)
+
+#define GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name)	\
+	GPADC_CHANNEL(_id, _hw_id, _type,			\
+		      BIT(IIO_CHAN_INFO_RAW) |			\
+		      BIT(IIO_CHAN_INFO_SCALE) |		\
+		      BIT(IIO_CHAN_INFO_OFFSET),		\
+		      _ext_name)
+
+#define GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name)		\
+	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_PROCESSED),	\
+		      _ext_name)
+
+/* Supported channels */
+static const struct iio_chan_spec da9150_gpadc_channels[] = {
+	GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_5V, IIO_VOLTAGE, "GPIOA"),
+	GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_5V, IIO_VOLTAGE, "GPIOB"),
+	GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_5V, IIO_VOLTAGE, "GPIOC"),
+	GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_5V, IIO_VOLTAGE, "GPIOD"),
+	GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
+	GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
+	GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
+	GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
+	GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
+	GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
+	GPADC_CHANNEL_PROCESSED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP, "TJUNC_CORE"),
+	GPADC_CHANNEL_PROCESSED(TJUNC_OVP, TJUNC_OVP, IIO_TEMP, "TJUNC_OVP"),
+};
+
+/* Default maps used by da9150-charger */
+static struct iio_map da9150_gpadc_default_maps[] = {
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_IBUS",
+		.adc_channel_label = "IBUS",
+	},
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_VBUS",
+		.adc_channel_label = "VBUS",
+	},
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_TJUNC",
+		.adc_channel_label = "TJUNC_CORE",
+	},
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_VBAT",
+		.adc_channel_label = "VBAT",
+	},
+	{},
+};
+
+static int da9150_gpadc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da9150 *da9150 = dev_get_drvdata(dev->parent);
+	struct da9150_gpadc *gpadc;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev,
+					  sizeof(struct da9150_gpadc));
+	if (!indio_dev) {
+		dev_err(&pdev->dev, "Failed to allocate IIO device\n");
+		return -ENOMEM;
+	}
+	gpadc = iio_priv(indio_dev);
+
+	platform_set_drvdata(pdev, indio_dev);
+	gpadc->da9150 = da9150;
+	gpadc->dev = dev;
+
+	ret = iio_map_array_register(indio_dev, da9150_gpadc_default_maps);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO maps: %d\n", ret);
+		goto iio_map_fail;
+	}
+
+	mutex_init(&gpadc->lock);
+	init_completion(&gpadc->complete);
+
+	/* Register IRQ */
+	ret = da9150_register_irq(pdev, gpadc, da9150_gpadc_irq, "GPADC");
+	if (ret < 0)
+		goto irq_fail;
+
+	indio_dev->name = dev_name(dev);
+	indio_dev->dev.parent = dev;
+	indio_dev->dev.of_node = pdev->dev.of_node;
+	indio_dev->info = &da9150_gpadc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = da9150_gpadc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO device: %d\n", ret);
+		goto iio_dev_fail;
+	}
+
+	return ret;
+
+iio_dev_fail:
+irq_fail:
+	iio_map_array_unregister(indio_dev);
+
+iio_map_fail:
+	return ret;
+}
+
+static int da9150_gpadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	iio_map_array_unregister(indio_dev);
+	iio_device_unregister(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver da9150_gpadc_driver = {
+	.driver = {
+		.name = "da9150-gpadc",
+		.owner = THIS_MODULE,
+	},
+	.probe = da9150_gpadc_probe,
+	.remove = da9150_gpadc_remove,
+};
+
+module_platform_driver(da9150_gpadc_driver);
+
+MODULE_DESCRIPTION("GPADC Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
--
1.9.3


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

* [PATCH v2 3/7] iio: Add support for DA9150 GPADC
@ 2014-08-28 10:48   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:48 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

This patch adds support for DA9150 Charger & Fuel-Gauge IC GPADC.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 drivers/iio/adc/Kconfig        |   9 +
 drivers/iio/adc/Makefile       |   1 +
 drivers/iio/adc/da9150-gpadc.c | 430 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 440 insertions(+)
 create mode 100644 drivers/iio/adc/da9150-gpadc.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 11b048a..8041347 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -127,6 +127,15 @@ config AT91_ADC
 	help
 	  Say yes here to build support for Atmel AT91 ADC.

+config DA9150_GPADC
+	tristate "Dialog DA9150 GPADC driver support"
+	depends on MFD_DA9150
+	help
+	  Say yes here to build support for Dialog DA9150 GPADC.
+
+	  This driver can also be built as a module. If chosen, the module name
+	  will be da9150-gpadc.
+
 config EXYNOS_ADC
 	tristate "Exynos ADC driver support"
 	depends on ARCH_EXYNOS || (OF && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ad81b51..48413d2 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
 obj-$(CONFIG_AD7887) += ad7887.o
 obj-$(CONFIG_AD799X) += ad799x.o
 obj-$(CONFIG_AT91_ADC) += at91_adc.o
+obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
 obj-$(CONFIG_MAX1027) += max1027.o
diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
new file mode 100644
index 0000000..21a21a9
--- /dev/null
+++ b/drivers/iio/adc/da9150-gpadc.c
@@ -0,0 +1,430 @@
+/*
+ * DA9150 GPADC Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/pdata.h>
+#include <linux/mfd/da9150/registers.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+
+/* Channels */
+enum da9150_gpadc_hw_channel {
+	DA9150_GPADC_HW_CHAN_GPIOA_2V = 0,
+	DA9150_GPADC_HW_CHAN_GPIOA_2V_,
+	DA9150_GPADC_HW_CHAN_GPIOB_2V,
+	DA9150_GPADC_HW_CHAN_GPIOB_2V_,
+	DA9150_GPADC_HW_CHAN_GPIOC_2V,
+	DA9150_GPADC_HW_CHAN_GPIOC_2V_,
+	DA9150_GPADC_HW_CHAN_GPIOD_2V,
+	DA9150_GPADC_HW_CHAN_GPIOD_2V_,
+	DA9150_GPADC_HW_CHAN_IBUS_SENSE,
+	DA9150_GPADC_HW_CHAN_IBUS_SENSE_,
+	DA9150_GPADC_HW_CHAN_VBUS_DIV,
+	DA9150_GPADC_HW_CHAN_VBUS_DIV_,
+	DA9150_GPADC_HW_CHAN_ID,
+	DA9150_GPADC_HW_CHAN_ID_,
+	DA9150_GPADC_HW_CHAN_VSYS,
+	DA9150_GPADC_HW_CHAN_VSYS_,
+	DA9150_GPADC_HW_CHAN_GPIOA_5V,
+	DA9150_GPADC_HW_CHAN_GPIOA_5V_,
+	DA9150_GPADC_HW_CHAN_GPIOB_5V,
+	DA9150_GPADC_HW_CHAN_GPIOB_5V_,
+	DA9150_GPADC_HW_CHAN_GPIOC_5V,
+	DA9150_GPADC_HW_CHAN_GPIOC_5V_,
+	DA9150_GPADC_HW_CHAN_GPIOD_5V,
+	DA9150_GPADC_HW_CHAN_GPIOD_5V_,
+	DA9150_GPADC_HW_CHAN_VBAT,
+	DA9150_GPADC_HW_CHAN_VBAT_,
+	DA9150_GPADC_HW_CHAN_TBAT,
+	DA9150_GPADC_HW_CHAN_TBAT_,
+	DA9150_GPADC_HW_CHAN_TJUNC_CORE,
+	DA9150_GPADC_HW_CHAN_TJUNC_CORE_,
+	DA9150_GPADC_HW_CHAN_TJUNC_OVP,
+	DA9150_GPADC_HW_CHAN_TJUNC_OVP_,
+};
+
+enum da9150_gpadc_channel {
+	DA9150_GPADC_CHAN_GPIOA = 0,
+	DA9150_GPADC_CHAN_GPIOB,
+	DA9150_GPADC_CHAN_GPIOC,
+	DA9150_GPADC_CHAN_GPIOD,
+	DA9150_GPADC_CHAN_IBUS,
+	DA9150_GPADC_CHAN_VBUS,
+	DA9150_GPADC_CHAN_ID,
+	DA9150_GPADC_CHAN_VSYS,
+	DA9150_GPADC_CHAN_VBAT,
+	DA9150_GPADC_CHAN_TBAT,
+	DA9150_GPADC_CHAN_TJUNC_CORE,
+	DA9150_GPADC_CHAN_TJUNC_OVP,
+};
+
+/* Private data */
+struct da9150_gpadc {
+	struct da9150 *da9150;
+	struct device *dev;
+
+	struct mutex lock;
+	struct completion complete;
+};
+
+
+static irqreturn_t da9150_gpadc_irq(int irq, void *data)
+{
+
+	struct da9150_gpadc *gpadc = data;
+
+	complete(&gpadc->complete);
+
+	return IRQ_HANDLED;
+}
+
+int da9150_gpadc_read_adc(struct da9150_gpadc *gpadc, int hw_chan)
+{
+	u8 result_regs[2];
+	int result;
+
+	mutex_lock(&gpadc->lock);
+
+	/* Set channel & enable measurement */
+	da9150_reg_write(gpadc->da9150, DA9150_GPADC_MAN,
+			 (DA9150_GPADC_EN_MASK |
+			  hw_chan << DA9150_GPADC_MUX_SHIFT));
+
+	/* Consume left-over completion from a previous timeout */
+	try_wait_for_completion(&gpadc->complete);
+
+	/* Check for actual completion */
+	wait_for_completion_timeout(&gpadc->complete, msecs_to_jiffies(5));
+
+	/* Read result and status from device */
+	da9150_bulk_read(gpadc->da9150, DA9150_GPADC_RES_A, 2, result_regs);
+
+	mutex_unlock(&gpadc->lock);
+
+	/* Check to make sure device really has completed reading */
+	if (result_regs[1] & DA9150_GPADC_RUN_MASK) {
+		dev_err(gpadc->dev, "Timeout on channel %d of GP-ADC\n",
+			hw_chan);
+		return -ETIMEDOUT;
+	}
+
+	/* LSBs - 2 bits */
+	result = (result_regs[1] & DA9150_GPADC_RES_L_MASK) >>
+		 DA9150_GPADC_RES_L_SHIFT;
+	/* MSBs - 8 bits */
+	result |= result_regs[0] << DA9150_GPADC_RES_L_BITS;
+
+	return result;
+}
+
+static inline int da9150_gpadc_gpio_5v_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return (((6 * ((raw_val * 1000) + 500)) / 1024) * 1000);
+}
+
+static inline int da9150_gpadc_ibus_current_avg(int raw_val)
+{
+	/* Convert to uA */
+	return (((4 * ((raw_val * 1000) + 500)) / 2048) * 1000);
+}
+
+static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return (((21 * ((raw_val * 1000) + 500)) / 1024) * 1000);
+}
+
+static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return (((3 * ((raw_val * 1000) + 500)) / 512) * 1000);
+}
+
+static inline int da9150_gpadc_tjunc_temp(int raw_val)
+{
+	/* Convert to 0.1 degrees C */
+	return (((879 - (1023 - raw_val)) * 10000) / 4420);
+}
+
+static inline int da9150_gpadc_vbat_voltage_now(int raw_val)
+{
+	/* Convert to uV */
+	return ((2932 * raw_val) + 1500000);
+}
+
+int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
+				int hw_chan)
+{
+	int raw_val, ret;
+
+	raw_val = da9150_gpadc_read_adc(gpadc, hw_chan);
+	if (raw_val < 0)
+		return raw_val;
+
+	switch (channel) {
+	case DA9150_GPADC_CHAN_GPIOA:
+	case DA9150_GPADC_CHAN_GPIOB:
+	case DA9150_GPADC_CHAN_GPIOC:
+	case DA9150_GPADC_CHAN_GPIOD:
+		ret = da9150_gpadc_gpio_5v_voltage_now(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_IBUS:
+		ret = da9150_gpadc_ibus_current_avg(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_VBUS:
+		ret = da9150_gpadc_vbus_21v_voltage_now(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_VSYS:
+		ret = da9150_gpadc_vsys_6v_voltage_now(raw_val);
+		break;
+	case DA9150_GPADC_CHAN_TJUNC_CORE:
+	case DA9150_GPADC_CHAN_TJUNC_OVP:
+		ret = da9150_gpadc_tjunc_temp(raw_val);
+		break;
+	default:
+		/* No processing for other channels so return raw value */
+		ret = raw_val;
+		break;
+	}
+
+	return ret;
+}
+
+int da9150_gpadc_read_scale(int channel)
+{
+	int ret;
+
+	switch (channel) {
+	case DA9150_GPADC_CHAN_VBAT:
+		ret = 2932;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int da9150_gpadc_read_offset(int channel)
+{
+	int ret;
+
+	switch (channel) {
+	case DA9150_GPADC_CHAN_VBAT:
+		ret = 1500000 / 2932;
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+int da9150_gpadc_read_raw(struct iio_dev *indio_dev,
+			  struct iio_chan_spec const *chan,
+			  int *val, int *val2, long mask)
+{
+	struct da9150_gpadc *gpadc = iio_priv(indio_dev);
+	int ret;
+
+	if ((chan->channel < DA9150_GPADC_CHAN_GPIOA) ||
+	    (chan->channel > DA9150_GPADC_CHAN_TJUNC_OVP))
+		return -EINVAL;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
+		ret = da9150_gpadc_read_processed(gpadc, chan->channel,
+						  chan->address);
+		break;
+	case IIO_CHAN_INFO_SCALE:
+		ret = da9150_gpadc_read_scale(chan->channel);
+		break;
+	case IIO_CHAN_INFO_OFFSET:
+		ret = da9150_gpadc_read_offset(chan->channel);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+
+	return IIO_VAL_INT;
+}
+
+static const struct iio_info da9150_gpadc_info = {
+	.read_raw = &da9150_gpadc_read_raw,
+	.driver_module = THIS_MODULE,
+};
+
+#define GPADC_CHANNEL(_id, _hw_id, _type, chan_info, _ext_name) {	\
+	.type = _type,							\
+	.indexed = 1,							\
+	.channel = DA9150_GPADC_CHAN_##_id,				\
+	.address = DA9150_GPADC_HW_CHAN_##_hw_id,			\
+	.info_mask_separate = chan_info,				\
+	.extend_name = _ext_name,					\
+	.datasheet_name = #_id,						\
+}
+
+#define GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name)	\
+	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_RAW), _ext_name)
+
+#define GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name)	\
+	GPADC_CHANNEL(_id, _hw_id, _type,			\
+		      BIT(IIO_CHAN_INFO_RAW) |			\
+		      BIT(IIO_CHAN_INFO_SCALE) |		\
+		      BIT(IIO_CHAN_INFO_OFFSET),		\
+		      _ext_name)
+
+#define GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name)		\
+	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_PROCESSED),	\
+		      _ext_name)
+
+/* Supported channels */
+static const struct iio_chan_spec da9150_gpadc_channels[] = {
+	GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_5V, IIO_VOLTAGE, "GPIOA"),
+	GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_5V, IIO_VOLTAGE, "GPIOB"),
+	GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_5V, IIO_VOLTAGE, "GPIOC"),
+	GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_5V, IIO_VOLTAGE, "GPIOD"),
+	GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
+	GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
+	GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
+	GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
+	GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
+	GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
+	GPADC_CHANNEL_PROCESSED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP, "TJUNC_CORE"),
+	GPADC_CHANNEL_PROCESSED(TJUNC_OVP, TJUNC_OVP, IIO_TEMP, "TJUNC_OVP"),
+};
+
+/* Default maps used by da9150-charger */
+static struct iio_map da9150_gpadc_default_maps[] = {
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_IBUS",
+		.adc_channel_label = "IBUS",
+	},
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_VBUS",
+		.adc_channel_label = "VBUS",
+	},
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_TJUNC",
+		.adc_channel_label = "TJUNC_CORE",
+	},
+	{
+		.consumer_dev_name = "da9150-charger",
+		.consumer_channel = "CHAN_VBAT",
+		.adc_channel_label = "VBAT",
+	},
+	{},
+};
+
+static int da9150_gpadc_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da9150 *da9150 = dev_get_drvdata(dev->parent);
+	struct da9150_gpadc *gpadc;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev,
+					  sizeof(struct da9150_gpadc));
+	if (!indio_dev) {
+		dev_err(&pdev->dev, "Failed to allocate IIO device\n");
+		return -ENOMEM;
+	}
+	gpadc = iio_priv(indio_dev);
+
+	platform_set_drvdata(pdev, indio_dev);
+	gpadc->da9150 = da9150;
+	gpadc->dev = dev;
+
+	ret = iio_map_array_register(indio_dev, da9150_gpadc_default_maps);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO maps: %d\n", ret);
+		goto iio_map_fail;
+	}
+
+	mutex_init(&gpadc->lock);
+	init_completion(&gpadc->complete);
+
+	/* Register IRQ */
+	ret = da9150_register_irq(pdev, gpadc, da9150_gpadc_irq, "GPADC");
+	if (ret < 0)
+		goto irq_fail;
+
+	indio_dev->name = dev_name(dev);
+	indio_dev->dev.parent = dev;
+	indio_dev->dev.of_node = pdev->dev.of_node;
+	indio_dev->info = &da9150_gpadc_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = da9150_gpadc_channels;
+	indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels);
+
+	ret = iio_device_register(indio_dev);
+	if (ret) {
+		dev_err(dev, "Failed to register IIO device: %d\n", ret);
+		goto iio_dev_fail;
+	}
+
+	return ret;
+
+iio_dev_fail:
+irq_fail:
+	iio_map_array_unregister(indio_dev);
+
+iio_map_fail:
+	return ret;
+}
+
+static int da9150_gpadc_remove(struct platform_device *pdev)
+{
+	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+	iio_map_array_unregister(indio_dev);
+	iio_device_unregister(indio_dev);
+
+	return 0;
+}
+
+static struct platform_driver da9150_gpadc_driver = {
+	.driver = {
+		.name = "da9150-gpadc",
+		.owner = THIS_MODULE,
+	},
+	.probe = da9150_gpadc_probe,
+	.remove = da9150_gpadc_remove,
+};
+
+module_platform_driver(da9150_gpadc_driver);
+
+MODULE_DESCRIPTION("GPADC Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
--
1.9.3

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

* [PATCH v2 4/7] iio: da9150: Add DT binding documentation for GPADC
@ 2014-08-28 10:49   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 .../devicetree/bindings/iio/adc/da9150-gpadc.txt         | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt b/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
new file mode 100644
index 0000000..c07228d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
@@ -0,0 +1,16 @@
+Dialog Semiconductor DA9150 IIO GPADC bindings
+
+Required properties:
+- compatible: "dlg,da9150-gpadc" for DA9150 IIO GPADC
+- #io-channel-cells: Should be set to <1>
+  (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info)
+
+For further information on GPADC channels, see device datasheet.
+
+
+Example:
+
+	gpadc: da9150-gpadc {
+		compatible = "dlg,da9150-gpadc";
+		#io-channel-cells = <1>;
+	};
--
1.9.3


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

* [PATCH v2 4/7] iio: da9150: Add DT binding documentation for GPADC
@ 2014-08-28 10:49   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Joe Perches
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	support.opensource-WBD+wuPFNBhBDgjK7y7TUQ

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
---
 .../devicetree/bindings/iio/adc/da9150-gpadc.txt         | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt b/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
new file mode 100644
index 0000000..c07228d
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/da9150-gpadc.txt
@@ -0,0 +1,16 @@
+Dialog Semiconductor DA9150 IIO GPADC bindings
+
+Required properties:
+- compatible: "dlg,da9150-gpadc" for DA9150 IIO GPADC
+- #io-channel-cells: Should be set to <1>
+  (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info)
+
+For further information on GPADC channels, see device datasheet.
+
+
+Example:
+
+	gpadc: da9150-gpadc {
+		compatible = "dlg,da9150-gpadc";
+		#io-channel-cells = <1>;
+	};
--
1.9.3

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

* [PATCH v2 5/7] power: Add support for DA9150 Charger
  2014-08-28 10:48 ` Adam Thomson
@ 2014-08-28 10:49   ` Adam Thomson
  -1 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

This patch adds support for DA9150 Charger & Fuel-Guage IC Charger.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 drivers/power/Kconfig          |  12 +
 drivers/power/Makefile         |   1 +
 drivers/power/da9150-charger.c | 715 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 728 insertions(+)
 create mode 100644 drivers/power/da9150-charger.c

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 73cfcdf..622884d 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -192,6 +192,18 @@ config BATTERY_DA9052
 	  Say Y here to enable support for batteries charger integrated into
 	  DA9052 PMIC.

+config CHARGER_DA9150
+	tristate "Dialog Semiconductor DA9150 Charger support"
+	depends on MFD_DA9150
+	depends on DA9150_GPADC
+	depends on IIO
+	help
+	  Say Y here to enable support for charger unit of the DA9150
+	  Integrated Charger & Fuel-Gauge IC.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called da9150-charger.
+
 config BATTERY_MAX17040
 	tristate "Maxim MAX17040 Fuel Gauge"
 	depends on I2C
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index dfa8942..0c1896d 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_BATTERY_SBS)	+= sbs-battery.o
 obj-$(CONFIG_BATTERY_BQ27x00)	+= bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
 obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
+obj-$(CONFIG_CHARGER_DA9150)	+= da9150-charger.o
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
diff --git a/drivers/power/da9150-charger.c b/drivers/power/da9150-charger.c
new file mode 100644
index 0000000..391ad19c
--- /dev/null
+++ b/drivers/power/da9150-charger.c
@@ -0,0 +1,715 @@
+/*
+ * DA9150 Charger Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/power_supply.h>
+#include <linux/notifier.h>
+#include <linux/usb/phy.h>
+#include <linux/iio/consumer.h>
+#include <linux/sysfs.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/pdata.h>
+#include <linux/mfd/da9150/registers.h>
+
+/* Private data */
+struct da9150_charger_attr_map {
+	struct device_attribute attr;
+	u16 reg;
+	u8 shift;
+	u8 mask;
+};
+
+struct da9150_charger {
+	struct da9150 *da9150;
+	struct device *dev;
+
+	struct power_supply usb;
+	struct power_supply battery;
+	struct power_supply *supply_online;
+
+	struct usb_phy *usb_phy;
+	struct notifier_block otg_nb;
+	struct work_struct otg_work;
+	unsigned long usb_event;
+
+	struct iio_channel *ibus_chan;
+	struct iio_channel *vbus_chan;
+	struct iio_channel *tjunc_chan;
+	struct iio_channel *vbat_chan;
+};
+
+static inline int da9150_charger_supply_online(struct da9150_charger *charger,
+					       struct power_supply *psy,
+					       union power_supply_propval *val)
+{
+	val->intval = (psy == charger->supply_online) ? 1 : 0;
+
+	return 0;
+}
+
+/* Charger Properties */
+static int da9150_charger_vbus_voltage_now(struct da9150_charger *charger,
+					   union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->vbus_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - uV units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static int da9150_charger_ibus_current_avg(struct da9150_charger *charger,
+					   union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->ibus_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - uA degrees C units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static int da9150_charger_tjunc_temp(struct da9150_charger *charger,
+				     union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->tjunc_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - 0.1 degrees C units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static enum power_supply_property da9150_charger_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static int da9150_charger_get_prop(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct da9150_charger *charger = dev_get_drvdata(psy->dev->parent);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = da9150_charger_supply_online(charger, psy, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = da9150_charger_vbus_voltage_now(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		ret = da9150_charger_ibus_current_avg(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		ret = da9150_charger_tjunc_temp(charger, val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Battery Properties */
+static int da9150_charger_battery_status(struct da9150_charger *charger,
+					 union power_supply_propval *val)
+{
+	u8 reg;
+
+	/* Check to see if battery is discharging */
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_H);
+
+	if (((reg & DA9150_VBUS_STAT_MASK) == DA9150_VBUS_STAT_OFF) ||
+	    ((reg & DA9150_VBUS_STAT_MASK) == DA9150_VBUS_STAT_WAIT)) {
+		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+
+		return 0;
+	}
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+
+	/* Now check for other states */
+	switch (reg & DA9150_CHG_STAT_MASK) {
+	case DA9150_CHG_STAT_ACT:
+	case DA9150_CHG_STAT_PRE:
+	case DA9150_CHG_STAT_CC:
+	case DA9150_CHG_STAT_CV:
+		val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case DA9150_CHG_STAT_OFF:
+	case DA9150_CHG_STAT_SUSP:
+	case DA9150_CHG_STAT_TEMP:
+	case DA9150_CHG_STAT_TIME:
+	case DA9150_CHG_STAT_BAT:
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	case DA9150_CHG_STAT_FULL:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int da9150_charger_battery_health(struct da9150_charger *charger,
+					 union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+
+	/* Check if temperature limit reached */
+	switch (reg & DA9150_CHG_TEMP_MASK) {
+	case DA9150_CHG_TEMP_UNDER:
+		val->intval = POWER_SUPPLY_HEALTH_COLD;
+		return 0;
+	case DA9150_CHG_TEMP_OVER:
+		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		return 0;
+	default:
+		break;
+	}
+
+	/* Check for other health states */
+	switch (reg & DA9150_CHG_STAT_MASK) {
+	case DA9150_CHG_STAT_ACT:
+	case DA9150_CHG_STAT_PRE:
+		val->intval = POWER_SUPPLY_HEALTH_DEAD;
+		break;
+	case DA9150_CHG_STAT_TIME:
+		val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	}
+
+	return 0;
+}
+
+static int da9150_charger_battery_present(struct da9150_charger *charger,
+					  union power_supply_propval *val)
+{
+	u8 reg;
+
+	/* Check if battery present or removed */
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+	if ((reg & DA9150_CHG_STAT_MASK) == DA9150_CHG_STAT_BAT)
+		val->intval = 0;
+	else
+		val->intval = 1;
+
+	return 0;
+}
+
+static int da9150_charger_battery_charge_type(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+
+	switch (reg & DA9150_CHG_STAT_MASK) {
+	case DA9150_CHG_STAT_CC:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		break;
+	case DA9150_CHG_STAT_ACT:
+	case DA9150_CHG_STAT_PRE:
+	case DA9150_CHG_STAT_CV:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+		break;
+	}
+
+	return 0;
+}
+
+static int da9150_charger_battery_voltage_min(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_C);
+
+	/* Value starts at 2500 mV, 50 mV increments, presented in uV */
+	val->intval = ((reg & DA9150_CHG_VFAULT_MASK) * 50000) + 2500000;
+
+	return 0;
+}
+
+static int da9150_charger_battery_voltage_now(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->vbat_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - uV units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static int da9150_charger_battery_current_max(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	int reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_D);
+
+	/* 25mA increments */
+	val->intval = reg * 25000;
+
+	return 0;
+}
+
+static int da9150_charger_battery_voltage_max(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_B);
+
+	/* Value starts at 3650 mV, 25 mV increments, presented in uV */
+	val->intval = ((reg & DA9150_CHG_VBAT_MASK) * 25000) + 3650000;
+	return 0;
+}
+
+static enum power_supply_property da9150_charger_bat_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+};
+
+static int da9150_charger_battery_get_prop(struct power_supply *psy,
+					   enum power_supply_property psp,
+					   union power_supply_propval *val)
+{
+	struct da9150_charger *charger = dev_get_drvdata(psy->dev->parent);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		ret = da9150_charger_battery_status(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = da9150_charger_supply_online(charger, psy, val);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = da9150_charger_battery_health(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		ret = da9150_charger_battery_present(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		ret = da9150_charger_battery_charge_type(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		ret = da9150_charger_battery_voltage_min(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = da9150_charger_battery_voltage_now(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		ret = da9150_charger_battery_current_max(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		ret = da9150_charger_battery_voltage_max(charger, val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Other properties */
+static ssize_t da9150_charger_attr_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+
+#define DA9150_CHARGER_ATTR(_name, _reg, _shift, _mask)		\
+	{							\
+		.attr = __ATTR(_name, S_IRUGO,			\
+			       da9150_charger_attr_show,	\
+			       NULL),				\
+		.reg = _reg,					\
+		.shift = _shift,				\
+		.mask = _mask,					\
+	}
+
+static struct da9150_charger_attr_map da9150_charger_attrs[] = {
+	DA9150_CHARGER_ATTR(chg_en, DA9150_PPR_CHGCTRL_A,
+			    DA9150_CHG_EN_SHIFT, DA9150_CHG_EN_MASK),
+	DA9150_CHARGER_ATTR(chg_ipre, DA9150_PPR_CHGCTRL_C,
+			    DA9150_CHG_IPRE_SHIFT, DA9150_CHG_IPRE_MASK),
+	DA9150_CHARGER_ATTR(chg_iend, DA9150_PPR_CHGCTRL_E,
+			    DA9150_CHG_IEND_SHIFT, DA9150_CHG_IEND_MASK),
+	DA9150_CHARGER_ATTR(chg_temp, DA9150_STATUS_J,
+			    DA9150_CHG_TEMP_SHIFT, DA9150_CHG_TEMP_MASK),
+	DA9150_CHARGER_ATTR(chg_vdrop, DA9150_PPR_CHGCTRL_B,
+			    DA9150_CHG_VDROP_SHIFT, DA9150_CHG_VDROP_MASK),
+	DA9150_CHARGER_ATTR(tbat_upper, DA9150_PPR_THYST_E,
+			    DA9150_TBAT_T5_SHIFT, DA9150_TBAT_T5_MASK),
+	DA9150_CHARGER_ATTR(tbat_lower, DA9150_PPR_THYST_A,
+			    DA9150_TBAT_T1_SHIFT, DA9150_TBAT_T1_MASK),
+	DA9150_CHARGER_ATTR(vbus_mode, DA9150_PPR_BKCTRL_A,
+			    DA9150_VBUS_MODE_SHIFT, DA9150_VBUS_MODE_MASK),
+	DA9150_CHARGER_ATTR(vbus_tred, DA9150_STATUS_H,
+			    DA9150_VBUS_TRED_SHIFT, DA9150_VBUS_TRED_MASK),
+	DA9150_CHARGER_ATTR(vbus_drop_stat, DA9150_STATUS_H,
+			    DA9150_VBUS_DROP_STAT_SHIFT,
+			    DA9150_VBUS_DROP_STAT_MASK),
+};
+
+static ssize_t da9150_charger_attr_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct da9150_charger *charger = dev_get_drvdata(dev);
+	struct da9150_charger_attr_map *charger_attrs;
+	int i;
+
+	/* Find attribute, and print out register field contents. */
+	for (i = 0, charger_attrs = da9150_charger_attrs;
+	     i < ARRAY_SIZE(da9150_charger_attrs);
+	     ++i, ++charger_attrs) {
+		if (attr == &charger_attrs->attr) {
+			u8 val;
+
+			val = da9150_reg_read(charger->da9150,
+					      charger_attrs->reg);
+			val &= charger_attrs->mask;
+			val = val >> charger_attrs->shift;
+
+			return sprintf(buf, "0x%x\n", val);
+		}
+	}
+
+	return 0;
+}
+
+static irqreturn_t da9150_charger_chg_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+
+	power_supply_changed(&charger->battery);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t da9150_charger_tjunc_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+
+	/* Nothing we can really do except report this. */
+	dev_crit(charger->dev, "TJunc over temperature!!!\n");
+	power_supply_changed(&charger->usb);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t da9150_charger_vfault_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+
+	/* Nothing we can really do except report this. */
+	dev_crit(charger->dev, "VSYS under voltage!!!\n");
+	power_supply_changed(&charger->usb);
+	power_supply_changed(&charger->battery);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t da9150_charger_vbus_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_H);
+
+	/* Charger plugged in or battery only */
+	switch (reg & DA9150_VBUS_STAT_MASK) {
+	case DA9150_VBUS_STAT_OFF:
+	case DA9150_VBUS_STAT_WAIT:
+		charger->supply_online = &charger->battery;
+		break;
+	case DA9150_VBUS_STAT_CHG:
+		charger->supply_online = &charger->usb;
+		break;
+	default:
+		dev_warn(charger->dev, "Unknown VBUS state - reg = 0x%x\n",
+			 reg);
+		charger->supply_online = NULL;
+		break;
+	}
+
+	power_supply_changed(&charger->usb);
+	power_supply_changed(&charger->battery);
+
+	return IRQ_HANDLED;
+}
+
+static void da9150_charger_otg_work(struct work_struct *data)
+{
+	struct da9150_charger *charger =
+		container_of(data, struct da9150_charger, otg_work);
+
+	switch (charger->usb_event) {
+	case USB_EVENT_ID:
+		/* Enable OTG Boost */
+		da9150_set_bits(charger->da9150, DA9150_PPR_BKCTRL_A,
+				DA9150_VBUS_MODE_MASK, DA9150_VBUS_MODE_OTG);
+		break;
+	case USB_EVENT_NONE:
+		/* Revert to charge mode */
+		power_supply_changed(&charger->usb);
+		power_supply_changed(&charger->battery);
+		da9150_set_bits(charger->da9150, DA9150_PPR_BKCTRL_A,
+				DA9150_VBUS_MODE_MASK, DA9150_VBUS_MODE_CHG);
+		break;
+	}
+}
+
+static int da9150_charger_otg_ncb(struct notifier_block *nb, unsigned long val,
+				  void *priv)
+{
+	struct da9150_charger *charger =
+		container_of(nb, struct da9150_charger, otg_nb);
+
+	dev_dbg(charger->dev, "DA9150 OTG notify %lu\n", val);
+
+	charger->usb_event = val;
+	schedule_work(&charger->otg_work);
+
+	return NOTIFY_OK;
+}
+
+static int da9150_charger_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da9150 *da9150 = dev_get_drvdata(dev->parent);
+	struct da9150_charger *charger;
+	struct power_supply *usb, *battery;
+	u8 reg;
+	int i, ret;
+
+	charger = devm_kzalloc(dev, sizeof(struct da9150_charger), GFP_KERNEL);
+	if (charger == NULL)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, charger);
+	charger->da9150 = da9150;
+	charger->dev = dev;
+
+	/* Acquire ADC channels */
+	charger->ibus_chan = iio_channel_get(dev, "CHAN_IBUS");
+	if (IS_ERR(charger->ibus_chan)) {
+		ret = PTR_ERR(charger->ibus_chan);
+		goto ibus_chan_fail;
+	}
+
+	charger->vbus_chan = iio_channel_get(dev, "CHAN_VBUS");
+	if (IS_ERR(charger->vbus_chan)) {
+		ret = PTR_ERR(charger->vbus_chan);
+		goto vbus_chan_fail;
+	}
+
+	charger->tjunc_chan = iio_channel_get(dev, "CHAN_TJUNC");
+	if (IS_ERR(charger->tjunc_chan)) {
+		ret = PTR_ERR(charger->tjunc_chan);
+		goto tjunc_chan_fail;
+	}
+
+	charger->vbat_chan = iio_channel_get(dev, "CHAN_VBAT");
+	if (IS_ERR(charger->vbat_chan)) {
+		ret = PTR_ERR(charger->vbat_chan);
+		goto vbat_chan_fail;
+	}
+
+	/* Register power supplies */
+	usb = &charger->usb;
+	battery = &charger->battery;
+
+	usb->name = "da9150-usb",
+	usb->type = POWER_SUPPLY_TYPE_USB;
+	usb->properties = da9150_charger_props;
+	usb->num_properties = ARRAY_SIZE(da9150_charger_props);
+	usb->get_property = da9150_charger_get_prop;
+	ret = power_supply_register(dev, usb);
+	if (ret)
+		goto usb_fail;
+
+	battery->name = "da9150-battery";
+	battery->type = POWER_SUPPLY_TYPE_BATTERY;
+	battery->properties = da9150_charger_bat_props;
+	battery->num_properties = ARRAY_SIZE(da9150_charger_bat_props);
+	battery->get_property = da9150_charger_battery_get_prop;
+	ret = power_supply_register(dev, battery);
+	if (ret)
+		goto battery_fail;
+
+	/* Create additional sysfs attributes */
+	for (i = 0; i < ARRAY_SIZE(da9150_charger_attrs); ++i) {
+		ret = device_create_file(dev, &da9150_charger_attrs[i].attr);
+		if (ret < 0)
+			goto sysfs_fail;
+	}
+
+	/* Get initial online supply */
+	reg = da9150_reg_read(da9150, DA9150_STATUS_H);
+
+	/* Charger plugged in or battery only */
+	switch (reg & DA9150_VBUS_STAT_MASK) {
+	case DA9150_VBUS_STAT_OFF:
+	case DA9150_VBUS_STAT_WAIT:
+		charger->supply_online = &charger->battery;
+		break;
+	case DA9150_VBUS_STAT_CHG:
+		charger->supply_online = &charger->usb;
+		break;
+	default:
+		dev_warn(dev, "Unknown VBUS state - reg = 0x%x\n", reg);
+		charger->supply_online = NULL;
+		break;
+	}
+
+	/* Setup OTG reporting & configuration */
+	charger->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+	if (!IS_ERR_OR_NULL(charger->usb_phy)) {
+		INIT_WORK(&charger->otg_work, da9150_charger_otg_work);
+		charger->otg_nb.notifier_call = da9150_charger_otg_ncb;
+		usb_register_notifier(charger->usb_phy, &charger->otg_nb);
+	}
+
+	/* Register IRQs */
+	ret = da9150_register_irq(pdev, charger, da9150_charger_chg_irq,
+				  "CHG_STATUS");
+	if (ret < 0)
+		goto irq_fail;
+
+	ret = da9150_register_irq(pdev, charger, da9150_charger_tjunc_irq,
+				  "CHG_TJUNC");
+	if (ret < 0)
+		goto irq_fail;
+
+	ret = da9150_register_irq(pdev, charger, da9150_charger_vfault_irq,
+				  "CHG_VFAULT");
+	if (ret < 0)
+		goto irq_fail;
+
+	ret = da9150_register_irq(pdev, charger, da9150_charger_vbus_irq,
+				  "CHG_VBUS");
+	if (ret < 0)
+		goto irq_fail;
+
+	return 0;
+
+irq_fail:
+	if (!IS_ERR_OR_NULL(charger->usb_phy))
+		usb_unregister_notifier(charger->usb_phy, &charger->otg_nb);
+sysfs_fail:
+	while (--i >= 0)
+		device_remove_file(&pdev->dev, &da9150_charger_attrs[i].attr);
+	power_supply_unregister(battery);
+
+battery_fail:
+	power_supply_unregister(usb);
+
+usb_fail:
+	iio_channel_release(charger->vbat_chan);
+
+vbat_chan_fail:
+	iio_channel_release(charger->tjunc_chan);
+
+tjunc_chan_fail:
+	iio_channel_release(charger->vbus_chan);
+
+vbus_chan_fail:
+	iio_channel_release(charger->ibus_chan);
+
+ibus_chan_fail:
+	return ret;
+}
+
+static int da9150_charger_remove(struct platform_device *pdev)
+{
+	struct da9150_charger *charger = platform_get_drvdata(pdev);
+	int i;
+
+	/* Make sure IRQs are released before unregistering power supplies */
+	da9150_release_irq(pdev, charger, "CHG_VBUS");
+	da9150_release_irq(pdev, charger, "CHG_VFAULT");
+	da9150_release_irq(pdev, charger, "CHG_TJUNC");
+	da9150_release_irq(pdev, charger, "CHG_STATUS");
+
+	if (!IS_ERR_OR_NULL(charger->usb_phy))
+		usb_unregister_notifier(charger->usb_phy, &charger->otg_nb);
+
+	power_supply_unregister(&charger->battery);
+	power_supply_unregister(&charger->usb);
+
+	for (i = 0; i < ARRAY_SIZE(da9150_charger_attrs); ++i)
+		device_remove_file(&pdev->dev, &da9150_charger_attrs[i].attr);
+
+	/* Release ADC channels */
+	iio_channel_release(charger->ibus_chan);
+	iio_channel_release(charger->vbus_chan);
+	iio_channel_release(charger->tjunc_chan);
+	iio_channel_release(charger->vbat_chan);
+
+	return 0;
+}
+
+static struct platform_driver da9150_charger_driver = {
+	.driver = {
+		.name = "da9150-charger",
+		.owner = THIS_MODULE,
+	},
+	.probe = da9150_charger_probe,
+	.remove = da9150_charger_remove,
+};
+
+module_platform_driver(da9150_charger_driver);
+
+MODULE_DESCRIPTION("Charger Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
--
1.9.3


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

* [PATCH v2 5/7] power: Add support for DA9150 Charger
@ 2014-08-28 10:49   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

This patch adds support for DA9150 Charger & Fuel-Guage IC Charger.

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 drivers/power/Kconfig          |  12 +
 drivers/power/Makefile         |   1 +
 drivers/power/da9150-charger.c | 715 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 728 insertions(+)
 create mode 100644 drivers/power/da9150-charger.c

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 73cfcdf..622884d 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -192,6 +192,18 @@ config BATTERY_DA9052
 	  Say Y here to enable support for batteries charger integrated into
 	  DA9052 PMIC.

+config CHARGER_DA9150
+	tristate "Dialog Semiconductor DA9150 Charger support"
+	depends on MFD_DA9150
+	depends on DA9150_GPADC
+	depends on IIO
+	help
+	  Say Y here to enable support for charger unit of the DA9150
+	  Integrated Charger & Fuel-Gauge IC.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called da9150-charger.
+
 config BATTERY_MAX17040
 	tristate "Maxim MAX17040 Fuel Gauge"
 	depends on I2C
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index dfa8942..0c1896d 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_BATTERY_SBS)	+= sbs-battery.o
 obj-$(CONFIG_BATTERY_BQ27x00)	+= bq27x00_battery.o
 obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
 obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
+obj-$(CONFIG_CHARGER_DA9150)	+= da9150-charger.o
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
diff --git a/drivers/power/da9150-charger.c b/drivers/power/da9150-charger.c
new file mode 100644
index 0000000..391ad19c
--- /dev/null
+++ b/drivers/power/da9150-charger.c
@@ -0,0 +1,715 @@
+/*
+ * DA9150 Charger Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/power_supply.h>
+#include <linux/notifier.h>
+#include <linux/usb/phy.h>
+#include <linux/iio/consumer.h>
+#include <linux/sysfs.h>
+
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/pdata.h>
+#include <linux/mfd/da9150/registers.h>
+
+/* Private data */
+struct da9150_charger_attr_map {
+	struct device_attribute attr;
+	u16 reg;
+	u8 shift;
+	u8 mask;
+};
+
+struct da9150_charger {
+	struct da9150 *da9150;
+	struct device *dev;
+
+	struct power_supply usb;
+	struct power_supply battery;
+	struct power_supply *supply_online;
+
+	struct usb_phy *usb_phy;
+	struct notifier_block otg_nb;
+	struct work_struct otg_work;
+	unsigned long usb_event;
+
+	struct iio_channel *ibus_chan;
+	struct iio_channel *vbus_chan;
+	struct iio_channel *tjunc_chan;
+	struct iio_channel *vbat_chan;
+};
+
+static inline int da9150_charger_supply_online(struct da9150_charger *charger,
+					       struct power_supply *psy,
+					       union power_supply_propval *val)
+{
+	val->intval = (psy == charger->supply_online) ? 1 : 0;
+
+	return 0;
+}
+
+/* Charger Properties */
+static int da9150_charger_vbus_voltage_now(struct da9150_charger *charger,
+					   union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->vbus_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - uV units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static int da9150_charger_ibus_current_avg(struct da9150_charger *charger,
+					   union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->ibus_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - uA degrees C units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static int da9150_charger_tjunc_temp(struct da9150_charger *charger,
+				     union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->tjunc_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - 0.1 degrees C units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static enum power_supply_property da9150_charger_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_TEMP,
+};
+
+static int da9150_charger_get_prop(struct power_supply *psy,
+				   enum power_supply_property psp,
+				   union power_supply_propval *val)
+{
+	struct da9150_charger *charger = dev_get_drvdata(psy->dev->parent);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = da9150_charger_supply_online(charger, psy, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = da9150_charger_vbus_voltage_now(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		ret = da9150_charger_ibus_current_avg(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		ret = da9150_charger_tjunc_temp(charger, val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Battery Properties */
+static int da9150_charger_battery_status(struct da9150_charger *charger,
+					 union power_supply_propval *val)
+{
+	u8 reg;
+
+	/* Check to see if battery is discharging */
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_H);
+
+	if (((reg & DA9150_VBUS_STAT_MASK) == DA9150_VBUS_STAT_OFF) ||
+	    ((reg & DA9150_VBUS_STAT_MASK) == DA9150_VBUS_STAT_WAIT)) {
+		val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+
+		return 0;
+	}
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+
+	/* Now check for other states */
+	switch (reg & DA9150_CHG_STAT_MASK) {
+	case DA9150_CHG_STAT_ACT:
+	case DA9150_CHG_STAT_PRE:
+	case DA9150_CHG_STAT_CC:
+	case DA9150_CHG_STAT_CV:
+		val->intval = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case DA9150_CHG_STAT_OFF:
+	case DA9150_CHG_STAT_SUSP:
+	case DA9150_CHG_STAT_TEMP:
+	case DA9150_CHG_STAT_TIME:
+	case DA9150_CHG_STAT_BAT:
+		val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	case DA9150_CHG_STAT_FULL:
+		val->intval = POWER_SUPPLY_STATUS_FULL;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	}
+
+	return 0;
+}
+
+static int da9150_charger_battery_health(struct da9150_charger *charger,
+					 union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+
+	/* Check if temperature limit reached */
+	switch (reg & DA9150_CHG_TEMP_MASK) {
+	case DA9150_CHG_TEMP_UNDER:
+		val->intval = POWER_SUPPLY_HEALTH_COLD;
+		return 0;
+	case DA9150_CHG_TEMP_OVER:
+		val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
+		return 0;
+	default:
+		break;
+	}
+
+	/* Check for other health states */
+	switch (reg & DA9150_CHG_STAT_MASK) {
+	case DA9150_CHG_STAT_ACT:
+	case DA9150_CHG_STAT_PRE:
+		val->intval = POWER_SUPPLY_HEALTH_DEAD;
+		break;
+	case DA9150_CHG_STAT_TIME:
+		val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	}
+
+	return 0;
+}
+
+static int da9150_charger_battery_present(struct da9150_charger *charger,
+					  union power_supply_propval *val)
+{
+	u8 reg;
+
+	/* Check if battery present or removed */
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+	if ((reg & DA9150_CHG_STAT_MASK) == DA9150_CHG_STAT_BAT)
+		val->intval = 0;
+	else
+		val->intval = 1;
+
+	return 0;
+}
+
+static int da9150_charger_battery_charge_type(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_J);
+
+	switch (reg & DA9150_CHG_STAT_MASK) {
+	case DA9150_CHG_STAT_CC:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
+		break;
+	case DA9150_CHG_STAT_ACT:
+	case DA9150_CHG_STAT_PRE:
+	case DA9150_CHG_STAT_CV:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+		break;
+	default:
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
+		break;
+	}
+
+	return 0;
+}
+
+static int da9150_charger_battery_voltage_min(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_C);
+
+	/* Value starts at 2500 mV, 50 mV increments, presented in uV */
+	val->intval = ((reg & DA9150_CHG_VFAULT_MASK) * 50000) + 2500000;
+
+	return 0;
+}
+
+static int da9150_charger_battery_voltage_now(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	struct iio_channel *chan = charger->vbat_chan;
+
+	if (!chan)
+		return -EINVAL;
+
+	/* Read processed value - uV units */
+	return iio_read_channel_processed(chan, &val->intval);
+}
+
+static int da9150_charger_battery_current_max(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	int reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_D);
+
+	/* 25mA increments */
+	val->intval = reg * 25000;
+
+	return 0;
+}
+
+static int da9150_charger_battery_voltage_max(struct da9150_charger *charger,
+					      union power_supply_propval *val)
+{
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_PPR_CHGCTRL_B);
+
+	/* Value starts at 3650 mV, 25 mV increments, presented in uV */
+	val->intval = ((reg & DA9150_CHG_VBAT_MASK) * 25000) + 3650000;
+	return 0;
+}
+
+static enum power_supply_property da9150_charger_bat_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+};
+
+static int da9150_charger_battery_get_prop(struct power_supply *psy,
+					   enum power_supply_property psp,
+					   union power_supply_propval *val)
+{
+	struct da9150_charger *charger = dev_get_drvdata(psy->dev->parent);
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		ret = da9150_charger_battery_status(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = da9150_charger_supply_online(charger, psy, val);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = da9150_charger_battery_health(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		ret = da9150_charger_battery_present(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		ret = da9150_charger_battery_charge_type(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+		ret = da9150_charger_battery_voltage_min(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = da9150_charger_battery_voltage_now(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		ret = da9150_charger_battery_current_max(charger, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		ret = da9150_charger_battery_voltage_max(charger, val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Other properties */
+static ssize_t da9150_charger_attr_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf);
+
+#define DA9150_CHARGER_ATTR(_name, _reg, _shift, _mask)		\
+	{							\
+		.attr = __ATTR(_name, S_IRUGO,			\
+			       da9150_charger_attr_show,	\
+			       NULL),				\
+		.reg = _reg,					\
+		.shift = _shift,				\
+		.mask = _mask,					\
+	}
+
+static struct da9150_charger_attr_map da9150_charger_attrs[] = {
+	DA9150_CHARGER_ATTR(chg_en, DA9150_PPR_CHGCTRL_A,
+			    DA9150_CHG_EN_SHIFT, DA9150_CHG_EN_MASK),
+	DA9150_CHARGER_ATTR(chg_ipre, DA9150_PPR_CHGCTRL_C,
+			    DA9150_CHG_IPRE_SHIFT, DA9150_CHG_IPRE_MASK),
+	DA9150_CHARGER_ATTR(chg_iend, DA9150_PPR_CHGCTRL_E,
+			    DA9150_CHG_IEND_SHIFT, DA9150_CHG_IEND_MASK),
+	DA9150_CHARGER_ATTR(chg_temp, DA9150_STATUS_J,
+			    DA9150_CHG_TEMP_SHIFT, DA9150_CHG_TEMP_MASK),
+	DA9150_CHARGER_ATTR(chg_vdrop, DA9150_PPR_CHGCTRL_B,
+			    DA9150_CHG_VDROP_SHIFT, DA9150_CHG_VDROP_MASK),
+	DA9150_CHARGER_ATTR(tbat_upper, DA9150_PPR_THYST_E,
+			    DA9150_TBAT_T5_SHIFT, DA9150_TBAT_T5_MASK),
+	DA9150_CHARGER_ATTR(tbat_lower, DA9150_PPR_THYST_A,
+			    DA9150_TBAT_T1_SHIFT, DA9150_TBAT_T1_MASK),
+	DA9150_CHARGER_ATTR(vbus_mode, DA9150_PPR_BKCTRL_A,
+			    DA9150_VBUS_MODE_SHIFT, DA9150_VBUS_MODE_MASK),
+	DA9150_CHARGER_ATTR(vbus_tred, DA9150_STATUS_H,
+			    DA9150_VBUS_TRED_SHIFT, DA9150_VBUS_TRED_MASK),
+	DA9150_CHARGER_ATTR(vbus_drop_stat, DA9150_STATUS_H,
+			    DA9150_VBUS_DROP_STAT_SHIFT,
+			    DA9150_VBUS_DROP_STAT_MASK),
+};
+
+static ssize_t da9150_charger_attr_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct da9150_charger *charger = dev_get_drvdata(dev);
+	struct da9150_charger_attr_map *charger_attrs;
+	int i;
+
+	/* Find attribute, and print out register field contents. */
+	for (i = 0, charger_attrs = da9150_charger_attrs;
+	     i < ARRAY_SIZE(da9150_charger_attrs);
+	     ++i, ++charger_attrs) {
+		if (attr == &charger_attrs->attr) {
+			u8 val;
+
+			val = da9150_reg_read(charger->da9150,
+					      charger_attrs->reg);
+			val &= charger_attrs->mask;
+			val = val >> charger_attrs->shift;
+
+			return sprintf(buf, "0x%x\n", val);
+		}
+	}
+
+	return 0;
+}
+
+static irqreturn_t da9150_charger_chg_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+
+	power_supply_changed(&charger->battery);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t da9150_charger_tjunc_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+
+	/* Nothing we can really do except report this. */
+	dev_crit(charger->dev, "TJunc over temperature!!!\n");
+	power_supply_changed(&charger->usb);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t da9150_charger_vfault_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+
+	/* Nothing we can really do except report this. */
+	dev_crit(charger->dev, "VSYS under voltage!!!\n");
+	power_supply_changed(&charger->usb);
+	power_supply_changed(&charger->battery);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t da9150_charger_vbus_irq(int irq, void *data)
+{
+	struct da9150_charger *charger = data;
+	u8 reg;
+
+	reg = da9150_reg_read(charger->da9150, DA9150_STATUS_H);
+
+	/* Charger plugged in or battery only */
+	switch (reg & DA9150_VBUS_STAT_MASK) {
+	case DA9150_VBUS_STAT_OFF:
+	case DA9150_VBUS_STAT_WAIT:
+		charger->supply_online = &charger->battery;
+		break;
+	case DA9150_VBUS_STAT_CHG:
+		charger->supply_online = &charger->usb;
+		break;
+	default:
+		dev_warn(charger->dev, "Unknown VBUS state - reg = 0x%x\n",
+			 reg);
+		charger->supply_online = NULL;
+		break;
+	}
+
+	power_supply_changed(&charger->usb);
+	power_supply_changed(&charger->battery);
+
+	return IRQ_HANDLED;
+}
+
+static void da9150_charger_otg_work(struct work_struct *data)
+{
+	struct da9150_charger *charger =
+		container_of(data, struct da9150_charger, otg_work);
+
+	switch (charger->usb_event) {
+	case USB_EVENT_ID:
+		/* Enable OTG Boost */
+		da9150_set_bits(charger->da9150, DA9150_PPR_BKCTRL_A,
+				DA9150_VBUS_MODE_MASK, DA9150_VBUS_MODE_OTG);
+		break;
+	case USB_EVENT_NONE:
+		/* Revert to charge mode */
+		power_supply_changed(&charger->usb);
+		power_supply_changed(&charger->battery);
+		da9150_set_bits(charger->da9150, DA9150_PPR_BKCTRL_A,
+				DA9150_VBUS_MODE_MASK, DA9150_VBUS_MODE_CHG);
+		break;
+	}
+}
+
+static int da9150_charger_otg_ncb(struct notifier_block *nb, unsigned long val,
+				  void *priv)
+{
+	struct da9150_charger *charger =
+		container_of(nb, struct da9150_charger, otg_nb);
+
+	dev_dbg(charger->dev, "DA9150 OTG notify %lu\n", val);
+
+	charger->usb_event = val;
+	schedule_work(&charger->otg_work);
+
+	return NOTIFY_OK;
+}
+
+static int da9150_charger_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct da9150 *da9150 = dev_get_drvdata(dev->parent);
+	struct da9150_charger *charger;
+	struct power_supply *usb, *battery;
+	u8 reg;
+	int i, ret;
+
+	charger = devm_kzalloc(dev, sizeof(struct da9150_charger), GFP_KERNEL);
+	if (charger == NULL)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, charger);
+	charger->da9150 = da9150;
+	charger->dev = dev;
+
+	/* Acquire ADC channels */
+	charger->ibus_chan = iio_channel_get(dev, "CHAN_IBUS");
+	if (IS_ERR(charger->ibus_chan)) {
+		ret = PTR_ERR(charger->ibus_chan);
+		goto ibus_chan_fail;
+	}
+
+	charger->vbus_chan = iio_channel_get(dev, "CHAN_VBUS");
+	if (IS_ERR(charger->vbus_chan)) {
+		ret = PTR_ERR(charger->vbus_chan);
+		goto vbus_chan_fail;
+	}
+
+	charger->tjunc_chan = iio_channel_get(dev, "CHAN_TJUNC");
+	if (IS_ERR(charger->tjunc_chan)) {
+		ret = PTR_ERR(charger->tjunc_chan);
+		goto tjunc_chan_fail;
+	}
+
+	charger->vbat_chan = iio_channel_get(dev, "CHAN_VBAT");
+	if (IS_ERR(charger->vbat_chan)) {
+		ret = PTR_ERR(charger->vbat_chan);
+		goto vbat_chan_fail;
+	}
+
+	/* Register power supplies */
+	usb = &charger->usb;
+	battery = &charger->battery;
+
+	usb->name = "da9150-usb",
+	usb->type = POWER_SUPPLY_TYPE_USB;
+	usb->properties = da9150_charger_props;
+	usb->num_properties = ARRAY_SIZE(da9150_charger_props);
+	usb->get_property = da9150_charger_get_prop;
+	ret = power_supply_register(dev, usb);
+	if (ret)
+		goto usb_fail;
+
+	battery->name = "da9150-battery";
+	battery->type = POWER_SUPPLY_TYPE_BATTERY;
+	battery->properties = da9150_charger_bat_props;
+	battery->num_properties = ARRAY_SIZE(da9150_charger_bat_props);
+	battery->get_property = da9150_charger_battery_get_prop;
+	ret = power_supply_register(dev, battery);
+	if (ret)
+		goto battery_fail;
+
+	/* Create additional sysfs attributes */
+	for (i = 0; i < ARRAY_SIZE(da9150_charger_attrs); ++i) {
+		ret = device_create_file(dev, &da9150_charger_attrs[i].attr);
+		if (ret < 0)
+			goto sysfs_fail;
+	}
+
+	/* Get initial online supply */
+	reg = da9150_reg_read(da9150, DA9150_STATUS_H);
+
+	/* Charger plugged in or battery only */
+	switch (reg & DA9150_VBUS_STAT_MASK) {
+	case DA9150_VBUS_STAT_OFF:
+	case DA9150_VBUS_STAT_WAIT:
+		charger->supply_online = &charger->battery;
+		break;
+	case DA9150_VBUS_STAT_CHG:
+		charger->supply_online = &charger->usb;
+		break;
+	default:
+		dev_warn(dev, "Unknown VBUS state - reg = 0x%x\n", reg);
+		charger->supply_online = NULL;
+		break;
+	}
+
+	/* Setup OTG reporting & configuration */
+	charger->usb_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
+	if (!IS_ERR_OR_NULL(charger->usb_phy)) {
+		INIT_WORK(&charger->otg_work, da9150_charger_otg_work);
+		charger->otg_nb.notifier_call = da9150_charger_otg_ncb;
+		usb_register_notifier(charger->usb_phy, &charger->otg_nb);
+	}
+
+	/* Register IRQs */
+	ret = da9150_register_irq(pdev, charger, da9150_charger_chg_irq,
+				  "CHG_STATUS");
+	if (ret < 0)
+		goto irq_fail;
+
+	ret = da9150_register_irq(pdev, charger, da9150_charger_tjunc_irq,
+				  "CHG_TJUNC");
+	if (ret < 0)
+		goto irq_fail;
+
+	ret = da9150_register_irq(pdev, charger, da9150_charger_vfault_irq,
+				  "CHG_VFAULT");
+	if (ret < 0)
+		goto irq_fail;
+
+	ret = da9150_register_irq(pdev, charger, da9150_charger_vbus_irq,
+				  "CHG_VBUS");
+	if (ret < 0)
+		goto irq_fail;
+
+	return 0;
+
+irq_fail:
+	if (!IS_ERR_OR_NULL(charger->usb_phy))
+		usb_unregister_notifier(charger->usb_phy, &charger->otg_nb);
+sysfs_fail:
+	while (--i >= 0)
+		device_remove_file(&pdev->dev, &da9150_charger_attrs[i].attr);
+	power_supply_unregister(battery);
+
+battery_fail:
+	power_supply_unregister(usb);
+
+usb_fail:
+	iio_channel_release(charger->vbat_chan);
+
+vbat_chan_fail:
+	iio_channel_release(charger->tjunc_chan);
+
+tjunc_chan_fail:
+	iio_channel_release(charger->vbus_chan);
+
+vbus_chan_fail:
+	iio_channel_release(charger->ibus_chan);
+
+ibus_chan_fail:
+	return ret;
+}
+
+static int da9150_charger_remove(struct platform_device *pdev)
+{
+	struct da9150_charger *charger = platform_get_drvdata(pdev);
+	int i;
+
+	/* Make sure IRQs are released before unregistering power supplies */
+	da9150_release_irq(pdev, charger, "CHG_VBUS");
+	da9150_release_irq(pdev, charger, "CHG_VFAULT");
+	da9150_release_irq(pdev, charger, "CHG_TJUNC");
+	da9150_release_irq(pdev, charger, "CHG_STATUS");
+
+	if (!IS_ERR_OR_NULL(charger->usb_phy))
+		usb_unregister_notifier(charger->usb_phy, &charger->otg_nb);
+
+	power_supply_unregister(&charger->battery);
+	power_supply_unregister(&charger->usb);
+
+	for (i = 0; i < ARRAY_SIZE(da9150_charger_attrs); ++i)
+		device_remove_file(&pdev->dev, &da9150_charger_attrs[i].attr);
+
+	/* Release ADC channels */
+	iio_channel_release(charger->ibus_chan);
+	iio_channel_release(charger->vbus_chan);
+	iio_channel_release(charger->tjunc_chan);
+	iio_channel_release(charger->vbat_chan);
+
+	return 0;
+}
+
+static struct platform_driver da9150_charger_driver = {
+	.driver = {
+		.name = "da9150-charger",
+		.owner = THIS_MODULE,
+	},
+	.probe = da9150_charger_probe,
+	.remove = da9150_charger_remove,
+};
+
+module_platform_driver(da9150_charger_driver);
+
+MODULE_DESCRIPTION("Charger Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
+MODULE_LICENSE("GPL");
--
1.9.3

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

* [PATCH v2 6/7] power: da9150: Add DT binding documentation for charger
  2014-08-28 10:48 ` Adam Thomson
@ 2014-08-28 10:49   ` Adam Thomson
  -1 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 .../devicetree/bindings/power/da9150-charger.txt   | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/da9150-charger.txt

diff --git a/Documentation/devicetree/bindings/power/da9150-charger.txt b/Documentation/devicetree/bindings/power/da9150-charger.txt
new file mode 100644
index 0000000..f390666
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/da9150-charger.txt
@@ -0,0 +1,26 @@
+Dialog Semiconductor DA9150 Charger Power Supply bindings
+
+Required properties:
+- compatible: "dlg,da9150-charger" for DA9150 Charger Power Supply
+
+Optional properties:
+- io-channels: List of phandle and IIO specifier pairs
+- io-channel-names: List of channel names used by charger
+      ["CHAN_IBUS", "CHAN_VBUS", "CHAN_TJUNC", "CHAN_VBAT"]
+  (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info)
+
+
+Example:
+
+	da9150-charger {
+		compatible = "dlg,da9150-charger";
+
+		io-channels = <&gpadc 0>,
+			      <&gpadc 2>,
+			      <&gpadc 8>,
+			      <&gpadc 5>;
+		io-channel-names = "CHAN_IBUS",
+				   "CHAN_VBUS",
+				   "CHAN_TJUNC",
+				   "CHAN_VBAT";
+	};
--
1.9.3


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

* [PATCH v2 6/7] power: da9150: Add DT binding documentation for charger
@ 2014-08-28 10:49   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 .../devicetree/bindings/power/da9150-charger.txt   | 26 ++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/power/da9150-charger.txt

diff --git a/Documentation/devicetree/bindings/power/da9150-charger.txt b/Documentation/devicetree/bindings/power/da9150-charger.txt
new file mode 100644
index 0000000..f390666
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/da9150-charger.txt
@@ -0,0 +1,26 @@
+Dialog Semiconductor DA9150 Charger Power Supply bindings
+
+Required properties:
+- compatible: "dlg,da9150-charger" for DA9150 Charger Power Supply
+
+Optional properties:
+- io-channels: List of phandle and IIO specifier pairs
+- io-channel-names: List of channel names used by charger
+      ["CHAN_IBUS", "CHAN_VBUS", "CHAN_TJUNC", "CHAN_VBAT"]
+  (See Documentation/devicetree/bindings/iio/iio-bindings.txt for further info)
+
+
+Example:
+
+	da9150-charger {
+		compatible = "dlg,da9150-charger";
+
+		io-channels = <&gpadc 0>,
+			      <&gpadc 2>,
+			      <&gpadc 8>,
+			      <&gpadc 5>;
+		io-channel-names = "CHAN_IBUS",
+				   "CHAN_VBUS",
+				   "CHAN_TJUNC",
+				   "CHAN_VBAT";
+	};
--
1.9.3

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

* [PATCH v2 7/7] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list.
  2014-08-28 10:48 ` Adam Thomson
@ 2014-08-28 10:49   ` Adam Thomson
  -1 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 MAINTAINERS | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index aefa948..6dc0aee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2883,12 +2883,15 @@ S:	Supported
 F:	Documentation/hwmon/da90??
 F:	drivers/gpio/gpio-da90??.c
 F:	drivers/hwmon/da90??-hwmon.c
+F:	drivers/iio/adc/da91??-*.c
 F:	drivers/input/misc/da90??_onkey.c
 F:	drivers/input/touchscreen/da9052_tsi.c
 F:	drivers/leds/leds-da90??.c
 F:	drivers/mfd/da903x.c
 F:	drivers/mfd/da90??-*.c
+F:	drivers/mfd/da91??-*.c
 F:	drivers/power/da9052-battery.c
+F:	drivers/power/da91??-*.c
 F:	drivers/regulator/da903x.c
 F:	drivers/regulator/da9???-regulator.[ch]
 F:	drivers/rtc/rtc-da90??.c
@@ -2898,6 +2901,7 @@ F:	include/linux/mfd/da903x.h
 F:	include/linux/mfd/da9052/
 F:	include/linux/mfd/da9055/
 F:	include/linux/mfd/da9063/
+F:	include/linux/mfd/da9150/
 F:	include/sound/da[79]*.h
 F:	sound/soc/codecs/da[79]*.[ch]

--
1.9.3


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

* [PATCH v2 7/7] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list.
@ 2014-08-28 10:49   ` Adam Thomson
  0 siblings, 0 replies; 43+ messages in thread
From: Adam Thomson @ 2014-08-28 10:49 UTC (permalink / raw)
  To: Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
 MAINTAINERS | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index aefa948..6dc0aee 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2883,12 +2883,15 @@ S:	Supported
 F:	Documentation/hwmon/da90??
 F:	drivers/gpio/gpio-da90??.c
 F:	drivers/hwmon/da90??-hwmon.c
+F:	drivers/iio/adc/da91??-*.c
 F:	drivers/input/misc/da90??_onkey.c
 F:	drivers/input/touchscreen/da9052_tsi.c
 F:	drivers/leds/leds-da90??.c
 F:	drivers/mfd/da903x.c
 F:	drivers/mfd/da90??-*.c
+F:	drivers/mfd/da91??-*.c
 F:	drivers/power/da9052-battery.c
+F:	drivers/power/da91??-*.c
 F:	drivers/regulator/da903x.c
 F:	drivers/regulator/da9???-regulator.[ch]
 F:	drivers/rtc/rtc-da90??.c
@@ -2898,6 +2901,7 @@ F:	include/linux/mfd/da903x.h
 F:	include/linux/mfd/da9052/
 F:	include/linux/mfd/da9055/
 F:	include/linux/mfd/da9063/
+F:	include/linux/mfd/da9150/
 F:	include/sound/da[79]*.h
 F:	sound/soc/codecs/da[79]*.[ch]

--
1.9.3

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

* Re: [PATCH v2 7/7] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list.
@ 2014-08-28 11:17     ` Lee Jones
  0 siblings, 0 replies; 43+ messages in thread
From: Lee Jones @ 2014-08-28 11:17 UTC (permalink / raw)
  To: Adam Thomson
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, support.opensource

On Thu, 28 Aug 2014, Adam Thomson wrote:

> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> ---
>  MAINTAINERS | 4 ++++
>  1 file changed, 4 insertions(+)

Acked-by: Lee Jones <lee.jones@linaro.org>

> diff --git a/MAINTAINERS b/MAINTAINERS
> index aefa948..6dc0aee 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2883,12 +2883,15 @@ S:	Supported
>  F:	Documentation/hwmon/da90??
>  F:	drivers/gpio/gpio-da90??.c
>  F:	drivers/hwmon/da90??-hwmon.c
> +F:	drivers/iio/adc/da91??-*.c
>  F:	drivers/input/misc/da90??_onkey.c
>  F:	drivers/input/touchscreen/da9052_tsi.c
>  F:	drivers/leds/leds-da90??.c
>  F:	drivers/mfd/da903x.c
>  F:	drivers/mfd/da90??-*.c
> +F:	drivers/mfd/da91??-*.c
>  F:	drivers/power/da9052-battery.c
> +F:	drivers/power/da91??-*.c
>  F:	drivers/regulator/da903x.c
>  F:	drivers/regulator/da9???-regulator.[ch]
>  F:	drivers/rtc/rtc-da90??.c
> @@ -2898,6 +2901,7 @@ F:	include/linux/mfd/da903x.h
>  F:	include/linux/mfd/da9052/
>  F:	include/linux/mfd/da9055/
>  F:	include/linux/mfd/da9063/
> +F:	include/linux/mfd/da9150/
>  F:	include/sound/da[79]*.h
>  F:	sound/soc/codecs/da[79]*.[ch]
> 

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

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

* Re: [PATCH v2 7/7] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list.
@ 2014-08-28 11:17     ` Lee Jones
  0 siblings, 0 replies; 43+ messages in thread
From: Lee Jones @ 2014-08-28 11:17 UTC (permalink / raw)
  To: Adam Thomson
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Joe Perches,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	support.opensource-WBD+wuPFNBhBDgjK7y7TUQ

On Thu, 28 Aug 2014, Adam Thomson wrote:

> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
> ---
>  MAINTAINERS | 4 ++++
>  1 file changed, 4 insertions(+)

Acked-by: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

> diff --git a/MAINTAINERS b/MAINTAINERS
> index aefa948..6dc0aee 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2883,12 +2883,15 @@ S:	Supported
>  F:	Documentation/hwmon/da90??
>  F:	drivers/gpio/gpio-da90??.c
>  F:	drivers/hwmon/da90??-hwmon.c
> +F:	drivers/iio/adc/da91??-*.c
>  F:	drivers/input/misc/da90??_onkey.c
>  F:	drivers/input/touchscreen/da9052_tsi.c
>  F:	drivers/leds/leds-da90??.c
>  F:	drivers/mfd/da903x.c
>  F:	drivers/mfd/da90??-*.c
> +F:	drivers/mfd/da91??-*.c
>  F:	drivers/power/da9052-battery.c
> +F:	drivers/power/da91??-*.c
>  F:	drivers/regulator/da903x.c
>  F:	drivers/regulator/da9???-regulator.[ch]
>  F:	drivers/rtc/rtc-da90??.c
> @@ -2898,6 +2901,7 @@ F:	include/linux/mfd/da903x.h
>  F:	include/linux/mfd/da9052/
>  F:	include/linux/mfd/da9055/
>  F:	include/linux/mfd/da9063/
> +F:	include/linux/mfd/da9150/
>  F:	include/sound/da[79]*.h
>  F:	sound/soc/codecs/da[79]*.[ch]
> 

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

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

* Re: [PATCH v2 3/7] iio: Add support for DA9150 GPADC
  2014-08-28 10:48   ` Adam Thomson
  (?)
@ 2014-08-28 11:28   ` Peter Meerwald
  2014-08-30 20:01     ` Jonathan Cameron
  2014-09-09 10:51     ` Opensource [Adam Thomson]
  -1 siblings, 2 replies; 43+ messages in thread
From: Peter Meerwald @ 2014-08-28 11:28 UTC (permalink / raw)
  To: Adam Thomson; +Cc: Lee Jones, Jonathan Cameron, linux-iio, support.opensource


some minor comments inline

> This patch adds support for DA9150 Charger & Fuel-Gauge IC GPADC.
> 
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> ---
>  drivers/iio/adc/Kconfig        |   9 +
>  drivers/iio/adc/Makefile       |   1 +
>  drivers/iio/adc/da9150-gpadc.c | 430 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 440 insertions(+)
>  create mode 100644 drivers/iio/adc/da9150-gpadc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 11b048a..8041347 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -127,6 +127,15 @@ config AT91_ADC
>  	help
>  	  Say yes here to build support for Atmel AT91 ADC.
> 
> +config DA9150_GPADC
> +	tristate "Dialog DA9150 GPADC driver support"
> +	depends on MFD_DA9150
> +	help
> +	  Say yes here to build support for Dialog DA9150 GPADC.
> +
> +	  This driver can also be built as a module. If chosen, the module name
> +	  will be da9150-gpadc.
> +
>  config EXYNOS_ADC
>  	tristate "Exynos ADC driver support"
>  	depends on ARCH_EXYNOS || (OF && COMPILE_TEST)
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index ad81b51..48413d2 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
>  obj-$(CONFIG_AD7887) += ad7887.o
>  obj-$(CONFIG_AD799X) += ad799x.o
>  obj-$(CONFIG_AT91_ADC) += at91_adc.o
> +obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
>  obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
>  obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>  obj-$(CONFIG_MAX1027) += max1027.o
> diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
> new file mode 100644
> index 0000000..21a21a9
> --- /dev/null
> +++ b/drivers/iio/adc/da9150-gpadc.c
> @@ -0,0 +1,430 @@
> +/*
> + * DA9150 GPADC Driver
> + *
> + * Copyright (c) 2014 Dialog Semiconductor
> + *
> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +
> +#include <linux/mfd/da9150/core.h>
> +#include <linux/mfd/da9150/pdata.h>
> +#include <linux/mfd/da9150/registers.h>
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/machine.h>
> +#include <linux/iio/driver.h>
> +
> +
> +/* Channels */
> +enum da9150_gpadc_hw_channel {
> +	DA9150_GPADC_HW_CHAN_GPIOA_2V = 0,
> +	DA9150_GPADC_HW_CHAN_GPIOA_2V_,

why the underscore_ notation? 
couldn't you use e.g. DA9150_GPADC_HW_CHAN_GPIOB_2V = 2?

> +	DA9150_GPADC_HW_CHAN_GPIOB_2V,
> +	DA9150_GPADC_HW_CHAN_GPIOB_2V_,
> +	DA9150_GPADC_HW_CHAN_GPIOC_2V,
> +	DA9150_GPADC_HW_CHAN_GPIOC_2V_,
> +	DA9150_GPADC_HW_CHAN_GPIOD_2V,
> +	DA9150_GPADC_HW_CHAN_GPIOD_2V_,
> +	DA9150_GPADC_HW_CHAN_IBUS_SENSE,
> +	DA9150_GPADC_HW_CHAN_IBUS_SENSE_,
> +	DA9150_GPADC_HW_CHAN_VBUS_DIV,
> +	DA9150_GPADC_HW_CHAN_VBUS_DIV_,
> +	DA9150_GPADC_HW_CHAN_ID,
> +	DA9150_GPADC_HW_CHAN_ID_,
> +	DA9150_GPADC_HW_CHAN_VSYS,
> +	DA9150_GPADC_HW_CHAN_VSYS_,
> +	DA9150_GPADC_HW_CHAN_GPIOA_5V,
> +	DA9150_GPADC_HW_CHAN_GPIOA_5V_,
> +	DA9150_GPADC_HW_CHAN_GPIOB_5V,
> +	DA9150_GPADC_HW_CHAN_GPIOB_5V_,
> +	DA9150_GPADC_HW_CHAN_GPIOC_5V,
> +	DA9150_GPADC_HW_CHAN_GPIOC_5V_,
> +	DA9150_GPADC_HW_CHAN_GPIOD_5V,
> +	DA9150_GPADC_HW_CHAN_GPIOD_5V_,
> +	DA9150_GPADC_HW_CHAN_VBAT,
> +	DA9150_GPADC_HW_CHAN_VBAT_,
> +	DA9150_GPADC_HW_CHAN_TBAT,
> +	DA9150_GPADC_HW_CHAN_TBAT_,
> +	DA9150_GPADC_HW_CHAN_TJUNC_CORE,
> +	DA9150_GPADC_HW_CHAN_TJUNC_CORE_,
> +	DA9150_GPADC_HW_CHAN_TJUNC_OVP,
> +	DA9150_GPADC_HW_CHAN_TJUNC_OVP_,
> +};
> +
> +enum da9150_gpadc_channel {
> +	DA9150_GPADC_CHAN_GPIOA = 0,
> +	DA9150_GPADC_CHAN_GPIOB,
> +	DA9150_GPADC_CHAN_GPIOC,
> +	DA9150_GPADC_CHAN_GPIOD,
> +	DA9150_GPADC_CHAN_IBUS,
> +	DA9150_GPADC_CHAN_VBUS,
> +	DA9150_GPADC_CHAN_ID,
> +	DA9150_GPADC_CHAN_VSYS,
> +	DA9150_GPADC_CHAN_VBAT,
> +	DA9150_GPADC_CHAN_TBAT,
> +	DA9150_GPADC_CHAN_TJUNC_CORE,
> +	DA9150_GPADC_CHAN_TJUNC_OVP,
> +};
> +
> +/* Private data */
> +struct da9150_gpadc {
> +	struct da9150 *da9150;
> +	struct device *dev;
> +
> +	struct mutex lock;
> +	struct completion complete;
> +};
> +
> +
> +static irqreturn_t da9150_gpadc_irq(int irq, void *data)
> +{
> +
> +	struct da9150_gpadc *gpadc = data;
> +
> +	complete(&gpadc->complete);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +int da9150_gpadc_read_adc(struct da9150_gpadc *gpadc, int hw_chan)

static?

> +{
> +	u8 result_regs[2];
> +	int result;
> +
> +	mutex_lock(&gpadc->lock);
> +
> +	/* Set channel & enable measurement */
> +	da9150_reg_write(gpadc->da9150, DA9150_GPADC_MAN,
> +			 (DA9150_GPADC_EN_MASK |
> +			  hw_chan << DA9150_GPADC_MUX_SHIFT));
> +
> +	/* Consume left-over completion from a previous timeout */
> +	try_wait_for_completion(&gpadc->complete);
> +
> +	/* Check for actual completion */
> +	wait_for_completion_timeout(&gpadc->complete, msecs_to_jiffies(5));
> +
> +	/* Read result and status from device */
> +	da9150_bulk_read(gpadc->da9150, DA9150_GPADC_RES_A, 2, result_regs);
> +
> +	mutex_unlock(&gpadc->lock);
> +
> +	/* Check to make sure device really has completed reading */
> +	if (result_regs[1] & DA9150_GPADC_RUN_MASK) {
> +		dev_err(gpadc->dev, "Timeout on channel %d of GP-ADC\n",

GPADC everywhere else

> +			hw_chan);
> +		return -ETIMEDOUT;
> +	}
> +
> +	/* LSBs - 2 bits */
> +	result = (result_regs[1] & DA9150_GPADC_RES_L_MASK) >>
> +		 DA9150_GPADC_RES_L_SHIFT;
> +	/* MSBs - 8 bits */
> +	result |= result_regs[0] << DA9150_GPADC_RES_L_BITS;

can't the read be done with a 16bit read?

> +
> +	return result;
> +}
> +
> +static inline int da9150_gpadc_gpio_5v_voltage_now(int raw_val)
> +{
> +	/* Convert to uV */
> +	return (((6 * ((raw_val * 1000) + 500)) / 1024) * 1000);

outer parenthesis not needed, here and below

> +}
> +
> +static inline int da9150_gpadc_ibus_current_avg(int raw_val)
> +{
> +	/* Convert to uA */
> +	return (((4 * ((raw_val * 1000) + 500)) / 2048) * 1000);
> +}
> +
> +static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
> +{
> +	/* Convert to uV */
> +	return (((21 * ((raw_val * 1000) + 500)) / 1024) * 1000);
> +}
> +
> +static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
> +{
> +	/* Convert to uV */
> +	return (((3 * ((raw_val * 1000) + 500)) / 512) * 1000);
> +}
> +
> +static inline int da9150_gpadc_tjunc_temp(int raw_val)
> +{
> +	/* Convert to 0.1 degrees C */

IIO wants mille degrees C

> +	return (((879 - (1023 - raw_val)) * 10000) / 4420);
> +}
> +
> +static inline int da9150_gpadc_vbat_voltage_now(int raw_val)
> +{
> +	/* Convert to uV */
> +	return ((2932 * raw_val) + 1500000);
> +}
> +
> +int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
> +				int hw_chan)

static?

> +{
> +	int raw_val, ret;
> +
> +	raw_val = da9150_gpadc_read_adc(gpadc, hw_chan);
> +	if (raw_val < 0)
> +		return raw_val;
> +
> +	switch (channel) {
> +	case DA9150_GPADC_CHAN_GPIOA:
> +	case DA9150_GPADC_CHAN_GPIOB:
> +	case DA9150_GPADC_CHAN_GPIOC:
> +	case DA9150_GPADC_CHAN_GPIOD:
> +		ret = da9150_gpadc_gpio_5v_voltage_now(raw_val);

could return directly ...

> +		break;
> +	case DA9150_GPADC_CHAN_IBUS:
> +		ret = da9150_gpadc_ibus_current_avg(raw_val);
> +		break;
> +	case DA9150_GPADC_CHAN_VBUS:
> +		ret = da9150_gpadc_vbus_21v_voltage_now(raw_val);
> +		break;
> +	case DA9150_GPADC_CHAN_VSYS:
> +		ret = da9150_gpadc_vsys_6v_voltage_now(raw_val);
> +		break;
> +	case DA9150_GPADC_CHAN_TJUNC_CORE:
> +	case DA9150_GPADC_CHAN_TJUNC_OVP:
> +		ret = da9150_gpadc_tjunc_temp(raw_val);
> +		break;
> +	default:
> +		/* No processing for other channels so return raw value */
> +		ret = raw_val;
> +		break;
> +	}

and save the final return
> +
> +	return ret;
> +}
> +
> +int da9150_gpadc_read_scale(int channel)

static?

> +{
> +	int ret;
> +
> +	switch (channel) {
> +	case DA9150_GPADC_CHAN_VBAT:
> +		ret = 2932;

return directly?

> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +int da9150_gpadc_read_offset(int channel)
> +{
> +	int ret;
> +
> +	switch (channel) {
> +	case DA9150_GPADC_CHAN_VBAT:
> +		ret = 1500000 / 2932;

return directly?

> +		break;
> +	default:
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +int da9150_gpadc_read_raw(struct iio_dev *indio_dev,
> +			  struct iio_chan_spec const *chan,
> +			  int *val, int *val2, long mask)

static?

> +{
> +	struct da9150_gpadc *gpadc = iio_priv(indio_dev);
> +	int ret;
> +
> +	if ((chan->channel < DA9150_GPADC_CHAN_GPIOA) ||
> +	    (chan->channel > DA9150_GPADC_CHAN_TJUNC_OVP))
> +		return -EINVAL;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +	case IIO_CHAN_INFO_PROCESSED:
> +		ret = da9150_gpadc_read_processed(gpadc, chan->channel,
> +						  chan->address);
> +		break;
> +	case IIO_CHAN_INFO_SCALE:
> +		ret = da9150_gpadc_read_scale(chan->channel);
> +		break;
> +	case IIO_CHAN_INFO_OFFSET:
> +		ret = da9150_gpadc_read_offset(chan->channel);
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	*val = ret;
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static const struct iio_info da9150_gpadc_info = {
> +	.read_raw = &da9150_gpadc_read_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +#define GPADC_CHANNEL(_id, _hw_id, _type, chan_info, _ext_name) {	\
> +	.type = _type,							\
> +	.indexed = 1,							\

there is only one current channel, it should not be indexed

> +	.channel = DA9150_GPADC_CHAN_##_id,				\
> +	.address = DA9150_GPADC_HW_CHAN_##_hw_id,			\
> +	.info_mask_separate = chan_info,				\
> +	.extend_name = _ext_name,					\
> +	.datasheet_name = #_id,						\
> +}
> +
> +#define GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name)	\
> +	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_RAW), _ext_name)
> +
> +#define GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name)	\
> +	GPADC_CHANNEL(_id, _hw_id, _type,			\
> +		      BIT(IIO_CHAN_INFO_RAW) |			\
> +		      BIT(IIO_CHAN_INFO_SCALE) |		\
> +		      BIT(IIO_CHAN_INFO_OFFSET),		\
> +		      _ext_name)
> +
> +#define GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name)		\
> +	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_PROCESSED),	\
> +		      _ext_name)
> +
> +/* Supported channels */
> +static const struct iio_chan_spec da9150_gpadc_channels[] = {
> +	GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_5V, IIO_VOLTAGE, "GPIOA"),
> +	GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_5V, IIO_VOLTAGE, "GPIOB"),
> +	GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_5V, IIO_VOLTAGE, "GPIOC"),
> +	GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_5V, IIO_VOLTAGE, "GPIOD"),
> +	GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
> +	GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
> +	GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
> +	GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
> +	GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
> +	GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
> +	GPADC_CHANNEL_PROCESSED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP, "TJUNC_CORE"),
> +	GPADC_CHANNEL_PROCESSED(TJUNC_OVP, TJUNC_OVP, IIO_TEMP, "TJUNC_OVP"),
> +};
> +
> +/* Default maps used by da9150-charger */
> +static struct iio_map da9150_gpadc_default_maps[] = {
> +	{
> +		.consumer_dev_name = "da9150-charger",
> +		.consumer_channel = "CHAN_IBUS",
> +		.adc_channel_label = "IBUS",
> +	},
> +	{
> +		.consumer_dev_name = "da9150-charger",
> +		.consumer_channel = "CHAN_VBUS",
> +		.adc_channel_label = "VBUS",
> +	},
> +	{
> +		.consumer_dev_name = "da9150-charger",
> +		.consumer_channel = "CHAN_TJUNC",
> +		.adc_channel_label = "TJUNC_CORE",
> +	},
> +	{
> +		.consumer_dev_name = "da9150-charger",
> +		.consumer_channel = "CHAN_VBAT",
> +		.adc_channel_label = "VBAT",
> +	},
> +	{},
> +};
> +
> +static int da9150_gpadc_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct da9150 *da9150 = dev_get_drvdata(dev->parent);
> +	struct da9150_gpadc *gpadc;
> +	struct iio_dev *indio_dev;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev,
> +					  sizeof(struct da9150_gpadc));
> +	if (!indio_dev) {
> +		dev_err(&pdev->dev, "Failed to allocate IIO device\n");
> +		return -ENOMEM;
> +	}
> +	gpadc = iio_priv(indio_dev);
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +	gpadc->da9150 = da9150;
> +	gpadc->dev = dev;
> +
> +	ret = iio_map_array_register(indio_dev, da9150_gpadc_default_maps);
> +	if (ret) {
> +		dev_err(dev, "Failed to register IIO maps: %d\n", ret);
> +		goto iio_map_fail;

just return here?

> +	}
> +
> +	mutex_init(&gpadc->lock);
> +	init_completion(&gpadc->complete);
> +
> +	/* Register IRQ */
> +	ret = da9150_register_irq(pdev, gpadc, da9150_gpadc_irq, "GPADC");
> +	if (ret < 0)
> +		goto irq_fail;
> +
> +	indio_dev->name = dev_name(dev);
> +	indio_dev->dev.parent = dev;
> +	indio_dev->dev.of_node = pdev->dev.of_node;
> +	indio_dev->info = &da9150_gpadc_info;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->channels = da9150_gpadc_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels);
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret) {
> +		dev_err(dev, "Failed to register IIO device: %d\n", ret);
> +		goto iio_dev_fail;
> +	}
> +
> +	return ret;
> +
> +iio_dev_fail:
> +irq_fail:

why two labels?

> +	iio_map_array_unregister(indio_dev);
> +
> +iio_map_fail:
> +	return ret;
> +}
> +
> +static int da9150_gpadc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +
> +	iio_map_array_unregister(indio_dev);

unregister irq?

> +	iio_device_unregister(indio_dev);
> +
> +	return 0;
> +}
> +
> +static struct platform_driver da9150_gpadc_driver = {
> +	.driver = {
> +		.name = "da9150-gpadc",
> +		.owner = THIS_MODULE,
> +	},
> +	.probe = da9150_gpadc_probe,
> +	.remove = da9150_gpadc_remove,
> +};
> +
> +module_platform_driver(da9150_gpadc_driver);
> +
> +MODULE_DESCRIPTION("GPADC Driver for DA9150");
> +MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
> +MODULE_LICENSE("GPL");
> --
> 1.9.3
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

-- 

Peter Meerwald
+43-664-2444418 (mobile)

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

* Re: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-08-28 10:48   ` Adam Thomson
  (?)
@ 2014-08-28 11:47   ` Varka Bhadram
  2014-09-09 10:32       ` Opensource [Adam Thomson]
  -1 siblings, 1 reply; 43+ messages in thread
From: Varka Bhadram @ 2014-08-28 11:47 UTC (permalink / raw)
  To: Adam Thomson, Lee Jones, Samuel Ortiz, Jonathan Cameron,
	linux-iio, Sebastian Reichel, Dmitry Eremin-Solenikov,
	David Woodhouse, linux-pm, Rob Herring, Pawel Moll, Mark Rutland,
	Ian Campbell, Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, support.opensource

On 08/28/2014 04:18 PM, Adam Thomson wrote:

(...)

> +static int da9150_probe(struct i2c_client *client,
> +			const struct i2c_device_id *id)
> +{
> +	struct da9150 *da9150;
> +	int ret;
> +
> +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> +	if (da9150 == NULL)
> +		return -ENOMEM;

da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
if (!da9150)
	return -ENOMEM;

> +	da9150->dev = &client->dev;
> +	da9150->irq = client->irq;
> +	i2c_set_clientdata(client, da9150);
> +	dev_set_drvdata(da9150->dev, da9150);
> +
> +	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
> +	if (IS_ERR(da9150->regmap)) {
> +		ret = PTR_ERR(da9150->regmap);
> +		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	return da9150_device_init(da9150);
> +}
> +
> +static int da9150_remove(struct i2c_client *client)
> +{
> +	struct da9150 *da9150 = i2c_get_clientdata(client);
> +
> +	da9150_device_exit(da9150);
> +
> +	return 0;
> +}
> +
> +static void da9150_shutdown(struct i2c_client *client)
> +{
> +	struct da9150 *da9150 = i2c_get_clientdata(client);
> +
> +	da9150_device_shutdown(da9150);
> +}
> +
> +static const struct i2c_device_id da9150_i2c_id[] = {
> +	{ "da9150", 0 },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
> +
> +static const struct of_device_id da9150_of_match[] = {
> +	{ .compatible = "dlg,da9150", },
> +	{ }
> +};
> +

missed MODULE_DEVICE_TABLE(of, ...)   ?

> +static struct i2c_driver da9150_driver = {
> +	.driver	= {
> +		.name	= "da9150",
> +		.owner	= THIS_MODULE,

No need to update this field...

> +		.of_match_table = of_match_ptr(da9150_of_match),
> +	},
> +	.probe		= da9150_probe,
> +	.remove		= da9150_remove,
> +	.shutdown	= da9150_shutdown,
> +	.id_table	= da9150_i2c_id,
> +};
> +
> +module_i2c_driver(da9150_driver);
> +
> +MODULE_DESCRIPTION("I2C Driver for DA9150");
> +MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
> +MODULE_LICENSE("GPL");
>
-- 
Regards,
Varka Bhadram.


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

* Re: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-08-28 10:48   ` Adam Thomson
  (?)
  (?)
@ 2014-08-28 16:36   ` Lee Jones
  2014-09-09 10:37       ` Opensource [Adam Thomson]
  -1 siblings, 1 reply; 43+ messages in thread
From: Lee Jones @ 2014-08-28 16:36 UTC (permalink / raw)
  To: Adam Thomson
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, support.opensource

On Thu, 28 Aug 2014, Adam Thomson wrote:

> DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> GPIO and GPADC functionality.
> 
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> ---
>  drivers/mfd/Kconfig                  |   12 +
>  drivers/mfd/Makefile                 |    2 +
>  drivers/mfd/da9150-core.c            |  332 ++++++++++
>  drivers/mfd/da9150-i2c.c             |  176 ++++++

Do you also have another, say SPI version?

>  include/linux/mfd/da9150/core.h      |   80 +++
>  include/linux/mfd/da9150/pdata.h     |   21 +
>  include/linux/mfd/da9150/registers.h | 1153 ++++++++++++++++++++++++++++++++++
>  7 files changed, 1776 insertions(+)
>  create mode 100644 drivers/mfd/da9150-core.c
>  create mode 100644 drivers/mfd/da9150-i2c.c
>  create mode 100644 include/linux/mfd/da9150/core.h
>  create mode 100644 include/linux/mfd/da9150/pdata.h
>  create mode 100644 include/linux/mfd/da9150/registers.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index de5abf2..76adb2c 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -183,6 +183,18 @@ config MFD_DA9063
>  	  Additional drivers must be enabled in order to use the functionality
>  	  of the device.
> 
> +config MFD_DA9150
> +	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"

Why can't this be built as a module?

> +	depends on I2C=y
> +	select MFD_CORE
> +	select REGMAP_I2C
> +	select REGMAP_IRQ
> +	help
> +	  This adds support for the DA9150 integrated charger and fuel-gauge
> +	  chip. This driver provides common support for accessing the device.
> +	  Additional drivers must be enabled in order to use the specific
> +	  features of the device.
> +
>  config MFD_MC13XXX
>  	tristate
>  	depends on (SPI_MASTER || I2C)
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index f001487..098dfa1 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
>  da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
>  obj-$(CONFIG_MFD_DA9063)	+= da9063.o
> 
> +obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
> +

Do the other drivers smell?  Please butt up against them.

I'm not entirely sure why there are so many '\n's in the Makefile!

>  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
>  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
>  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
> new file mode 100644
> index 0000000..029a30b
> --- /dev/null
> +++ b/drivers/mfd/da9150-core.c
> @@ -0,0 +1,332 @@
> +/*
> + * DA9150 Core MFD Driver
> + *
> + * Copyright (c) 2014 Dialog Semiconductor
> + *
> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/core.h>
> +

No real need for this '\n'.

> +#include <linux/mfd/da9150/core.h>
> +#include <linux/mfd/da9150/registers.h>
> +#include <linux/mfd/da9150/pdata.h>
> +
> +u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
> +{
> +	int val, ret;
> +
> +	ret = regmap_read(da9150->regmap, reg, &val);
> +	if (ret < 0)

What if ret > 0?  Is that a good thing? :)

Just 'if (ret)'.

> +		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
> +			reg, ret);
> +
> +	return (u8) val;
> +}
> +EXPORT_SYMBOL_GPL(da9150_reg_read);

Not sure I like this abstraction stuff.  I could understand if there
were locking involved, but there isn't.  You don't appear to check for
errors in the subordinate drivers either, rather you just plough on
ahead.  Not sure that's a good idea either.

Anyone have a second opinion?

> +int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
> +{
> +	int ret;
> +
> +	ret = regmap_write(da9150->regmap, reg, val);
> +	if (ret < 0)
> +		dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
> +			reg, ret);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(da9150_reg_write);

Blah.

> +int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
> +{
> +	int ret;
> +
> +	ret = regmap_update_bits(da9150->regmap, reg, mask, val);
> +	if (ret < 0)
> +		dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
> +			reg, ret);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(da9150_set_bits);

Blah.

> +int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
> +{
> +	int ret;
> +
> +	ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
> +	if (ret < 0)
> +		dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
> +			reg, ret);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(da9150_bulk_read);

Blah.

> +int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
> +{
> +	int ret;
> +
> +	ret = regmap_raw_write(da9150->regmap, reg, buf, count);
> +	if (ret < 0)
> +		dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
> +			reg, ret);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(da9150_bulk_write);

Blah.

> +static struct regmap_irq da9150_irqs[] = {
> +	[DA9150_IRQ_VBUS] = {
> +		.reg_offset = 0,
> +		.mask = DA9150_E_VBUS_MASK,
> +	},
> +	[DA9150_IRQ_CHG] = {
> +		.reg_offset = 0,
> +		.mask = DA9150_E_CHG_MASK,
> +	},
> +	[DA9150_IRQ_TCLASS] = {
> +		.reg_offset = 0,
> +		.mask = DA9150_E_TCLASS_MASK,
> +	},
> +	[DA9150_IRQ_TJUNC] = {
> +		.reg_offset = 0,
> +		.mask = DA9150_E_TJUNC_MASK,
> +	},
> +	[DA9150_IRQ_VFAULT] = {
> +		.reg_offset = 0,
> +		.mask = DA9150_E_VFAULT_MASK,
> +	},
> +	[DA9150_IRQ_CONF] = {
> +		.reg_offset = 1,
> +		.mask = DA9150_E_CONF_MASK,
> +	},
> +	[DA9150_IRQ_DAT] = {
> +		.reg_offset = 1,
> +		.mask = DA9150_E_DAT_MASK,
> +	},
> +	[DA9150_IRQ_DTYPE] = {
> +		.reg_offset = 1,
> +		.mask = DA9150_E_DTYPE_MASK,
> +	},
> +	[DA9150_IRQ_ID] = {
> +		.reg_offset = 1,
> +		.mask = DA9150_E_ID_MASK,
> +	},
> +	[DA9150_IRQ_ADP] = {
> +		.reg_offset = 1,
> +		.mask = DA9150_E_ADP_MASK,
> +	},
> +	[DA9150_IRQ_SESS_END] = {
> +		.reg_offset = 1,
> +		.mask = DA9150_E_SESS_END_MASK,
> +	},
> +	[DA9150_IRQ_SESS_VLD] = {
> +		.reg_offset = 1,
> +		.mask = DA9150_E_SESS_VLD_MASK,
> +	},
> +	[DA9150_IRQ_FG] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_FG_MASK,
> +	},
> +	[DA9150_IRQ_GP] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_GP_MASK,
> +	},
> +	[DA9150_IRQ_TBAT] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_TBAT_MASK,
> +	},
> +	[DA9150_IRQ_GPIOA] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_GPIOA_MASK,
> +	},
> +	[DA9150_IRQ_GPIOB] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_GPIOB_MASK,
> +	},
> +	[DA9150_IRQ_GPIOC] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_GPIOC_MASK,
> +	},
> +	[DA9150_IRQ_GPIOD] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_GPIOD_MASK,
> +	},
> +	[DA9150_IRQ_GPADC] = {
> +		.reg_offset = 2,
> +		.mask = DA9150_E_GPADC_MASK,
> +	},
> +	[DA9150_IRQ_WKUP] = {
> +		.reg_offset = 3,
> +		.mask = DA9150_E_WKUP_MASK,
> +	},
> +};
> +
> +static struct regmap_irq_chip da9150_regmap_irq_chip = {
> +	.name = "da9150_irq",
> +	.status_base = DA9150_EVENT_E,
> +	.mask_base = DA9150_IRQ_MASK_E,
> +	.ack_base = DA9150_EVENT_E,
> +	.num_regs = DA9150_NUM_IRQ_REGS,
> +	.irqs = da9150_irqs,
> +	.num_irqs = ARRAY_SIZE(da9150_irqs),
> +};
> +
> +/* Helper functions for sub-devices to request/free IRQs */
> +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> +			irq_handler_t handler, const char *name)
> +{
> +	int irq, ret;
> +
> +	irq = platform_get_irq_byname(pdev, name);
> +	if (irq < 0)
> +		return irq;
> +
> +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> +					IRQF_ONESHOT, name, dev_id);
> +	if (ret)
> +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(da9150_register_irq);

Why do they need help?  What problem does adding these layers solve?

> +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> +		       const char *name)
> +{
> +	int irq;
> +
> +	irq = platform_get_irq_byname(pdev, name);
> +	if (irq < 0)
> +		return;
> +
> +	devm_free_irq(&pdev->dev, irq, dev_id);
> +}
> +EXPORT_SYMBOL_GPL(da9150_release_irq);

Do you ever release the IRQ and not unbind the driver?

Are there ordering issues at play here?

If not, there's no need to conduct a manual free.

> +static struct resource da9150_gpadc_resources[] = {
> +	{
> +		.name = "GPADC",
> +		.start = DA9150_IRQ_GPADC,
> +		.end = DA9150_IRQ_GPADC,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct resource da9150_charger_resources[] = {
> +	{
> +		.name = "CHG_STATUS",
> +		.start = DA9150_IRQ_CHG,
> +		.end = DA9150_IRQ_CHG,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.name = "CHG_TJUNC",
> +		.start = DA9150_IRQ_TJUNC,
> +		.end = DA9150_IRQ_TJUNC,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.name = "CHG_VFAULT",
> +		.start = DA9150_IRQ_VFAULT,
> +		.end = DA9150_IRQ_VFAULT,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +	{
> +		.name = "CHG_VBUS",
> +		.start = DA9150_IRQ_VBUS,
> +		.end = DA9150_IRQ_VBUS,
> +		.flags = IORESOURCE_IRQ,
> +	},
> +};
> +
> +static struct mfd_cell da9150_devs[] = {
> +	{
> +		.name = "da9150-gpadc",
> +		.of_compatible = "dlg,da9150-gpadc",
> +		.resources = da9150_gpadc_resources,
> +		.num_resources = ARRAY_SIZE(da9150_gpadc_resources),
> +	},
> +	{
> +		.name = "da9150-charger",
> +		.of_compatible = "dlg,da9150-charger",
> +		.resources = da9150_charger_resources,
> +		.num_resources = ARRAY_SIZE(da9150_charger_resources),
> +	},
> +};
> +
> +int da9150_device_init(struct da9150 *da9150)
> +{
> +	struct da9150_pdata *pdata = da9150->dev->platform_data;

dev_get_platdata()

> +	int ret;
> +
> +	/* Handle platform data */

This comment doesn't add anything - the code is clear enough.

> +	if (pdata)
> +		da9150->irq_base = pdata->irq_base;
> +	else
> +		da9150->irq_base = -1;

pdata ? pdata->irq_base : -1;

> +	/* Init IRQs */

No need for these, please only add comments where the code is complex
or convoluted.

> +	ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
> +				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> +				  da9150->irq_base, &da9150_regmap_irq_chip,
> +				  &da9150->regmap_irq_data);
> +	if (ret < 0)

'if (ret)' where positive replies aren't possible or are errors.

> +		goto err_irq;

Just return here and remove 'err_irq' label.

> +	da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
> +
> +	/* Make the IRQ line a wake source */
> +	enable_irq_wake(da9150->irq);
> +
> +	/* Add MFD Devices */
> +	ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
> +			      ARRAY_SIZE(da9150_devs), NULL,
> +			      da9150->irq_base, NULL);
> +	if (ret < 0) {
> +		dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
> +		goto err_mfd;
> +	}
> +
> +	return 0;
> +
> +err_mfd:
> +	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> +err_irq:
> +	return ret;
> +}
> +
> +void da9150_device_exit(struct da9150 *da9150)
> +{
> +	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> +	mfd_remove_devices(da9150->dev);
> +}
> +
> +void da9150_device_shutdown(struct da9150 *da9150)
> +{
> +	/* Make sure we have a wakup source for the device */
> +	da9150_set_bits(da9150, DA9150_CONFIG_D,
> +			DA9150_WKUP_PM_EN_MASK,
> +			DA9150_WKUP_PM_EN_MASK);
> +
> +	/* Set device to DISABLED mode */
> +	da9150_set_bits(da9150, DA9150_CONTROL_C,
> +			DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
> +}
> +
> +MODULE_DESCRIPTION("MFD Core Driver for DA9150");
> +MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/mfd/da9150-i2c.c b/drivers/mfd/da9150-i2c.c
> new file mode 100644
> index 0000000..a02525c
> --- /dev/null
> +++ b/drivers/mfd/da9150-i2c.c
> @@ -0,0 +1,176 @@
> +/*
> + * DA9150 I2C Driver
> + *
> + * Copyright (c) 2014 Dialog Semiconductor
> + *
> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> + *
> + * This program is free software; you can redistribute  it and/or modify it
> + * under  the terms of  the GNU General  Public License as published by the
> + * Free Software Foundation;  either version 2 of the  License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +

Remove this line.

> +#include <linux/mfd/da9150/core.h>
> +#include <linux/mfd/da9150/registers.h>
> +
> +static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
> +{
> +	switch (reg) {
> +	case DA9150_PAGE_CON:
> +	case DA9150_STATUS_A:
> +	case DA9150_STATUS_B:
> +	case DA9150_STATUS_C:
> +	case DA9150_STATUS_D:
> +	case DA9150_STATUS_E:
> +	case DA9150_STATUS_F:
> +	case DA9150_STATUS_G:
> +	case DA9150_STATUS_H:
> +	case DA9150_STATUS_I:
> +	case DA9150_STATUS_J:
> +	case DA9150_STATUS_K:
> +	case DA9150_STATUS_L:
> +	case DA9150_STATUS_N:
> +	case DA9150_FAULT_LOG_A:
> +	case DA9150_FAULT_LOG_B:
> +	case DA9150_EVENT_E:
> +	case DA9150_EVENT_F:
> +	case DA9150_EVENT_G:
> +	case DA9150_EVENT_H:
> +	case DA9150_CONTROL_B:
> +	case DA9150_CONTROL_C:
> +	case DA9150_GPADC_MAN:
> +	case DA9150_GPADC_RES_A:
> +	case DA9150_GPADC_RES_B:
> +	case DA9150_ADETVB_CFG_C:
> +	case DA9150_ADETD_STAT:
> +	case DA9150_ADET_CMPSTAT:
> +	case DA9150_ADET_CTRL_A:
> +	case DA9150_PPR_TCTR_B:
> +	case DA9150_COREBTLD_STAT_A:
> +	case DA9150_CORE_DATA_A:
> +	case DA9150_CORE_DATA_B:
> +	case DA9150_CORE_DATA_C:
> +	case DA9150_CORE_DATA_D:
> +	case DA9150_CORE2WIRE_STAT_A:
> +	case DA9150_FW_CTRL_C:
> +	case DA9150_FG_CTRL_B:
> +	case DA9150_FW_CTRL_B:
> +	case DA9150_GPADC_CMAN:
> +	case DA9150_GPADC_CRES_A:
> +	case DA9150_GPADC_CRES_B:
> +	case DA9150_CC_ICHG_RES_A:
> +	case DA9150_CC_ICHG_RES_B:
> +	case DA9150_CC_IAVG_RES_A:
> +	case DA9150_CC_IAVG_RES_B:
> +	case DA9150_TAUX_CTRL_A:
> +	case DA9150_TAUX_VALUE_H:
> +	case DA9150_TAUX_VALUE_L:
> +	case DA9150_TBAT_RES_A:
> +	case DA9150_TBAT_RES_B:
> +		return true;
> +	default:
> +		return false;
> +	}
> +}
> +
> +static const struct regmap_range_cfg da9150_range_cfg[] = {
> +	{
> +		.range_min = DA9150_PAGE_CON,
> +		.range_max = DA9150_TBAT_RES_B,
> +		.selector_reg = DA9150_PAGE_CON,
> +		.selector_mask = DA9150_I2C_PAGE_MASK,
> +		.selector_shift = DA9150_I2C_PAGE_SHIFT,
> +		.window_start = 0,
> +		.window_len = 256,
> +	},
> +};
> +
> +static struct regmap_config da9150_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.ranges = da9150_range_cfg,
> +	.num_ranges = ARRAY_SIZE(da9150_range_cfg),
> +	.max_register = DA9150_TBAT_RES_B,
> +
> +	.cache_type = REGCACHE_RBTREE,
> +
> +	.volatile_reg = da9150_volatile_reg,
> +};
> +
> +static int da9150_probe(struct i2c_client *client,
> +			const struct i2c_device_id *id)
> +{
> +	struct da9150 *da9150;
> +	int ret;
> +
> +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);

sizeof(*da9150)

> +	if (da9150 == NULL)

if (!da9150)

> +		return -ENOMEM;

'\n'

> +	da9150->dev = &client->dev;
> +	da9150->irq = client->irq;
> +	i2c_set_clientdata(client, da9150);
> +	dev_set_drvdata(da9150->dev, da9150);

Why do you need this in both locations?

> +	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
> +	if (IS_ERR(da9150->regmap)) {
> +		ret = PTR_ERR(da9150->regmap);
> +		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
> +			ret);
> +		return ret;
> +	}
> +
> +	return da9150_device_init(da9150);
> +}
> +
> +static int da9150_remove(struct i2c_client *client)
> +{
> +	struct da9150 *da9150 = i2c_get_clientdata(client);
> +
> +	da9150_device_exit(da9150);
> +
> +	return 0;
> +}
> +
> +static void da9150_shutdown(struct i2c_client *client)
> +{
> +	struct da9150 *da9150 = i2c_get_clientdata(client);
> +
> +	da9150_device_shutdown(da9150);
> +}
> +
> +static const struct i2c_device_id da9150_i2c_id[] = {
> +	{ "da9150", 0 },

I don't see the .id parameter being used, just leave it blank.

> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
> +
> +static const struct of_device_id da9150_of_match[] = {
> +	{ .compatible = "dlg,da9150", },
> +	{ }
> +};

MODULE_DEVICE_TABLE(of, ...)

> +static struct i2c_driver da9150_driver = {
> +	.driver	= {
> +		.name	= "da9150",
> +		.owner	= THIS_MODULE,

You can remove this line, it's taken care of for you elsewhere.

> +		.of_match_table = of_match_ptr(da9150_of_match),
> +	},
> +	.probe		= da9150_probe,
> +	.remove		= da9150_remove,
> +	.shutdown	= da9150_shutdown,
> +	.id_table	= da9150_i2c_id,
> +};
> +
> +module_i2c_driver(da9150_driver);
> +
> +MODULE_DESCRIPTION("I2C Driver for DA9150");
> +MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/da9150/core.h b/include/linux/mfd/da9150/core.h
> new file mode 100644
> index 0000000..d23c500
> --- /dev/null
> +++ b/include/linux/mfd/da9150/core.h
> @@ -0,0 +1,80 @@
> +/*
> + * DA9150 MFD Driver - Core Data
> + *
> + * Copyright (c) 2014 Dialog Semiconductor
> + *
> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> + */
> +
> +#ifndef __DA9150_CORE_H
> +#define __DA9150_CORE_H
> +
> +#include <linux/device.h>
> +#include <linux/i2c.h>

What's this used for?

> +#include <linux/interrupt.h>
> +#include <linux/regmap.h>
> +#include <linux/mutex.h>
> +
> +/* I2C address paging */
> +#define DA9150_REG_PAGE_SHIFT	8
> +#define DA9150_REG_PAGE_MASK	0xFF
> +
> +/* IRQs */
> +#define DA9150_NUM_IRQ_REGS	4
> +#define DA9150_IRQ_VBUS		0
> +#define DA9150_IRQ_CHG		1
> +#define DA9150_IRQ_TCLASS	2
> +#define DA9150_IRQ_TJUNC	3
> +#define DA9150_IRQ_VFAULT	4
> +#define DA9150_IRQ_CONF		5
> +#define DA9150_IRQ_DAT		6
> +#define DA9150_IRQ_DTYPE	7
> +#define DA9150_IRQ_ID		8
> +#define DA9150_IRQ_ADP		9
> +#define DA9150_IRQ_SESS_END	10
> +#define DA9150_IRQ_SESS_VLD	11
> +#define DA9150_IRQ_FG		12
> +#define DA9150_IRQ_GP		13
> +#define DA9150_IRQ_TBAT		14
> +#define DA9150_IRQ_GPIOA	15
> +#define DA9150_IRQ_GPIOB	16
> +#define DA9150_IRQ_GPIOC	17
> +#define DA9150_IRQ_GPIOD	18
> +#define DA9150_IRQ_GPADC	19
> +#define DA9150_IRQ_WKUP		20
> +
> +struct da9150 {
> +	struct device *dev;
> +
> +	struct regmap *regmap;
> +

Why the '\n's?

> +	struct regmap_irq_chip_data *regmap_irq_data;
> +	int irq;
> +	int irq_base;
> +};
> +
> +/* Device I/O */
> +u8 da9150_reg_read(struct da9150 *da9150, u16 reg);
> +int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val);
> +int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val);
> +
> +int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf);
> +int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf);
> +
> +/* IRQ helper functions */
> +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> +			irq_handler_t handler, const char *name);
> +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> +			const char *name);

I'm not sure why any of these 7 functions are required.

> +/* Init/Exit */
> +int da9150_device_init(struct da9150 *da9150);
> +void da9150_device_exit(struct da9150 *da9150);
> +void da9150_device_shutdown(struct da9150 *da9150);
> +
> +#endif /* __DA9150_CORE_H */
> diff --git a/include/linux/mfd/da9150/pdata.h b/include/linux/mfd/da9150/pdata.h
> new file mode 100644
> index 0000000..e2b37f1
> --- /dev/null
> +++ b/include/linux/mfd/da9150/pdata.h
> @@ -0,0 +1,21 @@
> +/*
> + * DA9150 MFD Driver - Platform Data
> + *
> + * Copyright (c) 2014 Dialog Semiconductor
> + *
> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> + */
> +
> +#ifndef __DA9150_PDATA_H
> +#define __DA9150_PDATA_H
> +
> +struct da9150_pdata {
> +	int irq_base;
> +};

Just put this in core.h and do away witht this header file.

> +#endif /* __DA9150_PDATA_H */
> diff --git a/include/linux/mfd/da9150/registers.h b/include/linux/mfd/da9150/registers.h
> new file mode 100644
> index 0000000..ef4826d
> --- /dev/null
> +++ b/include/linux/mfd/da9150/registers.h
> @@ -0,0 +1,1153 @@
> +/*
> + * DA9150 MFD Driver - Registers
> + *
> + * Copyright (c) 2014 Dialog Semiconductor
> + *
> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> + */
> +
> +#ifndef __DA9150_REGISTERS_H
> +#define __DA9150_REGISTERS_H
> +
> +/* Registers */

[...]

> +/* DA9150_CONTROL_A = 0x0E5 */
> +#define DA9150_VDD33_SL_SHIFT			0
> +#define DA9150_VDD33_SL_MASK			(0x01 << 0)
> +#define DA9150_VDD33_LPM_SHIFT			1
> +#define DA9150_VDD33_LPM_MASK			(0x03 << 1)
> +#define DA9150_VDD33_EN_SHIFT			3
> +#define DA9150_VDD33_EN_MASK			(0x01 << 3)
> +#define DA9150_GPI_LPM_SHIFT			6
> +#define DA9150_GPI_LPM_MASK			(0x01 << 6)
> +#define DA9150_PM_IF_LPM_SHIFT			7
> +#define DA9150_PM_IF_LPM_MASK			(0x01 << 7)
> +
> +/* DA9150_CONTROL_B = 0x0E6 */
> +#define DA9150_LPM_SHIFT			0
> +#define DA9150_LPM_MASK				(0x01 << 0)
> +#define DA9150_RESET_SHIFT			1
> +#define DA9150_RESET_MASK			(0x01 << 1)
> +#define DA9150_RESET_USRCONF_EN_SHIFT		2
> +#define DA9150_RESET_USRCONF_EN_MASK		(0x01 << 2)
> +
> +/* DA9150_CONTROL_C = 0x0E7 */
> +#define DA9150_DISABLE_SHIFT			0
> +#define DA9150_DISABLE_MASK			(0x01 << 0)

Use BIT() for all of these (1 << X) macros.

[...]

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

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

* Re: [PATCH v2 3/7] iio: Add support for DA9150 GPADC
  2014-08-28 11:28   ` Peter Meerwald
@ 2014-08-30 20:01     ` Jonathan Cameron
  2014-09-09 10:53       ` Opensource [Adam Thomson]
  2014-09-09 10:51     ` Opensource [Adam Thomson]
  1 sibling, 1 reply; 43+ messages in thread
From: Jonathan Cameron @ 2014-08-30 20:01 UTC (permalink / raw)
  To: Peter Meerwald, Adam Thomson; +Cc: Lee Jones, linux-iio, support.opensource

On 28/08/14 12:28, Peter Meerwald wrote:
>
> some minor comments inline
A few more from me + make sure all your units match the ABI and in
particular that everything you use is documented in
Documentation/ABI/testing/syfs-bus-iio.  Some stuff that only
exists in staging drivers isn't documented in there as yet
(current measurements for example) so the docs will need additions
alongside this driver.

Thanks,

Jonathan
>
>> This patch adds support for DA9150 Charger & Fuel-Gauge IC GPADC.
>>
>> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
>> ---
>>  drivers/iio/adc/Kconfig        |   9 +
>>  drivers/iio/adc/Makefile       |   1 +
>>  drivers/iio/adc/da9150-gpadc.c | 430 +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 440 insertions(+)
>>  create mode 100644 drivers/iio/adc/da9150-gpadc.c
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 11b048a..8041347 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -127,6 +127,15 @@ config AT91_ADC
>>  	help
>>  	  Say yes here to build support for Atmel AT91 ADC.
>>
>> +config DA9150_GPADC
>> +	tristate "Dialog DA9150 GPADC driver support"
>> +	depends on MFD_DA9150
>> +	help
>> +	  Say yes here to build support for Dialog DA9150 GPADC.
>> +
>> +	  This driver can also be built as a module. If chosen, the module name
>> +	  will be da9150-gpadc.
>> +
>>  config EXYNOS_ADC
>>  	tristate "Exynos ADC driver support"
>>  	depends on ARCH_EXYNOS || (OF && COMPILE_TEST)
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index ad81b51..48413d2 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
>>  obj-$(CONFIG_AD7887) += ad7887.o
>>  obj-$(CONFIG_AD799X) += ad799x.o
>>  obj-$(CONFIG_AT91_ADC) += at91_adc.o
>> +obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
>>  obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
>>  obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>>  obj-$(CONFIG_MAX1027) += max1027.o
>> diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
>> new file mode 100644
>> index 0000000..21a21a9
>> --- /dev/null
>> +++ b/drivers/iio/adc/da9150-gpadc.c
>> @@ -0,0 +1,430 @@
>> +/*
>> + * DA9150 GPADC Driver
>> + *
>> + * Copyright (c) 2014 Dialog Semiconductor
>> + *
>> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
>> + *
>> + * This program is free software; you can redistribute  it and/or modify it
>> + * under  the terms of  the GNU General  Public License as published by the
>> + * Free Software Foundation;  either version 2 of the  License, or (at your
>> + * option) any later version.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/slab.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/interrupt.h>
>> +
>> +#include <linux/mfd/da9150/core.h>
>> +#include <linux/mfd/da9150/pdata.h>
>> +#include <linux/mfd/da9150/registers.h>
>> +
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/machine.h>
>> +#include <linux/iio/driver.h>
>> +
>> +
>> +/* Channels */
>> +enum da9150_gpadc_hw_channel {
>> +	DA9150_GPADC_HW_CHAN_GPIOA_2V = 0,
>> +	DA9150_GPADC_HW_CHAN_GPIOA_2V_,
>
> why the underscore_ notation?
> couldn't you use e.g. DA9150_GPADC_HW_CHAN_GPIOB_2V = 2?
>
>> +	DA9150_GPADC_HW_CHAN_GPIOB_2V,
>> +	DA9150_GPADC_HW_CHAN_GPIOB_2V_,
>> +	DA9150_GPADC_HW_CHAN_GPIOC_2V,
>> +	DA9150_GPADC_HW_CHAN_GPIOC_2V_,
>> +	DA9150_GPADC_HW_CHAN_GPIOD_2V,
>> +	DA9150_GPADC_HW_CHAN_GPIOD_2V_,
>> +	DA9150_GPADC_HW_CHAN_IBUS_SENSE,
>> +	DA9150_GPADC_HW_CHAN_IBUS_SENSE_,
>> +	DA9150_GPADC_HW_CHAN_VBUS_DIV,
>> +	DA9150_GPADC_HW_CHAN_VBUS_DIV_,
>> +	DA9150_GPADC_HW_CHAN_ID,
>> +	DA9150_GPADC_HW_CHAN_ID_,
>> +	DA9150_GPADC_HW_CHAN_VSYS,
>> +	DA9150_GPADC_HW_CHAN_VSYS_,
>> +	DA9150_GPADC_HW_CHAN_GPIOA_5V,
>> +	DA9150_GPADC_HW_CHAN_GPIOA_5V_,
>> +	DA9150_GPADC_HW_CHAN_GPIOB_5V,
>> +	DA9150_GPADC_HW_CHAN_GPIOB_5V_,
>> +	DA9150_GPADC_HW_CHAN_GPIOC_5V,
>> +	DA9150_GPADC_HW_CHAN_GPIOC_5V_,
>> +	DA9150_GPADC_HW_CHAN_GPIOD_5V,
>> +	DA9150_GPADC_HW_CHAN_GPIOD_5V_,
>> +	DA9150_GPADC_HW_CHAN_VBAT,
>> +	DA9150_GPADC_HW_CHAN_VBAT_,
>> +	DA9150_GPADC_HW_CHAN_TBAT,
>> +	DA9150_GPADC_HW_CHAN_TBAT_,
>> +	DA9150_GPADC_HW_CHAN_TJUNC_CORE,
>> +	DA9150_GPADC_HW_CHAN_TJUNC_CORE_,
>> +	DA9150_GPADC_HW_CHAN_TJUNC_OVP,
>> +	DA9150_GPADC_HW_CHAN_TJUNC_OVP_,
>> +};
>> +
>> +enum da9150_gpadc_channel {
>> +	DA9150_GPADC_CHAN_GPIOA = 0,
>> +	DA9150_GPADC_CHAN_GPIOB,
>> +	DA9150_GPADC_CHAN_GPIOC,
>> +	DA9150_GPADC_CHAN_GPIOD,
>> +	DA9150_GPADC_CHAN_IBUS,
>> +	DA9150_GPADC_CHAN_VBUS,
>> +	DA9150_GPADC_CHAN_ID,
>> +	DA9150_GPADC_CHAN_VSYS,
>> +	DA9150_GPADC_CHAN_VBAT,
>> +	DA9150_GPADC_CHAN_TBAT,
>> +	DA9150_GPADC_CHAN_TJUNC_CORE,
>> +	DA9150_GPADC_CHAN_TJUNC_OVP,
>> +};
>> +
>> +/* Private data */
>> +struct da9150_gpadc {
>> +	struct da9150 *da9150;
>> +	struct device *dev;
>> +
>> +	struct mutex lock;
>> +	struct completion complete;
>> +};
>> +
>> +
>> +static irqreturn_t da9150_gpadc_irq(int irq, void *data)
>> +{
>> +
>> +	struct da9150_gpadc *gpadc = data;
>> +
>> +	complete(&gpadc->complete);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +int da9150_gpadc_read_adc(struct da9150_gpadc *gpadc, int hw_chan)
>
> static?
>
>> +{
>> +	u8 result_regs[2];
>> +	int result;
>> +
>> +	mutex_lock(&gpadc->lock);
>> +
>> +	/* Set channel & enable measurement */
>> +	da9150_reg_write(gpadc->da9150, DA9150_GPADC_MAN,
>> +			 (DA9150_GPADC_EN_MASK |
>> +			  hw_chan << DA9150_GPADC_MUX_SHIFT));
>> +
>> +	/* Consume left-over completion from a previous timeout */
>> +	try_wait_for_completion(&gpadc->complete);
>> +
>> +	/* Check for actual completion */
>> +	wait_for_completion_timeout(&gpadc->complete, msecs_to_jiffies(5));
>> +
>> +	/* Read result and status from device */
>> +	da9150_bulk_read(gpadc->da9150, DA9150_GPADC_RES_A, 2, result_regs);
>> +
>> +	mutex_unlock(&gpadc->lock);
>> +
>> +	/* Check to make sure device really has completed reading */
>> +	if (result_regs[1] & DA9150_GPADC_RUN_MASK) {
>> +		dev_err(gpadc->dev, "Timeout on channel %d of GP-ADC\n",
>
> GPADC everywhere else
>
>> +			hw_chan);
>> +		return -ETIMEDOUT;
>> +	}
>> +
>> +	/* LSBs - 2 bits */
>> +	result = (result_regs[1] & DA9150_GPADC_RES_L_MASK) >>
>> +		 DA9150_GPADC_RES_L_SHIFT;
>> +	/* MSBs - 8 bits */
>> +	result |= result_regs[0] << DA9150_GPADC_RES_L_BITS;
>
> can't the read be done with a 16bit read?
>
>> +
>> +	return result;
>> +}
>> +
>> +static inline int da9150_gpadc_gpio_5v_voltage_now(int raw_val)
>> +{
>> +	/* Convert to uV */
>> +	return (((6 * ((raw_val * 1000) + 500)) / 1024) * 1000);
Base units of voltage are millivolts.  See Documentation/ABI/testing/sysfs-bus-iio.
>
> outer parenthesis not needed, here and below
>
>> +}
>> +
>> +static inline int da9150_gpadc_ibus_current_avg(int raw_val)
>> +{
>> +	/* Convert to uA */
>> +	return (((4 * ((raw_val * 1000) + 500)) / 2048) * 1000);
interestingly this is actually our first current channel outside staging.
As such the docs don't cover it.  Please add, keeping inline with the
units used in hwmon. mA, IIRC
>> +}
>> +
>> +static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
>> +{
>> +	/* Convert to uV */
>> +	return (((21 * ((raw_val * 1000) + 500)) / 1024) * 1000);
>> +}
>> +
>> +static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
>> +{
>> +	/* Convert to uV */
>> +	return (((3 * ((raw_val * 1000) + 500)) / 512) * 1000);
>> +}
>> +
>> +static inline int da9150_gpadc_tjunc_temp(int raw_val)
>> +{
>> +	/* Convert to 0.1 degrees C */
>
> IIO wants mille degrees C
Exactly.  Please check all of these correspond to the base units required
by the documentation.  Most of these might be better handled as raw
with scale and offset provided, letting the maths be doing in userspace using
floating point.
>
>> +	return (((879 - (1023 - raw_val)) * 10000) / 4420);
>> +}
>> +
>> +static inline int da9150_gpadc_vbat_voltage_now(int raw_val)
>> +{
>> +	/* Convert to uV */
>> +	return ((2932 * raw_val) + 1500000);
>> +}
>> +
>> +int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
>> +				int hw_chan)
>
> static?
>
>> +{
>> +	int raw_val, ret;
>> +
>> +	raw_val = da9150_gpadc_read_adc(gpadc, hw_chan);
>> +	if (raw_val < 0)
>> +		return raw_val;
>> +
>> +	switch (channel) {
>> +	case DA9150_GPADC_CHAN_GPIOA:
>> +	case DA9150_GPADC_CHAN_GPIOB:
>> +	case DA9150_GPADC_CHAN_GPIOC:
>> +	case DA9150_GPADC_CHAN_GPIOD:
>> +		ret = da9150_gpadc_gpio_5v_voltage_now(raw_val);
>
> could return directly ...
>
>> +		break;
>> +	case DA9150_GPADC_CHAN_IBUS:
>> +		ret = da9150_gpadc_ibus_current_avg(raw_val);
>> +		break;
>> +	case DA9150_GPADC_CHAN_VBUS:
>> +		ret = da9150_gpadc_vbus_21v_voltage_now(raw_val);
>> +		break;
>> +	case DA9150_GPADC_CHAN_VSYS:
>> +		ret = da9150_gpadc_vsys_6v_voltage_now(raw_val);
>> +		break;
>> +	case DA9150_GPADC_CHAN_TJUNC_CORE:
>> +	case DA9150_GPADC_CHAN_TJUNC_OVP:
>> +		ret = da9150_gpadc_tjunc_temp(raw_val);
>> +		break;
>> +	default:
>> +		/* No processing for other channels so return raw value */
>> +		ret = raw_val;
>> +		break;
>> +	}
>
> and save the final return
>> +
>> +	return ret;
>> +}
>> +
>> +int da9150_gpadc_read_scale(int channel)
>
> static?
>
>> +{
>> +	int ret;
>> +
>> +	switch (channel) {
>> +	case DA9150_GPADC_CHAN_VBAT:
>> +		ret = 2932;
>
> return directly?
>
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +int da9150_gpadc_read_offset(int channel)
>> +{
>> +	int ret;
>> +
>> +	switch (channel) {
>> +	case DA9150_GPADC_CHAN_VBAT:
>> +		ret = 1500000 / 2932;
>
> return directly?
>
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +int da9150_gpadc_read_raw(struct iio_dev *indio_dev,
>> +			  struct iio_chan_spec const *chan,
>> +			  int *val, int *val2, long mask)
>
> static?
>
>> +{
>> +	struct da9150_gpadc *gpadc = iio_priv(indio_dev);
>> +	int ret;
>> +
>> +	if ((chan->channel < DA9150_GPADC_CHAN_GPIOA) ||
>> +	    (chan->channel > DA9150_GPADC_CHAN_TJUNC_OVP))
>> +		return -EINVAL;
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_RAW:
>> +	case IIO_CHAN_INFO_PROCESSED:
Would be cleaner to have each of these functions use ret for return code
including IIO_VAL_INT and pass val as an arguement.  Would get rid
of the fiddly handling at the end of this function and allow direct
returns from each of the case statements.

Also, are the base units of all of these channels really giving us
an integer result?  E.g. mV, mA etc? Not impossible, but seems unlikely!

>> +		ret = da9150_gpadc_read_processed(gpadc, chan->channel,
>> +						  chan->address);
>> +		break;
>> +	case IIO_CHAN_INFO_SCALE:
>> +		ret = da9150_gpadc_read_scale(chan->channel);
>> +		break;
>> +	case IIO_CHAN_INFO_OFFSET:
>> +		ret = da9150_gpadc_read_offset(chan->channel);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	*val = ret;
>> +
>> +	return IIO_VAL_INT;
>> +}
>> +
>> +static const struct iio_info da9150_gpadc_info = {
>> +	.read_raw = &da9150_gpadc_read_raw,
>> +	.driver_module = THIS_MODULE,
>> +};
>> +
>> +#define GPADC_CHANNEL(_id, _hw_id, _type, chan_info, _ext_name) {	\
>> +	.type = _type,							\
>> +	.indexed = 1,							\
>
> there is only one current channel, it should not be indexed
Optional. Either way userspace should cope fine. At one point I thought
about insisting everything was indexed, to reduce userspace complexity
(ever so slightly) but was a bit late by the time I thought of it ;)
>
>> +	.channel = DA9150_GPADC_CHAN_##_id,				\
>> +	.address = DA9150_GPADC_HW_CHAN_##_hw_id,			\
>> +	.info_mask_separate = chan_info,				\
>> +	.extend_name = _ext_name,					\
>> +	.datasheet_name = #_id,						\
>> +}
>> +
>> +#define GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name)	\
>> +	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_RAW), _ext_name)
>> +
>> +#define GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name)	\
>> +	GPADC_CHANNEL(_id, _hw_id, _type,			\
>> +		      BIT(IIO_CHAN_INFO_RAW) |			\
>> +		      BIT(IIO_CHAN_INFO_SCALE) |		\
>> +		      BIT(IIO_CHAN_INFO_OFFSET),		\
>> +		      _ext_name)
>> +
>> +#define GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name)		\
>> +	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_PROCESSED),	\
>> +		      _ext_name)
This macro and similar need a DA9150 prefix to avoid likely name clashes in
future.
>> +
>> +/* Supported channels */
>> +static const struct iio_chan_spec da9150_gpadc_channels[] = {
>> +	GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_5V, IIO_VOLTAGE, "GPIOA"),
>> +	GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_5V, IIO_VOLTAGE, "GPIOB"),
>> +	GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_5V, IIO_VOLTAGE, "GPIOC"),
>> +	GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_5V, IIO_VOLTAGE, "GPIOD"),
>> +	GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
>> +	GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
>> +	GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
>> +	GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
>> +	GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
>> +	GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
>> +	GPADC_CHANNEL_PROCESSED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP, "TJUNC_CORE"),
>> +	GPADC_CHANNEL_PROCESSED(TJUNC_OVP, TJUNC_OVP, IIO_TEMP, "TJUNC_OVP"),
>> +};
>> +
>> +/* Default maps used by da9150-charger */
>> +static struct iio_map da9150_gpadc_default_maps[] = {
>> +	{
>> +		.consumer_dev_name = "da9150-charger",
>> +		.consumer_channel = "CHAN_IBUS",
>> +		.adc_channel_label = "IBUS",
>> +	},
>> +	{
>> +		.consumer_dev_name = "da9150-charger",
>> +		.consumer_channel = "CHAN_VBUS",
>> +		.adc_channel_label = "VBUS",
>> +	},
>> +	{
>> +		.consumer_dev_name = "da9150-charger",
>> +		.consumer_channel = "CHAN_TJUNC",
>> +		.adc_channel_label = "TJUNC_CORE",
>> +	},
>> +	{
>> +		.consumer_dev_name = "da9150-charger",
>> +		.consumer_channel = "CHAN_VBAT",
>> +		.adc_channel_label = "VBAT",
>> +	},
>> +	{},
>> +};
>> +
>> +static int da9150_gpadc_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct da9150 *da9150 = dev_get_drvdata(dev->parent);
>> +	struct da9150_gpadc *gpadc;
>> +	struct iio_dev *indio_dev;
>> +	int ret;
>> +
>> +	indio_dev = devm_iio_device_alloc(&pdev->dev,
>> +					  sizeof(struct da9150_gpadc));
>> +	if (!indio_dev) {
>> +		dev_err(&pdev->dev, "Failed to allocate IIO device\n");
>> +		return -ENOMEM;
>> +	}
>> +	gpadc = iio_priv(indio_dev);
>> +
>> +	platform_set_drvdata(pdev, indio_dev);
>> +	gpadc->da9150 = da9150;
>> +	gpadc->dev = dev;
>> +
>> +	ret = iio_map_array_register(indio_dev, da9150_gpadc_default_maps);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to register IIO maps: %d\n", ret);
>> +		goto iio_map_fail;
>
> just return here?
>
>> +	}
>> +
>> +	mutex_init(&gpadc->lock);
>> +	init_completion(&gpadc->complete);
>> +
>> +	/* Register IRQ */
>> +	ret = da9150_register_irq(pdev, gpadc, da9150_gpadc_irq, "GPADC");
This function wants renaming to indicate that it is doing a managed
irq request... devm_da9150 etc would be conventional ;)
>> +	if (ret < 0)
>> +		goto irq_fail;
>> +
>> +	indio_dev->name = dev_name(dev);
>> +	indio_dev->dev.parent = dev;
>> +	indio_dev->dev.of_node = pdev->dev.of_node;
>> +	indio_dev->info = &da9150_gpadc_info;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +	indio_dev->channels = da9150_gpadc_channels;
>> +	indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels);
>> +
>> +	ret = iio_device_register(indio_dev);
>> +	if (ret) {
>> +		dev_err(dev, "Failed to register IIO device: %d\n", ret);
>> +		goto iio_dev_fail;
>> +	}
>> +
>> +	return ret;
>> +
>> +iio_dev_fail:
>> +irq_fail:
>
> why two labels?
>
>> +	iio_map_array_unregister(indio_dev);
>> +
>> +iio_map_fail:
>> +	return ret;
>> +}
>> +
>> +static int da9150_gpadc_remove(struct platform_device *pdev)
>> +{
>> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +
>> +	iio_map_array_unregister(indio_dev);
>
> unregister irq?
Not actually needed as it was a devm register - having said that
the function should indicate that it's naming.
>
>> +	iio_device_unregister(indio_dev);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct platform_driver da9150_gpadc_driver = {
>> +	.driver = {
>> +		.name = "da9150-gpadc",
>> +		.owner = THIS_MODULE,
>> +	},
>> +	.probe = da9150_gpadc_probe,
>> +	.remove = da9150_gpadc_remove,
>> +};
>> +
>> +module_platform_driver(da9150_gpadc_driver);
>> +
>> +MODULE_DESCRIPTION("GPADC Driver for DA9150");
>> +MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com");
>> +MODULE_LICENSE("GPL");
>> --
>> 1.9.3
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
>>
>

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-09 10:32       ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:32 UTC (permalink / raw)
  To: Varka Bhadram, Opensource [Adam Thomson],
	Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, Support Opensource

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2545 bytes --]

On August 28, 2014 12:47, Varka Bhadram wrote:

> On 08/28/2014 04:18 PM, Adam Thomson wrote:
> 
> (...)
> 
> > +static int da9150_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id)
> > +{
> > +	struct da9150 *da9150;
> > +	int ret;
> > +
> > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> > +	if (da9150 == NULL)
> > +		return -ENOMEM;
> 
> da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
> if (!da9150)
> 	return -ENOMEM;

Ok, no real difference, but can change it.

> 
> > +	da9150->dev = &client->dev;
> > +	da9150->irq = client->irq;
> > +	i2c_set_clientdata(client, da9150);
> > +	dev_set_drvdata(da9150->dev, da9150);
> > +
> > +	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
> > +	if (IS_ERR(da9150->regmap)) {
> > +		ret = PTR_ERR(da9150->regmap);
> > +		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
> > +			ret);
> > +		return ret;
> > +	}
> > +
> > +	return da9150_device_init(da9150);
> > +}
> > +
> > +static int da9150_remove(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_exit(da9150);
> > +
> > +	return 0;
> > +}
> > +
> > +static void da9150_shutdown(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_shutdown(da9150);
> > +}
> > +
> > +static const struct i2c_device_id da9150_i2c_id[] = {
> > +	{ "da9150", 0 },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
> > +
> > +static const struct of_device_id da9150_of_match[] = {
> > +	{ .compatible = "dlg,da9150", },
> > +	{ }
> > +};
> > +
> 
> missed MODULE_DEVICE_TABLE(of, ...)   ?

Ok, will add that in.

> 
> > +static struct i2c_driver da9150_driver = {
> > +	.driver	= {
> > +		.name	= "da9150",
> > +		.owner	= THIS_MODULE,
> 
> No need to update this field...

Ok, will remove .owner setting.

> 
> > +		.of_match_table = of_match_ptr(da9150_of_match),
> > +	},
> > +	.probe		= da9150_probe,
> > +	.remove		= da9150_remove,
> > +	.shutdown	= da9150_shutdown,
> > +	.id_table	= da9150_i2c_id,
> > +};
> > +
> > +module_i2c_driver(da9150_driver);
> > +
> > +MODULE_DESCRIPTION("I2C Driver for DA9150");
> > +MODULE_AUTHOR("Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com");
> > +MODULE_LICENSE("GPL");
> >
> --
> Regards,
> Varka Bhadram.

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-09 10:32       ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:32 UTC (permalink / raw)
  To: Varka Bhadram, Opensource [Adam Thomson],
	Lee Jones, Samuel Ortiz, Jonathan Cameron,
	linux-iio-u79uwXL29TY76Z2rM5mHXA, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Joe Perches
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Support Opensource

On August 28, 2014 12:47, Varka Bhadram wrote:

> On 08/28/2014 04:18 PM, Adam Thomson wrote:
> 
> (...)
> 
> > +static int da9150_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id)
> > +{
> > +	struct da9150 *da9150;
> > +	int ret;
> > +
> > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> > +	if (da9150 == NULL)
> > +		return -ENOMEM;
> 
> da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
> if (!da9150)
> 	return -ENOMEM;

Ok, no real difference, but can change it.

> 
> > +	da9150->dev = &client->dev;
> > +	da9150->irq = client->irq;
> > +	i2c_set_clientdata(client, da9150);
> > +	dev_set_drvdata(da9150->dev, da9150);
> > +
> > +	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
> > +	if (IS_ERR(da9150->regmap)) {
> > +		ret = PTR_ERR(da9150->regmap);
> > +		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
> > +			ret);
> > +		return ret;
> > +	}
> > +
> > +	return da9150_device_init(da9150);
> > +}
> > +
> > +static int da9150_remove(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_exit(da9150);
> > +
> > +	return 0;
> > +}
> > +
> > +static void da9150_shutdown(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_shutdown(da9150);
> > +}
> > +
> > +static const struct i2c_device_id da9150_i2c_id[] = {
> > +	{ "da9150", 0 },
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
> > +
> > +static const struct of_device_id da9150_of_match[] = {
> > +	{ .compatible = "dlg,da9150", },
> > +	{ }
> > +};
> > +
> 
> missed MODULE_DEVICE_TABLE(of, ...)   ?

Ok, will add that in.

> 
> > +static struct i2c_driver da9150_driver = {
> > +	.driver	= {
> > +		.name	= "da9150",
> > +		.owner	= THIS_MODULE,
> 
> No need to update this field...

Ok, will remove .owner setting.

> 
> > +		.of_match_table = of_match_ptr(da9150_of_match),
> > +	},
> > +	.probe		= da9150_probe,
> > +	.remove		= da9150_remove,
> > +	.shutdown	= da9150_shutdown,
> > +	.id_table	= da9150_i2c_id,
> > +};
> > +
> > +module_i2c_driver(da9150_driver);
> > +
> > +MODULE_DESCRIPTION("I2C Driver for DA9150");
> > +MODULE_AUTHOR("Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com");
> > +MODULE_LICENSE("GPL");
> >
> --
> Regards,
> Varka Bhadram.


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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-09 10:32       ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:32 UTC (permalink / raw)
  To: Varka Bhadram, Opensource [Adam Thomson],
	Lee Jones, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches
  Cc: linux-kernel, Support Opensource

T24gQXVndXN0IDI4LCAyMDE0IDEyOjQ3LCBWYXJrYSBCaGFkcmFtIHdyb3RlOg0KDQo+IE9uIDA4
LzI4LzIwMTQgMDQ6MTggUE0sIEFkYW0gVGhvbXNvbiB3cm90ZToNCj4gDQo+ICguLi4pDQo+IA0K
PiA+ICtzdGF0aWMgaW50IGRhOTE1MF9wcm9iZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LA0K
PiA+ICsJCQljb25zdCBzdHJ1Y3QgaTJjX2RldmljZV9pZCAqaWQpDQo+ID4gK3sNCj4gPiArCXN0
cnVjdCBkYTkxNTAgKmRhOTE1MDsNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ICsJZGE5MTUw
ID0gZGV2bV9remFsbG9jKCZjbGllbnQtPmRldiwgc2l6ZW9mKHN0cnVjdCBkYTkxNTApLCBHRlBf
S0VSTkVMKTsNCj4gPiArCWlmIChkYTkxNTAgPT0gTlVMTCkNCj4gPiArCQlyZXR1cm4gLUVOT01F
TTsNCj4gDQo+IGRhOTE1MCA9IGRldm1fa3phbGxvYygmY2xpZW50LT5kZXYsIHNpemVvZigqZGE5
MTUwKSwgR0ZQX0tFUk5FTCk7DQo+IGlmICghZGE5MTUwKQ0KPiAJcmV0dXJuIC1FTk9NRU07DQoN
Ck9rLCBubyByZWFsIGRpZmZlcmVuY2UsIGJ1dCBjYW4gY2hhbmdlIGl0Lg0KDQo+IA0KPiA+ICsJ
ZGE5MTUwLT5kZXYgPSAmY2xpZW50LT5kZXY7DQo+ID4gKwlkYTkxNTAtPmlycSA9IGNsaWVudC0+
aXJxOw0KPiA+ICsJaTJjX3NldF9jbGllbnRkYXRhKGNsaWVudCwgZGE5MTUwKTsNCj4gPiArCWRl
dl9zZXRfZHJ2ZGF0YShkYTkxNTAtPmRldiwgZGE5MTUwKTsNCj4gPiArDQo+ID4gKwlkYTkxNTAt
PnJlZ21hcCA9IGRldm1fcmVnbWFwX2luaXRfaTJjKGNsaWVudCwgJmRhOTE1MF9yZWdtYXBfY29u
ZmlnKTsNCj4gPiArCWlmIChJU19FUlIoZGE5MTUwLT5yZWdtYXApKSB7DQo+ID4gKwkJcmV0ID0g
UFRSX0VSUihkYTkxNTAtPnJlZ21hcCk7DQo+ID4gKwkJZGV2X2VycihkYTkxNTAtPmRldiwgIkZh
aWxlZCB0byBhbGxvY2F0ZSByZWdpc3RlciBtYXA6ICVkXG4iLA0KPiA+ICsJCQlyZXQpOw0KPiA+
ICsJCXJldHVybiByZXQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0dXJuIGRhOTE1MF9kZXZp
Y2VfaW5pdChkYTkxNTApOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGRhOTE1MF9y
ZW1vdmUoc3RydWN0IGkyY19jbGllbnQgKmNsaWVudCkNCj4gPiArew0KPiA+ICsJc3RydWN0IGRh
OTE1MCAqZGE5MTUwID0gaTJjX2dldF9jbGllbnRkYXRhKGNsaWVudCk7DQo+ID4gKw0KPiA+ICsJ
ZGE5MTUwX2RldmljZV9leGl0KGRhOTE1MCk7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4g
K30NCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIGRhOTE1MF9zaHV0ZG93bihzdHJ1Y3QgaTJjX2Ns
aWVudCAqY2xpZW50KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgZGE5MTUwICpkYTkxNTAgPSBpMmNf
Z2V0X2NsaWVudGRhdGEoY2xpZW50KTsNCj4gPiArDQo+ID4gKwlkYTkxNTBfZGV2aWNlX3NodXRk
b3duKGRhOTE1MCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaTJj
X2RldmljZV9pZCBkYTkxNTBfaTJjX2lkW10gPSB7DQo+ID4gKwl7ICJkYTkxNTAiLCAwIH0sDQo+
ID4gKwl7IH0NCj4gPiArfTsNCj4gPiArTU9EVUxFX0RFVklDRV9UQUJMRShpMmMsIGRhOTE1MF9p
MmNfaWQpOw0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0IHN0cnVjdCBvZl9kZXZpY2VfaWQgZGE5
MTUwX29mX21hdGNoW10gPSB7DQo+ID4gKwl7IC5jb21wYXRpYmxlID0gImRsZyxkYTkxNTAiLCB9
LA0KPiA+ICsJeyB9DQo+ID4gK307DQo+ID4gKw0KPiANCj4gbWlzc2VkIE1PRFVMRV9ERVZJQ0Vf
VEFCTEUob2YsIC4uLikgICA/DQoNCk9rLCB3aWxsIGFkZCB0aGF0IGluLg0KDQo+IA0KPiA+ICtz
dGF0aWMgc3RydWN0IGkyY19kcml2ZXIgZGE5MTUwX2RyaXZlciA9IHsNCj4gPiArCS5kcml2ZXIJ
PSB7DQo+ID4gKwkJLm5hbWUJPSAiZGE5MTUwIiwNCj4gPiArCQkub3duZXIJPSBUSElTX01PRFVM
RSwNCj4gDQo+IE5vIG5lZWQgdG8gdXBkYXRlIHRoaXMgZmllbGQuLi4NCg0KT2ssIHdpbGwgcmVt
b3ZlIC5vd25lciBzZXR0aW5nLg0KDQo+IA0KPiA+ICsJCS5vZl9tYXRjaF90YWJsZSA9IG9mX21h
dGNoX3B0cihkYTkxNTBfb2ZfbWF0Y2gpLA0KPiA+ICsJfSwNCj4gPiArCS5wcm9iZQkJPSBkYTkx
NTBfcHJvYmUsDQo+ID4gKwkucmVtb3ZlCQk9IGRhOTE1MF9yZW1vdmUsDQo+ID4gKwkuc2h1dGRv
d24JPSBkYTkxNTBfc2h1dGRvd24sDQo+ID4gKwkuaWRfdGFibGUJPSBkYTkxNTBfaTJjX2lkLA0K
PiA+ICt9Ow0KPiA+ICsNCj4gPiArbW9kdWxlX2kyY19kcml2ZXIoZGE5MTUwX2RyaXZlcik7DQo+
ID4gKw0KPiA+ICtNT0RVTEVfREVTQ1JJUFRJT04oIkkyQyBEcml2ZXIgZm9yIERBOTE1MCIpOw0K
PiA+ICtNT0RVTEVfQVVUSE9SKCJBZGFtIFRob21zb24NCj4gPEFkYW0uVGhvbXNvbi5PcGVuc291
cmNlQGRpYXNlbWkuY29tIik7DQo+ID4gK01PRFVMRV9MSUNFTlNFKCJHUEwiKTsNCj4gPg0KPiAt
LQ0KPiBSZWdhcmRzLA0KPiBWYXJrYSBCaGFkcmFtLg0KDQo=

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-08-28 16:36   ` Lee Jones
  2014-09-09 10:37       ` Opensource [Adam Thomson]
@ 2014-09-09 10:37       ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:37 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 27143 bytes --]

On August 28, 2014 17:36, Lee Jones wrote:

Thanks for the feedback. As a general comment a couple of the items you've
identified relate to future updates (additional functionality being added).
I already have code in place for this but have stripped out a couple of the
drivers just to reduce the churn and size of patch submission. These will be
added once these patches have been accepted.

Where this is the case, I have added notes in-line against the relevant
comments you made.

> On Thu, 28 Aug 2014, Adam Thomson wrote:
> 
> > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > GPIO and GPADC functionality.
> >
> > Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > ---
> >  drivers/mfd/Kconfig                  |   12 +
> >  drivers/mfd/Makefile                 |    2 +
> >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> 
> Do you also have another, say SPI version?

No, not yet, but this is something that we may add later as the device does
support SPI.

> 
> >  include/linux/mfd/da9150/core.h      |   80 +++
> >  include/linux/mfd/da9150/pdata.h     |   21 +
> >  include/linux/mfd/da9150/registers.h | 1153
> ++++++++++++++++++++++++++++++++++
> >  7 files changed, 1776 insertions(+)
> >  create mode 100644 drivers/mfd/da9150-core.c
> >  create mode 100644 drivers/mfd/da9150-i2c.c
> >  create mode 100644 include/linux/mfd/da9150/core.h
> >  create mode 100644 include/linux/mfd/da9150/pdata.h
> >  create mode 100644 include/linux/mfd/da9150/registers.h
> >
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index de5abf2..76adb2c 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -183,6 +183,18 @@ config MFD_DA9063
> >  	  Additional drivers must be enabled in order to use the functionality
> >  	  of the device.
> >
> > +config MFD_DA9150
> > +	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
> 
> Why can't this be built as a module?

No reason. Will change it.

> 
> > +	depends on I2C=y
> > +	select MFD_CORE
> > +	select REGMAP_I2C
> > +	select REGMAP_IRQ
> > +	help
> > +	  This adds support for the DA9150 integrated charger and fuel-gauge
> > +	  chip. This driver provides common support for accessing the device.
> > +	  Additional drivers must be enabled in order to use the specific
> > +	  features of the device.
> > +
> >  config MFD_MC13XXX
> >  	tristate
> >  	depends on (SPI_MASTER || I2C)
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index f001487..098dfa1 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
> >  da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
> >  obj-$(CONFIG_MFD_DA9063)	+= da9063.o
> >
> > +obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
> > +
> 
> Do the other drivers smell?  Please butt up against them.
> 
> I'm not entirely sure why there are so many '\n's in the Makefile!

Okey dokey. Will change.

> 
> >  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
> >  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
> >  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> > diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
> > new file mode 100644
> > index 0000000..029a30b
> > --- /dev/null
> > +++ b/drivers/mfd/da9150-core.c
> > @@ -0,0 +1,332 @@
> > +/*
> > + * DA9150 Core MFD Driver
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > + *
> > + * This program is free software; you can redistribute  it and/or modify it
> > + * under  the terms of  the GNU General  Public License as published by the
> > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > + * option) any later version.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/mfd/core.h>
> > +
> 
> No real need for this '\n'.

I can change this, but my reason was to separate common kernel includes from
device specific ones, for readability. 

> 
> > +#include <linux/mfd/da9150/core.h>
> > +#include <linux/mfd/da9150/registers.h>
> > +#include <linux/mfd/da9150/pdata.h>
> > +
> > +u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
> > +{
> > +	int val, ret;
> > +
> > +	ret = regmap_read(da9150->regmap, reg, &val);
> > +	if (ret < 0)
> 
> What if ret > 0?  Is that a good thing? :)
> 
> Just 'if (ret)'.

Fine, will change.

> 
> > +		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return (u8) val;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_reg_read);
> 
> Not sure I like this abstraction stuff.  I could understand if there
> were locking involved, but there isn't.  You don't appear to check for
> errors in the subordinate drivers either, rather you just plough on
> ahead.  Not sure that's a good idea either.
> 
> Anyone have a second opinion?

The reason for these is because future patches to add additional functionality
will introduce I2C access functions which do not use regmap and access the
device via a separate I2C address for this purpose. I will need to provide
access functions for that, and so having a common style of I2C access makes
sense for this driver. Means any access just needs to provide the MFD private
data, and the relevant functions take care of the rest. I think this is cleaner
in this instance.

With regards to errors, if we're seeing problems on I2C I don't believe dealing
with the errors elsewhere is going to help much. I wanted to provide logging
though in case this is seen for some reason. However I could just make these
functions void return as you're right in your comments that no checking is done
elsewhere.

> 
> > +int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_write(da9150->regmap, reg, val);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_reg_write);
> 
> Blah.
> 
> > +int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_update_bits(da9150->regmap, reg, mask, val);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_set_bits);
> 
> Blah.
> 
> > +int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_bulk_read);
> 
> Blah.
> 
> > +int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_raw_write(da9150->regmap, reg, buf, count);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_bulk_write);
> 
> Blah.
> 
> > +static struct regmap_irq da9150_irqs[] = {
> > +	[DA9150_IRQ_VBUS] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_VBUS_MASK,
> > +	},
> > +	[DA9150_IRQ_CHG] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_CHG_MASK,
> > +	},
> > +	[DA9150_IRQ_TCLASS] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_TCLASS_MASK,
> > +	},
> > +	[DA9150_IRQ_TJUNC] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_TJUNC_MASK,
> > +	},
> > +	[DA9150_IRQ_VFAULT] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_VFAULT_MASK,
> > +	},
> > +	[DA9150_IRQ_CONF] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_CONF_MASK,
> > +	},
> > +	[DA9150_IRQ_DAT] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_DAT_MASK,
> > +	},
> > +	[DA9150_IRQ_DTYPE] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_DTYPE_MASK,
> > +	},
> > +	[DA9150_IRQ_ID] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_ID_MASK,
> > +	},
> > +	[DA9150_IRQ_ADP] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_ADP_MASK,
> > +	},
> > +	[DA9150_IRQ_SESS_END] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_SESS_END_MASK,
> > +	},
> > +	[DA9150_IRQ_SESS_VLD] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_SESS_VLD_MASK,
> > +	},
> > +	[DA9150_IRQ_FG] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_FG_MASK,
> > +	},
> > +	[DA9150_IRQ_GP] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GP_MASK,
> > +	},
> > +	[DA9150_IRQ_TBAT] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_TBAT_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOA] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOA_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOB] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOB_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOC] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOC_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOD] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOD_MASK,
> > +	},
> > +	[DA9150_IRQ_GPADC] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPADC_MASK,
> > +	},
> > +	[DA9150_IRQ_WKUP] = {
> > +		.reg_offset = 3,
> > +		.mask = DA9150_E_WKUP_MASK,
> > +	},
> > +};
> > +
> > +static struct regmap_irq_chip da9150_regmap_irq_chip = {
> > +	.name = "da9150_irq",
> > +	.status_base = DA9150_EVENT_E,
> > +	.mask_base = DA9150_IRQ_MASK_E,
> > +	.ack_base = DA9150_EVENT_E,
> > +	.num_regs = DA9150_NUM_IRQ_REGS,
> > +	.irqs = da9150_irqs,
> > +	.num_irqs = ARRAY_SIZE(da9150_irqs),
> > +};
> > +
> > +/* Helper functions for sub-devices to request/free IRQs */
> > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > +			irq_handler_t handler, const char *name)
> > +{
> > +	int irq, ret;
> > +
> > +	irq = platform_get_irq_byname(pdev, name);
> > +	if (irq < 0)
> > +		return irq;
> > +
> > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > +					IRQF_ONESHOT, name, dev_id);
> > +	if (ret)
> > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> 
> Why do they need help?  What problem does adding these layers solve?

Means I don't have to keep adding print error lines everywhere else if this
function takes care of it. Thought that would be cleaner.

> 
> > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > +		       const char *name)
> > +{
> > +	int irq;
> > +
> > +	irq = platform_get_irq_byname(pdev, name);
> > +	if (irq < 0)
> > +		return;
> > +
> > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> 
> Do you ever release the IRQ and not unbind the driver?
> 
> Are there ordering issues at play here?
> 
> If not, there's no need to conduct a manual free.

In the charger driver, in the remove function there is a need I believe to
free the IRQs before other items are cleared up (e.g. power_supply classes),
so this is why I have added this in here.

> 
> > +static struct resource da9150_gpadc_resources[] = {
> > +	{
> > +		.name = "GPADC",
> > +		.start = DA9150_IRQ_GPADC,
> > +		.end = DA9150_IRQ_GPADC,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +};
> > +
> > +static struct resource da9150_charger_resources[] = {
> > +	{
> > +		.name = "CHG_STATUS",
> > +		.start = DA9150_IRQ_CHG,
> > +		.end = DA9150_IRQ_CHG,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.name = "CHG_TJUNC",
> > +		.start = DA9150_IRQ_TJUNC,
> > +		.end = DA9150_IRQ_TJUNC,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.name = "CHG_VFAULT",
> > +		.start = DA9150_IRQ_VFAULT,
> > +		.end = DA9150_IRQ_VFAULT,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.name = "CHG_VBUS",
> > +		.start = DA9150_IRQ_VBUS,
> > +		.end = DA9150_IRQ_VBUS,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +};
> > +
> > +static struct mfd_cell da9150_devs[] = {
> > +	{
> > +		.name = "da9150-gpadc",
> > +		.of_compatible = "dlg,da9150-gpadc",
> > +		.resources = da9150_gpadc_resources,
> > +		.num_resources = ARRAY_SIZE(da9150_gpadc_resources),
> > +	},
> > +	{
> > +		.name = "da9150-charger",
> > +		.of_compatible = "dlg,da9150-charger",
> > +		.resources = da9150_charger_resources,
> > +		.num_resources = ARRAY_SIZE(da9150_charger_resources),
> > +	},
> > +};
> > +
> > +int da9150_device_init(struct da9150 *da9150)
> > +{
> > +	struct da9150_pdata *pdata = da9150->dev->platform_data;
> 
> dev_get_platdata()

Right ho. Will update.

> 
> > +	int ret;
> > +
> > +	/* Handle platform data */
> 
> This comment doesn't add anything - the code is clear enough.

Ok will scrap that.

> 
> > +	if (pdata)
> > +		da9150->irq_base = pdata->irq_base;
> > +	else
> > +		da9150->irq_base = -1;
> 
> pdata ? pdata->irq_base : -1;

This is left this way as later updates to add additional functionality will
require addtional work to be done with the platform data. Seemed pointless
changing it here just to change it back later.

> 
> > +	/* Init IRQs */
> 
> No need for these, please only add comments where the code is complex
> or convoluted.

Ok, will remove.

> 
> > +	ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
> > +				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> > +				  da9150->irq_base, &da9150_regmap_irq_chip,
> > +				  &da9150->regmap_irq_data);
> > +	if (ret < 0)
> 
> 'if (ret)' where positive replies aren't possible or are errors.

Ok, fine.

> 
> > +		goto err_irq;
> 
> Just return here and remove 'err_irq' label.

Yep, will tidy up.

> 
> > +	da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
> > +
> > +	/* Make the IRQ line a wake source */
> > +	enable_irq_wake(da9150->irq);
> > +
> > +	/* Add MFD Devices */
> > +	ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
> > +			      ARRAY_SIZE(da9150_devs), NULL,
> > +			      da9150->irq_base, NULL);
> > +	if (ret < 0) {
> > +		dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
> > +		goto err_mfd;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_mfd:
> > +	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> > +err_irq:
> > +	return ret;
> > +}
> > +
> > +void da9150_device_exit(struct da9150 *da9150)
> > +{
> > +	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> > +	mfd_remove_devices(da9150->dev);
> > +}
> > +
> > +void da9150_device_shutdown(struct da9150 *da9150)
> > +{
> > +	/* Make sure we have a wakup source for the device */
> > +	da9150_set_bits(da9150, DA9150_CONFIG_D,
> > +			DA9150_WKUP_PM_EN_MASK,
> > +			DA9150_WKUP_PM_EN_MASK);
> > +
> > +	/* Set device to DISABLED mode */
> > +	da9150_set_bits(da9150, DA9150_CONTROL_C,
> > +			DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
> > +}
> > +
> > +MODULE_DESCRIPTION("MFD Core Driver for DA9150");
> > +MODULE_AUTHOR("Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/mfd/da9150-i2c.c b/drivers/mfd/da9150-i2c.c
> > new file mode 100644
> > index 0000000..a02525c
> > --- /dev/null
> > +++ b/drivers/mfd/da9150-i2c.c
> > @@ -0,0 +1,176 @@
> > +/*
> > + * DA9150 I2C Driver
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > + *
> > + * This program is free software; you can redistribute  it and/or modify it
> > + * under  the terms of  the GNU General  Public License as published by the
> > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > + * option) any later version.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/i2c.h>
> > +#include <linux/regmap.h>
> > +#include <linux/slab.h>
> > +
> 
> Remove this line.

Ok.

> 
> > +#include <linux/mfd/da9150/core.h>
> > +#include <linux/mfd/da9150/registers.h>
> > +
> > +static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
> > +{
> > +	switch (reg) {
> > +	case DA9150_PAGE_CON:
> > +	case DA9150_STATUS_A:
> > +	case DA9150_STATUS_B:
> > +	case DA9150_STATUS_C:
> > +	case DA9150_STATUS_D:
> > +	case DA9150_STATUS_E:
> > +	case DA9150_STATUS_F:
> > +	case DA9150_STATUS_G:
> > +	case DA9150_STATUS_H:
> > +	case DA9150_STATUS_I:
> > +	case DA9150_STATUS_J:
> > +	case DA9150_STATUS_K:
> > +	case DA9150_STATUS_L:
> > +	case DA9150_STATUS_N:
> > +	case DA9150_FAULT_LOG_A:
> > +	case DA9150_FAULT_LOG_B:
> > +	case DA9150_EVENT_E:
> > +	case DA9150_EVENT_F:
> > +	case DA9150_EVENT_G:
> > +	case DA9150_EVENT_H:
> > +	case DA9150_CONTROL_B:
> > +	case DA9150_CONTROL_C:
> > +	case DA9150_GPADC_MAN:
> > +	case DA9150_GPADC_RES_A:
> > +	case DA9150_GPADC_RES_B:
> > +	case DA9150_ADETVB_CFG_C:
> > +	case DA9150_ADETD_STAT:
> > +	case DA9150_ADET_CMPSTAT:
> > +	case DA9150_ADET_CTRL_A:
> > +	case DA9150_PPR_TCTR_B:
> > +	case DA9150_COREBTLD_STAT_A:
> > +	case DA9150_CORE_DATA_A:
> > +	case DA9150_CORE_DATA_B:
> > +	case DA9150_CORE_DATA_C:
> > +	case DA9150_CORE_DATA_D:
> > +	case DA9150_CORE2WIRE_STAT_A:
> > +	case DA9150_FW_CTRL_C:
> > +	case DA9150_FG_CTRL_B:
> > +	case DA9150_FW_CTRL_B:
> > +	case DA9150_GPADC_CMAN:
> > +	case DA9150_GPADC_CRES_A:
> > +	case DA9150_GPADC_CRES_B:
> > +	case DA9150_CC_ICHG_RES_A:
> > +	case DA9150_CC_ICHG_RES_B:
> > +	case DA9150_CC_IAVG_RES_A:
> > +	case DA9150_CC_IAVG_RES_B:
> > +	case DA9150_TAUX_CTRL_A:
> > +	case DA9150_TAUX_VALUE_H:
> > +	case DA9150_TAUX_VALUE_L:
> > +	case DA9150_TBAT_RES_A:
> > +	case DA9150_TBAT_RES_B:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> > +static const struct regmap_range_cfg da9150_range_cfg[] = {
> > +	{
> > +		.range_min = DA9150_PAGE_CON,
> > +		.range_max = DA9150_TBAT_RES_B,
> > +		.selector_reg = DA9150_PAGE_CON,
> > +		.selector_mask = DA9150_I2C_PAGE_MASK,
> > +		.selector_shift = DA9150_I2C_PAGE_SHIFT,
> > +		.window_start = 0,
> > +		.window_len = 256,
> > +	},
> > +};
> > +
> > +static struct regmap_config da9150_regmap_config = {
> > +	.reg_bits = 8,
> > +	.val_bits = 8,
> > +	.ranges = da9150_range_cfg,
> > +	.num_ranges = ARRAY_SIZE(da9150_range_cfg),
> > +	.max_register = DA9150_TBAT_RES_B,
> > +
> > +	.cache_type = REGCACHE_RBTREE,
> > +
> > +	.volatile_reg = da9150_volatile_reg,
> > +};
> > +
> > +static int da9150_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id)
> > +{
> > +	struct da9150 *da9150;
> > +	int ret;
> > +
> > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> 
> sizeof(*da9150)

Same difference, but ok.

> 
> > +	if (da9150 == NULL)
> 
> if (!da9150)

Right, fine.

> 
> > +		return -ENOMEM;
> 
> '\n'

Right, fine.

> 
> > +	da9150->dev = &client->dev;
> > +	da9150->irq = client->irq;
> > +	i2c_set_clientdata(client, da9150);
> > +	dev_set_drvdata(da9150->dev, da9150);
> 
> Why do you need this in both locations?
> 

Don't. Will remove accordingly.

> > +	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
> > +	if (IS_ERR(da9150->regmap)) {
> > +		ret = PTR_ERR(da9150->regmap);
> > +		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
> > +			ret);
> > +		return ret;
> > +	}
> > +
> > +	return da9150_device_init(da9150);
> > +}
> > +
> > +static int da9150_remove(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_exit(da9150);
> > +
> > +	return 0;
> > +}
> > +
> > +static void da9150_shutdown(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_shutdown(da9150);
> > +}
> > +
> > +static const struct i2c_device_id da9150_i2c_id[] = {
> > +	{ "da9150", 0 },
> 
> I don't see the .id parameter being used, just leave it blank.

Ok, no problem.

> 
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
> > +
> > +static const struct of_device_id da9150_of_match[] = {
> > +	{ .compatible = "dlg,da9150", },
> > +	{ }
> > +};
> 
> MODULE_DEVICE_TABLE(of, ...)
> 
> > +static struct i2c_driver da9150_driver = {
> > +	.driver	= {
> > +		.name	= "da9150",
> > +		.owner	= THIS_MODULE,
> 
> You can remove this line, it's taken care of for you elsewhere.

Yes, will remove.

> 
> > +		.of_match_table = of_match_ptr(da9150_of_match),
> > +	},
> > +	.probe		= da9150_probe,
> > +	.remove		= da9150_remove,
> > +	.shutdown	= da9150_shutdown,
> > +	.id_table	= da9150_i2c_id,
> > +};
> > +
> > +module_i2c_driver(da9150_driver);
> > +
> > +MODULE_DESCRIPTION("I2C Driver for DA9150");
> > +MODULE_AUTHOR("Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/mfd/da9150/core.h b/include/linux/mfd/da9150/core.h
> > new file mode 100644
> > index 0000000..d23c500
> > --- /dev/null
> > +++ b/include/linux/mfd/da9150/core.h
> > @@ -0,0 +1,80 @@
> > +/*
> > + * DA9150 MFD Driver - Core Data
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> > + */
> > +
> > +#ifndef __DA9150_CORE_H
> > +#define __DA9150_CORE_H
> > +
> > +#include <linux/device.h>
> > +#include <linux/i2c.h>
> 
> What's this used for?
> 
> > +#include <linux/interrupt.h>
> > +#include <linux/regmap.h>
> > +#include <linux/mutex.h>
> > +
> > +/* I2C address paging */
> > +#define DA9150_REG_PAGE_SHIFT	8
> > +#define DA9150_REG_PAGE_MASK	0xFF
> > +
> > +/* IRQs */
> > +#define DA9150_NUM_IRQ_REGS	4
> > +#define DA9150_IRQ_VBUS		0
> > +#define DA9150_IRQ_CHG		1
> > +#define DA9150_IRQ_TCLASS	2
> > +#define DA9150_IRQ_TJUNC	3
> > +#define DA9150_IRQ_VFAULT	4
> > +#define DA9150_IRQ_CONF		5
> > +#define DA9150_IRQ_DAT		6
> > +#define DA9150_IRQ_DTYPE	7
> > +#define DA9150_IRQ_ID		8
> > +#define DA9150_IRQ_ADP		9
> > +#define DA9150_IRQ_SESS_END	10
> > +#define DA9150_IRQ_SESS_VLD	11
> > +#define DA9150_IRQ_FG		12
> > +#define DA9150_IRQ_GP		13
> > +#define DA9150_IRQ_TBAT		14
> > +#define DA9150_IRQ_GPIOA	15
> > +#define DA9150_IRQ_GPIOB	16
> > +#define DA9150_IRQ_GPIOC	17
> > +#define DA9150_IRQ_GPIOD	18
> > +#define DA9150_IRQ_GPADC	19
> > +#define DA9150_IRQ_WKUP		20
> > +
> > +struct da9150 {
> > +	struct device *dev;
> > +
> > +	struct regmap *regmap;
> > +
> 
> Why the '\n's?

Personal preference, but will remove.

> 
> > +	struct regmap_irq_chip_data *regmap_irq_data;
> > +	int irq;
> > +	int irq_base;
> > +};
> > +
> > +/* Device I/O */
> > +u8 da9150_reg_read(struct da9150 *da9150, u16 reg);
> > +int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val);
> > +int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val);
> > +
> > +int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf);
> > +int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf);
> > +
> > +/* IRQ helper functions */
> > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > +			irq_handler_t handler, const char *name);
> > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > +			const char *name);
> 
> I'm not sure why any of these 7 functions are required.

Clarified my intentions in previous comments.

> 
> > +/* Init/Exit */
> > +int da9150_device_init(struct da9150 *da9150);
> > +void da9150_device_exit(struct da9150 *da9150);
> > +void da9150_device_shutdown(struct da9150 *da9150);
> > +
> > +#endif /* __DA9150_CORE_H */
> > diff --git a/include/linux/mfd/da9150/pdata.h b/include/linux/mfd/da9150/pdata.h
> > new file mode 100644
> > index 0000000..e2b37f1
> > --- /dev/null
> > +++ b/include/linux/mfd/da9150/pdata.h
> > @@ -0,0 +1,21 @@
> > +/*
> > + * DA9150 MFD Driver - Platform Data
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> > + */
> > +
> > +#ifndef __DA9150_PDATA_H
> > +#define __DA9150_PDATA_H
> > +
> > +struct da9150_pdata {
> > +	int irq_base;
> > +};
> 
> Just put this in core.h and do away witht this header file.

The reason for this is that I will add more platform data items later with
subsequent submissions for additional features. It felt cleaner to separate out
these structures than throw it in the core.h header. However if it's going to
be a problem I'll fold this into core.h

> 
> > +#endif /* __DA9150_PDATA_H */
> > diff --git a/include/linux/mfd/da9150/registers.h
> b/include/linux/mfd/da9150/registers.h
> > new file mode 100644
> > index 0000000..ef4826d
> > --- /dev/null
> > +++ b/include/linux/mfd/da9150/registers.h
> > @@ -0,0 +1,1153 @@
> > +/*
> > + * DA9150 MFD Driver - Registers
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> > + */
> > +
> > +#ifndef __DA9150_REGISTERS_H
> > +#define __DA9150_REGISTERS_H
> > +
> > +/* Registers */
> 
> [...]
> 
> > +/* DA9150_CONTROL_A = 0x0E5 */
> > +#define DA9150_VDD33_SL_SHIFT			0
> > +#define DA9150_VDD33_SL_MASK			(0x01 << 0)
> > +#define DA9150_VDD33_LPM_SHIFT			1
> > +#define DA9150_VDD33_LPM_MASK			(0x03 << 1)
> > +#define DA9150_VDD33_EN_SHIFT			3
> > +#define DA9150_VDD33_EN_MASK			(0x01 << 3)
> > +#define DA9150_GPI_LPM_SHIFT			6
> > +#define DA9150_GPI_LPM_MASK			(0x01 << 6)
> > +#define DA9150_PM_IF_LPM_SHIFT			7
> > +#define DA9150_PM_IF_LPM_MASK			(0x01 << 7)
> > +
> > +/* DA9150_CONTROL_B = 0x0E6 */
> > +#define DA9150_LPM_SHIFT			0
> > +#define DA9150_LPM_MASK				(0x01 << 0)
> > +#define DA9150_RESET_SHIFT			1
> > +#define DA9150_RESET_MASK			(0x01 << 1)
> > +#define DA9150_RESET_USRCONF_EN_SHIFT		2
> > +#define DA9150_RESET_USRCONF_EN_MASK		(0x01 << 2)
> > +
> > +/* DA9150_CONTROL_C = 0x0E7 */
> > +#define DA9150_DISABLE_SHIFT			0
> > +#define DA9150_DISABLE_MASK			(0x01 << 0)
> 
> Use BIT() for all of these (1 << X) macros.

OK, will do.

> 
> [...]
> 
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-09 10:37       ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:37 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

On August 28, 2014 17:36, Lee Jones wrote:

Thanks for the feedback. As a general comment a couple of the items you've
identified relate to future updates (additional functionality being added).
I already have code in place for this but have stripped out a couple of the
drivers just to reduce the churn and size of patch submission. These will be
added once these patches have been accepted.

Where this is the case, I have added notes in-line against the relevant
comments you made.

> On Thu, 28 Aug 2014, Adam Thomson wrote:
> 
> > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > GPIO and GPADC functionality.
> >
> > Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > ---
> >  drivers/mfd/Kconfig                  |   12 +
> >  drivers/mfd/Makefile                 |    2 +
> >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> 
> Do you also have another, say SPI version?

No, not yet, but this is something that we may add later as the device does
support SPI.

> 
> >  include/linux/mfd/da9150/core.h      |   80 +++
> >  include/linux/mfd/da9150/pdata.h     |   21 +
> >  include/linux/mfd/da9150/registers.h | 1153
> ++++++++++++++++++++++++++++++++++
> >  7 files changed, 1776 insertions(+)
> >  create mode 100644 drivers/mfd/da9150-core.c
> >  create mode 100644 drivers/mfd/da9150-i2c.c
> >  create mode 100644 include/linux/mfd/da9150/core.h
> >  create mode 100644 include/linux/mfd/da9150/pdata.h
> >  create mode 100644 include/linux/mfd/da9150/registers.h
> >
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index de5abf2..76adb2c 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -183,6 +183,18 @@ config MFD_DA9063
> >  	  Additional drivers must be enabled in order to use the functionality
> >  	  of the device.
> >
> > +config MFD_DA9150
> > +	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
> 
> Why can't this be built as a module?

No reason. Will change it.

> 
> > +	depends on I2C=y
> > +	select MFD_CORE
> > +	select REGMAP_I2C
> > +	select REGMAP_IRQ
> > +	help
> > +	  This adds support for the DA9150 integrated charger and fuel-gauge
> > +	  chip. This driver provides common support for accessing the device.
> > +	  Additional drivers must be enabled in order to use the specific
> > +	  features of the device.
> > +
> >  config MFD_MC13XXX
> >  	tristate
> >  	depends on (SPI_MASTER || I2C)
> > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > index f001487..098dfa1 100644
> > --- a/drivers/mfd/Makefile
> > +++ b/drivers/mfd/Makefile
> > @@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
> >  da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
> >  obj-$(CONFIG_MFD_DA9063)	+= da9063.o
> >
> > +obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
> > +
> 
> Do the other drivers smell?  Please butt up against them.
> 
> I'm not entirely sure why there are so many '\n's in the Makefile!

Okey dokey. Will change.

> 
> >  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
> >  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
> >  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> > diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
> > new file mode 100644
> > index 0000000..029a30b
> > --- /dev/null
> > +++ b/drivers/mfd/da9150-core.c
> > @@ -0,0 +1,332 @@
> > +/*
> > + * DA9150 Core MFD Driver
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > + *
> > + * This program is free software; you can redistribute  it and/or modify it
> > + * under  the terms of  the GNU General  Public License as published by the
> > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > + * option) any later version.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/slab.h>
> > +#include <linux/irq.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/mfd/core.h>
> > +
> 
> No real need for this '\n'.

I can change this, but my reason was to separate common kernel includes from
device specific ones, for readability. 

> 
> > +#include <linux/mfd/da9150/core.h>
> > +#include <linux/mfd/da9150/registers.h>
> > +#include <linux/mfd/da9150/pdata.h>
> > +
> > +u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
> > +{
> > +	int val, ret;
> > +
> > +	ret = regmap_read(da9150->regmap, reg, &val);
> > +	if (ret < 0)
> 
> What if ret > 0?  Is that a good thing? :)
> 
> Just 'if (ret)'.

Fine, will change.

> 
> > +		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return (u8) val;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_reg_read);
> 
> Not sure I like this abstraction stuff.  I could understand if there
> were locking involved, but there isn't.  You don't appear to check for
> errors in the subordinate drivers either, rather you just plough on
> ahead.  Not sure that's a good idea either.
> 
> Anyone have a second opinion?

The reason for these is because future patches to add additional functionality
will introduce I2C access functions which do not use regmap and access the
device via a separate I2C address for this purpose. I will need to provide
access functions for that, and so having a common style of I2C access makes
sense for this driver. Means any access just needs to provide the MFD private
data, and the relevant functions take care of the rest. I think this is cleaner
in this instance.

With regards to errors, if we're seeing problems on I2C I don't believe dealing
with the errors elsewhere is going to help much. I wanted to provide logging
though in case this is seen for some reason. However I could just make these
functions void return as you're right in your comments that no checking is done
elsewhere.

> 
> > +int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_write(da9150->regmap, reg, val);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_reg_write);
> 
> Blah.
> 
> > +int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_update_bits(da9150->regmap, reg, mask, val);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_set_bits);
> 
> Blah.
> 
> > +int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_bulk_read);
> 
> Blah.
> 
> > +int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
> > +{
> > +	int ret;
> > +
> > +	ret = regmap_raw_write(da9150->regmap, reg, buf, count);
> > +	if (ret < 0)
> > +		dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
> > +			reg, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_bulk_write);
> 
> Blah.
> 
> > +static struct regmap_irq da9150_irqs[] = {
> > +	[DA9150_IRQ_VBUS] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_VBUS_MASK,
> > +	},
> > +	[DA9150_IRQ_CHG] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_CHG_MASK,
> > +	},
> > +	[DA9150_IRQ_TCLASS] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_TCLASS_MASK,
> > +	},
> > +	[DA9150_IRQ_TJUNC] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_TJUNC_MASK,
> > +	},
> > +	[DA9150_IRQ_VFAULT] = {
> > +		.reg_offset = 0,
> > +		.mask = DA9150_E_VFAULT_MASK,
> > +	},
> > +	[DA9150_IRQ_CONF] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_CONF_MASK,
> > +	},
> > +	[DA9150_IRQ_DAT] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_DAT_MASK,
> > +	},
> > +	[DA9150_IRQ_DTYPE] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_DTYPE_MASK,
> > +	},
> > +	[DA9150_IRQ_ID] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_ID_MASK,
> > +	},
> > +	[DA9150_IRQ_ADP] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_ADP_MASK,
> > +	},
> > +	[DA9150_IRQ_SESS_END] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_SESS_END_MASK,
> > +	},
> > +	[DA9150_IRQ_SESS_VLD] = {
> > +		.reg_offset = 1,
> > +		.mask = DA9150_E_SESS_VLD_MASK,
> > +	},
> > +	[DA9150_IRQ_FG] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_FG_MASK,
> > +	},
> > +	[DA9150_IRQ_GP] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GP_MASK,
> > +	},
> > +	[DA9150_IRQ_TBAT] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_TBAT_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOA] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOA_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOB] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOB_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOC] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOC_MASK,
> > +	},
> > +	[DA9150_IRQ_GPIOD] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPIOD_MASK,
> > +	},
> > +	[DA9150_IRQ_GPADC] = {
> > +		.reg_offset = 2,
> > +		.mask = DA9150_E_GPADC_MASK,
> > +	},
> > +	[DA9150_IRQ_WKUP] = {
> > +		.reg_offset = 3,
> > +		.mask = DA9150_E_WKUP_MASK,
> > +	},
> > +};
> > +
> > +static struct regmap_irq_chip da9150_regmap_irq_chip = {
> > +	.name = "da9150_irq",
> > +	.status_base = DA9150_EVENT_E,
> > +	.mask_base = DA9150_IRQ_MASK_E,
> > +	.ack_base = DA9150_EVENT_E,
> > +	.num_regs = DA9150_NUM_IRQ_REGS,
> > +	.irqs = da9150_irqs,
> > +	.num_irqs = ARRAY_SIZE(da9150_irqs),
> > +};
> > +
> > +/* Helper functions for sub-devices to request/free IRQs */
> > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > +			irq_handler_t handler, const char *name)
> > +{
> > +	int irq, ret;
> > +
> > +	irq = platform_get_irq_byname(pdev, name);
> > +	if (irq < 0)
> > +		return irq;
> > +
> > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > +					IRQF_ONESHOT, name, dev_id);
> > +	if (ret)
> > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> 
> Why do they need help?  What problem does adding these layers solve?

Means I don't have to keep adding print error lines everywhere else if this
function takes care of it. Thought that would be cleaner.

> 
> > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > +		       const char *name)
> > +{
> > +	int irq;
> > +
> > +	irq = platform_get_irq_byname(pdev, name);
> > +	if (irq < 0)
> > +		return;
> > +
> > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > +}
> > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> 
> Do you ever release the IRQ and not unbind the driver?
> 
> Are there ordering issues at play here?
> 
> If not, there's no need to conduct a manual free.

In the charger driver, in the remove function there is a need I believe to
free the IRQs before other items are cleared up (e.g. power_supply classes),
so this is why I have added this in here.

> 
> > +static struct resource da9150_gpadc_resources[] = {
> > +	{
> > +		.name = "GPADC",
> > +		.start = DA9150_IRQ_GPADC,
> > +		.end = DA9150_IRQ_GPADC,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +};
> > +
> > +static struct resource da9150_charger_resources[] = {
> > +	{
> > +		.name = "CHG_STATUS",
> > +		.start = DA9150_IRQ_CHG,
> > +		.end = DA9150_IRQ_CHG,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.name = "CHG_TJUNC",
> > +		.start = DA9150_IRQ_TJUNC,
> > +		.end = DA9150_IRQ_TJUNC,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.name = "CHG_VFAULT",
> > +		.start = DA9150_IRQ_VFAULT,
> > +		.end = DA9150_IRQ_VFAULT,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +	{
> > +		.name = "CHG_VBUS",
> > +		.start = DA9150_IRQ_VBUS,
> > +		.end = DA9150_IRQ_VBUS,
> > +		.flags = IORESOURCE_IRQ,
> > +	},
> > +};
> > +
> > +static struct mfd_cell da9150_devs[] = {
> > +	{
> > +		.name = "da9150-gpadc",
> > +		.of_compatible = "dlg,da9150-gpadc",
> > +		.resources = da9150_gpadc_resources,
> > +		.num_resources = ARRAY_SIZE(da9150_gpadc_resources),
> > +	},
> > +	{
> > +		.name = "da9150-charger",
> > +		.of_compatible = "dlg,da9150-charger",
> > +		.resources = da9150_charger_resources,
> > +		.num_resources = ARRAY_SIZE(da9150_charger_resources),
> > +	},
> > +};
> > +
> > +int da9150_device_init(struct da9150 *da9150)
> > +{
> > +	struct da9150_pdata *pdata = da9150->dev->platform_data;
> 
> dev_get_platdata()

Right ho. Will update.

> 
> > +	int ret;
> > +
> > +	/* Handle platform data */
> 
> This comment doesn't add anything - the code is clear enough.

Ok will scrap that.

> 
> > +	if (pdata)
> > +		da9150->irq_base = pdata->irq_base;
> > +	else
> > +		da9150->irq_base = -1;
> 
> pdata ? pdata->irq_base : -1;

This is left this way as later updates to add additional functionality will
require addtional work to be done with the platform data. Seemed pointless
changing it here just to change it back later.

> 
> > +	/* Init IRQs */
> 
> No need for these, please only add comments where the code is complex
> or convoluted.

Ok, will remove.

> 
> > +	ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
> > +				  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> > +				  da9150->irq_base, &da9150_regmap_irq_chip,
> > +				  &da9150->regmap_irq_data);
> > +	if (ret < 0)
> 
> 'if (ret)' where positive replies aren't possible or are errors.

Ok, fine.

> 
> > +		goto err_irq;
> 
> Just return here and remove 'err_irq' label.

Yep, will tidy up.

> 
> > +	da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
> > +
> > +	/* Make the IRQ line a wake source */
> > +	enable_irq_wake(da9150->irq);
> > +
> > +	/* Add MFD Devices */
> > +	ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
> > +			      ARRAY_SIZE(da9150_devs), NULL,
> > +			      da9150->irq_base, NULL);
> > +	if (ret < 0) {
> > +		dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
> > +		goto err_mfd;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_mfd:
> > +	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> > +err_irq:
> > +	return ret;
> > +}
> > +
> > +void da9150_device_exit(struct da9150 *da9150)
> > +{
> > +	regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> > +	mfd_remove_devices(da9150->dev);
> > +}
> > +
> > +void da9150_device_shutdown(struct da9150 *da9150)
> > +{
> > +	/* Make sure we have a wakup source for the device */
> > +	da9150_set_bits(da9150, DA9150_CONFIG_D,
> > +			DA9150_WKUP_PM_EN_MASK,
> > +			DA9150_WKUP_PM_EN_MASK);
> > +
> > +	/* Set device to DISABLED mode */
> > +	da9150_set_bits(da9150, DA9150_CONTROL_C,
> > +			DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
> > +}
> > +
> > +MODULE_DESCRIPTION("MFD Core Driver for DA9150");
> > +MODULE_AUTHOR("Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/mfd/da9150-i2c.c b/drivers/mfd/da9150-i2c.c
> > new file mode 100644
> > index 0000000..a02525c
> > --- /dev/null
> > +++ b/drivers/mfd/da9150-i2c.c
> > @@ -0,0 +1,176 @@
> > +/*
> > + * DA9150 I2C Driver
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > + *
> > + * This program is free software; you can redistribute  it and/or modify it
> > + * under  the terms of  the GNU General  Public License as published by the
> > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > + * option) any later version.
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/i2c.h>
> > +#include <linux/regmap.h>
> > +#include <linux/slab.h>
> > +
> 
> Remove this line.

Ok.

> 
> > +#include <linux/mfd/da9150/core.h>
> > +#include <linux/mfd/da9150/registers.h>
> > +
> > +static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
> > +{
> > +	switch (reg) {
> > +	case DA9150_PAGE_CON:
> > +	case DA9150_STATUS_A:
> > +	case DA9150_STATUS_B:
> > +	case DA9150_STATUS_C:
> > +	case DA9150_STATUS_D:
> > +	case DA9150_STATUS_E:
> > +	case DA9150_STATUS_F:
> > +	case DA9150_STATUS_G:
> > +	case DA9150_STATUS_H:
> > +	case DA9150_STATUS_I:
> > +	case DA9150_STATUS_J:
> > +	case DA9150_STATUS_K:
> > +	case DA9150_STATUS_L:
> > +	case DA9150_STATUS_N:
> > +	case DA9150_FAULT_LOG_A:
> > +	case DA9150_FAULT_LOG_B:
> > +	case DA9150_EVENT_E:
> > +	case DA9150_EVENT_F:
> > +	case DA9150_EVENT_G:
> > +	case DA9150_EVENT_H:
> > +	case DA9150_CONTROL_B:
> > +	case DA9150_CONTROL_C:
> > +	case DA9150_GPADC_MAN:
> > +	case DA9150_GPADC_RES_A:
> > +	case DA9150_GPADC_RES_B:
> > +	case DA9150_ADETVB_CFG_C:
> > +	case DA9150_ADETD_STAT:
> > +	case DA9150_ADET_CMPSTAT:
> > +	case DA9150_ADET_CTRL_A:
> > +	case DA9150_PPR_TCTR_B:
> > +	case DA9150_COREBTLD_STAT_A:
> > +	case DA9150_CORE_DATA_A:
> > +	case DA9150_CORE_DATA_B:
> > +	case DA9150_CORE_DATA_C:
> > +	case DA9150_CORE_DATA_D:
> > +	case DA9150_CORE2WIRE_STAT_A:
> > +	case DA9150_FW_CTRL_C:
> > +	case DA9150_FG_CTRL_B:
> > +	case DA9150_FW_CTRL_B:
> > +	case DA9150_GPADC_CMAN:
> > +	case DA9150_GPADC_CRES_A:
> > +	case DA9150_GPADC_CRES_B:
> > +	case DA9150_CC_ICHG_RES_A:
> > +	case DA9150_CC_ICHG_RES_B:
> > +	case DA9150_CC_IAVG_RES_A:
> > +	case DA9150_CC_IAVG_RES_B:
> > +	case DA9150_TAUX_CTRL_A:
> > +	case DA9150_TAUX_VALUE_H:
> > +	case DA9150_TAUX_VALUE_L:
> > +	case DA9150_TBAT_RES_A:
> > +	case DA9150_TBAT_RES_B:
> > +		return true;
> > +	default:
> > +		return false;
> > +	}
> > +}
> > +
> > +static const struct regmap_range_cfg da9150_range_cfg[] = {
> > +	{
> > +		.range_min = DA9150_PAGE_CON,
> > +		.range_max = DA9150_TBAT_RES_B,
> > +		.selector_reg = DA9150_PAGE_CON,
> > +		.selector_mask = DA9150_I2C_PAGE_MASK,
> > +		.selector_shift = DA9150_I2C_PAGE_SHIFT,
> > +		.window_start = 0,
> > +		.window_len = 256,
> > +	},
> > +};
> > +
> > +static struct regmap_config da9150_regmap_config = {
> > +	.reg_bits = 8,
> > +	.val_bits = 8,
> > +	.ranges = da9150_range_cfg,
> > +	.num_ranges = ARRAY_SIZE(da9150_range_cfg),
> > +	.max_register = DA9150_TBAT_RES_B,
> > +
> > +	.cache_type = REGCACHE_RBTREE,
> > +
> > +	.volatile_reg = da9150_volatile_reg,
> > +};
> > +
> > +static int da9150_probe(struct i2c_client *client,
> > +			const struct i2c_device_id *id)
> > +{
> > +	struct da9150 *da9150;
> > +	int ret;
> > +
> > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> 
> sizeof(*da9150)

Same difference, but ok.

> 
> > +	if (da9150 == NULL)
> 
> if (!da9150)

Right, fine.

> 
> > +		return -ENOMEM;
> 
> '\n'

Right, fine.

> 
> > +	da9150->dev = &client->dev;
> > +	da9150->irq = client->irq;
> > +	i2c_set_clientdata(client, da9150);
> > +	dev_set_drvdata(da9150->dev, da9150);
> 
> Why do you need this in both locations?
> 

Don't. Will remove accordingly.

> > +	da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
> > +	if (IS_ERR(da9150->regmap)) {
> > +		ret = PTR_ERR(da9150->regmap);
> > +		dev_err(da9150->dev, "Failed to allocate register map: %d\n",
> > +			ret);
> > +		return ret;
> > +	}
> > +
> > +	return da9150_device_init(da9150);
> > +}
> > +
> > +static int da9150_remove(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_exit(da9150);
> > +
> > +	return 0;
> > +}
> > +
> > +static void da9150_shutdown(struct i2c_client *client)
> > +{
> > +	struct da9150 *da9150 = i2c_get_clientdata(client);
> > +
> > +	da9150_device_shutdown(da9150);
> > +}
> > +
> > +static const struct i2c_device_id da9150_i2c_id[] = {
> > +	{ "da9150", 0 },
> 
> I don't see the .id parameter being used, just leave it blank.

Ok, no problem.

> 
> > +	{ }
> > +};
> > +MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
> > +
> > +static const struct of_device_id da9150_of_match[] = {
> > +	{ .compatible = "dlg,da9150", },
> > +	{ }
> > +};
> 
> MODULE_DEVICE_TABLE(of, ...)
> 
> > +static struct i2c_driver da9150_driver = {
> > +	.driver	= {
> > +		.name	= "da9150",
> > +		.owner	= THIS_MODULE,
> 
> You can remove this line, it's taken care of for you elsewhere.

Yes, will remove.

> 
> > +		.of_match_table = of_match_ptr(da9150_of_match),
> > +	},
> > +	.probe		= da9150_probe,
> > +	.remove		= da9150_remove,
> > +	.shutdown	= da9150_shutdown,
> > +	.id_table	= da9150_i2c_id,
> > +};
> > +
> > +module_i2c_driver(da9150_driver);
> > +
> > +MODULE_DESCRIPTION("I2C Driver for DA9150");
> > +MODULE_AUTHOR("Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/mfd/da9150/core.h b/include/linux/mfd/da9150/core.h
> > new file mode 100644
> > index 0000000..d23c500
> > --- /dev/null
> > +++ b/include/linux/mfd/da9150/core.h
> > @@ -0,0 +1,80 @@
> > +/*
> > + * DA9150 MFD Driver - Core Data
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> > + */
> > +
> > +#ifndef __DA9150_CORE_H
> > +#define __DA9150_CORE_H
> > +
> > +#include <linux/device.h>
> > +#include <linux/i2c.h>
> 
> What's this used for?
> 
> > +#include <linux/interrupt.h>
> > +#include <linux/regmap.h>
> > +#include <linux/mutex.h>
> > +
> > +/* I2C address paging */
> > +#define DA9150_REG_PAGE_SHIFT	8
> > +#define DA9150_REG_PAGE_MASK	0xFF
> > +
> > +/* IRQs */
> > +#define DA9150_NUM_IRQ_REGS	4
> > +#define DA9150_IRQ_VBUS		0
> > +#define DA9150_IRQ_CHG		1
> > +#define DA9150_IRQ_TCLASS	2
> > +#define DA9150_IRQ_TJUNC	3
> > +#define DA9150_IRQ_VFAULT	4
> > +#define DA9150_IRQ_CONF		5
> > +#define DA9150_IRQ_DAT		6
> > +#define DA9150_IRQ_DTYPE	7
> > +#define DA9150_IRQ_ID		8
> > +#define DA9150_IRQ_ADP		9
> > +#define DA9150_IRQ_SESS_END	10
> > +#define DA9150_IRQ_SESS_VLD	11
> > +#define DA9150_IRQ_FG		12
> > +#define DA9150_IRQ_GP		13
> > +#define DA9150_IRQ_TBAT		14
> > +#define DA9150_IRQ_GPIOA	15
> > +#define DA9150_IRQ_GPIOB	16
> > +#define DA9150_IRQ_GPIOC	17
> > +#define DA9150_IRQ_GPIOD	18
> > +#define DA9150_IRQ_GPADC	19
> > +#define DA9150_IRQ_WKUP		20
> > +
> > +struct da9150 {
> > +	struct device *dev;
> > +
> > +	struct regmap *regmap;
> > +
> 
> Why the '\n's?

Personal preference, but will remove.

> 
> > +	struct regmap_irq_chip_data *regmap_irq_data;
> > +	int irq;
> > +	int irq_base;
> > +};
> > +
> > +/* Device I/O */
> > +u8 da9150_reg_read(struct da9150 *da9150, u16 reg);
> > +int da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val);
> > +int da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val);
> > +
> > +int da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf);
> > +int da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf);
> > +
> > +/* IRQ helper functions */
> > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > +			irq_handler_t handler, const char *name);
> > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > +			const char *name);
> 
> I'm not sure why any of these 7 functions are required.

Clarified my intentions in previous comments.

> 
> > +/* Init/Exit */
> > +int da9150_device_init(struct da9150 *da9150);
> > +void da9150_device_exit(struct da9150 *da9150);
> > +void da9150_device_shutdown(struct da9150 *da9150);
> > +
> > +#endif /* __DA9150_CORE_H */
> > diff --git a/include/linux/mfd/da9150/pdata.h b/include/linux/mfd/da9150/pdata.h
> > new file mode 100644
> > index 0000000..e2b37f1
> > --- /dev/null
> > +++ b/include/linux/mfd/da9150/pdata.h
> > @@ -0,0 +1,21 @@
> > +/*
> > + * DA9150 MFD Driver - Platform Data
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> > + */
> > +
> > +#ifndef __DA9150_PDATA_H
> > +#define __DA9150_PDATA_H
> > +
> > +struct da9150_pdata {
> > +	int irq_base;
> > +};
> 
> Just put this in core.h and do away witht this header file.

The reason for this is that I will add more platform data items later with
subsequent submissions for additional features. It felt cleaner to separate out
these structures than throw it in the core.h header. However if it's going to
be a problem I'll fold this into core.h

> 
> > +#endif /* __DA9150_PDATA_H */
> > diff --git a/include/linux/mfd/da9150/registers.h
> b/include/linux/mfd/da9150/registers.h
> > new file mode 100644
> > index 0000000..ef4826d
> > --- /dev/null
> > +++ b/include/linux/mfd/da9150/registers.h
> > @@ -0,0 +1,1153 @@
> > +/*
> > + * DA9150 MFD Driver - Registers
> > + *
> > + * Copyright (c) 2014 Dialog Semiconductor
> > + *
> > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.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.
> > + */
> > +
> > +#ifndef __DA9150_REGISTERS_H
> > +#define __DA9150_REGISTERS_H
> > +
> > +/* Registers */
> 
> [...]
> 
> > +/* DA9150_CONTROL_A = 0x0E5 */
> > +#define DA9150_VDD33_SL_SHIFT			0
> > +#define DA9150_VDD33_SL_MASK			(0x01 << 0)
> > +#define DA9150_VDD33_LPM_SHIFT			1
> > +#define DA9150_VDD33_LPM_MASK			(0x03 << 1)
> > +#define DA9150_VDD33_EN_SHIFT			3
> > +#define DA9150_VDD33_EN_MASK			(0x01 << 3)
> > +#define DA9150_GPI_LPM_SHIFT			6
> > +#define DA9150_GPI_LPM_MASK			(0x01 << 6)
> > +#define DA9150_PM_IF_LPM_SHIFT			7
> > +#define DA9150_PM_IF_LPM_MASK			(0x01 << 7)
> > +
> > +/* DA9150_CONTROL_B = 0x0E6 */
> > +#define DA9150_LPM_SHIFT			0
> > +#define DA9150_LPM_MASK				(0x01 << 0)
> > +#define DA9150_RESET_SHIFT			1
> > +#define DA9150_RESET_MASK			(0x01 << 1)
> > +#define DA9150_RESET_USRCONF_EN_SHIFT		2
> > +#define DA9150_RESET_USRCONF_EN_MASK		(0x01 << 2)
> > +
> > +/* DA9150_CONTROL_C = 0x0E7 */
> > +#define DA9150_DISABLE_SHIFT			0
> > +#define DA9150_DISABLE_MASK			(0x01 << 0)
> 
> Use BIT() for all of these (1 << X) macros.

OK, will do.

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

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-09 10:37       ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:37 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

T24gQXVndXN0IDI4LCAyMDE0IDE3OjM2LCBMZWUgSm9uZXMgd3JvdGU6DQoNClRoYW5rcyBmb3Ig
dGhlIGZlZWRiYWNrLiBBcyBhIGdlbmVyYWwgY29tbWVudCBhIGNvdXBsZSBvZiB0aGUgaXRlbXMg
eW91J3ZlDQppZGVudGlmaWVkIHJlbGF0ZSB0byBmdXR1cmUgdXBkYXRlcyAoYWRkaXRpb25hbCBm
dW5jdGlvbmFsaXR5IGJlaW5nIGFkZGVkKS4NCkkgYWxyZWFkeSBoYXZlIGNvZGUgaW4gcGxhY2Ug
Zm9yIHRoaXMgYnV0IGhhdmUgc3RyaXBwZWQgb3V0IGEgY291cGxlIG9mIHRoZQ0KZHJpdmVycyBq
dXN0IHRvIHJlZHVjZSB0aGUgY2h1cm4gYW5kIHNpemUgb2YgcGF0Y2ggc3VibWlzc2lvbi4gVGhl
c2Ugd2lsbCBiZQ0KYWRkZWQgb25jZSB0aGVzZSBwYXRjaGVzIGhhdmUgYmVlbiBhY2NlcHRlZC4N
Cg0KV2hlcmUgdGhpcyBpcyB0aGUgY2FzZSwgSSBoYXZlIGFkZGVkIG5vdGVzIGluLWxpbmUgYWdh
aW5zdCB0aGUgcmVsZXZhbnQNCmNvbW1lbnRzIHlvdSBtYWRlLg0KDQo+IE9uIFRodSwgMjggQXVn
IDIwMTQsIEFkYW0gVGhvbXNvbiB3cm90ZToNCj4gDQo+ID4gREE5MTUwIGlzIGEgY29tYmluZWQg
Q2hhcmdlciBhbmQgRnVlbC1HYXVnZSBJQywgd2l0aCBhZGRpdGlvbmFsDQo+ID4gR1BJTyBhbmQg
R1BBREMgZnVuY3Rpb25hbGl0eS4NCj4gPg0KPiA+IFNpZ25lZC1vZmYtYnk6IEFkYW0gVGhvbXNv
biA8QWRhbS5UaG9tc29uLk9wZW5zb3VyY2VAZGlhc2VtaS5jb20+DQo+ID4gLS0tDQo+ID4gIGRy
aXZlcnMvbWZkL0tjb25maWcgICAgICAgICAgICAgICAgICB8ICAgMTIgKw0KPiA+ICBkcml2ZXJz
L21mZC9NYWtlZmlsZSAgICAgICAgICAgICAgICAgfCAgICAyICsNCj4gPiAgZHJpdmVycy9tZmQv
ZGE5MTUwLWNvcmUuYyAgICAgICAgICAgIHwgIDMzMiArKysrKysrKysrDQo+ID4gIGRyaXZlcnMv
bWZkL2RhOTE1MC1pMmMuYyAgICAgICAgICAgICB8ICAxNzYgKysrKysrDQo+IA0KPiBEbyB5b3Ug
YWxzbyBoYXZlIGFub3RoZXIsIHNheSBTUEkgdmVyc2lvbj8NCg0KTm8sIG5vdCB5ZXQsIGJ1dCB0
aGlzIGlzIHNvbWV0aGluZyB0aGF0IHdlIG1heSBhZGQgbGF0ZXIgYXMgdGhlIGRldmljZSBkb2Vz
DQpzdXBwb3J0IFNQSS4NCg0KPiANCj4gPiAgaW5jbHVkZS9saW51eC9tZmQvZGE5MTUwL2NvcmUu
aCAgICAgIHwgICA4MCArKysNCj4gPiAgaW5jbHVkZS9saW51eC9tZmQvZGE5MTUwL3BkYXRhLmgg
ICAgIHwgICAyMSArDQo+ID4gIGluY2x1ZGUvbGludXgvbWZkL2RhOTE1MC9yZWdpc3RlcnMuaCB8
IDExNTMNCj4gKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKw0KPiA+ICA3IGZpbGVz
IGNoYW5nZWQsIDE3NzYgaW5zZXJ0aW9ucygrKQ0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJp
dmVycy9tZmQvZGE5MTUwLWNvcmUuYw0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9t
ZmQvZGE5MTUwLWkyYy5jDQo+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL2xpbnV4L21m
ZC9kYTkxNTAvY29yZS5oDQo+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL2xpbnV4L21m
ZC9kYTkxNTAvcGRhdGEuaA0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgaW5jbHVkZS9saW51eC9t
ZmQvZGE5MTUwL3JlZ2lzdGVycy5oDQo+ID4NCj4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9tZmQv
S2NvbmZpZyBiL2RyaXZlcnMvbWZkL0tjb25maWcNCj4gPiBpbmRleCBkZTVhYmYyLi43NmFkYjJj
IDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvbWZkL0tjb25maWcNCj4gPiArKysgYi9kcml2ZXJz
L21mZC9LY29uZmlnDQo+ID4gQEAgLTE4Myw2ICsxODMsMTggQEAgY29uZmlnIE1GRF9EQTkwNjMN
Cj4gPiAgCSAgQWRkaXRpb25hbCBkcml2ZXJzIG11c3QgYmUgZW5hYmxlZCBpbiBvcmRlciB0byB1
c2UgdGhlIGZ1bmN0aW9uYWxpdHkNCj4gPiAgCSAgb2YgdGhlIGRldmljZS4NCj4gPg0KPiA+ICtj
b25maWcgTUZEX0RBOTE1MA0KPiA+ICsJYm9vbCAiRGlhbG9nIFNlbWljb25kdWN0b3IgREE5MTUw
IENoYXJnZXIgRnVlbC1HYXVnZSBjaGlwIg0KPiANCj4gV2h5IGNhbid0IHRoaXMgYmUgYnVpbHQg
YXMgYSBtb2R1bGU/DQoNCk5vIHJlYXNvbi4gV2lsbCBjaGFuZ2UgaXQuDQoNCj4gDQo+ID4gKwlk
ZXBlbmRzIG9uIEkyQz15DQo+ID4gKwlzZWxlY3QgTUZEX0NPUkUNCj4gPiArCXNlbGVjdCBSRUdN
QVBfSTJDDQo+ID4gKwlzZWxlY3QgUkVHTUFQX0lSUQ0KPiA+ICsJaGVscA0KPiA+ICsJICBUaGlz
IGFkZHMgc3VwcG9ydCBmb3IgdGhlIERBOTE1MCBpbnRlZ3JhdGVkIGNoYXJnZXIgYW5kIGZ1ZWwt
Z2F1Z2UNCj4gPiArCSAgY2hpcC4gVGhpcyBkcml2ZXIgcHJvdmlkZXMgY29tbW9uIHN1cHBvcnQg
Zm9yIGFjY2Vzc2luZyB0aGUgZGV2aWNlLg0KPiA+ICsJICBBZGRpdGlvbmFsIGRyaXZlcnMgbXVz
dCBiZSBlbmFibGVkIGluIG9yZGVyIHRvIHVzZSB0aGUgc3BlY2lmaWMNCj4gPiArCSAgZmVhdHVy
ZXMgb2YgdGhlIGRldmljZS4NCj4gPiArDQo+ID4gIGNvbmZpZyBNRkRfTUMxM1hYWA0KPiA+ICAJ
dHJpc3RhdGUNCj4gPiAgCWRlcGVuZHMgb24gKFNQSV9NQVNURVIgfHwgSTJDKQ0KPiA+IGRpZmYg
LS1naXQgYS9kcml2ZXJzL21mZC9NYWtlZmlsZSBiL2RyaXZlcnMvbWZkL01ha2VmaWxlDQo+ID4g
aW5kZXggZjAwMTQ4Ny4uMDk4ZGZhMSAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL21mZC9NYWtl
ZmlsZQ0KPiA+ICsrKyBiL2RyaXZlcnMvbWZkL01ha2VmaWxlDQo+ID4gQEAgLTExNCw2ICsxMTQs
OCBAQCBvYmotJChDT05GSUdfTUZEX0RBOTA1NSkJKz0gZGE5MDU1Lm8NCj4gPiAgZGE5MDYzLW9i
anMJCQk6PSBkYTkwNjMtY29yZS5vIGRhOTA2My1pcnEubyBkYTkwNjMtaTJjLm8NCj4gPiAgb2Jq
LSQoQ09ORklHX01GRF9EQTkwNjMpCSs9IGRhOTA2My5vDQo+ID4NCj4gPiArb2JqLSQoQ09ORklH
X01GRF9EQTkxNTApCSs9IGRhOTE1MC1jb3JlLm8gZGE5MTUwLWkyYy5vDQo+ID4gKw0KPiANCj4g
RG8gdGhlIG90aGVyIGRyaXZlcnMgc21lbGw/ICBQbGVhc2UgYnV0dCB1cCBhZ2FpbnN0IHRoZW0u
DQo+IA0KPiBJJ20gbm90IGVudGlyZWx5IHN1cmUgd2h5IHRoZXJlIGFyZSBzbyBtYW55ICdcbidz
IGluIHRoZSBNYWtlZmlsZSENCg0KT2tleSBkb2tleS4gV2lsbCBjaGFuZ2UuDQoNCj4gDQo+ID4g
IG9iai0kKENPTkZJR19NRkRfTUFYMTQ1NzcpCSs9IG1heDE0NTc3Lm8NCj4gPiAgb2JqLSQoQ09O
RklHX01GRF9NQVg3NzY4NikJKz0gbWF4Nzc2ODYubw0KPiA+ICBvYmotJChDT05GSUdfTUZEX01B
WDc3NjkzKQkrPSBtYXg3NzY5My5vDQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbWZkL2RhOTE1
MC1jb3JlLmMgYi9kcml2ZXJzL21mZC9kYTkxNTAtY29yZS5jDQo+ID4gbmV3IGZpbGUgbW9kZSAx
MDA2NDQNCj4gPiBpbmRleCAwMDAwMDAwLi4wMjlhMzBiDQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+
ICsrKyBiL2RyaXZlcnMvbWZkL2RhOTE1MC1jb3JlLmMNCj4gPiBAQCAtMCwwICsxLDMzMiBAQA0K
PiA+ICsvKg0KPiA+ICsgKiBEQTkxNTAgQ29yZSBNRkQgRHJpdmVyDQo+ID4gKyAqDQo+ID4gKyAq
IENvcHlyaWdodCAoYykgMjAxNCBEaWFsb2cgU2VtaWNvbmR1Y3Rvcg0KPiA+ICsgKg0KPiA+ICsg
KiBBdXRob3I6IEFkYW0gVGhvbXNvbiA8QWRhbS5UaG9tc29uLk9wZW5zb3VyY2VAZGlhc2VtaS5j
b20+DQo+ID4gKyAqDQo+ID4gKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3Ug
Y2FuIHJlZGlzdHJpYnV0ZSAgaXQgYW5kL29yIG1vZGlmeSBpdA0KPiA+ICsgKiB1bmRlciAgdGhl
IHRlcm1zIG9mICB0aGUgR05VIEdlbmVyYWwgIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBi
eSB0aGUNCj4gPiArICogRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyAgZWl0aGVyIHZlcnNpb24g
MiBvZiB0aGUgIExpY2Vuc2UsIG9yIChhdCB5b3VyDQo+ID4gKyAqIG9wdGlvbikgYW55IGxhdGVy
IHZlcnNpb24uDQo+ID4gKyAqLw0KPiA+ICsNCj4gPiArI2luY2x1ZGUgPGxpbnV4L2tlcm5lbC5o
Pg0KPiA+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9w
bGF0Zm9ybV9kZXZpY2UuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4NCj4gPiArI2lu
Y2x1ZGUgPGxpbnV4L2lycS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvaW50ZXJydXB0Lmg+DQo+
ID4gKyNpbmNsdWRlIDxsaW51eC9tZmQvY29yZS5oPg0KPiA+ICsNCj4gDQo+IE5vIHJlYWwgbmVl
ZCBmb3IgdGhpcyAnXG4nLg0KDQpJIGNhbiBjaGFuZ2UgdGhpcywgYnV0IG15IHJlYXNvbiB3YXMg
dG8gc2VwYXJhdGUgY29tbW9uIGtlcm5lbCBpbmNsdWRlcyBmcm9tDQpkZXZpY2Ugc3BlY2lmaWMg
b25lcywgZm9yIHJlYWRhYmlsaXR5LiANCg0KPiANCj4gPiArI2luY2x1ZGUgPGxpbnV4L21mZC9k
YTkxNTAvY29yZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvbWZkL2RhOTE1MC9yZWdpc3RlcnMu
aD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L21mZC9kYTkxNTAvcGRhdGEuaD4NCj4gPiArDQo+ID4g
K3U4IGRhOTE1MF9yZWdfcmVhZChzdHJ1Y3QgZGE5MTUwICpkYTkxNTAsIHUxNiByZWcpDQo+ID4g
K3sNCj4gPiArCWludCB2YWwsIHJldDsNCj4gPiArDQo+ID4gKwlyZXQgPSByZWdtYXBfcmVhZChk
YTkxNTAtPnJlZ21hcCwgcmVnLCAmdmFsKTsNCj4gPiArCWlmIChyZXQgPCAwKQ0KPiANCj4gV2hh
dCBpZiByZXQgPiAwPyAgSXMgdGhhdCBhIGdvb2QgdGhpbmc/IDopDQo+IA0KPiBKdXN0ICdpZiAo
cmV0KScuDQoNCkZpbmUsIHdpbGwgY2hhbmdlLg0KDQo+IA0KPiA+ICsJCWRldl9lcnIoZGE5MTUw
LT5kZXYsICJGYWlsZWQgdG8gcmVhZCBmcm9tIHJlZyAweCV4OiAlZFxuIiwNCj4gPiArCQkJcmVn
LCByZXQpOw0KPiA+ICsNCj4gPiArCXJldHVybiAodTgpIHZhbDsNCj4gPiArfQ0KPiA+ICtFWFBP
UlRfU1lNQk9MX0dQTChkYTkxNTBfcmVnX3JlYWQpOw0KPiANCj4gTm90IHN1cmUgSSBsaWtlIHRo
aXMgYWJzdHJhY3Rpb24gc3R1ZmYuICBJIGNvdWxkIHVuZGVyc3RhbmQgaWYgdGhlcmUNCj4gd2Vy
ZSBsb2NraW5nIGludm9sdmVkLCBidXQgdGhlcmUgaXNuJ3QuICBZb3UgZG9uJ3QgYXBwZWFyIHRv
IGNoZWNrIGZvcg0KPiBlcnJvcnMgaW4gdGhlIHN1Ym9yZGluYXRlIGRyaXZlcnMgZWl0aGVyLCBy
YXRoZXIgeW91IGp1c3QgcGxvdWdoIG9uDQo+IGFoZWFkLiAgTm90IHN1cmUgdGhhdCdzIGEgZ29v
ZCBpZGVhIGVpdGhlci4NCj4gDQo+IEFueW9uZSBoYXZlIGEgc2Vjb25kIG9waW5pb24/DQoNClRo
ZSByZWFzb24gZm9yIHRoZXNlIGlzIGJlY2F1c2UgZnV0dXJlIHBhdGNoZXMgdG8gYWRkIGFkZGl0
aW9uYWwgZnVuY3Rpb25hbGl0eQ0Kd2lsbCBpbnRyb2R1Y2UgSTJDIGFjY2VzcyBmdW5jdGlvbnMg
d2hpY2ggZG8gbm90IHVzZSByZWdtYXAgYW5kIGFjY2VzcyB0aGUNCmRldmljZSB2aWEgYSBzZXBh
cmF0ZSBJMkMgYWRkcmVzcyBmb3IgdGhpcyBwdXJwb3NlLiBJIHdpbGwgbmVlZCB0byBwcm92aWRl
DQphY2Nlc3MgZnVuY3Rpb25zIGZvciB0aGF0LCBhbmQgc28gaGF2aW5nIGEgY29tbW9uIHN0eWxl
IG9mIEkyQyBhY2Nlc3MgbWFrZXMNCnNlbnNlIGZvciB0aGlzIGRyaXZlci4gTWVhbnMgYW55IGFj
Y2VzcyBqdXN0IG5lZWRzIHRvIHByb3ZpZGUgdGhlIE1GRCBwcml2YXRlDQpkYXRhLCBhbmQgdGhl
IHJlbGV2YW50IGZ1bmN0aW9ucyB0YWtlIGNhcmUgb2YgdGhlIHJlc3QuIEkgdGhpbmsgdGhpcyBp
cyBjbGVhbmVyDQppbiB0aGlzIGluc3RhbmNlLg0KDQpXaXRoIHJlZ2FyZHMgdG8gZXJyb3JzLCBp
ZiB3ZSdyZSBzZWVpbmcgcHJvYmxlbXMgb24gSTJDIEkgZG9uJ3QgYmVsaWV2ZSBkZWFsaW5nDQp3
aXRoIHRoZSBlcnJvcnMgZWxzZXdoZXJlIGlzIGdvaW5nIHRvIGhlbHAgbXVjaC4gSSB3YW50ZWQg
dG8gcHJvdmlkZSBsb2dnaW5nDQp0aG91Z2ggaW4gY2FzZSB0aGlzIGlzIHNlZW4gZm9yIHNvbWUg
cmVhc29uLiBIb3dldmVyIEkgY291bGQganVzdCBtYWtlIHRoZXNlDQpmdW5jdGlvbnMgdm9pZCBy
ZXR1cm4gYXMgeW91J3JlIHJpZ2h0IGluIHlvdXIgY29tbWVudHMgdGhhdCBubyBjaGVja2luZyBp
cyBkb25lDQplbHNld2hlcmUuDQoNCj4gDQo+ID4gK2ludCBkYTkxNTBfcmVnX3dyaXRlKHN0cnVj
dCBkYTkxNTAgKmRhOTE1MCwgdTE2IHJlZywgdTggdmFsKQ0KPiA+ICt7DQo+ID4gKwlpbnQgcmV0
Ow0KPiA+ICsNCj4gPiArCXJldCA9IHJlZ21hcF93cml0ZShkYTkxNTAtPnJlZ21hcCwgcmVnLCB2
YWwpOw0KPiA+ICsJaWYgKHJldCA8IDApDQo+ID4gKwkJZGV2X2VycihkYTkxNTAtPmRldiwgIkZh
aWxlZCB0byB3cml0ZSB0byByZWcgMHgleDogJWRcbiIsDQo+ID4gKwkJCXJlZywgcmV0KTsNCj4g
PiArDQo+ID4gKwlyZXR1cm4gcmV0Ow0KPiA+ICt9DQo+ID4gK0VYUE9SVF9TWU1CT0xfR1BMKGRh
OTE1MF9yZWdfd3JpdGUpOw0KPiANCj4gQmxhaC4NCj4gDQo+ID4gK2ludCBkYTkxNTBfc2V0X2Jp
dHMoc3RydWN0IGRhOTE1MCAqZGE5MTUwLCB1MTYgcmVnLCB1OCBtYXNrLCB1OCB2YWwpDQo+ID4g
K3sNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ICsJcmV0ID0gcmVnbWFwX3VwZGF0ZV9iaXRz
KGRhOTE1MC0+cmVnbWFwLCByZWcsIG1hc2ssIHZhbCk7DQo+ID4gKwlpZiAocmV0IDwgMCkNCj4g
PiArCQlkZXZfZXJyKGRhOTE1MC0+ZGV2LCAiRmFpbGVkIHRvIHNldCBiaXRzIGluIHJlZyAweCV4
OiAlZFxuIiwNCj4gPiArCQkJcmVnLCByZXQpOw0KPiA+ICsNCj4gPiArCXJldHVybiByZXQ7DQo+
ID4gK30NCj4gPiArRVhQT1JUX1NZTUJPTF9HUEwoZGE5MTUwX3NldF9iaXRzKTsNCj4gDQo+IEJs
YWguDQo+IA0KPiA+ICtpbnQgZGE5MTUwX2J1bGtfcmVhZChzdHJ1Y3QgZGE5MTUwICpkYTkxNTAs
IHUxNiByZWcsIGludCBjb3VudCwgdTggKmJ1ZikNCj4gPiArew0KPiA+ICsJaW50IHJldDsNCj4g
PiArDQo+ID4gKwlyZXQgPSByZWdtYXBfYnVsa19yZWFkKGRhOTE1MC0+cmVnbWFwLCByZWcsIGJ1
ZiwgY291bnQpOw0KPiA+ICsJaWYgKHJldCA8IDApDQo+ID4gKwkJZGV2X2VycihkYTkxNTAtPmRl
diwgIkZhaWxlZCB0byBidWxrIHJlYWQgZnJvbSByZWcgMHgleDogJWRcbiIsDQo+ID4gKwkJCXJl
ZywgcmV0KTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gcmV0Ow0KPiA+ICt9DQo+ID4gK0VYUE9SVF9T
WU1CT0xfR1BMKGRhOTE1MF9idWxrX3JlYWQpOw0KPiANCj4gQmxhaC4NCj4gDQo+ID4gK2ludCBk
YTkxNTBfYnVsa193cml0ZShzdHJ1Y3QgZGE5MTUwICpkYTkxNTAsIHUxNiByZWcsIGludCBjb3Vu
dCwgY29uc3QgdTggKmJ1ZikNCj4gPiArew0KPiA+ICsJaW50IHJldDsNCj4gPiArDQo+ID4gKwly
ZXQgPSByZWdtYXBfcmF3X3dyaXRlKGRhOTE1MC0+cmVnbWFwLCByZWcsIGJ1ZiwgY291bnQpOw0K
PiA+ICsJaWYgKHJldCA8IDApDQo+ID4gKwkJZGV2X2VycihkYTkxNTAtPmRldiwgIkZhaWxlZCB0
byBidWxrIHdyaXRlIHRvIHJlZyAweCV4ICVkXG4iLA0KPiA+ICsJCQlyZWcsIHJldCk7DQo+ID4g
Kw0KPiA+ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICtFWFBPUlRfU1lNQk9MX0dQTChkYTkx
NTBfYnVsa193cml0ZSk7DQo+IA0KPiBCbGFoLg0KPiANCj4gPiArc3RhdGljIHN0cnVjdCByZWdt
YXBfaXJxIGRhOTE1MF9pcnFzW10gPSB7DQo+ID4gKwlbREE5MTUwX0lSUV9WQlVTXSA9IHsNCj4g
PiArCQkucmVnX29mZnNldCA9IDAsDQo+ID4gKwkJLm1hc2sgPSBEQTkxNTBfRV9WQlVTX01BU0ss
DQo+ID4gKwl9LA0KPiA+ICsJW0RBOTE1MF9JUlFfQ0hHXSA9IHsNCj4gPiArCQkucmVnX29mZnNl
dCA9IDAsDQo+ID4gKwkJLm1hc2sgPSBEQTkxNTBfRV9DSEdfTUFTSywNCj4gPiArCX0sDQo+ID4g
KwlbREE5MTUwX0lSUV9UQ0xBU1NdID0gew0KPiA+ICsJCS5yZWdfb2Zmc2V0ID0gMCwNCj4gPiAr
CQkubWFzayA9IERBOTE1MF9FX1RDTEFTU19NQVNLLA0KPiA+ICsJfSwNCj4gPiArCVtEQTkxNTBf
SVJRX1RKVU5DXSA9IHsNCj4gPiArCQkucmVnX29mZnNldCA9IDAsDQo+ID4gKwkJLm1hc2sgPSBE
QTkxNTBfRV9USlVOQ19NQVNLLA0KPiA+ICsJfSwNCj4gPiArCVtEQTkxNTBfSVJRX1ZGQVVMVF0g
PSB7DQo+ID4gKwkJLnJlZ19vZmZzZXQgPSAwLA0KPiA+ICsJCS5tYXNrID0gREE5MTUwX0VfVkZB
VUxUX01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJW0RBOTE1MF9JUlFfQ09ORl0gPSB7DQo+ID4gKwkJ
LnJlZ19vZmZzZXQgPSAxLA0KPiA+ICsJCS5tYXNrID0gREE5MTUwX0VfQ09ORl9NQVNLLA0KPiA+
ICsJfSwNCj4gPiArCVtEQTkxNTBfSVJRX0RBVF0gPSB7DQo+ID4gKwkJLnJlZ19vZmZzZXQgPSAx
LA0KPiA+ICsJCS5tYXNrID0gREE5MTUwX0VfREFUX01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJW0RB
OTE1MF9JUlFfRFRZUEVdID0gew0KPiA+ICsJCS5yZWdfb2Zmc2V0ID0gMSwNCj4gPiArCQkubWFz
ayA9IERBOTE1MF9FX0RUWVBFX01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJW0RBOTE1MF9JUlFfSURd
ID0gew0KPiA+ICsJCS5yZWdfb2Zmc2V0ID0gMSwNCj4gPiArCQkubWFzayA9IERBOTE1MF9FX0lE
X01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJW0RBOTE1MF9JUlFfQURQXSA9IHsNCj4gPiArCQkucmVn
X29mZnNldCA9IDEsDQo+ID4gKwkJLm1hc2sgPSBEQTkxNTBfRV9BRFBfTUFTSywNCj4gPiArCX0s
DQo+ID4gKwlbREE5MTUwX0lSUV9TRVNTX0VORF0gPSB7DQo+ID4gKwkJLnJlZ19vZmZzZXQgPSAx
LA0KPiA+ICsJCS5tYXNrID0gREE5MTUwX0VfU0VTU19FTkRfTUFTSywNCj4gPiArCX0sDQo+ID4g
KwlbREE5MTUwX0lSUV9TRVNTX1ZMRF0gPSB7DQo+ID4gKwkJLnJlZ19vZmZzZXQgPSAxLA0KPiA+
ICsJCS5tYXNrID0gREE5MTUwX0VfU0VTU19WTERfTUFTSywNCj4gPiArCX0sDQo+ID4gKwlbREE5
MTUwX0lSUV9GR10gPSB7DQo+ID4gKwkJLnJlZ19vZmZzZXQgPSAyLA0KPiA+ICsJCS5tYXNrID0g
REE5MTUwX0VfRkdfTUFTSywNCj4gPiArCX0sDQo+ID4gKwlbREE5MTUwX0lSUV9HUF0gPSB7DQo+
ID4gKwkJLnJlZ19vZmZzZXQgPSAyLA0KPiA+ICsJCS5tYXNrID0gREE5MTUwX0VfR1BfTUFTSywN
Cj4gPiArCX0sDQo+ID4gKwlbREE5MTUwX0lSUV9UQkFUXSA9IHsNCj4gPiArCQkucmVnX29mZnNl
dCA9IDIsDQo+ID4gKwkJLm1hc2sgPSBEQTkxNTBfRV9UQkFUX01BU0ssDQo+ID4gKwl9LA0KPiA+
ICsJW0RBOTE1MF9JUlFfR1BJT0FdID0gew0KPiA+ICsJCS5yZWdfb2Zmc2V0ID0gMiwNCj4gPiAr
CQkubWFzayA9IERBOTE1MF9FX0dQSU9BX01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJW0RBOTE1MF9J
UlFfR1BJT0JdID0gew0KPiA+ICsJCS5yZWdfb2Zmc2V0ID0gMiwNCj4gPiArCQkubWFzayA9IERB
OTE1MF9FX0dQSU9CX01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJW0RBOTE1MF9JUlFfR1BJT0NdID0g
ew0KPiA+ICsJCS5yZWdfb2Zmc2V0ID0gMiwNCj4gPiArCQkubWFzayA9IERBOTE1MF9FX0dQSU9D
X01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJW0RBOTE1MF9JUlFfR1BJT0RdID0gew0KPiA+ICsJCS5y
ZWdfb2Zmc2V0ID0gMiwNCj4gPiArCQkubWFzayA9IERBOTE1MF9FX0dQSU9EX01BU0ssDQo+ID4g
Kwl9LA0KPiA+ICsJW0RBOTE1MF9JUlFfR1BBRENdID0gew0KPiA+ICsJCS5yZWdfb2Zmc2V0ID0g
MiwNCj4gPiArCQkubWFzayA9IERBOTE1MF9FX0dQQURDX01BU0ssDQo+ID4gKwl9LA0KPiA+ICsJ
W0RBOTE1MF9JUlFfV0tVUF0gPSB7DQo+ID4gKwkJLnJlZ19vZmZzZXQgPSAzLA0KPiA+ICsJCS5t
YXNrID0gREE5MTUwX0VfV0tVUF9NQVNLLA0KPiA+ICsJfSwNCj4gPiArfTsNCj4gPiArDQo+ID4g
K3N0YXRpYyBzdHJ1Y3QgcmVnbWFwX2lycV9jaGlwIGRhOTE1MF9yZWdtYXBfaXJxX2NoaXAgPSB7
DQo+ID4gKwkubmFtZSA9ICJkYTkxNTBfaXJxIiwNCj4gPiArCS5zdGF0dXNfYmFzZSA9IERBOTE1
MF9FVkVOVF9FLA0KPiA+ICsJLm1hc2tfYmFzZSA9IERBOTE1MF9JUlFfTUFTS19FLA0KPiA+ICsJ
LmFja19iYXNlID0gREE5MTUwX0VWRU5UX0UsDQo+ID4gKwkubnVtX3JlZ3MgPSBEQTkxNTBfTlVN
X0lSUV9SRUdTLA0KPiA+ICsJLmlycXMgPSBkYTkxNTBfaXJxcywNCj4gPiArCS5udW1faXJxcyA9
IEFSUkFZX1NJWkUoZGE5MTUwX2lycXMpLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArLyogSGVscGVy
IGZ1bmN0aW9ucyBmb3Igc3ViLWRldmljZXMgdG8gcmVxdWVzdC9mcmVlIElSUXMgKi8NCj4gPiAr
aW50IGRhOTE1MF9yZWdpc3Rlcl9pcnEoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldiwgdm9p
ZCAqZGV2X2lkLA0KPiA+ICsJCQlpcnFfaGFuZGxlcl90IGhhbmRsZXIsIGNvbnN0IGNoYXIgKm5h
bWUpDQo+ID4gK3sNCj4gPiArCWludCBpcnEsIHJldDsNCj4gPiArDQo+ID4gKwlpcnEgPSBwbGF0
Zm9ybV9nZXRfaXJxX2J5bmFtZShwZGV2LCBuYW1lKTsNCj4gPiArCWlmIChpcnEgPCAwKQ0KPiA+
ICsJCXJldHVybiBpcnE7DQo+ID4gKw0KPiA+ICsJcmV0ID0gZGV2bV9yZXF1ZXN0X3RocmVhZGVk
X2lycSgmcGRldi0+ZGV2LCBpcnEsIE5VTEwsIGhhbmRsZXIsDQo+ID4gKwkJCQkJSVJRRl9PTkVT
SE9ULCBuYW1lLCBkZXZfaWQpOw0KPiA+ICsJaWYgKHJldCkNCj4gPiArCQlkZXZfZXJyKCZwZGV2
LT5kZXYsICJGYWlsZWQgdG8gcmVxdWVzdCBJUlEgJWQ6ICVkXG4iLCBpcnEsIHJldCk7DQo+ID4g
Kw0KPiA+ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICtFWFBPUlRfU1lNQk9MX0dQTChkYTkx
NTBfcmVnaXN0ZXJfaXJxKTsNCj4gDQo+IFdoeSBkbyB0aGV5IG5lZWQgaGVscD8gIFdoYXQgcHJv
YmxlbSBkb2VzIGFkZGluZyB0aGVzZSBsYXllcnMgc29sdmU/DQoNCk1lYW5zIEkgZG9uJ3QgaGF2
ZSB0byBrZWVwIGFkZGluZyBwcmludCBlcnJvciBsaW5lcyBldmVyeXdoZXJlIGVsc2UgaWYgdGhp
cw0KZnVuY3Rpb24gdGFrZXMgY2FyZSBvZiBpdC4gVGhvdWdodCB0aGF0IHdvdWxkIGJlIGNsZWFu
ZXIuDQoNCj4gDQo+ID4gK3ZvaWQgZGE5MTUwX3JlbGVhc2VfaXJxKHN0cnVjdCBwbGF0Zm9ybV9k
ZXZpY2UgKnBkZXYsIHZvaWQgKmRldl9pZCwNCj4gPiArCQkgICAgICAgY29uc3QgY2hhciAqbmFt
ZSkNCj4gPiArew0KPiA+ICsJaW50IGlycTsNCj4gPiArDQo+ID4gKwlpcnEgPSBwbGF0Zm9ybV9n
ZXRfaXJxX2J5bmFtZShwZGV2LCBuYW1lKTsNCj4gPiArCWlmIChpcnEgPCAwKQ0KPiA+ICsJCXJl
dHVybjsNCj4gPiArDQo+ID4gKwlkZXZtX2ZyZWVfaXJxKCZwZGV2LT5kZXYsIGlycSwgZGV2X2lk
KTsNCj4gPiArfQ0KPiA+ICtFWFBPUlRfU1lNQk9MX0dQTChkYTkxNTBfcmVsZWFzZV9pcnEpOw0K
PiANCj4gRG8geW91IGV2ZXIgcmVsZWFzZSB0aGUgSVJRIGFuZCBub3QgdW5iaW5kIHRoZSBkcml2
ZXI/DQo+IA0KPiBBcmUgdGhlcmUgb3JkZXJpbmcgaXNzdWVzIGF0IHBsYXkgaGVyZT8NCj4gDQo+
IElmIG5vdCwgdGhlcmUncyBubyBuZWVkIHRvIGNvbmR1Y3QgYSBtYW51YWwgZnJlZS4NCg0KSW4g
dGhlIGNoYXJnZXIgZHJpdmVyLCBpbiB0aGUgcmVtb3ZlIGZ1bmN0aW9uIHRoZXJlIGlzIGEgbmVl
ZCBJIGJlbGlldmUgdG8NCmZyZWUgdGhlIElSUXMgYmVmb3JlIG90aGVyIGl0ZW1zIGFyZSBjbGVh
cmVkIHVwIChlLmcuIHBvd2VyX3N1cHBseSBjbGFzc2VzKSwNCnNvIHRoaXMgaXMgd2h5IEkgaGF2
ZSBhZGRlZCB0aGlzIGluIGhlcmUuDQoNCj4gDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgcmVzb3VyY2Ug
ZGE5MTUwX2dwYWRjX3Jlc291cmNlc1tdID0gew0KPiA+ICsJew0KPiA+ICsJCS5uYW1lID0gIkdQ
QURDIiwNCj4gPiArCQkuc3RhcnQgPSBEQTkxNTBfSVJRX0dQQURDLA0KPiA+ICsJCS5lbmQgPSBE
QTkxNTBfSVJRX0dQQURDLA0KPiA+ICsJCS5mbGFncyA9IElPUkVTT1VSQ0VfSVJRLA0KPiA+ICsJ
fSwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgcmVzb3VyY2UgZGE5MTUwX2No
YXJnZXJfcmVzb3VyY2VzW10gPSB7DQo+ID4gKwl7DQo+ID4gKwkJLm5hbWUgPSAiQ0hHX1NUQVRV
UyIsDQo+ID4gKwkJLnN0YXJ0ID0gREE5MTUwX0lSUV9DSEcsDQo+ID4gKwkJLmVuZCA9IERBOTE1
MF9JUlFfQ0hHLA0KPiA+ICsJCS5mbGFncyA9IElPUkVTT1VSQ0VfSVJRLA0KPiA+ICsJfSwNCj4g
PiArCXsNCj4gPiArCQkubmFtZSA9ICJDSEdfVEpVTkMiLA0KPiA+ICsJCS5zdGFydCA9IERBOTE1
MF9JUlFfVEpVTkMsDQo+ID4gKwkJLmVuZCA9IERBOTE1MF9JUlFfVEpVTkMsDQo+ID4gKwkJLmZs
YWdzID0gSU9SRVNPVVJDRV9JUlEsDQo+ID4gKwl9LA0KPiA+ICsJew0KPiA+ICsJCS5uYW1lID0g
IkNIR19WRkFVTFQiLA0KPiA+ICsJCS5zdGFydCA9IERBOTE1MF9JUlFfVkZBVUxULA0KPiA+ICsJ
CS5lbmQgPSBEQTkxNTBfSVJRX1ZGQVVMVCwNCj4gPiArCQkuZmxhZ3MgPSBJT1JFU09VUkNFX0lS
USwNCj4gPiArCX0sDQo+ID4gKwl7DQo+ID4gKwkJLm5hbWUgPSAiQ0hHX1ZCVVMiLA0KPiA+ICsJ
CS5zdGFydCA9IERBOTE1MF9JUlFfVkJVUywNCj4gPiArCQkuZW5kID0gREE5MTUwX0lSUV9WQlVT
LA0KPiA+ICsJCS5mbGFncyA9IElPUkVTT1VSQ0VfSVJRLA0KPiA+ICsJfSwNCj4gPiArfTsNCj4g
PiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgbWZkX2NlbGwgZGE5MTUwX2RldnNbXSA9IHsNCj4gPiAr
CXsNCj4gPiArCQkubmFtZSA9ICJkYTkxNTAtZ3BhZGMiLA0KPiA+ICsJCS5vZl9jb21wYXRpYmxl
ID0gImRsZyxkYTkxNTAtZ3BhZGMiLA0KPiA+ICsJCS5yZXNvdXJjZXMgPSBkYTkxNTBfZ3BhZGNf
cmVzb3VyY2VzLA0KPiA+ICsJCS5udW1fcmVzb3VyY2VzID0gQVJSQVlfU0laRShkYTkxNTBfZ3Bh
ZGNfcmVzb3VyY2VzKSwNCj4gPiArCX0sDQo+ID4gKwl7DQo+ID4gKwkJLm5hbWUgPSAiZGE5MTUw
LWNoYXJnZXIiLA0KPiA+ICsJCS5vZl9jb21wYXRpYmxlID0gImRsZyxkYTkxNTAtY2hhcmdlciIs
DQo+ID4gKwkJLnJlc291cmNlcyA9IGRhOTE1MF9jaGFyZ2VyX3Jlc291cmNlcywNCj4gPiArCQku
bnVtX3Jlc291cmNlcyA9IEFSUkFZX1NJWkUoZGE5MTUwX2NoYXJnZXJfcmVzb3VyY2VzKSwNCj4g
PiArCX0sDQo+ID4gK307DQo+ID4gKw0KPiA+ICtpbnQgZGE5MTUwX2RldmljZV9pbml0KHN0cnVj
dCBkYTkxNTAgKmRhOTE1MCkNCj4gPiArew0KPiA+ICsJc3RydWN0IGRhOTE1MF9wZGF0YSAqcGRh
dGEgPSBkYTkxNTAtPmRldi0+cGxhdGZvcm1fZGF0YTsNCj4gDQo+IGRldl9nZXRfcGxhdGRhdGEo
KQ0KDQpSaWdodCBoby4gV2lsbCB1cGRhdGUuDQoNCj4gDQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsN
Cj4gPiArCS8qIEhhbmRsZSBwbGF0Zm9ybSBkYXRhICovDQo+IA0KPiBUaGlzIGNvbW1lbnQgZG9l
c24ndCBhZGQgYW55dGhpbmcgLSB0aGUgY29kZSBpcyBjbGVhciBlbm91Z2guDQoNCk9rIHdpbGwg
c2NyYXAgdGhhdC4NCg0KPiANCj4gPiArCWlmIChwZGF0YSkNCj4gPiArCQlkYTkxNTAtPmlycV9i
YXNlID0gcGRhdGEtPmlycV9iYXNlOw0KPiA+ICsJZWxzZQ0KPiA+ICsJCWRhOTE1MC0+aXJxX2Jh
c2UgPSAtMTsNCj4gDQo+IHBkYXRhID8gcGRhdGEtPmlycV9iYXNlIDogLTE7DQoNClRoaXMgaXMg
bGVmdCB0aGlzIHdheSBhcyBsYXRlciB1cGRhdGVzIHRvIGFkZCBhZGRpdGlvbmFsIGZ1bmN0aW9u
YWxpdHkgd2lsbA0KcmVxdWlyZSBhZGR0aW9uYWwgd29yayB0byBiZSBkb25lIHdpdGggdGhlIHBs
YXRmb3JtIGRhdGEuIFNlZW1lZCBwb2ludGxlc3MNCmNoYW5naW5nIGl0IGhlcmUganVzdCB0byBj
aGFuZ2UgaXQgYmFjayBsYXRlci4NCg0KPiANCj4gPiArCS8qIEluaXQgSVJRcyAqLw0KPiANCj4g
Tm8gbmVlZCBmb3IgdGhlc2UsIHBsZWFzZSBvbmx5IGFkZCBjb21tZW50cyB3aGVyZSB0aGUgY29k
ZSBpcyBjb21wbGV4DQo+IG9yIGNvbnZvbHV0ZWQuDQoNCk9rLCB3aWxsIHJlbW92ZS4NCg0KPiAN
Cj4gPiArCXJldCA9IHJlZ21hcF9hZGRfaXJxX2NoaXAoZGE5MTUwLT5yZWdtYXAsIGRhOTE1MC0+
aXJxLA0KPiA+ICsJCQkJICBJUlFGX1RSSUdHRVJfTE9XIHwgSVJRRl9PTkVTSE9ULA0KPiA+ICsJ
CQkJICBkYTkxNTAtPmlycV9iYXNlLCAmZGE5MTUwX3JlZ21hcF9pcnFfY2hpcCwNCj4gPiArCQkJ
CSAgJmRhOTE1MC0+cmVnbWFwX2lycV9kYXRhKTsNCj4gPiArCWlmIChyZXQgPCAwKQ0KPiANCj4g
J2lmIChyZXQpJyB3aGVyZSBwb3NpdGl2ZSByZXBsaWVzIGFyZW4ndCBwb3NzaWJsZSBvciBhcmUg
ZXJyb3JzLg0KDQpPaywgZmluZS4NCg0KPiANCj4gPiArCQlnb3RvIGVycl9pcnE7DQo+IA0KPiBK
dXN0IHJldHVybiBoZXJlIGFuZCByZW1vdmUgJ2Vycl9pcnEnIGxhYmVsLg0KDQpZZXAsIHdpbGwg
dGlkeSB1cC4NCg0KPiANCj4gPiArCWRhOTE1MC0+aXJxX2Jhc2UgPSByZWdtYXBfaXJxX2NoaXBf
Z2V0X2Jhc2UoZGE5MTUwLT5yZWdtYXBfaXJxX2RhdGEpOw0KPiA+ICsNCj4gPiArCS8qIE1ha2Ug
dGhlIElSUSBsaW5lIGEgd2FrZSBzb3VyY2UgKi8NCj4gPiArCWVuYWJsZV9pcnFfd2FrZShkYTkx
NTAtPmlycSk7DQo+ID4gKw0KPiA+ICsJLyogQWRkIE1GRCBEZXZpY2VzICovDQo+ID4gKwlyZXQg
PSBtZmRfYWRkX2RldmljZXMoZGE5MTUwLT5kZXYsIC0xLCBkYTkxNTBfZGV2cywNCj4gPiArCQkJ
ICAgICAgQVJSQVlfU0laRShkYTkxNTBfZGV2cyksIE5VTEwsDQo+ID4gKwkJCSAgICAgIGRhOTE1
MC0+aXJxX2Jhc2UsIE5VTEwpOw0KPiA+ICsJaWYgKHJldCA8IDApIHsNCj4gPiArCQlkZXZfZXJy
KGRhOTE1MC0+ZGV2LCAiRmFpbGVkIHRvIGFkZCBjaGlsZCBkZXZpY2VzOiAlZFxuIiwgcmV0KTsN
Cj4gPiArCQlnb3RvIGVycl9tZmQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+
ID4gKw0KPiA+ICtlcnJfbWZkOg0KPiA+ICsJcmVnbWFwX2RlbF9pcnFfY2hpcChkYTkxNTAtPmly
cSwgZGE5MTUwLT5yZWdtYXBfaXJxX2RhdGEpOw0KPiA+ICtlcnJfaXJxOg0KPiA+ICsJcmV0dXJu
IHJldDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArdm9pZCBkYTkxNTBfZGV2aWNlX2V4aXQoc3RydWN0
IGRhOTE1MCAqZGE5MTUwKQ0KPiA+ICt7DQo+ID4gKwlyZWdtYXBfZGVsX2lycV9jaGlwKGRhOTE1
MC0+aXJxLCBkYTkxNTAtPnJlZ21hcF9pcnFfZGF0YSk7DQo+ID4gKwltZmRfcmVtb3ZlX2Rldmlj
ZXMoZGE5MTUwLT5kZXYpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICt2b2lkIGRhOTE1MF9kZXZpY2Vf
c2h1dGRvd24oc3RydWN0IGRhOTE1MCAqZGE5MTUwKQ0KPiA+ICt7DQo+ID4gKwkvKiBNYWtlIHN1
cmUgd2UgaGF2ZSBhIHdha3VwIHNvdXJjZSBmb3IgdGhlIGRldmljZSAqLw0KPiA+ICsJZGE5MTUw
X3NldF9iaXRzKGRhOTE1MCwgREE5MTUwX0NPTkZJR19ELA0KPiA+ICsJCQlEQTkxNTBfV0tVUF9Q
TV9FTl9NQVNLLA0KPiA+ICsJCQlEQTkxNTBfV0tVUF9QTV9FTl9NQVNLKTsNCj4gPiArDQo+ID4g
KwkvKiBTZXQgZGV2aWNlIHRvIERJU0FCTEVEIG1vZGUgKi8NCj4gPiArCWRhOTE1MF9zZXRfYml0
cyhkYTkxNTAsIERBOTE1MF9DT05UUk9MX0MsDQo+ID4gKwkJCURBOTE1MF9ESVNBQkxFX01BU0ss
IERBOTE1MF9ESVNBQkxFX01BU0spOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtNT0RVTEVfREVTQ1JJ
UFRJT04oIk1GRCBDb3JlIERyaXZlciBmb3IgREE5MTUwIik7DQo+ID4gK01PRFVMRV9BVVRIT1Io
IkFkYW0gVGhvbXNvbg0KPiA8QWRhbS5UaG9tc29uLk9wZW5zb3VyY2VAZGlhc2VtaS5jb20iKTsN
Cj4gPiArTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL21m
ZC9kYTkxNTAtaTJjLmMgYi9kcml2ZXJzL21mZC9kYTkxNTAtaTJjLmMNCj4gPiBuZXcgZmlsZSBt
b2RlIDEwMDY0NA0KPiA+IGluZGV4IDAwMDAwMDAuLmEwMjUyNWMNCj4gPiAtLS0gL2Rldi9udWxs
DQo+ID4gKysrIGIvZHJpdmVycy9tZmQvZGE5MTUwLWkyYy5jDQo+ID4gQEAgLTAsMCArMSwxNzYg
QEANCj4gPiArLyoNCj4gPiArICogREE5MTUwIEkyQyBEcml2ZXINCj4gPiArICoNCj4gPiArICog
Q29weXJpZ2h0IChjKSAyMDE0IERpYWxvZyBTZW1pY29uZHVjdG9yDQo+ID4gKyAqDQo+ID4gKyAq
IEF1dGhvcjogQWRhbSBUaG9tc29uIDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNv
bT4NCj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBj
YW4gcmVkaXN0cmlidXRlICBpdCBhbmQvb3IgbW9kaWZ5IGl0DQo+ID4gKyAqIHVuZGVyICB0aGUg
dGVybXMgb2YgIHRoZSBHTlUgR2VuZXJhbCAgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5
IHRoZQ0KPiA+ICsgKiBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247ICBlaXRoZXIgdmVyc2lvbiAy
IG9mIHRoZSAgTGljZW5zZSwgb3IgKGF0IHlvdXINCj4gPiArICogb3B0aW9uKSBhbnkgbGF0ZXIg
dmVyc2lvbi4NCj4gPiArICovDQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8bGludXgva2VybmVsLmg+
DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3Bs
YXRmb3JtX2RldmljZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvaTJjLmg+DQo+ID4gKyNpbmNs
dWRlIDxsaW51eC9yZWdtYXAuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4NCj4gPiAr
DQo+IA0KPiBSZW1vdmUgdGhpcyBsaW5lLg0KDQpPay4NCg0KPiANCj4gPiArI2luY2x1ZGUgPGxp
bnV4L21mZC9kYTkxNTAvY29yZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvbWZkL2RhOTE1MC9y
ZWdpc3RlcnMuaD4NCj4gPiArDQo+ID4gK3N0YXRpYyBib29sIGRhOTE1MF92b2xhdGlsZV9yZWco
c3RydWN0IGRldmljZSAqZGV2LCB1bnNpZ25lZCBpbnQgcmVnKQ0KPiA+ICt7DQo+ID4gKwlzd2l0
Y2ggKHJlZykgew0KPiA+ICsJY2FzZSBEQTkxNTBfUEFHRV9DT046DQo+ID4gKwljYXNlIERBOTE1
MF9TVEFUVVNfQToNCj4gPiArCWNhc2UgREE5MTUwX1NUQVRVU19COg0KPiA+ICsJY2FzZSBEQTkx
NTBfU1RBVFVTX0M6DQo+ID4gKwljYXNlIERBOTE1MF9TVEFUVVNfRDoNCj4gPiArCWNhc2UgREE5
MTUwX1NUQVRVU19FOg0KPiA+ICsJY2FzZSBEQTkxNTBfU1RBVFVTX0Y6DQo+ID4gKwljYXNlIERB
OTE1MF9TVEFUVVNfRzoNCj4gPiArCWNhc2UgREE5MTUwX1NUQVRVU19IOg0KPiA+ICsJY2FzZSBE
QTkxNTBfU1RBVFVTX0k6DQo+ID4gKwljYXNlIERBOTE1MF9TVEFUVVNfSjoNCj4gPiArCWNhc2Ug
REE5MTUwX1NUQVRVU19LOg0KPiA+ICsJY2FzZSBEQTkxNTBfU1RBVFVTX0w6DQo+ID4gKwljYXNl
IERBOTE1MF9TVEFUVVNfTjoNCj4gPiArCWNhc2UgREE5MTUwX0ZBVUxUX0xPR19BOg0KPiA+ICsJ
Y2FzZSBEQTkxNTBfRkFVTFRfTE9HX0I6DQo+ID4gKwljYXNlIERBOTE1MF9FVkVOVF9FOg0KPiA+
ICsJY2FzZSBEQTkxNTBfRVZFTlRfRjoNCj4gPiArCWNhc2UgREE5MTUwX0VWRU5UX0c6DQo+ID4g
KwljYXNlIERBOTE1MF9FVkVOVF9IOg0KPiA+ICsJY2FzZSBEQTkxNTBfQ09OVFJPTF9COg0KPiA+
ICsJY2FzZSBEQTkxNTBfQ09OVFJPTF9DOg0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfTUFOOg0K
PiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfUkVTX0E6DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19S
RVNfQjoNCj4gPiArCWNhc2UgREE5MTUwX0FERVRWQl9DRkdfQzoNCj4gPiArCWNhc2UgREE5MTUw
X0FERVREX1NUQVQ6DQo+ID4gKwljYXNlIERBOTE1MF9BREVUX0NNUFNUQVQ6DQo+ID4gKwljYXNl
IERBOTE1MF9BREVUX0NUUkxfQToNCj4gPiArCWNhc2UgREE5MTUwX1BQUl9UQ1RSX0I6DQo+ID4g
KwljYXNlIERBOTE1MF9DT1JFQlRMRF9TVEFUX0E6DQo+ID4gKwljYXNlIERBOTE1MF9DT1JFX0RB
VEFfQToNCj4gPiArCWNhc2UgREE5MTUwX0NPUkVfREFUQV9COg0KPiA+ICsJY2FzZSBEQTkxNTBf
Q09SRV9EQVRBX0M6DQo+ID4gKwljYXNlIERBOTE1MF9DT1JFX0RBVEFfRDoNCj4gPiArCWNhc2Ug
REE5MTUwX0NPUkUyV0lSRV9TVEFUX0E6DQo+ID4gKwljYXNlIERBOTE1MF9GV19DVFJMX0M6DQo+
ID4gKwljYXNlIERBOTE1MF9GR19DVFJMX0I6DQo+ID4gKwljYXNlIERBOTE1MF9GV19DVFJMX0I6
DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19DTUFOOg0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENf
Q1JFU19BOg0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ1JFU19COg0KPiA+ICsJY2FzZSBEQTkx
NTBfQ0NfSUNIR19SRVNfQToNCj4gPiArCWNhc2UgREE5MTUwX0NDX0lDSEdfUkVTX0I6DQo+ID4g
KwljYXNlIERBOTE1MF9DQ19JQVZHX1JFU19BOg0KPiA+ICsJY2FzZSBEQTkxNTBfQ0NfSUFWR19S
RVNfQjoNCj4gPiArCWNhc2UgREE5MTUwX1RBVVhfQ1RSTF9BOg0KPiA+ICsJY2FzZSBEQTkxNTBf
VEFVWF9WQUxVRV9IOg0KPiA+ICsJY2FzZSBEQTkxNTBfVEFVWF9WQUxVRV9MOg0KPiA+ICsJY2Fz
ZSBEQTkxNTBfVEJBVF9SRVNfQToNCj4gPiArCWNhc2UgREE5MTUwX1RCQVRfUkVTX0I6DQo+ID4g
KwkJcmV0dXJuIHRydWU7DQo+ID4gKwlkZWZhdWx0Og0KPiA+ICsJCXJldHVybiBmYWxzZTsNCj4g
PiArCX0NCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0IHN0cnVjdCByZWdtYXBfcmFu
Z2VfY2ZnIGRhOTE1MF9yYW5nZV9jZmdbXSA9IHsNCj4gPiArCXsNCj4gPiArCQkucmFuZ2VfbWlu
ID0gREE5MTUwX1BBR0VfQ09OLA0KPiA+ICsJCS5yYW5nZV9tYXggPSBEQTkxNTBfVEJBVF9SRVNf
QiwNCj4gPiArCQkuc2VsZWN0b3JfcmVnID0gREE5MTUwX1BBR0VfQ09OLA0KPiA+ICsJCS5zZWxl
Y3Rvcl9tYXNrID0gREE5MTUwX0kyQ19QQUdFX01BU0ssDQo+ID4gKwkJLnNlbGVjdG9yX3NoaWZ0
ID0gREE5MTUwX0kyQ19QQUdFX1NISUZULA0KPiA+ICsJCS53aW5kb3dfc3RhcnQgPSAwLA0KPiA+
ICsJCS53aW5kb3dfbGVuID0gMjU2LA0KPiA+ICsJfSwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0
YXRpYyBzdHJ1Y3QgcmVnbWFwX2NvbmZpZyBkYTkxNTBfcmVnbWFwX2NvbmZpZyA9IHsNCj4gPiAr
CS5yZWdfYml0cyA9IDgsDQo+ID4gKwkudmFsX2JpdHMgPSA4LA0KPiA+ICsJLnJhbmdlcyA9IGRh
OTE1MF9yYW5nZV9jZmcsDQo+ID4gKwkubnVtX3JhbmdlcyA9IEFSUkFZX1NJWkUoZGE5MTUwX3Jh
bmdlX2NmZyksDQo+ID4gKwkubWF4X3JlZ2lzdGVyID0gREE5MTUwX1RCQVRfUkVTX0IsDQo+ID4g
Kw0KPiA+ICsJLmNhY2hlX3R5cGUgPSBSRUdDQUNIRV9SQlRSRUUsDQo+ID4gKw0KPiA+ICsJLnZv
bGF0aWxlX3JlZyA9IGRhOTE1MF92b2xhdGlsZV9yZWcsDQo+ID4gK307DQo+ID4gKw0KPiA+ICtz
dGF0aWMgaW50IGRhOTE1MF9wcm9iZShzdHJ1Y3QgaTJjX2NsaWVudCAqY2xpZW50LA0KPiA+ICsJ
CQljb25zdCBzdHJ1Y3QgaTJjX2RldmljZV9pZCAqaWQpDQo+ID4gK3sNCj4gPiArCXN0cnVjdCBk
YTkxNTAgKmRhOTE1MDsNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ICsJZGE5MTUwID0gZGV2
bV9remFsbG9jKCZjbGllbnQtPmRldiwgc2l6ZW9mKHN0cnVjdCBkYTkxNTApLCBHRlBfS0VSTkVM
KTsNCj4gDQo+IHNpemVvZigqZGE5MTUwKQ0KDQpTYW1lIGRpZmZlcmVuY2UsIGJ1dCBvay4NCg0K
PiANCj4gPiArCWlmIChkYTkxNTAgPT0gTlVMTCkNCj4gDQo+IGlmICghZGE5MTUwKQ0KDQpSaWdo
dCwgZmluZS4NCg0KPiANCj4gPiArCQlyZXR1cm4gLUVOT01FTTsNCj4gDQo+ICdcbicNCg0KUmln
aHQsIGZpbmUuDQoNCj4gDQo+ID4gKwlkYTkxNTAtPmRldiA9ICZjbGllbnQtPmRldjsNCj4gPiAr
CWRhOTE1MC0+aXJxID0gY2xpZW50LT5pcnE7DQo+ID4gKwlpMmNfc2V0X2NsaWVudGRhdGEoY2xp
ZW50LCBkYTkxNTApOw0KPiA+ICsJZGV2X3NldF9kcnZkYXRhKGRhOTE1MC0+ZGV2LCBkYTkxNTAp
Ow0KPiANCj4gV2h5IGRvIHlvdSBuZWVkIHRoaXMgaW4gYm90aCBsb2NhdGlvbnM/DQo+IA0KDQpE
b24ndC4gV2lsbCByZW1vdmUgYWNjb3JkaW5nbHkuDQoNCj4gPiArCWRhOTE1MC0+cmVnbWFwID0g
ZGV2bV9yZWdtYXBfaW5pdF9pMmMoY2xpZW50LCAmZGE5MTUwX3JlZ21hcF9jb25maWcpOw0KPiA+
ICsJaWYgKElTX0VSUihkYTkxNTAtPnJlZ21hcCkpIHsNCj4gPiArCQlyZXQgPSBQVFJfRVJSKGRh
OTE1MC0+cmVnbWFwKTsNCj4gPiArCQlkZXZfZXJyKGRhOTE1MC0+ZGV2LCAiRmFpbGVkIHRvIGFs
bG9jYXRlIHJlZ2lzdGVyIG1hcDogJWRcbiIsDQo+ID4gKwkJCXJldCk7DQo+ID4gKwkJcmV0dXJu
IHJldDsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlyZXR1cm4gZGE5MTUwX2RldmljZV9pbml0KGRh
OTE1MCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgZGE5MTUwX3JlbW92ZShzdHJ1
Y3QgaTJjX2NsaWVudCAqY2xpZW50KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgZGE5MTUwICpkYTkx
NTAgPSBpMmNfZ2V0X2NsaWVudGRhdGEoY2xpZW50KTsNCj4gPiArDQo+ID4gKwlkYTkxNTBfZGV2
aWNlX2V4aXQoZGE5MTUwKTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsN
Cj4gPiArc3RhdGljIHZvaWQgZGE5MTUwX3NodXRkb3duKHN0cnVjdCBpMmNfY2xpZW50ICpjbGll
bnQpDQo+ID4gK3sNCj4gPiArCXN0cnVjdCBkYTkxNTAgKmRhOTE1MCA9IGkyY19nZXRfY2xpZW50
ZGF0YShjbGllbnQpOw0KPiA+ICsNCj4gPiArCWRhOTE1MF9kZXZpY2Vfc2h1dGRvd24oZGE5MTUw
KTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0IHN0cnVjdCBpMmNfZGV2aWNlX2lk
IGRhOTE1MF9pMmNfaWRbXSA9IHsNCj4gPiArCXsgImRhOTE1MCIsIDAgfSwNCj4gDQo+IEkgZG9u
J3Qgc2VlIHRoZSAuaWQgcGFyYW1ldGVyIGJlaW5nIHVzZWQsIGp1c3QgbGVhdmUgaXQgYmxhbmsu
DQoNCk9rLCBubyBwcm9ibGVtLg0KDQo+IA0KPiA+ICsJeyB9DQo+ID4gK307DQo+ID4gK01PRFVM
RV9ERVZJQ0VfVEFCTEUoaTJjLCBkYTkxNTBfaTJjX2lkKTsNCj4gPiArDQo+ID4gK3N0YXRpYyBj
b25zdCBzdHJ1Y3Qgb2ZfZGV2aWNlX2lkIGRhOTE1MF9vZl9tYXRjaFtdID0gew0KPiA+ICsJeyAu
Y29tcGF0aWJsZSA9ICJkbGcsZGE5MTUwIiwgfSwNCj4gPiArCXsgfQ0KPiA+ICt9Ow0KPiANCj4g
TU9EVUxFX0RFVklDRV9UQUJMRShvZiwgLi4uKQ0KPiANCj4gPiArc3RhdGljIHN0cnVjdCBpMmNf
ZHJpdmVyIGRhOTE1MF9kcml2ZXIgPSB7DQo+ID4gKwkuZHJpdmVyCT0gew0KPiA+ICsJCS5uYW1l
CT0gImRhOTE1MCIsDQo+ID4gKwkJLm93bmVyCT0gVEhJU19NT0RVTEUsDQo+IA0KPiBZb3UgY2Fu
IHJlbW92ZSB0aGlzIGxpbmUsIGl0J3MgdGFrZW4gY2FyZSBvZiBmb3IgeW91IGVsc2V3aGVyZS4N
Cg0KWWVzLCB3aWxsIHJlbW92ZS4NCg0KPiANCj4gPiArCQkub2ZfbWF0Y2hfdGFibGUgPSBvZl9t
YXRjaF9wdHIoZGE5MTUwX29mX21hdGNoKSwNCj4gPiArCX0sDQo+ID4gKwkucHJvYmUJCT0gZGE5
MTUwX3Byb2JlLA0KPiA+ICsJLnJlbW92ZQkJPSBkYTkxNTBfcmVtb3ZlLA0KPiA+ICsJLnNodXRk
b3duCT0gZGE5MTUwX3NodXRkb3duLA0KPiA+ICsJLmlkX3RhYmxlCT0gZGE5MTUwX2kyY19pZCwN
Cj4gPiArfTsNCj4gPiArDQo+ID4gK21vZHVsZV9pMmNfZHJpdmVyKGRhOTE1MF9kcml2ZXIpOw0K
PiA+ICsNCj4gPiArTU9EVUxFX0RFU0NSSVBUSU9OKCJJMkMgRHJpdmVyIGZvciBEQTkxNTAiKTsN
Cj4gPiArTU9EVUxFX0FVVEhPUigiQWRhbSBUaG9tc29uDQo+IDxBZGFtLlRob21zb24uT3BlbnNv
dXJjZUBkaWFzZW1pLmNvbSIpOw0KPiA+ICtNT0RVTEVfTElDRU5TRSgiR1BMIik7DQo+ID4gZGlm
ZiAtLWdpdCBhL2luY2x1ZGUvbGludXgvbWZkL2RhOTE1MC9jb3JlLmggYi9pbmNsdWRlL2xpbnV4
L21mZC9kYTkxNTAvY29yZS5oDQo+ID4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gPiBpbmRleCAw
MDAwMDAwLi5kMjNjNTAwDQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ICsrKyBiL2luY2x1ZGUvbGlu
dXgvbWZkL2RhOTE1MC9jb3JlLmgNCj4gPiBAQCAtMCwwICsxLDgwIEBADQo+ID4gKy8qDQo+ID4g
KyAqIERBOTE1MCBNRkQgRHJpdmVyIC0gQ29yZSBEYXRhDQo+ID4gKyAqDQo+ID4gKyAqIENvcHly
aWdodCAoYykgMjAxNCBEaWFsb2cgU2VtaWNvbmR1Y3Rvcg0KPiA+ICsgKg0KPiA+ICsgKiBBdXRo
b3I6IEFkYW0gVGhvbXNvbiA8QWRhbS5UaG9tc29uLk9wZW5zb3VyY2VAZGlhc2VtaS5jb20+DQo+
ID4gKyAqDQo+ID4gKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJl
ZGlzdHJpYnV0ZSAgaXQgYW5kL29yIG1vZGlmeSBpdA0KPiA+ICsgKiB1bmRlciAgdGhlIHRlcm1z
IG9mICB0aGUgR05VIEdlbmVyYWwgIFB1YmxpYyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUN
Cj4gPiArICogRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyAgZWl0aGVyIHZlcnNpb24gMiBvZiB0
aGUgIExpY2Vuc2UsIG9yIChhdCB5b3VyDQo+ID4gKyAqIG9wdGlvbikgYW55IGxhdGVyIHZlcnNp
b24uDQo+ID4gKyAqLw0KPiA+ICsNCj4gPiArI2lmbmRlZiBfX0RBOTE1MF9DT1JFX0gNCj4gPiAr
I2RlZmluZSBfX0RBOTE1MF9DT1JFX0gNCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxsaW51eC9kZXZp
Y2UuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L2kyYy5oPg0KPiANCj4gV2hhdCdzIHRoaXMgdXNl
ZCBmb3I/DQo+IA0KPiA+ICsjaW5jbHVkZSA8bGludXgvaW50ZXJydXB0Lmg+DQo+ID4gKyNpbmNs
dWRlIDxsaW51eC9yZWdtYXAuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L211dGV4Lmg+DQo+ID4g
Kw0KPiA+ICsvKiBJMkMgYWRkcmVzcyBwYWdpbmcgKi8NCj4gPiArI2RlZmluZSBEQTkxNTBfUkVH
X1BBR0VfU0hJRlQJOA0KPiA+ICsjZGVmaW5lIERBOTE1MF9SRUdfUEFHRV9NQVNLCTB4RkYNCj4g
PiArDQo+ID4gKy8qIElSUXMgKi8NCj4gPiArI2RlZmluZSBEQTkxNTBfTlVNX0lSUV9SRUdTCTQN
Cj4gPiArI2RlZmluZSBEQTkxNTBfSVJRX1ZCVVMJCTANCj4gPiArI2RlZmluZSBEQTkxNTBfSVJR
X0NIRwkJMQ0KPiA+ICsjZGVmaW5lIERBOTE1MF9JUlFfVENMQVNTCTINCj4gPiArI2RlZmluZSBE
QTkxNTBfSVJRX1RKVU5DCTMNCj4gPiArI2RlZmluZSBEQTkxNTBfSVJRX1ZGQVVMVAk0DQo+ID4g
KyNkZWZpbmUgREE5MTUwX0lSUV9DT05GCQk1DQo+ID4gKyNkZWZpbmUgREE5MTUwX0lSUV9EQVQJ
CTYNCj4gPiArI2RlZmluZSBEQTkxNTBfSVJRX0RUWVBFCTcNCj4gPiArI2RlZmluZSBEQTkxNTBf
SVJRX0lECQk4DQo+ID4gKyNkZWZpbmUgREE5MTUwX0lSUV9BRFAJCTkNCj4gPiArI2RlZmluZSBE
QTkxNTBfSVJRX1NFU1NfRU5ECTEwDQo+ID4gKyNkZWZpbmUgREE5MTUwX0lSUV9TRVNTX1ZMRAkx
MQ0KPiA+ICsjZGVmaW5lIERBOTE1MF9JUlFfRkcJCTEyDQo+ID4gKyNkZWZpbmUgREE5MTUwX0lS
UV9HUAkJMTMNCj4gPiArI2RlZmluZSBEQTkxNTBfSVJRX1RCQVQJCTE0DQo+ID4gKyNkZWZpbmUg
REE5MTUwX0lSUV9HUElPQQkxNQ0KPiA+ICsjZGVmaW5lIERBOTE1MF9JUlFfR1BJT0IJMTYNCj4g
PiArI2RlZmluZSBEQTkxNTBfSVJRX0dQSU9DCTE3DQo+ID4gKyNkZWZpbmUgREE5MTUwX0lSUV9H
UElPRAkxOA0KPiA+ICsjZGVmaW5lIERBOTE1MF9JUlFfR1BBREMJMTkNCj4gPiArI2RlZmluZSBE
QTkxNTBfSVJRX1dLVVAJCTIwDQo+ID4gKw0KPiA+ICtzdHJ1Y3QgZGE5MTUwIHsNCj4gPiArCXN0
cnVjdCBkZXZpY2UgKmRldjsNCj4gPiArDQo+ID4gKwlzdHJ1Y3QgcmVnbWFwICpyZWdtYXA7DQo+
ID4gKw0KPiANCj4gV2h5IHRoZSAnXG4ncz8NCg0KUGVyc29uYWwgcHJlZmVyZW5jZSwgYnV0IHdp
bGwgcmVtb3ZlLg0KDQo+IA0KPiA+ICsJc3RydWN0IHJlZ21hcF9pcnFfY2hpcF9kYXRhICpyZWdt
YXBfaXJxX2RhdGE7DQo+ID4gKwlpbnQgaXJxOw0KPiA+ICsJaW50IGlycV9iYXNlOw0KPiA+ICt9
Ow0KPiA+ICsNCj4gPiArLyogRGV2aWNlIEkvTyAqLw0KPiA+ICt1OCBkYTkxNTBfcmVnX3JlYWQo
c3RydWN0IGRhOTE1MCAqZGE5MTUwLCB1MTYgcmVnKTsNCj4gPiAraW50IGRhOTE1MF9yZWdfd3Jp
dGUoc3RydWN0IGRhOTE1MCAqZGE5MTUwLCB1MTYgcmVnLCB1OCB2YWwpOw0KPiA+ICtpbnQgZGE5
MTUwX3NldF9iaXRzKHN0cnVjdCBkYTkxNTAgKmRhOTE1MCwgdTE2IHJlZywgdTggbWFzaywgdTgg
dmFsKTsNCj4gPiArDQo+ID4gK2ludCBkYTkxNTBfYnVsa19yZWFkKHN0cnVjdCBkYTkxNTAgKmRh
OTE1MCwgdTE2IHJlZywgaW50IGNvdW50LCB1OCAqYnVmKTsNCj4gPiAraW50IGRhOTE1MF9idWxr
X3dyaXRlKHN0cnVjdCBkYTkxNTAgKmRhOTE1MCwgdTE2IHJlZywgaW50IGNvdW50LCBjb25zdCB1
OCAqYnVmKTsNCj4gPiArDQo+ID4gKy8qIElSUSBoZWxwZXIgZnVuY3Rpb25zICovDQo+ID4gK2lu
dCBkYTkxNTBfcmVnaXN0ZXJfaXJxKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYsIHZvaWQg
KmRldl9pZCwNCj4gPiArCQkJaXJxX2hhbmRsZXJfdCBoYW5kbGVyLCBjb25zdCBjaGFyICpuYW1l
KTsNCj4gPiArdm9pZCBkYTkxNTBfcmVsZWFzZV9pcnEoc3RydWN0IHBsYXRmb3JtX2RldmljZSAq
cGRldiwgdm9pZCAqZGV2X2lkLA0KPiA+ICsJCQljb25zdCBjaGFyICpuYW1lKTsNCj4gDQo+IEkn
bSBub3Qgc3VyZSB3aHkgYW55IG9mIHRoZXNlIDcgZnVuY3Rpb25zIGFyZSByZXF1aXJlZC4NCg0K
Q2xhcmlmaWVkIG15IGludGVudGlvbnMgaW4gcHJldmlvdXMgY29tbWVudHMuDQoNCj4gDQo+ID4g
Ky8qIEluaXQvRXhpdCAqLw0KPiA+ICtpbnQgZGE5MTUwX2RldmljZV9pbml0KHN0cnVjdCBkYTkx
NTAgKmRhOTE1MCk7DQo+ID4gK3ZvaWQgZGE5MTUwX2RldmljZV9leGl0KHN0cnVjdCBkYTkxNTAg
KmRhOTE1MCk7DQo+ID4gK3ZvaWQgZGE5MTUwX2RldmljZV9zaHV0ZG93bihzdHJ1Y3QgZGE5MTUw
ICpkYTkxNTApOw0KPiA+ICsNCj4gPiArI2VuZGlmIC8qIF9fREE5MTUwX0NPUkVfSCAqLw0KPiA+
IGRpZmYgLS1naXQgYS9pbmNsdWRlL2xpbnV4L21mZC9kYTkxNTAvcGRhdGEuaCBiL2luY2x1ZGUv
bGludXgvbWZkL2RhOTE1MC9wZGF0YS5oDQo+ID4gbmV3IGZpbGUgbW9kZSAxMDA2NDQNCj4gPiBp
bmRleCAwMDAwMDAwLi5lMmIzN2YxDQo+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ICsrKyBiL2luY2x1
ZGUvbGludXgvbWZkL2RhOTE1MC9wZGF0YS5oDQo+ID4gQEAgLTAsMCArMSwyMSBAQA0KPiA+ICsv
Kg0KPiA+ICsgKiBEQTkxNTAgTUZEIERyaXZlciAtIFBsYXRmb3JtIERhdGENCj4gPiArICoNCj4g
PiArICogQ29weXJpZ2h0IChjKSAyMDE0IERpYWxvZyBTZW1pY29uZHVjdG9yDQo+ID4gKyAqDQo+
ID4gKyAqIEF1dGhvcjogQWRhbSBUaG9tc29uIDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFz
ZW1pLmNvbT4NCj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7
IHlvdSBjYW4gcmVkaXN0cmlidXRlICBpdCBhbmQvb3IgbW9kaWZ5IGl0DQo+ID4gKyAqIHVuZGVy
ICB0aGUgdGVybXMgb2YgIHRoZSBHTlUgR2VuZXJhbCAgUHVibGljIExpY2Vuc2UgYXMgcHVibGlz
aGVkIGJ5IHRoZQ0KPiA+ICsgKiBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247ICBlaXRoZXIgdmVy
c2lvbiAyIG9mIHRoZSAgTGljZW5zZSwgb3IgKGF0IHlvdXINCj4gPiArICogb3B0aW9uKSBhbnkg
bGF0ZXIgdmVyc2lvbi4NCj4gPiArICovDQo+ID4gKw0KPiA+ICsjaWZuZGVmIF9fREE5MTUwX1BE
QVRBX0gNCj4gPiArI2RlZmluZSBfX0RBOTE1MF9QREFUQV9IDQo+ID4gKw0KPiA+ICtzdHJ1Y3Qg
ZGE5MTUwX3BkYXRhIHsNCj4gPiArCWludCBpcnFfYmFzZTsNCj4gPiArfTsNCj4gDQo+IEp1c3Qg
cHV0IHRoaXMgaW4gY29yZS5oIGFuZCBkbyBhd2F5IHdpdGh0IHRoaXMgaGVhZGVyIGZpbGUuDQoN
ClRoZSByZWFzb24gZm9yIHRoaXMgaXMgdGhhdCBJIHdpbGwgYWRkIG1vcmUgcGxhdGZvcm0gZGF0
YSBpdGVtcyBsYXRlciB3aXRoDQpzdWJzZXF1ZW50IHN1Ym1pc3Npb25zIGZvciBhZGRpdGlvbmFs
IGZlYXR1cmVzLiBJdCBmZWx0IGNsZWFuZXIgdG8gc2VwYXJhdGUgb3V0DQp0aGVzZSBzdHJ1Y3R1
cmVzIHRoYW4gdGhyb3cgaXQgaW4gdGhlIGNvcmUuaCBoZWFkZXIuIEhvd2V2ZXIgaWYgaXQncyBn
b2luZyB0bw0KYmUgYSBwcm9ibGVtIEknbGwgZm9sZCB0aGlzIGludG8gY29yZS5oDQoNCj4gDQo+
ID4gKyNlbmRpZiAvKiBfX0RBOTE1MF9QREFUQV9IICovDQo+ID4gZGlmZiAtLWdpdCBhL2luY2x1
ZGUvbGludXgvbWZkL2RhOTE1MC9yZWdpc3RlcnMuaA0KPiBiL2luY2x1ZGUvbGludXgvbWZkL2Rh
OTE1MC9yZWdpc3RlcnMuaA0KPiA+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+ID4gaW5kZXggMDAw
MDAwMC4uZWY0ODI2ZA0KPiA+IC0tLSAvZGV2L251bGwNCj4gPiArKysgYi9pbmNsdWRlL2xpbnV4
L21mZC9kYTkxNTAvcmVnaXN0ZXJzLmgNCj4gPiBAQCAtMCwwICsxLDExNTMgQEANCj4gPiArLyoN
Cj4gPiArICogREE5MTUwIE1GRCBEcml2ZXIgLSBSZWdpc3RlcnMNCj4gPiArICoNCj4gPiArICog
Q29weXJpZ2h0IChjKSAyMDE0IERpYWxvZyBTZW1pY29uZHVjdG9yDQo+ID4gKyAqDQo+ID4gKyAq
IEF1dGhvcjogQWRhbSBUaG9tc29uIDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNv
bT4NCj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBj
YW4gcmVkaXN0cmlidXRlICBpdCBhbmQvb3IgbW9kaWZ5IGl0DQo+ID4gKyAqIHVuZGVyICB0aGUg
dGVybXMgb2YgIHRoZSBHTlUgR2VuZXJhbCAgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5
IHRoZQ0KPiA+ICsgKiBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247ICBlaXRoZXIgdmVyc2lvbiAy
IG9mIHRoZSAgTGljZW5zZSwgb3IgKGF0IHlvdXINCj4gPiArICogb3B0aW9uKSBhbnkgbGF0ZXIg
dmVyc2lvbi4NCj4gPiArICovDQo+ID4gKw0KPiA+ICsjaWZuZGVmIF9fREE5MTUwX1JFR0lTVEVS
U19IDQo+ID4gKyNkZWZpbmUgX19EQTkxNTBfUkVHSVNURVJTX0gNCj4gPiArDQo+ID4gKy8qIFJl
Z2lzdGVycyAqLw0KPiANCj4gWy4uLl0NCj4gDQo+ID4gKy8qIERBOTE1MF9DT05UUk9MX0EgPSAw
eDBFNSAqLw0KPiA+ICsjZGVmaW5lIERBOTE1MF9WREQzM19TTF9TSElGVAkJCTANCj4gPiArI2Rl
ZmluZSBEQTkxNTBfVkREMzNfU0xfTUFTSwkJCSgweDAxIDw8IDApDQo+ID4gKyNkZWZpbmUgREE5
MTUwX1ZERDMzX0xQTV9TSElGVAkJCTENCj4gPiArI2RlZmluZSBEQTkxNTBfVkREMzNfTFBNX01B
U0sJCQkoMHgwMyA8PCAxKQ0KPiA+ICsjZGVmaW5lIERBOTE1MF9WREQzM19FTl9TSElGVAkJCTMN
Cj4gPiArI2RlZmluZSBEQTkxNTBfVkREMzNfRU5fTUFTSwkJCSgweDAxIDw8IDMpDQo+ID4gKyNk
ZWZpbmUgREE5MTUwX0dQSV9MUE1fU0hJRlQJCQk2DQo+ID4gKyNkZWZpbmUgREE5MTUwX0dQSV9M
UE1fTUFTSwkJCSgweDAxIDw8IDYpDQo+ID4gKyNkZWZpbmUgREE5MTUwX1BNX0lGX0xQTV9TSElG
VAkJCTcNCj4gPiArI2RlZmluZSBEQTkxNTBfUE1fSUZfTFBNX01BU0sJCQkoMHgwMSA8PCA3KQ0K
PiA+ICsNCj4gPiArLyogREE5MTUwX0NPTlRST0xfQiA9IDB4MEU2ICovDQo+ID4gKyNkZWZpbmUg
REE5MTUwX0xQTV9TSElGVAkJCTANCj4gPiArI2RlZmluZSBEQTkxNTBfTFBNX01BU0sJCQkJKDB4
MDEgPDwgMCkNCj4gPiArI2RlZmluZSBEQTkxNTBfUkVTRVRfU0hJRlQJCQkxDQo+ID4gKyNkZWZp
bmUgREE5MTUwX1JFU0VUX01BU0sJCQkoMHgwMSA8PCAxKQ0KPiA+ICsjZGVmaW5lIERBOTE1MF9S
RVNFVF9VU1JDT05GX0VOX1NISUZUCQkyDQo+ID4gKyNkZWZpbmUgREE5MTUwX1JFU0VUX1VTUkNP
TkZfRU5fTUFTSwkJKDB4MDEgPDwgMikNCj4gPiArDQo+ID4gKy8qIERBOTE1MF9DT05UUk9MX0Mg
PSAweDBFNyAqLw0KPiA+ICsjZGVmaW5lIERBOTE1MF9ESVNBQkxFX1NISUZUCQkJMA0KPiA+ICsj
ZGVmaW5lIERBOTE1MF9ESVNBQkxFX01BU0sJCQkoMHgwMSA8PCAwKQ0KPiANCj4gVXNlIEJJVCgp
IGZvciBhbGwgb2YgdGhlc2UgKDEgPDwgWCkgbWFjcm9zLg0KDQpPSywgd2lsbCBkby4NCg0KPiAN
Cj4gWy4uLl0NCj4gDQo+IC0tDQo+IExlZSBKb25lcw0KPiBMaW5hcm8gU1RNaWNyb2VsZWN0cm9u
aWNzIExhbmRpbmcgVGVhbSBMZWFkDQo+IExpbmFyby5vcmcg4pSCIE9wZW4gc291cmNlIHNvZnR3
YXJlIGZvciBBUk0gU29Dcw0KPiBGb2xsb3cgTGluYXJvOiBGYWNlYm9vayB8IFR3aXR0ZXIgfCBC
bG9nDQo=

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

* RE: [PATCH v2 3/7] iio: Add support for DA9150 GPADC
  2014-08-28 11:28   ` Peter Meerwald
  2014-08-30 20:01     ` Jonathan Cameron
@ 2014-09-09 10:51     ` Opensource [Adam Thomson]
  1 sibling, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:51 UTC (permalink / raw)
  To: Peter Meerwald, Opensource [Adam Thomson]
  Cc: Lee Jones, Jonathan Cameron, linux-iio, Support Opensource

T24gQXVndXN0IDI4LCAyMDE0IDEyOjI4LCBQZXRlciBNZWVyd2FsZCB3cm90ZToNCg0KPiBzb21l
IG1pbm9yIGNvbW1lbnRzIGlubGluZQ0KPiANCj4gPiBUaGlzIHBhdGNoIGFkZHMgc3VwcG9ydCBm
b3IgREE5MTUwIENoYXJnZXIgJiBGdWVsLUdhdWdlIElDIEdQQURDLg0KPiA+DQo+ID4gU2lnbmVk
LW9mZi1ieTogQWRhbSBUaG9tc29uIDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNv
bT4NCj4gPiAtLS0NCj4gPiAgZHJpdmVycy9paW8vYWRjL0tjb25maWcgICAgICAgIHwgICA5ICsN
Cj4gPiAgZHJpdmVycy9paW8vYWRjL01ha2VmaWxlICAgICAgIHwgICAxICsNCj4gPiAgZHJpdmVy
cy9paW8vYWRjL2RhOTE1MC1ncGFkYy5jIHwgNDMwDQo+ICsrKysrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrDQo+ID4gIDMgZmlsZXMgY2hhbmdlZCwgNDQwIGluc2VydGlvbnMo
KykNCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvaWlvL2FkYy9kYTkxNTAtZ3BhZGMu
Yw0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvaWlvL2FkYy9LY29uZmlnIGIvZHJpdmVy
cy9paW8vYWRjL0tjb25maWcNCj4gPiBpbmRleCAxMWIwNDhhLi44MDQxMzQ3IDEwMDY0NA0KPiA+
IC0tLSBhL2RyaXZlcnMvaWlvL2FkYy9LY29uZmlnDQo+ID4gKysrIGIvZHJpdmVycy9paW8vYWRj
L0tjb25maWcNCj4gPiBAQCAtMTI3LDYgKzEyNywxNSBAQCBjb25maWcgQVQ5MV9BREMNCj4gPiAg
CWhlbHANCj4gPiAgCSAgU2F5IHllcyBoZXJlIHRvIGJ1aWxkIHN1cHBvcnQgZm9yIEF0bWVsIEFU
OTEgQURDLg0KPiA+DQo+ID4gK2NvbmZpZyBEQTkxNTBfR1BBREMNCj4gPiArCXRyaXN0YXRlICJE
aWFsb2cgREE5MTUwIEdQQURDIGRyaXZlciBzdXBwb3J0Ig0KPiA+ICsJZGVwZW5kcyBvbiBNRkRf
REE5MTUwDQo+ID4gKwloZWxwDQo+ID4gKwkgIFNheSB5ZXMgaGVyZSB0byBidWlsZCBzdXBwb3J0
IGZvciBEaWFsb2cgREE5MTUwIEdQQURDLg0KPiA+ICsNCj4gPiArCSAgVGhpcyBkcml2ZXIgY2Fu
IGFsc28gYmUgYnVpbHQgYXMgYSBtb2R1bGUuIElmIGNob3NlbiwgdGhlIG1vZHVsZSBuYW1lDQo+
ID4gKwkgIHdpbGwgYmUgZGE5MTUwLWdwYWRjLg0KPiA+ICsNCj4gPiAgY29uZmlnIEVYWU5PU19B
REMNCj4gPiAgCXRyaXN0YXRlICJFeHlub3MgQURDIGRyaXZlciBzdXBwb3J0Ig0KPiA+ICAJZGVw
ZW5kcyBvbiBBUkNIX0VYWU5PUyB8fCAoT0YgJiYgQ09NUElMRV9URVNUKQ0KPiA+IGRpZmYgLS1n
aXQgYS9kcml2ZXJzL2lpby9hZGMvTWFrZWZpbGUgYi9kcml2ZXJzL2lpby9hZGMvTWFrZWZpbGUN
Cj4gPiBpbmRleCBhZDgxYjUxLi40ODQxM2QyIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvaWlv
L2FkYy9NYWtlZmlsZQ0KPiA+ICsrKyBiL2RyaXZlcnMvaWlvL2FkYy9NYWtlZmlsZQ0KPiA+IEBA
IC0xNCw2ICsxNCw3IEBAIG9iai0kKENPTkZJR19BRDc3OTMpICs9IGFkNzc5My5vDQo+ID4gIG9i
ai0kKENPTkZJR19BRDc4ODcpICs9IGFkNzg4Ny5vDQo+ID4gIG9iai0kKENPTkZJR19BRDc5OVgp
ICs9IGFkNzk5eC5vDQo+ID4gIG9iai0kKENPTkZJR19BVDkxX0FEQykgKz0gYXQ5MV9hZGMubw0K
PiA+ICtvYmotJChDT05GSUdfREE5MTUwX0dQQURDKSArPSBkYTkxNTAtZ3BhZGMubw0KPiA+ICBv
YmotJChDT05GSUdfRVhZTk9TX0FEQykgKz0gZXh5bm9zX2FkYy5vDQo+ID4gIG9iai0kKENPTkZJ
R19MUDg3ODhfQURDKSArPSBscDg3ODhfYWRjLm8NCj4gPiAgb2JqLSQoQ09ORklHX01BWDEwMjcp
ICs9IG1heDEwMjcubw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2lpby9hZGMvZGE5MTUwLWdw
YWRjLmMgYi9kcml2ZXJzL2lpby9hZGMvZGE5MTUwLWdwYWRjLmMNCj4gPiBuZXcgZmlsZSBtb2Rl
IDEwMDY0NA0KPiA+IGluZGV4IDAwMDAwMDAuLjIxYTIxYTkNCj4gPiAtLS0gL2Rldi9udWxsDQo+
ID4gKysrIGIvZHJpdmVycy9paW8vYWRjL2RhOTE1MC1ncGFkYy5jDQo+ID4gQEAgLTAsMCArMSw0
MzAgQEANCj4gPiArLyoNCj4gPiArICogREE5MTUwIEdQQURDIERyaXZlcg0KPiA+ICsgKg0KPiA+
ICsgKiBDb3B5cmlnaHQgKGMpIDIwMTQgRGlhbG9nIFNlbWljb25kdWN0b3INCj4gPiArICoNCj4g
PiArICogQXV0aG9yOiBBZGFtIFRob21zb24gPEFkYW0uVGhvbXNvbi5PcGVuc291cmNlQGRpYXNl
bWkuY29tPg0KPiA+ICsgKg0KPiA+ICsgKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsg
eW91IGNhbiByZWRpc3RyaWJ1dGUgIGl0IGFuZC9vciBtb2RpZnkgaXQNCj4gPiArICogdW5kZXIg
IHRoZSB0ZXJtcyBvZiAgdGhlIEdOVSBHZW5lcmFsICBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNo
ZWQgYnkgdGhlDQo+ID4gKyAqIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgIGVpdGhlciB2ZXJz
aW9uIDIgb2YgdGhlICBMaWNlbnNlLCBvciAoYXQgeW91cg0KPiA+ICsgKiBvcHRpb24pIGFueSBs
YXRlciB2ZXJzaW9uLg0KPiA+ICsgKi8NCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxsaW51eC9rZXJu
ZWwuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4
L21vZHVsZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGV2aWNlLmg+DQo+ID4g
KyNpbmNsdWRlIDxsaW51eC9pbnRlcnJ1cHQuaD4NCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxsaW51
eC9tZmQvZGE5MTUwL2NvcmUuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L21mZC9kYTkxNTAvcGRh
dGEuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L21mZC9kYTkxNTAvcmVnaXN0ZXJzLmg+DQo+ID4g
Kw0KPiA+ICsjaW5jbHVkZSA8bGludXgvaWlvL2lpby5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgv
aWlvL21hY2hpbmUuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L2lpby9kcml2ZXIuaD4NCj4gPiAr
DQo+ID4gKw0KPiA+ICsvKiBDaGFubmVscyAqLw0KPiA+ICtlbnVtIGRhOTE1MF9ncGFkY19od19j
aGFubmVsIHsNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9BXzJWID0gMCwNCj4gPiAr
CURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9BXzJWXywNCj4gDQo+IHdoeSB0aGUgdW5kZXJzY29y
ZV8gbm90YXRpb24/DQo+IGNvdWxkbid0IHlvdSB1c2UgZS5nLiBEQTkxNTBfR1BBRENfSFdfQ0hB
Tl9HUElPQl8yViA9IDI/DQoNCldpdGhpbiB0aGUgZGV2aWNlIHRoZXNlIGFyZSBjaGFubmVscyB0
b28sIGFsdGhvdWdoIG1vc3QgcHJvdmlkZSBpZGVudGljYWwgZGF0YQ0KdG8gdGhlaXIgbm9uICdf
JyBjb3VudGVycGFydC4gSGF2ZSBsZWZ0IHRob3NlIGluIGZvciBjb21wbGV0ZW5lc3MsIGFsdGhv
dWdoDQpzb21lIGFyZW4ndCB1c2VkLiBJZiBpdCdzIGEgYmlnIGRlYWwgdGhvdWdoIEkgY2FuIGNo
YW5nZSBpdC4NCg0KPiANCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9CXzJWLA0KPiA+
ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0JfMlZfLA0KPiA+ICsJREE5MTUwX0dQQURDX0hX
X0NIQU5fR1BJT0NfMlYsDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPQ18yVl8sDQo+
ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPRF8yViwNCj4gPiArCURBOTE1MF9HUEFEQ19I
V19DSEFOX0dQSU9EXzJWXywNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0lCVVNfU0VOU0Us
DQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9JQlVTX1NFTlNFXywNCj4gPiArCURBOTE1MF9H
UEFEQ19IV19DSEFOX1ZCVVNfRElWLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fVkJVU19E
SVZfLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fSUQsDQo+ID4gKwlEQTkxNTBfR1BBRENf
SFdfQ0hBTl9JRF8sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9WU1lTLA0KPiA+ICsJREE5
MTUwX0dQQURDX0hXX0NIQU5fVlNZU18sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElP
QV81ViwNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9BXzVWXywNCj4gPiArCURBOTE1
MF9HUEFEQ19IV19DSEFOX0dQSU9CXzVWLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJ
T0JfNVZfLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0NfNVYsDQo+ID4gKwlEQTkx
NTBfR1BBRENfSFdfQ0hBTl9HUElPQ181Vl8sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9H
UElPRF81ViwNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9EXzVWXywNCj4gPiArCURB
OTE1MF9HUEFEQ19IV19DSEFOX1ZCQVQsDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9WQkFU
XywNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX1RCQVQsDQo+ID4gKwlEQTkxNTBfR1BBRENf
SFdfQ0hBTl9UQkFUXywNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX1RKVU5DX0NPUkUsDQo+
ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9USlVOQ19DT1JFXywNCj4gPiArCURBOTE1MF9HUEFE
Q19IV19DSEFOX1RKVU5DX09WUCwNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX1RKVU5DX09W
UF8sDQo+ID4gK307DQo+ID4gKw0KPiA+ICtlbnVtIGRhOTE1MF9ncGFkY19jaGFubmVsIHsNCj4g
PiArCURBOTE1MF9HUEFEQ19DSEFOX0dQSU9BID0gMCwNCj4gPiArCURBOTE1MF9HUEFEQ19DSEFO
X0dQSU9CLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5fR1BJT0MsDQo+ID4gKwlEQTkxNTBfR1BB
RENfQ0hBTl9HUElPRCwNCj4gPiArCURBOTE1MF9HUEFEQ19DSEFOX0lCVVMsDQo+ID4gKwlEQTkx
NTBfR1BBRENfQ0hBTl9WQlVTLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5fSUQsDQo+ID4gKwlE
QTkxNTBfR1BBRENfQ0hBTl9WU1lTLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5fVkJBVCwNCj4g
PiArCURBOTE1MF9HUEFEQ19DSEFOX1RCQVQsDQo+ID4gKwlEQTkxNTBfR1BBRENfQ0hBTl9USlVO
Q19DT1JFLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5fVEpVTkNfT1ZQLA0KPiA+ICt9Ow0KPiA+
ICsNCj4gPiArLyogUHJpdmF0ZSBkYXRhICovDQo+ID4gK3N0cnVjdCBkYTkxNTBfZ3BhZGMgew0K
PiA+ICsJc3RydWN0IGRhOTE1MCAqZGE5MTUwOw0KPiA+ICsJc3RydWN0IGRldmljZSAqZGV2Ow0K
PiA+ICsNCj4gPiArCXN0cnVjdCBtdXRleCBsb2NrOw0KPiA+ICsJc3RydWN0IGNvbXBsZXRpb24g
Y29tcGxldGU7DQo+ID4gK307DQo+ID4gKw0KPiA+ICsNCj4gPiArc3RhdGljIGlycXJldHVybl90
IGRhOTE1MF9ncGFkY19pcnEoaW50IGlycSwgdm9pZCAqZGF0YSkNCj4gPiArew0KPiA+ICsNCj4g
PiArCXN0cnVjdCBkYTkxNTBfZ3BhZGMgKmdwYWRjID0gZGF0YTsNCj4gPiArDQo+ID4gKwljb21w
bGV0ZSgmZ3BhZGMtPmNvbXBsZXRlKTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gSVJRX0hBTkRMRUQ7
DQo+ID4gK30NCj4gPiArDQo+ID4gK2ludCBkYTkxNTBfZ3BhZGNfcmVhZF9hZGMoc3RydWN0IGRh
OTE1MF9ncGFkYyAqZ3BhZGMsIGludCBod19jaGFuKQ0KPiANCj4gc3RhdGljPw0KDQpZZXMsIHdp
bGwgdXBkYXRlLg0KDQo+IA0KPiA+ICt7DQo+ID4gKwl1OCByZXN1bHRfcmVnc1syXTsNCj4gPiAr
CWludCByZXN1bHQ7DQo+ID4gKw0KPiA+ICsJbXV0ZXhfbG9jaygmZ3BhZGMtPmxvY2spOw0KPiA+
ICsNCj4gPiArCS8qIFNldCBjaGFubmVsICYgZW5hYmxlIG1lYXN1cmVtZW50ICovDQo+ID4gKwlk
YTkxNTBfcmVnX3dyaXRlKGdwYWRjLT5kYTkxNTAsIERBOTE1MF9HUEFEQ19NQU4sDQo+ID4gKwkJ
CSAoREE5MTUwX0dQQURDX0VOX01BU0sgfA0KPiA+ICsJCQkgIGh3X2NoYW4gPDwgREE5MTUwX0dQ
QURDX01VWF9TSElGVCkpOw0KPiA+ICsNCj4gPiArCS8qIENvbnN1bWUgbGVmdC1vdmVyIGNvbXBs
ZXRpb24gZnJvbSBhIHByZXZpb3VzIHRpbWVvdXQgKi8NCj4gPiArCXRyeV93YWl0X2Zvcl9jb21w
bGV0aW9uKCZncGFkYy0+Y29tcGxldGUpOw0KPiA+ICsNCj4gPiArCS8qIENoZWNrIGZvciBhY3R1
YWwgY29tcGxldGlvbiAqLw0KPiA+ICsJd2FpdF9mb3JfY29tcGxldGlvbl90aW1lb3V0KCZncGFk
Yy0+Y29tcGxldGUsIG1zZWNzX3RvX2ppZmZpZXMoNSkpOw0KPiA+ICsNCj4gPiArCS8qIFJlYWQg
cmVzdWx0IGFuZCBzdGF0dXMgZnJvbSBkZXZpY2UgKi8NCj4gPiArCWRhOTE1MF9idWxrX3JlYWQo
Z3BhZGMtPmRhOTE1MCwgREE5MTUwX0dQQURDX1JFU19BLCAyLCByZXN1bHRfcmVncyk7DQo+ID4g
Kw0KPiA+ICsJbXV0ZXhfdW5sb2NrKCZncGFkYy0+bG9jayk7DQo+ID4gKw0KPiA+ICsJLyogQ2hl
Y2sgdG8gbWFrZSBzdXJlIGRldmljZSByZWFsbHkgaGFzIGNvbXBsZXRlZCByZWFkaW5nICovDQo+
ID4gKwlpZiAocmVzdWx0X3JlZ3NbMV0gJiBEQTkxNTBfR1BBRENfUlVOX01BU0spIHsNCj4gPiAr
CQlkZXZfZXJyKGdwYWRjLT5kZXYsICJUaW1lb3V0IG9uIGNoYW5uZWwgJWQgb2YgR1AtQURDXG4i
LA0KPiANCj4gR1BBREMgZXZlcnl3aGVyZSBlbHNlDQoNClJpZ2h0LiBXaWxsIGNoYW5nZS4NCg0K
PiANCj4gPiArCQkJaHdfY2hhbik7DQo+ID4gKwkJcmV0dXJuIC1FVElNRURPVVQ7DQo+ID4gKwl9
DQo+ID4gKw0KPiA+ICsJLyogTFNCcyAtIDIgYml0cyAqLw0KPiA+ICsJcmVzdWx0ID0gKHJlc3Vs
dF9yZWdzWzFdICYgREE5MTUwX0dQQURDX1JFU19MX01BU0spID4+DQo+ID4gKwkJIERBOTE1MF9H
UEFEQ19SRVNfTF9TSElGVDsNCj4gPiArCS8qIE1TQnMgLSA4IGJpdHMgKi8NCj4gPiArCXJlc3Vs
dCB8PSByZXN1bHRfcmVnc1swXSA8PCBEQTkxNTBfR1BBRENfUkVTX0xfQklUUzsNCj4gDQo+IGNh
bid0IHRoZSByZWFkIGJlIGRvbmUgd2l0aCBhIDE2Yml0IHJlYWQ/DQoNCk5vLiBUaGUgc2Vjb25k
IHJlZ2lzdGVyIHJlYWQgY29udGFpbnMgYml0cyBub3QgcmVsYXRlZCB0byB0aGUgY2FsY3VsYXRp
b24gd2hpY2gNCm5lZWQgdG8gYmUgbWFza2VkIG91dCwgYW5kIHRoZSB2YWx1ZSB0aGVuIG5lZWRz
IHRvIGJlIHNoaWZ0ZWQgYWNjb3JkaW5nbHkuDQoNCj4gDQo+ID4gKw0KPiA+ICsJcmV0dXJuIHJl
c3VsdDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGlubGluZSBpbnQgZGE5MTUwX2dwYWRj
X2dwaW9fNXZfdm9sdGFnZV9ub3coaW50IHJhd192YWwpDQo+ID4gK3sNCj4gPiArCS8qIENvbnZl
cnQgdG8gdVYgKi8NCj4gPiArCXJldHVybiAoKCg2ICogKChyYXdfdmFsICogMTAwMCkgKyA1MDAp
KSAvIDEwMjQpICogMTAwMCk7DQo+IA0KPiBvdXRlciBwYXJlbnRoZXNpcyBub3QgbmVlZGVkLCBo
ZXJlIGFuZCBiZWxvdw0KDQpQZXJzb25hbCBwcmVmZXJlbmNlLCBidXQgY2FuIGNoYW5nZS4NCg0K
PiANCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGlubGluZSBpbnQgZGE5MTUwX2dwYWRjX2li
dXNfY3VycmVudF9hdmcoaW50IHJhd192YWwpDQo+ID4gK3sNCj4gPiArCS8qIENvbnZlcnQgdG8g
dUEgKi8NCj4gPiArCXJldHVybiAoKCg0ICogKChyYXdfdmFsICogMTAwMCkgKyA1MDApKSAvIDIw
NDgpICogMTAwMCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1
MF9ncGFkY192YnVzXzIxdl92b2x0YWdlX25vdyhpbnQgcmF3X3ZhbCkNCj4gPiArew0KPiA+ICsJ
LyogQ29udmVydCB0byB1ViAqLw0KPiA+ICsJcmV0dXJuICgoKDIxICogKChyYXdfdmFsICogMTAw
MCkgKyA1MDApKSAvIDEwMjQpICogMTAwMCk7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBp
bmxpbmUgaW50IGRhOTE1MF9ncGFkY192c3lzXzZ2X3ZvbHRhZ2Vfbm93KGludCByYXdfdmFsKQ0K
PiA+ICt7DQo+ID4gKwkvKiBDb252ZXJ0IHRvIHVWICovDQo+ID4gKwlyZXR1cm4gKCgoMyAqICgo
cmF3X3ZhbCAqIDEwMDApICsgNTAwKSkgLyA1MTIpICogMTAwMCk7DQo+ID4gK30NCj4gPiArDQo+
ID4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1MF9ncGFkY190anVuY190ZW1wKGludCByYXdfdmFs
KQ0KPiA+ICt7DQo+ID4gKwkvKiBDb252ZXJ0IHRvIDAuMSBkZWdyZWVzIEMgKi8NCj4gDQo+IElJ
TyB3YW50cyBtaWxsZSBkZWdyZWVzIEMNCg0KDQoNCj4gDQo+ID4gKwlyZXR1cm4gKCgoODc5IC0g
KDEwMjMgLSByYXdfdmFsKSkgKiAxMDAwMCkgLyA0NDIwKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr
c3RhdGljIGlubGluZSBpbnQgZGE5MTUwX2dwYWRjX3ZiYXRfdm9sdGFnZV9ub3coaW50IHJhd192
YWwpDQo+ID4gK3sNCj4gPiArCS8qIENvbnZlcnQgdG8gdVYgKi8NCj4gPiArCXJldHVybiAoKDI5
MzIgKiByYXdfdmFsKSArIDE1MDAwMDApOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtpbnQgZGE5MTUw
X2dwYWRjX3JlYWRfcHJvY2Vzc2VkKHN0cnVjdCBkYTkxNTBfZ3BhZGMgKmdwYWRjLCBpbnQgY2hh
bm5lbCwNCj4gPiArCQkJCWludCBod19jaGFuKQ0KPiANCj4gc3RhdGljPw0KDQpZZXAsIHdpbGwg
dXBkYXRlLg0KDQo+IA0KPiA+ICt7DQo+ID4gKwlpbnQgcmF3X3ZhbCwgcmV0Ow0KPiA+ICsNCj4g
PiArCXJhd192YWwgPSBkYTkxNTBfZ3BhZGNfcmVhZF9hZGMoZ3BhZGMsIGh3X2NoYW4pOw0KPiA+
ICsJaWYgKHJhd192YWwgPCAwKQ0KPiA+ICsJCXJldHVybiByYXdfdmFsOw0KPiA+ICsNCj4gPiAr
CXN3aXRjaCAoY2hhbm5lbCkgew0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9HUElPQToN
Cj4gPiArCWNhc2UgREE5MTUwX0dQQURDX0NIQU5fR1BJT0I6DQo+ID4gKwljYXNlIERBOTE1MF9H
UEFEQ19DSEFOX0dQSU9DOg0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9HUElPRDoNCj4g
PiArCQlyZXQgPSBkYTkxNTBfZ3BhZGNfZ3Bpb181dl92b2x0YWdlX25vdyhyYXdfdmFsKTsNCj4g
DQo+IGNvdWxkIHJldHVybiBkaXJlY3RseSAuLi4NCj4gDQo+ID4gKwkJYnJlYWs7DQo+ID4gKwlj
YXNlIERBOTE1MF9HUEFEQ19DSEFOX0lCVVM6DQo+ID4gKwkJcmV0ID0gZGE5MTUwX2dwYWRjX2li
dXNfY3VycmVudF9hdmcocmF3X3ZhbCk7DQo+ID4gKwkJYnJlYWs7DQo+ID4gKwljYXNlIERBOTE1
MF9HUEFEQ19DSEFOX1ZCVVM6DQo+ID4gKwkJcmV0ID0gZGE5MTUwX2dwYWRjX3ZidXNfMjF2X3Zv
bHRhZ2Vfbm93KHJhd192YWwpOw0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJY2FzZSBEQTkxNTBfR1BB
RENfQ0hBTl9WU1lTOg0KPiA+ICsJCXJldCA9IGRhOTE1MF9ncGFkY192c3lzXzZ2X3ZvbHRhZ2Vf
bm93KHJhd192YWwpOw0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ0hB
Tl9USlVOQ19DT1JFOg0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9USlVOQ19PVlA6DQo+
ID4gKwkJcmV0ID0gZGE5MTUwX2dwYWRjX3RqdW5jX3RlbXAocmF3X3ZhbCk7DQo+ID4gKwkJYnJl
YWs7DQo+ID4gKwlkZWZhdWx0Og0KPiA+ICsJCS8qIE5vIHByb2Nlc3NpbmcgZm9yIG90aGVyIGNo
YW5uZWxzIHNvIHJldHVybiByYXcgdmFsdWUgKi8NCj4gPiArCQlyZXQgPSByYXdfdmFsOw0KPiA+
ICsJCWJyZWFrOw0KPiA+ICsJfQ0KPiANCj4gYW5kIHNhdmUgdGhlIGZpbmFsIHJldHVybg0KDQpG
ZWx0IHRoaXMgd2FzIGEgbmljZXIgYXBwcm9hY2gsIGJ1dCBoYXZlIG5vIHN0cm9uZyBmZWVsaW5n
cyBlaXRoZXIgd2F5Lg0KDQo+ID4gKw0KPiA+ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsN
Cj4gPiAraW50IGRhOTE1MF9ncGFkY19yZWFkX3NjYWxlKGludCBjaGFubmVsKQ0KPiANCj4gc3Rh
dGljPw0KDQpZZXAuDQoNCj4gDQo+ID4gK3sNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ICsJ
c3dpdGNoIChjaGFubmVsKSB7DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19DSEFOX1ZCQVQ6DQo+
ID4gKwkJcmV0ID0gMjkzMjsNCj4gDQo+IHJldHVybiBkaXJlY3RseT8NCg0KQXMgYmVmb3JlLg0K
DQo+IA0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJZGVmYXVsdDoNCj4gPiArCQlyZXQgPSAtRUlOVkFM
Ow0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4g
K2ludCBkYTkxNTBfZ3BhZGNfcmVhZF9vZmZzZXQoaW50IGNoYW5uZWwpDQo+ID4gK3sNCj4gPiAr
CWludCByZXQ7DQo+ID4gKw0KPiA+ICsJc3dpdGNoIChjaGFubmVsKSB7DQo+ID4gKwljYXNlIERB
OTE1MF9HUEFEQ19DSEFOX1ZCQVQ6DQo+ID4gKwkJcmV0ID0gMTUwMDAwMCAvIDI5MzI7DQo+IA0K
PiByZXR1cm4gZGlyZWN0bHk/DQoNCkFzIGJlZm9yZS4NCg0KPiANCj4gPiArCQlicmVhazsNCj4g
PiArCWRlZmF1bHQ6DQo+ID4gKwkJcmV0ID0gLUVJTlZBTDsNCj4gPiArCX0NCj4gPiArDQo+ID4g
KwlyZXR1cm4gcmV0Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtpbnQgZGE5MTUwX2dwYWRjX3JlYWRf
cmF3KHN0cnVjdCBpaW9fZGV2ICppbmRpb19kZXYsDQo+ID4gKwkJCSAgc3RydWN0IGlpb19jaGFu
X3NwZWMgY29uc3QgKmNoYW4sDQo+ID4gKwkJCSAgaW50ICp2YWwsIGludCAqdmFsMiwgbG9uZyBt
YXNrKQ0KPiANCj4gc3RhdGljPw0KDQp5ZXAuDQoNCj4gDQo+ID4gK3sNCj4gPiArCXN0cnVjdCBk
YTkxNTBfZ3BhZGMgKmdwYWRjID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCj4gPiArCWludCByZXQ7
DQo+ID4gKw0KPiA+ICsJaWYgKChjaGFuLT5jaGFubmVsIDwgREE5MTUwX0dQQURDX0NIQU5fR1BJ
T0EpIHx8DQo+ID4gKwkgICAgKGNoYW4tPmNoYW5uZWwgPiBEQTkxNTBfR1BBRENfQ0hBTl9USlVO
Q19PVlApKQ0KPiA+ICsJCXJldHVybiAtRUlOVkFMOw0KPiA+ICsNCj4gPiArCXN3aXRjaCAobWFz
aykgew0KPiA+ICsJY2FzZSBJSU9fQ0hBTl9JTkZPX1JBVzoNCj4gPiArCWNhc2UgSUlPX0NIQU5f
SU5GT19QUk9DRVNTRUQ6DQo+ID4gKwkJcmV0ID0gZGE5MTUwX2dwYWRjX3JlYWRfcHJvY2Vzc2Vk
KGdwYWRjLCBjaGFuLT5jaGFubmVsLA0KPiA+ICsJCQkJCQkgIGNoYW4tPmFkZHJlc3MpOw0KPiA+
ICsJCWJyZWFrOw0KPiA+ICsJY2FzZSBJSU9fQ0hBTl9JTkZPX1NDQUxFOg0KPiA+ICsJCXJldCA9
IGRhOTE1MF9ncGFkY19yZWFkX3NjYWxlKGNoYW4tPmNoYW5uZWwpOw0KPiA+ICsJCWJyZWFrOw0K
PiA+ICsJY2FzZSBJSU9fQ0hBTl9JTkZPX09GRlNFVDoNCj4gPiArCQlyZXQgPSBkYTkxNTBfZ3Bh
ZGNfcmVhZF9vZmZzZXQoY2hhbi0+Y2hhbm5lbCk7DQo+ID4gKwkJYnJlYWs7DQo+ID4gKwlkZWZh
dWx0Og0KPiA+ICsJCXJldCA9IC1FSU5WQUw7DQo+ID4gKwkJYnJlYWs7DQo+ID4gKwl9DQo+ID4g
Kw0KPiA+ICsJaWYgKHJldCA8IDApDQo+ID4gKwkJcmV0dXJuIHJldDsNCj4gPiArDQo+ID4gKwkq
dmFsID0gcmV0Ow0KPiA+ICsNCj4gPiArCXJldHVybiBJSU9fVkFMX0lOVDsNCj4gPiArfQ0KPiA+
ICsNCj4gPiArc3RhdGljIGNvbnN0IHN0cnVjdCBpaW9faW5mbyBkYTkxNTBfZ3BhZGNfaW5mbyA9
IHsNCj4gPiArCS5yZWFkX3JhdyA9ICZkYTkxNTBfZ3BhZGNfcmVhZF9yYXcsDQo+ID4gKwkuZHJp
dmVyX21vZHVsZSA9IFRISVNfTU9EVUxFLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArI2RlZmluZSBH
UEFEQ19DSEFOTkVMKF9pZCwgX2h3X2lkLCBfdHlwZSwgY2hhbl9pbmZvLCBfZXh0X25hbWUpIHsJ
XA0KPiA+ICsJLnR5cGUgPSBfdHlwZSwJCQkJCQkJXA0KPiA+ICsJLmluZGV4ZWQgPSAxLAkJCQkJ
CQlcDQo+IA0KPiB0aGVyZSBpcyBvbmx5IG9uZSBjdXJyZW50IGNoYW5uZWwsIGl0IHNob3VsZCBu
b3QgYmUgaW5kZXhlZA0KDQpIYXZlIHJlc3BvbmRlZCB0byB0aGlzIGFnYWluc3QgSm9uYXRoYW4n
cyBtYWlsLg0KDQo+IA0KPiA+ICsJLmNoYW5uZWwgPSBEQTkxNTBfR1BBRENfQ0hBTl8jI19pZCwJ
CQkJXA0KPiA+ICsJLmFkZHJlc3MgPSBEQTkxNTBfR1BBRENfSFdfQ0hBTl8jI19od19pZCwJCQlc
DQo+ID4gKwkuaW5mb19tYXNrX3NlcGFyYXRlID0gY2hhbl9pbmZvLAkJCQlcDQo+ID4gKwkuZXh0
ZW5kX25hbWUgPSBfZXh0X25hbWUsCQkJCQlcDQo+ID4gKwkuZGF0YXNoZWV0X25hbWUgPSAjX2lk
LAkJCQkJCVwNCj4gPiArfQ0KPiA+ICsNCj4gPiArI2RlZmluZSBHUEFEQ19DSEFOTkVMX1JBVyhf
aWQsIF9od19pZCwgX3R5cGUsIF9leHRfbmFtZSkJXA0KPiA+ICsJR1BBRENfQ0hBTk5FTChfaWQs
IF9od19pZCwgX3R5cGUsIEJJVChJSU9fQ0hBTl9JTkZPX1JBVyksDQo+IF9leHRfbmFtZSkNCj4g
PiArDQo+ID4gKyNkZWZpbmUgR1BBRENfQ0hBTk5FTF9TQ0FMRUQoX2lkLCBfaHdfaWQsIF90eXBl
LCBfZXh0X25hbWUpCVwNCj4gPiArCUdQQURDX0NIQU5ORUwoX2lkLCBfaHdfaWQsIF90eXBlLAkJ
CVwNCj4gPiArCQkgICAgICBCSVQoSUlPX0NIQU5fSU5GT19SQVcpIHwJCQlcDQo+ID4gKwkJICAg
ICAgQklUKElJT19DSEFOX0lORk9fU0NBTEUpIHwJCVwNCj4gPiArCQkgICAgICBCSVQoSUlPX0NI
QU5fSU5GT19PRkZTRVQpLAkJXA0KPiA+ICsJCSAgICAgIF9leHRfbmFtZSkNCj4gPiArDQo+ID4g
KyNkZWZpbmUgR1BBRENfQ0hBTk5FTF9QUk9DRVNTRUQoX2lkLCBfaHdfaWQsIF90eXBlLCBfZXh0
X25hbWUpDQo+IAlcDQo+ID4gKwlHUEFEQ19DSEFOTkVMKF9pZCwgX2h3X2lkLCBfdHlwZSwgQklU
KElJT19DSEFOX0lORk9fUFJPQ0VTU0VEKSwJXA0KPiA+ICsJCSAgICAgIF9leHRfbmFtZSkNCj4g
PiArDQo+ID4gKy8qIFN1cHBvcnRlZCBjaGFubmVscyAqLw0KPiA+ICtzdGF0aWMgY29uc3Qgc3Ry
dWN0IGlpb19jaGFuX3NwZWMgZGE5MTUwX2dwYWRjX2NoYW5uZWxzW10gPSB7DQo+ID4gKwlHUEFE
Q19DSEFOTkVMX1BST0NFU1NFRChHUElPQSwgR1BJT0FfNVYsIElJT19WT0xUQUdFLCAiR1BJT0Ei
KSwNCj4gPiArCUdQQURDX0NIQU5ORUxfUFJPQ0VTU0VEKEdQSU9CLCBHUElPQl81ViwgSUlPX1ZP
TFRBR0UsICJHUElPQiIpLA0KPiA+ICsJR1BBRENfQ0hBTk5FTF9QUk9DRVNTRUQoR1BJT0MsIEdQ
SU9DXzVWLCBJSU9fVk9MVEFHRSwgIkdQSU9DIiksDQo+ID4gKwlHUEFEQ19DSEFOTkVMX1BST0NF
U1NFRChHUElPRCwgR1BJT0RfNVYsIElJT19WT0xUQUdFLCAiR1BJT0QiKSwNCj4gPiArCUdQQURD
X0NIQU5ORUxfUFJPQ0VTU0VEKElCVVMsIElCVVNfU0VOU0UsIElJT19DVVJSRU5ULCAiSUJVUyIp
LA0KPiA+ICsJR1BBRENfQ0hBTk5FTF9QUk9DRVNTRUQoVkJVUywgVkJVU19ESVZfLCBJSU9fVk9M
VEFHRSwgIlZCVVMiKSwNCj4gPiArCUdQQURDX0NIQU5ORUxfUkFXKElELCBJRCwgSUlPX1ZPTFRB
R0UsICJJRCIpLA0KPiA+ICsJR1BBRENfQ0hBTk5FTF9QUk9DRVNTRUQoVlNZUywgVlNZUywgSUlP
X1ZPTFRBR0UsICJWU1lTIiksDQo+ID4gKwlHUEFEQ19DSEFOTkVMX1NDQUxFRChWQkFULCBWQkFU
LCBJSU9fVk9MVEFHRSwgIlZCQVQiKSwNCj4gPiArCUdQQURDX0NIQU5ORUxfUkFXKFRCQVQsIFRC
QVQsIElJT19WT0xUQUdFLCAiVEJBVCIpLA0KPiA+ICsJR1BBRENfQ0hBTk5FTF9QUk9DRVNTRUQo
VEpVTkNfQ09SRSwgVEpVTkNfQ09SRSwgSUlPX1RFTVAsDQo+ICJUSlVOQ19DT1JFIiksDQo+ID4g
KwlHUEFEQ19DSEFOTkVMX1BST0NFU1NFRChUSlVOQ19PVlAsIFRKVU5DX09WUCwgSUlPX1RFTVAs
DQo+ICJUSlVOQ19PVlAiKSwNCj4gPiArfTsNCj4gPiArDQo+ID4gKy8qIERlZmF1bHQgbWFwcyB1
c2VkIGJ5IGRhOTE1MC1jaGFyZ2VyICovDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgaWlvX21hcCBkYTkx
NTBfZ3BhZGNfZGVmYXVsdF9tYXBzW10gPSB7DQo+ID4gKwl7DQo+ID4gKwkJLmNvbnN1bWVyX2Rl
dl9uYW1lID0gImRhOTE1MC1jaGFyZ2VyIiwNCj4gPiArCQkuY29uc3VtZXJfY2hhbm5lbCA9ICJD
SEFOX0lCVVMiLA0KPiA+ICsJCS5hZGNfY2hhbm5lbF9sYWJlbCA9ICJJQlVTIiwNCj4gPiArCX0s
DQo+ID4gKwl7DQo+ID4gKwkJLmNvbnN1bWVyX2Rldl9uYW1lID0gImRhOTE1MC1jaGFyZ2VyIiwN
Cj4gPiArCQkuY29uc3VtZXJfY2hhbm5lbCA9ICJDSEFOX1ZCVVMiLA0KPiA+ICsJCS5hZGNfY2hh
bm5lbF9sYWJlbCA9ICJWQlVTIiwNCj4gPiArCX0sDQo+ID4gKwl7DQo+ID4gKwkJLmNvbnN1bWVy
X2Rldl9uYW1lID0gImRhOTE1MC1jaGFyZ2VyIiwNCj4gPiArCQkuY29uc3VtZXJfY2hhbm5lbCA9
ICJDSEFOX1RKVU5DIiwNCj4gPiArCQkuYWRjX2NoYW5uZWxfbGFiZWwgPSAiVEpVTkNfQ09SRSIs
DQo+ID4gKwl9LA0KPiA+ICsJew0KPiA+ICsJCS5jb25zdW1lcl9kZXZfbmFtZSA9ICJkYTkxNTAt
Y2hhcmdlciIsDQo+ID4gKwkJLmNvbnN1bWVyX2NoYW5uZWwgPSAiQ0hBTl9WQkFUIiwNCj4gPiAr
CQkuYWRjX2NoYW5uZWxfbGFiZWwgPSAiVkJBVCIsDQo+ID4gKwl9LA0KPiA+ICsJe30sDQo+ID4g
K307DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGRhOTE1MF9ncGFkY19wcm9iZShzdHJ1Y3QgcGxh
dGZvcm1fZGV2aWNlICpwZGV2KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAm
cGRldi0+ZGV2Ow0KPiA+ICsJc3RydWN0IGRhOTE1MCAqZGE5MTUwID0gZGV2X2dldF9kcnZkYXRh
KGRldi0+cGFyZW50KTsNCj4gPiArCXN0cnVjdCBkYTkxNTBfZ3BhZGMgKmdwYWRjOw0KPiA+ICsJ
c3RydWN0IGlpb19kZXYgKmluZGlvX2RldjsNCj4gPiArCWludCByZXQ7DQo+ID4gKw0KPiA+ICsJ
aW5kaW9fZGV2ID0gZGV2bV9paW9fZGV2aWNlX2FsbG9jKCZwZGV2LT5kZXYsDQo+ID4gKwkJCQkJ
ICBzaXplb2Yoc3RydWN0IGRhOTE1MF9ncGFkYykpOw0KPiA+ICsJaWYgKCFpbmRpb19kZXYpIHsN
Cj4gPiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJGYWlsZWQgdG8gYWxsb2NhdGUgSUlPIGRldmlj
ZVxuIik7DQo+ID4gKwkJcmV0dXJuIC1FTk9NRU07DQo+ID4gKwl9DQo+ID4gKwlncGFkYyA9IGlp
b19wcml2KGluZGlvX2Rldik7DQo+ID4gKw0KPiA+ICsJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRl
diwgaW5kaW9fZGV2KTsNCj4gPiArCWdwYWRjLT5kYTkxNTAgPSBkYTkxNTA7DQo+ID4gKwlncGFk
Yy0+ZGV2ID0gZGV2Ow0KPiA+ICsNCj4gPiArCXJldCA9IGlpb19tYXBfYXJyYXlfcmVnaXN0ZXIo
aW5kaW9fZGV2LCBkYTkxNTBfZ3BhZGNfZGVmYXVsdF9tYXBzKTsNCj4gPiArCWlmIChyZXQpIHsN
Cj4gPiArCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byByZWdpc3RlciBJSU8gbWFwczogJWRcbiIs
IHJldCk7DQo+ID4gKwkJZ290byBpaW9fbWFwX2ZhaWw7DQo+IA0KPiBqdXN0IHJldHVybiBoZXJl
Pw0KDQpSaWdodCwgZmluZS4NCg0KPiANCj4gPiArCX0NCj4gPiArDQo+ID4gKwltdXRleF9pbml0
KCZncGFkYy0+bG9jayk7DQo+ID4gKwlpbml0X2NvbXBsZXRpb24oJmdwYWRjLT5jb21wbGV0ZSk7
DQo+ID4gKw0KPiA+ICsJLyogUmVnaXN0ZXIgSVJRICovDQo+ID4gKwlyZXQgPSBkYTkxNTBfcmVn
aXN0ZXJfaXJxKHBkZXYsIGdwYWRjLCBkYTkxNTBfZ3BhZGNfaXJxLCAiR1BBREMiKTsNCj4gPiAr
CWlmIChyZXQgPCAwKQ0KPiA+ICsJCWdvdG8gaXJxX2ZhaWw7DQo+ID4gKw0KPiA+ICsJaW5kaW9f
ZGV2LT5uYW1lID0gZGV2X25hbWUoZGV2KTsNCj4gPiArCWluZGlvX2Rldi0+ZGV2LnBhcmVudCA9
IGRldjsNCj4gPiArCWluZGlvX2Rldi0+ZGV2Lm9mX25vZGUgPSBwZGV2LT5kZXYub2Zfbm9kZTsN
Cj4gPiArCWluZGlvX2Rldi0+aW5mbyA9ICZkYTkxNTBfZ3BhZGNfaW5mbzsNCj4gPiArCWluZGlv
X2Rldi0+bW9kZXMgPSBJTkRJT19ESVJFQ1RfTU9ERTsNCj4gPiArCWluZGlvX2Rldi0+Y2hhbm5l
bHMgPSBkYTkxNTBfZ3BhZGNfY2hhbm5lbHM7DQo+ID4gKwlpbmRpb19kZXYtPm51bV9jaGFubmVs
cyA9IEFSUkFZX1NJWkUoZGE5MTUwX2dwYWRjX2NoYW5uZWxzKTsNCj4gPiArDQo+ID4gKwlyZXQg
PSBpaW9fZGV2aWNlX3JlZ2lzdGVyKGluZGlvX2Rldik7DQo+ID4gKwlpZiAocmV0KSB7DQo+ID4g
KwkJZGV2X2VycihkZXYsICJGYWlsZWQgdG8gcmVnaXN0ZXIgSUlPIGRldmljZTogJWRcbiIsIHJl
dCk7DQo+ID4gKwkJZ290byBpaW9fZGV2X2ZhaWw7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0
dXJuIHJldDsNCj4gPiArDQo+ID4gK2lpb19kZXZfZmFpbDoNCj4gPiAraXJxX2ZhaWw6DQo+IA0K
PiB3aHkgdHdvIGxhYmVscz8NCg0KTGFiZWxzIHJlZmVyZXJyZWQgdG8gdGhlIHR5cGUgb2YgZmFp
bHVyZSwgYnV0IGJvdGggcmVxdWlyZWQgc2FtZSBjbGVhbi11cCByb3V0ZS4NCkNhbiBjaGFuZ2Ug
dGhvdWdoIHRvIHJlbW92ZSBvbmUuDQoNCj4gDQo+ID4gKwlpaW9fbWFwX2FycmF5X3VucmVnaXN0
ZXIoaW5kaW9fZGV2KTsNCj4gPiArDQo+ID4gK2lpb19tYXBfZmFpbDoNCj4gPiArCXJldHVybiBy
ZXQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgZGE5MTUwX2dwYWRjX3JlbW92ZShz
dHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgaWlvX2Rl
diAqaW5kaW9fZGV2ID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRldik7DQo+ID4gKw0KPiA+ICsJ
aWlvX21hcF9hcnJheV91bnJlZ2lzdGVyKGluZGlvX2Rldik7DQo+IA0KPiB1bnJlZ2lzdGVyIGly
cT8NCg0KdXNlcyBkZXZtIG1lY2hhbmlzbSwgYWx0aG91Z2ggdGhhdCdzIG5vdCBvYnZpb3VzIHVu
bGVzcyB5b3UgbG9vayBhdCBNRkQNCmhlbHBlciBmdW5jdGlvbnMuIFdpbGwgdXBkYXRlIG5hbWlu
ZyB0byBpbmRpY2F0ZSBhY2NvcmRpbmdseS4NCg0KPiANCj4gPiArCWlpb19kZXZpY2VfdW5yZWdp
c3RlcihpbmRpb19kZXYpOw0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0K
PiA+ICtzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2RyaXZlciBkYTkxNTBfZ3BhZGNfZHJpdmVyID0g
ew0KPiA+ICsJLmRyaXZlciA9IHsNCj4gPiArCQkubmFtZSA9ICJkYTkxNTAtZ3BhZGMiLA0KPiA+
ICsJCS5vd25lciA9IFRISVNfTU9EVUxFLA0KPiA+ICsJfSwNCj4gPiArCS5wcm9iZSA9IGRhOTE1
MF9ncGFkY19wcm9iZSwNCj4gPiArCS5yZW1vdmUgPSBkYTkxNTBfZ3BhZGNfcmVtb3ZlLA0KPiA+
ICt9Ow0KPiA+ICsNCj4gPiArbW9kdWxlX3BsYXRmb3JtX2RyaXZlcihkYTkxNTBfZ3BhZGNfZHJp
dmVyKTsNCj4gPiArDQo+ID4gK01PRFVMRV9ERVNDUklQVElPTigiR1BBREMgRHJpdmVyIGZvciBE
QTkxNTAiKTsNCj4gPiArTU9EVUxFX0FVVEhPUigiQWRhbSBUaG9tc29uDQo+IDxBZGFtLlRob21z
b24uT3BlbnNvdXJjZUBkaWFzZW1pLmNvbSIpOw0KPiA+ICtNT0RVTEVfTElDRU5TRSgiR1BMIik7
DQo+ID4gLS0NCj4gPiAxLjkuMw0KPiA+DQo+ID4gLS0NCj4gPiBUbyB1bnN1YnNjcmliZSBmcm9t
IHRoaXMgbGlzdDogc2VuZCB0aGUgbGluZSAidW5zdWJzY3JpYmUgbGludXgta2VybmVsIiBpbg0K
PiA+IHRoZSBib2R5IG9mIGEgbWVzc2FnZSB0byBtYWpvcmRvbW9Admdlci5rZXJuZWwub3JnDQo+
ID4gTW9yZSBtYWpvcmRvbW8gaW5mbyBhdCAgaHR0cDovL3ZnZXIua2VybmVsLm9yZy9tYWpvcmRv
bW8taW5mby5odG1sDQo+ID4gUGxlYXNlIHJlYWQgdGhlIEZBUSBhdCAgaHR0cDovL3d3dy50dXgu
b3JnL2xrbWwvDQo+ID4NCj4gDQo+IC0tDQo+IA0KPiBQZXRlciBNZWVyd2FsZA0KPiArNDMtNjY0
LTI0NDQ0MTggKG1vYmlsZSkNCg==

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

* RE: [PATCH v2 3/7] iio: Add support for DA9150 GPADC
  2014-08-30 20:01     ` Jonathan Cameron
@ 2014-09-09 10:53       ` Opensource [Adam Thomson]
  2014-09-14 17:26         ` Jonathan Cameron
  0 siblings, 1 reply; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-09 10:53 UTC (permalink / raw)
  To: Jonathan Cameron, Peter Meerwald, Opensource [Adam Thomson]
  Cc: Lee Jones, linux-iio, Support Opensource

T24gQXVndXN0IDMwLCAyMDE0IDIxOjAxLCBKb25hdGhhbiBDYW1lcm9uIHdyb3RlOg0KDQo+IE9u
IDI4LzA4LzE0IDEyOjI4LCBQZXRlciBNZWVyd2FsZCB3cm90ZToNCj4gPg0KPiA+IHNvbWUgbWlu
b3IgY29tbWVudHMgaW5saW5lDQo+IEEgZmV3IG1vcmUgZnJvbSBtZSArIG1ha2Ugc3VyZSBhbGwg
eW91ciB1bml0cyBtYXRjaCB0aGUgQUJJIGFuZCBpbg0KPiBwYXJ0aWN1bGFyIHRoYXQgZXZlcnl0
aGluZyB5b3UgdXNlIGlzIGRvY3VtZW50ZWQgaW4NCj4gRG9jdW1lbnRhdGlvbi9BQkkvdGVzdGlu
Zy9zeWZzLWJ1cy1paW8uICBTb21lIHN0dWZmIHRoYXQgb25seQ0KPiBleGlzdHMgaW4gc3RhZ2lu
ZyBkcml2ZXJzIGlzbid0IGRvY3VtZW50ZWQgaW4gdGhlcmUgYXMgeWV0DQo+IChjdXJyZW50IG1l
YXN1cmVtZW50cyBmb3IgZXhhbXBsZSkgc28gdGhlIGRvY3Mgd2lsbCBuZWVkIGFkZGl0aW9ucw0K
PiBhbG9uZ3NpZGUgdGhpcyBkcml2ZXIuDQo+IA0KPiBUaGFua3MsDQo+IA0KPiBKb25hdGhhbg0K
PiA+DQo+ID4+IFRoaXMgcGF0Y2ggYWRkcyBzdXBwb3J0IGZvciBEQTkxNTAgQ2hhcmdlciAmIEZ1
ZWwtR2F1Z2UgSUMgR1BBREMuDQo+ID4+DQo+ID4+IFNpZ25lZC1vZmYtYnk6IEFkYW0gVGhvbXNv
biA8QWRhbS5UaG9tc29uLk9wZW5zb3VyY2VAZGlhc2VtaS5jb20+DQo+ID4+IC0tLQ0KPiA+PiAg
ZHJpdmVycy9paW8vYWRjL0tjb25maWcgICAgICAgIHwgICA5ICsNCj4gPj4gIGRyaXZlcnMvaWlv
L2FkYy9NYWtlZmlsZSAgICAgICB8ICAgMSArDQo+ID4+ICBkcml2ZXJzL2lpby9hZGMvZGE5MTUw
LWdwYWRjLmMgfCA0MzANCj4gKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr
KysNCj4gPj4gIDMgZmlsZXMgY2hhbmdlZCwgNDQwIGluc2VydGlvbnMoKykNCj4gPj4gIGNyZWF0
ZSBtb2RlIDEwMDY0NCBkcml2ZXJzL2lpby9hZGMvZGE5MTUwLWdwYWRjLmMNCj4gPj4NCj4gPj4g
ZGlmZiAtLWdpdCBhL2RyaXZlcnMvaWlvL2FkYy9LY29uZmlnIGIvZHJpdmVycy9paW8vYWRjL0tj
b25maWcNCj4gPj4gaW5kZXggMTFiMDQ4YS4uODA0MTM0NyAxMDA2NDQNCj4gPj4gLS0tIGEvZHJp
dmVycy9paW8vYWRjL0tjb25maWcNCj4gPj4gKysrIGIvZHJpdmVycy9paW8vYWRjL0tjb25maWcN
Cj4gPj4gQEAgLTEyNyw2ICsxMjcsMTUgQEAgY29uZmlnIEFUOTFfQURDDQo+ID4+ICAJaGVscA0K
PiA+PiAgCSAgU2F5IHllcyBoZXJlIHRvIGJ1aWxkIHN1cHBvcnQgZm9yIEF0bWVsIEFUOTEgQURD
Lg0KPiA+Pg0KPiA+PiArY29uZmlnIERBOTE1MF9HUEFEQw0KPiA+PiArCXRyaXN0YXRlICJEaWFs
b2cgREE5MTUwIEdQQURDIGRyaXZlciBzdXBwb3J0Ig0KPiA+PiArCWRlcGVuZHMgb24gTUZEX0RB
OTE1MA0KPiA+PiArCWhlbHANCj4gPj4gKwkgIFNheSB5ZXMgaGVyZSB0byBidWlsZCBzdXBwb3J0
IGZvciBEaWFsb2cgREE5MTUwIEdQQURDLg0KPiA+PiArDQo+ID4+ICsJICBUaGlzIGRyaXZlciBj
YW4gYWxzbyBiZSBidWlsdCBhcyBhIG1vZHVsZS4gSWYgY2hvc2VuLCB0aGUgbW9kdWxlIG5hbWUN
Cj4gPj4gKwkgIHdpbGwgYmUgZGE5MTUwLWdwYWRjLg0KPiA+PiArDQo+ID4+ICBjb25maWcgRVhZ
Tk9TX0FEQw0KPiA+PiAgCXRyaXN0YXRlICJFeHlub3MgQURDIGRyaXZlciBzdXBwb3J0Ig0KPiA+
PiAgCWRlcGVuZHMgb24gQVJDSF9FWFlOT1MgfHwgKE9GICYmIENPTVBJTEVfVEVTVCkNCj4gPj4g
ZGlmZiAtLWdpdCBhL2RyaXZlcnMvaWlvL2FkYy9NYWtlZmlsZSBiL2RyaXZlcnMvaWlvL2FkYy9N
YWtlZmlsZQ0KPiA+PiBpbmRleCBhZDgxYjUxLi40ODQxM2QyIDEwMDY0NA0KPiA+PiAtLS0gYS9k
cml2ZXJzL2lpby9hZGMvTWFrZWZpbGUNCj4gPj4gKysrIGIvZHJpdmVycy9paW8vYWRjL01ha2Vm
aWxlDQo+ID4+IEBAIC0xNCw2ICsxNCw3IEBAIG9iai0kKENPTkZJR19BRDc3OTMpICs9IGFkNzc5
My5vDQo+ID4+ICBvYmotJChDT05GSUdfQUQ3ODg3KSArPSBhZDc4ODcubw0KPiA+PiAgb2JqLSQo
Q09ORklHX0FENzk5WCkgKz0gYWQ3OTl4Lm8NCj4gPj4gIG9iai0kKENPTkZJR19BVDkxX0FEQykg
Kz0gYXQ5MV9hZGMubw0KPiA+PiArb2JqLSQoQ09ORklHX0RBOTE1MF9HUEFEQykgKz0gZGE5MTUw
LWdwYWRjLm8NCj4gPj4gIG9iai0kKENPTkZJR19FWFlOT1NfQURDKSArPSBleHlub3NfYWRjLm8N
Cj4gPj4gIG9iai0kKENPTkZJR19MUDg3ODhfQURDKSArPSBscDg3ODhfYWRjLm8NCj4gPj4gIG9i
ai0kKENPTkZJR19NQVgxMDI3KSArPSBtYXgxMDI3Lm8NCj4gPj4gZGlmZiAtLWdpdCBhL2RyaXZl
cnMvaWlvL2FkYy9kYTkxNTAtZ3BhZGMuYyBiL2RyaXZlcnMvaWlvL2FkYy9kYTkxNTAtZ3BhZGMu
Yw0KPiA+PiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+PiBpbmRleCAwMDAwMDAwLi4yMWEyMWE5
DQo+ID4+IC0tLSAvZGV2L251bGwNCj4gPj4gKysrIGIvZHJpdmVycy9paW8vYWRjL2RhOTE1MC1n
cGFkYy5jDQo+ID4+IEBAIC0wLDAgKzEsNDMwIEBADQo+ID4+ICsvKg0KPiA+PiArICogREE5MTUw
IEdQQURDIERyaXZlcg0KPiA+PiArICoNCj4gPj4gKyAqIENvcHlyaWdodCAoYykgMjAxNCBEaWFs
b2cgU2VtaWNvbmR1Y3Rvcg0KPiA+PiArICoNCj4gPj4gKyAqIEF1dGhvcjogQWRhbSBUaG9tc29u
IDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNvbT4NCj4gPj4gKyAqDQo+ID4+ICsg
KiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgIGl0
IGFuZC9vciBtb2RpZnkgaXQNCj4gPj4gKyAqIHVuZGVyICB0aGUgdGVybXMgb2YgIHRoZSBHTlUg
R2VuZXJhbCAgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZQ0KPiA+PiArICogRnJl
ZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyAgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUgIExpY2Vuc2Us
IG9yIChhdCB5b3VyDQo+ID4+ICsgKiBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLg0KPiA+PiAr
ICovDQo+ID4+ICsNCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9rZXJuZWwuaD4NCj4gPj4gKyNpbmNs
dWRlIDxsaW51eC9zbGFiLmg+DQo+ID4+ICsjaW5jbHVkZSA8bGludXgvbW9kdWxlLmg+DQo+ID4+
ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGV2aWNlLmg+DQo+ID4+ICsjaW5jbHVkZSA8bGlu
dXgvaW50ZXJydXB0Lmg+DQo+ID4+ICsNCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9tZmQvZGE5MTUw
L2NvcmUuaD4NCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9tZmQvZGE5MTUwL3BkYXRhLmg+DQo+ID4+
ICsjaW5jbHVkZSA8bGludXgvbWZkL2RhOTE1MC9yZWdpc3RlcnMuaD4NCj4gPj4gKw0KPiA+PiAr
I2luY2x1ZGUgPGxpbnV4L2lpby9paW8uaD4NCj4gPj4gKyNpbmNsdWRlIDxsaW51eC9paW8vbWFj
aGluZS5oPg0KPiA+PiArI2luY2x1ZGUgPGxpbnV4L2lpby9kcml2ZXIuaD4NCj4gPj4gKw0KPiA+
PiArDQo+ID4+ICsvKiBDaGFubmVscyAqLw0KPiA+PiArZW51bSBkYTkxNTBfZ3BhZGNfaHdfY2hh
bm5lbCB7DQo+ID4+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0FfMlYgPSAwLA0KPiA+PiAr
CURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9BXzJWXywNCj4gPg0KPiA+IHdoeSB0aGUgdW5kZXJz
Y29yZV8gbm90YXRpb24/DQo+ID4gY291bGRuJ3QgeW91IHVzZSBlLmcuIERBOTE1MF9HUEFEQ19I
V19DSEFOX0dQSU9CXzJWID0gMj8NCj4gPg0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQ
SU9CXzJWLA0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9CXzJWXywNCj4gPj4gKwlE
QTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPQ18yViwNCj4gPj4gKwlEQTkxNTBfR1BBRENfSFdfQ0hB
Tl9HUElPQ18yVl8sDQo+ID4+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0RfMlYsDQo+ID4+
ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0RfMlZfLA0KPiA+PiArCURBOTE1MF9HUEFEQ19I
V19DSEFOX0lCVVNfU0VOU0UsDQo+ID4+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fSUJVU19TRU5T
RV8sDQo+ID4+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fVkJVU19ESVYsDQo+ID4+ICsJREE5MTUw
X0dQQURDX0hXX0NIQU5fVkJVU19ESVZfLA0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0lE
LA0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0lEXywNCj4gPj4gKwlEQTkxNTBfR1BBRENf
SFdfQ0hBTl9WU1lTLA0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19DSEFOX1ZTWVNfLA0KPiA+PiAr
CURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9BXzVWLA0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19D
SEFOX0dQSU9BXzVWXywNCj4gPj4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPQl81ViwNCj4g
Pj4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPQl81Vl8sDQo+ID4+ICsJREE5MTUwX0dQQURD
X0hXX0NIQU5fR1BJT0NfNVYsDQo+ID4+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0NfNVZf
LA0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9EXzVWLA0KPiA+PiArCURBOTE1MF9H
UEFEQ19IV19DSEFOX0dQSU9EXzVWXywNCj4gPj4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9WQkFU
LA0KPiA+PiArCURBOTE1MF9HUEFEQ19IV19DSEFOX1ZCQVRfLA0KPiA+PiArCURBOTE1MF9HUEFE
Q19IV19DSEFOX1RCQVQsDQo+ID4+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fVEJBVF8sDQo+ID4+
ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fVEpVTkNfQ09SRSwNCj4gPj4gKwlEQTkxNTBfR1BBRENf
SFdfQ0hBTl9USlVOQ19DT1JFXywNCj4gPj4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9USlVOQ19P
VlAsDQo+ID4+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fVEpVTkNfT1ZQXywNCj4gPj4gK307DQo+
ID4+ICsNCj4gPj4gK2VudW0gZGE5MTUwX2dwYWRjX2NoYW5uZWwgew0KPiA+PiArCURBOTE1MF9H
UEFEQ19DSEFOX0dQSU9BID0gMCwNCj4gPj4gKwlEQTkxNTBfR1BBRENfQ0hBTl9HUElPQiwNCj4g
Pj4gKwlEQTkxNTBfR1BBRENfQ0hBTl9HUElPQywNCj4gPj4gKwlEQTkxNTBfR1BBRENfQ0hBTl9H
UElPRCwNCj4gPj4gKwlEQTkxNTBfR1BBRENfQ0hBTl9JQlVTLA0KPiA+PiArCURBOTE1MF9HUEFE
Q19DSEFOX1ZCVVMsDQo+ID4+ICsJREE5MTUwX0dQQURDX0NIQU5fSUQsDQo+ID4+ICsJREE5MTUw
X0dQQURDX0NIQU5fVlNZUywNCj4gPj4gKwlEQTkxNTBfR1BBRENfQ0hBTl9WQkFULA0KPiA+PiAr
CURBOTE1MF9HUEFEQ19DSEFOX1RCQVQsDQo+ID4+ICsJREE5MTUwX0dQQURDX0NIQU5fVEpVTkNf
Q09SRSwNCj4gPj4gKwlEQTkxNTBfR1BBRENfQ0hBTl9USlVOQ19PVlAsDQo+ID4+ICt9Ow0KPiA+
PiArDQo+ID4+ICsvKiBQcml2YXRlIGRhdGEgKi8NCj4gPj4gK3N0cnVjdCBkYTkxNTBfZ3BhZGMg
ew0KPiA+PiArCXN0cnVjdCBkYTkxNTAgKmRhOTE1MDsNCj4gPj4gKwlzdHJ1Y3QgZGV2aWNlICpk
ZXY7DQo+ID4+ICsNCj4gPj4gKwlzdHJ1Y3QgbXV0ZXggbG9jazsNCj4gPj4gKwlzdHJ1Y3QgY29t
cGxldGlvbiBjb21wbGV0ZTsNCj4gPj4gK307DQo+ID4+ICsNCj4gPj4gKw0KPiA+PiArc3RhdGlj
IGlycXJldHVybl90IGRhOTE1MF9ncGFkY19pcnEoaW50IGlycSwgdm9pZCAqZGF0YSkNCj4gPj4g
K3sNCj4gPj4gKw0KPiA+PiArCXN0cnVjdCBkYTkxNTBfZ3BhZGMgKmdwYWRjID0gZGF0YTsNCj4g
Pj4gKw0KPiA+PiArCWNvbXBsZXRlKCZncGFkYy0+Y29tcGxldGUpOw0KPiA+PiArDQo+ID4+ICsJ
cmV0dXJuIElSUV9IQU5ETEVEOw0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtpbnQgZGE5MTUwX2dw
YWRjX3JlYWRfYWRjKHN0cnVjdCBkYTkxNTBfZ3BhZGMgKmdwYWRjLCBpbnQgaHdfY2hhbikNCj4g
Pg0KPiA+IHN0YXRpYz8NCj4gPg0KPiA+PiArew0KPiA+PiArCXU4IHJlc3VsdF9yZWdzWzJdOw0K
PiA+PiArCWludCByZXN1bHQ7DQo+ID4+ICsNCj4gPj4gKwltdXRleF9sb2NrKCZncGFkYy0+bG9j
ayk7DQo+ID4+ICsNCj4gPj4gKwkvKiBTZXQgY2hhbm5lbCAmIGVuYWJsZSBtZWFzdXJlbWVudCAq
Lw0KPiA+PiArCWRhOTE1MF9yZWdfd3JpdGUoZ3BhZGMtPmRhOTE1MCwgREE5MTUwX0dQQURDX01B
TiwNCj4gPj4gKwkJCSAoREE5MTUwX0dQQURDX0VOX01BU0sgfA0KPiA+PiArCQkJICBod19jaGFu
IDw8IERBOTE1MF9HUEFEQ19NVVhfU0hJRlQpKTsNCj4gPj4gKw0KPiA+PiArCS8qIENvbnN1bWUg
bGVmdC1vdmVyIGNvbXBsZXRpb24gZnJvbSBhIHByZXZpb3VzIHRpbWVvdXQgKi8NCj4gPj4gKwl0
cnlfd2FpdF9mb3JfY29tcGxldGlvbigmZ3BhZGMtPmNvbXBsZXRlKTsNCj4gPj4gKw0KPiA+PiAr
CS8qIENoZWNrIGZvciBhY3R1YWwgY29tcGxldGlvbiAqLw0KPiA+PiArCXdhaXRfZm9yX2NvbXBs
ZXRpb25fdGltZW91dCgmZ3BhZGMtPmNvbXBsZXRlLCBtc2Vjc190b19qaWZmaWVzKDUpKTsNCj4g
Pj4gKw0KPiA+PiArCS8qIFJlYWQgcmVzdWx0IGFuZCBzdGF0dXMgZnJvbSBkZXZpY2UgKi8NCj4g
Pj4gKwlkYTkxNTBfYnVsa19yZWFkKGdwYWRjLT5kYTkxNTAsIERBOTE1MF9HUEFEQ19SRVNfQSwg
MiwgcmVzdWx0X3JlZ3MpOw0KPiA+PiArDQo+ID4+ICsJbXV0ZXhfdW5sb2NrKCZncGFkYy0+bG9j
ayk7DQo+ID4+ICsNCj4gPj4gKwkvKiBDaGVjayB0byBtYWtlIHN1cmUgZGV2aWNlIHJlYWxseSBo
YXMgY29tcGxldGVkIHJlYWRpbmcgKi8NCj4gPj4gKwlpZiAocmVzdWx0X3JlZ3NbMV0gJiBEQTkx
NTBfR1BBRENfUlVOX01BU0spIHsNCj4gPj4gKwkJZGV2X2VycihncGFkYy0+ZGV2LCAiVGltZW91
dCBvbiBjaGFubmVsICVkIG9mIEdQLUFEQ1xuIiwNCj4gPg0KPiA+IEdQQURDIGV2ZXJ5d2hlcmUg
ZWxzZQ0KPiA+DQo+ID4+ICsJCQlod19jaGFuKTsNCj4gPj4gKwkJcmV0dXJuIC1FVElNRURPVVQ7
DQo+ID4+ICsJfQ0KPiA+PiArDQo+ID4+ICsJLyogTFNCcyAtIDIgYml0cyAqLw0KPiA+PiArCXJl
c3VsdCA9IChyZXN1bHRfcmVnc1sxXSAmIERBOTE1MF9HUEFEQ19SRVNfTF9NQVNLKSA+Pg0KPiA+
PiArCQkgREE5MTUwX0dQQURDX1JFU19MX1NISUZUOw0KPiA+PiArCS8qIE1TQnMgLSA4IGJpdHMg
Ki8NCj4gPj4gKwlyZXN1bHQgfD0gcmVzdWx0X3JlZ3NbMF0gPDwgREE5MTUwX0dQQURDX1JFU19M
X0JJVFM7DQo+ID4NCj4gPiBjYW4ndCB0aGUgcmVhZCBiZSBkb25lIHdpdGggYSAxNmJpdCByZWFk
Pw0KPiA+DQo+ID4+ICsNCj4gPj4gKwlyZXR1cm4gcmVzdWx0Ow0KPiA+PiArfQ0KPiA+PiArDQo+
ID4+ICtzdGF0aWMgaW5saW5lIGludCBkYTkxNTBfZ3BhZGNfZ3Bpb181dl92b2x0YWdlX25vdyhp
bnQgcmF3X3ZhbCkNCj4gPj4gK3sNCj4gPj4gKwkvKiBDb252ZXJ0IHRvIHVWICovDQo+ID4+ICsJ
cmV0dXJuICgoKDYgKiAoKHJhd192YWwgKiAxMDAwKSArIDUwMCkpIC8gMTAyNCkgKiAxMDAwKTsN
Cj4gQmFzZSB1bml0cyBvZiB2b2x0YWdlIGFyZSBtaWxsaXZvbHRzLiAgU2VlIERvY3VtZW50YXRp
b24vQUJJL3Rlc3Rpbmcvc3lzZnMtYnVzLWlpby4NCg0KUmlnaHQuIE9rLg0KDQo+ID4NCj4gPiBv
dXRlciBwYXJlbnRoZXNpcyBub3QgbmVlZGVkLCBoZXJlIGFuZCBiZWxvdw0KPiA+DQo+ID4+ICt9
DQo+ID4+ICsNCj4gPj4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1MF9ncGFkY19pYnVzX2N1cnJl
bnRfYXZnKGludCByYXdfdmFsKQ0KPiA+PiArew0KPiA+PiArCS8qIENvbnZlcnQgdG8gdUEgKi8N
Cj4gPj4gKwlyZXR1cm4gKCgoNCAqICgocmF3X3ZhbCAqIDEwMDApICsgNTAwKSkgLyAyMDQ4KSAq
IDEwMDApOw0KPiBpbnRlcmVzdGluZ2x5IHRoaXMgaXMgYWN0dWFsbHkgb3VyIGZpcnN0IGN1cnJl
bnQgY2hhbm5lbCBvdXRzaWRlIHN0YWdpbmcuDQo+IEFzIHN1Y2ggdGhlIGRvY3MgZG9uJ3QgY292
ZXIgaXQuICBQbGVhc2UgYWRkLCBrZWVwaW5nIGlubGluZSB3aXRoIHRoZQ0KPiB1bml0cyB1c2Vk
IGluIGh3bW9uLiBtQSwgSUlSQw0KDQpSaWdodCwgb2suDQoNCj4gPj4gK30NCj4gPj4gKw0KPiA+
PiArc3RhdGljIGlubGluZSBpbnQgZGE5MTUwX2dwYWRjX3ZidXNfMjF2X3ZvbHRhZ2Vfbm93KGlu
dCByYXdfdmFsKQ0KPiA+PiArew0KPiA+PiArCS8qIENvbnZlcnQgdG8gdVYgKi8NCj4gPj4gKwly
ZXR1cm4gKCgoMjEgKiAoKHJhd192YWwgKiAxMDAwKSArIDUwMCkpIC8gMTAyNCkgKiAxMDAwKTsN
Cj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIGlubGluZSBpbnQgZGE5MTUwX2dwYWRjX3Zz
eXNfNnZfdm9sdGFnZV9ub3coaW50IHJhd192YWwpDQo+ID4+ICt7DQo+ID4+ICsJLyogQ29udmVy
dCB0byB1ViAqLw0KPiA+PiArCXJldHVybiAoKCgzICogKChyYXdfdmFsICogMTAwMCkgKyA1MDAp
KSAvIDUxMikgKiAxMDAwKTsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIGlubGluZSBp
bnQgZGE5MTUwX2dwYWRjX3RqdW5jX3RlbXAoaW50IHJhd192YWwpDQo+ID4+ICt7DQo+ID4+ICsJ
LyogQ29udmVydCB0byAwLjEgZGVncmVlcyBDICovDQo+ID4NCj4gPiBJSU8gd2FudHMgbWlsbGUg
ZGVncmVlcyBDDQo+IEV4YWN0bHkuICBQbGVhc2UgY2hlY2sgYWxsIG9mIHRoZXNlIGNvcnJlc3Bv
bmQgdG8gdGhlIGJhc2UgdW5pdHMgcmVxdWlyZWQNCj4gYnkgdGhlIGRvY3VtZW50YXRpb24uICBN
b3N0IG9mIHRoZXNlIG1pZ2h0IGJlIGJldHRlciBoYW5kbGVkIGFzIHJhdw0KPiB3aXRoIHNjYWxl
IGFuZCBvZmZzZXQgcHJvdmlkZWQsIGxldHRpbmcgdGhlIG1hdGhzIGJlIGRvaW5nIGluIHVzZXJz
cGFjZSB1c2luZw0KPiBmbG9hdGluZyBwb2ludC4NCg0KU29tZSBhcmUgbmVlZGVkIGJ5IHRoZSBj
aGFyZ2VyIGRyaXZlci4gVGhlIGludGVudGlvbiBvZiBhZGRpbmcgdGhlIGNvbnZlcnNpb25zDQpo
ZXJlIHdhcyBzbyB0aGlzIGtub3dsZWRnZSB3YXMgbm90IG5lZWRlZCBpbiB0aGUgY2hhcmdlciBk
cml2ZXIuIFNlZW1zIHdyb25nIHRvDQptb3ZlIHRoZSBjYWxjdWxhdGlvbnMgb3V0IG9mIHRoZSBJ
SU8gZHJpdmVyLiBNb3N0IG9mIHRoZXNlIGFyZSBub3Qgc2ltcGxlIGxpbmVhcg0Kc28gc2NhbGUg
YW5kIG9mZnNldCB3aWxsIG5vdCB3b3JrLCB1bmxlc3MgSSdtIG1pc3Npbmcgc29tZXRoaW5nLg0K
DQo+ID4NCj4gPj4gKwlyZXR1cm4gKCgoODc5IC0gKDEwMjMgLSByYXdfdmFsKSkgKiAxMDAwMCkg
LyA0NDIwKTsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiArc3RhdGljIGlubGluZSBpbnQgZGE5MTUw
X2dwYWRjX3ZiYXRfdm9sdGFnZV9ub3coaW50IHJhd192YWwpDQo+ID4+ICt7DQo+ID4+ICsJLyog
Q29udmVydCB0byB1ViAqLw0KPiA+PiArCXJldHVybiAoKDI5MzIgKiByYXdfdmFsKSArIDE1MDAw
MDApOw0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtpbnQgZGE5MTUwX2dwYWRjX3JlYWRfcHJvY2Vz
c2VkKHN0cnVjdCBkYTkxNTBfZ3BhZGMgKmdwYWRjLCBpbnQgY2hhbm5lbCwNCj4gPj4gKwkJCQlp
bnQgaHdfY2hhbikNCj4gPg0KPiA+IHN0YXRpYz8NCj4gPg0KPiA+PiArew0KPiA+PiArCWludCBy
YXdfdmFsLCByZXQ7DQo+ID4+ICsNCj4gPj4gKwlyYXdfdmFsID0gZGE5MTUwX2dwYWRjX3JlYWRf
YWRjKGdwYWRjLCBod19jaGFuKTsNCj4gPj4gKwlpZiAocmF3X3ZhbCA8IDApDQo+ID4+ICsJCXJl
dHVybiByYXdfdmFsOw0KPiA+PiArDQo+ID4+ICsJc3dpdGNoIChjaGFubmVsKSB7DQo+ID4+ICsJ
Y2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9HUElPQToNCj4gPj4gKwljYXNlIERBOTE1MF9HUEFEQ19D
SEFOX0dQSU9COg0KPiA+PiArCWNhc2UgREE5MTUwX0dQQURDX0NIQU5fR1BJT0M6DQo+ID4+ICsJ
Y2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9HUElPRDoNCj4gPj4gKwkJcmV0ID0gZGE5MTUwX2dwYWRj
X2dwaW9fNXZfdm9sdGFnZV9ub3cocmF3X3ZhbCk7DQo+ID4NCj4gPiBjb3VsZCByZXR1cm4gZGly
ZWN0bHkgLi4uDQo+ID4NCj4gPj4gKwkJYnJlYWs7DQo+ID4+ICsJY2FzZSBEQTkxNTBfR1BBRENf
Q0hBTl9JQlVTOg0KPiA+PiArCQlyZXQgPSBkYTkxNTBfZ3BhZGNfaWJ1c19jdXJyZW50X2F2Zyhy
YXdfdmFsKTsNCj4gPj4gKwkJYnJlYWs7DQo+ID4+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9W
QlVTOg0KPiA+PiArCQlyZXQgPSBkYTkxNTBfZ3BhZGNfdmJ1c18yMXZfdm9sdGFnZV9ub3cocmF3
X3ZhbCk7DQo+ID4+ICsJCWJyZWFrOw0KPiA+PiArCWNhc2UgREE5MTUwX0dQQURDX0NIQU5fVlNZ
UzoNCj4gPj4gKwkJcmV0ID0gZGE5MTUwX2dwYWRjX3ZzeXNfNnZfdm9sdGFnZV9ub3cocmF3X3Zh
bCk7DQo+ID4+ICsJCWJyZWFrOw0KPiA+PiArCWNhc2UgREE5MTUwX0dQQURDX0NIQU5fVEpVTkNf
Q09SRToNCj4gPj4gKwljYXNlIERBOTE1MF9HUEFEQ19DSEFOX1RKVU5DX09WUDoNCj4gPj4gKwkJ
cmV0ID0gZGE5MTUwX2dwYWRjX3RqdW5jX3RlbXAocmF3X3ZhbCk7DQo+ID4+ICsJCWJyZWFrOw0K
PiA+PiArCWRlZmF1bHQ6DQo+ID4+ICsJCS8qIE5vIHByb2Nlc3NpbmcgZm9yIG90aGVyIGNoYW5u
ZWxzIHNvIHJldHVybiByYXcgdmFsdWUgKi8NCj4gPj4gKwkJcmV0ID0gcmF3X3ZhbDsNCj4gPj4g
KwkJYnJlYWs7DQo+ID4+ICsJfQ0KPiA+DQo+ID4gYW5kIHNhdmUgdGhlIGZpbmFsIHJldHVybg0K
PiA+PiArDQo+ID4+ICsJcmV0dXJuIHJldDsNCj4gPj4gK30NCj4gPj4gKw0KPiA+PiAraW50IGRh
OTE1MF9ncGFkY19yZWFkX3NjYWxlKGludCBjaGFubmVsKQ0KPiA+DQo+ID4gc3RhdGljPw0KPiA+
DQo+ID4+ICt7DQo+ID4+ICsJaW50IHJldDsNCj4gPj4gKw0KPiA+PiArCXN3aXRjaCAoY2hhbm5l
bCkgew0KPiA+PiArCWNhc2UgREE5MTUwX0dQQURDX0NIQU5fVkJBVDoNCj4gPj4gKwkJcmV0ID0g
MjkzMjsNCj4gPg0KPiA+IHJldHVybiBkaXJlY3RseT8NCj4gPg0KPiA+PiArCQlicmVhazsNCj4g
Pj4gKwlkZWZhdWx0Og0KPiA+PiArCQlyZXQgPSAtRUlOVkFMOw0KPiA+PiArCX0NCj4gPj4gKw0K
PiA+PiArCXJldHVybiByZXQ7DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4gK2ludCBkYTkxNTBfZ3Bh
ZGNfcmVhZF9vZmZzZXQoaW50IGNoYW5uZWwpDQo+ID4+ICt7DQo+ID4+ICsJaW50IHJldDsNCj4g
Pj4gKw0KPiA+PiArCXN3aXRjaCAoY2hhbm5lbCkgew0KPiA+PiArCWNhc2UgREE5MTUwX0dQQURD
X0NIQU5fVkJBVDoNCj4gPj4gKwkJcmV0ID0gMTUwMDAwMCAvIDI5MzI7DQo+ID4NCj4gPiByZXR1
cm4gZGlyZWN0bHk/DQo+ID4NCj4gPj4gKwkJYnJlYWs7DQo+ID4+ICsJZGVmYXVsdDoNCj4gPj4g
KwkJcmV0ID0gLUVJTlZBTDsNCj4gPj4gKwl9DQo+ID4+ICsNCj4gPj4gKwlyZXR1cm4gcmV0Ow0K
PiA+PiArfQ0KPiA+PiArDQo+ID4+ICtpbnQgZGE5MTUwX2dwYWRjX3JlYWRfcmF3KHN0cnVjdCBp
aW9fZGV2ICppbmRpb19kZXYsDQo+ID4+ICsJCQkgIHN0cnVjdCBpaW9fY2hhbl9zcGVjIGNvbnN0
ICpjaGFuLA0KPiA+PiArCQkJICBpbnQgKnZhbCwgaW50ICp2YWwyLCBsb25nIG1hc2spDQo+ID4N
Cj4gPiBzdGF0aWM/DQo+ID4NCj4gPj4gK3sNCj4gPj4gKwlzdHJ1Y3QgZGE5MTUwX2dwYWRjICpn
cGFkYyA9IGlpb19wcml2KGluZGlvX2Rldik7DQo+ID4+ICsJaW50IHJldDsNCj4gPj4gKw0KPiA+
PiArCWlmICgoY2hhbi0+Y2hhbm5lbCA8IERBOTE1MF9HUEFEQ19DSEFOX0dQSU9BKSB8fA0KPiA+
PiArCSAgICAoY2hhbi0+Y2hhbm5lbCA+IERBOTE1MF9HUEFEQ19DSEFOX1RKVU5DX09WUCkpDQo+
ID4+ICsJCXJldHVybiAtRUlOVkFMOw0KPiA+PiArDQo+ID4+ICsJc3dpdGNoIChtYXNrKSB7DQo+
ID4+ICsJY2FzZSBJSU9fQ0hBTl9JTkZPX1JBVzoNCj4gPj4gKwljYXNlIElJT19DSEFOX0lORk9f
UFJPQ0VTU0VEOg0KPiBXb3VsZCBiZSBjbGVhbmVyIHRvIGhhdmUgZWFjaCBvZiB0aGVzZSBmdW5j
dGlvbnMgdXNlIHJldCBmb3IgcmV0dXJuIGNvZGUNCj4gaW5jbHVkaW5nIElJT19WQUxfSU5UIGFu
ZCBwYXNzIHZhbCBhcyBhbiBhcmd1ZW1lbnQuICBXb3VsZCBnZXQgcmlkDQo+IG9mIHRoZSBmaWRk
bHkgaGFuZGxpbmcgYXQgdGhlIGVuZCBvZiB0aGlzIGZ1bmN0aW9uIGFuZCBhbGxvdyBkaXJlY3QN
Cj4gcmV0dXJucyBmcm9tIGVhY2ggb2YgdGhlIGNhc2Ugc3RhdGVtZW50cy4NCj4gDQo+IEFsc28s
IGFyZSB0aGUgYmFzZSB1bml0cyBvZiBhbGwgb2YgdGhlc2UgY2hhbm5lbHMgcmVhbGx5IGdpdmlu
ZyB1cw0KPiBhbiBpbnRlZ2VyIHJlc3VsdD8gIEUuZy4gbVYsIG1BIGV0Yz8gTm90IGltcG9zc2li
bGUsIGJ1dCBzZWVtcyB1bmxpa2VseSENCg0KT2ssIEkgY2FuIG1ha2UgdGhhdCBjaGFuZ2UuIFdv
dWxkbid0IHNheSB3aGF0IHdhcyB0aGVyZSBub3cgaXMgZmlkZGx5LCBidXQgYW0NCmhhcHB5IHRv
IHVwZGF0ZS4NCg0KSW4gdGVybXMgb2YgYmFzZSB1bml0cywgdGhleSBhcmUgYWN0dWFsbHkgaW4g
ViBvciBBLCByYXRoZXIgdGhhbiBzYXkgbVYgb3IgbUEsDQphY2NvcmRpbmcgdG8gdGhlIGRhdGFz
aGVldCwgYnV0IGFzIHRoZXJlJ3Mgbm8gZmxvYXRpbmcgcG9pbnQgc3VwcG9ydCBpbiB0aGUNCmtl
cm5lbCB0aGUgc2Vuc2libGUgb3B0aW9uIHdhcyB0byBwcm92aWRlIHRoZW0gaW4gc21hbGxlciB1
bml0cyBhbmQgcHJvdmlkZQ0KZ3JlYXRlciBhY2N1cmFjeS4NCg0KPiANCj4gPj4gKwkJcmV0ID0g
ZGE5MTUwX2dwYWRjX3JlYWRfcHJvY2Vzc2VkKGdwYWRjLCBjaGFuLT5jaGFubmVsLA0KPiA+PiAr
CQkJCQkJICBjaGFuLT5hZGRyZXNzKTsNCj4gPj4gKwkJYnJlYWs7DQo+ID4+ICsJY2FzZSBJSU9f
Q0hBTl9JTkZPX1NDQUxFOg0KPiA+PiArCQlyZXQgPSBkYTkxNTBfZ3BhZGNfcmVhZF9zY2FsZShj
aGFuLT5jaGFubmVsKTsNCj4gPj4gKwkJYnJlYWs7DQo+ID4+ICsJY2FzZSBJSU9fQ0hBTl9JTkZP
X09GRlNFVDoNCj4gPj4gKwkJcmV0ID0gZGE5MTUwX2dwYWRjX3JlYWRfb2Zmc2V0KGNoYW4tPmNo
YW5uZWwpOw0KPiA+PiArCQlicmVhazsNCj4gPj4gKwlkZWZhdWx0Og0KPiA+PiArCQlyZXQgPSAt
RUlOVkFMOw0KPiA+PiArCQlicmVhazsNCj4gPj4gKwl9DQo+ID4+ICsNCj4gPj4gKwlpZiAocmV0
IDwgMCkNCj4gPj4gKwkJcmV0dXJuIHJldDsNCj4gPj4gKw0KPiA+PiArCSp2YWwgPSByZXQ7DQo+
ID4+ICsNCj4gPj4gKwlyZXR1cm4gSUlPX1ZBTF9JTlQ7DQo+ID4+ICt9DQo+ID4+ICsNCj4gPj4g
K3N0YXRpYyBjb25zdCBzdHJ1Y3QgaWlvX2luZm8gZGE5MTUwX2dwYWRjX2luZm8gPSB7DQo+ID4+
ICsJLnJlYWRfcmF3ID0gJmRhOTE1MF9ncGFkY19yZWFkX3JhdywNCj4gPj4gKwkuZHJpdmVyX21v
ZHVsZSA9IFRISVNfTU9EVUxFLA0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArI2RlZmluZSBHUEFE
Q19DSEFOTkVMKF9pZCwgX2h3X2lkLCBfdHlwZSwgY2hhbl9pbmZvLCBfZXh0X25hbWUpIHsJXA0K
PiA+PiArCS50eXBlID0gX3R5cGUsCQkJCQkJCVwNCj4gPj4gKwkuaW5kZXhlZCA9IDEsCQkJCQkJ
CVwNCj4gPg0KPiA+IHRoZXJlIGlzIG9ubHkgb25lIGN1cnJlbnQgY2hhbm5lbCwgaXQgc2hvdWxk
IG5vdCBiZSBpbmRleGVkDQo+IE9wdGlvbmFsLiBFaXRoZXIgd2F5IHVzZXJzcGFjZSBzaG91bGQg
Y29wZSBmaW5lLiBBdCBvbmUgcG9pbnQgSSB0aG91Z2h0DQo+IGFib3V0IGluc2lzdGluZyBldmVy
eXRoaW5nIHdhcyBpbmRleGVkLCB0byByZWR1Y2UgdXNlcnNwYWNlIGNvbXBsZXhpdHkNCj4gKGV2
ZXIgc28gc2xpZ2h0bHkpIGJ1dCB3YXMgYSBiaXQgbGF0ZSBieSB0aGUgdGltZSBJIHRob3VnaHQg
b2YgaXQgOykNCg0KSWYgaXQncyBvaywgSSB3aWxsIGxlYXZlIGFzIGlzIGFzIHRvIGtlZXAgdGhp
cyBtYWNybyBjb21tb24uDQoNCj4gPg0KPiA+PiArCS5jaGFubmVsID0gREE5MTUwX0dQQURDX0NI
QU5fIyNfaWQsCQkJCVwNCj4gPj4gKwkuYWRkcmVzcyA9IERBOTE1MF9HUEFEQ19IV19DSEFOXyMj
X2h3X2lkLAkJCVwNCj4gPj4gKwkuaW5mb19tYXNrX3NlcGFyYXRlID0gY2hhbl9pbmZvLAkJCQlc
DQo+ID4+ICsJLmV4dGVuZF9uYW1lID0gX2V4dF9uYW1lLAkJCQkJXA0KPiA+PiArCS5kYXRhc2hl
ZXRfbmFtZSA9ICNfaWQsCQkJCQkJXA0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICsjZGVmaW5lIEdQ
QURDX0NIQU5ORUxfUkFXKF9pZCwgX2h3X2lkLCBfdHlwZSwgX2V4dF9uYW1lKQlcDQo+ID4+ICsJ
R1BBRENfQ0hBTk5FTChfaWQsIF9od19pZCwgX3R5cGUsIEJJVChJSU9fQ0hBTl9JTkZPX1JBVyks
DQo+IF9leHRfbmFtZSkNCj4gPj4gKw0KPiA+PiArI2RlZmluZSBHUEFEQ19DSEFOTkVMX1NDQUxF
RChfaWQsIF9od19pZCwgX3R5cGUsIF9leHRfbmFtZSkJXA0KPiA+PiArCUdQQURDX0NIQU5ORUwo
X2lkLCBfaHdfaWQsIF90eXBlLAkJCVwNCj4gPj4gKwkJICAgICAgQklUKElJT19DSEFOX0lORk9f
UkFXKSB8CQkJXA0KPiA+PiArCQkgICAgICBCSVQoSUlPX0NIQU5fSU5GT19TQ0FMRSkgfAkJXA0K
PiA+PiArCQkgICAgICBCSVQoSUlPX0NIQU5fSU5GT19PRkZTRVQpLAkJXA0KPiA+PiArCQkgICAg
ICBfZXh0X25hbWUpDQo+ID4+ICsNCj4gPj4gKyNkZWZpbmUgR1BBRENfQ0hBTk5FTF9QUk9DRVNT
RUQoX2lkLCBfaHdfaWQsIF90eXBlLCBfZXh0X25hbWUpDQo+IAlcDQo+ID4+ICsJR1BBRENfQ0hB
Tk5FTChfaWQsIF9od19pZCwgX3R5cGUsIEJJVChJSU9fQ0hBTl9JTkZPX1BST0NFU1NFRCksCVwN
Cj4gPj4gKwkJICAgICAgX2V4dF9uYW1lKQ0KPiBUaGlzIG1hY3JvIGFuZCBzaW1pbGFyIG5lZWQg
YSBEQTkxNTAgcHJlZml4IHRvIGF2b2lkIGxpa2VseSBuYW1lIGNsYXNoZXMgaW4NCj4gZnV0dXJl
Lg0KDQpGYWlyIHBvaW50LiBXaWxsIHVwZGF0ZS4NCg0KPiA+PiArDQo+ID4+ICsvKiBTdXBwb3J0
ZWQgY2hhbm5lbHMgKi8NCj4gPj4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaWlvX2NoYW5fc3BlYyBk
YTkxNTBfZ3BhZGNfY2hhbm5lbHNbXSA9IHsNCj4gPj4gKwlHUEFEQ19DSEFOTkVMX1BST0NFU1NF
RChHUElPQSwgR1BJT0FfNVYsIElJT19WT0xUQUdFLCAiR1BJT0EiKSwNCj4gPj4gKwlHUEFEQ19D
SEFOTkVMX1BST0NFU1NFRChHUElPQiwgR1BJT0JfNVYsIElJT19WT0xUQUdFLCAiR1BJT0IiKSwN
Cj4gPj4gKwlHUEFEQ19DSEFOTkVMX1BST0NFU1NFRChHUElPQywgR1BJT0NfNVYsIElJT19WT0xU
QUdFLCAiR1BJT0MiKSwNCj4gPj4gKwlHUEFEQ19DSEFOTkVMX1BST0NFU1NFRChHUElPRCwgR1BJ
T0RfNVYsIElJT19WT0xUQUdFLCAiR1BJT0QiKSwNCj4gPj4gKwlHUEFEQ19DSEFOTkVMX1BST0NF
U1NFRChJQlVTLCBJQlVTX1NFTlNFLCBJSU9fQ1VSUkVOVCwgIklCVVMiKSwNCj4gPj4gKwlHUEFE
Q19DSEFOTkVMX1BST0NFU1NFRChWQlVTLCBWQlVTX0RJVl8sIElJT19WT0xUQUdFLCAiVkJVUyIp
LA0KPiA+PiArCUdQQURDX0NIQU5ORUxfUkFXKElELCBJRCwgSUlPX1ZPTFRBR0UsICJJRCIpLA0K
PiA+PiArCUdQQURDX0NIQU5ORUxfUFJPQ0VTU0VEKFZTWVMsIFZTWVMsIElJT19WT0xUQUdFLCAi
VlNZUyIpLA0KPiA+PiArCUdQQURDX0NIQU5ORUxfU0NBTEVEKFZCQVQsIFZCQVQsIElJT19WT0xU
QUdFLCAiVkJBVCIpLA0KPiA+PiArCUdQQURDX0NIQU5ORUxfUkFXKFRCQVQsIFRCQVQsIElJT19W
T0xUQUdFLCAiVEJBVCIpLA0KPiA+PiArCUdQQURDX0NIQU5ORUxfUFJPQ0VTU0VEKFRKVU5DX0NP
UkUsIFRKVU5DX0NPUkUsIElJT19URU1QLA0KPiAiVEpVTkNfQ09SRSIpLA0KPiA+PiArCUdQQURD
X0NIQU5ORUxfUFJPQ0VTU0VEKFRKVU5DX09WUCwgVEpVTkNfT1ZQLCBJSU9fVEVNUCwNCj4gIlRK
VU5DX09WUCIpLA0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArLyogRGVmYXVsdCBtYXBzIHVzZWQg
YnkgZGE5MTUwLWNoYXJnZXIgKi8NCj4gPj4gK3N0YXRpYyBzdHJ1Y3QgaWlvX21hcCBkYTkxNTBf
Z3BhZGNfZGVmYXVsdF9tYXBzW10gPSB7DQo+ID4+ICsJew0KPiA+PiArCQkuY29uc3VtZXJfZGV2
X25hbWUgPSAiZGE5MTUwLWNoYXJnZXIiLA0KPiA+PiArCQkuY29uc3VtZXJfY2hhbm5lbCA9ICJD
SEFOX0lCVVMiLA0KPiA+PiArCQkuYWRjX2NoYW5uZWxfbGFiZWwgPSAiSUJVUyIsDQo+ID4+ICsJ
fSwNCj4gPj4gKwl7DQo+ID4+ICsJCS5jb25zdW1lcl9kZXZfbmFtZSA9ICJkYTkxNTAtY2hhcmdl
ciIsDQo+ID4+ICsJCS5jb25zdW1lcl9jaGFubmVsID0gIkNIQU5fVkJVUyIsDQo+ID4+ICsJCS5h
ZGNfY2hhbm5lbF9sYWJlbCA9ICJWQlVTIiwNCj4gPj4gKwl9LA0KPiA+PiArCXsNCj4gPj4gKwkJ
LmNvbnN1bWVyX2Rldl9uYW1lID0gImRhOTE1MC1jaGFyZ2VyIiwNCj4gPj4gKwkJLmNvbnN1bWVy
X2NoYW5uZWwgPSAiQ0hBTl9USlVOQyIsDQo+ID4+ICsJCS5hZGNfY2hhbm5lbF9sYWJlbCA9ICJU
SlVOQ19DT1JFIiwNCj4gPj4gKwl9LA0KPiA+PiArCXsNCj4gPj4gKwkJLmNvbnN1bWVyX2Rldl9u
YW1lID0gImRhOTE1MC1jaGFyZ2VyIiwNCj4gPj4gKwkJLmNvbnN1bWVyX2NoYW5uZWwgPSAiQ0hB
Tl9WQkFUIiwNCj4gPj4gKwkJLmFkY19jaGFubmVsX2xhYmVsID0gIlZCQVQiLA0KPiA+PiArCX0s
DQo+ID4+ICsJe30sDQo+ID4+ICt9Ow0KPiA+PiArDQo+ID4+ICtzdGF0aWMgaW50IGRhOTE1MF9n
cGFkY19wcm9iZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQ0KPiA+PiArew0KPiA+PiAr
CXN0cnVjdCBkZXZpY2UgKmRldiA9ICZwZGV2LT5kZXY7DQo+ID4+ICsJc3RydWN0IGRhOTE1MCAq
ZGE5MTUwID0gZGV2X2dldF9kcnZkYXRhKGRldi0+cGFyZW50KTsNCj4gPj4gKwlzdHJ1Y3QgZGE5
MTUwX2dwYWRjICpncGFkYzsNCj4gPj4gKwlzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2Ow0KPiA+
PiArCWludCByZXQ7DQo+ID4+ICsNCj4gPj4gKwlpbmRpb19kZXYgPSBkZXZtX2lpb19kZXZpY2Vf
YWxsb2MoJnBkZXYtPmRldiwNCj4gPj4gKwkJCQkJICBzaXplb2Yoc3RydWN0IGRhOTE1MF9ncGFk
YykpOw0KPiA+PiArCWlmICghaW5kaW9fZGV2KSB7DQo+ID4+ICsJCWRldl9lcnIoJnBkZXYtPmRl
diwgIkZhaWxlZCB0byBhbGxvY2F0ZSBJSU8gZGV2aWNlXG4iKTsNCj4gPj4gKwkJcmV0dXJuIC1F
Tk9NRU07DQo+ID4+ICsJfQ0KPiA+PiArCWdwYWRjID0gaWlvX3ByaXYoaW5kaW9fZGV2KTsNCj4g
Pj4gKw0KPiA+PiArCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIGluZGlvX2Rldik7DQo+ID4+
ICsJZ3BhZGMtPmRhOTE1MCA9IGRhOTE1MDsNCj4gPj4gKwlncGFkYy0+ZGV2ID0gZGV2Ow0KPiA+
PiArDQo+ID4+ICsJcmV0ID0gaWlvX21hcF9hcnJheV9yZWdpc3RlcihpbmRpb19kZXYsIGRhOTE1
MF9ncGFkY19kZWZhdWx0X21hcHMpOw0KPiA+PiArCWlmIChyZXQpIHsNCj4gPj4gKwkJZGV2X2Vy
cihkZXYsICJGYWlsZWQgdG8gcmVnaXN0ZXIgSUlPIG1hcHM6ICVkXG4iLCByZXQpOw0KPiA+PiAr
CQlnb3RvIGlpb19tYXBfZmFpbDsNCj4gPg0KPiA+IGp1c3QgcmV0dXJuIGhlcmU/DQo+ID4NCj4g
Pj4gKwl9DQo+ID4+ICsNCj4gPj4gKwltdXRleF9pbml0KCZncGFkYy0+bG9jayk7DQo+ID4+ICsJ
aW5pdF9jb21wbGV0aW9uKCZncGFkYy0+Y29tcGxldGUpOw0KPiA+PiArDQo+ID4+ICsJLyogUmVn
aXN0ZXIgSVJRICovDQo+ID4+ICsJcmV0ID0gZGE5MTUwX3JlZ2lzdGVyX2lycShwZGV2LCBncGFk
YywgZGE5MTUwX2dwYWRjX2lycSwgIkdQQURDIik7DQo+IFRoaXMgZnVuY3Rpb24gd2FudHMgcmVu
YW1pbmcgdG8gaW5kaWNhdGUgdGhhdCBpdCBpcyBkb2luZyBhIG1hbmFnZWQNCj4gaXJxIHJlcXVl
c3QuLi4gZGV2bV9kYTkxNTAgZXRjIHdvdWxkIGJlIGNvbnZlbnRpb25hbCA7KQ0KDQpZZXAsIGl0
J3MgYSBnb29kIHBvaW50LiBXaWxsIHVwZGF0ZS4NCg0KPiA+PiArCWlmIChyZXQgPCAwKQ0KPiA+
PiArCQlnb3RvIGlycV9mYWlsOw0KPiA+PiArDQo+ID4+ICsJaW5kaW9fZGV2LT5uYW1lID0gZGV2
X25hbWUoZGV2KTsNCj4gPj4gKwlpbmRpb19kZXYtPmRldi5wYXJlbnQgPSBkZXY7DQo+ID4+ICsJ
aW5kaW9fZGV2LT5kZXYub2Zfbm9kZSA9IHBkZXYtPmRldi5vZl9ub2RlOw0KPiA+PiArCWluZGlv
X2Rldi0+aW5mbyA9ICZkYTkxNTBfZ3BhZGNfaW5mbzsNCj4gPj4gKwlpbmRpb19kZXYtPm1vZGVz
ID0gSU5ESU9fRElSRUNUX01PREU7DQo+ID4+ICsJaW5kaW9fZGV2LT5jaGFubmVscyA9IGRhOTE1
MF9ncGFkY19jaGFubmVsczsNCj4gPj4gKwlpbmRpb19kZXYtPm51bV9jaGFubmVscyA9IEFSUkFZ
X1NJWkUoZGE5MTUwX2dwYWRjX2NoYW5uZWxzKTsNCj4gPj4gKw0KPiA+PiArCXJldCA9IGlpb19k
ZXZpY2VfcmVnaXN0ZXIoaW5kaW9fZGV2KTsNCj4gPj4gKwlpZiAocmV0KSB7DQo+ID4+ICsJCWRl
dl9lcnIoZGV2LCAiRmFpbGVkIHRvIHJlZ2lzdGVyIElJTyBkZXZpY2U6ICVkXG4iLCByZXQpOw0K
PiA+PiArCQlnb3RvIGlpb19kZXZfZmFpbDsNCj4gPj4gKwl9DQo+ID4+ICsNCj4gPj4gKwlyZXR1
cm4gcmV0Ow0KPiA+PiArDQo+ID4+ICtpaW9fZGV2X2ZhaWw6DQo+ID4+ICtpcnFfZmFpbDoNCj4g
Pg0KPiA+IHdoeSB0d28gbGFiZWxzPw0KPiA+DQo+ID4+ICsJaWlvX21hcF9hcnJheV91bnJlZ2lz
dGVyKGluZGlvX2Rldik7DQo+ID4+ICsNCj4gPj4gK2lpb19tYXBfZmFpbDoNCj4gPj4gKwlyZXR1
cm4gcmV0Ow0KPiA+PiArfQ0KPiA+PiArDQo+ID4+ICtzdGF0aWMgaW50IGRhOTE1MF9ncGFkY19y
ZW1vdmUoc3RydWN0IHBsYXRmb3JtX2RldmljZSAqcGRldikNCj4gPj4gK3sNCj4gPj4gKwlzdHJ1
Y3QgaWlvX2RldiAqaW5kaW9fZGV2ID0gcGxhdGZvcm1fZ2V0X2RydmRhdGEocGRldik7DQo+ID4+
ICsNCj4gPj4gKwlpaW9fbWFwX2FycmF5X3VucmVnaXN0ZXIoaW5kaW9fZGV2KTsNCj4gPg0KPiA+
IHVucmVnaXN0ZXIgaXJxPw0KPiBOb3QgYWN0dWFsbHkgbmVlZGVkIGFzIGl0IHdhcyBhIGRldm0g
cmVnaXN0ZXIgLSBoYXZpbmcgc2FpZCB0aGF0DQo+IHRoZSBmdW5jdGlvbiBzaG91bGQgaW5kaWNh
dGUgdGhhdCBpdCdzIG5hbWluZy4NCg0KQWdyZWVkLg0KDQo+ID4NCj4gPj4gKwlpaW9fZGV2aWNl
X3VucmVnaXN0ZXIoaW5kaW9fZGV2KTsNCj4gPj4gKw0KPiA+PiArCXJldHVybiAwOw0KPiA+PiAr
fQ0KPiA+PiArDQo+ID4+ICtzdGF0aWMgc3RydWN0IHBsYXRmb3JtX2RyaXZlciBkYTkxNTBfZ3Bh
ZGNfZHJpdmVyID0gew0KPiA+PiArCS5kcml2ZXIgPSB7DQo+ID4+ICsJCS5uYW1lID0gImRhOTE1
MC1ncGFkYyIsDQo+ID4+ICsJCS5vd25lciA9IFRISVNfTU9EVUxFLA0KPiA+PiArCX0sDQo+ID4+
ICsJLnByb2JlID0gZGE5MTUwX2dwYWRjX3Byb2JlLA0KPiA+PiArCS5yZW1vdmUgPSBkYTkxNTBf
Z3BhZGNfcmVtb3ZlLA0KPiA+PiArfTsNCj4gPj4gKw0KPiA+PiArbW9kdWxlX3BsYXRmb3JtX2Ry
aXZlcihkYTkxNTBfZ3BhZGNfZHJpdmVyKTsNCj4gPj4gKw0KPiA+PiArTU9EVUxFX0RFU0NSSVBU
SU9OKCJHUEFEQyBEcml2ZXIgZm9yIERBOTE1MCIpOw0KPiA+PiArTU9EVUxFX0FVVEhPUigiQWRh
bSBUaG9tc29uDQo+IDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNvbSIpOw0KPiA+
PiArTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOw0KPiA+PiAtLQ0KPiA+PiAxLjkuMw0KPiA+Pg0KPiA+
PiAtLQ0KPiA+PiBUbyB1bnN1YnNjcmliZSBmcm9tIHRoaXMgbGlzdDogc2VuZCB0aGUgbGluZSAi
dW5zdWJzY3JpYmUgbGludXgta2VybmVsIiBpbg0KPiA+PiB0aGUgYm9keSBvZiBhIG1lc3NhZ2Ug
dG8gbWFqb3Jkb21vQHZnZXIua2VybmVsLm9yZw0KPiA+PiBNb3JlIG1ham9yZG9tbyBpbmZvIGF0
ICBodHRwOi8vdmdlci5rZXJuZWwub3JnL21ham9yZG9tby1pbmZvLmh0bWwNCj4gPj4gUGxlYXNl
IHJlYWQgdGhlIEZBUSBhdCAgaHR0cDovL3d3dy50dXgub3JnL2xrbWwvDQo+ID4+DQo+ID4NCg==

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

* Re: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-09-09 10:37       ` Opensource [Adam Thomson]
  (?)
  (?)
@ 2014-09-10  9:49       ` Lee Jones
  2014-09-10 15:58           ` Opensource [Adam Thomson]
  -1 siblings, 1 reply; 43+ messages in thread
From: Lee Jones @ 2014-09-10  9:49 UTC (permalink / raw)
  To: Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:

> On August 28, 2014 17:36, Lee Jones wrote:
> 
> Thanks for the feedback. As a general comment a couple of the items you've
> identified relate to future updates (additional functionality being added).
> I already have code in place for this but have stripped out a couple of the
> drivers just to reduce the churn and size of patch submission. These will be
> added once these patches have been accepted.
> 
> Where this is the case, I have added notes in-line against the relevant
> comments you made.
> 
> > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > 
> > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > GPIO and GPADC functionality.
> > >
> > > Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > > ---
> > >  drivers/mfd/Kconfig                  |   12 +
> > >  drivers/mfd/Makefile                 |    2 +
> > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> > 
> > Do you also have another, say SPI version?
> 
> No, not yet, but this is something that we may add later as the device does
> support SPI.

I'm not sure we want to split up the files like this for an 'if we
decide to produce an SPI variant in the future'.  If you do, then you
can split the files up.  Until then, stick everything in -core.


> > >  include/linux/mfd/da9150/core.h      |   80 +++
> > >  include/linux/mfd/da9150/pdata.h     |   21 +
> > >  include/linux/mfd/da9150/registers.h | 1153
> > ++++++++++++++++++++++++++++++++++
> > >  7 files changed, 1776 insertions(+)
> > >  create mode 100644 drivers/mfd/da9150-core.c
> > >  create mode 100644 drivers/mfd/da9150-i2c.c
> > >  create mode 100644 include/linux/mfd/da9150/core.h
> > >  create mode 100644 include/linux/mfd/da9150/pdata.h
> > >  create mode 100644 include/linux/mfd/da9150/registers.h
> > >
> > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > > index de5abf2..76adb2c 100644
> > > --- a/drivers/mfd/Kconfig
> > > +++ b/drivers/mfd/Kconfig
> > > @@ -183,6 +183,18 @@ config MFD_DA9063
> > >  	  Additional drivers must be enabled in order to use the functionality
> > >  	  of the device.
> > >
> > > +config MFD_DA9150
> > > +	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
> > 
> > Why can't this be built as a module?
> 
> No reason. Will change it.
> 
> > 
> > > +	depends on I2C=y
> > > +	select MFD_CORE
> > > +	select REGMAP_I2C
> > > +	select REGMAP_IRQ
> > > +	help
> > > +	  This adds support for the DA9150 integrated charger and fuel-gauge
> > > +	  chip. This driver provides common support for accessing the device.
> > > +	  Additional drivers must be enabled in order to use the specific
> > > +	  features of the device.
> > > +
> > >  config MFD_MC13XXX
> > >  	tristate
> > >  	depends on (SPI_MASTER || I2C)
> > > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > > index f001487..098dfa1 100644
> > > --- a/drivers/mfd/Makefile
> > > +++ b/drivers/mfd/Makefile
> > > @@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
> > >  da9063-objs			:= da9063-core.o da9063-irq.o da9063-i2c.o
> > >  obj-$(CONFIG_MFD_DA9063)	+= da9063.o
> > >
> > > +obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
> > > +
> > 
> > Do the other drivers smell?  Please butt up against them.
> > 
> > I'm not entirely sure why there are so many '\n's in the Makefile!
> 
> Okey dokey. Will change.
> 
> > 
> > >  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
> > >  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
> > >  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> > > diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
> > > new file mode 100644
> > > index 0000000..029a30b
> > > --- /dev/null
> > > +++ b/drivers/mfd/da9150-core.c
> > > @@ -0,0 +1,332 @@
> > > +/*
> > > + * DA9150 Core MFD Driver
> > > + *
> > > + * Copyright (c) 2014 Dialog Semiconductor
> > > + *
> > > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > > + *
> > > + * This program is free software; you can redistribute  it and/or modify it
> > > + * under  the terms of  the GNU General  Public License as published by the
> > > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > > + * option) any later version.
> > > + */
> > > +
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/platform_device.h>
> > > +#include <linux/slab.h>
> > > +#include <linux/irq.h>
> > > +#include <linux/interrupt.h>
> > > +#include <linux/mfd/core.h>
> > > +
> > 
> > No real need for this '\n'.
> 
> I can change this, but my reason was to separate common kernel includes from
> device specific ones, for readability. 

It isn't any less readable with the '\n' removed.

> > > +#include <linux/mfd/da9150/core.h>
> > > +#include <linux/mfd/da9150/registers.h>
> > > +#include <linux/mfd/da9150/pdata.h>
> > > +
> > > +u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
> > > +{
> > > +	int val, ret;
> > > +
> > > +	ret = regmap_read(da9150->regmap, reg, &val);
> > > +	if (ret < 0)
> > 
> > What if ret > 0?  Is that a good thing? :)
> > 
> > Just 'if (ret)'.
> 
> Fine, will change.
> 
> > 
> > > +		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
> > > +			reg, ret);
> > > +
> > > +	return (u8) val;
> > > +}
> > > +EXPORT_SYMBOL_GPL(da9150_reg_read);
> > 
> > Not sure I like this abstraction stuff.  I could understand if there
> > were locking involved, but there isn't.  You don't appear to check for
> > errors in the subordinate drivers either, rather you just plough on
> > ahead.  Not sure that's a good idea either.
> > 
> > Anyone have a second opinion?
> 
> The reason for these is because future patches to add additional functionality
> will introduce I2C access functions which do not use regmap and access the
> device via a separate I2C address for this purpose. I will need to provide
> access functions for that, and so having a common style of I2C access makes
> sense for this driver. Means any access just needs to provide the MFD private
> data, and the relevant functions take care of the rest. I think this is cleaner
> in this instance.

So long as these appear soon.  Otherwise it's just cruft.

[...]

> > > +/* Helper functions for sub-devices to request/free IRQs */
> > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > +			irq_handler_t handler, const char *name)
> > > +{
> > > +	int irq, ret;
> > > +
> > > +	irq = platform_get_irq_byname(pdev, name);
> > > +	if (irq < 0)
> > > +		return irq;
> > > +
> > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > +					IRQF_ONESHOT, name, dev_id);
> > > +	if (ret)
> > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > 
> > Why do they need help?  What problem does adding these layers solve?
> 
> Means I don't have to keep adding print error lines everywhere else if this
> function takes care of it. Thought that would be cleaner.

You only need to request each IRQ once.  It's just more abstraction
for the sake of it.  I would prefer if you removed them.

> > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > +		       const char *name)
> > > +{
> > > +	int irq;
> > > +
> > > +	irq = platform_get_irq_byname(pdev, name);
> > > +	if (irq < 0)
> > > +		return;
> > > +
> > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > +}
> > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > 
> > Do you ever release the IRQ and not unbind the driver?
> > 
> > Are there ordering issues at play here?
> > 
> > If not, there's no need to conduct a manual free.
> 
> In the charger driver, in the remove function there is a need I believe to
> free the IRQs before other items are cleared up (e.g. power_supply classes),
> so this is why I have added this in here.

Can you handle this separately in the Charger driver then please?

[...]

> > > +	if (pdata)
> > > +		da9150->irq_base = pdata->irq_base;
> > > +	else
> > > +		da9150->irq_base = -1;
> > 
> > pdata ? pdata->irq_base : -1;
> 
> This is left this way as later updates to add additional functionality will
> require addtional work to be done with the platform data. Seemed pointless
> changing it here just to change it back later.

You're not changing anything, as this is the introduction of the code.
I can't tell you how many times I've heard "I will change it later",
or "doing it this way will support subsequent submissions", then
received no more patches.  It's okay to do it nicely now and expand
it back out in the new patches.

[...]

> > > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> > 
> > sizeof(*da9150)
> 
> Same difference, but ok.

It's more succinct and almost always done this way because of it.

[...]

> > > +struct da9150_pdata {
> > > +	int irq_base;
> > > +};
> > 
> > Just put this in core.h and do away witht this header file.
> 
> The reason for this is that I will add more platform data items later with
> subsequent submissions for additional features. It felt cleaner to separate out
> these structures than throw it in the core.h header. However if it's going to
> be a problem I'll fold this into core.h

More "I will"s. :)

Please do what's right for 'this submission'.  If things change later
you can act accordingly.

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

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

* Re: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-09-09 10:32       ` Opensource [Adam Thomson]
  (?)
  (?)
@ 2014-09-10  9:51       ` Lee Jones
  -1 siblings, 0 replies; 43+ messages in thread
From: Lee Jones @ 2014-09-10  9:51 UTC (permalink / raw)
  To: Opensource [Adam Thomson]
  Cc: Varka Bhadram, Samuel Ortiz, Jonathan Cameron, linux-iio,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, devicetree, Andrew Morton, Joe Perches, linux-kernel,
	Support Opensource

On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> On August 28, 2014 12:47, Varka Bhadram wrote:
> 
> > On 08/28/2014 04:18 PM, Adam Thomson wrote:
> > 
> > (...)
> > 
> > > +static int da9150_probe(struct i2c_client *client,
> > > +			const struct i2c_device_id *id)
> > > +{
> > > +	struct da9150 *da9150;
> > > +	int ret;
> > > +
> > > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> > > +	if (da9150 == NULL)
> > > +		return -ENOMEM;
> > 
> > da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
> > if (!da9150)
> > 	return -ENOMEM;
> 
> Ok, no real difference, but can change it.

Not functionally, but we like to do things as succinctly as possible.

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

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-09-10  9:49       ` Lee Jones
  2014-09-10 15:58           ` Opensource [Adam Thomson]
@ 2014-09-10 15:58           ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-10 15:58 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 11504 bytes --]

On September 10, 2014 10:50, Lee Jones wrote:

> On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> 
> > On August 28, 2014 17:36, Lee Jones wrote:
> >
> > Thanks for the feedback. As a general comment a couple of the items you've
> > identified relate to future updates (additional functionality being added).
> > I already have code in place for this but have stripped out a couple of the
> > drivers just to reduce the churn and size of patch submission. These will be
> > added once these patches have been accepted.
> >
> > Where this is the case, I have added notes in-line against the relevant
> > comments you made.
> >
> > > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > >
> > > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > > GPIO and GPADC functionality.
> > > >
> > > > Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > > > ---
> > > >  drivers/mfd/Kconfig                  |   12 +
> > > >  drivers/mfd/Makefile                 |    2 +
> > > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > > >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> > >
> > > Do you also have another, say SPI version?
> >
> > No, not yet, but this is something that we may add later as the device does
> > support SPI.
> 
> I'm not sure we want to split up the files like this for an 'if we
> decide to produce an SPI variant in the future'.  If you do, then you
> can split the files up.  Until then, stick everything in -core.

Right. Can't say I agree here, but will refactor.

> 
> 
> > > >  include/linux/mfd/da9150/core.h      |   80 +++
> > > >  include/linux/mfd/da9150/pdata.h     |   21 +
> > > >  include/linux/mfd/da9150/registers.h | 1153
> > > ++++++++++++++++++++++++++++++++++
> > > >  7 files changed, 1776 insertions(+)
> > > >  create mode 100644 drivers/mfd/da9150-core.c
> > > >  create mode 100644 drivers/mfd/da9150-i2c.c
> > > >  create mode 100644 include/linux/mfd/da9150/core.h
> > > >  create mode 100644 include/linux/mfd/da9150/pdata.h
> > > >  create mode 100644 include/linux/mfd/da9150/registers.h
> > > >
> > > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > > > index de5abf2..76adb2c 100644
> > > > --- a/drivers/mfd/Kconfig
> > > > +++ b/drivers/mfd/Kconfig
> > > > @@ -183,6 +183,18 @@ config MFD_DA9063
> > > >  	  Additional drivers must be enabled in order to use the functionality
> > > >  	  of the device.
> > > >
> > > > +config MFD_DA9150
> > > > +	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
> > >
> > > Why can't this be built as a module?
> >
> > No reason. Will change it.
> >
> > >
> > > > +	depends on I2C=y
> > > > +	select MFD_CORE
> > > > +	select REGMAP_I2C
> > > > +	select REGMAP_IRQ
> > > > +	help
> > > > +	  This adds support for the DA9150 integrated charger and fuel-gauge
> > > > +	  chip. This driver provides common support for accessing the device.
> > > > +	  Additional drivers must be enabled in order to use the specific
> > > > +	  features of the device.
> > > > +
> > > >  config MFD_MC13XXX
> > > >  	tristate
> > > >  	depends on (SPI_MASTER || I2C)
> > > > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > > > index f001487..098dfa1 100644
> > > > --- a/drivers/mfd/Makefile
> > > > +++ b/drivers/mfd/Makefile
> > > > @@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
> > > >  da9063-objs			:= da9063-core.o da9063-irq.o da9063-
> i2c.o
> > > >  obj-$(CONFIG_MFD_DA9063)	+= da9063.o
> > > >
> > > > +obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
> > > > +
> > >
> > > Do the other drivers smell?  Please butt up against them.
> > >
> > > I'm not entirely sure why there are so many '\n's in the Makefile!
> >
> > Okey dokey. Will change.
> >
> > >
> > > >  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
> > > >  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
> > > >  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> > > > diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
> > > > new file mode 100644
> > > > index 0000000..029a30b
> > > > --- /dev/null
> > > > +++ b/drivers/mfd/da9150-core.c
> > > > @@ -0,0 +1,332 @@
> > > > +/*
> > > > + * DA9150 Core MFD Driver
> > > > + *
> > > > + * Copyright (c) 2014 Dialog Semiconductor
> > > > + *
> > > > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > > > + *
> > > > + * This program is free software; you can redistribute  it and/or modify it
> > > > + * under  the terms of  the GNU General  Public License as published by the
> > > > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > > > + * option) any later version.
> > > > + */
> > > > +
> > > > +#include <linux/kernel.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/platform_device.h>
> > > > +#include <linux/slab.h>
> > > > +#include <linux/irq.h>
> > > > +#include <linux/interrupt.h>
> > > > +#include <linux/mfd/core.h>
> > > > +
> > >
> > > No real need for this '\n'.
> >
> > I can change this, but my reason was to separate common kernel includes from
> > device specific ones, for readability.
> 
> It isn't any less readable with the '\n' removed.

I prefer with, but personal preference I guess. Anyway, will update.

> 
> > > > +#include <linux/mfd/da9150/core.h>
> > > > +#include <linux/mfd/da9150/registers.h>
> > > > +#include <linux/mfd/da9150/pdata.h>
> > > > +
> > > > +u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
> > > > +{
> > > > +	int val, ret;
> > > > +
> > > > +	ret = regmap_read(da9150->regmap, reg, &val);
> > > > +	if (ret < 0)
> > >
> > > What if ret > 0?  Is that a good thing? :)
> > >
> > > Just 'if (ret)'.
> >
> > Fine, will change.
> >
> > >
> > > > +		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
> > > > +			reg, ret);
> > > > +
> > > > +	return (u8) val;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(da9150_reg_read);
> > >
> > > Not sure I like this abstraction stuff.  I could understand if there
> > > were locking involved, but there isn't.  You don't appear to check for
> > > errors in the subordinate drivers either, rather you just plough on
> > > ahead.  Not sure that's a good idea either.
> > >
> > > Anyone have a second opinion?
> >
> > The reason for these is because future patches to add additional functionality
> > will introduce I2C access functions which do not use regmap and access the
> > device via a separate I2C address for this purpose. I will need to provide
> > access functions for that, and so having a common style of I2C access makes
> > sense for this driver. Means any access just needs to provide the MFD private
> > data, and the relevant functions take care of the rest. I think this is cleaner
> > in this instance.
> 
> So long as these appear soon.  Otherwise it's just cruft.

Have other patches already in place and ready to go. When this patch set is
accepted, I will begin submission of the remaining drivers.

> 
> [...]
> 
> > > > +/* Helper functions for sub-devices to request/free IRQs */
> > > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > > +			irq_handler_t handler, const char *name)
> > > > +{
> > > > +	int irq, ret;
> > > > +
> > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > +	if (irq < 0)
> > > > +		return irq;
> > > > +
> > > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > > +					IRQF_ONESHOT, name, dev_id);
> > > > +	if (ret)
> > > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > >
> > > Why do they need help?  What problem does adding these layers solve?
> >
> > Means I don't have to keep adding print error lines everywhere else if this
> > function takes care of it. Thought that would be cleaner.
> 
> You only need to request each IRQ once.  It's just more abstraction
> for the sake of it.  I would prefer if you removed them.

Yes, but in the charger driver for example, there are 4 IRQs to request. If
I don't use this approach the IRQ requesting becomes bloated, hence why I went
for a common function like this. Thought generally the intention was to cut
down on repeated code?

> 
> > > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > > +		       const char *name)
> > > > +{
> > > > +	int irq;
> > > > +
> > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > +	if (irq < 0)
> > > > +		return;
> > > > +
> > > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > >
> > > Do you ever release the IRQ and not unbind the driver?
> > >
> > > Are there ordering issues at play here?
> > >
> > > If not, there's no need to conduct a manual free.
> >
> > In the charger driver, in the remove function there is a need I believe to
> > free the IRQs before other items are cleared up (e.g. power_supply classes),
> > so this is why I have added this in here.
> 
> Can you handle this separately in the Charger driver then please?
> 
> [...]

If I have to remove the IRQ register function, then yes, otherwise it makes more
sense to have the pair of functions in the MFD core I would say.

> 
> > > > +	if (pdata)
> > > > +		da9150->irq_base = pdata->irq_base;
> > > > +	else
> > > > +		da9150->irq_base = -1;
> > >
> > > pdata ? pdata->irq_base : -1;
> >
> > This is left this way as later updates to add additional functionality will
> > require addtional work to be done with the platform data. Seemed pointless
> > changing it here just to change it back later.
> 
> You're not changing anything, as this is the introduction of the code.
> I can't tell you how many times I've heard "I will change it later",
> or "doing it this way will support subsequent submissions", then
> received no more patches.  It's okay to do it nicely now and expand
> it back out in the new patches.
> 
> [...]

It appears that way to you but I have to modify my code for sumbission as the
local code I have covers all functionality. Am having to refactor again and
again just to suit this initial submission, and then I have to revert it back
again when submitting the last couple of drivers. Time consuming, and quite
frustrating when the intention was to make the whole process easier. Anyway,
will update for now and revert in subsequent patches.

> 
> > > > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> > >
> > > sizeof(*da9150)
> >
> > Same difference, but ok.
> 
> It's more succinct and almost always done this way because of it.
> 
> [...]
> 
> > > > +struct da9150_pdata {
> > > > +	int irq_base;
> > > > +};
> > >
> > > Just put this in core.h and do away witht this header file.
> >
> > The reason for this is that I will add more platform data items later with
> > subsequent submissions for additional features. It felt cleaner to separate out
> > these structures than throw it in the core.h header. However if it's going to
> > be a problem I'll fold this into core.h
> 
> More "I will"s. :)
> 
> Please do what's right for 'this submission'.  If things change later
> you can act accordingly.

It's not a case of 'if things change'. They will. Anyway, will refactor now and
revert later.

> 
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-10 15:58           ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-10 15:58 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Joe Perches,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Support Opensource

On September 10, 2014 10:50, Lee Jones wrote:

> On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> 
> > On August 28, 2014 17:36, Lee Jones wrote:
> >
> > Thanks for the feedback. As a general comment a couple of the items you've
> > identified relate to future updates (additional functionality being added).
> > I already have code in place for this but have stripped out a couple of the
> > drivers just to reduce the churn and size of patch submission. These will be
> > added once these patches have been accepted.
> >
> > Where this is the case, I have added notes in-line against the relevant
> > comments you made.
> >
> > > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > >
> > > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > > GPIO and GPADC functionality.
> > > >
> > > > Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > > > ---
> > > >  drivers/mfd/Kconfig                  |   12 +
> > > >  drivers/mfd/Makefile                 |    2 +
> > > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > > >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> > >
> > > Do you also have another, say SPI version?
> >
> > No, not yet, but this is something that we may add later as the device does
> > support SPI.
> 
> I'm not sure we want to split up the files like this for an 'if we
> decide to produce an SPI variant in the future'.  If you do, then you
> can split the files up.  Until then, stick everything in -core.

Right. Can't say I agree here, but will refactor.

> 
> 
> > > >  include/linux/mfd/da9150/core.h      |   80 +++
> > > >  include/linux/mfd/da9150/pdata.h     |   21 +
> > > >  include/linux/mfd/da9150/registers.h | 1153
> > > ++++++++++++++++++++++++++++++++++
> > > >  7 files changed, 1776 insertions(+)
> > > >  create mode 100644 drivers/mfd/da9150-core.c
> > > >  create mode 100644 drivers/mfd/da9150-i2c.c
> > > >  create mode 100644 include/linux/mfd/da9150/core.h
> > > >  create mode 100644 include/linux/mfd/da9150/pdata.h
> > > >  create mode 100644 include/linux/mfd/da9150/registers.h
> > > >
> > > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > > > index de5abf2..76adb2c 100644
> > > > --- a/drivers/mfd/Kconfig
> > > > +++ b/drivers/mfd/Kconfig
> > > > @@ -183,6 +183,18 @@ config MFD_DA9063
> > > >  	  Additional drivers must be enabled in order to use the functionality
> > > >  	  of the device.
> > > >
> > > > +config MFD_DA9150
> > > > +	bool "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
> > >
> > > Why can't this be built as a module?
> >
> > No reason. Will change it.
> >
> > >
> > > > +	depends on I2C=y
> > > > +	select MFD_CORE
> > > > +	select REGMAP_I2C
> > > > +	select REGMAP_IRQ
> > > > +	help
> > > > +	  This adds support for the DA9150 integrated charger and fuel-gauge
> > > > +	  chip. This driver provides common support for accessing the device.
> > > > +	  Additional drivers must be enabled in order to use the specific
> > > > +	  features of the device.
> > > > +
> > > >  config MFD_MC13XXX
> > > >  	tristate
> > > >  	depends on (SPI_MASTER || I2C)
> > > > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> > > > index f001487..098dfa1 100644
> > > > --- a/drivers/mfd/Makefile
> > > > +++ b/drivers/mfd/Makefile
> > > > @@ -114,6 +114,8 @@ obj-$(CONFIG_MFD_DA9055)	+= da9055.o
> > > >  da9063-objs			:= da9063-core.o da9063-irq.o da9063-
> i2c.o
> > > >  obj-$(CONFIG_MFD_DA9063)	+= da9063.o
> > > >
> > > > +obj-$(CONFIG_MFD_DA9150)	+= da9150-core.o da9150-i2c.o
> > > > +
> > >
> > > Do the other drivers smell?  Please butt up against them.
> > >
> > > I'm not entirely sure why there are so many '\n's in the Makefile!
> >
> > Okey dokey. Will change.
> >
> > >
> > > >  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
> > > >  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
> > > >  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> > > > diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
> > > > new file mode 100644
> > > > index 0000000..029a30b
> > > > --- /dev/null
> > > > +++ b/drivers/mfd/da9150-core.c
> > > > @@ -0,0 +1,332 @@
> > > > +/*
> > > > + * DA9150 Core MFD Driver
> > > > + *
> > > > + * Copyright (c) 2014 Dialog Semiconductor
> > > > + *
> > > > + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > > > + *
> > > > + * This program is free software; you can redistribute  it and/or modify it
> > > > + * under  the terms of  the GNU General  Public License as published by the
> > > > + * Free Software Foundation;  either version 2 of the  License, or (at your
> > > > + * option) any later version.
> > > > + */
> > > > +
> > > > +#include <linux/kernel.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/platform_device.h>
> > > > +#include <linux/slab.h>
> > > > +#include <linux/irq.h>
> > > > +#include <linux/interrupt.h>
> > > > +#include <linux/mfd/core.h>
> > > > +
> > >
> > > No real need for this '\n'.
> >
> > I can change this, but my reason was to separate common kernel includes from
> > device specific ones, for readability.
> 
> It isn't any less readable with the '\n' removed.

I prefer with, but personal preference I guess. Anyway, will update.

> 
> > > > +#include <linux/mfd/da9150/core.h>
> > > > +#include <linux/mfd/da9150/registers.h>
> > > > +#include <linux/mfd/da9150/pdata.h>
> > > > +
> > > > +u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
> > > > +{
> > > > +	int val, ret;
> > > > +
> > > > +	ret = regmap_read(da9150->regmap, reg, &val);
> > > > +	if (ret < 0)
> > >
> > > What if ret > 0?  Is that a good thing? :)
> > >
> > > Just 'if (ret)'.
> >
> > Fine, will change.
> >
> > >
> > > > +		dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
> > > > +			reg, ret);
> > > > +
> > > > +	return (u8) val;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(da9150_reg_read);
> > >
> > > Not sure I like this abstraction stuff.  I could understand if there
> > > were locking involved, but there isn't.  You don't appear to check for
> > > errors in the subordinate drivers either, rather you just plough on
> > > ahead.  Not sure that's a good idea either.
> > >
> > > Anyone have a second opinion?
> >
> > The reason for these is because future patches to add additional functionality
> > will introduce I2C access functions which do not use regmap and access the
> > device via a separate I2C address for this purpose. I will need to provide
> > access functions for that, and so having a common style of I2C access makes
> > sense for this driver. Means any access just needs to provide the MFD private
> > data, and the relevant functions take care of the rest. I think this is cleaner
> > in this instance.
> 
> So long as these appear soon.  Otherwise it's just cruft.

Have other patches already in place and ready to go. When this patch set is
accepted, I will begin submission of the remaining drivers.

> 
> [...]
> 
> > > > +/* Helper functions for sub-devices to request/free IRQs */
> > > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > > +			irq_handler_t handler, const char *name)
> > > > +{
> > > > +	int irq, ret;
> > > > +
> > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > +	if (irq < 0)
> > > > +		return irq;
> > > > +
> > > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > > +					IRQF_ONESHOT, name, dev_id);
> > > > +	if (ret)
> > > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> > > > +
> > > > +	return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > >
> > > Why do they need help?  What problem does adding these layers solve?
> >
> > Means I don't have to keep adding print error lines everywhere else if this
> > function takes care of it. Thought that would be cleaner.
> 
> You only need to request each IRQ once.  It's just more abstraction
> for the sake of it.  I would prefer if you removed them.

Yes, but in the charger driver for example, there are 4 IRQs to request. If
I don't use this approach the IRQ requesting becomes bloated, hence why I went
for a common function like this. Thought generally the intention was to cut
down on repeated code?

> 
> > > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > > +		       const char *name)
> > > > +{
> > > > +	int irq;
> > > > +
> > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > +	if (irq < 0)
> > > > +		return;
> > > > +
> > > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > >
> > > Do you ever release the IRQ and not unbind the driver?
> > >
> > > Are there ordering issues at play here?
> > >
> > > If not, there's no need to conduct a manual free.
> >
> > In the charger driver, in the remove function there is a need I believe to
> > free the IRQs before other items are cleared up (e.g. power_supply classes),
> > so this is why I have added this in here.
> 
> Can you handle this separately in the Charger driver then please?
> 
> [...]

If I have to remove the IRQ register function, then yes, otherwise it makes more
sense to have the pair of functions in the MFD core I would say.

> 
> > > > +	if (pdata)
> > > > +		da9150->irq_base = pdata->irq_base;
> > > > +	else
> > > > +		da9150->irq_base = -1;
> > >
> > > pdata ? pdata->irq_base : -1;
> >
> > This is left this way as later updates to add additional functionality will
> > require addtional work to be done with the platform data. Seemed pointless
> > changing it here just to change it back later.
> 
> You're not changing anything, as this is the introduction of the code.
> I can't tell you how many times I've heard "I will change it later",
> or "doing it this way will support subsequent submissions", then
> received no more patches.  It's okay to do it nicely now and expand
> it back out in the new patches.
> 
> [...]

It appears that way to you but I have to modify my code for sumbission as the
local code I have covers all functionality. Am having to refactor again and
again just to suit this initial submission, and then I have to revert it back
again when submitting the last couple of drivers. Time consuming, and quite
frustrating when the intention was to make the whole process easier. Anyway,
will update for now and revert in subsequent patches.

> 
> > > > +	da9150 = devm_kzalloc(&client->dev, sizeof(struct da9150), GFP_KERNEL);
> > >
> > > sizeof(*da9150)
> >
> > Same difference, but ok.
> 
> It's more succinct and almost always done this way because of it.
> 
> [...]
> 
> > > > +struct da9150_pdata {
> > > > +	int irq_base;
> > > > +};
> > >
> > > Just put this in core.h and do away witht this header file.
> >
> > The reason for this is that I will add more platform data items later with
> > subsequent submissions for additional features. It felt cleaner to separate out
> > these structures than throw it in the core.h header. However if it's going to
> > be a problem I'll fold this into core.h
> 
> More "I will"s. :)
> 
> Please do what's right for 'this submission'.  If things change later
> you can act accordingly.

It's not a case of 'if things change'. They will. Anyway, will refactor now and
revert later.

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

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-10 15:58           ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-10 15:58 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

T24gU2VwdGVtYmVyIDEwLCAyMDE0IDEwOjUwLCBMZWUgSm9uZXMgd3JvdGU6DQoNCj4gT24gVHVl
LCAwOSBTZXAgMjAxNCwgT3BlbnNvdXJjZSBbQWRhbSBUaG9tc29uXSB3cm90ZToNCj4gDQo+ID4g
T24gQXVndXN0IDI4LCAyMDE0IDE3OjM2LCBMZWUgSm9uZXMgd3JvdGU6DQo+ID4NCj4gPiBUaGFu
a3MgZm9yIHRoZSBmZWVkYmFjay4gQXMgYSBnZW5lcmFsIGNvbW1lbnQgYSBjb3VwbGUgb2YgdGhl
IGl0ZW1zIHlvdSd2ZQ0KPiA+IGlkZW50aWZpZWQgcmVsYXRlIHRvIGZ1dHVyZSB1cGRhdGVzIChh
ZGRpdGlvbmFsIGZ1bmN0aW9uYWxpdHkgYmVpbmcgYWRkZWQpLg0KPiA+IEkgYWxyZWFkeSBoYXZl
IGNvZGUgaW4gcGxhY2UgZm9yIHRoaXMgYnV0IGhhdmUgc3RyaXBwZWQgb3V0IGEgY291cGxlIG9m
IHRoZQ0KPiA+IGRyaXZlcnMganVzdCB0byByZWR1Y2UgdGhlIGNodXJuIGFuZCBzaXplIG9mIHBh
dGNoIHN1Ym1pc3Npb24uIFRoZXNlIHdpbGwgYmUNCj4gPiBhZGRlZCBvbmNlIHRoZXNlIHBhdGNo
ZXMgaGF2ZSBiZWVuIGFjY2VwdGVkLg0KPiA+DQo+ID4gV2hlcmUgdGhpcyBpcyB0aGUgY2FzZSwg
SSBoYXZlIGFkZGVkIG5vdGVzIGluLWxpbmUgYWdhaW5zdCB0aGUgcmVsZXZhbnQNCj4gPiBjb21t
ZW50cyB5b3UgbWFkZS4NCj4gPg0KPiA+ID4gT24gVGh1LCAyOCBBdWcgMjAxNCwgQWRhbSBUaG9t
c29uIHdyb3RlOg0KPiA+ID4NCj4gPiA+ID4gREE5MTUwIGlzIGEgY29tYmluZWQgQ2hhcmdlciBh
bmQgRnVlbC1HYXVnZSBJQywgd2l0aCBhZGRpdGlvbmFsDQo+ID4gPiA+IEdQSU8gYW5kIEdQQURD
IGZ1bmN0aW9uYWxpdHkuDQo+ID4gPiA+DQo+ID4gPiA+IFNpZ25lZC1vZmYtYnk6IEFkYW0gVGhv
bXNvbiA8QWRhbS5UaG9tc29uLk9wZW5zb3VyY2VAZGlhc2VtaS5jb20+DQo+ID4gPiA+IC0tLQ0K
PiA+ID4gPiAgZHJpdmVycy9tZmQvS2NvbmZpZyAgICAgICAgICAgICAgICAgIHwgICAxMiArDQo+
ID4gPiA+ICBkcml2ZXJzL21mZC9NYWtlZmlsZSAgICAgICAgICAgICAgICAgfCAgICAyICsNCj4g
PiA+ID4gIGRyaXZlcnMvbWZkL2RhOTE1MC1jb3JlLmMgICAgICAgICAgICB8ICAzMzIgKysrKysr
KysrKw0KPiA+ID4gPiAgZHJpdmVycy9tZmQvZGE5MTUwLWkyYy5jICAgICAgICAgICAgIHwgIDE3
NiArKysrKysNCj4gPiA+DQo+ID4gPiBEbyB5b3UgYWxzbyBoYXZlIGFub3RoZXIsIHNheSBTUEkg
dmVyc2lvbj8NCj4gPg0KPiA+IE5vLCBub3QgeWV0LCBidXQgdGhpcyBpcyBzb21ldGhpbmcgdGhh
dCB3ZSBtYXkgYWRkIGxhdGVyIGFzIHRoZSBkZXZpY2UgZG9lcw0KPiA+IHN1cHBvcnQgU1BJLg0K
PiANCj4gSSdtIG5vdCBzdXJlIHdlIHdhbnQgdG8gc3BsaXQgdXAgdGhlIGZpbGVzIGxpa2UgdGhp
cyBmb3IgYW4gJ2lmIHdlDQo+IGRlY2lkZSB0byBwcm9kdWNlIGFuIFNQSSB2YXJpYW50IGluIHRo
ZSBmdXR1cmUnLiAgSWYgeW91IGRvLCB0aGVuIHlvdQ0KPiBjYW4gc3BsaXQgdGhlIGZpbGVzIHVw
LiAgVW50aWwgdGhlbiwgc3RpY2sgZXZlcnl0aGluZyBpbiAtY29yZS4NCg0KUmlnaHQuIENhbid0
IHNheSBJIGFncmVlIGhlcmUsIGJ1dCB3aWxsIHJlZmFjdG9yLg0KDQo+IA0KPiANCj4gPiA+ID4g
IGluY2x1ZGUvbGludXgvbWZkL2RhOTE1MC9jb3JlLmggICAgICB8ICAgODAgKysrDQo+ID4gPiA+
ICBpbmNsdWRlL2xpbnV4L21mZC9kYTkxNTAvcGRhdGEuaCAgICAgfCAgIDIxICsNCj4gPiA+ID4g
IGluY2x1ZGUvbGludXgvbWZkL2RhOTE1MC9yZWdpc3RlcnMuaCB8IDExNTMNCj4gPiA+ICsrKysr
KysrKysrKysrKysrKysrKysrKysrKysrKysrKysNCj4gPiA+ID4gIDcgZmlsZXMgY2hhbmdlZCwg
MTc3NiBpbnNlcnRpb25zKCspDQo+ID4gPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy9t
ZmQvZGE5MTUwLWNvcmUuYw0KPiA+ID4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvbWZk
L2RhOTE1MC1pMmMuYw0KPiA+ID4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1ZGUvbGludXgv
bWZkL2RhOTE1MC9jb3JlLmgNCj4gPiA+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBpbmNsdWRlL2xp
bnV4L21mZC9kYTkxNTAvcGRhdGEuaA0KPiA+ID4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGluY2x1
ZGUvbGludXgvbWZkL2RhOTE1MC9yZWdpc3RlcnMuaA0KPiA+ID4gPg0KPiA+ID4gPiBkaWZmIC0t
Z2l0IGEvZHJpdmVycy9tZmQvS2NvbmZpZyBiL2RyaXZlcnMvbWZkL0tjb25maWcNCj4gPiA+ID4g
aW5kZXggZGU1YWJmMi4uNzZhZGIyYyAxMDA2NDQNCj4gPiA+ID4gLS0tIGEvZHJpdmVycy9tZmQv
S2NvbmZpZw0KPiA+ID4gPiArKysgYi9kcml2ZXJzL21mZC9LY29uZmlnDQo+ID4gPiA+IEBAIC0x
ODMsNiArMTgzLDE4IEBAIGNvbmZpZyBNRkRfREE5MDYzDQo+ID4gPiA+ICAJICBBZGRpdGlvbmFs
IGRyaXZlcnMgbXVzdCBiZSBlbmFibGVkIGluIG9yZGVyIHRvIHVzZSB0aGUgZnVuY3Rpb25hbGl0
eQ0KPiA+ID4gPiAgCSAgb2YgdGhlIGRldmljZS4NCj4gPiA+ID4NCj4gPiA+ID4gK2NvbmZpZyBN
RkRfREE5MTUwDQo+ID4gPiA+ICsJYm9vbCAiRGlhbG9nIFNlbWljb25kdWN0b3IgREE5MTUwIENo
YXJnZXIgRnVlbC1HYXVnZSBjaGlwIg0KPiA+ID4NCj4gPiA+IFdoeSBjYW4ndCB0aGlzIGJlIGJ1
aWx0IGFzIGEgbW9kdWxlPw0KPiA+DQo+ID4gTm8gcmVhc29uLiBXaWxsIGNoYW5nZSBpdC4NCj4g
Pg0KPiA+ID4NCj4gPiA+ID4gKwlkZXBlbmRzIG9uIEkyQz15DQo+ID4gPiA+ICsJc2VsZWN0IE1G
RF9DT1JFDQo+ID4gPiA+ICsJc2VsZWN0IFJFR01BUF9JMkMNCj4gPiA+ID4gKwlzZWxlY3QgUkVH
TUFQX0lSUQ0KPiA+ID4gPiArCWhlbHANCj4gPiA+ID4gKwkgIFRoaXMgYWRkcyBzdXBwb3J0IGZv
ciB0aGUgREE5MTUwIGludGVncmF0ZWQgY2hhcmdlciBhbmQgZnVlbC1nYXVnZQ0KPiA+ID4gPiAr
CSAgY2hpcC4gVGhpcyBkcml2ZXIgcHJvdmlkZXMgY29tbW9uIHN1cHBvcnQgZm9yIGFjY2Vzc2lu
ZyB0aGUgZGV2aWNlLg0KPiA+ID4gPiArCSAgQWRkaXRpb25hbCBkcml2ZXJzIG11c3QgYmUgZW5h
YmxlZCBpbiBvcmRlciB0byB1c2UgdGhlIHNwZWNpZmljDQo+ID4gPiA+ICsJICBmZWF0dXJlcyBv
ZiB0aGUgZGV2aWNlLg0KPiA+ID4gPiArDQo+ID4gPiA+ICBjb25maWcgTUZEX01DMTNYWFgNCj4g
PiA+ID4gIAl0cmlzdGF0ZQ0KPiA+ID4gPiAgCWRlcGVuZHMgb24gKFNQSV9NQVNURVIgfHwgSTJD
KQ0KPiA+ID4gPiBkaWZmIC0tZ2l0IGEvZHJpdmVycy9tZmQvTWFrZWZpbGUgYi9kcml2ZXJzL21m
ZC9NYWtlZmlsZQ0KPiA+ID4gPiBpbmRleCBmMDAxNDg3Li4wOThkZmExIDEwMDY0NA0KPiA+ID4g
PiAtLS0gYS9kcml2ZXJzL21mZC9NYWtlZmlsZQ0KPiA+ID4gPiArKysgYi9kcml2ZXJzL21mZC9N
YWtlZmlsZQ0KPiA+ID4gPiBAQCAtMTE0LDYgKzExNCw4IEBAIG9iai0kKENPTkZJR19NRkRfREE5
MDU1KQkrPSBkYTkwNTUubw0KPiA+ID4gPiAgZGE5MDYzLW9ianMJCQk6PSBkYTkwNjMtY29yZS5v
IGRhOTA2My1pcnEubyBkYTkwNjMtDQo+IGkyYy5vDQo+ID4gPiA+ICBvYmotJChDT05GSUdfTUZE
X0RBOTA2MykJKz0gZGE5MDYzLm8NCj4gPiA+ID4NCj4gPiA+ID4gK29iai0kKENPTkZJR19NRkRf
REE5MTUwKQkrPSBkYTkxNTAtY29yZS5vIGRhOTE1MC1pMmMubw0KPiA+ID4gPiArDQo+ID4gPg0K
PiA+ID4gRG8gdGhlIG90aGVyIGRyaXZlcnMgc21lbGw/ICBQbGVhc2UgYnV0dCB1cCBhZ2FpbnN0
IHRoZW0uDQo+ID4gPg0KPiA+ID4gSSdtIG5vdCBlbnRpcmVseSBzdXJlIHdoeSB0aGVyZSBhcmUg
c28gbWFueSAnXG4ncyBpbiB0aGUgTWFrZWZpbGUhDQo+ID4NCj4gPiBPa2V5IGRva2V5LiBXaWxs
IGNoYW5nZS4NCj4gPg0KPiA+ID4NCj4gPiA+ID4gIG9iai0kKENPTkZJR19NRkRfTUFYMTQ1Nzcp
CSs9IG1heDE0NTc3Lm8NCj4gPiA+ID4gIG9iai0kKENPTkZJR19NRkRfTUFYNzc2ODYpCSs9IG1h
eDc3Njg2Lm8NCj4gPiA+ID4gIG9iai0kKENPTkZJR19NRkRfTUFYNzc2OTMpCSs9IG1heDc3Njkz
Lm8NCj4gPiA+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvbWZkL2RhOTE1MC1jb3JlLmMgYi9kcml2
ZXJzL21mZC9kYTkxNTAtY29yZS5jDQo+ID4gPiA+IG5ldyBmaWxlIG1vZGUgMTAwNjQ0DQo+ID4g
PiA+IGluZGV4IDAwMDAwMDAuLjAyOWEzMGINCj4gPiA+ID4gLS0tIC9kZXYvbnVsbA0KPiA+ID4g
PiArKysgYi9kcml2ZXJzL21mZC9kYTkxNTAtY29yZS5jDQo+ID4gPiA+IEBAIC0wLDAgKzEsMzMy
IEBADQo+ID4gPiA+ICsvKg0KPiA+ID4gPiArICogREE5MTUwIENvcmUgTUZEIERyaXZlcg0KPiA+
ID4gPiArICoNCj4gPiA+ID4gKyAqIENvcHlyaWdodCAoYykgMjAxNCBEaWFsb2cgU2VtaWNvbmR1
Y3Rvcg0KPiA+ID4gPiArICoNCj4gPiA+ID4gKyAqIEF1dGhvcjogQWRhbSBUaG9tc29uIDxBZGFt
LlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNvbT4NCj4gPiA+ID4gKyAqDQo+ID4gPiA+ICsg
KiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgIGl0
IGFuZC9vciBtb2RpZnkgaXQNCj4gPiA+ID4gKyAqIHVuZGVyICB0aGUgdGVybXMgb2YgIHRoZSBH
TlUgR2VuZXJhbCAgUHVibGljIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZQ0KPiA+ID4gPiAr
ICogRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyAgZWl0aGVyIHZlcnNpb24gMiBvZiB0aGUgIExp
Y2Vuc2UsIG9yIChhdCB5b3VyDQo+ID4gPiA+ICsgKiBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9u
Lg0KPiA+ID4gPiArICovDQo+ID4gPiA+ICsNCj4gPiA+ID4gKyNpbmNsdWRlIDxsaW51eC9rZXJu
ZWwuaD4NCj4gPiA+ID4gKyNpbmNsdWRlIDxsaW51eC9tb2R1bGUuaD4NCj4gPiA+ID4gKyNpbmNs
dWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4NCj4gPiA+ID4gKyNpbmNsdWRlIDxsaW51eC9z
bGFiLmg+DQo+ID4gPiA+ICsjaW5jbHVkZSA8bGludXgvaXJxLmg+DQo+ID4gPiA+ICsjaW5jbHVk
ZSA8bGludXgvaW50ZXJydXB0Lmg+DQo+ID4gPiA+ICsjaW5jbHVkZSA8bGludXgvbWZkL2NvcmUu
aD4NCj4gPiA+ID4gKw0KPiA+ID4NCj4gPiA+IE5vIHJlYWwgbmVlZCBmb3IgdGhpcyAnXG4nLg0K
PiA+DQo+ID4gSSBjYW4gY2hhbmdlIHRoaXMsIGJ1dCBteSByZWFzb24gd2FzIHRvIHNlcGFyYXRl
IGNvbW1vbiBrZXJuZWwgaW5jbHVkZXMgZnJvbQ0KPiA+IGRldmljZSBzcGVjaWZpYyBvbmVzLCBm
b3IgcmVhZGFiaWxpdHkuDQo+IA0KPiBJdCBpc24ndCBhbnkgbGVzcyByZWFkYWJsZSB3aXRoIHRo
ZSAnXG4nIHJlbW92ZWQuDQoNCkkgcHJlZmVyIHdpdGgsIGJ1dCBwZXJzb25hbCBwcmVmZXJlbmNl
IEkgZ3Vlc3MuIEFueXdheSwgd2lsbCB1cGRhdGUuDQoNCj4gDQo+ID4gPiA+ICsjaW5jbHVkZSA8
bGludXgvbWZkL2RhOTE1MC9jb3JlLmg+DQo+ID4gPiA+ICsjaW5jbHVkZSA8bGludXgvbWZkL2Rh
OTE1MC9yZWdpc3RlcnMuaD4NCj4gPiA+ID4gKyNpbmNsdWRlIDxsaW51eC9tZmQvZGE5MTUwL3Bk
YXRhLmg+DQo+ID4gPiA+ICsNCj4gPiA+ID4gK3U4IGRhOTE1MF9yZWdfcmVhZChzdHJ1Y3QgZGE5
MTUwICpkYTkxNTAsIHUxNiByZWcpDQo+ID4gPiA+ICt7DQo+ID4gPiA+ICsJaW50IHZhbCwgcmV0
Ow0KPiA+ID4gPiArDQo+ID4gPiA+ICsJcmV0ID0gcmVnbWFwX3JlYWQoZGE5MTUwLT5yZWdtYXAs
IHJlZywgJnZhbCk7DQo+ID4gPiA+ICsJaWYgKHJldCA8IDApDQo+ID4gPg0KPiA+ID4gV2hhdCBp
ZiByZXQgPiAwPyAgSXMgdGhhdCBhIGdvb2QgdGhpbmc/IDopDQo+ID4gPg0KPiA+ID4gSnVzdCAn
aWYgKHJldCknLg0KPiA+DQo+ID4gRmluZSwgd2lsbCBjaGFuZ2UuDQo+ID4NCj4gPiA+DQo+ID4g
PiA+ICsJCWRldl9lcnIoZGE5MTUwLT5kZXYsICJGYWlsZWQgdG8gcmVhZCBmcm9tIHJlZyAweCV4
OiAlZFxuIiwNCj4gPiA+ID4gKwkJCXJlZywgcmV0KTsNCj4gPiA+ID4gKw0KPiA+ID4gPiArCXJl
dHVybiAodTgpIHZhbDsNCj4gPiA+ID4gK30NCj4gPiA+ID4gK0VYUE9SVF9TWU1CT0xfR1BMKGRh
OTE1MF9yZWdfcmVhZCk7DQo+ID4gPg0KPiA+ID4gTm90IHN1cmUgSSBsaWtlIHRoaXMgYWJzdHJh
Y3Rpb24gc3R1ZmYuICBJIGNvdWxkIHVuZGVyc3RhbmQgaWYgdGhlcmUNCj4gPiA+IHdlcmUgbG9j
a2luZyBpbnZvbHZlZCwgYnV0IHRoZXJlIGlzbid0LiAgWW91IGRvbid0IGFwcGVhciB0byBjaGVj
ayBmb3INCj4gPiA+IGVycm9ycyBpbiB0aGUgc3Vib3JkaW5hdGUgZHJpdmVycyBlaXRoZXIsIHJh
dGhlciB5b3UganVzdCBwbG91Z2ggb24NCj4gPiA+IGFoZWFkLiAgTm90IHN1cmUgdGhhdCdzIGEg
Z29vZCBpZGVhIGVpdGhlci4NCj4gPiA+DQo+ID4gPiBBbnlvbmUgaGF2ZSBhIHNlY29uZCBvcGlu
aW9uPw0KPiA+DQo+ID4gVGhlIHJlYXNvbiBmb3IgdGhlc2UgaXMgYmVjYXVzZSBmdXR1cmUgcGF0
Y2hlcyB0byBhZGQgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5DQo+ID4gd2lsbCBpbnRyb2R1Y2Ug
STJDIGFjY2VzcyBmdW5jdGlvbnMgd2hpY2ggZG8gbm90IHVzZSByZWdtYXAgYW5kIGFjY2VzcyB0
aGUNCj4gPiBkZXZpY2UgdmlhIGEgc2VwYXJhdGUgSTJDIGFkZHJlc3MgZm9yIHRoaXMgcHVycG9z
ZS4gSSB3aWxsIG5lZWQgdG8gcHJvdmlkZQ0KPiA+IGFjY2VzcyBmdW5jdGlvbnMgZm9yIHRoYXQs
IGFuZCBzbyBoYXZpbmcgYSBjb21tb24gc3R5bGUgb2YgSTJDIGFjY2VzcyBtYWtlcw0KPiA+IHNl
bnNlIGZvciB0aGlzIGRyaXZlci4gTWVhbnMgYW55IGFjY2VzcyBqdXN0IG5lZWRzIHRvIHByb3Zp
ZGUgdGhlIE1GRCBwcml2YXRlDQo+ID4gZGF0YSwgYW5kIHRoZSByZWxldmFudCBmdW5jdGlvbnMg
dGFrZSBjYXJlIG9mIHRoZSByZXN0LiBJIHRoaW5rIHRoaXMgaXMgY2xlYW5lcg0KPiA+IGluIHRo
aXMgaW5zdGFuY2UuDQo+IA0KPiBTbyBsb25nIGFzIHRoZXNlIGFwcGVhciBzb29uLiAgT3RoZXJ3
aXNlIGl0J3MganVzdCBjcnVmdC4NCg0KSGF2ZSBvdGhlciBwYXRjaGVzIGFscmVhZHkgaW4gcGxh
Y2UgYW5kIHJlYWR5IHRvIGdvLiBXaGVuIHRoaXMgcGF0Y2ggc2V0IGlzDQphY2NlcHRlZCwgSSB3
aWxsIGJlZ2luIHN1Ym1pc3Npb24gb2YgdGhlIHJlbWFpbmluZyBkcml2ZXJzLg0KDQo+IA0KPiBb
Li4uXQ0KPiANCj4gPiA+ID4gKy8qIEhlbHBlciBmdW5jdGlvbnMgZm9yIHN1Yi1kZXZpY2VzIHRv
IHJlcXVlc3QvZnJlZSBJUlFzICovDQo+ID4gPiA+ICtpbnQgZGE5MTUwX3JlZ2lzdGVyX2lycShz
dHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2LCB2b2lkICpkZXZfaWQsDQo+ID4gPiA+ICsJCQlp
cnFfaGFuZGxlcl90IGhhbmRsZXIsIGNvbnN0IGNoYXIgKm5hbWUpDQo+ID4gPiA+ICt7DQo+ID4g
PiA+ICsJaW50IGlycSwgcmV0Ow0KPiA+ID4gPiArDQo+ID4gPiA+ICsJaXJxID0gcGxhdGZvcm1f
Z2V0X2lycV9ieW5hbWUocGRldiwgbmFtZSk7DQo+ID4gPiA+ICsJaWYgKGlycSA8IDApDQo+ID4g
PiA+ICsJCXJldHVybiBpcnE7DQo+ID4gPiA+ICsNCj4gPiA+ID4gKwlyZXQgPSBkZXZtX3JlcXVl
c3RfdGhyZWFkZWRfaXJxKCZwZGV2LT5kZXYsIGlycSwgTlVMTCwgaGFuZGxlciwNCj4gPiA+ID4g
KwkJCQkJSVJRRl9PTkVTSE9ULCBuYW1lLCBkZXZfaWQpOw0KPiA+ID4gPiArCWlmIChyZXQpDQo+
ID4gPiA+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgIkZhaWxlZCB0byByZXF1ZXN0IElSUSAlZDog
JWRcbiIsIGlycSwgcmV0KTsNCj4gPiA+ID4gKw0KPiA+ID4gPiArCXJldHVybiByZXQ7DQo+ID4g
PiA+ICt9DQo+ID4gPiA+ICtFWFBPUlRfU1lNQk9MX0dQTChkYTkxNTBfcmVnaXN0ZXJfaXJxKTsN
Cj4gPiA+DQo+ID4gPiBXaHkgZG8gdGhleSBuZWVkIGhlbHA/ICBXaGF0IHByb2JsZW0gZG9lcyBh
ZGRpbmcgdGhlc2UgbGF5ZXJzIHNvbHZlPw0KPiA+DQo+ID4gTWVhbnMgSSBkb24ndCBoYXZlIHRv
IGtlZXAgYWRkaW5nIHByaW50IGVycm9yIGxpbmVzIGV2ZXJ5d2hlcmUgZWxzZSBpZiB0aGlzDQo+
ID4gZnVuY3Rpb24gdGFrZXMgY2FyZSBvZiBpdC4gVGhvdWdodCB0aGF0IHdvdWxkIGJlIGNsZWFu
ZXIuDQo+IA0KPiBZb3Ugb25seSBuZWVkIHRvIHJlcXVlc3QgZWFjaCBJUlEgb25jZS4gIEl0J3Mg
anVzdCBtb3JlIGFic3RyYWN0aW9uDQo+IGZvciB0aGUgc2FrZSBvZiBpdC4gIEkgd291bGQgcHJl
ZmVyIGlmIHlvdSByZW1vdmVkIHRoZW0uDQoNClllcywgYnV0IGluIHRoZSBjaGFyZ2VyIGRyaXZl
ciBmb3IgZXhhbXBsZSwgdGhlcmUgYXJlIDQgSVJRcyB0byByZXF1ZXN0LiBJZg0KSSBkb24ndCB1
c2UgdGhpcyBhcHByb2FjaCB0aGUgSVJRIHJlcXVlc3RpbmcgYmVjb21lcyBibG9hdGVkLCBoZW5j
ZSB3aHkgSSB3ZW50DQpmb3IgYSBjb21tb24gZnVuY3Rpb24gbGlrZSB0aGlzLiBUaG91Z2h0IGdl
bmVyYWxseSB0aGUgaW50ZW50aW9uIHdhcyB0byBjdXQNCmRvd24gb24gcmVwZWF0ZWQgY29kZT8N
Cg0KPiANCj4gPiA+ID4gK3ZvaWQgZGE5MTUwX3JlbGVhc2VfaXJxKHN0cnVjdCBwbGF0Zm9ybV9k
ZXZpY2UgKnBkZXYsIHZvaWQgKmRldl9pZCwNCj4gPiA+ID4gKwkJICAgICAgIGNvbnN0IGNoYXIg
Km5hbWUpDQo+ID4gPiA+ICt7DQo+ID4gPiA+ICsJaW50IGlycTsNCj4gPiA+ID4gKw0KPiA+ID4g
PiArCWlycSA9IHBsYXRmb3JtX2dldF9pcnFfYnluYW1lKHBkZXYsIG5hbWUpOw0KPiA+ID4gPiAr
CWlmIChpcnEgPCAwKQ0KPiA+ID4gPiArCQlyZXR1cm47DQo+ID4gPiA+ICsNCj4gPiA+ID4gKwlk
ZXZtX2ZyZWVfaXJxKCZwZGV2LT5kZXYsIGlycSwgZGV2X2lkKTsNCj4gPiA+ID4gK30NCj4gPiA+
ID4gK0VYUE9SVF9TWU1CT0xfR1BMKGRhOTE1MF9yZWxlYXNlX2lycSk7DQo+ID4gPg0KPiA+ID4g
RG8geW91IGV2ZXIgcmVsZWFzZSB0aGUgSVJRIGFuZCBub3QgdW5iaW5kIHRoZSBkcml2ZXI/DQo+
ID4gPg0KPiA+ID4gQXJlIHRoZXJlIG9yZGVyaW5nIGlzc3VlcyBhdCBwbGF5IGhlcmU/DQo+ID4g
Pg0KPiA+ID4gSWYgbm90LCB0aGVyZSdzIG5vIG5lZWQgdG8gY29uZHVjdCBhIG1hbnVhbCBmcmVl
Lg0KPiA+DQo+ID4gSW4gdGhlIGNoYXJnZXIgZHJpdmVyLCBpbiB0aGUgcmVtb3ZlIGZ1bmN0aW9u
IHRoZXJlIGlzIGEgbmVlZCBJIGJlbGlldmUgdG8NCj4gPiBmcmVlIHRoZSBJUlFzIGJlZm9yZSBv
dGhlciBpdGVtcyBhcmUgY2xlYXJlZCB1cCAoZS5nLiBwb3dlcl9zdXBwbHkgY2xhc3NlcyksDQo+
ID4gc28gdGhpcyBpcyB3aHkgSSBoYXZlIGFkZGVkIHRoaXMgaW4gaGVyZS4NCj4gDQo+IENhbiB5
b3UgaGFuZGxlIHRoaXMgc2VwYXJhdGVseSBpbiB0aGUgQ2hhcmdlciBkcml2ZXIgdGhlbiBwbGVh
c2U/DQo+IA0KPiBbLi4uXQ0KDQpJZiBJIGhhdmUgdG8gcmVtb3ZlIHRoZSBJUlEgcmVnaXN0ZXIg
ZnVuY3Rpb24sIHRoZW4geWVzLCBvdGhlcndpc2UgaXQgbWFrZXMgbW9yZQ0Kc2Vuc2UgdG8gaGF2
ZSB0aGUgcGFpciBvZiBmdW5jdGlvbnMgaW4gdGhlIE1GRCBjb3JlIEkgd291bGQgc2F5Lg0KDQo+
IA0KPiA+ID4gPiArCWlmIChwZGF0YSkNCj4gPiA+ID4gKwkJZGE5MTUwLT5pcnFfYmFzZSA9IHBk
YXRhLT5pcnFfYmFzZTsNCj4gPiA+ID4gKwllbHNlDQo+ID4gPiA+ICsJCWRhOTE1MC0+aXJxX2Jh
c2UgPSAtMTsNCj4gPiA+DQo+ID4gPiBwZGF0YSA/IHBkYXRhLT5pcnFfYmFzZSA6IC0xOw0KPiA+
DQo+ID4gVGhpcyBpcyBsZWZ0IHRoaXMgd2F5IGFzIGxhdGVyIHVwZGF0ZXMgdG8gYWRkIGFkZGl0
aW9uYWwgZnVuY3Rpb25hbGl0eSB3aWxsDQo+ID4gcmVxdWlyZSBhZGR0aW9uYWwgd29yayB0byBi
ZSBkb25lIHdpdGggdGhlIHBsYXRmb3JtIGRhdGEuIFNlZW1lZCBwb2ludGxlc3MNCj4gPiBjaGFu
Z2luZyBpdCBoZXJlIGp1c3QgdG8gY2hhbmdlIGl0IGJhY2sgbGF0ZXIuDQo+IA0KPiBZb3UncmUg
bm90IGNoYW5naW5nIGFueXRoaW5nLCBhcyB0aGlzIGlzIHRoZSBpbnRyb2R1Y3Rpb24gb2YgdGhl
IGNvZGUuDQo+IEkgY2FuJ3QgdGVsbCB5b3UgaG93IG1hbnkgdGltZXMgSSd2ZSBoZWFyZCAiSSB3
aWxsIGNoYW5nZSBpdCBsYXRlciIsDQo+IG9yICJkb2luZyBpdCB0aGlzIHdheSB3aWxsIHN1cHBv
cnQgc3Vic2VxdWVudCBzdWJtaXNzaW9ucyIsIHRoZW4NCj4gcmVjZWl2ZWQgbm8gbW9yZSBwYXRj
aGVzLiAgSXQncyBva2F5IHRvIGRvIGl0IG5pY2VseSBub3cgYW5kIGV4cGFuZA0KPiBpdCBiYWNr
IG91dCBpbiB0aGUgbmV3IHBhdGNoZXMuDQo+IA0KPiBbLi4uXQ0KDQpJdCBhcHBlYXJzIHRoYXQg
d2F5IHRvIHlvdSBidXQgSSBoYXZlIHRvIG1vZGlmeSBteSBjb2RlIGZvciBzdW1iaXNzaW9uIGFz
IHRoZQ0KbG9jYWwgY29kZSBJIGhhdmUgY292ZXJzIGFsbCBmdW5jdGlvbmFsaXR5LiBBbSBoYXZp
bmcgdG8gcmVmYWN0b3IgYWdhaW4gYW5kDQphZ2FpbiBqdXN0IHRvIHN1aXQgdGhpcyBpbml0aWFs
IHN1Ym1pc3Npb24sIGFuZCB0aGVuIEkgaGF2ZSB0byByZXZlcnQgaXQgYmFjaw0KYWdhaW4gd2hl
biBzdWJtaXR0aW5nIHRoZSBsYXN0IGNvdXBsZSBvZiBkcml2ZXJzLiBUaW1lIGNvbnN1bWluZywg
YW5kIHF1aXRlDQpmcnVzdHJhdGluZyB3aGVuIHRoZSBpbnRlbnRpb24gd2FzIHRvIG1ha2UgdGhl
IHdob2xlIHByb2Nlc3MgZWFzaWVyLiBBbnl3YXksDQp3aWxsIHVwZGF0ZSBmb3Igbm93IGFuZCBy
ZXZlcnQgaW4gc3Vic2VxdWVudCBwYXRjaGVzLg0KDQo+IA0KPiA+ID4gPiArCWRhOTE1MCA9IGRl
dm1fa3phbGxvYygmY2xpZW50LT5kZXYsIHNpemVvZihzdHJ1Y3QgZGE5MTUwKSwgR0ZQX0tFUk5F
TCk7DQo+ID4gPg0KPiA+ID4gc2l6ZW9mKCpkYTkxNTApDQo+ID4NCj4gPiBTYW1lIGRpZmZlcmVu
Y2UsIGJ1dCBvay4NCj4gDQo+IEl0J3MgbW9yZSBzdWNjaW5jdCBhbmQgYWxtb3N0IGFsd2F5cyBk
b25lIHRoaXMgd2F5IGJlY2F1c2Ugb2YgaXQuDQo+IA0KPiBbLi4uXQ0KPiANCj4gPiA+ID4gK3N0
cnVjdCBkYTkxNTBfcGRhdGEgew0KPiA+ID4gPiArCWludCBpcnFfYmFzZTsNCj4gPiA+ID4gK307
DQo+ID4gPg0KPiA+ID4gSnVzdCBwdXQgdGhpcyBpbiBjb3JlLmggYW5kIGRvIGF3YXkgd2l0aHQg
dGhpcyBoZWFkZXIgZmlsZS4NCj4gPg0KPiA+IFRoZSByZWFzb24gZm9yIHRoaXMgaXMgdGhhdCBJ
IHdpbGwgYWRkIG1vcmUgcGxhdGZvcm0gZGF0YSBpdGVtcyBsYXRlciB3aXRoDQo+ID4gc3Vic2Vx
dWVudCBzdWJtaXNzaW9ucyBmb3IgYWRkaXRpb25hbCBmZWF0dXJlcy4gSXQgZmVsdCBjbGVhbmVy
IHRvIHNlcGFyYXRlIG91dA0KPiA+IHRoZXNlIHN0cnVjdHVyZXMgdGhhbiB0aHJvdyBpdCBpbiB0
aGUgY29yZS5oIGhlYWRlci4gSG93ZXZlciBpZiBpdCdzIGdvaW5nIHRvDQo+ID4gYmUgYSBwcm9i
bGVtIEknbGwgZm9sZCB0aGlzIGludG8gY29yZS5oDQo+IA0KPiBNb3JlICJJIHdpbGwicy4gOikN
Cj4gDQo+IFBsZWFzZSBkbyB3aGF0J3MgcmlnaHQgZm9yICd0aGlzIHN1Ym1pc3Npb24nLiAgSWYg
dGhpbmdzIGNoYW5nZSBsYXRlcg0KPiB5b3UgY2FuIGFjdCBhY2NvcmRpbmdseS4NCg0KSXQncyBu
b3QgYSBjYXNlIG9mICdpZiB0aGluZ3MgY2hhbmdlJy4gVGhleSB3aWxsLiBBbnl3YXksIHdpbGwg
cmVmYWN0b3Igbm93IGFuZA0KcmV2ZXJ0IGxhdGVyLg0KDQo+IA0KPiAtLQ0KPiBMZWUgSm9uZXMN
Cj4gTGluYXJvIFNUTWljcm9lbGVjdHJvbmljcyBMYW5kaW5nIFRlYW0gTGVhZA0KPiBMaW5hcm8u
b3JnIOKUgiBPcGVuIHNvdXJjZSBzb2Z0d2FyZSBmb3IgQVJNIFNvQ3MNCj4gRm9sbG93IExpbmFy
bzogRmFjZWJvb2sgfCBUd2l0dGVyIHwgQmxvZw0K

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

* Re: [PATCH v2 3/7] iio: Add support for DA9150 GPADC
  2014-09-09 10:53       ` Opensource [Adam Thomson]
@ 2014-09-14 17:26         ` Jonathan Cameron
  2014-09-15 10:32           ` Opensource [Adam Thomson]
  0 siblings, 1 reply; 43+ messages in thread
From: Jonathan Cameron @ 2014-09-14 17:26 UTC (permalink / raw)
  To: Opensource [Adam Thomson], Peter Meerwald
  Cc: Lee Jones, linux-iio, Support Opensource

On 09/09/14 11:53, Opensource [Adam Thomson] wrote:
> On August 30, 2014 21:01, Jonathan Cameron wrote:
> 
>> On 28/08/14 12:28, Peter Meerwald wrote:
>>>
>>> some minor comments inline
>> A few more from me + make sure all your units match the ABI and in
>> particular that everything you use is documented in
>> Documentation/ABI/testing/syfs-bus-iio.  Some stuff that only
>> exists in staging drivers isn't documented in there as yet
>> (current measurements for example) so the docs will need additions
>> alongside this driver.
>>
>> Thanks,
>>
>> Jonathan
>>>
>>>> This patch adds support for DA9150 Charger & Fuel-Gauge IC GPADC.
>>>>
>>>> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
>>>> ---
>>>>  drivers/iio/adc/Kconfig        |   9 +
>>>>  drivers/iio/adc/Makefile       |   1 +
>>>>  drivers/iio/adc/da9150-gpadc.c | 430
>> +++++++++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 440 insertions(+)
>>>>  create mode 100644 drivers/iio/adc/da9150-gpadc.c
>>>>
>>>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>>>> index 11b048a..8041347 100644
>>>> --- a/drivers/iio/adc/Kconfig
>>>> +++ b/drivers/iio/adc/Kconfig
>>>> @@ -127,6 +127,15 @@ config AT91_ADC
>>>>  	help
>>>>  	  Say yes here to build support for Atmel AT91 ADC.
>>>>
>>>> +config DA9150_GPADC
>>>> +	tristate "Dialog DA9150 GPADC driver support"
>>>> +	depends on MFD_DA9150
>>>> +	help
>>>> +	  Say yes here to build support for Dialog DA9150 GPADC.
>>>> +
>>>> +	  This driver can also be built as a module. If chosen, the module name
>>>> +	  will be da9150-gpadc.
>>>> +
>>>>  config EXYNOS_ADC
>>>>  	tristate "Exynos ADC driver support"
>>>>  	depends on ARCH_EXYNOS || (OF && COMPILE_TEST)
>>>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>>>> index ad81b51..48413d2 100644
>>>> --- a/drivers/iio/adc/Makefile
>>>> +++ b/drivers/iio/adc/Makefile
>>>> @@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
>>>>  obj-$(CONFIG_AD7887) += ad7887.o
>>>>  obj-$(CONFIG_AD799X) += ad799x.o
>>>>  obj-$(CONFIG_AT91_ADC) += at91_adc.o
>>>> +obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
>>>>  obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
>>>>  obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
>>>>  obj-$(CONFIG_MAX1027) += max1027.o
>>>> diff --git a/drivers/iio/adc/da9150-gpadc.c b/drivers/iio/adc/da9150-gpadc.c
>>>> new file mode 100644
>>>> index 0000000..21a21a9
>>>> --- /dev/null
>>>> +++ b/drivers/iio/adc/da9150-gpadc.c
>>>> @@ -0,0 +1,430 @@
>>>> +/*
>>>> + * DA9150 GPADC Driver
>>>> + *
>>>> + * Copyright (c) 2014 Dialog Semiconductor
>>>> + *
>>>> + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
>>>> + *
>>>> + * This program is free software; you can redistribute  it and/or modify it
>>>> + * under  the terms of  the GNU General  Public License as published by the
>>>> + * Free Software Foundation;  either version 2 of the  License, or (at your
>>>> + * option) any later version.
>>>> + */
>>>> +
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/slab.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/interrupt.h>
>>>> +
>>>> +#include <linux/mfd/da9150/core.h>
>>>> +#include <linux/mfd/da9150/pdata.h>
>>>> +#include <linux/mfd/da9150/registers.h>
>>>> +
>>>> +#include <linux/iio/iio.h>
>>>> +#include <linux/iio/machine.h>
>>>> +#include <linux/iio/driver.h>
>>>> +
>>>> +
>>>> +/* Channels */
>>>> +enum da9150_gpadc_hw_channel {
>>>> +	DA9150_GPADC_HW_CHAN_GPIOA_2V = 0,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOA_2V_,
>>>
>>> why the underscore_ notation?
>>> couldn't you use e.g. DA9150_GPADC_HW_CHAN_GPIOB_2V = 2?
>>>
>>>> +	DA9150_GPADC_HW_CHAN_GPIOB_2V,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOB_2V_,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOC_2V,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOC_2V_,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOD_2V,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOD_2V_,
>>>> +	DA9150_GPADC_HW_CHAN_IBUS_SENSE,
>>>> +	DA9150_GPADC_HW_CHAN_IBUS_SENSE_,
>>>> +	DA9150_GPADC_HW_CHAN_VBUS_DIV,
>>>> +	DA9150_GPADC_HW_CHAN_VBUS_DIV_,
>>>> +	DA9150_GPADC_HW_CHAN_ID,
>>>> +	DA9150_GPADC_HW_CHAN_ID_,
>>>> +	DA9150_GPADC_HW_CHAN_VSYS,
>>>> +	DA9150_GPADC_HW_CHAN_VSYS_,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOA_5V,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOA_5V_,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOB_5V,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOB_5V_,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOC_5V,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOC_5V_,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOD_5V,
>>>> +	DA9150_GPADC_HW_CHAN_GPIOD_5V_,
>>>> +	DA9150_GPADC_HW_CHAN_VBAT,
>>>> +	DA9150_GPADC_HW_CHAN_VBAT_,
>>>> +	DA9150_GPADC_HW_CHAN_TBAT,
>>>> +	DA9150_GPADC_HW_CHAN_TBAT_,
>>>> +	DA9150_GPADC_HW_CHAN_TJUNC_CORE,
>>>> +	DA9150_GPADC_HW_CHAN_TJUNC_CORE_,
>>>> +	DA9150_GPADC_HW_CHAN_TJUNC_OVP,
>>>> +	DA9150_GPADC_HW_CHAN_TJUNC_OVP_,
>>>> +};
>>>> +
>>>> +enum da9150_gpadc_channel {
>>>> +	DA9150_GPADC_CHAN_GPIOA = 0,
>>>> +	DA9150_GPADC_CHAN_GPIOB,
>>>> +	DA9150_GPADC_CHAN_GPIOC,
>>>> +	DA9150_GPADC_CHAN_GPIOD,
>>>> +	DA9150_GPADC_CHAN_IBUS,
>>>> +	DA9150_GPADC_CHAN_VBUS,
>>>> +	DA9150_GPADC_CHAN_ID,
>>>> +	DA9150_GPADC_CHAN_VSYS,
>>>> +	DA9150_GPADC_CHAN_VBAT,
>>>> +	DA9150_GPADC_CHAN_TBAT,
>>>> +	DA9150_GPADC_CHAN_TJUNC_CORE,
>>>> +	DA9150_GPADC_CHAN_TJUNC_OVP,
>>>> +};
>>>> +
>>>> +/* Private data */
>>>> +struct da9150_gpadc {
>>>> +	struct da9150 *da9150;
>>>> +	struct device *dev;
>>>> +
>>>> +	struct mutex lock;
>>>> +	struct completion complete;
>>>> +};
>>>> +
>>>> +
>>>> +static irqreturn_t da9150_gpadc_irq(int irq, void *data)
>>>> +{
>>>> +
>>>> +	struct da9150_gpadc *gpadc = data;
>>>> +
>>>> +	complete(&gpadc->complete);
>>>> +
>>>> +	return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +int da9150_gpadc_read_adc(struct da9150_gpadc *gpadc, int hw_chan)
>>>
>>> static?
>>>
>>>> +{
>>>> +	u8 result_regs[2];
>>>> +	int result;
>>>> +
>>>> +	mutex_lock(&gpadc->lock);
>>>> +
>>>> +	/* Set channel & enable measurement */
>>>> +	da9150_reg_write(gpadc->da9150, DA9150_GPADC_MAN,
>>>> +			 (DA9150_GPADC_EN_MASK |
>>>> +			  hw_chan << DA9150_GPADC_MUX_SHIFT));
>>>> +
>>>> +	/* Consume left-over completion from a previous timeout */
>>>> +	try_wait_for_completion(&gpadc->complete);
>>>> +
>>>> +	/* Check for actual completion */
>>>> +	wait_for_completion_timeout(&gpadc->complete, msecs_to_jiffies(5));
>>>> +
>>>> +	/* Read result and status from device */
>>>> +	da9150_bulk_read(gpadc->da9150, DA9150_GPADC_RES_A, 2, result_regs);
>>>> +
>>>> +	mutex_unlock(&gpadc->lock);
>>>> +
>>>> +	/* Check to make sure device really has completed reading */
>>>> +	if (result_regs[1] & DA9150_GPADC_RUN_MASK) {
>>>> +		dev_err(gpadc->dev, "Timeout on channel %d of GP-ADC\n",
>>>
>>> GPADC everywhere else
>>>
>>>> +			hw_chan);
>>>> +		return -ETIMEDOUT;
>>>> +	}
>>>> +
>>>> +	/* LSBs - 2 bits */
>>>> +	result = (result_regs[1] & DA9150_GPADC_RES_L_MASK) >>
>>>> +		 DA9150_GPADC_RES_L_SHIFT;
>>>> +	/* MSBs - 8 bits */
>>>> +	result |= result_regs[0] << DA9150_GPADC_RES_L_BITS;
>>>
>>> can't the read be done with a 16bit read?
>>>
>>>> +
>>>> +	return result;
>>>> +}
>>>> +
>>>> +static inline int da9150_gpadc_gpio_5v_voltage_now(int raw_val)
>>>> +{
>>>> +	/* Convert to uV */
>>>> +	return (((6 * ((raw_val * 1000) + 500)) / 1024) * 1000);
>> Base units of voltage are millivolts.  See Documentation/ABI/testing/sysfs-bus-iio.
> 
> Right. Ok.
> 
>>>
>>> outer parenthesis not needed, here and below
>>>
>>>> +}
>>>> +
>>>> +static inline int da9150_gpadc_ibus_current_avg(int raw_val)
>>>> +{
>>>> +	/* Convert to uA */
>>>> +	return (((4 * ((raw_val * 1000) + 500)) / 2048) * 1000);
>> interestingly this is actually our first current channel outside staging.
>> As such the docs don't cover it.  Please add, keeping inline with the
>> units used in hwmon. mA, IIRC
> 
> Right, ok.
> 
>>>> +}
>>>> +
>>>> +static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
>>>> +{
>>>> +	/* Convert to uV */
>>>> +	return (((21 * ((raw_val * 1000) + 500)) / 1024) * 1000);
>>>> +}
>>>> +
>>>> +static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
>>>> +{
>>>> +	/* Convert to uV */
>>>> +	return (((3 * ((raw_val * 1000) + 500)) / 512) * 1000);
>>>> +}
>>>> +
>>>> +static inline int da9150_gpadc_tjunc_temp(int raw_val)
>>>> +{
>>>> +	/* Convert to 0.1 degrees C */
>>>
>>> IIO wants mille degrees C
>> Exactly.  Please check all of these correspond to the base units required
>> by the documentation.  Most of these might be better handled as raw
>> with scale and offset provided, letting the maths be doing in userspace using
>> floating point.
> 
> Some are needed by the charger driver. The intention of adding the conversions
> here was so this knowledge was not needed in the charger driver. Seems wrong to
> move the calculations out of the IIO driver. Most of these are not simple linear
> so scale and offset will not work, unless I'm missing something.
Umm. They all appear to be simple linear conversions to me - be it written a form
that slightly obscures that fact. But I'm not that fussed if you really want to
do them in kernel.
> 
>>>
>>>> +	return (((879 - (1023 - raw_val)) * 10000) / 4420);
>>>> +}
>>>> +
>>>> +static inline int da9150_gpadc_vbat_voltage_now(int raw_val)
>>>> +{
>>>> +	/* Convert to uV */
>>>> +	return ((2932 * raw_val) + 1500000);
>>>> +}
>>>> +
>>>> +int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
>>>> +				int hw_chan)
>>>
>>> static?
>>>
>>>> +{
>>>> +	int raw_val, ret;
>>>> +
>>>> +	raw_val = da9150_gpadc_read_adc(gpadc, hw_chan);
>>>> +	if (raw_val < 0)
>>>> +		return raw_val;
>>>> +
>>>> +	switch (channel) {
>>>> +	case DA9150_GPADC_CHAN_GPIOA:
>>>> +	case DA9150_GPADC_CHAN_GPIOB:
>>>> +	case DA9150_GPADC_CHAN_GPIOC:
>>>> +	case DA9150_GPADC_CHAN_GPIOD:
>>>> +		ret = da9150_gpadc_gpio_5v_voltage_now(raw_val);
>>>
>>> could return directly ...
>>>
>>>> +		break;
>>>> +	case DA9150_GPADC_CHAN_IBUS:
>>>> +		ret = da9150_gpadc_ibus_current_avg(raw_val);
>>>> +		break;
>>>> +	case DA9150_GPADC_CHAN_VBUS:
>>>> +		ret = da9150_gpadc_vbus_21v_voltage_now(raw_val);
>>>> +		break;
>>>> +	case DA9150_GPADC_CHAN_VSYS:
>>>> +		ret = da9150_gpadc_vsys_6v_voltage_now(raw_val);
>>>> +		break;
>>>> +	case DA9150_GPADC_CHAN_TJUNC_CORE:
>>>> +	case DA9150_GPADC_CHAN_TJUNC_OVP:
>>>> +		ret = da9150_gpadc_tjunc_temp(raw_val);
>>>> +		break;
>>>> +	default:
>>>> +		/* No processing for other channels so return raw value */
>>>> +		ret = raw_val;
>>>> +		break;
>>>> +	}
>>>
>>> and save the final return
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +int da9150_gpadc_read_scale(int channel)
>>>
>>> static?
>>>
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	switch (channel) {
>>>> +	case DA9150_GPADC_CHAN_VBAT:
>>>> +		ret = 2932;
>>>
>>> return directly?
>>>
>>>> +		break;
>>>> +	default:
>>>> +		ret = -EINVAL;
>>>> +	}
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +int da9150_gpadc_read_offset(int channel)
>>>> +{
>>>> +	int ret;
>>>> +
>>>> +	switch (channel) {
>>>> +	case DA9150_GPADC_CHAN_VBAT:
>>>> +		ret = 1500000 / 2932;
>>>
>>> return directly?
>>>
>>>> +		break;
>>>> +	default:
>>>> +		ret = -EINVAL;
>>>> +	}
>>>> +
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +int da9150_gpadc_read_raw(struct iio_dev *indio_dev,
>>>> +			  struct iio_chan_spec const *chan,
>>>> +			  int *val, int *val2, long mask)
>>>
>>> static?
>>>
>>>> +{
>>>> +	struct da9150_gpadc *gpadc = iio_priv(indio_dev);
>>>> +	int ret;
>>>> +
>>>> +	if ((chan->channel < DA9150_GPADC_CHAN_GPIOA) ||
>>>> +	    (chan->channel > DA9150_GPADC_CHAN_TJUNC_OVP))
>>>> +		return -EINVAL;
>>>> +
>>>> +	switch (mask) {
>>>> +	case IIO_CHAN_INFO_RAW:
>>>> +	case IIO_CHAN_INFO_PROCESSED:
>> Would be cleaner to have each of these functions use ret for return code
>> including IIO_VAL_INT and pass val as an arguement.  Would get rid
>> of the fiddly handling at the end of this function and allow direct
>> returns from each of the case statements.
>>
>> Also, are the base units of all of these channels really giving us
>> an integer result?  E.g. mV, mA etc? Not impossible, but seems unlikely!
> 
> Ok, I can make that change. Wouldn't say what was there now is fiddly, but am
> happy to update.
> 
> In terms of base units, they are actually in V or A, rather than say mV or mA,
> according to the datasheet, but as there's no floating point support in the
> kernel the sensible option was to provide them in smaller units and provide
> greater accuracy.
No it really isn't. There is no floating point in kernel, so we simulate the
effect using the IIO_VAL types and a pair of 32bit integers.  It's not ideal
but it does allow us to cover any plausible range.  The reason other drivers need to
match it is that we need a clean ABI to userspace.  Hence they must all be the same.
This is why we try to move the conversions into userspace where possible.  It can
be done in kernel but is admittedly rather fiddly!
> 
>>
>>>> +		ret = da9150_gpadc_read_processed(gpadc, chan->channel,
>>>> +						  chan->address);
>>>> +		break;
>>>> +	case IIO_CHAN_INFO_SCALE:
>>>> +		ret = da9150_gpadc_read_scale(chan->channel);
>>>> +		break;
>>>> +	case IIO_CHAN_INFO_OFFSET:
>>>> +		ret = da9150_gpadc_read_offset(chan->channel);
>>>> +		break;
>>>> +	default:
>>>> +		ret = -EINVAL;
>>>> +		break;
>>>> +	}
>>>> +
>>>> +	if (ret < 0)
>>>> +		return ret;
>>>> +
>>>> +	*val = ret;
>>>> +
>>>> +	return IIO_VAL_INT;
>>>> +}
>>>> +
>>>> +static const struct iio_info da9150_gpadc_info = {
>>>> +	.read_raw = &da9150_gpadc_read_raw,
>>>> +	.driver_module = THIS_MODULE,
>>>> +};
>>>> +
>>>> +#define GPADC_CHANNEL(_id, _hw_id, _type, chan_info, _ext_name) {	\
>>>> +	.type = _type,							\
>>>> +	.indexed = 1,							\
>>>
>>> there is only one current channel, it should not be indexed
>> Optional. Either way userspace should cope fine. At one point I thought
>> about insisting everything was indexed, to reduce userspace complexity
>> (ever so slightly) but was a bit late by the time I thought of it ;)
> 
> If it's ok, I will leave as is as to keep this macro common.
> 
>>>
>>>> +	.channel = DA9150_GPADC_CHAN_##_id,				\
>>>> +	.address = DA9150_GPADC_HW_CHAN_##_hw_id,			\
>>>> +	.info_mask_separate = chan_info,				\
>>>> +	.extend_name = _ext_name,					\
>>>> +	.datasheet_name = #_id,						\
>>>> +}
>>>> +
>>>> +#define GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name)	\
>>>> +	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_RAW),
>> _ext_name)
>>>> +
>>>> +#define GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name)	\
>>>> +	GPADC_CHANNEL(_id, _hw_id, _type,			\
>>>> +		      BIT(IIO_CHAN_INFO_RAW) |			\
>>>> +		      BIT(IIO_CHAN_INFO_SCALE) |		\
>>>> +		      BIT(IIO_CHAN_INFO_OFFSET),		\
>>>> +		      _ext_name)
>>>> +
>>>> +#define GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name)
>> 	\
>>>> +	GPADC_CHANNEL(_id, _hw_id, _type, BIT(IIO_CHAN_INFO_PROCESSED),	\
>>>> +		      _ext_name)
>> This macro and similar need a DA9150 prefix to avoid likely name clashes in
>> future.
> 
> Fair point. Will update.
> 
>>>> +
>>>> +/* Supported channels */
>>>> +static const struct iio_chan_spec da9150_gpadc_channels[] = {
>>>> +	GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_5V, IIO_VOLTAGE, "GPIOA"),
>>>> +	GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_5V, IIO_VOLTAGE, "GPIOB"),
>>>> +	GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_5V, IIO_VOLTAGE, "GPIOC"),
>>>> +	GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_5V, IIO_VOLTAGE, "GPIOD"),
>>>> +	GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
>>>> +	GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
>>>> +	GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
>>>> +	GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
>>>> +	GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
>>>> +	GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
>>>> +	GPADC_CHANNEL_PROCESSED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP,
>> "TJUNC_CORE"),
>>>> +	GPADC_CHANNEL_PROCESSED(TJUNC_OVP, TJUNC_OVP, IIO_TEMP,
>> "TJUNC_OVP"),
>>>> +};
>>>> +
>>>> +/* Default maps used by da9150-charger */
>>>> +static struct iio_map da9150_gpadc_default_maps[] = {
>>>> +	{
>>>> +		.consumer_dev_name = "da9150-charger",
>>>> +		.consumer_channel = "CHAN_IBUS",
>>>> +		.adc_channel_label = "IBUS",
>>>> +	},
>>>> +	{
>>>> +		.consumer_dev_name = "da9150-charger",
>>>> +		.consumer_channel = "CHAN_VBUS",
>>>> +		.adc_channel_label = "VBUS",
>>>> +	},
>>>> +	{
>>>> +		.consumer_dev_name = "da9150-charger",
>>>> +		.consumer_channel = "CHAN_TJUNC",
>>>> +		.adc_channel_label = "TJUNC_CORE",
>>>> +	},
>>>> +	{
>>>> +		.consumer_dev_name = "da9150-charger",
>>>> +		.consumer_channel = "CHAN_VBAT",
>>>> +		.adc_channel_label = "VBAT",
>>>> +	},
>>>> +	{},
>>>> +};
>>>> +
>>>> +static int da9150_gpadc_probe(struct platform_device *pdev)
>>>> +{
>>>> +	struct device *dev = &pdev->dev;
>>>> +	struct da9150 *da9150 = dev_get_drvdata(dev->parent);
>>>> +	struct da9150_gpadc *gpadc;
>>>> +	struct iio_dev *indio_dev;
>>>> +	int ret;
>>>> +
>>>> +	indio_dev = devm_iio_device_alloc(&pdev->dev,
>>>> +					  sizeof(struct da9150_gpadc));
>>>> +	if (!indio_dev) {
>>>> +		dev_err(&pdev->dev, "Failed to allocate IIO device\n");
>>>> +		return -ENOMEM;
>>>> +	}
>>>> +	gpadc = iio_priv(indio_dev);
>>>> +
>>>> +	platform_set_drvdata(pdev, indio_dev);
>>>> +	gpadc->da9150 = da9150;
>>>> +	gpadc->dev = dev;
>>>> +
>>>> +	ret = iio_map_array_register(indio_dev, da9150_gpadc_default_maps);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "Failed to register IIO maps: %d\n", ret);
>>>> +		goto iio_map_fail;
>>>
>>> just return here?
>>>
>>>> +	}
>>>> +
>>>> +	mutex_init(&gpadc->lock);
>>>> +	init_completion(&gpadc->complete);
>>>> +
>>>> +	/* Register IRQ */
>>>> +	ret = da9150_register_irq(pdev, gpadc, da9150_gpadc_irq, "GPADC");
>> This function wants renaming to indicate that it is doing a managed
>> irq request... devm_da9150 etc would be conventional ;)
> 
> Yep, it's a good point. Will update.
> 
>>>> +	if (ret < 0)
>>>> +		goto irq_fail;
>>>> +
>>>> +	indio_dev->name = dev_name(dev);
>>>> +	indio_dev->dev.parent = dev;
>>>> +	indio_dev->dev.of_node = pdev->dev.of_node;
>>>> +	indio_dev->info = &da9150_gpadc_info;
>>>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>>>> +	indio_dev->channels = da9150_gpadc_channels;
>>>> +	indio_dev->num_channels = ARRAY_SIZE(da9150_gpadc_channels);
>>>> +
>>>> +	ret = iio_device_register(indio_dev);
>>>> +	if (ret) {
>>>> +		dev_err(dev, "Failed to register IIO device: %d\n", ret);
>>>> +		goto iio_dev_fail;
>>>> +	}
>>>> +
>>>> +	return ret;
>>>> +
>>>> +iio_dev_fail:
>>>> +irq_fail:
>>>
>>> why two labels?
>>>
>>>> +	iio_map_array_unregister(indio_dev);
>>>> +
>>>> +iio_map_fail:
>>>> +	return ret;
>>>> +}
>>>> +
>>>> +static int da9150_gpadc_remove(struct platform_device *pdev)
>>>> +{
>>>> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>>>> +
>>>> +	iio_map_array_unregister(indio_dev);
>>>
>>> unregister irq?
>> Not actually needed as it was a devm register - having said that
>> the function should indicate that it's naming.
> 
> Agreed.
> 
>>>
>>>> +	iio_device_unregister(indio_dev);
>>>> +
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static struct platform_driver da9150_gpadc_driver = {
>>>> +	.driver = {
>>>> +		.name = "da9150-gpadc",
>>>> +		.owner = THIS_MODULE,
>>>> +	},
>>>> +	.probe = da9150_gpadc_probe,
>>>> +	.remove = da9150_gpadc_remove,
>>>> +};
>>>> +
>>>> +module_platform_driver(da9150_gpadc_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("GPADC Driver for DA9150");
>>>> +MODULE_AUTHOR("Adam Thomson
>> <Adam.Thomson.Opensource@diasemi.com");
>>>> +MODULE_LICENSE("GPL");
>>>> --
>>>> 1.9.3
>>>>
>>>> --
>>>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>>>> the body of a message to majordomo@vger.kernel.org
>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>> Please read the FAQ at  http://www.tux.org/lkml/
>>>>
>>>

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

* RE: [PATCH v2 3/7] iio: Add support for DA9150 GPADC
  2014-09-14 17:26         ` Jonathan Cameron
@ 2014-09-15 10:32           ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-15 10:32 UTC (permalink / raw)
  To: Jonathan Cameron, Opensource [Adam Thomson], Peter Meerwald
  Cc: Lee Jones, linux-iio, Support Opensource

T24gU2VwdGVtYmVyIDE0LCAyMDE0IDE4OjI2LCBKb25hdGhhbiBDYW1lcm9uIHdyb3RlOg0KDQo+
ID4+Pj4gK30NCj4gPj4+PiArDQo+ID4+Pj4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1MF9ncGFk
Y192YnVzXzIxdl92b2x0YWdlX25vdyhpbnQgcmF3X3ZhbCkNCj4gPj4+PiArew0KPiA+Pj4+ICsJ
LyogQ29udmVydCB0byB1ViAqLw0KPiA+Pj4+ICsJcmV0dXJuICgoKDIxICogKChyYXdfdmFsICog
MTAwMCkgKyA1MDApKSAvIDEwMjQpICogMTAwMCk7DQo+ID4+Pj4gK30NCj4gPj4+PiArDQo+ID4+
Pj4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1MF9ncGFkY192c3lzXzZ2X3ZvbHRhZ2Vfbm93KGlu
dCByYXdfdmFsKQ0KPiA+Pj4+ICt7DQo+ID4+Pj4gKwkvKiBDb252ZXJ0IHRvIHVWICovDQo+ID4+
Pj4gKwlyZXR1cm4gKCgoMyAqICgocmF3X3ZhbCAqIDEwMDApICsgNTAwKSkgLyA1MTIpICogMTAw
MCk7DQo+ID4+Pj4gK30NCj4gPj4+PiArDQo+ID4+Pj4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1
MF9ncGFkY190anVuY190ZW1wKGludCByYXdfdmFsKQ0KPiA+Pj4+ICt7DQo+ID4+Pj4gKwkvKiBD
b252ZXJ0IHRvIDAuMSBkZWdyZWVzIEMgKi8NCj4gPj4+DQo+ID4+PiBJSU8gd2FudHMgbWlsbGUg
ZGVncmVlcyBDDQo+ID4+IEV4YWN0bHkuICBQbGVhc2UgY2hlY2sgYWxsIG9mIHRoZXNlIGNvcnJl
c3BvbmQgdG8gdGhlIGJhc2UgdW5pdHMgcmVxdWlyZWQNCj4gPj4gYnkgdGhlIGRvY3VtZW50YXRp
b24uICBNb3N0IG9mIHRoZXNlIG1pZ2h0IGJlIGJldHRlciBoYW5kbGVkIGFzIHJhdw0KPiA+PiB3
aXRoIHNjYWxlIGFuZCBvZmZzZXQgcHJvdmlkZWQsIGxldHRpbmcgdGhlIG1hdGhzIGJlIGRvaW5n
IGluIHVzZXJzcGFjZSB1c2luZw0KPiA+PiBmbG9hdGluZyBwb2ludC4NCj4gPg0KPiA+IFNvbWUg
YXJlIG5lZWRlZCBieSB0aGUgY2hhcmdlciBkcml2ZXIuIFRoZSBpbnRlbnRpb24gb2YgYWRkaW5n
IHRoZSBjb252ZXJzaW9ucw0KPiA+IGhlcmUgd2FzIHNvIHRoaXMga25vd2xlZGdlIHdhcyBub3Qg
bmVlZGVkIGluIHRoZSBjaGFyZ2VyIGRyaXZlci4gU2VlbXMgd3JvbmcgdG8NCj4gPiBtb3ZlIHRo
ZSBjYWxjdWxhdGlvbnMgb3V0IG9mIHRoZSBJSU8gZHJpdmVyLiBNb3N0IG9mIHRoZXNlIGFyZSBu
b3Qgc2ltcGxlIGxpbmVhcg0KPiA+IHNvIHNjYWxlIGFuZCBvZmZzZXQgd2lsbCBub3Qgd29yaywg
dW5sZXNzIEknbSBtaXNzaW5nIHNvbWV0aGluZy4NCj4gVW1tLiBUaGV5IGFsbCBhcHBlYXIgdG8g
YmUgc2ltcGxlIGxpbmVhciBjb252ZXJzaW9ucyB0byBtZSAtIGJlIGl0IHdyaXR0ZW4gYSBmb3Jt
DQo+IHRoYXQgc2xpZ2h0bHkgb2JzY3VyZXMgdGhhdCBmYWN0LiBCdXQgSSdtIG5vdCB0aGF0IGZ1
c3NlZCBpZiB5b3UgcmVhbGx5IHdhbnQgdG8NCj4gZG8gdGhlbSBpbiBrZXJuZWwuDQoNCkkgbG9v
a2VkIGF0IHRoZSB2b2x0YWdlIGNhbGN1bGF0aW9ucyBhbmQgaG93IEkgY291bGQgdXNlIHRoZSBz
Y2FsZSAmIG9mZnNldA0KZmVhdHVyZXMgYWxyZWFkeSBwcm92aWRlZC4gVGhlIHByb2JsZW0gaXMg
dGhhdCB0aGUgb2Zmc2V0IHZhbHVlIGlzIGEgZnJhY3Rpb24NCmlmIGFkZGVkIHRvIHRoZSByYXcg
dmFsdWUgZmlyc3QgYmVmb3JlIHNjYWxlIChhcyB3b3VsZCBiZSBkb25lIGluIHRoZSBpbmtlcm4u
Yw0KY29kZSksIHNvIEkgY291bGQgbm90IHNlZSBhIHdheSB0byBnZXQgYW4gYWNjdXJhdGUgZW5v
dWdoIHJlc3VsdCB3aXRob3V0IGRvaW5nDQp0aGUgY2FsY3VsYXRpb24gaGVyZS4gSSB3aWxsIGhv
d2V2ZXIgcmVtb3ZlIHRoZSBmdW5jdGlvbiBmb3IgdGp1bmNfdGVtcCBhcyB0aGlzDQpjYW4gYmUg
ZG9uZSB1c2luZyBzY2FsZSBhbmQgb2Zmc2V0LCBzbyB3aWxsIHVwZGF0ZSBhY2NvcmRpbmdseS4N
Cg0KPiA+Pj4+ICt7DQo+ID4+Pj4gKwlzdHJ1Y3QgZGE5MTUwX2dwYWRjICpncGFkYyA9IGlpb19w
cml2KGluZGlvX2Rldik7DQo+ID4+Pj4gKwlpbnQgcmV0Ow0KPiA+Pj4+ICsNCj4gPj4+PiArCWlm
ICgoY2hhbi0+Y2hhbm5lbCA8IERBOTE1MF9HUEFEQ19DSEFOX0dQSU9BKSB8fA0KPiA+Pj4+ICsJ
ICAgIChjaGFuLT5jaGFubmVsID4gREE5MTUwX0dQQURDX0NIQU5fVEpVTkNfT1ZQKSkNCj4gPj4+
PiArCQlyZXR1cm4gLUVJTlZBTDsNCj4gPj4+PiArDQo+ID4+Pj4gKwlzd2l0Y2ggKG1hc2spIHsN
Cj4gPj4+PiArCWNhc2UgSUlPX0NIQU5fSU5GT19SQVc6DQo+ID4+Pj4gKwljYXNlIElJT19DSEFO
X0lORk9fUFJPQ0VTU0VEOg0KPiA+PiBXb3VsZCBiZSBjbGVhbmVyIHRvIGhhdmUgZWFjaCBvZiB0
aGVzZSBmdW5jdGlvbnMgdXNlIHJldCBmb3IgcmV0dXJuIGNvZGUNCj4gPj4gaW5jbHVkaW5nIElJ
T19WQUxfSU5UIGFuZCBwYXNzIHZhbCBhcyBhbiBhcmd1ZW1lbnQuICBXb3VsZCBnZXQgcmlkDQo+
ID4+IG9mIHRoZSBmaWRkbHkgaGFuZGxpbmcgYXQgdGhlIGVuZCBvZiB0aGlzIGZ1bmN0aW9uIGFu
ZCBhbGxvdyBkaXJlY3QNCj4gPj4gcmV0dXJucyBmcm9tIGVhY2ggb2YgdGhlIGNhc2Ugc3RhdGVt
ZW50cy4NCj4gPj4NCj4gPj4gQWxzbywgYXJlIHRoZSBiYXNlIHVuaXRzIG9mIGFsbCBvZiB0aGVz
ZSBjaGFubmVscyByZWFsbHkgZ2l2aW5nIHVzDQo+ID4+IGFuIGludGVnZXIgcmVzdWx0PyAgRS5n
LiBtViwgbUEgZXRjPyBOb3QgaW1wb3NzaWJsZSwgYnV0IHNlZW1zIHVubGlrZWx5IQ0KPiA+DQo+
ID4gT2ssIEkgY2FuIG1ha2UgdGhhdCBjaGFuZ2UuIFdvdWxkbid0IHNheSB3aGF0IHdhcyB0aGVy
ZSBub3cgaXMgZmlkZGx5LCBidXQgYW0NCj4gPiBoYXBweSB0byB1cGRhdGUuDQo+ID4NCj4gPiBJ
biB0ZXJtcyBvZiBiYXNlIHVuaXRzLCB0aGV5IGFyZSBhY3R1YWxseSBpbiBWIG9yIEEsIHJhdGhl
ciB0aGFuIHNheSBtViBvciBtQSwNCj4gPiBhY2NvcmRpbmcgdG8gdGhlIGRhdGFzaGVldCwgYnV0
IGFzIHRoZXJlJ3Mgbm8gZmxvYXRpbmcgcG9pbnQgc3VwcG9ydCBpbiB0aGUNCj4gPiBrZXJuZWwg
dGhlIHNlbnNpYmxlIG9wdGlvbiB3YXMgdG8gcHJvdmlkZSB0aGVtIGluIHNtYWxsZXIgdW5pdHMg
YW5kIHByb3ZpZGUNCj4gPiBncmVhdGVyIGFjY3VyYWN5Lg0KPiBObyBpdCByZWFsbHkgaXNuJ3Qu
IFRoZXJlIGlzIG5vIGZsb2F0aW5nIHBvaW50IGluIGtlcm5lbCwgc28gd2Ugc2ltdWxhdGUgdGhl
DQo+IGVmZmVjdCB1c2luZyB0aGUgSUlPX1ZBTCB0eXBlcyBhbmQgYSBwYWlyIG9mIDMyYml0IGlu
dGVnZXJzLiAgSXQncyBub3QgaWRlYWwNCj4gYnV0IGl0IGRvZXMgYWxsb3cgdXMgdG8gY292ZXIg
YW55IHBsYXVzaWJsZSByYW5nZS4gIFRoZSByZWFzb24gb3RoZXIgZHJpdmVycyBuZWVkIHRvDQo+
IG1hdGNoIGl0IGlzIHRoYXQgd2UgbmVlZCBhIGNsZWFuIEFCSSB0byB1c2Vyc3BhY2UuICBIZW5j
ZSB0aGV5IG11c3QgYWxsIGJlIHRoZSBzYW1lLg0KPiBUaGlzIGlzIHdoeSB3ZSB0cnkgdG8gbW92
ZSB0aGUgY29udmVyc2lvbnMgaW50byB1c2Vyc3BhY2Ugd2hlcmUgcG9zc2libGUuICBJdCBjYW4N
Cj4gYmUgZG9uZSBpbiBrZXJuZWwgYnV0IGlzIGFkbWl0dGVkbHkgcmF0aGVyIGZpZGRseSENCg0K
T2YgY291cnNlLiBXaWxsIG1ha2Ugc3VyZSB0aGUgY29ycmVjdCB0eXBlcyBhcmUgcHJvdmlkZWQg
dG8ga2VlcCBpbi1saW5lIHdpdGgNCnRoaXMuIFRoYW5rcy4NCg==

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

* Re: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-09-10 15:58           ` Opensource [Adam Thomson]
  (?)
  (?)
@ 2014-09-15 22:39           ` Lee Jones
  2014-09-16 10:50               ` Opensource [Adam Thomson]
  -1 siblings, 1 reply; 43+ messages in thread
From: Lee Jones @ 2014-09-15 22:39 UTC (permalink / raw)
  To: Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

On Wed, 10 Sep 2014, Opensource [Adam Thomson] wrote:
> On September 10, 2014 10:50, Lee Jones wrote:
> > On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> > 
> > > On August 28, 2014 17:36, Lee Jones wrote:
> > >
> > > Thanks for the feedback. As a general comment a couple of the items you've
> > > identified relate to future updates (additional functionality being added).
> > > I already have code in place for this but have stripped out a couple of the
> > > drivers just to reduce the churn and size of patch submission. These will be
> > > added once these patches have been accepted.
> > >
> > > Where this is the case, I have added notes in-line against the relevant
> > > comments you made.
> > >
> > > > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > > >
> > > > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > > > GPIO and GPADC functionality.
> > > > >
> > > > > Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
> > > > > ---
> > > > >  drivers/mfd/Kconfig                  |   12 +
> > > > >  drivers/mfd/Makefile                 |    2 +
> > > > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > > > >  drivers/mfd/da9150-i2c.c             |  176 ++++++

[...]

> > > > > +/* Helper functions for sub-devices to request/free IRQs */
> > > > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > > > +			irq_handler_t handler, const char *name)
> > > > > +{
> > > > > +	int irq, ret;
> > > > > +
> > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > +	if (irq < 0)
> > > > > +		return irq;
> > > > > +
> > > > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > > > +					IRQF_ONESHOT, name, dev_id);
> > > > > +	if (ret)
> > > > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> > > > > +
> > > > > +	return ret;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > > >
> > > > Why do they need help?  What problem does adding these layers solve?
> > >
> > > Means I don't have to keep adding print error lines everywhere else if this
> > > function takes care of it. Thought that would be cleaner.
> > 
> > You only need to request each IRQ once.  It's just more abstraction
> > for the sake of it.  I would prefer if you removed them.
> 
> Yes, but in the charger driver for example, there are 4 IRQs to request. If
> I don't use this approach the IRQ requesting becomes bloated, hence why I went
> for a common function like this. Thought generally the intention was to cut
> down on repeated code?

If you're worried about bloat in .probe() it's okay to define a new
function within the charger driver; however, creating a call-back into
the MFD driver like this I think it over-kill for 4 requests.

> > > > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > > > +		       const char *name)
> > > > > +{
> > > > > +	int irq;
> > > > > +
> > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > +	if (irq < 0)
> > > > > +		return;
> > > > > +
> > > > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > > >
> > > > Do you ever release the IRQ and not unbind the driver?
> > > >
> > > > Are there ordering issues at play here?
> > > >
> > > > If not, there's no need to conduct a manual free.
> > >
> > > In the charger driver, in the remove function there is a need I believe to
> > > free the IRQs before other items are cleared up (e.g. power_supply classes),
> > > so this is why I have added this in here.
> > 
> > Can you handle this separately in the Charger driver then please?
> > 
> > [...]
> 
> If I have to remove the IRQ register function, then yes, otherwise it makes more
> sense to have the pair of functions in the MFD core I would say.

I would prefer you to remove the call-back please.

> > > > > +	if (pdata)
> > > > > +		da9150->irq_base = pdata->irq_base;
> > > > > +	else
> > > > > +		da9150->irq_base = -1;
> > > >
> > > > pdata ? pdata->irq_base : -1;
> > >
> > > This is left this way as later updates to add additional functionality will
> > > require addtional work to be done with the platform data. Seemed pointless
> > > changing it here just to change it back later.
> > 
> > You're not changing anything, as this is the introduction of the code.
> > I can't tell you how many times I've heard "I will change it later",
> > or "doing it this way will support subsequent submissions", then
> > received no more patches.  It's okay to do it nicely now and expand
> > it back out in the new patches.
> > 
> > [...]
> 
> It appears that way to you but I have to modify my code for sumbission as the
> local code I have covers all functionality. Am having to refactor again and
> again just to suit this initial submission, and then I have to revert it back
> again when submitting the last couple of drivers. Time consuming, and quite
> frustrating when the intention was to make the whole process easier. Anyway,
> will update for now and revert in subsequent patches.

I sincerely hope the refactorings won't add too much effort, but it's
difficult to have one rule for the masses and different ones for
others.

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

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
  2014-09-15 22:39           ` Lee Jones
  2014-09-16 10:50               ` Opensource [Adam Thomson]
@ 2014-09-16 10:50               ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-16 10:50 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 6374 bytes --]

On September 15, 2014 23:39, Lee Jones wrote:

> On Wed, 10 Sep 2014, Opensource [Adam Thomson] wrote:
> > On September 10, 2014 10:50, Lee Jones wrote:
> > > On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> > >
> > > > On August 28, 2014 17:36, Lee Jones wrote:
> > > >
> > > > Thanks for the feedback. As a general comment a couple of the items you've
> > > > identified relate to future updates (additional functionality being added).
> > > > I already have code in place for this but have stripped out a couple of the
> > > > drivers just to reduce the churn and size of patch submission. These will be
> > > > added once these patches have been accepted.
> > > >
> > > > Where this is the case, I have added notes in-line against the relevant
> > > > comments you made.
> > > >
> > > > > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > > > >
> > > > > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > > > > GPIO and GPADC functionality.
> > > > > >
> > > > > > Signed-off-by: Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com>
> > > > > > ---
> > > > > >  drivers/mfd/Kconfig                  |   12 +
> > > > > >  drivers/mfd/Makefile                 |    2 +
> > > > > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > > > > >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> 
> [...]
> 
> > > > > > +/* Helper functions for sub-devices to request/free IRQs */
> > > > > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > > > > +			irq_handler_t handler, const char *name)
> > > > > > +{
> > > > > > +	int irq, ret;
> > > > > > +
> > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > +	if (irq < 0)
> > > > > > +		return irq;
> > > > > > +
> > > > > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > > > > +					IRQF_ONESHOT, name, dev_id);
> > > > > > +	if (ret)
> > > > > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq,
> ret);
> > > > > > +
> > > > > > +	return ret;
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > > > >
> > > > > Why do they need help?  What problem does adding these layers solve?
> > > >
> > > > Means I don't have to keep adding print error lines everywhere else if this
> > > > function takes care of it. Thought that would be cleaner.
> > >
> > > You only need to request each IRQ once.  It's just more abstraction
> > > for the sake of it.  I would prefer if you removed them.
> >
> > Yes, but in the charger driver for example, there are 4 IRQs to request. If
> > I don't use this approach the IRQ requesting becomes bloated, hence why I went
> > for a common function like this. Thought generally the intention was to cut
> > down on repeated code?
> 
> If you're worried about bloat in .probe() it's okay to define a new
> function within the charger driver; however, creating a call-back into
> the MFD driver like this I think it over-kill for 4 requests.

I could do something just in the charger, but why not have something which can
be used for all sub-devices? There is also an IRQ used in the IIO ADC driver and
there will be another in the later fuel-gauge driver too. Doesn't make sense to
me not to do in the MFD code when that will provide a simple common call for all
sub-devices. What is your concern with adding something like this, just so I'm
clear?

> 
> > > > > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > > > > +		       const char *name)
> > > > > > +{
> > > > > > +	int irq;
> > > > > > +
> > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > +	if (irq < 0)
> > > > > > +		return;
> > > > > > +
> > > > > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > > > >
> > > > > Do you ever release the IRQ and not unbind the driver?
> > > > >
> > > > > Are there ordering issues at play here?
> > > > >
> > > > > If not, there's no need to conduct a manual free.
> > > >
> > > > In the charger driver, in the remove function there is a need I believe to
> > > > free the IRQs before other items are cleared up (e.g. power_supply classes),
> > > > so this is why I have added this in here.
> > >
> > > Can you handle this separately in the Charger driver then please?
> > >
> > > [...]
> >
> > If I have to remove the IRQ register function, then yes, otherwise it makes more
> > sense to have the pair of functions in the MFD core I would say.
> 
> I would prefer you to remove the call-back please.

Right.

> 
> > > > > > +	if (pdata)
> > > > > > +		da9150->irq_base = pdata->irq_base;
> > > > > > +	else
> > > > > > +		da9150->irq_base = -1;
> > > > >
> > > > > pdata ? pdata->irq_base : -1;
> > > >
> > > > This is left this way as later updates to add additional functionality will
> > > > require addtional work to be done with the platform data. Seemed pointless
> > > > changing it here just to change it back later.
> > >
> > > You're not changing anything, as this is the introduction of the code.
> > > I can't tell you how many times I've heard "I will change it later",
> > > or "doing it this way will support subsequent submissions", then
> > > received no more patches.  It's okay to do it nicely now and expand
> > > it back out in the new patches.
> > >
> > > [...]
> >
> > It appears that way to you but I have to modify my code for sumbission as the
> > local code I have covers all functionality. Am having to refactor again and
> > again just to suit this initial submission, and then I have to revert it back
> > again when submitting the last couple of drivers. Time consuming, and quite
> > frustrating when the intention was to make the whole process easier. Anyway,
> > will update for now and revert in subsequent patches.
> 
> I sincerely hope the refactorings won't add too much effort, but it's
> difficult to have one rule for the masses and different ones for
> others.

I do understand that, and that's fair enough. Is just frustrating when you're
trying to do a proper job. Anyway, am sure I'll live. :)

> 
> --
> Lee Jones
> Linaro STMicroelectronics Landing Team Lead
> Linaro.org │ Open source software for ARM SoCs
> Follow Linaro: Facebook | Twitter | Blog
ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-16 10:50               ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-16 10:50 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

On September 15, 2014 23:39, Lee Jones wrote:

> On Wed, 10 Sep 2014, Opensource [Adam Thomson] wrote:
> > On September 10, 2014 10:50, Lee Jones wrote:
> > > On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> > >
> > > > On August 28, 2014 17:36, Lee Jones wrote:
> > > >
> > > > Thanks for the feedback. As a general comment a couple of the items you've
> > > > identified relate to future updates (additional functionality being added).
> > > > I already have code in place for this but have stripped out a couple of the
> > > > drivers just to reduce the churn and size of patch submission. These will be
> > > > added once these patches have been accepted.
> > > >
> > > > Where this is the case, I have added notes in-line against the relevant
> > > > comments you made.
> > > >
> > > > > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > > > >
> > > > > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > > > > GPIO and GPADC functionality.
> > > > > >
> > > > > > Signed-off-by: Adam Thomson
> <Adam.Thomson.Opensource@diasemi.com>
> > > > > > ---
> > > > > >  drivers/mfd/Kconfig                  |   12 +
> > > > > >  drivers/mfd/Makefile                 |    2 +
> > > > > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > > > > >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> 
> [...]
> 
> > > > > > +/* Helper functions for sub-devices to request/free IRQs */
> > > > > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > > > > +			irq_handler_t handler, const char *name)
> > > > > > +{
> > > > > > +	int irq, ret;
> > > > > > +
> > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > +	if (irq < 0)
> > > > > > +		return irq;
> > > > > > +
> > > > > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > > > > +					IRQF_ONESHOT, name, dev_id);
> > > > > > +	if (ret)
> > > > > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq,
> ret);
> > > > > > +
> > > > > > +	return ret;
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > > > >
> > > > > Why do they need help?  What problem does adding these layers solve?
> > > >
> > > > Means I don't have to keep adding print error lines everywhere else if this
> > > > function takes care of it. Thought that would be cleaner.
> > >
> > > You only need to request each IRQ once.  It's just more abstraction
> > > for the sake of it.  I would prefer if you removed them.
> >
> > Yes, but in the charger driver for example, there are 4 IRQs to request. If
> > I don't use this approach the IRQ requesting becomes bloated, hence why I went
> > for a common function like this. Thought generally the intention was to cut
> > down on repeated code?
> 
> If you're worried about bloat in .probe() it's okay to define a new
> function within the charger driver; however, creating a call-back into
> the MFD driver like this I think it over-kill for 4 requests.

I could do something just in the charger, but why not have something which can
be used for all sub-devices? There is also an IRQ used in the IIO ADC driver and
there will be another in the later fuel-gauge driver too. Doesn't make sense to
me not to do in the MFD code when that will provide a simple common call for all
sub-devices. What is your concern with adding something like this, just so I'm
clear?

> 
> > > > > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > > > > +		       const char *name)
> > > > > > +{
> > > > > > +	int irq;
> > > > > > +
> > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > +	if (irq < 0)
> > > > > > +		return;
> > > > > > +
> > > > > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > > > >
> > > > > Do you ever release the IRQ and not unbind the driver?
> > > > >
> > > > > Are there ordering issues at play here?
> > > > >
> > > > > If not, there's no need to conduct a manual free.
> > > >
> > > > In the charger driver, in the remove function there is a need I believe to
> > > > free the IRQs before other items are cleared up (e.g. power_supply classes),
> > > > so this is why I have added this in here.
> > >
> > > Can you handle this separately in the Charger driver then please?
> > >
> > > [...]
> >
> > If I have to remove the IRQ register function, then yes, otherwise it makes more
> > sense to have the pair of functions in the MFD core I would say.
> 
> I would prefer you to remove the call-back please.

Right.

> 
> > > > > > +	if (pdata)
> > > > > > +		da9150->irq_base = pdata->irq_base;
> > > > > > +	else
> > > > > > +		da9150->irq_base = -1;
> > > > >
> > > > > pdata ? pdata->irq_base : -1;
> > > >
> > > > This is left this way as later updates to add additional functionality will
> > > > require addtional work to be done with the platform data. Seemed pointless
> > > > changing it here just to change it back later.
> > >
> > > You're not changing anything, as this is the introduction of the code.
> > > I can't tell you how many times I've heard "I will change it later",
> > > or "doing it this way will support subsequent submissions", then
> > > received no more patches.  It's okay to do it nicely now and expand
> > > it back out in the new patches.
> > >
> > > [...]
> >
> > It appears that way to you but I have to modify my code for sumbission as the
> > local code I have covers all functionality. Am having to refactor again and
> > again just to suit this initial submission, and then I have to revert it back
> > again when submitting the last couple of drivers. Time consuming, and quite
> > frustrating when the intention was to make the whole process easier. Anyway,
> > will update for now and revert in subsequent patches.
> 
> I sincerely hope the refactorings won't add too much effort, but it's
> difficult to have one rule for the masses and different ones for
> others.

I do understand that, and that's fair enough. Is just frustrating when you're
trying to do a proper job. Anyway, am sure I'll live. :)

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

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

* RE: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-16 10:50               ` Opensource [Adam Thomson]
  0 siblings, 0 replies; 43+ messages in thread
From: Opensource [Adam Thomson] @ 2014-09-16 10:50 UTC (permalink / raw)
  To: Lee Jones, Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

T24gU2VwdGVtYmVyIDE1LCAyMDE0IDIzOjM5LCBMZWUgSm9uZXMgd3JvdGU6DQoNCj4gT24gV2Vk
LCAxMCBTZXAgMjAxNCwgT3BlbnNvdXJjZSBbQWRhbSBUaG9tc29uXSB3cm90ZToNCj4gPiBPbiBT
ZXB0ZW1iZXIgMTAsIDIwMTQgMTA6NTAsIExlZSBKb25lcyB3cm90ZToNCj4gPiA+IE9uIFR1ZSwg
MDkgU2VwIDIwMTQsIE9wZW5zb3VyY2UgW0FkYW0gVGhvbXNvbl0gd3JvdGU6DQo+ID4gPg0KPiA+
ID4gPiBPbiBBdWd1c3QgMjgsIDIwMTQgMTc6MzYsIExlZSBKb25lcyB3cm90ZToNCj4gPiA+ID4N
Cj4gPiA+ID4gVGhhbmtzIGZvciB0aGUgZmVlZGJhY2suIEFzIGEgZ2VuZXJhbCBjb21tZW50IGEg
Y291cGxlIG9mIHRoZSBpdGVtcyB5b3UndmUNCj4gPiA+ID4gaWRlbnRpZmllZCByZWxhdGUgdG8g
ZnV0dXJlIHVwZGF0ZXMgKGFkZGl0aW9uYWwgZnVuY3Rpb25hbGl0eSBiZWluZyBhZGRlZCkuDQo+
ID4gPiA+IEkgYWxyZWFkeSBoYXZlIGNvZGUgaW4gcGxhY2UgZm9yIHRoaXMgYnV0IGhhdmUgc3Ry
aXBwZWQgb3V0IGEgY291cGxlIG9mIHRoZQ0KPiA+ID4gPiBkcml2ZXJzIGp1c3QgdG8gcmVkdWNl
IHRoZSBjaHVybiBhbmQgc2l6ZSBvZiBwYXRjaCBzdWJtaXNzaW9uLiBUaGVzZSB3aWxsIGJlDQo+
ID4gPiA+IGFkZGVkIG9uY2UgdGhlc2UgcGF0Y2hlcyBoYXZlIGJlZW4gYWNjZXB0ZWQuDQo+ID4g
PiA+DQo+ID4gPiA+IFdoZXJlIHRoaXMgaXMgdGhlIGNhc2UsIEkgaGF2ZSBhZGRlZCBub3RlcyBp
bi1saW5lIGFnYWluc3QgdGhlIHJlbGV2YW50DQo+ID4gPiA+IGNvbW1lbnRzIHlvdSBtYWRlLg0K
PiA+ID4gPg0KPiA+ID4gPiA+IE9uIFRodSwgMjggQXVnIDIwMTQsIEFkYW0gVGhvbXNvbiB3cm90
ZToNCj4gPiA+ID4gPg0KPiA+ID4gPiA+ID4gREE5MTUwIGlzIGEgY29tYmluZWQgQ2hhcmdlciBh
bmQgRnVlbC1HYXVnZSBJQywgd2l0aCBhZGRpdGlvbmFsDQo+ID4gPiA+ID4gPiBHUElPIGFuZCBH
UEFEQyBmdW5jdGlvbmFsaXR5Lg0KPiA+ID4gPiA+ID4NCj4gPiA+ID4gPiA+IFNpZ25lZC1vZmYt
Ynk6IEFkYW0gVGhvbXNvbg0KPiA8QWRhbS5UaG9tc29uLk9wZW5zb3VyY2VAZGlhc2VtaS5jb20+
DQo+ID4gPiA+ID4gPiAtLS0NCj4gPiA+ID4gPiA+ICBkcml2ZXJzL21mZC9LY29uZmlnICAgICAg
ICAgICAgICAgICAgfCAgIDEyICsNCj4gPiA+ID4gPiA+ICBkcml2ZXJzL21mZC9NYWtlZmlsZSAg
ICAgICAgICAgICAgICAgfCAgICAyICsNCj4gPiA+ID4gPiA+ICBkcml2ZXJzL21mZC9kYTkxNTAt
Y29yZS5jICAgICAgICAgICAgfCAgMzMyICsrKysrKysrKysNCj4gPiA+ID4gPiA+ICBkcml2ZXJz
L21mZC9kYTkxNTAtaTJjLmMgICAgICAgICAgICAgfCAgMTc2ICsrKysrKw0KPiANCj4gWy4uLl0N
Cj4gDQo+ID4gPiA+ID4gPiArLyogSGVscGVyIGZ1bmN0aW9ucyBmb3Igc3ViLWRldmljZXMgdG8g
cmVxdWVzdC9mcmVlIElSUXMgKi8NCj4gPiA+ID4gPiA+ICtpbnQgZGE5MTUwX3JlZ2lzdGVyX2ly
cShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2LCB2b2lkICpkZXZfaWQsDQo+ID4gPiA+ID4g
PiArCQkJaXJxX2hhbmRsZXJfdCBoYW5kbGVyLCBjb25zdCBjaGFyICpuYW1lKQ0KPiA+ID4gPiA+
ID4gK3sNCj4gPiA+ID4gPiA+ICsJaW50IGlycSwgcmV0Ow0KPiA+ID4gPiA+ID4gKw0KPiA+ID4g
PiA+ID4gKwlpcnEgPSBwbGF0Zm9ybV9nZXRfaXJxX2J5bmFtZShwZGV2LCBuYW1lKTsNCj4gPiA+
ID4gPiA+ICsJaWYgKGlycSA8IDApDQo+ID4gPiA+ID4gPiArCQlyZXR1cm4gaXJxOw0KPiA+ID4g
PiA+ID4gKw0KPiA+ID4gPiA+ID4gKwlyZXQgPSBkZXZtX3JlcXVlc3RfdGhyZWFkZWRfaXJxKCZw
ZGV2LT5kZXYsIGlycSwgTlVMTCwgaGFuZGxlciwNCj4gPiA+ID4gPiA+ICsJCQkJCUlSUUZfT05F
U0hPVCwgbmFtZSwgZGV2X2lkKTsNCj4gPiA+ID4gPiA+ICsJaWYgKHJldCkNCj4gPiA+ID4gPiA+
ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgIkZhaWxlZCB0byByZXF1ZXN0IElSUSAlZDogJWRcbiIs
IGlycSwNCj4gcmV0KTsNCj4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ICsJcmV0dXJuIHJldDsN
Cj4gPiA+ID4gPiA+ICt9DQo+ID4gPiA+ID4gPiArRVhQT1JUX1NZTUJPTF9HUEwoZGE5MTUwX3Jl
Z2lzdGVyX2lycSk7DQo+ID4gPiA+ID4NCj4gPiA+ID4gPiBXaHkgZG8gdGhleSBuZWVkIGhlbHA/
ICBXaGF0IHByb2JsZW0gZG9lcyBhZGRpbmcgdGhlc2UgbGF5ZXJzIHNvbHZlPw0KPiA+ID4gPg0K
PiA+ID4gPiBNZWFucyBJIGRvbid0IGhhdmUgdG8ga2VlcCBhZGRpbmcgcHJpbnQgZXJyb3IgbGlu
ZXMgZXZlcnl3aGVyZSBlbHNlIGlmIHRoaXMNCj4gPiA+ID4gZnVuY3Rpb24gdGFrZXMgY2FyZSBv
ZiBpdC4gVGhvdWdodCB0aGF0IHdvdWxkIGJlIGNsZWFuZXIuDQo+ID4gPg0KPiA+ID4gWW91IG9u
bHkgbmVlZCB0byByZXF1ZXN0IGVhY2ggSVJRIG9uY2UuICBJdCdzIGp1c3QgbW9yZSBhYnN0cmFj
dGlvbg0KPiA+ID4gZm9yIHRoZSBzYWtlIG9mIGl0LiAgSSB3b3VsZCBwcmVmZXIgaWYgeW91IHJl
bW92ZWQgdGhlbS4NCj4gPg0KPiA+IFllcywgYnV0IGluIHRoZSBjaGFyZ2VyIGRyaXZlciBmb3Ig
ZXhhbXBsZSwgdGhlcmUgYXJlIDQgSVJRcyB0byByZXF1ZXN0LiBJZg0KPiA+IEkgZG9uJ3QgdXNl
IHRoaXMgYXBwcm9hY2ggdGhlIElSUSByZXF1ZXN0aW5nIGJlY29tZXMgYmxvYXRlZCwgaGVuY2Ug
d2h5IEkgd2VudA0KPiA+IGZvciBhIGNvbW1vbiBmdW5jdGlvbiBsaWtlIHRoaXMuIFRob3VnaHQg
Z2VuZXJhbGx5IHRoZSBpbnRlbnRpb24gd2FzIHRvIGN1dA0KPiA+IGRvd24gb24gcmVwZWF0ZWQg
Y29kZT8NCj4gDQo+IElmIHlvdSdyZSB3b3JyaWVkIGFib3V0IGJsb2F0IGluIC5wcm9iZSgpIGl0
J3Mgb2theSB0byBkZWZpbmUgYSBuZXcNCj4gZnVuY3Rpb24gd2l0aGluIHRoZSBjaGFyZ2VyIGRy
aXZlcjsgaG93ZXZlciwgY3JlYXRpbmcgYSBjYWxsLWJhY2sgaW50bw0KPiB0aGUgTUZEIGRyaXZl
ciBsaWtlIHRoaXMgSSB0aGluayBpdCBvdmVyLWtpbGwgZm9yIDQgcmVxdWVzdHMuDQoNCkkgY291
bGQgZG8gc29tZXRoaW5nIGp1c3QgaW4gdGhlIGNoYXJnZXIsIGJ1dCB3aHkgbm90IGhhdmUgc29t
ZXRoaW5nIHdoaWNoIGNhbg0KYmUgdXNlZCBmb3IgYWxsIHN1Yi1kZXZpY2VzPyBUaGVyZSBpcyBh
bHNvIGFuIElSUSB1c2VkIGluIHRoZSBJSU8gQURDIGRyaXZlciBhbmQNCnRoZXJlIHdpbGwgYmUg
YW5vdGhlciBpbiB0aGUgbGF0ZXIgZnVlbC1nYXVnZSBkcml2ZXIgdG9vLiBEb2Vzbid0IG1ha2Ug
c2Vuc2UgdG8NCm1lIG5vdCB0byBkbyBpbiB0aGUgTUZEIGNvZGUgd2hlbiB0aGF0IHdpbGwgcHJv
dmlkZSBhIHNpbXBsZSBjb21tb24gY2FsbCBmb3IgYWxsDQpzdWItZGV2aWNlcy4gV2hhdCBpcyB5
b3VyIGNvbmNlcm4gd2l0aCBhZGRpbmcgc29tZXRoaW5nIGxpa2UgdGhpcywganVzdCBzbyBJJ20N
CmNsZWFyPw0KDQo+IA0KPiA+ID4gPiA+ID4gK3ZvaWQgZGE5MTUwX3JlbGVhc2VfaXJxKHN0cnVj
dCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYsIHZvaWQgKmRldl9pZCwNCj4gPiA+ID4gPiA+ICsJCSAg
ICAgICBjb25zdCBjaGFyICpuYW1lKQ0KPiA+ID4gPiA+ID4gK3sNCj4gPiA+ID4gPiA+ICsJaW50
IGlycTsNCj4gPiA+ID4gPiA+ICsNCj4gPiA+ID4gPiA+ICsJaXJxID0gcGxhdGZvcm1fZ2V0X2ly
cV9ieW5hbWUocGRldiwgbmFtZSk7DQo+ID4gPiA+ID4gPiArCWlmIChpcnEgPCAwKQ0KPiA+ID4g
PiA+ID4gKwkJcmV0dXJuOw0KPiA+ID4gPiA+ID4gKw0KPiA+ID4gPiA+ID4gKwlkZXZtX2ZyZWVf
aXJxKCZwZGV2LT5kZXYsIGlycSwgZGV2X2lkKTsNCj4gPiA+ID4gPiA+ICt9DQo+ID4gPiA+ID4g
PiArRVhQT1JUX1NZTUJPTF9HUEwoZGE5MTUwX3JlbGVhc2VfaXJxKTsNCj4gPiA+ID4gPg0KPiA+
ID4gPiA+IERvIHlvdSBldmVyIHJlbGVhc2UgdGhlIElSUSBhbmQgbm90IHVuYmluZCB0aGUgZHJp
dmVyPw0KPiA+ID4gPiA+DQo+ID4gPiA+ID4gQXJlIHRoZXJlIG9yZGVyaW5nIGlzc3VlcyBhdCBw
bGF5IGhlcmU/DQo+ID4gPiA+ID4NCj4gPiA+ID4gPiBJZiBub3QsIHRoZXJlJ3Mgbm8gbmVlZCB0
byBjb25kdWN0IGEgbWFudWFsIGZyZWUuDQo+ID4gPiA+DQo+ID4gPiA+IEluIHRoZSBjaGFyZ2Vy
IGRyaXZlciwgaW4gdGhlIHJlbW92ZSBmdW5jdGlvbiB0aGVyZSBpcyBhIG5lZWQgSSBiZWxpZXZl
IHRvDQo+ID4gPiA+IGZyZWUgdGhlIElSUXMgYmVmb3JlIG90aGVyIGl0ZW1zIGFyZSBjbGVhcmVk
IHVwIChlLmcuIHBvd2VyX3N1cHBseSBjbGFzc2VzKSwNCj4gPiA+ID4gc28gdGhpcyBpcyB3aHkg
SSBoYXZlIGFkZGVkIHRoaXMgaW4gaGVyZS4NCj4gPiA+DQo+ID4gPiBDYW4geW91IGhhbmRsZSB0
aGlzIHNlcGFyYXRlbHkgaW4gdGhlIENoYXJnZXIgZHJpdmVyIHRoZW4gcGxlYXNlPw0KPiA+ID4N
Cj4gPiA+IFsuLi5dDQo+ID4NCj4gPiBJZiBJIGhhdmUgdG8gcmVtb3ZlIHRoZSBJUlEgcmVnaXN0
ZXIgZnVuY3Rpb24sIHRoZW4geWVzLCBvdGhlcndpc2UgaXQgbWFrZXMgbW9yZQ0KPiA+IHNlbnNl
IHRvIGhhdmUgdGhlIHBhaXIgb2YgZnVuY3Rpb25zIGluIHRoZSBNRkQgY29yZSBJIHdvdWxkIHNh
eS4NCj4gDQo+IEkgd291bGQgcHJlZmVyIHlvdSB0byByZW1vdmUgdGhlIGNhbGwtYmFjayBwbGVh
c2UuDQoNClJpZ2h0Lg0KDQo+IA0KPiA+ID4gPiA+ID4gKwlpZiAocGRhdGEpDQo+ID4gPiA+ID4g
PiArCQlkYTkxNTAtPmlycV9iYXNlID0gcGRhdGEtPmlycV9iYXNlOw0KPiA+ID4gPiA+ID4gKwll
bHNlDQo+ID4gPiA+ID4gPiArCQlkYTkxNTAtPmlycV9iYXNlID0gLTE7DQo+ID4gPiA+ID4NCj4g
PiA+ID4gPiBwZGF0YSA/IHBkYXRhLT5pcnFfYmFzZSA6IC0xOw0KPiA+ID4gPg0KPiA+ID4gPiBU
aGlzIGlzIGxlZnQgdGhpcyB3YXkgYXMgbGF0ZXIgdXBkYXRlcyB0byBhZGQgYWRkaXRpb25hbCBm
dW5jdGlvbmFsaXR5IHdpbGwNCj4gPiA+ID4gcmVxdWlyZSBhZGR0aW9uYWwgd29yayB0byBiZSBk
b25lIHdpdGggdGhlIHBsYXRmb3JtIGRhdGEuIFNlZW1lZCBwb2ludGxlc3MNCj4gPiA+ID4gY2hh
bmdpbmcgaXQgaGVyZSBqdXN0IHRvIGNoYW5nZSBpdCBiYWNrIGxhdGVyLg0KPiA+ID4NCj4gPiA+
IFlvdSdyZSBub3QgY2hhbmdpbmcgYW55dGhpbmcsIGFzIHRoaXMgaXMgdGhlIGludHJvZHVjdGlv
biBvZiB0aGUgY29kZS4NCj4gPiA+IEkgY2FuJ3QgdGVsbCB5b3UgaG93IG1hbnkgdGltZXMgSSd2
ZSBoZWFyZCAiSSB3aWxsIGNoYW5nZSBpdCBsYXRlciIsDQo+ID4gPiBvciAiZG9pbmcgaXQgdGhp
cyB3YXkgd2lsbCBzdXBwb3J0IHN1YnNlcXVlbnQgc3VibWlzc2lvbnMiLCB0aGVuDQo+ID4gPiBy
ZWNlaXZlZCBubyBtb3JlIHBhdGNoZXMuICBJdCdzIG9rYXkgdG8gZG8gaXQgbmljZWx5IG5vdyBh
bmQgZXhwYW5kDQo+ID4gPiBpdCBiYWNrIG91dCBpbiB0aGUgbmV3IHBhdGNoZXMuDQo+ID4gPg0K
PiA+ID4gWy4uLl0NCj4gPg0KPiA+IEl0IGFwcGVhcnMgdGhhdCB3YXkgdG8geW91IGJ1dCBJIGhh
dmUgdG8gbW9kaWZ5IG15IGNvZGUgZm9yIHN1bWJpc3Npb24gYXMgdGhlDQo+ID4gbG9jYWwgY29k
ZSBJIGhhdmUgY292ZXJzIGFsbCBmdW5jdGlvbmFsaXR5LiBBbSBoYXZpbmcgdG8gcmVmYWN0b3Ig
YWdhaW4gYW5kDQo+ID4gYWdhaW4ganVzdCB0byBzdWl0IHRoaXMgaW5pdGlhbCBzdWJtaXNzaW9u
LCBhbmQgdGhlbiBJIGhhdmUgdG8gcmV2ZXJ0IGl0IGJhY2sNCj4gPiBhZ2FpbiB3aGVuIHN1Ym1p
dHRpbmcgdGhlIGxhc3QgY291cGxlIG9mIGRyaXZlcnMuIFRpbWUgY29uc3VtaW5nLCBhbmQgcXVp
dGUNCj4gPiBmcnVzdHJhdGluZyB3aGVuIHRoZSBpbnRlbnRpb24gd2FzIHRvIG1ha2UgdGhlIHdo
b2xlIHByb2Nlc3MgZWFzaWVyLiBBbnl3YXksDQo+ID4gd2lsbCB1cGRhdGUgZm9yIG5vdyBhbmQg
cmV2ZXJ0IGluIHN1YnNlcXVlbnQgcGF0Y2hlcy4NCj4gDQo+IEkgc2luY2VyZWx5IGhvcGUgdGhl
IHJlZmFjdG9yaW5ncyB3b24ndCBhZGQgdG9vIG11Y2ggZWZmb3J0LCBidXQgaXQncw0KPiBkaWZm
aWN1bHQgdG8gaGF2ZSBvbmUgcnVsZSBmb3IgdGhlIG1hc3NlcyBhbmQgZGlmZmVyZW50IG9uZXMg
Zm9yDQo+IG90aGVycy4NCg0KSSBkbyB1bmRlcnN0YW5kIHRoYXQsIGFuZCB0aGF0J3MgZmFpciBl
bm91Z2guIElzIGp1c3QgZnJ1c3RyYXRpbmcgd2hlbiB5b3UncmUNCnRyeWluZyB0byBkbyBhIHBy
b3BlciBqb2IuIEFueXdheSwgYW0gc3VyZSBJJ2xsIGxpdmUuIDopDQoNCj4gDQo+IC0tDQo+IExl
ZSBKb25lcw0KPiBMaW5hcm8gU1RNaWNyb2VsZWN0cm9uaWNzIExhbmRpbmcgVGVhbSBMZWFkDQo+
IExpbmFyby5vcmcg4pSCIE9wZW4gc291cmNlIHNvZnR3YXJlIGZvciBBUk0gU29Dcw0KPiBGb2xs
b3cgTGluYXJvOiBGYWNlYm9vayB8IFR3aXR0ZXIgfCBCbG9nDQo=

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

* Re: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-16 22:07                 ` Lee Jones
  0 siblings, 0 replies; 43+ messages in thread
From: Lee Jones @ 2014-09-16 22:07 UTC (permalink / raw)
  To: Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio, Sebastian Reichel,
	Dmitry Eremin-Solenikov, David Woodhouse, linux-pm, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, devicetree,
	Andrew Morton, Joe Perches, linux-kernel, Support Opensource

On Tue, 16 Sep 2014, Opensource [Adam Thomson] wrote:

> On September 15, 2014 23:39, Lee Jones wrote:
> 
> > On Wed, 10 Sep 2014, Opensource [Adam Thomson] wrote:
> > > On September 10, 2014 10:50, Lee Jones wrote:
> > > > On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> > > >
> > > > > On August 28, 2014 17:36, Lee Jones wrote:
> > > > >
> > > > > Thanks for the feedback. As a general comment a couple of the items you've
> > > > > identified relate to future updates (additional functionality being added).
> > > > > I already have code in place for this but have stripped out a couple of the
> > > > > drivers just to reduce the churn and size of patch submission. These will be
> > > > > added once these patches have been accepted.
> > > > >
> > > > > Where this is the case, I have added notes in-line against the relevant
> > > > > comments you made.
> > > > >
> > > > > > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > > > > >
> > > > > > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > > > > > GPIO and GPADC functionality.
> > > > > > >
> > > > > > > Signed-off-by: Adam Thomson
> > <Adam.Thomson.Opensource@diasemi.com>
> > > > > > > ---
> > > > > > >  drivers/mfd/Kconfig                  |   12 +
> > > > > > >  drivers/mfd/Makefile                 |    2 +
> > > > > > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > > > > > >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> > 
> > [...]
> > 
> > > > > > > +/* Helper functions for sub-devices to request/free IRQs */
> > > > > > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > > > > > +			irq_handler_t handler, const char *name)
> > > > > > > +{
> > > > > > > +	int irq, ret;
> > > > > > > +
> > > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > > +	if (irq < 0)
> > > > > > > +		return irq;
> > > > > > > +
> > > > > > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > > > > > +					IRQF_ONESHOT, name, dev_id);
> > > > > > > +	if (ret)
> > > > > > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq,
> > ret);
> > > > > > > +
> > > > > > > +	return ret;
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > > > > >
> > > > > > Why do they need help?  What problem does adding these layers solve?
> > > > >
> > > > > Means I don't have to keep adding print error lines everywhere else if this
> > > > > function takes care of it. Thought that would be cleaner.
> > > >
> > > > You only need to request each IRQ once.  It's just more abstraction
> > > > for the sake of it.  I would prefer if you removed them.
> > >
> > > Yes, but in the charger driver for example, there are 4 IRQs to request. If
> > > I don't use this approach the IRQ requesting becomes bloated, hence why I went
> > > for a common function like this. Thought generally the intention was to cut
> > > down on repeated code?
> > 
> > If you're worried about bloat in .probe() it's okay to define a new
> > function within the charger driver; however, creating a call-back into
> > the MFD driver like this I think it over-kill for 4 requests.
> 
> I could do something just in the charger, but why not have something which can
> be used for all sub-devices? There is also an IRQ used in the IIO ADC driver and
> there will be another in the later fuel-gauge driver too. Doesn't make sense to
> me not to do in the MFD code when that will provide a simple common call for all
> sub-devices. What is your concern with adding something like this, just so I'm
> clear?

I guess my last response wasn't as descriptive as it could have been.
I don't think that any helper function is required at all.  No need to
abstract/obfuscate how the IRQ is obtained and registered.  What I
meant by 'do it in the charger driver' was, copy and paste all of the
platform_get_irq_byname() and devm_request_threaded_irq() calls from
.probe() into a separate function, but only if you are worried about a
bloated .probe().  Personally I'd just leave them in there.

Bottom line is; I don't feel there is a necessity for any helper
function here.  I think it adds unnecessary complexity for the sake of
saving a few lines of code.

If you still think there is a requirement for it, perhaps a more
system-wide devm_request_threaded_irq_byname() is in order instead?

> > > > > > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > > > > > +		       const char *name)
> > > > > > > +{
> > > > > > > +	int irq;
> > > > > > > +
> > > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > > +	if (irq < 0)
> > > > > > > +		return;
> > > > > > > +
> > > > > > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > > > > >
> > > > > > Do you ever release the IRQ and not unbind the driver?
> > > > > >
> > > > > > Are there ordering issues at play here?
> > > > > >
> > > > > > If not, there's no need to conduct a manual free.
> > > > >
> > > > > In the charger driver, in the remove function there is a need I believe to
> > > > > free the IRQs before other items are cleared up (e.g. power_supply classes),
> > > > > so this is why I have added this in here.
> > > >
> > > > Can you handle this separately in the Charger driver then please?
> > > >
> > > > [...]
> > >
> > > If I have to remove the IRQ register function, then yes, otherwise it makes more
> > > sense to have the pair of functions in the MFD core I would say.
> > 
> > I would prefer you to remove the call-back please.
> 
> Right.
> 
> > 
> > > > > > > +	if (pdata)
> > > > > > > +		da9150->irq_base = pdata->irq_base;
> > > > > > > +	else
> > > > > > > +		da9150->irq_base = -1;
> > > > > >
> > > > > > pdata ? pdata->irq_base : -1;
> > > > >
> > > > > This is left this way as later updates to add additional functionality will
> > > > > require addtional work to be done with the platform data. Seemed pointless
> > > > > changing it here just to change it back later.
> > > >
> > > > You're not changing anything, as this is the introduction of the code.
> > > > I can't tell you how many times I've heard "I will change it later",
> > > > or "doing it this way will support subsequent submissions", then
> > > > received no more patches.  It's okay to do it nicely now and expand
> > > > it back out in the new patches.
> > > >
> > > > [...]
> > >
> > > It appears that way to you but I have to modify my code for sumbission as the
> > > local code I have covers all functionality. Am having to refactor again and
> > > again just to suit this initial submission, and then I have to revert it back
> > > again when submitting the last couple of drivers. Time consuming, and quite
> > > frustrating when the intention was to make the whole process easier. Anyway,
> > > will update for now and revert in subsequent patches.
> > 
> > I sincerely hope the refactorings won't add too much effort, but it's
> > difficult to have one rule for the masses and different ones for
> > others.
> 
> I do understand that, and that's fair enough. Is just frustrating when you're
> trying to do a proper job. Anyway, am sure I'll live. :)

I know how you feel, as I've been on the receiving end of such rules
more than once, but you could have probably re-factored twice in the
time it's taken us to have this conversation. :)

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

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

* Re: [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device
@ 2014-09-16 22:07                 ` Lee Jones
  0 siblings, 0 replies; 43+ messages in thread
From: Lee Jones @ 2014-09-16 22:07 UTC (permalink / raw)
  To: Opensource [Adam Thomson]
  Cc: Samuel Ortiz, Jonathan Cameron, linux-iio-u79uwXL29TY76Z2rM5mHXA,
	Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Pawel Moll,
	Mark Rutland, Ian Campbell, Kumar Gala,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Joe Perches,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Support Opensource

On Tue, 16 Sep 2014, Opensource [Adam Thomson] wrote:

> On September 15, 2014 23:39, Lee Jones wrote:
> 
> > On Wed, 10 Sep 2014, Opensource [Adam Thomson] wrote:
> > > On September 10, 2014 10:50, Lee Jones wrote:
> > > > On Tue, 09 Sep 2014, Opensource [Adam Thomson] wrote:
> > > >
> > > > > On August 28, 2014 17:36, Lee Jones wrote:
> > > > >
> > > > > Thanks for the feedback. As a general comment a couple of the items you've
> > > > > identified relate to future updates (additional functionality being added).
> > > > > I already have code in place for this but have stripped out a couple of the
> > > > > drivers just to reduce the churn and size of patch submission. These will be
> > > > > added once these patches have been accepted.
> > > > >
> > > > > Where this is the case, I have added notes in-line against the relevant
> > > > > comments you made.
> > > > >
> > > > > > On Thu, 28 Aug 2014, Adam Thomson wrote:
> > > > > >
> > > > > > > DA9150 is a combined Charger and Fuel-Gauge IC, with additional
> > > > > > > GPIO and GPADC functionality.
> > > > > > >
> > > > > > > Signed-off-by: Adam Thomson
> > <Adam.Thomson.Opensource-WBD+wuPFNBhBDgjK7y7TUQ@public.gmane.org>
> > > > > > > ---
> > > > > > >  drivers/mfd/Kconfig                  |   12 +
> > > > > > >  drivers/mfd/Makefile                 |    2 +
> > > > > > >  drivers/mfd/da9150-core.c            |  332 ++++++++++
> > > > > > >  drivers/mfd/da9150-i2c.c             |  176 ++++++
> > 
> > [...]
> > 
> > > > > > > +/* Helper functions for sub-devices to request/free IRQs */
> > > > > > > +int da9150_register_irq(struct platform_device *pdev, void *dev_id,
> > > > > > > +			irq_handler_t handler, const char *name)
> > > > > > > +{
> > > > > > > +	int irq, ret;
> > > > > > > +
> > > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > > +	if (irq < 0)
> > > > > > > +		return irq;
> > > > > > > +
> > > > > > > +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, handler,
> > > > > > > +					IRQF_ONESHOT, name, dev_id);
> > > > > > > +	if (ret)
> > > > > > > +		dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq,
> > ret);
> > > > > > > +
> > > > > > > +	return ret;
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL_GPL(da9150_register_irq);
> > > > > >
> > > > > > Why do they need help?  What problem does adding these layers solve?
> > > > >
> > > > > Means I don't have to keep adding print error lines everywhere else if this
> > > > > function takes care of it. Thought that would be cleaner.
> > > >
> > > > You only need to request each IRQ once.  It's just more abstraction
> > > > for the sake of it.  I would prefer if you removed them.
> > >
> > > Yes, but in the charger driver for example, there are 4 IRQs to request. If
> > > I don't use this approach the IRQ requesting becomes bloated, hence why I went
> > > for a common function like this. Thought generally the intention was to cut
> > > down on repeated code?
> > 
> > If you're worried about bloat in .probe() it's okay to define a new
> > function within the charger driver; however, creating a call-back into
> > the MFD driver like this I think it over-kill for 4 requests.
> 
> I could do something just in the charger, but why not have something which can
> be used for all sub-devices? There is also an IRQ used in the IIO ADC driver and
> there will be another in the later fuel-gauge driver too. Doesn't make sense to
> me not to do in the MFD code when that will provide a simple common call for all
> sub-devices. What is your concern with adding something like this, just so I'm
> clear?

I guess my last response wasn't as descriptive as it could have been.
I don't think that any helper function is required at all.  No need to
abstract/obfuscate how the IRQ is obtained and registered.  What I
meant by 'do it in the charger driver' was, copy and paste all of the
platform_get_irq_byname() and devm_request_threaded_irq() calls from
.probe() into a separate function, but only if you are worried about a
bloated .probe().  Personally I'd just leave them in there.

Bottom line is; I don't feel there is a necessity for any helper
function here.  I think it adds unnecessary complexity for the sake of
saving a few lines of code.

If you still think there is a requirement for it, perhaps a more
system-wide devm_request_threaded_irq_byname() is in order instead?

> > > > > > > +void da9150_release_irq(struct platform_device *pdev, void *dev_id,
> > > > > > > +		       const char *name)
> > > > > > > +{
> > > > > > > +	int irq;
> > > > > > > +
> > > > > > > +	irq = platform_get_irq_byname(pdev, name);
> > > > > > > +	if (irq < 0)
> > > > > > > +		return;
> > > > > > > +
> > > > > > > +	devm_free_irq(&pdev->dev, irq, dev_id);
> > > > > > > +}
> > > > > > > +EXPORT_SYMBOL_GPL(da9150_release_irq);
> > > > > >
> > > > > > Do you ever release the IRQ and not unbind the driver?
> > > > > >
> > > > > > Are there ordering issues at play here?
> > > > > >
> > > > > > If not, there's no need to conduct a manual free.
> > > > >
> > > > > In the charger driver, in the remove function there is a need I believe to
> > > > > free the IRQs before other items are cleared up (e.g. power_supply classes),
> > > > > so this is why I have added this in here.
> > > >
> > > > Can you handle this separately in the Charger driver then please?
> > > >
> > > > [...]
> > >
> > > If I have to remove the IRQ register function, then yes, otherwise it makes more
> > > sense to have the pair of functions in the MFD core I would say.
> > 
> > I would prefer you to remove the call-back please.
> 
> Right.
> 
> > 
> > > > > > > +	if (pdata)
> > > > > > > +		da9150->irq_base = pdata->irq_base;
> > > > > > > +	else
> > > > > > > +		da9150->irq_base = -1;
> > > > > >
> > > > > > pdata ? pdata->irq_base : -1;
> > > > >
> > > > > This is left this way as later updates to add additional functionality will
> > > > > require addtional work to be done with the platform data. Seemed pointless
> > > > > changing it here just to change it back later.
> > > >
> > > > You're not changing anything, as this is the introduction of the code.
> > > > I can't tell you how many times I've heard "I will change it later",
> > > > or "doing it this way will support subsequent submissions", then
> > > > received no more patches.  It's okay to do it nicely now and expand
> > > > it back out in the new patches.
> > > >
> > > > [...]
> > >
> > > It appears that way to you but I have to modify my code for sumbission as the
> > > local code I have covers all functionality. Am having to refactor again and
> > > again just to suit this initial submission, and then I have to revert it back
> > > again when submitting the last couple of drivers. Time consuming, and quite
> > > frustrating when the intention was to make the whole process easier. Anyway,
> > > will update for now and revert in subsequent patches.
> > 
> > I sincerely hope the refactorings won't add too much effort, but it's
> > difficult to have one rule for the masses and different ones for
> > others.
> 
> I do understand that, and that's fair enough. Is just frustrating when you're
> trying to do a proper job. Anyway, am sure I'll live. :)

I know how you feel, as I've been on the receiving end of such rules
more than once, but you could have probably re-factored twice in the
time it's taken us to have this conversation. :)

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
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] 43+ messages in thread

end of thread, other threads:[~2014-09-16 22:08 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-28 10:48 [PATCH v2 0/7] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
2014-08-28 10:48 ` Adam Thomson
2014-08-28 10:48 ` [PATCH v2 1/7] mfd: Add support for DA9150 combined charger & fuel-gauge device Adam Thomson
2014-08-28 10:48   ` Adam Thomson
2014-08-28 11:47   ` Varka Bhadram
2014-09-09 10:32     ` Opensource [Adam Thomson]
2014-09-09 10:32       ` Opensource [Adam Thomson]
2014-09-09 10:32       ` Opensource [Adam Thomson]
2014-09-10  9:51       ` Lee Jones
2014-08-28 16:36   ` Lee Jones
2014-09-09 10:37     ` Opensource [Adam Thomson]
2014-09-09 10:37       ` Opensource [Adam Thomson]
2014-09-09 10:37       ` Opensource [Adam Thomson]
2014-09-10  9:49       ` Lee Jones
2014-09-10 15:58         ` Opensource [Adam Thomson]
2014-09-10 15:58           ` Opensource [Adam Thomson]
2014-09-10 15:58           ` Opensource [Adam Thomson]
2014-09-15 22:39           ` Lee Jones
2014-09-16 10:50             ` Opensource [Adam Thomson]
2014-09-16 10:50               ` Opensource [Adam Thomson]
2014-09-16 10:50               ` Opensource [Adam Thomson]
2014-09-16 22:07               ` Lee Jones
2014-09-16 22:07                 ` Lee Jones
2014-08-28 10:48 ` [PATCH v2 2/7] mfd: da9150: Add DT binding documentation for core Adam Thomson
2014-08-28 10:48   ` Adam Thomson
2014-08-28 10:48 ` [PATCH v2 3/7] iio: Add support for DA9150 GPADC Adam Thomson
2014-08-28 10:48   ` Adam Thomson
2014-08-28 11:28   ` Peter Meerwald
2014-08-30 20:01     ` Jonathan Cameron
2014-09-09 10:53       ` Opensource [Adam Thomson]
2014-09-14 17:26         ` Jonathan Cameron
2014-09-15 10:32           ` Opensource [Adam Thomson]
2014-09-09 10:51     ` Opensource [Adam Thomson]
2014-08-28 10:49 ` [PATCH v2 4/7] iio: da9150: Add DT binding documentation for GPADC Adam Thomson
2014-08-28 10:49   ` Adam Thomson
2014-08-28 10:49 ` [PATCH v2 5/7] power: Add support for DA9150 Charger Adam Thomson
2014-08-28 10:49   ` Adam Thomson
2014-08-28 10:49 ` [PATCH v2 6/7] power: da9150: Add DT binding documentation for charger Adam Thomson
2014-08-28 10:49   ` Adam Thomson
2014-08-28 10:49 ` [PATCH v2 7/7] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list Adam Thomson
2014-08-28 10:49   ` Adam Thomson
2014-08-28 11:17   ` Lee Jones
2014-08-28 11:17     ` Lee Jones

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.