All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] Add new MFD driver for MAX77843
@ 2015-01-23  5:02 Jaewon Kim
  2015-01-23  5:02   ` Jaewon Kim
                   ` (5 more replies)
  0 siblings, 6 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-pm
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo, Jaewon Kim

This patch series adds MAX77843(Multi Function Device) driver.
The MAX77843 includes MUIC(Micro USB Interface Circuit), Li+ Charger
with Fuel Gauge and 2 safeout LDOs for USB device.
It is interfaced to host controller using I2C.

Beomho Seo (2):
  power: max77843_charger: Add Max77843 charger device driver
  power: max77843_battery: Add Max77843 fuel gauge device driver

Jaewon Kim (4):
  mfd: max77843: Add max77843 MFD driver core driver
  extcon: max77843: Add max77843 MUIC driver
  regulator: max77843: Add max77843 regulator driver
  Documentation: Add device tree bindings document for max77843

 Documentation/devicetree/bindings/mfd/max77843.txt |   87 ++
 drivers/extcon/Kconfig                             |   10 +
 drivers/extcon/Makefile                            |    1 +
 drivers/extcon/extcon-max77843.c                   |  871 ++++++++++++++++++++
 drivers/mfd/Kconfig                                |   14 +
 drivers/mfd/Makefile                               |    1 +
 drivers/mfd/max77843.c                             |  241 ++++++
 drivers/power/Kconfig                              |   16 +
 drivers/power/Makefile                             |    2 +
 drivers/power/max77843_battery.c                   |  283 +++++++
 drivers/power/max77843_charger.c                   |  506 ++++++++++++
 drivers/regulator/Kconfig                          |    8 +
 drivers/regulator/Makefile                         |    1 +
 drivers/regulator/max77843.c                       |  259 ++++++
 include/linux/mfd/max77843-private.h               |  410 +++++++++
 15 files changed, 2710 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/max77843.txt
 create mode 100644 drivers/extcon/extcon-max77843.c
 create mode 100644 drivers/mfd/max77843.c
 create mode 100644 drivers/power/max77843_battery.c
 create mode 100644 drivers/power/max77843_charger.c
 create mode 100644 drivers/regulator/max77843.c
 create mode 100644 include/linux/mfd/max77843-private.h

-- 
1.7.9.5


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

* [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  5:02   ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-pm
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo, Jaewon Kim

This patch adds MAX77843 core/irq driver to support PMIC,
MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
LED and Haptic device.

Cc: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
---
 drivers/mfd/Kconfig                  |   14 ++
 drivers/mfd/Makefile                 |    1 +
 drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
 include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
 4 files changed, 666 insertions(+)
 create mode 100644 drivers/mfd/max77843.c
 create mode 100644 include/linux/mfd/max77843-private.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2e6b731..0c67c79 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -442,6 +442,20 @@ config MFD_MAX77693
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config MFD_MAX77843
+	bool "Maxim Semiconductor MAX77843 PMIC Support"
+	depends on I2C=y
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	help
+	  Say yes here to add support for Maxim Semiconductor MAX77843.
+	  This is companion Power Management IC with LEDs, Haptic, Charger,
+	  Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
+	  This driver provides common support for accessing the device;
+	  additional drivers must be enabled in order to use the functionality
+	  of the device.
+
 config MFD_MAX8907
 	tristate "Maxim Semiconductor MAX8907 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 53467e2..fe4f75c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
 obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
+obj-$(CONFIG_MFD_MAX77843)	+= max77843.o
 obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
new file mode 100644
index 0000000..d7f8b76
--- /dev/null
+++ b/drivers/mfd/max77843.c
@@ -0,0 +1,241 @@
+/*
+ * max77843.c - MFD core driver for the Maxim MAX77843
+ *
+ * Copyright (C) 2014 Samsung Electrnoics
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77843-private.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+static const struct mfd_cell max77843_devs[] = {
+	{
+		.name = "max77843-muic",
+		.of_compatible = "maxim,max77843-muic",
+	}, {
+		.name = "max77843-regulator",
+		.of_compatible = "maxim,max77843-regulator",
+	}, {
+		.name = "max77843-charger",
+		.of_compatible = "maxim,max77843-charger"
+	}, {
+		.name = "max77843-fuelgauge",
+		.of_compatible = "maxim,max77843-fuelgauge",
+	},
+};
+
+static const struct regmap_config max77843_charger_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= MAX77843_CHG_REG_END,
+};
+
+static const struct regmap_config max77843_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= MAX77843_SYS_REG_END,
+};
+
+static const struct regmap_irq max77843_irqs[] = {
+	/* TOPSYS interrupts */
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
+};
+
+static const struct regmap_irq_chip max77843_irq_chip = {
+	.name		= "max77843",
+	.status_base	= MAX77843_SYS_REG_SYSINTSRC,
+	.mask_base	= MAX77843_SYS_REG_SYSINTMASK,
+	.mask_invert	= false,
+	.num_regs	= 1,
+	.irqs		= max77843_irqs,
+	.num_irqs	= ARRAY_SIZE(max77843_irqs),
+};
+
+static int max77843_chg_init(struct max77843 *max77843)
+{
+	int ret;
+
+	max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
+	if (!max77843->i2c_chg) {
+		dev_err(&max77843->i2c->dev,
+				"Cannot allocate I2C device for Charger\n");
+		return PTR_ERR(max77843->i2c_chg);
+	}
+	i2c_set_clientdata(max77843->i2c_chg, max77843);
+
+	max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
+			&max77843_charger_regmap_config);
+	if (IS_ERR(max77843->regmap_chg)) {
+		ret = PTR_ERR(max77843->regmap_chg);
+		goto err_chg_i2c;
+	}
+
+	return 0;
+
+err_chg_i2c:
+	i2c_unregister_device(max77843->i2c_chg);
+
+	return ret;
+}
+
+static int max77843_probe(struct i2c_client *i2c,
+					const struct i2c_device_id *id)
+{
+	struct max77843 *max77843;
+	int ret;
+	unsigned int reg_data;
+
+	max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
+	if (!max77843)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max77843);
+	max77843->dev = &i2c->dev;
+	max77843->i2c = i2c;
+	max77843->irq = i2c->irq;
+
+	max77843->regmap = devm_regmap_init_i2c(i2c,
+			&max77843_regmap_config);
+	if (IS_ERR(max77843->regmap)) {
+		dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
+		return PTR_ERR(max77843->regmap);
+	}
+
+	ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
+			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
+			0, &max77843_irq_chip, &max77843->irq_data);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
+		return ret;
+	}
+
+	ret = regmap_read(max77843->regmap,
+			MAX77843_SYS_REG_PMICID, &reg_data);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read PMIC ID\n");
+		goto err_pmic_id;
+	}
+	dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
+
+	ret = max77843_chg_init(max77843);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to init Charger\n");
+		goto err_pmic_id;
+	}
+
+	ret = regmap_update_bits(max77843->regmap,
+			MAX77843_SYS_REG_INTSRCMASK,
+			MAX77843_INTSRC_MASK_MASK,
+			(unsigned int)~MAX77843_INTSRC_MASK_MASK);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
+		goto err_pmic_id;
+	}
+
+	ret = mfd_add_devices(max77843->dev, -1, max77843_devs,
+			ARRAY_SIZE(max77843_devs), NULL, 0, NULL);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to add mfd device\n");
+		goto err_pmic_id;
+	}
+
+	device_init_wakeup(max77843->dev, 1);
+
+	return 0;
+
+err_pmic_id:
+	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
+
+	return ret;
+}
+
+static int max77843_remove(struct i2c_client *i2c)
+{
+	struct max77843 *max77843 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(max77843->dev);
+
+	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
+
+	i2c_unregister_device(max77843->i2c);
+
+	return 0;
+}
+
+static const struct of_device_id max77843_dt_match[] = {
+	{ .compatible = "maxim,max77843", },
+	{ /* sentinel */ },
+};
+
+static const struct i2c_device_id max77843_id[] = {
+	{ "max77843", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(i2c, max77843_id);
+
+static int __maybe_unused max77843_suspend(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77843 *max77843 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(max77843->irq);
+	disable_irq(max77843->irq);
+
+	return 0;
+}
+
+static int __maybe_unused max77843_resume(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77843 *max77843 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(max77843->irq);
+	enable_irq(max77843->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(max77843_pm, max77843_suspend, max77843_resume);
+
+static struct i2c_driver max77843_i2c_driver = {
+	.driver		= {
+		.name		= "max77843",
+		.pm		= &max77843_pm,
+		.of_match_table = max77843_dt_match,
+	},
+	.probe		= max77843_probe,
+	.remove		= max77843_remove,
+	.id_table	= max77843_id,
+};
+static int __init max77843_i2c_init(void)
+{
+	return i2c_add_driver(&max77843_i2c_driver);
+}
+subsys_initcall(max77843_i2c_init);
+
+static void __exit max77843_i2c_exit(void)
+{
+	i2c_del_driver(&max77843_i2c_driver);
+}
+module_exit(max77843_i2c_exit);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_DESCRIPTION("Maxim MAX77843 multi-function core driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h
new file mode 100644
index 0000000..560ed73
--- /dev/null
+++ b/include/linux/mfd/max77843-private.h
@@ -0,0 +1,410 @@
+/*
+ * max77843-private.h - Common API for the Maxim MAX77843 internal sub chip
+ *
+ * Copyright (C) 2014 Samsung Electrnoics
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MAX77843_PRIVATE_H_
+#define __MAX77843_PRIVATE_H_
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#define I2C_ADDR_TOPSYS	(0xCC >> 1)
+#define I2C_ADDR_CHG	(0xD2 >> 1)
+#define I2C_ADDR_FG	(0x6C >> 1)
+#define I2C_ADDR_MUIC	(0x4A >> 1)
+
+/* Topsys, Haptic and LED registers */
+enum max77843_sys_reg {
+	MAX77843_SYS_REG_PMICID		= 0x00,
+	MAX77843_SYS_REG_PMICREV	= 0x01,
+	MAX77843_SYS_REG_MAINCTRL1	= 0x02,
+	MAX77843_SYS_REG_INTSRC		= 0x22,
+	MAX77843_SYS_REG_INTSRCMASK	= 0x23,
+	MAX77843_SYS_REG_SYSINTSRC	= 0x24,
+	MAX77843_SYS_REG_SYSINTMASK	= 0x26,
+	MAX77843_SYS_REG_TOPSYS_STAT	= 0x28,
+	MAX77843_SYS_REG_SAFEOUTCTRL	= 0xC6,
+
+	MAX77843_SYS_REG_END,
+};
+
+enum max77843_led_reg {
+	MAX77843_LED_REG_LEDEN		= 0x30,
+	MAX77843_LED_REG_LED0BRT	= 0x31,
+	MAX77843_LED_REG_LED1BRT	= 0x32,
+	MAX77843_LED_REG_LED2BRT	= 0x33,
+	MAX77843_LED_REG_LED3BRT	= 0x34,
+	MAX77843_LED_REG_LEDBLNK	= 0x38,
+	MAX77843_LED_REG_LEDRAMP	= 0x36,
+
+	MAX77843_LED_REG_END,
+};
+
+/* Charger registers */
+enum max77843_charger_reg {
+	MAX77843_CHG_REG_CHG_INT	= 0xB0,
+	MAX77843_CHG_REG_CHG_INT_MASK	= 0xB1,
+	MAX77843_CHG_REG_CHG_INT_OK	= 0xB2,
+	MAX77843_CHG_REG_CHG_DTLS_00	= 0xB3,
+	MAX77843_CHG_REG_CHG_DTLS_01	= 0xB4,
+	MAX77843_CHG_REG_CHG_DTLS_02	= 0xB5,
+	MAX77843_CHG_REG_CHG_CNFG_00	= 0xB7,
+	MAX77843_CHG_REG_CHG_CNFG_01	= 0xB8,
+	MAX77843_CHG_REG_CHG_CNFG_02	= 0xB9,
+	MAX77843_CHG_REG_CHG_CNFG_03	= 0xBA,
+	MAX77843_CHG_REG_CHG_CNFG_04	= 0xBB,
+	MAX77843_CHG_REG_CHG_CNFG_06	= 0xBD,
+	MAX77843_CHG_REG_CHG_CNFG_07	= 0xBE,
+	MAX77843_CHG_REG_CHG_CNFG_09	= 0xC0,
+	MAX77843_CHG_REG_CHG_CNFG_10	= 0xC1,
+	MAX77843_CHG_REG_CHG_CNFG_11	= 0xC2,
+	MAX77843_CHG_REG_CHG_CNFG_12	= 0xC3,
+
+	MAX77843_CHG_REG_END,
+};
+
+/* Fuel gauge registers */
+enum max77843_fuelgauge {
+	MAX77843_FG_REG_STATUS		= 0x00,
+	MAX77843_FG_REG_VALRT_TH	= 0x01,
+	MAX77843_FG_REG_TALRT_TH	= 0x02,
+	MAX77843_FG_REG_SALRT_TH	= 0x03,
+	MAX77843_FG_RATE_AT_RATE	= 0x04,
+	MAX77843_FG_REG_REMCAP_REP	= 0x05,
+	MAX77843_FG_REG_SOCREP		= 0x06,
+	MAX77843_FG_REG_AGE		= 0x07,
+	MAX77843_FG_REG_TEMP		= 0x08,
+	MAX77843_FG_REG_VCELL		= 0x09,
+	MAX77843_FG_REG_CURRENT		= 0x0A,
+	MAX77843_FG_REG_AVG_CURRENT	= 0x0B,
+	MAX77843_FG_REG_SOCMIX		= 0x0D,
+	MAX77843_FG_REG_SOCAV		= 0x0E,
+	MAX77843_FG_REG_REMCAP_MIX	= 0x0F,
+	MAX77843_FG_REG_FULLCAP		= 0x10,
+	MAX77843_FG_REG_AVG_TEMP	= 0x16,
+	MAX77843_FG_REG_CYCLES		= 0x17,
+	MAX77843_FG_REG_AVG_VCELL	= 0x19,
+	MAX77843_FG_REG_CONFIG		= 0x1D,
+	MAX77843_FG_REG_REMCAP_AV	= 0x1F,
+	MAX77843_FG_REG_FULLCAP_NOM	= 0x23,
+	MAX77843_FG_REG_MISCCFG		= 0x2B,
+	MAX77843_FG_REG_RCOMP		= 0x38,
+	MAX77843_FG_REG_FSTAT		= 0x3D,
+	MAX77843_FG_REG_DQACC		= 0x45,
+	MAX77843_FG_REG_DPACC		= 0x46,
+	MAX77843_FG_REG_OCV		= 0xEE,
+	MAX77843_FG_REG_VFOCV		= 0xFB,
+	MAX77843_FG_SOCVF		= 0xFF,
+
+	MAX77843_FG_END,
+};
+
+/* Muic registers */
+enum max77843_muic_reg {
+	MAX77843_MUIC_REG_ID		= 0x00,
+	MAX77843_MUIC_REG_INT1		= 0x01,
+	MAX77843_MUIC_REG_INT2		= 0x02,
+	MAX77843_MUIC_REG_INT3		= 0x03,
+	MAX77843_MUIC_REG_STATUS1	= 0x04,
+	MAX77843_MUIC_REG_STATUS2	= 0x05,
+	MAX77843_MUIC_REG_STATUS3	= 0x06,
+	MAX77843_MUIC_REG_INTMASK1	= 0x07,
+	MAX77843_MUIC_REG_INTMASK2	= 0x08,
+	MAX77843_MUIC_REG_INTMASK3	= 0x09,
+	MAX77843_MUIC_REG_CDETCTRL1	= 0x0A,
+	MAX77843_MUIC_REG_CDETCTRL2	= 0x0B,
+	MAX77843_MUIC_REG_CONTROL1	= 0x0C,
+	MAX77843_MUIC_REG_CONTROL2	= 0x0D,
+	MAX77843_MUIC_REG_CONTROL3	= 0x0E,
+	MAX77843_MUIC_REG_CONTROL4	= 0x16,
+	MAX77843_MUIC_REG_HVCONTROL1	= 0x17,
+	MAX77843_MUIC_REG_HVCONTROL2	= 0x18,
+
+	MAX77843_MUIC_REG_END,
+};
+
+enum max77843_irq {
+	/* Topsys: SYSTEM */
+	MAX77843_SYS_IRQ_SYSINTSRC_SYSUVLO_INT,
+	MAX77843_SYS_IRQ_SYSINTSRC_SYSOVLO_INT,
+	MAX77843_SYS_IRQ_SYSINTSRC_TSHDN_INT,
+	MAX77843_SYS_IRQ_SYSINTSRC_TM_INT,
+
+	/* Charger: CHG_INT */
+	MAX77843_CHG_IRQ_CHG_INT_BYP_I,
+	MAX77843_CHG_IRQ_CHG_INT_BATP_I,
+	MAX77843_CHG_IRQ_CHG_INT_BAT_I,
+	MAX77843_CHG_IRQ_CHG_INT_CHG_I,
+	MAX77843_CHG_IRQ_CHG_INT_WCIN_I,
+	MAX77843_CHG_IRQ_CHG_INT_CHGIN_I,
+	MAX77843_CHG_IRQ_CHG_INT_AICL_I,
+
+	MAX77843_IRQ_NUM,
+};
+
+enum max77843_irq_muic {
+	/* MUIC: INT1 */
+	MAX77843_MUIC_IRQ_INT1_ADC,
+	MAX77843_MUIC_IRQ_INT1_ADCERROR,
+	MAX77843_MUIC_IRQ_INT1_ADC1K,
+
+	/* MUIC: INT2 */
+	MAX77843_MUIC_IRQ_INT2_CHGTYP,
+	MAX77843_MUIC_IRQ_INT2_CHGDETRUN,
+	MAX77843_MUIC_IRQ_INT2_DCDTMR,
+	MAX77843_MUIC_IRQ_INT2_DXOVP,
+	MAX77843_MUIC_IRQ_INT2_VBVOLT,
+
+	/* MUIC: INT3 */
+	MAX77843_MUIC_IRQ_INT3_VBADC,
+	MAX77843_MUIC_IRQ_INT3_VDNMON,
+	MAX77843_MUIC_IRQ_INT3_DNRES,
+	MAX77843_MUIC_IRQ_INT3_MPNACK,
+	MAX77843_MUIC_IRQ_INT3_MRXBUFOW,
+	MAX77843_MUIC_IRQ_INT3_MRXTRF,
+	MAX77843_MUIC_IRQ_INT3_MRXPERR,
+	MAX77843_MUIC_IRQ_INT3_MRXRDY,
+
+	MAX77843_MUIC_IRQ_NUM,
+};
+
+/* MAX77843 interrupts */
+#define MAX77843_SYS_IRQ_SYSUVLO_INT		BIT(0)
+#define MAX77843_SYS_IRQ_SYSOVLO_INT		BIT(1)
+#define MAX77843_SYS_IRQ_TSHDN_INT		BIT(2)
+#define MAX77843_SYS_IRQ_TM_INT			BIT(3)
+
+/* Max77843 charger insterrupts */
+#define MAX77843_CHG_BYP_I			BIT(0)
+#define MAX77843_CHG_BATP_I			BIT(2)
+#define MAX77843_CHG_BAT_I			BIT(3)
+#define MAX77843_CHG_CHG_I			BIT(4)
+#define MAX77843_CHG_WCIN_I			BIT(5)
+#define MAX77843_CHG_CHGIN_I			BIT(6)
+#define MAX77843_CHG_AICL_I			BIT(7)
+
+/* MAX77843 CHG_INT_OK register */
+#define MAX77843_CHG_BYP_OK			BIT(0)
+#define MAX77843_CHG_BATP_OK			BIT(2)
+#define MAX77843_CHG_BAT_OK			BIT(3)
+#define MAX77843_CHG_CHG_OK			BIT(4)
+#define MAX77843_CHG_WCIN_OK			BIT(5)
+#define MAX77843_CHG_CHGIN_OK			BIT(6)
+#define MAX77843_CHG_AICL_OK			BIT(7)
+
+/* MAX77843 CHG_DETAILS_00 register */
+#define MAX77843_CHG_BAT_DTLS			BIT(0)
+
+/* MAX77843 CHG_DETAILS_01 register */
+#define MAX77843_CHG_DTLS_MASK			0x0f
+#define MAX77843_CHG_PQ_MODE			0x00
+#define MAX77843_CHG_CC_MODE			0x01
+#define MAX77843_CHG_CV_MODE			0x02
+#define MAX77843_CHG_TO_MODE			0x03
+#define MAX77843_CHG_DO_MODE			0x04
+#define MAX77843_CHG_HT_MODE			0x05
+#define MAX77843_CHG_TF_MODE			0x06
+#define MAX77843_CHG_TS_MODE			0x07
+#define MAX77843_CHG_OFF_MODE			0x08
+
+#define MAX77843_CHG_BAT_DTLS_MASK		0xf0
+#define MAX77843_CHG_NO_BAT			(0x00 << 4)
+#define MAX77843_CHG_LOW_VOLT_BAT		(0x01 << 4)
+#define MAX77843_CHG_LONG_BAT_TIME		(0x02 << 4)
+#define MAX77843_CHG_OK_BAT			(0x03 << 4)
+#define MAX77843_CHG_OK_LOW_VOLT_BAT		(0x04 << 4)
+#define MAX77843_CHG_OVER_VOLT_BAT		(0x05 << 4)
+#define MAX77843_CHG_OVER_CURRENT_BAT		(0x06 << 4)
+
+/* MAX77843 CHG_CNFG_00 register */
+#define MAX77843_CHG_DISABLE			0x00
+#define MAX77843_CHG_ENABLE			0x05
+#define MAX77843_CHG_MASK			0x01
+#define MAX77843_CHG_BUCK_MASK			0x04
+
+/* MAX77843 CHG_CNFG_01 register */
+#define MAX77843_CHG_RESTART_THRESHOLD_100	0x00
+#define MAX77843_CHG_RESTART_THRESHOLD_150	0x10
+#define MAX77843_CHG_RESTART_THRESHOLD_200	0x20
+#define MAX77843_CHG_RESTART_THRESHOLD_DISABLE	0x30
+
+/* MAX77843 CHG_CNFG_02 register */
+#define MAX77843_CHG_FAST_CHG_CURRENT_MIN	100000
+#define MAX77843_CHG_FAST_CHG_CURRENT_MAX	3150000
+#define MAX77843_CHG_FAST_CHG_CURRENT_STEP	50000
+#define MAX77843_CHG_FAST_CHG_CURRENT_MASK	0x3f
+#define MAX77843_CHG_OTG_ILIMIT_500		(0x00 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_900		(0x01 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_1200		(0x02 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_1500		(0x03 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_MASK		0xc0
+
+/* MAX77843 CHG_CNFG_03 register */
+#define MAX77843_CHG_TOP_OFF_CURRENT_MIN	125000
+#define MAX77843_CHG_TOP_OFF_CURRENT_MAX	650000
+#define MAX77843_CHG_TOP_OFF_CURRENT_STEP	75000
+#define MAX77843_CHG_TOP_OFF_CURRENT_MASK	0x07
+
+/* MAX77843 CHG_CNFG_06 register */
+#define MAX77843_CHG_WRITE_CAP_BLOCK		0x10
+#define MAX77843_CHG_WRITE_CAP_UNBLOCK		0x0C
+
+/* MAX77843_CHG_CNFG_09_register */
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN	100000
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX	4000000
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_REF	3367000
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP	33000
+
+#define MAX77843_MUIC_ADC			BIT(0)
+#define MAX77843_MUIC_ADCERROR			BIT(2)
+#define MAX77843_MUIC_ADC1K			BIT(3)
+
+#define MAX77843_MUIC_CHGTYP			BIT(0)
+#define MAX77843_MUIC_CHGDETRUN			BIT(1)
+#define MAX77843_MUIC_DCDTMR			BIT(2)
+#define MAX77843_MUIC_DXOVP			BIT(3)
+#define MAX77843_MUIC_VBVOLT			BIT(4)
+
+#define MAX77843_MUIC_VBADC			BIT(0)
+#define MAX77843_MUIC_VDNMON			BIT(1)
+#define MAX77843_MUIC_DNRES			BIT(2)
+#define MAX77843_MUIC_MPNACK			BIT(3)
+#define MAX77843_MUIC_MRXBUFOW			BIT(4)
+#define MAX77843_MUIC_MRXTRF			BIT(5)
+#define MAX77843_MUIC_MRXPERR			BIT(6)
+#define MAX77843_MUIC_MRXRDY			BIT(7)
+
+/* MAX77843 INTSRCMASK register */
+#define MAX77843_INTSRCMASK_CHGR		0
+#define MAX77843_INTSRCMASK_SYS			1
+#define MAX77843_INTSRCMASK_FG			2
+#define MAX77843_INTSRCMASK_MUIC		3
+
+#define MAX77843_INTSRCMASK_CHGR_MASK          BIT(MAX77843_INTSRCMASK_CHGR)
+#define MAX77843_INTSRCMASK_SYS_MASK           BIT(MAX77843_INTSRCMASK_SYS)
+#define MAX77843_INTSRCMASK_FG_MASK            BIT(MAX77843_INTSRCMASK_FG)
+#define MAX77843_INTSRCMASK_MUIC_MASK          BIT(MAX77843_INTSRCMASK_MUIC)
+
+#define MAX77843_INTSRC_MASK_MASK \
+		(MAX77843_INTSRCMASK_MUIC_MASK | MAX77843_INTSRCMASK_FG_MASK | \
+		MAX77843_INTSRCMASK_SYS_MASK | MAX77843_INTSRCMASK_CHGR_MASK)
+
+/* MAX77843 STATUS register*/
+#define STATUS1_ADC_SHIFT			0
+#define STATUS1_ADCERROR_SHIFT			6
+#define STATUS1_ADC1K_SHIFT			7
+#define STATUS2_CHGTYP_SHIFT			0
+#define STATUS2_CHGDETRUN_SHIFT			3
+#define STATUS2_DCDTMR_SHIFT			4
+#define STATUS2_DXOVP_SHIFT			5
+#define STATUS2_VBVOLT_SHIFT			6
+#define STATUS3_VBADC_SHIFT			0
+#define STATUS3_VDNMON_SHIFT			4
+#define STATUS3_DNRES_SHIFT			5
+#define STATUS3_MPNACK_SHIFT			6
+
+#define MAX77843_MUIC_STATUS1_ADC_MASK		(0x1f << STATUS1_ADC_SHIFT)
+#define MAX77843_MUIC_STATUS1_ADCERROR_MASK	BIT(STATUS1_ADCERROR_SHIFT)
+#define MAX77843_MUIC_STATUS1_ADC1K_MASK	BIT(STATUS1_ADC1K_SHIFT)
+#define MAX77843_MUIC_STATUS2_CHGTYP_MASK	(0x7 << STATUS2_CHGTYP_SHIFT)
+#define MAX77843_MUIC_STATUS2_CHGDETRUN_MASK	BIT(STATUS2_CHGDETRUN_SHIFT)
+#define MAX77843_MUIC_STATUS2_DCDTMR_MASK	BIT(STATUS2_DCDTMR_SHIFT)
+#define MAX77843_MUIC_STATUS2_DXOVP_MASK	BIT(STATUS2_DXOVP_SHIFT)
+#define MAX77843_MUIC_STATUS2_VBVOLT_MASK	BIT(STATUS2_VBVOLT_SHIFT)
+#define MAX77843_MUIC_STATUS3_VBADC_MASK	(0xf << STATUS3_VBADC_SHIFT)
+#define MAX77843_MUIC_STATUS3_VDNMON_MASK	BIT(STATUS3_VDNMON_SHIFT)
+#define MAX77843_MUIC_STATUS3_DNRES_MASK	BIT(STATUS3_DNRES_SHIFT)
+#define MAX77843_MUIC_STATUS3_MPNACK_MASK	BIT(STATUS3_MPNACK_SHIFT)
+
+/* MAX77843 CONTROL register */
+#define CONTROL1_COMP1SW_SHIFT			0
+#define CONTROL1_COMP2SW_SHIFT			3
+#define CONTROL1_IDBEN_SHIFT			7
+#define CONTROL2_LOWPWR_SHIFT			0
+#define CONTROL2_ADCEN_SHIFT			1
+#define CONTROL2_CPEN_SHIFT			2
+#define CONTROL2_ACC_DET_SHIFT			5
+#define CONTROL2_USBCPINT_SHIFT			6
+#define CONTROL2_RCPS_SHIFT			7
+#define CONTROL3_JIGSET_SHIFT			0
+#define CONTROL4_ADCDBSET_SHIFT			0
+#define CONTROL4_USBAUTO_SHIFT			4
+#define CONTROL4_FCTAUTO_SHIFT			5
+#define CONTROL4_ADCMODE_SHIFT			6
+
+#define MAX77843_MUIC_CONTROL1_COMP1SW_MASK	(0x7 << CONTROL1_COMP1SW_SHIFT)
+#define MAX77843_MUIC_CONTROL1_COMP2SW_MASK	(0x7 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_MUIC_CONTROL1_IDBEN_MASK	BIT(CONTROL1_IDBEN_SHIFT)
+#define MAX77843_MUIC_CONTROL2_LOWPWR_MASK	BIT(CONTROL2_LOWPWR_SHIFT)
+#define MAX77843_MUIC_CONTROL2_ADCEN_MASK	BIT(CONTROL2_ADCEN_SHIFT)
+#define MAX77843_MUIC_CONTROL2_CPEN_MASK	BIT(CONTROL2_CPEN_SHIFT)
+#define MAX77843_MUIC_CONTROL2_ACC_DET_MASK	BIT(CONTROL2_ACC_DET_SHIFT)
+#define MAX77843_MUIC_CONTROL2_USBCPINT_MASK	BIT(CONTROL2_USBCPINT_SHIFT)
+#define MAX77843_MUIC_CONTROL2_RCPS_MASK	BIT(CONTROL2_RCPS_SHIFT)
+#define MAX77843_MUIC_CONTROL3_JIGSET_MASK	(0x3 << CONTROL3_JIGSET_SHIFT)
+#define MAX77843_MUIC_CONTROL4_ADCDBSET_MASK	(0x3 << CONTROL4_ADCDBSET_SHIFT)
+#define MAX77843_MUIC_CONTROL4_USBAUTO_MASK	BIT(CONTROL4_USBAUTO_SHIFT)
+#define MAX77843_MUIC_CONTROL4_FCTAUTO_MASK	BIT(CONTROL4_FCTAUTO_SHIFT)
+#define MAX77843_MUIC_CONTROL4_ADCMODE_MASK	(0x3 << CONTROL4_ADCMODE_SHIFT)
+
+/* MAX77843 switch port */
+#define MAX77843_SIWTH_PORT \
+(MAX77843_MUIC_CONTROL1_COMP1SW_MASK | MAX77843_MUIC_CONTROL1_COMP2SW_MASK)
+
+#define MAX77843_SWITCH_OPEN \
+		(0 << CONTROL1_COMP1SW_SHIFT | 0 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_USB \
+		(1 << CONTROL1_COMP1SW_SHIFT | 1 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_AUDIO \
+		(2 << CONTROL1_COMP1SW_SHIFT | 2 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_UART \
+		(3 << CONTROL1_COMP1SW_SHIFT | 3 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_AUX_USB \
+		(4 << CONTROL1_COMP1SW_SHIFT | 4 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_AUX_UART \
+		(5 << CONTROL1_COMP1SW_SHIFT | 5 << CONTROL1_COMP2SW_SHIFT)
+
+/* MAX77843 SAFEOUT LDO Control register */
+#define SAFEOUTCTRL_SAFEOUT1_SHIFT		0
+#define SAFEOUTCTRL_SAFEOUT2_SHIFT		2
+#define SAFEOUTCTRL_ENSAFEOUT1_SHIFT		6
+#define SAFEOUTCTRL_ENSAFEOUT2_SHIFT		7
+
+#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1 \
+		BIT(SAFEOUTCTRL_ENSAFEOUT1_SHIFT)
+#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2 \
+		BIT(SAFEOUTCTRL_ENSAFEOUT2_SHIFT)
+#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK \
+		(0x3 << SAFEOUTCTRL_SAFEOUT1_SHIFT)
+#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK \
+		(0x3 << SAFEOUTCTRL_SAFEOUT2_SHIFT)
+
+struct max77843 {
+	struct device *dev;
+
+	struct i2c_client *i2c;
+	struct i2c_client *i2c_chg;
+	struct i2c_client *i2c_fuel;
+	struct i2c_client *i2c_muic;
+
+	struct regmap *regmap;
+	struct regmap *regmap_chg;
+	struct regmap *regmap_fuel;
+	struct regmap *regmap_muic;
+
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap_irq_chip_data *irq_data_chg;
+	struct regmap_irq_chip_data *irq_data_fuel;
+	struct regmap_irq_chip_data *irq_data_muic;
+
+	int irq;
+};
+#endif /* __MAX77843_H__ */
-- 
1.7.9.5


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

* [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  5:02   ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo, Jaewon Kim

This patch adds MAX77843 core/irq driver to support PMIC,
MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
LED and Haptic device.

Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 drivers/mfd/Kconfig                  |   14 ++
 drivers/mfd/Makefile                 |    1 +
 drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
 include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
 4 files changed, 666 insertions(+)
 create mode 100644 drivers/mfd/max77843.c
 create mode 100644 include/linux/mfd/max77843-private.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2e6b731..0c67c79 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -442,6 +442,20 @@ config MFD_MAX77693
 	  additional drivers must be enabled in order to use the functionality
 	  of the device.
 
+config MFD_MAX77843
+	bool "Maxim Semiconductor MAX77843 PMIC Support"
+	depends on I2C=y
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	help
+	  Say yes here to add support for Maxim Semiconductor MAX77843.
+	  This is companion Power Management IC with LEDs, Haptic, Charger,
+	  Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
+	  This driver provides common support for accessing the device;
+	  additional drivers must be enabled in order to use the functionality
+	  of the device.
+
 config MFD_MAX8907
 	tristate "Maxim Semiconductor MAX8907 PMIC Support"
 	select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 53467e2..fe4f75c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
 obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
 obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
 obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
+obj-$(CONFIG_MFD_MAX77843)	+= max77843.o
 obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
 max8925-objs			:= max8925-core.o max8925-i2c.o
 obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
new file mode 100644
index 0000000..d7f8b76
--- /dev/null
+++ b/drivers/mfd/max77843.c
@@ -0,0 +1,241 @@
+/*
+ * max77843.c - MFD core driver for the Maxim MAX77843
+ *
+ * Copyright (C) 2014 Samsung Electrnoics
+ * Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max77843-private.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+static const struct mfd_cell max77843_devs[] = {
+	{
+		.name = "max77843-muic",
+		.of_compatible = "maxim,max77843-muic",
+	}, {
+		.name = "max77843-regulator",
+		.of_compatible = "maxim,max77843-regulator",
+	}, {
+		.name = "max77843-charger",
+		.of_compatible = "maxim,max77843-charger"
+	}, {
+		.name = "max77843-fuelgauge",
+		.of_compatible = "maxim,max77843-fuelgauge",
+	},
+};
+
+static const struct regmap_config max77843_charger_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= MAX77843_CHG_REG_END,
+};
+
+static const struct regmap_config max77843_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= MAX77843_SYS_REG_END,
+};
+
+static const struct regmap_irq max77843_irqs[] = {
+	/* TOPSYS interrupts */
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
+	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
+};
+
+static const struct regmap_irq_chip max77843_irq_chip = {
+	.name		= "max77843",
+	.status_base	= MAX77843_SYS_REG_SYSINTSRC,
+	.mask_base	= MAX77843_SYS_REG_SYSINTMASK,
+	.mask_invert	= false,
+	.num_regs	= 1,
+	.irqs		= max77843_irqs,
+	.num_irqs	= ARRAY_SIZE(max77843_irqs),
+};
+
+static int max77843_chg_init(struct max77843 *max77843)
+{
+	int ret;
+
+	max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
+	if (!max77843->i2c_chg) {
+		dev_err(&max77843->i2c->dev,
+				"Cannot allocate I2C device for Charger\n");
+		return PTR_ERR(max77843->i2c_chg);
+	}
+	i2c_set_clientdata(max77843->i2c_chg, max77843);
+
+	max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
+			&max77843_charger_regmap_config);
+	if (IS_ERR(max77843->regmap_chg)) {
+		ret = PTR_ERR(max77843->regmap_chg);
+		goto err_chg_i2c;
+	}
+
+	return 0;
+
+err_chg_i2c:
+	i2c_unregister_device(max77843->i2c_chg);
+
+	return ret;
+}
+
+static int max77843_probe(struct i2c_client *i2c,
+					const struct i2c_device_id *id)
+{
+	struct max77843 *max77843;
+	int ret;
+	unsigned int reg_data;
+
+	max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
+	if (!max77843)
+		return -ENOMEM;
+
+	i2c_set_clientdata(i2c, max77843);
+	max77843->dev = &i2c->dev;
+	max77843->i2c = i2c;
+	max77843->irq = i2c->irq;
+
+	max77843->regmap = devm_regmap_init_i2c(i2c,
+			&max77843_regmap_config);
+	if (IS_ERR(max77843->regmap)) {
+		dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
+		return PTR_ERR(max77843->regmap);
+	}
+
+	ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
+			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
+			0, &max77843_irq_chip, &max77843->irq_data);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
+		return ret;
+	}
+
+	ret = regmap_read(max77843->regmap,
+			MAX77843_SYS_REG_PMICID, &reg_data);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to read PMIC ID\n");
+		goto err_pmic_id;
+	}
+	dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
+
+	ret = max77843_chg_init(max77843);
+	if (ret) {
+		dev_err(&i2c->dev, "Failed to init Charger\n");
+		goto err_pmic_id;
+	}
+
+	ret = regmap_update_bits(max77843->regmap,
+			MAX77843_SYS_REG_INTSRCMASK,
+			MAX77843_INTSRC_MASK_MASK,
+			(unsigned int)~MAX77843_INTSRC_MASK_MASK);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
+		goto err_pmic_id;
+	}
+
+	ret = mfd_add_devices(max77843->dev, -1, max77843_devs,
+			ARRAY_SIZE(max77843_devs), NULL, 0, NULL);
+	if (ret < 0) {
+		dev_err(&i2c->dev, "Failed to add mfd device\n");
+		goto err_pmic_id;
+	}
+
+	device_init_wakeup(max77843->dev, 1);
+
+	return 0;
+
+err_pmic_id:
+	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
+
+	return ret;
+}
+
+static int max77843_remove(struct i2c_client *i2c)
+{
+	struct max77843 *max77843 = i2c_get_clientdata(i2c);
+
+	mfd_remove_devices(max77843->dev);
+
+	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
+
+	i2c_unregister_device(max77843->i2c);
+
+	return 0;
+}
+
+static const struct of_device_id max77843_dt_match[] = {
+	{ .compatible = "maxim,max77843", },
+	{ /* sentinel */ },
+};
+
+static const struct i2c_device_id max77843_id[] = {
+	{ "max77843", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(i2c, max77843_id);
+
+static int __maybe_unused max77843_suspend(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77843 *max77843 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		enable_irq_wake(max77843->irq);
+	disable_irq(max77843->irq);
+
+	return 0;
+}
+
+static int __maybe_unused max77843_resume(struct device *dev)
+{
+	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
+	struct max77843 *max77843 = i2c_get_clientdata(i2c);
+
+	if (device_may_wakeup(dev))
+		disable_irq_wake(max77843->irq);
+	enable_irq(max77843->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(max77843_pm, max77843_suspend, max77843_resume);
+
+static struct i2c_driver max77843_i2c_driver = {
+	.driver		= {
+		.name		= "max77843",
+		.pm		= &max77843_pm,
+		.of_match_table = max77843_dt_match,
+	},
+	.probe		= max77843_probe,
+	.remove		= max77843_remove,
+	.id_table	= max77843_id,
+};
+static int __init max77843_i2c_init(void)
+{
+	return i2c_add_driver(&max77843_i2c_driver);
+}
+subsys_initcall(max77843_i2c_init);
+
+static void __exit max77843_i2c_exit(void)
+{
+	i2c_del_driver(&max77843_i2c_driver);
+}
+module_exit(max77843_i2c_exit);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
+MODULE_DESCRIPTION("Maxim MAX77843 multi-function core driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h
new file mode 100644
index 0000000..560ed73
--- /dev/null
+++ b/include/linux/mfd/max77843-private.h
@@ -0,0 +1,410 @@
+/*
+ * max77843-private.h - Common API for the Maxim MAX77843 internal sub chip
+ *
+ * Copyright (C) 2014 Samsung Electrnoics
+ * Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __MAX77843_PRIVATE_H_
+#define __MAX77843_PRIVATE_H_
+
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#define I2C_ADDR_TOPSYS	(0xCC >> 1)
+#define I2C_ADDR_CHG	(0xD2 >> 1)
+#define I2C_ADDR_FG	(0x6C >> 1)
+#define I2C_ADDR_MUIC	(0x4A >> 1)
+
+/* Topsys, Haptic and LED registers */
+enum max77843_sys_reg {
+	MAX77843_SYS_REG_PMICID		= 0x00,
+	MAX77843_SYS_REG_PMICREV	= 0x01,
+	MAX77843_SYS_REG_MAINCTRL1	= 0x02,
+	MAX77843_SYS_REG_INTSRC		= 0x22,
+	MAX77843_SYS_REG_INTSRCMASK	= 0x23,
+	MAX77843_SYS_REG_SYSINTSRC	= 0x24,
+	MAX77843_SYS_REG_SYSINTMASK	= 0x26,
+	MAX77843_SYS_REG_TOPSYS_STAT	= 0x28,
+	MAX77843_SYS_REG_SAFEOUTCTRL	= 0xC6,
+
+	MAX77843_SYS_REG_END,
+};
+
+enum max77843_led_reg {
+	MAX77843_LED_REG_LEDEN		= 0x30,
+	MAX77843_LED_REG_LED0BRT	= 0x31,
+	MAX77843_LED_REG_LED1BRT	= 0x32,
+	MAX77843_LED_REG_LED2BRT	= 0x33,
+	MAX77843_LED_REG_LED3BRT	= 0x34,
+	MAX77843_LED_REG_LEDBLNK	= 0x38,
+	MAX77843_LED_REG_LEDRAMP	= 0x36,
+
+	MAX77843_LED_REG_END,
+};
+
+/* Charger registers */
+enum max77843_charger_reg {
+	MAX77843_CHG_REG_CHG_INT	= 0xB0,
+	MAX77843_CHG_REG_CHG_INT_MASK	= 0xB1,
+	MAX77843_CHG_REG_CHG_INT_OK	= 0xB2,
+	MAX77843_CHG_REG_CHG_DTLS_00	= 0xB3,
+	MAX77843_CHG_REG_CHG_DTLS_01	= 0xB4,
+	MAX77843_CHG_REG_CHG_DTLS_02	= 0xB5,
+	MAX77843_CHG_REG_CHG_CNFG_00	= 0xB7,
+	MAX77843_CHG_REG_CHG_CNFG_01	= 0xB8,
+	MAX77843_CHG_REG_CHG_CNFG_02	= 0xB9,
+	MAX77843_CHG_REG_CHG_CNFG_03	= 0xBA,
+	MAX77843_CHG_REG_CHG_CNFG_04	= 0xBB,
+	MAX77843_CHG_REG_CHG_CNFG_06	= 0xBD,
+	MAX77843_CHG_REG_CHG_CNFG_07	= 0xBE,
+	MAX77843_CHG_REG_CHG_CNFG_09	= 0xC0,
+	MAX77843_CHG_REG_CHG_CNFG_10	= 0xC1,
+	MAX77843_CHG_REG_CHG_CNFG_11	= 0xC2,
+	MAX77843_CHG_REG_CHG_CNFG_12	= 0xC3,
+
+	MAX77843_CHG_REG_END,
+};
+
+/* Fuel gauge registers */
+enum max77843_fuelgauge {
+	MAX77843_FG_REG_STATUS		= 0x00,
+	MAX77843_FG_REG_VALRT_TH	= 0x01,
+	MAX77843_FG_REG_TALRT_TH	= 0x02,
+	MAX77843_FG_REG_SALRT_TH	= 0x03,
+	MAX77843_FG_RATE_AT_RATE	= 0x04,
+	MAX77843_FG_REG_REMCAP_REP	= 0x05,
+	MAX77843_FG_REG_SOCREP		= 0x06,
+	MAX77843_FG_REG_AGE		= 0x07,
+	MAX77843_FG_REG_TEMP		= 0x08,
+	MAX77843_FG_REG_VCELL		= 0x09,
+	MAX77843_FG_REG_CURRENT		= 0x0A,
+	MAX77843_FG_REG_AVG_CURRENT	= 0x0B,
+	MAX77843_FG_REG_SOCMIX		= 0x0D,
+	MAX77843_FG_REG_SOCAV		= 0x0E,
+	MAX77843_FG_REG_REMCAP_MIX	= 0x0F,
+	MAX77843_FG_REG_FULLCAP		= 0x10,
+	MAX77843_FG_REG_AVG_TEMP	= 0x16,
+	MAX77843_FG_REG_CYCLES		= 0x17,
+	MAX77843_FG_REG_AVG_VCELL	= 0x19,
+	MAX77843_FG_REG_CONFIG		= 0x1D,
+	MAX77843_FG_REG_REMCAP_AV	= 0x1F,
+	MAX77843_FG_REG_FULLCAP_NOM	= 0x23,
+	MAX77843_FG_REG_MISCCFG		= 0x2B,
+	MAX77843_FG_REG_RCOMP		= 0x38,
+	MAX77843_FG_REG_FSTAT		= 0x3D,
+	MAX77843_FG_REG_DQACC		= 0x45,
+	MAX77843_FG_REG_DPACC		= 0x46,
+	MAX77843_FG_REG_OCV		= 0xEE,
+	MAX77843_FG_REG_VFOCV		= 0xFB,
+	MAX77843_FG_SOCVF		= 0xFF,
+
+	MAX77843_FG_END,
+};
+
+/* Muic registers */
+enum max77843_muic_reg {
+	MAX77843_MUIC_REG_ID		= 0x00,
+	MAX77843_MUIC_REG_INT1		= 0x01,
+	MAX77843_MUIC_REG_INT2		= 0x02,
+	MAX77843_MUIC_REG_INT3		= 0x03,
+	MAX77843_MUIC_REG_STATUS1	= 0x04,
+	MAX77843_MUIC_REG_STATUS2	= 0x05,
+	MAX77843_MUIC_REG_STATUS3	= 0x06,
+	MAX77843_MUIC_REG_INTMASK1	= 0x07,
+	MAX77843_MUIC_REG_INTMASK2	= 0x08,
+	MAX77843_MUIC_REG_INTMASK3	= 0x09,
+	MAX77843_MUIC_REG_CDETCTRL1	= 0x0A,
+	MAX77843_MUIC_REG_CDETCTRL2	= 0x0B,
+	MAX77843_MUIC_REG_CONTROL1	= 0x0C,
+	MAX77843_MUIC_REG_CONTROL2	= 0x0D,
+	MAX77843_MUIC_REG_CONTROL3	= 0x0E,
+	MAX77843_MUIC_REG_CONTROL4	= 0x16,
+	MAX77843_MUIC_REG_HVCONTROL1	= 0x17,
+	MAX77843_MUIC_REG_HVCONTROL2	= 0x18,
+
+	MAX77843_MUIC_REG_END,
+};
+
+enum max77843_irq {
+	/* Topsys: SYSTEM */
+	MAX77843_SYS_IRQ_SYSINTSRC_SYSUVLO_INT,
+	MAX77843_SYS_IRQ_SYSINTSRC_SYSOVLO_INT,
+	MAX77843_SYS_IRQ_SYSINTSRC_TSHDN_INT,
+	MAX77843_SYS_IRQ_SYSINTSRC_TM_INT,
+
+	/* Charger: CHG_INT */
+	MAX77843_CHG_IRQ_CHG_INT_BYP_I,
+	MAX77843_CHG_IRQ_CHG_INT_BATP_I,
+	MAX77843_CHG_IRQ_CHG_INT_BAT_I,
+	MAX77843_CHG_IRQ_CHG_INT_CHG_I,
+	MAX77843_CHG_IRQ_CHG_INT_WCIN_I,
+	MAX77843_CHG_IRQ_CHG_INT_CHGIN_I,
+	MAX77843_CHG_IRQ_CHG_INT_AICL_I,
+
+	MAX77843_IRQ_NUM,
+};
+
+enum max77843_irq_muic {
+	/* MUIC: INT1 */
+	MAX77843_MUIC_IRQ_INT1_ADC,
+	MAX77843_MUIC_IRQ_INT1_ADCERROR,
+	MAX77843_MUIC_IRQ_INT1_ADC1K,
+
+	/* MUIC: INT2 */
+	MAX77843_MUIC_IRQ_INT2_CHGTYP,
+	MAX77843_MUIC_IRQ_INT2_CHGDETRUN,
+	MAX77843_MUIC_IRQ_INT2_DCDTMR,
+	MAX77843_MUIC_IRQ_INT2_DXOVP,
+	MAX77843_MUIC_IRQ_INT2_VBVOLT,
+
+	/* MUIC: INT3 */
+	MAX77843_MUIC_IRQ_INT3_VBADC,
+	MAX77843_MUIC_IRQ_INT3_VDNMON,
+	MAX77843_MUIC_IRQ_INT3_DNRES,
+	MAX77843_MUIC_IRQ_INT3_MPNACK,
+	MAX77843_MUIC_IRQ_INT3_MRXBUFOW,
+	MAX77843_MUIC_IRQ_INT3_MRXTRF,
+	MAX77843_MUIC_IRQ_INT3_MRXPERR,
+	MAX77843_MUIC_IRQ_INT3_MRXRDY,
+
+	MAX77843_MUIC_IRQ_NUM,
+};
+
+/* MAX77843 interrupts */
+#define MAX77843_SYS_IRQ_SYSUVLO_INT		BIT(0)
+#define MAX77843_SYS_IRQ_SYSOVLO_INT		BIT(1)
+#define MAX77843_SYS_IRQ_TSHDN_INT		BIT(2)
+#define MAX77843_SYS_IRQ_TM_INT			BIT(3)
+
+/* Max77843 charger insterrupts */
+#define MAX77843_CHG_BYP_I			BIT(0)
+#define MAX77843_CHG_BATP_I			BIT(2)
+#define MAX77843_CHG_BAT_I			BIT(3)
+#define MAX77843_CHG_CHG_I			BIT(4)
+#define MAX77843_CHG_WCIN_I			BIT(5)
+#define MAX77843_CHG_CHGIN_I			BIT(6)
+#define MAX77843_CHG_AICL_I			BIT(7)
+
+/* MAX77843 CHG_INT_OK register */
+#define MAX77843_CHG_BYP_OK			BIT(0)
+#define MAX77843_CHG_BATP_OK			BIT(2)
+#define MAX77843_CHG_BAT_OK			BIT(3)
+#define MAX77843_CHG_CHG_OK			BIT(4)
+#define MAX77843_CHG_WCIN_OK			BIT(5)
+#define MAX77843_CHG_CHGIN_OK			BIT(6)
+#define MAX77843_CHG_AICL_OK			BIT(7)
+
+/* MAX77843 CHG_DETAILS_00 register */
+#define MAX77843_CHG_BAT_DTLS			BIT(0)
+
+/* MAX77843 CHG_DETAILS_01 register */
+#define MAX77843_CHG_DTLS_MASK			0x0f
+#define MAX77843_CHG_PQ_MODE			0x00
+#define MAX77843_CHG_CC_MODE			0x01
+#define MAX77843_CHG_CV_MODE			0x02
+#define MAX77843_CHG_TO_MODE			0x03
+#define MAX77843_CHG_DO_MODE			0x04
+#define MAX77843_CHG_HT_MODE			0x05
+#define MAX77843_CHG_TF_MODE			0x06
+#define MAX77843_CHG_TS_MODE			0x07
+#define MAX77843_CHG_OFF_MODE			0x08
+
+#define MAX77843_CHG_BAT_DTLS_MASK		0xf0
+#define MAX77843_CHG_NO_BAT			(0x00 << 4)
+#define MAX77843_CHG_LOW_VOLT_BAT		(0x01 << 4)
+#define MAX77843_CHG_LONG_BAT_TIME		(0x02 << 4)
+#define MAX77843_CHG_OK_BAT			(0x03 << 4)
+#define MAX77843_CHG_OK_LOW_VOLT_BAT		(0x04 << 4)
+#define MAX77843_CHG_OVER_VOLT_BAT		(0x05 << 4)
+#define MAX77843_CHG_OVER_CURRENT_BAT		(0x06 << 4)
+
+/* MAX77843 CHG_CNFG_00 register */
+#define MAX77843_CHG_DISABLE			0x00
+#define MAX77843_CHG_ENABLE			0x05
+#define MAX77843_CHG_MASK			0x01
+#define MAX77843_CHG_BUCK_MASK			0x04
+
+/* MAX77843 CHG_CNFG_01 register */
+#define MAX77843_CHG_RESTART_THRESHOLD_100	0x00
+#define MAX77843_CHG_RESTART_THRESHOLD_150	0x10
+#define MAX77843_CHG_RESTART_THRESHOLD_200	0x20
+#define MAX77843_CHG_RESTART_THRESHOLD_DISABLE	0x30
+
+/* MAX77843 CHG_CNFG_02 register */
+#define MAX77843_CHG_FAST_CHG_CURRENT_MIN	100000
+#define MAX77843_CHG_FAST_CHG_CURRENT_MAX	3150000
+#define MAX77843_CHG_FAST_CHG_CURRENT_STEP	50000
+#define MAX77843_CHG_FAST_CHG_CURRENT_MASK	0x3f
+#define MAX77843_CHG_OTG_ILIMIT_500		(0x00 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_900		(0x01 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_1200		(0x02 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_1500		(0x03 << 6)
+#define MAX77843_CHG_OTG_ILIMIT_MASK		0xc0
+
+/* MAX77843 CHG_CNFG_03 register */
+#define MAX77843_CHG_TOP_OFF_CURRENT_MIN	125000
+#define MAX77843_CHG_TOP_OFF_CURRENT_MAX	650000
+#define MAX77843_CHG_TOP_OFF_CURRENT_STEP	75000
+#define MAX77843_CHG_TOP_OFF_CURRENT_MASK	0x07
+
+/* MAX77843 CHG_CNFG_06 register */
+#define MAX77843_CHG_WRITE_CAP_BLOCK		0x10
+#define MAX77843_CHG_WRITE_CAP_UNBLOCK		0x0C
+
+/* MAX77843_CHG_CNFG_09_register */
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN	100000
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX	4000000
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_REF	3367000
+#define MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP	33000
+
+#define MAX77843_MUIC_ADC			BIT(0)
+#define MAX77843_MUIC_ADCERROR			BIT(2)
+#define MAX77843_MUIC_ADC1K			BIT(3)
+
+#define MAX77843_MUIC_CHGTYP			BIT(0)
+#define MAX77843_MUIC_CHGDETRUN			BIT(1)
+#define MAX77843_MUIC_DCDTMR			BIT(2)
+#define MAX77843_MUIC_DXOVP			BIT(3)
+#define MAX77843_MUIC_VBVOLT			BIT(4)
+
+#define MAX77843_MUIC_VBADC			BIT(0)
+#define MAX77843_MUIC_VDNMON			BIT(1)
+#define MAX77843_MUIC_DNRES			BIT(2)
+#define MAX77843_MUIC_MPNACK			BIT(3)
+#define MAX77843_MUIC_MRXBUFOW			BIT(4)
+#define MAX77843_MUIC_MRXTRF			BIT(5)
+#define MAX77843_MUIC_MRXPERR			BIT(6)
+#define MAX77843_MUIC_MRXRDY			BIT(7)
+
+/* MAX77843 INTSRCMASK register */
+#define MAX77843_INTSRCMASK_CHGR		0
+#define MAX77843_INTSRCMASK_SYS			1
+#define MAX77843_INTSRCMASK_FG			2
+#define MAX77843_INTSRCMASK_MUIC		3
+
+#define MAX77843_INTSRCMASK_CHGR_MASK          BIT(MAX77843_INTSRCMASK_CHGR)
+#define MAX77843_INTSRCMASK_SYS_MASK           BIT(MAX77843_INTSRCMASK_SYS)
+#define MAX77843_INTSRCMASK_FG_MASK            BIT(MAX77843_INTSRCMASK_FG)
+#define MAX77843_INTSRCMASK_MUIC_MASK          BIT(MAX77843_INTSRCMASK_MUIC)
+
+#define MAX77843_INTSRC_MASK_MASK \
+		(MAX77843_INTSRCMASK_MUIC_MASK | MAX77843_INTSRCMASK_FG_MASK | \
+		MAX77843_INTSRCMASK_SYS_MASK | MAX77843_INTSRCMASK_CHGR_MASK)
+
+/* MAX77843 STATUS register*/
+#define STATUS1_ADC_SHIFT			0
+#define STATUS1_ADCERROR_SHIFT			6
+#define STATUS1_ADC1K_SHIFT			7
+#define STATUS2_CHGTYP_SHIFT			0
+#define STATUS2_CHGDETRUN_SHIFT			3
+#define STATUS2_DCDTMR_SHIFT			4
+#define STATUS2_DXOVP_SHIFT			5
+#define STATUS2_VBVOLT_SHIFT			6
+#define STATUS3_VBADC_SHIFT			0
+#define STATUS3_VDNMON_SHIFT			4
+#define STATUS3_DNRES_SHIFT			5
+#define STATUS3_MPNACK_SHIFT			6
+
+#define MAX77843_MUIC_STATUS1_ADC_MASK		(0x1f << STATUS1_ADC_SHIFT)
+#define MAX77843_MUIC_STATUS1_ADCERROR_MASK	BIT(STATUS1_ADCERROR_SHIFT)
+#define MAX77843_MUIC_STATUS1_ADC1K_MASK	BIT(STATUS1_ADC1K_SHIFT)
+#define MAX77843_MUIC_STATUS2_CHGTYP_MASK	(0x7 << STATUS2_CHGTYP_SHIFT)
+#define MAX77843_MUIC_STATUS2_CHGDETRUN_MASK	BIT(STATUS2_CHGDETRUN_SHIFT)
+#define MAX77843_MUIC_STATUS2_DCDTMR_MASK	BIT(STATUS2_DCDTMR_SHIFT)
+#define MAX77843_MUIC_STATUS2_DXOVP_MASK	BIT(STATUS2_DXOVP_SHIFT)
+#define MAX77843_MUIC_STATUS2_VBVOLT_MASK	BIT(STATUS2_VBVOLT_SHIFT)
+#define MAX77843_MUIC_STATUS3_VBADC_MASK	(0xf << STATUS3_VBADC_SHIFT)
+#define MAX77843_MUIC_STATUS3_VDNMON_MASK	BIT(STATUS3_VDNMON_SHIFT)
+#define MAX77843_MUIC_STATUS3_DNRES_MASK	BIT(STATUS3_DNRES_SHIFT)
+#define MAX77843_MUIC_STATUS3_MPNACK_MASK	BIT(STATUS3_MPNACK_SHIFT)
+
+/* MAX77843 CONTROL register */
+#define CONTROL1_COMP1SW_SHIFT			0
+#define CONTROL1_COMP2SW_SHIFT			3
+#define CONTROL1_IDBEN_SHIFT			7
+#define CONTROL2_LOWPWR_SHIFT			0
+#define CONTROL2_ADCEN_SHIFT			1
+#define CONTROL2_CPEN_SHIFT			2
+#define CONTROL2_ACC_DET_SHIFT			5
+#define CONTROL2_USBCPINT_SHIFT			6
+#define CONTROL2_RCPS_SHIFT			7
+#define CONTROL3_JIGSET_SHIFT			0
+#define CONTROL4_ADCDBSET_SHIFT			0
+#define CONTROL4_USBAUTO_SHIFT			4
+#define CONTROL4_FCTAUTO_SHIFT			5
+#define CONTROL4_ADCMODE_SHIFT			6
+
+#define MAX77843_MUIC_CONTROL1_COMP1SW_MASK	(0x7 << CONTROL1_COMP1SW_SHIFT)
+#define MAX77843_MUIC_CONTROL1_COMP2SW_MASK	(0x7 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_MUIC_CONTROL1_IDBEN_MASK	BIT(CONTROL1_IDBEN_SHIFT)
+#define MAX77843_MUIC_CONTROL2_LOWPWR_MASK	BIT(CONTROL2_LOWPWR_SHIFT)
+#define MAX77843_MUIC_CONTROL2_ADCEN_MASK	BIT(CONTROL2_ADCEN_SHIFT)
+#define MAX77843_MUIC_CONTROL2_CPEN_MASK	BIT(CONTROL2_CPEN_SHIFT)
+#define MAX77843_MUIC_CONTROL2_ACC_DET_MASK	BIT(CONTROL2_ACC_DET_SHIFT)
+#define MAX77843_MUIC_CONTROL2_USBCPINT_MASK	BIT(CONTROL2_USBCPINT_SHIFT)
+#define MAX77843_MUIC_CONTROL2_RCPS_MASK	BIT(CONTROL2_RCPS_SHIFT)
+#define MAX77843_MUIC_CONTROL3_JIGSET_MASK	(0x3 << CONTROL3_JIGSET_SHIFT)
+#define MAX77843_MUIC_CONTROL4_ADCDBSET_MASK	(0x3 << CONTROL4_ADCDBSET_SHIFT)
+#define MAX77843_MUIC_CONTROL4_USBAUTO_MASK	BIT(CONTROL4_USBAUTO_SHIFT)
+#define MAX77843_MUIC_CONTROL4_FCTAUTO_MASK	BIT(CONTROL4_FCTAUTO_SHIFT)
+#define MAX77843_MUIC_CONTROL4_ADCMODE_MASK	(0x3 << CONTROL4_ADCMODE_SHIFT)
+
+/* MAX77843 switch port */
+#define MAX77843_SIWTH_PORT \
+(MAX77843_MUIC_CONTROL1_COMP1SW_MASK | MAX77843_MUIC_CONTROL1_COMP2SW_MASK)
+
+#define MAX77843_SWITCH_OPEN \
+		(0 << CONTROL1_COMP1SW_SHIFT | 0 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_USB \
+		(1 << CONTROL1_COMP1SW_SHIFT | 1 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_AUDIO \
+		(2 << CONTROL1_COMP1SW_SHIFT | 2 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_UART \
+		(3 << CONTROL1_COMP1SW_SHIFT | 3 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_AUX_USB \
+		(4 << CONTROL1_COMP1SW_SHIFT | 4 << CONTROL1_COMP2SW_SHIFT)
+#define MAX77843_SWITCH_AUX_UART \
+		(5 << CONTROL1_COMP1SW_SHIFT | 5 << CONTROL1_COMP2SW_SHIFT)
+
+/* MAX77843 SAFEOUT LDO Control register */
+#define SAFEOUTCTRL_SAFEOUT1_SHIFT		0
+#define SAFEOUTCTRL_SAFEOUT2_SHIFT		2
+#define SAFEOUTCTRL_ENSAFEOUT1_SHIFT		6
+#define SAFEOUTCTRL_ENSAFEOUT2_SHIFT		7
+
+#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1 \
+		BIT(SAFEOUTCTRL_ENSAFEOUT1_SHIFT)
+#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2 \
+		BIT(SAFEOUTCTRL_ENSAFEOUT2_SHIFT)
+#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK \
+		(0x3 << SAFEOUTCTRL_SAFEOUT1_SHIFT)
+#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK \
+		(0x3 << SAFEOUTCTRL_SAFEOUT2_SHIFT)
+
+struct max77843 {
+	struct device *dev;
+
+	struct i2c_client *i2c;
+	struct i2c_client *i2c_chg;
+	struct i2c_client *i2c_fuel;
+	struct i2c_client *i2c_muic;
+
+	struct regmap *regmap;
+	struct regmap *regmap_chg;
+	struct regmap *regmap_fuel;
+	struct regmap *regmap_muic;
+
+	struct regmap_irq_chip_data *irq_data;
+	struct regmap_irq_chip_data *irq_data_chg;
+	struct regmap_irq_chip_data *irq_data_fuel;
+	struct regmap_irq_chip_data *irq_data_muic;
+
+	int irq;
+};
+#endif /* __MAX77843_H__ */
-- 
1.7.9.5

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

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

* [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver
  2015-01-23  5:02 [PATCH 0/6] Add new MFD driver for MAX77843 Jaewon Kim
  2015-01-23  5:02   ` Jaewon Kim
@ 2015-01-23  5:02 ` Jaewon Kim
  2015-01-23  6:21     ` Chanwoo Choi
  2015-01-23  6:38   ` Krzysztof Kozłowski
  2015-01-23  5:02   ` Jaewon Kim
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-pm
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo, Jaewon Kim

This patch adds MAX77843 extcon driver to support for MUIC(Micro
USB Interface Controller) device by using EXTCON subsystem to handle
various external connectors.

Cc: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
---
 drivers/extcon/Kconfig           |   10 +
 drivers/extcon/Makefile          |    1 +
 drivers/extcon/extcon-max77843.c |  871 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 882 insertions(+)
 create mode 100644 drivers/extcon/extcon-max77843.c

diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 6a1f7de..0b67538 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -55,6 +55,16 @@ config EXTCON_MAX77693
 	  Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory
 	  detector and switch.
 
+config EXTCON_MAX77843
+	tristate "MAX77843 EXTCON Support"
+	depends on MFD_MAX77843
+	select IRQ_DOMAIN
+	select REGMAP_I2C
+	help
+	  If you say yes here you get support for the MUIC device of
+	  Maxim MAX77843. The MAX77843 MUIC is a USB port accessory
+	  detector add switch.
+
 config EXTCON_MAX8997
 	tristate "MAX8997 EXTCON Support"
 	depends on MFD_MAX8997 && IRQ_DOMAIN
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 0370b42..f21d5c4 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
 obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
 obj-$(CONFIG_EXTCON_MAX14577)	+= extcon-max14577.o
 obj-$(CONFIG_EXTCON_MAX77693)	+= extcon-max77693.o
+obj-$(CONFIG_EXTCON_MAX77843)	+= extcon-max77843.o
 obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
 obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
 obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
new file mode 100644
index 0000000..caae9a7
--- /dev/null
+++ b/drivers/extcon/extcon-max77843.c
@@ -0,0 +1,871 @@
+/*
+ * extcon-max77843.c - MAX77843 extcon driver to support MUIC
+ *
+ * Copyright (C) 2014 Samsung Electrnoics
+ *  Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/extcon.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/max77843-private.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define DELAY_MS_DEFAULT		15000	/* unit: millisecond */
+
+enum max77843_muic_acc_type {
+	MAX77843_MUIC_ADC_GROUND = 0,
+	MAX77843_MUIC_ADC_SEND_END_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S1_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S2_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S3_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S4_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S5_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S6_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S7_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S8_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S9_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S10_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S11_BUTTON,
+	MAX77843_MUIC_ADC_REMOTE_S12_BUTTON,
+	MAX77843_MUIC_ADC_RESERVED_ACC_1,
+	MAX77843_MUIC_ADC_RESERVED_ACC_2,
+	MAX77843_MUIC_ADC_RESERVED_ACC_3,
+	MAX77843_MUIC_ADC_RESERVED_ACC_4,
+	MAX77843_MUIC_ADC_RESERVED_ACC_5,
+	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2,
+	MAX77843_MUIC_ADC_PHONE_POWERED_DEV,
+	MAX77843_MUIC_ADC_TTY_CONVERTER,
+	MAX77843_MUIC_ADC_UART_CABLE,
+	MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG,
+	MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF,
+	MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON,
+	MAX77843_MUIC_ADC_AV_CABLE_NOLOAD,
+	MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG,
+	MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF,
+	MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON,
+	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
+	MAX77843_MUIC_ADC_OPEN,
+};
+
+enum max77843_muic_cable_group {
+	MAX77843_CABLE_GROUP_ADC = 0,
+	MAX77843_CABLE_GROUP_CHG,
+	MAX77843_CABLE_GROUP_GND,
+};
+
+enum max77843_muic_adv_debounce_time {
+	MAX77843_DEBOUNCE_TIME_5MS = 0,
+	MAX77843_DEBOUNCE_TIME_10MS,
+	MAX77843_DEBOUNCE_TIME_25MS,
+	MAX77843_DEBOUNCE_TIME_38_62MS,
+};
+
+enum max77843_muic_support_list {
+	EXTCON_CABLE_USB = 0,
+	EXTCON_CABLE_USB_HOST,
+	EXTCON_CABLE_USB_HOST_TA,
+	EXTCON_CABLE_TA,
+	EXTCON_CABLE_FAST_CHARGER,
+	EXTCON_CABLE_SLOW_CHARGER,
+	EXTCON_CABLE_CHARGE_DOWNSTREAM,
+	EXTCON_CABLE_MHL,
+	EXTCON_CABLE_MHL_TA,
+	EXTCON_CABLE_JIG_USB_ON,
+	EXTCON_CABLE_JIG_USB_OFF,
+	EXTCON_CABLE_JIG_UART_OFF,
+	EXTCON_CABLE_JIG_UART_ON,
+
+	EXTCON_CABLE_NUM,
+};
+
+enum max77843_muic_gnd_cable {
+	MAX77843_MUIC_GND_USB_OTG	= 0x0,
+	MAX77843_MUIC_GND_USB_OTG_VB	= 0x1,
+	MAX77843_MUIC_GND_MHL		= 0x2,
+	MAX77843_MUIC_GND_MHL_VB	= 0x3,
+
+	MAX77843_MUIC_GND_NUM,
+};
+
+enum max77843_muic_status {
+	MAX77843_MUIC_STATUS1 = 0,
+	MAX77843_MUIC_STATUS2,
+	MAX77843_MUIC_STATUS3,
+
+	MAX77843_MUIC_STATUS_NUM,
+};
+
+enum max77843_muic_charger_type {
+	MAX77843_CHG_TYPE_NONE = 0,
+	MAX77843_CHG_TYPE_USB,
+	MAX77843_CHG_TYPE_DOWNSTREAM,
+	MAX77843_CHG_TYPE_DEDICATED,
+	MAX77843_CHG_TYPE_SPECIAL_500MA,
+	MAX77843_CHG_TYPE_SPECIAL_1A,
+	MAX77843_CHG_TYPE_SPECIAL_BIAS,
+
+	MAX77843_CHG_TYPE_END,
+};
+
+enum max77843_muic_detection {
+	MAX77843_MUIC_AUTO_NONE = 0,
+	MAX77843_MUIC_AUTO_USB,
+	MAX77843_MUIC_AUTO_FAC,
+	MAX77843_MUIC_AUTO_USB_FAC,
+};
+
+struct max77843_muic_info {
+	struct device *dev;
+	struct max77843 *max77843;
+	struct extcon_dev *edev;
+
+	struct mutex mutex;
+	struct work_struct irq_work;
+	struct delayed_work wq_detcable;
+	struct max77843_muic_irq *muic_irqs;
+
+	u8 status[MAX77843_MUIC_STATUS_NUM];
+	int prev_cable_type;
+	int prev_chg_type;
+	int prev_gnd_type;
+
+	bool irq_adc;
+	bool irq_chg;
+	bool init_done;
+};
+
+struct max77843_muic_irq {
+	unsigned int irq;
+	const char *name;
+	unsigned int virq;
+};
+
+static const struct regmap_config max77843_muic_regmap_config = {
+	.reg_bits       = 8,
+	.val_bits       = 8,
+	.max_register   = MAX77843_MUIC_REG_END,
+};
+
+static const struct regmap_irq max77843_muic_irq[] = {
+	/* MUIC:INT1 interrupts */
+	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC, },
+	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADCERROR, },
+	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC1K, },
+
+	/* MUIC:INT2 interrupts */
+	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGTYP, },
+	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGDETRUN, },
+	{ .reg_offset = 1, .mask = MAX77843_MUIC_DCDTMR, },
+	{ .reg_offset = 1, .mask = MAX77843_MUIC_DXOVP, },
+	{ .reg_offset = 1, .mask = MAX77843_MUIC_VBVOLT, },
+
+	/* MUIC:INT3 interrupts */
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_VBADC, },
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_VDNMON, },
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_DNRES, },
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_MPNACK, },
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXBUFOW, },
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXTRF, },
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXPERR, },
+	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXRDY, },
+};
+
+static const struct regmap_irq_chip max77843_muic_irq_chip = {
+	.name           = "max77843-muic",
+	.status_base    = MAX77843_MUIC_REG_INT1,
+	.mask_base      = MAX77843_MUIC_REG_INTMASK1,
+	.mask_invert    = true,
+	.num_regs       = 3,
+	.irqs           = max77843_muic_irq,
+	.num_irqs       = ARRAY_SIZE(max77843_muic_irq),
+};
+
+static const char *max77843_extcon_cable[] = {
+	[EXTCON_CABLE_USB]			= "USB",
+	[EXTCON_CABLE_USB_HOST]			= "USB-HOST",
+	[EXTCON_CABLE_USB_HOST_TA]		= "USB-HOST-TA",
+	[EXTCON_CABLE_TA]			= "TA",
+	[EXTCON_CABLE_FAST_CHARGER]		= "FAST-CHARGER",
+	[EXTCON_CABLE_SLOW_CHARGER]		= "SLOW-CHARGER",
+	[EXTCON_CABLE_CHARGE_DOWNSTREAM]	= "CHARGER-DOWNSTREAM",
+	[EXTCON_CABLE_MHL]			= "MHL",
+	[EXTCON_CABLE_MHL_TA]			= "MHL-TA",
+	[EXTCON_CABLE_JIG_USB_ON]		= "JIG-USB-ON",
+	[EXTCON_CABLE_JIG_USB_OFF]		= "JIG-USB-OFF",
+	[EXTCON_CABLE_JIG_UART_OFF]		= "JIG-UART-OFF",
+	[EXTCON_CABLE_JIG_UART_ON]		= "JIG-UART-ON",
+};
+
+static struct max77843_muic_irq max77843_muic_irqs[] = {
+	{ MAX77843_MUIC_IRQ_INT1_ADC,		"MUIC-ADC" },
+	{ MAX77843_MUIC_IRQ_INT1_ADCERROR,	"MUIC-ADC_ERROR" },
+	{ MAX77843_MUIC_IRQ_INT1_ADC1K,		"MUIC-ADC1K" },
+	{ MAX77843_MUIC_IRQ_INT2_CHGTYP,	"MUIC-CHGTYP" },
+	{ MAX77843_MUIC_IRQ_INT2_CHGDETRUN,	"MUIC-CHGDETRUN" },
+	{ MAX77843_MUIC_IRQ_INT2_DCDTMR,	"MUIC-DCDTMR" },
+	{ MAX77843_MUIC_IRQ_INT2_DXOVP,		"MUIC-DXOVP" },
+	{ MAX77843_MUIC_IRQ_INT2_VBVOLT,	"MUIC-VBVOLT" },
+	{ MAX77843_MUIC_IRQ_INT3_VBADC,		"MUIC-VBADC" },
+	{ MAX77843_MUIC_IRQ_INT3_VDNMON,	"MUIC-VDNMON" },
+	{ MAX77843_MUIC_IRQ_INT3_DNRES,		"MUIC-DNRES" },
+	{ MAX77843_MUIC_IRQ_INT3_MPNACK,	"MUIC-MPNACK"},
+	{ MAX77843_MUIC_IRQ_INT3_MRXBUFOW,	"MUIC-MRXBUFOW"},
+	{ MAX77843_MUIC_IRQ_INT3_MRXTRF,	"MUIC-MRXTRF"},
+	{ MAX77843_MUIC_IRQ_INT3_MRXPERR,	"MUIC-MRXPERR"},
+	{ MAX77843_MUIC_IRQ_INT3_MRXRDY,	"MUIC-MRXRDY"},
+};
+
+static int max77843_muic_set_path(struct max77843_muic_info *info,
+		u8 val, bool attached)
+{
+	struct max77843 *max77843 = info->max77843;
+	int ret = 0;
+	unsigned int ctrl1, ctrl2;
+
+	if (attached)
+		ctrl1 = val;
+	else
+		ctrl1 = MAX77843_SWITCH_OPEN;
+
+	ret = regmap_update_bits(max77843->regmap_muic,
+			MAX77843_MUIC_REG_CONTROL1,
+			MAX77843_SIWTH_PORT, ctrl1);
+	if (ret < 0) {
+		dev_err(info->dev, "Cannot switch MUIC port\n");
+		return ret;
+	}
+
+	if (attached)
+		ctrl2 = MAX77843_MUIC_CONTROL2_CPEN_MASK;
+	else
+		ctrl2 = MAX77843_MUIC_CONTROL2_LOWPWR_MASK;
+
+	ret = regmap_update_bits(max77843->regmap_muic,
+			MAX77843_MUIC_REG_CONTROL2,
+			MAX77843_MUIC_CONTROL2_LOWPWR_MASK |
+			MAX77843_MUIC_CONTROL2_CPEN_MASK, ctrl2);
+	if (ret < 0) {
+		dev_err(info->dev, "Cannot update lowpower mode\n");
+		return ret;
+	}
+
+	dev_dbg(info->dev,
+		"CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
+		ctrl1, ctrl2, attached ? "attached" : "detached");
+
+	return 0;
+}
+
+static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
+		enum max77843_muic_cable_group group, bool *attached)
+{
+	int adc, chg_type, cable_type, gnd_type;
+
+	adc = info->status[MAX77843_MUIC_STATUS1] &
+			MAX77843_MUIC_STATUS1_ADC_MASK;
+	adc >>= STATUS1_ADC_SHIFT;
+
+	switch (group) {
+	case MAX77843_CABLE_GROUP_ADC:
+		if (adc == MAX77843_MUIC_ADC_OPEN) {
+			*attached = false;
+			cable_type = info->prev_cable_type;
+			info->prev_cable_type = MAX77843_MUIC_ADC_OPEN;
+		} else {
+			*attached = true;
+			cable_type = info->prev_cable_type = adc;
+		}
+
+		break;
+	case MAX77843_CABLE_GROUP_CHG:
+		if (adc == MAX77843_MUIC_ADC_GROUND) {
+			*attached = true;
+			cable_type = adc;
+			break;
+		}
+
+		chg_type = info->status[MAX77843_MUIC_STATUS2] &
+			MAX77843_MUIC_STATUS2_CHGTYP_MASK;
+		chg_type >>= STATUS2_CHGTYP_SHIFT;
+
+		if (chg_type == MAX77843_CHG_TYPE_NONE) {
+			*attached = false;
+			cable_type = info->prev_chg_type;
+			info->prev_chg_type = MAX77843_CHG_TYPE_NONE;
+		} else {
+			*attached = true;
+			cable_type = info->prev_chg_type = chg_type;
+		}
+
+		break;
+	case MAX77843_CABLE_GROUP_GND:
+		adc = info->status[MAX77843_MUIC_STATUS1] &
+			MAX77843_MUIC_STATUS1_ADC_MASK;
+		adc >>= STATUS1_ADC_SHIFT;
+
+		if (adc == MAX77843_MUIC_ADC_GROUND) {
+			*attached = true;
+			gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
+					MAX77843_MUIC_STATUS1_ADC1K_MASK) >>
+					(STATUS1_ADC1K_SHIFT-1);
+			gnd_type |= (info->status[MAX77843_MUIC_STATUS2] &
+					MAX77843_MUIC_STATUS2_VBVOLT_MASK) >>
+					STATUS2_VBVOLT_SHIFT;
+			cable_type = info->prev_gnd_type = gnd_type;
+		} else {
+			*attached = false;
+			cable_type = info->prev_gnd_type;
+			info->prev_gnd_type = MAX77843_MUIC_GND_NUM;
+		}
+
+		break;
+	default:
+		dev_err(info->dev, "Unknown cable group (%d)\n", group);
+		cable_type = -EINVAL;
+
+		break;
+	}
+
+	return cable_type;
+}
+
+static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
+{
+	int ret, gnd_cable_type;
+	u8 path;
+	bool attached;
+
+	gnd_cable_type = max77843_muic_get_cable_type(info,
+			MAX77843_CABLE_GROUP_GND, &attached);
+	dev_dbg(info->dev, "external connector is %s (gnd:0x%02x)\n",
+			attached ? "attached" : "detached", gnd_cable_type);
+
+	switch (gnd_cable_type) {
+	case MAX77843_MUIC_GND_USB_OTG:
+		extcon_set_cable_state(info->edev, "USB-HOST", attached);
+		path = MAX77843_SWITCH_USB;
+		info->irq_chg = false;
+		break;
+	case MAX77843_MUIC_GND_USB_OTG_VB:
+		extcon_set_cable_state(info->edev, "USB-HOST-TA", attached);
+		path = MAX77843_SWITCH_USB;
+		info->irq_chg = false;
+		break;
+	case MAX77843_MUIC_GND_MHL:
+		extcon_set_cable_state(info->edev, "MHL", attached);
+		path = MAX77843_SWITCH_OPEN;
+		info->irq_chg = false;
+		break;
+	case MAX77843_MUIC_GND_MHL_VB:
+		extcon_set_cable_state(info->edev, "MHL-TA", attached);
+		path = MAX77843_SWITCH_OPEN;
+		info->irq_chg = false;
+		break;
+	default:
+		dev_err(info->dev, "Cannot detect %s cable of gnd type\n",
+			attached ? "attached" : "detached");
+		return -EINVAL;
+	}
+
+	ret = max77843_muic_set_path(info, path, attached);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int max77843_muic_jig_handler(struct max77843_muic_info *info,
+		int cable_type, bool attached)
+{
+	char cable_name[32];
+	u8 path = MAX77843_SWITCH_OPEN;
+	int ret;
+
+	dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
+			attached ? "attached" : "detached", cable_type);
+
+	switch (cable_type) {
+	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
+		strcpy(cable_name, "JIG-USB-OFF");
+		path = MAX77843_SWITCH_USB;
+		break;
+	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
+		strcpy(cable_name, "JIG-USB-ON");
+		path = MAX77843_SWITCH_USB;
+		break;
+	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
+		strcpy(cable_name, "JIG-UART-OFF");
+		path = MAX77843_SWITCH_UART;
+		break;
+	default:
+		break;
+	}
+
+	ret = max77843_muic_set_path(info, path, attached);
+	if (ret < 0)
+		return ret;
+
+	extcon_set_cable_state(info->edev, cable_name, attached);
+
+	return 0;
+}
+
+static int max77843_muic_adc_handler(struct max77843_muic_info *info)
+{
+	int ret, cable_type;
+	bool attached;
+
+	cable_type = max77843_muic_get_cable_type(info,
+			MAX77843_CABLE_GROUP_ADC, &attached);
+
+	dev_dbg(info->dev,
+		"external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
+		attached ? "attached" : "detached", cable_type,
+		info->prev_cable_type);
+
+	switch (cable_type) {
+	case MAX77843_MUIC_ADC_GROUND:
+		ret = max77843_muic_adc_gnd_handler(info);
+		if (ret < 0)
+			return ret;
+		break;
+	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
+	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
+	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
+		ret = max77843_muic_jig_handler(info, cable_type, attached);
+		if (ret < 0)
+			return ret;
+		break;
+	case MAX77843_MUIC_ADC_SEND_END_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S1_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S2_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S3_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S4_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S5_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S6_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S7_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S8_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S9_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S10_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S11_BUTTON:
+	case MAX77843_MUIC_ADC_REMOTE_S12_BUTTON:
+	case MAX77843_MUIC_ADC_RESERVED_ACC_1:
+	case MAX77843_MUIC_ADC_RESERVED_ACC_2:
+	case MAX77843_MUIC_ADC_RESERVED_ACC_3:
+	case MAX77843_MUIC_ADC_RESERVED_ACC_4:
+	case MAX77843_MUIC_ADC_RESERVED_ACC_5:
+	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2:
+	case MAX77843_MUIC_ADC_PHONE_POWERED_DEV:
+	case MAX77843_MUIC_ADC_TTY_CONVERTER:
+	case MAX77843_MUIC_ADC_UART_CABLE:
+	case MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG:
+	case MAX77843_MUIC_ADC_AV_CABLE_NOLOAD:
+	case MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG:
+	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON:
+	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1:
+	case MAX77843_MUIC_ADC_OPEN:
+		dev_err(info->dev,
+			"accessory is %s but it isn't used (adc:0x%x)\n",
+			attached ? "attached" : "detached", cable_type);
+		return -EAGAIN;
+	default:
+		dev_err(info->dev,
+			"failed to detect %s accessory (adc:0x%x)\n",
+			attached ? "attached" : "detached", cable_type);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max77843_muic_chg_handler(struct max77843_muic_info *info)
+{
+	int ret, chg_type;
+	bool attached;
+	u8 path = MAX77843_SWITCH_OPEN;
+
+	chg_type = max77843_muic_get_cable_type(info,
+			MAX77843_CABLE_GROUP_CHG, &attached);
+
+	dev_dbg(info->dev,
+		"external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
+		attached ? "attached" : "detached",
+		chg_type, info->prev_chg_type);
+
+	switch (chg_type) {
+	case MAX77843_CHG_TYPE_USB:
+		path = MAX77843_SWITCH_USB;
+		extcon_set_cable_state(info->edev, "USB", attached);
+		break;
+	case MAX77843_CHG_TYPE_DOWNSTREAM:
+		path = MAX77843_SWITCH_OPEN;
+		extcon_set_cable_state(info->edev,
+				"CHARGER-DOWNSTREAM", attached);
+		break;
+	case MAX77843_CHG_TYPE_DEDICATED:
+		path = MAX77843_SWITCH_OPEN;
+		extcon_set_cable_state(info->edev, "TA", attached);
+		break;
+	case MAX77843_CHG_TYPE_SPECIAL_500MA:
+		path = MAX77843_SWITCH_OPEN;
+		extcon_set_cable_state(info->edev, "SLOW-CHAREGER", attached);
+		break;
+	case MAX77843_CHG_TYPE_SPECIAL_1A:
+		path = MAX77843_SWITCH_OPEN;
+		extcon_set_cable_state(info->edev, "FAST-CHARGER", attached);
+		break;
+	case MAX77843_CHG_TYPE_SPECIAL_BIAS:
+		path = MAX77843_SWITCH_OPEN;
+		break;
+	case MAX77843_CHG_TYPE_NONE:
+		return 0;
+	default:
+		dev_err(info->dev,
+			"failed to detect %s accessory (chg_type:0x%x)\n",
+			attached ? "attached" : "detached", chg_type);
+		return -EINVAL;
+	}
+
+	ret = max77843_muic_set_path(info, path, attached);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static void max77843_muic_irq_work(struct work_struct *work)
+{
+	struct max77843_muic_info *info = container_of(work,
+			struct max77843_muic_info, irq_work);
+	struct max77843 *max77843 = info->max77843;
+	int ret = 0;
+
+	if (!info->edev)
+		return;
+
+	mutex_lock(&info->mutex);
+
+	ret = regmap_bulk_read(max77843->regmap_muic,
+			MAX77843_MUIC_REG_STATUS1, info->status,
+			MAX77843_MUIC_STATUS_NUM);
+	if (ret) {
+		dev_err(info->dev, "Cannot read STATUS registers\n");
+		mutex_unlock(&info->mutex);
+		return;
+	}
+
+	if (info->irq_adc) {
+		ret = max77843_muic_adc_handler(info);
+		if (ret)
+			dev_err(info->dev, "Unknown cable type\n");
+		info->irq_adc = false;
+	}
+
+	if (info->irq_chg) {
+		ret = max77843_muic_chg_handler(info);
+		if (ret)
+			dev_err(info->dev, "Unknown charger type\n");
+		info->irq_chg = false;
+	}
+
+	mutex_unlock(&info->mutex);
+}
+
+static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
+{
+	struct max77843_muic_info *info = data;
+	int i, irq_type = -1;
+
+	if (!info->init_done)
+		return IRQ_HANDLED;
+
+	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++)
+		if (irq == info->muic_irqs[i].virq)
+			irq_type = info->muic_irqs[i].irq;
+
+	switch (irq_type) {
+	case MAX77843_MUIC_IRQ_INT1_ADC:
+	case MAX77843_MUIC_IRQ_INT1_ADCERROR:
+	case MAX77843_MUIC_IRQ_INT1_ADC1K:
+		info->irq_adc = true;
+		break;
+	case MAX77843_MUIC_IRQ_INT2_CHGTYP:
+	case MAX77843_MUIC_IRQ_INT2_CHGDETRUN:
+	case MAX77843_MUIC_IRQ_INT2_DCDTMR:
+	case MAX77843_MUIC_IRQ_INT2_DXOVP:
+	case MAX77843_MUIC_IRQ_INT2_VBVOLT:
+		info->irq_chg = true;
+		break;
+	case MAX77843_MUIC_IRQ_INT3_VBADC:
+	case MAX77843_MUIC_IRQ_INT3_VDNMON:
+	case MAX77843_MUIC_IRQ_INT3_DNRES:
+	case MAX77843_MUIC_IRQ_INT3_MPNACK:
+	case MAX77843_MUIC_IRQ_INT3_MRXBUFOW:
+	case MAX77843_MUIC_IRQ_INT3_MRXTRF:
+	case MAX77843_MUIC_IRQ_INT3_MRXPERR:
+	case MAX77843_MUIC_IRQ_INT3_MRXRDY:
+		break;
+	default:
+		dev_err(info->dev, "Cannot recognize IRQ(%d)\n", irq_type);
+		break;
+	}
+
+	schedule_work(&info->irq_work);
+
+	return IRQ_HANDLED;
+}
+
+static void max77843_muic_detect_cable_wq(struct work_struct *work)
+{
+	struct max77843_muic_info *info = container_of(to_delayed_work(work),
+			struct max77843_muic_info, wq_detcable);
+	struct max77843 *max77843 = info->max77843;
+	int chg_type, adc, ret;
+	bool attached;
+
+	mutex_lock(&info->mutex);
+
+	ret = regmap_bulk_read(max77843->regmap_muic,
+			MAX77843_MUIC_REG_STATUS1, info->status,
+			MAX77843_MUIC_STATUS_NUM);
+	if (ret) {
+		dev_err(info->dev, "Cannot read STATUS registers\n");
+		goto err_cable_wq;
+	}
+
+	adc = max77843_muic_get_cable_type(info,
+			MAX77843_CABLE_GROUP_ADC, &attached);
+	if (attached && adc != MAX77843_MUIC_ADC_OPEN) {
+		ret = max77843_muic_adc_handler(info);
+		if (ret < 0) {
+			dev_err(info->dev, "Cannot detect accessory\n");
+			goto err_cable_wq;
+		}
+	}
+
+	chg_type = max77843_muic_get_cable_type(info,
+			MAX77843_CABLE_GROUP_CHG, &attached);
+	if (attached && chg_type != MAX77843_CHG_TYPE_NONE) {
+		ret = max77843_muic_chg_handler(info);
+		if (ret < 0) {
+			dev_err(info->dev, "Cannot detect charger accessory\n");
+			goto err_cable_wq;
+		}
+	}
+
+err_cable_wq:
+	mutex_unlock(&info->mutex);
+}
+
+static int max77843_muic_set_debounce_time(struct max77843_muic_info *info,
+		enum max77843_muic_adv_debounce_time time)
+{
+	struct max77843 *max77843 = info->max77843;
+	unsigned int ret;
+
+	switch (time) {
+	case MAX77843_DEBOUNCE_TIME_5MS:
+	case MAX77843_DEBOUNCE_TIME_10MS:
+	case MAX77843_DEBOUNCE_TIME_25MS:
+	case MAX77843_DEBOUNCE_TIME_38_62MS:
+		ret = regmap_update_bits(max77843->regmap_muic,
+				MAX77843_MUIC_REG_CONTROL4,
+				MAX77843_MUIC_CONTROL4_ADCDBSET_MASK,
+				time << CONTROL4_ADCDBSET_SHIFT);
+		if (ret) {
+			dev_err(info->dev, "Cannot write MUIC regmap\n");
+			return ret;
+		}
+
+		break;
+	default:
+		dev_err(info->dev, "Invalid ADC debounce time\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int max77843_init_muic_regmap(struct max77843 *max77843)
+{
+	int ret;
+
+	max77843->i2c_muic = i2c_new_dummy(max77843->i2c->adapter,
+			I2C_ADDR_MUIC);
+	if (!max77843->i2c_muic) {
+		dev_err(&max77843->i2c->dev,
+				"Cannot allocate I2C device for MUIC\n");
+		return PTR_ERR(max77843->i2c_muic);
+	}
+
+	i2c_set_clientdata(max77843->i2c_muic, max77843);
+
+	max77843->regmap_muic = devm_regmap_init_i2c(max77843->i2c_muic,
+			&max77843_muic_regmap_config);
+	if (IS_ERR(max77843->regmap_muic)) {
+		ret = PTR_ERR(max77843->regmap_muic);
+		goto err_muic_i2c;
+	}
+
+	ret = regmap_add_irq_chip(max77843->regmap_muic, max77843->irq,
+			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
+			0, &max77843_muic_irq_chip, &max77843->irq_data_muic);
+	if (ret) {
+		dev_err(&max77843->i2c->dev, "Cannot add MUIC IRQ chip\n");
+		goto err_muic_i2c;
+	}
+
+	return 0;
+
+err_muic_i2c:
+	i2c_unregister_device(max77843->i2c_muic);
+
+	return ret;
+}
+
+static int max77843_muic_probe(struct platform_device *pdev)
+{
+	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
+	struct max77843_muic_info *info;
+	unsigned int id;
+	int i, ret;
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	info->dev = &pdev->dev;
+	info->max77843 = max77843;
+	info->muic_irqs = max77843_muic_irqs;
+	info->init_done = false;
+
+	platform_set_drvdata(pdev, info);
+	mutex_init(&info->mutex);
+	INIT_WORK(&info->irq_work, max77843_muic_irq_work);
+
+	/* Initialize i2c and regmap */
+	ret = max77843_init_muic_regmap(max77843);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to init MUIC regmap\n");
+		return ret;
+	}
+
+	/* Turn off auto detection configuration */
+	ret = regmap_update_bits(max77843->regmap_muic,
+			MAX77843_MUIC_REG_CONTROL4,
+			MAX77843_MUIC_CONTROL4_USBAUTO_MASK |
+			MAX77843_MUIC_CONTROL4_FCTAUTO_MASK,
+			MAX77843_MUIC_AUTO_NONE << CONTROL4_USBAUTO_SHIFT);
+
+	/* Support virtual irq domain for max77843 MUIC device */
+	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
+		struct max77843_muic_irq *muic_irq = &info->muic_irqs[i];
+		unsigned int virq = 0;
+
+		virq = regmap_irq_get_virq(max77843->irq_data_muic,
+				muic_irq->irq);
+		if (virq <= 0) {
+			ret = -EINVAL;
+			goto err_muic_irq;
+		}
+		muic_irq->virq = virq;
+
+		ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
+				max77843_muic_irq_handler, IRQF_NO_SUSPEND,
+				muic_irq->name, info);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed: irq request (IRQ: %d, error: %d)\n",
+				muic_irq->irq, ret);
+			goto err_muic_irq;
+		}
+	}
+
+	/* Initialize extcon device */
+	info->edev = devm_extcon_dev_allocate(&pdev->dev,
+			max77843_extcon_cable);
+	if (IS_ERR(info->edev)) {
+		dev_err(&pdev->dev, "Failed to allocate memory for extcon\n");
+		ret = -ENODEV;
+		goto err_muic_irq;
+	}
+
+	info->edev->name = dev_name(&pdev->dev);
+
+	ret = devm_extcon_dev_register(&pdev->dev, info->edev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register extcon device\n");
+		goto err_muic_irq;
+	}
+
+	/* Set ADC debounce time */
+	max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS);
+
+	/* Set initial path for UART */
+	max77843_muic_set_path(info, MAX77843_SWITCH_UART, true);
+
+	/* Detect accessory after completing the initialization of platform */
+	INIT_DELAYED_WORK(&info->wq_detcable, max77843_muic_detect_cable_wq);
+	queue_delayed_work(system_power_efficient_wq,
+			&info->wq_detcable, msecs_to_jiffies(DELAY_MS_DEFAULT));
+
+	/* Check revision number of MUIC device */
+	ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Failed to read revision number\n");
+		return ret;
+	}
+	dev_info(info->dev, "MUIC device ID : 0x%x\n", id);
+
+	info->init_done = true;
+
+	return 0;
+
+err_muic_irq:
+	regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
+
+	return ret;
+}
+
+static int max77843_muic_remove(struct platform_device *pdev)
+{
+	struct max77843_muic_info *info = platform_get_drvdata(pdev);
+
+	cancel_work_sync(&info->irq_work);
+
+	return 0;
+}
+
+static const struct platform_device_id max77843_muic_id[] = {
+	{ "max77843-muic", },
+	{ },
+};
+MODULE_DEVICE_TABLE(platform, max77843_muic_id);
+
+static struct platform_driver max77843_muic_driver = {
+	.driver		= {
+		.name		= "max77843-muic",
+	},
+	.probe		= max77843_muic_probe,
+	.remove		= max77843_muic_remove,
+	.id_table	= max77843_muic_id,
+};
+
+static int __init max77843_muic_init(void)
+{
+	return platform_driver_register(&max77843_muic_driver);
+}
+subsys_initcall(max77843_muic_init);
+
+MODULE_DESCRIPTION("Maxim MAX77843 Extcon driver");
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


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

* [PATCH 3/6] power: max77843_charger: Add Max77843 charger device driver
@ 2015-01-23  5:02   ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-pm
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo

From: Beomho Seo <beomho.seo@samsung.com>

This patch adds device driver of max77843 charger. This driver provide
initialize each charging mode(e.g. fast charge, top-off mode and constant
charging mode so on.). Additionally, control charging paramters to use
i2c interface.

Cc: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
---
 drivers/power/Kconfig            |    7 +
 drivers/power/Makefile           |    1 +
 drivers/power/max77843_charger.c |  506 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 514 insertions(+)
 create mode 100644 drivers/power/max77843_charger.c

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 0108c2a..a054a28 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -332,6 +332,13 @@ config CHARGER_MAX14577
 	  Say Y to enable support for the battery charger control sysfs and
 	  platform data of MAX14577/77836 MUICs.
 
+config CHARGER_MAX77843
+	tristate "Maxim MAX77843 battery charger driver"
+	depends on MFD_MAX77843
+	help
+	  Say Y to enable support for the battery charger control sysfs and
+	  platform data of MAX77843
+
 config CHARGER_MAX8997
 	tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
 	depends on MFD_MAX8997 && REGULATOR_MAX8997
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index dfa8942..212c6a2 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_CHARGER_LP8788)	+= lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO)	+= gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)	+= charger-manager.o
 obj-$(CONFIG_CHARGER_MAX14577)	+= max14577_charger.o
+obj-$(CONFIG_CHARGER_MAX77843)	+= max77843_charger.o
 obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o
diff --git a/drivers/power/max77843_charger.c b/drivers/power/max77843_charger.c
new file mode 100644
index 0000000..317b2cc
--- /dev/null
+++ b/drivers/power/max77843_charger.c
@@ -0,0 +1,506 @@
+/*
+ * Charger driver for Maxim MAX77843
+ *
+ * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
+ * Author: Beomho Seo <beomho.seo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published bythe Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max77843-private.h>
+
+struct max77843_charger_info {
+	u32 fast_charge_uamp;
+	u32 top_off_uamp;
+	u32 input_uamp_limit;
+};
+
+struct max77843_charger {
+	struct device		*dev;
+	struct max77843		*max77843;
+	struct i2c_client	*client;
+	struct regmap		*regmap;
+	struct power_supply	psy;
+
+	struct max77843_charger_info	*info;
+};
+
+static int max77843_charger_get_max_current(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_09, &reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	if (reg_data <= 0x03) {
+		val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
+	} else if (reg_data >= 0x78) {
+		val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX;
+	} else {
+		val = reg_data / 3;
+		if (reg_data % 3 == 0)
+			val *= 100000;
+		else if (reg_data % 3 == 1)
+			val = val * 100000 + 33000;
+		else
+			val = val * 100000 + 67000;
+	}
+
+	return val;
+}
+
+static int max77843_charger_get_now_current(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	reg_data &= MAX77843_CHG_FAST_CHG_CURRENT_MASK;
+
+	if (reg_data <= 0x02)
+		val = MAX77843_CHG_FAST_CHG_CURRENT_MIN;
+	else if (reg_data >= 0x3f)
+		val = MAX77843_CHG_FAST_CHG_CURRENT_MAX;
+	else
+		val = reg_data * MAX77843_CHG_FAST_CHG_CURRENT_STEP;
+
+	return val;
+}
+
+static int max77843_charger_get_online(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_INT_OK, &reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	if (reg_data & MAX77843_CHG_CHGIN_OK)
+		val = true;
+	else
+		val = false;
+
+	return val;
+}
+
+static int max77843_charger_get_present(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_00,	&reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	if (reg_data & MAX77843_CHG_BAT_DTLS)
+		val = false;
+	else
+		val = true;
+
+	return val;
+}
+
+static int max77843_charger_get_health(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = POWER_SUPPLY_HEALTH_UNKNOWN;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01,	&reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	reg_data &= MAX77843_CHG_BAT_DTLS_MASK;
+
+	switch (reg_data) {
+	case MAX77843_CHG_NO_BAT:
+		val = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+		break;
+	case MAX77843_CHG_LOW_VOLT_BAT:
+	case MAX77843_CHG_OK_BAT:
+	case MAX77843_CHG_OK_LOW_VOLT_BAT:
+		val = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case MAX77843_CHG_LONG_BAT_TIME:
+		val = POWER_SUPPLY_HEALTH_DEAD;
+		break;
+	case MAX77843_CHG_OVER_VOLT_BAT:
+	case MAX77843_CHG_OVER_CURRENT_BAT:
+		val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+		break;
+	default:
+		val = POWER_SUPPLY_HEALTH_UNKNOWN;
+		break;
+	}
+
+	return val;
+}
+
+static int max77843_charger_get_status(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01,	&reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	reg_data &= MAX77843_CHG_DTLS_MASK;
+
+	switch (reg_data) {
+	case MAX77843_CHG_PQ_MODE:
+	case MAX77843_CHG_CC_MODE:
+	case MAX77843_CHG_CV_MODE:
+		val = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case MAX77843_CHG_TO_MODE:
+	case MAX77843_CHG_DO_MODE:
+		val = POWER_SUPPLY_STATUS_FULL;
+		break;
+	case MAX77843_CHG_HT_MODE:
+	case MAX77843_CHG_TF_MODE:
+	case MAX77843_CHG_TS_MODE:
+		val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	case MAX77843_CHG_OFF_MODE:
+		val = POWER_SUPPLY_STATUS_DISCHARGING;
+		break;
+	default:
+		val = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	}
+
+	return val;
+}
+
+static const char *model_name = "MAX77843";
+static const char *manufacturer = "Maxim Integrated";
+
+static int max77843_charger_get_property(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct max77843_charger *charger = container_of(psy,
+				struct max77843_charger, psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = max77843_charger_get_status(charger);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = max77843_charger_get_health(charger);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = max77843_charger_get_present(charger);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = max77843_charger_get_online(charger);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = max77843_charger_get_now_current(charger);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = max77843_charger_get_max_current(charger);
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval =  model_name;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = manufacturer;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static enum power_supply_property max77843_charger_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int max77843_charger_init_current_limit(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	struct max77843_charger_info *info = charger->info;
+	unsigned int input_uamp_limit = info->input_uamp_limit;
+	int ret;
+	unsigned int reg_data, val;
+
+	ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
+			MAX77843_CHG_OTG_ILIMIT_MASK,
+			MAX77843_CHG_OTG_ILIMIT_900);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN) {
+		reg_data = 0x03;
+	} else if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX) {
+		reg_data = 0x78;
+	} else {
+		if (input_uamp_limit < MAX77843_CHG_INPUT_CURRENT_LIMIT_REF)
+			val = 0x03;
+		else
+			val = 0x02;
+
+		input_uamp_limit -= MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
+		input_uamp_limit /= MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP;
+		reg_data = val + input_uamp_limit;
+	}
+
+	ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77843_charger_init_top_off(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	struct max77843_charger_info *info = charger->info;
+	unsigned int top_off_uamp = info->top_off_uamp;
+	int ret;
+	unsigned int reg_data;
+
+	if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MIN) {
+		reg_data = 0x00;
+	} else if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MAX) {
+		reg_data = 0x07;
+	} else {
+		top_off_uamp -= MAX77843_CHG_TOP_OFF_CURRENT_MIN;
+		top_off_uamp /= MAX77843_CHG_TOP_OFF_CURRENT_STEP;
+		reg_data = top_off_uamp;
+	}
+
+	ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_03,
+			MAX77843_CHG_TOP_OFF_CURRENT_MASK, reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77843_charger_init_fast_charge(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	struct max77843_charger_info *info = charger->info;
+	unsigned int fast_charge_uamp = info->fast_charge_uamp;
+	int ret;
+	unsigned int reg_data;
+
+	if (fast_charge_uamp < info->input_uamp_limit) {
+		reg_data = 0x09;
+	} else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MIN) {
+		reg_data = 0x02;
+	} else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MAX) {
+		reg_data = 0x3f;
+	} else {
+		fast_charge_uamp -= MAX77843_CHG_FAST_CHG_CURRENT_MIN;
+		fast_charge_uamp /= MAX77843_CHG_FAST_CHG_CURRENT_STEP;
+		reg_data = 0x02 + fast_charge_uamp;
+	}
+
+	ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
+			MAX77843_CHG_FAST_CHG_CURRENT_MASK, reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77843_charger_init(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret;
+
+	ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_06,
+			MAX77843_CHG_WRITE_CAP_UNBLOCK);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_01,
+			MAX77843_CHG_RESTART_THRESHOLD_DISABLE);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	ret = max77843_charger_init_fast_charge(charger);
+	if (ret) {
+		dev_err(charger->dev, "Failed to set fast charge mode.\n");
+		return ret;
+	}
+
+	ret = max77843_charger_init_top_off(charger);
+	if (ret) {
+		dev_err(charger->dev, "Failed to set top off charge mode.\n");
+		return ret;
+	}
+
+	ret = max77843_charger_init_current_limit(charger);
+
+	return 0;
+}
+
+static struct max77843_charger_info *max77843_charger_dt_init(
+		struct platform_device *pdev)
+{
+	struct max77843_charger_info *info;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (!np) {
+		dev_err(&pdev->dev, "No charger OF node\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return ERR_PTR(-ENOMEM);
+
+	ret = of_property_read_u32(np, "maxim,fast-charge-uamp",
+			&info->fast_charge_uamp);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot parse fast charge current.\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = of_property_read_u32(np, "maxim,top-off-uamp",
+			&info->top_off_uamp);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Cannot parse primary charger termination voltage.\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = of_property_read_u32(np, "maxim,input-uamp-limit",
+			&info->input_uamp_limit);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot parse input current limit value\n");
+		return ERR_PTR(ret);
+	}
+
+	return info;
+}
+
+static int max77843_charger_probe(struct platform_device *pdev)
+{
+	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
+	struct max77843_charger *charger;
+	int ret;
+
+	charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
+	if (!charger)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, charger);
+	charger->dev = &pdev->dev;
+	charger->max77843 = max77843;
+	charger->client = max77843->i2c_chg;
+	charger->regmap = max77843->regmap_chg;
+
+	charger->info = max77843_charger_dt_init(pdev);
+	if (IS_ERR_OR_NULL(charger->info)) {
+		ret = PTR_ERR(charger->info);
+		goto err_i2c;
+	}
+
+	charger->psy.name	= "max77843-charger";
+	charger->psy.type	= POWER_SUPPLY_TYPE_MAINS;
+	charger->psy.get_property	= max77843_charger_get_property;
+	charger->psy.properties		= max77843_charger_props;
+	charger->psy.num_properties	= ARRAY_SIZE(max77843_charger_props);
+
+	ret = max77843_charger_init(charger);
+	if (ret)
+		goto err_i2c;
+
+	ret = power_supply_register(&pdev->dev, &charger->psy);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed  to register power supply\n");
+		goto err_i2c;
+	}
+
+	return 0;
+
+err_i2c:
+	i2c_unregister_device(charger->client);
+
+	return ret;
+}
+
+static int max77843_charger_remove(struct platform_device *pdev)
+{
+	struct max77843_charger *charger = platform_get_drvdata(pdev);
+
+	power_supply_unregister(&charger->psy);
+
+	return 0;
+}
+
+static const struct platform_device_id max77843_charger_id[] = {
+	{ "max77843-charger", },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max77843_charger_id);
+
+static struct platform_driver max77843_charger_driver = {
+	.driver = {
+		.name = "max77843-charger",
+	},
+	.probe = max77843_charger_probe,
+	.remove = max77843_charger_remove,
+	.id_table = max77843_charger_id,
+};
+module_platform_driver(max77843_charger_driver);
+
+MODULE_DESCRIPTION("Maxim MAX77843 charger driver");
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


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

* [PATCH 3/6] power: max77843_charger: Add Max77843 charger device driver
@ 2015-01-23  5:02   ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo

From: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

This patch adds device driver of max77843 charger. This driver provide
initialize each charging mode(e.g. fast charge, top-off mode and constant
charging mode so on.). Additionally, control charging paramters to use
i2c interface.

Cc: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
 drivers/power/Kconfig            |    7 +
 drivers/power/Makefile           |    1 +
 drivers/power/max77843_charger.c |  506 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 514 insertions(+)
 create mode 100644 drivers/power/max77843_charger.c

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 0108c2a..a054a28 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -332,6 +332,13 @@ config CHARGER_MAX14577
 	  Say Y to enable support for the battery charger control sysfs and
 	  platform data of MAX14577/77836 MUICs.
 
+config CHARGER_MAX77843
+	tristate "Maxim MAX77843 battery charger driver"
+	depends on MFD_MAX77843
+	help
+	  Say Y to enable support for the battery charger control sysfs and
+	  platform data of MAX77843
+
 config CHARGER_MAX8997
 	tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
 	depends on MFD_MAX8997 && REGULATOR_MAX8997
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index dfa8942..212c6a2 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_CHARGER_LP8788)	+= lp8788-charger.o
 obj-$(CONFIG_CHARGER_GPIO)	+= gpio-charger.o
 obj-$(CONFIG_CHARGER_MANAGER)	+= charger-manager.o
 obj-$(CONFIG_CHARGER_MAX14577)	+= max14577_charger.o
+obj-$(CONFIG_CHARGER_MAX77843)	+= max77843_charger.o
 obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o
diff --git a/drivers/power/max77843_charger.c b/drivers/power/max77843_charger.c
new file mode 100644
index 0000000..317b2cc
--- /dev/null
+++ b/drivers/power/max77843_charger.c
@@ -0,0 +1,506 @@
+/*
+ * Charger driver for Maxim MAX77843
+ *
+ * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
+ * Author: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published bythe Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max77843-private.h>
+
+struct max77843_charger_info {
+	u32 fast_charge_uamp;
+	u32 top_off_uamp;
+	u32 input_uamp_limit;
+};
+
+struct max77843_charger {
+	struct device		*dev;
+	struct max77843		*max77843;
+	struct i2c_client	*client;
+	struct regmap		*regmap;
+	struct power_supply	psy;
+
+	struct max77843_charger_info	*info;
+};
+
+static int max77843_charger_get_max_current(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_09, &reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	if (reg_data <= 0x03) {
+		val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
+	} else if (reg_data >= 0x78) {
+		val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX;
+	} else {
+		val = reg_data / 3;
+		if (reg_data % 3 == 0)
+			val *= 100000;
+		else if (reg_data % 3 == 1)
+			val = val * 100000 + 33000;
+		else
+			val = val * 100000 + 67000;
+	}
+
+	return val;
+}
+
+static int max77843_charger_get_now_current(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	reg_data &= MAX77843_CHG_FAST_CHG_CURRENT_MASK;
+
+	if (reg_data <= 0x02)
+		val = MAX77843_CHG_FAST_CHG_CURRENT_MIN;
+	else if (reg_data >= 0x3f)
+		val = MAX77843_CHG_FAST_CHG_CURRENT_MAX;
+	else
+		val = reg_data * MAX77843_CHG_FAST_CHG_CURRENT_STEP;
+
+	return val;
+}
+
+static int max77843_charger_get_online(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_INT_OK, &reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	if (reg_data & MAX77843_CHG_CHGIN_OK)
+		val = true;
+	else
+		val = false;
+
+	return val;
+}
+
+static int max77843_charger_get_present(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_00,	&reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	if (reg_data & MAX77843_CHG_BAT_DTLS)
+		val = false;
+	else
+		val = true;
+
+	return val;
+}
+
+static int max77843_charger_get_health(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = POWER_SUPPLY_HEALTH_UNKNOWN;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01,	&reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	reg_data &= MAX77843_CHG_BAT_DTLS_MASK;
+
+	switch (reg_data) {
+	case MAX77843_CHG_NO_BAT:
+		val = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+		break;
+	case MAX77843_CHG_LOW_VOLT_BAT:
+	case MAX77843_CHG_OK_BAT:
+	case MAX77843_CHG_OK_LOW_VOLT_BAT:
+		val = POWER_SUPPLY_HEALTH_GOOD;
+		break;
+	case MAX77843_CHG_LONG_BAT_TIME:
+		val = POWER_SUPPLY_HEALTH_DEAD;
+		break;
+	case MAX77843_CHG_OVER_VOLT_BAT:
+	case MAX77843_CHG_OVER_CURRENT_BAT:
+		val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+		break;
+	default:
+		val = POWER_SUPPLY_HEALTH_UNKNOWN;
+		break;
+	}
+
+	return val;
+}
+
+static int max77843_charger_get_status(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret, val = 0;
+	unsigned int reg_data;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01,	&reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	reg_data &= MAX77843_CHG_DTLS_MASK;
+
+	switch (reg_data) {
+	case MAX77843_CHG_PQ_MODE:
+	case MAX77843_CHG_CC_MODE:
+	case MAX77843_CHG_CV_MODE:
+		val = POWER_SUPPLY_STATUS_CHARGING;
+		break;
+	case MAX77843_CHG_TO_MODE:
+	case MAX77843_CHG_DO_MODE:
+		val = POWER_SUPPLY_STATUS_FULL;
+		break;
+	case MAX77843_CHG_HT_MODE:
+	case MAX77843_CHG_TF_MODE:
+	case MAX77843_CHG_TS_MODE:
+		val = POWER_SUPPLY_STATUS_NOT_CHARGING;
+		break;
+	case MAX77843_CHG_OFF_MODE:
+		val = POWER_SUPPLY_STATUS_DISCHARGING;
+		break;
+	default:
+		val = POWER_SUPPLY_STATUS_UNKNOWN;
+		break;
+	}
+
+	return val;
+}
+
+static const char *model_name = "MAX77843";
+static const char *manufacturer = "Maxim Integrated";
+
+static int max77843_charger_get_property(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct max77843_charger *charger = container_of(psy,
+				struct max77843_charger, psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = max77843_charger_get_status(charger);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		val->intval = max77843_charger_get_health(charger);
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = max77843_charger_get_present(charger);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = max77843_charger_get_online(charger);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = max77843_charger_get_now_current(charger);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = max77843_charger_get_max_current(charger);
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval =  model_name;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = manufacturer;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static enum power_supply_property max77843_charger_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int max77843_charger_init_current_limit(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	struct max77843_charger_info *info = charger->info;
+	unsigned int input_uamp_limit = info->input_uamp_limit;
+	int ret;
+	unsigned int reg_data, val;
+
+	ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
+			MAX77843_CHG_OTG_ILIMIT_MASK,
+			MAX77843_CHG_OTG_ILIMIT_900);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN) {
+		reg_data = 0x03;
+	} else if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX) {
+		reg_data = 0x78;
+	} else {
+		if (input_uamp_limit < MAX77843_CHG_INPUT_CURRENT_LIMIT_REF)
+			val = 0x03;
+		else
+			val = 0x02;
+
+		input_uamp_limit -= MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
+		input_uamp_limit /= MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP;
+		reg_data = val + input_uamp_limit;
+	}
+
+	ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77843_charger_init_top_off(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	struct max77843_charger_info *info = charger->info;
+	unsigned int top_off_uamp = info->top_off_uamp;
+	int ret;
+	unsigned int reg_data;
+
+	if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MIN) {
+		reg_data = 0x00;
+	} else if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MAX) {
+		reg_data = 0x07;
+	} else {
+		top_off_uamp -= MAX77843_CHG_TOP_OFF_CURRENT_MIN;
+		top_off_uamp /= MAX77843_CHG_TOP_OFF_CURRENT_STEP;
+		reg_data = top_off_uamp;
+	}
+
+	ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_03,
+			MAX77843_CHG_TOP_OFF_CURRENT_MASK, reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77843_charger_init_fast_charge(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	struct max77843_charger_info *info = charger->info;
+	unsigned int fast_charge_uamp = info->fast_charge_uamp;
+	int ret;
+	unsigned int reg_data;
+
+	if (fast_charge_uamp < info->input_uamp_limit) {
+		reg_data = 0x09;
+	} else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MIN) {
+		reg_data = 0x02;
+	} else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MAX) {
+		reg_data = 0x3f;
+	} else {
+		fast_charge_uamp -= MAX77843_CHG_FAST_CHG_CURRENT_MIN;
+		fast_charge_uamp /= MAX77843_CHG_FAST_CHG_CURRENT_STEP;
+		reg_data = 0x02 + fast_charge_uamp;
+	}
+
+	ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
+			MAX77843_CHG_FAST_CHG_CURRENT_MASK, reg_data);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int max77843_charger_init(struct max77843_charger *charger)
+{
+	struct regmap *regmap = charger->regmap;
+	int ret;
+
+	ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_06,
+			MAX77843_CHG_WRITE_CAP_UNBLOCK);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_01,
+			MAX77843_CHG_RESTART_THRESHOLD_DISABLE);
+	if (ret) {
+		dev_err(charger->dev, "Failed to write configure register\n");
+		return ret;
+	}
+
+	ret = max77843_charger_init_fast_charge(charger);
+	if (ret) {
+		dev_err(charger->dev, "Failed to set fast charge mode.\n");
+		return ret;
+	}
+
+	ret = max77843_charger_init_top_off(charger);
+	if (ret) {
+		dev_err(charger->dev, "Failed to set top off charge mode.\n");
+		return ret;
+	}
+
+	ret = max77843_charger_init_current_limit(charger);
+
+	return 0;
+}
+
+static struct max77843_charger_info *max77843_charger_dt_init(
+		struct platform_device *pdev)
+{
+	struct max77843_charger_info *info;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	if (!np) {
+		dev_err(&pdev->dev, "No charger OF node\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return ERR_PTR(-ENOMEM);
+
+	ret = of_property_read_u32(np, "maxim,fast-charge-uamp",
+			&info->fast_charge_uamp);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot parse fast charge current.\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = of_property_read_u32(np, "maxim,top-off-uamp",
+			&info->top_off_uamp);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"Cannot parse primary charger termination voltage.\n");
+		return ERR_PTR(ret);
+	}
+
+	ret = of_property_read_u32(np, "maxim,input-uamp-limit",
+			&info->input_uamp_limit);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot parse input current limit value\n");
+		return ERR_PTR(ret);
+	}
+
+	return info;
+}
+
+static int max77843_charger_probe(struct platform_device *pdev)
+{
+	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
+	struct max77843_charger *charger;
+	int ret;
+
+	charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
+	if (!charger)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, charger);
+	charger->dev = &pdev->dev;
+	charger->max77843 = max77843;
+	charger->client = max77843->i2c_chg;
+	charger->regmap = max77843->regmap_chg;
+
+	charger->info = max77843_charger_dt_init(pdev);
+	if (IS_ERR_OR_NULL(charger->info)) {
+		ret = PTR_ERR(charger->info);
+		goto err_i2c;
+	}
+
+	charger->psy.name	= "max77843-charger";
+	charger->psy.type	= POWER_SUPPLY_TYPE_MAINS;
+	charger->psy.get_property	= max77843_charger_get_property;
+	charger->psy.properties		= max77843_charger_props;
+	charger->psy.num_properties	= ARRAY_SIZE(max77843_charger_props);
+
+	ret = max77843_charger_init(charger);
+	if (ret)
+		goto err_i2c;
+
+	ret = power_supply_register(&pdev->dev, &charger->psy);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed  to register power supply\n");
+		goto err_i2c;
+	}
+
+	return 0;
+
+err_i2c:
+	i2c_unregister_device(charger->client);
+
+	return ret;
+}
+
+static int max77843_charger_remove(struct platform_device *pdev)
+{
+	struct max77843_charger *charger = platform_get_drvdata(pdev);
+
+	power_supply_unregister(&charger->psy);
+
+	return 0;
+}
+
+static const struct platform_device_id max77843_charger_id[] = {
+	{ "max77843-charger", },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max77843_charger_id);
+
+static struct platform_driver max77843_charger_driver = {
+	.driver = {
+		.name = "max77843-charger",
+	},
+	.probe = max77843_charger_probe,
+	.remove = max77843_charger_remove,
+	.id_table = max77843_charger_id,
+};
+module_platform_driver(max77843_charger_driver);
+
+MODULE_DESCRIPTION("Maxim MAX77843 charger driver");
+MODULE_AUTHOR("Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5

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

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

* [PATCH 4/6] power: max77843_battery: Add Max77843 fuel gauge device driver
  2015-01-23  5:02 [PATCH 0/6] Add new MFD driver for MAX77843 Jaewon Kim
                   ` (2 preceding siblings ...)
  2015-01-23  5:02   ` Jaewon Kim
@ 2015-01-23  5:02 ` Jaewon Kim
  2015-01-25 13:53     ` Sebastian Reichel
  2015-01-23  5:02 ` [PATCH 5/6] regulator: max77843: Add max77843 regulator driver Jaewon Kim
  2015-01-23  5:02 ` [PATCH 6/6] Documentation: Add device tree bindings document for max77843 Jaewon Kim
  5 siblings, 1 reply; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-pm
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo

From: Beomho Seo <beomho.seo@samsung.com>

This patch adds device driver of max77843 fuel gauge.
The driver support for battery fuel gauge in Maxim Max77843.
It is fuel-gauge systems for lithuum-ion batteries in handled and
portable devices.

Cc: Sebastian Reichel <sre@kernel.org>
Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
---
 drivers/power/Kconfig            |    9 ++
 drivers/power/Makefile           |    1 +
 drivers/power/max77843_battery.c |  283 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 293 insertions(+)
 create mode 100644 drivers/power/max77843_battery.c

diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index a054a28..0039bbb 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -212,6 +212,15 @@ config BATTERY_MAX17042
 	  with MAX17042. This driver also supports max17047/50 chips which are
 	  improved version of max17042.
 
+config BATTERY_MAX77843
+	tristate "Maxim MAX77843 Fuel Gauge"
+	depends on MFD_MAX77843
+	help
+	  This add support for battery fuel gauge in Maxim MAX77843. It is
+	  fuel-gauge systems for lithuum-ion (Li+) batteries in handled and
+	  portable devices. The MAX17040 is configured to operate with a single
+	  lithium cell.
+
 config BATTERY_Z2
 	tristate "Z2 battery driver"
 	depends on I2C && MACH_ZIPIT2
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 212c6a2..ae0d795 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
 obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
 obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
+obj-$(CONFIG_BATTERY_MAX77843)	+= max77843_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
 obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
 obj-$(CONFIG_BATTERY_TWL4030_MADC)	+= twl4030_madc_battery.o
diff --git a/drivers/power/max77843_battery.c b/drivers/power/max77843_battery.c
new file mode 100644
index 0000000..a08dd0c
--- /dev/null
+++ b/drivers/power/max77843_battery.c
@@ -0,0 +1,283 @@
+/*
+ * Fuel gauge driver for Maxim MAX77843
+ *
+ * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
+ * Author: Beomho Seo <beomho.seo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published bythe Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/max77843-private.h>
+
+struct max77843_battery {
+	struct device		*dev;
+	struct max77843		*max77843;
+	struct i2c_client	*client;
+	struct regmap		*regmap;
+	struct power_supply	psy;
+};
+
+static int max77843_battery_get_capacity(struct max77843_battery *battery)
+{
+	struct regmap *regmap = battery->regmap;
+	int ret, val;
+	u8 reg_data[2];
+
+	ret = regmap_bulk_read(regmap, MAX77843_FG_REG_SOCREP, reg_data, 2);
+	if (ret) {
+		dev_err(battery->dev, "Failed to read fuelgauge register\n");
+		return ret;
+	}
+
+	val =  ((reg_data[1] * 100) + (reg_data[0] * 100 / 256)) / 100;
+
+	return val;
+}
+
+static int max77843_battery_get_energy_prop(struct max77843_battery *battery,
+		enum power_supply_property psp)
+{
+	struct regmap *regmap = battery->regmap;
+	unsigned int reg;
+	int ret, val;
+	u8 reg_data[2];
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ENERGY_FULL:
+		reg = MAX77843_FG_REG_FULLCAP;
+		break;
+	case POWER_SUPPLY_PROP_ENERGY_NOW:
+		reg = MAX77843_FG_REG_REMCAP_REP;
+		break;
+	case POWER_SUPPLY_PROP_ENERGY_AVG:
+		reg = MAX77843_FG_REG_REMCAP_AV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
+	if (ret) {
+		dev_err(battery->dev, "Failed to read fuelgauge register\n");
+		return ret;
+	}
+
+	val = (reg_data[1] << 8) | reg_data[0];
+
+	return val;
+}
+
+static int max77843_battery_get_current_prop(struct max77843_battery *battery,
+		enum power_supply_property psp)
+{
+	struct regmap *regmap = battery->regmap;
+	unsigned int reg;
+	int ret, val;
+	u8 reg_data[2];
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		reg = MAX77843_FG_REG_CURRENT;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		reg = MAX77843_FG_REG_AVG_CURRENT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
+	if (ret) {
+		dev_err(battery->dev, "Failed to read fuelgauge register\n");
+		return ret;
+	}
+
+	val = (reg_data[1] << 8) | reg_data[0];
+	if (val & 0x8000) {
+		/* Negative */
+		val = ~val & 0xffff;
+		val++;
+		val *= -1;
+	}
+	/* Unit of current is mA */
+	val =  val * 15625 / 100000;
+
+	return val;
+}
+
+static int max77843_battery_get_voltage_prop(struct max77843_battery *battery,
+		enum power_supply_property psp)
+{
+	struct regmap *regmap = battery->regmap;
+	unsigned int reg;
+	int ret, val;
+	u8 reg_data[2];
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		reg = MAX77843_FG_REG_VCELL;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+		reg = MAX77843_FG_REG_AVG_VCELL;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		reg = MAX77843_FG_REG_OCV;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
+	if (ret) {
+		dev_err(battery->dev, "Failed to read fuelgauge register\n");
+		return ret;
+	}
+
+	val = ((reg_data[1] << 4) + (reg_data[0] >> 4)) * 125;
+	val /= 100;
+
+	return val;
+}
+
+static const char *model_name = "MAX77843";
+static const char *manufacturer = "Maxim Integrated";
+
+static int max77843_battery_get_property(struct power_supply *psy,
+		enum power_supply_property psp,
+		union power_supply_propval *val)
+{
+	struct max77843_battery *battery = container_of(psy,
+				struct max77843_battery, psy);
+	switch (psp) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		val->intval = max77843_battery_get_voltage_prop(battery, psp);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		val->intval = max77843_battery_get_current_prop(battery, psp);
+		break;
+	case POWER_SUPPLY_PROP_ENERGY_FULL:
+	case POWER_SUPPLY_PROP_ENERGY_NOW:
+	case POWER_SUPPLY_PROP_ENERGY_AVG:
+		val->intval = max77843_battery_get_energy_prop(battery, psp);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = max77843_battery_get_capacity(battery);
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval =  model_name;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = manufacturer;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static enum power_supply_property max77843_battery_props[] = {
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_VOLTAGE_AVG,
+	POWER_SUPPLY_PROP_VOLTAGE_OCV,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CURRENT_AVG,
+	POWER_SUPPLY_PROP_ENERGY_FULL,
+	POWER_SUPPLY_PROP_ENERGY_NOW,
+	POWER_SUPPLY_PROP_ENERGY_AVG,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static const struct regmap_config max77843_fuel_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= MAX77843_FG_END,
+};
+
+static int max77843_battery_probe(struct platform_device *pdev)
+{
+	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
+	struct max77843_battery *battery;
+	int ret;
+
+	battery = devm_kzalloc(&pdev->dev, sizeof(*battery), GFP_KERNEL);
+	if (!battery)
+		return -ENOMEM;
+
+	battery->dev = &pdev->dev;
+	battery->max77843 = max77843;
+
+	battery->client = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_FG);
+	if (!battery->client) {
+		dev_err(&pdev->dev, "Failed to get dummy i2c client.\n");
+		return PTR_ERR(battery->client);
+	}
+	i2c_set_clientdata(battery->client, max77843);
+
+	battery->regmap = devm_regmap_init_i2c(battery->client,
+			&max77843_fuel_regmap_config);
+	if (IS_ERR(battery->regmap)) {
+		ret = PTR_ERR(battery->regmap);
+		goto err_i2c;
+	}
+
+	platform_set_drvdata(pdev, battery);
+
+	battery->psy.name	= "max77843-fuelgauge";
+	battery->psy.type	= POWER_SUPPLY_TYPE_BATTERY;
+	battery->psy.get_property	= max77843_battery_get_property;
+	battery->psy.properties		= max77843_battery_props;
+	battery->psy.num_properties	= ARRAY_SIZE(max77843_battery_props);
+
+	ret = power_supply_register(&pdev->dev, &battery->psy);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed  to register power supply\n");
+		goto err_i2c;
+	}
+
+	return 0;
+
+err_i2c:
+	i2c_unregister_device(battery->client);
+
+	return ret;
+}
+
+static int max77843_battery_remove(struct platform_device *pdev)
+{
+	struct max77843_battery *battery = platform_get_drvdata(pdev);
+
+	power_supply_unregister(&battery->psy);
+
+	return 0;
+}
+
+static const struct platform_device_id max77843_battery_id[] = {
+	{ "max77843-fuelgauge", },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, max77843_battery_id);
+
+static struct platform_driver max77843_battery_driver = {
+	.driver = {
+		.name = "max77843-fuelgauge",
+	},
+	.probe = max77843_battery_probe,
+	.remove = max77843_battery_remove,
+	.id_table = max77843_battery_id,
+};
+module_platform_driver(max77843_battery_driver);
+
+MODULE_DESCRIPTION("Maxim MAX77843 fuel gauge driver");
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


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

* [PATCH 5/6] regulator: max77843: Add max77843 regulator driver
  2015-01-23  5:02 [PATCH 0/6] Add new MFD driver for MAX77843 Jaewon Kim
                   ` (3 preceding siblings ...)
  2015-01-23  5:02 ` [PATCH 4/6] power: max77843_battery: Add Max77843 fuel gauge " Jaewon Kim
@ 2015-01-23  5:02 ` Jaewon Kim
  2015-01-23  7:18   ` Krzysztof Kozłowski
  2015-01-23  5:02 ` [PATCH 6/6] Documentation: Add device tree bindings document for max77843 Jaewon Kim
  5 siblings, 1 reply; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-pm
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo, Jaewon Kim

This patch adds new regulator driver to support max77843
MFD(Multi Function Device) chip`s regulators.
The Max77843 has two voltage regulators for USB safeout.

Cc: Mark Brown <broonie@kernel.org>
Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
---
 drivers/regulator/Kconfig    |    8 ++
 drivers/regulator/Makefile   |    1 +
 drivers/regulator/max77843.c |  259 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 268 insertions(+)
 create mode 100644 drivers/regulator/max77843.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index c3a60b5..c1f9c33 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -414,6 +414,14 @@ config REGULATOR_MAX77802
 	  Exynos5420/Exynos5800 SoCs to control various voltages.
 	  It includes support for control of voltage and ramp speed.
 
+config REGULATOR_MAX77843
+	tristate "Maxim 77843 regulator"
+	depends on MFD_MAX77843
+	help
+	  This driver controls a Maxim 77843 regulator.
+	  The regulator include two 'SAFEOUT' for USB(Universal Serial Bus)
+	  This is suitable for Exynos5433 SoC chips.
+
 config REGULATOR_MC13XXX_CORE
 	tristate
 
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 1f28ebf..12408d6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
 obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
+obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c
new file mode 100644
index 0000000..86afc7a
--- /dev/null
+++ b/drivers/regulator/max77843.c
@@ -0,0 +1,259 @@
+/*
+ * max77843.c - Regulator driver for the Maxim MAX77843
+ *
+ * Copyright (C) 2014 Samsung Electrnoics
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max77843-private.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MAX77843_SUPPORTED_VOLTAGE_NUM	4
+
+enum max77843_regulator_type {
+	MAX77843_SAFEOUT1 = 0,
+	MAX77843_SAFEOUT2,
+	MAX77843_CHARGER,
+
+	MAX77843_NUM,
+};
+
+static const unsigned int max77843_regulator_table[] = {
+	4850000,
+	4900000,
+	4950000,
+	3300000,
+};
+
+static int max77843_reg_is_enabled(struct regulator_dev *rdev)
+{
+	struct regmap *regmap = rdev->regmap;
+	int ret;
+	unsigned int reg;
+
+	ret = regmap_read(regmap, rdev->desc->enable_reg, &reg);
+	if (ret) {
+		dev_err(&rdev->dev, "Fialed to read charger register\n");
+		return ret;
+	}
+
+	return (reg & rdev->desc->enable_mask) == rdev->desc->enable_mask;
+}
+
+static int max77843_reg_get_current_limit(struct regulator_dev *rdev)
+{
+	struct regmap *regmap = rdev->regmap;
+	unsigned int chg_min_uA = rdev->constraints->min_uA;
+	unsigned int chg_max_uA = rdev->constraints->max_uA;
+	unsigned int val;
+	int ret;
+	unsigned int reg, sel;
+
+	ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg);
+	if (ret) {
+		dev_err(&rdev->dev, "Failed to read charger register\n");
+		return ret;
+	}
+
+	sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK;
+
+	if (sel < 0x03)
+		sel = 0;
+	else
+		sel -= 2;
+
+	val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel;
+	if (val > chg_max_uA)
+		return -EINVAL;
+
+	return val;
+}
+
+static int max77843_reg_set_current_limit(struct regulator_dev *rdev,
+		int min_uA, int max_uA)
+{
+	struct regmap *regmap = rdev->regmap;
+	unsigned int chg_min_uA = rdev->constraints->min_uA;
+	int sel = 0;
+
+	while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA)
+		sel++;
+
+	if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA)
+		return -EINVAL;
+
+	sel += 2;
+
+	return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel);
+}
+
+static struct regulator_ops max77843_charger_ops = {
+	.is_enabled		= max77843_reg_is_enabled,
+	.enable			= regulator_enable_regmap,
+	.disable		= regulator_disable_regmap,
+	.get_current_limit	= max77843_reg_get_current_limit,
+	.set_current_limit	= max77843_reg_set_current_limit,
+};
+
+static struct regulator_ops max77843_regulator_ops = {
+	.is_enabled             = regulator_is_enabled_regmap,
+	.enable                 = regulator_enable_regmap,
+	.disable                = regulator_disable_regmap,
+	.list_voltage		= regulator_list_voltage_table,
+	.get_voltage_sel        = regulator_get_voltage_sel_regmap,
+	.set_voltage_sel        = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc max77843_supported_regulators[] = {
+	[MAX77843_SAFEOUT1] = {
+		.name		= "SAFEOUT1",
+		.id		= MAX77843_SAFEOUT1,
+		.ops		= &max77843_regulator_ops,
+		.type		= REGULATOR_VOLTAGE,
+		.owner		= THIS_MODULE,
+		.n_voltages	= MAX77843_SUPPORTED_VOLTAGE_NUM,
+		.volt_table	= max77843_regulator_table,
+		.enable_reg	= MAX77843_SYS_REG_SAFEOUTCTRL,
+		.enable_mask	= MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1,
+		.vsel_reg	= MAX77843_SYS_REG_SAFEOUTCTRL,
+		.vsel_mask	= MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK,
+	},
+	[MAX77843_SAFEOUT2] = {
+		.name           = "SAFEOUT2",
+		.id             = MAX77843_SAFEOUT2,
+		.ops            = &max77843_regulator_ops,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.n_voltages     = MAX77843_SUPPORTED_VOLTAGE_NUM,
+		.volt_table	= max77843_regulator_table,
+		.enable_reg     = MAX77843_SYS_REG_SAFEOUTCTRL,
+		.enable_mask    = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2,
+		.vsel_reg	= MAX77843_SYS_REG_SAFEOUTCTRL,
+		.vsel_mask	= MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK,
+	},
+	[MAX77843_CHARGER] = {
+		.name		= "CHARGER",
+		.id		= MAX77843_CHARGER,
+		.ops		= &max77843_charger_ops,
+		.type		= REGULATOR_CURRENT,
+		.owner		= THIS_MODULE,
+		.enable_reg	= MAX77843_CHG_REG_CHG_CNFG_00,
+		.enable_mask	= MAX77843_CHG_MASK,
+	},
+};
+
+static struct of_regulator_match max77843_regulator_matches[] = {
+	{ .name = "SAFEOUT1", },
+	{ .name = "SAFEOUT2", },
+	{ .name = "CHARGER", },
+};
+
+static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id)
+{
+	switch (reg_id) {
+	case MAX77843_SAFEOUT1:
+	case MAX77843_SAFEOUT2:
+		return max77843->regmap;
+	case MAX77843_CHARGER:
+		return max77843->regmap_chg;
+	default:
+		return max77843->regmap;
+	}
+}
+
+static int max77843_regulator_dt_parse(struct platform_device *pdev)
+{
+	struct device_node *np;
+	int ret;
+
+	np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
+	if (!np) {
+		dev_err(&pdev->dev,
+			"Cannot get child OF node for regulators\n");
+		return -EINVAL;
+	}
+
+	ret = of_regulator_match(&pdev->dev, np, max77843_regulator_matches,
+			ARRAY_SIZE(max77843_regulator_matches));
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Cannot parsing regulator init data\n");
+		return ret;
+	}
+
+	of_node_put(np);
+
+	return 0;
+}
+
+static int max77843_regulator_probe(struct platform_device *pdev)
+{
+	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
+	struct regulator_config config = {};
+	int i, ret;
+
+	ret = max77843_regulator_dt_parse(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to parse device tree\n");
+		return ret;
+	}
+
+	config.dev = &pdev->dev;
+	config.driver_data = max77843;
+
+	for (i = 0; i < ARRAY_SIZE(max77843_supported_regulators); i++) {
+		struct regulator_dev *regulator;
+
+		config.init_data = max77843_regulator_matches[i].init_data;
+		config.of_node = max77843_regulator_matches[i].of_node;
+		config.regmap = max77843_get_regmap(max77843,
+				max77843_supported_regulators[i].id);
+
+		regulator = devm_regulator_register(&pdev->dev,
+				&max77843_supported_regulators[i], &config);
+		if (IS_ERR(regulator)) {
+			dev_err(&pdev->dev,
+					"Failed to regiser regulator-%d\n", i);
+			return PTR_ERR(regulator);
+		}
+	}
+
+	return 0;
+}
+
+static const struct platform_device_id max77843_regulator_id[] = {
+	{ "max77843-regulator", },
+	{ /* sentinel */ },
+};
+
+static struct platform_driver max77843_regulator_driver = {
+	.driver	= {
+		.name = "max77843-regulator",
+	},
+	.probe		= max77843_regulator_probe,
+	.id_table	= max77843_regulator_id,
+};
+
+static int __init max77843_regulator_init(void)
+{
+	return platform_driver_register(&max77843_regulator_driver);
+}
+subsys_initcall(max77843_regulator_init);
+
+static void __exit max77843_regulator_exit(void)
+{
+	platform_driver_unregister(&max77843_regulator_driver);
+}
+module_exit(max77843_regulator_exit);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_DESCRIPTION("Maxim MAX77843 regulator driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5


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

* [PATCH 6/6] Documentation: Add device tree bindings document for max77843
  2015-01-23  5:02 [PATCH 0/6] Add new MFD driver for MAX77843 Jaewon Kim
                   ` (4 preceding siblings ...)
  2015-01-23  5:02 ` [PATCH 5/6] regulator: max77843: Add max77843 regulator driver Jaewon Kim
@ 2015-01-23  5:02 ` Jaewon Kim
  2015-01-23  6:25     ` Chanwoo Choi
  5 siblings, 1 reply; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  5:02 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-pm
  Cc: Inki Dae, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
	Kumar Gala, Lee Jones, Chanwoo Choi, Sebastian Reichel,
	Mark Brown, Beomho Seo, Jaewon Kim

Add document describing device tree bindings for max77843 MFD.
Drivers: MFD core, regulator, extcon, charger and fuelgauge.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
Cc: Kumar Gala <galak@codeaurora.org>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: Chanwoo Choi <cw00.choi@samsung.com>
Cc: Sebastian Reichel <sre@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
---
 Documentation/devicetree/bindings/mfd/max77843.txt |   87 ++++++++++++++++++++
 1 file changed, 87 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/max77843.txt

diff --git a/Documentation/devicetree/bindings/mfd/max77843.txt b/Documentation/devicetree/bindings/mfd/max77843.txt
new file mode 100644
index 0000000..6895604
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/max77843.txt
@@ -0,0 +1,87 @@
+Maxim MAX77843 multi-function device
+
+MAX77843 is a Multi-Function Device with the following submodules:
+- PMIC	  : 2 SAFEOUT LDOs for USB device
+- CHARGER : Li+ battery charger with Fuel Gauge
+- MUIC	  : Micro USB Interface Circuit
+- HAPTIC  : motor control driver for haptics
+- LED	  : 4 channel RGBW LED
+
+It is interfaced to host controller using I2C.
+
+Required properties:
+- compatible : Must be "maxim,max77843".
+- reg : I2C slave address of PMIC block.
+- interrupts : I2C line for main SoCs.
+- interrupt-parent : The parent of interrupt controller.
+
+Optional properties:
+- regulators : The regulators of max77843 have to be instantiated under subnode
+	named "regulators" using the following format.
+
+	[*]refer : Documentation/devicetree/bindings/regulator/regulator.txt
+
+	regulators {
+		SAFEOUT {
+			regulator-name = "SAFEOUT";
+		};
+	}
+
+	List of valid regulator names:
+	- SAFEOUT1, SAFEOUT2, CHARGER.
+
+- max77843-muic : This properties used by extcon consumers.
+	Required properties:
+		- compatible : Must be "maxim,max77842-muic".
+
+- max77843-charger : There battery charger of MAX77843 have to be instantiated
+	under sub-node named "max77843-charger" using the following format.
+	Required properties:
+		- compatible : Must be "maxim,max77842-charger".
+		- maxim,fast-charge-uamp : Fast charge current levels are
+			100 mA to 3150 mA programmed by I2C per 100 mA.
+		- maxim,top-off-uamp : Top off current threshold levels are
+			125 mA to 650 mA programmed by I2C per 75 mA.
+		- maxim,input-uamp-limit : Input current limit levels are
+			100 mA to 3533 mA programmed by I2C per 33 mA.
+- max77843-fuelgauge : There fuelgauge of MAX77843 have to be instantiated
+	under sub-node named "max77843-fuelgauge" using the following format.
+	Required properties:
+		- compatible : Must be "maxim,max77842-fuelgauge".
+
+Example:
+	max77843@66 {
+		compatible = "samsung,max77843";
+		reg = <0x66>;
+		interrupt-parent = <&gpa1>;
+		interrupts = <5 2>;
+
+		regulators {
+			SAFEOUT1 {
+				regulator-name = "SAFEOUT1";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <4950000>;
+			};
+			SAFEOUT2 {
+				regulator-name = "SAFEOUT2";
+				regulator-min-microvolt = <3300000>;
+				regulator-max-microvolt = <4950000>;
+			};
+		};
+
+		max77843-muic {
+			compatible = "maxim,max77843-muic";
+		};
+
+		max77843-charger {
+			compatible = "maxim,max77843-charger";
+			maxim,fast-charge-uamp = <450000>;
+			maxim,top-off-uamp = <125000>;
+			maxim,input-uamp-limit = <500000>;
+		};
+
+		max77843-fuelgauge {
+			compatible = "maxim,max77843-fuelgauge";
+		};
+
+	};
-- 
1.7.9.5


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

* Re: [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver
@ 2015-01-23  6:21     ` Chanwoo Choi
  0 siblings, 0 replies; 41+ messages in thread
From: Chanwoo Choi @ 2015-01-23  6:21 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown, Beomho Seo

Hi Jaewon,

On 01/23/2015 02:02 PM, Jaewon Kim wrote:
> This patch adds MAX77843 extcon driver to support for MUIC(Micro

Add company name (MAX77843 -> Maxim MAX77843)

> USB Interface Controller) device by using EXTCON subsystem to handle
> various external connectors.
> 
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> ---
>  drivers/extcon/Kconfig           |   10 +
>  drivers/extcon/Makefile          |    1 +
>  drivers/extcon/extcon-max77843.c |  871 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 882 insertions(+)
>  create mode 100644 drivers/extcon/extcon-max77843.c
> 
> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
> index 6a1f7de..0b67538 100644
> --- a/drivers/extcon/Kconfig
> +++ b/drivers/extcon/Kconfig
> @@ -55,6 +55,16 @@ config EXTCON_MAX77693
>  	  Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory
>  	  detector and switch.
>  
> +config EXTCON_MAX77843
> +	tristate "MAX77843 EXTCON Support"
> +	depends on MFD_MAX77843
> +	select IRQ_DOMAIN
> +	select REGMAP_I2C
> +	help
> +	  If you say yes here you get support for the MUIC device of
> +	  Maxim MAX77843. The MAX77843 MUIC is a USB port accessory
> +	  detector add switch.
> +
>  config EXTCON_MAX8997
>  	tristate "MAX8997 EXTCON Support"
>  	depends on MFD_MAX8997 && IRQ_DOMAIN
> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
> index 0370b42..f21d5c4 100644
> --- a/drivers/extcon/Makefile
> +++ b/drivers/extcon/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
>  obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
>  obj-$(CONFIG_EXTCON_MAX14577)	+= extcon-max14577.o
>  obj-$(CONFIG_EXTCON_MAX77693)	+= extcon-max77693.o
> +obj-$(CONFIG_EXTCON_MAX77843)	+= extcon-max77843.o
>  obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
> diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
> new file mode 100644
> index 0000000..caae9a7
> --- /dev/null
> +++ b/drivers/extcon/extcon-max77843.c
> @@ -0,0 +1,871 @@
> +/*
> + * extcon-max77843.c - MAX77843 extcon driver to support MUIC
> + *
> + * Copyright (C) 2014 Samsung Electrnoics
> + *  Author: Jaewon Kim <jaewon02.kim@samsung.com>

Remove un-necessary blank before 'Author'.

> + *
> + * 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/extcon.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/max77843-private.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/workqueue.h>
> +
> +#define DELAY_MS_DEFAULT		15000	/* unit: millisecond */
> +
> +enum max77843_muic_acc_type {
> +	MAX77843_MUIC_ADC_GROUND = 0,
> +	MAX77843_MUIC_ADC_SEND_END_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S1_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S2_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S3_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S4_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S5_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S6_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S7_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S8_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S9_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S10_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S11_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S12_BUTTON,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_1,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_2,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_3,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_4,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_5,
> +	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2,
> +	MAX77843_MUIC_ADC_PHONE_POWERED_DEV,
> +	MAX77843_MUIC_ADC_TTY_CONVERTER,
> +	MAX77843_MUIC_ADC_UART_CABLE,
> +	MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON,
> +	MAX77843_MUIC_ADC_AV_CABLE_NOLOAD,
> +	MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON,
> +	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
> +	MAX77843_MUIC_ADC_OPEN,
> +};
> +
> +enum max77843_muic_cable_group {
> +	MAX77843_CABLE_GROUP_ADC = 0,
> +	MAX77843_CABLE_GROUP_CHG,
> +	MAX77843_CABLE_GROUP_GND,
> +};

Cable group show the category of supported cables.
I think you better move this enum on upper of 'enum max77843_muic_acc_type'

> +
> +enum max77843_muic_adv_debounce_time {
> +	MAX77843_DEBOUNCE_TIME_5MS = 0,
> +	MAX77843_DEBOUNCE_TIME_10MS,
> +	MAX77843_DEBOUNCE_TIME_25MS,
> +	MAX77843_DEBOUNCE_TIME_38_62MS,
> +};
> +
> +enum max77843_muic_support_list {

Use only 'enum' keyword without 'max77843_muic_support_list' enum name.

> +	EXTCON_CABLE_USB = 0,
> +	EXTCON_CABLE_USB_HOST,
> +	EXTCON_CABLE_USB_HOST_TA,
> +	EXTCON_CABLE_TA,
> +	EXTCON_CABLE_FAST_CHARGER,
> +	EXTCON_CABLE_SLOW_CHARGER,
> +	EXTCON_CABLE_CHARGE_DOWNSTREAM,
> +	EXTCON_CABLE_MHL,
> +	EXTCON_CABLE_MHL_TA,
> +	EXTCON_CABLE_JIG_USB_ON,
> +	EXTCON_CABLE_JIG_USB_OFF,
> +	EXTCON_CABLE_JIG_UART_OFF,
> +	EXTCON_CABLE_JIG_UART_ON,
> +
> +	EXTCON_CABLE_NUM,
> +};
> +
> +enum max77843_muic_gnd_cable {
> +	MAX77843_MUIC_GND_USB_OTG	= 0x0,
> +	MAX77843_MUIC_GND_USB_OTG_VB	= 0x1,
> +	MAX77843_MUIC_GND_MHL		= 0x2,
> +	MAX77843_MUIC_GND_MHL_VB	= 0x3,

Why do you need 'max77843_muic_gnd_cable' enum?
You have to express supported all cables in 'max77843_muic_acc_type' enum list.
If you define one more cables enumeration, It is possible to incur the confusion
of what this driver is supported cable.


> +
> +	MAX77843_MUIC_GND_NUM,
> +};
> +
> +enum max77843_muic_status {
> +	MAX77843_MUIC_STATUS1 = 0,
> +	MAX77843_MUIC_STATUS2,
> +	MAX77843_MUIC_STATUS3,
> +
> +	MAX77843_MUIC_STATUS_NUM,
> +};
> +
> +enum max77843_muic_charger_type {
> +	MAX77843_CHG_TYPE_NONE = 0,
> +	MAX77843_CHG_TYPE_USB,
> +	MAX77843_CHG_TYPE_DOWNSTREAM,
> +	MAX77843_CHG_TYPE_DEDICATED,
> +	MAX77843_CHG_TYPE_SPECIAL_500MA,
> +	MAX77843_CHG_TYPE_SPECIAL_1A,
> +	MAX77843_CHG_TYPE_SPECIAL_BIAS,
> +
> +	MAX77843_CHG_TYPE_END,
> +};
> +
> +enum max77843_muic_detection {
> +	MAX77843_MUIC_AUTO_NONE = 0,
> +	MAX77843_MUIC_AUTO_USB,
> +	MAX77843_MUIC_AUTO_FAC,
> +	MAX77843_MUIC_AUTO_USB_FAC,
> +};

It it wrong. This enum is used to write the value to MUIC register.
You have to define it in max77843-private.h with 'enum' keyword.
I think you could refer other definition in max77843-private.h.

You have to re-order the definition by using follwoing sequence
to improbe readability.
1. cable group
2. supported cables
3. other definition with enum

Also,
I'm difficult to understand the meaning of enum definition.
MAX77843_MUIC_*
MAX77843_CABLE_*
MAX77843_DEBOUNCE_*
MAX77843_CHG_*

I think you need to clarify the meaning of enum definition
by makingt the name pattern to improve readability.

> +
> +struct max77843_muic_info {
> +	struct device *dev;
> +	struct max77843 *max77843;
> +	struct extcon_dev *edev;
> +
> +	struct mutex mutex;
> +	struct work_struct irq_work;
> +	struct delayed_work wq_detcable;
> +	struct max77843_muic_irq *muic_irqs;
> +
> +	u8 status[MAX77843_MUIC_STATUS_NUM];
> +	int prev_cable_type;
> +	int prev_chg_type;
> +	int prev_gnd_type;
> +
> +	bool irq_adc;
> +	bool irq_chg;
> +	bool init_done;

I don't want to use the 'init_don' field. I think it is legacy way
to solve some issue. I recommend you use other way.

> +};
> +
> +struct max77843_muic_irq {
> +	unsigned int irq;
> +	const char *name;
> +	unsigned int virq;
> +};
> +
> +static const struct regmap_config max77843_muic_regmap_config = {
> +	.reg_bits       = 8,
> +	.val_bits       = 8,
> +	.max_register   = MAX77843_MUIC_REG_END,
> +};
> +
> +static const struct regmap_irq max77843_muic_irq[] = {
> +	/* MUIC:INT1 interrupts */
	
Don' need 'MUIC:' prefix and fix string (s/interrupts/interrupt).

> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC, },
> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADCERROR, },
> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC1K, },
> +
> +	/* MUIC:INT2 interrupts */

ditto.

> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGTYP, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGDETRUN, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_DCDTMR, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_DXOVP, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_VBVOLT, },
> +
> +	/* MUIC:INT3 interrupts */

ditto.

> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_VBADC, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_VDNMON, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_DNRES, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MPNACK, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXBUFOW, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXTRF, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXPERR, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXRDY, },
> +};
> +
> +static const struct regmap_irq_chip max77843_muic_irq_chip = {
> +	.name           = "max77843-muic",
> +	.status_base    = MAX77843_MUIC_REG_INT1,
> +	.mask_base      = MAX77843_MUIC_REG_INTMASK1,
> +	.mask_invert    = true,
> +	.num_regs       = 3,
> +	.irqs           = max77843_muic_irq,
> +	.num_irqs       = ARRAY_SIZE(max77843_muic_irq),
> +};
> +
> +static const char *max77843_extcon_cable[] = {
> +	[EXTCON_CABLE_USB]			= "USB",
> +	[EXTCON_CABLE_USB_HOST]			= "USB-HOST",
> +	[EXTCON_CABLE_USB_HOST_TA]		= "USB-HOST-TA",
> +	[EXTCON_CABLE_TA]			= "TA",
> +	[EXTCON_CABLE_FAST_CHARGER]		= "FAST-CHARGER",
> +	[EXTCON_CABLE_SLOW_CHARGER]		= "SLOW-CHARGER",
> +	[EXTCON_CABLE_CHARGE_DOWNSTREAM]	= "CHARGER-DOWNSTREAM",
> +	[EXTCON_CABLE_MHL]			= "MHL",
> +	[EXTCON_CABLE_MHL_TA]			= "MHL-TA",
> +	[EXTCON_CABLE_JIG_USB_ON]		= "JIG-USB-ON",
> +	[EXTCON_CABLE_JIG_USB_OFF]		= "JIG-USB-OFF",
> +	[EXTCON_CABLE_JIG_UART_OFF]		= "JIG-UART-OFF",
> +	[EXTCON_CABLE_JIG_UART_ON]		= "JIG-UART-ON",
> +};
> +
> +static struct max77843_muic_irq max77843_muic_irqs[] = {
> +	{ MAX77843_MUIC_IRQ_INT1_ADC,		"MUIC-ADC" },
> +	{ MAX77843_MUIC_IRQ_INT1_ADCERROR,	"MUIC-ADC_ERROR" },
> +	{ MAX77843_MUIC_IRQ_INT1_ADC1K,		"MUIC-ADC1K" },
> +	{ MAX77843_MUIC_IRQ_INT2_CHGTYP,	"MUIC-CHGTYP" },
> +	{ MAX77843_MUIC_IRQ_INT2_CHGDETRUN,	"MUIC-CHGDETRUN" },
> +	{ MAX77843_MUIC_IRQ_INT2_DCDTMR,	"MUIC-DCDTMR" },
> +	{ MAX77843_MUIC_IRQ_INT2_DXOVP,		"MUIC-DXOVP" },
> +	{ MAX77843_MUIC_IRQ_INT2_VBVOLT,	"MUIC-VBVOLT" },
> +	{ MAX77843_MUIC_IRQ_INT3_VBADC,		"MUIC-VBADC" },
> +	{ MAX77843_MUIC_IRQ_INT3_VDNMON,	"MUIC-VDNMON" },
> +	{ MAX77843_MUIC_IRQ_INT3_DNRES,		"MUIC-DNRES" },
> +	{ MAX77843_MUIC_IRQ_INT3_MPNACK,	"MUIC-MPNACK"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXBUFOW,	"MUIC-MRXBUFOW"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXTRF,	"MUIC-MRXTRF"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXPERR,	"MUIC-MRXPERR"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXRDY,	"MUIC-MRXRDY"},
> +};
> +
> +static int max77843_muic_set_path(struct max77843_muic_info *info,
> +		u8 val, bool attached)
> +{
> +	struct max77843 *max77843 = info->max77843;
> +	int ret = 0;
> +	unsigned int ctrl1, ctrl2;
> +
> +	if (attached)
> +		ctrl1 = val;
> +	else
> +		ctrl1 = MAX77843_SWITCH_OPEN;

'SWITCH' keyword is right?
I can't the 'SWITCH' word in CONTROL1 register of MAX77843 MUIC datasheet.
When you define the field for register, I prefer to use the word which
expressed in register map of datasheet.

> +
> +	ret = regmap_update_bits(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_CONTROL1,
> +			MAX77843_SIWTH_PORT, ctrl1);
> +	if (ret < 0) {
> +		dev_err(info->dev, "Cannot switch MUIC port\n");
> +		return ret;
> +	}
> +
> +	if (attached)
> +		ctrl2 = MAX77843_MUIC_CONTROL2_CPEN_MASK;
> +	else
> +		ctrl2 = MAX77843_MUIC_CONTROL2_LOWPWR_MASK;
> +
> +	ret = regmap_update_bits(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_CONTROL2,
> +			MAX77843_MUIC_CONTROL2_LOWPWR_MASK |
> +			MAX77843_MUIC_CONTROL2_CPEN_MASK, ctrl2);
> +	if (ret < 0) {
> +		dev_err(info->dev, "Cannot update lowpower mode\n");
> +		return ret;
> +	}
> +
> +	dev_dbg(info->dev,
> +		"CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
> +		ctrl1, ctrl2, attached ? "attached" : "detached");
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
> +		enum max77843_muic_cable_group group, bool *attached)
> +{
> +	int adc, chg_type, cable_type, gnd_type;
> +
> +	adc = info->status[MAX77843_MUIC_STATUS1] &
> +			MAX77843_MUIC_STATUS1_ADC_MASK;

If you use the short definition for 'MAX77843_MUIC_STATUS1',
you could make this code on one line.

> +	adc >>= STATUS1_ADC_SHIFT;
> +
> +	switch (group) {
> +	case MAX77843_CABLE_GROUP_ADC:
> +		if (adc == MAX77843_MUIC_ADC_OPEN) {
> +			*attached = false;
> +			cable_type = info->prev_cable_type;
> +			info->prev_cable_type = MAX77843_MUIC_ADC_OPEN;
> +		} else {
> +			*attached = true;
> +			cable_type = info->prev_cable_type = adc;
> +		}
> +
> +		break;
> +	case MAX77843_CABLE_GROUP_CHG:
> +		if (adc == MAX77843_MUIC_ADC_GROUND) {
> +			*attached = true;
> +			cable_type = adc;
> +			break;
> +		}
> +
> +		chg_type = info->status[MAX77843_MUIC_STATUS2] &
> +			MAX77843_MUIC_STATUS2_CHGTYP_MASK;

ditto and I think you need one more indentation for readabiltiy.


> +		chg_type >>= STATUS2_CHGTYP_SHIFT;
> +

Remove unneeded blank line.

> +		if (chg_type == MAX77843_CHG_TYPE_NONE) {
> +			*attached = false;
> +			cable_type = info->prev_chg_type;
> +			info->prev_chg_type = MAX77843_CHG_TYPE_NONE;
> +		} else {
> +			*attached = true;
> +			cable_type = info->prev_chg_type = chg_type;
> +		}
> +
> +		break;
> +	case MAX77843_CABLE_GROUP_GND:
> +		adc = info->status[MAX77843_MUIC_STATUS1] &
> +			MAX77843_MUIC_STATUS1_ADC_MASK;

ditto.

> +		adc >>= STATUS1_ADC_SHIFT;
> +
> +		if (adc == MAX77843_MUIC_ADC_GROUND) {
> +			*attached = true;
> +			gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
> +					MAX77843_MUIC_STATUS1_ADC1K_MASK) >>
> +					(STATUS1_ADC1K_SHIFT-1);
> +			gnd_type |= (info->status[MAX77843_MUIC_STATUS2] &
> +					MAX77843_MUIC_STATUS2_VBVOLT_MASK) >>
> +					STATUS2_VBVOLT_SHIFT;
> +			cable_type = info->prev_gnd_type = gnd_type;
> +		} else {
> +			*attached = false;
> +			cable_type = info->prev_gnd_type;
> +			info->prev_gnd_type = MAX77843_MUIC_GND_NUM;
> +		}
> +
> +		break;
> +	default:
> +		dev_err(info->dev, "Unknown cable group (%d)\n", group);
> +		cable_type = -EINVAL;
> +
> +		break;
> +	}
> +
> +	return cable_type;
> +}
> +
> +static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
> +{
> +	int ret, gnd_cable_type;
> +	u8 path;
> +	bool attached;
> +
> +	gnd_cable_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_GND, &attached);
> +	dev_dbg(info->dev, "external connector is %s (gnd:0x%02x)\n",
> +			attached ? "attached" : "detached", gnd_cable_type);
> +
> +	switch (gnd_cable_type) {
> +	case MAX77843_MUIC_GND_USB_OTG:
> +		extcon_set_cable_state(info->edev, "USB-HOST", attached);
> +		path = MAX77843_SWITCH_USB;

Change the name insted of 'SWITCH' word.

Also, I think you have to change the path before sending uevent about cable information.
If you set cable state before setting the path, user-process might get the uevent
before changing the MUIC path. You have to modify it when cable state is changed.

> +		info->irq_chg = false;
> +		break;
> +	case MAX77843_MUIC_GND_USB_OTG_VB:
> +		extcon_set_cable_state(info->edev, "USB-HOST-TA", attached);
> +		path = MAX77843_SWITCH_USB;

ditto.

> +		info->irq_chg = false;
> +		break;
> +	case MAX77843_MUIC_GND_MHL:
> +		extcon_set_cable_state(info->edev, "MHL", attached);
> +		path = MAX77843_SWITCH_OPEN;

ditto.

> +		info->irq_chg = false;
> +		break;
> +	case MAX77843_MUIC_GND_MHL_VB:
> +		extcon_set_cable_state(info->edev, "MHL-TA", attached);
> +		path = MAX77843_SWITCH_OPEN;

ditto.

> +		info->irq_chg = false;
> +		break;
> +	default:
> +		dev_err(info->dev, "Cannot detect %s cable of gnd type\n",
> +			attached ? "attached" : "detached");
> +		return -EINVAL;
> +	}
> +
> +	ret = max77843_muic_set_path(info, path, attached);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_jig_handler(struct max77843_muic_info *info,
> +		int cable_type, bool attached)
> +{
> +	char cable_name[32];

Remove 'cable_name' array

> +	u8 path = MAX77843_SWITCH_OPEN;
> +	int ret;
> +
> +	dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
> +			attached ? "attached" : "detached", cable_type);
> +
> +	switch (cable_type) {
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
> +		strcpy(cable_name, "JIG-USB-OFF");

You execute direclty extcon_set_cable_state() function instead of using strcpy.

> +		path = MAX77843_SWITCH_USB;
> +		break;
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
> +		strcpy(cable_name, "JIG-USB-ON");
> +		path = MAX77843_SWITCH_USB;
> +		break;
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
> +		strcpy(cable_name, "JIG-UART-OFF");
> +		path = MAX77843_SWITCH_UART;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	ret = max77843_muic_set_path(info, path, attached);
> +	if (ret < 0)
> +		return ret;
> +
> +	extcon_set_cable_state(info->edev, cable_name, attached);
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_adc_handler(struct max77843_muic_info *info)
> +{
> +	int ret, cable_type;
> +	bool attached;
> +
> +	cable_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_ADC, &attached);
> +
> +	dev_dbg(info->dev,
> +		"external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
> +		attached ? "attached" : "detached", cable_type,
> +		info->prev_cable_type);
> +
> +	switch (cable_type) {
> +	case MAX77843_MUIC_ADC_GROUND:
> +		ret = max77843_muic_adc_gnd_handler(info);
> +		if (ret < 0)
> +			return ret;
> +		break;
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
> +		ret = max77843_muic_jig_handler(info, cable_type, attached);
> +		if (ret < 0)
> +			return ret;
> +		break;
> +	case MAX77843_MUIC_ADC_SEND_END_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S1_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S2_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S3_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S4_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S5_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S6_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S7_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S8_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S9_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S10_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S11_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S12_BUTTON:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_1:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_2:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_3:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_4:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_5:
> +	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2:
> +	case MAX77843_MUIC_ADC_PHONE_POWERED_DEV:
> +	case MAX77843_MUIC_ADC_TTY_CONVERTER:
> +	case MAX77843_MUIC_ADC_UART_CABLE:
> +	case MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG:
> +	case MAX77843_MUIC_ADC_AV_CABLE_NOLOAD:
> +	case MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG:
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON:
> +	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1:
> +	case MAX77843_MUIC_ADC_OPEN:
> +		dev_err(info->dev,
> +			"accessory is %s but it isn't used (adc:0x%x)\n",
> +			attached ? "attached" : "detached", cable_type);
> +		return -EAGAIN;
> +	default:
> +		dev_err(info->dev,
> +			"failed to detect %s accessory (adc:0x%x)\n",
> +			attached ? "attached" : "detached", cable_type);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_chg_handler(struct max77843_muic_info *info)
> +{
> +	int ret, chg_type;
> +	bool attached;
> +	u8 path = MAX77843_SWITCH_OPEN;

ditto.

> +
> +	chg_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_CHG, &attached);
> +
> +	dev_dbg(info->dev,
> +		"external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
> +		attached ? "attached" : "detached",
> +		chg_type, info->prev_chg_type);
> +
> +	switch (chg_type) {
> +	case MAX77843_CHG_TYPE_USB:
> +		path = MAX77843_SWITCH_USB;
> +		extcon_set_cable_state(info->edev, "USB", attached);

ditto. you have to change the muic path before setting the cable state.

> +		break;
> +	case MAX77843_CHG_TYPE_DOWNSTREAM:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev,
> +				"CHARGER-DOWNSTREAM", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_DEDICATED:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev, "TA", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_SPECIAL_500MA:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev, "SLOW-CHAREGER", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_SPECIAL_1A:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev, "FAST-CHARGER", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_SPECIAL_BIAS:
> +		path = MAX77843_SWITCH_OPEN;
> +		break;
> +	case MAX77843_CHG_TYPE_NONE:
> +		return 0;
> +	default:
> +		dev_err(info->dev,
> +			"failed to detect %s accessory (chg_type:0x%x)\n",
> +			attached ? "attached" : "detached", chg_type);
> +		return -EINVAL;
> +	}
> +
> +	ret = max77843_muic_set_path(info, path, attached);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void max77843_muic_irq_work(struct work_struct *work)
> +{
> +	struct max77843_muic_info *info = container_of(work,
> +			struct max77843_muic_info, irq_work);
> +	struct max77843 *max77843 = info->max77843;
> +	int ret = 0;
> +
> +	if (!info->edev)
> +		return;
> +
> +	mutex_lock(&info->mutex);
> +
> +	ret = regmap_bulk_read(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_STATUS1, info->status,
> +			MAX77843_MUIC_STATUS_NUM);
> +	if (ret) {
> +		dev_err(info->dev, "Cannot read STATUS registers\n");
> +		mutex_unlock(&info->mutex);
> +		return;
> +	}
> +
> +	if (info->irq_adc) {
> +		ret = max77843_muic_adc_handler(info);
> +		if (ret)
> +			dev_err(info->dev, "Unknown cable type\n");
> +		info->irq_adc = false;
> +	}
> +
> +	if (info->irq_chg) {
> +		ret = max77843_muic_chg_handler(info);
> +		if (ret)
> +			dev_err(info->dev, "Unknown charger type\n");
> +		info->irq_chg = false;
> +	}
> +
> +	mutex_unlock(&info->mutex);
> +}
> +
> +static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
> +{
> +	struct max77843_muic_info *info = data;
> +	int i, irq_type = -1;
> +
> +	if (!info->init_done)
> +		return IRQ_HANDLED;
> +
> +	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++)
> +		if (irq == info->muic_irqs[i].virq)
> +			irq_type = info->muic_irqs[i].irq;
> +
> +	switch (irq_type) {
> +	case MAX77843_MUIC_IRQ_INT1_ADC:
> +	case MAX77843_MUIC_IRQ_INT1_ADCERROR:
> +	case MAX77843_MUIC_IRQ_INT1_ADC1K:
> +		info->irq_adc = true;
> +		break;
> +	case MAX77843_MUIC_IRQ_INT2_CHGTYP:
> +	case MAX77843_MUIC_IRQ_INT2_CHGDETRUN:
> +	case MAX77843_MUIC_IRQ_INT2_DCDTMR:
> +	case MAX77843_MUIC_IRQ_INT2_DXOVP:
> +	case MAX77843_MUIC_IRQ_INT2_VBVOLT:
> +		info->irq_chg = true;
> +		break;
> +	case MAX77843_MUIC_IRQ_INT3_VBADC:
> +	case MAX77843_MUIC_IRQ_INT3_VDNMON:
> +	case MAX77843_MUIC_IRQ_INT3_DNRES:
> +	case MAX77843_MUIC_IRQ_INT3_MPNACK:
> +	case MAX77843_MUIC_IRQ_INT3_MRXBUFOW:
> +	case MAX77843_MUIC_IRQ_INT3_MRXTRF:
> +	case MAX77843_MUIC_IRQ_INT3_MRXPERR:
> +	case MAX77843_MUIC_IRQ_INT3_MRXRDY:
> +		break;
> +	default:
> +		dev_err(info->dev, "Cannot recognize IRQ(%d)\n", irq_type);
> +		break;
> +	}
> +
> +	schedule_work(&info->irq_work);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void max77843_muic_detect_cable_wq(struct work_struct *work)
> +{
> +	struct max77843_muic_info *info = container_of(to_delayed_work(work),
> +			struct max77843_muic_info, wq_detcable);
> +	struct max77843 *max77843 = info->max77843;
> +	int chg_type, adc, ret;
> +	bool attached;
> +
> +	mutex_lock(&info->mutex);
> +
> +	ret = regmap_bulk_read(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_STATUS1, info->status,
> +			MAX77843_MUIC_STATUS_NUM);
> +	if (ret) {
> +		dev_err(info->dev, "Cannot read STATUS registers\n");
> +		goto err_cable_wq;
> +	}
> +
> +	adc = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_ADC, &attached);
> +	if (attached && adc != MAX77843_MUIC_ADC_OPEN) {
> +		ret = max77843_muic_adc_handler(info);
> +		if (ret < 0) {
> +			dev_err(info->dev, "Cannot detect accessory\n");
> +			goto err_cable_wq;
> +		}
> +	}
> +
> +	chg_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_CHG, &attached);
> +	if (attached && chg_type != MAX77843_CHG_TYPE_NONE) {
> +		ret = max77843_muic_chg_handler(info);
> +		if (ret < 0) {
> +			dev_err(info->dev, "Cannot detect charger accessory\n");
> +			goto err_cable_wq;
> +		}
> +	}
> +
> +err_cable_wq:
> +	mutex_unlock(&info->mutex);
> +}
> +
> +static int max77843_muic_set_debounce_time(struct max77843_muic_info *info,
> +		enum max77843_muic_adv_debounce_time time)
> +{
> +	struct max77843 *max77843 = info->max77843;
> +	unsigned int ret;
> +
> +	switch (time) {
> +	case MAX77843_DEBOUNCE_TIME_5MS:
> +	case MAX77843_DEBOUNCE_TIME_10MS:
> +	case MAX77843_DEBOUNCE_TIME_25MS:
> +	case MAX77843_DEBOUNCE_TIME_38_62MS:
> +		ret = regmap_update_bits(max77843->regmap_muic,
> +				MAX77843_MUIC_REG_CONTROL4,
> +				MAX77843_MUIC_CONTROL4_ADCDBSET_MASK,
> +				time << CONTROL4_ADCDBSET_SHIFT);
> +		if (ret) {

I prfer to use following condition statement to check return value
	if (ret) -> if (ret < 0)

> +			dev_err(info->dev, "Cannot write MUIC regmap\n");
> +			return ret;
> +		}
> +
> +		break;
> +	default:
> +		dev_err(info->dev, "Invalid ADC debounce time\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77843_init_muic_regmap(struct max77843 *max77843)
> +{
> +	int ret;
> +
> +	max77843->i2c_muic = i2c_new_dummy(max77843->i2c->adapter,
> +			I2C_ADDR_MUIC);
> +	if (!max77843->i2c_muic) {
> +		dev_err(&max77843->i2c->dev,
> +				"Cannot allocate I2C device for MUIC\n");
> +		return PTR_ERR(max77843->i2c_muic);
> +	}
> +
> +	i2c_set_clientdata(max77843->i2c_muic, max77843);
> +
> +	max77843->regmap_muic = devm_regmap_init_i2c(max77843->i2c_muic,
> +			&max77843_muic_regmap_config);
> +	if (IS_ERR(max77843->regmap_muic)) {
> +		ret = PTR_ERR(max77843->regmap_muic);
> +		goto err_muic_i2c;
> +	}
> +
> +	ret = regmap_add_irq_chip(max77843->regmap_muic, max77843->irq,
> +			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> +			0, &max77843_muic_irq_chip, &max77843->irq_data_muic);
> +	if (ret) {

ditto.
	if (ret < 0)

> +		dev_err(&max77843->i2c->dev, "Cannot add MUIC IRQ chip\n");
> +		goto err_muic_i2c;
> +	}
> +
> +	return 0;
> +
> +err_muic_i2c:
> +	i2c_unregister_device(max77843->i2c_muic);
> +
> +	return ret;
> +}
> +
> +static int max77843_muic_probe(struct platform_device *pdev)
> +{
> +	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
> +	struct max77843_muic_info *info;
> +	unsigned int id;
> +	int i, ret;
> +
> +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	info->dev = &pdev->dev;
> +	info->max77843 = max77843;
> +	info->muic_irqs = max77843_muic_irqs;
> +	info->init_done = false;
> +
> +	platform_set_drvdata(pdev, info);
> +	mutex_init(&info->mutex);
> +	INIT_WORK(&info->irq_work, max77843_muic_irq_work);
> +
> +	/* Initialize i2c and regmap */
> +	ret = max77843_init_muic_regmap(max77843);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to init MUIC regmap\n");
> +		return ret;
> +	}
> +
> +	/* Turn off auto detection configuration */
> +	ret = regmap_update_bits(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_CONTROL4,
> +			MAX77843_MUIC_CONTROL4_USBAUTO_MASK |
> +			MAX77843_MUIC_CONTROL4_FCTAUTO_MASK,
> +			MAX77843_MUIC_AUTO_NONE << CONTROL4_USBAUTO_SHIFT);
> +
> +	/* Support virtual irq domain for max77843 MUIC device */
> +	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
> +		struct max77843_muic_irq *muic_irq = &info->muic_irqs[i];
> +		unsigned int virq = 0;
> +
> +		virq = regmap_irq_get_virq(max77843->irq_data_muic,
> +				muic_irq->irq);
> +		if (virq <= 0) {
> +			ret = -EINVAL;
> +			goto err_muic_irq;
> +		}
> +		muic_irq->virq = virq;
> +
> +		ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
> +				max77843_muic_irq_handler, IRQF_NO_SUSPEND,
> +				muic_irq->name, info);
> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"Failed: irq request (IRQ: %d, error: %d)\n",
> +				muic_irq->irq, ret);
> +			goto err_muic_irq;
> +		}
> +	}
> +
> +	/* Initialize extcon device */
> +	info->edev = devm_extcon_dev_allocate(&pdev->dev,
> +			max77843_extcon_cable);
> +	if (IS_ERR(info->edev)) {
> +		dev_err(&pdev->dev, "Failed to allocate memory for extcon\n");
> +		ret = -ENODEV;
> +		goto err_muic_irq;
> +	}
> +
> +	info->edev->name = dev_name(&pdev->dev);

Don't need it. extcon_dev_register() set the name of extcon device.

> +
> +	ret = devm_extcon_dev_register(&pdev->dev, info->edev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to register extcon device\n");
> +		goto err_muic_irq;
> +	}
> +
> +	/* Set ADC debounce time */
> +	max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS);
> +
> +	/* Set initial path for UART */
> +	max77843_muic_set_path(info, MAX77843_SWITCH_UART, true);
> +
> +	/* Detect accessory after completing the initialization of platform */
> +	INIT_DELAYED_WORK(&info->wq_detcable, max77843_muic_detect_cable_wq);
> +	queue_delayed_work(system_power_efficient_wq,
> +			&info->wq_detcable, msecs_to_jiffies(DELAY_MS_DEFAULT));
> +
> +	/* Check revision number of MUIC device */
> +	ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Failed to read revision number\n");
> +		return ret;
> +	}
> +	dev_info(info->dev, "MUIC device ID : 0x%x\n", id);
> +
> +	info->init_done = true;
> +
> +	return 0;
> +
> +err_muic_irq:
> +	regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
> +
> +	return ret;
> +}
> +
> +static int max77843_muic_remove(struct platform_device *pdev)
> +{
> +	struct max77843_muic_info *info = platform_get_drvdata(pdev);
> +
> +	cancel_work_sync(&info->irq_work);
> +
> +	return 0;
> +}
> +
> +static const struct platform_device_id max77843_muic_id[] = {
> +	{ "max77843-muic", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(platform, max77843_muic_id);
> +
> +static struct platform_driver max77843_muic_driver = {
> +	.driver		= {
> +		.name		= "max77843-muic",
> +	},
> +	.probe		= max77843_muic_probe,
> +	.remove		= max77843_muic_remove,
> +	.id_table	= max77843_muic_id,
> +};
> +
> +static int __init max77843_muic_init(void)
> +{
> +	return platform_driver_register(&max77843_muic_driver);
> +}
> +subsys_initcall(max77843_muic_init);
> +
> +MODULE_DESCRIPTION("Maxim MAX77843 Extcon driver");
> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
> +MODULE_LICENSE("GPL");
> 

Thanks,
Chanwoo Choi


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

* Re: [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver
@ 2015-01-23  6:21     ` Chanwoo Choi
  0 siblings, 0 replies; 41+ messages in thread
From: Chanwoo Choi @ 2015-01-23  6:21 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown, Beomho Seo

Hi Jaewon,

On 01/23/2015 02:02 PM, Jaewon Kim wrote:
> This patch adds MAX77843 extcon driver to support for MUIC(Micro

Add company name (MAX77843 -> Maxim MAX77843)

> USB Interface Controller) device by using EXTCON subsystem to handle
> various external connectors.
> 
> Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/extcon/Kconfig           |   10 +
>  drivers/extcon/Makefile          |    1 +
>  drivers/extcon/extcon-max77843.c |  871 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 882 insertions(+)
>  create mode 100644 drivers/extcon/extcon-max77843.c
> 
> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
> index 6a1f7de..0b67538 100644
> --- a/drivers/extcon/Kconfig
> +++ b/drivers/extcon/Kconfig
> @@ -55,6 +55,16 @@ config EXTCON_MAX77693
>  	  Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory
>  	  detector and switch.
>  
> +config EXTCON_MAX77843
> +	tristate "MAX77843 EXTCON Support"
> +	depends on MFD_MAX77843
> +	select IRQ_DOMAIN
> +	select REGMAP_I2C
> +	help
> +	  If you say yes here you get support for the MUIC device of
> +	  Maxim MAX77843. The MAX77843 MUIC is a USB port accessory
> +	  detector add switch.
> +
>  config EXTCON_MAX8997
>  	tristate "MAX8997 EXTCON Support"
>  	depends on MFD_MAX8997 && IRQ_DOMAIN
> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
> index 0370b42..f21d5c4 100644
> --- a/drivers/extcon/Makefile
> +++ b/drivers/extcon/Makefile
> @@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
>  obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
>  obj-$(CONFIG_EXTCON_MAX14577)	+= extcon-max14577.o
>  obj-$(CONFIG_EXTCON_MAX77693)	+= extcon-max77693.o
> +obj-$(CONFIG_EXTCON_MAX77843)	+= extcon-max77843.o
>  obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>  obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>  obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
> diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
> new file mode 100644
> index 0000000..caae9a7
> --- /dev/null
> +++ b/drivers/extcon/extcon-max77843.c
> @@ -0,0 +1,871 @@
> +/*
> + * extcon-max77843.c - MAX77843 extcon driver to support MUIC
> + *
> + * Copyright (C) 2014 Samsung Electrnoics
> + *  Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

Remove un-necessary blank before 'Author'.

> + *
> + * 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/extcon.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/max77843-private.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/workqueue.h>
> +
> +#define DELAY_MS_DEFAULT		15000	/* unit: millisecond */
> +
> +enum max77843_muic_acc_type {
> +	MAX77843_MUIC_ADC_GROUND = 0,
> +	MAX77843_MUIC_ADC_SEND_END_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S1_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S2_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S3_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S4_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S5_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S6_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S7_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S8_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S9_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S10_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S11_BUTTON,
> +	MAX77843_MUIC_ADC_REMOTE_S12_BUTTON,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_1,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_2,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_3,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_4,
> +	MAX77843_MUIC_ADC_RESERVED_ACC_5,
> +	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2,
> +	MAX77843_MUIC_ADC_PHONE_POWERED_DEV,
> +	MAX77843_MUIC_ADC_TTY_CONVERTER,
> +	MAX77843_MUIC_ADC_UART_CABLE,
> +	MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON,
> +	MAX77843_MUIC_ADC_AV_CABLE_NOLOAD,
> +	MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF,
> +	MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON,
> +	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
> +	MAX77843_MUIC_ADC_OPEN,
> +};
> +
> +enum max77843_muic_cable_group {
> +	MAX77843_CABLE_GROUP_ADC = 0,
> +	MAX77843_CABLE_GROUP_CHG,
> +	MAX77843_CABLE_GROUP_GND,
> +};

Cable group show the category of supported cables.
I think you better move this enum on upper of 'enum max77843_muic_acc_type'

> +
> +enum max77843_muic_adv_debounce_time {
> +	MAX77843_DEBOUNCE_TIME_5MS = 0,
> +	MAX77843_DEBOUNCE_TIME_10MS,
> +	MAX77843_DEBOUNCE_TIME_25MS,
> +	MAX77843_DEBOUNCE_TIME_38_62MS,
> +};
> +
> +enum max77843_muic_support_list {

Use only 'enum' keyword without 'max77843_muic_support_list' enum name.

> +	EXTCON_CABLE_USB = 0,
> +	EXTCON_CABLE_USB_HOST,
> +	EXTCON_CABLE_USB_HOST_TA,
> +	EXTCON_CABLE_TA,
> +	EXTCON_CABLE_FAST_CHARGER,
> +	EXTCON_CABLE_SLOW_CHARGER,
> +	EXTCON_CABLE_CHARGE_DOWNSTREAM,
> +	EXTCON_CABLE_MHL,
> +	EXTCON_CABLE_MHL_TA,
> +	EXTCON_CABLE_JIG_USB_ON,
> +	EXTCON_CABLE_JIG_USB_OFF,
> +	EXTCON_CABLE_JIG_UART_OFF,
> +	EXTCON_CABLE_JIG_UART_ON,
> +
> +	EXTCON_CABLE_NUM,
> +};
> +
> +enum max77843_muic_gnd_cable {
> +	MAX77843_MUIC_GND_USB_OTG	= 0x0,
> +	MAX77843_MUIC_GND_USB_OTG_VB	= 0x1,
> +	MAX77843_MUIC_GND_MHL		= 0x2,
> +	MAX77843_MUIC_GND_MHL_VB	= 0x3,

Why do you need 'max77843_muic_gnd_cable' enum?
You have to express supported all cables in 'max77843_muic_acc_type' enum list.
If you define one more cables enumeration, It is possible to incur the confusion
of what this driver is supported cable.


> +
> +	MAX77843_MUIC_GND_NUM,
> +};
> +
> +enum max77843_muic_status {
> +	MAX77843_MUIC_STATUS1 = 0,
> +	MAX77843_MUIC_STATUS2,
> +	MAX77843_MUIC_STATUS3,
> +
> +	MAX77843_MUIC_STATUS_NUM,
> +};
> +
> +enum max77843_muic_charger_type {
> +	MAX77843_CHG_TYPE_NONE = 0,
> +	MAX77843_CHG_TYPE_USB,
> +	MAX77843_CHG_TYPE_DOWNSTREAM,
> +	MAX77843_CHG_TYPE_DEDICATED,
> +	MAX77843_CHG_TYPE_SPECIAL_500MA,
> +	MAX77843_CHG_TYPE_SPECIAL_1A,
> +	MAX77843_CHG_TYPE_SPECIAL_BIAS,
> +
> +	MAX77843_CHG_TYPE_END,
> +};
> +
> +enum max77843_muic_detection {
> +	MAX77843_MUIC_AUTO_NONE = 0,
> +	MAX77843_MUIC_AUTO_USB,
> +	MAX77843_MUIC_AUTO_FAC,
> +	MAX77843_MUIC_AUTO_USB_FAC,
> +};

It it wrong. This enum is used to write the value to MUIC register.
You have to define it in max77843-private.h with 'enum' keyword.
I think you could refer other definition in max77843-private.h.

You have to re-order the definition by using follwoing sequence
to improbe readability.
1. cable group
2. supported cables
3. other definition with enum

Also,
I'm difficult to understand the meaning of enum definition.
MAX77843_MUIC_*
MAX77843_CABLE_*
MAX77843_DEBOUNCE_*
MAX77843_CHG_*

I think you need to clarify the meaning of enum definition
by makingt the name pattern to improve readability.

> +
> +struct max77843_muic_info {
> +	struct device *dev;
> +	struct max77843 *max77843;
> +	struct extcon_dev *edev;
> +
> +	struct mutex mutex;
> +	struct work_struct irq_work;
> +	struct delayed_work wq_detcable;
> +	struct max77843_muic_irq *muic_irqs;
> +
> +	u8 status[MAX77843_MUIC_STATUS_NUM];
> +	int prev_cable_type;
> +	int prev_chg_type;
> +	int prev_gnd_type;
> +
> +	bool irq_adc;
> +	bool irq_chg;
> +	bool init_done;

I don't want to use the 'init_don' field. I think it is legacy way
to solve some issue. I recommend you use other way.

> +};
> +
> +struct max77843_muic_irq {
> +	unsigned int irq;
> +	const char *name;
> +	unsigned int virq;
> +};
> +
> +static const struct regmap_config max77843_muic_regmap_config = {
> +	.reg_bits       = 8,
> +	.val_bits       = 8,
> +	.max_register   = MAX77843_MUIC_REG_END,
> +};
> +
> +static const struct regmap_irq max77843_muic_irq[] = {
> +	/* MUIC:INT1 interrupts */
	
Don' need 'MUIC:' prefix and fix string (s/interrupts/interrupt).

> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC, },
> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADCERROR, },
> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC1K, },
> +
> +	/* MUIC:INT2 interrupts */

ditto.

> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGTYP, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGDETRUN, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_DCDTMR, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_DXOVP, },
> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_VBVOLT, },
> +
> +	/* MUIC:INT3 interrupts */

ditto.

> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_VBADC, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_VDNMON, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_DNRES, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MPNACK, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXBUFOW, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXTRF, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXPERR, },
> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXRDY, },
> +};
> +
> +static const struct regmap_irq_chip max77843_muic_irq_chip = {
> +	.name           = "max77843-muic",
> +	.status_base    = MAX77843_MUIC_REG_INT1,
> +	.mask_base      = MAX77843_MUIC_REG_INTMASK1,
> +	.mask_invert    = true,
> +	.num_regs       = 3,
> +	.irqs           = max77843_muic_irq,
> +	.num_irqs       = ARRAY_SIZE(max77843_muic_irq),
> +};
> +
> +static const char *max77843_extcon_cable[] = {
> +	[EXTCON_CABLE_USB]			= "USB",
> +	[EXTCON_CABLE_USB_HOST]			= "USB-HOST",
> +	[EXTCON_CABLE_USB_HOST_TA]		= "USB-HOST-TA",
> +	[EXTCON_CABLE_TA]			= "TA",
> +	[EXTCON_CABLE_FAST_CHARGER]		= "FAST-CHARGER",
> +	[EXTCON_CABLE_SLOW_CHARGER]		= "SLOW-CHARGER",
> +	[EXTCON_CABLE_CHARGE_DOWNSTREAM]	= "CHARGER-DOWNSTREAM",
> +	[EXTCON_CABLE_MHL]			= "MHL",
> +	[EXTCON_CABLE_MHL_TA]			= "MHL-TA",
> +	[EXTCON_CABLE_JIG_USB_ON]		= "JIG-USB-ON",
> +	[EXTCON_CABLE_JIG_USB_OFF]		= "JIG-USB-OFF",
> +	[EXTCON_CABLE_JIG_UART_OFF]		= "JIG-UART-OFF",
> +	[EXTCON_CABLE_JIG_UART_ON]		= "JIG-UART-ON",
> +};
> +
> +static struct max77843_muic_irq max77843_muic_irqs[] = {
> +	{ MAX77843_MUIC_IRQ_INT1_ADC,		"MUIC-ADC" },
> +	{ MAX77843_MUIC_IRQ_INT1_ADCERROR,	"MUIC-ADC_ERROR" },
> +	{ MAX77843_MUIC_IRQ_INT1_ADC1K,		"MUIC-ADC1K" },
> +	{ MAX77843_MUIC_IRQ_INT2_CHGTYP,	"MUIC-CHGTYP" },
> +	{ MAX77843_MUIC_IRQ_INT2_CHGDETRUN,	"MUIC-CHGDETRUN" },
> +	{ MAX77843_MUIC_IRQ_INT2_DCDTMR,	"MUIC-DCDTMR" },
> +	{ MAX77843_MUIC_IRQ_INT2_DXOVP,		"MUIC-DXOVP" },
> +	{ MAX77843_MUIC_IRQ_INT2_VBVOLT,	"MUIC-VBVOLT" },
> +	{ MAX77843_MUIC_IRQ_INT3_VBADC,		"MUIC-VBADC" },
> +	{ MAX77843_MUIC_IRQ_INT3_VDNMON,	"MUIC-VDNMON" },
> +	{ MAX77843_MUIC_IRQ_INT3_DNRES,		"MUIC-DNRES" },
> +	{ MAX77843_MUIC_IRQ_INT3_MPNACK,	"MUIC-MPNACK"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXBUFOW,	"MUIC-MRXBUFOW"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXTRF,	"MUIC-MRXTRF"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXPERR,	"MUIC-MRXPERR"},
> +	{ MAX77843_MUIC_IRQ_INT3_MRXRDY,	"MUIC-MRXRDY"},
> +};
> +
> +static int max77843_muic_set_path(struct max77843_muic_info *info,
> +		u8 val, bool attached)
> +{
> +	struct max77843 *max77843 = info->max77843;
> +	int ret = 0;
> +	unsigned int ctrl1, ctrl2;
> +
> +	if (attached)
> +		ctrl1 = val;
> +	else
> +		ctrl1 = MAX77843_SWITCH_OPEN;

'SWITCH' keyword is right?
I can't the 'SWITCH' word in CONTROL1 register of MAX77843 MUIC datasheet.
When you define the field for register, I prefer to use the word which
expressed in register map of datasheet.

> +
> +	ret = regmap_update_bits(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_CONTROL1,
> +			MAX77843_SIWTH_PORT, ctrl1);
> +	if (ret < 0) {
> +		dev_err(info->dev, "Cannot switch MUIC port\n");
> +		return ret;
> +	}
> +
> +	if (attached)
> +		ctrl2 = MAX77843_MUIC_CONTROL2_CPEN_MASK;
> +	else
> +		ctrl2 = MAX77843_MUIC_CONTROL2_LOWPWR_MASK;
> +
> +	ret = regmap_update_bits(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_CONTROL2,
> +			MAX77843_MUIC_CONTROL2_LOWPWR_MASK |
> +			MAX77843_MUIC_CONTROL2_CPEN_MASK, ctrl2);
> +	if (ret < 0) {
> +		dev_err(info->dev, "Cannot update lowpower mode\n");
> +		return ret;
> +	}
> +
> +	dev_dbg(info->dev,
> +		"CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
> +		ctrl1, ctrl2, attached ? "attached" : "detached");
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
> +		enum max77843_muic_cable_group group, bool *attached)
> +{
> +	int adc, chg_type, cable_type, gnd_type;
> +
> +	adc = info->status[MAX77843_MUIC_STATUS1] &
> +			MAX77843_MUIC_STATUS1_ADC_MASK;

If you use the short definition for 'MAX77843_MUIC_STATUS1',
you could make this code on one line.

> +	adc >>= STATUS1_ADC_SHIFT;
> +
> +	switch (group) {
> +	case MAX77843_CABLE_GROUP_ADC:
> +		if (adc == MAX77843_MUIC_ADC_OPEN) {
> +			*attached = false;
> +			cable_type = info->prev_cable_type;
> +			info->prev_cable_type = MAX77843_MUIC_ADC_OPEN;
> +		} else {
> +			*attached = true;
> +			cable_type = info->prev_cable_type = adc;
> +		}
> +
> +		break;
> +	case MAX77843_CABLE_GROUP_CHG:
> +		if (adc == MAX77843_MUIC_ADC_GROUND) {
> +			*attached = true;
> +			cable_type = adc;
> +			break;
> +		}
> +
> +		chg_type = info->status[MAX77843_MUIC_STATUS2] &
> +			MAX77843_MUIC_STATUS2_CHGTYP_MASK;

ditto and I think you need one more indentation for readabiltiy.


> +		chg_type >>= STATUS2_CHGTYP_SHIFT;
> +

Remove unneeded blank line.

> +		if (chg_type == MAX77843_CHG_TYPE_NONE) {
> +			*attached = false;
> +			cable_type = info->prev_chg_type;
> +			info->prev_chg_type = MAX77843_CHG_TYPE_NONE;
> +		} else {
> +			*attached = true;
> +			cable_type = info->prev_chg_type = chg_type;
> +		}
> +
> +		break;
> +	case MAX77843_CABLE_GROUP_GND:
> +		adc = info->status[MAX77843_MUIC_STATUS1] &
> +			MAX77843_MUIC_STATUS1_ADC_MASK;

ditto.

> +		adc >>= STATUS1_ADC_SHIFT;
> +
> +		if (adc == MAX77843_MUIC_ADC_GROUND) {
> +			*attached = true;
> +			gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
> +					MAX77843_MUIC_STATUS1_ADC1K_MASK) >>
> +					(STATUS1_ADC1K_SHIFT-1);
> +			gnd_type |= (info->status[MAX77843_MUIC_STATUS2] &
> +					MAX77843_MUIC_STATUS2_VBVOLT_MASK) >>
> +					STATUS2_VBVOLT_SHIFT;
> +			cable_type = info->prev_gnd_type = gnd_type;
> +		} else {
> +			*attached = false;
> +			cable_type = info->prev_gnd_type;
> +			info->prev_gnd_type = MAX77843_MUIC_GND_NUM;
> +		}
> +
> +		break;
> +	default:
> +		dev_err(info->dev, "Unknown cable group (%d)\n", group);
> +		cable_type = -EINVAL;
> +
> +		break;
> +	}
> +
> +	return cable_type;
> +}
> +
> +static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
> +{
> +	int ret, gnd_cable_type;
> +	u8 path;
> +	bool attached;
> +
> +	gnd_cable_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_GND, &attached);
> +	dev_dbg(info->dev, "external connector is %s (gnd:0x%02x)\n",
> +			attached ? "attached" : "detached", gnd_cable_type);
> +
> +	switch (gnd_cable_type) {
> +	case MAX77843_MUIC_GND_USB_OTG:
> +		extcon_set_cable_state(info->edev, "USB-HOST", attached);
> +		path = MAX77843_SWITCH_USB;

Change the name insted of 'SWITCH' word.

Also, I think you have to change the path before sending uevent about cable information.
If you set cable state before setting the path, user-process might get the uevent
before changing the MUIC path. You have to modify it when cable state is changed.

> +		info->irq_chg = false;
> +		break;
> +	case MAX77843_MUIC_GND_USB_OTG_VB:
> +		extcon_set_cable_state(info->edev, "USB-HOST-TA", attached);
> +		path = MAX77843_SWITCH_USB;

ditto.

> +		info->irq_chg = false;
> +		break;
> +	case MAX77843_MUIC_GND_MHL:
> +		extcon_set_cable_state(info->edev, "MHL", attached);
> +		path = MAX77843_SWITCH_OPEN;

ditto.

> +		info->irq_chg = false;
> +		break;
> +	case MAX77843_MUIC_GND_MHL_VB:
> +		extcon_set_cable_state(info->edev, "MHL-TA", attached);
> +		path = MAX77843_SWITCH_OPEN;

ditto.

> +		info->irq_chg = false;
> +		break;
> +	default:
> +		dev_err(info->dev, "Cannot detect %s cable of gnd type\n",
> +			attached ? "attached" : "detached");
> +		return -EINVAL;
> +	}
> +
> +	ret = max77843_muic_set_path(info, path, attached);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_jig_handler(struct max77843_muic_info *info,
> +		int cable_type, bool attached)
> +{
> +	char cable_name[32];

Remove 'cable_name' array

> +	u8 path = MAX77843_SWITCH_OPEN;
> +	int ret;
> +
> +	dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
> +			attached ? "attached" : "detached", cable_type);
> +
> +	switch (cable_type) {
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
> +		strcpy(cable_name, "JIG-USB-OFF");

You execute direclty extcon_set_cable_state() function instead of using strcpy.

> +		path = MAX77843_SWITCH_USB;
> +		break;
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
> +		strcpy(cable_name, "JIG-USB-ON");
> +		path = MAX77843_SWITCH_USB;
> +		break;
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
> +		strcpy(cable_name, "JIG-UART-OFF");
> +		path = MAX77843_SWITCH_UART;
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	ret = max77843_muic_set_path(info, path, attached);
> +	if (ret < 0)
> +		return ret;
> +
> +	extcon_set_cable_state(info->edev, cable_name, attached);
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_adc_handler(struct max77843_muic_info *info)
> +{
> +	int ret, cable_type;
> +	bool attached;
> +
> +	cable_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_ADC, &attached);
> +
> +	dev_dbg(info->dev,
> +		"external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
> +		attached ? "attached" : "detached", cable_type,
> +		info->prev_cable_type);
> +
> +	switch (cable_type) {
> +	case MAX77843_MUIC_ADC_GROUND:
> +		ret = max77843_muic_adc_gnd_handler(info);
> +		if (ret < 0)
> +			return ret;
> +		break;
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
> +		ret = max77843_muic_jig_handler(info, cable_type, attached);
> +		if (ret < 0)
> +			return ret;
> +		break;
> +	case MAX77843_MUIC_ADC_SEND_END_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S1_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S2_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S3_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S4_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S5_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S6_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S7_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S8_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S9_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S10_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S11_BUTTON:
> +	case MAX77843_MUIC_ADC_REMOTE_S12_BUTTON:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_1:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_2:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_3:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_4:
> +	case MAX77843_MUIC_ADC_RESERVED_ACC_5:
> +	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2:
> +	case MAX77843_MUIC_ADC_PHONE_POWERED_DEV:
> +	case MAX77843_MUIC_ADC_TTY_CONVERTER:
> +	case MAX77843_MUIC_ADC_UART_CABLE:
> +	case MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG:
> +	case MAX77843_MUIC_ADC_AV_CABLE_NOLOAD:
> +	case MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG:
> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON:
> +	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1:
> +	case MAX77843_MUIC_ADC_OPEN:
> +		dev_err(info->dev,
> +			"accessory is %s but it isn't used (adc:0x%x)\n",
> +			attached ? "attached" : "detached", cable_type);
> +		return -EAGAIN;
> +	default:
> +		dev_err(info->dev,
> +			"failed to detect %s accessory (adc:0x%x)\n",
> +			attached ? "attached" : "detached", cable_type);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77843_muic_chg_handler(struct max77843_muic_info *info)
> +{
> +	int ret, chg_type;
> +	bool attached;
> +	u8 path = MAX77843_SWITCH_OPEN;

ditto.

> +
> +	chg_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_CHG, &attached);
> +
> +	dev_dbg(info->dev,
> +		"external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
> +		attached ? "attached" : "detached",
> +		chg_type, info->prev_chg_type);
> +
> +	switch (chg_type) {
> +	case MAX77843_CHG_TYPE_USB:
> +		path = MAX77843_SWITCH_USB;
> +		extcon_set_cable_state(info->edev, "USB", attached);

ditto. you have to change the muic path before setting the cable state.

> +		break;
> +	case MAX77843_CHG_TYPE_DOWNSTREAM:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev,
> +				"CHARGER-DOWNSTREAM", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_DEDICATED:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev, "TA", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_SPECIAL_500MA:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev, "SLOW-CHAREGER", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_SPECIAL_1A:
> +		path = MAX77843_SWITCH_OPEN;
> +		extcon_set_cable_state(info->edev, "FAST-CHARGER", attached);
> +		break;
> +	case MAX77843_CHG_TYPE_SPECIAL_BIAS:
> +		path = MAX77843_SWITCH_OPEN;
> +		break;
> +	case MAX77843_CHG_TYPE_NONE:
> +		return 0;
> +	default:
> +		dev_err(info->dev,
> +			"failed to detect %s accessory (chg_type:0x%x)\n",
> +			attached ? "attached" : "detached", chg_type);
> +		return -EINVAL;
> +	}
> +
> +	ret = max77843_muic_set_path(info, path, attached);
> +	if (ret < 0)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static void max77843_muic_irq_work(struct work_struct *work)
> +{
> +	struct max77843_muic_info *info = container_of(work,
> +			struct max77843_muic_info, irq_work);
> +	struct max77843 *max77843 = info->max77843;
> +	int ret = 0;
> +
> +	if (!info->edev)
> +		return;
> +
> +	mutex_lock(&info->mutex);
> +
> +	ret = regmap_bulk_read(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_STATUS1, info->status,
> +			MAX77843_MUIC_STATUS_NUM);
> +	if (ret) {
> +		dev_err(info->dev, "Cannot read STATUS registers\n");
> +		mutex_unlock(&info->mutex);
> +		return;
> +	}
> +
> +	if (info->irq_adc) {
> +		ret = max77843_muic_adc_handler(info);
> +		if (ret)
> +			dev_err(info->dev, "Unknown cable type\n");
> +		info->irq_adc = false;
> +	}
> +
> +	if (info->irq_chg) {
> +		ret = max77843_muic_chg_handler(info);
> +		if (ret)
> +			dev_err(info->dev, "Unknown charger type\n");
> +		info->irq_chg = false;
> +	}
> +
> +	mutex_unlock(&info->mutex);
> +}
> +
> +static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
> +{
> +	struct max77843_muic_info *info = data;
> +	int i, irq_type = -1;
> +
> +	if (!info->init_done)
> +		return IRQ_HANDLED;
> +
> +	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++)
> +		if (irq == info->muic_irqs[i].virq)
> +			irq_type = info->muic_irqs[i].irq;
> +
> +	switch (irq_type) {
> +	case MAX77843_MUIC_IRQ_INT1_ADC:
> +	case MAX77843_MUIC_IRQ_INT1_ADCERROR:
> +	case MAX77843_MUIC_IRQ_INT1_ADC1K:
> +		info->irq_adc = true;
> +		break;
> +	case MAX77843_MUIC_IRQ_INT2_CHGTYP:
> +	case MAX77843_MUIC_IRQ_INT2_CHGDETRUN:
> +	case MAX77843_MUIC_IRQ_INT2_DCDTMR:
> +	case MAX77843_MUIC_IRQ_INT2_DXOVP:
> +	case MAX77843_MUIC_IRQ_INT2_VBVOLT:
> +		info->irq_chg = true;
> +		break;
> +	case MAX77843_MUIC_IRQ_INT3_VBADC:
> +	case MAX77843_MUIC_IRQ_INT3_VDNMON:
> +	case MAX77843_MUIC_IRQ_INT3_DNRES:
> +	case MAX77843_MUIC_IRQ_INT3_MPNACK:
> +	case MAX77843_MUIC_IRQ_INT3_MRXBUFOW:
> +	case MAX77843_MUIC_IRQ_INT3_MRXTRF:
> +	case MAX77843_MUIC_IRQ_INT3_MRXPERR:
> +	case MAX77843_MUIC_IRQ_INT3_MRXRDY:
> +		break;
> +	default:
> +		dev_err(info->dev, "Cannot recognize IRQ(%d)\n", irq_type);
> +		break;
> +	}
> +
> +	schedule_work(&info->irq_work);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static void max77843_muic_detect_cable_wq(struct work_struct *work)
> +{
> +	struct max77843_muic_info *info = container_of(to_delayed_work(work),
> +			struct max77843_muic_info, wq_detcable);
> +	struct max77843 *max77843 = info->max77843;
> +	int chg_type, adc, ret;
> +	bool attached;
> +
> +	mutex_lock(&info->mutex);
> +
> +	ret = regmap_bulk_read(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_STATUS1, info->status,
> +			MAX77843_MUIC_STATUS_NUM);
> +	if (ret) {
> +		dev_err(info->dev, "Cannot read STATUS registers\n");
> +		goto err_cable_wq;
> +	}
> +
> +	adc = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_ADC, &attached);
> +	if (attached && adc != MAX77843_MUIC_ADC_OPEN) {
> +		ret = max77843_muic_adc_handler(info);
> +		if (ret < 0) {
> +			dev_err(info->dev, "Cannot detect accessory\n");
> +			goto err_cable_wq;
> +		}
> +	}
> +
> +	chg_type = max77843_muic_get_cable_type(info,
> +			MAX77843_CABLE_GROUP_CHG, &attached);
> +	if (attached && chg_type != MAX77843_CHG_TYPE_NONE) {
> +		ret = max77843_muic_chg_handler(info);
> +		if (ret < 0) {
> +			dev_err(info->dev, "Cannot detect charger accessory\n");
> +			goto err_cable_wq;
> +		}
> +	}
> +
> +err_cable_wq:
> +	mutex_unlock(&info->mutex);
> +}
> +
> +static int max77843_muic_set_debounce_time(struct max77843_muic_info *info,
> +		enum max77843_muic_adv_debounce_time time)
> +{
> +	struct max77843 *max77843 = info->max77843;
> +	unsigned int ret;
> +
> +	switch (time) {
> +	case MAX77843_DEBOUNCE_TIME_5MS:
> +	case MAX77843_DEBOUNCE_TIME_10MS:
> +	case MAX77843_DEBOUNCE_TIME_25MS:
> +	case MAX77843_DEBOUNCE_TIME_38_62MS:
> +		ret = regmap_update_bits(max77843->regmap_muic,
> +				MAX77843_MUIC_REG_CONTROL4,
> +				MAX77843_MUIC_CONTROL4_ADCDBSET_MASK,
> +				time << CONTROL4_ADCDBSET_SHIFT);
> +		if (ret) {

I prfer to use following condition statement to check return value
	if (ret) -> if (ret < 0)

> +			dev_err(info->dev, "Cannot write MUIC regmap\n");
> +			return ret;
> +		}
> +
> +		break;
> +	default:
> +		dev_err(info->dev, "Invalid ADC debounce time\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int max77843_init_muic_regmap(struct max77843 *max77843)
> +{
> +	int ret;
> +
> +	max77843->i2c_muic = i2c_new_dummy(max77843->i2c->adapter,
> +			I2C_ADDR_MUIC);
> +	if (!max77843->i2c_muic) {
> +		dev_err(&max77843->i2c->dev,
> +				"Cannot allocate I2C device for MUIC\n");
> +		return PTR_ERR(max77843->i2c_muic);
> +	}
> +
> +	i2c_set_clientdata(max77843->i2c_muic, max77843);
> +
> +	max77843->regmap_muic = devm_regmap_init_i2c(max77843->i2c_muic,
> +			&max77843_muic_regmap_config);
> +	if (IS_ERR(max77843->regmap_muic)) {
> +		ret = PTR_ERR(max77843->regmap_muic);
> +		goto err_muic_i2c;
> +	}
> +
> +	ret = regmap_add_irq_chip(max77843->regmap_muic, max77843->irq,
> +			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> +			0, &max77843_muic_irq_chip, &max77843->irq_data_muic);
> +	if (ret) {

ditto.
	if (ret < 0)

> +		dev_err(&max77843->i2c->dev, "Cannot add MUIC IRQ chip\n");
> +		goto err_muic_i2c;
> +	}
> +
> +	return 0;
> +
> +err_muic_i2c:
> +	i2c_unregister_device(max77843->i2c_muic);
> +
> +	return ret;
> +}
> +
> +static int max77843_muic_probe(struct platform_device *pdev)
> +{
> +	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
> +	struct max77843_muic_info *info;
> +	unsigned int id;
> +	int i, ret;
> +
> +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
> +	if (!info)
> +		return -ENOMEM;
> +
> +	info->dev = &pdev->dev;
> +	info->max77843 = max77843;
> +	info->muic_irqs = max77843_muic_irqs;
> +	info->init_done = false;
> +
> +	platform_set_drvdata(pdev, info);
> +	mutex_init(&info->mutex);
> +	INIT_WORK(&info->irq_work, max77843_muic_irq_work);
> +
> +	/* Initialize i2c and regmap */
> +	ret = max77843_init_muic_regmap(max77843);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to init MUIC regmap\n");
> +		return ret;
> +	}
> +
> +	/* Turn off auto detection configuration */
> +	ret = regmap_update_bits(max77843->regmap_muic,
> +			MAX77843_MUIC_REG_CONTROL4,
> +			MAX77843_MUIC_CONTROL4_USBAUTO_MASK |
> +			MAX77843_MUIC_CONTROL4_FCTAUTO_MASK,
> +			MAX77843_MUIC_AUTO_NONE << CONTROL4_USBAUTO_SHIFT);
> +
> +	/* Support virtual irq domain for max77843 MUIC device */
> +	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
> +		struct max77843_muic_irq *muic_irq = &info->muic_irqs[i];
> +		unsigned int virq = 0;
> +
> +		virq = regmap_irq_get_virq(max77843->irq_data_muic,
> +				muic_irq->irq);
> +		if (virq <= 0) {
> +			ret = -EINVAL;
> +			goto err_muic_irq;
> +		}
> +		muic_irq->virq = virq;
> +
> +		ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
> +				max77843_muic_irq_handler, IRQF_NO_SUSPEND,
> +				muic_irq->name, info);
> +		if (ret) {
> +			dev_err(&pdev->dev,
> +				"Failed: irq request (IRQ: %d, error: %d)\n",
> +				muic_irq->irq, ret);
> +			goto err_muic_irq;
> +		}
> +	}
> +
> +	/* Initialize extcon device */
> +	info->edev = devm_extcon_dev_allocate(&pdev->dev,
> +			max77843_extcon_cable);
> +	if (IS_ERR(info->edev)) {
> +		dev_err(&pdev->dev, "Failed to allocate memory for extcon\n");
> +		ret = -ENODEV;
> +		goto err_muic_irq;
> +	}
> +
> +	info->edev->name = dev_name(&pdev->dev);

Don't need it. extcon_dev_register() set the name of extcon device.

> +
> +	ret = devm_extcon_dev_register(&pdev->dev, info->edev);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed to register extcon device\n");
> +		goto err_muic_irq;
> +	}
> +
> +	/* Set ADC debounce time */
> +	max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS);
> +
> +	/* Set initial path for UART */
> +	max77843_muic_set_path(info, MAX77843_SWITCH_UART, true);
> +
> +	/* Detect accessory after completing the initialization of platform */
> +	INIT_DELAYED_WORK(&info->wq_detcable, max77843_muic_detect_cable_wq);
> +	queue_delayed_work(system_power_efficient_wq,
> +			&info->wq_detcable, msecs_to_jiffies(DELAY_MS_DEFAULT));
> +
> +	/* Check revision number of MUIC device */
> +	ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Failed to read revision number\n");
> +		return ret;
> +	}
> +	dev_info(info->dev, "MUIC device ID : 0x%x\n", id);
> +
> +	info->init_done = true;
> +
> +	return 0;
> +
> +err_muic_irq:
> +	regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
> +
> +	return ret;
> +}
> +
> +static int max77843_muic_remove(struct platform_device *pdev)
> +{
> +	struct max77843_muic_info *info = platform_get_drvdata(pdev);
> +
> +	cancel_work_sync(&info->irq_work);
> +
> +	return 0;
> +}
> +
> +static const struct platform_device_id max77843_muic_id[] = {
> +	{ "max77843-muic", },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(platform, max77843_muic_id);
> +
> +static struct platform_driver max77843_muic_driver = {
> +	.driver		= {
> +		.name		= "max77843-muic",
> +	},
> +	.probe		= max77843_muic_probe,
> +	.remove		= max77843_muic_remove,
> +	.id_table	= max77843_muic_id,
> +};
> +
> +static int __init max77843_muic_init(void)
> +{
> +	return platform_driver_register(&max77843_muic_driver);
> +}
> +subsys_initcall(max77843_muic_init);
> +
> +MODULE_DESCRIPTION("Maxim MAX77843 Extcon driver");
> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
> +MODULE_LICENSE("GPL");
> 

Thanks,
Chanwoo Choi

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

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

* Re: [PATCH 6/6] Documentation: Add device tree bindings document for max77843
@ 2015-01-23  6:25     ` Chanwoo Choi
  0 siblings, 0 replies; 41+ messages in thread
From: Chanwoo Choi @ 2015-01-23  6:25 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown, Beomho Seo

Hi Jaewon,

On 01/23/2015 02:02 PM, Jaewon Kim wrote:
> Add document describing device tree bindings for max77843 MFD.
> Drivers: MFD core, regulator, extcon, charger and fuelgauge.
> 
> Cc: Rob Herring <robh+dt@kernel.org>
> Cc: Pawel Moll <pawel.moll@arm.com>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
> Cc: Kumar Gala <galak@codeaurora.org>
> Cc: Lee Jones <lee.jones@linaro.org>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Cc: Sebastian Reichel <sre@kernel.org>
> Cc: Mark Brown <broonie@kernel.org>
> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> ---
>  Documentation/devicetree/bindings/mfd/max77843.txt |   87 ++++++++++++++++++++
>  1 file changed, 87 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/max77843.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/max77843.txt b/Documentation/devicetree/bindings/mfd/max77843.txt
> new file mode 100644
> index 0000000..6895604
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/max77843.txt
> @@ -0,0 +1,87 @@
> +Maxim MAX77843 multi-function device
> +
> +MAX77843 is a Multi-Function Device with the following submodules:
> +- PMIC	  : 2 SAFEOUT LDOs for USB device
> +- CHARGER : Li+ battery charger with Fuel Gauge
> +- MUIC	  : Micro USB Interface Circuit
> +- HAPTIC  : motor control driver for haptics

HAPTIC ?

> +- LED	  : 4 channel RGBW LED

LED ?

This patchset don't include andy haptic/led drivers.
I think it is un-necessary information.

When you implement the haptic/led driver, you will add the information
for haptic/led driver.

> +
> +It is interfaced to host controller using I2C.
> +
> +Required properties:
> +- compatible : Must be "maxim,max77843".
> +- reg : I2C slave address of PMIC block.
> +- interrupts : I2C line for main SoCs.
> +- interrupt-parent : The parent of interrupt controller.
> +
> +Optional properties:
> +- regulators : The regulators of max77843 have to be instantiated under subnode
> +	named "regulators" using the following format.
> +
> +	[*]refer : Documentation/devicetree/bindings/regulator/regulator.txt
> +
> +	regulators {
> +		SAFEOUT {
> +			regulator-name = "SAFEOUT";
> +		};
> +	}
> +
> +	List of valid regulator names:
> +	- SAFEOUT1, SAFEOUT2, CHARGER.
> +
> +- max77843-muic : This properties used by extcon consumers.
> +	Required properties:
> +		- compatible : Must be "maxim,max77842-muic".
> +
> +- max77843-charger : There battery charger of MAX77843 have to be instantiated
> +	under sub-node named "max77843-charger" using the following format.
> +	Required properties:
> +		- compatible : Must be "maxim,max77842-charger".
> +		- maxim,fast-charge-uamp : Fast charge current levels are
> +			100 mA to 3150 mA programmed by I2C per 100 mA.
> +		- maxim,top-off-uamp : Top off current threshold levels are
> +			125 mA to 650 mA programmed by I2C per 75 mA.
> +		- maxim,input-uamp-limit : Input current limit levels are
> +			100 mA to 3533 mA programmed by I2C per 33 mA.
> +- max77843-fuelgauge : There fuelgauge of MAX77843 have to be instantiated
> +	under sub-node named "max77843-fuelgauge" using the following format.
> +	Required properties:
> +		- compatible : Must be "maxim,max77842-fuelgauge".
> +
> +Example:
> +	max77843@66 {
> +		compatible = "samsung,max77843";
> +		reg = <0x66>;
> +		interrupt-parent = <&gpa1>;
> +		interrupts = <5 2>;
> +
> +		regulators {
> +			SAFEOUT1 {
> +				regulator-name = "SAFEOUT1";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <4950000>;
> +			};
> +			SAFEOUT2 {
> +				regulator-name = "SAFEOUT2";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <4950000>;
> +			};

As I knew, max77843 regulator driver supprot 'CHARGER' regulator.
I think you have to add the 'CHARGER' dt node for regulators.


> +		};
> +
> +		max77843-muic {
> +			compatible = "maxim,max77843-muic";
> +		};
> +
> +		max77843-charger {
> +			compatible = "maxim,max77843-charger";
> +			maxim,fast-charge-uamp = <450000>;
> +			maxim,top-off-uamp = <125000>;
> +			maxim,input-uamp-limit = <500000>;
> +		};
> +
> +		max77843-fuelgauge {
> +			compatible = "maxim,max77843-fuelgauge";
> +		};
> +
> +	};
> 

Thanks,
Chanwoo Choi

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

* Re: [PATCH 6/6] Documentation: Add device tree bindings document for max77843
@ 2015-01-23  6:25     ` Chanwoo Choi
  0 siblings, 0 replies; 41+ messages in thread
From: Chanwoo Choi @ 2015-01-23  6:25 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown, Beomho Seo

Hi Jaewon,

On 01/23/2015 02:02 PM, Jaewon Kim wrote:
> Add document describing device tree bindings for max77843 MFD.
> Drivers: MFD core, regulator, extcon, charger and fuelgauge.
> 
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> Cc: Ian Campbell <ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
> Cc: Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Cc: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/mfd/max77843.txt |   87 ++++++++++++++++++++
>  1 file changed, 87 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/mfd/max77843.txt
> 
> diff --git a/Documentation/devicetree/bindings/mfd/max77843.txt b/Documentation/devicetree/bindings/mfd/max77843.txt
> new file mode 100644
> index 0000000..6895604
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mfd/max77843.txt
> @@ -0,0 +1,87 @@
> +Maxim MAX77843 multi-function device
> +
> +MAX77843 is a Multi-Function Device with the following submodules:
> +- PMIC	  : 2 SAFEOUT LDOs for USB device
> +- CHARGER : Li+ battery charger with Fuel Gauge
> +- MUIC	  : Micro USB Interface Circuit
> +- HAPTIC  : motor control driver for haptics

HAPTIC ?

> +- LED	  : 4 channel RGBW LED

LED ?

This patchset don't include andy haptic/led drivers.
I think it is un-necessary information.

When you implement the haptic/led driver, you will add the information
for haptic/led driver.

> +
> +It is interfaced to host controller using I2C.
> +
> +Required properties:
> +- compatible : Must be "maxim,max77843".
> +- reg : I2C slave address of PMIC block.
> +- interrupts : I2C line for main SoCs.
> +- interrupt-parent : The parent of interrupt controller.
> +
> +Optional properties:
> +- regulators : The regulators of max77843 have to be instantiated under subnode
> +	named "regulators" using the following format.
> +
> +	[*]refer : Documentation/devicetree/bindings/regulator/regulator.txt
> +
> +	regulators {
> +		SAFEOUT {
> +			regulator-name = "SAFEOUT";
> +		};
> +	}
> +
> +	List of valid regulator names:
> +	- SAFEOUT1, SAFEOUT2, CHARGER.
> +
> +- max77843-muic : This properties used by extcon consumers.
> +	Required properties:
> +		- compatible : Must be "maxim,max77842-muic".
> +
> +- max77843-charger : There battery charger of MAX77843 have to be instantiated
> +	under sub-node named "max77843-charger" using the following format.
> +	Required properties:
> +		- compatible : Must be "maxim,max77842-charger".
> +		- maxim,fast-charge-uamp : Fast charge current levels are
> +			100 mA to 3150 mA programmed by I2C per 100 mA.
> +		- maxim,top-off-uamp : Top off current threshold levels are
> +			125 mA to 650 mA programmed by I2C per 75 mA.
> +		- maxim,input-uamp-limit : Input current limit levels are
> +			100 mA to 3533 mA programmed by I2C per 33 mA.
> +- max77843-fuelgauge : There fuelgauge of MAX77843 have to be instantiated
> +	under sub-node named "max77843-fuelgauge" using the following format.
> +	Required properties:
> +		- compatible : Must be "maxim,max77842-fuelgauge".
> +
> +Example:
> +	max77843@66 {
> +		compatible = "samsung,max77843";
> +		reg = <0x66>;
> +		interrupt-parent = <&gpa1>;
> +		interrupts = <5 2>;
> +
> +		regulators {
> +			SAFEOUT1 {
> +				regulator-name = "SAFEOUT1";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <4950000>;
> +			};
> +			SAFEOUT2 {
> +				regulator-name = "SAFEOUT2";
> +				regulator-min-microvolt = <3300000>;
> +				regulator-max-microvolt = <4950000>;
> +			};

As I knew, max77843 regulator driver supprot 'CHARGER' regulator.
I think you have to add the 'CHARGER' dt node for regulators.


> +		};
> +
> +		max77843-muic {
> +			compatible = "maxim,max77843-muic";
> +		};
> +
> +		max77843-charger {
> +			compatible = "maxim,max77843-charger";
> +			maxim,fast-charge-uamp = <450000>;
> +			maxim,top-off-uamp = <125000>;
> +			maxim,input-uamp-limit = <500000>;
> +		};
> +
> +		max77843-fuelgauge {
> +			compatible = "maxim,max77843-fuelgauge";
> +		};
> +
> +	};
> 

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

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  6:32     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2015-01-23  6:32 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
> This patch adds MAX77843 core/irq driver to support PMIC,
> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
> LED and Haptic device.
>
> Cc: Lee Jones <lee.jones@linaro.org>
> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> ---
>  drivers/mfd/Kconfig                  |   14 ++
>  drivers/mfd/Makefile                 |    1 +
>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>  4 files changed, 666 insertions(+)
>  create mode 100644 drivers/mfd/max77843.c
>  create mode 100644 include/linux/mfd/max77843-private.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 2e6b731..0c67c79 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -442,6 +442,20 @@ config MFD_MAX77693
>           additional drivers must be enabled in order to use the functionality
>           of the device.
>
> +config MFD_MAX77843
> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
> +       depends on I2C=y
> +       select MFD_CORE
> +       select REGMAP_I2C
> +       select REGMAP_IRQ
> +       help
> +         Say yes here to add support for Maxim Semiconductor MAX77843.
> +         This is companion Power Management IC with LEDs, Haptic, Charger,
> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
> +         This driver provides common support for accessing the device;
> +         additional drivers must be enabled in order to use the functionality
> +         of the device.
> +
>  config MFD_MAX8907
>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
>         select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 53467e2..fe4f75c 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>  max8925-objs                   := max8925-core.o max8925-i2c.o
>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
> new file mode 100644
> index 0000000..d7f8b76
> --- /dev/null
> +++ b/drivers/mfd/max77843.c
> @@ -0,0 +1,241 @@
> +/*
> + * max77843.c - MFD core driver for the Maxim MAX77843
> + *
> + * Copyright (C) 2014 Samsung Electrnoics
> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/max77843-private.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +static const struct mfd_cell max77843_devs[] = {
> +       {
> +               .name = "max77843-muic",
> +               .of_compatible = "maxim,max77843-muic",
> +       }, {
> +               .name = "max77843-regulator",
> +               .of_compatible = "maxim,max77843-regulator",
> +       }, {
> +               .name = "max77843-charger",
> +               .of_compatible = "maxim,max77843-charger"
> +       }, {
> +               .name = "max77843-fuelgauge",
> +               .of_compatible = "maxim,max77843-fuelgauge",
> +       },
> +};
> +
> +static const struct regmap_config max77843_charger_regmap_config = {
> +       .reg_bits       = 8,
> +       .val_bits       = 8,
> +       .max_register   = MAX77843_CHG_REG_END,
> +};
> +
> +static const struct regmap_config max77843_regmap_config = {
> +       .reg_bits       = 8,
> +       .val_bits       = 8,
> +       .max_register   = MAX77843_SYS_REG_END,
> +};
> +
> +static const struct regmap_irq max77843_irqs[] = {
> +       /* TOPSYS interrupts */
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
> +};
> +
> +static const struct regmap_irq_chip max77843_irq_chip = {
> +       .name           = "max77843",
> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
> +       .mask_invert    = false,
> +       .num_regs       = 1,
> +       .irqs           = max77843_irqs,
> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
> +};
> +
> +static int max77843_chg_init(struct max77843 *max77843)
> +{

Could this function be moved to the charger driver? This way the
driver will manage its own resources instead of depending on parent
MFD driver.

> +       int ret;
> +
> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
> +       if (!max77843->i2c_chg) {
> +               dev_err(&max77843->i2c->dev,
> +                               "Cannot allocate I2C device for Charger\n");
> +               return PTR_ERR(max77843->i2c_chg);
> +       }
> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
> +
> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
> +                       &max77843_charger_regmap_config);
> +       if (IS_ERR(max77843->regmap_chg)) {
> +               ret = PTR_ERR(max77843->regmap_chg);
> +               goto err_chg_i2c;
> +       }
> +
> +       return 0;
> +
> +err_chg_i2c:
> +       i2c_unregister_device(max77843->i2c_chg);
> +
> +       return ret;
> +}
> +
> +static int max77843_probe(struct i2c_client *i2c,
> +                                       const struct i2c_device_id *id)
> +{
> +       struct max77843 *max77843;
> +       int ret;
> +       unsigned int reg_data;
> +
> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
> +       if (!max77843)
> +               return -ENOMEM;
> +
> +       i2c_set_clientdata(i2c, max77843);
> +       max77843->dev = &i2c->dev;
> +       max77843->i2c = i2c;
> +       max77843->irq = i2c->irq;
> +
> +       max77843->regmap = devm_regmap_init_i2c(i2c,
> +                       &max77843_regmap_config);
> +       if (IS_ERR(max77843->regmap)) {
> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
> +               return PTR_ERR(max77843->regmap);
> +       }
> +
> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> +                       0, &max77843_irq_chip, &max77843->irq_data);

Why shared IRQ?

> +       if (ret) {
> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
> +               return ret;
> +       }
> +
> +       ret = regmap_read(max77843->regmap,
> +                       MAX77843_SYS_REG_PMICID, &reg_data);
> +       if (ret < 0) {
> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
> +               goto err_pmic_id;
> +       }
> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
> +
> +       ret = max77843_chg_init(max77843);
> +       if (ret) {
> +               dev_err(&i2c->dev, "Failed to init Charger\n");
> +               goto err_pmic_id;
> +       }
> +
> +       ret = regmap_update_bits(max77843->regmap,
> +                       MAX77843_SYS_REG_INTSRCMASK,
> +                       MAX77843_INTSRC_MASK_MASK,
> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
> +       if (ret < 0) {
> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");

s/sourece/source/

Best regards,
Krzysztof

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  6:32     ` Krzysztof Kozlowski
  0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2015-01-23  6:32 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>:
> This patch adds MAX77843 core/irq driver to support PMIC,
> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
> LED and Haptic device.
>
> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/mfd/Kconfig                  |   14 ++
>  drivers/mfd/Makefile                 |    1 +
>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>  4 files changed, 666 insertions(+)
>  create mode 100644 drivers/mfd/max77843.c
>  create mode 100644 include/linux/mfd/max77843-private.h
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 2e6b731..0c67c79 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -442,6 +442,20 @@ config MFD_MAX77693
>           additional drivers must be enabled in order to use the functionality
>           of the device.
>
> +config MFD_MAX77843
> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
> +       depends on I2C=y
> +       select MFD_CORE
> +       select REGMAP_I2C
> +       select REGMAP_IRQ
> +       help
> +         Say yes here to add support for Maxim Semiconductor MAX77843.
> +         This is companion Power Management IC with LEDs, Haptic, Charger,
> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
> +         This driver provides common support for accessing the device;
> +         additional drivers must be enabled in order to use the functionality
> +         of the device.
> +
>  config MFD_MAX8907
>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
>         select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 53467e2..fe4f75c 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>  max8925-objs                   := max8925-core.o max8925-i2c.o
>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
> new file mode 100644
> index 0000000..d7f8b76
> --- /dev/null
> +++ b/drivers/mfd/max77843.c
> @@ -0,0 +1,241 @@
> +/*
> + * max77843.c - MFD core driver for the Maxim MAX77843
> + *
> + * Copyright (C) 2014 Samsung Electrnoics
> + * Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/max77843-private.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +static const struct mfd_cell max77843_devs[] = {
> +       {
> +               .name = "max77843-muic",
> +               .of_compatible = "maxim,max77843-muic",
> +       }, {
> +               .name = "max77843-regulator",
> +               .of_compatible = "maxim,max77843-regulator",
> +       }, {
> +               .name = "max77843-charger",
> +               .of_compatible = "maxim,max77843-charger"
> +       }, {
> +               .name = "max77843-fuelgauge",
> +               .of_compatible = "maxim,max77843-fuelgauge",
> +       },
> +};
> +
> +static const struct regmap_config max77843_charger_regmap_config = {
> +       .reg_bits       = 8,
> +       .val_bits       = 8,
> +       .max_register   = MAX77843_CHG_REG_END,
> +};
> +
> +static const struct regmap_config max77843_regmap_config = {
> +       .reg_bits       = 8,
> +       .val_bits       = 8,
> +       .max_register   = MAX77843_SYS_REG_END,
> +};
> +
> +static const struct regmap_irq max77843_irqs[] = {
> +       /* TOPSYS interrupts */
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
> +};
> +
> +static const struct regmap_irq_chip max77843_irq_chip = {
> +       .name           = "max77843",
> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
> +       .mask_invert    = false,
> +       .num_regs       = 1,
> +       .irqs           = max77843_irqs,
> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
> +};
> +
> +static int max77843_chg_init(struct max77843 *max77843)
> +{

Could this function be moved to the charger driver? This way the
driver will manage its own resources instead of depending on parent
MFD driver.

> +       int ret;
> +
> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
> +       if (!max77843->i2c_chg) {
> +               dev_err(&max77843->i2c->dev,
> +                               "Cannot allocate I2C device for Charger\n");
> +               return PTR_ERR(max77843->i2c_chg);
> +       }
> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
> +
> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
> +                       &max77843_charger_regmap_config);
> +       if (IS_ERR(max77843->regmap_chg)) {
> +               ret = PTR_ERR(max77843->regmap_chg);
> +               goto err_chg_i2c;
> +       }
> +
> +       return 0;
> +
> +err_chg_i2c:
> +       i2c_unregister_device(max77843->i2c_chg);
> +
> +       return ret;
> +}
> +
> +static int max77843_probe(struct i2c_client *i2c,
> +                                       const struct i2c_device_id *id)
> +{
> +       struct max77843 *max77843;
> +       int ret;
> +       unsigned int reg_data;
> +
> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
> +       if (!max77843)
> +               return -ENOMEM;
> +
> +       i2c_set_clientdata(i2c, max77843);
> +       max77843->dev = &i2c->dev;
> +       max77843->i2c = i2c;
> +       max77843->irq = i2c->irq;
> +
> +       max77843->regmap = devm_regmap_init_i2c(i2c,
> +                       &max77843_regmap_config);
> +       if (IS_ERR(max77843->regmap)) {
> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
> +               return PTR_ERR(max77843->regmap);
> +       }
> +
> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> +                       0, &max77843_irq_chip, &max77843->irq_data);

Why shared IRQ?

> +       if (ret) {
> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
> +               return ret;
> +       }
> +
> +       ret = regmap_read(max77843->regmap,
> +                       MAX77843_SYS_REG_PMICID, &reg_data);
> +       if (ret < 0) {
> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
> +               goto err_pmic_id;
> +       }
> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
> +
> +       ret = max77843_chg_init(max77843);
> +       if (ret) {
> +               dev_err(&i2c->dev, "Failed to init Charger\n");
> +               goto err_pmic_id;
> +       }
> +
> +       ret = regmap_update_bits(max77843->regmap,
> +                       MAX77843_SYS_REG_INTSRCMASK,
> +                       MAX77843_INTSRC_MASK_MASK,
> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
> +       if (ret < 0) {
> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");

s/sourece/source/

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

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

* Re: [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver
  2015-01-23  5:02 ` [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver Jaewon Kim
  2015-01-23  6:21     ` Chanwoo Choi
@ 2015-01-23  6:38   ` Krzysztof Kozłowski
  2015-01-23  7:18     ` Jaewon Kim
  1 sibling, 1 reply; 41+ messages in thread
From: Krzysztof Kozłowski @ 2015-01-23  6:38 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
> This patch adds MAX77843 extcon driver to support for MUIC(Micro
> USB Interface Controller) device by using EXTCON subsystem to handle
> various external connectors.
>
> Cc: Chanwoo Choi <cw00.choi@samsung.com>
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> ---
>  drivers/extcon/Kconfig           |   10 +
>  drivers/extcon/Makefile          |    1 +
>  drivers/extcon/extcon-max77843.c |  871 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 882 insertions(+)
>  create mode 100644 drivers/extcon/extcon-max77843.c
>

(...)

> +static int max77843_muic_remove(struct platform_device *pdev)
> +{
> +       struct max77843_muic_info *info = platform_get_drvdata(pdev);
> +
> +       cancel_work_sync(&info->irq_work);
> +

Missing regmap_del_irq_chip().

Best regards,
Krzysztof

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  6:41       ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23  6:41 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown

On 01/23/2015 03:32 PM, Krzysztof Kozlowski wrote:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
>> This patch adds MAX77843 core/irq driver to support PMIC,
>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>> LED and Haptic device.
>>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>>  drivers/mfd/Kconfig                  |   14 ++
>>  drivers/mfd/Makefile                 |    1 +
>>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>  4 files changed, 666 insertions(+)
>>  create mode 100644 drivers/mfd/max77843.c
>>  create mode 100644 include/linux/mfd/max77843-private.h
>>
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 2e6b731..0c67c79 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>           additional drivers must be enabled in order to use the functionality
>>           of the device.
>>
>> +config MFD_MAX77843
>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
>> +       depends on I2C=y
>> +       select MFD_CORE
>> +       select REGMAP_I2C
>> +       select REGMAP_IRQ
>> +       help
>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>> +         This driver provides common support for accessing the device;
>> +         additional drivers must be enabled in order to use the functionality
>> +         of the device.
>> +
>>  config MFD_MAX8907
>>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>         select MFD_CORE
>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> index 53467e2..fe4f75c 100644
>> --- a/drivers/mfd/Makefile
>> +++ b/drivers/mfd/Makefile
>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>>  max8925-objs                   := max8925-core.o max8925-i2c.o
>>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>> new file mode 100644
>> index 0000000..d7f8b76
>> --- /dev/null
>> +++ b/drivers/mfd/max77843.c
>> @@ -0,0 +1,241 @@
>> +/*
>> + * max77843.c - MFD core driver for the Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/mfd/max77843-private.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +
>> +static const struct mfd_cell max77843_devs[] = {
>> +       {
>> +               .name = "max77843-muic",
>> +               .of_compatible = "maxim,max77843-muic",
>> +       }, {
>> +               .name = "max77843-regulator",
>> +               .of_compatible = "maxim,max77843-regulator",
>> +       }, {
>> +               .name = "max77843-charger",
>> +               .of_compatible = "maxim,max77843-charger"
>> +       }, {
>> +               .name = "max77843-fuelgauge",
>> +               .of_compatible = "maxim,max77843-fuelgauge",
>> +       },
>> +};
>> +
>> +static const struct regmap_config max77843_charger_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_CHG_REG_END,
>> +};
>> +
>> +static const struct regmap_config max77843_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_SYS_REG_END,
>> +};
>> +
>> +static const struct regmap_irq max77843_irqs[] = {
>> +       /* TOPSYS interrupts */
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>> +};
>> +
>> +static const struct regmap_irq_chip max77843_irq_chip = {
>> +       .name           = "max77843",
>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
>> +       .mask_invert    = false,
>> +       .num_regs       = 1,
>> +       .irqs           = max77843_irqs,
>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
>> +};
>> +
>> +static int max77843_chg_init(struct max77843 *max77843)
>> +{
> 
> Could this function be moved to the charger driver? This way the
> driver will manage its own resources instead of depending on parent
> MFD driver.
> 

Charger regulator and Charger share same resources.
So I include this function core driver.

>> +       int ret;
>> +
>> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
>> +       if (!max77843->i2c_chg) {
>> +               dev_err(&max77843->i2c->dev,
>> +                               "Cannot allocate I2C device for Charger\n");
>> +               return PTR_ERR(max77843->i2c_chg);
>> +       }
>> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
>> +
>> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
>> +                       &max77843_charger_regmap_config);
>> +       if (IS_ERR(max77843->regmap_chg)) {
>> +               ret = PTR_ERR(max77843->regmap_chg);
>> +               goto err_chg_i2c;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_chg_i2c:
>> +       i2c_unregister_device(max77843->i2c_chg);
>> +
>> +       return ret;
>> +}
>> +
>> +static int max77843_probe(struct i2c_client *i2c,
>> +                                       const struct i2c_device_id *id)
>> +{
>> +       struct max77843 *max77843;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
>> +       if (!max77843)
>> +               return -ENOMEM;
>> +
>> +       i2c_set_clientdata(i2c, max77843);
>> +       max77843->dev = &i2c->dev;
>> +       max77843->i2c = i2c;
>> +       max77843->irq = i2c->irq;
>> +
>> +       max77843->regmap = devm_regmap_init_i2c(i2c,
>> +                       &max77843_regmap_config);
>> +       if (IS_ERR(max77843->regmap)) {
>> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
>> +               return PTR_ERR(max77843->regmap);
>> +       }
>> +
>> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
>> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
>> +                       0, &max77843_irq_chip, &max77843->irq_data);
> 
> Why shared IRQ?
> 
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = regmap_read(max77843->regmap,
>> +                       MAX77843_SYS_REG_PMICID, &reg_data);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
>> +               goto err_pmic_id;
>> +       }
>> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
>> +
>> +       ret = max77843_chg_init(max77843);
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to init Charger\n");
>> +               goto err_pmic_id;
>> +       }
>> +
>> +       ret = regmap_update_bits(max77843->regmap,
>> +                       MAX77843_SYS_REG_INTSRCMASK,
>> +                       MAX77843_INTSRC_MASK_MASK,
>> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> 
> s/sourece/source/
> 
> Best regards,
> Krzysztof
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" 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] 41+ messages in thread

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  6:41       ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23  6:41 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown

On 01/23/2015 03:32 PM, Krzysztof Kozlowski wrote:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>:
>> This patch adds MAX77843 core/irq driver to support PMIC,
>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>> LED and Haptic device.
>>
>> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>>  drivers/mfd/Kconfig                  |   14 ++
>>  drivers/mfd/Makefile                 |    1 +
>>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>  4 files changed, 666 insertions(+)
>>  create mode 100644 drivers/mfd/max77843.c
>>  create mode 100644 include/linux/mfd/max77843-private.h
>>
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 2e6b731..0c67c79 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>           additional drivers must be enabled in order to use the functionality
>>           of the device.
>>
>> +config MFD_MAX77843
>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
>> +       depends on I2C=y
>> +       select MFD_CORE
>> +       select REGMAP_I2C
>> +       select REGMAP_IRQ
>> +       help
>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>> +         This driver provides common support for accessing the device;
>> +         additional drivers must be enabled in order to use the functionality
>> +         of the device.
>> +
>>  config MFD_MAX8907
>>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>         select MFD_CORE
>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> index 53467e2..fe4f75c 100644
>> --- a/drivers/mfd/Makefile
>> +++ b/drivers/mfd/Makefile
>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>>  max8925-objs                   := max8925-core.o max8925-i2c.o
>>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>> new file mode 100644
>> index 0000000..d7f8b76
>> --- /dev/null
>> +++ b/drivers/mfd/max77843.c
>> @@ -0,0 +1,241 @@
>> +/*
>> + * max77843.c - MFD core driver for the Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + * Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/mfd/max77843-private.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +
>> +static const struct mfd_cell max77843_devs[] = {
>> +       {
>> +               .name = "max77843-muic",
>> +               .of_compatible = "maxim,max77843-muic",
>> +       }, {
>> +               .name = "max77843-regulator",
>> +               .of_compatible = "maxim,max77843-regulator",
>> +       }, {
>> +               .name = "max77843-charger",
>> +               .of_compatible = "maxim,max77843-charger"
>> +       }, {
>> +               .name = "max77843-fuelgauge",
>> +               .of_compatible = "maxim,max77843-fuelgauge",
>> +       },
>> +};
>> +
>> +static const struct regmap_config max77843_charger_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_CHG_REG_END,
>> +};
>> +
>> +static const struct regmap_config max77843_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_SYS_REG_END,
>> +};
>> +
>> +static const struct regmap_irq max77843_irqs[] = {
>> +       /* TOPSYS interrupts */
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>> +};
>> +
>> +static const struct regmap_irq_chip max77843_irq_chip = {
>> +       .name           = "max77843",
>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
>> +       .mask_invert    = false,
>> +       .num_regs       = 1,
>> +       .irqs           = max77843_irqs,
>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
>> +};
>> +
>> +static int max77843_chg_init(struct max77843 *max77843)
>> +{
> 
> Could this function be moved to the charger driver? This way the
> driver will manage its own resources instead of depending on parent
> MFD driver.
> 

Charger regulator and Charger share same resources.
So I include this function core driver.

>> +       int ret;
>> +
>> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
>> +       if (!max77843->i2c_chg) {
>> +               dev_err(&max77843->i2c->dev,
>> +                               "Cannot allocate I2C device for Charger\n");
>> +               return PTR_ERR(max77843->i2c_chg);
>> +       }
>> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
>> +
>> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
>> +                       &max77843_charger_regmap_config);
>> +       if (IS_ERR(max77843->regmap_chg)) {
>> +               ret = PTR_ERR(max77843->regmap_chg);
>> +               goto err_chg_i2c;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_chg_i2c:
>> +       i2c_unregister_device(max77843->i2c_chg);
>> +
>> +       return ret;
>> +}
>> +
>> +static int max77843_probe(struct i2c_client *i2c,
>> +                                       const struct i2c_device_id *id)
>> +{
>> +       struct max77843 *max77843;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
>> +       if (!max77843)
>> +               return -ENOMEM;
>> +
>> +       i2c_set_clientdata(i2c, max77843);
>> +       max77843->dev = &i2c->dev;
>> +       max77843->i2c = i2c;
>> +       max77843->irq = i2c->irq;
>> +
>> +       max77843->regmap = devm_regmap_init_i2c(i2c,
>> +                       &max77843_regmap_config);
>> +       if (IS_ERR(max77843->regmap)) {
>> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
>> +               return PTR_ERR(max77843->regmap);
>> +       }
>> +
>> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
>> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
>> +                       0, &max77843_irq_chip, &max77843->irq_data);
> 
> Why shared IRQ?
> 
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = regmap_read(max77843->regmap,
>> +                       MAX77843_SYS_REG_PMICID, &reg_data);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
>> +               goto err_pmic_id;
>> +       }
>> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
>> +
>> +       ret = max77843_chg_init(max77843);
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to init Charger\n");
>> +               goto err_pmic_id;
>> +       }
>> +
>> +       ret = regmap_update_bits(max77843->regmap,
>> +                       MAX77843_SYS_REG_INTSRCMASK,
>> +                       MAX77843_INTSRC_MASK_MASK,
>> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> 
> s/sourece/source/
> 
> Best regards,
> Krzysztof
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
  2015-01-23  5:02   ` Jaewon Kim
  (?)
  (?)
@ 2015-01-23  6:49   ` Chanwoo Choi
  2015-01-23  8:43     ` Jaewon Kim
  -1 siblings, 1 reply; 41+ messages in thread
From: Chanwoo Choi @ 2015-01-23  6:49 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown, Beomho Seo

Hi Jaewon,

On 01/23/2015 02:02 PM, Jaewon Kim wrote:
> This patch adds MAX77843 core/irq driver to support PMIC,
> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
> LED and Haptic device.
> 
> Cc: Lee Jones <lee.jones@linaro.org>
> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> ---
>  drivers/mfd/Kconfig                  |   14 ++
>  drivers/mfd/Makefile                 |    1 +
>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>  4 files changed, 666 insertions(+)
>  create mode 100644 drivers/mfd/max77843.c
>  create mode 100644 include/linux/mfd/max77843-private.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 2e6b731..0c67c79 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -442,6 +442,20 @@ config MFD_MAX77693
>  	  additional drivers must be enabled in order to use the functionality
>  	  of the device.
>  
> +config MFD_MAX77843
> +	bool "Maxim Semiconductor MAX77843 PMIC Support"
> +	depends on I2C=y
> +	select MFD_CORE
> +	select REGMAP_I2C
> +	select REGMAP_IRQ
> +	help
> +	  Say yes here to add support for Maxim Semiconductor MAX77843.
> +	  This is companion Power Management IC with LEDs, Haptic, Charger,
> +	  Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
> +	  This driver provides common support for accessing the device;
> +	  additional drivers must be enabled in order to use the functionality
> +	  of the device.
> +
>  config MFD_MAX8907
>  	tristate "Maxim Semiconductor MAX8907 PMIC Support"
>  	select MFD_CORE
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index 53467e2..fe4f75c 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
>  obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
>  obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
>  obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
> +obj-$(CONFIG_MFD_MAX77843)	+= max77843.o
>  obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
>  max8925-objs			:= max8925-core.o max8925-i2c.o
>  obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
> new file mode 100644
> index 0000000..d7f8b76
> --- /dev/null
> +++ b/drivers/mfd/max77843.c
> @@ -0,0 +1,241 @@
> +/*
> + * max77843.c - MFD core driver for the Maxim MAX77843
> + *
> + * Copyright (C) 2014 Samsung Electrnoics
> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/max77843-private.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +static const struct mfd_cell max77843_devs[] = {
> +	{
> +		.name = "max77843-muic",
> +		.of_compatible = "maxim,max77843-muic",
> +	}, {
> +		.name = "max77843-regulator",
> +		.of_compatible = "maxim,max77843-regulator",
> +	}, {
> +		.name = "max77843-charger",
> +		.of_compatible = "maxim,max77843-charger"
> +	}, {
> +		.name = "max77843-fuelgauge",
> +		.of_compatible = "maxim,max77843-fuelgauge",
> +	},
> +};
> +
> +static const struct regmap_config max77843_charger_regmap_config = {
> +	.reg_bits	= 8,
> +	.val_bits	= 8,
> +	.max_register	= MAX77843_CHG_REG_END,
> +};
> +
> +static const struct regmap_config max77843_regmap_config = {
> +	.reg_bits	= 8,
> +	.val_bits	= 8,
> +	.max_register	= MAX77843_SYS_REG_END,
> +};
> +
> +static const struct regmap_irq max77843_irqs[] = {
> +	/* TOPSYS interrupts */
> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
> +};
> +
> +static const struct regmap_irq_chip max77843_irq_chip = {
> +	.name		= "max77843",
> +	.status_base	= MAX77843_SYS_REG_SYSINTSRC,
> +	.mask_base	= MAX77843_SYS_REG_SYSINTMASK,
> +	.mask_invert	= false,
> +	.num_regs	= 1,
> +	.irqs		= max77843_irqs,
> +	.num_irqs	= ARRAY_SIZE(max77843_irqs),
> +};
> +
> +static int max77843_chg_init(struct max77843 *max77843)
> +{
> +	int ret;
> +
> +	max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
> +	if (!max77843->i2c_chg) {
> +		dev_err(&max77843->i2c->dev,
> +				"Cannot allocate I2C device for Charger\n");
> +		return PTR_ERR(max77843->i2c_chg);
> +	}
> +	i2c_set_clientdata(max77843->i2c_chg, max77843);
> +
> +	max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
> +			&max77843_charger_regmap_config);
> +	if (IS_ERR(max77843->regmap_chg)) {
> +		ret = PTR_ERR(max77843->regmap_chg);
> +		goto err_chg_i2c;
> +	}
> +
> +	return 0;
> +
> +err_chg_i2c:
> +	i2c_unregister_device(max77843->i2c_chg);
> +
> +	return ret;
> +}
> +
> +static int max77843_probe(struct i2c_client *i2c,
> +					const struct i2c_device_id *id)
> +{
> +	struct max77843 *max77843;
> +	int ret;
> +	unsigned int reg_data;
> +
> +	max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
> +	if (!max77843)
> +		return -ENOMEM;
> +
> +	i2c_set_clientdata(i2c, max77843);
> +	max77843->dev = &i2c->dev;
> +	max77843->i2c = i2c;
> +	max77843->irq = i2c->irq;
> +
> +	max77843->regmap = devm_regmap_init_i2c(i2c, 
> +			&max77843_regmap_config);
> +	if (IS_ERR(max77843->regmap)) {
> +		dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
> +		return PTR_ERR(max77843->regmap);
> +	}
> +
> +	ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
> +			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> +			0, &max77843_irq_chip, &max77843->irq_data);
> +	if (ret) {
> +		dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
> +		return ret;
> +	}
> +
> +	ret = regmap_read(max77843->regmap,
> +			MAX77843_SYS_REG_PMICID, &reg_data);
> +	if (ret < 0) {
> +		dev_err(&i2c->dev, "Failed to read PMIC ID\n");
> +		goto err_pmic_id;
> +	}
> +	dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
> +
> +	ret = max77843_chg_init(max77843);
> +	if (ret) {
> +		dev_err(&i2c->dev, "Failed to init Charger\n");
> +		goto err_pmic_id;
> +	}
> +
> +	ret = regmap_update_bits(max77843->regmap,
> +			MAX77843_SYS_REG_INTSRCMASK,
> +			MAX77843_INTSRC_MASK_MASK,
> +			(unsigned int)~MAX77843_INTSRC_MASK_MASK);

Do you must need the casting with (unsigned int)?
I think you better use the correct value which
includes the unmasking data of some interrupts
instead of (unsigned int)~MAX77843_INTSRC_MASK_MASK.

> +	if (ret < 0) {
> +		dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> +		goto err_pmic_id;
> +	}
> +
> +	ret = mfd_add_devices(max77843->dev, -1, max77843_devs,
> +			ARRAY_SIZE(max77843_devs), NULL, 0, NULL);
> +	if (ret < 0) {
> +		dev_err(&i2c->dev, "Failed to add mfd device\n");
> +		goto err_pmic_id;
> +	}
> +
> +	device_init_wakeup(max77843->dev, 1);
> +
> +	return 0;
> +
> +err_pmic_id:
> +	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
> +
> +	return ret;
> +}
> +
> +static int max77843_remove(struct i2c_client *i2c)
> +{
> +	struct max77843 *max77843 = i2c_get_clientdata(i2c);
> +
> +	mfd_remove_devices(max77843->dev);
> +
> +	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
> +
> +	i2c_unregister_device(max77843->i2c);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id max77843_dt_match[] = {
> +	{ .compatible = "maxim,max77843", },
> +	{ /* sentinel */ },
> +};
> +
> +static const struct i2c_device_id max77843_id[] = {
> +	{ "max77843", },
> +	{ /* sentinel */ },
> +};
> +MODULE_DEVICE_TABLE(i2c, max77843_id);
> +
> +static int __maybe_unused max77843_suspend(struct device *dev)
> +{
> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> +	struct max77843 *max77843 = i2c_get_clientdata(i2c);
> +
> +	if (device_may_wakeup(dev))
> +		enable_irq_wake(max77843->irq);
> +	disable_irq(max77843->irq);
> +
> +	return 0;
> +}
> +
> +static int __maybe_unused max77843_resume(struct device *dev)
> +{
> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
> +	struct max77843 *max77843 = i2c_get_clientdata(i2c);
> +
> +	if (device_may_wakeup(dev))
> +		disable_irq_wake(max77843->irq);
> +	enable_irq(max77843->irq);
> +
> +	return 0;
> +}
> +
> +static SIMPLE_DEV_PM_OPS(max77843_pm, max77843_suspend, max77843_resume);
> +
> +static struct i2c_driver max77843_i2c_driver = {
> +	.driver		= {
> +		.name		= "max77843",
> +		.pm		= &max77843_pm,
> +		.of_match_table = max77843_dt_match,
> +	},
> +	.probe		= max77843_probe,
> +	.remove		= max77843_remove,
> +	.id_table	= max77843_id,
> +};
> +static int __init max77843_i2c_init(void)
> +{
> +	return i2c_add_driver(&max77843_i2c_driver);
> +}
> +subsys_initcall(max77843_i2c_init);
> +
> +static void __exit max77843_i2c_exit(void)
> +{
> +	i2c_del_driver(&max77843_i2c_driver);
> +}
> +module_exit(max77843_i2c_exit);
> +
> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
> +MODULE_DESCRIPTION("Maxim MAX77843 multi-function core driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h
> new file mode 100644
> index 0000000..560ed73
> --- /dev/null
> +++ b/include/linux/mfd/max77843-private.h
> @@ -0,0 +1,410 @@
> +/*
> + * max77843-private.h - Common API for the Maxim MAX77843 internal sub chip
> + *
> + * Copyright (C) 2014 Samsung Electrnoics
> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#ifndef __MAX77843_PRIVATE_H_
> +#define __MAX77843_PRIVATE_H_
> +
> +#include <linux/i2c.h>
> +#include <linux/regmap.h>
> +
> +#define I2C_ADDR_TOPSYS	(0xCC >> 1)
> +#define I2C_ADDR_CHG	(0xD2 >> 1)
> +#define I2C_ADDR_FG	(0x6C >> 1)
> +#define I2C_ADDR_MUIC	(0x4A >> 1)
> +
> +/* Topsys, Haptic and LED registers */
> +enum max77843_sys_reg {
> +	MAX77843_SYS_REG_PMICID		= 0x00,
> +	MAX77843_SYS_REG_PMICREV	= 0x01,
> +	MAX77843_SYS_REG_MAINCTRL1	= 0x02,
> +	MAX77843_SYS_REG_INTSRC		= 0x22,
> +	MAX77843_SYS_REG_INTSRCMASK	= 0x23,
> +	MAX77843_SYS_REG_SYSINTSRC	= 0x24,
> +	MAX77843_SYS_REG_SYSINTMASK	= 0x26,
> +	MAX77843_SYS_REG_TOPSYS_STAT	= 0x28,
> +	MAX77843_SYS_REG_SAFEOUTCTRL	= 0xC6,
> +
> +	MAX77843_SYS_REG_END,
> +};
> +
> +enum max77843_led_reg {
> +	MAX77843_LED_REG_LEDEN		= 0x30,
> +	MAX77843_LED_REG_LED0BRT	= 0x31,
> +	MAX77843_LED_REG_LED1BRT	= 0x32,
> +	MAX77843_LED_REG_LED2BRT	= 0x33,
> +	MAX77843_LED_REG_LED3BRT	= 0x34,
> +	MAX77843_LED_REG_LEDBLNK	= 0x38,
> +	MAX77843_LED_REG_LEDRAMP	= 0x36,
> +
> +	MAX77843_LED_REG_END,
> +};
> +
> +/* Charger registers */
> +enum max77843_charger_reg {
> +	MAX77843_CHG_REG_CHG_INT	= 0xB0,
> +	MAX77843_CHG_REG_CHG_INT_MASK	= 0xB1,
> +	MAX77843_CHG_REG_CHG_INT_OK	= 0xB2,
> +	MAX77843_CHG_REG_CHG_DTLS_00	= 0xB3,
> +	MAX77843_CHG_REG_CHG_DTLS_01	= 0xB4,
> +	MAX77843_CHG_REG_CHG_DTLS_02	= 0xB5,
> +	MAX77843_CHG_REG_CHG_CNFG_00	= 0xB7,
> +	MAX77843_CHG_REG_CHG_CNFG_01	= 0xB8,
> +	MAX77843_CHG_REG_CHG_CNFG_02	= 0xB9,
> +	MAX77843_CHG_REG_CHG_CNFG_03	= 0xBA,
> +	MAX77843_CHG_REG_CHG_CNFG_04	= 0xBB,
> +	MAX77843_CHG_REG_CHG_CNFG_06	= 0xBD,
> +	MAX77843_CHG_REG_CHG_CNFG_07	= 0xBE,
> +	MAX77843_CHG_REG_CHG_CNFG_09	= 0xC0,
> +	MAX77843_CHG_REG_CHG_CNFG_10	= 0xC1,
> +	MAX77843_CHG_REG_CHG_CNFG_11	= 0xC2,
> +	MAX77843_CHG_REG_CHG_CNFG_12	= 0xC3,
> +
> +	MAX77843_CHG_REG_END,
> +};
> +
> +/* Fuel gauge registers */
> +enum max77843_fuelgauge {
> +	MAX77843_FG_REG_STATUS		= 0x00,
> +	MAX77843_FG_REG_VALRT_TH	= 0x01,
> +	MAX77843_FG_REG_TALRT_TH	= 0x02,
> +	MAX77843_FG_REG_SALRT_TH	= 0x03,
> +	MAX77843_FG_RATE_AT_RATE	= 0x04,
> +	MAX77843_FG_REG_REMCAP_REP	= 0x05,
> +	MAX77843_FG_REG_SOCREP		= 0x06,
> +	MAX77843_FG_REG_AGE		= 0x07,
> +	MAX77843_FG_REG_TEMP		= 0x08,
> +	MAX77843_FG_REG_VCELL		= 0x09,
> +	MAX77843_FG_REG_CURRENT		= 0x0A,
> +	MAX77843_FG_REG_AVG_CURRENT	= 0x0B,
> +	MAX77843_FG_REG_SOCMIX		= 0x0D,
> +	MAX77843_FG_REG_SOCAV		= 0x0E,
> +	MAX77843_FG_REG_REMCAP_MIX	= 0x0F,
> +	MAX77843_FG_REG_FULLCAP		= 0x10,
> +	MAX77843_FG_REG_AVG_TEMP	= 0x16,
> +	MAX77843_FG_REG_CYCLES		= 0x17,
> +	MAX77843_FG_REG_AVG_VCELL	= 0x19,
> +	MAX77843_FG_REG_CONFIG		= 0x1D,
> +	MAX77843_FG_REG_REMCAP_AV	= 0x1F,
> +	MAX77843_FG_REG_FULLCAP_NOM	= 0x23,
> +	MAX77843_FG_REG_MISCCFG		= 0x2B,
> +	MAX77843_FG_REG_RCOMP		= 0x38,
> +	MAX77843_FG_REG_FSTAT		= 0x3D,
> +	MAX77843_FG_REG_DQACC		= 0x45,
> +	MAX77843_FG_REG_DPACC		= 0x46,
> +	MAX77843_FG_REG_OCV		= 0xEE,
> +	MAX77843_FG_REG_VFOCV		= 0xFB,
> +	MAX77843_FG_SOCVF		= 0xFF,
> +
> +	MAX77843_FG_END,
> +};
> +
> +/* Muic registers */
> +enum max77843_muic_reg {
> +	MAX77843_MUIC_REG_ID		= 0x00,
> +	MAX77843_MUIC_REG_INT1		= 0x01,
> +	MAX77843_MUIC_REG_INT2		= 0x02,
> +	MAX77843_MUIC_REG_INT3		= 0x03,
> +	MAX77843_MUIC_REG_STATUS1	= 0x04,
> +	MAX77843_MUIC_REG_STATUS2	= 0x05,
> +	MAX77843_MUIC_REG_STATUS3	= 0x06,
> +	MAX77843_MUIC_REG_INTMASK1	= 0x07,
> +	MAX77843_MUIC_REG_INTMASK2	= 0x08,
> +	MAX77843_MUIC_REG_INTMASK3	= 0x09,
> +	MAX77843_MUIC_REG_CDETCTRL1	= 0x0A,
> +	MAX77843_MUIC_REG_CDETCTRL2	= 0x0B,
> +	MAX77843_MUIC_REG_CONTROL1	= 0x0C,
> +	MAX77843_MUIC_REG_CONTROL2	= 0x0D,
> +	MAX77843_MUIC_REG_CONTROL3	= 0x0E,
> +	MAX77843_MUIC_REG_CONTROL4	= 0x16,
> +	MAX77843_MUIC_REG_HVCONTROL1	= 0x17,
> +	MAX77843_MUIC_REG_HVCONTROL2	= 0x18,
> +
> +	MAX77843_MUIC_REG_END,
> +};
> +
> +enum max77843_irq {
> +	/* Topsys: SYSTEM */
> +	MAX77843_SYS_IRQ_SYSINTSRC_SYSUVLO_INT,
> +	MAX77843_SYS_IRQ_SYSINTSRC_SYSOVLO_INT,
> +	MAX77843_SYS_IRQ_SYSINTSRC_TSHDN_INT,
> +	MAX77843_SYS_IRQ_SYSINTSRC_TM_INT,
> +
> +	/* Charger: CHG_INT */
> +	MAX77843_CHG_IRQ_CHG_INT_BYP_I,
> +	MAX77843_CHG_IRQ_CHG_INT_BATP_I,
> +	MAX77843_CHG_IRQ_CHG_INT_BAT_I,
> +	MAX77843_CHG_IRQ_CHG_INT_CHG_I,
> +	MAX77843_CHG_IRQ_CHG_INT_WCIN_I,
> +	MAX77843_CHG_IRQ_CHG_INT_CHGIN_I,
> +	MAX77843_CHG_IRQ_CHG_INT_AICL_I,
> +
> +	MAX77843_IRQ_NUM,
> +};
> +
> +enum max77843_irq_muic {
> +	/* MUIC: INT1 */
> +	MAX77843_MUIC_IRQ_INT1_ADC,
> +	MAX77843_MUIC_IRQ_INT1_ADCERROR,
> +	MAX77843_MUIC_IRQ_INT1_ADC1K,
> +
> +	/* MUIC: INT2 */
> +	MAX77843_MUIC_IRQ_INT2_CHGTYP,
> +	MAX77843_MUIC_IRQ_INT2_CHGDETRUN,
> +	MAX77843_MUIC_IRQ_INT2_DCDTMR,
> +	MAX77843_MUIC_IRQ_INT2_DXOVP,
> +	MAX77843_MUIC_IRQ_INT2_VBVOLT,
> +
> +	/* MUIC: INT3 */
> +	MAX77843_MUIC_IRQ_INT3_VBADC,
> +	MAX77843_MUIC_IRQ_INT3_VDNMON,
> +	MAX77843_MUIC_IRQ_INT3_DNRES,
> +	MAX77843_MUIC_IRQ_INT3_MPNACK,
> +	MAX77843_MUIC_IRQ_INT3_MRXBUFOW,
> +	MAX77843_MUIC_IRQ_INT3_MRXTRF,
> +	MAX77843_MUIC_IRQ_INT3_MRXPERR,
> +	MAX77843_MUIC_IRQ_INT3_MRXRDY,
> +
> +	MAX77843_MUIC_IRQ_NUM,
> +};
> +
> +/* MAX77843 interrupts */
> +#define MAX77843_SYS_IRQ_SYSUVLO_INT		BIT(0)
> +#define MAX77843_SYS_IRQ_SYSOVLO_INT		BIT(1)
> +#define MAX77843_SYS_IRQ_TSHDN_INT		BIT(2)
> +#define MAX77843_SYS_IRQ_TM_INT			BIT(3)
> +
> +/* Max77843 charger insterrupts */
> +#define MAX77843_CHG_BYP_I			BIT(0)
> +#define MAX77843_CHG_BATP_I			BIT(2)
> +#define MAX77843_CHG_BAT_I			BIT(3)
> +#define MAX77843_CHG_CHG_I			BIT(4)
> +#define MAX77843_CHG_WCIN_I			BIT(5)
> +#define MAX77843_CHG_CHGIN_I			BIT(6)
> +#define MAX77843_CHG_AICL_I			BIT(7)
> +
> +/* MAX77843 CHG_INT_OK register */
> +#define MAX77843_CHG_BYP_OK			BIT(0)
> +#define MAX77843_CHG_BATP_OK			BIT(2)
> +#define MAX77843_CHG_BAT_OK			BIT(3)
> +#define MAX77843_CHG_CHG_OK			BIT(4)
> +#define MAX77843_CHG_WCIN_OK			BIT(5)
> +#define MAX77843_CHG_CHGIN_OK			BIT(6)
> +#define MAX77843_CHG_AICL_OK			BIT(7)
> +
> +/* MAX77843 CHG_DETAILS_00 register */
> +#define MAX77843_CHG_BAT_DTLS			BIT(0)
> +
> +/* MAX77843 CHG_DETAILS_01 register */
> +#define MAX77843_CHG_DTLS_MASK			0x0f
> +#define MAX77843_CHG_PQ_MODE			0x00
> +#define MAX77843_CHG_CC_MODE			0x01
> +#define MAX77843_CHG_CV_MODE			0x02
> +#define MAX77843_CHG_TO_MODE			0x03
> +#define MAX77843_CHG_DO_MODE			0x04
> +#define MAX77843_CHG_HT_MODE			0x05
> +#define MAX77843_CHG_TF_MODE			0x06
> +#define MAX77843_CHG_TS_MODE			0x07
> +#define MAX77843_CHG_OFF_MODE			0x08
> +
> +#define MAX77843_CHG_BAT_DTLS_MASK		0xf0
> +#define MAX77843_CHG_NO_BAT			(0x00 << 4)
> +#define MAX77843_CHG_LOW_VOLT_BAT		(0x01 << 4)
> +#define MAX77843_CHG_LONG_BAT_TIME		(0x02 << 4)
> +#define MAX77843_CHG_OK_BAT			(0x03 << 4)
> +#define MAX77843_CHG_OK_LOW_VOLT_BAT		(0x04 << 4)
> +#define MAX77843_CHG_OVER_VOLT_BAT		(0x05 << 4)
> +#define MAX77843_CHG_OVER_CURRENT_BAT		(0x06 << 4)
> +
> +/* MAX77843 CHG_CNFG_00 register */
> +#define MAX77843_CHG_DISABLE			0x00
> +#define MAX77843_CHG_ENABLE			0x05
> +#define MAX77843_CHG_MASK			0x01
> +#define MAX77843_CHG_BUCK_MASK			0x04
> +
> +/* MAX77843 CHG_CNFG_01 register */
> +#define MAX77843_CHG_RESTART_THRESHOLD_100	0x00
> +#define MAX77843_CHG_RESTART_THRESHOLD_150	0x10
> +#define MAX77843_CHG_RESTART_THRESHOLD_200	0x20
> +#define MAX77843_CHG_RESTART_THRESHOLD_DISABLE	0x30
> +
> +/* MAX77843 CHG_CNFG_02 register */
> +#define MAX77843_CHG_FAST_CHG_CURRENT_MIN	100000
> +#define MAX77843_CHG_FAST_CHG_CURRENT_MAX	3150000
> +#define MAX77843_CHG_FAST_CHG_CURRENT_STEP	50000
> +#define MAX77843_CHG_FAST_CHG_CURRENT_MASK	0x3f
> +#define MAX77843_CHG_OTG_ILIMIT_500		(0x00 << 6)
> +#define MAX77843_CHG_OTG_ILIMIT_900		(0x01 << 6)
> +#define MAX77843_CHG_OTG_ILIMIT_1200		(0x02 << 6)
> +#define MAX77843_CHG_OTG_ILIMIT_1500		(0x03 << 6)
> +#define MAX77843_CHG_OTG_ILIMIT_MASK		0xc0
> +
> +/* MAX77843 CHG_CNFG_03 register */
> +#define MAX77843_CHG_TOP_OFF_CURRENT_MIN	125000
> +#define MAX77843_CHG_TOP_OFF_CURRENT_MAX	650000
> +#define MAX77843_CHG_TOP_OFF_CURRENT_STEP	75000
> +#define MAX77843_CHG_TOP_OFF_CURRENT_MASK	0x07
> +
> +/* MAX77843 CHG_CNFG_06 register */
> +#define MAX77843_CHG_WRITE_CAP_BLOCK		0x10
> +#define MAX77843_CHG_WRITE_CAP_UNBLOCK		0x0C
> +
> +/* MAX77843_CHG_CNFG_09_register */
> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN	100000
> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX	4000000
> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_REF	3367000
> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP	33000
> +
> +#define MAX77843_MUIC_ADC			BIT(0)
> +#define MAX77843_MUIC_ADCERROR			BIT(2)
> +#define MAX77843_MUIC_ADC1K			BIT(3)
> +
> +#define MAX77843_MUIC_CHGTYP			BIT(0)
> +#define MAX77843_MUIC_CHGDETRUN			BIT(1)
> +#define MAX77843_MUIC_DCDTMR			BIT(2)
> +#define MAX77843_MUIC_DXOVP			BIT(3)
> +#define MAX77843_MUIC_VBVOLT			BIT(4)
> +
> +#define MAX77843_MUIC_VBADC			BIT(0)
> +#define MAX77843_MUIC_VDNMON			BIT(1)
> +#define MAX77843_MUIC_DNRES			BIT(2)
> +#define MAX77843_MUIC_MPNACK			BIT(3)
> +#define MAX77843_MUIC_MRXBUFOW			BIT(4)
> +#define MAX77843_MUIC_MRXTRF			BIT(5)
> +#define MAX77843_MUIC_MRXPERR			BIT(6)
> +#define MAX77843_MUIC_MRXRDY			BIT(7)
> +
> +/* MAX77843 INTSRCMASK register */
> +#define MAX77843_INTSRCMASK_CHGR		0
> +#define MAX77843_INTSRCMASK_SYS			1
> +#define MAX77843_INTSRCMASK_FG			2
> +#define MAX77843_INTSRCMASK_MUIC		3
> +
> +#define MAX77843_INTSRCMASK_CHGR_MASK          BIT(MAX77843_INTSRCMASK_CHGR)
> +#define MAX77843_INTSRCMASK_SYS_MASK           BIT(MAX77843_INTSRCMASK_SYS)
> +#define MAX77843_INTSRCMASK_FG_MASK            BIT(MAX77843_INTSRCMASK_FG)
> +#define MAX77843_INTSRCMASK_MUIC_MASK          BIT(MAX77843_INTSRCMASK_MUIC)
> +
> +#define MAX77843_INTSRC_MASK_MASK \
> +		(MAX77843_INTSRCMASK_MUIC_MASK | MAX77843_INTSRCMASK_FG_MASK | \
> +		MAX77843_INTSRCMASK_SYS_MASK | MAX77843_INTSRCMASK_CHGR_MASK)
> +
> +/* MAX77843 STATUS register*/
> +#define STATUS1_ADC_SHIFT			0
> +#define STATUS1_ADCERROR_SHIFT			6
> +#define STATUS1_ADC1K_SHIFT			7
> +#define STATUS2_CHGTYP_SHIFT			0
> +#define STATUS2_CHGDETRUN_SHIFT			3
> +#define STATUS2_DCDTMR_SHIFT			4
> +#define STATUS2_DXOVP_SHIFT			5
> +#define STATUS2_VBVOLT_SHIFT			6
> +#define STATUS3_VBADC_SHIFT			0
> +#define STATUS3_VDNMON_SHIFT			4
> +#define STATUS3_DNRES_SHIFT			5
> +#define STATUS3_MPNACK_SHIFT			6
> +
> +#define MAX77843_MUIC_STATUS1_ADC_MASK		(0x1f << STATUS1_ADC_SHIFT)
> +#define MAX77843_MUIC_STATUS1_ADCERROR_MASK	BIT(STATUS1_ADCERROR_SHIFT)
> +#define MAX77843_MUIC_STATUS1_ADC1K_MASK	BIT(STATUS1_ADC1K_SHIFT)
> +#define MAX77843_MUIC_STATUS2_CHGTYP_MASK	(0x7 << STATUS2_CHGTYP_SHIFT)
> +#define MAX77843_MUIC_STATUS2_CHGDETRUN_MASK	BIT(STATUS2_CHGDETRUN_SHIFT)
> +#define MAX77843_MUIC_STATUS2_DCDTMR_MASK	BIT(STATUS2_DCDTMR_SHIFT)
> +#define MAX77843_MUIC_STATUS2_DXOVP_MASK	BIT(STATUS2_DXOVP_SHIFT)
> +#define MAX77843_MUIC_STATUS2_VBVOLT_MASK	BIT(STATUS2_VBVOLT_SHIFT)
> +#define MAX77843_MUIC_STATUS3_VBADC_MASK	(0xf << STATUS3_VBADC_SHIFT)
> +#define MAX77843_MUIC_STATUS3_VDNMON_MASK	BIT(STATUS3_VDNMON_SHIFT)
> +#define MAX77843_MUIC_STATUS3_DNRES_MASK	BIT(STATUS3_DNRES_SHIFT)
> +#define MAX77843_MUIC_STATUS3_MPNACK_MASK	BIT(STATUS3_MPNACK_SHIFT)
> +
> +/* MAX77843 CONTROL register */
> +#define CONTROL1_COMP1SW_SHIFT			0
> +#define CONTROL1_COMP2SW_SHIFT			3
> +#define CONTROL1_IDBEN_SHIFT			7
> +#define CONTROL2_LOWPWR_SHIFT			0
> +#define CONTROL2_ADCEN_SHIFT			1
> +#define CONTROL2_CPEN_SHIFT			2
> +#define CONTROL2_ACC_DET_SHIFT			5
> +#define CONTROL2_USBCPINT_SHIFT			6
> +#define CONTROL2_RCPS_SHIFT			7
> +#define CONTROL3_JIGSET_SHIFT			0
> +#define CONTROL4_ADCDBSET_SHIFT			0
> +#define CONTROL4_USBAUTO_SHIFT			4
> +#define CONTROL4_FCTAUTO_SHIFT			5
> +#define CONTROL4_ADCMODE_SHIFT			6
> +
> +#define MAX77843_MUIC_CONTROL1_COMP1SW_MASK	(0x7 << CONTROL1_COMP1SW_SHIFT)
> +#define MAX77843_MUIC_CONTROL1_COMP2SW_MASK	(0x7 << CONTROL1_COMP2SW_SHIFT)
> +#define MAX77843_MUIC_CONTROL1_IDBEN_MASK	BIT(CONTROL1_IDBEN_SHIFT)
> +#define MAX77843_MUIC_CONTROL2_LOWPWR_MASK	BIT(CONTROL2_LOWPWR_SHIFT)
> +#define MAX77843_MUIC_CONTROL2_ADCEN_MASK	BIT(CONTROL2_ADCEN_SHIFT)
> +#define MAX77843_MUIC_CONTROL2_CPEN_MASK	BIT(CONTROL2_CPEN_SHIFT)
> +#define MAX77843_MUIC_CONTROL2_ACC_DET_MASK	BIT(CONTROL2_ACC_DET_SHIFT)
> +#define MAX77843_MUIC_CONTROL2_USBCPINT_MASK	BIT(CONTROL2_USBCPINT_SHIFT)
> +#define MAX77843_MUIC_CONTROL2_RCPS_MASK	BIT(CONTROL2_RCPS_SHIFT)
> +#define MAX77843_MUIC_CONTROL3_JIGSET_MASK	(0x3 << CONTROL3_JIGSET_SHIFT)
> +#define MAX77843_MUIC_CONTROL4_ADCDBSET_MASK	(0x3 << CONTROL4_ADCDBSET_SHIFT)
> +#define MAX77843_MUIC_CONTROL4_USBAUTO_MASK	BIT(CONTROL4_USBAUTO_SHIFT)
> +#define MAX77843_MUIC_CONTROL4_FCTAUTO_MASK	BIT(CONTROL4_FCTAUTO_SHIFT)
> +#define MAX77843_MUIC_CONTROL4_ADCMODE_MASK	(0x3 << CONTROL4_ADCMODE_SHIFT)
> +
> +/* MAX77843 switch port */
> +#define MAX77843_SIWTH_PORT \
> +(MAX77843_MUIC_CONTROL1_COMP1SW_MASK | MAX77843_MUIC_CONTROL1_COMP2SW_MASK)
> +
> +#define MAX77843_SWITCH_OPEN \
> +		(0 << CONTROL1_COMP1SW_SHIFT | 0 << CONTROL1_COMP2SW_SHIFT)
> +#define MAX77843_SWITCH_USB \
> +		(1 << CONTROL1_COMP1SW_SHIFT | 1 << CONTROL1_COMP2SW_SHIFT)
> +#define MAX77843_SWITCH_AUDIO \
> +		(2 << CONTROL1_COMP1SW_SHIFT | 2 << CONTROL1_COMP2SW_SHIFT)
> +#define MAX77843_SWITCH_UART \
> +		(3 << CONTROL1_COMP1SW_SHIFT | 3 << CONTROL1_COMP2SW_SHIFT)
> +#define MAX77843_SWITCH_AUX_USB \
> +		(4 << CONTROL1_COMP1SW_SHIFT | 4 << CONTROL1_COMP2SW_SHIFT)
> +#define MAX77843_SWITCH_AUX_UART \
> +		(5 << CONTROL1_COMP1SW_SHIFT | 5 << CONTROL1_COMP2SW_SHIFT)
> +
> +/* MAX77843 SAFEOUT LDO Control register */
> +#define SAFEOUTCTRL_SAFEOUT1_SHIFT		0
> +#define SAFEOUTCTRL_SAFEOUT2_SHIFT		2
> +#define SAFEOUTCTRL_ENSAFEOUT1_SHIFT		6
> +#define SAFEOUTCTRL_ENSAFEOUT2_SHIFT		7
> +
> +#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1 \
> +		BIT(SAFEOUTCTRL_ENSAFEOUT1_SHIFT)
> +#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2 \
> +		BIT(SAFEOUTCTRL_ENSAFEOUT2_SHIFT)
> +#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK \
> +		(0x3 << SAFEOUTCTRL_SAFEOUT1_SHIFT)
> +#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK \
> +		(0x3 << SAFEOUTCTRL_SAFEOUT2_SHIFT)
> +
> +struct max77843 {
> +	struct device *dev;
> +
> +	struct i2c_client *i2c;
> +	struct i2c_client *i2c_chg;
> +	struct i2c_client *i2c_fuel;
> +	struct i2c_client *i2c_muic;
> +
> +	struct regmap *regmap;
> +	struct regmap *regmap_chg;
> +	struct regmap *regmap_fuel;
> +	struct regmap *regmap_muic;
> +
> +	struct regmap_irq_chip_data *irq_data;
> +	struct regmap_irq_chip_data *irq_data_chg;
> +	struct regmap_irq_chip_data *irq_data_fuel;
> +	struct regmap_irq_chip_data *irq_data_muic;
> +
> +	int irq;
> +};
> +#endif /* __MAX77843_H__ */
> 

Thanks,
Chanwoo Choi

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  6:55       ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  6:55 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

Hi Krzysztof,

2015년 01월 23일 15:32에 Krzysztof Kozlowski 이(가) 쓴 글:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
>> This patch adds MAX77843 core/irq driver to support PMIC,
>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>> LED and Haptic device.
>>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>>   drivers/mfd/Kconfig                  |   14 ++
>>   drivers/mfd/Makefile                 |    1 +
>>   drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>   include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>   4 files changed, 666 insertions(+)
>>   create mode 100644 drivers/mfd/max77843.c
>>   create mode 100644 include/linux/mfd/max77843-private.h
>>
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 2e6b731..0c67c79 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>            additional drivers must be enabled in order to use the functionality
>>            of the device.
>>
>> +config MFD_MAX77843
>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
>> +       depends on I2C=y
>> +       select MFD_CORE
>> +       select REGMAP_I2C
>> +       select REGMAP_IRQ
>> +       help
>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>> +         This driver provides common support for accessing the device;
>> +         additional drivers must be enabled in order to use the functionality
>> +         of the device.
>> +
>>   config MFD_MAX8907
>>          tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>          select MFD_CORE
>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> index 53467e2..fe4f75c 100644
>> --- a/drivers/mfd/Makefile
>> +++ b/drivers/mfd/Makefile
>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>>   obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>>   obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>>   obj-$(CONFIG_MFD_MAX77693)     += max77693.o
>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>>   obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>>   max8925-objs                   := max8925-core.o max8925-i2c.o
>>   obj-$(CONFIG_MFD_MAX8925)      += max8925.o
>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>> new file mode 100644
>> index 0000000..d7f8b76
>> --- /dev/null
>> +++ b/drivers/mfd/max77843.c
>> @@ -0,0 +1,241 @@
>> +/*
>> + * max77843.c - MFD core driver for the Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/mfd/max77843-private.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +
>> +static const struct mfd_cell max77843_devs[] = {
>> +       {
>> +               .name = "max77843-muic",
>> +               .of_compatible = "maxim,max77843-muic",
>> +       }, {
>> +               .name = "max77843-regulator",
>> +               .of_compatible = "maxim,max77843-regulator",
>> +       }, {
>> +               .name = "max77843-charger",
>> +               .of_compatible = "maxim,max77843-charger"
>> +       }, {
>> +               .name = "max77843-fuelgauge",
>> +               .of_compatible = "maxim,max77843-fuelgauge",
>> +       },
>> +};
>> +
>> +static const struct regmap_config max77843_charger_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_CHG_REG_END,
>> +};
>> +
>> +static const struct regmap_config max77843_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_SYS_REG_END,
>> +};
>> +
>> +static const struct regmap_irq max77843_irqs[] = {
>> +       /* TOPSYS interrupts */
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>> +};
>> +
>> +static const struct regmap_irq_chip max77843_irq_chip = {
>> +       .name           = "max77843",
>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
>> +       .mask_invert    = false,
>> +       .num_regs       = 1,
>> +       .irqs           = max77843_irqs,
>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
>> +};
>> +
>> +static int max77843_chg_init(struct max77843 *max77843)
>> +{
> Could this function be moved to the charger driver? This way the
> driver will manage its own resources instead of depending on parent
> MFD driver.
>
>> +       int ret;
>> +
>> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
>> +       if (!max77843->i2c_chg) {
>> +               dev_err(&max77843->i2c->dev,
>> +                               "Cannot allocate I2C device for Charger\n");
>> +               return PTR_ERR(max77843->i2c_chg);
>> +       }
>> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
>> +
>> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
>> +                       &max77843_charger_regmap_config);
>> +       if (IS_ERR(max77843->regmap_chg)) {
>> +               ret = PTR_ERR(max77843->regmap_chg);
>> +               goto err_chg_i2c;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_chg_i2c:
>> +       i2c_unregister_device(max77843->i2c_chg);
>> +
>> +       return ret;
>> +}
>> +
>> +static int max77843_probe(struct i2c_client *i2c,
>> +                                       const struct i2c_device_id *id)
>> +{
>> +       struct max77843 *max77843;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
>> +       if (!max77843)
>> +               return -ENOMEM;
>> +
>> +       i2c_set_clientdata(i2c, max77843);
>> +       max77843->dev = &i2c->dev;
>> +       max77843->i2c = i2c;
>> +       max77843->irq = i2c->irq;
>> +
>> +       max77843->regmap = devm_regmap_init_i2c(i2c,
>> +                       &max77843_regmap_config);
>> +       if (IS_ERR(max77843->regmap)) {
>> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
>> +               return PTR_ERR(max77843->regmap);
>> +       }
>> +
>> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
>> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
>> +                       0, &max77843_irq_chip, &max77843->irq_data);
> Why shared IRQ?

This IRQ shared with submodules.
you can see another IRQ register process in extcon-max77843 driver.

>
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = regmap_read(max77843->regmap,
>> +                       MAX77843_SYS_REG_PMICID, &reg_data);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
>> +               goto err_pmic_id;
>> +       }
>> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
>> +
>> +       ret = max77843_chg_init(max77843);
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to init Charger\n");
>> +               goto err_pmic_id;
>> +       }
>> +
>> +       ret = regmap_update_bits(max77843->regmap,
>> +                       MAX77843_SYS_REG_INTSRCMASK,
>> +                       MAX77843_INTSRC_MASK_MASK,
>> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> s/sourece/source/

I will fix typo in next version.

>
> Best regards,
> Krzysztof
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

Thanks to review my patch.
Jaewon Kim

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  6:55       ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  6:55 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

Hi Krzysztof,

2015년 01월 23일 15:32에 Krzysztof Kozlowski 이(가) 쓴 글:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>:
>> This patch adds MAX77843 core/irq driver to support PMIC,
>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>> LED and Haptic device.
>>
>> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>>   drivers/mfd/Kconfig                  |   14 ++
>>   drivers/mfd/Makefile                 |    1 +
>>   drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>   include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>   4 files changed, 666 insertions(+)
>>   create mode 100644 drivers/mfd/max77843.c
>>   create mode 100644 include/linux/mfd/max77843-private.h
>>
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 2e6b731..0c67c79 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>            additional drivers must be enabled in order to use the functionality
>>            of the device.
>>
>> +config MFD_MAX77843
>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
>> +       depends on I2C=y
>> +       select MFD_CORE
>> +       select REGMAP_I2C
>> +       select REGMAP_IRQ
>> +       help
>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>> +         This driver provides common support for accessing the device;
>> +         additional drivers must be enabled in order to use the functionality
>> +         of the device.
>> +
>>   config MFD_MAX8907
>>          tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>          select MFD_CORE
>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> index 53467e2..fe4f75c 100644
>> --- a/drivers/mfd/Makefile
>> +++ b/drivers/mfd/Makefile
>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>>   obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>>   obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>>   obj-$(CONFIG_MFD_MAX77693)     += max77693.o
>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>>   obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>>   max8925-objs                   := max8925-core.o max8925-i2c.o
>>   obj-$(CONFIG_MFD_MAX8925)      += max8925.o
>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>> new file mode 100644
>> index 0000000..d7f8b76
>> --- /dev/null
>> +++ b/drivers/mfd/max77843.c
>> @@ -0,0 +1,241 @@
>> +/*
>> + * max77843.c - MFD core driver for the Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + * Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/mfd/max77843-private.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +
>> +static const struct mfd_cell max77843_devs[] = {
>> +       {
>> +               .name = "max77843-muic",
>> +               .of_compatible = "maxim,max77843-muic",
>> +       }, {
>> +               .name = "max77843-regulator",
>> +               .of_compatible = "maxim,max77843-regulator",
>> +       }, {
>> +               .name = "max77843-charger",
>> +               .of_compatible = "maxim,max77843-charger"
>> +       }, {
>> +               .name = "max77843-fuelgauge",
>> +               .of_compatible = "maxim,max77843-fuelgauge",
>> +       },
>> +};
>> +
>> +static const struct regmap_config max77843_charger_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_CHG_REG_END,
>> +};
>> +
>> +static const struct regmap_config max77843_regmap_config = {
>> +       .reg_bits       = 8,
>> +       .val_bits       = 8,
>> +       .max_register   = MAX77843_SYS_REG_END,
>> +};
>> +
>> +static const struct regmap_irq max77843_irqs[] = {
>> +       /* TOPSYS interrupts */
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>> +};
>> +
>> +static const struct regmap_irq_chip max77843_irq_chip = {
>> +       .name           = "max77843",
>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
>> +       .mask_invert    = false,
>> +       .num_regs       = 1,
>> +       .irqs           = max77843_irqs,
>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
>> +};
>> +
>> +static int max77843_chg_init(struct max77843 *max77843)
>> +{
> Could this function be moved to the charger driver? This way the
> driver will manage its own resources instead of depending on parent
> MFD driver.
>
>> +       int ret;
>> +
>> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
>> +       if (!max77843->i2c_chg) {
>> +               dev_err(&max77843->i2c->dev,
>> +                               "Cannot allocate I2C device for Charger\n");
>> +               return PTR_ERR(max77843->i2c_chg);
>> +       }
>> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
>> +
>> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
>> +                       &max77843_charger_regmap_config);
>> +       if (IS_ERR(max77843->regmap_chg)) {
>> +               ret = PTR_ERR(max77843->regmap_chg);
>> +               goto err_chg_i2c;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_chg_i2c:
>> +       i2c_unregister_device(max77843->i2c_chg);
>> +
>> +       return ret;
>> +}
>> +
>> +static int max77843_probe(struct i2c_client *i2c,
>> +                                       const struct i2c_device_id *id)
>> +{
>> +       struct max77843 *max77843;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
>> +       if (!max77843)
>> +               return -ENOMEM;
>> +
>> +       i2c_set_clientdata(i2c, max77843);
>> +       max77843->dev = &i2c->dev;
>> +       max77843->i2c = i2c;
>> +       max77843->irq = i2c->irq;
>> +
>> +       max77843->regmap = devm_regmap_init_i2c(i2c,
>> +                       &max77843_regmap_config);
>> +       if (IS_ERR(max77843->regmap)) {
>> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
>> +               return PTR_ERR(max77843->regmap);
>> +       }
>> +
>> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
>> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
>> +                       0, &max77843_irq_chip, &max77843->irq_data);
> Why shared IRQ?

This IRQ shared with submodules.
you can see another IRQ register process in extcon-max77843 driver.

>
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = regmap_read(max77843->regmap,
>> +                       MAX77843_SYS_REG_PMICID, &reg_data);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
>> +               goto err_pmic_id;
>> +       }
>> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
>> +
>> +       ret = max77843_chg_init(max77843);
>> +       if (ret) {
>> +               dev_err(&i2c->dev, "Failed to init Charger\n");
>> +               goto err_pmic_id;
>> +       }
>> +
>> +       ret = regmap_update_bits(max77843->regmap,
>> +                       MAX77843_SYS_REG_INTSRCMASK,
>> +                       MAX77843_INTSRC_MASK_MASK,
>> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
>> +       if (ret < 0) {
>> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> s/sourece/source/

I will fix typo in next version.

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

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

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

* Re: [PATCH 3/6] power: max77843_charger: Add Max77843 charger device driver
  2015-01-23  5:02   ` Jaewon Kim
  (?)
@ 2015-01-23  7:04   ` Krzysztof Kozłowski
  2015-01-23  7:28       ` Beomho Seo
  -1 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Kozłowski @ 2015-01-23  7:04 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
> From: Beomho Seo <beomho.seo@samsung.com>
>
> This patch adds device driver of max77843 charger. This driver provide
> initialize each charging mode(e.g. fast charge, top-off mode and constant
> charging mode so on.). Additionally, control charging paramters to use
> i2c interface.
>
> Cc: Sebastian Reichel <sre@kernel.org>
> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> ---
>  drivers/power/Kconfig            |    7 +
>  drivers/power/Makefile           |    1 +
>  drivers/power/max77843_charger.c |  506 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 514 insertions(+)
>  create mode 100644 drivers/power/max77843_charger.c
>
> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
> index 0108c2a..a054a28 100644
> --- a/drivers/power/Kconfig
> +++ b/drivers/power/Kconfig
> @@ -332,6 +332,13 @@ config CHARGER_MAX14577
>           Say Y to enable support for the battery charger control sysfs and
>           platform data of MAX14577/77836 MUICs.
>
> +config CHARGER_MAX77843
> +       tristate "Maxim MAX77843 battery charger driver"
> +       depends on MFD_MAX77843
> +       help
> +         Say Y to enable support for the battery charger control sysfs and
> +         platform data of MAX77843
> +
>  config CHARGER_MAX8997
>         tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
>         depends on MFD_MAX8997 && REGULATOR_MAX8997
> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
> index dfa8942..212c6a2 100644
> --- a/drivers/power/Makefile
> +++ b/drivers/power/Makefile
> @@ -50,6 +50,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
>  obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
>  obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
>  obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
> +obj-$(CONFIG_CHARGER_MAX77843) += max77843_charger.o
>  obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
>  obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
>  obj-$(CONFIG_CHARGER_BQ2415X)  += bq2415x_charger.o
> diff --git a/drivers/power/max77843_charger.c b/drivers/power/max77843_charger.c
> new file mode 100644
> index 0000000..317b2cc
> --- /dev/null
> +++ b/drivers/power/max77843_charger.c
> @@ -0,0 +1,506 @@
> +/*
> + * Charger driver for Maxim MAX77843
> + *
> + * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
> + * Author: Beomho Seo <beomho.seo@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published bythe Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/mfd/max77843-private.h>
> +
> +struct max77843_charger_info {
> +       u32 fast_charge_uamp;
> +       u32 top_off_uamp;
> +       u32 input_uamp_limit;
> +};
> +
> +struct max77843_charger {
> +       struct device           *dev;
> +       struct max77843         *max77843;
> +       struct i2c_client       *client;
> +       struct regmap           *regmap;
> +       struct power_supply     psy;
> +
> +       struct max77843_charger_info    *info;
> +};

Why creating two separate structures?

> +
> +static int max77843_charger_get_max_current(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       int ret, val = 0;
> +       unsigned int reg_data;
> +
> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_09, &reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to read charger register\n");
> +               return ret;
> +       }
> +
> +       if (reg_data <= 0x03) {
> +               val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
> +       } else if (reg_data >= 0x78) {
> +               val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX;
> +       } else {
> +               val = reg_data / 3;
> +               if (reg_data % 3 == 0)
> +                       val *= 100000;
> +               else if (reg_data % 3 == 1)
> +                       val = val * 100000 + 33000;
> +               else
> +                       val = val * 100000 + 67000;
> +       }
> +
> +       return val;
> +}
> +
> +static int max77843_charger_get_now_current(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       int ret, val = 0;
> +       unsigned int reg_data;
> +
> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to read charger register\n");

This error log shows up in many places. Please print also error code.

Additionally I think it could be useful to print also details about
register which failed. Currently user would not know which register
access failed. Consider adding short description like "Failed to read
current charger register: %d...". However I do not insist on this so
it is up to you.

> +               return ret;
> +       }
> +
> +       reg_data &= MAX77843_CHG_FAST_CHG_CURRENT_MASK;
> +
> +       if (reg_data <= 0x02)
> +               val = MAX77843_CHG_FAST_CHG_CURRENT_MIN;
> +       else if (reg_data >= 0x3f)
> +               val = MAX77843_CHG_FAST_CHG_CURRENT_MAX;
> +       else
> +               val = reg_data * MAX77843_CHG_FAST_CHG_CURRENT_STEP;
> +
> +       return val;
> +}
> +
> +static int max77843_charger_get_online(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       int ret, val = 0;
> +       unsigned int reg_data;
> +
> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_INT_OK, &reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to read charger register\n");
> +               return ret;
> +       }
> +
> +       if (reg_data & MAX77843_CHG_CHGIN_OK)
> +               val = true;
> +       else
> +               val = false;
> +
> +       return val;
> +}
> +
> +static int max77843_charger_get_present(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       int ret, val = 0;
> +       unsigned int reg_data;
> +
> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_00, &reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to read charger register\n");
> +               return ret;
> +       }
> +
> +       if (reg_data & MAX77843_CHG_BAT_DTLS)
> +               val = false;
> +       else
> +               val = true;
> +
> +       return val;
> +}
> +
> +static int max77843_charger_get_health(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       int ret, val = POWER_SUPPLY_HEALTH_UNKNOWN;
> +       unsigned int reg_data;
> +
> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01, &reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to read charger register\n");
> +               return ret;
> +       }
> +
> +       reg_data &= MAX77843_CHG_BAT_DTLS_MASK;
> +
> +       switch (reg_data) {
> +       case MAX77843_CHG_NO_BAT:
> +               val = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
> +               break;
> +       case MAX77843_CHG_LOW_VOLT_BAT:
> +       case MAX77843_CHG_OK_BAT:
> +       case MAX77843_CHG_OK_LOW_VOLT_BAT:
> +               val = POWER_SUPPLY_HEALTH_GOOD;
> +               break;
> +       case MAX77843_CHG_LONG_BAT_TIME:
> +               val = POWER_SUPPLY_HEALTH_DEAD;
> +               break;
> +       case MAX77843_CHG_OVER_VOLT_BAT:
> +       case MAX77843_CHG_OVER_CURRENT_BAT:
> +               val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
> +               break;
> +       default:
> +               val = POWER_SUPPLY_HEALTH_UNKNOWN;
> +               break;
> +       }
> +
> +       return val;
> +}
> +
> +static int max77843_charger_get_status(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       int ret, val = 0;
> +       unsigned int reg_data;
> +
> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01, &reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to read charger register\n");
> +               return ret;
> +       }
> +
> +       reg_data &= MAX77843_CHG_DTLS_MASK;
> +
> +       switch (reg_data) {
> +       case MAX77843_CHG_PQ_MODE:
> +       case MAX77843_CHG_CC_MODE:
> +       case MAX77843_CHG_CV_MODE:
> +               val = POWER_SUPPLY_STATUS_CHARGING;
> +               break;
> +       case MAX77843_CHG_TO_MODE:
> +       case MAX77843_CHG_DO_MODE:
> +               val = POWER_SUPPLY_STATUS_FULL;
> +               break;
> +       case MAX77843_CHG_HT_MODE:
> +       case MAX77843_CHG_TF_MODE:
> +       case MAX77843_CHG_TS_MODE:
> +               val = POWER_SUPPLY_STATUS_NOT_CHARGING;
> +               break;
> +       case MAX77843_CHG_OFF_MODE:
> +               val = POWER_SUPPLY_STATUS_DISCHARGING;
> +               break;
> +       default:
> +               val = POWER_SUPPLY_STATUS_UNKNOWN;
> +               break;
> +       }
> +
> +       return val;
> +}
> +
> +static const char *model_name = "MAX77843";
> +static const char *manufacturer = "Maxim Integrated";
> +
> +static int max77843_charger_get_property(struct power_supply *psy,
> +               enum power_supply_property psp,
> +               union power_supply_propval *val)
> +{
> +       struct max77843_charger *charger = container_of(psy,
> +                               struct max77843_charger, psy);
> +
> +       switch (psp) {
> +       case POWER_SUPPLY_PROP_STATUS:
> +               val->intval = max77843_charger_get_status(charger);
> +               break;
> +       case POWER_SUPPLY_PROP_HEALTH:
> +               val->intval = max77843_charger_get_health(charger);
> +               break;
> +       case POWER_SUPPLY_PROP_PRESENT:
> +               val->intval = max77843_charger_get_present(charger);
> +               break;
> +       case POWER_SUPPLY_PROP_ONLINE:
> +               val->intval = max77843_charger_get_online(charger);
> +               break;
> +       case POWER_SUPPLY_PROP_CURRENT_NOW:
> +               val->intval = max77843_charger_get_now_current(charger);
> +               break;
> +       case POWER_SUPPLY_PROP_CURRENT_MAX:
> +               val->intval = max77843_charger_get_max_current(charger);
> +               break;
> +       case POWER_SUPPLY_PROP_MODEL_NAME:
> +               val->strval =  model_name;
> +               break;
> +       case POWER_SUPPLY_PROP_MANUFACTURER:
> +               val->strval = manufacturer;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static enum power_supply_property max77843_charger_props[] = {
> +       POWER_SUPPLY_PROP_STATUS,
> +       POWER_SUPPLY_PROP_HEALTH,
> +       POWER_SUPPLY_PROP_PRESENT,
> +       POWER_SUPPLY_PROP_ONLINE,
> +       POWER_SUPPLY_PROP_CURRENT_NOW,
> +       POWER_SUPPLY_PROP_CURRENT_MAX,
> +       POWER_SUPPLY_PROP_MODEL_NAME,
> +       POWER_SUPPLY_PROP_MANUFACTURER,
> +};
> +
> +static int max77843_charger_init_current_limit(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       struct max77843_charger_info *info = charger->info;
> +       unsigned int input_uamp_limit = info->input_uamp_limit;
> +       int ret;
> +       unsigned int reg_data, val;
> +
> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
> +                       MAX77843_CHG_OTG_ILIMIT_MASK,
> +                       MAX77843_CHG_OTG_ILIMIT_900);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to write configure register\n");

Same as in case of "read" operation failures - please print also error code.

> +               return ret;
> +       }
> +
> +       if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN) {
> +               reg_data = 0x03;
> +       } else if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX) {
> +               reg_data = 0x78;
> +       } else {
> +               if (input_uamp_limit < MAX77843_CHG_INPUT_CURRENT_LIMIT_REF)
> +                       val = 0x03;
> +               else
> +                       val = 0x02;
> +
> +               input_uamp_limit -= MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
> +               input_uamp_limit /= MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP;
> +               reg_data = val + input_uamp_limit;
> +       }
> +
> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to write configure register\n");
> +               return ret;
> +       }
> +
> +       return 0;

Could you merge it into:

       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
       if (ret)
              dev_err(charger->dev, "Failed to write configure register\n");
       return ret;


> +
> +static int max77843_charger_init_top_off(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       struct max77843_charger_info *info = charger->info;
> +       unsigned int top_off_uamp = info->top_off_uamp;
> +       int ret;
> +       unsigned int reg_data;
> +
> +       if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MIN) {
> +               reg_data = 0x00;
> +       } else if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MAX) {
> +               reg_data = 0x07;
> +       } else {
> +               top_off_uamp -= MAX77843_CHG_TOP_OFF_CURRENT_MIN;
> +               top_off_uamp /= MAX77843_CHG_TOP_OFF_CURRENT_STEP;
> +               reg_data = top_off_uamp;
> +       }
> +
> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_03,
> +                       MAX77843_CHG_TOP_OFF_CURRENT_MASK, reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to write configure register\n");
> +               return ret;
> +       }
> +
> +       return 0;

Ditto

> +}
> +
> +static int max77843_charger_init_fast_charge(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       struct max77843_charger_info *info = charger->info;
> +       unsigned int fast_charge_uamp = info->fast_charge_uamp;
> +       int ret;
> +       unsigned int reg_data;
> +
> +       if (fast_charge_uamp < info->input_uamp_limit) {
> +               reg_data = 0x09;
> +       } else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MIN) {
> +               reg_data = 0x02;
> +       } else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MAX) {
> +               reg_data = 0x3f;
> +       } else {
> +               fast_charge_uamp -= MAX77843_CHG_FAST_CHG_CURRENT_MIN;
> +               fast_charge_uamp /= MAX77843_CHG_FAST_CHG_CURRENT_STEP;
> +               reg_data = 0x02 + fast_charge_uamp;
> +       }
> +
> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
> +                       MAX77843_CHG_FAST_CHG_CURRENT_MASK, reg_data);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to write configure register\n");
> +               return ret;
> +       }
> +
> +       return 0;

Ditto

> +}
> +
> +static int max77843_charger_init(struct max77843_charger *charger)
> +{
> +       struct regmap *regmap = charger->regmap;
> +       int ret;
> +
> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_06,
> +                       MAX77843_CHG_WRITE_CAP_UNBLOCK);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to write configure register\n");
> +               return ret;
> +       }
> +
> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_01,
> +                       MAX77843_CHG_RESTART_THRESHOLD_DISABLE);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to write configure register\n");
> +               return ret;
> +       }
> +
> +       ret = max77843_charger_init_fast_charge(charger);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to set fast charge mode.\n");
> +               return ret;
> +       }
> +
> +       ret = max77843_charger_init_top_off(charger);
> +       if (ret) {
> +               dev_err(charger->dev, "Failed to set top off charge mode.\n");
> +               return ret;
> +       }
> +
> +       ret = max77843_charger_init_current_limit(charger);
> +

Why this return value is ignored?

> +       return 0;
> +}
> +
> +static struct max77843_charger_info *max77843_charger_dt_init(
> +               struct platform_device *pdev)
> +{
> +       struct max77843_charger_info *info;
> +       struct device_node *np = pdev->dev.of_node;
> +       int ret;
> +
> +       if (!np) {
> +               dev_err(&pdev->dev, "No charger OF node\n");
> +               return ERR_PTR(-EINVAL);
> +       }
> +
> +       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
> +       if (!info)
> +               return ERR_PTR(-ENOMEM);
> +
> +       ret = of_property_read_u32(np, "maxim,fast-charge-uamp",
> +                       &info->fast_charge_uamp);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Cannot parse fast charge current.\n");
> +               return ERR_PTR(ret);
> +       }
> +
> +       ret = of_property_read_u32(np, "maxim,top-off-uamp",
> +                       &info->top_off_uamp);
> +       if (ret) {
> +               dev_err(&pdev->dev,
> +                       "Cannot parse primary charger termination voltage.\n");
> +               return ERR_PTR(ret);
> +       }
> +
> +       ret = of_property_read_u32(np, "maxim,input-uamp-limit",
> +                       &info->input_uamp_limit);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Cannot parse input current limit value\n");
> +               return ERR_PTR(ret);
> +       }
> +
> +       return info;
> +}
> +
> +static int max77843_charger_probe(struct platform_device *pdev)
> +{
> +       struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
> +       struct max77843_charger *charger;
> +       int ret;
> +
> +       charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
> +       if (!charger)
> +               return -ENOMEM;
> +
> +       platform_set_drvdata(pdev, charger);
> +       charger->dev = &pdev->dev;
> +       charger->max77843 = max77843;
> +       charger->client = max77843->i2c_chg;
> +       charger->regmap = max77843->regmap_chg;
> +
> +       charger->info = max77843_charger_dt_init(pdev);
> +       if (IS_ERR_OR_NULL(charger->info)) {
> +               ret = PTR_ERR(charger->info);
> +               goto err_i2c;
> +       }
> +
> +       charger->psy.name       = "max77843-charger";
> +       charger->psy.type       = POWER_SUPPLY_TYPE_MAINS;
> +       charger->psy.get_property       = max77843_charger_get_property;
> +       charger->psy.properties         = max77843_charger_props;
> +       charger->psy.num_properties     = ARRAY_SIZE(max77843_charger_props);
> +
> +       ret = max77843_charger_init(charger);
> +       if (ret)
> +               goto err_i2c;
> +
> +       ret = power_supply_register(&pdev->dev, &charger->psy);
> +       if (ret) {
> +               dev_err(&pdev->dev, "Failed  to register power supply\n");
> +               goto err_i2c;
> +       }
> +
> +       return 0;
> +
> +err_i2c:
> +       i2c_unregister_device(charger->client);

This seems complicated. The MFD registers the i2c dummy for charger...
and sometimes charger driver unregisters it and sometimes not. The
ownership should be in one place: probably in charger driver... but I
asked about this in another thread so lets discuss it there.

Best regards,
Krzysztof

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  7:05         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2015-01-23  7:05 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

On pią, 2015-01-23 at 15:55 +0900, Jaewon Kim wrote:
> Hi Krzysztof,
> 
> 2015년 01월 23일 15:32에 Krzysztof Kozlowski 이(가) 쓴 글:
> > 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
> >> This patch adds MAX77843 core/irq driver to support PMIC,
> >> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
> >> LED and Haptic device.
> >>
> >> Cc: Lee Jones <lee.jones@linaro.org>
> >> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> >> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> >> ---
> >>   drivers/mfd/Kconfig                  |   14 ++
> >>   drivers/mfd/Makefile                 |    1 +
> >>   drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
> >>   include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
> >>   4 files changed, 666 insertions(+)
> >>   create mode 100644 drivers/mfd/max77843.c
> >>   create mode 100644 include/linux/mfd/max77843-private.h
> >>
> >> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >> index 2e6b731..0c67c79 100644
> >> --- a/drivers/mfd/Kconfig
> >> +++ b/drivers/mfd/Kconfig
> >> @@ -442,6 +442,20 @@ config MFD_MAX77693
> >>            additional drivers must be enabled in order to use the functionality
> >>            of the device.
> >>
> >> +config MFD_MAX77843
> >> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
> >> +       depends on I2C=y
> >> +       select MFD_CORE
> >> +       select REGMAP_I2C
> >> +       select REGMAP_IRQ
> >> +       help
> >> +         Say yes here to add support for Maxim Semiconductor MAX77843.
> >> +         This is companion Power Management IC with LEDs, Haptic, Charger,
> >> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
> >> +         This driver provides common support for accessing the device;
> >> +         additional drivers must be enabled in order to use the functionality
> >> +         of the device.
> >> +
> >>   config MFD_MAX8907
> >>          tristate "Maxim Semiconductor MAX8907 PMIC Support"
> >>          select MFD_CORE
> >> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> >> index 53467e2..fe4f75c 100644
> >> --- a/drivers/mfd/Makefile
> >> +++ b/drivers/mfd/Makefile
> >> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
> >>   obj-$(CONFIG_MFD_MAX14577)     += max14577.o
> >>   obj-$(CONFIG_MFD_MAX77686)     += max77686.o
> >>   obj-$(CONFIG_MFD_MAX77693)     += max77693.o
> >> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
> >>   obj-$(CONFIG_MFD_MAX8907)      += max8907.o
> >>   max8925-objs                   := max8925-core.o max8925-i2c.o
> >>   obj-$(CONFIG_MFD_MAX8925)      += max8925.o
> >> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
> >> new file mode 100644
> >> index 0000000..d7f8b76
> >> --- /dev/null
> >> +++ b/drivers/mfd/max77843.c
> >> @@ -0,0 +1,241 @@
> >> +/*
> >> + * max77843.c - MFD core driver for the Maxim MAX77843
> >> + *
> >> + * Copyright (C) 2014 Samsung Electrnoics
> >> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#include <linux/err.h>
> >> +#include <linux/i2c.h>
> >> +#include <linux/init.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/module.h>
> >> +#include <linux/mfd/core.h>
> >> +#include <linux/mfd/max77843-private.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/platform_device.h>
> >> +
> >> +static const struct mfd_cell max77843_devs[] = {
> >> +       {
> >> +               .name = "max77843-muic",
> >> +               .of_compatible = "maxim,max77843-muic",
> >> +       }, {
> >> +               .name = "max77843-regulator",
> >> +               .of_compatible = "maxim,max77843-regulator",
> >> +       }, {
> >> +               .name = "max77843-charger",
> >> +               .of_compatible = "maxim,max77843-charger"
> >> +       }, {
> >> +               .name = "max77843-fuelgauge",
> >> +               .of_compatible = "maxim,max77843-fuelgauge",
> >> +       },
> >> +};
> >> +
> >> +static const struct regmap_config max77843_charger_regmap_config = {
> >> +       .reg_bits       = 8,
> >> +       .val_bits       = 8,
> >> +       .max_register   = MAX77843_CHG_REG_END,
> >> +};
> >> +
> >> +static const struct regmap_config max77843_regmap_config = {
> >> +       .reg_bits       = 8,
> >> +       .val_bits       = 8,
> >> +       .max_register   = MAX77843_SYS_REG_END,
> >> +};
> >> +
> >> +static const struct regmap_irq max77843_irqs[] = {
> >> +       /* TOPSYS interrupts */
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
> >> +};
> >> +
> >> +static const struct regmap_irq_chip max77843_irq_chip = {
> >> +       .name           = "max77843",
> >> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
> >> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
> >> +       .mask_invert    = false,
> >> +       .num_regs       = 1,
> >> +       .irqs           = max77843_irqs,
> >> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
> >> +};
> >> +
> >> +static int max77843_chg_init(struct max77843 *max77843)
> >> +{
> > Could this function be moved to the charger driver? This way the
> > driver will manage its own resources instead of depending on parent
> > MFD driver.
> >
> >> +       int ret;
> >> +
> >> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
> >> +       if (!max77843->i2c_chg) {
> >> +               dev_err(&max77843->i2c->dev,
> >> +                               "Cannot allocate I2C device for Charger\n");
> >> +               return PTR_ERR(max77843->i2c_chg);
> >> +       }
> >> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
> >> +
> >> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
> >> +                       &max77843_charger_regmap_config);
> >> +       if (IS_ERR(max77843->regmap_chg)) {
> >> +               ret = PTR_ERR(max77843->regmap_chg);
> >> +               goto err_chg_i2c;
> >> +       }
> >> +
> >> +       return 0;
> >> +
> >> +err_chg_i2c:
> >> +       i2c_unregister_device(max77843->i2c_chg);
> >> +
> >> +       return ret;
> >> +}
> >> +
> >> +static int max77843_probe(struct i2c_client *i2c,
> >> +                                       const struct i2c_device_id *id)
> >> +{
> >> +       struct max77843 *max77843;
> >> +       int ret;
> >> +       unsigned int reg_data;
> >> +
> >> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
> >> +       if (!max77843)
> >> +               return -ENOMEM;
> >> +
> >> +       i2c_set_clientdata(i2c, max77843);
> >> +       max77843->dev = &i2c->dev;
> >> +       max77843->i2c = i2c;
> >> +       max77843->irq = i2c->irq;
> >> +
> >> +       max77843->regmap = devm_regmap_init_i2c(i2c,
> >> +                       &max77843_regmap_config);
> >> +       if (IS_ERR(max77843->regmap)) {
> >> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
> >> +               return PTR_ERR(max77843->regmap);
> >> +       }
> >> +
> >> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
> >> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> >> +                       0, &max77843_irq_chip, &max77843->irq_data);
> > Why shared IRQ?
> 
> This IRQ shared with submodules.
> you can see another IRQ register process in extcon-max77843 driver.

Right, I found it later.

> 
> >
> >> +       if (ret) {
> >> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
> >> +               return ret;
> >> +       }
> >> +
> >> +       ret = regmap_read(max77843->regmap,
> >> +                       MAX77843_SYS_REG_PMICID, &reg_data);
> >> +       if (ret < 0) {
> >> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
> >> +               goto err_pmic_id;
> >> +       }
> >> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
> >> +
> >> +       ret = max77843_chg_init(max77843);
> >> +       if (ret) {
> >> +               dev_err(&i2c->dev, "Failed to init Charger\n");
> >> +               goto err_pmic_id;
> >> +       }
> >> +
> >> +       ret = regmap_update_bits(max77843->regmap,
> >> +                       MAX77843_SYS_REG_INTSRCMASK,
> >> +                       MAX77843_INTSRC_MASK_MASK,
> >> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
> >> +       if (ret < 0) {
> >> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> > s/sourece/source/
> 
> I will fix typo in next version.
> 
> >
> > Best regards,
> > Krzysztof
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> Thanks to review my patch.
> Jaewon Kim


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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23  7:05         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 41+ messages in thread
From: Krzysztof Kozlowski @ 2015-01-23  7:05 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

On pią, 2015-01-23 at 15:55 +0900, Jaewon Kim wrote:
> Hi Krzysztof,
> 
> 2015년 01월 23일 15:32에 Krzysztof Kozlowski 이(가) 쓴 글:
> > 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>:
> >> This patch adds MAX77843 core/irq driver to support PMIC,
> >> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
> >> LED and Haptic device.
> >>
> >> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> >> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> ---
> >>   drivers/mfd/Kconfig                  |   14 ++
> >>   drivers/mfd/Makefile                 |    1 +
> >>   drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
> >>   include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
> >>   4 files changed, 666 insertions(+)
> >>   create mode 100644 drivers/mfd/max77843.c
> >>   create mode 100644 include/linux/mfd/max77843-private.h
> >>
> >> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >> index 2e6b731..0c67c79 100644
> >> --- a/drivers/mfd/Kconfig
> >> +++ b/drivers/mfd/Kconfig
> >> @@ -442,6 +442,20 @@ config MFD_MAX77693
> >>            additional drivers must be enabled in order to use the functionality
> >>            of the device.
> >>
> >> +config MFD_MAX77843
> >> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
> >> +       depends on I2C=y
> >> +       select MFD_CORE
> >> +       select REGMAP_I2C
> >> +       select REGMAP_IRQ
> >> +       help
> >> +         Say yes here to add support for Maxim Semiconductor MAX77843.
> >> +         This is companion Power Management IC with LEDs, Haptic, Charger,
> >> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
> >> +         This driver provides common support for accessing the device;
> >> +         additional drivers must be enabled in order to use the functionality
> >> +         of the device.
> >> +
> >>   config MFD_MAX8907
> >>          tristate "Maxim Semiconductor MAX8907 PMIC Support"
> >>          select MFD_CORE
> >> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> >> index 53467e2..fe4f75c 100644
> >> --- a/drivers/mfd/Makefile
> >> +++ b/drivers/mfd/Makefile
> >> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
> >>   obj-$(CONFIG_MFD_MAX14577)     += max14577.o
> >>   obj-$(CONFIG_MFD_MAX77686)     += max77686.o
> >>   obj-$(CONFIG_MFD_MAX77693)     += max77693.o
> >> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
> >>   obj-$(CONFIG_MFD_MAX8907)      += max8907.o
> >>   max8925-objs                   := max8925-core.o max8925-i2c.o
> >>   obj-$(CONFIG_MFD_MAX8925)      += max8925.o
> >> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
> >> new file mode 100644
> >> index 0000000..d7f8b76
> >> --- /dev/null
> >> +++ b/drivers/mfd/max77843.c
> >> @@ -0,0 +1,241 @@
> >> +/*
> >> + * max77843.c - MFD core driver for the Maxim MAX77843
> >> + *
> >> + * Copyright (C) 2014 Samsung Electrnoics
> >> + * Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#include <linux/err.h>
> >> +#include <linux/i2c.h>
> >> +#include <linux/init.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/module.h>
> >> +#include <linux/mfd/core.h>
> >> +#include <linux/mfd/max77843-private.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/platform_device.h>
> >> +
> >> +static const struct mfd_cell max77843_devs[] = {
> >> +       {
> >> +               .name = "max77843-muic",
> >> +               .of_compatible = "maxim,max77843-muic",
> >> +       }, {
> >> +               .name = "max77843-regulator",
> >> +               .of_compatible = "maxim,max77843-regulator",
> >> +       }, {
> >> +               .name = "max77843-charger",
> >> +               .of_compatible = "maxim,max77843-charger"
> >> +       }, {
> >> +               .name = "max77843-fuelgauge",
> >> +               .of_compatible = "maxim,max77843-fuelgauge",
> >> +       },
> >> +};
> >> +
> >> +static const struct regmap_config max77843_charger_regmap_config = {
> >> +       .reg_bits       = 8,
> >> +       .val_bits       = 8,
> >> +       .max_register   = MAX77843_CHG_REG_END,
> >> +};
> >> +
> >> +static const struct regmap_config max77843_regmap_config = {
> >> +       .reg_bits       = 8,
> >> +       .val_bits       = 8,
> >> +       .max_register   = MAX77843_SYS_REG_END,
> >> +};
> >> +
> >> +static const struct regmap_irq max77843_irqs[] = {
> >> +       /* TOPSYS interrupts */
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
> >> +};
> >> +
> >> +static const struct regmap_irq_chip max77843_irq_chip = {
> >> +       .name           = "max77843",
> >> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
> >> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
> >> +       .mask_invert    = false,
> >> +       .num_regs       = 1,
> >> +       .irqs           = max77843_irqs,
> >> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
> >> +};
> >> +
> >> +static int max77843_chg_init(struct max77843 *max77843)
> >> +{
> > Could this function be moved to the charger driver? This way the
> > driver will manage its own resources instead of depending on parent
> > MFD driver.
> >
> >> +       int ret;
> >> +
> >> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
> >> +       if (!max77843->i2c_chg) {
> >> +               dev_err(&max77843->i2c->dev,
> >> +                               "Cannot allocate I2C device for Charger\n");
> >> +               return PTR_ERR(max77843->i2c_chg);
> >> +       }
> >> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
> >> +
> >> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
> >> +                       &max77843_charger_regmap_config);
> >> +       if (IS_ERR(max77843->regmap_chg)) {
> >> +               ret = PTR_ERR(max77843->regmap_chg);
> >> +               goto err_chg_i2c;
> >> +       }
> >> +
> >> +       return 0;
> >> +
> >> +err_chg_i2c:
> >> +       i2c_unregister_device(max77843->i2c_chg);
> >> +
> >> +       return ret;
> >> +}
> >> +
> >> +static int max77843_probe(struct i2c_client *i2c,
> >> +                                       const struct i2c_device_id *id)
> >> +{
> >> +       struct max77843 *max77843;
> >> +       int ret;
> >> +       unsigned int reg_data;
> >> +
> >> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
> >> +       if (!max77843)
> >> +               return -ENOMEM;
> >> +
> >> +       i2c_set_clientdata(i2c, max77843);
> >> +       max77843->dev = &i2c->dev;
> >> +       max77843->i2c = i2c;
> >> +       max77843->irq = i2c->irq;
> >> +
> >> +       max77843->regmap = devm_regmap_init_i2c(i2c,
> >> +                       &max77843_regmap_config);
> >> +       if (IS_ERR(max77843->regmap)) {
> >> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
> >> +               return PTR_ERR(max77843->regmap);
> >> +       }
> >> +
> >> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
> >> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> >> +                       0, &max77843_irq_chip, &max77843->irq_data);
> > Why shared IRQ?
> 
> This IRQ shared with submodules.
> you can see another IRQ register process in extcon-max77843 driver.

Right, I found it later.

> 
> >
> >> +       if (ret) {
> >> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
> >> +               return ret;
> >> +       }
> >> +
> >> +       ret = regmap_read(max77843->regmap,
> >> +                       MAX77843_SYS_REG_PMICID, &reg_data);
> >> +       if (ret < 0) {
> >> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
> >> +               goto err_pmic_id;
> >> +       }
> >> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
> >> +
> >> +       ret = max77843_chg_init(max77843);
> >> +       if (ret) {
> >> +               dev_err(&i2c->dev, "Failed to init Charger\n");
> >> +               goto err_pmic_id;
> >> +       }
> >> +
> >> +       ret = regmap_update_bits(max77843->regmap,
> >> +                       MAX77843_SYS_REG_INTSRCMASK,
> >> +                       MAX77843_INTSRC_MASK_MASK,
> >> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
> >> +       if (ret < 0) {
> >> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> > s/sourece/source/
> 
> I will fix typo in next version.
> 
> >
> > Best regards,
> > Krzysztof
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> > the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >
> 
> Thanks to review my patch.
> Jaewon Kim

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

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
  2015-01-23  6:41       ` Beomho Seo
  (?)
@ 2015-01-23  7:16       ` Krzysztof Kozlowski
  2015-01-23 11:10         ` Beomho Seo
  -1 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Kozlowski @ 2015-01-23  7:16 UTC (permalink / raw)
  To: Beomho Seo
  Cc: Jaewon Kim, linux-kernel, devicetree, linux-pm, Inki Dae,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Lee Jones, Chanwoo Choi, Sebastian Reichel, Mark Brown

On pią, 2015-01-23 at 15:41 +0900, Beomho Seo wrote:
> On 01/23/2015 03:32 PM, Krzysztof Kozlowski wrote:
> > 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
> >> This patch adds MAX77843 core/irq driver to support PMIC,
> >> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
> >> LED and Haptic device.
> >>
> >> Cc: Lee Jones <lee.jones@linaro.org>
> >> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> >> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> >> ---
> >>  drivers/mfd/Kconfig                  |   14 ++
> >>  drivers/mfd/Makefile                 |    1 +
> >>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
> >>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
> >>  4 files changed, 666 insertions(+)
> >>  create mode 100644 drivers/mfd/max77843.c
> >>  create mode 100644 include/linux/mfd/max77843-private.h
> >>
> >> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >> index 2e6b731..0c67c79 100644
> >> --- a/drivers/mfd/Kconfig
> >> +++ b/drivers/mfd/Kconfig
> >> @@ -442,6 +442,20 @@ config MFD_MAX77693
> >>           additional drivers must be enabled in order to use the functionality
> >>           of the device.
> >>
> >> +config MFD_MAX77843
> >> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
> >> +       depends on I2C=y
> >> +       select MFD_CORE
> >> +       select REGMAP_I2C
> >> +       select REGMAP_IRQ
> >> +       help
> >> +         Say yes here to add support for Maxim Semiconductor MAX77843.
> >> +         This is companion Power Management IC with LEDs, Haptic, Charger,
> >> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
> >> +         This driver provides common support for accessing the device;
> >> +         additional drivers must be enabled in order to use the functionality
> >> +         of the device.
> >> +
> >>  config MFD_MAX8907
> >>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
> >>         select MFD_CORE
> >> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> >> index 53467e2..fe4f75c 100644
> >> --- a/drivers/mfd/Makefile
> >> +++ b/drivers/mfd/Makefile
> >> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
> >>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
> >>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
> >>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
> >> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
> >>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
> >>  max8925-objs                   := max8925-core.o max8925-i2c.o
> >>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
> >> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
> >> new file mode 100644
> >> index 0000000..d7f8b76
> >> --- /dev/null
> >> +++ b/drivers/mfd/max77843.c
> >> @@ -0,0 +1,241 @@
> >> +/*
> >> + * max77843.c - MFD core driver for the Maxim MAX77843
> >> + *
> >> + * Copyright (C) 2014 Samsung Electrnoics
> >> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
> >> + *
> >> + * This program is free software; you can redistribute it and/or modify
> >> + * it under the terms of the GNU General Public License as published by
> >> + * the Free Software Foundation; either version 2 of the License, or
> >> + * (at your option) any later version.
> >> + */
> >> +
> >> +#include <linux/err.h>
> >> +#include <linux/i2c.h>
> >> +#include <linux/init.h>
> >> +#include <linux/interrupt.h>
> >> +#include <linux/module.h>
> >> +#include <linux/mfd/core.h>
> >> +#include <linux/mfd/max77843-private.h>
> >> +#include <linux/of_device.h>
> >> +#include <linux/platform_device.h>
> >> +
> >> +static const struct mfd_cell max77843_devs[] = {
> >> +       {
> >> +               .name = "max77843-muic",
> >> +               .of_compatible = "maxim,max77843-muic",
> >> +       }, {
> >> +               .name = "max77843-regulator",
> >> +               .of_compatible = "maxim,max77843-regulator",
> >> +       }, {
> >> +               .name = "max77843-charger",
> >> +               .of_compatible = "maxim,max77843-charger"
> >> +       }, {
> >> +               .name = "max77843-fuelgauge",
> >> +               .of_compatible = "maxim,max77843-fuelgauge",
> >> +       },
> >> +};
> >> +
> >> +static const struct regmap_config max77843_charger_regmap_config = {
> >> +       .reg_bits       = 8,
> >> +       .val_bits       = 8,
> >> +       .max_register   = MAX77843_CHG_REG_END,
> >> +};
> >> +
> >> +static const struct regmap_config max77843_regmap_config = {
> >> +       .reg_bits       = 8,
> >> +       .val_bits       = 8,
> >> +       .max_register   = MAX77843_SYS_REG_END,
> >> +};
> >> +
> >> +static const struct regmap_irq max77843_irqs[] = {
> >> +       /* TOPSYS interrupts */
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
> >> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
> >> +};
> >> +
> >> +static const struct regmap_irq_chip max77843_irq_chip = {
> >> +       .name           = "max77843",
> >> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
> >> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
> >> +       .mask_invert    = false,
> >> +       .num_regs       = 1,
> >> +       .irqs           = max77843_irqs,
> >> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
> >> +};
> >> +
> >> +static int max77843_chg_init(struct max77843 *max77843)
> >> +{
> > 
> > Could this function be moved to the charger driver? This way the
> > driver will manage its own resources instead of depending on parent
> > MFD driver.
> > 
> 
> Charger regulator and Charger share same resources.
> So I include this function core driver.

OK, I see... Could you describe it in comments somewhere? For example in
comment above the function. Currently this looks like only as regmap for
charger.

Unfortunately current solution imposes problem with releasing resources.
Who is the owner of i2c dummy device?

1. The charger driver will unregister it if max77843_charger_probe()
fails. What will happen with regulator driver in such case?

2. Who will release this i2c dummy device in normal unbind? Currently it
leaks.

Best regards,
Krzysztof

> 
> >> +       int ret;
> >> +
> >> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
> >> +       if (!max77843->i2c_chg) {
> >> +               dev_err(&max77843->i2c->dev,
> >> +                               "Cannot allocate I2C device for Charger\n");
> >> +               return PTR_ERR(max77843->i2c_chg);
> >> +       }
> >> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
> >> +
> >> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
> >> +                       &max77843_charger_regmap_config);
> >> +       if (IS_ERR(max77843->regmap_chg)) {
> >> +               ret = PTR_ERR(max77843->regmap_chg);
> >> +               goto err_chg_i2c;
> >> +       }
> >> +
> >> +       return 0;
> >> +
> >> +err_chg_i2c:
> >> +       i2c_unregister_device(max77843->i2c_chg);
> >> +
> >> +       return ret;
> >> +}
> >> +
> >> +static int max77843_probe(struct i2c_client *i2c,
> >> +                                       const struct i2c_device_id *id)
> >> +{
> >> +       struct max77843 *max77843;
> >> +       int ret;
> >> +       unsigned int reg_data;
> >> +
> >> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
> >> +       if (!max77843)
> >> +               return -ENOMEM;
> >> +
> >> +       i2c_set_clientdata(i2c, max77843);
> >> +       max77843->dev = &i2c->dev;
> >> +       max77843->i2c = i2c;
> >> +       max77843->irq = i2c->irq;
> >> +
> >> +       max77843->regmap = devm_regmap_init_i2c(i2c,
> >> +                       &max77843_regmap_config);
> >> +       if (IS_ERR(max77843->regmap)) {
> >> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
> >> +               return PTR_ERR(max77843->regmap);
> >> +       }
> >> +
> >> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
> >> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
> >> +                       0, &max77843_irq_chip, &max77843->irq_data);
> > 
> > Why shared IRQ?
> > 
> >> +       if (ret) {
> >> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
> >> +               return ret;
> >> +       }
> >> +
> >> +       ret = regmap_read(max77843->regmap,
> >> +                       MAX77843_SYS_REG_PMICID, &reg_data);
> >> +       if (ret < 0) {
> >> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
> >> +               goto err_pmic_id;
> >> +       }
> >> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
> >> +
> >> +       ret = max77843_chg_init(max77843);
> >> +       if (ret) {
> >> +               dev_err(&i2c->dev, "Failed to init Charger\n");
> >> +               goto err_pmic_id;
> >> +       }
> >> +
> >> +       ret = regmap_update_bits(max77843->regmap,
> >> +                       MAX77843_SYS_REG_INTSRCMASK,
> >> +                       MAX77843_INTSRC_MASK_MASK,
> >> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
> >> +       if (ret < 0) {
> >> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
> > 
> > s/sourece/source/
> > 
> > Best regards,
> > Krzysztof
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-pm" 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] 41+ messages in thread

* Re: [PATCH 5/6] regulator: max77843: Add max77843 regulator driver
  2015-01-23  5:02 ` [PATCH 5/6] regulator: max77843: Add max77843 regulator driver Jaewon Kim
@ 2015-01-23  7:18   ` Krzysztof Kozłowski
  2015-01-23  7:26     ` Jaewon Kim
  0 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Kozłowski @ 2015-01-23  7:18 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
> This patch adds new regulator driver to support max77843
> MFD(Multi Function Device) chip`s regulators.
> The Max77843 has two voltage regulators for USB safeout.
>
> Cc: Mark Brown <broonie@kernel.org>
> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> ---
>  drivers/regulator/Kconfig    |    8 ++
>  drivers/regulator/Makefile   |    1 +
>  drivers/regulator/max77843.c |  259 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 268 insertions(+)
>  create mode 100644 drivers/regulator/max77843.c
>
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index c3a60b5..c1f9c33 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -414,6 +414,14 @@ config REGULATOR_MAX77802
>           Exynos5420/Exynos5800 SoCs to control various voltages.
>           It includes support for control of voltage and ramp speed.
>
> +config REGULATOR_MAX77843
> +       tristate "Maxim 77843 regulator"
> +       depends on MFD_MAX77843
> +       help
> +         This driver controls a Maxim 77843 regulator.
> +         The regulator include two 'SAFEOUT' for USB(Universal Serial Bus)
> +         This is suitable for Exynos5433 SoC chips.
> +
>  config REGULATOR_MC13XXX_CORE
>         tristate
>
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 1f28ebf..12408d6 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
>  obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
>  obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
>  obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
> +obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o
>  obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
>  obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
>  obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
> diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c
> new file mode 100644
> index 0000000..86afc7a
> --- /dev/null
> +++ b/drivers/regulator/max77843.c
> @@ -0,0 +1,259 @@
> +/*
> + * max77843.c - Regulator driver for the Maxim MAX77843
> + *
> + * Copyright (C) 2014 Samsung Electrnoics
> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/mfd/max77843-private.h>
> +#include <linux/regulator/of_regulator.h>
> +
> +#define MAX77843_SUPPORTED_VOLTAGE_NUM 4
> +
> +enum max77843_regulator_type {
> +       MAX77843_SAFEOUT1 = 0,
> +       MAX77843_SAFEOUT2,
> +       MAX77843_CHARGER,
> +
> +       MAX77843_NUM,
> +};
> +
> +static const unsigned int max77843_regulator_table[] = {
> +       4850000,
> +       4900000,
> +       4950000,
> +       3300000,
> +};
> +
> +static int max77843_reg_is_enabled(struct regulator_dev *rdev)
> +{
> +       struct regmap *regmap = rdev->regmap;
> +       int ret;
> +       unsigned int reg;
> +
> +       ret = regmap_read(regmap, rdev->desc->enable_reg, &reg);
> +       if (ret) {
> +               dev_err(&rdev->dev, "Fialed to read charger register\n");
> +               return ret;
> +       }
> +
> +       return (reg & rdev->desc->enable_mask) == rdev->desc->enable_mask;
> +}
> +
> +static int max77843_reg_get_current_limit(struct regulator_dev *rdev)
> +{
> +       struct regmap *regmap = rdev->regmap;
> +       unsigned int chg_min_uA = rdev->constraints->min_uA;
> +       unsigned int chg_max_uA = rdev->constraints->max_uA;
> +       unsigned int val;
> +       int ret;
> +       unsigned int reg, sel;
> +
> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg);
> +       if (ret) {
> +               dev_err(&rdev->dev, "Failed to read charger register\n");
> +               return ret;
> +       }
> +
> +       sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK;
> +
> +       if (sel < 0x03)
> +               sel = 0;
> +       else
> +               sel -= 2;
> +
> +       val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel;
> +       if (val > chg_max_uA)
> +               return -EINVAL;
> +
> +       return val;
> +}
> +
> +static int max77843_reg_set_current_limit(struct regulator_dev *rdev,
> +               int min_uA, int max_uA)
> +{
> +       struct regmap *regmap = rdev->regmap;
> +       unsigned int chg_min_uA = rdev->constraints->min_uA;
> +       int sel = 0;
> +
> +       while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA)
> +               sel++;
> +
> +       if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA)
> +               return -EINVAL;
> +
> +       sel += 2;
> +
> +       return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel);
> +}
> +
> +static struct regulator_ops max77843_charger_ops = {
> +       .is_enabled             = max77843_reg_is_enabled,
> +       .enable                 = regulator_enable_regmap,
> +       .disable                = regulator_disable_regmap,
> +       .get_current_limit      = max77843_reg_get_current_limit,
> +       .set_current_limit      = max77843_reg_set_current_limit,
> +};
> +
> +static struct regulator_ops max77843_regulator_ops = {
> +       .is_enabled             = regulator_is_enabled_regmap,
> +       .enable                 = regulator_enable_regmap,
> +       .disable                = regulator_disable_regmap,
> +       .list_voltage           = regulator_list_voltage_table,
> +       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
> +       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
> +};
> +
> +static const struct regulator_desc max77843_supported_regulators[] = {
> +       [MAX77843_SAFEOUT1] = {
> +               .name           = "SAFEOUT1",
> +               .id             = MAX77843_SAFEOUT1,
> +               .ops            = &max77843_regulator_ops,
> +               .type           = REGULATOR_VOLTAGE,
> +               .owner          = THIS_MODULE,
> +               .n_voltages     = MAX77843_SUPPORTED_VOLTAGE_NUM,
> +               .volt_table     = max77843_regulator_table,
> +               .enable_reg     = MAX77843_SYS_REG_SAFEOUTCTRL,
> +               .enable_mask    = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1,
> +               .vsel_reg       = MAX77843_SYS_REG_SAFEOUTCTRL,
> +               .vsel_mask      = MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK,
> +       },
> +       [MAX77843_SAFEOUT2] = {
> +               .name           = "SAFEOUT2",
> +               .id             = MAX77843_SAFEOUT2,
> +               .ops            = &max77843_regulator_ops,
> +               .type           = REGULATOR_VOLTAGE,
> +               .owner          = THIS_MODULE,
> +               .n_voltages     = MAX77843_SUPPORTED_VOLTAGE_NUM,
> +               .volt_table     = max77843_regulator_table,
> +               .enable_reg     = MAX77843_SYS_REG_SAFEOUTCTRL,
> +               .enable_mask    = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2,
> +               .vsel_reg       = MAX77843_SYS_REG_SAFEOUTCTRL,
> +               .vsel_mask      = MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK,
> +       },
> +       [MAX77843_CHARGER] = {
> +               .name           = "CHARGER",
> +               .id             = MAX77843_CHARGER,
> +               .ops            = &max77843_charger_ops,
> +               .type           = REGULATOR_CURRENT,
> +               .owner          = THIS_MODULE,
> +               .enable_reg     = MAX77843_CHG_REG_CHG_CNFG_00,
> +               .enable_mask    = MAX77843_CHG_MASK,
> +       },
> +};
> +
> +static struct of_regulator_match max77843_regulator_matches[] = {
> +       { .name = "SAFEOUT1", },
> +       { .name = "SAFEOUT2", },
> +       { .name = "CHARGER", },
> +};
> +
> +static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id)
> +{
> +       switch (reg_id) {
> +       case MAX77843_SAFEOUT1:
> +       case MAX77843_SAFEOUT2:
> +               return max77843->regmap;
> +       case MAX77843_CHARGER:
> +               return max77843->regmap_chg;
> +       default:
> +               return max77843->regmap;
> +       }
> +}
> +
> +static int max77843_regulator_dt_parse(struct platform_device *pdev)
> +{
> +       struct device_node *np;
> +       int ret;
> +
> +       np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
> +       if (!np) {
> +               dev_err(&pdev->dev,
> +                       "Cannot get child OF node for regulators\n");
> +               return -EINVAL;
> +       }
> +
> +       ret = of_regulator_match(&pdev->dev, np, max77843_regulator_matches,
> +                       ARRAY_SIZE(max77843_regulator_matches));
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Cannot parsing regulator init data\n");
> +               return ret;
> +       }
> +
> +       of_node_put(np);
> +
> +       return 0;

Use simplified DT parsing method (of_match and regulators_node from
regulators_desc). This function could be removed then.

Best regards,
Krzysztof

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

* Re: [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver
  2015-01-23  6:38   ` Krzysztof Kozłowski
@ 2015-01-23  7:18     ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  7:18 UTC (permalink / raw)
  To: Krzysztof Kozłowski
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

Hi Krzysztof,

2015년 01월 23일 15:38에 Krzysztof Kozłowski 이(가) 쓴 글:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
>> This patch adds MAX77843 extcon driver to support for MUIC(Micro
>> USB Interface Controller) device by using EXTCON subsystem to handle
>> various external connectors.
>>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>>   drivers/extcon/Kconfig           |   10 +
>>   drivers/extcon/Makefile          |    1 +
>>   drivers/extcon/extcon-max77843.c |  871 ++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 882 insertions(+)
>>   create mode 100644 drivers/extcon/extcon-max77843.c
>>
> (...)
>
>> +static int max77843_muic_remove(struct platform_device *pdev)
>> +{
>> +       struct max77843_muic_info *info = platform_get_drvdata(pdev);
>> +
>> +       cancel_work_sync(&info->irq_work);
>> +
> Missing regmap_del_irq_chip().
>
> Best regards,
> Krzysztof
>

I miss remap_del_irq_chip() function. thanks.
I wil add this function.


Thanks
Jaewon Kim


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

* Re: [PATCH 5/6] regulator: max77843: Add max77843 regulator driver
  2015-01-23  7:18   ` Krzysztof Kozłowski
@ 2015-01-23  7:26     ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  7:26 UTC (permalink / raw)
  To: Krzysztof Kozłowski
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown, Beomho Seo

Hi Krzysztof,

2015년 01월 23일 16:18에 Krzysztof Kozłowski 이(가) 쓴 글:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
>> This patch adds new regulator driver to support max77843
>> MFD(Multi Function Device) chip`s regulators.
>> The Max77843 has two voltage regulators for USB safeout.
>>
>> Cc: Mark Brown <broonie@kernel.org>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>>   drivers/regulator/Kconfig    |    8 ++
>>   drivers/regulator/Makefile   |    1 +
>>   drivers/regulator/max77843.c |  259 ++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 268 insertions(+)
>>   create mode 100644 drivers/regulator/max77843.c
>>
>> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
>> index c3a60b5..c1f9c33 100644
>> --- a/drivers/regulator/Kconfig
>> +++ b/drivers/regulator/Kconfig
>> @@ -414,6 +414,14 @@ config REGULATOR_MAX77802
>>            Exynos5420/Exynos5800 SoCs to control various voltages.
>>            It includes support for control of voltage and ramp speed.
>>
>> +config REGULATOR_MAX77843
>> +       tristate "Maxim 77843 regulator"
>> +       depends on MFD_MAX77843
>> +       help
>> +         This driver controls a Maxim 77843 regulator.
>> +         The regulator include two 'SAFEOUT' for USB(Universal Serial Bus)
>> +         This is suitable for Exynos5433 SoC chips.
>> +
>>   config REGULATOR_MC13XXX_CORE
>>          tristate
>>
>> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
>> index 1f28ebf..12408d6 100644
>> --- a/drivers/regulator/Makefile
>> +++ b/drivers/regulator/Makefile
>> @@ -55,6 +55,7 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
>>   obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
>>   obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
>>   obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
>> +obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o
>>   obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
>>   obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
>>   obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
>> diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c
>> new file mode 100644
>> index 0000000..86afc7a
>> --- /dev/null
>> +++ b/drivers/regulator/max77843.c
>> @@ -0,0 +1,259 @@
>> +/*
>> + * max77843.c - Regulator driver for the Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regulator/driver.h>
>> +#include <linux/regulator/machine.h>
>> +#include <linux/mfd/max77843-private.h>
>> +#include <linux/regulator/of_regulator.h>
>> +
>> +#define MAX77843_SUPPORTED_VOLTAGE_NUM 4
>> +
>> +enum max77843_regulator_type {
>> +       MAX77843_SAFEOUT1 = 0,
>> +       MAX77843_SAFEOUT2,
>> +       MAX77843_CHARGER,
>> +
>> +       MAX77843_NUM,
>> +};
>> +
>> +static const unsigned int max77843_regulator_table[] = {
>> +       4850000,
>> +       4900000,
>> +       4950000,
>> +       3300000,
>> +};
>> +
>> +static int max77843_reg_is_enabled(struct regulator_dev *rdev)
>> +{
>> +       struct regmap *regmap = rdev->regmap;
>> +       int ret;
>> +       unsigned int reg;
>> +
>> +       ret = regmap_read(regmap, rdev->desc->enable_reg, &reg);
>> +       if (ret) {
>> +               dev_err(&rdev->dev, "Fialed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       return (reg & rdev->desc->enable_mask) == rdev->desc->enable_mask;
>> +}
>> +
>> +static int max77843_reg_get_current_limit(struct regulator_dev *rdev)
>> +{
>> +       struct regmap *regmap = rdev->regmap;
>> +       unsigned int chg_min_uA = rdev->constraints->min_uA;
>> +       unsigned int chg_max_uA = rdev->constraints->max_uA;
>> +       unsigned int val;
>> +       int ret;
>> +       unsigned int reg, sel;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg);
>> +       if (ret) {
>> +               dev_err(&rdev->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK;
>> +
>> +       if (sel < 0x03)
>> +               sel = 0;
>> +       else
>> +               sel -= 2;
>> +
>> +       val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel;
>> +       if (val > chg_max_uA)
>> +               return -EINVAL;
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_reg_set_current_limit(struct regulator_dev *rdev,
>> +               int min_uA, int max_uA)
>> +{
>> +       struct regmap *regmap = rdev->regmap;
>> +       unsigned int chg_min_uA = rdev->constraints->min_uA;
>> +       int sel = 0;
>> +
>> +       while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA)
>> +               sel++;
>> +
>> +       if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA)
>> +               return -EINVAL;
>> +
>> +       sel += 2;
>> +
>> +       return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel);
>> +}
>> +
>> +static struct regulator_ops max77843_charger_ops = {
>> +       .is_enabled             = max77843_reg_is_enabled,
>> +       .enable                 = regulator_enable_regmap,
>> +       .disable                = regulator_disable_regmap,
>> +       .get_current_limit      = max77843_reg_get_current_limit,
>> +       .set_current_limit      = max77843_reg_set_current_limit,
>> +};
>> +
>> +static struct regulator_ops max77843_regulator_ops = {
>> +       .is_enabled             = regulator_is_enabled_regmap,
>> +       .enable                 = regulator_enable_regmap,
>> +       .disable                = regulator_disable_regmap,
>> +       .list_voltage           = regulator_list_voltage_table,
>> +       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
>> +       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
>> +};
>> +
>> +static const struct regulator_desc max77843_supported_regulators[] = {
>> +       [MAX77843_SAFEOUT1] = {
>> +               .name           = "SAFEOUT1",
>> +               .id             = MAX77843_SAFEOUT1,
>> +               .ops            = &max77843_regulator_ops,
>> +               .type           = REGULATOR_VOLTAGE,
>> +               .owner          = THIS_MODULE,
>> +               .n_voltages     = MAX77843_SUPPORTED_VOLTAGE_NUM,
>> +               .volt_table     = max77843_regulator_table,
>> +               .enable_reg     = MAX77843_SYS_REG_SAFEOUTCTRL,
>> +               .enable_mask    = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1,
>> +               .vsel_reg       = MAX77843_SYS_REG_SAFEOUTCTRL,
>> +               .vsel_mask      = MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK,
>> +       },
>> +       [MAX77843_SAFEOUT2] = {
>> +               .name           = "SAFEOUT2",
>> +               .id             = MAX77843_SAFEOUT2,
>> +               .ops            = &max77843_regulator_ops,
>> +               .type           = REGULATOR_VOLTAGE,
>> +               .owner          = THIS_MODULE,
>> +               .n_voltages     = MAX77843_SUPPORTED_VOLTAGE_NUM,
>> +               .volt_table     = max77843_regulator_table,
>> +               .enable_reg     = MAX77843_SYS_REG_SAFEOUTCTRL,
>> +               .enable_mask    = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2,
>> +               .vsel_reg       = MAX77843_SYS_REG_SAFEOUTCTRL,
>> +               .vsel_mask      = MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK,
>> +       },
>> +       [MAX77843_CHARGER] = {
>> +               .name           = "CHARGER",
>> +               .id             = MAX77843_CHARGER,
>> +               .ops            = &max77843_charger_ops,
>> +               .type           = REGULATOR_CURRENT,
>> +               .owner          = THIS_MODULE,
>> +               .enable_reg     = MAX77843_CHG_REG_CHG_CNFG_00,
>> +               .enable_mask    = MAX77843_CHG_MASK,
>> +       },
>> +};
>> +
>> +static struct of_regulator_match max77843_regulator_matches[] = {
>> +       { .name = "SAFEOUT1", },
>> +       { .name = "SAFEOUT2", },
>> +       { .name = "CHARGER", },
>> +};
>> +
>> +static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id)
>> +{
>> +       switch (reg_id) {
>> +       case MAX77843_SAFEOUT1:
>> +       case MAX77843_SAFEOUT2:
>> +               return max77843->regmap;
>> +       case MAX77843_CHARGER:
>> +               return max77843->regmap_chg;
>> +       default:
>> +               return max77843->regmap;
>> +       }
>> +}
>> +
>> +static int max77843_regulator_dt_parse(struct platform_device *pdev)
>> +{
>> +       struct device_node *np;
>> +       int ret;
>> +
>> +       np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
>> +       if (!np) {
>> +               dev_err(&pdev->dev,
>> +                       "Cannot get child OF node for regulators\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       ret = of_regulator_match(&pdev->dev, np, max77843_regulator_matches,
>> +                       ARRAY_SIZE(max77843_regulator_matches));
>> +       if (ret < 0) {
>> +               dev_err(&pdev->dev, "Cannot parsing regulator init data\n");
>> +               return ret;
>> +       }
>> +
>> +       of_node_put(np);
>> +
>> +       return 0;
> Use simplified DT parsing method (of_match and regulators_node from
> regulators_desc). This function could be removed then.

Thanks to advice.
I will use more simplified method in next version.
>
> Best regards,
> Krzysztof
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

Thanks,
Jaewon Kim

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

* Re: [PATCH 3/6] power: max77843_charger: Add Max77843 charger device driver
@ 2015-01-23  7:28       ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23  7:28 UTC (permalink / raw)
  To: Krzysztof Kozłowski, Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown

Thank you for review.

On 01/23/2015 04:04 PM, Krzysztof Kozłowski wrote:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
>> From: Beomho Seo <beomho.seo@samsung.com>
>>
>> This patch adds device driver of max77843 charger. This driver provide
>> initialize each charging mode(e.g. fast charge, top-off mode and constant
>> charging mode so on.). Additionally, control charging paramters to use
>> i2c interface.
>>
>> Cc: Sebastian Reichel <sre@kernel.org>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> ---
>>  drivers/power/Kconfig            |    7 +
>>  drivers/power/Makefile           |    1 +
>>  drivers/power/max77843_charger.c |  506 ++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 514 insertions(+)
>>  create mode 100644 drivers/power/max77843_charger.c
>>
>> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
>> index 0108c2a..a054a28 100644
>> --- a/drivers/power/Kconfig
>> +++ b/drivers/power/Kconfig
>> @@ -332,6 +332,13 @@ config CHARGER_MAX14577
>>           Say Y to enable support for the battery charger control sysfs and
>>           platform data of MAX14577/77836 MUICs.
>>
>> +config CHARGER_MAX77843
>> +       tristate "Maxim MAX77843 battery charger driver"
>> +       depends on MFD_MAX77843
>> +       help
>> +         Say Y to enable support for the battery charger control sysfs and
>> +         platform data of MAX77843
>> +
>>  config CHARGER_MAX8997
>>         tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
>>         depends on MFD_MAX8997 && REGULATOR_MAX8997
>> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
>> index dfa8942..212c6a2 100644
>> --- a/drivers/power/Makefile
>> +++ b/drivers/power/Makefile
>> @@ -50,6 +50,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
>>  obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
>>  obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
>>  obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
>> +obj-$(CONFIG_CHARGER_MAX77843) += max77843_charger.o
>>  obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
>>  obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
>>  obj-$(CONFIG_CHARGER_BQ2415X)  += bq2415x_charger.o
>> diff --git a/drivers/power/max77843_charger.c b/drivers/power/max77843_charger.c
>> new file mode 100644
>> index 0000000..317b2cc
>> --- /dev/null
>> +++ b/drivers/power/max77843_charger.c
>> @@ -0,0 +1,506 @@
>> +/*
>> + * Charger driver for Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
>> + * Author: Beomho Seo <beomho.seo@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published bythe Free Software Foundation.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/power_supply.h>
>> +#include <linux/mfd/max77843-private.h>
>> +
>> +struct max77843_charger_info {
>> +       u32 fast_charge_uamp;
>> +       u32 top_off_uamp;
>> +       u32 input_uamp_limit;
>> +};
>> +
>> +struct max77843_charger {
>> +       struct device           *dev;
>> +       struct max77843         *max77843;
>> +       struct i2c_client       *client;
>> +       struct regmap           *regmap;
>> +       struct power_supply     psy;
>> +
>> +       struct max77843_charger_info    *info;
>> +};
> 
> Why creating two separate structures?
> 

max77843_charger_info structure just have property of charger.
If you want to merge one structure, I will revise above structure.

>> +
>> +static int max77843_charger_get_max_current(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_09, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       if (reg_data <= 0x03) {
>> +               val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
>> +       } else if (reg_data >= 0x78) {
>> +               val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX;
>> +       } else {
>> +               val = reg_data / 3;
>> +               if (reg_data % 3 == 0)
>> +                       val *= 100000;
>> +               else if (reg_data % 3 == 1)
>> +                       val = val * 100000 + 33000;
>> +               else
>> +                       val = val * 100000 + 67000;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_now_current(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
> 
> This error log shows up in many places. Please print also error code.
> 
> Additionally I think it could be useful to print also details about
> register which failed. Currently user would not know which register
> access failed. Consider adding short description like "Failed to read
> current charger register: %d...". However I do not insist on this so
> it is up to you.
> 

OK. I will fix error log.

>> +               return ret;
>> +       }
>> +
>> +       reg_data &= MAX77843_CHG_FAST_CHG_CURRENT_MASK;
>> +
>> +       if (reg_data <= 0x02)
>> +               val = MAX77843_CHG_FAST_CHG_CURRENT_MIN;
>> +       else if (reg_data >= 0x3f)
>> +               val = MAX77843_CHG_FAST_CHG_CURRENT_MAX;
>> +       else
>> +               val = reg_data * MAX77843_CHG_FAST_CHG_CURRENT_STEP;
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_online(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_INT_OK, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       if (reg_data & MAX77843_CHG_CHGIN_OK)
>> +               val = true;
>> +       else
>> +               val = false;
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_present(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_00, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       if (reg_data & MAX77843_CHG_BAT_DTLS)
>> +               val = false;
>> +       else
>> +               val = true;
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_health(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = POWER_SUPPLY_HEALTH_UNKNOWN;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       reg_data &= MAX77843_CHG_BAT_DTLS_MASK;
>> +
>> +       switch (reg_data) {
>> +       case MAX77843_CHG_NO_BAT:
>> +               val = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
>> +               break;
>> +       case MAX77843_CHG_LOW_VOLT_BAT:
>> +       case MAX77843_CHG_OK_BAT:
>> +       case MAX77843_CHG_OK_LOW_VOLT_BAT:
>> +               val = POWER_SUPPLY_HEALTH_GOOD;
>> +               break;
>> +       case MAX77843_CHG_LONG_BAT_TIME:
>> +               val = POWER_SUPPLY_HEALTH_DEAD;
>> +               break;
>> +       case MAX77843_CHG_OVER_VOLT_BAT:
>> +       case MAX77843_CHG_OVER_CURRENT_BAT:
>> +               val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
>> +               break;
>> +       default:
>> +               val = POWER_SUPPLY_HEALTH_UNKNOWN;
>> +               break;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_status(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       reg_data &= MAX77843_CHG_DTLS_MASK;
>> +
>> +       switch (reg_data) {
>> +       case MAX77843_CHG_PQ_MODE:
>> +       case MAX77843_CHG_CC_MODE:
>> +       case MAX77843_CHG_CV_MODE:
>> +               val = POWER_SUPPLY_STATUS_CHARGING;
>> +               break;
>> +       case MAX77843_CHG_TO_MODE:
>> +       case MAX77843_CHG_DO_MODE:
>> +               val = POWER_SUPPLY_STATUS_FULL;
>> +               break;
>> +       case MAX77843_CHG_HT_MODE:
>> +       case MAX77843_CHG_TF_MODE:
>> +       case MAX77843_CHG_TS_MODE:
>> +               val = POWER_SUPPLY_STATUS_NOT_CHARGING;
>> +               break;
>> +       case MAX77843_CHG_OFF_MODE:
>> +               val = POWER_SUPPLY_STATUS_DISCHARGING;
>> +               break;
>> +       default:
>> +               val = POWER_SUPPLY_STATUS_UNKNOWN;
>> +               break;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static const char *model_name = "MAX77843";
>> +static const char *manufacturer = "Maxim Integrated";
>> +
>> +static int max77843_charger_get_property(struct power_supply *psy,
>> +               enum power_supply_property psp,
>> +               union power_supply_propval *val)
>> +{
>> +       struct max77843_charger *charger = container_of(psy,
>> +                               struct max77843_charger, psy);
>> +
>> +       switch (psp) {
>> +       case POWER_SUPPLY_PROP_STATUS:
>> +               val->intval = max77843_charger_get_status(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_HEALTH:
>> +               val->intval = max77843_charger_get_health(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_PRESENT:
>> +               val->intval = max77843_charger_get_present(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_ONLINE:
>> +               val->intval = max77843_charger_get_online(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_CURRENT_NOW:
>> +               val->intval = max77843_charger_get_now_current(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_CURRENT_MAX:
>> +               val->intval = max77843_charger_get_max_current(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_MODEL_NAME:
>> +               val->strval =  model_name;
>> +               break;
>> +       case POWER_SUPPLY_PROP_MANUFACTURER:
>> +               val->strval = manufacturer;
>> +               break;
>> +       default:
>> +               return -EINVAL;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static enum power_supply_property max77843_charger_props[] = {
>> +       POWER_SUPPLY_PROP_STATUS,
>> +       POWER_SUPPLY_PROP_HEALTH,
>> +       POWER_SUPPLY_PROP_PRESENT,
>> +       POWER_SUPPLY_PROP_ONLINE,
>> +       POWER_SUPPLY_PROP_CURRENT_NOW,
>> +       POWER_SUPPLY_PROP_CURRENT_MAX,
>> +       POWER_SUPPLY_PROP_MODEL_NAME,
>> +       POWER_SUPPLY_PROP_MANUFACTURER,
>> +};
>> +
>> +static int max77843_charger_init_current_limit(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       struct max77843_charger_info *info = charger->info;
>> +       unsigned int input_uamp_limit = info->input_uamp_limit;
>> +       int ret;
>> +       unsigned int reg_data, val;
>> +
>> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
>> +                       MAX77843_CHG_OTG_ILIMIT_MASK,
>> +                       MAX77843_CHG_OTG_ILIMIT_900);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
> 
> Same as in case of "read" operation failures - please print also error code.
> 

OK.

>> +               return ret;
>> +       }
>> +
>> +       if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN) {
>> +               reg_data = 0x03;
>> +       } else if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX) {
>> +               reg_data = 0x78;
>> +       } else {
>> +               if (input_uamp_limit < MAX77843_CHG_INPUT_CURRENT_LIMIT_REF)
>> +                       val = 0x03;
>> +               else
>> +                       val = 0x02;
>> +
>> +               input_uamp_limit -= MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
>> +               input_uamp_limit /= MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP;
>> +               reg_data = val + input_uamp_limit;
>> +       }
>> +
>> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
> 
> Could you merge it into:
> 
>        ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
>        if (ret)
>               dev_err(charger->dev, "Failed to write configure register\n");
>        return ret;
> 
> 

I will merge it into.

>> +
>> +static int max77843_charger_init_top_off(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       struct max77843_charger_info *info = charger->info;
>> +       unsigned int top_off_uamp = info->top_off_uamp;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MIN) {
>> +               reg_data = 0x00;
>> +       } else if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MAX) {
>> +               reg_data = 0x07;
>> +       } else {
>> +               top_off_uamp -= MAX77843_CHG_TOP_OFF_CURRENT_MIN;
>> +               top_off_uamp /= MAX77843_CHG_TOP_OFF_CURRENT_STEP;
>> +               reg_data = top_off_uamp;
>> +       }
>> +
>> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_03,
>> +                       MAX77843_CHG_TOP_OFF_CURRENT_MASK, reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
> 
> Ditto
> 

Ditto

>> +}
>> +
>> +static int max77843_charger_init_fast_charge(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       struct max77843_charger_info *info = charger->info;
>> +       unsigned int fast_charge_uamp = info->fast_charge_uamp;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       if (fast_charge_uamp < info->input_uamp_limit) {
>> +               reg_data = 0x09;
>> +       } else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MIN) {
>> +               reg_data = 0x02;
>> +       } else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MAX) {
>> +               reg_data = 0x3f;
>> +       } else {
>> +               fast_charge_uamp -= MAX77843_CHG_FAST_CHG_CURRENT_MIN;
>> +               fast_charge_uamp /= MAX77843_CHG_FAST_CHG_CURRENT_STEP;
>> +               reg_data = 0x02 + fast_charge_uamp;
>> +       }
>> +
>> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
>> +                       MAX77843_CHG_FAST_CHG_CURRENT_MASK, reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
> 
> Ditto
> 
>> +}
>> +
>> +static int max77843_charger_init(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret;
>> +
>> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_06,
>> +                       MAX77843_CHG_WRITE_CAP_UNBLOCK);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_01,
>> +                       MAX77843_CHG_RESTART_THRESHOLD_DISABLE);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = max77843_charger_init_fast_charge(charger);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to set fast charge mode.\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = max77843_charger_init_top_off(charger);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to set top off charge mode.\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = max77843_charger_init_current_limit(charger);
>> +
> 
> Why this return value is ignored?
> 

I will fix it.

>> +       return 0;
>> +}
>> +
>> +static struct max77843_charger_info *max77843_charger_dt_init(
>> +               struct platform_device *pdev)
>> +{
>> +       struct max77843_charger_info *info;
>> +       struct device_node *np = pdev->dev.of_node;
>> +       int ret;
>> +
>> +       if (!np) {
>> +               dev_err(&pdev->dev, "No charger OF node\n");
>> +               return ERR_PTR(-EINVAL);
>> +       }
>> +
>> +       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>> +       if (!info)
>> +               return ERR_PTR(-ENOMEM);
>> +
>> +       ret = of_property_read_u32(np, "maxim,fast-charge-uamp",
>> +                       &info->fast_charge_uamp);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Cannot parse fast charge current.\n");
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       ret = of_property_read_u32(np, "maxim,top-off-uamp",
>> +                       &info->top_off_uamp);
>> +       if (ret) {
>> +               dev_err(&pdev->dev,
>> +                       "Cannot parse primary charger termination voltage.\n");
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       ret = of_property_read_u32(np, "maxim,input-uamp-limit",
>> +                       &info->input_uamp_limit);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Cannot parse input current limit value\n");
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       return info;
>> +}
>> +
>> +static int max77843_charger_probe(struct platform_device *pdev)
>> +{
>> +       struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
>> +       struct max77843_charger *charger;
>> +       int ret;
>> +
>> +       charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
>> +       if (!charger)
>> +               return -ENOMEM;
>> +
>> +       platform_set_drvdata(pdev, charger);
>> +       charger->dev = &pdev->dev;
>> +       charger->max77843 = max77843;
>> +       charger->client = max77843->i2c_chg;
>> +       charger->regmap = max77843->regmap_chg;
>> +
>> +       charger->info = max77843_charger_dt_init(pdev);
>> +       if (IS_ERR_OR_NULL(charger->info)) {
>> +               ret = PTR_ERR(charger->info);
>> +               goto err_i2c;
>> +       }
>> +
>> +       charger->psy.name       = "max77843-charger";
>> +       charger->psy.type       = POWER_SUPPLY_TYPE_MAINS;
>> +       charger->psy.get_property       = max77843_charger_get_property;
>> +       charger->psy.properties         = max77843_charger_props;
>> +       charger->psy.num_properties     = ARRAY_SIZE(max77843_charger_props);
>> +
>> +       ret = max77843_charger_init(charger);
>> +       if (ret)
>> +               goto err_i2c;
>> +
>> +       ret = power_supply_register(&pdev->dev, &charger->psy);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Failed  to register power supply\n");
>> +               goto err_i2c;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_i2c:
>> +       i2c_unregister_device(charger->client);
> 
> This seems complicated. The MFD registers the i2c dummy for charger...
> and sometimes charger driver unregisters it and sometimes not. The
> ownership should be in one place: probably in charger driver... but I
> asked about this in another thread so lets discuss it there.
> 

OK. I will revise after discuss it.

> Best regards,
> Krzysztof
> 

Thanks,
Beomho Seo

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

* Re: [PATCH 3/6] power: max77843_charger: Add Max77843 charger device driver
@ 2015-01-23  7:28       ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23  7:28 UTC (permalink / raw)
  To: Krzysztof Kozłowski, Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown

Thank you for review.

On 01/23/2015 04:04 PM, Krzysztof Kozłowski wrote:
> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>:
>> From: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>
>> This patch adds device driver of max77843 charger. This driver provide
>> initialize each charging mode(e.g. fast charge, top-off mode and constant
>> charging mode so on.). Additionally, control charging paramters to use
>> i2c interface.
>>
>> Cc: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>>  drivers/power/Kconfig            |    7 +
>>  drivers/power/Makefile           |    1 +
>>  drivers/power/max77843_charger.c |  506 ++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 514 insertions(+)
>>  create mode 100644 drivers/power/max77843_charger.c
>>
>> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
>> index 0108c2a..a054a28 100644
>> --- a/drivers/power/Kconfig
>> +++ b/drivers/power/Kconfig
>> @@ -332,6 +332,13 @@ config CHARGER_MAX14577
>>           Say Y to enable support for the battery charger control sysfs and
>>           platform data of MAX14577/77836 MUICs.
>>
>> +config CHARGER_MAX77843
>> +       tristate "Maxim MAX77843 battery charger driver"
>> +       depends on MFD_MAX77843
>> +       help
>> +         Say Y to enable support for the battery charger control sysfs and
>> +         platform data of MAX77843
>> +
>>  config CHARGER_MAX8997
>>         tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
>>         depends on MFD_MAX8997 && REGULATOR_MAX8997
>> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
>> index dfa8942..212c6a2 100644
>> --- a/drivers/power/Makefile
>> +++ b/drivers/power/Makefile
>> @@ -50,6 +50,7 @@ obj-$(CONFIG_CHARGER_LP8788)  += lp8788-charger.o
>>  obj-$(CONFIG_CHARGER_GPIO)     += gpio-charger.o
>>  obj-$(CONFIG_CHARGER_MANAGER)  += charger-manager.o
>>  obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
>> +obj-$(CONFIG_CHARGER_MAX77843) += max77843_charger.o
>>  obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
>>  obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
>>  obj-$(CONFIG_CHARGER_BQ2415X)  += bq2415x_charger.o
>> diff --git a/drivers/power/max77843_charger.c b/drivers/power/max77843_charger.c
>> new file mode 100644
>> index 0000000..317b2cc
>> --- /dev/null
>> +++ b/drivers/power/max77843_charger.c
>> @@ -0,0 +1,506 @@
>> +/*
>> + * Charger driver for Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
>> + * Author: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published bythe Free Software Foundation.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/power_supply.h>
>> +#include <linux/mfd/max77843-private.h>
>> +
>> +struct max77843_charger_info {
>> +       u32 fast_charge_uamp;
>> +       u32 top_off_uamp;
>> +       u32 input_uamp_limit;
>> +};
>> +
>> +struct max77843_charger {
>> +       struct device           *dev;
>> +       struct max77843         *max77843;
>> +       struct i2c_client       *client;
>> +       struct regmap           *regmap;
>> +       struct power_supply     psy;
>> +
>> +       struct max77843_charger_info    *info;
>> +};
> 
> Why creating two separate structures?
> 

max77843_charger_info structure just have property of charger.
If you want to merge one structure, I will revise above structure.

>> +
>> +static int max77843_charger_get_max_current(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_09, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       if (reg_data <= 0x03) {
>> +               val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
>> +       } else if (reg_data >= 0x78) {
>> +               val = MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX;
>> +       } else {
>> +               val = reg_data / 3;
>> +               if (reg_data % 3 == 0)
>> +                       val *= 100000;
>> +               else if (reg_data % 3 == 1)
>> +                       val = val * 100000 + 33000;
>> +               else
>> +                       val = val * 100000 + 67000;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_now_current(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
> 
> This error log shows up in many places. Please print also error code.
> 
> Additionally I think it could be useful to print also details about
> register which failed. Currently user would not know which register
> access failed. Consider adding short description like "Failed to read
> current charger register: %d...". However I do not insist on this so
> it is up to you.
> 

OK. I will fix error log.

>> +               return ret;
>> +       }
>> +
>> +       reg_data &= MAX77843_CHG_FAST_CHG_CURRENT_MASK;
>> +
>> +       if (reg_data <= 0x02)
>> +               val = MAX77843_CHG_FAST_CHG_CURRENT_MIN;
>> +       else if (reg_data >= 0x3f)
>> +               val = MAX77843_CHG_FAST_CHG_CURRENT_MAX;
>> +       else
>> +               val = reg_data * MAX77843_CHG_FAST_CHG_CURRENT_STEP;
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_online(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_INT_OK, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       if (reg_data & MAX77843_CHG_CHGIN_OK)
>> +               val = true;
>> +       else
>> +               val = false;
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_present(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_00, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       if (reg_data & MAX77843_CHG_BAT_DTLS)
>> +               val = false;
>> +       else
>> +               val = true;
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_health(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = POWER_SUPPLY_HEALTH_UNKNOWN;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       reg_data &= MAX77843_CHG_BAT_DTLS_MASK;
>> +
>> +       switch (reg_data) {
>> +       case MAX77843_CHG_NO_BAT:
>> +               val = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
>> +               break;
>> +       case MAX77843_CHG_LOW_VOLT_BAT:
>> +       case MAX77843_CHG_OK_BAT:
>> +       case MAX77843_CHG_OK_LOW_VOLT_BAT:
>> +               val = POWER_SUPPLY_HEALTH_GOOD;
>> +               break;
>> +       case MAX77843_CHG_LONG_BAT_TIME:
>> +               val = POWER_SUPPLY_HEALTH_DEAD;
>> +               break;
>> +       case MAX77843_CHG_OVER_VOLT_BAT:
>> +       case MAX77843_CHG_OVER_CURRENT_BAT:
>> +               val = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
>> +               break;
>> +       default:
>> +               val = POWER_SUPPLY_HEALTH_UNKNOWN;
>> +               break;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static int max77843_charger_get_status(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret, val = 0;
>> +       unsigned int reg_data;
>> +
>> +       ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_DTLS_01, &reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to read charger register\n");
>> +               return ret;
>> +       }
>> +
>> +       reg_data &= MAX77843_CHG_DTLS_MASK;
>> +
>> +       switch (reg_data) {
>> +       case MAX77843_CHG_PQ_MODE:
>> +       case MAX77843_CHG_CC_MODE:
>> +       case MAX77843_CHG_CV_MODE:
>> +               val = POWER_SUPPLY_STATUS_CHARGING;
>> +               break;
>> +       case MAX77843_CHG_TO_MODE:
>> +       case MAX77843_CHG_DO_MODE:
>> +               val = POWER_SUPPLY_STATUS_FULL;
>> +               break;
>> +       case MAX77843_CHG_HT_MODE:
>> +       case MAX77843_CHG_TF_MODE:
>> +       case MAX77843_CHG_TS_MODE:
>> +               val = POWER_SUPPLY_STATUS_NOT_CHARGING;
>> +               break;
>> +       case MAX77843_CHG_OFF_MODE:
>> +               val = POWER_SUPPLY_STATUS_DISCHARGING;
>> +               break;
>> +       default:
>> +               val = POWER_SUPPLY_STATUS_UNKNOWN;
>> +               break;
>> +       }
>> +
>> +       return val;
>> +}
>> +
>> +static const char *model_name = "MAX77843";
>> +static const char *manufacturer = "Maxim Integrated";
>> +
>> +static int max77843_charger_get_property(struct power_supply *psy,
>> +               enum power_supply_property psp,
>> +               union power_supply_propval *val)
>> +{
>> +       struct max77843_charger *charger = container_of(psy,
>> +                               struct max77843_charger, psy);
>> +
>> +       switch (psp) {
>> +       case POWER_SUPPLY_PROP_STATUS:
>> +               val->intval = max77843_charger_get_status(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_HEALTH:
>> +               val->intval = max77843_charger_get_health(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_PRESENT:
>> +               val->intval = max77843_charger_get_present(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_ONLINE:
>> +               val->intval = max77843_charger_get_online(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_CURRENT_NOW:
>> +               val->intval = max77843_charger_get_now_current(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_CURRENT_MAX:
>> +               val->intval = max77843_charger_get_max_current(charger);
>> +               break;
>> +       case POWER_SUPPLY_PROP_MODEL_NAME:
>> +               val->strval =  model_name;
>> +               break;
>> +       case POWER_SUPPLY_PROP_MANUFACTURER:
>> +               val->strval = manufacturer;
>> +               break;
>> +       default:
>> +               return -EINVAL;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static enum power_supply_property max77843_charger_props[] = {
>> +       POWER_SUPPLY_PROP_STATUS,
>> +       POWER_SUPPLY_PROP_HEALTH,
>> +       POWER_SUPPLY_PROP_PRESENT,
>> +       POWER_SUPPLY_PROP_ONLINE,
>> +       POWER_SUPPLY_PROP_CURRENT_NOW,
>> +       POWER_SUPPLY_PROP_CURRENT_MAX,
>> +       POWER_SUPPLY_PROP_MODEL_NAME,
>> +       POWER_SUPPLY_PROP_MANUFACTURER,
>> +};
>> +
>> +static int max77843_charger_init_current_limit(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       struct max77843_charger_info *info = charger->info;
>> +       unsigned int input_uamp_limit = info->input_uamp_limit;
>> +       int ret;
>> +       unsigned int reg_data, val;
>> +
>> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
>> +                       MAX77843_CHG_OTG_ILIMIT_MASK,
>> +                       MAX77843_CHG_OTG_ILIMIT_900);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
> 
> Same as in case of "read" operation failures - please print also error code.
> 

OK.

>> +               return ret;
>> +       }
>> +
>> +       if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN) {
>> +               reg_data = 0x03;
>> +       } else if (input_uamp_limit == MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX) {
>> +               reg_data = 0x78;
>> +       } else {
>> +               if (input_uamp_limit < MAX77843_CHG_INPUT_CURRENT_LIMIT_REF)
>> +                       val = 0x03;
>> +               else
>> +                       val = 0x02;
>> +
>> +               input_uamp_limit -= MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN;
>> +               input_uamp_limit /= MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP;
>> +               reg_data = val + input_uamp_limit;
>> +       }
>> +
>> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
> 
> Could you merge it into:
> 
>        ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_09, reg_data);
>        if (ret)
>               dev_err(charger->dev, "Failed to write configure register\n");
>        return ret;
> 
> 

I will merge it into.

>> +
>> +static int max77843_charger_init_top_off(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       struct max77843_charger_info *info = charger->info;
>> +       unsigned int top_off_uamp = info->top_off_uamp;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MIN) {
>> +               reg_data = 0x00;
>> +       } else if (top_off_uamp == MAX77843_CHG_TOP_OFF_CURRENT_MAX) {
>> +               reg_data = 0x07;
>> +       } else {
>> +               top_off_uamp -= MAX77843_CHG_TOP_OFF_CURRENT_MIN;
>> +               top_off_uamp /= MAX77843_CHG_TOP_OFF_CURRENT_STEP;
>> +               reg_data = top_off_uamp;
>> +       }
>> +
>> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_03,
>> +                       MAX77843_CHG_TOP_OFF_CURRENT_MASK, reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
> 
> Ditto
> 

Ditto

>> +}
>> +
>> +static int max77843_charger_init_fast_charge(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       struct max77843_charger_info *info = charger->info;
>> +       unsigned int fast_charge_uamp = info->fast_charge_uamp;
>> +       int ret;
>> +       unsigned int reg_data;
>> +
>> +       if (fast_charge_uamp < info->input_uamp_limit) {
>> +               reg_data = 0x09;
>> +       } else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MIN) {
>> +               reg_data = 0x02;
>> +       } else if (fast_charge_uamp == MAX77843_CHG_FAST_CHG_CURRENT_MAX) {
>> +               reg_data = 0x3f;
>> +       } else {
>> +               fast_charge_uamp -= MAX77843_CHG_FAST_CHG_CURRENT_MIN;
>> +               fast_charge_uamp /= MAX77843_CHG_FAST_CHG_CURRENT_STEP;
>> +               reg_data = 0x02 + fast_charge_uamp;
>> +       }
>> +
>> +       ret = regmap_update_bits(regmap, MAX77843_CHG_REG_CHG_CNFG_02,
>> +                       MAX77843_CHG_FAST_CHG_CURRENT_MASK, reg_data);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       return 0;
> 
> Ditto
> 
>> +}
>> +
>> +static int max77843_charger_init(struct max77843_charger *charger)
>> +{
>> +       struct regmap *regmap = charger->regmap;
>> +       int ret;
>> +
>> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_06,
>> +                       MAX77843_CHG_WRITE_CAP_UNBLOCK);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_01,
>> +                       MAX77843_CHG_RESTART_THRESHOLD_DISABLE);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to write configure register\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = max77843_charger_init_fast_charge(charger);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to set fast charge mode.\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = max77843_charger_init_top_off(charger);
>> +       if (ret) {
>> +               dev_err(charger->dev, "Failed to set top off charge mode.\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = max77843_charger_init_current_limit(charger);
>> +
> 
> Why this return value is ignored?
> 

I will fix it.

>> +       return 0;
>> +}
>> +
>> +static struct max77843_charger_info *max77843_charger_dt_init(
>> +               struct platform_device *pdev)
>> +{
>> +       struct max77843_charger_info *info;
>> +       struct device_node *np = pdev->dev.of_node;
>> +       int ret;
>> +
>> +       if (!np) {
>> +               dev_err(&pdev->dev, "No charger OF node\n");
>> +               return ERR_PTR(-EINVAL);
>> +       }
>> +
>> +       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>> +       if (!info)
>> +               return ERR_PTR(-ENOMEM);
>> +
>> +       ret = of_property_read_u32(np, "maxim,fast-charge-uamp",
>> +                       &info->fast_charge_uamp);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Cannot parse fast charge current.\n");
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       ret = of_property_read_u32(np, "maxim,top-off-uamp",
>> +                       &info->top_off_uamp);
>> +       if (ret) {
>> +               dev_err(&pdev->dev,
>> +                       "Cannot parse primary charger termination voltage.\n");
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       ret = of_property_read_u32(np, "maxim,input-uamp-limit",
>> +                       &info->input_uamp_limit);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Cannot parse input current limit value\n");
>> +               return ERR_PTR(ret);
>> +       }
>> +
>> +       return info;
>> +}
>> +
>> +static int max77843_charger_probe(struct platform_device *pdev)
>> +{
>> +       struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
>> +       struct max77843_charger *charger;
>> +       int ret;
>> +
>> +       charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL);
>> +       if (!charger)
>> +               return -ENOMEM;
>> +
>> +       platform_set_drvdata(pdev, charger);
>> +       charger->dev = &pdev->dev;
>> +       charger->max77843 = max77843;
>> +       charger->client = max77843->i2c_chg;
>> +       charger->regmap = max77843->regmap_chg;
>> +
>> +       charger->info = max77843_charger_dt_init(pdev);
>> +       if (IS_ERR_OR_NULL(charger->info)) {
>> +               ret = PTR_ERR(charger->info);
>> +               goto err_i2c;
>> +       }
>> +
>> +       charger->psy.name       = "max77843-charger";
>> +       charger->psy.type       = POWER_SUPPLY_TYPE_MAINS;
>> +       charger->psy.get_property       = max77843_charger_get_property;
>> +       charger->psy.properties         = max77843_charger_props;
>> +       charger->psy.num_properties     = ARRAY_SIZE(max77843_charger_props);
>> +
>> +       ret = max77843_charger_init(charger);
>> +       if (ret)
>> +               goto err_i2c;
>> +
>> +       ret = power_supply_register(&pdev->dev, &charger->psy);
>> +       if (ret) {
>> +               dev_err(&pdev->dev, "Failed  to register power supply\n");
>> +               goto err_i2c;
>> +       }
>> +
>> +       return 0;
>> +
>> +err_i2c:
>> +       i2c_unregister_device(charger->client);
> 
> This seems complicated. The MFD registers the i2c dummy for charger...
> and sometimes charger driver unregisters it and sometimes not. The
> ownership should be in one place: probably in charger driver... but I
> asked about this in another thread so lets discuss it there.
> 

OK. I will revise after discuss it.

> Best regards,
> Krzysztof
> 

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

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

* Re: [PATCH 6/6] Documentation: Add device tree bindings document for max77843
@ 2015-01-23  7:40       ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23  7:40 UTC (permalink / raw)
  To: Chanwoo Choi, Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown

On 01/23/2015 03:25 PM, Chanwoo Choi wrote:
> Hi Jaewon,
> 
> On 01/23/2015 02:02 PM, Jaewon Kim wrote:
>> Add document describing device tree bindings for max77843 MFD.
>> Drivers: MFD core, regulator, extcon, charger and fuelgauge.
>>
>> Cc: Rob Herring <robh+dt@kernel.org>
>> Cc: Pawel Moll <pawel.moll@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
>> Cc: Kumar Gala <galak@codeaurora.org>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> Cc: Sebastian Reichel <sre@kernel.org>
>> Cc: Mark Brown <broonie@kernel.org>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>>  Documentation/devicetree/bindings/mfd/max77843.txt |   87 ++++++++++++++++++++
>>  1 file changed, 87 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mfd/max77843.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/max77843.txt b/Documentation/devicetree/bindings/mfd/max77843.txt
>> new file mode 100644
>> index 0000000..6895604
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/max77843.txt
>> @@ -0,0 +1,87 @@
>> +Maxim MAX77843 multi-function device
>> +
>> +MAX77843 is a Multi-Function Device with the following submodules:
>> +- PMIC	  : 2 SAFEOUT LDOs for USB device
>> +- CHARGER : Li+ battery charger with Fuel Gauge
>> +- MUIC	  : Micro USB Interface Circuit
>> +- HAPTIC  : motor control driver for haptics
> 
> HAPTIC ?
> 
>> +- LED	  : 4 channel RGBW LED
> 
> LED ?
> 
> This patchset don't include andy haptic/led drivers.
> I think it is un-necessary information.
> 
> When you implement the haptic/led driver, you will add the information
> for haptic/led driver.
> 

OK. I will remove them.

>> +
>> +It is interfaced to host controller using I2C.
>> +
>> +Required properties:
>> +- compatible : Must be "maxim,max77843".
>> +- reg : I2C slave address of PMIC block.
>> +- interrupts : I2C line for main SoCs.
>> +- interrupt-parent : The parent of interrupt controller.
>> +
>> +Optional properties:
>> +- regulators : The regulators of max77843 have to be instantiated under subnode
>> +	named "regulators" using the following format.
>> +
>> +	[*]refer : Documentation/devicetree/bindings/regulator/regulator.txt
>> +
>> +	regulators {
>> +		SAFEOUT {
>> +			regulator-name = "SAFEOUT";
>> +		};
>> +	}
>> +
>> +	List of valid regulator names:
>> +	- SAFEOUT1, SAFEOUT2, CHARGER.
>> +
>> +- max77843-muic : This properties used by extcon consumers.
>> +	Required properties:
>> +		- compatible : Must be "maxim,max77842-muic".
>> +
>> +- max77843-charger : There battery charger of MAX77843 have to be instantiated
>> +	under sub-node named "max77843-charger" using the following format.
>> +	Required properties:
>> +		- compatible : Must be "maxim,max77842-charger".
>> +		- maxim,fast-charge-uamp : Fast charge current levels are
>> +			100 mA to 3150 mA programmed by I2C per 100 mA.
>> +		- maxim,top-off-uamp : Top off current threshold levels are
>> +			125 mA to 650 mA programmed by I2C per 75 mA.
>> +		- maxim,input-uamp-limit : Input current limit levels are
>> +			100 mA to 3533 mA programmed by I2C per 33 mA.
>> +- max77843-fuelgauge : There fuelgauge of MAX77843 have to be instantiated
>> +	under sub-node named "max77843-fuelgauge" using the following format.
>> +	Required properties:
>> +		- compatible : Must be "maxim,max77842-fuelgauge".
>> +
>> +Example:
>> +	max77843@66 {
>> +		compatible = "samsung,max77843";
>> +		reg = <0x66>;
>> +		interrupt-parent = <&gpa1>;
>> +		interrupts = <5 2>;
>> +
>> +		regulators {
>> +			SAFEOUT1 {
>> +				regulator-name = "SAFEOUT1";
>> +				regulator-min-microvolt = <3300000>;
>> +				regulator-max-microvolt = <4950000>;
>> +			};
>> +			SAFEOUT2 {
>> +				regulator-name = "SAFEOUT2";
>> +				regulator-min-microvolt = <3300000>;
>> +				regulator-max-microvolt = <4950000>;
>> +			};
> 
> As I knew, max77843 regulator driver supprot 'CHARGER' regulator.
> I think you have to add the 'CHARGER' dt node for regulators.
> 
> 

Right, I will include charger regulator.

>> +		};
>> +
>> +		max77843-muic {
>> +			compatible = "maxim,max77843-muic";
>> +		};
>> +
>> +		max77843-charger {
>> +			compatible = "maxim,max77843-charger";
>> +			maxim,fast-charge-uamp = <450000>;
>> +			maxim,top-off-uamp = <125000>;
>> +			maxim,input-uamp-limit = <500000>;
>> +		};
>> +
>> +		max77843-fuelgauge {
>> +			compatible = "maxim,max77843-fuelgauge";
>> +		};
>> +
>> +	};
>>
> 
> Thanks,
> Chanwoo Choi
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" 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] 41+ messages in thread

* Re: [PATCH 6/6] Documentation: Add device tree bindings document for max77843
@ 2015-01-23  7:40       ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23  7:40 UTC (permalink / raw)
  To: Chanwoo Choi, Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown

On 01/23/2015 03:25 PM, Chanwoo Choi wrote:
> Hi Jaewon,
> 
> On 01/23/2015 02:02 PM, Jaewon Kim wrote:
>> Add document describing device tree bindings for max77843 MFD.
>> Drivers: MFD core, regulator, extcon, charger and fuelgauge.
>>
>> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> Cc: Pawel Moll <pawel.moll-5wv7dgnIgG8@public.gmane.org>
>> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
>> Cc: Ian Campbell <ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg@public.gmane.org>
>> Cc: Kumar Gala <galak-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
>> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> Cc: Chanwoo Choi <cw00.choi-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Cc: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> Cc: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>> ---
>>  Documentation/devicetree/bindings/mfd/max77843.txt |   87 ++++++++++++++++++++
>>  1 file changed, 87 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mfd/max77843.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mfd/max77843.txt b/Documentation/devicetree/bindings/mfd/max77843.txt
>> new file mode 100644
>> index 0000000..6895604
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mfd/max77843.txt
>> @@ -0,0 +1,87 @@
>> +Maxim MAX77843 multi-function device
>> +
>> +MAX77843 is a Multi-Function Device with the following submodules:
>> +- PMIC	  : 2 SAFEOUT LDOs for USB device
>> +- CHARGER : Li+ battery charger with Fuel Gauge
>> +- MUIC	  : Micro USB Interface Circuit
>> +- HAPTIC  : motor control driver for haptics
> 
> HAPTIC ?
> 
>> +- LED	  : 4 channel RGBW LED
> 
> LED ?
> 
> This patchset don't include andy haptic/led drivers.
> I think it is un-necessary information.
> 
> When you implement the haptic/led driver, you will add the information
> for haptic/led driver.
> 

OK. I will remove them.

>> +
>> +It is interfaced to host controller using I2C.
>> +
>> +Required properties:
>> +- compatible : Must be "maxim,max77843".
>> +- reg : I2C slave address of PMIC block.
>> +- interrupts : I2C line for main SoCs.
>> +- interrupt-parent : The parent of interrupt controller.
>> +
>> +Optional properties:
>> +- regulators : The regulators of max77843 have to be instantiated under subnode
>> +	named "regulators" using the following format.
>> +
>> +	[*]refer : Documentation/devicetree/bindings/regulator/regulator.txt
>> +
>> +	regulators {
>> +		SAFEOUT {
>> +			regulator-name = "SAFEOUT";
>> +		};
>> +	}
>> +
>> +	List of valid regulator names:
>> +	- SAFEOUT1, SAFEOUT2, CHARGER.
>> +
>> +- max77843-muic : This properties used by extcon consumers.
>> +	Required properties:
>> +		- compatible : Must be "maxim,max77842-muic".
>> +
>> +- max77843-charger : There battery charger of MAX77843 have to be instantiated
>> +	under sub-node named "max77843-charger" using the following format.
>> +	Required properties:
>> +		- compatible : Must be "maxim,max77842-charger".
>> +		- maxim,fast-charge-uamp : Fast charge current levels are
>> +			100 mA to 3150 mA programmed by I2C per 100 mA.
>> +		- maxim,top-off-uamp : Top off current threshold levels are
>> +			125 mA to 650 mA programmed by I2C per 75 mA.
>> +		- maxim,input-uamp-limit : Input current limit levels are
>> +			100 mA to 3533 mA programmed by I2C per 33 mA.
>> +- max77843-fuelgauge : There fuelgauge of MAX77843 have to be instantiated
>> +	under sub-node named "max77843-fuelgauge" using the following format.
>> +	Required properties:
>> +		- compatible : Must be "maxim,max77842-fuelgauge".
>> +
>> +Example:
>> +	max77843@66 {
>> +		compatible = "samsung,max77843";
>> +		reg = <0x66>;
>> +		interrupt-parent = <&gpa1>;
>> +		interrupts = <5 2>;
>> +
>> +		regulators {
>> +			SAFEOUT1 {
>> +				regulator-name = "SAFEOUT1";
>> +				regulator-min-microvolt = <3300000>;
>> +				regulator-max-microvolt = <4950000>;
>> +			};
>> +			SAFEOUT2 {
>> +				regulator-name = "SAFEOUT2";
>> +				regulator-min-microvolt = <3300000>;
>> +				regulator-max-microvolt = <4950000>;
>> +			};
> 
> As I knew, max77843 regulator driver supprot 'CHARGER' regulator.
> I think you have to add the 'CHARGER' dt node for regulators.
> 
> 

Right, I will include charger regulator.

>> +		};
>> +
>> +		max77843-muic {
>> +			compatible = "maxim,max77843-muic";
>> +		};
>> +
>> +		max77843-charger {
>> +			compatible = "maxim,max77843-charger";
>> +			maxim,fast-charge-uamp = <450000>;
>> +			maxim,top-off-uamp = <125000>;
>> +			maxim,input-uamp-limit = <500000>;
>> +		};
>> +
>> +		max77843-fuelgauge {
>> +			compatible = "maxim,max77843-fuelgauge";
>> +		};
>> +
>> +	};
>>
> 
> Thanks,
> Chanwoo Choi
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

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

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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
  2015-01-23  6:49   ` Chanwoo Choi
@ 2015-01-23  8:43     ` Jaewon Kim
  0 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23  8:43 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown, Beomho Seo

HI Chanwoo,

2015년 01월 23일 15:49에 Chanwoo Choi 이(가) 쓴 글:
> Hi Jaewon,
>
> On 01/23/2015 02:02 PM, Jaewon Kim wrote:
>> This patch adds MAX77843 core/irq driver to support PMIC,
>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>> LED and Haptic device.
>>
>> Cc: Lee Jones <lee.jones@linaro.org>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>>   drivers/mfd/Kconfig                  |   14 ++
>>   drivers/mfd/Makefile                 |    1 +
>>   drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>   include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>   4 files changed, 666 insertions(+)
>>   create mode 100644 drivers/mfd/max77843.c
>>   create mode 100644 include/linux/mfd/max77843-private.h
>>
>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>> index 2e6b731..0c67c79 100644
>> --- a/drivers/mfd/Kconfig
>> +++ b/drivers/mfd/Kconfig
>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>   	  additional drivers must be enabled in order to use the functionality
>>   	  of the device.
>>   
>> +config MFD_MAX77843
>> +	bool "Maxim Semiconductor MAX77843 PMIC Support"
>> +	depends on I2C=y
>> +	select MFD_CORE
>> +	select REGMAP_I2C
>> +	select REGMAP_IRQ
>> +	help
>> +	  Say yes here to add support for Maxim Semiconductor MAX77843.
>> +	  This is companion Power Management IC with LEDs, Haptic, Charger,
>> +	  Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>> +	  This driver provides common support for accessing the device;
>> +	  additional drivers must be enabled in order to use the functionality
>> +	  of the device.
>> +
>>   config MFD_MAX8907
>>   	tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>   	select MFD_CORE
>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>> index 53467e2..fe4f75c 100644
>> --- a/drivers/mfd/Makefile
>> +++ b/drivers/mfd/Makefile
>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)	+= da9063.o
>>   obj-$(CONFIG_MFD_MAX14577)	+= max14577.o
>>   obj-$(CONFIG_MFD_MAX77686)	+= max77686.o
>>   obj-$(CONFIG_MFD_MAX77693)	+= max77693.o
>> +obj-$(CONFIG_MFD_MAX77843)	+= max77843.o
>>   obj-$(CONFIG_MFD_MAX8907)	+= max8907.o
>>   max8925-objs			:= max8925-core.o max8925-i2c.o
>>   obj-$(CONFIG_MFD_MAX8925)	+= max8925.o
>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>> new file mode 100644
>> index 0000000..d7f8b76
>> --- /dev/null
>> +++ b/drivers/mfd/max77843.c
>> @@ -0,0 +1,241 @@
>> +/*
>> + * max77843.c - MFD core driver for the Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#include <linux/err.h>
>> +#include <linux/i2c.h>
>> +#include <linux/init.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/module.h>
>> +#include <linux/mfd/core.h>
>> +#include <linux/mfd/max77843-private.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +
>> +static const struct mfd_cell max77843_devs[] = {
>> +	{
>> +		.name = "max77843-muic",
>> +		.of_compatible = "maxim,max77843-muic",
>> +	}, {
>> +		.name = "max77843-regulator",
>> +		.of_compatible = "maxim,max77843-regulator",
>> +	}, {
>> +		.name = "max77843-charger",
>> +		.of_compatible = "maxim,max77843-charger"
>> +	}, {
>> +		.name = "max77843-fuelgauge",
>> +		.of_compatible = "maxim,max77843-fuelgauge",
>> +	},
>> +};
>> +
>> +static const struct regmap_config max77843_charger_regmap_config = {
>> +	.reg_bits	= 8,
>> +	.val_bits	= 8,
>> +	.max_register	= MAX77843_CHG_REG_END,
>> +};
>> +
>> +static const struct regmap_config max77843_regmap_config = {
>> +	.reg_bits	= 8,
>> +	.val_bits	= 8,
>> +	.max_register	= MAX77843_SYS_REG_END,
>> +};
>> +
>> +static const struct regmap_irq max77843_irqs[] = {
>> +	/* TOPSYS interrupts */
>> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>> +	{ .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>> +};
>> +
>> +static const struct regmap_irq_chip max77843_irq_chip = {
>> +	.name		= "max77843",
>> +	.status_base	= MAX77843_SYS_REG_SYSINTSRC,
>> +	.mask_base	= MAX77843_SYS_REG_SYSINTMASK,
>> +	.mask_invert	= false,
>> +	.num_regs	= 1,
>> +	.irqs		= max77843_irqs,
>> +	.num_irqs	= ARRAY_SIZE(max77843_irqs),
>> +};
>> +
>> +static int max77843_chg_init(struct max77843 *max77843)
>> +{
>> +	int ret;
>> +
>> +	max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
>> +	if (!max77843->i2c_chg) {
>> +		dev_err(&max77843->i2c->dev,
>> +				"Cannot allocate I2C device for Charger\n");
>> +		return PTR_ERR(max77843->i2c_chg);
>> +	}
>> +	i2c_set_clientdata(max77843->i2c_chg, max77843);
>> +
>> +	max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
>> +			&max77843_charger_regmap_config);
>> +	if (IS_ERR(max77843->regmap_chg)) {
>> +		ret = PTR_ERR(max77843->regmap_chg);
>> +		goto err_chg_i2c;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_chg_i2c:
>> +	i2c_unregister_device(max77843->i2c_chg);
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77843_probe(struct i2c_client *i2c,
>> +					const struct i2c_device_id *id)
>> +{
>> +	struct max77843 *max77843;
>> +	int ret;
>> +	unsigned int reg_data;
>> +
>> +	max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
>> +	if (!max77843)
>> +		return -ENOMEM;
>> +
>> +	i2c_set_clientdata(i2c, max77843);
>> +	max77843->dev = &i2c->dev;
>> +	max77843->i2c = i2c;
>> +	max77843->irq = i2c->irq;
>> +
>> +	max77843->regmap = devm_regmap_init_i2c(i2c,
>> +			&max77843_regmap_config);
>> +	if (IS_ERR(max77843->regmap)) {
>> +		dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
>> +		return PTR_ERR(max77843->regmap);
>> +	}
>> +
>> +	ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
>> +			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
>> +			0, &max77843_irq_chip, &max77843->irq_data);
>> +	if (ret) {
>> +		dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = regmap_read(max77843->regmap,
>> +			MAX77843_SYS_REG_PMICID, &reg_data);
>> +	if (ret < 0) {
>> +		dev_err(&i2c->dev, "Failed to read PMIC ID\n");
>> +		goto err_pmic_id;
>> +	}
>> +	dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
>> +
>> +	ret = max77843_chg_init(max77843);
>> +	if (ret) {
>> +		dev_err(&i2c->dev, "Failed to init Charger\n");
>> +		goto err_pmic_id;
>> +	}
>> +
>> +	ret = regmap_update_bits(max77843->regmap,
>> +			MAX77843_SYS_REG_INTSRCMASK,
>> +			MAX77843_INTSRC_MASK_MASK,
>> +			(unsigned int)~MAX77843_INTSRC_MASK_MASK);
> Do you must need the casting with (unsigned int)?
> I think you better use the correct value which
> includes the unmasking data of some interrupts
> instead of (unsigned int)~MAX77843_INTSRC_MASK_MASK.

Okay, I will use with correct value.


>
>> +	if (ret < 0) {
>> +		dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
>> +		goto err_pmic_id;
>> +	}
>> +
>> +	ret = mfd_add_devices(max77843->dev, -1, max77843_devs,
>> +			ARRAY_SIZE(max77843_devs), NULL, 0, NULL);
>> +	if (ret < 0) {
>> +		dev_err(&i2c->dev, "Failed to add mfd device\n");
>> +		goto err_pmic_id;
>> +	}
>> +
>> +	device_init_wakeup(max77843->dev, 1);
>> +
>> +	return 0;
>> +
>> +err_pmic_id:
>> +	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77843_remove(struct i2c_client *i2c)
>> +{
>> +	struct max77843 *max77843 = i2c_get_clientdata(i2c);
>> +
>> +	mfd_remove_devices(max77843->dev);
>> +
>> +	regmap_del_irq_chip(max77843->irq, max77843->irq_data);
>> +
>> +	i2c_unregister_device(max77843->i2c);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id max77843_dt_match[] = {
>> +	{ .compatible = "maxim,max77843", },
>> +	{ /* sentinel */ },
>> +};
>> +
>> +static const struct i2c_device_id max77843_id[] = {
>> +	{ "max77843", },
>> +	{ /* sentinel */ },
>> +};
>> +MODULE_DEVICE_TABLE(i2c, max77843_id);
>> +
>> +static int __maybe_unused max77843_suspend(struct device *dev)
>> +{
>> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>> +	struct max77843 *max77843 = i2c_get_clientdata(i2c);
>> +
>> +	if (device_may_wakeup(dev))
>> +		enable_irq_wake(max77843->irq);
>> +	disable_irq(max77843->irq);
>> +
>> +	return 0;
>> +}
>> +
>> +static int __maybe_unused max77843_resume(struct device *dev)
>> +{
>> +	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
>> +	struct max77843 *max77843 = i2c_get_clientdata(i2c);
>> +
>> +	if (device_may_wakeup(dev))
>> +		disable_irq_wake(max77843->irq);
>> +	enable_irq(max77843->irq);
>> +
>> +	return 0;
>> +}
>> +
>> +static SIMPLE_DEV_PM_OPS(max77843_pm, max77843_suspend, max77843_resume);
>> +
>> +static struct i2c_driver max77843_i2c_driver = {
>> +	.driver		= {
>> +		.name		= "max77843",
>> +		.pm		= &max77843_pm,
>> +		.of_match_table = max77843_dt_match,
>> +	},
>> +	.probe		= max77843_probe,
>> +	.remove		= max77843_remove,
>> +	.id_table	= max77843_id,
>> +};
>> +static int __init max77843_i2c_init(void)
>> +{
>> +	return i2c_add_driver(&max77843_i2c_driver);
>> +}
>> +subsys_initcall(max77843_i2c_init);
>> +
>> +static void __exit max77843_i2c_exit(void)
>> +{
>> +	i2c_del_driver(&max77843_i2c_driver);
>> +}
>> +module_exit(max77843_i2c_exit);
>> +
>> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
>> +MODULE_DESCRIPTION("Maxim MAX77843 multi-function core driver");
>> +MODULE_LICENSE("GPL");
>> diff --git a/include/linux/mfd/max77843-private.h b/include/linux/mfd/max77843-private.h
>> new file mode 100644
>> index 0000000..560ed73
>> --- /dev/null
>> +++ b/include/linux/mfd/max77843-private.h
>> @@ -0,0 +1,410 @@
>> +/*
>> + * max77843-private.h - Common API for the Maxim MAX77843 internal sub chip
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +
>> +#ifndef __MAX77843_PRIVATE_H_
>> +#define __MAX77843_PRIVATE_H_
>> +
>> +#include <linux/i2c.h>
>> +#include <linux/regmap.h>
>> +
>> +#define I2C_ADDR_TOPSYS	(0xCC >> 1)
>> +#define I2C_ADDR_CHG	(0xD2 >> 1)
>> +#define I2C_ADDR_FG	(0x6C >> 1)
>> +#define I2C_ADDR_MUIC	(0x4A >> 1)
>> +
>> +/* Topsys, Haptic and LED registers */
>> +enum max77843_sys_reg {
>> +	MAX77843_SYS_REG_PMICID		= 0x00,
>> +	MAX77843_SYS_REG_PMICREV	= 0x01,
>> +	MAX77843_SYS_REG_MAINCTRL1	= 0x02,
>> +	MAX77843_SYS_REG_INTSRC		= 0x22,
>> +	MAX77843_SYS_REG_INTSRCMASK	= 0x23,
>> +	MAX77843_SYS_REG_SYSINTSRC	= 0x24,
>> +	MAX77843_SYS_REG_SYSINTMASK	= 0x26,
>> +	MAX77843_SYS_REG_TOPSYS_STAT	= 0x28,
>> +	MAX77843_SYS_REG_SAFEOUTCTRL	= 0xC6,
>> +
>> +	MAX77843_SYS_REG_END,
>> +};
>> +
>> +enum max77843_led_reg {
>> +	MAX77843_LED_REG_LEDEN		= 0x30,
>> +	MAX77843_LED_REG_LED0BRT	= 0x31,
>> +	MAX77843_LED_REG_LED1BRT	= 0x32,
>> +	MAX77843_LED_REG_LED2BRT	= 0x33,
>> +	MAX77843_LED_REG_LED3BRT	= 0x34,
>> +	MAX77843_LED_REG_LEDBLNK	= 0x38,
>> +	MAX77843_LED_REG_LEDRAMP	= 0x36,
>> +
>> +	MAX77843_LED_REG_END,
>> +};
>> +
>> +/* Charger registers */
>> +enum max77843_charger_reg {
>> +	MAX77843_CHG_REG_CHG_INT	= 0xB0,
>> +	MAX77843_CHG_REG_CHG_INT_MASK	= 0xB1,
>> +	MAX77843_CHG_REG_CHG_INT_OK	= 0xB2,
>> +	MAX77843_CHG_REG_CHG_DTLS_00	= 0xB3,
>> +	MAX77843_CHG_REG_CHG_DTLS_01	= 0xB4,
>> +	MAX77843_CHG_REG_CHG_DTLS_02	= 0xB5,
>> +	MAX77843_CHG_REG_CHG_CNFG_00	= 0xB7,
>> +	MAX77843_CHG_REG_CHG_CNFG_01	= 0xB8,
>> +	MAX77843_CHG_REG_CHG_CNFG_02	= 0xB9,
>> +	MAX77843_CHG_REG_CHG_CNFG_03	= 0xBA,
>> +	MAX77843_CHG_REG_CHG_CNFG_04	= 0xBB,
>> +	MAX77843_CHG_REG_CHG_CNFG_06	= 0xBD,
>> +	MAX77843_CHG_REG_CHG_CNFG_07	= 0xBE,
>> +	MAX77843_CHG_REG_CHG_CNFG_09	= 0xC0,
>> +	MAX77843_CHG_REG_CHG_CNFG_10	= 0xC1,
>> +	MAX77843_CHG_REG_CHG_CNFG_11	= 0xC2,
>> +	MAX77843_CHG_REG_CHG_CNFG_12	= 0xC3,
>> +
>> +	MAX77843_CHG_REG_END,
>> +};
>> +
>> +/* Fuel gauge registers */
>> +enum max77843_fuelgauge {
>> +	MAX77843_FG_REG_STATUS		= 0x00,
>> +	MAX77843_FG_REG_VALRT_TH	= 0x01,
>> +	MAX77843_FG_REG_TALRT_TH	= 0x02,
>> +	MAX77843_FG_REG_SALRT_TH	= 0x03,
>> +	MAX77843_FG_RATE_AT_RATE	= 0x04,
>> +	MAX77843_FG_REG_REMCAP_REP	= 0x05,
>> +	MAX77843_FG_REG_SOCREP		= 0x06,
>> +	MAX77843_FG_REG_AGE		= 0x07,
>> +	MAX77843_FG_REG_TEMP		= 0x08,
>> +	MAX77843_FG_REG_VCELL		= 0x09,
>> +	MAX77843_FG_REG_CURRENT		= 0x0A,
>> +	MAX77843_FG_REG_AVG_CURRENT	= 0x0B,
>> +	MAX77843_FG_REG_SOCMIX		= 0x0D,
>> +	MAX77843_FG_REG_SOCAV		= 0x0E,
>> +	MAX77843_FG_REG_REMCAP_MIX	= 0x0F,
>> +	MAX77843_FG_REG_FULLCAP		= 0x10,
>> +	MAX77843_FG_REG_AVG_TEMP	= 0x16,
>> +	MAX77843_FG_REG_CYCLES		= 0x17,
>> +	MAX77843_FG_REG_AVG_VCELL	= 0x19,
>> +	MAX77843_FG_REG_CONFIG		= 0x1D,
>> +	MAX77843_FG_REG_REMCAP_AV	= 0x1F,
>> +	MAX77843_FG_REG_FULLCAP_NOM	= 0x23,
>> +	MAX77843_FG_REG_MISCCFG		= 0x2B,
>> +	MAX77843_FG_REG_RCOMP		= 0x38,
>> +	MAX77843_FG_REG_FSTAT		= 0x3D,
>> +	MAX77843_FG_REG_DQACC		= 0x45,
>> +	MAX77843_FG_REG_DPACC		= 0x46,
>> +	MAX77843_FG_REG_OCV		= 0xEE,
>> +	MAX77843_FG_REG_VFOCV		= 0xFB,
>> +	MAX77843_FG_SOCVF		= 0xFF,
>> +
>> +	MAX77843_FG_END,
>> +};
>> +
>> +/* Muic registers */
>> +enum max77843_muic_reg {
>> +	MAX77843_MUIC_REG_ID		= 0x00,
>> +	MAX77843_MUIC_REG_INT1		= 0x01,
>> +	MAX77843_MUIC_REG_INT2		= 0x02,
>> +	MAX77843_MUIC_REG_INT3		= 0x03,
>> +	MAX77843_MUIC_REG_STATUS1	= 0x04,
>> +	MAX77843_MUIC_REG_STATUS2	= 0x05,
>> +	MAX77843_MUIC_REG_STATUS3	= 0x06,
>> +	MAX77843_MUIC_REG_INTMASK1	= 0x07,
>> +	MAX77843_MUIC_REG_INTMASK2	= 0x08,
>> +	MAX77843_MUIC_REG_INTMASK3	= 0x09,
>> +	MAX77843_MUIC_REG_CDETCTRL1	= 0x0A,
>> +	MAX77843_MUIC_REG_CDETCTRL2	= 0x0B,
>> +	MAX77843_MUIC_REG_CONTROL1	= 0x0C,
>> +	MAX77843_MUIC_REG_CONTROL2	= 0x0D,
>> +	MAX77843_MUIC_REG_CONTROL3	= 0x0E,
>> +	MAX77843_MUIC_REG_CONTROL4	= 0x16,
>> +	MAX77843_MUIC_REG_HVCONTROL1	= 0x17,
>> +	MAX77843_MUIC_REG_HVCONTROL2	= 0x18,
>> +
>> +	MAX77843_MUIC_REG_END,
>> +};
>> +
>> +enum max77843_irq {
>> +	/* Topsys: SYSTEM */
>> +	MAX77843_SYS_IRQ_SYSINTSRC_SYSUVLO_INT,
>> +	MAX77843_SYS_IRQ_SYSINTSRC_SYSOVLO_INT,
>> +	MAX77843_SYS_IRQ_SYSINTSRC_TSHDN_INT,
>> +	MAX77843_SYS_IRQ_SYSINTSRC_TM_INT,
>> +
>> +	/* Charger: CHG_INT */
>> +	MAX77843_CHG_IRQ_CHG_INT_BYP_I,
>> +	MAX77843_CHG_IRQ_CHG_INT_BATP_I,
>> +	MAX77843_CHG_IRQ_CHG_INT_BAT_I,
>> +	MAX77843_CHG_IRQ_CHG_INT_CHG_I,
>> +	MAX77843_CHG_IRQ_CHG_INT_WCIN_I,
>> +	MAX77843_CHG_IRQ_CHG_INT_CHGIN_I,
>> +	MAX77843_CHG_IRQ_CHG_INT_AICL_I,
>> +
>> +	MAX77843_IRQ_NUM,
>> +};
>> +
>> +enum max77843_irq_muic {
>> +	/* MUIC: INT1 */
>> +	MAX77843_MUIC_IRQ_INT1_ADC,
>> +	MAX77843_MUIC_IRQ_INT1_ADCERROR,
>> +	MAX77843_MUIC_IRQ_INT1_ADC1K,
>> +
>> +	/* MUIC: INT2 */
>> +	MAX77843_MUIC_IRQ_INT2_CHGTYP,
>> +	MAX77843_MUIC_IRQ_INT2_CHGDETRUN,
>> +	MAX77843_MUIC_IRQ_INT2_DCDTMR,
>> +	MAX77843_MUIC_IRQ_INT2_DXOVP,
>> +	MAX77843_MUIC_IRQ_INT2_VBVOLT,
>> +
>> +	/* MUIC: INT3 */
>> +	MAX77843_MUIC_IRQ_INT3_VBADC,
>> +	MAX77843_MUIC_IRQ_INT3_VDNMON,
>> +	MAX77843_MUIC_IRQ_INT3_DNRES,
>> +	MAX77843_MUIC_IRQ_INT3_MPNACK,
>> +	MAX77843_MUIC_IRQ_INT3_MRXBUFOW,
>> +	MAX77843_MUIC_IRQ_INT3_MRXTRF,
>> +	MAX77843_MUIC_IRQ_INT3_MRXPERR,
>> +	MAX77843_MUIC_IRQ_INT3_MRXRDY,
>> +
>> +	MAX77843_MUIC_IRQ_NUM,
>> +};
>> +
>> +/* MAX77843 interrupts */
>> +#define MAX77843_SYS_IRQ_SYSUVLO_INT		BIT(0)
>> +#define MAX77843_SYS_IRQ_SYSOVLO_INT		BIT(1)
>> +#define MAX77843_SYS_IRQ_TSHDN_INT		BIT(2)
>> +#define MAX77843_SYS_IRQ_TM_INT			BIT(3)
>> +
>> +/* Max77843 charger insterrupts */
>> +#define MAX77843_CHG_BYP_I			BIT(0)
>> +#define MAX77843_CHG_BATP_I			BIT(2)
>> +#define MAX77843_CHG_BAT_I			BIT(3)
>> +#define MAX77843_CHG_CHG_I			BIT(4)
>> +#define MAX77843_CHG_WCIN_I			BIT(5)
>> +#define MAX77843_CHG_CHGIN_I			BIT(6)
>> +#define MAX77843_CHG_AICL_I			BIT(7)
>> +
>> +/* MAX77843 CHG_INT_OK register */
>> +#define MAX77843_CHG_BYP_OK			BIT(0)
>> +#define MAX77843_CHG_BATP_OK			BIT(2)
>> +#define MAX77843_CHG_BAT_OK			BIT(3)
>> +#define MAX77843_CHG_CHG_OK			BIT(4)
>> +#define MAX77843_CHG_WCIN_OK			BIT(5)
>> +#define MAX77843_CHG_CHGIN_OK			BIT(6)
>> +#define MAX77843_CHG_AICL_OK			BIT(7)
>> +
>> +/* MAX77843 CHG_DETAILS_00 register */
>> +#define MAX77843_CHG_BAT_DTLS			BIT(0)
>> +
>> +/* MAX77843 CHG_DETAILS_01 register */
>> +#define MAX77843_CHG_DTLS_MASK			0x0f
>> +#define MAX77843_CHG_PQ_MODE			0x00
>> +#define MAX77843_CHG_CC_MODE			0x01
>> +#define MAX77843_CHG_CV_MODE			0x02
>> +#define MAX77843_CHG_TO_MODE			0x03
>> +#define MAX77843_CHG_DO_MODE			0x04
>> +#define MAX77843_CHG_HT_MODE			0x05
>> +#define MAX77843_CHG_TF_MODE			0x06
>> +#define MAX77843_CHG_TS_MODE			0x07
>> +#define MAX77843_CHG_OFF_MODE			0x08
>> +
>> +#define MAX77843_CHG_BAT_DTLS_MASK		0xf0
>> +#define MAX77843_CHG_NO_BAT			(0x00 << 4)
>> +#define MAX77843_CHG_LOW_VOLT_BAT		(0x01 << 4)
>> +#define MAX77843_CHG_LONG_BAT_TIME		(0x02 << 4)
>> +#define MAX77843_CHG_OK_BAT			(0x03 << 4)
>> +#define MAX77843_CHG_OK_LOW_VOLT_BAT		(0x04 << 4)
>> +#define MAX77843_CHG_OVER_VOLT_BAT		(0x05 << 4)
>> +#define MAX77843_CHG_OVER_CURRENT_BAT		(0x06 << 4)
>> +
>> +/* MAX77843 CHG_CNFG_00 register */
>> +#define MAX77843_CHG_DISABLE			0x00
>> +#define MAX77843_CHG_ENABLE			0x05
>> +#define MAX77843_CHG_MASK			0x01
>> +#define MAX77843_CHG_BUCK_MASK			0x04
>> +
>> +/* MAX77843 CHG_CNFG_01 register */
>> +#define MAX77843_CHG_RESTART_THRESHOLD_100	0x00
>> +#define MAX77843_CHG_RESTART_THRESHOLD_150	0x10
>> +#define MAX77843_CHG_RESTART_THRESHOLD_200	0x20
>> +#define MAX77843_CHG_RESTART_THRESHOLD_DISABLE	0x30
>> +
>> +/* MAX77843 CHG_CNFG_02 register */
>> +#define MAX77843_CHG_FAST_CHG_CURRENT_MIN	100000
>> +#define MAX77843_CHG_FAST_CHG_CURRENT_MAX	3150000
>> +#define MAX77843_CHG_FAST_CHG_CURRENT_STEP	50000
>> +#define MAX77843_CHG_FAST_CHG_CURRENT_MASK	0x3f
>> +#define MAX77843_CHG_OTG_ILIMIT_500		(0x00 << 6)
>> +#define MAX77843_CHG_OTG_ILIMIT_900		(0x01 << 6)
>> +#define MAX77843_CHG_OTG_ILIMIT_1200		(0x02 << 6)
>> +#define MAX77843_CHG_OTG_ILIMIT_1500		(0x03 << 6)
>> +#define MAX77843_CHG_OTG_ILIMIT_MASK		0xc0
>> +
>> +/* MAX77843 CHG_CNFG_03 register */
>> +#define MAX77843_CHG_TOP_OFF_CURRENT_MIN	125000
>> +#define MAX77843_CHG_TOP_OFF_CURRENT_MAX	650000
>> +#define MAX77843_CHG_TOP_OFF_CURRENT_STEP	75000
>> +#define MAX77843_CHG_TOP_OFF_CURRENT_MASK	0x07
>> +
>> +/* MAX77843 CHG_CNFG_06 register */
>> +#define MAX77843_CHG_WRITE_CAP_BLOCK		0x10
>> +#define MAX77843_CHG_WRITE_CAP_UNBLOCK		0x0C
>> +
>> +/* MAX77843_CHG_CNFG_09_register */
>> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MIN	100000
>> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_MAX	4000000
>> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_REF	3367000
>> +#define MAX77843_CHG_INPUT_CURRENT_LIMIT_STEP	33000
>> +
>> +#define MAX77843_MUIC_ADC			BIT(0)
>> +#define MAX77843_MUIC_ADCERROR			BIT(2)
>> +#define MAX77843_MUIC_ADC1K			BIT(3)
>> +
>> +#define MAX77843_MUIC_CHGTYP			BIT(0)
>> +#define MAX77843_MUIC_CHGDETRUN			BIT(1)
>> +#define MAX77843_MUIC_DCDTMR			BIT(2)
>> +#define MAX77843_MUIC_DXOVP			BIT(3)
>> +#define MAX77843_MUIC_VBVOLT			BIT(4)
>> +
>> +#define MAX77843_MUIC_VBADC			BIT(0)
>> +#define MAX77843_MUIC_VDNMON			BIT(1)
>> +#define MAX77843_MUIC_DNRES			BIT(2)
>> +#define MAX77843_MUIC_MPNACK			BIT(3)
>> +#define MAX77843_MUIC_MRXBUFOW			BIT(4)
>> +#define MAX77843_MUIC_MRXTRF			BIT(5)
>> +#define MAX77843_MUIC_MRXPERR			BIT(6)
>> +#define MAX77843_MUIC_MRXRDY			BIT(7)
>> +
>> +/* MAX77843 INTSRCMASK register */
>> +#define MAX77843_INTSRCMASK_CHGR		0
>> +#define MAX77843_INTSRCMASK_SYS			1
>> +#define MAX77843_INTSRCMASK_FG			2
>> +#define MAX77843_INTSRCMASK_MUIC		3
>> +
>> +#define MAX77843_INTSRCMASK_CHGR_MASK          BIT(MAX77843_INTSRCMASK_CHGR)
>> +#define MAX77843_INTSRCMASK_SYS_MASK           BIT(MAX77843_INTSRCMASK_SYS)
>> +#define MAX77843_INTSRCMASK_FG_MASK            BIT(MAX77843_INTSRCMASK_FG)
>> +#define MAX77843_INTSRCMASK_MUIC_MASK          BIT(MAX77843_INTSRCMASK_MUIC)
>> +
>> +#define MAX77843_INTSRC_MASK_MASK \
>> +		(MAX77843_INTSRCMASK_MUIC_MASK | MAX77843_INTSRCMASK_FG_MASK | \
>> +		MAX77843_INTSRCMASK_SYS_MASK | MAX77843_INTSRCMASK_CHGR_MASK)
>> +
>> +/* MAX77843 STATUS register*/
>> +#define STATUS1_ADC_SHIFT			0
>> +#define STATUS1_ADCERROR_SHIFT			6
>> +#define STATUS1_ADC1K_SHIFT			7
>> +#define STATUS2_CHGTYP_SHIFT			0
>> +#define STATUS2_CHGDETRUN_SHIFT			3
>> +#define STATUS2_DCDTMR_SHIFT			4
>> +#define STATUS2_DXOVP_SHIFT			5
>> +#define STATUS2_VBVOLT_SHIFT			6
>> +#define STATUS3_VBADC_SHIFT			0
>> +#define STATUS3_VDNMON_SHIFT			4
>> +#define STATUS3_DNRES_SHIFT			5
>> +#define STATUS3_MPNACK_SHIFT			6
>> +
>> +#define MAX77843_MUIC_STATUS1_ADC_MASK		(0x1f << STATUS1_ADC_SHIFT)
>> +#define MAX77843_MUIC_STATUS1_ADCERROR_MASK	BIT(STATUS1_ADCERROR_SHIFT)
>> +#define MAX77843_MUIC_STATUS1_ADC1K_MASK	BIT(STATUS1_ADC1K_SHIFT)
>> +#define MAX77843_MUIC_STATUS2_CHGTYP_MASK	(0x7 << STATUS2_CHGTYP_SHIFT)
>> +#define MAX77843_MUIC_STATUS2_CHGDETRUN_MASK	BIT(STATUS2_CHGDETRUN_SHIFT)
>> +#define MAX77843_MUIC_STATUS2_DCDTMR_MASK	BIT(STATUS2_DCDTMR_SHIFT)
>> +#define MAX77843_MUIC_STATUS2_DXOVP_MASK	BIT(STATUS2_DXOVP_SHIFT)
>> +#define MAX77843_MUIC_STATUS2_VBVOLT_MASK	BIT(STATUS2_VBVOLT_SHIFT)
>> +#define MAX77843_MUIC_STATUS3_VBADC_MASK	(0xf << STATUS3_VBADC_SHIFT)
>> +#define MAX77843_MUIC_STATUS3_VDNMON_MASK	BIT(STATUS3_VDNMON_SHIFT)
>> +#define MAX77843_MUIC_STATUS3_DNRES_MASK	BIT(STATUS3_DNRES_SHIFT)
>> +#define MAX77843_MUIC_STATUS3_MPNACK_MASK	BIT(STATUS3_MPNACK_SHIFT)
>> +
>> +/* MAX77843 CONTROL register */
>> +#define CONTROL1_COMP1SW_SHIFT			0
>> +#define CONTROL1_COMP2SW_SHIFT			3
>> +#define CONTROL1_IDBEN_SHIFT			7
>> +#define CONTROL2_LOWPWR_SHIFT			0
>> +#define CONTROL2_ADCEN_SHIFT			1
>> +#define CONTROL2_CPEN_SHIFT			2
>> +#define CONTROL2_ACC_DET_SHIFT			5
>> +#define CONTROL2_USBCPINT_SHIFT			6
>> +#define CONTROL2_RCPS_SHIFT			7
>> +#define CONTROL3_JIGSET_SHIFT			0
>> +#define CONTROL4_ADCDBSET_SHIFT			0
>> +#define CONTROL4_USBAUTO_SHIFT			4
>> +#define CONTROL4_FCTAUTO_SHIFT			5
>> +#define CONTROL4_ADCMODE_SHIFT			6
>> +
>> +#define MAX77843_MUIC_CONTROL1_COMP1SW_MASK	(0x7 << CONTROL1_COMP1SW_SHIFT)
>> +#define MAX77843_MUIC_CONTROL1_COMP2SW_MASK	(0x7 << CONTROL1_COMP2SW_SHIFT)
>> +#define MAX77843_MUIC_CONTROL1_IDBEN_MASK	BIT(CONTROL1_IDBEN_SHIFT)
>> +#define MAX77843_MUIC_CONTROL2_LOWPWR_MASK	BIT(CONTROL2_LOWPWR_SHIFT)
>> +#define MAX77843_MUIC_CONTROL2_ADCEN_MASK	BIT(CONTROL2_ADCEN_SHIFT)
>> +#define MAX77843_MUIC_CONTROL2_CPEN_MASK	BIT(CONTROL2_CPEN_SHIFT)
>> +#define MAX77843_MUIC_CONTROL2_ACC_DET_MASK	BIT(CONTROL2_ACC_DET_SHIFT)
>> +#define MAX77843_MUIC_CONTROL2_USBCPINT_MASK	BIT(CONTROL2_USBCPINT_SHIFT)
>> +#define MAX77843_MUIC_CONTROL2_RCPS_MASK	BIT(CONTROL2_RCPS_SHIFT)
>> +#define MAX77843_MUIC_CONTROL3_JIGSET_MASK	(0x3 << CONTROL3_JIGSET_SHIFT)
>> +#define MAX77843_MUIC_CONTROL4_ADCDBSET_MASK	(0x3 << CONTROL4_ADCDBSET_SHIFT)
>> +#define MAX77843_MUIC_CONTROL4_USBAUTO_MASK	BIT(CONTROL4_USBAUTO_SHIFT)
>> +#define MAX77843_MUIC_CONTROL4_FCTAUTO_MASK	BIT(CONTROL4_FCTAUTO_SHIFT)
>> +#define MAX77843_MUIC_CONTROL4_ADCMODE_MASK	(0x3 << CONTROL4_ADCMODE_SHIFT)
>> +
>> +/* MAX77843 switch port */
>> +#define MAX77843_SIWTH_PORT \
>> +(MAX77843_MUIC_CONTROL1_COMP1SW_MASK | MAX77843_MUIC_CONTROL1_COMP2SW_MASK)
>> +
>> +#define MAX77843_SWITCH_OPEN \
>> +		(0 << CONTROL1_COMP1SW_SHIFT | 0 << CONTROL1_COMP2SW_SHIFT)
>> +#define MAX77843_SWITCH_USB \
>> +		(1 << CONTROL1_COMP1SW_SHIFT | 1 << CONTROL1_COMP2SW_SHIFT)
>> +#define MAX77843_SWITCH_AUDIO \
>> +		(2 << CONTROL1_COMP1SW_SHIFT | 2 << CONTROL1_COMP2SW_SHIFT)
>> +#define MAX77843_SWITCH_UART \
>> +		(3 << CONTROL1_COMP1SW_SHIFT | 3 << CONTROL1_COMP2SW_SHIFT)
>> +#define MAX77843_SWITCH_AUX_USB \
>> +		(4 << CONTROL1_COMP1SW_SHIFT | 4 << CONTROL1_COMP2SW_SHIFT)
>> +#define MAX77843_SWITCH_AUX_UART \
>> +		(5 << CONTROL1_COMP1SW_SHIFT | 5 << CONTROL1_COMP2SW_SHIFT)
>> +
>> +/* MAX77843 SAFEOUT LDO Control register */
>> +#define SAFEOUTCTRL_SAFEOUT1_SHIFT		0
>> +#define SAFEOUTCTRL_SAFEOUT2_SHIFT		2
>> +#define SAFEOUTCTRL_ENSAFEOUT1_SHIFT		6
>> +#define SAFEOUTCTRL_ENSAFEOUT2_SHIFT		7
>> +
>> +#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1 \
>> +		BIT(SAFEOUTCTRL_ENSAFEOUT1_SHIFT)
>> +#define MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2 \
>> +		BIT(SAFEOUTCTRL_ENSAFEOUT2_SHIFT)
>> +#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK \
>> +		(0x3 << SAFEOUTCTRL_SAFEOUT1_SHIFT)
>> +#define MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK \
>> +		(0x3 << SAFEOUTCTRL_SAFEOUT2_SHIFT)
>> +
>> +struct max77843 {
>> +	struct device *dev;
>> +
>> +	struct i2c_client *i2c;
>> +	struct i2c_client *i2c_chg;
>> +	struct i2c_client *i2c_fuel;
>> +	struct i2c_client *i2c_muic;
>> +
>> +	struct regmap *regmap;
>> +	struct regmap *regmap_chg;
>> +	struct regmap *regmap_fuel;
>> +	struct regmap *regmap_muic;
>> +
>> +	struct regmap_irq_chip_data *irq_data;
>> +	struct regmap_irq_chip_data *irq_data_chg;
>> +	struct regmap_irq_chip_data *irq_data_fuel;
>> +	struct regmap_irq_chip_data *irq_data_muic;
>> +
>> +	int irq;
>> +};
>> +#endif /* __MAX77843_H__ */
>>
> Thanks,
> Chanwoo Choi
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" 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] 41+ messages in thread

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
  2015-01-23  7:16       ` Krzysztof Kozlowski
@ 2015-01-23 11:10         ` Beomho Seo
  2015-01-23 11:18           ` Krzysztof Kozlowski
  0 siblings, 1 reply; 41+ messages in thread
From: Beomho Seo @ 2015-01-23 11:10 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Jaewon Kim, linux-kernel, devicetree, linux-pm, Inki Dae,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Lee Jones, Chanwoo Choi, Sebastian Reichel, Mark Brown

On 01/23/2015 04:16 PM, Krzysztof Kozlowski wrote:
> On pią, 2015-01-23 at 15:41 +0900, Beomho Seo wrote:
>> On 01/23/2015 03:32 PM, Krzysztof Kozlowski wrote:
>>> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
>>>> This patch adds MAX77843 core/irq driver to support PMIC,
>>>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>>>> LED and Haptic device.
>>>>
>>>> Cc: Lee Jones <lee.jones@linaro.org>
>>>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>>>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>>>> ---
>>>>  drivers/mfd/Kconfig                  |   14 ++
>>>>  drivers/mfd/Makefile                 |    1 +
>>>>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>>>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>>>  4 files changed, 666 insertions(+)
>>>>  create mode 100644 drivers/mfd/max77843.c
>>>>  create mode 100644 include/linux/mfd/max77843-private.h
>>>>
>>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>>>> index 2e6b731..0c67c79 100644
>>>> --- a/drivers/mfd/Kconfig
>>>> +++ b/drivers/mfd/Kconfig
>>>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>>>           additional drivers must be enabled in order to use the functionality
>>>>           of the device.
>>>>
>>>> +config MFD_MAX77843
>>>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
>>>> +       depends on I2C=y
>>>> +       select MFD_CORE
>>>> +       select REGMAP_I2C
>>>> +       select REGMAP_IRQ
>>>> +       help
>>>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
>>>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
>>>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>>>> +         This driver provides common support for accessing the device;
>>>> +         additional drivers must be enabled in order to use the functionality
>>>> +         of the device.
>>>> +
>>>>  config MFD_MAX8907
>>>>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>>>         select MFD_CORE
>>>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>>>> index 53467e2..fe4f75c 100644
>>>> --- a/drivers/mfd/Makefile
>>>> +++ b/drivers/mfd/Makefile
>>>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>>>>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>>>>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>>>>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
>>>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>>>>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>>>>  max8925-objs                   := max8925-core.o max8925-i2c.o
>>>>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
>>>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>>>> new file mode 100644
>>>> index 0000000..d7f8b76
>>>> --- /dev/null
>>>> +++ b/drivers/mfd/max77843.c
>>>> @@ -0,0 +1,241 @@
>>>> +/*
>>>> + * max77843.c - MFD core driver for the Maxim MAX77843
>>>> + *
>>>> + * Copyright (C) 2014 Samsung Electrnoics
>>>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License as published by
>>>> + * the Free Software Foundation; either version 2 of the License, or
>>>> + * (at your option) any later version.
>>>> + */
>>>> +
>>>> +#include <linux/err.h>
>>>> +#include <linux/i2c.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/mfd/core.h>
>>>> +#include <linux/mfd/max77843-private.h>
>>>> +#include <linux/of_device.h>
>>>> +#include <linux/platform_device.h>
>>>> +
>>>> +static const struct mfd_cell max77843_devs[] = {
>>>> +       {
>>>> +               .name = "max77843-muic",
>>>> +               .of_compatible = "maxim,max77843-muic",
>>>> +       }, {
>>>> +               .name = "max77843-regulator",
>>>> +               .of_compatible = "maxim,max77843-regulator",
>>>> +       }, {
>>>> +               .name = "max77843-charger",
>>>> +               .of_compatible = "maxim,max77843-charger"
>>>> +       }, {
>>>> +               .name = "max77843-fuelgauge",
>>>> +               .of_compatible = "maxim,max77843-fuelgauge",
>>>> +       },
>>>> +};
>>>> +
>>>> +static const struct regmap_config max77843_charger_regmap_config = {
>>>> +       .reg_bits       = 8,
>>>> +       .val_bits       = 8,
>>>> +       .max_register   = MAX77843_CHG_REG_END,
>>>> +};
>>>> +
>>>> +static const struct regmap_config max77843_regmap_config = {
>>>> +       .reg_bits       = 8,
>>>> +       .val_bits       = 8,
>>>> +       .max_register   = MAX77843_SYS_REG_END,
>>>> +};
>>>> +
>>>> +static const struct regmap_irq max77843_irqs[] = {
>>>> +       /* TOPSYS interrupts */
>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>>>> +};
>>>> +
>>>> +static const struct regmap_irq_chip max77843_irq_chip = {
>>>> +       .name           = "max77843",
>>>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
>>>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
>>>> +       .mask_invert    = false,
>>>> +       .num_regs       = 1,
>>>> +       .irqs           = max77843_irqs,
>>>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
>>>> +};
>>>> +
>>>> +static int max77843_chg_init(struct max77843 *max77843)
>>>> +{
>>>
>>> Could this function be moved to the charger driver? This way the
>>> driver will manage its own resources instead of depending on parent
>>> MFD driver.
>>>
>>
>> Charger regulator and Charger share same resources.
>> So I include this function core driver.
> 
> OK, I see... Could you describe it in comments somewhere? For example in
> comment above the function. Currently this looks like only as regmap for
> charger.
> 

Charger regulator and Charger use same regmap.

> Unfortunately current solution imposes problem with releasing resources.
> Who is the owner of i2c dummy device?
> 

Core driver owner of i2c dummy device.

> 1. The charger driver will unregister it if max77843_charger_probe()
> fails. What will happen with regulator driver in such case?
> 

Charger is enabled/disabled by Charger regulator.
Currently, If charger probe fails, charger regulator failed to read regmap and occur panic(It have to fix.)


> 2. Who will release this i2c dummy device in normal unbind? Currently it
> leaks.
> 

I think core driver release i2c dummy device in normal unbind.
We need to more discussion about this problem.
If you have any idea, I hope tell me. Again, Thank you for your advice.

Thanks,
Beomho Seo


> Best regards,
> Krzysztof
> 
>>
>>>> +       int ret;
>>>> +
>>>> +       max77843->i2c_chg = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_CHG);
>>>> +       if (!max77843->i2c_chg) {
>>>> +               dev_err(&max77843->i2c->dev,
>>>> +                               "Cannot allocate I2C device for Charger\n");
>>>> +               return PTR_ERR(max77843->i2c_chg);
>>>> +       }
>>>> +       i2c_set_clientdata(max77843->i2c_chg, max77843);
>>>> +
>>>> +       max77843->regmap_chg = devm_regmap_init_i2c(max77843->i2c_chg,
>>>> +                       &max77843_charger_regmap_config);
>>>> +       if (IS_ERR(max77843->regmap_chg)) {
>>>> +               ret = PTR_ERR(max77843->regmap_chg);
>>>> +               goto err_chg_i2c;
>>>> +       }
>>>> +
>>>> +       return 0;
>>>> +
>>>> +err_chg_i2c:
>>>> +       i2c_unregister_device(max77843->i2c_chg);
>>>> +
>>>> +       return ret;
>>>> +}
>>>> +
>>>> +static int max77843_probe(struct i2c_client *i2c,
>>>> +                                       const struct i2c_device_id *id)
>>>> +{
>>>> +       struct max77843 *max77843;
>>>> +       int ret;
>>>> +       unsigned int reg_data;
>>>> +
>>>> +       max77843 = devm_kzalloc(&i2c->dev, sizeof(*max77843), GFP_KERNEL);
>>>> +       if (!max77843)
>>>> +               return -ENOMEM;
>>>> +
>>>> +       i2c_set_clientdata(i2c, max77843);
>>>> +       max77843->dev = &i2c->dev;
>>>> +       max77843->i2c = i2c;
>>>> +       max77843->irq = i2c->irq;
>>>> +
>>>> +       max77843->regmap = devm_regmap_init_i2c(i2c,
>>>> +                       &max77843_regmap_config);
>>>> +       if (IS_ERR(max77843->regmap)) {
>>>> +               dev_err(&i2c->dev, "Failed to allocate topsys register map\n");
>>>> +               return PTR_ERR(max77843->regmap);
>>>> +       }
>>>> +
>>>> +       ret = regmap_add_irq_chip(max77843->regmap, max77843->irq,
>>>> +                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
>>>> +                       0, &max77843_irq_chip, &max77843->irq_data);
>>>
>>> Why shared IRQ?
>>>
>>>> +       if (ret) {
>>>> +               dev_err(&i2c->dev, "Failed to add TOPSYS IRQ chip\n");
>>>> +               return ret;
>>>> +       }
>>>> +
>>>> +       ret = regmap_read(max77843->regmap,
>>>> +                       MAX77843_SYS_REG_PMICID, &reg_data);
>>>> +       if (ret < 0) {
>>>> +               dev_err(&i2c->dev, "Failed to read PMIC ID\n");
>>>> +               goto err_pmic_id;
>>>> +       }
>>>> +       dev_info(&i2c->dev, "device ID: 0x%x\n", reg_data);
>>>> +
>>>> +       ret = max77843_chg_init(max77843);
>>>> +       if (ret) {
>>>> +               dev_err(&i2c->dev, "Failed to init Charger\n");
>>>> +               goto err_pmic_id;
>>>> +       }
>>>> +
>>>> +       ret = regmap_update_bits(max77843->regmap,
>>>> +                       MAX77843_SYS_REG_INTSRCMASK,
>>>> +                       MAX77843_INTSRC_MASK_MASK,
>>>> +                       (unsigned int)~MAX77843_INTSRC_MASK_MASK);
>>>> +       if (ret < 0) {
>>>> +               dev_err(&i2c->dev, "Failed to unmask interrupt sourece\n");
>>>
>>> s/sourece/source/
>>>
>>> Best regards,
>>> Krzysztof
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" 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] 41+ messages in thread

* Re: [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver
  2015-01-23  6:21     ` Chanwoo Choi
  (?)
@ 2015-01-23 11:17     ` Jaewon Kim
  -1 siblings, 0 replies; 41+ messages in thread
From: Jaewon Kim @ 2015-01-23 11:17 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Sebastian Reichel, Mark Brown, Beomho Seo

Hi Chanwoo,

2015년 01월 23일 15:21에 Chanwoo Choi 이(가) 쓴 글:
> Hi Jaewon,
>
> On 01/23/2015 02:02 PM, Jaewon Kim wrote:
>> This patch adds MAX77843 extcon driver to support for MUIC(Micro
> Add company name (MAX77843 -> Maxim MAX77843)

Okay. I will fix it.
>
>> USB Interface Controller) device by using EXTCON subsystem to handle
>> various external connectors.
>>
>> Cc: Chanwoo Choi <cw00.choi@samsung.com>
>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>> ---
>>   drivers/extcon/Kconfig           |   10 +
>>   drivers/extcon/Makefile          |    1 +
>>   drivers/extcon/extcon-max77843.c |  871 ++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 882 insertions(+)
>>   create mode 100644 drivers/extcon/extcon-max77843.c
>>
>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>> index 6a1f7de..0b67538 100644
>> --- a/drivers/extcon/Kconfig
>> +++ b/drivers/extcon/Kconfig
>> @@ -55,6 +55,16 @@ config EXTCON_MAX77693
>>   	  Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory
>>   	  detector and switch.
>>   
>> +config EXTCON_MAX77843
>> +	tristate "MAX77843 EXTCON Support"
>> +	depends on MFD_MAX77843
>> +	select IRQ_DOMAIN
>> +	select REGMAP_I2C
>> +	help
>> +	  If you say yes here you get support for the MUIC device of
>> +	  Maxim MAX77843. The MAX77843 MUIC is a USB port accessory
>> +	  detector add switch.
>> +
>>   config EXTCON_MAX8997
>>   	tristate "MAX8997 EXTCON Support"
>>   	depends on MFD_MAX8997 && IRQ_DOMAIN
>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>> index 0370b42..f21d5c4 100644
>> --- a/drivers/extcon/Makefile
>> +++ b/drivers/extcon/Makefile
>> @@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
>>   obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
>>   obj-$(CONFIG_EXTCON_MAX14577)	+= extcon-max14577.o
>>   obj-$(CONFIG_EXTCON_MAX77693)	+= extcon-max77693.o
>> +obj-$(CONFIG_EXTCON_MAX77843)	+= extcon-max77843.o
>>   obj-$(CONFIG_EXTCON_MAX8997)	+= extcon-max8997.o
>>   obj-$(CONFIG_EXTCON_PALMAS)	+= extcon-palmas.o
>>   obj-$(CONFIG_EXTCON_RT8973A)	+= extcon-rt8973a.o
>> diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c
>> new file mode 100644
>> index 0000000..caae9a7
>> --- /dev/null
>> +++ b/drivers/extcon/extcon-max77843.c
>> @@ -0,0 +1,871 @@
>> +/*
>> + * extcon-max77843.c - MAX77843 extcon driver to support MUIC
>> + *
>> + * Copyright (C) 2014 Samsung Electrnoics
>> + *  Author: Jaewon Kim <jaewon02.kim@samsung.com>
> Remove un-necessary blank before 'Author'.

Okay. I will fix it.
>
>> + *
>> + * 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/extcon.h>
>> +#include <linux/i2c.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/max77843-private.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/workqueue.h>
>> +
>> +#define DELAY_MS_DEFAULT		15000	/* unit: millisecond */
>> +
>> +enum max77843_muic_acc_type {
>> +	MAX77843_MUIC_ADC_GROUND = 0,
>> +	MAX77843_MUIC_ADC_SEND_END_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S1_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S2_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S3_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S4_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S5_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S6_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S7_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S8_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S9_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S10_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S11_BUTTON,
>> +	MAX77843_MUIC_ADC_REMOTE_S12_BUTTON,
>> +	MAX77843_MUIC_ADC_RESERVED_ACC_1,
>> +	MAX77843_MUIC_ADC_RESERVED_ACC_2,
>> +	MAX77843_MUIC_ADC_RESERVED_ACC_3,
>> +	MAX77843_MUIC_ADC_RESERVED_ACC_4,
>> +	MAX77843_MUIC_ADC_RESERVED_ACC_5,
>> +	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2,
>> +	MAX77843_MUIC_ADC_PHONE_POWERED_DEV,
>> +	MAX77843_MUIC_ADC_TTY_CONVERTER,
>> +	MAX77843_MUIC_ADC_UART_CABLE,
>> +	MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG,
>> +	MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF,
>> +	MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON,
>> +	MAX77843_MUIC_ADC_AV_CABLE_NOLOAD,
>> +	MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG,
>> +	MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF,
>> +	MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON,
>> +	MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1,
>> +	MAX77843_MUIC_ADC_OPEN,
>> +};
>> +
>> +enum max77843_muic_cable_group {
>> +	MAX77843_CABLE_GROUP_ADC = 0,
>> +	MAX77843_CABLE_GROUP_CHG,
>> +	MAX77843_CABLE_GROUP_GND,
>> +};
> Cable group show the category of supported cables.
> I think you better move this enum on upper of 'enum max77843_muic_acc_type'

This is not a cable type.
I categorized cable group. GROUP_ADC  is

We can know cable group by IRQ type. so I categorized cable group.

It is used to parameter of 'max77843_muic_get_cable_type()' function.


>
>> +
>> +enum max77843_muic_adv_debounce_time {
>> +	MAX77843_DEBOUNCE_TIME_5MS = 0,
>> +	MAX77843_DEBOUNCE_TIME_10MS,
>> +	MAX77843_DEBOUNCE_TIME_25MS,
>> +	MAX77843_DEBOUNCE_TIME_38_62MS,
>> +};
>> +
>> +enum max77843_muic_support_list {
> Use only 'enum' keyword without 'max77843_muic_support_list' enum name.
Okay, i remove enum name.
>
>> +	EXTCON_CABLE_USB = 0,
>> +	EXTCON_CABLE_USB_HOST,
>> +	EXTCON_CABLE_USB_HOST_TA,
>> +	EXTCON_CABLE_TA,
>> +	EXTCON_CABLE_FAST_CHARGER,
>> +	EXTCON_CABLE_SLOW_CHARGER,
>> +	EXTCON_CABLE_CHARGE_DOWNSTREAM,
>> +	EXTCON_CABLE_MHL,
>> +	EXTCON_CABLE_MHL_TA,
>> +	EXTCON_CABLE_JIG_USB_ON,
>> +	EXTCON_CABLE_JIG_USB_OFF,
>> +	EXTCON_CABLE_JIG_UART_OFF,
>> +	EXTCON_CABLE_JIG_UART_ON,
>> +
>> +	EXTCON_CABLE_NUM,
>> +};
>> +
>> +enum max77843_muic_gnd_cable {
>> +	MAX77843_MUIC_GND_USB_OTG	= 0x0,
>> +	MAX77843_MUIC_GND_USB_OTG_VB	= 0x1,
>> +	MAX77843_MUIC_GND_MHL		= 0x2,
>> +	MAX77843_MUIC_GND_MHL_VB	= 0x3,
> Why do you need 'max77843_muic_gnd_cable' enum?
> You have to express supported all cables in 'max77843_muic_acc_type' enum list.
> If you define one more cables enumeration, It is possible to incur the confusion
> of what this driver is supported cable.
I will clean up 'max77843_muic_gnd_cable' and it will be move to 
'max77843_muic_acc_type'

>
>
>> +
>> +	MAX77843_MUIC_GND_NUM,
>> +};
>> +
>> +enum max77843_muic_status {
>> +	MAX77843_MUIC_STATUS1 = 0,
>> +	MAX77843_MUIC_STATUS2,
>> +	MAX77843_MUIC_STATUS3,
>> +
>> +	MAX77843_MUIC_STATUS_NUM,
>> +};
>> +
>> +enum max77843_muic_charger_type {
>> +	MAX77843_CHG_TYPE_NONE = 0,
>> +	MAX77843_CHG_TYPE_USB,
>> +	MAX77843_CHG_TYPE_DOWNSTREAM,
>> +	MAX77843_CHG_TYPE_DEDICATED,
>> +	MAX77843_CHG_TYPE_SPECIAL_500MA,
>> +	MAX77843_CHG_TYPE_SPECIAL_1A,
>> +	MAX77843_CHG_TYPE_SPECIAL_BIAS,
>> +
>> +	MAX77843_CHG_TYPE_END,
>> +};
>> +
>> +enum max77843_muic_detection {
>> +	MAX77843_MUIC_AUTO_NONE = 0,
>> +	MAX77843_MUIC_AUTO_USB,
>> +	MAX77843_MUIC_AUTO_FAC,
>> +	MAX77843_MUIC_AUTO_USB_FAC,
>> +};
> It it wrong. This enum is used to write the value to MUIC register.
> You have to define it in max77843-private.h with 'enum' keyword.
> I think you could refer other definition in max77843-private.h.
>
> You have to re-order the definition by using follwoing sequence
> to improbe readability.
> 1. cable group
> 2. supported cables
> 3. other definition with enum
>
> Also,
> I'm difficult to understand the meaning of enum definition.
> MAX77843_MUIC_*
> MAX77843_CABLE_*
> MAX77843_DEBOUNCE_*
> MAX77843_CHG_*
>
> I think you need to clarify the meaning of enum definition
> by makingt the name pattern to improve readability.

Thank to point out confusing names.
I will cleanup overall enum lists.

>
>> +
>> +struct max77843_muic_info {
>> +	struct device *dev;
>> +	struct max77843 *max77843;
>> +	struct extcon_dev *edev;
>> +
>> +	struct mutex mutex;
>> +	struct work_struct irq_work;
>> +	struct delayed_work wq_detcable;
>> +	struct max77843_muic_irq *muic_irqs;
>> +
>> +	u8 status[MAX77843_MUIC_STATUS_NUM];
>> +	int prev_cable_type;
>> +	int prev_chg_type;
>> +	int prev_gnd_type;
>> +
>> +	bool irq_adc;
>> +	bool irq_chg;
>> +	bool init_done;
> I don't want to use the 'init_done' field. I think it is legacy way
> to solve some issue. I recommend you use other way.
Okay, I will check it than use init_done variable.
>
>> +};
>> +
>> +struct max77843_muic_irq {
>> +	unsigned int irq;
>> +	const char *name;
>> +	unsigned int virq;
>> +};
>> +
>> +static const struct regmap_config max77843_muic_regmap_config = {
>> +	.reg_bits       = 8,
>> +	.val_bits       = 8,
>> +	.max_register   = MAX77843_MUIC_REG_END,
>> +};
>> +
>> +static const struct regmap_irq max77843_muic_irq[] = {
>> +	/* MUIC:INT1 interrupts */
> 	
> Don' need 'MUIC:' prefix and fix string (s/interrupts/interrupt).
>
>> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC, },
>> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADCERROR, },
>> +	{ .reg_offset = 0, .mask = MAX77843_MUIC_ADC1K, },
>> +
>> +	/* MUIC:INT2 interrupts */
> ditto.
>
>> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGTYP, },
>> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_CHGDETRUN, },
>> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_DCDTMR, },
>> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_DXOVP, },
>> +	{ .reg_offset = 1, .mask = MAX77843_MUIC_VBVOLT, },
>> +
>> +	/* MUIC:INT3 interrupts */
> ditto.
>
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_VBADC, },
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_VDNMON, },
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_DNRES, },
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MPNACK, },
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXBUFOW, },
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXTRF, },
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXPERR, },
>> +	{ .reg_offset = 2, .mask = MAX77843_MUIC_MRXRDY, },
>> +};
>> +
>> +static const struct regmap_irq_chip max77843_muic_irq_chip = {
>> +	.name           = "max77843-muic",
>> +	.status_base    = MAX77843_MUIC_REG_INT1,
>> +	.mask_base      = MAX77843_MUIC_REG_INTMASK1,
>> +	.mask_invert    = true,
>> +	.num_regs       = 3,
>> +	.irqs           = max77843_muic_irq,
>> +	.num_irqs       = ARRAY_SIZE(max77843_muic_irq),
>> +};
>> +
>> +static const char *max77843_extcon_cable[] = {
>> +	[EXTCON_CABLE_USB]			= "USB",
>> +	[EXTCON_CABLE_USB_HOST]			= "USB-HOST",
>> +	[EXTCON_CABLE_USB_HOST_TA]		= "USB-HOST-TA",
>> +	[EXTCON_CABLE_TA]			= "TA",
>> +	[EXTCON_CABLE_FAST_CHARGER]		= "FAST-CHARGER",
>> +	[EXTCON_CABLE_SLOW_CHARGER]		= "SLOW-CHARGER",
>> +	[EXTCON_CABLE_CHARGE_DOWNSTREAM]	= "CHARGER-DOWNSTREAM",
>> +	[EXTCON_CABLE_MHL]			= "MHL",
>> +	[EXTCON_CABLE_MHL_TA]			= "MHL-TA",
>> +	[EXTCON_CABLE_JIG_USB_ON]		= "JIG-USB-ON",
>> +	[EXTCON_CABLE_JIG_USB_OFF]		= "JIG-USB-OFF",
>> +	[EXTCON_CABLE_JIG_UART_OFF]		= "JIG-UART-OFF",
>> +	[EXTCON_CABLE_JIG_UART_ON]		= "JIG-UART-ON",
>> +};
>> +
>> +static struct max77843_muic_irq max77843_muic_irqs[] = {
>> +	{ MAX77843_MUIC_IRQ_INT1_ADC,		"MUIC-ADC" },
>> +	{ MAX77843_MUIC_IRQ_INT1_ADCERROR,	"MUIC-ADC_ERROR" },
>> +	{ MAX77843_MUIC_IRQ_INT1_ADC1K,		"MUIC-ADC1K" },
>> +	{ MAX77843_MUIC_IRQ_INT2_CHGTYP,	"MUIC-CHGTYP" },
>> +	{ MAX77843_MUIC_IRQ_INT2_CHGDETRUN,	"MUIC-CHGDETRUN" },
>> +	{ MAX77843_MUIC_IRQ_INT2_DCDTMR,	"MUIC-DCDTMR" },
>> +	{ MAX77843_MUIC_IRQ_INT2_DXOVP,		"MUIC-DXOVP" },
>> +	{ MAX77843_MUIC_IRQ_INT2_VBVOLT,	"MUIC-VBVOLT" },
>> +	{ MAX77843_MUIC_IRQ_INT3_VBADC,		"MUIC-VBADC" },
>> +	{ MAX77843_MUIC_IRQ_INT3_VDNMON,	"MUIC-VDNMON" },
>> +	{ MAX77843_MUIC_IRQ_INT3_DNRES,		"MUIC-DNRES" },
>> +	{ MAX77843_MUIC_IRQ_INT3_MPNACK,	"MUIC-MPNACK"},
>> +	{ MAX77843_MUIC_IRQ_INT3_MRXBUFOW,	"MUIC-MRXBUFOW"},
>> +	{ MAX77843_MUIC_IRQ_INT3_MRXTRF,	"MUIC-MRXTRF"},
>> +	{ MAX77843_MUIC_IRQ_INT3_MRXPERR,	"MUIC-MRXPERR"},
>> +	{ MAX77843_MUIC_IRQ_INT3_MRXRDY,	"MUIC-MRXRDY"},
>> +};
>> +
>> +static int max77843_muic_set_path(struct max77843_muic_info *info,
>> +		u8 val, bool attached)
>> +{
>> +	struct max77843 *max77843 = info->max77843;
>> +	int ret = 0;
>> +	unsigned int ctrl1, ctrl2;
>> +
>> +	if (attached)
>> +		ctrl1 = val;
>> +	else
>> +		ctrl1 = MAX77843_SWITCH_OPEN;
> 'SWITCH' keyword is right?
> I can't the 'SWITCH' word in CONTROL1 register of MAX77843 MUIC datasheet.
> When you define the field for register, I prefer to use the word which
> expressed in register map of datasheet.
>
>> +
>> +	ret = regmap_update_bits(max77843->regmap_muic,
>> +			MAX77843_MUIC_REG_CONTROL1,
>> +			MAX77843_SIWTH_PORT, ctrl1);
>> +	if (ret < 0) {
>> +		dev_err(info->dev, "Cannot switch MUIC port\n");
>> +		return ret;
>> +	}
>> +
>> +	if (attached)
>> +		ctrl2 = MAX77843_MUIC_CONTROL2_CPEN_MASK;
>> +	else
>> +		ctrl2 = MAX77843_MUIC_CONTROL2_LOWPWR_MASK;
>> +
>> +	ret = regmap_update_bits(max77843->regmap_muic,
>> +			MAX77843_MUIC_REG_CONTROL2,
>> +			MAX77843_MUIC_CONTROL2_LOWPWR_MASK |
>> +			MAX77843_MUIC_CONTROL2_CPEN_MASK, ctrl2);
>> +	if (ret < 0) {
>> +		dev_err(info->dev, "Cannot update lowpower mode\n");
>> +		return ret;
>> +	}
>> +
>> +	dev_dbg(info->dev,
>> +		"CONTROL1 : 0x%02x, CONTROL2 : 0x%02x, state : %s\n",
>> +		ctrl1, ctrl2, attached ? "attached" : "detached");
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77843_muic_get_cable_type(struct max77843_muic_info *info,
>> +		enum max77843_muic_cable_group group, bool *attached)
>> +{
>> +	int adc, chg_type, cable_type, gnd_type;
>> +
>> +	adc = info->status[MAX77843_MUIC_STATUS1] &
>> +			MAX77843_MUIC_STATUS1_ADC_MASK;
> If you use the short definition for 'MAX77843_MUIC_STATUS1',
> you could make this code on one line.
>
>> +	adc >>= STATUS1_ADC_SHIFT;
>> +
>> +	switch (group) {
>> +	case MAX77843_CABLE_GROUP_ADC:
>> +		if (adc == MAX77843_MUIC_ADC_OPEN) {
>> +			*attached = false;
>> +			cable_type = info->prev_cable_type;
>> +			info->prev_cable_type = MAX77843_MUIC_ADC_OPEN;
>> +		} else {
>> +			*attached = true;
>> +			cable_type = info->prev_cable_type = adc;
>> +		}
>> +
>> +		break;
>> +	case MAX77843_CABLE_GROUP_CHG:
>> +		if (adc == MAX77843_MUIC_ADC_GROUND) {
>> +			*attached = true;
>> +			cable_type = adc;
>> +			break;
>> +		}
>> +
>> +		chg_type = info->status[MAX77843_MUIC_STATUS2] &
>> +			MAX77843_MUIC_STATUS2_CHGTYP_MASK;
> ditto and I think you need one more indentation for readabiltiy.
>
>
>> +		chg_type >>= STATUS2_CHGTYP_SHIFT;
>> +
> Remove unneeded blank line.
>
>> +		if (chg_type == MAX77843_CHG_TYPE_NONE) {
>> +			*attached = false;
>> +			cable_type = info->prev_chg_type;
>> +			info->prev_chg_type = MAX77843_CHG_TYPE_NONE;
>> +		} else {
>> +			*attached = true;
>> +			cable_type = info->prev_chg_type = chg_type;
>> +		}
>> +
>> +		break;
>> +	case MAX77843_CABLE_GROUP_GND:
>> +		adc = info->status[MAX77843_MUIC_STATUS1] &
>> +			MAX77843_MUIC_STATUS1_ADC_MASK;
> ditto.
>
>> +		adc >>= STATUS1_ADC_SHIFT;
>> +
>> +		if (adc == MAX77843_MUIC_ADC_GROUND) {
>> +			*attached = true;
>> +			gnd_type = (info->status[MAX77843_MUIC_STATUS1] &
>> +					MAX77843_MUIC_STATUS1_ADC1K_MASK) >>
>> +					(STATUS1_ADC1K_SHIFT-1);
>> +			gnd_type |= (info->status[MAX77843_MUIC_STATUS2] &
>> +					MAX77843_MUIC_STATUS2_VBVOLT_MASK) >>
>> +					STATUS2_VBVOLT_SHIFT;
>> +			cable_type = info->prev_gnd_type = gnd_type;
>> +		} else {
>> +			*attached = false;
>> +			cable_type = info->prev_gnd_type;
>> +			info->prev_gnd_type = MAX77843_MUIC_GND_NUM;
>> +		}
>> +
>> +		break;
>> +	default:
>> +		dev_err(info->dev, "Unknown cable group (%d)\n", group);
>> +		cable_type = -EINVAL;
>> +
>> +		break;
>> +	}
>> +
>> +	return cable_type;
>> +}
>> +
>> +static int max77843_muic_adc_gnd_handler(struct max77843_muic_info *info)
>> +{
>> +	int ret, gnd_cable_type;
>> +	u8 path;
>> +	bool attached;
>> +
>> +	gnd_cable_type = max77843_muic_get_cable_type(info,
>> +			MAX77843_CABLE_GROUP_GND, &attached);
>> +	dev_dbg(info->dev, "external connector is %s (gnd:0x%02x)\n",
>> +			attached ? "attached" : "detached", gnd_cable_type);
>> +
>> +	switch (gnd_cable_type) {
>> +	case MAX77843_MUIC_GND_USB_OTG:
>> +		extcon_set_cable_state(info->edev, "USB-HOST", attached);
>> +		path = MAX77843_SWITCH_USB;
> Change the name insted of 'SWITCH' word.
>
> Also, I think you have to change the path before sending uevent about cable information.
> If you set cable state before setting the path, user-process might get the uevent
> before changing the MUIC path. You have to modify it when cable state is changed.
>
>> +		info->irq_chg = false;
>> +		break;
>> +	case MAX77843_MUIC_GND_USB_OTG_VB:
>> +		extcon_set_cable_state(info->edev, "USB-HOST-TA", attached);
>> +		path = MAX77843_SWITCH_USB;
> ditto.
>
>> +		info->irq_chg = false;
>> +		break;
>> +	case MAX77843_MUIC_GND_MHL:
>> +		extcon_set_cable_state(info->edev, "MHL", attached);
>> +		path = MAX77843_SWITCH_OPEN;
> ditto.
>
>> +		info->irq_chg = false;
>> +		break;
>> +	case MAX77843_MUIC_GND_MHL_VB:
>> +		extcon_set_cable_state(info->edev, "MHL-TA", attached);
>> +		path = MAX77843_SWITCH_OPEN;
> ditto.
>
>> +		info->irq_chg = false;
>> +		break;
>> +	default:
>> +		dev_err(info->dev, "Cannot detect %s cable of gnd type\n",
>> +			attached ? "attached" : "detached");
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = max77843_muic_set_path(info, path, attached);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77843_muic_jig_handler(struct max77843_muic_info *info,
>> +		int cable_type, bool attached)
>> +{
>> +	char cable_name[32];
> Remove 'cable_name' array
>
>> +	u8 path = MAX77843_SWITCH_OPEN;
>> +	int ret;
>> +
>> +	dev_dbg(info->dev, "external connector is %s (adc:0x%02x)\n",
>> +			attached ? "attached" : "detached", cable_type);
>> +
>> +	switch (cable_type) {
>> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
>> +		strcpy(cable_name, "JIG-USB-OFF");
> You execute direclty extcon_set_cable_state() function instead of using strcpy.
Okay, i will fix it.
>
>> +		path = MAX77843_SWITCH_USB;
>> +		break;
>> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
>> +		strcpy(cable_name, "JIG-USB-ON");
>> +		path = MAX77843_SWITCH_USB;
>> +		break;
>> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
>> +		strcpy(cable_name, "JIG-UART-OFF");
>> +		path = MAX77843_SWITCH_UART;
>> +		break;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	ret = max77843_muic_set_path(info, path, attached);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	extcon_set_cable_state(info->edev, cable_name, attached);
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77843_muic_adc_handler(struct max77843_muic_info *info)
>> +{
>> +	int ret, cable_type;
>> +	bool attached;
>> +
>> +	cable_type = max77843_muic_get_cable_type(info,
>> +			MAX77843_CABLE_GROUP_ADC, &attached);
>> +
>> +	dev_dbg(info->dev,
>> +		"external connector is %s (adc:0x%02x, prev_adc:0x%x)\n",
>> +		attached ? "attached" : "detached", cable_type,
>> +		info->prev_cable_type);
>> +
>> +	switch (cable_type) {
>> +	case MAX77843_MUIC_ADC_GROUND:
>> +		ret = max77843_muic_adc_gnd_handler(info);
>> +		if (ret < 0)
>> +			return ret;
>> +		break;
>> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_OFF:
>> +	case MAX77843_MUIC_ADC_FACTORY_MODE_USB_ON:
>> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_OFF:
>> +		ret = max77843_muic_jig_handler(info, cable_type, attached);
>> +		if (ret < 0)
>> +			return ret;
>> +		break;
>> +	case MAX77843_MUIC_ADC_SEND_END_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S1_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S2_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S3_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S4_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S5_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S6_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S7_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S8_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S9_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S10_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S11_BUTTON:
>> +	case MAX77843_MUIC_ADC_REMOTE_S12_BUTTON:
>> +	case MAX77843_MUIC_ADC_RESERVED_ACC_1:
>> +	case MAX77843_MUIC_ADC_RESERVED_ACC_2:
>> +	case MAX77843_MUIC_ADC_RESERVED_ACC_3:
>> +	case MAX77843_MUIC_ADC_RESERVED_ACC_4:
>> +	case MAX77843_MUIC_ADC_RESERVED_ACC_5:
>> +	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE2:
>> +	case MAX77843_MUIC_ADC_PHONE_POWERED_DEV:
>> +	case MAX77843_MUIC_ADC_TTY_CONVERTER:
>> +	case MAX77843_MUIC_ADC_UART_CABLE:
>> +	case MAX77843_MUIC_ADC_CEA936A_TYPE1_CHG:
>> +	case MAX77843_MUIC_ADC_AV_CABLE_NOLOAD:
>> +	case MAX77843_MUIC_ADC_CEA936A_TYPE2_CHG:
>> +	case MAX77843_MUIC_ADC_FACTORY_MODE_UART_ON:
>> +	case MAX77843_MUIC_ADC_AUDIO_DEVICE_TYPE1:
>> +	case MAX77843_MUIC_ADC_OPEN:
>> +		dev_err(info->dev,
>> +			"accessory is %s but it isn't used (adc:0x%x)\n",
>> +			attached ? "attached" : "detached", cable_type);
>> +		return -EAGAIN;
>> +	default:
>> +		dev_err(info->dev,
>> +			"failed to detect %s accessory (adc:0x%x)\n",
>> +			attached ? "attached" : "detached", cable_type);
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77843_muic_chg_handler(struct max77843_muic_info *info)
>> +{
>> +	int ret, chg_type;
>> +	bool attached;
>> +	u8 path = MAX77843_SWITCH_OPEN;
> ditto.
>
>> +
>> +	chg_type = max77843_muic_get_cable_type(info,
>> +			MAX77843_CABLE_GROUP_CHG, &attached);
>> +
>> +	dev_dbg(info->dev,
>> +		"external connector is %s(chg_type:0x%x, prev_chg_type:0x%x)\n",
>> +		attached ? "attached" : "detached",
>> +		chg_type, info->prev_chg_type);
>> +
>> +	switch (chg_type) {
>> +	case MAX77843_CHG_TYPE_USB:
>> +		path = MAX77843_SWITCH_USB;
>> +		extcon_set_cable_state(info->edev, "USB", attached);
> ditto. you have to change the muic path before setting the cable state.
Okay, iwill fix it.
>
>> +		break;
>> +	case MAX77843_CHG_TYPE_DOWNSTREAM:
>> +		path = MAX77843_SWITCH_OPEN;
>> +		extcon_set_cable_state(info->edev,
>> +				"CHARGER-DOWNSTREAM", attached);
>> +		break;
>> +	case MAX77843_CHG_TYPE_DEDICATED:
>> +		path = MAX77843_SWITCH_OPEN;
>> +		extcon_set_cable_state(info->edev, "TA", attached);
>> +		break;
>> +	case MAX77843_CHG_TYPE_SPECIAL_500MA:
>> +		path = MAX77843_SWITCH_OPEN;
>> +		extcon_set_cable_state(info->edev, "SLOW-CHAREGER", attached);
>> +		break;
>> +	case MAX77843_CHG_TYPE_SPECIAL_1A:
>> +		path = MAX77843_SWITCH_OPEN;
>> +		extcon_set_cable_state(info->edev, "FAST-CHARGER", attached);
>> +		break;
>> +	case MAX77843_CHG_TYPE_SPECIAL_BIAS:
>> +		path = MAX77843_SWITCH_OPEN;
>> +		break;
>> +	case MAX77843_CHG_TYPE_NONE:
>> +		return 0;
>> +	default:
>> +		dev_err(info->dev,
>> +			"failed to detect %s accessory (chg_type:0x%x)\n",
>> +			attached ? "attached" : "detached", chg_type);
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = max77843_muic_set_path(info, path, attached);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return 0;
>> +}
>> +
>> +static void max77843_muic_irq_work(struct work_struct *work)
>> +{
>> +	struct max77843_muic_info *info = container_of(work,
>> +			struct max77843_muic_info, irq_work);
>> +	struct max77843 *max77843 = info->max77843;
>> +	int ret = 0;
>> +
>> +	if (!info->edev)
>> +		return;
>> +
>> +	mutex_lock(&info->mutex);
>> +
>> +	ret = regmap_bulk_read(max77843->regmap_muic,
>> +			MAX77843_MUIC_REG_STATUS1, info->status,
>> +			MAX77843_MUIC_STATUS_NUM);
>> +	if (ret) {
>> +		dev_err(info->dev, "Cannot read STATUS registers\n");
>> +		mutex_unlock(&info->mutex);
>> +		return;
>> +	}
>> +
>> +	if (info->irq_adc) {
>> +		ret = max77843_muic_adc_handler(info);
>> +		if (ret)
>> +			dev_err(info->dev, "Unknown cable type\n");
>> +		info->irq_adc = false;
>> +	}
>> +
>> +	if (info->irq_chg) {
>> +		ret = max77843_muic_chg_handler(info);
>> +		if (ret)
>> +			dev_err(info->dev, "Unknown charger type\n");
>> +		info->irq_chg = false;
>> +	}
>> +
>> +	mutex_unlock(&info->mutex);
>> +}
>> +
>> +static irqreturn_t max77843_muic_irq_handler(int irq, void *data)
>> +{
>> +	struct max77843_muic_info *info = data;
>> +	int i, irq_type = -1;
>> +
>> +	if (!info->init_done)
>> +		return IRQ_HANDLED;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++)
>> +		if (irq == info->muic_irqs[i].virq)
>> +			irq_type = info->muic_irqs[i].irq;
>> +
>> +	switch (irq_type) {
>> +	case MAX77843_MUIC_IRQ_INT1_ADC:
>> +	case MAX77843_MUIC_IRQ_INT1_ADCERROR:
>> +	case MAX77843_MUIC_IRQ_INT1_ADC1K:
>> +		info->irq_adc = true;
>> +		break;
>> +	case MAX77843_MUIC_IRQ_INT2_CHGTYP:
>> +	case MAX77843_MUIC_IRQ_INT2_CHGDETRUN:
>> +	case MAX77843_MUIC_IRQ_INT2_DCDTMR:
>> +	case MAX77843_MUIC_IRQ_INT2_DXOVP:
>> +	case MAX77843_MUIC_IRQ_INT2_VBVOLT:
>> +		info->irq_chg = true;
>> +		break;
>> +	case MAX77843_MUIC_IRQ_INT3_VBADC:
>> +	case MAX77843_MUIC_IRQ_INT3_VDNMON:
>> +	case MAX77843_MUIC_IRQ_INT3_DNRES:
>> +	case MAX77843_MUIC_IRQ_INT3_MPNACK:
>> +	case MAX77843_MUIC_IRQ_INT3_MRXBUFOW:
>> +	case MAX77843_MUIC_IRQ_INT3_MRXTRF:
>> +	case MAX77843_MUIC_IRQ_INT3_MRXPERR:
>> +	case MAX77843_MUIC_IRQ_INT3_MRXRDY:
>> +		break;
>> +	default:
>> +		dev_err(info->dev, "Cannot recognize IRQ(%d)\n", irq_type);
>> +		break;
>> +	}
>> +
>> +	schedule_work(&info->irq_work);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static void max77843_muic_detect_cable_wq(struct work_struct *work)
>> +{
>> +	struct max77843_muic_info *info = container_of(to_delayed_work(work),
>> +			struct max77843_muic_info, wq_detcable);
>> +	struct max77843 *max77843 = info->max77843;
>> +	int chg_type, adc, ret;
>> +	bool attached;
>> +
>> +	mutex_lock(&info->mutex);
>> +
>> +	ret = regmap_bulk_read(max77843->regmap_muic,
>> +			MAX77843_MUIC_REG_STATUS1, info->status,
>> +			MAX77843_MUIC_STATUS_NUM);
>> +	if (ret) {
>> +		dev_err(info->dev, "Cannot read STATUS registers\n");
>> +		goto err_cable_wq;
>> +	}
>> +
>> +	adc = max77843_muic_get_cable_type(info,
>> +			MAX77843_CABLE_GROUP_ADC, &attached);
>> +	if (attached && adc != MAX77843_MUIC_ADC_OPEN) {
>> +		ret = max77843_muic_adc_handler(info);
>> +		if (ret < 0) {
>> +			dev_err(info->dev, "Cannot detect accessory\n");
>> +			goto err_cable_wq;
>> +		}
>> +	}
>> +
>> +	chg_type = max77843_muic_get_cable_type(info,
>> +			MAX77843_CABLE_GROUP_CHG, &attached);
>> +	if (attached && chg_type != MAX77843_CHG_TYPE_NONE) {
>> +		ret = max77843_muic_chg_handler(info);
>> +		if (ret < 0) {
>> +			dev_err(info->dev, "Cannot detect charger accessory\n");
>> +			goto err_cable_wq;
>> +		}
>> +	}
>> +
>> +err_cable_wq:
>> +	mutex_unlock(&info->mutex);
>> +}
>> +
>> +static int max77843_muic_set_debounce_time(struct max77843_muic_info *info,
>> +		enum max77843_muic_adv_debounce_time time)
>> +{
>> +	struct max77843 *max77843 = info->max77843;
>> +	unsigned int ret;
>> +
>> +	switch (time) {
>> +	case MAX77843_DEBOUNCE_TIME_5MS:
>> +	case MAX77843_DEBOUNCE_TIME_10MS:
>> +	case MAX77843_DEBOUNCE_TIME_25MS:
>> +	case MAX77843_DEBOUNCE_TIME_38_62MS:
>> +		ret = regmap_update_bits(max77843->regmap_muic,
>> +				MAX77843_MUIC_REG_CONTROL4,
>> +				MAX77843_MUIC_CONTROL4_ADCDBSET_MASK,
>> +				time << CONTROL4_ADCDBSET_SHIFT);
>> +		if (ret) {
> I prfer to use following condition statement to check return value
> 	if (ret) -> if (ret < 0)
Okay, i will fix it.
>
>> +			dev_err(info->dev, "Cannot write MUIC regmap\n");
>> +			return ret;
>> +		}
>> +
>> +		break;
>> +	default:
>> +		dev_err(info->dev, "Invalid ADC debounce time\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int max77843_init_muic_regmap(struct max77843 *max77843)
>> +{
>> +	int ret;
>> +
>> +	max77843->i2c_muic = i2c_new_dummy(max77843->i2c->adapter,
>> +			I2C_ADDR_MUIC);
>> +	if (!max77843->i2c_muic) {
>> +		dev_err(&max77843->i2c->dev,
>> +				"Cannot allocate I2C device for MUIC\n");
>> +		return PTR_ERR(max77843->i2c_muic);
>> +	}
>> +
>> +	i2c_set_clientdata(max77843->i2c_muic, max77843);
>> +
>> +	max77843->regmap_muic = devm_regmap_init_i2c(max77843->i2c_muic,
>> +			&max77843_muic_regmap_config);
>> +	if (IS_ERR(max77843->regmap_muic)) {
>> +		ret = PTR_ERR(max77843->regmap_muic);
>> +		goto err_muic_i2c;
>> +	}
>> +
>> +	ret = regmap_add_irq_chip(max77843->regmap_muic, max77843->irq,
>> +			IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
>> +			0, &max77843_muic_irq_chip, &max77843->irq_data_muic);
>> +	if (ret) {
> ditto.
> 	if (ret < 0)
okay, I will fix it.
>> +		dev_err(&max77843->i2c->dev, "Cannot add MUIC IRQ chip\n");
>> +		goto err_muic_i2c;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_muic_i2c:
>> +	i2c_unregister_device(max77843->i2c_muic);
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77843_muic_probe(struct platform_device *pdev)
>> +{
>> +	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
>> +	struct max77843_muic_info *info;
>> +	unsigned int id;
>> +	int i, ret;
>> +
>> +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
>> +	if (!info)
>> +		return -ENOMEM;
>> +
>> +	info->dev = &pdev->dev;
>> +	info->max77843 = max77843;
>> +	info->muic_irqs = max77843_muic_irqs;
>> +	info->init_done = false;
>> +
>> +	platform_set_drvdata(pdev, info);
>> +	mutex_init(&info->mutex);
>> +	INIT_WORK(&info->irq_work, max77843_muic_irq_work);
>> +
>> +	/* Initialize i2c and regmap */
>> +	ret = max77843_init_muic_regmap(max77843);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Failed to init MUIC regmap\n");
>> +		return ret;
>> +	}
>> +
>> +	/* Turn off auto detection configuration */
>> +	ret = regmap_update_bits(max77843->regmap_muic,
>> +			MAX77843_MUIC_REG_CONTROL4,
>> +			MAX77843_MUIC_CONTROL4_USBAUTO_MASK |
>> +			MAX77843_MUIC_CONTROL4_FCTAUTO_MASK,
>> +			MAX77843_MUIC_AUTO_NONE << CONTROL4_USBAUTO_SHIFT);
>> +
>> +	/* Support virtual irq domain for max77843 MUIC device */
>> +	for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) {
>> +		struct max77843_muic_irq *muic_irq = &info->muic_irqs[i];
>> +		unsigned int virq = 0;
>> +
>> +		virq = regmap_irq_get_virq(max77843->irq_data_muic,
>> +				muic_irq->irq);
>> +		if (virq <= 0) {
>> +			ret = -EINVAL;
>> +			goto err_muic_irq;
>> +		}
>> +		muic_irq->virq = virq;
>> +
>> +		ret = devm_request_threaded_irq(&pdev->dev, virq, NULL,
>> +				max77843_muic_irq_handler, IRQF_NO_SUSPEND,
>> +				muic_irq->name, info);
>> +		if (ret) {
>> +			dev_err(&pdev->dev,
>> +				"Failed: irq request (IRQ: %d, error: %d)\n",
>> +				muic_irq->irq, ret);
>> +			goto err_muic_irq;
>> +		}
>> +	}
>> +
>> +	/* Initialize extcon device */
>> +	info->edev = devm_extcon_dev_allocate(&pdev->dev,
>> +			max77843_extcon_cable);
>> +	if (IS_ERR(info->edev)) {
>> +		dev_err(&pdev->dev, "Failed to allocate memory for extcon\n");
>> +		ret = -ENODEV;
>> +		goto err_muic_irq;
>> +	}
>> +
>> +	info->edev->name = dev_name(&pdev->dev);
> Don't need it. extcon_dev_register() set the name of extcon device.
Okay, I will fix it.
>
>> +
>> +	ret = devm_extcon_dev_register(&pdev->dev, info->edev);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Failed to register extcon device\n");
>> +		goto err_muic_irq;
>> +	}
>> +
>> +	/* Set ADC debounce time */
>> +	max77843_muic_set_debounce_time(info, MAX77843_DEBOUNCE_TIME_25MS);
>> +
>> +	/* Set initial path for UART */
>> +	max77843_muic_set_path(info, MAX77843_SWITCH_UART, true);
>> +
>> +	/* Detect accessory after completing the initialization of platform */
>> +	INIT_DELAYED_WORK(&info->wq_detcable, max77843_muic_detect_cable_wq);
>> +	queue_delayed_work(system_power_efficient_wq,
>> +			&info->wq_detcable, msecs_to_jiffies(DELAY_MS_DEFAULT));
>> +
>> +	/* Check revision number of MUIC device */
>> +	ret = regmap_read(max77843->regmap_muic, MAX77843_MUIC_REG_ID, &id);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "Failed to read revision number\n");
>> +		return ret;
>> +	}
>> +	dev_info(info->dev, "MUIC device ID : 0x%x\n", id);
>> +
>> +	info->init_done = true;
>> +
>> +	return 0;
>> +
>> +err_muic_irq:
>> +	regmap_del_irq_chip(max77843->irq, max77843->irq_data_muic);
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77843_muic_remove(struct platform_device *pdev)
>> +{
>> +	struct max77843_muic_info *info = platform_get_drvdata(pdev);
>> +
>> +	cancel_work_sync(&info->irq_work);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct platform_device_id max77843_muic_id[] = {
>> +	{ "max77843-muic", },
>> +	{ },
>> +};
>> +MODULE_DEVICE_TABLE(platform, max77843_muic_id);
>> +
>> +static struct platform_driver max77843_muic_driver = {
>> +	.driver		= {
>> +		.name		= "max77843-muic",
>> +	},
>> +	.probe		= max77843_muic_probe,
>> +	.remove		= max77843_muic_remove,
>> +	.id_table	= max77843_muic_id,
>> +};
>> +
>> +static int __init max77843_muic_init(void)
>> +{
>> +	return platform_driver_register(&max77843_muic_driver);
>> +}
>> +subsys_initcall(max77843_muic_init);
>> +
>> +MODULE_DESCRIPTION("Maxim MAX77843 Extcon driver");
>> +MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
>> +MODULE_LICENSE("GPL");
>>
> Thanks,
> Chanwoo Choi
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

I list up your review list.
1. cleanup enum lists
2. set path befor send uevent.
3. fix variable names and typos for readability.

Thanks
Jaewon Kim


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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
  2015-01-23 11:10         ` Beomho Seo
@ 2015-01-23 11:18           ` Krzysztof Kozlowski
  2015-01-23 11:26               ` Beomho Seo
  0 siblings, 1 reply; 41+ messages in thread
From: Krzysztof Kozlowski @ 2015-01-23 11:18 UTC (permalink / raw)
  To: Beomho Seo
  Cc: Jaewon Kim, linux-kernel, devicetree, linux-pm, Inki Dae,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Lee Jones, Chanwoo Choi, Sebastian Reichel, Mark Brown

On pią, 2015-01-23 at 20:10 +0900, Beomho Seo wrote:
> On 01/23/2015 04:16 PM, Krzysztof Kozlowski wrote:
> > On pią, 2015-01-23 at 15:41 +0900, Beomho Seo wrote:
> >> On 01/23/2015 03:32 PM, Krzysztof Kozlowski wrote:
> >>> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
> >>>> This patch adds MAX77843 core/irq driver to support PMIC,
> >>>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
> >>>> LED and Haptic device.
> >>>>
> >>>> Cc: Lee Jones <lee.jones@linaro.org>
> >>>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> >>>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
> >>>> ---
> >>>>  drivers/mfd/Kconfig                  |   14 ++
> >>>>  drivers/mfd/Makefile                 |    1 +
> >>>>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
> >>>>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
> >>>>  4 files changed, 666 insertions(+)
> >>>>  create mode 100644 drivers/mfd/max77843.c
> >>>>  create mode 100644 include/linux/mfd/max77843-private.h
> >>>>
> >>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> >>>> index 2e6b731..0c67c79 100644
> >>>> --- a/drivers/mfd/Kconfig
> >>>> +++ b/drivers/mfd/Kconfig
> >>>> @@ -442,6 +442,20 @@ config MFD_MAX77693
> >>>>           additional drivers must be enabled in order to use the functionality
> >>>>           of the device.
> >>>>
> >>>> +config MFD_MAX77843
> >>>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
> >>>> +       depends on I2C=y
> >>>> +       select MFD_CORE
> >>>> +       select REGMAP_I2C
> >>>> +       select REGMAP_IRQ
> >>>> +       help
> >>>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
> >>>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
> >>>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
> >>>> +         This driver provides common support for accessing the device;
> >>>> +         additional drivers must be enabled in order to use the functionality
> >>>> +         of the device.
> >>>> +
> >>>>  config MFD_MAX8907
> >>>>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
> >>>>         select MFD_CORE
> >>>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> >>>> index 53467e2..fe4f75c 100644
> >>>> --- a/drivers/mfd/Makefile
> >>>> +++ b/drivers/mfd/Makefile
> >>>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
> >>>>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
> >>>>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
> >>>>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
> >>>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
> >>>>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
> >>>>  max8925-objs                   := max8925-core.o max8925-i2c.o
> >>>>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
> >>>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
> >>>> new file mode 100644
> >>>> index 0000000..d7f8b76
> >>>> --- /dev/null
> >>>> +++ b/drivers/mfd/max77843.c
> >>>> @@ -0,0 +1,241 @@
> >>>> +/*
> >>>> + * max77843.c - MFD core driver for the Maxim MAX77843
> >>>> + *
> >>>> + * Copyright (C) 2014 Samsung Electrnoics
> >>>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
> >>>> + *
> >>>> + * This program is free software; you can redistribute it and/or modify
> >>>> + * it under the terms of the GNU General Public License as published by
> >>>> + * the Free Software Foundation; either version 2 of the License, or
> >>>> + * (at your option) any later version.
> >>>> + */
> >>>> +
> >>>> +#include <linux/err.h>
> >>>> +#include <linux/i2c.h>
> >>>> +#include <linux/init.h>
> >>>> +#include <linux/interrupt.h>
> >>>> +#include <linux/module.h>
> >>>> +#include <linux/mfd/core.h>
> >>>> +#include <linux/mfd/max77843-private.h>
> >>>> +#include <linux/of_device.h>
> >>>> +#include <linux/platform_device.h>
> >>>> +
> >>>> +static const struct mfd_cell max77843_devs[] = {
> >>>> +       {
> >>>> +               .name = "max77843-muic",
> >>>> +               .of_compatible = "maxim,max77843-muic",
> >>>> +       }, {
> >>>> +               .name = "max77843-regulator",
> >>>> +               .of_compatible = "maxim,max77843-regulator",
> >>>> +       }, {
> >>>> +               .name = "max77843-charger",
> >>>> +               .of_compatible = "maxim,max77843-charger"
> >>>> +       }, {
> >>>> +               .name = "max77843-fuelgauge",
> >>>> +               .of_compatible = "maxim,max77843-fuelgauge",
> >>>> +       },
> >>>> +};
> >>>> +
> >>>> +static const struct regmap_config max77843_charger_regmap_config = {
> >>>> +       .reg_bits       = 8,
> >>>> +       .val_bits       = 8,
> >>>> +       .max_register   = MAX77843_CHG_REG_END,
> >>>> +};
> >>>> +
> >>>> +static const struct regmap_config max77843_regmap_config = {
> >>>> +       .reg_bits       = 8,
> >>>> +       .val_bits       = 8,
> >>>> +       .max_register   = MAX77843_SYS_REG_END,
> >>>> +};
> >>>> +
> >>>> +static const struct regmap_irq max77843_irqs[] = {
> >>>> +       /* TOPSYS interrupts */
> >>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
> >>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
> >>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
> >>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
> >>>> +};
> >>>> +
> >>>> +static const struct regmap_irq_chip max77843_irq_chip = {
> >>>> +       .name           = "max77843",
> >>>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
> >>>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
> >>>> +       .mask_invert    = false,
> >>>> +       .num_regs       = 1,
> >>>> +       .irqs           = max77843_irqs,
> >>>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
> >>>> +};
> >>>> +
> >>>> +static int max77843_chg_init(struct max77843 *max77843)
> >>>> +{
> >>>
> >>> Could this function be moved to the charger driver? This way the
> >>> driver will manage its own resources instead of depending on parent
> >>> MFD driver.
> >>>
> >>
> >> Charger regulator and Charger share same resources.
> >> So I include this function core driver.
> > 
> > OK, I see... Could you describe it in comments somewhere? For example in
> > comment above the function. Currently this looks like only as regmap for
> > charger.
> > 
> 
> Charger regulator and Charger use same regmap.

OK, just put it in a comment around that function.

> 
> > Unfortunately current solution imposes problem with releasing resources.
> > Who is the owner of i2c dummy device?
> > 
> 
> Core driver owner of i2c dummy device.

OK, good idea. So the core driver should be the only place to unregister
it. So needed changes are:
1. Remove the i2c_unregister_device() call from
max77843_charger_probe().
2. Add i2c_unregister_device(max77843->i2c_chg) in max77843_remove().

The MFD core driver will handle it.

> 
> > 1. The charger driver will unregister it if max77843_charger_probe()
> > fails. What will happen with regulator driver in such case?
> > 
> 
> Charger is enabled/disabled by Charger regulator.
> Currently, If charger probe fails, charger regulator failed to read regmap and occur panic(It have to fix.)
> 
> 
> > 2. Who will release this i2c dummy device in normal unbind? Currently it
> > leaks.
> > 
> 
> I think core driver release i2c dummy device in normal unbind.
> We need to more discussion about this problem.
> If you have any idea, I hope tell me. Again, Thank you for your advice.

I think handling the ownership in core driver could solve this.

Best regards,
Krzysztof




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

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
  2015-01-23 11:18           ` Krzysztof Kozlowski
@ 2015-01-23 11:26               ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23 11:26 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Jaewon Kim, linux-kernel, devicetree, linux-pm, Inki Dae,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Lee Jones, Chanwoo Choi, Sebastian Reichel, Mark Brown

On 01/23/2015 08:18 PM, Krzysztof Kozlowski wrote:
> On pią, 2015-01-23 at 20:10 +0900, Beomho Seo wrote:
>> On 01/23/2015 04:16 PM, Krzysztof Kozlowski wrote:
>>> On pią, 2015-01-23 at 15:41 +0900, Beomho Seo wrote:
>>>> On 01/23/2015 03:32 PM, Krzysztof Kozlowski wrote:
>>>>> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim@samsung.com>:
>>>>>> This patch adds MAX77843 core/irq driver to support PMIC,
>>>>>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>>>>>> LED and Haptic device.
>>>>>>
>>>>>> Cc: Lee Jones <lee.jones@linaro.org>
>>>>>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>>>>>> Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
>>>>>> ---
>>>>>>  drivers/mfd/Kconfig                  |   14 ++
>>>>>>  drivers/mfd/Makefile                 |    1 +
>>>>>>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>>>>>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>>>>>  4 files changed, 666 insertions(+)
>>>>>>  create mode 100644 drivers/mfd/max77843.c
>>>>>>  create mode 100644 include/linux/mfd/max77843-private.h
>>>>>>
>>>>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>>>>>> index 2e6b731..0c67c79 100644
>>>>>> --- a/drivers/mfd/Kconfig
>>>>>> +++ b/drivers/mfd/Kconfig
>>>>>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>>>>>           additional drivers must be enabled in order to use the functionality
>>>>>>           of the device.
>>>>>>
>>>>>> +config MFD_MAX77843
>>>>>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
>>>>>> +       depends on I2C=y
>>>>>> +       select MFD_CORE
>>>>>> +       select REGMAP_I2C
>>>>>> +       select REGMAP_IRQ
>>>>>> +       help
>>>>>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
>>>>>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
>>>>>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>>>>>> +         This driver provides common support for accessing the device;
>>>>>> +         additional drivers must be enabled in order to use the functionality
>>>>>> +         of the device.
>>>>>> +
>>>>>>  config MFD_MAX8907
>>>>>>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>>>>>         select MFD_CORE
>>>>>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>>>>>> index 53467e2..fe4f75c 100644
>>>>>> --- a/drivers/mfd/Makefile
>>>>>> +++ b/drivers/mfd/Makefile
>>>>>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>>>>>>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>>>>>>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>>>>>>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
>>>>>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>>>>>>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>>>>>>  max8925-objs                   := max8925-core.o max8925-i2c.o
>>>>>>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
>>>>>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>>>>>> new file mode 100644
>>>>>> index 0000000..d7f8b76
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/mfd/max77843.c
>>>>>> @@ -0,0 +1,241 @@
>>>>>> +/*
>>>>>> + * max77843.c - MFD core driver for the Maxim MAX77843
>>>>>> + *
>>>>>> + * Copyright (C) 2014 Samsung Electrnoics
>>>>>> + * Author: Jaewon Kim <jaewon02.kim@samsung.com>
>>>>>> + *
>>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>>> + * it under the terms of the GNU General Public License as published by
>>>>>> + * the Free Software Foundation; either version 2 of the License, or
>>>>>> + * (at your option) any later version.
>>>>>> + */
>>>>>> +
>>>>>> +#include <linux/err.h>
>>>>>> +#include <linux/i2c.h>
>>>>>> +#include <linux/init.h>
>>>>>> +#include <linux/interrupt.h>
>>>>>> +#include <linux/module.h>
>>>>>> +#include <linux/mfd/core.h>
>>>>>> +#include <linux/mfd/max77843-private.h>
>>>>>> +#include <linux/of_device.h>
>>>>>> +#include <linux/platform_device.h>
>>>>>> +
>>>>>> +static const struct mfd_cell max77843_devs[] = {
>>>>>> +       {
>>>>>> +               .name = "max77843-muic",
>>>>>> +               .of_compatible = "maxim,max77843-muic",
>>>>>> +       }, {
>>>>>> +               .name = "max77843-regulator",
>>>>>> +               .of_compatible = "maxim,max77843-regulator",
>>>>>> +       }, {
>>>>>> +               .name = "max77843-charger",
>>>>>> +               .of_compatible = "maxim,max77843-charger"
>>>>>> +       }, {
>>>>>> +               .name = "max77843-fuelgauge",
>>>>>> +               .of_compatible = "maxim,max77843-fuelgauge",
>>>>>> +       },
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_config max77843_charger_regmap_config = {
>>>>>> +       .reg_bits       = 8,
>>>>>> +       .val_bits       = 8,
>>>>>> +       .max_register   = MAX77843_CHG_REG_END,
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_config max77843_regmap_config = {
>>>>>> +       .reg_bits       = 8,
>>>>>> +       .val_bits       = 8,
>>>>>> +       .max_register   = MAX77843_SYS_REG_END,
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_irq max77843_irqs[] = {
>>>>>> +       /* TOPSYS interrupts */
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_irq_chip max77843_irq_chip = {
>>>>>> +       .name           = "max77843",
>>>>>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
>>>>>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
>>>>>> +       .mask_invert    = false,
>>>>>> +       .num_regs       = 1,
>>>>>> +       .irqs           = max77843_irqs,
>>>>>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
>>>>>> +};
>>>>>> +
>>>>>> +static int max77843_chg_init(struct max77843 *max77843)
>>>>>> +{
>>>>>
>>>>> Could this function be moved to the charger driver? This way the
>>>>> driver will manage its own resources instead of depending on parent
>>>>> MFD driver.
>>>>>
>>>>
>>>> Charger regulator and Charger share same resources.
>>>> So I include this function core driver.
>>>
>>> OK, I see... Could you describe it in comments somewhere? For example in
>>> comment above the function. Currently this looks like only as regmap for
>>> charger.
>>>
>>
>> Charger regulator and Charger use same regmap.
> 
> OK, just put it in a comment around that function.
>

OK, I add comment above max77843_chg_init function.

>>
>>> Unfortunately current solution imposes problem with releasing resources.
>>> Who is the owner of i2c dummy device?
>>>
>>
>> Core driver owner of i2c dummy device.
> 
> OK, good idea. So the core driver should be the only place to unregister
> it. So needed changes are:
> 1. Remove the i2c_unregister_device() call from
> max77843_charger_probe().
> 2. Add i2c_unregister_device(max77843->i2c_chg) in max77843_remove().
> 
> The MFD core driver will handle it.
> 

It will be fixed comply with your advice.

>>
>>> 1. The charger driver will unregister it if max77843_charger_probe()
>>> fails. What will happen with regulator driver in such case?
>>>
>>
>> Charger is enabled/disabled by Charger regulator.
>> Currently, If charger probe fails, charger regulator failed to read regmap and occur panic(It have to fix.)
>>
>>
>>> 2. Who will release this i2c dummy device in normal unbind? Currently it
>>> leaks.
>>>
>>
>> I think core driver release i2c dummy device in normal unbind.
>> We need to more discussion about this problem.
>> If you have any idea, I hope tell me. Again, Thank you for your advice.
> 
> I think handling the ownership in core driver could solve this.
> 
> Best regards,
> Krzysztof
> 

OK. I will fix it.

Thanks,
Beomho

> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" 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] 41+ messages in thread

* Re: [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver
@ 2015-01-23 11:26               ` Beomho Seo
  0 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-23 11:26 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Jaewon Kim, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Sebastian Reichel, Mark Brown

On 01/23/2015 08:18 PM, Krzysztof Kozlowski wrote:
> On pią, 2015-01-23 at 20:10 +0900, Beomho Seo wrote:
>> On 01/23/2015 04:16 PM, Krzysztof Kozlowski wrote:
>>> On pią, 2015-01-23 at 15:41 +0900, Beomho Seo wrote:
>>>> On 01/23/2015 03:32 PM, Krzysztof Kozlowski wrote:
>>>>> 2015-01-23 6:02 GMT+01:00 Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>:
>>>>>> This patch adds MAX77843 core/irq driver to support PMIC,
>>>>>> MUIC(Micro USB Interface Controller), Charger, Fuel Gauge,
>>>>>> LED and Haptic device.
>>>>>>
>>>>>> Cc: Lee Jones <lee.jones-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>>>>>> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>>>>> Signed-off-by: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>>>>> ---
>>>>>>  drivers/mfd/Kconfig                  |   14 ++
>>>>>>  drivers/mfd/Makefile                 |    1 +
>>>>>>  drivers/mfd/max77843.c               |  241 ++++++++++++++++++++
>>>>>>  include/linux/mfd/max77843-private.h |  410 ++++++++++++++++++++++++++++++++++
>>>>>>  4 files changed, 666 insertions(+)
>>>>>>  create mode 100644 drivers/mfd/max77843.c
>>>>>>  create mode 100644 include/linux/mfd/max77843-private.h
>>>>>>
>>>>>> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
>>>>>> index 2e6b731..0c67c79 100644
>>>>>> --- a/drivers/mfd/Kconfig
>>>>>> +++ b/drivers/mfd/Kconfig
>>>>>> @@ -442,6 +442,20 @@ config MFD_MAX77693
>>>>>>           additional drivers must be enabled in order to use the functionality
>>>>>>           of the device.
>>>>>>
>>>>>> +config MFD_MAX77843
>>>>>> +       bool "Maxim Semiconductor MAX77843 PMIC Support"
>>>>>> +       depends on I2C=y
>>>>>> +       select MFD_CORE
>>>>>> +       select REGMAP_I2C
>>>>>> +       select REGMAP_IRQ
>>>>>> +       help
>>>>>> +         Say yes here to add support for Maxim Semiconductor MAX77843.
>>>>>> +         This is companion Power Management IC with LEDs, Haptic, Charger,
>>>>>> +         Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip.
>>>>>> +         This driver provides common support for accessing the device;
>>>>>> +         additional drivers must be enabled in order to use the functionality
>>>>>> +         of the device.
>>>>>> +
>>>>>>  config MFD_MAX8907
>>>>>>         tristate "Maxim Semiconductor MAX8907 PMIC Support"
>>>>>>         select MFD_CORE
>>>>>> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
>>>>>> index 53467e2..fe4f75c 100644
>>>>>> --- a/drivers/mfd/Makefile
>>>>>> +++ b/drivers/mfd/Makefile
>>>>>> @@ -117,6 +117,7 @@ obj-$(CONFIG_MFD_DA9063)    += da9063.o
>>>>>>  obj-$(CONFIG_MFD_MAX14577)     += max14577.o
>>>>>>  obj-$(CONFIG_MFD_MAX77686)     += max77686.o
>>>>>>  obj-$(CONFIG_MFD_MAX77693)     += max77693.o
>>>>>> +obj-$(CONFIG_MFD_MAX77843)     += max77843.o
>>>>>>  obj-$(CONFIG_MFD_MAX8907)      += max8907.o
>>>>>>  max8925-objs                   := max8925-core.o max8925-i2c.o
>>>>>>  obj-$(CONFIG_MFD_MAX8925)      += max8925.o
>>>>>> diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c
>>>>>> new file mode 100644
>>>>>> index 0000000..d7f8b76
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/mfd/max77843.c
>>>>>> @@ -0,0 +1,241 @@
>>>>>> +/*
>>>>>> + * max77843.c - MFD core driver for the Maxim MAX77843
>>>>>> + *
>>>>>> + * Copyright (C) 2014 Samsung Electrnoics
>>>>>> + * Author: Jaewon Kim <jaewon02.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>>>>> + *
>>>>>> + * This program is free software; you can redistribute it and/or modify
>>>>>> + * it under the terms of the GNU General Public License as published by
>>>>>> + * the Free Software Foundation; either version 2 of the License, or
>>>>>> + * (at your option) any later version.
>>>>>> + */
>>>>>> +
>>>>>> +#include <linux/err.h>
>>>>>> +#include <linux/i2c.h>
>>>>>> +#include <linux/init.h>
>>>>>> +#include <linux/interrupt.h>
>>>>>> +#include <linux/module.h>
>>>>>> +#include <linux/mfd/core.h>
>>>>>> +#include <linux/mfd/max77843-private.h>
>>>>>> +#include <linux/of_device.h>
>>>>>> +#include <linux/platform_device.h>
>>>>>> +
>>>>>> +static const struct mfd_cell max77843_devs[] = {
>>>>>> +       {
>>>>>> +               .name = "max77843-muic",
>>>>>> +               .of_compatible = "maxim,max77843-muic",
>>>>>> +       }, {
>>>>>> +               .name = "max77843-regulator",
>>>>>> +               .of_compatible = "maxim,max77843-regulator",
>>>>>> +       }, {
>>>>>> +               .name = "max77843-charger",
>>>>>> +               .of_compatible = "maxim,max77843-charger"
>>>>>> +       }, {
>>>>>> +               .name = "max77843-fuelgauge",
>>>>>> +               .of_compatible = "maxim,max77843-fuelgauge",
>>>>>> +       },
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_config max77843_charger_regmap_config = {
>>>>>> +       .reg_bits       = 8,
>>>>>> +       .val_bits       = 8,
>>>>>> +       .max_register   = MAX77843_CHG_REG_END,
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_config max77843_regmap_config = {
>>>>>> +       .reg_bits       = 8,
>>>>>> +       .val_bits       = 8,
>>>>>> +       .max_register   = MAX77843_SYS_REG_END,
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_irq max77843_irqs[] = {
>>>>>> +       /* TOPSYS interrupts */
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSUVLO_INT, },
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_SYSOVLO_INT, },
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TSHDN_INT, },
>>>>>> +       { .reg_offset = 0, .mask = MAX77843_SYS_IRQ_TM_INT, },
>>>>>> +};
>>>>>> +
>>>>>> +static const struct regmap_irq_chip max77843_irq_chip = {
>>>>>> +       .name           = "max77843",
>>>>>> +       .status_base    = MAX77843_SYS_REG_SYSINTSRC,
>>>>>> +       .mask_base      = MAX77843_SYS_REG_SYSINTMASK,
>>>>>> +       .mask_invert    = false,
>>>>>> +       .num_regs       = 1,
>>>>>> +       .irqs           = max77843_irqs,
>>>>>> +       .num_irqs       = ARRAY_SIZE(max77843_irqs),
>>>>>> +};
>>>>>> +
>>>>>> +static int max77843_chg_init(struct max77843 *max77843)
>>>>>> +{
>>>>>
>>>>> Could this function be moved to the charger driver? This way the
>>>>> driver will manage its own resources instead of depending on parent
>>>>> MFD driver.
>>>>>
>>>>
>>>> Charger regulator and Charger share same resources.
>>>> So I include this function core driver.
>>>
>>> OK, I see... Could you describe it in comments somewhere? For example in
>>> comment above the function. Currently this looks like only as regmap for
>>> charger.
>>>
>>
>> Charger regulator and Charger use same regmap.
> 
> OK, just put it in a comment around that function.
>

OK, I add comment above max77843_chg_init function.

>>
>>> Unfortunately current solution imposes problem with releasing resources.
>>> Who is the owner of i2c dummy device?
>>>
>>
>> Core driver owner of i2c dummy device.
> 
> OK, good idea. So the core driver should be the only place to unregister
> it. So needed changes are:
> 1. Remove the i2c_unregister_device() call from
> max77843_charger_probe().
> 2. Add i2c_unregister_device(max77843->i2c_chg) in max77843_remove().
> 
> The MFD core driver will handle it.
> 

It will be fixed comply with your advice.

>>
>>> 1. The charger driver will unregister it if max77843_charger_probe()
>>> fails. What will happen with regulator driver in such case?
>>>
>>
>> Charger is enabled/disabled by Charger regulator.
>> Currently, If charger probe fails, charger regulator failed to read regmap and occur panic(It have to fix.)
>>
>>
>>> 2. Who will release this i2c dummy device in normal unbind? Currently it
>>> leaks.
>>>
>>
>> I think core driver release i2c dummy device in normal unbind.
>> We need to more discussion about this problem.
>> If you have any idea, I hope tell me. Again, Thank you for your advice.
> 
> I think handling the ownership in core driver could solve this.
> 
> Best regards,
> Krzysztof
> 

OK. I will fix it.

Thanks,
Beomho

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

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

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

* Re: [PATCH 4/6] power: max77843_battery: Add Max77843 fuel gauge device driver
@ 2015-01-25 13:53     ` Sebastian Reichel
  0 siblings, 0 replies; 41+ messages in thread
From: Sebastian Reichel @ 2015-01-25 13:53 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Mark Brown, Beomho Seo

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

Hi,

On Fri, Jan 23, 2015 at 02:02:45PM +0900, Jaewon Kim wrote:
> From: Beomho Seo <beomho.seo@samsung.com>
> 
> This patch adds device driver of max77843 fuel gauge.
> The driver support for battery fuel gauge in Maxim Max77843.
> It is fuel-gauge systems for lithuum-ion batteries in handled and
> portable devices.
> 
> Cc: Sebastian Reichel <sre@kernel.org>
> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
> ---
>  drivers/power/Kconfig            |    9 ++
>  drivers/power/Makefile           |    1 +
>  drivers/power/max77843_battery.c |  283 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 293 insertions(+)
>  create mode 100644 drivers/power/max77843_battery.c
> 
> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
> index a054a28..0039bbb 100644
> --- a/drivers/power/Kconfig
> +++ b/drivers/power/Kconfig
> @@ -212,6 +212,15 @@ config BATTERY_MAX17042
>  	  with MAX17042. This driver also supports max17047/50 chips which are
>  	  improved version of max17042.
>  
> +config BATTERY_MAX77843
> +	tristate "Maxim MAX77843 Fuel Gauge"
> +	depends on MFD_MAX77843
> +	help
> +	  This add support for battery fuel gauge in Maxim MAX77843.

add -> adds

> +	  It is fuel-gauge systems for lithuum-ion (Li+) batteries in handled and
> +	  portable devices. The MAX17040 is configured to operate with a single
> +	  lithium cell.

It is a fuel-gauge for a lithium-ion batteries with a single
cell and can be found in portable devices.

> +
>  config BATTERY_Z2
>  	tristate "Z2 battery driver"
>  	depends on I2C && MACH_ZIPIT2
> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
> index 212c6a2..ae0d795 100644
> --- a/drivers/power/Makefile
> +++ b/drivers/power/Makefile
> @@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
>  obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
>  obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
>  obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
> +obj-$(CONFIG_BATTERY_MAX77843)	+= max77843_battery.o
>  obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
>  obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
>  obj-$(CONFIG_BATTERY_TWL4030_MADC)	+= twl4030_madc_battery.o
> diff --git a/drivers/power/max77843_battery.c b/drivers/power/max77843_battery.c
> new file mode 100644
> index 0000000..a08dd0c
> --- /dev/null
> +++ b/drivers/power/max77843_battery.c
> @@ -0,0 +1,283 @@
> +/*
> + * Fuel gauge driver for Maxim MAX77843
> + *
> + * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
> + * Author: Beomho Seo <beomho.seo@samsung.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published bythe Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/mfd/max77843-private.h>
> +
> +struct max77843_battery {
> +	struct device		*dev;
> +	struct max77843		*max77843;
> +	struct i2c_client	*client;
> +	struct regmap		*regmap;
> +	struct power_supply	psy;
> +};
> +
> +static int max77843_battery_get_capacity(struct max77843_battery *battery)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	ret = regmap_bulk_read(regmap, MAX77843_FG_REG_SOCREP, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val =  ((reg_data[1] * 100) + (reg_data[0] * 100 / 256)) / 100;

so

val = reg_data[1]?

> +	return val;
> +}
> +
> +static int max77843_battery_get_energy_prop(struct max77843_battery *battery,
> +		enum power_supply_property psp)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	unsigned int reg;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_ENERGY_FULL:
> +		reg = MAX77843_FG_REG_FULLCAP;
> +		break;
> +	case POWER_SUPPLY_PROP_ENERGY_NOW:
> +		reg = MAX77843_FG_REG_REMCAP_REP;
> +		break;
> +	case POWER_SUPPLY_PROP_ENERGY_AVG:
> +		reg = MAX77843_FG_REG_REMCAP_AV;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val = (reg_data[1] << 8) | reg_data[0];
> +
> +	return val;
> +}
> +
> +static int max77843_battery_get_current_prop(struct max77843_battery *battery,
> +		enum power_supply_property psp)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	unsigned int reg;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
> +		reg = MAX77843_FG_REG_CURRENT;
> +		break;
> +	case POWER_SUPPLY_PROP_CURRENT_AVG:
> +		reg = MAX77843_FG_REG_AVG_CURRENT;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val = (reg_data[1] << 8) | reg_data[0];
> +	if (val & 0x8000) {
> +		/* Negative */
> +		val = ~val & 0xffff;
> +		val++;
> +		val *= -1;
> +	}
> +	/* Unit of current is mA */
> +	val =  val * 15625 / 100000;
> +
> +	return val;
> +}
> +
> +static int max77843_battery_get_voltage_prop(struct max77843_battery *battery,
> +		enum power_supply_property psp)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	unsigned int reg;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +		reg = MAX77843_FG_REG_VCELL;
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> +		reg = MAX77843_FG_REG_AVG_VCELL;
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
> +		reg = MAX77843_FG_REG_OCV;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val = ((reg_data[1] << 4) + (reg_data[0] >> 4)) * 125;
> +	val /= 100;
> +
> +	return val;
> +}
> +
> +static const char *model_name = "MAX77843";
> +static const char *manufacturer = "Maxim Integrated";
> +
> +static int max77843_battery_get_property(struct power_supply *psy,
> +		enum power_supply_property psp,
> +		union power_supply_propval *val)
> +{
> +	struct max77843_battery *battery = container_of(psy,
> +				struct max77843_battery, psy);
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
> +		val->intval = max77843_battery_get_voltage_prop(battery, psp);
> +		break;
> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
> +	case POWER_SUPPLY_PROP_CURRENT_AVG:
> +		val->intval = max77843_battery_get_current_prop(battery, psp);
> +		break;
> +	case POWER_SUPPLY_PROP_ENERGY_FULL:
> +	case POWER_SUPPLY_PROP_ENERGY_NOW:
> +	case POWER_SUPPLY_PROP_ENERGY_AVG:
> +		val->intval = max77843_battery_get_energy_prop(battery, psp);
> +		break;
> +	case POWER_SUPPLY_PROP_CAPACITY:
> +		val->intval = max77843_battery_get_capacity(battery);
> +		break;
> +	case POWER_SUPPLY_PROP_MODEL_NAME:
> +		val->strval =  model_name;
> +		break;
> +	case POWER_SUPPLY_PROP_MANUFACTURER:
> +		val->strval = manufacturer;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static enum power_supply_property max77843_battery_props[] = {
> +	POWER_SUPPLY_PROP_VOLTAGE_NOW,
> +	POWER_SUPPLY_PROP_VOLTAGE_AVG,
> +	POWER_SUPPLY_PROP_VOLTAGE_OCV,
> +	POWER_SUPPLY_PROP_CURRENT_NOW,
> +	POWER_SUPPLY_PROP_CURRENT_AVG,
> +	POWER_SUPPLY_PROP_ENERGY_FULL,
> +	POWER_SUPPLY_PROP_ENERGY_NOW,
> +	POWER_SUPPLY_PROP_ENERGY_AVG,
> +	POWER_SUPPLY_PROP_CAPACITY,
> +	POWER_SUPPLY_PROP_MODEL_NAME,
> +	POWER_SUPPLY_PROP_MANUFACTURER,
> +};
> +
> +static const struct regmap_config max77843_fuel_regmap_config = {
> +	.reg_bits	= 8,
> +	.val_bits	= 8,
> +	.max_register	= MAX77843_FG_END,
> +};

You always read 2 bytes, so it seems the device uses 16 bit sized
values?

> +static int max77843_battery_probe(struct platform_device *pdev)
> +{
> +	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
> +	struct max77843_battery *battery;
> +	int ret;
> +
> +	battery = devm_kzalloc(&pdev->dev, sizeof(*battery), GFP_KERNEL);
> +	if (!battery)
> +		return -ENOMEM;
> +
> +	battery->dev = &pdev->dev;
> +	battery->max77843 = max77843;
> +
> +	battery->client = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_FG);
> +	if (!battery->client) {
> +		dev_err(&pdev->dev, "Failed to get dummy i2c client.\n");
> +		return PTR_ERR(battery->client);
> +	}
> +	i2c_set_clientdata(battery->client, max77843);
> +
> +	battery->regmap = devm_regmap_init_i2c(battery->client,
> +			&max77843_fuel_regmap_config);
> +	if (IS_ERR(battery->regmap)) {
> +		ret = PTR_ERR(battery->regmap);
> +		goto err_i2c;
> +	}
> +
> +	platform_set_drvdata(pdev, battery);
> +
> +	battery->psy.name	= "max77843-fuelgauge";
> +	battery->psy.type	= POWER_SUPPLY_TYPE_BATTERY;
> +	battery->psy.get_property	= max77843_battery_get_property;
> +	battery->psy.properties		= max77843_battery_props;
> +	battery->psy.num_properties	= ARRAY_SIZE(max77843_battery_props);
> +
> +	ret = power_supply_register(&pdev->dev, &battery->psy);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed  to register power supply\n");
> +		goto err_i2c;
> +	}
> +
> +	return 0;
> +
> +err_i2c:
> +	i2c_unregister_device(battery->client);

This is missing in max77843_battery_remove()

> +
> +	return ret;
> +}
> +
> +static int max77843_battery_remove(struct platform_device *pdev)
> +{
> +	struct max77843_battery *battery = platform_get_drvdata(pdev);
> +
> +	power_supply_unregister(&battery->psy);
> +
> +	return 0;
> +}

> [...]

-- Sebastian

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

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

* Re: [PATCH 4/6] power: max77843_battery: Add Max77843 fuel gauge device driver
@ 2015-01-25 13:53     ` Sebastian Reichel
  0 siblings, 0 replies; 41+ messages in thread
From: Sebastian Reichel @ 2015-01-25 13:53 UTC (permalink / raw)
  To: Jaewon Kim
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Mark Brown, Beomho Seo

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

Hi,

On Fri, Jan 23, 2015 at 02:02:45PM +0900, Jaewon Kim wrote:
> From: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> 
> This patch adds device driver of max77843 fuel gauge.
> The driver support for battery fuel gauge in Maxim Max77843.
> It is fuel-gauge systems for lithuum-ion batteries in handled and
> portable devices.
> 
> Cc: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Signed-off-by: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
>  drivers/power/Kconfig            |    9 ++
>  drivers/power/Makefile           |    1 +
>  drivers/power/max77843_battery.c |  283 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 293 insertions(+)
>  create mode 100644 drivers/power/max77843_battery.c
> 
> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
> index a054a28..0039bbb 100644
> --- a/drivers/power/Kconfig
> +++ b/drivers/power/Kconfig
> @@ -212,6 +212,15 @@ config BATTERY_MAX17042
>  	  with MAX17042. This driver also supports max17047/50 chips which are
>  	  improved version of max17042.
>  
> +config BATTERY_MAX77843
> +	tristate "Maxim MAX77843 Fuel Gauge"
> +	depends on MFD_MAX77843
> +	help
> +	  This add support for battery fuel gauge in Maxim MAX77843.

add -> adds

> +	  It is fuel-gauge systems for lithuum-ion (Li+) batteries in handled and
> +	  portable devices. The MAX17040 is configured to operate with a single
> +	  lithium cell.

It is a fuel-gauge for a lithium-ion batteries with a single
cell and can be found in portable devices.

> +
>  config BATTERY_Z2
>  	tristate "Z2 battery driver"
>  	depends on I2C && MACH_ZIPIT2
> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
> index 212c6a2..ae0d795 100644
> --- a/drivers/power/Makefile
> +++ b/drivers/power/Makefile
> @@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
>  obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
>  obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
>  obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
> +obj-$(CONFIG_BATTERY_MAX77843)	+= max77843_battery.o
>  obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
>  obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
>  obj-$(CONFIG_BATTERY_TWL4030_MADC)	+= twl4030_madc_battery.o
> diff --git a/drivers/power/max77843_battery.c b/drivers/power/max77843_battery.c
> new file mode 100644
> index 0000000..a08dd0c
> --- /dev/null
> +++ b/drivers/power/max77843_battery.c
> @@ -0,0 +1,283 @@
> +/*
> + * Fuel gauge driver for Maxim MAX77843
> + *
> + * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
> + * Author: Beomho Seo <beomho.seo-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published bythe Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/mfd/max77843-private.h>
> +
> +struct max77843_battery {
> +	struct device		*dev;
> +	struct max77843		*max77843;
> +	struct i2c_client	*client;
> +	struct regmap		*regmap;
> +	struct power_supply	psy;
> +};
> +
> +static int max77843_battery_get_capacity(struct max77843_battery *battery)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	ret = regmap_bulk_read(regmap, MAX77843_FG_REG_SOCREP, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val =  ((reg_data[1] * 100) + (reg_data[0] * 100 / 256)) / 100;

so

val = reg_data[1]?

> +	return val;
> +}
> +
> +static int max77843_battery_get_energy_prop(struct max77843_battery *battery,
> +		enum power_supply_property psp)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	unsigned int reg;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_ENERGY_FULL:
> +		reg = MAX77843_FG_REG_FULLCAP;
> +		break;
> +	case POWER_SUPPLY_PROP_ENERGY_NOW:
> +		reg = MAX77843_FG_REG_REMCAP_REP;
> +		break;
> +	case POWER_SUPPLY_PROP_ENERGY_AVG:
> +		reg = MAX77843_FG_REG_REMCAP_AV;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val = (reg_data[1] << 8) | reg_data[0];
> +
> +	return val;
> +}
> +
> +static int max77843_battery_get_current_prop(struct max77843_battery *battery,
> +		enum power_supply_property psp)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	unsigned int reg;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
> +		reg = MAX77843_FG_REG_CURRENT;
> +		break;
> +	case POWER_SUPPLY_PROP_CURRENT_AVG:
> +		reg = MAX77843_FG_REG_AVG_CURRENT;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val = (reg_data[1] << 8) | reg_data[0];
> +	if (val & 0x8000) {
> +		/* Negative */
> +		val = ~val & 0xffff;
> +		val++;
> +		val *= -1;
> +	}
> +	/* Unit of current is mA */
> +	val =  val * 15625 / 100000;
> +
> +	return val;
> +}
> +
> +static int max77843_battery_get_voltage_prop(struct max77843_battery *battery,
> +		enum power_supply_property psp)
> +{
> +	struct regmap *regmap = battery->regmap;
> +	unsigned int reg;
> +	int ret, val;
> +	u8 reg_data[2];
> +
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +		reg = MAX77843_FG_REG_VCELL;
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> +		reg = MAX77843_FG_REG_AVG_VCELL;
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
> +		reg = MAX77843_FG_REG_OCV;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
> +	if (ret) {
> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
> +		return ret;
> +	}
> +
> +	val = ((reg_data[1] << 4) + (reg_data[0] >> 4)) * 125;
> +	val /= 100;
> +
> +	return val;
> +}
> +
> +static const char *model_name = "MAX77843";
> +static const char *manufacturer = "Maxim Integrated";
> +
> +static int max77843_battery_get_property(struct power_supply *psy,
> +		enum power_supply_property psp,
> +		union power_supply_propval *val)
> +{
> +	struct max77843_battery *battery = container_of(psy,
> +				struct max77843_battery, psy);
> +	switch (psp) {
> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
> +		val->intval = max77843_battery_get_voltage_prop(battery, psp);
> +		break;
> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
> +	case POWER_SUPPLY_PROP_CURRENT_AVG:
> +		val->intval = max77843_battery_get_current_prop(battery, psp);
> +		break;
> +	case POWER_SUPPLY_PROP_ENERGY_FULL:
> +	case POWER_SUPPLY_PROP_ENERGY_NOW:
> +	case POWER_SUPPLY_PROP_ENERGY_AVG:
> +		val->intval = max77843_battery_get_energy_prop(battery, psp);
> +		break;
> +	case POWER_SUPPLY_PROP_CAPACITY:
> +		val->intval = max77843_battery_get_capacity(battery);
> +		break;
> +	case POWER_SUPPLY_PROP_MODEL_NAME:
> +		val->strval =  model_name;
> +		break;
> +	case POWER_SUPPLY_PROP_MANUFACTURER:
> +		val->strval = manufacturer;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static enum power_supply_property max77843_battery_props[] = {
> +	POWER_SUPPLY_PROP_VOLTAGE_NOW,
> +	POWER_SUPPLY_PROP_VOLTAGE_AVG,
> +	POWER_SUPPLY_PROP_VOLTAGE_OCV,
> +	POWER_SUPPLY_PROP_CURRENT_NOW,
> +	POWER_SUPPLY_PROP_CURRENT_AVG,
> +	POWER_SUPPLY_PROP_ENERGY_FULL,
> +	POWER_SUPPLY_PROP_ENERGY_NOW,
> +	POWER_SUPPLY_PROP_ENERGY_AVG,
> +	POWER_SUPPLY_PROP_CAPACITY,
> +	POWER_SUPPLY_PROP_MODEL_NAME,
> +	POWER_SUPPLY_PROP_MANUFACTURER,
> +};
> +
> +static const struct regmap_config max77843_fuel_regmap_config = {
> +	.reg_bits	= 8,
> +	.val_bits	= 8,
> +	.max_register	= MAX77843_FG_END,
> +};

You always read 2 bytes, so it seems the device uses 16 bit sized
values?

> +static int max77843_battery_probe(struct platform_device *pdev)
> +{
> +	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
> +	struct max77843_battery *battery;
> +	int ret;
> +
> +	battery = devm_kzalloc(&pdev->dev, sizeof(*battery), GFP_KERNEL);
> +	if (!battery)
> +		return -ENOMEM;
> +
> +	battery->dev = &pdev->dev;
> +	battery->max77843 = max77843;
> +
> +	battery->client = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_FG);
> +	if (!battery->client) {
> +		dev_err(&pdev->dev, "Failed to get dummy i2c client.\n");
> +		return PTR_ERR(battery->client);
> +	}
> +	i2c_set_clientdata(battery->client, max77843);
> +
> +	battery->regmap = devm_regmap_init_i2c(battery->client,
> +			&max77843_fuel_regmap_config);
> +	if (IS_ERR(battery->regmap)) {
> +		ret = PTR_ERR(battery->regmap);
> +		goto err_i2c;
> +	}
> +
> +	platform_set_drvdata(pdev, battery);
> +
> +	battery->psy.name	= "max77843-fuelgauge";
> +	battery->psy.type	= POWER_SUPPLY_TYPE_BATTERY;
> +	battery->psy.get_property	= max77843_battery_get_property;
> +	battery->psy.properties		= max77843_battery_props;
> +	battery->psy.num_properties	= ARRAY_SIZE(max77843_battery_props);
> +
> +	ret = power_supply_register(&pdev->dev, &battery->psy);
> +	if (ret) {
> +		dev_err(&pdev->dev, "Failed  to register power supply\n");
> +		goto err_i2c;
> +	}
> +
> +	return 0;
> +
> +err_i2c:
> +	i2c_unregister_device(battery->client);

This is missing in max77843_battery_remove()

> +
> +	return ret;
> +}
> +
> +static int max77843_battery_remove(struct platform_device *pdev)
> +{
> +	struct max77843_battery *battery = platform_get_drvdata(pdev);
> +
> +	power_supply_unregister(&battery->psy);
> +
> +	return 0;
> +}

> [...]

-- Sebastian

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

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

* Re: [PATCH 4/6] power: max77843_battery: Add Max77843 fuel gauge device driver
  2015-01-25 13:53     ` Sebastian Reichel
  (?)
@ 2015-01-25 23:44     ` Beomho Seo
  -1 siblings, 0 replies; 41+ messages in thread
From: Beomho Seo @ 2015-01-25 23:44 UTC (permalink / raw)
  To: Sebastian Reichel, Jaewon Kim
  Cc: linux-kernel, devicetree, linux-pm, Inki Dae, Rob Herring,
	Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Lee Jones,
	Chanwoo Choi, Mark Brown

Hi,

Thanks for your review.

I'll fix patch as your advice.

Thanks,
Beomho Seo

On 01/25/2015 10:53 PM, Sebastian Reichel wrote:
> Hi,
> 
> On Fri, Jan 23, 2015 at 02:02:45PM +0900, Jaewon Kim wrote:
>> From: Beomho Seo <beomho.seo@samsung.com>
>>
>> This patch adds device driver of max77843 fuel gauge.
>> The driver support for battery fuel gauge in Maxim Max77843.
>> It is fuel-gauge systems for lithuum-ion batteries in handled and
>> portable devices.
>>
>> Cc: Sebastian Reichel <sre@kernel.org>
>> Signed-off-by: Beomho Seo <beomho.seo@samsung.com>
>> ---
>>  drivers/power/Kconfig            |    9 ++
>>  drivers/power/Makefile           |    1 +
>>  drivers/power/max77843_battery.c |  283 ++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 293 insertions(+)
>>  create mode 100644 drivers/power/max77843_battery.c
>>
>> diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
>> index a054a28..0039bbb 100644
>> --- a/drivers/power/Kconfig
>> +++ b/drivers/power/Kconfig
>> @@ -212,6 +212,15 @@ config BATTERY_MAX17042
>>  	  with MAX17042. This driver also supports max17047/50 chips which are
>>  	  improved version of max17042.
>>  
>> +config BATTERY_MAX77843
>> +	tristate "Maxim MAX77843 Fuel Gauge"
>> +	depends on MFD_MAX77843
>> +	help
>> +	  This add support for battery fuel gauge in Maxim MAX77843.
> 
> add -> adds
> 
>> +	  It is fuel-gauge systems for lithuum-ion (Li+) batteries in handled and
>> +	  portable devices. The MAX17040 is configured to operate with a single
>> +	  lithium cell.
> 
> It is a fuel-gauge for a lithium-ion batteries with a single
> cell and can be found in portable devices.
> 
>> +
>>  config BATTERY_Z2
>>  	tristate "Z2 battery driver"
>>  	depends on I2C && MACH_ZIPIT2
>> diff --git a/drivers/power/Makefile b/drivers/power/Makefile
>> index 212c6a2..ae0d795 100644
>> --- a/drivers/power/Makefile
>> +++ b/drivers/power/Makefile
>> @@ -33,6 +33,7 @@ obj-$(CONFIG_BATTERY_DA9030)	+= da9030_battery.o
>>  obj-$(CONFIG_BATTERY_DA9052)	+= da9052-battery.o
>>  obj-$(CONFIG_BATTERY_MAX17040)	+= max17040_battery.o
>>  obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
>> +obj-$(CONFIG_BATTERY_MAX77843)	+= max77843_battery.o
>>  obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
>>  obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
>>  obj-$(CONFIG_BATTERY_TWL4030_MADC)	+= twl4030_madc_battery.o
>> diff --git a/drivers/power/max77843_battery.c b/drivers/power/max77843_battery.c
>> new file mode 100644
>> index 0000000..a08dd0c
>> --- /dev/null
>> +++ b/drivers/power/max77843_battery.c
>> @@ -0,0 +1,283 @@
>> +/*
>> + * Fuel gauge driver for Maxim MAX77843
>> + *
>> + * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
>> + * Author: Beomho Seo <beomho.seo@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published bythe Free Software Foundation.
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/power_supply.h>
>> +#include <linux/mfd/max77843-private.h>
>> +
>> +struct max77843_battery {
>> +	struct device		*dev;
>> +	struct max77843		*max77843;
>> +	struct i2c_client	*client;
>> +	struct regmap		*regmap;
>> +	struct power_supply	psy;
>> +};
>> +
>> +static int max77843_battery_get_capacity(struct max77843_battery *battery)
>> +{
>> +	struct regmap *regmap = battery->regmap;
>> +	int ret, val;
>> +	u8 reg_data[2];
>> +
>> +	ret = regmap_bulk_read(regmap, MAX77843_FG_REG_SOCREP, reg_data, 2);
>> +	if (ret) {
>> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
>> +		return ret;
>> +	}
>> +
>> +	val =  ((reg_data[1] * 100) + (reg_data[0] * 100 / 256)) / 100;
> 
> so
> 
> val = reg_data[1]?
> 
>> +	return val;
>> +}
>> +
>> +static int max77843_battery_get_energy_prop(struct max77843_battery *battery,
>> +		enum power_supply_property psp)
>> +{
>> +	struct regmap *regmap = battery->regmap;
>> +	unsigned int reg;
>> +	int ret, val;
>> +	u8 reg_data[2];
>> +
>> +	switch (psp) {
>> +	case POWER_SUPPLY_PROP_ENERGY_FULL:
>> +		reg = MAX77843_FG_REG_FULLCAP;
>> +		break;
>> +	case POWER_SUPPLY_PROP_ENERGY_NOW:
>> +		reg = MAX77843_FG_REG_REMCAP_REP;
>> +		break;
>> +	case POWER_SUPPLY_PROP_ENERGY_AVG:
>> +		reg = MAX77843_FG_REG_REMCAP_AV;
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
>> +	if (ret) {
>> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
>> +		return ret;
>> +	}
>> +
>> +	val = (reg_data[1] << 8) | reg_data[0];
>> +
>> +	return val;
>> +}
>> +
>> +static int max77843_battery_get_current_prop(struct max77843_battery *battery,
>> +		enum power_supply_property psp)
>> +{
>> +	struct regmap *regmap = battery->regmap;
>> +	unsigned int reg;
>> +	int ret, val;
>> +	u8 reg_data[2];
>> +
>> +	switch (psp) {
>> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
>> +		reg = MAX77843_FG_REG_CURRENT;
>> +		break;
>> +	case POWER_SUPPLY_PROP_CURRENT_AVG:
>> +		reg = MAX77843_FG_REG_AVG_CURRENT;
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
>> +	if (ret) {
>> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
>> +		return ret;
>> +	}
>> +
>> +	val = (reg_data[1] << 8) | reg_data[0];
>> +	if (val & 0x8000) {
>> +		/* Negative */
>> +		val = ~val & 0xffff;
>> +		val++;
>> +		val *= -1;
>> +	}
>> +	/* Unit of current is mA */
>> +	val =  val * 15625 / 100000;
>> +
>> +	return val;
>> +}
>> +
>> +static int max77843_battery_get_voltage_prop(struct max77843_battery *battery,
>> +		enum power_supply_property psp)
>> +{
>> +	struct regmap *regmap = battery->regmap;
>> +	unsigned int reg;
>> +	int ret, val;
>> +	u8 reg_data[2];
>> +
>> +	switch (psp) {
>> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>> +		reg = MAX77843_FG_REG_VCELL;
>> +		break;
>> +	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
>> +		reg = MAX77843_FG_REG_AVG_VCELL;
>> +		break;
>> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
>> +		reg = MAX77843_FG_REG_OCV;
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	ret = regmap_bulk_read(regmap, reg, reg_data, 2);
>> +	if (ret) {
>> +		dev_err(battery->dev, "Failed to read fuelgauge register\n");
>> +		return ret;
>> +	}
>> +
>> +	val = ((reg_data[1] << 4) + (reg_data[0] >> 4)) * 125;
>> +	val /= 100;
>> +
>> +	return val;
>> +}
>> +
>> +static const char *model_name = "MAX77843";
>> +static const char *manufacturer = "Maxim Integrated";
>> +
>> +static int max77843_battery_get_property(struct power_supply *psy,
>> +		enum power_supply_property psp,
>> +		union power_supply_propval *val)
>> +{
>> +	struct max77843_battery *battery = container_of(psy,
>> +				struct max77843_battery, psy);
>> +	switch (psp) {
>> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
>> +	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
>> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
>> +		val->intval = max77843_battery_get_voltage_prop(battery, psp);
>> +		break;
>> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
>> +	case POWER_SUPPLY_PROP_CURRENT_AVG:
>> +		val->intval = max77843_battery_get_current_prop(battery, psp);
>> +		break;
>> +	case POWER_SUPPLY_PROP_ENERGY_FULL:
>> +	case POWER_SUPPLY_PROP_ENERGY_NOW:
>> +	case POWER_SUPPLY_PROP_ENERGY_AVG:
>> +		val->intval = max77843_battery_get_energy_prop(battery, psp);
>> +		break;
>> +	case POWER_SUPPLY_PROP_CAPACITY:
>> +		val->intval = max77843_battery_get_capacity(battery);
>> +		break;
>> +	case POWER_SUPPLY_PROP_MODEL_NAME:
>> +		val->strval =  model_name;
>> +		break;
>> +	case POWER_SUPPLY_PROP_MANUFACTURER:
>> +		val->strval = manufacturer;
>> +		break;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static enum power_supply_property max77843_battery_props[] = {
>> +	POWER_SUPPLY_PROP_VOLTAGE_NOW,
>> +	POWER_SUPPLY_PROP_VOLTAGE_AVG,
>> +	POWER_SUPPLY_PROP_VOLTAGE_OCV,
>> +	POWER_SUPPLY_PROP_CURRENT_NOW,
>> +	POWER_SUPPLY_PROP_CURRENT_AVG,
>> +	POWER_SUPPLY_PROP_ENERGY_FULL,
>> +	POWER_SUPPLY_PROP_ENERGY_NOW,
>> +	POWER_SUPPLY_PROP_ENERGY_AVG,
>> +	POWER_SUPPLY_PROP_CAPACITY,
>> +	POWER_SUPPLY_PROP_MODEL_NAME,
>> +	POWER_SUPPLY_PROP_MANUFACTURER,
>> +};
>> +
>> +static const struct regmap_config max77843_fuel_regmap_config = {
>> +	.reg_bits	= 8,
>> +	.val_bits	= 8,
>> +	.max_register	= MAX77843_FG_END,
>> +};
> 
> You always read 2 bytes, so it seems the device uses 16 bit sized
> values?
> 
>> +static int max77843_battery_probe(struct platform_device *pdev)
>> +{
>> +	struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
>> +	struct max77843_battery *battery;
>> +	int ret;
>> +
>> +	battery = devm_kzalloc(&pdev->dev, sizeof(*battery), GFP_KERNEL);
>> +	if (!battery)
>> +		return -ENOMEM;
>> +
>> +	battery->dev = &pdev->dev;
>> +	battery->max77843 = max77843;
>> +
>> +	battery->client = i2c_new_dummy(max77843->i2c->adapter, I2C_ADDR_FG);
>> +	if (!battery->client) {
>> +		dev_err(&pdev->dev, "Failed to get dummy i2c client.\n");
>> +		return PTR_ERR(battery->client);
>> +	}
>> +	i2c_set_clientdata(battery->client, max77843);
>> +
>> +	battery->regmap = devm_regmap_init_i2c(battery->client,
>> +			&max77843_fuel_regmap_config);
>> +	if (IS_ERR(battery->regmap)) {
>> +		ret = PTR_ERR(battery->regmap);
>> +		goto err_i2c;
>> +	}
>> +
>> +	platform_set_drvdata(pdev, battery);
>> +
>> +	battery->psy.name	= "max77843-fuelgauge";
>> +	battery->psy.type	= POWER_SUPPLY_TYPE_BATTERY;
>> +	battery->psy.get_property	= max77843_battery_get_property;
>> +	battery->psy.properties		= max77843_battery_props;
>> +	battery->psy.num_properties	= ARRAY_SIZE(max77843_battery_props);
>> +
>> +	ret = power_supply_register(&pdev->dev, &battery->psy);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "Failed  to register power supply\n");
>> +		goto err_i2c;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_i2c:
>> +	i2c_unregister_device(battery->client);
> 
> This is missing in max77843_battery_remove()
> 
>> +
>> +	return ret;
>> +}
>> +
>> +static int max77843_battery_remove(struct platform_device *pdev)
>> +{
>> +	struct max77843_battery *battery = platform_get_drvdata(pdev);
>> +
>> +	power_supply_unregister(&battery->psy);
>> +
>> +	return 0;
>> +}
> 
>> [...]
> 
> -- Sebastian
> 


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

end of thread, other threads:[~2015-01-25 23:44 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-23  5:02 [PATCH 0/6] Add new MFD driver for MAX77843 Jaewon Kim
2015-01-23  5:02 ` [PATCH 1/6] mfd: max77843: Add max77843 MFD driver core driver Jaewon Kim
2015-01-23  5:02   ` Jaewon Kim
2015-01-23  6:32   ` Krzysztof Kozlowski
2015-01-23  6:32     ` Krzysztof Kozlowski
2015-01-23  6:41     ` Beomho Seo
2015-01-23  6:41       ` Beomho Seo
2015-01-23  7:16       ` Krzysztof Kozlowski
2015-01-23 11:10         ` Beomho Seo
2015-01-23 11:18           ` Krzysztof Kozlowski
2015-01-23 11:26             ` Beomho Seo
2015-01-23 11:26               ` Beomho Seo
2015-01-23  6:55     ` Jaewon Kim
2015-01-23  6:55       ` Jaewon Kim
2015-01-23  7:05       ` Krzysztof Kozlowski
2015-01-23  7:05         ` Krzysztof Kozlowski
2015-01-23  6:49   ` Chanwoo Choi
2015-01-23  8:43     ` Jaewon Kim
2015-01-23  5:02 ` [PATCH 2/6] extcon: max77843: Add max77843 MUIC driver Jaewon Kim
2015-01-23  6:21   ` Chanwoo Choi
2015-01-23  6:21     ` Chanwoo Choi
2015-01-23 11:17     ` Jaewon Kim
2015-01-23  6:38   ` Krzysztof Kozłowski
2015-01-23  7:18     ` Jaewon Kim
2015-01-23  5:02 ` [PATCH 3/6] power: max77843_charger: Add Max77843 charger device driver Jaewon Kim
2015-01-23  5:02   ` Jaewon Kim
2015-01-23  7:04   ` Krzysztof Kozłowski
2015-01-23  7:28     ` Beomho Seo
2015-01-23  7:28       ` Beomho Seo
2015-01-23  5:02 ` [PATCH 4/6] power: max77843_battery: Add Max77843 fuel gauge " Jaewon Kim
2015-01-25 13:53   ` Sebastian Reichel
2015-01-25 13:53     ` Sebastian Reichel
2015-01-25 23:44     ` Beomho Seo
2015-01-23  5:02 ` [PATCH 5/6] regulator: max77843: Add max77843 regulator driver Jaewon Kim
2015-01-23  7:18   ` Krzysztof Kozłowski
2015-01-23  7:26     ` Jaewon Kim
2015-01-23  5:02 ` [PATCH 6/6] Documentation: Add device tree bindings document for max77843 Jaewon Kim
2015-01-23  6:25   ` Chanwoo Choi
2015-01-23  6:25     ` Chanwoo Choi
2015-01-23  7:40     ` Beomho Seo
2015-01-23  7:40       ` Beomho Seo

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