diff options
Diffstat (limited to 'drivers/mfd')
29 files changed, 1904 insertions, 277 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 42346154e6..5189364c2c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only menu "Multifunction device drivers" config MFD_ACT8846 @@ -63,30 +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_STM32MP || COMPILE_TEST + 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 a3b296a803..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,7 +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 1f32869038..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; @@ -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; @@ -283,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; @@ -299,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 e48c38affa..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,15 +356,13 @@ 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.set_timeout = da9063_watchdog_set_timeout; @@ -395,7 +383,7 @@ static int da9063_probe(struct device_d *dev) da9063_detect_reset_source(priv); - priv->restart.priority = of_get_restart_priority(dev->device_node); + priv->restart.of_node = dev->of_node; priv->restart.name = "da9063"; priv->restart.restart = &da9063_restart; @@ -411,8 +399,8 @@ static int da9063_probe(struct device_d *dev) goto on_error; } - if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node) - return of_platform_populate(dev->device_node, NULL, dev); + if (IS_ENABLED(CONFIG_OFDEVICE) && dev->of_node) + return of_platform_populate(dev->of_node, NULL, dev); return 0; @@ -438,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, ®); + 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, ®); + 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 c6ad57d517..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) { /* @@ -668,7 +666,7 @@ static int rave_sp_emulated_get_status(struct rave_sp *sp, static int rave_sp_get_status(struct rave_sp *sp) { - struct device_d *dev = sp->serdev->dev; + struct device *dev = sp->serdev->dev; struct rave_sp_status status; const char *mode; int ret; @@ -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, ®); + 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, ®); + 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, ®, 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 index c53a25687e..3b47800105 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) STMicroelectronics 2016 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> @@ -11,6 +11,7 @@ #include <io.h> #include <linux/bitfield.h> #include <linux/mfd/stm32-timers.h> +#include <linux/regmap.h> #include <of.h> #include <linux/reset.h> @@ -34,7 +35,7 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata) regmap_write(ddata->regmap, TIM_ARR, 0x0); } -static int stm32_timers_probe(struct device_d *dev) +static int stm32_timers_probe(struct device *dev) { struct stm32_timers *ddata; struct resource *res; @@ -58,15 +59,16 @@ static int stm32_timers_probe(struct device_d *dev) dev->priv = ddata; - return of_platform_populate(dev->device_node, NULL, dev); + return of_platform_populate(dev->of_node, NULL, dev); } static const struct of_device_id stm32_timers_of_match[] = { { .compatible = "st,stm32-timers", }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, stm32_timers_of_match); -static struct driver_d stm32_timers_driver = { +static struct driver stm32_timers_driver = { .name = "stm32-timers", .probe = stm32_timers_probe, .of_compatible = stm32_timers_of_match, diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index 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 d22758bd61..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,66 +8,25 @@ #include <errno.h> #include <i2c/i2c.h> #include <init.h> -#include <malloc.h> #include <of.h> -#include <regmap.h> -#include <xfuncs.h> +#include <linux/regmap.h> #include <linux/mfd/stpmic1.h> -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, -}; - static const struct regmap_config stpmic1_regmap_i2c_config = { .reg_bits = 8, .val_bits = 8, .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, ®map_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) @@ -80,15 +39,16 @@ static int __init stpmic1_probe(struct device_d *dev) } dev_info(dev, "PMIC Chip Version: 0x%x\n", reg); - return of_platform_populate(dev->device_node, NULL, dev); + return of_platform_populate(dev->of_node, NULL, dev); } static __maybe_unused struct of_device_id stpmic1_dt_ids[] = { { .compatible = "st,stpmic1" }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, stpmic1_dt_ids); -static struct driver_d stpmic1_i2c_driver = { +static struct driver stpmic1_i2c_driver = { .name = "stpmic1-i2c", .probe = stpmic1_probe, .of_compatible = DRV_OF_COMPAT(stpmic1_dt_ids), diff --git a/drivers/mfd/superio.c b/drivers/mfd/superio.c index ab94a4fa8f..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); @@ -87,8 +87,7 @@ 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) diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index a464dfc506..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> @@ -20,6 +16,7 @@ #include <of_address.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/regmap.h> #include <mfd/syscon.h> @@ -77,8 +74,6 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) syscon_config.val_bits = reg_io_width * 8; syscon_config.max_register = resource_size(&res) - reg_io_width; - list_add_tail(&syscon->list, &syscon_list); - syscon->regmap = regmap_init_mmio_clk(NULL, NULL, syscon->base, &syscon_config); @@ -96,6 +91,8 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) } } + list_add_tail(&syscon->list, &syscon_list); + return syscon; err_map: @@ -146,21 +143,6 @@ static void __iomem *syscon_node_to_base(struct device_node *np) return syscon->base; } -void __iomem *syscon_base_lookup_by_pdevname(const char *s) -{ - struct syscon *syscon; - struct device_d *dev; - - for_each_device(dev) { - if (!strcmp(dev_name(dev), s)) { - syscon = dev->priv; - return syscon->base; - } - } - - return ERR_PTR(-ENODEV); -} - void __iomem *syscon_base_lookup_by_phandle(struct device_node *np, const char *property) { @@ -235,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; @@ -261,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, }; |