From b1b3ced389795d2671e88dd3e9e07a48dc9632fc Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 10 Mar 2021 10:06:05 +0200 Subject: mfd: Support ROHM BD9576MUF and BD9573MUF Add core support for ROHM BD9576MUF and BD9573MUF PMICs which are mainly used to power the R-Car series processors. Signed-off-by: Matti Vaittinen Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 11 +++++ drivers/mfd/Makefile | 1 + drivers/mfd/rohm-bd9576.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 drivers/mfd/rohm-bd9576.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b74efa469e90..f0c9529e7bfd 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1989,6 +1989,17 @@ config MFD_ROHM_BD71828 Also included is a Coulomb counter, a real-time clock (RTC), and a 32.768 kHz clock gate. +config MFD_ROHM_BD957XMUF + tristate "ROHM BD9576MUF and BD9573MUF Power Management ICs" + depends on I2C=y + depends on OF + select REGMAP_I2C + select MFD_CORE + help + Select this option to get support for the ROHM BD9576MUF and + BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily + designed to be used to power R-Car series processors. + config MFD_STM32_LPTIMER tristate "Support for STM32 Low-Power Timer" depends on (ARCH_STM32 && OF) || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 834f5463af28..d93f6f361fd3 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -261,6 +261,7 @@ obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o +obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o obj-$(CONFIG_MFD_STMFX) += stmfx.o obj-$(CONFIG_MFD_KHADAS_MCU) += khadas-mcu.o obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o diff --git a/drivers/mfd/rohm-bd9576.c b/drivers/mfd/rohm-bd9576.c new file mode 100644 index 000000000000..2dbda1f401e2 --- /dev/null +++ b/drivers/mfd/rohm-bd9576.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 ROHM Semiconductors + * + * ROHM BD9576MUF and BD9573MUF PMIC driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct mfd_cell bd9573_mfd_cells[] = { + { .name = "bd9573-regulator", }, + { .name = "bd9576-wdt", }, +}; + +static struct mfd_cell bd9576_mfd_cells[] = { + { .name = "bd9576-regulator", }, + { .name = "bd9576-wdt", }, +}; + +static const struct regmap_range volatile_ranges[] = { + regmap_reg_range(BD957X_REG_SMRB_ASSERT, BD957X_REG_SMRB_ASSERT), + regmap_reg_range(BD957X_REG_PMIC_INTERNAL_STAT, + BD957X_REG_PMIC_INTERNAL_STAT), + regmap_reg_range(BD957X_REG_INT_THERM_STAT, BD957X_REG_INT_THERM_STAT), + regmap_reg_range(BD957X_REG_INT_OVP_STAT, BD957X_REG_INT_SYS_STAT), + regmap_reg_range(BD957X_REG_INT_MAIN_STAT, BD957X_REG_INT_MAIN_STAT), +}; + +static const struct regmap_access_table volatile_regs = { + .yes_ranges = &volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(volatile_ranges), +}; + +static struct regmap_config bd957x_regmap = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &volatile_regs, + .max_register = BD957X_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, +}; + +static int bd957x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + int ret; + struct regmap *regmap; + struct mfd_cell *cells; + int num_cells; + unsigned long chip_type; + + chip_type = (unsigned long)of_device_get_match_data(&i2c->dev); + + switch (chip_type) { + case ROHM_CHIP_TYPE_BD9576: + cells = bd9576_mfd_cells; + num_cells = ARRAY_SIZE(bd9576_mfd_cells); + break; + case ROHM_CHIP_TYPE_BD9573: + cells = bd9573_mfd_cells; + num_cells = ARRAY_SIZE(bd9573_mfd_cells); + break; + default: + dev_err(&i2c->dev, "Unknown device type"); + return -EINVAL; + } + + regmap = devm_regmap_init_i2c(i2c, &bd957x_regmap); + if (IS_ERR(regmap)) { + dev_err(&i2c->dev, "Failed to initialize Regmap\n"); + return PTR_ERR(regmap); + } + + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, cells, + num_cells, NULL, 0, NULL); + if (ret) + dev_err(&i2c->dev, "Failed to create subdevices\n"); + + return ret; +} + +static const struct of_device_id bd957x_of_match[] = { + { .compatible = "rohm,bd9576", .data = (void *)ROHM_CHIP_TYPE_BD9576, }, + { .compatible = "rohm,bd9573", .data = (void *)ROHM_CHIP_TYPE_BD9573, }, + { }, +}; +MODULE_DEVICE_TABLE(of, bd957x_of_match); + +static struct i2c_driver bd957x_drv = { + .driver = { + .name = "rohm-bd957x", + .of_match_table = bd957x_of_match, + }, + .probe = &bd957x_i2c_probe, +}; +module_i2c_driver(bd957x_drv); + +MODULE_AUTHOR("Matti Vaittinen "); +MODULE_DESCRIPTION("ROHM BD9576MUF and BD9573MUF Power Management IC driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 0e9692607f94ecc59aedc0ecfd2348124c743412 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 10 Mar 2021 10:08:02 +0200 Subject: mfd: bd9576: Add IRQ support BD9573 and BD9576 support set of "protection" interrupts for "fatal" issues. Those lead to SOC reset as PMIC shuts the power outputs. Thus there is no relevant IRQ handling for them. Few "detection" interrupts were added to the BD9576 with the idea that SOC could take some recovery-action before error gets unrecoverable. Unfortunately the BD9576 interrupt logic was not re-evaluated. IRQs are not designed to be properly acknowleged - and IRQ line is kept active for whole duration of error condition (in comparison to informing only about state change). For above reason, do not consider missing IRQ as error. Signed-off-by: Matti Vaittinen Signed-off-by: Lee Jones --- drivers/mfd/rohm-bd9576.c | 90 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 5 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rohm-bd9576.c b/drivers/mfd/rohm-bd9576.c index 2dbda1f401e2..6661a27d69a8 100644 --- a/drivers/mfd/rohm-bd9576.c +++ b/drivers/mfd/rohm-bd9576.c @@ -17,14 +17,30 @@ #include #include +enum { + BD957X_REGULATOR_CELL, + BD957X_WDT_CELL, +}; + +/* + * Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs. + * These will be added to regulator resources only if IRQ information for the + * PMIC is populated in device-tree. + */ +static const struct resource bd9576_regulator_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD9576_INT_THERM, "bd9576-temp"), + DEFINE_RES_IRQ_NAMED(BD9576_INT_OVD, "bd9576-ovd"), + DEFINE_RES_IRQ_NAMED(BD9576_INT_UVD, "bd9576-uvd"), +}; + static struct mfd_cell bd9573_mfd_cells[] = { - { .name = "bd9573-regulator", }, - { .name = "bd9576-wdt", }, + [BD957X_REGULATOR_CELL] = { .name = "bd9573-regulator", }, + [BD957X_WDT_CELL] = { .name = "bd9576-wdt", }, }; static struct mfd_cell bd9576_mfd_cells[] = { - { .name = "bd9576-regulator", }, - { .name = "bd9576-wdt", }, + [BD957X_REGULATOR_CELL] = { .name = "bd9576-regulator", }, + [BD957X_WDT_CELL] = { .name = "bd9576-wdt", }, }; static const struct regmap_range volatile_ranges[] = { @@ -49,6 +65,29 @@ static struct regmap_config bd957x_regmap = { .cache_type = REGCACHE_RBTREE, }; +static struct regmap_irq bd9576_irqs[] = { + REGMAP_IRQ_REG(BD9576_INT_THERM, 0, BD957X_MASK_INT_MAIN_THERM), + REGMAP_IRQ_REG(BD9576_INT_OVP, 0, BD957X_MASK_INT_MAIN_OVP), + REGMAP_IRQ_REG(BD9576_INT_SCP, 0, BD957X_MASK_INT_MAIN_SCP), + REGMAP_IRQ_REG(BD9576_INT_OCP, 0, BD957X_MASK_INT_MAIN_OCP), + REGMAP_IRQ_REG(BD9576_INT_OVD, 0, BD957X_MASK_INT_MAIN_OVD), + REGMAP_IRQ_REG(BD9576_INT_UVD, 0, BD957X_MASK_INT_MAIN_UVD), + REGMAP_IRQ_REG(BD9576_INT_UVP, 0, BD957X_MASK_INT_MAIN_UVP), + REGMAP_IRQ_REG(BD9576_INT_SYS, 0, BD957X_MASK_INT_MAIN_SYS), +}; + +static struct regmap_irq_chip bd9576_irq_chip = { + .name = "bd9576_irq", + .irqs = &bd9576_irqs[0], + .num_irqs = ARRAY_SIZE(bd9576_irqs), + .status_base = BD957X_REG_INT_MAIN_STAT, + .mask_base = BD957X_REG_INT_MAIN_MASK, + .ack_base = BD957X_REG_INT_MAIN_STAT, + .init_ack_masked = true, + .num_regs = 1, + .irq_reg_stride = 1, +}; + static int bd957x_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -57,6 +96,8 @@ static int bd957x_i2c_probe(struct i2c_client *i2c, struct mfd_cell *cells; int num_cells; unsigned long chip_type; + struct irq_domain *domain; + bool usable_irqs; chip_type = (unsigned long)of_device_get_match_data(&i2c->dev); @@ -64,10 +105,16 @@ static int bd957x_i2c_probe(struct i2c_client *i2c, case ROHM_CHIP_TYPE_BD9576: cells = bd9576_mfd_cells; num_cells = ARRAY_SIZE(bd9576_mfd_cells); + usable_irqs = !!i2c->irq; break; case ROHM_CHIP_TYPE_BD9573: cells = bd9573_mfd_cells; num_cells = ARRAY_SIZE(bd9573_mfd_cells); + /* + * BD9573 only supports fatal IRQs which we can not handle + * because SoC is going to lose the power. + */ + usable_irqs = false; break; default: dev_err(&i2c->dev, "Unknown device type"); @@ -80,8 +127,41 @@ static int bd957x_i2c_probe(struct i2c_client *i2c, return PTR_ERR(regmap); } + /* + * BD9576 behaves badly. It kepts IRQ line asserted for the whole + * duration of detected HW condition (like over temperature). So we + * don't require IRQ to be populated. + * If IRQ information is not given, then we mask all IRQs and do not + * provide IRQ resources to regulator driver - which then just omits + * the notifiers. + */ + if (usable_irqs) { + struct regmap_irq_chip_data *irq_data; + struct mfd_cell *regulators; + + regulators = &bd9576_mfd_cells[BD957X_REGULATOR_CELL]; + regulators->resources = bd9576_regulator_irqs; + regulators->num_resources = ARRAY_SIZE(bd9576_regulator_irqs); + + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq, + IRQF_ONESHOT, 0, + &bd9576_irq_chip, &irq_data); + if (ret) { + dev_err(&i2c->dev, "Failed to add IRQ chip\n"); + return ret; + } + domain = regmap_irq_get_domain(irq_data); + } else { + ret = regmap_update_bits(regmap, BD957X_REG_INT_MAIN_MASK, + BD957X_MASK_INT_ALL, + BD957X_MASK_INT_ALL); + if (ret) + return ret; + domain = NULL; + } + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, cells, - num_cells, NULL, 0, NULL); + num_cells, NULL, 0, domain); if (ret) dev_err(&i2c->dev, "Failed to create subdevices\n"); -- cgit v1.2.3 From eceae583930666a69ab805eee8e81f9699bf6930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Neusch=C3=A4fer?= Date: Sun, 24 Jan 2021 22:41:23 +0100 Subject: mfd: Add base driver for Netronix embedded controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Netronix embedded controller is a microcontroller found in some e-book readers designed by the original design manufacturer Netronix, Inc. It contains RTC, battery monitoring, system power management, and PWM functionality. This driver implements register access and version detection. Third-party hardware documentation is available at: https://github.com/neuschaefer/linux/wiki/Netronix-MSP430-embedded-controller The EC supports interrupts, but the driver doesn't make use of them so far. Signed-off-by: Jonathan Neuschäfer Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 11 +++ drivers/mfd/Makefile | 1 + drivers/mfd/ntxec.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 drivers/mfd/ntxec.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b74efa469e90..a03de3f7a8ed 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -967,6 +967,17 @@ config MFD_VIPERBOARD You need to select the mfd cell drivers separately. The drivers do not support all features the board exposes. +config MFD_NTXEC + tristate "Netronix embedded controller (EC)" + depends on OF || COMPILE_TEST + depends on I2C + select REGMAP_I2C + select MFD_CORE + help + Say yes here if you want to support the embedded controller found in + certain e-book readers designed by the original design manufacturer + Netronix. + config MFD_RETU tristate "Nokia Retu and Tahvo multi-function device" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 834f5463af28..bb5e8f2a8e3a 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -218,6 +218,7 @@ obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o obj-$(CONFIG_MFD_INTEL_PMT) += intel_pmt.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o +obj-$(CONFIG_MFD_NTXEC) += ntxec.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_RK808) += rk808.o obj-$(CONFIG_MFD_RN5T618) += rn5t618.o diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c new file mode 100644 index 000000000000..957de2b03529 --- /dev/null +++ b/drivers/mfd/ntxec.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * The Netronix embedded controller is a microcontroller found in some + * e-book readers designed by the original design manufacturer Netronix, Inc. + * It contains RTC, battery monitoring, system power management, and PWM + * functionality. + * + * This driver implements register access, version detection, and system + * power-off/reset. + * + * Copyright 2020 Jonathan Neuschäfer + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NTXEC_REG_VERSION 0x00 +#define NTXEC_REG_POWEROFF 0x50 +#define NTXEC_REG_POWERKEEP 0x70 +#define NTXEC_REG_RESET 0x90 + +#define NTXEC_POWEROFF_VALUE 0x0100 +#define NTXEC_POWERKEEP_VALUE 0x0800 +#define NTXEC_RESET_VALUE 0xff00 + +static struct i2c_client *poweroff_restart_client; + +static void ntxec_poweroff(void) +{ + int res; + u8 buf[3] = { NTXEC_REG_POWEROFF }; + struct i2c_msg msgs[] = { + { + .addr = poweroff_restart_client->addr, + .flags = 0, + .len = sizeof(buf), + .buf = buf, + }, + }; + + put_unaligned_be16(NTXEC_POWEROFF_VALUE, buf + 1); + + res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs)); + if (res < 0) + dev_warn(&poweroff_restart_client->dev, + "Failed to power off (err = %d)\n", res); + + /* + * The time from the register write until the host CPU is powered off + * has been observed to be about 2.5 to 3 seconds. Sleep long enough to + * safely avoid returning from the poweroff handler. + */ + msleep(5000); +} + +static int ntxec_restart(struct notifier_block *nb, + unsigned long action, void *data) +{ + int res; + u8 buf[3] = { NTXEC_REG_RESET }; + /* + * NOTE: The lower half of the reset value is not sent, because sending + * it causes an I2C error. (The reset handler in the downstream driver + * does send the full two-byte value, but doesn't check the result). + */ + struct i2c_msg msgs[] = { + { + .addr = poweroff_restart_client->addr, + .flags = 0, + .len = sizeof(buf) - 1, + .buf = buf, + }, + }; + + put_unaligned_be16(NTXEC_RESET_VALUE, buf + 1); + + res = i2c_transfer(poweroff_restart_client->adapter, msgs, ARRAY_SIZE(msgs)); + if (res < 0) + dev_warn(&poweroff_restart_client->dev, + "Failed to restart (err = %d)\n", res); + + return NOTIFY_DONE; +} + +static struct notifier_block ntxec_restart_handler = { + .notifier_call = ntxec_restart, + .priority = 128, +}; + +static const struct regmap_config regmap_config = { + .name = "ntxec", + .reg_bits = 8, + .val_bits = 16, + .cache_type = REGCACHE_NONE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static const struct mfd_cell ntxec_subdevices[] = { + { .name = "ntxec-rtc" }, + { .name = "ntxec-pwm" }, +}; + +static int ntxec_probe(struct i2c_client *client) +{ + struct ntxec *ec; + unsigned int version; + int res; + + ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL); + if (!ec) + return -ENOMEM; + + ec->dev = &client->dev; + + ec->regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(ec->regmap)) { + dev_err(ec->dev, "Failed to set up regmap for device\n"); + return PTR_ERR(ec->regmap); + } + + /* Determine the firmware version */ + res = regmap_read(ec->regmap, NTXEC_REG_VERSION, &version); + if (res < 0) { + dev_err(ec->dev, "Failed to read firmware version number\n"); + return res; + } + + /* Bail out if we encounter an unknown firmware version */ + switch (version) { + case NTXEC_VERSION_KOBO_AURA: + break; + default: + dev_err(ec->dev, + "Netronix embedded controller version %04x is not supported.\n", + version); + return -ENODEV; + } + + dev_info(ec->dev, + "Netronix embedded controller version %04x detected.\n", version); + + if (of_device_is_system_power_controller(ec->dev->of_node)) { + /* + * Set the 'powerkeep' bit. This is necessary on some boards + * in order to keep the system running. + */ + res = regmap_write(ec->regmap, NTXEC_REG_POWERKEEP, + NTXEC_POWERKEEP_VALUE); + if (res < 0) + return res; + + if (poweroff_restart_client) + /* + * Another instance of the driver already took + * poweroff/restart duties. + */ + dev_err(ec->dev, "poweroff_restart_client already assigned\n"); + else + poweroff_restart_client = client; + + if (pm_power_off) + /* Another driver already registered a poweroff handler. */ + dev_err(ec->dev, "pm_power_off already assigned\n"); + else + pm_power_off = ntxec_poweroff; + + res = register_restart_handler(&ntxec_restart_handler); + if (res) + dev_err(ec->dev, + "Failed to register restart handler: %d\n", res); + } + + i2c_set_clientdata(client, ec); + + res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE, ntxec_subdevices, + ARRAY_SIZE(ntxec_subdevices), NULL, 0, NULL); + if (res) + dev_err(ec->dev, "Failed to add subdevices: %d\n", res); + + return res; +} + +static int ntxec_remove(struct i2c_client *client) +{ + if (client == poweroff_restart_client) { + poweroff_restart_client = NULL; + pm_power_off = NULL; + unregister_restart_handler(&ntxec_restart_handler); + } + + return 0; +} + +static const struct of_device_id of_ntxec_match_table[] = { + { .compatible = "netronix,ntxec", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_ntxec_match_table); + +static struct i2c_driver ntxec_driver = { + .driver = { + .name = "ntxec", + .of_match_table = of_ntxec_match_table, + }, + .probe_new = ntxec_probe, + .remove = ntxec_remove, +}; +module_i2c_driver(ntxec_driver); + +MODULE_AUTHOR("Jonathan Neuschäfer "); +MODULE_DESCRIPTION("Core driver for Netronix EC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From f7cb7fe34db9f32e8b1c13ecc823112480b875f8 Mon Sep 17 00:00:00 2001 From: Cristian Ciocaltea Date: Tue, 26 Jan 2021 11:55:59 +0200 Subject: mfd: Add MFD driver for ATC260x PMICs Add initial support for the Actions Semi ATC260x PMICs which integrates Audio Codec, Power management, Clock generation and GPIO controller blocks. For the moment this driver only supports Regulator, Poweroff and Onkey functionalities for the ATC2603C and ATC2609A chip variants. Since the PMICs can be accessed using both I2C and SPI buses, the following driver structure has been adopted: -----> atc260x-core.c (Implements core functionalities) / ATC260x --------> atc260x-i2c.c (Implements I2C interface) \ -----> atc260x-spi.c (Implements SPI interface - TODO) Co-developed-by: Manivannan Sadhasivam Signed-off-by: Manivannan Sadhasivam Signed-off-by: Cristian Ciocaltea Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 18 +++ drivers/mfd/Makefile | 3 + drivers/mfd/atc260x-core.c | 310 +++++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/atc260x-i2c.c | 64 ++++++++++ 4 files changed, 395 insertions(+) create mode 100644 drivers/mfd/atc260x-core.c create mode 100644 drivers/mfd/atc260x-i2c.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b74efa469e90..f9b43f15790b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2055,6 +2055,24 @@ config MFD_WCD934X This driver provides common support WCD934x audio codec and its associated Pin Controller, Soundwire Controller and Audio codec. +config MFD_ATC260X + tristate + select MFD_CORE + select REGMAP + select REGMAP_IRQ + +config MFD_ATC260X_I2C + tristate "Actions Semi ATC260x PMICs with I2C" + select MFD_ATC260X + select REGMAP_I2C + depends on I2C + help + Support for the Actions Semi ATC260x PMICs controlled via I2C. + + This driver provides common support for accessing the ATC2603C + and ATC2609A chip variants, additional drivers must be enabled + in order to use the functionality of the device. + config MFD_KHADAS_MCU tristate "Support for Khadas System control Microcontroller" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 834f5463af28..f7872d0bd570 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -268,3 +268,6 @@ obj-$(CONFIG_MFD_ACER_A500_EC) += acer-ec-a500.o obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o obj-$(CONFIG_MFD_INTEL_M10_BMC) += intel-m10-bmc.o + +obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o +obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o diff --git a/drivers/mfd/atc260x-core.c b/drivers/mfd/atc260x-core.c new file mode 100644 index 000000000000..7148ff5b05b1 --- /dev/null +++ b/drivers/mfd/atc260x-core.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Core support for ATC260x PMICs + * + * Copyright (C) 2019 Manivannan Sadhasivam + * Copyright (C) 2020 Cristian Ciocaltea + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ATC260X_CHIP_REV_MAX 31 + +struct atc260x_init_regs { + unsigned int cmu_devrst; + unsigned int cmu_devrst_ints; + unsigned int ints_msk; + unsigned int pad_en; + unsigned int pad_en_extirq; +}; + +static void regmap_lock_mutex(void *__mutex) +{ + struct mutex *mutex = __mutex; + + /* + * Using regmap within an atomic context (e.g. accessing a PMIC when + * powering system down) is normally allowed only if the regmap type + * is MMIO and the regcache type is either REGCACHE_NONE or + * REGCACHE_FLAT. For slow buses like I2C and SPI, the regmap is + * internally protected by a mutex which is acquired non-atomically. + * + * Let's improve this by using a customized locking scheme inspired + * from I2C atomic transfer. See i2c_in_atomic_xfer_mode() for a + * starting point. + */ + if (system_state > SYSTEM_RUNNING && irqs_disabled()) + mutex_trylock(mutex); + else + mutex_lock(mutex); +} + +static void regmap_unlock_mutex(void *__mutex) +{ + struct mutex *mutex = __mutex; + + mutex_unlock(mutex); +} + +static const struct regmap_config atc2603c_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = ATC2603C_SADDR, + .cache_type = REGCACHE_NONE, +}; + +static const struct regmap_config atc2609a_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .max_register = ATC2609A_SADDR, + .cache_type = REGCACHE_NONE, +}; + +static const struct regmap_irq atc2603c_regmap_irqs[] = { + REGMAP_IRQ_REG(ATC2603C_IRQ_AUDIO, 0, ATC2603C_INTS_MSK_AUDIO), + REGMAP_IRQ_REG(ATC2603C_IRQ_OV, 0, ATC2603C_INTS_MSK_OV), + REGMAP_IRQ_REG(ATC2603C_IRQ_OC, 0, ATC2603C_INTS_MSK_OC), + REGMAP_IRQ_REG(ATC2603C_IRQ_OT, 0, ATC2603C_INTS_MSK_OT), + REGMAP_IRQ_REG(ATC2603C_IRQ_UV, 0, ATC2603C_INTS_MSK_UV), + REGMAP_IRQ_REG(ATC2603C_IRQ_ALARM, 0, ATC2603C_INTS_MSK_ALARM), + REGMAP_IRQ_REG(ATC2603C_IRQ_ONOFF, 0, ATC2603C_INTS_MSK_ONOFF), + REGMAP_IRQ_REG(ATC2603C_IRQ_SGPIO, 0, ATC2603C_INTS_MSK_SGPIO), + REGMAP_IRQ_REG(ATC2603C_IRQ_IR, 0, ATC2603C_INTS_MSK_IR), + REGMAP_IRQ_REG(ATC2603C_IRQ_REMCON, 0, ATC2603C_INTS_MSK_REMCON), + REGMAP_IRQ_REG(ATC2603C_IRQ_POWER_IN, 0, ATC2603C_INTS_MSK_POWERIN), +}; + +static const struct regmap_irq atc2609a_regmap_irqs[] = { + REGMAP_IRQ_REG(ATC2609A_IRQ_AUDIO, 0, ATC2609A_INTS_MSK_AUDIO), + REGMAP_IRQ_REG(ATC2609A_IRQ_OV, 0, ATC2609A_INTS_MSK_OV), + REGMAP_IRQ_REG(ATC2609A_IRQ_OC, 0, ATC2609A_INTS_MSK_OC), + REGMAP_IRQ_REG(ATC2609A_IRQ_OT, 0, ATC2609A_INTS_MSK_OT), + REGMAP_IRQ_REG(ATC2609A_IRQ_UV, 0, ATC2609A_INTS_MSK_UV), + REGMAP_IRQ_REG(ATC2609A_IRQ_ALARM, 0, ATC2609A_INTS_MSK_ALARM), + REGMAP_IRQ_REG(ATC2609A_IRQ_ONOFF, 0, ATC2609A_INTS_MSK_ONOFF), + REGMAP_IRQ_REG(ATC2609A_IRQ_WKUP, 0, ATC2609A_INTS_MSK_WKUP), + REGMAP_IRQ_REG(ATC2609A_IRQ_IR, 0, ATC2609A_INTS_MSK_IR), + REGMAP_IRQ_REG(ATC2609A_IRQ_REMCON, 0, ATC2609A_INTS_MSK_REMCON), + REGMAP_IRQ_REG(ATC2609A_IRQ_POWER_IN, 0, ATC2609A_INTS_MSK_POWERIN), +}; + +static const struct regmap_irq_chip atc2603c_regmap_irq_chip = { + .name = "atc2603c", + .irqs = atc2603c_regmap_irqs, + .num_irqs = ARRAY_SIZE(atc2603c_regmap_irqs), + .num_regs = 1, + .status_base = ATC2603C_INTS_PD, + .mask_base = ATC2603C_INTS_MSK, + .mask_invert = true, +}; + +static const struct regmap_irq_chip atc2609a_regmap_irq_chip = { + .name = "atc2609a", + .irqs = atc2609a_regmap_irqs, + .num_irqs = ARRAY_SIZE(atc2609a_regmap_irqs), + .num_regs = 1, + .status_base = ATC2609A_INTS_PD, + .mask_base = ATC2609A_INTS_MSK, + .mask_invert = true, +}; + +static const struct resource atc2603c_onkey_resources[] = { + DEFINE_RES_IRQ(ATC2603C_IRQ_ONOFF), +}; + +static const struct resource atc2609a_onkey_resources[] = { + DEFINE_RES_IRQ(ATC2609A_IRQ_ONOFF), +}; + +static const struct mfd_cell atc2603c_mfd_cells[] = { + { .name = "atc260x-regulator" }, + { .name = "atc260x-pwrc" }, + { + .name = "atc260x-onkey", + .num_resources = ARRAY_SIZE(atc2603c_onkey_resources), + .resources = atc2603c_onkey_resources, + }, +}; + +static const struct mfd_cell atc2609a_mfd_cells[] = { + { .name = "atc260x-regulator" }, + { .name = "atc260x-pwrc" }, + { + .name = "atc260x-onkey", + .num_resources = ARRAY_SIZE(atc2609a_onkey_resources), + .resources = atc2609a_onkey_resources, + }, +}; + +static const struct atc260x_init_regs atc2603c_init_regs = { + .cmu_devrst = ATC2603C_CMU_DEVRST, + .cmu_devrst_ints = ATC2603C_CMU_DEVRST_INTS, + .ints_msk = ATC2603C_INTS_MSK, + .pad_en = ATC2603C_PAD_EN, + .pad_en_extirq = ATC2603C_PAD_EN_EXTIRQ, +}; + +static const struct atc260x_init_regs atc2609a_init_regs = { + .cmu_devrst = ATC2609A_CMU_DEVRST, + .cmu_devrst_ints = ATC2609A_CMU_DEVRST_INTS, + .ints_msk = ATC2609A_INTS_MSK, + .pad_en = ATC2609A_PAD_EN, + .pad_en_extirq = ATC2609A_PAD_EN_EXTIRQ, +}; + +static void atc260x_cmu_reset(struct atc260x *atc260x) +{ + const struct atc260x_init_regs *regs = atc260x->init_regs; + + /* Assert reset */ + regmap_update_bits(atc260x->regmap, regs->cmu_devrst, + regs->cmu_devrst_ints, ~regs->cmu_devrst_ints); + + /* De-assert reset */ + regmap_update_bits(atc260x->regmap, regs->cmu_devrst, + regs->cmu_devrst_ints, regs->cmu_devrst_ints); +} + +static void atc260x_dev_init(struct atc260x *atc260x) +{ + const struct atc260x_init_regs *regs = atc260x->init_regs; + + /* Initialize interrupt block */ + atc260x_cmu_reset(atc260x); + + /* Disable all interrupt sources */ + regmap_write(atc260x->regmap, regs->ints_msk, 0); + + /* Enable EXTIRQ pad */ + regmap_update_bits(atc260x->regmap, regs->pad_en, + regs->pad_en_extirq, regs->pad_en_extirq); +} + +/** + * atc260x_match_device(): Setup ATC260x variant related fields + * + * @atc260x: ATC260x device to setup (.dev field must be set) + * @regmap_cfg: regmap config associated with this ATC260x device + * + * This lets the ATC260x core configure the MFD cells and register maps + * for later use. + */ +int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_cfg) +{ + struct device *dev = atc260x->dev; + const void *of_data; + + of_data = of_device_get_match_data(dev); + if (!of_data) + return -ENODEV; + + atc260x->ic_type = (unsigned long)of_data; + + switch (atc260x->ic_type) { + case ATC2603C: + *regmap_cfg = atc2603c_regmap_config; + atc260x->regmap_irq_chip = &atc2603c_regmap_irq_chip; + atc260x->cells = atc2603c_mfd_cells; + atc260x->nr_cells = ARRAY_SIZE(atc2603c_mfd_cells); + atc260x->type_name = "atc2603c"; + atc260x->rev_reg = ATC2603C_CHIP_VER; + atc260x->init_regs = &atc2603c_init_regs; + break; + case ATC2609A: + *regmap_cfg = atc2609a_regmap_config; + atc260x->regmap_irq_chip = &atc2609a_regmap_irq_chip; + atc260x->cells = atc2609a_mfd_cells; + atc260x->nr_cells = ARRAY_SIZE(atc2609a_mfd_cells); + atc260x->type_name = "atc2609a"; + atc260x->rev_reg = ATC2609A_CHIP_VER; + atc260x->init_regs = &atc2609a_init_regs; + break; + default: + dev_err(dev, "Unsupported ATC260x device type: %u\n", + atc260x->ic_type); + return -EINVAL; + } + + atc260x->regmap_mutex = devm_kzalloc(dev, sizeof(*atc260x->regmap_mutex), + GFP_KERNEL); + if (!atc260x->regmap_mutex) + return -ENOMEM; + + mutex_init(atc260x->regmap_mutex); + + regmap_cfg->lock = regmap_lock_mutex, + regmap_cfg->unlock = regmap_unlock_mutex, + regmap_cfg->lock_arg = atc260x->regmap_mutex; + + return 0; +} +EXPORT_SYMBOL_GPL(atc260x_match_device); + +/** + * atc260x_device_probe(): Probe a configured ATC260x device + * + * @atc260x: ATC260x device to probe (must be configured) + * + * This function lets the ATC260x core register the ATC260x MFD devices + * and IRQCHIP. The ATC260x device passed in must be fully configured + * with atc260x_match_device, its IRQ set, and regmap created. + */ +int atc260x_device_probe(struct atc260x *atc260x) +{ + struct device *dev = atc260x->dev; + unsigned int chip_rev; + int ret; + + if (!atc260x->irq) { + dev_err(dev, "No interrupt support\n"); + return -EINVAL; + } + + /* Initialize the hardware */ + atc260x_dev_init(atc260x); + + ret = regmap_read(atc260x->regmap, atc260x->rev_reg, &chip_rev); + if (ret) { + dev_err(dev, "Failed to get chip revision\n"); + return ret; + } + + if (chip_rev > ATC260X_CHIP_REV_MAX) { + dev_err(dev, "Unknown chip revision: %u\n", chip_rev); + return -EINVAL; + } + + atc260x->ic_ver = __ffs(chip_rev + 1U); + + dev_info(dev, "Detected chip type %s rev.%c\n", + atc260x->type_name, 'A' + atc260x->ic_ver); + + ret = devm_regmap_add_irq_chip(dev, atc260x->regmap, atc260x->irq, IRQF_ONESHOT, + -1, atc260x->regmap_irq_chip, &atc260x->irq_data); + if (ret) { + dev_err(dev, "Failed to add IRQ chip: %d\n", ret); + return ret; + } + + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, + atc260x->cells, atc260x->nr_cells, NULL, 0, + regmap_irq_get_domain(atc260x->irq_data)); + if (ret) { + dev_err(dev, "Failed to add child devices: %d\n", ret); + regmap_del_irq_chip(atc260x->irq, atc260x->irq_data); + } + + return ret; +} +EXPORT_SYMBOL_GPL(atc260x_device_probe); + +MODULE_DESCRIPTION("ATC260x PMICs Core support"); +MODULE_AUTHOR("Manivannan Sadhasivam "); +MODULE_AUTHOR("Cristian Ciocaltea "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/atc260x-i2c.c b/drivers/mfd/atc260x-i2c.c new file mode 100644 index 000000000000..362005703367 --- /dev/null +++ b/drivers/mfd/atc260x-i2c.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * I2C bus interface for ATC260x PMICs + * + * Copyright (C) 2019 Manivannan Sadhasivam + * Copyright (C) 2020 Cristian Ciocaltea + */ + +#include +#include +#include +#include +#include + +static int atc260x_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct atc260x *atc260x; + struct regmap_config regmap_cfg; + int ret; + + atc260x = devm_kzalloc(&client->dev, sizeof(*atc260x), GFP_KERNEL); + if (!atc260x) + return -ENOMEM; + + atc260x->dev = &client->dev; + atc260x->irq = client->irq; + + ret = atc260x_match_device(atc260x, ®map_cfg); + if (ret) + return ret; + + i2c_set_clientdata(client, atc260x); + + atc260x->regmap = devm_regmap_init_i2c(client, ®map_cfg); + if (IS_ERR(atc260x->regmap)) { + ret = PTR_ERR(atc260x->regmap); + dev_err(&client->dev, "failed to init regmap: %d\n", ret); + return ret; + } + + return atc260x_device_probe(atc260x); +} + +const struct of_device_id atc260x_i2c_of_match[] = { + { .compatible = "actions,atc2603c", .data = (void *)ATC2603C }, + { .compatible = "actions,atc2609a", .data = (void *)ATC2609A }, + { } +}; +MODULE_DEVICE_TABLE(of, atc260x_i2c_of_match); + +static struct i2c_driver atc260x_i2c_driver = { + .driver = { + .name = "atc260x", + .of_match_table = of_match_ptr(atc260x_i2c_of_match), + }, + .probe = atc260x_i2c_probe, +}; +module_i2c_driver(atc260x_i2c_driver); + +MODULE_DESCRIPTION("ATC260x PMICs I2C bus interface"); +MODULE_AUTHOR("Manivannan Sadhasivam "); +MODULE_AUTHOR("Cristian Ciocaltea "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4e0b9ea85e6fb7654a3d28c23bbde736ce1592ae Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 7 Mar 2021 16:17:55 +0100 Subject: mfd: arizona: Drop arizona-extcon cells The arizona jack-dection handling is being reworked so that the codec-child-device drivers directly handle jack-detect themselves, so it is no longer necessary to instantiate "arizona-extcon" child-devices. Signed-off-by: Hans de Goede Acked-by: Charles Keepax Tested-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-core.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 75f1bc671d59..ce6fe6de34f8 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -881,11 +881,6 @@ static const char * const wm5102_supplies[] = { static const struct mfd_cell wm5102_devs[] = { { .name = "arizona-micsupp" }, { .name = "arizona-gpio" }, - { - .name = "arizona-extcon", - .parent_supplies = wm5102_supplies, - .num_parent_supplies = 1, /* We only need MICVDD */ - }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { @@ -898,11 +893,6 @@ static const struct mfd_cell wm5102_devs[] = { static const struct mfd_cell wm5110_devs[] = { { .name = "arizona-micsupp" }, { .name = "arizona-gpio" }, - { - .name = "arizona-extcon", - .parent_supplies = wm5102_supplies, - .num_parent_supplies = 1, /* We only need MICVDD */ - }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { @@ -939,11 +929,6 @@ static const char * const wm8997_supplies[] = { static const struct mfd_cell wm8997_devs[] = { { .name = "arizona-micsupp" }, { .name = "arizona-gpio" }, - { - .name = "arizona-extcon", - .parent_supplies = wm8997_supplies, - .num_parent_supplies = 1, /* We only need MICVDD */ - }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { @@ -956,11 +941,6 @@ static const struct mfd_cell wm8997_devs[] = { static const struct mfd_cell wm8998_devs[] = { { .name = "arizona-micsupp" }, { .name = "arizona-gpio" }, - { - .name = "arizona-extcon", - .parent_supplies = wm5102_supplies, - .num_parent_supplies = 1, /* We only need MICVDD */ - }, { .name = "arizona-haptics" }, { .name = "arizona-pwm" }, { -- cgit v1.2.3 From 316d0d92fbc9b926bda8ce7ccc109de0dccb4d92 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 5 Apr 2021 14:40:44 +0300 Subject: mfd: bd718x7: simplify by cleaning unnecessary device data Most ROHM PMIC sub-devices only use the regmap pointer from parent device. They can obtain this by dev_get_regamap so in most cases the MFD device does not need to allocate and populate the driver data. Simplify drivers by removing this. The BD70528 still needs the access to watchdog mutex so keep rohm_regmap_dev in use on BD70528 RTC and WDG drivers for now. Signed-off-by: Matti Vaittinen Signed-off-by: Lee Jones --- drivers/mfd/rohm-bd718x7.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c index c32c1b6c98fa..bfd81f78beae 100644 --- a/drivers/mfd/rohm-bd718x7.c +++ b/drivers/mfd/rohm-bd718x7.c @@ -91,9 +91,9 @@ static const struct regmap_config bd718xx_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int bd718xx_init_press_duration(struct bd718xx *bd718xx) +static int bd718xx_init_press_duration(struct regmap *regmap, + struct device *dev) { - struct device* dev = bd718xx->chip.dev; u32 short_press_ms, long_press_ms; u32 short_press_value, long_press_value; int ret; @@ -102,8 +102,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx) &short_press_ms); if (!ret) { short_press_value = min(15u, (short_press_ms + 250) / 500); - ret = regmap_update_bits(bd718xx->chip.regmap, - BD718XX_REG_PWRONCONFIG0, + ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG0, BD718XX_PWRBTN_PRESS_DURATION_MASK, short_press_value); if (ret) { @@ -116,8 +115,7 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx) &long_press_ms); if (!ret) { long_press_value = min(15u, (long_press_ms + 500) / 1000); - ret = regmap_update_bits(bd718xx->chip.regmap, - BD718XX_REG_PWRONCONFIG1, + ret = regmap_update_bits(regmap, BD718XX_REG_PWRONCONFIG1, BD718XX_PWRBTN_PRESS_DURATION_MASK, long_press_value); if (ret) { @@ -132,7 +130,8 @@ static int bd718xx_init_press_duration(struct bd718xx *bd718xx) static int bd718xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct bd718xx *bd718xx; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; int ret; unsigned int chip_type; struct mfd_cell *mfd; @@ -142,13 +141,6 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "No IRQ configured\n"); return -EINVAL; } - - bd718xx = devm_kzalloc(&i2c->dev, sizeof(struct bd718xx), GFP_KERNEL); - - if (!bd718xx) - return -ENOMEM; - - bd718xx->chip_irq = i2c->irq; chip_type = (unsigned int)(uintptr_t) of_device_get_match_data(&i2c->dev); switch (chip_type) { @@ -164,29 +156,26 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Unknown device type"); return -EINVAL; } - bd718xx->chip.dev = &i2c->dev; - dev_set_drvdata(&i2c->dev, bd718xx); - bd718xx->chip.regmap = devm_regmap_init_i2c(i2c, - &bd718xx_regmap_config); - if (IS_ERR(bd718xx->chip.regmap)) { + regmap = devm_regmap_init_i2c(i2c, &bd718xx_regmap_config); + if (IS_ERR(regmap)) { dev_err(&i2c->dev, "regmap initialization failed\n"); - return PTR_ERR(bd718xx->chip.regmap); + return PTR_ERR(regmap); } - ret = devm_regmap_add_irq_chip(&i2c->dev, bd718xx->chip.regmap, - bd718xx->chip_irq, IRQF_ONESHOT, 0, - &bd718xx_irq_chip, &bd718xx->irq_data); + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq, + IRQF_ONESHOT, 0, &bd718xx_irq_chip, + &irq_data); if (ret) { dev_err(&i2c->dev, "Failed to add irq_chip\n"); return ret; } - ret = bd718xx_init_press_duration(bd718xx); + ret = bd718xx_init_press_duration(regmap, &i2c->dev); if (ret) return ret; - ret = regmap_irq_get_virq(bd718xx->irq_data, BD718XX_INT_PWRBTN_S); + ret = regmap_irq_get_virq(irq_data, BD718XX_INT_PWRBTN_S); if (ret < 0) { dev_err(&i2c->dev, "Failed to get the IRQ\n"); @@ -195,9 +184,9 @@ static int bd718xx_i2c_probe(struct i2c_client *i2c, button.irq = ret; - ret = devm_mfd_add_devices(bd718xx->chip.dev, PLATFORM_DEVID_AUTO, + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells, NULL, 0, - regmap_irq_get_domain(bd718xx->irq_data)); + regmap_irq_get_domain(irq_data)); if (ret) dev_err(&i2c->dev, "Failed to create subdevices\n"); -- cgit v1.2.3 From 4dcdcfd5abb34d3139669fcd830b756d45678c47 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Mon, 5 Apr 2021 14:42:51 +0300 Subject: mfd: Support for ROHM BD71815 PMIC core Add core support for ROHM BD71815 Power Management IC. The IC integrates regulators, a battery charger with a coulomb counter, a real-time clock (RTC), clock gate and general-purpose outputs (GPO). Signed-off-by: Matti Vaittinen Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 15 +- drivers/mfd/rohm-bd71828.c | 486 +++++++++++++++++++++++++++++++++------------ 2 files changed, 368 insertions(+), 133 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b74efa469e90..60d9ae559f0a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1975,19 +1975,20 @@ config MFD_ROHM_BD70528 charger. config MFD_ROHM_BD71828 - tristate "ROHM BD71828 Power Management IC" + tristate "ROHM BD71828 and BD71815 Power Management IC" depends on I2C=y depends on OF select REGMAP_I2C select REGMAP_IRQ select MFD_CORE help - Select this option to get support for the ROHM BD71828 Power - Management IC. BD71828GW is a single-chip power management IC for - battery-powered portable devices. The IC integrates 7 buck - converters, 7 LDOs, and a 1500 mA single-cell linear charger. - Also included is a Coulomb counter, a real-time clock (RTC), and - a 32.768 kHz clock gate. + Select this option to get support for the ROHM BD71828 and BD71815 + Power Management ICs. BD71828GW and BD71815AGW are single-chip power + management ICs mainly for battery-powered portable devices. + The BD71828 integrates 7 buck converters and 7 LDOs. The BD71815 + has 5 bucks, 7 LDOs, and a boost for driving LEDs. Both ICs provide + also a single-cell linear charger, a Coulomb counter, a real-time + clock (RTC), GPIOs and a 32.768 kHz clock gate. config MFD_STM32_LPTIMER tristate "Support for STM32 Low-Power Timer" diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c index 210261d026f2..714d9fcbf07b 100644 --- a/drivers/mfd/rohm-bd71828.c +++ b/drivers/mfd/rohm-bd71828.c @@ -2,7 +2,7 @@ // // Copyright (C) 2019 ROHM Semiconductors // -// ROHM BD71828 PMIC driver +// ROHM BD71828/BD71815 PMIC driver #include #include @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -29,12 +31,84 @@ static struct gpio_keys_platform_data bd71828_powerkey_data = { .name = "bd71828-pwrkey", }; -static const struct resource rtc_irqs[] = { +static const struct resource bd71815_rtc_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd71815-rtc-alm-0"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd71815-rtc-alm-1"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd71815-rtc-alm-2"), +}; + +static const struct resource bd71828_rtc_irqs[] = { DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd71828-rtc-alm-0"), DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd71828-rtc-alm-1"), DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd71828-rtc-alm-2"), }; +static struct resource bd71815_power_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_RMV, "bd71815-dcin-rmv"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_OUT, "bd71815-clps-out"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CLPS_IN, "bd71815-clps-in"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_RES, "bd71815-dcin-ovp-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_OVP_DET, "bd71815-dcin-ovp-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_RES, "bd71815-dcin-mon-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_DCIN_MON_DET, "bd71815-dcin-mon-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_RES, "bd71815-vsys-uv-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_UV_DET, "bd71815-vsys-uv-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_RES, "bd71815-vsys-low-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_LOW_DET, "bd71815-vsys-low-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_VSYS_MON_RES, "bd71815-vsys-mon-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TEMP, "bd71815-chg-wdg-temp"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_WDG_TIME, "bd71815-chg-wdg"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_RES, "bd71815-rechg-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RECHARGE_DET, "bd71815-rechg-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, "bd71815-ranged-temp-transit"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_CHG_STATE_TRANSITION, "bd71815-chg-state-change"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_NORMAL, "bd71815-bat-temp-normal"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_TEMP_ERANGE, "bd71815-bat-temp-erange"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_REMOVED, "bd71815-bat-rmv"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DETECTED, "bd71815-bat-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_REMOVED, "bd71815-therm-rmv"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_THERM_DETECTED, "bd71815-therm-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_DEAD, "bd71815-bat-dead"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_RES, "bd71815-bat-short-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_SHORTC_DET, "bd71815-bat-short-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_RES, "bd71815-bat-low-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_LOW_VOLT_DET, "bd71815-bat-low-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_RES, "bd71815-bat-over-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_VOLT_DET, "bd71815-bat-over-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_RES, "bd71815-bat-mon-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_MON_DET, "bd71815-bat-mon-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON1, "bd71815-bat-cc-mon1"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON2, "bd71815-bat-cc-mon2"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_CC_MON3, "bd71815-bat-cc-mon3"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_RES, "bd71815-bat-oc1-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_1_DET, "bd71815-bat-oc1-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_RES, "bd71815-bat-oc2-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_2_DET, "bd71815-bat-oc2-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_RES, "bd71815-bat-oc3-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_BAT_OVER_CURR_3_DET, "bd71815-bat-oc3-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_RES, "bd71815-bat-low-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_LOW_DET, "bd71815-bat-low-det"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_RES, "bd71815-bat-hi-res"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_TEMP_BAT_HI_DET, "bd71815-bat-hi-det"), +}; + +static struct mfd_cell bd71815_mfd_cells[] = { + { .name = "bd71815-pmic", }, + { .name = "bd71815-clk", }, + { .name = "bd71815-gpo", }, + { + .name = "bd71815-power", + .num_resources = ARRAY_SIZE(bd71815_power_irqs), + .resources = &bd71815_power_irqs[0], + }, + { + .name = "bd71815-rtc", + .num_resources = ARRAY_SIZE(bd71815_rtc_irqs), + .resources = &bd71815_rtc_irqs[0], + }, +}; + static struct mfd_cell bd71828_mfd_cells[] = { { .name = "bd71828-pmic", }, { .name = "bd71828-gpio", }, @@ -47,8 +121,8 @@ static struct mfd_cell bd71828_mfd_cells[] = { { .name = "bd71827-power", }, { .name = "bd71828-rtc", - .resources = rtc_irqs, - .num_resources = ARRAY_SIZE(rtc_irqs), + .resources = bd71828_rtc_irqs, + .num_resources = ARRAY_SIZE(bd71828_rtc_irqs), }, { .name = "gpio-keys", .platform_data = &bd71828_powerkey_data, @@ -56,7 +130,35 @@ static struct mfd_cell bd71828_mfd_cells[] = { }, }; -static const struct regmap_range volatile_ranges[] = { +static const struct regmap_range bd71815_volatile_ranges[] = { + { + .range_min = BD71815_REG_SEC, + .range_max = BD71815_REG_YEAR, + }, { + .range_min = BD71815_REG_CONF, + .range_max = BD71815_REG_BAT_TEMP, + }, { + .range_min = BD71815_REG_VM_IBAT_U, + .range_max = BD71815_REG_CC_CTRL, + }, { + .range_min = BD71815_REG_CC_STAT, + .range_max = BD71815_REG_CC_CURCD_L, + }, { + .range_min = BD71815_REG_VM_BTMP_MON, + .range_max = BD71815_REG_VM_BTMP_MON, + }, { + .range_min = BD71815_REG_INT_STAT, + .range_max = BD71815_REG_INT_UPDATE, + }, { + .range_min = BD71815_REG_VM_VSYS_U, + .range_max = BD71815_REG_REX_CTRL_1, + }, { + .range_min = BD71815_REG_FULL_CCNTD_3, + .range_max = BD71815_REG_CCNTD_CHG_2, + }, +}; + +static const struct regmap_range bd71828_volatile_ranges[] = { { .range_min = BD71828_REG_PS_CTRL_1, .range_max = BD71828_REG_PS_CTRL_1, @@ -80,15 +182,28 @@ static const struct regmap_range volatile_ranges[] = { }, }; -static const struct regmap_access_table volatile_regs = { - .yes_ranges = &volatile_ranges[0], - .n_yes_ranges = ARRAY_SIZE(volatile_ranges), +static const struct regmap_access_table bd71815_volatile_regs = { + .yes_ranges = &bd71815_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bd71815_volatile_ranges), +}; + +static const struct regmap_access_table bd71828_volatile_regs = { + .yes_ranges = &bd71828_volatile_ranges[0], + .n_yes_ranges = ARRAY_SIZE(bd71828_volatile_ranges), +}; + +static const struct regmap_config bd71815_regmap = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &bd71815_volatile_regs, + .max_register = BD71815_MAX_REGISTER - 1, + .cache_type = REGCACHE_RBTREE, }; -static struct regmap_config bd71828_regmap = { +static const struct regmap_config bd71828_regmap = { .reg_bits = 8, .val_bits = 8, - .volatile_table = &volatile_regs, + .volatile_table = &bd71828_volatile_regs, .max_register = BD71828_MAX_REGISTER, .cache_type = REGCACHE_RBTREE, }; @@ -96,7 +211,7 @@ static struct regmap_config bd71828_regmap = { /* * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can * access corect sub-IRQ registers based on bits that are set in main IRQ - * register. + * register. BD71815 and BD71828 have same sub-register-block offests. */ static unsigned int bit0_offsets[] = {11}; /* RTC IRQ */ @@ -108,7 +223,7 @@ static unsigned int bit5_offsets[] = {3}; /* VSYS IRQ */ static unsigned int bit6_offsets[] = {1, 2}; /* DCIN IRQ */ static unsigned int bit7_offsets[] = {0}; /* BUCK IRQ */ -static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = { +static struct regmap_irq_sub_irq_map bd718xx_sub_irq_offsets[] = { REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), @@ -119,6 +234,88 @@ static struct regmap_irq_sub_irq_map bd71828_sub_irq_offsets[] = { REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), }; +static const struct regmap_irq bd71815_irqs[] = { + REGMAP_IRQ_REG(BD71815_INT_BUCK1_OCP, 0, BD71815_INT_BUCK1_OCP_MASK), + REGMAP_IRQ_REG(BD71815_INT_BUCK2_OCP, 0, BD71815_INT_BUCK2_OCP_MASK), + REGMAP_IRQ_REG(BD71815_INT_BUCK3_OCP, 0, BD71815_INT_BUCK3_OCP_MASK), + REGMAP_IRQ_REG(BD71815_INT_BUCK4_OCP, 0, BD71815_INT_BUCK4_OCP_MASK), + REGMAP_IRQ_REG(BD71815_INT_BUCK5_OCP, 0, BD71815_INT_BUCK5_OCP_MASK), + REGMAP_IRQ_REG(BD71815_INT_LED_OVP, 0, BD71815_INT_LED_OVP_MASK), + REGMAP_IRQ_REG(BD71815_INT_LED_OCP, 0, BD71815_INT_LED_OCP_MASK), + REGMAP_IRQ_REG(BD71815_INT_LED_SCP, 0, BD71815_INT_LED_SCP_MASK), + /* DCIN1 interrupts */ + REGMAP_IRQ_REG(BD71815_INT_DCIN_RMV, 1, BD71815_INT_DCIN_RMV_MASK), + REGMAP_IRQ_REG(BD71815_INT_CLPS_OUT, 1, BD71815_INT_CLPS_OUT_MASK), + REGMAP_IRQ_REG(BD71815_INT_CLPS_IN, 1, BD71815_INT_CLPS_IN_MASK), + REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_RES, 1, BD71815_INT_DCIN_OVP_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_DCIN_OVP_DET, 1, BD71815_INT_DCIN_OVP_DET_MASK), + /* DCIN2 interrupts */ + REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_RES, 2, BD71815_INT_DCIN_MON_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_DCIN_MON_DET, 2, BD71815_INT_DCIN_MON_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_WDOG, 2, BD71815_INT_WDOG_MASK), + /* Vsys */ + REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_RES, 3, BD71815_INT_VSYS_UV_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_VSYS_UV_DET, 3, BD71815_INT_VSYS_UV_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_RES, 3, BD71815_INT_VSYS_LOW_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_VSYS_LOW_DET, 3, BD71815_INT_VSYS_LOW_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_RES, 3, BD71815_INT_VSYS_MON_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_VSYS_MON_DET, 3, BD71815_INT_VSYS_MON_DET_MASK), + /* Charger */ + REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TEMP, 4, BD71815_INT_CHG_WDG_TEMP_MASK), + REGMAP_IRQ_REG(BD71815_INT_CHG_WDG_TIME, 4, BD71815_INT_CHG_WDG_TIME_MASK), + REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_RES, 4, BD71815_INT_CHG_RECHARGE_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_CHG_RECHARGE_DET, 4, BD71815_INT_CHG_RECHARGE_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_CHG_RANGED_TEMP_TRANSITION, 4, + BD71815_INT_CHG_RANGED_TEMP_TRANSITION_MASK), + REGMAP_IRQ_REG(BD71815_INT_CHG_STATE_TRANSITION, 4, BD71815_INT_CHG_STATE_TRANSITION_MASK), + /* Battery */ + REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_NORMAL, 5, BD71815_INT_BAT_TEMP_NORMAL_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_TEMP_ERANGE, 5, BD71815_INT_BAT_TEMP_ERANGE_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_REMOVED, 5, BD71815_INT_BAT_REMOVED_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_DETECTED, 5, BD71815_INT_BAT_DETECTED_MASK), + REGMAP_IRQ_REG(BD71815_INT_THERM_REMOVED, 5, BD71815_INT_THERM_REMOVED_MASK), + REGMAP_IRQ_REG(BD71815_INT_THERM_DETECTED, 5, BD71815_INT_THERM_DETECTED_MASK), + /* Battery Mon 1 */ + REGMAP_IRQ_REG(BD71815_INT_BAT_DEAD, 6, BD71815_INT_BAT_DEAD_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_RES, 6, BD71815_INT_BAT_SHORTC_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_SHORTC_DET, 6, BD71815_INT_BAT_SHORTC_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_RES, 6, BD71815_INT_BAT_LOW_VOLT_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_LOW_VOLT_DET, 6, BD71815_INT_BAT_LOW_VOLT_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_RES, 6, BD71815_INT_BAT_OVER_VOLT_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_VOLT_DET, 6, BD71815_INT_BAT_OVER_VOLT_DET_MASK), + /* Battery Mon 2 */ + REGMAP_IRQ_REG(BD71815_INT_BAT_MON_RES, 7, BD71815_INT_BAT_MON_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_MON_DET, 7, BD71815_INT_BAT_MON_DET_MASK), + /* Battery Mon 3 (Coulomb counter) */ + REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON1, 8, BD71815_INT_BAT_CC_MON1_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON2, 8, BD71815_INT_BAT_CC_MON2_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_CC_MON3, 8, BD71815_INT_BAT_CC_MON3_MASK), + /* Battery Mon 4 */ + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_RES, 9, BD71815_INT_BAT_OVER_CURR_1_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_1_DET, 9, BD71815_INT_BAT_OVER_CURR_1_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_RES, 9, BD71815_INT_BAT_OVER_CURR_2_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_2_DET, 9, BD71815_INT_BAT_OVER_CURR_2_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_RES, 9, BD71815_INT_BAT_OVER_CURR_3_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_BAT_OVER_CURR_3_DET, 9, BD71815_INT_BAT_OVER_CURR_3_DET_MASK), + /* Temperature */ + REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_RES, 10, BD71815_INT_TEMP_BAT_LOW_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_LOW_DET, 10, BD71815_INT_TEMP_BAT_LOW_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_RES, 10, BD71815_INT_TEMP_BAT_HI_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_TEMP_BAT_HI_DET, 10, BD71815_INT_TEMP_BAT_HI_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_RES, 10, + BD71815_INT_TEMP_CHIP_OVER_125_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_125_DET, 10, + BD71815_INT_TEMP_CHIP_OVER_125_DET_MASK), + REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_RES, 10, + BD71815_INT_TEMP_CHIP_OVER_VF_RES_MASK), + REGMAP_IRQ_REG(BD71815_INT_TEMP_CHIP_OVER_VF_DET, 10, + BD71815_INT_TEMP_CHIP_OVER_VF_DET_MASK), + /* RTC Alarm */ + REGMAP_IRQ_REG(BD71815_INT_RTC0, 11, BD71815_INT_RTC0_MASK), + REGMAP_IRQ_REG(BD71815_INT_RTC1, 11, BD71815_INT_RTC1_MASK), + REGMAP_IRQ_REG(BD71815_INT_RTC2, 11, BD71815_INT_RTC2_MASK), +}; + static struct regmap_irq bd71828_irqs[] = { REGMAP_IRQ_REG(BD71828_INT_BUCK1_OCP, 0, BD71828_INT_BUCK1_OCP_MASK), REGMAP_IRQ_REG(BD71828_INT_BUCK2_OCP, 0, BD71828_INT_BUCK2_OCP_MASK), @@ -134,10 +331,8 @@ static struct regmap_irq bd71828_irqs[] = { REGMAP_IRQ_REG(BD71828_INT_CLPS_OUT, 1, BD71828_INT_CLPS_OUT_MASK), REGMAP_IRQ_REG(BD71828_INT_CLPS_IN, 1, BD71828_INT_CLPS_IN_MASK), /* DCIN2 interrupts */ - REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, - BD71828_INT_DCIN_MON_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, - BD71828_INT_DCIN_MON_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_RES, 2, BD71828_INT_DCIN_MON_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_DCIN_MON_DET, 2, BD71828_INT_DCIN_MON_DET_MASK), REGMAP_IRQ_REG(BD71828_INT_LONGPUSH, 2, BD71828_INT_LONGPUSH_MASK), REGMAP_IRQ_REG(BD71828_INT_MIDPUSH, 2, BD71828_INT_MIDPUSH_MASK), REGMAP_IRQ_REG(BD71828_INT_SHORTPUSH, 2, BD71828_INT_SHORTPUSH_MASK), @@ -145,102 +340,59 @@ static struct regmap_irq bd71828_irqs[] = { REGMAP_IRQ_REG(BD71828_INT_WDOG, 2, BD71828_INT_WDOG_MASK), REGMAP_IRQ_REG(BD71828_INT_SWRESET, 2, BD71828_INT_SWRESET_MASK), /* Vsys */ - REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, - BD71828_INT_VSYS_UV_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, - BD71828_INT_VSYS_UV_DET_MASK), - REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, - BD71828_INT_VSYS_LOW_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, - BD71828_INT_VSYS_LOW_DET_MASK), - REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, - BD71828_INT_VSYS_HALL_IN_MASK), - REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, - BD71828_INT_VSYS_HALL_TOGGLE_MASK), - REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, - BD71828_INT_VSYS_MON_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, - BD71828_INT_VSYS_MON_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_RES, 3, BD71828_INT_VSYS_UV_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_UV_DET, 3, BD71828_INT_VSYS_UV_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_RES, 3, BD71828_INT_VSYS_LOW_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_LOW_DET, 3, BD71828_INT_VSYS_LOW_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_IN, 3, BD71828_INT_VSYS_HALL_IN_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_HALL_TOGGLE, 3, BD71828_INT_VSYS_HALL_TOGGLE_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_RES, 3, BD71828_INT_VSYS_MON_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_VSYS_MON_DET, 3, BD71828_INT_VSYS_MON_DET_MASK), /* Charger */ - REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, - BD71828_INT_CHG_DCIN_ILIM_MASK), - REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, - BD71828_INT_CHG_TOPOFF_TO_DONE_MASK), - REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, - BD71828_INT_CHG_WDG_TEMP_MASK), - REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, - BD71828_INT_CHG_WDG_TIME_MASK), - REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, - BD71828_INT_CHG_RECHARGE_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, - BD71828_INT_CHG_RECHARGE_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_DCIN_ILIM, 4, BD71828_INT_CHG_DCIN_ILIM_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_TOPOFF_TO_DONE, 4, BD71828_INT_CHG_TOPOFF_TO_DONE_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TEMP, 4, BD71828_INT_CHG_WDG_TEMP_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_WDG_TIME, 4, BD71828_INT_CHG_WDG_TIME_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_RES, 4, BD71828_INT_CHG_RECHARGE_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_RECHARGE_DET, 4, BD71828_INT_CHG_RECHARGE_DET_MASK), REGMAP_IRQ_REG(BD71828_INT_CHG_RANGED_TEMP_TRANSITION, 4, BD71828_INT_CHG_RANGED_TEMP_TRANSITION_MASK), - REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, - BD71828_INT_CHG_STATE_TRANSITION_MASK), + REGMAP_IRQ_REG(BD71828_INT_CHG_STATE_TRANSITION, 4, BD71828_INT_CHG_STATE_TRANSITION_MASK), /* Battery */ - REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, - BD71828_INT_BAT_TEMP_NORMAL_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, - BD71828_INT_BAT_TEMP_ERANGE_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, - BD71828_INT_BAT_TEMP_WARN_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, - BD71828_INT_BAT_REMOVED_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, - BD71828_INT_BAT_DETECTED_MASK), - REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, - BD71828_INT_THERM_REMOVED_MASK), - REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, - BD71828_INT_THERM_DETECTED_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_NORMAL, 5, BD71828_INT_BAT_TEMP_NORMAL_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_ERANGE, 5, BD71828_INT_BAT_TEMP_ERANGE_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_TEMP_WARN, 5, BD71828_INT_BAT_TEMP_WARN_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_REMOVED, 5, BD71828_INT_BAT_REMOVED_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_DETECTED, 5, BD71828_INT_BAT_DETECTED_MASK), + REGMAP_IRQ_REG(BD71828_INT_THERM_REMOVED, 5, BD71828_INT_THERM_REMOVED_MASK), + REGMAP_IRQ_REG(BD71828_INT_THERM_DETECTED, 5, BD71828_INT_THERM_DETECTED_MASK), /* Battery Mon 1 */ REGMAP_IRQ_REG(BD71828_INT_BAT_DEAD, 6, BD71828_INT_BAT_DEAD_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, - BD71828_INT_BAT_SHORTC_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, - BD71828_INT_BAT_SHORTC_DET_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, - BD71828_INT_BAT_LOW_VOLT_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, - BD71828_INT_BAT_LOW_VOLT_DET_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, - BD71828_INT_BAT_OVER_VOLT_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, - BD71828_INT_BAT_OVER_VOLT_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_RES, 6, BD71828_INT_BAT_SHORTC_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_SHORTC_DET, 6, BD71828_INT_BAT_SHORTC_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_RES, 6, BD71828_INT_BAT_LOW_VOLT_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_LOW_VOLT_DET, 6, BD71828_INT_BAT_LOW_VOLT_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_RES, 6, BD71828_INT_BAT_OVER_VOLT_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_VOLT_DET, 6, BD71828_INT_BAT_OVER_VOLT_DET_MASK), /* Battery Mon 2 */ - REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, - BD71828_INT_BAT_MON_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, - BD71828_INT_BAT_MON_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_MON_RES, 7, BD71828_INT_BAT_MON_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_MON_DET, 7, BD71828_INT_BAT_MON_DET_MASK), /* Battery Mon 3 (Coulomb counter) */ - REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, - BD71828_INT_BAT_CC_MON1_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, - BD71828_INT_BAT_CC_MON2_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, - BD71828_INT_BAT_CC_MON3_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON1, 8, BD71828_INT_BAT_CC_MON1_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON2, 8, BD71828_INT_BAT_CC_MON2_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_CC_MON3, 8, BD71828_INT_BAT_CC_MON3_MASK), /* Battery Mon 4 */ - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, - BD71828_INT_BAT_OVER_CURR_1_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, - BD71828_INT_BAT_OVER_CURR_1_DET_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, - BD71828_INT_BAT_OVER_CURR_2_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, - BD71828_INT_BAT_OVER_CURR_2_DET_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, - BD71828_INT_BAT_OVER_CURR_3_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, - BD71828_INT_BAT_OVER_CURR_3_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_RES, 9, BD71828_INT_BAT_OVER_CURR_1_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_1_DET, 9, BD71828_INT_BAT_OVER_CURR_1_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_RES, 9, BD71828_INT_BAT_OVER_CURR_2_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_2_DET, 9, BD71828_INT_BAT_OVER_CURR_2_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_RES, 9, BD71828_INT_BAT_OVER_CURR_3_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_BAT_OVER_CURR_3_DET, 9, BD71828_INT_BAT_OVER_CURR_3_DET_MASK), /* Temperature */ - REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, - BD71828_INT_TEMP_BAT_LOW_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, - BD71828_INT_TEMP_BAT_LOW_DET_MASK), - REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, - BD71828_INT_TEMP_BAT_HI_RES_MASK), - REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, - BD71828_INT_TEMP_BAT_HI_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_RES, 10, BD71828_INT_TEMP_BAT_LOW_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_LOW_DET, 10, BD71828_INT_TEMP_BAT_LOW_DET_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_RES, 10, BD71828_INT_TEMP_BAT_HI_RES_MASK), + REGMAP_IRQ_REG(BD71828_INT_TEMP_BAT_HI_DET, 10, BD71828_INT_TEMP_BAT_HI_DET_MASK), REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_RES, 10, BD71828_INT_TEMP_CHIP_OVER_125_RES_MASK), REGMAP_IRQ_REG(BD71828_INT_TEMP_CHIP_OVER_125_DET, 10, @@ -267,57 +419,133 @@ static struct regmap_irq_chip bd71828_irq_chip = { .init_ack_masked = true, .num_regs = 12, .num_main_regs = 1, - .sub_reg_offsets = &bd71828_sub_irq_offsets[0], + .sub_reg_offsets = &bd718xx_sub_irq_offsets[0], + .num_main_status_bits = 8, + .irq_reg_stride = 1, +}; + +static struct regmap_irq_chip bd71815_irq_chip = { + .name = "bd71815_irq", + .main_status = BD71815_REG_INT_STAT, + .irqs = &bd71815_irqs[0], + .num_irqs = ARRAY_SIZE(bd71815_irqs), + .status_base = BD71815_REG_INT_STAT_01, + .mask_base = BD71815_REG_INT_EN_01, + .ack_base = BD71815_REG_INT_STAT_01, + .mask_invert = true, + .init_ack_masked = true, + .num_regs = 12, + .num_main_regs = 1, + .sub_reg_offsets = &bd718xx_sub_irq_offsets[0], .num_main_status_bits = 8, .irq_reg_stride = 1, }; +static int set_clk_mode(struct device *dev, struct regmap *regmap, + int clkmode_reg) +{ + int ret; + unsigned int open_drain; + + ret = of_property_read_u32(dev->of_node, "rohm,clkout-open-drain", &open_drain); + if (ret) { + if (ret == -EINVAL) + return 0; + return ret; + } + if (open_drain > 1) { + dev_err(dev, "bad clk32kout mode configuration"); + return -EINVAL; + } + + if (open_drain) + return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE, + OUT32K_MODE_OPEN_DRAIN); + + return regmap_update_bits(regmap, clkmode_reg, OUT32K_MODE, + OUT32K_MODE_CMOS); +} + static int bd71828_i2c_probe(struct i2c_client *i2c) { - struct rohm_regmap_dev *chip; struct regmap_irq_chip_data *irq_data; int ret; + struct regmap *regmap; + const struct regmap_config *regmap_config; + struct regmap_irq_chip *irqchip; + unsigned int chip_type; + struct mfd_cell *mfd; + int cells; + int button_irq; + int clkmode_reg; if (!i2c->irq) { dev_err(&i2c->dev, "No IRQ configured\n"); return -EINVAL; } - chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - dev_set_drvdata(&i2c->dev, chip); + chip_type = (unsigned int)(uintptr_t) + of_device_get_match_data(&i2c->dev); + switch (chip_type) { + case ROHM_CHIP_TYPE_BD71828: + mfd = bd71828_mfd_cells; + cells = ARRAY_SIZE(bd71828_mfd_cells); + regmap_config = &bd71828_regmap; + irqchip = &bd71828_irq_chip; + clkmode_reg = BD71828_REG_OUT32K; + button_irq = BD71828_INT_SHORTPUSH; + break; + case ROHM_CHIP_TYPE_BD71815: + mfd = bd71815_mfd_cells; + cells = ARRAY_SIZE(bd71815_mfd_cells); + regmap_config = &bd71815_regmap; + irqchip = &bd71815_irq_chip; + clkmode_reg = BD71815_REG_OUT32K; + /* + * If BD71817 support is needed we should be able to handle it + * with proper DT configs + BD71815 drivers + power-button. + * BD71815 data-sheet does not list the power-button IRQ so we + * don't use it. + */ + button_irq = 0; + break; + default: + dev_err(&i2c->dev, "Unknown device type"); + return -EINVAL; + } - chip->regmap = devm_regmap_init_i2c(i2c, &bd71828_regmap); - if (IS_ERR(chip->regmap)) { + regmap = devm_regmap_init_i2c(i2c, regmap_config); + if (IS_ERR(regmap)) { dev_err(&i2c->dev, "Failed to initialize Regmap\n"); - return PTR_ERR(chip->regmap); + return PTR_ERR(regmap); } - ret = devm_regmap_add_irq_chip(&i2c->dev, chip->regmap, - i2c->irq, IRQF_ONESHOT, 0, - &bd71828_irq_chip, &irq_data); + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, i2c->irq, + IRQF_ONESHOT, 0, irqchip, &irq_data); if (ret) { dev_err(&i2c->dev, "Failed to add IRQ chip\n"); return ret; } dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n", - bd71828_irq_chip.num_irqs); + irqchip->num_irqs); - ret = regmap_irq_get_virq(irq_data, BD71828_INT_SHORTPUSH); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to get the power-key IRQ\n"); - return ret; + if (button_irq) { + ret = regmap_irq_get_virq(irq_data, button_irq); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to get the power-key IRQ\n"); + return ret; + } + + button.irq = ret; } - button.irq = ret; + ret = set_clk_mode(&i2c->dev, regmap, clkmode_reg); + if (ret) + return ret; - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, - bd71828_mfd_cells, - ARRAY_SIZE(bd71828_mfd_cells), NULL, 0, - regmap_irq_get_domain(irq_data)); + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells, + NULL, 0, regmap_irq_get_domain(irq_data)); if (ret) dev_err(&i2c->dev, "Failed to create subdevices\n"); @@ -325,7 +553,13 @@ static int bd71828_i2c_probe(struct i2c_client *i2c) } static const struct of_device_id bd71828_of_match[] = { - { .compatible = "rohm,bd71828", }, + { + .compatible = "rohm,bd71828", + .data = (void *)ROHM_CHIP_TYPE_BD71828, + }, { + .compatible = "rohm,bd71815", + .data = (void *)ROHM_CHIP_TYPE_BD71815, + }, { }, }; MODULE_DEVICE_TABLE(of, bd71828_of_match); -- cgit v1.2.3 From c4d09226d5c484665e5f394bd8d278e071c5e2ee Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 10 Feb 2021 07:56:26 +0000 Subject: mfd: arizona: Make some symbols static The sparse tool complains as follows: drivers/mfd/arizona-spi.c:28:31: warning: symbol 'reset_gpios' was not declared. Should it be static? drivers/mfd/arizona-spi.c:29:31: warning: symbol 'ldoena_gpios' was not declared. Should it be static? Those symbols are not used outside of arizona-spi.c, so this commit marks them static. Fixes: e933836744a2 ("mfd: arizona: Add support for ACPI enumeration of WM5102 connected over SPI") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Reviewed-by: Hans de Goede Acked-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 24a2c75d691a..aa1d6f94ae53 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -25,8 +25,8 @@ #include "arizona.h" #ifdef CONFIG_ACPI -const struct acpi_gpio_params reset_gpios = { 1, 0, false }; -const struct acpi_gpio_params ldoena_gpios = { 2, 0, false }; +static const struct acpi_gpio_params reset_gpios = { 1, 0, false }; +static const struct acpi_gpio_params ldoena_gpios = { 2, 0, false }; static const struct acpi_gpio_mapping arizona_acpi_gpios[] = { { "reset-gpios", &reset_gpios, 1, }, -- cgit v1.2.3 From cb9e880a797a77c21c0f0e7ccd553da8eb4870af Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Fri, 5 Mar 2021 00:07:09 +0100 Subject: mfd: stmpe: Revert "Constify static struct resource" In stmpe_devices_init(), the start and end field of these structs are modified, so they can not be const. Add a comment to those structs that lacked it to reduce the risk that this happens again. This reverts commit 8d7b3a6dac4eae22c58b0853696cbd256966741b. Fixes: 8d7b3a6dac4e ("mfd: stmpe: Constify static struct resource") Reported-by: Andy Shevchenko Signed-off-by: Rikard Falkeborn Reviewed-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/stmpe.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 90f3292230c9..1dd39483e7c1 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -312,7 +312,7 @@ EXPORT_SYMBOL_GPL(stmpe_set_altfunc); * GPIO (all variants) */ -static const struct resource stmpe_gpio_resources[] = { +static struct resource stmpe_gpio_resources[] = { /* Start and end filled dynamically */ { .flags = IORESOURCE_IRQ, @@ -336,7 +336,8 @@ static const struct mfd_cell stmpe_gpio_cell_noirq = { * Keypad (1601, 2401, 2403) */ -static const struct resource stmpe_keypad_resources[] = { +static struct resource stmpe_keypad_resources[] = { + /* Start and end filled dynamically */ { .name = "KEYPAD", .flags = IORESOURCE_IRQ, @@ -357,7 +358,8 @@ static const struct mfd_cell stmpe_keypad_cell = { /* * PWM (1601, 2401, 2403) */ -static const struct resource stmpe_pwm_resources[] = { +static struct resource stmpe_pwm_resources[] = { + /* Start and end filled dynamically */ { .name = "PWM0", .flags = IORESOURCE_IRQ, @@ -445,7 +447,8 @@ static struct stmpe_variant_info stmpe801_noirq = { * Touchscreen (STMPE811 or STMPE610) */ -static const struct resource stmpe_ts_resources[] = { +static struct resource stmpe_ts_resources[] = { + /* Start and end filled dynamically */ { .name = "TOUCH_DET", .flags = IORESOURCE_IRQ, @@ -467,7 +470,8 @@ static const struct mfd_cell stmpe_ts_cell = { * ADC (STMPE811) */ -static const struct resource stmpe_adc_resources[] = { +static struct resource stmpe_adc_resources[] = { + /* Start and end filled dynamically */ { .name = "STMPE_TEMP_SENS", .flags = IORESOURCE_IRQ, -- cgit v1.2.3 From a98688d2ddfe274cb7c7ca3c6b6afbe9f844ffc3 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 7 Mar 2021 00:22:27 +0100 Subject: mfd: ab8500: Drop bm disable parameter Nobody is passing the module parameter to disable the battery management portions so just drop this parameter. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-core.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 22c0e3d87629..c2ba498ad302 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -120,12 +120,6 @@ static DEFINE_SPINLOCK(on_stat_lock); static u8 turn_on_stat_mask = 0xFF; static u8 turn_on_stat_set; -static bool no_bm; /* No battery management */ -/* - * not really modular, but the easiest way to keep compat with existing - * bootargs behaviour is to continue using module_param here. - */ -module_param(no_bm, bool, S_IRUGO); #define AB9540_MODEM_CTRL2_REG 0x23 #define AB9540_MODEM_CTRL2_SWDBBRSTN_BIT BIT(2) @@ -1254,14 +1248,12 @@ static int ab8500_probe(struct platform_device *pdev) if (ret) return ret; - if (!no_bm) { - /* Add battery management devices */ - ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, - ARRAY_SIZE(ab8500_bm_devs), NULL, - 0, ab8500->domain); - if (ret) - dev_err(ab8500->dev, "error adding bm devices\n"); - } + /* Add battery management devices */ + ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, + ARRAY_SIZE(ab8500_bm_devs), NULL, + 0, ab8500->domain); + if (ret) + dev_err(ab8500->dev, "error adding bm devices\n"); if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) -- cgit v1.2.3 From 16f961544bfd7170f75d805d7585e09023671dbc Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sun, 7 Mar 2021 21:23:25 +0100 Subject: mfd: Remove support for AB3100 The ST-Ericsson U300 platform has been removed, so this driver is no longer needed. Signed-off-by: Arnd Bergmann Reviewed-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 26 +- drivers/mfd/Makefile | 2 - drivers/mfd/ab3100-core.c | 929 ---------------------------------------------- drivers/mfd/ab3100-otp.c | 240 ------------ 4 files changed, 1 insertion(+), 1196 deletions(-) delete mode 100644 drivers/mfd/ab3100-core.c delete mode 100644 drivers/mfd/ab3100-otp.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 6e31210915c7..2152126c5b0b 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1235,7 +1235,7 @@ config MFD_SC27XX_PMIC config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" - default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST + default y if ARCH_U8500 || COMPILE_TEST help Say yes here if you have the ABX500 Mixed Signal IC family chips. This core driver expose register access functions. @@ -1243,30 +1243,6 @@ config ABX500_CORE remain unchanged when IC changes. Binding of the functions to actual register access is done by the IC core driver. -config AB3100_CORE - bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" - depends on I2C=y && ABX500_CORE - select MFD_CORE - default y if ARCH_U300 - help - Select this to enable the AB3100 Mixed Signal IC core - functionality. This connects to a AB3100 on the I2C bus - and expose a number of symbols needed for dependent devices - to read and write registers and subscribe to events from - this multi-functional IC. This is needed to use other features - of the AB3100 such as battery-backed RTC, charging control, - LEDs, vibrator, system power and temperature, power management - and ALSA sound. - -config AB3100_OTP - tristate "ST-Ericsson AB3100 OTP functions" - depends on AB3100_CORE - default y if AB3100_CORE - help - Select this to enable the AB3100 Mixed Signal IC OTP (one-time - programmable memory) support. This exposes a sysfs file to read - out OTP values. - config AB8500_CORE bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" depends on ABX500_CORE && MFD_DB8500_PRCMU diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 279b80822147..4f6d2b8a5f76 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -178,8 +178,6 @@ obj-$(CONFIG_MFD_PCF50633) += pcf50633.o obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o obj-$(CONFIG_ABX500_CORE) += abx500-core.o -obj-$(CONFIG_AB3100_CORE) += ab3100-core.o -obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o # ab8500-core need to come after db8500-prcmu (which provides the channel) diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c deleted file mode 100644 index ee71ae04b5e6..000000000000 --- a/drivers/mfd/ab3100-core.c +++ /dev/null @@ -1,929 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2007-2010 ST-Ericsson - * Low-level core for exclusive access to the AB3100 IC on the I2C bus - * and some basic chip-configuration. - * Author: Linus Walleij - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* These are the only registers inside AB3100 used in this main file */ - -/* Interrupt event registers */ -#define AB3100_EVENTA1 0x21 -#define AB3100_EVENTA2 0x22 -#define AB3100_EVENTA3 0x23 - -/* AB3100 DAC converter registers */ -#define AB3100_DIS 0x00 -#define AB3100_D0C 0x01 -#define AB3100_D1C 0x02 -#define AB3100_D2C 0x03 -#define AB3100_D3C 0x04 - -/* Chip ID register */ -#define AB3100_CID 0x20 - -/* AB3100 interrupt registers */ -#define AB3100_IMRA1 0x24 -#define AB3100_IMRA2 0x25 -#define AB3100_IMRA3 0x26 -#define AB3100_IMRB1 0x2B -#define AB3100_IMRB2 0x2C -#define AB3100_IMRB3 0x2D - -/* System Power Monitoring and control registers */ -#define AB3100_MCA 0x2E -#define AB3100_MCB 0x2F - -/* SIM power up */ -#define AB3100_SUP 0x50 - -/* - * I2C communication - * - * The AB3100 is usually assigned address 0x48 (7-bit) - * The chip is defined in the platform i2c_board_data section. - */ -static int ab3100_get_chip_id(struct device *dev) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return (int)ab3100->chip_id; -} - -static int ab3100_set_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 regval) -{ - u8 regandval[2] = {reg, regval}; - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* - * A two-byte write message with the first byte containing the register - * number and the second byte containing the value to be written - * effectively sets a register in the AB3100. - */ - err = i2c_master_send(ab3100->i2c_client, regandval, 2); - if (err < 0) { - dev_err(ab3100->dev, - "write error (write register): %d\n", - err); - } else if (err != 2) { - dev_err(ab3100->dev, - "write error (write register)\n" - " %d bytes transferred (expected 2)\n", - err); - err = -EIO; - } else { - /* All is well */ - err = 0; - } - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int set_register_interruptible(struct device *dev, - u8 bank, u8 reg, u8 value) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_set_register_interruptible(ab3100, reg, value); -} - -/* - * The test registers exist at an I2C bus address up one - * from the ordinary base. They are not supposed to be used - * in production code, but sometimes you have to do that - * anyway. It's currently only used from this file so declare - * it static and do not export. - */ -static int ab3100_set_test_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 regval) -{ - u8 regandval[2] = {reg, regval}; - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - err = i2c_master_send(ab3100->testreg_client, regandval, 2); - if (err < 0) { - dev_err(ab3100->dev, - "write error (write test register): %d\n", - err); - } else if (err != 2) { - dev_err(ab3100->dev, - "write error (write test register)\n" - " %d bytes transferred (expected 2)\n", - err); - err = -EIO; - } else { - /* All is well */ - err = 0; - } - mutex_unlock(&ab3100->access_mutex); - - return err; -} - -static int ab3100_get_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 *regval) -{ - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* - * AB3100 require an I2C "stop" command between each message, else - * it will not work. The only way of achieveing this with the - * message transport layer is to send the read and write messages - * separately. - */ - err = i2c_master_send(ab3100->i2c_client, ®, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (send register address): %d\n", - err); - goto get_reg_out_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (send register address)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_reg_out_unlock; - } else { - /* All is well */ - err = 0; - } - - err = i2c_master_recv(ab3100->i2c_client, regval, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (read register): %d\n", - err); - goto get_reg_out_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (read register)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_reg_out_unlock; - } else { - /* All is well */ - err = 0; - } - - get_reg_out_unlock: - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int get_register_interruptible(struct device *dev, u8 bank, u8 reg, - u8 *value) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_get_register_interruptible(ab3100, reg, value); -} - -static int ab3100_get_register_page_interruptible(struct ab3100 *ab3100, - u8 first_reg, u8 *regvals, u8 numregs) -{ - int err; - - if (ab3100->chip_id == 0xa0 || - ab3100->chip_id == 0xa1) - /* These don't support paged reads */ - return -EIO; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* - * Paged read also require an I2C "stop" command. - */ - err = i2c_master_send(ab3100->i2c_client, &first_reg, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (send first register address): %d\n", - err); - goto get_reg_page_out_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (send first register address)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_reg_page_out_unlock; - } - - err = i2c_master_recv(ab3100->i2c_client, regvals, numregs); - if (err < 0) { - dev_err(ab3100->dev, - "write error (read register page): %d\n", - err); - goto get_reg_page_out_unlock; - } else if (err != numregs) { - dev_err(ab3100->dev, - "write error (read register page)\n" - " %d bytes transferred (expected %d)\n", - err, numregs); - err = -EIO; - goto get_reg_page_out_unlock; - } - - /* All is well */ - err = 0; - - get_reg_page_out_unlock: - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int get_register_page_interruptible(struct device *dev, u8 bank, - u8 first_reg, u8 *regvals, u8 numregs) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_get_register_page_interruptible(ab3100, - first_reg, regvals, numregs); -} - -static int ab3100_mask_and_set_register_interruptible(struct ab3100 *ab3100, - u8 reg, u8 andmask, u8 ormask) -{ - u8 regandval[2] = {reg, 0}; - int err; - - err = mutex_lock_interruptible(&ab3100->access_mutex); - if (err) - return err; - - /* First read out the target register */ - err = i2c_master_send(ab3100->i2c_client, ®, 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (maskset send address): %d\n", - err); - goto get_maskset_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (maskset send address)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_maskset_unlock; - } - - err = i2c_master_recv(ab3100->i2c_client, ®andval[1], 1); - if (err < 0) { - dev_err(ab3100->dev, - "write error (maskset read register): %d\n", - err); - goto get_maskset_unlock; - } else if (err != 1) { - dev_err(ab3100->dev, - "write error (maskset read register)\n" - " %d bytes transferred (expected 1)\n", - err); - err = -EIO; - goto get_maskset_unlock; - } - - /* Modify the register */ - regandval[1] &= andmask; - regandval[1] |= ormask; - - /* Write the register */ - err = i2c_master_send(ab3100->i2c_client, regandval, 2); - if (err < 0) { - dev_err(ab3100->dev, - "write error (write register): %d\n", - err); - goto get_maskset_unlock; - } else if (err != 2) { - dev_err(ab3100->dev, - "write error (write register)\n" - " %d bytes transferred (expected 2)\n", - err); - err = -EIO; - goto get_maskset_unlock; - } - - /* All is well */ - err = 0; - - get_maskset_unlock: - mutex_unlock(&ab3100->access_mutex); - return err; -} - -static int mask_and_set_register_interruptible(struct device *dev, u8 bank, - u8 reg, u8 bitmask, u8 bitvalues) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - return ab3100_mask_and_set_register_interruptible(ab3100, - reg, bitmask, (bitmask & bitvalues)); -} - -/* - * Register a simple callback for handling any AB3100 events. - */ -int ab3100_event_register(struct ab3100 *ab3100, - struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&ab3100->event_subscribers, - nb); -} -EXPORT_SYMBOL(ab3100_event_register); - -/* - * Remove a previously registered callback. - */ -int ab3100_event_unregister(struct ab3100 *ab3100, - struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&ab3100->event_subscribers, - nb); -} -EXPORT_SYMBOL(ab3100_event_unregister); - - -static int ab3100_event_registers_startup_state_get(struct device *dev, - u8 *event) -{ - struct ab3100 *ab3100 = dev_get_drvdata(dev->parent); - - if (!ab3100->startup_events_read) - return -EAGAIN; /* Try again later */ - memcpy(event, ab3100->startup_events, 3); - - return 0; -} - -static struct abx500_ops ab3100_ops = { - .get_chip_id = ab3100_get_chip_id, - .set_register = set_register_interruptible, - .get_register = get_register_interruptible, - .get_register_page = get_register_page_interruptible, - .set_register_page = NULL, - .mask_and_set_register = mask_and_set_register_interruptible, - .event_registers_startup_state_get = - ab3100_event_registers_startup_state_get, - .startup_irq_enabled = NULL, -}; - -/* - * This is a threaded interrupt handler so we can make some - * I2C calls etc. - */ -static irqreturn_t ab3100_irq_handler(int irq, void *data) -{ - struct ab3100 *ab3100 = data; - u8 event_regs[3]; - u32 fatevent; - int err; - - err = ab3100_get_register_page_interruptible(ab3100, AB3100_EVENTA1, - event_regs, 3); - if (err) - goto err_event; - - fatevent = (event_regs[0] << 16) | - (event_regs[1] << 8) | - event_regs[2]; - - if (!ab3100->startup_events_read) { - ab3100->startup_events[0] = event_regs[0]; - ab3100->startup_events[1] = event_regs[1]; - ab3100->startup_events[2] = event_regs[2]; - ab3100->startup_events_read = true; - } - /* - * The notified parties will have to mask out the events - * they're interested in and react to them. They will be - * notified on all events, then they use the fatevent value - * to determine if they're interested. - */ - blocking_notifier_call_chain(&ab3100->event_subscribers, - fatevent, NULL); - - dev_dbg(ab3100->dev, - "IRQ Event: 0x%08x\n", fatevent); - - return IRQ_HANDLED; - - err_event: - dev_dbg(ab3100->dev, - "error reading event status\n"); - return IRQ_HANDLED; -} - -#ifdef CONFIG_DEBUG_FS -/* - * Some debugfs entries only exposed if we're using debug - */ -static int ab3100_registers_print(struct seq_file *s, void *p) -{ - struct ab3100 *ab3100 = s->private; - u8 value; - u8 reg; - - seq_puts(s, "AB3100 registers:\n"); - - for (reg = 0; reg < 0xff; reg++) { - ab3100_get_register_interruptible(ab3100, reg, &value); - seq_printf(s, "[0x%x]: 0x%x\n", reg, value); - } - return 0; -} - -static int ab3100_registers_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab3100_registers_print, inode->i_private); -} - -static const struct file_operations ab3100_registers_fops = { - .open = ab3100_registers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -struct ab3100_get_set_reg_priv { - struct ab3100 *ab3100; - bool mode; -}; - -static ssize_t ab3100_get_set_reg(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ab3100_get_set_reg_priv *priv = file->private_data; - struct ab3100 *ab3100 = priv->ab3100; - char buf[32]; - ssize_t buf_size; - int regp; - u8 user_reg; - int err; - int i = 0; - - /* Get userspace string and assure termination */ - buf_size = min((ssize_t)count, (ssize_t)(sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - /* - * The idea is here to parse a string which is either - * "0xnn" for reading a register, or "0xaa 0xbb" for - * writing 0xbb to the register 0xaa. First move past - * whitespace and then begin to parse the register. - */ - while ((i < buf_size) && (buf[i] == ' ')) - i++; - regp = i; - - /* - * Advance pointer to end of string then terminate - * the register string. This is needed to satisfy - * the kstrtou8() function. - */ - while ((i < buf_size) && (buf[i] != ' ')) - i++; - buf[i] = '\0'; - - err = kstrtou8(&buf[regp], 16, &user_reg); - if (err) - return err; - - /* Either we read or we write a register here */ - if (!priv->mode) { - /* Reading */ - u8 regvalue; - - ab3100_get_register_interruptible(ab3100, user_reg, ®value); - - dev_info(ab3100->dev, - "debug read AB3100 reg[0x%02x]: 0x%02x\n", - user_reg, regvalue); - } else { - int valp; - u8 user_value; - u8 regvalue; - - /* - * Writing, we need some value to write to - * the register so keep parsing the string - * from userspace. - */ - i++; - while ((i < buf_size) && (buf[i] == ' ')) - i++; - valp = i; - while ((i < buf_size) && (buf[i] != ' ')) - i++; - buf[i] = '\0'; - - err = kstrtou8(&buf[valp], 16, &user_value); - if (err) - return err; - - ab3100_set_register_interruptible(ab3100, user_reg, user_value); - ab3100_get_register_interruptible(ab3100, user_reg, ®value); - - dev_info(ab3100->dev, - "debug write reg[0x%02x]\n" - " with 0x%02x, after readback: 0x%02x\n", - user_reg, user_value, regvalue); - } - return buf_size; -} - -static const struct file_operations ab3100_get_set_reg_fops = { - .open = simple_open, - .write = ab3100_get_set_reg, - .llseek = noop_llseek, -}; - -static struct ab3100_get_set_reg_priv ab3100_get_priv; -static struct ab3100_get_set_reg_priv ab3100_set_priv; - -static void ab3100_setup_debugfs(struct ab3100 *ab3100) -{ - struct dentry *ab3100_dir; - - ab3100_dir = debugfs_create_dir("ab3100", NULL); - - debugfs_create_file("registers", S_IRUGO, ab3100_dir, ab3100, - &ab3100_registers_fops); - - ab3100_get_priv.ab3100 = ab3100; - ab3100_get_priv.mode = false; - debugfs_create_file("get_reg", S_IWUSR, ab3100_dir, &ab3100_get_priv, - &ab3100_get_set_reg_fops); - - ab3100_set_priv.ab3100 = ab3100; - ab3100_set_priv.mode = true; - debugfs_create_file("set_reg", S_IWUSR, ab3100_dir, &ab3100_set_priv, - &ab3100_get_set_reg_fops); -} -#else -static inline void ab3100_setup_debugfs(struct ab3100 *ab3100) -{ -} -#endif - -/* - * Basic set-up, datastructure creation/destruction and I2C interface. - * This sets up a default config in the AB3100 chip so that it - * will work as expected. - */ - -struct ab3100_init_setting { - u8 abreg; - u8 setting; -}; - -static const struct ab3100_init_setting ab3100_init_settings[] = { - { - .abreg = AB3100_MCA, - .setting = 0x01 - }, { - .abreg = AB3100_MCB, - .setting = 0x30 - }, { - .abreg = AB3100_IMRA1, - .setting = 0x00 - }, { - .abreg = AB3100_IMRA2, - .setting = 0xFF - }, { - .abreg = AB3100_IMRA3, - .setting = 0x01 - }, { - .abreg = AB3100_IMRB1, - .setting = 0xBF - }, { - .abreg = AB3100_IMRB2, - .setting = 0xFF - }, { - .abreg = AB3100_IMRB3, - .setting = 0xFF - }, { - .abreg = AB3100_SUP, - .setting = 0x00 - }, { - .abreg = AB3100_DIS, - .setting = 0xF0 - }, { - .abreg = AB3100_D0C, - .setting = 0x00 - }, { - .abreg = AB3100_D1C, - .setting = 0x00 - }, { - .abreg = AB3100_D2C, - .setting = 0x00 - }, { - .abreg = AB3100_D3C, - .setting = 0x00 - }, -}; - -static int ab3100_setup(struct ab3100 *ab3100) -{ - int err = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(ab3100_init_settings); i++) { - err = ab3100_set_register_interruptible(ab3100, - ab3100_init_settings[i].abreg, - ab3100_init_settings[i].setting); - if (err) - goto exit_no_setup; - } - - /* - * Special trick to make the AB3100 use the 32kHz clock (RTC) - * bit 3 in test register 0x02 is a special, undocumented test - * register bit that only exist in AB3100 P1E - */ - if (ab3100->chip_id == 0xc4) { - dev_warn(ab3100->dev, - "AB3100 P1E variant detected forcing chip to 32KHz\n"); - err = ab3100_set_test_register_interruptible(ab3100, - 0x02, 0x08); - } - - exit_no_setup: - return err; -} - -/* The subdevices of the AB3100 */ -static struct mfd_cell ab3100_devs[] = { - { - .name = "ab3100-dac", - .id = -1, - }, - { - .name = "ab3100-leds", - .id = -1, - }, - { - .name = "ab3100-power", - .id = -1, - }, - { - .name = "ab3100-regulators", - .of_compatible = "stericsson,ab3100-regulators", - .id = -1, - }, - { - .name = "ab3100-sim", - .id = -1, - }, - { - .name = "ab3100-uart", - .id = -1, - }, - { - .name = "ab3100-rtc", - .id = -1, - }, - { - .name = "ab3100-charger", - .id = -1, - }, - { - .name = "ab3100-boost", - .id = -1, - }, - { - .name = "ab3100-adc", - .id = -1, - }, - { - .name = "ab3100-fuelgauge", - .id = -1, - }, - { - .name = "ab3100-vibrator", - .id = -1, - }, - { - .name = "ab3100-otp", - .id = -1, - }, - { - .name = "ab3100-codec", - .id = -1, - }, -}; - -struct ab_family_id { - u8 id; - char *name; -}; - -static const struct ab_family_id ids[] = { - /* AB3100 */ - { - .id = 0xc0, - .name = "P1A" - }, { - .id = 0xc1, - .name = "P1B" - }, { - .id = 0xc2, - .name = "P1C" - }, { - .id = 0xc3, - .name = "P1D" - }, { - .id = 0xc4, - .name = "P1E" - }, { - .id = 0xc5, - .name = "P1F/R1A" - }, { - .id = 0xc6, - .name = "P1G/R1A" - }, { - .id = 0xc7, - .name = "P2A/R2A" - }, { - .id = 0xc8, - .name = "P2B/R2B" - }, - /* AB3000 variants, not supported */ - { - .id = 0xa0 - }, { - .id = 0xa1 - }, { - .id = 0xa2 - }, { - .id = 0xa3 - }, { - .id = 0xa4 - }, { - .id = 0xa5 - }, { - .id = 0xa6 - }, { - .id = 0xa7 - }, - /* Terminator */ - { - .id = 0x00, - }, -}; - -static int ab3100_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ab3100 *ab3100; - struct ab3100_platform_data *ab3100_plf_data = - dev_get_platdata(&client->dev); - int err; - int i; - - ab3100 = devm_kzalloc(&client->dev, sizeof(struct ab3100), GFP_KERNEL); - if (!ab3100) - return -ENOMEM; - - /* Initialize data structure */ - mutex_init(&ab3100->access_mutex); - BLOCKING_INIT_NOTIFIER_HEAD(&ab3100->event_subscribers); - - ab3100->i2c_client = client; - ab3100->dev = &ab3100->i2c_client->dev; - - i2c_set_clientdata(client, ab3100); - - /* Read chip ID register */ - err = ab3100_get_register_interruptible(ab3100, AB3100_CID, - &ab3100->chip_id); - if (err) { - dev_err(&client->dev, - "failed to communicate with AB3100 chip\n"); - goto exit_no_detect; - } - - for (i = 0; ids[i].id != 0x0; i++) { - if (ids[i].id == ab3100->chip_id) { - if (ids[i].name) - break; - - dev_err(&client->dev, "AB3000 is not supported\n"); - goto exit_no_detect; - } - } - - snprintf(&ab3100->chip_name[0], - sizeof(ab3100->chip_name) - 1, "AB3100 %s", ids[i].name); - - if (ids[i].id == 0x0) { - dev_err(&client->dev, "unknown analog baseband chip id: 0x%x\n", - ab3100->chip_id); - dev_err(&client->dev, - "accepting it anyway. Please update the driver.\n"); - goto exit_no_detect; - } - - dev_info(&client->dev, "Detected chip: %s\n", - &ab3100->chip_name[0]); - - /* Attach a second dummy i2c_client to the test register address */ - ab3100->testreg_client = i2c_new_dummy_device(client->adapter, - client->addr + 1); - if (IS_ERR(ab3100->testreg_client)) { - err = PTR_ERR(ab3100->testreg_client); - goto exit_no_testreg_client; - } - - err = ab3100_setup(ab3100); - if (err) - goto exit_no_setup; - - err = devm_request_threaded_irq(&client->dev, - client->irq, NULL, ab3100_irq_handler, - IRQF_ONESHOT, "ab3100-core", ab3100); - if (err) - goto exit_no_irq; - - err = abx500_register_ops(&client->dev, &ab3100_ops); - if (err) - goto exit_no_ops; - - /* Set up and register the platform devices. */ - for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { - ab3100_devs[i].platform_data = ab3100_plf_data; - ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data); - } - - err = mfd_add_devices(&client->dev, 0, ab3100_devs, - ARRAY_SIZE(ab3100_devs), NULL, 0, NULL); - - ab3100_setup_debugfs(ab3100); - - return 0; - - exit_no_ops: - exit_no_irq: - exit_no_setup: - i2c_unregister_device(ab3100->testreg_client); - exit_no_testreg_client: - exit_no_detect: - return err; -} - -static const struct i2c_device_id ab3100_id[] = { - { "ab3100", 0 }, - { } -}; - -static struct i2c_driver ab3100_driver = { - .driver = { - .name = "ab3100", - .suppress_bind_attrs = true, - }, - .id_table = ab3100_id, - .probe = ab3100_probe, -}; - -static int __init ab3100_i2c_init(void) -{ - return i2c_add_driver(&ab3100_driver); -} -subsys_initcall(ab3100_i2c_init); diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c deleted file mode 100644 index c393102e3a39..000000000000 --- a/drivers/mfd/ab3100-otp.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/mfd/ab3100_otp.c - * - * Copyright (C) 2007-2009 ST-Ericsson AB - * Driver to read out OTP from the AB3100 Mixed-signal circuit - * Author: Linus Walleij - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* The OTP registers */ -#define AB3100_OTP0 0xb0 -#define AB3100_OTP1 0xb1 -#define AB3100_OTP2 0xb2 -#define AB3100_OTP3 0xb3 -#define AB3100_OTP4 0xb4 -#define AB3100_OTP5 0xb5 -#define AB3100_OTP6 0xb6 -#define AB3100_OTP7 0xb7 -#define AB3100_OTPP 0xbf - -/** - * struct ab3100_otp - * @dev: containing device - * @locked: whether the OTP is locked, after locking, no more bits - * can be changed but before locking it is still possible - * to change bits from 1->0. - * @freq: clocking frequency for the OTP, this frequency is either - * 32768Hz or 1MHz/30 - * @paf: product activation flag, indicates whether this is a real - * product (paf true) or a lab board etc (paf false) - * @imeich: if this is set it is possible to override the - * IMEI number found in the tac, fac and svn fields with - * (secured) software - * @cid: customer ID - * @tac: type allocation code of the IMEI - * @fac: final assembly code of the IMEI - * @svn: software version number of the IMEI - * @debugfs: a debugfs file used when dumping to file - */ -struct ab3100_otp { - struct device *dev; - bool locked; - u32 freq; - bool paf; - bool imeich; - u16 cid:14; - u32 tac:20; - u8 fac; - u32 svn:20; - struct dentry *debugfs; -}; - -static int __init ab3100_otp_read(struct ab3100_otp *otp) -{ - u8 otpval[8]; - u8 otpp; - int err; - - err = abx500_get_register_interruptible(otp->dev, 0, - AB3100_OTPP, &otpp); - if (err) { - dev_err(otp->dev, "unable to read OTPP register\n"); - return err; - } - - err = abx500_get_register_page_interruptible(otp->dev, 0, - AB3100_OTP0, otpval, 8); - if (err) { - dev_err(otp->dev, "unable to read OTP register page\n"); - return err; - } - - /* Cache OTP properties, they never change by nature */ - otp->locked = (otpp & 0x80); - otp->freq = (otpp & 0x40) ? 32768 : 34100; - otp->paf = (otpval[1] & 0x80); - otp->imeich = (otpval[1] & 0x40); - otp->cid = ((otpval[1] << 8) | otpval[0]) & 0x3fff; - otp->tac = ((otpval[4] & 0x0f) << 16) | (otpval[3] << 8) | otpval[2]; - otp->fac = ((otpval[5] & 0x0f) << 4) | (otpval[4] >> 4); - otp->svn = (otpval[7] << 12) | (otpval[6] << 4) | (otpval[5] >> 4); - return 0; -} - -/* - * This is a simple debugfs human-readable file that dumps out - * the contents of the OTP. - */ -#ifdef CONFIG_DEBUG_FS -static int ab3100_show_otp(struct seq_file *s, void *v) -{ - struct ab3100_otp *otp = s->private; - - seq_printf(s, "OTP is %s\n", otp->locked ? "LOCKED" : "UNLOCKED"); - seq_printf(s, "OTP clock switch startup is %uHz\n", otp->freq); - seq_printf(s, "PAF is %s\n", otp->paf ? "SET" : "NOT SET"); - seq_printf(s, "IMEI is %s\n", otp->imeich ? - "CHANGEABLE" : "NOT CHANGEABLE"); - seq_printf(s, "CID: 0x%04x (decimal: %d)\n", otp->cid, otp->cid); - seq_printf(s, "IMEI: %u-%u-%u\n", otp->tac, otp->fac, otp->svn); - return 0; -} - -static int ab3100_otp_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab3100_show_otp, inode->i_private); -} - -static const struct file_operations ab3100_otp_operations = { - .open = ab3100_otp_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void __init ab3100_otp_init_debugfs(struct device *dev, - struct ab3100_otp *otp) -{ - otp->debugfs = debugfs_create_file("ab3100_otp", S_IFREG | S_IRUGO, - NULL, otp, &ab3100_otp_operations); -} - -static void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) -{ - debugfs_remove(otp->debugfs); -} -#else -/* Compile this out if debugfs not selected */ -static inline void __init ab3100_otp_init_debugfs(struct device *dev, - struct ab3100_otp *otp) -{ -} - -static inline void __exit ab3100_otp_exit_debugfs(struct ab3100_otp *otp) -{ -} -#endif - -#define SHOW_AB3100_ATTR(name) \ -static ssize_t ab3100_otp_##name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{\ - struct ab3100_otp *otp = dev_get_drvdata(dev); \ - return sprintf(buf, "%u\n", otp->name); \ -} - -SHOW_AB3100_ATTR(locked) -SHOW_AB3100_ATTR(freq) -SHOW_AB3100_ATTR(paf) -SHOW_AB3100_ATTR(imeich) -SHOW_AB3100_ATTR(cid) -SHOW_AB3100_ATTR(fac) -SHOW_AB3100_ATTR(tac) -SHOW_AB3100_ATTR(svn) - -static struct device_attribute ab3100_otp_attrs[] = { - __ATTR(locked, S_IRUGO, ab3100_otp_locked_show, NULL), - __ATTR(freq, S_IRUGO, ab3100_otp_freq_show, NULL), - __ATTR(paf, S_IRUGO, ab3100_otp_paf_show, NULL), - __ATTR(imeich, S_IRUGO, ab3100_otp_imeich_show, NULL), - __ATTR(cid, S_IRUGO, ab3100_otp_cid_show, NULL), - __ATTR(fac, S_IRUGO, ab3100_otp_fac_show, NULL), - __ATTR(tac, S_IRUGO, ab3100_otp_tac_show, NULL), - __ATTR(svn, S_IRUGO, ab3100_otp_svn_show, NULL), -}; - -static int __init ab3100_otp_probe(struct platform_device *pdev) -{ - struct ab3100_otp *otp; - int err = 0; - int i; - - otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL); - if (!otp) - return -ENOMEM; - - otp->dev = &pdev->dev; - - /* Replace platform data coming in with a local struct */ - platform_set_drvdata(pdev, otp); - - err = ab3100_otp_read(otp); - if (err) - return err; - - dev_info(&pdev->dev, "AB3100 OTP readout registered\n"); - - /* sysfs entries */ - for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++) { - err = device_create_file(&pdev->dev, - &ab3100_otp_attrs[i]); - if (err) - goto err; - } - - /* debugfs entries */ - ab3100_otp_init_debugfs(&pdev->dev, otp); - - return 0; - -err: - while (--i >= 0) - device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]); - return err; -} - -static int __exit ab3100_otp_remove(struct platform_device *pdev) -{ - struct ab3100_otp *otp = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++) - device_remove_file(&pdev->dev, - &ab3100_otp_attrs[i]); - ab3100_otp_exit_debugfs(otp); - return 0; -} - -static struct platform_driver ab3100_otp_driver = { - .driver = { - .name = "ab3100-otp", - }, - .remove = __exit_p(ab3100_otp_remove), -}; - -module_platform_driver_probe(ab3100_otp_driver, ab3100_otp_probe); - -MODULE_AUTHOR("Linus Walleij "); -MODULE_DESCRIPTION("AB3100 OTP Readout Driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5a2cf054221a78f394b4c0f4c0ed1ae94a710ae3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 8 Mar 2021 12:31:47 +0000 Subject: mfd: ene-kb3930: Make local symbol 'kb3930_power_off' static The sparse tool complains as follows: drivers/mfd/ene-kb3930.c:36:15: warning: symbol 'kb3930_power_off' was not declared. Should it be static? The symbol is not used outside of this file. Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Acked-by: Lubomir Rintel Signed-off-by: Lee Jones --- drivers/mfd/ene-kb3930.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ene-kb3930.c b/drivers/mfd/ene-kb3930.c index 83243e668e3f..1b73318d1f1f 100644 --- a/drivers/mfd/ene-kb3930.c +++ b/drivers/mfd/ene-kb3930.c @@ -33,7 +33,7 @@ struct kb3930 { struct gpio_descs *off_gpios; }; -struct kb3930 *kb3930_power_off; +static struct kb3930 *kb3930_power_off; #define EC_GPIO_WAVE 0 #define EC_GPIO_OFF_MODE 1 -- cgit v1.2.3 From 23144a323118380a97e39b3b3f09ae3099c5aeb4 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Tue, 23 Feb 2021 17:42:24 +0800 Subject: mfd: lm3533: Switch to using the new API kobj_to_dev() Fixes the following coccicheck warning: drivers/mfd/lm3533-core.c:361:60-61: WARNING opportunity for kobj_to_dev() Reported-by: Abaci Robot Signed-off-by: Yang Li Signed-off-by: Lee Jones --- drivers/mfd/lm3533-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 22fdffd564f7..5690768f3e63 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -358,7 +358,7 @@ static struct attribute *lm3533_attributes[] = { static umode_t lm3533_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct lm3533 *lm3533 = dev_get_drvdata(dev); struct device_attribute *dattr = to_dev_attr(attr); struct lm3533_device_attribute *lattr = to_lm3533_dev_attr(dattr); -- cgit v1.2.3 From 5893f4d1f43036664010e3ae1d3f7a98b2165a5d Mon Sep 17 00:00:00 2001 From: Xu Yilun Date: Wed, 10 Mar 2021 23:55:46 +0800 Subject: mfd: intel-m10-bmc: Simplify the legacy version reg definition The version register is the only one in the legacy I/O space to be accessed, so it is not necessary to define the legacy base & version register offset. A direct definition of the legacy version register address would be fine. Signed-off-by: Xu Yilun Reviewed-by: Tom Rix Signed-off-by: Lee Jones --- drivers/mfd/intel-m10-bmc.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index 06c977519479..90d0448a5500 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -116,17 +116,14 @@ static int check_m10bmc_version(struct intel_m10bmc *ddata) int ret; /* - * This check is to filter out the very old legacy BMC versions, - * M10BMC_LEGACY_SYS_BASE is the offset to this old block of mmio - * registers. In the old BMC chips, the BMC version info is stored - * in this old version register (M10BMC_LEGACY_SYS_BASE + - * M10BMC_BUILD_VER), so its read out value would have not been - * LEGACY_INVALID (0xffffffff). But in new BMC chips that the - * driver supports, the value of this register should be - * LEGACY_INVALID. + * This check is to filter out the very old legacy BMC versions. In the + * old BMC chips, the BMC version info is stored in the old version + * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have + * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC + * chips that the driver supports, the value of this register should be + * M10BMC_VER_LEGACY_INVALID. */ - ret = m10bmc_raw_read(ddata, - M10BMC_LEGACY_SYS_BASE + M10BMC_BUILD_VER, &v); + ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v); if (ret) return -ENODEV; -- cgit v1.2.3 From 8169f74ca6f318f4187536050d2f5408fce9c264 Mon Sep 17 00:00:00 2001 From: Matthew Gerlach Date: Wed, 10 Mar 2021 23:55:47 +0800 Subject: mfd: intel-m10-bmc: Add access table configuration to the regmap This patch adds access tables to the MAX 10 BMC regmap. This prevents the host from accessing the unwanted I/O space. It also filters out the invalid outputs when reading the regmap debugfs interface. Signed-off-by: Matthew Gerlach Signed-off-by: Xu Yilun Reviewed-by: Tom Rix Signed-off-by: Lee Jones --- drivers/mfd/intel-m10-bmc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index 90d0448a5500..1161933cbd4a 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -23,10 +23,23 @@ static struct mfd_cell m10bmc_pacn3000_subdevs[] = { { .name = "n3000bmc-secure" }, }; +static const struct regmap_range m10bmc_regmap_range[] = { + regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER), + regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END), + regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END), +}; + +static const struct regmap_access_table m10bmc_access_table = { + .yes_ranges = m10bmc_regmap_range, + .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range), +}; + static struct regmap_config intel_m10bmc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, + .wr_table = &m10bmc_access_table, + .rd_table = &m10bmc_access_table, .max_register = M10BMC_MEM_END, }; -- cgit v1.2.3 From 0c8f2d1081fd67fb045e055f98869bc0f64e44ec Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 16 Mar 2021 14:25:15 +0100 Subject: mfd: sec: Initialize driver via module_platform_driver() The driver was using subsys_initcall() because in old times deferred probe was not supported everywhere and specific ordering was needed. Since probe deferral works fine and specific ordering is discouraged (hides dependencies between drivers and couples their boot order), the driver can be converted to regular module_platform_driver. Signed-off-by: Krzysztof Kozlowski Tested-by: Marek Szyprowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 95473ff9bb4b..8d55992da19e 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -549,19 +549,7 @@ static struct i2c_driver sec_pmic_driver = { .shutdown = sec_pmic_shutdown, .id_table = sec_pmic_id, }; - -static int __init sec_pmic_init(void) -{ - return i2c_add_driver(&sec_pmic_driver); -} - -subsys_initcall(sec_pmic_init); - -static void __exit sec_pmic_exit(void) -{ - i2c_del_driver(&sec_pmic_driver); -} -module_exit(sec_pmic_exit); +module_i2c_driver(sec_pmic_driver); MODULE_AUTHOR("Sangbeom Kim "); MODULE_DESCRIPTION("Core support for the S5M MFD"); -- cgit v1.2.3 From 586478bfc9f7e16504d6f64cf18bcbdf6fd0cbc9 Mon Sep 17 00:00:00 2001 From: Hubert Streidl Date: Tue, 16 Mar 2021 17:22:37 +0100 Subject: mfd: da9063: Support SMBus and I2C mode By default the PMIC DA9063 2-wire interface is SMBus compliant. This means the PMIC will automatically reset the interface when the clock signal ceases for more than the SMBus timeout of 35 ms. If the I2C driver / device is not capable of creating atomic I2C transactions, a context change can cause a ceasing of the clock signal. This can happen if for example a real-time thread is scheduled. Then the DA9063 in SMBus mode will reset the 2-wire interface. Subsequently a write message could end up in the wrong register. This could cause unpredictable system behavior. The DA9063 PMIC also supports an I2C compliant mode for the 2-wire interface. This mode does not reset the interface when the clock signal ceases. Thus the problem depicted above does not occur. This patch tests for the bus functionality "I2C_FUNC_I2C". It can reasonably be assumed that the bus cannot obey SMBus timings if this functionality is set. SMBus commands most probably are emulated in this case which is prone to the latency issue described above. This patch enables the I2C bus mode if I2C_FUNC_I2C is set or otherwise keeps the default SMBus mode. Signed-off-by: Hubert Streidl Signed-off-by: Mark Jonas Reviewed-by: Wolfram Sang Signed-off-by: Lee Jones --- drivers/mfd/da9063-i2c.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c index 3781d0bb7786..783a14af18e2 100644 --- a/drivers/mfd/da9063-i2c.c +++ b/drivers/mfd/da9063-i2c.c @@ -442,6 +442,16 @@ static int da9063_i2c_probe(struct i2c_client *i2c, return ret; } + /* If SMBus is not available and only I2C is possible, enter I2C mode */ + if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + ret = regmap_clear_bits(da9063->regmap, DA9063_REG_CONFIG_J, + DA9063_TWOWIRE_TO); + if (ret < 0) { + dev_err(da9063->dev, "Failed to set Two-Wire Bus Mode.\n"); + return -EIO; + } + } + return da9063_device_init(da9063, i2c->irq); } -- cgit v1.2.3 From 42e59982917a25ad254b74e6e8decee5e684763d Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 1 Mar 2021 16:42:19 +0200 Subject: mfd: core: Add support for software nodes The old device property API is going to be removed and replaced with the newer software node API. This prepares MFD subsystem for the transition. Signed-off-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index fc00aaccb5f7..e24008b94aac 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -244,6 +244,12 @@ static int mfd_add_device(struct device *parent, int id, goto fail_of_entry; } + if (cell->swnode) { + ret = device_add_software_node(&pdev->dev, cell->swnode); + if (ret) + goto fail_of_entry; + } + for (r = 0; r < cell->num_resources; r++) { res[r].name = cell->resources[r].name; res[r].flags = cell->resources[r].flags; @@ -304,6 +310,7 @@ fail_of_entry: list_del(&of_entry->list); kfree(of_entry); } + device_remove_software_node(&pdev->dev); fail_alias: regulator_bulk_unregister_supply_alias(&pdev->dev, cell->parent_supplies, @@ -372,6 +379,8 @@ static int mfd_remove_devices_fn(struct device *dev, void *data) regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies, cell->num_parent_supplies); + device_remove_software_node(&pdev->dev); + platform_device_unregister(pdev); return 0; } -- cgit v1.2.3 From 9677e6f78f75470318f021d0ac43107ffee62dc0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 1 Mar 2021 16:42:20 +0200 Subject: mfd: intel-lpss: Constify device property structures There is no point to have non-constant device properties in this driver. Thus, constify them for good. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss-acpi.c | 8 ++++---- drivers/mfd/intel-lpss-pci.c | 10 +++++----- drivers/mfd/intel-lpss.h | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index c8fe334b5fe8..14a9cd83d4ef 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -22,7 +22,7 @@ static const struct intel_lpss_platform_info spt_info = { .clk_rate = 120000000, }; -static struct property_entry spt_i2c_properties[] = { +static const struct property_entry spt_i2c_properties[] = { PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), { }, }; @@ -32,7 +32,7 @@ static const struct intel_lpss_platform_info spt_i2c_info = { .properties = spt_i2c_properties, }; -static struct property_entry uart_properties[] = { +static const struct property_entry uart_properties[] = { PROPERTY_ENTRY_U32("reg-io-width", 4), PROPERTY_ENTRY_U32("reg-shift", 2), PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"), @@ -49,7 +49,7 @@ static const struct intel_lpss_platform_info bxt_info = { .clk_rate = 100000000, }; -static struct property_entry bxt_i2c_properties[] = { +static const struct property_entry bxt_i2c_properties[] = { PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42), PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), @@ -61,7 +61,7 @@ static const struct intel_lpss_platform_info bxt_i2c_info = { .properties = bxt_i2c_properties, }; -static struct property_entry apl_i2c_properties[] = { +static const struct property_entry apl_i2c_properties[] = { PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207), PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 1522c8afc540..7837f77d70d0 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -65,7 +65,7 @@ static const struct intel_lpss_platform_info spt_info = { .clk_rate = 120000000, }; -static struct property_entry spt_i2c_properties[] = { +static const struct property_entry spt_i2c_properties[] = { PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 230), { }, }; @@ -75,7 +75,7 @@ static const struct intel_lpss_platform_info spt_i2c_info = { .properties = spt_i2c_properties, }; -static struct property_entry uart_properties[] = { +static const struct property_entry uart_properties[] = { PROPERTY_ENTRY_U32("reg-io-width", 4), PROPERTY_ENTRY_U32("reg-shift", 2), PROPERTY_ENTRY_BOOL("snps,uart-16550-compatible"), @@ -98,7 +98,7 @@ static const struct intel_lpss_platform_info bxt_uart_info = { .properties = uart_properties, }; -static struct property_entry bxt_i2c_properties[] = { +static const struct property_entry bxt_i2c_properties[] = { PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 42), PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), @@ -110,7 +110,7 @@ static const struct intel_lpss_platform_info bxt_i2c_info = { .properties = bxt_i2c_properties, }; -static struct property_entry apl_i2c_properties[] = { +static const struct property_entry apl_i2c_properties[] = { PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207), PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208), @@ -122,7 +122,7 @@ static const struct intel_lpss_platform_info apl_i2c_info = { .properties = apl_i2c_properties, }; -static struct property_entry glk_i2c_properties[] = { +static const struct property_entry glk_i2c_properties[] = { PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 313), PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171), PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 290), diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index 4ae58a86bb42..a2fbaed061ba 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h @@ -22,7 +22,7 @@ struct intel_lpss_platform_info { int irq; unsigned long clk_rate; const char *clk_con_id; - struct property_entry *properties; + const struct property_entry *properties; }; int intel_lpss_probe(struct device *dev, -- cgit v1.2.3 From 03152e35dd228065d4189464fe1b2554434da6ac Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 1 Mar 2021 16:42:21 +0200 Subject: mfd: intel-lpss: Switch to use the software nodes Software node was always created for the device if it was supplied with additional device properties, so those nodes might as well be constant. Signed-off-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss-acpi.c | 24 ++++++++++++++++++++---- drivers/mfd/intel-lpss-pci.c | 36 ++++++++++++++++++++++++++++-------- drivers/mfd/intel-lpss.c | 2 +- drivers/mfd/intel-lpss.h | 4 ++-- 4 files changed, 51 insertions(+), 15 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 14a9cd83d4ef..1f396039d58f 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -27,9 +27,13 @@ static const struct property_entry spt_i2c_properties[] = { { }, }; +static const struct software_node spt_i2c_node = { + .properties = spt_i2c_properties, +}; + static const struct intel_lpss_platform_info spt_i2c_info = { .clk_rate = 120000000, - .properties = spt_i2c_properties, + .swnode = &spt_i2c_node, }; static const struct property_entry uart_properties[] = { @@ -39,10 +43,14 @@ static const struct property_entry uart_properties[] = { { }, }; +static const struct software_node uart_node = { + .properties = uart_properties, +}; + static const struct intel_lpss_platform_info spt_uart_info = { .clk_rate = 120000000, .clk_con_id = "baudclk", - .properties = uart_properties, + .swnode = &uart_node, }; static const struct intel_lpss_platform_info bxt_info = { @@ -56,9 +64,13 @@ static const struct property_entry bxt_i2c_properties[] = { { }, }; +static const struct software_node bxt_i2c_node = { + .properties = bxt_i2c_properties, +}; + static const struct intel_lpss_platform_info bxt_i2c_info = { .clk_rate = 133000000, - .properties = bxt_i2c_properties, + .swnode = &bxt_i2c_node, }; static const struct property_entry apl_i2c_properties[] = { @@ -68,9 +80,13 @@ static const struct property_entry apl_i2c_properties[] = { { }, }; +static const struct software_node apl_i2c_node = { + .properties = apl_i2c_properties, +}; + static const struct intel_lpss_platform_info apl_i2c_info = { .clk_rate = 133000000, - .properties = apl_i2c_properties, + .swnode = &apl_i2c_node, }; static const struct acpi_device_id intel_lpss_acpi_ids[] = { diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 7837f77d70d0..79c53617489c 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -70,9 +70,13 @@ static const struct property_entry spt_i2c_properties[] = { { }, }; +static const struct software_node spt_i2c_node = { + .properties = spt_i2c_properties, +}; + static const struct intel_lpss_platform_info spt_i2c_info = { .clk_rate = 120000000, - .properties = spt_i2c_properties, + .swnode = &spt_i2c_node, }; static const struct property_entry uart_properties[] = { @@ -82,10 +86,14 @@ static const struct property_entry uart_properties[] = { { }, }; +static const struct software_node uart_node = { + .properties = uart_properties, +}; + static const struct intel_lpss_platform_info spt_uart_info = { .clk_rate = 120000000, .clk_con_id = "baudclk", - .properties = uart_properties, + .swnode = &uart_node, }; static const struct intel_lpss_platform_info bxt_info = { @@ -95,7 +103,7 @@ static const struct intel_lpss_platform_info bxt_info = { static const struct intel_lpss_platform_info bxt_uart_info = { .clk_rate = 100000000, .clk_con_id = "baudclk", - .properties = uart_properties, + .swnode = &uart_node, }; static const struct property_entry bxt_i2c_properties[] = { @@ -105,9 +113,13 @@ static const struct property_entry bxt_i2c_properties[] = { { }, }; +static const struct software_node bxt_i2c_node = { + .properties = bxt_i2c_properties, +}; + static const struct intel_lpss_platform_info bxt_i2c_info = { .clk_rate = 133000000, - .properties = bxt_i2c_properties, + .swnode = &bxt_i2c_node, }; static const struct property_entry apl_i2c_properties[] = { @@ -117,9 +129,13 @@ static const struct property_entry apl_i2c_properties[] = { { }, }; +static const struct software_node apl_i2c_node = { + .properties = apl_i2c_properties, +}; + static const struct intel_lpss_platform_info apl_i2c_info = { .clk_rate = 133000000, - .properties = apl_i2c_properties, + .swnode = &apl_i2c_node, }; static const struct property_entry glk_i2c_properties[] = { @@ -129,19 +145,23 @@ static const struct property_entry glk_i2c_properties[] = { { }, }; +static const struct software_node glk_i2c_node = { + .properties = glk_i2c_properties, +}; + static const struct intel_lpss_platform_info glk_i2c_info = { .clk_rate = 133000000, - .properties = glk_i2c_properties, + .swnode = &glk_i2c_node, }; static const struct intel_lpss_platform_info cnl_i2c_info = { .clk_rate = 216000000, - .properties = spt_i2c_properties, + .swnode = &spt_i2c_node, }; static const struct intel_lpss_platform_info ehl_i2c_info = { .clk_rate = 100000000, - .properties = bxt_i2c_properties, + .swnode = &bxt_i2c_node, }; static const struct pci_device_id intel_lpss_pci_ids[] = { diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index b0f0781a6b9c..a9bf10bee796 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -399,7 +399,7 @@ int intel_lpss_probe(struct device *dev, if (ret) return ret; - lpss->cell->properties = info->properties; + lpss->cell->swnode = info->swnode; intel_lpss_init_dev(lpss); diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index a2fbaed061ba..22dbc4aed793 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h @@ -15,14 +15,14 @@ struct device; struct resource; -struct property_entry; +struct software_node; struct intel_lpss_platform_info { struct resource *mem; int irq; unsigned long clk_rate; const char *clk_con_id; - const struct property_entry *properties; + const struct software_node *swnode; }; int intel_lpss_probe(struct device *dev, -- cgit v1.2.3 From b4a66acc0997cff7cb9a4c3992e97808700aa1ff Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Mon, 1 Mar 2021 16:42:22 +0200 Subject: mfd: core: Remove support for dangling device properties From now on only accepting complete software nodes. Signed-off-by: Heikki Krogerus Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index e24008b94aac..6dcff4b8e15e 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -238,12 +238,6 @@ static int mfd_add_device(struct device *parent, int id, goto fail_of_entry; } - if (cell->properties) { - ret = platform_device_add_properties(pdev, cell->properties); - if (ret) - goto fail_of_entry; - } - if (cell->swnode) { ret = device_add_software_node(&pdev->dev, cell->swnode); if (ret) -- cgit v1.2.3 From c0d46b89ddeae419ee3ee8679fe6836119a83e14 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 11 Mar 2021 13:15:07 +0000 Subject: mfd: Make symbol 'atc260x_i2c_of_match' static The sparse tool complains as follows: drivers/mfd/atc260x-i2c.c:45:27: warning: symbol 'atc260x_i2c_of_match' was not declared. Should it be static? This symbol is not used outside of atc260x-i2c.c, so this commit marks it static. Fixes: f7cb7fe34db9 ("mfd: Add MFD driver for ATC260x PMICs") Reported-by: Hulk Robot Signed-off-by: Wei Yongjun Reviewed-by: Cristian Ciocaltea Signed-off-by: Lee Jones --- drivers/mfd/atc260x-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/atc260x-i2c.c b/drivers/mfd/atc260x-i2c.c index 362005703367..5855efd09efc 100644 --- a/drivers/mfd/atc260x-i2c.c +++ b/drivers/mfd/atc260x-i2c.c @@ -42,7 +42,7 @@ static int atc260x_i2c_probe(struct i2c_client *client, return atc260x_device_probe(atc260x); } -const struct of_device_id atc260x_i2c_of_match[] = { +static const struct of_device_id atc260x_i2c_of_match[] = { { .compatible = "actions,atc2603c", .data = (void *)ATC2603C }, { .compatible = "actions,atc2609a", .data = (void *)ATC2609A }, { } -- cgit v1.2.3 From 4502647e60cb4afd74f74d648bc2990954c1b73a Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Sun, 14 Mar 2021 12:02:36 +0100 Subject: mfd: rn5t618: Do not cache various USB related registers These register get reset to their OTP defaults after USB plugging. And while at it, also add a missing register for detecting the charger type. Signed-off-by: Andreas Kemnade Signed-off-by: Lee Jones --- drivers/mfd/rn5t618.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index dc452df1f1bf..6ed04e6dbc78 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -45,8 +45,11 @@ static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg) case RN5T618_INTMON: case RN5T618_RTC_CTRL1 ... RN5T618_RTC_CTRL2: case RN5T618_RTC_SECONDS ... RN5T618_RTC_YEAR: + case RN5T618_CHGCTL1: + case RN5T618_REGISET1 ... RN5T618_REGISET2: case RN5T618_CHGSTATE: case RN5T618_CHGCTRL_IRR ... RN5T618_CHGERR_MONI: + case RN5T618_GCHGDET: case RN5T618_CONTROL ... RN5T618_CC_AVEREG0: return true; default: -- cgit v1.2.3 From 0cab0aa14928ddf626d9e55944b59a3520187ac7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 16 Mar 2021 14:37:00 +0100 Subject: mfd: Kconfig: ABX500_CORE should depend on ARCH_U8500 The ST-Ericsson ABX500 Mixed Signal IC family chips are only present on ST-Ericsson U8500 Series platforms. Hence add a dependency on ARCH_U8500, to prevent asking the user about this driver when configuring a kernel without U8500 support. Also, merely enabling CONFIG_COMPILE_TEST should not enable additional code, and thus should not enable this driver by default. Signed-off-by: Geert Uytterhoeven Reviewed-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 2152126c5b0b..ffd616a17852 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1235,7 +1235,8 @@ config MFD_SC27XX_PMIC config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" - default y if ARCH_U8500 || COMPILE_TEST + depends on ARCH_U8500 || COMPILE_TEST + default y if ARCH_U8500 help Say yes here if you have the ABX500 Mixed Signal IC family chips. This core driver expose register access functions. -- cgit v1.2.3 From 1514ce4935f317384313af88c387341997665c78 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Mar 2021 15:56:17 +0200 Subject: mfd: intel_quark_i2c_gpio: Unregister resources in reversed order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ->remove() unregister resources in reversed order, i.e. MFD devices first followed by I²C clock. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index fe8ca945f367..3f13dc3710b7 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -268,8 +268,8 @@ err_unregister_i2c_clk: static void intel_quark_mfd_remove(struct pci_dev *pdev) { - intel_quark_unregister_i2c_clk(&pdev->dev); mfd_remove_devices(&pdev->dev); + intel_quark_unregister_i2c_clk(&pdev->dev); } static struct pci_driver intel_quark_mfd_driver = { -- cgit v1.2.3 From 2b77ea7a0a42878a0a3f2956cfc657281fcf74c0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Mar 2021 15:56:18 +0200 Subject: mfd: intel_quark_i2c_gpio: Remove unused struct device member The device pointer in the custom structure is not used anywhere, remove it for good. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 3f13dc3710b7..532c852a2732 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -45,7 +45,6 @@ #define INTEL_QUARK_I2C_CLK_HZ 33000000 struct intel_quark_mfd { - struct device *dev; struct clk *i2c_clk; struct clk_lookup *i2c_clk_lookup; }; @@ -238,7 +237,6 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, if (!quark_mfd) return -ENOMEM; - quark_mfd->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, quark_mfd); ret = intel_quark_register_i2c_clk(&pdev->dev); -- cgit v1.2.3 From 10d82ade4fa7dd032b60fc6ba76cd587b276608e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 2 Mar 2021 15:56:19 +0200 Subject: =?UTF-8?q?mfd:=20intel=5Fquark=5Fi2c=5Fgpio:=20Replace=20I=C2=B2C?= =?UTF-8?q?=20speeds=20with=20descriptive=20definitions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I²C header provides a descriptive definitions for standard bus speeds. Use them instead of plain numbers. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 532c852a2732..f7e1634e43b3 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -54,19 +55,19 @@ static const struct dmi_system_id dmi_platform_info[] = { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"), }, - .driver_data = (void *)100000, + .driver_data = (void *)I2C_MAX_STANDARD_MODE_FREQ, }, { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"), }, - .driver_data = (void *)400000, + .driver_data = (void *)I2C_MAX_FAST_MODE_FREQ, }, { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), }, - .driver_data = (void *)400000, + .driver_data = (void *)I2C_MAX_FAST_MODE_FREQ, }, {} }; @@ -174,7 +175,7 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) return -ENOMEM; /* Normal mode by default */ - pdata->i2c_scl_freq = 100000; + pdata->i2c_scl_freq = I2C_MAX_STANDARD_MODE_FREQ; dmi_id = dmi_first_match(dmi_platform_info); if (dmi_id) -- cgit v1.2.3 From 4917e498c6894ba077867aff78f82cffd5ffbb5c Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 3 Mar 2021 18:51:35 +0100 Subject: mfd: stm32-timers: Avoid clearing auto reload register The ARR register is cleared unconditionally upon probing, after the maximum value has been read. This initial condition is rather not intuitive, when considering the counter child driver. It rather expects the maximum value by default: - The counter interface shows a zero value by default for 'ceiling' attribute. - Enabling the counter without any prior configuration makes it doesn't count. The reset value of ARR register is the maximum. So Choice here is to backup it, and restore it then, instead of clearing its value. It also fixes the initial condition seen by the counter driver. Fixes: d0f949e220fd ("mfd: Add STM32 Timers driver") Signed-off-by: Fabrice Gasnier Acked-by: William Breathitt Gray Signed-off-by: Lee Jones --- drivers/mfd/stm32-timers.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c index add603359124..44ed2fce0319 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -158,13 +158,18 @@ static const struct regmap_config stm32_timers_regmap_cfg = { static void stm32_timers_get_arr_size(struct stm32_timers *ddata) { + u32 arr; + + /* Backup ARR to restore it after getting the maximum value */ + regmap_read(ddata->regmap, TIM_ARR, &arr); + /* * Only the available bits will be written so when readback * we get the maximum value of auto reload register */ regmap_write(ddata->regmap, TIM_ARR, ~0L); regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr); - regmap_write(ddata->regmap, TIM_ARR, 0x0); + regmap_write(ddata->regmap, TIM_ARR, arr); } static int stm32_timers_dma_probe(struct device *dev, -- cgit v1.2.3 From d1157530d476ffce4485182eea5b492065362a09 Mon Sep 17 00:00:00 2001 From: Andreas Kemnade Date: Mon, 15 Mar 2021 20:18:32 +0100 Subject: mfd: ntxec: Support for EC in Tolino Shine 2 HD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the version of the EC in the Tolino Shine 2 HD to the supported versions. It seems not to have an RTC and does not ack data written to it. The vendor kernel happily ignores write errors, using I2C via userspace i2c-set also shows the error. So add a quirk to ignore that error. PWM can be successfully configured despite of that error. Signed-off-by: Andreas Kemnade Reviewed-by: Jonathan Neuschäfer Signed-off-by: Lee Jones --- drivers/mfd/ntxec.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c index 957de2b03529..b711e73eedcb 100644 --- a/drivers/mfd/ntxec.c +++ b/drivers/mfd/ntxec.c @@ -96,6 +96,38 @@ static struct notifier_block ntxec_restart_handler = { .priority = 128, }; +static int regmap_ignore_write(void *context, + unsigned int reg, unsigned int val) + +{ + struct regmap *regmap = context; + + regmap_write(regmap, reg, val); + + return 0; +} + +static int regmap_wrap_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct regmap *regmap = context; + + return regmap_read(regmap, reg, val); +} + +/* + * Some firmware versions do not ack written data, add a wrapper. It + * is used to stack another regmap on top. + */ +static const struct regmap_config regmap_config_noack = { + .name = "ntxec_noack", + .reg_bits = 8, + .val_bits = 16, + .cache_type = REGCACHE_NONE, + .reg_write = regmap_ignore_write, + .reg_read = regmap_wrap_read +}; + static const struct regmap_config regmap_config = { .name = "ntxec", .reg_bits = 8, @@ -104,16 +136,22 @@ static const struct regmap_config regmap_config = { .val_format_endian = REGMAP_ENDIAN_BIG, }; -static const struct mfd_cell ntxec_subdevices[] = { +static const struct mfd_cell ntxec_subdev[] = { { .name = "ntxec-rtc" }, { .name = "ntxec-pwm" }, }; +static const struct mfd_cell ntxec_subdev_pwm[] = { + { .name = "ntxec-pwm" }, +}; + static int ntxec_probe(struct i2c_client *client) { struct ntxec *ec; unsigned int version; int res; + const struct mfd_cell *subdevs; + size_t n_subdevs; ec = devm_kmalloc(&client->dev, sizeof(*ec), GFP_KERNEL); if (!ec) @@ -137,6 +175,18 @@ static int ntxec_probe(struct i2c_client *client) /* Bail out if we encounter an unknown firmware version */ switch (version) { case NTXEC_VERSION_KOBO_AURA: + subdevs = ntxec_subdev; + n_subdevs = ARRAY_SIZE(ntxec_subdev); + break; + case NTXEC_VERSION_TOLINO_SHINE2: + subdevs = ntxec_subdev_pwm; + n_subdevs = ARRAY_SIZE(ntxec_subdev_pwm); + /* Another regmap stacked on top of the other */ + ec->regmap = devm_regmap_init(ec->dev, NULL, + ec->regmap, + ®map_config_noack); + if (IS_ERR(ec->regmap)) + return PTR_ERR(ec->regmap); break; default: dev_err(ec->dev, @@ -181,8 +231,8 @@ static int ntxec_probe(struct i2c_client *client) i2c_set_clientdata(client, ec); - res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE, ntxec_subdevices, - ARRAY_SIZE(ntxec_subdevices), NULL, 0, NULL); + res = devm_mfd_add_devices(ec->dev, PLATFORM_DEVID_NONE, + subdevs, n_subdevs, NULL, 0, NULL); if (res) dev_err(ec->dev, "Failed to add subdevices: %d\n", res); -- cgit v1.2.3 From 98d6e7fce6b0174c701dc596539dc7bc1e96f8ce Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 23 Mar 2021 14:34:32 +0200 Subject: mfd: intel_quark_i2c_gpio: Reuse BAR definitions for MFD cell indexing It's convenient and less error prone to use definitions to address different cells in an array. For this purpose we may reuse existing BAR definitions. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index f7e1634e43b3..d63427876210 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -96,15 +96,7 @@ static struct mfd_cell_acpi_match intel_quark_acpi_match_gpio = { }; static struct mfd_cell intel_quark_mfd_cells[] = { - { - .id = MFD_GPIO_BAR, - .name = "gpio-dwapb", - .acpi_match = &intel_quark_acpi_match_gpio, - .num_resources = ARRAY_SIZE(intel_quark_gpio_res), - .resources = intel_quark_gpio_res, - .ignore_resource_conflicts = true, - }, - { + [MFD_I2C_BAR] = { .id = MFD_I2C_BAR, .name = "i2c_designware", .acpi_match = &intel_quark_acpi_match_i2c, @@ -112,6 +104,14 @@ static struct mfd_cell intel_quark_mfd_cells[] = { .resources = intel_quark_i2c_res, .ignore_resource_conflicts = true, }, + [MFD_GPIO_BAR] = { + .id = MFD_GPIO_BAR, + .name = "gpio-dwapb", + .acpi_match = &intel_quark_acpi_match_gpio, + .num_resources = ARRAY_SIZE(intel_quark_gpio_res), + .resources = intel_quark_gpio_res, + .ignore_resource_conflicts = true, + }, }; static const struct pci_device_id intel_quark_mfd_ids[] = { @@ -244,11 +244,11 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, if (ret) return ret; - ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[1]); + ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[MFD_I2C_BAR]); if (ret) goto err_unregister_i2c_clk; - ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[0]); + ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[MFD_GPIO_BAR]); if (ret) goto err_unregister_i2c_clk; -- cgit v1.2.3 From 91076ebb3e2204cbb81aa2d6930f2a88638e4bb0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 24 Mar 2021 19:08:34 +0200 Subject: mfd: intel_quark_i2c_gpio: Enable MSI interrupt Allow interrupts to be MSI if supported by hardware. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index d63427876210..5253504b22e9 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -167,8 +167,8 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR); - res[INTEL_QUARK_IORES_IRQ].start = pdev->irq; - res[INTEL_QUARK_IORES_IRQ].end = pdev->irq; + res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0); + res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -215,7 +215,7 @@ static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) pdata->properties->idx = 0; pdata->properties->ngpio = INTEL_QUARK_MFD_NGPIO; pdata->properties->gpio_base = INTEL_QUARK_MFD_GPIO_BASE; - pdata->properties->irq[0] = pdev->irq; + pdata->properties->irq[0] = pci_irq_vector(pdev, 0); pdata->properties->irq_shared = true; cell->platform_data = pdata; @@ -244,22 +244,31 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, if (ret) return ret; + pci_set_master(pdev); + + /* This driver only requires 1 IRQ vector */ + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + goto err_unregister_i2c_clk; + ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[MFD_I2C_BAR]); if (ret) - goto err_unregister_i2c_clk; + goto err_free_irq_vectors; ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[MFD_GPIO_BAR]); if (ret) - goto err_unregister_i2c_clk; + goto err_free_irq_vectors; ret = mfd_add_devices(&pdev->dev, 0, intel_quark_mfd_cells, ARRAY_SIZE(intel_quark_mfd_cells), NULL, 0, NULL); if (ret) - goto err_unregister_i2c_clk; + goto err_free_irq_vectors; return 0; +err_free_irq_vectors: + pci_free_irq_vectors(pdev); err_unregister_i2c_clk: intel_quark_unregister_i2c_clk(&pdev->dev); return ret; @@ -268,6 +277,7 @@ err_unregister_i2c_clk: static void intel_quark_mfd_remove(struct pci_dev *pdev) { mfd_remove_devices(&pdev->dev); + pci_free_irq_vectors(pdev); intel_quark_unregister_i2c_clk(&pdev->dev); } -- cgit v1.2.3 From 6dac44c602bef283484ca84591396e65f8d8f1a5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 26 Mar 2021 14:48:42 +0200 Subject: mfd: intel_quark_i2c_gpio: Don't play dirty trick with const As Linus rightfully noticed, the driver plays dirty trick with const, i.e. it assigns a place holder data structure to the const field in the MFD cell and then drops the const by explicit casting. This is not how it should be. Assign local pointers of the cell and resource to the respective non-const place holders in the intel_quark_i2c_setup() and intel_quark_gpio_setup(). Reported-by: Linus Torvalds Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 5253504b22e9..8eb36c79f320 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -155,17 +155,16 @@ static void intel_quark_unregister_i2c_clk(struct device *dev) clk_unregister(quark_mfd->i2c_clk); } -static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) +static int intel_quark_i2c_setup(struct pci_dev *pdev) { + struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR]; + struct resource *res = intel_quark_i2c_res; const struct dmi_system_id *dmi_id; struct dw_i2c_platform_data *pdata; - struct resource *res = (struct resource *)cell->resources; struct device *dev = &pdev->dev; - res[INTEL_QUARK_IORES_MEM].start = - pci_resource_start(pdev, MFD_I2C_BAR); - res[INTEL_QUARK_IORES_MEM].end = - pci_resource_end(pdev, MFD_I2C_BAR); + res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR); + res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR); res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0); res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0); @@ -187,16 +186,15 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev, struct mfd_cell *cell) return 0; } -static int intel_quark_gpio_setup(struct pci_dev *pdev, struct mfd_cell *cell) +static int intel_quark_gpio_setup(struct pci_dev *pdev) { + struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_GPIO_BAR]; + struct resource *res = intel_quark_gpio_res; struct dwapb_platform_data *pdata; - struct resource *res = (struct resource *)cell->resources; struct device *dev = &pdev->dev; - res[INTEL_QUARK_IORES_MEM].start = - pci_resource_start(pdev, MFD_GPIO_BAR); - res[INTEL_QUARK_IORES_MEM].end = - pci_resource_end(pdev, MFD_GPIO_BAR); + res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_GPIO_BAR); + res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_GPIO_BAR); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -251,11 +249,11 @@ static int intel_quark_mfd_probe(struct pci_dev *pdev, if (ret < 0) goto err_unregister_i2c_clk; - ret = intel_quark_i2c_setup(pdev, &intel_quark_mfd_cells[MFD_I2C_BAR]); + ret = intel_quark_i2c_setup(pdev); if (ret) goto err_free_irq_vectors; - ret = intel_quark_gpio_setup(pdev, &intel_quark_mfd_cells[MFD_GPIO_BAR]); + ret = intel_quark_gpio_setup(pdev); if (ret) goto err_free_irq_vectors; -- cgit v1.2.3 From 40cb71f321dd753afa65cf9d90fb803f13b82df0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 6 Apr 2021 15:32:20 +0300 Subject: mfd: core: Use acpi_find_child_device() for child devices lookup Use acpi_find_child_device() for child devices lookup in mfd_acpi_add_device() instead of open coded approach. No functional change intended. While at it, amend a note comment, since usage of _ADR is found on other platforms and tables than Intel Galileo Gen 2, in particular USB wired devices are using it, according to Microsoft specifications for embedded platforms. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 6dcff4b8e15e..6f02b8022c6d 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -65,7 +65,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, { const struct mfd_cell_acpi_match *match = cell->acpi_match; struct acpi_device *parent, *child; - struct acpi_device *adev; + struct acpi_device *adev = NULL; parent = ACPI_COMPANION(pdev->dev.parent); if (!parent) @@ -77,10 +77,9 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, * _ADR or it will use the parent handle if is no ID is given. * * Note that use of _ADR is a grey area in the ACPI specification, - * though Intel Galileo Gen2 is using it to distinguish the children - * devices. + * though at least Intel Galileo Gen 2 is using it to distinguish + * the children devices. */ - adev = parent; if (match) { if (match->pnpid) { struct acpi_device_id ids[2] = {}; @@ -93,22 +92,11 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, } } } else { - unsigned long long adr; - acpi_status status; - - list_for_each_entry(child, &parent->children, node) { - status = acpi_evaluate_integer(child->handle, - "_ADR", NULL, - &adr); - if (ACPI_SUCCESS(status) && match->adr == adr) { - adev = child; - break; - } - } + adev = acpi_find_child_device(parent, match->adr, false); } } - ACPI_COMPANION_SET(&pdev->dev, adev); + ACPI_COMPANION_SET(&pdev->dev, adev ?: parent); } #else static inline void mfd_acpi_add_device(const struct mfd_cell *cell, -- cgit v1.2.3 From fe6df2b48043bbe1e852b2320501d3b169363c35 Mon Sep 17 00:00:00 2001 From: Dinghao Liu Date: Wed, 7 Apr 2021 13:11:49 +0800 Subject: mfd: arizona: Fix rumtime PM imbalance on error pm_runtime_get_sync() will increase the rumtime PM counter even it returns an error. Thus a pairing decrement is needed to prevent refcount leak. Fix this by replacing this API with pm_runtime_resume_and_get(), which will not change the runtime PM counter on error. Signed-off-by: Dinghao Liu Acked-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 077d9ab112b7..d919ae9691e2 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -100,7 +100,7 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) unsigned int val; int ret; - ret = pm_runtime_get_sync(arizona->dev); + ret = pm_runtime_resume_and_get(arizona->dev); if (ret < 0) { dev_err(arizona->dev, "Failed to resume device: %d\n", ret); return IRQ_NONE; -- cgit v1.2.3 From 922e8ce883e59b52786b2c11656d84dc58ef084a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 3 Mar 2021 18:49:44 +0200 Subject: mfd: lpc_sch: Partially revert "Add support for Intel Quark X1000" The IRQ support for SCH GPIO is not specific to the Intel Quark SoC. Moreover the IRQ routing is quite interesting there, so while it's needs a special support, the driver haven't it anyway yet. Due to above remove basically redundant code of IRQ support. This reverts commit ec689a8a8155ce8b966bd5d7737a3916f5e48be3. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/lpc_sch.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index f27eb8dabc1c..428a526cbe86 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -26,9 +26,6 @@ #define GPIO_IO_SIZE 64 #define GPIO_IO_SIZE_CENTERTON 128 -/* Intel Quark X1000 GPIO IRQ Number */ -#define GPIO_IRQ_QUARK_X1000 9 - #define WDTBASE 0x84 #define WDT_IO_SIZE 64 @@ -43,30 +40,25 @@ struct lpc_sch_info { unsigned int io_size_smbus; unsigned int io_size_gpio; unsigned int io_size_wdt; - int irq_gpio; }; static struct lpc_sch_info sch_chipset_info[] = { [LPC_SCH] = { .io_size_smbus = SMBUS_IO_SIZE, .io_size_gpio = GPIO_IO_SIZE, - .irq_gpio = -1, }, [LPC_ITC] = { .io_size_smbus = SMBUS_IO_SIZE, .io_size_gpio = GPIO_IO_SIZE, .io_size_wdt = WDT_IO_SIZE, - .irq_gpio = -1, }, [LPC_CENTERTON] = { .io_size_smbus = SMBUS_IO_SIZE, .io_size_gpio = GPIO_IO_SIZE_CENTERTON, .io_size_wdt = WDT_IO_SIZE, - .irq_gpio = -1, }, [LPC_QUARK_X1000] = { .io_size_gpio = GPIO_IO_SIZE, - .irq_gpio = GPIO_IRQ_QUARK_X1000, .io_size_wdt = WDT_IO_SIZE, }, }; @@ -113,13 +105,13 @@ static int lpc_sch_get_io(struct pci_dev *pdev, int where, const char *name, } static int lpc_sch_populate_cell(struct pci_dev *pdev, int where, - const char *name, int size, int irq, - int id, struct mfd_cell *cell) + const char *name, int size, int id, + struct mfd_cell *cell) { struct resource *res; int ret; - res = devm_kcalloc(&pdev->dev, 2, sizeof(*res), GFP_KERNEL); + res = devm_kzalloc(&pdev->dev, sizeof(*res), GFP_KERNEL); if (!res) return -ENOMEM; @@ -135,18 +127,6 @@ static int lpc_sch_populate_cell(struct pci_dev *pdev, int where, cell->ignore_resource_conflicts = true; cell->id = id; - /* Check if we need to add an IRQ resource */ - if (irq < 0) - return 0; - - res++; - - res->start = irq; - res->end = irq; - res->flags = IORESOURCE_IRQ; - - cell->num_resources++; - return 0; } @@ -158,7 +138,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) int ret; ret = lpc_sch_populate_cell(dev, SMBASE, "isch_smbus", - info->io_size_smbus, -1, + info->io_size_smbus, id->device, &lpc_sch_cells[cells]); if (ret < 0) return ret; @@ -166,7 +146,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) cells++; ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio", - info->io_size_gpio, info->irq_gpio, + info->io_size_gpio, id->device, &lpc_sch_cells[cells]); if (ret < 0) return ret; @@ -174,7 +154,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) cells++; ret = lpc_sch_populate_cell(dev, WDTBASE, "ie6xx_wdt", - info->io_size_wdt, -1, + info->io_size_wdt, id->device, &lpc_sch_cells[cells]); if (ret < 0) return ret; -- cgit v1.2.3 From c58ddd297fb903e11b0fcae0c0d38106125c1b58 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 31 Mar 2021 18:48:50 +0300 Subject: =?UTF-8?q?mfd:=20intel=5Fquark=5Fi2c=5Fgpio:=20Convert=20I=C2=B2C?= =?UTF-8?q?=20to=20use=20software=20nodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can provide a software node group instead of passing legacy platform data. This will allow to drop the legacy platform data structures along with unifying a child device driver to use same interface for all property providers, i.e. Device Tree, ACPI, and board files. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/intel_quark_i2c_gpio.c | 41 ++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 8eb36c79f320..553881f5ef36 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* PCI BAR for register base address */ #define MFD_I2C_BAR 0 @@ -50,24 +50,44 @@ struct intel_quark_mfd { struct clk_lookup *i2c_clk_lookup; }; +static const struct property_entry intel_quark_i2c_controller_standard_properties[] = { + PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_STANDARD_MODE_FREQ), + { } +}; + +static const struct software_node intel_quark_i2c_controller_standard_node = { + .name = "intel-quark-i2c-controller", + .properties = intel_quark_i2c_controller_standard_properties, +}; + +static const struct property_entry intel_quark_i2c_controller_fast_properties[] = { + PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_FREQ), + { } +}; + +static const struct software_node intel_quark_i2c_controller_fast_node = { + .name = "intel-quark-i2c-controller", + .properties = intel_quark_i2c_controller_fast_properties, +}; + static const struct dmi_system_id dmi_platform_info[] = { { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "Galileo"), }, - .driver_data = (void *)I2C_MAX_STANDARD_MODE_FREQ, + .driver_data = (void *)&intel_quark_i2c_controller_standard_node, }, { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "GalileoGen2"), }, - .driver_data = (void *)I2C_MAX_FAST_MODE_FREQ, + .driver_data = (void *)&intel_quark_i2c_controller_fast_node, }, { .matches = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), }, - .driver_data = (void *)I2C_MAX_FAST_MODE_FREQ, + .driver_data = (void *)&intel_quark_i2c_controller_fast_node, }, {} }; @@ -160,8 +180,6 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev) struct mfd_cell *cell = &intel_quark_mfd_cells[MFD_I2C_BAR]; struct resource *res = intel_quark_i2c_res; const struct dmi_system_id *dmi_id; - struct dw_i2c_platform_data *pdata; - struct device *dev = &pdev->dev; res[INTEL_QUARK_IORES_MEM].start = pci_resource_start(pdev, MFD_I2C_BAR); res[INTEL_QUARK_IORES_MEM].end = pci_resource_end(pdev, MFD_I2C_BAR); @@ -169,19 +187,12 @@ static int intel_quark_i2c_setup(struct pci_dev *pdev) res[INTEL_QUARK_IORES_IRQ].start = pci_irq_vector(pdev, 0); res[INTEL_QUARK_IORES_IRQ].end = pci_irq_vector(pdev, 0); - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; - /* Normal mode by default */ - pdata->i2c_scl_freq = I2C_MAX_STANDARD_MODE_FREQ; + cell->swnode = &intel_quark_i2c_controller_standard_node; dmi_id = dmi_first_match(dmi_platform_info); if (dmi_id) - pdata->i2c_scl_freq = (uintptr_t)dmi_id->driver_data; - - cell->platform_data = pdata; - cell->pdata_size = sizeof(*pdata); + cell->swnode = (struct software_node *)dmi_id->driver_data; return 0; } -- cgit v1.2.3 From 2397c3eef24c3511d2065f4b99c1fae399b9e0df Mon Sep 17 00:00:00 2001 From: Timon Baetz Date: Mon, 5 Apr 2021 07:14:35 +0000 Subject: Revert "mfd: max8997: Add of_compatible to Extcon and Charger mfd_cell" This reverts commit 9c03008da125c1007919a9186628af3cc105f526. commit 41a8a027f4d3 ("regulator: dt-bindings: Document charger-supply for max8997") introduced a binding which uses a property of the max8997 pmic node to configure charger supply, making subnodes for MFD cells obsolete. Signed-off-by: Timon Baetz Signed-off-by: Lee Jones --- drivers/mfd/max8997.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 55d3a6f97783..68d8f2b95287 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -29,9 +29,9 @@ static const struct mfd_cell max8997_devs[] = { { .name = "max8997-pmic", }, { .name = "max8997-rtc", }, - { .name = "max8997-battery", .of_compatible = "maxim,max8997-battery", }, + { .name = "max8997-battery", }, { .name = "max8997-haptic", }, - { .name = "max8997-muic", .of_compatible = "maxim,max8997-muic", }, + { .name = "max8997-muic", }, { .name = "max8997-led", .id = 1 }, { .name = "max8997-led", .id = 2 }, }; -- cgit v1.2.3