summaryrefslogtreecommitdiff
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/88pm886.c14
-rw-r--r--drivers/mfd/Kconfig35
-rw-r--r--drivers/mfd/Makefile5
-rw-r--r--drivers/mfd/aat2870-core.c4
-rw-r--r--drivers/mfd/as3722.c4
-rw-r--r--drivers/mfd/bcm590xx.c66
-rw-r--r--drivers/mfd/exynos-lpass.c31
-rw-r--r--drivers/mfd/max14577.c1
-rw-r--r--drivers/mfd/max77541.c2
-rw-r--r--drivers/mfd/max77705.c4
-rw-r--r--drivers/mfd/max8925-i2c.c1
-rw-r--r--drivers/mfd/rohm-bd96801.c565
-rw-r--r--drivers/mfd/rt5033.c6
-rw-r--r--drivers/mfd/sec-acpm.c442
-rw-r--r--drivers/mfd/sec-common.c301
-rw-r--r--drivers/mfd/sec-core.c481
-rw-r--r--drivers/mfd/sec-core.h23
-rw-r--r--drivers/mfd/sec-i2c.c239
-rw-r--r--drivers/mfd/sec-irq.c460
-rw-r--r--drivers/mfd/sm501.c50
-rw-r--r--drivers/mfd/sprd-sc27xx-spi.c5
-rw-r--r--drivers/mfd/stm32-lptimer.c33
-rw-r--r--drivers/mfd/stmpe-spi.c2
-rw-r--r--drivers/mfd/tps65010.c9
-rw-r--r--drivers/mfd/ucb1x00-core.c7
25 files changed, 1799 insertions, 991 deletions
diff --git a/drivers/mfd/88pm886.c b/drivers/mfd/88pm886.c
index 891fdce5d8c1..39dd9a818b0f 100644
--- a/drivers/mfd/88pm886.c
+++ b/drivers/mfd/88pm886.c
@@ -16,11 +16,11 @@ static const struct regmap_config pm886_regmap_config = {
.max_register = PM886_REG_RTC_SPARE6,
};
-static struct regmap_irq pm886_regmap_irqs[] = {
+static const struct regmap_irq pm886_regmap_irqs[] = {
REGMAP_IRQ_REG(PM886_IRQ_ONKEY, 0, PM886_INT_ENA1_ONKEY),
};
-static struct regmap_irq_chip pm886_regmap_irq_chip = {
+static const struct regmap_irq_chip pm886_regmap_irq_chip = {
.name = "88pm886",
.irqs = pm886_regmap_irqs,
.num_irqs = ARRAY_SIZE(pm886_regmap_irqs),
@@ -30,11 +30,11 @@ static struct regmap_irq_chip pm886_regmap_irq_chip = {
.unmask_base = PM886_REG_INT_ENA_1,
};
-static struct resource pm886_onkey_resources[] = {
+static const struct resource pm886_onkey_resources[] = {
DEFINE_RES_IRQ_NAMED(PM886_IRQ_ONKEY, "88pm886-onkey"),
};
-static struct mfd_cell pm886_devs[] = {
+static const struct mfd_cell pm886_devs[] = {
MFD_CELL_RES("88pm886-onkey", pm886_onkey_resources),
MFD_CELL_NAME("88pm886-regulator"),
MFD_CELL_NAME("88pm886-rtc"),
@@ -124,7 +124,11 @@ static int pm886_probe(struct i2c_client *client)
if (err)
return dev_err_probe(dev, err, "Failed to register power off handler\n");
- device_init_wakeup(dev, device_property_read_bool(dev, "wakeup-source"));
+ if (device_property_read_bool(dev, "wakeup-source")) {
+ err = devm_device_init_wakeup(dev);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to init wakeup\n");
+ }
return 0;
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 96992af22565..6fb3768e3d71 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1312,21 +1312,42 @@ config MFD_RN5T618
functionality of the device.
config MFD_SEC_CORE
- tristate "Samsung Electronics PMIC Series Support"
+ tristate
+ select MFD_CORE
+ select REGMAP_IRQ
+
+config MFD_SEC_ACPM
+ tristate "Samsung Electronics S2MPG1x PMICs"
+ depends on EXYNOS_ACPM_PROTOCOL
+ depends on OF
+ select MFD_SEC_CORE
+ help
+ Support for the Samsung Electronics PMICs with ACPM interface.
+ This is a Power Management IC for mobile applications with buck
+ converters, various LDOs, power meters, RTC, clock outputs, and
+ additional GPIOs interfaces.
+ This driver provides common support for accessing the device;
+ additional drivers must be enabled in order to use the functionality
+ of the device.
+
+ To compile this driver as a module, choose M here: the module will be
+ called sec-acpm.
+
+config MFD_SEC_I2C
+ tristate "Samsung Electronics S2MPA/S2MPS1X/S2MPU/S5M series PMICs"
depends on I2C=y
depends on OF
- select MFD_CORE
+ select MFD_SEC_CORE
select REGMAP_I2C
- select REGMAP_IRQ
help
- Support for the Samsung Electronics PMIC devices coming
- usually along with Samsung Exynos SoC chipset.
+ Support for the Samsung Electronics PMIC devices with I2C interface
+ coming usually along with Samsung Exynos SoC chipset.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
- of the device
+ of the device.
To compile this driver as a module, choose M here: the
- module will be called sec-core.
+ module will be called sec-i2c.
Have in mind that important core drivers (like regulators) depend
on this driver so building this as a module might require proper
initial ramdisk or might not boot up as well in certain scenarios.
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 5e5cc279af60..79495f9f3457 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -229,7 +229,10 @@ obj-$(CONFIG_MFD_RK8XX) += rk8xx-core.o
obj-$(CONFIG_MFD_RK8XX_I2C) += rk8xx-i2c.o
obj-$(CONFIG_MFD_RK8XX_SPI) += rk8xx-spi.o
obj-$(CONFIG_MFD_RN5T618) += rn5t618.o
-obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o
+sec-core-objs := sec-common.o sec-irq.o
+obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o
+obj-$(CONFIG_MFD_SEC_ACPM) += sec-acpm.o
+obj-$(CONFIG_MFD_SEC_I2C) += sec-i2c.o
obj-$(CONFIG_MFD_SYSCON) += syscon.o
obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o
obj-$(CONFIG_MFD_VEXPRESS_SYSREG) += vexpress-sysreg.o
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
index 8ef510e84688..34d66ba9646a 100644
--- a/drivers/mfd/aat2870-core.c
+++ b/drivers/mfd/aat2870-core.c
@@ -320,9 +320,7 @@ static const struct file_operations aat2870_reg_fops = {
static void aat2870_init_debugfs(struct aat2870_data *aat2870)
{
- aat2870->dentry_root = debugfs_create_dir("aat2870", NULL);
-
- debugfs_create_file("regs", 0644, aat2870->dentry_root, aat2870,
+ debugfs_create_file("regs", 0644, aat2870->client->debugfs, aat2870,
&aat2870_reg_fops);
}
diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c
index 6c0d89b0c7e3..7ab6fcc9c27c 100644
--- a/drivers/mfd/as3722.c
+++ b/drivers/mfd/as3722.c
@@ -394,7 +394,9 @@ static int as3722_i2c_probe(struct i2c_client *i2c)
return ret;
}
- device_init_wakeup(as3722->dev, true);
+ ret = devm_device_init_wakeup(as3722->dev);
+ if (ret)
+ return dev_err_probe(as3722->dev, ret, "Failed to init wakeup\n");
dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n");
return 0;
diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c
index 8b56786d85d0..5a8456bbd63f 100644
--- a/drivers/mfd/bcm590xx.c
+++ b/drivers/mfd/bcm590xx.c
@@ -17,6 +17,15 @@
#include <linux/regmap.h>
#include <linux/slab.h>
+/* Under primary I2C address: */
+#define BCM590XX_REG_PMUID 0x1e
+
+#define BCM590XX_REG_PMUREV 0x1f
+#define BCM590XX_PMUREV_DIG_MASK 0xF
+#define BCM590XX_PMUREV_DIG_SHIFT 0
+#define BCM590XX_PMUREV_ANA_MASK 0xF0
+#define BCM590XX_PMUREV_ANA_SHIFT 4
+
static const struct mfd_cell bcm590xx_devs[] = {
{
.name = "bcm590xx-vregs",
@@ -37,6 +46,47 @@ static const struct regmap_config bcm590xx_regmap_config_sec = {
.cache_type = REGCACHE_MAPLE,
};
+/* Map PMU ID value to model name string */
+static const char * const bcm590xx_names[] = {
+ [BCM590XX_PMUID_BCM59054] = "BCM59054",
+ [BCM590XX_PMUID_BCM59056] = "BCM59056",
+};
+
+static int bcm590xx_parse_version(struct bcm590xx *bcm590xx)
+{
+ unsigned int id, rev;
+ int ret;
+
+ /* Get PMU ID and verify that it matches compatible */
+ ret = regmap_read(bcm590xx->regmap_pri, BCM590XX_REG_PMUID, &id);
+ if (ret) {
+ dev_err(bcm590xx->dev, "failed to read PMU ID: %d\n", ret);
+ return ret;
+ }
+
+ if (id != bcm590xx->pmu_id) {
+ dev_err(bcm590xx->dev, "Incorrect ID for %s: expected %x, got %x.\n",
+ bcm590xx_names[bcm590xx->pmu_id], bcm590xx->pmu_id, id);
+ return -ENODEV;
+ }
+
+ /* Get PMU revision and store it in the info struct */
+ ret = regmap_read(bcm590xx->regmap_pri, BCM590XX_REG_PMUREV, &rev);
+ if (ret) {
+ dev_err(bcm590xx->dev, "failed to read PMU revision: %d\n", ret);
+ return ret;
+ }
+
+ bcm590xx->rev_digital = (rev & BCM590XX_PMUREV_DIG_MASK) >> BCM590XX_PMUREV_DIG_SHIFT;
+
+ bcm590xx->rev_analog = (rev & BCM590XX_PMUREV_ANA_MASK) >> BCM590XX_PMUREV_ANA_SHIFT;
+
+ dev_dbg(bcm590xx->dev, "PMU ID 0x%x (%s), revision: digital %d, analog %d",
+ id, bcm590xx_names[id], bcm590xx->rev_digital, bcm590xx->rev_analog);
+
+ return 0;
+}
+
static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri)
{
struct bcm590xx *bcm590xx;
@@ -50,6 +100,8 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri)
bcm590xx->dev = &i2c_pri->dev;
bcm590xx->i2c_pri = i2c_pri;
+ bcm590xx->pmu_id = (uintptr_t) of_device_get_match_data(bcm590xx->dev);
+
bcm590xx->regmap_pri = devm_regmap_init_i2c(i2c_pri,
&bcm590xx_regmap_config_pri);
if (IS_ERR(bcm590xx->regmap_pri)) {
@@ -76,6 +128,10 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri)
goto err;
}
+ ret = bcm590xx_parse_version(bcm590xx);
+ if (ret)
+ goto err;
+
ret = devm_mfd_add_devices(&i2c_pri->dev, -1, bcm590xx_devs,
ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL);
if (ret < 0) {
@@ -91,12 +147,20 @@ err:
}
static const struct of_device_id bcm590xx_of_match[] = {
- { .compatible = "brcm,bcm59056" },
+ {
+ .compatible = "brcm,bcm59054",
+ .data = (void *)BCM590XX_PMUID_BCM59054,
+ },
+ {
+ .compatible = "brcm,bcm59056",
+ .data = (void *)BCM590XX_PMUID_BCM59056,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, bcm590xx_of_match);
static const struct i2c_device_id bcm590xx_i2c_id[] = {
+ { "bcm59054" },
{ "bcm59056" },
{ }
};
diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c
index 6a585173230b..44797001a432 100644
--- a/drivers/mfd/exynos-lpass.c
+++ b/drivers/mfd/exynos-lpass.c
@@ -104,11 +104,22 @@ static const struct regmap_config exynos_lpass_reg_conf = {
.fast_io = true,
};
+static void exynos_lpass_disable_lpass(void *data)
+{
+ struct platform_device *pdev = data;
+ struct exynos_lpass *lpass = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ if (!pm_runtime_status_suspended(&pdev->dev))
+ exynos_lpass_disable(lpass);
+}
+
static int exynos_lpass_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct exynos_lpass *lpass;
void __iomem *base_top;
+ int ret;
lpass = devm_kzalloc(dev, sizeof(*lpass), GFP_KERNEL);
if (!lpass)
@@ -122,8 +133,8 @@ static int exynos_lpass_probe(struct platform_device *pdev)
if (IS_ERR(lpass->sfr0_clk))
return PTR_ERR(lpass->sfr0_clk);
- lpass->top = regmap_init_mmio(dev, base_top,
- &exynos_lpass_reg_conf);
+ lpass->top = devm_regmap_init_mmio(dev, base_top,
+ &exynos_lpass_reg_conf);
if (IS_ERR(lpass->top)) {
dev_err(dev, "LPASS top regmap initialization failed\n");
return PTR_ERR(lpass->top);
@@ -134,18 +145,11 @@ static int exynos_lpass_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
exynos_lpass_enable(lpass);
- return devm_of_platform_populate(dev);
-}
-
-static void exynos_lpass_remove(struct platform_device *pdev)
-{
- struct exynos_lpass *lpass = platform_get_drvdata(pdev);
+ ret = devm_add_action_or_reset(dev, exynos_lpass_disable_lpass, pdev);
+ if (ret)
+ return ret;
- exynos_lpass_disable(lpass);
- pm_runtime_disable(&pdev->dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
- exynos_lpass_disable(lpass);
- regmap_exit(lpass->top);
+ return devm_of_platform_populate(dev);
}
static int __maybe_unused exynos_lpass_suspend(struct device *dev)
@@ -185,7 +189,6 @@ static struct platform_driver exynos_lpass_driver = {
.of_match_table = exynos_lpass_of_match,
},
.probe = exynos_lpass_probe,
- .remove = exynos_lpass_remove,
};
module_platform_driver(exynos_lpass_driver);
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index 6fce79ec2dc6..7e7e8af9af22 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -456,6 +456,7 @@ static void max14577_i2c_remove(struct i2c_client *i2c)
{
struct max14577 *max14577 = i2c_get_clientdata(i2c);
+ device_init_wakeup(max14577->dev, false);
mfd_remove_devices(max14577->dev);
regmap_del_irq_chip(max14577->irq, max14577->irq_data);
if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836)
diff --git a/drivers/mfd/max77541.c b/drivers/mfd/max77541.c
index d77c31c86e43..f91b4f5373ce 100644
--- a/drivers/mfd/max77541.c
+++ b/drivers/mfd/max77541.c
@@ -152,7 +152,7 @@ static int max77541_pmic_setup(struct device *dev)
if (ret)
return dev_err_probe(dev, ret, "Failed to initialize IRQ\n");
- ret = device_init_wakeup(dev, true);
+ ret = devm_device_init_wakeup(dev);
if (ret)
return dev_err_probe(dev, ret, "Unable to init wakeup\n");
diff --git a/drivers/mfd/max77705.c b/drivers/mfd/max77705.c
index 60c457c21d95..6b263bacb8c2 100644
--- a/drivers/mfd/max77705.c
+++ b/drivers/mfd/max77705.c
@@ -131,7 +131,9 @@ static int max77705_i2c_probe(struct i2c_client *i2c)
if (ret)
return dev_err_probe(dev, ret, "Failed to register child devices\n");
- device_init_wakeup(dev, true);
+ ret = devm_device_init_wakeup(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init wakeup\n");
return 0;
}
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 556aea7ec0a0..ab19ff0c7867 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -201,6 +201,7 @@ static void max8925_remove(struct i2c_client *client)
struct max8925_chip *chip = i2c_get_clientdata(client);
max8925_device_exit(chip);
+ device_init_wakeup(&client->dev, false);
i2c_unregister_device(chip->adc);
i2c_unregister_device(chip->rtc);
}
diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c
index 60ec8db790a7..66fa017ad568 100644
--- a/drivers/mfd/rohm-bd96801.c
+++ b/drivers/mfd/rohm-bd96801.c
@@ -38,108 +38,172 @@
#include <linux/types.h>
#include <linux/mfd/rohm-bd96801.h>
+#include <linux/mfd/rohm-bd96802.h>
#include <linux/mfd/rohm-generic.h>
-static const struct resource regulator_errb_irqs[] = {
- DEFINE_RES_IRQ_NAMED(BD96801_OTP_ERR_STAT, "bd96801-otp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_DBIST_ERR_STAT, "bd96801-dbist-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_EEP_ERR_STAT, "bd96801-eep-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_ABIST_ERR_STAT, "bd96801-abist-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_PRSTB_ERR_STAT, "bd96801-prstb-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_DRMOS1_ERR_STAT, "bd96801-drmoserr1"),
- DEFINE_RES_IRQ_NAMED(BD96801_DRMOS2_ERR_STAT, "bd96801-drmoserr2"),
- DEFINE_RES_IRQ_NAMED(BD96801_SLAVE_ERR_STAT, "bd96801-slave-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_VREF_ERR_STAT, "bd96801-vref-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_TSD_ERR_STAT, "bd96801-tsd"),
- DEFINE_RES_IRQ_NAMED(BD96801_UVLO_ERR_STAT, "bd96801-uvlo-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_OVLO_ERR_STAT, "bd96801-ovlo-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_OSC_ERR_STAT, "bd96801-osc-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_PON_ERR_STAT, "bd96801-pon-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_POFF_ERR_STAT, "bd96801-poff-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_CMD_SHDN_ERR_STAT, "bd96801-cmd-shdn-err"),
+struct bd968xx {
+ const struct resource *errb_irqs;
+ const struct resource *intb_irqs;
+ int num_errb_irqs;
+ int num_intb_irqs;
+ const struct regmap_irq_chip *errb_irq_chip;
+ const struct regmap_irq_chip *intb_irq_chip;
+ const struct regmap_config *regmap_config;
+ struct mfd_cell *cells;
+ int num_cells;
+ int unlock_reg;
+ int unlock_val;
+};
+
+static const struct resource bd96801_reg_errb_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD96801_OTP_ERR_STAT, "otp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_DBIST_ERR_STAT, "dbist-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_EEP_ERR_STAT, "eep-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_ABIST_ERR_STAT, "abist-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_PRSTB_ERR_STAT, "prstb-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_DRMOS1_ERR_STAT, "drmoserr1"),
+ DEFINE_RES_IRQ_NAMED(BD96801_DRMOS2_ERR_STAT, "drmoserr2"),
+ DEFINE_RES_IRQ_NAMED(BD96801_SLAVE_ERR_STAT, "slave-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_VREF_ERR_STAT, "vref-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_TSD_ERR_STAT, "tsd"),
+ DEFINE_RES_IRQ_NAMED(BD96801_UVLO_ERR_STAT, "uvlo-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_OVLO_ERR_STAT, "ovlo-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_OSC_ERR_STAT, "osc-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_PON_ERR_STAT, "pon-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_POFF_ERR_STAT, "poff-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_CMD_SHDN_ERR_STAT, "cmd-shdn-err"),
DEFINE_RES_IRQ_NAMED(BD96801_INT_PRSTB_WDT_ERR, "bd96801-prstb-wdt-err"),
DEFINE_RES_IRQ_NAMED(BD96801_INT_CHIP_IF_ERR, "bd96801-chip-if-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_INT_SHDN_ERR_STAT, "bd96801-int-shdn-err"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_PVIN_ERR_STAT, "bd96801-buck1-pvin-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVP_ERR_STAT, "bd96801-buck1-ovp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVP_ERR_STAT, "bd96801-buck1-uvp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_SHDN_ERR_STAT, "bd96801-buck1-shdn-err"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_PVIN_ERR_STAT, "bd96801-buck2-pvin-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVP_ERR_STAT, "bd96801-buck2-ovp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVP_ERR_STAT, "bd96801-buck2-uvp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_SHDN_ERR_STAT, "bd96801-buck2-shdn-err"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_PVIN_ERR_STAT, "bd96801-buck3-pvin-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVP_ERR_STAT, "bd96801-buck3-ovp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVP_ERR_STAT, "bd96801-buck3-uvp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_SHDN_ERR_STAT, "bd96801-buck3-shdn-err"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_PVIN_ERR_STAT, "bd96801-buck4-pvin-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVP_ERR_STAT, "bd96801-buck4-ovp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVP_ERR_STAT, "bd96801-buck4-uvp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_SHDN_ERR_STAT, "bd96801-buck4-shdn-err"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_LDO5_PVIN_ERR_STAT, "bd96801-ldo5-pvin-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVP_ERR_STAT, "bd96801-ldo5-ovp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVP_ERR_STAT, "bd96801-ldo5-uvp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO5_SHDN_ERR_STAT, "bd96801-ldo5-shdn-err"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_LDO6_PVIN_ERR_STAT, "bd96801-ldo6-pvin-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVP_ERR_STAT, "bd96801-ldo6-ovp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVP_ERR_STAT, "bd96801-ldo6-uvp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO6_SHDN_ERR_STAT, "bd96801-ldo6-shdn-err"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_LDO7_PVIN_ERR_STAT, "bd96801-ldo7-pvin-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVP_ERR_STAT, "bd96801-ldo7-ovp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVP_ERR_STAT, "bd96801-ldo7-uvp-err"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "bd96801-ldo7-shdn-err"),
-};
-
-static const struct resource regulator_intb_irqs[] = {
- DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "bd96801-core-thermal"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "bd96801-buck1-overcurr-h"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "bd96801-buck1-overcurr-l"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "bd96801-buck1-overcurr-n"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "bd96801-buck1-overvolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "bd96801-buck1-undervolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "bd96801-buck1-thermal"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "bd96801-buck2-overcurr-h"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "bd96801-buck2-overcurr-l"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "bd96801-buck2-overcurr-n"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "bd96801-buck2-overvolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "bd96801-buck2-undervolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "bd96801-buck2-thermal"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "bd96801-buck3-overcurr-h"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "bd96801-buck3-overcurr-l"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "bd96801-buck3-overcurr-n"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "bd96801-buck3-overvolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "bd96801-buck3-undervolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "bd96801-buck3-thermal"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "bd96801-buck4-overcurr-h"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "bd96801-buck4-overcurr-l"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "bd96801-buck4-overcurr-n"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "bd96801-buck4-overvolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "bd96801-buck4-undervolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "bd96801-buck4-thermal"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "bd96801-ldo5-overcurr"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "bd96801-ldo5-overvolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "bd96801-ldo5-undervolt"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "bd96801-ldo6-overcurr"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "bd96801-ldo6-overvolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "bd96801-ldo6-undervolt"),
-
- DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "bd96801-ldo7-overcurr"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "bd96801-ldo7-overvolt"),
- DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "bd96801-ldo7-undervolt"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_INT_SHDN_ERR_STAT, "int-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_PVIN_ERR_STAT, "buck1-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVP_ERR_STAT, "buck1-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVP_ERR_STAT, "buck1-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_SHDN_ERR_STAT, "buck1-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_PVIN_ERR_STAT, "buck2-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVP_ERR_STAT, "buck2-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVP_ERR_STAT, "buck2-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_SHDN_ERR_STAT, "buck2-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_PVIN_ERR_STAT, "buck3-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVP_ERR_STAT, "buck3-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVP_ERR_STAT, "buck3-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_SHDN_ERR_STAT, "buck3-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_PVIN_ERR_STAT, "buck4-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVP_ERR_STAT, "buck4-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVP_ERR_STAT, "buck4-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_SHDN_ERR_STAT, "buck4-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_PVIN_ERR_STAT, "ldo5-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVP_ERR_STAT, "ldo5-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVP_ERR_STAT, "ldo5-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_SHDN_ERR_STAT, "ldo5-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_PVIN_ERR_STAT, "ldo6-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVP_ERR_STAT, "ldo6-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVP_ERR_STAT, "ldo6-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_SHDN_ERR_STAT, "ldo6-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_PVIN_ERR_STAT, "ldo7-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVP_ERR_STAT, "ldo7-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVP_ERR_STAT, "ldo7-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "ldo7-shdn-err"),
+};
+
+static const struct resource bd96802_reg_errb_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD96802_OTP_ERR_STAT, "otp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_DBIST_ERR_STAT, "dbist-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_EEP_ERR_STAT, "eep-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_ABIST_ERR_STAT, "abist-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_PRSTB_ERR_STAT, "prstb-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_DRMOS1_ERR_STAT, "drmoserr1"),
+ DEFINE_RES_IRQ_NAMED(BD96802_DRMOS1_ERR_STAT, "drmoserr2"),
+ DEFINE_RES_IRQ_NAMED(BD96802_SLAVE_ERR_STAT, "slave-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_VREF_ERR_STAT, "vref-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_TSD_ERR_STAT, "tsd"),
+ DEFINE_RES_IRQ_NAMED(BD96802_UVLO_ERR_STAT, "uvlo-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_OVLO_ERR_STAT, "ovlo-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_OSC_ERR_STAT, "osc-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_PON_ERR_STAT, "pon-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_POFF_ERR_STAT, "poff-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_CMD_SHDN_ERR_STAT, "cmd-shdn-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_INT_SHDN_ERR_STAT, "int-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_PVIN_ERR_STAT, "buck1-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OVP_ERR_STAT, "buck1-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_UVP_ERR_STAT, "buck1-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_SHDN_ERR_STAT, "buck1-shdn-err"),
+
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_PVIN_ERR_STAT, "buck2-pvin-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OVP_ERR_STAT, "buck2-ovp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_UVP_ERR_STAT, "buck2-uvp-err"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_SHDN_ERR_STAT, "buck2-shdn-err"),
+};
+
+static const struct resource bd96801_reg_intb_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "core-thermal"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "buck1-overcurr-h"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "buck1-overcurr-l"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "buck1-overcurr-n"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "buck1-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "buck1-undervolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "buck1-thermal"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "buck2-overcurr-h"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "buck2-overcurr-l"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "buck2-overcurr-n"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "buck2-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "buck2-undervolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "buck2-thermal"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "buck3-overcurr-h"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "buck3-overcurr-l"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "buck3-overcurr-n"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "buck3-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "buck3-undervolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "buck3-thermal"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "buck4-overcurr-h"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "buck4-overcurr-l"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "buck4-overcurr-n"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "buck4-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "buck4-undervolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "buck4-thermal"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "ldo5-overcurr"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "ldo5-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "ldo5-undervolt"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "ldo6-overcurr"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "ldo6-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "ldo6-undervolt"),
+
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "ldo7-overcurr"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "ldo7-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "ldo7-undervolt"),
+};
+
+static const struct resource bd96802_reg_intb_irqs[] = {
+ DEFINE_RES_IRQ_NAMED(BD96802_TW_STAT, "core-thermal"),
+
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPH_STAT, "buck1-overcurr-h"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPL_STAT, "buck1-overcurr-l"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPN_STAT, "buck1-overcurr-n"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OVD_STAT, "buck1-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_UVD_STAT, "buck1-undervolt"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_TW_CH_STAT, "buck1-thermal"),
+
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPH_STAT, "buck2-overcurr-h"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPL_STAT, "buck2-overcurr-l"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPN_STAT, "buck2-overcurr-n"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OVD_STAT, "buck2-overvolt"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_UVD_STAT, "buck2-undervolt"),
+ DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_TW_CH_STAT, "buck2-thermal"),
};
enum {
@@ -152,6 +216,20 @@ static struct mfd_cell bd96801_cells[] = {
[REGULATOR_CELL] = { .name = "bd96801-regulator", },
};
+static struct mfd_cell bd96802_cells[] = {
+ [WDG_CELL] = { .name = "bd96801-wdt", },
+ [REGULATOR_CELL] = { .name = "bd96802-regulator", },
+};
+static struct mfd_cell bd96805_cells[] = {
+ [WDG_CELL] = { .name = "bd96801-wdt", },
+ [REGULATOR_CELL] = { .name = "bd96805-regulator", },
+};
+
+static struct mfd_cell bd96806_cells[] = {
+ [WDG_CELL] = { .name = "bd96806-wdt", },
+ [REGULATOR_CELL] = { .name = "bd96806-regulator", },
+};
+
static const struct regmap_range bd96801_volatile_ranges[] = {
/* Status registers */
regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT),
@@ -169,11 +247,28 @@ static const struct regmap_range bd96801_volatile_ranges[] = {
regmap_reg_range(BD96801_LDO5_VOL_LVL_REG, BD96801_LDO7_VOL_LVL_REG),
};
-static const struct regmap_access_table volatile_regs = {
+static const struct regmap_range bd96802_volatile_ranges[] = {
+ /* Status regs */
+ regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT),
+ regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK),
+ regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS),
+ regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_BUCK2_ERRB),
+ regmap_reg_range(BD96801_REG_INT_SYS_INTB, BD96801_REG_INT_BUCK2_INTB),
+ /* Registers which do not update value unless PMIC is in STBY */
+ regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB),
+ regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME),
+};
+
+static const struct regmap_access_table bd96801_volatile_regs = {
.yes_ranges = bd96801_volatile_ranges,
.n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges),
};
+static const struct regmap_access_table bd96802_volatile_regs = {
+ .yes_ranges = bd96802_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(bd96802_volatile_ranges),
+};
+
/*
* For ERRB we need main register bit mapping as bit(0) indicates active IRQ
* in one of the first 3 sub IRQ registers, For INTB we can use default 1 to 1
@@ -188,7 +283,7 @@ static unsigned int bit5_offsets[] = {7}; /* LDO 5 stat */
static unsigned int bit6_offsets[] = {8}; /* LDO 6 stat */
static unsigned int bit7_offsets[] = {9}; /* LDO 7 stat */
-static const struct regmap_irq_sub_irq_map errb_sub_irq_offsets[] = {
+static const struct regmap_irq_sub_irq_map bd96801_errb_sub_irq_offsets[] = {
REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
@@ -199,6 +294,12 @@ static const struct regmap_irq_sub_irq_map errb_sub_irq_offsets[] = {
REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets),
};
+static const struct regmap_irq_sub_irq_map bd96802_errb_sub_irq_offsets[] = {
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets),
+ REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets),
+};
+
static const struct regmap_irq bd96801_errb_irqs[] = {
/* Reg 0x52 Fatal ERRB1 */
REGMAP_IRQ_REG(BD96801_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK),
@@ -259,6 +360,39 @@ static const struct regmap_irq bd96801_errb_irqs[] = {
REGMAP_IRQ_REG(BD96801_LDO7_SHDN_ERR_STAT, 9, BD96801_OUT_SHDN_ERR_MASK),
};
+static const struct regmap_irq bd96802_errb_irqs[] = {
+ /* Reg 0x52 Fatal ERRB1 */
+ REGMAP_IRQ_REG(BD96802_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_DBIST_ERR_STAT, 0, BD96801_DBIST_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_EEP_ERR_STAT, 0, BD96801_EEP_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_ABIST_ERR_STAT, 0, BD96801_ABIST_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_PRSTB_ERR_STAT, 0, BD96801_PRSTB_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_DRMOS1_ERR_STAT, 0, BD96801_DRMOS1_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_DRMOS2_ERR_STAT, 0, BD96801_DRMOS2_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_SLAVE_ERR_STAT, 0, BD96801_SLAVE_ERR_MASK),
+ /* 0x53 Fatal ERRB2 */
+ REGMAP_IRQ_REG(BD96802_VREF_ERR_STAT, 1, BD96801_VREF_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_TSD_ERR_STAT, 1, BD96801_TSD_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_UVLO_ERR_STAT, 1, BD96801_UVLO_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_OVLO_ERR_STAT, 1, BD96801_OVLO_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_OSC_ERR_STAT, 1, BD96801_OSC_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_PON_ERR_STAT, 1, BD96801_PON_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_POFF_ERR_STAT, 1, BD96801_POFF_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_CMD_SHDN_ERR_STAT, 1, BD96801_CMD_SHDN_ERR_MASK),
+ /* 0x54 Fatal INTB shadowed to ERRB */
+ REGMAP_IRQ_REG(BD96802_INT_SHDN_ERR_STAT, 2, BD96801_INT_SHDN_ERR_MASK),
+ /* Reg 0x55 BUCK1 ERR IRQs */
+ REGMAP_IRQ_REG(BD96802_BUCK1_PVIN_ERR_STAT, 3, BD96801_OUT_PVIN_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_OVP_ERR_STAT, 3, BD96801_OUT_OVP_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_UVP_ERR_STAT, 3, BD96801_OUT_UVP_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_SHDN_ERR_STAT, 3, BD96801_OUT_SHDN_ERR_MASK),
+ /* Reg 0x56 BUCK2 ERR IRQs */
+ REGMAP_IRQ_REG(BD96802_BUCK2_PVIN_ERR_STAT, 4, BD96801_OUT_PVIN_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_OVP_ERR_STAT, 4, BD96801_OUT_OVP_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_UVP_ERR_STAT, 4, BD96801_OUT_UVP_ERR_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_SHDN_ERR_STAT, 4, BD96801_OUT_SHDN_ERR_MASK),
+};
+
static const struct regmap_irq bd96801_intb_irqs[] = {
/* STATUS SYSTEM INTB */
REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK),
@@ -307,6 +441,69 @@ static const struct regmap_irq bd96801_intb_irqs[] = {
REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK),
};
+static const struct regmap_irq bd96802_intb_irqs[] = {
+ /* STATUS SYSTEM INTB */
+ REGMAP_IRQ_REG(BD96802_TW_STAT, 0, BD96801_TW_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK),
+ /* STATUS BUCK1 INTB */
+ REGMAP_IRQ_REG(BD96802_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK),
+ /* BUCK 2 INTB */
+ REGMAP_IRQ_REG(BD96802_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK),
+ REGMAP_IRQ_REG(BD96802_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK),
+};
+
+/*
+ * The IRQ stuff is a bit hairy. The BD96801 / BD96802 provide two physical
+ * IRQ lines called INTB and ERRB. They share the same main status register.
+ *
+ * For ERRB, mapping from main status to sub-status is such that the
+ * 'global' faults are mapped to first 3 sub-status registers - and indicated
+ * by the first bit[0] in main status reg.
+ *
+ * Rest of the status registers are for indicating stuff for individual
+ * regulators, 1 sub register / regulator and 1 main status register bit /
+ * regulator, starting from bit[1].
+ *
+ * Eg, regulator specific stuff has 1 to 1 mapping from main-status to sub
+ * registers but 'global' ERRB IRQs require mapping from main status bit[0] to
+ * 3 status registers.
+ *
+ * Furthermore, the BD96801 has 7 regulators where the BD96802 has only 2.
+ *
+ * INTB has only 1 sub status register for 'global' events and then own sub
+ * status register for each of the regulators. So, for INTB we have direct
+ * 1 to 1 mapping - BD96801 just having 5 register and 5 main status bits
+ * more than the BD96802.
+ *
+ * Sharing the main status bits could be a problem if we had both INTB and
+ * ERRB IRQs asserted but for different sub-status offsets. This might lead
+ * IRQ controller code to go read a sub status register which indicates no
+ * active IRQs. I assume this occurring repeteadly might lead the IRQ to be
+ * disabled by core as a result of repeteadly returned IRQ_NONEs.
+ *
+ * I don't consider this as a fatal problem for now because:
+ * a) Having ERRB asserted leads to PMIC fault state which will kill
+ * the SoC powered by the PMIC. (So, relevant only for potential
+ * case of not powering the processor with this PMIC).
+ * b) Having ERRB set without having respective INTB is unlikely
+ * (haven't actually verified this).
+ *
+ * So, let's proceed with main status enabled for both INTB and ERRB. We can
+ * later disable main-status usage on systems where this ever proves to be
+ * a problem.
+ */
+
static const struct regmap_irq_chip bd96801_irq_chip_errb = {
.name = "bd96801-irq-errb",
.domain_suffix = "errb",
@@ -320,7 +517,23 @@ static const struct regmap_irq_chip bd96801_irq_chip_errb = {
.init_ack_masked = true,
.num_regs = 10,
.irq_reg_stride = 1,
- .sub_reg_offsets = &errb_sub_irq_offsets[0],
+ .sub_reg_offsets = &bd96801_errb_sub_irq_offsets[0],
+};
+
+static const struct regmap_irq_chip bd96802_irq_chip_errb = {
+ .name = "bd96802-irq-errb",
+ .domain_suffix = "errb",
+ .main_status = BD96801_REG_INT_MAIN,
+ .num_main_regs = 1,
+ .irqs = &bd96802_errb_irqs[0],
+ .num_irqs = ARRAY_SIZE(bd96802_errb_irqs),
+ .status_base = BD96801_REG_INT_SYS_ERRB1,
+ .mask_base = BD96801_REG_MASK_SYS_ERRB,
+ .ack_base = BD96801_REG_INT_SYS_ERRB1,
+ .init_ack_masked = true,
+ .num_regs = 5,
+ .irq_reg_stride = 1,
+ .sub_reg_offsets = &bd96802_errb_sub_irq_offsets[0],
};
static const struct regmap_irq_chip bd96801_irq_chip_intb = {
@@ -338,25 +551,124 @@ static const struct regmap_irq_chip bd96801_irq_chip_intb = {
.irq_reg_stride = 1,
};
+static const struct regmap_irq_chip bd96802_irq_chip_intb = {
+ .name = "bd96802-irq-intb",
+ .domain_suffix = "intb",
+ .main_status = BD96801_REG_INT_MAIN,
+ .num_main_regs = 1,
+ .irqs = &bd96802_intb_irqs[0],
+ .num_irqs = ARRAY_SIZE(bd96802_intb_irqs),
+ .status_base = BD96801_REG_INT_SYS_INTB,
+ .mask_base = BD96801_REG_MASK_SYS_INTB,
+ .ack_base = BD96801_REG_INT_SYS_INTB,
+ .init_ack_masked = true,
+ .num_regs = 3,
+ .irq_reg_stride = 1,
+};
+
static const struct regmap_config bd96801_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .volatile_table = &volatile_regs,
+ .volatile_table = &bd96801_volatile_regs,
+ .cache_type = REGCACHE_MAPLE,
+};
+
+static const struct regmap_config bd96802_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .volatile_table = &bd96802_volatile_regs,
.cache_type = REGCACHE_MAPLE,
};
+static const struct bd968xx bd96801_data = {
+ .errb_irqs = bd96801_reg_errb_irqs,
+ .intb_irqs = bd96801_reg_intb_irqs,
+ .num_errb_irqs = ARRAY_SIZE(bd96801_reg_errb_irqs),
+ .num_intb_irqs = ARRAY_SIZE(bd96801_reg_intb_irqs),
+ .errb_irq_chip = &bd96801_irq_chip_errb,
+ .intb_irq_chip = &bd96801_irq_chip_intb,
+ .regmap_config = &bd96801_regmap_config,
+ .cells = bd96801_cells,
+ .num_cells = ARRAY_SIZE(bd96801_cells),
+ .unlock_reg = BD96801_LOCK_REG,
+ .unlock_val = BD96801_UNLOCK,
+};
+
+static const struct bd968xx bd96802_data = {
+ .errb_irqs = bd96802_reg_errb_irqs,
+ .intb_irqs = bd96802_reg_intb_irqs,
+ .num_errb_irqs = ARRAY_SIZE(bd96802_reg_errb_irqs),
+ .num_intb_irqs = ARRAY_SIZE(bd96802_reg_intb_irqs),
+ .errb_irq_chip = &bd96802_irq_chip_errb,
+ .intb_irq_chip = &bd96802_irq_chip_intb,
+ .regmap_config = &bd96802_regmap_config,
+ .cells = bd96802_cells,
+ .num_cells = ARRAY_SIZE(bd96802_cells),
+ .unlock_reg = BD96801_LOCK_REG,
+ .unlock_val = BD96801_UNLOCK,
+};
+
+static const struct bd968xx bd96805_data = {
+ .errb_irqs = bd96801_reg_errb_irqs,
+ .intb_irqs = bd96801_reg_intb_irqs,
+ .num_errb_irqs = ARRAY_SIZE(bd96801_reg_errb_irqs),
+ .num_intb_irqs = ARRAY_SIZE(bd96801_reg_intb_irqs),
+ .errb_irq_chip = &bd96801_irq_chip_errb,
+ .intb_irq_chip = &bd96801_irq_chip_intb,
+ .regmap_config = &bd96801_regmap_config,
+ .cells = bd96805_cells,
+ .num_cells = ARRAY_SIZE(bd96805_cells),
+ .unlock_reg = BD96801_LOCK_REG,
+ .unlock_val = BD96801_UNLOCK,
+};
+
+static struct bd968xx bd96806_data = {
+ .errb_irqs = bd96802_reg_errb_irqs,
+ .intb_irqs = bd96802_reg_intb_irqs,
+ .num_errb_irqs = ARRAY_SIZE(bd96802_reg_errb_irqs),
+ .num_intb_irqs = ARRAY_SIZE(bd96802_reg_intb_irqs),
+ .errb_irq_chip = &bd96802_irq_chip_errb,
+ .intb_irq_chip = &bd96802_irq_chip_intb,
+ .regmap_config = &bd96802_regmap_config,
+ .cells = bd96806_cells,
+ .num_cells = ARRAY_SIZE(bd96806_cells),
+ .unlock_reg = BD96801_LOCK_REG,
+ .unlock_val = BD96801_UNLOCK,
+};
+
static int bd96801_i2c_probe(struct i2c_client *i2c)
{
struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data;
struct irq_domain *intb_domain, *errb_domain;
+ const struct bd968xx *ddata;
const struct fwnode_handle *fwnode;
struct resource *regulator_res;
struct resource wdg_irq;
struct regmap *regmap;
- int intb_irq, errb_irq, num_intb, num_errb = 0;
+ int intb_irq, errb_irq, num_errb = 0;
int num_regu_irqs, wdg_irq_no;
+ unsigned int chip_type;
int i, ret;
+ chip_type = (unsigned int)(uintptr_t)device_get_match_data(&i2c->dev);
+ switch (chip_type) {
+ case ROHM_CHIP_TYPE_BD96801:
+ ddata = &bd96801_data;
+ break;
+ case ROHM_CHIP_TYPE_BD96802:
+ ddata = &bd96802_data;
+ break;
+ case ROHM_CHIP_TYPE_BD96805:
+ ddata = &bd96805_data;
+ break;
+ case ROHM_CHIP_TYPE_BD96806:
+ ddata = &bd96806_data;
+ break;
+ default:
+ dev_err(&i2c->dev, "Unknown IC\n");
+ return -EINVAL;
+ }
+
fwnode = dev_fwnode(&i2c->dev);
if (!fwnode)
return dev_err_probe(&i2c->dev, -EINVAL, "Failed to find fwnode\n");
@@ -365,34 +677,32 @@ static int bd96801_i2c_probe(struct i2c_client *i2c)
if (intb_irq < 0)
return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n");
- num_intb = ARRAY_SIZE(regulator_intb_irqs);
-
/* ERRB may be omitted if processor is powered by the PMIC */
errb_irq = fwnode_irq_get_byname(fwnode, "errb");
- if (errb_irq < 0)
- errb_irq = 0;
+ if (errb_irq == -EPROBE_DEFER)
+ return errb_irq;
- if (errb_irq)
- num_errb = ARRAY_SIZE(regulator_errb_irqs);
+ if (errb_irq > 0)
+ num_errb = ddata->num_errb_irqs;
- num_regu_irqs = num_intb + num_errb;
+ num_regu_irqs = ddata->num_intb_irqs + num_errb;
regulator_res = devm_kcalloc(&i2c->dev, num_regu_irqs,
sizeof(*regulator_res), GFP_KERNEL);
if (!regulator_res)
return -ENOMEM;
- regmap = devm_regmap_init_i2c(i2c, &bd96801_regmap_config);
+ regmap = devm_regmap_init_i2c(i2c, ddata->regmap_config);
if (IS_ERR(regmap))
return dev_err_probe(&i2c->dev, PTR_ERR(regmap),
"Regmap initialization failed\n");
- ret = regmap_write(regmap, BD96801_LOCK_REG, BD96801_UNLOCK);
+ ret = regmap_write(regmap, ddata->unlock_reg, ddata->unlock_val);
if (ret)
return dev_err_probe(&i2c->dev, ret, "Failed to unlock PMIC\n");
ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq,
- IRQF_ONESHOT, 0, &bd96801_irq_chip_intb,
+ IRQF_ONESHOT, 0, ddata->intb_irq_chip,
&intb_irq_data);
if (ret)
return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n");
@@ -404,24 +714,25 @@ static int bd96801_i2c_probe(struct i2c_client *i2c)
* has two domains so we do IRQ mapping here and provide the
* already mapped IRQ numbers to sub-devices.
*/
- for (i = 0; i < num_intb; i++) {
+ for (i = 0; i < ddata->num_intb_irqs; i++) {
struct resource *res = &regulator_res[i];
- *res = regulator_intb_irqs[i];
+ *res = ddata->intb_irqs[i];
res->start = res->end = irq_create_mapping(intb_domain,
res->start);
}
wdg_irq_no = irq_create_mapping(intb_domain, BD96801_WDT_ERR_STAT);
wdg_irq = DEFINE_RES_IRQ_NAMED(wdg_irq_no, "bd96801-wdg");
- bd96801_cells[WDG_CELL].resources = &wdg_irq;
- bd96801_cells[WDG_CELL].num_resources = 1;
+
+ ddata->cells[WDG_CELL].resources = &wdg_irq;
+ ddata->cells[WDG_CELL].num_resources = 1;
if (!num_errb)
goto skip_errb;
ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, errb_irq, IRQF_ONESHOT,
- 0, &bd96801_irq_chip_errb, &errb_irq_data);
+ 0, ddata->errb_irq_chip, &errb_irq_data);
if (ret)
return dev_err_probe(&i2c->dev, ret,
"Failed to add ERRB IRQ chip\n");
@@ -429,18 +740,17 @@ static int bd96801_i2c_probe(struct i2c_client *i2c)
errb_domain = regmap_irq_get_domain(errb_irq_data);
for (i = 0; i < num_errb; i++) {
- struct resource *res = &regulator_res[num_intb + i];
+ struct resource *res = &regulator_res[ddata->num_intb_irqs + i];
- *res = regulator_errb_irqs[i];
+ *res = ddata->errb_irqs[i];
res->start = res->end = irq_create_mapping(errb_domain, res->start);
}
skip_errb:
- bd96801_cells[REGULATOR_CELL].resources = regulator_res;
- bd96801_cells[REGULATOR_CELL].num_resources = num_regu_irqs;
-
- ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, bd96801_cells,
- ARRAY_SIZE(bd96801_cells), NULL, 0, NULL);
+ ddata->cells[REGULATOR_CELL].resources = regulator_res;
+ ddata->cells[REGULATOR_CELL].num_resources = num_regu_irqs;
+ ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, ddata->cells,
+ ddata->num_cells, NULL, 0, NULL);
if (ret)
dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n");
@@ -448,7 +758,10 @@ skip_errb:
}
static const struct of_device_id bd96801_of_match[] = {
- { .compatible = "rohm,bd96801", },
+ { .compatible = "rohm,bd96801", .data = (void *)ROHM_CHIP_TYPE_BD96801 },
+ { .compatible = "rohm,bd96802", .data = (void *)ROHM_CHIP_TYPE_BD96802 },
+ { .compatible = "rohm,bd96805", .data = (void *)ROHM_CHIP_TYPE_BD96805 },
+ { .compatible = "rohm,bd96806", .data = (void *)ROHM_CHIP_TYPE_BD96806 },
{ }
};
MODULE_DEVICE_TABLE(of, bd96801_of_match);
@@ -476,5 +789,5 @@ static void __exit bd96801_i2c_exit(void)
module_exit(bd96801_i2c_exit);
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
-MODULE_DESCRIPTION("ROHM BD96801 Power Management IC driver");
+MODULE_DESCRIPTION("ROHM BD9680X Power Management IC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c
index 84ebc96f58e4..2204bf1c5a51 100644
--- a/drivers/mfd/rt5033.c
+++ b/drivers/mfd/rt5033.c
@@ -98,7 +98,11 @@ static int rt5033_i2c_probe(struct i2c_client *i2c)
return ret;
}
- device_init_wakeup(rt5033->dev, rt5033->wakeup);
+ if (rt5033->wakeup) {
+ ret = devm_device_init_wakeup(rt5033->dev);
+ if (ret)
+ return dev_err_probe(rt5033->dev, ret, "Failed to init wakeup\n");
+ }
return 0;
}
diff --git a/drivers/mfd/sec-acpm.c b/drivers/mfd/sec-acpm.c
new file mode 100644
index 000000000000..8b31c816d65b
--- /dev/null
+++ b/drivers/mfd/sec-acpm.c
@@ -0,0 +1,442 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2020 Google Inc
+ * Copyright 2025 Linaro Ltd.
+ *
+ * Samsung S2MPG1x ACPM driver
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/firmware/samsung/exynos-acpm-protocol.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/rtc.h>
+#include <linux/mfd/samsung/s2mpg10.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include "sec-core.h"
+
+#define ACPM_ADDR_BITS 8
+#define ACPM_MAX_BULK_DATA 8
+
+struct sec_pmic_acpm_platform_data {
+ int device_type;
+
+ unsigned int acpm_chan_id;
+ u8 speedy_channel;
+
+ const struct regmap_config *regmap_cfg_common;
+ const struct regmap_config *regmap_cfg_pmic;
+ const struct regmap_config *regmap_cfg_rtc;
+ const struct regmap_config *regmap_cfg_meter;
+};
+
+static const struct regmap_range s2mpg10_common_registers[] = {
+ regmap_reg_range(0x00, 0x02), /* CHIP_ID_M, INT, INT_MASK */
+ regmap_reg_range(0x0a, 0x0c), /* Speedy control */
+ regmap_reg_range(0x1a, 0x2a), /* Debug */
+};
+
+static const struct regmap_range s2mpg10_common_ro_registers[] = {
+ regmap_reg_range(0x00, 0x01), /* CHIP_ID_M, INT */
+ regmap_reg_range(0x28, 0x2a), /* Debug */
+};
+
+static const struct regmap_range s2mpg10_common_nonvolatile_registers[] = {
+ regmap_reg_range(0x00, 0x00), /* CHIP_ID_M */
+ regmap_reg_range(0x02, 0x02), /* INT_MASK */
+ regmap_reg_range(0x0a, 0x0c), /* Speedy control */
+};
+
+static const struct regmap_range s2mpg10_common_precious_registers[] = {
+ regmap_reg_range(0x01, 0x01), /* INT */
+};
+
+static const struct regmap_access_table s2mpg10_common_wr_table = {
+ .yes_ranges = s2mpg10_common_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_common_registers),
+ .no_ranges = s2mpg10_common_ro_registers,
+ .n_no_ranges = ARRAY_SIZE(s2mpg10_common_ro_registers),
+};
+
+static const struct regmap_access_table s2mpg10_common_rd_table = {
+ .yes_ranges = s2mpg10_common_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_common_registers),
+};
+
+static const struct regmap_access_table s2mpg10_common_volatile_table = {
+ .no_ranges = s2mpg10_common_nonvolatile_registers,
+ .n_no_ranges = ARRAY_SIZE(s2mpg10_common_nonvolatile_registers),
+};
+
+static const struct regmap_access_table s2mpg10_common_precious_table = {
+ .yes_ranges = s2mpg10_common_precious_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_common_precious_registers),
+};
+
+static const struct regmap_config s2mpg10_regmap_config_common = {
+ .name = "common",
+ .reg_bits = ACPM_ADDR_BITS,
+ .val_bits = 8,
+ .max_register = S2MPG10_COMMON_SPD_DEBUG4,
+ .wr_table = &s2mpg10_common_wr_table,
+ .rd_table = &s2mpg10_common_rd_table,
+ .volatile_table = &s2mpg10_common_volatile_table,
+ .precious_table = &s2mpg10_common_precious_table,
+ .num_reg_defaults_raw = S2MPG10_COMMON_SPD_DEBUG4 + 1,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_range s2mpg10_pmic_registers[] = {
+ regmap_reg_range(0x00, 0xf6), /* All PMIC registers */
+};
+
+static const struct regmap_range s2mpg10_pmic_ro_registers[] = {
+ regmap_reg_range(0x00, 0x05), /* INTx */
+ regmap_reg_range(0x0c, 0x0f), /* STATUSx PWRONSRC OFFSRC */
+ regmap_reg_range(0xc7, 0xc7), /* GPIO input */
+};
+
+static const struct regmap_range s2mpg10_pmic_nonvolatile_registers[] = {
+ regmap_reg_range(0x06, 0x0b), /* INTxM */
+};
+
+static const struct regmap_range s2mpg10_pmic_precious_registers[] = {
+ regmap_reg_range(0x00, 0x05), /* INTx */
+};
+
+static const struct regmap_access_table s2mpg10_pmic_wr_table = {
+ .yes_ranges = s2mpg10_pmic_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_pmic_registers),
+ .no_ranges = s2mpg10_pmic_ro_registers,
+ .n_no_ranges = ARRAY_SIZE(s2mpg10_pmic_ro_registers),
+};
+
+static const struct regmap_access_table s2mpg10_pmic_rd_table = {
+ .yes_ranges = s2mpg10_pmic_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_pmic_registers),
+};
+
+static const struct regmap_access_table s2mpg10_pmic_volatile_table = {
+ .no_ranges = s2mpg10_pmic_nonvolatile_registers,
+ .n_no_ranges = ARRAY_SIZE(s2mpg10_pmic_nonvolatile_registers),
+};
+
+static const struct regmap_access_table s2mpg10_pmic_precious_table = {
+ .yes_ranges = s2mpg10_pmic_precious_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_pmic_precious_registers),
+};
+
+static const struct regmap_config s2mpg10_regmap_config_pmic = {
+ .name = "pmic",
+ .reg_bits = ACPM_ADDR_BITS,
+ .val_bits = 8,
+ .max_register = S2MPG10_PMIC_LDO_SENSE4,
+ .wr_table = &s2mpg10_pmic_wr_table,
+ .rd_table = &s2mpg10_pmic_rd_table,
+ .volatile_table = &s2mpg10_pmic_volatile_table,
+ .precious_table = &s2mpg10_pmic_precious_table,
+ .num_reg_defaults_raw = S2MPG10_PMIC_LDO_SENSE4 + 1,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_range s2mpg10_rtc_registers[] = {
+ regmap_reg_range(0x00, 0x2b), /* All RTC registers */
+};
+
+static const struct regmap_range s2mpg10_rtc_volatile_registers[] = {
+ regmap_reg_range(0x01, 0x01), /* RTC_UPDATE */
+ regmap_reg_range(0x05, 0x0c), /* Time / date */
+};
+
+static const struct regmap_access_table s2mpg10_rtc_rd_table = {
+ .yes_ranges = s2mpg10_rtc_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_rtc_registers),
+};
+
+static const struct regmap_access_table s2mpg10_rtc_volatile_table = {
+ .yes_ranges = s2mpg10_rtc_volatile_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_rtc_volatile_registers),
+};
+
+static const struct regmap_config s2mpg10_regmap_config_rtc = {
+ .name = "rtc",
+ .reg_bits = ACPM_ADDR_BITS,
+ .val_bits = 8,
+ .max_register = S2MPG10_RTC_OSC_CTRL,
+ .rd_table = &s2mpg10_rtc_rd_table,
+ .volatile_table = &s2mpg10_rtc_volatile_table,
+ .num_reg_defaults_raw = S2MPG10_RTC_OSC_CTRL + 1,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_range s2mpg10_meter_registers[] = {
+ regmap_reg_range(0x00, 0x21), /* Meter config */
+ regmap_reg_range(0x40, 0x8a), /* Meter data */
+ regmap_reg_range(0xee, 0xee), /* Offset */
+ regmap_reg_range(0xf1, 0xf1), /* Trim */
+};
+
+static const struct regmap_range s2mpg10_meter_ro_registers[] = {
+ regmap_reg_range(0x40, 0x8a), /* Meter data */
+};
+
+static const struct regmap_access_table s2mpg10_meter_wr_table = {
+ .yes_ranges = s2mpg10_meter_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_meter_registers),
+ .no_ranges = s2mpg10_meter_ro_registers,
+ .n_no_ranges = ARRAY_SIZE(s2mpg10_meter_ro_registers),
+};
+
+static const struct regmap_access_table s2mpg10_meter_rd_table = {
+ .yes_ranges = s2mpg10_meter_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_meter_registers),
+};
+
+static const struct regmap_access_table s2mpg10_meter_volatile_table = {
+ .yes_ranges = s2mpg10_meter_ro_registers,
+ .n_yes_ranges = ARRAY_SIZE(s2mpg10_meter_ro_registers),
+};
+
+static const struct regmap_config s2mpg10_regmap_config_meter = {
+ .name = "meter",
+ .reg_bits = ACPM_ADDR_BITS,
+ .val_bits = 8,
+ .max_register = S2MPG10_METER_BUCK_METER_TRIM3,
+ .wr_table = &s2mpg10_meter_wr_table,
+ .rd_table = &s2mpg10_meter_rd_table,
+ .volatile_table = &s2mpg10_meter_volatile_table,
+ .num_reg_defaults_raw = S2MPG10_METER_BUCK_METER_TRIM3 + 1,
+ .cache_type = REGCACHE_FLAT,
+};
+
+struct sec_pmic_acpm_shared_bus_context {
+ const struct acpm_handle *acpm;
+ unsigned int acpm_chan_id;
+ u8 speedy_channel;
+};
+
+enum sec_pmic_acpm_accesstype {
+ SEC_PMIC_ACPM_ACCESSTYPE_COMMON = 0x00,
+ SEC_PMIC_ACPM_ACCESSTYPE_PMIC = 0x01,
+ SEC_PMIC_ACPM_ACCESSTYPE_RTC = 0x02,
+ SEC_PMIC_ACPM_ACCESSTYPE_METER = 0x0a,
+ SEC_PMIC_ACPM_ACCESSTYPE_WLWP = 0x0b,
+ SEC_PMIC_ACPM_ACCESSTYPE_TRIM = 0x0f,
+};
+
+struct sec_pmic_acpm_bus_context {
+ struct sec_pmic_acpm_shared_bus_context *shared;
+ enum sec_pmic_acpm_accesstype type;
+};
+
+static int sec_pmic_acpm_bus_write(void *context, const void *data,
+ size_t count)
+{
+ struct sec_pmic_acpm_bus_context *ctx = context;
+ const struct acpm_handle *acpm = ctx->shared->acpm;
+ const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops;
+ size_t val_count = count - BITS_TO_BYTES(ACPM_ADDR_BITS);
+ const u8 *d = data;
+ const u8 *vals = &d[BITS_TO_BYTES(ACPM_ADDR_BITS)];
+ u8 reg;
+
+ if (val_count < 1 || val_count > ACPM_MAX_BULK_DATA)
+ return -EINVAL;
+
+ reg = d[0];
+
+ return pmic_ops->bulk_write(acpm, ctx->shared->acpm_chan_id, ctx->type, reg,
+ ctx->shared->speedy_channel, val_count, vals);
+}
+
+static int sec_pmic_acpm_bus_read(void *context, const void *reg_buf, size_t reg_size,
+ void *val_buf, size_t val_size)
+{
+ struct sec_pmic_acpm_bus_context *ctx = context;
+ const struct acpm_handle *acpm = ctx->shared->acpm;
+ const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops;
+ const u8 *r = reg_buf;
+ u8 reg;
+
+ if (reg_size != BITS_TO_BYTES(ACPM_ADDR_BITS) || !val_size ||
+ val_size > ACPM_MAX_BULK_DATA)
+ return -EINVAL;
+
+ reg = r[0];
+
+ return pmic_ops->bulk_read(acpm, ctx->shared->acpm_chan_id, ctx->type, reg,
+ ctx->shared->speedy_channel, val_size, val_buf);
+}
+
+static int sec_pmic_acpm_bus_reg_update_bits(void *context, unsigned int reg, unsigned int mask,
+ unsigned int val)
+{
+ struct sec_pmic_acpm_bus_context *ctx = context;
+ const struct acpm_handle *acpm = ctx->shared->acpm;
+ const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops;
+
+ return pmic_ops->update_reg(acpm, ctx->shared->acpm_chan_id, ctx->type, reg & 0xff,
+ ctx->shared->speedy_channel, val, mask);
+}
+
+static const struct regmap_bus sec_pmic_acpm_regmap_bus = {
+ .write = sec_pmic_acpm_bus_write,
+ .read = sec_pmic_acpm_bus_read,
+ .reg_update_bits = sec_pmic_acpm_bus_reg_update_bits,
+ .max_raw_read = ACPM_MAX_BULK_DATA,
+ .max_raw_write = ACPM_MAX_BULK_DATA,
+};
+
+static struct regmap *sec_pmic_acpm_regmap_init(struct device *dev,
+ struct sec_pmic_acpm_shared_bus_context *shared_ctx,
+ enum sec_pmic_acpm_accesstype type,
+ const struct regmap_config *cfg, bool do_attach)
+{
+ struct sec_pmic_acpm_bus_context *ctx;
+ struct regmap *regmap;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->shared = shared_ctx;
+ ctx->type = type;
+
+ regmap = devm_regmap_init(dev, &sec_pmic_acpm_regmap_bus, ctx, cfg);
+ if (IS_ERR(regmap))
+ return dev_err_cast_probe(dev, regmap, "regmap init (%s) failed\n", cfg->name);
+
+ if (do_attach) {
+ int ret;
+
+ ret = regmap_attach_dev(dev, regmap, cfg);
+ if (ret)
+ return dev_err_ptr_probe(dev, ret, "regmap attach (%s) failed\n",
+ cfg->name);
+ }
+
+ 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;
+ const struct sec_pmic_acpm_platform_data *pdata;
+ struct sec_pmic_acpm_shared_bus_context *shared_ctx;
+ const struct acpm_handle *acpm;
+ struct device *dev = &pdev->dev;
+ int ret, irq;
+
+ pdata = device_get_match_data(dev);
+ if (!pdata)
+ return dev_err_probe(dev, -ENODEV, "unsupported device type\n");
+
+ acpm = devm_acpm_get_by_node(dev, dev->parent->of_node);
+ if (IS_ERR(acpm))
+ return dev_err_probe(dev, PTR_ERR(acpm), "failed to get acpm\n");
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ shared_ctx = devm_kzalloc(dev, sizeof(*shared_ctx), GFP_KERNEL);
+ if (!shared_ctx)
+ return -ENOMEM;
+
+ shared_ctx->acpm = acpm;
+ shared_ctx->acpm_chan_id = pdata->acpm_chan_id;
+ 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);
+ 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))
+ return PTR_ERR(regmap_pmic);
+
+ regmap = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_RTC,
+ pdata->regmap_cfg_rtc, true);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ regmap = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_METER,
+ pdata->regmap_cfg_meter, true);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = sec_pmic_probe(dev, pdata->device_type, irq, regmap_pmic, NULL);
+ if (ret)
+ return ret;
+
+ 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;
+}
+
+static void sec_pmic_acpm_shutdown(struct platform_device *pdev)
+{
+ sec_pmic_shutdown(&pdev->dev);
+}
+
+static const struct sec_pmic_acpm_platform_data s2mpg10_data = {
+ .device_type = S2MPG10,
+ .acpm_chan_id = 2,
+ .speedy_channel = 0,
+ .regmap_cfg_common = &s2mpg10_regmap_config_common,
+ .regmap_cfg_pmic = &s2mpg10_regmap_config_pmic,
+ .regmap_cfg_rtc = &s2mpg10_regmap_config_rtc,
+ .regmap_cfg_meter = &s2mpg10_regmap_config_meter,
+};
+
+static const struct of_device_id sec_pmic_acpm_of_match[] = {
+ { .compatible = "samsung,s2mpg10-pmic", .data = &s2mpg10_data, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sec_pmic_acpm_of_match);
+
+static struct platform_driver sec_pmic_acpm_driver = {
+ .driver = {
+ .name = "sec-pmic-acpm",
+ .pm = pm_sleep_ptr(&sec_pmic_pm_ops),
+ .of_match_table = sec_pmic_acpm_of_match,
+ },
+ .probe = sec_pmic_acpm_probe,
+ .shutdown = sec_pmic_acpm_shutdown,
+};
+module_platform_driver(sec_pmic_acpm_driver);
+
+MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>");
+MODULE_DESCRIPTION("ACPM driver for the Samsung S2MPG1x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sec-common.c b/drivers/mfd/sec-common.c
new file mode 100644
index 000000000000..42d55e70e34c
--- /dev/null
+++ b/drivers/mfd/sec-common.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ * Copyright 2025 Linaro Ltd.
+ *
+ * Samsung SxM core driver
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/irq.h>
+#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps13.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include "sec-core.h"
+
+static const struct mfd_cell s5m8767_devs[] = {
+ MFD_CELL_NAME("s5m8767-pmic"),
+ MFD_CELL_NAME("s5m-rtc"),
+ MFD_CELL_OF("s5m8767-clk", NULL, NULL, 0, 0, "samsung,s5m8767-clk"),
+};
+
+static const struct mfd_cell s2dos05_devs[] = {
+ MFD_CELL_NAME("s2dos05-regulator"),
+};
+
+static const struct mfd_cell s2mpg10_devs[] = {
+ MFD_CELL_NAME("s2mpg10-meter"),
+ MFD_CELL_NAME("s2mpg10-regulator"),
+ MFD_CELL_NAME("s2mpg10-rtc"),
+ MFD_CELL_OF("s2mpg10-clk", NULL, NULL, 0, 0, "samsung,s2mpg10-clk"),
+ MFD_CELL_OF("s2mpg10-gpio", NULL, NULL, 0, 0, "samsung,s2mpg10-gpio"),
+};
+
+static const struct mfd_cell s2mps11_devs[] = {
+ MFD_CELL_NAME("s2mps11-regulator"),
+ MFD_CELL_NAME("s2mps14-rtc"),
+ MFD_CELL_OF("s2mps11-clk", NULL, NULL, 0, 0, "samsung,s2mps11-clk"),
+};
+
+static const struct mfd_cell s2mps13_devs[] = {
+ MFD_CELL_NAME("s2mps13-regulator"),
+ MFD_CELL_NAME("s2mps13-rtc"),
+ MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"),
+};
+
+static const struct mfd_cell s2mps14_devs[] = {
+ MFD_CELL_NAME("s2mps14-regulator"),
+ MFD_CELL_NAME("s2mps14-rtc"),
+ MFD_CELL_OF("s2mps14-clk", NULL, NULL, 0, 0, "samsung,s2mps14-clk"),
+};
+
+static const struct mfd_cell s2mps15_devs[] = {
+ MFD_CELL_NAME("s2mps15-regulator"),
+ MFD_CELL_NAME("s2mps15-rtc"),
+ MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"),
+};
+
+static const struct mfd_cell s2mpa01_devs[] = {
+ MFD_CELL_NAME("s2mpa01-pmic"),
+ MFD_CELL_NAME("s2mps14-rtc"),
+};
+
+static const struct mfd_cell s2mpu02_devs[] = {
+ MFD_CELL_NAME("s2mpu02-regulator"),
+};
+
+static const struct mfd_cell s2mpu05_devs[] = {
+ MFD_CELL_NAME("s2mpu05-regulator"),
+ MFD_CELL_NAME("s2mps15-rtc"),
+};
+
+static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic)
+{
+ unsigned int val;
+
+ /* For s2mpg1x, the revision is in a different regmap */
+ if (sec_pmic->device_type == S2MPG10)
+ return;
+
+ /* For each device type, the REG_ID is always the first register */
+ if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val))
+ dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val);
+}
+
+static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic)
+{
+ int err;
+
+ if (sec_pmic->device_type != S2MPS13X)
+ return;
+
+ if (sec_pmic->pdata->disable_wrstbi) {
+ /*
+ * If WRSTBI pin is pulled down this feature must be disabled
+ * because each Suspend to RAM will trigger buck voltage reset
+ * to default values.
+ */
+ err = regmap_update_bits(sec_pmic->regmap_pmic,
+ S2MPS13_REG_WRSTBI,
+ S2MPS13_REG_WRSTBI_MASK, 0x0);
+ if (err)
+ dev_warn(sec_pmic->dev,
+ "Cannot initialize WRSTBI config: %d\n",
+ err);
+ }
+}
+
+/*
+ * Only the common platform data elements for s5m8767 are parsed here from the
+ * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
+ * others have to parse their own platform data elements from device tree.
+ *
+ * The s5m8767 platform data structure is instantiated here and the drivers for
+ * the sub-modules need not instantiate another instance while parsing their
+ * platform data.
+ */
+static struct sec_platform_data *
+sec_pmic_parse_dt_pdata(struct device *dev)
+{
+ struct sec_platform_data *pd;
+
+ pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+
+ pd->manual_poweroff = of_property_read_bool(dev->of_node,
+ "samsung,s2mps11-acokb-ground");
+ pd->disable_wrstbi = of_property_read_bool(dev->of_node,
+ "samsung,s2mps11-wrstbi-ground");
+ return pd;
+}
+
+int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq,
+ struct regmap *regmap, struct i2c_client *client)
+{
+ struct sec_platform_data *pdata;
+ const struct mfd_cell *sec_devs;
+ struct sec_pmic_dev *sec_pmic;
+ int ret, num_sec_devs;
+
+ sec_pmic = devm_kzalloc(dev, sizeof(*sec_pmic), GFP_KERNEL);
+ if (!sec_pmic)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, sec_pmic);
+ sec_pmic->dev = dev;
+ sec_pmic->device_type = device_type;
+ sec_pmic->i2c = client;
+ sec_pmic->irq = irq;
+ sec_pmic->regmap_pmic = regmap;
+
+ pdata = sec_pmic_parse_dt_pdata(sec_pmic->dev);
+ if (IS_ERR(pdata)) {
+ ret = PTR_ERR(pdata);
+ return ret;
+ }
+
+ sec_pmic->pdata = pdata;
+
+ ret = sec_irq_init(sec_pmic);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_active(sec_pmic->dev);
+
+ switch (sec_pmic->device_type) {
+ case S5M8767X:
+ sec_devs = s5m8767_devs;
+ num_sec_devs = ARRAY_SIZE(s5m8767_devs);
+ break;
+ case S2DOS05:
+ sec_devs = s2dos05_devs;
+ num_sec_devs = ARRAY_SIZE(s2dos05_devs);
+ break;
+ case S2MPA01:
+ sec_devs = s2mpa01_devs;
+ num_sec_devs = ARRAY_SIZE(s2mpa01_devs);
+ break;
+ case S2MPG10:
+ sec_devs = s2mpg10_devs;
+ num_sec_devs = ARRAY_SIZE(s2mpg10_devs);
+ break;
+ case S2MPS11X:
+ sec_devs = s2mps11_devs;
+ num_sec_devs = ARRAY_SIZE(s2mps11_devs);
+ break;
+ case S2MPS13X:
+ sec_devs = s2mps13_devs;
+ num_sec_devs = ARRAY_SIZE(s2mps13_devs);
+ break;
+ case S2MPS14X:
+ sec_devs = s2mps14_devs;
+ num_sec_devs = ARRAY_SIZE(s2mps14_devs);
+ break;
+ case S2MPS15X:
+ sec_devs = s2mps15_devs;
+ num_sec_devs = ARRAY_SIZE(s2mps15_devs);
+ break;
+ case S2MPU02:
+ sec_devs = s2mpu02_devs;
+ num_sec_devs = ARRAY_SIZE(s2mpu02_devs);
+ break;
+ case S2MPU05:
+ sec_devs = s2mpu05_devs;
+ num_sec_devs = ARRAY_SIZE(s2mpu05_devs);
+ break;
+ default:
+ return dev_err_probe(sec_pmic->dev, -EINVAL,
+ "Unsupported device type %d\n",
+ sec_pmic->device_type);
+ }
+ ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs,
+ NULL, 0, NULL);
+ if (ret)
+ return ret;
+
+ sec_pmic_configure(sec_pmic);
+ sec_pmic_dump_rev(sec_pmic);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sec_pmic_probe);
+
+void sec_pmic_shutdown(struct device *dev)
+{
+ struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
+ unsigned int reg, mask;
+
+ if (!sec_pmic->pdata->manual_poweroff)
+ return;
+
+ switch (sec_pmic->device_type) {
+ case S2MPS11X:
+ reg = S2MPS11_REG_CTRL1;
+ mask = S2MPS11_CTRL1_PWRHOLD_MASK;
+ break;
+ default:
+ /*
+ * Currently only one board with S2MPS11 needs this, so just
+ * ignore the rest.
+ */
+ dev_warn(sec_pmic->dev,
+ "Unsupported device %d for manual power off\n",
+ sec_pmic->device_type);
+ return;
+ }
+
+ regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0);
+}
+EXPORT_SYMBOL_GPL(sec_pmic_shutdown);
+
+static int sec_pmic_suspend(struct device *dev)
+{
+ struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(sec_pmic->irq);
+ /*
+ * PMIC IRQ must be disabled during suspend for RTC alarm
+ * to work properly.
+ * When device is woken up from suspend, an
+ * interrupt occurs before resuming I2C bus controller.
+ * The interrupt is handled by regmap_irq_thread which tries
+ * to read RTC registers. This read fails (I2C is still
+ * suspended) and RTC Alarm interrupt is disabled.
+ */
+ disable_irq(sec_pmic->irq);
+
+ return 0;
+}
+
+static int sec_pmic_resume(struct device *dev)
+{
+ struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(sec_pmic->irq);
+ enable_irq(sec_pmic->irq);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
+EXPORT_SYMBOL_GPL(sec_pmic_pm_ops);
+
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>");
+MODULE_DESCRIPTION("Core driver for the Samsung S5M");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
deleted file mode 100644
index 3e9b65c988a7..000000000000
--- a/drivers/mfd/sec-core.c
+++ /dev/null
@@ -1,481 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-//
-// Copyright (c) 2012 Samsung Electronics Co., Ltd
-// http://www.samsung.com
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/of.h>
-#include <linux/interrupt.h>
-#include <linux/pm_runtime.h>
-#include <linux/mutex.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/samsung/core.h>
-#include <linux/mfd/samsung/irq.h>
-#include <linux/mfd/samsung/s2mpa01.h>
-#include <linux/mfd/samsung/s2mps11.h>
-#include <linux/mfd/samsung/s2mps13.h>
-#include <linux/mfd/samsung/s2mps14.h>
-#include <linux/mfd/samsung/s2mps15.h>
-#include <linux/mfd/samsung/s2mpu02.h>
-#include <linux/mfd/samsung/s5m8767.h>
-#include <linux/regmap.h>
-
-static const struct mfd_cell s5m8767_devs[] = {
- { .name = "s5m8767-pmic", },
- { .name = "s5m-rtc", },
- {
- .name = "s5m8767-clk",
- .of_compatible = "samsung,s5m8767-clk",
- },
-};
-
-static const struct mfd_cell s2dos05_devs[] = {
- { .name = "s2dos05-regulator", },
-};
-
-static const struct mfd_cell s2mps11_devs[] = {
- { .name = "s2mps11-regulator", },
- { .name = "s2mps14-rtc", },
- {
- .name = "s2mps11-clk",
- .of_compatible = "samsung,s2mps11-clk",
- },
-};
-
-static const struct mfd_cell s2mps13_devs[] = {
- { .name = "s2mps13-regulator", },
- { .name = "s2mps13-rtc", },
- {
- .name = "s2mps13-clk",
- .of_compatible = "samsung,s2mps13-clk",
- },
-};
-
-static const struct mfd_cell s2mps14_devs[] = {
- { .name = "s2mps14-regulator", },
- { .name = "s2mps14-rtc", },
- {
- .name = "s2mps14-clk",
- .of_compatible = "samsung,s2mps14-clk",
- },
-};
-
-static const struct mfd_cell s2mps15_devs[] = {
- { .name = "s2mps15-regulator", },
- { .name = "s2mps15-rtc", },
- {
- .name = "s2mps13-clk",
- .of_compatible = "samsung,s2mps13-clk",
- },
-};
-
-static const struct mfd_cell s2mpa01_devs[] = {
- { .name = "s2mpa01-pmic", },
- { .name = "s2mps14-rtc", },
-};
-
-static const struct mfd_cell s2mpu02_devs[] = {
- { .name = "s2mpu02-regulator", },
-};
-
-static const struct mfd_cell s2mpu05_devs[] = {
- { .name = "s2mpu05-regulator", },
- { .name = "s2mps15-rtc", },
-};
-
-static const struct of_device_id sec_dt_match[] = {
- {
- .compatible = "samsung,s5m8767-pmic",
- .data = (void *)S5M8767X,
- }, {
- .compatible = "samsung,s2dos05",
- .data = (void *)S2DOS05,
- }, {
- .compatible = "samsung,s2mps11-pmic",
- .data = (void *)S2MPS11X,
- }, {
- .compatible = "samsung,s2mps13-pmic",
- .data = (void *)S2MPS13X,
- }, {
- .compatible = "samsung,s2mps14-pmic",
- .data = (void *)S2MPS14X,
- }, {
- .compatible = "samsung,s2mps15-pmic",
- .data = (void *)S2MPS15X,
- }, {
- .compatible = "samsung,s2mpa01-pmic",
- .data = (void *)S2MPA01,
- }, {
- .compatible = "samsung,s2mpu02-pmic",
- .data = (void *)S2MPU02,
- }, {
- .compatible = "samsung,s2mpu05-pmic",
- .data = (void *)S2MPU05,
- }, {
- /* Sentinel */
- },
-};
-MODULE_DEVICE_TABLE(of, sec_dt_match);
-
-static bool s2mpa01_volatile(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case S2MPA01_REG_INT1M:
- case S2MPA01_REG_INT2M:
- case S2MPA01_REG_INT3M:
- return false;
- default:
- return true;
- }
-}
-
-static bool s2mps11_volatile(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case S2MPS11_REG_INT1M:
- case S2MPS11_REG_INT2M:
- case S2MPS11_REG_INT3M:
- return false;
- default:
- return true;
- }
-}
-
-static bool s2mpu02_volatile(struct device *dev, unsigned int reg)
-{
- switch (reg) {
- case S2MPU02_REG_INT1M:
- case S2MPU02_REG_INT2M:
- case S2MPU02_REG_INT3M:
- return false;
- default:
- return true;
- }
-}
-
-static const struct regmap_config sec_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-};
-
-static const struct regmap_config s2mpa01_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = S2MPA01_REG_LDO_OVCB4,
- .volatile_reg = s2mpa01_volatile,
- .cache_type = REGCACHE_FLAT,
-};
-
-static const struct regmap_config s2mps11_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = S2MPS11_REG_L38CTRL,
- .volatile_reg = s2mps11_volatile,
- .cache_type = REGCACHE_FLAT,
-};
-
-static const struct regmap_config s2mps13_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = S2MPS13_REG_LDODSCH5,
- .volatile_reg = s2mps11_volatile,
- .cache_type = REGCACHE_FLAT,
-};
-
-static const struct regmap_config s2mps14_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = S2MPS14_REG_LDODSCH3,
- .volatile_reg = s2mps11_volatile,
- .cache_type = REGCACHE_FLAT,
-};
-
-static const struct regmap_config s2mps15_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = S2MPS15_REG_LDODSCH4,
- .volatile_reg = s2mps11_volatile,
- .cache_type = REGCACHE_FLAT,
-};
-
-static const struct regmap_config s2mpu02_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = S2MPU02_REG_DVSDATA,
- .volatile_reg = s2mpu02_volatile,
- .cache_type = REGCACHE_FLAT,
-};
-
-static const struct regmap_config s5m8767_regmap_config = {
- .reg_bits = 8,
- .val_bits = 8,
-
- .max_register = S5M8767_REG_LDO28CTRL,
- .volatile_reg = s2mps11_volatile,
- .cache_type = REGCACHE_FLAT,
-};
-
-static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic)
-{
- unsigned int val;
-
- /* For each device type, the REG_ID is always the first register */
- if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val))
- dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val);
-}
-
-static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic)
-{
- int err;
-
- if (sec_pmic->device_type != S2MPS13X)
- return;
-
- if (sec_pmic->pdata->disable_wrstbi) {
- /*
- * If WRSTBI pin is pulled down this feature must be disabled
- * because each Suspend to RAM will trigger buck voltage reset
- * to default values.
- */
- err = regmap_update_bits(sec_pmic->regmap_pmic,
- S2MPS13_REG_WRSTBI,
- S2MPS13_REG_WRSTBI_MASK, 0x0);
- if (err)
- dev_warn(sec_pmic->dev,
- "Cannot initialize WRSTBI config: %d\n",
- err);
- }
-}
-
-/*
- * Only the common platform data elements for s5m8767 are parsed here from the
- * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and
- * others have to parse their own platform data elements from device tree.
- *
- * The s5m8767 platform data structure is instantiated here and the drivers for
- * the sub-modules need not instantiate another instance while parsing their
- * platform data.
- */
-static struct sec_platform_data *
-sec_pmic_i2c_parse_dt_pdata(struct device *dev)
-{
- struct sec_platform_data *pd;
-
- pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return ERR_PTR(-ENOMEM);
-
- pd->manual_poweroff = of_property_read_bool(dev->of_node,
- "samsung,s2mps11-acokb-ground");
- pd->disable_wrstbi = of_property_read_bool(dev->of_node,
- "samsung,s2mps11-wrstbi-ground");
- return pd;
-}
-
-static int sec_pmic_probe(struct i2c_client *i2c)
-{
- const struct regmap_config *regmap;
- struct sec_platform_data *pdata;
- const struct mfd_cell *sec_devs;
- struct sec_pmic_dev *sec_pmic;
- int ret, num_sec_devs;
-
- sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev),
- GFP_KERNEL);
- if (sec_pmic == NULL)
- return -ENOMEM;
-
- i2c_set_clientdata(i2c, sec_pmic);
- sec_pmic->dev = &i2c->dev;
- sec_pmic->i2c = i2c;
- sec_pmic->irq = i2c->irq;
-
- pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev);
- if (IS_ERR(pdata)) {
- ret = PTR_ERR(pdata);
- return ret;
- }
-
- sec_pmic->device_type = (unsigned long)of_device_get_match_data(sec_pmic->dev);
- sec_pmic->pdata = pdata;
-
- switch (sec_pmic->device_type) {
- case S2MPA01:
- regmap = &s2mpa01_regmap_config;
- break;
- case S2MPS11X:
- regmap = &s2mps11_regmap_config;
- break;
- case S2MPS13X:
- regmap = &s2mps13_regmap_config;
- break;
- case S2MPS14X:
- regmap = &s2mps14_regmap_config;
- break;
- case S2MPS15X:
- regmap = &s2mps15_regmap_config;
- break;
- case S5M8767X:
- regmap = &s5m8767_regmap_config;
- break;
- case S2MPU02:
- regmap = &s2mpu02_regmap_config;
- break;
- default:
- regmap = &sec_regmap_config;
- break;
- }
-
- sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap);
- if (IS_ERR(sec_pmic->regmap_pmic)) {
- ret = PTR_ERR(sec_pmic->regmap_pmic);
- dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
- ret);
- return ret;
- }
-
- sec_irq_init(sec_pmic);
-
- pm_runtime_set_active(sec_pmic->dev);
-
- switch (sec_pmic->device_type) {
- case S5M8767X:
- sec_devs = s5m8767_devs;
- num_sec_devs = ARRAY_SIZE(s5m8767_devs);
- break;
- case S2DOS05:
- sec_devs = s2dos05_devs;
- num_sec_devs = ARRAY_SIZE(s2dos05_devs);
- break;
- case S2MPA01:
- sec_devs = s2mpa01_devs;
- num_sec_devs = ARRAY_SIZE(s2mpa01_devs);
- break;
- case S2MPS11X:
- sec_devs = s2mps11_devs;
- num_sec_devs = ARRAY_SIZE(s2mps11_devs);
- break;
- case S2MPS13X:
- sec_devs = s2mps13_devs;
- num_sec_devs = ARRAY_SIZE(s2mps13_devs);
- break;
- case S2MPS14X:
- sec_devs = s2mps14_devs;
- num_sec_devs = ARRAY_SIZE(s2mps14_devs);
- break;
- case S2MPS15X:
- sec_devs = s2mps15_devs;
- num_sec_devs = ARRAY_SIZE(s2mps15_devs);
- break;
- case S2MPU02:
- sec_devs = s2mpu02_devs;
- num_sec_devs = ARRAY_SIZE(s2mpu02_devs);
- break;
- case S2MPU05:
- sec_devs = s2mpu05_devs;
- num_sec_devs = ARRAY_SIZE(s2mpu05_devs);
- break;
- default:
- dev_err(&i2c->dev, "Unsupported device type (%lu)\n",
- sec_pmic->device_type);
- return -ENODEV;
- }
- ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs,
- NULL, 0, NULL);
- if (ret)
- return ret;
-
- sec_pmic_configure(sec_pmic);
- sec_pmic_dump_rev(sec_pmic);
-
- return ret;
-}
-
-static void sec_pmic_shutdown(struct i2c_client *i2c)
-{
- struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
- unsigned int reg, mask;
-
- if (!sec_pmic->pdata->manual_poweroff)
- return;
-
- switch (sec_pmic->device_type) {
- case S2MPS11X:
- reg = S2MPS11_REG_CTRL1;
- mask = S2MPS11_CTRL1_PWRHOLD_MASK;
- break;
- default:
- /*
- * Currently only one board with S2MPS11 needs this, so just
- * ignore the rest.
- */
- dev_warn(sec_pmic->dev,
- "Unsupported device %lu for manual power off\n",
- sec_pmic->device_type);
- return;
- }
-
- regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0);
-}
-
-static int sec_pmic_suspend(struct device *dev)
-{
- struct i2c_client *i2c = to_i2c_client(dev);
- struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
-
- if (device_may_wakeup(dev))
- enable_irq_wake(sec_pmic->irq);
- /*
- * PMIC IRQ must be disabled during suspend for RTC alarm
- * to work properly.
- * When device is woken up from suspend, an
- * interrupt occurs before resuming I2C bus controller.
- * The interrupt is handled by regmap_irq_thread which tries
- * to read RTC registers. This read fails (I2C is still
- * suspended) and RTC Alarm interrupt is disabled.
- */
- disable_irq(sec_pmic->irq);
-
- return 0;
-}
-
-static int sec_pmic_resume(struct device *dev)
-{
- struct i2c_client *i2c = to_i2c_client(dev);
- struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
-
- if (device_may_wakeup(dev))
- disable_irq_wake(sec_pmic->irq);
- enable_irq(sec_pmic->irq);
-
- return 0;
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops,
- sec_pmic_suspend, sec_pmic_resume);
-
-static struct i2c_driver sec_pmic_driver = {
- .driver = {
- .name = "sec_pmic",
- .pm = pm_sleep_ptr(&sec_pmic_pm_ops),
- .of_match_table = sec_dt_match,
- },
- .probe = sec_pmic_probe,
- .shutdown = sec_pmic_shutdown,
-};
-module_i2c_driver(sec_pmic_driver);
-
-MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_DESCRIPTION("Core support for the S5M MFD");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sec-core.h b/drivers/mfd/sec-core.h
new file mode 100644
index 000000000000..92c7558ab8b0
--- /dev/null
+++ b/drivers/mfd/sec-core.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ * Copyright 2025 Linaro Ltd.
+ *
+ * Samsung SxM core driver internal data
+ */
+
+#ifndef __SEC_CORE_INT_H
+#define __SEC_CORE_INT_H
+
+struct i2c_client;
+
+extern const struct dev_pm_ops sec_pmic_pm_ops;
+
+int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq,
+ struct regmap *regmap, struct i2c_client *client);
+void sec_pmic_shutdown(struct device *dev);
+
+int sec_irq_init(struct sec_pmic_dev *sec_pmic);
+
+#endif /* __SEC_CORE_INT_H */
diff --git a/drivers/mfd/sec-i2c.c b/drivers/mfd/sec-i2c.c
new file mode 100644
index 000000000000..3132b849b4bc
--- /dev/null
+++ b/drivers/mfd/sec-i2c.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2012 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ * Copyright 2025 Linaro Ltd.
+ *
+ * Samsung SxM I2C driver
+ */
+
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/mfd/samsung/s2mpa01.h>
+#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps13.h>
+#include <linux/mfd/samsung/s2mps14.h>
+#include <linux/mfd/samsung/s2mps15.h>
+#include <linux/mfd/samsung/s2mpu02.h>
+#include <linux/mfd/samsung/s5m8767.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include "sec-core.h"
+
+struct sec_pmic_i2c_platform_data {
+ const struct regmap_config *regmap_cfg;
+ int device_type;
+};
+
+static bool s2mpa01_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case S2MPA01_REG_INT1M:
+ case S2MPA01_REG_INT2M:
+ case S2MPA01_REG_INT3M:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static bool s2mps11_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case S2MPS11_REG_INT1M:
+ case S2MPS11_REG_INT2M:
+ case S2MPS11_REG_INT3M:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static bool s2mpu02_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case S2MPU02_REG_INT1M:
+ case S2MPU02_REG_INT2M:
+ case S2MPU02_REG_INT3M:
+ return false;
+ default:
+ return true;
+ }
+}
+
+static const struct regmap_config s2dos05_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct regmap_config s2mpa01_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPA01_REG_LDO_OVCB4,
+ .volatile_reg = s2mpa01_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config s2mps11_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS11_REG_L38CTRL,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config s2mps13_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS13_REG_LDODSCH5,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config s2mps14_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS14_REG_LDODSCH3,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config s2mps15_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS15_REG_LDODSCH4,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config s2mpu02_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPU02_REG_DVSDATA,
+ .volatile_reg = s2mpu02_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static const struct regmap_config s2mpu05_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static const struct regmap_config s5m8767_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S5M8767_REG_LDO28CTRL,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
+static int sec_pmic_i2c_probe(struct i2c_client *client)
+{
+ const struct sec_pmic_i2c_platform_data *pdata;
+ struct regmap *regmap_pmic;
+
+ pdata = device_get_match_data(&client->dev);
+ if (!pdata)
+ return dev_err_probe(&client->dev, -ENODEV,
+ "Unsupported device type\n");
+
+ regmap_pmic = devm_regmap_init_i2c(client, pdata->regmap_cfg);
+ if (IS_ERR(regmap_pmic))
+ return dev_err_probe(&client->dev, PTR_ERR(regmap_pmic),
+ "regmap init failed\n");
+
+ return sec_pmic_probe(&client->dev, pdata->device_type, client->irq,
+ regmap_pmic, client);
+}
+
+static void sec_pmic_i2c_shutdown(struct i2c_client *i2c)
+{
+ sec_pmic_shutdown(&i2c->dev);
+}
+
+static const struct sec_pmic_i2c_platform_data s2dos05_data = {
+ .regmap_cfg = &s2dos05_regmap_config,
+ .device_type = S2DOS05
+};
+
+static const struct sec_pmic_i2c_platform_data s2mpa01_data = {
+ .regmap_cfg = &s2mpa01_regmap_config,
+ .device_type = S2MPA01,
+};
+
+static const struct sec_pmic_i2c_platform_data s2mps11_data = {
+ .regmap_cfg = &s2mps11_regmap_config,
+ .device_type = S2MPS11X,
+};
+
+static const struct sec_pmic_i2c_platform_data s2mps13_data = {
+ .regmap_cfg = &s2mps13_regmap_config,
+ .device_type = S2MPS13X,
+};
+
+static const struct sec_pmic_i2c_platform_data s2mps14_data = {
+ .regmap_cfg = &s2mps14_regmap_config,
+ .device_type = S2MPS14X,
+};
+
+static const struct sec_pmic_i2c_platform_data s2mps15_data = {
+ .regmap_cfg = &s2mps15_regmap_config,
+ .device_type = S2MPS15X,
+};
+
+static const struct sec_pmic_i2c_platform_data s2mpu02_data = {
+ .regmap_cfg = &s2mpu02_regmap_config,
+ .device_type = S2MPU02,
+};
+
+static const struct sec_pmic_i2c_platform_data s2mpu05_data = {
+ .regmap_cfg = &s2mpu05_regmap_config,
+ .device_type = S2MPU05,
+};
+
+static const struct sec_pmic_i2c_platform_data s5m8767_data = {
+ .regmap_cfg = &s5m8767_regmap_config,
+ .device_type = S5M8767X,
+};
+
+static const struct of_device_id sec_pmic_i2c_of_match[] = {
+ { .compatible = "samsung,s2dos05", .data = &s2dos05_data, },
+ { .compatible = "samsung,s2mpa01-pmic", .data = &s2mpa01_data, },
+ { .compatible = "samsung,s2mps11-pmic", .data = &s2mps11_data, },
+ { .compatible = "samsung,s2mps13-pmic", .data = &s2mps13_data, },
+ { .compatible = "samsung,s2mps14-pmic", .data = &s2mps14_data, },
+ { .compatible = "samsung,s2mps15-pmic", .data = &s2mps15_data, },
+ { .compatible = "samsung,s2mpu02-pmic", .data = &s2mpu02_data, },
+ { .compatible = "samsung,s2mpu05-pmic", .data = &s2mpu05_data, },
+ { .compatible = "samsung,s5m8767-pmic", .data = &s5m8767_data, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sec_pmic_i2c_of_match);
+
+static struct i2c_driver sec_pmic_i2c_driver = {
+ .driver = {
+ .name = "sec-pmic-i2c",
+ .pm = pm_sleep_ptr(&sec_pmic_pm_ops),
+ .of_match_table = sec_pmic_i2c_of_match,
+ },
+ .probe = sec_pmic_i2c_probe,
+ .shutdown = sec_pmic_i2c_shutdown,
+};
+module_i2c_driver(sec_pmic_i2c_driver);
+
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>");
+MODULE_DESCRIPTION("I2C driver for the Samsung S5M");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index 047fc065fcf1..c5c80b1ba104 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -3,227 +3,139 @@
// Copyright (c) 2011-2014 Samsung Electronics Co., Ltd
// http://www.samsung.com
-#include <linux/device.h>
+#include <linux/array_size.h>
+#include <linux/build_bug.h>
+#include <linux/dev_printk.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/regmap.h>
-
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/irq.h>
+#include <linux/mfd/samsung/s2mpg10.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s2mpu02.h>
#include <linux/mfd/samsung/s2mpu05.h>
#include <linux/mfd/samsung/s5m8767.h>
+#include <linux/regmap.h>
+#include "sec-core.h"
+
+static const struct regmap_irq s2mpg10_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),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_JIGONBR, 0, S2MPG10_IRQ_JIGONBR_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_ACOKBF, 0, S2MPG10_IRQ_ACOKBF_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_ACOKBR, 0, S2MPG10_IRQ_ACOKBR_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWRON1S, 0, S2MPG10_IRQ_PWRON1S_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_MRB, 0, S2MPG10_IRQ_MRB_MASK),
+
+ REGMAP_IRQ_REG(S2MPG10_IRQ_RTC60S, 1, S2MPG10_IRQ_RTC60S_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_RTCA1, 1, S2MPG10_IRQ_RTCA1_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_RTCA0, 1, S2MPG10_IRQ_RTCA0_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_RTC1S, 1, S2MPG10_IRQ_RTC1S_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_WTSR_COLDRST, 1, S2MPG10_IRQ_WTSR_COLDRST_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_WTSR, 1, S2MPG10_IRQ_WTSR_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_WRST, 1, S2MPG10_IRQ_WRST_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_SMPL, 1, S2MPG10_IRQ_SMPL_MASK),
+
+ REGMAP_IRQ_REG(S2MPG10_IRQ_120C, 2, S2MPG10_IRQ_INT120C_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_140C, 2, S2MPG10_IRQ_INT140C_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_TSD, 2, S2MPG10_IRQ_TSD_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PIF_TIMEOUT1, 2, S2MPG10_IRQ_PIF_TIMEOUT1_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PIF_TIMEOUT2, 2, S2MPG10_IRQ_PIF_TIMEOUT2_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_SPD_PARITY_ERR, 2, S2MPG10_IRQ_SPD_PARITY_ERR_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_SPD_ABNORMAL_STOP, 2, S2MPG10_IRQ_SPD_ABNORMAL_STOP_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PMETER_OVERF, 2, S2MPG10_IRQ_PMETER_OVERF_MASK),
+
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B1M, 3, S2MPG10_IRQ_OCP_B1M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B2M, 3, S2MPG10_IRQ_OCP_B2M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B3M, 3, S2MPG10_IRQ_OCP_B3M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B4M, 3, S2MPG10_IRQ_OCP_B4M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B5M, 3, S2MPG10_IRQ_OCP_B5M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B6M, 3, S2MPG10_IRQ_OCP_B6M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B7M, 3, S2MPG10_IRQ_OCP_B7M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B8M, 3, S2MPG10_IRQ_OCP_B8M_MASK),
+
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B9M, 4, S2MPG10_IRQ_OCP_B9M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B10M, 4, S2MPG10_IRQ_OCP_B10M_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_WLWP_ACC, 4, S2MPG10_IRQ_WLWP_ACC_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_SMPL_TIMEOUT, 4, S2MPG10_IRQ_SMPL_TIMEOUT_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_WTSR_TIMEOUT, 4, S2MPG10_IRQ_WTSR_TIMEOUT_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_SPD_SRP_PKT_RST, 4, S2MPG10_IRQ_SPD_SRP_PKT_RST_MASK),
+
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH0, 5, S2MPG10_IRQ_PWR_WARN_CH0_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH1, 5, S2MPG10_IRQ_PWR_WARN_CH1_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH2, 5, S2MPG10_IRQ_PWR_WARN_CH2_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH3, 5, S2MPG10_IRQ_PWR_WARN_CH3_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH4, 5, S2MPG10_IRQ_PWR_WARN_CH4_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH5, 5, S2MPG10_IRQ_PWR_WARN_CH5_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH6, 5, S2MPG10_IRQ_PWR_WARN_CH6_MASK),
+ REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH7, 5, S2MPG10_IRQ_PWR_WARN_CH7_MASK),
+};
static const struct regmap_irq s2mps11_irqs[] = {
- [S2MPS11_IRQ_PWRONF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRONF_MASK,
- },
- [S2MPS11_IRQ_PWRONR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRONR_MASK,
- },
- [S2MPS11_IRQ_JIGONBF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_JIGONBF_MASK,
- },
- [S2MPS11_IRQ_JIGONBR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_JIGONBR_MASK,
- },
- [S2MPS11_IRQ_ACOKBF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_ACOKBF_MASK,
- },
- [S2MPS11_IRQ_ACOKBR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_ACOKBR_MASK,
- },
- [S2MPS11_IRQ_PWRON1S] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRON1S_MASK,
- },
- [S2MPS11_IRQ_MRB] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_MRB_MASK,
- },
- [S2MPS11_IRQ_RTC60S] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTC60S_MASK,
- },
- [S2MPS11_IRQ_RTCA1] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA1_MASK,
- },
- [S2MPS11_IRQ_RTCA0] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA0_MASK,
- },
- [S2MPS11_IRQ_SMPL] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_SMPL_MASK,
- },
- [S2MPS11_IRQ_RTC1S] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTC1S_MASK,
- },
- [S2MPS11_IRQ_WTSR] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_WTSR_MASK,
- },
- [S2MPS11_IRQ_INT120C] = {
- .reg_offset = 2,
- .mask = S2MPS11_IRQ_INT120C_MASK,
- },
- [S2MPS11_IRQ_INT140C] = {
- .reg_offset = 2,
- .mask = S2MPS11_IRQ_INT140C_MASK,
- },
+ REGMAP_IRQ_REG(S2MPS11_IRQ_PWRONF, 0, S2MPS11_IRQ_PWRONF_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_PWRONR, 0, S2MPS11_IRQ_PWRONR_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_JIGONBF, 0, S2MPS11_IRQ_JIGONBF_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_JIGONBR, 0, S2MPS11_IRQ_JIGONBR_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_ACOKBF, 0, S2MPS11_IRQ_ACOKBF_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_ACOKBR, 0, S2MPS11_IRQ_ACOKBR_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_PWRON1S, 0, S2MPS11_IRQ_PWRON1S_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_MRB, 0, S2MPS11_IRQ_MRB_MASK),
+
+ REGMAP_IRQ_REG(S2MPS11_IRQ_RTC60S, 1, S2MPS11_IRQ_RTC60S_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_RTCA1, 1, S2MPS11_IRQ_RTCA1_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_RTCA0, 1, S2MPS11_IRQ_RTCA0_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_SMPL, 1, S2MPS11_IRQ_SMPL_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_RTC1S, 1, S2MPS11_IRQ_RTC1S_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_WTSR, 1, S2MPS11_IRQ_WTSR_MASK),
+
+ REGMAP_IRQ_REG(S2MPS11_IRQ_INT120C, 2, S2MPS11_IRQ_INT120C_MASK),
+ REGMAP_IRQ_REG(S2MPS11_IRQ_INT140C, 2, S2MPS11_IRQ_INT140C_MASK),
};
static const struct regmap_irq s2mps14_irqs[] = {
- [S2MPS14_IRQ_PWRONF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRONF_MASK,
- },
- [S2MPS14_IRQ_PWRONR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRONR_MASK,
- },
- [S2MPS14_IRQ_JIGONBF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_JIGONBF_MASK,
- },
- [S2MPS14_IRQ_JIGONBR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_JIGONBR_MASK,
- },
- [S2MPS14_IRQ_ACOKBF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_ACOKBF_MASK,
- },
- [S2MPS14_IRQ_ACOKBR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_ACOKBR_MASK,
- },
- [S2MPS14_IRQ_PWRON1S] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRON1S_MASK,
- },
- [S2MPS14_IRQ_MRB] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_MRB_MASK,
- },
- [S2MPS14_IRQ_RTC60S] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTC60S_MASK,
- },
- [S2MPS14_IRQ_RTCA1] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA1_MASK,
- },
- [S2MPS14_IRQ_RTCA0] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA0_MASK,
- },
- [S2MPS14_IRQ_SMPL] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_SMPL_MASK,
- },
- [S2MPS14_IRQ_RTC1S] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTC1S_MASK,
- },
- [S2MPS14_IRQ_WTSR] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_WTSR_MASK,
- },
- [S2MPS14_IRQ_INT120C] = {
- .reg_offset = 2,
- .mask = S2MPS11_IRQ_INT120C_MASK,
- },
- [S2MPS14_IRQ_INT140C] = {
- .reg_offset = 2,
- .mask = S2MPS11_IRQ_INT140C_MASK,
- },
- [S2MPS14_IRQ_TSD] = {
- .reg_offset = 2,
- .mask = S2MPS14_IRQ_TSD_MASK,
- },
+ REGMAP_IRQ_REG(S2MPS14_IRQ_PWRONF, 0, S2MPS11_IRQ_PWRONF_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_PWRONR, 0, S2MPS11_IRQ_PWRONR_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_JIGONBF, 0, S2MPS11_IRQ_JIGONBF_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_JIGONBR, 0, S2MPS11_IRQ_JIGONBR_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_ACOKBF, 0, S2MPS11_IRQ_ACOKBF_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_ACOKBR, 0, S2MPS11_IRQ_ACOKBR_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_PWRON1S, 0, S2MPS11_IRQ_PWRON1S_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_MRB, 0, S2MPS11_IRQ_MRB_MASK),
+
+ REGMAP_IRQ_REG(S2MPS14_IRQ_RTC60S, 1, S2MPS11_IRQ_RTC60S_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_RTCA1, 1, S2MPS11_IRQ_RTCA1_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_RTCA0, 1, S2MPS11_IRQ_RTCA0_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_SMPL, 1, S2MPS11_IRQ_SMPL_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_RTC1S, 1, S2MPS11_IRQ_RTC1S_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_WTSR, 1, S2MPS11_IRQ_WTSR_MASK),
+
+ REGMAP_IRQ_REG(S2MPS14_IRQ_INT120C, 2, S2MPS11_IRQ_INT120C_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_INT140C, 2, S2MPS11_IRQ_INT140C_MASK),
+ REGMAP_IRQ_REG(S2MPS14_IRQ_TSD, 2, S2MPS14_IRQ_TSD_MASK),
};
static const struct regmap_irq s2mpu02_irqs[] = {
- [S2MPU02_IRQ_PWRONF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRONF_MASK,
- },
- [S2MPU02_IRQ_PWRONR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRONR_MASK,
- },
- [S2MPU02_IRQ_JIGONBF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_JIGONBF_MASK,
- },
- [S2MPU02_IRQ_JIGONBR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_JIGONBR_MASK,
- },
- [S2MPU02_IRQ_ACOKBF] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_ACOKBF_MASK,
- },
- [S2MPU02_IRQ_ACOKBR] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_ACOKBR_MASK,
- },
- [S2MPU02_IRQ_PWRON1S] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_PWRON1S_MASK,
- },
- [S2MPU02_IRQ_MRB] = {
- .reg_offset = 0,
- .mask = S2MPS11_IRQ_MRB_MASK,
- },
- [S2MPU02_IRQ_RTC60S] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTC60S_MASK,
- },
- [S2MPU02_IRQ_RTCA1] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA1_MASK,
- },
- [S2MPU02_IRQ_RTCA0] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTCA0_MASK,
- },
- [S2MPU02_IRQ_SMPL] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_SMPL_MASK,
- },
- [S2MPU02_IRQ_RTC1S] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_RTC1S_MASK,
- },
- [S2MPU02_IRQ_WTSR] = {
- .reg_offset = 1,
- .mask = S2MPS11_IRQ_WTSR_MASK,
- },
- [S2MPU02_IRQ_INT120C] = {
- .reg_offset = 2,
- .mask = S2MPS11_IRQ_INT120C_MASK,
- },
- [S2MPU02_IRQ_INT140C] = {
- .reg_offset = 2,
- .mask = S2MPS11_IRQ_INT140C_MASK,
- },
- [S2MPU02_IRQ_TSD] = {
- .reg_offset = 2,
- .mask = S2MPS14_IRQ_TSD_MASK,
- },
+ REGMAP_IRQ_REG(S2MPU02_IRQ_PWRONF, 0, S2MPS11_IRQ_PWRONF_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_PWRONR, 0, S2MPS11_IRQ_PWRONR_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_JIGONBF, 0, S2MPS11_IRQ_JIGONBF_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_JIGONBR, 0, S2MPS11_IRQ_JIGONBR_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_ACOKBF, 0, S2MPS11_IRQ_ACOKBF_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_ACOKBR, 0, S2MPS11_IRQ_ACOKBR_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_PWRON1S, 0, S2MPS11_IRQ_PWRON1S_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_MRB, 0, S2MPS11_IRQ_MRB_MASK),
+
+ REGMAP_IRQ_REG(S2MPU02_IRQ_RTC60S, 1, S2MPS11_IRQ_RTC60S_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_RTCA1, 1, S2MPS11_IRQ_RTCA1_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_RTCA0, 1, S2MPS11_IRQ_RTCA0_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_SMPL, 1, S2MPS11_IRQ_SMPL_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_RTC1S, 1, S2MPS11_IRQ_RTC1S_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_WTSR, 1, S2MPS11_IRQ_WTSR_MASK),
+
+ REGMAP_IRQ_REG(S2MPU02_IRQ_INT120C, 2, S2MPS11_IRQ_INT120C_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_INT140C, 2, S2MPS11_IRQ_INT140C_MASK),
+ REGMAP_IRQ_REG(S2MPU02_IRQ_TSD, 2, S2MPS14_IRQ_TSD_MASK),
};
static const struct regmap_irq s2mpu05_irqs[] = {
@@ -247,74 +159,35 @@ static const struct regmap_irq s2mpu05_irqs[] = {
};
static const struct regmap_irq s5m8767_irqs[] = {
- [S5M8767_IRQ_PWRR] = {
- .reg_offset = 0,
- .mask = S5M8767_IRQ_PWRR_MASK,
- },
- [S5M8767_IRQ_PWRF] = {
- .reg_offset = 0,
- .mask = S5M8767_IRQ_PWRF_MASK,
- },
- [S5M8767_IRQ_PWR1S] = {
- .reg_offset = 0,
- .mask = S5M8767_IRQ_PWR1S_MASK,
- },
- [S5M8767_IRQ_JIGR] = {
- .reg_offset = 0,
- .mask = S5M8767_IRQ_JIGR_MASK,
- },
- [S5M8767_IRQ_JIGF] = {
- .reg_offset = 0,
- .mask = S5M8767_IRQ_JIGF_MASK,
- },
- [S5M8767_IRQ_LOWBAT2] = {
- .reg_offset = 0,
- .mask = S5M8767_IRQ_LOWBAT2_MASK,
- },
- [S5M8767_IRQ_LOWBAT1] = {
- .reg_offset = 0,
- .mask = S5M8767_IRQ_LOWBAT1_MASK,
- },
- [S5M8767_IRQ_MRB] = {
- .reg_offset = 1,
- .mask = S5M8767_IRQ_MRB_MASK,
- },
- [S5M8767_IRQ_DVSOK2] = {
- .reg_offset = 1,
- .mask = S5M8767_IRQ_DVSOK2_MASK,
- },
- [S5M8767_IRQ_DVSOK3] = {
- .reg_offset = 1,
- .mask = S5M8767_IRQ_DVSOK3_MASK,
- },
- [S5M8767_IRQ_DVSOK4] = {
- .reg_offset = 1,
- .mask = S5M8767_IRQ_DVSOK4_MASK,
- },
- [S5M8767_IRQ_RTC60S] = {
- .reg_offset = 2,
- .mask = S5M8767_IRQ_RTC60S_MASK,
- },
- [S5M8767_IRQ_RTCA1] = {
- .reg_offset = 2,
- .mask = S5M8767_IRQ_RTCA1_MASK,
- },
- [S5M8767_IRQ_RTCA2] = {
- .reg_offset = 2,
- .mask = S5M8767_IRQ_RTCA2_MASK,
- },
- [S5M8767_IRQ_SMPL] = {
- .reg_offset = 2,
- .mask = S5M8767_IRQ_SMPL_MASK,
- },
- [S5M8767_IRQ_RTC1S] = {
- .reg_offset = 2,
- .mask = S5M8767_IRQ_RTC1S_MASK,
- },
- [S5M8767_IRQ_WTSR] = {
- .reg_offset = 2,
- .mask = S5M8767_IRQ_WTSR_MASK,
- },
+ REGMAP_IRQ_REG(S5M8767_IRQ_PWRR, 0, S5M8767_IRQ_PWRR_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_PWRF, 0, S5M8767_IRQ_PWRF_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_PWR1S, 0, S5M8767_IRQ_PWR1S_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_JIGR, 0, S5M8767_IRQ_JIGR_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_JIGF, 0, S5M8767_IRQ_JIGF_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_LOWBAT2, 0, S5M8767_IRQ_LOWBAT2_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_LOWBAT1, 0, S5M8767_IRQ_LOWBAT1_MASK),
+
+ REGMAP_IRQ_REG(S5M8767_IRQ_MRB, 1, S5M8767_IRQ_MRB_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_DVSOK2, 1, S5M8767_IRQ_DVSOK2_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_DVSOK3, 1, S5M8767_IRQ_DVSOK3_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_DVSOK4, 1, S5M8767_IRQ_DVSOK4_MASK),
+
+ REGMAP_IRQ_REG(S5M8767_IRQ_RTC60S, 2, S5M8767_IRQ_RTC60S_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_RTCA1, 2, S5M8767_IRQ_RTCA1_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_RTCA2, 2, S5M8767_IRQ_RTCA2_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_SMPL, 2, S5M8767_IRQ_SMPL_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_RTC1S, 2, S5M8767_IRQ_RTC1S_MASK),
+ REGMAP_IRQ_REG(S5M8767_IRQ_WTSR, 2, S5M8767_IRQ_WTSR_MASK),
+};
+
+/* All S2MPG10 interrupt sources are read-only and don't require clearing */
+static const struct regmap_irq_chip s2mpg10_irq_chip = {
+ .name = "s2mpg10",
+ .irqs = s2mpg10_irqs,
+ .num_irqs = ARRAY_SIZE(s2mpg10_irqs),
+ .num_regs = 6,
+ .status_base = S2MPG10_PMIC_INT1,
+ .mask_base = S2MPG10_PMIC_INT1M,
};
static const struct regmap_irq_chip s2mps11_irq_chip = {
@@ -382,23 +255,21 @@ static const struct regmap_irq_chip s5m8767_irq_chip = {
int sec_irq_init(struct sec_pmic_dev *sec_pmic)
{
- int ret = 0;
- int type = sec_pmic->device_type;
const struct regmap_irq_chip *sec_irq_chip;
+ int ret;
- if (!sec_pmic->irq) {
- dev_warn(sec_pmic->dev,
- "No interrupt specified, no interrupts\n");
- return 0;
- }
-
- switch (type) {
+ switch (sec_pmic->device_type) {
case S5M8767X:
sec_irq_chip = &s5m8767_irq_chip;
break;
+ case S2DOS05:
+ return 0;
case S2MPA01:
sec_irq_chip = &s2mps14_irq_chip;
break;
+ case S2MPG10:
+ sec_irq_chip = &s2mpg10_irq_chip;
+ break;
case S2MPS11X:
sec_irq_chip = &s2mps11_irq_chip;
break;
@@ -418,18 +289,24 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
sec_irq_chip = &s2mpu05_irq_chip;
break;
default:
- dev_err(sec_pmic->dev, "Unknown device type %lu\n",
- sec_pmic->device_type);
- return -EINVAL;
+ return dev_err_probe(sec_pmic->dev, -EINVAL,
+ "Unsupported device type %d\n",
+ sec_pmic->device_type);
+ }
+
+ if (!sec_pmic->irq) {
+ dev_warn(sec_pmic->dev,
+ "No interrupt specified, no interrupts\n");
+ return 0;
}
ret = devm_regmap_add_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic,
sec_pmic->irq, IRQF_ONESHOT,
0, sec_irq_chip, &sec_pmic->irq_data);
- if (ret != 0) {
- dev_err(sec_pmic->dev, "Failed to register IRQ chip: %d\n", ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(sec_pmic->dev, ret,
+ "Failed to add %s IRQ chip\n",
+ sec_irq_chip->name);
/*
* The rtc-s5m driver requests S2MPS14_IRQ_RTCA0 also for S2MPS11
@@ -439,10 +316,3 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
return 0;
}
-EXPORT_SYMBOL_GPL(sec_irq_init);
-
-MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
-MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
-MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
-MODULE_DESCRIPTION("Interrupt support for the S5M MFD");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 7ee293b09f62..a5f9241fa3f2 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -631,49 +631,6 @@ unsigned long sm501_set_clock(struct device *dev,
EXPORT_SYMBOL_GPL(sm501_set_clock);
-/* sm501_find_clock
- *
- * finds the closest available frequency for a given clock
-*/
-
-unsigned long sm501_find_clock(struct device *dev,
- int clksrc,
- unsigned long req_freq)
-{
- struct sm501_devdata *sm = dev_get_drvdata(dev);
- unsigned long sm501_freq; /* the frequency achieveable by the 501 */
- struct sm501_clock to;
-
- switch (clksrc) {
- case SM501_CLOCK_P2XCLK:
- if (sm->rev >= 0xC0) {
- /* SM502 -> use the programmable PLL */
- sm501_freq = (sm501_calc_pll(2 * req_freq,
- &to, 5) / 2);
- } else {
- sm501_freq = (sm501_select_clock(2 * req_freq,
- &to, 5) / 2);
- }
- break;
-
- case SM501_CLOCK_V2XCLK:
- sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2);
- break;
-
- case SM501_CLOCK_MCLK:
- case SM501_CLOCK_M1XCLK:
- sm501_freq = sm501_select_clock(req_freq, &to, 3);
- break;
-
- default:
- sm501_freq = 0; /* error */
- }
-
- return sm501_freq;
-}
-
-EXPORT_SYMBOL_GPL(sm501_find_clock);
-
static struct sm501_device *to_sm_device(struct platform_device *pdev)
{
return container_of(pdev, struct sm501_device, pdev);
@@ -915,7 +872,8 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip,
}
}
-static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int sm501_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct sm501_gpio_chip *smchip = gpiochip_get_data(chip);
@@ -939,6 +897,8 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
sm501_gpio_ensure_gpio(smchip, bit);
spin_unlock_irqrestore(&smgpio->lock, save);
+
+ return 0;
}
static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset)
@@ -1005,7 +965,7 @@ static const struct gpio_chip gpio_chip_template = {
.ngpio = 32,
.direction_input = sm501_gpio_input,
.direction_output = sm501_gpio_output,
- .set = sm501_gpio_set,
+ .set_rv = sm501_gpio_set,
.get = sm501_gpio_get,
};
diff --git a/drivers/mfd/sprd-sc27xx-spi.c b/drivers/mfd/sprd-sc27xx-spi.c
index 7186e2108108..d6b4350779e6 100644
--- a/drivers/mfd/sprd-sc27xx-spi.c
+++ b/drivers/mfd/sprd-sc27xx-spi.c
@@ -210,7 +210,10 @@ static int sprd_pmic_probe(struct spi_device *spi)
return ret;
}
- device_init_wakeup(&spi->dev, true);
+ ret = devm_device_init_wakeup(&spi->dev);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret, "Failed to init wakeup\n");
+
return 0;
}
diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c
index b2704a9809c7..09073dbc9c80 100644
--- a/drivers/mfd/stm32-lptimer.c
+++ b/drivers/mfd/stm32-lptimer.c
@@ -6,6 +6,7 @@
* Inspired by Benjamin Gaignard's stm32-timers driver
*/
+#include <linux/bitfield.h>
#include <linux/mfd/stm32-lptimer.h>
#include <linux/module.h>
#include <linux/of_platform.h>
@@ -49,6 +50,36 @@ static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata)
return 0;
}
+static int stm32_lptimer_detect_hwcfgr(struct stm32_lptimer *ddata)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_read(ddata->regmap, STM32_LPTIM_VERR, &ddata->version);
+ if (ret)
+ return ret;
+
+ /* Try to guess parameters from HWCFGR: e.g. encoder mode (STM32MP15) */
+ ret = regmap_read(ddata->regmap, STM32_LPTIM_HWCFGR1, &val);
+ if (ret)
+ return ret;
+
+ /* Fallback to legacy init if HWCFGR isn't present */
+ if (!val)
+ return stm32_lptimer_detect_encoder(ddata);
+
+ ddata->has_encoder = FIELD_GET(STM32_LPTIM_HWCFGR1_ENCODER, val);
+
+ ret = regmap_read(ddata->regmap, STM32_LPTIM_HWCFGR2, &val);
+ if (ret)
+ return ret;
+
+ /* Number of capture/compare channels */
+ ddata->num_cc_chans = FIELD_GET(STM32_LPTIM_HWCFGR2_CHAN_NUM, val);
+
+ return 0;
+}
+
static int stm32_lptimer_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -73,7 +104,7 @@ static int stm32_lptimer_probe(struct platform_device *pdev)
if (IS_ERR(ddata->clk))
return PTR_ERR(ddata->clk);
- ret = stm32_lptimer_detect_encoder(ddata);
+ ret = stm32_lptimer_detect_hwcfgr(ddata);
if (ret)
return ret;
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c
index 792236f56399..b9cc85ea2c40 100644
--- a/drivers/mfd/stmpe-spi.c
+++ b/drivers/mfd/stmpe-spi.c
@@ -129,7 +129,7 @@ static const struct spi_device_id stmpe_spi_id[] = {
{ "stmpe2403", STMPE2403 },
{ }
};
-MODULE_DEVICE_TABLE(spi, stmpe_id);
+MODULE_DEVICE_TABLE(spi, stmpe_spi_id);
static struct spi_driver stmpe_spi_driver = {
.driver = {
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index 00fb12c4f491..03bd5cd66798 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -446,7 +446,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
* offset 6 == vibrator motor driver
*/
-static void
+static int
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
if (offset < 4)
@@ -455,6 +455,8 @@ tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
tps65010_set_led(offset - 3, value ? ON : OFF);
else
tps65010_set_vib(value);
+
+ return 0;
}
static int
@@ -512,7 +514,6 @@ static void tps65010_remove(struct i2c_client *client)
if (client->irq > 0)
free_irq(client->irq, tps);
cancel_delayed_work_sync(&tps->work);
- debugfs_remove(tps->file);
the_tps = NULL;
}
@@ -608,7 +609,7 @@ static int tps65010_probe(struct i2c_client *client)
tps65010_work(&tps->work.work);
- tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
+ tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, client->debugfs,
tps, DEBUG_FOPS);
/* optionally register GPIOs */
@@ -619,7 +620,7 @@ static int tps65010_probe(struct i2c_client *client)
tps->chip.parent = &client->dev;
tps->chip.owner = THIS_MODULE;
- tps->chip.set = tps65010_gpio_set;
+ tps->chip.set_rv = tps65010_gpio_set;
tps->chip.direction_output = tps65010_output;
/* NOTE: only partial support for inputs; nyet IRQs */
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index fc4d4c844a81..fd71ba29f6b5 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -104,7 +104,8 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
return ucb1x00_reg_read(ucb, UCB_IO_DATA);
}
-static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static int ucb1x00_gpio_set(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct ucb1x00 *ucb = gpiochip_get_data(chip);
unsigned long flags;
@@ -119,6 +120,8 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
ucb1x00_disable(ucb);
spin_unlock_irqrestore(&ucb->io_lock, flags);
+
+ return 0;
}
static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -567,7 +570,7 @@ static int ucb1x00_probe(struct mcp *mcp)
ucb->gpio.owner = THIS_MODULE;
ucb->gpio.base = pdata->gpio_base;
ucb->gpio.ngpio = 10;
- ucb->gpio.set = ucb1x00_gpio_set;
+ ucb->gpio.set_rv = ucb1x00_gpio_set;
ucb->gpio.get = ucb1x00_gpio_get;
ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
ucb->gpio.direction_output = ucb1x00_gpio_direction_output;