All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
@ 2017-03-27 13:27 Hans de Goede
  2017-03-27 18:05 ` kbuild test robot
  0 siblings, 1 reply; 10+ messages in thread
From: Hans de Goede @ 2017-03-27 13:27 UTC (permalink / raw)
  To: Andy Shevchenko, Lee Jones
  Cc: Hans de Goede, linux-kernel, 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>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.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
Changes in v4:
-Use PLATFORM_DEVID_NONE
Changes in v5:
-Change Kconfig option from tristate to boolean and add a select for the
 i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
 OPRegion handler, which must be available before other drivers using it
 are loaded, which can only be ensured if the mfd, opregion and i2c-bus
 drivers are built in. This fixes errors like these during boot:
 mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA
 ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] (20170119/evregion-166)
 ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-299)
 ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93543b0cde10), AE_NOT_EXIST (20170119/psparse-543)
 ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b0b5cd0), AE_NOT_EXIST (20170119/psparse-543)
 acpi 80860F14:02: Failed to change power state to D0
-Some minor style and capitalization fixes from review by Lee Jones
Changes in v6:
-Fix Kconfig depends and selects to fix warning reported by kbuild test robot
---
 drivers/mfd/Kconfig                |  17 +++
 drivers/mfd/Makefile               |   1 +
 drivers/mfd/intel_soc_pmic_chtwc.c | 239 +++++++++++++++++++++++++++++++++++++
 3 files changed, 257 insertions(+)
 create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 55ecdfb..2c34574 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -437,6 +437,23 @@ config INTEL_SOC_PMIC
 	  thermal, charger and related power management functions
 	  on these systems.
 
+config INTEL_SOC_PMIC_CHTWC
+	# This is a bool as it provides an ACPI Opregion which must be
+	# available as soon as possible
+	bool "Support for Intel Cherry Trail Whiskey Cove PMIC"
+	depends on ACPI && HAS_IOMEM
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	# In order for the ACPI Opregion to be available the i2c-adapter
+	# driver must be builtin too, select it and its deps
+	select I2C
+	select COMMON_CLK
+	select I2C_DESIGNWARE_PLATFORM
+	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..8665269
--- /dev/null
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -0,0 +1,239 @@
+/*
+ * 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 of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#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, PLATFORM_DEVID_NONE,
+				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] 10+ messages in thread

* Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-03-27 13:27 [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver Hans de Goede
@ 2017-03-27 18:05 ` kbuild test robot
  0 siblings, 0 replies; 10+ messages in thread
From: kbuild test robot @ 2017-03-27 18:05 UTC (permalink / raw)
  To: Hans de Goede
  Cc: kbuild-all, Andy Shevchenko, Lee Jones, Hans de Goede,
	linux-kernel, Bin Gao, Felipe Balbi

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

Hi Hans,

[auto build test ERROR on ljones-mfd/for-mfd-next]
[also build test ERROR on v4.11-rc4 next-20170327]
[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/mfd-Add-Cherry-Trail-Whiskey-Cove-PMIC-driver/20170327-235905
base:   https://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git for-mfd-next
config: ia64-allmodconfig (attached as .config)
compiler: ia64-linux-gcc (GCC) 6.2.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=ia64 

All error/warnings (new ones prefixed by >>):

>> drivers//clocksource/timer-sun5i.c:52:21: error: field 'clksrc' has incomplete type
     struct clocksource clksrc;
                        ^~~~~~
>> drivers//clocksource/timer-sun5i.c:60:28: error: field 'clkevt' has incomplete type
     struct clock_event_device clkevt;
                               ^~~~~~
   In file included from include/linux/clk.h:16:0,
                    from drivers//clocksource/timer-sun5i.c:13:
   drivers//clocksource/timer-sun5i.c: In function 'sun5i_clkevt_shutdown':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
>> drivers//clocksource/timer-sun5i.c:108:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
>> drivers//clocksource/timer-sun5i.c:108:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c: In function 'sun5i_clkevt_set_oneshot':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c:116:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c:116:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c: In function 'sun5i_clkevt_set_periodic':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c:125:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c:125:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c: In function 'sun5i_clkevt_next_event':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c:136:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c:136:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c: In function 'sun5i_clksrc_read':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/timer-sun5i.c:56:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clksrc, clksrc)
     ^~~~~~~~~~~~
>> drivers//clocksource/timer-sun5i.c:157:34: note: in expansion of macro 'to_sun5i_timer_clksrc'
     struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'cs')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/timer-sun5i.c:56:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clksrc, clksrc)
     ^~~~~~~~~~~~
>> drivers//clocksource/timer-sun5i.c:157:34: note: in expansion of macro 'to_sun5i_timer_clksrc'
     struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/timer-sun5i.c: In function 'sun5i_rate_cb_clksrc':
>> drivers//clocksource/timer-sun5i.c:171:3: error: implicit declaration of function 'clocksource_unregister' [-Werror=implicit-function-declaration]
      clocksource_unregister(&cs->clksrc);
      ^~~~~~~~~~~~~~~~~~~~~~
--
>> drivers//clocksource/cadence_ttc_timer.c:92:21: error: field 'cs' has incomplete type
     struct clocksource cs;
                        ^~
>> drivers//clocksource/cadence_ttc_timer.c:100:28: error: field 'ce' has incomplete type
     struct clock_event_device ce;
                               ^~
   In file included from include/linux/clk.h:16:0,
                    from drivers//clocksource/cadence_ttc_timer.c:18:
   drivers//clocksource/cadence_ttc_timer.c: In function '__ttc_clocksource_read':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/cadence_ttc_timer.c:96:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clocksource, cs)
      ^~~~~~~~~~~~
>> drivers//clocksource/cadence_ttc_timer.c:163:29: note: in expansion of macro 'to_ttc_timer_clksrc'
     struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc;
                                ^~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'timer')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
>> drivers//clocksource/cadence_ttc_timer.c:96:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clocksource, cs)
      ^~~~~~~~~~~~
>> drivers//clocksource/cadence_ttc_timer.c:163:29: note: in expansion of macro 'to_ttc_timer_clksrc'
     struct ttc_timer *timer = &to_ttc_timer_clksrc(cs)->ttc;
                                ^~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: In function 'ttc_set_next_event':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
>> drivers//clocksource/cadence_ttc_timer.c:185:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ttce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
>> drivers//clocksource/cadence_ttc_timer.c:185:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: In function 'ttc_shutdown':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c:199:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ttce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c:199:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: In function 'ttc_set_periodic':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c:211:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ttce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c:211:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: In function 'ttc_resume':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c:221:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ttce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers//clocksource/cadence_ttc_timer.c:104:3: note: in expansion of macro 'container_of'
      container_of(x, struct ttc_timer_clockevent, ce)
      ^~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c:221:38: note: in expansion of macro 'to_ttc_timer_clkevent'
     struct ttc_timer_clockevent *ttce = to_ttc_timer_clkevent(evt);
                                         ^~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: In function 'ttc_setup_clocksource':
>> drivers//clocksource/cadence_ttc_timer.c:358:19: error: implicit declaration of function 'CLOCKSOURCE_MASK' [-Werror=implicit-function-declaration]
     ttccs->cs.mask = CLOCKSOURCE_MASK(timer_width);
                      ^~~~~~~~~~~~~~~~
>> drivers//clocksource/cadence_ttc_timer.c:359:20: error: 'CLOCK_SOURCE_IS_CONTINUOUS' undeclared (first use in this function)
     ttccs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
                       ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c:359:20: note: each undeclared identifier is reported only once for each function it appears in
>> drivers//clocksource/cadence_ttc_timer.c:372:8: error: implicit declaration of function 'clocksource_register_hz' [-Werror=implicit-function-declaration]
     err = clocksource_register_hz(&ttccs->cs, ttccs->ttc.freq / PRESCALE);
           ^~~~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: In function 'ttc_rate_change_clockevent_cb':
>> drivers//clocksource/cadence_ttc_timer.c:398:3: error: implicit declaration of function 'clockevents_update_freq' [-Werror=implicit-function-declaration]
      clockevents_update_freq(&ttcce->ce, ndata->new_rate / PRESCALE);
      ^~~~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: In function 'ttc_setup_clockevent':
>> drivers//clocksource/cadence_ttc_timer.c:441:23: error: 'CLOCK_EVT_FEAT_PERIODIC' undeclared (first use in this function)
     ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
                          ^~~~~~~~~~~~~~~~~~~~~~~
>> drivers//clocksource/cadence_ttc_timer.c:441:49: error: 'CLOCK_EVT_FEAT_ONESHOT' undeclared (first use in this function)
     ttcce->ce.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
                                                    ^~~~~~~~~~~~~~~~~~~~~~
>> drivers//clocksource/cadence_ttc_timer.c:468:2: error: implicit declaration of function 'clockevents_config_and_register' [-Werror=implicit-function-declaration]
     clockevents_config_and_register(&ttcce->ce,
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers//clocksource/cadence_ttc_timer.c: At top level:
--
   drivers/clocksource/timer-sun5i.c:52:21: error: field 'clksrc' has incomplete type
     struct clocksource clksrc;
                        ^~~~~~
   drivers/clocksource/timer-sun5i.c:60:28: error: field 'clkevt' has incomplete type
     struct clock_event_device clkevt;
                               ^~~~~~
   In file included from include/linux/clk.h:16:0,
                    from drivers/clocksource/timer-sun5i.c:13:
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_clkevt_shutdown':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:108:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:108:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_clkevt_set_oneshot':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:116:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:116:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_clkevt_set_periodic':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:125:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:125:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_clkevt_next_event':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:136:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'ce')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:64:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clkevt, clkevt)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:136:34: note: in expansion of macro 'to_sun5i_timer_clkevt'
     struct sun5i_timer_clkevt *ce = to_sun5i_timer_clkevt(clkevt);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_clksrc_read':
>> include/linux/kernel.h:852:48: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types]
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:56:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clksrc, clksrc)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:157:34: note: in expansion of macro 'to_sun5i_timer_clksrc'
     struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
                                     ^~~~~~~~~~~~~~~~~~~~~
   include/linux/kernel.h:852:48: note: (near initialization for 'cs')
     const typeof( ((type *)0)->member ) *__mptr = (ptr); \
                                                   ^
   drivers/clocksource/timer-sun5i.c:56:2: note: in expansion of macro 'container_of'
     container_of(x, struct sun5i_timer_clksrc, clksrc)
     ^~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:157:34: note: in expansion of macro 'to_sun5i_timer_clksrc'
     struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
                                     ^~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_rate_cb_clksrc':
   drivers/clocksource/timer-sun5i.c:171:3: error: implicit declaration of function 'clocksource_unregister' [-Werror=implicit-function-declaration]
      clocksource_unregister(&cs->clksrc);
      ^~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:175:3: error: implicit declaration of function 'clocksource_register_hz' [-Werror=implicit-function-declaration]
      clocksource_register_hz(&cs->clksrc, ndata->new_rate);
      ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_setup_clocksource':
   drivers/clocksource/timer-sun5i.c:223:20: error: implicit declaration of function 'CLOCKSOURCE_MASK' [-Werror=implicit-function-declaration]
     cs->clksrc.mask = CLOCKSOURCE_MASK(32);
                       ^~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:224:21: error: 'CLOCK_SOURCE_IS_CONTINUOUS' undeclared (first use in this function)
     cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:224:21: note: each undeclared identifier is reported only once for each function it appears in
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_rate_cb_clkevt':
   drivers/clocksource/timer-sun5i.c:251:3: error: implicit declaration of function 'clockevents_update_freq' [-Werror=implicit-function-declaration]
      clockevents_update_freq(&ce->clkevt, ndata->new_rate);
      ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: In function 'sun5i_setup_clockevent':
   drivers/clocksource/timer-sun5i.c:291:24: error: 'CLOCK_EVT_FEAT_PERIODIC' undeclared (first use in this function)
     ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
                           ^~~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:291:50: error: 'CLOCK_EVT_FEAT_ONESHOT' undeclared (first use in this function)
     ce->clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
                                                     ^~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:305:2: error: implicit declaration of function 'clockevents_config_and_register' [-Werror=implicit-function-declaration]
     clockevents_config_and_register(&ce->clkevt, rate,
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c: At top level:
   drivers/clocksource/timer-sun5i.c:361:35: error: expected ')' before string constant
    CLOCKSOURCE_OF_DECLARE(sun5i_a13, "allwinner,sun5i-a13-hstimer",
                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:363:35: error: expected ')' before string constant
    CLOCKSOURCE_OF_DECLARE(sun7i_a20, "allwinner,sun7i-a20-hstimer",
                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/clocksource/timer-sun5i.c:326:19: warning: 'sun5i_timer_init' defined but not used [-Wunused-function]
    static int __init sun5i_timer_init(struct device_node *node)
                      ^~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors
..

vim +852 include/linux/kernel.h

^1da177e Linus Torvalds 2005-04-16  846   * @ptr:	the pointer to the member.
^1da177e Linus Torvalds 2005-04-16  847   * @type:	the type of the container struct this is embedded in.
^1da177e Linus Torvalds 2005-04-16  848   * @member:	the name of the member within the struct.
^1da177e Linus Torvalds 2005-04-16  849   *
^1da177e Linus Torvalds 2005-04-16  850   */
^1da177e Linus Torvalds 2005-04-16  851  #define container_of(ptr, type, member) ({			\
^1da177e Linus Torvalds 2005-04-16 @852  	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
^1da177e Linus Torvalds 2005-04-16  853  	(type *)( (char *)__mptr - offsetof(type,member) );})
^1da177e Linus Torvalds 2005-04-16  854  
b9d4f426 Arnaud Lacombe 2011-07-25  855  /* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */

:::::: The code at line 852 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: 48295 bytes --]

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

* Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-05-21  9:51       ` Hans de Goede
@ 2017-05-21 19:05         ` Paul Gortmaker
  0 siblings, 0 replies; 10+ messages in thread
From: Paul Gortmaker @ 2017-05-21 19:05 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Lee Jones, LKML, Bin Gao, Felipe Balbi, Andy Shevchenko

[Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver] On 21/05/2017 (Sun 11:51) Hans de Goede wrote:

> Hi,
> 
> On 20-05-17 21:26, Paul Gortmaker wrote:
> >On Sat, May 20, 2017 at 3:21 PM, Paul Gortmaker
> ><paul.gortmaker@windriver.com> wrote:
> >>On Mon, May 15, 2017 at 2:20 PM, Hans de Goede <hdegoede@redhat.com> wrote:
> >>>Hi,
> >>>
> >>>This is actually v7, with the following changes:
> >>>
> >>>Changes in v7:
> >>>-Add explanation why this is a bool and why it selects i2c-designwaree
> >
> >Gah -- I missed the explanation mentioned above:
> >
> >-Change Kconfig option from tristate to boolean and add a select for the
> >  i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
> >  OPRegion handler, which must be available before other drivers using it
> >  are loaded, which can only be ensured if the mfd, opregion and i2c-bus
> >  drivers are built in
> >
> >Given that, can we get rid of the modular macros in the code now as well?
> 
> Yes we can, to be clear you are talking about dropping:
> 
> MODULE_DEVICE_TABLE(i2c, cht_wc_i2c_id);
> MODULE_DEVICE_TABLE(acpi, cht_wc_acpi_ids);
> MODULE_LICENSE("GPL v2");
> MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
> 
> And replacing:
> 
> module_i2c_driver(cht_wc_driver);
> 
> with:
> 
> builtin_i2c_driver(cht_wc_driver);

Yes.

> 
> Right ?
> 
> Anything I'm missing ?

Delete the include of <module.h> and perhaps replace it with <init.h> as
required, depending on whether your file already has it and or uses the
__init prefixes.

> 
> If not I will post a new version with these removed / replaced.

Great, thanks a lot.
Paul.
--

> 
> Regards,
> 
> Hans

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

* Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-05-20 19:26     ` Paul Gortmaker
@ 2017-05-21  9:51       ` Hans de Goede
  2017-05-21 19:05         ` Paul Gortmaker
  0 siblings, 1 reply; 10+ messages in thread
From: Hans de Goede @ 2017-05-21  9:51 UTC (permalink / raw)
  To: Paul Gortmaker; +Cc: Lee Jones, LKML, Bin Gao, Felipe Balbi, Andy Shevchenko

Hi,

On 20-05-17 21:26, Paul Gortmaker wrote:
> On Sat, May 20, 2017 at 3:21 PM, Paul Gortmaker
> <paul.gortmaker@windriver.com> wrote:
>> On Mon, May 15, 2017 at 2:20 PM, Hans de Goede <hdegoede@redhat.com> wrote:
>>> Hi,
>>>
>>> This is actually v7, with the following changes:
>>>
>>> Changes in v7:
>>> -Add explanation why this is a bool and why it selects i2c-designwaree
> 
> Gah -- I missed the explanation mentioned above:
> 
> -Change Kconfig option from tristate to boolean and add a select for the
>   i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
>   OPRegion handler, which must be available before other drivers using it
>   are loaded, which can only be ensured if the mfd, opregion and i2c-bus
>   drivers are built in
> 
> Given that, can we get rid of the modular macros in the code now as well?

Yes we can, to be clear you are talking about dropping:

MODULE_DEVICE_TABLE(i2c, cht_wc_i2c_id);
MODULE_DEVICE_TABLE(acpi, cht_wc_acpi_ids);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");

And replacing:

module_i2c_driver(cht_wc_driver);

with:

builtin_i2c_driver(cht_wc_driver);

Right ?

Anything I'm missing ?

If not I will post a new version with these removed / replaced.

Regards,

Hans

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

* Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-05-20 19:21   ` Paul Gortmaker
@ 2017-05-20 19:26     ` Paul Gortmaker
  2017-05-21  9:51       ` Hans de Goede
  0 siblings, 1 reply; 10+ messages in thread
From: Paul Gortmaker @ 2017-05-20 19:26 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Lee Jones, LKML, Bin Gao, Felipe Balbi, Andy Shevchenko

On Sat, May 20, 2017 at 3:21 PM, Paul Gortmaker
<paul.gortmaker@windriver.com> wrote:
> On Mon, May 15, 2017 at 2:20 PM, Hans de Goede <hdegoede@redhat.com> wrote:
>> Hi,
>>
>> This is actually v7, with the following changes:
>>
>> Changes in v7:
>> -Add explanation why this is a bool and why it selects i2c-designwaree

Gah -- I missed the explanation mentioned above:

-Change Kconfig option from tristate to boolean and add a select for the
 i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
 OPRegion handler, which must be available before other drivers using it
 are loaded, which can only be ensured if the mfd, opregion and i2c-bus
 drivers are built in

Given that, can we get rid of the modular macros in the code now as well?

Thanks,
Paul.
--


>>  to the help text rather then as comments in the Kconfig
>
> I just noticed the changelog says it was updated to be
> buildable as a module but the Kconfig is still "bool"...
>
> Guessing this was just an oversight since there is
> code for modular use in the driver itself.
>
> Paul.
> --
>
>>
>> Regards,
>>
>> Hans
>>
>>
>>
>> On 15-05-17 20:17, 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.
>>>
>>> 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:
>>> -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
>
>  [...]
>
>>> +};
>>> +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>");
>>>
>>

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

* Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-05-15 18:20 ` Hans de Goede
@ 2017-05-20 19:21   ` Paul Gortmaker
  2017-05-20 19:26     ` Paul Gortmaker
  0 siblings, 1 reply; 10+ messages in thread
From: Paul Gortmaker @ 2017-05-20 19:21 UTC (permalink / raw)
  To: Hans de Goede; +Cc: Lee Jones, LKML, Bin Gao, Felipe Balbi, Andy Shevchenko

On Mon, May 15, 2017 at 2:20 PM, Hans de Goede <hdegoede@redhat.com> wrote:
> Hi,
>
> This is actually v7, with the following changes:
>
> Changes in v7:
> -Add explanation why this is a bool and why it selects i2c-designwaree
>  to the help text rather then as comments in the Kconfig

I just noticed the changelog says it was updated to be
buildable as a module but the Kconfig is still "bool"...

Guessing this was just an oversight since there is
code for modular use in the driver itself.

Paul.
--

>
> Regards,
>
> Hans
>
>
>
> On 15-05-17 20:17, 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.
>>
>> 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:
>> -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

 [...]

>> +};
>> +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>");
>>
>

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

* Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-05-15 18:17 Hans de Goede
@ 2017-05-15 18:20 ` Hans de Goede
  2017-05-20 19:21   ` Paul Gortmaker
  0 siblings, 1 reply; 10+ messages in thread
From: Hans de Goede @ 2017-05-15 18:20 UTC (permalink / raw)
  To: Lee Jones; +Cc: linux-kernel, Bin Gao, Felipe Balbi, Andy Shevchenko

Hi,

This is actually v7, with the following changes:

Changes in v7:
-Add explanation why this is a bool and why it selects i2c-designwaree
  to the help text rather then as comments in the Kconfig

Regards,

Hans


On 15-05-17 20:17, 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.
> 
> 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:
> -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
> Changes in v4:
> -Use PLATFORM_DEVID_NONE
> Changes in v5:
> -Change Kconfig option from tristate to boolean and add a select for the
>   i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
>   OPRegion handler, which must be available before other drivers using it
>   are loaded, which can only be ensured if the mfd, opregion and i2c-bus
>   drivers are built in. This fixes errors like these during boot:
>   mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA
>   ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] (20170119/evregion-166)
>   ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-299)
>   ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93543b0cde10), AE_NOT_EXIST (20170119/psparse-543)
>   ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b0b5cd0), AE_NOT_EXIST (20170119/psparse-543)
>   acpi 80860F14:02: Failed to change power state to D0
> -Some minor style and capitalization fixes from review by Lee Jones
> Changes in v6:
> -Fix Kconfig depends and selects to fix warning reported by kbuild test robot
> ---
>   drivers/mfd/Kconfig                |  17 +++
>   drivers/mfd/Makefile               |   1 +
>   drivers/mfd/intel_soc_pmic_chtwc.c | 239 +++++++++++++++++++++++++++++++++++++
>   3 files changed, 257 insertions(+)
>   create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 3eb5c93595f6..1b6a83a4a114 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -470,6 +470,23 @@ config INTEL_SOC_PMIC_BXTWC
>   	  thermal, charger and related power management functions
>   	  on these systems.
>   
> +config INTEL_SOC_PMIC_CHTWC
> +	bool "Support for Intel Cherry Trail Whiskey Cove PMIC"
> +	depends on ACPI && HAS_IOMEM
> +	select MFD_CORE
> +	select I2C
> +	select REGMAP_I2C
> +	select REGMAP_IRQ
> +	select COMMON_CLK
> +	select I2C_DESIGNWARE_PLATFORM
> +	help
> +	  Select this option to enable support for the Intel Cherry Trail
> +	  Whiskey Cove PMIC found on some Intel Cherry Trail systems.
> +
> +	  This option is a bool as it provides an ACPI Opregion which must be
> +	  available before any devices using it are probed. This option also
> +	  causes the designware-i2c driver to be builtin for the same reason.
> +
>   config MFD_INTEL_LPSS
>   	tristate
>   	select COMMON_CLK
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index c16bf1ea0ea9..6f6aed8cfccc 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -214,6 +214,7 @@ obj-$(CONFIG_MFD_SKY81452)	+= sky81452.o
>   intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
>   obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
>   obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC)	+= intel_soc_pmic_bxtwc.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 000000000000..866526969188
> --- /dev/null
> +++ b/drivers/mfd/intel_soc_pmic_chtwc.c
> @@ -0,0 +1,239 @@
> +/*
> + * 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 of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#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, PLATFORM_DEVID_NONE,
> +				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>");
> 

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

* [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
@ 2017-05-15 18:17 Hans de Goede
  2017-05-15 18:20 ` Hans de Goede
  0 siblings, 1 reply; 10+ messages in thread
From: Hans de Goede @ 2017-05-15 18:17 UTC (permalink / raw)
  To: Lee Jones
  Cc: Hans de Goede, linux-kernel, Bin Gao, Felipe Balbi, Andy Shevchenko

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>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.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
Changes in v4:
-Use PLATFORM_DEVID_NONE
Changes in v5:
-Change Kconfig option from tristate to boolean and add a select for the
 i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
 OPRegion handler, which must be available before other drivers using it
 are loaded, which can only be ensured if the mfd, opregion and i2c-bus
 drivers are built in. This fixes errors like these during boot:
 mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA
 ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] (20170119/evregion-166)
 ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-299)
 ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93543b0cde10), AE_NOT_EXIST (20170119/psparse-543)
 ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b0b5cd0), AE_NOT_EXIST (20170119/psparse-543)
 acpi 80860F14:02: Failed to change power state to D0
-Some minor style and capitalization fixes from review by Lee Jones
Changes in v6:
-Fix Kconfig depends and selects to fix warning reported by kbuild test robot
---
 drivers/mfd/Kconfig                |  17 +++
 drivers/mfd/Makefile               |   1 +
 drivers/mfd/intel_soc_pmic_chtwc.c | 239 +++++++++++++++++++++++++++++++++++++
 3 files changed, 257 insertions(+)
 create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3eb5c93595f6..1b6a83a4a114 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -470,6 +470,23 @@ config INTEL_SOC_PMIC_BXTWC
 	  thermal, charger and related power management functions
 	  on these systems.
 
+config INTEL_SOC_PMIC_CHTWC
+	bool "Support for Intel Cherry Trail Whiskey Cove PMIC"
+	depends on ACPI && HAS_IOMEM
+	select MFD_CORE
+	select I2C
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	select COMMON_CLK
+	select I2C_DESIGNWARE_PLATFORM
+	help
+	  Select this option to enable support for the Intel Cherry Trail
+	  Whiskey Cove PMIC found on some Intel Cherry Trail systems.
+
+	  This option is a bool as it provides an ACPI Opregion which must be
+	  available before any devices using it are probed. This option also
+	  causes the designware-i2c driver to be builtin for the same reason.
+
 config MFD_INTEL_LPSS
 	tristate
 	select COMMON_CLK
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c16bf1ea0ea9..6f6aed8cfccc 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -214,6 +214,7 @@ obj-$(CONFIG_MFD_SKY81452)	+= sky81452.o
 intel-soc-pmic-objs		:= intel_soc_pmic_core.o intel_soc_pmic_crc.o
 obj-$(CONFIG_INTEL_SOC_PMIC)	+= intel-soc-pmic.o
 obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC)	+= intel_soc_pmic_bxtwc.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 000000000000..866526969188
--- /dev/null
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -0,0 +1,239 @@
+/*
+ * 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 of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#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, PLATFORM_DEVID_NONE,
+				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.12.2

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

* Re: [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-04-19 12:56 ` [PATCH v6] " Hans de Goede
@ 2017-04-24 11:55   ` Lee Jones
  0 siblings, 0 replies; 10+ messages in thread
From: Lee Jones @ 2017-04-24 11:55 UTC (permalink / raw)
  To: Hans de Goede; +Cc: linux-kernel, Bin Gao, Felipe Balbi, Andy Shevchenko

On Wed, 19 Apr 2017, 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.
> 
> 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:
> -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
> Changes in v4:
> -Use PLATFORM_DEVID_NONE
> Changes in v5:
> -Change Kconfig option from tristate to boolean and add a select for the
>  i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
>  OPRegion handler, which must be available before other drivers using it
>  are loaded, which can only be ensured if the mfd, opregion and i2c-bus
>  drivers are built in. This fixes errors like these during boot:
>  mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA
>  ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] (20170119/evregion-166)
>  ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-299)
>  ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93543b0cde10), AE_NOT_EXIST (20170119/psparse-543)
>  ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b0b5cd0), AE_NOT_EXIST (20170119/psparse-543)
>  acpi 80860F14:02: Failed to change power state to D0
> -Some minor style and capitalization fixes from review by Lee Jones
> Changes in v6:
> -Fix Kconfig depends and selects to fix warning reported by kbuild test robot
> ---
>  drivers/mfd/Kconfig                |  17 +++
>  drivers/mfd/Makefile               |   1 +
>  drivers/mfd/intel_soc_pmic_chtwc.c | 239 +++++++++++++++++++++++++++++++++++++
>  3 files changed, 257 insertions(+)
>  create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 55ecdfb..2c34574 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -437,6 +437,23 @@ config INTEL_SOC_PMIC
>  	  thermal, charger and related power management functions
>  	  on these systems.
>  
> +config INTEL_SOC_PMIC_CHTWC
> +	# This is a bool as it provides an ACPI Opregion which must be
> +	# available as soon as possible
> +	bool "Support for Intel Cherry Trail Whiskey Cove PMIC"
> +	depends on ACPI && HAS_IOMEM
> +	select MFD_CORE
> +	select REGMAP_I2C
> +	select REGMAP_IRQ
> +	# In order for the ACPI Opregion to be available the i2c-adapter
> +	# driver must be builtin too, select it and its deps
> +	select I2C
> +	select COMMON_CLK
> +	select I2C_DESIGNWARE_PLATFORM
> +	help
> +	  Select this option to enable support for the Intel Cherry Trail
> +	  Whiskey Cove PMIC found on some Intel Cherry Trail systems.

I'm really not keen on the over-commenting in the Kconfig entry.

Every select or depends in the Kconfig is there for one reason or
another, we really don't need to explain them all.

Be as verbose as you like in the commit log, but please consider
removing the comments.

>  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..8665269
> --- /dev/null
> +++ b/drivers/mfd/intel_soc_pmic_chtwc.c
> @@ -0,0 +1,239 @@
> +/*
> + * 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 of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#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, PLATFORM_DEVID_NONE,
> +				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>");

-- 
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] 10+ messages in thread

* [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver
  2017-04-19 12:56 [PATCH resend v6 0/1] " Hans de Goede
@ 2017-04-19 12:56 ` Hans de Goede
  2017-04-24 11:55   ` Lee Jones
  0 siblings, 1 reply; 10+ messages in thread
From: Hans de Goede @ 2017-04-19 12:56 UTC (permalink / raw)
  To: Lee Jones
  Cc: Hans de Goede, linux-kernel, Bin Gao, Felipe Balbi, Andy Shevchenko

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>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.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
Changes in v4:
-Use PLATFORM_DEVID_NONE
Changes in v5:
-Change Kconfig option from tristate to boolean and add a select for the
 i2c-bus driver, this is necessary because the chtwc PMIC provides an ACPI
 OPRegion handler, which must be available before other drivers using it
 are loaded, which can only be ensured if the mfd, opregion and i2c-bus
 drivers are built in. This fixes errors like these during boot:
 mmc0: SDHCI controller on ACPI [80860F14:00] using ADMA
 ACPI Error: No handler for Region [REGS] (ffff93543b0cc3a8) [UserDefinedRegion] (20170119/evregion-166)
 ACPI Error: Region UserDefinedRegion (ID=143) has no handler (20170119/exfldio-299)
 ACPI Error: Method parse/execution failed [\_SB.PCI0.I2C7.PMI5.GET] (Node ffff93543b0cde10), AE_NOT_EXIST (20170119/psparse-543)
 ACPI Error: Method parse/execution failed [\_SB.PCI0.SHC1._PS0] (Node ffff93543b0b5cd0), AE_NOT_EXIST (20170119/psparse-543)
 acpi 80860F14:02: Failed to change power state to D0
-Some minor style and capitalization fixes from review by Lee Jones
Changes in v6:
-Fix Kconfig depends and selects to fix warning reported by kbuild test robot
---
 drivers/mfd/Kconfig                |  17 +++
 drivers/mfd/Makefile               |   1 +
 drivers/mfd/intel_soc_pmic_chtwc.c | 239 +++++++++++++++++++++++++++++++++++++
 3 files changed, 257 insertions(+)
 create mode 100644 drivers/mfd/intel_soc_pmic_chtwc.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 55ecdfb..2c34574 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -437,6 +437,23 @@ config INTEL_SOC_PMIC
 	  thermal, charger and related power management functions
 	  on these systems.
 
+config INTEL_SOC_PMIC_CHTWC
+	# This is a bool as it provides an ACPI Opregion which must be
+	# available as soon as possible
+	bool "Support for Intel Cherry Trail Whiskey Cove PMIC"
+	depends on ACPI && HAS_IOMEM
+	select MFD_CORE
+	select REGMAP_I2C
+	select REGMAP_IRQ
+	# In order for the ACPI Opregion to be available the i2c-adapter
+	# driver must be builtin too, select it and its deps
+	select I2C
+	select COMMON_CLK
+	select I2C_DESIGNWARE_PLATFORM
+	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..8665269
--- /dev/null
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -0,0 +1,239 @@
+/*
+ * 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 of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#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, PLATFORM_DEVID_NONE,
+				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] 10+ messages in thread

end of thread, other threads:[~2017-05-21 19:05 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-27 13:27 [PATCH v6] mfd: Add Cherry Trail Whiskey Cove PMIC driver Hans de Goede
2017-03-27 18:05 ` kbuild test robot
2017-04-19 12:56 [PATCH resend v6 0/1] " Hans de Goede
2017-04-19 12:56 ` [PATCH v6] " Hans de Goede
2017-04-24 11:55   ` Lee Jones
2017-05-15 18:17 Hans de Goede
2017-05-15 18:20 ` Hans de Goede
2017-05-20 19:21   ` Paul Gortmaker
2017-05-20 19:26     ` Paul Gortmaker
2017-05-21  9:51       ` Hans de Goede
2017-05-21 19:05         ` Paul Gortmaker

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