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