diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-22 18:29:42 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-02-22 18:29:42 +0100 |
commit | f158bbee9403b7bd2ad22f0c03b7e9762c20ad18 (patch) | |
tree | f269395da87bc13a31fe2511d65fa86c06202d55 /drivers | |
parent | Merge tag 'backlight-next-5.12' of git://git.kernel.org/pub/scm/linux/kernel/... (diff) | |
parent | mfd: wm831x-auxadc: Prevent use after free in wm831x_auxadc_read_irq() (diff) | |
download | linux-f158bbee9403b7bd2ad22f0c03b7e9762c20ad18.tar.xz linux-f158bbee9403b7bd2ad22f0c03b7e9762c20ad18.zip |
Merge tag 'mfd-next-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Core Frameworks:
- Standardise MFD_CELL_* helpers
New Drivers:
- Add support for Acer Iconia Tab A500 Embedded Controller
New Device Support:
- Add support for ROHM BD9574MWF to BD9571MWV
- Add support for Intel Alder Lake PCH-P PCI to LPSS
- Add support for Intel Alder Lake PCH-S PCI to LPSS
New Functionality:
- Support ACPI enumeration; arizona
Fix-ups:
- Managed resources; bd9571mwv
- DT additions/fix-ups; bd9571mwv, iqs62x, max8997, gateworks-gsc, ene-kb930
- Convert to SPDX; bd9571mw
- Fix return values/error handling; sunxi
- Provide SOFTDEP; arizona
- Make use of DIV_ROUND_UP; mcp-sa11x0
- Use generic APIs; arizona
- Add MAC address sysfs entries; intel-m10-bmc
- Trivial: Coding-style fix-ups; iqs62x
- Trivial: Remove superflouous code; iqs62x
- Clear-up naming conventions; iqs62x
Bug Fixes:
- Fix 'pointer from integer' error; altera-sysmgr
- Convert SGI_MFD_IOC3 from tristate to bool; Kconfig
- Fix interrupt handling; gateworks-gsc
- Extend required delay; iqs62x
- Do not use I2C polling during calibration; iqs62x
- Do no adjust clock frequency during calibration; iqs62x
- Fix use-after-free; wm831x-auxad"
* tag 'mfd-next-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (32 commits)
mfd: wm831x-auxadc: Prevent use after free in wm831x_auxadc_read_irq()
mfd: iqs62x: Do not change clock frequency during ATI
mfd: iqs62x: Do not poll during ATI
mfd: iqs62x: Increase interrupt handler return delay
mfd: iqs62x: Rename regmap_config struct
mfd: iqs62x: Remove unused bit mask
mfd: iqs62x: Remove superfluous whitespace above fallthroughs
mfd: intel-lpss: Add Intel Alder Lake PCH-S PCI IDs
mfd: intel-m10-bmc: Expose MAC address and count
mfd: Add driver for Embedded Controller found on Acer Iconia Tab A500
dt-bindings: mfd: Add ENE KB930 Embedded Controller binding
dt-bindings: mfd: gateworks-gsc: Add fan-tach mode
mfd: intel-lpss: Add Intel Alder Lake PCH-P PCI IDs
mfd: gateworks-gsc: Fix interrupt type
mfd: Standardise MFD_CELL_* helper names
mfd: mcp-sa11x0: Use DIV_ROUND_UP to calculate rw_timeout
mfd: max8997: Add of_compatible to Extcon and Charger mfd_cell
dt-bindings: mfd: Correct the node name of the panel LED
mfd: sgi-ioc3: Turn Kconfig option into a bool
mfd: altera-sysmgr: Fix physical address storing more
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/gpio-bd9571mwv.c | 35 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 13 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/ab8500-core.c | 42 | ||||
-rw-r--r-- | drivers/mfd/acer-ec-a500.c | 202 | ||||
-rw-r--r-- | drivers/mfd/altera-sysmgr.c | 3 | ||||
-rw-r--r-- | drivers/mfd/bd9571mwv.c | 178 | ||||
-rw-r--r-- | drivers/mfd/db8500-prcmu.c | 6 | ||||
-rw-r--r-- | drivers/mfd/gateworks-gsc.c | 2 | ||||
-rw-r--r-- | drivers/mfd/intel-lpss-pci.c | 28 | ||||
-rw-r--r-- | drivers/mfd/intel-m10-bmc.c | 43 | ||||
-rw-r--r-- | drivers/mfd/iqs62x.c | 144 | ||||
-rw-r--r-- | drivers/mfd/max8997.c | 4 | ||||
-rw-r--r-- | drivers/mfd/mcp-sa11x0.c | 3 | ||||
-rw-r--r-- | drivers/mfd/mt6360-core.c | 12 | ||||
-rw-r--r-- | drivers/mfd/wm831x-auxadc.c | 3 | ||||
-rw-r--r-- | drivers/regulator/bd9571mwv-regulator.c | 59 |
17 files changed, 569 insertions, 209 deletions
diff --git a/drivers/gpio/gpio-bd9571mwv.c b/drivers/gpio/gpio-bd9571mwv.c index c0abc9c6851b..df6102b57734 100644 --- a/drivers/gpio/gpio-bd9571mwv.c +++ b/drivers/gpio/gpio-bd9571mwv.c @@ -1,31 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * ROHM BD9571MWV-M GPIO driver + * ROHM BD9571MWV-M and BD9574MWF-M GPIO driver * * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65086 driver * * NOTE: Interrupts are not supported yet. */ #include <linux/gpio/driver.h> +#include <linux/mfd/rohm-generic.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/mfd/bd9571mwv.h> struct bd9571mwv_gpio { + struct regmap *regmap; struct gpio_chip chip; - struct bd9571mwv *bd; }; static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip, @@ -34,7 +27,7 @@ static int bd9571mwv_gpio_get_direction(struct gpio_chip *chip, struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); int ret, val; - ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_DIR, &val); + ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_DIR, &val); if (ret < 0) return ret; if (val & BIT(offset)) @@ -48,8 +41,7 @@ static int bd9571mwv_gpio_direction_input(struct gpio_chip *chip, { struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); - regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR, - BIT(offset), 0); + regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR, BIT(offset), 0); return 0; } @@ -60,9 +52,9 @@ static int bd9571mwv_gpio_direction_output(struct gpio_chip *chip, struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); /* Set the initial value */ - regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT, + regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT, BIT(offset), value ? BIT(offset) : 0); - regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_DIR, + regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_DIR, BIT(offset), BIT(offset)); return 0; @@ -73,7 +65,7 @@ static int bd9571mwv_gpio_get(struct gpio_chip *chip, unsigned int offset) struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); int ret, val; - ret = regmap_read(gpio->bd->regmap, BD9571MWV_GPIO_IN, &val); + ret = regmap_read(gpio->regmap, BD9571MWV_GPIO_IN, &val); if (ret < 0) return ret; @@ -85,7 +77,7 @@ static void bd9571mwv_gpio_set(struct gpio_chip *chip, unsigned int offset, { struct bd9571mwv_gpio *gpio = gpiochip_get_data(chip); - regmap_update_bits(gpio->bd->regmap, BD9571MWV_GPIO_OUT, + regmap_update_bits(gpio->regmap, BD9571MWV_GPIO_OUT, BIT(offset), value ? BIT(offset) : 0); } @@ -113,9 +105,9 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpio); - gpio->bd = dev_get_drvdata(pdev->dev.parent); + gpio->regmap = dev_get_regmap(pdev->dev.parent, NULL); gpio->chip = template_chip; - gpio->chip.parent = gpio->bd->dev; + gpio->chip.parent = pdev->dev.parent; ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); if (ret < 0) { @@ -127,7 +119,8 @@ static int bd9571mwv_gpio_probe(struct platform_device *pdev) } static const struct platform_device_id bd9571mwv_gpio_id_table[] = { - { "bd9571mwv-gpio", }, + { "bd9571mwv-gpio", ROHM_CHIP_TYPE_BD9571 }, + { "bd9574mwf-gpio", ROHM_CHIP_TYPE_BD9574 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, bd9571mwv_gpio_id_table); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index bdfce7b15621..40c723e9a852 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2085,6 +2085,17 @@ config MFD_KHADAS_MCU additional drivers must be enabled in order to use the functionality of the device. +config MFD_ACER_A500_EC + tristate "Support for Acer Iconia Tab A500 Embedded Controller" + depends on I2C + depends on (ARCH_TEGRA_2x_SOC && OF) || COMPILE_TEST + select MFD_CORE + select REGMAP + help + Support for Embedded Controller found on Acer Iconia Tab A500. + The controller itself is ENE KB930, it is running firmware + customized for the specific needs of the Acer A500 hardware. + menu "Multimedia Capabilities Port drivers" depends on ARCH_SA1100 @@ -2129,7 +2140,7 @@ config RAVE_SP_CORE device found on several devices in RAVE line of hardware. config SGI_MFD_IOC3 - tristate "SGI IOC3 core driver" + bool "SGI IOC3 core driver" depends on PCI && MIPS && 64BIT select MFD_CORE help diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 14fdb188af02..025543418835 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -264,6 +264,7 @@ obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.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 obj-$(CONFIG_SGI_MFD_IOC3) += ioc3.o obj-$(CONFIG_MFD_SIMPLE_MFD_I2C) += simple-mfd-i2c.o diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 3b2276f04a98..a9037911162b 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -609,52 +609,52 @@ int ab8500_suspend(struct ab8500 *ab8500) } static const struct mfd_cell ab8500_bm_devs[] = { - OF_MFD_CELL("ab8500-charger", NULL, &ab8500_bm_data, + MFD_CELL_OF("ab8500-charger", NULL, &ab8500_bm_data, sizeof(ab8500_bm_data), 0, "stericsson,ab8500-charger"), - OF_MFD_CELL("ab8500-btemp", NULL, &ab8500_bm_data, + MFD_CELL_OF("ab8500-btemp", NULL, &ab8500_bm_data, sizeof(ab8500_bm_data), 0, "stericsson,ab8500-btemp"), - OF_MFD_CELL("ab8500-fg", NULL, &ab8500_bm_data, + MFD_CELL_OF("ab8500-fg", NULL, &ab8500_bm_data, sizeof(ab8500_bm_data), 0, "stericsson,ab8500-fg"), - OF_MFD_CELL("ab8500-chargalg", NULL, &ab8500_bm_data, + MFD_CELL_OF("ab8500-chargalg", NULL, &ab8500_bm_data, sizeof(ab8500_bm_data), 0, "stericsson,ab8500-chargalg"), }; static const struct mfd_cell ab8500_devs[] = { #ifdef CONFIG_DEBUG_FS - OF_MFD_CELL("ab8500-debug", + MFD_CELL_OF("ab8500-debug", NULL, NULL, 0, 0, "stericsson,ab8500-debug"), #endif - OF_MFD_CELL("ab8500-sysctrl", + MFD_CELL_OF("ab8500-sysctrl", NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"), - OF_MFD_CELL("ab8500-ext-regulator", + MFD_CELL_OF("ab8500-ext-regulator", NULL, NULL, 0, 0, "stericsson,ab8500-ext-regulator"), - OF_MFD_CELL("ab8500-regulator", + MFD_CELL_OF("ab8500-regulator", NULL, NULL, 0, 0, "stericsson,ab8500-regulator"), - OF_MFD_CELL("ab8500-clk", + MFD_CELL_OF("ab8500-clk", NULL, NULL, 0, 0, "stericsson,ab8500-clk"), - OF_MFD_CELL("ab8500-gpadc", + MFD_CELL_OF("ab8500-gpadc", NULL, NULL, 0, 0, "stericsson,ab8500-gpadc"), - OF_MFD_CELL("ab8500-rtc", + MFD_CELL_OF("ab8500-rtc", NULL, NULL, 0, 0, "stericsson,ab8500-rtc"), - OF_MFD_CELL("ab8500-acc-det", + MFD_CELL_OF("ab8500-acc-det", NULL, NULL, 0, 0, "stericsson,ab8500-acc-det"), - OF_MFD_CELL("ab8500-poweron-key", + MFD_CELL_OF("ab8500-poweron-key", NULL, NULL, 0, 0, "stericsson,ab8500-poweron-key"), - OF_MFD_CELL("ab8500-pwm", + MFD_CELL_OF("ab8500-pwm", NULL, NULL, 0, 1, "stericsson,ab8500-pwm"), - OF_MFD_CELL("ab8500-pwm", + MFD_CELL_OF("ab8500-pwm", NULL, NULL, 0, 2, "stericsson,ab8500-pwm"), - OF_MFD_CELL("ab8500-pwm", + MFD_CELL_OF("ab8500-pwm", NULL, NULL, 0, 3, "stericsson,ab8500-pwm"), - OF_MFD_CELL("ab8500-denc", + MFD_CELL_OF("ab8500-denc", NULL, NULL, 0, 0, "stericsson,ab8500-denc"), - OF_MFD_CELL("pinctrl-ab8500", + MFD_CELL_OF("pinctrl-ab8500", NULL, NULL, 0, 0, "stericsson,ab8500-gpio"), - OF_MFD_CELL("abx500-temp", + MFD_CELL_OF("abx500-temp", NULL, NULL, 0, 0, "stericsson,abx500-temp"), - OF_MFD_CELL("ab8500-usb", + MFD_CELL_OF("ab8500-usb", NULL, NULL, 0, 0, "stericsson,ab8500-usb"), - OF_MFD_CELL("ab8500-codec", + MFD_CELL_OF("ab8500-codec", NULL, NULL, 0, 0, "stericsson,ab8500-codec"), }; diff --git a/drivers/mfd/acer-ec-a500.c b/drivers/mfd/acer-ec-a500.c new file mode 100644 index 000000000000..80c2fdd14fc4 --- /dev/null +++ b/drivers/mfd/acer-ec-a500.c @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Acer Iconia Tab A500 Embedded Controller Driver + * + * Copyright 2020 GRATE-driver project + */ + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/reboot.h> +#include <linux/regmap.h> + +#define A500_EC_I2C_ERR_TIMEOUT 500 +#define A500_EC_POWER_CMD_TIMEOUT 1000 + +/* + * Controller's firmware expects specific command opcodes to be used for the + * corresponding registers. Unsupported commands are skipped by the firmware. + */ +#define CMD_SHUTDOWN 0x0 +#define CMD_WARM_REBOOT 0x0 +#define CMD_COLD_REBOOT 0x1 + +enum { + REG_CURRENT_NOW = 0x03, + REG_SHUTDOWN = 0x52, + REG_WARM_REBOOT = 0x54, + REG_COLD_REBOOT = 0x55, +}; + +static struct i2c_client *a500_ec_client_pm_off; + +static int a500_ec_read(void *context, const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_sizel) +{ + struct i2c_client *client = context; + unsigned int reg, retries = 5; + u16 *ret_val = val_buf; + s32 ret = 0; + + reg = *(u8 *)reg_buf; + + while (retries-- > 0) { + ret = i2c_smbus_read_word_data(client, reg); + if (ret >= 0) + break; + + msleep(A500_EC_I2C_ERR_TIMEOUT); + } + + if (ret < 0) { + dev_err(&client->dev, "read 0x%x failed: %d\n", reg, ret); + return ret; + } + + *ret_val = ret; + + if (reg == REG_CURRENT_NOW) + fsleep(10000); + + return 0; +} + +static int a500_ec_write(void *context, const void *data, size_t count) +{ + struct i2c_client *client = context; + unsigned int reg, val, retries = 5; + s32 ret = 0; + + reg = *(u8 *)(data + 0); + val = *(u16 *)(data + 1); + + while (retries-- > 0) { + ret = i2c_smbus_write_word_data(client, reg, val); + if (ret >= 0) + break; + + msleep(A500_EC_I2C_ERR_TIMEOUT); + } + + if (ret < 0) { + dev_err(&client->dev, "write 0x%x failed: %d\n", reg, ret); + return ret; + } + + return 0; +} + +static const struct regmap_config a500_ec_regmap_config = { + .name = "KB930", + .reg_bits = 8, + .val_bits = 16, + .max_register = 0xff, +}; + +static const struct regmap_bus a500_ec_regmap_bus = { + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_LITTLE, + .write = a500_ec_write, + .read = a500_ec_read, + .max_raw_read = 2, +}; + +static void a500_ec_poweroff(void) +{ + i2c_smbus_write_word_data(a500_ec_client_pm_off, + REG_SHUTDOWN, CMD_SHUTDOWN); + + mdelay(A500_EC_POWER_CMD_TIMEOUT); +} + +static int a500_ec_restart_notify(struct notifier_block *this, + unsigned long reboot_mode, void *data) +{ + if (reboot_mode == REBOOT_WARM) + i2c_smbus_write_word_data(a500_ec_client_pm_off, + REG_WARM_REBOOT, CMD_WARM_REBOOT); + else + i2c_smbus_write_word_data(a500_ec_client_pm_off, + REG_COLD_REBOOT, CMD_COLD_REBOOT); + + mdelay(A500_EC_POWER_CMD_TIMEOUT); + + return NOTIFY_DONE; +} + +static struct notifier_block a500_ec_restart_handler = { + .notifier_call = a500_ec_restart_notify, + .priority = 200, +}; + +static const struct mfd_cell a500_ec_cells[] = { + { .name = "acer-a500-iconia-battery", }, + { .name = "acer-a500-iconia-leds", }, +}; + +static int a500_ec_probe(struct i2c_client *client) +{ + struct regmap *regmap; + int err; + + regmap = devm_regmap_init(&client->dev, &a500_ec_regmap_bus, + client, &a500_ec_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + err = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + a500_ec_cells, ARRAY_SIZE(a500_ec_cells), + NULL, 0, NULL); + if (err) { + dev_err(&client->dev, "failed to add sub-devices: %d\n", err); + return err; + } + + if (of_device_is_system_power_controller(client->dev.of_node)) { + a500_ec_client_pm_off = client; + + err = register_restart_handler(&a500_ec_restart_handler); + if (err) + return err; + + if (!pm_power_off) + pm_power_off = a500_ec_poweroff; + } + + return 0; +} + +static int a500_ec_remove(struct i2c_client *client) +{ + if (of_device_is_system_power_controller(client->dev.of_node)) { + if (pm_power_off == a500_ec_poweroff) + pm_power_off = NULL; + + unregister_restart_handler(&a500_ec_restart_handler); + } + + return 0; +} + +static const struct of_device_id a500_ec_match[] = { + { .compatible = "acer,a500-iconia-ec" }, + { } +}; +MODULE_DEVICE_TABLE(of, a500_ec_match); + +static struct i2c_driver a500_ec_driver = { + .driver = { + .name = "acer-a500-embedded-controller", + .of_match_table = a500_ec_match, + }, + .probe_new = a500_ec_probe, + .remove = a500_ec_remove, +}; +module_i2c_driver(a500_ec_driver); + +MODULE_DESCRIPTION("Acer Iconia Tab A500 Embedded Controller driver"); +MODULE_AUTHOR("Dmitry Osipenko <digetx@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c index 193a96c8b1ea..20cb294c7512 100644 --- a/drivers/mfd/altera-sysmgr.c +++ b/drivers/mfd/altera-sysmgr.c @@ -145,7 +145,8 @@ static int sysmgr_probe(struct platform_device *pdev) sysmgr_config.reg_write = s10_protected_reg_write; /* Need physical address for SMCC call */ - regmap = devm_regmap_init(dev, NULL, (void *)res->start, + regmap = devm_regmap_init(dev, NULL, + (void *)(uintptr_t)res->start, &sysmgr_config); } else { base = devm_ioremap(dev, res->start, resource_size(res)); diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c index fab3cdc27ed6..e15b1acfb063 100644 --- a/drivers/mfd/bd9571mwv.c +++ b/drivers/mfd/bd9571mwv.c @@ -1,16 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * ROHM BD9571MWV-M MFD driver + * ROHM BD9571MWV-M and BD9574MVF-M core driver * * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. + * Copyright (C) 2020 Renesas Electronics Corporation * * Based on the TPS65086 driver */ @@ -18,6 +11,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/mfd/core.h> +#include <linux/mfd/rohm-generic.h> #include <linux/module.h> #include <linux/mfd/bd9571mwv.h> @@ -110,13 +104,78 @@ static struct regmap_irq_chip bd9571mwv_irq_chip = { .num_irqs = ARRAY_SIZE(bd9571mwv_irqs), }; -static int bd9571mwv_identify(struct bd9571mwv *bd) +static const struct mfd_cell bd9574mwf_cells[] = { + { .name = "bd9574mwf-regulator", }, + { .name = "bd9574mwf-gpio", }, +}; + +static const struct regmap_range bd9574mwf_readable_yes_ranges[] = { + regmap_reg_range(BD9571MWV_VENDOR_CODE, BD9571MWV_PRODUCT_REVISION), + regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT), + regmap_reg_range(BD9571MWV_DVFS_VINIT, BD9571MWV_DVFS_SETVMAX), + regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_MONIVDAC), + regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), + regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INTMASK), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), +}; + +static const struct regmap_access_table bd9574mwf_readable_table = { + .yes_ranges = bd9574mwf_readable_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9574mwf_readable_yes_ranges), +}; + +static const struct regmap_range bd9574mwf_writable_yes_ranges[] = { + regmap_reg_range(BD9571MWV_BKUP_MODE_CNT, BD9571MWV_BKUP_MODE_CNT), + regmap_reg_range(BD9571MWV_DVFS_SETVID, BD9571MWV_DVFS_SETVID), + regmap_reg_range(BD9571MWV_GPIO_DIR, BD9571MWV_GPIO_OUT), + regmap_reg_range(BD9571MWV_GPIO_INT_SET, BD9571MWV_GPIO_INTMASK), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTMASK), +}; + +static const struct regmap_access_table bd9574mwf_writable_table = { + .yes_ranges = bd9574mwf_writable_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9574mwf_writable_yes_ranges), +}; + +static const struct regmap_range bd9574mwf_volatile_yes_ranges[] = { + regmap_reg_range(BD9571MWV_DVFS_MONIVDAC, BD9571MWV_DVFS_MONIVDAC), + regmap_reg_range(BD9571MWV_GPIO_IN, BD9571MWV_GPIO_IN), + regmap_reg_range(BD9571MWV_GPIO_INT, BD9571MWV_GPIO_INT), + regmap_reg_range(BD9571MWV_INT_INTREQ, BD9571MWV_INT_INTREQ), +}; + +static const struct regmap_access_table bd9574mwf_volatile_table = { + .yes_ranges = bd9574mwf_volatile_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(bd9574mwf_volatile_yes_ranges), +}; + +static const struct regmap_config bd9574mwf_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .rd_table = &bd9574mwf_readable_table, + .wr_table = &bd9574mwf_writable_table, + .volatile_table = &bd9574mwf_volatile_table, + .max_register = 0xff, +}; + +static struct regmap_irq_chip bd9574mwf_irq_chip = { + .name = "bd9574mwf", + .status_base = BD9571MWV_INT_INTREQ, + .mask_base = BD9571MWV_INT_INTMASK, + .ack_base = BD9571MWV_INT_INTREQ, + .init_ack_masked = true, + .num_regs = 1, + .irqs = bd9571mwv_irqs, + .num_irqs = ARRAY_SIZE(bd9571mwv_irqs), +}; + +static int bd957x_identify(struct device *dev, struct regmap *regmap) { - struct device *dev = bd->dev; unsigned int value; int ret; - ret = regmap_read(bd->regmap, BD9571MWV_VENDOR_CODE, &value); + ret = regmap_read(regmap, BD9571MWV_VENDOR_CODE, &value); if (ret) { dev_err(dev, "Failed to read vendor code register (ret=%i)\n", ret); @@ -129,84 +188,82 @@ static int bd9571mwv_identify(struct bd9571mwv *bd) return -EINVAL; } - ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_CODE, &value); + ret = regmap_read(regmap, BD9571MWV_PRODUCT_CODE, &value); if (ret) { dev_err(dev, "Failed to read product code register (ret=%i)\n", ret); return ret; } - - if (value != BD9571MWV_PRODUCT_CODE_VAL) { - dev_err(dev, "Invalid product code ID %02x (expected %02x)\n", - value, BD9571MWV_PRODUCT_CODE_VAL); - return -EINVAL; - } - - ret = regmap_read(bd->regmap, BD9571MWV_PRODUCT_REVISION, &value); + ret = regmap_read(regmap, BD9571MWV_PRODUCT_REVISION, &value); if (ret) { dev_err(dev, "Failed to read revision register (ret=%i)\n", ret); return ret; } - dev_info(dev, "Device: BD9571MWV rev. %d\n", value & 0xff); - return 0; } static int bd9571mwv_probe(struct i2c_client *client, - const struct i2c_device_id *ids) + const struct i2c_device_id *ids) { - struct bd9571mwv *bd; - int ret; - - bd = devm_kzalloc(&client->dev, sizeof(*bd), GFP_KERNEL); - if (!bd) - return -ENOMEM; + const struct regmap_config *regmap_config; + const struct regmap_irq_chip *irq_chip; + const struct mfd_cell *cells; + struct device *dev = &client->dev; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; + int ret, num_cells, irq = client->irq; + + /* Read the PMIC product code */ + ret = i2c_smbus_read_byte_data(client, BD9571MWV_PRODUCT_CODE); + if (ret < 0) { + dev_err(dev, "Failed to read product code\n"); + return ret; + } - i2c_set_clientdata(client, bd); - bd->dev = &client->dev; - bd->irq = client->irq; + switch (ret) { + case BD9571MWV_PRODUCT_CODE_BD9571MWV: + regmap_config = &bd9571mwv_regmap_config; + irq_chip = &bd9571mwv_irq_chip; + cells = bd9571mwv_cells; + num_cells = ARRAY_SIZE(bd9571mwv_cells); + break; + case BD9571MWV_PRODUCT_CODE_BD9574MWF: + regmap_config = &bd9574mwf_regmap_config; + irq_chip = &bd9574mwf_irq_chip; + cells = bd9574mwf_cells; + num_cells = ARRAY_SIZE(bd9574mwf_cells); + break; + default: + dev_err(dev, "Unsupported device 0x%x\n", ret); + return -ENODEV; + } - bd->regmap = devm_regmap_init_i2c(client, &bd9571mwv_regmap_config); - if (IS_ERR(bd->regmap)) { - dev_err(bd->dev, "Failed to initialize register map\n"); - return PTR_ERR(bd->regmap); + regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "Failed to initialize register map\n"); + return PTR_ERR(regmap); } - ret = bd9571mwv_identify(bd); + ret = bd957x_identify(dev, regmap); if (ret) return ret; - ret = regmap_add_irq_chip(bd->regmap, bd->irq, IRQF_ONESHOT, 0, - &bd9571mwv_irq_chip, &bd->irq_data); - if (ret) { - dev_err(bd->dev, "Failed to register IRQ chip\n"); - return ret; - } - - ret = mfd_add_devices(bd->dev, PLATFORM_DEVID_AUTO, bd9571mwv_cells, - ARRAY_SIZE(bd9571mwv_cells), NULL, 0, - regmap_irq_get_domain(bd->irq_data)); + ret = devm_regmap_add_irq_chip(dev, regmap, irq, IRQF_ONESHOT, 0, + irq_chip, &irq_data); if (ret) { - regmap_del_irq_chip(bd->irq, bd->irq_data); + dev_err(dev, "Failed to register IRQ chip\n"); return ret; } - return 0; -} - -static int bd9571mwv_remove(struct i2c_client *client) -{ - struct bd9571mwv *bd = i2c_get_clientdata(client); - - regmap_del_irq_chip(bd->irq, bd->irq_data); - - return 0; + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, num_cells, + NULL, 0, regmap_irq_get_domain(irq_data)); } static const struct of_device_id bd9571mwv_of_match_table[] = { { .compatible = "rohm,bd9571mwv", }, + { .compatible = "rohm,bd9574mwf", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table); @@ -223,7 +280,6 @@ static struct i2c_driver bd9571mwv_driver = { .of_match_table = bd9571mwv_of_match_table, }, .probe = bd9571mwv_probe, - .remove = bd9571mwv_remove, .id_table = bd9571mwv_id_table, }; module_i2c_driver(bd9571mwv_driver); diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index a5983d515db0..167faac9b75b 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -2954,12 +2954,12 @@ static const struct mfd_cell common_prcmu_devs[] = { }; static const struct mfd_cell db8500_prcmu_devs[] = { - OF_MFD_CELL("db8500-prcmu-regulators", NULL, + MFD_CELL_OF("db8500-prcmu-regulators", NULL, &db8500_regulators, sizeof(db8500_regulators), 0, "stericsson,db8500-prcmu-regulator"), - OF_MFD_CELL("cpuidle-dbx500", + MFD_CELL_OF("cpuidle-dbx500", NULL, NULL, 0, 0, "stericsson,cpuidle-dbx500"), - OF_MFD_CELL("db8500-thermal", + MFD_CELL_OF("db8500-thermal", NULL, NULL, 0, 0, "stericsson,db8500-thermal"), }; diff --git a/drivers/mfd/gateworks-gsc.c b/drivers/mfd/gateworks-gsc.c index 576da62fbb0c..d87876747b91 100644 --- a/drivers/mfd/gateworks-gsc.c +++ b/drivers/mfd/gateworks-gsc.c @@ -234,7 +234,7 @@ static int gsc_probe(struct i2c_client *client) ret = devm_regmap_add_irq_chip(dev, gsc->regmap, client->irq, IRQF_ONESHOT | IRQF_SHARED | - IRQF_TRIGGER_FALLING, 0, + IRQF_TRIGGER_LOW, 0, &gsc_irq_chip, &irq_data); if (ret) return ret; diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 2d7c588ef1ed..1522c8afc540 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -277,6 +277,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x4dea), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x4deb), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&spt_info }, + /* ADL-P */ + { PCI_VDEVICE(INTEL, 0x51a8), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x51a9), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x51c5), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x51c6), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x51c7), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x51e8), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x51e9), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x51ea), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x51eb), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&bxt_info }, /* APL */ { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info }, { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info }, @@ -293,6 +306,21 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x5aee), (kernel_ulong_t)&bxt_uart_info }, + /* ADL-S */ + { PCI_VDEVICE(INTEL, 0x7aa8), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7aa9), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x7acc), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7acd), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7ace), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7acf), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7adc), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x7afc), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7afd), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7afe), (kernel_ulong_t)&bxt_uart_info }, /* LKF */ { PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info }, diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index b84579b7b4f0..06c977519479 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -60,9 +60,52 @@ static ssize_t bmcfw_version_show(struct device *dev, } static DEVICE_ATTR_RO(bmcfw_version); +static ssize_t mac_address_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_m10bmc *max10 = dev_get_drvdata(dev); + unsigned int macaddr_low, macaddr_high; + int ret; + + ret = m10bmc_sys_read(max10, M10BMC_MAC_LOW, &macaddr_low); + if (ret) + return ret; + + ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high); + if (ret) + return ret; + + return sysfs_emit(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", + (u8)FIELD_GET(M10BMC_MAC_BYTE1, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE2, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE3, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE4, macaddr_low), + (u8)FIELD_GET(M10BMC_MAC_BYTE5, macaddr_high), + (u8)FIELD_GET(M10BMC_MAC_BYTE6, macaddr_high)); +} +static DEVICE_ATTR_RO(mac_address); + +static ssize_t mac_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_m10bmc *max10 = dev_get_drvdata(dev); + unsigned int macaddr_high; + int ret; + + ret = m10bmc_sys_read(max10, M10BMC_MAC_HIGH, &macaddr_high); + if (ret) + return ret; + + return sysfs_emit(buf, "%u\n", + (u8)FIELD_GET(M10BMC_MAC_COUNT, macaddr_high)); +} +static DEVICE_ATTR_RO(mac_count); + static struct attribute *m10bmc_attrs[] = { &dev_attr_bmc_version.attr, &dev_attr_bmcfw_version.attr, + &dev_attr_mac_address.attr, + &dev_attr_mac_count.attr, NULL, }; ATTRIBUTE_GROUPS(m10bmc); diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c index 761b4ef3a381..d1fc38a78acb 100644 --- a/drivers/mfd/iqs62x.c +++ b/drivers/mfd/iqs62x.c @@ -36,7 +36,6 @@ #define IQS62X_PROD_NUM 0x00 #define IQS62X_SYS_FLAGS 0x10 -#define IQS62X_SYS_FLAGS_IN_ATI BIT(2) #define IQS620_HALL_FLAGS 0x16 #define IQS621_HALL_FLAGS 0x19 @@ -57,10 +56,10 @@ #define IQS620_TEMP_CAL_OFFS 0xC4 #define IQS62X_SYS_SETTINGS 0xD0 -#define IQS62X_SYS_SETTINGS_SOFT_RESET BIT(7) #define IQS62X_SYS_SETTINGS_ACK_RESET BIT(6) #define IQS62X_SYS_SETTINGS_EVENT_MODE BIT(5) #define IQS62X_SYS_SETTINGS_CLK_DIV BIT(4) +#define IQS62X_SYS_SETTINGS_COMM_ATI BIT(3) #define IQS62X_SYS_SETTINGS_REDO_ATI BIT(1) #define IQS62X_PWR_SETTINGS 0xD2 @@ -82,9 +81,8 @@ #define IQS62X_FW_REC_TYPE_MASK 3 #define IQS62X_FW_REC_TYPE_DATA 4 -#define IQS62X_ATI_POLL_SLEEP_US 10000 -#define IQS62X_ATI_POLL_TIMEOUT_US 500000 -#define IQS62X_ATI_STABLE_DELAY_MS 150 +#define IQS62X_ATI_STARTUP_MS 350 +#define IQS62X_FILT_SETTLE_MS 250 struct iqs62x_fw_rec { u8 type; @@ -112,9 +110,16 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x) struct iqs62x_fw_blk *fw_blk; unsigned int val; int ret; - u8 clk_div = 1; list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) { + /* + * In case ATI is in progress, wait for it to complete before + * lowering the core clock frequency. + */ + if (fw_blk->addr == IQS62X_SYS_SETTINGS && + *fw_blk->data & IQS62X_SYS_SETTINGS_CLK_DIV) + msleep(IQS62X_ATI_STARTUP_MS); + if (fw_blk->mask) ret = regmap_update_bits(iqs62x->regmap, fw_blk->addr, fw_blk->mask, *fw_blk->data); @@ -135,7 +140,6 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x) if (val & IQS620_PROX_SETTINGS_4_SAR_EN) iqs62x->ui_sel = IQS62X_UI_SAR1; - fallthrough; case IQS621_PROD_NUM: @@ -183,28 +187,32 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x) return ret; } - ret = regmap_read(iqs62x->regmap, IQS62X_SYS_SETTINGS, &val); - if (ret) - return ret; - - if (val & IQS62X_SYS_SETTINGS_CLK_DIV) - clk_div = iqs62x->dev_desc->clk_div; - - ret = regmap_write(iqs62x->regmap, IQS62X_SYS_SETTINGS, val | - IQS62X_SYS_SETTINGS_ACK_RESET | - IQS62X_SYS_SETTINGS_EVENT_MODE | - IQS62X_SYS_SETTINGS_REDO_ATI); - if (ret) - return ret; - - ret = regmap_read_poll_timeout(iqs62x->regmap, IQS62X_SYS_FLAGS, val, - !(val & IQS62X_SYS_FLAGS_IN_ATI), - IQS62X_ATI_POLL_SLEEP_US, - IQS62X_ATI_POLL_TIMEOUT_US * clk_div); + /* + * Place the device in streaming mode at first so as not to miss the + * limited number of interrupts that would otherwise occur after ATI + * completes. The device is subsequently placed in event mode by the + * interrupt handler. + * + * In the meantime, mask interrupts during ATI to prevent the device + * from soliciting I2C traffic until the noise-sensitive ATI process + * is complete. + */ + ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS, + IQS62X_SYS_SETTINGS_ACK_RESET | + IQS62X_SYS_SETTINGS_EVENT_MODE | + IQS62X_SYS_SETTINGS_COMM_ATI | + IQS62X_SYS_SETTINGS_REDO_ATI, + IQS62X_SYS_SETTINGS_ACK_RESET | + IQS62X_SYS_SETTINGS_REDO_ATI); if (ret) return ret; - msleep(IQS62X_ATI_STABLE_DELAY_MS * clk_div); + /* + * The following delay gives the device time to deassert its RDY output + * in case a communication window was open while the REDO_ATI field was + * written. This prevents an interrupt from being serviced prematurely. + */ + usleep_range(5000, 5100); return 0; } @@ -435,6 +443,11 @@ const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = { .mask = BIT(7), .val = BIT(7), }, + [IQS62X_EVENT_SYS_ATI] = { + .reg = IQS62X_EVENT_SYS, + .mask = BIT(2), + .val = BIT(2), + }, }; EXPORT_SYMBOL_GPL(iqs62x_events); @@ -469,7 +482,6 @@ static irqreturn_t iqs62x_irq(int irq, void *context) switch (event_reg) { case IQS62X_EVENT_UI_LO: event_data.ui_data = get_unaligned_le16(&event_map[i]); - fallthrough; case IQS62X_EVENT_UI_HI: @@ -490,7 +502,6 @@ static irqreturn_t iqs62x_irq(int irq, void *context) case IQS62X_EVENT_HYST: event_map[i] <<= iqs62x->dev_desc->hyst_shift; - fallthrough; case IQS62X_EVENT_WHEEL: @@ -525,19 +536,46 @@ static irqreturn_t iqs62x_irq(int irq, void *context) "Failed to re-initialize device: %d\n", ret); return IRQ_NONE; } + + iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_RESET); + reinit_completion(&iqs62x->ati_done); + } else if (event_flags & BIT(IQS62X_EVENT_SYS_ATI)) { + iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_ATI); + reinit_completion(&iqs62x->ati_done); + } else if (!completion_done(&iqs62x->ati_done)) { + ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS, + IQS62X_SYS_SETTINGS_EVENT_MODE, 0xFF); + if (ret) { + dev_err(&client->dev, + "Failed to enable event mode: %d\n", ret); + return IRQ_NONE; + } + + msleep(IQS62X_FILT_SETTLE_MS); + complete_all(&iqs62x->ati_done); } - ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags, - &event_data); - if (ret & NOTIFY_STOP_MASK) - return IRQ_NONE; + /* + * Reset and ATI events are not broadcast to the sub-device drivers + * until ATI has completed. Any other events that may have occurred + * during ATI are ignored. + */ + if (completion_done(&iqs62x->ati_done)) { + event_flags |= iqs62x->event_cache; + ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags, + &event_data); + if (ret & NOTIFY_STOP_MASK) + return IRQ_NONE; + + iqs62x->event_cache = 0; + } /* * Once the communication window is closed, a small delay is added to * ensure the device's RDY output has been deasserted by the time the * interrupt handler returns. */ - usleep_range(50, 100); + usleep_range(150, 200); return IRQ_HANDLED; } @@ -571,6 +609,12 @@ static void iqs62x_firmware_load(const struct firmware *fw, void *context) goto err_out; } + if (!wait_for_completion_timeout(&iqs62x->ati_done, + msecs_to_jiffies(2000))) { + dev_err(&client->dev, "Failed to complete ATI\n"); + goto err_out; + } + ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, iqs62x->dev_desc->sub_devs, iqs62x->dev_desc->num_sub_devs, @@ -752,22 +796,17 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = { .dev_name = "iqs620at", .sub_devs = iqs620at_sub_devs, .num_sub_devs = ARRAY_SIZE(iqs620at_sub_devs), - .prod_num = IQS620_PROD_NUM, .sw_num = 0x08, .cal_regs = iqs620at_cal_regs, .num_cal_regs = ARRAY_SIZE(iqs620at_cal_regs), - .prox_mask = BIT(0), .sar_mask = BIT(1) | BIT(7), .hall_mask = BIT(2), .hyst_mask = BIT(3), .temp_mask = BIT(4), - .prox_settings = IQS620_PROX_SETTINGS_4, .hall_flags = IQS620_HALL_FLAGS, - - .clk_div = 4, .fw_name = "iqs620a.bin", .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX], }, @@ -775,20 +814,15 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = { .dev_name = "iqs620a", .sub_devs = iqs620a_sub_devs, .num_sub_devs = ARRAY_SIZE(iqs620a_sub_devs), - .prod_num = IQS620_PROD_NUM, .sw_num = 0x08, - .prox_mask = BIT(0), .sar_mask = BIT(1) | BIT(7), .hall_mask = BIT(2), .hyst_mask = BIT(3), .temp_mask = BIT(4), - .prox_settings = IQS620_PROX_SETTINGS_4, .hall_flags = IQS620_HALL_FLAGS, - - .clk_div = 4, .fw_name = "iqs620a.bin", .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX], }, @@ -796,23 +830,18 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = { .dev_name = "iqs621", .sub_devs = iqs621_sub_devs, .num_sub_devs = ARRAY_SIZE(iqs621_sub_devs), - .prod_num = IQS621_PROD_NUM, .sw_num = 0x09, .cal_regs = iqs621_cal_regs, .num_cal_regs = ARRAY_SIZE(iqs621_cal_regs), - .prox_mask = BIT(0), .hall_mask = BIT(1), .als_mask = BIT(2), .hyst_mask = BIT(3), .temp_mask = BIT(4), - .als_flags = IQS621_ALS_FLAGS, .hall_flags = IQS621_HALL_FLAGS, .hyst_shift = 5, - - .clk_div = 2, .fw_name = "iqs621.bin", .event_regs = &iqs621_event_regs[IQS62X_UI_PROX], }, @@ -820,21 +849,16 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = { .dev_name = "iqs622", .sub_devs = iqs622_sub_devs, .num_sub_devs = ARRAY_SIZE(iqs622_sub_devs), - .prod_num = IQS622_PROD_NUM, .sw_num = 0x06, - .prox_mask = BIT(0), .sar_mask = BIT(1), .hall_mask = BIT(2), .als_mask = BIT(3), .ir_mask = BIT(4), - .prox_settings = IQS622_PROX_SETTINGS_4, .als_flags = IQS622_ALS_FLAGS, .hall_flags = IQS622_HALL_FLAGS, - - .clk_div = 2, .fw_name = "iqs622.bin", .event_regs = &iqs622_event_regs[IQS62X_UI_PROX], }, @@ -842,14 +866,10 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = { .dev_name = "iqs624", .sub_devs = iqs624_sub_devs, .num_sub_devs = ARRAY_SIZE(iqs624_sub_devs), - .prod_num = IQS624_PROD_NUM, .sw_num = 0x0B, - .interval = IQS624_INTERVAL_NUM, .interval_div = 3, - - .clk_div = 2, .fw_name = "iqs624.bin", .event_regs = &iqs624_event_regs[IQS62X_UI_PROX], }, @@ -857,20 +877,16 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = { .dev_name = "iqs625", .sub_devs = iqs625_sub_devs, .num_sub_devs = ARRAY_SIZE(iqs625_sub_devs), - .prod_num = IQS625_PROD_NUM, .sw_num = 0x0B, - .interval = IQS625_INTERVAL_NUM, .interval_div = 10, - - .clk_div = 2, .fw_name = "iqs625.bin", .event_regs = &iqs625_event_regs[IQS62X_UI_PROX], }, }; -static const struct regmap_config iqs62x_map_config = { +static const struct regmap_config iqs62x_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = IQS62X_MAX_REG, @@ -894,9 +910,11 @@ static int iqs62x_probe(struct i2c_client *client) BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh); INIT_LIST_HEAD(&iqs62x->fw_blk_head); + + init_completion(&iqs62x->ati_done); init_completion(&iqs62x->fw_done); - iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_map_config); + iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config); if (IS_ERR(iqs62x->regmap)) { ret = PTR_ERR(iqs62x->regmap); dev_err(&client->dev, "Failed to initialize register map: %d\n", diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 68d8f2b95287..55d3a6f97783 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", }, + { .name = "max8997-battery", .of_compatible = "maxim,max8997-battery", }, { .name = "max8997-haptic", }, - { .name = "max8997-muic", }, + { .name = "max8997-muic", .of_compatible = "maxim,max8997-muic", }, { .name = "max8997-led", .id = 1 }, { .name = "max8997-led", .id = 2 }, }; diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 98fa0af0e56e..4629dff187cd 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -214,8 +214,7 @@ static int mcp_sa11x0_probe(struct platform_device *dev) * rate. This is the period for 3 64-bit frames. Always * round this time up. */ - mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) / - mcp->sclk_rate; + mcp->rw_timeout = DIV_ROUND_UP(64 * 3 * 1000000, mcp->sclk_rate); ret = mcp_host_add(mcp, data->codec_pdata); if (ret == 0) diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c index 4661c1b29a72..480722acf706 100644 --- a/drivers/mfd/mt6360-core.c +++ b/drivers/mfd/mt6360-core.c @@ -292,17 +292,17 @@ static const struct resource mt6360_ldo_resources[] = { }; static const struct mfd_cell mt6360_devs[] = { - OF_MFD_CELL("mt6360_adc", mt6360_adc_resources, + MFD_CELL_OF("mt6360_adc", mt6360_adc_resources, NULL, 0, 0, "mediatek,mt6360_adc"), - OF_MFD_CELL("mt6360_chg", mt6360_chg_resources, + MFD_CELL_OF("mt6360_chg", mt6360_chg_resources, NULL, 0, 0, "mediatek,mt6360_chg"), - OF_MFD_CELL("mt6360_led", mt6360_led_resources, + MFD_CELL_OF("mt6360_led", mt6360_led_resources, NULL, 0, 0, "mediatek,mt6360_led"), - OF_MFD_CELL("mt6360_pmic", mt6360_pmic_resources, + MFD_CELL_OF("mt6360_pmic", mt6360_pmic_resources, NULL, 0, 0, "mediatek,mt6360_pmic"), - OF_MFD_CELL("mt6360_ldo", mt6360_ldo_resources, + MFD_CELL_OF("mt6360_ldo", mt6360_ldo_resources, NULL, 0, 0, "mediatek,mt6360_ldo"), - OF_MFD_CELL("mt6360_tcpc", NULL, + MFD_CELL_OF("mt6360_tcpc", NULL, NULL, 0, 0, "mediatek,mt6360_tcpc"), }; diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c index 8a7cc0f86958..65b98f3fbd92 100644 --- a/drivers/mfd/wm831x-auxadc.c +++ b/drivers/mfd/wm831x-auxadc.c @@ -93,11 +93,10 @@ static int wm831x_auxadc_read_irq(struct wm831x *wm831x, wait_for_completion_timeout(&req->done, msecs_to_jiffies(500)); mutex_lock(&wm831x->auxadc_lock); - - list_del(&req->list); ret = req->val; out: + list_del(&req->list); mutex_unlock(&wm831x->auxadc_lock); kfree(req); diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index e690c2ce5b3c..7b0cd08db446 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * ROHM BD9571MWV-M regulator driver + * ROHM BD9571MWV-M and BD9574MWF-M regulator driver * * Copyright (C) 2017 Marek Vasut <marek.vasut+renesas@gmail.com> * @@ -9,6 +9,7 @@ * NOTE: VD09 is missing */ +#include <linux/mfd/rohm-generic.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> @@ -17,7 +18,7 @@ #include <linux/mfd/bd9571mwv.h> struct bd9571mwv_reg { - struct bd9571mwv *bd; + struct regmap *regmap; /* DDR Backup Power */ u8 bkup_mode_cnt_keepon; /* from "rohm,ddr-backup-power" */ @@ -137,26 +138,30 @@ static const struct regulator_desc regulators[] = { }; #ifdef CONFIG_PM_SLEEP -static int bd9571mwv_bkup_mode_read(struct bd9571mwv *bd, unsigned int *mode) +static int bd9571mwv_bkup_mode_read(struct bd9571mwv_reg *bdreg, + unsigned int *mode) { int ret; - ret = regmap_read(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode); + ret = regmap_read(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode); if (ret) { - dev_err(bd->dev, "failed to read backup mode (%d)\n", ret); + dev_err(regmap_get_device(bdreg->regmap), + "failed to read backup mode (%d)\n", ret); return ret; } return 0; } -static int bd9571mwv_bkup_mode_write(struct bd9571mwv *bd, unsigned int mode) +static int bd9571mwv_bkup_mode_write(struct bd9571mwv_reg *bdreg, + unsigned int mode) { int ret; - ret = regmap_write(bd->regmap, BD9571MWV_BKUP_MODE_CNT, mode); + ret = regmap_write(bdreg->regmap, BD9571MWV_BKUP_MODE_CNT, mode); if (ret) { - dev_err(bd->dev, "failed to configure backup mode 0x%x (%d)\n", + dev_err(regmap_get_device(bdreg->regmap), + "failed to configure backup mode 0x%x (%d)\n", mode, ret); return ret; } @@ -194,7 +199,7 @@ static ssize_t backup_mode_store(struct device *dev, * Configure DDR Backup Mode, to change the role of the accessory power * switch from a power switch to a wake-up switch, or vice versa */ - ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode); + ret = bd9571mwv_bkup_mode_read(bdreg, &mode); if (ret) return ret; @@ -202,7 +207,7 @@ static ssize_t backup_mode_store(struct device *dev, if (bdreg->bkup_mode_enabled) mode |= bdreg->bkup_mode_cnt_keepon; - ret = bd9571mwv_bkup_mode_write(bdreg->bd, mode); + ret = bd9571mwv_bkup_mode_write(bdreg, mode); if (ret) return ret; @@ -221,7 +226,7 @@ static int bd9571mwv_suspend(struct device *dev) return 0; /* Save DDR Backup Mode */ - ret = bd9571mwv_bkup_mode_read(bdreg->bd, &mode); + ret = bd9571mwv_bkup_mode_read(bdreg, &mode); if (ret) return ret; @@ -235,7 +240,7 @@ static int bd9571mwv_suspend(struct device *dev) mode |= bdreg->bkup_mode_cnt_keepon; if (mode != bdreg->bkup_mode_cnt_saved) - return bd9571mwv_bkup_mode_write(bdreg->bd, mode); + return bd9571mwv_bkup_mode_write(bdreg, mode); return 0; } @@ -248,7 +253,7 @@ static int bd9571mwv_resume(struct device *dev) return 0; /* Restore DDR Backup Mode */ - return bd9571mwv_bkup_mode_write(bdreg->bd, bdreg->bkup_mode_cnt_saved); + return bd9571mwv_bkup_mode_write(bdreg, bdreg->bkup_mode_cnt_saved); } static const struct dev_pm_ops bd9571mwv_pm = { @@ -268,51 +273,54 @@ static int bd9571mwv_regulator_remove(struct platform_device *pdev) static int bd9571mwv_regulator_probe(struct platform_device *pdev) { - struct bd9571mwv *bd = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct bd9571mwv_reg *bdreg; struct regulator_dev *rdev; unsigned int val; int i; + enum rohm_chip_type chip = platform_get_device_id(pdev)->driver_data; bdreg = devm_kzalloc(&pdev->dev, sizeof(*bdreg), GFP_KERNEL); if (!bdreg) return -ENOMEM; - bdreg->bd = bd; + bdreg->regmap = dev_get_regmap(pdev->dev.parent, NULL); platform_set_drvdata(pdev, bdreg); config.dev = &pdev->dev; - config.dev->of_node = bd->dev->of_node; - config.driver_data = bd; - config.regmap = bd->regmap; + config.dev->of_node = pdev->dev.parent->of_node; + config.driver_data = bdreg; + config.regmap = bdreg->regmap; for (i = 0; i < ARRAY_SIZE(regulators); i++) { + /* BD9574MWF supports DVFS only */ + if (chip == ROHM_CHIP_TYPE_BD9574 && regulators[i].id != DVFS) + continue; rdev = devm_regulator_register(&pdev->dev, ®ulators[i], &config); if (IS_ERR(rdev)) { - dev_err(bd->dev, "failed to register %s regulator\n", + dev_err(&pdev->dev, "failed to register %s regulator\n", pdev->name); return PTR_ERR(rdev); } } val = 0; - of_property_read_u32(bd->dev->of_node, "rohm,ddr-backup-power", &val); + of_property_read_u32(config.dev->of_node, "rohm,ddr-backup-power", &val); if (val & ~BD9571MWV_BKUP_MODE_CNT_KEEPON_MASK) { - dev_err(bd->dev, "invalid %s mode %u\n", + dev_err(&pdev->dev, "invalid %s mode %u\n", "rohm,ddr-backup-power", val); return -EINVAL; } bdreg->bkup_mode_cnt_keepon = val; - bdreg->rstbmode_level = of_property_read_bool(bd->dev->of_node, + bdreg->rstbmode_level = of_property_read_bool(config.dev->of_node, "rohm,rstbmode-level"); - bdreg->rstbmode_pulse = of_property_read_bool(bd->dev->of_node, + bdreg->rstbmode_pulse = of_property_read_bool(config.dev->of_node, "rohm,rstbmode-pulse"); if (bdreg->rstbmode_level && bdreg->rstbmode_pulse) { - dev_err(bd->dev, "only one rohm,rstbmode-* may be specified"); + dev_err(&pdev->dev, "only one rohm,rstbmode-* may be specified"); return -EINVAL; } @@ -336,7 +344,8 @@ static int bd9571mwv_regulator_probe(struct platform_device *pdev) } static const struct platform_device_id bd9571mwv_regulator_id_table[] = { - { "bd9571mwv-regulator", }, + { "bd9571mwv-regulator", ROHM_CHIP_TYPE_BD9571 }, + { "bd9574mwf-regulator", ROHM_CHIP_TYPE_BD9574 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, bd9571mwv_regulator_id_table); |