diff options
Diffstat (limited to 'drivers/mfd/sec-i2c.c')
| -rw-r--r-- | drivers/mfd/sec-i2c.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/drivers/mfd/sec-i2c.c b/drivers/mfd/sec-i2c.c new file mode 100644 index 000000000000..8e3a365ff3e5 --- /dev/null +++ b/drivers/mfd/sec-i2c.c @@ -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"); |