summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig45
-rw-r--r--drivers/mfd/Makefile7
-rw-r--r--drivers/mfd/act8846.c4
-rw-r--r--drivers/mfd/atmel-flexcom.c9
-rw-r--r--drivers/mfd/atmel-smc.c355
-rw-r--r--drivers/mfd/axp20x-i2c.c73
-rw-r--r--drivers/mfd/axp20x.c382
-rw-r--r--drivers/mfd/core.c26
-rw-r--r--drivers/mfd/da9053.c11
-rw-r--r--drivers/mfd/da9063.c15
-rw-r--r--drivers/mfd/lp3972.c4
-rw-r--r--drivers/mfd/mc13xxx.c13
-rw-r--r--drivers/mfd/mc34704.c5
-rw-r--r--drivers/mfd/mc9sdz60.c4
-rw-r--r--drivers/mfd/pca9450.c127
-rw-r--r--drivers/mfd/rave-sp.c25
-rw-r--r--drivers/mfd/rk808.c397
-rw-r--r--drivers/mfd/rn5t568.c38
-rw-r--r--drivers/mfd/rohm-bd718x7.c140
-rw-r--r--drivers/mfd/stm32-timers.c8
-rw-r--r--drivers/mfd/stmpe-i2c.c10
-rw-r--r--drivers/mfd/stpmic1.c9
-rw-r--r--drivers/mfd/superio.c6
-rw-r--r--drivers/mfd/syscon.c24
-rw-r--r--drivers/mfd/twl4030.c4
-rw-r--r--drivers/mfd/twl6030.c4
26 files changed, 1636 insertions, 109 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 9d4a82a9bb..5189364c2c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -64,12 +64,21 @@ config RAVE_SP_CORE
config MFD_STPMIC1
depends on I2C
+ select REGMAP_I2C
bool "STPMIC1 MFD driver"
help
Select this to support communication with the STPMIC1.
+config MFD_PCA9450
+ depends on I2C
+ select REGMAP_I2C
+ bool "PCA9450 MFD driver"
+ help
+ Select this to support communication with the PCA9450 PMIC.
+
config MFD_RN568PMIC
depends on I2C
+ select REGMAP_I2C
bool "Ricoh RN5T568 MFD driver"
help
Select this to support communication with the Ricoh RN5T568 PMIC.
@@ -108,4 +117,40 @@ config MFD_ATMEL_FLEXCOM
by the probe function of this MFD driver according to a device tree
property.
+config MFD_RK808
+ tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip"
+ depends on I2C && OFDEVICE
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the RK805, RK808, RK809,
+ RK817 and RK818 Power Management chips.
+ This driver provides common support for accessing the device
+ through I2C interface.
+
+config MFD_AXP20X_I2C
+ tristate "X-Powers AXP series PMICs with I2C"
+ depends on I2C && OFDEVICE
+ select REGMAP_I2C
+ help
+ If you say Y here you get support for the X-Powers AXP series power
+ management ICs (PMICs) controlled with I2C.
+ This driver currently only provide a character device in /dev.
+
+config MFD_ROHM_BD718XX
+ tristate "ROHM BD71837 Power Management IC"
+ depends on I2C=y
+ depends on OFDEVICE
+ select REGMAP_I2C
+ help
+ Select this option to get support for the ROHM BD71837
+ Power Management ICs. BD71837 is designed to power processors like
+ NXP i.MX8. It contains 8 BUCK outputs and 7 LDOs, voltage monitoring
+ and emergency shut down as well as 32,768KHz clock output.
+
+ This driver currently only provide a character device in /dev.
+
+config MFD_ATMEL_SMC
+ bool
+ select MFD_SYSCON
+
endmenu
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 50f54cfcf2..00f3eacf3c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -1,4 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
+obj-y += core.o
+
obj-$(CONFIG_MFD_ACT8846) += act8846.o
obj-$(CONFIG_MFD_DA9053) += da9053.o
obj-$(CONFIG_MFD_DA9063) += da9063.o
@@ -19,3 +21,8 @@ obj-$(CONFIG_FINTEK_SUPERIO) += fintek-superio.o
obj-$(CONFIG_SMSC_SUPERIO) += smsc-superio.o
obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o
+obj-$(CONFIG_MFD_RK808) += rk808.o
+obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o axp20x.o
+obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o
+obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
+obj-$(CONFIG_MFD_PCA9450) += pca9450.o
diff --git a/drivers/mfd/act8846.c b/drivers/mfd/act8846.c
index 0e2ac8471e..f15310f507 100644
--- a/drivers/mfd/act8846.c
+++ b/drivers/mfd/act8846.c
@@ -110,7 +110,7 @@ static struct cdev_operations act8846_fops = {
.write = act8846_write,
};
-static int act8846_probe(struct device_d *dev)
+static int act8846_probe(struct device *dev)
{
if (act8846_dev)
return -EBUSY;
@@ -127,7 +127,7 @@ static int act8846_probe(struct device_d *dev)
return 0;
}
-static struct driver_d act8846_driver = {
+static struct driver act8846_driver = {
.name = DRIVERNAME,
.probe = act8846_probe,
};
diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c
index 996d4850ee..58e94c4889 100644
--- a/drivers/mfd/atmel-flexcom.c
+++ b/drivers/mfd/atmel-flexcom.c
@@ -20,14 +20,14 @@
#define FLEX_MR_OPMODE(opmode) (((opmode) << FLEX_MR_OPMODE_OFFSET) & \
FLEX_MR_OPMODE_MASK)
-static int atmel_flexcom_probe(struct device_d *dev)
+static int atmel_flexcom_probe(struct device *dev)
{
struct resource *res;
struct clk *clk;
u32 opmode;
int err;
- err = of_property_read_u32(dev->device_node,
+ err = of_property_read_u32(dev->of_node,
"atmel,flexcom-mode", &opmode);
if (err)
return err;
@@ -57,15 +57,16 @@ static int atmel_flexcom_probe(struct device_d *dev)
clk_disable(clk);
- return of_platform_populate(dev->device_node, NULL, dev);
+ return of_platform_populate(dev->of_node, NULL, dev);
}
static const struct of_device_id atmel_flexcom_of_match[] = {
{ .compatible = "atmel,sama5d2-flexcom" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, atmel_flexcom_of_match);
-static struct driver_d atmel_flexcom_driver = {
+static struct driver atmel_flexcom_driver = {
.probe = atmel_flexcom_probe,
.name = "atmel_flexcom",
.of_compatible = atmel_flexcom_of_match,
diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c
new file mode 100644
index 0000000000..9432aa2c68
--- /dev/null
+++ b/drivers/mfd/atmel-smc.c
@@ -0,0 +1,355 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Atmel SMC (Static Memory Controller) helper functions.
+ *
+ * Copyright (C) 2017 Atmel
+ * Copyright (C) 2017 Free Electrons
+ *
+ * Author: Boris Brezillon <boris.brezillon@free-electrons.com>
+ */
+
+#include <linux/mfd/syscon/atmel-smc.h>
+#include <linux/string.h>
+#include <linux/export.h>
+#include <linux/regmap.h>
+#include <linux/bitops.h>
+
+/**
+ * atmel_smc_cs_conf_init - initialize a SMC CS conf
+ * @conf: the SMC CS conf to initialize
+ *
+ * Set all fields to 0 so that one can start defining a new config.
+ */
+void atmel_smc_cs_conf_init(struct atmel_smc_cs_conf *conf)
+{
+ memset(conf, 0, sizeof(*conf));
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_init);
+
+/**
+ * atmel_smc_cs_encode_ncycles - encode a number of MCK clk cycles in the
+ * format expected by the SMC engine
+ * @ncycles: number of MCK clk cycles
+ * @msbpos: position of the MSB part of the timing field
+ * @msbwidth: width of the MSB part of the timing field
+ * @msbfactor: factor applied to the MSB
+ * @encodedval: param used to store the encoding result
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Setup/Pulse/Cycle/Timings Register"). This is a generic
+ * helper which called with different parameter depending on the encoding
+ * scheme.
+ *
+ * If the @ncycles value is too big to be encoded, -ERANGE is returned and
+ * the encodedval is contains the maximum val. Otherwise, 0 is returned.
+ */
+static int atmel_smc_cs_encode_ncycles(unsigned int ncycles,
+ unsigned int msbpos,
+ unsigned int msbwidth,
+ unsigned int msbfactor,
+ unsigned int *encodedval)
+{
+ unsigned int lsbmask = GENMASK(msbpos - 1, 0);
+ unsigned int msbmask = GENMASK(msbwidth - 1, 0);
+ unsigned int msb, lsb;
+ int ret = 0;
+
+ msb = ncycles / msbfactor;
+ lsb = ncycles % msbfactor;
+
+ if (lsb > lsbmask) {
+ lsb = 0;
+ msb++;
+ }
+
+ /*
+ * Let's just put the maximum we can if the requested setting does
+ * not fit in the register field.
+ * We still return -ERANGE in case the caller cares.
+ */
+ if (msb > msbmask) {
+ msb = msbmask;
+ lsb = lsbmask;
+ ret = -ERANGE;
+ }
+
+ *encodedval = (msb << msbpos) | lsb;
+
+ return ret;
+}
+
+/**
+ * atmel_smc_cs_conf_set_timing - set the SMC CS conf Txx parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the Txx field in the TIMINGS register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this Txx
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Timings Register"), and then stores the result in the
+ * @conf->timings field at @shift position.
+ *
+ * Returns -EINVAL if shift is invalid, -ERANGE if ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_timing(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_HSMC_TIMINGS_TCLR_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TADL_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TAR_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TRR_SHIFT &&
+ shift != ATMEL_HSMC_TIMINGS_TWB_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "HSMC Timings
+ * Register"):
+ *
+ * ncycles = (Txx[3] * 64) + Txx[2:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 3, 1, 64, &val);
+ conf->timings &= ~GENMASK(shift + 3, shift);
+ conf->timings |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_timing);
+
+/**
+ * atmel_smc_cs_conf_set_setup - set the SMC CS conf xx_SETUP parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_SETUP field in the SETUP register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_SETUP
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Setup Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_setup(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
+ shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "SMC Setup
+ * Register"):
+ *
+ * ncycles = (128 * xx_SETUP[5]) + xx_SETUP[4:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 5, 1, 128, &val);
+ conf->setup &= ~GENMASK(shift + 7, shift);
+ conf->setup |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_setup);
+
+/**
+ * atmel_smc_cs_conf_set_pulse - set the SMC CS conf xx_PULSE parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_PULSE field in the PULSE register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_PULSE
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Pulse Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_pulse(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NCS_WR_SHIFT &&
+ shift != ATMEL_SMC_NRD_SHIFT && shift != ATMEL_SMC_NCS_RD_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "SMC Pulse
+ * Register"):
+ *
+ * ncycles = (256 * xx_PULSE[6]) + xx_PULSE[5:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 6, 1, 256, &val);
+ conf->pulse &= ~GENMASK(shift + 7, shift);
+ conf->pulse |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_pulse);
+
+/**
+ * atmel_smc_cs_conf_set_cycle - set the SMC CS conf xx_CYCLE parameter to a
+ * specific value
+ * @conf: SMC CS conf descriptor
+ * @shift: the position of the xx_CYCLE field in the CYCLE register
+ * @ncycles: value (expressed in MCK clk cycles) to assign to this xx_CYCLE
+ * parameter
+ *
+ * This function encodes the @ncycles value as described in the datasheet
+ * (section "SMC Cycle Register"), and then stores the result in the
+ * @conf->setup field at @shift position.
+ *
+ * Returns -EINVAL if @shift is invalid, -ERANGE if @ncycles does not fit in
+ * the field, and 0 otherwise.
+ */
+int atmel_smc_cs_conf_set_cycle(struct atmel_smc_cs_conf *conf,
+ unsigned int shift, unsigned int ncycles)
+{
+ unsigned int val;
+ int ret;
+
+ if (shift != ATMEL_SMC_NWE_SHIFT && shift != ATMEL_SMC_NRD_SHIFT)
+ return -EINVAL;
+
+ /*
+ * The formula described in atmel datasheets (section "SMC Cycle
+ * Register"):
+ *
+ * ncycles = (xx_CYCLE[8:7] * 256) + xx_CYCLE[6:0]
+ */
+ ret = atmel_smc_cs_encode_ncycles(ncycles, 7, 2, 256, &val);
+ conf->cycle &= ~GENMASK(shift + 15, shift);
+ conf->cycle |= val << shift;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle);
+
+/**
+ * atmel_smc_cs_conf_apply - apply an SMC CS conf
+ * @regmap: the SMC regmap
+ * @cs: the CS id
+ * @conf: the SMC CS conf to apply
+ *
+ * Applies an SMC CS configuration.
+ * Only valid on at91sam9/avr32 SoCs.
+ */
+void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs,
+ const struct atmel_smc_cs_conf *conf)
+{
+ regmap_write(regmap, ATMEL_SMC_SETUP(cs), conf->setup);
+ regmap_write(regmap, ATMEL_SMC_PULSE(cs), conf->pulse);
+ regmap_write(regmap, ATMEL_SMC_CYCLE(cs), conf->cycle);
+ regmap_write(regmap, ATMEL_SMC_MODE(cs), conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply);
+
+/**
+ * atmel_hsmc_cs_conf_apply - apply an SMC CS conf
+ * @regmap: the HSMC regmap
+ * @cs: the CS id
+ * @layout: the layout of registers
+ * @conf: the SMC CS conf to apply
+ *
+ * Applies an SMC CS configuration.
+ * Only valid on post-sama5 SoCs.
+ */
+void atmel_hsmc_cs_conf_apply(struct regmap *regmap,
+ const struct atmel_hsmc_reg_layout *layout,
+ int cs, const struct atmel_smc_cs_conf *conf)
+{
+ regmap_write(regmap, ATMEL_HSMC_SETUP(layout, cs), conf->setup);
+ regmap_write(regmap, ATMEL_HSMC_PULSE(layout, cs), conf->pulse);
+ regmap_write(regmap, ATMEL_HSMC_CYCLE(layout, cs), conf->cycle);
+ regmap_write(regmap, ATMEL_HSMC_TIMINGS(layout, cs), conf->timings);
+ regmap_write(regmap, ATMEL_HSMC_MODE(layout, cs), conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply);
+
+/**
+ * atmel_smc_cs_conf_get - retrieve the current SMC CS conf
+ * @regmap: the SMC regmap
+ * @cs: the CS id
+ * @conf: the SMC CS conf object to store the current conf
+ *
+ * Retrieve the SMC CS configuration.
+ * Only valid on at91sam9/avr32 SoCs.
+ */
+void atmel_smc_cs_conf_get(struct regmap *regmap, int cs,
+ struct atmel_smc_cs_conf *conf)
+{
+ regmap_read(regmap, ATMEL_SMC_SETUP(cs), &conf->setup);
+ regmap_read(regmap, ATMEL_SMC_PULSE(cs), &conf->pulse);
+ regmap_read(regmap, ATMEL_SMC_CYCLE(cs), &conf->cycle);
+ regmap_read(regmap, ATMEL_SMC_MODE(cs), &conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get);
+
+/**
+ * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf
+ * @regmap: the HSMC regmap
+ * @cs: the CS id
+ * @layout: the layout of registers
+ * @conf: the SMC CS conf object to store the current conf
+ *
+ * Retrieve the SMC CS configuration.
+ * Only valid on post-sama5 SoCs.
+ */
+void atmel_hsmc_cs_conf_get(struct regmap *regmap,
+ const struct atmel_hsmc_reg_layout *layout,
+ int cs, struct atmel_smc_cs_conf *conf)
+{
+ regmap_read(regmap, ATMEL_HSMC_SETUP(layout, cs), &conf->setup);
+ regmap_read(regmap, ATMEL_HSMC_PULSE(layout, cs), &conf->pulse);
+ regmap_read(regmap, ATMEL_HSMC_CYCLE(layout, cs), &conf->cycle);
+ regmap_read(regmap, ATMEL_HSMC_TIMINGS(layout, cs), &conf->timings);
+ regmap_read(regmap, ATMEL_HSMC_MODE(layout, cs), &conf->mode);
+}
+EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_get);
+
+static const struct atmel_hsmc_reg_layout sama5d3_reg_layout = {
+ .timing_regs_offset = 0x600,
+};
+
+static const struct atmel_hsmc_reg_layout sama5d2_reg_layout = {
+ .timing_regs_offset = 0x700,
+};
+
+static const struct of_device_id atmel_smc_ids[] = {
+ { .compatible = "atmel,at91sam9260-smc", .data = NULL },
+ { .compatible = "atmel,sama5d3-smc", .data = &sama5d3_reg_layout },
+ { .compatible = "atmel,sama5d2-smc", .data = &sama5d2_reg_layout },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, atmel_smc_ids);
+
+/**
+ * atmel_hsmc_get_reg_layout - retrieve the layout of HSMC registers
+ * @np: the HSMC regmap
+ *
+ * Retrieve the layout of HSMC registers.
+ *
+ * Returns NULL in case of SMC, a struct atmel_hsmc_reg_layout pointer
+ * in HSMC case, otherwise ERR_PTR(-EINVAL).
+ */
+const struct atmel_hsmc_reg_layout *
+atmel_hsmc_get_reg_layout(struct device_node *np)
+{
+ const struct of_device_id *match;
+
+ match = of_match_node(atmel_smc_ids, np);
+
+ return match ? match->data : ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(atmel_hsmc_get_reg_layout);
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c
new file mode 100644
index 0000000000..bfd93902b4
--- /dev/null
+++ b/drivers/mfd/axp20x-i2c.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * I2C driver for the X-Powers' Power Management ICs
+ *
+ * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
+ * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as configurable GPIOs.
+ *
+ * This driver supports the I2C variants.
+ *
+ * Copyright (C) 2014 Carlo Caione
+ *
+ * Author: Carlo Caione <carlo@caione.org>
+ */
+
+#include <common.h>
+#include <of.h>
+#include <linux/err.h>
+#include <i2c/i2c.h>
+#include <module.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regmap.h>
+
+static int axp20x_i2c_probe(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct axp20x_dev *axp20x;
+ int ret;
+
+ axp20x = xzalloc(sizeof(*axp20x));
+
+ axp20x->dev = dev;
+
+ ret = axp20x_match_device(axp20x);
+ if (ret)
+ return ret;
+
+ axp20x->regmap = regmap_init_i2c(client, axp20x->regmap_cfg);
+ if (IS_ERR(axp20x->regmap))
+ return dev_err_probe(dev, PTR_ERR(axp20x->regmap),
+ "regmap init failed\n");
+
+ ret = axp20x_device_probe(axp20x);
+ if (ret)
+ return ret;
+
+ return regmap_register_cdev(axp20x->regmap, NULL);
+}
+
+static const struct of_device_id axp20x_i2c_of_match[] = {
+ { .compatible = "x-powers,axp152", .data = (void *)AXP152_ID },
+ { .compatible = "x-powers,axp202", .data = (void *)AXP202_ID },
+ { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
+ { .compatible = "x-powers,axp313a", .data = (void *)AXP313A_ID },
+ { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
+ { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
+ { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID },
+ { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
+ { },
+};
+MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match);
+
+static struct driver axp20x_i2c_driver = {
+ .name = "axp20x-i2c",
+ .probe = axp20x_i2c_probe,
+ .of_compatible = DRV_OF_COMPAT(axp20x_i2c_of_match),
+};
+
+coredevice_i2c_driver(axp20x_i2c_driver);
+
+MODULE_DESCRIPTION("PMIC MFD I2C driver for AXP20X");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
new file mode 100644
index 0000000000..666b9ea98c
--- /dev/null
+++ b/drivers/mfd/axp20x.c
@@ -0,0 +1,382 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MFD core driver for the X-Powers' Power Management ICs
+ *
+ * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
+ * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as configurable GPIOs.
+ *
+ * This file contains the interface independent core functions.
+ *
+ * Copyright (C) 2014 Carlo Caione
+ *
+ * Author: Carlo Caione <carlo@caione.org>
+ */
+
+#include <common.h>
+#include <linux/bitops.h>
+#include <clock.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/mfd/core.h>
+#include <module.h>
+#include <of.h>
+#include <of_device.h>
+#include <linux/regmap.h>
+#include <regulator.h>
+
+#define AXP20X_OFF BIT(7)
+
+#define AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE 0
+#define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4)
+
+static const char * const axp20x_model_names[] = {
+ "AXP152",
+ "AXP202",
+ "AXP209",
+ "AXP221",
+ "AXP223",
+ "AXP288",
+ "AXP313A",
+ "AXP803",
+ "AXP806",
+ "AXP809",
+ "AXP813",
+};
+
+static const struct regmap_config axp152_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP152_PWM1_DUTY_CYCLE,
+};
+
+static const struct regmap_config axp20x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP20X_OCV(AXP20X_OCV_MAX),
+};
+
+static const struct regmap_config axp22x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP22X_BATLOW_THRES1,
+};
+
+static const struct regmap_config axp288_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP288_FG_TUNE5,
+};
+
+static const struct regmap_config axp313a_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP313A_POK_CONTROL,
+};
+
+static const struct regmap_config axp806_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AXP806_REG_ADDR_EXT,
+};
+
+static const struct mfd_cell axp20x_cells[] = {
+ {
+ .name = "axp20x-gpio",
+ /* .of_compatible = "x-powers,axp209-gpio", */
+ }, {
+ .name = "axp20x-pek",
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp20x-adc",
+ /* .of_compatible = "x-powers,axp209-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp209-battery-power-supply", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp202-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp202-usb-power-supply", */
+ },
+};
+
+static const struct mfd_cell axp221_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp22x-adc",
+ /* .of_compatible = "x-powers,axp221-adc", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp221-ac-power-supply", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp221-battery-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp221-usb-power-supply", */
+ },
+};
+
+static const struct mfd_cell axp223_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp22x-adc",
+ /* .of_compatible = "x-powers,axp221-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp221-battery-power-supply", */
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp221-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp223-usb-power-supply", */
+ },
+};
+
+static const struct mfd_cell axp152_cells[] = {
+ {
+ .name = "axp20x-pek",
+ },
+ {
+ .name = "axp20x-regulator",
+ },
+};
+
+static const struct mfd_cell axp288_cells[] = {
+ {
+ .name = "axp288_adc",
+ }, {
+ .name = "axp288_extcon",
+ }, {
+ .name = "axp288_charger",
+ }, {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp288_pmic_acpi",
+ },
+};
+
+static const struct mfd_cell axp313a_cells[] = {
+ {
+ .name = "axp313a-regulator"
+ },
+};
+
+
+static const struct mfd_cell axp803_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-gpio",
+ /* .of_compatible = "x-powers,axp813-gpio", */
+ }, {
+ .name = "axp813-adc",
+ /* .of_compatible = "x-powers,axp813-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp813-battery-power-supply", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp813-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp813-usb-power-supply", */
+ },
+ { .name = "axp20x-regulator" },
+};
+
+static const struct mfd_cell axp806_cells[] = {
+ {
+ .name = "axp20x-regulator",
+ },
+};
+
+static const struct mfd_cell axp809_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-regulator",
+ },
+};
+
+static const struct mfd_cell axp813_cells[] = {
+ {
+ .name = "axp221-pek",
+ }, {
+ .name = "axp20x-regulator",
+ }, {
+ .name = "axp20x-gpio",
+ /* .of_compatible = "x-powers,axp813-gpio", */
+ }, {
+ .name = "axp813-adc",
+ /* .of_compatible = "x-powers,axp813-adc", */
+ }, {
+ .name = "axp20x-battery-power-supply",
+ /* .of_compatible = "x-powers,axp813-battery-power-supply", */
+ }, {
+ .name = "axp20x-ac-power-supply",
+ /* .of_compatible = "x-powers,axp813-ac-power-supply", */
+ }, {
+ .name = "axp20x-usb-power-supply",
+ /* .of_compatible = "x-powers,axp813-usb-power-supply", */
+ },
+};
+
+static void axp20x_power_off(struct poweroff_handler *handler)
+{
+ struct axp20x_dev *axp20x = container_of(handler, struct axp20x_dev, poweroff);
+
+ regmap_write(axp20x->regmap, AXP20X_OFF_CTRL, AXP20X_OFF);
+
+ shutdown_barebox();
+
+ /* Give capacitors etc. time to drain to avoid kernel panic msg. */
+ mdelay(500);
+ hang();
+}
+
+int axp20x_match_device(struct axp20x_dev *axp20x)
+{
+ struct device *dev = axp20x->dev;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_device(dev->driver->of_compatible, dev);
+ if (!of_id) {
+ dev_err(dev, "Unable to match OF ID\n");
+ return -ENODEV;
+ }
+ axp20x->variant = (long)of_id->data;
+
+ switch (axp20x->variant) {
+ case AXP152_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp152_cells);
+ axp20x->cells = axp152_cells;
+ axp20x->regmap_cfg = &axp152_regmap_config;
+ break;
+ case AXP202_ID:
+ case AXP209_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
+ axp20x->cells = axp20x_cells;
+ axp20x->regmap_cfg = &axp20x_regmap_config;
+ break;
+ case AXP221_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp221_cells);
+ axp20x->cells = axp221_cells;
+ axp20x->regmap_cfg = &axp22x_regmap_config;
+ break;
+ case AXP223_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp223_cells);
+ axp20x->cells = axp223_cells;
+ axp20x->regmap_cfg = &axp22x_regmap_config;
+ break;
+ case AXP288_ID:
+ axp20x->cells = axp288_cells;
+ axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ break;
+ case AXP313A_ID:
+ axp20x->cells = axp313a_cells;
+ axp20x->nr_cells = ARRAY_SIZE(axp313a_cells);
+ axp20x->regmap_cfg = &axp313a_regmap_config;
+ break;
+ case AXP803_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp803_cells);
+ axp20x->cells = axp803_cells;
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ break;
+ case AXP806_ID:
+ /*
+ * Don't register the power key part if in slave mode or
+ * if there is no interrupt line.
+ */
+ axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
+ axp20x->cells = axp806_cells;
+ axp20x->regmap_cfg = &axp806_regmap_config;
+ break;
+ case AXP809_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp809_cells);
+ axp20x->cells = axp809_cells;
+ axp20x->regmap_cfg = &axp22x_regmap_config;
+ break;
+ case AXP813_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp813_cells);
+ axp20x->cells = axp813_cells;
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ break;
+ default:
+ dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
+ return -EINVAL;
+ }
+ dev_info(dev, "AXP20x variant %s found\n",
+ axp20x_model_names[axp20x->variant]);
+
+ return 0;
+}
+EXPORT_SYMBOL(axp20x_match_device);
+
+int axp20x_device_probe(struct axp20x_dev *axp20x)
+{
+ int ret;
+
+ /*
+ * The AXP806 supports either master/standalone or slave mode.
+ * Slave mode allows sharing the serial bus, even with multiple
+ * AXP806 which all have the same hardware address.
+ *
+ * This is done with extra "serial interface address extension",
+ * or AXP806_BUS_ADDR_EXT, and "register address extension", or
+ * AXP806_REG_ADDR_EXT, registers. The former is read-only, with
+ * 1 bit customizable at the factory, and 1 bit depending on the
+ * state of an external pin. The latter is writable. The device
+ * will only respond to operations to its other registers when
+ * the these device addressing bits (in the upper 4 bits of the
+ * registers) match.
+ *
+ * By default we support an AXP806 chained to an AXP809 in slave
+ * mode. Boards which use an AXP806 in master mode can set the
+ * property "x-powers,master-mode" to override the default.
+ */
+ if (axp20x->variant == AXP806_ID) {
+ if (of_property_read_bool(axp20x->dev->of_node,
+ "x-powers,master-mode") ||
+ of_property_read_bool(axp20x->dev->of_node,
+ "x-powers,self-working-mode"))
+ regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+ AXP806_REG_ADDR_EXT_ADDR_MASTER_MODE);
+ else
+ regmap_write(axp20x->regmap, AXP806_REG_ADDR_EXT,
+ AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE);
+ }
+
+ axp20x->dev->priv = axp20x;
+
+ ret = mfd_add_devices(axp20x->dev, axp20x->cells, axp20x->nr_cells);
+ if (ret)
+ return dev_err_probe(axp20x->dev, ret, "failed to add MFD devices\n");
+
+
+ axp20x->poweroff.name = "axp20x-poweroff";
+ axp20x->poweroff.poweroff = axp20x_power_off;
+ axp20x->poweroff.priority = 200;
+
+ if (!(axp20x->variant == AXP288_ID) || (axp20x->variant == AXP313A_ID))
+ poweroff_handler_register(&axp20x->poweroff);
+
+ return 0;
+}
+EXPORT_SYMBOL(axp20x_device_probe);
+
+MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/core.c b/drivers/mfd/core.c
new file mode 100644
index 0000000000..0868bbb905
--- /dev/null
+++ b/drivers/mfd/core.c
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <linux/mfd/core.h>
+#include <driver.h>
+
+int mfd_add_devices(struct device *parent, const struct mfd_cell *cells,
+ int n_devs)
+{
+ struct device *dev;
+ int ret, i;
+
+ for (i = 0; i < n_devs; i++) {
+ dev = device_alloc(cells[i].name, DEVICE_ID_DYNAMIC);
+ dev->parent = parent;
+
+ ret = device_add_data(dev, &cells[i], sizeof(cells[i]));
+ if (ret)
+ return ret;
+
+ ret = platform_device_register(dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c
index 99827c9689..cbfb62cef9 100644
--- a/drivers/mfd/da9053.c
+++ b/drivers/mfd/da9053.c
@@ -77,7 +77,7 @@
struct da9053_priv {
struct watchdog wd;
struct i2c_client *client;
- struct device_d *dev;
+ struct device *dev;
struct restart_handler restart;
};
@@ -137,7 +137,7 @@ static int da9053_enable_multiwrite(struct da9053_priv *da9053)
static int da9053_set_timeout(struct watchdog *wd, unsigned timeout)
{
struct da9053_priv *da9053 = wd_to_da9053_priv(wd);
- struct device_d *dev = da9053->dev;
+ struct device *dev = da9053->dev;
unsigned scale = 0;
int ret;
u8 val;
@@ -251,7 +251,7 @@ static void __noreturn da9053_force_system_reset(struct restart_handler *rst)
hang();
}
-static int da9053_probe(struct device_d *dev)
+static int da9053_probe(struct device *dev)
{
struct da9053_priv *da9053;
int ret;
@@ -272,7 +272,7 @@ static int da9053_probe(struct device_d *dev)
da9053_detect_reset_source(da9053);
- da9053->restart.priority = of_get_restart_priority(dev->device_node);
+ da9053->restart.of_node = dev->of_node;
da9053->restart.name = "da9063";
da9053->restart.restart = &da9053_force_system_reset;
@@ -288,8 +288,9 @@ static __maybe_unused struct of_device_id da9053_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, da9053_dt_ids);
-static struct driver_d da9053_driver = {
+static struct driver da9053_driver = {
.name = DRIVERNAME,
.probe = da9053_probe,
.of_compatible = DRV_OF_COMPAT(da9053_dt_ids),
diff --git a/drivers/mfd/da9063.c b/drivers/mfd/da9063.c
index a4e5226f3c..04bcad8804 100644
--- a/drivers/mfd/da9063.c
+++ b/drivers/mfd/da9063.c
@@ -22,7 +22,7 @@ struct da9063 {
struct i2c_client *client;
/* dummy client for accessing bank #1 */
struct i2c_client *client1;
- struct device_d *dev;
+ struct device *dev;
unsigned int timeout;
uint64_t last_ping;
};
@@ -253,7 +253,7 @@ static int da9063_watchdog_ping(struct da9063 *priv)
static int da9063_watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
{
struct da9063 *priv = container_of(wd, struct da9063, wd);
- struct device_d *dev = priv->dev;
+ struct device *dev = priv->dev;
unsigned int scale = 0;
int ret;
@@ -356,7 +356,7 @@ static struct da906x_device_data const da9062_device_data = {
.init = da9062_device_init,
};
-static int da9063_probe(struct device_d *dev)
+static int da9063_probe(struct device *dev)
{
struct da9063 *priv = NULL;
struct da906x_device_data const *dev_data;
@@ -383,7 +383,7 @@ static int da9063_probe(struct device_d *dev)
da9063_detect_reset_source(priv);
- priv->restart.priority = of_get_restart_priority(dev->device_node);
+ priv->restart.of_node = dev->of_node;
priv->restart.name = "da9063";
priv->restart.restart = &da9063_restart;
@@ -399,8 +399,8 @@ static int da9063_probe(struct device_d *dev)
goto on_error;
}
- if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node)
- return of_platform_populate(dev->device_node, NULL, dev);
+ if (IS_ENABLED(CONFIG_OFDEVICE) && dev->of_node)
+ return of_platform_populate(dev->of_node, NULL, dev);
return 0;
@@ -426,8 +426,9 @@ static struct of_device_id const da906x_dt_ids[] = {
}, {
}
};
+MODULE_DEVICE_TABLE(of, da906x_dt_ids);
-static struct driver_d da9063_driver = {
+static struct driver da9063_driver = {
.name = "da9063",
.probe = da9063_probe,
.id_table = da9063_id,
diff --git a/drivers/mfd/lp3972.c b/drivers/mfd/lp3972.c
index 934c4fe038..d72f697da5 100644
--- a/drivers/mfd/lp3972.c
+++ b/drivers/mfd/lp3972.c
@@ -63,7 +63,7 @@ static struct cdev_operations lp_fops = {
.read = lp_read,
};
-static int lp_probe(struct device_d *dev)
+static int lp_probe(struct device *dev)
{
if (lp_dev)
return -EBUSY;
@@ -80,7 +80,7 @@ static int lp_probe(struct device_d *dev)
return 0;
}
-static struct driver_d lp_driver = {
+static struct driver lp_driver = {
.name = DRIVERNAME,
.probe = lp_probe,
};
diff --git a/drivers/mfd/mc13xxx.c b/drivers/mfd/mc13xxx.c
index 1851950406..1e06a24b45 100644
--- a/drivers/mfd/mc13xxx.c
+++ b/drivers/mfd/mc13xxx.c
@@ -11,7 +11,7 @@
#include <errno.h>
#include <malloc.h>
#include <of.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <i2c/i2c.h>
#include <spi/spi.h>
@@ -22,7 +22,7 @@
#define MC13XXX_NUMREGS 0x3f
struct mc13xxx {
- struct device_d *dev;
+ struct device *dev;
struct regmap *map;
union {
struct i2c_client *client;
@@ -300,7 +300,7 @@ static const struct regmap_config mc13xxx_regmap_i2c_config = {
};
#endif
-static int __init mc13xxx_probe(struct device_d *dev)
+static int __init mc13xxx_probe(struct device *dev)
{
struct mc13xxx_devtype *devtype;
int ret, rev;
@@ -353,7 +353,7 @@ static int __init mc13xxx_probe(struct device_d *dev)
if (mc13xxx_init_callback)
mc13xxx_init_callback(mc_dev);
- if (of_property_read_bool(dev->device_node, "fsl,mc13xxx-uses-adc"))
+ if (of_property_read_bool(dev->of_node, "fsl,mc13xxx-uses-adc"))
mc13xxx_adc_probe(dev, mc_dev);
return 0;
@@ -387,8 +387,9 @@ static __maybe_unused struct of_device_id mc13xxx_dt_ids[] = {
{ .compatible = "fsl,mc34708", .data = &mc34708_devtype, },
{ }
};
+MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
-static __maybe_unused struct driver_d mc13xxx_i2c_driver = {
+static __maybe_unused struct driver mc13xxx_i2c_driver = {
.name = "mc13xxx-i2c",
.probe = mc13xxx_probe,
.id_table = mc13xxx_ids,
@@ -399,7 +400,7 @@ static __maybe_unused struct driver_d mc13xxx_i2c_driver = {
coredevice_i2c_driver(mc13xxx_i2c_driver);
#endif
-static __maybe_unused struct driver_d mc13xxx_spi_driver = {
+static __maybe_unused struct driver mc13xxx_spi_driver = {
.name = "mc13xxx-spi",
.probe = mc13xxx_probe,
.id_table = mc13xxx_ids,
diff --git a/drivers/mfd/mc34704.c b/drivers/mfd/mc34704.c
index 732542e34f..7a893ef8b7 100644
--- a/drivers/mfd/mc34704.c
+++ b/drivers/mfd/mc34704.c
@@ -93,7 +93,7 @@ static struct cdev_operations mc34704_fops = {
.write = mc34704_write,
};
-static int mc34704_probe(struct device_d *dev)
+static int mc34704_probe(struct device *dev)
{
if (mc34704_dev)
return -EBUSY;
@@ -114,8 +114,9 @@ static __maybe_unused struct of_device_id mc34704_dt_ids[] = {
{ .compatible = "fsl,mc34704", },
{ }
};
+MODULE_DEVICE_TABLE(of, mc34704_dt_ids);
-static struct driver_d mc34704_driver = {
+static struct driver mc34704_driver = {
.name = DRIVERNAME,
.probe = mc34704_probe,
.of_compatible = DRV_OF_COMPAT(mc34704_dt_ids),
diff --git a/drivers/mfd/mc9sdz60.c b/drivers/mfd/mc9sdz60.c
index f55733dae9..1f8a5611b4 100644
--- a/drivers/mfd/mc9sdz60.c
+++ b/drivers/mfd/mc9sdz60.c
@@ -105,7 +105,7 @@ static struct cdev_operations mc_fops = {
.write = mc_write,
};
-static int mc_probe(struct device_d *dev)
+static int mc_probe(struct device *dev)
{
if (mc_dev)
return -EBUSY;
@@ -122,7 +122,7 @@ static int mc_probe(struct device_d *dev)
return 0;
}
-static struct driver_d mc_driver = {
+static struct driver mc_driver = {
.name = DRIVERNAME,
.probe = mc_probe,
};
diff --git a/drivers/mfd/pca9450.c b/drivers/mfd/pca9450.c
new file mode 100644
index 0000000000..8fa5363f8a
--- /dev/null
+++ b/drivers/mfd/pca9450.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2023 Holger Assmann, Pengutronix
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <i2c/i2c.h>
+#include <init.h>
+#include <mfd/pca9450.h>
+#include <of.h>
+#include <regmap.h>
+#include <reset_source.h>
+
+#define REASON_PMIC_RST 0x10
+#define REASON_SW_RST 0x20
+#define REASON_WDOG 0x40
+#define REASON_PWON 0x80
+
+static const struct regmap_config pca9450_regmap_i2c_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x2E,
+};
+
+static int pca9450_get_reset_source(struct device *dev, struct regmap *map)
+{
+ enum reset_src_type type;
+ int reg;
+ int ret;
+
+ ret = regmap_read(map, PCA9450_PWRON_STAT, &reg);
+ if (ret)
+ return ret;
+
+ switch (reg) {
+ case REASON_PWON:
+ dev_dbg(dev, "Power ON triggered by PMIC_ON_REQ.\n");
+ type = RESET_POR;
+ break;
+ case REASON_WDOG:
+ dev_dbg(dev, "Detected cold reset by WDOGB pin\n");
+ type = RESET_WDG;
+ break;
+ case REASON_SW_RST:
+ dev_dbg(dev, "Detected cold reset by SW_RST\n");
+ type = RESET_RST;
+ break;
+ case REASON_PMIC_RST:
+ dev_dbg(dev, "Detected cold reset by PMIC_RST_B\n");
+ type = RESET_EXT;
+ break;
+ default:
+ dev_warn(dev, "Could not determine reset reason.\n");
+ type = RESET_UKWN;
+ }
+
+ reset_source_set_device(dev, type);
+
+ return 0;
+};
+
+static struct regmap *pca9450_map;
+
+static void (*pca9450_init_callback)(struct regmap *map);
+
+int pca9450_register_init_callback(void(*callback)(struct regmap *map))
+{
+ if (pca9450_init_callback)
+ return -EBUSY;
+
+ pca9450_init_callback = callback;
+
+ if (pca9450_map)
+ pca9450_init_callback(pca9450_map);
+
+ return 0;
+}
+
+static int __init pca9450_probe(struct device *dev)
+{
+ struct regmap *regmap;
+ int reg;
+ int ret;
+
+ regmap = regmap_init_i2c(to_i2c_client(dev), &pca9450_regmap_i2c_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ ret = regmap_register_cdev(regmap, NULL);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(regmap, PCA9450_REG_DEV_ID, &reg);
+ if (ret) {
+ dev_err(dev, "Unable to read PMIC Chip ID\n");
+ return ret;
+ }
+
+ /* Chip ID defined in bits [7:4] */
+ dev_info(dev, "PMIC Chip ID: 0x%x\n", (reg >> 4));
+
+ if (pca9450_init_callback)
+ pca9450_init_callback(regmap);
+ pca9450_map = regmap;
+
+ pca9450_get_reset_source(dev,regmap);
+
+ return of_platform_populate(dev->of_node, NULL, dev);
+}
+
+static __maybe_unused struct of_device_id pca9450_dt_ids[] = {
+ { .compatible = "nxp,pca9450a" },
+ { .compatible = "nxp,pca9450c" },
+ { .compatible = "nxp,pca9451a" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pca9450_dt_ids);
+
+static struct driver pca9450_i2c_driver = {
+ .name = "pca9450-i2c",
+ .probe = pca9450_probe,
+ .of_compatible = DRV_OF_COMPAT(pca9450_dt_ids),
+};
+
+coredevice_i2c_driver(pca9450_i2c_driver);
diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c
index 30d4bde5dc..c7968b75f5 100644
--- a/drivers/mfd/rave-sp.c
+++ b/drivers/mfd/rave-sp.c
@@ -185,7 +185,7 @@ struct rave_sp_variant {
* @part_number_bootloader: Bootloader version
*/
struct rave_sp {
- struct device_d dev;
+ struct device dev;
struct serdev_device *serdev;
struct rave_sp_deframer deframer;
unsigned int ackid;
@@ -310,7 +310,7 @@ int rave_sp_exec(struct rave_sp *sp,
void *__data, size_t data_size,
void *reply_data, size_t reply_data_size)
{
- struct device_d *dev = sp->serdev->dev;
+ struct device *dev = sp->serdev->dev;
struct rave_sp_reply reply = {
.data = reply_data,
.length = reply_data_size,
@@ -366,7 +366,7 @@ static void rave_sp_receive_event(struct rave_sp *sp,
static void rave_sp_receive_reply(struct rave_sp *sp,
const unsigned char *data, size_t length)
{
- struct device_d *dev = sp->serdev->dev;
+ struct device *dev = sp->serdev->dev;
struct rave_sp_reply *reply;
const size_t payload_length = length - 2;
@@ -402,7 +402,7 @@ static void rave_sp_receive_frame(struct rave_sp *sp,
const size_t checksum_length = sp->variant->checksum->length;
const size_t payload_length = length - checksum_length;
const u8 *crc_reported = &data[payload_length];
- struct device_d *dev = sp->serdev->dev;
+ struct device *dev = sp->serdev->dev;
u8 crc_calculated[checksum_length];
print_hex_dump_debug("rave-sp rx: ", DUMP_PREFIX_NONE, 16, 1,
@@ -430,7 +430,7 @@ static void rave_sp_receive_frame(struct rave_sp *sp,
static int rave_sp_receive_buf(struct serdev_device *serdev,
const unsigned char *buf, size_t size)
{
- struct device_d *dev = serdev->dev;
+ struct device *dev = serdev->dev;
struct rave_sp *sp = dev->priv;
struct rave_sp_deframer *deframer = &sp->deframer;
const unsigned char *src = buf;
@@ -603,7 +603,7 @@ static int rave_sp_default_cmd_translate(enum rave_sp_command command)
}
}
-static const char *devm_rave_sp_version(struct device_d *dev,
+static const char *devm_rave_sp_version(struct device *dev,
struct rave_sp_version *version)
{
/*
@@ -666,7 +666,7 @@ static int rave_sp_emulated_get_status(struct rave_sp *sp,
static int rave_sp_get_status(struct rave_sp *sp)
{
- struct device_d *dev = sp->serdev->dev;
+ struct device *dev = sp->serdev->dev;
struct rave_sp_status status;
const char *mode;
int ret;
@@ -731,6 +731,7 @@ static const struct of_device_id __maybe_unused rave_sp_dt_ids[] = {
{ .compatible = "zii,rave-sp-rdu2", .data = &rave_sp_rdu2 },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, rave_sp_dt_ids);
static int rave_sp_req_ip_addr(struct param_d *p, void *context)
{
@@ -766,7 +767,7 @@ static int rave_sp_req_ip_addr(struct param_d *p, void *context)
static int rave_sp_add_params(struct rave_sp *sp)
{
- struct device_d *dev = &sp->dev;
+ struct device *dev = &sp->dev;
struct param_d *p;
int ret;
@@ -788,14 +789,14 @@ static int rave_sp_add_params(struct rave_sp *sp)
return PTR_ERR_OR_ZERO(p);
}
-static int rave_sp_probe(struct device_d *dev)
+static int rave_sp_probe(struct device *dev)
{
struct serdev_device *serdev = to_serdev_device(dev->parent);
struct rave_sp *sp;
u32 baud;
int ret;
- if (of_property_read_u32(dev->device_node, "current-speed", &baud)) {
+ if (of_property_read_u32(dev->of_node, "current-speed", &baud)) {
dev_err(dev,
"'current-speed' is not specified in device node\n");
return -EINVAL;
@@ -850,10 +851,10 @@ static int rave_sp_probe(struct device_d *dev)
return ret;
}
- return of_platform_populate(dev->device_node, NULL, dev);
+ return of_platform_populate(dev->of_node, NULL, dev);
}
-static struct driver_d rave_sp_drv = {
+static struct driver rave_sp_drv = {
.name = "rave-sp",
.probe = rave_sp_probe,
.of_compatible = DRV_OF_COMPAT(rave_sp_dt_ids),
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
new file mode 100644
index 0000000000..77493a7b5b
--- /dev/null
+++ b/drivers/mfd/rk808.c
@@ -0,0 +1,397 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MFD core driver for Rockchip RK808/RK818
+ *
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ * Author: Zhang Qing <zhangqing@rock-chips.com>
+ *
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov@phytec.de>
+ */
+
+#define pr_fmt(fmt) "rk808: " fmt
+
+#include <common.h>
+#include <i2c/i2c.h>
+#include <linux/mfd/rk808.h>
+#include <linux/mfd/core.h>
+#include <driver.h>
+#include <poweroff.h>
+#include <of.h>
+#include <linux/regmap.h>
+
+struct rk808_reg_data {
+ int addr;
+ int mask;
+ int value;
+};
+
+static const struct regmap_config rk818_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RK818_USB_CTRL_REG,
+};
+
+static const struct regmap_config rk805_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RK805_OFF_SOURCE_REG,
+};
+
+static const struct regmap_config rk808_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RK808_IO_POL_REG,
+};
+
+static const struct regmap_config rk817_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RK817_GPIO_INT_CFG,
+};
+
+static const struct mfd_cell rk805s[] = {
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
+ { .name = "rk805-pinctrl", },
+ { .name = "rk808-rtc", },
+ { .name = "rk805-pwrkey", },
+};
+
+static const struct mfd_cell rk808s[] = {
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
+ { .name = "rk808-rtc", },
+};
+
+static const struct mfd_cell rk817s[] = {
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
+ { .name = "rk805-pwrkey", },
+ { .name = "rk808-rtc", },
+ { .name = "rk817-codec", },
+};
+
+static const struct mfd_cell rk818s[] = {
+ { .name = "rk808-clkout", },
+ { .name = "rk808-regulator", },
+ { .name = "rk808-rtc", },
+};
+
+static const struct rk808_reg_data rk805_pre_init_reg[] = {
+ {RK805_BUCK1_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK,
+ RK805_BUCK1_2_ILMAX_4000MA},
+ {RK805_BUCK2_CONFIG_REG, RK805_BUCK1_2_ILMAX_MASK,
+ RK805_BUCK1_2_ILMAX_4000MA},
+ {RK805_BUCK3_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK,
+ RK805_BUCK3_ILMAX_3000MA},
+ {RK805_BUCK4_CONFIG_REG, RK805_BUCK3_4_ILMAX_MASK,
+ RK805_BUCK4_ILMAX_3500MA},
+ {RK805_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_400MA},
+ {RK805_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP115C},
+};
+
+static const struct rk808_reg_data rk808_pre_init_reg[] = {
+ { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA },
+ { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA },
+ { RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
+ { RK808_BUCK1_CONFIG_REG, BUCK1_RATE_MASK, BUCK_ILMIN_200MA },
+ { RK808_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_200MA },
+ { RK808_DCDC_UV_ACT_REG, BUCK_UV_ACT_MASK, BUCK_UV_ACT_DISABLE},
+ { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
+ VB_LO_SEL_3500MV },
+};
+
+static const struct rk808_reg_data rk817_pre_init_reg[] = {
+ {RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP},
+ /* Codec specific registers */
+ { RK817_CODEC_DTOP_VUCTL, MASK_ALL, 0x03 },
+ { RK817_CODEC_DTOP_VUCTIME, MASK_ALL, 0x00 },
+ { RK817_CODEC_DTOP_LPT_SRST, MASK_ALL, 0x00 },
+ { RK817_CODEC_DTOP_DIGEN_CLKE, MASK_ALL, 0x00 },
+ /* from vendor driver, CODEC_AREF_RTCFG0 not defined in data sheet */
+ { RK817_CODEC_AREF_RTCFG0, MASK_ALL, 0x00 },
+ { RK817_CODEC_AREF_RTCFG1, MASK_ALL, 0x06 },
+ { RK817_CODEC_AADC_CFG0, MASK_ALL, 0xc8 },
+ /* from vendor driver, CODEC_AADC_CFG1 not defined in data sheet */
+ { RK817_CODEC_AADC_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_VOLL, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_VOLR, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_SR_ACL0, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_ALC1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_ALC2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_NG, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_HPF, MASK_ALL, 0x00 },
+ { RK817_CODEC_DADC_RVOLL, MASK_ALL, 0xff },
+ { RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff },
+ { RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 },
+ { RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 },
+ { RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 },
+ /* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */
+ { RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 },
+ { RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 },
+ { RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 },
+ { RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 },
+ { RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff },
+ { RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff },
+ { RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 },
+ { RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 },
+ { RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 },
+ /* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */
+ { RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 },
+ { RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 },
+ { RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 },
+ { RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 },
+ { RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 },
+ { RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff },
+ { RK817_CODEC_DDAC_RVOLR, MASK_ALL, 0xff },
+ { RK817_CODEC_AHP_ANTI0, MASK_ALL, 0x00 },
+ { RK817_CODEC_AHP_ANTI1, MASK_ALL, 0x00 },
+ { RK817_CODEC_AHP_CFG0, MASK_ALL, 0xe0 },
+ { RK817_CODEC_AHP_CFG1, MASK_ALL, 0x1f },
+ { RK817_CODEC_AHP_CP, MASK_ALL, 0x09 },
+ { RK817_CODEC_ACLASSD_CFG1, MASK_ALL, 0x69 },
+ { RK817_CODEC_ACLASSD_CFG2, MASK_ALL, 0x44 },
+ { RK817_CODEC_APLL_CFG0, MASK_ALL, 0x04 },
+ { RK817_CODEC_APLL_CFG1, MASK_ALL, 0x00 },
+ { RK817_CODEC_APLL_CFG2, MASK_ALL, 0x30 },
+ { RK817_CODEC_APLL_CFG3, MASK_ALL, 0x19 },
+ { RK817_CODEC_APLL_CFG4, MASK_ALL, 0x65 },
+ { RK817_CODEC_APLL_CFG5, MASK_ALL, 0x01 },
+ { RK817_CODEC_DI2S_CKM, MASK_ALL, 0x01 },
+ { RK817_CODEC_DI2S_RSD, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_RXCR1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_RXCR2, MASK_ALL, 0x17 },
+ { RK817_CODEC_DI2S_RXCMD_TSD, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_TXCR1, MASK_ALL, 0x00 },
+ { RK817_CODEC_DI2S_TXCR2, MASK_ALL, 0x17 },
+ { RK817_CODEC_DI2S_TXCR3_TXCMD, MASK_ALL, 0x00 },
+ {RK817_GPIO_INT_CFG, RK817_INT_POL_MSK, RK817_INT_POL_L},
+ {RK817_SYS_CFG(1), RK817_HOTDIE_TEMP_MSK | RK817_TSD_TEMP_MSK,
+ RK817_HOTDIE_105 | RK817_TSD_140},
+};
+
+static const struct rk808_reg_data rk818_pre_init_reg[] = {
+ /* improve efficiency */
+ { RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_250MA },
+ { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA },
+ { RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
+ { RK818_USB_CTRL_REG, RK818_USB_ILIM_SEL_MASK,
+ RK818_USB_ILMIN_2000MA },
+ /* close charger when usb lower then 3.4V */
+ { RK818_USB_CTRL_REG, RK818_USB_CHG_SD_VSEL_MASK,
+ (0x7 << 4) },
+ /* no action when vref */
+ { RK818_H5V_EN_REG, BIT(1), RK818_REF_RDY_CTRL },
+ /* enable HDMI 5V */
+ { RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN },
+ { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
+ VB_LO_SEL_3500MV },
+};
+
+static void rk808_poweroff(struct poweroff_handler *handler)
+{
+ struct rk808 *rk808 = container_of(handler, struct rk808, poweroff);
+ int ret;
+ unsigned int reg, bit;
+
+ switch (rk808->variant) {
+ case RK805_ID:
+ reg = RK805_DEV_CTRL_REG;
+ bit = DEV_OFF;
+ break;
+ case RK808_ID:
+ reg = RK808_DEVCTRL_REG,
+ bit = DEV_OFF_RST;
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ reg = RK817_SYS_CFG(3);
+ bit = DEV_OFF;
+ break;
+ case RK818_ID:
+ reg = RK818_DEVCTRL_REG;
+ bit = DEV_OFF;
+ break;
+ default:
+ return;
+ }
+
+ shutdown_barebox();
+
+ ret = regmap_update_bits(rk808->regmap, reg, bit, bit);
+ if (ret)
+ pr_err("Failed to shutdown device!\n");
+
+ mdelay(1000);
+ hang();
+}
+
+static int rk808_probe(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct device_node *np = dev->of_node;
+ struct rk808 *rk808;
+ const struct rk808_reg_data *pre_init_reg;
+ const struct mfd_cell *cells;
+ int nr_pre_init_regs;
+ int nr_cells;
+ int msb, lsb;
+ unsigned char pmic_id_msb, pmic_id_lsb;
+ int ret;
+ int i;
+
+ rk808 = kzalloc(sizeof(*rk808), GFP_KERNEL);
+ if (!rk808)
+ return -ENOMEM;
+
+ dev->priv = rk808;
+
+ if (of_device_is_compatible(np, "rockchip,rk817") ||
+ of_device_is_compatible(np, "rockchip,rk809")) {
+ pmic_id_msb = RK817_ID_MSB;
+ pmic_id_lsb = RK817_ID_LSB;
+ } else {
+ pmic_id_msb = RK808_ID_MSB;
+ pmic_id_lsb = RK808_ID_LSB;
+ }
+
+ /* Read chip variant */
+ msb = i2c_smbus_read_byte_data(client, pmic_id_msb);
+ if (msb < 0) {
+ dev_err(dev, "failed to read the chip id at 0x%x\n",
+ RK808_ID_MSB);
+ return msb;
+ }
+
+ lsb = i2c_smbus_read_byte_data(client, pmic_id_lsb);
+ if (lsb < 0) {
+ dev_err(dev, "failed to read the chip id at 0x%x\n",
+ RK808_ID_LSB);
+ return lsb;
+ }
+
+ rk808->variant = ((msb << 8) | lsb) & RK8XX_ID_MSK;
+ dev_info(dev, "chip id: 0x%x\n", (unsigned int)rk808->variant);
+
+ switch (rk808->variant) {
+ case RK805_ID:
+ rk808->regmap_cfg = &rk805_regmap_config;
+ pre_init_reg = rk805_pre_init_reg;
+ nr_pre_init_regs = ARRAY_SIZE(rk805_pre_init_reg);
+ cells = rk805s;
+ nr_cells = ARRAY_SIZE(rk805s);
+ break;
+ case RK808_ID:
+ rk808->regmap_cfg = &rk808_regmap_config;
+ pre_init_reg = rk808_pre_init_reg;
+ nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
+ cells = rk808s;
+ nr_cells = ARRAY_SIZE(rk808s);
+ break;
+ case RK818_ID:
+ rk808->regmap_cfg = &rk818_regmap_config;
+ pre_init_reg = rk818_pre_init_reg;
+ nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
+ cells = rk818s;
+ nr_cells = ARRAY_SIZE(rk818s);
+ break;
+ case RK809_ID:
+ case RK817_ID:
+ rk808->regmap_cfg = &rk817_regmap_config;
+ pre_init_reg = rk817_pre_init_reg;
+ nr_pre_init_regs = ARRAY_SIZE(rk817_pre_init_reg);
+ cells = rk817s;
+ nr_cells = ARRAY_SIZE(rk817s);
+ break;
+ default:
+ dev_err(dev, "Unsupported RK8XX ID %lu\n",
+ rk808->variant);
+ return -EINVAL;
+ }
+
+ rk808->i2c = client;
+ i2c_set_clientdata(client, rk808);
+
+ rk808->regmap = regmap_init_i2c_smbus(client, rk808->regmap_cfg);
+ if (IS_ERR(rk808->regmap)) {
+ dev_err(dev, "regmap initialization failed\n");
+ return PTR_ERR(rk808->regmap);
+ }
+
+ ret = regmap_register_cdev(rk808->regmap, NULL);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nr_pre_init_regs; i++) {
+ ret = regmap_update_bits(rk808->regmap,
+ pre_init_reg[i].addr,
+ pre_init_reg[i].mask,
+ pre_init_reg[i].value);
+ if (ret) {
+ dev_err(dev,
+ "0x%x write err\n",
+ pre_init_reg[i].addr);
+ return ret;
+ }
+ }
+
+ ret = mfd_add_devices(dev, cells, nr_cells);
+ if (ret) {
+ dev_err(dev, "failed to add MFD devices %d\n", ret);
+ return ret;
+ }
+
+ rk808->poweroff.name = "stpmic1-poweroff";
+ rk808->poweroff.poweroff = rk808_poweroff;
+ rk808->poweroff.priority = 200;
+
+ if (of_property_read_bool(np, "rockchip,system-power-controller"))
+ rk808->poweroff.priority += 100;
+
+ poweroff_handler_register(&rk808->poweroff);
+ return 0;
+}
+
+static const struct of_device_id rk808_of_match[] = {
+ { .compatible = "rockchip,rk805" },
+ { .compatible = "rockchip,rk808" },
+ { .compatible = "rockchip,rk809" },
+ { .compatible = "rockchip,rk817" },
+ { .compatible = "rockchip,rk818" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rk808_of_match);
+
+static struct driver rk808_i2c_driver = {
+ .name = "rk808",
+ .of_compatible = rk808_of_match,
+ .probe = rk808_probe,
+};
+coredevice_i2c_driver(rk808_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
+MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
+MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
+MODULE_DESCRIPTION("RK808/RK818 PMIC driver");
diff --git a/drivers/mfd/rn5t568.c b/drivers/mfd/rn5t568.c
index c1c792cbec..f1e2eeb0c8 100644
--- a/drivers/mfd/rn5t568.c
+++ b/drivers/mfd/rn5t568.c
@@ -13,32 +13,10 @@
#include <i2c/i2c.h>
#include <init.h>
#include <of.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <reset_source.h>
#include <restart.h>
-
-#define RN5T568_LSIVER 0x00
-#define RN5T568_OTPVER 0x01
-#define RN5T568_PONHIS 0x09
-# define RN5T568_PONHIS_ON_EXTINPON BIT(3)
-# define RN5T568_PONHIS_ON_REPWRPON BIT(1)
-# define RN5T568_PONHIS_ON_PWRONPON BIT(0)
-#define RN5T568_POFFHIS 0x0a
-# define RN5T568_POFFHIS_N_OEPOFF BIT(7)
-# define RN5T568_POFFHIS_DCLIMPOFF BIT(6)
-# define RN5T568_POFFHIS_WDGPOFF BIT(5)
-# define RN5T568_POFFHIS_CPUPOFF BIT(4)
-# define RN5T568_POFFHIS_IODETPOFF BIT(3)
-# define RN5T568_POFFHIS_VINDETPOFF BIT(2)
-# define RN5T568_POFFHIS_TSHUTPOFF BIT(1)
-# define RN5T568_POFFHIS_PWRONPOFF BIT(0)
-#define RN5T568_SLPCNT 0x0e
-# define RN5T568_SLPCNT_SWPPWROFF BIT(0)
-#define RN5T568_REPCNT 0x0f
-# define RN5T568_REPCNT_OFF_RESETO_16MS 0x30
-# define RN5T568_REPCNT_OFF_REPWRTIM_1000MS 0x06
-# define RN5T568_REPCNT_OFF_REPWRON BIT(0)
-#define RN5T568_MAX_REG 0xbc
+#include <mfd/rn5t568.h>
struct rn5t568 {
struct restart_handler restart;
@@ -52,7 +30,8 @@ static void rn5t568_restart(struct restart_handler *rst)
regmap_write(rn5t568->regmap, RN5T568_SLPCNT, RN5T568_SLPCNT_SWPPWROFF);
}
-static int rn5t568_reset_reason_detect(struct device_d *dev, struct regmap *regmap)
+static int rn5t568_reset_reason_detect(struct device *dev,
+ struct regmap *regmap)
{
unsigned int reg;
int ret;
@@ -111,7 +90,7 @@ static const struct regmap_config rn5t568_regmap_config = {
.max_register = RN5T568_MAX_REG,
};
-static int __init rn5t568_i2c_probe(struct device_d *dev)
+static int __init rn5t568_i2c_probe(struct device *dev)
{
struct rn5t568 *pmic_instance;
unsigned char reg[2];
@@ -138,7 +117,7 @@ static int __init rn5t568_i2c_probe(struct device_d *dev)
regmap_write(pmic_instance->regmap, RN5T568_REPCNT, RN5T568_REPCNT_OFF_RESETO_16MS |
RN5T568_REPCNT_OFF_REPWRTIM_1000MS | RN5T568_REPCNT_OFF_REPWRON);
- pmic_instance->restart.priority = of_get_restart_priority(dev->device_node);
+ pmic_instance->restart.of_node = dev->of_node;
pmic_instance->restart.name = "RN5T568";
pmic_instance->restart.restart = &rn5t568_restart;
restart_handler_register(&pmic_instance->restart);
@@ -148,15 +127,16 @@ static int __init rn5t568_i2c_probe(struct device_d *dev)
if (ret)
dev_warn(dev, "Failed to query reset reason\n");
- return of_platform_populate(dev->device_node, NULL, dev);
+ return of_platform_populate(dev->of_node, NULL, dev);
}
static __maybe_unused const struct of_device_id rn5t568_of_match[] = {
{ .compatible = "ricoh,rn5t568", .data = NULL, },
{ }
};
+MODULE_DEVICE_TABLE(of, rn5t568_of_match);
-static struct driver_d rn5t568_i2c_driver = {
+static struct driver rn5t568_i2c_driver = {
.name = "rn5t568-i2c",
.probe = rn5t568_i2c_probe,
.of_compatible = DRV_OF_COMPAT(rn5t568_of_match),
diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c
new file mode 100644
index 0000000000..e317a29ce5
--- /dev/null
+++ b/drivers/mfd/rohm-bd718x7.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+//
+// Copyright (C) 2018 ROHM Semiconductors
+//
+// ROHM BD71837MWV and BD71847MWV PMIC driver
+//
+// Datasheet for BD71837MWV available from
+// https://www.rohm.com/datasheet/BD71837MWV/bd71837mwv-e
+
+#include <common.h>
+#include <i2c/i2c.h>
+#include <mfd/bd71837.h>
+#include <linux/mfd/core.h>
+#include <driver.h>
+#include <poweroff.h>
+#include <of.h>
+#include <linux/regmap.h>
+
+static struct mfd_cell bd71837_mfd_cells[] = {
+ { .name = "gpio-keys", },
+ { .name = "bd71837-clk", },
+ { .name = "bd71837-pmic", },
+};
+
+static struct mfd_cell bd71847_mfd_cells[] = {
+ { .name = "gpio-keys", },
+ { .name = "bd71847-clk", },
+ { .name = "bd71847-pmic", },
+};
+
+static const struct regmap_config bd718xx_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = BD718XX_MAX_REGISTER - 1,
+};
+
+static int bd718xx_init_press_duration(struct regmap *regmap,
+ struct device *dev)
+{
+ u32 short_press_ms, long_press_ms;
+ u32 short_press_value, long_press_value;
+ int ret;
+
+ ret = of_property_read_u32(dev->of_node, "rohm,short-press-ms",
+ &short_press_ms);
+ if (!ret) {
+ short_press_value = min(15u, (short_press_ms + 250) / 500);
+ ret = regmap_update_bits(regmap, BD718XX_PWRONCONFIG0,
+ BD718XX_PWRBTN_PRESS_DURATION_MASK,
+ short_press_value);
+ if (ret) {
+ dev_err(dev, "Failed to init pwron short press\n");
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u32(dev->of_node, "rohm,long-press-ms",
+ &long_press_ms);
+ if (!ret) {
+ long_press_value = min(15u, (long_press_ms + 500) / 1000);
+ ret = regmap_update_bits(regmap, BD718XX_PWRONCONFIG1,
+ BD718XX_PWRBTN_PRESS_DURATION_MASK,
+ long_press_value);
+ if (ret) {
+ dev_err(dev, "Failed to init pwron long press\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int bd718xx_i2c_probe(struct device *dev)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct regmap *regmap;
+ int ret;
+ unsigned int chip_type;
+ struct mfd_cell *mfd;
+ int cells;
+
+ chip_type = (unsigned int)(uintptr_t)device_get_match_data(dev);
+ switch (chip_type) {
+ case ROHM_CHIP_TYPE_BD71837:
+ mfd = bd71837_mfd_cells;
+ cells = ARRAY_SIZE(bd71837_mfd_cells);
+ break;
+ case ROHM_CHIP_TYPE_BD71847:
+ mfd = bd71847_mfd_cells;
+ cells = ARRAY_SIZE(bd71847_mfd_cells);
+ break;
+ default:
+ dev_err(dev, "Unknown device type");
+ return -EINVAL;
+ }
+
+ regmap = regmap_init_i2c(i2c, &bd718xx_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "regmap initialization failed\n");
+ return PTR_ERR(regmap);
+ }
+
+ ret = bd718xx_init_press_duration(regmap, dev);
+ if (ret)
+ return ret;
+
+ ret = mfd_add_devices(dev, mfd, cells);
+ if (ret)
+ dev_err(dev, "Failed to create subdevices\n");
+
+ return regmap_register_cdev(regmap, NULL);
+}
+
+static const struct of_device_id bd718xx_of_match[] = {
+ {
+ .compatible = "rohm,bd71837",
+ .data = (void *)ROHM_CHIP_TYPE_BD71837,
+ },
+ {
+ .compatible = "rohm,bd71847",
+ .data = (void *)ROHM_CHIP_TYPE_BD71847,
+ },
+ {
+ .compatible = "rohm,bd71850",
+ .data = (void *)ROHM_CHIP_TYPE_BD71847,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(of, bd718xx_of_match);
+
+static struct driver bd718xx_i2c_driver = {
+ .name = "rohm-bd718x7",
+ .of_match_table = bd718xx_of_match,
+ .probe = bd718xx_i2c_probe,
+};
+coredevice_i2c_driver(bd718xx_i2c_driver);
+
+MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
+MODULE_DESCRIPTION("ROHM BD71837/BD71847 Power Management IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
index 4814c06a62..3b47800105 100644
--- a/drivers/mfd/stm32-timers.c
+++ b/drivers/mfd/stm32-timers.c
@@ -11,6 +11,7 @@
#include <io.h>
#include <linux/bitfield.h>
#include <linux/mfd/stm32-timers.h>
+#include <linux/regmap.h>
#include <of.h>
#include <linux/reset.h>
@@ -34,7 +35,7 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
regmap_write(ddata->regmap, TIM_ARR, 0x0);
}
-static int stm32_timers_probe(struct device_d *dev)
+static int stm32_timers_probe(struct device *dev)
{
struct stm32_timers *ddata;
struct resource *res;
@@ -58,15 +59,16 @@ static int stm32_timers_probe(struct device_d *dev)
dev->priv = ddata;
- return of_platform_populate(dev->device_node, NULL, dev);
+ return of_platform_populate(dev->of_node, NULL, dev);
}
static const struct of_device_id stm32_timers_of_match[] = {
{ .compatible = "st,stm32-timers", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, stm32_timers_of_match);
-static struct driver_d stm32_timers_driver = {
+static struct driver stm32_timers_driver = {
.name = "stm32-timers",
.probe = stm32_timers_probe,
.of_compatible = stm32_timers_of_match,
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index 37cf6b8b36..08dc48246e 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -95,17 +95,17 @@ static struct cdev_operations stmpe_fops = {
.write = stmpe_write,
};
-static struct stmpe_platform_data *stmpe_of_probe(struct device_d *dev)
+static struct stmpe_platform_data *stmpe_of_probe(struct device *dev)
{
struct stmpe_platform_data *pdata;
struct device_node *node;
- if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->device_node)
+ if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->of_node)
return NULL;
pdata = xzalloc(sizeof(*pdata));
- for_each_child_of_node(dev->device_node, node) {
+ for_each_child_of_node(dev->of_node, node) {
if (!strcmp(node->name, "stmpe_gpio")) {
pdata->blocks |= STMPE_BLOCK_GPIO;
}
@@ -114,7 +114,7 @@ static struct stmpe_platform_data *stmpe_of_probe(struct device_d *dev)
return pdata;
}
-static int stmpe_probe(struct device_d *dev)
+static int stmpe_probe(struct device *dev)
{
struct stmpe_platform_data *pdata = dev->platform_data;
struct stmpe *stmpe_dev;
@@ -156,7 +156,7 @@ static struct platform_device_id stmpe_i2c_id[] = {
{ }
};
-static struct driver_d stmpe_driver = {
+static struct driver stmpe_driver = {
.name = DRIVERNAME,
.probe = stmpe_probe,
.id_table = stmpe_i2c_id,
diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c
index 1de5afa2ef..9985673aa6 100644
--- a/drivers/mfd/stpmic1.c
+++ b/drivers/mfd/stpmic1.c
@@ -9,7 +9,7 @@
#include <i2c/i2c.h>
#include <init.h>
#include <of.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <linux/mfd/stpmic1.h>
static const struct regmap_config stpmic1_regmap_i2c_config = {
@@ -18,7 +18,7 @@ static const struct regmap_config stpmic1_regmap_i2c_config = {
.max_register = 0xB3,
};
-static int __init stpmic1_probe(struct device_d *dev)
+static int __init stpmic1_probe(struct device *dev)
{
struct regmap *regmap;
u32 reg;
@@ -39,15 +39,16 @@ static int __init stpmic1_probe(struct device_d *dev)
}
dev_info(dev, "PMIC Chip Version: 0x%x\n", reg);
- return of_platform_populate(dev->device_node, NULL, dev);
+ return of_platform_populate(dev->of_node, NULL, dev);
}
static __maybe_unused struct of_device_id stpmic1_dt_ids[] = {
{ .compatible = "st,stpmic1" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, stpmic1_dt_ids);
-static struct driver_d stpmic1_i2c_driver = {
+static struct driver stpmic1_i2c_driver = {
.name = "stpmic1-i2c",
.probe = stpmic1_probe,
.of_compatible = DRV_OF_COMPAT(stpmic1_dt_ids),
diff --git a/drivers/mfd/superio.c b/drivers/mfd/superio.c
index bfb2f15dd2..16d0bba450 100644
--- a/drivers/mfd/superio.c
+++ b/drivers/mfd/superio.c
@@ -7,11 +7,11 @@
#include <common.h>
#include <superio.h>
-#include <regmap.h>
+#include <linux/regmap.h>
-struct device_d *superio_func_add(struct superio_chip *siochip, const char *name)
+struct device *superio_func_add(struct superio_chip *siochip, const char *name)
{
- struct device_d *dev;
+ struct device *dev;
int ret;
dev = device_alloc(name, DEVICE_ID_DYNAMIC);
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index d0f2f0917e..3c2e1241fd 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -16,6 +16,7 @@
#include <of_address.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/regmap.h>
#include <mfd/syscon.h>
@@ -73,8 +74,6 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
syscon_config.val_bits = reg_io_width * 8;
syscon_config.max_register = resource_size(&res) - reg_io_width;
- list_add_tail(&syscon->list, &syscon_list);
-
syscon->regmap = regmap_init_mmio_clk(NULL, NULL, syscon->base,
&syscon_config);
@@ -92,6 +91,8 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
}
}
+ list_add_tail(&syscon->list, &syscon_list);
+
return syscon;
err_map:
@@ -142,21 +143,6 @@ static void __iomem *syscon_node_to_base(struct device_node *np)
return syscon->base;
}
-void __iomem *syscon_base_lookup_by_pdevname(const char *s)
-{
- struct syscon *syscon;
- struct device_d *dev;
-
- for_each_device(dev) {
- if (!strcmp(dev_name(dev), s)) {
- syscon = dev->priv;
- return syscon->base;
- }
- }
-
- return ERR_PTR(-ENODEV);
-}
-
void __iomem *syscon_base_lookup_by_phandle(struct device_node *np,
const char *property)
{
@@ -231,7 +217,7 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
return regmap;
}
-static int syscon_probe(struct device_d *dev)
+static int syscon_probe(struct device *dev)
{
struct syscon *syscon;
struct resource *res;
@@ -257,7 +243,7 @@ static struct platform_device_id syscon_ids[] = {
{ }
};
-static struct driver_d syscon_driver = {
+static struct driver syscon_driver = {
.name = "syscon",
.probe = syscon_probe,
.id_table = syscon_ids,
diff --git a/drivers/mfd/twl4030.c b/drivers/mfd/twl4030.c
index 072a49cb62..7acf9b18bd 100644
--- a/drivers/mfd/twl4030.c
+++ b/drivers/mfd/twl4030.c
@@ -26,7 +26,7 @@ struct twl4030 *twl4030_get(void)
}
EXPORT_SYMBOL(twl4030_get);
-static int twl_probe(struct device_d *dev)
+static int twl_probe(struct device *dev)
{
if (twl_dev)
return -EBUSY;
@@ -43,7 +43,7 @@ static int twl_probe(struct device_d *dev)
return 0;
}
-static struct driver_d twl_driver = {
+static struct driver twl_driver = {
.name = DRIVERNAME,
.probe = twl_probe,
};
diff --git a/drivers/mfd/twl6030.c b/drivers/mfd/twl6030.c
index 1ed0e25c3a..d7a7d9baf8 100644
--- a/drivers/mfd/twl6030.c
+++ b/drivers/mfd/twl6030.c
@@ -23,7 +23,7 @@ struct twl6030 *twl6030_get(void)
}
EXPORT_SYMBOL(twl6030_get);
-static int twl_probe(struct device_d *dev)
+static int twl_probe(struct device *dev)
{
if (twl_dev)
return -EBUSY;
@@ -61,7 +61,7 @@ static int twl_probe(struct device_d *dev)
return 0;
}
-static struct driver_d twl_driver = {
+static struct driver twl_driver = {
.name = DRIVERNAME,
.probe = twl_probe,
};