diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-14 13:39:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-14 13:39:08 -0400 |
commit | ebcf5bb28241fe3ddc9e786e3816848a10f688b8 (patch) | |
tree | 28c8ce0f20c690b0ac2492e034fab34ad89aa9d1 /drivers/mfd | |
parent | 414147d99b928c574ed76e9374a5d2cb77866a29 (diff) | |
parent | ed835136ee679dc528333c454ca4d1543c5aab76 (diff) |
Merge tag 'mfd-next-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Core Framework:
- Document (kerneldoc) core mfd_add_devices() API
New Drivers:
- Altera SOCFPGA System Manager
- Maxim MAX77650/77651 PMIC
- Maxim MAX77663 PMIC
- ST Multi-Function eXpander (STMFX)
New Device Support:
- LEDs support in Intel Cherry Trail Whiskey Cove PMIC
- RTC support in SAMSUNG Electronics S2MPA01 PMIC
- SAM9X60 support in Atmel HLCDC (High-end LCD Controller)
- USB X-Powers AXP 8xx PMICs
- Integrated Sensor Hub (ISH) in ChromeOS EC
- USB PD Logger in ChromeOS EC
- AXP223 in X-Powers AXP series PMICs
- Power Supply in X-Powers AXP 803 PMICs
- Comet Lake in Intel Low Power Subsystem
- Fingerprint MCU in ChromeOS EC
- Touchpad MCU in ChromeOS EC
- Move TI LM3532 support to LED
New Functionality:
- max77650, max77620: Add/extend DT support
- max77620 power-off
- syscon clocking
- croc_ec host sleep event
Fix-ups:
- Trivial; Formatting, spelling, etc; Kconfig, sec-core, ab8500-debugfs
- Remove unused functionality; rk808, da9063-*
- SPDX conversion; da9063-*, atmel-*,
- Adapt/add new register definitions; cs47l35-tables, cs47l90-tables, imx6q-iomuxc-gpr
- Fix-up DT bindings; ti-lmu, cirrus,lochnagar
- Simply obtaining driver data; ssbi, t7l66xb, tc6387xb, tc6393xb
Bug Fixes:
- Fix incorrect defined values; max77620, da9063
- Fix device initialisation; twl6040
- Reset device on init; intel-lpss
- Fix build warnings when !OF; sun6i-prcm
- Register OF match tables; tps65912-spi
- Fix DMI matching; intel_quark_i2c_gpio"
* tag 'mfd-next-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (65 commits)
mfd: Use dev_get_drvdata() directly
mfd: cros_ec: Instantiate properly CrOS Touchpad MCU device
mfd: cros_ec: Instantiate properly CrOS FP MCU device
mfd: cros_ec: Update the EC feature codes
mfd: intel-lpss: Add Intel Comet Lake PCI IDs
mfd: lochnagar: Add links to binding docs for sound and hwmon
mfd: ab8500-debugfs: Fix a typo ("deubgfs")
mfd: imx6sx: Add MQS register definition for iomuxc gpr
dt-bindings: mfd: LMU: Fix lm3632 dt binding example
mfd: intel_quark_i2c_gpio: Adjust IOT2000 matching
mfd: da9063: Fix OTP control register names to match datasheets for DA9063/63L
mfd: tps65912-spi: Add missing of table registration
mfd: axp20x: Add USB power supply mfd cell to AXP803
mfd: sun6i-prcm: Fix build warning for non-OF configurations
mfd: intel-lpss: Set the device in reset state when init
platform/chrome: Add support for v1 of host sleep event
mfd: cros_ec: Add host_sleep_event_v1 command
mfd: cros_ec: Instantiate the CrOS USB PD logger driver
mfd: cs47l90: Make DAC_AEC_CONTROL_2 readable
mfd: cs47l35: Make DAC_AEC_CONTROL_2 readable
...
Diffstat (limited to 'drivers/mfd')
33 files changed, 1350 insertions, 176 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 26ad6468d13a..294d9567cc71 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -16,7 +16,7 @@ config MFD_CS5535 | |||
16 | depends on PCI && (X86_32 || (X86 && COMPILE_TEST)) | 16 | depends on PCI && (X86_32 || (X86 && COMPILE_TEST)) |
17 | ---help--- | 17 | ---help--- |
18 | This is the core driver for CS5535/CS5536 MFD functions. This is | 18 | This is the core driver for CS5535/CS5536 MFD functions. This is |
19 | necessary for using the board's GPIO and MFGPT functionality. | 19 | necessary for using the board's GPIO and MFGPT functionality. |
20 | 20 | ||
21 | config MFD_ALTERA_A10SR | 21 | config MFD_ALTERA_A10SR |
22 | bool "Altera Arria10 DevKit System Resource chip" | 22 | bool "Altera Arria10 DevKit System Resource chip" |
@@ -29,6 +29,16 @@ config MFD_ALTERA_A10SR | |||
29 | accessing the external gpio extender (LEDs & buttons) and | 29 | accessing the external gpio extender (LEDs & buttons) and |
30 | power supply alarms (hwmon). | 30 | power supply alarms (hwmon). |
31 | 31 | ||
32 | config MFD_ALTERA_SYSMGR | ||
33 | bool "Altera SOCFPGA System Manager" | ||
34 | depends on (ARCH_SOCFPGA || ARCH_STRATIX10) && OF | ||
35 | select MFD_SYSCON | ||
36 | help | ||
37 | Select this to get System Manager support for all Altera branded | ||
38 | SOCFPGAs. The SOCFPGA System Manager handles all SOCFPGAs by | ||
39 | using regmap_mmio accesses for ARM32 parts and SMC calls to | ||
40 | EL3 for ARM64 parts. | ||
41 | |||
32 | config MFD_ACT8945A | 42 | config MFD_ACT8945A |
33 | tristate "Active-semi ACT8945A" | 43 | tristate "Active-semi ACT8945A" |
34 | select MFD_CORE | 44 | select MFD_CORE |
@@ -213,13 +223,13 @@ config MFD_CROS_EC | |||
213 | protocol for talking to the EC is defined by the bus driver. | 223 | protocol for talking to the EC is defined by the bus driver. |
214 | 224 | ||
215 | config MFD_CROS_EC_CHARDEV | 225 | config MFD_CROS_EC_CHARDEV |
216 | tristate "Chrome OS Embedded Controller userspace device interface" | 226 | tristate "Chrome OS Embedded Controller userspace device interface" |
217 | depends on MFD_CROS_EC | 227 | depends on MFD_CROS_EC |
218 | ---help--- | 228 | ---help--- |
219 | This driver adds support to talk with the ChromeOS EC from userspace. | 229 | This driver adds support to talk with the ChromeOS EC from userspace. |
220 | 230 | ||
221 | If you have a supported Chromebook, choose Y or M here. | 231 | If you have a supported Chromebook, choose Y or M here. |
222 | The module will be called cros_ec_dev. | 232 | The module will be called cros_ec_dev. |
223 | 233 | ||
224 | config MFD_MADERA | 234 | config MFD_MADERA |
225 | tristate "Cirrus Logic Madera codecs" | 235 | tristate "Cirrus Logic Madera codecs" |
@@ -733,6 +743,20 @@ config MFD_MAX77620 | |||
733 | provides common support for accessing the device; additional drivers | 743 | provides common support for accessing the device; additional drivers |
734 | must be enabled in order to use the functionality of the device. | 744 | must be enabled in order to use the functionality of the device. |
735 | 745 | ||
746 | config MFD_MAX77650 | ||
747 | tristate "Maxim MAX77650/77651 PMIC Support" | ||
748 | depends on I2C | ||
749 | depends on OF || COMPILE_TEST | ||
750 | select MFD_CORE | ||
751 | select REGMAP_I2C | ||
752 | help | ||
753 | Say Y here to add support for Maxim Semiconductor MAX77650 and | ||
754 | MAX77651 Power Management ICs. This is the core multifunction | ||
755 | driver for interacting with the device. The module name is | ||
756 | 'max77650'. Additional drivers can be enabled in order to use | ||
757 | the following functionalities of the device: GPIO, regulator, | ||
758 | charger, LED, onkey. | ||
759 | |||
736 | config MFD_MAX77686 | 760 | config MFD_MAX77686 |
737 | tristate "Maxim Semiconductor MAX77686/802 PMIC Support" | 761 | tristate "Maxim Semiconductor MAX77686/802 PMIC Support" |
738 | depends on I2C | 762 | depends on I2C |
@@ -867,7 +891,7 @@ config MFD_CPCAP | |||
867 | At least Motorola Droid 4 is known to use CPCAP. | 891 | At least Motorola Droid 4 is known to use CPCAP. |
868 | 892 | ||
869 | config MFD_VIPERBOARD | 893 | config MFD_VIPERBOARD |
870 | tristate "Nano River Technologies Viperboard" | 894 | tristate "Nano River Technologies Viperboard" |
871 | select MFD_CORE | 895 | select MFD_CORE |
872 | depends on USB | 896 | depends on USB |
873 | default n | 897 | default n |
@@ -903,15 +927,15 @@ config PCF50633_ADC | |||
903 | tristate "NXP PCF50633 ADC" | 927 | tristate "NXP PCF50633 ADC" |
904 | depends on MFD_PCF50633 | 928 | depends on MFD_PCF50633 |
905 | help | 929 | help |
906 | Say yes here if you want to include support for ADC in the | 930 | Say yes here if you want to include support for ADC in the |
907 | NXP PCF50633 chip. | 931 | NXP PCF50633 chip. |
908 | 932 | ||
909 | config PCF50633_GPIO | 933 | config PCF50633_GPIO |
910 | tristate "NXP PCF50633 GPIO" | 934 | tristate "NXP PCF50633 GPIO" |
911 | depends on MFD_PCF50633 | 935 | depends on MFD_PCF50633 |
912 | help | 936 | help |
913 | Say yes here if you want to include support GPIO for pins on | 937 | Say yes here if you want to include support GPIO for pins on |
914 | the PCF50633 chip. | 938 | the PCF50633 chip. |
915 | 939 | ||
916 | config UCB1400_CORE | 940 | config UCB1400_CORE |
917 | tristate "Philips UCB1400 Core driver" | 941 | tristate "Philips UCB1400 Core driver" |
@@ -1026,7 +1050,7 @@ config MFD_RN5T618 | |||
1026 | select REGMAP_I2C | 1050 | select REGMAP_I2C |
1027 | help | 1051 | help |
1028 | Say yes here to add support for the Ricoh RN5T567, | 1052 | Say yes here to add support for the Ricoh RN5T567, |
1029 | RN5T618, RC5T619 PMIC. | 1053 | RN5T618, RC5T619 PMIC. |
1030 | This driver provides common support for accessing the device, | 1054 | This driver provides common support for accessing the device, |
1031 | additional drivers must be enabled in order to use the | 1055 | additional drivers must be enabled in order to use the |
1032 | functionality of the device. | 1056 | functionality of the device. |
@@ -1079,9 +1103,9 @@ config MFD_SM501_GPIO | |||
1079 | bool "Export GPIO via GPIO layer" | 1103 | bool "Export GPIO via GPIO layer" |
1080 | depends on MFD_SM501 && GPIOLIB | 1104 | depends on MFD_SM501 && GPIOLIB |
1081 | ---help--- | 1105 | ---help--- |
1082 | This option uses the gpio library layer to export the 64 GPIO | 1106 | This option uses the gpio library layer to export the 64 GPIO |
1083 | lines on the SM501. The platform data is used to supply the | 1107 | lines on the SM501. The platform data is used to supply the |
1084 | base number for the first GPIO line to register. | 1108 | base number for the first GPIO line to register. |
1085 | 1109 | ||
1086 | config MFD_SKY81452 | 1110 | config MFD_SKY81452 |
1087 | tristate "Skyworks Solutions SKY81452" | 1111 | tristate "Skyworks Solutions SKY81452" |
@@ -1096,16 +1120,16 @@ config MFD_SKY81452 | |||
1096 | will be called sky81452. | 1120 | will be called sky81452. |
1097 | 1121 | ||
1098 | config MFD_SMSC | 1122 | config MFD_SMSC |
1099 | bool "SMSC ECE1099 series chips" | 1123 | bool "SMSC ECE1099 series chips" |
1100 | depends on I2C=y | 1124 | depends on I2C=y |
1101 | select MFD_CORE | 1125 | select MFD_CORE |
1102 | select REGMAP_I2C | 1126 | select REGMAP_I2C |
1103 | help | 1127 | help |
1104 | If you say yes here you get support for the | 1128 | If you say yes here you get support for the |
1105 | ece1099 chips from SMSC. | 1129 | ece1099 chips from SMSC. |
1106 | 1130 | ||
1107 | To compile this driver as a module, choose M here: the | 1131 | To compile this driver as a module, choose M here: the |
1108 | module will be called smsc. | 1132 | module will be called smsc. |
1109 | 1133 | ||
1110 | config MFD_SC27XX_PMIC | 1134 | config MFD_SC27XX_PMIC |
1111 | tristate "Spreadtrum SC27xx PMICs" | 1135 | tristate "Spreadtrum SC27xx PMICs" |
@@ -1171,12 +1195,12 @@ config AB8500_CORE | |||
1171 | This chip embeds various other multimedia funtionalities as well. | 1195 | This chip embeds various other multimedia funtionalities as well. |
1172 | 1196 | ||
1173 | config AB8500_DEBUG | 1197 | config AB8500_DEBUG |
1174 | bool "Enable debug info via debugfs" | 1198 | bool "Enable debug info via debugfs" |
1175 | depends on AB8500_GPADC && DEBUG_FS | 1199 | depends on AB8500_GPADC && DEBUG_FS |
1176 | default y if DEBUG_FS | 1200 | default y if DEBUG_FS |
1177 | help | 1201 | help |
1178 | Select this option if you want debug information using the debug | 1202 | Select this option if you want debug information using the debug |
1179 | filesystem, debugfs. | 1203 | filesystem, debugfs. |
1180 | 1204 | ||
1181 | config AB8500_GPADC | 1205 | config AB8500_GPADC |
1182 | bool "ST-Ericsson AB8500 GPADC driver" | 1206 | bool "ST-Ericsson AB8500 GPADC driver" |
@@ -1907,6 +1931,19 @@ config MFD_STPMIC1 | |||
1907 | To compile this driver as a module, choose M here: the | 1931 | To compile this driver as a module, choose M here: the |
1908 | module will be called stpmic1. | 1932 | module will be called stpmic1. |
1909 | 1933 | ||
1934 | config MFD_STMFX | ||
1935 | tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)" | ||
1936 | depends on I2C | ||
1937 | depends on OF || COMPILE_TEST | ||
1938 | select MFD_CORE | ||
1939 | select REGMAP_I2C | ||
1940 | help | ||
1941 | Support for the STMicroelectronics Multi-Function eXpander. | ||
1942 | |||
1943 | This driver provides common support for accessing the device, | ||
1944 | additional drivers must be enabled in order to use the functionality | ||
1945 | of the device. | ||
1946 | |||
1910 | menu "Multimedia Capabilities Port drivers" | 1947 | menu "Multimedia Capabilities Port drivers" |
1911 | depends on ARCH_SA1100 | 1948 | depends on ARCH_SA1100 |
1912 | 1949 | ||
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b4569ed7f3f3..52b1a90ff515 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -155,6 +155,7 @@ obj-$(CONFIG_MFD_DA9150) += da9150-core.o | |||
155 | 155 | ||
156 | obj-$(CONFIG_MFD_MAX14577) += max14577.o | 156 | obj-$(CONFIG_MFD_MAX14577) += max14577.o |
157 | obj-$(CONFIG_MFD_MAX77620) += max77620.o | 157 | obj-$(CONFIG_MFD_MAX77620) += max77620.o |
158 | obj-$(CONFIG_MFD_MAX77650) += max77650.o | ||
158 | obj-$(CONFIG_MFD_MAX77686) += max77686.o | 159 | obj-$(CONFIG_MFD_MAX77686) += max77686.o |
159 | obj-$(CONFIG_MFD_MAX77693) += max77693.o | 160 | obj-$(CONFIG_MFD_MAX77693) += max77693.o |
160 | obj-$(CONFIG_MFD_MAX77843) += max77843.o | 161 | obj-$(CONFIG_MFD_MAX77843) += max77843.o |
@@ -237,6 +238,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o | |||
237 | obj-$(CONFIG_MFD_MT6397) += mt6397-core.o | 238 | obj-$(CONFIG_MFD_MT6397) += mt6397-core.o |
238 | 239 | ||
239 | obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o | 240 | obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o |
241 | obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o | ||
240 | obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o | 242 | obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o |
241 | obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o | 243 | obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o |
242 | 244 | ||
@@ -246,4 +248,4 @@ obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o | |||
246 | obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o | 248 | obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o |
247 | obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o | 249 | obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o |
248 | obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o | 250 | obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o |
249 | 251 | obj-$(CONFIG_MFD_STMFX) += stmfx.o | |
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 8d652b2f9d14..f70d3f6a959b 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c | |||
@@ -2587,7 +2587,7 @@ static ssize_t ab8500_unsubscribe_write(struct file *file, | |||
2587 | } | 2587 | } |
2588 | 2588 | ||
2589 | /* | 2589 | /* |
2590 | * - several deubgfs nodes fops | 2590 | * - several debugfs nodes fops |
2591 | */ | 2591 | */ |
2592 | 2592 | ||
2593 | static const struct file_operations ab8500_bank_fops = { | 2593 | static const struct file_operations ab8500_bank_fops = { |
diff --git a/drivers/mfd/altera-sysmgr.c b/drivers/mfd/altera-sysmgr.c new file mode 100644 index 000000000000..8976f82785bb --- /dev/null +++ b/drivers/mfd/altera-sysmgr.c | |||
@@ -0,0 +1,211 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright (C) 2018-2019, Intel Corporation. | ||
4 | * Copyright (C) 2012 Freescale Semiconductor, Inc. | ||
5 | * Copyright (C) 2012 Linaro Ltd. | ||
6 | * | ||
7 | * Based on syscon driver. | ||
8 | */ | ||
9 | |||
10 | #include <linux/arm-smccc.h> | ||
11 | #include <linux/err.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/mfd/altera-sysmgr.h> | ||
14 | #include <linux/mfd/syscon.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_address.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | /** | ||
23 | * struct altr_sysmgr - Altera SOCFPGA System Manager | ||
24 | * @regmap: the regmap used for System Manager accesses. | ||
25 | * @base : the base address for the System Manager | ||
26 | */ | ||
27 | struct altr_sysmgr { | ||
28 | struct regmap *regmap; | ||
29 | resource_size_t *base; | ||
30 | }; | ||
31 | |||
32 | static struct platform_driver altr_sysmgr_driver; | ||
33 | |||
34 | /** | ||
35 | * s10_protected_reg_write | ||
36 | * Write to a protected SMC register. | ||
37 | * @base: Base address of System Manager | ||
38 | * @reg: Address offset of register | ||
39 | * @val: Value to write | ||
40 | * Return: INTEL_SIP_SMC_STATUS_OK (0) on success | ||
41 | * INTEL_SIP_SMC_REG_ERROR on error | ||
42 | * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported | ||
43 | */ | ||
44 | static int s10_protected_reg_write(void *base, | ||
45 | unsigned int reg, unsigned int val) | ||
46 | { | ||
47 | struct arm_smccc_res result; | ||
48 | unsigned long sysmgr_base = (unsigned long)base; | ||
49 | |||
50 | arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, sysmgr_base + reg, | ||
51 | val, 0, 0, 0, 0, 0, &result); | ||
52 | |||
53 | return (int)result.a0; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * s10_protected_reg_read | ||
58 | * Read the status of a protected SMC register | ||
59 | * @base: Base address of System Manager. | ||
60 | * @reg: Address of register | ||
61 | * @val: Value read. | ||
62 | * Return: INTEL_SIP_SMC_STATUS_OK (0) on success | ||
63 | * INTEL_SIP_SMC_REG_ERROR on error | ||
64 | * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported | ||
65 | */ | ||
66 | static int s10_protected_reg_read(void *base, | ||
67 | unsigned int reg, unsigned int *val) | ||
68 | { | ||
69 | struct arm_smccc_res result; | ||
70 | unsigned long sysmgr_base = (unsigned long)base; | ||
71 | |||
72 | arm_smccc_smc(INTEL_SIP_SMC_REG_READ, sysmgr_base + reg, | ||
73 | 0, 0, 0, 0, 0, 0, &result); | ||
74 | |||
75 | *val = (unsigned int)result.a1; | ||
76 | |||
77 | return (int)result.a0; | ||
78 | } | ||
79 | |||
80 | static struct regmap_config altr_sysmgr_regmap_cfg = { | ||
81 | .name = "altr_sysmgr", | ||
82 | .reg_bits = 32, | ||
83 | .reg_stride = 4, | ||
84 | .val_bits = 32, | ||
85 | .fast_io = true, | ||
86 | .use_single_read = true, | ||
87 | .use_single_write = true, | ||
88 | }; | ||
89 | |||
90 | /** | ||
91 | * sysmgr_match_phandle | ||
92 | * Matching function used by driver_find_device(). | ||
93 | * Return: True if match is found, otherwise false. | ||
94 | */ | ||
95 | static int sysmgr_match_phandle(struct device *dev, void *data) | ||
96 | { | ||
97 | return dev->of_node == (struct device_node *)data; | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * altr_sysmgr_regmap_lookup_by_phandle | ||
102 | * Find the sysmgr previous configured in probe() and return regmap property. | ||
103 | * Return: regmap if found or error if not found. | ||
104 | */ | ||
105 | struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, | ||
106 | const char *property) | ||
107 | { | ||
108 | struct device *dev; | ||
109 | struct altr_sysmgr *sysmgr; | ||
110 | struct device_node *sysmgr_np; | ||
111 | |||
112 | if (property) | ||
113 | sysmgr_np = of_parse_phandle(np, property, 0); | ||
114 | else | ||
115 | sysmgr_np = np; | ||
116 | |||
117 | if (!sysmgr_np) | ||
118 | return ERR_PTR(-ENODEV); | ||
119 | |||
120 | dev = driver_find_device(&altr_sysmgr_driver.driver, NULL, | ||
121 | (void *)sysmgr_np, sysmgr_match_phandle); | ||
122 | of_node_put(sysmgr_np); | ||
123 | if (!dev) | ||
124 | return ERR_PTR(-EPROBE_DEFER); | ||
125 | |||
126 | sysmgr = dev_get_drvdata(dev); | ||
127 | |||
128 | return sysmgr->regmap; | ||
129 | } | ||
130 | EXPORT_SYMBOL_GPL(altr_sysmgr_regmap_lookup_by_phandle); | ||
131 | |||
132 | static int sysmgr_probe(struct platform_device *pdev) | ||
133 | { | ||
134 | struct altr_sysmgr *sysmgr; | ||
135 | struct regmap *regmap; | ||
136 | struct resource *res; | ||
137 | struct regmap_config sysmgr_config = altr_sysmgr_regmap_cfg; | ||
138 | struct device *dev = &pdev->dev; | ||
139 | struct device_node *np = dev->of_node; | ||
140 | |||
141 | sysmgr = devm_kzalloc(dev, sizeof(*sysmgr), GFP_KERNEL); | ||
142 | if (!sysmgr) | ||
143 | return -ENOMEM; | ||
144 | |||
145 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
146 | if (!res) | ||
147 | return -ENOENT; | ||
148 | |||
149 | sysmgr_config.max_register = resource_size(res) - | ||
150 | sysmgr_config.reg_stride; | ||
151 | if (of_device_is_compatible(np, "altr,sys-mgr-s10")) { | ||
152 | /* Need physical address for SMCC call */ | ||
153 | sysmgr->base = (resource_size_t *)res->start; | ||
154 | sysmgr_config.reg_read = s10_protected_reg_read; | ||
155 | sysmgr_config.reg_write = s10_protected_reg_write; | ||
156 | |||
157 | regmap = devm_regmap_init(dev, NULL, sysmgr->base, | ||
158 | &sysmgr_config); | ||
159 | } else { | ||
160 | sysmgr->base = devm_ioremap(dev, res->start, | ||
161 | resource_size(res)); | ||
162 | if (!sysmgr->base) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | sysmgr_config.max_register = res->end - res->start - 3; | ||
166 | regmap = devm_regmap_init_mmio(dev, sysmgr->base, | ||
167 | &sysmgr_config); | ||
168 | } | ||
169 | |||
170 | if (IS_ERR(regmap)) { | ||
171 | pr_err("regmap init failed\n"); | ||
172 | return PTR_ERR(regmap); | ||
173 | } | ||
174 | |||
175 | sysmgr->regmap = regmap; | ||
176 | |||
177 | platform_set_drvdata(pdev, sysmgr); | ||
178 | |||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static const struct of_device_id altr_sysmgr_of_match[] = { | ||
183 | { .compatible = "altr,sys-mgr" }, | ||
184 | { .compatible = "altr,sys-mgr-s10" }, | ||
185 | {}, | ||
186 | }; | ||
187 | MODULE_DEVICE_TABLE(of, altr_sysmgr_of_match); | ||
188 | |||
189 | static struct platform_driver altr_sysmgr_driver = { | ||
190 | .probe = sysmgr_probe, | ||
191 | .driver = { | ||
192 | .name = "altr,system_manager", | ||
193 | .of_match_table = altr_sysmgr_of_match, | ||
194 | }, | ||
195 | }; | ||
196 | |||
197 | static int __init altr_sysmgr_init(void) | ||
198 | { | ||
199 | return platform_driver_register(&altr_sysmgr_driver); | ||
200 | } | ||
201 | core_initcall(altr_sysmgr_init); | ||
202 | |||
203 | static void __exit altr_sysmgr_exit(void) | ||
204 | { | ||
205 | platform_driver_unregister(&altr_sysmgr_driver); | ||
206 | } | ||
207 | module_exit(altr_sysmgr_exit); | ||
208 | |||
209 | MODULE_AUTHOR("Thor Thayer <>"); | ||
210 | MODULE_DESCRIPTION("SOCFPGA System Manager driver"); | ||
211 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c index e82543bcfdc8..35a9e16f9902 100644 --- a/drivers/mfd/atmel-hlcdc.c +++ b/drivers/mfd/atmel-hlcdc.c | |||
@@ -141,6 +141,7 @@ static const struct of_device_id atmel_hlcdc_match[] = { | |||
141 | { .compatible = "atmel,sama5d2-hlcdc" }, | 141 | { .compatible = "atmel,sama5d2-hlcdc" }, |
142 | { .compatible = "atmel,sama5d3-hlcdc" }, | 142 | { .compatible = "atmel,sama5d3-hlcdc" }, |
143 | { .compatible = "atmel,sama5d4-hlcdc" }, | 143 | { .compatible = "atmel,sama5d4-hlcdc" }, |
144 | { .compatible = "microchip,sam9x60-hlcdc" }, | ||
144 | { /* sentinel */ }, | 145 | { /* sentinel */ }, |
145 | }; | 146 | }; |
146 | MODULE_DEVICE_TABLE(of, atmel_hlcdc_match); | 147 | MODULE_DEVICE_TABLE(of, atmel_hlcdc_match); |
diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index a7b7c5423ea5..c2e8a0dee7f8 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c | |||
@@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = { | |||
65 | { .compatible = "x-powers,axp202", .data = (void *)AXP202_ID }, | 65 | { .compatible = "x-powers,axp202", .data = (void *)AXP202_ID }, |
66 | { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID }, | 66 | { .compatible = "x-powers,axp209", .data = (void *)AXP209_ID }, |
67 | { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID }, | 67 | { .compatible = "x-powers,axp221", .data = (void *)AXP221_ID }, |
68 | { .compatible = "x-powers,axp223", .data = (void *)AXP223_ID }, | ||
68 | { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, | 69 | { .compatible = "x-powers,axp806", .data = (void *)AXP806_ID }, |
69 | { }, | 70 | { }, |
70 | }; | 71 | }; |
@@ -75,6 +76,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = { | |||
75 | { "axp202", 0 }, | 76 | { "axp202", 0 }, |
76 | { "axp209", 0 }, | 77 | { "axp209", 0 }, |
77 | { "axp221", 0 }, | 78 | { "axp221", 0 }, |
79 | { "axp223", 0 }, | ||
78 | { "axp806", 0 }, | 80 | { "axp806", 0 }, |
79 | { }, | 81 | { }, |
80 | }; | 82 | }; |
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 3c97f2c0fdfe..2215660dfa05 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c | |||
@@ -198,6 +198,12 @@ static const struct resource axp22x_usb_power_supply_resources[] = { | |||
198 | DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), | 198 | DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), |
199 | }; | 199 | }; |
200 | 200 | ||
201 | /* AXP803 and AXP813/AXP818 share the same interrupts */ | ||
202 | static const struct resource axp803_usb_power_supply_resources[] = { | ||
203 | DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"), | ||
204 | DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"), | ||
205 | }; | ||
206 | |||
201 | static const struct resource axp22x_pek_resources[] = { | 207 | static const struct resource axp22x_pek_resources[] = { |
202 | DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_RIS_EDGE, "PEK_DBR"), | 208 | DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_RIS_EDGE, "PEK_DBR"), |
203 | DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_FAL_EDGE, "PEK_DBF"), | 209 | DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_FAL_EDGE, "PEK_DBF"), |
@@ -741,6 +747,11 @@ static const struct mfd_cell axp803_cells[] = { | |||
741 | .of_compatible = "x-powers,axp813-ac-power-supply", | 747 | .of_compatible = "x-powers,axp813-ac-power-supply", |
742 | .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources), | 748 | .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources), |
743 | .resources = axp20x_ac_power_supply_resources, | 749 | .resources = axp20x_ac_power_supply_resources, |
750 | }, { | ||
751 | .name = "axp20x-usb-power-supply", | ||
752 | .num_resources = ARRAY_SIZE(axp803_usb_power_supply_resources), | ||
753 | .resources = axp803_usb_power_supply_resources, | ||
754 | .of_compatible = "x-powers,axp813-usb-power-supply", | ||
744 | }, | 755 | }, |
745 | { .name = "axp20x-regulator" }, | 756 | { .name = "axp20x-regulator" }, |
746 | }; | 757 | }; |
@@ -793,6 +804,11 @@ static const struct mfd_cell axp813_cells[] = { | |||
793 | .of_compatible = "x-powers,axp813-ac-power-supply", | 804 | .of_compatible = "x-powers,axp813-ac-power-supply", |
794 | .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources), | 805 | .num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources), |
795 | .resources = axp20x_ac_power_supply_resources, | 806 | .resources = axp20x_ac_power_supply_resources, |
807 | }, { | ||
808 | .name = "axp20x-usb-power-supply", | ||
809 | .num_resources = ARRAY_SIZE(axp803_usb_power_supply_resources), | ||
810 | .resources = axp803_usb_power_supply_resources, | ||
811 | .of_compatible = "x-powers,axp813-usb-power-supply", | ||
796 | }, | 812 | }, |
797 | }; | 813 | }; |
798 | 814 | ||
diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 6acfe036d522..bd2bcdd4718b 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c | |||
@@ -75,20 +75,49 @@ static irqreturn_t ec_irq_thread(int irq, void *data) | |||
75 | 75 | ||
76 | static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) | 76 | static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event) |
77 | { | 77 | { |
78 | int ret; | ||
78 | struct { | 79 | struct { |
79 | struct cros_ec_command msg; | 80 | struct cros_ec_command msg; |
80 | struct ec_params_host_sleep_event req; | 81 | union { |
82 | struct ec_params_host_sleep_event req0; | ||
83 | struct ec_params_host_sleep_event_v1 req1; | ||
84 | struct ec_response_host_sleep_event_v1 resp1; | ||
85 | } u; | ||
81 | } __packed buf; | 86 | } __packed buf; |
82 | 87 | ||
83 | memset(&buf, 0, sizeof(buf)); | 88 | memset(&buf, 0, sizeof(buf)); |
84 | 89 | ||
85 | buf.req.sleep_event = sleep_event; | 90 | if (ec_dev->host_sleep_v1) { |
91 | buf.u.req1.sleep_event = sleep_event; | ||
92 | buf.u.req1.suspend_params.sleep_timeout_ms = | ||
93 | EC_HOST_SLEEP_TIMEOUT_DEFAULT; | ||
94 | |||
95 | buf.msg.outsize = sizeof(buf.u.req1); | ||
96 | if ((sleep_event == HOST_SLEEP_EVENT_S3_RESUME) || | ||
97 | (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) | ||
98 | buf.msg.insize = sizeof(buf.u.resp1); | ||
99 | |||
100 | buf.msg.version = 1; | ||
101 | |||
102 | } else { | ||
103 | buf.u.req0.sleep_event = sleep_event; | ||
104 | buf.msg.outsize = sizeof(buf.u.req0); | ||
105 | } | ||
86 | 106 | ||
87 | buf.msg.command = EC_CMD_HOST_SLEEP_EVENT; | 107 | buf.msg.command = EC_CMD_HOST_SLEEP_EVENT; |
88 | buf.msg.version = 0; | ||
89 | buf.msg.outsize = sizeof(buf.req); | ||
90 | 108 | ||
91 | return cros_ec_cmd_xfer(ec_dev, &buf.msg); | 109 | ret = cros_ec_cmd_xfer(ec_dev, &buf.msg); |
110 | |||
111 | /* For now, report failure to transition to S0ix with a warning. */ | ||
112 | if (ret >= 0 && ec_dev->host_sleep_v1 && | ||
113 | (sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME)) | ||
114 | WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions & | ||
115 | EC_HOST_RESUME_SLEEP_TIMEOUT, | ||
116 | "EC detected sleep transition timeout. Total slp_s0 transitions: %d", | ||
117 | buf.u.resp1.resume_response.sleep_transitions & | ||
118 | EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK); | ||
119 | |||
120 | return ret; | ||
92 | } | 121 | } |
93 | 122 | ||
94 | int cros_ec_register(struct cros_ec_device *ec_dev) | 123 | int cros_ec_register(struct cros_ec_device *ec_dev) |
diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index d275deaecb12..54a58df571b6 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c | |||
@@ -385,7 +385,8 @@ static const struct mfd_cell cros_ec_rtc_cells[] = { | |||
385 | }; | 385 | }; |
386 | 386 | ||
387 | static const struct mfd_cell cros_usbpd_charger_cells[] = { | 387 | static const struct mfd_cell cros_usbpd_charger_cells[] = { |
388 | { .name = "cros-usbpd-charger" } | 388 | { .name = "cros-usbpd-charger" }, |
389 | { .name = "cros-usbpd-logger" }, | ||
389 | }; | 390 | }; |
390 | 391 | ||
391 | static const struct mfd_cell cros_ec_platform_cells[] = { | 392 | static const struct mfd_cell cros_ec_platform_cells[] = { |
@@ -418,6 +419,39 @@ static int ec_device_probe(struct platform_device *pdev) | |||
418 | device_initialize(&ec->class_dev); | 419 | device_initialize(&ec->class_dev); |
419 | cdev_init(&ec->cdev, &fops); | 420 | cdev_init(&ec->cdev, &fops); |
420 | 421 | ||
422 | /* Check whether this is actually a Fingerprint MCU rather than an EC */ | ||
423 | if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) { | ||
424 | dev_info(dev, "CrOS Fingerprint MCU detected.\n"); | ||
425 | /* | ||
426 | * Help userspace differentiating ECs from FP MCU, | ||
427 | * regardless of the probing order. | ||
428 | */ | ||
429 | ec_platform->ec_name = CROS_EC_DEV_FP_NAME; | ||
430 | } | ||
431 | |||
432 | /* | ||
433 | * Check whether this is actually an Integrated Sensor Hub (ISH) | ||
434 | * rather than an EC. | ||
435 | */ | ||
436 | if (cros_ec_check_features(ec, EC_FEATURE_ISH)) { | ||
437 | dev_info(dev, "CrOS ISH MCU detected.\n"); | ||
438 | /* | ||
439 | * Help userspace differentiating ECs from ISH MCU, | ||
440 | * regardless of the probing order. | ||
441 | */ | ||
442 | ec_platform->ec_name = CROS_EC_DEV_ISH_NAME; | ||
443 | } | ||
444 | |||
445 | /* Check whether this is actually a Touchpad MCU rather than an EC */ | ||
446 | if (cros_ec_check_features(ec, EC_FEATURE_TOUCHPAD)) { | ||
447 | dev_info(dev, "CrOS Touchpad MCU detected.\n"); | ||
448 | /* | ||
449 | * Help userspace differentiating ECs from TP MCU, | ||
450 | * regardless of the probing order. | ||
451 | */ | ||
452 | ec_platform->ec_name = CROS_EC_DEV_TP_NAME; | ||
453 | } | ||
454 | |||
421 | /* | 455 | /* |
422 | * Add the class device | 456 | * Add the class device |
423 | * Link to the character device for creating the /dev entry | 457 | * Link to the character device for creating the /dev entry |
diff --git a/drivers/mfd/cs47l35-tables.c b/drivers/mfd/cs47l35-tables.c index 604c9dd14df5..338b825127f1 100644 --- a/drivers/mfd/cs47l35-tables.c +++ b/drivers/mfd/cs47l35-tables.c | |||
@@ -178,6 +178,7 @@ static const struct reg_default cs47l35_reg_default[] = { | |||
178 | { 0x00000448, 0x0a83 }, /* R1096 (0x448) - eDRE Enable */ | 178 | { 0x00000448, 0x0a83 }, /* R1096 (0x448) - eDRE Enable */ |
179 | { 0x0000044a, 0x0000 }, /* R1098 (0x44a) - eDRE Manual */ | 179 | { 0x0000044a, 0x0000 }, /* R1098 (0x44a) - eDRE Manual */ |
180 | { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ | 180 | { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ |
181 | { 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */ | ||
181 | { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ | 182 | { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ |
182 | { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ | 183 | { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ |
183 | { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ | 184 | { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ |
@@ -970,6 +971,7 @@ static bool cs47l35_16bit_readable_register(struct device *dev, | |||
970 | case MADERA_EDRE_ENABLE: | 971 | case MADERA_EDRE_ENABLE: |
971 | case MADERA_EDRE_MANUAL: | 972 | case MADERA_EDRE_MANUAL: |
972 | case MADERA_DAC_AEC_CONTROL_1: | 973 | case MADERA_DAC_AEC_CONTROL_1: |
974 | case MADERA_DAC_AEC_CONTROL_2: | ||
973 | case MADERA_NOISE_GATE_CONTROL: | 975 | case MADERA_NOISE_GATE_CONTROL: |
974 | case MADERA_PDM_SPK1_CTRL_1: | 976 | case MADERA_PDM_SPK1_CTRL_1: |
975 | case MADERA_PDM_SPK1_CTRL_2: | 977 | case MADERA_PDM_SPK1_CTRL_2: |
diff --git a/drivers/mfd/cs47l90-tables.c b/drivers/mfd/cs47l90-tables.c index 77207d98f0cc..c040d3d7232a 100644 --- a/drivers/mfd/cs47l90-tables.c +++ b/drivers/mfd/cs47l90-tables.c | |||
@@ -263,6 +263,7 @@ static const struct reg_default cs47l90_reg_default[] = { | |||
263 | { 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */ | 263 | { 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */ |
264 | { 0x00000448, 0x003f }, /* R1096 (0x448) - eDRE Enable */ | 264 | { 0x00000448, 0x003f }, /* R1096 (0x448) - eDRE Enable */ |
265 | { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ | 265 | { 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */ |
266 | { 0x00000451, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 2 */ | ||
266 | { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ | 267 | { 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */ |
267 | { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ | 268 | { 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */ |
268 | { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ | 269 | { 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */ |
@@ -1692,6 +1693,7 @@ static bool cs47l90_16bit_readable_register(struct device *dev, | |||
1692 | case MADERA_DRE_ENABLE: | 1693 | case MADERA_DRE_ENABLE: |
1693 | case MADERA_EDRE_ENABLE: | 1694 | case MADERA_EDRE_ENABLE: |
1694 | case MADERA_DAC_AEC_CONTROL_1: | 1695 | case MADERA_DAC_AEC_CONTROL_1: |
1696 | case MADERA_DAC_AEC_CONTROL_2: | ||
1695 | case MADERA_NOISE_GATE_CONTROL: | 1697 | case MADERA_NOISE_GATE_CONTROL: |
1696 | case MADERA_PDM_SPK1_CTRL_1: | 1698 | case MADERA_PDM_SPK1_CTRL_1: |
1697 | case MADERA_PDM_SPK1_CTRL_2: | 1699 | case MADERA_PDM_SPK1_CTRL_2: |
diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c index 6e4ce49b4405..b125f90dd375 100644 --- a/drivers/mfd/da9063-core.c +++ b/drivers/mfd/da9063-core.c | |||
@@ -1,5 +1,6 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
1 | /* | 2 | /* |
2 | * da9063-core.c: Device access for Dialog DA9063 modules | 3 | * Device access for Dialog DA9063 modules |
3 | * | 4 | * |
4 | * Copyright 2012 Dialog Semiconductors Ltd. | 5 | * Copyright 2012 Dialog Semiconductors Ltd. |
5 | * Copyright 2013 Philipp Zabel, Pengutronix | 6 | * Copyright 2013 Philipp Zabel, Pengutronix |
@@ -7,11 +8,6 @@ | |||
7 | * Author: Krystian Garbaciak, Dialog Semiconductor | 8 | * Author: Krystian Garbaciak, Dialog Semiconductor |
8 | * Author: Michal Hajduk, Dialog Semiconductor | 9 | * Author: Michal Hajduk, Dialog Semiconductor |
9 | * | 10 | * |
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | * | ||
15 | */ | 11 | */ |
16 | 12 | ||
17 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
@@ -26,7 +22,6 @@ | |||
26 | #include <linux/regmap.h> | 22 | #include <linux/regmap.h> |
27 | 23 | ||
28 | #include <linux/mfd/da9063/core.h> | 24 | #include <linux/mfd/da9063/core.h> |
29 | #include <linux/mfd/da9063/pdata.h> | ||
30 | #include <linux/mfd/da9063/registers.h> | 25 | #include <linux/mfd/da9063/registers.h> |
31 | 26 | ||
32 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
@@ -165,7 +160,6 @@ static int da9063_clear_fault_log(struct da9063 *da9063) | |||
165 | 160 | ||
166 | int da9063_device_init(struct da9063 *da9063, unsigned int irq) | 161 | int da9063_device_init(struct da9063 *da9063, unsigned int irq) |
167 | { | 162 | { |
168 | struct da9063_pdata *pdata = da9063->dev->platform_data; | ||
169 | int model, variant_id, variant_code; | 163 | int model, variant_id, variant_code; |
170 | int ret; | 164 | int ret; |
171 | 165 | ||
@@ -173,24 +167,10 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq) | |||
173 | if (ret < 0) | 167 | if (ret < 0) |
174 | dev_err(da9063->dev, "Cannot clear fault log\n"); | 168 | dev_err(da9063->dev, "Cannot clear fault log\n"); |
175 | 169 | ||
176 | if (pdata) { | 170 | da9063->flags = 0; |
177 | da9063->flags = pdata->flags; | 171 | da9063->irq_base = -1; |
178 | da9063->irq_base = pdata->irq_base; | ||
179 | } else { | ||
180 | da9063->flags = 0; | ||
181 | da9063->irq_base = -1; | ||
182 | } | ||
183 | da9063->chip_irq = irq; | 172 | da9063->chip_irq = irq; |
184 | 173 | ||
185 | if (pdata && pdata->init != NULL) { | ||
186 | ret = pdata->init(da9063); | ||
187 | if (ret != 0) { | ||
188 | dev_err(da9063->dev, | ||
189 | "Platform initialization failed.\n"); | ||
190 | return ret; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model); | 174 | ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model); |
195 | if (ret < 0) { | 175 | if (ret < 0) { |
196 | dev_err(da9063->dev, "Cannot read chip model id.\n"); | 176 | dev_err(da9063->dev, "Cannot read chip model id.\n"); |
diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c index 50a24b1921d0..455de74c0dd2 100644 --- a/drivers/mfd/da9063-i2c.c +++ b/drivers/mfd/da9063-i2c.c | |||
@@ -1,15 +1,10 @@ | |||
1 | /* da9063-i2c.c: Interrupt support for Dialog DA9063 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* I2C support for Dialog DA9063 | ||
2 | * | 3 | * |
3 | * Copyright 2012 Dialog Semiconductor Ltd. | 4 | * Copyright 2012 Dialog Semiconductor Ltd. |
4 | * Copyright 2013 Philipp Zabel, Pengutronix | 5 | * Copyright 2013 Philipp Zabel, Pengutronix |
5 | * | 6 | * |
6 | * Author: Krystian Garbaciak, Dialog Semiconductor | 7 | * Author: Krystian Garbaciak, Dialog Semiconductor |
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | 8 | */ |
14 | 9 | ||
15 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -22,7 +17,6 @@ | |||
22 | 17 | ||
23 | #include <linux/mfd/core.h> | 18 | #include <linux/mfd/core.h> |
24 | #include <linux/mfd/da9063/core.h> | 19 | #include <linux/mfd/da9063/core.h> |
25 | #include <linux/mfd/da9063/pdata.h> | ||
26 | #include <linux/mfd/da9063/registers.h> | 20 | #include <linux/mfd/da9063/registers.h> |
27 | 21 | ||
28 | #include <linux/of.h> | 22 | #include <linux/of.h> |
diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c index ecc0c8ce6c58..e2bbedf58e68 100644 --- a/drivers/mfd/da9063-irq.c +++ b/drivers/mfd/da9063-irq.c | |||
@@ -1,15 +1,10 @@ | |||
1 | /* da9063-irq.c: Interrupts support for Dialog DA9063 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* Interrupt support for Dialog DA9063 | ||
2 | * | 3 | * |
3 | * Copyright 2012 Dialog Semiconductor Ltd. | 4 | * Copyright 2012 Dialog Semiconductor Ltd. |
4 | * Copyright 2013 Philipp Zabel, Pengutronix | 5 | * Copyright 2013 Philipp Zabel, Pengutronix |
5 | * | 6 | * |
6 | * Author: Michal Hajduk, Dialog Semiconductor | 7 | * Author: Michal Hajduk, Dialog Semiconductor |
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | */ | 8 | */ |
14 | 9 | ||
15 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
@@ -19,7 +14,6 @@ | |||
19 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
20 | #include <linux/regmap.h> | 15 | #include <linux/regmap.h> |
21 | #include <linux/mfd/da9063/core.h> | 16 | #include <linux/mfd/da9063/core.h> |
22 | #include <linux/mfd/da9063/pdata.h> | ||
23 | 17 | ||
24 | #define DA9063_REG_EVENT_A_OFFSET 0 | 18 | #define DA9063_REG_EVENT_A_OFFSET 0 |
25 | #define DA9063_REG_EVENT_B_OFFSET 1 | 19 | #define DA9063_REG_EVENT_B_OFFSET 1 |
diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index cba2eb166650..6b111be944d9 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c | |||
@@ -129,6 +129,19 @@ static const struct intel_lpss_platform_info cnl_i2c_info = { | |||
129 | }; | 129 | }; |
130 | 130 | ||
131 | static const struct pci_device_id intel_lpss_pci_ids[] = { | 131 | static const struct pci_device_id intel_lpss_pci_ids[] = { |
132 | /* CML */ | ||
133 | { PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info }, | ||
134 | { PCI_VDEVICE(INTEL, 0x02a9), (kernel_ulong_t)&spt_uart_info }, | ||
135 | { PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&spt_info }, | ||
136 | { PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&spt_info }, | ||
137 | { PCI_VDEVICE(INTEL, 0x02c5), (kernel_ulong_t)&cnl_i2c_info }, | ||
138 | { PCI_VDEVICE(INTEL, 0x02c6), (kernel_ulong_t)&cnl_i2c_info }, | ||
139 | { PCI_VDEVICE(INTEL, 0x02c7), (kernel_ulong_t)&spt_uart_info }, | ||
140 | { PCI_VDEVICE(INTEL, 0x02e8), (kernel_ulong_t)&cnl_i2c_info }, | ||
141 | { PCI_VDEVICE(INTEL, 0x02e9), (kernel_ulong_t)&cnl_i2c_info }, | ||
142 | { PCI_VDEVICE(INTEL, 0x02ea), (kernel_ulong_t)&cnl_i2c_info }, | ||
143 | { PCI_VDEVICE(INTEL, 0x02eb), (kernel_ulong_t)&cnl_i2c_info }, | ||
144 | { PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&spt_info }, | ||
132 | /* BXT A-Step */ | 145 | /* BXT A-Step */ |
133 | { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info }, | 146 | { PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info }, |
134 | { PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info }, | 147 | { PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info }, |
diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 45221e092ecf..7e425ff53491 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c | |||
@@ -273,6 +273,9 @@ static void intel_lpss_init_dev(const struct intel_lpss *lpss) | |||
273 | { | 273 | { |
274 | u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN; | 274 | u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN; |
275 | 275 | ||
276 | /* Set the device in reset state */ | ||
277 | writel(0, lpss->priv + LPSS_PRIV_RESETS); | ||
278 | |||
276 | intel_lpss_deassert_reset(lpss); | 279 | intel_lpss_deassert_reset(lpss); |
277 | 280 | ||
278 | intel_lpss_set_remap_addr(lpss); | 281 | intel_lpss_set_remap_addr(lpss); |
diff --git a/drivers/mfd/intel_quark_i2c_gpio.c b/drivers/mfd/intel_quark_i2c_gpio.c index 5bddb84cfc1f..11adbf77960d 100644 --- a/drivers/mfd/intel_quark_i2c_gpio.c +++ b/drivers/mfd/intel_quark_i2c_gpio.c | |||
@@ -74,16 +74,6 @@ static const struct dmi_system_id dmi_platform_info[] = { | |||
74 | { | 74 | { |
75 | .matches = { | 75 | .matches = { |
76 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), | 76 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), |
77 | DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, | ||
78 | "6ES7647-0AA00-0YA2"), | ||
79 | }, | ||
80 | .driver_data = (void *)400000, | ||
81 | }, | ||
82 | { | ||
83 | .matches = { | ||
84 | DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"), | ||
85 | DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG, | ||
86 | "6ES7647-0AA00-1YA2"), | ||
87 | }, | 77 | }, |
88 | .driver_data = (void *)400000, | 78 | .driver_data = (void *)400000, |
89 | }, | 79 | }, |
diff --git a/drivers/mfd/intel_soc_pmic_chtwc.c b/drivers/mfd/intel_soc_pmic_chtwc.c index 64a3aece9c5e..be84bb2aa837 100644 --- a/drivers/mfd/intel_soc_pmic_chtwc.c +++ b/drivers/mfd/intel_soc_pmic_chtwc.c | |||
@@ -60,6 +60,7 @@ static struct mfd_cell cht_wc_dev[] = { | |||
60 | .resources = cht_wc_ext_charger_resources, | 60 | .resources = cht_wc_ext_charger_resources, |
61 | }, | 61 | }, |
62 | { .name = "cht_wcove_region", }, | 62 | { .name = "cht_wcove_region", }, |
63 | { .name = "cht_wcove_leds", }, | ||
63 | }; | 64 | }; |
64 | 65 | ||
65 | /* | 66 | /* |
diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index d8ddd1a6f304..436361ce3737 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c | |||
@@ -37,6 +37,8 @@ | |||
37 | #include <linux/regmap.h> | 37 | #include <linux/regmap.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | 39 | ||
40 | static struct max77620_chip *max77620_scratch; | ||
41 | |||
40 | static const struct resource gpio_resources[] = { | 42 | static const struct resource gpio_resources[] = { |
41 | DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO), | 43 | DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO), |
42 | }; | 44 | }; |
@@ -111,6 +113,26 @@ static const struct mfd_cell max20024_children[] = { | |||
111 | }, | 113 | }, |
112 | }; | 114 | }; |
113 | 115 | ||
116 | static const struct mfd_cell max77663_children[] = { | ||
117 | { .name = "max77620-pinctrl", }, | ||
118 | { .name = "max77620-clock", }, | ||
119 | { .name = "max77663-pmic", }, | ||
120 | { .name = "max77620-watchdog", }, | ||
121 | { | ||
122 | .name = "max77620-gpio", | ||
123 | .resources = gpio_resources, | ||
124 | .num_resources = ARRAY_SIZE(gpio_resources), | ||
125 | }, { | ||
126 | .name = "max77620-rtc", | ||
127 | .resources = rtc_resources, | ||
128 | .num_resources = ARRAY_SIZE(rtc_resources), | ||
129 | }, { | ||
130 | .name = "max77663-power", | ||
131 | .resources = power_resources, | ||
132 | .num_resources = ARRAY_SIZE(power_resources), | ||
133 | }, | ||
134 | }; | ||
135 | |||
114 | static const struct regmap_range max77620_readable_ranges[] = { | 136 | static const struct regmap_range max77620_readable_ranges[] = { |
115 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), | 137 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4), |
116 | }; | 138 | }; |
@@ -171,6 +193,35 @@ static const struct regmap_config max20024_regmap_config = { | |||
171 | .volatile_table = &max77620_volatile_table, | 193 | .volatile_table = &max77620_volatile_table, |
172 | }; | 194 | }; |
173 | 195 | ||
196 | static const struct regmap_range max77663_readable_ranges[] = { | ||
197 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5), | ||
198 | }; | ||
199 | |||
200 | static const struct regmap_access_table max77663_readable_table = { | ||
201 | .yes_ranges = max77663_readable_ranges, | ||
202 | .n_yes_ranges = ARRAY_SIZE(max77663_readable_ranges), | ||
203 | }; | ||
204 | |||
205 | static const struct regmap_range max77663_writable_ranges[] = { | ||
206 | regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5), | ||
207 | }; | ||
208 | |||
209 | static const struct regmap_access_table max77663_writable_table = { | ||
210 | .yes_ranges = max77663_writable_ranges, | ||
211 | .n_yes_ranges = ARRAY_SIZE(max77663_writable_ranges), | ||
212 | }; | ||
213 | |||
214 | static const struct regmap_config max77663_regmap_config = { | ||
215 | .name = "power-slave", | ||
216 | .reg_bits = 8, | ||
217 | .val_bits = 8, | ||
218 | .max_register = MAX77620_REG_CID5 + 1, | ||
219 | .cache_type = REGCACHE_RBTREE, | ||
220 | .rd_table = &max77663_readable_table, | ||
221 | .wr_table = &max77663_writable_table, | ||
222 | .volatile_table = &max77620_volatile_table, | ||
223 | }; | ||
224 | |||
174 | /* | 225 | /* |
175 | * MAX77620 and MAX20024 has the following steps of the interrupt handling | 226 | * MAX77620 and MAX20024 has the following steps of the interrupt handling |
176 | * for TOP interrupts: | 227 | * for TOP interrupts: |
@@ -240,6 +291,9 @@ static int max77620_get_fps_period_reg_value(struct max77620_chip *chip, | |||
240 | case MAX77620: | 291 | case MAX77620: |
241 | fps_min_period = MAX77620_FPS_PERIOD_MIN_US; | 292 | fps_min_period = MAX77620_FPS_PERIOD_MIN_US; |
242 | break; | 293 | break; |
294 | case MAX77663: | ||
295 | fps_min_period = MAX20024_FPS_PERIOD_MIN_US; | ||
296 | break; | ||
243 | default: | 297 | default: |
244 | return -EINVAL; | 298 | return -EINVAL; |
245 | } | 299 | } |
@@ -274,6 +328,9 @@ static int max77620_config_fps(struct max77620_chip *chip, | |||
274 | case MAX77620: | 328 | case MAX77620: |
275 | fps_max_period = MAX77620_FPS_PERIOD_MAX_US; | 329 | fps_max_period = MAX77620_FPS_PERIOD_MAX_US; |
276 | break; | 330 | break; |
331 | case MAX77663: | ||
332 | fps_max_period = MAX20024_FPS_PERIOD_MAX_US; | ||
333 | break; | ||
277 | default: | 334 | default: |
278 | return -EINVAL; | 335 | return -EINVAL; |
279 | } | 336 | } |
@@ -375,6 +432,9 @@ static int max77620_initialise_fps(struct max77620_chip *chip) | |||
375 | } | 432 | } |
376 | 433 | ||
377 | skip_fps: | 434 | skip_fps: |
435 | if (chip->chip_id == MAX77663) | ||
436 | return 0; | ||
437 | |||
378 | /* Enable wake on EN0 pin */ | 438 | /* Enable wake on EN0 pin */ |
379 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, | 439 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, |
380 | MAX77620_ONOFFCNFG2_WK_EN0, | 440 | MAX77620_ONOFFCNFG2_WK_EN0, |
@@ -423,6 +483,15 @@ static int max77620_read_es_version(struct max77620_chip *chip) | |||
423 | return ret; | 483 | return ret; |
424 | } | 484 | } |
425 | 485 | ||
486 | static void max77620_pm_power_off(void) | ||
487 | { | ||
488 | struct max77620_chip *chip = max77620_scratch; | ||
489 | |||
490 | regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1, | ||
491 | MAX77620_ONOFFCNFG1_SFT_RST, | ||
492 | MAX77620_ONOFFCNFG1_SFT_RST); | ||
493 | } | ||
494 | |||
426 | static int max77620_probe(struct i2c_client *client, | 495 | static int max77620_probe(struct i2c_client *client, |
427 | const struct i2c_device_id *id) | 496 | const struct i2c_device_id *id) |
428 | { | 497 | { |
@@ -430,6 +499,7 @@ static int max77620_probe(struct i2c_client *client, | |||
430 | struct max77620_chip *chip; | 499 | struct max77620_chip *chip; |
431 | const struct mfd_cell *mfd_cells; | 500 | const struct mfd_cell *mfd_cells; |
432 | int n_mfd_cells; | 501 | int n_mfd_cells; |
502 | bool pm_off; | ||
433 | int ret; | 503 | int ret; |
434 | 504 | ||
435 | chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); | 505 | chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); |
@@ -453,6 +523,11 @@ static int max77620_probe(struct i2c_client *client, | |||
453 | n_mfd_cells = ARRAY_SIZE(max20024_children); | 523 | n_mfd_cells = ARRAY_SIZE(max20024_children); |
454 | rmap_config = &max20024_regmap_config; | 524 | rmap_config = &max20024_regmap_config; |
455 | break; | 525 | break; |
526 | case MAX77663: | ||
527 | mfd_cells = max77663_children; | ||
528 | n_mfd_cells = ARRAY_SIZE(max77663_children); | ||
529 | rmap_config = &max77663_regmap_config; | ||
530 | break; | ||
456 | default: | 531 | default: |
457 | dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id); | 532 | dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id); |
458 | return -EINVAL; | 533 | return -EINVAL; |
@@ -491,6 +566,12 @@ static int max77620_probe(struct i2c_client *client, | |||
491 | return ret; | 566 | return ret; |
492 | } | 567 | } |
493 | 568 | ||
569 | pm_off = of_device_is_system_power_controller(client->dev.of_node); | ||
570 | if (pm_off && !pm_power_off) { | ||
571 | max77620_scratch = chip; | ||
572 | pm_power_off = max77620_pm_power_off; | ||
573 | } | ||
574 | |||
494 | return 0; | 575 | return 0; |
495 | } | 576 | } |
496 | 577 | ||
@@ -546,6 +627,9 @@ static int max77620_i2c_suspend(struct device *dev) | |||
546 | return ret; | 627 | return ret; |
547 | } | 628 | } |
548 | 629 | ||
630 | if (chip->chip_id == MAX77663) | ||
631 | goto out; | ||
632 | |||
549 | /* Disable WK_EN0 */ | 633 | /* Disable WK_EN0 */ |
550 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, | 634 | ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2, |
551 | MAX77620_ONOFFCNFG2_WK_EN0, 0); | 635 | MAX77620_ONOFFCNFG2_WK_EN0, 0); |
@@ -581,7 +665,7 @@ static int max77620_i2c_resume(struct device *dev) | |||
581 | * For MAX20024: No need to configure WKEN0 on resume as | 665 | * For MAX20024: No need to configure WKEN0 on resume as |
582 | * it is configured on Init. | 666 | * it is configured on Init. |
583 | */ | 667 | */ |
584 | if (chip->chip_id == MAX20024) | 668 | if (chip->chip_id == MAX20024 || chip->chip_id == MAX77663) |
585 | goto out; | 669 | goto out; |
586 | 670 | ||
587 | /* Enable WK_EN0 */ | 671 | /* Enable WK_EN0 */ |
@@ -603,6 +687,7 @@ out: | |||
603 | static const struct i2c_device_id max77620_id[] = { | 687 | static const struct i2c_device_id max77620_id[] = { |
604 | {"max77620", MAX77620}, | 688 | {"max77620", MAX77620}, |
605 | {"max20024", MAX20024}, | 689 | {"max20024", MAX20024}, |
690 | {"max77663", MAX77663}, | ||
606 | {}, | 691 | {}, |
607 | }; | 692 | }; |
608 | 693 | ||
diff --git a/drivers/mfd/max77650.c b/drivers/mfd/max77650.c new file mode 100644 index 000000000000..60e07aca6ae5 --- /dev/null +++ b/drivers/mfd/max77650.c | |||
@@ -0,0 +1,232 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // | ||
3 | // Copyright (C) 2018 BayLibre SAS | ||
4 | // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
5 | // | ||
6 | // Core MFD driver for MAXIM 77650/77651 charger/power-supply. | ||
7 | // Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf | ||
8 | |||
9 | #include <linux/i2c.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/mfd/core.h> | ||
13 | #include <linux/mfd/max77650.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/regmap.h> | ||
17 | |||
18 | #define MAX77650_INT_GPI_F_MSK BIT(0) | ||
19 | #define MAX77650_INT_GPI_R_MSK BIT(1) | ||
20 | #define MAX77650_INT_GPI_MSK \ | ||
21 | (MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK) | ||
22 | #define MAX77650_INT_nEN_F_MSK BIT(2) | ||
23 | #define MAX77650_INT_nEN_R_MSK BIT(3) | ||
24 | #define MAX77650_INT_TJAL1_R_MSK BIT(4) | ||
25 | #define MAX77650_INT_TJAL2_R_MSK BIT(5) | ||
26 | #define MAX77650_INT_DOD_R_MSK BIT(6) | ||
27 | |||
28 | #define MAX77650_INT_THM_MSK BIT(0) | ||
29 | #define MAX77650_INT_CHG_MSK BIT(1) | ||
30 | #define MAX77650_INT_CHGIN_MSK BIT(2) | ||
31 | #define MAX77650_INT_TJ_REG_MSK BIT(3) | ||
32 | #define MAX77650_INT_CHGIN_CTRL_MSK BIT(4) | ||
33 | #define MAX77650_INT_SYS_CTRL_MSK BIT(5) | ||
34 | #define MAX77650_INT_SYS_CNFG_MSK BIT(6) | ||
35 | |||
36 | #define MAX77650_INT_GLBL_OFFSET 0 | ||
37 | #define MAX77650_INT_CHG_OFFSET 1 | ||
38 | |||
39 | #define MAX77650_SBIA_LPM_MASK BIT(5) | ||
40 | #define MAX77650_SBIA_LPM_DISABLED 0x00 | ||
41 | |||
42 | enum { | ||
43 | MAX77650_INT_GPI, | ||
44 | MAX77650_INT_nEN_F, | ||
45 | MAX77650_INT_nEN_R, | ||
46 | MAX77650_INT_TJAL1_R, | ||
47 | MAX77650_INT_TJAL2_R, | ||
48 | MAX77650_INT_DOD_R, | ||
49 | MAX77650_INT_THM, | ||
50 | MAX77650_INT_CHG, | ||
51 | MAX77650_INT_CHGIN, | ||
52 | MAX77650_INT_TJ_REG, | ||
53 | MAX77650_INT_CHGIN_CTRL, | ||
54 | MAX77650_INT_SYS_CTRL, | ||
55 | MAX77650_INT_SYS_CNFG, | ||
56 | }; | ||
57 | |||
58 | static const struct resource max77650_charger_resources[] = { | ||
59 | DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHG, "CHG"), | ||
60 | DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHGIN, "CHGIN"), | ||
61 | }; | ||
62 | |||
63 | static const struct resource max77650_gpio_resources[] = { | ||
64 | DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"), | ||
65 | }; | ||
66 | |||
67 | static const struct resource max77650_onkey_resources[] = { | ||
68 | DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_F, "nEN_F"), | ||
69 | DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_R, "nEN_R"), | ||
70 | }; | ||
71 | |||
72 | static const struct mfd_cell max77650_cells[] = { | ||
73 | { | ||
74 | .name = "max77650-regulator", | ||
75 | .of_compatible = "maxim,max77650-regulator", | ||
76 | }, { | ||
77 | .name = "max77650-charger", | ||
78 | .of_compatible = "maxim,max77650-charger", | ||
79 | .resources = max77650_charger_resources, | ||
80 | .num_resources = ARRAY_SIZE(max77650_charger_resources), | ||
81 | }, { | ||
82 | .name = "max77650-gpio", | ||
83 | .of_compatible = "maxim,max77650-gpio", | ||
84 | .resources = max77650_gpio_resources, | ||
85 | .num_resources = ARRAY_SIZE(max77650_gpio_resources), | ||
86 | }, { | ||
87 | .name = "max77650-led", | ||
88 | .of_compatible = "maxim,max77650-led", | ||
89 | }, { | ||
90 | .name = "max77650-onkey", | ||
91 | .of_compatible = "maxim,max77650-onkey", | ||
92 | .resources = max77650_onkey_resources, | ||
93 | .num_resources = ARRAY_SIZE(max77650_onkey_resources), | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | static const struct regmap_irq max77650_irqs[] = { | ||
98 | [MAX77650_INT_GPI] = { | ||
99 | .reg_offset = MAX77650_INT_GLBL_OFFSET, | ||
100 | .mask = MAX77650_INT_GPI_MSK, | ||
101 | .type = { | ||
102 | .type_falling_val = MAX77650_INT_GPI_F_MSK, | ||
103 | .type_rising_val = MAX77650_INT_GPI_R_MSK, | ||
104 | .types_supported = IRQ_TYPE_EDGE_BOTH, | ||
105 | }, | ||
106 | }, | ||
107 | REGMAP_IRQ_REG(MAX77650_INT_nEN_F, | ||
108 | MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_F_MSK), | ||
109 | REGMAP_IRQ_REG(MAX77650_INT_nEN_R, | ||
110 | MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_R_MSK), | ||
111 | REGMAP_IRQ_REG(MAX77650_INT_TJAL1_R, | ||
112 | MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL1_R_MSK), | ||
113 | REGMAP_IRQ_REG(MAX77650_INT_TJAL2_R, | ||
114 | MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL2_R_MSK), | ||
115 | REGMAP_IRQ_REG(MAX77650_INT_DOD_R, | ||
116 | MAX77650_INT_GLBL_OFFSET, MAX77650_INT_DOD_R_MSK), | ||
117 | REGMAP_IRQ_REG(MAX77650_INT_THM, | ||
118 | MAX77650_INT_CHG_OFFSET, MAX77650_INT_THM_MSK), | ||
119 | REGMAP_IRQ_REG(MAX77650_INT_CHG, | ||
120 | MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHG_MSK), | ||
121 | REGMAP_IRQ_REG(MAX77650_INT_CHGIN, | ||
122 | MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_MSK), | ||
123 | REGMAP_IRQ_REG(MAX77650_INT_TJ_REG, | ||
124 | MAX77650_INT_CHG_OFFSET, MAX77650_INT_TJ_REG_MSK), | ||
125 | REGMAP_IRQ_REG(MAX77650_INT_CHGIN_CTRL, | ||
126 | MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_CTRL_MSK), | ||
127 | REGMAP_IRQ_REG(MAX77650_INT_SYS_CTRL, | ||
128 | MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CTRL_MSK), | ||
129 | REGMAP_IRQ_REG(MAX77650_INT_SYS_CNFG, | ||
130 | MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CNFG_MSK), | ||
131 | }; | ||
132 | |||
133 | static const struct regmap_irq_chip max77650_irq_chip = { | ||
134 | .name = "max77650-irq", | ||
135 | .irqs = max77650_irqs, | ||
136 | .num_irqs = ARRAY_SIZE(max77650_irqs), | ||
137 | .num_regs = 2, | ||
138 | .status_base = MAX77650_REG_INT_GLBL, | ||
139 | .mask_base = MAX77650_REG_INTM_GLBL, | ||
140 | .type_in_mask = true, | ||
141 | .type_invert = true, | ||
142 | .init_ack_masked = true, | ||
143 | .clear_on_unmask = true, | ||
144 | }; | ||
145 | |||
146 | static const struct regmap_config max77650_regmap_config = { | ||
147 | .name = "max77650", | ||
148 | .reg_bits = 8, | ||
149 | .val_bits = 8, | ||
150 | }; | ||
151 | |||
152 | static int max77650_i2c_probe(struct i2c_client *i2c) | ||
153 | { | ||
154 | struct regmap_irq_chip_data *irq_data; | ||
155 | struct device *dev = &i2c->dev; | ||
156 | struct irq_domain *domain; | ||
157 | struct regmap *map; | ||
158 | unsigned int val; | ||
159 | int rv, id; | ||
160 | |||
161 | map = devm_regmap_init_i2c(i2c, &max77650_regmap_config); | ||
162 | if (IS_ERR(map)) { | ||
163 | dev_err(dev, "Unable to initialise I2C Regmap\n"); | ||
164 | return PTR_ERR(map); | ||
165 | } | ||
166 | |||
167 | rv = regmap_read(map, MAX77650_REG_CID, &val); | ||
168 | if (rv) { | ||
169 | dev_err(dev, "Unable to read Chip ID\n"); | ||
170 | return rv; | ||
171 | } | ||
172 | |||
173 | id = MAX77650_CID_BITS(val); | ||
174 | switch (id) { | ||
175 | case MAX77650_CID_77650A: | ||
176 | case MAX77650_CID_77650C: | ||
177 | case MAX77650_CID_77651A: | ||
178 | case MAX77650_CID_77651B: | ||
179 | break; | ||
180 | default: | ||
181 | dev_err(dev, "Chip not supported - ID: 0x%02x\n", id); | ||
182 | return -ENODEV; | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | * This IC has a low-power mode which reduces the quiescent current | ||
187 | * consumption to ~5.6uA but is only suitable for systems consuming | ||
188 | * less than ~2mA. Since this is not likely the case even on | ||
189 | * linux-based wearables - keep the chip in normal power mode. | ||
190 | */ | ||
191 | rv = regmap_update_bits(map, | ||
192 | MAX77650_REG_CNFG_GLBL, | ||
193 | MAX77650_SBIA_LPM_MASK, | ||
194 | MAX77650_SBIA_LPM_DISABLED); | ||
195 | if (rv) { | ||
196 | dev_err(dev, "Unable to change the power mode\n"); | ||
197 | return rv; | ||
198 | } | ||
199 | |||
200 | rv = devm_regmap_add_irq_chip(dev, map, i2c->irq, | ||
201 | IRQF_ONESHOT | IRQF_SHARED, 0, | ||
202 | &max77650_irq_chip, &irq_data); | ||
203 | if (rv) { | ||
204 | dev_err(dev, "Unable to add Regmap IRQ chip\n"); | ||
205 | return rv; | ||
206 | } | ||
207 | |||
208 | domain = regmap_irq_get_domain(irq_data); | ||
209 | |||
210 | return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, | ||
211 | max77650_cells, ARRAY_SIZE(max77650_cells), | ||
212 | NULL, 0, domain); | ||
213 | } | ||
214 | |||
215 | static const struct of_device_id max77650_of_match[] = { | ||
216 | { .compatible = "maxim,max77650" }, | ||
217 | { } | ||
218 | }; | ||
219 | MODULE_DEVICE_TABLE(of, max77650_of_match); | ||
220 | |||
221 | static struct i2c_driver max77650_i2c_driver = { | ||
222 | .driver = { | ||
223 | .name = "max77650", | ||
224 | .of_match_table = of_match_ptr(max77650_of_match), | ||
225 | }, | ||
226 | .probe_new = max77650_i2c_probe, | ||
227 | }; | ||
228 | module_i2c_driver(max77650_i2c_driver); | ||
229 | |||
230 | MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver"); | ||
231 | MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); | ||
232 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 94e3f32ce935..1ade4c8cc91f 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c | |||
@@ -269,6 +269,19 @@ fail_alloc: | |||
269 | return ret; | 269 | return ret; |
270 | } | 270 | } |
271 | 271 | ||
272 | /** | ||
273 | * mfd_add_devices - register child devices | ||
274 | * | ||
275 | * @parent: Pointer to parent device. | ||
276 | * @id: Can be PLATFORM_DEVID_AUTO to let the Platform API take care | ||
277 | * of device numbering, or will be added to a device's cell_id. | ||
278 | * @cells: Array of (struct mfd_cell)s describing child devices. | ||
279 | * @n_devs: Number of child devices to register. | ||
280 | * @mem_base: Parent register range resource for child devices. | ||
281 | * @irq_base: Base of the range of virtual interrupt numbers allocated for | ||
282 | * this MFD device. Unused if @domain is specified. | ||
283 | * @domain: Interrupt domain to create mappings for hardware interrupts. | ||
284 | */ | ||
272 | int mfd_add_devices(struct device *parent, int id, | 285 | int mfd_add_devices(struct device *parent, int id, |
273 | const struct mfd_cell *cells, int n_devs, | 286 | const struct mfd_cell *cells, int n_devs, |
274 | struct resource *mem_base, | 287 | struct resource *mem_base, |
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 216fbf6adec9..94377782d208 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c | |||
@@ -568,14 +568,6 @@ static int rk808_remove(struct i2c_client *client) | |||
568 | return 0; | 568 | return 0; |
569 | } | 569 | } |
570 | 570 | ||
571 | static const struct i2c_device_id rk808_ids[] = { | ||
572 | { "rk805" }, | ||
573 | { "rk808" }, | ||
574 | { "rk818" }, | ||
575 | { }, | ||
576 | }; | ||
577 | MODULE_DEVICE_TABLE(i2c, rk808_ids); | ||
578 | |||
579 | static struct i2c_driver rk808_i2c_driver = { | 571 | static struct i2c_driver rk808_i2c_driver = { |
580 | .driver = { | 572 | .driver = { |
581 | .name = "rk808", | 573 | .name = "rk808", |
@@ -583,7 +575,6 @@ static struct i2c_driver rk808_i2c_driver = { | |||
583 | }, | 575 | }, |
584 | .probe = rk808_probe, | 576 | .probe = rk808_probe, |
585 | .remove = rk808_remove, | 577 | .remove = rk808_remove, |
586 | .id_table = rk808_ids, | ||
587 | }; | 578 | }; |
588 | 579 | ||
589 | module_i2c_driver(rk808_i2c_driver); | 580 | module_i2c_driver(rk808_i2c_driver); |
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 521319086c81..95473ff9bb4b 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c | |||
@@ -28,45 +28,33 @@ | |||
28 | #include <linux/regmap.h> | 28 | #include <linux/regmap.h> |
29 | 29 | ||
30 | static const struct mfd_cell s5m8751_devs[] = { | 30 | static const struct mfd_cell s5m8751_devs[] = { |
31 | { | 31 | { .name = "s5m8751-pmic", }, |
32 | .name = "s5m8751-pmic", | 32 | { .name = "s5m-charger", }, |
33 | }, { | 33 | { .name = "s5m8751-codec", }, |
34 | .name = "s5m-charger", | ||
35 | }, { | ||
36 | .name = "s5m8751-codec", | ||
37 | }, | ||
38 | }; | 34 | }; |
39 | 35 | ||
40 | static const struct mfd_cell s5m8763_devs[] = { | 36 | static const struct mfd_cell s5m8763_devs[] = { |
41 | { | 37 | { .name = "s5m8763-pmic", }, |
42 | .name = "s5m8763-pmic", | 38 | { .name = "s5m-rtc", }, |
43 | }, { | 39 | { .name = "s5m-charger", }, |
44 | .name = "s5m-rtc", | ||
45 | }, { | ||
46 | .name = "s5m-charger", | ||
47 | }, | ||
48 | }; | 40 | }; |
49 | 41 | ||
50 | static const struct mfd_cell s5m8767_devs[] = { | 42 | static const struct mfd_cell s5m8767_devs[] = { |
43 | { .name = "s5m8767-pmic", }, | ||
44 | { .name = "s5m-rtc", }, | ||
51 | { | 45 | { |
52 | .name = "s5m8767-pmic", | ||
53 | }, { | ||
54 | .name = "s5m-rtc", | ||
55 | }, { | ||
56 | .name = "s5m8767-clk", | 46 | .name = "s5m8767-clk", |
57 | .of_compatible = "samsung,s5m8767-clk", | 47 | .of_compatible = "samsung,s5m8767-clk", |
58 | } | 48 | }, |
59 | }; | 49 | }; |
60 | 50 | ||
61 | static const struct mfd_cell s2mps11_devs[] = { | 51 | static const struct mfd_cell s2mps11_devs[] = { |
52 | { .name = "s2mps11-regulator", }, | ||
53 | { .name = "s2mps14-rtc", }, | ||
62 | { | 54 | { |
63 | .name = "s2mps11-regulator", | ||
64 | }, { | ||
65 | .name = "s2mps14-rtc", | ||
66 | }, { | ||
67 | .name = "s2mps11-clk", | 55 | .name = "s2mps11-clk", |
68 | .of_compatible = "samsung,s2mps11-clk", | 56 | .of_compatible = "samsung,s2mps11-clk", |
69 | } | 57 | }, |
70 | }; | 58 | }; |
71 | 59 | ||
72 | static const struct mfd_cell s2mps13_devs[] = { | 60 | static const struct mfd_cell s2mps13_devs[] = { |
@@ -79,37 +67,30 @@ static const struct mfd_cell s2mps13_devs[] = { | |||
79 | }; | 67 | }; |
80 | 68 | ||
81 | static const struct mfd_cell s2mps14_devs[] = { | 69 | static const struct mfd_cell s2mps14_devs[] = { |
70 | { .name = "s2mps14-regulator", }, | ||
71 | { .name = "s2mps14-rtc", }, | ||
82 | { | 72 | { |
83 | .name = "s2mps14-regulator", | ||
84 | }, { | ||
85 | .name = "s2mps14-rtc", | ||
86 | }, { | ||
87 | .name = "s2mps14-clk", | 73 | .name = "s2mps14-clk", |
88 | .of_compatible = "samsung,s2mps14-clk", | 74 | .of_compatible = "samsung,s2mps14-clk", |
89 | } | 75 | }, |
90 | }; | 76 | }; |
91 | 77 | ||
92 | static const struct mfd_cell s2mps15_devs[] = { | 78 | static const struct mfd_cell s2mps15_devs[] = { |
79 | { .name = "s2mps15-regulator", }, | ||
80 | { .name = "s2mps15-rtc", }, | ||
93 | { | 81 | { |
94 | .name = "s2mps15-regulator", | ||
95 | }, { | ||
96 | .name = "s2mps15-rtc", | ||
97 | }, { | ||
98 | .name = "s2mps13-clk", | 82 | .name = "s2mps13-clk", |
99 | .of_compatible = "samsung,s2mps13-clk", | 83 | .of_compatible = "samsung,s2mps13-clk", |
100 | }, | 84 | }, |
101 | }; | 85 | }; |
102 | 86 | ||
103 | static const struct mfd_cell s2mpa01_devs[] = { | 87 | static const struct mfd_cell s2mpa01_devs[] = { |
104 | { | 88 | { .name = "s2mpa01-pmic", }, |
105 | .name = "s2mpa01-pmic", | 89 | { .name = "s2mps14-rtc", }, |
106 | }, | ||
107 | }; | 90 | }; |
108 | 91 | ||
109 | static const struct mfd_cell s2mpu02_devs[] = { | 92 | static const struct mfd_cell s2mpu02_devs[] = { |
110 | { | 93 | { .name = "s2mpu02-regulator", }, |
111 | .name = "s2mpu02-regulator", | ||
112 | }, | ||
113 | }; | 94 | }; |
114 | 95 | ||
115 | #ifdef CONFIG_OF | 96 | #ifdef CONFIG_OF |
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index ad0099077e7e..a98c5d165039 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c | |||
@@ -455,6 +455,9 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) | |||
455 | case S5M8767X: | 455 | case S5M8767X: |
456 | sec_irq_chip = &s5m8767_irq_chip; | 456 | sec_irq_chip = &s5m8767_irq_chip; |
457 | break; | 457 | break; |
458 | case S2MPA01: | ||
459 | sec_irq_chip = &s2mps14_irq_chip; | ||
460 | break; | ||
458 | case S2MPS11X: | 461 | case S2MPS11X: |
459 | sec_irq_chip = &s2mps11_irq_chip; | 462 | sec_irq_chip = &s2mps11_irq_chip; |
460 | break; | 463 | break; |
diff --git a/drivers/mfd/ssbi.c b/drivers/mfd/ssbi.c index 36b96fee4ce6..0ae27cd30268 100644 --- a/drivers/mfd/ssbi.c +++ b/drivers/mfd/ssbi.c | |||
@@ -80,8 +80,6 @@ struct ssbi { | |||
80 | int (*write)(struct ssbi *, u16 addr, const u8 *buf, int len); | 80 | int (*write)(struct ssbi *, u16 addr, const u8 *buf, int len); |
81 | }; | 81 | }; |
82 | 82 | ||
83 | #define to_ssbi(dev) platform_get_drvdata(to_platform_device(dev)) | ||
84 | |||
85 | static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg) | 83 | static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg) |
86 | { | 84 | { |
87 | return readl(ssbi->base + reg); | 85 | return readl(ssbi->base + reg); |
@@ -243,7 +241,7 @@ err: | |||
243 | 241 | ||
244 | int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len) | 242 | int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len) |
245 | { | 243 | { |
246 | struct ssbi *ssbi = to_ssbi(dev); | 244 | struct ssbi *ssbi = dev_get_drvdata(dev); |
247 | unsigned long flags; | 245 | unsigned long flags; |
248 | int ret; | 246 | int ret; |
249 | 247 | ||
@@ -257,7 +255,7 @@ EXPORT_SYMBOL_GPL(ssbi_read); | |||
257 | 255 | ||
258 | int ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len) | 256 | int ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len) |
259 | { | 257 | { |
260 | struct ssbi *ssbi = to_ssbi(dev); | 258 | struct ssbi *ssbi = dev_get_drvdata(dev); |
261 | unsigned long flags; | 259 | unsigned long flags; |
262 | int ret; | 260 | int ret; |
263 | 261 | ||
diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c new file mode 100644 index 000000000000..fe8efba2d45f --- /dev/null +++ b/drivers/mfd/stmfx.c | |||
@@ -0,0 +1,545 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Driver for STMicroelectronics Multi-Function eXpander (STMFX) core | ||
4 | * | ||
5 | * Copyright (C) 2019 STMicroelectronics | ||
6 | * Author(s): Amelie Delaunay <amelie.delaunay@st.com>. | ||
7 | */ | ||
8 | #include <linux/bitfield.h> | ||
9 | #include <linux/i2c.h> | ||
10 | #include <linux/interrupt.h> | ||
11 | #include <linux/irq.h> | ||
12 | #include <linux/mfd/core.h> | ||
13 | #include <linux/mfd/stmfx.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/regulator/consumer.h> | ||
16 | |||
17 | static bool stmfx_reg_volatile(struct device *dev, unsigned int reg) | ||
18 | { | ||
19 | switch (reg) { | ||
20 | case STMFX_REG_SYS_CTRL: | ||
21 | case STMFX_REG_IRQ_SRC_EN: | ||
22 | case STMFX_REG_IRQ_PENDING: | ||
23 | case STMFX_REG_IRQ_GPI_PENDING1: | ||
24 | case STMFX_REG_IRQ_GPI_PENDING2: | ||
25 | case STMFX_REG_IRQ_GPI_PENDING3: | ||
26 | case STMFX_REG_GPIO_STATE1: | ||
27 | case STMFX_REG_GPIO_STATE2: | ||
28 | case STMFX_REG_GPIO_STATE3: | ||
29 | case STMFX_REG_IRQ_GPI_SRC1: | ||
30 | case STMFX_REG_IRQ_GPI_SRC2: | ||
31 | case STMFX_REG_IRQ_GPI_SRC3: | ||
32 | case STMFX_REG_GPO_SET1: | ||
33 | case STMFX_REG_GPO_SET2: | ||
34 | case STMFX_REG_GPO_SET3: | ||
35 | case STMFX_REG_GPO_CLR1: | ||
36 | case STMFX_REG_GPO_CLR2: | ||
37 | case STMFX_REG_GPO_CLR3: | ||
38 | return true; | ||
39 | default: | ||
40 | return false; | ||
41 | } | ||
42 | } | ||
43 | |||
44 | static bool stmfx_reg_writeable(struct device *dev, unsigned int reg) | ||
45 | { | ||
46 | return (reg >= STMFX_REG_SYS_CTRL); | ||
47 | } | ||
48 | |||
49 | static const struct regmap_config stmfx_regmap_config = { | ||
50 | .reg_bits = 8, | ||
51 | .reg_stride = 1, | ||
52 | .val_bits = 8, | ||
53 | .max_register = STMFX_REG_MAX, | ||
54 | .volatile_reg = stmfx_reg_volatile, | ||
55 | .writeable_reg = stmfx_reg_writeable, | ||
56 | .cache_type = REGCACHE_RBTREE, | ||
57 | }; | ||
58 | |||
59 | static const struct resource stmfx_pinctrl_resources[] = { | ||
60 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_GPIO), | ||
61 | }; | ||
62 | |||
63 | static const struct resource stmfx_idd_resources[] = { | ||
64 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_IDD), | ||
65 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_ERROR), | ||
66 | }; | ||
67 | |||
68 | static const struct resource stmfx_ts_resources[] = { | ||
69 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_DET), | ||
70 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_NE), | ||
71 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_TH), | ||
72 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_FULL), | ||
73 | DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_OVF), | ||
74 | }; | ||
75 | |||
76 | static struct mfd_cell stmfx_cells[] = { | ||
77 | { | ||
78 | .of_compatible = "st,stmfx-0300-pinctrl", | ||
79 | .name = "stmfx-pinctrl", | ||
80 | .resources = stmfx_pinctrl_resources, | ||
81 | .num_resources = ARRAY_SIZE(stmfx_pinctrl_resources), | ||
82 | }, | ||
83 | { | ||
84 | .of_compatible = "st,stmfx-0300-idd", | ||
85 | .name = "stmfx-idd", | ||
86 | .resources = stmfx_idd_resources, | ||
87 | .num_resources = ARRAY_SIZE(stmfx_idd_resources), | ||
88 | }, | ||
89 | { | ||
90 | .of_compatible = "st,stmfx-0300-ts", | ||
91 | .name = "stmfx-ts", | ||
92 | .resources = stmfx_ts_resources, | ||
93 | .num_resources = ARRAY_SIZE(stmfx_ts_resources), | ||
94 | }, | ||
95 | }; | ||
96 | |||
97 | static u8 stmfx_func_to_mask(u32 func) | ||
98 | { | ||
99 | u8 mask = 0; | ||
100 | |||
101 | if (func & STMFX_FUNC_GPIO) | ||
102 | mask |= STMFX_REG_SYS_CTRL_GPIO_EN; | ||
103 | |||
104 | if ((func & STMFX_FUNC_ALTGPIO_LOW) || (func & STMFX_FUNC_ALTGPIO_HIGH)) | ||
105 | mask |= STMFX_REG_SYS_CTRL_ALTGPIO_EN; | ||
106 | |||
107 | if (func & STMFX_FUNC_TS) | ||
108 | mask |= STMFX_REG_SYS_CTRL_TS_EN; | ||
109 | |||
110 | if (func & STMFX_FUNC_IDD) | ||
111 | mask |= STMFX_REG_SYS_CTRL_IDD_EN; | ||
112 | |||
113 | return mask; | ||
114 | } | ||
115 | |||
116 | int stmfx_function_enable(struct stmfx *stmfx, u32 func) | ||
117 | { | ||
118 | u32 sys_ctrl; | ||
119 | u8 mask; | ||
120 | int ret; | ||
121 | |||
122 | ret = regmap_read(stmfx->map, STMFX_REG_SYS_CTRL, &sys_ctrl); | ||
123 | if (ret) | ||
124 | return ret; | ||
125 | |||
126 | /* | ||
127 | * IDD and TS have priority in STMFX FW, so if IDD and TS are enabled, | ||
128 | * ALTGPIO function is disabled by STMFX FW. If IDD or TS is enabled, | ||
129 | * the number of aGPIO available decreases. To avoid GPIO management | ||
130 | * disturbance, abort IDD or TS function enable in this case. | ||
131 | */ | ||
132 | if (((func & STMFX_FUNC_IDD) || (func & STMFX_FUNC_TS)) && | ||
133 | (sys_ctrl & STMFX_REG_SYS_CTRL_ALTGPIO_EN)) { | ||
134 | dev_err(stmfx->dev, "ALTGPIO function already enabled\n"); | ||
135 | return -EBUSY; | ||
136 | } | ||
137 | |||
138 | /* If TS is enabled, aGPIO[3:0] cannot be used */ | ||
139 | if ((func & STMFX_FUNC_ALTGPIO_LOW) && | ||
140 | (sys_ctrl & STMFX_REG_SYS_CTRL_TS_EN)) { | ||
141 | dev_err(stmfx->dev, "TS in use, aGPIO[3:0] unavailable\n"); | ||
142 | return -EBUSY; | ||
143 | } | ||
144 | |||
145 | /* If IDD is enabled, aGPIO[7:4] cannot be used */ | ||
146 | if ((func & STMFX_FUNC_ALTGPIO_HIGH) && | ||
147 | (sys_ctrl & STMFX_REG_SYS_CTRL_IDD_EN)) { | ||
148 | dev_err(stmfx->dev, "IDD in use, aGPIO[7:4] unavailable\n"); | ||
149 | return -EBUSY; | ||
150 | } | ||
151 | |||
152 | mask = stmfx_func_to_mask(func); | ||
153 | |||
154 | return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, mask); | ||
155 | } | ||
156 | EXPORT_SYMBOL_GPL(stmfx_function_enable); | ||
157 | |||
158 | int stmfx_function_disable(struct stmfx *stmfx, u32 func) | ||
159 | { | ||
160 | u8 mask = stmfx_func_to_mask(func); | ||
161 | |||
162 | return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, 0); | ||
163 | } | ||
164 | EXPORT_SYMBOL_GPL(stmfx_function_disable); | ||
165 | |||
166 | static void stmfx_irq_bus_lock(struct irq_data *data) | ||
167 | { | ||
168 | struct stmfx *stmfx = irq_data_get_irq_chip_data(data); | ||
169 | |||
170 | mutex_lock(&stmfx->lock); | ||
171 | } | ||
172 | |||
173 | static void stmfx_irq_bus_sync_unlock(struct irq_data *data) | ||
174 | { | ||
175 | struct stmfx *stmfx = irq_data_get_irq_chip_data(data); | ||
176 | |||
177 | regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, stmfx->irq_src); | ||
178 | |||
179 | mutex_unlock(&stmfx->lock); | ||
180 | } | ||
181 | |||
182 | static void stmfx_irq_mask(struct irq_data *data) | ||
183 | { | ||
184 | struct stmfx *stmfx = irq_data_get_irq_chip_data(data); | ||
185 | |||
186 | stmfx->irq_src &= ~BIT(data->hwirq % 8); | ||
187 | } | ||
188 | |||
189 | static void stmfx_irq_unmask(struct irq_data *data) | ||
190 | { | ||
191 | struct stmfx *stmfx = irq_data_get_irq_chip_data(data); | ||
192 | |||
193 | stmfx->irq_src |= BIT(data->hwirq % 8); | ||
194 | } | ||
195 | |||
196 | static struct irq_chip stmfx_irq_chip = { | ||
197 | .name = "stmfx-core", | ||
198 | .irq_bus_lock = stmfx_irq_bus_lock, | ||
199 | .irq_bus_sync_unlock = stmfx_irq_bus_sync_unlock, | ||
200 | .irq_mask = stmfx_irq_mask, | ||
201 | .irq_unmask = stmfx_irq_unmask, | ||
202 | }; | ||
203 | |||
204 | static irqreturn_t stmfx_irq_handler(int irq, void *data) | ||
205 | { | ||
206 | struct stmfx *stmfx = data; | ||
207 | unsigned long n, pending; | ||
208 | u32 ack; | ||
209 | int ret; | ||
210 | |||
211 | ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING, | ||
212 | (u32 *)&pending); | ||
213 | if (ret) | ||
214 | return IRQ_NONE; | ||
215 | |||
216 | /* | ||
217 | * There is no ACK for GPIO, MFX_REG_IRQ_PENDING_GPIO is a logical OR | ||
218 | * of MFX_REG_IRQ_GPI _PENDING1/_PENDING2/_PENDING3 | ||
219 | */ | ||
220 | ack = pending & ~BIT(STMFX_REG_IRQ_SRC_EN_GPIO); | ||
221 | if (ack) { | ||
222 | ret = regmap_write(stmfx->map, STMFX_REG_IRQ_ACK, ack); | ||
223 | if (ret) | ||
224 | return IRQ_NONE; | ||
225 | } | ||
226 | |||
227 | for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX) | ||
228 | handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n)); | ||
229 | |||
230 | return IRQ_HANDLED; | ||
231 | } | ||
232 | |||
233 | static int stmfx_irq_map(struct irq_domain *d, unsigned int virq, | ||
234 | irq_hw_number_t hwirq) | ||
235 | { | ||
236 | irq_set_chip_data(virq, d->host_data); | ||
237 | irq_set_chip_and_handler(virq, &stmfx_irq_chip, handle_simple_irq); | ||
238 | irq_set_nested_thread(virq, 1); | ||
239 | irq_set_noprobe(virq); | ||
240 | |||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static void stmfx_irq_unmap(struct irq_domain *d, unsigned int virq) | ||
245 | { | ||
246 | irq_set_chip_and_handler(virq, NULL, NULL); | ||
247 | irq_set_chip_data(virq, NULL); | ||
248 | } | ||
249 | |||
250 | static const struct irq_domain_ops stmfx_irq_ops = { | ||
251 | .map = stmfx_irq_map, | ||
252 | .unmap = stmfx_irq_unmap, | ||
253 | }; | ||
254 | |||
255 | static void stmfx_irq_exit(struct i2c_client *client) | ||
256 | { | ||
257 | struct stmfx *stmfx = i2c_get_clientdata(client); | ||
258 | int hwirq; | ||
259 | |||
260 | for (hwirq = 0; hwirq < STMFX_REG_IRQ_SRC_MAX; hwirq++) | ||
261 | irq_dispose_mapping(irq_find_mapping(stmfx->irq_domain, hwirq)); | ||
262 | |||
263 | irq_domain_remove(stmfx->irq_domain); | ||
264 | } | ||
265 | |||
266 | static int stmfx_irq_init(struct i2c_client *client) | ||
267 | { | ||
268 | struct stmfx *stmfx = i2c_get_clientdata(client); | ||
269 | u32 irqoutpin = 0, irqtrigger; | ||
270 | int ret; | ||
271 | |||
272 | stmfx->irq_domain = irq_domain_add_simple(stmfx->dev->of_node, | ||
273 | STMFX_REG_IRQ_SRC_MAX, 0, | ||
274 | &stmfx_irq_ops, stmfx); | ||
275 | if (!stmfx->irq_domain) { | ||
276 | dev_err(stmfx->dev, "Failed to create IRQ domain\n"); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | if (!of_property_read_bool(stmfx->dev->of_node, "drive-open-drain")) | ||
281 | irqoutpin |= STMFX_REG_IRQ_OUT_PIN_TYPE; | ||
282 | |||
283 | irqtrigger = irq_get_trigger_type(client->irq); | ||
284 | if ((irqtrigger & IRQ_TYPE_EDGE_RISING) || | ||
285 | (irqtrigger & IRQ_TYPE_LEVEL_HIGH)) | ||
286 | irqoutpin |= STMFX_REG_IRQ_OUT_PIN_POL; | ||
287 | |||
288 | ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | ret = devm_request_threaded_irq(stmfx->dev, client->irq, | ||
293 | NULL, stmfx_irq_handler, | ||
294 | irqtrigger | IRQF_ONESHOT, | ||
295 | "stmfx", stmfx); | ||
296 | if (ret) | ||
297 | stmfx_irq_exit(client); | ||
298 | |||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | static int stmfx_chip_reset(struct stmfx *stmfx) | ||
303 | { | ||
304 | int ret; | ||
305 | |||
306 | ret = regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, | ||
307 | STMFX_REG_SYS_CTRL_SWRST); | ||
308 | if (ret) | ||
309 | return ret; | ||
310 | |||
311 | msleep(STMFX_BOOT_TIME_MS); | ||
312 | |||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | static int stmfx_chip_init(struct i2c_client *client) | ||
317 | { | ||
318 | struct stmfx *stmfx = i2c_get_clientdata(client); | ||
319 | u32 id; | ||
320 | u8 version[2]; | ||
321 | int ret; | ||
322 | |||
323 | stmfx->vdd = devm_regulator_get_optional(&client->dev, "vdd"); | ||
324 | ret = PTR_ERR_OR_ZERO(stmfx->vdd); | ||
325 | if (ret == -ENODEV) { | ||
326 | stmfx->vdd = NULL; | ||
327 | } else if (ret == -EPROBE_DEFER) { | ||
328 | return ret; | ||
329 | } else if (ret) { | ||
330 | dev_err(&client->dev, "Failed to get VDD regulator: %d\n", ret); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | if (stmfx->vdd) { | ||
335 | ret = regulator_enable(stmfx->vdd); | ||
336 | if (ret) { | ||
337 | dev_err(&client->dev, "VDD enable failed: %d\n", ret); | ||
338 | return ret; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | ret = regmap_read(stmfx->map, STMFX_REG_CHIP_ID, &id); | ||
343 | if (ret) { | ||
344 | dev_err(&client->dev, "Error reading chip ID: %d\n", ret); | ||
345 | goto err; | ||
346 | } | ||
347 | |||
348 | /* | ||
349 | * Check that ID is the complement of the I2C address: | ||
350 | * STMFX I2C address follows the 7-bit format (MSB), that's why | ||
351 | * client->addr is shifted. | ||
352 | * | ||
353 | * STMFX_I2C_ADDR| STMFX | Linux | ||
354 | * input pin | I2C device address | I2C device address | ||
355 | *--------------------------------------------------------- | ||
356 | * 0 | b: 1000 010x h:0x84 | 0x42 | ||
357 | * 1 | b: 1000 011x h:0x86 | 0x43 | ||
358 | */ | ||
359 | if (FIELD_GET(STMFX_REG_CHIP_ID_MASK, ~id) != (client->addr << 1)) { | ||
360 | dev_err(&client->dev, "Unknown chip ID: %#x\n", id); | ||
361 | ret = -EINVAL; | ||
362 | goto err; | ||
363 | } | ||
364 | |||
365 | ret = regmap_bulk_read(stmfx->map, STMFX_REG_FW_VERSION_MSB, | ||
366 | version, ARRAY_SIZE(version)); | ||
367 | if (ret) { | ||
368 | dev_err(&client->dev, "Error reading FW version: %d\n", ret); | ||
369 | goto err; | ||
370 | } | ||
371 | |||
372 | dev_info(&client->dev, "STMFX id: %#x, fw version: %x.%02x\n", | ||
373 | id, version[0], version[1]); | ||
374 | |||
375 | ret = stmfx_chip_reset(stmfx); | ||
376 | if (ret) { | ||
377 | dev_err(&client->dev, "Failed to reset chip: %d\n", ret); | ||
378 | goto err; | ||
379 | } | ||
380 | |||
381 | return 0; | ||
382 | |||
383 | err: | ||
384 | if (stmfx->vdd) | ||
385 | return regulator_disable(stmfx->vdd); | ||
386 | |||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | static int stmfx_chip_exit(struct i2c_client *client) | ||
391 | { | ||
392 | struct stmfx *stmfx = i2c_get_clientdata(client); | ||
393 | |||
394 | regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, 0); | ||
395 | regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, 0); | ||
396 | |||
397 | if (stmfx->vdd) | ||
398 | return regulator_disable(stmfx->vdd); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int stmfx_probe(struct i2c_client *client, | ||
404 | const struct i2c_device_id *id) | ||
405 | { | ||
406 | struct device *dev = &client->dev; | ||
407 | struct stmfx *stmfx; | ||
408 | int ret; | ||
409 | |||
410 | stmfx = devm_kzalloc(dev, sizeof(*stmfx), GFP_KERNEL); | ||
411 | if (!stmfx) | ||
412 | return -ENOMEM; | ||
413 | |||
414 | i2c_set_clientdata(client, stmfx); | ||
415 | |||
416 | stmfx->dev = dev; | ||
417 | |||
418 | stmfx->map = devm_regmap_init_i2c(client, &stmfx_regmap_config); | ||
419 | if (IS_ERR(stmfx->map)) { | ||
420 | ret = PTR_ERR(stmfx->map); | ||
421 | dev_err(dev, "Failed to allocate register map: %d\n", ret); | ||
422 | return ret; | ||
423 | } | ||
424 | |||
425 | mutex_init(&stmfx->lock); | ||
426 | |||
427 | ret = stmfx_chip_init(client); | ||
428 | if (ret) { | ||
429 | if (ret == -ETIMEDOUT) | ||
430 | return -EPROBE_DEFER; | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | if (client->irq < 0) { | ||
435 | dev_err(dev, "Failed to get IRQ: %d\n", client->irq); | ||
436 | ret = client->irq; | ||
437 | goto err_chip_exit; | ||
438 | } | ||
439 | |||
440 | ret = stmfx_irq_init(client); | ||
441 | if (ret) | ||
442 | goto err_chip_exit; | ||
443 | |||
444 | ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE, | ||
445 | stmfx_cells, ARRAY_SIZE(stmfx_cells), NULL, | ||
446 | 0, stmfx->irq_domain); | ||
447 | if (ret) | ||
448 | goto err_irq_exit; | ||
449 | |||
450 | return 0; | ||
451 | |||
452 | err_irq_exit: | ||
453 | stmfx_irq_exit(client); | ||
454 | err_chip_exit: | ||
455 | stmfx_chip_exit(client); | ||
456 | |||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | static int stmfx_remove(struct i2c_client *client) | ||
461 | { | ||
462 | stmfx_irq_exit(client); | ||
463 | |||
464 | return stmfx_chip_exit(client); | ||
465 | } | ||
466 | |||
467 | #ifdef CONFIG_PM_SLEEP | ||
468 | static int stmfx_suspend(struct device *dev) | ||
469 | { | ||
470 | struct stmfx *stmfx = dev_get_drvdata(dev); | ||
471 | int ret; | ||
472 | |||
473 | ret = regmap_raw_read(stmfx->map, STMFX_REG_SYS_CTRL, | ||
474 | &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); | ||
475 | if (ret) | ||
476 | return ret; | ||
477 | |||
478 | ret = regmap_raw_read(stmfx->map, STMFX_REG_IRQ_OUT_PIN, | ||
479 | &stmfx->bkp_irqoutpin, | ||
480 | sizeof(stmfx->bkp_irqoutpin)); | ||
481 | if (ret) | ||
482 | return ret; | ||
483 | |||
484 | if (stmfx->vdd) | ||
485 | return regulator_disable(stmfx->vdd); | ||
486 | |||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static int stmfx_resume(struct device *dev) | ||
491 | { | ||
492 | struct stmfx *stmfx = dev_get_drvdata(dev); | ||
493 | int ret; | ||
494 | |||
495 | if (stmfx->vdd) { | ||
496 | ret = regulator_enable(stmfx->vdd); | ||
497 | if (ret) { | ||
498 | dev_err(stmfx->dev, | ||
499 | "VDD enable failed: %d\n", ret); | ||
500 | return ret; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL, | ||
505 | &stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl)); | ||
506 | if (ret) | ||
507 | return ret; | ||
508 | |||
509 | ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, | ||
510 | &stmfx->bkp_irqoutpin, | ||
511 | sizeof(stmfx->bkp_irqoutpin)); | ||
512 | if (ret) | ||
513 | return ret; | ||
514 | |||
515 | ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, | ||
516 | &stmfx->irq_src, sizeof(stmfx->irq_src)); | ||
517 | if (ret) | ||
518 | return ret; | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | #endif | ||
523 | |||
524 | static SIMPLE_DEV_PM_OPS(stmfx_dev_pm_ops, stmfx_suspend, stmfx_resume); | ||
525 | |||
526 | static const struct of_device_id stmfx_of_match[] = { | ||
527 | { .compatible = "st,stmfx-0300", }, | ||
528 | {}, | ||
529 | }; | ||
530 | MODULE_DEVICE_TABLE(of, stmfx_of_match); | ||
531 | |||
532 | static struct i2c_driver stmfx_driver = { | ||
533 | .driver = { | ||
534 | .name = "stmfx-core", | ||
535 | .of_match_table = of_match_ptr(stmfx_of_match), | ||
536 | .pm = &stmfx_dev_pm_ops, | ||
537 | }, | ||
538 | .probe = stmfx_probe, | ||
539 | .remove = stmfx_remove, | ||
540 | }; | ||
541 | module_i2c_driver(stmfx_driver); | ||
542 | |||
543 | MODULE_DESCRIPTION("STMFX core driver"); | ||
544 | MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>"); | ||
545 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c index 2b658bed47db..2f12a415b807 100644 --- a/drivers/mfd/sun6i-prcm.c +++ b/drivers/mfd/sun6i-prcm.c | |||
@@ -148,13 +148,12 @@ static const struct of_device_id sun6i_prcm_dt_ids[] = { | |||
148 | 148 | ||
149 | static int sun6i_prcm_probe(struct platform_device *pdev) | 149 | static int sun6i_prcm_probe(struct platform_device *pdev) |
150 | { | 150 | { |
151 | struct device_node *np = pdev->dev.of_node; | ||
152 | const struct of_device_id *match; | 151 | const struct of_device_id *match; |
153 | const struct prcm_data *data; | 152 | const struct prcm_data *data; |
154 | struct resource *res; | 153 | struct resource *res; |
155 | int ret; | 154 | int ret; |
156 | 155 | ||
157 | match = of_match_node(sun6i_prcm_dt_ids, np); | 156 | match = of_match_node(sun6i_prcm_dt_ids, pdev->dev.of_node); |
158 | if (!match) | 157 | if (!match) |
159 | return -EINVAL; | 158 | return -EINVAL; |
160 | 159 | ||
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 0ecdffb3d967..f6922a0f8058 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/clk.h> | ||
15 | #include <linux/err.h> | 16 | #include <linux/err.h> |
16 | #include <linux/hwspinlock.h> | 17 | #include <linux/hwspinlock.h> |
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
@@ -45,6 +46,7 @@ static const struct regmap_config syscon_regmap_config = { | |||
45 | 46 | ||
46 | static struct syscon *of_syscon_register(struct device_node *np) | 47 | static struct syscon *of_syscon_register(struct device_node *np) |
47 | { | 48 | { |
49 | struct clk *clk; | ||
48 | struct syscon *syscon; | 50 | struct syscon *syscon; |
49 | struct regmap *regmap; | 51 | struct regmap *regmap; |
50 | void __iomem *base; | 52 | void __iomem *base; |
@@ -119,6 +121,18 @@ static struct syscon *of_syscon_register(struct device_node *np) | |||
119 | goto err_regmap; | 121 | goto err_regmap; |
120 | } | 122 | } |
121 | 123 | ||
124 | clk = of_clk_get(np, 0); | ||
125 | if (IS_ERR(clk)) { | ||
126 | ret = PTR_ERR(clk); | ||
127 | /* clock is optional */ | ||
128 | if (ret != -ENOENT) | ||
129 | goto err_clk; | ||
130 | } else { | ||
131 | ret = regmap_mmio_attach_clk(regmap, clk); | ||
132 | if (ret) | ||
133 | goto err_attach; | ||
134 | } | ||
135 | |||
122 | syscon->regmap = regmap; | 136 | syscon->regmap = regmap; |
123 | syscon->np = np; | 137 | syscon->np = np; |
124 | 138 | ||
@@ -128,6 +142,11 @@ static struct syscon *of_syscon_register(struct device_node *np) | |||
128 | 142 | ||
129 | return syscon; | 143 | return syscon; |
130 | 144 | ||
145 | err_attach: | ||
146 | if (!IS_ERR(clk)) | ||
147 | clk_put(clk); | ||
148 | err_clk: | ||
149 | regmap_exit(regmap); | ||
131 | err_regmap: | 150 | err_regmap: |
132 | iounmap(base); | 151 | iounmap(base); |
133 | err_map: | 152 | err_map: |
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 43d8683266de..e9cfb147345e 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c | |||
@@ -82,8 +82,7 @@ struct t7l66xb { | |||
82 | 82 | ||
83 | static int t7l66xb_mmc_enable(struct platform_device *mmc) | 83 | static int t7l66xb_mmc_enable(struct platform_device *mmc) |
84 | { | 84 | { |
85 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 85 | struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); |
86 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
87 | unsigned long flags; | 86 | unsigned long flags; |
88 | u8 dev_ctl; | 87 | u8 dev_ctl; |
89 | int ret; | 88 | int ret; |
@@ -108,8 +107,7 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc) | |||
108 | 107 | ||
109 | static int t7l66xb_mmc_disable(struct platform_device *mmc) | 108 | static int t7l66xb_mmc_disable(struct platform_device *mmc) |
110 | { | 109 | { |
111 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 110 | struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); |
112 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
113 | unsigned long flags; | 111 | unsigned long flags; |
114 | u8 dev_ctl; | 112 | u8 dev_ctl; |
115 | 113 | ||
@@ -128,16 +126,14 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc) | |||
128 | 126 | ||
129 | static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state) | 127 | static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state) |
130 | { | 128 | { |
131 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 129 | struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); |
132 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
133 | 130 | ||
134 | tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state); | 131 | tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state); |
135 | } | 132 | } |
136 | 133 | ||
137 | static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state) | 134 | static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state) |
138 | { | 135 | { |
139 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 136 | struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent); |
140 | struct t7l66xb *t7l66xb = platform_get_drvdata(dev); | ||
141 | 137 | ||
142 | tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state); | 138 | tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state); |
143 | } | 139 | } |
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 85fab3729102..f417c6fecfe2 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c | |||
@@ -80,16 +80,14 @@ static int tc6387xb_resume(struct platform_device *dev) | |||
80 | 80 | ||
81 | static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state) | 81 | static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state) |
82 | { | 82 | { |
83 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 83 | struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); |
84 | struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | ||
85 | 84 | ||
86 | tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state); | 85 | tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state); |
87 | } | 86 | } |
88 | 87 | ||
89 | static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state) | 88 | static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state) |
90 | { | 89 | { |
91 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 90 | struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); |
92 | struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | ||
93 | 91 | ||
94 | tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state); | 92 | tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state); |
95 | } | 93 | } |
@@ -97,8 +95,7 @@ static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state) | |||
97 | 95 | ||
98 | static int tc6387xb_mmc_enable(struct platform_device *mmc) | 96 | static int tc6387xb_mmc_enable(struct platform_device *mmc) |
99 | { | 97 | { |
100 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 98 | struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); |
101 | struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | ||
102 | 99 | ||
103 | clk_prepare_enable(tc6387xb->clk32k); | 100 | clk_prepare_enable(tc6387xb->clk32k); |
104 | 101 | ||
@@ -110,8 +107,7 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc) | |||
110 | 107 | ||
111 | static int tc6387xb_mmc_disable(struct platform_device *mmc) | 108 | static int tc6387xb_mmc_disable(struct platform_device *mmc) |
112 | { | 109 | { |
113 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 110 | struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent); |
114 | struct tc6387xb *tc6387xb = platform_get_drvdata(dev); | ||
115 | 111 | ||
116 | clk_disable_unprepare(tc6387xb->clk32k); | 112 | clk_disable_unprepare(tc6387xb->clk32k); |
117 | 113 | ||
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 0c9f0390e891..6943048a64c2 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c | |||
@@ -122,14 +122,13 @@ enum { | |||
122 | 122 | ||
123 | static int tc6393xb_nand_enable(struct platform_device *nand) | 123 | static int tc6393xb_nand_enable(struct platform_device *nand) |
124 | { | 124 | { |
125 | struct platform_device *dev = to_platform_device(nand->dev.parent); | 125 | struct tc6393xb *tc6393xb = dev_get_drvdata(nand->dev.parent); |
126 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
127 | unsigned long flags; | 126 | unsigned long flags; |
128 | 127 | ||
129 | raw_spin_lock_irqsave(&tc6393xb->lock, flags); | 128 | raw_spin_lock_irqsave(&tc6393xb->lock, flags); |
130 | 129 | ||
131 | /* SMD buffer on */ | 130 | /* SMD buffer on */ |
132 | dev_dbg(&dev->dev, "SMD buffer on\n"); | 131 | dev_dbg(nand->dev.parent, "SMD buffer on\n"); |
133 | tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); | 132 | tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1)); |
134 | 133 | ||
135 | raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); | 134 | raw_spin_unlock_irqrestore(&tc6393xb->lock, flags); |
@@ -312,8 +311,7 @@ static int tc6393xb_fb_disable(struct platform_device *dev) | |||
312 | 311 | ||
313 | int tc6393xb_lcd_set_power(struct platform_device *fb, bool on) | 312 | int tc6393xb_lcd_set_power(struct platform_device *fb, bool on) |
314 | { | 313 | { |
315 | struct platform_device *dev = to_platform_device(fb->dev.parent); | 314 | struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent); |
316 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
317 | u8 fer; | 315 | u8 fer; |
318 | unsigned long flags; | 316 | unsigned long flags; |
319 | 317 | ||
@@ -334,8 +332,7 @@ EXPORT_SYMBOL(tc6393xb_lcd_set_power); | |||
334 | 332 | ||
335 | int tc6393xb_lcd_mode(struct platform_device *fb, | 333 | int tc6393xb_lcd_mode(struct platform_device *fb, |
336 | const struct fb_videomode *mode) { | 334 | const struct fb_videomode *mode) { |
337 | struct platform_device *dev = to_platform_device(fb->dev.parent); | 335 | struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent); |
338 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
339 | unsigned long flags; | 336 | unsigned long flags; |
340 | 337 | ||
341 | raw_spin_lock_irqsave(&tc6393xb->lock, flags); | 338 | raw_spin_lock_irqsave(&tc6393xb->lock, flags); |
@@ -351,8 +348,7 @@ EXPORT_SYMBOL(tc6393xb_lcd_mode); | |||
351 | 348 | ||
352 | static int tc6393xb_mmc_enable(struct platform_device *mmc) | 349 | static int tc6393xb_mmc_enable(struct platform_device *mmc) |
353 | { | 350 | { |
354 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 351 | struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); |
355 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
356 | 352 | ||
357 | tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0, | 353 | tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0, |
358 | tc6393xb_mmc_resources[0].start & 0xfffe); | 354 | tc6393xb_mmc_resources[0].start & 0xfffe); |
@@ -362,8 +358,7 @@ static int tc6393xb_mmc_enable(struct platform_device *mmc) | |||
362 | 358 | ||
363 | static int tc6393xb_mmc_resume(struct platform_device *mmc) | 359 | static int tc6393xb_mmc_resume(struct platform_device *mmc) |
364 | { | 360 | { |
365 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 361 | struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); |
366 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
367 | 362 | ||
368 | tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0, | 363 | tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0, |
369 | tc6393xb_mmc_resources[0].start & 0xfffe); | 364 | tc6393xb_mmc_resources[0].start & 0xfffe); |
@@ -373,16 +368,14 @@ static int tc6393xb_mmc_resume(struct platform_device *mmc) | |||
373 | 368 | ||
374 | static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state) | 369 | static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state) |
375 | { | 370 | { |
376 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 371 | struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); |
377 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
378 | 372 | ||
379 | tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state); | 373 | tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state); |
380 | } | 374 | } |
381 | 375 | ||
382 | static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state) | 376 | static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state) |
383 | { | 377 | { |
384 | struct platform_device *dev = to_platform_device(mmc->dev.parent); | 378 | struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent); |
385 | struct tc6393xb *tc6393xb = platform_get_drvdata(dev); | ||
386 | 379 | ||
387 | tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state); | 380 | tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state); |
388 | } | 381 | } |
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index 3bd75061f777..f78be039e463 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c | |||
@@ -27,6 +27,7 @@ static const struct of_device_id tps65912_spi_of_match_table[] = { | |||
27 | { .compatible = "ti,tps65912", }, | 27 | { .compatible = "ti,tps65912", }, |
28 | { /* sentinel */ } | 28 | { /* sentinel */ } |
29 | }; | 29 | }; |
30 | MODULE_DEVICE_TABLE(of, tps65912_spi_of_match_table); | ||
30 | 31 | ||
31 | static int tps65912_spi_probe(struct spi_device *spi) | 32 | static int tps65912_spi_probe(struct spi_device *spi) |
32 | { | 33 | { |
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 7c3c5fd5fcd0..86052c5c6069 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c | |||
@@ -322,8 +322,19 @@ int twl6040_power(struct twl6040 *twl6040, int on) | |||
322 | } | 322 | } |
323 | } | 323 | } |
324 | 324 | ||
325 | /* | ||
326 | * Register access can produce errors after power-up unless we | ||
327 | * wait at least 8ms based on measurements on duovero. | ||
328 | */ | ||
329 | usleep_range(10000, 12000); | ||
330 | |||
325 | /* Sync with the HW */ | 331 | /* Sync with the HW */ |
326 | regcache_sync(twl6040->regmap); | 332 | ret = regcache_sync(twl6040->regmap); |
333 | if (ret) { | ||
334 | dev_err(twl6040->dev, "Failed to sync with the HW: %i\n", | ||
335 | ret); | ||
336 | goto out; | ||
337 | } | ||
327 | 338 | ||
328 | /* Default PLL configuration after power up */ | 339 | /* Default PLL configuration after power up */ |
329 | twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; | 340 | twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; |