summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-07 13:30:05 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-07 13:30:05 -0700
commit6972b007ca771e33dec992ccd104c95a97a186e5 (patch)
tree0668041e466832b3157bcb02fa7923a29d477ea2 /drivers/mfd
parentc7d28eca1d58d335ff8de6f33559b221bdd029f9 (diff)
parent1e3496000c11ec1ec56cf664b6a01d66de423507 (diff)
Merge (most of) tag 'mfd-next-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones: "New Drivers: - Intel Cherry Trail Whiskey Cove PMIC - TI LP87565 PMIC New Device Support: - Add support for Cannonlake to intel-lpss-pci - Add support for Simatic IOT2000 to intel_quark_i2c_gpio New Functionality: - Add Regulator support (axp20x) Fix-ups: - Rework IRQ handling (intel_soc_pmic_bxtwc, rtsx_pcr, cros_ec) - Remove unused/unwelcome code (ipaq-micro, wm831x-core, da9062-core) - Provide deregistration on unbind (rn5t618) - Rework DT code/documentation (arizona) - Constify things (fsl-imx25-tsadc) - MAINTAINERS updates (DA9062/61) - Kconfig configuration adaptions (INTEL_SOC_PMIC, MFD_AXP20X_I2C) - Switch to DMI matching (intel_quark_i2c_gpio) - Provide an appropriate level of error checking (wm831x-{i2c,spi}, twl4030-irq, tc6393xb) - Make use of devm_* (resource handling) calls (intel_soc_pmic_bxtwc, stm32-timers, atmel-flexcom, cros_ec, fsl-imx25-tsadc, exynos-lpass, palmas, qcom-spmi-pmic, smsc-ece1099, motorola-cpcap)" [ Skipped the last commit in that series that added eight thousand lines of pointless repeated register definitions. - Linus ] * tag 'mfd-next-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (38 commits) mfd: Add LP87565 PMIC support mfd: cros_ec: Free IRQ on exit dt-bindings: vendor-prefixes: Add arctic to vendor prefix mfd: da9061: Fix to remove BBAT_CONT register from chip model mfd: da9061: Fix to remove BBAT_CONT register from chip model mfd: axp20x-i2c: Document that this must be builtin on x86 mfd: Add Cherry Trail Whiskey Cove PMIC driver mfd: tc6393xb: Handle return value of clk_prepare_enable mfd: intel_quark_i2c_gpio: Add support for SIMATIC IOT2000 platform mfd: intel_quark_i2c_gpio: Use dmi_system_id table for retrieving frequency mfd: motorola-cpcap: Use devm_of_platform_populate() mfd: smsc-ece: Use devm_of_platform_populate() mfd: qcom-spmi-pmic: Use devm_of_platform_populate() mfd: palmas: Use devm_of_platform_populate() mfd: exynos: Use devm_of_platform_populate() mfd: fsl-imx25: Use devm_of_platform_populate() mfd: cros_ec: Use devm_of_platform_populate() mfd: atmel: Use devm_of_platform_populate() mfd: stm32-timers: Use devm_of_platform_populate() mfd: intel_soc_pmic: Select designware i2c-bus driver ...
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig44
-rw-r--r--drivers/mfd/Makefile2
-rw-r--r--drivers/mfd/atmel-flexcom.c2
-rw-r--r--drivers/mfd/axp20x.c3
-rw-r--r--drivers/mfd/cros_ec.c5
-rw-r--r--drivers/mfd/da9062-core.c12
-rw-r--r--drivers/mfd/exynos-lpass.c2
-rw-r--r--drivers/mfd/fsl-imx25-tsadc.c7
-rw-r--r--drivers/mfd/intel-lpss-pci.c24
-rw-r--r--drivers/mfd/intel_quark_i2c_gpio.c49
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c232
-rw-r--r--drivers/mfd/intel_soc_pmic_chtwc.c230
-rw-r--r--drivers/mfd/ipaq-micro.c5
-rw-r--r--drivers/mfd/lp87565.c100
-rw-r--r--drivers/mfd/motorola-cpcap.c13
-rw-r--r--drivers/mfd/palmas.c2
-rw-r--r--drivers/mfd/qcom-spmi-pmic.c9
-rw-r--r--drivers/mfd/rn5t618.c2
-rw-r--r--drivers/mfd/rtsx_pcr.c17
-rw-r--r--drivers/mfd/smsc-ece1099.c3
-rw-r--r--drivers/mfd/stm32-timers.c10
-rw-r--r--drivers/mfd/tc6393xb.c4
-rw-r--r--drivers/mfd/twl4030-irq.c4
-rw-r--r--drivers/mfd/wm831x-core.c26
-rw-r--r--drivers/mfd/wm831x-i2c.c4
-rw-r--r--drivers/mfd/wm831x-spi.c4
26 files changed, 641 insertions, 174 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3eb5c93595f6..94ad2c1c3d90 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -160,6 +160,11 @@ config MFD_AXP20X_I2C
components like regulators or the PEK (Power Enable Key) under the
corresponding menus.
+ Note on x86 this provides an ACPI OpRegion, so this must be 'y'
+ (builtin) and not a module, as the OpRegion must be available as
+ soon as possible. For the same reason the I2C bus driver options
+ I2C_DESIGNWARE_PLATFORM and I2C_DESIGNWARE_BAYTRAIL must be 'y' too.
+
config MFD_AXP20X_RSB
tristate "X-Powers AXP series PMICs with RSB"
select MFD_AXP20X
@@ -448,17 +453,22 @@ config LPC_SCH
config INTEL_SOC_PMIC
bool "Support for Crystal Cove PMIC"
- depends on GPIOLIB
- depends on I2C=y
+ depends on HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK
+ depends on X86 || COMPILE_TEST
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
+ select I2C_DESIGNWARE_PLATFORM if ACPI
help
Select this option to enable support for Crystal Cove PMIC
on some Intel SoC systems. The PMIC provides ADC, GPIO,
thermal, charger and related power management functions
on these 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 INTEL_SOC_PMIC_BXTWC
tristate "Support for Intel Broxton Whiskey Cove PMIC"
depends on INTEL_PMC_IPC
@@ -470,6 +480,22 @@ config INTEL_SOC_PMIC_BXTWC
thermal, charger and related power management functions
on these systems.
+config INTEL_SOC_PMIC_CHTWC
+ tristate "Support for Intel Cherry Trail Whiskey Cove PMIC"
+ depends on ACPI && HAS_IOMEM && I2C=y && COMMON_CLK
+ depends on X86 || COMPILE_TEST
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ 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
@@ -1325,6 +1351,20 @@ config MFD_TI_LP873X
This driver can also be built as a module. If so, the module
will be called lp873x.
+config MFD_TI_LP87565
+ tristate "TI LP87565 Power Management IC"
+ depends on I2C && OF
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ If you say yes here then you get support for the LP87565 series of
+ Power Management Integrated Circuits (PMIC).
+ These include voltage regulators, thermal protection, configurable
+ General Purpose Outputs (GPO) that are used in portable devices.
+
+ This driver can also be built as a module. If so, the module
+ will be called lp87565.
+
config MFD_TPS65218
tristate "TI TPS65218 Power Management chips"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c16bf1ea0ea9..080793b3fd0e 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o
+obj-$(CONFIG_MFD_TI_LP87565) += lp87565.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
@@ -214,6 +215,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/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c
index e8e67be6b493..064bde9cff5a 100644
--- a/drivers/mfd/atmel-flexcom.c
+++ b/drivers/mfd/atmel-flexcom.c
@@ -80,7 +80,7 @@ static int atmel_flexcom_probe(struct platform_device *pdev)
clk_disable_unprepare(clk);
- return of_platform_populate(np, NULL, NULL, &pdev->dev);
+ return devm_of_platform_populate(&pdev->dev);
}
static const struct of_device_id atmel_flexcom_of_match[] = {
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 1dc6235778eb..917b6ddc4f15 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -848,7 +848,8 @@ static struct mfd_cell axp803_cells[] = {
.name = "axp20x-pek",
.num_resources = ARRAY_SIZE(axp803_pek_resources),
.resources = axp803_pek_resources,
- }
+ },
+ { .name = "axp20x-regulator" },
};
static struct mfd_cell axp806_cells[] = {
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c
index d4a407e466b5..dc6ce9091694 100644
--- a/drivers/mfd/cros_ec.c
+++ b/drivers/mfd/cros_ec.c
@@ -147,7 +147,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
}
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
- err = of_platform_populate(dev->of_node, NULL, NULL, dev);
+ err = devm_of_platform_populate(dev);
if (err) {
mfd_remove_devices(dev);
dev_err(dev, "Failed to register sub-devices\n");
@@ -183,6 +183,9 @@ int cros_ec_remove(struct cros_ec_device *ec_dev)
cros_ec_acpi_remove_gpe_handler();
+ if (ec_dev->irq)
+ free_irq(ec_dev->irq, ec_dev);
+
return 0;
}
EXPORT_SYMBOL(cros_ec_remove);
diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c
index 7f5e8be0a9ea..fbe0f245ce8e 100644
--- a/drivers/mfd/da9062-core.c
+++ b/drivers/mfd/da9062-core.c
@@ -429,9 +429,6 @@ static const struct regmap_range da9061_aa_readable_ranges[] = {
.range_min = DA9062AA_VLDO1_B,
.range_max = DA9062AA_VLDO4_B,
}, {
- .range_min = DA9062AA_BBAT_CONT,
- .range_max = DA9062AA_BBAT_CONT,
- }, {
.range_min = DA9062AA_INTERFACE,
.range_max = DA9062AA_CONFIG_E,
}, {
@@ -514,9 +511,6 @@ static const struct regmap_range da9061_aa_writeable_ranges[] = {
.range_min = DA9062AA_VLDO1_B,
.range_max = DA9062AA_VLDO4_B,
}, {
- .range_min = DA9062AA_BBAT_CONT,
- .range_max = DA9062AA_BBAT_CONT,
- }, {
.range_min = DA9062AA_GP_ID_0,
.range_max = DA9062AA_GP_ID_19,
},
@@ -651,9 +645,6 @@ static const struct regmap_range da9062_aa_readable_ranges[] = {
.range_min = DA9062AA_VLDO1_B,
.range_max = DA9062AA_VLDO4_B,
}, {
- .range_min = DA9062AA_BBAT_CONT,
- .range_max = DA9062AA_BBAT_CONT,
- }, {
.range_min = DA9062AA_INTERFACE,
.range_max = DA9062AA_CONFIG_E,
}, {
@@ -730,9 +721,6 @@ static const struct regmap_range da9062_aa_writeable_ranges[] = {
.range_min = DA9062AA_VLDO1_B,
.range_max = DA9062AA_VLDO4_B,
}, {
- .range_min = DA9062AA_BBAT_CONT,
- .range_max = DA9062AA_BBAT_CONT,
- }, {
.range_min = DA9062AA_GP_ID_0,
.range_max = DA9062AA_GP_ID_19,
},
diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c
index 0bf3aebdac45..ca829f85672f 100644
--- a/drivers/mfd/exynos-lpass.c
+++ b/drivers/mfd/exynos-lpass.c
@@ -138,7 +138,7 @@ static int exynos_lpass_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
exynos_lpass_enable(lpass);
- return of_platform_populate(dev->of_node, NULL, NULL, dev);
+ return devm_of_platform_populate(dev);
}
static int exynos_lpass_remove(struct platform_device *pdev)
diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c
index ac430a396a89..b3767c3141e5 100644
--- a/drivers/mfd/fsl-imx25-tsadc.c
+++ b/drivers/mfd/fsl-imx25-tsadc.c
@@ -59,7 +59,7 @@ static int mx25_tsadc_domain_map(struct irq_domain *d, unsigned int irq,
return 0;
}
-static struct irq_domain_ops mx25_tsadc_domain_ops = {
+static const struct irq_domain_ops mx25_tsadc_domain_ops = {
.map = mx25_tsadc_domain_map,
.xlate = irq_domain_xlate_onecell,
};
@@ -129,7 +129,6 @@ static void mx25_tsadc_setup_clk(struct platform_device *pdev,
static int mx25_tsadc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
struct mx25_tsadc *tsadc;
struct resource *res;
int ret;
@@ -178,9 +177,7 @@ static int mx25_tsadc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, tsadc);
- of_platform_populate(np, NULL, NULL, dev);
-
- return 0;
+ return devm_of_platform_populate(dev);
}
static const struct of_device_id mx25_tsadc_ids[] = {
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c
index 16ffeaeb1385..ad388bb056cd 100644
--- a/drivers/mfd/intel-lpss-pci.c
+++ b/drivers/mfd/intel-lpss-pci.c
@@ -201,6 +201,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info },
+ /* CNL-LP */
+ { PCI_VDEVICE(INTEL, 0x9da8), (kernel_ulong_t)&spt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x9da9), (kernel_ulong_t)&spt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&spt_info },
+ { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&spt_info },
+ { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&spt_info },
+ { PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x9dc7), (kernel_ulong_t)&spt_uart_info },
+ { PCI_VDEVICE(INTEL, 0x9de8), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&spt_i2c_info },
/* SPT-H */
{ PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info },
{ PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info },
@@ -219,6 +232,17 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&spt_i2c_info },
{ PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&spt_uart_info },
+ /* CNL-H */
+ { PCI_VDEVICE(INTEL, 0xa328), (kernel_ulong_t)&spt_uart_info },
+ { PCI_VDEVICE(INTEL, 0xa329), (kernel_ulong_t)&spt_uart_info },
+ { PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&spt_info },
+ { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&spt_info },
+ { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&spt_info },
+ { PCI_VDEVICE(INTEL, 0xa347), (kernel_ulong_t)&spt_uart_info },
+ { PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&spt_i2c_info },
+ { PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&spt_i2c_info },
{ }
};
MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c
index 7946d6e38b87..90e35dec8648 100644
--- a/drivers/mfd/intel_quark_i2c_gpio.c
+++ b/drivers/mfd/intel_quark_i2c_gpio.c
@@ -58,19 +58,34 @@ struct intel_quark_mfd {
struct clk_lookup *i2c_clk_lookup;
};
-struct i2c_mode_info {
- const char *name;
- unsigned int i2c_scl_freq;
-};
-
-static const struct i2c_mode_info platform_i2c_mode_info[] = {
+static const struct dmi_system_id dmi_platform_info[] = {
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"),
+ },
+ .driver_data = (void *)100000,
+ },
{
- .name = "Galileo",
- .i2c_scl_freq = 100000,
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"),
+ },
+ .driver_data = (void *)400000,
},
{
- .name = "GalileoGen2",
- .i2c_scl_freq = 400000,
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+ DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+ "6ES7647-0AA00-0YA2"),
+ },
+ .driver_data = (void *)400000,
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
+ DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
+ "6ES7647-0AA00-1YA2"),
+ },
+ .driver_data = (void *)400000,
},
{}
};
@@ -160,8 +175,7 @@ static void intel_quark_unregister_i2c_clk(struct device *dev)
static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell)
{
- const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
- const struct i2c_mode_info *info;
+ const struct dmi_system_id *dmi_id;
struct dw_i2c_platform_data *pdata;
struct resource *res = (struct resource *)cell->resources;
struct device *dev = &pdev->dev;
@@ -181,14 +195,9 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell)
/* Normal mode by default */
pdata->i2c_scl_freq = 100000;
- if (board_name) {
- for (info = platform_i2c_mode_info; info->name; info++) {
- if (!strcmp(board_name, info->name)) {
- pdata->i2c_scl_freq = info->i2c_scl_freq;
- break;
- }
- }
- }
+ dmi_id = dmi_first_match(dmi_platform_info);
+ if (dmi_id)
+ pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data;
cell->platform_data = pdata;
cell->pdata_size = sizeof(*pdata);
diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c
index 8c3cbf63c6ad..15bc052704a6 100644
--- a/drivers/mfd/intel_soc_pmic_bxtwc.c
+++ b/drivers/mfd/intel_soc_pmic_bxtwc.c
@@ -82,20 +82,26 @@ enum bxtwc_irqs {
BXTWC_PWRBTN_IRQ,
};
-enum bxtwc_irqs_level2 {
- /* Level 2 */
- BXTWC_THRM0_IRQ = 0,
- BXTWC_THRM1_IRQ,
- BXTWC_THRM2_IRQ,
- BXTWC_BCU_IRQ,
- BXTWC_ADC_IRQ,
- BXTWC_USBC_IRQ,
+enum bxtwc_irqs_bcu {
+ BXTWC_BCU_IRQ = 0,
+};
+
+enum bxtwc_irqs_adc {
+ BXTWC_ADC_IRQ = 0,
+};
+
+enum bxtwc_irqs_chgr {
+ BXTWC_USBC_IRQ = 0,
BXTWC_CHGR0_IRQ,
BXTWC_CHGR1_IRQ,
- BXTWC_GPIO0_IRQ,
- BXTWC_GPIO1_IRQ,
- BXTWC_CRIT_IRQ,
- BXTWC_TMU_IRQ,
+};
+
+enum bxtwc_irqs_tmu {
+ BXTWC_TMU_IRQ = 0,
+};
+
+enum bxtwc_irqs_crit {
+ BXTWC_CRIT_IRQ = 0,
};
static const struct regmap_irq bxtwc_regmap_irqs[] = {
@@ -110,24 +116,28 @@ static const struct regmap_irq bxtwc_regmap_irqs[] = {
REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 1, 0x03),
};
-static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
- REGMAP_IRQ_REG(BXTWC_THRM0_IRQ, 0, 0xff),
- REGMAP_IRQ_REG(BXTWC_THRM1_IRQ, 1, 0xbf),
- REGMAP_IRQ_REG(BXTWC_THRM2_IRQ, 2, 0xff),
- REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 3, 0x1f),
- REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 4, 0xff),
- REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 5, BIT(5)),
- REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x1f),
- REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 6, 0x1f),
- REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 7, 0xff),
- REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 8, 0x3f),
- REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03),
+static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = {
+ REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, 0x1f),
+};
+
+static const struct regmap_irq bxtwc_regmap_irqs_adc[] = {
+ REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, 0xff),
+};
+
+static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = {
+ REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, BIT(5)),
+ REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, 0x1f),
+ REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, 0x1f),
};
static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = {
REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06),
};
+static const struct regmap_irq bxtwc_regmap_irqs_crit[] = {
+ REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, 0x03),
+};
+
static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
.name = "bxtwc_irq_chip",
.status_base = BXTWC_IRQLVL1,
@@ -137,15 +147,6 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip = {
.num_regs = 2,
};
-static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = {
- .name = "bxtwc_irq_chip_level2",
- .status_base = BXTWC_THRM0IRQ,
- .mask_base = BXTWC_MTHRM0IRQ,
- .irqs = bxtwc_regmap_irqs_level2,
- .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_level2),
- .num_regs = 10,
-};
-
static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
.name = "bxtwc_irq_chip_tmu",
.status_base = BXTWC_TMUIRQ,
@@ -155,9 +156,44 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = {
.num_regs = 1,
};
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = {
+ .name = "bxtwc_irq_chip_bcu",
+ .status_base = BXTWC_BCUIRQ,
+ .mask_base = BXTWC_MBCUIRQ,
+ .irqs = bxtwc_regmap_irqs_bcu,
+ .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_bcu),
+ .num_regs = 1,
+};
+
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = {
+ .name = "bxtwc_irq_chip_adc",
+ .status_base = BXTWC_ADCIRQ,
+ .mask_base = BXTWC_MADCIRQ,
+ .irqs = bxtwc_regmap_irqs_adc,
+ .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_adc),
+ .num_regs = 1,
+};
+
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = {
+ .name = "bxtwc_irq_chip_chgr",
+ .status_base = BXTWC_CHGR0IRQ,
+ .mask_base = BXTWC_MCHGR0IRQ,
+ .irqs = bxtwc_regmap_irqs_chgr,
+ .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_chgr),
+ .num_regs = 2,
+};
+
+static struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = {
+ .name = "bxtwc_irq_chip_crit",
+ .status_base = BXTWC_CRITIRQ,
+ .mask_base = BXTWC_MCRITIRQ,
+ .irqs = bxtwc_regmap_irqs_crit,
+ .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_crit),
+ .num_regs = 1,
+};
+
static struct resource gpio_resources[] = {
- DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"),
- DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"),
+ DEFINE_RES_IRQ_NAMED(BXTWC_GPIO_LVL1_IRQ, "GPIO"),
};
static struct resource adc_resources[] = {
@@ -174,9 +210,7 @@ static struct resource charger_resources[] = {
};
static struct resource thermal_resources[] = {
- DEFINE_RES_IRQ(BXTWC_THRM0_IRQ),
- DEFINE_RES_IRQ(BXTWC_THRM1_IRQ),
- DEFINE_RES_IRQ(BXTWC_THRM2_IRQ),
+ DEFINE_RES_IRQ(BXTWC_THRM_LVL1_IRQ),
};
static struct resource bcu_resources[] = {
@@ -367,6 +401,26 @@ static const struct regmap_config bxtwc_regmap_config = {
.reg_read = regmap_ipc_byte_reg_read,
};
+static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic,
+ struct regmap_irq_chip_data *pdata,
+ int pirq, int irq_flags,
+ const struct regmap_irq_chip *chip,
+ struct regmap_irq_chip_data **data)
+{
+ int irq;
+
+ irq = regmap_irq_get_virq(pdata, pirq);
+ if (irq < 0) {
+ dev_err(pmic->dev,
+ "Failed to get parent vIRQ(%d) for chip %s, ret:%d\n",
+ pirq, chip->name, irq);
+ return irq;
+ }
+
+ return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags,
+ 0, chip, data);
+}
+
static int bxtwc_probe(struct platform_device *pdev)
{
int ret;
@@ -409,45 +463,88 @@ static int bxtwc_probe(struct platform_device *pdev)
return ret;
}
- ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
- IRQF_ONESHOT | IRQF_SHARED,
- 0, &bxtwc_regmap_irq_chip,
- &pmic->irq_chip_data);
+ ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq,
+ IRQF_ONESHOT | IRQF_SHARED,
+ 0, &bxtwc_regmap_irq_chip,
+ &pmic->irq_chip_data);
if (ret) {
dev_err(&pdev->dev, "Failed to add IRQ chip\n");
return ret;
}
- ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
- IRQF_ONESHOT | IRQF_SHARED,
- 0, &bxtwc_regmap_irq_chip_level2,
- &pmic->irq_chip_data_level2);
+ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
+ BXTWC_TMU_LVL1_IRQ,
+ IRQF_ONESHOT,
+ &bxtwc_regmap_irq_chip_tmu,
+ &pmic->irq_chip_data_tmu);
if (ret) {
- dev_err(&pdev->dev, "Failed to add secondary IRQ chip\n");
- goto err_irq_chip_level2;
+ dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n");
+ return ret;
}
- ret = regmap_add_irq_chip(pmic->regmap, pmic->irq,
- IRQF_ONESHOT | IRQF_SHARED,
- 0, &bxtwc_regmap_irq_chip_tmu,
- &pmic->irq_chip_data_tmu);
+ /* Add chained IRQ handler for BCU IRQs */
+ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
+ BXTWC_BCU_LVL1_IRQ,
+ IRQF_ONESHOT,
+ &bxtwc_regmap_irq_chip_bcu,
+ &pmic->irq_chip_data_bcu);
+
+
if (ret) {
- dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n");
- goto err_irq_chip_tmu;
+ dev_err(&pdev->dev, "Failed to add BUC IRQ chip\n");
+ return ret;
+ }
+
+ /* Add chained IRQ handler for ADC IRQs */
+ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
+ BXTWC_ADC_LVL1_IRQ,
+ IRQF_ONESHOT,
+ &bxtwc_regmap_irq_chip_adc,
+ &pmic->irq_chip_data_adc);
+
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add ADC IRQ chip\n");
+ return ret;
+ }
+
+ /* Add chained IRQ handler for CHGR IRQs */
+ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
+ BXTWC_CHGR_LVL1_IRQ,
+ IRQF_ONESHOT,
+ &bxtwc_regmap_irq_chip_chgr,
+ &pmic->irq_chip_data_chgr);
+
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add CHGR IRQ chip\n");
+ return ret;
+ }
+
+ /* Add chained IRQ handler for CRIT IRQs */
+ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data,
+ BXTWC_CRIT_LVL1_IRQ,
+ IRQF_ONESHOT,
+ &bxtwc_regmap_irq_chip_crit,
+ &pmic->irq_chip_data_crit);
+
+
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add CRIT IRQ chip\n");
+ return ret;
}
- ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
- ARRAY_SIZE(bxt_wc_dev), NULL, 0,
- NULL);
+ ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev,
+ ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL);
if (ret) {
dev_err(&pdev->dev, "Failed to add devices\n");
- goto err_mfd;
+ return ret;
}
ret = sysfs_create_group(&pdev->dev.kobj, &bxtwc_group);
if (ret) {
dev_err(&pdev->dev, "Failed to create sysfs group %d\n", ret);
- goto err_sysfs;
+ return ret;
}
/*
@@ -461,28 +558,11 @@ static int bxtwc_probe(struct platform_device *pdev)
BXTWC_MIRQLVL1_MCHGR, 0);
return 0;
-
-err_sysfs:
- mfd_remove_devices(&pdev->dev);
-err_mfd:
- regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
-err_irq_chip_tmu:
- regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
-err_irq_chip_level2:
- regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
-
- return ret;
}
static int bxtwc_remove(struct platform_device *pdev)
{
- struct intel_soc_pmic *pmic = dev_get_drvdata(&pdev->dev);
-
sysfs_remove_group(&pdev->dev.kobj, &bxtwc_group);
- mfd_remove_devices(&pdev->dev);
- regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data);
- regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2);
- regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu);
return 0;
}
diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c
new file mode 100644
index 000000000000..b35da01d5bcf
--- /dev/null
+++ b/drivers/mfd/intel_soc_pmic_chtwc.c
@@ -0,0 +1,230 @@
+/*
+ * 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/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_RE