summaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig32
-rw-r--r--drivers/mfd/Makefile3
-rw-r--r--drivers/mfd/altera-sysmgr.c2
-rw-r--r--drivers/mfd/bcm2835-pm.c1
-rw-r--r--drivers/mfd/da9055-core.c2
-rw-r--r--drivers/mfd/da9063-i2c.c3
-rw-r--r--drivers/mfd/ls2k-bmc-core.c14
-rw-r--r--drivers/mfd/macsmc.c6
-rw-r--r--drivers/mfd/max77620.c15
-rw-r--r--drivers/mfd/mt6358-irq.c1
-rw-r--r--drivers/mfd/mt6397-irq.c1
-rw-r--r--drivers/mfd/pf1550.c367
-rw-r--r--drivers/mfd/qnap-mcu.c80
-rw-r--r--drivers/mfd/rohm-bd718x7.c9
-rw-r--r--drivers/mfd/sec-acpm.c23
-rw-r--r--drivers/mfd/sec-irq.c73
-rw-r--r--drivers/mfd/simple-mfd-i2c.c18
-rw-r--r--drivers/mfd/syscon.c2
-rw-r--r--drivers/mfd/tqmx86.c8
-rw-r--r--drivers/mfd/wl1273-core.c262
20 files changed, 591 insertions, 331 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 6cec1858947b..aace5766b38a 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -45,7 +45,8 @@ config MFD_ALTERA_A10SR
config MFD_ALTERA_SYSMGR
bool "Altera SOCFPGA System Manager"
- depends on ARCH_INTEL_SOCFPGA && OF
+ depends on ARCH_INTEL_SOCFPGA || COMPILE_TEST
+ depends on OF
select MFD_SYSCON
help
Select this to get System Manager support for all Altera branded
@@ -605,6 +606,22 @@ config MFD_MX25_TSADC
i.MX25 processors. They consist of a conversion queue for general
purpose ADC and a queue for Touchscreens.
+config MFD_PF1550
+ tristate "NXP PF1550 PMIC Support"
+ depends on I2C=y && OF
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ help
+ Say yes here to add support for NXP PF1550. This is a companion Power
+ Management IC with regulators, onkey, and charger control on chip.
+ This driver provides common support for accessing the device;
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
+ This driver can also be built as a module and if so will be called
+ pf1550.
+
config MFD_HI6421_PMIC
tristate "HiSilicon Hi6421 PMU/Codec IC"
depends on OF
@@ -879,7 +896,7 @@ config MFD_88PM886_PMIC
config MFD_MAX5970
tristate "Maxim 5970/5978 power switch and monitor"
- depends on I2C && OF
+ depends on I2C
select MFD_SIMPLE_MFD_I2C
help
This driver controls a Maxim 5970/5978 switch via I2C bus.
@@ -1258,7 +1275,6 @@ config MFD_SPACEMIT_P1
tristate "SpacemiT P1 PMIC"
depends on ARCH_SPACEMIT || COMPILE_TEST
depends on I2C
- select I2C_K1
select MFD_SIMPLE_MFD_I2C
help
This option supports the I2C-based SpacemiT P1 PMIC, which
@@ -1986,16 +2002,6 @@ config MENELAUS
and other features that are often used in portable devices like
cell phones and PDAs.
-config MFD_WL1273_CORE
- tristate "TI WL1273 FM radio"
- depends on I2C
- select MFD_CORE
- default n
- help
- This is the core driver for the TI WL1273 FM radio. This MFD
- driver connects the radio-wl1273 V4L2 module and the wl1273
- audio codec.
-
config MFD_LM3533
tristate "TI/National Semiconductor LM3533 Lighting Power chip"
depends on I2C
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 865e9f12faff..e75e8045c28a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -122,6 +122,8 @@ obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
+obj-$(CONFIG_MFD_PF1550) += pf1550.o
+
obj-$(CONFIG_MFD_NCT6694) += nct6694.o
obj-$(CONFIG_MFD_CORE) += mfd-core.o
@@ -205,7 +207,6 @@ obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o
obj-$(CONFIG_MFD_VX855) += vx855.o
-obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o
obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c
index fb5f988e61f3..90c6902d537d 100644
--- a/drivers/mfd/altera-sysmgr.c
+++ b/drivers/mfd/altera-sysmgr.c
@@ -117,6 +117,8 @@ struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
sysmgr = dev_get_drvdata(dev);
+ put_device(dev);
+
return sysmgr->regmap;
}
EXPORT_SYMBOL_GPL(altr_sysmgr_regmap_lookup_by_phandle);
diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c
index 3cb2b9423121..8bed59816e82 100644
--- a/drivers/mfd/bcm2835-pm.c
+++ b/drivers/mfd/bcm2835-pm.c
@@ -108,6 +108,7 @@ static const struct of_device_id bcm2835_pm_of_match[] = {
{ .compatible = "brcm,bcm2835-pm-wdt", },
{ .compatible = "brcm,bcm2835-pm", },
{ .compatible = "brcm,bcm2711-pm", },
+ { .compatible = "brcm,bcm2712-pm", },
{},
};
MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c
index 1f727ef60d63..158590ad37d4 100644
--- a/drivers/mfd/da9055-core.c
+++ b/drivers/mfd/da9055-core.c
@@ -387,7 +387,7 @@ int da9055_device_init(struct da9055 *da9055)
return 0;
err:
- mfd_remove_devices(da9055->dev);
+ regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data);
return ret;
}
diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c
index 1ec9ab56442d..a803b7440f09 100644
--- a/drivers/mfd/da9063-i2c.c
+++ b/drivers/mfd/da9063-i2c.c
@@ -469,6 +469,9 @@ static int da9063_i2c_probe(struct i2c_client *i2c)
}
}
+ /* Reserve our unused second address so userspace won't interfere */
+ devm_i2c_new_dummy_device(&i2c->dev, i2c->adapter, i2c->addr + 1);
+
return da9063_device_init(da9063, i2c->irq);
}
diff --git a/drivers/mfd/ls2k-bmc-core.c b/drivers/mfd/ls2k-bmc-core.c
index e162b3c7c9f8..e42f1de9e641 100644
--- a/drivers/mfd/ls2k-bmc-core.c
+++ b/drivers/mfd/ls2k-bmc-core.c
@@ -265,7 +265,7 @@ static int ls2k_bmc_recover_pci_data(void *data)
if (!ls2k_bmc_bar0_addr_is_set(parent))
break;
mdelay(1);
- };
+ }
if (i == 0)
return false;
@@ -469,7 +469,7 @@ static int ls2k_bmc_probe(struct pci_dev *dev, const struct pci_device_id *id)
return ret;
ddata = devm_kzalloc(&dev->dev, sizeof(*ddata), GFP_KERNEL);
- if (IS_ERR(ddata)) {
+ if (!ddata) {
ret = -ENOMEM;
goto disable_pci;
}
@@ -495,9 +495,13 @@ static int ls2k_bmc_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto disable_pci;
}
- return devm_mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO,
- ls2k_bmc_cells, ARRAY_SIZE(ls2k_bmc_cells),
- &dev->resource[0], 0, NULL);
+ ret = devm_mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO,
+ ls2k_bmc_cells, ARRAY_SIZE(ls2k_bmc_cells),
+ &dev->resource[0], 0, NULL);
+ if (ret)
+ goto disable_pci;
+
+ return 0;
disable_pci:
pci_disable_device(dev);
diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c
index e6cdae221f1d..e3893e255ce5 100644
--- a/drivers/mfd/macsmc.c
+++ b/drivers/mfd/macsmc.c
@@ -173,7 +173,7 @@ int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size)
}
EXPORT_SYMBOL(apple_smc_read);
-int apple_smc_write(struct apple_smc *smc, smc_key key, void *buf, size_t size)
+int apple_smc_write(struct apple_smc *smc, smc_key key, const void *buf, size_t size)
{
guard(mutex)(&smc->mutex);
@@ -181,7 +181,7 @@ int apple_smc_write(struct apple_smc *smc, smc_key key, void *buf, size_t size)
}
EXPORT_SYMBOL(apple_smc_write);
-int apple_smc_rw(struct apple_smc *smc, smc_key key, void *wbuf, size_t wsize,
+int apple_smc_rw(struct apple_smc *smc, smc_key key, const void *wbuf, size_t wsize,
void *rbuf, size_t rsize)
{
guard(mutex)(&smc->mutex);
@@ -239,7 +239,7 @@ int apple_smc_enter_atomic(struct apple_smc *smc)
}
EXPORT_SYMBOL(apple_smc_enter_atomic);
-int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, void *buf, size_t size)
+int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf, size_t size)
{
guard(spinlock_irqsave)(&smc->lock);
u8 result;
diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c
index 21d2ab3db254..3af2974b3023 100644
--- a/drivers/mfd/max77620.c
+++ b/drivers/mfd/max77620.c
@@ -254,7 +254,7 @@ static int max77620_irq_global_unmask(void *irq_drv_data)
return ret;
}
-static struct regmap_irq_chip max77620_top_irq_chip = {
+static const struct regmap_irq_chip max77620_top_irq_chip = {
.name = "max77620-top",
.irqs = max77620_top_irqs,
.num_irqs = ARRAY_SIZE(max77620_top_irqs),
@@ -498,6 +498,7 @@ static int max77620_probe(struct i2c_client *client)
const struct i2c_device_id *id = i2c_client_get_device_id(client);
const struct regmap_config *rmap_config;
struct max77620_chip *chip;
+ struct regmap_irq_chip *chip_desc;
const struct mfd_cell *mfd_cells;
int n_mfd_cells;
bool pm_off;
@@ -508,6 +509,14 @@ static int max77620_probe(struct i2c_client *client)
return -ENOMEM;
i2c_set_clientdata(client, chip);
+
+ chip_desc = devm_kmemdup(&client->dev, &max77620_top_irq_chip,
+ sizeof(max77620_top_irq_chip),
+ GFP_KERNEL);
+ if (!chip_desc)
+ return -ENOMEM;
+ chip_desc->irq_drv_data = chip;
+
chip->dev = &client->dev;
chip->chip_irq = client->irq;
chip->chip_id = (enum max77620_chip_id)id->driver_data;
@@ -544,11 +553,9 @@ static int max77620_probe(struct i2c_client *client)
if (ret < 0)
return ret;
- max77620_top_irq_chip.irq_drv_data = chip;
ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq,
IRQF_ONESHOT | IRQF_SHARED, 0,
- &max77620_top_irq_chip,
- &chip->top_irq_data);
+ chip_desc, &chip->top_irq_data);
if (ret < 0) {
dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret);
return ret;
diff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c
index f467b00d2366..74cf20843044 100644
--- a/drivers/mfd/mt6358-irq.c
+++ b/drivers/mfd/mt6358-irq.c
@@ -285,6 +285,7 @@ int mt6358_irq_init(struct mt6397_chip *chip)
if (ret) {
dev_err(chip->dev, "Failed to register IRQ=%d, ret=%d\n",
chip->irq, ret);
+ irq_domain_remove(chip->irq_domain);
return ret;
}
diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c
index 0e463026c5a9..5d2e5459f744 100644
--- a/drivers/mfd/mt6397-irq.c
+++ b/drivers/mfd/mt6397-irq.c
@@ -229,6 +229,7 @@ int mt6397_irq_init(struct mt6397_chip *chip)
if (ret) {
dev_err(chip->dev, "failed to register irq=%d; err: %d\n",
chip->irq, ret);
+ irq_domain_remove(chip->irq_domain);
return ret;
}
diff --git a/drivers/mfd/pf1550.c b/drivers/mfd/pf1550.c
new file mode 100644
index 000000000000..c4f567c05564
--- /dev/null
+++ b/drivers/mfd/pf1550.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Core driver for the PF1550
+ *
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Robin Gong <yibin.gong@freescale.com>
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+static const struct regmap_config pf1550_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = PF1550_PMIC_REG_END,
+};
+
+static const struct regmap_irq pf1550_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_IRQ_CHG, 0, IRQ_CHG),
+ REGMAP_IRQ_REG(PF1550_IRQ_REGULATOR, 0, IRQ_REGULATOR),
+ REGMAP_IRQ_REG(PF1550_IRQ_ONKEY, 0, IRQ_ONKEY),
+};
+
+static const struct regmap_irq_chip pf1550_irq_chip = {
+ .name = "pf1550",
+ .status_base = PF1550_PMIC_REG_INT_CATEGORY,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_irqs),
+};
+
+static const struct regmap_irq pf1550_regulator_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_LS, 0, PMIC_IRQ_SW1_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_LS, 0, PMIC_IRQ_SW2_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_LS, 0, PMIC_IRQ_SW3_LS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW1_HS, 3, PMIC_IRQ_SW1_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW2_HS, 3, PMIC_IRQ_SW2_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_SW3_HS, 3, PMIC_IRQ_SW3_HS),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO1_FAULT, 16, PMIC_IRQ_LDO1_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO2_FAULT, 16, PMIC_IRQ_LDO2_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_LDO3_FAULT, 16, PMIC_IRQ_LDO3_FAULT),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_110, 24, PMIC_IRQ_TEMP_110),
+ REGMAP_IRQ_REG(PF1550_PMIC_IRQ_TEMP_125, 24, PMIC_IRQ_TEMP_125),
+};
+
+static const struct regmap_irq_chip pf1550_regulator_irq_chip = {
+ .name = "pf1550-regulator",
+ .status_base = PF1550_PMIC_REG_SW_INT_STAT0,
+ .ack_base = PF1550_PMIC_REG_SW_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_SW_INT_MASK0,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 25,
+ .irqs = pf1550_regulator_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_regulator_irqs),
+};
+
+static const struct resource regulator_resources[] = {
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_LS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW1_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW2_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_SW3_HS),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO1_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO2_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_LDO3_FAULT),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_110),
+ DEFINE_RES_IRQ(PF1550_PMIC_IRQ_TEMP_125),
+};
+
+static const struct regmap_irq pf1550_onkey_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_PUSHI, 0, ONKEY_IRQ_PUSHI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_1SI, 0, ONKEY_IRQ_1SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_2SI, 0, ONKEY_IRQ_2SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_3SI, 0, ONKEY_IRQ_3SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_4SI, 0, ONKEY_IRQ_4SI),
+ REGMAP_IRQ_REG(PF1550_ONKEY_IRQ_8SI, 0, ONKEY_IRQ_8SI),
+};
+
+static const struct regmap_irq_chip pf1550_onkey_irq_chip = {
+ .name = "pf1550-onkey",
+ .status_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .ack_base = PF1550_PMIC_REG_ONKEY_INT_STAT0,
+ .mask_base = PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_onkey_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_onkey_irqs),
+};
+
+static const struct resource onkey_resources[] = {
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_PUSHI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_1SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_2SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_3SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_4SI),
+ DEFINE_RES_IRQ(PF1550_ONKEY_IRQ_8SI),
+};
+
+static const struct regmap_irq pf1550_charger_irqs[] = {
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BAT2SOCI, 0, CHARG_IRQ_BAT2SOCI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_BATI, 0, CHARG_IRQ_BATI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_CHGI, 0, CHARG_IRQ_CHGI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_VBUSI, 0, CHARG_IRQ_VBUSI),
+ REGMAP_IRQ_REG(PF1550_CHARG_IRQ_THMI, 0, CHARG_IRQ_THMI),
+};
+
+static const struct regmap_irq_chip pf1550_charger_irq_chip = {
+ .name = "pf1550-charger",
+ .status_base = PF1550_CHARG_REG_CHG_INT,
+ .ack_base = PF1550_CHARG_REG_CHG_INT,
+ .mask_base = PF1550_CHARG_REG_CHG_INT_MASK,
+ .use_ack = 1,
+ .init_ack_masked = 1,
+ .num_regs = 1,
+ .irqs = pf1550_charger_irqs,
+ .num_irqs = ARRAY_SIZE(pf1550_charger_irqs),
+};
+
+static const struct resource charger_resources[] = {
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BAT2SOCI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_BATI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_CHGI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_VBUSI),
+ DEFINE_RES_IRQ(PF1550_CHARG_IRQ_THMI),
+};
+
+static const struct mfd_cell pf1550_regulator_cell = {
+ .name = "pf1550-regulator",
+ .num_resources = ARRAY_SIZE(regulator_resources),
+ .resources = regulator_resources,
+};
+
+static const struct mfd_cell pf1550_onkey_cell = {
+ .name = "pf1550-onkey",
+ .num_resources = ARRAY_SIZE(onkey_resources),
+ .resources = onkey_resources,
+};
+
+static const struct mfd_cell pf1550_charger_cell = {
+ .name = "pf1550-charger",
+ .num_resources = ARRAY_SIZE(charger_resources),
+ .resources = charger_resources,
+};
+
+/*
+ * The PF1550 is shipped in variants of A0, A1,...A9. Each variant defines a
+ * configuration of the PMIC in a One-Time Programmable (OTP) memory.
+ * This memory is accessed indirectly by writing valid keys to specific
+ * registers of the PMIC. To read the OTP memory after writing the valid keys,
+ * the OTP register address to be read is written to pf1550 register 0xc4 and
+ * its value read from pf1550 register 0xc5.
+ */
+static int pf1550_read_otp(const struct pf1550_ddata *pf1550, unsigned int index,
+ unsigned int *val)
+{
+ int ret = 0;
+
+ ret = regmap_write(pf1550->regmap, PF1550_PMIC_REG_KEY, PF1550_OTP_PMIC_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_CHARG_REG_CHGR_KEY2, PF1550_OTP_CHGR_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_KEY3, PF1550_OTP_TEST_KEY);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_write(pf1550->regmap, PF1550_TEST_REG_FMRADDR, index);
+ if (ret)
+ goto read_err;
+
+ ret = regmap_read(pf1550->regmap, PF1550_TEST_REG_FMRDATA, val);
+ if (ret)
+ goto read_err;
+
+ return 0;
+
+read_err:
+ return dev_err_probe(pf1550->dev, ret, "OTP reg %x not found!\n", index);
+}
+
+static int pf1550_i2c_probe(struct i2c_client *i2c)
+{
+ const struct mfd_cell *regulator = &pf1550_regulator_cell;
+ const struct mfd_cell *charger = &pf1550_charger_cell;
+ const struct mfd_cell *onkey = &pf1550_onkey_cell;
+ unsigned int reg_data = 0, otp_data = 0;
+ struct pf1550_ddata *pf1550;
+ struct irq_domain *domain;
+ int irq, ret = 0;
+
+ pf1550 = devm_kzalloc(&i2c->dev, sizeof(*pf1550), GFP_KERNEL);
+ if (!pf1550)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, pf1550);
+ pf1550->dev = &i2c->dev;
+ pf1550->irq = i2c->irq;
+
+ pf1550->regmap = devm_regmap_init_i2c(i2c, &pf1550_regmap_config);
+ if (IS_ERR(pf1550->regmap))
+ return dev_err_probe(pf1550->dev, PTR_ERR(pf1550->regmap),
+ "failed to allocate register map\n");
+
+ ret = regmap_read(pf1550->regmap, PF1550_PMIC_REG_DEVICE_ID, &reg_data);
+ if (ret < 0)
+ return dev_err_probe(pf1550->dev, ret, "cannot read chip ID\n");
+ if (reg_data != PF1550_DEVICE_ID)
+ return dev_err_probe(pf1550->dev, -ENODEV, "invalid device ID: 0x%02x\n", reg_data);
+
+ /* Regulator DVS for SW2 */
+ ret = pf1550_read_otp(pf1550, PF1550_OTP_SW2_SW3, &otp_data);
+ if (ret)
+ return ret;
+
+ /* When clear, DVS should be enabled */
+ if (!(otp_data & OTP_SW2_DVS_ENB))
+ pf1550->dvs2_enable = true;
+
+ /* Regulator DVS for SW1 */
+ ret = pf1550_read_otp(pf1550, PF1550_OTP_SW1_SW2, &otp_data);
+ if (ret)
+ return ret;
+
+ if (!(otp_data & OTP_SW1_DVS_ENB))
+ pf1550->dvs1_enable = true;
+
+ /* Add top level interrupts */
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, pf1550->irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING,
+ 0, &pf1550_irq_chip,
+ &pf1550->irq_data);
+ if (ret)
+ return ret;
+
+ /* Add regulator */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_REGULATOR);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_REGULATOR, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_regulator_irq_chip,
+ &pf1550->irq_data_regulator);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_regulator_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_regulator);
+
+ ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, regulator, 1, NULL, 0, domain);
+ if (ret)
+ return ret;
+
+ /* Add onkey */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_ONKEY);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_ONKEY, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_onkey_irq_chip,
+ &pf1550->irq_data_onkey);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_onkey_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_onkey);
+
+ ret = devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, onkey, 1, NULL, 0, domain);
+ if (ret)
+ return ret;
+
+ /* Add battery charger */
+ irq = regmap_irq_get_virq(pf1550->irq_data, PF1550_IRQ_CHG);
+ if (irq < 0)
+ return dev_err_probe(pf1550->dev, irq,
+ "Failed to get parent vIRQ(%d) for chip %s\n",
+ PF1550_IRQ_CHG, pf1550_irq_chip.name);
+
+ ret = devm_regmap_add_irq_chip(pf1550->dev, pf1550->regmap, irq,
+ IRQF_ONESHOT | IRQF_SHARED |
+ IRQF_TRIGGER_FALLING, 0,
+ &pf1550_charger_irq_chip,
+ &pf1550->irq_data_charger);
+ if (ret)
+ return dev_err_probe(pf1550->dev, ret, "Failed to add %s IRQ chip\n",
+ pf1550_charger_irq_chip.name);
+
+ domain = regmap_irq_get_domain(pf1550->irq_data_charger);
+
+ return devm_mfd_add_devices(pf1550->dev, PLATFORM_DEVID_NONE, charger, 1, NULL, 0, domain);
+}
+
+static int pf1550_suspend(struct device *dev)
+{
+ struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ enable_irq_wake(pf1550->irq);
+ disable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+
+static int pf1550_resume(struct device *dev)
+{
+ struct pf1550_ddata *pf1550 = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(pf1550->irq);
+ enable_irq(pf1550->irq);
+ }
+
+ return 0;
+}
+static DEFINE_SIMPLE_DEV_PM_OPS(pf1550_pm, pf1550_suspend, pf1550_resume);
+
+static const struct i2c_device_id pf1550_i2c_id[] = {
+ { "pf1550" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, pf1550_i2c_id);
+
+static const struct of_device_id pf1550_dt_match[] = {
+ { .compatible = "nxp,pf1550" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pf1550_dt_match);
+
+static struct i2c_driver pf1550_i2c_driver = {
+ .driver = {
+ .name = "pf1550",
+ .pm = pm_sleep_ptr(&pf1550_pm),
+ .of_match_table = pf1550_dt_match,
+ },
+ .probe = pf1550_i2c_probe,
+ .id_table = pf1550_i2c_id,
+};
+module_i2c_driver(pf1550_i2c_driver);
+
+MODULE_DESCRIPTION("NXP PF1550 core driver");
+MODULE_AUTHOR("Robin Gong <yibin.gong@freescale.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/qnap-mcu.c b/drivers/mfd/qnap-mcu.c
index 4ec1f4cf902f..f81c69f22254 100644
--- a/drivers/mfd/qnap-mcu.c
+++ b/drivers/mfd/qnap-mcu.c
@@ -19,6 +19,7 @@
/* The longest command found so far is 5 bytes long */
#define QNAP_MCU_MAX_CMD_SIZE 5
#define QNAP_MCU_MAX_DATA_SIZE 36
+#define QNAP_MCU_ERROR_SIZE 2
#define QNAP_MCU_CHECKSUM_SIZE 1
#define QNAP_MCU_RX_BUFFER_SIZE \
@@ -78,6 +79,13 @@ static u8 qnap_mcu_csum(const u8 *buf, size_t size)
return csum;
}
+static bool qnap_mcu_verify_checksum(const u8 *buf, size_t size)
+{
+ u8 crc = qnap_mcu_csum(buf, size - QNAP_MCU_CHECKSUM_SIZE);
+
+ return crc == buf[size - QNAP_MCU_CHECKSUM_SIZE];
+}
+
static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size)
{
unsigned char tx[QNAP_MCU_TX_BUFFER_SIZE];
@@ -96,6 +104,48 @@ static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size)
return serdev_device_write(mcu->serdev, tx, length, HZ);
}
+static bool qnap_mcu_is_error_msg(size_t size)
+{
+ return (size == QNAP_MCU_ERROR_SIZE + QNAP_MCU_CHECKSUM_SIZE);
+}
+
+static bool qnap_mcu_reply_is_generic_error(unsigned char *buf, size_t size)
+{
+ if (!qnap_mcu_is_error_msg(size))
+ return false;
+
+ if (buf[0] == '@' && buf[1] == '9')
+ return true;
+
+ return false;
+}
+
+static bool qnap_mcu_reply_is_checksum_error(unsigned char *buf, size_t size)
+{
+ if (!qnap_mcu_is_error_msg(size))
+ return false;
+
+ if (buf[0] == '@' && buf[1] == '8')
+ return true;
+
+ return false;
+}
+
+static bool qnap_mcu_reply_is_any_error(struct qnap_mcu *mcu, unsigned char *buf, size_t size)
+{
+ if (qnap_mcu_reply_is_generic_error(buf, size)) {
+ dev_err(&mcu->serdev->dev, "Controller sent generic error response\n");
+ return true;
+ }
+
+ if (qnap_mcu_reply_is_checksum_error(buf, size)) {
+ dev_err(&mcu->serdev->dev, "Controller received invalid checksum for the command\n");
+ return true;
+ }
+
+ return false;
+}
+
static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t size)
{
struct device *dev = &serdev->dev;
@@ -130,6 +180,24 @@ static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf,
}
/*
+ * We received everything the uart had to offer for now.
+ * This could mean that either the uart will send more in a 2nd
+ * receive run, or that the MCU cut the reply short because it
+ * sent an error code instead of the expected reply.
+ *
+ * So check if the received data has the correct size for an error
+ * reply and if it matches, is an actual error code.
+ */
+ if (qnap_mcu_is_error_msg(reply->received) &&
+ qnap_mcu_verify_checksum(reply->data, reply->received) &&
+ qnap_mcu_reply_is_any_error(mcu, reply->data, reply->received)) {
+ /* The reply was an error code, we're done */
+ reply->length = 0;
+
+ complete(&reply->done);
+ }
+
+ /*
* The only way to get out of the above loop and end up here
* is through consuming all of the supplied data, so here we
* report that we processed it all.
@@ -150,7 +218,6 @@ int qnap_mcu_exec(struct qnap_mcu *mcu,
size_t length = reply_data_size + QNAP_MCU_CHECKSUM_SIZE;
struct qnap_mcu_reply *reply = &mcu->reply;
int ret = 0;
- u8 crc;
if (length > sizeof(rx)) {
dev_err(&mcu->serdev->dev, "expected data too big for receive buffer");
@@ -175,12 +242,14 @@ int qnap_mcu_exec(struct qnap_mcu *mcu,
return -ETIMEDOUT;
}
- crc = qnap_mcu_csum(rx, reply_data_size);
- if (crc != rx[reply_data_size]) {
- dev_err(&mcu->serdev->dev, "Invalid Checksum received\n");
- return -EIO;
+ if (!qnap_mcu_verify_checksum(rx, reply->received)) {
+ dev_err(&mcu->serdev->dev, "Invalid Checksum received from controller\n");
+ return -EPROTO;
}
+ if (qnap_mcu_reply_is_any_error(mcu, rx, reply->received))
+ return -EPROTO;
+
memcpy(reply_data, rx, reply_data_size);
return 0;
@@ -264,6 +333,7 @@ static const struct qnap_mcu_variant qnap_ts433_mcu = {
};
static struct mfd_cell qnap_mcu_cells[] = {
+ { .name = "qnap-mcu-eeprom", },
{ .name = "qnap-mcu-input", },
{ .name = "qnap-mcu-leds", },
{ .name = "qnap-mcu-hwmon", }
diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
index 25e494a93d48..ff714fd4f54d 100644
--- a/drivers/mfd/rohm-bd718x7.c
+++ b/drivers/mfd/rohm-bd718x7.c
@@ -72,14 +72,13 @@ static const struct regmap_irq_chip bd718xx_irq_chip = {
.init_ack_masked = true,
};
-static const struct regmap_range pmic_status_range = {
- .range_min = BD718XX_REG_IRQ,
- .range_max = BD718XX_REG_POW_STATE,
+static const struct regmap_range pmic_status_range[] = {
+ regmap_reg_range(BD718XX_REG_IRQ, BD718XX_REG_POW_STATE),
};
static const struct regmap_access_table volatile_regs = {
- .yes_ranges = &pmic_status_range,
- .n_yes_ranges = 1,
+ .yes_ranges = &pmic_status_range[0],
+ .n_yes_ranges = ARRAY_SIZE(pmic_status_range),
};
static const struct regmap_config bd718xx_regmap_config = {
diff --git a/drivers/mfd/sec-acpm.c b/drivers/mfd/sec-acpm.c
index 8b31c816d65b..36622069a788 100644
--- a/drivers/mfd/sec-acpm.c
+++ b/drivers/mfd/sec-acpm.c
@@ -325,11 +325,6 @@ static struct regmap *sec_pmic_acpm_regmap_init(struct device *dev,
return regmap;
}
-static void sec_pmic_acpm_mask_common_irqs(void *regmap_common)
-{
- regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC);
-}
-
static int sec_pmic_acpm_probe(struct platform_device *pdev)
{
struct regmap *regmap_common, *regmap_pmic, *regmap;
@@ -360,15 +355,10 @@ static int sec_pmic_acpm_probe(struct platform_device *pdev)
shared_ctx->speedy_channel = pdata->speedy_channel;
regmap_common = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_COMMON,
- pdata->regmap_cfg_common, false);
+ pdata->regmap_cfg_common, true);
if (IS_ERR(regmap_common))
return PTR_ERR(regmap_common);
- /* Mask all interrupts from 'common' block, until successful init */
- ret = regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC);
- if (ret)
- return dev_err_probe(dev, ret, "failed to mask common block interrupts\n");
-
regmap_pmic = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_PMIC,
pdata->regmap_cfg_pmic, false);
if (IS_ERR(regmap_pmic))
@@ -391,17 +381,6 @@ static int sec_pmic_acpm_probe(struct platform_device *pdev)
if (device_property_read_bool(dev, "wakeup-source"))
devm_device_init_wakeup(dev);
- /* Unmask PMIC interrupt from 'common' block, now that everything is in place. */
- ret = regmap_clear_bits(regmap_common, S2MPG10_COMMON_INT_MASK,
- S2MPG10_COMMON_INT_SRC_PMIC);
- if (ret)
- return dev_err_probe(dev, ret, "failed to unmask PMIC interrupt\n");
-
- /* Mask all interrupts from 'common' block on shutdown */
- ret = devm_add_action_or_reset(dev, sec_pmic_acpm_mask_common_irqs, regmap_common);
- if (ret)
- return ret;
-
return 0;
}
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index c5c80b1ba104..74ac70002d1f 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -20,6 +20,12 @@
#include "sec-core.h"
static const struct regmap_irq s2mpg10_irqs[] = {
+ REGMAP_IRQ_REG(S2MPG10_COMMON_IRQ_PMIC, 0, S2MPG10_COMMON_INT_SRC_PMIC),
+ /* No documentation or other reference for remaining bits */
+ REGMAP_IRQ_REG(S2MPG10_COMMON_IRQ_UNUSED, 0, GENMASK(7, 1)),
+};
+
+static const struct regmap_irq s2mpg10_pmic_irqs[] = {
REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONF, 0, S2MPG10_IRQ_PWRONF_MASK),
REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONR, 0, S2MPG10_IRQ_PWRONR_MASK),
REGMAP_IRQ_REG(S2MPG10_IRQ_JIGONBF, 0, S2MPG10_IRQ_JIGONBF_MASK),
@@ -183,11 +189,20 @@ static const struct regmap_irq s5m8767_irqs[] = {
/* All S2MPG10 interrupt sources are read-only and don't require clearing */
static const struct regmap_irq_chip s2mpg10_irq_chip = {
.name = "s2mpg10",
+ .status_base = S2MPG10_COMMON_INT,
+ .mask_base = S2MPG10_COMMON_INT_MASK,
+ .num_regs = 1,
.irqs = s2mpg10_irqs,
.num_irqs = ARRAY_SIZE(s2mpg10_irqs),
- .num_regs = 6,
+};
+
+static const struct regmap_irq_chip s2mpg10_irq_chip_pmic = {
+ .name = "s2mpg10-pmic",
.status_base = S2MPG10_PMIC_INT1,
.mask_base = S2MPG10_PMIC_INT1M,
+ .num_regs = 6,
+ .irqs = s2mpg10_pmic_irqs,
+ .num_irqs = ARRAY_SIZE(s2mpg10_pmic_irqs),
};
static const struct regmap_irq_chip s2mps11_irq_chip = {
@@ -253,6 +268,59 @@ static const struct regmap_irq_chip s5m8767_irq_chip = {
.ack_base = S5M8767_REG_INT1,
};
+static int s2mpg1x_add_chained_irq_chip(struct device *dev, struct regmap *regmap, int pirq,
+ struct regmap_irq_chip_data *parent,
+ const struct regmap_irq_chip *chip,
+ struct regmap_irq_chip_data **data)
+{
+ int irq, ret;
+
+ irq = regmap_irq_get_virq(parent, pirq);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", pirq,
+ chip->name);
+
+ ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT | IRQF_SHARED, 0, chip, data);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name);
+
+ return 0;
+}
+
+static int sec_irq_init_s2mpg1x(struct sec_pmic_dev *sec_pmic)
+{
+ const struct regmap_irq_chip *irq_chip, *chained_irq_chip;
+ struct regmap_irq_chip_data *irq_data;
+ struct regmap *regmap_common;
+ int chained_pirq;
+ int ret;
+
+ switch (sec_pmic->device_type) {
+ case S2MPG10:
+ irq_chip = &s2mpg10_irq_chip;
+ chained_irq_chip = &s2mpg10_irq_chip_pmic;
+ chained_pirq = S2MPG10_COMMON_IRQ_PMIC;
+ break;
+ default:
+ return dev_err_probe(sec_pmic->dev, -EINVAL, "Unsupported device type %d\n",
+ sec_pmic->device_type);
+ }
+
+ regmap_common = dev_get_regmap(sec_pmic->dev, "common");
+ if (!regmap_common)
+ return dev_err_probe(sec_pmic->dev, -EINVAL, "No 'common' regmap %d\n",
+ sec_pmic->device_type);
+
+ ret = devm_regmap_add_irq_chip(sec_pmic->dev, regmap_common, sec_pmic->irq, IRQF_ONESHOT, 0,
+ irq_chip, &irq_data);
+ if (ret)
+ return dev_err_probe(sec_pmic->dev, ret, "Failed to add %s IRQ chip\n",
+ irq_chip->name);
+
+ return s2mpg1x_add_chained_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic, chained_pirq,
+ irq_data, chained_irq_chip, &sec_pmic->irq_data);
+}
+
int sec_irq_init(struct sec_pmic_dev *sec_pmic)
{
const struct regmap_irq_chip *sec_irq_chip;
@@ -268,8 +336,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
sec_irq_chip = &s2mps14_irq_chip;
break;
case S2MPG10:
- sec_irq_chip = &s2mpg10_irq_chip;
- break;
+ return sec_irq_init_s2mpg1x(sec_pmic);
case S2MPS11X:
sec_irq_chip = &s2mps11_irq_chip;
break;
diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c
index 0a607a1e3ca1..8b751d8e3b5a 100644
--- a/drivers/mfd/simple-mfd-i2c.c
+++ b/drivers/mfd/simple-mfd-i2c.c
@@ -15,12 +15,18 @@
* will be subsequently registered.
*/
+#include <linux/array_size.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/kernel.h>
#include <linux/mfd/core.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/stddef.h>
#include "simple-mfd-i2c.h"
@@ -114,11 +120,11 @@ static const struct of_device_id simple_mfd_i2c_of_match[] = {
{ .compatible = "fsl,lx2160aqds-fpga" },
{ .compatible = "fsl,lx2160ardb-fpga" },
{ .compatible = "kontron,sl28cpld" },
- { .compatible = "maxim,max5970", .data = &maxim_max5970},
- { .compatible = "maxim,max5978", .data = &maxim_max5970},
- { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705},
- { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a},
- { .compatible = "spacemit,p1", .data = &spacemit_p1, },
+ { .compatible = "maxim,max5970", .data = &maxim_max5970 },
+ { .compatible = "maxim,max5978", .data = &maxim_max5970 },
+ { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705 },
+ { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a },
+ { .compatible = "spacemit,p1", .data = &spacemit_p1 },
{}
};
MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match);
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index ae71a2710bed..e5d5def594f6 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -183,7 +183,7 @@ static struct regmap *device_node_get_regmap(struct device_node *np,
if (create_regmap)
syscon = of_syscon_register(np, check_res);
else
- syscon = ERR_PTR(-EINVAL);
+ syscon = ERR_PTR(-EPROBE_DEFER);
}
mutex_unlock(&syscon_list_lock);
diff --git a/drivers/mfd/tqmx86.c b/drivers/mfd/tqmx86.c
index 1cba3b67b0fb..1c2fe3f91238 100644
--- a/drivers/mfd/tqmx86.c
+++ b/drivers/mfd/tqmx86.c
@@ -43,6 +43,8 @@
#define TQMX86_REG_BOARD_ID_E40C2 15
#define TQMX86_REG_BOARD_ID_130UC 16
#define TQMX86_REG_BOARD_ID_E41S 19
+#define TQMX86_REG_BOARD_ID_CU1_HPCM 24
+#define TQMX86_REG_BOARD_ID_CU2_HPCM 25
#define TQMX86_REG_BOARD_REV 0x01
#define TQMX86_REG_IO_EXT_INT 0x06
#define TQMX86_REG_IO_EXT_INT_NONE 0
@@ -165,6 +167,10 @@ static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc)
return "TQMx130UC";
case TQMX86_REG_BOARD_ID_E41S:
return "TQMxE41S";
+ case TQMX86_REG_BOARD_ID_CU1_HPCM:
+ return "TQMxCU1-HPCM";
+ case TQMX86_REG_BOARD_ID_CU2_HPCM:
+ return "TQMxCU2-HPCM";
default:
return "Unknown";
}
@@ -185,6 +191,8 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id)
case TQMX86_REG_BOARD_ID_E40C2:
case TQMX86_REG_BOARD_ID_130UC:
case TQMX86_REG_BOARD_ID_E41S:
+ case TQMX86_REG_BOARD_ID_CU1_HPCM:
+ case TQMX86_REG_BOARD_ID_CU2_HPCM:
return 24000;
case TQMX86_REG_BOARD_ID_E39MS:
case TQMX86_REG_BOARD_ID_E39C1:
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c
deleted file mode 100644
index 2f185e93318e..000000000000
--- a/drivers/mfd/wl1273-core.c
+++ /dev/null
@@ -1,262 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * MFD driver for wl1273 FM radio and audio codec submodules.
- *
- * Copyright (C) 2011 Nokia Corporation
- * Author: Matti Aaltonen <matti.j.aaltonen@nokia.com>
- */
-
-#include <linux/mfd/wl1273-core.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#define DRIVER_DESC "WL1273 FM Radio Core"
-
-static const struct i2c_device_id wl1273_driver_id_table[] = {
- { WL1273_FM_DRIVER_NAME },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table);
-
-static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value)
-{
- struct i2c_client *client = core->client;
- u8 b[2];
- int r;
-
- r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b);
- if (r != 2) {
- dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg);
- return -EREMOTEIO;
- }
-
- *value = (u16)b[0] << 8 | b[1];
-
- return 0;
-}
-
-static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param)
-{
- struct i2c_client *client = core->client;
- u8 buf[] = { (param >> 8) & 0xff, param & 0xff };
- int r;
-
- r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf);
- if (r) {
- dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd);
- return r;
- }
-
- return 0;
-}
-
-static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len)
-{
- struct i2c_client *client = core->client;
- struct i2c_msg msg;
- int r;
-
- msg.addr = client->addr;
- msg.flags = 0;
- msg.buf = data;
- msg.len = len;
-
- r = i2c_transfer(client->adapter, &msg, 1);
- if (r != 1) {
- dev_err(&client->dev, "%s: write error.\n", __func__);
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-/**
- * wl1273_fm_set_audio() - Set audio mode.
- * @core: A pointer to the device struct.
- * @new_mode: The new audio mode.
- *
- * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG.
- */
-static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode)
-{
- int r = 0;
-
- if (core->mode == WL1273_MODE_OFF ||
- core->mode == WL1273_MODE_SUSPENDED)
- return -EPERM;
-
- if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) {
- r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET,
- WL1273_PCM_DEF_MODE);
- if (r)
- goto out;
-
- r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
- core->i2s_mode);
- if (r)
- goto out;
-
- r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
- WL1273_AUDIO_ENABLE_I2S);
- if (r)
- goto out;
-
- } else if (core->mode == WL1273_MODE_RX &&
- new_mode == WL1273_AUDIO_ANALOG) {
- r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
- WL1273_AUDIO_ENABLE_ANALOG);
- if (r)
- goto out;
-
- } else if (core->mode == WL1273_MODE_TX &&
- new_mode == WL1273_AUDIO_DIGITAL) {
- r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
- core->i2s_mode);
- if (r)
- goto out;
-
- r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
- WL1273_AUDIO_IO_SET_I2S);
- if (r)
- goto out;
-
- } else if (core->mode == WL1273_MODE_TX &&
- new_mode == WL1273_AUDIO_ANALOG) {
- r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
- WL1273_AUDIO_IO_SET_ANALOG);
- if (r)
- goto out;
- }
-
- core->audio_mode = new_mode;
-out:
- return r;
-}
-
-/**
- * wl1273_fm_set_volume() - Set volume.
- * @core: A pointer to the device struct.
- * @volume: The new volume value.
- */
-static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
-{
- int r;
-
- if (volume > WL1273_MAX_VOLUME)
- return -EINVAL;
-
- if (core->volume == volume)
- return 0;
-
- r = wl1273_fm_write_cmd(core, WL1273_VOLUME_SET, volume);
- if (r)
- return r;
-
- core->volume = volume;
- return 0;
-}
-
-static int wl1273_core_probe(struct i2c_client *client)
-{
- struct wl1273_fm_platform_data *pdata = dev_get_platdata(&client->dev);
- struct wl1273_core *core;
- struct mfd_cell *cell;
- int children = 0;
- int r = 0;
-
- dev_dbg(&client->dev, "%s\n", __func__);
-
- if (!pdata) {
- dev_err(&client->dev, "No platform data.\n");
- return -EINVAL;
- }
-
- if (!(pdata->children & WL1273_RADIO_CHILD)) {
- dev_err(&client->dev, "Cannot function without radio child.\n");
- return -EINVAL;
- }
-
- core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL);
- if (!core)
- return -ENOMEM;
-
- core->pdata = pdata;
- core->client = client;
- mutex_init(&core->lock);
-
- i2c_set_clientdata(client, core);
-
- dev_dbg(&client->dev, "%s: Have V4L2.\n", __func__);
-
- cell = &core->cells[children];
- cell->name = "wl1273_fm_radio";
- cell->platform_data = &core;
- cell->pdata_size = sizeof(core);
- children++;
-
- core->read = wl1273_fm_read_reg;
- core->write = wl1273_fm_write_cmd;
- core->write_data = wl1273_fm_write_data;
- core->set_audio = wl1273_fm_set_audio;
- core->set_volume = wl1273_fm_set_volume;
-
- if (pdata->children & WL1273_CODEC_CHILD) {
- cell = &core->cells[children];
-
- dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
- cell->name = "wl1273-codec";
- cell->platform_data = &core;
- cell->pdata_size = sizeof(core);
- children++;
- }
-
- dev_dbg(&client->dev, "%s: number of children: %d.\n",
- __func__, children);
-
- r = devm_mfd_add_devices(&client->dev, -1, core->cells,
- children, NULL, 0, NULL);
- if (r)
- goto err;
-
- return 0;
-
-err:
- pdata->free_resources();
-
- dev_dbg(&client->dev, "%s\n", __func__);
-
- return r;
-}
-
-static struct i2c_driver wl1273_core_driver = {
- .driver = {
- .name = WL1273_FM_DRIVER_NAME,
- },
- .probe = wl1273_core_probe,
- .id_table = wl1273_driver_id_table,
-};
-
-static int __init wl1273_core_init(void)
-{
- int r;
-
- r = i2c_add_driver(&wl1273_core_driver);
- if (r) {
- pr_err(WL1273_FM_DRIVER_NAME
- ": driver registration failed\n");
- return r;
- }
-
- return r;
-}
-
-static void __exit wl1273_core_exit(void)
-{
- i2c_del_driver(&wl1273_core_driver);
-}
-late_initcall(wl1273_core_init);
-module_exit(wl1273_core_exit);
-
-MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");