diff options
Diffstat (limited to 'drivers/mfd')
119 files changed, 2878 insertions, 4098 deletions
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index eaf9845633b4..a30e47b74327 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -583,7 +583,7 @@ out_init: return ret; } -static int pm800_remove(struct i2c_client *client) +static void pm800_remove(struct i2c_client *client) { struct pm80x_chip *chip = i2c_get_clientdata(client); @@ -592,8 +592,6 @@ static int pm800_remove(struct i2c_client *client) pm800_pages_exit(chip); pm80x_deinit(); - - return 0; } static struct i2c_driver pm800_driver = { diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index ada6c513302b..10d3637840c8 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -239,7 +239,7 @@ out_init: return ret; } -static int pm805_remove(struct i2c_client *client) +static void pm805_remove(struct i2c_client *client) { struct pm80x_chip *chip = i2c_get_clientdata(client); @@ -247,8 +247,6 @@ static int pm805_remove(struct i2c_client *client) device_irq_exit_805(chip); pm80x_deinit(); - - return 0; } static struct i2c_driver pm805_driver = { diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index b1e829ea909b..5dc86dd66202 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1201,7 +1201,7 @@ static int pm860x_probe(struct i2c_client *client) return 0; } -static int pm860x_remove(struct i2c_client *client) +static void pm860x_remove(struct i2c_client *client) { struct pm860x_chip *chip = i2c_get_clientdata(client); @@ -1210,7 +1210,6 @@ static int pm860x_remove(struct i2c_client *client) regmap_exit(chip->regmap_companion); i2c_unregister_device(chip->companion); } - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3fb480818599..8b93856de432 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -572,6 +572,7 @@ config LPC_ICH tristate "Intel ICH LPC" depends on PCI select MFD_CORE + select P2SB if X86 help The LPC bridge function of the Intel ICH provides support for many functional units. This driver provides needed support for @@ -588,8 +589,8 @@ config LPC_SCH config INTEL_SOC_PMIC bool "Support for Crystal Cove PMIC" - depends on ACPI && HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK - depends on X86 || COMPILE_TEST + depends on HAS_IOMEM && I2C=y && GPIOLIB && COMMON_CLK + depends on (X86 && ACPI) || COMPILE_TEST depends on I2C_DESIGNWARE_PLATFORM=y select MFD_CORE select REGMAP_I2C @@ -634,7 +635,7 @@ config INTEL_SOC_PMIC_CHTWC config INTEL_SOC_PMIC_CHTDC_TI tristate "Support for Intel Cherry Trail Dollar Cove TI PMIC" depends on GPIOLIB - depends on I2C + depends on I2C=y && I2C_DESIGNWARE_PLATFORM=y depends on ACPI depends on X86 select MFD_CORE @@ -644,6 +645,10 @@ config INTEL_SOC_PMIC_CHTDC_TI Select this option for supporting Dollar Cove (TI version) PMIC device that is found on some Intel Cherry Trail systems. + This option is a bool as it provides an ACPI OpRegion which must be + available before any devices using it are probed. This option also + needs the designware-i2c driver to be builtin for the same reason. + config INTEL_SOC_PMIC_MRFLD tristate "Support for Intel Merrifield Basin Cove PMIC" depends on GPIOLIB @@ -692,16 +697,6 @@ config MFD_INTEL_PMC_BXT Register and P-unit access. In addition this creates devices for iTCO watchdog and telemetry that are part of the PMC. -config MFD_INTEL_PMT - tristate "Intel Platform Monitoring Technology (PMT) support" - depends on X86 && PCI - select MFD_CORE - help - The Intel Platform Monitoring Technology (PMT) is an interface that - provides access to hardware monitor registers. This driver supports - Telemetry, Watcher, and Crashlog PMT capabilities/devices for - platforms starting from Tiger Lake. - config MFD_IPAQ_MICRO bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" depends on SA1100_H3100 || SA1100_H3600 @@ -855,6 +850,20 @@ config MFD_MAX77693 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 + depends on OF || COMPILE_TEST + select MFD_CORE + select REGMAP_I2C + help + Say yes here to add support for Maxim Semiconductor MAX77714. + This is a Power Management IC with 4 buck regulators, 9 + low-dropout regulators, 8 GPIOs, RTC, watchdog etc. This driver + provides common support for accessing the device; additional + drivers must be enabled in order to use each functionality of the + device. + config MFD_MAX77843 bool "Maxim Semiconductor MAX77843 PMIC Support" depends on I2C=y @@ -929,6 +938,22 @@ config MFD_MT6360 PMIC part includes 2-channel BUCKs and 2-channel LDOs LDO part includes 4-channel LDOs +config MFD_MT6370 + tristate "MediaTek MT6370 SubPMIC" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C + help + Say Y here to enable MT6370 SubPMIC functional support. + It consists of a single cell battery charger with ADC monitoring, RGB + LEDs, dual channel flashlight, WLED backlight driver, display bias + voltage supply, one general purpose LDO, and the USB Type-C & PD + controller complies with the latest USB Type-C and PD standards. + + This driver can also be built as a module. If so, the module + will be called "mt6370". + config MFD_MT6397 tristate "MediaTek MT6397 PMIC Support" select MFD_CORE @@ -954,6 +979,27 @@ config MFD_MENF21BMC This driver can also be built as a module. If so the module will be called menf21bmc. +config MFD_OCELOT + tristate "Microsemi Ocelot External Control Support" + depends on SPI_MASTER + select MFD_CORE + select REGMAP_SPI + help + Ocelot is a family of networking chips that support multiple ethernet + and fibre interfaces. In addition to networking, they contain several + other functions, including pinctrl, MDIO, and communication with + external chips. While some chips have an internal processor capable of + running an OS, others don't. All chips can be controlled externally + through different interfaces, including SPI, I2C, and PCIe. + + Say yes here to add support for Ocelot chips (VSC7511, VSC7512, + VSC7513, VSC7514) controlled externally. + + To compile this driver as a module, choose M here: the module will be + called ocelot-soc. + + If unsure, say N. + config EZX_PCAP bool "Motorola EZXPCAP Support" depends on SPI_MASTER @@ -1087,6 +1133,16 @@ config MFD_SPMI_PMIC Say M here if you want to include support for the SPMI PMIC series as a module. The module will be called "qcom-spmi-pmic". +config MFD_SY7636A + tristate "Silergy SY7636A voltage regulator" + depends on I2C + select MFD_SIMPLE_MFD_I2C + help + Enable support for Silergy SY7636A voltage regulator. + + To enable support for building sub-devices as modules, + choose M here. + config MFD_RDC321X tristate "RDC R-321x southbridge" select MFD_CORE @@ -1119,6 +1175,18 @@ config MFD_RT5033 sub-devices like charger, fuel gauge, flash LED, current source, LDO and Buck. +config MFD_RT5120 + tristate "Richtek RT5120 Power Management IC" + depends on I2C + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + The enables support for Richtek RT5120 PMIC. It includes four high + efficiency buck converters and one LDO voltage regulator. The device + is targeted at providing the CPU voltage, memory, I/O and peripheral + power rails in home entertainment devices. + config MFD_RC5T583 bool "Ricoh RC5T583 Power Management system device" depends on I2C=y @@ -1289,14 +1357,6 @@ config AB8500_CORE the irq_chip parts for handling the Mixed Signal chip events. This chip embeds various other multimedia functionalities as well. -config AB8500_DEBUG - bool "Enable debug info via debugfs" - depends on AB8500_GPADC && DEBUG_FS - default y if DEBUG_FS - help - Select this option if you want debug information using the debug - filesystem, debugfs. - config MFD_DB8500_PRCMU bool "ST-Ericsson DB8500 Power Reset Control Management Unit" depends on UX500_SOC_DB8500 @@ -1357,12 +1417,13 @@ config MFD_STA2X11 select REGMAP_MMIO config MFD_SUN6I_PRCM - bool "Allwinner A31 PRCM controller" + bool "Allwinner A31/A23/A33 PRCM controller" depends on ARCH_SUNXI || COMPILE_TEST select MFD_CORE help Support for the PRCM (Power/Reset/Clock Management) unit available - in A31 SoC. + in the A31, A23, and A33 SoCs. Other Allwinner SoCs contain similar + hardware, but they do not use this driver. config MFD_SYSCON bool "System Controller Register R/W Based on Regmap" @@ -1945,23 +2006,6 @@ config MFD_ROHM_BD718XX NXP i.MX8. It contains 8 BUCK outputs and 7 LDOs, voltage monitoring and emergency shut down as well as 32,768KHz clock output. -config MFD_ROHM_BD70528 - tristate "ROHM BD70528 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 BD70528 Power - Management IC. BD71837 is general purpose single-chip power - management IC for battery-powered portable devices. It contains - 3 ultra-low current consumption buck converters, 3 LDOs and 2 LED - drivers. Also included are 4 GPIOs, a real-time clock (RTC), a 32kHz - crystal oscillator, high-accuracy VREF for use with an external ADC, - 10 bits SAR ADC for battery temperature monitor and 1S battery - charger. - config MFD_ROHM_BD71828 tristate "ROHM BD71828 and BD71815 Power Management IC" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0b1b629aef3e..7ed3ef4a698c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -120,6 +120,9 @@ obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o obj-$(CONFIG_MFD_CORE) += mfd-core.o +ocelot-soc-objs := ocelot-core.o ocelot-spi.o +obj-$(CONFIG_MFD_OCELOT) += ocelot-soc.o + obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o obj-$(CONFIG_MFD_CPCAP) += motorola-cpcap.o @@ -162,6 +165,7 @@ 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_MAX77714) += max77714.o obj-$(CONFIG_MFD_MAX77843) += max77843.o obj-$(CONFIG_MFD_MAX8907) += max8907.o max8925-objs := max8925-core.o max8925-i2c.o @@ -171,12 +175,16 @@ obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o obj-$(CONFIG_MFD_MP2629) += mp2629.o +obj-$(CONFIG_MFD_MT6360) += mt6360-core.o +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_ABX500_CORE) += abx500-core.o -obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o # ab8500-core need to come after db8500-prcmu (which provides the channel) obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o @@ -211,7 +219,6 @@ obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o obj-$(CONFIG_MFD_INTEL_PMC_BXT) += intel_pmc_bxt.o -obj-$(CONFIG_MFD_INTEL_PMT) += intel_pmt.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o obj-$(CONFIG_MFD_NTXEC) += ntxec.o @@ -235,16 +242,13 @@ obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o obj-$(CONFIG_MFD_DLN2) += dln2.o obj-$(CONFIG_MFD_RT4831) += rt4831.o obj-$(CONFIG_MFD_RT5033) += rt5033.o +obj-$(CONFIG_MFD_RT5120) += rt5120.o obj-$(CONFIG_MFD_SKY81452) += sky81452.o -intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o -obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o +obj-$(CONFIG_INTEL_SOC_PMIC) += intel_soc_pmic_crc.o obj-$(CONFIG_INTEL_SOC_PMIC_BXTWC) += intel_soc_pmic_bxtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTWC) += intel_soc_pmic_chtwc.o obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o -obj-$(CONFIG_MFD_MT6360) += mt6360-core.o -mt6397-objs := mt6397-core.o mt6397-irq.o mt6358-irq.o -obj-$(CONFIG_MFD_MT6397) += mt6397.o obj-$(CONFIG_INTEL_SOC_PMIC_MRFLD) += intel_soc_pmic_mrfld.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o @@ -257,7 +261,6 @@ obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o -obj-$(CONFIG_MFD_ROHM_BD70528) += rohm-bd70528.o obj-$(CONFIG_MFD_ROHM_BD71828) += rohm-bd71828.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_ROHM_BD957XMUF) += rohm-bd9576.o diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index cca0aac26148..9d9e9787d5e8 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -613,10 +613,6 @@ static const struct mfd_cell ab8500_bm_devs[] = { }; static const struct mfd_cell ab8500_devs[] = { -#ifdef CONFIG_DEBUG_FS - MFD_CELL_OF("ab8500-debug", - NULL, NULL, 0, 0, "stericsson,ab8500-debug"), -#endif MFD_CELL_OF("ab8500-sysctrl", NULL, NULL, 0, 0, "stericsson,ab8500-sysctrl"), MFD_CELL_OF("ab8500-ext-regulator", @@ -652,11 +648,6 @@ static const struct mfd_cell ab8500_devs[] = { }; static const struct mfd_cell ab9540_devs[] = { -#ifdef CONFIG_DEBUG_FS - { - .name = "ab8500-debug", - }, -#endif { .name = "ab8500-sysctrl", }, @@ -707,12 +698,6 @@ static const struct mfd_cell ab9540_devs[] = { /* Device list for ab8505 */ static const struct mfd_cell ab8505_devs[] = { -#ifdef CONFIG_DEBUG_FS - { - .name = "ab8500-debug", - .of_compatible = "stericsson,ab8500-debug", - }, -#endif { .name = "ab8500-sysctrl", .of_compatible = "stericsson,ab8500-sysctrl", @@ -764,11 +749,6 @@ static const struct mfd_cell ab8505_devs[] = { }; static const struct mfd_cell ab8540_devs[] = { -#ifdef CONFIG_DEBUG_FS - { - .name = "ab8500-debug", - }, -#endif { .name = "ab8500-sysctrl", }, @@ -1042,9 +1022,9 @@ static int ab8500_probe(struct platform_device *pdev) enum ab8500_version version = AB8500_VERSION_UNDEFINED; struct device_node *np = pdev->dev.of_node; struct ab8500 *ab8500; - struct resource *resource; int ret; int i; + int irq; u8 value; ab8500 = devm_kzalloc(&pdev->dev, sizeof(*ab8500), GFP_KERNEL); @@ -1053,13 +1033,11 @@ static int ab8500_probe(struct platform_device *pdev) ab8500->dev = &pdev->dev; - resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!resource) { - dev_err(&pdev->dev, "no IRQ resource\n"); - return -ENODEV; - } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; - ab8500->irq = resource->start; + ab8500->irq = irq; ab8500->read = ab8500_prcmu_read; ab8500->write = ab8500_prcmu_write; diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c deleted file mode 100644 index e43dea89b094..000000000000 --- a/drivers/mfd/ab8500-debugfs.c +++ /dev/null @@ -1,2096 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * Author: Mattias Wallin <mattias.wallin@stericsson.com> for ST-Ericsson. - */ -/* - * AB8500 register access - * ====================== - * - * read: - * # echo BANK > <debugfs>/ab8500/register-bank - * # echo ADDR > <debugfs>/ab8500/register-address - * # cat <debugfs>/ab8500/register-value - * - * write: - * # echo BANK > <debugfs>/ab8500/register-bank - * # echo ADDR > <debugfs>/ab8500/register-address - * # echo VALUE > <debugfs>/ab8500/register-value - * - * read all registers from a bank: - * # echo BANK > <debugfs>/ab8500/register-bank - * # cat <debugfs>/ab8500/all-bank-register - * - * BANK target AB8500 register bank - * ADDR target AB8500 register address - * VALUE decimal or 0x-prefixed hexadecimal - * - * - * User Space notification on AB8500 IRQ - * ===================================== - * - * Allows user space entity to be notified when target AB8500 IRQ occurs. - * When subscribed, a sysfs entry is created in ab8500.i2c platform device. - * One can pool this file to get target IRQ occurence information. - * - * subscribe to an AB8500 IRQ: - * # echo IRQ > <debugfs>/ab8500/irq-subscribe - * - * unsubscribe from an AB8500 IRQ: - * # echo IRQ > <debugfs>/ab8500/irq-unsubscribe - * - * - * AB8500 register formated read/write access - * ========================================== - * - * Read: read data, data>>SHIFT, data&=MASK, output data - * [0xABCDEF98] shift=12 mask=0xFFF => 0x00000CDE - * Write: read data, data &= ~(MASK<<SHIFT), data |= (VALUE<<SHIFT), write data - * [0xABCDEF98] shift=12 mask=0xFFF value=0x123 => [0xAB123F98] - * - * Usage: - * # echo "CMD [OPTIONS] BANK ADRESS [VALUE]" > $debugfs/ab8500/hwreg - * - * CMD read read access - * write write access - * - * BANK target reg bank - * ADDRESS target reg address - * VALUE (write) value to be updated - * - * OPTIONS - * -d|-dec (read) output in decimal - * -h|-hexa (read) output in 0x-hexa (default) - * -l|-w|-b 32bit (default), 16bit or 8bit reg access - * -m|-mask MASK 0x-hexa mask (default 0xFFFFFFFF) - * -s|-shift SHIFT bit shift value (read:left, write:right) - * -o|-offset OFFSET address offset to add to ADDRESS value - * - * Warning: bit shift operation is applied to bit-mask. - * Warning: bit shift direction depends on read or right command. - */ - -#include <linux/seq_file.h> -#include <linux/uaccess.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/debugfs.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/kobject.h> -#include <linux/slab.h> -#include <linux/irq.h> - -#include <linux/mfd/abx500.h> -#include <linux/mfd/abx500/ab8500.h> - -#ifdef CONFIG_DEBUG_FS -#include <linux/string.h> -#include <linux/ctype.h> -#endif - -static u32 debug_bank; -static u32 debug_address; - -static int irq_ab8500; -static int irq_first; -static int irq_last; -static u32 *irq_count; -static int num_irqs; - -static struct device_attribute **dev_attr; -static char **event_name; - -/** - * struct ab8500_reg_range - * @first: the first address of the range - * @last: the last address of the range - * @perm: access permissions for the range - */ -struct ab8500_reg_range { - u8 first; - u8 last; - u8 perm; -}; - -/** - * struct ab8500_prcmu_ranges - * @num_ranges: the number of ranges in the list - * @bankid: bank identifier - * @range: the list of register ranges - */ -struct ab8500_prcmu_ranges { - u8 num_ranges; - u8 bankid; - const struct ab8500_reg_range *range; -}; - -/* hwreg- "mask" and "shift" entries ressources */ -struct hwreg_cfg { - u32 bank; /* target bank */ - unsigned long addr; /* target address */ - uint fmt; /* format */ - unsigned long mask; /* read/write mask, applied before any bit shift */ - long shift; /* bit shift (read:right shift, write:left shift */ -}; -/* fmt bit #0: 0=hexa, 1=dec */ -#define REG_FMT_DEC(c) ((c)->fmt & 0x1) -#define REG_FMT_HEX(c) (!REG_FMT_DEC(c)) - -static struct hwreg_cfg hwreg_cfg = { - .addr = 0, /* default: invalid phys addr */ - .fmt = 0, /* default: 32bit access, hex output */ - .mask = 0xFFFFFFFF, /* default: no mask */ - .shift = 0, /* default: no bit shift */ -}; - -#define AB8500_NAME_STRING "ab8500" -#define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST - -#define AB8500_REV_REG 0x80 - -static struct ab8500_prcmu_ranges *debug_ranges; - -static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = { - [AB8500_M_FSM_RANK] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_SYS_CTRL1_BLOCK] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x02, - }, - { - .first = 0x42, - .last = 0x42, - }, - { - .first = 0x80, - .last = 0x81, - }, - }, - }, - [AB8500_SYS_CTRL2_BLOCK] = { - .num_ranges = 4, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x0D, - }, - { - .first = 0x0F, - .last = 0x17, - }, - { - .first = 0x30, - .last = 0x30, - }, - { - .first = 0x32, - .last = 0x33, - }, - }, - }, - [AB8500_REGU_CTRL1] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x03, - .last = 0x10, - }, - { - .first = 0x80, - .last = 0x84, - }, - }, - }, - [AB8500_REGU_CTRL2] = { - .num_ranges = 5, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x15, - }, - { - .first = 0x17, - .last = 0x19, - }, - { - .first = 0x1B, - .last = 0x1D, - }, - { - .first = 0x1F, - .last = 0x22, - }, - { - .first = 0x40, - .last = 0x44, - }, - /* - * 0x80-0x8B are SIM registers and should - * not be accessed from here - */ - }, - }, - [AB8500_USB] = { - .num_ranges = 2, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x80, - .last = 0x83, - }, - { - .first = 0x87, - .last = 0x8A, - }, - }, - }, - [AB8500_TVOUT] = { - .num_ranges = 9, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x12, - }, - { - .first = 0x15, - .last = 0x17, - }, - { - .first = 0x19, - .last = 0x21, - }, - { - .first = 0x27, - .last = 0x2C, - }, - { - .first = 0x41, - .last = 0x41, - }, - { - .first = 0x45, - .last = 0x5B, - }, - { - .first = 0x5D, - .last = 0x5D, - }, - { - .first = 0x69, - .last = 0x69, - }, - { - .first = 0x80, - .last = 0x81, - }, - }, - }, - [AB8500_DBI] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_ECI_AV_ACC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x80, - .last = 0x82, - }, - }, - }, - [AB8500_RESERVED] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_GPADC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x08, - }, - }, - }, - [AB8500_CHARGER] = { - .num_ranges = 9, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x03, - }, - { - .first = 0x05, - .last = 0x05, - }, - { - .first = 0x40, - .last = 0x40, - }, - { - .first = 0x42, - .last = 0x42, - }, - { - .first = 0x44, - .last = 0x44, - }, - { - .first = 0x50, - .last = 0x55, - }, - { - .first = 0x80, - .last = 0x82, - }, - { - .first = 0xC0, - .last = 0xC2, - }, - { - .first = 0xf5, - .last = 0xf6, - }, - }, - }, - [AB8500_GAS_GAUGE] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x07, - .last = 0x0A, - }, - { - .first = 0x10, - .last = 0x14, - }, - }, - }, - [AB8500_AUDIO] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x6F, - }, - }, - }, - [AB8500_INTERRUPT] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_RTC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x0F, - }, - }, - }, - [AB8500_MISC] = { - .num_ranges = 8, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x05, - }, - { - .first = 0x10, - .last = 0x15, - }, - { - .first = 0x20, - .last = 0x25, - }, - { - .first = 0x30, - .last = 0x35, - }, - { - .first = 0x40, - .last = 0x45, - }, - { - .first = 0x50, - .last = 0x50, - }, - { - .first = 0x60, - .last = 0x67, - }, - { - .first = 0x80, - .last = 0x80, - }, - }, - }, - [AB8500_DEVELOPMENT] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - }, - }, - [AB8500_DEBUG] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x05, - .last = 0x07, - }, - }, - }, - [AB8500_PROD_TEST] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_STE_TEST] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_OTP_EMUL] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x01, - .last = 0x0F, - }, - }, - }, -}; - -static struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = { - [0x0] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_SYS_CTRL1_BLOCK] = { - .num_ranges = 5, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x04, - }, - { - .first = 0x42, - .last = 0x42, - }, - { - .first = 0x52, - .last = 0x52, - }, - { - .first = 0x54, - .last = 0x57, - }, - { - .first = 0x80, - .last = 0x83, - }, - }, - }, - [AB8500_SYS_CTRL2_BLOCK] = { - .num_ranges = 5, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x0D, - }, - { - .first = 0x0F, - .last = 0x17, - }, - { - .first = 0x20, - .last = 0x20, - }, - { - .first = 0x30, - .last = 0x30, - }, - { - .first = 0x32, - .last = 0x3A, - }, - }, - }, - [AB8500_REGU_CTRL1] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x03, - .last = 0x11, - }, - { - .first = 0x80, - .last = 0x86, - }, - }, - }, - [AB8500_REGU_CTRL2] = { - .num_ranges = 6, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x06, - }, - { - .first = 0x08, - .last = 0x15, - }, - { - .first = 0x17, - .last = 0x19, - }, - { - .first = 0x1B, - .last = 0x1D, - }, - { - .first = 0x1F, - .last = 0x30, - }, - { - .first = 0x40, - .last = 0x48, - }, - /* - * 0x80-0x8B are SIM registers and should - * not be accessed from here - */ - }, - }, - [AB8500_USB] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x80, - .last = 0x83, - }, - { - .first = 0x87, - .last = 0x8A, - }, - { - .first = 0x91, - .last = 0x94, - }, - }, - }, - [AB8500_TVOUT] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_DBI] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_ECI_AV_ACC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x80, - .last = 0x82, - }, - }, - }, - [AB8500_RESERVED] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_GPADC] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x08, - }, - }, - }, - [AB8500_CHARGER] = { - .num_ranges = 9, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x02, - .last = 0x03, - }, - { - .first = 0x05, - .last = 0x05, - }, - { - .first = 0x40, - .last = 0x44, - }, - { - .first = 0x50, - .last = 0x57, - }, - { - .first = 0x60, - .last = 0x60, - }, - { - .first = 0xA0, - .last = 0xA7, - }, - { - .first = 0xAF, - .last = 0xB2, - }, - { - .first = 0xC0, - .last = 0xC2, - }, - { - .first = 0xF5, - .last = 0xF5, - }, - }, - }, - [AB8500_GAS_GAUGE] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x07, - .last = 0x0A, - }, - { - .first = 0x10, - .last = 0x14, - }, - }, - }, - [AB8500_AUDIO] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x83, - }, - }, - }, - [AB8500_INTERRUPT] = { - .num_ranges = 11, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x04, - }, - { - .first = 0x06, - .last = 0x07, - }, - { - .first = 0x09, - .last = 0x09, - }, - { - .first = 0x0B, - .last = 0x0C, - }, - { - .first = 0x12, - .last = 0x15, - }, - { - .first = 0x18, - .last = 0x18, - }, - /* Latch registers should not be read here */ - { - .first = 0x40, - .last = 0x44, - }, - { - .first = 0x46, - .last = 0x49, - }, - { - .first = 0x4B, - .last = 0x4D, - }, - { - .first = 0x52, - .last = 0x55, - }, - { - .first = 0x58, - .last = 0x58, - }, - /* LatchHier registers should not be read here */ - }, - }, - [AB8500_RTC] = { - .num_ranges = 2, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x14, - }, - { - .first = 0x16, - .last = 0x17, - }, - }, - }, - [AB8500_MISC] = { - .num_ranges = 8, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x06, - }, - { - .first = 0x10, - .last = 0x16, - }, - { - .first = 0x20, - .last = 0x26, - }, - { - .first = 0x30, - .last = 0x36, - }, - { - .first = 0x40, - .last = 0x46, - }, - { - .first = 0x50, - .last = 0x50, - }, - { - .first = 0x60, - .last = 0x6B, - }, - { - .first = 0x80, - .last = 0x82, - }, - }, - }, - [AB8500_DEVELOPMENT] = { - .num_ranges = 2, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x05, - .last = 0x05, - }, - }, - }, - [AB8500_DEBUG] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x05, - .last = 0x07, - }, - }, - }, - [AB8500_PROD_TEST] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_STE_TEST] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_OTP_EMUL] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x01, - .last = 0x15, - }, - }, - }, -}; - -static struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = { - [AB8500_M_FSM_RANK] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x0B, - }, - }, - }, - [AB8500_SYS_CTRL1_BLOCK] = { - .num_ranges = 6, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x04, - }, - { - .first = 0x42, - .last = 0x42, - }, - { - .first = 0x50, - .last = 0x54, - }, - { - .first = 0x57, - .last = 0x57, - }, - { - .first = 0x80, - .last = 0x83, - }, - { - .first = 0x90, - .last = 0x90, - }, - }, - }, - [AB8500_SYS_CTRL2_BLOCK] = { - .num_ranges = 5, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x0D, - }, - { - .first = 0x0F, - .last = 0x10, - }, - { - .first = 0x20, - .last = 0x21, - }, - { - .first = 0x32, - .last = 0x3C, - }, - { - .first = 0x40, - .last = 0x42, - }, - }, - }, - [AB8500_REGU_CTRL1] = { - .num_ranges = 4, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x03, - .last = 0x15, - }, - { - .first = 0x20, - .last = 0x20, - }, - { - .first = 0x80, - .last = 0x85, - }, - { - .first = 0x87, - .last = 0x88, - }, - }, - }, - [AB8500_REGU_CTRL2] = { - .num_ranges = 8, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x06, - }, - { - .first = 0x08, - .last = 0x15, - }, - { - .first = 0x17, - .last = 0x19, - }, - { - .first = 0x1B, - .last = 0x1D, - }, - { - .first = 0x1F, - .last = 0x2F, - }, - { - .first = 0x31, - .last = 0x3A, - }, - { - .first = 0x43, - .last = 0x44, - }, - { - .first = 0x48, - .last = 0x49, - }, - }, - }, - [AB8500_USB] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x80, - .last = 0x83, - }, - { - .first = 0x87, - .last = 0x8A, - }, - { - .first = 0x91, - .last = 0x94, - }, - }, - }, - [AB8500_TVOUT] = { - .num_ranges = 0, - .range = NULL - }, - [AB8500_DBI] = { - .num_ranges = 4, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x07, - }, - { - .first = 0x10, - .last = 0x11, - }, - { - .first = 0x20, - .last = 0x21, - }, - { - .first = 0x30, - .last = 0x43, - }, - }, - }, - [AB8500_ECI_AV_ACC] = { - .num_ranges = 2, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x03, - }, - { - .first = 0x80, - .last = 0x82, - }, - }, - }, - [AB8500_RESERVED] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_GPADC] = { - .num_ranges = 4, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x01, - }, - { - .first = 0x04, - .last = 0x06, - }, - { - .first = 0x09, - .last = 0x0A, - }, - { - .first = 0x10, - .last = 0x14, - }, - }, - }, - [AB8500_CHARGER] = { - .num_ranges = 10, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x02, - .last = 0x05, - }, - { - .first = 0x40, - .last = 0x44, - }, - { - .first = 0x50, - .last = 0x57, - }, - { - .first = 0x60, - .last = 0x60, - }, - { - .first = 0x70, - .last = 0x70, - }, - { - .first = 0xA0, - .last = 0xA9, - }, - { - .first = 0xAF, - .last = 0xB2, - }, - { - .first = 0xC0, - .last = 0xC6, - }, - { - .first = 0xF5, - .last = 0xF5, - }, - }, - }, - [AB8500_GAS_GAUGE] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x00, - }, - { - .first = 0x07, - .last = 0x0A, - }, - { - .first = 0x10, - .last = 0x14, - }, - }, - }, - [AB8500_AUDIO] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x9f, - }, - }, - }, - [AB8500_INTERRUPT] = { - .num_ranges = 6, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x05, - }, - { - .first = 0x0B, - .last = 0x0D, - }, - { - .first = 0x12, - .last = 0x20, - }, - /* Latch registers should not be read here */ - { - .first = 0x40, - .last = 0x45, - }, - { - .first = 0x4B, - .last = 0x4D, - }, - { - .first = 0x52, - .last = 0x60, - }, - /* LatchHier registers should not be read here */ - }, - }, - [AB8500_RTC] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x07, - }, - { - .first = 0x0B, - .last = 0x18, - }, - { - .first = 0x20, - .last = 0x25, - }, - }, - }, - [AB8500_MISC] = { - .num_ranges = 9, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x06, - }, - { - .first = 0x10, - .last = 0x16, - }, - { - .first = 0x20, - .last = 0x26, - }, - { - .first = 0x30, - .last = 0x36, - }, - { - .first = 0x40, - .last = 0x49, - }, - { - .first = 0x50, - .last = 0x50, - }, - { - .first = 0x60, - .last = 0x6B, - }, - { - .first = 0x70, - .last = 0x74, - }, - { - .first = 0x80, - .last = 0x82, - }, - }, - }, - [AB8500_DEVELOPMENT] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x01, - }, - { - .first = 0x06, - .last = 0x06, - }, - { - .first = 0x10, - .last = 0x21, - }, - }, - }, - [AB8500_DEBUG] = { - .num_ranges = 3, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x01, - .last = 0x0C, - }, - { - .first = 0x0E, - .last = 0x11, - }, - { - .first = 0x80, - .last = 0x81, - }, - }, - }, - [AB8500_PROD_TEST] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_STE_TEST] = { - .num_ranges = 0, - .range = NULL, - }, - [AB8500_OTP_EMUL] = { - .num_ranges = 1, - .range = (struct ab8500_reg_range[]) { - { - .first = 0x00, - .last = 0x3F, - }, - }, - }, -}; - -static irqreturn_t ab8500_debug_handler(int irq, void *data) -{ - char buf[16]; - struct kobject *kobj = (struct kobject *)data; - unsigned int irq_abb = irq - irq_first; - - if (irq_abb < num_irqs) - irq_count[irq_abb]++; - /* - * This makes it possible to use poll for events (EPOLLPRI | EPOLLERR) - * from userspace on sysfs file named <irq-nr> - */ - sprintf(buf, "%d", irq); - sysfs_notify(kobj, NULL, buf); - - return IRQ_HANDLED; -} - -/* Prints to seq_file or log_buf */ -static int ab8500_registers_print(struct device *dev, u32 bank, - struct seq_file *s) -{ - unsigned int i; - - for (i = 0; i < debug_ranges[bank].num_ranges; i++) { - u32 reg; - - for (reg = debug_ranges[bank].range[i].first; - reg <= debug_ranges[bank].range[i].last; - reg++) { - u8 value; - int err; - - err = abx500_get_register_interruptible(dev, - (u8)bank, (u8)reg, &value); - if (err < 0) { - dev_err(dev, "ab->read fail %d\n", err); - return err; - } - - if (s) { - seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n", - bank, reg, value); - /* - * Error is not returned here since - * the output is wanted in any case - */ - if (seq_has_overflowed(s)) - return 0; - } else { - dev_info(dev, " [0x%02X/0x%02X]: 0x%02X\n", - bank, reg, value); - } - } - } - - return 0; -} - -static int ab8500_bank_registers_show(struct seq_file *s, void *p) -{ - struct device *dev = s->private; - u32 bank = debug_bank; - - seq_puts(s, AB8500_NAME_STRING " register values:\n"); - - seq_printf(s, " bank 0x%02X:\n", bank); - - return ab8500_registers_print(dev, bank, s); -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_bank_registers); - -static int ab8500_print_all_banks(struct seq_file *s, void *p) -{ - struct device *dev = s->private; - unsigned int i; - - seq_puts(s, AB8500_NAME_STRING " register values:\n"); - - for (i = 0; i < AB8500_NUM_BANKS; i++) { - int err; - - seq_printf(s, " bank 0x%02X:\n", i); - err = ab8500_registers_print(dev, i, s); - if (err) - return err; - } - return 0; -} - -/* Dump registers to kernel log */ -void ab8500_dump_all_banks(struct device *dev) -{ - unsigned int i; - - dev_info(dev, "ab8500 register values:\n"); - - for (i = 1; i < AB8500_NUM_BANKS; i++) { - dev_info(dev, " bank 0x%02X:\n", i); - ab8500_registers_print(dev, i, NULL); - } -} - -static int ab8500_all_banks_open(struct inode *inode, struct file *file) -{ - struct seq_file *s; - int err; - - err = single_open(file, ab8500_print_all_banks, inode->i_private); - if (!err) { - /* Default buf size in seq_read is not enough */ - s = (struct seq_file *)file->private_data; - s->size = (PAGE_SIZE * 2); - s->buf = kmalloc(s->size, GFP_KERNEL); - if (!s->buf) { - single_release(inode, file); - err = -ENOMEM; - } - } - return err; -} - -static const struct file_operations ab8500_all_banks_fops = { - .open = ab8500_all_banks_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_bank_print(struct seq_file *s, void *p) -{ - seq_printf(s, "0x%02X\n", debug_bank); - return 0; -} - -static int ab8500_bank_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_bank_print, inode->i_private); -} - -static ssize_t ab8500_bank_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_bank; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &user_bank); - if (err) - return err; - - if (user_bank >= AB8500_NUM_BANKS) { - dev_err(dev, "debugfs error input > number of banks\n"); - return -EINVAL; - } - - debug_bank = user_bank; - - return count; -} - -static int ab8500_address_print(struct seq_file *s, void *p) -{ - seq_printf(s, "0x%02X\n", debug_address); - return 0; -} - -static int ab8500_address_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_address_print, inode->i_private); -} - -static ssize_t ab8500_address_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_address; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &user_address); - if (err) - return err; - - if (user_address > 0xff) { - dev_err(dev, "debugfs error input > 0xff\n"); - return -EINVAL; - } - debug_address = user_address; - - return count; -} - -static int ab8500_val_print(struct seq_file *s, void *p) -{ - struct device *dev = s->private; - int ret; - u8 regvalue; - - ret = abx500_get_register_interruptible(dev, - (u8)debug_bank, (u8)debug_address, ®value); - if (ret < 0) { - dev_err(dev, "abx500_get_reg fail %d, %d\n", - ret, __LINE__); - return -EINVAL; - } - seq_printf(s, "0x%02X\n", regvalue); - - return 0; -} - -static int ab8500_val_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_val_print, inode->i_private); -} - -static ssize_t ab8500_val_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_val; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &user_val); - if (err) - return err; - - if (user_val > 0xff) { - dev_err(dev, "debugfs error input > 0xff\n"); - return -EINVAL; - } - err = abx500_set_register_interruptible(dev, - (u8)debug_bank, debug_address, (u8)user_val); - if (err < 0) { - pr_err("abx500_set_reg failed %d, %d", err, __LINE__); - return -EINVAL; - } - - return count; -} - -/* - * Interrupt status - */ -static u32 num_interrupts[AB8500_MAX_NR_IRQS]; -static u32 num_wake_interrupts[AB8500_MAX_NR_IRQS]; -static int num_interrupt_lines; - -void ab8500_debug_register_interrupt(int line) -{ - if (line < num_interrupt_lines) - num_interrupts[line]++; -} - -static int ab8500_interrupts_show(struct seq_file *s, void *p) -{ - int line; - - seq_puts(s, "name: number: irq: number of: wake:\n"); - - for (line = 0; line < num_interrupt_lines; line++) { - seq_printf(s, "%3i: %4i %6i %4i\n", - line, - line + irq_first, - num_interrupts[line], - num_wake_interrupts[line]); - } - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_interrupts); - -/* - * - HWREG DB8500 formated routines - */ -static int ab8500_hwreg_print(struct seq_file *s, void *d) -{ - struct device *dev = s->private; - int ret; - u8 regvalue; - - ret = abx500_get_register_interruptible(dev, - (u8)hwreg_cfg.bank, (u8)hwreg_cfg.addr, ®value); - if (ret < 0) { - dev_err(dev, "abx500_get_reg fail %d, %d\n", - ret, __LINE__); - return -EINVAL; - } - - if (hwreg_cfg.shift >= 0) - regvalue >>= hwreg_cfg.shift; - else - regvalue <<= -hwreg_cfg.shift; - regvalue &= hwreg_cfg.mask; - - if (REG_FMT_DEC(&hwreg_cfg)) - seq_printf(s, "%d\n", regvalue); - else - seq_printf(s, "0x%02X\n", regvalue); - return 0; -} - -static int ab8500_hwreg_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_hwreg_print, inode->i_private); -} - -#define AB8500_SUPPLY_CONTROL_CONFIG_1 0x01 -#define AB8500_SUPPLY_CONTROL_REG 0x00 -#define AB8500_FIRST_SIM_REG 0x80 -#define AB8500_LAST_SIM_REG 0x8B -#define AB8505_LAST_SIM_REG 0x8C - -static int ab8500_modem_show(struct seq_file *s, void *p) -{ - struct device *dev = s->private; - struct ab8500 *ab8500; - int err; - u8 value; - u8 orig_value; - u32 bank = AB8500_REGU_CTRL2; - u32 last_sim_reg = AB8500_LAST_SIM_REG; - u32 reg; - - ab8500 = dev_get_drvdata(dev->parent); - dev_warn(dev, "WARNING! This operation can interfer with modem side\n" - "and should only be done with care\n"); - - err = abx500_get_register_interruptible(dev, - AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, &orig_value); - if (err < 0) - goto report_read_failure; - - /* Config 1 will allow APE side to read SIM registers */ - err = abx500_set_register_interruptible(dev, - AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, - AB8500_SUPPLY_CONTROL_CONFIG_1); - if (err < 0) - goto report_write_failure; - - seq_printf(s, " bank 0x%02X:\n", bank); - - if (is_ab9540(ab8500) || is_ab8505(ab8500)) - last_sim_reg = AB8505_LAST_SIM_REG; - - for (reg = AB8500_FIRST_SIM_REG; reg <= last_sim_reg; reg++) { - err = abx500_get_register_interruptible(dev, - bank, reg, &value); - if (err < 0) - goto report_read_failure; - - seq_printf(s, " [0x%02X/0x%02X]: 0x%02X\n", bank, reg, value); - } - err = abx500_set_register_interruptible(dev, - AB8500_REGU_CTRL1, AB8500_SUPPLY_CONTROL_REG, orig_value); - if (err < 0) - goto report_write_failure; - - return 0; - -report_read_failure: - dev_err(dev, "ab->read fail %d\n", err); - return err; - -report_write_failure: - dev_err(dev, "ab->write fail %d\n", err); - return err; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_modem); - -/* - * return length of an ASCII numerical value, 0 is string is not a - * numerical value. - * string shall start at value 1st char. - * string can be tailed with \0 or space or newline chars only. - * value can be decimal or hexadecimal (prefixed 0x or 0X). - */ -static int strval_len(char *b) -{ - char *s = b; - - if ((*s == '0') && ((*(s+1) == 'x') || (*(s+1) == 'X'))) { - s += 2; - for (; *s && (*s != ' ') && (*s != '\n'); s++) { - if (!isxdigit(*s)) - return 0; - } - } else { - if (*s == '-') - s++; - for (; *s && (*s != ' ') && (*s != '\n'); s++) { - if (!isdigit(*s)) - return 0; - } - } - return (int) (s-b); -} - -/* - * parse hwreg input data. - * update global hwreg_cfg only if input data syntax is ok. - */ -static ssize_t hwreg_common_write(char *b, struct hwreg_cfg *cfg, - struct device *dev) -{ - uint write, val = 0; - u8 regvalue; - int ret; - struct hwreg_cfg loc = { - .bank = 0, /* default: invalid phys addr */ - .addr = 0, /* default: invalid phys addr */ - .fmt = 0, /* default: 32bit access, hex output */ - .mask = 0xFFFFFFFF, /* default: no mask */ - .shift = 0, /* default: no bit shift */ - }; - - /* read or write ? */ - if (!strncmp(b, "read ", 5)) { - write = 0; - b += 5; - } else if (!strncmp(b, "write ", 6)) { - write = 1; - b += 6; - } else - return -EINVAL; - - /* OPTIONS -l|-w|-b -s -m -o */ - while ((*b == ' ') || (*b == '-')) { - if (*(b-1) != ' ') { - b++; - continue; - } - if ((!strncmp(b, "-d ", 3)) || - (!strncmp(b, "-dec ", 5))) { - b += (*(b+2) == ' ') ? 3 : 5; - loc.fmt |= (1<<0); - } else if ((!strncmp(b, "-h ", 3)) || - (!strncmp(b, "-hex ", 5))) { - b += (*(b+2) == ' ') ? 3 : 5; - loc.fmt &= ~(1<<0); - } else if ((!strncmp(b, "-m ", 3)) || - (!strncmp(b, "-mask ", 6))) { - b += (*(b+2) == ' ') ? 3 : 6; - if (strval_len(b) == 0) - return -EINVAL; - ret = kstrtoul(b, 0, &loc.mask); - if (ret) - return ret; - } else if ((!strncmp(b, "-s ", 3)) || - (!strncmp(b, "-shift ", 7))) { - b += (*(b+2) == ' ') ? 3 : 7; - if (strval_len(b) == 0) - return -EINVAL; - ret = kstrtol(b, 0, &loc.shift); - if (ret) - return ret; - } else { - return -EINVAL; - } - } - /* get arg BANK and ADDRESS */ - if (strval_len(b) == 0) - return -EINVAL; - ret = kstrtouint(b, 0, &loc.bank); - if (ret) - return ret; - while (*b == ' ') - b++; - if (strval_len(b) == 0) - return -EINVAL; - ret = kstrtoul(b, 0, &loc.addr); - if (ret) - return ret; - - if (write) { - while (*b == ' ') - b++; - if (strval_len(b) == 0) - return -EINVAL; - ret = kstrtouint(b, 0, &val); - if (ret) - return ret; - } - - /* args are ok, update target cfg (mainly for read) */ - *cfg = loc; - -#ifdef ABB_HWREG_DEBUG - pr_warn("HWREG request: %s, %s,\n", (write) ? "write" : "read", - REG_FMT_DEC(cfg) ? "decimal" : "hexa"); - pr_warn(" addr=0x%08X, mask=0x%X, shift=%d" "value=0x%X\n", - cfg->addr, cfg->mask, cfg->shift, val); -#endif - - if (!write) - return 0; - - ret = abx500_get_register_interruptible(dev, - (u8)cfg->bank, (u8)cfg->addr, ®value); - if (ret < 0) { - dev_err(dev, "abx500_get_reg fail %d, %d\n", - ret, __LINE__); - return -EINVAL; - } - - if (cfg->shift >= 0) { - regvalue &= ~(cfg->mask << (cfg->shift)); - val = (val & cfg->mask) << (cfg->shift); - } else { - regvalue &= ~(cfg->mask >> (-cfg->shift)); - val = (val & cfg->mask) >> (-cfg->shift); - } - val = val | regvalue; - - ret = abx500_set_register_interruptible(dev, - (u8)cfg->bank, (u8)cfg->addr, (u8)val); - if (ret < 0) { - pr_err("abx500_set_reg failed %d, %d", ret, __LINE__); - return -EINVAL; - } - - return 0; -} - -static ssize_t ab8500_hwreg_write(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - char buf[128]; - int buf_size, ret; - - /* Get userspace string and assure termination */ - buf_size = min((int)count, (int)(sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - buf[buf_size] = 0; - - /* get args and process */ - ret = hwreg_common_write(buf, &hwreg_cfg, dev); - return (ret) ? ret : buf_size; -} - -/* - * - irq subscribe/unsubscribe stuff - */ -static int ab8500_subscribe_unsubscribe_print(struct seq_file *s, void *p) -{ - seq_printf(s, "%d\n", irq_first); - - return 0; -} - -static int ab8500_subscribe_unsubscribe_open(struct inode *inode, - struct file *file) -{ - return single_open(file, ab8500_subscribe_unsubscribe_print, - inode->i_private); -} - -/* - * Userspace should use poll() on this file. When an event occur - * the blocking poll will be released. - */ -static ssize_t show_irq(struct device *dev, - struct device_attribute *attr, char *buf) -{ - unsigned long name; - unsigned int irq_index; - int err; - - err = kstrtoul(attr->attr.name, 0, &name); - if (err) - return err; - - irq_index = name - irq_first; - if (irq_index >= num_irqs) - return -EINVAL; - - return sprintf(buf, "%u\n", irq_count[irq_index]); -} - -static ssize_t ab8500_subscribe_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_val; - int err; - unsigned int irq_index; - - err = kstrtoul_from_user(user_buf, count, 0, &user_val); - if (err) - return err; - - if (user_val < irq_first) { - dev_err(dev, "debugfs error input < %d\n", irq_first); - return -EINVAL; - } - if (user_val > irq_last) { - dev_err(dev, "debugfs error input > %d\n", irq_last); - return -EINVAL; - } - - irq_index = user_val - irq_first; - if (irq_index >= num_irqs) - return -EINVAL; - - /* - * This will create a sysfs file named <irq-nr> which userspace can - * use to select or poll and get the AB8500 events - */ - dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute), - GFP_KERNEL); - if (!dev_attr[irq_index]) - return -ENOMEM; - - event_name[irq_index] = kasprintf(GFP_KERNEL, "%lu", user_val); - if (!event_name[irq_index]) - return -ENOMEM; - - dev_attr[irq_index]->show = show_irq; - dev_attr[irq_index]->store = NULL; - dev_attr[irq_index]->attr.name = event_name[irq_index]; - dev_attr[irq_index]->attr.mode = S_IRUGO; - err = sysfs_create_file(&dev->kobj, &dev_attr[irq_index]->attr); - if (err < 0) { - pr_info("sysfs_create_file failed %d\n", err); - return err; - } - - err = request_threaded_irq(user_val, NULL, ab8500_debug_handler, - IRQF_SHARED | IRQF_NO_SUSPEND | IRQF_ONESHOT, - "ab8500-debug", &dev->kobj); - if (err < 0) { - pr_info("request_threaded_irq failed %d, %lu\n", - err, user_val); - sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr); - return err; - } - - return count; -} - -static ssize_t ab8500_unsubscribe_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_val; - int err; - unsigned int irq_index; - - err = kstrtoul_from_user(user_buf, count, 0, &user_val); - if (err) - return err; - - if (user_val < irq_first) { - dev_err(dev, "debugfs error input < %d\n", irq_first); - return -EINVAL; - } - if (user_val > irq_last) { - dev_err(dev, "debugfs error input > %d\n", irq_last); - return -EINVAL; - } - - irq_index = user_val - irq_first; - if (irq_index >= num_irqs) - return -EINVAL; - - /* Set irq count to 0 when unsubscribe */ - irq_count[irq_index] = 0; - - if (dev_attr[irq_index]) - sysfs_remove_file(&dev->kobj, &dev_attr[irq_index]->attr); - - - free_irq(user_val, &dev->kobj); - kfree(event_name[irq_index]); - kfree(dev_attr[irq_index]); - - return count; -} - -/* - * - several debugfs nodes fops - */ - -static const struct file_operations ab8500_bank_fops = { - .open = ab8500_bank_open, - .write = ab8500_bank_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations ab8500_address_fops = { - .open = ab8500_address_open, - .write = ab8500_address_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations ab8500_val_fops = { - .open = ab8500_val_open, - .write = ab8500_val_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations ab8500_subscribe_fops = { - .open = ab8500_subscribe_unsubscribe_open, - .write = ab8500_subscribe_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations ab8500_unsubscribe_fops = { - .open = ab8500_subscribe_unsubscribe_open, - .write = ab8500_unsubscribe_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static const struct file_operations ab8500_hwreg_fops = { - .open = ab8500_hwreg_open, - .write = ab8500_hwreg_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_debug_probe(struct platform_device *plf) -{ - struct dentry *ab8500_dir; - struct ab8500 *ab8500; - struct resource *res; - - debug_bank = AB8500_MISC; - debug_address = AB8500_REV_REG & 0x00FF; - - ab8500 = dev_get_drvdata(plf->dev.parent); - num_irqs = ab8500->mask_size; - - irq_count = devm_kcalloc(&plf->dev, - num_irqs, sizeof(*irq_count), GFP_KERNEL); - if (!irq_count) - return -ENOMEM; - - dev_attr = devm_kcalloc(&plf->dev, - num_irqs, sizeof(*dev_attr), GFP_KERNEL); - if (!dev_attr) - return -ENOMEM; - - event_name = devm_kcalloc(&plf->dev, - num_irqs, sizeof(*event_name), GFP_KERNEL); - if (!event_name) - return -ENOMEM; - - res = platform_get_resource_byname(plf, 0, "IRQ_AB8500"); - if (!res) { - dev_err(&plf->dev, "AB8500 irq not found, err %d\n", irq_first); - return -ENXIO; - } - irq_ab8500 = res->start; - - irq_first = platform_get_irq_byname(plf, "IRQ_FIRST"); - if (irq_first < 0) - return irq_first; - - irq_last = platform_get_irq_byname(plf, "IRQ_LAST"); - if (irq_last < 0) - return irq_last; - - ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); - - debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir, - &plf->dev, &ab8500_bank_registers_fops); - debugfs_create_file("all-banks", S_IRUGO, ab8500_dir, - &plf->dev, &ab8500_all_banks_fops); - debugfs_create_file("register-bank", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_bank_fops); - debugfs_create_file("register-address", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_address_fops); - debugfs_create_file("register-value", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_val_fops); - debugfs_create_file("irq-subscribe", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_subscribe_fops); - - if (is_ab8500(ab8500)) { - debug_ranges = ab8500_debug_ranges; - num_interrupt_lines = AB8500_NR_IRQS; - } else if (is_ab8505(ab8500)) { - debug_ranges = ab8505_debug_ranges; - num_interrupt_lines = AB8505_NR_IRQS; - } else if (is_ab9540(ab8500)) { - debug_ranges = ab8505_debug_ranges; - num_interrupt_lines = AB9540_NR_IRQS; - } else if (is_ab8540(ab8500)) { - debug_ranges = ab8540_debug_ranges; - num_interrupt_lines = AB8540_NR_IRQS; - } - - debugfs_create_file("interrupts", (S_IRUGO), ab8500_dir, &plf->dev, - &ab8500_interrupts_fops); - debugfs_create_file("irq-unsubscribe", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_unsubscribe_fops); - debugfs_create_file("hwreg", (S_IRUGO | S_IWUSR | S_IWGRP), ab8500_dir, - &plf->dev, &ab8500_hwreg_fops); - debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_dir, &plf->dev, &ab8500_modem_fops); - - return 0; -} - -static struct platform_driver ab8500_debug_driver = { - .driver = { - .name = "ab8500-debug", - .suppress_bind_attrs = true, - }, - .probe = ab8500_debug_probe, -}; - -static int __init ab8500_debug_init(void) -{ - return platform_driver_register(&ab8500_debug_driver); -} -subsys_initcall(ab8500_debug_init); diff --git a/drivers/mfd/acer-ec-a500.c b/drivers/mfd/acer-ec-a500.c index 80c2fdd14fc4..7fd8b9988075 100644 --- a/drivers/mfd/acer-ec-a500.c +++ b/drivers/mfd/acer-ec-a500.c @@ -169,7 +169,7 @@ static int a500_ec_probe(struct i2c_client *client) return 0; } -static int a500_ec_remove(struct i2c_client *client) +static void a500_ec_remove(struct i2c_client *client) { if (of_device_is_system_power_controller(client->dev.of_node)) { if (pm_power_off == a500_ec_poweroff) @@ -177,8 +177,6 @@ static int a500_ec_remove(struct i2c_client *client) unregister_restart_handler(&a500_ec_restart_handler); } - - return 0; } static const struct of_device_id a500_ec_match[] = { diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index 3ed810e81f63..bfc7cf56ff2c 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -84,13 +84,11 @@ static int arizona_i2c_probe(struct i2c_client *i2c, return arizona_dev_init(arizona); } -static int arizona_i2c_remove(struct i2c_client *i2c) +static void arizona_i2c_remove(struct i2c_client *i2c) { struct arizona *arizona = dev_get_drvdata(&i2c->dev); arizona_dev_exit(arizona); - - return 0; } static const struct i2c_device_id arizona_i2c_id[] = { @@ -105,7 +103,7 @@ static const struct i2c_device_id arizona_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, arizona_i2c_id); #ifdef CONFIG_OF -const struct of_device_id arizona_i2c_of_match[] = { +static const struct of_device_id arizona_i2c_of_match[] = { { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, { .compatible = "wlf,wm8280", .data = (void *)WM8280 }, diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index 9fe06dda3782..941b0267d09d 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -43,31 +43,13 @@ static const struct gpiod_lookup arizona_soc_gpios[] = { { "arizona", 4, "wlf,micd-pol", 0, GPIO_ACTIVE_LOW }, }; -/* - * The AOSP 3.5 mm Headset: Accessory Specification gives the following values: - * Function A Play/Pause: 0 ohm - * Function D Voice assistant: 135 ohm - * Function B Volume Up 240 ohm - * Function C Volume Down 470 ohm - * Minimum Mic DC resistance 1000 ohm - * Minimum Ear speaker impedance 16 ohm - * Note the first max value below must be less then the min. speaker impedance, - * to allow CTIA/OMTP detection to work. The other max values are the closest - * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances. - */ -static const struct arizona_micd_range arizona_micd_aosp_ranges[] = { - { .max = 11, .key = KEY_PLAYPAUSE }, - { .max = 186, .key = KEY_VOICECOMMAND }, - { .max = 348, .key = KEY_VOLUMEUP }, - { .max = 752, .key = KEY_VOLUMEDOWN }, -}; - static void arizona_spi_acpi_remove_lookup(void *lookup) { gpiod_remove_lookup_table(lookup); } -static int arizona_spi_acpi_probe(struct arizona *arizona) +/* For ACPI tables from boards which ship with Windows as factory OS */ +static int arizona_spi_acpi_windows_probe(struct arizona *arizona) { struct gpiod_lookup_table *lookup; acpi_status status; @@ -96,6 +78,65 @@ static int arizona_spi_acpi_probe(struct arizona *arizona) if (ACPI_FAILURE(status)) dev_warn(arizona->dev, "Failed to enable 32KHz clk ACPI error %d\n", status); + return 0; +} + +/* For ACPI tables from boards which ship with Android as factory OS */ +static int arizona_spi_acpi_android_probe(struct arizona *arizona) +{ + int ret; + + /* + * Get the reset GPIO, treating -ENOENT as -EPROBE_DEFER to wait for + * the x86-android-tablets module to register the board specific GPIO + * lookup table. + */ + arizona->pdata.reset = devm_gpiod_get(arizona->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(arizona->pdata.reset)) { + ret = PTR_ERR(arizona->pdata.reset); + if (ret == -ENOENT) { + dev_info_once(arizona->dev, + "Deferring probe till GPIO lookup is registered\n"); + ret = -EPROBE_DEFER; + } + return dev_err_probe(arizona->dev, ret, "getting reset GPIO\n"); + } + + return 0; +} + +/* + * The AOSP 3.5 mm Headset: Accessory Specification gives the following values: + * Function A Play/Pause: 0 ohm + * Function D Voice assistant: 135 ohm + * Function B Volume Up 240 ohm + * Function C Volume Down 470 ohm + * Minimum Mic DC resistance 1000 ohm + * Minimum Ear speaker impedance 16 ohm + * Note the first max value below must be less then the min. speaker impedance, + * to allow CTIA/OMTP detection to work. The other max values are the closest + * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances. + */ +static const struct arizona_micd_range arizona_micd_aosp_ranges[] = { + { .max = 11, .key = KEY_PLAYPAUSE }, + { .max = 186, .key = KEY_VOICECOMMAND }, + { .max = 348, .key = KEY_VOLUMEUP }, + { .max = 752, .key = KEY_VOLUMEDOWN }, +}; + +static int arizona_spi_acpi_probe(struct arizona *arizona) +{ + struct acpi_device *adev = ACPI_COMPANION(arizona->dev); + int ret; + + if (acpi_dev_hid_uid_match(adev, "10WM5102", NULL)) + ret = arizona_spi_acpi_android_probe(arizona); + else + ret = arizona_spi_acpi_windows_probe(arizona); + + if (ret) + return ret; + /* * Some DSDTs wrongly declare the IRQ trigger-type as IRQF_TRIGGER_FALLING * The IRQ line will stay low when a new IRQ event happens between reading @@ -130,6 +171,10 @@ static const struct acpi_device_id arizona_acpi_match[] = { .id = "WM510205", .driver_data = WM5102, }, + { + .id = "10WM5102", + .driver_data = WM5102, + }, { } }; MODULE_DEVICE_TABLE(acpi, arizona_acpi_match); @@ -206,13 +251,11 @@ static int arizona_spi_probe(struct spi_device *spi) return arizona_dev_init(arizona); } -static int arizona_spi_remove(struct spi_device *spi) +static void arizona_spi_remove(struct spi_device *spi) { struct arizona *arizona = spi_get_drvdata(spi); arizona_dev_exit(arizona); - - return 0; } static const struct spi_device_id arizona_spi_ids[] = { @@ -226,7 +269,7 @@ static const struct spi_device_id arizona_spi_ids[] = { MODULE_DEVICE_TABLE(spi, arizona_spi_ids); #ifdef CONFIG_OF -const struct of_device_id arizona_spi_of_match[] = { +static const struct of_device_id arizona_spi_of_match[] = { { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, { .compatible = "wlf,wm8280", .data = (void *)WM8280 }, diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 8d58c8df46cf..4fb7e35eb5ed 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -596,12 +596,11 @@ static __init int asic3_gpio_probe(struct platform_device *pdev, return gpiochip_add_data(&asic->gpio, asic); } -static int asic3_gpio_remove(struct platform_device *pdev) +static void asic3_gpio_remove(struct platform_device *pdev) { struct asic3 *asic = platform_get_drvdata(pdev); gpiochip_remove(&asic->gpio); - return 0; } static void asic3_clk_enable(struct asic3 *asic, struct asic3_clk *clk) @@ -906,14 +905,14 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); if (ret < 0) - goto out; + goto out_unmap; } if (mem_sdio && (irq >= 0)) { ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_mmc, 1, mem_sdio, irq, NULL); if (ret < 0) - goto out; + goto out_unmap; } ret = 0; @@ -927,8 +926,12 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, ret = mfd_add_devices(&pdev->dev, 0, asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); } + return ret; - out: +out_unmap: + if (asic->tmio_cnf) + iounmap(asic->tmio_cnf); +out: return ret; } @@ -1026,7 +1029,6 @@ static int __init asic3_probe(struct platform_device *pdev) static int asic3_remove(struct platform_device *pdev) { - int ret; struct asic3 *asic = platform_get_drvdata(pdev); asic3_set_register(asic, ASIC3_OFFSET(EXTCF, SELECT), @@ -1034,9 +1036,8 @@ static int asic3_remove(struct platform_device *pdev) asic3_mfd_remove(pdev); - ret = asic3_gpio_remove(pdev); - if (ret < 0) - return ret; + asic3_gpio_remove(pdev); + asic3_irq_remove(pdev); asic3_write_register(asic, ASIC3_OFFSET(CLOCK, SEL), 0); diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c index d2f5c073fdf3..33caa4fba6af 100644 --- a/drivers/mfd/atmel-flexcom.c +++ b/drivers/mfd/atmel-flexcom.c @@ -87,8 +87,7 @@ static const struct of_device_id atmel_flexcom_of_match[] = { }; MODULE_DEVICE_TABLE(of, atmel_flexcom_of_match); -#ifdef CONFIG_PM_SLEEP -static int atmel_flexcom_resume(struct device *dev) +static int __maybe_unused atmel_flexcom_resume_noirq(struct device *dev) { struct atmel_flexcom *ddata = dev_get_drvdata(dev); int err; @@ -105,16 +104,16 @@ static int atmel_flexcom_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(atmel_flexcom_pm_ops, NULL, - atmel_flexcom_resume); +static const struct dev_pm_ops __maybe_unused atmel_flexcom_pm_ops = { + .resume_noirq = atmel_flexcom_resume_noirq, +}; static struct platform_driver atmel_flexcom_driver = { .probe = atmel_flexcom_probe, .driver = { .name = "atmel_flexcom", - .pm = &atmel_flexcom_pm_ops, + .pm = pm_ptr(&atmel_flexcom_pm_ops), .of_match_table = atmel_flexcom_of_match, }, }; diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index d96f1d689e7f..f3bad2b52f17 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -240,7 +240,7 @@ EXPORT_SYMBOL_GPL(atmel_smc_cs_conf_set_cycle); * @conf: the SMC CS conf to apply * * Applies an SMC CS configuration. - * Only valid on at91sam9/avr32 SoCs. + * Only valid on at91sam9 SoCs. */ void atmel_smc_cs_conf_apply(struct regmap *regmap, int cs, const struct atmel_smc_cs_conf *conf) @@ -281,7 +281,7 @@ EXPORT_SYMBOL_GPL(atmel_hsmc_cs_conf_apply); * @conf: the SMC CS conf object to store the current conf * * Retrieve the SMC CS configuration. - * Only valid on at91sam9/avr32 SoCs. + * Only valid on at91sam9 SoCs. */ void atmel_smc_cs_conf_get(struct regmap *regmap, int cs, struct atmel_smc_cs_conf *conf) diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index 00ab48018d8d..8fd6727dc30a 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -50,13 +50,11 @@ static int axp20x_i2c_probe(struct i2c_client *i2c, return axp20x_device_probe(axp20x); } -static int axp20x_i2c_remove(struct i2c_client *i2c) +static void axp20x_i2c_remove(struct i2c_client *i2c) { struct axp20x_dev *axp20x = i2c_get_clientdata(i2c); axp20x_device_remove(axp20x); - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 8161a5dc68e8..88a212a8168c 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -619,6 +619,9 @@ static const struct mfd_cell axp20x_cells[] = { static const struct mfd_cell axp221_cells[] = { { + .name = "axp20x-gpio", + .of_compatible = "x-powers,axp221-gpio", + }, { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), .resources = axp22x_pek_resources, @@ -645,6 +648,9 @@ static const struct mfd_cell axp221_cells[] = { static const struct mfd_cell axp223_cells[] = { { + .name = "axp20x-gpio", + .of_compatible = "x-powers,axp221-gpio", + }, { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp22x_pek_resources), .resources = axp22x_pek_resources, @@ -785,6 +791,9 @@ static const struct mfd_cell axp806_cells[] = { static const struct mfd_cell axp809_cells[] = { { + .name = "axp20x-gpio", + .of_compatible = "x-powers,axp221-gpio", + }, { .name = "axp221-pek", .num_resources = ARRAY_SIZE(axp809_pek_resources), .resources = axp809_pek_resources, diff --git a/drivers/mfd/bcm2835-pm.c b/drivers/mfd/bcm2835-pm.c index 42fe67f1538e..49cd1f03884a 100644 --- a/drivers/mfd/bcm2835-pm.c +++ b/drivers/mfd/bcm2835-pm.c @@ -25,9 +25,52 @@ static const struct mfd_cell bcm2835_power_devs[] = { { .name = "bcm2835-power" }, }; +static int bcm2835_pm_get_pdata(struct platform_device *pdev, + struct bcm2835_pm *pm) +{ + if (of_find_property(pm->dev->of_node, "reg-names", NULL)) { + struct resource *res; + + pm->base = devm_platform_ioremap_resource_byname(pdev, "pm"); + if (IS_ERR(pm->base)) + return PTR_ERR(pm->base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "asb"); + if (res) { + pm->asb = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pm->asb)) + pm->asb = NULL; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "rpivid_asb"); + if (res) { + pm->rpivid_asb = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pm->rpivid_asb)) + pm->rpivid_asb = NULL; + } + + return 0; + } + + /* If no 'reg-names' property is found we can assume we're using old DTB. */ + pm->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pm->base)) + return PTR_ERR(pm->base); + + pm->asb = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(pm->asb)) + pm->asb = NULL; + + pm->rpivid_asb = devm_platform_ioremap_resource(pdev, 2); + if (IS_ERR(pm->rpivid_asb)) + pm->rpivid_asb = NULL; + + return 0; +} + static int bcm2835_pm_probe(struct platform_device *pdev) { - struct resource *res; struct device *dev = &pdev->dev; struct bcm2835_pm *pm; int ret; @@ -39,10 +82,9 @@ static int bcm2835_pm_probe(struct platform_device *pdev) pm->dev = dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pm->base = devm_ioremap_resource(dev, res); - if (IS_ERR(pm->base)) - return PTR_ERR(pm->base); + ret = bcm2835_pm_get_pdata(pdev, pm); + if (ret) + return ret; ret = devm_mfd_add_devices(dev, -1, bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs), @@ -50,30 +92,22 @@ static int bcm2835_pm_probe(struct platform_device *pdev) if (ret) return ret; - /* We'll use the presence of the AXI ASB regs in the + /* + * We'll use the presence of the AXI ASB regs in the * bcm2835-pm binding as the key for whether we can reference * the full PM register range and support power domains. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) { - pm->asb = devm_ioremap_resource(dev, res); - if (IS_ERR(pm->asb)) - return PTR_ERR(pm->asb); - - ret = devm_mfd_add_devices(dev, -1, - bcm2835_power_devs, - ARRAY_SIZE(bcm2835_power_devs), - NULL, 0, NULL); - if (ret) - return ret; - } - + if (pm->asb) + return devm_mfd_add_devices(dev, -1, bcm2835_power_devs, + ARRAY_SIZE(bcm2835_power_devs), + NULL, 0, NULL); return 0; } static const struct of_device_id bcm2835_pm_of_match[] = { { .compatible = "brcm,bcm2835-pm-wdt", }, { .compatible = "brcm,bcm2835-pm", }, + { .compatible = "brcm,bcm2711-pm", }, {}, }; MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match); diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 546feef851ab..344ad03bdc42 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -65,6 +65,11 @@ static const struct cros_feature_to_name cros_mcu_devices[] = { .desc = "System Control Processor", }, { + .id = EC_FEATURE_SCP_C1, + .name = CROS_EC_DEV_SCP_C1_NAME, + .desc = "System Control Processor 2nd Core", + }, + { .id = EC_FEATURE_TOUCHPAD, .name = CROS_EC_DEV_TP_NAME, .desc = "Touchpad", @@ -114,6 +119,9 @@ static const struct mfd_cell cros_ec_platform_cells[] = { { .name = "cros-ec-chardev", }, { .name = "cros-ec-debugfs", }, { .name = "cros-ec-sysfs", }, +}; + +static const struct mfd_cell cros_ec_pchg_cells[] = { { .name = "cros-ec-pchg", }, }; @@ -137,6 +145,7 @@ static int ec_device_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct cros_ec_platform *ec_platform = dev_get_platdata(dev); struct cros_ec_dev *ec = kzalloc(sizeof(*ec), GFP_KERNEL); + struct ec_response_pchg_count pchg_count; int i; if (!ec) @@ -243,6 +252,21 @@ static int ec_device_probe(struct platform_device *pdev) } /* + * The PCHG device cannot be detected by sending EC_FEATURE_GET_CMD, but + * it can be detected by querying the number of peripheral chargers. + */ + retval = cros_ec_cmd(ec->ec_dev, 0, EC_CMD_PCHG_COUNT, NULL, 0, + &pchg_count, sizeof(pchg_count)); + if (retval >= 0 && pchg_count.port_count) { + retval = mfd_add_hotplug_devices(ec->dev, + cros_ec_pchg_cells, + ARRAY_SIZE(cros_ec_pchg_cells)); + if (retval) + dev_warn(ec->dev, "failed to add pchg: %d\n", + retval); + } + + /* * The following subdevices cannot be detected by sending the * EC_FEATURE_GET_CMD to the Embedded Controller device. */ diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index a818fbb55988..3f8f6ad3a98c 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -532,12 +532,11 @@ static int da903x_probe(struct i2c_client *client, return da903x_add_subdevs(chip, pdata); } -static int da903x_remove(struct i2c_client *client) +static void da903x_remove(struct i2c_client *client) { struct da903x_chip *chip = i2c_get_clientdata(client); da903x_remove_subdevs(chip); - return 0; } static struct i2c_driver da903x_driver = { diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 8de93db35f3a..5a74696c8704 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -168,12 +168,11 @@ static int da9052_i2c_probe(struct i2c_client *client, return da9052_device_init(da9052, id->driver_data); } -static int da9052_i2c_remove(struct i2c_client *client) +static void da9052_i2c_remove(struct i2c_client *client) { struct da9052 *da9052 = i2c_get_clientdata(client); da9052_device_exit(da9052); - return 0; } static struct i2c_driver da9052_i2c_driver = { diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index 5faf3766a5e2..b79a57b45c1e 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -55,12 +55,11 @@ static int da9052_spi_probe(struct spi_device *spi) return da9052_device_init(da9052, id->driver_data); } -static int da9052_spi_remove(struct spi_device *spi) +static void da9052_spi_remove(struct spi_device *spi) { struct da9052 *da9052 = spi_get_drvdata(spi); da9052_device_exit(da9052); - return 0; } static const struct spi_device_id da9052_spi_id[] = { diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index bc60433b68db..276c7d1c509e 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -41,13 +41,11 @@ static int da9055_i2c_probe(struct i2c_client *i2c, return da9055_device_init(da9055); } -static int da9055_i2c_remove(struct i2c_client *i2c) +static void da9055_i2c_remove(struct i2c_client *i2c) { struct da9055 *da9055 = i2c_get_clientdata(i2c); da9055_device_exit(da9055); - - return 0; } /* diff --git a/drivers/mfd/da9062-core.c b/drivers/mfd/da9062-core.c index 01f8e10dfa55..a26e473507c7 100644 --- a/drivers/mfd/da9062-core.c +++ b/drivers/mfd/da9062-core.c @@ -453,6 +453,7 @@ static const struct regmap_range da9061_aa_writeable_ranges[] = { regmap_reg_range(DA9062AA_VBUCK1_B, DA9062AA_VBUCK4_B), regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B), regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B), + regmap_reg_range(DA9062AA_CONFIG_J, DA9062AA_CONFIG_J), regmap_reg_range(DA9062AA_GP_ID_0, DA9062AA_GP_ID_19), }; @@ -556,6 +557,7 @@ static const struct regmap_range da9062_aa_writeable_ranges[] = { regmap_reg_range(DA9062AA_VBUCK3_B, DA9062AA_VBUCK3_B), regmap_reg_range(DA9062AA_VLDO1_B, DA9062AA_VLDO4_B), regmap_reg_range(DA9062AA_BBAT_CONT, DA9062AA_BBAT_CONT), + regmap_reg_range(DA9062AA_CONFIG_J, DA9062AA_CONFIG_J), regmap_reg_range(DA9062AA_GP_ID_0, DA9062AA_GP_ID_19), }; @@ -674,6 +676,17 @@ static int da9062_i2c_probe(struct i2c_client *i2c, return ret; } + /* If SMBus is not available and only I2C is possible, enter I2C mode */ + if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_info(chip->dev, "Entering I2C mode!\n"); + ret = regmap_clear_bits(chip->regmap, DA9062AA_CONFIG_J, + DA9062AA_TWOWIRE_TO_MASK); + if (ret < 0) { + dev_err(chip->dev, "Failed to set Two-Wire Bus Mode.\n"); + return ret; + } + } + ret = da9062_clear_fault_log(chip); if (ret < 0) dev_warn(chip->dev, "Cannot clear fault log\n"); @@ -711,14 +724,12 @@ static int da9062_i2c_probe(struct i2c_client *i2c, return ret; } -static int da9062_i2c_remove(struct i2c_client *i2c) +static void da9062_i2c_remove(struct i2c_client *i2c) { struct da9062 *chip = i2c_get_clientdata(i2c); mfd_remove_devices(chip->dev); regmap_del_irq_chip(i2c->irq, chip->regmap_irq); - - return 0; } static const struct i2c_device_id da9062_i2c_id[] = { diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c index 58009c8cb870..6ae56e46d24e 100644 --- a/drivers/mfd/da9150-core.c +++ b/drivers/mfd/da9150-core.c @@ -471,15 +471,13 @@ regmap_irq_fail: return ret; } -static int da9150_remove(struct i2c_client *client) +static void da9150_remove(struct i2c_client *client) { struct da9150 *da9150 = i2c_get_clientdata(client); regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data); mfd_remove_devices(da9150->dev); i2c_unregister_device(da9150->core_qif); - - return 0; } static void da9150_shutdown(struct i2c_client *client) diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index e5c8bc998eb4..965820481f1e 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -46,14 +46,12 @@ static int __init davinci_vc_probe(struct platform_device *pdev) } clk_enable(davinci_vc->clk); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - fifo_base = (dma_addr_t)res->start; - davinci_vc->base = devm_ioremap_resource(&pdev->dev, res); + davinci_vc->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(davinci_vc->base)) { ret = PTR_ERR(davinci_vc->base); goto fail; } + fifo_base = (dma_addr_t)res->start; davinci_vc->regmap = devm_regmap_init_mmio(&pdev->dev, davinci_vc->base, diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 56c61c99eb23..27a881da4d6e 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -798,7 +798,7 @@ void db8500_prcmu_get_abb_event_buffer(void __iomem **buf) * @opp: The new ARM operating point to which transition is to be made * Returns: 0 on success, non-zero on failure * - * This function sets the the operating point of the ARM. + * This function sets the operating point of the ARM. */ int db8500_prcmu_set_arm_opp(u8 opp) { diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c index 852129ea0766..6cd0b0c752d6 100644 --- a/drivers/mfd/dln2.c +++ b/drivers/mfd/dln2.c @@ -91,11 +91,6 @@ struct dln2_mod_rx_slots { spinlock_t lock; }; -enum dln2_endpoint { - DLN2_EP_OUT = 0, - DLN2_EP_IN = 1, -}; - struct dln2_dev { struct usb_device *usb_dev; struct usb_interface *interface; @@ -777,16 +772,12 @@ static int dln2_probe(struct usb_interface *interface, int ret; int i, j; - if (hostif->desc.bInterfaceNumber != 0 || - hostif->desc.bNumEndpoints < 2) + if (hostif->desc.bInterfaceNumber != 0) return -ENODEV; - epout = &hostif->endpoint[DLN2_EP_OUT].desc; - if (!usb_endpoint_is_bulk_out(epout)) - return -ENODEV; - epin = &hostif->endpoint[DLN2_EP_IN].desc; - if (!usb_endpoint_is_bulk_in(epin)) - return -ENODEV; + ret = usb_find_common_endpoints(hostif, &epin, &epout, NULL, NULL); + if (ret) + return ret; dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL); if (!dln2) diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 54fb6cbd2aa0..759c59690680 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -375,11 +375,10 @@ static void dm355evm_power_off(void) dm355evm_command(MSP_COMMAND_POWEROFF); } -static int dm355evm_msp_remove(struct i2c_client *client) +static void dm355evm_msp_remove(struct i2c_client *client) { pm_power_off = NULL; msp430 = NULL; - return 0; } static int diff --git a/drivers/mfd/ene-kb3930.c b/drivers/mfd/ene-kb3930.c index 1b73318d1f1f..3eff98e26bea 100644 --- a/drivers/mfd/ene-kb3930.c +++ b/drivers/mfd/ene-kb3930.c @@ -177,7 +177,7 @@ static int kb3930_probe(struct i2c_client *client) return 0; } -static int kb3930_remove(struct i2c_client *client) +static void kb3930_remove(struct i2c_client *client) { struct kb3930 *ddata = i2c_get_clientdata(client); @@ -187,8 +187,6 @@ static int kb3930_remove(struct i2c_client *client) unregister_restart_handler(&kb3930_restart_nb); } kb3930_power_off = NULL; - - return 0; } static const struct of_device_id kb3930_dt_ids[] = { diff --git a/drivers/mfd/exynos-lpass.c b/drivers/mfd/exynos-lpass.c index 99bd0e73c19c..166cd21088cd 100644 --- a/drivers/mfd/exynos-lpass.c +++ b/drivers/mfd/exynos-lpass.c @@ -15,7 +15,6 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/mfd/syscon.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 70fa18b04ad2..3d5ce18aa9ae 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -193,13 +193,11 @@ static void pcap_isr_work(struct work_struct *work) ezx_pcap_write(pcap, PCAP_REG_MSR, isr | msr); ezx_pcap_write(pcap, PCAP_REG_ISR, isr); - local_irq_disable(); service = isr & ~msr; for (irq = pcap->irq_base; service; service >>= 1, irq++) { if (service & 1) - generic_handle_irq(irq); + generic_handle_irq_safe(irq); } - local_irq_enable(); ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); } while (gpio_get_value(pdata->gpio)); } @@ -392,7 +390,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, return ret; } -static int ezx_pcap_remove(struct spi_device *spi) +static void ezx_pcap_remove(struct spi_device *spi) { struct pcap_chip *pcap = spi_get_drvdata(spi); unsigned long flags; @@ -412,8 +410,6 @@ static int ezx_pcap_remove(struct spi_device *spi) irq_set_chip_and_handler(i, NULL, NULL); destroy_workqueue(pcap->workqueue); - - return 0; } static int ezx_pcap_probe(struct spi_device *spi) diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index 37e5e02a1d05..823595bcc9b7 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -69,7 +69,7 @@ static int mx25_tsadc_setup_irq(struct platform_device *pdev, int irq; irq = platform_get_irq(pdev, 0); - if (irq <= 0) + if (irq < 0) return irq; tsadc->domain = irq_domain_add_simple(np, 2, 0, &mx25_tsadc_domain_ops, @@ -84,6 +84,19 @@ static int mx25_tsadc_setup_irq(struct platform_device *pdev, return 0; } +static int mx25_tsadc_unset_irq(struct platform_device *pdev) +{ + struct mx25_tsadc *tsadc = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + if (irq >= 0) { + irq_set_chained_handler_and_data(irq, NULL, NULL); + irq_domain_remove(tsadc->domain); + } + + return 0; +} + static void mx25_tsadc_setup_clk(struct platform_device *pdev, struct mx25_tsadc *tsadc) { @@ -171,18 +184,21 @@ static int mx25_tsadc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, tsadc); - return devm_of_platform_populate(dev); + ret = devm_of_platform_populate(dev); + if (ret) + goto err_irq; + + return 0; + +err_irq: + mx25_tsadc_unset_irq(pdev); + + return ret; } static int mx25_tsadc_remove(struct platform_device *pdev) { - struct mx25_tsadc *tsadc = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - if (irq) { - irq_set_chained_handler_and_data(irq, NULL, NULL); - irq_domain_remove(tsadc->domain); - } + mx25_tsadc_unset_irq(pdev); return 0; } diff --git a/drivers/mfd/gateworks-gsc.c b/drivers/mfd/gateworks-gsc.c index d87876747b91..9d7d870c44a8 100644 --- a/drivers/mfd/gateworks-gsc.c +++ b/drivers/mfd/gateworks-gsc.c @@ -255,11 +255,9 @@ static int gsc_probe(struct i2c_client *client) return 0; } -static int gsc_remove(struct i2c_client *client) +static void gsc_remove(struct i2c_client *client) { sysfs_remove_group(&client->dev.kobj, &attr_group); - - return 0; } static struct i2c_driver gsc_driver = { diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index 6909d075d017..a58e42ddcd0c 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -9,14 +9,13 @@ * Fei Wang <w.f@huawei.com> */ -#include <linux/gpio.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/init.h> #include <linux/mfd/core.h> #include <linux/mfd/hi655x-pmic.h> #include <linux/module.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -94,7 +93,6 @@ static int hi655x_pmic_probe(struct platform_device *pdev) int ret; struct hi655x_pmic *pmic; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; void __iomem *base; pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); @@ -120,21 +118,12 @@ static int hi655x_pmic_probe(struct platform_device *pdev) hi655x_local_irq_clear(pmic->regmap); - pmic->gpio = of_get_named_gpio(np, "pmic-gpios", 0); - if (!gpio_is_valid(pmic->gpio)) { - dev_err(dev, "Failed to get the pmic-gpios\n"); - return -ENODEV; - } - - ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, - "hi655x_pmic_irq"); - if (ret < 0) { - dev_err(dev, "Failed to request gpio %d ret = %d\n", - pmic->gpio, ret); - return ret; - } + pmic->gpio = devm_gpiod_get_optional(dev, "pmic", GPIOD_IN); + if (IS_ERR(pmic->gpio)) + return dev_err_probe(dev, PTR_ERR(pmic->gpio), + "Failed to request hi655x pmic-gpio"); - ret = regmap_add_irq_chip(pmic->regmap, gpio_to_irq(pmic->gpio), + ret = regmap_add_irq_chip(pmic->regmap, gpiod_to_irq(pmic->gpio), IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND, 0, &hi655x_irq_chip, &pmic->irq_data); if (ret) { @@ -149,7 +138,7 @@ static int hi655x_pmic_probe(struct platform_device *pdev) regmap_irq_get_domain(pmic->irq_data)); if (ret) { dev_err(dev, "Failed to register device %d\n", ret); - regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data); + regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data); return ret; } @@ -160,7 +149,7 @@ static int hi655x_pmic_remove(struct platform_device *pdev) { struct hi655x_pmic *pmic = platform_get_drvdata(pdev); - regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data); + regmap_del_irq_chip(gpiod_to_irq(pmic->gpio), pmic->irq_data); mfd_remove_devices(&pdev->dev); return 0; } diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 417b0355d904..b45b1346ab54 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -20,7 +20,9 @@ #include <linux/irq.h> #include <linux/spinlock.h> #include <linux/htcpld.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> struct htcpld_chip { @@ -58,8 +60,8 @@ struct htcpld_data { uint irq_start; int nirqs; uint chained_irq; - unsigned int int_reset_gpio_hi; - unsigned int int_reset_gpio_lo; + struct gpio_desc *int_reset_gpio_hi; + struct gpio_desc *int_reset_gpio_lo; /* htcpld info */ struct htcpld_chip *chip; @@ -196,9 +198,9 @@ static irqreturn_t htcpld_handler(int irq, void *dev) * be asserted. */ if (htcpld->int_reset_gpio_hi) - gpio_set_value(htcpld->int_reset_gpio_hi, 1); + gpiod_set_value(htcpld->int_reset_gpio_hi, 1); if (htcpld->int_reset_gpio_lo) - gpio_set_value(htcpld->int_reset_gpio_lo, 0); + gpiod_set_value(htcpld->int_reset_gpio_lo, 0); return IRQ_HANDLED; } @@ -352,7 +354,7 @@ static int htcpld_register_chip_i2c( memset(&info, 0, sizeof(struct i2c_board_info)); info.addr = plat_chip_data->addr; - strlcpy(info.type, "htcpld-chip", I2C_NAME_SIZE); + strscpy(info.type, "htcpld-chip", I2C_NAME_SIZE); info.platform_data = chip; /* Add the I2C device. This calls the probe() function. */ @@ -562,34 +564,28 @@ static int htcpld_core_probe(struct platform_device *pdev) return ret; /* Request the GPIO(s) for the int reset and set them up */ - if (pdata->int_reset_gpio_hi) { - ret = gpio_request(pdata->int_reset_gpio_hi, "htcpld-core"); - if (ret) { - /* - * If it failed, that sucks, but we can probably - * continue on without it. - */ - dev_warn(dev, "Unable to request int_reset_gpio_hi -- interrupts may not work\n"); - htcpld->int_reset_gpio_hi = 0; - } else { - htcpld->int_reset_gpio_hi = pdata->int_reset_gpio_hi; - gpio_set_value(htcpld->int_reset_gpio_hi, 1); - } + htcpld->int_reset_gpio_hi = gpiochip_request_own_desc(&htcpld->chip[2].chip_out, + 7, "htcpld-core", GPIO_ACTIVE_HIGH, + GPIOD_OUT_HIGH); + if (IS_ERR(htcpld->int_reset_gpio_hi)) { + /* + * If it failed, that sucks, but we can probably + * continue on without it. + */ + htcpld->int_reset_gpio_hi = NULL; + dev_warn(dev, "Unable to request int_reset_gpio_hi -- interrupts may not work\n"); } - if (pdata->int_reset_gpio_lo) { - ret = gpio_request(pdata->int_reset_gpio_lo, "htcpld-core"); - if (ret) { - /* - * If it failed, that sucks, but we can probably - * continue on without it. - */ - dev_warn(dev, "Unable to request int_reset_gpio_lo -- interrupts may not work\n"); - htcpld->int_reset_gpio_lo = 0; - } else { - htcpld->int_reset_gpio_lo = pdata->int_reset_gpio_lo; - gpio_set_value(htcpld->int_reset_gpio_lo, 0); - } + htcpld->int_reset_gpio_lo = gpiochip_request_own_desc(&htcpld->chip[2].chip_out, + 0, "htcpld-core", GPIO_ACTIVE_HIGH, + GPIOD_OUT_LOW); + if (IS_ERR(htcpld->int_reset_gpio_lo)) { + /* + * If it failed, that sucks, but we can probably + * continue on without it. + */ + htcpld->int_reset_gpio_lo = NULL; + dev_warn(dev, "Unable to request int_reset_gpio_lo -- interrupts may not work\n"); } dev_info(dev, "Initialized successfully\n"); diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 3f1d976eb67c..a143c8dca2d9 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -15,11 +15,22 @@ #include <linux/pm_runtime.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/pxa2xx_ssp.h> #include "intel-lpss.h" +static const struct property_entry spt_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_SPT_SSP), + { } +}; + +static const struct software_node spt_spi_node = { + .properties = spt_spi_properties, +}; + static const struct intel_lpss_platform_info spt_info = { .clk_rate = 120000000, + .swnode = &spt_spi_node, }; static const struct property_entry spt_i2c_properties[] = { @@ -53,8 +64,18 @@ static const struct intel_lpss_platform_info spt_uart_info = { .swnode = &uart_node, }; +static const struct property_entry bxt_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_BXT_SSP), + { } +}; + +static const struct software_node bxt_spi_node = { + .properties = bxt_spi_properties, +}; + static const struct intel_lpss_platform_info bxt_info = { .clk_rate = 100000000, + .swnode = &bxt_spi_node, }; static const struct property_entry bxt_i2c_properties[] = { @@ -89,6 +110,20 @@ static const struct intel_lpss_platform_info apl_i2c_info = { .swnode = &apl_i2c_node, }; +static const struct property_entry cnl_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_CNL_SSP), + { } +}; + +static const struct software_node cnl_spi_node = { + .properties = cnl_spi_properties, +}; + +static const struct intel_lpss_platform_info cnl_info = { + .clk_rate = 120000000, + .swnode = &cnl_spi_node, +}; + static const struct intel_lpss_platform_info cnl_i2c_info = { .clk_rate = 216000000, .swnode = &spt_i2c_node, @@ -108,8 +143,8 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = { { "INT3449", (kernel_ulong_t)&spt_uart_info }, { "INT344A", (kernel_ulong_t)&spt_uart_info }, /* CNL */ - { "INT34B0", (kernel_ulong_t)&spt_info }, - { "INT34B1", (kernel_ulong_t)&spt_info }, + { "INT34B0", (kernel_ulong_t)&cnl_info }, + { "INT34B1", (kernel_ulong_t)&cnl_info }, { "INT34B2", (kernel_ulong_t)&cnl_i2c_info }, { "INT34B3", (kernel_ulong_t)&cnl_i2c_info }, { "INT34B4", (kernel_ulong_t)&cnl_i2c_info }, @@ -119,7 +154,7 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = { { "INT34B8", (kernel_ulong_t)&spt_uart_info }, { "INT34B9", (kernel_ulong_t)&spt_uart_info }, { "INT34BA", (kernel_ulong_t)&spt_uart_info }, - { "INT34BC", (kernel_ulong_t)&spt_info }, + { "INT34BC", (kernel_ulong_t)&cnl_info }, /* BXT */ { "80860AAC", (kernel_ulong_t)&bxt_i2c_info }, { "80860ABC", (kernel_ulong_t)&bxt_info }, @@ -136,6 +171,7 @@ static int intel_lpss_acpi_probe(struct platform_device *pdev) { struct intel_lpss_platform_info *info; const struct acpi_device_id *id; + int ret; id = acpi_match_device(intel_lpss_acpi_ids, &pdev->dev); if (!id) @@ -149,10 +185,14 @@ static int intel_lpss_acpi_probe(struct platform_device *pdev) info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); info->irq = platform_get_irq(pdev, 0); + ret = intel_lpss_probe(&pdev->dev, info); + if (ret) + return ret; + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - return intel_lpss_probe(&pdev->dev, info); + return 0; } static int intel_lpss_acpi_remove(struct platform_device *pdev) diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index a872b4485eac..dde31c50a632 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -14,9 +14,19 @@ #include <linux/pci.h> #include <linux/pm_runtime.h> #include <linux/property.h> +#include <linux/pxa2xx_ssp.h> #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 int intel_lpss_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -35,6 +45,9 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev, info->mem = &pdev->resource[0]; info->irq = pdev->irq; + if (pci_match_id(ignore_resource_conflicts_ids, pdev)) + info->ignore_resource_conflicts = true; + pdev->d3cold_delay = 0; /* Probably it is enough to set this for iDMA capable devices only */ @@ -61,8 +74,18 @@ static void intel_lpss_pci_remove(struct pci_dev *pdev) static INTEL_LPSS_PM_OPS(intel_lpss_pci_pm_ops); +static const struct property_entry spt_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_SPT_SSP), + { } +}; + +static const struct software_node spt_spi_node = { + .properties = spt_spi_properties, +}; + static const struct intel_lpss_platform_info spt_info = { .clk_rate = 120000000, + .swnode = &spt_spi_node, }; static const struct property_entry spt_i2c_properties[] = { @@ -96,8 +119,18 @@ static const struct intel_lpss_platform_info spt_uart_info = { .swnode = &uart_node, }; +static const struct property_entry bxt_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_BXT_SSP), + { } +}; + +static const struct software_node bxt_spi_node = { + .properties = bxt_spi_properties, +}; + static const struct intel_lpss_platform_info bxt_info = { .clk_rate = 100000000, + .swnode = &bxt_spi_node, }; static const struct intel_lpss_platform_info bxt_uart_info = { @@ -154,6 +187,20 @@ static const struct intel_lpss_platform_info glk_i2c_info = { .swnode = &glk_i2c_node, }; +static const struct property_entry cnl_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_CNL_SSP), + { } +}; + +static const struct software_node cnl_spi_node = { + .properties = cnl_spi_properties, +}; + +static const struct intel_lpss_platform_info cnl_info = { + .clk_rate = 120000000, + .swnode = &cnl_spi_node, +}; + static const struct intel_lpss_platform_info cnl_i2c_info = { .clk_rate = 216000000, .swnode = &spt_i2c_node, @@ -164,12 +211,26 @@ static const struct intel_lpss_platform_info ehl_i2c_info = { .swnode = &bxt_i2c_node, }; +static const struct property_entry tgl_spi_properties[] = { + PROPERTY_ENTRY_U32("intel,spi-pxa2xx-type", LPSS_CNL_SSP), + { } +}; + +static const struct software_node tgl_spi_node = { + .properties = tgl_spi_properties, +}; + +static const struct intel_lpss_platform_info tgl_info = { + .clk_rate = 100000000, + .swnode = &tgl_spi_node, +}; + 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)&spt_info }, - { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&cnl_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 }, @@ -177,18 +238,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)&spt_info }, + { PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&cnl_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)&spt_info }, - { PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x06aa), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x06ab), (kernel_ulong_t)&cnl_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)&spt_info }, + { PCI_VDEVICE(INTEL, 0x06fb), (kernel_ulong_t)&cnl_info }, /* BXT A-Step */ { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info }, @@ -243,8 +304,8 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { /* 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)&spt_info }, - { PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x34aa), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x34ab), (kernel_ulong_t)&cnl_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 }, @@ -252,15 +313,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)&spt_info }, + { PCI_VDEVICE(INTEL, 0x34fb), (kernel_ulong_t)&cnl_info }, /* ICL-N */ - { PCI_VDEVICE(INTEL, 0x38a8), (kernel_ulong_t)&bxt_uart_info }, + { 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)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x43aa), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x43ab), (kernel_ulong_t)&tgl_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 }, @@ -269,8 +330,8 @@ 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)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x43fb), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x43fd), (kernel_ulong_t)&tgl_info }, /* EHL */ { PCI_VDEVICE(INTEL, 0x4b28), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x4b29), (kernel_ulong_t)&bxt_uart_info }, @@ -289,8 +350,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)&spt_info }, - { PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x4daa), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x4dab), (kernel_ulong_t)&cnl_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 }, @@ -298,25 +359,27 @@ 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)&spt_info }, + { PCI_VDEVICE(INTEL, 0x4dfb), (kernel_ulong_t)&cnl_info }, /* ADL-P */ { PCI_VDEVICE(INTEL, 0x51a8), (kernel_ulong_t)&bxt_uart_info }, { PCI_VDEVICE(INTEL, 0x51a9), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x51aa), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x51ab), (kernel_ulong_t)&tgl_info }, { PCI_VDEVICE(INTEL, 0x51c5), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x51c6), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x51c7), (kernel_ulong_t)&bxt_uart_info }, + { PCI_VDEVICE(INTEL, 0x51d8), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x51d9), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x51e8), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x51e9), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x51ea), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x51eb), (kernel_ulong_t)&bxt_i2c_info }, - { PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x51fb), (kernel_ulong_t)&tgl_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)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x54aa), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x54ab), (kernel_ulong_t)&tgl_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 }, @@ -324,7 +387,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)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x54fb), (kernel_ulong_t)&tgl_info }, /* APL */ { PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info }, { PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info }, @@ -341,25 +404,60 @@ static const struct pci_device_id intel_lpss_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x5ac4), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x5ac6), (kernel_ulong_t)&bxt_info }, { PCI_VDEVICE(INTEL, 0x5aee), (kernel_ulong_t)&bxt_uart_info }, + /* 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, 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, 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)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x7aaa), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7aab), (kernel_ulong_t)&tgl_info }, { PCI_VDEVICE(INTEL, 0x7acc), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7acd), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7ace), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7acf), (kernel_ulong_t)&bxt_i2c_info }, { PCI_VDEVICE(INTEL, 0x7adc), (kernel_ulong_t)&bxt_uart_info }, - { PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&bxt_info }, - { PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&bxt_info }, + { PCI_VDEVICE(INTEL, 0x7af9), (kernel_ulong_t)&tgl_info }, + { PCI_VDEVICE(INTEL, 0x7afb), (kernel_ulong_t)&tgl_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, 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 }, + { PCI_VDEVICE(INTEL, 0x7e78), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7e79), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7e7a), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x7e7b), (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, 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 }, + { PCI_VDEVICE(INTEL, 0x98e8), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x98e9), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x98ea), (kernel_ulong_t)&bxt_i2c_info }, + { PCI_VDEVICE(INTEL, 0x98eb), (kernel_ulong_t)&bxt_i2c_info }, /* SPT-LP */ { PCI_VDEVICE(INTEL, 0x9d27), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, @@ -375,8 +473,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)&spt_info }, - { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9daa), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x9dab), (kernel_ulong_t)&cnl_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 }, @@ -384,12 +482,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)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9dfb), (kernel_ulong_t)&cnl_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)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0aa), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0ab), (kernel_ulong_t)&cnl_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 }, @@ -399,15 +497,15 @@ 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)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa0de), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa0df), (kernel_ulong_t)&cnl_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)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa0fd), (kernel_ulong_t)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa0fe), (kernel_ulong_t)&spt_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 }, /* SPT-H */ { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, @@ -430,14 +528,14 @@ 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)&spt_info }, - { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa32a), (kernel_ulong_t)&cnl_info }, + { PCI_VDEVICE(INTEL, 0xa32b), (kernel_ulong_t)&cnl_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)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa37b), (kernel_ulong_t)&cnl_info }, /* CML-V */ { PCI_VDEVICE(INTEL, 0xa3a7), (kernel_ulong_t)&spt_uart_info }, { PCI_VDEVICE(INTEL, 0xa3a8), (kernel_ulong_t)&spt_uart_info }, diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 0e15afc39f54..cfbee2cfba6b 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -401,6 +401,7 @@ int intel_lpss_probe(struct device *dev, return ret; lpss->cell->swnode = info->swnode; + lpss->cell->ignore_resource_conflicts = info->ignore_resource_conflicts; intel_lpss_init_dev(lpss); diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h index 22dbc4aed793..062ce95b68b9 100644 --- a/drivers/mfd/intel-lpss.h +++ b/drivers/mfd/intel-lpss.h @@ -19,6 +19,7 @@ struct software_node; struct intel_lpss_platform_info { struct resource *mem; + bool ignore_resource_conflicts; int irq; unsigned long clk_rate; const char *clk_con_id; diff --git a/drivers/mfd/intel-m10-bmc.c b/drivers/mfd/intel-m10-bmc.c index 8db3bcf5fccc..7e3319e5b22f 100644 --- a/drivers/mfd/intel-m10-bmc.c +++ b/drivers/mfd/intel-m10-bmc.c @@ -21,12 +21,13 @@ enum m10bmc_type { static struct mfd_cell m10bmc_d5005_subdevs[] = { { .name = "d5005bmc-hwmon" }, + { .name = "d5005bmc-sec-update" } }; static struct mfd_cell m10bmc_pacn3000_subdevs[] = { { .name = "n3000bmc-hwmon" }, { .name = "n3000bmc-retimer" }, - { .name = "n3000bmc-secure" }, + { .name = "n3000bmc-sec-update" }, }; static struct mfd_cell m10bmc_n5010_subdevs[] = { diff --git a/drivers/mfd/intel_pmt.c b/drivers/mfd/intel_pmt.c deleted file mode 100644 index dd7eb614c28e..000000000000 --- a/drivers/mfd/intel_pmt.c +++ /dev/null @@ -1,261 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel Platform Monitoring Technology PMT driver - * - * Copyright (c) 2020, Intel Corporation. - * All Rights Reserved. - * - * Author: David E. Box <david.e.box@linux.intel.com> - */ - -#include <linux/bits.h> -#include <linux/kernel.h> -#include <linux/mfd/core.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/platform_device.h> -#include <linux/pm.h> -#include <linux/pm_runtime.h> -#include <linux/types.h> - -/* Intel DVSEC capability vendor space offsets */ -#define INTEL_DVSEC_ENTRIES 0xA -#define INTEL_DVSEC_SIZE 0xB -#define INTEL_DVSEC_TABLE 0xC -#define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0)) -#define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3)) -#define INTEL_DVSEC_ENTRY_SIZE 4 - -/* PMT capabilities */ -#define DVSEC_INTEL_ID_TELEMETRY 2 -#define DVSEC_INTEL_ID_WATCHER 3 -#define DVSEC_INTEL_ID_CRASHLOG 4 - -struct intel_dvsec_header { - u16 length; - u16 id; - u8 num_entries; - u8 entry_size; - u8 tbir; - u32 offset; -}; - -enum pmt_quirks { - /* Watcher capability not supported */ - PMT_QUIRK_NO_WATCHER = BIT(0), - - /* Crashlog capability not supported */ - PMT_QUIRK_NO_CRASHLOG = BIT(1), - - /* Use shift instead of mask to read discovery table offset */ - PMT_QUIRK_TABLE_SHIFT = BIT(2), - - /* DVSEC not present (provided in driver data) */ - PMT_QUIRK_NO_DVSEC = BIT(3), -}; - -struct pmt_platform_info { - unsigned long quirks; - struct intel_dvsec_header **capabilities; -}; - -static const struct pmt_platform_info tgl_info = { - .quirks = PMT_QUIRK_NO_WATCHER | PMT_QUIRK_NO_CRASHLOG | - PMT_QUIRK_TABLE_SHIFT, -}; - -/* DG1 Platform with DVSEC quirk*/ -static struct intel_dvsec_header dg1_telemetry = { - .length = 0x10, - .id = 2, - .num_entries = 1, - .entry_size = 3, - .tbir = 0, - .offset = 0x466000, -}; - -static struct intel_dvsec_header *dg1_capabilities[] = { - &dg1_telemetry, - NULL -}; - -static const struct pmt_platform_info dg1_info = { - .quirks = PMT_QUIRK_NO_DVSEC, - .capabilities = dg1_capabilities, -}; - -static int pmt_add_dev(struct pci_dev *pdev, struct intel_dvsec_header *header, - unsigned long quirks) -{ - struct device *dev = &pdev->dev; - struct resource *res, *tmp; - struct mfd_cell *cell; - const char *name; - int count = header->num_entries; - int size = header->entry_size; - int id = header->id; - int i; - - switch (id) { - case DVSEC_INTEL_ID_TELEMETRY: - name = "pmt_telemetry"; - break; - case DVSEC_INTEL_ID_WATCHER: - if (quirks & PMT_QUIRK_NO_WATCHER) { - dev_info(dev, "Watcher not supported\n"); - return -EINVAL; - } - name = "pmt_watcher"; - break; - case DVSEC_INTEL_ID_CRASHLOG: - if (quirks & PMT_QUIRK_NO_CRASHLOG) { - dev_info(dev, "Crashlog not supported\n"); - return -EINVAL; - } - name = "pmt_crashlog"; - break; - default: - return -EINVAL; - } - - if (!header->num_entries || !header->entry_size) { - dev_err(dev, "Invalid count or size for %s header\n", name); - return -EINVAL; - } - - cell = devm_kzalloc(dev, sizeof(*cell), GFP_KERNEL); - if (!cell) - return -ENOMEM; - - res = devm_kcalloc(dev, count, sizeof(*res), GFP_KERNEL); - if (!res) - return -ENOMEM; - - if (quirks & PMT_QUIRK_TABLE_SHIFT) - header->offset >>= 3; - - /* - * The PMT DVSEC contains the starting offset and count for a block of - * discovery tables, each providing access to monitoring facilities for - * a section of the device. Create a resource list of these tables to - * provide to the driver. - */ - for (i = 0, tmp = res; i < count; i++, tmp++) { - tmp->start = pdev->resource[header->tbir].start + - header->offset + i * (size << 2); - tmp->end = tmp->start + (size << 2) - 1; - tmp->flags = IORESOURCE_MEM; - } - - cell->resources = res; - cell->num_resources = count; - cell->name = name; - - return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cell, 1, NULL, 0, - NULL); -} - -static int pmt_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct pmt_platform_info *info; - unsigned long quirks = 0; - bool found_devices = false; - int ret, pos = 0; - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - info = (struct pmt_platform_info *)id->driver_data; - - if (info) - quirks = info->quirks; - - if (info && (info->quirks & PMT_QUIRK_NO_DVSEC)) { - struct intel_dvsec_header **header; - - header = info->capabilities; - while (*header) { - ret = pmt_add_dev(pdev, *header, quirks); - if (ret) - dev_warn(&pdev->dev, - "Failed to add device for DVSEC id %d\n", - (*header)->id); - else - found_devices = true; - - ++header; - } - } else { - do { - struct intel_dvsec_header header; - u32 table; - u16 vid; - - pos = pci_find_next_ext_capability(pdev, pos, PCI_EXT_CAP_ID_DVSEC); - if (!pos) - break; - - pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vid); - if (vid != PCI_VENDOR_ID_INTEL) - continue; - - pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2, - &header.id); - pci_read_config_byte(pdev, pos + INTEL_DVSEC_ENTRIES, - &header.num_entries); - pci_read_config_byte(pdev, pos + INTEL_DVSEC_SIZE, - &header.entry_size); - pci_read_config_dword(pdev, pos + INTEL_DVSEC_TABLE, - &table); - - header.tbir = INTEL_DVSEC_TABLE_BAR(table); - header.offset = INTEL_DVSEC_TABLE_OFFSET(table); - - ret = pmt_add_dev(pdev, &header, quirks); - if (ret) - continue; - - found_devices = true; - } while (true); - } - - if (!found_devices) - return -ENODEV; - - pm_runtime_put(&pdev->dev); - pm_runtime_allow(&pdev->dev); - - return 0; -} - -static void pmt_pci_remove(struct pci_dev *pdev) -{ - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); -} - -#define PCI_DEVICE_ID_INTEL_PMT_ADL 0x467d -#define PCI_DEVICE_ID_INTEL_PMT_DG1 0x490e -#define PCI_DEVICE_ID_INTEL_PMT_OOBMSM 0x09a7 -#define PCI_DEVICE_ID_INTEL_PMT_TGL 0x9a0d -static const struct pci_device_id pmt_pci_ids[] = { - { PCI_DEVICE_DATA(INTEL, PMT_ADL, &tgl_info) }, - { PCI_DEVICE_DATA(INTEL, PMT_DG1, &dg1_info) }, - { PCI_DEVICE_DATA(INTEL, PMT_OOBMSM, NULL) }, - { PCI_DEVICE_DATA(INTEL, PMT_TGL, &tgl_info) }, - { } -}; -MODULE_DEVICE_TABLE(pci, pmt_pci_ids); - -static struct pci_driver pmt_pci_driver = { - .name = "intel-pmt", - .id_table = pmt_pci_ids, - .probe = pmt_pci_probe, - .remove = pmt_pci_remove, -}; -module_pci_driver(pmt_pci_driver); - -MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>"); -MODULE_DESCRIPTION("Intel Platform Monitoring Technology PMT driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index bc069c4daa60..8dac0d41f64f 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -2,10 +2,11 @@ /* * MFD core driver for Intel Broxton Whiskey Cove PMIC * - * Copyright (C) 2015 Intel Corporation. All rights reserved. + * Copyright (C) 2015-2017, 2022 Intel Corporation. All rights reserved. */ #include <linux/acpi.h> +#include <linux/bits.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/interrupt.h> @@ -18,9 +19,9 @@ #include <asm/intel_scu_ipc.h> /* PMIC device registers */ -#define REG_ADDR_MASK 0xFF00 +#define REG_ADDR_MASK GENMASK(15, 8) #define REG_ADDR_SHIFT 8 -#define REG_OFFSET_MASK 0xFF +#define REG_OFFSET_MASK GENMASK(7, 0) /* Interrupt Status Registers */ #define BXTWC_IRQLVL1 0x4E02 @@ -112,29 +113,29 @@ static const struct regmap_irq bxtwc_regmap_irqs[] = { }; static const struct regmap_irq bxtwc_regmap_irqs_pwrbtn[] = { - REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 0, 0x01), + REGMAP_IRQ_REG(BXTWC_PWRBTN_IRQ, 0, BIT(0)), }; static const struct regmap_irq bxtwc_regmap_irqs_bcu[] = { - REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, 0x1f), + REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 0, GENMASK(4, 0)), }; static const struct regmap_irq bxtwc_regmap_irqs_adc[] = { - REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, 0xff), + REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 0, GENMASK(7, 0)), }; static const struct regmap_irq bxtwc_regmap_irqs_chgr[] = { - REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, 0x20), - REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, 0x1f), - REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, 0x1f), + REGMAP_IRQ_REG(BXTWC_USBC_IRQ, 0, BIT(5)), + REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 0, GENMASK(4, 0)), + REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 1, GENMASK(4, 0)), }; static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { - REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06), + REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, GENMASK(2, 1)), }; static const struct regmap_irq bxtwc_regmap_irqs_crit[] = { - REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, 0x03), + REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 0, GENMASK(1, 0)), }; static struct regmap_irq_chip bxtwc_regmap_irq_chip = { @@ -333,17 +334,19 @@ static unsigned long bxtwc_reg_addr; static ssize_t addr_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "0x%lx\n", bxtwc_reg_addr); + return sysfs_emit(buf, "0x%lx\n", bxtwc_reg_addr); } static ssize_t addr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - if (kstrtoul(buf, 0, &bxtwc_reg_addr)) { - dev_err(dev, "Invalid register address\n"); - return -EINVAL; - } - return (ssize_t)count; + int ret; + + ret = kstrtoul(buf, 0, &bxtwc_reg_addr); + if (ret) + return ret; + + return count; } static ssize_t val_show(struct device *dev, @@ -354,12 +357,12 @@ static ssize_t val_show(struct device *dev, struct intel_soc_pmic *pmic = dev_get_drvdata(dev); ret = regmap_read(pmic->regmap, bxtwc_reg_addr, &val); - if (ret < 0) { + if (ret) { dev_err(dev, "Failed to read 0x%lx\n", bxtwc_reg_addr); - return -EIO; + return ret; } - return sprintf(buf, "0x%02x\n", val); + return sysfs_emit(buf, "0x%02x\n", val); } static ssize_t val_store(struct device *dev, @@ -377,7 +380,7 @@ static ssize_t val_store(struct device *dev, if (ret) { dev_err(dev, "Failed to write value 0x%02x to address 0x%lx", val, bxtwc_reg_addr); - return -EIO; + return ret; } return count; } @@ -394,6 +397,11 @@ static const struct attribute_group bxtwc_group = { .attrs = bxtwc_attrs, }; +static const struct attribute_group *bxtwc_groups[] = { + &bxtwc_group, + NULL +}; + static const struct regmap_config bxtwc_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -410,12 +418,9 @@ static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, int irq; irq = regmap_irq_get_virq(pdata, pirq); - if (irq < 0) { - dev_err(pmic->dev, - "Failed to get parent vIRQ(%d) for chip %s, ret:%d\n", - pirq, chip->name, irq); - return irq; - } + if (irq < 0) + return dev_err_probe(pmic->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); @@ -423,25 +428,19 @@ static int bxtwc_add_chained_irq_chip(struct intel_soc_pmic *pmic, static int bxtwc_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int ret; - acpi_handle handle; acpi_status status; unsigned long long hrv; struct intel_soc_pmic *pmic; - handle = ACPI_HANDLE(&pdev->dev); - status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv); - if (ACPI_FAILURE(status)) { - dev_err(&pdev->dev, "Failed to get PMIC hardware revision\n"); - return -ENODEV; - } - if (hrv != BROXTON_PMIC_WC_HRV) { - dev_err(&pdev->dev, "Invalid PMIC hardware revision: %llu\n", - hrv); - return -ENODEV; - } + status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); + if (ACPI_FAILURE(status)) + return dev_err_probe(dev, -ENODEV, "Failed to get PMIC hardware revision\n"); + if (hrv != BROXTON_PMIC_WC_HRV) + return dev_err_probe(dev, -ENODEV, "Invalid PMIC hardware revision: %llu\n", hrv); - pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; @@ -450,49 +449,39 @@ static int bxtwc_probe(struct platform_device *pdev) return ret; pmic->irq = ret; - dev_set_drvdata(&pdev->dev, pmic); - pmic->dev = &pdev->dev; + platform_set_drvdata(pdev, pmic); + pmic->dev = dev; - pmic->scu = devm_intel_scu_ipc_dev_get(&pdev->dev); + pmic->scu = devm_intel_scu_ipc_dev_get(dev); if (!pmic->scu) return -EPROBE_DEFER; - pmic->regmap = devm_regmap_init(&pdev->dev, NULL, pmic, - &bxtwc_regmap_config); - if (IS_ERR(pmic->regmap)) { - ret = PTR_ERR(pmic->regmap); - dev_err(&pdev->dev, "Failed to initialise regmap: %d\n", ret); - return ret; - } + pmic->regmap = devm_regmap_init(dev, NULL, pmic, &bxtwc_regmap_config); + if (IS_ERR(pmic->regmap)) + return dev_err_probe(dev, PTR_ERR(pmic->regmap), "Failed to initialise regmap\n"); - ret = devm_regmap_add_irq_chip(&pdev->dev, pmic->regmap, pmic->irq, + ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, IRQF_ONESHOT | IRQF_SHARED, 0, &bxtwc_regmap_irq_chip, &pmic->irq_chip_data); - if (ret) { - dev_err(&pdev->dev, "Failed to add IRQ chip\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); 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) { - dev_err(&pdev->dev, "Failed to add PWRBTN IRQ chip\n"); - return ret; - } + 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) { - dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to add TMU IRQ chip\n"); /* Add chained IRQ handler for BCU IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, @@ -500,12 +489,8 @@ static int bxtwc_probe(struct platform_device *pdev) IRQF_ONESHOT, &bxtwc_regmap_irq_chip_bcu, &pmic->irq_chip_data_bcu); - - - if (ret) { - dev_err(&pdev->dev, "Failed to add BUC IRQ chip\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to add BUC IRQ chip\n"); /* Add chained IRQ handler for ADC IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, @@ -513,12 +498,8 @@ static int bxtwc_probe(struct platform_device *pdev) IRQF_ONESHOT, &bxtwc_regmap_irq_chip_adc, &pmic->irq_chip_data_adc); - - - if (ret) { - dev_err(&pdev->dev, "Failed to add ADC IRQ chip\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to add ADC IRQ chip\n"); /* Add chained IRQ handler for CHGR IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, @@ -526,12 +507,8 @@ static int bxtwc_probe(struct platform_device *pdev) IRQF_ONESHOT, &bxtwc_regmap_irq_chip_chgr, &pmic->irq_chip_data_chgr); - - - if (ret) { - dev_err(&pdev->dev, "Failed to add CHGR IRQ chip\n"); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to add CHGR IRQ chip\n"); /* Add chained IRQ handler for CRIT IRQs */ ret = bxtwc_add_chained_irq_chip(pmic, pmic->irq_chip_data, @@ -539,54 +516,33 @@ static int bxtwc_probe(struct platform_device *pdev) IRQF_ONESHOT, &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"); - - if (ret) { - dev_err(&pdev->dev, "Failed to add CRIT IRQ chip\n"); - return ret; - } - - ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, - ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); - if (ret) { - dev_err(&pdev->dev, "Failed to add devices\n"); - return ret; - } - - ret = sysfs_create_group(&pdev->dev.kobj, &bxtwc_group); - if (ret) { - dev_err(&pdev->dev, "Failed to create sysfs group %d\n", ret); - return ret; - } + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, bxt_wc_dev, ARRAY_SIZE(bxt_wc_dev), + NULL, 0, NULL); + if (ret) + return dev_err_probe(dev, ret, "Failed to add devices\n"); /* - * There is known hw bug. Upon reset BIT 5 of register + * There is a known H/W bug. Upon reset, BIT 5 of register * BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However, * later it's set to 1(masked) automatically by hardware. So we - * have the software workaround here to unmaksed it in order to let - * charger interrutp work. + * place the software workaround here to unmask it again in order + * to re-enable the charger interrupt. */ - regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1, - BXTWC_MIRQLVL1_MCHGR, 0); - - return 0; -} - -static int bxtwc_remove(struct platform_device *pdev) -{ - sysfs_remove_group(&pdev->dev.kobj, &bxtwc_group); + regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1, BXTWC_MIRQLVL1_MCHGR, 0); return 0; } static void bxtwc_shutdown(struct platform_device *pdev) { - struct intel_soc_pmic *pmic = dev_get_drvdata(&pdev->dev); + struct intel_soc_pmic *pmic = platform_get_drvdata(pdev); disable_irq(pmic->irq); } -#ifdef CONFIG_PM_SLEEP static int bxtwc_suspend(struct device *dev) { struct intel_soc_pmic *pmic = dev_get_drvdata(dev); @@ -603,8 +559,8 @@ static int bxtwc_resume(struct device *dev) enable_irq(pmic->irq); return 0; } -#endif -static SIMPLE_DEV_PM_OPS(bxtwc_pm_ops, bxtwc_suspend, bxtwc_resume); + +static DEFINE_SIMPLE_DEV_PM_OPS(bxtwc_pm_ops, bxtwc_suspend, bxtwc_resume); static const struct acpi_device_id bxtwc_acpi_ids[] = { { "INT34D3", }, @@ -614,16 +570,16 @@ MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids); static struct platform_driver bxtwc_driver = { .probe = bxtwc_probe, - .remove = bxtwc_remove, .shutdown = bxtwc_shutdown, .driver = { .name = "BXTWC PMIC", - .pm = &bxtwc_pm_ops, - .acpi_match_table = ACPI_PTR(bxtwc_acpi_ids), + .pm = pm_sleep_ptr(&bxtwc_pm_ops), + .acpi_match_table = bxtwc_acpi_ids, + .dev_groups = bxtwc_groups, }, }; module_platform_driver(bxtwc_driver); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Qipeng Zha<qipeng.zha@intel.com>"); +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 1c7577b881ff..282b8fd08009 100644 --- a/drivers/mfd/intel_soc_pmic_chtdc_ti.c +++ b/drivers/mfd/intel_soc_pmic_chtdc_ti.c @@ -140,7 +140,7 @@ static void chtdc_ti_shutdown(struct i2c_client *i2c) disable_irq(pmic->irq); } -static int __maybe_unused chtdc_ti_suspend(struct device *dev) +static int chtdc_ti_suspend(struct device *dev) { struct intel_soc_pmic *pmic = dev_get_drvdata(dev); @@ -149,7 +149,7 @@ static int __maybe_unused chtdc_ti_suspend(struct device *dev) return 0; } -static int __maybe_unused chtdc_ti_resume(struct device *dev) +static int chtdc_ti_resume(struct device *dev) { struct intel_soc_pmic *pmic = dev_get_drvdata(dev); @@ -158,7 +158,7 @@ static int __maybe_unused chtdc_ti_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(chtdc_ti_pm_ops, chtdc_ti_suspend, chtdc_ti_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(chtdc_ti_pm_ops, chtdc_ti_suspend, chtdc_ti_resume); static const struct acpi_device_id chtdc_ti_acpi_ids[] = { { "INT33F5" }, @@ -169,7 +169,7 @@ MODULE_DEVICE_TABLE(acpi, chtdc_ti_acpi_ids); static struct i2c_driver chtdc_ti_i2c_driver = { .driver = { .name = "intel_soc_pmic_chtdc_ti", - .pm = &chtdc_ti_pm_ops, + .pm = pm_sleep_ptr(&chtdc_ti_pm_ops), .acpi_match_table = chtdc_ti_acpi_ids, }, .probe_new = chtdc_ti_probe, diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index 49c5f71664bc..9216f0d34206 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c @@ -10,6 +10,7 @@ #include <linux/acpi.h> #include <linux/delay.h> +#include <linux/dmi.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -134,32 +135,66 @@ static const struct regmap_irq_chip cht_wc_regmap_irq_chip = { .num_regs = 1, }; +static const struct dmi_system_id cht_wc_model_dmi_ids[] = { + { + /* GPD win / GPD pocket mini laptops */ + .driver_data = (void *)(long)INTEL_CHT_WC_GPD_WIN_POCKET, + /* + * This DMI match may not seem unique, but it is. In the 67000+ + * DMI decode dumps from linux-hardware.org only 116 have + * board_vendor set to "AMI Corporation" and of those 116 only + * the GPD win's and pocket's board_name is "Default string". + */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"), + DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"), + }, + }, { + /* Xiaomi Mi Pad 2 */ + .driver_data = (void *)(long)INTEL_CHT_WC_XIAOMI_MIPAD2, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"), + }, + }, { + /* Lenovo Yoga Book X90F / X91F / X91L */ + .driver_data = (void *)(long)INTEL_CHT_WC_LENOVO_YOGABOOK1, + .matches = { + /* Non exact match to match all versions */ + DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"), + }, + }, + { } +}; + static int cht_wc_probe(struct i2c_client *client) { struct device *dev = &client->dev; + const struct dmi_system_id *id; struct intel_soc_pmic *pmic; acpi_status status; unsigned long long hrv; int ret; status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); - if (ACPI_FAILURE(status)) { - dev_err(dev, "Failed to get PMIC hardware revision\n"); - return -ENODEV; - } - if (hrv != CHT_WC_HRV) { - dev_err(dev, "Invalid PMIC hardware revision: %llu\n", hrv); - return -ENODEV; - } - if (client->irq < 0) { - dev_err(dev, "Invalid IRQ\n"); - return -EINVAL; - } + if (ACPI_FAILURE(status)) + return dev_err_probe(dev, -ENODEV, "Failed to get PMIC hardware revision\n"); + if (hrv != CHT_WC_HRV) + return dev_err_probe(dev, -ENODEV, "Invalid PMIC hardware revision: %llu\n", hrv); + + if (client->irq < 0) + return dev_err_probe(dev, -EINVAL, "Invalid IRQ\n"); pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; + id = dmi_first_match(cht_wc_model_dmi_ids); + if (id) + pmic->cht_wc_model = (long)id->driver_data; + pmic->irq = client->irq; pmic->dev = dev; i2c_set_clientdata(client, pmic); @@ -187,7 +222,7 @@ static void cht_wc_shutdown(struct i2c_client *client) disable_irq(pmic->irq); } -static int __maybe_unused cht_wc_suspend(struct device *dev) +static int cht_wc_suspend(struct device *dev) { struct intel_soc_pmic *pmic = dev_get_drvdata(dev); @@ -196,7 +231,7 @@ static int __maybe_unused cht_wc_suspend(struct device *dev) return 0; } -static int __maybe_unused cht_wc_resume(struct device *dev) +static int cht_wc_resume(struct device *dev) { struct intel_soc_pmic *pmic = dev_get_drvdata(dev); @@ -204,7 +239,7 @@ static int __maybe_unused cht_wc_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(cht_wc_pm_ops, cht_wc_suspend, cht_wc_resume); static const struct i2c_device_id cht_wc_i2c_id[] = { { } @@ -218,7 +253,7 @@ static const struct acpi_device_id cht_wc_acpi_ids[] = { static struct i2c_driver cht_wc_driver = { .driver = { .name = "CHT Whiskey Cove PMIC", - .pm = &cht_wc_pm_ops, + .pm = pm_sleep_ptr(&cht_wc_pm_ops), .acpi_match_table = cht_wc_acpi_ids, }, .probe_new = cht_wc_probe, diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c deleted file mode 100644 index ddd64f9e3341..000000000000 --- a/drivers/mfd/intel_soc_pmic_core.c +++ /dev/null @@ -1,178 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel SoC PMIC MFD Driver - * - * Copyright (C) 2013, 2014 Intel Corporation. All rights reserved. - * - * Author: Yang, Bin <bin.yang@intel.com> - * Author: Zhu, Lejun <lejun.zhu@linux.intel.com> - */ - -#include <linux/acpi.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/mfd/core.h> -#include <linux/mfd/intel_soc_pmic.h> -#include <linux/pwm.h> -#include <linux/regmap.h> - -#include "intel_soc_pmic_core.h" - -/* Crystal Cove PMIC shares same ACPI ID between different platforms */ -#define BYT_CRC_HRV 2 -#define CHT_CRC_HRV 3 - -/* 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), -}; - -static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *i2c_id) -{ - struct device *dev = &i2c->dev; - struct intel_soc_pmic_config *config; - struct intel_soc_pmic *pmic; - unsigned long long hrv; - acpi_status status; - int ret; - - /* - * There are 2 different Crystal Cove PMICs a Bay Trail and Cherry - * Trail version, use _HRV to differentiate between the 2. - */ - status = acpi_evaluate_integer(ACPI_HANDLE(dev), "_HRV", NULL, &hrv); - if (ACPI_FAILURE(status)) { - dev_err(dev, "Failed to get PMIC hardware revision\n"); - return -ENODEV; - } - - switch (hrv) { - case BYT_CRC_HRV: - config = &intel_soc_pmic_config_byt_crc; - break; - case CHT_CRC_HRV: - config = &intel_soc_pmic_config_cht_crc; - break; - default: - dev_warn(dev, "Unknown hardware rev %llu, assuming BYT\n", hrv); - config = &intel_soc_pmic_config_byt_crc; - } - - pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); - if (!pmic) - return -ENOMEM; - - dev_set_drvdata(dev, pmic); - - pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config); - if (IS_ERR(pmic->regmap)) - return PTR_ERR(pmic->regmap); - - pmic->irq = i2c->irq; - - ret = regmap_add_irq_chip(pmic->regmap, pmic->irq, - config->irq_flags | IRQF_ONESHOT, - 0, config->irq_chip, - &pmic->irq_chip_data); - if (ret) - return ret; - - ret = enable_irq_wake(pmic->irq); - if (ret) - dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret); - - /* Add lookup table for crc-pwm */ - pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); - - ret = mfd_add_devices(dev, -1, config->cell_dev, - config->n_cell_devs, NULL, 0, - regmap_irq_get_domain(pmic->irq_chip_data)); - if (ret) - goto err_del_irq_chip; - - return 0; - -err_del_irq_chip: - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); - return ret; -} - -static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c) -{ - struct intel_soc_pmic *pmic = dev_get_drvdata(&i2c->dev); - - regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); - - /* remove crc-pwm lookup table */ - pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); - - mfd_remove_devices(&i2c->dev); - - return 0; -} - -static void intel_soc_pmic_shutdown(struct i2c_client *i2c) -{ - struct intel_soc_pmic *pmic = dev_get_drvdata(&i2c->dev); - - disable_irq(pmic->irq); - - return; -} - -#if defined(CONFIG_PM_SLEEP) -static int intel_soc_pmic_suspend(struct device *dev) -{ - struct intel_soc_pmic *pmic = dev_get_drvdata(dev); - - disable_irq(pmic->irq); - - return 0; -} - -static int intel_soc_pmic_resume(struct device *dev) -{ - struct intel_soc_pmic *pmic = dev_get_drvdata(dev); - - enable_irq(pmic->irq); - - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend, - intel_soc_pmic_resume); - -static const struct i2c_device_id intel_soc_pmic_i2c_id[] = { - { } -}; -MODULE_DEVICE_TABLE(i2c, intel_soc_pmic_i2c_id); - -#if defined(CONFIG_ACPI) -static const struct acpi_device_id intel_soc_pmic_acpi_match[] = { - { "INT33FD" }, - { }, -}; -MODULE_DEVICE_TABLE(acpi, intel_soc_pmic_acpi_match); -#endif - -static struct i2c_driver intel_soc_pmic_i2c_driver = { - .driver = { - .name = "intel_soc_pmic_i2c", - .pm = &intel_soc_pmic_pm_ops, - .acpi_match_table = ACPI_PTR(intel_soc_pmic_acpi_match), - }, - .probe = intel_soc_pmic_i2c_probe, - .remove = intel_soc_pmic_i2c_remove, - .id_table = intel_soc_pmic_i2c_id, - .shutdown = intel_soc_pmic_shutdown, -}; - -module_i2c_driver(intel_soc_pmic_i2c_driver); - -MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>"); -MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>"); diff --git a/drivers/mfd/intel_soc_pmic_core.h b/drivers/mfd/intel_soc_pmic_core.h deleted file mode 100644 index d490685845eb..000000000000 --- a/drivers/mfd/intel_soc_pmic_core.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Intel SoC PMIC MFD Driver - * - * Copyright (C) 2012-2014 Intel Corporation. All rights reserved. - * - * Author: Yang, Bin <bin.yang@intel.com> - * Author: Zhu, Lejun <lejun.zhu@linux.intel.com> - */ - -#ifndef __INTEL_SOC_PMIC_CORE_H__ -#define __INTEL_SOC_PMIC_CORE_H__ - -struct intel_soc_pmic_config { - unsigned long irq_flags; - struct mfd_cell *cell_dev; - int n_cell_devs; - const struct regmap_config *regmap_config; - const struct regmap_irq_chip *irq_chip; -}; - -extern struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc; -extern struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc; - -#endif /* __INTEL_SOC_PMIC_CORE_H__ */ diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 38acb20e2d60..b1548a933dc3 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -2,18 +2,21 @@ /* * Device access for Crystal Cove PMIC * - * Copyright (C) 2013, 2014 Intel Corporation. All rights reserved. + * Copyright (C) 2012-2014, 2022 Intel Corporation. All rights reserved. * * Author: Yang, Bin <bin.yang@intel.com> * Author: Zhu, Lejun <lejun.zhu@linux.intel.com> */ +#include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/regmap.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/mfd/core.h> #include <linux/mfd/intel_soc_pmic.h> - -#include "intel_soc_pmic_core.h" +#include <linux/platform_data/x86/soc.h> +#include <linux/pwm.h> +#include <linux/regmap.h> #define CRYSTAL_COVE_MAX_REGISTER 0xC6 @@ -28,18 +31,10 @@ #define CRYSTAL_COVE_IRQ_GPIO 5 #define CRYSTAL_COVE_IRQ_VHDMIOCP 6 -static const struct resource gpio_resources[] = { - DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"), -}; - static const struct resource pwrsrc_resources[] = { DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_PWRSRC, "PWRSRC"), }; -static const struct resource adc_resources[] = { - DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"), -}; - static const struct resource thermal_resources[] = { DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_THRM, "THERMAL"), }; @@ -48,6 +43,18 @@ static const struct resource bcu_resources[] = { DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_BCU, "BCU"), }; +static const struct resource adc_resources[] = { + DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"), +}; + +static const struct resource charger_resources[] = { + DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_CHGR, "CHGR"), +}; + +static const struct resource gpio_resources[] = { + DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"), +}; + static struct mfd_cell crystal_cove_byt_dev[] = { { .name = "crystal_cove_pwrsrc", @@ -55,11 +62,6 @@ static struct mfd_cell crystal_cove_byt_dev[] = { .resources = pwrsrc_resources, }, { - .name = "crystal_cove_adc", - .num_resources = ARRAY_SIZE(adc_resources), - .resources = adc_resources, - }, - { .name = "crystal_cove_thermal", .num_resources = ARRAY_SIZE(thermal_resources), .resources = thermal_resources, @@ -70,6 +72,16 @@ static struct mfd_cell crystal_cove_byt_dev[] = { .resources = bcu_resources, }, { + .name = "crystal_cove_adc", + .num_resources = ARRAY_SIZE(adc_resources), + .resources = adc_resources, + }, + { + .name = "crystal_cove_charger", + .num_resources = ARRAY_SIZE(charger_resources), + .resources = charger_resources, + }, + { .name = "crystal_cove_gpio", .num_resources = ARRAY_SIZE(gpio_resources), .resources = gpio_resources, @@ -123,7 +135,20 @@ static const struct regmap_irq_chip crystal_cove_irq_chip = { .mask_base = CRYSTAL_COVE_REG_MIRQLVL1, }; -struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc = { +/* 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), +}; + +struct crystal_cove_config { + unsigned long irq_flags; + struct mfd_cell *cell_dev; + int n_cell_devs; + const struct regmap_config *regmap_config; + const struct regmap_irq_chip *irq_chip; +}; + +static const struct crystal_cove_config crystal_cove_config_byt_crc = { .irq_flags = IRQF_TRIGGER_RISING, .cell_dev = crystal_cove_byt_dev, .n_cell_devs = ARRAY_SIZE(crystal_cove_byt_dev), @@ -131,10 +156,121 @@ struct intel_soc_pmic_config intel_soc_pmic_config_byt_crc = { .irq_chip = &crystal_cove_irq_chip, }; -struct intel_soc_pmic_config intel_soc_pmic_config_cht_crc = { +static const struct crystal_cove_config crystal_cove_config_cht_crc = { .irq_flags = IRQF_TRIGGER_RISING, .cell_dev = crystal_cove_cht_dev, .n_cell_devs = ARRAY_SIZE(crystal_cove_cht_dev), .regmap_config = &crystal_cove_regmap_config, .irq_chip = &crystal_cove_irq_chip, }; + +static int crystal_cove_i2c_probe(struct i2c_client *i2c) +{ + const struct crystal_cove_config *config; + struct device *dev = &i2c->dev; + struct intel_soc_pmic *pmic; + int ret; + + if (soc_intel_is_byt()) + config = &crystal_cove_config_byt_crc; + else + config = &crystal_cove_config_cht_crc; + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + i2c_set_clientdata(i2c, pmic); + + pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config); + if (IS_ERR(pmic->regmap)) + return PTR_ERR(pmic->regmap); + + pmic->irq = i2c->irq; + + ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, + config->irq_flags | IRQF_ONESHOT, + 0, config->irq_chip, &pmic->irq_chip_data); + if (ret) + return ret; + + ret = enable_irq_wake(pmic->irq); + if (ret) + dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret); + + /* Add lookup table for crc-pwm */ + pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); + + /* To distuingish this domain from the GPIO/charger's irqchip domains */ + irq_domain_update_bus_token(regmap_irq_get_domain(pmic->irq_chip_data), + DOMAIN_BUS_NEXUS); + + ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, config->cell_dev, + config->n_cell_devs, NULL, 0, + regmap_irq_get_domain(pmic->irq_chip_data)); + if (ret) + pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); + + return ret; +} + +static void crystal_cove_i2c_remove(struct i2c_client *i2c) +{ + /* remove crc-pwm lookup table */ + pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); + + mfd_remove_devices(&i2c->dev); +} + +static void crystal_cove_shutdown(struct i2c_client *i2c) +{ + struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c); + + disable_irq(pmic->irq); + + return; +} + +static int crystal_cove_suspend(struct device *dev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + disable_irq(pmic->irq); + + return 0; +} + +static int crystal_cove_resume(struct device *dev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + enable_irq(pmic->irq); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(crystal_cove_pm_ops, crystal_cove_suspend, crystal_cove_resume); + +static const struct acpi_device_id crystal_cove_acpi_match[] = { + { "INT33FD" }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, crystal_cove_acpi_match); + +static struct i2c_driver crystal_cove_i2c_driver = { + .driver = { + .name = "crystal_cove_i2c", + .pm = pm_sleep_ptr(&crystal_cove_pm_ops), + .acpi_match_table = crystal_cove_acpi_match, + }, + .probe_new = crystal_cove_i2c_probe, + .remove = crystal_cove_i2c_remove, + .shutdown = crystal_cove_shutdown, +}; + +module_i2c_driver(crystal_cove_i2c_driver); + +MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>"); +MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>"); diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index e92eeeb67a98..4cd5ecc72211 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -403,7 +403,7 @@ static int __init micro_probe(struct platform_device *pdev) micro_reset_comm(micro); irq = platform_get_irq(pdev, 0); - if (!irq) + if (irq < 0) return -EINVAL; ret = devm_request_irq(&pdev->dev, irq, micro_serial_isr, IRQF_SHARED, "ipaq-micro", diff --git a/drivers/mfd/iqs62x.c b/drivers/mfd/iqs62x.c index 9805cf191245..1895fce25b06 100644 --- a/drivers/mfd/iqs62x.c +++ b/drivers/mfd/iqs62x.c @@ -898,7 +898,6 @@ static int iqs62x_probe(struct i2c_client *client) struct iqs62x_info info; unsigned int val; int ret, i, j; - u8 sw_num = 0; const char *fw_name = NULL; iqs62x = devm_kzalloc(&client->dev, sizeof(*iqs62x), GFP_KERNEL); @@ -949,7 +948,8 @@ static int iqs62x_probe(struct i2c_client *client) if (info.sw_num < iqs62x->dev_desc->sw_num) continue; - sw_num = info.sw_num; + iqs62x->sw_num = info.sw_num; + iqs62x->hw_num = info.hw_num; /* * Read each of the device's designated calibration registers, @@ -985,7 +985,7 @@ static int iqs62x_probe(struct i2c_client *client) return -EINVAL; } - if (!sw_num) { + if (!iqs62x->sw_num) { dev_err(&client->dev, "Unrecognized software number: 0x%02X\n", info.sw_num); return -EINVAL; @@ -1008,13 +1008,11 @@ static int iqs62x_probe(struct i2c_client *client) return ret; } -static int iqs62x_remove(struct i2c_client *client) +static void iqs62x_remove(struct i2c_client *client) { struct iqs62x_core *iqs62x = i2c_get_clientdata(client); wait_for_completion(&iqs62x->fw_done); - - return 0; } static int __maybe_unused iqs62x_suspend(struct device *dev) diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 5690768f3e63..be32ffc5af38 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -607,15 +607,13 @@ static int lm3533_i2c_probe(struct i2c_client *i2c, return lm3533_device_init(lm3533); } -static int lm3533_i2c_remove(struct i2c_client *i2c) +static void lm3533_i2c_remove(struct i2c_client *i2c) { struct lm3533 *lm3533 = i2c_get_clientdata(i2c); dev_dbg(&i2c->dev, "%s\n", __func__); lm3533_device_exit(lm3533); - - return 0; } static const struct i2c_device_id lm3533_i2c_ids[] = { diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c index 858c9e0a49a4..b6166dec492d 100644 --- a/drivers/mfd/lp873x.c +++ b/drivers/mfd/lp873x.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/ * * Author: Keerthy <j-keerthy@ti.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/interrupt.h> diff --git a/drivers/mfd/lp8788-irq.c b/drivers/mfd/lp8788-irq.c index 348439a3fbbd..39006297f3d2 100644 --- a/drivers/mfd/lp8788-irq.c +++ b/drivers/mfd/lp8788-irq.c @@ -175,6 +175,7 @@ int lp8788_irq_init(struct lp8788 *lp, int irq) IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lp8788-irq", irqd); if (ret) { + irq_domain_remove(lp->irqdm); dev_err(lp->dev, "failed to create a thread for IRQ_N\n"); return ret; } @@ -188,4 +189,6 @@ void lp8788_irq_exit(struct lp8788 *lp) { if (lp->irq) free_irq(lp->irq, lp->irqdm); + if (lp->irqdm) + irq_domain_remove(lp->irqdm); } diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index c223d2c6a363..724a5712b36b 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -195,17 +195,24 @@ static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) if (ret) return ret; - return mfd_add_devices(lp->dev, -1, lp8788_devs, - ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); + ret = mfd_add_devices(lp->dev, -1, lp8788_devs, + ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); + if (ret) + goto err_exit_irq; + + return 0; + +err_exit_irq: + lp8788_irq_exit(lp); + return ret; } -static int lp8788_remove(struct i2c_client *cl) +static void lp8788_remove(struct i2c_client *cl) { struct lp8788 *lp = i2c_get_clientdata(cl); mfd_remove_devices(lp->dev); lp8788_irq_exit(lp); - return 0; } static const struct i2c_device_id lp8788_ids[] = { diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index f10e53187f67..7b1c597b6879 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -8,7 +8,8 @@ * Configuration Registers. * * This driver is derived from lpc_sch. - + * + * Copyright (c) 2017, 2021-2022 Intel Corporation * Copyright (c) 2011 Extreme Engineering Solution, Inc. * Author: Aaron Sierra <asierra@xes-inc.com> * @@ -42,9 +43,11 @@ #include <linux/errno.h> #include <linux/acpi.h> #include <linux/pci.h> +#include <linux/pinctrl/pinctrl.h> #include <linux/mfd/core.h> #include <linux/mfd/lpc_ich.h> #include <linux/platform_data/itco_wdt.h> +#include <linux/platform_data/x86/p2sb.h> #define ACPIBASE 0x40 #define ACPIBASE_GPE_OFF 0x28 @@ -63,14 +66,14 @@ #define SPIBASE_BYT 0x54 #define SPIBASE_BYT_SZ 512 #define SPIBASE_BYT_EN BIT(1) +#define BYT_BCR 0xfc +#define BYT_BCR_WPD BIT(0) #define SPIBASE_LPT 0x3800 #define SPIBASE_LPT_SZ 512 #define BCR 0xdc #define BCR_WPD BIT(0) -#define SPIBASE_APL_SZ 4096 - #define GPIOBASE_ICH0 0x58 #define GPIOCTRL_ICH0 0x5C #define GPIOBASE_ICH6 0x48 @@ -141,6 +144,73 @@ static struct mfd_cell lpc_ich_gpio_cell = { .ignore_resource_conflicts = true, }; +#define APL_GPIO_NORTH 0 +#define APL_GPIO_NORTHWEST 1 +#define APL_GPIO_WEST 2 +#define APL_GPIO_SOUTHWEST 3 +#define APL_GPIO_NR_DEVICES 4 + +/* Offset data for Apollo Lake GPIO controllers */ +static resource_size_t apl_gpio_offsets[APL_GPIO_NR_DEVICES] = { + [APL_GPIO_NORTH] = 0xc50000, + [APL_GPIO_NORTHWEST] = 0xc40000, + [APL_GPIO_WEST] = 0xc70000, + [APL_GPIO_SOUTHWEST] = 0xc00000, +}; + +#define APL_GPIO_RESOURCE_SIZE 0x1000 + +#define APL_GPIO_IRQ 14 + +static struct resource apl_gpio_resources[APL_GPIO_NR_DEVICES][2] = { + [APL_GPIO_NORTH] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, + [APL_GPIO_NORTHWEST] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, + [APL_GPIO_WEST] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, + [APL_GPIO_SOUTHWEST] = { + DEFINE_RES_MEM(0, 0), + DEFINE_RES_IRQ(APL_GPIO_IRQ), + }, +}; + +static const struct mfd_cell apl_gpio_devices[APL_GPIO_NR_DEVICES] = { + [APL_GPIO_NORTH] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_NORTH, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTH]), + .resources = apl_gpio_resources[APL_GPIO_NORTH], + .ignore_resource_conflicts = true, + }, + [APL_GPIO_NORTHWEST] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_NORTHWEST, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTHWEST]), + .resources = apl_gpio_resources[APL_GPIO_NORTHWEST], + .ignore_resource_conflicts = true, + }, + [APL_GPIO_WEST] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_WEST, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_WEST]), + .resources = apl_gpio_resources[APL_GPIO_WEST], + .ignore_resource_conflicts = true, + }, + [APL_GPIO_SOUTHWEST] = { + .name = "apollolake-pinctrl", + .id = APL_GPIO_SOUTHWEST, + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_SOUTHWEST]), + .resources = apl_gpio_resources[APL_GPIO_SOUTHWEST], + .ignore_resource_conflicts = true, + }, +}; static struct mfd_cell lpc_ich_spi_cell = { .name = "intel-spi", @@ -889,7 +959,7 @@ static int lpc_ich_finalize_wdt_cell(struct pci_dev *dev) info = &lpc_chipset_info[priv->chipset]; pdata->version = info->iTCO_version; - strlcpy(pdata->name, info->name, sizeof(pdata->name)); + strscpy(pdata->name, info->name, sizeof(pdata->name)); cell->platform_data = pdata; cell->pdata_size = sizeof(*pdata); @@ -1084,12 +1154,83 @@ wdt_done: return ret; } +static int lpc_ich_init_pinctrl(struct pci_dev *dev) +{ + struct resource base; + unsigned int i; + int ret; + + /* Check, if GPIO has been exported as an ACPI device */ + if (acpi_dev_present("INT3452", NULL, -1)) + return -EEXIST; + + ret = p2sb_bar(dev->bus, 0, &base); + if (ret) + return ret; + + for (i = 0; i < ARRAY_SIZE(apl_gpio_devices); i++) { + struct resource *mem = &apl_gpio_resources[i][0]; + resource_size_t offset = apl_gpio_offsets[i]; + + /* Fill MEM resource */ + mem->start = base.start + offset; + mem->end = base.start + offset + APL_GPIO_RESOURCE_SIZE - 1; + mem->flags = base.flags; + } + + return mfd_add_devices(&dev->dev, 0, apl_gpio_devices, + ARRAY_SIZE(apl_gpio_devices), NULL, 0, NULL); +} + +static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data) +{ + u32 val; + + val = readl(base + BYT_BCR); + if (!(val & BYT_BCR_WPD)) { + val |= BYT_BCR_WPD; + writel(val, base + BYT_BCR); + val = readl(base + BYT_BCR); + } + + return val & BYT_BCR_WPD; +} + +static bool lpc_ich_set_writeable(struct pci_bus *bus, unsigned int devfn) +{ + u32 bcr; + + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_bus_write_config_dword(bus, devfn, BCR, bcr); + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); + } + + return bcr & BCR_WPD; +} + +static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) +{ + struct pci_dev *pdev = data; + + return lpc_ich_set_writeable(pdev->bus, pdev->devfn); +} + +static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data) +{ + struct pci_dev *pdev = data; + + return lpc_ich_set_writeable(pdev->bus, PCI_DEVFN(13, 2)); +} + static int lpc_ich_init_spi(struct pci_dev *dev) { struct lpc_ich_priv *priv = pci_get_drvdata(dev); struct resource *res = &intel_spi_res[0]; struct intel_spi_boardinfo *info; - u32 spi_base, rcba, bcr; + u32 spi_base, rcba; + int ret; info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -1103,6 +1244,8 @@ static int lpc_ich_init_spi(struct pci_dev *dev) if (spi_base & SPIBASE_BYT_EN) { res->start = spi_base & ~(SPIBASE_BYT_SZ - 1); res->end = res->start + SPIBASE_BYT_SZ - 1; + + info->set_writeable = lpc_ich_byt_set_writeable; } break; @@ -1113,35 +1256,24 @@ static int lpc_ich_init_spi(struct pci_dev *dev) res->start = spi_base + SPIBASE_LPT; res->end = res->start + SPIBASE_LPT_SZ - 1; - pci_read_config_dword(dev, BCR, &bcr); - info->writeable = !!(bcr & BCR_WPD); + info->set_writeable = lpc_ich_lpt_set_writeable; + info->data = dev; } break; - case INTEL_SPI_BXT: { - unsigned int p2sb = PCI_DEVFN(13, 0); - unsigned int spi = PCI_DEVFN(13, 2); - struct pci_bus *bus = dev->bus; - + case INTEL_SPI_BXT: /* * The P2SB is hidden by BIOS and we need to unhide it in * order to read BAR of the SPI flash device. Once that is * done we hide it again. */ - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x0); - pci_bus_read_config_dword(bus, spi, PCI_BASE_ADDRESS_0, - &spi_base); - if (spi_base != ~0) { - res->start = spi_base & 0xfffffff0; - res->end = res->start + SPIBASE_APL_SZ - 1; - - pci_bus_read_config_dword(bus, spi, BCR, &bcr); - info->writeable = !!(bcr & BCR_WPD); - } + ret = p2sb_bar(dev->bus, PCI_DEVFN(13, 2), res); + if (ret) + return ret; - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1); + info->set_writeable = lpc_ich_bxt_set_writeable; + info->data = dev; break; - } default: return -EINVAL; @@ -1200,6 +1332,12 @@ static int lpc_ich_probe(struct pci_dev *dev, cell_added = true; } + if (priv->chipset == LPC_APL) { + ret = lpc_ich_init_pinctrl(dev); + if (!ret) + cell_added = true; + } + if (lpc_chipset_info[priv->chipset].spi_type) { ret = lpc_ich_init_spi(dev); if (!ret) diff --git a/drivers/mfd/madera-i2c.c b/drivers/mfd/madera-i2c.c index 7df5b9ba5855..915d2f95bad3 100644 --- a/drivers/mfd/madera-i2c.c +++ b/drivers/mfd/madera-i2c.c @@ -112,13 +112,11 @@ static int madera_i2c_probe(struct i2c_client *i2c, return madera_dev_init(madera); } -static int madera_i2c_remove(struct i2c_client *i2c) +static void madera_i2c_remove(struct i2c_client *i2c) { struct madera *madera = dev_get_drvdata(&i2c->dev); madera_dev_exit(madera); - - return 0; } static const struct i2c_device_id madera_i2c_id[] = { diff --git a/drivers/mfd/madera-spi.c b/drivers/mfd/madera-spi.c index e860f5ff0933..da84eb50e53a 100644 --- a/drivers/mfd/madera-spi.c +++ b/drivers/mfd/madera-spi.c @@ -112,13 +112,11 @@ static int madera_spi_probe(struct spi_device *spi) return madera_dev_init(madera); } -static int madera_spi_remove(struct spi_device *spi) +static void madera_spi_remove(struct spi_device *spi) { struct madera *madera = spi_get_drvdata(spi); madera_dev_exit(madera); - - return 0; } static const struct spi_device_id madera_spi_ids[] = { diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 6c487fa14e9c..d44ad6f33742 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -463,7 +463,7 @@ err_max77836: return ret; } -static int max14577_i2c_remove(struct i2c_client *i2c) +static void max14577_i2c_remove(struct i2c_client *i2c) { struct max14577 *max14577 = i2c_get_clientdata(i2c); @@ -471,8 +471,6 @@ static int max14577_i2c_remove(struct i2c_client *i2c) regmap_del_irq_chip(max14577->irq, max14577->irq_data); if (max14577->dev_type == MAXIM_DEVICE_TYPE_MAX77836) max77836_remove(max14577); - - return 0; } static const struct i2c_device_id max14577_i2c_id[] = { diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index fec2096474ad..a6661e07035b 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -419,9 +419,11 @@ static int max77620_initialise_fps(struct max77620_chip *chip) ret = max77620_config_fps(chip, fps_child); if (ret < 0) { of_node_put(fps_child); + of_node_put(fps_np); return ret; } } + of_node_put(fps_np); config = chip->enable_global_lpm ? MAX77620_ONOFFCNFG2_SLP_LPM_MSK : 0; ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index f9e12ab2bc75..2ac64277fb84 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -87,7 +87,7 @@ static bool max77802_rtc_is_volatile_reg(struct device *dev, unsigned int reg) reg == MAX77802_RTC_WEEKDAY || reg == MAX77802_RTC_MONTH || reg == MAX77802_RTC_YEAR || - reg == MAX77802_RTC_DATE); + reg == MAX77802_RTC_MONTHDAY); } static bool max77802_is_volatile_reg(struct device *dev, unsigned int reg) diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 4e6244e17559..7088cb6f9174 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -294,7 +294,7 @@ err_i2c_haptic: return ret; } -static int max77693_i2c_remove(struct i2c_client *i2c) +static void max77693_i2c_remove(struct i2c_client *i2c) { struct max77693_dev *max77693 = i2c_get_clientdata(i2c); @@ -307,8 +307,6 @@ static int max77693_i2c_remove(struct i2c_client *i2c) i2c_unregister_device(max77693->i2c_muic); i2c_unregister_device(max77693->i2c_haptic); - - return 0; } static const struct i2c_device_id max77693_i2c_id[] = { diff --git a/drivers/mfd/max77714.c b/drivers/mfd/max77714.c new file mode 100644 index 000000000000..143a432ea343 --- /dev/null +++ b/drivers/mfd/max77714.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Maxim MAX77714 Core Driver + * + * Copyright (C) 2022 Luca Ceresoli + * Author: Luca Ceresoli <luca.ceresoli@bootlin.com> + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mfd/core.h> +#include <linux/mfd/max77714.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> + +static const struct mfd_cell max77714_cells[] = { + { .name = "max77714-watchdog" }, + { .name = "max77714-rtc" }, +}; + +static const struct regmap_range max77714_readable_ranges[] = { + regmap_reg_range(MAX77714_INT_TOP, MAX77714_INT_TOP), + regmap_reg_range(MAX77714_INT_TOPM, MAX77714_INT_TOPM), + regmap_reg_range(MAX77714_32K_STATUS, MAX77714_32K_CONFIG), + regmap_reg_range(MAX77714_CNFG_GLBL2, MAX77714_CNFG2_ONOFF), +}; + +static const struct regmap_range max77714_writable_ranges[] = { + regmap_reg_range(MAX77714_INT_TOPM, MAX77714_INT_TOPM), + regmap_reg_range(MAX77714_32K_CONFIG, MAX77714_32K_CONFIG), + regmap_reg_range(MAX77714_CNFG_GLBL2, MAX77714_CNFG2_ONOFF), +}; + +static const struct regmap_access_table max77714_readable_table = { + .yes_ranges = max77714_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(max77714_readable_ranges), +}; + +static const struct regmap_access_table max77714_writable_table = { + .yes_ranges = max77714_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(max77714_writable_ranges), +}; + +static const struct regmap_config max77714_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX77714_CNFG2_ONOFF, + .rd_table = &max77714_readable_table, + .wr_table = &max77714_writable_table, +}; + +static const struct regmap_irq max77714_top_irqs[] = { + REGMAP_IRQ_REG(MAX77714_IRQ_TOP_ONOFF, 0, MAX77714_INT_TOP_ONOFF), + REGMAP_IRQ_REG(MAX77714_IRQ_TOP_RTC, 0, MAX77714_INT_TOP_RTC), + REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GPIO, 0, MAX77714_INT_TOP_GPIO), + REGMAP_IRQ_REG(MAX77714_IRQ_TOP_LDO, 0, MAX77714_INT_TOP_LDO), + REGMAP_IRQ_REG(MAX77714_IRQ_TOP_SD, 0, MAX77714_INT_TOP_SD), + REGMAP_IRQ_REG(MAX77714_IRQ_TOP_GLBL, 0, MAX77714_INT_TOP_GLBL), +}; + +static const struct regmap_irq_chip max77714_irq_chip = { + .name = "max77714-pmic", + .status_base = MAX77714_INT_TOP, + .mask_base = MAX77714_INT_TOPM, + .num_regs = 1, + .irqs = max77714_top_irqs, + .num_irqs = ARRAY_SIZE(max77714_top_irqs), +}; + +/* + * MAX77714 initially uses the internal, low precision oscillator. Enable + * the external oscillator by setting the XOSC_RETRY bit. If the external + * oscillator is not OK (probably not installed) this has no effect. + */ +static int max77714_setup_xosc(struct device *dev, struct regmap *regmap) +{ + /* Internal Crystal Load Capacitance, indexed by value of 32KLOAD bits */ + static const unsigned int load_cap[4] = {0, 10, 12, 22}; /* pF */ + unsigned int load_cap_idx; + unsigned int status; + int err; + + err = regmap_update_bits(regmap, MAX77714_32K_CONFIG, + MAX77714_32K_CONFIG_XOSC_RETRY, + MAX77714_32K_CONFIG_XOSC_RETRY); + if (err) + return dev_err_probe(dev, err, "Failed to configure the external oscillator\n"); + + err = regmap_read(regmap, MAX77714_32K_STATUS, &status); + if (err) + return dev_err_probe(dev, err, "Failed to read external oscillator status\n"); + + load_cap_idx = (status >> MAX77714_32K_STATUS_32KLOAD_SHF) + & MAX77714_32K_STATUS_32KLOAD_MSK; + + dev_info(dev, "Using %s oscillator, %d pF load cap\n", + status & MAX77714_32K_STATUS_32KSOURCE ? "internal" : "external", + load_cap[load_cap_idx]); + + return 0; +} + +static int max77714_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; + int err; + + regmap = devm_regmap_init_i2c(client, &max77714_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to initialise regmap\n"); + + err = max77714_setup_xosc(dev, regmap); + if (err) + return err; + + err = devm_regmap_add_irq_chip(dev, regmap, client->irq, + IRQF_ONESHOT | IRQF_SHARED, 0, + &max77714_irq_chip, &irq_data); + if (err) + return dev_err_probe(dev, err, "Failed to add PMIC IRQ chip\n"); + + err = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, + max77714_cells, ARRAY_SIZE(max77714_cells), + NULL, 0, NULL); + if (err) + return dev_err_probe(dev, err, "Failed to register child devices\n"); + + return 0; +} + +static const struct of_device_id max77714_dt_match[] = { + { .compatible = "maxim,max77714" }, + {}, +}; +MODULE_DEVICE_TABLE(of, max77714_dt_match); + +static struct i2c_driver max77714_driver = { + .driver = { + .name = "max77714", + .of_match_table = max77714_dt_match, + }, + .probe_new = max77714_probe, +}; +module_i2c_driver(max77714_driver); + +MODULE_DESCRIPTION("Maxim MAX77714 MFD core driver"); +MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 41f566e6a096..c340080971ce 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -282,7 +282,7 @@ err_alloc_drvdata: return ret; } -static int max8907_i2c_remove(struct i2c_client *i2c) +static void max8907_i2c_remove(struct i2c_client *i2c) { struct max8907 *max8907 = i2c_get_clientdata(i2c); @@ -293,8 +293,6 @@ static int max8907_i2c_remove(struct i2c_client *i2c) regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); i2c_unregister_device(max8907->i2c_rtc); - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 114e905bef25..04101da42bd3 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -198,14 +198,13 @@ static int max8925_probe(struct i2c_client *client, return 0; } -static int max8925_remove(struct i2c_client *client) +static void max8925_remove(struct i2c_client *client) { struct max8925_chip *chip = i2c_get_clientdata(client); max8925_device_exit(chip); i2c_unregister_device(chip->adc); i2c_unregister_device(chip->rtc); - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 8a4f1d90dcfd..1000572761a8 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -323,8 +323,10 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode, adc1 |= MC13783_ADC1_ATOX; dev_dbg(mc13xxx->dev, "%s: request irq\n", __func__); - mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, + ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_ADCDONE, mc13xxx_handler_adcdone, __func__, &adcdone_data); + if (ret) + goto out; mc13xxx_reg_write(mc13xxx, MC13XXX_ADC0, adc0); mc13xxx_reg_write(mc13xxx, MC13XXX_ADC1, adc1); diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c index fb937f66277e..eb94f3004cf3 100644 --- a/drivers/mfd/mc13xxx-i2c.c +++ b/drivers/mfd/mc13xxx-i2c.c @@ -85,10 +85,9 @@ static int mc13xxx_i2c_probe(struct i2c_client *client, return mc13xxx_common_init(&client->dev); } -static int mc13xxx_i2c_remove(struct i2c_client *client) +static void mc13xxx_i2c_remove(struct i2c_client *client) { mc13xxx_common_exit(&client->dev); - return 0; } static struct i2c_driver mc13xxx_i2c_driver = { diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 4d8913d647e6..f803527e5819 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -166,10 +166,9 @@ static int mc13xxx_spi_probe(struct spi_device *spi) return mc13xxx_common_init(&spi->dev); } -static int mc13xxx_spi_remove(struct spi_device *spi) +static void mc13xxx_spi_remove(struct spi_device *spi) { mc13xxx_common_exit(&spi->dev); - return 0; } static struct spi_driver mc13xxx_spi_driver = { diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 07e0ca2e467c..eb08f69001f9 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1222,14 +1222,13 @@ fail: return err; } -static int menelaus_remove(struct i2c_client *client) +static void menelaus_remove(struct i2c_client *client) { struct menelaus_chip *menelaus = i2c_get_clientdata(client); free_irq(client->irq, menelaus); flush_work(&menelaus->work); the_menelaus = NULL; - return 0; } static const struct i2c_device_id menelaus_id[] = { diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 684a011a6396..16d1861e9682 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -60,12 +60,29 @@ int mfd_cell_disable(struct platform_device *pdev) EXPORT_SYMBOL(mfd_cell_disable); #if IS_ENABLED(CONFIG_ACPI) +struct match_ids_walk_data { + struct acpi_device_id *ids; + struct acpi_device *adev; +}; + +static int match_device_ids(struct acpi_device *adev, void *data) +{ + struct match_ids_walk_data *wd = data; + + if (!acpi_match_device_ids(adev, wd->ids)) { + wd->adev = adev; + return 1; + } + + return 0; +} + static void mfd_acpi_add_device(const struct mfd_cell *cell, struct platform_device *pdev) { const struct mfd_cell_acpi_match *match = cell->acpi_match; - struct acpi_device *parent, *child; struct acpi_device *adev = NULL; + struct acpi_device *parent; parent = ACPI_COMPANION(pdev->dev.parent); if (!parent) @@ -83,14 +100,14 @@ static void mfd_acpi_add_device(const struct mfd_cell *cell, if (match) { if (match->pnpid) { struct acpi_device_id ids[2] = {}; - - strlcpy(ids[0].id, match->pnpid, sizeof(ids[0].id)); - list_for_each_entry(child, &parent->children, node) { - if (!acpi_match_device_ids(child, ids)) { - adev = child; - break; - } - } + struct match_ids_walk_data wd = { + .adev = NULL, + .ids = ids, + }; + + strscpy(ids[0].id, match->pnpid, sizeof(ids[0].id)); + acpi_dev_for_each_child(parent, match_device_ids, &wd); + adev = wd.adev; } else { adev = acpi_find_child_device(parent, match->adr, false); } @@ -351,6 +368,7 @@ static int mfd_remove_devices_fn(struct device *dev, void *data) { struct platform_device *pdev; const struct mfd_cell *cell; + struct mfd_of_node_entry *of_entry, *tmp; int *level = data; if (dev->type != &mfd_dev_type) @@ -365,6 +383,12 @@ static int mfd_remove_devices_fn(struct device *dev, void *data) if (cell->swnode) device_remove_software_node(&pdev->dev); + list_for_each_entry_safe(of_entry, tmp, &mfd_of_node_list, list) + if (of_entry->dev == &pdev->dev) { + list_del(&of_entry->list); + kfree(of_entry); + } + regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies, cell->num_parent_supplies); diff --git a/drivers/mfd/mt6358-irq.c b/drivers/mfd/mt6358-irq.c index 83f3ffbdbb4c..389756436af6 100644 --- a/drivers/mfd/mt6358-irq.c +++ b/drivers/mfd/mt6358-irq.c @@ -3,6 +3,8 @@ // Copyright (c) 2020 MediaTek Inc. #include <linux/interrupt.h> +#include <linux/mfd/mt6357/core.h> +#include <linux/mfd/mt6357/registers.h> #include <linux/mfd/mt6358/core.h> #include <linux/mfd/mt6358/registers.h> #include <linux/mfd/mt6359/core.h> @@ -17,6 +19,17 @@ #define MTK_PMIC_REG_WIDTH 16 +static const struct irq_top_t mt6357_ints[] = { + MT6357_TOP_GEN(BUCK), + MT6357_TOP_GEN(LDO), + MT6357_TOP_GEN(PSC), + MT6357_TOP_GEN(SCK), + MT6357_TOP_GEN(BM), + MT6357_TOP_GEN(HK), + MT6357_TOP_GEN(AUD), + MT6357_TOP_GEN(MISC), +}; + static const struct irq_top_t mt6358_ints[] = { MT6358_TOP_GEN(BUCK), MT6358_TOP_GEN(LDO), @@ -39,6 +52,13 @@ static const struct irq_top_t mt6359_ints[] = { MT6359_TOP_GEN(MISC), }; +static struct pmic_irq_data mt6357_irqd = { + .num_top = ARRAY_SIZE(mt6357_ints), + .num_pmic_irqs = MT6357_IRQ_NR, + .top_int_status_reg = MT6357_TOP_INT_STATUS0, + .pmic_ints = mt6357_ints, +}; + static struct pmic_irq_data mt6358_irqd = { .num_top = ARRAY_SIZE(mt6358_ints), .num_pmic_irqs = MT6358_IRQ_NR, @@ -211,7 +231,12 @@ int mt6358_irq_init(struct mt6397_chip *chip) struct pmic_irq_data *irqd; switch (chip->chip_id) { + case MT6357_CHIP_ID: + chip->irq_data = &mt6357_irqd; + break; + case MT6358_CHIP_ID: + case MT6366_CHIP_ID: chip->irq_data = &mt6358_irqd; break; diff --git a/drivers/mfd/mt6370.c b/drivers/mfd/mt6370.c new file mode 100644 index 000000000000..cf19cce2fdc0 --- /dev/null +++ b/drivers/mfd/mt6370.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiYuan Huang <cy_huang@richtek.com> + */ + +#include <linux/bits.h> +#include <linux/bitfield.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/regmap.h> + +#include "mt6370.h" + +#define MT6370_REG_DEV_INFO 0x100 +#define MT6370_REG_CHG_IRQ1 0x1C0 +#define MT6370_REG_CHG_MASK1 0x1E0 +#define MT6370_REG_MAXADDR 0x1FF + +#define MT6370_VENID_MASK GENMASK(7, 4) + +#define MT6370_NUM_IRQREGS 16 +#define MT6370_USBC_I2CADDR 0x4E +#define MT6370_MAX_ADDRLEN 2 + +#define MT6370_VENID_RT5081 0x8 +#define MT6370_VENID_RT5081A 0xA +#define MT6370_VENID_MT6370 0xE +#define MT6370_VENID_MT6371 0xF +#define MT6370_VENID_MT6372P 0x9 +#define MT6370_VENID_MT6372CP 0xB + +static const struct regmap_irq mt6370_irqs[] = { + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHGON, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TREG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_AICR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_MIVR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_PWR_RDY, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FL_CHG_VINOVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSUV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VSYSOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VBATOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_VINOVPCHG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COLD, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_COOL, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_WARM, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_BAT_HOT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TS_STATC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_FAULT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_STATC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_BATABS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ADPBAD, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_TSHUTDOWN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IINMEAS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_ICCMEAS, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_WDTMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_SSFINISH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_RECHG, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_TERM, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHG_IEOC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_ADC_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_PUMPX_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_BATUV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_MIDOV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BST_OLP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_ATTACH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DETACH, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_STPDONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_VBUSDET_DONE, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_HVDCP_DET, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_CHGDET, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DCDT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_VGOK, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_WDTMR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_UC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DIRCHG_OV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_SWON, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP_D, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_UVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP_D, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OVPCTRL_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_STRBPIN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TORPIN, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_TX, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED_LVF, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_SHORT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_SHORT, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_STRB, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB, 8), + REGMAP_IRQ_REG_LINE(mT6370_IRQ_FLED2_STRB_TO, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_STRB_TO, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED2_TOR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_FLED1_TOR, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_OTP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_VDDA_UV, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_LDO_OC, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_BLED_OVP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_BST_OCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VNEG_SCP, 8), + REGMAP_IRQ_REG_LINE(MT6370_IRQ_DSV_VPOS_SCP, 8), +}; + +static const struct regmap_irq_chip mt6370_irq_chip = { + .name = "mt6370-irqs", + .status_base = MT6370_REG_CHG_IRQ1, + .mask_base = MT6370_REG_CHG_MASK1, + .num_regs = MT6370_NUM_IRQREGS, + .irqs = mt6370_irqs, + .num_irqs = ARRAY_SIZE(mt6370_irqs), +}; + +static const struct resource mt6370_regulator_irqs[] = { + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_SCP, "db_vpos_scp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_SCP, "db_vneg_scp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_BST_OCP, "db_vbst_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VPOS_OCP, "db_vpos_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_DSV_VNEG_OCP, "db_vneg_ocp"), + DEFINE_RES_IRQ_NAMED(MT6370_IRQ_LDO_OC, "ldo_oc"), +}; + +static const struct mfd_cell mt6370_devices[] = { + MFD_CELL_OF("mt6370-adc", + NULL, NULL, 0, 0, "mediatek,mt6370-adc"), + MFD_CELL_OF("mt6370-charger", + NULL, NULL, 0, 0, "mediatek,mt6370-charger"), + MFD_CELL_OF("mt6370-flashlight", + NULL, NULL, 0, 0, "mediatek,mt6370-flashlight"), + MFD_CELL_OF("mt6370-indicator", + NULL, NULL, 0, 0, "mediatek,mt6370-indicator"), + MFD_CELL_OF("mt6370-tcpc", + NULL, NULL, 0, 0, "mediatek,mt6370-tcpc"), + MFD_CELL_RES("mt6370-regulator", mt6370_regulator_irqs), +}; + +static const struct mfd_cell mt6370_exclusive_devices[] = { + MFD_CELL_OF("mt6370-backlight", + NULL, NULL, 0, 0, "mediatek,mt6370-backlight"), +}; + +static const struct mfd_cell mt6372_exclusive_devices[] = { + MFD_CELL_OF("mt6370-backlight", + NULL, NULL, 0, 0, "mediatek,mt6372-backlight"), +}; + +static int mt6370_check_vendor_info(struct device *dev, struct regmap *rmap, + int *vid) +{ + unsigned int devinfo; + int ret; + + ret = regmap_read(rmap, MT6370_REG_DEV_INFO, &devinfo); + if (ret) + return ret; + + *vid = FIELD_GET(MT6370_VENID_MASK, devinfo); + switch (*vid) { + case MT6370_VENID_RT5081: + case MT6370_VENID_RT5081A: + case MT6370_VENID_MT6370: + case MT6370_VENID_MT6371: + case MT6370_VENID_MT6372P: + case MT6370_VENID_MT6372CP: + return 0; + default: + dev_err(dev, "Unknown Vendor ID 0x%02x\n", devinfo); + return -ENODEV; + } +} + +static int mt6370_regmap_read(void *context, const void *reg_buf, + size_t reg_size, void *val_buf, size_t val_size) +{ + struct mt6370_info *info = context; + const u8 *u8_buf = reg_buf; + u8 bank_idx, bank_addr; + int ret; + + bank_idx = u8_buf[0]; + bank_addr = u8_buf[1]; + + ret = i2c_smbus_read_i2c_block_data(info->i2c[bank_idx], bank_addr, + val_size, val_buf); + if (ret < 0) + return ret; + + if (ret != val_size) + return -EIO; + + return 0; +} + +static int mt6370_regmap_write(void *context, const void *data, size_t count) +{ + struct mt6370_info *info = context; + const u8 *u8_buf = data; + u8 bank_idx, bank_addr; + int len = count - MT6370_MAX_ADDRLEN; + + bank_idx = u8_buf[0]; + bank_addr = u8_buf[1]; + + return i2c_smbus_write_i2c_block_data(info->i2c[bank_idx], bank_addr, + len, data + MT6370_MAX_ADDRLEN); +} + +static const struct regmap_bus mt6370_regmap_bus = { + .read = mt6370_regmap_read, + .write = mt6370_regmap_write, +}; + +static const struct regmap_config mt6370_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .max_register = MT6370_REG_MAXADDR, +}; + +static int mt6370_probe(struct i2c_client *i2c) +{ + struct mt6370_info *info; + struct i2c_client *usbc_i2c; + struct regmap *regmap; + struct device *dev = &i2c->dev; + int ret, vid; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + usbc_i2c = devm_i2c_new_dummy_device(dev, i2c->adapter, + MT6370_USBC_I2CADDR); + if (IS_ERR(usbc_i2c)) + return dev_err_probe(dev, PTR_ERR(usbc_i2c), + "Failed to register USBC I2C client\n"); + + /* Assign I2C client for PMU and TypeC */ + info->i2c[MT6370_PMU_I2C] = i2c; + info->i2c[MT6370_USBC_I2C] = usbc_i2c; + + regmap = devm_regmap_init(dev, &mt6370_regmap_bus, + info, &mt6370_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to init regmap\n"); + + ret = mt6370_check_vendor_info(dev, regmap, &vid); + if (ret) + return dev_err_probe(dev, ret, "Failed to check vendor info\n"); + + ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq, + IRQF_ONESHOT, -1, &mt6370_irq_chip, + &info->irq_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to add irq chip\n"); + + switch (vid) { + case MT6370_VENID_MT6372P: + case MT6370_VENID_MT6372CP: + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + mt6372_exclusive_devices, + ARRAY_SIZE(mt6372_exclusive_devices), + NULL, 0, + regmap_irq_get_domain(info->irq_data)); + break; + default: + ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + mt6370_exclusive_devices, + ARRAY_SIZE(mt6370_exclusive_devices), + NULL, 0, + regmap_irq_get_domain(info->irq_data)); + break; + } + + if (ret) + return dev_err_probe(dev, ret, "Failed to add the exclusive devices\n"); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, + mt6370_devices, ARRAY_SIZE(mt6370_devices), + NULL, 0, + regmap_irq_get_domain(info->irq_data)); +} + +static const struct of_device_id mt6370_match_table[] = { + { .compatible = "mediatek,mt6370" }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6370_match_table); + +static struct i2c_driver mt6370_driver = { + .driver = { + .name = "mt6370", + .of_match_table = mt6370_match_table, + }, + .probe_new = mt6370_probe, +}; +module_i2c_driver(mt6370_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("MediaTek MT6370 SubPMIC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/mt6370.h b/drivers/mfd/mt6370.h new file mode 100644 index 000000000000..094e59e4af4e --- /dev/null +++ b/drivers/mfd/mt6370.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2022 Richtek Technology Corp. + * + * Author: ChiYuan Huang <cy_huang@richtek.com> + */ + +#ifndef __MFD_MT6370_H__ +#define __MFD_MT6370_H__ + +/* IRQ definitions */ +#define MT6370_IRQ_DIRCHGON 0 +#define MT6370_IRQ_CHG_TREG 4 +#define MT6370_IRQ_CHG_AICR 5 +#define MT6370_IRQ_CHG_MIVR 6 +#define MT6370_IRQ_PWR_RDY 7 +#define MT6370_IRQ_FL_CHG_VINOVP 11 +#define MT6370_IRQ_CHG_VSYSUV 12 +#define MT6370_IRQ_CHG_VSYSOV 13 +#define MT6370_IRQ_CHG_VBATOV 14 +#define MT6370_IRQ_CHG_VINOVPCHG 15 +#define MT6370_IRQ_TS_BAT_COLD 20 +#define MT6370_IRQ_TS_BAT_COOL 21 +#define MT6370_IRQ_TS_BAT_WARM 22 +#define MT6370_IRQ_TS_BAT_HOT 23 +#define MT6370_IRQ_TS_STATC 24 +#define MT6370_IRQ_CHG_FAULT 25 +#define MT6370_IRQ_CHG_STATC 26 +#define MT6370_IRQ_CHG_TMR 27 +#define MT6370_IRQ_CHG_BATABS 28 +#define MT6370_IRQ_CHG_ADPBAD 29 +#define MT6370_IRQ_CHG_RVP 30 +#define MT6370_IRQ_TSHUTDOWN 31 +#define MT6370_IRQ_CHG_IINMEAS 32 +#define MT6370_IRQ_CHG_ICCMEAS 33 +#define MT6370_IRQ_CHGDET_DONE 34 +#define MT6370_IRQ_WDTMR 35 +#define MT6370_IRQ_SSFINISH 36 +#define MT6370_IRQ_CHG_RECHG 37 +#define MT6370_IRQ_CHG_TERM 38 +#define MT6370_IRQ_CHG_IEOC 39 +#define MT6370_IRQ_ADC_DONE 40 +#define MT6370_IRQ_PUMPX_DONE 41 +#define MT6370_IRQ_BST_BATUV 45 +#define MT6370_IRQ_BST_MIDOV 46 +#define MT6370_IRQ_BST_OLP 47 +#define MT6370_IRQ_ATTACH 48 +#define MT6370_IRQ_DETACH 49 +#define MT6370_IRQ_HVDCP_STPDONE 51 +#define MT6370_IRQ_HVDCP_VBUSDET_DONE 52 +#define MT6370_IRQ_HVDCP_DET 53 +#define MT6370_IRQ_CHGDET 54 +#define MT6370_IRQ_DCDT 55 +#define MT6370_IRQ_DIRCHG_VGOK 59 +#define MT6370_IRQ_DIRCHG_WDTMR 60 +#define MT6370_IRQ_DIRCHG_UC 61 +#define MT6370_IRQ_DIRCHG_OC 62 +#define MT6370_IRQ_DIRCHG_OV 63 +#define MT6370_IRQ_OVPCTRL_SWON 67 +#define MT6370_IRQ_OVPCTRL_UVP_D 68 +#define MT6370_IRQ_OVPCTRL_UVP 69 +#define MT6370_IRQ_OVPCTRL_OVP_D 70 +#define MT6370_IRQ_OVPCTRL_OVP 71 +#define MT6370_IRQ_FLED_STRBPIN 72 +#define MT6370_IRQ_FLED_TORPIN 73 +#define MT6370_IRQ_FLED_TX 74 +#define MT6370_IRQ_FLED_LVF 75 +#define MT6370_IRQ_FLED2_SHORT 78 +#define MT6370_IRQ_FLED1_SHORT 79 +#define MT6370_IRQ_FLED2_STRB 80 +#define MT6370_IRQ_FLED1_STRB 81 +#define mT6370_IRQ_FLED2_STRB_TO 82 +#define MT6370_IRQ_FLED1_STRB_TO 83 +#define MT6370_IRQ_FLED2_TOR 84 +#define MT6370_IRQ_FLED1_TOR 85 +#define MT6370_IRQ_OTP 93 +#define MT6370_IRQ_VDDA_OVP 94 +#define MT6370_IRQ_VDDA_UV 95 +#define MT6370_IRQ_LDO_OC 103 +#define MT6370_IRQ_BLED_OCP 118 +#define MT6370_IRQ_BLED_OVP 119 +#define MT6370_IRQ_DSV_VNEG_OCP 123 +#define MT6370_IRQ_DSV_VPOS_OCP 124 +#define MT6370_IRQ_DSV_BST_OCP 125 +#define MT6370_IRQ_DSV_VNEG_SCP 126 +#define MT6370_IRQ_DSV_VPOS_SCP 127 + +enum { + MT6370_USBC_I2C = 0, + MT6370_PMU_I2C, + MT6370_MAX_I2C +}; + +struct mt6370_info { + struct i2c_client *i2c[MT6370_MAX_I2C]; + struct regmap_irq_chip_data *irq_data; +}; + +#endif /* __MFD_MT6375_H__ */ diff --git a/drivers/mfd/mt6397-core.c b/drivers/mfd/mt6397-core.c index bddb40054b9e..f6c1f80f94a4 100644 --- a/drivers/mfd/mt6397-core.c +++ b/drivers/mfd/mt6397-core.c @@ -12,10 +12,14 @@ #include <linux/regmap.h> #include <linux/mfd/core.h> #include <linux/mfd/mt6323/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/mt6331/registers.h> +#include <linux/mfd/mt6357/registers.h> #include <linux/mfd/mt6358/registers.h> #include <linux/mfd/mt6359/registers.h> #include <linux/mfd/mt6397/registers.h> @@ -23,6 +27,12 @@ #define MT6323_RTC_BASE 0x8000 #define MT6323_RTC_SIZE 0x40 +#define MT6357_RTC_BASE 0x0588 +#define MT6357_RTC_SIZE 0x3c + +#define MT6331_RTC_BASE 0x4000 +#define MT6331_RTC_SIZE 0x40 + #define MT6358_RTC_BASE 0x0588 #define MT6358_RTC_SIZE 0x3c @@ -37,6 +47,16 @@ static const struct resource mt6323_rtc_resources[] = { DEFINE_RES_IRQ(MT6323_IRQ_STATUS_RTC), }; +static const struct resource mt6357_rtc_resources[] = { + DEFINE_RES_MEM(MT6357_RTC_BASE, MT6357_RTC_SIZE), + DEFINE_RES_IRQ(MT6357_IRQ_RTC), +}; + +static const struct resource mt6331_rtc_resources[] = { + DEFINE_RES_MEM(MT6331_RTC_BASE, MT6331_RTC_SIZE), + DEFINE_RES_IRQ(MT6331_IRQ_STATUS_RTC), +}; + static const struct resource mt6358_rtc_resources[] = { DEFINE_RES_MEM(MT6358_RTC_BASE, MT6358_RTC_SIZE), DEFINE_RES_IRQ(MT6358_IRQ_RTC), @@ -54,11 +74,30 @@ static const struct resource mt6358_keys_resources[] = { DEFINE_RES_IRQ_NAMED(MT6358_IRQ_HOMEKEY_R, "homekey_r"), }; +static const struct resource mt6359_keys_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6359_IRQ_PWRKEY, "powerkey"), + DEFINE_RES_IRQ_NAMED(MT6359_IRQ_HOMEKEY, "homekey"), + DEFINE_RES_IRQ_NAMED(MT6359_IRQ_PWRKEY_R, "powerkey_r"), + DEFINE_RES_IRQ_NAMED(MT6359_IRQ_HOMEKEY_R, "homekey_r"), +}; + 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 mt6357_keys_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6357_IRQ_PWRKEY, "powerkey"), + DEFINE_RES_IRQ_NAMED(MT6357_IRQ_HOMEKEY, "homekey"), + DEFINE_RES_IRQ_NAMED(MT6357_IRQ_PWRKEY_R, "powerkey_r"), + DEFINE_RES_IRQ_NAMED(MT6357_IRQ_HOMEKEY_R, "homekey_r"), +}; + +static const struct resource mt6331_keys_resources[] = { + DEFINE_RES_IRQ_NAMED(MT6331_IRQ_STATUS_PWRKEY, "powerkey"), + DEFINE_RES_IRQ_NAMED(MT6331_IRQ_STATUS_HOMEKEY, "homekey"), +}; + static const struct resource mt6397_keys_resources[] = { DEFINE_RES_IRQ_NAMED(MT6397_IRQ_PWRKEY, "powerkey"), DEFINE_RES_IRQ_NAMED(MT6397_IRQ_HOMEKEY, "homekey"), @@ -93,6 +132,43 @@ static const struct mfd_cell mt6323_devs[] = { }, }; +static const struct mfd_cell mt6357_devs[] = { + { + .name = "mt6357-regulator", + }, { + .name = "mt6357-rtc", + .num_resources = ARRAY_SIZE(mt6357_rtc_resources), + .resources = mt6357_rtc_resources, + .of_compatible = "mediatek,mt6357-rtc", + }, { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6357_keys_resources), + .resources = mt6357_keys_resources, + .of_compatible = "mediatek,mt6357-keys" + }, +}; + +/* MT6331 is always used in combination with MT6332 */ +static const struct mfd_cell mt6331_mt6332_devs[] = { + { + .name = "mt6331-rtc", + .num_resources = ARRAY_SIZE(mt6331_rtc_resources), + .resources = mt6331_rtc_resources, + .of_compatible = "mediatek,mt6331-rtc", + }, { + .name = "mt6331-regulator", + .of_compatible = "mediatek,mt6331-regulator" + }, { + .name = "mt6332-regulator", + .of_compatible = "mediatek,mt6332-regulator" + }, { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6331_keys_resources), + .resources = mt6331_keys_resources, + .of_compatible = "mediatek,mt6331-keys" + }, +}; + static const struct mfd_cell mt6358_devs[] = { { .name = "mt6358-regulator", @@ -122,6 +198,12 @@ static const struct mfd_cell mt6359_devs[] = { .of_compatible = "mediatek,mt6358-rtc", }, { .name = "mt6359-sound", }, + { + .name = "mtk-pmic-keys", + .num_resources = ARRAY_SIZE(mt6359_keys_resources), + .resources = mt6359_keys_resources, + .of_compatible = "mediatek,mt6359-keys" + }, }; static const struct mfd_cell mt6397_devs[] = { @@ -166,6 +248,22 @@ static const struct chip_data mt6323_core = { .irq_init = mt6397_irq_init, }; +static const struct chip_data mt6357_core = { + .cid_addr = MT6357_SWCID, + .cid_shift = 8, + .cells = mt6357_devs, + .cell_size = ARRAY_SIZE(mt6357_devs), + .irq_init = mt6358_irq_init, +}; + +static const struct chip_data mt6331_mt6332_core = { + .cid_addr = MT6331_HWCID, + .cid_shift = 0, + .cells = mt6331_mt6332_devs, + .cell_size = ARRAY_SIZE(mt6331_mt6332_devs), + .irq_init = mt6397_irq_init, +}; + static const struct chip_data mt6358_core = { .cid_addr = MT6358_SWCID, .cid_shift = 8, @@ -249,6 +347,12 @@ static const struct of_device_id mt6397_of_match[] = { .compatible = "mediatek,mt6323", .data = &mt6323_core, }, { + .compatible = "mediatek,mt6331", + .data = &mt6331_mt6332_core, + }, { + .compatible = "mediatek,mt6357", + .data = &mt6357_core, + }, { .compatible = "mediatek,mt6358", .data = &mt6358_core, }, { diff --git a/drivers/mfd/mt6397-irq.c b/drivers/mfd/mt6397-irq.c index 2924919da991..eff53fed8fe7 100644 --- a/drivers/mfd/mt6397-irq.c +++ b/drivers/mfd/mt6397-irq.c @@ -12,6 +12,8 @@ #include <linux/suspend.h> #include <linux/mfd/mt6323/core.h> #include <linux/mfd/mt6323/registers.h> +#include <linux/mfd/mt6331/core.h> +#include <linux/mfd/mt6331/registers.h> #include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/registers.h> @@ -172,7 +174,12 @@ int mt6397_irq_init(struct mt6397_chip *chip) chip->int_status[0] = MT6323_INT_STATUS0; chip->int_status[1] = MT6323_INT_STATUS1; break; - + case MT6331_CHIP_ID: + chip->int_con[0] = MT6331_INT_CON0; + chip->int_con[1] = MT6331_INT_CON1; + chip->int_status[0] = MT6331_INT_STATUS_CON0; + chip->int_status[1] = MT6331_INT_STATUS_CON1; + break; case MT6391_CHIP_ID: case MT6397_CHIP_ID: chip->int_con[0] = MT6397_INT_CON0; diff --git a/drivers/mfd/ntxec.c b/drivers/mfd/ntxec.c index b711e73eedcb..e16a7a82a929 100644 --- a/drivers/mfd/ntxec.c +++ b/drivers/mfd/ntxec.c @@ -239,15 +239,13 @@ static int ntxec_probe(struct i2c_client *client) return res; } -static int ntxec_remove(struct i2c_client *client) +static void ntxec_remove(struct i2c_client *client) { if (client == poweroff_restart_client) { poweroff_restart_client = NULL; pm_power_off = NULL; unregister_restart_handler(&ntxec_restart_handler); } - - return 0; } static const struct of_device_id of_ntxec_match_table[] = { diff --git a/drivers/mfd/ocelot-core.c b/drivers/mfd/ocelot-core.c new file mode 100644 index 000000000000..1816d52c65c5 --- /dev/null +++ b/drivers/mfd/ocelot-core.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * Core driver for the Ocelot chip family. + * + * The VSC7511, 7512, 7513, and 7514 can be controlled internally via an + * on-chip MIPS processor, or externally via SPI, I2C, PCIe. This core driver is + * intended to be the bus-agnostic glue between, for example, the SPI bus and + * the child devices. + * + * Copyright 2021-2022 Innovative Advantage Inc. + * + * Author: Colin Foster <colin.foster@in-advantage.com> + */ + +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/export.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/mfd/ocelot.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/types.h> + +#include <soc/mscc/ocelot.h> + +#include "ocelot.h" + +#define REG_GCB_SOFT_RST 0x0008 + +#define BIT_SOFT_CHIP_RST BIT(0) + +#define VSC7512_MIIM0_RES_START 0x7107009c +#define VSC7512_MIIM1_RES_START 0x710700c0 +#define VSC7512_MIIM_RES_SIZE 0x024 + +#define VSC7512_PHY_RES_START 0x710700f0 +#define VSC7512_PHY_RES_SIZE 0x004 + +#define VSC7512_GPIO_RES_START 0x71070034 +#define VSC7512_GPIO_RES_SIZE 0x06c + +#define VSC7512_SIO_CTRL_RES_START 0x710700f8 +#define VSC7512_SIO_CTRL_RES_SIZE 0x100 + +#define VSC7512_GCB_RST_SLEEP_US 100 +#define VSC7512_GCB_RST_TIMEOUT_US 100000 + +static int ocelot_gcb_chip_rst_status(struct ocelot_ddata *ddata) +{ + int val, err; + + err = regmap_read(ddata->gcb_regmap, REG_GCB_SOFT_RST, &val); + if (err) + return err; + + return val; +} + +int ocelot_chip_reset(struct device *dev) +{ + struct ocelot_ddata *ddata = dev_get_drvdata(dev); + int ret, val; + + /* + * Reset the entire chip here to put it into a completely known state. + * Other drivers may want to reset their own subsystems. The register + * self-clears, so one write is all that is needed and wait for it to + * clear. + */ + ret = regmap_write(ddata->gcb_regmap, REG_GCB_SOFT_RST, BIT_SOFT_CHIP_RST); + if (ret) + return ret; + + 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); + +static const struct resource vsc7512_miim0_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_MIIM0_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim0"), + DEFINE_RES_REG_NAMED(VSC7512_PHY_RES_START, VSC7512_PHY_RES_SIZE, "gcb_phy"), +}; + +static const struct resource vsc7512_miim1_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_MIIM1_RES_START, VSC7512_MIIM_RES_SIZE, "gcb_miim1"), +}; + +static const struct resource vsc7512_pinctrl_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_GPIO_RES_START, VSC7512_GPIO_RES_SIZE, "gcb_gpio"), +}; + +static const struct resource vsc7512_sgpio_resources[] = { + DEFINE_RES_REG_NAMED(VSC7512_SIO_CTRL_RES_START, VSC7512_SIO_CTRL_RES_SIZE, "gcb_sio"), +}; + +static const struct mfd_cell vsc7512_devs[] = { + { + .name = "ocelot-pinctrl", + .of_compatible = "mscc,ocelot-pinctrl", + .num_resources = ARRAY_SIZE(vsc7512_pinctrl_resources), + .resources = vsc7512_pinctrl_resources, + }, { + .name = "ocelot-sgpio", + .of_compatible = "mscc,ocelot-sgpio", + .num_resources = ARRAY_SIZE(vsc7512_sgpio_resources), + .resources = vsc7512_sgpio_resources, + }, { + .name = "ocelot-miim0", + .of_compatible = "mscc,ocelot-miim", + .of_reg = VSC7512_MIIM0_RES_START, + .use_of_reg = true, + .num_resources = ARRAY_SIZE(vsc7512_miim0_resources), + .resources = vsc7512_miim0_resources, + }, { + .name = "ocelot-miim1", + .of_compatible = "mscc,ocelot-miim", + .of_reg = VSC7512_MIIM1_RES_START, + .use_of_reg = true, + .num_resources = ARRAY_SIZE(vsc7512_miim1_resources), + .resources = vsc7512_miim1_resources, + }, +}; + +static void ocelot_core_try_add_regmap(struct device *dev, + const struct resource *res) +{ + if (dev_get_regmap(dev, res->name)) + return; + + ocelot_spi_init_regmap(dev, res); +} + +static void ocelot_core_try_add_regmaps(struct device *dev, + const struct mfd_cell *cell) +{ + int i; + + for (i = 0; i < cell->num_resources; i++) + ocelot_core_try_add_regmap(dev, &cell->resources[i]); +} + +int ocelot_core_init(struct device *dev) +{ + int i, ndevs; + + ndevs = ARRAY_SIZE(vsc7512_devs); + + for (i = 0; i < ndevs; i++) + ocelot_core_try_add_regmaps(dev, &vsc7512_devs[i]); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, vsc7512_devs, ndevs, NULL, 0, NULL); +} +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); diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c new file mode 100644 index 000000000000..2ecd271de2fb --- /dev/null +++ b/drivers/mfd/ocelot-spi.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +/* + * SPI core driver for the Ocelot chip family. + * + * This driver will handle everything necessary to allow for communication over + * SPI to the VSC7511, VSC7512, VSC7513 and VSC7514 chips. The main functions + * are to prepare the chip's SPI interface for a specific bus speed, and a host + * processor's endianness. This will create and distribute regmaps for any + * children. + * + * Copyright 2021-2022 Innovative Advantage Inc. + * + * Author: Colin Foster <colin.foster@in-advantage.com> + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/export.h> +#include <linux/ioport.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/units.h> + +#include "ocelot.h" + +#define REG_DEV_CPUORG_IF_CTRL 0x0000 +#define REG_DEV_CPUORG_IF_CFGSTAT 0x0004 + +#define CFGSTAT_IF_NUM_VCORE (0 << 24) +#define CFGSTAT_IF_NUM_VRAP (1 << 24) +#define CFGSTAT_IF_NUM_SI (2 << 24) +#define CFGSTAT_IF_NUM_MIIM (3 << 24) + +#define VSC7512_DEVCPU_ORG_RES_START 0x71000000 +#define VSC7512_DEVCPU_ORG_RES_SIZE 0x38 + +#define VSC7512_CHIP_REGS_RES_START 0x71070000 +#define VSC7512_CHIP_REGS_RES_SIZE 0x14 + +static const struct resource vsc7512_dev_cpuorg_resource = + DEFINE_RES_REG_NAMED(VSC7512_DEVCPU_ORG_RES_START, + VSC7512_DEVCPU_ORG_RES_SIZE, + "devcpu_org"); + +static const struct resource vsc7512_gcb_resource = + DEFINE_RES_REG_NAMED(VSC7512_CHIP_REGS_RES_START, + VSC7512_CHIP_REGS_RES_SIZE, + "devcpu_gcb_chip_regs"); + +static int ocelot_spi_initialize(struct device *dev) +{ + struct ocelot_ddata *ddata = dev_get_drvdata(dev); + u32 val, check; + int err; + + val = OCELOT_SPI_BYTE_ORDER; + + /* + * The SPI address must be big-endian, but we want the payload to match + * our CPU. These are two bits (0 and 1) but they're repeated such that + * the write from any configuration will be valid. The four + * configurations are: + * + * 0b00: little-endian, MSB first + * | 111111 | 22221111 | 33222222 | + * | 76543210 | 54321098 | 32109876 | 10987654 | + * + * 0b01: big-endian, MSB first + * | 33222222 | 22221111 | 111111 | | + * | 10987654 | 32109876 | 54321098 | 76543210 | + * + * 0b10: little-endian, LSB first + * | 111111 | 11112222 | 22222233 | + * | 01234567 | 89012345 | 67890123 | 45678901 | + * + * 0b11: big-endian, LSB first + * | 22222233 | 11112222 | 111111 | | + * | 45678901 | 67890123 | 89012345 | 01234567 | + */ + err = regmap_write(ddata->cpuorg_regmap, REG_DEV_CPUORG_IF_CTRL, val); + if (err) + return err; + + /* + * Apply the number of padding bytes between a read request and the data + * payload. Some registers have access times of up to 1us, so if the + * first payload bit is shifted out too quickly, the read will fail. + */ + val = ddata->spi_padding_bytes; + err = regmap_write(ddata->cpuorg_regmap, REG_DEV_CPUORG_IF_CFGSTAT, val); + if (err) + return err; + + /* + * After we write the interface configuration, read it back here. This + * will verify several different things. The first is that the number of + * padding bytes actually got written correctly. These are found in bits + * 0:3. + * + * The second is that bit 16 is cleared. Bit 16 is IF_CFGSTAT:IF_STAT, + * and will be set if the register access is too fast. This would be in + * the condition that the number of padding bytes is insufficient for + * the SPI bus frequency. + * + * The last check is for bits 31:24, which define the interface by which + * the registers are being accessed. Since we're accessing them via the + * serial interface, it must return IF_NUM_SI. + */ + check = val | CFGSTAT_IF_NUM_SI; + + err = regmap_read(ddata->cpuorg_regmap, REG_DEV_CPUORG_IF_CFGSTAT, &val); + if (err) + return err; + + if (check != val) + return -ENODEV; + + return 0; +} + +static const struct regmap_config ocelot_spi_regmap_config = { + .reg_bits = 24, + .reg_stride = 4, + .reg_downshift = 2, + .val_bits = 32, + + .write_flag_mask = 0x80, + + .use_single_write = true, + .can_multi_write = false, + + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_NATIVE, +}; + +static int ocelot_spi_regmap_bus_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct spi_transfer xfers[3] = {0}; + 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); + spi = to_spi_device(dev); + + xfers[index].tx_buf = reg; + xfers[index].len = reg_size; + index++; + + if (ddata->spi_padding_bytes) { + xfers[index].len = ddata->spi_padding_bytes; + xfers[index].tx_buf = ddata->dummy_buf; + xfers[index].dummy_data = 1; + index++; + } + + xfers[index].rx_buf = val; + xfers[index].len = val_size; + index++; + + spi_message_init_with_transfers(&msg, xfers, index); + + return spi_sync(spi, &msg); +} + +static int ocelot_spi_regmap_bus_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct spi_device *spi = to_spi_device(dev); + + return spi_write(spi, data, count); +} + +static const struct regmap_bus ocelot_spi_regmap_bus = { + .write = ocelot_spi_regmap_bus_write, + .read = ocelot_spi_regmap_bus_read, +}; + +struct regmap *ocelot_spi_init_regmap(struct device *dev, const struct resource *res) +{ + struct regmap_config regmap_config; + + memcpy(®map_config, &ocelot_spi_regmap_config, sizeof(regmap_config)); + + regmap_config.name = res->name; + regmap_config.max_register = resource_size(res) - 1; + regmap_config.reg_base = res->start; + + return devm_regmap_init(dev, &ocelot_spi_regmap_bus, dev, ®map_config); +} +EXPORT_SYMBOL_NS(ocelot_spi_init_regmap, MFD_OCELOT_SPI); + +static int ocelot_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ocelot_ddata *ddata; + struct regmap *r; + int err; + + ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + spi_set_drvdata(spi, ddata); + + if (spi->max_speed_hz <= 500000) { + ddata->spi_padding_bytes = 0; + } else { + /* + * Calculation taken from the manual for IF_CFGSTAT:IF_CFG. + * Register access time is 1us, so we need to configure and send + * out enough padding bytes between the read request and data + * transmission that lasts at least 1 microsecond. + */ + ddata->spi_padding_bytes = 1 + (spi->max_speed_hz / HZ_PER_MHZ + 2) / 8; + + ddata->dummy_buf = devm_kzalloc(dev, ddata->spi_padding_bytes, GFP_KERNEL); + if (!ddata->dummy_buf) + return -ENOMEM; + } + + spi->bits_per_word = 8; + + err = spi_setup(spi); + if (err) + return dev_err_probe(&spi->dev, err, "Error performing SPI setup\n"); + + r = ocelot_spi_init_regmap(dev, &vsc7512_dev_cpuorg_resource); + if (IS_ERR(r)) + return PTR_ERR(r); + + ddata->cpuorg_regmap = r; + + r = ocelot_spi_init_regmap(dev, &vsc7512_gcb_resource); + if (IS_ERR(r)) + return PTR_ERR(r); + + ddata->gcb_regmap = r; + + /* + * The chip must be set up for SPI before it gets initialized and reset. + * This must be done before calling init, and after a chip reset is + * performed. + */ + err = ocelot_spi_initialize(dev); + if (err) + return dev_err_probe(dev, err, "Error initializing SPI bus\n"); + + err = ocelot_chip_reset(dev); + if (err) + return dev_err_probe(dev, err, "Error resetting device\n"); + + /* + * A chip reset will clear the SPI configuration, so it needs to be done + * again before we can access any registers. + */ + err = ocelot_spi_initialize(dev); + if (err) + return dev_err_probe(dev, err, "Error initializing SPI bus after reset\n"); + + err = ocelot_core_init(dev); + if (err) + return dev_err_probe(dev, err, "Error initializing Ocelot core\n"); + + return 0; +} + +static const struct spi_device_id ocelot_spi_ids[] = { + { "vsc7512", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ocelot_spi_ids); + +static const struct of_device_id ocelot_spi_of_match[] = { + { .compatible = "mscc,vsc7512" }, + { } +}; +MODULE_DEVICE_TABLE(of, ocelot_spi_of_match); + +static struct spi_driver ocelot_spi_driver = { + .driver = { + .name = "ocelot-soc", + .of_match_table = ocelot_spi_of_match, + }, + .id_table = ocelot_spi_ids, + .probe = ocelot_spi_probe, +}; +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); diff --git a/drivers/mfd/ocelot.h b/drivers/mfd/ocelot.h new file mode 100644 index 000000000000..b8bc2f1486e2 --- /dev/null +++ b/drivers/mfd/ocelot.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* Copyright 2021, 2022 Innovative Advantage Inc. */ + +#ifndef _MFD_OCELOT_H +#define _MFD_OCELOT_H + +#include <linux/kconfig.h> + +struct device; +struct regmap; +struct resource; + +/** + * struct ocelot_ddata - Private data for an external Ocelot chip + * @gcb_regmap: General Configuration Block regmap. Used for + * operations like chip reset. + * @cpuorg_regmap: CPU Device Origin Block regmap. Used for operations + * like SPI bus configuration. + * @spi_padding_bytes: Number of padding bytes that must be thrown out before + * read data gets returned. This is calculated during + * initialization based on bus speed. + * @dummy_buf: Zero-filled buffer of spi_padding_bytes size. The dummy + * bytes that will be sent out between the address and + * data of a SPI read operation. + */ +struct ocelot_ddata { + struct regmap *gcb_regmap; + struct regmap *cpuorg_regmap; + int spi_padding_bytes; + void *dummy_buf; +}; + +int ocelot_chip_reset(struct device *dev); +int ocelot_core_init(struct device *dev); + +/* SPI-specific routines that won't be necessary for other interfaces */ +struct regmap *ocelot_spi_init_regmap(struct device *dev, + const struct resource *res); + +#define OCELOT_SPI_BYTE_ORDER_LE 0x00000000 +#define OCELOT_SPI_BYTE_ORDER_BE 0x81818181 + +#ifdef __LITTLE_ENDIAN +#define OCELOT_SPI_BYTE_ORDER OCELOT_SPI_BYTE_ORDER_LE +#else +#define OCELOT_SPI_BYTE_ORDER OCELOT_SPI_BYTE_ORDER_BE +#endif + +#endif diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index f5b3fa973b13..8b7429bd2e3e 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -700,7 +700,7 @@ err_i2c: return ret; } -static int palmas_i2c_remove(struct i2c_client *i2c) +static void palmas_i2c_remove(struct i2c_client *i2c) { struct palmas *palmas = i2c_get_clientdata(i2c); int i; @@ -716,8 +716,6 @@ static int palmas_i2c_remove(struct i2c_client *i2c) pm_power_off = NULL; palmas_dev = NULL; } - - return 0; } static const struct i2c_device_id palmas_i2c_id[] = { diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index e9c565cf0f54..4ccc2c3e7681 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -273,7 +273,7 @@ err2: return ret; } -static int pcf50633_remove(struct i2c_client *client) +static void pcf50633_remove(struct i2c_client *client) { struct pcf50633 *pcf = i2c_get_clientdata(client); int i; @@ -289,8 +289,6 @@ static int pcf50633_remove(struct i2c_client *client) for (i = 0; i < PCF50633_NUM_REGULATORS; i++) platform_device_unregister(pcf->regulator_pdev[i]); - - return 0; } static const struct i2c_device_id pcf50633_id_table[] = { diff --git a/drivers/mfd/qcom-pm8008.c b/drivers/mfd/qcom-pm8008.c index c472d7f8103c..4b8ff947762f 100644 --- a/drivers/mfd/qcom-pm8008.c +++ b/drivers/mfd/qcom-pm8008.c @@ -54,13 +54,6 @@ enum { #define PM8008_PERIPH_OFFSET(paddr) (paddr - PM8008_PERIPH_0_BASE) -struct pm8008_data { - struct device *dev; - struct regmap *regmap; - int irq; - struct regmap_irq_chip_data *irq_data; -}; - static unsigned int p0_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_0_BASE)}; static unsigned int p1_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_1_BASE)}; static unsigned int p2_offs[] = {PM8008_PERIPH_OFFSET(PM8008_PERIPH_2_BASE)}; @@ -150,7 +143,7 @@ static struct regmap_config qcom_mfd_regmap_cfg = { .max_register = 0xFFFF, }; -static int pm8008_init(struct pm8008_data *chip) +static int pm8008_init(struct regmap *regmap) { int rc; @@ -160,34 +153,31 @@ static int pm8008_init(struct pm8008_data *chip) * This is required to enable the writing of TYPE registers in * regmap_irq_sync_unlock(). */ - rc = regmap_write(chip->regmap, - (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), - BIT(0)); + rc = regmap_write(regmap, (PM8008_TEMP_ALARM_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); if (rc) return rc; /* Do the same for GPIO1 and GPIO2 peripherals */ - rc = regmap_write(chip->regmap, - (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); + rc = regmap_write(regmap, (PM8008_GPIO1_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); if (rc) return rc; - rc = regmap_write(chip->regmap, - (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); + rc = regmap_write(regmap, (PM8008_GPIO2_ADDR | INT_SET_TYPE_OFFSET), BIT(0)); return rc; } -static int pm8008_probe_irq_peripherals(struct pm8008_data *chip, +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; - rc = pm8008_init(chip); + rc = pm8008_init(regmap); if (rc) { - dev_err(chip->dev, "Init failed: %d\n", rc); + dev_err(dev, "Init failed: %d\n", rc); return rc; } @@ -207,10 +197,10 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip, IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW); } - rc = devm_regmap_add_irq_chip(chip->dev, chip->regmap, client_irq, + rc = devm_regmap_add_irq_chip(dev, regmap, client_irq, IRQF_SHARED, 0, &pm8008_irq_chip, &irq_data); if (rc) { - dev_err(chip->dev, "Failed to add IRQ chip: %d\n", rc); + dev_err(dev, "Failed to add IRQ chip: %d\n", rc); return rc; } @@ -220,26 +210,23 @@ static int pm8008_probe_irq_peripherals(struct pm8008_data *chip, static int pm8008_probe(struct i2c_client *client) { int rc; - struct pm8008_data *chip; - - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; + struct device *dev; + struct regmap *regmap; - chip->dev = &client->dev; - chip->regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg); - if (!chip->regmap) + dev = &client->dev; + regmap = devm_regmap_init_i2c(client, &qcom_mfd_regmap_cfg); + if (!regmap) return -ENODEV; - i2c_set_clientdata(client, chip); + i2c_set_clientdata(client, regmap); - if (of_property_read_bool(chip->dev->of_node, "interrupt-controller")) { - rc = pm8008_probe_irq_peripherals(chip, client->irq); + if (of_property_read_bool(dev->of_node, "interrupt-controller")) { + rc = pm8008_probe_irq_peripherals(dev, regmap, client->irq); if (rc) - dev_err(chip->dev, "Failed to probe irq periphs: %d\n", rc); + dev_err(dev, "Failed to probe irq periphs: %d\n", rc); } - return devm_of_platform_populate(chip->dev); + return devm_of_platform_populate(dev); } static const struct of_device_id pm8008_match[] = { diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c index 1cacc00aa6c9..7e2cd79d17eb 100644 --- a/drivers/mfd/qcom-spmi-pmic.c +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -3,120 +3,167 @@ * Copyright (c) 2014, The Linux Foundation. All rights reserved. */ +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gfp.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/spmi.h> +#include <linux/types.h> #include <linux/regmap.h> #include <linux/of_platform.h> +#include <soc/qcom/qcom-spmi-pmic.h> #define PMIC_REV2 0x101 #define PMIC_REV3 0x102 #define PMIC_REV4 0x103 #define PMIC_TYPE 0x104 #define PMIC_SUBTYPE 0x105 +#define PMIC_FAB_ID 0x1f2 #define PMIC_TYPE_VALUE 0x51 -#define COMMON_SUBTYPE 0x00 -#define PM8941_SUBTYPE 0x01 -#define PM8841_SUBTYPE 0x02 -#define PM8019_SUBTYPE 0x03 -#define PM8226_SUBTYPE 0x04 -#define PM8110_SUBTYPE 0x05 -#define PMA8084_SUBTYPE 0x06 -#define PMI8962_SUBTYPE 0x07 -#define PMD9635_SUBTYPE 0x08 -#define PM8994_SUBTYPE 0x09 -#define PMI8994_SUBTYPE 0x0a -#define PM8916_SUBTYPE 0x0b -#define PM8004_SUBTYPE 0x0c -#define PM8909_SUBTYPE 0x0d -#define PM8028_SUBTYPE 0x0e -#define PM8901_SUBTYPE 0x0f -#define PM8950_SUBTYPE 0x10 -#define PMI8950_SUBTYPE 0x11 -#define PM8998_SUBTYPE 0x14 -#define PMI8998_SUBTYPE 0x15 -#define PM8005_SUBTYPE 0x18 -#define PM660L_SUBTYPE 0x1A -#define PM660_SUBTYPE 0x1B -#define PM8150_SUBTYPE 0x1E -#define PM8150L_SUBTYPE 0x1f -#define PM8150B_SUBTYPE 0x20 -#define PMK8002_SUBTYPE 0x21 -#define PM8009_SUBTYPE 0x24 -#define PM8150C_SUBTYPE 0x26 -#define SMB2351_SUBTYPE 0x29 +#define PMIC_REV4_V2 0x02 + +struct qcom_spmi_dev { + int num_usids; + struct qcom_spmi_pmic pmic; +}; + +#define N_USIDS(n) ((void *)n) static const struct of_device_id pmic_spmi_id_table[] = { - { .compatible = "qcom,pm660", .data = (void *)PM660_SUBTYPE }, - { .compatible = "qcom,pm660l", .data = (void *)PM660L_SUBTYPE }, - { .compatible = "qcom,pm8004", .data = (void *)PM8004_SUBTYPE }, - { .compatible = "qcom,pm8005", .data = (void *)PM8005_SUBTYPE }, - { .compatible = "qcom,pm8019", .data = (void *)PM8019_SUBTYPE }, - { .compatible = "qcom,pm8028", .data = (void *)PM8028_SUBTYPE }, - { .compatible = "qcom,pm8110", .data = (void *)PM8110_SUBTYPE }, - { .compatible = "qcom,pm8150", .data = (void *)PM8150_SUBTYPE }, - { .compatible = "qcom,pm8150b", .data = (void *)PM8150B_SUBTYPE }, - { .compatible = "qcom,pm8150c", .data = (void *)PM8150C_SUBTYPE }, - { .compatible = "qcom,pm8150l", .data = (void *)PM8150L_SUBTYPE }, - { .compatible = "qcom,pm8226", .data = (void *)PM8226_SUBTYPE }, - { .compatible = "qcom,pm8841", .data = (void *)PM8841_SUBTYPE }, - { .compatible = "qcom,pm8901", .data = (void *)PM8901_SUBTYPE }, - { .compatible = "qcom,pm8909", .data = (void *)PM8909_SUBTYPE }, - { .compatible = "qcom,pm8916", .data = (void *)PM8916_SUBTYPE }, - { .compatible = "qcom,pm8941", .data = (void *)PM8941_SUBTYPE }, - { .compatible = "qcom,pm8950", .data = (void *)PM8950_SUBTYPE }, - { .compatible = "qcom,pm8994", .data = (void *)PM8994_SUBTYPE }, - { .compatible = "qcom,pm8998", .data = (void *)PM8998_SUBTYPE }, - { .compatible = "qcom,pma8084", .data = (void *)PMA8084_SUBTYPE }, - { .compatible = "qcom,pmd9635", .data = (void *)PMD9635_SUBTYPE }, - { .compatible = "qcom,pmi8950", .data = (void *)PMI8950_SUBTYPE }, - { .compatible = "qcom,pmi8962", .data = (void *)PMI8962_SUBTYPE }, - { .compatible = "qcom,pmi8994", .data = (void *)PMI8994_SUBTYPE }, - { .compatible = "qcom,pmi8998", .data = (void *)PMI8998_SUBTYPE }, - { .compatible = "qcom,pmk8002", .data = (void *)PMK8002_SUBTYPE }, - { .compatible = "qcom,smb2351", .data = (void *)SMB2351_SUBTYPE }, - { .compatible = "qcom,spmi-pmic", .data = (void *)COMMON_SUBTYPE }, + { .compatible = "qcom,pm660", .data = N_USIDS(2) }, + { .compatible = "qcom,pm660l", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8004", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8005", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8019", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8028", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8110", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150b", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150c", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8150l", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8226", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8841", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8901", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8909", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8916", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8941", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8950", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8994", .data = N_USIDS(2) }, + { .compatible = "qcom,pm8998", .data = N_USIDS(2) }, + { .compatible = "qcom,pma8084", .data = N_USIDS(2) }, + { .compatible = "qcom,pmd9635", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8950", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8962", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8994", .data = N_USIDS(2) }, + { .compatible = "qcom,pmi8998", .data = N_USIDS(2) }, + { .compatible = "qcom,pmk8002", .data = N_USIDS(2) }, + { .compatible = "qcom,pmp8074", .data = N_USIDS(2) }, + { .compatible = "qcom,smb2351", .data = N_USIDS(2) }, + { .compatible = "qcom,spmi-pmic", .data = N_USIDS(1) }, { } }; -static void pmic_spmi_show_revid(struct regmap *map, struct device *dev) +/* + * A PMIC can be represented by multiple SPMI devices, but + * only the base PMIC device will contain a reference to + * the revision information. + * + * This function takes a pointer to a pmic device and + * returns a pointer to the base PMIC device. + * + * This only supports PMICs with 1 or 2 USIDs. + */ +static struct spmi_device *qcom_pmic_get_base_usid(struct device *dev) { - unsigned int rev2, minor, major, type, subtype; - const char *name = "unknown"; - int ret, i; + struct spmi_device *sdev; + struct qcom_spmi_dev *ctx; + struct device_node *spmi_bus; + struct device_node *other_usid = NULL; + int function_parent_usid, ret; + u32 pmic_addr; - ret = regmap_read(map, PMIC_TYPE, &type); - if (ret < 0) - return; + sdev = to_spmi_device(dev); + ctx = dev_get_drvdata(&sdev->dev); - if (type != PMIC_TYPE_VALUE) - return; + /* + * Quick return if the function device is already in the base + * USID. This will always be hit for PMICs with only 1 USID. + */ + if (sdev->usid % ctx->num_usids == 0) + return sdev; - ret = regmap_read(map, PMIC_SUBTYPE, &subtype); + function_parent_usid = sdev->usid; + + /* + * Walk through the list of PMICs until we find the sibling USID. + * The goal is to find the first USID which is less than the + * number of USIDs in the PMIC array, e.g. for a PMIC with 2 USIDs + * where the function device is under USID 3, we want to find the + * device for USID 2. + */ + spmi_bus = of_get_parent(sdev->dev.of_node); + do { + other_usid = of_get_next_child(spmi_bus, other_usid); + + ret = of_property_read_u32_index(other_usid, "reg", 0, &pmic_addr); + if (ret) + return ERR_PTR(ret); + + sdev = spmi_device_from_of(other_usid); + if (pmic_addr == function_parent_usid - (ctx->num_usids - 1)) { + if (!sdev) + /* + * If the base USID for this PMIC hasn't probed yet + * but the secondary USID has, then we need to defer + * the function driver so that it will attempt to + * probe again when the base USID is ready. + */ + return ERR_PTR(-EPROBE_DEFER); + return sdev; + } + } while (other_usid->sibling); + + return ERR_PTR(-ENODATA); +} + +static int pmic_spmi_load_revid(struct regmap *map, struct device *dev, + struct qcom_spmi_pmic *pmic) +{ + int ret; + + ret = regmap_read(map, PMIC_TYPE, &pmic->type); if (ret < 0) - return; + return ret; - for (i = 0; i < ARRAY_SIZE(pmic_spmi_id_table); i++) { - if (subtype == (unsigned long)pmic_spmi_id_table[i].data) - break; - } + if (pmic->type != PMIC_TYPE_VALUE) + return ret; - if (i != ARRAY_SIZE(pmic_spmi_id_table)) - name = pmic_spmi_id_table[i].compatible; + ret = regmap_read(map, PMIC_SUBTYPE, &pmic->subtype); + if (ret < 0) + return ret; + + pmic->name = of_match_device(pmic_spmi_id_table, dev)->compatible; - ret = regmap_read(map, PMIC_REV2, &rev2); + ret = regmap_read(map, PMIC_REV2, &pmic->rev2); if (ret < 0) - return; + return ret; - ret = regmap_read(map, PMIC_REV3, &minor); + ret = regmap_read(map, PMIC_REV3, &pmic->minor); if (ret < 0) - return; + return ret; - ret = regmap_read(map, PMIC_REV4, &major); + ret = regmap_read(map, PMIC_REV4, &pmic->major); if (ret < 0) - return; + return ret; + + if (pmic->subtype == PMI8998_SUBTYPE || pmic->subtype == PM660_SUBTYPE) { + ret = regmap_read(map, PMIC_FAB_ID, &pmic->fab_id); + if (ret < 0) + return ret; + } /* * In early versions of PM8941 and PM8226, the major revision number @@ -124,16 +171,50 @@ static void pmic_spmi_show_revid(struct regmap *map, struct device *dev) * Increment the major revision number here if the chip is an early * version of PM8941 or PM8226. */ - if ((subtype == PM8941_SUBTYPE || subtype == PM8226_SUBTYPE) && - major < 0x02) - major++; + if ((pmic->subtype == PM8941_SUBTYPE || pmic->subtype == PM8226_SUBTYPE) && + pmic->major < PMIC_REV4_V2) + pmic->major++; + + if (pmic->subtype == PM8110_SUBTYPE) + pmic->minor = pmic->rev2; - if (subtype == PM8110_SUBTYPE) - minor = rev2; + dev_dbg(dev, "%x: %s v%d.%d\n", + pmic->subtype, pmic->name, pmic->major, pmic->minor); - dev_dbg(dev, "%x: %s v%d.%d\n", subtype, name, major, minor); + return 0; } +/** + * qcom_pmic_get() - Get a pointer to the base PMIC device + * + * This function takes a struct device for a driver which is a child of a PMIC. + * And locates the PMIC revision information for it. + * + * @dev: the pmic function device + * @return: the struct qcom_spmi_pmic* pointer associated with the function device + */ +const struct qcom_spmi_pmic *qcom_pmic_get(struct device *dev) +{ + struct spmi_device *sdev; + struct qcom_spmi_dev *spmi; + + /* + * Make sure the device is actually a child of a PMIC + */ + if (!of_match_device(pmic_spmi_id_table, dev->parent)) + return ERR_PTR(-EINVAL); + + sdev = qcom_pmic_get_base_usid(dev->parent); + + if (IS_ERR(sdev)) + return ERR_CAST(sdev); + + spmi = dev_get_drvdata(&sdev->dev); + + return &spmi->pmic; +} +EXPORT_SYMBOL(qcom_pmic_get); + static const struct regmap_config spmi_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -144,14 +225,26 @@ static const struct regmap_config spmi_regmap_config = { static int pmic_spmi_probe(struct spmi_device *sdev) { struct regmap *regmap; + struct qcom_spmi_dev *ctx; + int ret; regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); + ctx = devm_kzalloc(&sdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->num_usids = (uintptr_t)of_device_get_match_data(&sdev->dev); + /* Only the first slave id for a PMIC contains this information */ - if (sdev->usid % 2 == 0) - pmic_spmi_show_revid(regmap, &sdev->dev); + if (sdev->usid % ctx->num_usids == 0) { + ret = pmic_spmi_load_revid(regmap, &sdev->dev, &ctx->pmic); + if (ret < 0) + return ret; + } + spmi_device_set_drvdata(sdev, ctx); return devm_of_platform_populate(&sdev->dev); } diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c index c748fd29a220..3b5acf7ca39c 100644 --- a/drivers/mfd/retu-mfd.c +++ b/drivers/mfd/retu-mfd.c @@ -287,7 +287,7 @@ static int retu_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return 0; } -static int retu_remove(struct i2c_client *i2c) +static void retu_remove(struct i2c_client *i2c) { struct retu_dev *rdev = i2c_get_clientdata(i2c); @@ -297,8 +297,6 @@ static int retu_remove(struct i2c_client *i2c) } mfd_remove_devices(rdev->dev); regmap_del_irq_chip(i2c->irq, rdev->irq_data); - - return 0; } static const struct i2c_device_id retu_id[] = { diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index b181fe401330..e00da7c7e3b1 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/of_device.h> #include <linux/regmap.h> +#include <linux/reboot.h> struct rk808_reg_data { int addr; @@ -66,6 +67,10 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg) case RK817_SECONDS_REG ... RK817_WEEKS_REG: case RK817_RTC_STATUS_REG: case RK817_CODEC_DTOP_LPT_SRST: + case RK817_GAS_GAUGE_ADC_CONFIG0 ... RK817_GAS_GAUGE_CUR_ADC_K0: + case RK817_PMIC_CHRG_STS: + case RK817_PMIC_CHRG_OUT: + case RK817_PMIC_CHRG_IN: case RK817_INT_STS_REG0: case RK817_INT_STS_REG1: case RK817_INT_STS_REG2: @@ -73,7 +78,7 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg) return true; } - return true; + return false; } static const struct regmap_config rk818_regmap_config = { @@ -126,6 +131,11 @@ static const struct resource rk817_pwrkey_resources[] = { DEFINE_RES_IRQ(RK817_IRQ_PWRON_FALL), }; +static const struct resource rk817_charger_resources[] = { + DEFINE_RES_IRQ(RK817_IRQ_PLUG_IN), + DEFINE_RES_IRQ(RK817_IRQ_PLUG_OUT), +}; + static const struct mfd_cell rk805s[] = { { .name = "rk808-clkout", }, { .name = "rk808-regulator", }, @@ -165,6 +175,11 @@ static const struct mfd_cell rk817s[] = { .resources = &rk817_rtc_resources[0], }, { .name = "rk817-codec",}, + { + .name = "rk817-charger", + .num_resources = ARRAY_SIZE(rk817_charger_resources), + .resources = &rk817_charger_resources[0], + }, }; static const struct mfd_cell rk818s[] = { @@ -543,6 +558,7 @@ static void rk808_pm_power_off(void) reg = RK808_DEVCTRL_REG, bit = DEV_OFF_RST; break; + case RK809_ID: case RK817_ID: reg = RK817_SYS_CFG(3); bit = DEV_OFF; @@ -559,6 +575,34 @@ static void rk808_pm_power_off(void) dev_err(&rk808_i2c_client->dev, "Failed to shutdown device!\n"); } +static int rk808_restart_notify(struct notifier_block *this, unsigned long mode, void *cmd) +{ + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + unsigned int reg, bit; + int ret; + + switch (rk808->variant) { + case RK809_ID: + case RK817_ID: + reg = RK817_SYS_CFG(3); + bit = DEV_RST; + break; + + default: + return NOTIFY_DONE; + } + ret = regmap_update_bits(rk808->regmap, reg, bit, bit); + if (ret) + dev_err(&rk808_i2c_client->dev, "Failed to restart device!\n"); + + return NOTIFY_DONE; +} + +static struct notifier_block rk808_restart_handler = { + .notifier_call = rk808_restart_notify, + .priority = 192, +}; + static void rk8xx_shutdown(struct i2c_client *client) { struct rk808 *rk808 = i2c_get_clientdata(client); @@ -727,6 +771,18 @@ static int rk808_probe(struct i2c_client *client, if (of_property_read_bool(np, "rockchip,system-power-controller")) { rk808_i2c_client = client; pm_power_off = rk808_pm_power_off; + + switch (rk808->variant) { + case RK809_ID: + case RK817_ID: + ret = register_restart_handler(&rk808_restart_handler); + if (ret) + dev_warn(&client->dev, "failed to register rst handler, %d\n", ret); + break; + default: + dev_dbg(&client->dev, "pmic controlled board reset not supported\n"); + break; + } } return 0; @@ -736,7 +792,7 @@ err_irq: return ret; } -static int rk808_remove(struct i2c_client *client) +static void rk808_remove(struct i2c_client *client) { struct rk808 *rk808 = i2c_get_clientdata(client); @@ -749,7 +805,7 @@ static int rk808_remove(struct i2c_client *client) if (pm_power_off == rk808_pm_power_off) pm_power_off = NULL; - return 0; + unregister_restart_handler(&rk808_restart_handler); } static int __maybe_unused rk8xx_suspend(struct device *dev) diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index 384acb459427..eb8005b4e58d 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -241,7 +241,7 @@ static int rn5t618_i2c_probe(struct i2c_client *i2c) return rn5t618_irq_init(priv); } -static int rn5t618_i2c_remove(struct i2c_client *i2c) +static void rn5t618_i2c_remove(struct i2c_client *i2c) { if (i2c == rn5t618_pm_power_off) { rn5t618_pm_power_off = NULL; @@ -249,8 +249,6 @@ static int rn5t618_i2c_remove(struct i2c_client *i2c) } unregister_restart_handler(&rn5t618_restart_handler); - - return 0; } static int __maybe_unused rn5t618_i2c_suspend(struct device *dev) diff --git a/drivers/mfd/rohm-bd70528.c b/drivers/mfd/rohm-bd70528.c deleted file mode 100644 index 5c44d3b77b3e..000000000000 --- a/drivers/mfd/rohm-bd70528.c +++ /dev/null @@ -1,314 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// -// Copyright (C) 2019 ROHM Semiconductors -// -// ROHM BD70528 PMIC driver - -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/irq.h> -#include <linux/mfd/core.h> -#include <linux/mfd/rohm-bd70528.h> -#include <linux/module.h> -#include <linux/of_device.h> -#include <linux/regmap.h> -#include <linux/types.h> - -#define BD70528_NUM_OF_GPIOS 4 - -static const struct resource rtc_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD70528_INT_RTC_ALARM, "bd70528-rtc-alm"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_ELPS_TIM, "bd70528-elapsed-timer"), -}; - -static const struct resource charger_irqs[] = { - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_OV_RES, "bd70528-bat-ov-res"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_OV_DET, "bd70528-bat-ov-det"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DBAT_DET, "bd70528-bat-dead"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_COLD_RES, "bd70528-bat-warmed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_COLD_DET, "bd70528-bat-cold"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_HOT_RES, "bd70528-bat-cooled"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BATTSD_HOT_DET, "bd70528-bat-hot"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_CHG_TSD, "bd70528-chg-tshd"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_RMV, "bd70528-bat-removed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_BAT_DET, "bd70528-bat-detected"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_OV_RES, "bd70528-dcin2-ov-res"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_OV_DET, "bd70528-dcin2-ov-det"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_RMV, "bd70528-dcin2-removed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN2_DET, "bd70528-dcin2-detected"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN1_RMV, "bd70528-dcin1-removed"), - DEFINE_RES_IRQ_NAMED(BD70528_INT_DCIN1_DET, "bd70528-dcin1-detected"), -}; - -static struct mfd_cell bd70528_mfd_cells[] = { - { .name = "bd70528-pmic", }, - { .name = "bd70528-gpio", }, - /* - * We use BD71837 driver to drive the clock block. Only differences to - * BD70528 clock gate are the register address and mask. - */ - { .name = "bd70528-clk", }, - { .name = "bd70528-wdt", }, - { - .name = "bd70528-power", - .resources = charger_irqs, - .num_resources = ARRAY_SIZE(charger_irqs), - }, { - .name = "bd70528-rtc", - .resources = rtc_irqs, - .num_resources = ARRAY_SIZE(rtc_irqs), - }, -}; - -static const struct regmap_range volatile_ranges[] = { - { - .range_min = BD70528_REG_INT_MAIN, - .range_max = BD70528_REG_INT_OP_FAIL, - }, { - .range_min = BD70528_REG_RTC_COUNT_H, - .range_max = BD70528_REG_RTC_ALM_REPEAT, - }, { - /* - * WDT control reg is special. Magic values must be written to - * it in order to change the control. Should not be cached. - */ - .range_min = BD70528_REG_WDT_CTRL, - .range_max = BD70528_REG_WDT_CTRL, - }, { - /* - * BD70528 also contains a few other registers which require - * magic sequences to be written in order to update the value. - * At least SHIPMODE, HWRESET, WARMRESET,and STANDBY - */ - .range_min = BD70528_REG_SHIPMODE, - .range_max = BD70528_REG_STANDBY, - }, -}; - -static const struct regmap_access_table volatile_regs = { - .yes_ranges = &volatile_ranges[0], - .n_yes_ranges = ARRAY_SIZE(volatile_ranges), -}; - -static struct regmap_config bd70528_regmap = { - .reg_bits = 8, - .val_bits = 8, - .volatile_table = &volatile_regs, - .max_register = BD70528_MAX_REGISTER, - .cache_type = REGCACHE_RBTREE, -}; - -/* - * Mapping of main IRQ register bits to sub-IRQ register offsets so that we can - * access corect sub-IRQ registers based on bits that are set in main IRQ - * register. - */ - -static unsigned int bit0_offsets[] = {0}; /* Shutdown */ -static unsigned int bit1_offsets[] = {1}; /* Power failure */ -static unsigned int bit2_offsets[] = {2}; /* VR FAULT */ -static unsigned int bit3_offsets[] = {3}; /* PMU interrupts */ -static unsigned int bit4_offsets[] = {4, 5}; /* Charger 1 and Charger 2 */ -static unsigned int bit5_offsets[] = {6}; /* RTC */ -static unsigned int bit6_offsets[] = {7}; /* GPIO */ -static unsigned int bit7_offsets[] = {8}; /* Invalid operation */ - -static struct regmap_irq_sub_irq_map bd70528_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 struct regmap_irq bd70528_irqs[] = { - REGMAP_IRQ_REG(BD70528_INT_LONGPUSH, 0, BD70528_INT_LONGPUSH_MASK), - REGMAP_IRQ_REG(BD70528_INT_WDT, 0, BD70528_INT_WDT_MASK), - REGMAP_IRQ_REG(BD70528_INT_HWRESET, 0, BD70528_INT_HWRESET_MASK), - REGMAP_IRQ_REG(BD70528_INT_RSTB_FAULT, 0, BD70528_INT_RSTB_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_VBAT_UVLO, 0, BD70528_INT_VBAT_UVLO_MASK), - REGMAP_IRQ_REG(BD70528_INT_TSD, 0, BD70528_INT_TSD_MASK), - REGMAP_IRQ_REG(BD70528_INT_RSTIN, 0, BD70528_INT_RSTIN_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_FAULT, 1, - BD70528_INT_BUCK1_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_FAULT, 1, - BD70528_INT_BUCK2_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK3_FAULT, 1, - BD70528_INT_BUCK3_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LDO1_FAULT, 1, BD70528_INT_LDO1_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LDO2_FAULT, 1, BD70528_INT_LDO2_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LDO3_FAULT, 1, BD70528_INT_LDO3_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED1_FAULT, 1, BD70528_INT_LED1_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED2_FAULT, 1, BD70528_INT_LED2_FAULT_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_OCP, 2, BD70528_INT_BUCK1_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_OCP, 2, BD70528_INT_BUCK2_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK3_OCP, 2, BD70528_INT_BUCK3_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED1_OCP, 2, BD70528_INT_LED1_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED2_OCP, 2, BD70528_INT_LED2_OCP_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_FULLON, 2, - BD70528_INT_BUCK1_FULLON_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_FULLON, 2, - BD70528_INT_BUCK2_FULLON_MASK), - REGMAP_IRQ_REG(BD70528_INT_SHORTPUSH, 3, BD70528_INT_SHORTPUSH_MASK), - REGMAP_IRQ_REG(BD70528_INT_AUTO_WAKEUP, 3, - BD70528_INT_AUTO_WAKEUP_MASK), - REGMAP_IRQ_REG(BD70528_INT_STATE_CHANGE, 3, - BD70528_INT_STATE_CHANGE_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_OV_RES, 4, BD70528_INT_BAT_OV_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_OV_DET, 4, BD70528_INT_BAT_OV_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DBAT_DET, 4, BD70528_INT_DBAT_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_COLD_RES, 4, - BD70528_INT_BATTSD_COLD_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_COLD_DET, 4, - BD70528_INT_BATTSD_COLD_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_HOT_RES, 4, - BD70528_INT_BATTSD_HOT_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_BATTSD_HOT_DET, 4, - BD70528_INT_BATTSD_HOT_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_CHG_TSD, 4, BD70528_INT_CHG_TSD_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_RMV, 5, BD70528_INT_BAT_RMV_MASK), - REGMAP_IRQ_REG(BD70528_INT_BAT_DET, 5, BD70528_INT_BAT_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_OV_RES, 5, - BD70528_INT_DCIN2_OV_RES_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_OV_DET, 5, - BD70528_INT_DCIN2_OV_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_RMV, 5, BD70528_INT_DCIN2_RMV_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN2_DET, 5, BD70528_INT_DCIN2_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN1_RMV, 5, BD70528_INT_DCIN1_RMV_MASK), - REGMAP_IRQ_REG(BD70528_INT_DCIN1_DET, 5, BD70528_INT_DCIN1_DET_MASK), - REGMAP_IRQ_REG(BD70528_INT_RTC_ALARM, 6, BD70528_INT_RTC_ALARM_MASK), - REGMAP_IRQ_REG(BD70528_INT_ELPS_TIM, 6, BD70528_INT_ELPS_TIM_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO0, 7, BD70528_INT_GPIO0_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO1, 7, BD70528_INT_GPIO1_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO2, 7, BD70528_INT_GPIO2_MASK), - REGMAP_IRQ_REG(BD70528_INT_GPIO3, 7, BD70528_INT_GPIO3_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK1_DVS_OPFAIL, 8, - BD70528_INT_BUCK1_DVS_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK2_DVS_OPFAIL, 8, - BD70528_INT_BUCK2_DVS_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_BUCK3_DVS_OPFAIL, 8, - BD70528_INT_BUCK3_DVS_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED1_VOLT_OPFAIL, 8, - BD70528_INT_LED1_VOLT_OPFAIL_MASK), - REGMAP_IRQ_REG(BD70528_INT_LED2_VOLT_OPFAIL, 8, - BD70528_INT_LED2_VOLT_OPFAIL_MASK), -}; - -static struct regmap_irq_chip bd70528_irq_chip = { - .name = "bd70528_irq", - .main_status = BD70528_REG_INT_MAIN, - .irqs = &bd70528_irqs[0], - .num_irqs = ARRAY_SIZE(bd70528_irqs), - .status_base = BD70528_REG_INT_SHDN, - .mask_base = BD70528_REG_INT_SHDN_MASK, - .ack_base = BD70528_REG_INT_SHDN, - .type_base = BD70528_REG_GPIO1_IN, - .init_ack_masked = true, - .num_regs = 9, - .num_main_regs = 1, - .num_type_reg = 4, - .sub_reg_offsets = &bd70528_sub_irq_offsets[0], - .num_main_status_bits = 8, - .irq_reg_stride = 1, -}; - -static int bd70528_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) -{ - struct bd70528_data *bd70528; - struct regmap_irq_chip_data *irq_data; - int ret, i; - - if (!i2c->irq) { - dev_err(&i2c->dev, "No IRQ configured\n"); - return -EINVAL; - } - - bd70528 = devm_kzalloc(&i2c->dev, sizeof(*bd70528), GFP_KERNEL); - if (!bd70528) - return -ENOMEM; - - mutex_init(&bd70528->rtc_timer_lock); - - dev_set_drvdata(&i2c->dev, &bd70528->chip); - - bd70528->chip.regmap = devm_regmap_init_i2c(i2c, &bd70528_regmap); - if (IS_ERR(bd70528->chip.regmap)) { - dev_err(&i2c->dev, "Failed to initialize Regmap\n"); - return PTR_ERR(bd70528->chip.regmap); - } - - /* - * Disallow type setting for all IRQs by default as most of them do not - * support setting type. - */ - for (i = 0; i < ARRAY_SIZE(bd70528_irqs); i++) - bd70528_irqs[i].type.types_supported = 0; - - /* Set IRQ typesetting information for GPIO pins 0 - 3 */ - for (i = 0; i < BD70528_NUM_OF_GPIOS; i++) { - struct regmap_irq_type *type; - - type = &bd70528_irqs[BD70528_INT_GPIO0 + i].type; - type->type_reg_offset = 2 * i; - type->type_rising_val = 0x20; - type->type_falling_val = 0x10; - type->type_level_high_val = 0x40; - type->type_level_low_val = 0x50; - type->types_supported = (IRQ_TYPE_EDGE_BOTH | - IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW); - } - - ret = devm_regmap_add_irq_chip(&i2c->dev, bd70528->chip.regmap, - i2c->irq, IRQF_ONESHOT, 0, - &bd70528_irq_chip, &irq_data); - if (ret) { - dev_err(&i2c->dev, "Failed to add IRQ chip\n"); - return ret; - } - dev_dbg(&i2c->dev, "Registered %d IRQs for chip\n", - bd70528_irq_chip.num_irqs); - - /* - * BD70528 IRQ controller is not touching the main mask register. - * So enable the GPIO block interrupts at main level. We can just leave - * them enabled as the IRQ controller should disable IRQs from - * sub-registers when IRQ is disabled or freed. - */ - ret = regmap_update_bits(bd70528->chip.regmap, - BD70528_REG_INT_MAIN_MASK, - BD70528_INT_GPIO_MASK, 0); - - ret = devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, - bd70528_mfd_cells, - ARRAY_SIZE(bd70528_mfd_cells), NULL, 0, - regmap_irq_get_domain(irq_data)); - if (ret) - dev_err(&i2c->dev, "Failed to create subdevices\n"); - - return ret; -} - -static const struct of_device_id bd70528_of_match[] = { - { .compatible = "rohm,bd70528", }, - { }, -}; -MODULE_DEVICE_TABLE(of, bd70528_of_match); - -static struct i2c_driver bd70528_drv = { - .driver = { - .name = "rohm-bd70528", - .of_match_table = bd70528_of_match, - }, - .probe = &bd70528_i2c_probe, -}; - -module_i2c_driver(bd70528_drv); - -MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); -MODULE_DESCRIPTION("ROHM BD70528 Power Management IC driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/rohm-bd9576.c b/drivers/mfd/rohm-bd9576.c index 6661a27d69a8..f37cd4f27aeb 100644 --- a/drivers/mfd/rohm-bd9576.c +++ b/drivers/mfd/rohm-bd9576.c @@ -23,7 +23,7 @@ enum { }; /* - * Due to the BD9576MUF nasty IRQ behaiour we don't always populate IRQs. + * Due to the BD9576MUF nasty IRQ behaviour we don't always populate IRQs. * These will be added to regulator resources only if IRQ information for the * PMIC is populated in device-tree. */ diff --git a/drivers/mfd/rsmu_i2c.c b/drivers/mfd/rsmu_i2c.c index dc001c9791c1..f716ab8039a0 100644 --- a/drivers/mfd/rsmu_i2c.c +++ b/drivers/mfd/rsmu_i2c.c @@ -146,13 +146,11 @@ static int rsmu_i2c_probe(struct i2c_client *client, return rsmu_core_init(rsmu); } -static int rsmu_i2c_remove(struct i2c_client *client) +static void rsmu_i2c_remove(struct i2c_client *client) { struct rsmu_ddata *rsmu = i2c_get_clientdata(client); rsmu_core_exit(rsmu); - - return 0; } static const struct i2c_device_id rsmu_i2c_id[] = { diff --git a/drivers/mfd/rsmu_spi.c b/drivers/mfd/rsmu_spi.c index fec2b4ec477c..d2f3d8f1e05a 100644 --- a/drivers/mfd/rsmu_spi.c +++ b/drivers/mfd/rsmu_spi.c @@ -220,13 +220,11 @@ static int rsmu_spi_probe(struct spi_device *client) return rsmu_core_init(rsmu); } -static int rsmu_spi_remove(struct spi_device *client) +static void rsmu_spi_remove(struct spi_device *client) { struct rsmu_ddata *rsmu = spi_get_drvdata(client); rsmu_core_exit(rsmu); - - return 0; } static const struct spi_device_id rsmu_spi_id[] = { diff --git a/drivers/mfd/rt4831.c b/drivers/mfd/rt4831.c index b169781ac675..c6d34dc2b520 100644 --- a/drivers/mfd/rt4831.c +++ b/drivers/mfd/rt4831.c @@ -87,12 +87,15 @@ static int rt4831_probe(struct i2c_client *client) ARRAY_SIZE(rt4831_subdevs), NULL, 0, NULL); } -static int rt4831_remove(struct i2c_client *client) +static void rt4831_remove(struct i2c_client *client) { struct regmap *regmap = dev_get_regmap(&client->dev, NULL); + int ret; /* Disable WLED and DSV outputs */ - return regmap_update_bits(regmap, RT4831_REG_ENABLE, RT4831_RESET_MASK, RT4831_RESET_MASK); + ret = regmap_update_bits(regmap, RT4831_REG_ENABLE, RT4831_RESET_MASK, RT4831_RESET_MASK); + if (ret) + dev_warn(&client->dev, "Failed to disable outputs (%pe)\n", ERR_PTR(ret)); } static const struct of_device_id __maybe_unused rt4831_of_match[] = { diff --git a/drivers/mfd/rt5120.c b/drivers/mfd/rt5120.c new file mode 100644 index 000000000000..8046e383bc92 --- /dev/null +++ b/drivers/mfd/rt5120.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Richtek Technology Corp. + * Author: ChiYuan Huang <cy_huang@richtek.com> + */ + +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> + +#define RT5120_REG_INTENABLE 0x1D +#define RT5120_REG_INTSTAT 0x1E +#define RT5120_REG_FZCMODE 0x44 + +#define RT5120_INT_HOTDIE 0 +#define RT5120_INT_PWRKEY_REL 5 +#define RT5120_INT_PWRKEY_PRESS 6 + +static const struct regmap_range rt5120_rd_yes_ranges[] = { + regmap_reg_range(0x03, 0x13), + regmap_reg_range(0x1c, 0x20), + regmap_reg_range(0x44, 0x44), +}; + +static const struct regmap_range rt5120_wr_yes_ranges[] = { + regmap_reg_range(0x06, 0x13), + regmap_reg_range(0x1c, 0x20), + regmap_reg_range(0x44, 0x44), +}; + +static const struct regmap_access_table rt5120_rd_table = { + .yes_ranges = rt5120_rd_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(rt5120_rd_yes_ranges), +}; + +static const struct regmap_access_table rt5120_wr_table = { + .yes_ranges = rt5120_wr_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(rt5120_wr_yes_ranges), +}; + +static const struct regmap_config rt5120_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RT5120_REG_FZCMODE, + + .wr_table = &rt5120_wr_table, + .rd_table = &rt5120_rd_table, +}; + +static const struct regmap_irq rt5120_irqs[] = { + REGMAP_IRQ_REG_LINE(RT5120_INT_HOTDIE, 8), + REGMAP_IRQ_REG_LINE(RT5120_INT_PWRKEY_REL, 8), + REGMAP_IRQ_REG_LINE(RT5120_INT_PWRKEY_PRESS, 8), +}; + +static const struct regmap_irq_chip rt5120_irq_chip = { + .name = "rt5120-pmic", + .status_base = RT5120_REG_INTSTAT, + .mask_base = RT5120_REG_INTENABLE, + .ack_base = RT5120_REG_INTSTAT, + .mask_invert = true, + .use_ack = true, + .num_regs = 1, + .irqs = rt5120_irqs, + .num_irqs = ARRAY_SIZE(rt5120_irqs), +}; + +static const struct resource rt5120_regulator_resources[] = { + DEFINE_RES_IRQ(RT5120_INT_HOTDIE), +}; + +static const struct resource rt5120_pwrkey_resources[] = { + DEFINE_RES_IRQ_NAMED(RT5120_INT_PWRKEY_PRESS, "pwrkey-press"), + DEFINE_RES_IRQ_NAMED(RT5120_INT_PWRKEY_REL, "pwrkey-release"), +}; + +static const struct mfd_cell rt5120_devs[] = { + MFD_CELL_RES("rt5120-regulator", rt5120_regulator_resources), + MFD_CELL_OF("rt5120-pwrkey", rt5120_pwrkey_resources, NULL, 0, 0, "richtek,rt5120-pwrkey"), +}; + +static int rt5120_probe(struct i2c_client *i2c) +{ + struct device *dev = &i2c->dev; + struct regmap *regmap; + struct regmap_irq_chip_data *irq_data; + int ret; + + regmap = devm_regmap_init_i2c(i2c, &rt5120_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Failed to init regmap\n"); + + ret = devm_regmap_add_irq_chip(dev, regmap, i2c->irq, IRQF_ONESHOT, 0, + &rt5120_irq_chip, &irq_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to add IRQ chip\n"); + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, rt5120_devs, + ARRAY_SIZE(rt5120_devs), NULL, 0, + regmap_irq_get_domain(irq_data)); +} + +static const struct of_device_id rt5120_device_match_table[] = { + { .compatible = "richtek,rt5120" }, + {} +}; +MODULE_DEVICE_TABLE(of, rt5120_device_match_table); + +static struct i2c_driver rt5120_driver = { + .driver = { + .name = "rt5120", + .of_match_table = rt5120_device_match_table, + }, + .probe_new = rt5120_probe, +}; +module_i2c_driver(rt5120_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RT5120 I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index a2635c2d9d1a..8166949b725c 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -835,7 +835,7 @@ free_gpio: return rval; } -static int si476x_core_remove(struct i2c_client *client) +static void si476x_core_remove(struct i2c_client *client) { struct si476x_core *core = i2c_get_clientdata(client); @@ -851,8 +851,6 @@ static int si476x_core_remove(struct i2c_client *client) if (gpio_is_valid(core->gpio_reset)) gpio_free(core->gpio_reset); - - return 0; } diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index 51536691ad9d..f4c8fc3ee463 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -62,8 +62,19 @@ static int simple_mfd_i2c_probe(struct i2c_client *i2c) return ret; } +static const struct mfd_cell sy7636a_cells[] = { + { .name = "sy7636a-regulator", }, + { .name = "sy7636a-temperature", }, +}; + +static const struct simple_mfd_data silergy_sy7636a = { + .mfd_cell = sy7636a_cells, + .mfd_cell_size = ARRAY_SIZE(sy7636a_cells), +}; + static const struct of_device_id simple_mfd_i2c_of_match[] = { { .compatible = "kontron,sl28cpld" }, + { .compatible = "silergy,sy7636a", .data = &silergy_sy7636a}, {} }; MODULE_DEVICE_TABLE(of, simple_mfd_i2c_of_match); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index bc0a2c38653e..3ac4508a6742 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1720,7 +1720,12 @@ static struct platform_driver sm501_plat_driver = { static int __init sm501_base_init(void) { - platform_driver_register(&sm501_plat_driver); + int ret; + + ret = platform_driver_register(&sm501_plat_driver); + if (ret < 0) + return ret; + return pci_register_driver(&sm501_pci_driver); } diff --git a/drivers/mfd/sprd-sc27xx-spi.c b/drivers/mfd/sprd-sc27xx-spi.c index 55d2c31bdfb2..d05a47c5187f 100644 --- a/drivers/mfd/sprd-sc27xx-spi.c +++ b/drivers/mfd/sprd-sc27xx-spi.c @@ -240,13 +240,14 @@ static int sprd_pmic_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(sprd_pmic_pm_ops, sprd_pmic_suspend, sprd_pmic_resume); static const struct of_device_id sprd_pmic_match[] = { - { .compatible = "sprd,sc2731", .data = &sc2731_data }, { .compatible = "sprd,sc2730", .data = &sc2730_data }, + { .compatible = "sprd,sc2731", .data = &sc2731_data }, {}, }; MODULE_DEVICE_TABLE(of, sprd_pmic_match); static const struct spi_device_id sprd_pmic_spi_ids[] = { + { .name = "sc2730", .driver_data = (unsigned long)&sc2730_data }, { .name = "sc2731", .driver_data = (unsigned long)&sc2731_data }, {}, }; diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index 1819c8fe4d8f..02cc49daf2e3 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c @@ -590,7 +590,7 @@ static int sta2x11_mfd_probe(struct pci_dev *pdev, /* Record this pdev before mfd_add_devices: their probe looks for it */ if (!sta2x11_mfd_find(pdev)) - sta2x11_mfd_add(pdev, GFP_ATOMIC); + sta2x11_mfd_add(pdev, GFP_KERNEL); /* Just 2 bars for all mfd's at present */ for (i = 0; i < 2; i++) { diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c index e095a3930142..5dd7d9688459 100644 --- a/drivers/mfd/stmfx.c +++ b/drivers/mfd/stmfx.c @@ -392,17 +392,22 @@ err: return ret; } -static int stmfx_chip_exit(struct i2c_client *client) +static void stmfx_chip_exit(struct i2c_client *client) { struct stmfx *stmfx = i2c_get_clientdata(client); regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, 0); regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, 0); - if (stmfx->vdd) - return regulator_disable(stmfx->vdd); + if (stmfx->vdd) { + int ret; - return 0; + ret = regulator_disable(stmfx->vdd); + if (ret) + dev_err(&client->dev, + "Failed to disable vdd regulator: %pe\n", + ERR_PTR(ret)); + } } static int stmfx_probe(struct i2c_client *client, @@ -462,11 +467,11 @@ err_chip_exit: return ret; } -static int stmfx_remove(struct i2c_client *client) +static void stmfx_remove(struct i2c_client *client) { stmfx_irq_exit(client); - return stmfx_chip_exit(client); + stmfx_chip_exit(client); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index d3eedf3d607e..4d55494a97c4 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -91,13 +91,11 @@ stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) return stmpe_probe(&i2c_ci, partnum); } -static int stmpe_i2c_remove(struct i2c_client *i2c) +static void stmpe_i2c_remove(struct i2c_client *i2c) { struct stmpe *stmpe = dev_get_drvdata(&i2c->dev); stmpe_remove(stmpe); - - return 0; } static const struct i2c_device_id stmpe_i2c_id[] = { diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index 6c5915016be5..ad8055a0e286 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -102,13 +102,11 @@ stmpe_spi_probe(struct spi_device *spi) return stmpe_probe(&spi_ci, id->driver_data); } -static int stmpe_spi_remove(struct spi_device *spi) +static void stmpe_spi_remove(struct spi_device *spi) { struct stmpe *stmpe = spi_get_drvdata(spi); stmpe_remove(stmpe); - - return 0; } static const struct of_device_id stmpe_spi_of_match[] = { diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index e928df95e316..0c4f74197d3e 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -8,14 +8,13 @@ */ #include <linux/err.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/export.h> #include <linux/kernel.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/pm.h> #include <linux/slab.h> #include <linux/mfd/core.h> @@ -30,17 +29,12 @@ * @irq_trigger: IRQ trigger to use for the interrupt to the host * @autosleep: bool to enable/disable stmpe autosleep * @autosleep_timeout: inactivity timeout in milliseconds for autosleep - * @irq_over_gpio: true if gpio is used to get irq - * @irq_gpio: gpio number over which irq will be requested (significant only if - * irq_over_gpio is true) */ struct stmpe_platform_data { int id; unsigned int blocks; unsigned int irq_trigger; bool autosleep; - bool irq_over_gpio; - int irq_gpio; int autosleep_timeout; }; @@ -1349,32 +1343,22 @@ static void stmpe_of_probe(struct stmpe_platform_data *pdata, if (pdata->id < 0) pdata->id = -1; - pdata->irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0, - &pdata->irq_trigger); - if (gpio_is_valid(pdata->irq_gpio)) - pdata->irq_over_gpio = 1; - else - pdata->irq_trigger = IRQF_TRIGGER_NONE; - of_property_read_u32(np, "st,autosleep-timeout", &pdata->autosleep_timeout); pdata->autosleep = (pdata->autosleep_timeout) ? true : false; - for_each_child_of_node(np, child) { - if (of_node_name_eq(child, "stmpe_gpio")) { + for_each_available_child_of_node(np, child) { + if (of_device_is_compatible(child, stmpe_gpio_cell.of_compatible)) pdata->blocks |= STMPE_BLOCK_GPIO; - } else if (of_node_name_eq(child, "stmpe_keypad")) { + else if (of_device_is_compatible(child, stmpe_keypad_cell.of_compatible)) pdata->blocks |= STMPE_BLOCK_KEYPAD; - } else if (of_node_name_eq(child, "stmpe_touchscreen")) { + else if (of_device_is_compatible(child, stmpe_ts_cell.of_compatible)) pdata->blocks |= STMPE_BLOCK_TOUCHSCREEN; - } else if (of_node_name_eq(child, "stmpe_adc")) { + else if (of_device_is_compatible(child, stmpe_adc_cell.of_compatible)) pdata->blocks |= STMPE_BLOCK_ADC; - } else if (of_node_name_eq(child, "stmpe_pwm")) { + else if (of_device_is_compatible(child, stmpe_pwm_cell.of_compatible)) pdata->blocks |= STMPE_BLOCK_PWM; - } else if (of_node_name_eq(child, "stmpe_rotator")) { - pdata->blocks |= STMPE_BLOCK_ROTATOR; - } } } @@ -1384,6 +1368,7 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) struct stmpe_platform_data *pdata; struct device_node *np = ci->dev->of_node; struct stmpe *stmpe; + struct gpio_desc *irq_gpio; int ret; u32 val; @@ -1437,18 +1422,20 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum) if (ci->init) ci->init(stmpe); - if (pdata->irq_over_gpio) { - ret = devm_gpio_request_one(ci->dev, pdata->irq_gpio, - GPIOF_DIR_IN, "stmpe"); - if (ret) { - dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n", - ret); - return ret; - } + irq_gpio = devm_gpiod_get_optional(ci->dev, "irq", GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(irq_gpio); + if (ret) { + dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n", ret); + return ret; + } - stmpe->irq = gpio_to_irq(pdata->irq_gpio); + if (irq_gpio) { + stmpe->irq = gpiod_to_irq(irq_gpio); + pdata->irq_trigger = gpiod_is_active_low(irq_gpio) ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; } else { stmpe->irq = ci->irq; + pdata->irq_trigger = IRQF_TRIGGER_NONE; } if (stmpe->irq < 0) { diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 191fdb87c424..bdb2ce7ff03b 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -101,8 +101,7 @@ static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) } } - syscon_config.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", np, - (u64)res.start); + syscon_config.name = kasprintf(GFP_KERNEL, "%pOFn@%pa", np, &res.start); 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; diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 5369c67e3280..663ffd4b8570 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -397,11 +397,8 @@ err_noirq: static int t7l66xb_remove(struct platform_device *dev) { - struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - int ret; - ret = pdata->disable(dev); clk_disable_unprepare(t7l66xb->clk48m); clk_put(t7l66xb->clk48m); clk_disable_unprepare(t7l66xb->clk32k); @@ -412,8 +409,7 @@ static int t7l66xb_remove(struct platform_device *dev) mfd_remove_devices(&dev->dev); kfree(t7l66xb); - return ret; - + return 0; } static struct platform_driver t7l66xb_platform_driver = { diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 13583cdb93b6..d5d0ec117acb 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -429,13 +429,11 @@ static int tc3589x_probe(struct i2c_client *i2c, return 0; } -static int tc3589x_remove(struct i2c_client *client) +static void tc3589x_remove(struct i2c_client *client) { struct tc3589x *tc3589x = i2c_get_clientdata(client); mfd_remove_devices(tc3589x->dev); - - return 0; } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 3d5b14c60e20..aa903a31dd43 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -22,6 +22,8 @@ #include <linux/mfd/tmio.h> #include <linux/mfd/tc6393xb.h> #include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #define SCR_REVID 0x08 /* b Revision ID */ @@ -87,8 +89,10 @@ struct tc6393xb { void __iomem *scr; + struct device *dev; struct gpio_chip gpio; + struct gpio_desc *vcc_on; struct clk *clk; /* 3,6 Mhz */ @@ -497,17 +501,93 @@ static int tc6393xb_gpio_direction_output(struct gpio_chip *chip, return 0; } -static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) +/* + * TC6393XB GPIOs as used on TOSA, are the only user of this chip. + * GPIOs 2, 5, 8 and 13 are not connected. + */ +#define TOSA_GPIO_TG_ON 0 +#define TOSA_GPIO_L_MUTE 1 +#define TOSA_GPIO_BL_C20MA 3 +#define TOSA_GPIO_CARD_VCC_ON 4 +#define TOSA_GPIO_CHARGE_OFF 6 +#define TOSA_GPIO_CHARGE_OFF_JC 7 +#define TOSA_GPIO_BAT0_V_ON 9 +#define TOSA_GPIO_BAT1_V_ON 10 +#define TOSA_GPIO_BU_CHRG_ON 11 +#define TOSA_GPIO_BAT_SW_ON 12 +#define TOSA_GPIO_BAT0_TH_ON 14 +#define TOSA_GPIO_BAT1_TH_ON 15 + + +GPIO_LOOKUP_SINGLE(tosa_lcd_gpio_lookup, "spi2.0", "tc6393xb", + TOSA_GPIO_TG_ON, "tg #pwr", GPIO_ACTIVE_HIGH); + +GPIO_LOOKUP_SINGLE(tosa_lcd_bl_gpio_lookup, "i2c-tos-bl", "tc6393xb", + TOSA_GPIO_BL_C20MA, "backlight", GPIO_ACTIVE_HIGH); + +GPIO_LOOKUP_SINGLE(tosa_audio_gpio_lookup, "tosa-audio", "tc6393xb", + TOSA_GPIO_L_MUTE, NULL, GPIO_ACTIVE_HIGH); + +static struct gpiod_lookup_table tosa_battery_gpio_lookup = { + .dev_id = "wm97xx-battery", + .table = { + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF, + "main charge off", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_CHARGE_OFF_JC, + "jacket charge off", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_V_ON, + "main battery", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_V_ON, + "jacket battery", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BU_CHRG_ON, + "backup battery", GPIO_ACTIVE_HIGH), + /* BAT1 and BAT0 thermistors appear to be swapped */ + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT1_TH_ON, + "main battery temp", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT0_TH_ON, + "jacket battery temp", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("tc6393xb", TOSA_GPIO_BAT_SW_ON, + "battery switch", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table *tc6393xb_gpio_lookups[] = { + &tosa_lcd_gpio_lookup, + &tosa_lcd_bl_gpio_lookup, + &tosa_audio_gpio_lookup, + &tosa_battery_gpio_lookup, +}; + +static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb) { - tc6393xb->gpio.label = "tc6393xb"; - tc6393xb->gpio.base = gpio_base; - tc6393xb->gpio.ngpio = 16; - tc6393xb->gpio.set = tc6393xb_gpio_set; - tc6393xb->gpio.get = tc6393xb_gpio_get; - tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input; - tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output; - - return gpiochip_add_data(&tc6393xb->gpio, tc6393xb); + struct gpio_chip *gc = &tc6393xb->gpio; + struct device *dev = tc6393xb->dev; + int ret; + + gc->label = "tc6393xb"; + gc->base = -1; /* Dynamic allocation */ + gc->ngpio = 16; + gc->set = tc6393xb_gpio_set; + gc->get = tc6393xb_gpio_get; + gc->direction_input = tc6393xb_gpio_direction_input; + gc->direction_output = tc6393xb_gpio_direction_output; + + ret = devm_gpiochip_add_data(dev, gc, tc6393xb); + if (ret) + return dev_err_probe(dev, ret, "failed to add GPIO chip\n"); + + /* Register descriptor look-ups for consumers */ + gpiod_add_lookup_tables(tc6393xb_gpio_lookups, ARRAY_SIZE(tc6393xb_gpio_lookups)); + + /* Request some of our own GPIOs */ + tc6393xb->vcc_on = gpiochip_request_own_desc(gc, TOSA_GPIO_CARD_VCC_ON, "VCC ON", + GPIO_ACTIVE_HIGH, GPIOD_OUT_HIGH); + if (IS_ERR(tc6393xb->vcc_on)) + return dev_err_probe(dev, PTR_ERR(tc6393xb->vcc_on), + "failed to request VCC ON GPIO\n"); + + return 0; } /*--------------------------------------------------------------------------*/ @@ -617,6 +697,7 @@ static int tc6393xb_probe(struct platform_device *dev) ret = -ENOMEM; goto err_kzalloc; } + tc6393xb->dev = &dev->dev; raw_spin_lock_init(&tc6393xb->lock); @@ -676,22 +757,12 @@ static int tc6393xb_probe(struct platform_device *dev) tmio_ioread8(tc6393xb->scr + SCR_REVID), (unsigned long) iomem->start, tc6393xb->irq); - tc6393xb->gpio.base = -1; - - if (tcpd->gpio_base >= 0) { - ret = tc6393xb_register_gpio(tc6393xb, tcpd->gpio_base); - if (ret) - goto err_gpio_add; - } + ret = tc6393xb_register_gpio(tc6393xb); + if (ret) + goto err_gpio_add; tc6393xb_attach_irq(dev); - if (tcpd->setup) { - ret = tcpd->setup(dev); - if (ret) - goto err_setup; - } - tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data; tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size = sizeof(*tcpd->nand_data); @@ -705,15 +776,8 @@ static int tc6393xb_probe(struct platform_device *dev) if (!ret) return 0; - if (tcpd->teardown) - tcpd->teardown(dev); - -err_setup: tc6393xb_detach_irq(dev); - err_gpio_add: - if (tc6393xb->gpio.base != -1) - gpiochip_remove(&tc6393xb->gpio); tcpd->disable(dev); err_enable: clk_disable_unprepare(tc6393xb->clk); @@ -734,26 +798,19 @@ static int tc6393xb_remove(struct platform_device *dev) { struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); - int ret; mfd_remove_devices(&dev->dev); - if (tcpd->teardown) - tcpd->teardown(dev); - tc6393xb_detach_irq(dev); - if (tc6393xb->gpio.base != -1) - gpiochip_remove(&tc6393xb->gpio); - - ret = tcpd->disable(dev); + tcpd->disable(dev); clk_disable_unprepare(tc6393xb->clk); iounmap(tc6393xb->scr); release_resource(&tc6393xb->rscr); clk_put(tc6393xb->clk); kfree(tc6393xb); - return ret; + return 0; } #ifdef CONFIG_PM diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index c906324d293e..b360568ea675 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -179,7 +179,7 @@ static int tps6105x_probe(struct i2c_client *client, return ret; } -static int tps6105x_remove(struct i2c_client *client) +static void tps6105x_remove(struct i2c_client *client) { struct tps6105x *tps6105x = i2c_get_clientdata(client); @@ -189,8 +189,6 @@ static int tps6105x_remove(struct i2c_client *client) regmap_update_bits(tps6105x->regmap, TPS6105X_REG_0, TPS6105X_REG0_MODE_MASK, TPS6105X_MODE_SHUTDOWN << TPS6105X_REG0_MODE_SHIFT); - - return 0; } static const struct i2c_device_id tps6105x_id[] = { diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 7e7dbee58ca9..c2afa2e69f42 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -501,7 +501,7 @@ static int tps65010_gpio_get(struct gpio_chip *chip, unsigned offset) static struct tps65010 *the_tps; -static int tps65010_remove(struct i2c_client *client) +static void tps65010_remove(struct i2c_client *client) { struct tps65010 *tps = i2c_get_clientdata(client); struct tps65010_board *board = dev_get_platdata(&client->dev); @@ -517,7 +517,6 @@ static int tps65010_remove(struct i2c_client *client) cancel_delayed_work_sync(&tps->work); debugfs_remove(tps->file); the_tps = NULL; - return 0; } static int tps65010_probe(struct i2c_client *client, diff --git a/drivers/mfd/tps65086.c b/drivers/mfd/tps65086.c index 3bd5728844a0..81a7360a87bb 100644 --- a/drivers/mfd/tps65086.c +++ b/drivers/mfd/tps65086.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis <afd@ti.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65912 driver */ @@ -119,14 +111,12 @@ static int tps65086_probe(struct i2c_client *client, return ret; } -static int tps65086_remove(struct i2c_client *client) +static void tps65086_remove(struct i2c_client *client) { struct tps65086 *tps = i2c_get_clientdata(client); if (tps->irq > 0) regmap_del_irq_chip(tps->irq, tps->irq_data); - - return 0; } static const struct i2c_device_id tps65086_id_table[] = { diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 8027b0a9e14f..eebd60601b01 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * tps65217.c * * TPS65217 chip family multi-function driver * * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/device.h> @@ -382,7 +374,7 @@ static int tps65217_probe(struct i2c_client *client) return 0; } -static int tps65217_remove(struct i2c_client *client) +static void tps65217_remove(struct i2c_client *client) { struct tps65217 *tps = i2c_get_clientdata(client); unsigned int virq; @@ -396,8 +388,6 @@ static int tps65217_remove(struct i2c_client *client) irq_domain_remove(tps->irq_domain); tps->irq_domain = NULL; - - return 0; } static const struct i2c_device_id tps65217_id_table[] = { diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 167e9fc308ef..49bb8fd168f8 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Driver for TPS65218 Integrated power management chipsets * * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. */ #include <linux/kernel.h> diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index c9303d3d6602..fb340da64bbc 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -579,7 +579,7 @@ err_mfd_add: return ret; } -static int tps6586x_i2c_remove(struct i2c_client *client) +static void tps6586x_i2c_remove(struct i2c_client *client) { struct tps6586x *tps6586x = i2c_get_clientdata(client); @@ -587,7 +587,6 @@ static int tps6586x_i2c_remove(struct i2c_client *client) mfd_remove_devices(tps6586x->dev); if (client->irq) free_irq(client->irq, tps6586x); - return 0; } static int __maybe_unused tps6586x_i2c_suspend(struct device *dev) diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 6e105cca27d4..67e2707af4bc 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -436,15 +436,6 @@ static void tps65910_power_off(void) tps65910 = dev_get_drvdata(&tps65910_i2c_client->dev); - /* - * The PWR_OFF bit needs to be set separately, before transitioning - * to the OFF state. It enables the "sequential" power-off mode on - * TPS65911, it's a NO-OP on TPS65910. - */ - if (regmap_set_bits(tps65910->regmap, TPS65910_DEVCTRL, - DEVCTRL_PWR_OFF_MASK) < 0) - return; - regmap_update_bits(tps65910->regmap, TPS65910_DEVCTRL, DEVCTRL_DEV_OFF_MASK | DEVCTRL_DEV_ON_MASK, DEVCTRL_DEV_OFF_MASK); @@ -504,6 +495,19 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_sleepinit(tps65910, pmic_plat_data); if (pmic_plat_data->pm_off && !pm_power_off) { + /* + * The PWR_OFF bit needs to be set separately, before + * transitioning to the OFF state. It enables the "sequential" + * power-off mode on TPS65911, it's a NO-OP on TPS65910. + */ + ret = regmap_set_bits(tps65910->regmap, TPS65910_DEVCTRL, + DEVCTRL_PWR_OFF_MASK); + if (ret) { + dev_err(&i2c->dev, "failed to set power-off mode: %d\n", + ret); + return ret; + } + tps65910_i2c_client = i2c; pm_power_off = tps65910_power_off; } diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index c282a05e7146..7d994b8a5965 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Core functions for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis <afd@ti.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera <magi@slimlogic.co.uk> */ diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index 06eb2784d322..7e2b19efe867 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * I2C access driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis <afd@ti.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera <magi@slimlogic.co.uk> */ @@ -51,13 +43,11 @@ static int tps65912_i2c_probe(struct i2c_client *client, return tps65912_device_init(tps); } -static int tps65912_i2c_remove(struct i2c_client *client) +static void tps65912_i2c_remove(struct i2c_client *client) { struct tps65912 *tps = i2c_get_clientdata(client); tps65912_device_exit(tps); - - return 0; } static const struct i2c_device_id tps65912_i2c_id_table[] = { diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index d701926aa46e..9e976f9c6bbe 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -1,18 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * SPI access driver for TI TPS65912x PMICs * * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/ * Andrew F. Davis <afd@ti.com> * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether expressed or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License version 2 for more details. - * * Based on the TPS65218 driver and the previous TPS65912 driver by * Margarita Olaya Cabrera <magi@slimlogic.co.uk> */ @@ -50,13 +42,11 @@ static int tps65912_spi_probe(struct spi_device *spi) return tps65912_device_init(tps); } -static int tps65912_spi_remove(struct spi_device *spi) +static void tps65912_spi_remove(struct spi_device *spi) { struct tps65912 *tps = spi_get_drvdata(spi); tps65912_device_exit(tps); - - return 0; } static const struct spi_device_id tps65912_spi_id_table[] = { diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 289b556dede2..f6b4b9d94bbd 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -656,309 +656,6 @@ static inline struct device *add_child(unsigned mod_no, const char *name, can_wakeup, irq0, irq1); } -static struct device * -add_regulator_linked(int num, struct regulator_init_data *pdata, - struct regulator_consumer_supply *consumers, - unsigned num_consumers, unsigned long features) -{ - struct twl_regulator_driver_data drv_data; - - /* regulator framework demands init_data ... */ - if (!pdata) - return NULL; - - if (consumers) { - pdata->consumer_supplies = consumers; - pdata->num_consumer_supplies = num_consumers; - } - - if (pdata->driver_data) { - /* If we have existing drv_data, just add the flags */ - struct twl_regulator_driver_data *tmp; - tmp = pdata->driver_data; - tmp->features |= features; - } else { - /* add new driver data struct, used only during init */ - drv_data.features = features; - drv_data.set_voltage = NULL; - drv_data.get_voltage = NULL; - drv_data.data = NULL; - pdata->driver_data = &drv_data; - } - - /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ - return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num, - pdata, sizeof(*pdata), false, 0, 0); -} - -static struct device * -add_regulator(int num, struct regulator_init_data *pdata, - unsigned long features) -{ - return add_regulator_linked(num, pdata, NULL, 0, features); -} - -/* - * NOTE: We know the first 8 IRQs after pdata->base_irq are - * for the PIH, and the next are for the PWR_INT SIH, since - * that's how twl_init_irq() sets things up. - */ - -static int -add_children(struct twl4030_platform_data *pdata, unsigned irq_base, - unsigned long features) -{ - struct device *child; - - if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) { - child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio", - pdata->gpio, sizeof(*pdata->gpio), - false, irq_base + GPIO_INTR_OFFSET, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) { - child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad", - pdata->keypad, sizeof(*pdata->keypad), - true, irq_base + KEYPAD_INTR_OFFSET, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc && - twl_class_is_4030()) { - child = add_child(TWL4030_MODULE_MADC, "twl4030_madc", - pdata->madc, sizeof(*pdata->madc), - true, irq_base + MADC_INTR_OFFSET, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) { - /* - * REVISIT platform_data here currently might expose the - * "msecure" line ... but for now we just expect board - * setup to tell the chip "it's always ok to SET_TIME". - * Eventually, Linux might become more aware of such - * HW security concerns, and "least privilege". - */ - child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0, - true, irq_base + RTC_INTR_OFFSET, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_PWM_TWL)) { - child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0, - false, 0, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_PWM_TWL_LED)) { - child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0, - false, 0, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && - twl_class_is_4030()) { - - static struct regulator_consumer_supply usb1v5 = { - .supply = "usb1v5", - }; - static struct regulator_consumer_supply usb1v8 = { - .supply = "usb1v8", - }; - static struct regulator_consumer_supply usb3v1 = { - .supply = "usb3v1", - }; - - /* First add the regulators so that they can be used by transceiver */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { - /* this is a template that gets copied */ - struct regulator_init_data usb_fixed = { - .constraints.valid_modes_mask = - REGULATOR_MODE_NORMAL - | REGULATOR_MODE_STANDBY, - .constraints.valid_ops_mask = - REGULATOR_CHANGE_MODE - | REGULATOR_CHANGE_STATUS, - }; - - child = add_regulator_linked(TWL4030_REG_VUSB1V5, - &usb_fixed, &usb1v5, 1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator_linked(TWL4030_REG_VUSB1V8, - &usb_fixed, &usb1v8, 1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator_linked(TWL4030_REG_VUSB3V1, - &usb_fixed, &usb3v1, 1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - } - - child = add_child(TWL_MODULE_USB, "twl4030_usb", - pdata->usb, sizeof(*pdata->usb), true, - /* irq0 = USB_PRES, irq1 = USB */ - irq_base + USB_PRES_INTR_OFFSET, - irq_base + USB_INTR_OFFSET); - - if (IS_ERR(child)) - return PTR_ERR(child); - - /* we need to connect regulators to this transceiver */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { - usb1v5.dev_name = dev_name(child); - usb1v8.dev_name = dev_name(child); - usb3v1.dev_name = dev_name(child); - } - } - - if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { - child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL, - 0, false, 0, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { - child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton", - NULL, 0, true, irq_base + 8 + 0, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && - twl_class_is_4030()) { - child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio", - pdata->audio, sizeof(*pdata->audio), - false, 0, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - /* twl4030 regulators */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) { - child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VIO, pdata->vio, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VDAC, pdata->vdac, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator((features & TWL4030_VAUX2) - ? TWL4030_REG_VAUX2_4030 - : TWL4030_REG_VAUX2, - pdata->vaux2, features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - /* maybe add LDOs that are omitted on cost-reduced parts */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET) - && twl_class_is_4030()) { - child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VSIM, pdata->vsim, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && - !(features & (TPS_SUBSET | TWL5031))) { - child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci", - pdata->bci, sizeof(*pdata->bci), false, - /* irq0 = CHG_PRES, irq1 = BCI */ - irq_base + BCI_PRES_INTR_OFFSET, - irq_base + BCI_INTR_OFFSET); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) { - child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power", - pdata->power, sizeof(*pdata->power), false, - 0, 0); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - return 0; -} - /*----------------------------------------------------------------------*/ /* @@ -987,8 +684,7 @@ static inline int unprotect_pm_master(void) return e; } -static void clocks_init(struct device *dev, - struct twl4030_clock_init_data *clock) +static void clocks_init(struct device *dev) { int e = 0; struct clk *osc; @@ -1018,8 +714,6 @@ static void clocks_init(struct device *dev, } ctrl |= HIGH_PERF_SQ; - if (clock && clock->ck32k_lowpwr_enable) - ctrl |= CK32K_LOWPWR_EN; e |= unprotect_pm_master(); /* effect->MADC+USB ck en */ @@ -1033,18 +727,14 @@ static void clocks_init(struct device *dev, /*----------------------------------------------------------------------*/ -static int twl_remove(struct i2c_client *client) +static void twl_remove(struct i2c_client *client) { unsigned i, num_slaves; - int status; if (twl_class_is_4030()) - status = twl4030_exit_irq(); + twl4030_exit_irq(); else - status = twl6030_exit_irq(); - - if (status < 0) - return status; + twl6030_exit_irq(); num_slaves = twl_get_num_slaves(); for (i = 0; i < num_slaves; i++) { @@ -1055,7 +745,6 @@ static int twl_remove(struct i2c_client *client) twl->client = NULL; } twl_priv->ready = false; - return 0; } static struct of_dev_auxdata twl_auxdata_lookup[] = { @@ -1067,7 +756,6 @@ static struct of_dev_auxdata twl_auxdata_lookup[] = { static int twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *node = client->dev.of_node; struct platform_device *pdev; const struct regmap_config *twl_regmap_config; @@ -1075,7 +763,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) int status; unsigned i, num_slaves; - if (!node && !pdata) { + if (!node) { dev_err(&client->dev, "no platform data\n"); return -EINVAL; } @@ -1165,7 +853,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) twl_priv->ready = true; /* setup clock framework */ - clocks_init(&client->dev, pdata ? pdata->clock : NULL); + clocks_init(&client->dev); /* read TWL IDCODE Register */ if (twl_class_is_4030()) { @@ -1194,7 +882,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0. * * Also, always enable SmartReflex bit as that's needed for omaps to - * to do anything over I2C4 for voltage scaling even if SmartReflex + * do anything over I2C4 for voltage scaling even if SmartReflex * is disabled. Without the SmartReflex bit omap sys_clkreq idle * signal will never trigger for retention idle. */ @@ -1213,14 +901,8 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) TWL4030_DCDC_GLOBAL_CFG); } - if (node) { - if (pdata) - twl_auxdata_lookup[0].platform_data = pdata->gpio; - status = of_platform_populate(node, NULL, twl_auxdata_lookup, - &client->dev); - } else { - status = add_children(pdata, irq_base, id->driver_data); - } + status = of_platform_populate(node, NULL, twl_auxdata_lookup, + &client->dev); fail: if (status < 0) diff --git a/drivers/mfd/twl-core.h b/drivers/mfd/twl-core.h index 6f96c2009a9f..b4bf6a233bd0 100644 --- a/drivers/mfd/twl-core.h +++ b/drivers/mfd/twl-core.h @@ -3,9 +3,9 @@ #define __TWL_CORE_H__ extern int twl6030_init_irq(struct device *dev, int irq_num); -extern int twl6030_exit_irq(void); +extern void twl6030_exit_irq(void); extern int twl4030_init_irq(struct device *dev, int irq_num); -extern int twl4030_exit_irq(void); +extern void twl4030_exit_irq(void); extern int twl4030_init_chip_irq(const char *chip); #endif /* __TWL_CORE_H__ */ diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index ab417438d1fa..87496c1cb8bc 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -14,6 +14,7 @@ * by syed khasim <x0khasim@ti.com> */ +#include <linux/device.h> #include <linux/export.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -753,14 +754,11 @@ fail: return status; } -int twl4030_exit_irq(void) +void twl4030_exit_irq(void) { /* FIXME undo twl_init_irq() */ - if (twl4030_irq_base) { + if (twl4030_irq_base) pr_err("twl4030: can't yet clean up IRQs?\n"); - return -ENOSYS; - } - return 0; } int twl4030_init_chip_irq(const char *chip) diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 97af6c2a6007..3c03681c124c 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -438,7 +438,7 @@ fail_irq: return status; } -int twl6030_exit_irq(void) +void twl6030_exit_irq(void) { if (twl6030_irq && twl6030_irq->twl_irq) { unregister_pm_notifier(&twl6030_irq->pm_nb); @@ -453,6 +453,5 @@ int twl6030_exit_irq(void) * in this module. */ } - return 0; } diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index b9c6d94b4002..f429b8f00db6 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -808,7 +808,7 @@ gpio_err: return ret; } -static int twl6040_remove(struct i2c_client *client) +static void twl6040_remove(struct i2c_client *client) { struct twl6040 *twl6040 = i2c_get_clientdata(client); @@ -820,8 +820,6 @@ static int twl6040_remove(struct i2c_client *client) mfd_remove_devices(&client->dev); regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); - - return 0; } static const struct i2c_device_id twl6040_i2c_id[] = { diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index 8c3832a58ef6..ac1d18039568 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -72,11 +72,9 @@ static int ucb1400_core_probe(struct device *dev) /* GPIO */ ucb_gpio.ac97 = ac97; - if (pdata) { - ucb_gpio.gpio_setup = pdata->gpio_setup; - ucb_gpio.gpio_teardown = pdata->gpio_teardown; + if (pdata) ucb_gpio.gpio_offset = pdata->gpio_offset; - } + ucb->ucb1400_gpio = platform_device_alloc("ucb1400_gpio", -1); if (!ucb->ucb1400_gpio) { err = -ENOMEM; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 7b1d270722ba..7e88f5b0abe6 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -657,13 +657,11 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, return wm8994_device_init(wm8994, i2c->irq); } -static int wm8994_i2c_remove(struct i2c_client *i2c) +static void wm8994_i2c_remove(struct i2c_client *i2c) { struct wm8994 *wm8994 = i2c_get_clientdata(i2c); wm8994_device_exit(wm8994); - - return 0; } static const struct i2c_device_id wm8994_i2c_id[] = { |