linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support
@ 2017-03-17  9:55 Hans de Goede
  2017-03-17  9:55 ` [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver Hans de Goede
                   ` (14 more replies)
  0 siblings, 15 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

Hi All,

Here is a patch-series adding support for the Intel Cherry Trail Whiskey
Cove PMIC. The first 2 patches have been send before and as such are
at v3 now, the rest is new. This series touches a lot of subsystems
(as usually is the case with mfd devices). I'm sending this as a single
series so that people can see how all the bits fit together.

Patches 1-13 do not have any interdependencies (other then runtime deps
which are not a problem for merging) and can be merged directly into
their resp. subsystems when they pass review.

Patch 14: power: supply: Add driver for Cherry Trail Whiskey Cove
PMIC Fuel Gauge, depends on the i2c-core changes from patches 11-13.

Patch 15: i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS
controller driver, depends on both the bq24190_charger patches as it
uses new bq24190_platform_data fields for the i2c_board_info->platform_data
for the i2c client it registers, as well as on patch 14 as it uses
the cht_wc_fg_get_property symbol that patch adds/exports.

Regards,

Hans

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

* [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:00   ` Andy Shevchenko
  2017-03-17  9:55 ` [PATCH 02/15] ACPI / PMIC: Add opregion driver for Intel CHT Whiskey Cove PMIC Hans de Goede
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm, Bin Gao, Felipe Balbi

Add mfd driver for Intel CHT Whiskey Cove PMIC, based on various non
upstreamed CHT Whiskey Cove PMIC patches.

This is a somewhat minimal version which adds irqchip support and cells
for: ACPI PMIC opregion support, the i2c-controller driving the external
charger irc and the pwrsrc/extcon block.

Further cells can be added in the future if/when drivers are upstreamed
for them.

Cc: Bin Gao <bin.gao@intel.com>
Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Since this uses plain mfd and not the intel_soc_pmic stuff give it
 its own Kconfig and allow this to be built as a module
-Add missing #include <acpi/acpi_bus.h>
Changes in v3:
-Drop #include <acpi/acpi_bus.h> again, not the right fix for the build errors
-Error out when the upper byte of the register-address passed to the regmap
 functions is 0 rather then hardcoding an address in that case
-Various minor style tweaks / cleanups
-Move defines of regulator register addresses to intel_pmic_chtwc.c,
 it is the only place where they are used
-Drop now empty include/linux/mfd/intel_chtwc.h
-Rename intel_soc_pmic_chtwc.c to intel_cht_wc.c to match Kconfig option name
-Add irqchip support
-Add external charger cell
-Add pwrsrc cell
---
 drivers/mfd/Kconfig                |  11 ++
 drivers/mfd/Makefile               |   1 +
 drivers/mfd/intel_soc_pmic_chtwc.c | 243 +++++++++++++++++++++++++++++++++++++
 3 files changed, 255 insertions(+)
 create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 55ecdfb..d427a10 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -437,6 +437,17 @@ config INTEL_SOC_PMIC
 	  thermal, charger and related power management functions
 	  on these systems.
 
+config INTEL_SOC_PMIC_CHTWC
+	tristate "Support for Intel Cherry Trail Whiskey Cove PMIC"
+	depends on ACPI
+	depends on I2C
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	help
+	  Select this option to enable support for the Intel Cherry Trail
+	  Whiskey Cove PMIC found on some Intel Cherry Trail systems.
+
 config MFD_INTEL_LPSS
 	tristate
 	select COMMON_CLK
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 31ce076..d2ca514 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -209,6 +209,7 @@ obj-$(CONFIG_MFD_SKY81452)	+= sky81452.o
 intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
 intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC)	+= intel_soc_pmic_bxtwc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
+obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o
 obj-$(CONFIG_MFD_MT6397)	+= mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR)	+= altera-a10sr.o
diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c
new file mode 100644
index 0000000..449462a
--- /dev/null
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -0,0 +1,243 @@
+/*
+ * MFD core driver for Intel Cherrytrail Whiskey Cove PMIC
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
+ * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+/* PMIC device registers */
+#define REG_OFFSET_MASK		GENMASK(7, 0)
+#define REG_ADDR_MASK		GENMASK(15, 8)
+#define REG_ADDR_SHIFT		8
+
+#define CHT_WC_IRQLVL1		0x6e02
+#define CHT_WC_IRQLVL1_MASK	0x6e0e
+
+/* Whiskey Cove PMIC share same ACPI ID between different platforms */
+#define CHT_WC_HRV		3
+
+/* Level 1 IRQs (level 2 IRQs are handled in the child device drivers) */
+enum {
+	CHT_WC_PWRSRC_IRQ = 0,
+	CHT_WC_THRM_IRQ,
+	CHT_WC_BCU_IRQ,
+	CHT_WC_ADC_IRQ,
+	CHT_WC_EXT_CHGR_IRQ,
+	CHT_WC_GPIO_IRQ,
+	/* There is no irq 6 */
+	CHT_WC_CRIT_IRQ = 7,
+};
+
+static struct resource cht_wc_pwrsrc_resources[] = {
+	DEFINE_RES_IRQ(CHT_WC_PWRSRC_IRQ),
+};
+
+static struct resource cht_wc_ext_charger_resources[] = {
+	DEFINE_RES_IRQ(CHT_WC_EXT_CHGR_IRQ),
+};
+
+static struct mfd_cell cht_wc_dev[] = {
+	{
+		.name = "cht_wcove_pwrsrc",
+		.num_resources = ARRAY_SIZE(cht_wc_pwrsrc_resources),
+		.resources = cht_wc_pwrsrc_resources,
+	},
+	{
+		.name = "cht_wcove_ext_chgr",
+		.num_resources = ARRAY_SIZE(cht_wc_ext_charger_resources),
+		.resources = cht_wc_ext_charger_resources,
+	},
+	{
+		.name = "cht_wcove_region",
+	},
+};
+
+/*
+ * The CHT Whiskey Cove covers multiple i2c addresses, with a 1 byte
+ * register address space per i2c address, so we use 16 bit register
+ * addresses where the high 8 bits contain the i2c client address.
+ */
+static int cht_wc_byte_reg_read(void *context, unsigned int reg,
+				unsigned int *val)
+{
+	struct i2c_client *client = context;
+	int ret, orig_addr = client->addr;
+
+	if (!(reg & REG_ADDR_MASK)) {
+		dev_err(&client->dev, "Error i2c address not specified\n");
+		return -EINVAL;
+	}
+
+	client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
+	ret = i2c_smbus_read_byte_data(client, reg & REG_OFFSET_MASK);
+	client->addr = orig_addr;
+
+	if (ret < 0)
+		return ret;
+
+	*val = ret;
+	return 0;
+}
+
+static int cht_wc_byte_reg_write(void *context, unsigned int reg,
+				 unsigned int val)
+{
+	struct i2c_client *client = context;
+	int ret, orig_addr = client->addr;
+
+	if (!(reg & REG_ADDR_MASK)) {
+		dev_err(&client->dev, "Error i2c address not specified\n");
+		return -EINVAL;
+	}
+
+	client->addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
+	ret = i2c_smbus_write_byte_data(client, reg & REG_OFFSET_MASK, val);
+	client->addr = orig_addr;
+
+	return ret;
+}
+
+static const struct regmap_config cht_wc_regmap_cfg = {
+	.reg_bits = 16,
+	.val_bits = 8,
+	.reg_write = cht_wc_byte_reg_write,
+	.reg_read = cht_wc_byte_reg_read,
+};
+
+static const struct regmap_irq cht_wc_regmap_irqs[] = {
+	REGMAP_IRQ_REG(CHT_WC_PWRSRC_IRQ, 0, BIT(CHT_WC_PWRSRC_IRQ)),
+	REGMAP_IRQ_REG(CHT_WC_THRM_IRQ, 0, BIT(CHT_WC_THRM_IRQ)),
+	REGMAP_IRQ_REG(CHT_WC_BCU_IRQ, 0, BIT(CHT_WC_BCU_IRQ)),
+	REGMAP_IRQ_REG(CHT_WC_ADC_IRQ, 0, BIT(CHT_WC_ADC_IRQ)),
+	REGMAP_IRQ_REG(CHT_WC_EXT_CHGR_IRQ, 0, BIT(CHT_WC_EXT_CHGR_IRQ)),
+	REGMAP_IRQ_REG(CHT_WC_GPIO_IRQ, 0, BIT(CHT_WC_GPIO_IRQ)),
+	REGMAP_IRQ_REG(CHT_WC_CRIT_IRQ, 0, BIT(CHT_WC_CRIT_IRQ)),
+};
+
+static const struct regmap_irq_chip cht_wc_regmap_irq_chip = {
+	.name = "cht_wc_irq_chip",
+	.status_base = CHT_WC_IRQLVL1,
+	.mask_base = CHT_WC_IRQLVL1_MASK,
+	.irqs = cht_wc_regmap_irqs,
+	.num_irqs = ARRAY_SIZE(cht_wc_regmap_irqs),
+	.num_regs = 1,
+};
+
+static int cht_wc_probe(struct i2c_client *client,
+			const struct i2c_device_id *i2c_id)
+{
+	struct device *dev = &client->dev;
+	struct intel_soc_pmic *pmic;
+	acpi_status status;
+	unsigned long long hrv;
+	int ret;
+
+	status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv);
+	if (ACPI_FAILURE(status)) {
+		dev_err(dev, "Failed to get PMIC hardware revision\n");
+		return -ENODEV;
+	}
+	if (hrv != CHT_WC_HRV) {
+		dev_err(dev, "Invalid PMIC hardware revision: %llu\n", hrv);
+		return -ENODEV;
+	}
+	if (client->irq < 0) {
+		dev_err(dev, "Invalid IRQ\n");
+		return -ENODEV;
+	}
+
+	pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+	if (!pmic)
+		return -ENOMEM;
+
+	pmic->irq = client->irq;
+	pmic->dev = dev;
+	i2c_set_clientdata(client, pmic);
+
+	pmic->regmap = devm_regmap_init(dev, NULL, client, &cht_wc_regmap_cfg);
+	if (IS_ERR(pmic->regmap))
+		return PTR_ERR(pmic->regmap);
+
+	ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,
+				       IRQF_ONESHOT | IRQF_SHARED, 0,
+				       &cht_wc_regmap_irq_chip,
+				       &pmic->irq_chip_data);
+	if (ret)
+		return ret;
+
+	return devm_mfd_add_devices(dev, -1, cht_wc_dev, ARRAY_SIZE(cht_wc_dev),
+			NULL, 0, regmap_irq_get_domain(pmic->irq_chip_data));
+}
+
+static void cht_wc_shutdown(struct i2c_client *client)
+{
+	struct intel_soc_pmic *pmic = i2c_get_clientdata(client);
+
+	disable_irq(pmic->irq);
+}
+
+static int __maybe_unused cht_wc_suspend(struct device *dev)
+{
+	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
+
+	disable_irq(pmic->irq);
+	return 0;
+}
+
+static int __maybe_unused cht_wc_resume(struct device *dev)
+{
+	struct intel_soc_pmic *pmic = dev_get_drvdata(dev);
+
+	enable_irq(pmic->irq);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume);
+
+static const struct i2c_device_id cht_wc_i2c_id[] = {
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cht_wc_i2c_id);
+
+static const struct acpi_device_id cht_wc_acpi_ids[] = {
+	{ "INT34D3", },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, cht_wc_acpi_ids);
+
+static struct i2c_driver cht_wc_driver = {
+	.driver	= {
+		.name	= "CHT Whiskey Cove PMIC",
+		.pm     = &cht_wc_pm_ops,
+		.acpi_match_table = ACPI_PTR(cht_wc_acpi_ids),
+	},
+	.probe = cht_wc_probe,
+	.shutdown = cht_wc_shutdown,
+	.id_table = cht_wc_i2c_id,
+};
+
+module_i2c_driver(cht_wc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
-- 
2.9.3

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

* [PATCH 02/15] ACPI / PMIC: Add opregion driver for Intel CHT Whiskey Cove PMIC
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
  2017-03-17  9:55 ` [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17  9:55 ` [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver Hans de Goede
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm, Bin Gao, Felipe Balbi

Add opregion driver for Intel CHT Whiskey Cove PMIC, based on various
non upstreamed CHT Whiskey Cove PMIC patches. This does not include
support for the Thermal opregion (DPTF) due to lacking documentation.

Cc: Bin Gao <bin.gao@intel.com>
Cc: Felipe Balbi <felipe.balbi@linux.intel.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
Changes in v2:
-s/WhiskeyCove/Whiskey Cove/
-Some minor style tweaks
-Allow building as module
Changes in v3:
-Drop filename from copyright header
-Simplify intel_cht_wc_pmic_update_power to 1 line
-Move defines of regulator register addresses to intel_pmic_chtwc.c,
 it is the only place where they are used
---
 drivers/acpi/Kconfig                 |   6 +
 drivers/acpi/Makefile                |   1 +
 drivers/acpi/pmic/intel_pmic_chtwc.c | 280 +++++++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)
 create mode 100644 drivers/acpi/pmic/intel_pmic_chtwc.c

diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 83e5f7e..e3c4ef0 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -516,6 +516,12 @@ config BXT_WC_PMIC_OPREGION
 	help
 	  This config adds ACPI operation region support for BXT WhiskeyCove PMIC.
 
+config CHT_WC_PMIC_OPREGION
+	tristate "ACPI operation region support for CHT Whiskey Cove PMIC"
+	depends on INTEL_SOC_PMIC_CHTWC
+	help
+	  This config adds ACPI operation region support for CHT Whiskey Cove PMIC.
+
 endif
 
 config ACPI_CONFIGFS
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index a391bbc..6f6b47f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -102,6 +102,7 @@ obj-$(CONFIG_PMIC_OPREGION)	+= pmic/intel_pmic.o
 obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
 obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
 obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += pmic/intel_pmic_bxtwc.o
+obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o
 
 obj-$(CONFIG_ACPI_CONFIGFS)	+= acpi_configfs.o
 
diff --git a/drivers/acpi/pmic/intel_pmic_chtwc.c b/drivers/acpi/pmic/intel_pmic_chtwc.c
new file mode 100644
index 0000000..85636d7
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic_chtwc.c
@@ -0,0 +1,280 @@
+/*
+ * Intel CHT Whiskey Cove PMIC operation region driver
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
+ * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include "intel_pmic.h"
+
+#define CHT_WC_V1P05A_CTRL		0x6e3b
+#define CHT_WC_V1P15_CTRL		0x6e3c
+#define CHT_WC_V1P05A_VSEL		0x6e3d
+#define CHT_WC_V1P15_VSEL		0x6e3e
+#define CHT_WC_V1P8A_CTRL		0x6e56
+#define CHT_WC_V1P8SX_CTRL		0x6e57
+#define CHT_WC_VDDQ_CTRL		0x6e58
+#define CHT_WC_V1P2A_CTRL		0x6e59
+#define CHT_WC_V1P2SX_CTRL		0x6e5a
+#define CHT_WC_V1P8A_VSEL		0x6e5b
+#define CHT_WC_VDDQ_VSEL		0x6e5c
+#define CHT_WC_V2P8SX_CTRL		0x6e5d
+#define CHT_WC_V3P3A_CTRL		0x6e5e
+#define CHT_WC_V3P3SD_CTRL		0x6e5f
+#define CHT_WC_VSDIO_CTRL		0x6e67
+#define CHT_WC_V3P3A_VSEL		0x6e68
+#define CHT_WC_VPROG1A_CTRL		0x6e90
+#define CHT_WC_VPROG1B_CTRL		0x6e91
+#define CHT_WC_VPROG1F_CTRL		0x6e95
+#define CHT_WC_VPROG2D_CTRL		0x6e99
+#define CHT_WC_VPROG3A_CTRL		0x6e9a
+#define CHT_WC_VPROG3B_CTRL		0x6e9b
+#define CHT_WC_VPROG4A_CTRL		0x6e9c
+#define CHT_WC_VPROG4B_CTRL		0x6e9d
+#define CHT_WC_VPROG4C_CTRL		0x6e9e
+#define CHT_WC_VPROG4D_CTRL		0x6e9f
+#define CHT_WC_VPROG5A_CTRL		0x6ea0
+#define CHT_WC_VPROG5B_CTRL		0x6ea1
+#define CHT_WC_VPROG6A_CTRL		0x6ea2
+#define CHT_WC_VPROG6B_CTRL		0x6ea3
+#define CHT_WC_VPROG1A_VSEL		0x6ec0
+#define CHT_WC_VPROG1B_VSEL		0x6ec1
+#define CHT_WC_V1P8SX_VSEL		0x6ec2
+#define CHT_WC_V1P2SX_VSEL		0x6ec3
+#define CHT_WC_V1P2A_VSEL		0x6ec4
+#define CHT_WC_VPROG1F_VSEL		0x6ec5
+#define CHT_WC_VSDIO_VSEL		0x6ec6
+#define CHT_WC_V2P8SX_VSEL		0x6ec7
+#define CHT_WC_V3P3SD_VSEL		0x6ec8
+#define CHT_WC_VPROG2D_VSEL		0x6ec9
+#define CHT_WC_VPROG3A_VSEL		0x6eca
+#define CHT_WC_VPROG3B_VSEL		0x6ecb
+#define CHT_WC_VPROG4A_VSEL		0x6ecc
+#define CHT_WC_VPROG4B_VSEL		0x6ecd
+#define CHT_WC_VPROG4C_VSEL		0x6ece
+#define CHT_WC_VPROG4D_VSEL		0x6ecf
+#define CHT_WC_VPROG5A_VSEL		0x6ed0
+#define CHT_WC_VPROG5B_VSEL		0x6ed1
+#define CHT_WC_VPROG6A_VSEL		0x6ed2
+#define CHT_WC_VPROG6B_VSEL		0x6ed3
+
+/*
+ * Regulator support is based on the non upstream patch:
+ * "regulator: whiskey_cove: implements Whiskey Cove pmic VRF support"
+ * https://github.com/intel-aero/meta-intel-aero/blob/master/recipes-kernel/linux/linux-yocto/0019-regulator-whiskey_cove-implements-WhiskeyCove-pmic-V.patch
+ */
+static struct pmic_table power_table[] = {
+	{
+		.address = 0x0,
+		.reg = CHT_WC_V1P8A_CTRL,
+		.bit = 0x01,
+	}, /* V18A */
+	{
+		.address = 0x04,
+		.reg = CHT_WC_V1P8SX_CTRL,
+		.bit = 0x07,
+	}, /* V18X */
+	{
+		.address = 0x08,
+		.reg = CHT_WC_VDDQ_CTRL,
+		.bit = 0x01,
+	}, /* VDDQ */
+	{
+		.address = 0x0c,
+		.reg = CHT_WC_V1P2A_CTRL,
+		.bit = 0x07,
+	}, /* V12A */
+	{
+		.address = 0x10,
+		.reg = CHT_WC_V1P2SX_CTRL,
+		.bit = 0x07,
+	}, /* V12X */
+	{
+		.address = 0x14,
+		.reg = CHT_WC_V2P8SX_CTRL,
+		.bit = 0x07,
+	}, /* V28X */
+	{
+		.address = 0x18,
+		.reg = CHT_WC_V3P3A_CTRL,
+		.bit = 0x01,
+	}, /* V33A */
+	{
+		.address = 0x1c,
+		.reg = CHT_WC_V3P3SD_CTRL,
+		.bit = 0x07,
+	}, /* V3SD */
+	{
+		.address = 0x20,
+		.reg = CHT_WC_VSDIO_CTRL,
+		.bit = 0x07,
+	}, /* VSD */
+/*	{
+		.address = 0x24,
+		.reg = ??,
+		.bit = ??,
+	}, ** VSW2 */
+/*	{
+		.address = 0x28,
+		.reg = ??,
+		.bit = ??,
+	}, ** VSW1 */
+/*	{
+		.address = 0x2c,
+		.reg = ??,
+		.bit = ??,
+	}, ** VUPY */
+/*	{
+		.address = 0x30,
+		.reg = ??,
+		.bit = ??,
+	}, ** VRSO */
+	{
+		.address = 0x34,
+		.reg = CHT_WC_VPROG1A_CTRL,
+		.bit = 0x07,
+	}, /* VP1A */
+	{
+		.address = 0x38,
+		.reg = CHT_WC_VPROG1B_CTRL,
+		.bit = 0x07,
+	}, /* VP1B */
+	{
+		.address = 0x3c,
+		.reg = CHT_WC_VPROG1F_CTRL,
+		.bit = 0x07,
+	}, /* VP1F */
+	{
+		.address = 0x40,
+		.reg = CHT_WC_VPROG2D_CTRL,
+		.bit = 0x07,
+	}, /* VP2D */
+	{
+		.address = 0x44,
+		.reg = CHT_WC_VPROG3A_CTRL,
+		.bit = 0x07,
+	}, /* VP3A */
+	{
+		.address = 0x48,
+		.reg = CHT_WC_VPROG3B_CTRL,
+		.bit = 0x07,
+	}, /* VP3B */
+	{
+		.address = 0x4c,
+		.reg = CHT_WC_VPROG4A_CTRL,
+		.bit = 0x07,
+	}, /* VP4A */
+	{
+		.address = 0x50,
+		.reg = CHT_WC_VPROG4B_CTRL,
+		.bit = 0x07,
+	}, /* VP4B */
+	{
+		.address = 0x54,
+		.reg = CHT_WC_VPROG4C_CTRL,
+		.bit = 0x07,
+	}, /* VP4C */
+	{
+		.address = 0x58,
+		.reg = CHT_WC_VPROG4D_CTRL,
+		.bit = 0x07,
+	}, /* VP4D */
+	{
+		.address = 0x5c,
+		.reg = CHT_WC_VPROG5A_CTRL,
+		.bit = 0x07,
+	}, /* VP5A */
+	{
+		.address = 0x60,
+		.reg = CHT_WC_VPROG5B_CTRL,
+		.bit = 0x07,
+	}, /* VP5B */
+	{
+		.address = 0x64,
+		.reg = CHT_WC_VPROG6A_CTRL,
+		.bit = 0x07,
+	}, /* VP6A */
+	{
+		.address = 0x68,
+		.reg = CHT_WC_VPROG6B_CTRL,
+		.bit = 0x07,
+	}, /* VP6B */
+/*	{
+		.address = 0x6c,
+		.reg = ??,
+		.bit = ??,
+	}  ** VP7A */
+};
+
+static int intel_cht_wc_pmic_get_power(struct regmap *regmap, int reg,
+		int bit, u64 *value)
+{
+	int data;
+
+	if (regmap_read(regmap, reg, &data))
+		return -EIO;
+
+	*value = (data & bit) ? 1 : 0;
+	return 0;
+}
+
+static int intel_cht_wc_pmic_update_power(struct regmap *regmap, int reg,
+		int bitmask, bool on)
+{
+	return regmap_update_bits(regmap, reg, bitmask, on ? 1 : 0);
+}
+
+/*
+ * The thermal table and ops are empty, we do not support the Thermal opregion
+ * (DPTF) due to lacking documentation.
+ */
+static struct intel_pmic_opregion_data intel_cht_wc_pmic_opregion_data = {
+	.get_power		= intel_cht_wc_pmic_get_power,
+	.update_power		= intel_cht_wc_pmic_update_power,
+	.power_table		= power_table,
+	.power_table_count	= ARRAY_SIZE(power_table),
+};
+
+static int intel_cht_wc_pmic_opregion_probe(struct platform_device *pdev)
+{
+	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+
+	return intel_pmic_install_opregion_handler(&pdev->dev,
+			ACPI_HANDLE(pdev->dev.parent),
+			pmic->regmap,
+			&intel_cht_wc_pmic_opregion_data);
+}
+
+static struct platform_device_id cht_wc_opregion_id_table[] = {
+	{ .name = "cht_wcove_region" },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, cht_wc_opregion_id_table);
+
+static struct platform_driver intel_cht_wc_pmic_opregion_driver = {
+	.probe = intel_cht_wc_pmic_opregion_probe,
+	.driver = {
+		.name = "cht_whiskey_cove_pmic",
+	},
+	.id_table = cht_wc_opregion_id_table,
+};
+module_platform_driver(intel_cht_wc_pmic_opregion_driver);
+
+MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC operation region driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
-- 
2.9.3

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

* [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
  2017-03-17  9:55 ` [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver Hans de Goede
  2017-03-17  9:55 ` [PATCH 02/15] ACPI / PMIC: Add opregion driver for Intel CHT Whiskey Cove PMIC Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:18   ` Andy Shevchenko
  2017-03-20  1:33   ` Chanwoo Choi
  2017-03-17  9:55 ` [PATCH 04/15] power: supply: bq24190_charger: Add no_register_reset pdata flag Hans de Goede
                   ` (11 subsequent siblings)
  14 siblings, 2 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

Add a driver for charger detection / control on the Intel Cherrytrail
Whiskey Cove PMIC.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/extcon/Kconfig         |   7 +
 drivers/extcon/Makefile        |   1 +
 drivers/extcon/extcon-cht-wc.c | 356 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 364 insertions(+)
 create mode 100644 drivers/extcon/extcon-cht-wc.c

diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
index 96bbae5..4cace6b 100644
--- a/drivers/extcon/Kconfig
+++ b/drivers/extcon/Kconfig
@@ -52,6 +52,13 @@ config EXTCON_INTEL_INT3496
 	  This ACPI device is typically found on Intel Baytrail or Cherrytrail
 	  based tablets, or other Baytrail / Cherrytrail devices.
 
+config EXTCON_CHT_WC
+	tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver"
+	depends on INTEL_SOC_PMIC_CHTWC
+	help
+	  Say Y here to enable extcon support for charger detection / control
+	  on the Intel Cherrytrail Whiskey Cove PMIC.
+
 config EXTCON_MAX14577
 	tristate "Maxim MAX14577/77836 EXTCON Support"
 	depends on MFD_MAX14577
diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
index 237ac3f..160f88b 100644
--- a/drivers/extcon/Makefile
+++ b/drivers/extcon/Makefile
@@ -7,6 +7,7 @@ extcon-core-objs		+= extcon.o devres.o
 obj-$(CONFIG_EXTCON_ADC_JACK)	+= extcon-adc-jack.o
 obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
 obj-$(CONFIG_EXTCON_AXP288)	+= extcon-axp288.o
+obj-$(CONFIG_EXTCON_CHT_WC)	+= extcon-cht-wc.o
 obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
 obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
 obj-$(CONFIG_EXTCON_MAX14577)	+= extcon-max14577.o
diff --git a/drivers/extcon/extcon-cht-wc.c b/drivers/extcon/extcon-cht-wc.c
new file mode 100644
index 0000000..896eee6
--- /dev/null
+++ b/drivers/extcon/extcon-cht-wc.c
@@ -0,0 +1,356 @@
+/*
+ * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
+ * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/extcon.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define CHT_WC_PWRSRC_IRQ		0x6e03
+#define CHT_WC_PWRSRC_IRQ_MASK		0x6e0f
+#define CHT_WC_PWRSRC_STS		0x6e1e
+#define CHT_WC_PWRSRC_VBUS		BIT(0)
+#define CHT_WC_PWRSRC_DC		BIT(1)
+#define CHT_WC_PWRSRC_BAT		BIT(2)
+#define CHT_WC_PWRSRC_ID_GND		BIT(3)
+#define CHT_WC_PWRSRC_ID_FLOAT		BIT(4)
+
+#define CHT_WC_PHYCTRL			0x5e07
+
+#define CHT_WC_CHGRCTRL0		0x5e16
+
+#define CHT_WC_CHGRCTRL0		0x5e16
+#define CHT_WC_CHGRCTRL0_CHGRRESET	BIT(0)
+#define CHT_WC_CHGRCTRL0_EMRGCHREN	BIT(1)
+#define CHT_WC_CHGRCTRL0_EXTCHRDIS	BIT(2)
+#define CHT_WC_CHGRCTRL0_SWCONTROL	BIT(3)
+#define CHT_WC_CHGRCTRL0_TTLCK_MASK	BIT(4)
+#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK	BIT(5)
+#define CHT_WC_CHGRCTRL0_DBPOFF_MASK	BIT(6)
+#define CHT_WC_CHGRCTRL0_WDT_NOKICK	BIT(7)
+
+#define CHT_WC_CHGRCTRL1		0x5e17
+
+#define CHT_WC_USBSRC			0x5e29
+#define CHT_WC_USBSRC_STS_MASK		GENMASK(1, 0)
+#define CHT_WC_USBSRC_STS_SUCCESS	2
+#define CHT_WC_USBSRC_STS_FAIL		3
+#define CHT_WC_USBSRC_TYPE_SHIFT	2
+#define CHT_WC_USBSRC_TYPE_MASK		GENMASK(5, 2)
+#define CHT_WC_USBSRC_TYPE_NONE		0
+#define CHT_WC_USBSRC_TYPE_SDP		1
+#define CHT_WC_USBSRC_TYPE_DCP		2
+#define CHT_WC_USBSRC_TYPE_CDP		3
+#define CHT_WC_USBSRC_TYPE_ACA		4
+#define CHT_WC_USBSRC_TYPE_SE1		5
+#define CHT_WC_USBSRC_TYPE_MHL		6
+#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN	7
+#define CHT_WC_USBSRC_TYPE_OTHER	8
+#define CHT_WC_USBSRC_TYPE_DCP_EXTPHY	9
+
+enum cht_wc_usb_id {
+	USB_ID_OTG,
+	USB_ID_GND,
+	USB_ID_FLOAT,
+	USB_RID_A,
+	USB_RID_B,
+	USB_RID_C,
+};
+
+/* Strings matching the cht_wc_usb_id enum labels */
+static const char * const usb_id_str[] = {
+	"otg", "gnd", "float", "rid_a", "rid_b", "rid_c" };
+
+enum cht_wc_mux_select {
+	MUX_SEL_PMIC = 0,
+	MUX_SEL_SOC,
+};
+
+static const unsigned int cht_wc_extcon_cables[] = {
+	EXTCON_USB,
+	EXTCON_USB_HOST,
+	EXTCON_CHG_USB_SDP,
+	EXTCON_CHG_USB_CDP,
+	EXTCON_CHG_USB_DCP,
+	EXTCON_NONE,
+};
+
+struct cht_wc_extcon_data {
+	struct device *dev;
+	struct regmap *regmap;
+	struct extcon_dev *edev;
+	unsigned int previous_cable;
+	int usb_id;
+};
+
+static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
+{
+	if (ext->usb_id)
+		return ext->usb_id;
+
+	if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
+		return USB_ID_GND;
+	if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
+		return USB_ID_FLOAT;
+
+	/*
+	 * Once we have iio support for the gpadc we should read the USBID
+	 * gpadc channel here and determine ACA role based on that.
+	 */
+	return USB_ID_FLOAT;
+}
+
+static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext)
+{
+	int ret, usbsrc, status, retries = 5;
+
+	do {
+		ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc);
+		if (ret) {
+			dev_err(ext->dev, "Error reading usbsrc: %d\n", ret);
+			return ret;
+		}
+		status = usbsrc & CHT_WC_USBSRC_STS_MASK;
+		if (status == CHT_WC_USBSRC_STS_SUCCESS ||
+		    status == CHT_WC_USBSRC_STS_FAIL)
+			break;
+
+		msleep(200);
+	} while (retries--);
+
+	if (status != CHT_WC_USBSRC_STS_SUCCESS) {
+		if (status == CHT_WC_USBSRC_STS_FAIL)
+			dev_warn(ext->dev, "Could not detect charger type\n");
+		else
+			dev_warn(ext->dev, "Timeout detecting charger type\n");
+		return EXTCON_CHG_USB_SDP; /* Save fallback */
+	}
+
+	ret = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;
+	switch (ret) {
+	default:
+		dev_warn(ext->dev, "Unhandled charger type %d\n", ret);
+		/* Fall through treat as SDP */
+	case CHT_WC_USBSRC_TYPE_SDP:
+	case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
+	case CHT_WC_USBSRC_TYPE_OTHER:
+		return EXTCON_CHG_USB_SDP;
+	case CHT_WC_USBSRC_TYPE_CDP:
+		return EXTCON_CHG_USB_CDP;
+	case CHT_WC_USBSRC_TYPE_DCP:
+	case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
+	case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
+		return EXTCON_CHG_USB_DCP;
+	case CHT_WC_USBSRC_TYPE_ACA:
+		return EXTCON_CHG_USB_ACA;
+	}
+}
+
+static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state)
+{
+	int ret;
+
+	ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state);
+	if (ret)
+		dev_err(ext->dev, "Error writing phyctrl: %d\n", ret);
+}
+
+static void cht_wc_extcon_det_event(struct cht_wc_extcon_data *ext)
+{
+	int ret, pwrsrc_sts, id;
+	unsigned int cable = EXTCON_NONE;
+
+	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
+	if (ret) {
+		dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
+		return;
+	}
+
+	id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
+	if (id == USB_ID_GND) {
+		/* The 5v boost causes a false VBUS / SDP detect, skip */
+		goto charger_det_done;
+	}
+
+	/* Plugged into a host/charger or not connected? */
+	if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) {
+		/* Route D+ and D- to PMIC for future charger detection */
+		cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
+		goto set_state;
+	}
+
+	ret = cht_wc_extcon_get_charger(ext);
+	if (ret >= 0)
+		cable = ret;
+
+charger_det_done:
+	/* Route D+ and D- to SoC for the host / gadget controller */
+	cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC);
+
+set_state:
+	extcon_set_state_sync(ext->edev, cable, true);
+	extcon_set_state_sync(ext->edev, ext->previous_cable, false);
+	extcon_set_state_sync(ext->edev, EXTCON_USB_HOST,
+			      id == USB_ID_GND || id == USB_RID_A);
+	ext->previous_cable = cable;
+}
+
+static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
+{
+	struct cht_wc_extcon_data *ext = data;
+	int ret, irqs;
+
+	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
+	if (ret)
+		dev_err(ext->dev, "Error reading irqs: %d\n", ret);
+
+	cht_wc_extcon_det_event(ext);
+
+	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
+	if (ret)
+		dev_err(ext->dev, "Error writing irqs: %d\n", ret);
+
+	return IRQ_HANDLED;
+}
+
+/* usb_id sysfs attribute for debug / testing purposes */
+static ssize_t usb_id_show(struct device *dev, struct device_attribute *attr,
+			   char *buf)
+{
+	struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", usb_id_str[ext->usb_id]);
+}
+
+static ssize_t usb_id_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t n)
+{
+	struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(usb_id_str); i++) {
+		if (sysfs_streq(buf, usb_id_str[i])) {
+			dev_info(ext->dev, "New usb_id %s\n", usb_id_str[i]);
+			ext->usb_id = i;
+			cht_wc_extcon_det_event(ext);
+			return n;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static DEVICE_ATTR(usb_id, 0644, usb_id_show, usb_id_store);
+
+static int cht_wc_extcon_probe(struct platform_device *pdev)
+{
+	struct cht_wc_extcon_data *ext;
+	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+	int irq, ret;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL);
+	if (!ext)
+		return -ENOMEM;
+
+	ext->dev = &pdev->dev;
+	ext->regmap = pmic->regmap;
+	ext->previous_cable = EXTCON_NONE;
+
+	/* Initialize extcon device */
+	ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables);
+	if (IS_ERR(ext->edev))
+		return PTR_ERR(ext->edev);
+
+	ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0,
+		 CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK,
+		 CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK);
+	if (ret) {
+		dev_err(ext->dev, "Error enabling sw control\n");
+		return ret;
+	}
+
+	/* Register extcon device */
+	ret = devm_extcon_dev_register(ext->dev, ext->edev);
+	if (ret) {
+		dev_err(ext->dev, "Failed to register extcon device\n");
+		return ret;
+	}
+
+	/* Route D+ and D- to PMIC for initial charger detection */
+	cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
+
+	/* Get initial state */
+	cht_wc_extcon_det_event(ext);
+
+	ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr,
+					IRQF_ONESHOT, pdev->name, ext);
+	if (ret) {
+		dev_err(ext->dev, "Failed to request interrupt\n");
+		return ret;
+	}
+
+	/* Unmask irqs */
+	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
+			   (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
+				  CHT_WC_PWRSRC_ID_FLOAT));
+	if (ret) {
+		dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, ext);
+	device_create_file(ext->dev, &dev_attr_usb_id);
+
+	return 0;
+}
+
+static int cht_wc_extcon_remove(struct platform_device *pdev)
+{
+	struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev);
+
+	device_remove_file(ext->dev, &dev_attr_usb_id);
+
+	return 0;
+}
+
+static const struct platform_device_id cht_wc_extcon_table[] = {
+	{ .name = "cht_wcove_pwrsrc" },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
+
+static struct platform_driver cht_wc_extcon_driver = {
+	.probe = cht_wc_extcon_probe,
+	.remove = cht_wc_extcon_remove,
+	.id_table = cht_wc_extcon_table,
+	.driver = {
+		.name = "cht_wcove_pwrsrc",
+	},
+};
+module_platform_driver(cht_wc_extcon_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver");
+MODULE_LICENSE("GPL v2");
-- 
2.9.3

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

* [PATCH 04/15] power: supply: bq24190_charger: Add no_register_reset pdata flag
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (2 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:20   ` Andy Shevchenko
  2017-03-17  9:55 ` [PATCH 05/15] power: supply: bq24190_charger: Limit charging voltage to 4.3V Hans de Goede
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

On some platforms the register have been setup with platform specific
values by the firmware and should not be reset.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/bq24190_charger.c | 5 +++++
 include/linux/power/bq24190_charger.h  | 1 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index a4f0849..c92a40e4 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -151,6 +151,7 @@ struct bq24190_dev_info {
 	struct device			*dev;
 	struct power_supply		*charger;
 	struct power_supply		*battery;
+	struct bq24190_platform_data	*pdata;
 	char				model_name[I2C_NAME_SIZE];
 	kernel_ulong_t			model;
 	unsigned int			gpio_int;
@@ -506,6 +507,9 @@ static int bq24190_register_reset(struct bq24190_dev_info *bdi)
 	int ret, limit = 100;
 	u8 v;
 
+	if (bdi->pdata && bdi->pdata->no_register_reset)
+		return 0;
+
 	/* Reset the registers */
 	ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
 			BQ24190_REG_POC_RESET_MASK,
@@ -1339,6 +1343,7 @@ static int bq24190_probe(struct i2c_client *client,
 	bdi->client = client;
 	bdi->dev = dev;
 	bdi->model = id->driver_data;
+	bdi->pdata = client->dev.platform_data;
 	strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
 	mutex_init(&bdi->f_reg_lock);
 	bdi->f_reg = 0;
diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h
index 9f02837..cb49717 100644
--- a/include/linux/power/bq24190_charger.h
+++ b/include/linux/power/bq24190_charger.h
@@ -11,6 +11,7 @@
 
 struct bq24190_platform_data {
 	unsigned int	gpio_int;	/* GPIO pin that's connected to INT# */
+	bool no_register_reset;
 };
 
 #endif
-- 
2.9.3

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

* [PATCH 05/15] power: supply: bq24190_charger: Limit charging voltage to 4.3V
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (3 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 04/15] power: supply: bq24190_charger: Add no_register_reset pdata flag Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17  9:55 ` [PATCH 06/15] power: supply: bq24190_charger: Use i2c-core irq-mapping code Hans de Goede
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

When the platform data asks us to not reset the charger to its default
values and instead trust the firmware set values check the charging
voltage and clamp it to 4.304V.

Some firmwares set really too high voltages, e.g. the GPD-win I've been
working on uses 4.384V. New LiHV (High Voltage) batteries may be charged
upto 4.35V but that significantly impacts their lifetime, limit charging
to 4.304V for safety and lifetime reasons.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/bq24190_charger.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index c92a40e4..7bca8d0 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -504,11 +504,32 @@ static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
 
 static int bq24190_register_reset(struct bq24190_dev_info *bdi)
 {
-	int ret, limit = 100;
+	int ret, voltage, limit = 100;
 	u8 v;
 
-	if (bdi->pdata && bdi->pdata->no_register_reset)
-		return 0;
+	if (bdi->pdata && bdi->pdata->no_register_reset) {
+		/*
+		 * We've been asked to keep the firmware settings as is, but
+		 * some firmwares set really too high voltages (e.g. 4.384V).
+		 * New LiHV (High Voltage) batteries may be charged upto 4.35V
+		 * but that significantly impacts their lifetime, limit
+		 * charging to 4.304V for safety and lifetime reasons.
+		 */
+		ret = bq24190_get_field_val(bdi, BQ24190_REG_CVC,
+			BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
+			bq24190_cvc_vreg_values,
+			ARRAY_SIZE(bq24190_cvc_vreg_values), &voltage);
+		if (ret < 0)
+			return ret;
+
+		if (voltage <= 4304000)
+			return 0;
+
+		return bq24190_set_field_val(bdi, BQ24190_REG_CVC,
+			BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
+			bq24190_cvc_vreg_values,
+			ARRAY_SIZE(bq24190_cvc_vreg_values), 4304000);
+	}
 
 	/* Reset the registers */
 	ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
-- 
2.9.3

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

* [PATCH 06/15] power: supply: bq24190_charger: Use i2c-core irq-mapping code
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (4 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 05/15] power: supply: bq24190_charger: Limit charging voltage to 4.3V Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:24   ` Andy Shevchenko
  2017-03-17  9:55 ` [PATCH 07/15] power: supply: bq24190_charger: Add support for bq24192[i] Hans de Goede
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

The i2c-core already maps of irqs before calling the driver's probe
function and there are no in tree users of
bq24190_platform_data->gpio_int.

Remove the redundant custom irq-mapping code and just use client->irq.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/bq24190_charger.c | 61 ++--------------------------------
 include/linux/power/bq24190_charger.h  |  1 -
 2 files changed, 2 insertions(+), 60 deletions(-)

diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 7bca8d0..9c4b171 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -154,8 +154,6 @@ struct bq24190_dev_info {
 	struct bq24190_platform_data	*pdata;
 	char				model_name[I2C_NAME_SIZE];
 	kernel_ulong_t			model;
-	unsigned int			gpio_int;
-	unsigned int			irq;
 	struct mutex			f_reg_lock;
 	u8				f_reg;
 	u8				ss_reg;
@@ -1296,56 +1294,11 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi)
 	return ret;
 }
 
-#ifdef CONFIG_OF
-static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
-{
-	bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
-	if (bdi->irq <= 0)
-		return -1;
-
-	return 0;
-}
-#else
-static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
-{
-	return -1;
-}
-#endif
-
-static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
-		struct bq24190_platform_data *pdata)
-{
-	int ret;
-
-	if (!gpio_is_valid(pdata->gpio_int))
-		return -1;
-
-	ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
-	if (ret < 0)
-		return -1;
-
-	ret = gpio_direction_input(pdata->gpio_int);
-	if (ret < 0)
-		goto out;
-
-	bdi->irq = gpio_to_irq(pdata->gpio_int);
-	if (!bdi->irq)
-		goto out;
-
-	bdi->gpio_int = pdata->gpio_int;
-	return 0;
-
-out:
-	gpio_free(pdata->gpio_int);
-	return -1;
-}
-
 static int bq24190_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 	struct device *dev = &client->dev;
-	struct bq24190_platform_data *pdata = client->dev.platform_data;
 	struct power_supply_config charger_cfg = {}, battery_cfg = {};
 	struct bq24190_dev_info *bdi;
 	int ret;
@@ -1372,12 +1325,7 @@ static int bq24190_probe(struct i2c_client *client,
 
 	i2c_set_clientdata(client, bdi);
 
-	if (dev->of_node)
-		ret = bq24190_setup_dt(bdi);
-	else
-		ret = bq24190_setup_pdata(bdi, pdata);
-
-	if (ret) {
+	if (!client->irq) {
 		dev_err(dev, "Can't get irq info\n");
 		return -EINVAL;
 	}
@@ -1417,7 +1365,7 @@ static int bq24190_probe(struct i2c_client *client,
 		goto out3;
 	}
 
-	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
+	ret = devm_request_threaded_irq(dev, client->irq, NULL,
 			bq24190_irq_handler_thread,
 			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 			"bq24190-charger", bdi);
@@ -1439,8 +1387,6 @@ static int bq24190_probe(struct i2c_client *client,
 
 out1:
 	pm_runtime_disable(dev);
-	if (bdi->gpio_int)
-		gpio_free(bdi->gpio_int);
 	return ret;
 }
 
@@ -1457,9 +1403,6 @@ static int bq24190_remove(struct i2c_client *client)
 	power_supply_unregister(bdi->charger);
 	pm_runtime_disable(bdi->dev);
 
-	if (bdi->gpio_int)
-		gpio_free(bdi->gpio_int);
-
 	return 0;
 }
 
diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h
index cb49717..8d918cb 100644
--- a/include/linux/power/bq24190_charger.h
+++ b/include/linux/power/bq24190_charger.h
@@ -10,7 +10,6 @@
 #define _BQ24190_CHARGER_H_
 
 struct bq24190_platform_data {
-	unsigned int	gpio_int;	/* GPIO pin that's connected to INT# */
 	bool no_register_reset;
 };
 
-- 
2.9.3

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

* [PATCH 07/15] power: supply: bq24190_charger: Add support for bq24192[i]
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (5 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 06/15] power: supply: bq24190_charger: Use i2c-core irq-mapping code Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17  9:55 ` [PATCH 08/15] power: supply: bq24190_charger: Add support for external fuel gauge Hans de Goede
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

The bq24192 and bq24192i are mostly identical to the bq24190, TI even
published a single datasheet for all 3 of them. The difference
between the bq24190 and bq24192[i] is the way charger-type detection
is done, the bq24190 is to be directly connected to the USB a/b lines,
where as the the bq24192[i] has a gpio which should be driven high/low
externally depending on the type of charger connected, from a register
level access pov there is no difference.

The differences between the bq24192 and bq24192i are:
1) Lower default charge rate on the bq24192i
2) Pre-charge-current can be max 640 mA on the bq24192i

Since we do not provide an API for setting the pre-charge-current,
these differences can be ignored and we can simply use the existing
code as-is with the bq24192 and bq24192i.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/bq24190_charger.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 9c4b171..9014dee 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -1275,7 +1275,14 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi)
 	if (ret < 0)
 		goto out;
 
-	if (v != bdi->model) {
+	switch (v) {
+	case BQ24190_REG_VPRS_PN_24190:
+	case BQ24190_REG_VPRS_PN_24192:
+	case BQ24190_REG_VPRS_PN_24192I:
+		bdi->model = v;
+		break;
+	default:
+		dev_err(bdi->dev, "Error unknown model: 0x%02x\n", v);
 		ret = -ENODEV;
 		goto out;
 	}
@@ -1316,7 +1323,6 @@ static int bq24190_probe(struct i2c_client *client,
 
 	bdi->client = client;
 	bdi->dev = dev;
-	bdi->model = id->driver_data;
 	bdi->pdata = client->dev.platform_data;
 	strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
 	mutex_init(&bdi->f_reg_lock);
@@ -1450,6 +1456,8 @@ static SIMPLE_DEV_PM_OPS(bq24190_pm_ops, bq24190_pm_suspend, bq24190_pm_resume);
  */
 static const struct i2c_device_id bq24190_i2c_ids[] = {
 	{ "bq24190", BQ24190_REG_VPRS_PN_24190 },
+	{ "bq24192", BQ24190_REG_VPRS_PN_24192 },
+	{ "bq24192i", BQ24190_REG_VPRS_PN_24192I },
 	{ },
 };
 MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
-- 
2.9.3

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

* [PATCH 08/15] power: supply: bq24190_charger: Add support for external fuel gauge
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (6 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 07/15] power: supply: bq24190_charger: Add support for bq24192[i] Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17  9:55 ` [PATCH 09/15] power: supply: bq24190_charger: Add voltage_max_design prop to battery Hans de Goede
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

Some platforms with a bq24190_charger have an external fuel gauge which
makes it possible to reliably report battery (dis)charge state, at
support for this by adding an optional get_ext_bat_property callback
to the platform_data and using this if the platform provides it.

By convention the callback will return -ENXIO when it is not ready yet,
or the driver providing it has been unbound from its device. Since it
returns the same error when unbound it cannot return -EPROBE_DEFER
as that is not a valid errno.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/bq24190_charger.c | 41 +++++++++++++++++++++++++++++++---
 include/linux/power/bq24190_charger.h  |  4 ++++
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 9014dee..9fe69a5 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -1111,7 +1111,10 @@ static int bq24190_battery_get_property(struct power_supply *psy,
 		ret = 0;
 		break;
 	default:
-		ret = -ENODATA;
+		if (bdi->pdata && bdi->pdata->get_ext_bat_property)
+			ret = bdi->pdata->get_ext_bat_property(psp, val);
+		else
+			ret = -ENODATA;
 	}
 
 	pm_runtime_put_sync(bdi->dev);
@@ -1168,12 +1171,31 @@ static enum power_supply_property bq24190_battery_properties[] = {
 	POWER_SUPPLY_PROP_TECHNOLOGY,
 	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
 	POWER_SUPPLY_PROP_SCOPE,
+	/* Begin of extended battery properties */
+	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_CHARGE_FULL_DESIGN,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
 };
 
 static const struct power_supply_desc bq24190_battery_desc = {
 	.name			= "bq24190-battery",
 	.type			= POWER_SUPPLY_TYPE_BATTERY,
 	.properties		= bq24190_battery_properties,
+	.num_properties		= 6,
+	.get_property		= bq24190_battery_get_property,
+	.set_property		= bq24190_battery_set_property,
+	.property_is_writeable	= bq24190_battery_property_is_writeable,
+};
+
+static const struct power_supply_desc bq24190_ext_battery_desc = {
+	.name			= "bq24190-battery",
+	.type			= POWER_SUPPLY_TYPE_BATTERY,
+	.properties		= bq24190_battery_properties,
 	.num_properties		= ARRAY_SIZE(bq24190_battery_properties),
 	.get_property		= bq24190_battery_get_property,
 	.set_property		= bq24190_battery_set_property,
@@ -1336,6 +1358,15 @@ static int bq24190_probe(struct i2c_client *client,
 		return -EINVAL;
 	}
 
+	if (bdi->pdata && bdi->pdata->get_ext_bat_property) {
+		union power_supply_propval val;
+
+		/* Check external fuel gauge is ready */
+		ret = bdi->pdata->get_ext_bat_property(0, &val);
+		if (ret == -ENXIO)
+			return -EPROBE_DEFER;
+	}
+
 	pm_runtime_enable(dev);
 	pm_runtime_resume(dev);
 
@@ -1357,8 +1388,12 @@ static int bq24190_probe(struct i2c_client *client,
 	}
 
 	battery_cfg.drv_data = bdi;
-	bdi->battery = power_supply_register(dev, &bq24190_battery_desc,
-						&battery_cfg);
+	if (bdi->pdata && bdi->pdata->get_ext_bat_property)
+		bdi->battery = power_supply_register(dev,
+				    &bq24190_ext_battery_desc, &battery_cfg);
+	else
+		bdi->battery = power_supply_register(dev,
+				    &bq24190_battery_desc, &battery_cfg);
 	if (IS_ERR(bdi->battery)) {
 		dev_err(dev, "Can't register battery\n");
 		ret = PTR_ERR(bdi->battery);
diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h
index 8d918cb..02d248b 100644
--- a/include/linux/power/bq24190_charger.h
+++ b/include/linux/power/bq24190_charger.h
@@ -9,8 +9,12 @@
 #ifndef _BQ24190_CHARGER_H_
 #define _BQ24190_CHARGER_H_
 
+#include <linux/power_supply.h>
+
 struct bq24190_platform_data {
 	bool no_register_reset;
+	int (*get_ext_bat_property)(enum power_supply_property prop,
+				    union power_supply_propval *val);
 };
 
 #endif
-- 
2.9.3

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

* [PATCH 09/15] power: supply: bq24190_charger: Add voltage_max_design prop to battery
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (7 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 08/15] power: supply: bq24190_charger: Add support for external fuel gauge Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-20  5:12   ` Sebastian Reichel
  2017-03-17  9:55 ` [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost Hans de Goede
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

When combined with an external fuel-gauge, upower needs voltage_max_design
as it internally does all its calculations in Watts and converts the
charge_foo properties from A to Watts by using voltage_max_design.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/bq24190_charger.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 9fe69a5..82cb33d 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -1103,6 +1103,13 @@ static int bq24190_battery_get_property(struct power_supply *psy,
 		val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
 		ret = 0;
 		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+		/*
+		 * Report charger configured voltage as max design voltage,
+		 * not entirely correct, but userspace needs something here.
+		 */
+		ret = bq24190_charger_get_voltage(bdi, val);
+		break;
 	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
 		ret = bq24190_battery_get_temp_alert_max(bdi, val);
 		break;
@@ -1169,6 +1176,7 @@ static enum power_supply_property bq24190_battery_properties[] = {
 	POWER_SUPPLY_PROP_HEALTH,
 	POWER_SUPPLY_PROP_ONLINE,
 	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
 	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
 	POWER_SUPPLY_PROP_SCOPE,
 	/* Begin of extended battery properties */
@@ -1186,7 +1194,7 @@ static const struct power_supply_desc bq24190_battery_desc = {
 	.name			= "bq24190-battery",
 	.type			= POWER_SUPPLY_TYPE_BATTERY,
 	.properties		= bq24190_battery_properties,
-	.num_properties		= 6,
+	.num_properties		= 7,
 	.get_property		= bq24190_battery_get_property,
 	.set_property		= bq24190_battery_set_property,
 	.property_is_writeable	= bq24190_battery_property_is_writeable,
-- 
2.9.3

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

* [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (8 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 09/15] power: supply: bq24190_charger: Add voltage_max_design prop to battery Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:33   ` Andy Shevchenko
  2017-03-20  4:52   ` Sebastian Reichel
  2017-03-17  9:55 ` [PATCH 11/15] i2c: core: Allow getting ACPI info by index Hans de Goede
                   ` (4 subsequent siblings)
  14 siblings, 2 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

Add support for monitoring an extcon device with SDP/CDP/DCP and HOST
cables and adjust ilimit and enable/disable the 5v boost converter
accordingly. This is necessary on systems where the PSEL pin is hardwired
high and ILIM needs to be set by software based on the detected charger
type.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/Kconfig           |  1 +
 drivers/power/supply/bq24190_charger.c | 85 ++++++++++++++++++++++++++++++++++
 include/linux/power/bq24190_charger.h  |  1 +
 3 files changed, 87 insertions(+)

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index f8b6e64..fd93110 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -442,6 +442,7 @@ config CHARGER_BQ2415X
 config CHARGER_BQ24190
 	tristate "TI BQ24190 battery charger driver"
 	depends on I2C
+	depends on EXTCON
 	depends on GPIOLIB || COMPILE_TEST
 	help
 	  Say Y to enable support for the TI BQ24190 battery charger.
diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
index 82cb33d..03990e2 100644
--- a/drivers/power/supply/bq24190_charger.c
+++ b/drivers/power/supply/bq24190_charger.c
@@ -11,10 +11,12 @@
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/extcon.h>
 #include <linux/of_irq.h>
 #include <linux/of_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/power_supply.h>
+#include <linux/workqueue.h>
 #include <linux/gpio.h>
 #include <linux/i2c.h>
 
@@ -39,6 +41,8 @@
 #define BQ24190_REG_POC_WDT_RESET_SHIFT		6
 #define BQ24190_REG_POC_CHG_CONFIG_MASK		(BIT(5) | BIT(4))
 #define BQ24190_REG_POC_CHG_CONFIG_SHIFT	4
+#define BQ24190_REG_POC_CHG_CONFIG_CHARGE	1
+#define BQ24190_REG_POC_CHG_CONFIG_OTG		2
 #define BQ24190_REG_POC_SYS_MIN_MASK		(BIT(3) | BIT(2) | BIT(1))
 #define BQ24190_REG_POC_SYS_MIN_SHIFT		1
 #define BQ24190_REG_POC_BOOST_LIM_MASK		BIT(0)
@@ -152,6 +156,9 @@ struct bq24190_dev_info {
 	struct power_supply		*charger;
 	struct power_supply		*battery;
 	struct bq24190_platform_data	*pdata;
+	struct extcon_dev		*extcon;
+	struct notifier_block		extcon_nb;
+	struct work_struct		extcon_work;
 	char				model_name[I2C_NAME_SIZE];
 	kernel_ulong_t			model;
 	struct mutex			f_reg_lock;
@@ -167,6 +174,11 @@ struct bq24190_dev_info {
  * number at that index in the array is the real-world value that it
  * represents.
  */
+
+/* REG00[2:0] (IINLIM) in uAh */
+static const int bq24190_iinlim_values[] = {
+	100000, 150000, 500000, 900000, 1200000, 1500000, 2000000, 3000000 };
+
 /* REG02[7:2] (ICHG) in uAh */
 static const int bq24190_ccc_ichg_values[] = {
 	 512000,  576000,  640000,  704000,  768000,  832000,  896000,  960000,
@@ -1290,6 +1302,61 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static void bq24190_extcon_work(struct work_struct *work)
+{
+	struct bq24190_dev_info *bdi =
+		container_of(work, struct bq24190_dev_info, extcon_work);
+	int ret, iinlim = 0;
+
+	if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_SDP) == 1)
+		iinlim = 500000;
+	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_CDP) == 1 ||
+		 extcon_get_state(bdi->extcon, EXTCON_CHG_USB_ACA) == 1)
+		iinlim = 1500000;
+	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_DCP) == 1)
+		iinlim = 2000000;
+
+	if (iinlim) {
+		ret = bq24190_set_field_val(bdi, BQ24190_REG_ISC,
+				BQ24190_REG_ISC_IINLIM_MASK,
+				BQ24190_REG_ISC_IINLIM_SHIFT,
+				bq24190_iinlim_values,
+				ARRAY_SIZE(bq24190_iinlim_values),
+				iinlim);
+		if (ret)
+			dev_err(bdi->dev, "Can't set IINLIM: %d\n", ret);
+	}
+
+	/*
+	 * If no charger has been detected and host mode is requested, activate
+	 * the 5V boost converter, otherwise deactivate it.
+	 */
+	if (!iinlim && extcon_get_state(bdi->extcon, EXTCON_USB_HOST) == 1) {
+		ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
+					 BQ24190_REG_POC_CHG_CONFIG_MASK,
+					 BQ24190_REG_POC_CHG_CONFIG_SHIFT,
+					 BQ24190_REG_POC_CHG_CONFIG_OTG);
+	} else {
+		ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
+					 BQ24190_REG_POC_CHG_CONFIG_MASK,
+					 BQ24190_REG_POC_CHG_CONFIG_SHIFT,
+					 BQ24190_REG_POC_CHG_CONFIG_CHARGE);
+	}
+	if (ret)
+		dev_err(bdi->dev, "Can't set CHG_CONFIG: %d\n", ret);
+}
+
+static int bq24190_extcon_event(struct notifier_block *nb, unsigned long event,
+				void *param)
+{
+	struct bq24190_dev_info *bdi =
+		container_of(nb, struct bq24190_dev_info, extcon_nb);
+
+	schedule_work(&bdi->extcon_work);
+
+	return NOTIFY_OK;
+}
+
 static int bq24190_hw_init(struct bq24190_dev_info *bdi)
 {
 	u8 v;
@@ -1375,6 +1442,12 @@ static int bq24190_probe(struct i2c_client *client,
 			return -EPROBE_DEFER;
 	}
 
+	if (bdi->pdata && bdi->pdata->extcon_name) {
+		bdi->extcon = extcon_get_extcon_dev(bdi->pdata->extcon_name);
+		if (!bdi->extcon)
+			return -EPROBE_DEFER;
+	}
+
 	pm_runtime_enable(dev);
 	pm_runtime_resume(dev);
 
@@ -1423,6 +1496,18 @@ static int bq24190_probe(struct i2c_client *client,
 		goto out4;
 	}
 
+	if (bdi->extcon) {
+		INIT_WORK(&bdi->extcon_work, bq24190_extcon_work);
+		bdi->extcon_nb.notifier_call = bq24190_extcon_event;
+		ret = devm_extcon_register_notifier(dev, bdi->extcon, -1,
+						    &bdi->extcon_nb);
+		if (ret)
+			goto out4;
+
+		/* Sync initial cable state */
+		schedule_work(&bdi->extcon_work);
+	}
+
 	return 0;
 
 out4:
diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h
index 02d248b..909c5b9 100644
--- a/include/linux/power/bq24190_charger.h
+++ b/include/linux/power/bq24190_charger.h
@@ -13,6 +13,7 @@
 
 struct bq24190_platform_data {
 	bool no_register_reset;
+	const char *extcon_name;
 	int (*get_ext_bat_property)(enum power_supply_property prop,
 				    union power_supply_propval *val);
 };
-- 
2.9.3

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

* [PATCH 11/15] i2c: core: Allow getting ACPI info by index
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (9 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:35   ` Andy Shevchenko
  2017-03-17  9:55 ` [PATCH 12/15] i2c: core: Add new i2c_acpi_new_device helper function Hans de Goede
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

Modify struct i2c_acpi_lookup and i2c_acpi_fill_info() to allow
using them to get the info from a certain index in the ACPI-resource
list rather then taking the first I2cSerialBus resource.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/i2c/i2c-core.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d2402bb..32b58fb 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -112,6 +112,8 @@ struct i2c_acpi_lookup {
 	acpi_handle adapter_handle;
 	acpi_handle device_handle;
 	acpi_handle search_handle;
+	int n;
+	int index;
 	u32 speed;
 	u32 min_speed;
 };
@@ -123,6 +125,9 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
 	struct acpi_resource_i2c_serialbus *sb;
 	acpi_status status;
 
+	if (lookup->index != -1 && lookup->n++ != lookup->index)
+		return 1;
+
 	if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
 		return 1;
 
@@ -182,6 +187,7 @@ static int i2c_acpi_get_info(struct acpi_device *adev,
 
 	memset(&lookup, 0, sizeof(lookup));
 	lookup.info = info;
+	lookup.index = -1;
 
 	ret = i2c_acpi_do_lookup(adev, &lookup);
 	if (ret)
@@ -328,6 +334,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
 	lookup.search_handle = ACPI_HANDLE(dev);
 	lookup.min_speed = UINT_MAX;
 	lookup.info = &dummy;
+	lookup.index = -1;
 
 	status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
 				     I2C_ACPI_MAX_SCAN_DEPTH,
-- 
2.9.3

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

* [PATCH 12/15] i2c: core: Add new i2c_acpi_new_device helper function
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (10 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 11/15] i2c: core: Allow getting ACPI info by index Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:37   ` Andy Shevchenko
  2017-03-17  9:55 ` [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI Hans de Goede
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

By default the i2c subsys creates an i2c-client for the first I2cSerialBus
resource of an acpi_device, but some acpi_devices have multiple
I2cSerialBus resources and the driver may need access to the others.

This commit adds a new i2c_acpi_new_device function which can be used by
drivers to create an i2c-client for any (other) I2cSerialBus resource of
an acpi_device.

Note that the other resources may even be on a different i2c bus, so just
retrieving the client address is not enough.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/i2c/i2c-core.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/i2c.h    |  5 +++++
 2 files changed, 53 insertions(+)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 32b58fb..fd45207 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -421,6 +421,54 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
 static struct notifier_block i2c_acpi_notifier = {
 	.notifier_call = i2c_acpi_notify,
 };
+
+/**
+ * i2c_acpi_new_device - Create i2c client for the Nth acpi resource of dev
+ * @dev:     Device owning the acpi resources to get the client from
+ * @index:   Index of acpi resource to get
+ *
+ * By default the i2c subsys creates an i2c-client for the first I2cSerialBus
+ * resource of an acpi_device, but some acpi_devices have multiple
+ * I2cSerialBus resources and the driver may need access to the others.
+ * This function can be used by drivers to create an i2c-client for any
+ * resource of an acpi_device.
+ *
+ * Returns a pointer to the new i2c-client, or NULL if the resource or
+ * adapter were not found.
+ */
+struct i2c_client *i2c_acpi_new_device(struct device *dev, int index)
+{
+	struct i2c_acpi_lookup lookup;
+	struct i2c_board_info info;
+	struct i2c_adapter *adapter;
+	struct acpi_device *adev;
+	LIST_HEAD(resource_list);
+	int ret;
+
+	adev = ACPI_COMPANION(dev);
+	if (!adev)
+		return NULL;
+
+	memset(&info, 0, sizeof(info));
+	memset(&lookup, 0, sizeof(lookup));
+	lookup.info = &info;
+	lookup.device_handle = acpi_device_handle(adev);
+	lookup.index = index;
+
+	ret = acpi_dev_get_resources(adev, &resource_list,
+				     i2c_acpi_fill_info, &lookup);
+	acpi_dev_free_resource_list(&resource_list);
+
+	if (ret < 0 || !info.addr)
+		return NULL;
+
+	adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
+	if (!adapter)
+		return NULL;
+
+	return i2c_new_device(adapter, &info);
+}
+EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
 #else /* CONFIG_ACPI */
 static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
 extern struct notifier_block i2c_acpi_notifier;
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 6b18352..369ebfa 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -824,11 +824,16 @@ static inline const struct of_device_id
 
 #if IS_ENABLED(CONFIG_ACPI)
 u32 i2c_acpi_find_bus_speed(struct device *dev);
+struct i2c_client *i2c_acpi_new_device(struct device *dev, int index);
 #else
 static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
 {
 	return 0;
 }
+static inline struct i2c_client *i2c_acpi_new_device(struct device *d, int i)
+{
+	return NULL;
+}
 #endif /* CONFIG_ACPI */
 
 #endif /* _LINUX_I2C_H */
-- 
2.9.3

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

* [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (11 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 12/15] i2c: core: Add new i2c_acpi_new_device helper function Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:41   ` Andy Shevchenko
  2017-03-20  8:55   ` kbuild test robot
  2017-03-17  9:55 ` [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge Hans de Goede
  2017-03-17  9:55 ` [PATCH 15/15] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS controller driver Hans de Goede
  14 siblings, 2 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

Some of or ACPI declared / enumerated devices may have multiple irq
resources declared and the driver may want to use a different irq then
the one with index 0.

This commit adds a new irq_index field to struct i2c_driver and makes
the i2c-core pass this to of_irq_get / acpi_dev_gpio_irq_get.

This is esp. useful for ACPI declared devices where the irq with
index 0 may be entirely useless and cause i2c_device_probe to fail with
-EPROBE_DEFER.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Actually also use the irq_index for of interrupts
---
 drivers/i2c/i2c-core.c | 8 ++++++--
 include/linux/i2c.h    | 3 +++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index fd45207..2457995 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -984,6 +984,8 @@ static int i2c_device_probe(struct device *dev)
 	if (!client)
 		return 0;
 
+	driver = to_i2c_driver(dev->driver);
+
 	if (!client->irq) {
 		int irq = -ENOENT;
 
@@ -993,9 +995,11 @@ static int i2c_device_probe(struct device *dev)
 		} else if (dev->of_node) {
 			irq = of_irq_get_byname(dev->of_node, "irq");
 			if (irq == -EINVAL || irq == -ENODATA)
-				irq = of_irq_get(dev->of_node, 0);
+				irq = of_irq_get(dev->of_node,
+						 driver->irq_index);
 		} else if (ACPI_COMPANION(dev)) {
-			irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
+			irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev),
+						    driver->irq_index);
 		}
 		if (irq == -EPROBE_DEFER)
 			return irq;
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 369ebfa..a5ffe29 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -212,6 +212,9 @@ struct i2c_driver {
 	int (*detect)(struct i2c_client *, struct i2c_board_info *);
 	const unsigned short *address_list;
 	struct list_head clients;
+
+	/* IRQ index for retreiving irq from ACPI resources */
+	int irq_index;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
-- 
2.9.3

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

* [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (12 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 17:58   ` Andy Shevchenko
  2017-03-20  5:07   ` Sebastian Reichel
  2017-03-17  9:55 ` [PATCH 15/15] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS controller driver Hans de Goede
  14 siblings, 2 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

Add a driver for the Cherry Trail Whiskey Cove PMIC Fuel Gauge, note
the Cherry Trail Whiskey Cove PMIC Fuel Gauge block is purely a fuel gauge
and not a full battery controller. As such it offers a platform_data
callback for extra power_supply properties for the actual external-charger
ic driver and does not register a power_supply itself.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/power/supply/Kconfig             |   9 ++
 drivers/power/supply/Makefile            |   1 +
 drivers/power/supply/cht_wc_fuel_gauge.c | 209 +++++++++++++++++++++++++++++++
 include/linux/power/cht_wc_fuel_gauge.h  |  21 ++++
 4 files changed, 240 insertions(+)
 create mode 100644 drivers/power/supply/cht_wc_fuel_gauge.c
 create mode 100644 include/linux/power/cht_wc_fuel_gauge.h

diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
index fd93110..34ebfca 100644
--- a/drivers/power/supply/Kconfig
+++ b/drivers/power/supply/Kconfig
@@ -538,4 +538,13 @@ config AXP20X_POWER
 	  This driver provides support for the power supply features of
 	  AXP20x PMIC.
 
+config CHT_WC_FUEL_GAUGE
+	tristate "Intel Cherry Trail Whiskey Cove PMIC Fuel Gauge"
+	depends on INTEL_SOC_PMIC_CHTWC
+	help
+	  This adds support for the battery fuel gauge found in the Intel
+	  Cherry Trail Whiskey Cove PMIC. This driver allows monitoring
+	  of the charge level of the battery on Intel Cherry Trail systems
+	  with a Whiskey Cove PMIC.
+
 endif # POWER_SUPPLY
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
index 3789a2c..702e28a 100644
--- a/drivers/power/supply/Makefile
+++ b/drivers/power/supply/Makefile
@@ -74,3 +74,4 @@ obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
 obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
 obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
 obj-$(CONFIG_AXP288_CHARGER)	+= axp288_charger.o
+obj-$(CONFIG_CHT_WC_FUEL_GAUGE)	+= cht_wc_fuel_gauge.o
diff --git a/drivers/power/supply/cht_wc_fuel_gauge.c b/drivers/power/supply/cht_wc_fuel_gauge.c
new file mode 100644
index 0000000..56f6e5a
--- /dev/null
+++ b/drivers/power/supply/cht_wc_fuel_gauge.c
@@ -0,0 +1,209 @@
+/*
+ * Intel CHT Whiskey Cove Fuel Gauge driver
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.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 by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Cherrytrail Whiskey Cove devices have 2 functional blocks which interact
+ * with the battery.
+ *
+ * 1) The fuel-gauge which is build into the Whiskey Cove PMIC, but has its
+ * own i2c bus and i2c client addresses separately from the rest of the PMIC.
+ * That block is what this driver is for.
+ *
+ * 2) An external charger IC, which is connected to the SMBUS controller
+ * which is part of the rest of the Whiskey Cove PMIC, mfd/intel_cht_wc.c
+ * registers a platform device for the SMBUS controller and
+ * i2c/busses/i2c-cht-wc.c contains the i2c-adapter driver for this.
+ *
+ * However we want to present this as a single power_supply device to
+ * userspace. So this driver offers a callback to get the fuel-gauge
+ * power_supply properties, which gets passed to the external charger
+ * driver via i2c_board_info when i2c-cht-wc.c calls i2c_new_device().
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/power/cht_wc_fuel_gauge.h>
+#include <linux/slab.h>
+
+#define REG_CHARGE_NOW		0x05
+#define REG_VOLTAGE_NOW		0x09
+#define REG_CURRENT_NOW		0x0a
+#define REG_CURRENT_AVG		0x0b
+#define REG_CHARGE_FULL		0x10
+#define REG_CHARGE_DESIGN	0x18
+#define REG_VOLTAGE_AVG		0x19
+#define REG_VOLTAGE_OCV		0x1b /* Only updated during charging */
+
+#define CHT_WC_FG_PTYPE		4
+
+struct cht_wc_fg_data {
+	struct device *dev;
+	struct i2c_client *client;
+};
+
+static DEFINE_MUTEX(cht_wc_fg_mutex);
+static struct cht_wc_fg_data *cht_wc_fg;
+
+static int cht_wc_fg_read(struct cht_wc_fg_data *fg, u8 reg,
+			  union power_supply_propval *val, int scale,
+			  int sign_extend)
+{
+	int ret;
+
+	ret = i2c_smbus_read_word_data(fg->client, reg);
+	if (ret < 0)
+		return ret;
+
+	if (sign_extend)
+		ret = sign_extend32(ret, 15);
+
+	val->intval = ret * scale;
+
+	return 0;
+}
+
+int cht_wc_fg_get_property(enum power_supply_property prop,
+			   union power_supply_propval *val)
+{
+	int ret = 0;
+
+	mutex_lock(&cht_wc_fg_mutex);
+
+	if (!cht_wc_fg) {
+		ret = -ENXIO;
+		goto out_unlock;
+	}
+
+	switch (prop) {
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_VOLTAGE_NOW, val, 75, 0);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_VOLTAGE_AVG, val, 75, 0);
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_VOLTAGE_OCV, val, 75, 0);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_CURRENT_NOW, val, 150, 1);
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_AVG:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_CURRENT_AVG, val, 150, 1);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_CHARGE_DESIGN, val, 500, 0);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_CHARGE_FULL, val, 500, 0);
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW:
+		ret = cht_wc_fg_read(cht_wc_fg, REG_CHARGE_NOW, val, 500, 0);
+		break;
+	default:
+		ret = -ENODATA;
+	}
+out_unlock:
+	mutex_unlock(&cht_wc_fg_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(cht_wc_fg_get_property);
+
+static int cht_wc_fg_probe(struct i2c_client *client,
+			const struct i2c_device_id *i2c_id)
+{
+	struct device *dev = &client->dev;
+	struct cht_wc_fg_data *fg;
+	acpi_status status;
+	unsigned long long ptyp;
+
+	fg = devm_kzalloc(dev, sizeof(*fg), GFP_KERNEL);
+	if (!fg)
+		return -ENOMEM;
+
+	status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
+	if (ACPI_FAILURE(status)) {
+		dev_err(dev, "Failed to get PTYPE\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * The same ACPI HID is used with different PMICs check PTYP to
+	 * ensure that we are dealing with a Whiskey Cove PMIC.
+	 */
+	if (ptyp != CHT_WC_FG_PTYPE)
+		return -ENODEV;
+
+	fg->dev = dev;
+	/*
+	 * The current resource settings table for the fuel gauge contains
+	 * multiple i2c devices on 2 different i2c-busses. The one we actually
+	 * want is the second resource (index 1).
+	 */
+	fg->client = i2c_acpi_new_device(dev, 1);
+	if (!fg->client)
+		return -EPROBE_DEFER;
+
+	i2c_set_clientdata(client, fg);
+
+	mutex_lock(&cht_wc_fg_mutex);
+	cht_wc_fg = fg;
+	mutex_unlock(&cht_wc_fg_mutex);
+
+	return 0;
+}
+
+static int cht_wc_fg_remove(struct i2c_client *i2c)
+{
+	struct cht_wc_fg_data *fg = i2c_get_clientdata(i2c);
+
+	mutex_lock(&cht_wc_fg_mutex);
+	cht_wc_fg = NULL;
+	mutex_unlock(&cht_wc_fg_mutex);
+
+	i2c_unregister_device(fg->client);
+
+	return 0;
+}
+
+static const struct i2c_device_id cht_wc_fg_i2c_id[] = {
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, cht_wc_fg_i2c_id);
+
+static const struct acpi_device_id cht_wc_fg_acpi_ids[] = {
+	{ "INT33FE", },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, cht_wc_fg_acpi_ids);
+
+static struct i2c_driver cht_wc_fg_driver = {
+	.driver	= {
+		.name	= "CHT Whiskey Cove PMIC Fuel Gauge",
+		.acpi_match_table = ACPI_PTR(cht_wc_fg_acpi_ids),
+	},
+	.probe = cht_wc_fg_probe,
+	.remove = cht_wc_fg_remove,
+	.id_table = cht_wc_fg_i2c_id,
+	.irq_index = 1,
+};
+
+module_i2c_driver(cht_wc_fg_driver);
+
+MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC Fuel Gauge driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/power/cht_wc_fuel_gauge.h b/include/linux/power/cht_wc_fuel_gauge.h
new file mode 100644
index 0000000..4b4e051
--- /dev/null
+++ b/include/linux/power/cht_wc_fuel_gauge.h
@@ -0,0 +1,21 @@
+/*
+ * Intel CHT Whiskey Cove Fuel Gauge driver
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.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 by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CHT_WC_FUEL_GAUGE_H
+#define __CHT_WC_FUEL_GAUGE_H
+
+int cht_wc_fg_get_property(enum power_supply_property prop,
+			   union power_supply_propval *val);
+
+#endif
-- 
2.9.3

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

* [PATCH 15/15] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS controller driver
  2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
                   ` (13 preceding siblings ...)
  2017-03-17  9:55 ` [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge Hans de Goede
@ 2017-03-17  9:55 ` Hans de Goede
  2017-03-17 18:22   ` Andy Shevchenko
  14 siblings, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-17  9:55 UTC (permalink / raw)
  To: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c, linux-kernel,
	linux-pm

The Intel Cherry Trail Whiskey Cove PMIC has a builtin SMBUS controller
for talking to an external PMIC. Add a driver for this.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 drivers/i2c/busses/Kconfig      |   9 ++
 drivers/i2c/busses/Makefile     |   1 +
 drivers/i2c/busses/i2c-cht-wc.c | 338 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 348 insertions(+)
 create mode 100644 drivers/i2c/busses/i2c-cht-wc.c

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 8adc0f1..19ddd82 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -187,6 +187,15 @@ config I2C_PIIX4
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-piix4.
 
+config I2C_CHT_WC
+	tristate "Intel Cherry Trail Whiskey Cove PMIC smbus controller"
+	depends on INTEL_SOC_PMIC_CHTWC
+	depends on CHT_WC_FUEL_GAUGE
+	help
+	  If you say yes to this option, support will be included for the
+	  SMBus controller found in the Intel Cherry Trail Whiskey Cove PMIC
+	  found on some Intel Cherry Trail systems.
+
 config I2C_NFORCE2
 	tristate "Nvidia nForce2, nForce3 and nForce4"
 	depends on PCI
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 30b6085..f6443fa 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_I2C_ALI15X3)	+= i2c-ali15x3.o
 obj-$(CONFIG_I2C_AMD756)	+= i2c-amd756.o
 obj-$(CONFIG_I2C_AMD756_S4882)	+= i2c-amd756-s4882.o
 obj-$(CONFIG_I2C_AMD8111)	+= i2c-amd8111.o
+obj-$(CONFIG_I2C_CHT_WC)	+= i2c-cht-wc.o
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
 obj-$(CONFIG_I2C_ISCH)		+= i2c-isch.o
 obj-$(CONFIG_I2C_ISMT)		+= i2c-ismt.o
diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c
new file mode 100644
index 0000000..70599f7
--- /dev/null
+++ b/drivers/i2c/busses/i2c-cht-wc.c
@@ -0,0 +1,338 @@
+/*
+ * Intel CHT Whiskey Cove PMIC I2C Master driver
+ * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
+ * Copyright (C) 2011 - 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power/bq24190_charger.h>
+#include <linux/power/cht_wc_fuel_gauge.h>
+#include <linux/slab.h>
+
+#define CHT_WC_I2C_CTRL			0x5e24
+#define CHT_WC_I2C_CTRL_WR		BIT(0)
+#define CHT_WC_I2C_CTRL_RD		BIT(1)
+#define CHT_WC_I2C_CLIENT_ADDR		0x5e25
+#define CHT_WC_I2C_REG_OFFSET		0x5e26
+#define CHT_WC_I2C_WRDATA		0x5e27
+#define CHT_WC_I2C_RDDATA		0x5e28
+
+#define CHT_WC_EXTCHGRIRQ		0x6e0a
+#define CHT_WC_EXTCHGRIRQ_CLIENT_IRQ	BIT(0)
+#define CHT_WC_EXTCHGRIRQ_WRITE_IRQ	BIT(1)
+#define CHT_WC_EXTCHGRIRQ_READ_IRQ	BIT(2)
+#define CHT_WC_EXTCHGRIRQ_NACK_IRQ	BIT(3)
+#define CHT_WC_EXTCHGRIRQ_ADAP_IRQS	((u8)(BIT(1) | BIT(2) | BIT(3)))
+#define CHT_WC_EXTCHGRIRQ_MSK		0x6e17
+
+struct cht_wc_i2c_adap {
+	struct i2c_adapter adapter;
+	wait_queue_head_t wait;
+	struct irq_chip irqchip;
+	struct mutex irqchip_lock;
+	struct regmap *regmap;
+	struct irq_domain *irq_domain;
+	struct i2c_client *client;
+	int client_irq;
+	u8 irq_mask;
+	u8 old_irq_mask;
+	bool nack;
+	bool done;
+};
+
+static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data)
+{
+	struct cht_wc_i2c_adap *adap = data;
+	int ret, reg;
+
+	/* Read irqs */
+	ret = regmap_read(adap->regmap, CHT_WC_EXTCHGRIRQ, &reg);
+	if (ret) {
+		dev_err(&adap->adapter.dev, "Error reading extchgrirq reg\n");
+		return IRQ_NONE;
+	}
+
+	reg &= ~adap->irq_mask;
+
+	/*
+	 * Immediately ack irqs, so that if new irqs arrives while we're
+	 * handling the previous ones our irq will re-trigger when we're done.
+	 */
+	ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg);
+	if (ret)
+		dev_err(&adap->adapter.dev, "Error writing extchgrirq reg\n");
+
+	/*
+	 * Do NOT use handle_nested_irq here, the client irq handler will
+	 * likely want to do i2c transfers and the i2c controller uses this
+	 * interrupt handler as well, so running the client irq handler from
+	 * this thread will cause things to lock up.
+	 */
+	if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) {
+		/*
+		 * generic_handle_irq expects local irqs to be disabled
+		 * as normally it is called from interrupt context.
+		 */
+		local_irq_disable();
+		generic_handle_irq(adap->client_irq);
+		local_irq_enable();
+	}
+
+	if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQS) {
+		if (reg & CHT_WC_EXTCHGRIRQ_NACK_IRQ)
+			adap->nack = true;
+		adap->done = true;
+		wake_up(&adap->wait);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap)
+{
+	/* This i2c adapter only supports smbus byte transfers */
+	return I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr,
+				      unsigned short flags, char read_write,
+				      u8 command, int size,
+				      union i2c_smbus_data *data)
+{
+	struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap);
+	int ret, reg;
+
+	adap->nack = false;
+	adap->done = false;
+
+	ret = regmap_write(adap->regmap, CHT_WC_I2C_CLIENT_ADDR, addr);
+	if (ret)
+		return ret;
+
+	if (read_write == I2C_SMBUS_WRITE) {
+		ret = regmap_write(adap->regmap, CHT_WC_I2C_WRDATA, data->byte);
+		if (ret)
+			return ret;
+	}
+
+	ret = regmap_write(adap->regmap, CHT_WC_I2C_REG_OFFSET, command);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adap->regmap, CHT_WC_I2C_CTRL,
+			   (read_write == I2C_SMBUS_WRITE) ?
+			   CHT_WC_I2C_CTRL_WR : CHT_WC_I2C_CTRL_RD);
+	if (ret)
+		return ret;
+
+	/* 3 second timeout, during cable plug the PMIC responds quite slow */
+	ret = wait_event_timeout(adap->wait, adap->done, HZ * 3);
+	if (ret == 0)
+		return -ETIMEDOUT;
+	if (adap->nack)
+		return -EIO;
+
+	if (read_write == I2C_SMBUS_READ) {
+		ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA, &reg);
+		if (ret)
+			return ret;
+
+		data->byte = reg;
+	}
+
+	return 0;
+}
+
+static const struct i2c_algorithm cht_wc_i2c_adap_algo = {
+	.functionality = cht_wc_i2c_adap_master_func,
+	.smbus_xfer = cht_wc_i2c_adap_smbus_xfer,
+};
+
+/**** irqchip for the client connected to the extchgr i2c adapter ****/
+static void cht_wc_i2c_irq_lock(struct irq_data *data)
+{
+	struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+
+	mutex_lock(&adap->irqchip_lock);
+}
+
+static void cht_wc_i2c_irq_sync_unlock(struct irq_data *data)
+{
+	struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+	int ret;
+
+	if (adap->irq_mask != adap->old_irq_mask) {
+		ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK,
+				   adap->irq_mask);
+		if (ret == 0)
+			adap->old_irq_mask = adap->irq_mask;
+		else
+			dev_err(&adap->adapter.dev, "Error writing extchgrirq_msk\n");
+	}
+
+	mutex_unlock(&adap->irqchip_lock);
+}
+
+static void cht_wc_i2c_irq_enable(struct irq_data *data)
+{
+	struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+
+	adap->irq_mask &= ~CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
+}
+
+static void cht_wc_i2c_irq_disable(struct irq_data *data)
+{
+	struct cht_wc_i2c_adap *adap = irq_data_get_irq_chip_data(data);
+
+	adap->irq_mask |= CHT_WC_EXTCHGRIRQ_CLIENT_IRQ;
+}
+
+static const struct irq_chip cht_wc_i2c_irq_chip = {
+	.irq_bus_lock		= cht_wc_i2c_irq_lock,
+	.irq_bus_sync_unlock	= cht_wc_i2c_irq_sync_unlock,
+	.irq_disable		= cht_wc_i2c_irq_disable,
+	.irq_enable		= cht_wc_i2c_irq_enable,
+	.name			= "cht_wc_ext_chrg_irq_chip",
+};
+
+static const struct bq24190_platform_data bq24190_pdata = {
+	.no_register_reset = true,
+	.extcon_name = "cht_wcove_pwrsrc",
+	.get_ext_bat_property = cht_wc_fg_get_property,
+};
+
+static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
+{
+	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+	struct cht_wc_i2c_adap *adap;
+	struct i2c_board_info board_info = {
+		.type = "bq24190",
+		.addr = 0x6b,
+		.platform_data = (void *)&bq24190_pdata,
+	};
+	int ret, irq;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "Error missing irq resource\n");
+		return -EINVAL;
+	}
+
+	adap = devm_kzalloc(&pdev->dev, sizeof(*adap), GFP_KERNEL);
+	if (!adap)
+		return -ENOMEM;
+
+	init_waitqueue_head(&adap->wait);
+	mutex_init(&adap->irqchip_lock);
+	adap->irqchip = cht_wc_i2c_irq_chip;
+	adap->regmap = pmic->regmap;
+	adap->adapter.owner = THIS_MODULE;
+	adap->adapter.class = I2C_CLASS_HWMON;
+	adap->adapter.algo = &cht_wc_i2c_adap_algo;
+	strlcpy(adap->adapter.name, "PMIC I2C Adapter",
+		sizeof(adap->adapter.name));
+	adap->adapter.dev.parent = &pdev->dev;
+
+	/* Clear and activate i2c-adapter interrupts, disable client irq */
+	adap->old_irq_mask = adap->irq_mask = ~CHT_WC_EXTCHGRIRQ_ADAP_IRQS;
+	ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, ~adap->irq_mask);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ_MSK, adap->irq_mask);
+	if (ret)
+		return ret;
+
+	/* Alloc and register client irq */
+	adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node, 1,
+						 &irq_domain_simple_ops, NULL);
+	if (!adap->irq_domain)
+		return -ENOMEM;
+
+	adap->client_irq = irq_create_mapping(adap->irq_domain, 0);
+	if (!adap->client_irq) {
+		ret = -ENOMEM;
+		goto remove_irq_domain;
+	}
+
+	irq_set_chip_data(adap->client_irq, adap);
+	irq_set_chip_and_handler(adap->client_irq, &adap->irqchip,
+				 handle_simple_irq);
+
+	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+					cht_wc_i2c_adap_thread_handler,
+					IRQF_ONESHOT, "PMIC I2C Adapter", adap);
+	if (ret)
+		goto remove_irq_domain;
+
+	i2c_set_adapdata(&adap->adapter, adap);
+	ret = i2c_add_adapter(&adap->adapter);
+	if (ret)
+		goto remove_irq_domain;
+
+	board_info.irq = adap->client_irq;
+	adap->client = i2c_new_device(&adap->adapter, &board_info);
+	if (!adap->client) {
+		ret = -ENOMEM;
+		goto del_adapter;
+	}
+
+	platform_set_drvdata(pdev, adap);
+	return 0;
+
+del_adapter:
+	i2c_del_adapter(&adap->adapter);
+remove_irq_domain:
+	irq_domain_remove(adap->irq_domain);
+	return ret;
+}
+
+static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev)
+{
+	struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev);
+
+	i2c_unregister_device(adap->client);
+	i2c_del_adapter(&adap->adapter);
+	irq_domain_remove(adap->irq_domain);
+
+	return 0;
+}
+
+static struct platform_device_id cht_wc_i2c_adap_id_table[] = {
+	{ .name = "cht_wcove_ext_chgr" },
+	{},
+};
+MODULE_DEVICE_TABLE(platform, cht_wc_i2c_adap_id_table);
+
+struct platform_driver cht_wc_i2c_adap_driver = {
+	.probe = cht_wc_i2c_adap_i2c_probe,
+	.remove = cht_wc_i2c_adap_i2c_remove,
+	.driver = {
+		.name = "cht_wcove_ext_chgr",
+	},
+	.id_table = cht_wc_i2c_adap_id_table,
+};
+module_platform_driver(cht_wc_i2c_adap_driver);
+
+MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC I2C Master driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
-- 
2.9.3

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

* Re: [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-03-17  9:55 ` [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver Hans de Goede
@ 2017-03-17 17:00   ` Andy Shevchenko
  2017-03-20 10:41     ` Lee Jones
  0 siblings, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:00 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm,
	Bin Gao, Felipe Balbi

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> Add mfd driver for Intel CHT Whiskey Cove PMIC, based on various non
> upstreamed CHT Whiskey Cove PMIC patches.
> 
> This is a somewhat minimal version which adds irqchip support and
> cells
> for: ACPI PMIC opregion support, the i2c-controller driving the
> external
> charger irc and the pwrsrc/extcon block.
> 
> Further cells can be added in the future if/when drivers are
> upstreamed
> for them.

Couple of minor comments, otherwise looks good to me:

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> +/* Whiskey Cove PMIC share same ACPI ID between different platforms
> */
> +#define CHT_WC_HRV		3
> +
> +/* Level 1 IRQs (level 2 IRQs are handled in the child device
> drivers) */
> +enum {
> +	CHT_WC_PWRSRC_IRQ = 0,
> +	CHT_WC_THRM_IRQ,
> +	CHT_WC_BCU_IRQ,
> +	CHT_WC_ADC_IRQ,
> +	CHT_WC_EXT_CHGR_IRQ,
> +	CHT_WC_GPIO_IRQ,
> +	/* There is no irq 6 */
> +	CHT_WC_CRIT_IRQ = 7,

I would prefer explicit over implicit (adding = N to each line), but
this is minor.

> +};

> +	pmic->regmap = devm_regmap_init(dev, NULL, client,
> &cht_wc_regmap_cfg);
> +	if (IS_ERR(pmic->regmap))
> +		return PTR_ERR(pmic->regmap);
> +
> +	ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq,
> +				       IRQF_ONESHOT | IRQF_SHARED, 0,
> +				       &cht_wc_regmap_irq_chip,
> +				       &pmic->irq_chip_data);
> +	if (ret)
> +		return ret;
> +


> +	return devm_mfd_add_devices(dev, -1, cht_wc_dev,
> ARRAY_SIZE(cht_wc_dev),
> +			NULL, 0, regmap_irq_get_domain(pmic-
> >irq_chip_data));

PLATFORM_DEVID_NONE, please.

> +}

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-17  9:55 ` [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver Hans de Goede
@ 2017-03-17 17:18   ` Andy Shevchenko
  2017-03-20 18:08     ` Hans de Goede
  2017-03-20  1:33   ` Chanwoo Choi
  1 sibling, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:18 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm,
	Felipe Balbi

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> Add a driver for charger detection / control on the Intel Cherrytrail
> Whiskey Cove PMIC.

+Cc: Felipe for some question(s) below.

>  drivers/extcon/extcon-cht-wc.c | 356 

I would use same pattern across drivers, i.e. "chtwc" (same for the rest
of the drivers in this series).

> +#define CHT_WC_PWRSRC_IRQ		0x6e03
> +#define CHT_WC_PWRSRC_IRQ_MASK		0x6e0f
> +#define CHT_WC_PWRSRC_STS		0x6e1e
> +#define CHT_WC_PWRSRC_VBUS		BIT(0)
> +#define CHT_WC_PWRSRC_DC		BIT(1)
> +#define CHT_WC_PWRSRC_BAT		BIT(2)
> +#define CHT_WC_PWRSRC_ID_GND		BIT(3)
> +#define CHT_WC_PWRSRC_ID_FLOAT		BIT(4)

Not obvious for which register those bit definitions are.
Also, keep them ordered by offset.

> +
> +#define CHT_WC_PHYCTRL			0x5e07
> +

> +#define CHT_WC_CHGRCTRL0		0x5e16

Dup!

> +
> +#define CHT_WC_CHGRCTRL0		0x5e16

> +static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext)
> +{
> +	int ret, usbsrc, status, retries = 5;
> +
> +	do {
> +		ret = regmap_read(ext->regmap, CHT_WC_USBSRC,
> &usbsrc);
> +		if (ret) {
> +			dev_err(ext->dev, "Error reading usbsrc:
> %d\n", ret);
> +			return ret;
> +		}
> +		status = usbsrc & CHT_WC_USBSRC_STS_MASK;
> +		if (status == CHT_WC_USBSRC_STS_SUCCESS ||
> +		    status == CHT_WC_USBSRC_STS_FAIL)
> +			break;
> +

> +		msleep(200);

Comment why and why so long?

> +	} while (retries--);

> +static void cht_wc_extcon_det_event(struct cht_wc_extcon_data *ext)

det -> detect ?


> 
+static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
> +{
> +	struct cht_wc_extcon_data *ext = data;
> +	int ret, irqs;
> +
> +	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
> +	if (ret)
> +		dev_err(ext->dev, "Error reading irqs: %d\n", ret);

Shouldn't we return IRQ_NONE here?
Perhaps comment is needed.

> +
> +	cht_wc_extcon_det_event(ext);
> +
> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
> +	if (ret)
> +		dev_err(ext->dev, "Error writing irqs: %d\n", ret);
> +
> +	return IRQ_HANDLED;
> +}
> +

> +/* usb_id sysfs attribute for debug / testing purposes */

Hmm... I would use debugfs for debug, otherwise it looks like it should
be framework (extcon) wide.

Perhaps Felipe can advise something here.

> +static int cht_wc_extcon_probe(struct platform_device *pdev)
> +{

> +	struct cht_wc_extcon_data *ext;
> +	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev-
> >dev.parent);

Exchange them (assignment first).

> +	int irq, ret;
> +


> +	ret = devm_request_threaded_irq(ext->dev, irq, NULL,
> cht_wc_extcon_isr,
> +					IRQF_ONESHOT, pdev->name,
> ext);
> +	if (ret) {
> +		dev_err(ext->dev, "Failed to request interrupt\n");
> +		return ret;
> +	}
> +
> +	/* Unmask irqs */
> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
> +			   (int)~(CHT_WC_PWRSRC_VBUS | 

Hmm... Do you need explicit casting here?

> CHT_WC_PWRSRC_ID_GND |
> +				  CHT_WC_PWRSRC_ID_FLOAT));
> +	if (ret) {
> +		dev_err(ext->dev, "Error writing irq-mask: %d\n",
> ret);
> +		return ret;
> +	}

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 04/15] power: supply: bq24190_charger: Add no_register_reset pdata flag
  2017-03-17  9:55 ` [PATCH 04/15] power: supply: bq24190_charger: Add no_register_reset pdata flag Hans de Goede
@ 2017-03-17 17:20   ` Andy Shevchenko
  0 siblings, 0 replies; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:20 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> On some platforms the register have been setup with platform specific
> values by the firmware and should not be reset.
> 

I would not extend platform data at all.
For GPIO we may use GPIO lookup tables, for the rest -- unified (built-
in) device properties API.

Consider to get rid of 
 include/linux/power/bq24190_charger.h
completely.

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 06/15] power: supply: bq24190_charger: Use i2c-core irq-mapping code
  2017-03-17  9:55 ` [PATCH 06/15] power: supply: bq24190_charger: Use i2c-core irq-mapping code Hans de Goede
@ 2017-03-17 17:24   ` Andy Shevchenko
  2017-03-20  4:46     ` Sebastian Reichel
  0 siblings, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:24 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> The i2c-core already maps of irqs before calling the driver's probe
> function and there are no in tree users of
> bq24190_platform_data->gpio_int.
> 
> Remove the redundant custom irq-mapping code and just use client->irq.
> 

Nice! I did similar clean up to some other driver, so,

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

P.S. This should be first in the series against bq24190.

> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  drivers/power/supply/bq24190_charger.c | 61 ++-----------------------
> ---------
>  include/linux/power/bq24190_charger.h  |  1 -
>  2 files changed, 2 insertions(+), 60 deletions(-)
> 
> diff --git a/drivers/power/supply/bq24190_charger.c
> b/drivers/power/supply/bq24190_charger.c
> index 7bca8d0..9c4b171 100644
> --- a/drivers/power/supply/bq24190_charger.c
> +++ b/drivers/power/supply/bq24190_charger.c
> @@ -154,8 +154,6 @@ struct bq24190_dev_info {
>  	struct bq24190_platform_data	*pdata;
>  	char				model_name[I2C_NAME_SIZE]
> ;
>  	kernel_ulong_t			model;
> -	unsigned int			gpio_int;
> -	unsigned int			irq;
>  	struct mutex			f_reg_lock;
>  	u8				f_reg;
>  	u8				ss_reg;
> @@ -1296,56 +1294,11 @@ static int bq24190_hw_init(struct
> bq24190_dev_info *bdi)
>  	return ret;
>  }
>  
> -#ifdef CONFIG_OF
> -static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
> -{
> -	bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
> -	if (bdi->irq <= 0)
> -		return -1;
> -
> -	return 0;
> -}
> -#else
> -static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
> -{
> -	return -1;
> -}
> -#endif
> -
> -static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
> -		struct bq24190_platform_data *pdata)
> -{
> -	int ret;
> -
> -	if (!gpio_is_valid(pdata->gpio_int))
> -		return -1;
> -
> -	ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
> -	if (ret < 0)
> -		return -1;
> -
> -	ret = gpio_direction_input(pdata->gpio_int);
> -	if (ret < 0)
> -		goto out;
> -
> -	bdi->irq = gpio_to_irq(pdata->gpio_int);
> -	if (!bdi->irq)
> -		goto out;
> -
> -	bdi->gpio_int = pdata->gpio_int;
> -	return 0;
> -
> -out:
> -	gpio_free(pdata->gpio_int);
> -	return -1;
> -}
> -
>  static int bq24190_probe(struct i2c_client *client,
>  		const struct i2c_device_id *id)
>  {
>  	struct i2c_adapter *adapter = to_i2c_adapter(client-
> >dev.parent);
>  	struct device *dev = &client->dev;
> -	struct bq24190_platform_data *pdata = client-
> >dev.platform_data;
>  	struct power_supply_config charger_cfg = {}, battery_cfg =
> {};
>  	struct bq24190_dev_info *bdi;
>  	int ret;
> @@ -1372,12 +1325,7 @@ static int bq24190_probe(struct i2c_client
> *client,
>  
>  	i2c_set_clientdata(client, bdi);
>  
> -	if (dev->of_node)
> -		ret = bq24190_setup_dt(bdi);
> -	else
> -		ret = bq24190_setup_pdata(bdi, pdata);
> -
> -	if (ret) {
> +	if (!client->irq) {
>  		dev_err(dev, "Can't get irq info\n");
>  		return -EINVAL;
>  	}
> @@ -1417,7 +1365,7 @@ static int bq24190_probe(struct i2c_client
> *client,
>  		goto out3;
>  	}
>  
> -	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
> +	ret = devm_request_threaded_irq(dev, client->irq, NULL,
>  			bq24190_irq_handler_thread,
>  			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
>  			"bq24190-charger", bdi);
> @@ -1439,8 +1387,6 @@ static int bq24190_probe(struct i2c_client
> *client,
>  
>  out1:
>  	pm_runtime_disable(dev);
> -	if (bdi->gpio_int)
> -		gpio_free(bdi->gpio_int);
>  	return ret;
>  }
>  
> @@ -1457,9 +1403,6 @@ static int bq24190_remove(struct i2c_client
> *client)
>  	power_supply_unregister(bdi->charger);
>  	pm_runtime_disable(bdi->dev);
>  
> -	if (bdi->gpio_int)
> -		gpio_free(bdi->gpio_int);
> -
>  	return 0;
>  }
>  
> diff --git a/include/linux/power/bq24190_charger.h
> b/include/linux/power/bq24190_charger.h
> index cb49717..8d918cb 100644
> --- a/include/linux/power/bq24190_charger.h
> +++ b/include/linux/power/bq24190_charger.h
> @@ -10,7 +10,6 @@
>  #define _BQ24190_CHARGER_H_
>  
>  struct bq24190_platform_data {
> -	unsigned int	gpio_int;	/* GPIO pin that's
> connected to INT# */
>  	bool no_register_reset;
>  };
>  

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost
  2017-03-17  9:55 ` [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost Hans de Goede
@ 2017-03-17 17:33   ` Andy Shevchenko
  2017-03-20 22:38     ` Hans de Goede
  2017-03-20  4:52   ` Sebastian Reichel
  1 sibling, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:33 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> Add support for monitoring an extcon device with SDP/CDP/DCP and HOST
> cables and adjust ilimit and enable/disable the 5v boost converter
> accordingly. This is necessary on systems where the PSEL pin is
> hardwired
> high and ILIM needs to be set by software based on the detected
> charger
> type.
> 

>  config CHARGER_BQ24190
>  	tristate "TI BQ24190 battery charger driver"
>  	depends on I2C

> +	depends on EXTCON

I dunno what is preferred here, but if we would like to keep
compatibility with previous configurations "select" should be used over
"depends on".

> +static void bq24190_extcon_work(struct work_struct *work)
> +{
> +	struct bq24190_dev_info *bdi =
> +		container_of(work, struct bq24190_dev_info,
> extcon_work);
> +	int ret, iinlim = 0;
> +
> +	if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_SDP) == 1)
> +		iinlim = 500000;
> +	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_CDP) ==
> 1 ||
> +		 extcon_get_state(bdi->extcon, EXTCON_CHG_USB_ACA) ==
> 1)
> +		iinlim = 1500000;
> +	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_DCP) ==
> 1)
> +		iinlim = 2000000;
> +

> +	if (iinlim) {

Could be possible to call below unconditionally here (use 0)?

> +		ret = bq24190_set_field_val(bdi, BQ24190_REG_ISC,
> +				BQ24190_REG_ISC_IINLIM_MASK,
> +				BQ24190_REG_ISC_IINLIM_SHIFT,
> +				bq24190_iinlim_values,
> +				ARRAY_SIZE(bq24190_iinlim_values),
> +				iinlim);
> +		if (ret)
> +			dev_err(bdi->dev, "Can't set IINLIM: %d\n",
> ret);
> +	}

Perhaps make above as a helper?

In that case no need for "if (iinlim)" and perhaps switch-case might be
used instead of if-else-if (latter is up to you).

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 11/15] i2c: core: Allow getting ACPI info by index
  2017-03-17  9:55 ` [PATCH 11/15] i2c: core: Allow getting ACPI info by index Hans de Goede
@ 2017-03-17 17:35   ` Andy Shevchenko
  0 siblings, 0 replies; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:35 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm,
	Jarkko Nikula

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> Modify struct i2c_acpi_lookup and i2c_acpi_fill_info() to allow
> using them to get the info from a certain index in the ACPI-resource
> list rather then taking the first I2cSerialBus resource.
> 

+Cc: Jarkko (our main I2C guy)

> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  drivers/i2c/i2c-core.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index d2402bb..32b58fb 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -112,6 +112,8 @@ struct i2c_acpi_lookup {
>  	acpi_handle adapter_handle;
>  	acpi_handle device_handle;
>  	acpi_handle search_handle;
> +	int n;
> +	int index;
>  	u32 speed;
>  	u32 min_speed;
>  };
> @@ -123,6 +125,9 @@ static int i2c_acpi_fill_info(struct acpi_resource
> *ares, void *data)
>  	struct acpi_resource_i2c_serialbus *sb;
>  	acpi_status status;
>  
> +	if (lookup->index != -1 && lookup->n++ != lookup->index)
> +		return 1;
> +
>  	if (info->addr || ares->type !=
> ACPI_RESOURCE_TYPE_SERIAL_BUS)
>  		return 1;
>  
> @@ -182,6 +187,7 @@ static int i2c_acpi_get_info(struct acpi_device
> *adev,
>  
>  	memset(&lookup, 0, sizeof(lookup));
>  	lookup.info = info;
> +	lookup.index = -1;
>  
>  	ret = i2c_acpi_do_lookup(adev, &lookup);
>  	if (ret)
> @@ -328,6 +334,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
>  	lookup.search_handle = ACPI_HANDLE(dev);
>  	lookup.min_speed = UINT_MAX;
>  	lookup.info = &dummy;
> +	lookup.index = -1;
>  
>  	status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
> ACPI_ROOT_OBJECT,
>  				     I2C_ACPI_MAX_SCAN_DEPTH,

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 12/15] i2c: core: Add new i2c_acpi_new_device helper function
  2017-03-17  9:55 ` [PATCH 12/15] i2c: core: Add new i2c_acpi_new_device helper function Hans de Goede
@ 2017-03-17 17:37   ` Andy Shevchenko
  2017-03-22 15:59     ` Hans de Goede
  0 siblings, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:37 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> By default the i2c subsys creates an i2c-client for the first
> I2cSerialBus
> resource of an acpi_device, but some acpi_devices have multiple
> I2cSerialBus resources and the driver may need access to the others.
> 
> This commit adds a new i2c_acpi_new_device function which can be used
> by
> drivers to create an i2c-client for any (other) I2cSerialBus resource
> of
> an acpi_device.
> 
> Note that the other resources may even be on a different i2c bus, so
> just
> retrieving the client address is not enough.
> 

Looks sane to me:

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

Nevertheless, one nit, can you update commit message with real excerpt
of DSDT?

> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  drivers/i2c/i2c-core.c | 48
> ++++++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/i2c.h    |  5 +++++
>  2 files changed, 53 insertions(+)
> 
> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
> index 32b58fb..fd45207 100644
> --- a/drivers/i2c/i2c-core.c
> +++ b/drivers/i2c/i2c-core.c
> @@ -421,6 +421,54 @@ static int i2c_acpi_notify(struct notifier_block
> *nb, unsigned long value,
>  static struct notifier_block i2c_acpi_notifier = {
>  	.notifier_call = i2c_acpi_notify,
>  };
> +
> +/**
> + * i2c_acpi_new_device - Create i2c client for the Nth acpi resource
> of dev
> + * @dev:     Device owning the acpi resources to get the client from
> + * @index:   Index of acpi resource to get
> + *
> + * By default the i2c subsys creates an i2c-client for the first
> I2cSerialBus
> + * resource of an acpi_device, but some acpi_devices have multiple
> + * I2cSerialBus resources and the driver may need access to the
> others.
> + * This function can be used by drivers to create an i2c-client for
> any
> + * resource of an acpi_device.
> + *
> + * Returns a pointer to the new i2c-client, or NULL if the resource
> or
> + * adapter were not found.
> + */
> +struct i2c_client *i2c_acpi_new_device(struct device *dev, int index)
> +{
> +	struct i2c_acpi_lookup lookup;
> +	struct i2c_board_info info;
> +	struct i2c_adapter *adapter;
> +	struct acpi_device *adev;
> +	LIST_HEAD(resource_list);
> +	int ret;
> +
> +	adev = ACPI_COMPANION(dev);
> +	if (!adev)
> +		return NULL;
> +
> +	memset(&info, 0, sizeof(info));
> +	memset(&lookup, 0, sizeof(lookup));
> +	lookup.info = &info;
> +	lookup.device_handle = acpi_device_handle(adev);
> +	lookup.index = index;
> +
> +	ret = acpi_dev_get_resources(adev, &resource_list,
> +				     i2c_acpi_fill_info, &lookup);
> +	acpi_dev_free_resource_list(&resource_list);
> +
> +	if (ret < 0 || !info.addr)
> +		return NULL;
> +
> +	adapter =
> i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
> +	if (!adapter)
> +		return NULL;
> +
> +	return i2c_new_device(adapter, &info);
> +}
> +EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
>  #else /* CONFIG_ACPI */
>  static inline void i2c_acpi_register_devices(struct i2c_adapter
> *adap) { }
>  extern struct notifier_block i2c_acpi_notifier;
> diff --git a/include/linux/i2c.h b/include/linux/i2c.h
> index 6b18352..369ebfa 100644
> --- a/include/linux/i2c.h
> +++ b/include/linux/i2c.h
> @@ -824,11 +824,16 @@ static inline const struct of_device_id
>  
>  #if IS_ENABLED(CONFIG_ACPI)
>  u32 i2c_acpi_find_bus_speed(struct device *dev);
> +struct i2c_client *i2c_acpi_new_device(struct device *dev, int
> index);
>  #else
>  static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
>  {
>  	return 0;
>  }
> +static inline struct i2c_client *i2c_acpi_new_device(struct device
> *d, int i)
> +{
> +	return NULL;
> +}
>  #endif /* CONFIG_ACPI */
>  
>  #endif /* _LINUX_I2C_H */

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI
  2017-03-17  9:55 ` [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI Hans de Goede
@ 2017-03-17 17:41   ` Andy Shevchenko
  2017-03-20  8:55   ` kbuild test robot
  1 sibling, 0 replies; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:41 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> Some of or ACPI declared / enumerated devices may have multiple irq
> resources declared and the driver may want to use a different irq then
> the one with index 0.
> 
> This commit adds a new irq_index field to struct i2c_driver and makes
> the i2c-core pass this to of_irq_get / acpi_dev_gpio_irq_get.
> 
> This is esp. useful for ACPI declared devices where the irq with
> index 0 may be entirely useless and cause i2c_device_probe to fail
> with
> -EPROBE_DEFER.

> --- a/include/linux/i2c.h
> +++ b/include/linux/i2c.h
> @@ -212,6 +212,9 @@ struct i2c_driver {
>  	int (*detect)(struct i2c_client *, struct i2c_board_info *);
>  	const unsigned short *address_list;
>  	struct list_head clients;
> +
> +	/* IRQ index for retreiving irq from ACPI resources */

We have kernel doc.

> +	int irq_index;

Not sure about name (would like it to be shorter, but Friday evening
doesn't allow to be creative).

>  };
>  #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge
  2017-03-17  9:55 ` [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge Hans de Goede
@ 2017-03-17 17:58   ` Andy Shevchenko
  2017-03-22 17:03     ` Hans de Goede
  2017-03-20  5:07   ` Sebastian Reichel
  1 sibling, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 17:58 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> Add a driver for the Cherry Trail Whiskey Cove PMIC Fuel Gauge, note
> the Cherry Trail Whiskey Cove PMIC Fuel Gauge block is purely a fuel
> gauge
> and not a full battery controller. As such it offers a platform_data
> callback for extra power_supply properties for the actual external-
> charger
> ic driver and does not register a power_supply itself.

ic -> IC

Can we move to something like built-in device properties for additional
properties instead of extending platform data?

> +config CHT_WC_FUEL_GAUGE

I would use similar pattern:

FUEL_GAUGE_INTEL_CHTWC (or FUEL_GAUGE_CHTWC, but this might be less
obvious about vendor)

> --- /dev/null
> +++ b/drivers/power/supply/cht_wc_fuel_gauge.c
> @@ -0,0 +1,209 @@
> +/*
> + * Intel CHT Whiskey Cove Fuel Gauge driver

CHT -> Cherry Trail 

> + *
> + * Cherrytrail Whiskey Cove devices have 2 functional blocks which
> interact
> + * with the battery.

Cherry Trail? 

> +#define REG_CHARGE_NOW		0x05
> +#define REG_VOLTAGE_NOW		0x09
> +#define REG_CURRENT_NOW		0x0a
> +#define REG_CURRENT_AVG		0x0b
> +#define REG_CHARGE_FULL		0x10
> +#define REG_CHARGE_DESIGN	0x18
> +#define REG_VOLTAGE_AVG		0x19

> +#define REG_VOLTAGE_OCV		0x1b /* Only updated during
> charging */

I think comment makes more sense where actual update is happening in the
code.

> +
> +static int cht_wc_fg_read(struct cht_wc_fg_data *fg, u8 reg,
> +			  union power_supply_propval *val, int scale,
> +			  int sign_extend)
> +{
> +	int ret;
> +
> +	ret = i2c_smbus_read_word_data(fg->client, reg);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (sign_extend)
> +		ret = sign_extend32(ret, 15);

Magic?

> +
> +	val->intval = ret * scale;
> +
> +	return 0;
> +}


> +
> +int cht_wc_fg_get_property(enum power_supply_property prop,
> +			   union power_supply_propval *val)
> +{
> +	int ret = 0;

Sounds like redundant assignment...

> +
> +	mutex_lock(&cht_wc_fg_mutex);
> +
> 

> +	if (!cht_wc_fg) {
> +		ret = -ENXIO;
> +		goto out_unlock;
> +	}

...otherwise maybe

ret = cht_wc_fg ? 0 : -ENXIO;
if (ret)
 goto ...;

?

> +	default:
> +		ret = -ENODATA;
> +	}
> +out_unlock:
> +	mutex_unlock(&cht_wc_fg_mutex);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(cht_wc_fg_get_property);

> +
> +static int cht_wc_fg_probe(struct i2c_client *client,
> +			const struct i2c_device_id *i2c_id)
> +{
> +	struct device *dev = &client->dev;
> +	struct cht_wc_fg_data *fg;
> +	acpi_status status;
> +	unsigned long long ptyp;

> +	status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP",
> NULL, &ptyp);
> +	if (ACPI_FAILURE(status)) {
> +		dev_err(dev, "Failed to get PTYPE\n");
> +		return -ENODEV;
> +	}
> +
> +	/*
> +	 * The same ACPI HID is used with different PMICs check PTYP
> to
> +	 * ensure that we are dealing with a Whiskey Cove PMIC.
> +	 */
> +	if (ptyp != CHT_WC_FG_PTYPE)
> +		return -ENODEV;

Logically I would split this part to be a main driver for device which
would use actual driver based on this, though I think it too much churn
for no benefit right now.

> +	mutex_lock(&cht_wc_fg_mutex);
> +	cht_wc_fg = fg;
> +	mutex_unlock(&cht_wc_fg_mutex);

It's pity we have no common storage of single possible present device
drivers in the kernel. I would use some kind of framework rather then
keeping all those global variables with locking. Perhaps radix / RB
tree.

> +
> +	return 0;
> +}

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 15/15] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS controller driver
  2017-03-17  9:55 ` [PATCH 15/15] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS controller driver Hans de Goede
@ 2017-03-17 18:22   ` Andy Shevchenko
  2017-03-23 13:58     ` Hans de Goede
  0 siblings, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-17 18:22 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> The Intel Cherry Trail Whiskey Cove PMIC has a builtin SMBUS
> controller
> for talking to an external PMIC. Add a driver for this.

Looking to all this mess we have with PMICs, perhaps some file under
Documentation to explain all those dependencies with nice ASCII flow
charts would be created.

>  drivers/i2c/busses/i2c-cht-wc.c | 338 

File name: i2c-chtwc.c

> +#include <linux/power/cht_wc_fuel_gauge.h>

Perhaps chtwc_fuel_gauge or intel_chtwc_fuel_gauge.h (see previous patch
for comment regarding naming).

> +#include <linux/slab.h>
> +
> +#define CHT_WC_I2C_CTRL			0x5e24
> +#define CHT_WC_I2C_CTRL_WR		BIT(0)
> +#define CHT_WC_I2C_CTRL_RD		BIT(1)
> +#define CHT_WC_I2C_CLIENT_ADDR		0x5e25
> +#define CHT_WC_I2C_REG_OFFSET		0x5e26
> +#define CHT_WC_I2C_WRDATA		0x5e27
> +#define CHT_WC_I2C_RDDATA		0x5e28
> +
> +#define CHT_WC_EXTCHGRIRQ		0x6e0a
> +#define CHT_WC_EXTCHGRIRQ_CLIENT_IRQ	BIT(0)
> +#define CHT_WC_EXTCHGRIRQ_WRITE_IRQ	BIT(1)
> +#define CHT_WC_EXTCHGRIRQ_READ_IRQ	BIT(2)
> +#define CHT_WC_EXTCHGRIRQ_NACK_IRQ	BIT(3)
> 

> +#define CHT_WC_EXTCHGRIRQ_ADAP_IRQS	((u8)(BIT(1) | BIT(2) |
> BIT(3)))

_IRQ_MASK ?

GENMASK() ?

> +#define CHT_WC_EXTCHGRIRQ_MSK		0x6e17

> +struct cht_wc_i2c_adap {
> +	struct i2c_adapter adapter;
> +	wait_queue_head_t wait;
> +	struct irq_chip irqchip;
> +	struct mutex irqchip_lock;
> +	struct regmap *regmap;
> +	struct irq_domain *irq_domain;
> +	struct i2c_client *client;
> +	int client_irq;
> +	u8 irq_mask;
> +	u8 old_irq_mask;
> +	bool nack;
> +	bool done;
> +};
> +
> +static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data)
> +{
> +	struct cht_wc_i2c_adap *adap = data;
> +	int ret, reg;
> +
> +	/* Read irqs */

IRQs

> +	ret = regmap_read(adap->regmap, CHT_WC_EXTCHGRIRQ, &reg);
> +	if (ret) {
> +		dev_err(&adap->adapter.dev, "Error reading extchgrirq
> reg\n");
> +		return IRQ_NONE;
> +	}
> +
> +	reg &= ~adap->irq_mask;
> +
> +	/*
> +	 * Immediately ack irqs, so that if new irqs arrives while
> we're
> +	 * handling the previous ones our irq will re-trigger when
> we're done.
> +	 */
> +	ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg);
> +	if (ret)
> +		dev_err(&adap->adapter.dev, "Error writing extchgrirq
> reg\n");
> +
> +	/*
> +	 * Do NOT use handle_nested_irq here, the client irq handler
> will
> +	 * likely want to do i2c transfers and the i2c controller
> uses this
> +	 * interrupt handler as well, so running the client irq
> handler from
> +	 * this thread will cause things to lock up.
> +	 */
> +	if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) {
> +		/*
> +		 * generic_handle_irq expects local irqs to be
> disabled
> +		 * as normally it is called from interrupt context.
> +		 */
> +		local_irq_disable();
> +		generic_handle_irq(adap->client_irq);
> +		local_irq_enable();
> +	}
> +
> +	if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQS) {

> +		if (reg & CHT_WC_EXTCHGRIRQ_NACK_IRQ)
> +			adap->nack = true;

adap->nack = !!(reg & ...);

> +		adap->done = true;
> +		wake_up(&adap->wait);
> +	}
> +
> +	return IRQ_HANDLED;
> +}

> +static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap)
> +{
> +	/* This i2c adapter only supports smbus byte transfers */

smbus -> SMBUS

> +	return I2C_FUNC_SMBUS_BYTE_DATA;
> +}
> +
> +static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16
> addr,
> +				      unsigned short flags, char
> read_write,
> +				      u8 command, int size,
> +				      union i2c_smbus_data *data)
> +{
> +	struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap);
> +	int ret, reg;
> +

> +
> +	/* 3 second timeout, during cable plug the PMIC responds
> quite slow */
> +	ret = wait_event_timeout(adap->wait, adap->done, HZ * 3);

3 * HZ

> +	if (ret == 0)
> +		return -ETIMEDOUT;
> +	if (adap->nack)
> +		return -EIO;
> +
> +	if (read_write == I2C_SMBUS_READ) {
> +		ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA,
> &reg);
> +		if (ret)
> +			return ret;
> +
> +		data->byte = reg;
> +	}
> +
> +	return 0;
> +}

> +/**** irqchip for the client connected to the extchgr i2c adapter
> ****/

Useless ?

> +static void cht_wc_i2c_irq_lock(struct irq_data *data)
> +{
> +	struct cht_wc_i2c_adap *adap =
> irq_data_get_irq_chip_data(data);
> +
> +	mutex_lock(&adap->irqchip_lock);
> +}
> +
> +static void cht_wc_i2c_irq_sync_unlock(struct irq_data *data)
> +{
> +	struct cht_wc_i2c_adap *adap =
> irq_data_get_irq_chip_data(data);
> +	int ret;
> +
> +	if (adap->irq_mask != adap->old_irq_mask) {
> +		ret = regmap_write(adap->regmap,
> CHT_WC_EXTCHGRIRQ_MSK,
> +				   adap->irq_mask);
> +		if (ret == 0)
> +			adap->old_irq_mask = adap->irq_mask;
> +		else
> +			dev_err(&adap->adapter.dev, "Error writing
> extchgrirq_msk\n");

extchgrirq_msk -> EXTCHGRIRQ_MSK ?
> +	}
> +
> +	mutex_unlock(&adap->irqchip_lock);
> +}


> +static const struct bq24190_platform_data bq24190_pdata = {
> +	.no_register_reset = true,
> +	.extcon_name = "cht_wcove_pwrsrc",
> +	.get_ext_bat_property = cht_wc_fg_get_property,
> +};
> +
> +static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
> +{
> +	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev-
> >dev.parent);
> +	struct cht_wc_i2c_adap *adap;

> +	struct i2c_board_info board_info = {
> +		.type = "bq24190",
> +		.addr = 0x6b,
> +		.platform_data = (void *)&bq24190_pdata,
> +	};
> +	int ret, irq;
> +

> +	/* Clear and activate i2c-adapter interrupts, disable client
> irq */

irq -> IRQ

> +
> +	/* Alloc and register client irq */

Ditto.

> +	adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
> 1,
> +						 &irq_domain_simple_o
> ps, NULL);

Can you use irq_domain_add_simple()?

And why do we need separate domain for one IRQ line?

> +	if (!adap->irq_domain)
> +		return -ENOMEM;
> +
> +	adap->client_irq = irq_create_mapping(adap->irq_domain, 0);
> +	if (!adap->client_irq) {
> +		ret = -ENOMEM;
> +		goto remove_irq_domain;
> +	}
> +
> +	irq_set_chip_data(adap->client_irq, adap);
> +	irq_set_chip_and_handler(adap->client_irq, &adap->irqchip,
> +				 handle_simple_irq);
> +

> +	board_info.irq = adap->client_irq;
> +	adap->client = i2c_new_device(&adap->adapter, &board_info);
> +	if (!adap->client) {
> +		ret = -ENOMEM;
> +		goto del_adapter;
> +	}

I would split this to some other module with board info.

Does it make sense?

By the way, doesn't ACPI have the charger IC node?

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-17  9:55 ` [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver Hans de Goede
  2017-03-17 17:18   ` Andy Shevchenko
@ 2017-03-20  1:33   ` Chanwoo Choi
  2017-03-20 13:00     ` Andy Shevchenko
  2017-03-20 19:57     ` Hans de Goede
  1 sibling, 2 replies; 46+ messages in thread
From: Chanwoo Choi @ 2017-03-20  1:33 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Andy Shevchenko, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 2017년 03월 17일 18:55, Hans de Goede wrote:
> Add a driver for charger detection / control on the Intel Cherrytrail
> Whiskey Cove PMIC.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> ---
>  drivers/extcon/Kconfig         |   7 +
>  drivers/extcon/Makefile        |   1 +
>  drivers/extcon/extcon-cht-wc.c | 356 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 364 insertions(+)
>  create mode 100644 drivers/extcon/extcon-cht-wc.c
> 
> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
> index 96bbae5..4cace6b 100644
> --- a/drivers/extcon/Kconfig
> +++ b/drivers/extcon/Kconfig
> @@ -52,6 +52,13 @@ config EXTCON_INTEL_INT3496
>  	  This ACPI device is typically found on Intel Baytrail or Cherrytrail
>  	  based tablets, or other Baytrail / Cherrytrail devices.
>  
> +config EXTCON_CHT_WC

Need to reorder it alpabetically as the following Makefile.

> +	tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver"
> +	depends on INTEL_SOC_PMIC_CHTWC
> +	help
> +	  Say Y here to enable extcon support for charger detection / control
> +	  on the Intel Cherrytrail Whiskey Cove PMIC.
> +
>  config EXTCON_MAX14577
>  	tristate "Maxim MAX14577/77836 EXTCON Support"
>  	depends on MFD_MAX14577
> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
> index 237ac3f..160f88b 100644
> --- a/drivers/extcon/Makefile
> +++ b/drivers/extcon/Makefile
> @@ -7,6 +7,7 @@ extcon-core-objs		+= extcon.o devres.o
>  obj-$(CONFIG_EXTCON_ADC_JACK)	+= extcon-adc-jack.o
>  obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
>  obj-$(CONFIG_EXTCON_AXP288)	+= extcon-axp288.o
> +obj-$(CONFIG_EXTCON_CHT_WC)	+= extcon-cht-wc.o
>  obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
>  obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
>  obj-$(CONFIG_EXTCON_MAX14577)	+= extcon-max14577.o
> diff --git a/drivers/extcon/extcon-cht-wc.c b/drivers/extcon/extcon-cht-wc.c
> new file mode 100644
> index 0000000..896eee6
> --- /dev/null
> +++ b/drivers/extcon/extcon-cht-wc.c
> @@ -0,0 +1,356 @@
> +/*
> + * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
> + *
> + * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:

Maybe, you don't need to add ':' at the end of line.

> + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/extcon.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/intel_soc_pmic.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +#define CHT_WC_PWRSRC_IRQ		0x6e03
> +#define CHT_WC_PWRSRC_IRQ_MASK		0x6e0f
> +#define CHT_WC_PWRSRC_STS		0x6e1e
> +#define CHT_WC_PWRSRC_VBUS		BIT(0)
> +#define CHT_WC_PWRSRC_DC		BIT(1)
> +#define CHT_WC_PWRSRC_BAT		BIT(2)
> +#define CHT_WC_PWRSRC_ID_GND		BIT(3)
> +#define CHT_WC_PWRSRC_ID_FLOAT		BIT(4)
> +
> +#define CHT_WC_PHYCTRL			0x5e07
> +
> +#define CHT_WC_CHGRCTRL0		0x5e16
> +
> +#define CHT_WC_CHGRCTRL0		0x5e16
> +#define CHT_WC_CHGRCTRL0_CHGRRESET	BIT(0)
> +#define CHT_WC_CHGRCTRL0_EMRGCHREN	BIT(1)
> +#define CHT_WC_CHGRCTRL0_EXTCHRDIS	BIT(2)
> +#define CHT_WC_CHGRCTRL0_SWCONTROL	BIT(3)
> +#define CHT_WC_CHGRCTRL0_TTLCK_MASK	BIT(4)
> +#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK	BIT(5)
> +#define CHT_WC_CHGRCTRL0_DBPOFF_MASK	BIT(6)
> +#define CHT_WC_CHGRCTRL0_WDT_NOKICK	BIT(7)
> +
> +#define CHT_WC_CHGRCTRL1		0x5e17
> +
> +#define CHT_WC_USBSRC			0x5e29
> +#define CHT_WC_USBSRC_STS_MASK		GENMASK(1, 0)
> +#define CHT_WC_USBSRC_STS_SUCCESS	2
> +#define CHT_WC_USBSRC_STS_FAIL		3
> +#define CHT_WC_USBSRC_TYPE_SHIFT	2
> +#define CHT_WC_USBSRC_TYPE_MASK		GENMASK(5, 2)
> +#define CHT_WC_USBSRC_TYPE_NONE		0
> +#define CHT_WC_USBSRC_TYPE_SDP		1
> +#define CHT_WC_USBSRC_TYPE_DCP		2
> +#define CHT_WC_USBSRC_TYPE_CDP		3
> +#define CHT_WC_USBSRC_TYPE_ACA		4
> +#define CHT_WC_USBSRC_TYPE_SE1		5
> +#define CHT_WC_USBSRC_TYPE_MHL		6
> +#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN	7
> +#define CHT_WC_USBSRC_TYPE_OTHER	8
> +#define CHT_WC_USBSRC_TYPE_DCP_EXTPHY	9
> +
> +enum cht_wc_usb_id {
> +	USB_ID_OTG,
> +	USB_ID_GND,
> +	USB_ID_FLOAT,
> +	USB_RID_A,
> +	USB_RID_B,
> +	USB_RID_C,
> +};
> +
> +/* Strings matching the cht_wc_usb_id enum labels */
> +static const char * const usb_id_str[] = {
> +	"otg", "gnd", "float", "rid_a", "rid_b", "rid_c" };
> +
> +enum cht_wc_mux_select {
> +	MUX_SEL_PMIC = 0,
> +	MUX_SEL_SOC,
> +};
> +
> +static const unsigned int cht_wc_extcon_cables[] = {
> +	EXTCON_USB,
> +	EXTCON_USB_HOST,
> +	EXTCON_CHG_USB_SDP,
> +	EXTCON_CHG_USB_CDP,
> +	EXTCON_CHG_USB_DCP,
> +	EXTCON_NONE,
> +};
> +
> +struct cht_wc_extcon_data {
> +	struct device *dev;
> +	struct regmap *regmap;
> +	struct extcon_dev *edev;
> +	unsigned int previous_cable;
> +	int usb_id;
> +};
> +
> +static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
> +{
> +	if (ext->usb_id)
> +		return ext->usb_id;
> +
> +	if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
> +		return USB_ID_GND;
> +	if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
> +		return USB_ID_FLOAT;
> +
> +	/*
> +	 * Once we have iio support for the gpadc we should read the USBID
> +	 * gpadc channel here and determine ACA role based on that.
> +	 */
> +	return USB_ID_FLOAT;
> +}
> +
> +static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext)
> +{
> +	int ret, usbsrc, status, retries = 5;

You have to define the constant for '5' because the name of constant
definition indicates what is meaning. So, maybe you will use the 'for' loope
instead of 'do..while'.

> +
> +	do {
> +		ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc);
> +		if (ret) {
> +			dev_err(ext->dev, "Error reading usbsrc: %d\n", ret);
> +			return ret;
> +		}

Need to add one blank line.

> +		status = usbsrc & CHT_WC_USBSRC_STS_MASK;
> +		if (status == CHT_WC_USBSRC_STS_SUCCESS ||
> +		    status == CHT_WC_USBSRC_STS_FAIL)
> +			break;
> +
> +		msleep(200);

You have to define the constant for '200' because the name of constant
definition indicates what is meaning.

> +	} while (retries--);
> +
> +	if (status != CHT_WC_USBSRC_STS_SUCCESS) {
> +		if (status == CHT_WC_USBSRC_STS_FAIL)
> +			dev_warn(ext->dev, "Could not detect charger type\n");
> +		else
> +			dev_warn(ext->dev, "Timeout detecting charger type\n");
> +		return EXTCON_CHG_USB_SDP; /* Save fallback */
> +	}
> +
> +	ret = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;

'ret' is not proper indicates the meaning of 'CHT_WC_USBSRC_TYPE'.
You have to use the more correct local variable such as 'usbsrc_type'.

> +	switch (ret) {
> +	default:
> +		dev_warn(ext->dev, "Unhandled charger type %d\n", ret);
> +		/* Fall through treat as SDP */

Is it right? Why do you located the 'default' on the top in the switch?

> +	case CHT_WC_USBSRC_TYPE_SDP:
> +	case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
> +	case CHT_WC_USBSRC_TYPE_OTHER:
> +		return EXTCON_CHG_USB_SDP;
> +	case CHT_WC_USBSRC_TYPE_CDP:
> +		return EXTCON_CHG_USB_CDP;
> +	case CHT_WC_USBSRC_TYPE_DCP:
> +	case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
> +	case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
> +		return EXTCON_CHG_USB_DCP;
> +	case CHT_WC_USBSRC_TYPE_ACA:
> +		return EXTCON_CHG_USB_ACA;
> +	}
> +}
> +
> +static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state)
> +{
> +	int ret;
> +
> +	ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state);
> +	if (ret)
> +		dev_err(ext->dev, "Error writing phyctrl: %d\n", ret);

This function is only called in the cht_wc_extcon_det_event().
Also, this funciton write only one register. It is too short.
So, you don't need to add the separate function.
You better to include this code in the cht_wc_extcon_det_event().

> +}
> +
> +static void cht_wc_extcon_det_event(struct cht_wc_extcon_data *ext)
> +{
> +	int ret, pwrsrc_sts, id;
> +	unsigned int cable = EXTCON_NONE;
> +
> +	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
> +	if (ret) {
> +		dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
> +		return;
> +	}
> +
> +	id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
> +	if (id == USB_ID_GND) {
> +		/* The 5v boost causes a false VBUS / SDP detect, skip */
> +		goto charger_det_done;
> +	}
> +
> +	/* Plugged into a host/charger or not connected? */
> +	if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) {
> +		/* Route D+ and D- to PMIC for future charger detection */
> +		cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
> +		goto set_state;
> +	}

The cht_wc_extcon_get_id() and cht_wc_extcon_det_event() use the value
of CHT_WC_PWRSRC_STS register. So, I think you better to gather the 
code related to the CHT_WC_PWRSRC_STS for readability.
- First suggestion, remove the separate the cht_wc_extcon_get_id()
- Second suggestion, The code from regmap_read() to "!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)"
          move into the cht_wc_extcon_get_id().

In my opinion, I recommend that second way.

> +
> +	ret = cht_wc_extcon_get_charger(ext);
> +	if (ret >= 0)
> +		cable = ret;
> +
> +charger_det_done:
> +	/* Route D+ and D- to SoC for the host / gadget controller */

Minor comment.
You better to use '&' instead of '/' 

> +	cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC);
> +
> +set_state:
> +	extcon_set_state_sync(ext->edev, cable, true);
> +	extcon_set_state_sync(ext->edev, ext->previous_cable, false);
> +	extcon_set_state_sync(ext->edev, EXTCON_USB_HOST,
> +			      id == USB_ID_GND || id == USB_RID_A);
> +	ext->previous_cable = cable;
> +}
> +
> +static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
> +{
> +	struct cht_wc_extcon_data *ext = data;
> +	int ret, irqs;
> +
> +	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
> +	if (ret)
> +		dev_err(ext->dev, "Error reading irqs: %d\n", ret);
> +
> +	cht_wc_extcon_det_event(ext);
> +
> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
> +	if (ret)
> +		dev_err(ext->dev, "Error writing irqs: %d\n", ret);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/* usb_id sysfs attribute for debug / testing purposes */
> +static ssize_t usb_id_show(struct device *dev, struct device_attribute *attr,
> +			   char *buf)
> +{
> +	struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
> +
> +	return sprintf(buf, "%s\n", usb_id_str[ext->usb_id]);
> +}
> +
> +static ssize_t usb_id_store(struct device *dev, struct device_attribute *attr,
> +			    const char *buf, size_t n)
> +{
> +	struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(usb_id_str); i++) {
> +		if (sysfs_streq(buf, usb_id_str[i])) {
> +			dev_info(ext->dev, "New usb_id %s\n", usb_id_str[i]);
> +			ext->usb_id = i;
> +			cht_wc_extcon_det_event(ext);
> +			return n;
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static DEVICE_ATTR(usb_id, 0644, usb_id_show, usb_id_store);

I think it is not good to add specific sysfs for only this device driver.
The sysfs entry of framework must include the only common and standard interfarce
for all extcon device drivers. Because the sysfs entry affects the ABI interface.

So, It is not proper.

> +
> +static int cht_wc_extcon_probe(struct platform_device *pdev)
> +{
> +	struct cht_wc_extcon_data *ext;
> +	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
> +	int irq, ret;
> +
> +	irq = platform_get_irq(pdev, 0);
> +	if (irq < 0)
> +		return irq;
> +
> +	ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL);
> +	if (!ext)
> +		return -ENOMEM;
> +
> +	ext->dev = &pdev->dev;
> +	ext->regmap = pmic->regmap;
> +	ext->previous_cable = EXTCON_NONE;
> +
> +	/* Initialize extcon device */
> +	ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables);
> +	if (IS_ERR(ext->edev))
> +		return PTR_ERR(ext->edev);
> +
> +	ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0,
> +		 CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK,
> +		 CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK);
> +	if (ret) {
> +		dev_err(ext->dev, "Error enabling sw control\n");
> +		return ret;
> +	}
> +
> +	/* Register extcon device */
> +	ret = devm_extcon_dev_register(ext->dev, ext->edev);
> +	if (ret) {
> +		dev_err(ext->dev, "Failed to register extcon device\n");
> +		return ret;
> +	}
> +
> +	/* Route D+ and D- to PMIC for initial charger detection */
> +	cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
> +
> +	/* Get initial state */
> +	cht_wc_extcon_det_event(ext);
> +
> +	ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr,
> +					IRQF_ONESHOT, pdev->name, ext);
> +	if (ret) {
> +		dev_err(ext->dev, "Failed to request interrupt\n");
> +		return ret;
> +	}
> +
> +	/* Unmask irqs */
> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
> +			   (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
> +				  CHT_WC_PWRSRC_ID_FLOAT));
> +	if (ret) {
> +		dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);

I prefer to use the consistent error log. In the probe function,
you use the 'Failed to ...' when error hanppen. So, You better
to use the consistent format for errr log as following:
	- "Failed to write the irq-mask: %d\n", ret);

I think it improve the readability of your device driver.

> +		return ret;
> +	}
> +
> +	platform_set_drvdata(pdev, ext);
> +	device_create_file(ext->dev, &dev_attr_usb_id);
> +
> +	return 0;


In the probe function, you touch the some register for initialization.
But, if error happen, the probe function don't restore the register value.
Is it ok? I think you need to handle the error case.

> +}
> +
> +static int cht_wc_extcon_remove(struct platform_device *pdev)
> +{
> +	struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev);
> +
> +	device_remove_file(ext->dev, &dev_attr_usb_id);

Don't need it.

> +
> +	return 0;
> +}
> +
> +static const struct platform_device_id cht_wc_extcon_table[] = {
> +	{ .name = "cht_wcove_pwrsrc" },

You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
So, To maintain the consistency, you better to use the 'cht-wc' as the name.
- I prefer to use '-' instead of '_' in the name.
	.name ="cht-wc"

> +	{},
> +};
> +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
> +
> +static struct platform_driver cht_wc_extcon_driver = {
> +	.probe = cht_wc_extcon_probe,
> +	.remove = cht_wc_extcon_remove,
> +	.id_table = cht_wc_extcon_table,
> +	.driver = {
> +		.name = "cht_wcove_pwrsrc",
> +	},
> +};
> +module_platform_driver(cht_wc_extcon_driver);
> +
> +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
> +MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver");

Minor comment.
You better to locate the MODULE_DESCRIPTION at the first line
and then MODULE_AUTHOR is at second line.

> +MODULE_LICENSE("GPL v2");
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

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

* Re: [PATCH 06/15] power: supply: bq24190_charger: Use i2c-core irq-mapping code
  2017-03-17 17:24   ` Andy Shevchenko
@ 2017-03-20  4:46     ` Sebastian Reichel
  0 siblings, 0 replies; 46+ messages in thread
From: Sebastian Reichel @ 2017-03-20  4:46 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, MyungJoo Ham, Chanwoo Choi, linux-acpi, Takashi Iwai,
	linux-i2c, linux-kernel, linux-pm

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

Hi,

On Fri, Mar 17, 2017 at 07:24:14PM +0200, Andy Shevchenko wrote:
> On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> > The i2c-core already maps of irqs before calling the driver's probe
> > function and there are no in tree users of
> > bq24190_platform_data->gpio_int.
> > 
> > Remove the redundant custom irq-mapping code and just use client->irq.
> > 
> 
> Nice! I did similar clean up to some other driver, so,
> 
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> 
> P.S. This should be first in the series against bq24190.

Right.

Acked-by: Sebastian Reichel <sre@kernel.org>

-- Sebastian

> > Signed-off-by: Hans de Goede <hdegoede@redhat.com>
> > ---
> >  drivers/power/supply/bq24190_charger.c | 61 ++-----------------------
> > ---------
> >  include/linux/power/bq24190_charger.h  |  1 -
> >  2 files changed, 2 insertions(+), 60 deletions(-)
> > 
> > diff --git a/drivers/power/supply/bq24190_charger.c
> > b/drivers/power/supply/bq24190_charger.c
> > index 7bca8d0..9c4b171 100644
> > --- a/drivers/power/supply/bq24190_charger.c
> > +++ b/drivers/power/supply/bq24190_charger.c
> > @@ -154,8 +154,6 @@ struct bq24190_dev_info {
> >  	struct bq24190_platform_data	*pdata;
> >  	char				model_name[I2C_NAME_SIZE]
> > ;
> >  	kernel_ulong_t			model;
> > -	unsigned int			gpio_int;
> > -	unsigned int			irq;
> >  	struct mutex			f_reg_lock;
> >  	u8				f_reg;
> >  	u8				ss_reg;
> > @@ -1296,56 +1294,11 @@ static int bq24190_hw_init(struct
> > bq24190_dev_info *bdi)
> >  	return ret;
> >  }
> >  
> > -#ifdef CONFIG_OF
> > -static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
> > -{
> > -	bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
> > -	if (bdi->irq <= 0)
> > -		return -1;
> > -
> > -	return 0;
> > -}
> > -#else
> > -static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
> > -{
> > -	return -1;
> > -}
> > -#endif
> > -
> > -static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
> > -		struct bq24190_platform_data *pdata)
> > -{
> > -	int ret;
> > -
> > -	if (!gpio_is_valid(pdata->gpio_int))
> > -		return -1;
> > -
> > -	ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
> > -	if (ret < 0)
> > -		return -1;
> > -
> > -	ret = gpio_direction_input(pdata->gpio_int);
> > -	if (ret < 0)
> > -		goto out;
> > -
> > -	bdi->irq = gpio_to_irq(pdata->gpio_int);
> > -	if (!bdi->irq)
> > -		goto out;
> > -
> > -	bdi->gpio_int = pdata->gpio_int;
> > -	return 0;
> > -
> > -out:
> > -	gpio_free(pdata->gpio_int);
> > -	return -1;
> > -}
> > -
> >  static int bq24190_probe(struct i2c_client *client,
> >  		const struct i2c_device_id *id)
> >  {
> >  	struct i2c_adapter *adapter = to_i2c_adapter(client-
> > >dev.parent);
> >  	struct device *dev = &client->dev;
> > -	struct bq24190_platform_data *pdata = client-
> > >dev.platform_data;
> >  	struct power_supply_config charger_cfg = {}, battery_cfg =
> > {};
> >  	struct bq24190_dev_info *bdi;
> >  	int ret;
> > @@ -1372,12 +1325,7 @@ static int bq24190_probe(struct i2c_client
> > *client,
> >  
> >  	i2c_set_clientdata(client, bdi);
> >  
> > -	if (dev->of_node)
> > -		ret = bq24190_setup_dt(bdi);
> > -	else
> > -		ret = bq24190_setup_pdata(bdi, pdata);
> > -
> > -	if (ret) {
> > +	if (!client->irq) {
> >  		dev_err(dev, "Can't get irq info\n");
> >  		return -EINVAL;
> >  	}
> > @@ -1417,7 +1365,7 @@ static int bq24190_probe(struct i2c_client
> > *client,
> >  		goto out3;
> >  	}
> >  
> > -	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
> > +	ret = devm_request_threaded_irq(dev, client->irq, NULL,
> >  			bq24190_irq_handler_thread,
> >  			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
> >  			"bq24190-charger", bdi);
> > @@ -1439,8 +1387,6 @@ static int bq24190_probe(struct i2c_client
> > *client,
> >  
> >  out1:
> >  	pm_runtime_disable(dev);
> > -	if (bdi->gpio_int)
> > -		gpio_free(bdi->gpio_int);
> >  	return ret;
> >  }
> >  
> > @@ -1457,9 +1403,6 @@ static int bq24190_remove(struct i2c_client
> > *client)
> >  	power_supply_unregister(bdi->charger);
> >  	pm_runtime_disable(bdi->dev);
> >  
> > -	if (bdi->gpio_int)
> > -		gpio_free(bdi->gpio_int);
> > -
> >  	return 0;
> >  }
> >  
> > diff --git a/include/linux/power/bq24190_charger.h
> > b/include/linux/power/bq24190_charger.h
> > index cb49717..8d918cb 100644
> > --- a/include/linux/power/bq24190_charger.h
> > +++ b/include/linux/power/bq24190_charger.h
> > @@ -10,7 +10,6 @@
> >  #define _BQ24190_CHARGER_H_
> >  
> >  struct bq24190_platform_data {
> > -	unsigned int	gpio_int;	/* GPIO pin that's
> > connected to INT# */
> >  	bool no_register_reset;
> >  };
> >  
> 
> -- 
> Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Intel Finland Oy

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost
  2017-03-17  9:55 ` [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost Hans de Goede
  2017-03-17 17:33   ` Andy Shevchenko
@ 2017-03-20  4:52   ` Sebastian Reichel
  1 sibling, 0 replies; 46+ messages in thread
From: Sebastian Reichel @ 2017-03-20  4:52 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, MyungJoo Ham, Chanwoo Choi, linux-acpi, Takashi Iwai,
	linux-i2c, linux-kernel, linux-pm

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

Hi,

On Fri, Mar 17, 2017 at 10:55:22AM +0100, Hans de Goede wrote:
> Add support for monitoring an extcon device with SDP/CDP/DCP and HOST
> cables and adjust ilimit and enable/disable the 5v boost converter
> accordingly. This is necessary on systems where the PSEL pin is hardwired
> high and ILIM needs to be set by software based on the detected charger
> type.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Acked-By: Sebastian Reichel <sre@kernel.org>

-- Sebastian

> ---
>  drivers/power/supply/Kconfig           |  1 +
>  drivers/power/supply/bq24190_charger.c | 85 ++++++++++++++++++++++++++++++++++
>  include/linux/power/bq24190_charger.h  |  1 +
>  3 files changed, 87 insertions(+)
> 
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index f8b6e64..fd93110 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -442,6 +442,7 @@ config CHARGER_BQ2415X
>  config CHARGER_BQ24190
>  	tristate "TI BQ24190 battery charger driver"
>  	depends on I2C
> +	depends on EXTCON
>  	depends on GPIOLIB || COMPILE_TEST
>  	help
>  	  Say Y to enable support for the TI BQ24190 battery charger.
> diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
> index 82cb33d..03990e2 100644
> --- a/drivers/power/supply/bq24190_charger.c
> +++ b/drivers/power/supply/bq24190_charger.c
> @@ -11,10 +11,12 @@
>  #include <linux/module.h>
>  #include <linux/interrupt.h>
>  #include <linux/delay.h>
> +#include <linux/extcon.h>
>  #include <linux/of_irq.h>
>  #include <linux/of_device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/power_supply.h>
> +#include <linux/workqueue.h>
>  #include <linux/gpio.h>
>  #include <linux/i2c.h>
>  
> @@ -39,6 +41,8 @@
>  #define BQ24190_REG_POC_WDT_RESET_SHIFT		6
>  #define BQ24190_REG_POC_CHG_CONFIG_MASK		(BIT(5) | BIT(4))
>  #define BQ24190_REG_POC_CHG_CONFIG_SHIFT	4
> +#define BQ24190_REG_POC_CHG_CONFIG_CHARGE	1
> +#define BQ24190_REG_POC_CHG_CONFIG_OTG		2
>  #define BQ24190_REG_POC_SYS_MIN_MASK		(BIT(3) | BIT(2) | BIT(1))
>  #define BQ24190_REG_POC_SYS_MIN_SHIFT		1
>  #define BQ24190_REG_POC_BOOST_LIM_MASK		BIT(0)
> @@ -152,6 +156,9 @@ struct bq24190_dev_info {
>  	struct power_supply		*charger;
>  	struct power_supply		*battery;
>  	struct bq24190_platform_data	*pdata;
> +	struct extcon_dev		*extcon;
> +	struct notifier_block		extcon_nb;
> +	struct work_struct		extcon_work;
>  	char				model_name[I2C_NAME_SIZE];
>  	kernel_ulong_t			model;
>  	struct mutex			f_reg_lock;
> @@ -167,6 +174,11 @@ struct bq24190_dev_info {
>   * number at that index in the array is the real-world value that it
>   * represents.
>   */
> +
> +/* REG00[2:0] (IINLIM) in uAh */
> +static const int bq24190_iinlim_values[] = {
> +	100000, 150000, 500000, 900000, 1200000, 1500000, 2000000, 3000000 };
> +
>  /* REG02[7:2] (ICHG) in uAh */
>  static const int bq24190_ccc_ichg_values[] = {
>  	 512000,  576000,  640000,  704000,  768000,  832000,  896000,  960000,
> @@ -1290,6 +1302,61 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
>  	return IRQ_HANDLED;
>  }
>  
> +static void bq24190_extcon_work(struct work_struct *work)
> +{
> +	struct bq24190_dev_info *bdi =
> +		container_of(work, struct bq24190_dev_info, extcon_work);
> +	int ret, iinlim = 0;
> +
> +	if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_SDP) == 1)
> +		iinlim = 500000;
> +	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_CDP) == 1 ||
> +		 extcon_get_state(bdi->extcon, EXTCON_CHG_USB_ACA) == 1)
> +		iinlim = 1500000;
> +	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_DCP) == 1)
> +		iinlim = 2000000;
> +
> +	if (iinlim) {
> +		ret = bq24190_set_field_val(bdi, BQ24190_REG_ISC,
> +				BQ24190_REG_ISC_IINLIM_MASK,
> +				BQ24190_REG_ISC_IINLIM_SHIFT,
> +				bq24190_iinlim_values,
> +				ARRAY_SIZE(bq24190_iinlim_values),
> +				iinlim);
> +		if (ret)
> +			dev_err(bdi->dev, "Can't set IINLIM: %d\n", ret);
> +	}
> +
> +	/*
> +	 * If no charger has been detected and host mode is requested, activate
> +	 * the 5V boost converter, otherwise deactivate it.
> +	 */
> +	if (!iinlim && extcon_get_state(bdi->extcon, EXTCON_USB_HOST) == 1) {
> +		ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
> +					 BQ24190_REG_POC_CHG_CONFIG_MASK,
> +					 BQ24190_REG_POC_CHG_CONFIG_SHIFT,
> +					 BQ24190_REG_POC_CHG_CONFIG_OTG);
> +	} else {
> +		ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
> +					 BQ24190_REG_POC_CHG_CONFIG_MASK,
> +					 BQ24190_REG_POC_CHG_CONFIG_SHIFT,
> +					 BQ24190_REG_POC_CHG_CONFIG_CHARGE);
> +	}
> +	if (ret)
> +		dev_err(bdi->dev, "Can't set CHG_CONFIG: %d\n", ret);
> +}
> +
> +static int bq24190_extcon_event(struct notifier_block *nb, unsigned long event,
> +				void *param)
> +{
> +	struct bq24190_dev_info *bdi =
> +		container_of(nb, struct bq24190_dev_info, extcon_nb);
> +
> +	schedule_work(&bdi->extcon_work);
> +
> +	return NOTIFY_OK;
> +}
> +
>  static int bq24190_hw_init(struct bq24190_dev_info *bdi)
>  {
>  	u8 v;
> @@ -1375,6 +1442,12 @@ static int bq24190_probe(struct i2c_client *client,
>  			return -EPROBE_DEFER;
>  	}
>  
> +	if (bdi->pdata && bdi->pdata->extcon_name) {
> +		bdi->extcon = extcon_get_extcon_dev(bdi->pdata->extcon_name);
> +		if (!bdi->extcon)
> +			return -EPROBE_DEFER;
> +	}
> +
>  	pm_runtime_enable(dev);
>  	pm_runtime_resume(dev);
>  
> @@ -1423,6 +1496,18 @@ static int bq24190_probe(struct i2c_client *client,
>  		goto out4;
>  	}
>  
> +	if (bdi->extcon) {
> +		INIT_WORK(&bdi->extcon_work, bq24190_extcon_work);
> +		bdi->extcon_nb.notifier_call = bq24190_extcon_event;
> +		ret = devm_extcon_register_notifier(dev, bdi->extcon, -1,
> +						    &bdi->extcon_nb);
> +		if (ret)
> +			goto out4;
> +
> +		/* Sync initial cable state */
> +		schedule_work(&bdi->extcon_work);
> +	}
> +
>  	return 0;
>  
>  out4:
> diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h
> index 02d248b..909c5b9 100644
> --- a/include/linux/power/bq24190_charger.h
> +++ b/include/linux/power/bq24190_charger.h
> @@ -13,6 +13,7 @@
>  
>  struct bq24190_platform_data {
>  	bool no_register_reset;
> +	const char *extcon_name;
>  	int (*get_ext_bat_property)(enum power_supply_property prop,
>  				    union power_supply_propval *val);
>  };
> -- 
> 2.9.3
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge
  2017-03-17  9:55 ` [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge Hans de Goede
  2017-03-17 17:58   ` Andy Shevchenko
@ 2017-03-20  5:07   ` Sebastian Reichel
  1 sibling, 0 replies; 46+ messages in thread
From: Sebastian Reichel @ 2017-03-20  5:07 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, MyungJoo Ham, Chanwoo Choi, linux-acpi, Takashi Iwai,
	linux-i2c, linux-kernel, linux-pm

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

Hi,

On Fri, Mar 17, 2017 at 10:55:26AM +0100, Hans de Goede wrote:
> Add a driver for the Cherry Trail Whiskey Cove PMIC Fuel Gauge, note
> the Cherry Trail Whiskey Cove PMIC Fuel Gauge block is purely a fuel gauge
> and not a full battery controller. As such it offers a platform_data
> callback for extra power_supply properties for the actual external-charger
> ic driver and does not register a power_supply itself.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

I think this should become a normal battery-type power-supply
driver. bq24190_charger driver should only expose a charger-type
power-supply device on your system (and probably most others, its
very rare, that systems have a programmable charger and no
fuel-gauge).

-- Sebastian

> ---
>  drivers/power/supply/Kconfig             |   9 ++
>  drivers/power/supply/Makefile            |   1 +
>  drivers/power/supply/cht_wc_fuel_gauge.c | 209 +++++++++++++++++++++++++++++++
>  include/linux/power/cht_wc_fuel_gauge.h  |  21 ++++
>  4 files changed, 240 insertions(+)
>  create mode 100644 drivers/power/supply/cht_wc_fuel_gauge.c
>  create mode 100644 include/linux/power/cht_wc_fuel_gauge.h
> 
> diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig
> index fd93110..34ebfca 100644
> --- a/drivers/power/supply/Kconfig
> +++ b/drivers/power/supply/Kconfig
> @@ -538,4 +538,13 @@ config AXP20X_POWER
>  	  This driver provides support for the power supply features of
>  	  AXP20x PMIC.
>  
> +config CHT_WC_FUEL_GAUGE
> +	tristate "Intel Cherry Trail Whiskey Cove PMIC Fuel Gauge"
> +	depends on INTEL_SOC_PMIC_CHTWC
> +	help
> +	  This adds support for the battery fuel gauge found in the Intel
> +	  Cherry Trail Whiskey Cove PMIC. This driver allows monitoring
> +	  of the charge level of the battery on Intel Cherry Trail systems
> +	  with a Whiskey Cove PMIC.
> +
>  endif # POWER_SUPPLY
> diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile
> index 3789a2c..702e28a 100644
> --- a/drivers/power/supply/Makefile
> +++ b/drivers/power/supply/Makefile
> @@ -74,3 +74,4 @@ obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
>  obj-$(CONFIG_CHARGER_TPS65217)	+= tps65217_charger.o
>  obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o
>  obj-$(CONFIG_AXP288_CHARGER)	+= axp288_charger.o
> +obj-$(CONFIG_CHT_WC_FUEL_GAUGE)	+= cht_wc_fuel_gauge.o
> diff --git a/drivers/power/supply/cht_wc_fuel_gauge.c b/drivers/power/supply/cht_wc_fuel_gauge.c
> new file mode 100644
> index 0000000..56f6e5a
> --- /dev/null
> +++ b/drivers/power/supply/cht_wc_fuel_gauge.c
> @@ -0,0 +1,209 @@
> +/*
> + * Intel CHT Whiskey Cove Fuel Gauge driver
> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.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 by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * Cherrytrail Whiskey Cove devices have 2 functional blocks which interact
> + * with the battery.
> + *
> + * 1) The fuel-gauge which is build into the Whiskey Cove PMIC, but has its
> + * own i2c bus and i2c client addresses separately from the rest of the PMIC.
> + * That block is what this driver is for.
> + *
> + * 2) An external charger IC, which is connected to the SMBUS controller
> + * which is part of the rest of the Whiskey Cove PMIC, mfd/intel_cht_wc.c
> + * registers a platform device for the SMBUS controller and
> + * i2c/busses/i2c-cht-wc.c contains the i2c-adapter driver for this.
> + *
> + * However we want to present this as a single power_supply device to
> + * userspace. So this driver offers a callback to get the fuel-gauge
> + * power_supply properties, which gets passed to the external charger
> + * driver via i2c_board_info when i2c-cht-wc.c calls i2c_new_device().
> + */
> +
> +#include <linux/acpi.h>
> +#include <linux/delay.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/intel_soc_pmic.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/power_supply.h>
> +#include <linux/power/cht_wc_fuel_gauge.h>
> +#include <linux/slab.h>
> +
> +#define REG_CHARGE_NOW		0x05
> +#define REG_VOLTAGE_NOW		0x09
> +#define REG_CURRENT_NOW		0x0a
> +#define REG_CURRENT_AVG		0x0b
> +#define REG_CHARGE_FULL		0x10
> +#define REG_CHARGE_DESIGN	0x18
> +#define REG_VOLTAGE_AVG		0x19
> +#define REG_VOLTAGE_OCV		0x1b /* Only updated during charging */
> +
> +#define CHT_WC_FG_PTYPE		4
> +
> +struct cht_wc_fg_data {
> +	struct device *dev;
> +	struct i2c_client *client;
> +};
> +
> +static DEFINE_MUTEX(cht_wc_fg_mutex);
> +static struct cht_wc_fg_data *cht_wc_fg;
> +
> +static int cht_wc_fg_read(struct cht_wc_fg_data *fg, u8 reg,
> +			  union power_supply_propval *val, int scale,
> +			  int sign_extend)
> +{
> +	int ret;
> +
> +	ret = i2c_smbus_read_word_data(fg->client, reg);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (sign_extend)
> +		ret = sign_extend32(ret, 15);
> +
> +	val->intval = ret * scale;
> +
> +	return 0;
> +}
> +
> +int cht_wc_fg_get_property(enum power_supply_property prop,
> +			   union power_supply_propval *val)
> +{
> +	int ret = 0;
> +
> +	mutex_lock(&cht_wc_fg_mutex);
> +
> +	if (!cht_wc_fg) {
> +		ret = -ENXIO;
> +		goto out_unlock;
> +	}
> +
> +	switch (prop) {
> +	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_VOLTAGE_NOW, val, 75, 0);
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_VOLTAGE_AVG, val, 75, 0);
> +		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_VOLTAGE_OCV, val, 75, 0);
> +		break;
> +	case POWER_SUPPLY_PROP_CURRENT_NOW:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_CURRENT_NOW, val, 150, 1);
> +		break;
> +	case POWER_SUPPLY_PROP_CURRENT_AVG:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_CURRENT_AVG, val, 150, 1);
> +		break;
> +	case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_CHARGE_DESIGN, val, 500, 0);
> +		break;
> +	case POWER_SUPPLY_PROP_CHARGE_FULL:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_CHARGE_FULL, val, 500, 0);
> +		break;
> +	case POWER_SUPPLY_PROP_CHARGE_NOW:
> +		ret = cht_wc_fg_read(cht_wc_fg, REG_CHARGE_NOW, val, 500, 0);
> +		break;
> +	default:
> +		ret = -ENODATA;
> +	}
> +out_unlock:
> +	mutex_unlock(&cht_wc_fg_mutex);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(cht_wc_fg_get_property);
> +
> +static int cht_wc_fg_probe(struct i2c_client *client,
> +			const struct i2c_device_id *i2c_id)
> +{
> +	struct device *dev = &client->dev;
> +	struct cht_wc_fg_data *fg;
> +	acpi_status status;
> +	unsigned long long ptyp;
> +
> +	fg = devm_kzalloc(dev, sizeof(*fg), GFP_KERNEL);
> +	if (!fg)
> +		return -ENOMEM;
> +
> +	status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
> +	if (ACPI_FAILURE(status)) {
> +		dev_err(dev, "Failed to get PTYPE\n");
> +		return -ENODEV;
> +	}
> +
> +	/*
> +	 * The same ACPI HID is used with different PMICs check PTYP to
> +	 * ensure that we are dealing with a Whiskey Cove PMIC.
> +	 */
> +	if (ptyp != CHT_WC_FG_PTYPE)
> +		return -ENODEV;
> +
> +	fg->dev = dev;
> +	/*
> +	 * The current resource settings table for the fuel gauge contains
> +	 * multiple i2c devices on 2 different i2c-busses. The one we actually
> +	 * want is the second resource (index 1).
> +	 */
> +	fg->client = i2c_acpi_new_device(dev, 1);
> +	if (!fg->client)
> +		return -EPROBE_DEFER;
> +
> +	i2c_set_clientdata(client, fg);
> +
> +	mutex_lock(&cht_wc_fg_mutex);
> +	cht_wc_fg = fg;
> +	mutex_unlock(&cht_wc_fg_mutex);
> +
> +	return 0;
> +}
> +
> +static int cht_wc_fg_remove(struct i2c_client *i2c)
> +{
> +	struct cht_wc_fg_data *fg = i2c_get_clientdata(i2c);
> +
> +	mutex_lock(&cht_wc_fg_mutex);
> +	cht_wc_fg = NULL;
> +	mutex_unlock(&cht_wc_fg_mutex);
> +
> +	i2c_unregister_device(fg->client);
> +
> +	return 0;
> +}
> +
> +static const struct i2c_device_id cht_wc_fg_i2c_id[] = {
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(i2c, cht_wc_fg_i2c_id);
> +
> +static const struct acpi_device_id cht_wc_fg_acpi_ids[] = {
> +	{ "INT33FE", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(acpi, cht_wc_fg_acpi_ids);
> +
> +static struct i2c_driver cht_wc_fg_driver = {
> +	.driver	= {
> +		.name	= "CHT Whiskey Cove PMIC Fuel Gauge",
> +		.acpi_match_table = ACPI_PTR(cht_wc_fg_acpi_ids),
> +	},
> +	.probe = cht_wc_fg_probe,
> +	.remove = cht_wc_fg_remove,
> +	.id_table = cht_wc_fg_i2c_id,
> +	.irq_index = 1,
> +};
> +
> +module_i2c_driver(cht_wc_fg_driver);
> +
> +MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC Fuel Gauge driver");
> +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/power/cht_wc_fuel_gauge.h b/include/linux/power/cht_wc_fuel_gauge.h
> new file mode 100644
> index 0000000..4b4e051
> --- /dev/null
> +++ b/include/linux/power/cht_wc_fuel_gauge.h
> @@ -0,0 +1,21 @@
> +/*
> + * Intel CHT Whiskey Cove Fuel Gauge driver
> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.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 by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __CHT_WC_FUEL_GAUGE_H
> +#define __CHT_WC_FUEL_GAUGE_H
> +
> +int cht_wc_fg_get_property(enum power_supply_property prop,
> +			   union power_supply_propval *val);
> +
> +#endif
> -- 
> 2.9.3
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH 09/15] power: supply: bq24190_charger: Add voltage_max_design prop to battery
  2017-03-17  9:55 ` [PATCH 09/15] power: supply: bq24190_charger: Add voltage_max_design prop to battery Hans de Goede
@ 2017-03-20  5:12   ` Sebastian Reichel
  0 siblings, 0 replies; 46+ messages in thread
From: Sebastian Reichel @ 2017-03-20  5:12 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Rafael J . Wysocki, Len Brown, Wolfram Sang, Andy Shevchenko,
	Lee Jones, MyungJoo Ham, Chanwoo Choi, linux-acpi, Takashi Iwai,
	linux-i2c, linux-kernel, linux-pm

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

Hi,

On Fri, Mar 17, 2017 at 10:55:21AM +0100, Hans de Goede wrote:
> When combined with an external fuel-gauge, upower needs voltage_max_design
> as it internally does all its calculations in Watts and converts the
> charge_foo properties from A to Watts by using voltage_max_design.
> 
> Signed-off-by: Hans de Goede <hdegoede@redhat.com>

Assuming, that my comment on patch 14 works POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN
is required in the fuel-gauge driver instead. As far as I understand
it the charger voltage was too high for your device anyways, so that
you capped it at 4.3V. So I assume, that you can just provide it via
device properties.

-- Sebastian

>  drivers/power/supply/bq24190_charger.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c
> index 9fe69a5..82cb33d 100644
> --- a/drivers/power/supply/bq24190_charger.c
> +++ b/drivers/power/supply/bq24190_charger.c
> @@ -1103,6 +1103,13 @@ static int bq24190_battery_get_property(struct power_supply *psy,
>  		val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
>  		ret = 0;
>  		break;
> +	case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
> +		/*
> +		 * Report charger configured voltage as max design voltage,
> +		 * not entirely correct, but userspace needs something here.
> +		 */
> +		ret = bq24190_charger_get_voltage(bdi, val);
> +		break;
>  	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
>  		ret = bq24190_battery_get_temp_alert_max(bdi, val);
>  		break;
> @@ -1169,6 +1176,7 @@ static enum power_supply_property bq24190_battery_properties[] = {
>  	POWER_SUPPLY_PROP_HEALTH,
>  	POWER_SUPPLY_PROP_ONLINE,
>  	POWER_SUPPLY_PROP_TECHNOLOGY,
> +	POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
>  	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
>  	POWER_SUPPLY_PROP_SCOPE,
>  	/* Begin of extended battery properties */
> @@ -1186,7 +1194,7 @@ static const struct power_supply_desc bq24190_battery_desc = {
>  	.name			= "bq24190-battery",
>  	.type			= POWER_SUPPLY_TYPE_BATTERY,
>  	.properties		= bq24190_battery_properties,
> -	.num_properties		= 6,
> +	.num_properties		= 7,
>  	.get_property		= bq24190_battery_get_property,
>  	.set_property		= bq24190_battery_set_property,
>  	.property_is_writeable	= bq24190_battery_property_is_writeable,
> -- 
> 2.9.3
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

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

* Re: [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI
  2017-03-17  9:55 ` [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI Hans de Goede
  2017-03-17 17:41   ` Andy Shevchenko
@ 2017-03-20  8:55   ` kbuild test robot
  1 sibling, 0 replies; 46+ messages in thread
From: kbuild test robot @ 2017-03-20  8:55 UTC (permalink / raw)
  To: Hans de Goede
  Cc: kbuild-all, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Andy Shevchenko, Lee Jones, Sebastian Reichel, MyungJoo Ham,
	Chanwoo Choi, Hans de Goede, linux-acpi, Takashi Iwai, linux-i2c,
	linux-kernel, linux-pm

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

Hi Hans,

[auto build test WARNING on wsa/i2c/for-next]
[also build test WARNING on v4.11-rc3 next-20170310]
[cannot apply to battery/master]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Hans-de-Goede/Add-Intel-Cherry-Trail-Whiskey-Cove-PMIC-support/20170320-144648
base:   https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-next
reproduce: make htmldocs

All warnings (new ones prefixed by >>):

   include/linux/init.h:1: warning: no structured comments found
   kernel/sched/core.c:2085: warning: No description found for parameter 'rf'
   kernel/sched/core.c:2085: warning: Excess function parameter 'cookie' description in 'try_to_wake_up_local'
   include/linux/kthread.h:26: warning: Excess function parameter '...' description in 'kthread_create'
   kernel/sys.c:1: warning: no structured comments found
   include/linux/device.h:969: warning: No description found for parameter 'dma_ops'
   drivers/dma-buf/seqno-fence.c:1: warning: no structured comments found
>> include/linux/i2c.h:219: warning: No description found for parameter 'irq_index'
   include/linux/iio/iio.h:597: warning: No description found for parameter 'trig_readonly'
   include/linux/iio/trigger.h:151: warning: No description found for parameter 'indio_dev'
   include/linux/iio/trigger.h:151: warning: No description found for parameter 'trig'
   include/linux/device.h:970: warning: No description found for parameter 'dma_ops'
   drivers/regulator/core.c:1467: warning: Excess function parameter 'ret' description in 'regulator_dev_lookup'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'open'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'preclose'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'postclose'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'lastclose'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'set_busid'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'irq_handler'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'irq_preinstall'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'irq_postinstall'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'irq_uninstall'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'debugfs_init'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'debugfs_cleanup'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_open_object'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_close_object'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'prime_handle_to_fd'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'prime_fd_to_handle'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_export'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_import'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_pin'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_unpin'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_res_obj'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_get_sg_table'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_import_sg_table'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_vmap'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_vunmap'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_prime_mmap'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'gem_vm_ops'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'major'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'minor'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'patchlevel'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'name'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'desc'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'date'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'driver_features'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'ioctls'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'num_ioctls'
   include/drm/drm_drv.h:438: warning: No description found for parameter 'fops'
   include/drm/drm_color_mgmt.h:1: warning: no structured comments found
   drivers/gpu/drm/drm_fb_cma_helper.c:557: warning: Excess function parameter 'num_crtc' description in 'drm_fbdev_cma_init'
   drivers/gpu/drm/drm_fb_cma_helper.c:558: warning: Excess function parameter 'num_crtc' description in 'drm_fbdev_cma_init'
   drivers/gpu/drm/i915/intel_lpe_audio.c:342: warning: No description found for parameter 'pipe'
   drivers/gpu/drm/i915/intel_lpe_audio.c:342: warning: No description found for parameter 'dp_output'
   drivers/gpu/drm/i915/intel_lpe_audio.c:342: warning: No description found for parameter 'link_rate'
   drivers/gpu/drm/i915/intel_lpe_audio.c:343: warning: No description found for parameter 'pipe'
   drivers/gpu/drm/i915/intel_lpe_audio.c:343: warning: No description found for parameter 'dp_output'
   drivers/gpu/drm/i915/intel_lpe_audio.c:343: warning: No description found for parameter 'link_rate'
   drivers/media/dvb-core/dvb_frontend.h:677: warning: No description found for parameter 'refcount'
   Documentation/core-api/assoc_array.rst:13: WARNING: Enumerated list ends without a blank line; unexpected unindent.
   Documentation/doc-guide/sphinx.rst:110: ERROR: Unknown target name: "sphinx c domain".
   kernel/sched/fair.c:7616: WARNING: Inline emphasis start-string without end-string.
   kernel/time/timer.c:1200: ERROR: Unexpected indentation.
   kernel/time/timer.c:1202: ERROR: Unexpected indentation.
   kernel/time/timer.c:1203: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/linux/wait.h:122: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/linux/wait.h:125: ERROR: Unexpected indentation.
   include/linux/wait.h:127: WARNING: Block quote ends without a blank line; unexpected unindent.
   kernel/time/hrtimer.c:990: WARNING: Block quote ends without a blank line; unexpected unindent.
   kernel/signal.c:322: WARNING: Inline literal start-string without end-string.
   include/linux/iio/iio.h:219: ERROR: Unexpected indentation.
   include/linux/iio/iio.h:220: WARNING: Block quote ends without a blank line; unexpected unindent.
   include/linux/iio/iio.h:226: WARNING: Definition list ends without a blank line; unexpected unindent.
   drivers/iio/industrialio-core.c:639: ERROR: Unknown target name: "iio_val".
   drivers/iio/industrialio-core.c:646: ERROR: Unknown target name: "iio_val".
   drivers/message/fusion/mptbase.c:5051: WARNING: Definition list ends without a blank line; unexpected unindent.
   drivers/tty/serial/serial_core.c:1898: WARNING: Definition list ends without a blank line; unexpected unindent.
   include/linux/regulator/driver.h:271: ERROR: Unknown target name: "regulator_regmap_x_voltage".
   include/linux/spi/spi.h:369: ERROR: Unexpected indentation.
   drivers/usb/core/message.c:478: ERROR: Unexpected indentation.
   drivers/usb/core/message.c:479: WARNING: Block quote ends without a blank line; unexpected unindent.
   Documentation/driver-api/usb.rst:623: ERROR: Unknown target name: "usb_type".
   Documentation/driver-api/usb.rst:623: ERROR: Unknown target name: "usb_dir".
   Documentation/driver-api/usb.rst:623: ERROR: Unknown target name: "usb_recip".
   Documentation/driver-api/usb.rst:689: ERROR: Unknown target name: "usbdevfs_urb_type".
   sound/soc/soc-core.c:2670: ERROR: Unknown target name: "snd_soc_daifmt".
   sound/core/jack.c:312: ERROR: Unknown target name: "snd_jack_btn".
   WARNING: dvipng command 'dvipng' cannot be run (needed for math display), check the imgmath_dvipng setting

vim +/irq_index +219 include/linux/i2c.h

^1da177e Linus Torvalds 2005-04-16  203  	/* a ioctl like command that can be used to perform specific functions
^1da177e Linus Torvalds 2005-04-16  204  	 * with the device.
^1da177e Linus Torvalds 2005-04-16  205  	 */
^1da177e Linus Torvalds 2005-04-16  206  	int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
^1da177e Linus Torvalds 2005-04-16  207  
^1da177e Linus Torvalds 2005-04-16  208  	struct device_driver driver;
d2653e92 Jean Delvare   2008-04-29  209  	const struct i2c_device_id *id_table;
4735c98f Jean Delvare   2008-07-14  210  
4735c98f Jean Delvare   2008-07-14  211  	/* Device detection callback for automatic device creation */
310ec792 Jean Delvare   2009-12-14  212  	int (*detect)(struct i2c_client *, struct i2c_board_info *);
c3813d6a Jean Delvare   2009-12-14  213  	const unsigned short *address_list;
4735c98f Jean Delvare   2008-07-14  214  	struct list_head clients;
f55c71b4 Hans de Goede  2017-03-17  215  
f55c71b4 Hans de Goede  2017-03-17  216  	/* IRQ index for retreiving irq from ACPI resources */
f55c71b4 Hans de Goede  2017-03-17  217  	int irq_index;
^1da177e Linus Torvalds 2005-04-16  218  };
^1da177e Linus Torvalds 2005-04-16 @219  #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
^1da177e Linus Torvalds 2005-04-16  220  
2096b956 David Brownell 2007-05-01  221  /**
2096b956 David Brownell 2007-05-01  222   * struct i2c_client - represent an I2C slave device
d64f73be David Brownell 2007-07-12  223   * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
d64f73be David Brownell 2007-07-12  224   *	I2C_CLIENT_PEC indicates it uses SMBus Packet Error Checking
2096b956 David Brownell 2007-05-01  225   * @addr: Address used on the I2C bus connected to the parent adapter.
2096b956 David Brownell 2007-05-01  226   * @name: Indicates the type of the device, usually a chip name that's
2096b956 David Brownell 2007-05-01  227   *	generic enough to hide second-sourcing and compatible revisions.

:::::: The code at line 219 was first introduced by commit
:::::: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 Linux-2.6.12-rc2

:::::: TO: Linus Torvalds <torvalds@ppc970.osdl.org>
:::::: CC: Linus Torvalds <torvalds@ppc970.osdl.org>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 6576 bytes --]

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

* Re: [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-03-17 17:00   ` Andy Shevchenko
@ 2017-03-20 10:41     ` Lee Jones
  2017-03-20 12:55       ` Andy Shevchenko
  0 siblings, 1 reply; 46+ messages in thread
From: Lee Jones @ 2017-03-20 10:41 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Sebastian Reichel, MyungJoo Ham, Chanwoo Choi, linux-acpi,
	Takashi Iwai, linux-i2c, linux-kernel, linux-pm, Bin Gao,
	Felipe Balbi

On Fri, 17 Mar 2017, Andy Shevchenko wrote:

> On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
> > Add mfd driver for Intel CHT Whiskey Cove PMIC, based on various non
> > upstreamed CHT Whiskey Cove PMIC patches.
> > 
> > This is a somewhat minimal version which adds irqchip support and
> > cells
> > for: ACPI PMIC opregion support, the i2c-controller driving the
> > external
> > charger irc and the pwrsrc/extcon block.
> > 
> > Further cells can be added in the future if/when drivers are
> > upstreamed
> > for them.
> 
> Couple of minor comments, otherwise looks good to me:
> 
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> 
> > +/* Whiskey Cove PMIC share same ACPI ID between different platforms
> > */
> > +#define CHT_WC_HRV		3
> > +
> > +/* Level 1 IRQs (level 2 IRQs are handled in the child device
> > drivers) */
> > +enum {
> > +	CHT_WC_PWRSRC_IRQ = 0,
> > +	CHT_WC_THRM_IRQ,
> > +	CHT_WC_BCU_IRQ,
> > +	CHT_WC_ADC_IRQ,
> > +	CHT_WC_EXT_CHGR_IRQ,
> > +	CHT_WC_GPIO_IRQ,
> > +	/* There is no irq 6 */
> > +	CHT_WC_CRIT_IRQ = 7,
> 
> I would prefer explicit over implicit (adding = N to each line), but
> this is minor.

No need.  The C standard is clear on what is expected of enums.

[...]

> > +	return devm_mfd_add_devices(dev, -1, cht_wc_dev,
> > ARRAY_SIZE(cht_wc_dev),
> > +			NULL, 0, regmap_irq_get_domain(pmic-
> > >irq_chip_data));
> 
> PLATFORM_DEVID_NONE, please.

+1

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

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

* Re: [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-03-20 10:41     ` Lee Jones
@ 2017-03-20 12:55       ` Andy Shevchenko
  0 siblings, 0 replies; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-20 12:55 UTC (permalink / raw)
  To: Lee Jones
  Cc: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Sebastian Reichel, MyungJoo Ham, Chanwoo Choi, linux-acpi,
	Takashi Iwai, linux-i2c, linux-kernel, linux-pm, Bin Gao,
	Felipe Balbi

On Mon, 2017-03-20 at 10:41 +0000, Lee Jones wrote:
> On Fri, 17 Mar 2017, Andy Shevchenko wrote:
> > On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:

> > > +enum {
> > > +	CHT_WC_PWRSRC_IRQ = 0,
> > > +	CHT_WC_THRM_IRQ,
> > > +	CHT_WC_BCU_IRQ,
> > > +	CHT_WC_ADC_IRQ,
> > > +	CHT_WC_EXT_CHGR_IRQ,
> > > +	CHT_WC_GPIO_IRQ,
> > > +	/* There is no irq 6 */
> > > +	CHT_WC_CRIT_IRQ = 7,
> > 
> > I would prefer explicit over implicit (adding = N to each line), but
> > this is minor.
> 
> No need.  The C standard is clear on what is expected of enums.

I understand that, though I don't like gaps in enums. That's why I
prefer in such cases pure #define over enum (yes, I understand that enum
in many cases is better).

But this all matter of taste. So, I will not insist if it would be left
as it is now.

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-20  1:33   ` Chanwoo Choi
@ 2017-03-20 13:00     ` Andy Shevchenko
  2017-03-21  3:54       ` Chanwoo Choi
  2017-03-20 19:57     ` Hans de Goede
  1 sibling, 1 reply; 46+ messages in thread
From: Andy Shevchenko @ 2017-03-20 13:00 UTC (permalink / raw)
  To: Chanwoo Choi, Hans de Goede, Rafael J . Wysocki, Len Brown,
	Wolfram Sang, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On Mon, 2017-03-20 at 10:33 +0900, Chanwoo Choi wrote:
> On 2017년 03월 17일 18:55, Hans de Goede wrote:

> > +static const struct platform_device_id cht_wc_extcon_table[] = {
> > +	{ .name = "cht_wcove_pwrsrc" },
> 
> You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
> So, To maintain the consistency, you better to use the 'cht-wc' as the
> name.
> - I prefer to use '-' instead of '_' in the name.
> 	.name ="cht-wc"

I would keep as Hans did for the sake of consistency among all Whiskey
Cove device drivers (and predecessors like Crystal Cove).

I understand your point from extcon subsystem view, but PMICs like
Whiskey Cove are multi-functional devices, and thus naming across them
(same prefix in use to be precise) is better idea.

> 
> > +	{},
> > +};
> > +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);

-- 
Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Intel Finland Oy

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-17 17:18   ` Andy Shevchenko
@ 2017-03-20 18:08     ` Hans de Goede
  0 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-20 18:08 UTC (permalink / raw)
  To: Andy Shevchenko, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm,
	Felipe Balbi

Hi,

On 17-03-17 18:18, Andy Shevchenko wrote:
> On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
>> Add a driver for charger detection / control on the Intel Cherrytrail
>> Whiskey Cove PMIC.
>
> +Cc: Felipe for some question(s) below.
>
>>  drivers/extcon/extcon-cht-wc.c | 356
>
> I would use same pattern across drivers, i.e. "chtwc" (same for the rest
> of the drivers in this series).

I already answered this in another part of the thread,
but for the archives sake let me copy and paste my answer:

"One thing I disagree with is the cht_wc > chtwc rename you are
proposing for one Cherry Trail and Whiskey Cove are 2 different
words (4 if you look at spelling but 2 if you look at pronunciation,
so IMHO cht_wc is more readable other then that I see the suggested
rename as a lot of extra churn without any tangible benefits."

>
>> +#define CHT_WC_PWRSRC_IRQ		0x6e03
>> +#define CHT_WC_PWRSRC_IRQ_MASK		0x6e0f
>> +#define CHT_WC_PWRSRC_STS		0x6e1e
>> +#define CHT_WC_PWRSRC_VBUS		BIT(0)
>> +#define CHT_WC_PWRSRC_DC		BIT(1)
>> +#define CHT_WC_PWRSRC_BAT		BIT(2)
>> +#define CHT_WC_PWRSRC_ID_GND		BIT(3)
>> +#define CHT_WC_PWRSRC_ID_FLOAT		BIT(4)
>
> Not obvious for which register those bit definitions are.

They are for all 3 CHT_WC_PWRSRC_* registers, this is the
more or less usual irq setup for some i2c devices where
there is a status register, an irq register where the hardware
sets bits to 1 (and we write 1 to clear) when the corresponding
status bits changes and a mask register to select which irq
register bits actually will raise the interrupt line.

> Also, keep them ordered by offset.

Will fix.

>
>> +
>> +#define CHT_WC_PHYCTRL			0x5e07
>> +
>
>> +#define CHT_WC_CHGRCTRL0		0x5e16
>
> Dup!

Good catch, will fix.


>
>> +
>> +#define CHT_WC_CHGRCTRL0		0x5e16
>
>> +static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext)
>> +{
>> +	int ret, usbsrc, status, retries = 5;
>> +
>> +	do {
>> +		ret = regmap_read(ext->regmap, CHT_WC_USBSRC,
>> &usbsrc);
>> +		if (ret) {
>> +			dev_err(ext->dev, "Error reading usbsrc:
>> %d\n", ret);
>> +			return ret;
>> +		}
>> +		status = usbsrc & CHT_WC_USBSRC_STS_MASK;
>> +		if (status == CHT_WC_USBSRC_STS_SUCCESS ||
>> +		    status == CHT_WC_USBSRC_STS_FAIL)
>> +			break;
>> +
>
>> +		msleep(200);
>
> Comment why and why so long?

Fixed for v2 (actually switched to using jiffies +
time_before for a more accurate timeout).

>> +	} while (retries--);
>
>> +static void cht_wc_extcon_det_event(struct cht_wc_extcon_data *ext)
>
> det -> detect ?

Renamed to more accurate cht_wc_extcon_pwrsrc_event

> +static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
>> +{
>> +	struct cht_wc_extcon_data *ext = data;
>> +	int ret, irqs;
>> +
>> +	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
>> +	if (ret)
>> +		dev_err(ext->dev, "Error reading irqs: %d\n", ret);
>
> Shouldn't we return IRQ_NONE here?

I was wondering the same myself here, there is no good
answer here, this should simply never fail ... which does
make returning IRQ_NONE a good idea, I was worried that
would lead to a "nobody cared, disabling irq", but as said this
should never happen, so when it does, disabling the irq is
probably for the best. Will fix.

>
>> +
>> +	cht_wc_extcon_det_event(ext);
>> +
>> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
>> +	if (ret)
>> +		dev_err(ext->dev, "Error writing irqs: %d\n", ret);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>
>> +/* usb_id sysfs attribute for debug / testing purposes */
>
> Hmm... I would use debugfs for debug, otherwise it looks like it should
> be framework (extcon) wide.

Unfortunately these kinda sysfs files are somewhat normal when
dealing with USB-OTG. For example my board does not have the
id-pin hooked up to the connector, so to test host mode
I need to echo "gnd" to the sysfs attr. But also if I actually
want to use host-mode (or anyone else with the same or a similar
board).

This definitely is not something which belongs in the extcon-core.

> Perhaps Felipe can advise something here.
>
>> +static int cht_wc_extcon_probe(struct platform_device *pdev)
>> +{
>
>> +	struct cht_wc_extcon_data *ext;
>> +	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev-
>>> dev.parent);
>
> Exchange them (assignment first).

Fixed.

>
>> +	int irq, ret;
>> +
>
>
>> +	ret = devm_request_threaded_irq(ext->dev, irq, NULL,
>> cht_wc_extcon_isr,
>> +					IRQF_ONESHOT, pdev->name,
>> ext);
>> +	if (ret) {
>> +		dev_err(ext->dev, "Failed to request interrupt\n");
>> +		return ret;
>> +	}
>> +
>> +	/* Unmask irqs */
>> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
>> +			   (int)~(CHT_WC_PWRSRC_VBUS |
>
> Hmm... Do you need explicit casting here?

Yes because the BIT(x) macros are unsigned longs and the ~ sets
the MSB so then the compiler complaints about truncating the
variable without the cast.

>
>> CHT_WC_PWRSRC_ID_GND |
>> +				  CHT_WC_PWRSRC_ID_FLOAT));
>> +	if (ret) {
>> +		dev_err(ext->dev, "Error writing irq-mask: %d\n",
>> ret);
>> +		return ret;
>> +	}
>

Regards,

Hans

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-20  1:33   ` Chanwoo Choi
  2017-03-20 13:00     ` Andy Shevchenko
@ 2017-03-20 19:57     ` Hans de Goede
  2017-03-21  5:16       ` Chanwoo Choi
  1 sibling, 1 reply; 46+ messages in thread
From: Hans de Goede @ 2017-03-20 19:57 UTC (permalink / raw)
  To: Chanwoo Choi, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Andy Shevchenko, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 20-03-17 02:33, Chanwoo Choi wrote:
> Hi,
>
> On 2017년 03월 17일 18:55, Hans de Goede wrote:
>> Add a driver for charger detection / control on the Intel Cherrytrail
>> Whiskey Cove PMIC.
>>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>>  drivers/extcon/Kconfig         |   7 +
>>  drivers/extcon/Makefile        |   1 +
>>  drivers/extcon/extcon-cht-wc.c | 356 +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 364 insertions(+)
>>  create mode 100644 drivers/extcon/extcon-cht-wc.c
>>
>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>> index 96bbae5..4cace6b 100644
>> --- a/drivers/extcon/Kconfig
>> +++ b/drivers/extcon/Kconfig
>> @@ -52,6 +52,13 @@ config EXTCON_INTEL_INT3496
>>  	  This ACPI device is typically found on Intel Baytrail or Cherrytrail
>>  	  based tablets, or other Baytrail / Cherrytrail devices.
>>
>> +config EXTCON_CHT_WC
>
> Need to reorder it alpabetically as the following Makefile.

The idea is to have the items alphabetically listed in "make menuconfig"
and the name of the menu item starts with Intel:

>
>> +	tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver"
>> +	depends on INTEL_SOC_PMIC_CHTWC
>> +	help
>> +	  Say Y here to enable extcon support for charger detection / control
>> +	  on the Intel Cherrytrail Whiskey Cove PMIC.
>> +
>>  config EXTCON_MAX14577
>>  	tristate "Maxim MAX14577/77836 EXTCON Support"
>>  	depends on MFD_MAX14577
>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>> index 237ac3f..160f88b 100644
>> --- a/drivers/extcon/Makefile
>> +++ b/drivers/extcon/Makefile
>> @@ -7,6 +7,7 @@ extcon-core-objs		+= extcon.o devres.o
>>  obj-$(CONFIG_EXTCON_ADC_JACK)	+= extcon-adc-jack.o
>>  obj-$(CONFIG_EXTCON_ARIZONA)	+= extcon-arizona.o
>>  obj-$(CONFIG_EXTCON_AXP288)	+= extcon-axp288.o
>> +obj-$(CONFIG_EXTCON_CHT_WC)	+= extcon-cht-wc.o
>>  obj-$(CONFIG_EXTCON_GPIO)	+= extcon-gpio.o
>>  obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
>>  obj-$(CONFIG_EXTCON_MAX14577)	+= extcon-max14577.o
>> diff --git a/drivers/extcon/extcon-cht-wc.c b/drivers/extcon/extcon-cht-wc.c
>> new file mode 100644
>> index 0000000..896eee6
>> --- /dev/null
>> +++ b/drivers/extcon/extcon-cht-wc.c
>> @@ -0,0 +1,356 @@
>> +/*
>> + * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
>> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
>> + *
>> + * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
>
> Maybe, you don't need to add ':' at the end of line.

Th ':' is there because the following copyright line:
>
>> + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.

Comes from those various non upstream patches.

>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms and conditions of the GNU General Public License,
>> + * version 2, as published by the Free Software Foundation.
>> + *
>> + * This program is distributed in the hope it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>> + * more details.
>> + */
>> +
>> +#include <linux/extcon.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/intel_soc_pmic.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +#include <linux/slab.h>
>> +
>> +#define CHT_WC_PWRSRC_IRQ		0x6e03
>> +#define CHT_WC_PWRSRC_IRQ_MASK		0x6e0f
>> +#define CHT_WC_PWRSRC_STS		0x6e1e
>> +#define CHT_WC_PWRSRC_VBUS		BIT(0)
>> +#define CHT_WC_PWRSRC_DC		BIT(1)
>> +#define CHT_WC_PWRSRC_BAT		BIT(2)
>> +#define CHT_WC_PWRSRC_ID_GND		BIT(3)
>> +#define CHT_WC_PWRSRC_ID_FLOAT		BIT(4)
>> +
>> +#define CHT_WC_PHYCTRL			0x5e07
>> +
>> +#define CHT_WC_CHGRCTRL0		0x5e16
>> +
>> +#define CHT_WC_CHGRCTRL0		0x5e16
>> +#define CHT_WC_CHGRCTRL0_CHGRRESET	BIT(0)
>> +#define CHT_WC_CHGRCTRL0_EMRGCHREN	BIT(1)
>> +#define CHT_WC_CHGRCTRL0_EXTCHRDIS	BIT(2)
>> +#define CHT_WC_CHGRCTRL0_SWCONTROL	BIT(3)
>> +#define CHT_WC_CHGRCTRL0_TTLCK_MASK	BIT(4)
>> +#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK	BIT(5)
>> +#define CHT_WC_CHGRCTRL0_DBPOFF_MASK	BIT(6)
>> +#define CHT_WC_CHGRCTRL0_WDT_NOKICK	BIT(7)
>> +
>> +#define CHT_WC_CHGRCTRL1		0x5e17
>> +
>> +#define CHT_WC_USBSRC			0x5e29
>> +#define CHT_WC_USBSRC_STS_MASK		GENMASK(1, 0)
>> +#define CHT_WC_USBSRC_STS_SUCCESS	2
>> +#define CHT_WC_USBSRC_STS_FAIL		3
>> +#define CHT_WC_USBSRC_TYPE_SHIFT	2
>> +#define CHT_WC_USBSRC_TYPE_MASK		GENMASK(5, 2)
>> +#define CHT_WC_USBSRC_TYPE_NONE		0
>> +#define CHT_WC_USBSRC_TYPE_SDP		1
>> +#define CHT_WC_USBSRC_TYPE_DCP		2
>> +#define CHT_WC_USBSRC_TYPE_CDP		3
>> +#define CHT_WC_USBSRC_TYPE_ACA		4
>> +#define CHT_WC_USBSRC_TYPE_SE1		5
>> +#define CHT_WC_USBSRC_TYPE_MHL		6
>> +#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN	7
>> +#define CHT_WC_USBSRC_TYPE_OTHER	8
>> +#define CHT_WC_USBSRC_TYPE_DCP_EXTPHY	9
>> +
>> +enum cht_wc_usb_id {
>> +	USB_ID_OTG,
>> +	USB_ID_GND,
>> +	USB_ID_FLOAT,
>> +	USB_RID_A,
>> +	USB_RID_B,
>> +	USB_RID_C,
>> +};
>> +
>> +/* Strings matching the cht_wc_usb_id enum labels */
>> +static const char * const usb_id_str[] = {
>> +	"otg", "gnd", "float", "rid_a", "rid_b", "rid_c" };
>> +
>> +enum cht_wc_mux_select {
>> +	MUX_SEL_PMIC = 0,
>> +	MUX_SEL_SOC,
>> +};
>> +
>> +static const unsigned int cht_wc_extcon_cables[] = {
>> +	EXTCON_USB,
>> +	EXTCON_USB_HOST,
>> +	EXTCON_CHG_USB_SDP,
>> +	EXTCON_CHG_USB_CDP,
>> +	EXTCON_CHG_USB_DCP,
>> +	EXTCON_NONE,
>> +};
>> +
>> +struct cht_wc_extcon_data {
>> +	struct device *dev;
>> +	struct regmap *regmap;
>> +	struct extcon_dev *edev;
>> +	unsigned int previous_cable;
>> +	int usb_id;
>> +};
>> +
>> +static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
>> +{
>> +	if (ext->usb_id)
>> +		return ext->usb_id;
>> +
>> +	if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
>> +		return USB_ID_GND;
>> +	if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
>> +		return USB_ID_FLOAT;
>> +
>> +	/*
>> +	 * Once we have iio support for the gpadc we should read the USBID
>> +	 * gpadc channel here and determine ACA role based on that.
>> +	 */
>> +	return USB_ID_FLOAT;
>> +}
>> +
>> +static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext)
>> +{
>> +	int ret, usbsrc, status, retries = 5;
>
> You have to define the constant for '5' because the name of constant
> definition indicates what is meaning. So, maybe you will use the 'for' loope
> instead of 'do..while'.

Right, already fixed as a result of Andy's review.

>
>> +
>> +	do {
>> +		ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc);
>> +		if (ret) {
>> +			dev_err(ext->dev, "Error reading usbsrc: %d\n", ret);
>> +			return ret;
>> +		}
>
> Need to add one blank line.
>
>> +		status = usbsrc & CHT_WC_USBSRC_STS_MASK;
>> +		if (status == CHT_WC_USBSRC_STS_SUCCESS ||
>> +		    status == CHT_WC_USBSRC_STS_FAIL)
>> +			break;
>> +
>> +		msleep(200);
>
> You have to define the constant for '200' because the name of constant
> definition indicates what is meaning.
>
>> +	} while (retries--);
>> +
>> +	if (status != CHT_WC_USBSRC_STS_SUCCESS) {
>> +		if (status == CHT_WC_USBSRC_STS_FAIL)
>> +			dev_warn(ext->dev, "Could not detect charger type\n");
>> +		else
>> +			dev_warn(ext->dev, "Timeout detecting charger type\n");
>> +		return EXTCON_CHG_USB_SDP; /* Save fallback */
>> +	}
>> +
>> +	ret = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;
>
> 'ret' is not proper indicates the meaning of 'CHT_WC_USBSRC_TYPE'.
> You have to use the more correct local variable such as 'usbsrc_type'.

Fixed for v2.
>
>> +	switch (ret) {
>> +	default:
>> +		dev_warn(ext->dev, "Unhandled charger type %d\n", ret);
>> +		/* Fall through treat as SDP */
>
> Is it right? Why do you located the 'default' on the top in the switch?

So that I can use fall-through, there is no rule in C where the default goes.

The fallthrough is there because assuming SDP (and thus max 500mA current
draw) is always safe.

>
>> +	case CHT_WC_USBSRC_TYPE_SDP:
>> +	case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
>> +	case CHT_WC_USBSRC_TYPE_OTHER:
>> +		return EXTCON_CHG_USB_SDP;
>> +	case CHT_WC_USBSRC_TYPE_CDP:
>> +		return EXTCON_CHG_USB_CDP;
>> +	case CHT_WC_USBSRC_TYPE_DCP:
>> +	case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
>> +	case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
>> +		return EXTCON_CHG_USB_DCP;
>> +	case CHT_WC_USBSRC_TYPE_ACA:
>> +		return EXTCON_CHG_USB_ACA;
>> +	}
>> +}
>> +
>> +static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state);
>> +	if (ret)
>> +		dev_err(ext->dev, "Error writing phyctrl: %d\n", ret);
>
> This function is only called in the cht_wc_extcon_det_event().
> Also, this funciton write only one register. It is too short.
> So, you don't need to add the separate function.
> You better to include this code in the cht_wc_extcon_det_event().

This is used multiple times in cht_wc_extcon_det_event() and is
also used in probe() so it saves having to copy and paste the error
check. Also the flow of cht_wc_extcon_det_event() is more readable
this way. If it is more efficient to have this inline the compiler
will auto-inline it.


>
>> +}
>> +
>> +static void cht_wc_extcon_det_event(struct cht_wc_extcon_data *ext)
>> +{
>> +	int ret, pwrsrc_sts, id;
>> +	unsigned int cable = EXTCON_NONE;
>> +
>> +	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
>> +	if (ret) {
>> +		dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
>> +		return;
>> +	}
>> +
>> +	id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
>> +	if (id == USB_ID_GND) {
>> +		/* The 5v boost causes a false VBUS / SDP detect, skip */
>> +		goto charger_det_done;
>> +	}
>> +
>> +	/* Plugged into a host/charger or not connected? */
>> +	if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) {
>> +		/* Route D+ and D- to PMIC for future charger detection */
>> +		cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
>> +		goto set_state;
>> +	}
>
> The cht_wc_extcon_get_id() and cht_wc_extcon_det_event() use the value
> of CHT_WC_PWRSRC_STS register. So, I think you better to gather the
> code related to the CHT_WC_PWRSRC_STS for readability.
> - First suggestion, remove the separate the cht_wc_extcon_get_id()
> - Second suggestion, The code from regmap_read() to "!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)"
>           move into the cht_wc_extcon_get_id().
>
> In my opinion, I recommend that second way.

These register reads are i2c register reads which are quite costly,
so we really want to do this only once, which is why the code is
as it is.

>> +
>> +	ret = cht_wc_extcon_get_charger(ext);
>> +	if (ret >= 0)
>> +		cable = ret;
>> +
>> +charger_det_done:
>> +	/* Route D+ and D- to SoC for the host / gadget controller */
>
> Minor comment.
> You better to use '&' instead of '/'

The data lines get used by either the host OR the gadget controller,
as there is another mux inside the SoC.

>
>> +	cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC);
>> +
>> +set_state:
>> +	extcon_set_state_sync(ext->edev, cable, true);
>> +	extcon_set_state_sync(ext->edev, ext->previous_cable, false);
>> +	extcon_set_state_sync(ext->edev, EXTCON_USB_HOST,
>> +			      id == USB_ID_GND || id == USB_RID_A);
>> +	ext->previous_cable = cable;
>> +}
>> +
>> +static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
>> +{
>> +	struct cht_wc_extcon_data *ext = data;
>> +	int ret, irqs;
>> +
>> +	ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
>> +	if (ret)
>> +		dev_err(ext->dev, "Error reading irqs: %d\n", ret);
>> +
>> +	cht_wc_extcon_det_event(ext);
>> +
>> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
>> +	if (ret)
>> +		dev_err(ext->dev, "Error writing irqs: %d\n", ret);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +/* usb_id sysfs attribute for debug / testing purposes */
>> +static ssize_t usb_id_show(struct device *dev, struct device_attribute *attr,
>> +			   char *buf)
>> +{
>> +	struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
>> +
>> +	return sprintf(buf, "%s\n", usb_id_str[ext->usb_id]);
>> +}
>> +
>> +static ssize_t usb_id_store(struct device *dev, struct device_attribute *attr,
>> +			    const char *buf, size_t n)
>> +{
>> +	struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
>> +	int i;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(usb_id_str); i++) {
>> +		if (sysfs_streq(buf, usb_id_str[i])) {
>> +			dev_info(ext->dev, "New usb_id %s\n", usb_id_str[i]);
>> +			ext->usb_id = i;
>> +			cht_wc_extcon_det_event(ext);
>> +			return n;
>> +		}
>> +	}
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static DEVICE_ATTR(usb_id, 0644, usb_id_show, usb_id_store);
>
> I think it is not good to add specific sysfs for only this device driver.
> The sysfs entry of framework must include the only common and standard interfarce
> for all extcon device drivers. Because the sysfs entry affects the ABI interface.
>
> So, It is not proper.

Unfortunately these kinda sysfs files are somewhat normal when
dealing with USB-OTG. For example my board does not have the
id-pin hooked up to the connector, so to test host mode
I need to echo "gnd" to the sysfs attr. But also if I actually
want to use host-mode (or anyone else with the same or a similar
board).

See for example also the "mode" sysfs attribute of the musb driver.

Since the id-pin setting influences multiple other drivers through
extcon the best place for this is in the extcon driver, as that
it the canonical source of the EXTCON_USB_HOST cable value.


>
>> +
>> +static int cht_wc_extcon_probe(struct platform_device *pdev)
>> +{
>> +	struct cht_wc_extcon_data *ext;
>> +	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
>> +	int irq, ret;
>> +
>> +	irq = platform_get_irq(pdev, 0);
>> +	if (irq < 0)
>> +		return irq;
>> +
>> +	ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL);
>> +	if (!ext)
>> +		return -ENOMEM;
>> +
>> +	ext->dev = &pdev->dev;
>> +	ext->regmap = pmic->regmap;
>> +	ext->previous_cable = EXTCON_NONE;
>> +
>> +	/* Initialize extcon device */
>> +	ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables);
>> +	if (IS_ERR(ext->edev))
>> +		return PTR_ERR(ext->edev);
>> +
>> +	ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0,
>> +		 CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK,
>> +		 CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK);
>> +	if (ret) {
>> +		dev_err(ext->dev, "Error enabling sw control\n");
>> +		return ret;
>> +	}
>> +
>> +	/* Register extcon device */
>> +	ret = devm_extcon_dev_register(ext->dev, ext->edev);
>> +	if (ret) {
>> +		dev_err(ext->dev, "Failed to register extcon device\n");
>> +		return ret;
>> +	}
>> +
>> +	/* Route D+ and D- to PMIC for initial charger detection */
>> +	cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
>> +
>> +	/* Get initial state */
>> +	cht_wc_extcon_det_event(ext);
>> +
>> +	ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr,
>> +					IRQF_ONESHOT, pdev->name, ext);
>> +	if (ret) {
>> +		dev_err(ext->dev, "Failed to request interrupt\n");
>> +		return ret;
>> +	}
>> +
>> +	/* Unmask irqs */
>> +	ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
>> +			   (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
>> +				  CHT_WC_PWRSRC_ID_FLOAT));
>> +	if (ret) {
>> +		dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);
>
> I prefer to use the consistent error log. In the probe function,
> you use the 'Failed to ...' when error hanppen. So, You better
> to use the consistent format for errr log as following:
> 	- "Failed to write the irq-mask: %d\n", ret);

Fixed for v2.

>
> I think it improve the readability of your device driver.
>
>> +		return ret;
>> +	}
>> +
>> +	platform_set_drvdata(pdev, ext);
>> +	device_create_file(ext->dev, &dev_attr_usb_id);
>> +
>> +	return 0;
>
>
> In the probe function, you touch the some register for initialization.
> But, if error happen, the probe function don't restore the register value.
> Is it ok? I think you need to handle the error case.

Fixed for v2.

>
>> +}
>> +
>> +static int cht_wc_extcon_remove(struct platform_device *pdev)
>> +{
>> +	struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev);
>> +
>> +	device_remove_file(ext->dev, &dev_attr_usb_id);
>
> Don't need it.
>
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct platform_device_id cht_wc_extcon_table[] = {
>> +	{ .name = "cht_wcove_pwrsrc" },
>
> You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
> So, To maintain the consistency, you better to use the 'cht-wc' as the name.
> - I prefer to use '-' instead of '_' in the name.
> 	.name ="cht-wc"

Already answered by Andy.

>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
>> +
>> +static struct platform_driver cht_wc_extcon_driver = {
>> +	.probe = cht_wc_extcon_probe,
>> +	.remove = cht_wc_extcon_remove,
>> +	.id_table = cht_wc_extcon_table,
>> +	.driver = {
>> +		.name = "cht_wcove_pwrsrc",
>> +	},
>> +};
>> +module_platform_driver(cht_wc_extcon_driver);
>> +
>> +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
>> +MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver");
>
> Minor comment.
> You better to locate the MODULE_DESCRIPTION at the first line
> and then MODULE_AUTHOR is at second line.

Fixed for v2.

Regards,

Hans

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

* Re: [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost
  2017-03-17 17:33   ` Andy Shevchenko
@ 2017-03-20 22:38     ` Hans de Goede
  0 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-20 22:38 UTC (permalink / raw)
  To: Andy Shevchenko, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 17-03-17 18:33, Andy Shevchenko wrote:
> On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
>> Add support for monitoring an extcon device with SDP/CDP/DCP and HOST
>> cables and adjust ilimit and enable/disable the 5v boost converter
>> accordingly. This is necessary on systems where the PSEL pin is
>> hardwired
>> high and ILIM needs to be set by software based on the detected
>> charger
>> type.
>>
>
>>  config CHARGER_BQ24190
>>  	tristate "TI BQ24190 battery charger driver"
>>  	depends on I2C
>
>> +	depends on EXTCON
>
> I dunno what is preferred here, but if we would like to keep
> compatibility with previous configurations "select" should be used over
> "depends on".

select really should only be used for hidden options,
using select in other scenarios leads to all sort of
problems (hard to debug Kconfig dependency loops).

>
>> +static void bq24190_extcon_work(struct work_struct *work)
>> +{
>> +	struct bq24190_dev_info *bdi =
>> +		container_of(work, struct bq24190_dev_info,
>> extcon_work);
>> +	int ret, iinlim = 0;
>> +
>> +	if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_SDP) == 1)
>> +		iinlim = 500000;
>> +	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_CDP) ==
>> 1 ||
>> +		 extcon_get_state(bdi->extcon, EXTCON_CHG_USB_ACA) ==
>> 1)
>> +		iinlim = 1500000;
>> +	else if (extcon_get_state(bdi->extcon, EXTCON_CHG_USB_DCP) ==
>> 1)
>> +		iinlim = 2000000;
>> +
>
>> +	if (iinlim) {
>
> Could be possible to call below unconditionally here (use 0)?

If there is no Vbus setting iinlim is not useful, the charger
will reset it to a default as soon as Vbus comes up and i2c
transactions are not free.

>
>> +		ret = bq24190_set_field_val(bdi, BQ24190_REG_ISC,
>> +				BQ24190_REG_ISC_IINLIM_MASK,
>> +				BQ24190_REG_ISC_IINLIM_SHIFT,
>> +				bq24190_iinlim_values,
>> +				ARRAY_SIZE(bq24190_iinlim_values),
>> +				iinlim);
>> +		if (ret)
>> +			dev_err(bdi->dev, "Can't set IINLIM: %d\n",
>> ret);
>> +	}
>
> Perhaps make above as a helper?
>
> In that case no need for "if (iinlim)" and perhaps switch-case might be
> used instead of if-else-if (latter is up to you).

I prefer to keep this as is.

Thanks & Regards,

Hans

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-20 13:00     ` Andy Shevchenko
@ 2017-03-21  3:54       ` Chanwoo Choi
  2017-03-21  5:21         ` Chanwoo Choi
  0 siblings, 1 reply; 46+ messages in thread
From: Chanwoo Choi @ 2017-03-21  3:54 UTC (permalink / raw)
  To: Andy Shevchenko, Hans de Goede, Rafael J . Wysocki, Len Brown,
	Wolfram Sang, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On 2017년 03월 20일 22:00, Andy Shevchenko wrote:
> On Mon, 2017-03-20 at 10:33 +0900, Chanwoo Choi wrote:
>> On 2017년 03월 17일 18:55, Hans de Goede wrote:
> 
>>> +static const struct platform_device_id cht_wc_extcon_table[] = {
>>> +	{ .name = "cht_wcove_pwrsrc" },
>>
>> You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
>> So, To maintain the consistency, you better to use the 'cht-wc' as the
>> name.
>> - I prefer to use '-' instead of '_' in the name.
>> 	.name ="cht-wc"
> 
> I would keep as Hans did for the sake of consistency among all Whiskey
> Cove device drivers (and predecessors like Crystal Cove).

The 'wcove' short word is not used in this patch.
If the author want to use the 'wcove', I recommend that
you should use the 'wcove' instead of 'wc' in this patch.

And, I think that  'pwrsrc' is not ambiguous.
Hans might use the 'pwrsrc' as the 'Power Source'.
But, this driver is not power source. Instead,
this driver supports the detection of external connector.

I think 'power source' means the power supply instead of detector.

> 
> I understand your point from extcon subsystem view, but PMICs like
> Whiskey Cove are multi-functional devices, and thus naming across them
> (same prefix in use to be precise) is better idea.
> 
>>
>>> +	{},
>>> +};
>>> +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-20 19:57     ` Hans de Goede
@ 2017-03-21  5:16       ` Chanwoo Choi
  2017-03-23 15:22         ` Hans de Goede
  0 siblings, 1 reply; 46+ messages in thread
From: Chanwoo Choi @ 2017-03-21  5:16 UTC (permalink / raw)
  To: Hans de Goede, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Andy Shevchenko, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 2017년 03월 21일 04:57, Hans de Goede wrote:
> Hi,
> 
> On 20-03-17 02:33, Chanwoo Choi wrote:
>> Hi,
>>
>> On 2017년 03월 17일 18:55, Hans de Goede wrote:
>>> Add a driver for charger detection / control on the Intel Cherrytrail
>>> Whiskey Cove PMIC.
>>>
>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>> ---
>>>  drivers/extcon/Kconfig         |   7 +
>>>  drivers/extcon/Makefile        |   1 +
>>>  drivers/extcon/extcon-cht-wc.c | 356 +++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 364 insertions(+)
>>>  create mode 100644 drivers/extcon/extcon-cht-wc.c
>>>
>>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>>> index 96bbae5..4cace6b 100644
>>> --- a/drivers/extcon/Kconfig
>>> +++ b/drivers/extcon/Kconfig
>>> @@ -52,6 +52,13 @@ config EXTCON_INTEL_INT3496
>>>        This ACPI device is typically found on Intel Baytrail or Cherrytrail
>>>        based tablets, or other Baytrail / Cherrytrail devices.
>>>
>>> +config EXTCON_CHT_WC
>>
>> Need to reorder it alpabetically as the following Makefile.
> 
> The idea is to have the items alphabetically listed in "make menuconfig"
> and the name of the menu item starts with Intel:

If you want to locate it under the EXTCON_INTEL_INT3496,
you should change the filename as following style:
- extcon-intel-cht-wc.c

I want to locate all entry alphabetically. 

> 
>>
>>> +    tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver"
>>> +    depends on INTEL_SOC_PMIC_CHTWC
>>> +    help
>>> +      Say Y here to enable extcon support for charger detection / control
>>> +      on the Intel Cherrytrail Whiskey Cove PMIC.
>>> +
>>>  config EXTCON_MAX14577
>>>      tristate "Maxim MAX14577/77836 EXTCON Support"
>>>      depends on MFD_MAX14577
>>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>>> index 237ac3f..160f88b 100644
>>> --- a/drivers/extcon/Makefile
>>> +++ b/drivers/extcon/Makefile
>>> @@ -7,6 +7,7 @@ extcon-core-objs        += extcon.o devres.o
>>>  obj-$(CONFIG_EXTCON_ADC_JACK)    += extcon-adc-jack.o
>>>  obj-$(CONFIG_EXTCON_ARIZONA)    += extcon-arizona.o
>>>  obj-$(CONFIG_EXTCON_AXP288)    += extcon-axp288.o
>>> +obj-$(CONFIG_EXTCON_CHT_WC)    += extcon-cht-wc.o
>>>  obj-$(CONFIG_EXTCON_GPIO)    += extcon-gpio.o
>>>  obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
>>>  obj-$(CONFIG_EXTCON_MAX14577)    += extcon-max14577.o
>>> diff --git a/drivers/extcon/extcon-cht-wc.c b/drivers/extcon/extcon-cht-wc.c
>>> new file mode 100644
>>> index 0000000..896eee6
>>> --- /dev/null
>>> +++ b/drivers/extcon/extcon-cht-wc.c
>>> @@ -0,0 +1,356 @@
>>> +/*
>>> + * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
>>> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
>>> + *
>>> + * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
>>
>> Maybe, you don't need to add ':' at the end of line.
> 
> Th ':' is there because the following copyright line:
>>
>>> + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
> 
> Comes from those various non upstream patches.
> 
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms and conditions of the GNU General Public License,
>>> + * version 2, as published by the Free Software Foundation.
>>> + *
>>> + * This program is distributed in the hope it will be useful, but WITHOUT
>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>>> + * more details.
>>> + */
>>> +
>>> +#include <linux/extcon.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/mfd/intel_soc_pmic.h>
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/slab.h>
>>> +
>>> +#define CHT_WC_PWRSRC_IRQ        0x6e03
>>> +#define CHT_WC_PWRSRC_IRQ_MASK        0x6e0f
>>> +#define CHT_WC_PWRSRC_STS        0x6e1e
>>> +#define CHT_WC_PWRSRC_VBUS        BIT(0)
>>> +#define CHT_WC_PWRSRC_DC        BIT(1)
>>> +#define CHT_WC_PWRSRC_BAT        BIT(2)
>>> +#define CHT_WC_PWRSRC_ID_GND        BIT(3)
>>> +#define CHT_WC_PWRSRC_ID_FLOAT        BIT(4)
>>> +
>>> +#define CHT_WC_PHYCTRL            0x5e07
>>> +
>>> +#define CHT_WC_CHGRCTRL0        0x5e16
>>> +
>>> +#define CHT_WC_CHGRCTRL0        0x5e16
>>> +#define CHT_WC_CHGRCTRL0_CHGRRESET    BIT(0)
>>> +#define CHT_WC_CHGRCTRL0_EMRGCHREN    BIT(1)
>>> +#define CHT_WC_CHGRCTRL0_EXTCHRDIS    BIT(2)
>>> +#define CHT_WC_CHGRCTRL0_SWCONTROL    BIT(3)
>>> +#define CHT_WC_CHGRCTRL0_TTLCK_MASK    BIT(4)
>>> +#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK    BIT(5)
>>> +#define CHT_WC_CHGRCTRL0_DBPOFF_MASK    BIT(6)
>>> +#define CHT_WC_CHGRCTRL0_WDT_NOKICK    BIT(7)
>>> +
>>> +#define CHT_WC_CHGRCTRL1        0x5e17
>>> +
>>> +#define CHT_WC_USBSRC            0x5e29
>>> +#define CHT_WC_USBSRC_STS_MASK        GENMASK(1, 0)
>>> +#define CHT_WC_USBSRC_STS_SUCCESS    2
>>> +#define CHT_WC_USBSRC_STS_FAIL        3
>>> +#define CHT_WC_USBSRC_TYPE_SHIFT    2
>>> +#define CHT_WC_USBSRC_TYPE_MASK        GENMASK(5, 2)
>>> +#define CHT_WC_USBSRC_TYPE_NONE        0
>>> +#define CHT_WC_USBSRC_TYPE_SDP        1
>>> +#define CHT_WC_USBSRC_TYPE_DCP        2
>>> +#define CHT_WC_USBSRC_TYPE_CDP        3
>>> +#define CHT_WC_USBSRC_TYPE_ACA        4
>>> +#define CHT_WC_USBSRC_TYPE_SE1        5
>>> +#define CHT_WC_USBSRC_TYPE_MHL        6
>>> +#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN    7
>>> +#define CHT_WC_USBSRC_TYPE_OTHER    8
>>> +#define CHT_WC_USBSRC_TYPE_DCP_EXTPHY    9
>>> +
>>> +enum cht_wc_usb_id {
>>> +    USB_ID_OTG,
>>> +    USB_ID_GND,
>>> +    USB_ID_FLOAT,
>>> +    USB_RID_A,
>>> +    USB_RID_B,
>>> +    USB_RID_C,
>>> +};
>>> +
>>> +/* Strings matching the cht_wc_usb_id enum labels */
>>> +static const char * const usb_id_str[] = {
>>> +    "otg", "gnd", "float", "rid_a", "rid_b", "rid_c" };
>>> +
>>> +enum cht_wc_mux_select {
>>> +    MUX_SEL_PMIC = 0,
>>> +    MUX_SEL_SOC,
>>> +};
>>> +
>>> +static const unsigned int cht_wc_extcon_cables[] = {
>>> +    EXTCON_USB,
>>> +    EXTCON_USB_HOST,
>>> +    EXTCON_CHG_USB_SDP,
>>> +    EXTCON_CHG_USB_CDP,
>>> +    EXTCON_CHG_USB_DCP,
>>> +    EXTCON_NONE,
>>> +};
>>> +
>>> +struct cht_wc_extcon_data {
>>> +    struct device *dev;
>>> +    struct regmap *regmap;
>>> +    struct extcon_dev *edev;
>>> +    unsigned int previous_cable;
>>> +    int usb_id;
>>> +};
>>> +
>>> +static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
>>> +{
>>> +    if (ext->usb_id)
>>> +        return ext->usb_id;
>>> +
>>> +    if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
>>> +        return USB_ID_GND;
>>> +    if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
>>> +        return USB_ID_FLOAT;
>>> +
>>> +    /*
>>> +     * Once we have iio support for the gpadc we should read the USBID
>>> +     * gpadc channel here and determine ACA role based on that.
>>> +     */
>>> +    return USB_ID_FLOAT;
>>> +}
>>> +
>>> +static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext)
>>> +{
>>> +    int ret, usbsrc, status, retries = 5;
>>
>> You have to define the constant for '5' because the name of constant
>> definition indicates what is meaning. So, maybe you will use the 'for' loope
>> instead of 'do..while'.
> 
> Right, already fixed as a result of Andy's review.
> 
>>
>>> +
>>> +    do {
>>> +        ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc);
>>> +        if (ret) {
>>> +            dev_err(ext->dev, "Error reading usbsrc: %d\n", ret);
>>> +            return ret;
>>> +        }
>>
>> Need to add one blank line.
>>
>>> +        status = usbsrc & CHT_WC_USBSRC_STS_MASK;
>>> +        if (status == CHT_WC_USBSRC_STS_SUCCESS ||
>>> +            status == CHT_WC_USBSRC_STS_FAIL)
>>> +            break;
>>> +
>>> +        msleep(200);
>>
>> You have to define the constant for '200' because the name of constant
>> definition indicates what is meaning.
>>
>>> +    } while (retries--);
>>> +
>>> +    if (status != CHT_WC_USBSRC_STS_SUCCESS) {
>>> +        if (status == CHT_WC_USBSRC_STS_FAIL)
>>> +            dev_warn(ext->dev, "Could not detect charger type\n");
>>> +        else
>>> +            dev_warn(ext->dev, "Timeout detecting charger type\n");
>>> +        return EXTCON_CHG_USB_SDP; /* Save fallback */
>>> +    }
>>> +
>>> +    ret = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;
>>
>> 'ret' is not proper indicates the meaning of 'CHT_WC_USBSRC_TYPE'.
>> You have to use the more correct local variable such as 'usbsrc_type'.
> 
> Fixed for v2.
>>
>>> +    switch (ret) {
>>> +    default:
>>> +        dev_warn(ext->dev, "Unhandled charger type %d\n", ret);
>>> +        /* Fall through treat as SDP */
>>
>> Is it right? Why do you located the 'default' on the top in the switch?
> 
> So that I can use fall-through, there is no rule in C where the default goes.
> 
> The fallthrough is there because assuming SDP (and thus max 500mA current
> draw) is always safe.

If in the default statement, you treat the unhandled charger type as the SDP,
you don't remove the warning message. It makes the confusion.

Warning message is 'unhandled charger type'. But, the extcon
detects the 'SDP' connector type. It is not reasonable.

> 
>>
>>> +    case CHT_WC_USBSRC_TYPE_SDP:
>>> +    case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
>>> +    case CHT_WC_USBSRC_TYPE_OTHER:
>>> +        return EXTCON_CHG_USB_SDP;
>>> +    case CHT_WC_USBSRC_TYPE_CDP:
>>> +        return EXTCON_CHG_USB_CDP;
>>> +    case CHT_WC_USBSRC_TYPE_DCP:
>>> +    case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
>>> +    case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
>>> +        return EXTCON_CHG_USB_DCP;
>>> +    case CHT_WC_USBSRC_TYPE_ACA:
>>> +        return EXTCON_CHG_USB_ACA;
>>> +    }
>>> +}
>>> +
>>> +static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state)
>>> +{
>>> +    int ret;
>>> +
>>> +    ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state);
>>> +    if (ret)
>>> +        dev_err(ext->dev, "Error writing phyctrl: %d\n", ret);
>>
>> This function is only called in the cht_wc_extcon_det_event().
>> Also, this funciton write only one register. It is too short.
>> So, you don't need to add the separate function.
>> You better to include this code in the cht_wc_extcon_det_event().
> 
> This is used multiple times in cht_wc_extcon_det_event() and is
> also used in probe() so it saves having to copy and paste the error
> check. Also the flow of cht_wc_extcon_det_event() is more readable
> this way. If it is more efficient to have this inline the compiler
> will auto-inline it.

OK. I recognized it was called only on the cht_wc_extcon_det_event().
But, it is called on multiple points. It's OK.

> 
> 
>>
>>> +}
>>> +
>>> +static void cht_wc_extcon_det_event(struct cht_wc_extcon_data *ext)
>>> +{
>>> +    int ret, pwrsrc_sts, id;
>>> +    unsigned int cable = EXTCON_NONE;
>>> +
>>> +    ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
>>> +    if (ret) {
>>> +        dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
>>> +        return;
>>> +    }
>>> +
>>> +    id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
>>> +    if (id == USB_ID_GND) {
>>> +        /* The 5v boost causes a false VBUS / SDP detect, skip */
>>> +        goto charger_det_done;
>>> +    }
>>> +
>>> +    /* Plugged into a host/charger or not connected? */
>>> +    if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) {
>>> +        /* Route D+ and D- to PMIC for future charger detection */
>>> +        cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
>>> +        goto set_state;
>>> +    }
>>
>> The cht_wc_extcon_get_id() and cht_wc_extcon_det_event() use the value
>> of CHT_WC_PWRSRC_STS register. So, I think you better to gather the
>> code related to the CHT_WC_PWRSRC_STS for readability.
>> - First suggestion, remove the separate the cht_wc_extcon_get_id()
>> - Second suggestion, The code from regmap_read() to "!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)"
>>           move into the cht_wc_extcon_get_id().
>>
>> In my opinion, I recommend that second way.
> 
> These register reads are i2c register reads which are quite costly,
> so we really want to do this only once, which is why the code is
> as it is.

Sure, If you use the my second suggestion, you can read i2c register
only one time for all codes as following:

	cht_wc_extcon_get_id(ext)
		// Read the CHT_WC_PWRSRC_STS register through i2c
		// Check the usb_id and pwersrc_sts with CHT_WC_PWRSRC_ID_GND/CHT_WC_PWRSRC_ID_FLOAT.
		// Plugged into a host/charger or not connected?
> 
>>> +
>>> +    ret = cht_wc_extcon_get_charger(ext);
>>> +    if (ret >= 0)
>>> +        cable = ret;
>>> +
>>> +charger_det_done:
>>> +    /* Route D+ and D- to SoC for the host / gadget controller */
>>
>> Minor comment.
>> You better to use '&' instead of '/'
> 
> The data lines get used by either the host OR the gadget controller,
> as there is another mux inside the SoC.

If '/' means the 'or', you can use the 'or' instead of '/'.

> 
>>
>>> +    cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC);
>>> +
>>> +set_state:
>>> +    extcon_set_state_sync(ext->edev, cable, true);
>>> +    extcon_set_state_sync(ext->edev, ext->previous_cable, false);
>>> +    extcon_set_state_sync(ext->edev, EXTCON_USB_HOST,
>>> +                  id == USB_ID_GND || id == USB_RID_A);
>>> +    ext->previous_cable = cable;
>>> +}
>>> +
>>> +static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
>>> +{
>>> +    struct cht_wc_extcon_data *ext = data;
>>> +    int ret, irqs;
>>> +
>>> +    ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
>>> +    if (ret)
>>> +        dev_err(ext->dev, "Error reading irqs: %d\n", ret);
>>> +
>>> +    cht_wc_extcon_det_event(ext);
>>> +
>>> +    ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
>>> +    if (ret)
>>> +        dev_err(ext->dev, "Error writing irqs: %d\n", ret);
>>> +
>>> +    return IRQ_HANDLED;
>>> +}
>>> +
>>> +/* usb_id sysfs attribute for debug / testing purposes */
>>> +static ssize_t usb_id_show(struct device *dev, struct device_attribute *attr,
>>> +               char *buf)
>>> +{
>>> +    struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
>>> +
>>> +    return sprintf(buf, "%s\n", usb_id_str[ext->usb_id]);
>>> +}
>>> +
>>> +static ssize_t usb_id_store(struct device *dev, struct device_attribute *attr,
>>> +                const char *buf, size_t n)
>>> +{
>>> +    struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
>>> +    int i;
>>> +
>>> +    for (i = 0; i < ARRAY_SIZE(usb_id_str); i++) {
>>> +        if (sysfs_streq(buf, usb_id_str[i])) {
>>> +            dev_info(ext->dev, "New usb_id %s\n", usb_id_str[i]);
>>> +            ext->usb_id = i;
>>> +            cht_wc_extcon_det_event(ext);
>>> +            return n;
>>> +        }
>>> +    }
>>> +
>>> +    return -EINVAL;
>>> +}
>>> +
>>> +static DEVICE_ATTR(usb_id, 0644, usb_id_show, usb_id_store);
>>
>> I think it is not good to add specific sysfs for only this device driver.
>> The sysfs entry of framework must include the only common and standard interfarce
>> for all extcon device drivers. Because the sysfs entry affects the ABI interface.
>>
>> So, It is not proper.
> 
> Unfortunately these kinda sysfs files are somewhat normal when
> dealing with USB-OTG. For example my board does not have the
> id-pin hooked up to the connector, so to test host mode
> I need to echo "gnd" to the sysfs attr. But also if I actually
> want to use host-mode (or anyone else with the same or a similar
> board).

As I said, I don't want to create the non-standard sysfs interface
for only specific device driver.

If you want to change the some mode of device driver,
we should implement the something in the extcon framework
by keeping the standard interface for ABI. I don't want to
make such a special case.

> 
> See for example also the "mode" sysfs attribute of the musb driver.
> 
> Since the id-pin setting influences multiple other drivers through
> extcon the best place for this is in the extcon driver, as that
> it the canonical source of the EXTCON_USB_HOST cable value.
> 
> 
>>
>>> +
>>> +static int cht_wc_extcon_probe(struct platform_device *pdev)
>>> +{
>>> +    struct cht_wc_extcon_data *ext;
>>> +    struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
>>> +    int irq, ret;
>>> +
>>> +    irq = platform_get_irq(pdev, 0);
>>> +    if (irq < 0)
>>> +        return irq;
>>> +
>>> +    ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL);
>>> +    if (!ext)
>>> +        return -ENOMEM;
>>> +
>>> +    ext->dev = &pdev->dev;
>>> +    ext->regmap = pmic->regmap;
>>> +    ext->previous_cable = EXTCON_NONE;
>>> +
>>> +    /* Initialize extcon device */
>>> +    ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables);
>>> +    if (IS_ERR(ext->edev))
>>> +        return PTR_ERR(ext->edev);
>>> +
>>> +    ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0,
>>> +         CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK,
>>> +         CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK);
>>> +    if (ret) {
>>> +        dev_err(ext->dev, "Error enabling sw control\n");
>>> +        return ret;
>>> +    }
>>> +
>>> +    /* Register extcon device */
>>> +    ret = devm_extcon_dev_register(ext->dev, ext->edev);
>>> +    if (ret) {
>>> +        dev_err(ext->dev, "Failed to register extcon device\n");
>>> +        return ret;
>>> +    }
>>> +
>>> +    /* Route D+ and D- to PMIC for initial charger detection */
>>> +    cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
>>> +
>>> +    /* Get initial state */
>>> +    cht_wc_extcon_det_event(ext);
>>> +
>>> +    ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr,
>>> +                    IRQF_ONESHOT, pdev->name, ext);
>>> +    if (ret) {
>>> +        dev_err(ext->dev, "Failed to request interrupt\n");
>>> +        return ret;
>>> +    }
>>> +
>>> +    /* Unmask irqs */
>>> +    ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
>>> +               (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
>>> +                  CHT_WC_PWRSRC_ID_FLOAT));
>>> +    if (ret) {
>>> +        dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);
>>
>> I prefer to use the consistent error log. In the probe function,
>> you use the 'Failed to ...' when error hanppen. So, You better
>> to use the consistent format for errr log as following:
>>     - "Failed to write the irq-mask: %d\n", ret);
> 
> Fixed for v2.
> 
>>
>> I think it improve the readability of your device driver.
>>
>>> +        return ret;
>>> +    }
>>> +
>>> +    platform_set_drvdata(pdev, ext);
>>> +    device_create_file(ext->dev, &dev_attr_usb_id);
>>> +
>>> +    return 0;
>>
>>
>> In the probe function, you touch the some register for initialization.
>> But, if error happen, the probe function don't restore the register value.
>> Is it ok? I think you need to handle the error case.
> 
> Fixed for v2.
> 
>>
>>> +}
>>> +
>>> +static int cht_wc_extcon_remove(struct platform_device *pdev)
>>> +{
>>> +    struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev);
>>> +
>>> +    device_remove_file(ext->dev, &dev_attr_usb_id);
>>
>> Don't need it.
>>
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static const struct platform_device_id cht_wc_extcon_table[] = {
>>> +    { .name = "cht_wcove_pwrsrc" },
>>
>> You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
>> So, To maintain the consistency, you better to use the 'cht-wc' as the name.
>> - I prefer to use '-' instead of '_' in the name.
>>     .name ="cht-wc"
> 
> Already answered by Andy.

I replied again from the Andy's reply.

> 
>>> +    {},
>>> +};
>>> +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
>>> +
>>> +static struct platform_driver cht_wc_extcon_driver = {
>>> +    .probe = cht_wc_extcon_probe,
>>> +    .remove = cht_wc_extcon_remove,
>>> +    .id_table = cht_wc_extcon_table,
>>> +    .driver = {
>>> +        .name = "cht_wcove_pwrsrc",
>>> +    },
>>> +};
>>> +module_platform_driver(cht_wc_extcon_driver);
>>> +
>>> +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
>>> +MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver");
>>
>> Minor comment.
>> You better to locate the MODULE_DESCRIPTION at the first line
>> and then MODULE_AUTHOR is at second line.
> 
> Fixed for v2.
> 
> Regards,
> 
> Hans
> 
> 
> 

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-21  3:54       ` Chanwoo Choi
@ 2017-03-21  5:21         ` Chanwoo Choi
  2017-03-21  6:27           ` Chanwoo Choi
  0 siblings, 1 reply; 46+ messages in thread
From: Chanwoo Choi @ 2017-03-21  5:21 UTC (permalink / raw)
  To: Andy Shevchenko, Hans de Goede, Rafael J . Wysocki, Len Brown,
	Wolfram Sang, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

On 2017년 03월 21일 12:54, Chanwoo Choi wrote:
> On 2017년 03월 20일 22:00, Andy Shevchenko wrote:
>> On Mon, 2017-03-20 at 10:33 +0900, Chanwoo Choi wrote:
>>> On 2017년 03월 17일 18:55, Hans de Goede wrote:
>>
>>>> +static const struct platform_device_id cht_wc_extcon_table[] = {
>>>> +	{ .name = "cht_wcove_pwrsrc" },
>>>
>>> You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
>>> So, To maintain the consistency, you better to use the 'cht-wc' as the
>>> name.
>>> - I prefer to use '-' instead of '_' in the name.
>>> 	.name ="cht-wc"
>>
>> I would keep as Hans did for the sake of consistency among all Whiskey
>> Cove device drivers (and predecessors like Crystal Cove).
> 
> The 'wcove' short word is not used in this patch.
> If the author want to use the 'wcove', I recommend that
> you should use the 'wcove' instead of 'wc' in this patch.
> 
> And, I think that  'pwrsrc' is not ambiguous.

I'm sorry. I used the wrong word. I mean that 'pwrsrc' is not correct.

> Hans might use the 'pwrsrc' as the 'Power Source'.
> But, this driver is not power source. Instead,
> this driver supports the detection of external connector.
> 
> I think 'power source' means the power supply instead of detector.
> 
>>
>> I understand your point from extcon subsystem view, but PMICs like
>> Whiskey Cove are multi-functional devices, and thus naming across them
>> (same prefix in use to be precise) is better idea.
>>
>>>
>>>> +	{},
>>>> +};
>>>> +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
>>
> 
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-21  5:21         ` Chanwoo Choi
@ 2017-03-21  6:27           ` Chanwoo Choi
  0 siblings, 0 replies; 46+ messages in thread
From: Chanwoo Choi @ 2017-03-21  6:27 UTC (permalink / raw)
  To: Andy Shevchenko, Hans de Goede, Rafael J . Wysocki, Len Brown,
	Wolfram Sang, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

I think it again.
The "cht_wcove_pwrsrc' is ok, if the register use the 'pwrsrc' word
and using the 'wcove' instead of 'wc'. It is not big matter.

I agree to use the 'cht_wcove_pwrsrc'.

Best Regards,
Chanwoo Choi


On 2017년 03월 21일 14:21, Chanwoo Choi wrote:
> On 2017년 03월 21일 12:54, Chanwoo Choi wrote:
>> On 2017년 03월 20일 22:00, Andy Shevchenko wrote:
>>> On Mon, 2017-03-20 at 10:33 +0900, Chanwoo Choi wrote:
>>>> On 2017년 03월 17일 18:55, Hans de Goede wrote:
>>>
>>>>> +static const struct platform_device_id cht_wc_extcon_table[] = {
>>>>> +	{ .name = "cht_wcove_pwrsrc" },
>>>>
>>>> You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
>>>> So, To maintain the consistency, you better to use the 'cht-wc' as the
>>>> name.
>>>> - I prefer to use '-' instead of '_' in the name.
>>>> 	.name ="cht-wc"
>>>
>>> I would keep as Hans did for the sake of consistency among all Whiskey
>>> Cove device drivers (and predecessors like Crystal Cove).
>>
>> The 'wcove' short word is not used in this patch.
>> If the author want to use the 'wcove', I recommend that
>> you should use the 'wcove' instead of 'wc' in this patch.
>>
>> And, I think that  'pwrsrc' is not ambiguous.
> 
> I'm sorry. I used the wrong word. I mean that 'pwrsrc' is not correct.
> 
>> Hans might use the 'pwrsrc' as the 'Power Source'.
>> But, this driver is not power source. Instead,
>> this driver supports the detection of external connector.
>>
>> I think 'power source' means the power supply instead of detector.
>>
>>>
>>> I understand your point from extcon subsystem view, but PMICs like
>>> Whiskey Cove are multi-functional devices, and thus naming across them
>>> (same prefix in use to be precise) is better idea.
>>>
>>>>
>>>>> +	{},
>>>>> +};
>>>>> +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
>>>
>>
>>
> 
> 

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

* Re: [PATCH 12/15] i2c: core: Add new i2c_acpi_new_device helper function
  2017-03-17 17:37   ` Andy Shevchenko
@ 2017-03-22 15:59     ` Hans de Goede
  0 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-22 15:59 UTC (permalink / raw)
  To: Andy Shevchenko, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 17-03-17 18:37, Andy Shevchenko wrote:
> On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
>> By default the i2c subsys creates an i2c-client for the first
>> I2cSerialBus
>> resource of an acpi_device, but some acpi_devices have multiple
>> I2cSerialBus resources and the driver may need access to the others.
>>
>> This commit adds a new i2c_acpi_new_device function which can be used
>> by
>> drivers to create an i2c-client for any (other) I2cSerialBus resource
>> of
>> an acpi_device.
>>
>> Note that the other resources may even be on a different i2c bus, so
>> just
>> retrieving the client address is not enough.
>>
>
> Looks sane to me:
>
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
> Nevertheless, one nit, can you update commit message with real excerpt
> of DSDT?

Sure, will do for v2.

Regards,

Hans


>
>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>> ---
>>  drivers/i2c/i2c-core.c | 48
>> ++++++++++++++++++++++++++++++++++++++++++++++++
>>  include/linux/i2c.h    |  5 +++++
>>  2 files changed, 53 insertions(+)
>>
>> diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
>> index 32b58fb..fd45207 100644
>> --- a/drivers/i2c/i2c-core.c
>> +++ b/drivers/i2c/i2c-core.c
>> @@ -421,6 +421,54 @@ static int i2c_acpi_notify(struct notifier_block
>> *nb, unsigned long value,
>>  static struct notifier_block i2c_acpi_notifier = {
>>  	.notifier_call = i2c_acpi_notify,
>>  };
>> +
>> +/**
>> + * i2c_acpi_new_device - Create i2c client for the Nth acpi resource
>> of dev
>> + * @dev:     Device owning the acpi resources to get the client from
>> + * @index:   Index of acpi resource to get
>> + *
>> + * By default the i2c subsys creates an i2c-client for the first
>> I2cSerialBus
>> + * resource of an acpi_device, but some acpi_devices have multiple
>> + * I2cSerialBus resources and the driver may need access to the
>> others.
>> + * This function can be used by drivers to create an i2c-client for
>> any
>> + * resource of an acpi_device.
>> + *
>> + * Returns a pointer to the new i2c-client, or NULL if the resource
>> or
>> + * adapter were not found.
>> + */
>> +struct i2c_client *i2c_acpi_new_device(struct device *dev, int index)
>> +{
>> +	struct i2c_acpi_lookup lookup;
>> +	struct i2c_board_info info;
>> +	struct i2c_adapter *adapter;
>> +	struct acpi_device *adev;
>> +	LIST_HEAD(resource_list);
>> +	int ret;
>> +
>> +	adev = ACPI_COMPANION(dev);
>> +	if (!adev)
>> +		return NULL;
>> +
>> +	memset(&info, 0, sizeof(info));
>> +	memset(&lookup, 0, sizeof(lookup));
>> +	lookup.info = &info;
>> +	lookup.device_handle = acpi_device_handle(adev);
>> +	lookup.index = index;
>> +
>> +	ret = acpi_dev_get_resources(adev, &resource_list,
>> +				     i2c_acpi_fill_info, &lookup);
>> +	acpi_dev_free_resource_list(&resource_list);
>> +
>> +	if (ret < 0 || !info.addr)
>> +		return NULL;
>> +
>> +	adapter =
>> i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
>> +	if (!adapter)
>> +		return NULL;
>> +
>> +	return i2c_new_device(adapter, &info);
>> +}
>> +EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
>>  #else /* CONFIG_ACPI */
>>  static inline void i2c_acpi_register_devices(struct i2c_adapter
>> *adap) { }
>>  extern struct notifier_block i2c_acpi_notifier;
>> diff --git a/include/linux/i2c.h b/include/linux/i2c.h
>> index 6b18352..369ebfa 100644
>> --- a/include/linux/i2c.h
>> +++ b/include/linux/i2c.h
>> @@ -824,11 +824,16 @@ static inline const struct of_device_id
>>
>>  #if IS_ENABLED(CONFIG_ACPI)
>>  u32 i2c_acpi_find_bus_speed(struct device *dev);
>> +struct i2c_client *i2c_acpi_new_device(struct device *dev, int
>> index);
>>  #else
>>  static inline u32 i2c_acpi_find_bus_speed(struct device *dev)
>>  {
>>  	return 0;
>>  }
>> +static inline struct i2c_client *i2c_acpi_new_device(struct device
>> *d, int i)
>> +{
>> +	return NULL;
>> +}
>>  #endif /* CONFIG_ACPI */
>>
>>  #endif /* _LINUX_I2C_H */
>

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

* Re: [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge
  2017-03-17 17:58   ` Andy Shevchenko
@ 2017-03-22 17:03     ` Hans de Goede
  0 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-22 17:03 UTC (permalink / raw)
  To: Andy Shevchenko, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 17-03-17 18:58, Andy Shevchenko wrote:
> On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
>> Add a driver for the Cherry Trail Whiskey Cove PMIC Fuel Gauge, note
>> the Cherry Trail Whiskey Cove PMIC Fuel Gauge block is purely a fuel
>> gauge
>> and not a full battery controller. As such it offers a platform_data
>> callback for extra power_supply properties for the actual external-
>> charger
>> ic driver and does not register a power_supply itself.
>
> ic -> IC
>
> Can we move to something like built-in device properties for additional
> properties instead of extending platform data?
>
>> +config CHT_WC_FUEL_GAUGE
>
> I would use similar pattern:
>
> FUEL_GAUGE_INTEL_CHTWC (or FUEL_GAUGE_CHTWC, but this might be less
> obvious about vendor)

Good point, although all the fuel-gauge's seem to use
BATTERY as prefix, so I've gone with that.

>
>> --- /dev/null
>> +++ b/drivers/power/supply/cht_wc_fuel_gauge.c
>> @@ -0,0 +1,209 @@
>> +/*
>> + * Intel CHT Whiskey Cove Fuel Gauge driver
>
> CHT -> Cherry Trail

Fixed.

>
>> + *
>> + * Cherrytrail Whiskey Cove devices have 2 functional blocks which
>> interact
>> + * with the battery.
>
> Cherry Trail?

Since after discussion about how to deal with the charger / fuel_gauge
comment v2 is going to be a stand-alone power_supply driver this
comment has been dropped.

>
>> +#define REG_CHARGE_NOW		0x05
>> +#define REG_VOLTAGE_NOW		0x09
>> +#define REG_CURRENT_NOW		0x0a
>> +#define REG_CURRENT_AVG		0x0b
>> +#define REG_CHARGE_FULL		0x10
>> +#define REG_CHARGE_DESIGN	0x18
>> +#define REG_VOLTAGE_AVG		0x19
>
>> +#define REG_VOLTAGE_OCV		0x1b /* Only updated during
>> charging */
>
> I think comment makes more sense where actual update is happening in the
> code.
>
>> +
>> +static int cht_wc_fg_read(struct cht_wc_fg_data *fg, u8 reg,
>> +			  union power_supply_propval *val, int scale,
>> +			  int sign_extend)
>> +{
>> +	int ret;
>> +
>> +	ret = i2c_smbus_read_word_data(fg->client, reg);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	if (sign_extend)
>> +		ret = sign_extend32(ret, 15);
>
> Magic?

Nope just simply dealing with i2c_smbus_read_word_data always
returning 16 bit unsigned data (or a negative error code)
and some of the registers being 16 bit signed.

>
>> +
>> +	val->intval = ret * scale;
>> +
>> +	return 0;
>> +}
>
>
>> +
>> +int cht_wc_fg_get_property(enum power_supply_property prop,
>> +			   union power_supply_propval *val)
>> +{
>> +	int ret = 0;
>
> Sounds like redundant assignment...

No longer redundant in v2.

>
>> +
>> +	mutex_lock(&cht_wc_fg_mutex);
>> +
>>
>
>> +	if (!cht_wc_fg) {
>> +		ret = -ENXIO;
>> +		goto out_unlock;
>> +	}
>
> ...otherwise maybe
>
> ret = cht_wc_fg ? 0 : -ENXIO;
> if (ret)
>  goto ...;
>
> ?

With the stand-alone power_supply driver version this ugliness is gone.

>
>> +	default:
>> +		ret = -ENODATA;
>> +	}
>> +out_unlock:
>> +	mutex_unlock(&cht_wc_fg_mutex);
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(cht_wc_fg_get_property);
>
>> +
>> +static int cht_wc_fg_probe(struct i2c_client *client,
>> +			const struct i2c_device_id *i2c_id)
>> +{
>> +	struct device *dev = &client->dev;
>> +	struct cht_wc_fg_data *fg;
>> +	acpi_status status;
>> +	unsigned long long ptyp;
>
>> +	status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP",
>> NULL, &ptyp);
>> +	if (ACPI_FAILURE(status)) {
>> +		dev_err(dev, "Failed to get PTYPE\n");
>> +		return -ENODEV;
>> +	}
>> +
>> +	/*
>> +	 * The same ACPI HID is used with different PMICs check PTYP
>> to
>> +	 * ensure that we are dealing with a Whiskey Cove PMIC.
>> +	 */
>> +	if (ptyp != CHT_WC_FG_PTYPE)
>> +		return -ENODEV;
>
> Logically I would split this part to be a main driver for device which
> would use actual driver based on this, though I think it too much churn
> for no benefit right now.

Ack.

>
>> +	mutex_lock(&cht_wc_fg_mutex);
>> +	cht_wc_fg = fg;
>> +	mutex_unlock(&cht_wc_fg_mutex);
>
> It's pity we have no common storage of single possible present device
> drivers in the kernel. I would use some kind of framework rather then
> keeping all those global variables with locking. Perhaps radix / RB
> tree.

With the stand-alone power_supply driver version this ugliness is gone.

Regards,

Hans

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

* Re: [PATCH 15/15] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS controller driver
  2017-03-17 18:22   ` Andy Shevchenko
@ 2017-03-23 13:58     ` Hans de Goede
  0 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-23 13:58 UTC (permalink / raw)
  To: Andy Shevchenko, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Lee Jones, Sebastian Reichel, MyungJoo Ham, Chanwoo Choi
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 17-03-17 19:22, Andy Shevchenko wrote:
> On Fri, 2017-03-17 at 10:55 +0100, Hans de Goede wrote:
>> The Intel Cherry Trail Whiskey Cove PMIC has a builtin SMBUS
>> controller
>> for talking to an external PMIC. Add a driver for this.
>
> Looking to all this mess we have with PMICs, perhaps some file under
> Documentation to explain all those dependencies with nice ASCII flow
> charts would be created.

With Sebastian's suggestion to turn the fuel-gauge driver
into a full-blown power_supply driver things luckily aren't
quite that messy anymore.

<snip>

>> +#define CHT_WC_I2C_CTRL			0x5e24
>> +#define CHT_WC_I2C_CTRL_WR		BIT(0)
>> +#define CHT_WC_I2C_CTRL_RD		BIT(1)
>> +#define CHT_WC_I2C_CLIENT_ADDR		0x5e25
>> +#define CHT_WC_I2C_REG_OFFSET		0x5e26
>> +#define CHT_WC_I2C_WRDATA		0x5e27
>> +#define CHT_WC_I2C_RDDATA		0x5e28
>> +
>> +#define CHT_WC_EXTCHGRIRQ		0x6e0a
>> +#define CHT_WC_EXTCHGRIRQ_CLIENT_IRQ	BIT(0)
>> +#define CHT_WC_EXTCHGRIRQ_WRITE_IRQ	BIT(1)
>> +#define CHT_WC_EXTCHGRIRQ_READ_IRQ	BIT(2)
>> +#define CHT_WC_EXTCHGRIRQ_NACK_IRQ	BIT(3)
>>
>
>> +#define CHT_WC_EXTCHGRIRQ_ADAP_IRQS	((u8)(BIT(1) | BIT(2) |
>> BIT(3)))
>
> _IRQ_MASK ?
>
> GENMASK() ?

Both good idea, both fixed for v2. Note I'm not posting
v2 until the bq24190_charger patches are in place
(so that the device-properties to use are known).

>> +#define CHT_WC_EXTCHGRIRQ_MSK		0x6e17
>
>> +struct cht_wc_i2c_adap {
>> +	struct i2c_adapter adapter;
>> +	wait_queue_head_t wait;
>> +	struct irq_chip irqchip;
>> +	struct mutex irqchip_lock;
>> +	struct regmap *regmap;
>> +	struct irq_domain *irq_domain;
>> +	struct i2c_client *client;
>> +	int client_irq;
>> +	u8 irq_mask;
>> +	u8 old_irq_mask;
>> +	bool nack;
>> +	bool done;
>> +};
>> +
>> +static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data)
>> +{
>> +	struct cht_wc_i2c_adap *adap = data;
>> +	int ret, reg;
>> +
>> +	/* Read irqs */
>
> IRQs
>
>> +	ret = regmap_read(adap->regmap, CHT_WC_EXTCHGRIRQ, &reg);
>> +	if (ret) {
>> +		dev_err(&adap->adapter.dev, "Error reading extchgrirq
>> reg\n");
>> +		return IRQ_NONE;
>> +	}
>> +
>> +	reg &= ~adap->irq_mask;
>> +
>> +	/*
>> +	 * Immediately ack irqs, so that if new irqs arrives while
>> we're
>> +	 * handling the previous ones our irq will re-trigger when
>> we're done.
>> +	 */
>> +	ret = regmap_write(adap->regmap, CHT_WC_EXTCHGRIRQ, reg);
>> +	if (ret)
>> +		dev_err(&adap->adapter.dev, "Error writing extchgrirq
>> reg\n");
>> +
>> +	/*
>> +	 * Do NOT use handle_nested_irq here, the client irq handler
>> will
>> +	 * likely want to do i2c transfers and the i2c controller
>> uses this
>> +	 * interrupt handler as well, so running the client irq
>> handler from
>> +	 * this thread will cause things to lock up.
>> +	 */
>> +	if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) {
>> +		/*
>> +		 * generic_handle_irq expects local irqs to be
>> disabled
>> +		 * as normally it is called from interrupt context.
>> +		 */
>> +		local_irq_disable();
>> +		generic_handle_irq(adap->client_irq);
>> +		local_irq_enable();
>> +	}
>> +
>> +	if (reg & CHT_WC_EXTCHGRIRQ_ADAP_IRQS) {
>
>> +		if (reg & CHT_WC_EXTCHGRIRQ_NACK_IRQ)
>> +			adap->nack = true;
>
> adap->nack = !!(reg & ...);

Good idea, fixed for v2.

>
>> +		adap->done = true;
>> +		wake_up(&adap->wait);
>> +	}
>> +
>> +	return IRQ_HANDLED;
>> +}
>
>> +static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap)
>> +{
>> +	/* This i2c adapter only supports smbus byte transfers */
>
> smbus -> SMBUS
>
>> +	return I2C_FUNC_SMBUS_BYTE_DATA;
>> +}
>> +
>> +static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16
>> addr,
>> +				      unsigned short flags, char
>> read_write,
>> +				      u8 command, int size,
>> +				      union i2c_smbus_data *data)
>> +{
>> +	struct cht_wc_i2c_adap *adap = i2c_get_adapdata(_adap);
>> +	int ret, reg;
>> +
>
>> +
>> +	/* 3 second timeout, during cable plug the PMIC responds
>> quite slow */
>> +	ret = wait_event_timeout(adap->wait, adap->done, HZ * 3);
>
> 3 * HZ

Fixed for v2 (as well as all the capitalization remarks)

>
>> +	if (ret == 0)
>> +		return -ETIMEDOUT;
>> +	if (adap->nack)
>> +		return -EIO;
>> +
>> +	if (read_write == I2C_SMBUS_READ) {
>> +		ret = regmap_read(adap->regmap, CHT_WC_I2C_RDDATA,
>> &reg);
>> +		if (ret)
>> +			return ret;
>> +
>> +		data->byte = reg;
>> +	}
>> +
>> +	return 0;
>> +}
>
>> +/**** irqchip for the client connected to the extchgr i2c adapter
>> ****/
>
> Useless ?

It is meant as a visual separator between the i2c-adapter and
irqchip code.

>
>> +static void cht_wc_i2c_irq_lock(struct irq_data *data)
>> +{
>> +	struct cht_wc_i2c_adap *adap =
>> irq_data_get_irq_chip_data(data);
>> +
>> +	mutex_lock(&adap->irqchip_lock);
>> +}
>> +
>> +static void cht_wc_i2c_irq_sync_unlock(struct irq_data *data)
>> +{
>> +	struct cht_wc_i2c_adap *adap =
>> irq_data_get_irq_chip_data(data);
>> +	int ret;
>> +
>> +	if (adap->irq_mask != adap->old_irq_mask) {
>> +		ret = regmap_write(adap->regmap,
>> CHT_WC_EXTCHGRIRQ_MSK,
>> +				   adap->irq_mask);
>> +		if (ret == 0)
>> +			adap->old_irq_mask = adap->irq_mask;
>> +		else
>> +			dev_err(&adap->adapter.dev, "Error writing
>> extchgrirq_msk\n");
>
> extchgrirq_msk -> EXTCHGRIRQ_MSK ?

Fixed for v2.

>> +	}
>> +
>> +	mutex_unlock(&adap->irqchip_lock);
>> +}
>
>
>> +static const struct bq24190_platform_data bq24190_pdata = {
>> +	.no_register_reset = true,
>> +	.extcon_name = "cht_wcove_pwrsrc",
>> +	.get_ext_bat_property = cht_wc_fg_get_property,
>> +};
>> +
>> +static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev)
>> +{
>> +	struct intel_soc_pmic *pmic = dev_get_drvdata(pdev-
>>> dev.parent);
>> +	struct cht_wc_i2c_adap *adap;
>
>> +	struct i2c_board_info board_info = {
>> +		.type = "bq24190",
>> +		.addr = 0x6b,
>> +		.platform_data = (void *)&bq24190_pdata,
>> +	};
>> +	int ret, irq;
>> +
>
>> +	/* Clear and activate i2c-adapter interrupts, disable client
>> irq */
>
> irq -> IRQ
>
>> +
>> +	/* Alloc and register client irq */
>
> Ditto.
>
>> +	adap->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
>> 1,
>> +						 &irq_domain_simple_o
>> ps, NULL);
>
> Can you use irq_domain_add_simple()?

We don't have (nor want) a static virq for the irq,
so we would pass 0 for irq_domain_add_simple()'s
first_irq argument which makes it equivalent to
irq_domain_add_linear but with one more function
argument and making it less clear what is going on.

> And why do we need separate domain for one IRQ line?

Every irq-chip needs its own domain to map its hwirq
numbers to virq numbers (which are globally unique).

>
>> +	if (!adap->irq_domain)
>> +		return -ENOMEM;
>> +
>> +	adap->client_irq = irq_create_mapping(adap->irq_domain, 0);
>> +	if (!adap->client_irq) {
>> +		ret = -ENOMEM;
>> +		goto remove_irq_domain;
>> +	}
>> +
>> +	irq_set_chip_data(adap->client_irq, adap);
>> +	irq_set_chip_and_handler(adap->client_irq, &adap->irqchip,
>> +				 handle_simple_irq);
>> +
>
>> +	board_info.irq = adap->client_irq;
>> +	adap->client = i2c_new_device(&adap->adapter, &board_info);
>> +	if (!adap->client) {
>> +		ret = -ENOMEM;
>> +		goto del_adapter;
>> +	}
>
> I would split this to some other module with board info.

We need both the adapter and the irq line to instantiate
the i2c-client for the external charger both of which are
readily available here.

> By the way, doesn't ACPI have the charger IC node?

There are several (disabled, _STA returns 0) ACPI nodes
for charger ICs in all the Cherrytrail DSTDs I've (all
DSTDs seem to be copy and paste from the same templates),
but none of them points to the i2c bus controlled by
the Whiskey Cove PMIC. Those nodes seem to all be
for when the charger IC is directly connected to one
of the designware-i2c busses. TL;DR: No there is no
ACPI node for the external charger IC in this case.

Regards,

Hans

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

* Re: [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver
  2017-03-21  5:16       ` Chanwoo Choi
@ 2017-03-23 15:22         ` Hans de Goede
  0 siblings, 0 replies; 46+ messages in thread
From: Hans de Goede @ 2017-03-23 15:22 UTC (permalink / raw)
  To: Chanwoo Choi, Rafael J . Wysocki, Len Brown, Wolfram Sang,
	Andy Shevchenko, Lee Jones, Sebastian Reichel, MyungJoo Ham
  Cc: linux-acpi, Takashi Iwai, linux-i2c, linux-kernel, linux-pm

Hi,

On 21-03-17 06:16, Chanwoo Choi wrote:
> Hi,
>
> On 2017년 03월 21일 04:57, Hans de Goede wrote:
>> Hi,
>>
>> On 20-03-17 02:33, Chanwoo Choi wrote:
>>> Hi,
>>>
>>> On 2017년 03월 17일 18:55, Hans de Goede wrote:
>>>> Add a driver for charger detection / control on the Intel Cherrytrail
>>>> Whiskey Cove PMIC.
>>>>
>>>> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
>>>> ---
>>>>  drivers/extcon/Kconfig         |   7 +
>>>>  drivers/extcon/Makefile        |   1 +
>>>>  drivers/extcon/extcon-cht-wc.c | 356 +++++++++++++++++++++++++++++++++++++++++
>>>>  3 files changed, 364 insertions(+)
>>>>  create mode 100644 drivers/extcon/extcon-cht-wc.c
>>>>
>>>> diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
>>>> index 96bbae5..4cace6b 100644
>>>> --- a/drivers/extcon/Kconfig
>>>> +++ b/drivers/extcon/Kconfig
>>>> @@ -52,6 +52,13 @@ config EXTCON_INTEL_INT3496
>>>>        This ACPI device is typically found on Intel Baytrail or Cherrytrail
>>>>        based tablets, or other Baytrail / Cherrytrail devices.
>>>>
>>>> +config EXTCON_CHT_WC
>>>
>>> Need to reorder it alpabetically as the following Makefile.
>>
>> The idea is to have the items alphabetically listed in "make menuconfig"
>> and the name of the menu item starts with Intel:
>
> If you want to locate it under the EXTCON_INTEL_INT3496,
> you should change the filename as following style:
> - extcon-intel-cht-wc.c
>
> I want to locate all entry alphabetically.

Ok, will fix for v3

>
>>
>>>
>>>> +    tristate "Intel Cherrytrail Whiskey Cove PMIC extcon driver"
>>>> +    depends on INTEL_SOC_PMIC_CHTWC
>>>> +    help
>>>> +      Say Y here to enable extcon support for charger detection / control
>>>> +      on the Intel Cherrytrail Whiskey Cove PMIC.
>>>> +
>>>>  config EXTCON_MAX14577
>>>>      tristate "Maxim MAX14577/77836 EXTCON Support"
>>>>      depends on MFD_MAX14577
>>>> diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
>>>> index 237ac3f..160f88b 100644
>>>> --- a/drivers/extcon/Makefile
>>>> +++ b/drivers/extcon/Makefile
>>>> @@ -7,6 +7,7 @@ extcon-core-objs        += extcon.o devres.o
>>>>  obj-$(CONFIG_EXTCON_ADC_JACK)    += extcon-adc-jack.o
>>>>  obj-$(CONFIG_EXTCON_ARIZONA)    += extcon-arizona.o
>>>>  obj-$(CONFIG_EXTCON_AXP288)    += extcon-axp288.o
>>>> +obj-$(CONFIG_EXTCON_CHT_WC)    += extcon-cht-wc.o
>>>>  obj-$(CONFIG_EXTCON_GPIO)    += extcon-gpio.o
>>>>  obj-$(CONFIG_EXTCON_INTEL_INT3496) += extcon-intel-int3496.o
>>>>  obj-$(CONFIG_EXTCON_MAX14577)    += extcon-max14577.o
>>>> diff --git a/drivers/extcon/extcon-cht-wc.c b/drivers/extcon/extcon-cht-wc.c
>>>> new file mode 100644
>>>> index 0000000..896eee6
>>>> --- /dev/null
>>>> +++ b/drivers/extcon/extcon-cht-wc.c
>>>> @@ -0,0 +1,356 @@
>>>> +/*
>>>> + * Extcon charger detection driver for Intel Cherrytrail Whiskey Cove PMIC
>>>> + * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com>
>>>> + *
>>>> + * Based on various non upstream patches to support the CHT Whiskey Cove PMIC:
>>>
>>> Maybe, you don't need to add ':' at the end of line.
>>
>> Th ':' is there because the following copyright line:
>>>
>>>> + * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
>>
>> Comes from those various non upstream patches.
>>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify it
>>>> + * under the terms and conditions of the GNU General Public License,
>>>> + * version 2, as published by the Free Software Foundation.
>>>> + *
>>>> + * This program is distributed in the hope it will be useful, but WITHOUT
>>>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>>>> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
>>>> + * more details.
>>>> + */
>>>> +
>>>> +#include <linux/extcon.h>
>>>> +#include <linux/interrupt.h>
>>>> +#include <linux/kernel.h>
>>>> +#include <linux/mfd/intel_soc_pmic.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/regmap.h>
>>>> +#include <linux/slab.h>
>>>> +
>>>> +#define CHT_WC_PWRSRC_IRQ        0x6e03
>>>> +#define CHT_WC_PWRSRC_IRQ_MASK        0x6e0f
>>>> +#define CHT_WC_PWRSRC_STS        0x6e1e
>>>> +#define CHT_WC_PWRSRC_VBUS        BIT(0)
>>>> +#define CHT_WC_PWRSRC_DC        BIT(1)
>>>> +#define CHT_WC_PWRSRC_BAT        BIT(2)
>>>> +#define CHT_WC_PWRSRC_ID_GND        BIT(3)
>>>> +#define CHT_WC_PWRSRC_ID_FLOAT        BIT(4)
>>>> +
>>>> +#define CHT_WC_PHYCTRL            0x5e07
>>>> +
>>>> +#define CHT_WC_CHGRCTRL0        0x5e16
>>>> +
>>>> +#define CHT_WC_CHGRCTRL0        0x5e16
>>>> +#define CHT_WC_CHGRCTRL0_CHGRRESET    BIT(0)
>>>> +#define CHT_WC_CHGRCTRL0_EMRGCHREN    BIT(1)
>>>> +#define CHT_WC_CHGRCTRL0_EXTCHRDIS    BIT(2)
>>>> +#define CHT_WC_CHGRCTRL0_SWCONTROL    BIT(3)
>>>> +#define CHT_WC_CHGRCTRL0_TTLCK_MASK    BIT(4)
>>>> +#define CHT_WC_CHGRCTRL0_CCSM_OFF_MASK    BIT(5)
>>>> +#define CHT_WC_CHGRCTRL0_DBPOFF_MASK    BIT(6)
>>>> +#define CHT_WC_CHGRCTRL0_WDT_NOKICK    BIT(7)
>>>> +
>>>> +#define CHT_WC_CHGRCTRL1        0x5e17
>>>> +
>>>> +#define CHT_WC_USBSRC            0x5e29
>>>> +#define CHT_WC_USBSRC_STS_MASK        GENMASK(1, 0)
>>>> +#define CHT_WC_USBSRC_STS_SUCCESS    2
>>>> +#define CHT_WC_USBSRC_STS_FAIL        3
>>>> +#define CHT_WC_USBSRC_TYPE_SHIFT    2
>>>> +#define CHT_WC_USBSRC_TYPE_MASK        GENMASK(5, 2)
>>>> +#define CHT_WC_USBSRC_TYPE_NONE        0
>>>> +#define CHT_WC_USBSRC_TYPE_SDP        1
>>>> +#define CHT_WC_USBSRC_TYPE_DCP        2
>>>> +#define CHT_WC_USBSRC_TYPE_CDP        3
>>>> +#define CHT_WC_USBSRC_TYPE_ACA        4
>>>> +#define CHT_WC_USBSRC_TYPE_SE1        5
>>>> +#define CHT_WC_USBSRC_TYPE_MHL        6
>>>> +#define CHT_WC_USBSRC_TYPE_FLOAT_DP_DN    7
>>>> +#define CHT_WC_USBSRC_TYPE_OTHER    8
>>>> +#define CHT_WC_USBSRC_TYPE_DCP_EXTPHY    9
>>>> +
>>>> +enum cht_wc_usb_id {
>>>> +    USB_ID_OTG,
>>>> +    USB_ID_GND,
>>>> +    USB_ID_FLOAT,
>>>> +    USB_RID_A,
>>>> +    USB_RID_B,
>>>> +    USB_RID_C,
>>>> +};
>>>> +
>>>> +/* Strings matching the cht_wc_usb_id enum labels */
>>>> +static const char * const usb_id_str[] = {
>>>> +    "otg", "gnd", "float", "rid_a", "rid_b", "rid_c" };
>>>> +
>>>> +enum cht_wc_mux_select {
>>>> +    MUX_SEL_PMIC = 0,
>>>> +    MUX_SEL_SOC,
>>>> +};
>>>> +
>>>> +static const unsigned int cht_wc_extcon_cables[] = {
>>>> +    EXTCON_USB,
>>>> +    EXTCON_USB_HOST,
>>>> +    EXTCON_CHG_USB_SDP,
>>>> +    EXTCON_CHG_USB_CDP,
>>>> +    EXTCON_CHG_USB_DCP,
>>>> +    EXTCON_NONE,
>>>> +};
>>>> +
>>>> +struct cht_wc_extcon_data {
>>>> +    struct device *dev;
>>>> +    struct regmap *regmap;
>>>> +    struct extcon_dev *edev;
>>>> +    unsigned int previous_cable;
>>>> +    int usb_id;
>>>> +};
>>>> +
>>>> +static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
>>>> +{
>>>> +    if (ext->usb_id)
>>>> +        return ext->usb_id;
>>>> +
>>>> +    if (pwrsrc_sts & CHT_WC_PWRSRC_ID_GND)
>>>> +        return USB_ID_GND;
>>>> +    if (pwrsrc_sts & CHT_WC_PWRSRC_ID_FLOAT)
>>>> +        return USB_ID_FLOAT;
>>>> +
>>>> +    /*
>>>> +     * Once we have iio support for the gpadc we should read the USBID
>>>> +     * gpadc channel here and determine ACA role based on that.
>>>> +     */
>>>> +    return USB_ID_FLOAT;
>>>> +}
>>>> +
>>>> +static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext)
>>>> +{
>>>> +    int ret, usbsrc, status, retries = 5;
>>>
>>> You have to define the constant for '5' because the name of constant
>>> definition indicates what is meaning. So, maybe you will use the 'for' loope
>>> instead of 'do..while'.
>>
>> Right, already fixed as a result of Andy's review.
>>
>>>
>>>> +
>>>> +    do {
>>>> +        ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc);
>>>> +        if (ret) {
>>>> +            dev_err(ext->dev, "Error reading usbsrc: %d\n", ret);
>>>> +            return ret;
>>>> +        }
>>>
>>> Need to add one blank line.
>>>
>>>> +        status = usbsrc & CHT_WC_USBSRC_STS_MASK;
>>>> +        if (status == CHT_WC_USBSRC_STS_SUCCESS ||
>>>> +            status == CHT_WC_USBSRC_STS_FAIL)
>>>> +            break;
>>>> +
>>>> +        msleep(200);
>>>
>>> You have to define the constant for '200' because the name of constant
>>> definition indicates what is meaning.
>>>
>>>> +    } while (retries--);
>>>> +
>>>> +    if (status != CHT_WC_USBSRC_STS_SUCCESS) {
>>>> +        if (status == CHT_WC_USBSRC_STS_FAIL)
>>>> +            dev_warn(ext->dev, "Could not detect charger type\n");
>>>> +        else
>>>> +            dev_warn(ext->dev, "Timeout detecting charger type\n");
>>>> +        return EXTCON_CHG_USB_SDP; /* Save fallback */
>>>> +    }
>>>> +
>>>> +    ret = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;
>>>
>>> 'ret' is not proper indicates the meaning of 'CHT_WC_USBSRC_TYPE'.
>>> You have to use the more correct local variable such as 'usbsrc_type'.
>>
>> Fixed for v2.
>>>
>>>> +    switch (ret) {
>>>> +    default:
>>>> +        dev_warn(ext->dev, "Unhandled charger type %d\n", ret);
>>>> +        /* Fall through treat as SDP */
>>>
>>> Is it right? Why do you located the 'default' on the top in the switch?
>>
>> So that I can use fall-through, there is no rule in C where the default goes.
>>
>> The fallthrough is there because assuming SDP (and thus max 500mA current
>> draw) is always safe.
>
> If in the default statement, you treat the unhandled charger type as the SDP,
> you don't remove the warning message. It makes the confusion.
>
> Warning message is 'unhandled charger type'. But, the extcon
> detects the 'SDP' connector type. It is not reasonable.

Ok, I will change the warning message to say that we are defaulting to
SDP.

>
>>
>>>
>>>> +    case CHT_WC_USBSRC_TYPE_SDP:
>>>> +    case CHT_WC_USBSRC_TYPE_FLOAT_DP_DN:
>>>> +    case CHT_WC_USBSRC_TYPE_OTHER:
>>>> +        return EXTCON_CHG_USB_SDP;
>>>> +    case CHT_WC_USBSRC_TYPE_CDP:
>>>> +        return EXTCON_CHG_USB_CDP;
>>>> +    case CHT_WC_USBSRC_TYPE_DCP:
>>>> +    case CHT_WC_USBSRC_TYPE_DCP_EXTPHY:
>>>> +    case CHT_WC_USBSRC_TYPE_MHL: /* MHL2+ delivers upto 2A, treat as DCP */
>>>> +        return EXTCON_CHG_USB_DCP;
>>>> +    case CHT_WC_USBSRC_TYPE_ACA:
>>>> +        return EXTCON_CHG_USB_ACA;
>>>> +    }
>>>> +}
>>>> +
>>>> +static void cht_wc_extcon_set_phymux(struct cht_wc_extcon_data *ext, u8 state)
>>>> +{
>>>> +    int ret;
>>>> +
>>>> +    ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state);
>>>> +    if (ret)
>>>> +        dev_err(ext->dev, "Error writing phyctrl: %d\n", ret);
>>>
>>> This function is only called in the cht_wc_extcon_det_event().
>>> Also, this funciton write only one register. It is too short.
>>> So, you don't need to add the separate function.
>>> You better to include this code in the cht_wc_extcon_det_event().
>>
>> This is used multiple times in cht_wc_extcon_det_event() and is
>> also used in probe() so it saves having to copy and paste the error
>> check. Also the flow of cht_wc_extcon_det_event() is more readable
>> this way. If it is more efficient to have this inline the compiler
>> will auto-inline it.
>
> OK. I recognized it was called only on the cht_wc_extcon_det_event().
> But, it is called on multiple points. It's OK.
>
>>
>>
>>>
>>>> +}
>>>> +
>>>> +static void cht_wc_extcon_det_event(struct cht_wc_extcon_data *ext)
>>>> +{
>>>> +    int ret, pwrsrc_sts, id;
>>>> +    unsigned int cable = EXTCON_NONE;
>>>> +
>>>> +    ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts);
>>>> +    if (ret) {
>>>> +        dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret);
>>>> +        return;
>>>> +    }
>>>> +
>>>> +    id = cht_wc_extcon_get_id(ext, pwrsrc_sts);
>>>> +    if (id == USB_ID_GND) {
>>>> +        /* The 5v boost causes a false VBUS / SDP detect, skip */
>>>> +        goto charger_det_done;
>>>> +    }
>>>> +
>>>> +    /* Plugged into a host/charger or not connected? */
>>>> +    if (!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)) {
>>>> +        /* Route D+ and D- to PMIC for future charger detection */
>>>> +        cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
>>>> +        goto set_state;
>>>> +    }
>>>
>>> The cht_wc_extcon_get_id() and cht_wc_extcon_det_event() use the value
>>> of CHT_WC_PWRSRC_STS register. So, I think you better to gather the
>>> code related to the CHT_WC_PWRSRC_STS for readability.
>>> - First suggestion, remove the separate the cht_wc_extcon_get_id()
>>> - Second suggestion, The code from regmap_read() to "!(pwrsrc_sts & CHT_WC_PWRSRC_VBUS)"
>>>           move into the cht_wc_extcon_get_id().
>>>
>>> In my opinion, I recommend that second way.
>>
>> These register reads are i2c register reads which are quite costly,
>> so we really want to do this only once, which is why the code is
>> as it is.
>
> Sure, If you use the my second suggestion, you can read i2c register
> only one time for all codes as following:
>
> 	cht_wc_extcon_get_id(ext)
> 		// Read the CHT_WC_PWRSRC_STS register through i2c
> 		// Check the usb_id and pwersrc_sts with CHT_WC_PWRSRC_ID_GND/CHT_WC_PWRSRC_ID_FLOAT.
> 		// Plugged into a host/charger or not connected?
>>
>>>> +
>>>> +    ret = cht_wc_extcon_get_charger(ext);
>>>> +    if (ret >= 0)
>>>> +        cable = ret;
>>>> +
>>>> +charger_det_done:
>>>> +    /* Route D+ and D- to SoC for the host / gadget controller */
>>>
>>> Minor comment.
>>> You better to use '&' instead of '/'
>>
>> The data lines get used by either the host OR the gadget controller,
>> as there is another mux inside the SoC.
>
> If '/' means the 'or', you can use the 'or' instead of '/'.

Ok text changed to use or for v3.

>
>>
>>>
>>>> +    cht_wc_extcon_set_phymux(ext, MUX_SEL_SOC);
>>>> +
>>>> +set_state:
>>>> +    extcon_set_state_sync(ext->edev, cable, true);
>>>> +    extcon_set_state_sync(ext->edev, ext->previous_cable, false);
>>>> +    extcon_set_state_sync(ext->edev, EXTCON_USB_HOST,
>>>> +                  id == USB_ID_GND || id == USB_RID_A);
>>>> +    ext->previous_cable = cable;
>>>> +}
>>>> +
>>>> +static irqreturn_t cht_wc_extcon_isr(int irq, void *data)
>>>> +{
>>>> +    struct cht_wc_extcon_data *ext = data;
>>>> +    int ret, irqs;
>>>> +
>>>> +    ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs);
>>>> +    if (ret)
>>>> +        dev_err(ext->dev, "Error reading irqs: %d\n", ret);
>>>> +
>>>> +    cht_wc_extcon_det_event(ext);
>>>> +
>>>> +    ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs);
>>>> +    if (ret)
>>>> +        dev_err(ext->dev, "Error writing irqs: %d\n", ret);
>>>> +
>>>> +    return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +/* usb_id sysfs attribute for debug / testing purposes */
>>>> +static ssize_t usb_id_show(struct device *dev, struct device_attribute *attr,
>>>> +               char *buf)
>>>> +{
>>>> +    struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
>>>> +
>>>> +    return sprintf(buf, "%s\n", usb_id_str[ext->usb_id]);
>>>> +}
>>>> +
>>>> +static ssize_t usb_id_store(struct device *dev, struct device_attribute *attr,
>>>> +                const char *buf, size_t n)
>>>> +{
>>>> +    struct cht_wc_extcon_data *ext = dev_get_drvdata(dev);
>>>> +    int i;
>>>> +
>>>> +    for (i = 0; i < ARRAY_SIZE(usb_id_str); i++) {
>>>> +        if (sysfs_streq(buf, usb_id_str[i])) {
>>>> +            dev_info(ext->dev, "New usb_id %s\n", usb_id_str[i]);
>>>> +            ext->usb_id = i;
>>>> +            cht_wc_extcon_det_event(ext);
>>>> +            return n;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    return -EINVAL;
>>>> +}
>>>> +
>>>> +static DEVICE_ATTR(usb_id, 0644, usb_id_show, usb_id_store);
>>>
>>> I think it is not good to add specific sysfs for only this device driver.
>>> The sysfs entry of framework must include the only common and standard interfarce
>>> for all extcon device drivers. Because the sysfs entry affects the ABI interface.
>>>
>>> So, It is not proper.
>>
>> Unfortunately these kinda sysfs files are somewhat normal when
>> dealing with USB-OTG. For example my board does not have the
>> id-pin hooked up to the connector, so to test host mode
>> I need to echo "gnd" to the sysfs attr. But also if I actually
>> want to use host-mode (or anyone else with the same or a similar
>> board).
>
> As I said, I don't want to create the non-standard sysfs interface
> for only specific device driver.
>
> If you want to change the some mode of device driver,
> we should implement the something in the extcon framework
> by keeping the standard interface for ABI. I don't want to
> make such a special case.

Ok, I will drop this part of the driver for now, we can revisit
this later.

>> See for example also the "mode" sysfs attribute of the musb driver.
>>
>> Since the id-pin setting influences multiple other drivers through
>> extcon the best place for this is in the extcon driver, as that
>> it the canonical source of the EXTCON_USB_HOST cable value.
>>
>>
>>>
>>>> +
>>>> +static int cht_wc_extcon_probe(struct platform_device *pdev)
>>>> +{
>>>> +    struct cht_wc_extcon_data *ext;
>>>> +    struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
>>>> +    int irq, ret;
>>>> +
>>>> +    irq = platform_get_irq(pdev, 0);
>>>> +    if (irq < 0)
>>>> +        return irq;
>>>> +
>>>> +    ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL);
>>>> +    if (!ext)
>>>> +        return -ENOMEM;
>>>> +
>>>> +    ext->dev = &pdev->dev;
>>>> +    ext->regmap = pmic->regmap;
>>>> +    ext->previous_cable = EXTCON_NONE;
>>>> +
>>>> +    /* Initialize extcon device */
>>>> +    ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables);
>>>> +    if (IS_ERR(ext->edev))
>>>> +        return PTR_ERR(ext->edev);
>>>> +
>>>> +    ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0,
>>>> +         CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK,
>>>> +         CHT_WC_CHGRCTRL0_SWCONTROL | CHT_WC_CHGRCTRL0_CCSM_OFF_MASK);
>>>> +    if (ret) {
>>>> +        dev_err(ext->dev, "Error enabling sw control\n");
>>>> +        return ret;
>>>> +    }
>>>> +
>>>> +    /* Register extcon device */
>>>> +    ret = devm_extcon_dev_register(ext->dev, ext->edev);
>>>> +    if (ret) {
>>>> +        dev_err(ext->dev, "Failed to register extcon device\n");
>>>> +        return ret;
>>>> +    }
>>>> +
>>>> +    /* Route D+ and D- to PMIC for initial charger detection */
>>>> +    cht_wc_extcon_set_phymux(ext, MUX_SEL_PMIC);
>>>> +
>>>> +    /* Get initial state */
>>>> +    cht_wc_extcon_det_event(ext);
>>>> +
>>>> +    ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr,
>>>> +                    IRQF_ONESHOT, pdev->name, ext);
>>>> +    if (ret) {
>>>> +        dev_err(ext->dev, "Failed to request interrupt\n");
>>>> +        return ret;
>>>> +    }
>>>> +
>>>> +    /* Unmask irqs */
>>>> +    ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK,
>>>> +               (int)~(CHT_WC_PWRSRC_VBUS | CHT_WC_PWRSRC_ID_GND |
>>>> +                  CHT_WC_PWRSRC_ID_FLOAT));
>>>> +    if (ret) {
>>>> +        dev_err(ext->dev, "Error writing irq-mask: %d\n", ret);
>>>
>>> I prefer to use the consistent error log. In the probe function,
>>> you use the 'Failed to ...' when error hanppen. So, You better
>>> to use the consistent format for errr log as following:
>>>     - "Failed to write the irq-mask: %d\n", ret);
>>
>> Fixed for v2.
>>
>>>
>>> I think it improve the readability of your device driver.
>>>
>>>> +        return ret;
>>>> +    }
>>>> +
>>>> +    platform_set_drvdata(pdev, ext);
>>>> +    device_create_file(ext->dev, &dev_attr_usb_id);
>>>> +
>>>> +    return 0;
>>>
>>>
>>> In the probe function, you touch the some register for initialization.
>>> But, if error happen, the probe function don't restore the register value.
>>> Is it ok? I think you need to handle the error case.
>>
>> Fixed for v2.
>>
>>>
>>>> +}
>>>> +
>>>> +static int cht_wc_extcon_remove(struct platform_device *pdev)
>>>> +{
>>>> +    struct cht_wc_extcon_data *ext = platform_get_drvdata(pdev);
>>>> +
>>>> +    device_remove_file(ext->dev, &dev_attr_usb_id);
>>>
>>> Don't need it.
>>>
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static const struct platform_device_id cht_wc_extcon_table[] = {
>>>> +    { .name = "cht_wcove_pwrsrc" },
>>>
>>> You use the 'cht_wc' word instead of 'cht_wcove_pwrsrc'.
>>> So, To maintain the consistency, you better to use the 'cht-wc' as the name.
>>> - I prefer to use '-' instead of '_' in the name.
>>>     .name ="cht-wc"
>>
>> Already answered by Andy.
>
> I replied again from the Andy's reply.
>
>>
>>>> +    {},
>>>> +};
>>>> +MODULE_DEVICE_TABLE(platform, cht_wc_extcon_table);
>>>> +
>>>> +static struct platform_driver cht_wc_extcon_driver = {
>>>> +    .probe = cht_wc_extcon_probe,
>>>> +    .remove = cht_wc_extcon_remove,
>>>> +    .id_table = cht_wc_extcon_table,
>>>> +    .driver = {
>>>> +        .name = "cht_wcove_pwrsrc",
>>>> +    },
>>>> +};
>>>> +module_platform_driver(cht_wc_extcon_driver);
>>>> +
>>>> +MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
>>>> +MODULE_DESCRIPTION("Intel Cherrytrail Whiskey Cove PMIC extcon driver");
>>>
>>> Minor comment.
>>> You better to locate the MODULE_DESCRIPTION at the first line
>>> and then MODULE_AUTHOR is at second line.
>>
>> Fixed for v2.

Regards,

Hans

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

end of thread, other threads:[~2017-03-23 15:22 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-17  9:55 [PATCH 00/15] Add Intel Cherry Trail Whiskey Cove PMIC support Hans de Goede
2017-03-17  9:55 ` [PATCH 01/15] mfd: Add Cherry Trail Whiskey Cove PMIC driver Hans de Goede
2017-03-17 17:00   ` Andy Shevchenko
2017-03-20 10:41     ` Lee Jones
2017-03-20 12:55       ` Andy Shevchenko
2017-03-17  9:55 ` [PATCH 02/15] ACPI / PMIC: Add opregion driver for Intel CHT Whiskey Cove PMIC Hans de Goede
2017-03-17  9:55 ` [PATCH 03/15] extcon: cht-wc: Add Intel Cherry Trail Whiskey Cove PMIC extcon driver Hans de Goede
2017-03-17 17:18   ` Andy Shevchenko
2017-03-20 18:08     ` Hans de Goede
2017-03-20  1:33   ` Chanwoo Choi
2017-03-20 13:00     ` Andy Shevchenko
2017-03-21  3:54       ` Chanwoo Choi
2017-03-21  5:21         ` Chanwoo Choi
2017-03-21  6:27           ` Chanwoo Choi
2017-03-20 19:57     ` Hans de Goede
2017-03-21  5:16       ` Chanwoo Choi
2017-03-23 15:22         ` Hans de Goede
2017-03-17  9:55 ` [PATCH 04/15] power: supply: bq24190_charger: Add no_register_reset pdata flag Hans de Goede
2017-03-17 17:20   ` Andy Shevchenko
2017-03-17  9:55 ` [PATCH 05/15] power: supply: bq24190_charger: Limit charging voltage to 4.3V Hans de Goede
2017-03-17  9:55 ` [PATCH 06/15] power: supply: bq24190_charger: Use i2c-core irq-mapping code Hans de Goede
2017-03-17 17:24   ` Andy Shevchenko
2017-03-20  4:46     ` Sebastian Reichel
2017-03-17  9:55 ` [PATCH 07/15] power: supply: bq24190_charger: Add support for bq24192[i] Hans de Goede
2017-03-17  9:55 ` [PATCH 08/15] power: supply: bq24190_charger: Add support for external fuel gauge Hans de Goede
2017-03-17  9:55 ` [PATCH 09/15] power: supply: bq24190_charger: Add voltage_max_design prop to battery Hans de Goede
2017-03-20  5:12   ` Sebastian Reichel
2017-03-17  9:55 ` [PATCH 10/15] power: supply: bq24190_charger: Use extcon to determine ilimit, 5v boost Hans de Goede
2017-03-17 17:33   ` Andy Shevchenko
2017-03-20 22:38     ` Hans de Goede
2017-03-20  4:52   ` Sebastian Reichel
2017-03-17  9:55 ` [PATCH 11/15] i2c: core: Allow getting ACPI info by index Hans de Goede
2017-03-17 17:35   ` Andy Shevchenko
2017-03-17  9:55 ` [PATCH 12/15] i2c: core: Add new i2c_acpi_new_device helper function Hans de Goede
2017-03-17 17:37   ` Andy Shevchenko
2017-03-22 15:59     ` Hans de Goede
2017-03-17  9:55 ` [PATCH 13/15] i2c: core: Allow drivers to specify index for irq to get from of / ACPI Hans de Goede
2017-03-17 17:41   ` Andy Shevchenko
2017-03-20  8:55   ` kbuild test robot
2017-03-17  9:55 ` [PATCH 14/15] power: supply: Add driver for Cherry Trail Whiskey Cove PMIC Fuel Gauge Hans de Goede
2017-03-17 17:58   ` Andy Shevchenko
2017-03-22 17:03     ` Hans de Goede
2017-03-20  5:07   ` Sebastian Reichel
2017-03-17  9:55 ` [PATCH 15/15] i2c-cht-wc: Add Intel Cherry Trail Whiskey Cove SMBUS controller driver Hans de Goede
2017-03-17 18:22   ` Andy Shevchenko
2017-03-23 13:58     ` Hans de Goede

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).