S2dos05 has 1 buck and 4 LDO regulators, used for powering
panel/touchscreen.
Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com>
---
Changes in v4:
- remove excessive linux/module.h import
- use generic regulator helpers
- use of_match
- use devm_* for mem allocations
- use // style comment
- drop all junk Samsung code
- adjust to depend on sec-core
---
MAINTAINERS | 1 +
drivers/regulator/Kconfig | 8 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/s2dos05-regulator.c | 176 ++++++++++++++++++++++++++++++++++
include/linux/regulator/s2dos05.h | 73 ++++++++++++++
5 files changed, 259 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 444cc855a01e..25dcce07180a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20476,6 +20476,7 @@ F: Documentation/devicetree/bindings/regulator/samsung,s2m*.yaml
F: Documentation/devicetree/bindings/regulator/samsung,s5m*.yaml
F: drivers/clk/clk-s2mps11.c
F: drivers/mfd/sec*.c
+F: drivers/regulator/s2dos*.c
F: drivers/regulator/s2m*.c
F: drivers/regulator/s5m*.c
F: drivers/rtc/rtc-s5m.c
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4b411a09c1a6..63085d73cf74 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -1322,6 +1322,14 @@ config REGULATOR_RTQ2208
and two ldos. It features wide output voltage range from 0.4V to 2.05V
and the capability to configure the corresponding power stages.
+config REGULATOR_S2DOS05
+ tristate "SLSI S2DOS05 regulator"
+ depends on MFD_SEC_CORE || COMPILE_TEST
+ help
+ This driver provides support for the voltage regulators of the S2DOS05.
+ The S2DOS05 is a companion power management IC for the smart phones.
+ The S2DOS05 has 4 LDOs and 1 BUCK outputs.
+
config REGULATOR_S2MPA01
tristate "Samsung S2MPA01 voltage regulator"
depends on MFD_SEC_CORE || COMPILE_TEST
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index a61fa42b13c4..d26e0db7c825 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -154,6 +154,7 @@ obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o
obj-$(CONFIG_REGULATOR_RTQ2134) += rtq2134-regulator.o
obj-$(CONFIG_REGULATOR_RTQ6752) += rtq6752-regulator.o
obj-$(CONFIG_REGULATOR_RTQ2208) += rtq2208-regulator.o
+obj-$(CONFIG_REGULATOR_S2DOS05) += s2dos05-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
diff --git a/drivers/regulator/s2dos05-regulator.c b/drivers/regulator/s2dos05-regulator.c
new file mode 100644
index 000000000000..1325c8311b08
--- /dev/null
+++ b/drivers/regulator/s2dos05-regulator.c
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// s2dos05.c - Regulator driver for the Samsung s2dos05
+//
+// Copyright (C) 2024 Dzmitry Sankouski <dsankouski@gmail.com>
+
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/mfd/samsung/core.h>
+#include <linux/regulator/s2dos05.h>
+#include <linux/i2c.h>
+
+struct s2dos05_data {
+ struct regmap *regmap;
+ struct device *dev;
+};
+
+static const struct regulator_ops s2dos05_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_active_discharge = regulator_set_active_discharge_regmap,
+};
+
+#define _BUCK(macro) S2DOS05_BUCK##macro
+#define _buck_ops(num) s2dos05_ops##num
+
+#define _LDO(macro) S2DOS05_LDO##macro
+#define _REG(ctrl) S2DOS05_REG##ctrl
+#define _ldo_ops(num) s2dos05_ops##num
+#define _MASK(macro) S2DOS05_ENABLE_MASK##macro
+#define _TIME(macro) S2DOS05_ENABLE_TIME##macro
+
+#define BUCK_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \
+ .name = _name, \
+ .id = _id, \
+ .ops = _ops, \
+ .of_match = of_match_ptr(_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = m, \
+ .uV_step = s, \
+ .n_voltages = S2DOS05_BUCK_N_VOLTAGES, \
+ .vsel_reg = v, \
+ .vsel_mask = S2DOS05_BUCK_VSEL_MASK, \
+ .enable_reg = e, \
+ .enable_mask = em, \
+ .enable_time = t, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = S2DOS05_BUCK_FD_MASK, \
+ .active_discharge_reg = a, \
+ .active_discharge_mask = S2DOS05_BUCK_FD_MASK \
+}
+
+#define LDO_DESC(_name, _id, _ops, m, s, v, e, em, t, a) { \
+ .name = _name, \
+ .id = _id, \
+ .ops = _ops, \
+ .of_match = of_match_ptr(_name), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = m, \
+ .uV_step = s, \
+ .n_voltages = S2DOS05_LDO_N_VOLTAGES, \
+ .vsel_reg = v, \
+ .vsel_mask = S2DOS05_LDO_VSEL_MASK, \
+ .enable_reg = e, \
+ .enable_mask = em, \
+ .enable_time = t, \
+ .active_discharge_off = 0, \
+ .active_discharge_on = S2DOS05_LDO_FD_MASK, \
+ .active_discharge_reg = a, \
+ .active_discharge_mask = S2DOS05_LDO_FD_MASK \
+}
+
+static struct regulator_desc regulators[S2DOS05_REGULATOR_MAX] = {
+ // name, id, ops, min_uv, uV_step, vsel_reg, enable_reg
+ LDO_DESC("ldo1", _LDO(1), &_ldo_ops(), _LDO(_MIN1),
+ _LDO(_STEP1), _REG(_LDO1_CFG),
+ _REG(_EN), _MASK(_L1), _TIME(_LDO), _REG(_LDO1_CFG)),
+ LDO_DESC("ldo2", _LDO(2), &_ldo_ops(), _LDO(_MIN1),
+ _LDO(_STEP1), _REG(_LDO2_CFG),
+ _REG(_EN), _MASK(_L2), _TIME(_LDO), _REG(_LDO2_CFG)),
+ LDO_DESC("ldo3", _LDO(3), &_ldo_ops(), _LDO(_MIN2),
+ _LDO(_STEP1), _REG(_LDO3_CFG),
+ _REG(_EN), _MASK(_L3), _TIME(_LDO), _REG(_LDO3_CFG)),
+ LDO_DESC("ldo4", _LDO(4), &_ldo_ops(), _LDO(_MIN2),
+ _LDO(_STEP1), _REG(_LDO4_CFG),
+ _REG(_EN), _MASK(_L4), _TIME(_LDO), _REG(_LDO4_CFG)),
+ BUCK_DESC("buck1", _BUCK(1), &_buck_ops(), _BUCK(_MIN1),
+ _BUCK(_STEP1), _REG(_BUCK_VOUT),
+ _REG(_EN), _MASK(_B1), _TIME(_BUCK), _REG(_BUCK_CFG)),
+};
+
+static int s2dos05_pmic_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+ struct of_regulator_match *rdata = NULL;
+ struct s2dos05_data *s2dos05;
+ struct regulator_config config = { };
+ unsigned int rdev_num = ARRAY_SIZE(regulators);
+ int i, ret;
+
+ s2dos05 = devm_kzalloc(dev, sizeof(struct s2dos05_data),
+ GFP_KERNEL);
+ if (!s2dos05)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, s2dos05);
+
+ rdata = devm_kcalloc(dev, rdev_num, sizeof(*rdata), GFP_KERNEL);
+ if (!rdata)
+ return -ENOMEM;
+
+ for (i = 0; i < rdev_num; i++)
+ rdata[i].name = regulators[i].name;
+
+ s2dos05->regmap = iodev->regmap_pmic;
+ s2dos05->dev = dev;
+ if (!dev->of_node)
+ dev->of_node = dev->parent->of_node;
+
+ for (i = 0; i < rdev_num; i++) {
+ struct regulator_dev *regulator;
+
+ config.init_data = rdata[i].init_data;
+ config.of_node = rdata[i].of_node;
+ config.dev = dev;
+ config.driver_data = s2dos05;
+ regulator = devm_regulator_register(&pdev->dev,
+ ®ulators[i], &config);
+ if (IS_ERR(regulator)) {
+ ret = PTR_ERR(regulator);
+ dev_err(&pdev->dev, "regulator init failed for %d\n",
+ i);
+ }
+ }
+
+ return ret;
+}
+
+static const struct platform_device_id s2dos05_pmic_id[] = {
+ { "s2dos05-regulator" },
+ { },
+};
+MODULE_DEVICE_TABLE(platform, s2dos05_pmic_id);
+
+static struct platform_driver s2dos05_platform_driver = {
+ .driver = {
+ .name = "s2dos05",
+ },
+ .probe = s2dos05_pmic_probe,
+ .id_table = s2dos05_pmic_id,
+};
+module_platform_driver(s2dos05_platform_driver);
+
+MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>");
+MODULE_DESCRIPTION("SAMSUNG s2dos05 Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/s2dos05.h b/include/linux/regulator/s2dos05.h
new file mode 100644
index 000000000000..2e89fcbce769
--- /dev/null
+++ b/include/linux/regulator/s2dos05.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+// s2dos05.h
+//
+// Copyright (c) 2016 Samsung Electronics Co., Ltd
+// http://www.samsung.com
+// Copyright (C) 2024 Dzmitry Sankouski <dsankouski@gmail.com>
+
+#ifndef __LINUX_S2DOS05_H
+#define __LINUX_S2DOS05_H
+
+// S2DOS05 registers
+// Slave Addr : 0xC0
+enum S2DOS05_reg {
+ S2DOS05_REG_DEV_ID,
+ S2DOS05_REG_TOPSYS_STAT,
+ S2DOS05_REG_STAT,
+ S2DOS05_REG_EN,
+ S2DOS05_REG_LDO1_CFG,
+ S2DOS05_REG_LDO2_CFG,
+ S2DOS05_REG_LDO3_CFG,
+ S2DOS05_REG_LDO4_CFG,
+ S2DOS05_REG_BUCK_CFG,
+ S2DOS05_REG_BUCK_VOUT,
+ S2DOS05_REG_IRQ_MASK = 0x0D,
+ S2DOS05_REG_SSD_TSD = 0x0E,
+ S2DOS05_REG_OCL = 0x10,
+ S2DOS05_REG_IRQ = 0x11
+};
+
+// S2DOS05 regulator ids
+enum S2DOS05_regulators {
+ S2DOS05_LDO1,
+ S2DOS05_LDO2,
+ S2DOS05_LDO3,
+ S2DOS05_LDO4,
+ S2DOS05_BUCK1,
+ S2DOS05_REG_MAX,
+};
+
+#define S2DOS05_IRQ_PWRMT_MASK BIT(5)
+#define S2DOS05_IRQ_TSD_MASK BIT(4)
+#define S2DOS05_IRQ_SSD_MASK BIT(3)
+#define S2DOS05_IRQ_SCP_MASK BIT(2)
+#define S2DOS05_IRQ_UVLO_MASK BIT(1)
+#define S2DOS05_IRQ_OCD_MASK BIT(0)
+
+#define S2DOS05_BUCK_MIN1 506250
+#define S2DOS05_LDO_MIN1 1500000
+#define S2DOS05_LDO_MIN2 2700000
+#define S2DOS05_BUCK_STEP1 6250
+#define S2DOS05_LDO_STEP1 25000
+#define S2DOS05_LDO_VSEL_MASK 0x7F
+#define S2DOS05_LDO_FD_MASK 0x80
+#define S2DOS05_BUCK_VSEL_MASK 0xFF
+#define S2DOS05_BUCK_FD_MASK 0x08
+
+#define S2DOS05_ENABLE_MASK_L1 BIT(0)
+#define S2DOS05_ENABLE_MASK_L2 BIT(1)
+#define S2DOS05_ENABLE_MASK_L3 BIT(2)
+#define S2DOS05_ENABLE_MASK_L4 BIT(3)
+#define S2DOS05_ENABLE_MASK_B1 BIT(4)
+
+#define S2DOS05_RAMP_DELAY 12000
+
+#define S2DOS05_ENABLE_TIME_LDO 50
+#define S2DOS05_ENABLE_TIME_BUCK 350
+
+#define S2DOS05_LDO_N_VOLTAGES (S2DOS05_LDO_VSEL_MASK + 1)
+#define S2DOS05_BUCK_N_VOLTAGES (S2DOS05_BUCK_VSEL_MASK + 1)
+
+#define S2DOS05_REGULATOR_MAX (S2DOS05_REG_MAX)
+
+#endif // __LINUX_S2DOS05_H
--
2.39.2
On Fri, Sep 13, 2024 at 06:07:58PM +0300, Dzmitry Sankouski wrote: > S2dos05 has 1 buck and 4 LDO regulators, used for powering > panel/touchscreen. > > Signed-off-by: Dzmitry Sankouski <dsankouski@gmail.com> > ... > +#include <linux/bug.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/slab.h> > +#include <linux/module.h> > +#include <linux/regmap.h> > +#include <linux/interrupt.h> > +#include <linux/platform_device.h> > +#include <linux/regulator/driver.h> > +#include <linux/regulator/machine.h> > +#include <linux/regulator/of_regulator.h> > +#include <linux/mfd/samsung/core.h> > +#include <linux/regulator/s2dos05.h> > +#include <linux/i2c.h> > + > +struct s2dos05_data { > + struct regmap *regmap; > + struct device *dev; > +}; > + > +static const struct regulator_ops s2dos05_ops = { Keep definitions together. This goes down, after all declarations and macros. > + .list_voltage = regulator_list_voltage_linear, > + .map_voltage = regulator_map_voltage_linear, > + .is_enabled = regulator_is_enabled_regmap, > + .enable = regulator_enable_regmap, > + .disable = regulator_disable_regmap, > + .get_voltage_sel = regulator_get_voltage_sel_regmap, > + .set_voltage_sel = regulator_set_voltage_sel_regmap, > + .set_voltage_time_sel = regulator_set_voltage_time_sel, > + .set_active_discharge = regulator_set_active_discharge_regmap, > +}; > + > +#define _BUCK(macro) S2DOS05_BUCK##macro > +#define _buck_ops(num) s2dos05_ops##num > + > +#define _LDO(macro) S2DOS05_LDO##macro > +#define _REG(ctrl) S2DOS05_REG##ctrl > +#define _ldo_ops(num) s2dos05_ops##num > +#define _MASK(macro) S2DOS05_ENABLE_MASK##macro > +#define _TIME(macro) S2DOS05_ENABLE_TIME##macro > + ... > + > +static struct regulator_desc regulators[S2DOS05_REGULATOR_MAX] = { This should be const. > + // name, id, ops, min_uv, uV_step, vsel_reg, enable_reg > + LDO_DESC("ldo1", _LDO(1), &_ldo_ops(), _LDO(_MIN1), > + _LDO(_STEP1), _REG(_LDO1_CFG), > + _REG(_EN), _MASK(_L1), _TIME(_LDO), _REG(_LDO1_CFG)), > + LDO_DESC("ldo2", _LDO(2), &_ldo_ops(), _LDO(_MIN1), > + _LDO(_STEP1), _REG(_LDO2_CFG), > + _REG(_EN), _MASK(_L2), _TIME(_LDO), _REG(_LDO2_CFG)), > + LDO_DESC("ldo3", _LDO(3), &_ldo_ops(), _LDO(_MIN2), > + _LDO(_STEP1), _REG(_LDO3_CFG), > + _REG(_EN), _MASK(_L3), _TIME(_LDO), _REG(_LDO3_CFG)), > + LDO_DESC("ldo4", _LDO(4), &_ldo_ops(), _LDO(_MIN2), > + _LDO(_STEP1), _REG(_LDO4_CFG), > + _REG(_EN), _MASK(_L4), _TIME(_LDO), _REG(_LDO4_CFG)), > + BUCK_DESC("buck1", _BUCK(1), &_buck_ops(), _BUCK(_MIN1), > + _BUCK(_STEP1), _REG(_BUCK_VOUT), > + _REG(_EN), _MASK(_B1), _TIME(_BUCK), _REG(_BUCK_CFG)), > +}; > + > +static int s2dos05_pmic_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); > + struct of_regulator_match *rdata = NULL; > + struct s2dos05_data *s2dos05; > + struct regulator_config config = { }; > + unsigned int rdev_num = ARRAY_SIZE(regulators); > + int i, ret; > + > + s2dos05 = devm_kzalloc(dev, sizeof(struct s2dos05_data), > + GFP_KERNEL); sizeof(*) > + if (!s2dos05) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, s2dos05); > + > + rdata = devm_kcalloc(dev, rdev_num, sizeof(*rdata), GFP_KERNEL); > + if (!rdata) > + return -ENOMEM; > + > + for (i = 0; i < rdev_num; i++) > + rdata[i].name = regulators[i].name; > + > + s2dos05->regmap = iodev->regmap_pmic; > + s2dos05->dev = dev; > + if (!dev->of_node) > + dev->of_node = dev->parent->of_node; > + > + for (i = 0; i < rdev_num; i++) { > + struct regulator_dev *regulator; > + > + config.init_data = rdata[i].init_data; > + config.of_node = rdata[i].of_node; > + config.dev = dev; > + config.driver_data = s2dos05; > + regulator = devm_regulator_register(&pdev->dev, > + ®ulators[i], &config); > + if (IS_ERR(regulator)) { > + ret = PTR_ERR(regulator); > + dev_err(&pdev->dev, "regulator init failed for %d\n", > + i); > + } > + } > + > + return ret; > +} > + > +static const struct platform_device_id s2dos05_pmic_id[] = { > + { "s2dos05-regulator" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(platform, s2dos05_pmic_id); > + > +static struct platform_driver s2dos05_platform_driver = { > + .driver = { > + .name = "s2dos05", > + }, > + .probe = s2dos05_pmic_probe, > + .id_table = s2dos05_pmic_id, > +}; > +module_platform_driver(s2dos05_platform_driver); > + > +MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>"); > +MODULE_DESCRIPTION("SAMSUNG s2dos05 Regulator Driver"); s/SAMSUNG/Samsung/ Also, your Kconfig used different name, so please use one - probably Samsung. This applies to MFD patch as well. > +MODULE_LICENSE("GPL"); > diff --git a/include/linux/regulator/s2dos05.h b/include/linux/regulator/s2dos05.h > new file mode 100644 > index 000000000000..2e89fcbce769 > --- /dev/null > +++ b/include/linux/regulator/s2dos05.h > @@ -0,0 +1,73 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ Are you sure that here (and other places) you want any newer GPL? This is quite odd. Does original code (from which you took 2016 copyrights) have this as well? Best regards, Krzysztof
> > diff --git a/include/linux/regulator/s2dos05.h b/include/linux/regulator/s2dos05.h > > new file mode 100644 > > index 000000000000..2e89fcbce769 > > --- /dev/null > > +++ b/include/linux/regulator/s2dos05.h > > @@ -0,0 +1,73 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > Are you sure that here (and other places) you want any newer GPL? This > is quite odd. Does original code (from which you took 2016 copyrights) > have this as well? > Original code permits redistribution under 2+ license [1]. Is 2+ preferable over 2 only? [1]: https://github.com/klabit87/twrp_android_samsung_kernel_sdm845/blob/android-8.0/include/linux/regulator/s2dos05.h#L9
On 19/09/2024 16:28, Dzmitry Sankouski wrote: >>> diff --git a/include/linux/regulator/s2dos05.h b/include/linux/regulator/s2dos05.h >>> new file mode 100644 >>> index 000000000000..2e89fcbce769 >>> --- /dev/null >>> +++ b/include/linux/regulator/s2dos05.h >>> @@ -0,0 +1,73 @@ >>> +/* SPDX-License-Identifier: GPL-2.0+ */ >> >> Are you sure that here (and other places) you want any newer GPL? This >> is quite odd. Does original code (from which you took 2016 copyrights) >> have this as well? >> > Original code permits redistribution under 2+ license [1]. > Is 2+ preferable over 2 only? > > [1]: https://github.com/klabit87/twrp_android_samsung_kernel_sdm845/blob/android-8.0/include/linux/regulator/s2dos05.h#L9 For new code we usually suggest 2-only, but your work looks like derivative, so keeping 2+ is fine. Best regards, Krzysztof
© 2016 - 2024 Red Hat, Inc.