summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig73
-rw-r--r--drivers/mfd/Makefile11
-rw-r--r--drivers/mfd/act8846.c17
-rw-r--r--drivers/mfd/atmel-flexcom.c74
-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.c27
-rw-r--r--drivers/mfd/da9063.c48
-rw-r--r--drivers/mfd/fintek-superio.c2
-rw-r--r--drivers/mfd/lp3972.c17
-rw-r--r--drivers/mfd/mc13xxx.c53
-rw-r--r--drivers/mfd/mc34704.c22
-rw-r--r--drivers/mfd/mc9sdz60.c17
-rw-r--r--drivers/mfd/pca9450.c127
-rw-r--r--drivers/mfd/rave-sp.c44
-rw-r--r--drivers/mfd/rk808.c397
-rw-r--r--drivers/mfd/rn5t568.c145
-rw-r--r--drivers/mfd/rohm-bd718x7.c140
-rw-r--r--drivers/mfd/smsc-superio.c5
-rw-r--r--drivers/mfd/stm32-timers.c76
-rw-r--r--drivers/mfd/stmpe-i2c.c22
-rw-r--r--drivers/mfd/stpmic1.c63
-rw-r--r--drivers/mfd/superio.c15
-rw-r--r--drivers/mfd/syscon.c146
-rw-r--r--drivers/mfd/twl-core.c4
-rw-r--r--drivers/mfd/twl4030.c8
-rw-r--r--drivers/mfd/twl6030.c7
29 files changed, 2073 insertions, 323 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f4cc71ef0e..5189364c2c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1,4 +1,5 @@
-menu MFD
+# SPDX-License-Identifier: GPL-2.0-only
+menu "Multifunction device drivers"
config MFD_ACT8846
depends on I2C
@@ -63,23 +64,93 @@ 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.
+
config MFD_SUPERIO
bool
config FINTEK_SUPERIO
bool "Fintek Super I/O chip"
select MFD_SUPERIO
+ depends on X86 || COMPILE_TEST
help
Select this to probe for IO-port connected Fintek Super I/O chips.
config SMSC_SUPERIO
bool "SMSC Super I/O chip"
select MFD_SUPERIO
+ depends on X86 || COMPILE_TEST
help
Select this to probe for IO-port connected SMSC Super I/O chips.
+config MFD_STM32_TIMERS
+ bool "STM32 Timers"
+ depends on ARCH_STM32 || COMPILE_TEST
+ help
+ Select this to get regmap support for the timer blocks on STM32
+ MCUs and MPUs.
+
+config MFD_ATMEL_FLEXCOM
+ tristate "Atmel Flexcom (Flexible Serial Communication Unit)"
+ depends on OFDEVICE
+ help
+ Select this to get support for Atmel Flexcom. This is a wrapper
+ which embeds a SPI controller, a I2C controller and a USART. Only
+ one function can be used at a time. The choice is done at boot time
+ 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 0c24493e3d..00f3eacf3c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -1,3 +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
@@ -12,6 +15,14 @@ obj-$(CONFIG_MFD_TWL4030) += twl4030.o
obj-$(CONFIG_MFD_TWL6030) += twl6030.o
obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o
+obj-$(CONFIG_MFD_RN568PMIC) += rn5t568.o
obj-$(CONFIG_MFD_SUPERIO) += superio.o
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 b7a64c739c..f15310f507 100644
--- a/drivers/mfd/act8846.c
+++ b/drivers/mfd/act8846.c
@@ -1,20 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2007 Sascha Hauer, Pengutronix
* 2009 Marc Kleine-Budde <mkl@pengutronix.de>
*
* Copied from drivers/mfd/mc9sdz60.c
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -121,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;
@@ -138,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
new file mode 100644
index 0000000000..58e94c4889
--- /dev/null
+++ b/drivers/mfd/atmel-flexcom.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: (C) 2015 Atmel Corporation
+/*
+ * Driver for Atmel Flexcom
+ * Author: Cyrille Pitchen <cyrille.pitchen@atmel.com>
+ */
+
+#include <common.h>
+#include <of.h>
+#include <linux/clk.h>
+#include <dt-bindings/mfd/atmel-flexcom.h>
+
+/* I/O register offsets */
+#define FLEX_MR 0x0 /* Mode Register */
+#define FLEX_VERSION 0xfc /* Version Register */
+
+/* Mode Register bit fields */
+#define FLEX_MR_OPMODE_OFFSET (0) /* Operating Mode */
+#define FLEX_MR_OPMODE_MASK (0x3 << FLEX_MR_OPMODE_OFFSET)
+#define FLEX_MR_OPMODE(opmode) (((opmode) << FLEX_MR_OPMODE_OFFSET) & \
+ FLEX_MR_OPMODE_MASK)
+
+static int atmel_flexcom_probe(struct device *dev)
+{
+ struct resource *res;
+ struct clk *clk;
+ u32 opmode;
+ int err;
+
+ err = of_property_read_u32(dev->of_node,
+ "atmel,flexcom-mode", &opmode);
+ if (err)
+ return err;
+
+ if (opmode < ATMEL_FLEXCOM_MODE_USART || opmode > ATMEL_FLEXCOM_MODE_TWI)
+ return -EINVAL;
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ err = clk_enable(clk);
+ if (err)
+ return err;
+
+ /*
+ * Set the Operating Mode in the Mode Register: only the selected device
+ * is clocked. Hence, registers of the other serial devices remain
+ * inaccessible and are read as zero. Also the external I/O lines of the
+ * Flexcom are muxed to reach the selected device.
+ */
+ writel(FLEX_MR_OPMODE(opmode), IOMEM(res->start) + FLEX_MR);
+
+ clk_disable(clk);
+
+ 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 atmel_flexcom_driver = {
+ .probe = atmel_flexcom_probe,
+ .name = "atmel_flexcom",
+ .of_compatible = atmel_flexcom_of_match,
+};
+coredevice_platform_driver(atmel_flexcom_driver);
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 1faba813be..cbfb62cef9 100644
--- a/drivers/mfd/da9053.c
+++ b/drivers/mfd/da9053.c
@@ -1,17 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2013 Jan Luebbe <jlu@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -88,7 +77,7 @@
struct da9053_priv {
struct watchdog wd;
struct i2c_client *client;
- struct device_d *dev;
+ struct device *dev;
struct restart_handler restart;
};
@@ -148,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;
@@ -235,7 +224,7 @@ static void da9053_detect_reset_source(struct da9053_priv *da9053)
else
return;
- reset_source_set_device(da9053->dev, ltype);
+ reset_source_set_device(da9053->dev, type);
ret = da9053_reg_write(da9053, DA9053_FAULTLOG_REG, val);
if (ret < 0)
@@ -262,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;
@@ -271,7 +260,6 @@ static int da9053_probe(struct device_d *dev)
da9053->dev = dev;
da9053->client = to_i2c_client(dev);
da9053->wd.set_timeout = da9053_set_timeout;
- da9053->wd.priority = of_get_watchdog_priority(dev->device_node);
da9053->wd.hwdev = dev;
ret = da9053_enable_multiwrite(da9053);
@@ -284,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;
@@ -300,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 e1343bac76..04bcad8804 100644
--- a/drivers/mfd/da9063.c
+++ b/drivers/mfd/da9063.c
@@ -1,16 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2015 Pengutronix, Philipp Zabel <p.zabel@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -32,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;
};
@@ -263,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;
@@ -366,18 +356,15 @@ 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;
- void const *dev_data_tmp;
int ret;
- ret = dev_get_drvdata(dev, &dev_data_tmp);
- dev_data = ret < 0 ? NULL : dev_data_tmp;
+ dev_data = device_get_match_data(dev);
priv = xzalloc(sizeof(struct da9063));
- priv->wd.priority = of_get_watchdog_priority(dev->device_node);
priv->wd.set_timeout = da9063_watchdog_set_timeout;
priv->wd.hwdev = dev;
priv->timeout = DA9063_INITIAL_TIMEOUT;
@@ -396,22 +383,24 @@ 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;
restart_handler_register(&priv->restart);
- priv->gpio.base = -1;
- priv->gpio.ngpio = 5;
- priv->gpio.ops = &da9063_gpio_ops;
- priv->gpio.dev = dev;
- ret = gpiochip_add(&priv->gpio);
- if (ret)
- goto on_error;
+ if (IS_ENABLED(CONFIG_GPIOLIB)) {
+ priv->gpio.base = -1;
+ priv->gpio.ngpio = 5;
+ priv->gpio.ops = &da9063_gpio_ops;
+ priv->gpio.dev = dev;
+ ret = gpiochip_add(&priv->gpio);
+ if (ret)
+ 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;
@@ -437,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/fintek-superio.c b/drivers/mfd/fintek-superio.c
index 60785bce27..3a036bf347 100644
--- a/drivers/mfd/fintek-superio.c
+++ b/drivers/mfd/fintek-superio.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2019 Ahmad Fatoum, Pengutronix
*/
diff --git a/drivers/mfd/lp3972.c b/drivers/mfd/lp3972.c
index ca736710b2..d72f697da5 100644
--- a/drivers/mfd/lp3972.c
+++ b/drivers/mfd/lp3972.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2007 Sascha Hauer, Pengutronix
* 2009 Marc Kleine-Budde <mkl@pengutronix.de>
* 2009 Eric Benard <eric@eukrea.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -74,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;
@@ -91,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 a5877dbda1..1e06a24b45 100644
--- a/drivers/mfd/mc13xxx.c
+++ b/drivers/mfd/mc13xxx.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2007 Sascha Hauer, Pengutronix
* 2009 Marc Kleine-Budde <mkl@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -22,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>
@@ -33,7 +22,7 @@
#define MC13XXX_NUMREGS 0x3f
struct mc13xxx {
- struct device_d *dev;
+ struct device *dev;
struct regmap *map;
union {
struct i2c_client *client;
@@ -311,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;
@@ -364,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;
@@ -398,38 +387,26 @@ static __maybe_unused struct of_device_id mc13xxx_dt_ids[] = {
{ .compatible = "fsl,mc34708", .data = &mc34708_devtype, },
{ }
};
+MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
-static struct driver_d mc13xxx_i2c_driver = {
+static __maybe_unused struct driver mc13xxx_i2c_driver = {
.name = "mc13xxx-i2c",
.probe = mc13xxx_probe,
.id_table = mc13xxx_ids,
.of_compatible = DRV_OF_COMPAT(mc13xxx_dt_ids),
};
-static struct driver_d mc13xxx_spi_driver = {
+#if IS_ENABLED(CONFIG_I2C)
+coredevice_i2c_driver(mc13xxx_i2c_driver);
+#endif
+
+static __maybe_unused struct driver mc13xxx_spi_driver = {
.name = "mc13xxx-spi",
.probe = mc13xxx_probe,
.id_table = mc13xxx_ids,
.of_compatible = DRV_OF_COMPAT(mc13xxx_dt_ids),
};
-static int __init mc13xxx_init(void)
-{
- int err_spi = 0, err_i2c = 0;
-
- if (IS_ENABLED(CONFIG_I2C))
- err_spi = i2c_driver_register(&mc13xxx_i2c_driver);
-
- if (IS_ENABLED(CONFIG_SPI))
- err_i2c = spi_driver_register(&mc13xxx_spi_driver);
-
- if (err_spi)
- return err_spi;
-
- if (err_i2c)
- return err_i2c;
-
- return 0;
-
-}
-coredevice_initcall(mc13xxx_init);
+#if IS_ENABLED(CONFIG_SPI)
+coredevice_spi_driver(mc13xxx_spi_driver);
+#endif
diff --git a/drivers/mfd/mc34704.c b/drivers/mfd/mc34704.c
index 4aa02b74ff..7a893ef8b7 100644
--- a/drivers/mfd/mc34704.c
+++ b/drivers/mfd/mc34704.c
@@ -1,19 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2007 Sascha Hauer, Pengutronix
* 2009 Marc Kleine-Budde <mkl@pengutronix.de>
* Copyright (C) 2010 Baruch Siach <baruch@tkos.co.il>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -43,7 +32,7 @@ int mc34704_reg_read(struct mc34704 *mc34704, u8 reg, u8 *val)
{
int ret;
- ret = i2c_read_reg(mc34704->client, reg, val, 1);
+ ret = i2c_read_reg(mc34704->client, 1 << 7 | reg, val, 1);
return ret == 1 ? 0 : ret;
}
@@ -104,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;
@@ -112,7 +101,7 @@ static int mc34704_probe(struct device_d *dev)
mc34704_dev = xzalloc(sizeof(struct mc34704));
mc34704_dev->cdev.name = DRIVERNAME;
mc34704_dev->client = to_i2c_client(dev);
- mc34704_dev->cdev.size = 256;
+ mc34704_dev->cdev.size = 128;
mc34704_dev->cdev.dev = dev;
mc34704_dev->cdev.ops = &mc34704_fops;
@@ -125,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 408d746450..1f8a5611b4 100644
--- a/drivers/mfd/mc9sdz60.c
+++ b/drivers/mfd/mc9sdz60.c
@@ -1,18 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2007 Sascha Hauer, Pengutronix
* 2009 Marc Kleine-Budde <mkl@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- *
*/
#include <common.h>
@@ -116,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;
@@ -133,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 67f7d4c654..c7968b75f5 100644
--- a/drivers/mfd/rave-sp.c
+++ b/drivers/mfd/rave-sp.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Multifunction core driver for Zodiac Inflight Innovations RAVE
@@ -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;
@@ -269,9 +269,8 @@ static int rave_sp_write(struct rave_sp *sp, const u8 *data, u8 data_size)
length = dest - frame;
- if (IS_ENABLED(DEBUG))
- print_hex_dump(0, "rave-sp tx: ", DUMP_PREFIX_NONE,
- 16, 1, frame, length, false);
+ print_hex_dump_debug("rave-sp tx: ", DUMP_PREFIX_NONE, 16, 1,
+ frame, length, false);
return serdev_device_write(sp->serdev, frame, length, SECOND);
}
@@ -311,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,
@@ -367,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;
@@ -403,12 +402,11 @@ 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];
- if (IS_ENABLED(DEBUG))
- print_hex_dump(0, "rave-sp rx: ", DUMP_PREFIX_NONE,
- 16, 1, data, length, false);
+ print_hex_dump_debug("rave-sp rx: ", DUMP_PREFIX_NONE, 16, 1,
+ data, length, false);
if (unlikely(length <= checksum_length)) {
dev_warn(dev, "Dropping short frame\n");
@@ -432,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;
@@ -605,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)
{
/*
@@ -661,14 +659,14 @@ static int rave_sp_emulated_get_status(struct rave_sp *sp,
return ret;
status->general_status =
- firmware_mode ? RAVE_SP_STATUS_GS_FIRMWARE_MODE : 0;
+ firmware_mode ? 0 : RAVE_SP_STATUS_GS_FIRMWARE_MODE;
return 0;
}
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;
@@ -733,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)
{
@@ -768,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;
@@ -787,20 +786,17 @@ static int rave_sp_add_params(struct rave_sp *sp)
p = dev_add_param_ip(dev, "netmask", NULL, rave_sp_req_ip_addr,
&sp->netmask, sp);
- if (IS_ERR(p))
- return PTR_ERR(p);
-
- return 0;
+ 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;
@@ -855,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
new file mode 100644
index 0000000000..f1e2eeb0c8
--- /dev/null
+++ b/drivers/mfd/rn5t568.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MFD core driver for Ricoh RN5T618 PMIC
+ * Note: Manufacturer is now Nisshinbo Micro Devices Inc.
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
+ * Copyright (C) 2016 Toradex AG
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+#include <i2c/i2c.h>
+#include <init.h>
+#include <of.h>
+#include <linux/regmap.h>
+#include <reset_source.h>
+#include <restart.h>
+#include <mfd/rn5t568.h>
+
+struct rn5t568 {
+ struct restart_handler restart;
+ struct regmap *regmap;
+};
+
+static void rn5t568_restart(struct restart_handler *rst)
+{
+ struct rn5t568 *rn5t568 = container_of(rst, struct rn5t568, restart);
+
+ regmap_write(rn5t568->regmap, RN5T568_SLPCNT, RN5T568_SLPCNT_SWPPWROFF);
+}
+
+static int rn5t568_reset_reason_detect(struct device *dev,
+ struct regmap *regmap)
+{
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_read(regmap, RN5T568_PONHIS, &reg);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "Power-on history: %x\n", reg);
+
+ if (reg == 0) {
+ dev_info(dev, "No power-on reason available\n");
+ return 0;
+ }
+
+ if (reg & RN5T568_PONHIS_ON_EXTINPON) {
+ reset_source_set_device(dev, RESET_POR);
+ return 0;
+ } else if (reg & RN5T568_PONHIS_ON_PWRONPON) {
+ reset_source_set_device(dev, RESET_POR);
+ return 0;
+ } else if (!(reg & RN5T568_PONHIS_ON_REPWRPON))
+ return -EINVAL;
+
+ ret = regmap_read(regmap, RN5T568_POFFHIS, &reg);
+ if (ret)
+ return ret;
+
+ dev_dbg(dev, "Power-off history: %x\n", reg);
+
+ if (reg & RN5T568_POFFHIS_PWRONPOFF)
+ reset_source_set_device(dev, RESET_POR);
+ else if (reg & RN5T568_POFFHIS_TSHUTPOFF)
+ reset_source_set_device(dev, RESET_THERM);
+ else if (reg & RN5T568_POFFHIS_VINDETPOFF)
+ reset_source_set_device(dev, RESET_BROWNOUT);
+ else if (reg & RN5T568_POFFHIS_IODETPOFF)
+ reset_source_set_device(dev, RESET_UKWN);
+ else if (reg & RN5T568_POFFHIS_CPUPOFF)
+ reset_source_set_device(dev, RESET_RST);
+ else if (reg & RN5T568_POFFHIS_WDGPOFF)
+ reset_source_set_device(dev, RESET_WDG);
+ else if (reg & RN5T568_POFFHIS_DCLIMPOFF)
+ reset_source_set_device(dev, RESET_BROWNOUT);
+ else if (reg & RN5T568_POFFHIS_N_OEPOFF)
+ reset_source_set_device(dev, RESET_EXT);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct regmap_config rn5t568_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RN5T568_MAX_REG,
+};
+
+static int __init rn5t568_i2c_probe(struct device *dev)
+{
+ struct rn5t568 *pmic_instance;
+ unsigned char reg[2];
+ int ret;
+
+ pmic_instance = xzalloc(sizeof(struct rn5t568));
+ pmic_instance->regmap = regmap_init_i2c(to_i2c_client(dev), &rn5t568_regmap_config);
+ if (IS_ERR(pmic_instance->regmap))
+ return PTR_ERR(pmic_instance->regmap);
+
+ ret = regmap_register_cdev(pmic_instance->regmap, NULL);
+ if (ret)
+ return ret;
+
+ ret = regmap_bulk_read(pmic_instance->regmap, RN5T568_LSIVER, &reg, 2);
+ if (ret) {
+ dev_err(dev, "Failed to read PMIC version via I2C\n");
+ return ret;
+ }
+
+ dev_info(dev, "Found NMD RN5T568 LSI %x, OTP: %x\n", reg[0], reg[1]);
+
+ /* Settings used to trigger software reset and by a watchdog trigger */
+ regmap_write(pmic_instance->regmap, RN5T568_REPCNT, RN5T568_REPCNT_OFF_RESETO_16MS |
+ RN5T568_REPCNT_OFF_REPWRTIM_1000MS | RN5T568_REPCNT_OFF_REPWRON);
+
+ 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);
+ dev_dbg(dev, "RN5t: Restart handler with priority %d registered\n", pmic_instance->restart.priority);
+
+ ret = rn5t568_reset_reason_detect(dev, pmic_instance->regmap);
+ if (ret)
+ dev_warn(dev, "Failed to query reset reason\n");
+
+ 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 rn5t568_i2c_driver = {
+ .name = "rn5t568-i2c",
+ .probe = rn5t568_i2c_probe,
+ .of_compatible = DRV_OF_COMPAT(rn5t568_of_match),
+};
+
+coredevice_i2c_driver(rn5t568_i2c_driver);
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/smsc-superio.c b/drivers/mfd/smsc-superio.c
index 349c878cef..d716fbae3f 100644
--- a/drivers/mfd/smsc-superio.c
+++ b/drivers/mfd/smsc-superio.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2019 Ahmad Fatoum, Pengutronix
*/
@@ -106,8 +106,9 @@ static void smsc_superio_find(u16 sioaddr, u16 id_reg)
static int smsc_superio_detect(void)
{
u16 ports[] = { 0x2e, 0x4e, 0x162e, 0x164e, 0x3f0, 0x370 };
+ int i;
- for (int i = 0; i < ARRAY_SIZE(ports); i++)
+ for (i = 0; i < ARRAY_SIZE(ports); i++)
smsc_superio_find(ports[i], SIO_REG_DEVID);
return 0;
diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c
new file mode 100644
index 0000000000..3b47800105
--- /dev/null
+++ b/drivers/mfd/stm32-timers.c
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) STMicroelectronics 2016
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com>
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <driver.h>
+#include <init.h>
+#include <io.h>
+#include <linux/bitfield.h>
+#include <linux/mfd/stm32-timers.h>
+#include <linux/regmap.h>
+#include <of.h>
+#include <linux/reset.h>
+
+#define STM32_TIMERS_MAX_REGISTERS 0x3fc
+
+static const struct regmap_config stm32_timers_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = sizeof(u32),
+ .max_register = STM32_TIMERS_MAX_REGISTERS,
+};
+
+static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
+{
+ /*
+ * Only the available bits will be written so when readback
+ * we get the maximum value of auto reload register
+ */
+ regmap_write(ddata->regmap, TIM_ARR, ~0L);
+ regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr);
+ regmap_write(ddata->regmap, TIM_ARR, 0x0);
+}
+
+static int stm32_timers_probe(struct device *dev)
+{
+ struct stm32_timers *ddata;
+ struct resource *res;
+
+ ddata = xzalloc(sizeof(*ddata));
+
+ res = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ ddata->regmap = regmap_init_mmio_clk(dev, "int", IOMEM(res->start),
+ &stm32_timers_regmap_cfg);
+ if (IS_ERR(ddata->regmap))
+ return PTR_ERR(ddata->regmap);
+
+ ddata->clk = clk_get(dev, NULL);
+ if (IS_ERR(ddata->clk))
+ return PTR_ERR(ddata->clk);
+
+ stm32_timers_get_arr_size(ddata);
+
+ dev->priv = ddata;
+
+ 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 stm32_timers_driver = {
+ .name = "stm32-timers",
+ .probe = stm32_timers_probe,
+ .of_compatible = stm32_timers_of_match,
+};
+coredevice_platform_driver(stm32_timers_driver);
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index f140f1bbc4..08dc48246e 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -1,17 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012 Pengutronix
* Steffen Trumtrar <s.trumtrar@pengutronix.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
*/
#include <common.h>
@@ -105,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;
}
@@ -124,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;
@@ -166,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 eae6fe3a4e..9985673aa6 100644
--- a/drivers/mfd/stpmic1.c
+++ b/drivers/mfd/stpmic1.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2019 Ahmad Fatoum, Pengutronix
*/
@@ -8,47 +8,9 @@
#include <errno.h>
#include <i2c/i2c.h>
#include <init.h>
-#include <malloc.h>
#include <of.h>
-#include <regmap.h>
-#include <xfuncs.h>
-
-#define VERSION_SR 0x6
-
-struct stpmic1 {
- struct device_d *dev;
- struct i2c_client *client;
-};
-
-static int stpmic1_i2c_reg_read(void *ctx, unsigned int reg, unsigned int *val)
-{
- struct stpmic1 *stpmic1 = ctx;
- u8 buf[1];
- int ret;
-
- ret = i2c_read_reg(stpmic1->client, reg, buf, 1);
- *val = buf[0];
-
- return ret == 1 ? 0 : ret;
-}
-
-static int stpmic1_i2c_reg_write(void *ctx, unsigned int reg, unsigned int val)
-{
- struct stpmic1 *stpmic1 = ctx;
- u8 buf[] = {
- val & 0xff,
- };
- int ret;
-
- ret = i2c_write_reg(stpmic1->client, reg, buf, 1);
-
- return ret == 1 ? 0 : ret;
-}
-
-static struct regmap_bus regmap_stpmic1_i2c_bus = {
- .reg_write = stpmic1_i2c_reg_write,
- .reg_read = stpmic1_i2c_reg_read,
-};
+#include <linux/regmap.h>
+#include <linux/mfd/stpmic1.h>
static const struct regmap_config stpmic1_regmap_i2c_config = {
.reg_bits = 8,
@@ -56,19 +18,15 @@ 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 stpmic1 *stpmic1;
struct regmap *regmap;
u32 reg;
int ret;
- stpmic1 = xzalloc(sizeof(*stpmic1));
- stpmic1->dev = dev;
-
- stpmic1->client = to_i2c_client(dev);
- regmap = regmap_init(dev, &regmap_stpmic1_i2c_bus,
- stpmic1, &stpmic1_regmap_i2c_config);
+ regmap = regmap_init_i2c(to_i2c_client(dev), &stpmic1_regmap_i2c_config);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
ret = regmap_register_cdev(regmap, NULL);
if (ret)
@@ -81,18 +39,19 @@ 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),
};
-device_i2c_driver(stpmic1_i2c_driver);
+coredevice_i2c_driver(stpmic1_i2c_driver);
diff --git a/drivers/mfd/superio.c b/drivers/mfd/superio.c
index 12d74b40f6..16d0bba450 100644
--- a/drivers/mfd/superio.c
+++ b/drivers/mfd/superio.c
@@ -1,4 +1,4 @@
-// SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2019 Ahmad Fatoum, Pengutronix
*/
@@ -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);
@@ -24,7 +24,7 @@ struct device_d *superio_func_add(struct superio_chip *siochip, const char *name
return dev;
}
-EXPORT_SYMBOL(superio_func_add)
+EXPORT_SYMBOL(superio_func_add);
static int superio_reg_read(void *ctx, unsigned int reg, unsigned int *val)
{
@@ -87,12 +87,11 @@ void superio_chip_add(struct superio_chip *siochip)
regmap = regmap_init(siochip->dev, &superio_regmap_bus, siochip,
&superio_regmap_config);
if (IS_ERR(regmap))
- pr_warn("creating %s regmap failed: %s\n",
- chipname, strerrorp(regmap));
+ pr_warn("creating %s regmap failed: %pe\n", chipname, regmap);
ret = regmap_register_cdev(regmap, chipname);
if (ret)
pr_warn("registering %s regmap cdev failed: %s\n",
chipname, strerror(-ret));
}
-EXPORT_SYMBOL(superio_chip_add)
+EXPORT_SYMBOL(superio_chip_add);
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 8099419378..3c2e1241fd 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* System Control Driver
*
* Based on linux driver by:
* Copyright (C) 2012 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
* Author: Dong Aisheng <dong.aisheng@linaro.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <io.h>
@@ -19,6 +15,8 @@
#include <xfuncs.h>
#include <of_address.h>
#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
#include <mfd/syscon.h>
@@ -31,42 +29,20 @@ struct syscon {
struct regmap *regmap;
};
-static int syscon_reg_write(void *context, unsigned int reg,
- unsigned int val)
-{
- struct syscon *syscon = context;
- writel(val, syscon->base + reg);
- return 0;
-}
-
-static int syscon_reg_read(void *context, unsigned int reg,
- unsigned int *val)
-{
- struct syscon *syscon = context;
- *val = readl(syscon->base + reg);
- return 0;
-}
-
-static const struct regmap_bus syscon_regmap_bus = {
- .reg_write = syscon_reg_write,
- .reg_read = syscon_reg_read,
-};
-
static const struct regmap_config syscon_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
-static struct syscon *of_syscon_register(struct device_node *np)
+static struct syscon *of_syscon_register(struct device_node *np, bool check_clk)
{
- int ret;
+ struct regmap_config syscon_config = syscon_regmap_config;
struct syscon *syscon;
+ u32 reg_io_width;
+ int ret;
struct resource res;
- if (!of_device_is_compatible(np, "syscon"))
- return ERR_PTR(-EINVAL);
-
syscon = xzalloc(sizeof(*syscon));
if (of_address_to_resource(np, 0, &res)) {
@@ -75,14 +51,48 @@ static struct syscon *of_syscon_register(struct device_node *np)
}
syscon->base = IOMEM(res.start);
- syscon->np = np;
+
+ /* Parse the device's DT node for an endianness specification */
+ if (of_property_read_bool(np, "big-endian"))
+ syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
+ else if (of_property_read_bool(np, "little-endian"))
+ syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
+ else if (of_property_read_bool(np, "native-endian"))
+ syscon_config.val_format_endian = REGMAP_ENDIAN_NATIVE;
+
+ /*
+ * search for reg-io-width property in DT. If it is not provided,
+ * default to 4 bytes. regmap_init_mmio will return an error if values
+ * are invalid so there is no need to check them here.
+ */
+ ret = of_property_read_u32(np, "reg-io-width", &reg_io_width);
+ if (ret)
+ reg_io_width = 4;
+
+ syscon_config.name = np->full_name;
+ syscon_config.reg_stride = reg_io_width;
+ syscon_config.val_bits = reg_io_width * 8;
+ syscon_config.max_register = resource_size(&res) - reg_io_width;
+
+ syscon->regmap = regmap_init_mmio_clk(NULL, NULL, syscon->base,
+ &syscon_config);
+
+ if (check_clk) {
+ struct clk *clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ /* clock is optional */
+ if (ret != -ENOENT)
+ goto err_map;
+ } else {
+ ret = regmap_mmio_attach_clk(syscon->regmap, clk);
+ if (ret)
+ goto err_map;
+ }
+ }
list_add_tail(&syscon->list, &syscon_list);
- syscon->regmap = regmap_init(NULL,
- &syscon_regmap_bus,
- syscon,
- &syscon_regmap_config);
return syscon;
err_map:
@@ -90,7 +100,7 @@ err_map:
return ERR_PTR(ret);
}
-static struct syscon *node_to_syscon(struct device_node *np)
+static struct syscon *node_to_syscon(struct device_node *np, bool check_clk)
{
struct syscon *entry, *syscon = NULL;
@@ -101,7 +111,7 @@ static struct syscon *node_to_syscon(struct device_node *np)
}
if (!syscon)
- syscon = of_syscon_register(np);
+ syscon = of_syscon_register(np, check_clk);
if (IS_ERR(syscon))
return ERR_CAST(syscon);
@@ -111,27 +121,26 @@ static struct syscon *node_to_syscon(struct device_node *np)
static void __iomem *syscon_node_to_base(struct device_node *np)
{
- struct syscon *syscon = node_to_syscon(np);
+ struct syscon *syscon;
+ struct clk *clk;
+
+ if (!of_device_is_compatible(np, "syscon"))
+ return ERR_PTR(-EINVAL);
+ syscon = node_to_syscon(np, true);
if (IS_ERR(syscon))
return ERR_CAST(syscon);
- 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;
- }
- }
+ /* Returning the direct pointer here side steps the regmap
+ * and any specified clock wouldn't be enabled on access.
+ * Deal with this by enabling the clock permanently if any
+ * syscon_node_to_base users exist.
+ */
+ clk = of_clk_get(np, 0);
+ if (!IS_ERR(clk))
+ clk_enable(clk);
- return ERR_PTR(-ENODEV);
+ return syscon->base;
}
void __iomem *syscon_base_lookup_by_phandle(struct device_node *np,
@@ -150,16 +159,31 @@ void __iomem *syscon_base_lookup_by_phandle(struct device_node *np,
return syscon_node_to_base(syscon_np);
}
-struct regmap *syscon_node_to_regmap(struct device_node *np)
+static struct regmap *__device_node_to_regmap(struct device_node *np,
+ bool check_clk)
{
- struct syscon *syscon = node_to_syscon(np);
+ struct syscon *syscon;
+ syscon = node_to_syscon(np, check_clk);
if (IS_ERR(syscon))
return ERR_CAST(syscon);
return syscon->regmap;
}
+struct regmap *device_node_to_regmap(struct device_node *np)
+{
+ return __device_node_to_regmap(np, false);
+}
+
+struct regmap *syscon_node_to_regmap(struct device_node *np)
+{
+ if (!of_device_is_compatible(np, "syscon"))
+ return ERR_PTR(-EINVAL);
+
+ return __device_node_to_regmap(np, true);
+}
+
struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
{
struct device_node *syscon_np;
@@ -193,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;
@@ -219,17 +243,13 @@ 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,
};
-static int __init syscon_init(void)
-{
- return platform_driver_register(&syscon_driver);
-}
-core_initcall(syscon_init);
+core_platform_driver(syscon_driver);
MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
MODULE_DESCRIPTION("System Control driver");
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index c3240b8542..8d809259e0 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -1,11 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Alexander Aring <a.aring@phytec.de>
*
* Based on:
* Copyright (C) 2010 Michael Grzeschik <mgr@pengutronix.de>
- *
- * This file is released under the GPLv2
- *
*/
#include <common.h>
diff --git a/drivers/mfd/twl4030.c b/drivers/mfd/twl4030.c
index cf33efbd89..7acf9b18bd 100644
--- a/drivers/mfd/twl4030.c
+++ b/drivers/mfd/twl4030.c
@@ -1,8 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2010 Michael Grzeschik <mgr@pengutronix.de>
- *
- * This file is released under the GPLv2
- *
*/
#include <common.h>
@@ -28,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;
@@ -45,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 0a244de077..d7a7d9baf8 100644
--- a/drivers/mfd/twl6030.c
+++ b/drivers/mfd/twl6030.c
@@ -1,7 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Alexander Aring <a.aring@phytec.de>
- *
- * This file is released under the GPLv2
*/
#include <common.h>
@@ -24,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;
@@ -62,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,
};