aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/88pm800.c4
-rw-r--r--drivers/mfd/88pm805.c4
-rw-r--r--drivers/mfd/88pm860x-core.c3
-rw-r--r--drivers/mfd/Kconfig124
-rw-r--r--drivers/mfd/Makefile19
-rw-r--r--drivers/mfd/ab8500-core.c32
-rw-r--r--drivers/mfd/ab8500-debugfs.c2096
-rw-r--r--drivers/mfd/acer-ec-a500.c4
-rw-r--r--drivers/mfd/arizona-i2c.c6
-rw-r--r--drivers/mfd/arizona-spi.c91
-rw-r--r--drivers/mfd/asic3.c19
-rw-r--r--drivers/mfd/atmel-flexcom.c11
-rw-r--r--drivers/mfd/atmel-smc.c4
-rw-r--r--drivers/mfd/axp20x-i2c.c4
-rw-r--r--drivers/mfd/axp20x.c9
-rw-r--r--drivers/mfd/bcm2835-pm.c74
-rw-r--r--drivers/mfd/cros_ec_dev.c24
-rw-r--r--drivers/mfd/da903x.c3
-rw-r--r--drivers/mfd/da9052-i2c.c3
-rw-r--r--drivers/mfd/da9052-spi.c3
-rw-r--r--drivers/mfd/da9055-i2c.c4
-rw-r--r--drivers/mfd/da9062-core.c17
-rw-r--r--drivers/mfd/da9150-core.c4
-rw-r--r--drivers/mfd/davinci_voicecodec.c6
-rw-r--r--drivers/mfd/db8500-prcmu.c2
-rw-r--r--drivers/mfd/dln2.c17
-rw-r--r--drivers/mfd/dm355evm_msp.c3
-rw-r--r--drivers/mfd/ene-kb3930.c4
-rw-r--r--drivers/mfd/exynos-lpass.c1
-rw-r--r--drivers/mfd/ezx-pcap.c8
-rw-r--r--drivers/mfd/fsl-imx25-tsadc.c34
-rw-r--r--drivers/mfd/gateworks-gsc.c4
-rw-r--r--drivers/mfd/hi655x-pmic.c27
-rw-r--r--drivers/mfd/htc-i2cpld.c60
-rw-r--r--drivers/mfd/intel-lpss-acpi.c48
-rw-r--r--drivers/mfd/intel-lpss-pci.c178
-rw-r--r--drivers/mfd/intel-lpss.c1
-rw-r--r--drivers/mfd/intel-lpss.h1
-rw-r--r--drivers/mfd/intel-m10-bmc.c3
-rw-r--r--drivers/mfd/intel_pmt.c261
-rw-r--r--drivers/mfd/intel_soc_pmic_bxtwc.c194
-rw-r--r--drivers/mfd/intel_soc_pmic_chtdc_ti.c8
-rw-r--r--drivers/mfd/intel_soc_pmic_chtwc.c67
-rw-r--r--drivers/mfd/intel_soc_pmic_core.c178
-rw-r--r--drivers/mfd/intel_soc_pmic_core.h25
-rw-r--r--drivers/mfd/intel_soc_pmic_crc.c174
-rw-r--r--drivers/mfd/ipaq-micro.c2
-rw-r--r--drivers/mfd/iqs62x.c10
-rw-r--r--drivers/mfd/lm3533-core.c4
-rw-r--r--drivers/mfd/lp873x.c10
-rw-r--r--drivers/mfd/lp8788-irq.c3
-rw-r--r--drivers/mfd/lp8788.c15
-rw-r--r--drivers/mfd/lpc_ich.c186
-rw-r--r--drivers/mfd/madera-i2c.c4
-rw-r--r--drivers/mfd/madera-spi.c4
-rw-r--r--drivers/mfd/max14577.c4
-rw-r--r--drivers/mfd/max77620.c2
-rw-r--r--drivers/mfd/max77686.c2
-rw-r--r--drivers/mfd/max77693.c4
-rw-r--r--drivers/mfd/max77714.c152
-rw-r--r--drivers/mfd/max8907.c4
-rw-r--r--drivers/mfd/max8925-i2c.c3
-rw-r--r--drivers/mfd/mc13xxx-core.c4
-rw-r--r--drivers/mfd/mc13xxx-i2c.c3
-rw-r--r--drivers/mfd/mc13xxx-spi.c3
-rw-r--r--drivers/mfd/menelaus.c3
-rw-r--r--drivers/mfd/mfd-core.c42
-rw-r--r--drivers/mfd/mt6358-irq.c25
-rw-r--r--drivers/mfd/mt6370.c312
-rw-r--r--drivers/mfd/mt6370.h99
-rw-r--r--drivers/mfd/mt6397-core.c104
-rw-r--r--drivers/mfd/mt6397-irq.c9
-rw-r--r--drivers/mfd/ntxec.c4
-rw-r--r--drivers/mfd/ocelot-core.c161
-rw-r--r--drivers/mfd/ocelot-spi.c300
-rw-r--r--drivers/mfd/ocelot.h49
-rw-r--r--drivers/mfd/palmas.c4
-rw-r--r--drivers/mfd/pcf50633-core.c4
-rw-r--r--drivers/mfd/qcom-pm8008.c53
-rw-r--r--drivers/mfd/qcom-spmi-pmic.c273
-rw-r--r--drivers/mfd/retu-mfd.c4
-rw-r--r--drivers/mfd/rk808.c62
-rw-r--r--drivers/mfd/rn5t618.c4
-rw-r--r--drivers/mfd/rohm-bd70528.c314
-rw-r--r--drivers/mfd/rohm-bd9576.c2
-rw-r--r--drivers/mfd/rsmu_i2c.c4
-rw-r--r--drivers/mfd/rsmu_spi.c4
-rw-r--r--drivers/mfd/rt4831.c7
-rw-r--r--drivers/mfd/rt5120.c124
-rw-r--r--drivers/mfd/si476x-i2c.c4
-rw-r--r--drivers/mfd/simple-mfd-i2c.c11
-rw-r--r--drivers/mfd/sm501.c7
-rw-r--r--drivers/mfd/sprd-sc27xx-spi.c3
-rw-r--r--drivers/mfd/sta2x11-mfd.c2
-rw-r--r--drivers/mfd/stmfx.c17
-rw-r--r--drivers/mfd/stmpe-i2c.c4
-rw-r--r--drivers/mfd/stmpe-spi.c4
-rw-r--r--drivers/mfd/stmpe.c51
-rw-r--r--drivers/mfd/syscon.c3
-rw-r--r--drivers/mfd/t7l66xb.c6
-rw-r--r--drivers/mfd/tc3589x.c4
-rw-r--r--drivers/mfd/tc6393xb.c135
-rw-r--r--drivers/mfd/tps6105x.c4
-rw-r--r--drivers/mfd/tps65010.c3
-rw-r--r--drivers/mfd/tps65086.c14
-rw-r--r--drivers/mfd/tps65217.c14
-rw-r--r--drivers/mfd/tps65218.c10
-rw-r--r--drivers/mfd/tps6586x.c3
-rw-r--r--drivers/mfd/tps65910.c22
-rw-r--r--drivers/mfd/tps65912-core.c10
-rw-r--r--drivers/mfd/tps65912-i2c.c14
-rw-r--r--drivers/mfd/tps65912-spi.c14
-rw-r--r--drivers/mfd/twl-core.c336
-rw-r--r--drivers/mfd/twl-core.h4
-rw-r--r--drivers/mfd/twl4030-irq.c8
-rw-r--r--drivers/mfd/twl6030-irq.c3
-rw-r--r--drivers/mfd/twl6040.c4
-rw-r--r--drivers/mfd/ucb1400_core.c6
-rw-r--r--drivers/mfd/wm8994-core.c4
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, &regvalue);
- 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, &regvalue);
- 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, &regvalue);
- 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(&regmap_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, &regmap_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[] = {