diff options
Diffstat (limited to 'drivers/mfd')
-rw-r--r-- | drivers/mfd/88pm886.c | 14 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 35 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 5 | ||||
-rw-r--r-- | drivers/mfd/aat2870-core.c | 4 | ||||
-rw-r--r-- | drivers/mfd/as3722.c | 4 | ||||
-rw-r--r-- | drivers/mfd/bcm590xx.c | 66 | ||||
-rw-r--r-- | drivers/mfd/exynos-lpass.c | 31 | ||||
-rw-r--r-- | drivers/mfd/max14577.c | 1 | ||||
-rw-r--r-- | drivers/mfd/max77541.c | 2 | ||||
-rw-r--r-- | drivers/mfd/max77705.c | 4 | ||||
-rw-r--r-- | drivers/mfd/max8925-i2c.c | 1 | ||||
-rw-r--r-- | drivers/mfd/rohm-bd96801.c | 565 | ||||
-rw-r--r-- | drivers/mfd/rt5033.c | 6 | ||||
-rw-r--r-- | drivers/mfd/sec-acpm.c | 442 | ||||
-rw-r--r-- | drivers/mfd/sec-common.c | 301 | ||||
-rw-r--r-- | drivers/mfd/sec-core.c | 481 | ||||
-rw-r--r-- | drivers/mfd/sec-core.h | 23 | ||||
-rw-r--r-- | drivers/mfd/sec-i2c.c | 239 | ||||
-rw-r--r-- | drivers/mfd/sec-irq.c | 460 | ||||
-rw-r--r-- | drivers/mfd/sm501.c | 50 | ||||
-rw-r--r-- | drivers/mfd/sprd-sc27xx-spi.c | 5 | ||||
-rw-r--r-- | drivers/mfd/stm32-lptimer.c | 33 | ||||
-rw-r--r-- | drivers/mfd/stmpe-spi.c | 2 | ||||
-rw-r--r-- | drivers/mfd/tps65010.c | 9 | ||||
-rw-r--r-- | drivers/mfd/ucb1x00-core.c | 7 |
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 = ®ulator_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 = ®ulator_res[num_intb + i]; + struct resource *res = ®ulator_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; |