* [PATCH 1/8] mfd: Add support for DA9150 combined charger & fuel-gauge device
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-27 10:33 ` Jonathan Cameron
2014-09-23 10:53 ` [PATCH 2/8] mfd: da9150: Add DT binding documentation for core Adam Thomson
` (6 subsequent siblings)
7 siblings, 1 reply; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
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 | 413 ++++++++++++
include/linux/mfd/da9150/core.h | 68 ++
include/linux/mfd/da9150/registers.h | 1155 ++++++++++++++++++++++++++++++++++
5 files changed, 1649 insertions(+), 1 deletion(-)
create mode 100644 drivers/mfd/da9150-core.c
create mode 100644 include/linux/mfd/da9150/core.h
create mode 100644 include/linux/mfd/da9150/registers.h
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index de5abf2..e29fc9a 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
+ tristate "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..f5484b3 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -113,7 +113,7 @@ 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
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..1de6db7
--- /dev/null
+++ b/drivers/mfd/da9150-core.c
@@ -0,0 +1,413 @@
+/*
+ * 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/i2c.h>
+#include <linux/regmap.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>
+
+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,
+};
+
+u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
+{
+ int val, ret;
+
+ ret = regmap_read(da9150->regmap, reg, &val);
+ 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);
+
+void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
+{
+ int ret;
+
+ ret = regmap_write(da9150->regmap, reg, val);
+ if (ret)
+ dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
+ reg, ret);
+}
+EXPORT_SYMBOL_GPL(da9150_reg_write);
+
+void 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)
+ dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
+ reg, ret);
+}
+EXPORT_SYMBOL_GPL(da9150_set_bits);
+
+void 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)
+ dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
+ reg, ret);
+}
+EXPORT_SYMBOL_GPL(da9150_bulk_read);
+
+void 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)
+ dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
+ reg, 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),
+};
+
+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),
+ },
+};
+
+static int da9150_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct da9150 *da9150;
+ struct da9150_pdata *pdata = dev_get_platdata(&client->dev);
+ int ret;
+
+ 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);
+
+ 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;
+ }
+
+ da9150->irq_base = pdata ? pdata->irq_base : -1;
+
+ 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)
+ return ret;
+
+ da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
+ enable_irq_wake(da9150->irq);
+
+ ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
+ ARRAY_SIZE(da9150_devs), NULL,
+ da9150->irq_base, NULL);
+ if (ret) {
+ dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
+ regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int da9150_remove(struct i2c_client *client)
+{
+ struct da9150 *da9150 = i2c_get_clientdata(client);
+
+ regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+ mfd_remove_devices(da9150->dev);
+
+ return 0;
+}
+
+static void da9150_shutdown(struct i2c_client *client)
+{
+ struct da9150 *da9150 = i2c_get_clientdata(client);
+
+ /* 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);
+}
+
+static const struct i2c_device_id da9150_i2c_id[] = {
+ { "da9150", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
+
+static const struct of_device_id da9150_of_match[] = {
+ { .compatible = "dlg,da9150", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9150_of_match);
+
+static struct i2c_driver da9150_driver = {
+ .driver = {
+ .name = "da9150",
+ .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("MFD Core 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..76e6689
--- /dev/null
+++ b/include/linux/mfd/da9150/core.h
@@ -0,0 +1,68 @@
+/*
+ * 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/interrupt.h>
+#include <linux/regmap.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_pdata {
+ int irq_base;
+};
+
+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);
+void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val);
+void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val);
+
+void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf);
+void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf);
+#endif /* __DA9150_CORE_H */
diff --git a/include/linux/mfd/da9150/registers.h b/include/linux/mfd/da9150/registers.h
new file mode 100644
index 0000000..27ca6ee
--- /dev/null
+++ b/include/linux/mfd/da9150/registers.h
@@ -0,0 +1,1155 @@
+/*
+ * 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
+
+#include <linux/bitops.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 BIT(6)
+#define DA9150_REVERT_SHIFT 7
+#define DA9150_REVERT_MASK BIT(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 BIT(0)
+#define DA9150_TFAULT_STAT_SHIFT 1
+#define DA9150_TFAULT_STAT_MASK BIT(1)
+
+/* DA9150_STATUS_C = 0x06A */
+#define DA9150_VDD33_STAT_SHIFT 0
+#define DA9150_VDD33_STAT_MASK BIT(0)
+#define DA9150_VDD33_SLEEP_SHIFT 1
+#define DA9150_VDD33_SLEEP_MASK BIT(1)
+#define DA9150_LFOSC_STAT_SHIFT 7
+#define DA9150_LFOSC_STAT_MASK BIT(7)
+
+/* DA9150_STATUS_D = 0x06B */
+#define DA9150_GPIOA_STAT_SHIFT 0
+#define DA9150_GPIOA_STAT_MASK BIT(0)
+#define DA9150_GPIOB_STAT_SHIFT 1
+#define DA9150_GPIOB_STAT_MASK BIT(1)
+#define DA9150_GPIOC_STAT_SHIFT 2
+#define DA9150_GPIOC_STAT_MASK BIT(2)
+#define DA9150_GPIOD_STAT_SHIFT 3
+#define DA9150_GPIOD_STAT_MASK BIT(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 BIT(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 BIT(0)
+#define DA9150_ID_ERR_SHIFT 1
+#define DA9150_ID_ERR_MASK BIT(1)
+#define DA9150_PT_CHG_SHIFT 2
+#define DA9150_PT_CHG_MASK BIT(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 BIT(0)
+#define DA9150_VBUS_STAT_CHG (0x02 << 0)
+#define DA9150_VBUS_TRED_SHIFT 3
+#define DA9150_VBUS_TRED_MASK BIT(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 BIT(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 BIT(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 BIT(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 BIT(1)
+#define DA9150_CHG_TRED_SHIFT 2
+#define DA9150_CHG_TRED_MASK BIT(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 BIT(6)
+#define DA9150_CHG_BAT_REMOVED_SHIFT 7
+#define DA9150_CHG_BAT_REMOVED_MASK BIT(7)
+
+/* DA9150_FAULT_LOG_A = 0x076 */
+#define DA9150_TEMP_FAULT_SHIFT 0
+#define DA9150_TEMP_FAULT_MASK BIT(0)
+#define DA9150_VSYS_FAULT_SHIFT 1
+#define DA9150_VSYS_FAULT_MASK BIT(1)
+#define DA9150_START_FAULT_SHIFT 2
+#define DA9150_START_FAULT_MASK BIT(2)
+#define DA9150_EXT_FAULT_SHIFT 3
+#define DA9150_EXT_FAULT_MASK BIT(3)
+#define DA9150_POR_FAULT_SHIFT 4
+#define DA9150_POR_FAULT_MASK BIT(4)
+
+/* DA9150_FAULT_LOG_B = 0x077 */
+#define DA9150_VBUS_FAULT_SHIFT 0
+#define DA9150_VBUS_FAULT_MASK BIT(0)
+#define DA9150_OTG_FAULT_SHIFT 1
+#define DA9150_OTG_FAULT_MASK BIT(1)
+
+/* DA9150_EVENT_E = 0x078 */
+#define DA9150_E_VBUS_SHIFT 0
+#define DA9150_E_VBUS_MASK BIT(0)
+#define DA9150_E_CHG_SHIFT 1
+#define DA9150_E_CHG_MASK BIT(1)
+#define DA9150_E_TCLASS_SHIFT 2
+#define DA9150_E_TCLASS_MASK BIT(2)
+#define DA9150_E_TJUNC_SHIFT 3
+#define DA9150_E_TJUNC_MASK BIT(3)
+#define DA9150_E_VFAULT_SHIFT 4
+#define DA9150_E_VFAULT_MASK BIT(4)
+#define DA9150_EVENTS_H_SHIFT 5
+#define DA9150_EVENTS_H_MASK BIT(5)
+#define DA9150_EVENTS_G_SHIFT 6
+#define DA9150_EVENTS_G_MASK BIT(6)
+#define DA9150_EVENTS_F_SHIFT 7
+#define DA9150_EVENTS_F_MASK BIT(7)
+
+/* DA9150_EVENT_F = 0x079 */
+#define DA9150_E_CONF_SHIFT 0
+#define DA9150_E_CONF_MASK BIT(0)
+#define DA9150_E_DAT_SHIFT 1
+#define DA9150_E_DAT_MASK BIT(1)
+#define DA9150_E_DTYPE_SHIFT 3
+#define DA9150_E_DTYPE_MASK BIT(3)
+#define DA9150_E_ID_SHIFT 4
+#define DA9150_E_ID_MASK BIT(4)
+#define DA9150_E_ADP_SHIFT 5
+#define DA9150_E_ADP_MASK BIT(5)
+#define DA9150_E_SESS_END_SHIFT 6
+#define DA9150_E_SESS_END_MASK BIT(6)
+#define DA9150_E_SESS_VLD_SHIFT 7
+#define DA9150_E_SESS_VLD_MASK BIT(7)
+
+/* DA9150_EVENT_G = 0x07A */
+#define DA9150_E_FG_SHIFT 0
+#define DA9150_E_FG_MASK BIT(0)
+#define DA9150_E_GP_SHIFT 1
+#define DA9150_E_GP_MASK BIT(1)
+#define DA9150_E_TBAT_SHIFT 2
+#define DA9150_E_TBAT_MASK BIT(2)
+#define DA9150_E_GPIOA_SHIFT 3
+#define DA9150_E_GPIOA_MASK BIT(3)
+#define DA9150_E_GPIOB_SHIFT 4
+#define DA9150_E_GPIOB_MASK BIT(4)
+#define DA9150_E_GPIOC_SHIFT 5
+#define DA9150_E_GPIOC_MASK BIT(5)
+#define DA9150_E_GPIOD_SHIFT 6
+#define DA9150_E_GPIOD_MASK BIT(6)
+#define DA9150_E_GPADC_SHIFT 7
+#define DA9150_E_GPADC_MASK BIT(7)
+
+/* DA9150_EVENT_H = 0x07B */
+#define DA9150_E_WKUP_SHIFT 0
+#define DA9150_E_WKUP_MASK BIT(0)
+
+/* DA9150_IRQ_MASK_E = 0x07C */
+#define DA9150_M_VBUS_SHIFT 0
+#define DA9150_M_VBUS_MASK BIT(0)
+#define DA9150_M_CHG_SHIFT 1
+#define DA9150_M_CHG_MASK BIT(1)
+#define DA9150_M_TJUNC_SHIFT 3
+#define DA9150_M_TJUNC_MASK BIT(3)
+#define DA9150_M_VFAULT_SHIFT 4
+#define DA9150_M_VFAULT_MASK BIT(4)
+
+/* DA9150_IRQ_MASK_F = 0x07D */
+#define DA9150_M_CONF_SHIFT 0
+#define DA9150_M_CONF_MASK BIT(0)
+#define DA9150_M_DAT_SHIFT 1
+#define DA9150_M_DAT_MASK BIT(1)
+#define DA9150_M_DTYPE_SHIFT 3
+#define DA9150_M_DTYPE_MASK BIT(3)
+#define DA9150_M_ID_SHIFT 4
+#define DA9150_M_ID_MASK BIT(4)
+#define DA9150_M_ADP_SHIFT 5
+#define DA9150_M_ADP_MASK BIT(5)
+#define DA9150_M_SESS_END_SHIFT 6
+#define DA9150_M_SESS_END_MASK BIT(6)
+#define DA9150_M_SESS_VLD_SHIFT 7
+#define DA9150_M_SESS_VLD_MASK BIT(7)
+
+/* DA9150_IRQ_MASK_G = 0x07E */
+#define DA9150_M_FG_SHIFT 0
+#define DA9150_M_FG_MASK BIT(0)
+#define DA9150_M_GP_SHIFT 1
+#define DA9150_M_GP_MASK BIT(1)
+#define DA9150_M_TBAT_SHIFT 2
+#define DA9150_M_TBAT_MASK BIT(2)
+#define DA9150_M_GPIOA_SHIFT 3
+#define DA9150_M_GPIOA_MASK BIT(3)
+#define DA9150_M_GPIOB_SHIFT 4
+#define DA9150_M_GPIOB_MASK BIT(4)
+#define DA9150_M_GPIOC_SHIFT 5
+#define DA9150_M_GPIOC_MASK BIT(5)
+#define DA9150_M_GPIOD_SHIFT 6
+#define DA9150_M_GPIOD_MASK BIT(6)
+#define DA9150_M_GPADC_SHIFT 7
+#define DA9150_M_GPADC_MASK BIT(7)
+
+/* DA9150_IRQ_MASK_H = 0x07F */
+#define DA9150_M_WKUP_SHIFT 0
+#define DA9150_M_WKUP_MASK BIT(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 BIT(6)
+#define DA9150_REVERT_SHIFT 7
+#define DA9150_REVERT_MASK BIT(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 BIT(6)
+#define DA9150_PS_DISABLE_DIRECT_SHIFT 7
+#define DA9150_PS_DISABLE_DIRECT_MASK BIT(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 BIT(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 BIT(0)
+#define DA9150_VDD33_DWN_SHIFT 1
+#define DA9150_VDD33_DWN_MASK BIT(1)
+#define DA9150_WKUP_PM_EN_SHIFT 2
+#define DA9150_WKUP_PM_EN_MASK BIT(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 BIT(5)
+#define DA9150_DISABLE_DEL_SHIFT 7
+#define DA9150_DISABLE_DEL_MASK BIT(7)
+
+/* DA9150_CONFIG_E = 0x0E4 */
+#define DA9150_PM_SPKSUP_DIS_SHIFT 0
+#define DA9150_PM_SPKSUP_DIS_MASK BIT(0)
+#define DA9150_PM_MERGE_SHIFT 1
+#define DA9150_PM_MERGE_MASK BIT(1)
+#define DA9150_PM_SR_OFF_SHIFT 2
+#define DA9150_PM_SR_OFF_MASK BIT(2)
+#define DA9150_PM_TIMEOUT_EN_SHIFT 3
+#define DA9150_PM_TIMEOUT_EN_MASK BIT(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 BIT(7)
+
+/* DA9150_CONTROL_A = 0x0E5 */
+#define DA9150_VDD33_SL_SHIFT 0
+#define DA9150_VDD33_SL_MASK BIT(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 BIT(3)
+#define DA9150_GPI_LPM_SHIFT 6
+#define DA9150_GPI_LPM_MASK BIT(6)
+#define DA9150_PM_IF_LPM_SHIFT 7
+#define DA9150_PM_IF_LPM_MASK BIT(7)
+
+/* DA9150_CONTROL_B = 0x0E6 */
+#define DA9150_LPM_SHIFT 0
+#define DA9150_LPM_MASK BIT(0)
+#define DA9150_RESET_SHIFT 1
+#define DA9150_RESET_MASK BIT(1)
+#define DA9150_RESET_USRCONF_EN_SHIFT 2
+#define DA9150_RESET_USRCONF_EN_MASK BIT(2)
+
+/* DA9150_CONTROL_C = 0x0E7 */
+#define DA9150_DISABLE_SHIFT 0
+#define DA9150_DISABLE_MASK BIT(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 BIT(0)
+#define DA9150_GPIOA_TYPE_SHIFT 3
+#define DA9150_GPIOA_TYPE_MASK BIT(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 BIT(4)
+#define DA9150_GPIOB_TYPE_SHIFT 7
+#define DA9150_GPIOB_TYPE_MASK BIT(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 BIT(0)
+#define DA9150_GPIOC_TYPE_SHIFT 3
+#define DA9150_GPIOC_TYPE_MASK BIT(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 BIT(4)
+#define DA9150_GPIOD_TYPE_SHIFT 7
+#define DA9150_GPIOD_TYPE_MASK BIT(7)
+
+/* DA9150_GPIO_MODE_CONT = 0x0EA */
+#define DA9150_GPIOA_MODE_SHIFT 0
+#define DA9150_GPIOA_MODE_MASK BIT(0)
+#define DA9150_GPIOB_MODE_SHIFT 1
+#define DA9150_GPIOB_MODE_MASK BIT(1)
+#define DA9150_GPIOC_MODE_SHIFT 2
+#define DA9150_GPIOC_MODE_MASK BIT(2)
+#define DA9150_GPIOD_MODE_SHIFT 3
+#define DA9150_GPIOD_MODE_MASK BIT(3)
+#define DA9150_GPIOA_CONT_SHIFT 4
+#define DA9150_GPIOA_CONT_MASK BIT(4)
+#define DA9150_GPIOB_CONT_SHIFT 5
+#define DA9150_GPIOB_CONT_MASK BIT(5)
+#define DA9150_GPIOC_CONT_SHIFT 6
+#define DA9150_GPIOC_CONT_MASK BIT(6)
+#define DA9150_GPIOD_CONT_SHIFT 7
+#define DA9150_GPIOD_CONT_MASK BIT(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 BIT(2)
+#define DA9150_WAKE_CONT_SHIFT 3
+#define DA9150_WAKE_CONT_MASK BIT(3)
+#define DA9150_WAKE_DLY_SHIFT 4
+#define DA9150_WAKE_DLY_MASK BIT(4)
+
+/* DA9150_GPIO_CTRL_A = 0x0EC */
+#define DA9150_GPIOA_ANAEN_SHIFT 0
+#define DA9150_GPIOA_ANAEN_MASK BIT(0)
+#define DA9150_GPIOB_ANAEN_SHIFT 1
+#define DA9150_GPIOB_ANAEN_MASK BIT(1)
+#define DA9150_GPIOC_ANAEN_SHIFT 2
+#define DA9150_GPIOC_ANAEN_MASK BIT(2)
+#define DA9150_GPIOD_ANAEN_SHIFT 3
+#define DA9150_GPIOD_ANAEN_MASK BIT(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 BIT(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 BIT(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 BIT(0)
+#define DA9150_GPIOB_PUPD_SHIFT 1
+#define DA9150_GPIOB_PUPD_MASK BIT(1)
+#define DA9150_GPIOC_PUPD_SHIFT 2
+#define DA9150_GPIOC_PUPD_MASK BIT(2)
+#define DA9150_GPIOD_PUPD_SHIFT 3
+#define DA9150_GPIOD_PUPD_MASK BIT(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 BIT(7)
+
+/* DA9150_GPIO_CFG_C = 0x0F0 */
+#define DA9150_GPI_V_SHIFT 0
+#define DA9150_GPI_V_MASK BIT(0)
+#define DA9150_VDDIO_INT_SHIFT 1
+#define DA9150_VDDIO_INT_MASK BIT(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 BIT(6)
+#define DA9150_NIRQ_PUPD_SHIFT 7
+#define DA9150_NIRQ_PUPD_MASK BIT(7)
+
+/* DA9150_GPADC_MAN = 0x0F2 */
+#define DA9150_GPADC_EN_SHIFT 0
+#define DA9150_GPADC_EN_MASK BIT(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 BIT(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 BIT(6)
+#define DA9150_REVERT_SHIFT 7
+#define DA9150_REVERT_MASK BIT(7)
+
+/* DA9150_OTP_CONT_SHARED = 0x101 */
+#define DA9150_PC_DONE_SHIFT 3
+#define DA9150_PC_DONE_MASK BIT(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 BIT(1)
+#define DA9150_NIRQ_PIN_SHIFT 2
+#define DA9150_NIRQ_PIN_MASK BIT(2)
+#define DA9150_NIRQ_TYPE_SHIFT 3
+#define DA9150_NIRQ_TYPE_MASK BIT(3)
+#define DA9150_PM_IF_V_SHIFT 4
+#define DA9150_PM_IF_V_MASK BIT(4)
+#define DA9150_PM_IF_FMP_SHIFT 5
+#define DA9150_PM_IF_FMP_MASK BIT(5)
+#define DA9150_PM_IF_HSM_SHIFT 6
+#define DA9150_PM_IF_HSM_MASK BIT(6)
+
+/* DA9150_CONFIG_D_SHARED = 0x109 */
+#define DA9150_NIRQ_MODE_SHIFT 1
+#define DA9150_NIRQ_MODE_MASK BIT(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 BIT(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 BIT(5)
+#define DA9150_DM_STAT_SHIFT 6
+#define DA9150_DM_STAT_MASK BIT(6)
+
+/* DA9150_ADET_CMPSTAT = 0x152 */
+#define DA9150_DP_COMP_SHIFT 1
+#define DA9150_DP_COMP_MASK BIT(1)
+#define DA9150_DM_COMP_SHIFT 2
+#define DA9150_DM_COMP_MASK BIT(2)
+#define DA9150_ADP_SNS_COMP_SHIFT 3
+#define DA9150_ADP_SNS_COMP_MASK BIT(3)
+#define DA9150_ADP_PRB_COMP_SHIFT 4
+#define DA9150_ADP_PRB_COMP_MASK BIT(4)
+#define DA9150_ID_COMP_SHIFT 5
+#define DA9150_ID_COMP_MASK BIT(5)
+
+/* DA9150_ADET_CTRL_A = 0x153 */
+#define DA9150_AID_DAT_SHIFT 0
+#define DA9150_AID_DAT_MASK BIT(0)
+#define DA9150_AID_ID_SHIFT 1
+#define DA9150_AID_ID_MASK BIT(1)
+#define DA9150_AID_TRIG_SHIFT 2
+#define DA9150_AID_TRIG_MASK BIT(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 BIT(0)
+
+#define DA9150_TADP_PRB_SHIFT 2
+#define DA9150_TADP_PRB_MASK BIT(2)
+#define DA9150_DAT_RPD_EXT_SHIFT 5
+#define DA9150_DAT_RPD_EXT_MASK BIT(5)
+#define DA9150_CONF_RPD_SHIFT 6
+#define DA9150_CONF_RPD_MASK BIT(6)
+#define DA9150_CONF_SRP_SHIFT 7
+#define DA9150_CONF_SRP_MASK BIT(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 BIT(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 BIT(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 BIT(5)
+#define DA9150_CONF_GPIOB_SHIFT 6
+#define DA9150_CONF_GPIOB_MASK BIT(6)
+#define DA9150_AID_VB_SHIFT 7
+#define DA9150_AID_VB_MASK BIT(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 BIT(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 BIT(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 BIT(6)
+#define DA9150_DAT_CLAMP_EXT_SHIFT 7
+#define DA9150_DAT_CLAMP_EXT_MASK BIT(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 BIT(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 BIT(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 BIT(4)
+#define DA9150_VBUS_PWM_SHIFT 5
+#define DA9150_VBUS_PWM_MASK BIT(5)
+#define DA9150_VBUS_ISO_SHIFT 6
+#define DA9150_VBUS_ISO_MASK BIT(6)
+#define DA9150_VBUS_LDO_SHIFT 7
+#define DA9150_VBUS_LDO_MASK BIT(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 BIT(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 BIT(6)
+#define DA9150_OTG_FAULT_DIS_SHIFT 7
+#define DA9150_OTG_FAULT_DIS_MASK BIT(7)
+
+/* DA9150_PPR_CHGCTRL_A = 0x166 */
+#define DA9150_CHG_EN_SHIFT 0
+#define DA9150_CHG_EN_MASK BIT(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 BIT(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 BIT(6)
+#define DA9150_TBAT_TDP_EN_SHIFT 7
+#define DA9150_TBAT_TDP_EN_MASK BIT(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 BIT(5)
+#define DA9150_CHG_NBLO_SHIFT 6
+#define DA9150_CHG_NBLO_MASK BIT(6)
+#define DA9150_EBS_EN_SHIFT 7
+#define DA9150_EBS_EN_MASK BIT(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 BIT(6)
+#define DA9150_REVERT_SHIFT 7
+#define DA9150_REVERT_MASK BIT(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 BIT(6)
+#define DA9150_REVERT_SHIFT 7
+#define DA9150_REVERT_MASK BIT(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 BIT(6)
+#define DA9150_REVERT_SHIFT 7
+#define DA9150_REVERT_MASK BIT(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 BIT(6)
+#define DA9150_REVERT_SHIFT 7
+#define DA9150_REVERT_MASK BIT(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 BIT(2)
+
+/* DA9150_COREBTLD_CTRL_A = 0x303 */
+#define DA9150_CORE_RESET_SHIFT 0
+#define DA9150_CORE_RESET_MASK BIT(0)
+#define DA9150_CORE_STOP_SHIFT 1
+#define DA9150_CORE_STOP_MASK BIT(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 BIT(2)
+#define DA9150_WDT_AUTO_LOCK_SHIFT 3
+#define DA9150_WDT_AUTO_LOCK_MASK BIT(3)
+#define DA9150_WDT_HLT_NO_CLK_SHIFT 4
+#define DA9150_WDT_HLT_NO_CLK_MASK BIT(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 BIT(0)
+#define DA9150_CORE_EN_SHIFT 2
+#define DA9150_CORE_EN_MASK BIT(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 BIT(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 BIT(7)
+
+/* DA9150_CORE2WIRE_CTRL_A = 0x311 */
+#define DA9150_FW_FWDL_EN_SHIFT 0
+#define DA9150_FW_FWDL_EN_MASK BIT(0)
+#define DA9150_FG_QIF_EN_SHIFT 1
+#define DA9150_FG_QIF_EN_MASK BIT(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 BIT(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 BIT(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 BIT(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 BIT(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 BIT(0)
+#define DA9150_TAUX_MOD_SHIFT 1
+#define DA9150_TAUX_MOD_MASK BIT(1)
+#define DA9150_TAUX_UPDATE_SHIFT 2
+#define DA9150_TAUX_UPDATE_MASK BIT(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 BIT(0)
+
+/* DA9150_TBAT_CTRL_A = 0x342 */
+#define DA9150_TBAT_EN_SHIFT 0
+#define DA9150_TBAT_EN_MASK BIT(0)
+#define DA9150_TBAT_SW1_SHIFT 1
+#define DA9150_TBAT_SW1_MASK BIT(1)
+#define DA9150_TBAT_SW2_SHIFT 2
+#define DA9150_TBAT_SW2_MASK BIT(2)
+
+/* DA9150_TBAT_CTRL_B = 0x343 */
+#define DA9150_TBAT_SW_FRC_SHIFT 0
+#define DA9150_TBAT_SW_FRC_MASK BIT(0)
+#define DA9150_TBAT_STAT_SW1_SHIFT 1
+#define DA9150_TBAT_STAT_SW1_MASK BIT(1)
+#define DA9150_TBAT_STAT_SW2_SHIFT 2
+#define DA9150_TBAT_STAT_SW2_MASK BIT(2)
+#define DA9150_TBAT_HIGH_CURR_SHIFT 3
+#define DA9150_TBAT_HIGH_CURR_MASK BIT(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 BIT(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] 22+ messages in thread
* Re: [PATCH 1/8] mfd: Add support for DA9150 combined charger & fuel-gauge device
2014-09-23 10:53 ` [PATCH 1/8] mfd: Add support for DA9150 combined charger & fuel-gauge device Adam Thomson
@ 2014-09-27 10:33 ` Jonathan Cameron
0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2014-09-27 10:33 UTC (permalink / raw)
To: Adam Thomson, Lee Jones, Samuel Ortiz, linux-iio,
Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
On 23/09/14 11:53, 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>
A random suggestion to reduced the massive set of defines... Why
not just compute the shift from the mask where needed?
Just use ffs(MASK).
No idea if anyone else will like the suggestion though ;)
Otherwise looks fine to me.
> ---
> drivers/mfd/Kconfig | 12 +
> drivers/mfd/Makefile | 2 +-
> drivers/mfd/da9150-core.c | 413 ++++++++++++
> include/linux/mfd/da9150/core.h | 68 ++
> include/linux/mfd/da9150/registers.h | 1155 ++++++++++++++++++++++++++++++++++
> 5 files changed, 1649 insertions(+), 1 deletion(-)
> create mode 100644 drivers/mfd/da9150-core.c
> create mode 100644 include/linux/mfd/da9150/core.h
> create mode 100644 include/linux/mfd/da9150/registers.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index de5abf2..e29fc9a 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
> + tristate "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..f5484b3 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -113,7 +113,7 @@ 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
> 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..1de6db7
> --- /dev/null
> +++ b/drivers/mfd/da9150-core.c
> @@ -0,0 +1,413 @@
> +/*
> + * 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/i2c.h>
> +#include <linux/regmap.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>
> +
> +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,
> +};
> +
> +u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
> +{
> + int val, ret;
> +
> + ret = regmap_read(da9150->regmap, reg, &val);
> + 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);
> +
> +void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
> +{
> + int ret;
> +
> + ret = regmap_write(da9150->regmap, reg, val);
> + if (ret)
> + dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
> + reg, ret);
> +}
> +EXPORT_SYMBOL_GPL(da9150_reg_write);
> +
> +void 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)
> + dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
> + reg, ret);
> +}
> +EXPORT_SYMBOL_GPL(da9150_set_bits);
> +
> +void 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)
> + dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
> + reg, ret);
> +}
> +EXPORT_SYMBOL_GPL(da9150_bulk_read);
> +
> +void 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)
> + dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
> + reg, 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),
> +};
> +
> +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),
> + },
> +};
> +
> +static int da9150_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct da9150 *da9150;
> + struct da9150_pdata *pdata = dev_get_platdata(&client->dev);
> + int ret;
> +
> + 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);
> +
> + 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;
> + }
> +
> + da9150->irq_base = pdata ? pdata->irq_base : -1;
> +
> + 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)
> + return ret;
> +
> + da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
> + enable_irq_wake(da9150->irq);
> +
> + ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
> + ARRAY_SIZE(da9150_devs), NULL,
> + da9150->irq_base, NULL);
> + if (ret) {
> + dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
> + regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int da9150_remove(struct i2c_client *client)
> +{
> + struct da9150 *da9150 = i2c_get_clientdata(client);
> +
> + regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
> + mfd_remove_devices(da9150->dev);
> +
> + return 0;
> +}
> +
> +static void da9150_shutdown(struct i2c_client *client)
> +{
> + struct da9150 *da9150 = i2c_get_clientdata(client);
> +
> + /* 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);
> +}
> +
> +static const struct i2c_device_id da9150_i2c_id[] = {
> + { "da9150", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
> +
> +static const struct of_device_id da9150_of_match[] = {
> + { .compatible = "dlg,da9150", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, da9150_of_match);
> +
> +static struct i2c_driver da9150_driver = {
> + .driver = {
> + .name = "da9150",
> + .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("MFD Core 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..76e6689
> --- /dev/null
> +++ b/include/linux/mfd/da9150/core.h
> @@ -0,0 +1,68 @@
> +/*
> + * 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/interrupt.h>
> +#include <linux/regmap.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_pdata {
> + int irq_base;
> +};
> +
> +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);
> +void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val);
> +void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val);
> +
> +void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf);
> +void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf);
> +#endif /* __DA9150_CORE_H */
> diff --git a/include/linux/mfd/da9150/registers.h b/include/linux/mfd/da9150/registers.h
> new file mode 100644
> index 0000000..27ca6ee
> --- /dev/null
> +++ b/include/linux/mfd/da9150/registers.h
> @@ -0,0 +1,1155 @@
> +/*
> + * 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
> +
> +#include <linux/bitops.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
You could drop all the shift values and compute it from the mask...
(just ffs(MASK) should work I think).
Just feels very clunky to have all the repitition we have in these
defines!
> +#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 BIT(6)
> +#define DA9150_REVERT_SHIFT 7
> +#define DA9150_REVERT_MASK BIT(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 BIT(0)
> +#define DA9150_TFAULT_STAT_SHIFT 1
> +#define DA9150_TFAULT_STAT_MASK BIT(1)
> +
> +/* DA9150_STATUS_C = 0x06A */
> +#define DA9150_VDD33_STAT_SHIFT 0
> +#define DA9150_VDD33_STAT_MASK BIT(0)
> +#define DA9150_VDD33_SLEEP_SHIFT 1
> +#define DA9150_VDD33_SLEEP_MASK BIT(1)
> +#define DA9150_LFOSC_STAT_SHIFT 7
> +#define DA9150_LFOSC_STAT_MASK BIT(7)
> +
> +/* DA9150_STATUS_D = 0x06B */
> +#define DA9150_GPIOA_STAT_SHIFT 0
> +#define DA9150_GPIOA_STAT_MASK BIT(0)
> +#define DA9150_GPIOB_STAT_SHIFT 1
> +#define DA9150_GPIOB_STAT_MASK BIT(1)
> +#define DA9150_GPIOC_STAT_SHIFT 2
> +#define DA9150_GPIOC_STAT_MASK BIT(2)
> +#define DA9150_GPIOD_STAT_SHIFT 3
> +#define DA9150_GPIOD_STAT_MASK BIT(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 BIT(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 BIT(0)
> +#define DA9150_ID_ERR_SHIFT 1
> +#define DA9150_ID_ERR_MASK BIT(1)
> +#define DA9150_PT_CHG_SHIFT 2
> +#define DA9150_PT_CHG_MASK BIT(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 BIT(0)
> +#define DA9150_VBUS_STAT_CHG (0x02 << 0)
> +#define DA9150_VBUS_TRED_SHIFT 3
> +#define DA9150_VBUS_TRED_MASK BIT(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 BIT(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 BIT(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 BIT(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 BIT(1)
> +#define DA9150_CHG_TRED_SHIFT 2
> +#define DA9150_CHG_TRED_MASK BIT(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 BIT(6)
> +#define DA9150_CHG_BAT_REMOVED_SHIFT 7
> +#define DA9150_CHG_BAT_REMOVED_MASK BIT(7)
> +
> +/* DA9150_FAULT_LOG_A = 0x076 */
> +#define DA9150_TEMP_FAULT_SHIFT 0
> +#define DA9150_TEMP_FAULT_MASK BIT(0)
> +#define DA9150_VSYS_FAULT_SHIFT 1
> +#define DA9150_VSYS_FAULT_MASK BIT(1)
> +#define DA9150_START_FAULT_SHIFT 2
> +#define DA9150_START_FAULT_MASK BIT(2)
> +#define DA9150_EXT_FAULT_SHIFT 3
> +#define DA9150_EXT_FAULT_MASK BIT(3)
> +#define DA9150_POR_FAULT_SHIFT 4
> +#define DA9150_POR_FAULT_MASK BIT(4)
> +
> +/* DA9150_FAULT_LOG_B = 0x077 */
> +#define DA9150_VBUS_FAULT_SHIFT 0
> +#define DA9150_VBUS_FAULT_MASK BIT(0)
> +#define DA9150_OTG_FAULT_SHIFT 1
> +#define DA9150_OTG_FAULT_MASK BIT(1)
> +
> +/* DA9150_EVENT_E = 0x078 */
> +#define DA9150_E_VBUS_SHIFT 0
> +#define DA9150_E_VBUS_MASK BIT(0)
> +#define DA9150_E_CHG_SHIFT 1
> +#define DA9150_E_CHG_MASK BIT(1)
> +#define DA9150_E_TCLASS_SHIFT 2
> +#define DA9150_E_TCLASS_MASK BIT(2)
> +#define DA9150_E_TJUNC_SHIFT 3
> +#define DA9150_E_TJUNC_MASK BIT(3)
> +#define DA9150_E_VFAULT_SHIFT 4
> +#define DA9150_E_VFAULT_MASK BIT(4)
> +#define DA9150_EVENTS_H_SHIFT 5
> +#define DA9150_EVENTS_H_MASK BIT(5)
> +#define DA9150_EVENTS_G_SHIFT 6
> +#define DA9150_EVENTS_G_MASK BIT(6)
> +#define DA9150_EVENTS_F_SHIFT 7
> +#define DA9150_EVENTS_F_MASK BIT(7)
> +
> +/* DA9150_EVENT_F = 0x079 */
> +#define DA9150_E_CONF_SHIFT 0
> +#define DA9150_E_CONF_MASK BIT(0)
> +#define DA9150_E_DAT_SHIFT 1
> +#define DA9150_E_DAT_MASK BIT(1)
> +#define DA9150_E_DTYPE_SHIFT 3
> +#define DA9150_E_DTYPE_MASK BIT(3)
> +#define DA9150_E_ID_SHIFT 4
> +#define DA9150_E_ID_MASK BIT(4)
> +#define DA9150_E_ADP_SHIFT 5
> +#define DA9150_E_ADP_MASK BIT(5)
> +#define DA9150_E_SESS_END_SHIFT 6
> +#define DA9150_E_SESS_END_MASK BIT(6)
> +#define DA9150_E_SESS_VLD_SHIFT 7
> +#define DA9150_E_SESS_VLD_MASK BIT(7)
> +
> +/* DA9150_EVENT_G = 0x07A */
> +#define DA9150_E_FG_SHIFT 0
> +#define DA9150_E_FG_MASK BIT(0)
> +#define DA9150_E_GP_SHIFT 1
> +#define DA9150_E_GP_MASK BIT(1)
> +#define DA9150_E_TBAT_SHIFT 2
> +#define DA9150_E_TBAT_MASK BIT(2)
> +#define DA9150_E_GPIOA_SHIFT 3
> +#define DA9150_E_GPIOA_MASK BIT(3)
> +#define DA9150_E_GPIOB_SHIFT 4
> +#define DA9150_E_GPIOB_MASK BIT(4)
> +#define DA9150_E_GPIOC_SHIFT 5
> +#define DA9150_E_GPIOC_MASK BIT(5)
> +#define DA9150_E_GPIOD_SHIFT 6
> +#define DA9150_E_GPIOD_MASK BIT(6)
> +#define DA9150_E_GPADC_SHIFT 7
> +#define DA9150_E_GPADC_MASK BIT(7)
> +
> +/* DA9150_EVENT_H = 0x07B */
> +#define DA9150_E_WKUP_SHIFT 0
> +#define DA9150_E_WKUP_MASK BIT(0)
> +
> +/* DA9150_IRQ_MASK_E = 0x07C */
> +#define DA9150_M_VBUS_SHIFT 0
> +#define DA9150_M_VBUS_MASK BIT(0)
> +#define DA9150_M_CHG_SHIFT 1
> +#define DA9150_M_CHG_MASK BIT(1)
> +#define DA9150_M_TJUNC_SHIFT 3
> +#define DA9150_M_TJUNC_MASK BIT(3)
> +#define DA9150_M_VFAULT_SHIFT 4
> +#define DA9150_M_VFAULT_MASK BIT(4)
> +
> +/* DA9150_IRQ_MASK_F = 0x07D */
> +#define DA9150_M_CONF_SHIFT 0
> +#define DA9150_M_CONF_MASK BIT(0)
> +#define DA9150_M_DAT_SHIFT 1
> +#define DA9150_M_DAT_MASK BIT(1)
> +#define DA9150_M_DTYPE_SHIFT 3
> +#define DA9150_M_DTYPE_MASK BIT(3)
> +#define DA9150_M_ID_SHIFT 4
> +#define DA9150_M_ID_MASK BIT(4)
> +#define DA9150_M_ADP_SHIFT 5
> +#define DA9150_M_ADP_MASK BIT(5)
> +#define DA9150_M_SESS_END_SHIFT 6
> +#define DA9150_M_SESS_END_MASK BIT(6)
> +#define DA9150_M_SESS_VLD_SHIFT 7
> +#define DA9150_M_SESS_VLD_MASK BIT(7)
> +
> +/* DA9150_IRQ_MASK_G = 0x07E */
> +#define DA9150_M_FG_SHIFT 0
> +#define DA9150_M_FG_MASK BIT(0)
> +#define DA9150_M_GP_SHIFT 1
> +#define DA9150_M_GP_MASK BIT(1)
> +#define DA9150_M_TBAT_SHIFT 2
> +#define DA9150_M_TBAT_MASK BIT(2)
> +#define DA9150_M_GPIOA_SHIFT 3
> +#define DA9150_M_GPIOA_MASK BIT(3)
> +#define DA9150_M_GPIOB_SHIFT 4
> +#define DA9150_M_GPIOB_MASK BIT(4)
> +#define DA9150_M_GPIOC_SHIFT 5
> +#define DA9150_M_GPIOC_MASK BIT(5)
> +#define DA9150_M_GPIOD_SHIFT 6
> +#define DA9150_M_GPIOD_MASK BIT(6)
> +#define DA9150_M_GPADC_SHIFT 7
> +#define DA9150_M_GPADC_MASK BIT(7)
> +
> +/* DA9150_IRQ_MASK_H = 0x07F */
> +#define DA9150_M_WKUP_SHIFT 0
> +#define DA9150_M_WKUP_MASK BIT(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 BIT(6)
> +#define DA9150_REVERT_SHIFT 7
> +#define DA9150_REVERT_MASK BIT(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 BIT(6)
> +#define DA9150_PS_DISABLE_DIRECT_SHIFT 7
> +#define DA9150_PS_DISABLE_DIRECT_MASK BIT(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 BIT(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 BIT(0)
> +#define DA9150_VDD33_DWN_SHIFT 1
> +#define DA9150_VDD33_DWN_MASK BIT(1)
> +#define DA9150_WKUP_PM_EN_SHIFT 2
> +#define DA9150_WKUP_PM_EN_MASK BIT(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 BIT(5)
> +#define DA9150_DISABLE_DEL_SHIFT 7
> +#define DA9150_DISABLE_DEL_MASK BIT(7)
> +
> +/* DA9150_CONFIG_E = 0x0E4 */
> +#define DA9150_PM_SPKSUP_DIS_SHIFT 0
> +#define DA9150_PM_SPKSUP_DIS_MASK BIT(0)
> +#define DA9150_PM_MERGE_SHIFT 1
> +#define DA9150_PM_MERGE_MASK BIT(1)
> +#define DA9150_PM_SR_OFF_SHIFT 2
> +#define DA9150_PM_SR_OFF_MASK BIT(2)
> +#define DA9150_PM_TIMEOUT_EN_SHIFT 3
> +#define DA9150_PM_TIMEOUT_EN_MASK BIT(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 BIT(7)
> +
> +/* DA9150_CONTROL_A = 0x0E5 */
> +#define DA9150_VDD33_SL_SHIFT 0
> +#define DA9150_VDD33_SL_MASK BIT(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 BIT(3)
> +#define DA9150_GPI_LPM_SHIFT 6
> +#define DA9150_GPI_LPM_MASK BIT(6)
> +#define DA9150_PM_IF_LPM_SHIFT 7
> +#define DA9150_PM_IF_LPM_MASK BIT(7)
> +
> +/* DA9150_CONTROL_B = 0x0E6 */
> +#define DA9150_LPM_SHIFT 0
> +#define DA9150_LPM_MASK BIT(0)
> +#define DA9150_RESET_SHIFT 1
> +#define DA9150_RESET_MASK BIT(1)
> +#define DA9150_RESET_USRCONF_EN_SHIFT 2
> +#define DA9150_RESET_USRCONF_EN_MASK BIT(2)
> +
> +/* DA9150_CONTROL_C = 0x0E7 */
> +#define DA9150_DISABLE_SHIFT 0
> +#define DA9150_DISABLE_MASK BIT(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 BIT(0)
> +#define DA9150_GPIOA_TYPE_SHIFT 3
> +#define DA9150_GPIOA_TYPE_MASK BIT(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 BIT(4)
> +#define DA9150_GPIOB_TYPE_SHIFT 7
> +#define DA9150_GPIOB_TYPE_MASK BIT(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 BIT(0)
> +#define DA9150_GPIOC_TYPE_SHIFT 3
> +#define DA9150_GPIOC_TYPE_MASK BIT(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 BIT(4)
> +#define DA9150_GPIOD_TYPE_SHIFT 7
> +#define DA9150_GPIOD_TYPE_MASK BIT(7)
> +
> +/* DA9150_GPIO_MODE_CONT = 0x0EA */
> +#define DA9150_GPIOA_MODE_SHIFT 0
> +#define DA9150_GPIOA_MODE_MASK BIT(0)
> +#define DA9150_GPIOB_MODE_SHIFT 1
> +#define DA9150_GPIOB_MODE_MASK BIT(1)
> +#define DA9150_GPIOC_MODE_SHIFT 2
> +#define DA9150_GPIOC_MODE_MASK BIT(2)
> +#define DA9150_GPIOD_MODE_SHIFT 3
> +#define DA9150_GPIOD_MODE_MASK BIT(3)
> +#define DA9150_GPIOA_CONT_SHIFT 4
> +#define DA9150_GPIOA_CONT_MASK BIT(4)
> +#define DA9150_GPIOB_CONT_SHIFT 5
> +#define DA9150_GPIOB_CONT_MASK BIT(5)
> +#define DA9150_GPIOC_CONT_SHIFT 6
> +#define DA9150_GPIOC_CONT_MASK BIT(6)
> +#define DA9150_GPIOD_CONT_SHIFT 7
> +#define DA9150_GPIOD_CONT_MASK BIT(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 BIT(2)
> +#define DA9150_WAKE_CONT_SHIFT 3
> +#define DA9150_WAKE_CONT_MASK BIT(3)
> +#define DA9150_WAKE_DLY_SHIFT 4
> +#define DA9150_WAKE_DLY_MASK BIT(4)
> +
> +/* DA9150_GPIO_CTRL_A = 0x0EC */
> +#define DA9150_GPIOA_ANAEN_SHIFT 0
> +#define DA9150_GPIOA_ANAEN_MASK BIT(0)
> +#define DA9150_GPIOB_ANAEN_SHIFT 1
> +#define DA9150_GPIOB_ANAEN_MASK BIT(1)
> +#define DA9150_GPIOC_ANAEN_SHIFT 2
> +#define DA9150_GPIOC_ANAEN_MASK BIT(2)
> +#define DA9150_GPIOD_ANAEN_SHIFT 3
> +#define DA9150_GPIOD_ANAEN_MASK BIT(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 BIT(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 BIT(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 BIT(0)
> +#define DA9150_GPIOB_PUPD_SHIFT 1
> +#define DA9150_GPIOB_PUPD_MASK BIT(1)
> +#define DA9150_GPIOC_PUPD_SHIFT 2
> +#define DA9150_GPIOC_PUPD_MASK BIT(2)
> +#define DA9150_GPIOD_PUPD_SHIFT 3
> +#define DA9150_GPIOD_PUPD_MASK BIT(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 BIT(7)
> +
> +/* DA9150_GPIO_CFG_C = 0x0F0 */
> +#define DA9150_GPI_V_SHIFT 0
> +#define DA9150_GPI_V_MASK BIT(0)
> +#define DA9150_VDDIO_INT_SHIFT 1
> +#define DA9150_VDDIO_INT_MASK BIT(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 BIT(6)
> +#define DA9150_NIRQ_PUPD_SHIFT 7
> +#define DA9150_NIRQ_PUPD_MASK BIT(7)
> +
> +/* DA9150_GPADC_MAN = 0x0F2 */
> +#define DA9150_GPADC_EN_SHIFT 0
> +#define DA9150_GPADC_EN_MASK BIT(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 BIT(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 BIT(6)
> +#define DA9150_REVERT_SHIFT 7
> +#define DA9150_REVERT_MASK BIT(7)
> +
> +/* DA9150_OTP_CONT_SHARED = 0x101 */
> +#define DA9150_PC_DONE_SHIFT 3
> +#define DA9150_PC_DONE_MASK BIT(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 BIT(1)
> +#define DA9150_NIRQ_PIN_SHIFT 2
> +#define DA9150_NIRQ_PIN_MASK BIT(2)
> +#define DA9150_NIRQ_TYPE_SHIFT 3
> +#define DA9150_NIRQ_TYPE_MASK BIT(3)
> +#define DA9150_PM_IF_V_SHIFT 4
> +#define DA9150_PM_IF_V_MASK BIT(4)
> +#define DA9150_PM_IF_FMP_SHIFT 5
> +#define DA9150_PM_IF_FMP_MASK BIT(5)
> +#define DA9150_PM_IF_HSM_SHIFT 6
> +#define DA9150_PM_IF_HSM_MASK BIT(6)
> +
> +/* DA9150_CONFIG_D_SHARED = 0x109 */
> +#define DA9150_NIRQ_MODE_SHIFT 1
> +#define DA9150_NIRQ_MODE_MASK BIT(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 BIT(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 BIT(5)
> +#define DA9150_DM_STAT_SHIFT 6
> +#define DA9150_DM_STAT_MASK BIT(6)
> +
> +/* DA9150_ADET_CMPSTAT = 0x152 */
> +#define DA9150_DP_COMP_SHIFT 1
> +#define DA9150_DP_COMP_MASK BIT(1)
> +#define DA9150_DM_COMP_SHIFT 2
> +#define DA9150_DM_COMP_MASK BIT(2)
> +#define DA9150_ADP_SNS_COMP_SHIFT 3
> +#define DA9150_ADP_SNS_COMP_MASK BIT(3)
> +#define DA9150_ADP_PRB_COMP_SHIFT 4
> +#define DA9150_ADP_PRB_COMP_MASK BIT(4)
> +#define DA9150_ID_COMP_SHIFT 5
> +#define DA9150_ID_COMP_MASK BIT(5)
> +
> +/* DA9150_ADET_CTRL_A = 0x153 */
> +#define DA9150_AID_DAT_SHIFT 0
> +#define DA9150_AID_DAT_MASK BIT(0)
> +#define DA9150_AID_ID_SHIFT 1
> +#define DA9150_AID_ID_MASK BIT(1)
> +#define DA9150_AID_TRIG_SHIFT 2
> +#define DA9150_AID_TRIG_MASK BIT(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 BIT(0)
> +
> +#define DA9150_TADP_PRB_SHIFT 2
> +#define DA9150_TADP_PRB_MASK BIT(2)
> +#define DA9150_DAT_RPD_EXT_SHIFT 5
> +#define DA9150_DAT_RPD_EXT_MASK BIT(5)
> +#define DA9150_CONF_RPD_SHIFT 6
> +#define DA9150_CONF_RPD_MASK BIT(6)
> +#define DA9150_CONF_SRP_SHIFT 7
> +#define DA9150_CONF_SRP_MASK BIT(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 BIT(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 BIT(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 BIT(5)
> +#define DA9150_CONF_GPIOB_SHIFT 6
> +#define DA9150_CONF_GPIOB_MASK BIT(6)
> +#define DA9150_AID_VB_SHIFT 7
> +#define DA9150_AID_VB_MASK BIT(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 BIT(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 BIT(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 BIT(6)
> +#define DA9150_DAT_CLAMP_EXT_SHIFT 7
> +#define DA9150_DAT_CLAMP_EXT_MASK BIT(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 BIT(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 BIT(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 BIT(4)
> +#define DA9150_VBUS_PWM_SHIFT 5
> +#define DA9150_VBUS_PWM_MASK BIT(5)
> +#define DA9150_VBUS_ISO_SHIFT 6
> +#define DA9150_VBUS_ISO_MASK BIT(6)
> +#define DA9150_VBUS_LDO_SHIFT 7
> +#define DA9150_VBUS_LDO_MASK BIT(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 BIT(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 BIT(6)
> +#define DA9150_OTG_FAULT_DIS_SHIFT 7
> +#define DA9150_OTG_FAULT_DIS_MASK BIT(7)
> +
> +/* DA9150_PPR_CHGCTRL_A = 0x166 */
> +#define DA9150_CHG_EN_SHIFT 0
> +#define DA9150_CHG_EN_MASK BIT(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 BIT(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 BIT(6)
> +#define DA9150_TBAT_TDP_EN_SHIFT 7
> +#define DA9150_TBAT_TDP_EN_MASK BIT(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 BIT(5)
> +#define DA9150_CHG_NBLO_SHIFT 6
> +#define DA9150_CHG_NBLO_MASK BIT(6)
> +#define DA9150_EBS_EN_SHIFT 7
> +#define DA9150_EBS_EN_MASK BIT(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 BIT(6)
> +#define DA9150_REVERT_SHIFT 7
> +#define DA9150_REVERT_MASK BIT(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 BIT(6)
> +#define DA9150_REVERT_SHIFT 7
> +#define DA9150_REVERT_MASK BIT(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 BIT(6)
> +#define DA9150_REVERT_SHIFT 7
> +#define DA9150_REVERT_MASK BIT(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 BIT(6)
> +#define DA9150_REVERT_SHIFT 7
> +#define DA9150_REVERT_MASK BIT(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 BIT(2)
> +
> +/* DA9150_COREBTLD_CTRL_A = 0x303 */
> +#define DA9150_CORE_RESET_SHIFT 0
> +#define DA9150_CORE_RESET_MASK BIT(0)
> +#define DA9150_CORE_STOP_SHIFT 1
> +#define DA9150_CORE_STOP_MASK BIT(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 BIT(2)
> +#define DA9150_WDT_AUTO_LOCK_SHIFT 3
> +#define DA9150_WDT_AUTO_LOCK_MASK BIT(3)
> +#define DA9150_WDT_HLT_NO_CLK_SHIFT 4
> +#define DA9150_WDT_HLT_NO_CLK_MASK BIT(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 BIT(0)
> +#define DA9150_CORE_EN_SHIFT 2
> +#define DA9150_CORE_EN_MASK BIT(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 BIT(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 BIT(7)
> +
> +/* DA9150_CORE2WIRE_CTRL_A = 0x311 */
> +#define DA9150_FW_FWDL_EN_SHIFT 0
> +#define DA9150_FW_FWDL_EN_MASK BIT(0)
> +#define DA9150_FG_QIF_EN_SHIFT 1
> +#define DA9150_FG_QIF_EN_MASK BIT(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 BIT(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 BIT(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 BIT(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 BIT(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 BIT(0)
> +#define DA9150_TAUX_MOD_SHIFT 1
> +#define DA9150_TAUX_MOD_MASK BIT(1)
> +#define DA9150_TAUX_UPDATE_SHIFT 2
> +#define DA9150_TAUX_UPDATE_MASK BIT(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 BIT(0)
> +
> +/* DA9150_TBAT_CTRL_A = 0x342 */
> +#define DA9150_TBAT_EN_SHIFT 0
> +#define DA9150_TBAT_EN_MASK BIT(0)
> +#define DA9150_TBAT_SW1_SHIFT 1
> +#define DA9150_TBAT_SW1_MASK BIT(1)
> +#define DA9150_TBAT_SW2_SHIFT 2
> +#define DA9150_TBAT_SW2_MASK BIT(2)
> +
> +/* DA9150_TBAT_CTRL_B = 0x343 */
> +#define DA9150_TBAT_SW_FRC_SHIFT 0
> +#define DA9150_TBAT_SW_FRC_MASK BIT(0)
> +#define DA9150_TBAT_STAT_SW1_SHIFT 1
> +#define DA9150_TBAT_STAT_SW1_MASK BIT(1)
> +#define DA9150_TBAT_STAT_SW2_SHIFT 2
> +#define DA9150_TBAT_STAT_SW2_MASK BIT(2)
> +#define DA9150_TBAT_HIGH_CURR_SHIFT 3
> +#define DA9150_TBAT_HIGH_CURR_MASK BIT(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 BIT(0)
> +#define DA9150_TBAT_RES_L_SHIFT 6
> +#define DA9150_TBAT_RES_L_MASK (0x03 << 6)
> +
> +#endif /* __DA9150_REGISTERS_H */
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 2/8] mfd: da9150: Add DT binding documentation for core
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
2014-09-23 10:53 ` [PATCH 1/8] mfd: Add support for DA9150 combined charger & fuel-gauge device Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-27 10:36 ` Jonathan Cameron
2014-09-23 10:53 ` [PATCH 3/8] iio: Add support for DA9150 GPADC Adam Thomson
` (5 subsequent siblings)
7 siblings, 1 reply; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
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] 22+ messages in thread
* Re: [PATCH 2/8] mfd: da9150: Add DT binding documentation for core
2014-09-23 10:53 ` [PATCH 2/8] mfd: da9150: Add DT binding documentation for core Adam Thomson
@ 2014-09-27 10:36 ` Jonathan Cameron
2014-10-07 13:47 ` Opensource [Adam Thomson]
0 siblings, 1 reply; 22+ messages in thread
From: Jonathan Cameron @ 2014-09-27 10:36 UTC (permalink / raw)
To: Adam Thomson, Lee Jones, Samuel Ortiz, linux-iio,
Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
On 23/09/14 11:53, Adam Thomson wrote:
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
Obviously this really wants a review from one of the device tree guys, but I
have a few
bits based on what Mark has recently said in other reviews ;)
> ---
> 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):
What does I2C only add to the description?
> +
> +Device Description
> +------ -----------
> +da9150-gpadc : IIO - GPADC
Given usual aversion to anything driver specific in the device tree description
you probably
just want to describe what they do rather than what subsystem provides the driver.
> +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.
Cross refer to the standard interrupts doc for these...
> +- 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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 2/8] mfd: da9150: Add DT binding documentation for core
2014-09-27 10:36 ` Jonathan Cameron
@ 2014-10-07 13:47 ` Opensource [Adam Thomson]
0 siblings, 0 replies; 22+ messages in thread
From: Opensource [Adam Thomson] @ 2014-10-07 13:47 UTC (permalink / raw)
To: Jonathan Cameron, Opensource [Adam Thomson], Lee Jones,
Samuel Ortiz, linux-iio@vger.kernel.org, Sebastian Reichel,
Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm@vger.kernel.org, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Grant Likely,
devicetree@vger.kernel.org, Andrew Morton, Joe Perches,
linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Support Opensource
T24gU2VwdGVtYmVyIDI3LCAyMDE0IDExOjM3LCBKb25hdGhhbiBDYW1lcm9uIHdyb3RlOg0KDQo+
IE9uIDIzLzA5LzE0IDExOjUzLCBBZGFtIFRob21zb24gd3JvdGU6DQo+ID4gU2lnbmVkLW9mZi1i
eTogQWRhbSBUaG9tc29uIDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNvbT4NCj4g
T2J2aW91c2x5IHRoaXMgcmVhbGx5IHdhbnRzIGEgcmV2aWV3IGZyb20gb25lIG9mIHRoZSBkZXZp
Y2UgdHJlZSBndXlzLCBidXQgSQ0KPiBoYXZlIGEgZmV3DQo+IGJpdHMgYmFzZWQgb24gd2hhdCBN
YXJrIGhhcyByZWNlbnRseSBzYWlkIGluIG90aGVyIHJldmlld3MgOykNCj4gPiAtLS0NCj4gPiAg
RG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL21mZC9kYTkxNTAudHh0IHwgNDENCj4g
KysrKysrKysrKysrKysrKysrKysrKysrDQo+ID4gIDEgZmlsZSBjaGFuZ2VkLCA0MSBpbnNlcnRp
b25zKCspDQo+ID4gIGNyZWF0ZSBtb2RlIDEwMDY0NCBEb2N1bWVudGF0aW9uL2RldmljZXRyZWUv
YmluZGluZ3MvbWZkL2RhOTE1MC50eHQNCj4gPg0KPiA+IGRpZmYgLS1naXQgYS9Eb2N1bWVudGF0
aW9uL2RldmljZXRyZWUvYmluZGluZ3MvbWZkL2RhOTE1MC50eHQNCj4gYi9Eb2N1bWVudGF0aW9u
L2RldmljZXRyZWUvYmluZGluZ3MvbWZkL2RhOTE1MC50eHQNCj4gPiBuZXcgZmlsZSBtb2RlIDEw
MDY0NA0KPiA+IGluZGV4IDAwMDAwMDAuLmQ3ZGUxNTANCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4g
KysrIGIvRG9jdW1lbnRhdGlvbi9kZXZpY2V0cmVlL2JpbmRpbmdzL21mZC9kYTkxNTAudHh0DQo+
ID4gQEAgLTAsMCArMSw0MSBAQA0KPiA+ICtEaWFsb2cgU2VtaWNvbmR1Y3RvciBEQTkxNTAgQ29t
YmluZWQgQ2hhcmdlci9GdWVsLUdhdWdlIE1GRCBiaW5kaW5ncw0KPiA+ICsNCj4gPiArREE5MTUw
IGNvbnNpc3RzIG9mIGEgZ3JvdXAgb2Ygc3ViLWRldmljZXMgKEkyQyBPbmx5KToNCj4gV2hhdCBk
b2VzIEkyQyBvbmx5IGFkZCB0byB0aGUgZGVzY3JpcHRpb24/DQoNCk5vdGhpbmcgcmVhbGx5LiBX
aWxsIHJlbW92ZS4NCg0KPiA+ICsNCj4gPiArRGV2aWNlCQkJIERlc2NyaXB0aW9uDQo+ID4gKy0t
LS0tLQkJCSAtLS0tLS0tLS0tLQ0KPiA+ICtkYTkxNTAtZ3BhZGMJCTogSUlPIC0gR1BBREMNCj4g
R2l2ZW4gdXN1YWwgYXZlcnNpb24gdG8gYW55dGhpbmcgZHJpdmVyIHNwZWNpZmljIGluIHRoZSBk
ZXZpY2UgdHJlZSBkZXNjcmlwdGlvbg0KPiB5b3UgcHJvYmFibHkNCj4ganVzdCB3YW50IHRvIGRl
c2NyaWJlIHdoYXQgdGhleSBkbyByYXRoZXIgdGhhbiB3aGF0IHN1YnN5c3RlbSBwcm92aWRlcyB0
aGUgZHJpdmVyLg0KDQpPaywgY2FuIHVwZGF0ZSBhY2NvcmRpbmdseS4NCg0KPiANCj4gPiArZGE5
MTUwLWNoYXJnZXIJCTogUG93ZXIgU3VwcGx5IChDaGFyZ2VyKQ0KPiA+ICsNCj4gPiArPT09PT09
DQo+ID4gKw0KPiA+ICtSZXF1aXJlZCBwcm9wZXJ0aWVzOg0KPiA+ICstIGNvbXBhdGlibGUgOiBT
aG91bGQgYmUgImRsZyxkYTkxNTAiDQo+ID4gKy0gcmVnOiBTcGVjaWZpZXMgdGhlIEkyQyBzbGF2
ZSBhZGRyZXNzDQo+ID4gKy0gaW50ZXJydXB0LXBhcmVudDogU3BlY2lmaWVzIHRoZSBwaGFuZGxl
IG9mIHRoZSBpbnRlcnJ1cHQgY29udHJvbGxlciB0byB3aGljaA0KPiA+ICsgIHRoZSBJUlFzIGZy
b20gZGE5MTUwIGFyZSBkZWxpdmVyZWQgdG8uDQo+ID4gKy0gaW50ZXJydXB0czogSVJRIGxpbmUg
aW5mbyBmb3IgZGE5MTUwIGNoaXAuDQo+IENyb3NzIHJlZmVyIHRvIHRoZSBzdGFuZGFyZCBpbnRl
cnJ1cHRzIGRvYyBmb3IgdGhlc2UuLi4NCj4gDQoNCk9rLCBjYW4gZG8gdGhhdC4NCg0KPiA+ICst
IGludGVycnVwdC1jb250cm9sbGVyOiBkYTkxNTAgaGFzIGludGVybmFsIElSUXMgKG93biBJUlEg
ZG9tYWluKS4NCj4gPiArDQo+ID4gK1N1Yi1kZXZpY2VzOg0KPiA+ICstIGRhOTE1MC1ncGFkYzog
U2VlIERvY3VtZW50YXRpb24vZGV2aWNldHJlZS9iaW5kaW5ncy9paW8vYWRjL2RhOTE1MC0NCj4g
Z3BhZGMudHh0DQo+ID4gKy0gZGE5MTUwLWNoYXJnZXI6IFNlZSBEb2N1bWVudGF0aW9uL2Rldmlj
ZXRyZWUvYmluZGluZ3MvcG93ZXIvZGE5MTUwLQ0KPiBjaGFyZ2VyLnR4dA0KPiA+ICsNCj4gPiAr
DQo+ID4gK0V4YW1wbGU6DQo+ID4gKw0KPiA+ICsJY2hhcmdlcl9mZzogZGE5MTUwQDU4IHsNCj4g
PiArCQljb21wYXRpYmxlID0gImRsZyxkYTkxNTAiOw0KPiA+ICsJCXJlZyA9IDwweDU4PjsNCj4g
PiArCQlpbnRlcnJ1cHQtcGFyZW50ID0gPCZncGlvNj47DQo+ID4gKwkJaW50ZXJydXB0cyA9IDwx
MSBJUlFfVFlQRV9MRVZFTF9MT1c+Ow0KPiA+ICsJCWludGVycnVwdC1jb250cm9sbGVyOw0KPiA+
ICsNCj4gPiArCQlncGFkYzogZGE5MTUwLWdwYWRjIHsNCj4gPiArCQkJLi4uDQo+ID4gKwkJfTsN
Cj4gPiArDQo+ID4gKwkJZGE5MTUwLWNoYXJnZXIgew0KPiA+ICsJCQkuLi4NCj4gPiArCQl9Ow0K
PiA+ICsJfTsNCj4gPiAtLQ0KPiA+IDEuOS4zDQo+ID4NCj4gPiAtLQ0KPiA+IFRvIHVuc3Vic2Ny
aWJlIGZyb20gdGhpcyBsaXN0OiBzZW5kIHRoZSBsaW5lICJ1bnN1YnNjcmliZSBsaW51eC1paW8i
IGluDQo+ID4gdGhlIGJvZHkgb2YgYSBtZXNzYWdlIHRvIG1ham9yZG9tb0B2Z2VyLmtlcm5lbC5v
cmcNCj4gPiBNb3JlIG1ham9yZG9tbyBpbmZvIGF0ICBodHRwOi8vdmdlci5rZXJuZWwub3JnL21h
am9yZG9tby1pbmZvLmh0bWwNCj4gPg0K
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 3/8] iio: Add support for DA9150 GPADC
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
2014-09-23 10:53 ` [PATCH 1/8] mfd: Add support for DA9150 combined charger & fuel-gauge device Adam Thomson
2014-09-23 10:53 ` [PATCH 2/8] mfd: da9150: Add DT binding documentation for core Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-27 10:49 ` Jonathan Cameron
2014-10-11 22:47 ` Hartmut Knaack
2014-09-23 10:53 ` [PATCH 4/8] iio: da9150: Add DT binding documentation for GPADC Adam Thomson
` (4 subsequent siblings)
7 siblings, 2 replies; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
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 | 406 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 416 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..2b83ee0
--- /dev/null
+++ b/drivers/iio/adc/da9150-gpadc.c
@@ -0,0 +1,406 @@
+/*
+ * 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/mutex.h>
+#include <linux/completion.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/registers.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_6V,
+ DA9150_GPADC_HW_CHAN_GPIOA_6V_,
+ DA9150_GPADC_HW_CHAN_GPIOB_6V,
+ DA9150_GPADC_HW_CHAN_GPIOB_6V_,
+ DA9150_GPADC_HW_CHAN_GPIOC_6V,
+ DA9150_GPADC_HW_CHAN_GPIOC_6V_,
+ DA9150_GPADC_HW_CHAN_GPIOD_6V,
+ DA9150_GPADC_HW_CHAN_GPIOD_6V_,
+ 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;
+}
+
+static 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 GPADC\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_6v_voltage_now(int raw_val)
+{
+ /* Convert to mV */
+ return (6 * ((raw_val * 1000) + 500)) / 1024;
+}
+
+static inline int da9150_gpadc_ibus_current_avg(int raw_val)
+{
+ /* Convert to mA */
+ return (4 * ((raw_val * 1000) + 500)) / 2048;
+}
+
+static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
+{
+ /* Convert to mV */
+ return (21 * ((raw_val * 1000) + 500)) / 1024;
+}
+
+static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
+{
+ /* Convert to mV */
+ return (3 * ((raw_val * 1000) + 500)) / 512;
+}
+
+static int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
+ int hw_chan, int *val)
+{
+ int raw_val;
+
+ 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:
+ *val = da9150_gpadc_gpio_6v_voltage_now(raw_val);
+ break;
+ case DA9150_GPADC_CHAN_IBUS:
+ *val = da9150_gpadc_ibus_current_avg(raw_val);
+ break;
+ case DA9150_GPADC_CHAN_VBUS:
+ *val = da9150_gpadc_vbus_21v_voltage_now(raw_val);
+ break;
+ case DA9150_GPADC_CHAN_VSYS:
+ *val = da9150_gpadc_vsys_6v_voltage_now(raw_val);
+ break;
+ default:
+ /* No processing for other channels so return raw value */
+ *val = raw_val;
+ break;
+ }
+
+ return IIO_VAL_INT;
+}
+
+static int da9150_gpadc_read_scale(int channel, int *val, int *val2)
+{
+ switch (channel) {
+ case DA9150_GPADC_CHAN_VBAT:
+ *val = 2932;
+ *val2 = 1000;
+ return IIO_VAL_FRACTIONAL;
+ case DA9150_GPADC_CHAN_TJUNC_CORE:
+ case DA9150_GPADC_CHAN_TJUNC_OVP:
+ *val = 1000000;
+ *val2 = 4420;
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int da9150_gpadc_read_offset(int channel, int *val)
+{
+ switch (channel) {
+ case DA9150_GPADC_CHAN_VBAT:
+ *val = 1500000 / 2932;
+ return IIO_VAL_INT;
+ case DA9150_GPADC_CHAN_TJUNC_CORE:
+ case DA9150_GPADC_CHAN_TJUNC_OVP:
+ *val = -144;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static 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);
+
+ 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:
+ return da9150_gpadc_read_processed(gpadc, chan->channel,
+ chan->address, val);
+ case IIO_CHAN_INFO_SCALE:
+ return da9150_gpadc_read_scale(chan->channel, val, val2);
+ case IIO_CHAN_INFO_OFFSET:
+ return da9150_gpadc_read_offset(chan->channel, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info da9150_gpadc_info = {
+ .read_raw = &da9150_gpadc_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#define DA9150_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 DA9150_GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name) \
+ DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
+ BIT(IIO_CHAN_INFO_RAW), _ext_name)
+
+#define DA9150_GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name) \
+ DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
+ BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_OFFSET), \
+ _ext_name)
+
+#define DA9150_GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name) \
+ DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
+ BIT(IIO_CHAN_INFO_PROCESSED), _ext_name)
+
+/* Supported channels */
+static const struct iio_chan_spec da9150_gpadc_channels[] = {
+ DA9150_GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_6V, IIO_VOLTAGE, "GPIOA"),
+ DA9150_GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_6V, IIO_VOLTAGE, "GPIOB"),
+ DA9150_GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_6V, IIO_VOLTAGE, "GPIOC"),
+ DA9150_GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_6V, IIO_VOLTAGE, "GPIOD"),
+ DA9150_GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
+ DA9150_GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
+ DA9150_GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
+ DA9150_GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
+ DA9150_GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
+ DA9150_GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
+ DA9150_GPADC_CHANNEL_SCALED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP,
+ "TJUNC_CORE"),
+ DA9150_GPADC_CHANNEL_SCALED(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 irq, 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);
+ return ret;
+ }
+
+ mutex_init(&gpadc->lock);
+ init_completion(&gpadc->complete);
+
+ irq = platform_get_irq_byname(pdev, "GPADC");
+ ret = devm_request_threaded_irq(dev, irq, NULL, da9150_gpadc_irq,
+ IRQF_ONESHOT, "GPADC", gpadc);
+ if (ret) {
+ dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret);
+ goto iio_map_unreg;
+ }
+
+ 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_map_unreg;
+ }
+
+ return 0;
+
+iio_map_unreg:
+ iio_map_array_unregister(indio_dev);
+
+ 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",
+ },
+ .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] 22+ messages in thread
* Re: [PATCH 3/8] iio: Add support for DA9150 GPADC
2014-09-23 10:53 ` [PATCH 3/8] iio: Add support for DA9150 GPADC Adam Thomson
@ 2014-09-27 10:49 ` Jonathan Cameron
2014-10-07 14:55 ` Opensource [Adam Thomson]
2014-10-11 22:47 ` Hartmut Knaack
1 sibling, 1 reply; 22+ messages in thread
From: Jonathan Cameron @ 2014-09-27 10:49 UTC (permalink / raw)
To: Adam Thomson, Lee Jones, Samuel Ortiz, linux-iio,
Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
On 23/09/14 11:53, Adam Thomson wrote:
> This patch adds support for DA9150 Charger & Fuel-Gauge IC GPADC.
>
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
Very nearly there although I still would prefer all channels to use
(raw + offset) * scale and let userspace or in kernel conversion functions
handle it.
> ---
> drivers/iio/adc/Kconfig | 9 +
> drivers/iio/adc/Makefile | 1 +
> drivers/iio/adc/da9150-gpadc.c | 406 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 416 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..2b83ee0
> --- /dev/null
> +++ b/drivers/iio/adc/da9150-gpadc.c
> @@ -0,0 +1,406 @@
> +/*
> + * 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/mutex.h>
> +#include <linux/completion.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/machine.h>
> +#include <linux/iio/driver.h>
> +#include <linux/mfd/da9150/core.h>
> +#include <linux/mfd/da9150/registers.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_6V,
> + DA9150_GPADC_HW_CHAN_GPIOA_6V_,
> + DA9150_GPADC_HW_CHAN_GPIOB_6V,
> + DA9150_GPADC_HW_CHAN_GPIOB_6V_,
> + DA9150_GPADC_HW_CHAN_GPIOC_6V,
> + DA9150_GPADC_HW_CHAN_GPIOC_6V_,
> + DA9150_GPADC_HW_CHAN_GPIOD_6V,
> + DA9150_GPADC_HW_CHAN_GPIOD_6V_,
> + 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;
> +}
> +
> +static 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 GPADC\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_6v_voltage_now(int raw_val)
> +{
> + /* Convert to mV */
> + return (6 * ((raw_val * 1000) + 500)) / 1024;
These could all be expressed as raw values with offsets
and scales (and that would be preferred).
E.g. This one has offset 500000 and scale 6000/1024 or even
better use IIO_VAL_FRACTIONAL_LOG2 for scale with val1 = 6000
and val2 = (log_2 1024) = 10.
> +}
> +
> +static inline int da9150_gpadc_ibus_current_avg(int raw_val)
> +{
> + /* Convert to mA */
> + return (4 * ((raw_val * 1000) + 500)) / 2048;
> +}
> +
> +static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
> +{
> + /* Convert to mV */
> + return (21 * ((raw_val * 1000) + 500)) / 1024;
> +}
> +
> +static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
> +{
> + /* Convert to mV */
> + return (3 * ((raw_val * 1000) + 500)) / 512;
> +}
> +
> +static int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
> + int hw_chan, int *val)
> +{
> + int raw_val;
> +
> + 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:
> + *val = da9150_gpadc_gpio_6v_voltage_now(raw_val);
> + break;
> + case DA9150_GPADC_CHAN_IBUS:
> + *val = da9150_gpadc_ibus_current_avg(raw_val);
> + break;
> + case DA9150_GPADC_CHAN_VBUS:
> + *val = da9150_gpadc_vbus_21v_voltage_now(raw_val);
> + break;
> + case DA9150_GPADC_CHAN_VSYS:
> + *val = da9150_gpadc_vsys_6v_voltage_now(raw_val);
> + break;
> + default:
> + /* No processing for other channels so return raw value */
> + *val = raw_val;
> + break;
> + }
> +
> + return IIO_VAL_INT;
> +}
> +
> +static int da9150_gpadc_read_scale(int channel, int *val, int *val2)
> +{
> + switch (channel) {
> + case DA9150_GPADC_CHAN_VBAT:
> + *val = 2932;
> + *val2 = 1000;
> + return IIO_VAL_FRACTIONAL;
> + case DA9150_GPADC_CHAN_TJUNC_CORE:
> + case DA9150_GPADC_CHAN_TJUNC_OVP:
> + *val = 1000000;
> + *val2 = 4420;
> + return IIO_VAL_FRACTIONAL;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int da9150_gpadc_read_offset(int channel, int *val)
> +{
> + switch (channel) {
> + case DA9150_GPADC_CHAN_VBAT:
> + *val = 1500000 / 2932;
> + return IIO_VAL_INT;
> + case DA9150_GPADC_CHAN_TJUNC_CORE:
> + case DA9150_GPADC_CHAN_TJUNC_OVP:
> + *val = -144;
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static 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);
> +
> + 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:
> + return da9150_gpadc_read_processed(gpadc, chan->channel,
> + chan->address, val);
> + case IIO_CHAN_INFO_SCALE:
> + return da9150_gpadc_read_scale(chan->channel, val, val2);
> + case IIO_CHAN_INFO_OFFSET:
> + return da9150_gpadc_read_offset(chan->channel, val);
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static const struct iio_info da9150_gpadc_info = {
> + .read_raw = &da9150_gpadc_read_raw,
> + .driver_module = THIS_MODULE,
> +};
> +
> +#define DA9150_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 DA9150_GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name) \
> + DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
> + BIT(IIO_CHAN_INFO_RAW), _ext_name)
> +
> +#define DA9150_GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name) \
> + DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
> + BIT(IIO_CHAN_INFO_RAW) | \
> + BIT(IIO_CHAN_INFO_SCALE) | \
> + BIT(IIO_CHAN_INFO_OFFSET), \
> + _ext_name)
> +
> +#define DA9150_GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name) \
> + DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
> + BIT(IIO_CHAN_INFO_PROCESSED), _ext_name)
> +
> +/* Supported channels */
> +static const struct iio_chan_spec da9150_gpadc_channels[] = {
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_6V, IIO_VOLTAGE, "GPIOA"),
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_6V, IIO_VOLTAGE, "GPIOB"),
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_6V, IIO_VOLTAGE, "GPIOC"),
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_6V, IIO_VOLTAGE, "GPIOD"),
> + DA9150_GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
> + DA9150_GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
> + DA9150_GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
> + DA9150_GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
> + DA9150_GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
> + DA9150_GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
> + DA9150_GPADC_CHANNEL_SCALED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP,
> + "TJUNC_CORE"),
> + DA9150_GPADC_CHANNEL_SCALED(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 irq, 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);
> + return ret;
> + }
I'd suggest doing the devm_request_thread_irq before the iio_map_array
stuff. This is purely to avoid the order during remove not being
obviously correct as it isn't the reverse of during probe.
> +
> + mutex_init(&gpadc->lock);
> + init_completion(&gpadc->complete);
> +
> + irq = platform_get_irq_byname(pdev, "GPADC");
> + ret = devm_request_threaded_irq(dev, irq, NULL, da9150_gpadc_irq,
> + IRQF_ONESHOT, "GPADC", gpadc);
> + if (ret) {
> + dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret);
> + goto iio_map_unreg;
> + }
> +
> + 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_map_unreg;
> + }
> +
> + return 0;
> +
> +iio_map_unreg:
> + iio_map_array_unregister(indio_dev);
> +
> + 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);
Twice in one day. I'm definitely thinking we should add a
devm version of iio_map_array_register...
> + iio_device_unregister(indio_dev);
> +
> + return 0;
> +}
> +
> +static struct platform_driver da9150_gpadc_driver = {
> + .driver = {
> + .name = "da9150-gpadc",
> + },
> + .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-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 3/8] iio: Add support for DA9150 GPADC
2014-09-27 10:49 ` Jonathan Cameron
@ 2014-10-07 14:55 ` Opensource [Adam Thomson]
2014-10-07 19:36 ` Jonathan Cameron
0 siblings, 1 reply; 22+ messages in thread
From: Opensource [Adam Thomson] @ 2014-10-07 14:55 UTC (permalink / raw)
To: Jonathan Cameron, Opensource [Adam Thomson], Lee Jones,
Samuel Ortiz, linux-iio@vger.kernel.org, Sebastian Reichel,
Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm@vger.kernel.org, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Grant Likely,
devicetree@vger.kernel.org, Andrew Morton, Joe Perches,
linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Support Opensource
T24gU2VwdGVtYmVyIDI3LCAyMDE0IDExOjUwLCBKb25hdGhhbiBDYW1lcm9uIHdyb3RlOg0KDQo+
IE9uIDIzLzA5LzE0IDExOjUzLCBBZGFtIFRob21zb24gd3JvdGU6DQo+ID4gVGhpcyBwYXRjaCBh
ZGRzIHN1cHBvcnQgZm9yIERBOTE1MCBDaGFyZ2VyICYgRnVlbC1HYXVnZSBJQyBHUEFEQy4NCg0K
PiA+ICsNCj4gPiArc3RhdGljIGlubGluZSBpbnQgZGE5MTUwX2dwYWRjX2dwaW9fNnZfdm9sdGFn
ZV9ub3coaW50IHJhd192YWwpDQo+ID4gK3sNCj4gPiArCS8qIENvbnZlcnQgdG8gbVYgKi8NCj4g
PiArCXJldHVybiAoNiAqICgocmF3X3ZhbCAqIDEwMDApICsgNTAwKSkgLyAxMDI0Ow0KPiBUaGVz
ZSBjb3VsZCBhbGwgYmUgZXhwcmVzc2VkIGFzIHJhdyB2YWx1ZXMgd2l0aCBvZmZzZXRzDQo+IGFu
ZCBzY2FsZXMgKGFuZCB0aGF0IHdvdWxkIGJlIHByZWZlcnJlZCkuDQo+IEUuZy4gVGhpcyBvbmUg
aGFzIG9mZnNldCA1MDAwMDAgYW5kIHNjYWxlIDYwMDAvMTAyNCBvciBldmVuDQo+IGJldHRlciB1
c2UgSUlPX1ZBTF9GUkFDVElPTkFMX0xPRzIgZm9yIHNjYWxlIHdpdGggdmFsMSA9IDYwMDANCj4g
YW5kIHZhbDIgPSAobG9nXzIgMTAyNCkgPSAxMC4NCj4gDQoNCldoYXQgeW91J3ZlIHN1Z2dlc3Rl
ZCBpc24ndCBjb3JyZWN0LiBUaGUgcHJvYmxlbSBoZXJlIGlzIHRoYXQgdGhlIG9mZnNldCBpcw0K
YWRkZWQgZmlyc3QgdG8gdGhlIHJhdyBBREMgcmVhZGluZywgd2l0aG91dCBmYWN0b3JpbmcgdGhl
IEFEQyB2YWx1ZSBhY2NvcmRpbmdseQ0KdG8gbWF0Y2ggdGhlIGZhY3RvciBvZiB0aGUgb2Zmc2V0
LiBJZiB3ZSB0YWtlIHRoZSBvcmlnaW5hbCBlcXVhdGlvbiBwcm92aWRlZCBmb3INCnRoaXMgY2hh
bm5lbCBvZiB0aGUgQURDLCB0aGUgb2Zmc2V0IGlzIGFjdHVhbGx5IDAuNSB3aGljaCBzaG91bGQg
YmUgYWRkZWQgdG8gdGhlDQpyYXcgQURDIHZhbHVlLiBUaGlzIGRvZXNuJ3QgZml0IGludG8gdGhl
IGltcGxlbWVudGF0aW9uIGluIHRoZSBrZXJuZWwgYXMgd2UNCmNhbid0IHVzZSBmbG9hdGluZyBw
b2ludC4gSWYgd2UgbXVsdGlwbHkgdGhlIG9mZnNldCBidXQgbm90IHRoZSByYXcgQURDIHZhbHVl
LA0KdGhlbiBhZGQgdGhlbSBiZWZvcmUgYXBwbHlpbmcgdGhlIHNjYWxlIGZhY3RvciwgdGhlbiB0
aGUgcmVzdWx0IGlzIHdyb25nIGF0IHRoZQ0KZW5kLiBCYXNpY2FsbHkgeW91IG5lZWQgYSBzY2Fs
ZSBmb3IgdGhlIHJhdyBBREMgdmFsdWUgdG8gbWF0Y2ggdGhlIG9mZnNldCBzY2FsZQ0Kc28geW91
IGNhbiBhY2hpZXZlIHRoZSBjb3JyZWN0IHJlc3VsdHMsIHdoaWNoIGlzIHdoYXQgbXkgY2FsY3Vs
YXRpb24gZG9lcy4NCkJ1dCB0aGF0IHNlZW1zIGltcG9zc2libGUgd2l0aCB0aGUgY3VycmVudCBy
YXd8b2Zmc2V0fHNjYWxlIG1ldGhvZC4NCg0KPiA+ICsJcmV0ID0gaWlvX21hcF9hcnJheV9yZWdp
c3RlcihpbmRpb19kZXYsIGRhOTE1MF9ncGFkY19kZWZhdWx0X21hcHMpOw0KPiA+ICsJaWYgKHJl
dCkgew0KPiA+ICsJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIHJlZ2lzdGVyIElJTyBtYXBzOiAl
ZFxuIiwgcmV0KTsNCj4gPiArCQlyZXR1cm4gcmV0Ow0KPiA+ICsJfQ0KPiBJJ2Qgc3VnZ2VzdCBk
b2luZyB0aGUgZGV2bV9yZXF1ZXN0X3RocmVhZF9pcnEgYmVmb3JlIHRoZSBpaW9fbWFwX2FycmF5
DQo+IHN0dWZmLiAgVGhpcyBpcyBwdXJlbHkgdG8gYXZvaWQgdGhlIG9yZGVyIGR1cmluZyByZW1v
dmUgbm90IGJlaW5nDQo+IG9idmlvdXNseSBjb3JyZWN0IGFzIGl0IGlzbid0IHRoZSByZXZlcnNl
IG9mIGR1cmluZyBwcm9iZS4NCg0KT2ssIHNob3VsZCBzdGlsbCB3b3JrIG9rIHRoYXQgd2F5IHNv
IGNhbiB1cGRhdGUuDQoNCj4gPiArc3RhdGljIGludCBkYTkxNTBfZ3BhZGNfcmVtb3ZlKHN0cnVj
dCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpDQo+ID4gK3sNCj4gPiArCXN0cnVjdCBpaW9fZGV2ICpp
bmRpb19kZXYgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsNCj4gPiArDQo+ID4gKwlpaW9f
bWFwX2FycmF5X3VucmVnaXN0ZXIoaW5kaW9fZGV2KTsNCj4gVHdpY2UgaW4gb25lIGRheS4gIEkn
bSBkZWZpbml0ZWx5IHRoaW5raW5nIHdlIHNob3VsZCBhZGQgYQ0KPiBkZXZtIHZlcnNpb24gb2Yg
aWlvX21hcF9hcnJheV9yZWdpc3Rlci4uLg0KDQpJIGFzc3VtZSB5b3UgbWVhbiBoZXJlIHRoYXQg
aWlvX2RldmljZV91bnJlZ2lzdGVyKCkgc2hvdWxkIGNvbWUgZmlyc3Q/IFdpbGwNCnVwZGF0ZS4N
Cg==
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 3/8] iio: Add support for DA9150 GPADC
2014-10-07 14:55 ` Opensource [Adam Thomson]
@ 2014-10-07 19:36 ` Jonathan Cameron
2014-10-09 14:29 ` Opensource [Adam Thomson]
0 siblings, 1 reply; 22+ messages in thread
From: Jonathan Cameron @ 2014-10-07 19:36 UTC (permalink / raw)
To: Opensource [Adam Thomson], Lee Jones, Samuel Ortiz,
linux-iio@vger.kernel.org, Sebastian Reichel,
Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm@vger.kernel.org, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Grant Likely,
devicetree@vger.kernel.org, Andrew Morton, Joe Perches,
linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Support Opensource
On October 7, 2014 3:55:55 PM GMT+01:00, "Opensource [Adam Thomson]" <Adam.Thomson.Opensource@diasemi.com> wrote:
>On September 27, 2014 11:50, Jonathan Cameron wrote:
>
>> On 23/09/14 11:53, Adam Thomson wrote:
>> > This patch adds support for DA9150 Charger & Fuel-Gauge IC GPADC.
>
>> > +
>> > +static inline int da9150_gpadc_gpio_6v_voltage_now(int raw_val)
>> > +{
>> > + /* Convert to mV */
>> > + return (6 * ((raw_val * 1000) + 500)) / 1024;
>> These could all be expressed as raw values with offsets
>> and scales (and that would be preferred).
>> E.g. This one has offset 500000 and scale 6000/1024 or even
>> better use IIO_VAL_FRACTIONAL_LOG2 for scale with val1 = 6000
>> and val2 = (log_2 1024) = 10.
>>
>
>What you've suggested isn't correct. The problem here is that the
>offset is
>added first to the raw ADC reading, without factoring the ADC value
>accordingly
>to match the factor of the offset. If we take the original equation
>provided for
>this channel of the ADC, the offset is actually 0.5 which should be
>added to the
>raw ADC value. This doesn't fit into the implementation in the kernel
>as we
>can't use floating point. If we multiply the offset but not the raw ADC
>value,
>then add them before applying the scale factor, then the result is
>wrong at the
>end. Basically you need a scale for the raw ADC value to match the
>offset scale
>so you can achieve the correct results, which is what my calculation
>does.
>But that seems impossible with the current raw|offset|scale method.
Oops got that wrong. The fixed point maths to fix the in kernel interface isn't exactly
difficult but indeed it does not handle this currently.
>
>> > + ret = iio_map_array_register(indio_dev,
>da9150_gpadc_default_maps);
>> > + if (ret) {
>> > + dev_err(dev, "Failed to register IIO maps: %d\n", ret);
>> > + return ret;
>> > + }
>> I'd suggest doing the devm_request_thread_irq before the
>iio_map_array
>> stuff. This is purely to avoid the order during remove not being
>> obviously correct as it isn't the reverse of during probe.
>
>Ok, should still work ok that way so can update.
>
>> > +static int da9150_gpadc_remove(struct platform_device *pdev)
>> > +{
>> > + struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> > +
>> > + iio_map_array_unregister(indio_dev);
>> Twice in one day. I'm definitely thinking we should add a
>> devm version of iio_map_array_register...
>
>I assume you mean here that iio_device_unregister() should come first?
>Will
>update.
Nope just that such a new function might be useful.
--
Sent from my Android phone with K-9 Mail. Please excuse my brevity.
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 3/8] iio: Add support for DA9150 GPADC
2014-10-07 19:36 ` Jonathan Cameron
@ 2014-10-09 14:29 ` Opensource [Adam Thomson]
0 siblings, 0 replies; 22+ messages in thread
From: Opensource [Adam Thomson] @ 2014-10-09 14:29 UTC (permalink / raw)
To: Jonathan Cameron, Opensource [Adam Thomson], Lee Jones,
Samuel Ortiz, linux-iio@vger.kernel.org, Sebastian Reichel,
Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm@vger.kernel.org, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Grant Likely,
devicetree@vger.kernel.org, Andrew Morton, Joe Perches,
linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Support Opensource
T24gT2N0b2JlciA3LCAyMDE0IDIwOjM3LCBKb25hdGhhbiBDYW1lcm9uIHdyb3RlOg0KDQo+IE9u
IE9jdG9iZXIgNywgMjAxNCAzOjU1OjU1IFBNIEdNVCswMTowMCwgIk9wZW5zb3VyY2UgW0FkYW0g
VGhvbXNvbl0iDQo+IDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1pLmNvbT4gd3JvdGU6
DQo+ID5PbiBTZXB0ZW1iZXIgMjcsIDIwMTQgMTE6NTAsIEpvbmF0aGFuIENhbWVyb24gd3JvdGU6
DQo+ID4NCj4gPj4gT24gMjMvMDkvMTQgMTE6NTMsIEFkYW0gVGhvbXNvbiB3cm90ZToNCj4gPj4g
PiBUaGlzIHBhdGNoIGFkZHMgc3VwcG9ydCBmb3IgREE5MTUwIENoYXJnZXIgJiBGdWVsLUdhdWdl
IElDIEdQQURDLg0KPiA+DQo+ID4+ID4gKw0KPiA+PiA+ICtzdGF0aWMgaW5saW5lIGludCBkYTkx
NTBfZ3BhZGNfZ3Bpb182dl92b2x0YWdlX25vdyhpbnQgcmF3X3ZhbCkNCj4gPj4gPiArew0KPiA+
PiA+ICsJLyogQ29udmVydCB0byBtViAqLw0KPiA+PiA+ICsJcmV0dXJuICg2ICogKChyYXdfdmFs
ICogMTAwMCkgKyA1MDApKSAvIDEwMjQ7DQo+ID4+IFRoZXNlIGNvdWxkIGFsbCBiZSBleHByZXNz
ZWQgYXMgcmF3IHZhbHVlcyB3aXRoIG9mZnNldHMNCj4gPj4gYW5kIHNjYWxlcyAoYW5kIHRoYXQg
d291bGQgYmUgcHJlZmVycmVkKS4NCj4gPj4gRS5nLiBUaGlzIG9uZSBoYXMgb2Zmc2V0IDUwMDAw
MCBhbmQgc2NhbGUgNjAwMC8xMDI0IG9yIGV2ZW4NCj4gPj4gYmV0dGVyIHVzZSBJSU9fVkFMX0ZS
QUNUSU9OQUxfTE9HMiBmb3Igc2NhbGUgd2l0aCB2YWwxID0gNjAwMA0KPiA+PiBhbmQgdmFsMiA9
IChsb2dfMiAxMDI0KSA9IDEwLg0KPiA+Pg0KPiA+DQo+ID5XaGF0IHlvdSd2ZSBzdWdnZXN0ZWQg
aXNuJ3QgY29ycmVjdC4gVGhlIHByb2JsZW0gaGVyZSBpcyB0aGF0IHRoZQ0KPiA+b2Zmc2V0IGlz
DQo+ID5hZGRlZCBmaXJzdCB0byB0aGUgcmF3IEFEQyByZWFkaW5nLCB3aXRob3V0IGZhY3Rvcmlu
ZyB0aGUgQURDIHZhbHVlDQo+ID5hY2NvcmRpbmdseQ0KPiA+dG8gbWF0Y2ggdGhlIGZhY3RvciBv
ZiB0aGUgb2Zmc2V0LiBJZiB3ZSB0YWtlIHRoZSBvcmlnaW5hbCBlcXVhdGlvbg0KPiA+cHJvdmlk
ZWQgZm9yDQo+ID50aGlzIGNoYW5uZWwgb2YgdGhlIEFEQywgdGhlIG9mZnNldCBpcyBhY3R1YWxs
eSAwLjUgd2hpY2ggc2hvdWxkIGJlDQo+ID5hZGRlZCB0byB0aGUNCj4gPnJhdyBBREMgdmFsdWUu
IFRoaXMgZG9lc24ndCBmaXQgaW50byB0aGUgaW1wbGVtZW50YXRpb24gaW4gdGhlIGtlcm5lbA0K
PiA+YXMgd2UNCj4gPmNhbid0IHVzZSBmbG9hdGluZyBwb2ludC4gSWYgd2UgbXVsdGlwbHkgdGhl
IG9mZnNldCBidXQgbm90IHRoZSByYXcgQURDDQo+ID52YWx1ZSwNCj4gPnRoZW4gYWRkIHRoZW0g
YmVmb3JlIGFwcGx5aW5nIHRoZSBzY2FsZSBmYWN0b3IsIHRoZW4gdGhlIHJlc3VsdCBpcw0KPiA+
d3JvbmcgYXQgdGhlDQo+ID5lbmQuIEJhc2ljYWxseSB5b3UgbmVlZCBhIHNjYWxlIGZvciB0aGUg
cmF3IEFEQyB2YWx1ZSB0byBtYXRjaCB0aGUNCj4gPm9mZnNldCBzY2FsZQ0KPiA+c28geW91IGNh
biBhY2hpZXZlIHRoZSBjb3JyZWN0IHJlc3VsdHMsIHdoaWNoIGlzIHdoYXQgbXkgY2FsY3VsYXRp
b24NCj4gPmRvZXMuDQo+ID5CdXQgdGhhdCBzZWVtcyBpbXBvc3NpYmxlIHdpdGggdGhlIGN1cnJl
bnQgcmF3fG9mZnNldHxzY2FsZSBtZXRob2QuDQo+IE9vcHMgZ290IHRoYXQgd3JvbmcuICBUaGUg
Zml4ZWQgcG9pbnQgbWF0aHMgdG8gZml4IHRoZSBpbiBrZXJuZWwgaW50ZXJmYWNlIGlzbid0IGV4
YWN0bHkNCj4gIGRpZmZpY3VsdCBidXQgaW5kZWVkIGl0IGRvZXMgbm90IGhhbmRsZSB0aGlzIGN1
cnJlbnRseS4NCg0KSSBkaWQgaGF2ZSBhIHF1aWNrIGxvb2sgd2hlbiBJIGhhZCBhIHNwYXJlIG1v
bWVudCwgYW5kIEkgZ3Vlc3MgeW91IGNvdWxkIGRvDQpzb21ldGhpbmcgbGlrZSBoYXZpbmcgYW4g
b2Zmc2V0IHNjYWxlL2ZhY3RvciB3aGljaCBjYW4gYmUgYXBwbGllZCB0byB0aGUgcmF3DQpyZWFk
aW5nLCBwcmlvciB0byBhZGRpbmcgdGhlIG9mZnNldC4gTWF5IGJlIGFuIG9wdGlvbiBidXQgSSB0
aGluayB0aGlzIHdvdWxkDQphbHNvIGhhdmUgdG8gYmUgZXhwb3NlZCB0byB1c2VyLXNwYWNlIGFz
IEkgYmVsaWV2ZSB0aGUgc2FtZSBwcm9ibGVtIHdvdWxkIHJlc2lkZQ0KdGhlcmUgYXMgd2VsbC4N
Cg0KPiA+DQo+ID4+ID4gKwlyZXQgPSBpaW9fbWFwX2FycmF5X3JlZ2lzdGVyKGluZGlvX2RldiwN
Cj4gPmRhOTE1MF9ncGFkY19kZWZhdWx0X21hcHMpOw0KPiA+PiA+ICsJaWYgKHJldCkgew0KPiA+
PiA+ICsJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIHJlZ2lzdGVyIElJTyBtYXBzOiAlZFxuIiwg
cmV0KTsNCj4gPj4gPiArCQlyZXR1cm4gcmV0Ow0KPiA+PiA+ICsJfQ0KPiA+PiBJJ2Qgc3VnZ2Vz
dCBkb2luZyB0aGUgZGV2bV9yZXF1ZXN0X3RocmVhZF9pcnEgYmVmb3JlIHRoZQ0KPiA+aWlvX21h
cF9hcnJheQ0KPiA+PiBzdHVmZi4gIFRoaXMgaXMgcHVyZWx5IHRvIGF2b2lkIHRoZSBvcmRlciBk
dXJpbmcgcmVtb3ZlIG5vdCBiZWluZw0KPiA+PiBvYnZpb3VzbHkgY29ycmVjdCBhcyBpdCBpc24n
dCB0aGUgcmV2ZXJzZSBvZiBkdXJpbmcgcHJvYmUuDQo+ID4NCj4gPk9rLCBzaG91bGQgc3RpbGwg
d29yayBvayB0aGF0IHdheSBzbyBjYW4gdXBkYXRlLg0KPiA+DQo+ID4+ID4gK3N0YXRpYyBpbnQg
ZGE5MTUwX2dwYWRjX3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1fZGV2aWNlICpwZGV2KQ0KPiA+PiA+
ICt7DQo+ID4+ID4gKwlzdHJ1Y3QgaWlvX2RldiAqaW5kaW9fZGV2ID0gcGxhdGZvcm1fZ2V0X2Ry
dmRhdGEocGRldik7DQo+ID4+ID4gKw0KPiA+PiA+ICsJaWlvX21hcF9hcnJheV91bnJlZ2lzdGVy
KGluZGlvX2Rldik7DQo+ID4+IFR3aWNlIGluIG9uZSBkYXkuICBJJ20gZGVmaW5pdGVseSB0aGlu
a2luZyB3ZSBzaG91bGQgYWRkIGENCj4gPj4gZGV2bSB2ZXJzaW9uIG9mIGlpb19tYXBfYXJyYXlf
cmVnaXN0ZXIuLi4NCj4gPg0KPiA+SSBhc3N1bWUgeW91IG1lYW4gaGVyZSB0aGF0IGlpb19kZXZp
Y2VfdW5yZWdpc3RlcigpIHNob3VsZCBjb21lIGZpcnN0Pw0KPiA+V2lsbA0KPiA+dXBkYXRlLg0K
PiBOb3BlIGp1c3QgdGhhdCBzdWNoIGEgbmV3IGZ1bmN0aW9uIG1pZ2h0IGJlIHVzZWZ1bC4NCg0K
OikgT2sgZmFpciBlbm91Z2guDQoNCj4gDQo+IC0tDQo+IFNlbnQgZnJvbSBteSBBbmRyb2lkIHBo
b25lIHdpdGggSy05IE1haWwuIFBsZWFzZSBleGN1c2UgbXkgYnJldml0eS4NCg==
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 3/8] iio: Add support for DA9150 GPADC
2014-09-23 10:53 ` [PATCH 3/8] iio: Add support for DA9150 GPADC Adam Thomson
2014-09-27 10:49 ` Jonathan Cameron
@ 2014-10-11 22:47 ` Hartmut Knaack
2014-10-15 10:34 ` Opensource [Adam Thomson]
1 sibling, 1 reply; 22+ messages in thread
From: Hartmut Knaack @ 2014-10-11 22: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, Grant Likely, devicetree, Andrew Morton,
Joe Perches, linux-api
Cc: linux-kernel, support.opensource
Hi,
I have put a few comments inline.
Adam Thomson schrieb am 23.09.2014 12:53:
> 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 | 406 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 416 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..2b83ee0
> --- /dev/null
> +++ b/drivers/iio/adc/da9150-gpadc.c
> @@ -0,0 +1,406 @@
> +/*
> + * 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/mutex.h>
> +#include <linux/completion.h>
> +#include <linux/iio/iio.h>
> +#include <linux/iio/machine.h>
> +#include <linux/iio/driver.h>
> +#include <linux/mfd/da9150/core.h>
> +#include <linux/mfd/da9150/registers.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_6V,
> + DA9150_GPADC_HW_CHAN_GPIOA_6V_,
> + DA9150_GPADC_HW_CHAN_GPIOB_6V,
> + DA9150_GPADC_HW_CHAN_GPIOB_6V_,
> + DA9150_GPADC_HW_CHAN_GPIOC_6V,
> + DA9150_GPADC_HW_CHAN_GPIOC_6V_,
> + DA9150_GPADC_HW_CHAN_GPIOD_6V,
> + DA9150_GPADC_HW_CHAN_GPIOD_6V_,
> + 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;
> +}
> +
> +static 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 GPADC\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_6v_voltage_now(int raw_val)
> +{
> + /* Convert to mV */
> + return (6 * ((raw_val * 1000) + 500)) / 1024;
> +}
> +
> +static inline int da9150_gpadc_ibus_current_avg(int raw_val)
> +{
> + /* Convert to mA */
> + return (4 * ((raw_val * 1000) + 500)) / 2048;
> +}
> +
> +static inline int da9150_gpadc_vbus_21v_voltage_now(int raw_val)
> +{
> + /* Convert to mV */
> + return (21 * ((raw_val * 1000) + 500)) / 1024;
> +}
> +
> +static inline int da9150_gpadc_vsys_6v_voltage_now(int raw_val)
> +{
> + /* Convert to mV */
> + return (3 * ((raw_val * 1000) + 500)) / 512;
> +}
> +
> +static int da9150_gpadc_read_processed(struct da9150_gpadc *gpadc, int channel,
> + int hw_chan, int *val)
> +{
> + int raw_val;
> +
> + 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:
> + *val = da9150_gpadc_gpio_6v_voltage_now(raw_val);
> + break;
> + case DA9150_GPADC_CHAN_IBUS:
> + *val = da9150_gpadc_ibus_current_avg(raw_val);
> + break;
> + case DA9150_GPADC_CHAN_VBUS:
> + *val = da9150_gpadc_vbus_21v_voltage_now(raw_val);
> + break;
> + case DA9150_GPADC_CHAN_VSYS:
> + *val = da9150_gpadc_vsys_6v_voltage_now(raw_val);
> + break;
> + default:
> + /* No processing for other channels so return raw value */
> + *val = raw_val;
> + break;
> + }
> +
> + return IIO_VAL_INT;
> +}
> +
> +static int da9150_gpadc_read_scale(int channel, int *val, int *val2)
> +{
> + switch (channel) {
> + case DA9150_GPADC_CHAN_VBAT:
> + *val = 2932;
> + *val2 = 1000;
> + return IIO_VAL_FRACTIONAL;
> + case DA9150_GPADC_CHAN_TJUNC_CORE:
> + case DA9150_GPADC_CHAN_TJUNC_OVP:
> + *val = 1000000;
> + *val2 = 4420;
> + return IIO_VAL_FRACTIONAL;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int da9150_gpadc_read_offset(int channel, int *val)
> +{
> + switch (channel) {
> + case DA9150_GPADC_CHAN_VBAT:
> + *val = 1500000 / 2932;
> + return IIO_VAL_INT;
> + case DA9150_GPADC_CHAN_TJUNC_CORE:
> + case DA9150_GPADC_CHAN_TJUNC_OVP:
> + *val = -144;
> + return IIO_VAL_INT;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static 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);
> +
> + 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:
> + return da9150_gpadc_read_processed(gpadc, chan->channel,
> + chan->address, val);
> + case IIO_CHAN_INFO_SCALE:
> + return da9150_gpadc_read_scale(chan->channel, val, val2);
> + case IIO_CHAN_INFO_OFFSET:
> + return da9150_gpadc_read_offset(chan->channel, val);
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static const struct iio_info da9150_gpadc_info = {
> + .read_raw = &da9150_gpadc_read_raw,
> + .driver_module = THIS_MODULE,
> +};
> +
> +#define DA9150_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 DA9150_GPADC_CHANNEL_RAW(_id, _hw_id, _type, _ext_name) \
> + DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
> + BIT(IIO_CHAN_INFO_RAW), _ext_name)
> +
> +#define DA9150_GPADC_CHANNEL_SCALED(_id, _hw_id, _type, _ext_name) \
> + DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
> + BIT(IIO_CHAN_INFO_RAW) | \
> + BIT(IIO_CHAN_INFO_SCALE) | \
> + BIT(IIO_CHAN_INFO_OFFSET), \
> + _ext_name)
> +
> +#define DA9150_GPADC_CHANNEL_PROCESSED(_id, _hw_id, _type, _ext_name) \
> + DA9150_GPADC_CHANNEL(_id, _hw_id, _type, \
> + BIT(IIO_CHAN_INFO_PROCESSED), _ext_name)
> +
> +/* Supported channels */
> +static const struct iio_chan_spec da9150_gpadc_channels[] = {
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOA, GPIOA_6V, IIO_VOLTAGE, "GPIOA"),
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOB, GPIOB_6V, IIO_VOLTAGE, "GPIOB"),
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOC, GPIOC_6V, IIO_VOLTAGE, "GPIOC"),
> + DA9150_GPADC_CHANNEL_PROCESSED(GPIOD, GPIOD_6V, IIO_VOLTAGE, "GPIOD"),
> + DA9150_GPADC_CHANNEL_PROCESSED(IBUS, IBUS_SENSE, IIO_CURRENT, "IBUS"),
> + DA9150_GPADC_CHANNEL_PROCESSED(VBUS, VBUS_DIV_, IIO_VOLTAGE, "VBUS"),
> + DA9150_GPADC_CHANNEL_RAW(ID, ID, IIO_VOLTAGE, "ID"),
> + DA9150_GPADC_CHANNEL_PROCESSED(VSYS, VSYS, IIO_VOLTAGE, "VSYS"),
> + DA9150_GPADC_CHANNEL_SCALED(VBAT, VBAT, IIO_VOLTAGE, "VBAT"),
> + DA9150_GPADC_CHANNEL_RAW(TBAT, TBAT, IIO_VOLTAGE, "TBAT"),
> + DA9150_GPADC_CHANNEL_SCALED(TJUNC_CORE, TJUNC_CORE, IIO_TEMP,
> + "TJUNC_CORE"),
> + DA9150_GPADC_CHANNEL_SCALED(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);
Maybe you could find a slightly different name for the instance of this da9150 than its type name.
> + struct da9150_gpadc *gpadc;
> + struct iio_dev *indio_dev;
> + int irq, 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);
> + return ret;
> + }
> +
> + mutex_init(&gpadc->lock);
> + init_completion(&gpadc->complete);
> +
> + irq = platform_get_irq_byname(pdev, "GPADC");
Shouldn't you check irq for possible error codes? devm_request_threaded_irq() expects irq to be unsigned.
> + ret = devm_request_threaded_irq(dev, irq, NULL, da9150_gpadc_irq,
> + IRQF_ONESHOT, "GPADC", gpadc);
> + if (ret) {
> + dev_err(dev, "Failed to request IRQ %d: %d\n", irq, ret);
> + goto iio_map_unreg;
> + }
> +
> + 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_map_unreg;
> + }
> +
> + return 0;
> +
> +iio_map_unreg:
> + iio_map_array_unregister(indio_dev);
> +
> + 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);
Not sure if that was the intention of Jonathans comment, but these unregister calls should be switched to be in proper reverse order.
> +
> + return 0;
> +}
> +
> +static struct platform_driver da9150_gpadc_driver = {
> + .driver = {
> + .name = "da9150-gpadc",
> + },
> + .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");
You are missing a > at the end of your email-address.
> +MODULE_LICENSE("GPL");
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* RE: [PATCH 3/8] iio: Add support for DA9150 GPADC
2014-10-11 22:47 ` Hartmut Knaack
@ 2014-10-15 10:34 ` Opensource [Adam Thomson]
0 siblings, 0 replies; 22+ messages in thread
From: Opensource [Adam Thomson] @ 2014-10-15 10:34 UTC (permalink / raw)
To: Hartmut Knaack, Opensource [Adam Thomson], Lee Jones,
Samuel Ortiz, Jonathan Cameron, linux-iio@vger.kernel.org,
Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm@vger.kernel.org, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Grant Likely,
devicetree@vger.kernel.org, Andrew Morton, Joe Perches,
linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Support Opensource
T24gT2N0b2JlciAxMSwgMjAxNCAyMzo0OCwgSGFydG11dCBLbmFhY2sgd3JvdGU6DQoNCj4gSGks
DQo+IEkgaGF2ZSBwdXQgYSBmZXcgY29tbWVudHMgaW5saW5lLg0KPiANCj4gQWRhbSBUaG9tc29u
IHNjaHJpZWIgYW0gMjMuMDkuMjAxNCAxMjo1MzoNCj4gPiBUaGlzIHBhdGNoIGFkZHMgc3VwcG9y
dCBmb3IgREE5MTUwIENoYXJnZXIgJiBGdWVsLUdhdWdlIElDIEdQQURDLg0KPiA+DQo+ID4gU2ln
bmVkLW9mZi1ieTogQWRhbSBUaG9tc29uIDxBZGFtLlRob21zb24uT3BlbnNvdXJjZUBkaWFzZW1p
LmNvbT4NCj4gPiAtLS0NCj4gPiAgZHJpdmVycy9paW8vYWRjL0tjb25maWcgICAgICAgIHwgICA5
ICsNCj4gPiAgZHJpdmVycy9paW8vYWRjL01ha2VmaWxlICAgICAgIHwgICAxICsNCj4gPiAgZHJp
dmVycy9paW8vYWRjL2RhOTE1MC1ncGFkYy5jIHwgNDA2DQo+ICsrKysrKysrKysrKysrKysrKysr
KysrKysrKysrKysrKysrKysrKysrDQo+ID4gIDMgZmlsZXMgY2hhbmdlZCwgNDE2IGluc2VydGlv
bnMoKykNCj4gPiAgY3JlYXRlIG1vZGUgMTAwNjQ0IGRyaXZlcnMvaWlvL2FkYy9kYTkxNTAtZ3Bh
ZGMuYw0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvaWlvL2FkYy9LY29uZmlnIGIvZHJp
dmVycy9paW8vYWRjL0tjb25maWcNCj4gPiBpbmRleCAxMWIwNDhhLi44MDQxMzQ3IDEwMDY0NA0K
PiA+IC0tLSBhL2RyaXZlcnMvaWlvL2FkYy9LY29uZmlnDQo+ID4gKysrIGIvZHJpdmVycy9paW8v
YWRjL0tjb25maWcNCj4gPiBAQCAtMTI3LDYgKzEyNywxNSBAQCBjb25maWcgQVQ5MV9BREMNCj4g
PiAgCWhlbHANCj4gPiAgCSAgU2F5IHllcyBoZXJlIHRvIGJ1aWxkIHN1cHBvcnQgZm9yIEF0bWVs
IEFUOTEgQURDLg0KPiA+DQo+ID4gK2NvbmZpZyBEQTkxNTBfR1BBREMNCj4gPiArCXRyaXN0YXRl
ICJEaWFsb2cgREE5MTUwIEdQQURDIGRyaXZlciBzdXBwb3J0Ig0KPiA+ICsJZGVwZW5kcyBvbiBN
RkRfREE5MTUwDQo+ID4gKwloZWxwDQo+ID4gKwkgIFNheSB5ZXMgaGVyZSB0byBidWlsZCBzdXBw
b3J0IGZvciBEaWFsb2cgREE5MTUwIEdQQURDLg0KPiA+ICsNCj4gPiArCSAgVGhpcyBkcml2ZXIg
Y2FuIGFsc28gYmUgYnVpbHQgYXMgYSBtb2R1bGUuIElmIGNob3NlbiwgdGhlIG1vZHVsZSBuYW1l
DQo+ID4gKwkgIHdpbGwgYmUgZGE5MTUwLWdwYWRjLg0KPiA+ICsNCj4gPiAgY29uZmlnIEVYWU5P
U19BREMNCj4gPiAgCXRyaXN0YXRlICJFeHlub3MgQURDIGRyaXZlciBzdXBwb3J0Ig0KPiA+ICAJ
ZGVwZW5kcyBvbiBBUkNIX0VYWU5PUyB8fCAoT0YgJiYgQ09NUElMRV9URVNUKQ0KPiA+IGRpZmYg
LS1naXQgYS9kcml2ZXJzL2lpby9hZGMvTWFrZWZpbGUgYi9kcml2ZXJzL2lpby9hZGMvTWFrZWZp
bGUNCj4gPiBpbmRleCBhZDgxYjUxLi40ODQxM2QyIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMv
aWlvL2FkYy9NYWtlZmlsZQ0KPiA+ICsrKyBiL2RyaXZlcnMvaWlvL2FkYy9NYWtlZmlsZQ0KPiA+
IEBAIC0xNCw2ICsxNCw3IEBAIG9iai0kKENPTkZJR19BRDc3OTMpICs9IGFkNzc5My5vDQo+ID4g
IG9iai0kKENPTkZJR19BRDc4ODcpICs9IGFkNzg4Ny5vDQo+ID4gIG9iai0kKENPTkZJR19BRDc5
OVgpICs9IGFkNzk5eC5vDQo+ID4gIG9iai0kKENPTkZJR19BVDkxX0FEQykgKz0gYXQ5MV9hZGMu
bw0KPiA+ICtvYmotJChDT05GSUdfREE5MTUwX0dQQURDKSArPSBkYTkxNTAtZ3BhZGMubw0KPiA+
ICBvYmotJChDT05GSUdfRVhZTk9TX0FEQykgKz0gZXh5bm9zX2FkYy5vDQo+ID4gIG9iai0kKENP
TkZJR19MUDg3ODhfQURDKSArPSBscDg3ODhfYWRjLm8NCj4gPiAgb2JqLSQoQ09ORklHX01BWDEw
MjcpICs9IG1heDEwMjcubw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL2lpby9hZGMvZGE5MTUw
LWdwYWRjLmMgYi9kcml2ZXJzL2lpby9hZGMvZGE5MTUwLWdwYWRjLmMNCj4gPiBuZXcgZmlsZSBt
b2RlIDEwMDY0NA0KPiA+IGluZGV4IDAwMDAwMDAuLjJiODNlZTANCj4gPiAtLS0gL2Rldi9udWxs
DQo+ID4gKysrIGIvZHJpdmVycy9paW8vYWRjL2RhOTE1MC1ncGFkYy5jDQo+ID4gQEAgLTAsMCAr
MSw0MDYgQEANCj4gPiArLyoNCj4gPiArICogREE5MTUwIEdQQURDIERyaXZlcg0KPiA+ICsgKg0K
PiA+ICsgKiBDb3B5cmlnaHQgKGMpIDIwMTQgRGlhbG9nIFNlbWljb25kdWN0b3INCj4gPiArICoN
Cj4gPiArICogQXV0aG9yOiBBZGFtIFRob21zb24gPEFkYW0uVGhvbXNvbi5PcGVuc291cmNlQGRp
YXNlbWkuY29tPg0KPiA+ICsgKg0KPiA+ICsgKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2Fy
ZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgIGl0IGFuZC9vciBtb2RpZnkgaXQNCj4gPiArICogdW5k
ZXIgIHRoZSB0ZXJtcyBvZiAgdGhlIEdOVSBHZW5lcmFsICBQdWJsaWMgTGljZW5zZSBhcyBwdWJs
aXNoZWQgYnkgdGhlDQo+ID4gKyAqIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgIGVpdGhlciB2
ZXJzaW9uIDIgb2YgdGhlICBMaWNlbnNlLCBvciAoYXQgeW91cg0KPiA+ICsgKiBvcHRpb24pIGFu
eSBsYXRlciB2ZXJzaW9uLg0KPiA+ICsgKi8NCj4gPiArDQo+ID4gKyNpbmNsdWRlIDxsaW51eC9r
ZXJuZWwuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L3NsYWIuaD4NCj4gPiArI2luY2x1ZGUgPGxp
bnV4L21vZHVsZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcGxhdGZvcm1fZGV2aWNlLmg+DQo+
ID4gKyNpbmNsdWRlIDxsaW51eC9pbnRlcnJ1cHQuaD4NCj4gPiArI2luY2x1ZGUgPGxpbnV4L211
dGV4Lmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9jb21wbGV0aW9uLmg+DQo+ID4gKyNpbmNsdWRl
IDxsaW51eC9paW8vaWlvLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9paW8vbWFjaGluZS5oPg0K
PiA+ICsjaW5jbHVkZSA8bGludXgvaWlvL2RyaXZlci5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgv
bWZkL2RhOTE1MC9jb3JlLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9tZmQvZGE5MTUwL3JlZ2lz
dGVycy5oPg0KPiA+ICsNCj4gPiArLyogQ2hhbm5lbHMgKi8NCj4gPiArZW51bSBkYTkxNTBfZ3Bh
ZGNfaHdfY2hhbm5lbCB7DQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPQV8yViA9IDAs
DQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPQV8yVl8sDQo+ID4gKwlEQTkxNTBfR1BB
RENfSFdfQ0hBTl9HUElPQl8yViwNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9CXzJW
XywNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9DXzJWLA0KPiA+ICsJREE5MTUwX0dQ
QURDX0hXX0NIQU5fR1BJT0NfMlZfLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0Rf
MlYsDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPRF8yVl8sDQo+ID4gKwlEQTkxNTBf
R1BBRENfSFdfQ0hBTl9JQlVTX1NFTlNFLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fSUJV
U19TRU5TRV8sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9WQlVTX0RJViwNCj4gPiArCURB
OTE1MF9HUEFEQ19IV19DSEFOX1ZCVVNfRElWXywNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFO
X0lELA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fSURfLA0KPiA+ICsJREE5MTUwX0dQQURD
X0hXX0NIQU5fVlNZUywNCj4gPiArCURBOTE1MF9HUEFEQ19IV19DSEFOX1ZTWVNfLA0KPiA+ICsJ
REE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0FfNlYsDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hB
Tl9HUElPQV82Vl8sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9HUElPQl82ViwNCj4gPiAr
CURBOTE1MF9HUEFEQ19IV19DSEFOX0dQSU9CXzZWXywNCj4gPiArCURBOTE1MF9HUEFEQ19IV19D
SEFOX0dQSU9DXzZWLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0NfNlZfLA0KPiA+
ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fR1BJT0RfNlYsDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdf
Q0hBTl9HUElPRF82Vl8sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9WQkFULA0KPiA+ICsJ
REE5MTUwX0dQQURDX0hXX0NIQU5fVkJBVF8sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9U
QkFULA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fVEJBVF8sDQo+ID4gKwlEQTkxNTBfR1BB
RENfSFdfQ0hBTl9USlVOQ19DT1JFLA0KPiA+ICsJREE5MTUwX0dQQURDX0hXX0NIQU5fVEpVTkNf
Q09SRV8sDQo+ID4gKwlEQTkxNTBfR1BBRENfSFdfQ0hBTl9USlVOQ19PVlAsDQo+ID4gKwlEQTkx
NTBfR1BBRENfSFdfQ0hBTl9USlVOQ19PVlBfLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArZW51bSBk
YTkxNTBfZ3BhZGNfY2hhbm5lbCB7DQo+ID4gKwlEQTkxNTBfR1BBRENfQ0hBTl9HUElPQSA9IDAs
DQo+ID4gKwlEQTkxNTBfR1BBRENfQ0hBTl9HUElPQiwNCj4gPiArCURBOTE1MF9HUEFEQ19DSEFO
X0dQSU9DLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5fR1BJT0QsDQo+ID4gKwlEQTkxNTBfR1BB
RENfQ0hBTl9JQlVTLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5fVkJVUywNCj4gPiArCURBOTE1
MF9HUEFEQ19DSEFOX0lELA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5fVlNZUywNCj4gPiArCURB
OTE1MF9HUEFEQ19DSEFOX1ZCQVQsDQo+ID4gKwlEQTkxNTBfR1BBRENfQ0hBTl9UQkFULA0KPiA+
ICsJREE5MTUwX0dQQURDX0NIQU5fVEpVTkNfQ09SRSwNCj4gPiArCURBOTE1MF9HUEFEQ19DSEFO
X1RKVU5DX09WUCwNCj4gPiArfTsNCj4gPiArDQo+ID4gKy8qIFByaXZhdGUgZGF0YSAqLw0KPiA+
ICtzdHJ1Y3QgZGE5MTUwX2dwYWRjIHsNCj4gPiArCXN0cnVjdCBkYTkxNTAgKmRhOTE1MDsNCj4g
PiArCXN0cnVjdCBkZXZpY2UgKmRldjsNCj4gPiArDQo+ID4gKwlzdHJ1Y3QgbXV0ZXggbG9jazsN
Cj4gPiArCXN0cnVjdCBjb21wbGV0aW9uIGNvbXBsZXRlOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiAr
DQo+ID4gK3N0YXRpYyBpcnFyZXR1cm5fdCBkYTkxNTBfZ3BhZGNfaXJxKGludCBpcnEsIHZvaWQg
KmRhdGEpDQo+ID4gK3sNCj4gPiArDQo+ID4gKwlzdHJ1Y3QgZGE5MTUwX2dwYWRjICpncGFkYyA9
IGRhdGE7DQo+ID4gKw0KPiA+ICsJY29tcGxldGUoJmdwYWRjLT5jb21wbGV0ZSk7DQo+ID4gKw0K
PiA+ICsJcmV0dXJuIElSUV9IQU5ETEVEOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50
IGRhOTE1MF9ncGFkY19yZWFkX2FkYyhzdHJ1Y3QgZGE5MTUwX2dwYWRjICpncGFkYywgaW50IGh3
X2NoYW4pDQo+ID4gK3sNCj4gPiArCXU4IHJlc3VsdF9yZWdzWzJdOw0KPiA+ICsJaW50IHJlc3Vs
dDsNCj4gPiArDQo+ID4gKwltdXRleF9sb2NrKCZncGFkYy0+bG9jayk7DQo+ID4gKw0KPiA+ICsJ
LyogU2V0IGNoYW5uZWwgJiBlbmFibGUgbWVhc3VyZW1lbnQgKi8NCj4gPiArCWRhOTE1MF9yZWdf
d3JpdGUoZ3BhZGMtPmRhOTE1MCwgREE5MTUwX0dQQURDX01BTiwNCj4gPiArCQkJIChEQTkxNTBf
R1BBRENfRU5fTUFTSyB8DQo+ID4gKwkJCSAgaHdfY2hhbiA8PCBEQTkxNTBfR1BBRENfTVVYX1NI
SUZUKSk7DQo+ID4gKw0KPiA+ICsJLyogQ29uc3VtZSBsZWZ0LW92ZXIgY29tcGxldGlvbiBmcm9t
IGEgcHJldmlvdXMgdGltZW91dCAqLw0KPiA+ICsJdHJ5X3dhaXRfZm9yX2NvbXBsZXRpb24oJmdw
YWRjLT5jb21wbGV0ZSk7DQo+ID4gKw0KPiA+ICsJLyogQ2hlY2sgZm9yIGFjdHVhbCBjb21wbGV0
aW9uICovDQo+ID4gKwl3YWl0X2Zvcl9jb21wbGV0aW9uX3RpbWVvdXQoJmdwYWRjLT5jb21wbGV0
ZSwgbXNlY3NfdG9famlmZmllcyg1KSk7DQo+ID4gKw0KPiA+ICsJLyogUmVhZCByZXN1bHQgYW5k
IHN0YXR1cyBmcm9tIGRldmljZSAqLw0KPiA+ICsJZGE5MTUwX2J1bGtfcmVhZChncGFkYy0+ZGE5
MTUwLCBEQTkxNTBfR1BBRENfUkVTX0EsIDIsIHJlc3VsdF9yZWdzKTsNCj4gPiArDQo+ID4gKwlt
dXRleF91bmxvY2soJmdwYWRjLT5sb2NrKTsNCj4gPiArDQo+ID4gKwkvKiBDaGVjayB0byBtYWtl
IHN1cmUgZGV2aWNlIHJlYWxseSBoYXMgY29tcGxldGVkIHJlYWRpbmcgKi8NCj4gPiArCWlmIChy
ZXN1bHRfcmVnc1sxXSAmIERBOTE1MF9HUEFEQ19SVU5fTUFTSykgew0KPiA+ICsJCWRldl9lcnIo
Z3BhZGMtPmRldiwgIlRpbWVvdXQgb24gY2hhbm5lbCAlZCBvZiBHUEFEQ1xuIiwNCj4gPiArCQkJ
aHdfY2hhbik7DQo+ID4gKwkJcmV0dXJuIC1FVElNRURPVVQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+
ICsJLyogTFNCcyAtIDIgYml0cyAqLw0KPiA+ICsJcmVzdWx0ID0gKHJlc3VsdF9yZWdzWzFdICYg
REE5MTUwX0dQQURDX1JFU19MX01BU0spID4+DQo+ID4gKwkJIERBOTE1MF9HUEFEQ19SRVNfTF9T
SElGVDsNCj4gPiArCS8qIE1TQnMgLSA4IGJpdHMgKi8NCj4gPiArCXJlc3VsdCB8PSByZXN1bHRf
cmVnc1swXSA8PCBEQTkxNTBfR1BBRENfUkVTX0xfQklUUzsNCj4gPiArDQo+ID4gKwlyZXR1cm4g
cmVzdWx0Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW5saW5lIGludCBkYTkxNTBfZ3Bh
ZGNfZ3Bpb182dl92b2x0YWdlX25vdyhpbnQgcmF3X3ZhbCkNCj4gPiArew0KPiA+ICsJLyogQ29u
dmVydCB0byBtViAqLw0KPiA+ICsJcmV0dXJuICg2ICogKChyYXdfdmFsICogMTAwMCkgKyA1MDAp
KSAvIDEwMjQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1MF9n
cGFkY19pYnVzX2N1cnJlbnRfYXZnKGludCByYXdfdmFsKQ0KPiA+ICt7DQo+ID4gKwkvKiBDb252
ZXJ0IHRvIG1BICovDQo+ID4gKwlyZXR1cm4gKDQgKiAoKHJhd192YWwgKiAxMDAwKSArIDUwMCkp
IC8gMjA0ODsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGlubGluZSBpbnQgZGE5MTUwX2dw
YWRjX3ZidXNfMjF2X3ZvbHRhZ2Vfbm93KGludCByYXdfdmFsKQ0KPiA+ICt7DQo+ID4gKwkvKiBD
b252ZXJ0IHRvIG1WICovDQo+ID4gKwlyZXR1cm4gKDIxICogKChyYXdfdmFsICogMTAwMCkgKyA1
MDApKSAvIDEwMjQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbmxpbmUgaW50IGRhOTE1
MF9ncGFkY192c3lzXzZ2X3ZvbHRhZ2Vfbm93KGludCByYXdfdmFsKQ0KPiA+ICt7DQo+ID4gKwkv
KiBDb252ZXJ0IHRvIG1WICovDQo+ID4gKwlyZXR1cm4gKDMgKiAoKHJhd192YWwgKiAxMDAwKSAr
IDUwMCkpIC8gNTEyOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGRhOTE1MF9ncGFk
Y19yZWFkX3Byb2Nlc3NlZChzdHJ1Y3QgZGE5MTUwX2dwYWRjICpncGFkYywgaW50DQo+IGNoYW5u
ZWwsDQo+ID4gKwkJCQkgICAgICAgaW50IGh3X2NoYW4sIGludCAqdmFsKQ0KPiA+ICt7DQo+ID4g
KwlpbnQgcmF3X3ZhbDsNCj4gPiArDQo+ID4gKwlyYXdfdmFsID0gZGE5MTUwX2dwYWRjX3JlYWRf
YWRjKGdwYWRjLCBod19jaGFuKTsNCj4gPiArCWlmIChyYXdfdmFsIDwgMCkNCj4gPiArCQlyZXR1
cm4gcmF3X3ZhbDsNCj4gPiArDQo+ID4gKwlzd2l0Y2ggKGNoYW5uZWwpIHsNCj4gPiArCWNhc2Ug
REE5MTUwX0dQQURDX0NIQU5fR1BJT0E6DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19DSEFOX0dQ
SU9COg0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9HUElPQzoNCj4gPiArCWNhc2UgREE5
MTUwX0dQQURDX0NIQU5fR1BJT0Q6DQo+ID4gKwkJKnZhbCA9IGRhOTE1MF9ncGFkY19ncGlvXzZ2
X3ZvbHRhZ2Vfbm93KHJhd192YWwpOw0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJY2FzZSBEQTkxNTBf
R1BBRENfQ0hBTl9JQlVTOg0KPiA+ICsJCSp2YWwgPSBkYTkxNTBfZ3BhZGNfaWJ1c19jdXJyZW50
X2F2ZyhyYXdfdmFsKTsNCj4gPiArCQlicmVhazsNCj4gPiArCWNhc2UgREE5MTUwX0dQQURDX0NI
QU5fVkJVUzoNCj4gPiArCQkqdmFsID0gZGE5MTUwX2dwYWRjX3ZidXNfMjF2X3ZvbHRhZ2Vfbm93
KHJhd192YWwpOw0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJY2FzZSBEQTkxNTBfR1BBRENfQ0hBTl9W
U1lTOg0KPiA+ICsJCSp2YWwgPSBkYTkxNTBfZ3BhZGNfdnN5c182dl92b2x0YWdlX25vdyhyYXdf
dmFsKTsNCj4gPiArCQlicmVhazsNCj4gPiArCWRlZmF1bHQ6DQo+ID4gKwkJLyogTm8gcHJvY2Vz
c2luZyBmb3Igb3RoZXIgY2hhbm5lbHMgc28gcmV0dXJuIHJhdyB2YWx1ZSAqLw0KPiA+ICsJCSp2
YWwgPSByYXdfdmFsOw0KPiA+ICsJCWJyZWFrOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCXJldHVy
biBJSU9fVkFMX0lOVDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBkYTkxNTBfZ3Bh
ZGNfcmVhZF9zY2FsZShpbnQgY2hhbm5lbCwgaW50ICp2YWwsIGludCAqdmFsMikNCj4gPiArew0K
PiA+ICsJc3dpdGNoIChjaGFubmVsKSB7DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19DSEFOX1ZC
QVQ6DQo+ID4gKwkJKnZhbCA9IDI5MzI7DQo+ID4gKwkJKnZhbDIgPSAxMDAwOw0KPiA+ICsJCXJl
dHVybiBJSU9fVkFMX0ZSQUNUSU9OQUw7DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19DSEFOX1RK
VU5DX0NPUkU6DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19DSEFOX1RKVU5DX09WUDoNCj4gPiAr
CQkqdmFsID0gMTAwMDAwMDsNCj4gPiArCQkqdmFsMiA9IDQ0MjA7DQo+ID4gKwkJcmV0dXJuIElJ
T19WQUxfRlJBQ1RJT05BTDsNCj4gPiArCWRlZmF1bHQ6DQo+ID4gKwkJcmV0dXJuIC1FSU5WQUw7
DQo+ID4gKwl9DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgZGE5MTUwX2dwYWRjX3Jl
YWRfb2Zmc2V0KGludCBjaGFubmVsLCBpbnQgKnZhbCkNCj4gPiArew0KPiA+ICsJc3dpdGNoIChj
aGFubmVsKSB7DQo+ID4gKwljYXNlIERBOTE1MF9HUEFEQ19DSEFOX1ZCQVQ6DQo+ID4gKwkJKnZh
bCA9IDE1MDAwMDAgLyAyOTMyOw0KPiA+ICsJCXJldHVybiBJSU9fVkFMX0lOVDsNCj4gPiArCWNh
c2UgREE5MTUwX0dQQURDX0NIQU5fVEpVTkNfQ09SRToNCj4gPiArCWNhc2UgREE5MTUwX0dQQURD
X0NIQU5fVEpVTkNfT1ZQOg0KPiA+ICsJCSp2YWwgPSAtMTQ0Ow0KPiA+ICsJCXJldHVybiBJSU9f
VkFMX0lOVDsNCj4gPiArCWRlZmF1bHQ6DQo+ID4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ID4gKwl9
DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgZGE5MTUwX2dwYWRjX3JlYWRfcmF3KHN0
cnVjdCBpaW9fZGV2ICppbmRpb19kZXYsDQo+ID4gKwkJCQkgc3RydWN0IGlpb19jaGFuX3NwZWMg
Y29uc3QgKmNoYW4sDQo+ID4gKwkJCQkgaW50ICp2YWwsIGludCAqdmFsMiwgbG9uZyBtYXNrKQ0K
PiA+ICt7DQo+ID4gKwlzdHJ1Y3QgZGE5MTUwX2dwYWRjICpncGFkYyA9IGlpb19wcml2KGluZGlv
X2Rldik7DQo+ID4gKw0KPiA+ICsJaWYgKChjaGFuLT5jaGFubmVsIDwgREE5MTUwX0dQQURDX0NI
QU5fR1BJT0EpIHx8DQo+ID4gKwkgICAgKGNoYW4tPmNoYW5uZWwgPiBEQTkxNTBfR1BBRENfQ0hB
Tl9USlVOQ19PVlApKQ0KPiA+ICsJCXJldHVybiAtRUlOVkFMOw0KPiA+ICsNCj4gPiArCXN3aXRj
aCAobWFzaykgew0KPiA+ICsJY2FzZSBJSU9fQ0hBTl9JTkZPX1JBVzoNCj4gPiArCWNhc2UgSUlP
X0NIQU5fSU5GT19QUk9DRVNTRUQ6DQo+ID4gKwkJcmV0dXJuIGRhOTE1MF9ncGFkY19yZWFkX3By
b2Nlc3NlZChncGFkYywgY2hhbi0+Y2hhbm5lbCwNCj4gPiArCQkJCQkJICAgY2hhbi0+YWRkcmVz
cywgdmFsKTsNCj4gPiArCWNhc2UgSUlPX0NIQU5fSU5GT19TQ0FMRToNCj4gPiArCQlyZXR1cm4g
ZGE5MTUwX2dwYWRjX3JlYWRfc2NhbGUoY2hhbi0+Y2hhbm5lbCwgdmFsLCB2YWwyKTsNCj4gPiAr
CWNhc2UgSUlPX0NIQU5fSU5GT19PRkZTRVQ6DQo+ID4gKwkJcmV0dXJuIGRhOTE1MF9ncGFkY19y
ZWFkX29mZnNldChjaGFuLT5jaGFubmVsLCB2YWwpOw0KPiA+ICsJZGVmYXVsdDoNCj4gPiArCQly
ZXR1cm4gLUVJTlZBTDsNCj4gPiArCX0NCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGNvbnN0
IHN0cnVjdCBpaW9faW5mbyBkYTkxNTBfZ3BhZGNfaW5mbyA9IHsNCj4gPiArCS5yZWFkX3JhdyA9
ICZkYTkxNTBfZ3BhZGNfcmVhZF9yYXcsDQo+ID4gKwkuZHJpdmVyX21vZHVsZSA9IFRISVNfTU9E
VUxFLA0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArI2RlZmluZSBEQTkxNTBfR1BBRENfQ0hBTk5FTChf
aWQsIF9od19pZCwgX3R5cGUsIGNoYW5faW5mbywJXA0KPiA+ICsJCQkgICAgIF9leHRfbmFtZSkg
ewkJCVwNCj4gPiArCS50eXBlID0gX3R5cGUsCQkJCQkJXA0KPiA+ICsJLmluZGV4ZWQgPSAxLAkJ
CQkJCVwNCj4gPiArCS5jaGFubmVsID0gREE5MTUwX0dQQURDX0NIQU5fIyNfaWQsCQkJXA0KPiA+
ICsJLmFkZHJlc3MgPSBEQTkxNTBfR1BBRENfSFdfQ0hBTl8jI19od19pZCwJCVwNCj4gPiArCS5p
bmZvX21hc2tfc2VwYXJhdGUgPSBjaGFuX2luZm8sCQkJXA0KPiA+ICsJLmV4dGVuZF9uYW1lID0g
X2V4dF9uYW1lLAkJCQlcDQo+ID4gKwkuZGF0YXNoZWV0X25hbWUgPSAjX2lkLAkJCQkJXA0KPiA+
ICt9DQo+ID4gKw0KPiA+ICsjZGVmaW5lIERBOTE1MF9HUEFEQ19DSEFOTkVMX1JBVyhfaWQsIF9o
d19pZCwgX3R5cGUsIF9leHRfbmFtZSkJXA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5ORUwoX2lk
LCBfaHdfaWQsIF90eXBlLAkJXA0KPiA+ICsJCQkgICAgIEJJVChJSU9fQ0hBTl9JTkZPX1JBVyks
IF9leHRfbmFtZSkNCj4gPiArDQo+ID4gKyNkZWZpbmUgREE5MTUwX0dQQURDX0NIQU5ORUxfU0NB
TEVEKF9pZCwgX2h3X2lkLCBfdHlwZSwgX2V4dF9uYW1lKQlcDQo+ID4gKwlEQTkxNTBfR1BBRENf
Q0hBTk5FTChfaWQsIF9od19pZCwgX3R5cGUsCQkJXA0KPiA+ICsJCQkgICAgIEJJVChJSU9fQ0hB
Tl9JTkZPX1JBVykgfAkJCVwNCj4gPiArCQkJICAgICBCSVQoSUlPX0NIQU5fSU5GT19TQ0FMRSkg
fAkJCVwNCj4gPiArCQkJICAgICBCSVQoSUlPX0NIQU5fSU5GT19PRkZTRVQpLAkJCVwNCj4gPiAr
CQkJICAgICBfZXh0X25hbWUpDQo+ID4gKw0KPiA+ICsjZGVmaW5lIERBOTE1MF9HUEFEQ19DSEFO
TkVMX1BST0NFU1NFRChfaWQsIF9od19pZCwgX3R5cGUsIF9leHRfbmFtZSkNCj4gCVwNCj4gPiAr
CURBOTE1MF9HUEFEQ19DSEFOTkVMKF9pZCwgX2h3X2lkLCBfdHlwZSwJCQlcDQo+ID4gKwkJCSAg
ICAgQklUKElJT19DSEFOX0lORk9fUFJPQ0VTU0VEKSwgX2V4dF9uYW1lKQ0KPiA+ICsNCj4gPiAr
LyogU3VwcG9ydGVkIGNoYW5uZWxzICovDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1Y3QgaWlvX2No
YW5fc3BlYyBkYTkxNTBfZ3BhZGNfY2hhbm5lbHNbXSA9IHsNCj4gPiArCURBOTE1MF9HUEFEQ19D
SEFOTkVMX1BST0NFU1NFRChHUElPQSwgR1BJT0FfNlYsIElJT19WT0xUQUdFLA0KPiAiR1BJT0Ei
KSwNCj4gPiArCURBOTE1MF9HUEFEQ19DSEFOTkVMX1BST0NFU1NFRChHUElPQiwgR1BJT0JfNlYs
IElJT19WT0xUQUdFLA0KPiAiR1BJT0IiKSwNCj4gPiArCURBOTE1MF9HUEFEQ19DSEFOTkVMX1BS
T0NFU1NFRChHUElPQywgR1BJT0NfNlYsIElJT19WT0xUQUdFLA0KPiAiR1BJT0MiKSwNCj4gPiAr
CURBOTE1MF9HUEFEQ19DSEFOTkVMX1BST0NFU1NFRChHUElPRCwgR1BJT0RfNlYsIElJT19WT0xU
QUdFLA0KPiAiR1BJT0QiKSwNCj4gPiArCURBOTE1MF9HUEFEQ19DSEFOTkVMX1BST0NFU1NFRChJ
QlVTLCBJQlVTX1NFTlNFLCBJSU9fQ1VSUkVOVCwNCj4gIklCVVMiKSwNCj4gPiArCURBOTE1MF9H
UEFEQ19DSEFOTkVMX1BST0NFU1NFRChWQlVTLCBWQlVTX0RJVl8sIElJT19WT0xUQUdFLA0KPiAi
VkJVUyIpLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5ORUxfUkFXKElELCBJRCwgSUlPX1ZPTFRB
R0UsICJJRCIpLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5ORUxfUFJPQ0VTU0VEKFZTWVMsIFZT
WVMsIElJT19WT0xUQUdFLCAiVlNZUyIpLA0KPiA+ICsJREE5MTUwX0dQQURDX0NIQU5ORUxfU0NB
TEVEKFZCQVQsIFZCQVQsIElJT19WT0xUQUdFLCAiVkJBVCIpLA0KPiA+ICsJREE5MTUwX0dQQURD
X0NIQU5ORUxfUkFXKFRCQVQsIFRCQVQsIElJT19WT0xUQUdFLCAiVEJBVCIpLA0KPiA+ICsJREE5
MTUwX0dQQURDX0NIQU5ORUxfU0NBTEVEKFRKVU5DX0NPUkUsIFRKVU5DX0NPUkUsDQo+IElJT19U
RU1QLA0KPiA+ICsJCQkJICAgICJUSlVOQ19DT1JFIiksDQo+ID4gKwlEQTkxNTBfR1BBRENfQ0hB
Tk5FTF9TQ0FMRUQoVEpVTkNfT1ZQLCBUSlVOQ19PVlAsIElJT19URU1QLA0KPiA+ICsJCQkJICAg
ICJUSlVOQ19PVlAiKSwNCj4gPiArfTsNCj4gPiArDQo+ID4gKy8qIERlZmF1bHQgbWFwcyB1c2Vk
IGJ5IGRhOTE1MC1jaGFyZ2VyICovDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgaWlvX21hcCBkYTkxNTBf
Z3BhZGNfZGVmYXVsdF9tYXBzW10gPSB7DQo+ID4gKwl7DQo+ID4gKwkJLmNvbnN1bWVyX2Rldl9u
YW1lID0gImRhOTE1MC1jaGFyZ2VyIiwNCj4gPiArCQkuY29uc3VtZXJfY2hhbm5lbCA9ICJDSEFO
X0lCVVMiLA0KPiA+ICsJCS5hZGNfY2hhbm5lbF9sYWJlbCA9ICJJQlVTIiwNCj4gPiArCX0sDQo+
ID4gKwl7DQo+ID4gKwkJLmNvbnN1bWVyX2Rldl9uYW1lID0gImRhOTE1MC1jaGFyZ2VyIiwNCj4g
PiArCQkuY29uc3VtZXJfY2hhbm5lbCA9ICJDSEFOX1ZCVVMiLA0KPiA+ICsJCS5hZGNfY2hhbm5l
bF9sYWJlbCA9ICJWQlVTIiwNCj4gPiArCX0sDQo+ID4gKwl7DQo+ID4gKwkJLmNvbnN1bWVyX2Rl
dl9uYW1lID0gImRhOTE1MC1jaGFyZ2VyIiwNCj4gPiArCQkuY29uc3VtZXJfY2hhbm5lbCA9ICJD
SEFOX1RKVU5DIiwNCj4gPiArCQkuYWRjX2NoYW5uZWxfbGFiZWwgPSAiVEpVTkNfQ09SRSIsDQo+
ID4gKwl9LA0KPiA+ICsJew0KPiA+ICsJCS5jb25zdW1lcl9kZXZfbmFtZSA9ICJkYTkxNTAtY2hh
cmdlciIsDQo+ID4gKwkJLmNvbnN1bWVyX2NoYW5uZWwgPSAiQ0hBTl9WQkFUIiwNCj4gPiArCQku
YWRjX2NoYW5uZWxfbGFiZWwgPSAiVkJBVCIsDQo+ID4gKwl9LA0KPiA+ICsJe30sDQo+ID4gK307
DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGRhOTE1MF9ncGFkY19wcm9iZShzdHJ1Y3QgcGxhdGZv
cm1fZGV2aWNlICpwZGV2KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgZGV2aWNlICpkZXYgPSAmcGRl
di0+ZGV2Ow0KPiA+ICsJc3RydWN0IGRhOTE1MCAqZGE5MTUwID0gZGV2X2dldF9kcnZkYXRhKGRl
di0+cGFyZW50KTsNCj4gTWF5YmUgeW91IGNvdWxkIGZpbmQgYSBzbGlnaHRseSBkaWZmZXJlbnQg
bmFtZSBmb3IgdGhlIGluc3RhbmNlIG9mIHRoaXMgZGE5MTUwIHRoYW4NCj4gaXRzIHR5cGUgbmFt
ZS4NCg0KVGhpcyBpcyBxdWl0ZSBjb21tb24gdGhyb3VnaCBvdGhlciBkcml2ZXJzLCBhbmQgSSB0
aGluayB0aGUgdXNhZ2UgaXMgb2J2aW91cywNCnNvIHdvdWxkIHJhdGhlciBsZWF2ZSBhcyBpcy4N
Cg0KPiA+ICsJc3RydWN0IGRhOTE1MF9ncGFkYyAqZ3BhZGM7DQo+ID4gKwlzdHJ1Y3QgaWlvX2Rl
diAqaW5kaW9fZGV2Ow0KPiA+ICsJaW50IGlycSwgcmV0Ow0KPiA+ICsNCj4gPiArCWluZGlvX2Rl
diA9IGRldm1faWlvX2RldmljZV9hbGxvYygmcGRldi0+ZGV2LA0KPiA+ICsJCQkJCSAgc2l6ZW9m
KHN0cnVjdCBkYTkxNTBfZ3BhZGMpKTsNCj4gPiArCWlmICghaW5kaW9fZGV2KSB7DQo+ID4gKwkJ
ZGV2X2VycigmcGRldi0+ZGV2LCAiRmFpbGVkIHRvIGFsbG9jYXRlIElJTyBkZXZpY2VcbiIpOw0K
PiA+ICsJCXJldHVybiAtRU5PTUVNOw0KPiA+ICsJfQ0KPiA+ICsJZ3BhZGMgPSBpaW9fcHJpdihp
bmRpb19kZXYpOw0KPiA+ICsNCj4gPiArCXBsYXRmb3JtX3NldF9kcnZkYXRhKHBkZXYsIGluZGlv
X2Rldik7DQo+ID4gKwlncGFkYy0+ZGE5MTUwID0gZGE5MTUwOw0KPiA+ICsJZ3BhZGMtPmRldiA9
IGRldjsNCj4gPiArDQo+ID4gKwlyZXQgPSBpaW9fbWFwX2FycmF5X3JlZ2lzdGVyKGluZGlvX2Rl
diwgZGE5MTUwX2dwYWRjX2RlZmF1bHRfbWFwcyk7DQo+ID4gKwlpZiAocmV0KSB7DQo+ID4gKwkJ
ZGV2X2VycihkZXYsICJGYWlsZWQgdG8gcmVnaXN0ZXIgSUlPIG1hcHM6ICVkXG4iLCByZXQpOw0K
PiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJbXV0ZXhfaW5pdCgmZ3Bh
ZGMtPmxvY2spOw0KPiA+ICsJaW5pdF9jb21wbGV0aW9uKCZncGFkYy0+Y29tcGxldGUpOw0KPiA+
ICsNCj4gPiArCWlycSA9IHBsYXRmb3JtX2dldF9pcnFfYnluYW1lKHBkZXYsICJHUEFEQyIpOw0K
PiBTaG91bGRuJ3QgeW91IGNoZWNrIGlycSBmb3IgcG9zc2libGUgZXJyb3IgY29kZXM/IGRldm1f
cmVxdWVzdF90aHJlYWRlZF9pcnEoKQ0KPiBleHBlY3RzIGlycSB0byBiZSB1bnNpZ25lZC4NCg0K
VGhlIGludGVudGlvbiB3YXMgdG8gY3V0IGRvd24gb24gY29kZSBhcyBkZXZtX3JlcXVlc3RfdGhy
ZWFkZWRfaXJxIHNob3VsZCBmYWlsDQppZiB0aGUgSVJRIG51bWJlciBpcyBpbnZhbGlkLiBIb3dl
dmVyLCB5b3UncmUgcHJvYmFibHkgcmlnaHQgaGVyZSBhbmQgdGhlcmUgaXMNCnRoZSBvcHBvcnR1
bml0eSBmb3IgUFJPQkVfREVGRVIgdG8gYmUgcmV0dXJuZWQsIGlmIHVzaW5nIERULg0KDQo+ID4g
KwlyZXQgPSBkZXZtX3JlcXVlc3RfdGhyZWFkZWRfaXJxKGRldiwgaXJxLCBOVUxMLCBkYTkxNTBf
Z3BhZGNfaXJxLA0KPiA+ICsJCQkJCUlSUUZfT05FU0hPVCwgIkdQQURDIiwgZ3BhZGMpOw0KPiA+
ICsJaWYgKHJldCkgew0KPiA+ICsJCWRldl9lcnIoZGV2LCAiRmFpbGVkIHRvIHJlcXVlc3QgSVJR
ICVkOiAlZFxuIiwgaXJxLCByZXQpOw0KPiA+ICsJCWdvdG8gaWlvX21hcF91bnJlZzsNCj4gPiAr
CX0NCj4gPiArDQo+ID4gKwlpbmRpb19kZXYtPm5hbWUgPSBkZXZfbmFtZShkZXYpOw0KPiA+ICsJ
aW5kaW9fZGV2LT5kZXYucGFyZW50ID0gZGV2Ow0KPiA+ICsJaW5kaW9fZGV2LT5kZXYub2Zfbm9k
ZSA9IHBkZXYtPmRldi5vZl9ub2RlOw0KPiA+ICsJaW5kaW9fZGV2LT5pbmZvID0gJmRhOTE1MF9n
cGFkY19pbmZvOw0KPiA+ICsJaW5kaW9fZGV2LT5tb2RlcyA9IElORElPX0RJUkVDVF9NT0RFOw0K
PiA+ICsJaW5kaW9fZGV2LT5jaGFubmVscyA9IGRhOTE1MF9ncGFkY19jaGFubmVsczsNCj4gPiAr
CWluZGlvX2Rldi0+bnVtX2NoYW5uZWxzID0gQVJSQVlfU0laRShkYTkxNTBfZ3BhZGNfY2hhbm5l
bHMpOw0KPiA+ICsNCj4gPiArCXJldCA9IGlpb19kZXZpY2VfcmVnaXN0ZXIoaW5kaW9fZGV2KTsN
Cj4gPiArCWlmIChyZXQpIHsNCj4gPiArCQlkZXZfZXJyKGRldiwgIkZhaWxlZCB0byByZWdpc3Rl
ciBJSU8gZGV2aWNlOiAlZFxuIiwgcmV0KTsNCj4gPiArCQlnb3RvIGlpb19tYXBfdW5yZWc7DQo+
ID4gKwl9DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gKw0KPiA+ICtpaW9fbWFwX3VucmVn
Og0KPiA+ICsJaWlvX21hcF9hcnJheV91bnJlZ2lzdGVyKGluZGlvX2Rldik7DQo+ID4gKw0KPiA+
ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCBkYTkxNTBfZ3Bh
ZGNfcmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpDQo+ID4gK3sNCj4gPiArCXN0
cnVjdCBpaW9fZGV2ICppbmRpb19kZXYgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsNCj4g
PiArDQo+ID4gKwlpaW9fbWFwX2FycmF5X3VucmVnaXN0ZXIoaW5kaW9fZGV2KTsNCj4gPiArCWlp
b19kZXZpY2VfdW5yZWdpc3RlcihpbmRpb19kZXYpOw0KPiBOb3Qgc3VyZSBpZiB0aGF0IHdhcyB0
aGUgaW50ZW50aW9uIG9mIEpvbmF0aGFucyBjb21tZW50LCBidXQgdGhlc2UgdW5yZWdpc3RlciBj
YWxscw0KPiBzaG91bGQgYmUgc3dpdGNoZWQgdG8gYmUgaW4gcHJvcGVyIHJldmVyc2Ugb3JkZXIu
DQoNCkFscmVhZHkgcGxhbm5lZCB0byBkbyB0aGF0LCBidXQgdGhhbmtzLg0KDQo+ID4gKw0KPiA+
ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1f
ZHJpdmVyIGRhOTE1MF9ncGFkY19kcml2ZXIgPSB7DQo+ID4gKwkuZHJpdmVyID0gew0KPiA+ICsJ
CS5uYW1lID0gImRhOTE1MC1ncGFkYyIsDQo+ID4gKwl9LA0KPiA+ICsJLnByb2JlID0gZGE5MTUw
X2dwYWRjX3Byb2JlLA0KPiA+ICsJLnJlbW92ZSA9IGRhOTE1MF9ncGFkY19yZW1vdmUsDQo+ID4g
K307DQo+ID4gKw0KPiA+ICttb2R1bGVfcGxhdGZvcm1fZHJpdmVyKGRhOTE1MF9ncGFkY19kcml2
ZXIpOw0KPiA+ICsNCj4gPiArTU9EVUxFX0RFU0NSSVBUSU9OKCJHUEFEQyBEcml2ZXIgZm9yIERB
OTE1MCIpOw0KPiA+ICtNT0RVTEVfQVVUSE9SKCJBZGFtIFRob21zb24NCj4gPEFkYW0uVGhvbXNv
bi5PcGVuc291cmNlQGRpYXNlbWkuY29tIik7DQo+IFlvdSBhcmUgbWlzc2luZyBhID4gYXQgdGhl
IGVuZCBvZiB5b3VyIGVtYWlsLWFkZHJlc3MuDQoNCkdvb2Qgc3BvdC4gOikgV2lsbCB1cGRhdGUu
DQoNCj4gPiArTU9EVUxFX0xJQ0VOU0UoIkdQTCIpOw0KPiA+IC0tDQo+ID4gMS45LjMNCj4gPg0K
PiA+IC0tDQo+ID4gVG8gdW5zdWJzY3JpYmUgZnJvbSB0aGlzIGxpc3Q6IHNlbmQgdGhlIGxpbmUg
InVuc3Vic2NyaWJlIGxpbnV4LWlpbyIgaW4NCj4gPiB0aGUgYm9keSBvZiBhIG1lc3NhZ2UgdG8g
bWFqb3Jkb21vQHZnZXIua2VybmVsLm9yZw0KPiA+IE1vcmUgbWFqb3Jkb21vIGluZm8gYXQgIGh0
dHA6Ly92Z2VyLmtlcm5lbC5vcmcvbWFqb3Jkb21vLWluZm8uaHRtbA0KPiA+DQo=
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 4/8] iio: da9150: Add DT binding documentation for GPADC
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
` (2 preceding siblings ...)
2014-09-23 10:53 ` [PATCH 3/8] iio: Add support for DA9150 GPADC Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-27 10:52 ` Jonathan Cameron
2014-09-23 10:53 ` [PATCH 5/8] power: Add support for DA9150 Charger Adam Thomson
` (3 subsequent siblings)
7 siblings, 1 reply; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
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] 22+ messages in thread
* Re: [PATCH 4/8] iio: da9150: Add DT binding documentation for GPADC
2014-09-23 10:53 ` [PATCH 4/8] iio: da9150: Add DT binding documentation for GPADC Adam Thomson
@ 2014-09-27 10:52 ` Jonathan Cameron
0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2014-09-27 10:52 UTC (permalink / raw)
To: Adam Thomson, Lee Jones, Samuel Ortiz, linux-iio,
Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
On 23/09/14 11:53, Adam Thomson wrote:
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
Acked-by: Jonathan Cameron <jic23@kernel.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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 5/8] power: Add support for DA9150 Charger
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
` (3 preceding siblings ...)
2014-09-23 10:53 ` [PATCH 4/8] iio: da9150: Add DT binding documentation for GPADC Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-27 11:09 ` Jonathan Cameron
2014-09-23 10:53 ` [PATCH 6/8] power: da9150: Add DT binding documentation for charger Adam Thomson
` (2 subsequent siblings)
7 siblings, 1 reply; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
This patch adds support for DA9150 Charger & Fuel-Gauge 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 | 740 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 753 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..38345cf
--- /dev/null
+++ b/drivers/power/da9150-charger.c
@@ -0,0 +1,740 @@
+/*
+ * 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/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/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)
+{
+ int v_val, ret;
+
+ /* Read processed value - mV units */
+ ret = iio_read_channel_processed(charger->vbus_chan, &v_val);
+ if (ret < 0)
+ return ret;
+
+ /* Convert voltage to expected uV units */
+ val->intval = v_val * 1000;
+
+ return 0;
+}
+
+static int da9150_charger_ibus_current_avg(struct da9150_charger *charger,
+ union power_supply_propval *val)
+{
+ int i_val, ret;
+
+ /* Read processed value - mA units */
+ ret = iio_read_channel_processed(charger->ibus_chan, &i_val);
+ if (ret < 0)
+ return ret;
+
+ /* Convert current to expected uA units */
+ val->intval = i_val * 1000;
+
+ return 0;
+}
+
+static int da9150_charger_tjunc_temp(struct da9150_charger *charger,
+ union power_supply_propval *val)
+{
+ int t_val, ret;
+
+ /* Read processed value - 0.001 degrees C units */
+ ret = iio_read_channel_processed(charger->tjunc_chan, &t_val);
+ if (ret < 0)
+ return ret;
+
+ /* Convert temp to expect 0.1 degrees C units */
+ val->intval = t_val / 100;
+
+ return 0;
+}
+
+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)
+{
+ int v_val, ret;
+
+ /* Read processed value - mV units */
+ ret = iio_read_channel_processed(charger->vbat_chan, &v_val);
+ if (ret < 0)
+ return ret;
+
+ val->intval = v_val * 1000;
+
+ return 0;
+}
+
+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, irq, 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)
+ goto sysfs_fail;
+ }
+
+ /* Get initial online supply */
+ reg = da9150_reg_read(da9150, DA9150_STATUS_H);
+
+ 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 */
+ irq = platform_get_irq_byname(pdev, "CHG_STATUS");
+ ret = devm_request_threaded_irq(dev, irq, NULL, da9150_charger_chg_irq,
+ IRQF_ONESHOT, "CHG_STATUS", charger);
+ if (ret)
+ goto irq_fail;
+
+ irq = platform_get_irq_byname(pdev, "CHG_TJUNC");
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ da9150_charger_tjunc_irq,
+ IRQF_ONESHOT, "CHG_TJUNC", charger);
+ if (ret)
+ goto irq_fail;
+
+ irq = platform_get_irq_byname(pdev, "CHG_VFAULT");
+ ret = devm_request_threaded_irq(dev, irq, NULL,
+ da9150_charger_vfault_irq,
+ IRQF_ONESHOT, "CHG_VFAULT", charger);
+ if (ret)
+ goto irq_fail;
+
+ irq = platform_get_irq_byname(pdev, "CHG_VBUS");
+ ret = devm_request_threaded_irq(dev, irq, NULL, da9150_charger_vbus_irq,
+ IRQF_ONESHOT, "CHG_VBUS", charger);
+ if (ret)
+ goto irq_fail;
+
+ return 0;
+
+irq_fail:
+ dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
+ 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 device *dev = &pdev->dev;
+ struct da9150_charger *charger = platform_get_drvdata(pdev);
+ int i, irq;
+
+ /* Make sure IRQs are released before unregistering power supplies */
+ irq = platform_get_irq_byname(pdev, "CHG_VBUS");
+ devm_free_irq(dev, irq, charger);
+
+ irq = platform_get_irq_byname(pdev, "CHG_VFAULT");
+ devm_free_irq(dev, irq, charger);
+
+ irq = platform_get_irq_byname(pdev, "CHG_TJUNC");
+ devm_free_irq(dev, irq, charger);
+
+ irq = platform_get_irq_byname(pdev, "CHG_STATUS");
+ devm_free_irq(dev, irq, charger);
+
+ 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",
+ },
+ .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] 22+ messages in thread
* Re: [PATCH 5/8] power: Add support for DA9150 Charger
2014-09-23 10:53 ` [PATCH 5/8] power: Add support for DA9150 Charger Adam Thomson
@ 2014-09-27 11:09 ` Jonathan Cameron
0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2014-09-27 11:09 UTC (permalink / raw)
To: Adam Thomson, Lee Jones, Samuel Ortiz, linux-iio,
Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
On 23/09/14 11:53, Adam Thomson wrote:
> This patch adds support for DA9150 Charger & Fuel-Gauge IC Charger.
>
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
The IIO elements of this look fine to me. I'm not failiar enough with
the charger framework to give more than a superficial opinion on that.
I do note that we have a lot of attributes added to the device after
registration which we have spent time elsewhere in the kernel avoiding
because of notification issues...
http://kroah.com/log/blog/2013/06/26/how-to-create-a-sysfs-file-correctly/
(convient summary of this from GregKH)
Still probably not an issue with this driver it self...
> ---
> drivers/power/Kconfig | 12 +
> drivers/power/Makefile | 1 +
> drivers/power/da9150-charger.c | 740 +++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 753 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..38345cf
> --- /dev/null
> +++ b/drivers/power/da9150-charger.c
> @@ -0,0 +1,740 @@
> +/*
> + * 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/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/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)
> +{
> + int v_val, ret;
> +
> + /* Read processed value - mV units */
> + ret = iio_read_channel_processed(charger->vbus_chan, &v_val);
> + if (ret < 0)
> + return ret;
> +
> + /* Convert voltage to expected uV units */
> + val->intval = v_val * 1000;
> +
> + return 0;
> +}
> +
> +static int da9150_charger_ibus_current_avg(struct da9150_charger *charger,
> + union power_supply_propval *val)
> +{
> + int i_val, ret;
> +
> + /* Read processed value - mA units */
> + ret = iio_read_channel_processed(charger->ibus_chan, &i_val);
> + if (ret < 0)
> + return ret;
> +
> + /* Convert current to expected uA units */
> + val->intval = i_val * 1000;
> +
> + return 0;
> +}
> +
> +static int da9150_charger_tjunc_temp(struct da9150_charger *charger,
> + union power_supply_propval *val)
> +{
> + int t_val, ret;
> +
> + /* Read processed value - 0.001 degrees C units */
> + ret = iio_read_channel_processed(charger->tjunc_chan, &t_val);
> + if (ret < 0)
> + return ret;
> +
> + /* Convert temp to expect 0.1 degrees C units */
> + val->intval = t_val / 100;
> +
> + return 0;
> +}
> +
> +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)
> +{
> + int v_val, ret;
> +
> + /* Read processed value - mV units */
> + ret = iio_read_channel_processed(charger->vbat_chan, &v_val);
> + if (ret < 0)
> + return ret;
> +
> + val->intval = v_val * 1000;
> +
> + return 0;
> +}
> +
> +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, irq, 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)
> + goto sysfs_fail;
> + }
> +
> + /* Get initial online supply */
> + reg = da9150_reg_read(da9150, DA9150_STATUS_H);
> +
> + 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 */
> + irq = platform_get_irq_byname(pdev, "CHG_STATUS");
> + ret = devm_request_threaded_irq(dev, irq, NULL, da9150_charger_chg_irq,
> + IRQF_ONESHOT, "CHG_STATUS", charger);
> + if (ret)
> + goto irq_fail;
> +
> + irq = platform_get_irq_byname(pdev, "CHG_TJUNC");
> + ret = devm_request_threaded_irq(dev, irq, NULL,
> + da9150_charger_tjunc_irq,
> + IRQF_ONESHOT, "CHG_TJUNC", charger);
> + if (ret)
> + goto irq_fail;
> +
> + irq = platform_get_irq_byname(pdev, "CHG_VFAULT");
> + ret = devm_request_threaded_irq(dev, irq, NULL,
> + da9150_charger_vfault_irq,
> + IRQF_ONESHOT, "CHG_VFAULT", charger);
> + if (ret)
> + goto irq_fail;
> +
> + irq = platform_get_irq_byname(pdev, "CHG_VBUS");
> + ret = devm_request_threaded_irq(dev, irq, NULL, da9150_charger_vbus_irq,
> + IRQF_ONESHOT, "CHG_VBUS", charger);
> + if (ret)
> + goto irq_fail;
> +
> + return 0;
> +
> +irq_fail:
> + dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n", irq, ret);
> + 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 device *dev = &pdev->dev;
> + struct da9150_charger *charger = platform_get_drvdata(pdev);
> + int i, irq;
> +
> + /* Make sure IRQs are released before unregistering power supplies */
> + irq = platform_get_irq_byname(pdev, "CHG_VBUS");
> + devm_free_irq(dev, irq, charger);
> +
> + irq = platform_get_irq_byname(pdev, "CHG_VFAULT");
> + devm_free_irq(dev, irq, charger);
> +
> + irq = platform_get_irq_byname(pdev, "CHG_TJUNC");
> + devm_free_irq(dev, irq, charger);
> +
> + irq = platform_get_irq_byname(pdev, "CHG_STATUS");
> + devm_free_irq(dev, irq, charger);
> +
> + 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",
> + },
> + .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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 6/8] power: da9150: Add DT binding documentation for charger
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
` (4 preceding siblings ...)
2014-09-23 10:53 ` [PATCH 5/8] power: Add support for DA9150 Charger Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-23 10:53 ` [PATCH 7/8] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list Adam Thomson
2014-09-23 10:53 ` [PATCH 8/8] iio: Add ABI documentation for input current readings Adam Thomson
7 siblings, 0 replies; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
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] 22+ messages in thread
* [PATCH 7/8] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list.
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
` (5 preceding siblings ...)
2014-09-23 10:53 ` [PATCH 6/8] power: da9150: Add DT binding documentation for charger Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-23 10:53 ` [PATCH 8/8] iio: Add ABI documentation for input current readings Adam Thomson
7 siblings, 0 replies; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
MAINTAINERS | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1ff06de..3c86b30 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2890,12 +2890,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
@@ -2905,6 +2908,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] 22+ messages in thread
* [PATCH 8/8] iio: Add ABI documentation for input current readings
2014-09-23 10:53 [PATCH v3 0/8] Add initial support for DA9150 Charger & Fuel-Gauge IC Adam Thomson
` (6 preceding siblings ...)
2014-09-23 10:53 ` [PATCH 7/8] MAINTAINERS: Include DA9150 files in Dialog Semiconductor support list Adam Thomson
@ 2014-09-23 10:53 ` Adam Thomson
2014-09-27 10:23 ` Jonathan Cameron
7 siblings, 1 reply; 22+ messages in thread
From: Adam Thomson @ 2014-09-23 10:53 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, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
Add information on in_current related readings.
Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
---
Documentation/ABI/testing/sysfs-bus-iio | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index d760b02..37cd4d4 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -92,6 +92,18 @@ Description:
is required is a consistent labeling. Units after application
of scale and offset are millivolts.
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
+KernelVersion: 3.17
+Contact: linux-iio@vger.kernel.org
+Description:
+ Raw (unscaled no bias removal etc.) current measurement from
+ channel Y. In special cases where the channel does not
+ correspond to externally available input one of the named
+ versions may be used. The number must always be specified and
+ unique to allow association with event codes. Units after
+ application of scale and offset are milliamps.
+
What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
KernelVersion: 3.2
Contact: linux-iio@vger.kernel.org
@@ -227,6 +239,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset
+What: /sys/bus/iio/devices/iio:deviceX/in_current_offset
What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
@@ -249,8 +263,11 @@ Description:
to the _raw output.
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
+What: /sys/bus/iio/devices/iio:deviceX/in_current_scale
What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
--
1.9.3
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH 8/8] iio: Add ABI documentation for input current readings
2014-09-23 10:53 ` [PATCH 8/8] iio: Add ABI documentation for input current readings Adam Thomson
@ 2014-09-27 10:23 ` Jonathan Cameron
0 siblings, 0 replies; 22+ messages in thread
From: Jonathan Cameron @ 2014-09-27 10:23 UTC (permalink / raw)
To: Adam Thomson, Lee Jones, Samuel Ortiz, linux-iio,
Sebastian Reichel, Dmitry Eremin-Solenikov, David Woodhouse,
linux-pm, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Grant Likely, devicetree, Andrew Morton, Joe Perches,
linux-api
Cc: linux-kernel, support.opensource
On 23/09/14 11:53, Adam Thomson wrote:
> Add information on in_current related readings.
>
> Signed-off-by: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
This crossed with a similar patch also adding some docs for current channels.
That just missed this cycle anyway so I'll probably just merge this in as
an extension of that patch when we are happy with the rest of the series.
That patch covers the raw attribute but doesn't add the other entries..
(in the togreg branch of iio.git)
Jonathan
> ---
> Documentation/ABI/testing/sysfs-bus-iio | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
> index d760b02..37cd4d4 100644
> --- a/Documentation/ABI/testing/sysfs-bus-iio
> +++ b/Documentation/ABI/testing/sysfs-bus-iio
> @@ -92,6 +92,18 @@ Description:
> is required is a consistent labeling. Units after application
> of scale and offset are millivolts.
>
> +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_raw
> +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_raw
> +KernelVersion: 3.17
> +Contact: linux-iio@vger.kernel.org
> +Description:
> + Raw (unscaled no bias removal etc.) current measurement from
> + channel Y. In special cases where the channel does not
> + correspond to externally available input one of the named
> + versions may be used. The number must always be specified and
> + unique to allow association with event codes. Units after
> + application of scale and offset are milliamps.
> +
> What: /sys/bus/iio/devices/iio:deviceX/in_capacitanceY_raw
> KernelVersion: 3.2
> Contact: linux-iio@vger.kernel.org
> @@ -227,6 +239,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset
> What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset
> What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset
> What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset
> +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset
> +What: /sys/bus/iio/devices/iio:deviceX/in_current_offset
> What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset
> What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset
> What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset
> @@ -249,8 +263,11 @@ Description:
> to the _raw output.
>
> What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale
> +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale
> +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale
> +What: /sys/bus/iio/devices/iio:deviceX/in_current_scale
> What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale
> What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale
> What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale
> --
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 22+ messages in thread