mfd: sec: Split into core and transport (i2c) drivers

As a preparation for adding support for Samsung's S2MPG10, which is
connected via SPEEDY / ACPM rather than I2C, split out (move) all
I2C-specific driver code into its own kernel module, sec-i2c, and
make the existing sec-core module be just the transport-agnostic core
driver kernel module.

At the same time, update all defconfigs that reference the old kconfig
symbol name.

While at it, also update file header comments and module description(s)
to drop references to 'mfd', and update comments to be C-style, not
C++.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: André Draszik <andre.draszik@linaro.org>
Link: https://lore.kernel.org/r/20250409-s2mpg10-v4-8-d66d5f39b6bf@linaro.org
Signed-off-by: Lee Jones <lee@kernel.org>
This commit is contained in:
André Draszik 2025-04-09 21:37:29 +01:00 committed by Lee Jones
parent 8b88b5e4d5
commit 680ef57915
9 changed files with 287 additions and 227 deletions

View file

@ -167,7 +167,7 @@ CONFIG_MFD_MAX77686=y
CONFIG_MFD_MAX77693=y
CONFIG_MFD_MAX8997=y
CONFIG_MFD_MAX8998=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_SEC_I2C=y
CONFIG_MFD_STMPE=y
CONFIG_STMPE_I2C=y
CONFIG_MFD_TPS65090=y

View file

@ -612,7 +612,7 @@ CONFIG_MFD_QCOM_RPM=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_RK8XX_I2C=y
CONFIG_MFD_RN5T618=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_SEC_I2C=y
CONFIG_MFD_STMPE=y
CONFIG_MFD_PALMAS=y
CONFIG_MFD_TPS65090=y

View file

@ -335,7 +335,7 @@ CONFIG_MFD_MAX77693=y
CONFIG_MFD_MAX8907=m
CONFIG_EZX_PCAP=y
CONFIG_UCB1400_CORE=m
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_SEC_I2C=y
CONFIG_MFD_PALMAS=y
CONFIG_MFD_TPS65090=y
CONFIG_MFD_TPS6586X=y

View file

@ -769,7 +769,7 @@ CONFIG_MFD_MT6397=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_RK8XX_I2C=y
CONFIG_MFD_RK8XX_SPI=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_SEC_I2C=y
CONFIG_MFD_SL28CPLD=y
CONFIG_RZ_MTU3=y
CONFIG_MFD_TI_AM335X_TSCADC=m

View file

@ -1312,21 +1312,25 @@ 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_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.

View file

@ -230,6 +230,7 @@ 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
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

View file

@ -1,23 +1,21 @@
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright (c) 2012 Samsung Electronics Co., Ltd
// http://www.samsung.com
/*
* 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/i2c.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/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/of.h>
#include <linux/pm.h>
@ -88,144 +86,6 @@ static const struct mfd_cell s2mpu05_devs[] = {
{ .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;
@ -268,7 +128,7 @@ static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic)
* platform data.
*/
static struct sec_platform_data *
sec_pmic_i2c_parse_dt_pdata(struct device *dev)
sec_pmic_parse_dt_pdata(struct device *dev)
{
struct sec_platform_data *pd;
@ -283,68 +143,34 @@ sec_pmic_i2c_parse_dt_pdata(struct device *dev)
return pd;
}
static int sec_pmic_probe(struct i2c_client *i2c)
int sec_pmic_probe(struct device *dev, unsigned long device_type,
unsigned int irq, struct regmap *regmap,
struct i2c_client *client)
{
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);
sec_pmic = devm_kzalloc(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;
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_i2c_parse_dt_pdata(sec_pmic->dev);
pdata = sec_pmic_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);
@ -387,9 +213,9 @@ static int sec_pmic_probe(struct i2c_client *i2c)
num_sec_devs = ARRAY_SIZE(s2mpu05_devs);
break;
default:
dev_err(&i2c->dev, "Unsupported device type (%lu)\n",
dev_err(sec_pmic->dev, "Unsupported device type %lu\n",
sec_pmic->device_type);
return -ENODEV;
return -EINVAL;
}
ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs,
NULL, 0, NULL);
@ -401,10 +227,11 @@ static int sec_pmic_probe(struct i2c_client *i2c)
return ret;
}
EXPORT_SYMBOL_GPL(sec_pmic_probe);
static void sec_pmic_shutdown(struct i2c_client *i2c)
void sec_pmic_shutdown(struct device *dev)
{
struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
unsigned int reg, mask;
if (!sec_pmic->pdata->manual_poweroff)
@ -428,11 +255,11 @@ static void sec_pmic_shutdown(struct i2c_client *i2c)
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 i2c_client *i2c = to_i2c_client(dev);
struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c);
struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
enable_irq_wake(sec_pmic->irq);
@ -452,8 +279,7 @@ static int sec_pmic_suspend(struct device *dev)
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);
struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev);
if (device_may_wakeup(dev))
disable_irq_wake(sec_pmic->irq);
@ -462,20 +288,9 @@ static int sec_pmic_resume(struct device *dev)
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);
DEFINE_SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume);
EXPORT_SYMBOL_GPL(sec_pmic_pm_ops);
MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
MODULE_DESCRIPTION("Core support for the S5M MFD");
MODULE_DESCRIPTION("Core driver for the Samsung S5M");
MODULE_LICENSE("GPL");

View file

@ -10,6 +10,15 @@
#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, unsigned long 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 */

231
drivers/mfd/sec-i2c.c Normal file
View file

@ -0,0 +1,231 @@
// 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/of.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include "sec-core.h"
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 int sec_pmic_i2c_probe(struct i2c_client *client)
{
const struct regmap_config *regmap;
unsigned long device_type;
struct regmap *regmap_pmic;
int ret;
device_type = (unsigned long)of_device_get_match_data(&client->dev);
switch (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;
}
regmap_pmic = devm_regmap_init_i2c(client, regmap);
if (IS_ERR(regmap_pmic)) {
ret = PTR_ERR(regmap_pmic);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
ret);
return ret;
}
return sec_pmic_probe(&client->dev, 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 of_device_id sec_pmic_i2c_of_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,
},
{ },
};
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_DESCRIPTION("I2C driver for the Samsung S5M");
MODULE_LICENSE("GPL");