diff options
Diffstat (limited to 'drivers/mfd')
188 files changed, 7813 insertions, 3799 deletions
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index 300caa067335..e9941da58b18 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -116,7 +116,7 @@ enum { #define PM800_CHIP_GEN_ID_NUM 0x3 static const struct i2c_device_id pm80x_id_table[] = { - {"88PM800", 0}, + { "88PM800" }, {} /* NULL terminated */ }; MODULE_DEVICE_TABLE(i2c, pm80x_id_table); @@ -391,7 +391,7 @@ static void device_irq_exit_800(struct pm80x_chip *chip) regmap_del_irq_chip(chip->irq, chip->irq_data); } -static struct regmap_irq_chip pm800_irq_chip = { +static const struct regmap_irq_chip pm800_irq_chip = { .name = "88pm800", .irqs = pm800_irqs, .num_irqs = ARRAY_SIZE(pm800_irqs), diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index 68417c3c4f5a..f5d6663172ee 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -30,7 +30,7 @@ #include <linux/delay.h> static const struct i2c_device_id pm80x_id_table[] = { - {"88PM805", 0}, + { "88PM805" }, {} /* NULL terminated */ }; MODULE_DEVICE_TABLE(i2c, pm80x_id_table); @@ -73,7 +73,7 @@ static const struct mfd_cell codec_devs[] = { }, }; -static struct regmap_irq pm805_irqs[] = { +static const struct regmap_irq pm805_irqs[] = { /* INT0 */ [PM805_IRQ_LDO_OFF] = { .mask = PM805_INT1_HP1_SHRT, @@ -163,7 +163,7 @@ static void device_irq_exit_805(struct pm80x_chip *chip) regmap_del_irq_chip(chip->irq, chip->irq_data); } -static struct regmap_irq_chip pm805_irq_chip = { +static const struct regmap_irq_chip pm805_irq_chip = { .name = "88pm805", .irqs = pm805_irqs, .num_irqs = ARRAY_SIZE(pm805_irqs), diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 151bf03e772d..488e346047c1 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -624,8 +624,8 @@ static int device_irq_init(struct pm860x_chip *chip, ret = -EBUSY; goto out; } - irq_domain_add_legacy(node, nr_irqs, chip->irq_base, 0, - &pm860x_irq_domain_ops, chip); + irq_domain_create_legacy(of_fwnode_handle(node), nr_irqs, chip->irq_base, 0, + &pm860x_irq_domain_ops, chip); chip->core_irq = i2c->irq; if (!chip->core_irq) goto out; @@ -916,7 +916,7 @@ static void device_power_init(struct pm860x_chip *chip, power_devs[0].platform_data = pdata->power; power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata); power_devs[0].num_resources = ARRAY_SIZE(battery_resources); - power_devs[0].resources = &battery_resources[0], + power_devs[0].resources = &battery_resources[0]; ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, &battery_resources[0], chip->irq_base, NULL); if (ret < 0) @@ -925,7 +925,7 @@ static void device_power_init(struct pm860x_chip *chip, power_devs[1].platform_data = pdata->power; power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata); power_devs[1].num_resources = ARRAY_SIZE(charger_resources); - power_devs[1].resources = &charger_resources[0], + power_devs[1].resources = &charger_resources[0]; ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, &charger_resources[0], chip->irq_base, NULL); if (ret < 0) @@ -942,7 +942,7 @@ static void device_power_init(struct pm860x_chip *chip, pdata->chg_desc->charger_regulators = &chg_desc_regulator_data[0]; pdata->chg_desc->num_charger_regulators = - ARRAY_SIZE(chg_desc_regulator_data), + ARRAY_SIZE(chg_desc_regulator_data); power_devs[3].platform_data = pdata->chg_desc; power_devs[3].pdata_size = sizeof(*pdata->chg_desc); ret = mfd_add_devices(chip->dev, 0, &power_devs[3], 1, @@ -958,7 +958,7 @@ static void device_onkey_init(struct pm860x_chip *chip, int ret; onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources); - onkey_devs[0].resources = &onkey_resources[0], + onkey_devs[0].resources = &onkey_resources[0]; ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], ARRAY_SIZE(onkey_devs), &onkey_resources[0], chip->irq_base, NULL); @@ -972,7 +972,7 @@ static void device_codec_init(struct pm860x_chip *chip, int ret; codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); - codec_devs[0].resources = &codec_resources[0], + codec_devs[0].resources = &codec_resources[0]; ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], ARRAY_SIZE(codec_devs), &codec_resources[0], 0, NULL); @@ -1233,7 +1233,7 @@ static int pm860x_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); static const struct i2c_device_id pm860x_id_table[] = { - { "88PM860x", 0 }, + { "88PM860x" }, {} }; MODULE_DEVICE_TABLE(i2c, pm860x_id_table); diff --git a/drivers/mfd/88pm886.c b/drivers/mfd/88pm886.c new file mode 100644 index 000000000000..39dd9a818b0f --- /dev/null +++ b/drivers/mfd/88pm886.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <linux/i2c.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/regmap.h> + +#include <linux/mfd/88pm886.h> + +static const struct regmap_config pm886_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PM886_REG_RTC_SPARE6, +}; + +static const struct regmap_irq pm886_regmap_irqs[] = { + REGMAP_IRQ_REG(PM886_IRQ_ONKEY, 0, PM886_INT_ENA1_ONKEY), +}; + +static const struct regmap_irq_chip pm886_regmap_irq_chip = { + .name = "88pm886", + .irqs = pm886_regmap_irqs, + .num_irqs = ARRAY_SIZE(pm886_regmap_irqs), + .num_regs = 4, + .status_base = PM886_REG_INT_STATUS1, + .ack_base = PM886_REG_INT_STATUS1, + .unmask_base = PM886_REG_INT_ENA_1, +}; + +static const struct resource pm886_onkey_resources[] = { + DEFINE_RES_IRQ_NAMED(PM886_IRQ_ONKEY, "88pm886-onkey"), +}; + +static const struct mfd_cell pm886_devs[] = { + MFD_CELL_RES("88pm886-onkey", pm886_onkey_resources), + MFD_CELL_NAME("88pm886-regulator"), + MFD_CELL_NAME("88pm886-rtc"), +}; + +static int pm886_power_off_handler(struct sys_off_data *sys_off_data) +{ + struct pm886_chip *chip = sys_off_data->cb_data; + struct regmap *regmap = chip->regmap; + struct device *dev = &chip->client->dev; + int err; + + err = regmap_update_bits(regmap, PM886_REG_MISC_CONFIG1, PM886_SW_PDOWN, PM886_SW_PDOWN); + if (err) { + dev_err(dev, "Failed to power off the device: %d\n", err); + return NOTIFY_BAD; + } + return NOTIFY_DONE; +} + +static int pm886_setup_irq(struct pm886_chip *chip, + struct regmap_irq_chip_data **irq_data) +{ + struct regmap *regmap = chip->regmap; + struct device *dev = &chip->client->dev; + int err; + + /* Set interrupt clearing mode to clear on write. */ + err = regmap_update_bits(regmap, PM886_REG_MISC_CONFIG2, + PM886_INT_INV | PM886_INT_CLEAR | PM886_INT_MASK_MODE, + PM886_INT_WC); + if (err) { + dev_err(dev, "Failed to set interrupt clearing mode: %d\n", err); + return err; + } + + err = devm_regmap_add_irq_chip(dev, regmap, chip->client->irq, + IRQF_ONESHOT, 0, &pm886_regmap_irq_chip, + irq_data); + if (err) { + dev_err(dev, "Failed to request IRQ: %d\n", err); + return err; + } + + return 0; +} + +static int pm886_probe(struct i2c_client *client) +{ + struct regmap_irq_chip_data *irq_data; + struct device *dev = &client->dev; + struct pm886_chip *chip; + struct regmap *regmap; + unsigned int chip_id; + int err; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + chip->chip_id = (uintptr_t)device_get_match_data(dev); + i2c_set_clientdata(client, chip); + + regmap = devm_regmap_init_i2c(client, &pm886_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Failed to initialize regmap\n"); + chip->regmap = regmap; + + err = regmap_read(regmap, PM886_REG_ID, &chip_id); + if (err) + return dev_err_probe(dev, err, "Failed to read chip ID\n"); + + if (chip->chip_id != chip_id) + return dev_err_probe(dev, -EINVAL, "Unsupported chip: 0x%x\n", chip_id); + + err = pm886_setup_irq(chip, &irq_data); + if (err) + return err; + + err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, pm886_devs, ARRAY_SIZE(pm886_devs), + NULL, 0, regmap_irq_get_domain(irq_data)); + if (err) + return dev_err_probe(dev, err, "Failed to add devices\n"); + + err = devm_register_power_off_handler(dev, pm886_power_off_handler, chip); + if (err) + return dev_err_probe(dev, err, "Failed to register power off handler\n"); + + if (device_property_read_bool(dev, "wakeup-source")) { + err = devm_device_init_wakeup(dev); + if (err) + return dev_err_probe(dev, err, "Failed to init wakeup\n"); + } + + return 0; +} + +static const struct of_device_id pm886_of_match[] = { + { .compatible = "marvell,88pm886-a1", .data = (void *)PM886_A1_CHIP_ID }, + { } +}; +MODULE_DEVICE_TABLE(of, pm886_of_match); + +static struct i2c_driver pm886_i2c_driver = { + .driver = { + .name = "88pm886", + .of_match_table = pm886_of_match, + }, + .probe = pm886_probe, +}; +module_i2c_driver(pm886_i2c_driver); + +MODULE_DESCRIPTION("Marvell 88PM886 PMIC driver"); +MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e7a6e45b9fac..6fb3768e3d71 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -20,6 +20,18 @@ config MFD_CS5535 This is the core driver for CS5535/CS5536 MFD functions. This is necessary for using the board's GPIO and MFGPT functionality. +config MFD_ADP5585 + tristate "Analog Devices ADP5585 keypad decoder and I/O expander driver" + select MFD_CORE + select REGMAP_I2C + depends on I2C + depends on OF + help + Say yes here to add support for the Analog Devices ADP5585 GPIO + expander, PWM and keypad controller. This includes the I2C driver and + the core APIs _only_, you have to select individual components like + the GPIO and PWM functions under the corresponding menus. + config MFD_ALTERA_A10SR bool "Altera Arria10 DevKit System Resource chip" depends on ARCH_INTEL_SOCFPGA && SPI_MASTER=y && OF @@ -126,7 +138,7 @@ config MFD_AAT2870_CORE config MFD_AT91_USART tristate "AT91 USART Driver" select MFD_CORE - depends on ARCH_AT91 || COMPILE_TEST + depends on ARCH_AT91 || ARCH_LAN969X || COMPILE_TEST help Select this to get support for AT91 USART IP. This is a wrapper over at91-usart-serial driver and usart-spi-driver. Only one function @@ -224,6 +236,18 @@ config MFD_AXP20X_RSB components like regulators or the PEK (Power Enable Key) under the corresponding menus. +config MFD_CGBC + tristate "Congatec Board Controller" + select MFD_CORE + depends on X86 + help + This is the core driver of the Board Controller found on some Congatec + SMARC modules. The Board Controller provides functions like watchdog, + I2C busses, and GPIO controller. + + To compile this driver as a module, choose M here: the module will be + called cgbc-core. + config MFD_CROS_EC_DEV tristate "ChromeOS Embedded Controller multifunction device" select MFD_CORE @@ -292,7 +316,7 @@ config MFD_MADERA_SPI config MFD_MAX5970 tristate "Maxim 5970/5978 power switch and monitor" - depends on (I2C && OF) + depends on I2C && OF select MFD_SIMPLE_MFD_I2C help This driver controls a Maxim 5970/5978 switch via I2C bus. @@ -458,7 +482,7 @@ config MFD_EXYNOS_LPASS config MFD_GATEWORKS_GSC tristate "Gateworks System Controller" - depends on (I2C && OF) + depends on I2C && OF select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -473,7 +497,7 @@ config MFD_GATEWORKS_GSC config MFD_MC13XXX tristate - depends on (SPI_MASTER || I2C) + depends on SPI_MASTER || I2C select MFD_CORE select REGMAP_IRQ help @@ -794,6 +818,18 @@ config MFD_88PM860X select individual components like voltage regulators, RTC and battery-charger under the corresponding menus. +config MFD_88PM886_PMIC + bool "Marvell 88PM886 PMIC" + depends on I2C=y + depends on OF + select REGMAP_I2C + select REGMAP_IRQ + select MFD_CORE + help + This enables support for Marvell 88PM886 Power Management IC. + This includes the I2C driver and the core APIs _only_, you have to + select individual components like onkey under the corresponding menus. + config MFD_MAX14577 tristate "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support" depends on I2C @@ -822,7 +858,7 @@ config MFD_MAX77541 There are regulators and adc. config MFD_MAX77620 - bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support" + tristate "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support" depends on I2C=y depends on OF select MFD_CORE @@ -880,6 +916,19 @@ config MFD_MAX77693 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX77705 + tristate "Maxim MAX77705 PMIC Support" + depends on I2C + select MFD_CORE + select MFD_SIMPLE_MFD_I2C + help + Say yes here to add support for Maxim Integrated MAX77705 PMIC. + This is a Power Management IC with Charger, safe LDOs, Flash, Haptic + and MUIC controls on chip. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. + config MFD_MAX77714 tristate "Maxim Semiconductor MAX77714 PMIC Support" depends on I2C @@ -894,6 +943,26 @@ config MFD_MAX77714 drivers must be enabled in order to use each functionality of the device. +config MFD_MAX77759 + tristate "Maxim Integrated MAX77759 PMIC" + depends on I2C + depends on OF + select IRQ_DOMAIN + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + Say yes here to add support for Maxim Integrated MAX77759. + This is a companion Power Management IC for USB Type-C applications + with Battery Charger, Fuel Gauge, temperature sensors, USB Type-C + Port Controller (TCPC), NVMEM, and additional GPIO interfaces. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. + + To compile this driver as a module, choose M here: the module will be + called max77759. + config MFD_MAX77843 bool "Maxim Semiconductor MAX77843 PMIC Support" depends on I2C=y @@ -1083,33 +1152,9 @@ config MFD_RETU Retu and Tahvo are a multi-function devices found on Nokia Internet Tablets (770, N800 and N810). -config MFD_PCF50633 - tristate "NXP PCF50633" - depends on I2C - select REGMAP_I2C - help - Say yes here if you have NXP PCF50633 chip on your board. - This core driver provides register access and IRQ handling - facilities, and registers devices for the various functions - so that function-specific drivers can bind to them. - -config PCF50633_ADC - tristate "NXP PCF50633 ADC" - depends on MFD_PCF50633 - help - Say yes here if you want to include support for ADC in the - NXP PCF50633 chip. - -config PCF50633_GPIO - tristate "NXP PCF50633 GPIO" - depends on MFD_PCF50633 - help - Say yes here if you want to include support GPIO for pins on - the PCF50633 chip. - config MFD_PM8XXX tristate "Qualcomm PM8xxx PMIC chips driver" - depends on (ARM || HEXAGON || COMPILE_TEST) + depends on ARM || HEXAGON || COMPILE_TEST select IRQ_DOMAIN_HIERARCHY select MFD_CORE select REGMAP @@ -1225,7 +1270,7 @@ config MFD_RK8XX select MFD_CORE config MFD_RK8XX_I2C - tristate "Rockchip RK805/RK808/RK809/RK817/RK818 Power Management Chip" + tristate "Rockchip RK805/RK808/RK809/RK816/RK817/RK818 Power Management Chip" depends on I2C && OF select MFD_CORE select REGMAP_I2C @@ -1233,7 +1278,7 @@ config MFD_RK8XX_I2C select MFD_RK8XX help If you say yes here you get support for the RK805, RK808, RK809, - RK817 and RK818 Power Management chips. + RK816, RK817 and RK818 Power Management chips. This driver provides common support for accessing the device through I2C interface. The device supports multiple sub-devices including interrupts, RTC, LDO & DCDC regulators, and onkey. @@ -1267,21 +1312,42 @@ config MFD_RN5T618 functionality of the device. config MFD_SEC_CORE - tristate "Samsung Electronics PMIC Series Support" + tristate + select MFD_CORE + select REGMAP_IRQ + +config MFD_SEC_ACPM + tristate "Samsung Electronics S2MPG1x PMICs" + depends on EXYNOS_ACPM_PROTOCOL + depends on OF + select MFD_SEC_CORE + help + Support for the Samsung Electronics PMICs with ACPM interface. + This is a Power Management IC for mobile applications with buck + converters, various LDOs, power meters, RTC, clock outputs, and + additional GPIOs interfaces. + This driver provides common support for accessing the device; + additional drivers must be enabled in order to use the functionality + of the device. + + To compile this driver as a module, choose M here: the module will be + called sec-acpm. + +config MFD_SEC_I2C + tristate "Samsung Electronics S2MPA/S2MPS1X/S2MPU/S5M series PMICs" depends on I2C=y depends on OF - select MFD_CORE + select MFD_SEC_CORE select REGMAP_I2C - select REGMAP_IRQ help - Support for the Samsung Electronics PMIC devices coming - usually along with Samsung Exynos SoC chipset. + Support for the Samsung Electronics PMIC devices with I2C interface + coming usually along with Samsung Exynos SoC chipset. This driver provides common support for accessing the device, additional drivers must be enabled in order to use the functionality - of the device + of the device. To compile this driver as a module, choose M here: the - module will be called sec-core. + module will be called sec-i2c. Have in mind that important core drivers (like regulators) depend on this driver so building this as a module might require proper initial ramdisk or might not boot up as well in certain scenarios. @@ -1418,7 +1484,7 @@ config MFD_DB8500_PRCMU config MFD_STMPE bool "STMicroelectronics STMPE" - depends on (I2C=y || SPI_MASTER=y) + depends on I2C=y || SPI_MASTER=y depends on OF select MFD_CORE help @@ -1459,12 +1525,6 @@ config STMPE_SPI This is used to enable SPI interface of STMPE endmenu -config MFD_STA2X11 - bool "STMicroelectronics STA2X11" - depends on STA2X11 - select MFD_CORE - select REGMAP_MMIO - config MFD_SUN6I_PRCM bool "Allwinner A31/A23/A33 PRCM controller" depends on ARCH_SUNXI || COMPILE_TEST @@ -1773,6 +1833,7 @@ config TWL4030_CORE bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support" depends on I2C=y select IRQ_DOMAIN + select MFD_CORE select REGMAP_I2C help Say yes here if you have TWL4030 / TWL6030 family chip on your board. @@ -2088,6 +2149,19 @@ config MFD_ROHM_BD957XMUF BD9573MUF Power Management ICs. BD9576 and BD9573 are primarily designed to be used to power R-Car series processors. +config MFD_ROHM_BD96801 + tristate "ROHM BD96801 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 BD96801 Power + Management IC. The ROHM BD96801 is a highly scalable Power Management + IC for industrial and automotive use. The BD96801 can be used as a + master PMIC in a chained PMIC solution with suitable companion PMICs. + config MFD_STM32_LPTIMER tristate "Support for STM32 Low-Power Timer" depends on (ARCH_STM32 && OF) || COMPILE_TEST @@ -2115,7 +2189,7 @@ config MFD_STM32_TIMERS config MFD_STPMIC1 tristate "Support for STPMIC1 PMIC" - depends on (I2C=y && OF) + depends on I2C=y && OF select REGMAP_I2C select REGMAP_IRQ select MFD_CORE @@ -2207,6 +2281,7 @@ config MFD_ACER_A500_EC config MFD_QCOM_PM8008 tristate "QCOM PM8008 Power Management IC" depends on I2C && OF + select MFD_CORE select REGMAP_I2C select REGMAP_IRQ help @@ -2242,6 +2317,36 @@ config MCP_UCB1200_TS endmenu +config MFD_CS40L50_CORE + tristate + select MFD_CORE + select FW_CS_DSP + select REGMAP_IRQ + +config MFD_CS40L50_I2C + tristate "Cirrus Logic CS40L50 (I2C)" + select REGMAP_I2C + select MFD_CS40L50_CORE + depends on I2C + help + Select this to support the Cirrus Logic CS40L50 Haptic + Driver over I2C. + + This driver can be built as a module. If built as a module it will be + called "cs40l50-i2c". + +config MFD_CS40L50_SPI + tristate "Cirrus Logic CS40L50 (SPI)" + select REGMAP_SPI + select MFD_CS40L50_CORE + depends on SPI + help + Select this to support the Cirrus Logic CS40L50 Haptic + Driver over SPI. + + This driver can be built as a module. If built as a module it will be + called "cs40l50-spi". + config MFD_VEXPRESS_SYSREG tristate "Versatile Express System Registers" depends on VEXPRESS_CONFIG && GPIOLIB @@ -2305,6 +2410,19 @@ config MFD_INTEL_M10_BMC_PMCI additional drivers must be enabled in order to use the functionality of the device. +config MFD_QNAP_MCU + tristate "QNAP microcontroller unit core driver" + depends on SERIAL_DEV_BUS + select MFD_CORE + help + Select this to get support for the QNAP MCU device found in + several devices of QNAP network attached storage products that + implements additional functionality for the device, like fan + and LED control. + + This driver implements the base serial protocol to talk to the + device and provides functions for the other parts to hook into. + config MFD_RSMU_I2C tristate "Renesas Synchronization Management Unit with I2C" depends on I2C && OF @@ -2333,5 +2451,17 @@ config MFD_RSMU_SPI Additional drivers must be enabled in order to use the functionality of the device. +config MFD_UPBOARD_FPGA + tristate "Support for the AAeon UP board FPGA" + depends on (X86 && ACPI) + select MFD_CORE + help + Select this option to enable the AAEON UP and UP^2 onboard FPGA. + This is the core driver of this FPGA, which has a pin controller and a + LED controller. + + To compile this driver as a module, choose M here: the module will be + called upboard-fpga. + endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index c66f07edcd0e..79495f9f3457 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -7,11 +7,13 @@ obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o +obj-$(CONFIG_MFD_88PM886_PMIC) += 88pm886.o obj-$(CONFIG_MFD_ACT8945A) += act8945a.o obj-$(CONFIG_MFD_SM501) += sm501.o obj-$(CONFIG_ARCH_BCM2835) += bcm2835-pm.o obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o +obj-$(CONFIG_MFD_CGBC) += cgbc-core.o obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o obj-$(CONFIG_MFD_CS42L43) += cs42l43.o obj-$(CONFIG_MFD_CS42L43_I2C) += cs42l43-i2c.o @@ -24,7 +26,6 @@ obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o obj-$(CONFIG_MFD_TI_LP87565) += lp87565.o obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o -obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o obj-$(CONFIG_MFD_STMPE) += stmpe.o obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o @@ -88,6 +89,10 @@ obj-$(CONFIG_MFD_MADERA) += madera.o obj-$(CONFIG_MFD_MADERA_I2C) += madera-i2c.o obj-$(CONFIG_MFD_MADERA_SPI) += madera-spi.o +obj-$(CONFIG_MFD_CS40L50_CORE) += cs40l50-core.o +obj-$(CONFIG_MFD_CS40L50_I2C) += cs40l50-i2c.o +obj-$(CONFIG_MFD_CS40L50_SPI) += cs40l50-spi.o + obj-$(CONFIG_TPS6105X) += tps6105x.o obj-$(CONFIG_TPS65010) += tps65010.o obj-$(CONFIG_TPS6507X) += tps6507x.o @@ -162,7 +167,9 @@ obj-$(CONFIG_MFD_MAX77620) += max77620.o obj-$(CONFIG_MFD_MAX77650) += max77650.o obj-$(CONFIG_MFD_MAX77686) += max77686.o obj-$(CONFIG_MFD_MAX77693) += max77693.o +obj-$(CONFIG_MFD_MAX77705) += max77705.o obj-$(CONFIG_MFD_MAX77714) += max77714.o +obj-$(CONFIG_MFD_MAX77759) += max77759.o obj-$(CONFIG_MFD_MAX77843) += max77843.o obj-$(CONFIG_MFD_MAX8907) += max8907.o max8925-objs := max8925-core.o max8925-i2c.o @@ -177,10 +184,6 @@ obj-$(CONFIG_MFD_MT6370) += mt6370.o mt6397-objs := mt6397-core.o mt6397-irq.o mt6358-irq.o obj-$(CONFIG_MFD_MT6397) += mt6397.o -pcf50633-objs := pcf50633-core.o pcf50633-irq.o -obj-$(CONFIG_MFD_PCF50633) += pcf50633.o -obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o -obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o obj-$(CONFIG_RZ_MTU3) += rz-mtu3.o obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o @@ -188,6 +191,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o obj-$(CONFIG_PMIC_ADP5520) += adp5520.o +obj-$(CONFIG_MFD_ADP5585) += adp5585.o obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o obj-$(CONFIG_MFD_INTEL_QUARK_I2C_GPIO) += intel_quark_i2c_gpio.o obj-$(CONFIG_LPC_SCH) += lpc_sch.o @@ -225,7 +229,10 @@ obj-$(CONFIG_MFD_RK8XX) += rk8xx-core.o obj-$(CONFIG_MFD_RK8XX_I2C) += rk8xx-i2c.o obj-$(CONFIG_MFD_RK8XX_SPI) += rk8xx-spi.o obj-$(CONFIG_MFD_RN5T618) += rn5t618.o -obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o +sec-core-objs := sec-common.o sec-irq.o +obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o +obj-$(CONFIG_MFD_SEC_ACPM) += sec-acpm.o +obj-$(CONFIG_MFD_SEC_I2C) += sec-i2c.o obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o obj-$(CONFIG_MFD_VEXPRESS_SYSREG) += vexpress-sysreg.o @@ -264,6 +271,7 @@ obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.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_ROHM_BD96801) += rohm-bd96801.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 @@ -280,7 +288,9 @@ obj-$(CONFIG_MFD_INTEL_M10_BMC_PMCI) += intel-m10-bmc-pmci.o obj-$(CONFIG_MFD_ATC260X) += atc260x-core.o obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x-i2c.o -rsmu-i2c-objs := rsmu_core.o rsmu_i2c.o -rsmu-spi-objs := rsmu_core.o rsmu_spi.o -obj-$(CONFIG_MFD_RSMU_I2C) += rsmu-i2c.o -obj-$(CONFIG_MFD_RSMU_SPI) += rsmu-spi.o +obj-$(CONFIG_MFD_QNAP_MCU) += qnap-mcu.o + +obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o +obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o + +obj-$(CONFIG_MFD_UPBOARD_FPGA) += upboard-fpga.o diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 2fee62f1016c..34d66ba9646a 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -320,9 +320,7 @@ static const struct file_operations aat2870_reg_fops = { static void aat2870_init_debugfs(struct aat2870_data *aat2870) { - aat2870->dentry_root = debugfs_create_dir("aat2870", NULL); - - debugfs_create_file("regs", 0644, aat2870->dentry_root, aat2870, + debugfs_create_file("regs", 0644, aat2870->client->debugfs, aat2870, &aat2870_reg_fops); } @@ -439,7 +437,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend, aat2870_i2c_resume); static const struct i2c_device_id aat2870_i2c_id_table[] = { - { "aat2870", 0 }, + { "aat2870" }, { } }; diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 15c95828b09a..049abcbd71ce 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -580,9 +580,9 @@ static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) num_irqs = AB8500_NR_IRQS; /* If ->irq_base is zero this will give a linear mapping */ - ab8500->domain = irq_domain_add_simple(ab8500->dev->of_node, - num_irqs, 0, - &ab8500_irq_ops, ab8500); + ab8500->domain = irq_domain_create_simple(of_fwnode_handle(ab8500->dev->of_node), + num_irqs, 0, + &ab8500_irq_ops, ab8500); if (!ab8500->domain) { dev_err(ab8500->dev, "Failed to create irqdomain\n"); diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index 8f3ebe651eea..b6b44e2e3198 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -159,7 +159,7 @@ static struct platform_driver ab8500_sysctrl_driver = { .of_match_table = ab8500_sysctrl_match, }, .probe = ab8500_sysctrl_probe, - .remove_new = ab8500_sysctrl_remove, + .remove = ab8500_sysctrl_remove, }; static int __init ab8500_sysctrl_init(void) diff --git a/drivers/mfd/ac100.c b/drivers/mfd/ac100.c index 6d49d7fb5f14..8f47c392cbd1 100644 --- a/drivers/mfd/ac100.c +++ b/drivers/mfd/ac100.c @@ -72,7 +72,7 @@ static const struct regmap_config ac100_regmap_config = { .wr_table = &ac100_writeable_table, .volatile_table = &ac100_volatile_table, .max_register = AC100_RTC_GP(15), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static struct mfd_cell ac100_cells[] = { diff --git a/drivers/mfd/act8945a.c b/drivers/mfd/act8945a.c index 4e32ac3d573e..cafefb4451cb 100644 --- a/drivers/mfd/act8945a.c +++ b/drivers/mfd/act8945a.c @@ -54,7 +54,7 @@ static int act8945a_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id act8945a_i2c_id[] = { - { "act8945a", 0 }, + { "act8945a" }, {} }; MODULE_DEVICE_TABLE(i2c, act8945a_i2c_id); diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c new file mode 100644 index 000000000000..160e0b38106a --- /dev/null +++ b/drivers/mfd/adp5585.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADP5585 I/O expander, PWM controller and keypad controller + * + * Copyright 2022 NXP + * Copyright 2024 Ideas on Board Oy + */ + +#include <linux/array_size.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mfd/adp5585.h> +#include <linux/mfd/core.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/types.h> + +static const struct mfd_cell adp5585_devs[] = { + { .name = "adp5585-gpio", }, + { .name = "adp5585-pwm", }, +}; + +static const struct regmap_range adp5585_volatile_ranges[] = { + regmap_reg_range(ADP5585_ID, ADP5585_GPI_STATUS_B), +}; + +static const struct regmap_access_table adp5585_volatile_regs = { + .yes_ranges = adp5585_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(adp5585_volatile_ranges), +}; + +/* + * Chip variants differ in the default configuration of pull-up and pull-down + * resistors, and therefore have different default register values: + * + * - The -00, -01 and -03 variants (collectively referred to as + * ADP5585_REGMAP_00) have pull-up on all GPIO pins by default. + * - The -02 variant has no default pull-up or pull-down resistors. + * - The -04 variant has default pull-down resistors on all GPIO pins. + */ + +static const u8 adp5585_regmap_defaults_00[ADP5585_MAX_REG + 1] = { + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 adp5585_regmap_defaults_02[ADP5585_MAX_REG + 1] = { + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, + /* 0x18 */ 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 adp5585_regmap_defaults_04[ADP5585_MAX_REG + 1] = { + /* 0x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, + /* 0x18 */ 0x05, 0x55, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +enum adp5585_regmap_type { + ADP5585_REGMAP_00, + ADP5585_REGMAP_02, + ADP5585_REGMAP_04, +}; + +static const struct regmap_config adp5585_regmap_configs[] = { + [ADP5585_REGMAP_00] = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADP5585_MAX_REG, + .volatile_table = &adp5585_volatile_regs, + .cache_type = REGCACHE_MAPLE, + .reg_defaults_raw = adp5585_regmap_defaults_00, + .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_00), + }, + [ADP5585_REGMAP_02] = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADP5585_MAX_REG, + .volatile_table = &adp5585_volatile_regs, + .cache_type = REGCACHE_MAPLE, + .reg_defaults_raw = adp5585_regmap_defaults_02, + .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_02), + }, + [ADP5585_REGMAP_04] = { + .reg_bits = 8, + .val_bits = 8, + .max_register = ADP5585_MAX_REG, + .volatile_table = &adp5585_volatile_regs, + .cache_type = REGCACHE_MAPLE, + .reg_defaults_raw = adp5585_regmap_defaults_04, + .num_reg_defaults_raw = sizeof(adp5585_regmap_defaults_04), + }, +}; + +static int adp5585_i2c_probe(struct i2c_client *i2c) +{ + const struct regmap_config *regmap_config; + struct adp5585_dev *adp5585; + unsigned int id; + int ret; + + adp5585 = devm_kzalloc(&i2c->dev, sizeof(*adp5585), GFP_KERNEL); + if (!adp5585) + return -ENOMEM; + + i2c_set_clientdata(i2c, adp5585); + + regmap_config = i2c_get_match_data(i2c); + adp5585->regmap = devm_regmap_init_i2c(i2c, regmap_config); + if (IS_ERR(adp5585->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(adp5585->regmap), + "Failed to initialize register map\n"); + + ret = regmap_read(adp5585->regmap, ADP5585_ID, &id); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to read device ID\n"); + + if ((id & ADP5585_MAN_ID_MASK) != ADP5585_MAN_ID_VALUE) + return dev_err_probe(&i2c->dev, -ENODEV, + "Invalid device ID 0x%02x\n", id); + + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, + adp5585_devs, ARRAY_SIZE(adp5585_devs), + NULL, 0, NULL); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to add child devices\n"); + + return 0; +} + +static int adp5585_suspend(struct device *dev) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(dev); + + regcache_cache_only(adp5585->regmap, true); + + return 0; +} + +static int adp5585_resume(struct device *dev) +{ + struct adp5585_dev *adp5585 = dev_get_drvdata(dev); + + regcache_cache_only(adp5585->regmap, false); + regcache_mark_dirty(adp5585->regmap); + + return regcache_sync(adp5585->regmap); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(adp5585_pm, adp5585_suspend, adp5585_resume); + +static const struct of_device_id adp5585_of_match[] = { + { + .compatible = "adi,adp5585-00", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + }, { + .compatible = "adi,adp5585-01", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + }, { + .compatible = "adi,adp5585-02", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_02], + }, { + .compatible = "adi,adp5585-03", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_00], + }, { + .compatible = "adi,adp5585-04", + .data = &adp5585_regmap_configs[ADP5585_REGMAP_04], + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, adp5585_of_match); + +static struct i2c_driver adp5585_i2c_driver = { + .driver = { + .name = "adp5585", + .of_match_table = adp5585_of_match, + .pm = pm_sleep_ptr(&adp5585_pm), + }, + .probe = adp5585_i2c_probe, +}; +module_i2c_driver(adp5585_i2c_driver); + +MODULE_DESCRIPTION("ADP5585 core driver"); +MODULE_AUTHOR("Haibo Chen <haibo.chen@nxp.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c index 0e52bd2ebd74..fb5f988e61f3 100644 --- a/drivers/mfd/altera-sysmgr.c +++ b/drivers/mfd/altera-sysmgr.c @@ -109,7 +109,9 @@ struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, dev = driver_find_device_by_of_node(&altr_sysmgr_driver.driver, (void *)sysmgr_np); - of_node_put(sysmgr_np); + if (property) + of_node_put(sysmgr_np); + if (!dev) return ERR_PTR(-EPROBE_DEFER); diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 19a0adf8ce3d..85ff8717d850 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -1429,4 +1429,5 @@ int arizona_dev_exit(struct arizona *arizona) } EXPORT_SYMBOL_GPL(arizona_dev_exit); +MODULE_DESCRIPTION("Wolfson Arizona core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index d919ae9691e2..ac2139597fab 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -312,8 +312,7 @@ int arizona_irq_init(struct arizona *arizona) flags |= arizona->pdata.irq_flags; /* Allocate a virtual IRQ domain to distribute to the regmap domains */ - arizona->virq = irq_domain_add_linear(NULL, 2, &arizona_domain_ops, - arizona); + arizona->virq = irq_domain_create_linear(NULL, 2, &arizona_domain_ops, arizona); if (!arizona->virq) { dev_err(arizona->dev, "Failed to add core IRQ domain\n"); ret = -EINVAL; diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index de5d894ac04a..eaa2b2bc5dd0 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -190,19 +190,12 @@ static int arizona_spi_acpi_probe(struct arizona *arizona) static int arizona_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); - const void *match_data; struct arizona *arizona; const struct regmap_config *regmap_config = NULL; unsigned long type = 0; int ret; - match_data = device_get_match_data(&spi->dev); - if (match_data) - type = (unsigned long)match_data; - else if (id) - type = id->driver_data; - + type = (unsigned long)spi_get_device_match_data(spi); switch (type) { case WM5102: if (IS_ENABLED(CONFIG_MFD_WM5102)) diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index c7e85ff38013..9741977031df 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c @@ -106,7 +106,7 @@ static const struct regmap_config as3711_regmap_config = { .precious_reg = as3711_precious_reg, .max_register = AS3711_MAX_REG, .num_reg_defaults_raw = AS3711_NUM_REGS, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; #ifdef CONFIG_OF diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c index a2bf68afc131..7ab6fcc9c27c 100644 --- a/drivers/mfd/as3722.c +++ b/drivers/mfd/as3722.c @@ -299,7 +299,7 @@ static const struct regmap_config as3722_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = AS3722_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .rd_table = &as3722_readable_table, .wr_table = &as3722_writable_table, .volatile_table = &as3722_volatile_table, @@ -394,7 +394,9 @@ static int as3722_i2c_probe(struct i2c_client *i2c) return ret; } - device_init_wakeup(as3722->dev, true); + ret = devm_device_init_wakeup(as3722->dev); + if (ret) + return dev_err_probe(as3722->dev, ret, "Failed to init wakeup\n"); dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n"); return 0; @@ -430,8 +432,8 @@ static const struct of_device_id as3722_of_match[] = { MODULE_DEVICE_TABLE(of, as3722_of_match); static const struct i2c_device_id as3722_i2c_id[] = { - { "as3722", 0 }, - {}, + { "as3722" }, + {} }; MODULE_DEVICE_TABLE(i2c, as3722_i2c_id); diff --git a/drivers/mfd/atc260x-core.c b/drivers/mfd/atc260x-core.c index 67473b58b03d..6b6d5f1b9d76 100644 --- a/drivers/mfd/atc260x-core.c +++ b/drivers/mfd/atc260x-core.c @@ -235,8 +235,8 @@ int atc260x_match_device(struct atc260x *atc260x, struct regmap_config *regmap_c mutex_init(atc260x->regmap_mutex); - regmap_cfg->lock = regmap_lock_mutex, - regmap_cfg->unlock = regmap_unlock_mutex, + regmap_cfg->lock = regmap_lock_mutex; + regmap_cfg->unlock = regmap_unlock_mutex; regmap_cfg->lock_arg = atc260x->regmap_mutex; return 0; diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index b52f7ffdad35..d5df5466eaf5 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -95,7 +95,7 @@ static int __maybe_unused atmel_flexcom_resume_noirq(struct device *dev) if (err) return err; - val = FLEX_MR_OPMODE(ddata->opmode), + val = FLEX_MR_OPMODE(ddata->opmode); writel(val, ddata->base + FLEX_MR); clk_disable_unprepare(ddata->clk); diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index e560066e5885..4628ca14e766 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -255,8 +255,8 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_apply); /** * atmel_hsmc_cs_conf_apply - apply an SMC CS conf * @regmap: the HSMC regmap - * @cs: the CS id * @layout: the layout of registers + * @cs: the CS id * @conf: the SMC CS conf to apply * * Applies an SMC CS configuration. @@ -296,8 +296,8 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_get); /** * atmel_hsmc_cs_conf_get - retrieve the current SMC CS conf * @regmap: the HSMC regmap - * @cs: the CS id * @layout: the layout of registers + * @cs: the CS id * @conf: the SMC CS conf object to store the current conf * * Retrieve the SMC CS configuration. diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index 68d3560cfe4a..5c93136f977e 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -65,6 +65,8 @@ static const struct of_device_id axp20x_i2c_of_match[] = { { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID }, { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, { .compatible = "x-powers,axp313a", .data = (void *)AXP313A_ID }, + { .compatible = "x-powers,axp323", .data = (void *)AXP323_ID }, + { .compatible = "x-powers,axp717", .data = (void *)AXP717_ID }, { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, { .compatible = "x-powers,axp15060", .data = (void *)AXP15060_ID }, @@ -74,17 +76,18 @@ MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match); #endif static const struct i2c_device_id axp20x_i2c_id[] = { - { "axp152", 0 }, - { "axp192", 0 }, - { "axp202", 0 }, - { "axp209", 0 }, - { "axp221", 0 }, - { "axp223", 0 }, - { "axp313a", 0 }, - { "axp803", 0 }, - { "axp806", 0 }, - { "axp15060", 0 }, - { }, + { "axp152" }, + { "axp192" }, + { "axp202" }, + { "axp209" }, + { "axp221" }, + { "axp223" }, + { "axp313a" }, + { "axp717" }, + { "axp803" }, + { "axp806" }, + { "axp15060" }, + { } }; MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); diff --git a/drivers/mfd/axp20x-rsb.c b/drivers/mfd/axp20x-rsb.c index 214bc0d84d44..059656f2a1bd 100644 --- a/drivers/mfd/axp20x-rsb.c +++ b/drivers/mfd/axp20x-rsb.c @@ -58,6 +58,7 @@ static void axp20x_rsb_remove(struct sunxi_rsb_device *rdev) static const struct of_device_id axp20x_rsb_of_match[] = { { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, + { .compatible = "x-powers,axp717", .data = (void *)AXP717_ID }, { .compatible = "x-powers,axp803", .data = (void *)AXP803_ID }, { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, { .compatible = "x-powers,axp809", .data = (void *)AXP809_ID }, diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index deaa969bab4e..e9914e8a29a3 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -34,19 +34,21 @@ #define AXP806_REG_ADDR_EXT_ADDR_SLAVE_MODE BIT(4) static const char * const axp20x_model_names[] = { - "AXP152", - "AXP192", - "AXP202", - "AXP209", - "AXP221", - "AXP223", - "AXP288", - "AXP313a", - "AXP803", - "AXP806", - "AXP809", - "AXP813", - "AXP15060", + [AXP152_ID] = "AXP152", + [AXP192_ID] = "AXP192", + [AXP202_ID] = "AXP202", + [AXP209_ID] = "AXP209", + [AXP221_ID] = "AXP221", + [AXP223_ID] = "AXP223", + [AXP288_ID] = "AXP288", + [AXP313A_ID] = "AXP313a", + [AXP323_ID] = "AXP323", + [AXP717_ID] = "AXP717", + [AXP803_ID] = "AXP803", + [AXP806_ID] = "AXP806", + [AXP809_ID] = "AXP809", + [AXP813_ID] = "AXP813", + [AXP15060_ID] = "AXP15060", }; static const struct regmap_range axp152_writeable_ranges[] = { @@ -192,6 +194,10 @@ static const struct regmap_range axp313a_writeable_ranges[] = { regmap_reg_range(AXP313A_ON_INDICATE, AXP313A_IRQ_STATE), }; +static const struct regmap_range axp323_writeable_ranges[] = { + regmap_reg_range(AXP313A_ON_INDICATE, AXP323_DCDC_MODE_CTRL2), +}; + static const struct regmap_range axp313a_volatile_ranges[] = { regmap_reg_range(AXP313A_SHUTDOWN_CTRL, AXP313A_SHUTDOWN_CTRL), regmap_reg_range(AXP313A_IRQ_STATE, AXP313A_IRQ_STATE), @@ -202,11 +208,47 @@ static const struct regmap_access_table axp313a_writeable_table = { .n_yes_ranges = ARRAY_SIZE(axp313a_writeable_ranges), }; +static const struct regmap_access_table axp323_writeable_table = { + .yes_ranges = axp323_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp323_writeable_ranges), +}; + static const struct regmap_access_table axp313a_volatile_table = { .yes_ranges = axp313a_volatile_ranges, .n_yes_ranges = ARRAY_SIZE(axp313a_volatile_ranges), }; +static const struct regmap_range axp717_writeable_ranges[] = { + regmap_reg_range(AXP717_PMU_FAULT, AXP717_MODULE_EN_CONTROL_1), + regmap_reg_range(AXP717_MIN_SYS_V_CONTROL, AXP717_BOOST_CONTROL), + regmap_reg_range(AXP717_VSYS_V_POWEROFF, AXP717_VSYS_V_POWEROFF), + regmap_reg_range(AXP717_IRQ0_EN, AXP717_IRQ4_EN), + regmap_reg_range(AXP717_IRQ0_STATE, AXP717_IRQ4_STATE), + regmap_reg_range(AXP717_TS_PIN_CFG, AXP717_TS_PIN_CFG), + regmap_reg_range(AXP717_ICC_CHG_SET, AXP717_CV_CHG_SET), + regmap_reg_range(AXP717_DCDC_OUTPUT_CONTROL, AXP717_CPUSLDO_CONTROL), + regmap_reg_range(AXP717_ADC_CH_EN_CONTROL, AXP717_ADC_CH_EN_CONTROL), + regmap_reg_range(AXP717_ADC_DATA_SEL, AXP717_ADC_DATA_SEL), +}; + +static const struct regmap_range axp717_volatile_ranges[] = { + regmap_reg_range(AXP717_ON_INDICATE, AXP717_PMU_FAULT), + regmap_reg_range(AXP717_IRQ0_STATE, AXP717_IRQ4_STATE), + regmap_reg_range(AXP717_BATT_PERCENT_DATA, AXP717_BATT_PERCENT_DATA), + regmap_reg_range(AXP717_BATT_V_H, AXP717_BATT_CHRG_I_L), + regmap_reg_range(AXP717_ADC_DATA_H, AXP717_ADC_DATA_L), +}; + +static const struct regmap_access_table axp717_writeable_table = { + .yes_ranges = axp717_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp717_writeable_ranges), +}; + +static const struct regmap_access_table axp717_volatile_table = { + .yes_ranges = axp717_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(axp717_volatile_ranges), +}; + static const struct regmap_range axp806_volatile_ranges[] = { regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE), }; @@ -287,6 +329,12 @@ static const struct resource axp22x_usb_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), }; +static const struct resource axp717_usb_power_supply_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_OVER_V, "VBUS_OVER_V"), + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), +}; + /* AXP803 and AXP813/AXP818 share the same interrupts */ static const struct resource axp803_usb_power_supply_resources[] = { DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), @@ -317,6 +365,11 @@ static const struct resource axp313a_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP313A_IRQ_PEK_FAL_EDGE, "PEK_DBF"), }; +static const struct resource axp717_pek_resources[] = { + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_PEK_RIS_EDGE, "PEK_DBR"), + DEFINE_RES_IRQ_NAMED(AXP717_IRQ_PEK_FAL_EDGE, "PEK_DBF"), +}; + static const struct resource axp803_pek_resources[] = { DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_RIS_EDGE, "PEK_DBR"), DEFINE_RES_IRQ_NAMED(AXP803_IRQ_PEK_FAL_EDGE, "PEK_DBF"), @@ -352,7 +405,7 @@ static const struct regmap_config axp192_regmap_config = { .wr_table = &axp192_writeable_table, .volatile_table = &axp192_volatile_table, .max_register = AXP20X_CC_CTRL, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct regmap_config axp20x_regmap_config = { @@ -388,7 +441,25 @@ static const struct regmap_config axp313a_regmap_config = { .wr_table = &axp313a_writeable_table, .volatile_table = &axp313a_volatile_table, .max_register = AXP313A_IRQ_STATE, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, +}; + +static const struct regmap_config axp323_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp323_writeable_table, + .volatile_table = &axp313a_volatile_table, + .max_register = AXP323_DCDC_MODE_CTRL2, + .cache_type = REGCACHE_MAPLE, +}; + +static const struct regmap_config axp717_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp717_writeable_table, + .volatile_table = &axp717_volatile_table, + .max_register = AXP717_ADC_DATA_L, + .cache_type = REGCACHE_MAPLE, }; static const struct regmap_config axp806_regmap_config = { @@ -589,6 +660,40 @@ static const struct regmap_irq axp313a_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP313A, DIE_TEMP_HIGH, 0, 0), }; +static const struct regmap_irq axp717_regmap_irqs[] = { + INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL2, 0, 7), + INIT_REGMAP_IRQ(AXP717, SOC_DROP_LVL1, 0, 6), + INIT_REGMAP_IRQ(AXP717, GAUGE_NEW_SOC, 0, 4), + INIT_REGMAP_IRQ(AXP717, BOOST_OVER_V, 0, 2), + INIT_REGMAP_IRQ(AXP717, VBUS_OVER_V, 0, 1), + INIT_REGMAP_IRQ(AXP717, VBUS_FAULT, 0, 0), + INIT_REGMAP_IRQ(AXP717, VBUS_PLUGIN, 1, 7), + INIT_REGMAP_IRQ(AXP717, VBUS_REMOVAL, 1, 6), + INIT_REGMAP_IRQ(AXP717, BATT_PLUGIN, 1, 5), + INIT_REGMAP_IRQ(AXP717, BATT_REMOVAL, 1, 4), + INIT_REGMAP_IRQ(AXP717, PEK_SHORT, 1, 3), + INIT_REGMAP_IRQ(AXP717, PEK_LONG, 1, 2), + INIT_REGMAP_IRQ(AXP717, PEK_FAL_EDGE, 1, 1), + INIT_REGMAP_IRQ(AXP717, PEK_RIS_EDGE, 1, 0), + INIT_REGMAP_IRQ(AXP717, WDOG_EXPIRE, 2, 7), + INIT_REGMAP_IRQ(AXP717, LDO_OVER_CURR, 2, 6), + INIT_REGMAP_IRQ(AXP717, BATT_OVER_CURR, 2, 5), + INIT_REGMAP_IRQ(AXP717, CHARG_DONE, 2, 4), + INIT_REGMAP_IRQ(AXP717, CHARG, 2, 3), + INIT_REGMAP_IRQ(AXP717, DIE_TEMP_HIGH, 2, 2), + INIT_REGMAP_IRQ(AXP717, CHARG_TIMER, 2, 1), + INIT_REGMAP_IRQ(AXP717, BATT_OVER_V, 2, 0), + INIT_REGMAP_IRQ(AXP717, BC_USB_DONE, 3, 7), + INIT_REGMAP_IRQ(AXP717, BC_USB_CHNG, 3, 6), + INIT_REGMAP_IRQ(AXP717, BATT_QUIT_TEMP_HIGH, 3, 4), + INIT_REGMAP_IRQ(AXP717, BATT_CHG_TEMP_HIGH, 3, 3), + INIT_REGMAP_IRQ(AXP717, BATT_CHG_TEMP_LOW, 3, 2), + INIT_REGMAP_IRQ(AXP717, BATT_ACT_TEMP_HIGH, 3, 1), + INIT_REGMAP_IRQ(AXP717, BATT_ACT_TEMP_LOW, 3, 0), + INIT_REGMAP_IRQ(AXP717, TYPEC_REMOVE, 4, 6), + INIT_REGMAP_IRQ(AXP717, TYPEC_PLUGIN, 4, 5), +}; + static const struct regmap_irq axp803_regmap_irqs[] = { INIT_REGMAP_IRQ(AXP803, ACIN_OVER_V, 0, 7), INIT_REGMAP_IRQ(AXP803, ACIN_PLUGIN, 0, 6), @@ -776,6 +881,17 @@ static const struct regmap_irq_chip axp313a_regmap_irq_chip = { .num_regs = 1, }; +static const struct regmap_irq_chip axp717_regmap_irq_chip = { + .name = "axp717_irq_chip", + .status_base = AXP717_IRQ0_STATE, + .ack_base = AXP717_IRQ0_STATE, + .unmask_base = AXP717_IRQ0_EN, + .init_ack_masked = true, + .irqs = axp717_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp717_regmap_irqs), + .num_regs = 5, +}; + static const struct regmap_irq_chip axp803_regmap_irq_chip = { .name = "axp803", .status_base = AXP20X_IRQ1_STATE, @@ -941,6 +1057,18 @@ static struct mfd_cell axp313a_cells[] = { MFD_CELL_RES("axp313a-pek", axp313a_pek_resources), }; +static struct mfd_cell axp717_cells[] = { + MFD_CELL_NAME("axp20x-regulator"), + MFD_CELL_RES("axp20x-pek", axp717_pek_resources), + MFD_CELL_OF("axp717-adc", + NULL, NULL, 0, 0, "x-powers,axp717-adc"), + MFD_CELL_OF("axp20x-usb-power-supply", + axp717_usb_power_supply_resources, NULL, 0, 0, + "x-powers,axp717-usb-power-supply"), + MFD_CELL_OF("axp20x-battery-power-supply", + NULL, NULL, 0, 0, "x-powers,axp717-battery-power-supply"), +}; + static const struct resource axp288_adc_resources[] = { DEFINE_RES_IRQ_NAMED(AXP288_IRQ_GPADC, "GPADC"), }; @@ -1113,6 +1241,7 @@ static int axp20x_power_off(struct sys_off_data *data) unsigned int shutdown_reg; switch (axp20x->variant) { + case AXP323_ID: case AXP313A_ID: shutdown_reg = AXP313A_SHUTDOWN_CTRL; break; @@ -1181,6 +1310,18 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_cfg = &axp313a_regmap_config; axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip; break; + case AXP323_ID: + axp20x->nr_cells = ARRAY_SIZE(axp313a_cells); + axp20x->cells = axp313a_cells; + axp20x->regmap_cfg = &axp323_regmap_config; + axp20x->regmap_irq_chip = &axp313a_regmap_irq_chip; + break; + case AXP717_ID: + axp20x->nr_cells = ARRAY_SIZE(axp717_cells); + axp20x->cells = axp717_cells; + axp20x->regmap_cfg = &axp717_regmap_config; + axp20x->regmap_irq_chip = &axp717_regmap_irq_chip; + break; case AXP803_ID: axp20x->nr_cells = ARRAY_SIZE(axp803_cells); axp20x->cells = axp803_cells; @@ -1231,7 +1372,7 @@ int axp20x_match_device(struct axp20x_dev *axp20x) axp20x->regmap_irq_chip = &axp15060_regmap_irq_chip; break; default: - dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant); + dev_err(dev, "unsupported AXP20X ID %u\n", axp20x->variant); return -EINVAL; } @@ -1305,7 +1446,7 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) } } - ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells, + ret = mfd_add_devices(axp20x->dev, PLATFORM_DEVID_NONE, axp20x->cells, axp20x->nr_cells, NULL, 0, NULL); if (ret) { @@ -1315,10 +1456,7 @@ int axp20x_device_probe(struct axp20x_dev *axp20x) } if (axp20x->variant != AXP288_ID) - devm_register_sys_off_handler(axp20x->dev, - SYS_OFF_MODE_POWER_OFF, - SYS_OFF_PRIO_DEFAULT, - axp20x_power_off, axp20x); + devm_register_power_off_handler(axp20x->dev, axp20x_power_off, axp20x); dev_info(axp20x->dev, "AXP20X driver loaded\n"); diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index 92eede9a5e61..5a8456bbd63f 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -17,6 +17,15 @@ #include <linux/regmap.h> #include <linux/slab.h> +/* Under primary I2C address: */ +#define BCM590XX_REG_PMUID 0x1e + +#define BCM590XX_REG_PMUREV 0x1f +#define BCM590XX_PMUREV_DIG_MASK 0xF +#define BCM590XX_PMUREV_DIG_SHIFT 0 +#define BCM590XX_PMUREV_ANA_MASK 0xF0 +#define BCM590XX_PMUREV_ANA_SHIFT 4 + static const struct mfd_cell bcm590xx_devs[] = { { .name = "bcm590xx-vregs", @@ -27,16 +36,57 @@ static const struct regmap_config bcm590xx_regmap_config_pri = { .reg_bits = 8, .val_bits = 8, .max_register = BCM590XX_MAX_REGISTER_PRI, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct regmap_config bcm590xx_regmap_config_sec = { .reg_bits = 8, .val_bits = 8, .max_register = BCM590XX_MAX_REGISTER_SEC, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, +}; + +/* Map PMU ID value to model name string */ +static const char * const bcm590xx_names[] = { + [BCM590XX_PMUID_BCM59054] = "BCM59054", + [BCM590XX_PMUID_BCM59056] = "BCM59056", }; +static int bcm590xx_parse_version(struct bcm590xx *bcm590xx) +{ + unsigned int id, rev; + int ret; + + /* Get PMU ID and verify that it matches compatible */ + ret = regmap_read(bcm590xx->regmap_pri, BCM590XX_REG_PMUID, &id); + if (ret) { + dev_err(bcm590xx->dev, "failed to read PMU ID: %d\n", ret); + return ret; + } + + if (id != bcm590xx->pmu_id) { + dev_err(bcm590xx->dev, "Incorrect ID for %s: expected %x, got %x.\n", + bcm590xx_names[bcm590xx->pmu_id], bcm590xx->pmu_id, id); + return -ENODEV; + } + + /* Get PMU revision and store it in the info struct */ + ret = regmap_read(bcm590xx->regmap_pri, BCM590XX_REG_PMUREV, &rev); + if (ret) { + dev_err(bcm590xx->dev, "failed to read PMU revision: %d\n", ret); + return ret; + } + + bcm590xx->rev_digital = (rev & BCM590XX_PMUREV_DIG_MASK) >> BCM590XX_PMUREV_DIG_SHIFT; + + bcm590xx->rev_analog = (rev & BCM590XX_PMUREV_ANA_MASK) >> BCM590XX_PMUREV_ANA_SHIFT; + + dev_dbg(bcm590xx->dev, "PMU ID 0x%x (%s), revision: digital %d, analog %d", + id, bcm590xx_names[id], bcm590xx->rev_digital, bcm590xx->rev_analog); + + return 0; +} + static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri) { struct bcm590xx *bcm590xx; @@ -50,6 +100,8 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri) bcm590xx->dev = &i2c_pri->dev; bcm590xx->i2c_pri = i2c_pri; + bcm590xx->pmu_id = (uintptr_t) of_device_get_match_data(bcm590xx->dev); + bcm590xx->regmap_pri = devm_regmap_init_i2c(i2c_pri, &bcm590xx_regmap_config_pri); if (IS_ERR(bcm590xx->regmap_pri)) { @@ -76,6 +128,10 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri) goto err; } + ret = bcm590xx_parse_version(bcm590xx); + if (ret) + goto err; + ret = devm_mfd_add_devices(&i2c_pri->dev, -1, bcm590xx_devs, ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL); if (ret < 0) { @@ -91,12 +147,20 @@ err: } static const struct of_device_id bcm590xx_of_match[] = { - { .compatible = "brcm,bcm59056" }, + { + .compatible = "brcm,bcm59054", + .data = (void *)BCM590XX_PMUID_BCM59054, + }, + { + .compatible = "brcm,bcm59056", + .data = (void *)BCM590XX_PMUID_BCM59056, + }, { } }; MODULE_DEVICE_TABLE(of, bcm590xx_of_match); static const struct i2c_device_id bcm590xx_i2c_id[] = { + { "bcm59054" }, { "bcm59056" }, { } }; diff --git a/drivers/mfd/bd9571mwv.c b/drivers/mfd/bd9571mwv.c index 819d09e4d100..db8c2963fb48 100644 --- a/drivers/mfd/bd9571mwv.c +++ b/drivers/mfd/bd9571mwv.c @@ -67,7 +67,7 @@ static const struct regmap_access_table bd9571mwv_volatile_table = { static const struct regmap_config bd9571mwv_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .rd_table = &bd9571mwv_readable_table, .wr_table = &bd9571mwv_writable_table, .volatile_table = &bd9571mwv_volatile_table, @@ -93,7 +93,7 @@ static const struct regmap_irq bd9571mwv_irqs[] = { BD9571MWV_INT_INTREQ_BKUP_TRG_INT), }; -static struct regmap_irq_chip bd9571mwv_irq_chip = { +static const struct regmap_irq_chip bd9571mwv_irq_chip = { .name = "bd9571mwv", .status_base = BD9571MWV_INT_INTREQ, .mask_base = BD9571MWV_INT_INTMASK, @@ -152,14 +152,14 @@ static const struct regmap_access_table bd9574mwf_volatile_table = { static const struct regmap_config bd9574mwf_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .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 = { +static const struct regmap_irq_chip bd9574mwf_irq_chip = { .name = "bd9574mwf", .status_base = BD9571MWV_INT_INTREQ, .mask_base = BD9571MWV_INT_INTMASK, @@ -268,7 +268,7 @@ static const struct of_device_id bd9571mwv_of_match_table[] = { MODULE_DEVICE_TABLE(of, bd9571mwv_of_match_table); static const struct i2c_device_id bd9571mwv_id_table[] = { - { "bd9571mwv", 0 }, + { "bd9571mwv" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, bd9571mwv_id_table); diff --git a/drivers/mfd/cgbc-core.c b/drivers/mfd/cgbc-core.c new file mode 100644 index 000000000000..4782ff1114a9 --- /dev/null +++ b/drivers/mfd/cgbc-core.c @@ -0,0 +1,428 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Congatec Board Controller core driver. + * + * The x86 Congatec modules have an embedded micro controller named Board + * Controller. This Board Controller has a Watchdog timer, some GPIOs, and two + * I2C busses. + * + * Copyright (C) 2024 Bootlin + * + * Author: Thomas Richard <thomas.richard@bootlin.com> + */ + +#include <linux/dmi.h> +#include <linux/iopoll.h> +#include <linux/mfd/cgbc.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/sysfs.h> + +#define CGBC_IO_SESSION_BASE 0x0E20 +#define CGBC_IO_SESSION_END 0x0E30 +#define CGBC_IO_CMD_BASE 0x0E00 +#define CGBC_IO_CMD_END 0x0E10 + +#define CGBC_MASK_STATUS (BIT(6) | BIT(7)) +#define CGBC_MASK_DATA_COUNT 0x1F +#define CGBC_MASK_ERROR_CODE 0x1F + +#define CGBC_STATUS_DATA_READY 0x00 +#define CGBC_STATUS_CMD_READY BIT(6) +#define CGBC_STATUS_ERROR (BIT(6) | BIT(7)) + +#define CGBC_SESSION_CMD 0x00 +#define CGBC_SESSION_CMD_IDLE 0x00 +#define CGBC_SESSION_CMD_REQUEST 0x01 +#define CGBC_SESSION_DATA 0x01 +#define CGBC_SESSION_STATUS 0x02 +#define CGBC_SESSION_STATUS_FREE 0x03 +#define CGBC_SESSION_ACCESS 0x04 +#define CGBC_SESSION_ACCESS_GAINED 0x00 + +#define CGBC_SESSION_VALID_MIN 0x02 +#define CGBC_SESSION_VALID_MAX 0xFE + +#define CGBC_CMD_STROBE 0x00 +#define CGBC_CMD_INDEX 0x02 +#define CGBC_CMD_INDEX_CBM_MAN8 0x00 +#define CGBC_CMD_INDEX_CBM_AUTO32 0x03 +#define CGBC_CMD_DATA 0x04 +#define CGBC_CMD_ACCESS 0x0C + +#define CGBC_CMD_GET_FW_REV 0x21 + +static struct platform_device *cgbc_pdev; + +/* Wait the Board Controller is ready to receive some session commands */ +static int cgbc_wait_device(struct cgbc_device_data *cgbc) +{ + u16 status; + int ret; + + ret = readx_poll_timeout(ioread16, cgbc->io_session + CGBC_SESSION_STATUS, status, + status == CGBC_SESSION_STATUS_FREE, 0, 500000); + + if (ret || ioread32(cgbc->io_session + CGBC_SESSION_ACCESS)) + ret = -ENODEV; + + return ret; +} + +static int cgbc_session_command(struct cgbc_device_data *cgbc, u8 cmd) +{ + int ret; + u8 val; + + ret = readx_poll_timeout(ioread8, cgbc->io_session + CGBC_SESSION_CMD, val, + val == CGBC_SESSION_CMD_IDLE, 0, 100000); + if (ret) + return ret; + + iowrite8(cmd, cgbc->io_session + CGBC_SESSION_CMD); + + ret = readx_poll_timeout(ioread8, cgbc->io_session + CGBC_SESSION_CMD, val, + val == CGBC_SESSION_CMD_IDLE, 0, 100000); + if (ret) + return ret; + + ret = (int)ioread8(cgbc->io_session + CGBC_SESSION_DATA); + + iowrite8(CGBC_SESSION_STATUS_FREE, cgbc->io_session + CGBC_SESSION_STATUS); + + return ret; +} + +static int cgbc_session_request(struct cgbc_device_data *cgbc) +{ + int ret; + + ret = cgbc_wait_device(cgbc); + + if (ret) + return dev_err_probe(cgbc->dev, ret, "device not found or not ready\n"); + + cgbc->session = cgbc_session_command(cgbc, CGBC_SESSION_CMD_REQUEST); + + /* The Board Controller sent us a wrong session handle, we cannot communicate with it */ + if (cgbc->session < CGBC_SESSION_VALID_MIN || cgbc->session > CGBC_SESSION_VALID_MAX) + return dev_err_probe(cgbc->dev, -ECONNREFUSED, + "failed to get a valid session handle\n"); + + return 0; +} + +static void cgbc_session_release(struct cgbc_device_data *cgbc) +{ + if (cgbc_session_command(cgbc, cgbc->session) != cgbc->session) + dev_warn(cgbc->dev, "failed to release session\n"); +} + +static bool cgbc_command_lock(struct cgbc_device_data *cgbc) +{ + iowrite8(cgbc->session, cgbc->io_cmd + CGBC_CMD_ACCESS); + + return ioread8(cgbc->io_cmd + CGBC_CMD_ACCESS) == cgbc->session; +} + +static void cgbc_command_unlock(struct cgbc_device_data *cgbc) +{ + iowrite8(cgbc->session, cgbc->io_cmd + CGBC_CMD_ACCESS); +} + +int cgbc_command(struct cgbc_device_data *cgbc, void *cmd, unsigned int cmd_size, void *data, + unsigned int data_size, u8 *status) +{ + u8 checksum = 0, data_checksum = 0, istatus = 0, val; + u8 *_data = (u8 *)data; + u8 *_cmd = (u8 *)cmd; + int mode_change = -1; + bool lock; + int ret, i; + + mutex_lock(&cgbc->lock); + + /* Request access */ + ret = readx_poll_timeout(cgbc_command_lock, cgbc, lock, lock, 0, 100000); + if (ret) + goto out; + + /* Wait board controller is ready */ + ret = readx_poll_timeout(ioread8, cgbc->io_cmd + CGBC_CMD_STROBE, val, + val == CGBC_CMD_STROBE, 0, 100000); + if (ret) + goto release; + + /* Write command packet */ + if (cmd_size <= 2) { + iowrite8(CGBC_CMD_INDEX_CBM_MAN8, cgbc->io_cmd + CGBC_CMD_INDEX); + } else { + iowrite8(CGBC_CMD_INDEX_CBM_AUTO32, cgbc->io_cmd + CGBC_CMD_INDEX); + if ((cmd_size % 4) != 0x03) + mode_change = (cmd_size & 0xFFFC) - 1; + } + + for (i = 0; i < cmd_size; i++) { + iowrite8(_cmd[i], cgbc->io_cmd + CGBC_CMD_DATA + (i % 4)); + checksum ^= _cmd[i]; + if (mode_change == i) + iowrite8((i + 1) | CGBC_CMD_INDEX_CBM_MAN8, cgbc->io_cmd + CGBC_CMD_INDEX); + } + + /* Append checksum byte */ + iowrite8(checksum, cgbc->io_cmd + CGBC_CMD_DATA + (i % 4)); + + /* Perform command strobe */ + iowrite8(cgbc->session, cgbc->io_cmd + CGBC_CMD_STROBE); + + /* Rewind cmd buffer index */ + iowrite8(CGBC_CMD_INDEX_CBM_AUTO32, cgbc->io_cmd + CGBC_CMD_INDEX); + + /* Wait command completion */ + ret = read_poll_timeout(ioread8, val, val == CGBC_CMD_STROBE, 0, 100000, false, + cgbc->io_cmd + CGBC_CMD_STROBE); + if (ret) + goto release; + + istatus = ioread8(cgbc->io_cmd + CGBC_CMD_DATA); + checksum = istatus; + + /* Check command status */ + switch (istatus & CGBC_MASK_STATUS) { + case CGBC_STATUS_DATA_READY: + if (istatus > data_size) + istatus = data_size; + for (i = 0; i < istatus; i++) { + _data[i] = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + ((i + 1) % 4)); + checksum ^= _data[i]; + } + data_checksum = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + ((i + 1) % 4)); + istatus &= CGBC_MASK_DATA_COUNT; + break; + case CGBC_STATUS_ERROR: + case CGBC_STATUS_CMD_READY: + data_checksum = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + 1); + if ((istatus & CGBC_MASK_STATUS) == CGBC_STATUS_ERROR) + ret = -EIO; + istatus = istatus & CGBC_MASK_ERROR_CODE; + break; + default: + data_checksum = ioread8(cgbc->io_cmd + CGBC_CMD_DATA + 1); + istatus &= CGBC_MASK_ERROR_CODE; + ret = -EIO; + break; + } + + /* Checksum verification */ + if (ret == 0 && data_checksum != checksum) + ret = -EIO; + +release: + cgbc_command_unlock(cgbc); + +out: + mutex_unlock(&cgbc->lock); + + if (status) + *status = istatus; + + return ret; +} +EXPORT_SYMBOL_GPL(cgbc_command); + +static struct mfd_cell cgbc_devs[] = { + { .name = "cgbc-wdt" }, + { .name = "cgbc-gpio" }, + { .name = "cgbc-i2c", .id = 1 }, + { .name = "cgbc-i2c", .id = 2 }, + { .name = "cgbc-hwmon" }, +}; + +static int cgbc_map(struct cgbc_device_data *cgbc) +{ + struct device *dev = cgbc->dev; + struct platform_device *pdev = to_platform_device(dev); + struct resource *ioport; + + ioport = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!ioport) + return -EINVAL; + + cgbc->io_session = devm_ioport_map(dev, ioport->start, resource_size(ioport)); + if (!cgbc->io_session) + return -ENOMEM; + + ioport = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (!ioport) + return -EINVAL; + + cgbc->io_cmd = devm_ioport_map(dev, ioport->start, resource_size(ioport)); + if (!cgbc->io_cmd) + return -ENOMEM; + + return 0; +} + +static const struct resource cgbc_resources[] = { + { + .start = CGBC_IO_SESSION_BASE, + .end = CGBC_IO_SESSION_END, + .flags = IORESOURCE_IO, + }, + { + .start = CGBC_IO_CMD_BASE, + .end = CGBC_IO_CMD_END, + .flags = IORESOURCE_IO, + }, +}; + +static ssize_t cgbc_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cgbc_device_data *cgbc = dev_get_drvdata(dev); + + return sysfs_emit(buf, "CGBCP%c%c%c\n", cgbc->version.feature, cgbc->version.major, + cgbc->version.minor); +} + +static DEVICE_ATTR_RO(cgbc_version); + +static struct attribute *cgbc_attrs[] = { + &dev_attr_cgbc_version.attr, + NULL +}; + +ATTRIBUTE_GROUPS(cgbc); + +static int cgbc_get_version(struct cgbc_device_data *cgbc) +{ + u8 cmd = CGBC_CMD_GET_FW_REV; + u8 data[4]; + int ret; + + ret = cgbc_command(cgbc, &cmd, 1, &data, sizeof(data), NULL); + if (ret) + return ret; + + cgbc->version.feature = data[0]; + cgbc->version.major = data[1]; + cgbc->version.minor = data[2]; + + return 0; +} + +static int cgbc_init_device(struct cgbc_device_data *cgbc) +{ + int ret; + + ret = cgbc_session_request(cgbc); + if (ret) + return ret; + + ret = cgbc_get_version(cgbc); + if (ret) + goto release_session; + + ret = mfd_add_devices(cgbc->dev, -1, cgbc_devs, ARRAY_SIZE(cgbc_devs), + NULL, 0, NULL); + if (ret) + goto release_session; + + return 0; + +release_session: + cgbc_session_release(cgbc); + return ret; +} + +static int cgbc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cgbc_device_data *cgbc; + int ret; + + cgbc = devm_kzalloc(dev, sizeof(*cgbc), GFP_KERNEL); + if (!cgbc) + return -ENOMEM; + + cgbc->dev = dev; + + ret = cgbc_map(cgbc); + if (ret) + return ret; + + mutex_init(&cgbc->lock); + + platform_set_drvdata(pdev, cgbc); + + return cgbc_init_device(cgbc); +} + +static void cgbc_remove(struct platform_device *pdev) +{ + struct cgbc_device_data *cgbc = platform_get_drvdata(pdev); + + cgbc_session_release(cgbc); + + mfd_remove_devices(&pdev->dev); +} + +static struct platform_driver cgbc_driver = { + .driver = { + .name = "cgbc", + .dev_groups = cgbc_groups, + }, + .probe = cgbc_probe, + .remove = cgbc_remove, +}; + +static const struct dmi_system_id cgbc_dmi_table[] __initconst = { + { + .ident = "SA7", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "congatec"), + DMI_MATCH(DMI_BOARD_NAME, "conga-SA7"), + }, + }, + { + .ident = "SA8", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "congatec"), + DMI_MATCH(DMI_BOARD_NAME, "conga-SA8"), + }, + }, + {} +}; +MODULE_DEVICE_TABLE(dmi, cgbc_dmi_table); + +static int __init cgbc_init(void) +{ + const struct dmi_system_id *id; + int ret = -ENODEV; + + id = dmi_first_match(cgbc_dmi_table); + if (IS_ERR_OR_NULL(id)) + return ret; + + cgbc_pdev = platform_device_register_simple("cgbc", PLATFORM_DEVID_NONE, cgbc_resources, + ARRAY_SIZE(cgbc_resources)); + if (IS_ERR(cgbc_pdev)) + return PTR_ERR(cgbc_pdev); + + return platform_driver_register(&cgbc_driver); +} + +static void __exit cgbc_exit(void) +{ + platform_device_unregister(cgbc_pdev); + platform_driver_unregister(&cgbc_driver); +} + +module_init(cgbc_init); +module_exit(cgbc_exit); + +MODULE_DESCRIPTION("Congatec Board Controller Core Driver"); +MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cgbc-core"); diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 603b1cd52785..9f84a52b48d6 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space + * ChromeOS Embedded Controller * * Copyright (C) 2014 Google, Inc. */ @@ -74,6 +74,10 @@ static const struct mfd_cell cros_ec_cec_cells[] = { { .name = "cros-ec-cec", }, }; +static const struct mfd_cell cros_ec_gpio_cells[] = { + { .name = "cros-ec-gpio", }, +}; + static const struct mfd_cell cros_ec_rtc_cells[] = { { .name = "cros-ec-rtc", }, }; @@ -83,6 +87,7 @@ static const struct mfd_cell cros_ec_sensorhub_cells[] = { }; static const struct mfd_cell cros_usbpd_charger_cells[] = { + { .name = "cros-charge-control", }, { .name = "cros-usbpd-charger", }, { .name = "cros-usbpd-logger", }, }; @@ -91,6 +96,22 @@ static const struct mfd_cell cros_usbpd_notify_cells[] = { { .name = "cros-usbpd-notify", }, }; +static const struct mfd_cell cros_ec_wdt_cells[] = { + { .name = "cros-ec-wdt", } +}; + +static const struct mfd_cell cros_ec_led_cells[] = { + { .name = "cros-ec-led", }, +}; + +static const struct mfd_cell cros_ec_keyboard_leds_cells[] = { + { .name = "cros-keyboard-leds", }, +}; + +static const struct mfd_cell cros_ec_ucsi_cells[] = { + { .name = "cros_ec_ucsi", }, +}; + static const struct cros_feature_to_cells cros_subdevices[] = { { .id = EC_FEATURE_CEC, @@ -98,20 +119,41 @@ static const struct cros_feature_to_cells cros_subdevices[] = { .num_cells = ARRAY_SIZE(cros_ec_cec_cells), }, { + .id = EC_FEATURE_GPIO, + .mfd_cells = cros_ec_gpio_cells, + .num_cells = ARRAY_SIZE(cros_ec_gpio_cells), + }, + { .id = EC_FEATURE_RTC, .mfd_cells = cros_ec_rtc_cells, .num_cells = ARRAY_SIZE(cros_ec_rtc_cells), }, { - .id = EC_FEATURE_USB_PD, - .mfd_cells = cros_usbpd_charger_cells, - .num_cells = ARRAY_SIZE(cros_usbpd_charger_cells), + .id = EC_FEATURE_UCSI_PPM, + .mfd_cells = cros_ec_ucsi_cells, + .num_cells = ARRAY_SIZE(cros_ec_ucsi_cells), + }, + { + .id = EC_FEATURE_HANG_DETECT, + .mfd_cells = cros_ec_wdt_cells, + .num_cells = ARRAY_SIZE(cros_ec_wdt_cells), + }, + { + .id = EC_FEATURE_LED, + .mfd_cells = cros_ec_led_cells, + .num_cells = ARRAY_SIZE(cros_ec_led_cells), + }, + { + .id = EC_FEATURE_PWM_KEYB, + .mfd_cells = cros_ec_keyboard_leds_cells, + .num_cells = ARRAY_SIZE(cros_ec_keyboard_leds_cells), }, }; static const struct mfd_cell cros_ec_platform_cells[] = { { .name = "cros-ec-chardev", }, { .name = "cros-ec-debugfs", }, + { .name = "cros-ec-hwmon", }, { .name = "cros-ec-sysfs", }, }; @@ -215,6 +257,21 @@ static int ec_device_probe(struct platform_device *pdev) } /* + * UCSI provides power supply information so we don't need to separately + * load the cros_usbpd_charger driver. + */ + if (cros_ec_check_features(ec, EC_FEATURE_USB_PD) && + !cros_ec_check_features(ec, EC_FEATURE_UCSI_PPM)) { + retval = mfd_add_hotplug_devices(ec->dev, + cros_usbpd_charger_cells, + ARRAY_SIZE(cros_usbpd_charger_cells)); + + if (retval) + dev_warn(ec->dev, "failed to add usbpd-charger: %d\n", + retval); + } + + /* * Lightbar is a special case. Newer devices support autodetection, * but older ones do not. */ @@ -308,29 +365,24 @@ static struct platform_driver cros_ec_dev_driver = { }, .id_table = cros_ec_id, .probe = ec_device_probe, - .remove_new = ec_device_remove, + .remove = ec_device_remove, }; static int __init cros_ec_dev_init(void) { int ret; - ret = class_register(&cros_class); + ret = class_register(&cros_class); if (ret) { pr_err(CROS_EC_DEV_NAME ": failed to register device class\n"); return ret; } - /* Register the driver */ ret = platform_driver_register(&cros_ec_dev_driver); - if (ret < 0) { + if (ret) { pr_warn(CROS_EC_DEV_NAME ": can't register driver: %d\n", ret); - goto failed_devreg; + class_unregister(&cros_class); } - return 0; - -failed_devreg: - class_unregister(&cros_class); return ret; } @@ -344,6 +396,6 @@ module_init(cros_ec_dev_init); module_exit(cros_ec_dev_exit); MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>"); -MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller"); +MODULE_DESCRIPTION("ChromeOS Embedded Controller"); MODULE_VERSION("1.0"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/cs40l50-core.c b/drivers/mfd/cs40l50-core.c new file mode 100644 index 000000000000..4859a33777a0 --- /dev/null +++ b/drivers/mfd/cs40l50-core.c @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CS40L50 Advanced Haptic Driver with waveform memory, + * integrated DSP, and closed-loop algorithms + * + * Copyright 2024 Cirrus Logic, Inc. + * + * Author: James Ogletree <james.ogletree@cirrus.com> + */ + +#include <linux/firmware/cirrus/cs_dsp.h> +#include <linux/firmware/cirrus/wmfw.h> +#include <linux/mfd/core.h> +#include <linux/mfd/cs40l50.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> + +static const struct mfd_cell cs40l50_devs[] = { + { .name = "cs40l50-codec", }, + { .name = "cs40l50-vibra", }, +}; + +const struct regmap_config cs40l50_regmap = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; +EXPORT_SYMBOL_GPL(cs40l50_regmap); + +static const char * const cs40l50_supplies[] = { + "vdd-io", +}; + +static const struct regmap_irq cs40l50_reg_irqs[] = { + REGMAP_IRQ_REG(CS40L50_DSP_QUEUE_IRQ, CS40L50_IRQ1_INT_2_OFFSET, + CS40L50_DSP_QUEUE_MASK), + REGMAP_IRQ_REG(CS40L50_AMP_SHORT_IRQ, CS40L50_IRQ1_INT_1_OFFSET, + CS40L50_AMP_SHORT_MASK), + REGMAP_IRQ_REG(CS40L50_TEMP_ERR_IRQ, CS40L50_IRQ1_INT_8_OFFSET, + CS40L50_TEMP_ERR_MASK), + REGMAP_IRQ_REG(CS40L50_BST_UVP_IRQ, CS40L50_IRQ1_INT_9_OFFSET, + CS40L50_BST_UVP_MASK), + REGMAP_IRQ_REG(CS40L50_BST_SHORT_IRQ, CS40L50_IRQ1_INT_9_OFFSET, + CS40L50_BST_SHORT_MASK), + REGMAP_IRQ_REG(CS40L50_BST_ILIMIT_IRQ, CS40L50_IRQ1_INT_9_OFFSET, + CS40L50_BST_ILIMIT_MASK), + REGMAP_IRQ_REG(CS40L50_UVLO_VDDBATT_IRQ, CS40L50_IRQ1_INT_10_OFFSET, + CS40L50_UVLO_VDDBATT_MASK), + REGMAP_IRQ_REG(CS40L50_GLOBAL_ERROR_IRQ, CS40L50_IRQ1_INT_18_OFFSET, + CS40L50_GLOBAL_ERROR_MASK), +}; + +static struct regmap_irq_chip cs40l50_irq_chip = { + .name = "cs40l50", + .status_base = CS40L50_IRQ1_INT_1, + .mask_base = CS40L50_IRQ1_MASK_1, + .ack_base = CS40L50_IRQ1_INT_1, + .num_regs = 22, + .irqs = cs40l50_reg_irqs, + .num_irqs = ARRAY_SIZE(cs40l50_reg_irqs), + .runtime_pm = true, +}; + +int cs40l50_dsp_write(struct device *dev, struct regmap *regmap, u32 val) +{ + int i, ret; + u32 ack; + + /* Device NAKs if hibernating, so optionally retry */ + for (i = 0; i < CS40L50_DSP_TIMEOUT_COUNT; i++) { + ret = regmap_write(regmap, CS40L50_DSP_QUEUE, val); + if (!ret) + break; + + usleep_range(CS40L50_DSP_POLL_US, CS40L50_DSP_POLL_US + 100); + } + + /* If the write never took place, no need to check for the ACK */ + if (i == CS40L50_DSP_TIMEOUT_COUNT) { + dev_err(dev, "Timed out writing %#X to DSP: %d\n", val, ret); + return ret; + } + + ret = regmap_read_poll_timeout(regmap, CS40L50_DSP_QUEUE, ack, !ack, + CS40L50_DSP_POLL_US, + CS40L50_DSP_POLL_US * CS40L50_DSP_TIMEOUT_COUNT); + if (ret) + dev_err(dev, "DSP failed to ACK %#X: %d\n", val, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(cs40l50_dsp_write); + +static const struct cs_dsp_region cs40l50_dsp_regions[] = { + { .type = WMFW_HALO_PM_PACKED, .base = CS40L50_PMEM_0 }, + { .type = WMFW_HALO_XM_PACKED, .base = CS40L50_XMEM_PACKED_0 }, + { .type = WMFW_HALO_YM_PACKED, .base = CS40L50_YMEM_PACKED_0 }, + { .type = WMFW_ADSP2_XM, .base = CS40L50_XMEM_UNPACKED24_0 }, + { .type = WMFW_ADSP2_YM, .base = CS40L50_YMEM_UNPACKED24_0 }, +}; + +static const struct reg_sequence cs40l50_internal_vamp_config[] = { + { CS40L50_BST_LPMODE_SEL, CS40L50_DCM_LOW_POWER }, + { CS40L50_BLOCK_ENABLES2, CS40L50_OVERTEMP_WARN }, +}; + +static const struct reg_sequence cs40l50_irq_mask_override[] = { + { CS40L50_IRQ1_MASK_2, CS40L50_IRQ_MASK_2_OVERRIDE }, + { CS40L50_IRQ1_MASK_20, CS40L50_IRQ_MASK_20_OVERRIDE }, +}; + +static int cs40l50_wseq_init(struct cs40l50 *cs40l50) +{ + struct cs_dsp *dsp = &cs40l50->dsp; + + cs40l50->wseqs[CS40L50_STANDBY].ctl = cs_dsp_get_ctl(dsp, "STANDBY_SEQUENCE", + WMFW_ADSP2_XM, + CS40L50_PM_ALGO); + if (!cs40l50->wseqs[CS40L50_STANDBY].ctl) { + dev_err(cs40l50->dev, "Control not found for standby sequence\n"); + return -ENOENT; + } + + cs40l50->wseqs[CS40L50_ACTIVE].ctl = cs_dsp_get_ctl(dsp, "ACTIVE_SEQUENCE", + WMFW_ADSP2_XM, + CS40L50_PM_ALGO); + if (!cs40l50->wseqs[CS40L50_ACTIVE].ctl) { + dev_err(cs40l50->dev, "Control not found for active sequence\n"); + return -ENOENT; + } + + cs40l50->wseqs[CS40L50_PWR_ON].ctl = cs_dsp_get_ctl(dsp, "PM_PWR_ON_SEQ", + WMFW_ADSP2_XM, + CS40L50_PM_ALGO); + if (!cs40l50->wseqs[CS40L50_PWR_ON].ctl) { + dev_err(cs40l50->dev, "Control not found for power-on sequence\n"); + return -ENOENT; + } + + return cs_dsp_wseq_init(&cs40l50->dsp, cs40l50->wseqs, ARRAY_SIZE(cs40l50->wseqs)); +} + +static int cs40l50_dsp_config(struct cs40l50 *cs40l50) +{ + int ret; + + /* Configure internal V_AMP supply */ + ret = regmap_multi_reg_write(cs40l50->regmap, cs40l50_internal_vamp_config, + ARRAY_SIZE(cs40l50_internal_vamp_config)); + if (ret) + return ret; + + ret = cs_dsp_wseq_multi_write(&cs40l50->dsp, &cs40l50->wseqs[CS40L50_PWR_ON], + cs40l50_internal_vamp_config, CS_DSP_WSEQ_FULL, + ARRAY_SIZE(cs40l50_internal_vamp_config), false); + if (ret) + return ret; + + /* Override firmware defaults for IRQ masks */ + ret = regmap_multi_reg_write(cs40l50->regmap, cs40l50_irq_mask_override, + ARRAY_SIZE(cs40l50_irq_mask_override)); + if (ret) + return ret; + + return cs_dsp_wseq_multi_write(&cs40l50->dsp, &cs40l50->wseqs[CS40L50_PWR_ON], + cs40l50_irq_mask_override, CS_DSP_WSEQ_FULL, + ARRAY_SIZE(cs40l50_irq_mask_override), false); +} + +static int cs40l50_dsp_post_run(struct cs_dsp *dsp) +{ + struct cs40l50 *cs40l50 = container_of(dsp, struct cs40l50, dsp); + int ret; + + ret = cs40l50_wseq_init(cs40l50); + if (ret) + return ret; + + ret = cs40l50_dsp_config(cs40l50); + if (ret) { + dev_err(cs40l50->dev, "Failed to configure DSP: %d\n", ret); + return ret; + } + + ret = devm_mfd_add_devices(cs40l50->dev, PLATFORM_DEVID_NONE, cs40l50_devs, + ARRAY_SIZE(cs40l50_devs), NULL, 0, NULL); + if (ret) + dev_err(cs40l50->dev, "Failed to add child devices: %d\n", ret); + + return ret; +} + +static const struct cs_dsp_client_ops client_ops = { + .post_run = cs40l50_dsp_post_run, +}; + +static void cs40l50_dsp_remove(void *data) +{ + cs_dsp_remove(data); +} + +static int cs40l50_dsp_init(struct cs40l50 *cs40l50) +{ + int ret; + + cs40l50->dsp.num = 1; + cs40l50->dsp.type = WMFW_HALO; + cs40l50->dsp.dev = cs40l50->dev; + cs40l50->dsp.regmap = cs40l50->regmap; + cs40l50->dsp.base = CS40L50_CORE_BASE; + cs40l50->dsp.base_sysinfo = CS40L50_SYS_INFO_ID; + cs40l50->dsp.mem = cs40l50_dsp_regions; + cs40l50->dsp.num_mems = ARRAY_SIZE(cs40l50_dsp_regions); + cs40l50->dsp.no_core_startstop = true; + cs40l50->dsp.client_ops = &client_ops; + + ret = cs_dsp_halo_init(&cs40l50->dsp); + if (ret) + return ret; + + return devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_remove, + &cs40l50->dsp); +} + +static int cs40l50_reset_dsp(struct cs40l50 *cs40l50) +{ + int ret; + + mutex_lock(&cs40l50->lock); + + if (cs40l50->dsp.running) + cs_dsp_stop(&cs40l50->dsp); + + if (cs40l50->dsp.booted) + cs_dsp_power_down(&cs40l50->dsp); + + ret = cs40l50_dsp_write(cs40l50->dev, cs40l50->regmap, CS40L50_SHUTDOWN); + if (ret) + goto err_mutex; + + ret = cs_dsp_power_up(&cs40l50->dsp, cs40l50->fw, "cs40l50.wmfw", + cs40l50->bin, "cs40l50.bin", "cs40l50"); + if (ret) + goto err_mutex; + + ret = cs40l50_dsp_write(cs40l50->dev, cs40l50->regmap, CS40L50_SYSTEM_RESET); + if (ret) + goto err_mutex; + + ret = cs40l50_dsp_write(cs40l50->dev, cs40l50->regmap, CS40L50_PREVENT_HIBER); + if (ret) + goto err_mutex; + + ret = cs_dsp_run(&cs40l50->dsp); +err_mutex: + mutex_unlock(&cs40l50->lock); + + return ret; +} + +static void cs40l50_dsp_power_down(void *data) +{ + cs_dsp_power_down(data); +} + +static void cs40l50_dsp_stop(void *data) +{ + cs_dsp_stop(data); +} + +static void cs40l50_dsp_bringup(const struct firmware *bin, void *context) +{ + struct cs40l50 *cs40l50 = context; + u32 nwaves; + int ret; + + /* Wavetable is optional; bringup DSP regardless */ + cs40l50->bin = bin; + + ret = cs40l50_reset_dsp(cs40l50); + if (ret) { + dev_err(cs40l50->dev, "Failed to reset DSP: %d\n", ret); + goto err_fw; + } + + ret = regmap_read(cs40l50->regmap, CS40L50_NUM_WAVES, &nwaves); + if (ret) + goto err_fw; + + dev_info(cs40l50->dev, "%u RAM effects loaded\n", nwaves); + + /* Add teardown actions for first-time bringup */ + ret = devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_power_down, + &cs40l50->dsp); + if (ret) { + dev_err(cs40l50->dev, "Failed to add power down action: %d\n", ret); + goto err_fw; + } + + ret = devm_add_action_or_reset(cs40l50->dev, cs40l50_dsp_stop, &cs40l50->dsp); + if (ret) + dev_err(cs40l50->dev, "Failed to add stop action: %d\n", ret); +err_fw: + release_firmware(cs40l50->bin); + release_firmware(cs40l50->fw); +} + +static void cs40l50_request_firmware(const struct firmware *fw, void *context) +{ + struct cs40l50 *cs40l50 = context; + int ret; + + if (!fw) { + dev_err(cs40l50->dev, "No firmware file found\n"); + return; + } + + cs40l50->fw = fw; + + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, CS40L50_WT, + cs40l50->dev, GFP_KERNEL, cs40l50, + cs40l50_dsp_bringup); + if (ret) { + dev_err(cs40l50->dev, "Failed to request %s: %d\n", CS40L50_WT, ret); + release_firmware(cs40l50->fw); + } +} + +struct cs40l50_irq { + const char *name; + int virq; +}; + +static struct cs40l50_irq cs40l50_irqs[] = { + { "DSP", }, + { "Global", }, + { "Boost UVLO", }, + { "Boost current limit", }, + { "Boost short", }, + { "Boost undervolt", }, + { "Overtemp", }, + { "Amp short", }, +}; + +static const struct reg_sequence cs40l50_err_rls[] = { + { CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_SET }, + { CS40L50_ERR_RLS, CS40L50_GLOBAL_ERR_RLS_CLEAR }, +}; + +static irqreturn_t cs40l50_hw_err(int irq, void *data) +{ + struct cs40l50 *cs40l50 = data; + int ret = 0, i; + + mutex_lock(&cs40l50->lock); + + /* Log hardware interrupt and execute error release sequence */ + for (i = 1; i < ARRAY_SIZE(cs40l50_irqs); i++) { + if (cs40l50_irqs[i].virq == irq) { + dev_err(cs40l50->dev, "%s error\n", cs40l50_irqs[i].name); + ret = regmap_multi_reg_write(cs40l50->regmap, cs40l50_err_rls, + ARRAY_SIZE(cs40l50_err_rls)); + break; + } + } + + mutex_unlock(&cs40l50->lock); + return IRQ_RETVAL(!ret); +} + +static irqreturn_t cs40l50_dsp_queue(int irq, void *data) +{ + struct cs40l50 *cs40l50 = data; + u32 rd_ptr, val, wt_ptr; + int ret = 0; + + mutex_lock(&cs40l50->lock); + + /* Read from DSP queue, log, and update read pointer */ + while (!ret) { + ret = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_WT, &wt_ptr); + if (ret) + break; + + ret = regmap_read(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, &rd_ptr); + if (ret) + break; + + /* Check if queue is empty */ + if (wt_ptr == rd_ptr) + break; + + ret = regmap_read(cs40l50->regmap, rd_ptr, &val); + if (ret) + break; + + dev_dbg(cs40l50->dev, "DSP payload: %#X", val); + + rd_ptr += sizeof(u32); + + if (rd_ptr > CS40L50_DSP_QUEUE_END) + rd_ptr = CS40L50_DSP_QUEUE_BASE; + + ret = regmap_write(cs40l50->regmap, CS40L50_DSP_QUEUE_RD, rd_ptr); + } + + mutex_unlock(&cs40l50->lock); + + return IRQ_RETVAL(!ret); +} + +static int cs40l50_irq_init(struct cs40l50 *cs40l50) +{ + int ret, i, virq; + + ret = devm_regmap_add_irq_chip(cs40l50->dev, cs40l50->regmap, cs40l50->irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &cs40l50_irq_chip, &cs40l50->irq_data); + if (ret) { + dev_err(cs40l50->dev, "Failed adding IRQ chip\n"); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(cs40l50_irqs); i++) { + virq = regmap_irq_get_virq(cs40l50->irq_data, i); + if (virq < 0) { + dev_err(cs40l50->dev, "Failed getting virq for %s\n", + cs40l50_irqs[i].name); + return virq; + } + + cs40l50_irqs[i].virq = virq; + + /* Handle DSP and hardware interrupts separately */ + ret = devm_request_threaded_irq(cs40l50->dev, virq, NULL, + i ? cs40l50_hw_err : cs40l50_dsp_queue, + IRQF_ONESHOT | IRQF_SHARED, + cs40l50_irqs[i].name, cs40l50); + if (ret) { + return dev_err_probe(cs40l50->dev, ret, + "Failed requesting %s IRQ\n", + cs40l50_irqs[i].name); + } + } + + return 0; +} + +static int cs40l50_get_model(struct cs40l50 *cs40l50) +{ + int ret; + + ret = regmap_read(cs40l50->regmap, CS40L50_DEVID, &cs40l50->devid); + if (ret) + return ret; + + if (cs40l50->devid != CS40L50_DEVID_A) + return -EINVAL; + + ret = regmap_read(cs40l50->regmap, CS40L50_REVID, &cs40l50->revid); + if (ret) + return ret; + + if (cs40l50->revid < CS40L50_REVID_B0) + return -EINVAL; + + dev_dbg(cs40l50->dev, "Cirrus Logic CS40L50 rev. %02X\n", cs40l50->revid); + + return 0; +} + +static int cs40l50_pm_runtime_setup(struct device *dev) +{ + int ret; + + pm_runtime_set_autosuspend_delay(dev, CS40L50_AUTOSUSPEND_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_get_noresume(dev); + ret = pm_runtime_set_active(dev); + if (ret) + return ret; + + return devm_pm_runtime_enable(dev); +} + +int cs40l50_probe(struct cs40l50 *cs40l50) +{ + struct device *dev = cs40l50->dev; + int ret; + + mutex_init(&cs40l50->lock); + + cs40l50->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(cs40l50->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(cs40l50->reset_gpio), + "Failed getting reset GPIO\n"); + + ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(cs40l50_supplies), + cs40l50_supplies); + if (ret) + return dev_err_probe(dev, ret, "Failed getting supplies\n"); + + /* Ensure minimum reset pulse width */ + usleep_range(CS40L50_RESET_PULSE_US, CS40L50_RESET_PULSE_US + 100); + + gpiod_set_value_cansleep(cs40l50->reset_gpio, 0); + + /* Wait for control port to be ready */ + usleep_range(CS40L50_CP_READY_US, CS40L50_CP_READY_US + 100); + + ret = cs40l50_get_model(cs40l50); + if (ret) + return dev_err_probe(dev, ret, "Failed to get part number\n"); + + ret = cs40l50_dsp_init(cs40l50); + if (ret) + return dev_err_probe(dev, ret, "Failed to initialize DSP\n"); + + ret = cs40l50_pm_runtime_setup(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to initialize runtime PM\n"); + + ret = cs40l50_irq_init(cs40l50); + if (ret) + return ret; + + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, CS40L50_FW, + dev, GFP_KERNEL, cs40l50, cs40l50_request_firmware); + if (ret) + return dev_err_probe(dev, ret, "Failed to request %s\n", CS40L50_FW); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(cs40l50_probe); + +int cs40l50_remove(struct cs40l50 *cs40l50) +{ + gpiod_set_value_cansleep(cs40l50->reset_gpio, 1); + + return 0; +} +EXPORT_SYMBOL_GPL(cs40l50_remove); + +static int cs40l50_runtime_suspend(struct device *dev) +{ + struct cs40l50 *cs40l50 = dev_get_drvdata(dev); + + return regmap_write(cs40l50->regmap, CS40L50_DSP_QUEUE, CS40L50_ALLOW_HIBER); +} + +static int cs40l50_runtime_resume(struct device *dev) +{ + struct cs40l50 *cs40l50 = dev_get_drvdata(dev); + + return cs40l50_dsp_write(dev, cs40l50->regmap, CS40L50_PREVENT_HIBER); +} + +EXPORT_GPL_DEV_PM_OPS(cs40l50_pm_ops) = { + RUNTIME_PM_OPS(cs40l50_runtime_suspend, cs40l50_runtime_resume, NULL) +}; + +MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver"); +MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("FW_CS_DSP"); diff --git a/drivers/mfd/cs40l50-i2c.c b/drivers/mfd/cs40l50-i2c.c new file mode 100644 index 000000000000..639be743d956 --- /dev/null +++ b/drivers/mfd/cs40l50-i2c.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CS40L50 Advanced Haptic Driver with waveform memory, + * integrated DSP, and closed-loop algorithms + * + * Copyright 2024 Cirrus Logic, Inc. + * + * Author: James Ogletree <james.ogletree@cirrus.com> + */ + +#include <linux/i2c.h> +#include <linux/mfd/cs40l50.h> + +static int cs40l50_i2c_probe(struct i2c_client *i2c) +{ + struct cs40l50 *cs40l50; + + cs40l50 = devm_kzalloc(&i2c->dev, sizeof(*cs40l50), GFP_KERNEL); + if (!cs40l50) + return -ENOMEM; + + i2c_set_clientdata(i2c, cs40l50); + + cs40l50->dev = &i2c->dev; + cs40l50->irq = i2c->irq; + + cs40l50->regmap = devm_regmap_init_i2c(i2c, &cs40l50_regmap); + if (IS_ERR(cs40l50->regmap)) + return dev_err_probe(cs40l50->dev, PTR_ERR(cs40l50->regmap), + "Failed to initialize register map\n"); + + return cs40l50_probe(cs40l50); +} + +static void cs40l50_i2c_remove(struct i2c_client *i2c) +{ + struct cs40l50 *cs40l50 = i2c_get_clientdata(i2c); + + cs40l50_remove(cs40l50); +} + +static const struct i2c_device_id cs40l50_id_i2c[] = { + { "cs40l50" }, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs40l50_id_i2c); + +static const struct of_device_id cs40l50_of_match[] = { + { .compatible = "cirrus,cs40l50" }, + {} +}; +MODULE_DEVICE_TABLE(of, cs40l50_of_match); + +static struct i2c_driver cs40l50_i2c_driver = { + .driver = { + .name = "cs40l50", + .of_match_table = cs40l50_of_match, + .pm = pm_ptr(&cs40l50_pm_ops), + }, + .id_table = cs40l50_id_i2c, + .probe = cs40l50_i2c_probe, + .remove = cs40l50_i2c_remove, +}; +module_i2c_driver(cs40l50_i2c_driver); + +MODULE_DESCRIPTION("CS40L50 I2C Driver"); +MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/cs40l50-spi.c b/drivers/mfd/cs40l50-spi.c new file mode 100644 index 000000000000..53526b595a0d --- /dev/null +++ b/drivers/mfd/cs40l50-spi.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * CS40L50 Advanced Haptic Driver with waveform memory, + * integrated DSP, and closed-loop algorithms + * + * Copyright 2024 Cirrus Logic, Inc. + * + * Author: James Ogletree <james.ogletree@cirrus.com> + */ + +#include <linux/mfd/cs40l50.h> +#include <linux/spi/spi.h> + +static int cs40l50_spi_probe(struct spi_device *spi) +{ + struct cs40l50 *cs40l50; + + cs40l50 = devm_kzalloc(&spi->dev, sizeof(*cs40l50), GFP_KERNEL); + if (!cs40l50) + return -ENOMEM; + + spi_set_drvdata(spi, cs40l50); + + cs40l50->dev = &spi->dev; + cs40l50->irq = spi->irq; + + cs40l50->regmap = devm_regmap_init_spi(spi, &cs40l50_regmap); + if (IS_ERR(cs40l50->regmap)) + return dev_err_probe(cs40l50->dev, PTR_ERR(cs40l50->regmap), + "Failed to initialize register map\n"); + + return cs40l50_probe(cs40l50); +} + +static void cs40l50_spi_remove(struct spi_device *spi) +{ + struct cs40l50 *cs40l50 = spi_get_drvdata(spi); + + cs40l50_remove(cs40l50); +} + +static const struct spi_device_id cs40l50_id_spi[] = { + { "cs40l50" }, + {} +}; +MODULE_DEVICE_TABLE(spi, cs40l50_id_spi); + +static const struct of_device_id cs40l50_of_match[] = { + { .compatible = "cirrus,cs40l50" }, + {} +}; +MODULE_DEVICE_TABLE(of, cs40l50_of_match); + +static struct spi_driver cs40l50_spi_driver = { + .driver = { + .name = "cs40l50", + .of_match_table = cs40l50_of_match, + .pm = pm_ptr(&cs40l50_pm_ops), + }, + .id_table = cs40l50_id_spi, + .probe = cs40l50_spi_probe, + .remove = cs40l50_spi_remove, +}; +module_spi_driver(cs40l50_spi_driver); + +MODULE_DESCRIPTION("CS40L50 SPI Driver"); +MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c index 4922211680c9..a2ab001a600a 100644 --- a/drivers/mfd/cs42l43-i2c.c +++ b/drivers/mfd/cs42l43-i2c.c @@ -6,11 +6,15 @@ * Cirrus Logic International Semiconductor Ltd. */ +#include <linux/array_size.h> #include <linux/err.h> -#include <linux/errno.h> #include <linux/i2c.h> +#include <linux/mfd/cs42l43.h> #include <linux/mfd/cs42l43-regs.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pm.h> +#include <linux/regmap.h> #include "cs42l43.h" @@ -34,7 +38,6 @@ static const struct regmap_config cs42l43_i2c_regmap = { static int cs42l43_i2c_probe(struct i2c_client *i2c) { struct cs42l43 *cs42l43; - int ret; cs42l43 = devm_kzalloc(&i2c->dev, sizeof(*cs42l43), GFP_KERNEL); if (!cs42l43) @@ -46,22 +49,13 @@ static int cs42l43_i2c_probe(struct i2c_client *i2c) cs42l43->attached = true; cs42l43->regmap = devm_regmap_init_i2c(i2c, &cs42l43_i2c_regmap); - if (IS_ERR(cs42l43->regmap)) { - ret = PTR_ERR(cs42l43->regmap); - dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret); - return ret; - } + if (IS_ERR(cs42l43->regmap)) + return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->regmap), + "Failed to allocate regmap\n"); return cs42l43_dev_probe(cs42l43); } -static void cs42l43_i2c_remove(struct i2c_client *i2c) -{ - struct cs42l43 *cs42l43 = dev_get_drvdata(&i2c->dev); - - cs42l43_dev_remove(cs42l43); -} - #if IS_ENABLED(CONFIG_OF) static const struct of_device_id cs42l43_of_match[] = { { .compatible = "cirrus,cs42l43", }, @@ -87,11 +81,10 @@ static struct i2c_driver cs42l43_i2c_driver = { }, .probe = cs42l43_i2c_probe, - .remove = cs42l43_i2c_remove, }; module_i2c_driver(cs42l43_i2c_driver); -MODULE_IMPORT_NS(MFD_CS42L43); +MODULE_IMPORT_NS("MFD_CS42L43"); MODULE_DESCRIPTION("CS42L43 I2C Driver"); MODULE_AUTHOR("Charles Keepax <ckeepax@opensource.cirrus.com>"); diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c index 1d85bbf8cdd5..023f7e1a30f8 100644 --- a/drivers/mfd/cs42l43-sdw.c +++ b/drivers/mfd/cs42l43-sdw.c @@ -6,11 +6,15 @@ * Cirrus Logic International Semiconductor Ltd. */ +#include <linux/array_size.h> #include <linux/device.h> #include <linux/err.h> -#include <linux/errno.h> +#include <linux/mfd/cs42l43.h> #include <linux/mfd/cs42l43-regs.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/pm.h> +#include <linux/regmap.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_registers.h> #include <linux/soundwire/sdw_type.h> @@ -167,7 +171,6 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id * { struct cs42l43 *cs42l43; struct device *dev = &sdw->dev; - int ret; cs42l43 = devm_kzalloc(dev, sizeof(*cs42l43), GFP_KERNEL); if (!cs42l43) @@ -177,24 +180,13 @@ static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id * cs42l43->sdw = sdw; cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap); - if (IS_ERR(cs42l43->regmap)) { - ret = PTR_ERR(cs42l43->regmap); - dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret); - return ret; - } + if (IS_ERR(cs42l43->regmap)) + return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->regmap), + "Failed to allocate regmap\n"); return cs42l43_dev_probe(cs42l43); } -static int cs42l43_sdw_remove(struct sdw_slave *sdw) -{ - struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); - - cs42l43_dev_remove(cs42l43); - - return 0; -} - static const struct sdw_device_id cs42l43_sdw_id[] = { SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0), {} @@ -208,13 +200,12 @@ static struct sdw_driver cs42l43_sdw_driver = { }, .probe = cs42l43_sdw_probe, - .remove = cs42l43_sdw_remove, .id_table = cs42l43_sdw_id, .ops = &cs42l43_sdw_ops, }; module_sdw_driver(cs42l43_sdw_driver); -MODULE_IMPORT_NS(MFD_CS42L43); +MODULE_IMPORT_NS("MFD_CS42L43"); MODULE_DESCRIPTION("CS42L43 SoundWire Driver"); MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>"); diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c index 7b6d07cbe6fc..103787f37443 100644 --- a/drivers/mfd/cs42l43.c +++ b/drivers/mfd/cs42l43.c @@ -6,51 +6,61 @@ * Cirrus Logic International Semiconductor Ltd. */ +#include <linux/array_size.h> #include <linux/bitops.h> #include <linux/build_bug.h> #include <linux/delay.h> +#include <linux/device.h> #include <linux/err.h> -#include <linux/errno.h> #include <linux/firmware.h> +#include <linux/gpio/consumer.h> #include <linux/jiffies.h> #include <linux/mfd/core.h> +#include <linux/mfd/cs42l43.h> #include <linux/mfd/cs42l43-regs.h> #include <linux/module.h> +#include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/regmap.h> #include <linux/soundwire/sdw.h> +#include <linux/types.h> #include "cs42l43.h" -#define CS42L43_RESET_DELAY 20 +#define CS42L43_RESET_DELAY_MS 20 -#define CS42L43_SDW_ATTACH_TIMEOUT 500 -#define CS42L43_SDW_DETACH_TIMEOUT 100 +#define CS42L43_SDW_ATTACH_TIMEOUT_MS 5000 +#define CS42L43_SDW_DETACH_TIMEOUT_MS 100 #define CS42L43_MCU_BOOT_STAGE1 1 #define CS42L43_MCU_BOOT_STAGE2 2 #define CS42L43_MCU_BOOT_STAGE3 3 #define CS42L43_MCU_BOOT_STAGE4 4 -#define CS42L43_MCU_POLL 5000 -#define CS42L43_MCU_CMD_TIMEOUT 20000 +#define CS42L43_MCU_POLL_US 5000 +#define CS42L43_MCU_CMD_TIMEOUT_US 20000 #define CS42L43_MCU_UPDATE_FORMAT 3 #define CS42L43_MCU_UPDATE_OFFSET 0x100000 -#define CS42L43_MCU_UPDATE_TIMEOUT 500000 +#define CS42L43_MCU_UPDATE_TIMEOUT_US 500000 #define CS42L43_MCU_UPDATE_RETRIES 5 +#define CS42L43_MCU_ROM_REV 0x2001 +#define CS42L43_MCU_ROM_BIOS_REV 0x0000 + #define CS42L43_MCU_SUPPORTED_REV 0x2105 #define CS42L43_MCU_SHADOW_REGS_REQUIRED_REV 0x2200 +#define CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV 0x1002 #define CS42L43_MCU_SUPPORTED_BIOS_REV 0x0001 -#define CS42L43_VDDP_DELAY 50 -#define CS42L43_VDDD_DELAY 1000 +#define CS42L43_VDDP_DELAY_US 50 +#define CS42L43_VDDD_DELAY_US 1000 -#define CS42L43_AUTOSUSPEND_TIME 250 +#define CS42L43_AUTOSUSPEND_TIME_MS 250 struct cs42l43_patch_header { __le16 version; __le16 size; - u8 reserved; - u8 secure; + __u8 reserved; + __u8 secure; __le16 bss_size; __le32 apply_addr; __le32 checksum; @@ -84,7 +94,7 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { { CS42L43_DRV_CTRL_5, 0x136C00C0 }, { CS42L43_GPIO_CTRL1, 0x00000707 }, { CS42L43_GPIO_CTRL2, 0x00000000 }, - { CS42L43_GPIO_FN_SEL, 0x00000000 }, + { CS42L43_GPIO_FN_SEL, 0x00000004 }, { CS42L43_MCLK_SRC_SEL, 0x00000000 }, { CS42L43_SAMPLE_RATE1, 0x00000003 }, { CS42L43_SAMPLE_RATE2, 0x00000003 }, @@ -131,38 +141,38 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { { CS42L43_ASP_TX_CH4_CTRL, 0x00170091 }, { CS42L43_ASP_TX_CH5_CTRL, 0x001700C1 }, { CS42L43_ASP_TX_CH6_CTRL, 0x001700F1 }, - { CS42L43_ASPTX1_INPUT, 0x00800000 }, - { CS42L43_ASPTX2_INPUT, 0x00800000 }, - { CS42L43_ASPTX3_INPUT, 0x00800000 }, - { CS42L43_ASPTX4_INPUT, 0x00800000 }, - { CS42L43_ASPTX5_INPUT, 0x00800000 }, - { CS42L43_ASPTX6_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP1_CH1_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP1_CH2_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP1_CH3_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP1_CH4_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP2_CH1_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP2_CH2_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP3_CH1_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP3_CH2_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP4_CH1_INPUT, 0x00800000 }, - { CS42L43_SWIRE_DP4_CH2_INPUT, 0x00800000 }, - { CS42L43_ASRC_INT1_INPUT1, 0x00800000 }, - { CS42L43_ASRC_INT2_INPUT1, 0x00800000 }, - { CS42L43_ASRC_INT3_INPUT1, 0x00800000 }, - { CS42L43_ASRC_INT4_INPUT1, 0x00800000 }, - { CS42L43_ASRC_DEC1_INPUT1, 0x00800000 }, - { CS42L43_ASRC_DEC2_INPUT1, 0x00800000 }, - { CS42L43_ASRC_DEC3_INPUT1, 0x00800000 }, - { CS42L43_ASRC_DEC4_INPUT1, 0x00800000 }, - { CS42L43_ISRC1INT1_INPUT1, 0x00800000 }, - { CS42L43_ISRC1INT2_INPUT1, 0x00800000 }, - { CS42L43_ISRC1DEC1_INPUT1, 0x00800000 }, - { CS42L43_ISRC1DEC2_INPUT1, 0x00800000 }, - { CS42L43_ISRC2INT1_INPUT1, 0x00800000 }, - { CS42L43_ISRC2INT2_INPUT1, 0x00800000 }, - { CS42L43_ISRC2DEC1_INPUT1, 0x00800000 }, - { CS42L43_ISRC2DEC2_INPUT1, 0x00800000 }, + { CS42L43_ASPTX1_INPUT, 0x00000000 }, + { CS42L43_ASPTX2_INPUT, 0x00000000 }, + { CS42L43_ASPTX3_INPUT, 0x00000000 }, + { CS42L43_ASPTX4_INPUT, 0x00000000 }, + { CS42L43_ASPTX5_INPUT, 0x00000000 }, + { CS42L43_ASPTX6_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP1_CH1_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP1_CH2_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP1_CH3_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP1_CH4_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP2_CH1_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP2_CH2_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP3_CH1_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP3_CH2_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP4_CH1_INPUT, 0x00000000 }, + { CS42L43_SWIRE_DP4_CH2_INPUT, 0x00000000 }, + { CS42L43_ASRC_INT1_INPUT1, 0x00000000 }, + { CS42L43_ASRC_INT2_INPUT1, 0x00000000 }, + { CS42L43_ASRC_INT3_INPUT1, 0x00000000 }, + { CS42L43_ASRC_INT4_INPUT1, 0x00000000 }, + { CS42L43_ASRC_DEC1_INPUT1, 0x00000000 }, + { CS42L43_ASRC_DEC2_INPUT1, 0x00000000 }, + { CS42L43_ASRC_DEC3_INPUT1, 0x00000000 }, + { CS42L43_ASRC_DEC4_INPUT1, 0x00000000 }, + { CS42L43_ISRC1INT1_INPUT1, 0x00000000 }, + { CS42L43_ISRC1INT2_INPUT1, 0x00000000 }, + { CS42L43_ISRC1DEC1_INPUT1, 0x00000000 }, + { CS42L43_ISRC1DEC2_INPUT1, 0x00000000 }, + { CS42L43_ISRC2INT1_INPUT1, 0x00000000 }, + { CS42L43_ISRC2INT2_INPUT1, 0x00000000 }, + { CS42L43_ISRC2DEC1_INPUT1, 0x00000000 }, + { CS42L43_ISRC2DEC2_INPUT1, 0x00000000 }, { CS42L43_EQ1MIX_INPUT1, 0x00800000 }, { CS42L43_EQ1MIX_INPUT2, 0x00800000 }, { CS42L43_EQ1MIX_INPUT3, 0x00800000 }, @@ -171,8 +181,8 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { { CS42L43_EQ2MIX_INPUT2, 0x00800000 }, { CS42L43_EQ2MIX_INPUT3, 0x00800000 }, { CS42L43_EQ2MIX_INPUT4, 0x00800000 }, - { CS42L43_SPDIF1_INPUT1, 0x00800000 }, - { CS42L43_SPDIF2_INPUT1, 0x00800000 }, + { CS42L43_SPDIF1_INPUT1, 0x00000000 }, + { CS42L43_SPDIF2_INPUT1, 0x00000000 }, { CS42L43_AMP1MIX_INPUT1, 0x00800000 }, { CS42L43_AMP1MIX_INPUT2, 0x00800000 }, { CS42L43_AMP1MIX_INPUT3, 0x00800000 }, @@ -217,7 +227,7 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { { CS42L43_CTRL_REG, 0x00000006 }, { CS42L43_FDIV_FRAC, 0x40000000 }, { CS42L43_CAL_RATIO, 0x00000080 }, - { CS42L43_SPI_CLK_CONFIG1, 0x00000000 }, + { CS42L43_SPI_CLK_CONFIG1, 0x00000001 }, { CS42L43_SPI_CONFIG1, 0x00000000 }, { CS42L43_SPI_CONFIG2, 0x00000000 }, { CS42L43_SPI_CONFIG3, 0x00000001 }, @@ -255,7 +265,7 @@ const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS] = { { CS42L43_ASRC_MASK, 0x0000000F }, { CS42L43_HPOUT_MASK, 0x00000003 }, }; -EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_reg_default, "MFD_CS42L43"); bool cs42l43_readable_register(struct device *dev, unsigned int reg) { @@ -383,7 +393,7 @@ bool cs42l43_readable_register(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_readable_register, "MFD_CS42L43"); bool cs42l43_precious_register(struct device *dev, unsigned int reg) { @@ -398,7 +408,7 @@ bool cs42l43_precious_register(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_precious_register, "MFD_CS42L43"); bool cs42l43_volatile_register(struct device *dev, unsigned int reg) { @@ -426,7 +436,7 @@ bool cs42l43_volatile_register(struct device *dev, unsigned int reg) return cs42l43_precious_register(dev, reg); } } -EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_volatile_register, "MFD_CS42L43"); #define CS42L43_IRQ_OFFSET(reg) ((CS42L43_##reg##_INT) - CS42L43_DECIM_INT) @@ -532,10 +542,10 @@ static int cs42l43_soft_reset(struct cs42l43 *cs42l43) regcache_cache_only(cs42l43->regmap, true); regmap_multi_reg_write_bypassed(cs42l43->regmap, reset, ARRAY_SIZE(reset)); - msleep(CS42L43_RESET_DELAY); + msleep(CS42L43_RESET_DELAY_MS); if (cs42l43->sdw) { - unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_DETACH_TIMEOUT); + unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_DETACH_TIMEOUT_MS); unsigned long time; time = wait_for_completion_timeout(&cs42l43->device_detach, timeout); @@ -555,7 +565,7 @@ static int cs42l43_soft_reset(struct cs42l43 *cs42l43) static int cs42l43_wait_for_attach(struct cs42l43 *cs42l43) { if (!cs42l43->attached) { - unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_ATTACH_TIMEOUT); + unsigned long timeout = msecs_to_jiffies(CS42L43_SDW_ATTACH_TIMEOUT_MS); unsigned long time; time = wait_for_completion_timeout(&cs42l43->device_attach, timeout); @@ -597,7 +607,7 @@ static int cs42l43_mcu_stage_2_3(struct cs42l43 *cs42l43, bool shadow) ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_BOOT_STATUS, val, (val == CS42L43_MCU_BOOT_STAGE3), - CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT); + CS42L43_MCU_POLL_US, CS42L43_MCU_CMD_TIMEOUT_US); if (ret) { dev_err(cs42l43->dev, "Failed to move to stage 3: %d, 0x%x\n", ret, val); return ret; @@ -646,7 +656,7 @@ static int cs42l43_mcu_disable(struct cs42l43 *cs42l43) ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, (val & CS42L43_CONTROL_APPLIED_INT_MASK), - CS42L43_MCU_POLL, CS42L43_MCU_CMD_TIMEOUT); + CS42L43_MCU_POLL_US, CS42L43_MCU_CMD_TIMEOUT_US); if (ret) { dev_err(cs42l43->dev, "Failed to disable firmware: %d, 0x%x\n", ret, val); return ret; @@ -690,7 +700,7 @@ static void cs42l43_mcu_load_firmware(const struct firmware *firmware, void *con ret = regmap_read_poll_timeout(cs42l43->regmap, CS42L43_SOFT_INT_SHADOW, val, (val & CS42L43_PATCH_APPLIED_INT_MASK), - CS42L43_MCU_POLL, CS42L43_MCU_UPDATE_TIMEOUT); + CS42L43_MCU_POLL_US, CS42L43_MCU_UPDATE_TIMEOUT_US); if (ret) { dev_err(cs42l43->dev, "Failed to update firmware: %d, 0x%x\n", ret, val); cs42l43->firmware_error = ret; @@ -703,6 +713,23 @@ err: complete(&cs42l43->firmware_download); } +static int cs42l43_mcu_is_hw_compatible(struct cs42l43 *cs42l43, + unsigned int mcu_rev, + unsigned int bios_rev) +{ + /* + * The firmware has two revision numbers bringing either of them up to a + * supported version will provide the disable the driver requires. + */ + if (mcu_rev < CS42L43_MCU_SUPPORTED_REV && + bios_rev < CS42L43_MCU_SUPPORTED_BIOS_REV) { + dev_err(cs42l43->dev, "Firmware too old to support disable\n"); + return -EINVAL; + } + + return 0; +} + /* * The process of updating the firmware is split into a series of steps, at the * end of each step a soft reset of the device might be required which will @@ -739,16 +766,16 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) ((mcu_rev & CS42L43_FW_SUBMINOR_REV_MASK) >> 8); /* - * The firmware has two revision numbers bringing either of them up to a - * supported version will provide the features the driver requires. + * The firmware has two revision numbers both of them being at the ROM + * revision indicates no patch has been applied. */ - patched = mcu_rev >= CS42L43_MCU_SUPPORTED_REV || - bios_rev >= CS42L43_MCU_SUPPORTED_BIOS_REV; + patched = mcu_rev != CS42L43_MCU_ROM_REV || bios_rev != CS42L43_MCU_ROM_BIOS_REV; /* * Later versions of the firmwware require the driver to access some * features through a set of shadow registers. */ - shadow = mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV; + shadow = (mcu_rev >= CS42L43_MCU_SHADOW_REGS_REQUIRED_REV) || + (bios_rev >= CS42L43_BIOS_SHADOW_REGS_REQUIRED_REV); ret = regmap_read(cs42l43->regmap, CS42L43_BOOT_CONTROL, &secure_cfg); if (ret) { @@ -788,10 +815,15 @@ static int cs42l43_mcu_update_step(struct cs42l43 *cs42l43) return cs42l43_mcu_stage_2_3(cs42l43, shadow); } case CS42L43_MCU_BOOT_STAGE3: - if (patched) + if (patched) { + ret = cs42l43_mcu_is_hw_compatible(cs42l43, mcu_rev, bios_rev); + if (ret) + return ret; + return cs42l43_mcu_disable(cs42l43); - else + } else { return cs42l43_mcu_stage_3_2(cs42l43); + } case CS42L43_MCU_BOOT_STAGE4: return 0; default: @@ -937,7 +969,6 @@ static void cs42l43_boot_work(struct work_struct *work) err: pm_runtime_put_sync(cs42l43->dev); - cs42l43_dev_remove(cs42l43); } static int cs42l43_power_up(struct cs42l43 *cs42l43) @@ -951,9 +982,9 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43) } /* vdd-p must be on for 50uS before any other supply */ - usleep_range(CS42L43_VDDP_DELAY, 2 * CS42L43_VDDP_DELAY); + usleep_range(CS42L43_VDDP_DELAY_US, 2 * CS42L43_VDDP_DELAY_US); - gpiod_set_value_cansleep(cs42l43->reset, 1); + gpiod_set_raw_value_cansleep(cs42l43->reset, 1); ret = regulator_bulk_enable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); if (ret) { @@ -967,14 +998,14 @@ static int cs42l43_power_up(struct cs42l43 *cs42l43) goto err_core_supplies; } - usleep_range(CS42L43_VDDD_DELAY, 2 * CS42L43_VDDD_DELAY); + usleep_range(CS42L43_VDDD_DELAY_US, 2 * CS42L43_VDDD_DELAY_US); return 0; err_core_supplies: regulator_bulk_disable(CS42L43_N_SUPPLIES, cs42l43->core_supplies); err_reset: - gpiod_set_value_cansleep(cs42l43->reset, 0); + gpiod_set_raw_value_cansleep(cs42l43->reset, 0); regulator_disable(cs42l43->vdd_p); return ret; @@ -996,7 +1027,7 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43) return ret; } - gpiod_set_value_cansleep(cs42l43->reset, 0); + gpiod_set_raw_value_cansleep(cs42l43->reset, 0); ret = regulator_disable(cs42l43->vdd_p); if (ret) { @@ -1007,6 +1038,15 @@ static int cs42l43_power_down(struct cs42l43 *cs42l43) return 0; } +static void cs42l43_dev_remove(void *data) +{ + struct cs42l43 *cs42l43 = data; + + cancel_work_sync(&cs42l43->boot_work); + + cs42l43_power_down(cs42l43); +} + int cs42l43_dev_probe(struct cs42l43 *cs42l43) { int i, ret; @@ -1021,11 +1061,13 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) regcache_cache_only(cs42l43->regmap, true); - cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_LOW); + cs42l43->reset = devm_gpiod_get_optional(cs42l43->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(cs42l43->reset)) return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->reset), "Failed to get reset\n"); + gpiod_set_raw_value_cansleep(cs42l43->reset, 0); + cs42l43->vdd_p = devm_regulator_get(cs42l43->dev, "vdd-p"); if (IS_ERR(cs42l43->vdd_p)) return dev_err_probe(cs42l43->dev, PTR_ERR(cs42l43->vdd_p), @@ -1051,7 +1093,11 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) if (ret) return ret; - pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME); + ret = devm_add_action_or_reset(cs42l43->dev, cs42l43_dev_remove, cs42l43); + if (ret) + return ret; + + pm_runtime_set_autosuspend_delay(cs42l43->dev, CS42L43_AUTOSUSPEND_TIME_MS); pm_runtime_use_autosuspend(cs42l43->dev); pm_runtime_set_active(cs42l43->dev); /* @@ -1059,33 +1105,52 @@ int cs42l43_dev_probe(struct cs42l43 *cs42l43) * the boot work runs. */ pm_runtime_get_noresume(cs42l43->dev); - devm_pm_runtime_enable(cs42l43->dev); + ret = devm_pm_runtime_enable(cs42l43->dev); + if (ret) + return ret; queue_work(system_long_wq, &cs42l43->boot_work); return 0; } -EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, MFD_CS42L43); - -void cs42l43_dev_remove(struct cs42l43 *cs42l43) -{ - cs42l43_power_down(cs42l43); -} -EXPORT_SYMBOL_NS_GPL(cs42l43_dev_remove, MFD_CS42L43); +EXPORT_SYMBOL_NS_GPL(cs42l43_dev_probe, "MFD_CS42L43"); static int cs42l43_suspend(struct device *dev) { struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + static const struct reg_sequence mask_all[] = { + { CS42L43_DECIM_MASK, 0xFFFFFFFF, }, + { CS42L43_EQ_MIX_MASK, 0xFFFFFFFF, }, + { CS42L43_ASP_MASK, 0xFFFFFFFF, }, + { CS42L43_PLL_MASK, 0xFFFFFFFF, }, + { CS42L43_SOFT_MASK, 0xFFFFFFFF, }, + { CS42L43_SWIRE_MASK, 0xFFFFFFFF, }, + { CS42L43_MSM_MASK, 0xFFFFFFFF, }, + { CS42L43_ACC_DET_MASK, 0xFFFFFFFF, }, + { CS42L43_I2C_TGT_MASK, 0xFFFFFFFF, }, + { CS42L43_SPI_MSTR_MASK, 0xFFFFFFFF, }, + { CS42L43_SW_TO_SPI_BRIDGE_MASK, 0xFFFFFFFF, }, + { CS42L43_OTP_MASK, 0xFFFFFFFF, }, + { CS42L43_CLASS_D_AMP_MASK, 0xFFFFFFFF, }, + { CS42L43_GPIO_INT_MASK, 0xFFFFFFFF, }, + { CS42L43_ASRC_MASK, 0xFFFFFFFF, }, + { CS42L43_HPOUT_MASK, 0xFFFFFFFF, }, + }; int ret; - /* - * Don't care about being resumed here, but the driver does want - * force_resume to always trigger an actual resume, so that register - * state for the MCU/GPIOs is returned as soon as possible after system - * resume. force_resume will resume if the reference count is resumed on - * suspend hence the get_noresume. - */ - pm_runtime_get_noresume(dev); + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(cs42l43->dev, "Failed to resume for suspend: %d\n", ret); + return ret; + } + + /* The IRQs will be re-enabled on resume by the cache sync */ + ret = regmap_multi_reg_write_bypassed(cs42l43->regmap, + mask_all, ARRAY_SIZE(mask_all)); + if (ret) { + dev_err(cs42l43->dev, "Failed to mask IRQs: %d\n", ret); + return ret; + } ret = pm_runtime_force_suspend(dev); if (ret) { @@ -1100,6 +1165,26 @@ static int cs42l43_suspend(struct device *dev) if (ret) return ret; + disable_irq(cs42l43->irq); + + return 0; +} + +static int cs42l43_suspend_noirq(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + enable_irq(cs42l43->irq); + + return 0; +} + +static int cs42l43_resume_noirq(struct device *dev) +{ + struct cs42l43 *cs42l43 = dev_get_drvdata(dev); + + disable_irq(cs42l43->irq); + return 0; } @@ -1112,6 +1197,8 @@ static int cs42l43_resume(struct device *dev) if (ret) return ret; + enable_irq(cs42l43->irq); + ret = pm_runtime_force_resume(dev); if (ret) { dev_err(cs42l43->dev, "Failed to force resume: %d\n", ret); @@ -1179,6 +1266,7 @@ err: EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = { SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend_noirq, cs42l43_resume_noirq) RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL) }; diff --git a/drivers/mfd/cs42l43.h b/drivers/mfd/cs42l43.h index eb4caf393833..f3da783930f5 100644 --- a/drivers/mfd/cs42l43.h +++ b/drivers/mfd/cs42l43.h @@ -6,15 +6,17 @@ * Cirrus Logic International Semiconductor Ltd. */ -#include <linux/mfd/cs42l43.h> -#include <linux/pm.h> -#include <linux/regmap.h> - #ifndef CS42L43_CORE_INT_H #define CS42L43_CORE_INT_H #define CS42L43_N_DEFAULTS 176 +struct dev_pm_ops; +struct device; +struct reg_default; + +struct cs42l43; + extern const struct dev_pm_ops cs42l43_pm_ops; extern const struct reg_default cs42l43_reg_default[CS42L43_N_DEFAULTS]; @@ -23,6 +25,5 @@ bool cs42l43_precious_register(struct device *dev, unsigned int reg); bool cs42l43_volatile_register(struct device *dev, unsigned int reg); int cs42l43_dev_probe(struct cs42l43 *cs42l43); -void cs42l43_dev_remove(struct cs42l43 *cs42l43); #endif /* CS42L43_CORE_INT_H */ diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index 150448cd2eb0..b06cd518413b 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -533,7 +533,7 @@ const struct regmap_config da9052_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = DA9052_PAGE1_CON_REG, .readable_reg = da9052_reg_readable, @@ -585,6 +585,7 @@ static int da9052_clear_fault_log(struct da9052 *da9052) "Cannot reset FAULT_LOG values %d\n", ret); } + da9052->fault_log = fault_log; return ret; } diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index be5f2b34e18a..80fc5c0cac2f 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -37,7 +37,7 @@ static int da9052_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, da9052); config = da9052_regmap_config; - config.read_flag_mask = 1; + config.write_flag_mask = 1; config.reg_bits = 7; config.pad_bits = 1; config.val_bits = 8; diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index 768302e05baa..1f727ef60d63 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -245,7 +245,7 @@ const struct regmap_config da9055_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = DA9055_MAX_REGISTER_CNT, .readable_reg = da9055_register_readable, diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 9a5f51b60bad..6c1981832aaf 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -54,7 +54,7 @@ static void da9055_i2c_remove(struct i2c_client *i2c) * and CODEC, which must be different to operate together. */ static const struct i2c_device_id da9055_i2c_id[] = { - {"da9055-pmic", 0}, + { "da9055-pmic" }, { } }; MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 73a22107900c..637c5f47a4b0 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -25,7 +25,7 @@ #define DA9062_IRQ_LOW 0 #define DA9062_IRQ_HIGH 1 -static struct regmap_irq da9061_irqs[] = { +static const struct regmap_irq da9061_irqs[] = { /* EVENT A */ [DA9061_IRQ_ONKEY] = { .reg_offset = DA9062_REG_EVENT_A_OFFSET, @@ -79,7 +79,7 @@ static struct regmap_irq da9061_irqs[] = { }, }; -static struct regmap_irq_chip da9061_irq_chip = { +static const struct regmap_irq_chip da9061_irq_chip = { .name = "da9061-irq", .irqs = da9061_irqs, .num_irqs = DA9061_NUM_IRQ, @@ -89,7 +89,7 @@ static struct regmap_irq_chip da9061_irq_chip = { .ack_base = DA9062AA_EVENT_A, }; -static struct regmap_irq da9062_irqs[] = { +static const struct regmap_irq da9062_irqs[] = { /* EVENT A */ [DA9062_IRQ_ONKEY] = { .reg_offset = DA9062_REG_EVENT_A_OFFSET, @@ -151,7 +151,7 @@ static struct regmap_irq da9062_irqs[] = { }, }; -static struct regmap_irq_chip da9062_irq_chip = { +static const struct regmap_irq_chip da9062_irq_chip = { .name = "da9062-irq", .irqs = da9062_irqs, .num_irqs = DA9062_NUM_IRQ, @@ -470,13 +470,13 @@ static const struct regmap_range_cfg da9061_range_cfg[] = { } }; -static struct regmap_config da9061_regmap_config = { +static const struct regmap_config da9061_regmap_config = { .reg_bits = 8, .val_bits = 8, .ranges = da9061_range_cfg, .num_ranges = ARRAY_SIZE(da9061_range_cfg), .max_register = DA9062AA_CONFIG_ID, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .rd_table = &da9061_aa_readable_table, .wr_table = &da9061_aa_writeable_table, .volatile_table = &da9061_aa_volatile_table, @@ -576,13 +576,13 @@ static const struct regmap_range_cfg da9062_range_cfg[] = { } }; -static struct regmap_config da9062_regmap_config = { +static const struct regmap_config da9062_regmap_config = { .reg_bits = 8, .val_bits = 8, .ranges = da9062_range_cfg, .num_ranges = ARRAY_SIZE(da9062_range_cfg), .max_register = DA9062AA_CONFIG_ID, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .rd_table = &da9062_aa_readable_table, .wr_table = &da9062_aa_writeable_table, .volatile_table = &da9062_aa_volatile_table, diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c index d715cf9a9e68..c6235cd0dbdc 100644 --- a/drivers/mfd/da9063-i2c.c +++ b/drivers/mfd/da9063-i2c.c @@ -342,7 +342,7 @@ static struct regmap_config da9063_regmap_config = { .num_ranges = ARRAY_SIZE(da9063_range_cfg), .max_register = DA9063_REG_CONFIG_ID, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct of_device_id da9063_dt_ids[] = { diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c index 94d621e20635..5c59cc869fb3 100644 --- a/drivers/mfd/da9150-core.c +++ b/drivers/mfd/da9150-core.c @@ -169,7 +169,7 @@ static const struct regmap_config da9150_regmap_config = { .num_ranges = ARRAY_SIZE(da9150_range_cfg), .max_register = DA9150_TBAT_RES_B, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_reg = da9150_volatile_reg, }; diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 5b3e355e78f6..21e68a382b11 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -2607,9 +2607,9 @@ static int db8500_irq_init(struct device_node *np) { int i; - db8500_irq_domain = irq_domain_add_simple( - np, NUM_PRCMU_WAKEUPS, 0, - &db8500_irq_ops, NULL); + db8500_irq_domain = irq_domain_create_simple(of_fwnode_handle(np), + NUM_PRCMU_WAKEUPS, 0, + &db8500_irq_ops, NULL); if (!db8500_irq_domain) { pr_err("Failed to create irqdomain\n"); diff --git a/drivers/mfd/ene-kb3930.c b/drivers/mfd/ene-kb3930.c index fa0ad2f14a39..9460a67acb0b 100644 --- a/drivers/mfd/ene-kb3930.c +++ b/drivers/mfd/ene-kb3930.c @@ -162,7 +162,7 @@ static int kb3930_probe(struct i2c_client *client) devm_gpiod_get_array_optional(dev, "off", GPIOD_IN); if (IS_ERR(ddata->off_gpios)) return PTR_ERR(ddata->off_gpios); - if (ddata->off_gpios->ndescs < 2) { + if (ddata->off_gpios && ddata->off_gpios->ndescs < 2) { dev_err(dev, "invalid off-gpios property\n"); return -EINVAL; } diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c index e58990c85ed8..44797001a432 100644 --- a/drivers/mfd/exynos-lpass.c +++ b/drivers/mfd/exynos-lpass.c @@ -104,11 +104,22 @@ static const struct regmap_config exynos_lpass_reg_conf = { .fast_io = true, }; +static void exynos_lpass_disable_lpass(void *data) +{ + struct platform_device *pdev = data; + struct exynos_lpass *lpass = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + exynos_lpass_disable(lpass); +} + static int exynos_lpass_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct exynos_lpass *lpass; void __iomem *base_top; + int ret; lpass = devm_kzalloc(dev, sizeof(*lpass), GFP_KERNEL); if (!lpass) @@ -122,8 +133,8 @@ static int exynos_lpass_probe(struct platform_device *pdev) if (IS_ERR(lpass->sfr0_clk)) return PTR_ERR(lpass->sfr0_clk); - lpass->top = regmap_init_mmio(dev, base_top, - &exynos_lpass_reg_conf); + lpass->top = devm_regmap_init_mmio(dev, base_top, + &exynos_lpass_reg_conf); if (IS_ERR(lpass->top)) { dev_err(dev, "LPASS top regmap initialization failed\n"); return PTR_ERR(lpass->top); @@ -134,18 +145,11 @@ static int exynos_lpass_probe(struct platform_device *pdev) pm_runtime_enable(dev); exynos_lpass_enable(lpass); - return devm_of_platform_populate(dev); -} - -static void exynos_lpass_remove(struct platform_device *pdev) -{ - struct exynos_lpass *lpass = platform_get_drvdata(pdev); + ret = devm_add_action_or_reset(dev, exynos_lpass_disable_lpass, pdev); + if (ret) + return ret; - exynos_lpass_disable(lpass); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - exynos_lpass_disable(lpass); - regmap_exit(lpass->top); + return devm_of_platform_populate(dev); } static int __maybe_unused exynos_lpass_suspend(struct device *dev) @@ -179,13 +183,12 @@ static const struct of_device_id exynos_lpass_of_match[] = { MODULE_DEVICE_TABLE(of, exynos_lpass_of_match); static struct platform_driver exynos_lpass_driver = { - .driver = { + .driver = { .name = "exynos-lpass", .pm = &lpass_pm_ops, .of_match_table = exynos_lpass_of_match, }, .probe = exynos_lpass_probe, - .remove_new = exynos_lpass_remove, }; module_platform_driver(exynos_lpass_driver); diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 8d006f6be48c..1be4557b7bdd 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -25,11 +25,6 @@ struct pcap_adc_request { void *data; }; -struct pcap_adc_sync_request { - u16 res[2]; - struct completion completion; -}; - struct pcap_chip { struct spi_device *spi; @@ -335,34 +330,6 @@ int pcap_adc_async(struct pcap_chip *pcap, u8 bank, u32 flags, u8 ch[], } EXPORT_SYMBOL_GPL(pcap_adc_async); -static void pcap_adc_sync_cb(void *param, u16 res[]) -{ - struct pcap_adc_sync_request *req = param; - - req->res[0] = res[0]; - req->res[1] = res[1]; - complete(&req->completion); -} - -int pcap_adc_sync(struct pcap_chip *pcap, u8 bank, u32 flags, u8 ch[], - u16 res[]) -{ - struct pcap_adc_sync_request sync_data; - int ret; - - init_completion(&sync_data.completion); - ret = pcap_adc_async(pcap, bank, flags, ch, pcap_adc_sync_cb, - &sync_data); - if (ret) - return ret; - wait_for_completion(&sync_data.completion); - res[0] = sync_data.res[0]; - res[1] = sync_data.res[1]; - - return 0; -} -EXPORT_SYMBOL_GPL(pcap_adc_sync); - /* subdevs */ static int pcap_remove_subdev(struct device *dev, void *unused) { diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index 74f38bf3778f..d47152467951 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -16,7 +16,7 @@ #include <linux/platform_device.h> #include <linux/regmap.h> -static struct regmap_config mx25_tsadc_regmap_config = { +static const struct regmap_config mx25_tsadc_regmap_config = { .fast_io = true, .max_register = 8, .reg_bits = 32, @@ -65,15 +65,14 @@ static int mx25_tsadc_setup_irq(struct platform_device *pdev, struct mx25_tsadc *tsadc) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; int irq; irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - tsadc->domain = irq_domain_add_simple(np, 2, 0, &mx25_tsadc_domain_ops, - tsadc); + tsadc->domain = irq_domain_create_simple(of_fwnode_handle(dev->of_node), 2, 0, + &mx25_tsadc_domain_ops, tsadc); if (!tsadc->domain) { dev_err(dev, "Failed to add irq domain\n"); return -ENOMEM; @@ -211,7 +210,7 @@ static struct platform_driver mx25_tsadc_driver = { .of_match_table = mx25_tsadc_ids, }, .probe = mx25_tsadc_probe, - .remove_new = mx25_tsadc_remove, + .remove = mx25_tsadc_remove, }; module_platform_driver(mx25_tsadc_driver); diff --git a/drivers/mfd/gateworks-gsc.c b/drivers/mfd/gateworks-gsc.c index b02bfdc871e9..a3301502ce6a 100644 --- a/drivers/mfd/gateworks-gsc.c +++ b/drivers/mfd/gateworks-gsc.c @@ -20,7 +20,7 @@ #include <linux/platform_device.h> #include <linux/regmap.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> /* * The GSC suffers from an errata where occasionally during @@ -160,7 +160,7 @@ static const struct of_device_id gsc_of_match[] = { }; MODULE_DEVICE_TABLE(of, gsc_of_match); -static struct regmap_bus gsc_regmap_bus = { +static const struct regmap_bus gsc_regmap_bus = { .reg_read = gsc_read, .reg_write = gsc_write, }; diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index 042109304db4..3b4ffcbbee20 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -41,7 +41,7 @@ static const struct regmap_irq_chip hi655x_irq_chip = { .mask_base = HI655X_IRQ_MASK_BASE, }; -static struct regmap_config hi655x_regmap_config = { +static const struct regmap_config hi655x_regmap_config = { .reg_bits = 32, .reg_stride = HI655X_STRIDE, .val_bits = 8, @@ -159,12 +159,12 @@ static const struct of_device_id hi655x_pmic_match[] = { MODULE_DEVICE_TABLE(of, hi655x_pmic_match); static struct platform_driver hi655x_pmic_driver = { - .driver = { - .name = "hi655x-pmic", + .driver = { + .name = "hi655x-pmic", .of_match_table = hi655x_pmic_match, }, - .probe = hi655x_pmic_probe, - .remove_new = hi655x_pmic_remove, + .probe = hi655x_pmic_probe, + .remove = hi655x_pmic_remove, }; module_platform_driver(hi655x_pmic_driver); diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 2a83f8678f1d..63406026d809 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -208,7 +208,7 @@ static void intel_lpss_acpi_remove(struct platform_device *pdev) static struct platform_driver intel_lpss_acpi_driver = { .probe = intel_lpss_acpi_probe, - .remove_new = intel_lpss_acpi_remove, + .remove = intel_lpss_acpi_remove, .driver = { .name = "intel-lpss", .acpi_match_table = intel_lpss_acpi_ids, @@ -222,4 +222,4 @@ MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); MODULE_DESCRIPTION("Intel LPSS ACPI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(INTEL_LPSS); +MODULE_IMPORT_NS("INTEL_LPSS"); diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 4621d3950b8f..1a5b8b13f8d0 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -23,12 +23,22 @@ #include "intel-lpss.h" -/* Some DSDTs have an unused GEXP ACPI device conflicting with I2C4 resources */ -static const struct pci_device_id ignore_resource_conflicts_ids[] = { - /* Microsoft Surface Go (version 1) I2C4 */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, 0x9d64, 0x152d, 0x1182), }, - /* Microsoft Surface Go 2 I2C4 */ - { PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, 0x9d64, 0x152d, 0x1237), }, +static const struct pci_device_id quirk_ids[] = { + { + /* Microsoft Surface Go (version 1) I2C4 */ + PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, 0x9d64, 0x152d, 0x1182), + .driver_data = QUIRK_IGNORE_RESOURCE_CONFLICTS, + }, + { + /* Microsoft Surface Go 2 I2C4 */ + PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, 0x9d64, 0x152d, 0x1237), + .driver_data = QUIRK_IGNORE_RESOURCE_CONFLICTS, + }, + { + /* Dell XPS 9530 (2023) */ + PCI_DEVICE_SUB(PCI_VENDOR_ID_INTEL, 0x51fb, 0x1028, 0x0beb), + .driver_data = QUIRK_CLOCK_DIVIDER_UNITY, + }, { } }; @@ -36,6 +46,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { const struct intel_lpss_platform_info *data = (void *)id->driver_data; + const struct pci_device_id *quirk_pci_info; struct intel_lpss_platform_info *info; int ret; @@ -43,7 +54,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev, if (ret) return ret; - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY); + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) return ret; @@ -55,8 +66,9 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev, info->mem = pci_resource_n(pdev, 0); info->irq = pci_irq_vector(pdev, 0); - if (pci_match_id(ignore_resource_conflicts_ids, pdev)) - info->ignore_resource_conflicts = true; + quirk_pci_info = pci_match_id(quirk_ids, pdev); + if (quirk_pci_info) + info->quirks = quirk_pci_info->driver_data; pdev->d3cold_delay = 0; @@ -91,7 +103,7 @@ static const struct software_node spt_spi_node = { .properties = spt_spi_properties, }; -static const struct intel_lpss_platform_info spt_info = { +static const struct intel_lpss_platform_info spt_spi_info = { .clk_rate = 120000000, .swnode = &spt_spi_node, }; @@ -136,7 +148,7 @@ static const struct software_node bxt_spi_node = { .properties = bxt_spi_properties, }; -static const struct intel_lpss_platform_info bxt_info = { +static const struct intel_lpss_platform_info bxt_spi_info = { .clk_rate = 100000000, .swnode = &bxt_spi_node, }; @@ -204,7 +216,7 @@ static const struct software_node cnl_spi_node = { .properties = cnl_spi_properties, }; -static const struct intel_lpss_platform_info cnl_info = { +static const struct intel_lpss_platform_info cnl_spi_info = { .clk_rate = 120000000, .swnode = &cnl_spi_node, }; @@ -228,7 +240,7 @@ static const struct software_node tgl_spi_node = { .properties = tgl_spi_properties, }; -static const struct intel_lpss_platform_info tgl_info = { +static const struct intel_lpss_platform_info tgl_spi_info = { .clk_rate = 100000000, .swnode = &tgl_spi_node, }; @@ -237,8 +249,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* CML-LP */ { PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x02a9), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0x02c5), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x02c6), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x02c7), (kernel_ulong_t)&spt_uart_info }, @@ -246,18 +258,18 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x02e9), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x02ea), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x02eb), (kernel_ulong_t)&cnl_i2c_info }, - { PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&cnl_spi_info }, /* CML-H */ { PCI_VDEVICE(INTEL, 0x06a8), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x06a9), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0x06c7), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x06e8), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x06e9), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x06ea), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x06eb), (kernel_ulong_t)&cnl_i2c_info }, - { PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&cnl_spi_info }, /* BXT A-Step */ { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info }, @@ -270,9 +282,9 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x0abc), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x0abe), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x0ac0), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x0ac2), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x0ac4), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x0ac6), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x0ac2), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x0ac4), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x0ac6), (kernel_ulong_t)&bxt_spi_info }, { PCI_VDEVICE(INTEL, 0x0aee), (kernel_ulong_t)&bxt_uart_info }, /* BXT B-Step */ { PCI_VDEVICE(INTEL, 0x1aac), (kernel_ulong_t)&bxt_i2c_info }, @@ -286,9 +298,9 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x1abc), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x1abe), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x1ac0), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x1ac2), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x1ac2), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x1ac4), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x1ac6), (kernel_ulong_t)&bxt_spi_info }, { PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info }, /* EBG */ { PCI_VDEVICE(INTEL, 0x1bad), (kernel_ulong_t)&bxt_uart_info }, @@ -305,15 +317,15 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x31bc), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x31be), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x31c0), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x31c2), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x31c4), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x31c6), (kernel_ulong_t)&bxt_spi_info }, { PCI_VDEVICE(INTEL, 0x31ee), (kernel_ulong_t)&bxt_uart_info }, /* ICL-LP */ { PCI_VDEVICE(INTEL, 0x34a8), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x34a9), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0x34c5), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x34c6), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x34c7), (kernel_ulong_t)&spt_uart_info }, @@ -321,15 +333,15 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x34e9), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x34ea), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x34eb), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&cnl_spi_info }, /* ICL-N */ { PCI_VDEVICE(INTEL, 0x38a8), (kernel_ulong_t)&spt_uart_info }, /* TGL-H */ { PCI_VDEVICE(INTEL, 0x43a7), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x43a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x43a9), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0x43ad), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x43ae), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x43d8), (kernel_ulong_t)&bxt_i2c_info }, @@ -338,14 +350,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x43e9), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x43ea), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x43eb), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&tgl_spi_info }, /* EHL */ { PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x4b2a), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x4b2b), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x4b37), (kernel_ulong_t)&bxt_spi_info }, { PCI_VDEVICE(INTEL, 0x4b44), (kernel_ulong_t)&ehl_i2c_info }, { PCI_VDEVICE(INTEL, 0x4b45), (kernel_ulong_t)&ehl_i2c_info }, { PCI_VDEVICE(INTEL, 0x4b4b), (kernel_ulong_t)&ehl_i2c_info }, @@ -358,8 +370,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* JSL */ { PCI_VDEVICE(INTEL, 0x4da8), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x4da9), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0x4dc5), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x4dc6), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x4dc7), (kernel_ulong_t)&spt_uart_info }, @@ -367,12 +379,12 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x4de9), (kernel_ulong_t)&bxt_i2c_info }, { 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)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&cnl_spi_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)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&tgl_spi_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 }, @@ -382,12 +394,12 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { 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)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&tgl_spi_info }, /* ADL-M */ { PCI_VDEVICE(INTEL, 0x54a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x54a9), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0x54c5), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x54c6), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x54c7), (kernel_ulong_t)&bxt_uart_info }, @@ -395,7 +407,7 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x54e9), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x54ea), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x54eb), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&tgl_spi_info }, /* APL */ { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info }, { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info }, @@ -408,46 +420,59 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x5abc), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x5abe), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x5ac0), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x5ac2), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x5ac2), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_spi_info }, + { PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_spi_info }, { PCI_VDEVICE(INTEL, 0x5aee), (kernel_ulong_t)&bxt_uart_info }, + /* ARL-H */ + { PCI_VDEVICE(INTEL, 0x7725), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7726), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7727), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7730), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7746), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7750), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7751), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7752), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x7778), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7779), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x777a), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x777b), (kernel_ulong_t)&bxt_i2c_info }, /* RPL-S */ { PCI_VDEVICE(INTEL, 0x7a28), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x7a29), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x7a2a), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7a2b), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7a2a), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7a2b), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0x7a4c), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7a4d), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7a4e), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7a4f), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7a5c), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x7a79), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7a7b), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7a79), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7a7b), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0x7a7c), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7a7d), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7a7e), (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)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&tgl_spi_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)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&tgl_spi_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 }, /* MTL-P */ { PCI_VDEVICE(INTEL, 0x7e25), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x7e26), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x7e27), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7e30), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7e46), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7e27), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7e30), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7e46), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0x7e50), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7e51), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7e52), (kernel_ulong_t)&bxt_uart_info }, @@ -458,22 +483,22 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* MTP-S */ { PCI_VDEVICE(INTEL, 0x7f28), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x7f29), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x7f2a), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7f2b), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f2a), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7f2b), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0x7f4c), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7f4d), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7f4e), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7f4f), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7f5c), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x7f5d), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x7f5e), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0x7f5f), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7f5e), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0x7f5f), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0x7f7a), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7f7b), (kernel_ulong_t)&bxt_i2c_info }, /* LKF */ { PCI_VDEVICE(INTEL, 0x98a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x98a9), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x98aa), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x98aa), (kernel_ulong_t)&bxt_spi_info }, { PCI_VDEVICE(INTEL, 0x98c5), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x98c6), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x98c7), (kernel_ulong_t)&bxt_uart_info }, @@ -484,8 +509,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* SPT-LP */ { PCI_VDEVICE(INTEL, 0x9d27), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_spi_info }, + { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_spi_info }, { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_i2c_info }, @@ -496,8 +521,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* CNL-LP */ { PCI_VDEVICE(INTEL, 0x9da8), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x9da9), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0x9dc5), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x9dc6), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x9dc7), (kernel_ulong_t)&spt_uart_info }, @@ -505,12 +530,12 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x9de9), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x9dea), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0x9deb), (kernel_ulong_t)&cnl_i2c_info }, - { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&cnl_spi_info }, /* TGL-LP */ { PCI_VDEVICE(INTEL, 0xa0a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0xa0a9), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0xa0c5), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa0c6), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa0c7), (kernel_ulong_t)&bxt_uart_info }, @@ -520,20 +545,20 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa0db), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0xa0dc), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0xa0dd), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0xa0e8), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa0e9), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa0ea), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa0eb), (kernel_ulong_t)&spt_i2c_info }, - { PCI_VDEVICE(INTEL, 0xa0fb), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0fb), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&cnl_spi_info }, /* SPT-H */ { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_spi_info }, + { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_spi_info }, { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa162), (kernel_ulong_t)&spt_i2c_info }, @@ -541,8 +566,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* KBL-H */ { PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&spt_spi_info }, + { PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&spt_spi_info }, { PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&spt_i2c_info }, @@ -551,19 +576,19 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* CNL-H */ { PCI_VDEVICE(INTEL, 0xa328), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa329), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&cnl_info }, - { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&cnl_spi_info }, + { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&cnl_spi_info }, { PCI_VDEVICE(INTEL, 0xa347), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa368), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0xa369), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0xa36a), (kernel_ulong_t)&cnl_i2c_info }, { PCI_VDEVICE(INTEL, 0xa36b), (kernel_ulong_t)&cnl_i2c_info }, - { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&cnl_spi_info }, /* CML-V */ { PCI_VDEVICE(INTEL, 0xa3a7), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa3a8), (kernel_ulong_t)&spt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa3a9), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa3aa), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa3a9), (kernel_ulong_t)&spt_spi_info }, + { PCI_VDEVICE(INTEL, 0xa3aa), (kernel_ulong_t)&spt_spi_info }, { PCI_VDEVICE(INTEL, 0xa3e0), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa3e1), (kernel_ulong_t)&spt_i2c_info }, { PCI_VDEVICE(INTEL, 0xa3e2), (kernel_ulong_t)&spt_i2c_info }, @@ -572,9 +597,9 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* LNL-M */ { PCI_VDEVICE(INTEL, 0xa825), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0xa826), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0xa827), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0xa830), (kernel_ulong_t)&tgl_info }, - { PCI_VDEVICE(INTEL, 0xa846), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0xa827), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xa830), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xa846), (kernel_ulong_t)&tgl_spi_info }, { PCI_VDEVICE(INTEL, 0xa850), (kernel_ulong_t)&ehl_i2c_info }, { PCI_VDEVICE(INTEL, 0xa851), (kernel_ulong_t)&ehl_i2c_info }, { PCI_VDEVICE(INTEL, 0xa852), (kernel_ulong_t)&bxt_uart_info }, @@ -582,6 +607,32 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0xa879), (kernel_ulong_t)&ehl_i2c_info }, { PCI_VDEVICE(INTEL, 0xa87a), (kernel_ulong_t)&ehl_i2c_info }, { PCI_VDEVICE(INTEL, 0xa87b), (kernel_ulong_t)&ehl_i2c_info }, + /* PTL-H */ + { PCI_VDEVICE(INTEL, 0xe325), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe326), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe327), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xe330), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xe346), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xe350), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe351), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe352), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe378), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe379), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe37a), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe37b), (kernel_ulong_t)&ehl_i2c_info }, + /* PTL-P */ + { PCI_VDEVICE(INTEL, 0xe425), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe426), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe427), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xe430), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xe446), (kernel_ulong_t)&tgl_spi_info }, + { PCI_VDEVICE(INTEL, 0xe450), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe451), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe452), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0xe478), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe479), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe47a), (kernel_ulong_t)&ehl_i2c_info }, + { PCI_VDEVICE(INTEL, 0xe47b), (kernel_ulong_t)&ehl_i2c_info }, { } }; MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids); @@ -602,4 +653,4 @@ MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); MODULE_DESCRIPTION("Intel LPSS PCI driver"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(INTEL_LPSS); +MODULE_IMPORT_NS("INTEL_LPSS"); diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index eff423f7dd28..63d6694f7145 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -300,6 +300,7 @@ static int intel_lpss_register_clock_divider(struct intel_lpss *lpss, { char name[32]; struct clk *tmp = *clk; + int ret; snprintf(name, sizeof(name), "%s-enable", devname); tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 0, @@ -316,6 +317,12 @@ static int intel_lpss_register_clock_divider(struct intel_lpss *lpss, return PTR_ERR(tmp); *clk = tmp; + if (lpss->info->quirks & QUIRK_CLOCK_DIVIDER_UNITY) { + ret = clk_set_rate(tmp, lpss->info->clk_rate); + if (ret) + return ret; + } + snprintf(name, sizeof(name), "%s-update", devname); tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), CLK_SET_RATE_PARENT, lpss->priv, 31, 0, NULL); @@ -412,7 +419,7 @@ int intel_lpss_probe(struct device *dev, return ret; lpss->cell->swnode = info->swnode; - lpss->cell->ignore_resource_conflicts = info->ignore_resource_conflicts; + lpss->cell->ignore_resource_conflicts = info->quirks & QUIRK_IGNORE_RESOURCE_CONFLICTS; intel_lpss_init_dev(lpss); @@ -457,7 +464,7 @@ err_clk_register: return ret; } -EXPORT_SYMBOL_NS_GPL(intel_lpss_probe, INTEL_LPSS); +EXPORT_SYMBOL_NS_GPL(intel_lpss_probe, "INTEL_LPSS"); void intel_lpss_remove(struct device *dev) { @@ -469,11 +476,11 @@ void intel_lpss_remove(struct device *dev) intel_lpss_unregister_clock(lpss); ida_free(&intel_lpss_devid_ida, lpss->devid); } -EXPORT_SYMBOL_NS_GPL(intel_lpss_remove, INTEL_LPSS); +EXPORT_SYMBOL_NS_GPL(intel_lpss_remove, "INTEL_LPSS"); static int resume_lpss_device(struct device *dev, void *data) { - if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) + if (!dev_pm_smart_suspend(dev)) pm_runtime_resume(dev); return 0; diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index c1d72b117ed5..6f8f668f4c6f 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h @@ -11,16 +11,28 @@ #ifndef __MFD_INTEL_LPSS_H #define __MFD_INTEL_LPSS_H +#include <linux/bits.h> #include <linux/pm.h> +/* + * Some DSDTs have an unused GEXP ACPI device conflicting with I2C4 resources. + * Set to ignore resource conflicts with ACPI declared SystemMemory regions. + */ +#define QUIRK_IGNORE_RESOURCE_CONFLICTS BIT(0) +/* + * Some devices have misconfigured clock divider due to a firmware bug. + * Set this to force the clock divider to 1:1 ratio. + */ +#define QUIRK_CLOCK_DIVIDER_UNITY BIT(1) + struct device; struct resource; struct software_node; struct intel_lpss_platform_info { struct resource *mem; - bool ignore_resource_conflicts; int irq; + unsigned int quirks; unsigned long clk_rate; const char *clk_con_id; const struct software_node *swnode; diff --git a/drivers/mfd/intel-m10-bmc-core.c b/drivers/mfd/intel-m10-bmc-core.c index 8ad5b3821584..e930161bf65e 100644 --- a/drivers/mfd/intel-m10-bmc-core.c +++ b/drivers/mfd/intel-m10-bmc-core.c @@ -22,7 +22,7 @@ void m10bmc_fw_state_set(struct intel_m10bmc *m10bmc, enum m10bmc_fw_state new_s m10bmc->bmcfw_state = new_state; up_write(&m10bmc->bmcfw_lock); } -EXPORT_SYMBOL_NS_GPL(m10bmc_fw_state_set, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_fw_state_set, "INTEL_M10_BMC_CORE"); /* * For some Intel FPGA devices, the BMC firmware is not available to service @@ -75,7 +75,7 @@ int m10bmc_sys_read(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned i return ret; } -EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_sys_read, "INTEL_M10_BMC_CORE"); int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset, unsigned int msk, unsigned int val) @@ -95,7 +95,7 @@ int m10bmc_sys_update_bits(struct intel_m10bmc *m10bmc, unsigned int offset, return ret; } -EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_sys_update_bits, "INTEL_M10_BMC_CORE"); static ssize_t bmc_version_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -183,7 +183,7 @@ const struct attribute_group *m10bmc_dev_groups[] = { &m10bmc_group, NULL, }; -EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_dev_groups, "INTEL_M10_BMC_CORE"); int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platform_info *info) { @@ -201,7 +201,7 @@ int m10bmc_dev_init(struct intel_m10bmc *m10bmc, const struct intel_m10bmc_platf return ret; } -EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, INTEL_M10_BMC_CORE); +EXPORT_SYMBOL_NS_GPL(m10bmc_dev_init, "INTEL_M10_BMC_CORE"); MODULE_DESCRIPTION("Intel MAX 10 BMC core driver"); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/mfd/intel-m10-bmc-pmci.c b/drivers/mfd/intel-m10-bmc-pmci.c index 0392ef8b57d8..d213c6ec04ba 100644 --- a/drivers/mfd/intel-m10-bmc-pmci.c +++ b/drivers/mfd/intel-m10-bmc-pmci.c @@ -336,7 +336,7 @@ static const struct regmap_access_table m10bmc_pmci_access_table = { .n_yes_ranges = ARRAY_SIZE(m10bmc_pmci_regmap_range), }; -static struct regmap_config m10bmc_pmci_regmap_config = { +static const struct regmap_config m10bmc_pmci_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, @@ -370,6 +370,7 @@ static const struct m10bmc_csr_map m10bmc_n6000_csr_map = { .pr_reh_addr = M10BMC_N6000_PR_REH_ADDR, .pr_magic = M10BMC_N6000_PR_PROG_MAGIC, .rsu_update_counter = M10BMC_N6000_STAGING_FLASH_COUNT, + .staging_size = M10BMC_STAGING_SIZE, }; static const struct intel_m10bmc_platform_info m10bmc_pmci_n6000 = { @@ -453,4 +454,4 @@ module_dfl_driver(m10bmc_pmci_driver); MODULE_DESCRIPTION("MAX10 BMC PMCI-based interface"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); +MODULE_IMPORT_NS("INTEL_M10_BMC_CORE"); diff --git a/drivers/mfd/intel-m10-bmc-spi.c b/drivers/mfd/intel-m10-bmc-spi.c index cbeb7de9e041..cfa620f0c70e 100644 --- a/drivers/mfd/intel-m10-bmc-spi.c +++ b/drivers/mfd/intel-m10-bmc-spi.c @@ -24,7 +24,7 @@ static const struct regmap_access_table m10bmc_access_table = { .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range), }; -static struct regmap_config intel_m10bmc_regmap_config = { +static const struct regmap_config intel_m10bmc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -109,6 +109,7 @@ static const struct m10bmc_csr_map m10bmc_n3000_csr_map = { .pr_reh_addr = M10BMC_N3000_PR_REH_ADDR, .pr_magic = M10BMC_N3000_PR_PROG_MAGIC, .rsu_update_counter = M10BMC_N3000_STAGING_FLASH_COUNT, + .staging_size = M10BMC_STAGING_SIZE, }; static struct mfd_cell m10bmc_d5005_subdevs[] = { @@ -180,4 +181,4 @@ MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface"); MODULE_AUTHOR("Intel Corporation"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:intel-m10-bmc"); -MODULE_IMPORT_NS(INTEL_M10_BMC_CORE); +MODULE_IMPORT_NS("INTEL_M10_BMC_CORE"); diff --git a/drivers/mfd/intel_pmc_bxt.c b/drivers/mfd/intel_pmc_bxt.c index 9f01d38acc7f..e405d7513ca1 100644 --- a/drivers/mfd/intel_pmc_bxt.c +++ b/drivers/mfd/intel_pmc_bxt.c @@ -23,8 +23,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/platform_data/itco_wdt.h> - -#include <asm/intel_scu_ipc.h> +#include <linux/platform_data/x86/intel_scu_ipc.h> /* Residency with clock rate at 19.2MHz to usecs */ #define S0IX_RESIDENCY_IN_USECS(d, s) \ diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 8dac0d41f64f..9d89171d83f9 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -6,17 +6,27 @@ */ #include <linux/acpi.h> +#include <linux/array_size.h> #include <linux/bits.h> #include <linux/delay.h> +#include <linux/device.h> #include <linux/err.h> +#include <linux/errno.h> +#include <linux/gfp_types.h> #include <linux/interrupt.h> -#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/kstrtox.h> #include <linux/mfd/core.h> #include <linux/mfd/intel_soc_pmic.h> #include <linux/mfd/intel_soc_pmic_bxtwc.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> - -#include <asm/intel_scu_ipc.h> +#include <linux/platform_data/x86/intel_scu_ipc.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/sysfs.h> +#include <linux/types.h> /* PMIC device registers */ #define REG_ADDR_MASK GENMASK(15, 8) @@ -138,7 +148,7 @@ static const struct regmap_irq bxtwc_regmap_irqs_crit[] = { REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, GENMASK(1, 0)), }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip = { +static const struct regmap_irq_chip bxtwc_regmap_irq_chip = { .name = "bxtwc_irq_chip", .status_base = BXTWC_IRQLVL1, .mask_base = BXTWC_MIRQLVL1, @@ -147,8 +157,9 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip = { .num_regs = 1, }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { +static const struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { .name = "bxtwc_irq_chip_pwrbtn", + .domain_suffix = "PWRBTN", .status_base = BXTWC_PWRBTNIRQ, .mask_base = BXTWC_MPWRBTNIRQ, .irqs = bxtwc_regmap_irqs_pwrbtn, @@ -156,8 +167,9 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_pwrbtn = { .num_regs = 1, }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { +static const struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { .name = "bxtwc_irq_chip_tmu", + .domain_suffix = "TMU", .status_base = BXTWC_TMUIRQ, .mask_base = BXTWC_MTMUIRQ, .irqs = bxtwc_regmap_irqs_tmu, @@ -165,8 +177,9 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { .num_regs = 1, }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { +static const struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { .name = "bxtwc_irq_chip_bcu", + .domain_suffix = "BCU", .status_base = BXTWC_BCUIRQ, .mask_base = BXTWC_MBCUIRQ, .irqs = bxtwc_regmap_irqs_bcu, @@ -174,8 +187,9 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_bcu = { .num_regs = 1, }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { +static const struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { .name = "bxtwc_irq_chip_adc", + .domain_suffix = "ADC", .status_base = BXTWC_ADCIRQ, .mask_base = BXTWC_MADCIRQ, .irqs = bxtwc_regmap_irqs_adc, @@ -183,8 +197,9 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_adc = { .num_regs = 1, }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { +static const struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { .name = "bxtwc_irq_chip_chgr", + .domain_suffix = "CHGR", .status_base = BXTWC_CHGR0IRQ, .mask_base = BXTWC_MCHGR0IRQ, .irqs = bxtwc_regmap_irqs_chgr, @@ -192,8 +207,9 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_chgr = { .num_regs = 2, }; -static struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { +static const struct regmap_irq_chip bxtwc_regmap_irq_chip_crit = { .name = "bxtwc_irq_chip_crit", + .domain_suffix = "CRIT", .status_base = BXTWC_CRITIRQ, .mask_base = BXTWC_MCRITIRQ, .irqs = bxtwc_regmap_irqs_crit, @@ -232,43 +248,54 @@ static const struct resource tmu_resources[] = { static struct mfd_cell bxt_wc_dev[] = { { - .name = "bxt_wcove_gpadc", - .num_resources = ARRAY_SIZE(adc_resources), - .resources = adc_resources, - }, - { .name = "bxt_wcove_thermal", .num_resources = ARRAY_SIZE(thermal_resources), .resources = thermal_resources, }, { - .name = "bxt_wcove_usbc", - .num_resources = ARRAY_SIZE(usbc_resources), - .resources = usbc_resources, + .name = "bxt_wcove_gpio", + .num_resources = ARRAY_SIZE(gpio_resources), + .resources = gpio_resources, }, { - .name = "bxt_wcove_ext_charger", - .num_resources = ARRAY_SIZE(charger_resources), - .resources = charger_resources, + .name = "bxt_wcove_region", + }, +}; + +static const struct mfd_cell bxt_wc_tmu_dev[] = { + { + .name = "bxt_wcove_tmu", + .num_resources = ARRAY_SIZE(tmu_resources), + .resources = tmu_resources, }, +}; + +static const struct mfd_cell bxt_wc_bcu_dev[] = { { .name = "bxt_wcove_bcu", .num_resources = ARRAY_SIZE(bcu_resources), .resources = bcu_resources, }, +}; + +static const struct mfd_cell bxt_wc_adc_dev[] = { { - .name = "bxt_wcove_tmu", - .num_resources = ARRAY_SIZE(tmu_resources), - .resources = tmu_resources, + .name = "bxt_wcove_gpadc", + .num_resources = ARRAY_SIZE(adc_resources), + .resources = adc_resources, }, +}; +static struct mfd_cell bxt_wc_chgr_dev[] = { { - .name = "bxt_wcove_gpio", - .num_resources = ARRAY_SIZE(gpio_resources), - .resources = gpio_resources, + .name = "bxt_wcove_usbc", + .num_resources = ARRAY_SIZE(usbc_resources), + .resources = usbc_resources, }, { - .name = "bxt_wcove_region", + .name = "bxt_wcove_ext_charger", + .num_resources = ARRAY_SIZE(charger_resources), + .resources = charger_resources, }, }; @@ -348,6 +375,7 @@ static ssize_t addr_store(struct device *dev, return count; } +static DEVICE_ATTR_ADMIN_RW(addr); static ssize_t val_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -384,23 +412,14 @@ static ssize_t val_store(struct device *dev, } return count; } - -static DEVICE_ATTR_ADMIN_RW(addr); static DEVICE_ATTR_ADMIN_RW(val); + static struct attribute *bxtwc_attrs[] = { &dev_attr_addr.attr, &dev_attr_val.attr, NULL }; - -static const struct attribute_group bxtwc_group = { - .attrs = bxtwc_attrs, -}; - -static const struct attribute_group *bxtwc_groups[] = { - &bxtwc_group, - NULL -}; +ATTRIBUTE_GROUPS(bxtwc); static const struct regmap_config bxtwc_regmap_config = { .reg_bits = 16, @@ -415,15 +434,39 @@ static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, const struct regmap_irq_chip *chip, struct regmap_irq_chip_data **data) { - int irq; + struct device *dev = pmic->dev; + int irq, ret; irq = regmap_irq_get_virq(pdata, pirq); if (irq < 0) - return dev_err_probe(pmic->dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", + return dev_err_probe(dev, irq, "Failed to get parent vIRQ(%d) for chip %s\n", pirq, chip->name); - return devm_regmap_add_irq_chip(pmic->dev, pmic->regmap, irq, irq_flags, - 0, chip, data); + ret = devm_regmap_add_irq_chip(dev, pmic->regmap, irq, irq_flags, 0, chip, data); + if (ret) + return dev_err_probe(dev, ret, "Failed to add %s IRQ chip\n", chip->name); + + return 0; +} + +static int bxtwc_add_chained_devices(struct intel_soc_pmic *pmic, + const struct mfd_cell *cells, int n_devs, + struct regmap_irq_chip_data *pdata, + int pirq, int irq_flags, + const struct regmap_irq_chip *chip, + struct regmap_irq_chip_data **data) +{ + struct device *dev = pmic->dev; + struct irq_domain *domain; + int ret; + + ret = bxtwc_add_chained_irq_chip(pmic, pdata, pirq, irq_flags, chip, data); + if (ret) + return ret; + + domain = regmap_irq_get_domain(*data); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, cells, n_devs, NULL, 0, domain); } static int bxtwc_probe(struct platform_device *pdev) @@ -467,48 +510,49 @@ static int bxtwc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_tmu_dev, ARRAY_SIZE(bxt_wc_tmu_dev), + pmic->irq_chip_data, + BXTWC_TMU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_tmu, + &pmic->irq_chip_data_tmu); + if (ret) + return ret; + ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, BXTWC_PWRBTN_LVL1_IRQ, IRQF_ONESHOT, &bxtwc_regmap_irq_chip_pwrbtn, &pmic->irq_chip_data_pwrbtn); if (ret) - return dev_err_probe(dev, ret, "Failed to add PWRBTN IRQ chip\n"); - - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_TMU_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_tmu, - &pmic->irq_chip_data_tmu); - if (ret) - return dev_err_probe(dev, ret, "Failed to add TMU IRQ chip\n"); + return ret; - /* Add chained IRQ handler for BCU IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_BCU_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_bcu, - &pmic->irq_chip_data_bcu); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_bcu_dev, ARRAY_SIZE(bxt_wc_bcu_dev), + pmic->irq_chip_data, + BXTWC_BCU_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_bcu, + &pmic->irq_chip_data_bcu); if (ret) - return dev_err_probe(dev, ret, "Failed to add BUC IRQ chip\n"); + return ret; - /* Add chained IRQ handler for ADC IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_ADC_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_adc, - &pmic->irq_chip_data_adc); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_adc_dev, ARRAY_SIZE(bxt_wc_adc_dev), + pmic->irq_chip_data, + BXTWC_ADC_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_adc, + &pmic->irq_chip_data_adc); if (ret) - return dev_err_probe(dev, ret, "Failed to add ADC IRQ chip\n"); + return ret; - /* Add chained IRQ handler for CHGR IRQs */ - ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, - BXTWC_CHGR_LVL1_IRQ, - IRQF_ONESHOT, - &bxtwc_regmap_irq_chip_chgr, - &pmic->irq_chip_data_chgr); + ret = bxtwc_add_chained_devices(pmic, bxt_wc_chgr_dev, ARRAY_SIZE(bxt_wc_chgr_dev), + pmic->irq_chip_data, + BXTWC_CHGR_LVL1_IRQ, + IRQF_ONESHOT, + &bxtwc_regmap_irq_chip_chgr, + &pmic->irq_chip_data_chgr); if (ret) - return dev_err_probe(dev, ret, "Failed to add CHGR IRQ chip\n"); + return ret; /* Add chained IRQ handler for CRIT IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, @@ -517,7 +561,7 @@ static int bxtwc_probe(struct platform_device *pdev) &bxtwc_regmap_irq_chip_crit, &pmic->irq_chip_data_crit); if (ret) - return dev_err_probe(dev, ret, "Failed to add CRIT IRQ chip\n"); + return ret; ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, bxt_wc_dev, ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); @@ -572,7 +616,7 @@ static struct platform_driver bxtwc_driver = { .probe = bxtwc_probe, .shutdown = bxtwc_shutdown, .driver = { - .name = "BXTWC PMIC", + .name = "intel_soc_pmic_bxtwc", .pm = pm_sleep_ptr(&bxtwc_pm_ops), .acpi_match_table = bxtwc_acpi_ids, .dev_groups = bxtwc_groups, @@ -581,5 +625,6 @@ static struct platform_driver bxtwc_driver = { module_platform_driver(bxtwc_driver); +MODULE_DESCRIPTION("Intel Broxton Whiskey Cove PMIC MFD core driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Qipeng Zha <qipeng.zha@intel.com>"); diff --git a/drivers/mfd/intel_soc_pmic_chtdc_ti.c b/drivers/mfd/intel_soc_pmic_chtdc_ti.c index 992855bfda3e..4c1a68c9f575 100644 --- a/drivers/mfd/intel_soc_pmic_chtdc_ti.c +++ b/drivers/mfd/intel_soc_pmic_chtdc_ti.c @@ -81,8 +81,7 @@ static struct mfd_cell chtdc_ti_dev[] = { static const struct regmap_config chtdc_ti_regmap_config = { .reg_bits = 8, .val_bits = 8, - .max_register = 128, - .cache_type = REGCACHE_NONE, + .max_register = 0xff, }; static const struct regmap_irq chtdc_ti_irqs[] = { diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index 7fce3ef7ab45..aa71a7d83fcd 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -178,7 +178,6 @@ static const struct dmi_system_id cht_wc_model_dmi_ids[] = { .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YT3_X90, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), }, }, @@ -268,7 +267,7 @@ static const struct acpi_device_id cht_wc_acpi_ids[] = { static struct i2c_driver cht_wc_driver = { .driver = { - .name = "CHT Whiskey Cove PMIC", + .name = "intel_soc_pmic_chtwc", .pm = pm_sleep_ptr(&cht_wc_pm_ops), .acpi_match_table = cht_wc_acpi_ids, }, diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 581f81cbaa24..41429f9bcb69 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -113,7 +113,6 @@ static const struct regmap_config crystal_cove_regmap_config = { .val_bits = 8, .max_register = CRYSTAL_COVE_MAX_REGISTER, - .cache_type = REGCACHE_NONE, }; static const struct regmap_irq crystal_cove_irqs[] = { @@ -137,7 +136,9 @@ static const struct regmap_irq_chip crystal_cove_irq_chip = { /* PWM consumed by the Intel GFX */ static struct pwm_lookup crc_pwm_lookup[] = { - PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL), + PWM_LOOKUP_WITH_MODULE("crystal_cove_pwm", 0, "0000:00:02.0", + "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL, + "pwm-crc"), }; struct crystal_cove_config { @@ -257,12 +258,19 @@ static const struct acpi_device_id crystal_cove_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, crystal_cove_acpi_match); +static const struct i2c_device_id crystal_cove_i2c_match[] = { + { "intel_soc_pmic_crc" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, crystal_cove_i2c_match); + static struct i2c_driver crystal_cove_i2c_driver = { .driver = { - .name = "crystal_cove_i2c", + .name = "intel_soc_pmic_crc", .pm = pm_sleep_ptr(&crystal_cove_pm_ops), .acpi_match_table = crystal_cove_acpi_match, }, + .id_table = crystal_cove_i2c_match, .probe = crystal_cove_i2c_probe, .remove = crystal_cove_i2c_remove, .shutdown = crystal_cove_shutdown, diff --git a/drivers/mfd/intel_soc_pmic_mrfld.c b/drivers/mfd/intel_soc_pmic_mrfld.c index 71da861e8c27..77121775c1a3 100644 --- a/drivers/mfd/intel_soc_pmic_mrfld.c +++ b/drivers/mfd/intel_soc_pmic_mrfld.c @@ -12,11 +12,10 @@ #include <linux/mfd/intel_soc_pmic.h> #include <linux/mfd/intel_soc_pmic_mrfld.h> #include <linux/module.h> +#include <linux/platform_data/x86/intel_scu_ipc.h> #include <linux/platform_device.h> #include <linux/regmap.h> -#include <asm/intel_scu_ipc.h> - /* * Level 2 IRQs * diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index c964ea6539aa..4b757d847282 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -22,6 +22,7 @@ #include <linux/mfd/core.h> #include <linux/mfd/ipaq-micro.h> #include <linux/string.h> +#include <linux/string_choices.h> #include <linux/random.h> #include <linux/slab.h> #include <linux/list.h> @@ -130,6 +131,7 @@ static void micro_rx_msg(struct ipaq_micro *micro, u8 id, int len, u8 *data) default: dev_err(micro->dev, "unknown msg %d [%d] %*ph\n", id, len, len, data); + break; } spin_unlock(µ->lock); } @@ -266,7 +268,7 @@ static void __init ipaq_micro_eeprom_dump(struct ipaq_micro *micro) dev_info(micro->dev, "page mode: %u\n", ipaq_micro_to_u16(dump+84)); dev_info(micro->dev, "country ID: %u\n", ipaq_micro_to_u16(dump+86)); dev_info(micro->dev, "color display: %s\n", - ipaq_micro_to_u16(dump+88) ? "yes" : "no"); + str_yes_no(ipaq_micro_to_u16(dump + 88))); dev_info(micro->dev, "ROM size: %u MiB\n", ipaq_micro_to_u16(dump+90)); dev_info(micro->dev, "RAM size: %u KiB\n", ipaq_micro_to_u16(dump+92)); dev_info(micro->dev, "screen: %u x %u\n", diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c index 1b465590567c..ee017617d1d1 100644 --- a/drivers/mfd/iqs62x.c +++ b/drivers/mfd/iqs62x.c @@ -31,7 +31,7 @@ #include <linux/property.h> #include <linux/regmap.h> #include <linux/slab.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #define IQS62X_PROD_NUM 0x00 diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 67af36a38913..c5bfb6440a93 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -6,14 +6,17 @@ * Author: Michael Brunner <michael.brunner@kontron.com> */ +#include <linux/err.h> #include <linux/platform_device.h> #include <linux/mfd/core.h> #include <linux/mfd/kempld.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/dmi.h> #include <linux/io.h> #include <linux/delay.h> -#include <linux/acpi.h> +#include <linux/sysfs.h> #define MAX_ID_LEN 4 static char force_device_id[MAX_ID_LEN + 1] = ""; @@ -106,7 +109,7 @@ static int kempld_register_cells_generic(struct kempld_device_data *pld) if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART) devs[i++].name = kempld_dev_names[KEMPLD_UART]; - return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL); + return mfd_add_devices(pld->dev, PLATFORM_DEVID_NONE, devs, i, NULL, 0, NULL); } static struct resource kempld_ioresource = { @@ -126,31 +129,22 @@ static const struct kempld_platform_data kempld_platform_data_generic = { static struct platform_device *kempld_pdev; -static int kempld_create_platform_device(const struct dmi_system_id *id) +static int kempld_create_platform_device(const struct kempld_platform_data *pdata) { - const struct kempld_platform_data *pdata = id->driver_data; - int ret; - - kempld_pdev = platform_device_alloc("kempld", -1); - if (!kempld_pdev) - return -ENOMEM; - - ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata)); - if (ret) - goto err; - - ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1); - if (ret) - goto err; - - ret = platform_device_add(kempld_pdev); - if (ret) - goto err; + const struct platform_device_info pdevinfo = { + .name = "kempld", + .id = PLATFORM_DEVID_NONE, + .res = pdata->ioresource, + .num_res = 1, + .data = pdata, + .size_data = sizeof(*pdata), + }; + + kempld_pdev = platform_device_register_full(&pdevinfo); + if (IS_ERR(kempld_pdev)) + return PTR_ERR(kempld_pdev); return 0; -err: - platform_device_put(kempld_pdev); - return ret; } /** @@ -299,11 +293,8 @@ static int kempld_get_info(struct kempld_device_data *pld) else minor = (pld->info.minor - 10) + 'A'; - ret = scnprintf(pld->info.version, sizeof(pld->info.version), - "P%X%c%c.%04X", pld->info.number, major, minor, - pld->info.buildnr); - if (ret < 0) - return ret; + scnprintf(pld->info.version, sizeof(pld->info.version), "P%X%c%c.%04X", + pld->info.number, major, minor, pld->info.buildnr); return 0; } @@ -372,16 +363,13 @@ static DEVICE_ATTR_RO(pld_version); static DEVICE_ATTR_RO(pld_specification); static DEVICE_ATTR_RO(pld_type); -static struct attribute *pld_attributes[] = { +static struct attribute *pld_attrs[] = { &dev_attr_pld_version.attr, &dev_attr_pld_specification.attr, &dev_attr_pld_type.attr, NULL }; - -static const struct attribute_group pld_attr_group = { - .attrs = pld_attributes, -}; +ATTRIBUTE_GROUPS(pld); static int kempld_detect_device(struct kempld_device_data *pld) { @@ -414,74 +402,9 @@ static int kempld_detect_device(struct kempld_device_data *pld) pld->info.version, kempld_get_type_string(pld), pld->info.spec_major, pld->info.spec_minor); - ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group); - if (ret) - return ret; - - ret = kempld_register_cells(pld); - if (ret) - sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); - - return ret; + return kempld_register_cells(pld); } -#ifdef CONFIG_ACPI -static int kempld_get_acpi_data(struct platform_device *pdev) -{ - struct list_head resource_list; - struct resource *resources; - struct resource_entry *rentry; - struct device *dev = &pdev->dev; - struct acpi_device *acpi_dev = ACPI_COMPANION(dev); - const struct kempld_platform_data *pdata; - int ret; - int count; - - pdata = acpi_device_get_match_data(dev); - ret = platform_device_add_data(pdev, pdata, - sizeof(struct kempld_platform_data)); - if (ret) - return ret; - - INIT_LIST_HEAD(&resource_list); - ret = acpi_dev_get_resources(acpi_dev, &resource_list, NULL, NULL); - if (ret < 0) - goto out; - - count = ret; - - if (count == 0) { - ret = platform_device_add_resources(pdev, pdata->ioresource, 1); - goto out; - } - - resources = devm_kcalloc(&acpi_dev->dev, count, sizeof(*resources), - GFP_KERNEL); - if (!resources) { - ret = -ENOMEM; - goto out; - } - - count = 0; - list_for_each_entry(rentry, &resource_list, node) { - memcpy(&resources[count], rentry->res, - sizeof(*resources)); - count++; - } - ret = platform_device_add_resources(pdev, resources, count); - -out: - acpi_dev_free_resource_list(&resource_list); - - return ret; -} -#else -static int kempld_get_acpi_data(struct platform_device *pdev) -{ - return -ENODEV; -} -#endif /* CONFIG_ACPI */ - static int kempld_probe(struct platform_device *pdev) { const struct kempld_platform_data *pdata; @@ -490,15 +413,21 @@ static int kempld_probe(struct platform_device *pdev) struct resource *ioport; int ret; - if (kempld_pdev == NULL) { + if (IS_ERR_OR_NULL(kempld_pdev)) { /* * No kempld_pdev device has been registered in kempld_init, * so we seem to be probing an ACPI platform device. */ - ret = kempld_get_acpi_data(pdev); + pdata = device_get_match_data(dev); + if (!pdata) + return -ENODEV; + + ret = platform_device_add_data(pdev, pdata, sizeof(*pdata)); if (ret) return ret; - } else if (kempld_pdev != pdev) { + } else if (kempld_pdev == pdev) { + pdata = dev_get_platdata(dev); + } else { /* * The platform device we are probing is not the one we * registered in kempld_init using the DMI table, so this one @@ -509,7 +438,6 @@ static int kempld_probe(struct platform_device *pdev) dev_notice(dev, "platform device exists - not using ACPI\n"); return -ENODEV; } - pdata = dev_get_platdata(dev); pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL); if (!pld) @@ -540,28 +468,25 @@ static void kempld_remove(struct platform_device *pdev) struct kempld_device_data *pld = platform_get_drvdata(pdev); const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); - sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); - mfd_remove_devices(&pdev->dev); pdata->release_hardware_mutex(pld); } -#ifdef CONFIG_ACPI static const struct acpi_device_id kempld_acpi_table[] = { { "KEM0000", (kernel_ulong_t)&kempld_platform_data_generic }, { "KEM0001", (kernel_ulong_t)&kempld_platform_data_generic }, {} }; MODULE_DEVICE_TABLE(acpi, kempld_acpi_table); -#endif static struct platform_driver kempld_driver = { .driver = { .name = "kempld", - .acpi_match_table = ACPI_PTR(kempld_acpi_table), + .acpi_match_table = kempld_acpi_table, + .dev_groups = pld_groups, }, .probe = kempld_probe, - .remove_new = kempld_remove, + .remove = kempld_remove, }; static const struct dmi_system_id kempld_dmi_table[] __initconst = { @@ -571,375 +496,281 @@ static const struct dmi_system_id kempld_dmi_table[] __initconst = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "BBL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bBL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "BDV7", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bDV7"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "BHL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "BKL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "BSL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CAL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CBL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cBL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CBW6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cBW6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CCR2", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CCR6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CDV7", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cDV7"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CHL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CHR2", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CHR2", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CHR2", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CHR6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CHR6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CHR6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CKL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CNTG", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CNTG", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CNTX", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "PXT"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CSL6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cSL6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "CVV6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "FRI2", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BIOS_VERSION, "FRI2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "FRI2", .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "A203", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "KBox A-203"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "M4A1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-m4AL"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "MAL1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-mAL10"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "MAPL", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "mITX-APL"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "MBR1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "MVV1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "NTC1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "NTC1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "NTC1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "NUP1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "PAPL", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "pITX-APL"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "SXAL", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXAL"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "SXAL4", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXA4"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "UNP1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "UNP1", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "UNTG", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "UNTG", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "UUP6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "UTH6", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, { .ident = "Q7AL", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), DMI_MATCH(DMI_BOARD_NAME, "Qseven-Q7AL"), }, - .driver_data = (void *)&kempld_platform_data_generic, - .callback = kempld_create_platform_device, }, {} }; @@ -948,27 +779,28 @@ MODULE_DEVICE_TABLE(dmi, kempld_dmi_table); static int __init kempld_init(void) { const struct dmi_system_id *id; + int ret = -ENODEV; - if (force_device_id[0]) { - for (id = kempld_dmi_table; - id->matches[0].slot != DMI_NONE; id++) - if (strstr(id->ident, force_device_id)) - if (id->callback && !id->callback(id)) - break; - if (id->matches[0].slot == DMI_NONE) - return -ENODEV; - } else { - dmi_check_system(kempld_dmi_table); + for (id = dmi_first_match(kempld_dmi_table); id; id = dmi_first_match(id + 1)) { + /* Check, if user asked for the exact device ID match */ + if (force_device_id[0] && !strstr(id->ident, force_device_id)) + continue; + + ret = kempld_create_platform_device(&kempld_platform_data_generic); + if (ret) + continue; + + break; } + if (ret) + return ret; return platform_driver_register(&kempld_driver); } static void __exit kempld_exit(void) { - if (kempld_pdev) - platform_device_unregister(kempld_pdev); - + platform_device_unregister(kempld_pdev); platform_driver_unregister(&kempld_driver); } diff --git a/drivers/mfd/khadas-mcu.c b/drivers/mfd/khadas-mcu.c index 61396d824f16..ba981a788692 100644 --- a/drivers/mfd/khadas-mcu.c +++ b/drivers/mfd/khadas-mcu.c @@ -72,7 +72,7 @@ static const struct regmap_config khadas_mcu_regmap_config = { .max_register = KHADAS_MCU_CMD_FAN_STATUS_CTRL_REG, .volatile_reg = khadas_mcu_reg_volatile, .writeable_reg = khadas_mcu_reg_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static struct mfd_cell khadas_mcu_fan_cells[] = { diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index c211183cecb2..0a2409d00b2e 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -11,7 +11,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/mfd/core.h> #include <linux/regmap.h> @@ -225,14 +225,12 @@ static int lm3533_set_lvled_config(struct lm3533 *lm3533, u8 lvled, u8 led) static void lm3533_enable(struct lm3533 *lm3533) { - if (gpio_is_valid(lm3533->gpio_hwen)) - gpio_set_value(lm3533->gpio_hwen, 1); + gpiod_set_value(lm3533->hwen, 1); } static void lm3533_disable(struct lm3533 *lm3533) { - if (gpio_is_valid(lm3533->gpio_hwen)) - gpio_set_value(lm3533->gpio_hwen, 0); + gpiod_set_value(lm3533->hwen, 0); } enum lm3533_attribute_type { @@ -483,18 +481,10 @@ static int lm3533_device_init(struct lm3533 *lm3533) return -EINVAL; } - lm3533->gpio_hwen = pdata->gpio_hwen; - - if (gpio_is_valid(lm3533->gpio_hwen)) { - ret = devm_gpio_request_one(lm3533->dev, lm3533->gpio_hwen, - GPIOF_OUT_INIT_LOW, "lm3533-hwen"); - if (ret < 0) { - dev_err(lm3533->dev, - "failed to request HWEN GPIO %d\n", - lm3533->gpio_hwen); - return ret; - } - } + lm3533->hwen = devm_gpiod_get(lm3533->dev, NULL, GPIOD_OUT_LOW); + if (IS_ERR(lm3533->hwen)) + return dev_err_probe(lm3533->dev, PTR_ERR(lm3533->hwen), "failed to request HWEN GPIO\n"); + gpiod_set_consumer_name(lm3533->hwen, "lm3533-hwen"); lm3533_enable(lm3533); @@ -614,8 +604,8 @@ static void lm3533_i2c_remove(struct i2c_client *i2c) } static const struct i2c_device_id lm3533_i2c_ids[] = { - { "lm3533", 0 }, - { }, + { "lm3533" }, + { } }; MODULE_DEVICE_TABLE(i2c, lm3533_i2c_ids); diff --git a/drivers/mfd/lochnagar-i2c.c b/drivers/mfd/lochnagar-i2c.c index 0b76fcccd0bd..6c930c57f2e2 100644 --- a/drivers/mfd/lochnagar-i2c.c +++ b/drivers/mfd/lochnagar-i2c.c @@ -70,7 +70,7 @@ static const struct regmap_config lochnagar1_i2c_regmap = { .use_single_read = true, .use_single_write = true, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct reg_sequence lochnagar1_patch[] = { @@ -163,7 +163,7 @@ static const struct regmap_config lochnagar2_i2c_regmap = { .readable_reg = lochnagar2_readable_register, .volatile_reg = lochnagar2_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct reg_sequence lochnagar2_patch[] = { diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c index 7f749a23dca8..6764553147e4 100644 --- a/drivers/mfd/lp3943.c +++ b/drivers/mfd/lp3943.c @@ -126,7 +126,7 @@ static int lp3943_probe(struct i2c_client *cl) } static const struct i2c_device_id lp3943_ids[] = { - { "lp3943", 0 }, + { "lp3943" }, { } }; MODULE_DEVICE_TABLE(i2c, lp3943_ids); diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c index de7ab7aed3c6..e8c5c89c2a76 100644 --- a/drivers/mfd/lp873x.c +++ b/drivers/mfd/lp873x.c @@ -68,8 +68,8 @@ static const struct of_device_id of_lp873x_match_table[] = { MODULE_DEVICE_TABLE(of, of_lp873x_match_table); static const struct i2c_device_id lp873x_id_table[] = { - { "lp873x", 0 }, - { }, + { "lp873x" }, + { } }; MODULE_DEVICE_TABLE(i2c, lp873x_id_table); diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c index 08c62ddfb4f5..9488d3793c10 100644 --- a/drivers/mfd/lp87565.c +++ b/drivers/mfd/lp87565.c @@ -106,8 +106,8 @@ static void lp87565_shutdown(struct i2c_client *client) } static const struct i2c_device_id lp87565_id_table[] = { - { "lp87565-q1", 0 }, - { }, + { "lp87565-q1" }, + { } }; MODULE_DEVICE_TABLE(i2c, lp87565_id_table); diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c index 39006297f3d2..ea0fdf7a4b6e 100644 --- a/drivers/mfd/lp8788-irq.c +++ b/drivers/mfd/lp8788-irq.c @@ -161,7 +161,7 @@ int lp8788_irq_init(struct lp8788 *lp, int irq) return -ENOMEM; irqd->lp = lp; - irqd->domain = irq_domain_add_linear(lp->dev->of_node, LP8788_INT_MAX, + irqd->domain = irq_domain_create_linear(of_fwnode_handle(lp->dev->of_node), LP8788_INT_MAX, &lp8788_domain_ops, irqd); if (!irqd->domain) { dev_err(lp->dev, "failed to add irq domain err\n"); diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index f371eeb042e0..32f255378f5a 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -216,7 +216,7 @@ static void lp8788_remove(struct i2c_client *cl) } static const struct i2c_device_id lp8788_ids[] = { - {"lp8788", 0}, + { "lp8788" }, { } }; MODULE_DEVICE_TABLE(i2c, lp8788_ids); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 73a0e7f9bd31..4b7d0cb9340f 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -38,6 +38,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/align.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/errno.h> @@ -833,8 +834,9 @@ static const struct pci_device_id lpc_ich_ids[] = { { PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME}, { PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9}, { PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M}, - { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK}, { PCI_VDEVICE(INTEL, 0x2b9c), LPC_COUGARMOUNTAIN}, + { PCI_VDEVICE(INTEL, 0x3197), LPC_GLK}, + { PCI_VDEVICE(INTEL, 0x31e8), LPC_GLK}, { PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO}, { PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R}, { PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10}, @@ -1321,7 +1323,7 @@ static int lpc_ich_init_spi(struct pci_dev *dev) case INTEL_SPI_BYT: pci_read_config_dword(dev, SPIBASE_BYT, &spi_base); if (spi_base & SPIBASE_BYT_EN) { - res->start = spi_base & ~(SPIBASE_BYT_SZ - 1); + res->start = ALIGN_DOWN(spi_base, SPIBASE_BYT_SZ); res->end = res->start + SPIBASE_BYT_SZ - 1; info->set_writeable = lpc_ich_byt_set_writeable; diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c index ad07ebe29e59..ce9e90322c9c 100644 --- a/drivers/mfd/madera-spi.c +++ b/drivers/mfd/madera-spi.c @@ -18,21 +18,14 @@ static int madera_spi_probe(struct spi_device *spi) { - const struct spi_device_id *id = spi_get_device_id(spi); struct madera *madera; const struct regmap_config *regmap_16bit_config = NULL; const struct regmap_config *regmap_32bit_config = NULL; - const void *of_data; unsigned long type; const char *name; int ret; - of_data = of_device_get_match_data(&spi->dev); - if (of_data) - type = (unsigned long)of_data; - else - type = id->driver_data; - + type = (unsigned long)spi_get_device_match_data(spi); switch (type) { case CS47L15: if (IS_ENABLED(CONFIG_MFD_CS47L15)) { diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 8f7472c76009..7e7e8af9af22 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -143,6 +143,7 @@ static const struct of_device_id max14577_dt_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, max14577_dt_match); static bool max14577_muic_volatile_reg(struct device *dev, unsigned int reg) { @@ -397,7 +398,7 @@ static int max14577_i2c_probe(struct i2c_client *i2c) return ret; } - max14577->dev_type = (enum maxim_device_type)i2c_get_match_data(i2c); + max14577->dev_type = (kernel_ulong_t)i2c_get_match_data(i2c); max14577_print_dev_type(max14577); @@ -455,6 +456,7 @@ static void max14577_i2c_remove(struct i2c_client *i2c) { struct max14577 *max14577 = i2c_get_clientdata(i2c); + device_init_wakeup(max14577->dev, false); mfd_remove_devices(max14577->dev); regmap_del_irq_chip(max14577->irq, max14577->irq_data); if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) diff --git a/drivers/mfd/max77541.c b/drivers/mfd/max77541.c index d77c31c86e43..f91b4f5373ce 100644 --- a/drivers/mfd/max77541.c +++ b/drivers/mfd/max77541.c @@ -152,7 +152,7 @@ static int max77541_pmic_setup(struct device *dev) if (ret) return dev_err_probe(dev, ret, "Failed to initialize IRQ\n"); - ret = device_init_wakeup(dev, true); + ret = devm_device_init_wakeup(dev); if (ret) return dev_err_probe(dev, ret, "Unable to init wakeup\n"); diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index 74ef3f6d576c..21d2ab3db254 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -29,6 +29,7 @@ #include <linux/mfd/core.h> #include <linux/mfd/max77620.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -400,7 +401,7 @@ static int max77620_config_fps(struct max77620_chip *chip, static int max77620_initialise_fps(struct max77620_chip *chip) { struct device *dev = chip->dev; - struct device_node *fps_np, *fps_child; + struct device_node *fps_np; u8 config; int fps_id; int ret; @@ -414,10 +415,9 @@ static int max77620_initialise_fps(struct max77620_chip *chip) if (!fps_np) goto skip_fps; - for_each_child_of_node(fps_np, fps_child) { + for_each_child_of_node_scoped(fps_np, fps_child) { ret = max77620_config_fps(chip, fps_child); if (ret < 0) { - of_node_put(fps_child); of_node_put(fps_np); return ret; } @@ -701,3 +701,7 @@ static struct i2c_driver max77620_driver = { .id_table = max77620_id, }; builtin_i2c_driver(max77620_driver); + +MODULE_DESCRIPTION("Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/max77705.c b/drivers/mfd/max77705.c new file mode 100644 index 000000000000..6b263bacb8c2 --- /dev/null +++ b/drivers/mfd/max77705.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Maxim MAX77705 PMIC core driver + * + * Copyright (C) 2025 Dzmitry Sankouski <dsankouski@gmail.com> + **/ +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/mfd/max77705-private.h> +#include <linux/mfd/max77693-common.h> +#include <linux/pm.h> +#include <linux/power/max17042_battery.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/of.h> + +static struct mfd_cell max77705_devs[] = { + MFD_CELL_OF("max77705-rgb", NULL, NULL, 0, 0, "maxim,max77705-rgb"), + MFD_CELL_OF("max77705-charger", NULL, NULL, 0, 0, "maxim,max77705-charger"), + MFD_CELL_OF("max77705-haptic", NULL, NULL, 0, 0, "maxim,max77705-haptic"), +}; + +static const struct regmap_range max77705_readable_ranges[] = { + regmap_reg_range(MAX77705_PMIC_REG_PMICID1, MAX77705_PMIC_REG_BSTOUT_MASK), + regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29), + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), + regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2), + regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK), + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2), + regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET), +}; + +static const struct regmap_range max77705_writable_ranges[] = { + regmap_reg_range(MAX77705_PMIC_REG_MAINCTRL1, MAX77705_PMIC_REG_BSTOUT_MASK), + regmap_reg_range(MAX77705_PMIC_REG_INTSRC, MAX77705_PMIC_REG_RESERVED_29), + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), + regmap_reg_range(MAX77705_PMIC_REG_MCONFIG, MAX77705_PMIC_REG_MCONFIG2), + regmap_reg_range(MAX77705_PMIC_REG_FORCE_EN_MASK, MAX77705_PMIC_REG_FORCE_EN_MASK), + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL1, MAX77705_PMIC_REG_BOOSTCONTROL1), + regmap_reg_range(MAX77705_PMIC_REG_BOOSTCONTROL2, MAX77705_PMIC_REG_BOOSTCONTROL2), + regmap_reg_range(MAX77705_PMIC_REG_SW_RESET, MAX77705_PMIC_REG_USBC_RESET), +}; + +static const struct regmap_access_table max77705_readable_table = { + .yes_ranges = max77705_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(max77705_readable_ranges), +}; + +static const struct regmap_access_table max77705_writable_table = { + .yes_ranges = max77705_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(max77705_writable_ranges), +}; + +static const struct regmap_config max77705_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .rd_table = &max77705_readable_table, + .wr_table = &max77705_writable_table, + .max_register = MAX77705_PMIC_REG_USBC_RESET, +}; + +static const struct regmap_irq max77705_topsys_irqs[] = { + { .mask = MAX77705_SYSTEM_IRQ_BSTEN_INT, }, + { .mask = MAX77705_SYSTEM_IRQ_SYSUVLO_INT, }, + { .mask = MAX77705_SYSTEM_IRQ_SYSOVLO_INT, }, + { .mask = MAX77705_SYSTEM_IRQ_TSHDN_INT, }, + { .mask = MAX77705_SYSTEM_IRQ_TM_INT, }, +}; + +static const struct regmap_irq_chip max77705_topsys_irq_chip = { + .name = "max77705-topsys", + .status_base = MAX77705_PMIC_REG_SYSTEM_INT, + .mask_base = MAX77705_PMIC_REG_SYSTEM_INT_MASK, + .num_regs = 1, + .irqs = max77705_topsys_irqs, + .num_irqs = ARRAY_SIZE(max77705_topsys_irqs), +}; + +static int max77705_i2c_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct max77693_dev *max77705; + struct regmap_irq_chip_data *irq_data; + struct irq_domain *domain; + enum max77705_hw_rev pmic_rev; + unsigned int pmic_rev_value; + int ret; + + max77705 = devm_kzalloc(dev, sizeof(*max77705), GFP_KERNEL); + if (!max77705) + return -ENOMEM; + + max77705->i2c = i2c; + max77705->type = TYPE_MAX77705; + i2c_set_clientdata(i2c, max77705); + + max77705->regmap = devm_regmap_init_i2c(i2c, &max77705_regmap_config); + if (IS_ERR(max77705->regmap)) + return PTR_ERR(max77705->regmap); + + ret = regmap_read(max77705->regmap, MAX77705_PMIC_REG_PMICREV, &pmic_rev_value); + if (ret < 0) + return -ENODEV; + + pmic_rev = pmic_rev_value & MAX77705_REVISION_MASK; + if (pmic_rev != MAX77705_PASS3) + return dev_err_probe(dev, -ENODEV, "Rev.0x%x is not tested\n", pmic_rev); + + ret = devm_regmap_add_irq_chip(dev, max77705->regmap, + i2c->irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &max77705_topsys_irq_chip, + &irq_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); + + /* Unmask interrupts from all blocks in interrupt source register */ + ret = regmap_update_bits(max77705->regmap, + MAX77705_PMIC_REG_INTSRC_MASK, + MAX77705_SRC_IRQ_ALL, (unsigned int)~MAX77705_SRC_IRQ_ALL); + if (ret < 0) + return dev_err_probe(dev, ret, "Could not unmask interrupts in INTSRC\n"); + + domain = regmap_irq_get_domain(irq_data); + + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, + max77705_devs, ARRAY_SIZE(max77705_devs), + NULL, 0, domain); + if (ret) + return dev_err_probe(dev, ret, "Failed to register child devices\n"); + + ret = devm_device_init_wakeup(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to init wakeup\n"); + + return 0; +} + +static int max77705_suspend(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + + disable_irq(i2c->irq); + + if (device_may_wakeup(dev)) + enable_irq_wake(i2c->irq); + + return 0; +} + +static int max77705_resume(struct device *dev) +{ + struct i2c_client *i2c = to_i2c_client(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(i2c->irq); + + enable_irq(i2c->irq); + + return 0; +} +DEFINE_SIMPLE_DEV_PM_OPS(max77705_pm_ops, max77705_suspend, max77705_resume); + +static const struct of_device_id max77705_i2c_of_match[] = { + { .compatible = "maxim,max77705" }, + { } +}; +MODULE_DEVICE_TABLE(of, max77705_i2c_of_match); + +static struct i2c_driver max77705_i2c_driver = { + .driver = { + .name = "max77705", + .of_match_table = max77705_i2c_of_match, + .pm = pm_sleep_ptr(&max77705_pm_ops), + }, + .probe = max77705_i2c_probe +}; +module_i2c_driver(max77705_i2c_driver); + +MODULE_DESCRIPTION("Maxim MAX77705 PMIC core driver"); +MODULE_AUTHOR("Dzmitry Sankouski <dsankouski@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c new file mode 100644 index 000000000000..6cf6306c4a3b --- /dev/null +++ b/drivers/mfd/max77759.c @@ -0,0 +1,690 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2020 Google Inc + * Copyright 2025 Linaro Ltd. + * + * Core driver for Maxim MAX77759 companion PMIC for USB Type-C + */ + +#include <linux/array_size.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/cleanup.h> +#include <linux/completion.h> +#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/jiffies.h> +#include <linux/mfd/core.h> +#include <linux/mfd/max77759.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/overflow.h> +#include <linux/regmap.h> + +/* Chip ID as per MAX77759_PMIC_REG_PMIC_ID */ +enum { + MAX77759_CHIP_ID = 59, +}; + +enum max77759_i2c_subdev_id { + /* + * These are arbitrary and simply used to match struct + * max77759_i2c_subdev entries to the regmap pointers in struct + * max77759 during probe(). + */ + MAX77759_I2C_SUBDEV_ID_MAXQ, + MAX77759_I2C_SUBDEV_ID_CHARGER, +}; + +struct max77759_i2c_subdev { + enum max77759_i2c_subdev_id id; + const struct regmap_config *cfg; + u16 i2c_address; +}; + +static const struct regmap_range max77759_top_registers[] = { + regmap_reg_range(0x00, 0x02), /* PMIC_ID / PMIC_REVISION / OTP_REVISION */ + regmap_reg_range(0x22, 0x24), /* INTSRC / INTSRCMASK / TOPSYS_INT */ + regmap_reg_range(0x26, 0x26), /* TOPSYS_INT_MASK */ + regmap_reg_range(0x40, 0x40), /* I2C_CNFG */ + regmap_reg_range(0x50, 0x51), /* SWRESET / CONTROL_FG */ +}; + +static const struct regmap_range max77759_top_ro_registers[] = { + regmap_reg_range(0x00, 0x02), + regmap_reg_range(0x22, 0x22), +}; + +static const struct regmap_range max77759_top_volatile_registers[] = { + regmap_reg_range(0x22, 0x22), + regmap_reg_range(0x24, 0x24), +}; + +static const struct regmap_access_table max77759_top_wr_table = { + .yes_ranges = max77759_top_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_top_registers), + .no_ranges = max77759_top_ro_registers, + .n_no_ranges = ARRAY_SIZE(max77759_top_ro_registers), +}; + +static const struct regmap_access_table max77759_top_rd_table = { + .yes_ranges = max77759_top_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_top_registers), +}; + +static const struct regmap_access_table max77759_top_volatile_table = { + .yes_ranges = max77759_top_volatile_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_top_volatile_registers), +}; + +static const struct regmap_config max77759_regmap_config_top = { + .name = "top", + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX77759_PMIC_REG_CONTROL_FG, + .wr_table = &max77759_top_wr_table, + .rd_table = &max77759_top_rd_table, + .volatile_table = &max77759_top_volatile_table, + .num_reg_defaults_raw = MAX77759_PMIC_REG_CONTROL_FG + 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range max77759_maxq_registers[] = { + regmap_reg_range(0x60, 0x73), /* Device ID, Rev, INTx, STATUSx, MASKx */ + regmap_reg_range(0x81, 0xa1), /* AP_DATAOUTx */ + regmap_reg_range(0xb1, 0xd1), /* AP_DATAINx */ + regmap_reg_range(0xe0, 0xe0), /* UIC_SWRST */ +}; + +static const struct regmap_range max77759_maxq_ro_registers[] = { + regmap_reg_range(0x60, 0x63), /* Device ID, Rev */ + regmap_reg_range(0x68, 0x6f), /* STATUSx */ + regmap_reg_range(0xb1, 0xd1), +}; + +static const struct regmap_range max77759_maxq_volatile_registers[] = { + regmap_reg_range(0x64, 0x6f), /* INTx, STATUSx */ + regmap_reg_range(0xb1, 0xd1), + regmap_reg_range(0xe0, 0xe0), +}; + +static const struct regmap_access_table max77759_maxq_wr_table = { + .yes_ranges = max77759_maxq_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_maxq_registers), + .no_ranges = max77759_maxq_ro_registers, + .n_no_ranges = ARRAY_SIZE(max77759_maxq_ro_registers), +}; + +static const struct regmap_access_table max77759_maxq_rd_table = { + .yes_ranges = max77759_maxq_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_maxq_registers), +}; + +static const struct regmap_access_table max77759_maxq_volatile_table = { + .yes_ranges = max77759_maxq_volatile_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_maxq_volatile_registers), +}; + +static const struct regmap_config max77759_regmap_config_maxq = { + .name = "maxq", + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX77759_MAXQ_REG_UIC_SWRST, + .wr_table = &max77759_maxq_wr_table, + .rd_table = &max77759_maxq_rd_table, + .volatile_table = &max77759_maxq_volatile_table, + .num_reg_defaults_raw = MAX77759_MAXQ_REG_UIC_SWRST + 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range max77759_charger_registers[] = { + regmap_reg_range(0xb0, 0xcc), +}; + +static const struct regmap_range max77759_charger_ro_registers[] = { + regmap_reg_range(0xb4, 0xb8), /* INT_OK, DETAILS_0x */ +}; + +static const struct regmap_range max77759_charger_volatile_registers[] = { + regmap_reg_range(0xb0, 0xb1), /* INTx */ + regmap_reg_range(0xb4, 0xb8), +}; + +static const struct regmap_access_table max77759_charger_wr_table = { + .yes_ranges = max77759_charger_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_charger_registers), + .no_ranges = max77759_charger_ro_registers, + .n_no_ranges = ARRAY_SIZE(max77759_charger_ro_registers), +}; + +static const struct regmap_access_table max77759_charger_rd_table = { + .yes_ranges = max77759_charger_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_charger_registers), +}; + +static const struct regmap_access_table max77759_charger_volatile_table = { + .yes_ranges = max77759_charger_volatile_registers, + .n_yes_ranges = ARRAY_SIZE(max77759_charger_volatile_registers), +}; + +static const struct regmap_config max77759_regmap_config_charger = { + .name = "charger", + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX77759_CHGR_REG_CHG_CNFG_19, + .wr_table = &max77759_charger_wr_table, + .rd_table = &max77759_charger_rd_table, + .volatile_table = &max77759_charger_volatile_table, + .num_reg_defaults_raw = MAX77759_CHGR_REG_CHG_CNFG_19 + 1, + .cache_type = REGCACHE_FLAT, +}; + +/* + * Interrupts - with the following interrupt hierarchy: + * pmic IRQs (INTSRC) + * - MAXQ_INT: MaxQ IRQs + * - UIC_INT1 + * - APCmdResI + * - SysMsgI + * - GPIOxI + * - TOPSYS_INT: topsys + * - TOPSYS_INT + * - TSHDN_INT + * - SYSOVLO_INT + * - SYSUVLO_INT + * - FSHIP_NOT_RD + * - CHGR_INT: charger + * - CHG_INT + * - CHG_INT2 + */ +enum { + MAX77759_INT_MAXQ, + MAX77759_INT_TOPSYS, + MAX77759_INT_CHGR, +}; + +enum { + MAX77759_TOPSYS_INT_TSHDN, + MAX77759_TOPSYS_INT_SYSOVLO, + MAX77759_TOPSYS_INT_SYSUVLO, + MAX77759_TOPSYS_INT_FSHIP_NOT_RD, +}; + +enum { + MAX77759_MAXQ_INT_APCMDRESI, + MAX77759_MAXQ_INT_SYSMSGI, + MAX77759_MAXQ_INT_GPIO, + MAX77759_MAXQ_INT_UIC1, + MAX77759_MAXQ_INT_UIC2, + MAX77759_MAXQ_INT_UIC3, + MAX77759_MAXQ_INT_UIC4, +}; + +enum { + MAX77759_CHARGER_INT_1, + MAX77759_CHARGER_INT_2, +}; + +static const struct regmap_irq max77759_pmic_irqs[] = { + REGMAP_IRQ_REG(MAX77759_INT_MAXQ, 0, MAX77759_PMIC_REG_INTSRC_MAXQ), + REGMAP_IRQ_REG(MAX77759_INT_TOPSYS, 0, MAX77759_PMIC_REG_INTSRC_TOPSYS), + REGMAP_IRQ_REG(MAX77759_INT_CHGR, 0, MAX77759_PMIC_REG_INTSRC_CHGR), +}; + +static const struct regmap_irq max77759_maxq_irqs[] = { + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_APCMDRESI, 0, MAX77759_MAXQ_REG_UIC_INT1_APCMDRESI), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_SYSMSGI, 0, MAX77759_MAXQ_REG_UIC_INT1_SYSMSGI), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_GPIO, 0, GENMASK(1, 0)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC1, 0, GENMASK(5, 2)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC2, 1, GENMASK(7, 0)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC3, 2, GENMASK(7, 0)), + REGMAP_IRQ_REG(MAX77759_MAXQ_INT_UIC4, 3, GENMASK(7, 0)), +}; + +static const struct regmap_irq max77759_topsys_irqs[] = { + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_TSHDN, 0, MAX77759_PMIC_REG_TOPSYS_INT_TSHDN), + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_SYSOVLO, 0, MAX77759_PMIC_REG_TOPSYS_INT_SYSOVLO), + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_SYSUVLO, 0, MAX77759_PMIC_REG_TOPSYS_INT_SYSUVLO), + REGMAP_IRQ_REG(MAX77759_TOPSYS_INT_FSHIP_NOT_RD, 0, MAX77759_PMIC_REG_TOPSYS_INT_FSHIP), +}; + +static const struct regmap_irq max77759_chgr_irqs[] = { + REGMAP_IRQ_REG(MAX77759_CHARGER_INT_1, 0, GENMASK(7, 0)), + REGMAP_IRQ_REG(MAX77759_CHARGER_INT_2, 1, GENMASK(7, 0)), +}; + +static const struct regmap_irq_chip max77759_pmic_irq_chip = { + .name = "max77759-pmic", + /* INTSRC is read-only and doesn't require clearing */ + .status_base = MAX77759_PMIC_REG_INTSRC, + .mask_base = MAX77759_PMIC_REG_INTSRCMASK, + .num_regs = 1, + .irqs = max77759_pmic_irqs, + .num_irqs = ARRAY_SIZE(max77759_pmic_irqs), +}; + +/* + * We can let regmap-irq auto-ack the topsys interrupt bits as required, but + * for all others the individual drivers need to know which interrupt bit + * exactly is set inside their interrupt handlers, and therefore we can not set + * .ack_base for those. + */ +static const struct regmap_irq_chip max77759_maxq_irq_chip = { + .name = "max77759-maxq", + .domain_suffix = "MAXQ", + .status_base = MAX77759_MAXQ_REG_UIC_INT1, + .mask_base = MAX77759_MAXQ_REG_UIC_INT1_M, + .num_regs = 4, + .irqs = max77759_maxq_irqs, + .num_irqs = ARRAY_SIZE(max77759_maxq_irqs), +}; + +static const struct regmap_irq_chip max77759_topsys_irq_chip = { + .name = "max77759-topsys", + .domain_suffix = "TOPSYS", + .status_base = MAX77759_PMIC_REG_TOPSYS_INT, + .mask_base = MAX77759_PMIC_REG_TOPSYS_INT_MASK, + .ack_base = MAX77759_PMIC_REG_TOPSYS_INT, + .num_regs = 1, + .irqs = max77759_topsys_irqs, + .num_irqs = ARRAY_SIZE(max77759_topsys_irqs), +}; + +static const struct regmap_irq_chip max77759_chrg_irq_chip = { + .name = "max77759-chgr", + .domain_suffix = "CHGR", + .status_base = MAX77759_CHGR_REG_CHG_INT, + .mask_base = MAX77759_CHGR_REG_CHG_INT_MASK, + .num_regs = 2, + .irqs = max77759_chgr_irqs, + .num_irqs = ARRAY_SIZE(max77759_chgr_irqs), +}; + +static const struct max77759_i2c_subdev max77759_i2c_subdevs[] = { + { + .id = MAX77759_I2C_SUBDEV_ID_MAXQ, + .cfg = &max77759_regmap_config_maxq, + /* I2C address is same as for sub-block 'top' */ + }, + { + .id = MAX77759_I2C_SUBDEV_ID_CHARGER, + .cfg = &max77759_regmap_config_charger, + .i2c_address = 0x69, + }, +}; + +static const struct resource max77759_gpio_resources[] = { + DEFINE_RES_IRQ_NAMED(MAX77759_MAXQ_INT_GPIO, "GPI"), +}; + +static const struct resource max77759_charger_resources[] = { + DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_1, "INT1"), + DEFINE_RES_IRQ_NAMED(MAX77759_CHARGER_INT_2, "INT2"), +}; + +static const struct mfd_cell max77759_cells[] = { + MFD_CELL_OF("max77759-nvmem", NULL, NULL, 0, 0, + "maxim,max77759-nvmem"), +}; + +static const struct mfd_cell max77759_maxq_cells[] = { + MFD_CELL_OF("max77759-gpio", max77759_gpio_resources, NULL, 0, 0, + "maxim,max77759-gpio"), +}; + +static const struct mfd_cell max77759_charger_cells[] = { + MFD_CELL_RES("max77759-charger", max77759_charger_resources), +}; + +int max77759_maxq_command(struct max77759 *max77759, + const struct max77759_maxq_command *cmd, + struct max77759_maxq_response *rsp) +{ + DEFINE_FLEX(struct max77759_maxq_response, _rsp, rsp, length, 1); + struct device *dev = regmap_get_device(max77759->regmap_maxq); + static const unsigned int timeout_ms = 200; + int ret; + + if (cmd->length > MAX77759_MAXQ_OPCODE_MAXLENGTH) + return -EINVAL; + + /* + * As a convenience for API users when issuing simple commands, rsp is + * allowed to be NULL. In that case we need a temporary here to write + * the response to, as we need to verify that the command was indeed + * completed correctly. + */ + if (!rsp) + rsp = _rsp; + + if (!rsp->length || rsp->length > MAX77759_MAXQ_OPCODE_MAXLENGTH) + return -EINVAL; + + guard(mutex)(&max77759->maxq_lock); + + reinit_completion(&max77759->cmd_done); + + /* + * MaxQ latches the message when the DATAOUT32 register is written. If + * cmd->length is shorter we still need to write 0 to it. + */ + ret = regmap_bulk_write(max77759->regmap_maxq, + MAX77759_MAXQ_REG_AP_DATAOUT0, cmd->cmd, + cmd->length); + if (!ret && cmd->length < MAX77759_MAXQ_OPCODE_MAXLENGTH) + ret = regmap_write(max77759->regmap_maxq, + MAX77759_MAXQ_REG_AP_DATAOUT32, 0); + if (ret) { + dev_err(dev, "writing command failed: %d\n", ret); + return ret; + } + + /* Wait for response from MaxQ */ + if (!wait_for_completion_timeout(&max77759->cmd_done, + msecs_to_jiffies(timeout_ms))) { + dev_err(dev, "timed out waiting for response\n"); + return -ETIMEDOUT; + } + + ret = regmap_bulk_read(max77759->regmap_maxq, + MAX77759_MAXQ_REG_AP_DATAIN0, + rsp->rsp, rsp->length); + if (ret) { + dev_err(dev, "reading response failed: %d\n", ret); + return ret; + } + + /* + * As per the protocol, the first byte of the reply will match the + * request. + */ + if (cmd->cmd[0] != rsp->rsp[0]) { + dev_err(dev, "unexpected opcode response for %#.2x: %*ph\n", + cmd->cmd[0], (int)rsp->length, rsp->rsp); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_GPL(max77759_maxq_command); + +static irqreturn_t apcmdres_irq_handler(int irq, void *irq_data) +{ + struct max77759 *max77759 = irq_data; + + regmap_write(max77759->regmap_maxq, MAX77759_MAXQ_REG_UIC_INT1, + MAX77759_MAXQ_REG_UIC_INT1_APCMDRESI); + + complete(&max77759->cmd_done); + + return IRQ_HANDLED; +} + +static int max77759_create_i2c_subdev(struct i2c_client *client, + struct max77759 *max77759, + const struct max77759_i2c_subdev *sd) +{ + struct i2c_client *sub; + struct regmap *regmap; + int ret; + + /* + * If 'sd' has an I2C address, 'sub' will be assigned a new 'dummy' + * device, otherwise use it as-is. + */ + sub = client; + if (sd->i2c_address) { + sub = devm_i2c_new_dummy_device(&client->dev, + client->adapter, + sd->i2c_address); + + if (IS_ERR(sub)) + return dev_err_probe(&client->dev, PTR_ERR(sub), + "failed to claim I2C device %s\n", + sd->cfg->name); + } + + regmap = devm_regmap_init_i2c(sub, sd->cfg); + if (IS_ERR(regmap)) + return dev_err_probe(&sub->dev, PTR_ERR(regmap), + "regmap init for '%s' failed\n", + sd->cfg->name); + + ret = regmap_attach_dev(&client->dev, regmap, sd->cfg); + if (ret) + return dev_err_probe(&client->dev, ret, + "regmap attach of '%s' failed\n", + sd->cfg->name); + + if (sd->id == MAX77759_I2C_SUBDEV_ID_MAXQ) + max77759->regmap_maxq = regmap; + else if (sd->id == MAX77759_I2C_SUBDEV_ID_CHARGER) + max77759->regmap_charger = regmap; + + return 0; +} + +static int max77759_add_chained_irq_chip(struct device *dev, + struct regmap *regmap, + int pirq, + struct regmap_irq_chip_data *parent, + const struct regmap_irq_chip *chip, + struct regmap_irq_chip_data **data) +{ + int irq, ret; + + irq = regmap_irq_get_virq(parent, pirq); + if (irq < 0) + return dev_err_probe(dev, irq, + "failed to get parent vIRQ(%d) for chip %s\n", + pirq, chip->name); + + ret = devm_regmap_add_irq_chip(dev, regmap, irq, + IRQF_ONESHOT | IRQF_SHARED, 0, chip, + data); + if (ret) + return dev_err_probe(dev, ret, "failed to add %s IRQ chip\n", + chip->name); + + return 0; +} + +static int max77759_add_chained_maxq(struct i2c_client *client, + struct max77759 *max77759, + struct regmap_irq_chip_data *parent) +{ + struct regmap_irq_chip_data *irq_chip_data; + int apcmdres_irq; + int ret; + + ret = max77759_add_chained_irq_chip(&client->dev, + max77759->regmap_maxq, + MAX77759_INT_MAXQ, + parent, + &max77759_maxq_irq_chip, + &irq_chip_data); + if (ret) + return ret; + + init_completion(&max77759->cmd_done); + apcmdres_irq = regmap_irq_get_virq(irq_chip_data, + MAX77759_MAXQ_INT_APCMDRESI); + + ret = devm_request_threaded_irq(&client->dev, apcmdres_irq, + NULL, apcmdres_irq_handler, + IRQF_ONESHOT | IRQF_SHARED, + dev_name(&client->dev), max77759); + if (ret) + return dev_err_probe(&client->dev, ret, + "MAX77759_MAXQ_INT_APCMDRESI failed\n"); + + ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + max77759_maxq_cells, + ARRAY_SIZE(max77759_maxq_cells), + NULL, 0, + regmap_irq_get_domain(irq_chip_data)); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to add child devices (MaxQ)\n"); + + return 0; +} + +static int max77759_add_chained_topsys(struct i2c_client *client, + struct max77759 *max77759, + struct regmap_irq_chip_data *parent) +{ + struct regmap_irq_chip_data *irq_chip_data; + int ret; + + ret = max77759_add_chained_irq_chip(&client->dev, + max77759->regmap_top, + MAX77759_INT_TOPSYS, + parent, + &max77759_topsys_irq_chip, + &irq_chip_data); + if (ret) + return ret; + + return 0; +} + +static int max77759_add_chained_charger(struct i2c_client *client, + struct max77759 *max77759, + struct regmap_irq_chip_data *parent) +{ + struct regmap_irq_chip_data *irq_chip_data; + int ret; + + ret = max77759_add_chained_irq_chip(&client->dev, + max77759->regmap_charger, + MAX77759_INT_CHGR, + parent, + &max77759_chrg_irq_chip, + &irq_chip_data); + if (ret) + return ret; + + ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + max77759_charger_cells, + ARRAY_SIZE(max77759_charger_cells), + NULL, 0, + regmap_irq_get_domain(irq_chip_data)); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to add child devices (charger)\n"); + + return 0; +} + +static int max77759_probe(struct i2c_client *client) +{ + struct regmap_irq_chip_data *irq_chip_data_pmic; + struct irq_data *irq_data; + struct max77759 *max77759; + unsigned long irq_flags; + unsigned int pmic_id; + int ret; + + max77759 = devm_kzalloc(&client->dev, sizeof(*max77759), GFP_KERNEL); + if (!max77759) + return -ENOMEM; + + i2c_set_clientdata(client, max77759); + + max77759->regmap_top = devm_regmap_init_i2c(client, + &max77759_regmap_config_top); + if (IS_ERR(max77759->regmap_top)) + return dev_err_probe(&client->dev, PTR_ERR(max77759->regmap_top), + "regmap init for '%s' failed\n", + max77759_regmap_config_top.name); + + ret = regmap_read(max77759->regmap_top, + MAX77759_PMIC_REG_PMIC_ID, &pmic_id); + if (ret) + return dev_err_probe(&client->dev, ret, + "unable to read device ID\n"); + + if (pmic_id != MAX77759_CHIP_ID) + return dev_err_probe(&client->dev, -ENODEV, + "unsupported device ID %#.2x (%d)\n", + pmic_id, pmic_id); + + ret = devm_mutex_init(&client->dev, &max77759->maxq_lock); + if (ret) + return ret; + + for (int i = 0; i < ARRAY_SIZE(max77759_i2c_subdevs); i++) { + ret = max77759_create_i2c_subdev(client, max77759, + &max77759_i2c_subdevs[i]); + if (ret) + return ret; + } + + irq_data = irq_get_irq_data(client->irq); + if (!irq_data) + return dev_err_probe(&client->dev, -EINVAL, + "invalid IRQ: %d\n", client->irq); + + irq_flags = IRQF_ONESHOT | IRQF_SHARED; + irq_flags |= irqd_get_trigger_type(irq_data); + + ret = devm_regmap_add_irq_chip(&client->dev, max77759->regmap_top, + client->irq, irq_flags, 0, + &max77759_pmic_irq_chip, + &irq_chip_data_pmic); + if (ret) + return dev_err_probe(&client->dev, ret, + "failed to add IRQ chip '%s'\n", + max77759_pmic_irq_chip.name); + + ret = max77759_add_chained_maxq(client, max77759, irq_chip_data_pmic); + if (ret) + return ret; + + ret = max77759_add_chained_topsys(client, max77759, irq_chip_data_pmic); + if (ret) + return ret; + + ret = max77759_add_chained_charger(client, max77759, irq_chip_data_pmic); + if (ret) + return ret; + + return devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_AUTO, + max77759_cells, ARRAY_SIZE(max77759_cells), + NULL, 0, + regmap_irq_get_domain(irq_chip_data_pmic)); +} + +static const struct i2c_device_id max77759_i2c_id[] = { + { "max77759" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, max77759_i2c_id); + +static const struct of_device_id max77759_of_id[] = { + { .compatible = "maxim,max77759", }, + { } +}; +MODULE_DEVICE_TABLE(of, max77759_of_id); + +static struct i2c_driver max77759_i2c_driver = { + .driver = { + .name = "max77759", + .of_match_table = max77759_of_id, + }, + .probe = max77759_probe, + .id_table = max77759_i2c_id, +}; +module_i2c_driver(max77759_i2c_driver); + +MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>"); +MODULE_DESCRIPTION("Maxim MAX77759 core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index accf426234b6..7bac1d651771 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -300,7 +300,7 @@ MODULE_DEVICE_TABLE(of, max8907_of_match); #endif static const struct i2c_device_id max8907_i2c_id[] = { - {"max8907", 0}, + { "max8907" }, {} }; MODULE_DEVICE_TABLE(i2c, max8907_i2c_id); diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 105d79b91493..78b16c67a5fc 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -682,8 +682,8 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, return -EBUSY; } - irq_domain_add_legacy(node, MAX8925_NR_IRQS, chip->irq_base, 0, - &max8925_irq_domain_ops, chip); + irq_domain_create_legacy(of_fwnode_handle(node), MAX8925_NR_IRQS, chip->irq_base, 0, + &max8925_irq_domain_ops, chip); /* request irq handler for pmic main irq*/ chip->core_irq = irq; diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 7608000488f9..ab19ff0c7867 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -127,8 +127,8 @@ EXPORT_SYMBOL(max8925_set_bits); static const struct i2c_device_id max8925_id_table[] = { - { "max8925", 0 }, - { }, + { "max8925" }, + { } }; static int max8925_dt_init(struct device_node *np, struct device *dev, @@ -201,6 +201,7 @@ static void max8925_remove(struct i2c_client *client) struct max8925_chip *chip = i2c_get_clientdata(client); max8925_device_exit(chip); + device_init_wakeup(&client->dev, false); i2c_unregister_device(chip->adc); i2c_unregister_device(chip->rtc); } diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c index 93a3b1698d9c..cc87571c9af5 100644 --- a/drivers/mfd/max8997-irq.c +++ b/drivers/mfd/max8997-irq.c @@ -327,15 +327,16 @@ int max8997_irq_init(struct max8997_dev *max8997) true : false; } - domain = irq_domain_add_linear(NULL, MAX8997_IRQ_NR, - &max8997_irq_domain_ops, max8997); + domain = irq_domain_create_linear(NULL, MAX8997_IRQ_NR, + &max8997_irq_domain_ops, max8997); if (!domain) { dev_err(max8997->dev, "could not create irq domain\n"); return -ENODEV; } max8997->irq_domain = domain; - ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread, + ret = devm_request_threaded_irq(max8997->dev, max8997->irq, NULL, + max8997_irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "max8997-irq", max8997); @@ -348,7 +349,8 @@ int max8997_irq_init(struct max8997_dev *max8997) if (!max8997->ono) return 0; - ret = request_threaded_irq(max8997->ono, NULL, max8997_irq_thread, + ret = devm_request_threaded_irq(max8997->dev, max8997->ono, NULL, + max8997_irq_thread, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "max8997-ono", max8997); @@ -358,12 +360,3 @@ int max8997_irq_init(struct max8997_dev *max8997) return 0; } - -void max8997_irq_exit(struct max8997_dev *max8997) -{ - if (max8997->ono) - free_irq(max8997->ono, max8997); - - if (max8997->irq) - free_irq(max8997->irq, max8997); -} diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index 83b6f510bc05..b0773fa6e07f 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c @@ -230,7 +230,7 @@ int max8998_irq_init(struct max8998_dev *max8998) max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM1, 0xff); max8998_write_reg(max8998->i2c, MAX8998_REG_STATUSM2, 0xff); - domain = irq_domain_add_simple(NULL, MAX8998_IRQ_NR, + domain = irq_domain_create_simple(NULL, MAX8998_IRQ_NR, max8998->irq_base, &max8998_irq_domain_ops, max8998); if (!domain) { dev_err(max8998->dev, "could not create irq domain\n"); diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 1000572761a8..920797b806ce 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -7,6 +7,7 @@ * Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> */ +#include <linux/bitfield.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> @@ -174,28 +175,27 @@ int mc13xxx_irq_free(struct mc13xxx *mc13xxx, int irq, void *dev) } EXPORT_SYMBOL(mc13xxx_irq_free); -#define maskval(reg, mask) (((reg) & (mask)) >> __ffs(mask)) static void mc13xxx_print_revision(struct mc13xxx *mc13xxx, u32 revision) { dev_info(mc13xxx->dev, "%s: rev: %d.%d, " "fin: %d, fab: %d, icid: %d/%d\n", mc13xxx->variant->name, - maskval(revision, MC13XXX_REVISION_REVFULL), - maskval(revision, MC13XXX_REVISION_REVMETAL), - maskval(revision, MC13XXX_REVISION_FIN), - maskval(revision, MC13XXX_REVISION_FAB), - maskval(revision, MC13XXX_REVISION_ICID), - maskval(revision, MC13XXX_REVISION_ICIDCODE)); + FIELD_GET(MC13XXX_REVISION_REVFULL, revision), + FIELD_GET(MC13XXX_REVISION_REVMETAL, revision), + FIELD_GET(MC13XXX_REVISION_FIN, revision), + FIELD_GET(MC13XXX_REVISION_FAB, revision), + FIELD_GET(MC13XXX_REVISION_ICID, revision), + FIELD_GET(MC13XXX_REVISION_ICIDCODE, revision)); } static void mc34708_print_revision(struct mc13xxx *mc13xxx, u32 revision) { dev_info(mc13xxx->dev, "%s: rev %d.%d, fin: %d, fab: %d\n", mc13xxx->variant->name, - maskval(revision, MC34708_REVISION_REVFULL), - maskval(revision, MC34708_REVISION_REVMETAL), - maskval(revision, MC34708_REVISION_FIN), - maskval(revision, MC34708_REVISION_FAB)); + FIELD_GET(MC34708_REVISION_REVFULL, revision), + FIELD_GET(MC34708_REVISION_REVMETAL, revision), + FIELD_GET(MC34708_REVISION_FIN, revision), + FIELD_GET(MC34708_REVISION_FAB, revision)); } /* These are only exported for mc13xxx-i2c and mc13xxx-spi */ diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index c973e2579bdf..9f438d5d4326 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -116,7 +116,7 @@ static int mc13xxx_spi_write(void *context, const void *data, size_t count) * single transfer. */ -static struct regmap_bus regmap_mc13xxx_bus = { +static const struct regmap_bus regmap_mc13xxx_bus = { .write = mc13xxx_spi_write, .read = mc13xxx_spi_read, }; diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c index 2fa592c37c6f..be08eaee0a90 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -20,7 +20,7 @@ #define to_mcp(d) container_of(d, struct mcp, attached_device) #define to_mcp_driver(d) container_of(d, struct mcp_driver, drv) -static int mcp_bus_match(struct device *dev, struct device_driver *drv) +static int mcp_bus_match(struct device *dev, const struct device_driver *drv) { return 1; } @@ -41,7 +41,7 @@ static void mcp_bus_remove(struct device *dev) drv->remove(mcp); } -static struct bus_type mcp_bus_type = { +static const struct bus_type mcp_bus_type = { .name = "mcp", .match = mcp_bus_match, .probe = mcp_bus_probe, diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 3883e472b739..228c4a2f4c1f 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -286,7 +286,7 @@ static const struct dev_pm_ops mcp_sa11x0_pm_ops = { static struct platform_driver mcp_sa11x0_driver = { .probe = mcp_sa11x0_probe, - .remove_new = mcp_sa11x0_remove, + .remove = mcp_sa11x0_remove, .driver = { .name = DRIVER_NAME, .pm = pm_sleep_ptr(&mcp_sa11x0_pm_ops), diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 662604ea97f2..a125d40fa121 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -29,7 +29,6 @@ #include <linux/bcd.h> #include <linux/slab.h> #include <linux/mfd/menelaus.h> -#include <linux/gpio.h> #include <asm/mach/irq.h> @@ -1231,7 +1230,7 @@ static void menelaus_remove(struct i2c_client *client) } static const struct i2c_device_id menelaus_id[] = { - { "menelaus", 0 }, + { "menelaus" }, { } }; MODULE_DEVICE_TABLE(i2c, menelaus_id); diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 2b85509a90fc..76bd316a50af 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -29,7 +29,7 @@ struct mfd_of_node_entry { struct device_node *np; }; -static struct device_type mfd_dev_type = { +static const struct device_type mfd_dev_type = { .name = "mfd_device", }; @@ -87,7 +87,7 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, } } - ACPI_COMPANION_SET(&pdev->dev, adev ?: parent); + device_set_node(&pdev->dev, acpi_fwnode_handle(adev ?: parent)); } #else static inline void mfd_acpi_add_device(const struct mfd_cell *cell, @@ -131,8 +131,7 @@ allocate_of_node: of_entry->np = np; list_add_tail(&of_entry->list, &mfd_of_node_list); - pdev->dev.of_node = np; - pdev->dev.fwnode = &np->fwnode; + device_set_node(&pdev->dev, of_fwnode_handle(np)); #endif return 0; } @@ -437,5 +436,6 @@ int devm_mfd_add_devices(struct device *dev, int id, } EXPORT_SYMBOL(devm_mfd_add_devices); +MODULE_DESCRIPTION("Core MFD support"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); diff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c index 49830b526ee8..9f0bcc3ad7a1 100644 --- a/drivers/mfd/mt6358-irq.c +++ b/drivers/mfd/mt6358-irq.c @@ -272,9 +272,9 @@ int mt6358_irq_init(struct mt6397_chip *chip) irqd->pmic_ints[i].en_reg_shift * j, 0); } - chip->irq_domain = irq_domain_add_linear(chip->dev->of_node, - irqd->num_pmic_irqs, - &mt6358_irq_domain_ops, chip); + chip->irq_domain = irq_domain_create_linear(of_fwnode_handle(chip->dev->of_node), + irqd->num_pmic_irqs, + &mt6358_irq_domain_ops, chip); if (!chip->irq_domain) { dev_err(chip->dev, "Could not create IRQ domain\n"); return -ENODEV; diff --git a/drivers/mfd/mt6360-core.c b/drivers/mfd/mt6360-core.c index 2685efa5c9e2..b9b1036c8ff4 100644 --- a/drivers/mfd/mt6360-core.c +++ b/drivers/mfd/mt6360-core.c @@ -5,6 +5,7 @@ * Author: Gene Chen <gene_chen@richtek.com> */ +#include <linux/cleanup.h> #include <linux/crc8.h> #include <linux/i2c.h> #include <linux/init.h> @@ -404,7 +405,6 @@ static int mt6360_regmap_read(void *context, const void *reg, size_t reg_size, u8 reg_addr = *(u8 *)(reg + 1); struct i2c_client *i2c; bool crc_needed = false; - u8 *buf; int buf_len = MT6360_ALLOC_READ_SIZE(val_size); int read_size = val_size; u8 crc; @@ -423,7 +423,7 @@ static int mt6360_regmap_read(void *context, const void *reg, size_t reg_size, read_size += MT6360_CRC_CRC8_SIZE; } - buf = kzalloc(buf_len, GFP_KERNEL); + u8 *buf __free(kfree) = kzalloc(buf_len, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -433,24 +433,19 @@ static int mt6360_regmap_read(void *context, const void *reg, size_t reg_size, ret = i2c_smbus_read_i2c_block_data(i2c, reg_addr, read_size, buf + MT6360_CRC_PREDATA_OFFSET); if (ret < 0) - goto out; - else if (ret != read_size) { - ret = -EIO; - goto out; - } + return ret; + else if (ret != read_size) + return -EIO; if (crc_needed) { crc = crc8(ddata->crc8_tbl, buf, val_size + MT6360_CRC_PREDATA_OFFSET, 0); - if (crc != buf[val_size + MT6360_CRC_PREDATA_OFFSET]) { - ret = -EIO; - goto out; - } + if (crc != buf[val_size + MT6360_CRC_PREDATA_OFFSET]) + return -EIO; } memcpy(val, buf + MT6360_CRC_PREDATA_OFFSET, val_size); -out: - kfree(buf); - return (ret < 0) ? ret : 0; + + return 0; } static int mt6360_regmap_write(void *context, const void *val, size_t val_size) diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index 4449dde05021..5f8ed8988907 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -13,12 +13,14 @@ #include <linux/regmap.h> #include <linux/mfd/core.h> #include <linux/mfd/mt6323/core.h> +#include <linux/mfd/mt6328/core.h> #include <linux/mfd/mt6331/core.h> #include <linux/mfd/mt6357/core.h> #include <linux/mfd/mt6358/core.h> #include <linux/mfd/mt6359/core.h> #include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6323/registers.h> +#include <linux/mfd/mt6328/registers.h> #include <linux/mfd/mt6331/registers.h> #include <linux/mfd/mt6357/registers.h> #include <linux/mfd/mt6358/registers.h> @@ -82,11 +84,24 @@ static const struct resource mt6359_keys_resources[] = { DEFINE_RES_IRQ_NAMED(MT6359_IRQ_HOMEKEY_R, "homekey_r"), }; +static const struct resource mt6359_accdet_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6359_IRQ_ACCDET, "accdet_irq"), + DEFINE_RES_IRQ_NAMED(MT6359_IRQ_ACCDET_EINT0, "accdet_eint0"), + DEFINE_RES_IRQ_NAMED(MT6359_IRQ_ACCDET_EINT1, "accdet_eint1"), +}; + static const struct resource mt6323_keys_resources[] = { DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_PWRKEY, "powerkey"), DEFINE_RES_IRQ_NAMED(MT6323_IRQ_STATUS_FCHRKEY, "homekey"), }; +static const struct resource mt6328_keys_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_PWRKEY, "powerkey"), + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_HOMEKEY, "homekey"), + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_PWRKEY_R, "powerkey_r"), + DEFINE_RES_IRQ_NAMED(MT6328_IRQ_STATUS_HOMEKEY_R, "homekey_r"), +}; + static const struct resource mt6357_keys_resources[] = { DEFINE_RES_IRQ_NAMED(MT6357_IRQ_PWRKEY, "powerkey"), DEFINE_RES_IRQ_NAMED(MT6357_IRQ_HOMEKEY, "homekey"), @@ -133,8 +148,23 @@ static const struct mfd_cell mt6323_devs[] = { }, }; +static const struct mfd_cell mt6328_devs[] = { + { + .name = "mt6328-regulator", + .of_compatible = "mediatek,mt6328-regulator" + }, { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6328_keys_resources), + .resources = mt6328_keys_resources, + .of_compatible = "mediatek,mt6328-keys" + }, +}; + static const struct mfd_cell mt6357_devs[] = { { + .name = "mt6359-auxadc", + .of_compatible = "mediatek,mt6357-auxadc" + }, { .name = "mt6357-regulator", }, { .name = "mt6357-rtc", @@ -142,6 +172,9 @@ static const struct mfd_cell mt6357_devs[] = { .resources = mt6357_rtc_resources, .of_compatible = "mediatek,mt6357-rtc", }, { + .name = "mt6357-sound", + .of_compatible = "mediatek,mt6357-sound" + }, { .name = "mtk-pmic-keys", .num_resources = ARRAY_SIZE(mt6357_keys_resources), .resources = mt6357_keys_resources, @@ -172,6 +205,9 @@ static const struct mfd_cell mt6331_mt6332_devs[] = { static const struct mfd_cell mt6358_devs[] = { { + .name = "mt6359-auxadc", + .of_compatible = "mediatek,mt6358-auxadc" + }, { .name = "mt6358-regulator", .of_compatible = "mediatek,mt6358-regulator" }, { @@ -191,6 +227,10 @@ static const struct mfd_cell mt6358_devs[] = { }; static const struct mfd_cell mt6359_devs[] = { + { + .name = "mt6359-auxadc", + .of_compatible = "mediatek,mt6359-auxadc" + }, { .name = "mt6359-regulator", }, { .name = "mt6359-rtc", @@ -205,6 +245,12 @@ static const struct mfd_cell mt6359_devs[] = { .resources = mt6359_keys_resources, .of_compatible = "mediatek,mt6359-keys" }, + { + .name = "mt6359-accdet", + .of_compatible = "mediatek,mt6359-accdet", + .num_resources = ARRAY_SIZE(mt6359_accdet_resources), + .resources = mt6359_accdet_resources, + }, }; static const struct mfd_cell mt6397_devs[] = { @@ -249,6 +295,14 @@ static const struct chip_data mt6323_core = { .irq_init = mt6397_irq_init, }; +static const struct chip_data mt6328_core = { + .cid_addr = MT6328_HWCID, + .cid_shift = 0, + .cells = mt6328_devs, + .cell_size = ARRAY_SIZE(mt6328_devs), + .irq_init = mt6397_irq_init, +}; + static const struct chip_data mt6357_core = { .cid_addr = MT6357_SWCID, .cid_shift = 8, @@ -348,6 +402,9 @@ static const struct of_device_id mt6397_of_match[] = { .compatible = "mediatek,mt6323", .data = &mt6323_core, }, { + .compatible = "mediatek,mt6328", + .data = &mt6328_core, + }, { .compatible = "mediatek,mt6331", .data = &mt6331_mt6332_core, }, { diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c index 886745b5b607..badc614b4345 100644 --- a/drivers/mfd/mt6397-irq.c +++ b/drivers/mfd/mt6397-irq.c @@ -11,6 +11,8 @@ #include <linux/suspend.h> #include <linux/mfd/mt6323/core.h> #include <linux/mfd/mt6323/registers.h> +#include <linux/mfd/mt6328/core.h> +#include <linux/mfd/mt6328/registers.h> #include <linux/mfd/mt6331/core.h> #include <linux/mfd/mt6331/registers.h> #include <linux/mfd/mt6397/core.h> @@ -31,6 +33,9 @@ static void mt6397_irq_sync_unlock(struct irq_data *data) mt6397->irq_masks_cur[0]); regmap_write(mt6397->regmap, mt6397->int_con[1], mt6397->irq_masks_cur[1]); + if (mt6397->int_con[2]) + regmap_write(mt6397->regmap, mt6397->int_con[2], + mt6397->irq_masks_cur[2]); mutex_unlock(&mt6397->irqlock); } @@ -105,6 +110,8 @@ static irqreturn_t mt6397_irq_thread(int irq, void *data) mt6397_irq_handle_reg(mt6397, mt6397->int_status[0], 0); mt6397_irq_handle_reg(mt6397, mt6397->int_status[1], 16); + if (mt6397->int_status[2]) + mt6397_irq_handle_reg(mt6397, mt6397->int_status[2], 32); return IRQ_HANDLED; } @@ -138,6 +145,9 @@ static int mt6397_irq_pm_notifier(struct notifier_block *notifier, chip->int_con[0], chip->wake_mask[0]); regmap_write(chip->regmap, chip->int_con[1], chip->wake_mask[1]); + if (chip->int_con[2]) + regmap_write(chip->regmap, + chip->int_con[2], chip->wake_mask[2]); enable_irq_wake(chip->irq); break; @@ -146,6 +156,9 @@ static int mt6397_irq_pm_notifier(struct notifier_block *notifier, chip->int_con[0], chip->irq_masks_cur[0]); regmap_write(chip->regmap, chip->int_con[1], chip->irq_masks_cur[1]); + if (chip->int_con[2]) + regmap_write(chip->regmap, + chip->int_con[2], chip->irq_masks_cur[2]); disable_irq_wake(chip->irq); break; @@ -169,6 +182,14 @@ int mt6397_irq_init(struct mt6397_chip *chip) chip->int_status[0] = MT6323_INT_STATUS0; chip->int_status[1] = MT6323_INT_STATUS1; break; + case MT6328_CHIP_ID: + chip->int_con[0] = MT6328_INT_CON0; + chip->int_con[1] = MT6328_INT_CON1; + chip->int_con[2] = MT6328_INT_CON2; + chip->int_status[0] = MT6328_INT_STATUS0; + chip->int_status[1] = MT6328_INT_STATUS1; + chip->int_status[2] = MT6328_INT_STATUS2; + break; case MT6331_CHIP_ID: chip->int_con[0] = MT6331_INT_CON0; chip->int_con[1] = MT6331_INT_CON1; @@ -191,12 +212,12 @@ int mt6397_irq_init(struct mt6397_chip *chip) /* Mask all interrupt sources */ regmap_write(chip->regmap, chip->int_con[0], 0x0); regmap_write(chip->regmap, chip->int_con[1], 0x0); + if (chip->int_con[2]) + regmap_write(chip->regmap, chip->int_con[2], 0x0); chip->pm_nb.notifier_call = mt6397_irq_pm_notifier; - chip->irq_domain = irq_domain_add_linear(chip->dev->of_node, - MT6397_IRQ_NR, - &mt6397_irq_domain_ops, - chip); + chip->irq_domain = irq_domain_create_linear(of_fwnode_handle(chip->dev->of_node), + MT6397_IRQ_NR, &mt6397_irq_domain_ops, chip); if (!chip->irq_domain) { dev_err(chip->dev, "could not create irq domain\n"); return -ENOMEM; diff --git a/drivers/mfd/mxs-lradc.c b/drivers/mfd/mxs-lradc.c index 73893890b50a..64afc7631790 100644 --- a/drivers/mfd/mxs-lradc.c +++ b/drivers/mfd/mxs-lradc.c @@ -137,7 +137,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) if (!lradc) return -ENOMEM; - lradc->soc = (enum mxs_lradc_id)device_get_match_data(&pdev->dev); + lradc->soc = (kernel_ulong_t)device_get_match_data(&pdev->dev); lradc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(lradc->clk)) { @@ -243,7 +243,7 @@ static struct platform_driver mxs_lradc_driver = { .of_match_table = mxs_lradc_dt_ids, }, .probe = mxs_lradc_probe, - .remove_new = mxs_lradc_remove, + .remove = mxs_lradc_remove, }; module_platform_driver(mxs_lradc_driver); diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c index 4416cd37e539..08c68de0f01b 100644 --- a/drivers/mfd/ntxec.c +++ b/drivers/mfd/ntxec.c @@ -21,7 +21,7 @@ #include <linux/reboot.h> #include <linux/regmap.h> #include <linux/types.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #define NTXEC_REG_VERSION 0x00 #define NTXEC_REG_POWEROFF 0x50 diff --git a/drivers/mfd/ocelot-core.c b/drivers/mfd/ocelot-core.c index 9cccf54fc9c8..41aff2708854 100644 --- a/drivers/mfd/ocelot-core.c +++ b/drivers/mfd/ocelot-core.c @@ -113,7 +113,7 @@ int ocelot_chip_reset(struct device *dev) return readx_poll_timeout(ocelot_gcb_chip_rst_status, ddata, val, !val, VSC7512_GCB_RST_SLEEP_US, VSC7512_GCB_RST_TIMEOUT_US); } -EXPORT_SYMBOL_NS(ocelot_chip_reset, MFD_OCELOT); +EXPORT_SYMBOL_NS(ocelot_chip_reset, "MFD_OCELOT"); static const struct resource vsc7512_miim0_resources[] = { DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"), @@ -226,9 +226,9 @@ int ocelot_core_init(struct device *dev) return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL); } -EXPORT_SYMBOL_NS(ocelot_core_init, MFD_OCELOT); +EXPORT_SYMBOL_NS(ocelot_core_init, "MFD_OCELOT"); MODULE_DESCRIPTION("Externally Controlled Ocelot Chip Driver"); MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(MFD_OCELOT_SPI); +MODULE_IMPORT_NS("MFD_OCELOT_SPI"); diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c index 94f82677675b..1fed9878c323 100644 --- a/drivers/mfd/ocelot-spi.c +++ b/drivers/mfd/ocelot-spi.c @@ -145,7 +145,6 @@ static int ocelot_spi_regmap_bus_read(void *context, const void *reg, size_t reg struct device *dev = context; struct ocelot_ddata *ddata; struct spi_device *spi; - struct spi_message msg; unsigned int index = 0; ddata = dev_get_drvdata(dev); @@ -166,9 +165,7 @@ static int ocelot_spi_regmap_bus_read(void *context, const void *reg, size_t reg xfers[index].len = val_size; index++; - spi_message_init_with_transfers(&msg, xfers, index); - - return spi_sync(spi, &msg); + return spi_sync_transfer(spi, xfers, index); } static int ocelot_spi_regmap_bus_write(void *context, const void *data, size_t count) @@ -196,7 +193,7 @@ struct regmap *ocelot_spi_init_regmap(struct device *dev, const struct resource return devm_regmap_init(dev, &ocelot_spi_regmap_bus, dev, ®map_config); } -EXPORT_SYMBOL_NS(ocelot_spi_init_regmap, MFD_OCELOT_SPI); +EXPORT_SYMBOL_NS(ocelot_spi_init_regmap, "MFD_OCELOT_SPI"); static int ocelot_spi_probe(struct spi_device *spi) { @@ -298,4 +295,4 @@ module_spi_driver(ocelot_spi_driver); MODULE_DESCRIPTION("SPI Controlled Ocelot Chip Driver"); MODULE_AUTHOR("Colin Foster <colin.foster@in-advantage.com>"); MODULE_LICENSE("Dual MIT/GPL"); -MODULE_IMPORT_NS(MFD_OCELOT); +MODULE_IMPORT_NS("MFD_OCELOT"); diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index ebc62033db16..a77b6fc790f2 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -13,7 +13,6 @@ #include <linux/delay.h> #include <linux/clk.h> #include <linux/dma-mapping.h> -#include <linux/gpio.h> #include <linux/platform_device.h> #include <linux/platform_data/usb-omap.h> #include <linux/pm_runtime.h> @@ -699,7 +698,7 @@ static int usbhs_omap_probe(struct platform_device *pdev) } for (i = 0; i < omap->nports; i++) { - char clkname[30]; + char clkname[40]; /* clock names are indexed from 1*/ snprintf(clkname, sizeof(clkname), @@ -844,7 +843,7 @@ static struct platform_driver usbhs_omap_driver = { .of_match_table = usbhs_omap_dt_ids, }, .probe = usbhs_omap_probe, - .remove_new = usbhs_omap_remove, + .remove = usbhs_omap_remove, }; MODULE_AUTHOR("Keshava Munegowda <keshava_mgowda@ti.com>"); diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index b6303ddb013b..0f7fdb99c809 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c @@ -98,8 +98,8 @@ struct usbtll_omap { void __iomem *base; - int nch; /* num. of channels */ - struct clk *ch_clk[]; /* must be the last member */ + int nch; + struct clk *ch_clk[] __counted_by(nch); }; /*-------------------------------------------------------------------------*/ @@ -230,8 +230,7 @@ static int usbtll_omap_probe(struct platform_device *pdev) break; } - tll = devm_kzalloc(dev, sizeof(*tll) + sizeof(tll->ch_clk[nch]), - GFP_KERNEL); + tll = devm_kzalloc(dev, struct_size(tll, ch_clk, nch), GFP_KERNEL); if (!tll) { pm_runtime_put_sync(dev); pm_runtime_disable(dev); @@ -302,7 +301,7 @@ static struct platform_driver usbtll_omap_driver = { .of_match_table = usbtll_omap_dt_ids, }, .probe = usbtll_omap_probe, - .remove_new = usbtll_omap_remove, + .remove = usbtll_omap_remove, }; int omap_tll_init(struct usbhs_omap_platform_data *pdata) diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c deleted file mode 100644 index ab55906f91f9..000000000000 --- a/drivers/mfd/pcf50633-adc.c +++ /dev/null @@ -1,255 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* NXP PCF50633 ADC Driver - * - * (C) 2006-2008 by Openmoko, Inc. - * Author: Balaji Rao <balajirrao@openmoko.org> - * All rights reserved. - * - * Broken down from monstrous PCF50633 driver mainly by - * Harald Welte, Andy Green and Werner Almesberger - * - * NOTE: This driver does not yet support subtractive ADC mode, which means - * you can do only one measurement per read request. - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/platform_device.h> -#include <linux/completion.h> - -#include <linux/mfd/pcf50633/core.h> -#include <linux/mfd/pcf50633/adc.h> - -struct pcf50633_adc_request { - int mux; - int avg; - void (*callback)(struct pcf50633 *, void *, int); - void *callback_param; -}; - -struct pcf50633_adc_sync_request { - int result; - struct completion completion; -}; - -#define PCF50633_MAX_ADC_FIFO_DEPTH 8 - -struct pcf50633_adc { - struct pcf50633 *pcf; - - /* Private stuff */ - struct pcf50633_adc_request *queue[PCF50633_MAX_ADC_FIFO_DEPTH]; - int queue_head; - int queue_tail; - struct mutex queue_mutex; -}; - -static inline struct pcf50633_adc *__to_adc(struct pcf50633 *pcf) -{ - return platform_get_drvdata(pcf->adc_pdev); -} - -static void adc_setup(struct pcf50633 *pcf, int channel, int avg) -{ - channel &= PCF50633_ADCC1_ADCMUX_MASK; - - /* kill ratiometric, but enable ACCSW biasing */ - pcf50633_reg_write(pcf, PCF50633_REG_ADCC2, 0x00); - pcf50633_reg_write(pcf, PCF50633_REG_ADCC3, 0x01); - - /* start ADC conversion on selected channel */ - pcf50633_reg_write(pcf, PCF50633_REG_ADCC1, channel | avg | - PCF50633_ADCC1_ADCSTART | PCF50633_ADCC1_RES_10BIT); -} - -static void trigger_next_adc_job_if_any(struct pcf50633 *pcf) -{ - struct pcf50633_adc *adc = __to_adc(pcf); - int head; - - head = adc->queue_head; - - if (!adc->queue[head]) - return; - - adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg); -} - -static int -adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req) -{ - struct pcf50633_adc *adc = __to_adc(pcf); - int head, tail; - - mutex_lock(&adc->queue_mutex); - - head = adc->queue_head; - tail = adc->queue_tail; - - if (adc->queue[tail]) { - mutex_unlock(&adc->queue_mutex); - dev_err(pcf->dev, "ADC queue is full, dropping request\n"); - return -EBUSY; - } - - adc->queue[tail] = req; - if (head == tail) - trigger_next_adc_job_if_any(pcf); - adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1); - - mutex_unlock(&adc->queue_mutex); - - return 0; -} - -static void pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, - int result) -{ - struct pcf50633_adc_sync_request *req = param; - - req->result = result; - complete(&req->completion); -} - -int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) -{ - struct pcf50633_adc_sync_request req; - int ret; - - init_completion(&req.completion); - - ret = pcf50633_adc_async_read(pcf, mux, avg, - pcf50633_adc_sync_read_callback, &req); - if (ret) - return ret; - - wait_for_completion(&req.completion); - - return req.result; -} -EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read); - -int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg, - void (*callback)(struct pcf50633 *, void *, int), - void *callback_param) -{ - struct pcf50633_adc_request *req; - int ret; - - /* req is freed when the result is ready, in interrupt handler */ - req = kmalloc(sizeof(*req), GFP_KERNEL); - if (!req) - return -ENOMEM; - - req->mux = mux; - req->avg = avg; - req->callback = callback; - req->callback_param = callback_param; - - ret = adc_enqueue_request(pcf, req); - if (ret) - kfree(req); - - return ret; -} -EXPORT_SYMBOL_GPL(pcf50633_adc_async_read); - -static int adc_result(struct pcf50633 *pcf) -{ - u8 adcs1, adcs3; - u16 result; - - adcs1 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS1); - adcs3 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS3); - result = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK); - - dev_dbg(pcf->dev, "adc result = %d\n", result); - - return result; -} - -static void pcf50633_adc_irq(int irq, void *data) -{ - struct pcf50633_adc *adc = data; - struct pcf50633 *pcf = adc->pcf; - struct pcf50633_adc_request *req; - int head, res; - - mutex_lock(&adc->queue_mutex); - head = adc->queue_head; - - req = adc->queue[head]; - if (WARN_ON(!req)) { - dev_err(pcf->dev, "pcf50633-adc irq: ADC queue empty!\n"); - mutex_unlock(&adc->queue_mutex); - return; - } - adc->queue[head] = NULL; - adc->queue_head = (head + 1) & - (PCF50633_MAX_ADC_FIFO_DEPTH - 1); - - res = adc_result(pcf); - trigger_next_adc_job_if_any(pcf); - - mutex_unlock(&adc->queue_mutex); - - req->callback(pcf, req->callback_param, res); - kfree(req); -} - -static int pcf50633_adc_probe(struct platform_device *pdev) -{ - struct pcf50633_adc *adc; - - adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL); - if (!adc) - return -ENOMEM; - - adc->pcf = dev_to_pcf50633(pdev->dev.parent); - platform_set_drvdata(pdev, adc); - - pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY, - pcf50633_adc_irq, adc); - - mutex_init(&adc->queue_mutex); - - return 0; -} - -static void pcf50633_adc_remove(struct platform_device *pdev) -{ - struct pcf50633_adc *adc = platform_get_drvdata(pdev); - int i, head; - - pcf50633_free_irq(adc->pcf, PCF50633_IRQ_ADCRDY); - - mutex_lock(&adc->queue_mutex); - head = adc->queue_head; - - if (WARN_ON(adc->queue[head])) - dev_err(adc->pcf->dev, - "adc driver removed with request pending\n"); - - for (i = 0; i < PCF50633_MAX_ADC_FIFO_DEPTH; i++) - kfree(adc->queue[i]); - - mutex_unlock(&adc->queue_mutex); -} - -static struct platform_driver pcf50633_adc_driver = { - .driver = { - .name = "pcf50633-adc", - }, - .probe = pcf50633_adc_probe, - .remove_new = pcf50633_adc_remove, -}; - -module_platform_driver(pcf50633_adc_driver); - -MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); -MODULE_DESCRIPTION("PCF50633 adc driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pcf50633-adc"); - diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c deleted file mode 100644 index 014a68711b18..000000000000 --- a/drivers/mfd/pcf50633-core.c +++ /dev/null @@ -1,304 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* NXP PCF50633 Power Management Unit (PMU) driver - * - * (C) 2006-2008 by Openmoko, Inc. - * Author: Harald Welte <laforge@openmoko.org> - * Balaji Rao <balajirrao@openmoko.org> - * All rights reserved. - */ - -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/sysfs.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> -#include <linux/platform_device.h> -#include <linux/i2c.h> -#include <linux/pm.h> -#include <linux/slab.h> -#include <linux/regmap.h> -#include <linux/err.h> - -#include <linux/mfd/pcf50633/core.h> - -/* Read a block of up to 32 regs */ -int pcf50633_read_block(struct pcf50633 *pcf, u8 reg, - int nr_regs, u8 *data) -{ - int ret; - - ret = regmap_raw_read(pcf->regmap, reg, data, nr_regs); - if (ret != 0) - return ret; - - return nr_regs; -} -EXPORT_SYMBOL_GPL(pcf50633_read_block); - -/* Write a block of up to 32 regs */ -int pcf50633_write_block(struct pcf50633 *pcf , u8 reg, - int nr_regs, u8 *data) -{ - return regmap_raw_write(pcf->regmap, reg, data, nr_regs); -} -EXPORT_SYMBOL_GPL(pcf50633_write_block); - -u8 pcf50633_reg_read(struct pcf50633 *pcf, u8 reg) -{ - unsigned int val; - int ret; - - ret = regmap_read(pcf->regmap, reg, &val); - if (ret < 0) - return -1; - - return val; -} -EXPORT_SYMBOL_GPL(pcf50633_reg_read); - -int pcf50633_reg_write(struct pcf50633 *pcf, u8 reg, u8 val) -{ - return regmap_write(pcf->regmap, reg, val); -} -EXPORT_SYMBOL_GPL(pcf50633_reg_write); - -int pcf50633_reg_set_bit_mask(struct pcf50633 *pcf, u8 reg, u8 mask, u8 val) -{ - return regmap_update_bits(pcf->regmap, reg, mask, val); -} -EXPORT_SYMBOL_GPL(pcf50633_reg_set_bit_mask); - -int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 val) -{ - return regmap_update_bits(pcf->regmap, reg, val, 0); -} -EXPORT_SYMBOL_GPL(pcf50633_reg_clear_bits); - -/* sysfs attributes */ -static ssize_t dump_regs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pcf50633 *pcf = dev_get_drvdata(dev); - u8 dump[16]; - int n, n1, idx = 0; - char *buf1 = buf; - static u8 address_no_read[] = { /* must be ascending */ - PCF50633_REG_INT1, - PCF50633_REG_INT2, - PCF50633_REG_INT3, - PCF50633_REG_INT4, - PCF50633_REG_INT5, - 0 /* terminator */ - }; - - for (n = 0; n < 256; n += sizeof(dump)) { - for (n1 = 0; n1 < sizeof(dump); n1++) - if (n == address_no_read[idx]) { - idx++; - dump[n1] = 0x00; - } else - dump[n1] = pcf50633_reg_read(pcf, n + n1); - - buf1 += sprintf(buf1, "%*ph\n", (int)sizeof(dump), dump); - } - - return buf1 - buf; -} -static DEVICE_ATTR_ADMIN_RO(dump_regs); - -static ssize_t resume_reason_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pcf50633 *pcf = dev_get_drvdata(dev); - int n; - - n = sprintf(buf, "%02x%02x%02x%02x%02x\n", - pcf->resume_reason[0], - pcf->resume_reason[1], - pcf->resume_reason[2], - pcf->resume_reason[3], - pcf->resume_reason[4]); - - return n; -} -static DEVICE_ATTR_ADMIN_RO(resume_reason); - -static struct attribute *pcf_sysfs_entries[] = { - &dev_attr_dump_regs.attr, - &dev_attr_resume_reason.attr, - NULL, -}; - -static struct attribute_group pcf_attr_group = { - .name = NULL, /* put in device directory */ - .attrs = pcf_sysfs_entries, -}; - -static void -pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, - struct platform_device **pdev) -{ - int ret; - - *pdev = platform_device_alloc(name, -1); - if (!*pdev) { - dev_err(pcf->dev, "Failed to allocate %s\n", name); - return; - } - - (*pdev)->dev.parent = pcf->dev; - - ret = platform_device_add(*pdev); - if (ret) { - dev_err(pcf->dev, "Failed to register %s: %d\n", name, ret); - platform_device_put(*pdev); - *pdev = NULL; - } -} - -static const struct regmap_config pcf50633_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - -static int pcf50633_probe(struct i2c_client *client) -{ - struct pcf50633 *pcf; - struct platform_device *pdev; - struct pcf50633_platform_data *pdata = dev_get_platdata(&client->dev); - int i, j, ret; - int version, variant; - - if (!client->irq) { - dev_err(&client->dev, "Missing IRQ\n"); - return -ENOENT; - } - - pcf = devm_kzalloc(&client->dev, sizeof(*pcf), GFP_KERNEL); - if (!pcf) - return -ENOMEM; - - i2c_set_clientdata(client, pcf); - pcf->dev = &client->dev; - pcf->pdata = pdata; - - mutex_init(&pcf->lock); - - pcf->regmap = devm_regmap_init_i2c(client, &pcf50633_regmap_config); - if (IS_ERR(pcf->regmap)) { - ret = PTR_ERR(pcf->regmap); - dev_err(pcf->dev, "Failed to allocate register map: %d\n", ret); - return ret; - } - - version = pcf50633_reg_read(pcf, 0); - variant = pcf50633_reg_read(pcf, 1); - if (version < 0 || variant < 0) { - dev_err(pcf->dev, "Unable to probe pcf50633\n"); - ret = -ENODEV; - return ret; - } - - dev_info(pcf->dev, "Probed device version %d variant %d\n", - version, variant); - - pcf50633_irq_init(pcf, client->irq); - - /* Create sub devices */ - pcf50633_client_dev_register(pcf, "pcf50633-input", &pcf->input_pdev); - pcf50633_client_dev_register(pcf, "pcf50633-rtc", &pcf->rtc_pdev); - pcf50633_client_dev_register(pcf, "pcf50633-mbc", &pcf->mbc_pdev); - pcf50633_client_dev_register(pcf, "pcf50633-adc", &pcf->adc_pdev); - pcf50633_client_dev_register(pcf, "pcf50633-backlight", &pcf->bl_pdev); - - - for (i = 0; i < PCF50633_NUM_REGULATORS; i++) { - pdev = platform_device_alloc("pcf50633-regulator", i); - if (!pdev) { - ret = -ENOMEM; - goto err2; - } - - pdev->dev.parent = pcf->dev; - ret = platform_device_add_data(pdev, &pdata->reg_init_data[i], - sizeof(pdata->reg_init_data[i])); - if (ret) - goto err; - - ret = platform_device_add(pdev); - if (ret) - goto err; - - pcf->regulator_pdev[i] = pdev; - } - - ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group); - if (ret) - dev_warn(pcf->dev, "error creating sysfs entries\n"); - - if (pdata->probe_done) - pdata->probe_done(pcf); - - return 0; - -err: - platform_device_put(pdev); -err2: - for (j = 0; j < i; j++) - platform_device_put(pcf->regulator_pdev[j]); - - return ret; -} - -static void pcf50633_remove(struct i2c_client *client) -{ - struct pcf50633 *pcf = i2c_get_clientdata(client); - int i; - - sysfs_remove_group(&client->dev.kobj, &pcf_attr_group); - pcf50633_irq_free(pcf); - - platform_device_unregister(pcf->input_pdev); - platform_device_unregister(pcf->rtc_pdev); - platform_device_unregister(pcf->mbc_pdev); - platform_device_unregister(pcf->adc_pdev); - platform_device_unregister(pcf->bl_pdev); - - for (i = 0; i < PCF50633_NUM_REGULATORS; i++) - platform_device_unregister(pcf->regulator_pdev[i]); -} - -static const struct i2c_device_id pcf50633_id_table[] = { - {"pcf50633", 0x73}, - {/* end of list */} -}; -MODULE_DEVICE_TABLE(i2c, pcf50633_id_table); - -static struct i2c_driver pcf50633_driver = { - .driver = { - .name = "pcf50633", - .pm = pm_sleep_ptr(&pcf50633_pm), - }, - .id_table = pcf50633_id_table, - .probe = pcf50633_probe, - .remove = pcf50633_remove, -}; - -static int __init pcf50633_init(void) -{ - return i2c_add_driver(&pcf50633_driver); -} - -static void __exit pcf50633_exit(void) -{ - i2c_del_driver(&pcf50633_driver); -} - -MODULE_DESCRIPTION("I2C chip driver for NXP PCF50633 PMU"); -MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>"); -MODULE_LICENSE("GPL"); - -subsys_initcall(pcf50633_init); -module_exit(pcf50633_exit); diff --git a/drivers/mfd/pcf50633-gpio.c b/drivers/mfd/pcf50633-gpio.c deleted file mode 100644 index 4d2b53b12eeb..000000000000 --- a/drivers/mfd/pcf50633-gpio.c +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* NXP PCF50633 GPIO Driver - * - * (C) 2006-2008 by Openmoko, Inc. - * Author: Balaji Rao <balajirrao@openmoko.org> - * All rights reserved. - * - * Broken down from monstrous PCF50633 driver mainly by - * Harald Welte, Andy Green and Werner Almesberger - */ - -#include <linux/kernel.h> -#include <linux/module.h> - -#include <linux/mfd/pcf50633/core.h> -#include <linux/mfd/pcf50633/gpio.h> -#include <linux/mfd/pcf50633/pmic.h> - -static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = { - [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT, - [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT, - [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT, - [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT, - [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT, - [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT, - [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT, - [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT, - [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT, - [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT, - [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT, -}; - -int pcf50633_gpio_set(struct pcf50633 *pcf, int gpio, u8 val) -{ - u8 reg; - - reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; - - return pcf50633_reg_set_bit_mask(pcf, reg, 0x07, val); -} -EXPORT_SYMBOL_GPL(pcf50633_gpio_set); - -u8 pcf50633_gpio_get(struct pcf50633 *pcf, int gpio) -{ - u8 reg, val; - - reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; - val = pcf50633_reg_read(pcf, reg) & 0x07; - - return val; -} -EXPORT_SYMBOL_GPL(pcf50633_gpio_get); - -int pcf50633_gpio_invert_set(struct pcf50633 *pcf, int gpio, int invert) -{ - u8 val, reg; - - reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; - val = !!invert << 3; - - return pcf50633_reg_set_bit_mask(pcf, reg, 1 << 3, val); -} -EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_set); - -int pcf50633_gpio_invert_get(struct pcf50633 *pcf, int gpio) -{ - u8 reg, val; - - reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; - val = pcf50633_reg_read(pcf, reg); - - return val & (1 << 3); -} -EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_get); - -int pcf50633_gpio_power_supply_set(struct pcf50633 *pcf, - int gpio, int regulator, int on) -{ - u8 reg, val, mask; - - /* the *ENA register is always one after the *OUT register */ - reg = pcf50633_regulator_registers[regulator] + 1; - - val = !!on << (gpio - PCF50633_GPIO1); - mask = 1 << (gpio - PCF50633_GPIO1); - - return pcf50633_reg_set_bit_mask(pcf, reg, mask, val); -} -EXPORT_SYMBOL_GPL(pcf50633_gpio_power_supply_set); - -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/pcf50633-irq.c b/drivers/mfd/pcf50633-irq.c deleted file mode 100644 index e85af7f1cb0b..000000000000 --- a/drivers/mfd/pcf50633-irq.c +++ /dev/null @@ -1,312 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* NXP PCF50633 Power Management Unit (PMU) driver - * - * (C) 2006-2008 by Openmoko, Inc. - * Author: Harald Welte <laforge@openmoko.org> - * Balaji Rao <balajirrao@openmoko.org> - * All rights reserved. - */ - -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/mutex.h> -#include <linux/export.h> -#include <linux/slab.h> - -#include <linux/mfd/pcf50633/core.h> -#include <linux/mfd/pcf50633/mbc.h> - -int pcf50633_register_irq(struct pcf50633 *pcf, int irq, - void (*handler) (int, void *), void *data) -{ - if (irq < 0 || irq >= PCF50633_NUM_IRQ || !handler) - return -EINVAL; - - if (WARN_ON(pcf->irq_handler[irq].handler)) - return -EBUSY; - - mutex_lock(&pcf->lock); - pcf->irq_handler[irq].handler = handler; - pcf->irq_handler[irq].data = data; - mutex_unlock(&pcf->lock); - - return 0; -} -EXPORT_SYMBOL_GPL(pcf50633_register_irq); - -int pcf50633_free_irq(struct pcf50633 *pcf, int irq) -{ - if (irq < 0 || irq >= PCF50633_NUM_IRQ) - return -EINVAL; - - mutex_lock(&pcf->lock); - pcf->irq_handler[irq].handler = NULL; - mutex_unlock(&pcf->lock); - - return 0; -} -EXPORT_SYMBOL_GPL(pcf50633_free_irq); - -static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask) -{ - u8 reg, bit; - int idx; - - idx = irq >> 3; - reg = PCF50633_REG_INT1M + idx; - bit = 1 << (irq & 0x07); - - pcf50633_reg_set_bit_mask(pcf, reg, bit, mask ? bit : 0); - - mutex_lock(&pcf->lock); - - if (mask) - pcf->mask_regs[idx] |= bit; - else - pcf->mask_regs[idx] &= ~bit; - - mutex_unlock(&pcf->lock); - - return 0; -} - -int pcf50633_irq_mask(struct pcf50633 *pcf, int irq) -{ - dev_dbg(pcf->dev, "Masking IRQ %d\n", irq); - - return __pcf50633_irq_mask_set(pcf, irq, 1); -} -EXPORT_SYMBOL_GPL(pcf50633_irq_mask); - -int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq) -{ - dev_dbg(pcf->dev, "Unmasking IRQ %d\n", irq); - - return __pcf50633_irq_mask_set(pcf, irq, 0); -} -EXPORT_SYMBOL_GPL(pcf50633_irq_unmask); - -int pcf50633_irq_mask_get(struct pcf50633 *pcf, int irq) -{ - u8 reg, bits; - - reg = irq >> 3; - bits = 1 << (irq & 0x07); - - return pcf->mask_regs[reg] & bits; -} -EXPORT_SYMBOL_GPL(pcf50633_irq_mask_get); - -static void pcf50633_irq_call_handler(struct pcf50633 *pcf, int irq) -{ - if (pcf->irq_handler[irq].handler) - pcf->irq_handler[irq].handler(irq, pcf->irq_handler[irq].data); -} - -/* Maximum amount of time ONKEY is held before emergency action is taken */ -#define PCF50633_ONKEY1S_TIMEOUT 8 - -static irqreturn_t pcf50633_irq(int irq, void *data) -{ - struct pcf50633 *pcf = data; - int ret, i, j; - u8 pcf_int[5], chgstat; - - /* Read the 5 INT regs in one transaction */ - ret = pcf50633_read_block(pcf, PCF50633_REG_INT1, - ARRAY_SIZE(pcf_int), pcf_int); - if (ret != ARRAY_SIZE(pcf_int)) { - dev_err(pcf->dev, "Error reading INT registers\n"); - - /* - * If this doesn't ACK the interrupt to the chip, we'll be - * called once again as we're level triggered. - */ - goto out; - } - - /* defeat 8s death from lowsys on A5 */ - pcf50633_reg_write(pcf, PCF50633_REG_OOCSHDWN, 0x04); - - /* We immediately read the usb and adapter status. We thus make sure - * only of USBINS/USBREM IRQ handlers are called */ - if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) { - chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2); - if (chgstat & (0x3 << 4)) - pcf_int[0] &= ~PCF50633_INT1_USBREM; - else - pcf_int[0] &= ~PCF50633_INT1_USBINS; - } - - /* Make sure only one of ADPINS or ADPREM is set */ - if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) { - chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2); - if (chgstat & (0x3 << 4)) - pcf_int[0] &= ~PCF50633_INT1_ADPREM; - else - pcf_int[0] &= ~PCF50633_INT1_ADPINS; - } - - dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x " - "INT4=0x%02x INT5=0x%02x\n", pcf_int[0], - pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]); - - /* Some revisions of the chip don't have a 8s standby mode on - * ONKEY1S press. We try to manually do it in such cases. */ - if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) { - dev_info(pcf->dev, "ONKEY1S held for %d secs\n", - pcf->onkey1s_held); - if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT) - if (pcf->pdata->force_shutdown) - pcf->pdata->force_shutdown(pcf); - } - - if (pcf_int[2] & PCF50633_INT3_ONKEY1S) { - dev_info(pcf->dev, "ONKEY1S held\n"); - pcf->onkey1s_held = 1 ; - - /* Unmask IRQ_SECOND */ - pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M, - PCF50633_INT1_SECOND); - - /* Unmask IRQ_ONKEYR */ - pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M, - PCF50633_INT2_ONKEYR); - } - - if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) { - pcf->onkey1s_held = 0; - - /* Mask SECOND and ONKEYR interrupts */ - if (pcf->mask_regs[0] & PCF50633_INT1_SECOND) - pcf50633_reg_set_bit_mask(pcf, - PCF50633_REG_INT1M, - PCF50633_INT1_SECOND, - PCF50633_INT1_SECOND); - - if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR) - pcf50633_reg_set_bit_mask(pcf, - PCF50633_REG_INT2M, - PCF50633_INT2_ONKEYR, - PCF50633_INT2_ONKEYR); - } - - /* Have we just resumed ? */ - if (pcf->is_suspended) { - pcf->is_suspended = 0; - - /* Set the resume reason filtering out non resumers */ - for (i = 0; i < ARRAY_SIZE(pcf_int); i++) - pcf->resume_reason[i] = pcf_int[i] & - pcf->pdata->resumers[i]; - - /* Make sure we don't pass on any ONKEY events to - * userspace now */ - pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF); - } - - for (i = 0; i < ARRAY_SIZE(pcf_int); i++) { - /* Unset masked interrupts */ - pcf_int[i] &= ~pcf->mask_regs[i]; - - for (j = 0; j < 8 ; j++) - if (pcf_int[i] & (1 << j)) - pcf50633_irq_call_handler(pcf, (i * 8) + j); - } - -out: - return IRQ_HANDLED; -} - -static int pcf50633_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pcf50633 *pcf = i2c_get_clientdata(client); - int ret; - int i; - u8 res[5]; - - - /* Make sure our interrupt handlers are not called - * henceforth */ - disable_irq(pcf->irq); - - /* Save the masks */ - ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M, - ARRAY_SIZE(pcf->suspend_irq_masks), - pcf->suspend_irq_masks); - if (ret < 0) { - dev_err(pcf->dev, "error saving irq masks\n"); - goto out; - } - - /* Write wakeup irq masks */ - for (i = 0; i < ARRAY_SIZE(res); i++) - res[i] = ~pcf->pdata->resumers[i]; - - ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, - ARRAY_SIZE(res), &res[0]); - if (ret < 0) { - dev_err(pcf->dev, "error writing wakeup irq masks\n"); - goto out; - } - - pcf->is_suspended = 1; - -out: - return ret; -} - -static int pcf50633_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct pcf50633 *pcf = i2c_get_clientdata(client); - int ret; - - /* Write the saved mask registers */ - ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, - ARRAY_SIZE(pcf->suspend_irq_masks), - pcf->suspend_irq_masks); - if (ret < 0) - dev_err(pcf->dev, "Error restoring saved suspend masks\n"); - - enable_irq(pcf->irq); - - return ret; -} - -EXPORT_GPL_SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume); - -int pcf50633_irq_init(struct pcf50633 *pcf, int irq) -{ - int ret; - - pcf->irq = irq; - - /* Enable all interrupts except RTC SECOND */ - pcf->mask_regs[0] = 0x80; - pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]); - pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00); - pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00); - pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00); - pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00); - - ret = request_threaded_irq(irq, NULL, pcf50633_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "pcf50633", pcf); - - if (ret) - dev_err(pcf->dev, "Failed to request IRQ %d\n", ret); - - if (enable_irq_wake(irq) < 0) - dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source" - "in this hardware revision", irq); - - return ret; -} - -void pcf50633_irq_free(struct pcf50633 *pcf) -{ - free_irq(pcf->irq, pcf); -} diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c index 3ac3742f438b..60204cc9a2dc 100644 --- a/drivers/mfd/qcom-pm8008.c +++ b/drivers/mfd/qcom-pm8008.c @@ -4,10 +4,13 @@ */ #include <linux/bitops.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/interrupt.h> +#include <linux/ioport.h> #include <linux/irq.h> #include <linux/irqdomain.h> +#include <linux/mfd/core.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> @@ -15,8 +18,6 @@ #include <linux/regmap.h> #include <linux/slab.h> -#include <dt-bindings/mfd/qcom-pm8008.h> - #define I2C_INTR_STATUS_BASE 0x0550 #define INT_RT_STS_OFFSET 0x10 #define INT_SET_TYPE_OFFSET 0x11 @@ -37,34 +38,54 @@ enum { #define PM8008_PERIPH_0_BASE 0x900 #define PM8008_PERIPH_1_BASE 0x2400 -#define PM8008_PERIPH_2_BASE 0xC000 -#define PM8008_PERIPH_3_BASE 0xC100 +#define PM8008_PERIPH_2_BASE 0xc000 +#define PM8008_PERIPH_3_BASE 0xc100 #define PM8008_TEMP_ALARM_ADDR PM8008_PERIPH_1_BASE #define PM8008_GPIO1_ADDR PM8008_PERIPH_2_BASE #define PM8008_GPIO2_ADDR PM8008_PERIPH_3_BASE +/* PM8008 IRQ numbers */ +#define PM8008_IRQ_MISC_UVLO 0 +#define PM8008_IRQ_MISC_OVLO 1 +#define PM8008_IRQ_MISC_OTST2 2 +#define PM8008_IRQ_MISC_OTST3 3 +#define PM8008_IRQ_MISC_LDO_OCP 4 +#define PM8008_IRQ_TEMP_ALARM 5 +#define PM8008_IRQ_GPIO1 6 +#define PM8008_IRQ_GPIO2 7 + enum { SET_TYPE_INDEX, POLARITY_HI_INDEX, POLARITY_LO_INDEX, }; -static unsigned int pm8008_config_regs[] = { +static const unsigned int pm8008_config_regs[] = { INT_SET_TYPE_OFFSET, INT_POL_HIGH_OFFSET, INT_POL_LOW_OFFSET, }; -static struct regmap_irq pm8008_irqs[] = { - REGMAP_IRQ_REG(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0)), - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1)), - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2)), - REGMAP_IRQ_REG(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3)), - REGMAP_IRQ_REG(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4)), - REGMAP_IRQ_REG(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM, BIT(0)), - REGMAP_IRQ_REG(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0)), - REGMAP_IRQ_REG(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0)), +#define _IRQ(_irq, _off, _mask, _types) \ + [_irq] = { \ + .reg_offset = (_off), \ + .mask = (_mask), \ + .type = { \ + .type_reg_offset = (_off), \ + .types_supported = (_types), \ + }, \ + } + +static const struct regmap_irq pm8008_irqs[] = { + _IRQ(PM8008_IRQ_MISC_UVLO, PM8008_MISC, BIT(0), IRQ_TYPE_EDGE_RISING), + _IRQ(PM8008_IRQ_MISC_OVLO, PM8008_MISC, BIT(1), IRQ_TYPE_EDGE_RISING), + _IRQ(PM8008_IRQ_MISC_OTST2, PM8008_MISC, BIT(2), IRQ_TYPE_EDGE_RISING), + _IRQ(PM8008_IRQ_MISC_OTST3, PM8008_MISC, BIT(3), IRQ_TYPE_EDGE_RISING), + _IRQ(PM8008_IRQ_MISC_LDO_OCP, PM8008_MISC, BIT(4), IRQ_TYPE_EDGE_RISING), + _IRQ(PM8008_IRQ_TEMP_ALARM, PM8008_TEMP_ALARM,BIT(0), IRQ_TYPE_SENSE_MASK), + _IRQ(PM8008_IRQ_GPIO1, PM8008_GPIO1, BIT(0), IRQ_TYPE_SENSE_MASK), + _IRQ(PM8008_IRQ_GPIO2, PM8008_GPIO2, BIT(0), IRQ_TYPE_SENSE_MASK), }; static const unsigned int pm8008_periph_base[] = { @@ -118,8 +139,8 @@ static int pm8008_set_type_config(unsigned int **buf, unsigned int type, return 0; } -static struct regmap_irq_chip pm8008_irq_chip = { - .name = "pm8008_irq", +static const struct regmap_irq_chip pm8008_irq_chip = { + .name = "pm8008", .main_status = I2C_INTR_STATUS_BASE, .num_main_regs = 1, .irqs = pm8008_irqs, @@ -137,62 +158,106 @@ static struct regmap_irq_chip pm8008_irq_chip = { .get_irq_reg = pm8008_get_irq_reg, }; -static struct regmap_config qcom_mfd_regmap_cfg = { +static const struct regmap_config qcom_mfd_regmap_cfg = { + .name = "primary", .reg_bits = 16, .val_bits = 8, - .max_register = 0xFFFF, + .max_register = 0xffff, }; -static int pm8008_probe_irq_peripherals(struct device *dev, - struct regmap *regmap, - int client_irq) -{ - int rc, i; - struct regmap_irq_type *type; - struct regmap_irq_chip_data *irq_data; - - for (i = 0; i < ARRAY_SIZE(pm8008_irqs); i++) { - type = &pm8008_irqs[i].type; +static const struct regmap_config pm8008_regmap_cfg_2 = { + .name = "secondary", + .reg_bits = 16, + .val_bits = 8, + .max_register = 0xffff, +}; - type->type_reg_offset = pm8008_irqs[i].reg_offset; +static const struct resource pm8008_temp_res[] = { + DEFINE_RES_MEM(PM8008_TEMP_ALARM_ADDR, 0x100), + DEFINE_RES_IRQ(PM8008_IRQ_TEMP_ALARM), +}; - if (type->type_reg_offset == PM8008_MISC) - type->types_supported = IRQ_TYPE_EDGE_RISING; - else - type->types_supported = (IRQ_TYPE_EDGE_BOTH | - IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW); - } +static const struct mfd_cell pm8008_cells[] = { + MFD_CELL_NAME("pm8008-regulator"), + MFD_CELL_RES("qpnp-temp-alarm", pm8008_temp_res), + MFD_CELL_NAME("pm8008-gpio"), +}; - rc = devm_regmap_add_irq_chip(dev, regmap, client_irq, - IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data); - if (rc) { - dev_err(dev, "Failed to add IRQ chip: %d\n", rc); - return rc; - } +static void devm_irq_domain_fwnode_release(void *data) +{ + struct fwnode_handle *fwnode = data; - return 0; + irq_domain_free_fwnode(fwnode); } static int pm8008_probe(struct i2c_client *client) { - int rc; - struct device *dev; - struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; + struct device *dev = &client->dev; + struct regmap *regmap, *regmap2; + struct fwnode_handle *fwnode; + struct i2c_client *dummy; + struct gpio_desc *reset; + char *name; + int ret; + + dummy = devm_i2c_new_dummy_device(dev, client->adapter, client->addr + 1); + if (IS_ERR(dummy)) { + ret = PTR_ERR(dummy); + dev_err(dev, "failed to claim second address: %d\n", ret); + return ret; + } + + regmap2 = devm_regmap_init_i2c(dummy, &qcom_mfd_regmap_cfg); + if (IS_ERR(regmap2)) + return PTR_ERR(regmap2); + + ret = regmap_attach_dev(dev, regmap2, &pm8008_regmap_cfg_2); + if (ret) + return ret; - dev = &client->dev; + /* Default regmap must be attached last. */ regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg); if (IS_ERR(regmap)) return PTR_ERR(regmap); - i2c_set_clientdata(client, regmap); + reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset)) + return PTR_ERR(reset); - if (of_property_read_bool(dev->of_node, "interrupt-controller")) { - rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq); - if (rc) - dev_err(dev, "Failed to probe irq periphs: %d\n", rc); + /* + * The PMIC does not appear to require a post-reset delay, but wait + * for a millisecond for now anyway. + */ + usleep_range(1000, 2000); + + name = devm_kasprintf(dev, GFP_KERNEL, "%pOF-internal", dev->of_node); + if (!name) + return -ENOMEM; + + name = strreplace(name, '/', ':'); + + fwnode = irq_domain_alloc_named_fwnode(name); + if (!fwnode) + return -ENOMEM; + + ret = devm_add_action_or_reset(dev, devm_irq_domain_fwnode_release, fwnode); + if (ret) + return ret; + + ret = devm_regmap_add_irq_chip_fwnode(dev, fwnode, regmap, client->irq, + IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data); + if (ret) { + dev_err(dev, "failed to add IRQ chip: %d\n", ret); + return ret; } - return devm_of_platform_populate(dev); + /* Needed by GPIO driver. */ + dev_set_drvdata(dev, regmap_irq_get_domain(irq_data)); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, pm8008_cells, + ARRAY_SIZE(pm8008_cells), NULL, 0, + regmap_irq_get_domain(irq_data)); } static const struct of_device_id pm8008_match[] = { @@ -210,4 +275,5 @@ static struct i2c_driver pm8008_mfd_driver = { }; module_i2c_driver(pm8008_mfd_driver); +MODULE_DESCRIPTION("QCOM PM8008 Power Management IC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index 8b6285f687da..c96ea6fbede8 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -559,10 +559,8 @@ static int pm8xxx_probe(struct platform_device *pdev) chip->pm_irq_data = data; spin_lock_init(&chip->pm_irq_lock); - chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, - data->num_irqs, - &pm8xxx_irq_domain_ops, - chip); + chip->irqdomain = irq_domain_create_linear(of_fwnode_handle(pdev->dev.of_node), + data->num_irqs, &pm8xxx_irq_domain_ops, chip); if (!chip->irqdomain) return -ENODEV; @@ -595,7 +593,7 @@ static void pm8xxx_remove(struct platform_device *pdev) static struct platform_driver pm8xxx_driver = { .probe = pm8xxx_probe, - .remove_new = pm8xxx_remove, + .remove = pm8xxx_remove, .driver = { .name = "pm8xxx-core", .of_match_table = pm8xxx_id_table, diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index eab5bf6cff10..b4b178caf754 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -84,7 +84,6 @@ static const struct of_device_id pmic_spmi_id_table[] = { static struct spmi_device *qcom_pmic_get_base_usid(struct spmi_device *sdev, struct qcom_spmi_dev *ctx) { struct device_node *spmi_bus; - struct device_node *child; int function_parent_usid, ret; u32 pmic_addr; @@ -108,10 +107,9 @@ static struct spmi_device *qcom_pmic_get_base_usid(struct spmi_device *sdev, str */ spmi_bus = of_get_parent(sdev->dev.of_node); sdev = ERR_PTR(-ENODATA); - for_each_child_of_node(spmi_bus, child) { + for_each_child_of_node_scoped(spmi_bus, child) { ret = of_property_read_u32_index(child, "reg", 0, &pmic_addr); if (ret) { - of_node_put(child); sdev = ERR_PTR(ret); break; } @@ -125,7 +123,6 @@ static struct spmi_device *qcom_pmic_get_base_usid(struct spmi_device *sdev, str */ sdev = ERR_PTR(-EPROBE_DEFER); } - of_node_put(child); break; } } diff --git a/drivers/mfd/qnap-mcu.c b/drivers/mfd/qnap-mcu.c new file mode 100644 index 000000000000..89a8a1913d42 --- /dev/null +++ b/drivers/mfd/qnap-mcu.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Core driver for the microcontroller unit in QNAP NAS devices that is + * connected via a dedicated UART port. + * + * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de> + */ + +#include <linux/cleanup.h> +#include <linux/export.h> +#include <linux/mfd/core.h> +#include <linux/mfd/qnap-mcu.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/reboot.h> +#include <linux/serdev.h> +#include <linux/slab.h> + +/* The longest command found so far is 5 bytes long */ +#define QNAP_MCU_MAX_CMD_SIZE 5 +#define QNAP_MCU_MAX_DATA_SIZE 36 +#define QNAP_MCU_CHECKSUM_SIZE 1 + +#define QNAP_MCU_RX_BUFFER_SIZE \ + (QNAP_MCU_MAX_DATA_SIZE + QNAP_MCU_CHECKSUM_SIZE) + +#define QNAP_MCU_TX_BUFFER_SIZE \ + (QNAP_MCU_MAX_CMD_SIZE + QNAP_MCU_CHECKSUM_SIZE) + +#define QNAP_MCU_ACK_LEN 2 +#define QNAP_MCU_VERSION_LEN 4 + +#define QNAP_MCU_TIMEOUT_MS 500 + +/** + * struct qnap_mcu_reply - Reply to a command + * + * @data: Buffer to store reply payload in + * @length: Expected reply length, including the checksum + * @received: Received number of bytes, so far + * @done: Triggered when the entire reply has been received + */ +struct qnap_mcu_reply { + u8 *data; + size_t length; + size_t received; + struct completion done; +}; + +/** + * struct qnap_mcu - QNAP NAS embedded controller + * + * @serdev: Pointer to underlying serdev + * @bus_lock: Lock to serialize access to the device + * @reply: Reply data structure + * @variant: Device variant specific information + * @version: MCU firmware version + */ +struct qnap_mcu { + struct serdev_device *serdev; + struct mutex bus_lock; + struct qnap_mcu_reply reply; + const struct qnap_mcu_variant *variant; + u8 version[QNAP_MCU_VERSION_LEN]; +}; + +/* + * The QNAP-MCU uses a basic XOR checksum. + * It is always the last byte and XORs the whole previous message. + */ +static u8 qnap_mcu_csum(const u8 *buf, size_t size) +{ + u8 csum = 0; + + while (size--) + csum ^= *buf++; + + return csum; +} + +static int qnap_mcu_write(struct qnap_mcu *mcu, const u8 *data, u8 data_size) +{ + unsigned char tx[QNAP_MCU_TX_BUFFER_SIZE]; + size_t length = data_size + QNAP_MCU_CHECKSUM_SIZE; + + if (length > sizeof(tx)) { + dev_err(&mcu->serdev->dev, "data too big for transmit buffer"); + return -EINVAL; + } + + memcpy(tx, data, data_size); + tx[data_size] = qnap_mcu_csum(data, data_size); + + serdev_device_write_flush(mcu->serdev); + + return serdev_device_write(mcu->serdev, tx, length, HZ); +} + +static size_t qnap_mcu_receive_buf(struct serdev_device *serdev, const u8 *buf, size_t size) +{ + struct device *dev = &serdev->dev; + struct qnap_mcu *mcu = dev_get_drvdata(dev); + struct qnap_mcu_reply *reply = &mcu->reply; + const u8 *src = buf; + const u8 *end = buf + size; + + if (!reply->length) { + dev_warn(dev, "Received %zu bytes, we were not waiting for\n", size); + return size; + } + + while (src < end) { + reply->data[reply->received] = *src++; + reply->received++; + + if (reply->received == reply->length) { + /* We don't expect any characters from the device now */ + reply->length = 0; + + complete(&reply->done); + + /* + * We report the consumed number of bytes. If there + * are still bytes remaining (though there shouldn't) + * the serdev layer will re-execute this handler with + * the remainder of the Rx bytes. + */ + return src - buf; + } + } + + /* + * The only way to get out of the above loop and end up here + * is through consuming all of the supplied data, so here we + * report that we processed it all. + */ + return size; +} + +static const struct serdev_device_ops qnap_mcu_serdev_device_ops = { + .receive_buf = qnap_mcu_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +int qnap_mcu_exec(struct qnap_mcu *mcu, + const u8 *cmd_data, size_t cmd_data_size, + u8 *reply_data, size_t reply_data_size) +{ + unsigned char rx[QNAP_MCU_RX_BUFFER_SIZE]; + size_t length = reply_data_size + QNAP_MCU_CHECKSUM_SIZE; + struct qnap_mcu_reply *reply = &mcu->reply; + int ret = 0; + + if (length > sizeof(rx)) { + dev_err(&mcu->serdev->dev, "expected data too big for receive buffer"); + return -EINVAL; + } + + mutex_lock(&mcu->bus_lock); + + reply->data = rx; + reply->length = length; + reply->received = 0; + reinit_completion(&reply->done); + + qnap_mcu_write(mcu, cmd_data, cmd_data_size); + + serdev_device_wait_until_sent(mcu->serdev, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS)); + + if (!wait_for_completion_timeout(&reply->done, msecs_to_jiffies(QNAP_MCU_TIMEOUT_MS))) { + dev_err(&mcu->serdev->dev, "Command timeout\n"); + ret = -ETIMEDOUT; + } else { + u8 crc = qnap_mcu_csum(rx, reply_data_size); + + if (crc != rx[reply_data_size]) { + dev_err(&mcu->serdev->dev, + "Invalid Checksum received\n"); + ret = -EIO; + } else { + memcpy(reply_data, rx, reply_data_size); + } + } + + mutex_unlock(&mcu->bus_lock); + return ret; +} +EXPORT_SYMBOL_GPL(qnap_mcu_exec); + +int qnap_mcu_exec_with_ack(struct qnap_mcu *mcu, + const u8 *cmd_data, size_t cmd_data_size) +{ + u8 ack[QNAP_MCU_ACK_LEN]; + int ret; + + ret = qnap_mcu_exec(mcu, cmd_data, cmd_data_size, ack, sizeof(ack)); + if (ret) + return ret; + + /* Should return @0 */ + if (ack[0] != '@' || ack[1] != '0') { + dev_err(&mcu->serdev->dev, "Did not receive ack\n"); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_GPL(qnap_mcu_exec_with_ack); + +static int qnap_mcu_get_version(struct qnap_mcu *mcu) +{ + const u8 cmd[] = { '%', 'V' }; + u8 rx[14]; + int ret; + + /* Reply is the 2 command-bytes + 4 bytes describing the version */ + ret = qnap_mcu_exec(mcu, cmd, sizeof(cmd), rx, QNAP_MCU_VERSION_LEN + 2); + if (ret) + return ret; + + memcpy(mcu->version, &rx[2], QNAP_MCU_VERSION_LEN); + + return 0; +} + +/* + * The MCU controls power to the peripherals but not the CPU. + * + * So using the PMIC to power off the system keeps the MCU and hard-drives + * running. This also then prevents the system from turning back on until + * the MCU is turned off by unplugging the power cable. + * Turning off the MCU alone on the other hand turns off the hard drives, + * LEDs, etc while the main SoC stays running - including its network ports. + */ +static int qnap_mcu_power_off(struct sys_off_data *data) +{ + const u8 cmd[] = { '@', 'C', '0' }; + struct qnap_mcu *mcu = data->cb_data; + int ret; + + ret = qnap_mcu_exec_with_ack(mcu, cmd, sizeof(cmd)); + if (ret) { + dev_err(&mcu->serdev->dev, "MCU poweroff failed %d\n", ret); + return NOTIFY_STOP; + } + + return NOTIFY_DONE; +} + +static const struct qnap_mcu_variant qnap_ts433_mcu = { + .baud_rate = 115200, + .num_drives = 4, + .fan_pwm_min = 51, /* Specified in original model.conf */ + .fan_pwm_max = 255, + .usb_led = true, +}; + +static struct mfd_cell qnap_mcu_cells[] = { + { .name = "qnap-mcu-input", }, + { .name = "qnap-mcu-leds", }, + { .name = "qnap-mcu-hwmon", } +}; + +static int qnap_mcu_probe(struct serdev_device *serdev) +{ + struct device *dev = &serdev->dev; + struct qnap_mcu *mcu; + int ret; + + mcu = devm_kzalloc(dev, sizeof(*mcu), GFP_KERNEL); + if (!mcu) + return -ENOMEM; + + mcu->serdev = serdev; + dev_set_drvdata(dev, mcu); + + mcu->variant = of_device_get_match_data(dev); + if (!mcu->variant) + return -ENODEV; + + mutex_init(&mcu->bus_lock); + init_completion(&mcu->reply.done); + + serdev_device_set_client_ops(serdev, &qnap_mcu_serdev_device_ops); + ret = devm_serdev_device_open(dev, serdev); + if (ret) + return ret; + + serdev_device_set_baudrate(serdev, mcu->variant->baud_rate); + serdev_device_set_flow_control(serdev, false); + + ret = serdev_device_set_parity(serdev, SERDEV_PARITY_NONE); + if (ret) + return dev_err_probe(dev, ret, "Failed to set parity\n"); + + ret = qnap_mcu_get_version(mcu); + if (ret) + return ret; + + ret = devm_register_sys_off_handler(dev, + SYS_OFF_MODE_POWER_OFF_PREPARE, + SYS_OFF_PRIO_DEFAULT, + &qnap_mcu_power_off, mcu); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register poweroff handler\n"); + + for (int i = 0; i < ARRAY_SIZE(qnap_mcu_cells); i++) { + qnap_mcu_cells[i].platform_data = mcu->variant; + qnap_mcu_cells[i].pdata_size = sizeof(*mcu->variant); + } + + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, qnap_mcu_cells, + ARRAY_SIZE(qnap_mcu_cells), NULL, 0, NULL); + if (ret) + return dev_err_probe(dev, ret, "Failed to add child devices\n"); + + return 0; +} + +static const struct of_device_id qnap_mcu_dt_ids[] = { + { .compatible = "qnap,ts433-mcu", .data = &qnap_ts433_mcu }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, qnap_mcu_dt_ids); + +static struct serdev_device_driver qnap_mcu_drv = { + .probe = qnap_mcu_probe, + .driver = { + .name = "qnap-mcu", + .of_match_table = qnap_mcu_dt_ids, + }, +}; +module_serdev_device_driver(qnap_mcu_drv); + +MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); +MODULE_DESCRIPTION("QNAP MCU core driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rave-sp.c b/drivers/mfd/rave-sp.c index 6ff84b2600c5..c1b78d127a26 100644 --- a/drivers/mfd/rave-sp.c +++ b/drivers/mfd/rave-sp.c @@ -21,7 +21,7 @@ #include <linux/of_platform.h> #include <linux/sched.h> #include <linux/serdev.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> /* * UART protocol using following entities: @@ -358,7 +358,7 @@ int rave_sp_exec(struct rave_sp *sp, ackid = atomic_inc_return(&sp->ackid); reply.ackid = ackid; - reply.code = rave_sp_reply_code((u8)command), + reply.code = rave_sp_reply_code((u8)command); mutex_lock(&sp->bus_lock); @@ -471,8 +471,8 @@ static void rave_sp_receive_frame(struct rave_sp *sp, rave_sp_receive_reply(sp, data, length); } -static ssize_t rave_sp_receive_buf(struct serdev_device *serdev, - const u8 *buf, size_t size) +static size_t rave_sp_receive_buf(struct serdev_device *serdev, + const u8 *buf, size_t size) { struct device *dev = &serdev->dev; struct rave_sp *sp = dev_get_drvdata(dev); diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 5e81f011363f..2c0e8e9630f7 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -230,7 +230,7 @@ static const struct regmap_config rc5t583_regmap_config = { .volatile_reg = volatile_reg, .max_register = RC5T583_MAX_REG, .num_reg_defaults_raw = RC5T583_NUM_REGS, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int rc5t583_i2c_probe(struct i2c_client *i2c) diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index b50cfa7f4b8f..1d43458b4938 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c @@ -65,13 +65,13 @@ static const struct mfd_cell retu_devs[] = { } }; -static struct regmap_irq retu_irqs[] = { +static const struct regmap_irq retu_irqs[] = { [RETU_INT_PWR] = { .mask = 1 << RETU_INT_PWR, } }; -static struct regmap_irq_chip retu_irq_chip = { +static const struct regmap_irq_chip retu_irq_chip = { .name = "RETU", .irqs = retu_irqs, .num_irqs = ARRAY_SIZE(retu_irqs), @@ -101,13 +101,13 @@ static const struct mfd_cell tahvo_devs[] = { }, }; -static struct regmap_irq tahvo_irqs[] = { +static const struct regmap_irq tahvo_irqs[] = { [TAHVO_INT_VBUS] = { .mask = 1 << TAHVO_INT_VBUS, } }; -static struct regmap_irq_chip tahvo_irq_chip = { +static const struct regmap_irq_chip tahvo_irq_chip = { .name = "TAHVO", .irqs = tahvo_irqs, .num_irqs = ARRAY_SIZE(tahvo_irqs), @@ -120,7 +120,7 @@ static struct regmap_irq_chip tahvo_irq_chip = { static const struct retu_data { char *chip_name; char *companion_name; - struct regmap_irq_chip *irq_chip; + const struct regmap_irq_chip *irq_chip; const struct mfd_cell *children; int nchildren; } retu_data[] = { @@ -216,7 +216,7 @@ static int retu_regmap_write(void *context, const void *data, size_t count) return i2c_smbus_write_word_data(i2c, reg, val); } -static struct regmap_bus retu_bus = { +static const struct regmap_bus retu_bus = { .read = retu_regmap_read, .write = retu_regmap_write, .val_format_endian_default = REGMAP_ENDIAN_NATIVE, @@ -300,8 +300,8 @@ static void retu_remove(struct i2c_client *i2c) } static const struct i2c_device_id retu_id[] = { - { "retu", 0 }, - { "tahvo", 0 }, + { "retu" }, + { "tahvo" }, { } }; MODULE_DEVICE_TABLE(i2c, retu_id); diff --git a/drivers/mfd/rk8xx-core.c b/drivers/mfd/rk8xx-core.c index b1ffc3b9e2be..71c2b80a4678 100644 --- a/drivers/mfd/rk8xx-core.c +++ b/drivers/mfd/rk8xx-core.c @@ -28,6 +28,10 @@ static const struct resource rtc_resources[] = { DEFINE_RES_IRQ(RK808_IRQ_RTC_ALARM), }; +static const struct resource rk816_rtc_resources[] = { + DEFINE_RES_IRQ(RK816_IRQ_RTC_ALARM), +}; + static const struct resource rk817_rtc_resources[] = { DEFINE_RES_IRQ(RK817_IRQ_RTC_ALARM), }; @@ -43,8 +47,8 @@ static struct resource rk806_pwrkey_resources[] = { }; static const struct resource rk817_pwrkey_resources[] = { - DEFINE_RES_IRQ(RK817_IRQ_PWRON_RISE), DEFINE_RES_IRQ(RK817_IRQ_PWRON_FALL), + DEFINE_RES_IRQ(RK817_IRQ_PWRON_RISE), }; static const struct resource rk817_charger_resources[] = { @@ -87,6 +91,22 @@ static const struct mfd_cell rk808s[] = { }, }; +static const struct mfd_cell rk816s[] = { + { .name = "rk805-pinctrl", }, + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { + .name = "rk805-pwrkey", + .num_resources = ARRAY_SIZE(rk805_key_resources), + .resources = rk805_key_resources, + }, + { + .name = "rk808-rtc", + .num_resources = ARRAY_SIZE(rk816_rtc_resources), + .resources = rk816_rtc_resources, + }, +}; + static const struct mfd_cell rk817s[] = { { .name = "rk808-clkout", }, { .name = "rk808-regulator", }, @@ -148,6 +168,17 @@ static const struct rk808_reg_data rk808_pre_init_reg[] = { VB_LO_SEL_3500MV }, }; +static const struct rk808_reg_data rk816_pre_init_reg[] = { + { RK818_BUCK1_CONFIG_REG, RK817_RAMP_RATE_MASK, + RK817_RAMP_RATE_12_5MV_PER_US }, + { RK818_BUCK2_CONFIG_REG, RK817_RAMP_RATE_MASK, + RK817_RAMP_RATE_12_5MV_PER_US }, + { RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA }, + { RK808_THERMAL_REG, TEMP_HOTDIE_MSK, TEMP105C}, + { RK808_VB_MON_REG, VBAT_LOW_VOL_MASK | VBAT_LOW_ACT_MASK, + RK808_VBAT_LOW_3V0 | EN_VABT_LOW_SHUT_DOWN }, +}; + static const struct rk808_reg_data rk817_pre_init_reg[] = { {RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP}, /* Codec specific registers */ @@ -350,6 +381,59 @@ static const struct regmap_irq rk808_irqs[] = { }, }; +static const unsigned int rk816_irq_status_offsets[] = { + RK816_IRQ_STS_OFFSET(RK816_INT_STS_REG1), + RK816_IRQ_STS_OFFSET(RK816_INT_STS_REG2), + RK816_IRQ_STS_OFFSET(RK816_INT_STS_REG3), +}; + +static const unsigned int rk816_irq_mask_offsets[] = { + RK816_IRQ_MSK_OFFSET(RK816_INT_STS_MSK_REG1), + RK816_IRQ_MSK_OFFSET(RK816_INT_STS_MSK_REG2), + RK816_IRQ_MSK_OFFSET(RK816_INT_STS_MSK_REG3), +}; + +static unsigned int rk816_get_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base, int index) +{ + unsigned int irq_reg = base; + + switch (base) { + case RK816_INT_STS_REG1: + irq_reg += rk816_irq_status_offsets[index]; + break; + case RK816_INT_STS_MSK_REG1: + irq_reg += rk816_irq_mask_offsets[index]; + break; + } + + return irq_reg; +}; + +static const struct regmap_irq rk816_irqs[] = { + /* INT_STS_REG1 IRQs */ + REGMAP_IRQ_REG(RK816_IRQ_PWRON_FALL, 0, RK816_INT_STS_PWRON_FALL), + REGMAP_IRQ_REG(RK816_IRQ_PWRON_RISE, 0, RK816_INT_STS_PWRON_RISE), + + /* INT_STS_REG2 IRQs */ + REGMAP_IRQ_REG(RK816_IRQ_VB_LOW, 1, RK816_INT_STS_VB_LOW), + REGMAP_IRQ_REG(RK816_IRQ_PWRON, 1, RK816_INT_STS_PWRON), + REGMAP_IRQ_REG(RK816_IRQ_PWRON_LP, 1, RK816_INT_STS_PWRON_LP), + REGMAP_IRQ_REG(RK816_IRQ_HOTDIE, 1, RK816_INT_STS_HOTDIE), + REGMAP_IRQ_REG(RK816_IRQ_RTC_ALARM, 1, RK816_INT_STS_RTC_ALARM), + REGMAP_IRQ_REG(RK816_IRQ_RTC_PERIOD, 1, RK816_INT_STS_RTC_PERIOD), + REGMAP_IRQ_REG(RK816_IRQ_USB_OV, 1, RK816_INT_STS_USB_OV), + + /* INT_STS3 IRQs */ + REGMAP_IRQ_REG(RK816_IRQ_PLUG_IN, 2, RK816_INT_STS_PLUG_IN), + REGMAP_IRQ_REG(RK816_IRQ_PLUG_OUT, 2, RK816_INT_STS_PLUG_OUT), + REGMAP_IRQ_REG(RK816_IRQ_CHG_OK, 2, RK816_INT_STS_CHG_OK), + REGMAP_IRQ_REG(RK816_IRQ_CHG_TE, 2, RK816_INT_STS_CHG_TE), + REGMAP_IRQ_REG(RK816_IRQ_CHG_TS, 2, RK816_INT_STS_CHG_TS), + REGMAP_IRQ_REG(RK816_IRQ_CHG_CVTLIM, 2, RK816_INT_STS_CHG_CVTLIM), + REGMAP_IRQ_REG(RK816_IRQ_DISCHG_ILIM, 2, RK816_INT_STS_DISCHG_ILIM), +}; + static const struct regmap_irq rk818_irqs[] = { /* INT_STS */ [RK818_IRQ_VOUT_LO] = { @@ -447,7 +531,7 @@ static const struct regmap_irq rk817_irqs[RK817_IRQ_END] = { REGMAP_IRQ_REG_LINE(23, 8) }; -static struct regmap_irq_chip rk805_irq_chip = { +static const struct regmap_irq_chip rk805_irq_chip = { .name = "rk805", .irqs = rk805_irqs, .num_irqs = ARRAY_SIZE(rk805_irqs), @@ -458,7 +542,7 @@ static struct regmap_irq_chip rk805_irq_chip = { .init_ack_masked = true, }; -static struct regmap_irq_chip rk806_irq_chip = { +static const struct regmap_irq_chip rk806_irq_chip = { .name = "rk806", .irqs = rk806_irqs, .num_irqs = ARRAY_SIZE(rk806_irqs), @@ -482,7 +566,19 @@ static const struct regmap_irq_chip rk808_irq_chip = { .init_ack_masked = true, }; -static struct regmap_irq_chip rk817_irq_chip = { +static const struct regmap_irq_chip rk816_irq_chip = { + .name = "rk816", + .irqs = rk816_irqs, + .num_irqs = ARRAY_SIZE(rk816_irqs), + .num_regs = 3, + .get_irq_reg = rk816_get_irq_reg, + .status_base = RK816_INT_STS_REG1, + .mask_base = RK816_INT_STS_MSK_REG1, + .ack_base = RK816_INT_STS_REG1, + .init_ack_masked = true, +}; + +static const struct regmap_irq_chip rk817_irq_chip = { .name = "rk817", .irqs = rk817_irqs, .num_irqs = ARRAY_SIZE(rk817_irqs), @@ -522,7 +618,7 @@ static int rk808_power_off(struct sys_off_data *data) bit = DEV_OFF; break; case RK808_ID: - reg = RK808_DEVCTRL_REG, + reg = RK808_DEVCTRL_REG; bit = DEV_OFF_RST; break; case RK809_ID: @@ -530,6 +626,7 @@ static int rk808_power_off(struct sys_off_data *data) reg = RK817_SYS_CFG(3); bit = DEV_OFF; break; + case RK816_ID: case RK818_ID: reg = RK818_DEVCTRL_REG; bit = DEV_OFF; @@ -637,6 +734,13 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap cells = rk808s; nr_cells = ARRAY_SIZE(rk808s); break; + case RK816_ID: + rk808->regmap_irq_chip = &rk816_irq_chip; + pre_init_reg = rk816_pre_init_reg; + nr_pre_init_regs = ARRAY_SIZE(rk816_pre_init_reg); + cells = rk816s; + nr_cells = ARRAY_SIZE(rk816s); + break; case RK818_ID: rk808->regmap_irq_chip = &rk818_irq_chip; pre_init_reg = rk818_pre_init_reg; @@ -681,8 +785,8 @@ int rk8xx_probe(struct device *dev, int variant, unsigned int irq, struct regmap if (ret) return dev_err_probe(dev, ret, "failed to add MFD devices\n"); - if (device_property_read_bool(dev, "rockchip,system-power-controller") || - device_property_read_bool(dev, "system-power-controller")) { + if (device_property_read_bool(dev, "system-power-controller") || + device_property_read_bool(dev, "rockchip,system-power-controller")) { ret = devm_register_sys_off_handler(dev, SYS_OFF_MODE_POWER_OFF_PREPARE, SYS_OFF_PRIO_HIGH, &rk808_power_off, rk808); diff --git a/drivers/mfd/rk8xx-i2c.c b/drivers/mfd/rk8xx-i2c.c index 75b5cf09d5a0..37287b06dab0 100644 --- a/drivers/mfd/rk8xx-i2c.c +++ b/drivers/mfd/rk8xx-i2c.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Rockchip RK808/RK818 Core (I2C) driver + * Rockchip RK805/RK808/RK816/RK817/RK818 Core (I2C) driver * * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd * Copyright (C) 2016 PHYTEC Messtechnik GmbH @@ -21,6 +21,17 @@ struct rk8xx_i2c_platform_data { int variant; }; +static bool rk806_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RK806_POWER_EN0 ... RK806_POWER_EN5: + case RK806_DVS_START_CTRL ... RK806_INT_MSK1: + return true; + } + + return false; +} + static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg) { /* @@ -49,6 +60,35 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg) return false; } +static bool rk816_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* + * Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but + * we don't use that feature. It's better to cache. + */ + + switch (reg) { + case RK808_SECONDS_REG ... RK808_WEEKS_REG: + case RK808_RTC_STATUS_REG: + case RK808_VB_MON_REG: + case RK808_THERMAL_REG: + case RK816_DCDC_EN_REG1: + case RK816_DCDC_EN_REG2: + case RK816_INT_STS_REG1: + case RK816_INT_STS_REG2: + case RK816_INT_STS_REG3: + case RK808_DEVCTRL_REG: + case RK816_SUP_STS_REG: + case RK816_GGSTS_REG: + case RK816_ZERO_CUR_ADC_REGH: + case RK816_ZERO_CUR_ADC_REGL: + case RK816_GASCNT_REG(0) ... RK816_BAT_VOL_REGL: + return true; + } + + return false; +} + static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg) { /* @@ -92,6 +132,14 @@ static const struct regmap_config rk805_regmap_config = { .volatile_reg = rk808_is_volatile_reg, }; +static const struct regmap_config rk806_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK806_BUCK_RSERVE_REG5, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = rk806_is_volatile_reg, +}; + static const struct regmap_config rk808_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -100,6 +148,14 @@ static const struct regmap_config rk808_regmap_config = { .volatile_reg = rk808_is_volatile_reg, }; +static const struct regmap_config rk816_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK816_DATA_REG(18), + .cache_type = REGCACHE_MAPLE, + .volatile_reg = rk816_is_volatile_reg, +}; + static const struct regmap_config rk817_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -113,6 +169,11 @@ static const struct rk8xx_i2c_platform_data rk805_data = { .variant = RK805_ID, }; +static const struct rk8xx_i2c_platform_data rk806_data = { + .regmap_cfg = &rk806_regmap_config, + .variant = RK806_ID, +}; + static const struct rk8xx_i2c_platform_data rk808_data = { .regmap_cfg = &rk808_regmap_config, .variant = RK808_ID, @@ -123,6 +184,11 @@ static const struct rk8xx_i2c_platform_data rk809_data = { .variant = RK809_ID, }; +static const struct rk8xx_i2c_platform_data rk816_data = { + .regmap_cfg = &rk816_regmap_config, + .variant = RK816_ID, +}; + static const struct rk8xx_i2c_platform_data rk817_data = { .regmap_cfg = &rk817_regmap_config, .variant = RK817_ID, @@ -159,8 +225,10 @@ static SIMPLE_DEV_PM_OPS(rk8xx_i2c_pm_ops, rk8xx_suspend, rk8xx_resume); static const struct of_device_id rk8xx_i2c_of_match[] = { { .compatible = "rockchip,rk805", .data = &rk805_data }, + { .compatible = "rockchip,rk806", .data = &rk806_data }, { .compatible = "rockchip,rk808", .data = &rk808_data }, { .compatible = "rockchip,rk809", .data = &rk809_data }, + { .compatible = "rockchip,rk816", .data = &rk816_data }, { .compatible = "rockchip,rk817", .data = &rk817_data }, { .compatible = "rockchip,rk818", .data = &rk818_data }, { }, diff --git a/drivers/mfd/rk8xx-spi.c b/drivers/mfd/rk8xx-spi.c index fd137f38c2c4..3405fb82ff9f 100644 --- a/drivers/mfd/rk8xx-spi.c +++ b/drivers/mfd/rk8xx-spi.c @@ -34,7 +34,7 @@ static const struct regmap_config rk806_regmap_config_spi = { .reg_bits = 16, .val_bits = 8, .max_register = RK806_BUCK_RSERVE_REG5, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .volatile_table = &rk806_volatile_table, }; diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 7336e6d8a001..23ca00d2c624 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -62,7 +62,7 @@ static const struct regmap_config rn5t618_regmap_config = { .val_bits = 8, .volatile_reg = rn5t618_volatile_reg, .max_register = RN5T618_MAX_REG, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct regmap_irq rc5t619_irqs[] = { diff --git a/drivers/mfd/rohm-bd71828.c b/drivers/mfd/rohm-bd71828.c index 594718f7e8e1..738d8b3b9ffe 100644 --- a/drivers/mfd/rohm-bd71828.c +++ b/drivers/mfd/rohm-bd71828.c @@ -32,15 +32,15 @@ static struct gpio_keys_platform_data bd71828_powerkey_data = { }; 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"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC0, "bd70528-rtc-alm-0"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC1, "bd70528-rtc-alm-1"), + DEFINE_RES_IRQ_NAMED(BD71815_INT_RTC2, "bd70528-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"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC0, "bd70528-rtc-alm-0"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC1, "bd70528-rtc-alm-1"), + DEFINE_RES_IRQ_NAMED(BD71828_INT_RTC2, "bd70528-rtc-alm-2"), }; static struct resource bd71815_power_irqs[] = { @@ -197,7 +197,7 @@ static const struct regmap_config bd71815_regmap = { .val_bits = 8, .volatile_table = &bd71815_volatile_regs, .max_register = BD71815_MAX_REGISTER - 1, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct regmap_config bd71828_regmap = { @@ -205,7 +205,7 @@ static const struct regmap_config bd71828_regmap = { .val_bits = 8, .volatile_table = &bd71828_volatile_regs, .max_register = BD71828_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /* @@ -316,7 +316,7 @@ static const struct regmap_irq bd71815_irqs[] = { REGMAP_IRQ_REG(BD71815_INT_RTC2, 11, BD71815_INT_RTC2_MASK), }; -static struct regmap_irq bd71828_irqs[] = { +static const 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), REGMAP_IRQ_REG(BD71828_INT_BUCK3_OCP, 0, BD71828_INT_BUCK3_OCP_MASK), @@ -407,7 +407,7 @@ static struct regmap_irq bd71828_irqs[] = { REGMAP_IRQ_REG(BD71828_INT_RTC2, 11, BD71828_INT_RTC2_MASK), }; -static struct regmap_irq_chip bd71828_irq_chip = { +static const struct regmap_irq_chip bd71828_irq_chip = { .name = "bd71828_irq", .main_status = BD71828_REG_INT_MAIN, .irqs = &bd71828_irqs[0], @@ -423,7 +423,7 @@ static struct regmap_irq_chip bd71828_irq_chip = { .irq_reg_stride = 1, }; -static struct regmap_irq_chip bd71815_irq_chip = { +static const struct regmap_irq_chip bd71815_irq_chip = { .name = "bd71815_irq", .main_status = BD71815_REG_INT_STAT, .irqs = &bd71815_irqs[0], @@ -464,13 +464,34 @@ static int set_clk_mode(struct device *dev, struct regmap *regmap, OUT32K_MODE_CMOS); } +static struct i2c_client *bd71828_dev; +static void bd71828_power_off(void) +{ + while (true) { + s32 val; + + /* We are not allowed to sleep, so do not use regmap involving mutexes here. */ + val = i2c_smbus_read_byte_data(bd71828_dev, BD71828_REG_PS_CTRL_1); + if (val >= 0) + i2c_smbus_write_byte_data(bd71828_dev, + BD71828_REG_PS_CTRL_1, + BD71828_MASK_STATE_HBNT | (u8)val); + mdelay(500); + } +} + +static void bd71828_remove_poweroff(void *data) +{ + pm_power_off = NULL; +} + static int bd71828_i2c_probe(struct i2c_client *i2c) { struct regmap_irq_chip_data *irq_data; int ret; struct regmap *regmap; const struct regmap_config *regmap_config; - struct regmap_irq_chip *irqchip; + const struct regmap_irq_chip *irqchip; unsigned int chip_type; struct mfd_cell *mfd; int cells; @@ -542,7 +563,20 @@ static int bd71828_i2c_probe(struct i2c_client *i2c) ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, mfd, cells, NULL, 0, regmap_irq_get_domain(irq_data)); if (ret) - dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); + return dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); + + if (of_device_is_system_power_controller(i2c->dev.of_node) && + chip_type == ROHM_CHIP_TYPE_BD71828) { + if (!pm_power_off) { + bd71828_dev = i2c; + pm_power_off = bd71828_power_off; + ret = devm_add_action_or_reset(&i2c->dev, + bd71828_remove_poweroff, + NULL); + } else { + dev_warn(&i2c->dev, "Poweroff callback already assigned\n"); + } + } return ret; } diff --git a/drivers/mfd/rohm-bd718x7.c b/drivers/mfd/rohm-bd718x7.c index 4798bdf27afb..25e494a93d48 100644 --- a/drivers/mfd/rohm-bd718x7.c +++ b/drivers/mfd/rohm-bd718x7.c @@ -60,7 +60,7 @@ static const struct regmap_irq bd718xx_irqs[] = { REGMAP_IRQ_REG(BD718XX_INT_STBY_REQ, 0, BD718XX_INT_STBY_REQ_MASK), }; -static struct regmap_irq_chip bd718xx_irq_chip = { +static const struct regmap_irq_chip bd718xx_irq_chip = { .name = "bd718xx-irq", .irqs = bd718xx_irqs, .num_irqs = ARRAY_SIZE(bd718xx_irqs), @@ -87,7 +87,7 @@ static const struct regmap_config bd718xx_regmap_config = { .val_bits = 8, .volatile_table = &volatile_regs, .max_register = BD718XX_MAX_REGISTER - 1, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static int bd718xx_init_press_duration(struct regmap *regmap, diff --git a/drivers/mfd/rohm-bd9576.c b/drivers/mfd/rohm-bd9576.c index bceac7016740..17323ae39803 100644 --- a/drivers/mfd/rohm-bd9576.c +++ b/drivers/mfd/rohm-bd9576.c @@ -57,15 +57,15 @@ static const struct regmap_access_table volatile_regs = { .n_yes_ranges = ARRAY_SIZE(volatile_ranges), }; -static struct regmap_config bd957x_regmap = { +static const struct regmap_config bd957x_regmap = { .reg_bits = 8, .val_bits = 8, .volatile_table = &volatile_regs, .max_register = BD957X_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; -static struct regmap_irq bd9576_irqs[] = { +static const 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), @@ -76,7 +76,7 @@ static struct regmap_irq bd9576_irqs[] = { REGMAP_IRQ_REG(BD9576_INT_SYS, 0, BD957X_MASK_INT_MAIN_SYS), }; -static struct regmap_irq_chip bd9576_irq_chip = { +static const struct regmap_irq_chip bd9576_irq_chip = { .name = "bd9576_irq", .irqs = &bd9576_irqs[0], .num_irqs = ARRAY_SIZE(bd9576_irqs), diff --git a/drivers/mfd/rohm-bd96801.c b/drivers/mfd/rohm-bd96801.c new file mode 100644 index 000000000000..66fa017ad568 --- /dev/null +++ b/drivers/mfd/rohm-bd96801.c @@ -0,0 +1,793 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 ROHM Semiconductors + * + * ROHM BD96801 PMIC driver + * + * This version of the "BD86801 scalable PMIC"'s driver supports only very + * basic set of the PMIC features. + * Most notably, there is no support for the configurations which should + * be done when the PMIC is in STBY mode. + * + * Being able to reliably do the configurations like changing the + * regulator safety limits (like limits for the over/under -voltages, over + * current, thermal protection) would require the configuring driver to be + * synchronized with entity causing the PMIC state transitions. Eg, one + * should be able to ensure the PMIC is in STBY state when the + * configurations are applied to the hardware. How and when the PMIC state + * transitions are to be done is likely to be very system specific, as will + * be the need to configure these safety limits. Hence it's not simple to + * come up with a generic solution. + * + * Users who require the STBY state configurations can have a look at the + * original RFC: + * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ + * which implements some of the safety limit configurations - but leaves the + * state change handling and synchronization to be implemented. + * + * It would be great to hear (and receive a patch!) if you implement the + * STBY configuration support or a proper fix in your downstream driver ;) + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include <linux/mfd/rohm-bd96801.h> +#include <linux/mfd/rohm-bd96802.h> +#include <linux/mfd/rohm-generic.h> + +struct bd968xx { + const struct resource *errb_irqs; + const struct resource *intb_irqs; + int num_errb_irqs; + int num_intb_irqs; + const struct regmap_irq_chip *errb_irq_chip; + const struct regmap_irq_chip *intb_irq_chip; + const struct regmap_config *regmap_config; + struct mfd_cell *cells; + int num_cells; + int unlock_reg; + int unlock_val; +}; + +static const struct resource bd96801_reg_errb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96801_OTP_ERR_STAT, "otp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DBIST_ERR_STAT, "dbist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_EEP_ERR_STAT, "eep-err"), + DEFINE_RES_IRQ_NAMED(BD96801_ABIST_ERR_STAT, "abist-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PRSTB_ERR_STAT, "prstb-err"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS1_ERR_STAT, "drmoserr1"), + DEFINE_RES_IRQ_NAMED(BD96801_DRMOS2_ERR_STAT, "drmoserr2"), + DEFINE_RES_IRQ_NAMED(BD96801_SLAVE_ERR_STAT, "slave-err"), + DEFINE_RES_IRQ_NAMED(BD96801_VREF_ERR_STAT, "vref-err"), + DEFINE_RES_IRQ_NAMED(BD96801_TSD_ERR_STAT, "tsd"), + DEFINE_RES_IRQ_NAMED(BD96801_UVLO_ERR_STAT, "uvlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OVLO_ERR_STAT, "ovlo-err"), + DEFINE_RES_IRQ_NAMED(BD96801_OSC_ERR_STAT, "osc-err"), + DEFINE_RES_IRQ_NAMED(BD96801_PON_ERR_STAT, "pon-err"), + DEFINE_RES_IRQ_NAMED(BD96801_POFF_ERR_STAT, "poff-err"), + DEFINE_RES_IRQ_NAMED(BD96801_CMD_SHDN_ERR_STAT, "cmd-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_INT_PRSTB_WDT_ERR, "bd96801-prstb-wdt-err"), + DEFINE_RES_IRQ_NAMED(BD96801_INT_CHIP_IF_ERR, "bd96801-chip-if-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_INT_SHDN_ERR_STAT, "int-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_PVIN_ERR_STAT, "buck1-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVP_ERR_STAT, "buck1-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVP_ERR_STAT, "buck1-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_SHDN_ERR_STAT, "buck1-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_PVIN_ERR_STAT, "buck2-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVP_ERR_STAT, "buck2-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVP_ERR_STAT, "buck2-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_SHDN_ERR_STAT, "buck2-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_PVIN_ERR_STAT, "buck3-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVP_ERR_STAT, "buck3-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVP_ERR_STAT, "buck3-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_SHDN_ERR_STAT, "buck3-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_PVIN_ERR_STAT, "buck4-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVP_ERR_STAT, "buck4-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVP_ERR_STAT, "buck4-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_SHDN_ERR_STAT, "buck4-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_PVIN_ERR_STAT, "ldo5-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVP_ERR_STAT, "ldo5-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVP_ERR_STAT, "ldo5-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_SHDN_ERR_STAT, "ldo5-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_PVIN_ERR_STAT, "ldo6-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVP_ERR_STAT, "ldo6-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVP_ERR_STAT, "ldo6-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_SHDN_ERR_STAT, "ldo6-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_PVIN_ERR_STAT, "ldo7-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVP_ERR_STAT, "ldo7-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVP_ERR_STAT, "ldo7-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_SHDN_ERR_STAT, "ldo7-shdn-err"), +}; + +static const struct resource bd96802_reg_errb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96802_OTP_ERR_STAT, "otp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_DBIST_ERR_STAT, "dbist-err"), + DEFINE_RES_IRQ_NAMED(BD96802_EEP_ERR_STAT, "eep-err"), + DEFINE_RES_IRQ_NAMED(BD96802_ABIST_ERR_STAT, "abist-err"), + DEFINE_RES_IRQ_NAMED(BD96802_PRSTB_ERR_STAT, "prstb-err"), + DEFINE_RES_IRQ_NAMED(BD96802_DRMOS1_ERR_STAT, "drmoserr1"), + DEFINE_RES_IRQ_NAMED(BD96802_DRMOS1_ERR_STAT, "drmoserr2"), + DEFINE_RES_IRQ_NAMED(BD96802_SLAVE_ERR_STAT, "slave-err"), + DEFINE_RES_IRQ_NAMED(BD96802_VREF_ERR_STAT, "vref-err"), + DEFINE_RES_IRQ_NAMED(BD96802_TSD_ERR_STAT, "tsd"), + DEFINE_RES_IRQ_NAMED(BD96802_UVLO_ERR_STAT, "uvlo-err"), + DEFINE_RES_IRQ_NAMED(BD96802_OVLO_ERR_STAT, "ovlo-err"), + DEFINE_RES_IRQ_NAMED(BD96802_OSC_ERR_STAT, "osc-err"), + DEFINE_RES_IRQ_NAMED(BD96802_PON_ERR_STAT, "pon-err"), + DEFINE_RES_IRQ_NAMED(BD96802_POFF_ERR_STAT, "poff-err"), + DEFINE_RES_IRQ_NAMED(BD96802_CMD_SHDN_ERR_STAT, "cmd-shdn-err"), + DEFINE_RES_IRQ_NAMED(BD96802_INT_SHDN_ERR_STAT, "int-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_PVIN_ERR_STAT, "buck1-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OVP_ERR_STAT, "buck1-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_UVP_ERR_STAT, "buck1-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_SHDN_ERR_STAT, "buck1-shdn-err"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_PVIN_ERR_STAT, "buck2-pvin-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OVP_ERR_STAT, "buck2-ovp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_UVP_ERR_STAT, "buck2-uvp-err"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_SHDN_ERR_STAT, "buck2-shdn-err"), +}; + +static const struct resource bd96801_reg_intb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96801_TW_STAT, "core-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPH_STAT, "buck1-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPL_STAT, "buck1-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OCPN_STAT, "buck1-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_OVD_STAT, "buck1-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_UVD_STAT, "buck1-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK1_TW_CH_STAT, "buck1-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPH_STAT, "buck2-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPL_STAT, "buck2-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OCPN_STAT, "buck2-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_OVD_STAT, "buck2-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_UVD_STAT, "buck2-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK2_TW_CH_STAT, "buck2-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPH_STAT, "buck3-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPL_STAT, "buck3-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OCPN_STAT, "buck3-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_OVD_STAT, "buck3-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_UVD_STAT, "buck3-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK3_TW_CH_STAT, "buck3-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPH_STAT, "buck4-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPL_STAT, "buck4-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OCPN_STAT, "buck4-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_OVD_STAT, "buck4-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_UVD_STAT, "buck4-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96801_BUCK4_TW_CH_STAT, "buck4-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OCPH_STAT, "ldo5-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_OVD_STAT, "ldo5-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO5_UVD_STAT, "ldo5-undervolt"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OCPH_STAT, "ldo6-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_OVD_STAT, "ldo6-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO6_UVD_STAT, "ldo6-undervolt"), + + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OCPH_STAT, "ldo7-overcurr"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_OVD_STAT, "ldo7-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96801_LDO7_UVD_STAT, "ldo7-undervolt"), +}; + +static const struct resource bd96802_reg_intb_irqs[] = { + DEFINE_RES_IRQ_NAMED(BD96802_TW_STAT, "core-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPH_STAT, "buck1-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPL_STAT, "buck1-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OCPN_STAT, "buck1-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_OVD_STAT, "buck1-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_UVD_STAT, "buck1-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK1_TW_CH_STAT, "buck1-thermal"), + + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPH_STAT, "buck2-overcurr-h"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPL_STAT, "buck2-overcurr-l"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OCPN_STAT, "buck2-overcurr-n"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_OVD_STAT, "buck2-overvolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_UVD_STAT, "buck2-undervolt"), + DEFINE_RES_IRQ_NAMED(BD96802_BUCK2_TW_CH_STAT, "buck2-thermal"), +}; + +enum { + WDG_CELL = 0, + REGULATOR_CELL, +}; + +static struct mfd_cell bd96801_cells[] = { + [WDG_CELL] = { .name = "bd96801-wdt", }, + [REGULATOR_CELL] = { .name = "bd96801-regulator", }, +}; + +static struct mfd_cell bd96802_cells[] = { + [WDG_CELL] = { .name = "bd96801-wdt", }, + [REGULATOR_CELL] = { .name = "bd96802-regulator", }, +}; +static struct mfd_cell bd96805_cells[] = { + [WDG_CELL] = { .name = "bd96801-wdt", }, + [REGULATOR_CELL] = { .name = "bd96805-regulator", }, +}; + +static struct mfd_cell bd96806_cells[] = { + [WDG_CELL] = { .name = "bd96806-wdt", }, + [REGULATOR_CELL] = { .name = "bd96806-regulator", }, +}; + +static const struct regmap_range bd96801_volatile_ranges[] = { + /* Status registers */ + regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), + regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK), + regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS), + regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_LDO7_INTB), + /* Registers which do not update value unless PMIC is in STBY */ + regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB), + regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME), + /* + * LDO control registers have single bit (LDO MODE) which does not + * change when we write it unless PMIC is in STBY. It's safer to not + * cache it. + */ + regmap_reg_range(BD96801_LDO5_VOL_LVL_REG, BD96801_LDO7_VOL_LVL_REG), +}; + +static const struct regmap_range bd96802_volatile_ranges[] = { + /* Status regs */ + regmap_reg_range(BD96801_REG_WD_FEED, BD96801_REG_WD_FAILCOUNT), + regmap_reg_range(BD96801_REG_WD_ASK, BD96801_REG_WD_ASK), + regmap_reg_range(BD96801_REG_WD_STATUS, BD96801_REG_WD_STATUS), + regmap_reg_range(BD96801_REG_PMIC_STATE, BD96801_REG_INT_BUCK2_ERRB), + regmap_reg_range(BD96801_REG_INT_SYS_INTB, BD96801_REG_INT_BUCK2_INTB), + /* Registers which do not update value unless PMIC is in STBY */ + regmap_reg_range(BD96801_REG_SSCG_CTRL, BD96801_REG_SHD_INTB), + regmap_reg_range(BD96801_REG_BUCK_OVP, BD96801_REG_BOOT_OVERTIME), +}; + +static const struct regmap_access_table bd96801_volatile_regs = { + .yes_ranges = bd96801_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(bd96801_volatile_ranges), +}; + +static const struct regmap_access_table bd96802_volatile_regs = { + .yes_ranges = bd96802_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(bd96802_volatile_ranges), +}; + +/* + * For ERRB we need main register bit mapping as bit(0) indicates active IRQ + * in one of the first 3 sub IRQ registers, For INTB we can use default 1 to 1 + * mapping. + */ +static unsigned int bit0_offsets[] = {0, 1, 2}; /* System stat, 3 registers */ +static unsigned int bit1_offsets[] = {3}; /* Buck 1 stat */ +static unsigned int bit2_offsets[] = {4}; /* Buck 2 stat */ +static unsigned int bit3_offsets[] = {5}; /* Buck 3 stat */ +static unsigned int bit4_offsets[] = {6}; /* Buck 4 stat */ +static unsigned int bit5_offsets[] = {7}; /* LDO 5 stat */ +static unsigned int bit6_offsets[] = {8}; /* LDO 6 stat */ +static unsigned int bit7_offsets[] = {9}; /* LDO 7 stat */ + +static const struct regmap_irq_sub_irq_map bd96801_errb_sub_irq_offsets[] = { + REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit5_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit6_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), +}; + +static const struct regmap_irq_sub_irq_map bd96802_errb_sub_irq_offsets[] = { + REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), +}; + +static const struct regmap_irq bd96801_errb_irqs[] = { + /* Reg 0x52 Fatal ERRB1 */ + REGMAP_IRQ_REG(BD96801_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DBIST_ERR_STAT, 0, BD96801_DBIST_ERR_MASK), + REGMAP_IRQ_REG(BD96801_EEP_ERR_STAT, 0, BD96801_EEP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_ABIST_ERR_STAT, 0, BD96801_ABIST_ERR_MASK), + REGMAP_IRQ_REG(BD96801_PRSTB_ERR_STAT, 0, BD96801_PRSTB_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DRMOS1_ERR_STAT, 0, BD96801_DRMOS1_ERR_MASK), + REGMAP_IRQ_REG(BD96801_DRMOS2_ERR_STAT, 0, BD96801_DRMOS2_ERR_MASK), + REGMAP_IRQ_REG(BD96801_SLAVE_ERR_STAT, 0, BD96801_SLAVE_ERR_MASK), + /* 0x53 Fatal ERRB2 */ + REGMAP_IRQ_REG(BD96801_VREF_ERR_STAT, 1, BD96801_VREF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_TSD_ERR_STAT, 1, BD96801_TSD_ERR_MASK), + REGMAP_IRQ_REG(BD96801_UVLO_ERR_STAT, 1, BD96801_UVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96801_OVLO_ERR_STAT, 1, BD96801_OVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96801_OSC_ERR_STAT, 1, BD96801_OSC_ERR_MASK), + REGMAP_IRQ_REG(BD96801_PON_ERR_STAT, 1, BD96801_PON_ERR_MASK), + REGMAP_IRQ_REG(BD96801_POFF_ERR_STAT, 1, BD96801_POFF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_CMD_SHDN_ERR_STAT, 1, BD96801_CMD_SHDN_ERR_MASK), + /* 0x54 Fatal INTB shadowed to ERRB */ + REGMAP_IRQ_REG(BD96801_INT_PRSTB_WDT_ERR, 2, BD96801_INT_PRSTB_WDT_ERR_MASK), + REGMAP_IRQ_REG(BD96801_INT_CHIP_IF_ERR, 2, BD96801_INT_CHIP_IF_ERR_MASK), + REGMAP_IRQ_REG(BD96801_INT_SHDN_ERR_STAT, 2, BD96801_INT_SHDN_ERR_MASK), + /* Reg 0x55 BUCK1 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK1_PVIN_ERR_STAT, 3, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OVP_ERR_STAT, 3, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_UVP_ERR_STAT, 3, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_SHDN_ERR_STAT, 3, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x56 BUCK2 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK2_PVIN_ERR_STAT, 4, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OVP_ERR_STAT, 4, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_UVP_ERR_STAT, 4, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_SHDN_ERR_STAT, 4, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x57 BUCK3 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK3_PVIN_ERR_STAT, 5, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OVP_ERR_STAT, 5, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_UVP_ERR_STAT, 5, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_SHDN_ERR_STAT, 5, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x58 BUCK4 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_BUCK4_PVIN_ERR_STAT, 6, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OVP_ERR_STAT, 6, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_UVP_ERR_STAT, 6, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_SHDN_ERR_STAT, 6, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x59 LDO5 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO5_PVIN_ERR_STAT, 7, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_OVP_ERR_STAT, 7, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_UVP_ERR_STAT, 7, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_SHDN_ERR_STAT, 7, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x5a LDO6 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO6_PVIN_ERR_STAT, 8, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_OVP_ERR_STAT, 8, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_UVP_ERR_STAT, 8, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_SHDN_ERR_STAT, 8, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x5b LDO7 ERR IRQs */ + REGMAP_IRQ_REG(BD96801_LDO7_PVIN_ERR_STAT, 9, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_OVP_ERR_STAT, 9, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_UVP_ERR_STAT, 9, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_SHDN_ERR_STAT, 9, BD96801_OUT_SHDN_ERR_MASK), +}; + +static const struct regmap_irq bd96802_errb_irqs[] = { + /* Reg 0x52 Fatal ERRB1 */ + REGMAP_IRQ_REG(BD96802_OTP_ERR_STAT, 0, BD96801_OTP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_DBIST_ERR_STAT, 0, BD96801_DBIST_ERR_MASK), + REGMAP_IRQ_REG(BD96802_EEP_ERR_STAT, 0, BD96801_EEP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_ABIST_ERR_STAT, 0, BD96801_ABIST_ERR_MASK), + REGMAP_IRQ_REG(BD96802_PRSTB_ERR_STAT, 0, BD96801_PRSTB_ERR_MASK), + REGMAP_IRQ_REG(BD96802_DRMOS1_ERR_STAT, 0, BD96801_DRMOS1_ERR_MASK), + REGMAP_IRQ_REG(BD96802_DRMOS2_ERR_STAT, 0, BD96801_DRMOS2_ERR_MASK), + REGMAP_IRQ_REG(BD96802_SLAVE_ERR_STAT, 0, BD96801_SLAVE_ERR_MASK), + /* 0x53 Fatal ERRB2 */ + REGMAP_IRQ_REG(BD96802_VREF_ERR_STAT, 1, BD96801_VREF_ERR_MASK), + REGMAP_IRQ_REG(BD96802_TSD_ERR_STAT, 1, BD96801_TSD_ERR_MASK), + REGMAP_IRQ_REG(BD96802_UVLO_ERR_STAT, 1, BD96801_UVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96802_OVLO_ERR_STAT, 1, BD96801_OVLO_ERR_MASK), + REGMAP_IRQ_REG(BD96802_OSC_ERR_STAT, 1, BD96801_OSC_ERR_MASK), + REGMAP_IRQ_REG(BD96802_PON_ERR_STAT, 1, BD96801_PON_ERR_MASK), + REGMAP_IRQ_REG(BD96802_POFF_ERR_STAT, 1, BD96801_POFF_ERR_MASK), + REGMAP_IRQ_REG(BD96802_CMD_SHDN_ERR_STAT, 1, BD96801_CMD_SHDN_ERR_MASK), + /* 0x54 Fatal INTB shadowed to ERRB */ + REGMAP_IRQ_REG(BD96802_INT_SHDN_ERR_STAT, 2, BD96801_INT_SHDN_ERR_MASK), + /* Reg 0x55 BUCK1 ERR IRQs */ + REGMAP_IRQ_REG(BD96802_BUCK1_PVIN_ERR_STAT, 3, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OVP_ERR_STAT, 3, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_UVP_ERR_STAT, 3, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_SHDN_ERR_STAT, 3, BD96801_OUT_SHDN_ERR_MASK), + /* Reg 0x56 BUCK2 ERR IRQs */ + REGMAP_IRQ_REG(BD96802_BUCK2_PVIN_ERR_STAT, 4, BD96801_OUT_PVIN_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OVP_ERR_STAT, 4, BD96801_OUT_OVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_UVP_ERR_STAT, 4, BD96801_OUT_UVP_ERR_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_SHDN_ERR_STAT, 4, BD96801_OUT_SHDN_ERR_MASK), +}; + +static const struct regmap_irq bd96801_intb_irqs[] = { + /* STATUS SYSTEM INTB */ + REGMAP_IRQ_REG(BD96801_TW_STAT, 0, BD96801_TW_STAT_MASK), + REGMAP_IRQ_REG(BD96801_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96801_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96801_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK), + /* STATUS BUCK1 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 2 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 3 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK3_OCPH_STAT, 3, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OCPL_STAT, 3, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OCPN_STAT, 3, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_OVD_STAT, 3, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_UVD_STAT, 3, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK3_TW_CH_STAT, 3, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 4 INTB */ + REGMAP_IRQ_REG(BD96801_BUCK4_OCPH_STAT, 4, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OCPL_STAT, 4, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OCPN_STAT, 4, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_OVD_STAT, 4, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_UVD_STAT, 4, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_BUCK4_TW_CH_STAT, 4, BD96801_BUCK_TW_CH_STAT_MASK), + /* LDO5 INTB */ + REGMAP_IRQ_REG(BD96801_LDO5_OCPH_STAT, 5, BD96801_LDO_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_OVD_STAT, 5, BD96801_LDO_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO5_UVD_STAT, 5, BD96801_LDO_UVD_STAT_MASK), + /* LDO6 INTB */ + REGMAP_IRQ_REG(BD96801_LDO6_OCPH_STAT, 6, BD96801_LDO_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_OVD_STAT, 6, BD96801_LDO_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO6_UVD_STAT, 6, BD96801_LDO_UVD_STAT_MASK), + /* LDO7 INTB */ + REGMAP_IRQ_REG(BD96801_LDO7_OCPH_STAT, 7, BD96801_LDO_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_OVD_STAT, 7, BD96801_LDO_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96801_LDO7_UVD_STAT, 7, BD96801_LDO_UVD_STAT_MASK), +}; + +static const struct regmap_irq bd96802_intb_irqs[] = { + /* STATUS SYSTEM INTB */ + REGMAP_IRQ_REG(BD96802_TW_STAT, 0, BD96801_TW_STAT_MASK), + REGMAP_IRQ_REG(BD96802_WDT_ERR_STAT, 0, BD96801_WDT_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96802_I2C_ERR_STAT, 0, BD96801_I2C_ERR_STAT_MASK), + REGMAP_IRQ_REG(BD96802_CHIP_IF_ERR_STAT, 0, BD96801_CHIP_IF_ERR_STAT_MASK), + /* STATUS BUCK1 INTB */ + REGMAP_IRQ_REG(BD96802_BUCK1_OCPH_STAT, 1, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OCPL_STAT, 1, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OCPN_STAT, 1, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_OVD_STAT, 1, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_UVD_STAT, 1, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK1_TW_CH_STAT, 1, BD96801_BUCK_TW_CH_STAT_MASK), + /* BUCK 2 INTB */ + REGMAP_IRQ_REG(BD96802_BUCK2_OCPH_STAT, 2, BD96801_BUCK_OCPH_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OCPL_STAT, 2, BD96801_BUCK_OCPL_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OCPN_STAT, 2, BD96801_BUCK_OCPN_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_OVD_STAT, 2, BD96801_BUCK_OVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_UVD_STAT, 2, BD96801_BUCK_UVD_STAT_MASK), + REGMAP_IRQ_REG(BD96802_BUCK2_TW_CH_STAT, 2, BD96801_BUCK_TW_CH_STAT_MASK), +}; + +/* + * The IRQ stuff is a bit hairy. The BD96801 / BD96802 provide two physical + * IRQ lines called INTB and ERRB. They share the same main status register. + * + * For ERRB, mapping from main status to sub-status is such that the + * 'global' faults are mapped to first 3 sub-status registers - and indicated + * by the first bit[0] in main status reg. + * + * Rest of the status registers are for indicating stuff for individual + * regulators, 1 sub register / regulator and 1 main status register bit / + * regulator, starting from bit[1]. + * + * Eg, regulator specific stuff has 1 to 1 mapping from main-status to sub + * registers but 'global' ERRB IRQs require mapping from main status bit[0] to + * 3 status registers. + * + * Furthermore, the BD96801 has 7 regulators where the BD96802 has only 2. + * + * INTB has only 1 sub status register for 'global' events and then own sub + * status register for each of the regulators. So, for INTB we have direct + * 1 to 1 mapping - BD96801 just having 5 register and 5 main status bits + * more than the BD96802. + * + * Sharing the main status bits could be a problem if we had both INTB and + * ERRB IRQs asserted but for different sub-status offsets. This might lead + * IRQ controller code to go read a sub status register which indicates no + * active IRQs. I assume this occurring repeteadly might lead the IRQ to be + * disabled by core as a result of repeteadly returned IRQ_NONEs. + * + * I don't consider this as a fatal problem for now because: + * a) Having ERRB asserted leads to PMIC fault state which will kill + * the SoC powered by the PMIC. (So, relevant only for potential + * case of not powering the processor with this PMIC). + * b) Having ERRB set without having respective INTB is unlikely + * (haven't actually verified this). + * + * So, let's proceed with main status enabled for both INTB and ERRB. We can + * later disable main-status usage on systems where this ever proves to be + * a problem. + */ + +static const struct regmap_irq_chip bd96801_irq_chip_errb = { + .name = "bd96801-irq-errb", + .domain_suffix = "errb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96801_errb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96801_errb_irqs), + .status_base = BD96801_REG_INT_SYS_ERRB1, + .mask_base = BD96801_REG_MASK_SYS_ERRB, + .ack_base = BD96801_REG_INT_SYS_ERRB1, + .init_ack_masked = true, + .num_regs = 10, + .irq_reg_stride = 1, + .sub_reg_offsets = &bd96801_errb_sub_irq_offsets[0], +}; + +static const struct regmap_irq_chip bd96802_irq_chip_errb = { + .name = "bd96802-irq-errb", + .domain_suffix = "errb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96802_errb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96802_errb_irqs), + .status_base = BD96801_REG_INT_SYS_ERRB1, + .mask_base = BD96801_REG_MASK_SYS_ERRB, + .ack_base = BD96801_REG_INT_SYS_ERRB1, + .init_ack_masked = true, + .num_regs = 5, + .irq_reg_stride = 1, + .sub_reg_offsets = &bd96802_errb_sub_irq_offsets[0], +}; + +static const struct regmap_irq_chip bd96801_irq_chip_intb = { + .name = "bd96801-irq-intb", + .domain_suffix = "intb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96801_intb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96801_intb_irqs), + .status_base = BD96801_REG_INT_SYS_INTB, + .mask_base = BD96801_REG_MASK_SYS_INTB, + .ack_base = BD96801_REG_INT_SYS_INTB, + .init_ack_masked = true, + .num_regs = 8, + .irq_reg_stride = 1, +}; + +static const struct regmap_irq_chip bd96802_irq_chip_intb = { + .name = "bd96802-irq-intb", + .domain_suffix = "intb", + .main_status = BD96801_REG_INT_MAIN, + .num_main_regs = 1, + .irqs = &bd96802_intb_irqs[0], + .num_irqs = ARRAY_SIZE(bd96802_intb_irqs), + .status_base = BD96801_REG_INT_SYS_INTB, + .mask_base = BD96801_REG_MASK_SYS_INTB, + .ack_base = BD96801_REG_INT_SYS_INTB, + .init_ack_masked = true, + .num_regs = 3, + .irq_reg_stride = 1, +}; + +static const struct regmap_config bd96801_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &bd96801_volatile_regs, + .cache_type = REGCACHE_MAPLE, +}; + +static const struct regmap_config bd96802_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_table = &bd96802_volatile_regs, + .cache_type = REGCACHE_MAPLE, +}; + +static const struct bd968xx bd96801_data = { + .errb_irqs = bd96801_reg_errb_irqs, + .intb_irqs = bd96801_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96801_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96801_reg_intb_irqs), + .errb_irq_chip = &bd96801_irq_chip_errb, + .intb_irq_chip = &bd96801_irq_chip_intb, + .regmap_config = &bd96801_regmap_config, + .cells = bd96801_cells, + .num_cells = ARRAY_SIZE(bd96801_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + +static const struct bd968xx bd96802_data = { + .errb_irqs = bd96802_reg_errb_irqs, + .intb_irqs = bd96802_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96802_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96802_reg_intb_irqs), + .errb_irq_chip = &bd96802_irq_chip_errb, + .intb_irq_chip = &bd96802_irq_chip_intb, + .regmap_config = &bd96802_regmap_config, + .cells = bd96802_cells, + .num_cells = ARRAY_SIZE(bd96802_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + +static const struct bd968xx bd96805_data = { + .errb_irqs = bd96801_reg_errb_irqs, + .intb_irqs = bd96801_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96801_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96801_reg_intb_irqs), + .errb_irq_chip = &bd96801_irq_chip_errb, + .intb_irq_chip = &bd96801_irq_chip_intb, + .regmap_config = &bd96801_regmap_config, + .cells = bd96805_cells, + .num_cells = ARRAY_SIZE(bd96805_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + +static struct bd968xx bd96806_data = { + .errb_irqs = bd96802_reg_errb_irqs, + .intb_irqs = bd96802_reg_intb_irqs, + .num_errb_irqs = ARRAY_SIZE(bd96802_reg_errb_irqs), + .num_intb_irqs = ARRAY_SIZE(bd96802_reg_intb_irqs), + .errb_irq_chip = &bd96802_irq_chip_errb, + .intb_irq_chip = &bd96802_irq_chip_intb, + .regmap_config = &bd96802_regmap_config, + .cells = bd96806_cells, + .num_cells = ARRAY_SIZE(bd96806_cells), + .unlock_reg = BD96801_LOCK_REG, + .unlock_val = BD96801_UNLOCK, +}; + +static int bd96801_i2c_probe(struct i2c_client *i2c) +{ + struct regmap_irq_chip_data *intb_irq_data, *errb_irq_data; + struct irq_domain *intb_domain, *errb_domain; + const struct bd968xx *ddata; + const struct fwnode_handle *fwnode; + struct resource *regulator_res; + struct resource wdg_irq; + struct regmap *regmap; + int intb_irq, errb_irq, num_errb = 0; + int num_regu_irqs, wdg_irq_no; + unsigned int chip_type; + int i, ret; + + chip_type = (unsigned int)(uintptr_t)device_get_match_data(&i2c->dev); + switch (chip_type) { + case ROHM_CHIP_TYPE_BD96801: + ddata = &bd96801_data; + break; + case ROHM_CHIP_TYPE_BD96802: + ddata = &bd96802_data; + break; + case ROHM_CHIP_TYPE_BD96805: + ddata = &bd96805_data; + break; + case ROHM_CHIP_TYPE_BD96806: + ddata = &bd96806_data; + break; + default: + dev_err(&i2c->dev, "Unknown IC\n"); + return -EINVAL; + } + + fwnode = dev_fwnode(&i2c->dev); + if (!fwnode) + return dev_err_probe(&i2c->dev, -EINVAL, "Failed to find fwnode\n"); + + intb_irq = fwnode_irq_get_byname(fwnode, "intb"); + if (intb_irq < 0) + return dev_err_probe(&i2c->dev, intb_irq, "INTB IRQ not configured\n"); + + /* ERRB may be omitted if processor is powered by the PMIC */ + errb_irq = fwnode_irq_get_byname(fwnode, "errb"); + if (errb_irq == -EPROBE_DEFER) + return errb_irq; + + if (errb_irq > 0) + num_errb = ddata->num_errb_irqs; + + num_regu_irqs = ddata->num_intb_irqs + num_errb; + + regulator_res = devm_kcalloc(&i2c->dev, num_regu_irqs, + sizeof(*regulator_res), GFP_KERNEL); + if (!regulator_res) + return -ENOMEM; + + regmap = devm_regmap_init_i2c(i2c, ddata->regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(regmap), + "Regmap initialization failed\n"); + + ret = regmap_write(regmap, ddata->unlock_reg, ddata->unlock_val); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to unlock PMIC\n"); + + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, intb_irq, + IRQF_ONESHOT, 0, ddata->intb_irq_chip, + &intb_irq_data); + if (ret) + return dev_err_probe(&i2c->dev, ret, "Failed to add INTB IRQ chip\n"); + + intb_domain = regmap_irq_get_domain(intb_irq_data); + + /* + * MFD core code is built to handle only one IRQ domain. BD96801 + * has two domains so we do IRQ mapping here and provide the + * already mapped IRQ numbers to sub-devices. + */ + for (i = 0; i < ddata->num_intb_irqs; i++) { + struct resource *res = ®ulator_res[i]; + + *res = ddata->intb_irqs[i]; + res->start = res->end = irq_create_mapping(intb_domain, + res->start); + } + + wdg_irq_no = irq_create_mapping(intb_domain, BD96801_WDT_ERR_STAT); + wdg_irq = DEFINE_RES_IRQ_NAMED(wdg_irq_no, "bd96801-wdg"); + + ddata->cells[WDG_CELL].resources = &wdg_irq; + ddata->cells[WDG_CELL].num_resources = 1; + + if (!num_errb) + goto skip_errb; + + ret = devm_regmap_add_irq_chip(&i2c->dev, regmap, errb_irq, IRQF_ONESHOT, + 0, ddata->errb_irq_chip, &errb_irq_data); + if (ret) + return dev_err_probe(&i2c->dev, ret, + "Failed to add ERRB IRQ chip\n"); + + errb_domain = regmap_irq_get_domain(errb_irq_data); + + for (i = 0; i < num_errb; i++) { + struct resource *res = ®ulator_res[ddata->num_intb_irqs + i]; + + *res = ddata->errb_irqs[i]; + res->start = res->end = irq_create_mapping(errb_domain, res->start); + } + +skip_errb: + ddata->cells[REGULATOR_CELL].resources = regulator_res; + ddata->cells[REGULATOR_CELL].num_resources = num_regu_irqs; + ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, ddata->cells, + ddata->num_cells, NULL, 0, NULL); + if (ret) + dev_err_probe(&i2c->dev, ret, "Failed to create subdevices\n"); + + return ret; +} + +static const struct of_device_id bd96801_of_match[] = { + { .compatible = "rohm,bd96801", .data = (void *)ROHM_CHIP_TYPE_BD96801 }, + { .compatible = "rohm,bd96802", .data = (void *)ROHM_CHIP_TYPE_BD96802 }, + { .compatible = "rohm,bd96805", .data = (void *)ROHM_CHIP_TYPE_BD96805 }, + { .compatible = "rohm,bd96806", .data = (void *)ROHM_CHIP_TYPE_BD96806 }, + { } +}; +MODULE_DEVICE_TABLE(of, bd96801_of_match); + +static struct i2c_driver bd96801_i2c_driver = { + .driver = { + .name = "rohm-bd96801", + .of_match_table = bd96801_of_match, + }, + .probe = bd96801_i2c_probe, +}; + +static int __init bd96801_i2c_init(void) +{ + return i2c_add_driver(&bd96801_i2c_driver); +} + +/* Initialise early so consumer devices can complete system boot */ +subsys_initcall(bd96801_i2c_init); + +static void __exit bd96801_i2c_exit(void) +{ + i2c_del_driver(&bd96801_i2c_driver); +} +module_exit(bd96801_i2c_exit); + +MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); +MODULE_DESCRIPTION("ROHM BD9680X Power Management IC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rsmu_core.c b/drivers/mfd/rsmu_core.c index 29437fd0bd5b..fd04a6e5dfa3 100644 --- a/drivers/mfd/rsmu_core.c +++ b/drivers/mfd/rsmu_core.c @@ -78,11 +78,13 @@ int rsmu_core_init(struct rsmu_ddata *rsmu) return ret; } +EXPORT_SYMBOL_GPL(rsmu_core_init); void rsmu_core_exit(struct rsmu_ddata *rsmu) { mutex_destroy(&rsmu->lock); } +EXPORT_SYMBOL_GPL(rsmu_core_exit); MODULE_DESCRIPTION("Renesas SMU core driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c index 06d78a1cf1cc..cba64f107a2f 100644 --- a/drivers/mfd/rsmu_i2c.c +++ b/drivers/mfd/rsmu_i2c.c @@ -32,6 +32,8 @@ #define RSMU_SABRE_PAGE_ADDR 0x7F #define RSMU_SABRE_PAGE_WINDOW 128 +typedef int (*rsmu_rw_device)(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes); + static const struct regmap_range_cfg rsmu_sabre_range_cfg[] = { { .range_min = 0, @@ -54,7 +56,28 @@ static bool rsmu_sabre_volatile_reg(struct device *dev, unsigned int reg) } } -static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +static int rsmu_smbus_i2c_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes) +{ + struct i2c_client *client = to_i2c_client(rsmu->dev); + + return i2c_smbus_write_i2c_block_data(client, reg, bytes, buf); +} + +static int rsmu_smbus_i2c_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes) +{ + struct i2c_client *client = to_i2c_client(rsmu->dev); + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, reg, bytes, buf); + if (ret == bytes) + return 0; + else if (ret < 0) + return ret; + else + return -EIO; +} + +static int rsmu_i2c_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes) { struct i2c_client *client = to_i2c_client(rsmu->dev); struct i2c_msg msg[2]; @@ -84,10 +107,11 @@ static int rsmu_read_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) return 0; } -static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes) +static int rsmu_i2c_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u8 bytes) { struct i2c_client *client = to_i2c_client(rsmu->dev); - u8 msg[RSMU_MAX_WRITE_COUNT + 1]; /* 1 Byte added for the device register */ + /* we add 1 byte for device register */ + u8 msg[RSMU_MAX_WRITE_COUNT + 1]; int cnt; if (bytes > RSMU_MAX_WRITE_COUNT) @@ -107,7 +131,8 @@ static int rsmu_write_device(struct rsmu_ddata *rsmu, u8 reg, u8 *buf, u16 bytes return 0; } -static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) +static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg, + rsmu_rw_device rsmu_write_device) { u32 page = reg & RSMU_CM_PAGE_MASK; u8 buf[4]; @@ -136,35 +161,35 @@ static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) return err; } -static int rsmu_reg_read(void *context, unsigned int reg, unsigned int *val) +static int rsmu_i2c_reg_read(void *context, unsigned int reg, unsigned int *val) { struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); int err; - err = rsmu_write_page_register(rsmu, reg); + err = rsmu_write_page_register(rsmu, reg, rsmu_i2c_write_device); if (err) return err; - err = rsmu_read_device(rsmu, addr, (u8 *)val, 1); + err = rsmu_i2c_read_device(rsmu, addr, (u8 *)val, 1); if (err) dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr); return err; } -static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) +static int rsmu_i2c_reg_write(void *context, unsigned int reg, unsigned int val) { struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); u8 data = (u8)val; int err; - err = rsmu_write_page_register(rsmu, reg); + err = rsmu_write_page_register(rsmu, reg, rsmu_i2c_write_device); if (err) return err; - err = rsmu_write_device(rsmu, addr, &data, 1); + err = rsmu_i2c_write_device(rsmu, addr, &data, 1); if (err) dev_err(rsmu->dev, "Failed to write offset address 0x%x\n", addr); @@ -172,12 +197,57 @@ static int rsmu_reg_write(void *context, unsigned int reg, unsigned int val) return err; } -static const struct regmap_config rsmu_cm_regmap_config = { +static int rsmu_smbus_i2c_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + int err; + + err = rsmu_write_page_register(rsmu, reg, rsmu_smbus_i2c_write_device); + if (err) + return err; + + err = rsmu_smbus_i2c_read_device(rsmu, addr, (u8 *)val, 1); + if (err) + dev_err(rsmu->dev, "Failed to read offset address 0x%x\n", addr); + + return err; +} + +static int rsmu_smbus_i2c_reg_write(void *context, unsigned int reg, unsigned int val) +{ + struct rsmu_ddata *rsmu = i2c_get_clientdata((struct i2c_client *)context); + u8 addr = (u8)(reg & RSMU_CM_ADDRESS_MASK); + u8 data = (u8)val; + int err; + + err = rsmu_write_page_register(rsmu, reg, rsmu_smbus_i2c_write_device); + if (err) + return err; + + err = rsmu_smbus_i2c_write_device(rsmu, addr, &data, 1); + if (err) + dev_err(rsmu->dev, + "Failed to write offset address 0x%x\n", addr); + + return err; +} + +static const struct regmap_config rsmu_i2c_cm_regmap_config = { .reg_bits = 32, .val_bits = 8, .max_register = 0x20120000, - .reg_read = rsmu_reg_read, - .reg_write = rsmu_reg_write, + .reg_read = rsmu_i2c_reg_read, + .reg_write = rsmu_i2c_reg_write, + .cache_type = REGCACHE_NONE, +}; + +static const struct regmap_config rsmu_smbus_i2c_cm_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .max_register = 0x20120000, + .reg_read = rsmu_smbus_i2c_reg_read, + .reg_write = rsmu_smbus_i2c_reg_write, .cache_type = REGCACHE_NONE, }; @@ -188,7 +258,7 @@ static const struct regmap_config rsmu_sabre_regmap_config = { .ranges = rsmu_sabre_range_cfg, .num_ranges = ARRAY_SIZE(rsmu_sabre_range_cfg), .volatile_reg = rsmu_sabre_volatile_reg, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .can_multi_write = true, }; @@ -219,7 +289,15 @@ static int rsmu_i2c_probe(struct i2c_client *client) switch (rsmu->type) { case RSMU_CM: - cfg = &rsmu_cm_regmap_config; + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + cfg = &rsmu_i2c_cm_regmap_config; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)) { + cfg = &rsmu_smbus_i2c_cm_regmap_config; + } else { + dev_err(rsmu->dev, "Unsupported i2c adapter\n"); + return -ENOTSUPP; + } break; case RSMU_SABRE: cfg = &rsmu_sabre_regmap_config; @@ -236,6 +314,7 @@ static int rsmu_i2c_probe(struct i2c_client *client) rsmu->regmap = devm_regmap_init(&client->dev, NULL, client, cfg); else rsmu->regmap = devm_regmap_init_i2c(client, cfg); + if (IS_ERR(rsmu->regmap)) { ret = PTR_ERR(rsmu->regmap); dev_err(rsmu->dev, "Failed to allocate register map: %d\n", ret); diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c index ca0a1202c3ce..39d9be1e141f 100644 --- a/drivers/mfd/rsmu_spi.c +++ b/drivers/mfd/rsmu_spi.c @@ -106,10 +106,10 @@ static int rsmu_write_page_register(struct rsmu_ddata *rsmu, u32 reg) return 0; page_reg = RSMU_CM_PAGE_ADDR; page = reg & RSMU_PAGE_MASK; - buf[0] = (u8)(page & 0xff); - buf[1] = (u8)((page >> 8) & 0xff); - buf[2] = (u8)((page >> 16) & 0xff); - buf[3] = (u8)((page >> 24) & 0xff); + buf[0] = (u8)(page & 0xFF); + buf[1] = (u8)((page >> 8) & 0xFF); + buf[2] = (u8)((page >> 16) & 0xFF); + buf[3] = (u8)((page >> 24) & 0xFF); bytes = 4; break; case RSMU_SABRE: diff --git a/drivers/mfd/rt4831.c b/drivers/mfd/rt4831.c index f8d6dc55b558..1ab8870e4ebf 100644 --- a/drivers/mfd/rt4831.c +++ b/drivers/mfd/rt4831.c @@ -115,4 +115,5 @@ static struct i2c_driver rt4831_driver = { module_i2c_driver(rt4831_driver); MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RT4831 core driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c index 7e23ab3d5842..2204bf1c5a51 100644 --- a/drivers/mfd/rt5033.c +++ b/drivers/mfd/rt5033.c @@ -81,8 +81,8 @@ static int rt5033_i2c_probe(struct i2c_client *i2c) chip_rev = dev_id & RT5033_CHIP_REV_MASK; dev_info(&i2c->dev, "Device found (rev. %d)\n", chip_rev); - ret = regmap_add_irq_chip(rt5033->regmap, rt5033->irq, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ret = devm_regmap_add_irq_chip(rt5033->dev, rt5033->regmap, + rt5033->irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, &rt5033_irq_chip, &rt5033->irq_data); if (ret) { dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", @@ -98,7 +98,11 @@ static int rt5033_i2c_probe(struct i2c_client *i2c) return ret; } - device_init_wakeup(rt5033->dev, rt5033->wakeup); + if (rt5033->wakeup) { + ret = devm_device_init_wakeup(rt5033->dev); + if (ret) + return dev_err_probe(rt5033->dev, ret, "Failed to init wakeup\n"); + } return 0; } diff --git a/drivers/mfd/sec-acpm.c b/drivers/mfd/sec-acpm.c new file mode 100644 index 000000000000..8b31c816d65b --- /dev/null +++ b/drivers/mfd/sec-acpm.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright 2020 Google Inc + * Copyright 2025 Linaro Ltd. + * + * Samsung S2MPG1x ACPM driver + */ + +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/firmware/samsung/exynos-acpm-protocol.h> +#include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/rtc.h> +#include <linux/mfd/samsung/s2mpg10.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include "sec-core.h" + +#define ACPM_ADDR_BITS 8 +#define ACPM_MAX_BULK_DATA 8 + +struct sec_pmic_acpm_platform_data { + int device_type; + + unsigned int acpm_chan_id; + u8 speedy_channel; + + const struct regmap_config *regmap_cfg_common; + const struct regmap_config *regmap_cfg_pmic; + const struct regmap_config *regmap_cfg_rtc; + const struct regmap_config *regmap_cfg_meter; +}; + +static const struct regmap_range s2mpg10_common_registers[] = { + regmap_reg_range(0x00, 0x02), /* CHIP_ID_M, INT, INT_MASK */ + regmap_reg_range(0x0a, 0x0c), /* Speedy control */ + regmap_reg_range(0x1a, 0x2a), /* Debug */ +}; + +static const struct regmap_range s2mpg10_common_ro_registers[] = { + regmap_reg_range(0x00, 0x01), /* CHIP_ID_M, INT */ + regmap_reg_range(0x28, 0x2a), /* Debug */ +}; + +static const struct regmap_range s2mpg10_common_nonvolatile_registers[] = { + regmap_reg_range(0x00, 0x00), /* CHIP_ID_M */ + regmap_reg_range(0x02, 0x02), /* INT_MASK */ + regmap_reg_range(0x0a, 0x0c), /* Speedy control */ +}; + +static const struct regmap_range s2mpg10_common_precious_registers[] = { + regmap_reg_range(0x01, 0x01), /* INT */ +}; + +static const struct regmap_access_table s2mpg10_common_wr_table = { + .yes_ranges = s2mpg10_common_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_common_registers), + .no_ranges = s2mpg10_common_ro_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg10_common_ro_registers), +}; + +static const struct regmap_access_table s2mpg10_common_rd_table = { + .yes_ranges = s2mpg10_common_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_common_registers), +}; + +static const struct regmap_access_table s2mpg10_common_volatile_table = { + .no_ranges = s2mpg10_common_nonvolatile_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg10_common_nonvolatile_registers), +}; + +static const struct regmap_access_table s2mpg10_common_precious_table = { + .yes_ranges = s2mpg10_common_precious_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_common_precious_registers), +}; + +static const struct regmap_config s2mpg10_regmap_config_common = { + .name = "common", + .reg_bits = ACPM_ADDR_BITS, + .val_bits = 8, + .max_register = S2MPG10_COMMON_SPD_DEBUG4, + .wr_table = &s2mpg10_common_wr_table, + .rd_table = &s2mpg10_common_rd_table, + .volatile_table = &s2mpg10_common_volatile_table, + .precious_table = &s2mpg10_common_precious_table, + .num_reg_defaults_raw = S2MPG10_COMMON_SPD_DEBUG4 + 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range s2mpg10_pmic_registers[] = { + regmap_reg_range(0x00, 0xf6), /* All PMIC registers */ +}; + +static const struct regmap_range s2mpg10_pmic_ro_registers[] = { + regmap_reg_range(0x00, 0x05), /* INTx */ + regmap_reg_range(0x0c, 0x0f), /* STATUSx PWRONSRC OFFSRC */ + regmap_reg_range(0xc7, 0xc7), /* GPIO input */ +}; + +static const struct regmap_range s2mpg10_pmic_nonvolatile_registers[] = { + regmap_reg_range(0x06, 0x0b), /* INTxM */ +}; + +static const struct regmap_range s2mpg10_pmic_precious_registers[] = { + regmap_reg_range(0x00, 0x05), /* INTx */ +}; + +static const struct regmap_access_table s2mpg10_pmic_wr_table = { + .yes_ranges = s2mpg10_pmic_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_pmic_registers), + .no_ranges = s2mpg10_pmic_ro_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg10_pmic_ro_registers), +}; + +static const struct regmap_access_table s2mpg10_pmic_rd_table = { + .yes_ranges = s2mpg10_pmic_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_pmic_registers), +}; + +static const struct regmap_access_table s2mpg10_pmic_volatile_table = { + .no_ranges = s2mpg10_pmic_nonvolatile_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg10_pmic_nonvolatile_registers), +}; + +static const struct regmap_access_table s2mpg10_pmic_precious_table = { + .yes_ranges = s2mpg10_pmic_precious_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_pmic_precious_registers), +}; + +static const struct regmap_config s2mpg10_regmap_config_pmic = { + .name = "pmic", + .reg_bits = ACPM_ADDR_BITS, + .val_bits = 8, + .max_register = S2MPG10_PMIC_LDO_SENSE4, + .wr_table = &s2mpg10_pmic_wr_table, + .rd_table = &s2mpg10_pmic_rd_table, + .volatile_table = &s2mpg10_pmic_volatile_table, + .precious_table = &s2mpg10_pmic_precious_table, + .num_reg_defaults_raw = S2MPG10_PMIC_LDO_SENSE4 + 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range s2mpg10_rtc_registers[] = { + regmap_reg_range(0x00, 0x2b), /* All RTC registers */ +}; + +static const struct regmap_range s2mpg10_rtc_volatile_registers[] = { + regmap_reg_range(0x01, 0x01), /* RTC_UPDATE */ + regmap_reg_range(0x05, 0x0c), /* Time / date */ +}; + +static const struct regmap_access_table s2mpg10_rtc_rd_table = { + .yes_ranges = s2mpg10_rtc_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_rtc_registers), +}; + +static const struct regmap_access_table s2mpg10_rtc_volatile_table = { + .yes_ranges = s2mpg10_rtc_volatile_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_rtc_volatile_registers), +}; + +static const struct regmap_config s2mpg10_regmap_config_rtc = { + .name = "rtc", + .reg_bits = ACPM_ADDR_BITS, + .val_bits = 8, + .max_register = S2MPG10_RTC_OSC_CTRL, + .rd_table = &s2mpg10_rtc_rd_table, + .volatile_table = &s2mpg10_rtc_volatile_table, + .num_reg_defaults_raw = S2MPG10_RTC_OSC_CTRL + 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_range s2mpg10_meter_registers[] = { + regmap_reg_range(0x00, 0x21), /* Meter config */ + regmap_reg_range(0x40, 0x8a), /* Meter data */ + regmap_reg_range(0xee, 0xee), /* Offset */ + regmap_reg_range(0xf1, 0xf1), /* Trim */ +}; + +static const struct regmap_range s2mpg10_meter_ro_registers[] = { + regmap_reg_range(0x40, 0x8a), /* Meter data */ +}; + +static const struct regmap_access_table s2mpg10_meter_wr_table = { + .yes_ranges = s2mpg10_meter_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_meter_registers), + .no_ranges = s2mpg10_meter_ro_registers, + .n_no_ranges = ARRAY_SIZE(s2mpg10_meter_ro_registers), +}; + +static const struct regmap_access_table s2mpg10_meter_rd_table = { + .yes_ranges = s2mpg10_meter_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_meter_registers), +}; + +static const struct regmap_access_table s2mpg10_meter_volatile_table = { + .yes_ranges = s2mpg10_meter_ro_registers, + .n_yes_ranges = ARRAY_SIZE(s2mpg10_meter_ro_registers), +}; + +static const struct regmap_config s2mpg10_regmap_config_meter = { + .name = "meter", + .reg_bits = ACPM_ADDR_BITS, + .val_bits = 8, + .max_register = S2MPG10_METER_BUCK_METER_TRIM3, + .wr_table = &s2mpg10_meter_wr_table, + .rd_table = &s2mpg10_meter_rd_table, + .volatile_table = &s2mpg10_meter_volatile_table, + .num_reg_defaults_raw = S2MPG10_METER_BUCK_METER_TRIM3 + 1, + .cache_type = REGCACHE_FLAT, +}; + +struct sec_pmic_acpm_shared_bus_context { + const struct acpm_handle *acpm; + unsigned int acpm_chan_id; + u8 speedy_channel; +}; + +enum sec_pmic_acpm_accesstype { + SEC_PMIC_ACPM_ACCESSTYPE_COMMON = 0x00, + SEC_PMIC_ACPM_ACCESSTYPE_PMIC = 0x01, + SEC_PMIC_ACPM_ACCESSTYPE_RTC = 0x02, + SEC_PMIC_ACPM_ACCESSTYPE_METER = 0x0a, + SEC_PMIC_ACPM_ACCESSTYPE_WLWP = 0x0b, + SEC_PMIC_ACPM_ACCESSTYPE_TRIM = 0x0f, +}; + +struct sec_pmic_acpm_bus_context { + struct sec_pmic_acpm_shared_bus_context *shared; + enum sec_pmic_acpm_accesstype type; +}; + +static int sec_pmic_acpm_bus_write(void *context, const void *data, + size_t count) +{ + struct sec_pmic_acpm_bus_context *ctx = context; + const struct acpm_handle *acpm = ctx->shared->acpm; + const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops; + size_t val_count = count - BITS_TO_BYTES(ACPM_ADDR_BITS); + const u8 *d = data; + const u8 *vals = &d[BITS_TO_BYTES(ACPM_ADDR_BITS)]; + u8 reg; + + if (val_count < 1 || val_count > ACPM_MAX_BULK_DATA) + return -EINVAL; + + reg = d[0]; + + return pmic_ops->bulk_write(acpm, ctx->shared->acpm_chan_id, ctx->type, reg, + ctx->shared->speedy_channel, val_count, vals); +} + +static int sec_pmic_acpm_bus_read(void *context, const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_size) +{ + struct sec_pmic_acpm_bus_context *ctx = context; + const struct acpm_handle *acpm = ctx->shared->acpm; + const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops; + const u8 *r = reg_buf; + u8 reg; + + if (reg_size != BITS_TO_BYTES(ACPM_ADDR_BITS) || !val_size || + val_size > ACPM_MAX_BULK_DATA) + return -EINVAL; + + reg = r[0]; + + return pmic_ops->bulk_read(acpm, ctx->shared->acpm_chan_id, ctx->type, reg, + ctx->shared->speedy_channel, val_size, val_buf); +} + +static int sec_pmic_acpm_bus_reg_update_bits(void *context, unsigned int reg, unsigned int mask, + unsigned int val) +{ + struct sec_pmic_acpm_bus_context *ctx = context; + const struct acpm_handle *acpm = ctx->shared->acpm; + const struct acpm_pmic_ops *pmic_ops = &acpm->ops.pmic_ops; + + return pmic_ops->update_reg(acpm, ctx->shared->acpm_chan_id, ctx->type, reg & 0xff, + ctx->shared->speedy_channel, val, mask); +} + +static const struct regmap_bus sec_pmic_acpm_regmap_bus = { + .write = sec_pmic_acpm_bus_write, + .read = sec_pmic_acpm_bus_read, + .reg_update_bits = sec_pmic_acpm_bus_reg_update_bits, + .max_raw_read = ACPM_MAX_BULK_DATA, + .max_raw_write = ACPM_MAX_BULK_DATA, +}; + +static struct regmap *sec_pmic_acpm_regmap_init(struct device *dev, + struct sec_pmic_acpm_shared_bus_context *shared_ctx, + enum sec_pmic_acpm_accesstype type, + const struct regmap_config *cfg, bool do_attach) +{ + struct sec_pmic_acpm_bus_context *ctx; + struct regmap *regmap; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return ERR_PTR(-ENOMEM); + + ctx->shared = shared_ctx; + ctx->type = type; + + regmap = devm_regmap_init(dev, &sec_pmic_acpm_regmap_bus, ctx, cfg); + if (IS_ERR(regmap)) + return dev_err_cast_probe(dev, regmap, "regmap init (%s) failed\n", cfg->name); + + if (do_attach) { + int ret; + + ret = regmap_attach_dev(dev, regmap, cfg); + if (ret) + return dev_err_ptr_probe(dev, ret, "regmap attach (%s) failed\n", + cfg->name); + } + + return regmap; +} + +static void sec_pmic_acpm_mask_common_irqs(void *regmap_common) +{ + regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC); +} + +static int sec_pmic_acpm_probe(struct platform_device *pdev) +{ + struct regmap *regmap_common, *regmap_pmic, *regmap; + const struct sec_pmic_acpm_platform_data *pdata; + struct sec_pmic_acpm_shared_bus_context *shared_ctx; + const struct acpm_handle *acpm; + struct device *dev = &pdev->dev; + int ret, irq; + + pdata = device_get_match_data(dev); + if (!pdata) + return dev_err_probe(dev, -ENODEV, "unsupported device type\n"); + + acpm = devm_acpm_get_by_node(dev, dev->parent->of_node); + if (IS_ERR(acpm)) + return dev_err_probe(dev, PTR_ERR(acpm), "failed to get acpm\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + shared_ctx = devm_kzalloc(dev, sizeof(*shared_ctx), GFP_KERNEL); + if (!shared_ctx) + return -ENOMEM; + + shared_ctx->acpm = acpm; + shared_ctx->acpm_chan_id = pdata->acpm_chan_id; + shared_ctx->speedy_channel = pdata->speedy_channel; + + regmap_common = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_COMMON, + pdata->regmap_cfg_common, false); + if (IS_ERR(regmap_common)) + return PTR_ERR(regmap_common); + + /* Mask all interrupts from 'common' block, until successful init */ + ret = regmap_write(regmap_common, S2MPG10_COMMON_INT_MASK, S2MPG10_COMMON_INT_SRC); + if (ret) + return dev_err_probe(dev, ret, "failed to mask common block interrupts\n"); + + regmap_pmic = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_PMIC, + pdata->regmap_cfg_pmic, false); + if (IS_ERR(regmap_pmic)) + return PTR_ERR(regmap_pmic); + + regmap = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_RTC, + pdata->regmap_cfg_rtc, true); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + regmap = sec_pmic_acpm_regmap_init(dev, shared_ctx, SEC_PMIC_ACPM_ACCESSTYPE_METER, + pdata->regmap_cfg_meter, true); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = sec_pmic_probe(dev, pdata->device_type, irq, regmap_pmic, NULL); + if (ret) + return ret; + + if (device_property_read_bool(dev, "wakeup-source")) + devm_device_init_wakeup(dev); + + /* Unmask PMIC interrupt from 'common' block, now that everything is in place. */ + ret = regmap_clear_bits(regmap_common, S2MPG10_COMMON_INT_MASK, + S2MPG10_COMMON_INT_SRC_PMIC); + if (ret) + return dev_err_probe(dev, ret, "failed to unmask PMIC interrupt\n"); + + /* Mask all interrupts from 'common' block on shutdown */ + ret = devm_add_action_or_reset(dev, sec_pmic_acpm_mask_common_irqs, regmap_common); + if (ret) + return ret; + + return 0; +} + +static void sec_pmic_acpm_shutdown(struct platform_device *pdev) +{ + sec_pmic_shutdown(&pdev->dev); +} + +static const struct sec_pmic_acpm_platform_data s2mpg10_data = { + .device_type = S2MPG10, + .acpm_chan_id = 2, + .speedy_channel = 0, + .regmap_cfg_common = &s2mpg10_regmap_config_common, + .regmap_cfg_pmic = &s2mpg10_regmap_config_pmic, + .regmap_cfg_rtc = &s2mpg10_regmap_config_rtc, + .regmap_cfg_meter = &s2mpg10_regmap_config_meter, +}; + +static const struct of_device_id sec_pmic_acpm_of_match[] = { + { .compatible = "samsung,s2mpg10-pmic", .data = &s2mpg10_data, }, + { }, +}; +MODULE_DEVICE_TABLE(of, sec_pmic_acpm_of_match); + +static struct platform_driver sec_pmic_acpm_driver = { + .driver = { + .name = "sec-pmic-acpm", + .pm = pm_sleep_ptr(&sec_pmic_pm_ops), + .of_match_table = sec_pmic_acpm_of_match, + }, + .probe = sec_pmic_acpm_probe, + .shutdown = sec_pmic_acpm_shutdown, +}; +module_platform_driver(sec_pmic_acpm_driver); + +MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>"); +MODULE_DESCRIPTION("ACPM driver for the Samsung S2MPG1x"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/sec-common.c b/drivers/mfd/sec-common.c new file mode 100644 index 000000000000..42d55e70e34c --- /dev/null +++ b/drivers/mfd/sec-common.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * http://www.samsung.com + * Copyright 2025 Linaro Ltd. + * + * Samsung SxM core driver + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/export.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/irq.h> +#include <linux/mfd/samsung/s2mps11.h> +#include <linux/mfd/samsung/s2mps13.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include "sec-core.h" + +static const struct mfd_cell s5m8767_devs[] = { + MFD_CELL_NAME("s5m8767-pmic"), + MFD_CELL_NAME("s5m-rtc"), + MFD_CELL_OF("s5m8767-clk", NULL, NULL, 0, 0, "samsung,s5m8767-clk"), +}; + +static const struct mfd_cell s2dos05_devs[] = { + MFD_CELL_NAME("s2dos05-regulator"), +}; + +static const struct mfd_cell s2mpg10_devs[] = { + MFD_CELL_NAME("s2mpg10-meter"), + MFD_CELL_NAME("s2mpg10-regulator"), + MFD_CELL_NAME("s2mpg10-rtc"), + MFD_CELL_OF("s2mpg10-clk", NULL, NULL, 0, 0, "samsung,s2mpg10-clk"), + MFD_CELL_OF("s2mpg10-gpio", NULL, NULL, 0, 0, "samsung,s2mpg10-gpio"), +}; + +static const struct mfd_cell s2mps11_devs[] = { + MFD_CELL_NAME("s2mps11-regulator"), + MFD_CELL_NAME("s2mps14-rtc"), + MFD_CELL_OF("s2mps11-clk", NULL, NULL, 0, 0, "samsung,s2mps11-clk"), +}; + +static const struct mfd_cell s2mps13_devs[] = { + MFD_CELL_NAME("s2mps13-regulator"), + MFD_CELL_NAME("s2mps13-rtc"), + MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"), +}; + +static const struct mfd_cell s2mps14_devs[] = { + MFD_CELL_NAME("s2mps14-regulator"), + MFD_CELL_NAME("s2mps14-rtc"), + MFD_CELL_OF("s2mps14-clk", NULL, NULL, 0, 0, "samsung,s2mps14-clk"), +}; + +static const struct mfd_cell s2mps15_devs[] = { + MFD_CELL_NAME("s2mps15-regulator"), + MFD_CELL_NAME("s2mps15-rtc"), + MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"), +}; + +static const struct mfd_cell s2mpa01_devs[] = { + MFD_CELL_NAME("s2mpa01-pmic"), + MFD_CELL_NAME("s2mps14-rtc"), +}; + +static const struct mfd_cell s2mpu02_devs[] = { + MFD_CELL_NAME("s2mpu02-regulator"), +}; + +static const struct mfd_cell s2mpu05_devs[] = { + MFD_CELL_NAME("s2mpu05-regulator"), + MFD_CELL_NAME("s2mps15-rtc"), +}; + +static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) +{ + unsigned int val; + + /* For s2mpg1x, the revision is in a different regmap */ + if (sec_pmic->device_type == S2MPG10) + return; + + /* For each device type, the REG_ID is always the first register */ + if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val)) + dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val); +} + +static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic) +{ + int err; + + if (sec_pmic->device_type != S2MPS13X) + return; + + if (sec_pmic->pdata->disable_wrstbi) { + /* + * If WRSTBI pin is pulled down this feature must be disabled + * because each Suspend to RAM will trigger buck voltage reset + * to default values. + */ + err = regmap_update_bits(sec_pmic->regmap_pmic, + S2MPS13_REG_WRSTBI, + S2MPS13_REG_WRSTBI_MASK, 0x0); + if (err) + dev_warn(sec_pmic->dev, + "Cannot initialize WRSTBI config: %d\n", + err); + } +} + +/* + * Only the common platform data elements for s5m8767 are parsed here from the + * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and + * others have to parse their own platform data elements from device tree. + * + * The s5m8767 platform data structure is instantiated here and the drivers for + * the sub-modules need not instantiate another instance while parsing their + * platform data. + */ +static struct sec_platform_data * +sec_pmic_parse_dt_pdata(struct device *dev) +{ + struct sec_platform_data *pd; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return ERR_PTR(-ENOMEM); + + pd->manual_poweroff = of_property_read_bool(dev->of_node, + "samsung,s2mps11-acokb-ground"); + pd->disable_wrstbi = of_property_read_bool(dev->of_node, + "samsung,s2mps11-wrstbi-ground"); + return pd; +} + +int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, + struct regmap *regmap, struct i2c_client *client) +{ + struct sec_platform_data *pdata; + const struct mfd_cell *sec_devs; + struct sec_pmic_dev *sec_pmic; + int ret, num_sec_devs; + + sec_pmic = devm_kzalloc(dev, sizeof(*sec_pmic), GFP_KERNEL); + if (!sec_pmic) + return -ENOMEM; + + dev_set_drvdata(dev, sec_pmic); + sec_pmic->dev = dev; + sec_pmic->device_type = device_type; + sec_pmic->i2c = client; + sec_pmic->irq = irq; + sec_pmic->regmap_pmic = regmap; + + pdata = sec_pmic_parse_dt_pdata(sec_pmic->dev); + if (IS_ERR(pdata)) { + ret = PTR_ERR(pdata); + return ret; + } + + sec_pmic->pdata = pdata; + + ret = sec_irq_init(sec_pmic); + if (ret) + return ret; + + pm_runtime_set_active(sec_pmic->dev); + + switch (sec_pmic->device_type) { + case S5M8767X: + sec_devs = s5m8767_devs; + num_sec_devs = ARRAY_SIZE(s5m8767_devs); + break; + case S2DOS05: + sec_devs = s2dos05_devs; + num_sec_devs = ARRAY_SIZE(s2dos05_devs); + break; + case S2MPA01: + sec_devs = s2mpa01_devs; + num_sec_devs = ARRAY_SIZE(s2mpa01_devs); + break; + case S2MPG10: + sec_devs = s2mpg10_devs; + num_sec_devs = ARRAY_SIZE(s2mpg10_devs); + break; + case S2MPS11X: + sec_devs = s2mps11_devs; + num_sec_devs = ARRAY_SIZE(s2mps11_devs); + break; + case S2MPS13X: + sec_devs = s2mps13_devs; + num_sec_devs = ARRAY_SIZE(s2mps13_devs); + break; + case S2MPS14X: + sec_devs = s2mps14_devs; + num_sec_devs = ARRAY_SIZE(s2mps14_devs); + break; + case S2MPS15X: + sec_devs = s2mps15_devs; + num_sec_devs = ARRAY_SIZE(s2mps15_devs); + break; + case S2MPU02: + sec_devs = s2mpu02_devs; + num_sec_devs = ARRAY_SIZE(s2mpu02_devs); + break; + case S2MPU05: + sec_devs = s2mpu05_devs; + num_sec_devs = ARRAY_SIZE(s2mpu05_devs); + break; + default: + return dev_err_probe(sec_pmic->dev, -EINVAL, + "Unsupported device type %d\n", + sec_pmic->device_type); + } + ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, + NULL, 0, NULL); + if (ret) + return ret; + + sec_pmic_configure(sec_pmic); + sec_pmic_dump_rev(sec_pmic); + + return ret; +} +EXPORT_SYMBOL_GPL(sec_pmic_probe); + +void sec_pmic_shutdown(struct device *dev) +{ + struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev); + unsigned int reg, mask; + + if (!sec_pmic->pdata->manual_poweroff) + return; + + switch (sec_pmic->device_type) { + case S2MPS11X: + reg = S2MPS11_REG_CTRL1; + mask = S2MPS11_CTRL1_PWRHOLD_MASK; + break; + default: + /* + * Currently only one board with S2MPS11 needs this, so just + * ignore the rest. + */ + dev_warn(sec_pmic->dev, + "Unsupported device %d for manual power off\n", + sec_pmic->device_type); + return; + } + + regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0); +} +EXPORT_SYMBOL_GPL(sec_pmic_shutdown); + +static int sec_pmic_suspend(struct device *dev) +{ + struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(sec_pmic->irq); + /* + * PMIC IRQ must be disabled during suspend for RTC alarm + * to work properly. + * When device is woken up from suspend, an + * interrupt occurs before resuming I2C bus controller. + * The interrupt is handled by regmap_irq_thread which tries + * to read RTC registers. This read fails (I2C is still + * suspended) and RTC Alarm interrupt is disabled. + */ + disable_irq(sec_pmic->irq); + + return 0; +} + +static int sec_pmic_resume(struct device *dev) +{ + struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(sec_pmic->irq); + enable_irq(sec_pmic->irq); + + return 0; +} + +DEFINE_SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); +EXPORT_SYMBOL_GPL(sec_pmic_pm_ops); + +MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); +MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>"); +MODULE_DESCRIPTION("Core driver for the Samsung S5M"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c deleted file mode 100644 index a6b0d7300b2d..000000000000 --- a/drivers/mfd/sec-core.c +++ /dev/null @@ -1,458 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -// -// Copyright (c) 2012 Samsung Electronics Co., Ltd -// http://www.samsung.com - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/of.h> -#include <linux/interrupt.h> -#include <linux/pm_runtime.h> -#include <linux/mutex.h> -#include <linux/mfd/core.h> -#include <linux/mfd/samsung/core.h> -#include <linux/mfd/samsung/irq.h> -#include <linux/mfd/samsung/s2mpa01.h> -#include <linux/mfd/samsung/s2mps11.h> -#include <linux/mfd/samsung/s2mps13.h> -#include <linux/mfd/samsung/s2mps14.h> -#include <linux/mfd/samsung/s2mps15.h> -#include <linux/mfd/samsung/s2mpu02.h> -#include <linux/mfd/samsung/s5m8767.h> -#include <linux/regmap.h> - -static const struct mfd_cell s5m8767_devs[] = { - { .name = "s5m8767-pmic", }, - { .name = "s5m-rtc", }, - { - .name = "s5m8767-clk", - .of_compatible = "samsung,s5m8767-clk", - }, -}; - -static const struct mfd_cell s2mps11_devs[] = { - { .name = "s2mps11-regulator", }, - { .name = "s2mps14-rtc", }, - { - .name = "s2mps11-clk", - .of_compatible = "samsung,s2mps11-clk", - }, -}; - -static const struct mfd_cell s2mps13_devs[] = { - { .name = "s2mps13-regulator", }, - { .name = "s2mps13-rtc", }, - { - .name = "s2mps13-clk", - .of_compatible = "samsung,s2mps13-clk", - }, -}; - -static const struct mfd_cell s2mps14_devs[] = { - { .name = "s2mps14-regulator", }, - { .name = "s2mps14-rtc", }, - { - .name = "s2mps14-clk", - .of_compatible = "samsung,s2mps14-clk", - }, -}; - -static const struct mfd_cell s2mps15_devs[] = { - { .name = "s2mps15-regulator", }, - { .name = "s2mps15-rtc", }, - { - .name = "s2mps13-clk", - .of_compatible = "samsung,s2mps13-clk", - }, -}; - -static const struct mfd_cell s2mpa01_devs[] = { - { .name = "s2mpa01-pmic", }, - { .name = "s2mps14-rtc", }, -}; - -static const struct mfd_cell s2mpu02_devs[] = { - { .name = "s2mpu02-regulator", }, -}; - -static const struct of_device_id sec_dt_match[] = { - { - .compatible = "samsung,s5m8767-pmic", - .data = (void *)S5M8767X, - }, { - .compatible = "samsung,s2mps11-pmic", - .data = (void *)S2MPS11X, - }, { - .compatible = "samsung,s2mps13-pmic", - .data = (void *)S2MPS13X, - }, { - .compatible = "samsung,s2mps14-pmic", - .data = (void *)S2MPS14X, - }, { - .compatible = "samsung,s2mps15-pmic", - .data = (void *)S2MPS15X, - }, { - .compatible = "samsung,s2mpa01-pmic", - .data = (void *)S2MPA01, - }, { - .compatible = "samsung,s2mpu02-pmic", - .data = (void *)S2MPU02, - }, { - /* Sentinel */ - }, -}; -MODULE_DEVICE_TABLE(of, sec_dt_match); - -static bool s2mpa01_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S2MPA01_REG_INT1M: - case S2MPA01_REG_INT2M: - case S2MPA01_REG_INT3M: - return false; - default: - return true; - } -} - -static bool s2mps11_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S2MPS11_REG_INT1M: - case S2MPS11_REG_INT2M: - case S2MPS11_REG_INT3M: - return false; - default: - return true; - } -} - -static bool s2mpu02_volatile(struct device *dev, unsigned int reg) -{ - switch (reg) { - case S2MPU02_REG_INT1M: - case S2MPU02_REG_INT2M: - case S2MPU02_REG_INT3M: - return false; - default: - return true; - } -} - -static const struct regmap_config sec_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - -static const struct regmap_config s2mpa01_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPA01_REG_LDO_OVCB4, - .volatile_reg = s2mpa01_volatile, - .cache_type = REGCACHE_FLAT, -}; - -static const struct regmap_config s2mps11_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPS11_REG_L38CTRL, - .volatile_reg = s2mps11_volatile, - .cache_type = REGCACHE_FLAT, -}; - -static const struct regmap_config s2mps13_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPS13_REG_LDODSCH5, - .volatile_reg = s2mps11_volatile, - .cache_type = REGCACHE_FLAT, -}; - -static const struct regmap_config s2mps14_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPS14_REG_LDODSCH3, - .volatile_reg = s2mps11_volatile, - .cache_type = REGCACHE_FLAT, -}; - -static const struct regmap_config s2mps15_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPS15_REG_LDODSCH4, - .volatile_reg = s2mps11_volatile, - .cache_type = REGCACHE_FLAT, -}; - -static const struct regmap_config s2mpu02_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPU02_REG_DVSDATA, - .volatile_reg = s2mpu02_volatile, - .cache_type = REGCACHE_FLAT, -}; - -static const struct regmap_config s5m8767_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S5M8767_REG_LDO28CTRL, - .volatile_reg = s2mps11_volatile, - .cache_type = REGCACHE_FLAT, -}; - -static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) -{ - unsigned int val; - - /* For each device type, the REG_ID is always the first register */ - if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val)) - dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val); -} - -static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic) -{ - int err; - - if (sec_pmic->device_type != S2MPS13X) - return; - - if (sec_pmic->pdata->disable_wrstbi) { - /* - * If WRSTBI pin is pulled down this feature must be disabled - * because each Suspend to RAM will trigger buck voltage reset - * to default values. - */ - err = regmap_update_bits(sec_pmic->regmap_pmic, - S2MPS13_REG_WRSTBI, - S2MPS13_REG_WRSTBI_MASK, 0x0); - if (err) - dev_warn(sec_pmic->dev, - "Cannot initialize WRSTBI config: %d\n", - err); - } -} - -/* - * Only the common platform data elements for s5m8767 are parsed here from the - * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and - * others have to parse their own platform data elements from device tree. - * - * The s5m8767 platform data structure is instantiated here and the drivers for - * the sub-modules need not instantiate another instance while parsing their - * platform data. - */ -static struct sec_platform_data * -sec_pmic_i2c_parse_dt_pdata(struct device *dev) -{ - struct sec_platform_data *pd; - - pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); - if (!pd) - return ERR_PTR(-ENOMEM); - - pd->manual_poweroff = of_property_read_bool(dev->of_node, - "samsung,s2mps11-acokb-ground"); - pd->disable_wrstbi = of_property_read_bool(dev->of_node, - "samsung,s2mps11-wrstbi-ground"); - return pd; -} - -static int sec_pmic_probe(struct i2c_client *i2c) -{ - const struct regmap_config *regmap; - struct sec_platform_data *pdata; - const struct mfd_cell *sec_devs; - struct sec_pmic_dev *sec_pmic; - int ret, num_sec_devs; - - sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), - GFP_KERNEL); - if (sec_pmic == NULL) - return -ENOMEM; - - i2c_set_clientdata(i2c, sec_pmic); - sec_pmic->dev = &i2c->dev; - sec_pmic->i2c = i2c; - sec_pmic->irq = i2c->irq; - - pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - return ret; - } - - sec_pmic->device_type = (unsigned long)of_device_get_match_data(sec_pmic->dev); - sec_pmic->pdata = pdata; - - switch (sec_pmic->device_type) { - case S2MPA01: - regmap = &s2mpa01_regmap_config; - break; - case S2MPS11X: - regmap = &s2mps11_regmap_config; - break; - case S2MPS13X: - regmap = &s2mps13_regmap_config; - break; - case S2MPS14X: - regmap = &s2mps14_regmap_config; - break; - case S2MPS15X: - regmap = &s2mps15_regmap_config; - break; - case S5M8767X: - regmap = &s5m8767_regmap_config; - break; - case S2MPU02: - regmap = &s2mpu02_regmap_config; - break; - default: - regmap = &sec_regmap_config; - break; - } - - sec_pmic->regmap_pmic = devm_regmap_init_i2c(i2c, regmap); - if (IS_ERR(sec_pmic->regmap_pmic)) { - ret = PTR_ERR(sec_pmic->regmap_pmic); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - - sec_irq_init(sec_pmic); - - pm_runtime_set_active(sec_pmic->dev); - - switch (sec_pmic->device_type) { - case S5M8767X: - sec_devs = s5m8767_devs; - num_sec_devs = ARRAY_SIZE(s5m8767_devs); - break; - case S2MPA01: - sec_devs = s2mpa01_devs; - num_sec_devs = ARRAY_SIZE(s2mpa01_devs); - break; - case S2MPS11X: - sec_devs = s2mps11_devs; - num_sec_devs = ARRAY_SIZE(s2mps11_devs); - break; - case S2MPS13X: - sec_devs = s2mps13_devs; - num_sec_devs = ARRAY_SIZE(s2mps13_devs); - break; - case S2MPS14X: - sec_devs = s2mps14_devs; - num_sec_devs = ARRAY_SIZE(s2mps14_devs); - break; - case S2MPS15X: - sec_devs = s2mps15_devs; - num_sec_devs = ARRAY_SIZE(s2mps15_devs); - break; - case S2MPU02: - sec_devs = s2mpu02_devs; - num_sec_devs = ARRAY_SIZE(s2mpu02_devs); - break; - default: - dev_err(&i2c->dev, "Unsupported device type (%lu)\n", - sec_pmic->device_type); - return -ENODEV; - } - ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, - NULL, 0, NULL); - if (ret) - return ret; - - sec_pmic_configure(sec_pmic); - sec_pmic_dump_rev(sec_pmic); - - return ret; -} - -static void sec_pmic_shutdown(struct i2c_client *i2c) -{ - struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - unsigned int reg, mask; - - if (!sec_pmic->pdata->manual_poweroff) - return; - - switch (sec_pmic->device_type) { - case S2MPS11X: - reg = S2MPS11_REG_CTRL1; - mask = S2MPS11_CTRL1_PWRHOLD_MASK; - break; - default: - /* - * Currently only one board with S2MPS11 needs this, so just - * ignore the rest. - */ - dev_warn(sec_pmic->dev, - "Unsupported device %lu for manual power off\n", - sec_pmic->device_type); - return; - } - - regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0); -} - -static int sec_pmic_suspend(struct device *dev) -{ - struct i2c_client *i2c = to_i2c_client(dev); - struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - - if (device_may_wakeup(dev)) - enable_irq_wake(sec_pmic->irq); - /* - * PMIC IRQ must be disabled during suspend for RTC alarm - * to work properly. - * When device is woken up from suspend, an - * interrupt occurs before resuming I2C bus controller. - * The interrupt is handled by regmap_irq_thread which tries - * to read RTC registers. This read fails (I2C is still - * suspended) and RTC Alarm interrupt is disabled. - */ - disable_irq(sec_pmic->irq); - - return 0; -} - -static int sec_pmic_resume(struct device *dev) -{ - struct i2c_client *i2c = to_i2c_client(dev); - struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - - if (device_may_wakeup(dev)) - disable_irq_wake(sec_pmic->irq); - enable_irq(sec_pmic->irq); - - return 0; -} - -static DEFINE_SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, - sec_pmic_suspend, sec_pmic_resume); - -static struct i2c_driver sec_pmic_driver = { - .driver = { - .name = "sec_pmic", - .pm = pm_sleep_ptr(&sec_pmic_pm_ops), - .of_match_table = sec_dt_match, - }, - .probe = sec_pmic_probe, - .shutdown = sec_pmic_shutdown, -}; -module_i2c_driver(sec_pmic_driver); - -MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); -MODULE_DESCRIPTION("Core support for the S5M MFD"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/sec-core.h b/drivers/mfd/sec-core.h new file mode 100644 index 000000000000..92c7558ab8b0 --- /dev/null +++ b/drivers/mfd/sec-core.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * http://www.samsung.com + * Copyright 2025 Linaro Ltd. + * + * Samsung SxM core driver internal data + */ + +#ifndef __SEC_CORE_INT_H +#define __SEC_CORE_INT_H + +struct i2c_client; + +extern const struct dev_pm_ops sec_pmic_pm_ops; + +int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, + struct regmap *regmap, struct i2c_client *client); +void sec_pmic_shutdown(struct device *dev); + +int sec_irq_init(struct sec_pmic_dev *sec_pmic); + +#endif /* __SEC_CORE_INT_H */ diff --git a/drivers/mfd/sec-i2c.c b/drivers/mfd/sec-i2c.c new file mode 100644 index 000000000000..3132b849b4bc --- /dev/null +++ b/drivers/mfd/sec-i2c.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * http://www.samsung.com + * Copyright 2025 Linaro Ltd. + * + * Samsung SxM I2C driver + */ + +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/s2mpa01.h> +#include <linux/mfd/samsung/s2mps11.h> +#include <linux/mfd/samsung/s2mps13.h> +#include <linux/mfd/samsung/s2mps14.h> +#include <linux/mfd/samsung/s2mps15.h> +#include <linux/mfd/samsung/s2mpu02.h> +#include <linux/mfd/samsung/s5m8767.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/pm.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include "sec-core.h" + +struct sec_pmic_i2c_platform_data { + const struct regmap_config *regmap_cfg; + int device_type; +}; + +static bool s2mpa01_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S2MPA01_REG_INT1M: + case S2MPA01_REG_INT2M: + case S2MPA01_REG_INT3M: + return false; + default: + return true; + } +} + +static bool s2mps11_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S2MPS11_REG_INT1M: + case S2MPS11_REG_INT2M: + case S2MPS11_REG_INT3M: + return false; + default: + return true; + } +} + +static bool s2mpu02_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S2MPU02_REG_INT1M: + case S2MPU02_REG_INT2M: + case S2MPU02_REG_INT3M: + return false; + default: + return true; + } +} + +static const struct regmap_config s2dos05_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct regmap_config s2mpa01_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPA01_REG_LDO_OVCB4, + .volatile_reg = s2mpa01_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config s2mps11_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS11_REG_L38CTRL, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config s2mps13_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS13_REG_LDODSCH5, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config s2mps14_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS14_REG_LDODSCH3, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config s2mps15_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPS15_REG_LDODSCH4, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config s2mpu02_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S2MPU02_REG_DVSDATA, + .volatile_reg = s2mpu02_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config s2mpu05_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static const struct regmap_config s5m8767_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = S5M8767_REG_LDO28CTRL, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, +}; + +static int sec_pmic_i2c_probe(struct i2c_client *client) +{ + const struct sec_pmic_i2c_platform_data *pdata; + struct regmap *regmap_pmic; + + pdata = device_get_match_data(&client->dev); + if (!pdata) + return dev_err_probe(&client->dev, -ENODEV, + "Unsupported device type\n"); + + regmap_pmic = devm_regmap_init_i2c(client, pdata->regmap_cfg); + if (IS_ERR(regmap_pmic)) + return dev_err_probe(&client->dev, PTR_ERR(regmap_pmic), + "regmap init failed\n"); + + return sec_pmic_probe(&client->dev, pdata->device_type, client->irq, + regmap_pmic, client); +} + +static void sec_pmic_i2c_shutdown(struct i2c_client *i2c) +{ + sec_pmic_shutdown(&i2c->dev); +} + +static const struct sec_pmic_i2c_platform_data s2dos05_data = { + .regmap_cfg = &s2dos05_regmap_config, + .device_type = S2DOS05 +}; + +static const struct sec_pmic_i2c_platform_data s2mpa01_data = { + .regmap_cfg = &s2mpa01_regmap_config, + .device_type = S2MPA01, +}; + +static const struct sec_pmic_i2c_platform_data s2mps11_data = { + .regmap_cfg = &s2mps11_regmap_config, + .device_type = S2MPS11X, +}; + +static const struct sec_pmic_i2c_platform_data s2mps13_data = { + .regmap_cfg = &s2mps13_regmap_config, + .device_type = S2MPS13X, +}; + +static const struct sec_pmic_i2c_platform_data s2mps14_data = { + .regmap_cfg = &s2mps14_regmap_config, + .device_type = S2MPS14X, +}; + +static const struct sec_pmic_i2c_platform_data s2mps15_data = { + .regmap_cfg = &s2mps15_regmap_config, + .device_type = S2MPS15X, +}; + +static const struct sec_pmic_i2c_platform_data s2mpu02_data = { + .regmap_cfg = &s2mpu02_regmap_config, + .device_type = S2MPU02, +}; + +static const struct sec_pmic_i2c_platform_data s2mpu05_data = { + .regmap_cfg = &s2mpu05_regmap_config, + .device_type = S2MPU05, +}; + +static const struct sec_pmic_i2c_platform_data s5m8767_data = { + .regmap_cfg = &s5m8767_regmap_config, + .device_type = S5M8767X, +}; + +static const struct of_device_id sec_pmic_i2c_of_match[] = { + { .compatible = "samsung,s2dos05", .data = &s2dos05_data, }, + { .compatible = "samsung,s2mpa01-pmic", .data = &s2mpa01_data, }, + { .compatible = "samsung,s2mps11-pmic", .data = &s2mps11_data, }, + { .compatible = "samsung,s2mps13-pmic", .data = &s2mps13_data, }, + { .compatible = "samsung,s2mps14-pmic", .data = &s2mps14_data, }, + { .compatible = "samsung,s2mps15-pmic", .data = &s2mps15_data, }, + { .compatible = "samsung,s2mpu02-pmic", .data = &s2mpu02_data, }, + { .compatible = "samsung,s2mpu05-pmic", .data = &s2mpu05_data, }, + { .compatible = "samsung,s5m8767-pmic", .data = &s5m8767_data, }, + { }, +}; +MODULE_DEVICE_TABLE(of, sec_pmic_i2c_of_match); + +static struct i2c_driver sec_pmic_i2c_driver = { + .driver = { + .name = "sec-pmic-i2c", + .pm = pm_sleep_ptr(&sec_pmic_pm_ops), + .of_match_table = sec_pmic_i2c_of_match, + }, + .probe = sec_pmic_i2c_probe, + .shutdown = sec_pmic_i2c_shutdown, +}; +module_i2c_driver(sec_pmic_i2c_driver); + +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>"); +MODULE_DESCRIPTION("I2C driver for the Samsung S5M"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index e191aeb0c07c..c5c80b1ba104 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -3,297 +3,191 @@ // Copyright (c) 2011-2014 Samsung Electronics Co., Ltd // http://www.samsung.com -#include <linux/device.h> +#include <linux/array_size.h> +#include <linux/build_bug.h> +#include <linux/dev_printk.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/module.h> -#include <linux/regmap.h> - #include <linux/mfd/samsung/core.h> #include <linux/mfd/samsung/irq.h> +#include <linux/mfd/samsung/s2mpg10.h> #include <linux/mfd/samsung/s2mps11.h> #include <linux/mfd/samsung/s2mps14.h> #include <linux/mfd/samsung/s2mpu02.h> +#include <linux/mfd/samsung/s2mpu05.h> #include <linux/mfd/samsung/s5m8767.h> +#include <linux/regmap.h> +#include "sec-core.h" + +static const struct regmap_irq s2mpg10_irqs[] = { + REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONF, 0, S2MPG10_IRQ_PWRONF_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWRONR, 0, S2MPG10_IRQ_PWRONR_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_JIGONBF, 0, S2MPG10_IRQ_JIGONBF_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_JIGONBR, 0, S2MPG10_IRQ_JIGONBR_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_ACOKBF, 0, S2MPG10_IRQ_ACOKBF_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_ACOKBR, 0, S2MPG10_IRQ_ACOKBR_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWRON1S, 0, S2MPG10_IRQ_PWRON1S_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_MRB, 0, S2MPG10_IRQ_MRB_MASK), + + REGMAP_IRQ_REG(S2MPG10_IRQ_RTC60S, 1, S2MPG10_IRQ_RTC60S_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_RTCA1, 1, S2MPG10_IRQ_RTCA1_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_RTCA0, 1, S2MPG10_IRQ_RTCA0_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_RTC1S, 1, S2MPG10_IRQ_RTC1S_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_WTSR_COLDRST, 1, S2MPG10_IRQ_WTSR_COLDRST_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_WTSR, 1, S2MPG10_IRQ_WTSR_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_WRST, 1, S2MPG10_IRQ_WRST_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_SMPL, 1, S2MPG10_IRQ_SMPL_MASK), + + REGMAP_IRQ_REG(S2MPG10_IRQ_120C, 2, S2MPG10_IRQ_INT120C_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_140C, 2, S2MPG10_IRQ_INT140C_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_TSD, 2, S2MPG10_IRQ_TSD_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PIF_TIMEOUT1, 2, S2MPG10_IRQ_PIF_TIMEOUT1_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PIF_TIMEOUT2, 2, S2MPG10_IRQ_PIF_TIMEOUT2_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_SPD_PARITY_ERR, 2, S2MPG10_IRQ_SPD_PARITY_ERR_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_SPD_ABNORMAL_STOP, 2, S2MPG10_IRQ_SPD_ABNORMAL_STOP_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PMETER_OVERF, 2, S2MPG10_IRQ_PMETER_OVERF_MASK), + + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B1M, 3, S2MPG10_IRQ_OCP_B1M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B2M, 3, S2MPG10_IRQ_OCP_B2M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B3M, 3, S2MPG10_IRQ_OCP_B3M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B4M, 3, S2MPG10_IRQ_OCP_B4M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B5M, 3, S2MPG10_IRQ_OCP_B5M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B6M, 3, S2MPG10_IRQ_OCP_B6M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B7M, 3, S2MPG10_IRQ_OCP_B7M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B8M, 3, S2MPG10_IRQ_OCP_B8M_MASK), + + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B9M, 4, S2MPG10_IRQ_OCP_B9M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_OCP_B10M, 4, S2MPG10_IRQ_OCP_B10M_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_WLWP_ACC, 4, S2MPG10_IRQ_WLWP_ACC_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_SMPL_TIMEOUT, 4, S2MPG10_IRQ_SMPL_TIMEOUT_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_WTSR_TIMEOUT, 4, S2MPG10_IRQ_WTSR_TIMEOUT_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_SPD_SRP_PKT_RST, 4, S2MPG10_IRQ_SPD_SRP_PKT_RST_MASK), + + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH0, 5, S2MPG10_IRQ_PWR_WARN_CH0_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH1, 5, S2MPG10_IRQ_PWR_WARN_CH1_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH2, 5, S2MPG10_IRQ_PWR_WARN_CH2_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH3, 5, S2MPG10_IRQ_PWR_WARN_CH3_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH4, 5, S2MPG10_IRQ_PWR_WARN_CH4_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH5, 5, S2MPG10_IRQ_PWR_WARN_CH5_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH6, 5, S2MPG10_IRQ_PWR_WARN_CH6_MASK), + REGMAP_IRQ_REG(S2MPG10_IRQ_PWR_WARN_CH7, 5, S2MPG10_IRQ_PWR_WARN_CH7_MASK), +}; static const struct regmap_irq s2mps11_irqs[] = { - [S2MPS11_IRQ_PWRONF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRONF_MASK, - }, - [S2MPS11_IRQ_PWRONR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRONR_MASK, - }, - [S2MPS11_IRQ_JIGONBF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_JIGONBF_MASK, - }, - [S2MPS11_IRQ_JIGONBR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_JIGONBR_MASK, - }, - [S2MPS11_IRQ_ACOKBF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_ACOKBF_MASK, - }, - [S2MPS11_IRQ_ACOKBR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_ACOKBR_MASK, - }, - [S2MPS11_IRQ_PWRON1S] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRON1S_MASK, - }, - [S2MPS11_IRQ_MRB] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_MRB_MASK, - }, - [S2MPS11_IRQ_RTC60S] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTC60S_MASK, - }, - [S2MPS11_IRQ_RTCA1] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA1_MASK, - }, - [S2MPS11_IRQ_RTCA0] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA0_MASK, - }, - [S2MPS11_IRQ_SMPL] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_SMPL_MASK, - }, - [S2MPS11_IRQ_RTC1S] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTC1S_MASK, - }, - [S2MPS11_IRQ_WTSR] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_WTSR_MASK, - }, - [S2MPS11_IRQ_INT120C] = { - .reg_offset = 2, - .mask = S2MPS11_IRQ_INT120C_MASK, - }, - [S2MPS11_IRQ_INT140C] = { - .reg_offset = 2, - .mask = S2MPS11_IRQ_INT140C_MASK, - }, + REGMAP_IRQ_REG(S2MPS11_IRQ_PWRONF, 0, S2MPS11_IRQ_PWRONF_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_PWRONR, 0, S2MPS11_IRQ_PWRONR_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_JIGONBF, 0, S2MPS11_IRQ_JIGONBF_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_JIGONBR, 0, S2MPS11_IRQ_JIGONBR_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_ACOKBF, 0, S2MPS11_IRQ_ACOKBF_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_ACOKBR, 0, S2MPS11_IRQ_ACOKBR_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_PWRON1S, 0, S2MPS11_IRQ_PWRON1S_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_MRB, 0, S2MPS11_IRQ_MRB_MASK), + + REGMAP_IRQ_REG(S2MPS11_IRQ_RTC60S, 1, S2MPS11_IRQ_RTC60S_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_RTCA1, 1, S2MPS11_IRQ_RTCA1_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_RTCA0, 1, S2MPS11_IRQ_RTCA0_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_SMPL, 1, S2MPS11_IRQ_SMPL_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_RTC1S, 1, S2MPS11_IRQ_RTC1S_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_WTSR, 1, S2MPS11_IRQ_WTSR_MASK), + + REGMAP_IRQ_REG(S2MPS11_IRQ_INT120C, 2, S2MPS11_IRQ_INT120C_MASK), + REGMAP_IRQ_REG(S2MPS11_IRQ_INT140C, 2, S2MPS11_IRQ_INT140C_MASK), }; static const struct regmap_irq s2mps14_irqs[] = { - [S2MPS14_IRQ_PWRONF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRONF_MASK, - }, - [S2MPS14_IRQ_PWRONR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRONR_MASK, - }, - [S2MPS14_IRQ_JIGONBF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_JIGONBF_MASK, - }, - [S2MPS14_IRQ_JIGONBR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_JIGONBR_MASK, - }, - [S2MPS14_IRQ_ACOKBF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_ACOKBF_MASK, - }, - [S2MPS14_IRQ_ACOKBR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_ACOKBR_MASK, - }, - [S2MPS14_IRQ_PWRON1S] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRON1S_MASK, - }, - [S2MPS14_IRQ_MRB] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_MRB_MASK, - }, - [S2MPS14_IRQ_RTC60S] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTC60S_MASK, - }, - [S2MPS14_IRQ_RTCA1] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA1_MASK, - }, - [S2MPS14_IRQ_RTCA0] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA0_MASK, - }, - [S2MPS14_IRQ_SMPL] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_SMPL_MASK, - }, - [S2MPS14_IRQ_RTC1S] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTC1S_MASK, - }, - [S2MPS14_IRQ_WTSR] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_WTSR_MASK, - }, - [S2MPS14_IRQ_INT120C] = { - .reg_offset = 2, - .mask = S2MPS11_IRQ_INT120C_MASK, - }, - [S2MPS14_IRQ_INT140C] = { - .reg_offset = 2, - .mask = S2MPS11_IRQ_INT140C_MASK, - }, - [S2MPS14_IRQ_TSD] = { - .reg_offset = 2, - .mask = S2MPS14_IRQ_TSD_MASK, - }, + REGMAP_IRQ_REG(S2MPS14_IRQ_PWRONF, 0, S2MPS11_IRQ_PWRONF_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_PWRONR, 0, S2MPS11_IRQ_PWRONR_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_JIGONBF, 0, S2MPS11_IRQ_JIGONBF_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_JIGONBR, 0, S2MPS11_IRQ_JIGONBR_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_ACOKBF, 0, S2MPS11_IRQ_ACOKBF_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_ACOKBR, 0, S2MPS11_IRQ_ACOKBR_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_PWRON1S, 0, S2MPS11_IRQ_PWRON1S_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_MRB, 0, S2MPS11_IRQ_MRB_MASK), + + REGMAP_IRQ_REG(S2MPS14_IRQ_RTC60S, 1, S2MPS11_IRQ_RTC60S_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_RTCA1, 1, S2MPS11_IRQ_RTCA1_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_RTCA0, 1, S2MPS11_IRQ_RTCA0_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_SMPL, 1, S2MPS11_IRQ_SMPL_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_RTC1S, 1, S2MPS11_IRQ_RTC1S_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_WTSR, 1, S2MPS11_IRQ_WTSR_MASK), + + REGMAP_IRQ_REG(S2MPS14_IRQ_INT120C, 2, S2MPS11_IRQ_INT120C_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_INT140C, 2, S2MPS11_IRQ_INT140C_MASK), + REGMAP_IRQ_REG(S2MPS14_IRQ_TSD, 2, S2MPS14_IRQ_TSD_MASK), }; static const struct regmap_irq s2mpu02_irqs[] = { - [S2MPU02_IRQ_PWRONF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRONF_MASK, - }, - [S2MPU02_IRQ_PWRONR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRONR_MASK, - }, - [S2MPU02_IRQ_JIGONBF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_JIGONBF_MASK, - }, - [S2MPU02_IRQ_JIGONBR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_JIGONBR_MASK, - }, - [S2MPU02_IRQ_ACOKBF] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_ACOKBF_MASK, - }, - [S2MPU02_IRQ_ACOKBR] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_ACOKBR_MASK, - }, - [S2MPU02_IRQ_PWRON1S] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_PWRON1S_MASK, - }, - [S2MPU02_IRQ_MRB] = { - .reg_offset = 0, - .mask = S2MPS11_IRQ_MRB_MASK, - }, - [S2MPU02_IRQ_RTC60S] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTC60S_MASK, - }, - [S2MPU02_IRQ_RTCA1] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA1_MASK, - }, - [S2MPU02_IRQ_RTCA0] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTCA0_MASK, - }, - [S2MPU02_IRQ_SMPL] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_SMPL_MASK, - }, - [S2MPU02_IRQ_RTC1S] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_RTC1S_MASK, - }, - [S2MPU02_IRQ_WTSR] = { - .reg_offset = 1, - .mask = S2MPS11_IRQ_WTSR_MASK, - }, - [S2MPU02_IRQ_INT120C] = { - .reg_offset = 2, - .mask = S2MPS11_IRQ_INT120C_MASK, - }, - [S2MPU02_IRQ_INT140C] = { - .reg_offset = 2, - .mask = S2MPS11_IRQ_INT140C_MASK, - }, - [S2MPU02_IRQ_TSD] = { - .reg_offset = 2, - .mask = S2MPS14_IRQ_TSD_MASK, - }, + REGMAP_IRQ_REG(S2MPU02_IRQ_PWRONF, 0, S2MPS11_IRQ_PWRONF_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_PWRONR, 0, S2MPS11_IRQ_PWRONR_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_JIGONBF, 0, S2MPS11_IRQ_JIGONBF_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_JIGONBR, 0, S2MPS11_IRQ_JIGONBR_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_ACOKBF, 0, S2MPS11_IRQ_ACOKBF_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_ACOKBR, 0, S2MPS11_IRQ_ACOKBR_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_PWRON1S, 0, S2MPS11_IRQ_PWRON1S_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_MRB, 0, S2MPS11_IRQ_MRB_MASK), + + REGMAP_IRQ_REG(S2MPU02_IRQ_RTC60S, 1, S2MPS11_IRQ_RTC60S_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_RTCA1, 1, S2MPS11_IRQ_RTCA1_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_RTCA0, 1, S2MPS11_IRQ_RTCA0_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_SMPL, 1, S2MPS11_IRQ_SMPL_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_RTC1S, 1, S2MPS11_IRQ_RTC1S_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_WTSR, 1, S2MPS11_IRQ_WTSR_MASK), + + REGMAP_IRQ_REG(S2MPU02_IRQ_INT120C, 2, S2MPS11_IRQ_INT120C_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_INT140C, 2, S2MPS11_IRQ_INT140C_MASK), + REGMAP_IRQ_REG(S2MPU02_IRQ_TSD, 2, S2MPS14_IRQ_TSD_MASK), +}; + +static const struct regmap_irq s2mpu05_irqs[] = { + REGMAP_IRQ_REG(S2MPU05_IRQ_PWRONF, 0, S2MPU05_IRQ_PWRONF_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_PWRONR, 0, S2MPU05_IRQ_PWRONR_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_JIGONBF, 0, S2MPU05_IRQ_JIGONBF_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_JIGONBR, 0, S2MPU05_IRQ_JIGONBR_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_ACOKF, 0, S2MPU05_IRQ_ACOKF_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_ACOKR, 0, S2MPU05_IRQ_ACOKR_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_PWRON1S, 0, S2MPU05_IRQ_PWRON1S_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_MRB, 0, S2MPU05_IRQ_MRB_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_RTC60S, 1, S2MPU05_IRQ_RTC60S_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_RTCA1, 1, S2MPU05_IRQ_RTCA1_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_RTCA0, 1, S2MPU05_IRQ_RTCA0_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_SMPL, 1, S2MPU05_IRQ_SMPL_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_RTC1S, 1, S2MPU05_IRQ_RTC1S_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_WTSR, 1, S2MPU05_IRQ_WTSR_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_INT120C, 2, S2MPU05_IRQ_INT120C_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_INT140C, 2, S2MPU05_IRQ_INT140C_MASK), + REGMAP_IRQ_REG(S2MPU05_IRQ_TSD, 2, S2MPU05_IRQ_TSD_MASK), }; static const struct regmap_irq s5m8767_irqs[] = { - [S5M8767_IRQ_PWRR] = { - .reg_offset = 0, - .mask = S5M8767_IRQ_PWRR_MASK, - }, - [S5M8767_IRQ_PWRF] = { - .reg_offset = 0, - .mask = S5M8767_IRQ_PWRF_MASK, - }, - [S5M8767_IRQ_PWR1S] = { - .reg_offset = 0, - .mask = S5M8767_IRQ_PWR1S_MASK, - }, - [S5M8767_IRQ_JIGR] = { - .reg_offset = 0, - .mask = S5M8767_IRQ_JIGR_MASK, - }, - [S5M8767_IRQ_JIGF] = { - .reg_offset = 0, - .mask = S5M8767_IRQ_JIGF_MASK, - }, - [S5M8767_IRQ_LOWBAT2] = { - .reg_offset = 0, - .mask = S5M8767_IRQ_LOWBAT2_MASK, - }, - [S5M8767_IRQ_LOWBAT1] = { - .reg_offset = 0, - .mask = S5M8767_IRQ_LOWBAT1_MASK, - }, - [S5M8767_IRQ_MRB] = { - .reg_offset = 1, - .mask = S5M8767_IRQ_MRB_MASK, - }, - [S5M8767_IRQ_DVSOK2] = { - .reg_offset = 1, - .mask = S5M8767_IRQ_DVSOK2_MASK, - }, - [S5M8767_IRQ_DVSOK3] = { - .reg_offset = 1, - .mask = S5M8767_IRQ_DVSOK3_MASK, - }, - [S5M8767_IRQ_DVSOK4] = { - .reg_offset = 1, - .mask = S5M8767_IRQ_DVSOK4_MASK, - }, - [S5M8767_IRQ_RTC60S] = { - .reg_offset = 2, - .mask = S5M8767_IRQ_RTC60S_MASK, - }, - [S5M8767_IRQ_RTCA1] = { - .reg_offset = 2, - .mask = S5M8767_IRQ_RTCA1_MASK, - }, - [S5M8767_IRQ_RTCA2] = { - .reg_offset = 2, - .mask = S5M8767_IRQ_RTCA2_MASK, - }, - [S5M8767_IRQ_SMPL] = { - .reg_offset = 2, - .mask = S5M8767_IRQ_SMPL_MASK, - }, - [S5M8767_IRQ_RTC1S] = { - .reg_offset = 2, - .mask = S5M8767_IRQ_RTC1S_MASK, - }, - [S5M8767_IRQ_WTSR] = { - .reg_offset = 2, - .mask = S5M8767_IRQ_WTSR_MASK, - }, + REGMAP_IRQ_REG(S5M8767_IRQ_PWRR, 0, S5M8767_IRQ_PWRR_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_PWRF, 0, S5M8767_IRQ_PWRF_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_PWR1S, 0, S5M8767_IRQ_PWR1S_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_JIGR, 0, S5M8767_IRQ_JIGR_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_JIGF, 0, S5M8767_IRQ_JIGF_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_LOWBAT2, 0, S5M8767_IRQ_LOWBAT2_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_LOWBAT1, 0, S5M8767_IRQ_LOWBAT1_MASK), + + REGMAP_IRQ_REG(S5M8767_IRQ_MRB, 1, S5M8767_IRQ_MRB_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_DVSOK2, 1, S5M8767_IRQ_DVSOK2_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_DVSOK3, 1, S5M8767_IRQ_DVSOK3_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_DVSOK4, 1, S5M8767_IRQ_DVSOK4_MASK), + + REGMAP_IRQ_REG(S5M8767_IRQ_RTC60S, 2, S5M8767_IRQ_RTC60S_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_RTCA1, 2, S5M8767_IRQ_RTCA1_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_RTCA2, 2, S5M8767_IRQ_RTCA2_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_SMPL, 2, S5M8767_IRQ_SMPL_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_RTC1S, 2, S5M8767_IRQ_RTC1S_MASK), + REGMAP_IRQ_REG(S5M8767_IRQ_WTSR, 2, S5M8767_IRQ_WTSR_MASK), +}; + +/* All S2MPG10 interrupt sources are read-only and don't require clearing */ +static const struct regmap_irq_chip s2mpg10_irq_chip = { + .name = "s2mpg10", + .irqs = s2mpg10_irqs, + .num_irqs = ARRAY_SIZE(s2mpg10_irqs), + .num_regs = 6, + .status_base = S2MPG10_PMIC_INT1, + .mask_base = S2MPG10_PMIC_INT1M, }; static const struct regmap_irq_chip s2mps11_irq_chip = { @@ -339,6 +233,16 @@ static const struct regmap_irq_chip s2mpu02_irq_chip = { .ack_base = S2MPU02_REG_INT1, }; +static const struct regmap_irq_chip s2mpu05_irq_chip = { + .name = "s2mpu05", + .irqs = s2mpu05_irqs, + .num_irqs = ARRAY_SIZE(s2mpu05_irqs), + .num_regs = 3, + .status_base = S2MPU05_REG_INT1, + .mask_base = S2MPU05_REG_INT1M, + .ack_base = S2MPU05_REG_INT1, +}; + static const struct regmap_irq_chip s5m8767_irq_chip = { .name = "s5m8767", .irqs = s5m8767_irqs, @@ -351,23 +255,21 @@ static const struct regmap_irq_chip s5m8767_irq_chip = { int sec_irq_init(struct sec_pmic_dev *sec_pmic) { - int ret = 0; - int type = sec_pmic->device_type; const struct regmap_irq_chip *sec_irq_chip; + int ret; - if (!sec_pmic->irq) { - dev_warn(sec_pmic->dev, - "No interrupt specified, no interrupts\n"); - return 0; - } - - switch (type) { + switch (sec_pmic->device_type) { case S5M8767X: sec_irq_chip = &s5m8767_irq_chip; break; + case S2DOS05: + return 0; case S2MPA01: sec_irq_chip = &s2mps14_irq_chip; break; + case S2MPG10: + sec_irq_chip = &s2mpg10_irq_chip; + break; case S2MPS11X: sec_irq_chip = &s2mps11_irq_chip; break; @@ -383,19 +285,28 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) case S2MPU02: sec_irq_chip = &s2mpu02_irq_chip; break; + case S2MPU05: + sec_irq_chip = &s2mpu05_irq_chip; + break; default: - dev_err(sec_pmic->dev, "Unknown device type %lu\n", - sec_pmic->device_type); - return -EINVAL; + return dev_err_probe(sec_pmic->dev, -EINVAL, + "Unsupported device type %d\n", + sec_pmic->device_type); + } + + if (!sec_pmic->irq) { + dev_warn(sec_pmic->dev, + "No interrupt specified, no interrupts\n"); + return 0; } ret = devm_regmap_add_irq_chip(sec_pmic->dev, sec_pmic->regmap_pmic, sec_pmic->irq, IRQF_ONESHOT, 0, sec_irq_chip, &sec_pmic->irq_data); - if (ret != 0) { - dev_err(sec_pmic->dev, "Failed to register IRQ chip: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(sec_pmic->dev, ret, + "Failed to add %s IRQ chip\n", + sec_irq_chip->name); /* * The rtc-s5m driver requests S2MPS14_IRQ_RTCA0 also for S2MPS11 @@ -405,10 +316,3 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) return 0; } -EXPORT_SYMBOL_GPL(sec_irq_init); - -MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); -MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); -MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); -MODULE_DESCRIPTION("Interrupt support for the S5M MFD"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/si476x-cmd.c b/drivers/mfd/si476x-cmd.c index c9a0ec084aa8..3bb2decfebd3 100644 --- a/drivers/mfd/si476x-cmd.c +++ b/drivers/mfd/si476x-cmd.c @@ -20,7 +20,7 @@ #include <linux/mfd/si476x-core.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #define msb(x) ((u8)((u16) x >> 8)) #define lsb(x) ((u8)((u16) x & 0x00FF)) diff --git a/drivers/mfd/si476x-prop.c b/drivers/mfd/si476x-prop.c index f0608d138f02..3d5c118888b2 100644 --- a/drivers/mfd/si476x-prop.c +++ b/drivers/mfd/si476x-prop.c @@ -222,7 +222,7 @@ static const struct regmap_config si476x_regmap_config = { .reg_read = si476x_core_regmap_read, .reg_write = si476x_core_regmap_write, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; struct regmap *devm_regmap_init_si476x(struct si476x_core *core) diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index 6eda79533208..22159913bea0 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -83,11 +83,22 @@ static const struct simple_mfd_data maxim_max5970 = { .mfd_cell_size = ARRAY_SIZE(max5970_cells), }; +static const struct mfd_cell max77705_sensor_cells[] = { + { .name = "max77705-battery" }, + { .name = "max77705-hwmon", }, +}; + +static const struct simple_mfd_data maxim_mon_max77705 = { + .mfd_cell = max77705_sensor_cells, + .mfd_cell_size = ARRAY_SIZE(max77705_sensor_cells), +}; + static const struct of_device_id simple_mfd_i2c_of_match[] = { { .compatible = "kontron,sl28cpld" }, { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, { .compatible = "maxim,max5970", .data = &maxim_max5970}, { .compatible = "maxim,max5978", .data = &maxim_max5970}, + { .compatible = "maxim,max77705-battery", .data = &maxim_mon_max77705}, {} }; MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index b3592982a83b..a5f9241fa3f2 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -631,49 +631,6 @@ unsigned long sm501_set_clock(struct device *dev, EXPORT_SYMBOL_GPL(sm501_set_clock); -/* sm501_find_clock - * - * finds the closest available frequency for a given clock -*/ - -unsigned long sm501_find_clock(struct device *dev, - int clksrc, - unsigned long req_freq) -{ - struct sm501_devdata *sm = dev_get_drvdata(dev); - unsigned long sm501_freq; /* the frequency achieveable by the 501 */ - struct sm501_clock to; - - switch (clksrc) { - case SM501_CLOCK_P2XCLK: - if (sm->rev >= 0xC0) { - /* SM502 -> use the programmable PLL */ - sm501_freq = (sm501_calc_pll(2 * req_freq, - &to, 5) / 2); - } else { - sm501_freq = (sm501_select_clock(2 * req_freq, - &to, 5) / 2); - } - break; - - case SM501_CLOCK_V2XCLK: - sm501_freq = (sm501_select_clock(2 * req_freq, &to, 3) / 2); - break; - - case SM501_CLOCK_MCLK: - case SM501_CLOCK_M1XCLK: - sm501_freq = sm501_select_clock(req_freq, &to, 3); - break; - - default: - sm501_freq = 0; /* error */ - } - - return sm501_freq; -} - -EXPORT_SYMBOL_GPL(sm501_find_clock); - static struct sm501_device *to_sm_device(struct platform_device *pdev) { return container_of(pdev, struct sm501_device, pdev); @@ -915,12 +872,13 @@ static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip, } } -static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int sm501_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct sm501_gpio_chip *smchip = gpiochip_get_data(chip); struct sm501_gpio *smgpio = smchip->ourgpio; - unsigned long bit = 1 << offset; + unsigned long bit = BIT(offset); void __iomem *regs = smchip->regbase; unsigned long save; unsigned long val; @@ -939,6 +897,8 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) sm501_gpio_ensure_gpio(smchip, bit); spin_unlock_irqrestore(&smgpio->lock, save); + + return 0; } static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) @@ -946,7 +906,7 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) struct sm501_gpio_chip *smchip = gpiochip_get_data(chip); struct sm501_gpio *smgpio = smchip->ourgpio; void __iomem *regs = smchip->regbase; - unsigned long bit = 1 << offset; + unsigned long bit = BIT(offset); unsigned long save; unsigned long ddr; @@ -971,7 +931,7 @@ static int sm501_gpio_output(struct gpio_chip *chip, { struct sm501_gpio_chip *smchip = gpiochip_get_data(chip); struct sm501_gpio *smgpio = smchip->ourgpio; - unsigned long bit = 1 << offset; + unsigned long bit = BIT(offset); void __iomem *regs = smchip->regbase; unsigned long save; unsigned long val; @@ -1005,7 +965,7 @@ static const struct gpio_chip gpio_chip_template = { .ngpio = 32, .direction_input = sm501_gpio_input, .direction_output = sm501_gpio_output, - .set = sm501_gpio_set, + .set_rv = sm501_gpio_set, .get = sm501_gpio_get, }; @@ -1705,7 +1665,7 @@ static struct platform_driver sm501_plat_driver = { .of_match_table = of_sm501_match_tbl, }, .probe = sm501_plat_probe, - .remove_new = sm501_plat_remove, + .remove = sm501_plat_remove, .suspend = pm_sleep_ptr(sm501_plat_suspend), .resume = pm_sleep_ptr(sm501_plat_resume), }; diff --git a/drivers/mfd/sprd-sc27xx-spi.c b/drivers/mfd/sprd-sc27xx-spi.c index 81e517cdfb27..d6b4350779e6 100644 --- a/drivers/mfd/sprd-sc27xx-spi.c +++ b/drivers/mfd/sprd-sc27xx-spi.c @@ -135,7 +135,7 @@ static int sprd_pmic_spi_read(void *context, return 0; } -static struct regmap_bus sprd_pmic_regmap = { +static const struct regmap_bus sprd_pmic_regmap = { .write = sprd_pmic_spi_write, .read = sprd_pmic_spi_read, .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, @@ -210,7 +210,10 @@ static int sprd_pmic_probe(struct spi_device *spi) return ret; } - device_init_wakeup(&spi->dev, true); + ret = devm_device_init_wakeup(&spi->dev); + if (ret) + return dev_err_probe(&spi->dev, ret, "Failed to init wakeup\n"); + return 0; } diff --git a/drivers/mfd/ssbi.c b/drivers/mfd/ssbi.c index b0b0be483dbf..6e7aff6e2746 100644 --- a/drivers/mfd/ssbi.c +++ b/drivers/mfd/ssbi.c @@ -64,7 +64,6 @@ enum ssbi_controller_type { }; struct ssbi { - struct device *slave; void __iomem *base; spinlock_t lock; enum ssbi_controller_type controller_type; @@ -320,6 +319,7 @@ static struct platform_driver ssbi_driver = { }; module_platform_driver(ssbi_driver); +MODULE_DESCRIPTION("Qualcomm Single-wire Serial Bus Interface (SSBI) driver"); MODULE_LICENSE("GPL v2"); MODULE_VERSION("1.0"); MODULE_ALIAS("platform:ssbi"); diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c deleted file mode 100644 index 02cc49daf2e3..000000000000 --- a/drivers/mfd/sta2x11-mfd.c +++ /dev/null @@ -1,645 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * STA2x11 mfd for GPIO, SCTL and APBREG - * - * Copyright (c) 2009-2011 Wind River Systems, Inc. - * Copyright (c) 2011 ST Microelectronics (Alessandro Rubini, Davide Ciminaghi) - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/export.h> -#include <linux/spinlock.h> -#include <linux/errno.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/io.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/seq_file.h> -#include <linux/platform_device.h> -#include <linux/mfd/core.h> -#include <linux/mfd/sta2x11-mfd.h> -#include <linux/regmap.h> - -#include <asm/sta2x11.h> - -static inline int __reg_within_range(unsigned int r, - unsigned int start, - unsigned int end) -{ - return ((r >= start) && (r <= end)); -} - -/* This describes STA2X11 MFD chip for us, we may have several */ -struct sta2x11_mfd { - struct sta2x11_instance *instance; - struct regmap *regmap[sta2x11_n_mfd_plat_devs]; - spinlock_t lock[sta2x11_n_mfd_plat_devs]; - struct list_head list; - void __iomem *regs[sta2x11_n_mfd_plat_devs]; -}; - -static LIST_HEAD(sta2x11_mfd_list); - -/* Three functions to act on the list */ -static struct sta2x11_mfd *sta2x11_mfd_find(struct pci_dev *pdev) -{ - struct sta2x11_instance *instance; - struct sta2x11_mfd *mfd; - - if (!pdev && !list_empty(&sta2x11_mfd_list)) { - pr_warn("%s: Unspecified device, using first instance\n", - __func__); - return list_entry(sta2x11_mfd_list.next, - struct sta2x11_mfd, list); - } - - instance = sta2x11_get_instance(pdev); - if (!instance) - return NULL; - list_for_each_entry(mfd, &sta2x11_mfd_list, list) { - if (mfd->instance == instance) - return mfd; - } - return NULL; -} - -static int sta2x11_mfd_add(struct pci_dev *pdev, gfp_t flags) -{ - int i; - struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); - struct sta2x11_instance *instance; - - if (mfd) - return -EBUSY; - instance = sta2x11_get_instance(pdev); - if (!instance) - return -EINVAL; - mfd = kzalloc(sizeof(*mfd), flags); - if (!mfd) - return -ENOMEM; - INIT_LIST_HEAD(&mfd->list); - for (i = 0; i < ARRAY_SIZE(mfd->lock); i++) - spin_lock_init(&mfd->lock[i]); - mfd->instance = instance; - list_add(&mfd->list, &sta2x11_mfd_list); - return 0; -} - -/* This function is exported and is not expected to fail */ -u32 __sta2x11_mfd_mask(struct pci_dev *pdev, u32 reg, u32 mask, u32 val, - enum sta2x11_mfd_plat_dev index) -{ - struct sta2x11_mfd *mfd = sta2x11_mfd_find(pdev); - u32 r; - unsigned long flags; - void __iomem *regs; - - if (!mfd) { - dev_warn(&pdev->dev, ": can't access sctl regs\n"); - return 0; - } - - regs = mfd->regs[index]; - if (!regs) { - dev_warn(&pdev->dev, ": system ctl not initialized\n"); - return 0; - } - spin_lock_irqsave(&mfd->lock[index], flags); - r = readl(regs + reg); - r &= ~mask; - r |= val; - if (mask) - writel(r, regs + reg); - spin_unlock_irqrestore(&mfd->lock[index], flags); - return r; -} -EXPORT_SYMBOL(__sta2x11_mfd_mask); - -int sta2x11_mfd_get_regs_data(struct platform_device *dev, - enum sta2x11_mfd_plat_dev index, - void __iomem **regs, - spinlock_t **lock) -{ - struct pci_dev *pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev); - struct sta2x11_mfd *mfd; - - if (!pdev) - return -ENODEV; - mfd = sta2x11_mfd_find(pdev); - if (!mfd) - return -ENODEV; - if (index >= sta2x11_n_mfd_plat_devs) - return -ENODEV; - *regs = mfd->regs[index]; - *lock = &mfd->lock[index]; - pr_debug("%s %d *regs = %p\n", __func__, __LINE__, *regs); - return *regs ? 0 : -ENODEV; -} -EXPORT_SYMBOL(sta2x11_mfd_get_regs_data); - -/* - * Special sta2x11-mfd regmap lock/unlock functions - */ - -static void sta2x11_regmap_lock(void *__lock) -{ - spinlock_t *lock = __lock; - spin_lock(lock); -} - -static void sta2x11_regmap_unlock(void *__lock) -{ - spinlock_t *lock = __lock; - spin_unlock(lock); -} - -/* OTP (one time programmable registers do not require locking */ -static void sta2x11_regmap_nolock(void *__lock) -{ -} - -static const char *sta2x11_mfd_names[sta2x11_n_mfd_plat_devs] = { - [sta2x11_sctl] = STA2X11_MFD_SCTL_NAME, - [sta2x11_apbreg] = STA2X11_MFD_APBREG_NAME, - [sta2x11_apb_soc_regs] = STA2X11_MFD_APB_SOC_REGS_NAME, - [sta2x11_scr] = STA2X11_MFD_SCR_NAME, -}; - -static bool sta2x11_sctl_writeable_reg(struct device *dev, unsigned int reg) -{ - return !__reg_within_range(reg, SCTL_SCPCIECSBRST, SCTL_SCRSTSTA); -} - -static struct regmap_config sta2x11_sctl_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .lock = sta2x11_regmap_lock, - .unlock = sta2x11_regmap_unlock, - .max_register = SCTL_SCRSTSTA, - .writeable_reg = sta2x11_sctl_writeable_reg, -}; - -static bool sta2x11_scr_readable_reg(struct device *dev, unsigned int reg) -{ - return (reg == STA2X11_SECR_CR) || - __reg_within_range(reg, STA2X11_SECR_FVR0, STA2X11_SECR_FVR1); -} - -static bool sta2x11_scr_writeable_reg(struct device *dev, unsigned int reg) -{ - return false; -} - -static struct regmap_config sta2x11_scr_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .lock = sta2x11_regmap_nolock, - .unlock = sta2x11_regmap_nolock, - .max_register = STA2X11_SECR_FVR1, - .readable_reg = sta2x11_scr_readable_reg, - .writeable_reg = sta2x11_scr_writeable_reg, -}; - -static bool sta2x11_apbreg_readable_reg(struct device *dev, unsigned int reg) -{ - /* Two blocks (CAN and MLB, SARAC) 0x100 bytes apart */ - if (reg >= APBREG_BSR_SARAC) - reg -= APBREG_BSR_SARAC; - switch (reg) { - case APBREG_BSR: - case APBREG_PAER: - case APBREG_PWAC: - case APBREG_PRAC: - case APBREG_PCG: - case APBREG_PUR: - case APBREG_EMU_PCG: - return true; - default: - return false; - } -} - -static bool sta2x11_apbreg_writeable_reg(struct device *dev, unsigned int reg) -{ - if (reg >= APBREG_BSR_SARAC) - reg -= APBREG_BSR_SARAC; - if (!sta2x11_apbreg_readable_reg(dev, reg)) - return false; - return reg != APBREG_PAER; -} - -static struct regmap_config sta2x11_apbreg_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .lock = sta2x11_regmap_lock, - .unlock = sta2x11_regmap_unlock, - .max_register = APBREG_EMU_PCG_SARAC, - .readable_reg = sta2x11_apbreg_readable_reg, - .writeable_reg = sta2x11_apbreg_writeable_reg, -}; - -static bool sta2x11_apb_soc_regs_readable_reg(struct device *dev, - unsigned int reg) -{ - return reg <= PCIE_SoC_INT_ROUTER_STATUS3_REG || - __reg_within_range(reg, DMA_IP_CTRL_REG, SPARE3_RESERVED) || - __reg_within_range(reg, MASTER_LOCK_REG, - SYSTEM_CONFIG_STATUS_REG) || - reg == MSP_CLK_CTRL_REG || - __reg_within_range(reg, COMPENSATION_REG1, TEST_CTL_REG); -} - -static bool sta2x11_apb_soc_regs_writeable_reg(struct device *dev, - unsigned int reg) -{ - if (!sta2x11_apb_soc_regs_readable_reg(dev, reg)) - return false; - switch (reg) { - case PCIE_COMMON_CLOCK_CONFIG_0_4_0: - case SYSTEM_CONFIG_STATUS_REG: - case COMPENSATION_REG1: - case PCIE_SoC_INT_ROUTER_STATUS0_REG...PCIE_SoC_INT_ROUTER_STATUS3_REG: - case PCIE_PM_STATUS_0_PORT_0_4...PCIE_PM_STATUS_7_0_EP4: - return false; - default: - return true; - } -} - -static struct regmap_config sta2x11_apb_soc_regs_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .lock = sta2x11_regmap_lock, - .unlock = sta2x11_regmap_unlock, - .max_register = TEST_CTL_REG, - .readable_reg = sta2x11_apb_soc_regs_readable_reg, - .writeable_reg = sta2x11_apb_soc_regs_writeable_reg, -}; - -static struct regmap_config * -sta2x11_mfd_regmap_configs[sta2x11_n_mfd_plat_devs] = { - [sta2x11_sctl] = &sta2x11_sctl_regmap_config, - [sta2x11_apbreg] = &sta2x11_apbreg_regmap_config, - [sta2x11_apb_soc_regs] = &sta2x11_apb_soc_regs_regmap_config, - [sta2x11_scr] = &sta2x11_scr_regmap_config, -}; - -/* Probe for the four platform devices */ - -static int sta2x11_mfd_platform_probe(struct platform_device *dev, - enum sta2x11_mfd_plat_dev index) -{ - struct pci_dev **pdev; - struct sta2x11_mfd *mfd; - struct resource *res; - const char *name = sta2x11_mfd_names[index]; - struct regmap_config *regmap_config = sta2x11_mfd_regmap_configs[index]; - - pdev = dev_get_platdata(&dev->dev); - mfd = sta2x11_mfd_find(*pdev); - if (!mfd) - return -ENODEV; - if (!regmap_config) - return -ENODEV; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - return -ENOMEM; - - if (!request_mem_region(res->start, resource_size(res), name)) - return -EBUSY; - - mfd->regs[index] = ioremap(res->start, resource_size(res)); - if (!mfd->regs[index]) { - release_mem_region(res->start, resource_size(res)); - return -ENOMEM; - } - regmap_config->lock_arg = &mfd->lock; - /* - No caching, registers could be reached both via regmap and via - void __iomem * - */ - regmap_config->cache_type = REGCACHE_NONE; - mfd->regmap[index] = devm_regmap_init_mmio(&dev->dev, mfd->regs[index], - regmap_config); - WARN_ON(IS_ERR(mfd->regmap[index])); - - return 0; -} - -static int sta2x11_sctl_probe(struct platform_device *dev) -{ - return sta2x11_mfd_platform_probe(dev, sta2x11_sctl); -} - -static int sta2x11_apbreg_probe(struct platform_device *dev) -{ - return sta2x11_mfd_platform_probe(dev, sta2x11_apbreg); -} - -static int sta2x11_apb_soc_regs_probe(struct platform_device *dev) -{ - return sta2x11_mfd_platform_probe(dev, sta2x11_apb_soc_regs); -} - -static int sta2x11_scr_probe(struct platform_device *dev) -{ - return sta2x11_mfd_platform_probe(dev, sta2x11_scr); -} - -/* The three platform drivers */ -static struct platform_driver sta2x11_sctl_platform_driver = { - .driver = { - .name = STA2X11_MFD_SCTL_NAME, - }, - .probe = sta2x11_sctl_probe, -}; - -static struct platform_driver sta2x11_platform_driver = { - .driver = { - .name = STA2X11_MFD_APBREG_NAME, - }, - .probe = sta2x11_apbreg_probe, -}; - -static struct platform_driver sta2x11_apb_soc_regs_platform_driver = { - .driver = { - .name = STA2X11_MFD_APB_SOC_REGS_NAME, - }, - .probe = sta2x11_apb_soc_regs_probe, -}; - -static struct platform_driver sta2x11_scr_platform_driver = { - .driver = { - .name = STA2X11_MFD_SCR_NAME, - }, - .probe = sta2x11_scr_probe, -}; - -static struct platform_driver * const drivers[] = { - &sta2x11_platform_driver, - &sta2x11_sctl_platform_driver, - &sta2x11_apb_soc_regs_platform_driver, - &sta2x11_scr_platform_driver, -}; - -static int __init sta2x11_drivers_init(void) -{ - return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); -} - -/* - * What follows are the PCI devices that host the above pdevs. - * Each logic block is 4kB and they are all consecutive: we use this info. - */ - -/* Mfd 0 device */ - -/* Mfd 0, Bar 0 */ -enum mfd0_bar0_cells { - STA2X11_GPIO_0 = 0, - STA2X11_GPIO_1, - STA2X11_GPIO_2, - STA2X11_GPIO_3, - STA2X11_SCTL, - STA2X11_SCR, - STA2X11_TIME, -}; -/* Mfd 0 , Bar 1 */ -enum mfd0_bar1_cells { - STA2X11_APBREG = 0, -}; -#define CELL_4K(_name, _cell) { \ - .name = _name, \ - .start = _cell * 4096, .end = _cell * 4096 + 4095, \ - .flags = IORESOURCE_MEM, \ - } - -static const struct resource gpio_resources[] = { - { - /* 4 consecutive cells, 1 driver */ - .name = STA2X11_MFD_GPIO_NAME, - .start = 0, - .end = (4 * 4096) - 1, - .flags = IORESOURCE_MEM, - } -}; -static const struct resource sctl_resources[] = { - CELL_4K(STA2X11_MFD_SCTL_NAME, STA2X11_SCTL), -}; -static const struct resource scr_resources[] = { - CELL_4K(STA2X11_MFD_SCR_NAME, STA2X11_SCR), -}; -static const struct resource time_resources[] = { - CELL_4K(STA2X11_MFD_TIME_NAME, STA2X11_TIME), -}; - -static const struct resource apbreg_resources[] = { - CELL_4K(STA2X11_MFD_APBREG_NAME, STA2X11_APBREG), -}; - -#define DEV(_name, _r) \ - { .name = _name, .num_resources = ARRAY_SIZE(_r), .resources = _r, } - -static struct mfd_cell sta2x11_mfd0_bar0[] = { - /* offset 0: we add pdata later */ - DEV(STA2X11_MFD_GPIO_NAME, gpio_resources), - DEV(STA2X11_MFD_SCTL_NAME, sctl_resources), - DEV(STA2X11_MFD_SCR_NAME, scr_resources), - DEV(STA2X11_MFD_TIME_NAME, time_resources), -}; - -static struct mfd_cell sta2x11_mfd0_bar1[] = { - DEV(STA2X11_MFD_APBREG_NAME, apbreg_resources), -}; - -/* Mfd 1 devices */ - -/* Mfd 1, Bar 0 */ -enum mfd1_bar0_cells { - STA2X11_VIC = 0, -}; - -/* Mfd 1, Bar 1 */ -enum mfd1_bar1_cells { - STA2X11_APB_SOC_REGS = 0, -}; - -static const struct resource vic_resources[] = { - CELL_4K(STA2X11_MFD_VIC_NAME, STA2X11_VIC), -}; - -static const struct resource apb_soc_regs_resources[] = { - CELL_4K(STA2X11_MFD_APB_SOC_REGS_NAME, STA2X11_APB_SOC_REGS), -}; - -static struct mfd_cell sta2x11_mfd1_bar0[] = { - DEV(STA2X11_MFD_VIC_NAME, vic_resources), -}; - -static struct mfd_cell sta2x11_mfd1_bar1[] = { - DEV(STA2X11_MFD_APB_SOC_REGS_NAME, apb_soc_regs_resources), -}; - - -static int sta2x11_mfd_suspend(struct pci_dev *pdev, pm_message_t state) -{ - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -static int sta2x11_mfd_resume(struct pci_dev *pdev) -{ - int err; - - pci_set_power_state(pdev, PCI_D0); - err = pci_enable_device(pdev); - if (err) - return err; - pci_restore_state(pdev); - - return 0; -} - -struct sta2x11_mfd_bar_setup_data { - struct mfd_cell *cells; - int ncells; -}; - -struct sta2x11_mfd_setup_data { - struct sta2x11_mfd_bar_setup_data bars[2]; -}; - -#define STA2X11_MFD0 0 -#define STA2X11_MFD1 1 - -static struct sta2x11_mfd_setup_data mfd_setup_data[] = { - /* Mfd 0: gpio, sctl, scr, timers / apbregs */ - [STA2X11_MFD0] = { - .bars = { - [0] = { - .cells = sta2x11_mfd0_bar0, - .ncells = ARRAY_SIZE(sta2x11_mfd0_bar0), - }, - [1] = { - .cells = sta2x11_mfd0_bar1, - .ncells = ARRAY_SIZE(sta2x11_mfd0_bar1), - }, - }, - }, - /* Mfd 1: vic / apb-soc-regs */ - [STA2X11_MFD1] = { - .bars = { - [0] = { - .cells = sta2x11_mfd1_bar0, - .ncells = ARRAY_SIZE(sta2x11_mfd1_bar0), - }, - [1] = { - .cells = sta2x11_mfd1_bar1, - .ncells = ARRAY_SIZE(sta2x11_mfd1_bar1), - }, - }, - }, -}; - -static void sta2x11_mfd_setup(struct pci_dev *pdev, - struct sta2x11_mfd_setup_data *sd) -{ - int i, j; - for (i = 0; i < ARRAY_SIZE(sd->bars); i++) - for (j = 0; j < sd->bars[i].ncells; j++) { - sd->bars[i].cells[j].pdata_size = sizeof(pdev); - sd->bars[i].cells[j].platform_data = &pdev; - } -} - -static int sta2x11_mfd_probe(struct pci_dev *pdev, - const struct pci_device_id *pci_id) -{ - int err, i; - struct sta2x11_mfd_setup_data *setup_data; - - dev_info(&pdev->dev, "%s\n", __func__); - - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "Can't enable device.\n"); - return err; - } - - err = pci_enable_msi(pdev); - if (err) - dev_info(&pdev->dev, "Enable msi failed\n"); - - setup_data = pci_id->device == PCI_DEVICE_ID_STMICRO_GPIO ? - &mfd_setup_data[STA2X11_MFD0] : - &mfd_setup_data[STA2X11_MFD1]; - - /* platform data is the pci device for all of them */ - sta2x11_mfd_setup(pdev, setup_data); - - /* Record this pdev before mfd_add_devices: their probe looks for it */ - if (!sta2x11_mfd_find(pdev)) - sta2x11_mfd_add(pdev, GFP_KERNEL); - - /* Just 2 bars for all mfd's at present */ - for (i = 0; i < 2; i++) { - err = mfd_add_devices(&pdev->dev, -1, - setup_data->bars[i].cells, - setup_data->bars[i].ncells, - &pdev->resource[i], - 0, NULL); - if (err) { - dev_err(&pdev->dev, - "mfd_add_devices[%d] failed: %d\n", i, err); - goto err_disable; - } - } - - return 0; - -err_disable: - mfd_remove_devices(&pdev->dev); - pci_disable_device(pdev); - pci_disable_msi(pdev); - return err; -} - -static const struct pci_device_id sta2x11_mfd_tbl[] = { - {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_GPIO)}, - {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIC)}, - {0,}, -}; - -static struct pci_driver sta2x11_mfd_driver = { - .name = "sta2x11-mfd", - .id_table = sta2x11_mfd_tbl, - .probe = sta2x11_mfd_probe, - .suspend = sta2x11_mfd_suspend, - .resume = sta2x11_mfd_resume, -}; - -static int __init sta2x11_mfd_init(void) -{ - pr_info("%s\n", __func__); - return pci_register_driver(&sta2x11_mfd_driver); -} - -/* - * All of this must be ready before "normal" devices like MMCI appear. - * But MFD (the pci device) can't be too early. The following choice - * prepares platform drivers very early and probe the PCI device later, - * but before other PCI devices. - */ -subsys_initcall(sta2x11_drivers_init); -rootfs_initcall(sta2x11_mfd_init); diff --git a/drivers/mfd/stm32-lptimer.c b/drivers/mfd/stm32-lptimer.c index b2704a9809c7..09073dbc9c80 100644 --- a/drivers/mfd/stm32-lptimer.c +++ b/drivers/mfd/stm32-lptimer.c @@ -6,6 +6,7 @@ * Inspired by Benjamin Gaignard's stm32-timers driver */ +#include <linux/bitfield.h> #include <linux/mfd/stm32-lptimer.h> #include <linux/module.h> #include <linux/of_platform.h> @@ -49,6 +50,36 @@ static int stm32_lptimer_detect_encoder(struct stm32_lptimer *ddata) return 0; } +static int stm32_lptimer_detect_hwcfgr(struct stm32_lptimer *ddata) +{ + u32 val; + int ret; + + ret = regmap_read(ddata->regmap, STM32_LPTIM_VERR, &ddata->version); + if (ret) + return ret; + + /* Try to guess parameters from HWCFGR: e.g. encoder mode (STM32MP15) */ + ret = regmap_read(ddata->regmap, STM32_LPTIM_HWCFGR1, &val); + if (ret) + return ret; + + /* Fallback to legacy init if HWCFGR isn't present */ + if (!val) + return stm32_lptimer_detect_encoder(ddata); + + ddata->has_encoder = FIELD_GET(STM32_LPTIM_HWCFGR1_ENCODER, val); + + ret = regmap_read(ddata->regmap, STM32_LPTIM_HWCFGR2, &val); + if (ret) + return ret; + + /* Number of capture/compare channels */ + ddata->num_cc_chans = FIELD_GET(STM32_LPTIM_HWCFGR2_CHAN_NUM, val); + + return 0; +} + static int stm32_lptimer_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -73,7 +104,7 @@ static int stm32_lptimer_probe(struct platform_device *pdev) if (IS_ERR(ddata->clk)) return PTR_ERR(ddata->clk); - ret = stm32_lptimer_detect_encoder(ddata); + ret = stm32_lptimer_detect_hwcfgr(ddata); if (ret) return ret; diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c index 9fd13d88950c..e3c116ee4034 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/reset.h> #define STM32_TIMERS_MAX_REGISTERS 0x3fc @@ -173,6 +174,31 @@ static void stm32_timers_get_arr_size(struct stm32_timers *ddata) regmap_write(ddata->regmap, TIM_ARR, arr); } +static int stm32_timers_probe_hwcfgr(struct device *dev, struct stm32_timers *ddata) +{ + u32 val; + + ddata->ipidr = (uintptr_t)device_get_match_data(dev); + if (!ddata->ipidr) { + /* Fallback to legacy method for probing counter width */ + stm32_timers_get_arr_size(ddata); + return 0; + } + + regmap_read(ddata->regmap, TIM_IPIDR, &val); + if (val != ddata->ipidr) { + dev_err(dev, "Unsupported device detected: %u\n", val); + return -EINVAL; + } + + regmap_read(ddata->regmap, TIM_HWCFGR2, &val); + + /* Counter width in bits, max reload value is BIT(width) - 1 */ + ddata->max_arr = BIT(FIELD_GET(TIM_HWCFGR2_CNT_WIDTH, val)) - 1; + + return 0; +} + static int stm32_timers_dma_probe(struct device *dev, struct stm32_timers *ddata) { @@ -285,7 +311,9 @@ static int stm32_timers_probe(struct platform_device *pdev) if (IS_ERR(ddata->clk)) return PTR_ERR(ddata->clk); - stm32_timers_get_arr_size(ddata); + ret = stm32_timers_probe_hwcfgr(dev, ddata); + if (ret) + return ret; ret = stm32_timers_irq_probe(pdev, ddata); if (ret) @@ -320,13 +348,14 @@ static void stm32_timers_remove(struct platform_device *pdev) static const struct of_device_id stm32_timers_of_match[] = { { .compatible = "st,stm32-timers", }, + { .compatible = "st,stm32mp25-timers", .data = (void *)STM32MP25_TIM_IPIDR }, { /* end node */ }, }; MODULE_DEVICE_TABLE(of, stm32_timers_of_match); static struct platform_driver stm32_timers_driver = { .probe = stm32_timers_probe, - .remove_new = stm32_timers_remove, + .remove = stm32_timers_remove, .driver = { .name = "stm32-timers", .of_match_table = stm32_timers_of_match, diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c index c02cbd9c2f5d..823b1d29389e 100644 --- a/drivers/mfd/stmfx.c +++ b/drivers/mfd/stmfx.c @@ -53,7 +53,7 @@ static const struct regmap_config stmfx_regmap_config = { .max_register = STMFX_REG_MAX, .volatile_reg = stmfx_reg_volatile, .writeable_reg = stmfx_reg_writeable, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; static const struct resource stmfx_pinctrl_resources[] = { @@ -269,7 +269,7 @@ static int stmfx_irq_init(struct i2c_client *client) u32 irqoutpin = 0, irqtrigger; int ret; - stmfx->irq_domain = irq_domain_add_simple(stmfx->dev->of_node, + stmfx->irq_domain = irq_domain_create_simple(of_fwnode_handle(stmfx->dev->of_node), STMFX_REG_IRQ_SRC_MAX, 0, &stmfx_irq_ops, stmfx); if (!stmfx->irq_domain) { diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index 792236f56399..b9cc85ea2c40 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -129,7 +129,7 @@ static const struct spi_device_id stmpe_spi_id[] = { { "stmpe2403", STMPE2403 }, { } }; -MODULE_DEVICE_TABLE(spi, stmpe_id); +MODULE_DEVICE_TABLE(spi, stmpe_spi_id); static struct spi_driver stmpe_spi_driver = { .driver = { diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 9c3cf58457a7..819d19dc9b4a 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1219,8 +1219,8 @@ static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np) int base = 0; int num_irqs = stmpe->variant->num_irqs; - stmpe->domain = irq_domain_add_simple(np, num_irqs, base, - &stmpe_irq_ops, stmpe); + stmpe->domain = irq_domain_create_simple(of_fwnode_handle(np), num_irqs, + base, &stmpe_irq_ops, stmpe); if (!stmpe->domain) { dev_err(stmpe->dev, "Failed to create irqdomain\n"); return -ENOSYS; diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c index c5128fe96cc7..081827bc0596 100644 --- a/drivers/mfd/stpmic1.c +++ b/drivers/mfd/stpmic1.c @@ -63,7 +63,7 @@ static const struct regmap_access_table stpmic1_volatile_table = { static const struct regmap_config stpmic1_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = PMIC_MAX_REGISTER_ADDRESS, .rd_table = &stpmic1_readable_table, .wr_table = &stpmic1_writeable_table, @@ -170,11 +170,7 @@ static int stpmic1_probe(struct i2c_client *i2c) return ret; } - ret = devm_register_sys_off_handler(ddata->dev, - SYS_OFF_MODE_POWER_OFF, - SYS_OFF_PRIO_DEFAULT, - stpmic1_power_off, - ddata); + ret = devm_register_power_off_handler(ddata->dev, stpmic1_power_off, ddata); if (ret) { dev_err(ddata->dev, "failed to register sys-off handler: %d\n", ret); return ret; diff --git a/drivers/mfd/stw481x.c b/drivers/mfd/stw481x.c index f35c3af680dd..5ed64d53c23d 100644 --- a/drivers/mfd/stw481x.c +++ b/drivers/mfd/stw481x.c @@ -222,8 +222,8 @@ static int stw481x_probe(struct i2c_client *client) * the structure of the I2C core. */ static const struct i2c_device_id stw481x_id[] = { - { "stw481x", 0 }, - { }, + { "stw481x" }, + { } }; MODULE_DEVICE_TABLE(i2c, stw481x_id); diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index c9550368d9ea..ae71a2710bed 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -8,25 +8,20 @@ * Author: Dong Aisheng <dong.aisheng@linaro.org> */ +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/hwspinlock.h> -#include <linux/io.h> -#include <linux/init.h> #include <linux/list.h> +#include <linux/mutex.h> #include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_platform.h> -#include <linux/platform_data/syscon.h> -#include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/reset.h> #include <linux/mfd/syscon.h> #include <linux/slab.h> -static struct platform_driver syscon_driver; - -static DEFINE_SPINLOCK(syscon_list_slock); +static DEFINE_MUTEX(syscon_list_lock); static LIST_HEAD(syscon_list); struct syscon { @@ -45,7 +40,6 @@ static const struct regmap_config syscon_regmap_config = { static struct syscon *of_syscon_register(struct device_node *np, bool check_res) { struct clk *clk; - struct syscon *syscon; struct regmap *regmap; void __iomem *base; u32 reg_io_width; @@ -53,21 +47,20 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) struct regmap_config syscon_config = syscon_regmap_config; struct resource res; struct reset_control *reset; + resource_size_t res_size; - syscon = kzalloc(sizeof(*syscon), GFP_KERNEL); + WARN_ON(!mutex_is_locked(&syscon_list_lock)); + + struct syscon *syscon __free(kfree) = kzalloc(sizeof(*syscon), GFP_KERNEL); if (!syscon) return ERR_PTR(-ENOMEM); - if (of_address_to_resource(np, 0, &res)) { - ret = -ENOMEM; - goto err_map; - } + if (of_address_to_resource(np, 0, &res)) + return ERR_PTR(-ENOMEM); base = of_iomap(np, 0); - if (!base) { - ret = -ENOMEM; - goto err_map; - } + if (!base) + return ERR_PTR(-ENOMEM); /* Parse the device's DT node for an endianness specification */ if (of_property_read_bool(np, "big-endian")) @@ -104,6 +97,12 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) } } + res_size = resource_size(&res); + if (res_size < reg_io_width) { + ret = -EFAULT; + goto err_regmap; + } + syscon_config.name = kasprintf(GFP_KERNEL, "%pOFn@%pa", np, &res.start); if (!syscon_config.name) { ret = -ENOMEM; @@ -111,7 +110,9 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) } syscon_config.reg_stride = reg_io_width; syscon_config.val_bits = reg_io_width * 8; - syscon_config.max_register = resource_size(&res) - reg_io_width; + syscon_config.max_register = res_size - reg_io_width; + if (!syscon_config.max_register) + syscon_config.max_register_is_0 = true; regmap = regmap_init_mmio(NULL, base, &syscon_config); kfree(syscon_config.name); @@ -148,11 +149,9 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_res) syscon->regmap = regmap; syscon->np = np; - spin_lock(&syscon_list_slock); list_add_tail(&syscon->list, &syscon_list); - spin_unlock(&syscon_list_slock); - return syscon; + return_ptr(syscon); err_reset: reset_control_put(reset); @@ -163,17 +162,16 @@ err_clk: regmap_exit(regmap); err_regmap: iounmap(base); -err_map: - kfree(syscon); return ERR_PTR(ret); } static struct regmap *device_node_get_regmap(struct device_node *np, + bool create_regmap, bool check_res) { struct syscon *entry, *syscon = NULL; - spin_lock(&syscon_list_slock); + mutex_lock(&syscon_list_lock); list_for_each_entry(entry, &syscon_list, list) if (entry->np == np) { @@ -181,10 +179,13 @@ static struct regmap *device_node_get_regmap(struct device_node *np, break; } - spin_unlock(&syscon_list_slock); - - if (!syscon) - syscon = of_syscon_register(np, check_res); + if (!syscon) { + if (create_regmap) + syscon = of_syscon_register(np, check_res); + else + syscon = ERR_PTR(-EINVAL); + } + mutex_unlock(&syscon_list_lock); if (IS_ERR(syscon)) return ERR_CAST(syscon); @@ -192,18 +193,85 @@ static struct regmap *device_node_get_regmap(struct device_node *np, return syscon->regmap; } +/** + * of_syscon_register_regmap() - Register regmap for specified device node + * @np: Device tree node + * @regmap: Pointer to regmap object + * + * Register an externally created regmap object with syscon for the specified + * device tree node. This regmap will then be returned to client drivers using + * the syscon_regmap_lookup_by_phandle() API. + * + * Return: 0 on success, negative error code on failure. + */ +int of_syscon_register_regmap(struct device_node *np, struct regmap *regmap) +{ + struct syscon *entry, *syscon = NULL; + int ret; + + if (!np || !regmap) + return -EINVAL; + + syscon = kzalloc(sizeof(*syscon), GFP_KERNEL); + if (!syscon) + return -ENOMEM; + + /* check if syscon entry already exists */ + mutex_lock(&syscon_list_lock); + + list_for_each_entry(entry, &syscon_list, list) + if (entry->np == np) { + ret = -EEXIST; + goto err_unlock; + } + + syscon->regmap = regmap; + syscon->np = np; + + /* register the regmap in syscon list */ + list_add_tail(&syscon->list, &syscon_list); + mutex_unlock(&syscon_list_lock); + + return 0; + +err_unlock: + mutex_unlock(&syscon_list_lock); + kfree(syscon); + return ret; +} +EXPORT_SYMBOL_GPL(of_syscon_register_regmap); + +/** + * device_node_to_regmap() - Get or create a regmap for specified device node + * @np: Device tree node + * + * Get a regmap for the specified device node. If there's not an existing + * regmap, then one is instantiated. This function should not be used if the + * device node has a custom regmap driver or has resources (clocks, resets) to + * be managed. Use syscon_node_to_regmap() instead for those cases. + * + * Return: regmap ptr on success, negative error code on failure. + */ struct regmap *device_node_to_regmap(struct device_node *np) { - return device_node_get_regmap(np, false); + return device_node_get_regmap(np, true, false); } EXPORT_SYMBOL_GPL(device_node_to_regmap); +/** + * syscon_node_to_regmap() - Get or create a regmap for specified syscon device node + * @np: Device tree node + * + * Get a regmap for the specified device node. If there's not an existing + * regmap, then one is instantiated if the node is a generic "syscon". This + * function is safe to use for a syscon registered with + * of_syscon_register_regmap(). + * + * Return: regmap ptr on success, negative error code on failure. + */ struct regmap *syscon_node_to_regmap(struct device_node *np) { - if (!of_device_is_compatible(np, "syscon")) - return ERR_PTR(-EINVAL); - - return device_node_get_regmap(np, true); + return device_node_get_regmap(np, of_device_is_compatible(np, "syscon"), true); } EXPORT_SYMBOL_GPL(syscon_node_to_regmap); @@ -238,7 +306,9 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, return ERR_PTR(-ENODEV); regmap = syscon_node_to_regmap(syscon_np); - of_node_put(syscon_np); + + if (property) + of_node_put(syscon_np); return regmap; } @@ -290,59 +360,3 @@ struct regmap *syscon_regmap_lookup_by_phandle_optional(struct device_node *np, return regmap; } EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle_optional); - -static int syscon_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct syscon_platform_data *pdata = dev_get_platdata(dev); - struct syscon *syscon; - struct regmap_config syscon_config = syscon_regmap_config; - struct resource *res; - void __iomem *base; - - syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); - if (!syscon) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOENT; - - base = devm_ioremap(dev, res->start, resource_size(res)); - if (!base) - return -ENOMEM; - - syscon_config.max_register = resource_size(res) - 4; - if (pdata) - syscon_config.name = pdata->label; - syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_config); - if (IS_ERR(syscon->regmap)) { - dev_err(dev, "regmap init failed\n"); - return PTR_ERR(syscon->regmap); - } - - platform_set_drvdata(pdev, syscon); - - dev_dbg(dev, "regmap %pR registered\n", res); - - return 0; -} - -static const struct platform_device_id syscon_ids[] = { - { "syscon", }, - { } -}; - -static struct platform_driver syscon_driver = { - .driver = { - .name = "syscon", - }, - .probe = syscon_probe, - .id_table = syscon_ids, -}; - -static int __init syscon_init(void) -{ - return platform_driver_register(&syscon_driver); -} -postcore_initcall(syscon_init); diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index db28eb0c8995..2d4eb771e230 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -234,9 +234,9 @@ static const struct irq_domain_ops tc3589x_irq_ops = { static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np) { - tc3589x->domain = irq_domain_add_simple( - np, TC3589x_NR_INTERNAL_IRQS, 0, - &tc3589x_irq_ops, tc3589x); + tc3589x->domain = irq_domain_create_simple(of_fwnode_handle(np), + TC3589x_NR_INTERNAL_IRQS, 0, + &tc3589x_irq_ops, tc3589x); if (!tc3589x->domain) { dev_err(tc3589x->dev, "Failed to create irqdomain\n"); @@ -312,8 +312,6 @@ static int tc3589x_device_init(struct tc3589x *tc3589x) } static const struct of_device_id tc3589x_match[] = { - /* Legacy compatible string */ - { .compatible = "tc3589x", .data = (void *) TC3589X_UNKNOWN }, { .compatible = "toshiba,tc35890", .data = (void *) TC3589X_TC35890 }, { .compatible = "toshiba,tc35892", .data = (void *) TC3589X_TC35892 }, { .compatible = "toshiba,tc35893", .data = (void *) TC3589X_TC35893 }, diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 4bbd542d753e..068c25401c6c 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -119,8 +119,6 @@ static int ti_tscadc_probe(struct platform_device *pdev) struct clk *clk; struct device_node *node; struct mfd_cell *cell; - struct property *prop; - const __be32 *cur; bool use_tsc = false, use_mag = false; u32 val; int err; @@ -167,7 +165,7 @@ static int ti_tscadc_probe(struct platform_device *pdev) } node = of_get_child_by_name(pdev->dev.of_node, "adc"); - of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { + of_property_for_each_u32(node, "ti,adc-channels", val) { adc_channels++; if (val > 7) { dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n", @@ -379,7 +377,7 @@ static struct platform_driver ti_tscadc_driver = { .of_match_table = ti_tscadc_dt_ids, }, .probe = ti_tscadc_probe, - .remove_new = ti_tscadc_remove, + .remove = ti_tscadc_remove, }; diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 07e5aa10a146..b059713db875 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/mfd/core.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/timb_gpio.h> @@ -25,7 +26,6 @@ #include <linux/spi/max7301.h> #include <linux/spi/mc33880.h> -#include <linux/platform_data/tsc2007.h> #include <linux/platform_data/media/timb_radio.h> #include <linux/platform_data/media/timb_video.h> @@ -49,16 +49,21 @@ struct timberdale_device { /*--------------------------------------------------------------------------*/ -static struct tsc2007_platform_data timberdale_tsc2007_platform_data = { - .model = 2003, - .x_plate_ohms = 100 +static const struct property_entry timberdale_tsc2007_properties[] = { + PROPERTY_ENTRY_U32("ti,x-plate-ohms", 100), + { } +}; + +static const struct software_node timberdale_tsc2007_node = { + .name = "tsc2007", + .properties = timberdale_tsc2007_properties, }; static struct i2c_board_info timberdale_i2c_board_info[] = { { I2C_BOARD_INFO("tsc2007", 0x48), - .platform_data = &timberdale_tsc2007_platform_data, - .irq = IRQ_TIMBERDALE_TSC_INT + .irq = IRQ_TIMBERDALE_TSC_INT, + .swnode = &timberdale_tsc2007_node, }, }; @@ -765,7 +770,6 @@ static int timb_probe(struct pci_dev *dev, default: dev_err(&dev->dev, "Unknown IP setup: %d.%d.%d\n", priv->fw.major, priv->fw.minor, ip_setup); - err = -ENODEV; goto err_mfd; } @@ -854,4 +858,5 @@ module_pci_driver(timberdale_pci_driver); MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); MODULE_VERSION(DRV_VERSION); +MODULE_DESCRIPTION("Timberdale FPGA MFD driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index 5601f6d0d874..e2f6858d101e 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -23,7 +23,7 @@ #include <linux/mfd/core.h> #include <linux/mfd/tps6105x.h> -static struct regmap_config tps6105x_regmap_config = { +static const struct regmap_config tps6105x_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = TPS6105X_REG_3, @@ -191,8 +191,8 @@ static void tps6105x_remove(struct i2c_client *client) } static const struct i2c_device_id tps6105x_id[] = { - { "tps61050", 0 }, - { "tps61052", 0 }, + { "tps61050" }, + { "tps61052" }, { } }; MODULE_DEVICE_TABLE(i2c, tps6105x_id); diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 2b9105295f30..03bd5cd66798 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -16,6 +16,7 @@ #include <linux/workqueue.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <linux/string_choices.h> #include <linux/mutex.h> #include <linux/platform_device.h> @@ -250,7 +251,7 @@ static int dbg_show(struct seq_file *s, void *_) v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED1_PER); seq_printf(s, "led1 %s, on=%02x, per=%02x, %d/%d msec\n", (value & 0x80) - ? ((v2 & 0x80) ? "on" : "off") + ? str_on_off(v2 & 0x80) : ((v2 & 0x80) ? "blink" : "(nPG)"), value, v2, (value & 0x7f) * 10, (v2 & 0x7f) * 100); @@ -259,7 +260,7 @@ static int dbg_show(struct seq_file *s, void *_) v2 = i2c_smbus_read_byte_data(tps->client, TPS_LED2_PER); seq_printf(s, "led2 %s, on=%02x, per=%02x, %d/%d msec\n", (value & 0x80) - ? ((v2 & 0x80) ? "on" : "off") + ? str_on_off(v2 & 0x80) : ((v2 & 0x80) ? "blink" : "off"), value, v2, (value & 0x7f) * 10, (v2 & 0x7f) * 100); @@ -445,7 +446,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) * offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes) * offset 6 == vibrator motor driver */ -static void +static int tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { if (offset < 4) @@ -454,6 +455,8 @@ tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value) tps65010_set_led(offset - 3, value ? ON : OFF); else tps65010_set_vib(value); + + return 0; } static int @@ -511,7 +514,6 @@ static void tps65010_remove(struct i2c_client *client) if (client->irq > 0) free_irq(client->irq, tps); cancel_delayed_work_sync(&tps->work); - debugfs_remove(tps->file); the_tps = NULL; } @@ -544,17 +546,13 @@ static int tps65010_probe(struct i2c_client *client) */ if (client->irq > 0) { status = request_irq(client->irq, tps65010_irq, - IRQF_TRIGGER_FALLING, DRIVER_NAME, tps); + IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN, + DRIVER_NAME, tps); if (status < 0) { dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", client->irq, status); return status; } - /* annoying race here, ideally we'd have an option - * to claim the irq now and enable it later. - * FIXME genirq IRQF_NOAUTOEN now solves that ... - */ - disable_irq(client->irq); set_bit(FLAG_IRQ_ENABLE, &tps->flags); } else dev_warn(&client->dev, "IRQ not configured!\n"); @@ -611,7 +609,7 @@ static int tps65010_probe(struct i2c_client *client) tps65010_work(&tps->work.work); - tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL, + tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, client->debugfs, tps, DEBUG_FOPS); /* optionally register GPIOs */ @@ -622,7 +620,7 @@ static int tps65010_probe(struct i2c_client *client) tps->chip.parent = &client->dev; tps->chip.owner = THIS_MODULE; - tps->chip.set = tps65010_gpio_set; + tps->chip.set_rv = tps65010_gpio_set; tps->chip.direction_output = tps65010_output; /* NOTE: only partial support for inputs; nyet IRQs */ @@ -742,7 +740,7 @@ int tps65010_set_gpio_out_value(unsigned gpio, unsigned value) TPS_DEFGPIO, defgpio); pr_debug("%s: gpio%dout = %s, defgpio 0x%02x\n", DRIVER_NAME, - gpio, value ? "high" : "low", + gpio, str_high_low(value), i2c_smbus_read_byte_data(the_tps->client, TPS_DEFGPIO)); mutex_unlock(&the_tps->lock); @@ -854,7 +852,7 @@ int tps65010_set_vib(unsigned value) status = i2c_smbus_write_byte_data(the_tps->client, TPS_VDCDC2, vdcdc2); - pr_debug("%s: vibrator %s\n", DRIVER_NAME, value ? "on" : "off"); + pr_debug("%s: vibrator %s\n", DRIVER_NAME, str_on_off(value)); mutex_unlock(&the_tps->lock); return status; @@ -876,7 +874,7 @@ int tps65010_set_low_pwr(unsigned mode) mutex_lock(&the_tps->lock); pr_debug("%s: %s low_pwr, vdcdc1 0x%02x\n", DRIVER_NAME, - mode ? "enable" : "disable", + str_enable_disable(mode), i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); vdcdc1 = i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1); @@ -988,7 +986,7 @@ int tps65013_set_low_pwr(unsigned mode) pr_debug("%s: %s low_pwr, chgconfig 0x%02x vdcdc1 0x%02x\n", DRIVER_NAME, - mode ? "enable" : "disable", + str_enable_disable(mode), i2c_smbus_read_byte_data(the_tps->client, TPS_CHGCONFIG), i2c_smbus_read_byte_data(the_tps->client, TPS_VDCDC1)); diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 95dafb0e9f00..9865512dc7cc 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c @@ -103,7 +103,7 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id tps6507x_i2c_id[] = { - { "tps6507x", 0 }, + { "tps6507x" }, { } }; MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id); diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c index fdce81b33f60..54832e9321b9 100644 --- a/drivers/mfd/tps65086.c +++ b/drivers/mfd/tps65086.c @@ -45,7 +45,7 @@ static const struct regmap_irq tps65086_irqs[] = { REGMAP_IRQ_REG(TPS65086_IRQ_FAULT, 0, TPS65086_IRQ_FAULT_MASK), }; -static struct regmap_irq_chip tps65086_irq_chip = { +static const struct regmap_irq_chip tps65086_irq_chip = { .name = "tps65086", .status_base = TPS65086_IRQ, .mask_base = TPS65086_IRQ_MASK, @@ -127,7 +127,7 @@ static void tps65086_remove(struct i2c_client *client) } static const struct i2c_device_id tps65086_id_table[] = { - { "tps65086", 0 }, + { "tps65086" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, tps65086_id_table); diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index b764badaa62a..24f42175a9b4 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -120,7 +120,7 @@ static const struct regmap_irq tps65090_irqs[] = { }, }; -static struct regmap_irq_chip tps65090_irq_chip = { +static const struct regmap_irq_chip tps65090_irq_chip = { .name = "tps65090", .irqs = tps65090_irqs, .num_irqs = ARRAY_SIZE(tps65090_irqs), @@ -225,8 +225,8 @@ err_irq_exit: static const struct i2c_device_id tps65090_id_table[] = { - { "tps65090", 0 }, - { }, + { "tps65090" }, + { } }; static struct i2c_driver tps65090_driver = { diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 029ecc32f078..4e9669d327b4 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -158,7 +158,7 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq) tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK, TPS65217_INT_MASK, TPS65217_PROTECT_NONE); - tps->irq_domain = irq_domain_add_linear(tps->dev->of_node, + tps->irq_domain = irq_domain_create_linear(of_fwnode_handle(tps->dev->of_node), TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps); if (!tps->irq_domain) { dev_err(tps->dev, "Could not create IRQ domain\n"); diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 427a2b97f117..4f3e632f726f 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -186,7 +186,7 @@ static const struct regmap_irq tps65218_irqs[] = { }, }; -static struct regmap_irq_chip tps65218_irq_chip = { +static const struct regmap_irq_chip tps65218_irq_chip = { .name = "tps65218", .irqs = tps65218_irqs, .num_irqs = ARRAY_SIZE(tps65218_irqs), diff --git a/drivers/mfd/tps65219.c b/drivers/mfd/tps65219.c index 0e0c42e4fdfc..fd390600fbf0 100644 --- a/drivers/mfd/tps65219.c +++ b/drivers/mfd/tps65219.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 // -// Driver for TPS65219 Integrated Power Management Integrated Chips (PMIC) +// Driver for TPS65214/TPS65215/TPS65219 Power Management Integrated Chips // // Copyright (C) 2022 BayLibre Incorporated - https://www.baylibre.com/ +// Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ #include <linux/i2c.h> #include <linux/reboot.h> @@ -59,6 +60,84 @@ static const struct resource tps65219_pwrbutton_resources[] = { DEFINE_RES_IRQ_NAMED(TPS65219_INT_PB_RISING_EDGE_DETECT, "rising"), }; +static const struct resource tps65214_regulator_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_SCG, "LDO1_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_OC, "LDO1_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_UV, "LDO1_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_SCG, "LDO2_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_OC, "LDO2_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_UV, "LDO2_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_SCG, "BUCK3_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_OC, "BUCK3_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_NEG_OC, "BUCK3_NEG_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_UV, "BUCK3_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_SCG, "BUCK1_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_OC, "BUCK1_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_NEG_OC, "BUCK1_NEG_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_UV, "BUCK1_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_SCG, "BUCK2_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_OC, "BUCK2_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_NEG_OC, "BUCK2_NEG_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_UV, "BUCK2_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_RV, "BUCK1_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_RV, "BUCK2_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_RV, "BUCK3_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_RV, "LDO1_RV"), + DEFINE_RES_IRQ_NAMED(TPS65214_INT_LDO2_RV, "LDO2_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_RV_SD, "BUCK1_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_RV_SD, "BUCK2_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_RV_SD, "BUCK3_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65214_INT_LDO1_RV_SD, "LDO1_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO2_RV_SD, "LDO2_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_TIMEOUT, "TIMEOUT"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_2_WARM, "SENSOR_2_WARM"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_1_WARM, "SENSOR_1_WARM"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_0_WARM, "SENSOR_0_WARM"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_2_HOT, "SENSOR_2_HOT"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_1_HOT, "SENSOR_1_HOT"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_0_HOT, "SENSOR_0_HOT"), +}; + +static const struct resource tps65215_regulator_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO1_SCG, "LDO1_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO1_OC, "LDO1_OC"), + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO1_UV, "LDO1_UV"), + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO2_SCG, "LDO2_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO2_OC, "LDO2_OC"), + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO2_UV, "LDO2_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_SCG, "BUCK3_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_OC, "BUCK3_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_NEG_OC, "BUCK3_NEG_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_UV, "BUCK3_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_SCG, "BUCK1_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_OC, "BUCK1_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_NEG_OC, "BUCK1_NEG_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_UV, "BUCK1_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_SCG, "BUCK2_SCG"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_OC, "BUCK2_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_NEG_OC, "BUCK2_NEG_OC"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_UV, "BUCK2_UV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_RV, "BUCK1_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_RV, "BUCK2_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_RV, "BUCK3_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_RV, "LDO1_RV"), + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO2_RV, "LDO2_RV"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK1_RV_SD, "BUCK1_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK2_RV_SD, "BUCK2_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_BUCK3_RV_SD, "BUCK3_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO1_RV_SD, "LDO1_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65215_INT_LDO2_RV_SD, "LDO2_RV_SD"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_TIMEOUT, "TIMEOUT"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_3_WARM, "SENSOR_3_WARM"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_2_WARM, "SENSOR_2_WARM"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_1_WARM, "SENSOR_1_WARM"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_0_WARM, "SENSOR_0_WARM"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_3_HOT, "SENSOR_3_HOT"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_2_HOT, "SENSOR_2_HOT"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_1_HOT, "SENSOR_1_HOT"), + DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_0_HOT, "SENSOR_0_HOT"), +}; + static const struct resource tps65219_regulator_resources[] = { DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO3_SCG, "LDO3_SCG"), DEFINE_RES_IRQ_NAMED(TPS65219_INT_LDO3_OC, "LDO3_OC"), @@ -109,21 +188,24 @@ static const struct resource tps65219_regulator_resources[] = { DEFINE_RES_IRQ_NAMED(TPS65219_INT_SENSOR_0_HOT, "SENSOR_0_HOT"), }; -static const struct mfd_cell tps65219_cells[] = { - { - .name = "tps65219-regulator", - .resources = tps65219_regulator_resources, - .num_resources = ARRAY_SIZE(tps65219_regulator_resources), - }, - { .name = "tps65219-gpio", }, +static const struct mfd_cell tps65214_cells[] = { + MFD_CELL_RES("tps65214-regulator", tps65214_regulator_resources), + MFD_CELL_NAME("tps65215-gpio"), }; -static const struct mfd_cell tps65219_pwrbutton_cell = { - .name = "tps65219-pwrbutton", - .resources = tps65219_pwrbutton_resources, - .num_resources = ARRAY_SIZE(tps65219_pwrbutton_resources), +static const struct mfd_cell tps65215_cells[] = { + MFD_CELL_RES("tps65215-regulator", tps65215_regulator_resources), + MFD_CELL_NAME("tps65215-gpio"), }; +static const struct mfd_cell tps65219_cells[] = { + MFD_CELL_RES("tps65219-regulator", tps65219_regulator_resources), + MFD_CELL_NAME("tps65219-gpio"), +}; + +static const struct mfd_cell tps65219_pwrbutton_cell = + MFD_CELL_RES("tps65219-pwrbutton", tps65219_pwrbutton_resources); + static const struct regmap_config tps65219_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -143,8 +225,19 @@ static unsigned int bit3_offsets[] = { TPS65219_REG_INT_BUCK_1_2_POS }; /* Buck static unsigned int bit4_offsets[] = { TPS65219_REG_INT_BUCK_3_POS }; /* Buck 3 */ static unsigned int bit5_offsets[] = { TPS65219_REG_INT_LDO_1_2_POS }; /* LDO 1-2 */ static unsigned int bit6_offsets[] = { TPS65219_REG_INT_LDO_3_4_POS }; /* LDO 3-4 */ +static unsigned int tps65215_bit5_offsets[] = { TPS65215_REG_INT_LDO_1_POS }; +static unsigned int tps65215_bit6_offsets[] = { TPS65215_REG_INT_LDO_2_POS }; static unsigned int bit7_offsets[] = { TPS65219_REG_INT_PB_POS }; /* Power Button */ +/* TPS65214 INT_SOURCE bit 6 is 'RESERVED'*/ +static unsigned int tps65214_bit0_offsets[] = { TPS65214_REG_INT_TO_RV_POS }; +static unsigned int tps65214_bit1_offsets[] = { TPS65214_REG_INT_RV_POS }; +static unsigned int tps65214_bit2_offsets[] = { TPS65214_REG_INT_SYS_POS }; +static unsigned int tps65214_bit3_offsets[] = { TPS65214_REG_INT_BUCK_1_2_POS }; +static unsigned int tps65214_bit4_offsets[] = { TPS65214_REG_INT_BUCK_3_POS }; +static unsigned int tps65214_bit5_offsets[] = { TPS65214_REG_INT_LDO_1_2_POS }; +static unsigned int tps65214_bit7_offsets[] = { TPS65214_REG_INT_PB_POS }; + static struct regmap_irq_sub_irq_map tps65219_sub_irq_offsets[] = { REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), @@ -156,10 +249,113 @@ static struct regmap_irq_sub_irq_map tps65219_sub_irq_offsets[] = { REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), }; +static struct regmap_irq_sub_irq_map tps65215_sub_irq_offsets[] = { + REGMAP_IRQ_MAIN_REG_OFFSET(bit0_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit1_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit2_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit3_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit4_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65215_bit5_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65215_bit6_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(bit7_offsets), +}; + +static struct regmap_irq_sub_irq_map tps65214_sub_irq_offsets[] = { + REGMAP_IRQ_MAIN_REG_OFFSET(tps65214_bit0_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65214_bit1_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65214_bit2_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65214_bit3_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65214_bit4_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65214_bit5_offsets), + REGMAP_IRQ_MAIN_REG_OFFSET(tps65214_bit7_offsets), +}; + #define TPS65219_REGMAP_IRQ_REG(int_name, register_position) \ REGMAP_IRQ_REG(int_name, register_position, int_name##_MASK) -static struct regmap_irq tps65219_irqs[] = { +static const struct regmap_irq tps65214_irqs[] = { + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_SCG, TPS65214_REG_INT_LDO_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_OC, TPS65214_REG_INT_LDO_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_UV, TPS65214_REG_INT_LDO_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_SCG, TPS65214_REG_INT_LDO_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_OC, TPS65214_REG_INT_LDO_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_UV, TPS65214_REG_INT_LDO_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_SCG, TPS65214_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_OC, TPS65214_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_NEG_OC, TPS65214_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_UV, TPS65214_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_SCG, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_OC, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_NEG_OC, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_UV, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_SCG, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_OC, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_NEG_OC, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_UV, TPS65214_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_2_WARM, TPS65214_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_1_WARM, TPS65214_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_0_WARM, TPS65214_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_2_HOT, TPS65214_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_1_HOT, TPS65214_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_0_HOT, TPS65214_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_RV, TPS65214_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_RV, TPS65214_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_RV, TPS65214_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_RV, TPS65214_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65214_INT_LDO2_RV, TPS65214_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_RV_SD, TPS65214_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_RV_SD, TPS65214_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_RV_SD, TPS65214_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65214_INT_LDO1_RV_SD, TPS65214_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO2_RV_SD, TPS65214_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_TIMEOUT, TPS65214_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_PB_FALLING_EDGE_DETECT, TPS65214_REG_INT_PB_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_PB_RISING_EDGE_DETECT, TPS65214_REG_INT_PB_POS), +}; + +static const struct regmap_irq tps65215_irqs[] = { + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO1_SCG, TPS65215_REG_INT_LDO_1_POS), + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO1_OC, TPS65215_REG_INT_LDO_1_POS), + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO1_UV, TPS65215_REG_INT_LDO_1_POS), + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO2_SCG, TPS65215_REG_INT_LDO_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO2_OC, TPS65215_REG_INT_LDO_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO2_UV, TPS65215_REG_INT_LDO_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_SCG, TPS65219_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_OC, TPS65219_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_NEG_OC, TPS65219_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_UV, TPS65219_REG_INT_BUCK_3_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_SCG, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_OC, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_NEG_OC, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_UV, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_SCG, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_OC, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_NEG_OC, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_UV, TPS65219_REG_INT_BUCK_1_2_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_3_WARM, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_2_WARM, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_1_WARM, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_0_WARM, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_3_HOT, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_2_HOT, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_1_HOT, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_SENSOR_0_HOT, TPS65219_REG_INT_SYS_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_RV, TPS65219_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_RV, TPS65219_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_RV, TPS65219_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_RV, TPS65219_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO2_RV, TPS65219_REG_INT_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK1_RV_SD, TPS65219_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK2_RV_SD, TPS65219_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_BUCK3_RV_SD, TPS65219_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO1_RV_SD, TPS65219_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65215_INT_LDO2_RV_SD, TPS65219_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_TIMEOUT, TPS65219_REG_INT_TO_RV_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_PB_FALLING_EDGE_DETECT, TPS65219_REG_INT_PB_POS), + TPS65219_REGMAP_IRQ_REG(TPS65219_INT_PB_RISING_EDGE_DETECT, TPS65219_REG_INT_PB_POS), +}; + +static const struct regmap_irq tps65219_irqs[] = { TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_SCG, TPS65219_REG_INT_LDO_3_4_POS), TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_OC, TPS65219_REG_INT_LDO_3_4_POS), TPS65219_REGMAP_IRQ_REG(TPS65219_INT_LDO3_UV, TPS65219_REG_INT_LDO_3_4_POS), @@ -211,7 +407,35 @@ static struct regmap_irq tps65219_irqs[] = { TPS65219_REGMAP_IRQ_REG(TPS65219_INT_PB_RISING_EDGE_DETECT, TPS65219_REG_INT_PB_POS), }; -static struct regmap_irq_chip tps65219_irq_chip = { +static const struct regmap_irq_chip tps65214_irq_chip = { + .name = "tps65214_irq", + .main_status = TPS65219_REG_INT_SOURCE, + .num_main_regs = 1, + .num_main_status_bits = 8, + .irqs = tps65214_irqs, + .num_irqs = ARRAY_SIZE(tps65214_irqs), + .status_base = TPS65214_REG_INT_LDO_1_2, + .ack_base = TPS65214_REG_INT_LDO_1_2, + .clear_ack = 1, + .num_regs = 8, + .sub_reg_offsets = tps65214_sub_irq_offsets, +}; + +static const struct regmap_irq_chip tps65215_irq_chip = { + .name = "tps65215_irq", + .main_status = TPS65219_REG_INT_SOURCE, + .num_main_regs = 1, + .num_main_status_bits = 8, + .irqs = tps65215_irqs, + .num_irqs = ARRAY_SIZE(tps65215_irqs), + .status_base = TPS65215_REG_INT_LDO_2, + .ack_base = TPS65215_REG_INT_LDO_2, + .clear_ack = 1, + .num_regs = 8, + .sub_reg_offsets = tps65215_sub_irq_offsets, +}; + +static const struct regmap_irq_chip tps65219_irq_chip = { .name = "tps65219_irq", .main_status = TPS65219_REG_INT_SOURCE, .num_main_regs = 1, @@ -225,10 +449,34 @@ static struct regmap_irq_chip tps65219_irq_chip = { .sub_reg_offsets = tps65219_sub_irq_offsets, }; +struct tps65219_chip_data { + const struct regmap_irq_chip *irq_chip; + const struct mfd_cell *cells; + int n_cells; +}; + +static struct tps65219_chip_data chip_info_table[] = { + [TPS65214] = { + .irq_chip = &tps65214_irq_chip, + .cells = tps65214_cells, + .n_cells = ARRAY_SIZE(tps65214_cells), + }, + [TPS65215] = { + .irq_chip = &tps65215_irq_chip, + .cells = tps65215_cells, + .n_cells = ARRAY_SIZE(tps65215_cells), + }, + [TPS65219] = { + .irq_chip = &tps65219_irq_chip, + .cells = tps65219_cells, + .n_cells = ARRAY_SIZE(tps65219_cells), + }, +}; + static int tps65219_probe(struct i2c_client *client) { struct tps65219 *tps; - unsigned int chipid; + struct tps65219_chip_data *pmic; bool pwr_button; int ret; @@ -239,6 +487,8 @@ static int tps65219_probe(struct i2c_client *client) i2c_set_clientdata(client, tps); tps->dev = &client->dev; + tps->chip_id = (uintptr_t)i2c_get_match_data(client); + pmic = &chip_info_table[tps->chip_id]; tps->regmap = devm_regmap_init_i2c(client, &tps65219_regmap_config); if (IS_ERR(tps->regmap)) { @@ -247,20 +497,14 @@ static int tps65219_probe(struct i2c_client *client) return ret; } - ret = devm_regmap_add_irq_chip(&client->dev, tps->regmap, client->irq, - IRQF_ONESHOT, 0, &tps65219_irq_chip, + ret = devm_regmap_add_irq_chip(tps->dev, tps->regmap, client->irq, + IRQF_ONESHOT, 0, pmic->irq_chip, &tps->irq_data); if (ret) return ret; - ret = regmap_read(tps->regmap, TPS65219_REG_TI_DEV_ID, &chipid); - if (ret) { - dev_err(tps->dev, "Failed to read device ID: %d\n", ret); - return ret; - } - ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, - tps65219_cells, ARRAY_SIZE(tps65219_cells), + pmic->cells, pmic->n_cells, NULL, 0, regmap_irq_get_domain(tps->irq_data)); if (ret) { dev_err(tps->dev, "Failed to add child devices: %d\n", ret); @@ -298,7 +542,9 @@ static int tps65219_probe(struct i2c_client *client) } static const struct of_device_id of_tps65219_match_table[] = { - { .compatible = "ti,tps65219", }, + { .compatible = "ti,tps65214", .data = (void *)TPS65214, }, + { .compatible = "ti,tps65215", .data = (void *)TPS65215, }, + { .compatible = "ti,tps65219", .data = (void *)TPS65219, }, {} }; MODULE_DEVICE_TABLE(of, of_tps65219_match_table); @@ -313,5 +559,5 @@ static struct i2c_driver tps65219_driver = { module_i2c_driver(tps65219_driver); MODULE_AUTHOR("Jerome Neanne <jneanne@baylibre.com>"); -MODULE_DESCRIPTION("TPS65219 power management IC driver"); +MODULE_DESCRIPTION("TPS65214/TPS65215/TPS65219 PMIC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 03c65bbf2143..853c48286071 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -363,7 +363,7 @@ static int tps6586x_irq_init(struct tps6586x *tps6586x, int irq, new_irq_base = 0; } - tps6586x->irq_domain = irq_domain_add_simple(tps6586x->dev->of_node, + tps6586x->irq_domain = irq_domain_create_simple(of_fwnode_handle(tps6586x->dev->of_node), irq_num, new_irq_base, &tps6586x_domain_ops, tps6586x); if (!tps6586x->irq_domain) { @@ -642,8 +642,8 @@ static SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_i2c_suspend, tps6586x_i2c_resume); static const struct i2c_device_id tps6586x_id_table[] = { - { "tps6586x", 0 }, - { }, + { "tps6586x" }, + { } }; MODULE_DEVICE_TABLE(i2c, tps6586x_id_table); diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 8fb0384d5a8e..6a7b7a697fb7 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -197,7 +197,7 @@ static const struct regmap_irq tps65910_irqs[] = { }, }; -static struct regmap_irq_chip tps65911_irq_chip = { +static const struct regmap_irq_chip tps65911_irq_chip = { .name = "tps65910", .irqs = tps65911_irqs, .num_irqs = ARRAY_SIZE(tps65911_irqs), @@ -208,7 +208,7 @@ static struct regmap_irq_chip tps65911_irq_chip = { .ack_base = TPS65910_INT_STS, }; -static struct regmap_irq_chip tps65910_irq_chip = { +static const struct regmap_irq_chip tps65910_irq_chip = { .name = "tps65910", .irqs = tps65910_irqs, .num_irqs = ARRAY_SIZE(tps65910_irqs), @@ -223,7 +223,7 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq, struct tps65910_platform_data *pdata) { int ret; - static struct regmap_irq_chip *tps6591x_irqs_chip; + static const struct regmap_irq_chip *tps6591x_irqs_chip; if (!irq) { dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c index f206a9c50e9d..7098712ea008 100644 --- a/drivers/mfd/tps65911-comparator.c +++ b/drivers/mfd/tps65911-comparator.c @@ -154,7 +154,7 @@ static struct platform_driver tps65911_comparator_driver = { .name = "tps65911-comparator", }, .probe = tps65911_comparator_probe, - .remove_new = tps65911_comparator_remove, + .remove = tps65911_comparator_remove, }; static int __init tps65911_comparator_init(void) diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index 2305ea60367a..a9dcd7f0d9e3 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -57,7 +57,7 @@ static const struct regmap_irq tps65912_irqs[] = { REGMAP_IRQ_REG(TPS65912_IRQ_PGOOD_LDO10, 3, TPS65912_INT_STS4_PGOOD_LDO10), }; -static struct regmap_irq_chip tps65912_irq_chip = { +static const struct regmap_irq_chip tps65912_irq_chip = { .name = "tps65912", .irqs = tps65912_irqs, .num_irqs = ARRAY_SIZE(tps65912_irqs), @@ -90,29 +90,22 @@ int tps65912_device_init(struct tps65912 *tps) { int ret; - ret = regmap_add_irq_chip(tps->regmap, tps->irq, IRQF_ONESHOT, 0, - &tps65912_irq_chip, &tps->irq_data); + ret = devm_regmap_add_irq_chip(tps->dev, tps->regmap, tps->irq, + IRQF_ONESHOT, 0, &tps65912_irq_chip, + &tps->irq_data); if (ret) return ret; - ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65912_cells, - ARRAY_SIZE(tps65912_cells), NULL, 0, - regmap_irq_get_domain(tps->irq_data)); - if (ret) { - regmap_del_irq_chip(tps->irq, tps->irq_data); + ret = devm_mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65912_cells, + ARRAY_SIZE(tps65912_cells), NULL, 0, + regmap_irq_get_domain(tps->irq_data)); + if (ret) return ret; - } return 0; } EXPORT_SYMBOL_GPL(tps65912_device_init); -void tps65912_device_exit(struct tps65912 *tps) -{ - regmap_del_irq_chip(tps->irq, tps->irq_data); -} -EXPORT_SYMBOL_GPL(tps65912_device_exit); - MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); MODULE_DESCRIPTION("TPS65912x MFD Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index 3c5ac781b6c1..138e50497b51 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -42,15 +42,8 @@ static int tps65912_i2c_probe(struct i2c_client *client) return tps65912_device_init(tps); } -static void tps65912_i2c_remove(struct i2c_client *client) -{ - struct tps65912 *tps = i2c_get_clientdata(client); - - tps65912_device_exit(tps); -} - static const struct i2c_device_id tps65912_i2c_id_table[] = { - { "tps65912", 0 }, + { "tps65912" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, tps65912_i2c_id_table); @@ -61,7 +54,6 @@ static struct i2c_driver tps65912_i2c_driver = { .of_match_table = tps65912_i2c_of_match_table, }, .probe = tps65912_i2c_probe, - .remove = tps65912_i2c_remove, .id_table = tps65912_i2c_id_table, }; module_i2c_driver(tps65912_i2c_driver); diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index 9e976f9c6bbe..2a77dccd6059 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -42,13 +42,6 @@ static int tps65912_spi_probe(struct spi_device *spi) return tps65912_device_init(tps); } -static void tps65912_spi_remove(struct spi_device *spi) -{ - struct tps65912 *tps = spi_get_drvdata(spi); - - tps65912_device_exit(tps); -} - static const struct spi_device_id tps65912_spi_id_table[] = { { "tps65912", 0 }, { /* sentinel */ } @@ -61,7 +54,6 @@ static struct spi_driver tps65912_spi_driver = { .of_match_table = tps65912_spi_of_match_table, }, .probe = tps65912_spi_probe, - .remove = tps65912_spi_remove, .id_table = tps65912_spi_id_table, }; module_spi_driver(tps65912_spi_driver); diff --git a/drivers/mfd/tps6594-core.c b/drivers/mfd/tps6594-core.c index 783ee59901e8..a7223e873cd1 100644 --- a/drivers/mfd/tps6594-core.c +++ b/drivers/mfd/tps6594-core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Core functions for TI TPS6594/TPS6593/LP8764 PMICs + * Core functions for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs * * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ */ @@ -278,16 +278,159 @@ static const unsigned int tps6594_irq_reg[] = { TPS6594_REG_RTC_STATUS, }; +/* TPS65224 Resources */ + +static const struct resource tps65224_regulator_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK1_UVOV, TPS65224_IRQ_NAME_BUCK1_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK2_UVOV, TPS65224_IRQ_NAME_BUCK2_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK3_UVOV, TPS65224_IRQ_NAME_BUCK3_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BUCK4_UVOV, TPS65224_IRQ_NAME_BUCK4_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_LDO1_UVOV, TPS65224_IRQ_NAME_LDO1_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_LDO2_UVOV, TPS65224_IRQ_NAME_LDO2_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_LDO3_UVOV, TPS65224_IRQ_NAME_LDO3_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VCCA_UVOV, TPS65224_IRQ_NAME_VCCA_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VMON1_UVOV, TPS65224_IRQ_NAME_VMON1_UVOV), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VMON2_UVOV, TPS65224_IRQ_NAME_VMON2_UVOV), +}; + +static const struct resource tps65224_pinctrl_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO1, TPS65224_IRQ_NAME_GPIO1), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO2, TPS65224_IRQ_NAME_GPIO2), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO3, TPS65224_IRQ_NAME_GPIO3), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO4, TPS65224_IRQ_NAME_GPIO4), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO5, TPS65224_IRQ_NAME_GPIO5), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_GPIO6, TPS65224_IRQ_NAME_GPIO6), +}; + +static const struct resource tps65224_pfsm_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VSENSE, TPS65224_IRQ_NAME_VSENSE), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_ENABLE, TPS65224_IRQ_NAME_ENABLE), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_SHORT, TPS65224_IRQ_NAME_PB_SHORT), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_FSD, TPS65224_IRQ_NAME_FSD), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_SOFT_REBOOT, TPS65224_IRQ_NAME_SOFT_REBOOT), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BIST_PASS, TPS65224_IRQ_NAME_BIST_PASS), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_EXT_CLK, TPS65224_IRQ_NAME_EXT_CLK), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_UNLOCK, TPS65224_IRQ_NAME_REG_UNLOCK), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TWARN, TPS65224_IRQ_NAME_TWARN), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_LONG, TPS65224_IRQ_NAME_PB_LONG), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_FALL, TPS65224_IRQ_NAME_PB_FALL), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PB_RISE, TPS65224_IRQ_NAME_PB_RISE), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TSD_ORD, TPS65224_IRQ_NAME_TSD_ORD), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BIST_FAIL, TPS65224_IRQ_NAME_BIST_FAIL), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_REG_CRC_ERR, TPS65224_IRQ_NAME_REG_CRC_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_RECOV_CNT, TPS65224_IRQ_NAME_RECOV_CNT), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_TSD_IMM, TPS65224_IRQ_NAME_TSD_IMM), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_VCCA_OVP, TPS65224_IRQ_NAME_VCCA_OVP), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_PFSM_ERR, TPS65224_IRQ_NAME_PFSM_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_BG_XMON, TPS65224_IRQ_NAME_BG_XMON), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_IMM_SHUTDOWN, TPS65224_IRQ_NAME_IMM_SHUTDOWN), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_ORD_SHUTDOWN, TPS65224_IRQ_NAME_ORD_SHUTDOWN), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_MCU_PWR_ERR, TPS65224_IRQ_NAME_MCU_PWR_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_SOC_PWR_ERR, TPS65224_IRQ_NAME_SOC_PWR_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_COMM_ERR, TPS65224_IRQ_NAME_COMM_ERR), + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_I2C2_ERR, TPS65224_IRQ_NAME_I2C2_ERR), +}; + +static const struct resource tps65224_adc_resources[] = { + DEFINE_RES_IRQ_NAMED(TPS65224_IRQ_ADC_CONV_READY, TPS65224_IRQ_NAME_ADC_CONV_READY), +}; + +static const struct mfd_cell tps65224_common_cells[] = { + MFD_CELL_RES("tps65224-adc", tps65224_adc_resources), + MFD_CELL_RES("tps6594-pfsm", tps65224_pfsm_resources), + MFD_CELL_RES("tps6594-pinctrl", tps65224_pinctrl_resources), + MFD_CELL_RES("tps6594-regulator", tps65224_regulator_resources), +}; + +static const struct regmap_irq tps65224_irqs[] = { + /* INT_BUCK register */ + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK1_UVOV, 0, TPS65224_BIT_BUCK1_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK2_UVOV, 0, TPS65224_BIT_BUCK2_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK3_UVOV, 0, TPS65224_BIT_BUCK3_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BUCK4_UVOV, 0, TPS65224_BIT_BUCK4_UVOV_INT), + + /* INT_VMON_LDO register */ + REGMAP_IRQ_REG(TPS65224_IRQ_LDO1_UVOV, 1, TPS65224_BIT_LDO1_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_LDO2_UVOV, 1, TPS65224_BIT_LDO2_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_LDO3_UVOV, 1, TPS65224_BIT_LDO3_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VCCA_UVOV, 1, TPS65224_BIT_VCCA_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VMON1_UVOV, 1, TPS65224_BIT_VMON1_UVOV_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VMON2_UVOV, 1, TPS65224_BIT_VMON2_UVOV_INT), + + /* INT_GPIO register */ + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO1, 2, TPS65224_BIT_GPIO1_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO2, 2, TPS65224_BIT_GPIO2_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO3, 2, TPS65224_BIT_GPIO3_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO4, 2, TPS65224_BIT_GPIO4_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO5, 2, TPS65224_BIT_GPIO5_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_GPIO6, 2, TPS65224_BIT_GPIO6_INT), + + /* INT_STARTUP register */ + REGMAP_IRQ_REG(TPS65224_IRQ_VSENSE, 3, TPS65224_BIT_VSENSE_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_ENABLE, 3, TPS6594_BIT_ENABLE_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_SHORT, 3, TPS65224_BIT_PB_SHORT_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_FSD, 3, TPS6594_BIT_FSD_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_SOFT_REBOOT, 3, TPS6594_BIT_SOFT_REBOOT_INT), + + /* INT_MISC register */ + REGMAP_IRQ_REG(TPS65224_IRQ_BIST_PASS, 4, TPS6594_BIT_BIST_PASS_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_EXT_CLK, 4, TPS6594_BIT_EXT_CLK_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_REG_UNLOCK, 4, TPS65224_BIT_REG_UNLOCK_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_TWARN, 4, TPS6594_BIT_TWARN_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_LONG, 4, TPS65224_BIT_PB_LONG_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_FALL, 4, TPS65224_BIT_PB_FALL_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PB_RISE, 4, TPS65224_BIT_PB_RISE_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_ADC_CONV_READY, 4, TPS65224_BIT_ADC_CONV_READY_INT), + + /* INT_MODERATE_ERR register */ + REGMAP_IRQ_REG(TPS65224_IRQ_TSD_ORD, 5, TPS6594_BIT_TSD_ORD_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BIST_FAIL, 5, TPS6594_BIT_BIST_FAIL_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_REG_CRC_ERR, 5, TPS6594_BIT_REG_CRC_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_RECOV_CNT, 5, TPS6594_BIT_RECOV_CNT_INT), + + /* INT_SEVERE_ERR register */ + REGMAP_IRQ_REG(TPS65224_IRQ_TSD_IMM, 6, TPS6594_BIT_TSD_IMM_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_VCCA_OVP, 6, TPS6594_BIT_VCCA_OVP_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_PFSM_ERR, 6, TPS6594_BIT_PFSM_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_BG_XMON, 6, TPS65224_BIT_BG_XMON_INT), + + /* INT_FSM_ERR register */ + REGMAP_IRQ_REG(TPS65224_IRQ_IMM_SHUTDOWN, 7, TPS6594_BIT_IMM_SHUTDOWN_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_ORD_SHUTDOWN, 7, TPS6594_BIT_ORD_SHUTDOWN_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_MCU_PWR_ERR, 7, TPS6594_BIT_MCU_PWR_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_SOC_PWR_ERR, 7, TPS6594_BIT_SOC_PWR_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_COMM_ERR, 7, TPS6594_BIT_COMM_ERR_INT), + REGMAP_IRQ_REG(TPS65224_IRQ_I2C2_ERR, 7, TPS65224_BIT_I2C2_ERR_INT), +}; + +static const unsigned int tps65224_irq_reg[] = { + TPS6594_REG_INT_BUCK, + TPS6594_REG_INT_LDO_VMON, + TPS6594_REG_INT_GPIO, + TPS6594_REG_INT_STARTUP, + TPS6594_REG_INT_MISC, + TPS6594_REG_INT_MODERATE_ERR, + TPS6594_REG_INT_SEVERE_ERR, + TPS6594_REG_INT_FSM_ERR, +}; + static inline unsigned int tps6594_get_irq_reg(struct regmap_irq_chip_data *data, unsigned int base, int index) { return tps6594_irq_reg[index]; }; +static inline unsigned int tps65224_get_irq_reg(struct regmap_irq_chip_data *data, + unsigned int base, int index) +{ + return tps65224_irq_reg[index]; +}; + static int tps6594_handle_post_irq(void *irq_drv_data) { struct tps6594 *tps = irq_drv_data; int ret = 0; + unsigned int regmap_reg, mask_val; /* * When CRC is enabled, writing to a read-only bit triggers an error, @@ -299,10 +442,17 @@ static int tps6594_handle_post_irq(void *irq_drv_data) * COMM_ADR_ERR_INT bit set. Clear immediately this bit to avoid raising * a new interrupt. */ - if (tps->use_crc) - ret = regmap_write_bits(tps->regmap, TPS6594_REG_INT_COMM_ERR, - TPS6594_BIT_COMM_ADR_ERR_INT, - TPS6594_BIT_COMM_ADR_ERR_INT); + if (tps->use_crc) { + if (tps->chip_id == TPS65224) { + regmap_reg = TPS6594_REG_INT_FSM_ERR; + mask_val = TPS6594_BIT_COMM_ERR_INT; + } else { + regmap_reg = TPS6594_REG_INT_COMM_ERR; + mask_val = TPS6594_BIT_COMM_ADR_ERR_INT; + } + + ret = regmap_write_bits(tps->regmap, regmap_reg, mask_val, mask_val); + } return ret; }; @@ -319,24 +469,58 @@ static struct regmap_irq_chip tps6594_irq_chip = { .handle_post_irq = tps6594_handle_post_irq, }; -bool tps6594_is_volatile_reg(struct device *dev, unsigned int reg) -{ - return (reg >= TPS6594_REG_INT_TOP && reg <= TPS6594_REG_STAT_READBACK_ERR) || - reg == TPS6594_REG_RTC_STATUS; -} -EXPORT_SYMBOL_GPL(tps6594_is_volatile_reg); +static struct regmap_irq_chip tps65224_irq_chip = { + .ack_base = TPS6594_REG_INT_BUCK, + .ack_invert = 1, + .clear_ack = 1, + .init_ack_masked = 1, + .num_regs = ARRAY_SIZE(tps65224_irq_reg), + .irqs = tps65224_irqs, + .num_irqs = ARRAY_SIZE(tps65224_irqs), + .get_irq_reg = tps65224_get_irq_reg, + .handle_post_irq = tps6594_handle_post_irq, +}; + +static const struct regmap_range tps6594_volatile_ranges[] = { + regmap_reg_range(TPS6594_REG_INT_TOP, TPS6594_REG_STAT_READBACK_ERR), + regmap_reg_range(TPS6594_REG_RTC_STATUS, TPS6594_REG_RTC_STATUS), +}; + +const struct regmap_access_table tps6594_volatile_table = { + .yes_ranges = tps6594_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(tps6594_volatile_ranges), +}; +EXPORT_SYMBOL_GPL(tps6594_volatile_table); + +static const struct regmap_range tps65224_volatile_ranges[] = { + regmap_reg_range(TPS6594_REG_INT_TOP, TPS6594_REG_STAT_SEVERE_ERR), +}; + +const struct regmap_access_table tps65224_volatile_table = { + .yes_ranges = tps65224_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(tps65224_volatile_ranges), +}; +EXPORT_SYMBOL_GPL(tps65224_volatile_table); static int tps6594_check_crc_mode(struct tps6594 *tps, bool primary_pmic) { int ret; + unsigned int regmap_reg, mask_val; + + if (tps->chip_id == TPS65224) { + regmap_reg = TPS6594_REG_CONFIG_2; + mask_val = TPS65224_BIT_I2C1_SPI_CRC_EN; + } else { + regmap_reg = TPS6594_REG_SERIAL_IF_CONFIG; + mask_val = TPS6594_BIT_I2C1_SPI_CRC_EN; + } /* * Check if CRC is enabled. * Once CRC is enabled, it can't be disabled until next power cycle. */ tps->use_crc = true; - ret = regmap_test_bits(tps->regmap, TPS6594_REG_SERIAL_IF_CONFIG, - TPS6594_BIT_I2C1_SPI_CRC_EN); + ret = regmap_test_bits(tps->regmap, regmap_reg, mask_val); if (ret == 0) { ret = -EIO; } else if (ret > 0) { @@ -351,6 +535,15 @@ static int tps6594_check_crc_mode(struct tps6594 *tps, bool primary_pmic) static int tps6594_set_crc_feature(struct tps6594 *tps) { int ret; + unsigned int regmap_reg, mask_val; + + if (tps->chip_id == TPS65224) { + regmap_reg = TPS6594_REG_CONFIG_2; + mask_val = TPS65224_BIT_I2C1_SPI_CRC_EN; + } else { + regmap_reg = TPS6594_REG_FSM_I2C_TRIGGERS; + mask_val = TPS6594_BIT_TRIGGER_I2C(2); + } ret = tps6594_check_crc_mode(tps, true); if (ret) { @@ -359,8 +552,7 @@ static int tps6594_set_crc_feature(struct tps6594 *tps) * on primary PMIC. */ tps->use_crc = false; - ret = regmap_write_bits(tps->regmap, TPS6594_REG_FSM_I2C_TRIGGERS, - TPS6594_BIT_TRIGGER_I2C(2), TPS6594_BIT_TRIGGER_I2C(2)); + ret = regmap_write_bits(tps->regmap, regmap_reg, mask_val, mask_val); if (ret) return ret; @@ -416,6 +608,9 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) { struct device *dev = tps->dev; int ret; + struct regmap_irq_chip *irq_chip; + const struct mfd_cell *cells; + int n_cells; if (enable_crc) { ret = tps6594_enable_crc(tps); @@ -429,26 +624,35 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) if (ret) return dev_err_probe(dev, ret, "Failed to set PMIC state\n"); - tps6594_irq_chip.irq_drv_data = tps; - tps6594_irq_chip.name = devm_kasprintf(dev, GFP_KERNEL, "%s-%ld-0x%02x", - dev->driver->name, tps->chip_id, tps->reg); + if (tps->chip_id == TPS65224) { + irq_chip = &tps65224_irq_chip; + n_cells = ARRAY_SIZE(tps65224_common_cells); + cells = tps65224_common_cells; + } else { + irq_chip = &tps6594_irq_chip; + n_cells = ARRAY_SIZE(tps6594_common_cells); + cells = tps6594_common_cells; + } + + irq_chip->irq_drv_data = tps; + irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-%ld-0x%02x", + dev->driver->name, tps->chip_id, tps->reg); - if (!tps6594_irq_chip.name) + if (!irq_chip->name) return -ENOMEM; ret = devm_regmap_add_irq_chip(dev, tps->regmap, tps->irq, IRQF_SHARED | IRQF_ONESHOT, - 0, &tps6594_irq_chip, &tps->irq_data); + 0, irq_chip, &tps->irq_data); if (ret) return dev_err_probe(dev, ret, "Failed to add regmap IRQ\n"); - ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, tps6594_common_cells, - ARRAY_SIZE(tps6594_common_cells), NULL, 0, + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, n_cells, NULL, 0, regmap_irq_get_domain(tps->irq_data)); if (ret) return dev_err_probe(dev, ret, "Failed to add common child devices\n"); - /* No RTC for LP8764 */ - if (tps->chip_id != LP8764) { + /* No RTC for LP8764 and TPS65224 */ + if (tps->chip_id != LP8764 && tps->chip_id != TPS65224) { ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, tps6594_rtc_cells, ARRAY_SIZE(tps6594_rtc_cells), NULL, 0, regmap_irq_get_domain(tps->irq_data)); @@ -461,5 +665,6 @@ int tps6594_device_init(struct tps6594 *tps, bool enable_crc) EXPORT_SYMBOL_GPL(tps6594_device_init); MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>"); +MODULE_AUTHOR("Bhargav Raviprakash <bhargav.r@ltts.com"); MODULE_DESCRIPTION("TPS6594 Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tps6594-i2c.c b/drivers/mfd/tps6594-i2c.c index 899c88c0fe77..4ab91c34d9fb 100644 --- a/drivers/mfd/tps6594-i2c.c +++ b/drivers/mfd/tps6594-i2c.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * I2C access driver for TI TPS6594/TPS6593/LP8764 PMICs + * I2C access driver for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs * * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ */ @@ -183,11 +183,11 @@ static int tps6594_i2c_write(void *context, const void *data, size_t count) return ret; } -static const struct regmap_config tps6594_i2c_regmap_config = { +static struct regmap_config tps6594_i2c_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = TPS6594_REG_DWD_FAIL_CNT_REG, - .volatile_reg = tps6594_is_volatile_reg, + .volatile_table = &tps6594_volatile_table, .read = tps6594_i2c_read, .write = tps6594_i2c_write, }; @@ -196,6 +196,7 @@ static const struct of_device_id tps6594_i2c_of_match_table[] = { { .compatible = "ti,tps6594-q1", .data = (void *)TPS6594, }, { .compatible = "ti,tps6593-q1", .data = (void *)TPS6593, }, { .compatible = "ti,lp8764-q1", .data = (void *)LP8764, }, + { .compatible = "ti,tps65224-q1", .data = (void *)TPS65224, }, {} }; MODULE_DEVICE_TABLE(of, tps6594_i2c_of_match_table); @@ -216,15 +217,18 @@ static int tps6594_i2c_probe(struct i2c_client *client) tps->reg = client->addr; tps->irq = client->irq; - tps->regmap = devm_regmap_init(dev, NULL, client, &tps6594_i2c_regmap_config); - if (IS_ERR(tps->regmap)) - return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); - match = of_match_device(tps6594_i2c_of_match_table, dev); if (!match) return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n"); tps->chip_id = (unsigned long)match->data; + if (tps->chip_id == TPS65224) + tps6594_i2c_regmap_config.volatile_table = &tps65224_volatile_table; + + tps->regmap = devm_regmap_init(dev, NULL, client, &tps6594_i2c_regmap_config); + if (IS_ERR(tps->regmap)) + return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); + crc8_populate_msb(tps6594_i2c_crc_table, TPS6594_CRC8_POLYNOMIAL); return tps6594_device_init(tps, enable_crc); @@ -240,5 +244,5 @@ static struct i2c_driver tps6594_i2c_driver = { module_i2c_driver(tps6594_i2c_driver); MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>"); -MODULE_DESCRIPTION("TPS6594 I2C Interface Driver"); +MODULE_DESCRIPTION("I2C Interface Driver for TPS65224, TPS6594/3, and LP8764"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tps6594-spi.c b/drivers/mfd/tps6594-spi.c index 24b72847e3f5..6ebccb79f0cc 100644 --- a/drivers/mfd/tps6594-spi.c +++ b/drivers/mfd/tps6594-spi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * SPI access driver for TI TPS6594/TPS6593/LP8764 PMICs + * SPI access driver for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs * * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/ */ @@ -66,11 +66,11 @@ static int tps6594_spi_reg_write(void *context, unsigned int reg, unsigned int v return spi_write(spi, buf, count); } -static const struct regmap_config tps6594_spi_regmap_config = { +static struct regmap_config tps6594_spi_regmap_config = { .reg_bits = 16, .val_bits = 8, .max_register = TPS6594_REG_DWD_FAIL_CNT_REG, - .volatile_reg = tps6594_is_volatile_reg, + .volatile_table = &tps6594_volatile_table, .reg_read = tps6594_spi_reg_read, .reg_write = tps6594_spi_reg_write, .use_single_read = true, @@ -81,6 +81,7 @@ static const struct of_device_id tps6594_spi_of_match_table[] = { { .compatible = "ti,tps6594-q1", .data = (void *)TPS6594, }, { .compatible = "ti,tps6593-q1", .data = (void *)TPS6593, }, { .compatible = "ti,lp8764-q1", .data = (void *)LP8764, }, + { .compatible = "ti,tps65224-q1", .data = (void *)TPS65224, }, {} }; MODULE_DEVICE_TABLE(of, tps6594_spi_of_match_table); @@ -101,15 +102,18 @@ static int tps6594_spi_probe(struct spi_device *spi) tps->reg = spi_get_chipselect(spi, 0); tps->irq = spi->irq; - tps->regmap = devm_regmap_init(dev, NULL, spi, &tps6594_spi_regmap_config); - if (IS_ERR(tps->regmap)) - return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); - match = of_match_device(tps6594_spi_of_match_table, dev); if (!match) return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n"); tps->chip_id = (unsigned long)match->data; + if (tps->chip_id == TPS65224) + tps6594_spi_regmap_config.volatile_table = &tps65224_volatile_table; + + tps->regmap = devm_regmap_init(dev, NULL, spi, &tps6594_spi_regmap_config); + if (IS_ERR(tps->regmap)) + return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n"); + crc8_populate_msb(tps6594_spi_crc_table, TPS6594_CRC8_POLYNOMIAL); return tps6594_device_init(tps, enable_crc); @@ -125,5 +129,5 @@ static struct spi_driver tps6594_spi_driver = { module_spi_driver(tps6594_spi_driver); MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>"); -MODULE_DESCRIPTION("TPS6594 SPI Interface Driver"); +MODULE_DESCRIPTION("SPI Interface Driver for TPS65224, TPS6594/3, and LP8764"); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/tqmx86.c b/drivers/mfd/tqmx86.c index fac02875fe7d..1cba3b67b0fb 100644 --- a/drivers/mfd/tqmx86.c +++ b/drivers/mfd/tqmx86.c @@ -35,11 +35,14 @@ #define TQMX86_REG_BOARD_ID_E39C2 7 #define TQMX86_REG_BOARD_ID_70EB 8 #define TQMX86_REG_BOARD_ID_80UC 9 +#define TQMX86_REG_BOARD_ID_120UC 10 #define TQMX86_REG_BOARD_ID_110EB 11 #define TQMX86_REG_BOARD_ID_E40M 12 #define TQMX86_REG_BOARD_ID_E40S 13 #define TQMX86_REG_BOARD_ID_E40C1 14 #define TQMX86_REG_BOARD_ID_E40C2 15 +#define TQMX86_REG_BOARD_ID_130UC 16 +#define TQMX86_REG_BOARD_ID_E41S 19 #define TQMX86_REG_BOARD_REV 0x01 #define TQMX86_REG_IO_EXT_INT 0x06 #define TQMX86_REG_IO_EXT_INT_NONE 0 @@ -47,6 +50,7 @@ #define TQMX86_REG_IO_EXT_INT_9 2 #define TQMX86_REG_IO_EXT_INT_12 3 #define TQMX86_REG_IO_EXT_INT_MASK 0x3 +#define TQMX86_REG_IO_EXT_INT_I2C1_SHIFT 0 #define TQMX86_REG_IO_EXT_INT_GPIO_SHIFT 4 #define TQMX86_REG_SAUC 0x17 @@ -55,23 +59,36 @@ static uint gpio_irq; module_param(gpio_irq, uint, 0); -MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (7, 9, 12)"); +MODULE_PARM_DESC(gpio_irq, "GPIO IRQ number (valid parameters: 7, 9, 12)"); -static const struct resource tqmx_i2c_soft_resources[] = { - DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), +static uint i2c1_irq; +module_param(i2c1_irq, uint, 0); +MODULE_PARM_DESC(i2c1_irq, "I2C1 IRQ number (valid parameters: 7, 9, 12)"); + +enum tqmx86_i2c1_resource_type { + TQMX86_I2C1_IO, + TQMX86_I2C1_IRQ, +}; + +static struct resource tqmx_i2c_soft_resources[] = { + [TQMX86_I2C1_IO] = DEFINE_RES_IO(TQMX86_IOBASE_I2C, TQMX86_IOSIZE_I2C), + /* Placeholder for IRQ resource */ + [TQMX86_I2C1_IRQ] = {}, }; static const struct resource tqmx_watchdog_resources[] = { DEFINE_RES_IO(TQMX86_IOBASE_WATCHDOG, TQMX86_IOSIZE_WATCHDOG), }; -/* - * The IRQ resource must be first, since it is updated with the - * configured IRQ in the probe function. - */ +enum tqmx86_gpio_resource_type { + TQMX86_GPIO_IO, + TQMX86_GPIO_IRQ, +}; + static struct resource tqmx_gpio_resources[] = { - DEFINE_RES_IRQ(0), - DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), + [TQMX86_GPIO_IO] = DEFINE_RES_IO(TQMX86_IOBASE_GPIO, TQMX86_IOSIZE_GPIO), + /* Placeholder for IRQ resource */ + [TQMX86_GPIO_IRQ] = {}, }; static struct i2c_board_info tqmx86_i2c_devices[] = { @@ -132,6 +149,8 @@ static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) return "TQMx70EB"; case TQMX86_REG_BOARD_ID_80UC: return "TQMx80UC"; + case TQMX86_REG_BOARD_ID_120UC: + return "TQMx120UC"; case TQMX86_REG_BOARD_ID_110EB: return "TQMx110EB"; case TQMX86_REG_BOARD_ID_E40M: @@ -142,6 +161,10 @@ static const char *tqmx86_board_id_to_name(u8 board_id, u8 sauc) return "TQMxE40C1"; case TQMX86_REG_BOARD_ID_E40C2: return "TQMxE40C2"; + case TQMX86_REG_BOARD_ID_130UC: + return "TQMx130UC"; + case TQMX86_REG_BOARD_ID_E41S: + return "TQMxE41S"; default: return "Unknown"; } @@ -154,11 +177,14 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) case TQMX86_REG_BOARD_ID_60EB: case TQMX86_REG_BOARD_ID_70EB: case TQMX86_REG_BOARD_ID_80UC: + case TQMX86_REG_BOARD_ID_120UC: case TQMX86_REG_BOARD_ID_110EB: case TQMX86_REG_BOARD_ID_E40M: case TQMX86_REG_BOARD_ID_E40S: case TQMX86_REG_BOARD_ID_E40C1: case TQMX86_REG_BOARD_ID_E40C2: + case TQMX86_REG_BOARD_ID_130UC: + case TQMX86_REG_BOARD_ID_E41S: return 24000; case TQMX86_REG_BOARD_ID_E39MS: case TQMX86_REG_BOARD_ID_E39C1: @@ -174,33 +200,52 @@ static int tqmx86_board_id_to_clk_rate(struct device *dev, u8 board_id) } } -static int tqmx86_probe(struct platform_device *pdev) +static int tqmx86_setup_irq(struct device *dev, const char *label, u8 irq, + void __iomem *io_base, u8 reg_shift) { - u8 board_id, sauc, rev, i2c_det, io_ext_int_val; - struct device *dev = &pdev->dev; - u8 gpio_irq_cfg, readback; - const char *board_name; - void __iomem *io_base; - int err; + u8 val, readback; + int irq_cfg; - switch (gpio_irq) { + switch (irq) { case 0: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_NONE; + irq_cfg = TQMX86_REG_IO_EXT_INT_NONE; break; case 7: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_7; + irq_cfg = TQMX86_REG_IO_EXT_INT_7; break; case 9: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_9; + irq_cfg = TQMX86_REG_IO_EXT_INT_9; break; case 12: - gpio_irq_cfg = TQMX86_REG_IO_EXT_INT_12; + irq_cfg = TQMX86_REG_IO_EXT_INT_12; break; default: - pr_err("tqmx86: Invalid GPIO IRQ (%d)\n", gpio_irq); + dev_err(dev, "invalid %s IRQ (%d)\n", label, irq); return -EINVAL; } + val = ioread8(io_base + TQMX86_REG_IO_EXT_INT); + val &= ~(TQMX86_REG_IO_EXT_INT_MASK << reg_shift); + val |= (irq_cfg & TQMX86_REG_IO_EXT_INT_MASK) << reg_shift; + + iowrite8(val, io_base + TQMX86_REG_IO_EXT_INT); + readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); + if (readback != val) { + dev_warn(dev, "%s interrupts not supported\n", label); + return -EINVAL; + } + + return 0; +} + +static int tqmx86_probe(struct platform_device *pdev) +{ + u8 board_id, sauc, rev, i2c_det; + struct device *dev = &pdev->dev; + const char *board_name; + void __iomem *io_base; + int err; + io_base = devm_ioport_map(dev, TQMX86_IOBASE, TQMX86_IOSIZE); if (!io_base) return -ENOMEM; @@ -221,25 +266,23 @@ static int tqmx86_probe(struct platform_device *pdev) */ i2c_det = inb(TQMX86_REG_I2C_DETECT); - if (gpio_irq_cfg) { - io_ext_int_val = - gpio_irq_cfg << TQMX86_REG_IO_EXT_INT_GPIO_SHIFT; - iowrite8(io_ext_int_val, io_base + TQMX86_REG_IO_EXT_INT); - readback = ioread8(io_base + TQMX86_REG_IO_EXT_INT); - if (readback != io_ext_int_val) { - dev_warn(dev, "GPIO interrupts not supported.\n"); - return -EINVAL; - } - - /* Assumes the IRQ resource is first. */ - tqmx_gpio_resources[0].start = gpio_irq; - } else { - tqmx_gpio_resources[0].flags = 0; + if (gpio_irq) { + err = tqmx86_setup_irq(dev, "GPIO", gpio_irq, io_base, + TQMX86_REG_IO_EXT_INT_GPIO_SHIFT); + if (!err) + tqmx_gpio_resources[TQMX86_GPIO_IRQ] = DEFINE_RES_IRQ(gpio_irq); } ocores_platform_data.clock_khz = tqmx86_board_id_to_clk_rate(dev, board_id); if (i2c_det == TQMX86_REG_I2C_DETECT_SOFT) { + if (i2c1_irq) { + err = tqmx86_setup_irq(dev, "I2C1", i2c1_irq, io_base, + TQMX86_REG_IO_EXT_INT_I2C1_SHIFT); + if (!err) + tqmx_i2c_soft_resources[TQMX86_I2C1_IRQ] = DEFINE_RES_IRQ(i2c1_irq); + } + err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, tqmx86_i2c_soft_dev, ARRAY_SIZE(tqmx86_i2c_soft_dev), diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 6e384a79e341..f89eda4a17fe 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -124,6 +124,11 @@ #define TWL6030_BASEADD_RSV 0x0000 #define TWL6030_BASEADD_ZERO 0x0000 +/* Some fields in TWL6030_PHOENIX_DEV_ON */ +#define TWL6030_APP_DEVOFF BIT(0) +#define TWL6030_CON_DEVOFF BIT(1) +#define TWL6030_MOD_DEVOFF BIT(2) + /* Few power values */ #define R_CFG_BOOT 0x05 @@ -687,11 +692,29 @@ static void twl_remove(struct i2c_client *client) twl_priv->ready = false; } +static void twl6030_power_off(void) +{ + int err; + u8 val; + + err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, TWL6030_PHOENIX_DEV_ON); + if (err) + return; + + val |= TWL6030_APP_DEVOFF | TWL6030_CON_DEVOFF | TWL6030_MOD_DEVOFF; + twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val, TWL6030_PHOENIX_DEV_ON); +} + + static struct of_dev_auxdata twl_auxdata_lookup[] = { OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL), { /* sentinel */ }, }; +static const struct mfd_cell twl6030_cells[] = { + { .name = "twl6030-clk" }, +}; + static const struct mfd_cell twl6032_cells[] = { { .name = "twl6032-clk" }, }; @@ -842,14 +865,29 @@ twl_probe(struct i2c_client *client) TWL4030_DCDC_GLOBAL_CFG); } - if (id->driver_data == (TWL6030_CLASS | TWL6032_SUBCLASS)) { - status = devm_mfd_add_devices(&client->dev, - PLATFORM_DEVID_NONE, - twl6032_cells, - ARRAY_SIZE(twl6032_cells), - NULL, 0, NULL); + if (twl_class_is_6030()) { + const struct mfd_cell *cells; + int num_cells; + + if (id->driver_data & TWL6032_SUBCLASS) { + cells = twl6032_cells; + num_cells = ARRAY_SIZE(twl6032_cells); + } else { + cells = twl6030_cells; + num_cells = ARRAY_SIZE(twl6030_cells); + } + + status = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, + cells, num_cells, NULL, 0, NULL); if (status < 0) goto free; + + if (of_device_is_system_power_controller(node)) { + if (!pm_power_off) + pm_power_off = twl6030_power_off; + else + dev_warn(&client->dev, "Poweroff callback already assigned\n"); + } } status = of_platform_populate(node, NULL, twl_auxdata_lookup, diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index d436ddf661da..a4a550bafb3c 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -276,7 +276,7 @@ static struct platform_driver twl4030_audio_driver = { .of_match_table = twl4030_audio_of_match, }, .probe = twl4030_audio_probe, - .remove_new = twl4030_audio_remove, + .remove = twl4030_audio_remove, }; module_platform_driver(twl4030_audio_driver); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 87496c1cb8bc..232c2bfe8c18 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -691,8 +691,8 @@ int twl4030_init_irq(struct device *dev, int irq_num) return irq_base; } - irq_domain_add_legacy(node, nr_irqs, irq_base, 0, - &irq_domain_simple_ops, NULL); + irq_domain_create_legacy(of_fwnode_handle(node), nr_irqs, irq_base, 0, + &irq_domain_simple_ops, NULL); irq_end = irq_base + TWL4030_CORE_NR_IRQS; diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 1595e9c76132..0bca948ab6ba 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -686,6 +686,9 @@ static bool twl4030_power_use_poweroff(const struct twl4030_power_data *pdata, if (of_property_read_bool(node, "ti,use_poweroff")) return true; + if (of_device_is_system_power_controller(node->parent)) + return true; + return false; } diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 3c03681c124c..00b14cef1dfb 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -364,7 +364,6 @@ static const struct of_device_id twl6030_of_match[] __maybe_unused = { int twl6030_init_irq(struct device *dev, int irq_num) { - struct device_node *node = dev->of_node; int nr_irqs; int status; u8 mask[3]; @@ -412,8 +411,8 @@ int twl6030_init_irq(struct device *dev, int irq_num) twl6030_irq->irq_mapping_tbl = of_id->data; twl6030_irq->irq_domain = - irq_domain_add_linear(node, nr_irqs, - &twl6030_irq_domain_ops, twl6030_irq); + irq_domain_create_linear(of_fwnode_handle(dev->of_node), nr_irqs, + &twl6030_irq_domain_ops, twl6030_irq); if (!twl6030_irq->irq_domain) { dev_err(dev, "Can't add irq_domain\n"); return -ENOMEM; diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 9ce34dfd99b3..218d6195fad2 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -620,7 +620,7 @@ static const struct regmap_irq twl6040_irqs[] = { { .reg_offset = 0, .mask = TWL6040_READYINT, }, }; -static struct regmap_irq_chip twl6040_irq_chip = { +static const struct regmap_irq_chip twl6040_irq_chip = { .name = "twl6040", .irqs = twl6040_irqs, .num_irqs = ARRAY_SIZE(twl6040_irqs), @@ -817,9 +817,9 @@ static void twl6040_remove(struct i2c_client *client) } static const struct i2c_device_id twl6040_i2c_id[] = { - { "twl6040", 0, }, - { "twl6041", 0, }, - { }, + { "twl6040" }, + { "twl6041" }, + { } }; MODULE_DEVICE_TABLE(i2c, twl6040_i2c_id); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index fc4d4c844a81..fd71ba29f6b5 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -104,7 +104,8 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb) return ucb1x00_reg_read(ucb, UCB_IO_DATA); } -static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +static int ucb1x00_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct ucb1x00 *ucb = gpiochip_get_data(chip); unsigned long flags; @@ -119,6 +120,8 @@ static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value) ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); ucb1x00_disable(ucb); spin_unlock_irqrestore(&ucb->io_lock, flags); + + return 0; } static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset) @@ -567,7 +570,7 @@ static int ucb1x00_probe(struct mcp *mcp) ucb->gpio.owner = THIS_MODULE; ucb->gpio.base = pdata->gpio_base; ucb->gpio.ngpio = 10; - ucb->gpio.set = ucb1x00_gpio_set; + ucb->gpio.set_rv = ucb1x00_gpio_set; ucb->gpio.get = ucb1x00_gpio_get; ucb->gpio.direction_input = ucb1x00_gpio_direction_input; ucb->gpio.direction_output = ucb1x00_gpio_direction_output; diff --git a/drivers/mfd/upboard-fpga.c b/drivers/mfd/upboard-fpga.c new file mode 100644 index 000000000000..afce623bbba5 --- /dev/null +++ b/drivers/mfd/upboard-fpga.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UP Board FPGA driver. + * + * FPGA provides more GPIO driving power, LEDS and pin mux function. + * + * Copyright (c) AAEON. All rights reserved. + * Copyright (C) 2024 Bootlin + * + * Author: Gary Wang <garywang@aaeon.com.tw> + * Author: Thomas Richard <thomas.richard@bootlin.com> + */ + +#include <linux/bitfield.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/mfd/core.h> +#include <linux/mfd/upboard-fpga.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/sysfs.h> + +#define UPBOARD_AAEON_MANUFACTURER_ID 0x01 +#define UPBOARD_MANUFACTURER_ID_MASK GENMASK(7, 0) + +#define UPBOARD_ADDRESS_SIZE 7 +#define UPBOARD_REGISTER_SIZE 16 + +#define UPBOARD_READ_FLAG BIT(UPBOARD_ADDRESS_SIZE) + +#define UPBOARD_FW_ID_MAJOR_SUPPORTED 0x0 + +#define UPBOARD_FW_ID_BUILD_MASK GENMASK(15, 12) +#define UPBOARD_FW_ID_MAJOR_MASK GENMASK(11, 8) +#define UPBOARD_FW_ID_MINOR_MASK GENMASK(7, 4) +#define UPBOARD_FW_ID_PATCH_MASK GENMASK(3, 0) + +static int upboard_fpga_read(void *context, unsigned int reg, unsigned int *val) +{ + struct upboard_fpga *fpga = context; + int i; + + /* Clear to start new transaction */ + gpiod_set_value(fpga->clear_gpio, 0); + gpiod_set_value(fpga->clear_gpio, 1); + + reg |= UPBOARD_READ_FLAG; + + /* Send clock and addr from strobe & datain pins */ + for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) { + gpiod_set_value(fpga->strobe_gpio, 0); + gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i))); + gpiod_set_value(fpga->strobe_gpio, 1); + } + + gpiod_set_value(fpga->strobe_gpio, 0); + *val = 0; + + /* Read data from dataout pin */ + for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) { + gpiod_set_value(fpga->strobe_gpio, 1); + gpiod_set_value(fpga->strobe_gpio, 0); + *val |= gpiod_get_value(fpga->dataout_gpio) << i; + } + + gpiod_set_value(fpga->strobe_gpio, 1); + + return 0; +} + +static int upboard_fpga_write(void *context, unsigned int reg, unsigned int val) +{ + struct upboard_fpga *fpga = context; + int i; + + /* Clear to start new transcation */ + gpiod_set_value(fpga->clear_gpio, 0); + gpiod_set_value(fpga->clear_gpio, 1); + + /* Send clock and addr from strobe & datain pins */ + for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) { + gpiod_set_value(fpga->strobe_gpio, 0); + gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i))); + gpiod_set_value(fpga->strobe_gpio, 1); + } + + gpiod_set_value(fpga->strobe_gpio, 0); + + /* Write data to datain pin */ + for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) { + gpiod_set_value(fpga->datain_gpio, !!(val & BIT(i))); + gpiod_set_value(fpga->strobe_gpio, 1); + gpiod_set_value(fpga->strobe_gpio, 0); + } + + gpiod_set_value(fpga->strobe_gpio, 1); + + return 0; +} + +static const struct regmap_range upboard_up_readable_ranges[] = { + regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID), + regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0), + regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1), + regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1), +}; + +static const struct regmap_range upboard_up_writable_ranges[] = { + regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN0), + regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN1), + regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR1), +}; + +static const struct regmap_access_table upboard_up_readable_table = { + .yes_ranges = upboard_up_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(upboard_up_readable_ranges), +}; + +static const struct regmap_access_table upboard_up_writable_table = { + .yes_ranges = upboard_up_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(upboard_up_writable_ranges), +}; + +static const struct regmap_config upboard_up_regmap_config = { + .reg_bits = UPBOARD_ADDRESS_SIZE, + .val_bits = UPBOARD_REGISTER_SIZE, + .max_register = UPBOARD_REG_MAX, + .reg_read = upboard_fpga_read, + .reg_write = upboard_fpga_write, + .fast_io = false, + .cache_type = REGCACHE_NONE, + .rd_table = &upboard_up_readable_table, + .wr_table = &upboard_up_writable_table, +}; + +static const struct regmap_range upboard_up2_readable_ranges[] = { + regmap_reg_range(UPBOARD_REG_PLATFORM_ID, UPBOARD_REG_FIRMWARE_ID), + regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1), + regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2), + regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2), +}; + +static const struct regmap_range upboard_up2_writable_ranges[] = { + regmap_reg_range(UPBOARD_REG_FUNC_EN0, UPBOARD_REG_FUNC_EN1), + regmap_reg_range(UPBOARD_REG_GPIO_EN0, UPBOARD_REG_GPIO_EN2), + regmap_reg_range(UPBOARD_REG_GPIO_DIR0, UPBOARD_REG_GPIO_DIR2), +}; + +static const struct regmap_access_table upboard_up2_readable_table = { + .yes_ranges = upboard_up2_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(upboard_up2_readable_ranges), +}; + +static const struct regmap_access_table upboard_up2_writable_table = { + .yes_ranges = upboard_up2_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(upboard_up2_writable_ranges), +}; + +static const struct regmap_config upboard_up2_regmap_config = { + .reg_bits = UPBOARD_ADDRESS_SIZE, + .val_bits = UPBOARD_REGISTER_SIZE, + .max_register = UPBOARD_REG_MAX, + .reg_read = upboard_fpga_read, + .reg_write = upboard_fpga_write, + .fast_io = false, + .cache_type = REGCACHE_NONE, + .rd_table = &upboard_up2_readable_table, + .wr_table = &upboard_up2_writable_table, +}; + +static const struct mfd_cell upboard_up_mfd_cells[] = { + { .name = "upboard-pinctrl" }, + { .name = "upboard-leds" }, +}; + +static const struct upboard_fpga_data upboard_up_fpga_data = { + .type = UPBOARD_UP_FPGA, + .regmap_config = &upboard_up_regmap_config, +}; + +static const struct upboard_fpga_data upboard_up2_fpga_data = { + .type = UPBOARD_UP2_FPGA, + .regmap_config = &upboard_up2_regmap_config, +}; + +static int upboard_fpga_gpio_init(struct upboard_fpga *fpga) +{ + fpga->enable_gpio = devm_gpiod_get(fpga->dev, "enable", GPIOD_ASIS); + if (IS_ERR(fpga->enable_gpio)) + return PTR_ERR(fpga->enable_gpio); + + fpga->clear_gpio = devm_gpiod_get(fpga->dev, "clear", GPIOD_OUT_LOW); + if (IS_ERR(fpga->clear_gpio)) + return PTR_ERR(fpga->clear_gpio); + + fpga->strobe_gpio = devm_gpiod_get(fpga->dev, "strobe", GPIOD_OUT_LOW); + if (IS_ERR(fpga->strobe_gpio)) + return PTR_ERR(fpga->strobe_gpio); + + fpga->datain_gpio = devm_gpiod_get(fpga->dev, "datain", GPIOD_OUT_LOW); + if (IS_ERR(fpga->datain_gpio)) + return PTR_ERR(fpga->datain_gpio); + + fpga->dataout_gpio = devm_gpiod_get(fpga->dev, "dataout", GPIOD_IN); + if (IS_ERR(fpga->dataout_gpio)) + return PTR_ERR(fpga->dataout_gpio); + + gpiod_set_value(fpga->enable_gpio, 1); + + return 0; +} + +static int upboard_fpga_get_firmware_version(struct upboard_fpga *fpga) +{ + unsigned int platform_id, manufacturer_id; + int ret; + + if (!fpga) + return -ENOMEM; + + ret = regmap_read(fpga->regmap, UPBOARD_REG_PLATFORM_ID, &platform_id); + if (ret) + return ret; + + manufacturer_id = platform_id & UPBOARD_MANUFACTURER_ID_MASK; + if (manufacturer_id != UPBOARD_AAEON_MANUFACTURER_ID) + return dev_err_probe(fpga->dev, -ENODEV, + "driver not compatible with custom FPGA FW from manufacturer id %#02x.", + manufacturer_id); + + ret = regmap_read(fpga->regmap, UPBOARD_REG_FIRMWARE_ID, &fpga->firmware_version); + if (ret) + return ret; + + if (FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version) != + UPBOARD_FW_ID_MAJOR_SUPPORTED) + return dev_err_probe(fpga->dev, -ENODEV, + "unsupported FPGA FW v%lu.%lu.%lu build %#02lx", + FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version), + FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version), + FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version), + FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version)); + return 0; +} + +static ssize_t upboard_fpga_version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct upboard_fpga *fpga = dev_get_drvdata(dev); + + return sysfs_emit(buf, "FPGA FW v%lu.%lu.%lu build %#02lx\n", + FIELD_GET(UPBOARD_FW_ID_MAJOR_MASK, fpga->firmware_version), + FIELD_GET(UPBOARD_FW_ID_MINOR_MASK, fpga->firmware_version), + FIELD_GET(UPBOARD_FW_ID_PATCH_MASK, fpga->firmware_version), + FIELD_GET(UPBOARD_FW_ID_BUILD_MASK, fpga->firmware_version)); +} + +static DEVICE_ATTR_RO(upboard_fpga_version); + +static struct attribute *upboard_fpga_attrs[] = { + &dev_attr_upboard_fpga_version.attr, + NULL +}; + +ATTRIBUTE_GROUPS(upboard_fpga); + +static int upboard_fpga_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct upboard_fpga *fpga; + int ret; + + fpga = devm_kzalloc(dev, sizeof(*fpga), GFP_KERNEL); + if (!fpga) + return -ENOMEM; + + fpga->fpga_data = device_get_match_data(dev); + + fpga->dev = dev; + + platform_set_drvdata(pdev, fpga); + + fpga->regmap = devm_regmap_init(dev, NULL, fpga, fpga->fpga_data->regmap_config); + if (IS_ERR(fpga->regmap)) + return PTR_ERR(fpga->regmap); + + ret = upboard_fpga_gpio_init(fpga); + if (ret) + return dev_err_probe(dev, ret, "Failed to initialize FPGA common GPIOs"); + + ret = upboard_fpga_get_firmware_version(fpga); + if (ret) + return ret; + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, upboard_up_mfd_cells, + ARRAY_SIZE(upboard_up_mfd_cells), NULL, 0, NULL); +} + +static const struct acpi_device_id upboard_fpga_acpi_match[] = { + { "AANT0F01", (kernel_ulong_t)&upboard_up2_fpga_data }, + { "AANT0F04", (kernel_ulong_t)&upboard_up_fpga_data }, + {} +}; +MODULE_DEVICE_TABLE(acpi, upboard_fpga_acpi_match); + +static struct platform_driver upboard_fpga_driver = { + .driver = { + .name = "upboard-fpga", + .acpi_match_table = upboard_fpga_acpi_match, + .dev_groups = upboard_fpga_groups, + }, + .probe = upboard_fpga_probe, +}; + +module_platform_driver(upboard_fpga_driver); + +MODULE_AUTHOR("Gary Wang <garywang@aaeon.com.tw>"); +MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>"); +MODULE_DESCRIPTION("UP Board FPGA driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index eab82619ec31..ef03d6cec9ff 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -10,7 +10,6 @@ #include <linux/mfd/core.h> #include <linux/module.h> #include <linux/of_platform.h> -#include <linux/platform_data/syscon.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/stat.h> @@ -132,4 +131,5 @@ static struct platform_driver vexpress_sysreg_driver = { }; module_platform_driver(vexpress_sysreg_driver); +MODULE_DESCRIPTION("Versatile Express system registers driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/wcd934x.c b/drivers/mfd/wcd934x.c index 7b9873b72c37..3c3080e8c8cf 100644 --- a/drivers/mfd/wcd934x.c +++ b/drivers/mfd/wcd934x.c @@ -109,7 +109,7 @@ static const struct regmap_range_cfg wcd934x_ranges[] = { }, }; -static struct regmap_config wcd934x_regmap_config = { +static const struct regmap_config wcd934x_regmap_config = { .reg_bits = 16, .val_bits = 8, .cache_type = REGCACHE_MAPLE, @@ -284,6 +284,7 @@ static const struct slim_device_id wcd934x_slim_id[] = { SLIM_DEV_IDX_WCD9340, SLIM_DEV_INSTANCE_ID_WCD9340 }, {} }; +MODULE_DEVICE_TABLE(slim, wcd934x_slim_id); static struct slim_driver wcd934x_slim_driver = { .driver = { @@ -298,5 +299,4 @@ static struct slim_driver wcd934x_slim_driver = { module_slim_driver(wcd934x_slim_driver); MODULE_DESCRIPTION("WCD934X slim driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("slim:217:250:*"); MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>"); diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index e2a7fccaed01..2f185e93318e 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -13,7 +13,7 @@ #define DRIVER_DESC "WL1273 FM Radio Core" static const struct i2c_device_id wl1273_driver_id_table[] = { - { WL1273_FM_DRIVER_NAME, 0 }, + { WL1273_FM_DRIVER_NAME }, { } }; MODULE_DEVICE_TABLE(i2c, wl1273_driver_id_table); diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index f77ecc635b6f..6a8602c1c4ee 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -1922,7 +1922,7 @@ const struct regmap_config wm5102_spi_regmap = { .readable_reg = wm5102_readable_register, .volatile_reg = wm5102_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm5102_reg_default, .num_reg_defaults = ARRAY_SIZE(wm5102_reg_default), }; diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index eba324875afd..6ff33a54a068 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -3202,7 +3202,7 @@ const struct regmap_config wm5110_spi_regmap = { .readable_reg = wm5110_readable_register, .volatile_reg = wm5110_volatile_register, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm5110_reg_default, .num_reg_defaults = ARRAY_SIZE(wm5110_reg_default), }; diff --git a/drivers/mfd/wm831x-auxadc.c b/drivers/mfd/wm831x-auxadc.c index 65b98f3fbd92..18618a8f9206 100644 --- a/drivers/mfd/wm831x-auxadc.c +++ b/drivers/mfd/wm831x-auxadc.c @@ -152,7 +152,7 @@ static irqreturn_t wm831x_auxadc_irq(int irq, void *irq_data) static int wm831x_auxadc_read_polled(struct wm831x *wm831x, enum wm831x_auxadc input) { - int ret, src, timeout; + int ret, src; mutex_lock(&wm831x->auxadc_lock); @@ -179,32 +179,25 @@ static int wm831x_auxadc_read_polled(struct wm831x *wm831x, goto disable; } - /* If we're not using interrupts then poll the - * interrupt status register */ - timeout = 5; - while (timeout) { - msleep(1); + /* If we're not using interrupts then read the interrupt status register */ + msleep(20); - ret = wm831x_reg_read(wm831x, - WM831X_INTERRUPT_STATUS_1); - if (ret < 0) { - dev_err(wm831x->dev, - "ISR 1 read failed: %d\n", ret); - goto disable; - } + ret = wm831x_reg_read(wm831x, WM831X_INTERRUPT_STATUS_1); + if (ret < 0) { + dev_err(wm831x->dev, + "ISR 1 read failed: %d\n", ret); + goto disable; + } - /* Did it complete? */ - if (ret & WM831X_AUXADC_DATA_EINT) { - wm831x_reg_write(wm831x, - WM831X_INTERRUPT_STATUS_1, - WM831X_AUXADC_DATA_EINT); - break; - } else { - dev_err(wm831x->dev, - "AUXADC conversion timeout\n"); - ret = -EBUSY; - goto disable; - } + /* Did it complete? */ + if (ret & WM831X_AUXADC_DATA_EINT) { + wm831x_reg_write(wm831x, WM831X_INTERRUPT_STATUS_1, + WM831X_AUXADC_DATA_EINT); + } else { + dev_err(wm831x->dev, + "AUXADC conversion timeout\n"); + ret = -EBUSY; + goto disable; } ret = wm831x_reg_read(wm831x, WM831X_AUXADC_DATA); diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index f1f58e3149ae..b3883fa5dd9f 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -587,16 +587,13 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) } if (irq_base) - domain = irq_domain_add_legacy(wm831x->dev->of_node, - ARRAY_SIZE(wm831x_irqs), - irq_base, 0, - &wm831x_irq_domain_ops, - wm831x); + domain = irq_domain_create_legacy(of_fwnode_handle(wm831x->dev->of_node), + ARRAY_SIZE(wm831x_irqs), irq_base, 0, + &wm831x_irq_domain_ops, wm831x); else - domain = irq_domain_add_linear(wm831x->dev->of_node, - ARRAY_SIZE(wm831x_irqs), - &wm831x_irq_domain_ops, - wm831x); + domain = irq_domain_create_linear(of_fwnode_handle(wm831x->dev->of_node), + ARRAY_SIZE(wm831x_irqs), &wm831x_irq_domain_ops, + wm831x); if (!domain) { dev_warn(wm831x->dev, "Failed to allocate IRQ domain\n"); diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index c2a7d7069975..767c176b12a7 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -41,9 +41,9 @@ static int wm8350_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id wm8350_i2c_id[] = { - { "wm8350", 0 }, - { "wm8351", 0 }, - { "wm8352", 0 }, + { "wm8350" }, + { "wm8351" }, + { "wm8352" }, { } }; diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c index 5663b8b0b3ad..3d0ebb004dbf 100644 --- a/drivers/mfd/wm8350-regmap.c +++ b/drivers/mfd/wm8350-regmap.c @@ -325,7 +325,7 @@ const struct regmap_config wm8350_regmap = { .reg_bits = 8, .val_bits = 16, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .max_register = WM8350_MAX_REGISTER, .readable_reg = wm8350_readable, diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 75483c9be0c4..8ecfe878a5ba 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -100,7 +100,7 @@ static const struct regmap_config wm8400_regmap_config = { .volatile_reg = wm8400_volatile, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }; /** @@ -135,7 +135,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c) } static const struct i2c_device_id wm8400_i2c_id[] = { - { "wm8400", 0 }, + { "wm8400" }, { } }; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index d5ac066f9db4..094c0b3dbd97 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -622,7 +622,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c) wm8994->dev = &i2c->dev; wm8994->irq = i2c->irq; - wm8994->type = (enum wm8994_type)i2c_get_match_data(i2c); + wm8994->type = (kernel_ulong_t)i2c_get_match_data(i2c); wm8994->regmap = devm_regmap_init_i2c(i2c, &wm8994_base_regmap_config); if (IS_ERR(wm8994->regmap)) { diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 651a028bc519..1475b1ac6983 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -213,9 +213,7 @@ int wm8994_irq_init(struct wm8994 *wm8994) return ret; } - wm8994->edge_irq = irq_domain_add_linear(NULL, 1, - &wm8994_edge_irq_ops, - wm8994); + wm8994->edge_irq = irq_domain_create_linear(NULL, 1, &wm8994_edge_irq_ops, wm8994); ret = regmap_add_irq_chip(wm8994->regmap, irq_create_mapping(wm8994->edge_irq, diff --git a/drivers/mfd/wm97xx-core.c b/drivers/mfd/wm97xx-core.c index 663acbb1854c..1566a9b04b6a 100644 --- a/drivers/mfd/wm97xx-core.c +++ b/drivers/mfd/wm97xx-core.c @@ -95,7 +95,7 @@ static const struct regmap_config wm9705_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm9705_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults), @@ -163,7 +163,7 @@ static const struct regmap_config wm9712_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm9712_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults), @@ -234,7 +234,7 @@ static const struct regmap_config wm9713_regmap_config = { .reg_stride = 2, .val_bits = 16, .max_register = 0x7e, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, .reg_defaults = wm9713_reg_defaults, .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults), |