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 | |
| 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
...
79 files changed, 3745 insertions, 219 deletions
diff --git a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt index f4d04a067282..82edbaaa3f85 100644 --- a/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt +++ b/Documentation/devicetree/bindings/arm/altera/socfpga-system.txt | |||
| @@ -11,3 +11,15 @@ Example: | |||
| 11 | reg = <0xffd08000 0x1000>; | 11 | reg = <0xffd08000 0x1000>; |
| 12 | cpu1-start-addr = <0xffd080c4>; | 12 | cpu1-start-addr = <0xffd080c4>; |
| 13 | }; | 13 | }; |
| 14 | |||
| 15 | ARM64 - Stratix10 | ||
| 16 | Required properties: | ||
| 17 | - compatible : "altr,sys-mgr-s10" | ||
| 18 | - reg : Should contain 1 register range(address and length) | ||
| 19 | for system manager register. | ||
| 20 | |||
| 21 | Example: | ||
| 22 | sysmgr@ffd12000 { | ||
| 23 | compatible = "altr,sys-mgr-s10"; | ||
| 24 | reg = <0xffd12000 0x228>; | ||
| 25 | }; | ||
diff --git a/Documentation/devicetree/bindings/arm/stm32/stm32-syscon.txt b/Documentation/devicetree/bindings/arm/stm32/stm32-syscon.txt index 99980aee26e5..c92d411fd023 100644 --- a/Documentation/devicetree/bindings/arm/stm32/stm32-syscon.txt +++ b/Documentation/devicetree/bindings/arm/stm32/stm32-syscon.txt | |||
| @@ -5,10 +5,12 @@ Properties: | |||
| 5 | - " st,stm32mp157-syscfg " - for stm32mp157 based SoCs, | 5 | - " st,stm32mp157-syscfg " - for stm32mp157 based SoCs, |
| 6 | second value must be always "syscon". | 6 | second value must be always "syscon". |
| 7 | - reg : offset and length of the register set. | 7 | - reg : offset and length of the register set. |
| 8 | - clocks: phandle to the syscfg clock | ||
| 8 | 9 | ||
| 9 | Example: | 10 | Example: |
| 10 | syscfg: syscon@50020000 { | 11 | syscfg: syscon@50020000 { |
| 11 | compatible = "st,stm32mp157-syscfg", "syscon"; | 12 | compatible = "st,stm32mp157-syscfg", "syscon"; |
| 12 | reg = <0x50020000 0x400>; | 13 | reg = <0x50020000 0x400>; |
| 14 | clocks = <&rcc SYSCFG>; | ||
| 13 | }; | 15 | }; |
| 14 | 16 | ||
diff --git a/Documentation/devicetree/bindings/input/max77650-onkey.txt b/Documentation/devicetree/bindings/input/max77650-onkey.txt new file mode 100644 index 000000000000..477dc74f452a --- /dev/null +++ b/Documentation/devicetree/bindings/input/max77650-onkey.txt | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | Onkey driver for MAX77650 PMIC from Maxim Integrated. | ||
| 2 | |||
| 3 | This module is part of the MAX77650 MFD device. For more details | ||
| 4 | see Documentation/devicetree/bindings/mfd/max77650.txt. | ||
| 5 | |||
| 6 | The onkey controller is represented as a sub-node of the PMIC node on | ||
| 7 | the device tree. | ||
| 8 | |||
| 9 | Required properties: | ||
| 10 | -------------------- | ||
| 11 | - compatible: Must be "maxim,max77650-onkey". | ||
| 12 | |||
| 13 | Optional properties: | ||
| 14 | - linux,code: The key-code to be reported when the key is pressed. | ||
| 15 | Defaults to KEY_POWER. | ||
| 16 | - maxim,onkey-slide: The system's button is a slide switch, not the default | ||
| 17 | push button. | ||
| 18 | |||
| 19 | Example: | ||
| 20 | -------- | ||
| 21 | |||
| 22 | onkey { | ||
| 23 | compatible = "maxim,max77650-onkey"; | ||
| 24 | linux,code = <KEY_END>; | ||
| 25 | maxim,onkey-slide; | ||
| 26 | }; | ||
diff --git a/Documentation/devicetree/bindings/leds/leds-max77650.txt b/Documentation/devicetree/bindings/leds/leds-max77650.txt new file mode 100644 index 000000000000..3a67115cc1da --- /dev/null +++ b/Documentation/devicetree/bindings/leds/leds-max77650.txt | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | LED driver for MAX77650 PMIC from Maxim Integrated. | ||
| 2 | |||
| 3 | This module is part of the MAX77650 MFD device. For more details | ||
| 4 | see Documentation/devicetree/bindings/mfd/max77650.txt. | ||
| 5 | |||
| 6 | The LED controller is represented as a sub-node of the PMIC node on | ||
| 7 | the device tree. | ||
| 8 | |||
| 9 | This device has three current sinks. | ||
| 10 | |||
| 11 | Required properties: | ||
| 12 | -------------------- | ||
| 13 | - compatible: Must be "maxim,max77650-led" | ||
| 14 | - #address-cells: Must be <1>. | ||
| 15 | - #size-cells: Must be <0>. | ||
| 16 | |||
| 17 | Each LED is represented as a sub-node of the LED-controller node. Up to | ||
| 18 | three sub-nodes can be defined. | ||
| 19 | |||
| 20 | Required properties of the sub-node: | ||
| 21 | ------------------------------------ | ||
| 22 | |||
| 23 | - reg: Must be <0>, <1> or <2>. | ||
| 24 | |||
| 25 | Optional properties of the sub-node: | ||
| 26 | ------------------------------------ | ||
| 27 | |||
| 28 | - label: See Documentation/devicetree/bindings/leds/common.txt | ||
| 29 | - linux,default-trigger: See Documentation/devicetree/bindings/leds/common.txt | ||
| 30 | |||
| 31 | For more details, please refer to the generic GPIO DT binding document | ||
| 32 | <devicetree/bindings/gpio/gpio.txt>. | ||
| 33 | |||
| 34 | Example: | ||
| 35 | -------- | ||
| 36 | |||
| 37 | leds { | ||
| 38 | compatible = "maxim,max77650-led"; | ||
| 39 | #address-cells = <1>; | ||
| 40 | #size-cells = <0>; | ||
| 41 | |||
| 42 | led@0 { | ||
| 43 | reg = <0>; | ||
| 44 | label = "blue:usr0"; | ||
| 45 | }; | ||
| 46 | |||
| 47 | led@1 { | ||
| 48 | reg = <1>; | ||
| 49 | label = "red:usr1"; | ||
| 50 | linux,default-trigger = "heartbeat"; | ||
| 51 | }; | ||
| 52 | |||
| 53 | led@2 { | ||
| 54 | reg = <2>; | ||
| 55 | label = "green:usr2"; | ||
| 56 | }; | ||
| 57 | }; | ||
diff --git a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt index 3f643ef121ff..5f8880cc757e 100644 --- a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt +++ b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt | |||
| @@ -7,6 +7,7 @@ Required properties: | |||
| 7 | "atmel,sama5d2-hlcdc" | 7 | "atmel,sama5d2-hlcdc" |
| 8 | "atmel,sama5d3-hlcdc" | 8 | "atmel,sama5d3-hlcdc" |
| 9 | "atmel,sama5d4-hlcdc" | 9 | "atmel,sama5d4-hlcdc" |
| 10 | "microchip,sam9x60-hlcdc" | ||
| 10 | - reg: base address and size of the HLCDC device registers. | 11 | - reg: base address and size of the HLCDC device registers. |
| 11 | - clock-names: the name of the 3 clocks requested by the HLCDC device. | 12 | - clock-names: the name of the 3 clocks requested by the HLCDC device. |
| 12 | Should contain "periph_clk", "sys_clk" and "slow_clk". | 13 | Should contain "periph_clk", "sys_clk" and "slow_clk". |
diff --git a/Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt b/Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt index 004b0158cf4d..3bf92ad37fa1 100644 --- a/Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt +++ b/Documentation/devicetree/bindings/mfd/cirrus,lochnagar.txt | |||
| @@ -19,6 +19,8 @@ And these documents for the required sub-node binding details: | |||
| 19 | [4] Clock: ../clock/cirrus,lochnagar.txt | 19 | [4] Clock: ../clock/cirrus,lochnagar.txt |
| 20 | [5] Pinctrl: ../pinctrl/cirrus,lochnagar.txt | 20 | [5] Pinctrl: ../pinctrl/cirrus,lochnagar.txt |
| 21 | [6] Regulator: ../regulator/cirrus,lochnagar.txt | 21 | [6] Regulator: ../regulator/cirrus,lochnagar.txt |
| 22 | [7] Sound: ../sound/cirrus,lochnagar.txt | ||
| 23 | [8] Hardware Monitor: ../hwmon/cirrus,lochnagar.txt | ||
| 22 | 24 | ||
| 23 | Required properties: | 25 | Required properties: |
| 24 | 26 | ||
| @@ -41,6 +43,11 @@ Optional sub-nodes: | |||
| 41 | - Bindings for the regulator components, see [6]. Only available on | 43 | - Bindings for the regulator components, see [6]. Only available on |
| 42 | Lochnagar 2. | 44 | Lochnagar 2. |
| 43 | 45 | ||
| 46 | - lochnagar-sc : Binding for the sound card components, see [7]. | ||
| 47 | Only available on Lochnagar 2. | ||
| 48 | - lochnagar-hwmon : Binding for the hardware monitor components, see [8]. | ||
| 49 | Only available on Lochnagar 2. | ||
| 50 | |||
| 44 | Optional properties: | 51 | Optional properties: |
| 45 | 52 | ||
| 46 | - present-gpios : Host present line, indicating the presence of a | 53 | - present-gpios : Host present line, indicating the presence of a |
| @@ -65,4 +72,14 @@ lochnagar: lochnagar@22 { | |||
| 65 | compatible = "cirrus,lochnagar-pinctrl"; | 72 | compatible = "cirrus,lochnagar-pinctrl"; |
| 66 | ... | 73 | ... |
| 67 | }; | 74 | }; |
| 75 | |||
| 76 | lochnagar-sc { | ||
| 77 | compatible = "cirrus,lochnagar2-soundcard"; | ||
| 78 | ... | ||
| 79 | }; | ||
| 80 | |||
| 81 | lochnagar-hwmon { | ||
| 82 | compatible = "cirrus,lochnagar2-hwmon"; | ||
| 83 | ... | ||
| 84 | }; | ||
| 68 | }; | 85 | }; |
diff --git a/Documentation/devicetree/bindings/mfd/max77620.txt b/Documentation/devicetree/bindings/mfd/max77620.txt index 9c16d51cc15b..5a642a51d58e 100644 --- a/Documentation/devicetree/bindings/mfd/max77620.txt +++ b/Documentation/devicetree/bindings/mfd/max77620.txt | |||
| @@ -4,7 +4,8 @@ Required properties: | |||
| 4 | ------------------- | 4 | ------------------- |
| 5 | - compatible: Must be one of | 5 | - compatible: Must be one of |
| 6 | "maxim,max77620" | 6 | "maxim,max77620" |
| 7 | "maxim,max20024". | 7 | "maxim,max20024" |
| 8 | "maxim,max77663" | ||
| 8 | - reg: I2C device address. | 9 | - reg: I2C device address. |
| 9 | 10 | ||
| 10 | Optional properties: | 11 | Optional properties: |
| @@ -17,6 +18,11 @@ Optional properties: | |||
| 17 | IRQ numbers for different interrupt source of MAX77620 | 18 | IRQ numbers for different interrupt source of MAX77620 |
| 18 | are defined at dt-bindings/mfd/max77620.h. | 19 | are defined at dt-bindings/mfd/max77620.h. |
| 19 | 20 | ||
| 21 | - system-power-controller: Indicates that this PMIC is controlling the | ||
| 22 | system power, see [1] for more details. | ||
| 23 | |||
| 24 | [1] Documentation/devicetree/bindings/power/power-controller.txt | ||
| 25 | |||
| 20 | Optional subnodes and their properties: | 26 | Optional subnodes and their properties: |
| 21 | ======================================= | 27 | ======================================= |
| 22 | 28 | ||
| @@ -105,6 +111,7 @@ Optional properties: | |||
| 105 | Here supported time periods by device in microseconds are as follows: | 111 | Here supported time periods by device in microseconds are as follows: |
| 106 | MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds. | 112 | MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds. |
| 107 | MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds. | 113 | MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds. |
| 114 | MAX77663 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds. | ||
| 108 | 115 | ||
| 109 | -maxim,power-ok-control: configure map power ok bit | 116 | -maxim,power-ok-control: configure map power ok bit |
| 110 | 1: Enables POK(Power OK) to control nRST_IO and GPIO1 | 117 | 1: Enables POK(Power OK) to control nRST_IO and GPIO1 |
diff --git a/Documentation/devicetree/bindings/mfd/max77650.txt b/Documentation/devicetree/bindings/mfd/max77650.txt new file mode 100644 index 000000000000..b529d8d19335 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/max77650.txt | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | MAX77650 ultra low-power PMIC from Maxim Integrated. | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | ------------------- | ||
| 5 | - compatible: Must be "maxim,max77650" | ||
| 6 | - reg: I2C device address. | ||
| 7 | - interrupts: The interrupt on the parent the controller is | ||
| 8 | connected to. | ||
| 9 | - interrupt-controller: Marks the device node as an interrupt controller. | ||
| 10 | - #interrupt-cells: Must be <2>. | ||
| 11 | |||
| 12 | - gpio-controller: Marks the device node as a gpio controller. | ||
| 13 | - #gpio-cells: Must be <2>. The first cell is the pin number and | ||
| 14 | the second cell is used to specify the gpio active | ||
| 15 | state. | ||
| 16 | |||
| 17 | Optional properties: | ||
| 18 | -------------------- | ||
| 19 | gpio-line-names: Single string containing the name of the GPIO line. | ||
| 20 | |||
| 21 | The GPIO-controller module is represented as part of the top-level PMIC | ||
| 22 | node. The device exposes a single GPIO line. | ||
| 23 | |||
| 24 | For device-tree bindings of other sub-modules (regulator, power supply, | ||
| 25 | LEDs and onkey) refer to the binding documents under the respective | ||
| 26 | sub-system directories. | ||
| 27 | |||
| 28 | For more details on GPIO bindings, please refer to the generic GPIO DT | ||
| 29 | binding document <devicetree/bindings/gpio/gpio.txt>. | ||
| 30 | |||
| 31 | Example: | ||
| 32 | -------- | ||
| 33 | |||
| 34 | pmic@48 { | ||
| 35 | compatible = "maxim,max77650"; | ||
| 36 | reg = <0x48>; | ||
| 37 | |||
| 38 | interrupt-controller; | ||
| 39 | interrupt-parent = <&gpio2>; | ||
| 40 | #interrupt-cells = <2>; | ||
| 41 | interrupts = <3 IRQ_TYPE_LEVEL_LOW>; | ||
| 42 | |||
| 43 | gpio-controller; | ||
| 44 | #gpio-cells = <2>; | ||
| 45 | gpio-line-names = "max77650-charger"; | ||
| 46 | }; | ||
diff --git a/Documentation/devicetree/bindings/mfd/stmfx.txt b/Documentation/devicetree/bindings/mfd/stmfx.txt new file mode 100644 index 000000000000..f0c2f7fcf5c7 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/stmfx.txt | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | STMicroelectonics Multi-Function eXpander (STMFX) Core bindings | ||
| 2 | |||
| 3 | ST Multi-Function eXpander (STMFX) is a slave controller using I2C for | ||
| 4 | communication with the main MCU. Its main features are GPIO expansion, main | ||
| 5 | MCU IDD measurement (IDD is the amount of current that flows through VDD) and | ||
| 6 | resistive touchscreen controller. | ||
| 7 | |||
| 8 | Required properties: | ||
| 9 | - compatible: should be "st,stmfx-0300". | ||
| 10 | - reg: I2C slave address of the device. | ||
| 11 | - interrupts: interrupt specifier triggered by MFX_IRQ_OUT signal. | ||
| 12 | Please refer to ../interrupt-controller/interrupt.txt | ||
| 13 | |||
| 14 | Optional properties: | ||
| 15 | - drive-open-drain: configure MFX_IRQ_OUT as open drain. | ||
| 16 | - vdd-supply: phandle of the regulator supplying STMFX. | ||
| 17 | |||
| 18 | Example: | ||
| 19 | |||
| 20 | stmfx: stmfx@42 { | ||
| 21 | compatible = "st,stmfx-0300"; | ||
| 22 | reg = <0x42>; | ||
| 23 | interrupts = <8 IRQ_TYPE_EDGE_RISING>; | ||
| 24 | interrupt-parent = <&gpioi>; | ||
| 25 | vdd-supply = <&v3v3>; | ||
| 26 | }; | ||
| 27 | |||
| 28 | Please refer to ../pinctrl/pinctrl-stmfx.txt for STMFX GPIO expander function bindings. | ||
diff --git a/Documentation/devicetree/bindings/mfd/ti-lmu.txt b/Documentation/devicetree/bindings/mfd/ti-lmu.txt index 980394d701a7..86ca786d54fc 100644 --- a/Documentation/devicetree/bindings/mfd/ti-lmu.txt +++ b/Documentation/devicetree/bindings/mfd/ti-lmu.txt | |||
| @@ -104,8 +104,8 @@ lm3632@11 { | |||
| 104 | regulators { | 104 | regulators { |
| 105 | compatible = "ti,lm363x-regulator"; | 105 | compatible = "ti,lm363x-regulator"; |
| 106 | 106 | ||
| 107 | ti,lcm-en1-gpio = <&pioC 0 GPIO_ACTIVE_HIGH>; /* PC0 */ | 107 | enable-gpios = <&pioC 0 GPIO_ACTIVE_HIGH>, |
| 108 | ti,lcm-en2-gpio = <&pioC 1 GPIO_ACTIVE_HIGH>; /* PC1 */ | 108 | <&pioC 1 GPIO_ACTIVE_HIGH>; |
| 109 | 109 | ||
| 110 | vboost { | 110 | vboost { |
| 111 | regulator-name = "lcd_boost"; | 111 | regulator-name = "lcd_boost"; |
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt new file mode 100644 index 000000000000..c1b4c1819b84 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander bindings | ||
| 2 | |||
| 3 | ST Multi-Function eXpander (STMFX) offers up to 24 GPIOs expansion. | ||
| 4 | Please refer to ../mfd/stmfx.txt for STMFX Core bindings. | ||
| 5 | |||
| 6 | Required properties: | ||
| 7 | - compatible: should be "st,stmfx-0300-pinctrl". | ||
| 8 | - #gpio-cells: should be <2>, the first cell is the GPIO number and the second | ||
| 9 | cell is the gpio flags in accordance with <dt-bindings/gpio/gpio.h>. | ||
| 10 | - gpio-controller: marks the device as a GPIO controller. | ||
| 11 | - #interrupt-cells: should be <2>, the first cell is the GPIO number and the | ||
| 12 | second cell is the interrupt flags in accordance with | ||
| 13 | <dt-bindings/interrupt-controller/irq.h>. | ||
| 14 | - interrupt-controller: marks the device as an interrupt controller. | ||
| 15 | - gpio-ranges: specifies the mapping between gpio controller and pin | ||
| 16 | controller pins. Check "Concerning gpio-ranges property" below. | ||
| 17 | Please refer to ../gpio/gpio.txt. | ||
| 18 | |||
| 19 | Please refer to pinctrl-bindings.txt for pin configuration. | ||
| 20 | |||
| 21 | Required properties for pin configuration sub-nodes: | ||
| 22 | - pins: list of pins to which the configuration applies. | ||
| 23 | |||
| 24 | Optional properties for pin configuration sub-nodes (pinconf-generic ones): | ||
| 25 | - bias-disable: disable any bias on the pin. | ||
| 26 | - bias-pull-up: the pin will be pulled up. | ||
| 27 | - bias-pull-pin-default: use the pin-default pull state. | ||
| 28 | - bias-pull-down: the pin will be pulled down. | ||
| 29 | - drive-open-drain: the pin will be driven with open drain. | ||
| 30 | - drive-push-pull: the pin will be driven actively high and low. | ||
| 31 | - output-high: the pin will be configured as an output driving high level. | ||
| 32 | - output-low: the pin will be configured as an output driving low level. | ||
| 33 | |||
| 34 | Note that STMFX pins[15:0] are called "gpio[15:0]", and STMFX pins[23:16] are | ||
| 35 | called "agpio[7:0]". Example, to refer to pin 18 of STMFX, use "agpio2". | ||
| 36 | |||
| 37 | Concerning gpio-ranges property: | ||
| 38 | - if all STMFX pins[24:0] are available (no other STMFX function in use), you | ||
| 39 | should use gpio-ranges = <&stmfx_pinctrl 0 0 24>; | ||
| 40 | - if agpio[3:0] are not available (STMFX Touchscreen function in use), you | ||
| 41 | should use gpio-ranges = <&stmfx_pinctrl 0 0 16>, <&stmfx_pinctrl 20 20 4>; | ||
| 42 | - if agpio[7:4] are not available (STMFX IDD function in use), you | ||
| 43 | should use gpio-ranges = <&stmfx_pinctrl 0 0 20>; | ||
| 44 | |||
| 45 | |||
| 46 | Example: | ||
| 47 | |||
| 48 | stmfx: stmfx@42 { | ||
| 49 | ... | ||
| 50 | |||
| 51 | stmfx_pinctrl: stmfx-pin-controller { | ||
| 52 | compatible = "st,stmfx-0300-pinctrl"; | ||
| 53 | #gpio-cells = <2>; | ||
| 54 | #interrupt-cells = <2>; | ||
| 55 | gpio-controller; | ||
| 56 | interrupt-controller; | ||
| 57 | gpio-ranges = <&stmfx_pinctrl 0 0 24>; | ||
| 58 | |||
| 59 | joystick_pins: joystick { | ||
| 60 | pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4"; | ||
| 61 | drive-push-pull; | ||
| 62 | bias-pull-up; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | }; | ||
| 66 | |||
| 67 | Example of STMFX GPIO consumers: | ||
| 68 | |||
| 69 | joystick { | ||
| 70 | compatible = "gpio-keys"; | ||
| 71 | #address-cells = <1>; | ||
| 72 | #size-cells = <0>; | ||
| 73 | pinctrl-0 = <&joystick_pins>; | ||
| 74 | pinctrl-names = "default"; | ||
| 75 | button-0 { | ||
| 76 | label = "JoySel"; | ||
| 77 | linux,code = <KEY_ENTER>; | ||
| 78 | interrupt-parent = <&stmfx_pinctrl>; | ||
| 79 | interrupts = <0 IRQ_TYPE_EDGE_RISING>; | ||
| 80 | }; | ||
| 81 | button-1 { | ||
| 82 | label = "JoyDown"; | ||
| 83 | linux,code = <KEY_DOWN>; | ||
| 84 | interrupt-parent = <&stmfx_pinctrl>; | ||
| 85 | interrupts = <1 IRQ_TYPE_EDGE_RISING>; | ||
| 86 | }; | ||
| 87 | button-2 { | ||
| 88 | label = "JoyLeft"; | ||
| 89 | linux,code = <KEY_LEFT>; | ||
| 90 | interrupt-parent = <&stmfx_pinctrl>; | ||
| 91 | interrupts = <2 IRQ_TYPE_EDGE_RISING>; | ||
| 92 | }; | ||
| 93 | button-3 { | ||
| 94 | label = "JoyRight"; | ||
| 95 | linux,code = <KEY_RIGHT>; | ||
| 96 | interrupt-parent = <&stmfx_pinctrl>; | ||
| 97 | interrupts = <3 IRQ_TYPE_EDGE_RISING>; | ||
| 98 | }; | ||
| 99 | button-4 { | ||
| 100 | label = "JoyUp"; | ||
| 101 | linux,code = <KEY_UP>; | ||
| 102 | interrupt-parent = <&stmfx_pinctrl>; | ||
| 103 | interrupts = <4 IRQ_TYPE_EDGE_RISING>; | ||
| 104 | }; | ||
| 105 | }; | ||
| 106 | |||
| 107 | leds { | ||
| 108 | compatible = "gpio-leds"; | ||
| 109 | orange { | ||
| 110 | gpios = <&stmfx_pinctrl 17 1>; | ||
| 111 | }; | ||
| 112 | |||
| 113 | blue { | ||
| 114 | gpios = <&stmfx_pinctrl 19 1>; | ||
| 115 | }; | ||
| 116 | } | ||
diff --git a/Documentation/devicetree/bindings/power/supply/max77650-charger.txt b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt new file mode 100644 index 000000000000..e6d0fb6ff94e --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/max77650-charger.txt | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | Battery charger driver for MAX77650 PMIC from Maxim Integrated. | ||
| 2 | |||
| 3 | This module is part of the MAX77650 MFD device. For more details | ||
| 4 | see Documentation/devicetree/bindings/mfd/max77650.txt. | ||
| 5 | |||
| 6 | The charger is represented as a sub-node of the PMIC node on the device tree. | ||
| 7 | |||
| 8 | Required properties: | ||
| 9 | -------------------- | ||
| 10 | - compatible: Must be "maxim,max77650-charger" | ||
| 11 | |||
| 12 | Optional properties: | ||
| 13 | -------------------- | ||
| 14 | - input-voltage-min-microvolt: Minimum CHGIN regulation voltage. Must be one | ||
| 15 | of: 4000000, 4100000, 4200000, 4300000, | ||
| 16 | 4400000, 4500000, 4600000, 4700000. | ||
| 17 | - input-current-limit-microamp: CHGIN input current limit (in microamps). Must | ||
| 18 | be one of: 95000, 190000, 285000, 380000, | ||
| 19 | 475000. | ||
| 20 | |||
| 21 | Example: | ||
| 22 | -------- | ||
| 23 | |||
| 24 | charger { | ||
| 25 | compatible = "maxim,max77650-charger"; | ||
| 26 | input-voltage-min-microvolt = <4200000>; | ||
| 27 | input-current-limit-microamp = <285000>; | ||
| 28 | }; | ||
diff --git a/MAINTAINERS b/MAINTAINERS index a8b3eefc37a2..ce573aaa04df 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -710,6 +710,12 @@ L: linux-gpio@vger.kernel.org | |||
| 710 | S: Maintained | 710 | S: Maintained |
| 711 | F: drivers/gpio/gpio-altera.c | 711 | F: drivers/gpio/gpio-altera.c |
| 712 | 712 | ||
| 713 | ALTERA SYSTEM MANAGER DRIVER | ||
| 714 | M: Thor Thayer <thor.thayer@linux.intel.com> | ||
| 715 | S: Maintained | ||
| 716 | F: drivers/mfd/altera-sysmgr.c | ||
| 717 | F: include/linux/mfd/altera-sysgmr.h | ||
| 718 | |||
| 713 | ALTERA SYSTEM RESOURCE DRIVER FOR ARRIA10 DEVKIT | 719 | ALTERA SYSTEM RESOURCE DRIVER FOR ARRIA10 DEVKIT |
| 714 | M: Thor Thayer <thor.thayer@linux.intel.com> | 720 | M: Thor Thayer <thor.thayer@linux.intel.com> |
| 715 | S: Maintained | 721 | S: Maintained |
| @@ -9517,6 +9523,20 @@ S: Maintained | |||
| 9517 | F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt | 9523 | F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt |
| 9518 | F: drivers/iio/proximity/mb1232.c | 9524 | F: drivers/iio/proximity/mb1232.c |
| 9519 | 9525 | ||
| 9526 | MAXIM MAX77650 PMIC MFD DRIVER | ||
| 9527 | M: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
| 9528 | L: linux-kernel@vger.kernel.org | ||
| 9529 | S: Maintained | ||
| 9530 | F: Documentation/devicetree/bindings/*/*max77650.txt | ||
| 9531 | F: Documentation/devicetree/bindings/*/max77650*.txt | ||
| 9532 | F: include/linux/mfd/max77650.h | ||
| 9533 | F: drivers/mfd/max77650.c | ||
| 9534 | F: drivers/regulator/max77650-regulator.c | ||
| 9535 | F: drivers/power/supply/max77650-charger.c | ||
| 9536 | F: drivers/input/misc/max77650-onkey.c | ||
| 9537 | F: drivers/leds/leds-max77650.c | ||
| 9538 | F: drivers/gpio/gpio-max77650.c | ||
| 9539 | |||
| 9520 | MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER | 9540 | MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER |
| 9521 | M: Javier Martinez Canillas <javier@dowhile0.org> | 9541 | M: Javier Martinez Canillas <javier@dowhile0.org> |
| 9522 | L: linux-kernel@vger.kernel.org | 9542 | L: linux-kernel@vger.kernel.org |
diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig index 3b42e0d597bd..9d42cfe85f5b 100644 --- a/arch/arm/configs/socfpga_defconfig +++ b/arch/arm/configs/socfpga_defconfig | |||
| @@ -106,6 +106,7 @@ CONFIG_SENSORS_LTC2978_REGULATOR=y | |||
| 106 | CONFIG_WATCHDOG=y | 106 | CONFIG_WATCHDOG=y |
| 107 | CONFIG_DW_WATCHDOG=y | 107 | CONFIG_DW_WATCHDOG=y |
| 108 | CONFIG_MFD_ALTERA_A10SR=y | 108 | CONFIG_MFD_ALTERA_A10SR=y |
| 109 | CONFIG_MFD_ALTERA_SYSMGR=y | ||
| 109 | CONFIG_MFD_STMPE=y | 110 | CONFIG_MFD_STMPE=y |
| 110 | CONFIG_REGULATOR=y | 111 | CONFIG_REGULATOR=y |
| 111 | CONFIG_REGULATOR_FIXED_VOLTAGE=y | 112 | CONFIG_REGULATOR_FIXED_VOLTAGE=y |
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi index a2cec6218211..fe107ce115ef 100644 --- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi +++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | |||
| @@ -393,7 +393,7 @@ | |||
| 393 | }; | 393 | }; |
| 394 | 394 | ||
| 395 | sysmgr: sysmgr@ffd12000 { | 395 | sysmgr: sysmgr@ffd12000 { |
| 396 | compatible = "altr,sys-mgr", "syscon"; | 396 | compatible = "altr,sys-mgr-s10","altr,sys-mgr"; |
| 397 | reg = <0xffd12000 0x228>; | 397 | reg = <0xffd12000 0x228>; |
| 398 | }; | 398 | }; |
| 399 | 399 | ||
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index 9a8718bbf6ba..74f0a199166d 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig | |||
| @@ -432,6 +432,7 @@ CONFIG_MESON_WATCHDOG=m | |||
| 432 | CONFIG_RENESAS_WDT=y | 432 | CONFIG_RENESAS_WDT=y |
| 433 | CONFIG_UNIPHIER_WATCHDOG=y | 433 | CONFIG_UNIPHIER_WATCHDOG=y |
| 434 | CONFIG_BCM2835_WDT=y | 434 | CONFIG_BCM2835_WDT=y |
| 435 | CONFIG_MFD_ALTERA_SYSMGR=y | ||
| 435 | CONFIG_MFD_BD9571MWV=y | 436 | CONFIG_MFD_BD9571MWV=y |
| 436 | CONFIG_MFD_AXP20X_I2C=y | 437 | CONFIG_MFD_AXP20X_I2C=y |
| 437 | CONFIG_MFD_AXP20X_RSB=y | 438 | CONFIG_MFD_AXP20X_RSB=y |
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 9370276fe7fe..41f08362dad3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
| @@ -1097,6 +1097,13 @@ config GPIO_MAX77620 | |||
| 1097 | driver also provides interrupt support for each of the gpios. | 1097 | driver also provides interrupt support for each of the gpios. |
| 1098 | Say yes here to enable the max77620 to be used as gpio controller. | 1098 | Say yes here to enable the max77620 to be used as gpio controller. |
| 1099 | 1099 | ||
| 1100 | config GPIO_MAX77650 | ||
| 1101 | tristate "Maxim MAX77650/77651 GPIO support" | ||
| 1102 | depends on MFD_MAX77650 | ||
| 1103 | help | ||
| 1104 | GPIO driver for MAX77650/77651 PMIC from Maxim Semiconductor. | ||
| 1105 | These chips have a single pin that can be configured as GPIO. | ||
| 1106 | |||
| 1100 | config GPIO_MSIC | 1107 | config GPIO_MSIC |
| 1101 | bool "Intel MSIC mixed signal gpio support" | 1108 | bool "Intel MSIC mixed signal gpio support" |
| 1102 | depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC | 1109 | depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index db8d854f9aea..e19be766f6a6 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
| @@ -80,6 +80,7 @@ obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o | |||
| 80 | obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o | 80 | obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o |
| 81 | obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o | 81 | obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o |
| 82 | obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o | 82 | obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o |
| 83 | obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o | ||
| 83 | obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o | 84 | obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o |
| 84 | obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o | 85 | obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o |
| 85 | obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o | 86 | obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o |
diff --git a/drivers/gpio/gpio-max77650.c b/drivers/gpio/gpio-max77650.c new file mode 100644 index 000000000000..3f03f4e8956c --- /dev/null +++ b/drivers/gpio/gpio-max77650.c | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // | ||
| 3 | // Copyright (C) 2018 BayLibre SAS | ||
| 4 | // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
| 5 | // | ||
| 6 | // GPIO driver for MAXIM 77650/77651 charger/power-supply. | ||
| 7 | |||
| 8 | #include <linux/gpio/driver.h> | ||
| 9 | #include <linux/i2c.h> | ||
| 10 | #include <linux/mfd/max77650.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/regmap.h> | ||
| 14 | |||
| 15 | #define MAX77650_GPIO_DIR_MASK BIT(0) | ||
| 16 | #define MAX77650_GPIO_INVAL_MASK BIT(1) | ||
| 17 | #define MAX77650_GPIO_DRV_MASK BIT(2) | ||
| 18 | #define MAX77650_GPIO_OUTVAL_MASK BIT(3) | ||
| 19 | #define MAX77650_GPIO_DEBOUNCE_MASK BIT(4) | ||
| 20 | |||
| 21 | #define MAX77650_GPIO_DIR_OUT 0x00 | ||
| 22 | #define MAX77650_GPIO_DIR_IN BIT(0) | ||
| 23 | #define MAX77650_GPIO_OUT_LOW 0x00 | ||
| 24 | #define MAX77650_GPIO_OUT_HIGH BIT(3) | ||
| 25 | #define MAX77650_GPIO_DRV_OPEN_DRAIN 0x00 | ||
| 26 | #define MAX77650_GPIO_DRV_PUSH_PULL BIT(2) | ||
| 27 | #define MAX77650_GPIO_DEBOUNCE BIT(4) | ||
| 28 | |||
| 29 | #define MAX77650_GPIO_DIR_BITS(_reg) \ | ||
| 30 | ((_reg) & MAX77650_GPIO_DIR_MASK) | ||
| 31 | #define MAX77650_GPIO_INVAL_BITS(_reg) \ | ||
| 32 | (((_reg) & MAX77650_GPIO_INVAL_MASK) >> 1) | ||
| 33 | |||
| 34 | struct max77650_gpio_chip { | ||
| 35 | struct regmap *map; | ||
| 36 | struct gpio_chip gc; | ||
| 37 | int irq; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static int max77650_gpio_direction_input(struct gpio_chip *gc, | ||
| 41 | unsigned int offset) | ||
| 42 | { | ||
| 43 | struct max77650_gpio_chip *chip = gpiochip_get_data(gc); | ||
| 44 | |||
| 45 | return regmap_update_bits(chip->map, | ||
| 46 | MAX77650_REG_CNFG_GPIO, | ||
| 47 | MAX77650_GPIO_DIR_MASK, | ||
| 48 | MAX77650_GPIO_DIR_IN); | ||
| 49 | } | ||
| 50 | |||
| 51 | static int max77650_gpio_direction_output(struct gpio_chip *gc, | ||
| 52 | unsigned int offset, int value) | ||
| 53 | { | ||
| 54 | struct max77650_gpio_chip *chip = gpiochip_get_data(gc); | ||
| 55 | int mask, regval; | ||
| 56 | |||
| 57 | mask = MAX77650_GPIO_DIR_MASK | MAX77650_GPIO_OUTVAL_MASK; | ||
| 58 | regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW; | ||
| 59 | regval |= MAX77650_GPIO_DIR_OUT; | ||
| 60 | |||
| 61 | return regmap_update_bits(chip->map, | ||
| 62 | MAX77650_REG_CNFG_GPIO, mask, regval); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void max77650_gpio_set_value(struct gpio_chip *gc, | ||
| 66 | unsigned int offset, int value) | ||
| 67 | { | ||
| 68 | struct max77650_gpio_chip *chip = gpiochip_get_data(gc); | ||
| 69 | int rv, regval; | ||
| 70 | |||
| 71 | regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW; | ||
| 72 | |||
| 73 | rv = regmap_update_bits(chip->map, MAX77650_REG_CNFG_GPIO, | ||
| 74 | MAX77650_GPIO_OUTVAL_MASK, regval); | ||
| 75 | if (rv) | ||
| 76 | dev_err(gc->parent, "cannot set GPIO value: %d\n", rv); | ||
| 77 | } | ||
| 78 | |||
| 79 | static int max77650_gpio_get_value(struct gpio_chip *gc, | ||
| 80 | unsigned int offset) | ||
| 81 | { | ||
| 82 | struct max77650_gpio_chip *chip = gpiochip_get_data(gc); | ||
| 83 | unsigned int val; | ||
| 84 | int rv; | ||
| 85 | |||
| 86 | rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val); | ||
| 87 | if (rv) | ||
| 88 | return rv; | ||
| 89 | |||
| 90 | return MAX77650_GPIO_INVAL_BITS(val); | ||
| 91 | } | ||
| 92 | |||
| 93 | static int max77650_gpio_get_direction(struct gpio_chip *gc, | ||
| 94 | unsigned int offset) | ||
| 95 | { | ||
| 96 | struct max77650_gpio_chip *chip = gpiochip_get_data(gc); | ||
| 97 | unsigned int val; | ||
| 98 | int rv; | ||
| 99 | |||
| 100 | rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val); | ||
| 101 | if (rv) | ||
| 102 | return rv; | ||
| 103 | |||
| 104 | return MAX77650_GPIO_DIR_BITS(val); | ||
| 105 | } | ||
| 106 | |||
| 107 | static int max77650_gpio_set_config(struct gpio_chip *gc, | ||
| 108 | unsigned int offset, unsigned long cfg) | ||
| 109 | { | ||
| 110 | struct max77650_gpio_chip *chip = gpiochip_get_data(gc); | ||
| 111 | |||
| 112 | switch (pinconf_to_config_param(cfg)) { | ||
| 113 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: | ||
| 114 | return regmap_update_bits(chip->map, | ||
| 115 | MAX77650_REG_CNFG_GPIO, | ||
| 116 | MAX77650_GPIO_DRV_MASK, | ||
| 117 | MAX77650_GPIO_DRV_OPEN_DRAIN); | ||
| 118 | case PIN_CONFIG_DRIVE_PUSH_PULL: | ||
| 119 | return regmap_update_bits(chip->map, | ||
| 120 | MAX77650_REG_CNFG_GPIO, | ||
| 121 | MAX77650_GPIO_DRV_MASK, | ||
| 122 | MAX77650_GPIO_DRV_PUSH_PULL); | ||
| 123 | case PIN_CONFIG_INPUT_DEBOUNCE: | ||
| 124 | return regmap_update_bits(chip->map, | ||
| 125 | MAX77650_REG_CNFG_GPIO, | ||
| 126 | MAX77650_GPIO_DEBOUNCE_MASK, | ||
| 127 | MAX77650_GPIO_DEBOUNCE); | ||
| 128 | default: | ||
| 129 | return -ENOTSUPP; | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | static int max77650_gpio_to_irq(struct gpio_chip *gc, unsigned int offset) | ||
| 134 | { | ||
| 135 | struct max77650_gpio_chip *chip = gpiochip_get_data(gc); | ||
| 136 | |||
| 137 | return chip->irq; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int max77650_gpio_probe(struct platform_device *pdev) | ||
| 141 | { | ||
| 142 | struct max77650_gpio_chip *chip; | ||
| 143 | struct device *dev, *parent; | ||
| 144 | struct i2c_client *i2c; | ||
| 145 | |||
| 146 | dev = &pdev->dev; | ||
| 147 | parent = dev->parent; | ||
| 148 | i2c = to_i2c_client(parent); | ||
| 149 | |||
| 150 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); | ||
| 151 | if (!chip) | ||
| 152 | return -ENOMEM; | ||
| 153 | |||
| 154 | chip->map = dev_get_regmap(parent, NULL); | ||
| 155 | if (!chip->map) | ||
| 156 | return -ENODEV; | ||
| 157 | |||
| 158 | chip->irq = platform_get_irq_byname(pdev, "GPI"); | ||
| 159 | if (chip->irq < 0) | ||
| 160 | return chip->irq; | ||
| 161 | |||
| 162 | chip->gc.base = -1; | ||
| 163 | chip->gc.ngpio = 1; | ||
| 164 | chip->gc.label = i2c->name; | ||
| 165 | chip->gc.parent = dev; | ||
| 166 | chip->gc.owner = THIS_MODULE; | ||
| 167 | chip->gc.can_sleep = true; | ||
| 168 | |||
| 169 | chip->gc.direction_input = max77650_gpio_direction_input; | ||
| 170 | chip->gc.direction_output = max77650_gpio_direction_output; | ||
| 171 | chip->gc.set = max77650_gpio_set_value; | ||
| 172 | chip->gc.get = max77650_gpio_get_value; | ||
| 173 | chip->gc.get_direction = max77650_gpio_get_direction; | ||
| 174 | chip->gc.set_config = max77650_gpio_set_config; | ||
| 175 | chip->gc.to_irq = max77650_gpio_to_irq; | ||
| 176 | |||
| 177 | return devm_gpiochip_add_data(dev, &chip->gc, chip); | ||
| 178 | } | ||
| 179 | |||
| 180 | static struct platform_driver max77650_gpio_driver = { | ||
| 181 | .driver = { | ||
| 182 | .name = "max77650-gpio", | ||
| 183 | }, | ||
| 184 | .probe = max77650_gpio_probe, | ||
| 185 | }; | ||
| 186 | module_platform_driver(max77650_gpio_driver); | ||
| 187 | |||
| 188 | MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver"); | ||
| 189 | MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); | ||
| 190 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 6dfe9e2fe5b1..54d36f98b426 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig | |||
| @@ -190,6 +190,15 @@ config INPUT_M68K_BEEP | |||
| 190 | tristate "M68k Beeper support" | 190 | tristate "M68k Beeper support" |
| 191 | depends on M68K | 191 | depends on M68K |
| 192 | 192 | ||
| 193 | config INPUT_MAX77650_ONKEY | ||
| 194 | tristate "Maxim MAX77650 ONKEY support" | ||
| 195 | depends on MFD_MAX77650 | ||
| 196 | help | ||
| 197 | Support the ONKEY of the MAX77650 PMIC as an input device. | ||
| 198 | |||
| 199 | To compile this driver as a module, choose M here: the module | ||
| 200 | will be called max77650-onkey. | ||
| 201 | |||
| 193 | config INPUT_MAX77693_HAPTIC | 202 | config INPUT_MAX77693_HAPTIC |
| 194 | tristate "MAXIM MAX77693/MAX77843 haptic controller support" | 203 | tristate "MAXIM MAX77693/MAX77843 haptic controller support" |
| 195 | depends on (MFD_MAX77693 || MFD_MAX77843) && PWM | 204 | depends on (MFD_MAX77693 || MFD_MAX77843) && PWM |
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index f38ebbdb05e2..8fd187f314bd 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile | |||
| @@ -44,6 +44,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o | |||
| 44 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o | 44 | obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o |
| 45 | obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o | 45 | obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o |
| 46 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o | 46 | obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o |
| 47 | obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o | ||
| 47 | obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o | 48 | obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o |
| 48 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o | 49 | obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o |
| 49 | obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o | 50 | obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o |
diff --git a/drivers/input/misc/max77650-onkey.c b/drivers/input/misc/max77650-onkey.c new file mode 100644 index 000000000000..fbf6caab7217 --- /dev/null +++ b/drivers/input/misc/max77650-onkey.c | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // | ||
| 3 | // Copyright (C) 2018 BayLibre SAS | ||
| 4 | // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
| 5 | // | ||
| 6 | // ONKEY driver for MAXIM 77650/77651 charger/power-supply. | ||
| 7 | |||
| 8 | #include <linux/i2c.h> | ||
| 9 | #include <linux/input.h> | ||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/mfd/max77650.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/platform_device.h> | ||
| 14 | #include <linux/regmap.h> | ||
| 15 | |||
| 16 | #define MAX77650_ONKEY_MODE_MASK BIT(3) | ||
| 17 | #define MAX77650_ONKEY_MODE_PUSH 0x00 | ||
| 18 | #define MAX77650_ONKEY_MODE_SLIDE BIT(3) | ||
| 19 | |||
| 20 | struct max77650_onkey { | ||
| 21 | struct input_dev *input; | ||
| 22 | unsigned int code; | ||
| 23 | }; | ||
| 24 | |||
| 25 | static irqreturn_t max77650_onkey_falling(int irq, void *data) | ||
| 26 | { | ||
| 27 | struct max77650_onkey *onkey = data; | ||
| 28 | |||
| 29 | input_report_key(onkey->input, onkey->code, 0); | ||
| 30 | input_sync(onkey->input); | ||
| 31 | |||
| 32 | return IRQ_HANDLED; | ||
| 33 | } | ||
| 34 | |||
| 35 | static irqreturn_t max77650_onkey_rising(int irq, void *data) | ||
| 36 | { | ||
| 37 | struct max77650_onkey *onkey = data; | ||
| 38 | |||
| 39 | input_report_key(onkey->input, onkey->code, 1); | ||
| 40 | input_sync(onkey->input); | ||
| 41 | |||
| 42 | return IRQ_HANDLED; | ||
| 43 | } | ||
| 44 | |||
| 45 | static int max77650_onkey_probe(struct platform_device *pdev) | ||
| 46 | { | ||
| 47 | int irq_r, irq_f, error, mode; | ||
| 48 | struct max77650_onkey *onkey; | ||
| 49 | struct device *dev, *parent; | ||
| 50 | struct regmap *map; | ||
| 51 | unsigned int type; | ||
| 52 | |||
| 53 | dev = &pdev->dev; | ||
| 54 | parent = dev->parent; | ||
| 55 | |||
| 56 | map = dev_get_regmap(parent, NULL); | ||
| 57 | if (!map) | ||
| 58 | return -ENODEV; | ||
| 59 | |||
| 60 | onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); | ||
| 61 | if (!onkey) | ||
| 62 | return -ENOMEM; | ||
| 63 | |||
| 64 | error = device_property_read_u32(dev, "linux,code", &onkey->code); | ||
| 65 | if (error) | ||
| 66 | onkey->code = KEY_POWER; | ||
| 67 | |||
| 68 | if (device_property_read_bool(dev, "maxim,onkey-slide")) { | ||
| 69 | mode = MAX77650_ONKEY_MODE_SLIDE; | ||
| 70 | type = EV_SW; | ||
| 71 | } else { | ||
| 72 | mode = MAX77650_ONKEY_MODE_PUSH; | ||
| 73 | type = EV_KEY; | ||
| 74 | } | ||
| 75 | |||
| 76 | error = regmap_update_bits(map, MAX77650_REG_CNFG_GLBL, | ||
| 77 | MAX77650_ONKEY_MODE_MASK, mode); | ||
| 78 | if (error) | ||
| 79 | return error; | ||
| 80 | |||
| 81 | irq_f = platform_get_irq_byname(pdev, "nEN_F"); | ||
| 82 | if (irq_f < 0) | ||
| 83 | return irq_f; | ||
| 84 | |||
| 85 | irq_r = platform_get_irq_byname(pdev, "nEN_R"); | ||
| 86 | if (irq_r < 0) | ||
| 87 | return irq_r; | ||
| 88 | |||
| 89 | onkey->input = devm_input_allocate_device(dev); | ||
| 90 | if (!onkey->input) | ||
| 91 | return -ENOMEM; | ||
| 92 | |||
| 93 | onkey->input->name = "max77650_onkey"; | ||
| 94 | onkey->input->phys = "max77650_onkey/input0"; | ||
| 95 | onkey->input->id.bustype = BUS_I2C; | ||
| 96 | input_set_capability(onkey->input, type, onkey->code); | ||
| 97 | |||
| 98 | error = devm_request_any_context_irq(dev, irq_f, max77650_onkey_falling, | ||
| 99 | IRQF_ONESHOT, "onkey-down", onkey); | ||
| 100 | if (error < 0) | ||
| 101 | return error; | ||
| 102 | |||
| 103 | error = devm_request_any_context_irq(dev, irq_r, max77650_onkey_rising, | ||
| 104 | IRQF_ONESHOT, "onkey-up", onkey); | ||
| 105 | if (error < 0) | ||
| 106 | return error; | ||
| 107 | |||
| 108 | return input_register_device(onkey->input); | ||
| 109 | } | ||
| 110 | |||
| 111 | static struct platform_driver max77650_onkey_driver = { | ||
| 112 | .driver = { | ||
| 113 | .name = "max77650-onkey", | ||
| 114 | }, | ||
| 115 | .probe = max77650_onkey_probe, | ||
| 116 | }; | ||
| 117 | module_platform_driver(max77650_onkey_driver); | ||
| 118 | |||
| 119 | MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver"); | ||
| 120 | MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); | ||
| 121 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index f3000ccb8d35..71be87bdb926 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
| @@ -619,6 +619,12 @@ config LEDS_TLC591XX | |||
| 619 | This option enables support for Texas Instruments TLC59108 | 619 | This option enables support for Texas Instruments TLC59108 |
| 620 | and TLC59116 LED controllers. | 620 | and TLC59116 LED controllers. |
| 621 | 621 | ||
| 622 | config LEDS_MAX77650 | ||
| 623 | tristate "LED support for Maxim MAX77650 PMIC" | ||
| 624 | depends on LEDS_CLASS && MFD_MAX77650 | ||
| 625 | help | ||
| 626 | LEDs driver for MAX77650 family of PMICs from Maxim Integrated. | ||
| 627 | |||
| 622 | config LEDS_MAX77693 | 628 | config LEDS_MAX77693 |
| 623 | tristate "LED support for MAX77693 Flash" | 629 | tristate "LED support for MAX77693 Flash" |
| 624 | depends on LEDS_CLASS_FLASH | 630 | depends on LEDS_CLASS_FLASH |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 7a8b1f55d459..1e9702ebffee 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
| @@ -62,6 +62,7 @@ obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o | |||
| 62 | obj-$(CONFIG_LEDS_NS2) += leds-ns2.o | 62 | obj-$(CONFIG_LEDS_NS2) += leds-ns2.o |
| 63 | obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o | 63 | obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o |
| 64 | obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o | 64 | obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o |
| 65 | obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o | ||
| 65 | obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o | 66 | obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o |
| 66 | obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o | 67 | obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o |
| 67 | obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o | 68 | obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o |
diff --git a/drivers/leds/leds-max77650.c b/drivers/leds/leds-max77650.c new file mode 100644 index 000000000000..6b74ce9cac12 --- /dev/null +++ b/drivers/leds/leds-max77650.c | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // | ||
| 3 | // Copyright (C) 2018 BayLibre SAS | ||
| 4 | // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
| 5 | // | ||
| 6 | // LED driver for MAXIM 77650/77651 charger/power-supply. | ||
| 7 | |||
| 8 | #include <linux/i2c.h> | ||
| 9 | #include <linux/leds.h> | ||
| 10 | #include <linux/mfd/max77650.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/regmap.h> | ||
| 14 | |||
| 15 | #define MAX77650_LED_NUM_LEDS 3 | ||
| 16 | |||
| 17 | #define MAX77650_LED_A_BASE 0x40 | ||
| 18 | #define MAX77650_LED_B_BASE 0x43 | ||
| 19 | |||
| 20 | #define MAX77650_LED_BR_MASK GENMASK(4, 0) | ||
| 21 | #define MAX77650_LED_EN_MASK GENMASK(7, 6) | ||
| 22 | |||
| 23 | #define MAX77650_LED_MAX_BRIGHTNESS MAX77650_LED_BR_MASK | ||
| 24 | |||
| 25 | /* Enable EN_LED_MSTR. */ | ||
| 26 | #define MAX77650_LED_TOP_DEFAULT BIT(0) | ||
| 27 | |||
| 28 | #define MAX77650_LED_ENABLE GENMASK(7, 6) | ||
| 29 | #define MAX77650_LED_DISABLE 0x00 | ||
| 30 | |||
| 31 | #define MAX77650_LED_A_DEFAULT MAX77650_LED_DISABLE | ||
| 32 | /* 100% on duty */ | ||
| 33 | #define MAX77650_LED_B_DEFAULT GENMASK(3, 0) | ||
| 34 | |||
| 35 | struct max77650_led { | ||
| 36 | struct led_classdev cdev; | ||
| 37 | struct regmap *map; | ||
| 38 | unsigned int regA; | ||
| 39 | unsigned int regB; | ||
| 40 | }; | ||
| 41 | |||
| 42 | static struct max77650_led *max77650_to_led(struct led_classdev *cdev) | ||
| 43 | { | ||
| 44 | return container_of(cdev, struct max77650_led, cdev); | ||
| 45 | } | ||
| 46 | |||
| 47 | static int max77650_led_brightness_set(struct led_classdev *cdev, | ||
| 48 | enum led_brightness brightness) | ||
| 49 | { | ||
| 50 | struct max77650_led *led = max77650_to_led(cdev); | ||
| 51 | int val, mask; | ||
| 52 | |||
| 53 | mask = MAX77650_LED_BR_MASK | MAX77650_LED_EN_MASK; | ||
| 54 | |||
| 55 | if (brightness == LED_OFF) | ||
| 56 | val = MAX77650_LED_DISABLE; | ||
| 57 | else | ||
| 58 | val = MAX77650_LED_ENABLE | brightness; | ||
| 59 | |||
| 60 | return regmap_update_bits(led->map, led->regA, mask, val); | ||
| 61 | } | ||
| 62 | |||
| 63 | static int max77650_led_probe(struct platform_device *pdev) | ||
| 64 | { | ||
| 65 | struct device_node *of_node, *child; | ||
| 66 | struct max77650_led *leds, *led; | ||
| 67 | struct device *parent; | ||
| 68 | struct device *dev; | ||
| 69 | struct regmap *map; | ||
| 70 | const char *label; | ||
| 71 | int rv, num_leds; | ||
| 72 | u32 reg; | ||
| 73 | |||
| 74 | dev = &pdev->dev; | ||
| 75 | parent = dev->parent; | ||
| 76 | of_node = dev->of_node; | ||
| 77 | |||
| 78 | if (!of_node) | ||
| 79 | return -ENODEV; | ||
| 80 | |||
| 81 | leds = devm_kcalloc(dev, sizeof(*leds), | ||
| 82 | MAX77650_LED_NUM_LEDS, GFP_KERNEL); | ||
| 83 | if (!leds) | ||
| 84 | return -ENOMEM; | ||
| 85 | |||
| 86 | map = dev_get_regmap(dev->parent, NULL); | ||
| 87 | if (!map) | ||
| 88 | return -ENODEV; | ||
| 89 | |||
| 90 | num_leds = of_get_child_count(of_node); | ||
| 91 | if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS) | ||
| 92 | return -ENODEV; | ||
| 93 | |||
| 94 | for_each_child_of_node(of_node, child) { | ||
| 95 | rv = of_property_read_u32(child, "reg", ®); | ||
| 96 | if (rv || reg >= MAX77650_LED_NUM_LEDS) | ||
| 97 | return -EINVAL; | ||
| 98 | |||
| 99 | led = &leds[reg]; | ||
| 100 | led->map = map; | ||
| 101 | led->regA = MAX77650_LED_A_BASE + reg; | ||
| 102 | led->regB = MAX77650_LED_B_BASE + reg; | ||
| 103 | led->cdev.brightness_set_blocking = max77650_led_brightness_set; | ||
| 104 | led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS; | ||
| 105 | |||
| 106 | label = of_get_property(child, "label", NULL); | ||
| 107 | if (!label) { | ||
| 108 | led->cdev.name = "max77650::"; | ||
| 109 | } else { | ||
| 110 | led->cdev.name = devm_kasprintf(dev, GFP_KERNEL, | ||
| 111 | "max77650:%s", label); | ||
| 112 | if (!led->cdev.name) | ||
| 113 | return -ENOMEM; | ||
| 114 | } | ||
| 115 | |||
| 116 | of_property_read_string(child, "linux,default-trigger", | ||
| 117 | &led->cdev.default_trigger); | ||
| 118 | |||
| 119 | rv = devm_of_led_classdev_register(dev, child, &led->cdev); | ||
| 120 | if (rv) | ||
| 121 | return rv; | ||
| 122 | |||
| 123 | rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT); | ||
| 124 | if (rv) | ||
| 125 | return rv; | ||
| 126 | |||
| 127 | rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT); | ||
| 128 | if (rv) | ||
| 129 | return rv; | ||
| 130 | } | ||
| 131 | |||
| 132 | return regmap_write(map, | ||
| 133 | MAX77650_REG_CNFG_LED_TOP, | ||
| 134 | MAX77650_LED_TOP_DEFAULT); | ||
| 135 | } | ||
| 136 | |||
| 137 | static struct platform_driver max77650_led_driver = { | ||
| 138 | .driver = { | ||
| 139 | .name = "max77650-led", | ||
| 140 | }, | ||
| 141 | .probe = max77650_led_probe, | ||
| 142 | }; | ||
| 143 | module_platform_driver(max77650_led_driver); | ||
| 144 | |||
| 145 | MODULE_DESCRIPTION("MAXIM 77650/77651 LED driver"); | ||
| 146 | MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); | ||
| 147 | MODULE_LICENSE("GPL v2"); | ||
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; |
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 5b3b06a0a3bf..d466e33635b0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | * Adopted from dwmac-sti.c | 15 | * Adopted from dwmac-sti.c |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/mfd/syscon.h> | 18 | #include <linux/mfd/altera-sysmgr.h> |
| 19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
| 20 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
| 21 | #include <linux/of_net.h> | 21 | #include <linux/of_net.h> |
| @@ -114,7 +114,8 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * | |||
| 114 | 114 | ||
| 115 | dwmac->interface = of_get_phy_mode(np); | 115 | dwmac->interface = of_get_phy_mode(np); |
| 116 | 116 | ||
| 117 | sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); | 117 | sys_mgr_base_addr = |
| 118 | altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon"); | ||
| 118 | if (IS_ERR(sys_mgr_base_addr)) { | 119 | if (IS_ERR(sys_mgr_base_addr)) { |
| 119 | dev_info(dev, "No sysmgr-syscon node found\n"); | 120 | dev_info(dev, "No sysmgr-syscon node found\n"); |
| 120 | return PTR_ERR(sys_mgr_base_addr); | 121 | return PTR_ERR(sys_mgr_base_addr); |
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 19d8af9a36a2..ea798548b012 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
| @@ -273,6 +273,20 @@ config PINCTRL_ST | |||
| 273 | select PINCONF | 273 | select PINCONF |
| 274 | select GPIOLIB_IRQCHIP | 274 | select GPIOLIB_IRQCHIP |
| 275 | 275 | ||
| 276 | config PINCTRL_STMFX | ||
| 277 | tristate "STMicroelectronics STMFX GPIO expander pinctrl driver" | ||
| 278 | depends on I2C | ||
| 279 | depends on OF || COMPILE_TEST | ||
| 280 | select GENERIC_PINCONF | ||
| 281 | select GPIOLIB_IRQCHIP | ||
| 282 | select MFD_STMFX | ||
| 283 | help | ||
| 284 | Driver for STMicroelectronics Multi-Function eXpander (STMFX) | ||
| 285 | GPIO expander. | ||
| 286 | This provides a GPIO interface supporting inputs and outputs, | ||
| 287 | and configuring push-pull, open-drain, and can also be used as | ||
| 288 | interrupt-controller. | ||
| 289 | |||
| 276 | config PINCTRL_U300 | 290 | config PINCTRL_U300 |
| 277 | bool "U300 pin controller driver" | 291 | bool "U300 pin controller driver" |
| 278 | depends on ARCH_U300 | 292 | depends on ARCH_U300 |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 62df40647e02..ac537fdbc998 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
| @@ -41,6 +41,7 @@ obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o | |||
| 41 | obj-$(CONFIG_PINCTRL_LPC18XX) += pinctrl-lpc18xx.o | 41 | obj-$(CONFIG_PINCTRL_LPC18XX) += pinctrl-lpc18xx.o |
| 42 | obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o | 42 | obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o |
| 43 | obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o | 43 | obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o |
| 44 | obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o | ||
| 44 | obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o | 45 | obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o |
| 45 | obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o | 46 | obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o |
| 46 | obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o | 47 | obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o |
diff --git a/drivers/pinctrl/pinctrl-stmfx.c b/drivers/pinctrl/pinctrl-stmfx.c new file mode 100644 index 000000000000..eba872ce4a7c --- /dev/null +++ b/drivers/pinctrl/pinctrl-stmfx.c | |||
| @@ -0,0 +1,819 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 STMicroelectronics | ||
| 6 | * Author(s): Amelie Delaunay <amelie.delaunay@st.com>. | ||
| 7 | */ | ||
| 8 | #include <linux/gpio/driver.h> | ||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/mfd/stmfx.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/pinctrl/pinconf.h> | ||
| 14 | #include <linux/pinctrl/pinmux.h> | ||
| 15 | |||
| 16 | #include "core.h" | ||
| 17 | #include "pinctrl-utils.h" | ||
| 18 | |||
| 19 | /* GPIOs expander */ | ||
| 20 | /* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */ | ||
| 21 | #define STMFX_REG_GPIO_STATE STMFX_REG_GPIO_STATE1 /* R */ | ||
| 22 | /* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */ | ||
| 23 | #define STMFX_REG_GPIO_DIR STMFX_REG_GPIO_DIR1 /* RW */ | ||
| 24 | /* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */ | ||
| 25 | #define STMFX_REG_GPIO_TYPE STMFX_REG_GPIO_TYPE1 /* RW */ | ||
| 26 | /* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */ | ||
| 27 | #define STMFX_REG_GPIO_PUPD STMFX_REG_GPIO_PUPD1 /* RW */ | ||
| 28 | /* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */ | ||
| 29 | #define STMFX_REG_GPO_SET STMFX_REG_GPO_SET1 /* RW */ | ||
| 30 | /* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */ | ||
| 31 | #define STMFX_REG_GPO_CLR STMFX_REG_GPO_CLR1 /* RW */ | ||
| 32 | /* IRQ_GPI_SRC1 0x48, IRQ_GPI_SRC2 0x49, IRQ_GPI_SRC3 0x4A */ | ||
| 33 | #define STMFX_REG_IRQ_GPI_SRC STMFX_REG_IRQ_GPI_SRC1 /* RW */ | ||
| 34 | /* IRQ_GPI_EVT1 0x4C, IRQ_GPI_EVT2 0x4D, IRQ_GPI_EVT3 0x4E */ | ||
| 35 | #define STMFX_REG_IRQ_GPI_EVT STMFX_REG_IRQ_GPI_EVT1 /* RW */ | ||
| 36 | /* IRQ_GPI_TYPE1 0x50, IRQ_GPI_TYPE2 0x51, IRQ_GPI_TYPE3 0x52 */ | ||
| 37 | #define STMFX_REG_IRQ_GPI_TYPE STMFX_REG_IRQ_GPI_TYPE1 /* RW */ | ||
| 38 | /* IRQ_GPI_PENDING1 0x0C, IRQ_GPI_PENDING2 0x0D, IRQ_GPI_PENDING3 0x0E*/ | ||
| 39 | #define STMFX_REG_IRQ_GPI_PENDING STMFX_REG_IRQ_GPI_PENDING1 /* R */ | ||
| 40 | /* IRQ_GPI_ACK1 0x54, IRQ_GPI_ACK2 0x55, IRQ_GPI_ACK3 0x56 */ | ||
| 41 | #define STMFX_REG_IRQ_GPI_ACK STMFX_REG_IRQ_GPI_ACK1 /* RW */ | ||
| 42 | |||
| 43 | #define NR_GPIO_REGS 3 | ||
| 44 | #define NR_GPIOS_PER_REG 8 | ||
| 45 | #define get_reg(offset) ((offset) / NR_GPIOS_PER_REG) | ||
| 46 | #define get_shift(offset) ((offset) % NR_GPIOS_PER_REG) | ||
| 47 | #define get_mask(offset) (BIT(get_shift(offset))) | ||
| 48 | |||
| 49 | /* | ||
| 50 | * STMFX pinctrl can have up to 24 pins if STMFX other functions are not used. | ||
| 51 | * Pins availability is managed thanks to gpio-ranges property. | ||
| 52 | */ | ||
| 53 | static const struct pinctrl_pin_desc stmfx_pins[] = { | ||
| 54 | PINCTRL_PIN(0, "gpio0"), | ||
| 55 | PINCTRL_PIN(1, "gpio1"), | ||
| 56 | PINCTRL_PIN(2, "gpio2"), | ||
| 57 | PINCTRL_PIN(3, "gpio3"), | ||
| 58 | PINCTRL_PIN(4, "gpio4"), | ||
| 59 | PINCTRL_PIN(5, "gpio5"), | ||
| 60 | PINCTRL_PIN(6, "gpio6"), | ||
| 61 | PINCTRL_PIN(7, "gpio7"), | ||
| 62 | PINCTRL_PIN(8, "gpio8"), | ||
| 63 | PINCTRL_PIN(9, "gpio9"), | ||
| 64 | PINCTRL_PIN(10, "gpio10"), | ||
| 65 | PINCTRL_PIN(11, "gpio11"), | ||
| 66 | PINCTRL_PIN(12, "gpio12"), | ||
| 67 | PINCTRL_PIN(13, "gpio13"), | ||
| 68 | PINCTRL_PIN(14, "gpio14"), | ||
| 69 | PINCTRL_PIN(15, "gpio15"), | ||
| 70 | PINCTRL_PIN(16, "agpio0"), | ||
| 71 | PINCTRL_PIN(17, "agpio1"), | ||
| 72 | PINCTRL_PIN(18, "agpio2"), | ||
| 73 | PINCTRL_PIN(19, "agpio3"), | ||
| 74 | PINCTRL_PIN(20, "agpio4"), | ||
| 75 | PINCTRL_PIN(21, "agpio5"), | ||
| 76 | PINCTRL_PIN(22, "agpio6"), | ||
| 77 | PINCTRL_PIN(23, "agpio7"), | ||
| 78 | }; | ||
| 79 | |||
| 80 | struct stmfx_pinctrl { | ||
| 81 | struct device *dev; | ||
| 82 | struct stmfx *stmfx; | ||
| 83 | struct pinctrl_dev *pctl_dev; | ||
| 84 | struct pinctrl_desc pctl_desc; | ||
| 85 | struct gpio_chip gpio_chip; | ||
| 86 | struct irq_chip irq_chip; | ||
| 87 | struct mutex lock; /* IRQ bus lock */ | ||
| 88 | unsigned long gpio_valid_mask; | ||
| 89 | /* Cache of IRQ_GPI_* registers for bus_lock */ | ||
| 90 | u8 irq_gpi_src[NR_GPIO_REGS]; | ||
| 91 | u8 irq_gpi_type[NR_GPIO_REGS]; | ||
| 92 | u8 irq_gpi_evt[NR_GPIO_REGS]; | ||
| 93 | u8 irq_toggle_edge[NR_GPIO_REGS]; | ||
| 94 | #ifdef CONFIG_PM | ||
| 95 | /* Backup of GPIO_* registers for suspend/resume */ | ||
| 96 | u8 bkp_gpio_state[NR_GPIO_REGS]; | ||
| 97 | u8 bkp_gpio_dir[NR_GPIO_REGS]; | ||
| 98 | u8 bkp_gpio_type[NR_GPIO_REGS]; | ||
| 99 | u8 bkp_gpio_pupd[NR_GPIO_REGS]; | ||
| 100 | #endif | ||
| 101 | }; | ||
| 102 | |||
| 103 | static int stmfx_gpio_get(struct gpio_chip *gc, unsigned int offset) | ||
| 104 | { | ||
| 105 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); | ||
| 106 | u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset); | ||
| 107 | u32 mask = get_mask(offset); | ||
| 108 | u32 value; | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | ret = regmap_read(pctl->stmfx->map, reg, &value); | ||
| 112 | |||
| 113 | return ret ? ret : !!(value & mask); | ||
| 114 | } | ||
| 115 | |||
| 116 | static void stmfx_gpio_set(struct gpio_chip *gc, unsigned int offset, int value) | ||
| 117 | { | ||
| 118 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); | ||
| 119 | u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR; | ||
| 120 | u32 mask = get_mask(offset); | ||
| 121 | |||
| 122 | regmap_write_bits(pctl->stmfx->map, reg + get_reg(offset), | ||
| 123 | mask, mask); | ||
| 124 | } | ||
| 125 | |||
| 126 | static int stmfx_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) | ||
| 127 | { | ||
| 128 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); | ||
| 129 | u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); | ||
| 130 | u32 mask = get_mask(offset); | ||
| 131 | u32 val; | ||
| 132 | int ret; | ||
| 133 | |||
| 134 | ret = regmap_read(pctl->stmfx->map, reg, &val); | ||
| 135 | /* | ||
| 136 | * On stmfx, gpio pins direction is (0)input, (1)output. | ||
| 137 | * .get_direction returns 0=out, 1=in | ||
| 138 | */ | ||
| 139 | |||
| 140 | return ret ? ret : !(val & mask); | ||
| 141 | } | ||
| 142 | |||
| 143 | static int stmfx_gpio_direction_input(struct gpio_chip *gc, unsigned int offset) | ||
| 144 | { | ||
| 145 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); | ||
| 146 | u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); | ||
| 147 | u32 mask = get_mask(offset); | ||
| 148 | |||
| 149 | return regmap_write_bits(pctl->stmfx->map, reg, mask, 0); | ||
| 150 | } | ||
| 151 | |||
| 152 | static int stmfx_gpio_direction_output(struct gpio_chip *gc, | ||
| 153 | unsigned int offset, int value) | ||
| 154 | { | ||
| 155 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gc); | ||
| 156 | u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset); | ||
| 157 | u32 mask = get_mask(offset); | ||
| 158 | |||
| 159 | stmfx_gpio_set(gc, offset, value); | ||
| 160 | |||
| 161 | return regmap_write_bits(pctl->stmfx->map, reg, mask, mask); | ||
| 162 | } | ||
| 163 | |||
| 164 | static int stmfx_pinconf_get_pupd(struct stmfx_pinctrl *pctl, | ||
| 165 | unsigned int offset) | ||
| 166 | { | ||
| 167 | u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset); | ||
| 168 | u32 pupd, mask = get_mask(offset); | ||
| 169 | int ret; | ||
| 170 | |||
| 171 | ret = regmap_read(pctl->stmfx->map, reg, &pupd); | ||
| 172 | if (ret) | ||
| 173 | return ret; | ||
| 174 | |||
| 175 | return !!(pupd & mask); | ||
| 176 | } | ||
| 177 | |||
| 178 | static int stmfx_pinconf_set_pupd(struct stmfx_pinctrl *pctl, | ||
| 179 | unsigned int offset, u32 pupd) | ||
| 180 | { | ||
| 181 | u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset); | ||
| 182 | u32 mask = get_mask(offset); | ||
| 183 | |||
| 184 | return regmap_write_bits(pctl->stmfx->map, reg, mask, pupd ? mask : 0); | ||
| 185 | } | ||
| 186 | |||
| 187 | static int stmfx_pinconf_get_type(struct stmfx_pinctrl *pctl, | ||
| 188 | unsigned int offset) | ||
| 189 | { | ||
| 190 | u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset); | ||
| 191 | u32 type, mask = get_mask(offset); | ||
| 192 | int ret; | ||
| 193 | |||
| 194 | ret = regmap_read(pctl->stmfx->map, reg, &type); | ||
| 195 | if (ret) | ||
| 196 | return ret; | ||
| 197 | |||
| 198 | return !!(type & mask); | ||
| 199 | } | ||
| 200 | |||
| 201 | static int stmfx_pinconf_set_type(struct stmfx_pinctrl *pctl, | ||
| 202 | unsigned int offset, u32 type) | ||
| 203 | { | ||
| 204 | u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset); | ||
| 205 | u32 mask = get_mask(offset); | ||
| 206 | |||
| 207 | return regmap_write_bits(pctl->stmfx->map, reg, mask, type ? mask : 0); | ||
| 208 | } | ||
| 209 | |||
| 210 | static int stmfx_pinconf_get(struct pinctrl_dev *pctldev, | ||
| 211 | unsigned int pin, unsigned long *config) | ||
| 212 | { | ||
| 213 | struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
| 214 | u32 param = pinconf_to_config_param(*config); | ||
| 215 | struct pinctrl_gpio_range *range; | ||
| 216 | u32 arg = 0; | ||
| 217 | int ret, dir, type, pupd; | ||
| 218 | |||
| 219 | range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); | ||
| 220 | if (!range) | ||
| 221 | return -EINVAL; | ||
| 222 | |||
| 223 | dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin); | ||
| 224 | if (dir < 0) | ||
| 225 | return dir; | ||
| 226 | type = stmfx_pinconf_get_type(pctl, pin); | ||
| 227 | if (type < 0) | ||
| 228 | return type; | ||
| 229 | pupd = stmfx_pinconf_get_pupd(pctl, pin); | ||
| 230 | if (pupd < 0) | ||
| 231 | return pupd; | ||
| 232 | |||
| 233 | switch (param) { | ||
| 234 | case PIN_CONFIG_BIAS_DISABLE: | ||
| 235 | if ((!dir && (!type || !pupd)) || (dir && !type)) | ||
| 236 | arg = 1; | ||
| 237 | break; | ||
| 238 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
| 239 | if (dir && type && !pupd) | ||
| 240 | arg = 1; | ||
| 241 | break; | ||
| 242 | case PIN_CONFIG_BIAS_PULL_UP: | ||
| 243 | if (type && pupd) | ||
| 244 | arg = 1; | ||
| 245 | break; | ||
| 246 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: | ||
| 247 | if ((!dir && type) || (dir && !type)) | ||
| 248 | arg = 1; | ||
| 249 | break; | ||
| 250 | case PIN_CONFIG_DRIVE_PUSH_PULL: | ||
| 251 | if ((!dir && !type) || (dir && type)) | ||
| 252 | arg = 1; | ||
| 253 | break; | ||
| 254 | case PIN_CONFIG_OUTPUT: | ||
| 255 | if (dir) | ||
| 256 | return -EINVAL; | ||
| 257 | |||
| 258 | ret = stmfx_gpio_get(&pctl->gpio_chip, pin); | ||
| 259 | if (ret < 0) | ||
| 260 | return ret; | ||
| 261 | |||
| 262 | arg = ret; | ||
| 263 | break; | ||
| 264 | default: | ||
| 265 | return -ENOTSUPP; | ||
| 266 | } | ||
| 267 | |||
| 268 | *config = pinconf_to_config_packed(param, arg); | ||
| 269 | |||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static int stmfx_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, | ||
| 274 | unsigned long *configs, unsigned int num_configs) | ||
| 275 | { | ||
| 276 | struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
| 277 | struct pinctrl_gpio_range *range; | ||
| 278 | enum pin_config_param param; | ||
| 279 | u32 arg; | ||
| 280 | int dir, i, ret; | ||
| 281 | |||
| 282 | range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin); | ||
| 283 | if (!range) { | ||
| 284 | dev_err(pctldev->dev, "pin %d is not available\n", pin); | ||
| 285 | return -EINVAL; | ||
| 286 | } | ||
| 287 | |||
| 288 | dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin); | ||
| 289 | if (dir < 0) | ||
| 290 | return dir; | ||
| 291 | |||
| 292 | for (i = 0; i < num_configs; i++) { | ||
| 293 | param = pinconf_to_config_param(configs[i]); | ||
| 294 | arg = pinconf_to_config_argument(configs[i]); | ||
| 295 | |||
| 296 | switch (param) { | ||
| 297 | case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: | ||
| 298 | case PIN_CONFIG_BIAS_DISABLE: | ||
| 299 | case PIN_CONFIG_BIAS_PULL_DOWN: | ||
| 300 | ret = stmfx_pinconf_set_pupd(pctl, pin, 0); | ||
| 301 | if (ret) | ||
| 302 | return ret; | ||
| 303 | break; | ||
| 304 | case PIN_CONFIG_BIAS_PULL_UP: | ||
| 305 | ret = stmfx_pinconf_set_pupd(pctl, pin, 1); | ||
| 306 | if (ret) | ||
| 307 | return ret; | ||
| 308 | break; | ||
| 309 | case PIN_CONFIG_DRIVE_OPEN_DRAIN: | ||
| 310 | if (!dir) | ||
| 311 | ret = stmfx_pinconf_set_type(pctl, pin, 1); | ||
| 312 | else | ||
| 313 | ret = stmfx_pinconf_set_type(pctl, pin, 0); | ||
| 314 | if (ret) | ||
| 315 | return ret; | ||
| 316 | break; | ||
| 317 | case PIN_CONFIG_DRIVE_PUSH_PULL: | ||
| 318 | if (!dir) | ||
| 319 | ret = stmfx_pinconf_set_type(pctl, pin, 0); | ||
| 320 | else | ||
| 321 | ret = stmfx_pinconf_set_type(pctl, pin, 1); | ||
| 322 | if (ret) | ||
| 323 | return ret; | ||
| 324 | break; | ||
| 325 | case PIN_CONFIG_OUTPUT: | ||
| 326 | ret = stmfx_gpio_direction_output(&pctl->gpio_chip, | ||
| 327 | pin, arg); | ||
| 328 | if (ret) | ||
| 329 | return ret; | ||
| 330 | break; | ||
| 331 | default: | ||
| 332 | return -ENOTSUPP; | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | static void stmfx_pinconf_dbg_show(struct pinctrl_dev *pctldev, | ||
| 340 | struct seq_file *s, unsigned int offset) | ||
| 341 | { | ||
| 342 | struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); | ||
| 343 | struct pinctrl_gpio_range *range; | ||
| 344 | int dir, type, pupd, val; | ||
| 345 | |||
| 346 | range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, offset); | ||
| 347 | if (!range) | ||
| 348 | return; | ||
| 349 | |||
| 350 | dir = stmfx_gpio_get_direction(&pctl->gpio_chip, offset); | ||
| 351 | if (dir < 0) | ||
| 352 | return; | ||
| 353 | type = stmfx_pinconf_get_type(pctl, offset); | ||
| 354 | if (type < 0) | ||
| 355 | return; | ||
| 356 | pupd = stmfx_pinconf_get_pupd(pctl, offset); | ||
| 357 | if (pupd < 0) | ||
| 358 | return; | ||
| 359 | val = stmfx_gpio_get(&pctl->gpio_chip, offset); | ||
| 360 | if (val < 0) | ||
| 361 | return; | ||
| 362 | |||
| 363 | if (!dir) { | ||
| 364 | seq_printf(s, "output %s ", val ? "high" : "low"); | ||
| 365 | if (type) | ||
| 366 | seq_printf(s, "open drain %s internal pull-up ", | ||
| 367 | pupd ? "with" : "without"); | ||
| 368 | else | ||
| 369 | seq_puts(s, "push pull no pull "); | ||
| 370 | } else { | ||
| 371 | seq_printf(s, "input %s ", val ? "high" : "low"); | ||
| 372 | if (type) | ||
| 373 | seq_printf(s, "with internal pull-%s ", | ||
| 374 | pupd ? "up" : "down"); | ||
| 375 | else | ||
| 376 | seq_printf(s, "%s ", pupd ? "floating" : "analog"); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | static const struct pinconf_ops stmfx_pinconf_ops = { | ||
| 381 | .pin_config_get = stmfx_pinconf_get, | ||
| 382 | .pin_config_set = stmfx_pinconf_set, | ||
| 383 | .pin_config_dbg_show = stmfx_pinconf_dbg_show, | ||
| 384 | }; | ||
| 385 | |||
| 386 | static int stmfx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) | ||
| 387 | { | ||
| 388 | return 0; | ||
| 389 | } | ||
| 390 | |||
| 391 | static const char *stmfx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, | ||
| 392 | unsigned int selector) | ||
| 393 | { | ||
| 394 | return NULL; | ||
| 395 | } | ||
| 396 | |||
| 397 | static int stmfx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, | ||
| 398 | unsigned int selector, | ||
| 399 | const unsigned int **pins, | ||
| 400 | unsigned int *num_pins) | ||
| 401 | { | ||
| 402 | return -ENOTSUPP; | ||
| 403 | } | ||
| 404 | |||
| 405 | static const struct pinctrl_ops stmfx_pinctrl_ops = { | ||
| 406 | .get_groups_count = stmfx_pinctrl_get_groups_count, | ||
| 407 | .get_group_name = stmfx_pinctrl_get_group_name, | ||
| 408 | .get_group_pins = stmfx_pinctrl_get_group_pins, | ||
| 409 | .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, | ||
| 410 | .dt_free_map = pinctrl_utils_free_map, | ||
| 411 | }; | ||
| 412 | |||
| 413 | static void stmfx_pinctrl_irq_mask(struct irq_data *data) | ||
| 414 | { | ||
| 415 | struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); | ||
| 416 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); | ||
| 417 | u32 reg = get_reg(data->hwirq); | ||
| 418 | u32 mask = get_mask(data->hwirq); | ||
| 419 | |||
| 420 | pctl->irq_gpi_src[reg] &= ~mask; | ||
| 421 | } | ||
| 422 | |||
| 423 | static void stmfx_pinctrl_irq_unmask(struct irq_data *data) | ||
| 424 | { | ||
| 425 | struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); | ||
| 426 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); | ||
| 427 | u32 reg = get_reg(data->hwirq); | ||
| 428 | u32 mask = get_mask(data->hwirq); | ||
| 429 | |||
| 430 | pctl->irq_gpi_src[reg] |= mask; | ||
| 431 | } | ||
| 432 | |||
| 433 | static int stmfx_pinctrl_irq_set_type(struct irq_data *data, unsigned int type) | ||
| 434 | { | ||
| 435 | struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); | ||
| 436 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); | ||
| 437 | u32 reg = get_reg(data->hwirq); | ||
| 438 | u32 mask = get_mask(data->hwirq); | ||
| 439 | |||
| 440 | if (type == IRQ_TYPE_NONE) | ||
| 441 | return -EINVAL; | ||
| 442 | |||
| 443 | if (type & IRQ_TYPE_EDGE_BOTH) { | ||
| 444 | pctl->irq_gpi_evt[reg] |= mask; | ||
| 445 | irq_set_handler_locked(data, handle_edge_irq); | ||
| 446 | } else { | ||
| 447 | pctl->irq_gpi_evt[reg] &= ~mask; | ||
| 448 | irq_set_handler_locked(data, handle_level_irq); | ||
| 449 | } | ||
| 450 | |||
| 451 | if ((type & IRQ_TYPE_EDGE_RISING) || (type & IRQ_TYPE_LEVEL_HIGH)) | ||
| 452 | pctl->irq_gpi_type[reg] |= mask; | ||
| 453 | else | ||
| 454 | pctl->irq_gpi_type[reg] &= ~mask; | ||
| 455 | |||
| 456 | /* | ||
| 457 | * In case of (type & IRQ_TYPE_EDGE_BOTH), we need to know current | ||
| 458 | * GPIO value to set the right edge trigger. But in atomic context | ||
| 459 | * here we can't access registers over I2C. That's why (type & | ||
| 460 | * IRQ_TYPE_EDGE_BOTH) will be managed in .irq_sync_unlock. | ||
| 461 | */ | ||
| 462 | |||
| 463 | if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) | ||
| 464 | pctl->irq_toggle_edge[reg] |= mask; | ||
| 465 | else | ||
| 466 | pctl->irq_toggle_edge[reg] &= mask; | ||
| 467 | |||
| 468 | return 0; | ||
| 469 | } | ||
| 470 | |||
| 471 | static void stmfx_pinctrl_irq_bus_lock(struct irq_data *data) | ||
| 472 | { | ||
| 473 | struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); | ||
| 474 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); | ||
| 475 | |||
| 476 | mutex_lock(&pctl->lock); | ||
| 477 | } | ||
| 478 | |||
| 479 | static void stmfx_pinctrl_irq_bus_sync_unlock(struct irq_data *data) | ||
| 480 | { | ||
| 481 | struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data); | ||
| 482 | struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip); | ||
| 483 | u32 reg = get_reg(data->hwirq); | ||
| 484 | u32 mask = get_mask(data->hwirq); | ||
| 485 | |||
| 486 | /* | ||
| 487 | * In case of IRQ_TYPE_EDGE_BOTH), read the current GPIO value | ||
| 488 | * (this couldn't be done in .irq_set_type because of atomic context) | ||
| 489 | * to set the right irq trigger type. | ||
| 490 | */ | ||
| 491 | if (pctl->irq_toggle_edge[reg] & mask) { | ||
| 492 | if (stmfx_gpio_get(gpio_chip, data->hwirq)) | ||
| 493 | pctl->irq_gpi_type[reg] &= ~mask; | ||
| 494 | else | ||
| 495 | pctl->irq_gpi_type[reg] |= mask; | ||
| 496 | } | ||
| 497 | |||
| 498 | regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT, | ||
| 499 | pctl->irq_gpi_evt, NR_GPIO_REGS); | ||
| 500 | regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE, | ||
| 501 | pctl->irq_gpi_type, NR_GPIO_REGS); | ||
| 502 | regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, | ||
| 503 | pctl->irq_gpi_src, NR_GPIO_REGS); | ||
| 504 | |||
| 505 | mutex_unlock(&pctl->lock); | ||
| 506 | } | ||
| 507 | |||
| 508 | static void stmfx_pinctrl_irq_toggle_trigger(struct stmfx_pinctrl *pctl, | ||
| 509 | unsigned int offset) | ||
| 510 | { | ||
| 511 | u32 reg = get_reg(offset); | ||
| 512 | u32 mask = get_mask(offset); | ||
| 513 | int val; | ||
| 514 | |||
| 515 | if (!(pctl->irq_toggle_edge[reg] & mask)) | ||
| 516 | return; | ||
| 517 | |||
| 518 | val = stmfx_gpio_get(&pctl->gpio_chip, offset); | ||
| 519 | if (val < 0) | ||
| 520 | return; | ||
| 521 | |||
| 522 | if (val) { | ||
| 523 | pctl->irq_gpi_type[reg] &= mask; | ||
| 524 | regmap_write_bits(pctl->stmfx->map, | ||
| 525 | STMFX_REG_IRQ_GPI_TYPE + reg, | ||
| 526 | mask, 0); | ||
| 527 | |||
| 528 | } else { | ||
| 529 | pctl->irq_gpi_type[reg] |= mask; | ||
| 530 | regmap_write_bits(pctl->stmfx->map, | ||
| 531 | STMFX_REG_IRQ_GPI_TYPE + reg, | ||
| 532 | mask, mask); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id) | ||
| 537 | { | ||
| 538 | struct stmfx_pinctrl *pctl = (struct stmfx_pinctrl *)dev_id; | ||
| 539 | struct gpio_chip *gc = &pctl->gpio_chip; | ||
| 540 | u8 pending[NR_GPIO_REGS]; | ||
| 541 | u8 src[NR_GPIO_REGS] = {0, 0, 0}; | ||
| 542 | unsigned long n, status; | ||
| 543 | int ret; | ||
| 544 | |||
| 545 | ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_IRQ_GPI_PENDING, | ||
| 546 | &pending, NR_GPIO_REGS); | ||
| 547 | if (ret) | ||
| 548 | return IRQ_NONE; | ||
| 549 | |||
| 550 | regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, | ||
| 551 | src, NR_GPIO_REGS); | ||
| 552 | |||
| 553 | status = *(unsigned long *)pending; | ||
| 554 | for_each_set_bit(n, &status, gc->ngpio) { | ||
| 555 | handle_nested_irq(irq_find_mapping(gc->irq.domain, n)); | ||
| 556 | stmfx_pinctrl_irq_toggle_trigger(pctl, n); | ||
| 557 | } | ||
| 558 | |||
| 559 | regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, | ||
| 560 | pctl->irq_gpi_src, NR_GPIO_REGS); | ||
| 561 | |||
| 562 | return IRQ_HANDLED; | ||
| 563 | } | ||
| 564 | |||
| 565 | static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl) | ||
| 566 | { | ||
| 567 | struct pinctrl_gpio_range *gpio_range; | ||
| 568 | struct pinctrl_dev *pctl_dev = pctl->pctl_dev; | ||
| 569 | u32 func = STMFX_FUNC_GPIO; | ||
| 570 | |||
| 571 | pctl->gpio_valid_mask = GENMASK(15, 0); | ||
| 572 | |||
| 573 | gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 16); | ||
| 574 | if (gpio_range) { | ||
| 575 | func |= STMFX_FUNC_ALTGPIO_LOW; | ||
| 576 | pctl->gpio_valid_mask |= GENMASK(19, 16); | ||
| 577 | } | ||
| 578 | |||
| 579 | gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 20); | ||
| 580 | if (gpio_range) { | ||
| 581 | func |= STMFX_FUNC_ALTGPIO_HIGH; | ||
| 582 | pctl->gpio_valid_mask |= GENMASK(23, 20); | ||
| 583 | } | ||
| 584 | |||
| 585 | return stmfx_function_enable(pctl->stmfx, func); | ||
| 586 | } | ||
| 587 | |||
| 588 | static int stmfx_pinctrl_probe(struct platform_device *pdev) | ||
| 589 | { | ||
| 590 | struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent); | ||
| 591 | struct device_node *np = pdev->dev.of_node; | ||
| 592 | struct stmfx_pinctrl *pctl; | ||
| 593 | u32 n; | ||
| 594 | int irq, ret; | ||
| 595 | |||
| 596 | pctl = devm_kzalloc(stmfx->dev, sizeof(*pctl), GFP_KERNEL); | ||
| 597 | if (!pctl) | ||
| 598 | return -ENOMEM; | ||
| 599 | |||
| 600 | platform_set_drvdata(pdev, pctl); | ||
| 601 | |||
| 602 | pctl->dev = &pdev->dev; | ||
| 603 | pctl->stmfx = stmfx; | ||
| 604 | |||
| 605 | if (!of_find_property(np, "gpio-ranges", NULL)) { | ||
| 606 | dev_err(pctl->dev, "missing required gpio-ranges property\n"); | ||
| 607 | return -EINVAL; | ||
| 608 | } | ||
| 609 | |||
| 610 | irq = platform_get_irq(pdev, 0); | ||
| 611 | if (irq <= 0) { | ||
| 612 | dev_err(pctl->dev, "failed to get irq\n"); | ||
| 613 | return -ENXIO; | ||
| 614 | } | ||
| 615 | |||
| 616 | mutex_init(&pctl->lock); | ||
| 617 | |||
| 618 | /* Register pin controller */ | ||
| 619 | pctl->pctl_desc.name = "stmfx-pinctrl"; | ||
| 620 | pctl->pctl_desc.pctlops = &stmfx_pinctrl_ops; | ||
| 621 | pctl->pctl_desc.confops = &stmfx_pinconf_ops; | ||
| 622 | pctl->pctl_desc.pins = stmfx_pins; | ||
| 623 | pctl->pctl_desc.npins = ARRAY_SIZE(stmfx_pins); | ||
| 624 | pctl->pctl_desc.owner = THIS_MODULE; | ||
| 625 | |||
| 626 | ret = devm_pinctrl_register_and_init(pctl->dev, &pctl->pctl_desc, | ||
| 627 | pctl, &pctl->pctl_dev); | ||
| 628 | if (ret) { | ||
| 629 | dev_err(pctl->dev, "pinctrl registration failed\n"); | ||
| 630 | return ret; | ||
| 631 | } | ||
| 632 | |||
| 633 | ret = pinctrl_enable(pctl->pctl_dev); | ||
| 634 | if (ret) { | ||
| 635 | dev_err(pctl->dev, "pinctrl enable failed\n"); | ||
| 636 | return ret; | ||
| 637 | } | ||
| 638 | |||
| 639 | /* Register gpio controller */ | ||
| 640 | pctl->gpio_chip.label = "stmfx-gpio"; | ||
| 641 | pctl->gpio_chip.parent = pctl->dev; | ||
| 642 | pctl->gpio_chip.get_direction = stmfx_gpio_get_direction; | ||
| 643 | pctl->gpio_chip.direction_input = stmfx_gpio_direction_input; | ||
| 644 | pctl->gpio_chip.direction_output = stmfx_gpio_direction_output; | ||
| 645 | pctl->gpio_chip.get = stmfx_gpio_get; | ||
| 646 | pctl->gpio_chip.set = stmfx_gpio_set; | ||
| 647 | pctl->gpio_chip.set_config = gpiochip_generic_config; | ||
| 648 | pctl->gpio_chip.base = -1; | ||
| 649 | pctl->gpio_chip.ngpio = pctl->pctl_desc.npins; | ||
| 650 | pctl->gpio_chip.can_sleep = true; | ||
| 651 | pctl->gpio_chip.of_node = np; | ||
| 652 | pctl->gpio_chip.need_valid_mask = true; | ||
| 653 | |||
| 654 | ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl); | ||
| 655 | if (ret) { | ||
| 656 | dev_err(pctl->dev, "gpio_chip registration failed\n"); | ||
| 657 | return ret; | ||
| 658 | } | ||
| 659 | |||
| 660 | ret = stmfx_pinctrl_gpio_function_enable(pctl); | ||
| 661 | if (ret) | ||
| 662 | return ret; | ||
| 663 | |||
| 664 | pctl->irq_chip.name = dev_name(pctl->dev); | ||
| 665 | pctl->irq_chip.irq_mask = stmfx_pinctrl_irq_mask; | ||
| 666 | pctl->irq_chip.irq_unmask = stmfx_pinctrl_irq_unmask; | ||
| 667 | pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type; | ||
| 668 | pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock; | ||
| 669 | pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock; | ||
| 670 | for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio) | ||
| 671 | clear_bit(n, pctl->gpio_chip.valid_mask); | ||
| 672 | |||
| 673 | ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip, | ||
| 674 | 0, handle_bad_irq, IRQ_TYPE_NONE); | ||
| 675 | if (ret) { | ||
| 676 | dev_err(pctl->dev, "cannot add irqchip to gpiochip\n"); | ||
| 677 | return ret; | ||
| 678 | } | ||
| 679 | |||
| 680 | ret = devm_request_threaded_irq(pctl->dev, irq, NULL, | ||
| 681 | stmfx_pinctrl_irq_thread_fn, | ||
| 682 | IRQF_ONESHOT, | ||
| 683 | pctl->irq_chip.name, pctl); | ||
| 684 | if (ret) { | ||
| 685 | dev_err(pctl->dev, "cannot request irq%d\n", irq); | ||
| 686 | return ret; | ||
| 687 | } | ||
| 688 | |||
| 689 | gpiochip_set_nested_irqchip(&pctl->gpio_chip, &pctl->irq_chip, irq); | ||
| 690 | |||
| 691 | dev_info(pctl->dev, | ||
| 692 | "%ld GPIOs available\n", hweight_long(pctl->gpio_valid_mask)); | ||
| 693 | |||
| 694 | return 0; | ||
| 695 | } | ||
| 696 | |||
| 697 | static int stmfx_pinctrl_remove(struct platform_device *pdev) | ||
| 698 | { | ||
| 699 | struct stmfx *stmfx = dev_get_platdata(&pdev->dev); | ||
| 700 | |||
| 701 | return stmfx_function_disable(stmfx, | ||
| 702 | STMFX_FUNC_GPIO | | ||
| 703 | STMFX_FUNC_ALTGPIO_LOW | | ||
| 704 | STMFX_FUNC_ALTGPIO_HIGH); | ||
| 705 | } | ||
| 706 | |||
| 707 | #ifdef CONFIG_PM_SLEEP | ||
| 708 | static int stmfx_pinctrl_backup_regs(struct stmfx_pinctrl *pctl) | ||
| 709 | { | ||
| 710 | int ret; | ||
| 711 | |||
| 712 | ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_STATE, | ||
| 713 | &pctl->bkp_gpio_state, NR_GPIO_REGS); | ||
| 714 | if (ret) | ||
| 715 | return ret; | ||
| 716 | ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_DIR, | ||
| 717 | &pctl->bkp_gpio_dir, NR_GPIO_REGS); | ||
| 718 | if (ret) | ||
| 719 | return ret; | ||
| 720 | ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_TYPE, | ||
| 721 | &pctl->bkp_gpio_type, NR_GPIO_REGS); | ||
| 722 | if (ret) | ||
| 723 | return ret; | ||
| 724 | ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_PUPD, | ||
| 725 | &pctl->bkp_gpio_pupd, NR_GPIO_REGS); | ||
| 726 | if (ret) | ||
| 727 | return ret; | ||
| 728 | |||
| 729 | return 0; | ||
| 730 | } | ||
| 731 | |||
| 732 | static int stmfx_pinctrl_restore_regs(struct stmfx_pinctrl *pctl) | ||
| 733 | { | ||
| 734 | int ret; | ||
| 735 | |||
| 736 | ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_DIR, | ||
| 737 | pctl->bkp_gpio_dir, NR_GPIO_REGS); | ||
| 738 | if (ret) | ||
| 739 | return ret; | ||
| 740 | ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_TYPE, | ||
| 741 | pctl->bkp_gpio_type, NR_GPIO_REGS); | ||
| 742 | if (ret) | ||
| 743 | return ret; | ||
| 744 | ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_PUPD, | ||
| 745 | pctl->bkp_gpio_pupd, NR_GPIO_REGS); | ||
| 746 | if (ret) | ||
| 747 | return ret; | ||
| 748 | ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPO_SET, | ||
| 749 | pctl->bkp_gpio_state, NR_GPIO_REGS); | ||
| 750 | if (ret) | ||
| 751 | return ret; | ||
| 752 | ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT, | ||
| 753 | pctl->irq_gpi_evt, NR_GPIO_REGS); | ||
| 754 | if (ret) | ||
| 755 | return ret; | ||
| 756 | ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE, | ||
| 757 | pctl->irq_gpi_type, NR_GPIO_REGS); | ||
| 758 | if (ret) | ||
| 759 | return ret; | ||
| 760 | ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC, | ||
| 761 | pctl->irq_gpi_src, NR_GPIO_REGS); | ||
| 762 | if (ret) | ||
| 763 | return ret; | ||
| 764 | |||
| 765 | return 0; | ||
| 766 | } | ||
| 767 | |||
| 768 | static int stmfx_pinctrl_suspend(struct device *dev) | ||
| 769 | { | ||
| 770 | struct stmfx_pinctrl *pctl = dev_get_drvdata(dev); | ||
| 771 | int ret; | ||
| 772 | |||
| 773 | ret = stmfx_pinctrl_backup_regs(pctl); | ||
| 774 | if (ret) { | ||
| 775 | dev_err(pctl->dev, "registers backup failure\n"); | ||
| 776 | return ret; | ||
| 777 | } | ||
| 778 | |||
| 779 | return 0; | ||
| 780 | } | ||
| 781 | |||
| 782 | static int stmfx_pinctrl_resume(struct device *dev) | ||
| 783 | { | ||
| 784 | struct stmfx_pinctrl *pctl = dev_get_drvdata(dev); | ||
| 785 | int ret; | ||
| 786 | |||
| 787 | ret = stmfx_pinctrl_restore_regs(pctl); | ||
| 788 | if (ret) { | ||
| 789 | dev_err(pctl->dev, "registers restoration failure\n"); | ||
| 790 | return ret; | ||
| 791 | } | ||
| 792 | |||
| 793 | return 0; | ||
| 794 | } | ||
| 795 | #endif | ||
| 796 | |||
| 797 | static SIMPLE_DEV_PM_OPS(stmfx_pinctrl_dev_pm_ops, | ||
| 798 | stmfx_pinctrl_suspend, stmfx_pinctrl_resume); | ||
| 799 | |||
| 800 | static const struct of_device_id stmfx_pinctrl_of_match[] = { | ||
| 801 | { .compatible = "st,stmfx-0300-pinctrl", }, | ||
| 802 | {}, | ||
| 803 | }; | ||
| 804 | MODULE_DEVICE_TABLE(of, stmfx_pinctrl_of_match); | ||
| 805 | |||
| 806 | static struct platform_driver stmfx_pinctrl_driver = { | ||
| 807 | .driver = { | ||
| 808 | .name = "stmfx-pinctrl", | ||
| 809 | .of_match_table = stmfx_pinctrl_of_match, | ||
| 810 | .pm = &stmfx_pinctrl_dev_pm_ops, | ||
| 811 | }, | ||
| 812 | .probe = stmfx_pinctrl_probe, | ||
| 813 | .remove = stmfx_pinctrl_remove, | ||
| 814 | }; | ||
| 815 | module_platform_driver(stmfx_pinctrl_driver); | ||
| 816 | |||
| 817 | MODULE_DESCRIPTION("STMFX pinctrl/GPIO driver"); | ||
| 818 | MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>"); | ||
| 819 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 171475862ede..3d2325197a68 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c | |||
| @@ -429,6 +429,12 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev) | |||
| 429 | else | 429 | else |
| 430 | ec_dev->mkbp_event_supported = 1; | 430 | ec_dev->mkbp_event_supported = 1; |
| 431 | 431 | ||
| 432 | /* Probe if host sleep v1 is supported for S0ix failure detection. */ | ||
| 433 | ret = cros_ec_get_host_command_version_mask(ec_dev, | ||
| 434 | EC_CMD_HOST_SLEEP_EVENT, | ||
| 435 | &ver_mask); | ||
| 436 | ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1))); | ||
| 437 | |||
| 432 | /* | 438 | /* |
| 433 | * Get host event wake mask, assume all events are wake events | 439 | * Get host event wake mask, assume all events are wake events |
| 434 | * if unavailable. | 440 | * if unavailable. |
diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index e901b9879e7e..0230c96fa94d 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig | |||
| @@ -499,6 +499,13 @@ config CHARGER_DETECTOR_MAX14656 | |||
| 499 | Revision 1.2 and can be found e.g. in Kindle 4/5th generation | 499 | Revision 1.2 and can be found e.g. in Kindle 4/5th generation |
| 500 | readers and certain LG devices. | 500 | readers and certain LG devices. |
| 501 | 501 | ||
| 502 | config CHARGER_MAX77650 | ||
| 503 | tristate "Maxim MAX77650 battery charger driver" | ||
| 504 | depends on MFD_MAX77650 | ||
| 505 | help | ||
| 506 | Say Y to enable support for the battery charger control of MAX77650 | ||
| 507 | PMICs. | ||
| 508 | |||
| 502 | config CHARGER_MAX77693 | 509 | config CHARGER_MAX77693 |
| 503 | tristate "Maxim MAX77693 battery charger driver" | 510 | tristate "Maxim MAX77693 battery charger driver" |
| 504 | depends on MFD_MAX77693 | 511 | depends on MFD_MAX77693 |
diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index b731c2a9b695..b73eb8c5c1a9 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile | |||
| @@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o | |||
| 70 | obj-$(CONFIG_CHARGER_LTC3651) += ltc3651-charger.o | 70 | obj-$(CONFIG_CHARGER_LTC3651) += ltc3651-charger.o |
| 71 | obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o | 71 | obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o |
| 72 | obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o | 72 | obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o |
| 73 | obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o | ||
| 73 | obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o | 74 | obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o |
| 74 | obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o | 75 | obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o |
| 75 | obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o | 76 | obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o |
diff --git a/drivers/power/supply/max77650-charger.c b/drivers/power/supply/max77650-charger.c new file mode 100644 index 000000000000..e34714cb05ec --- /dev/null +++ b/drivers/power/supply/max77650-charger.c | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | // | ||
| 3 | // Copyright (C) 2018 BayLibre SAS | ||
| 4 | // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
| 5 | // | ||
| 6 | // Battery charger driver for MAXIM 77650/77651 charger/power-supply. | ||
| 7 | |||
| 8 | #include <linux/i2c.h> | ||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/mfd/max77650.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/power_supply.h> | ||
| 14 | #include <linux/regmap.h> | ||
| 15 | |||
| 16 | #define MAX77650_CHARGER_ENABLED BIT(0) | ||
| 17 | #define MAX77650_CHARGER_DISABLED 0x00 | ||
| 18 | #define MAX77650_CHARGER_CHG_EN_MASK BIT(0) | ||
| 19 | |||
| 20 | #define MAX77650_CHG_DETAILS_MASK GENMASK(7, 4) | ||
| 21 | #define MAX77650_CHG_DETAILS_BITS(_reg) \ | ||
| 22 | (((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4) | ||
| 23 | |||
| 24 | /* Charger is OFF. */ | ||
| 25 | #define MAX77650_CHG_OFF 0x00 | ||
| 26 | /* Charger is in prequalification mode. */ | ||
| 27 | #define MAX77650_CHG_PREQ 0x01 | ||
| 28 | /* Charger is in fast-charge constant current mode. */ | ||
| 29 | #define MAX77650_CHG_ON_CURR 0x02 | ||
| 30 | /* Charger is in JEITA modified fast-charge constant-current mode. */ | ||
| 31 | #define MAX77650_CHG_ON_CURR_JEITA 0x03 | ||
| 32 | /* Charger is in fast-charge constant-voltage mode. */ | ||
| 33 | #define MAX77650_CHG_ON_VOLT 0x04 | ||
| 34 | /* Charger is in JEITA modified fast-charge constant-voltage mode. */ | ||
| 35 | #define MAX77650_CHG_ON_VOLT_JEITA 0x05 | ||
| 36 | /* Charger is in top-off mode. */ | ||
| 37 | #define MAX77650_CHG_ON_TOPOFF 0x06 | ||
| 38 | /* Charger is in JEITA modified top-off mode. */ | ||
| 39 | #define MAX77650_CHG_ON_TOPOFF_JEITA 0x07 | ||
| 40 | /* Charger is done. */ | ||
| 41 | #define MAX77650_CHG_DONE 0x08 | ||
| 42 | /* Charger is JEITA modified done. */ | ||
| 43 | #define MAX77650_CHG_DONE_JEITA 0x09 | ||
| 44 | /* Charger is suspended due to a prequalification timer fault. */ | ||
| 45 | #define MAX77650_CHG_SUSP_PREQ_TIM_FAULT 0x0a | ||
| 46 | /* Charger is suspended due to a fast-charge timer fault. */ | ||
| 47 | #define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT 0x0b | ||
| 48 | /* Charger is suspended due to a battery temperature fault. */ | ||
| 49 | #define MAX77650_CHG_SUSP_BATT_TEMP_FAULT 0x0c | ||
| 50 | |||
| 51 | #define MAX77650_CHGIN_DETAILS_MASK GENMASK(3, 2) | ||
| 52 | #define MAX77650_CHGIN_DETAILS_BITS(_reg) \ | ||
| 53 | (((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2) | ||
| 54 | |||
| 55 | #define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT 0x00 | ||
| 56 | #define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT 0x01 | ||
| 57 | #define MAX77650_CHGIN_OKAY 0x11 | ||
| 58 | |||
| 59 | #define MAX77650_CHARGER_CHG_MASK BIT(1) | ||
| 60 | #define MAX77650_CHARGER_CHG_CHARGING(_reg) \ | ||
| 61 | (((_reg) & MAX77650_CHARGER_CHG_MASK) > 1) | ||
| 62 | |||
| 63 | #define MAX77650_CHARGER_VCHGIN_MIN_MASK 0xc0 | ||
| 64 | #define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val) ((_val) << 5) | ||
| 65 | |||
| 66 | #define MAX77650_CHARGER_ICHGIN_LIM_MASK 0x1c | ||
| 67 | #define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val) ((_val) << 2) | ||
| 68 | |||
| 69 | struct max77650_charger_data { | ||
| 70 | struct regmap *map; | ||
| 71 | struct device *dev; | ||
| 72 | }; | ||
| 73 | |||
| 74 | static enum power_supply_property max77650_charger_properties[] = { | ||
| 75 | POWER_SUPPLY_PROP_STATUS, | ||
| 76 | POWER_SUPPLY_PROP_ONLINE, | ||
| 77 | POWER_SUPPLY_PROP_CHARGE_TYPE | ||
| 78 | }; | ||
| 79 | |||
| 80 | static const unsigned int max77650_charger_vchgin_min_table[] = { | ||
| 81 | 4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000 | ||
| 82 | }; | ||
| 83 | |||
| 84 | static const unsigned int max77650_charger_ichgin_lim_table[] = { | ||
| 85 | 95000, 190000, 285000, 380000, 475000 | ||
| 86 | }; | ||
| 87 | |||
| 88 | static int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg, | ||
| 89 | unsigned int val) | ||
| 90 | { | ||
| 91 | int i, rv; | ||
| 92 | |||
| 93 | for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) { | ||
| 94 | if (val == max77650_charger_vchgin_min_table[i]) { | ||
| 95 | rv = regmap_update_bits(chg->map, | ||
| 96 | MAX77650_REG_CNFG_CHG_B, | ||
| 97 | MAX77650_CHARGER_VCHGIN_MIN_MASK, | ||
| 98 | MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i)); | ||
| 99 | if (rv) | ||
| 100 | return rv; | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | return -EINVAL; | ||
| 107 | } | ||
| 108 | |||
| 109 | static int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg, | ||
| 110 | unsigned int val) | ||
| 111 | { | ||
| 112 | int i, rv; | ||
| 113 | |||
| 114 | for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) { | ||
| 115 | if (val == max77650_charger_ichgin_lim_table[i]) { | ||
| 116 | rv = regmap_update_bits(chg->map, | ||
| 117 | MAX77650_REG_CNFG_CHG_B, | ||
| 118 | MAX77650_CHARGER_ICHGIN_LIM_MASK, | ||
| 119 | MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i)); | ||
| 120 | if (rv) | ||
| 121 | return rv; | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | return -EINVAL; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int max77650_charger_enable(struct max77650_charger_data *chg) | ||
| 131 | { | ||
| 132 | int rv; | ||
| 133 | |||
| 134 | rv = regmap_update_bits(chg->map, | ||
| 135 | MAX77650_REG_CNFG_CHG_B, | ||
| 136 | MAX77650_CHARGER_CHG_EN_MASK, | ||
| 137 | MAX77650_CHARGER_ENABLED); | ||
| 138 | if (rv) | ||
| 139 | dev_err(chg->dev, "unable to enable the charger: %d\n", rv); | ||
| 140 | |||
| 141 | return rv; | ||
| 142 | } | ||
| 143 | |||
| 144 | static int max77650_charger_disable(struct max77650_charger_data *chg) | ||
| 145 | { | ||
| 146 | int rv; | ||
| 147 | |||
| 148 | rv = regmap_update_bits(chg->map, | ||
| 149 | MAX77650_REG_CNFG_CHG_B, | ||
| 150 | MAX77650_CHARGER_CHG_EN_MASK, | ||
| 151 | MAX77650_CHARGER_DISABLED); | ||
| 152 | if (rv) | ||
| 153 | dev_err(chg->dev, "unable to disable the charger: %d\n", rv); | ||
| 154 | |||
| 155 | return rv; | ||
| 156 | } | ||
| 157 | |||
| 158 | static irqreturn_t max77650_charger_check_status(int irq, void *data) | ||
| 159 | { | ||
| 160 | struct max77650_charger_data *chg = data; | ||
| 161 | int rv, reg; | ||
| 162 | |||
| 163 | rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); | ||
| 164 | if (rv) { | ||
| 165 | dev_err(chg->dev, | ||
| 166 | "unable to read the charger status: %d\n", rv); | ||
| 167 | return IRQ_HANDLED; | ||
| 168 | } | ||
| 169 | |||
| 170 | switch (MAX77650_CHGIN_DETAILS_BITS(reg)) { | ||
| 171 | case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT: | ||
| 172 | dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n"); | ||
| 173 | max77650_charger_disable(chg); | ||
| 174 | break; | ||
| 175 | case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT: | ||
| 176 | dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n"); | ||
| 177 | max77650_charger_disable(chg); | ||
| 178 | break; | ||
| 179 | case MAX77650_CHGIN_OKAY: | ||
| 180 | max77650_charger_enable(chg); | ||
| 181 | break; | ||
| 182 | default: | ||
| 183 | /* May be 0x10 - debouncing */ | ||
| 184 | break; | ||
| 185 | } | ||
| 186 | |||
| 187 | return IRQ_HANDLED; | ||
| 188 | } | ||
| 189 | |||
| 190 | static int max77650_charger_get_property(struct power_supply *psy, | ||
| 191 | enum power_supply_property psp, | ||
| 192 | union power_supply_propval *val) | ||
| 193 | { | ||
| 194 | struct max77650_charger_data *chg = power_supply_get_drvdata(psy); | ||
| 195 | int rv, reg; | ||
| 196 | |||
| 197 | switch (psp) { | ||
| 198 | case POWER_SUPPLY_PROP_STATUS: | ||
| 199 | rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); | ||
| 200 | if (rv) | ||
| 201 | return rv; | ||
| 202 | |||
| 203 | if (MAX77650_CHARGER_CHG_CHARGING(reg)) { | ||
| 204 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
| 205 | break; | ||
| 206 | } | ||
| 207 | |||
| 208 | switch (MAX77650_CHG_DETAILS_BITS(reg)) { | ||
| 209 | case MAX77650_CHG_OFF: | ||
| 210 | case MAX77650_CHG_SUSP_PREQ_TIM_FAULT: | ||
| 211 | case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT: | ||
| 212 | case MAX77650_CHG_SUSP_BATT_TEMP_FAULT: | ||
| 213 | val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; | ||
| 214 | break; | ||
| 215 | case MAX77650_CHG_PREQ: | ||
| 216 | case MAX77650_CHG_ON_CURR: | ||
| 217 | case MAX77650_CHG_ON_CURR_JEITA: | ||
| 218 | case MAX77650_CHG_ON_VOLT: | ||
| 219 | case MAX77650_CHG_ON_VOLT_JEITA: | ||
| 220 | case MAX77650_CHG_ON_TOPOFF: | ||
| 221 | case MAX77650_CHG_ON_TOPOFF_JEITA: | ||
| 222 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
| 223 | break; | ||
| 224 | case MAX77650_CHG_DONE: | ||
| 225 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
| 226 | break; | ||
| 227 | default: | ||
| 228 | val->intval = POWER_SUPPLY_STATUS_UNKNOWN; | ||
| 229 | } | ||
| 230 | break; | ||
| 231 | case POWER_SUPPLY_PROP_ONLINE: | ||
| 232 | rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); | ||
| 233 | if (rv) | ||
| 234 | return rv; | ||
| 235 | |||
| 236 | val->intval = MAX77650_CHARGER_CHG_CHARGING(reg); | ||
| 237 | break; | ||
| 238 | case POWER_SUPPLY_PROP_CHARGE_TYPE: | ||
| 239 | rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®); | ||
| 240 | if (rv) | ||
| 241 | return rv; | ||
| 242 | |||
| 243 | if (!MAX77650_CHARGER_CHG_CHARGING(reg)) { | ||
| 244 | val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE; | ||
| 245 | break; | ||
| 246 | } | ||
| 247 | |||
| 248 | switch (MAX77650_CHG_DETAILS_BITS(reg)) { | ||
| 249 | case MAX77650_CHG_PREQ: | ||
| 250 | case MAX77650_CHG_ON_CURR: | ||
| 251 | case MAX77650_CHG_ON_CURR_JEITA: | ||
| 252 | case MAX77650_CHG_ON_VOLT: | ||
| 253 | case MAX77650_CHG_ON_VOLT_JEITA: | ||
| 254 | val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST; | ||
| 255 | break; | ||
| 256 | case MAX77650_CHG_ON_TOPOFF: | ||
| 257 | case MAX77650_CHG_ON_TOPOFF_JEITA: | ||
| 258 | val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; | ||
| 259 | break; | ||
| 260 | default: | ||
| 261 | val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; | ||
| 262 | } | ||
| 263 | break; | ||
| 264 | default: | ||
| 265 | return -EINVAL; | ||
| 266 | } | ||
| 267 | |||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | static const struct power_supply_desc max77650_battery_desc = { | ||
| 272 | .name = "max77650", | ||
| 273 | .type = POWER_SUPPLY_TYPE_USB, | ||
| 274 | .get_property = max77650_charger_get_property, | ||
| 275 | .properties = max77650_charger_properties, | ||
| 276 | .num_properties = ARRAY_SIZE(max77650_charger_properties), | ||
| 277 | }; | ||
| 278 | |||
| 279 | static int max77650_charger_probe(struct platform_device *pdev) | ||
| 280 | { | ||
| 281 | struct power_supply_config pscfg = {}; | ||
| 282 | struct max77650_charger_data *chg; | ||
| 283 | struct power_supply *battery; | ||
| 284 | struct device *dev, *parent; | ||
| 285 | int rv, chg_irq, chgin_irq; | ||
| 286 | unsigned int prop; | ||
| 287 | |||
| 288 | dev = &pdev->dev; | ||
| 289 | parent = dev->parent; | ||
| 290 | |||
| 291 | chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL); | ||
| 292 | if (!chg) | ||
| 293 | return -ENOMEM; | ||
| 294 | |||
| 295 | platform_set_drvdata(pdev, chg); | ||
| 296 | |||
| 297 | chg->map = dev_get_regmap(parent, NULL); | ||
| 298 | if (!chg->map) | ||
| 299 | return -ENODEV; | ||
| 300 | |||
| 301 | chg->dev = dev; | ||
| 302 | |||
| 303 | pscfg.of_node = dev->of_node; | ||
| 304 | pscfg.drv_data = chg; | ||
| 305 | |||
| 306 | chg_irq = platform_get_irq_byname(pdev, "CHG"); | ||
| 307 | if (chg_irq < 0) | ||
| 308 | return chg_irq; | ||
| 309 | |||
| 310 | chgin_irq = platform_get_irq_byname(pdev, "CHGIN"); | ||
| 311 | if (chgin_irq < 0) | ||
| 312 | return chgin_irq; | ||
| 313 | |||
| 314 | rv = devm_request_any_context_irq(dev, chg_irq, | ||
| 315 | max77650_charger_check_status, | ||
| 316 | IRQF_ONESHOT, "chg", chg); | ||
| 317 | if (rv < 0) | ||
| 318 | return rv; | ||
| 319 | |||
| 320 | rv = devm_request_any_context_irq(dev, chgin_irq, | ||
| 321 | max77650_charger_check_status, | ||
| 322 | IRQF_ONESHOT, "chgin", chg); | ||
| 323 | if (rv < 0) | ||
| 324 | return rv; | ||
| 325 | |||
| 326 | battery = devm_power_supply_register(dev, | ||
| 327 | &max77650_battery_desc, &pscfg); | ||
| 328 | if (IS_ERR(battery)) | ||
| 329 | return PTR_ERR(battery); | ||
| 330 | |||
| 331 | rv = of_property_read_u32(dev->of_node, | ||
| 332 | "input-voltage-min-microvolt", &prop); | ||
| 333 | if (rv == 0) { | ||
| 334 | rv = max77650_charger_set_vchgin_min(chg, prop); | ||
| 335 | if (rv) | ||
| 336 | return rv; | ||
| 337 | } | ||
| 338 | |||
| 339 | rv = of_property_read_u32(dev->of_node, | ||
| 340 | "input-current-limit-microamp", &prop); | ||
| 341 | if (rv == 0) { | ||
| 342 | rv = max77650_charger_set_ichgin_lim(chg, prop); | ||
| 343 | if (rv) | ||
| 344 | return rv; | ||
| 345 | } | ||
| 346 | |||
| 347 | return max77650_charger_enable(chg); | ||
| 348 | } | ||
| 349 | |||
| 350 | static int max77650_charger_remove(struct platform_device *pdev) | ||
| 351 | { | ||
| 352 | struct max77650_charger_data *chg = platform_get_drvdata(pdev); | ||
| 353 | |||
| 354 | return max77650_charger_disable(chg); | ||
| 355 | } | ||
| 356 | |||
| 357 | static struct platform_driver max77650_charger_driver = { | ||
| 358 | .driver = { | ||
| 359 | .name = "max77650-charger", | ||
| 360 | }, | ||
| 361 | .probe = max77650_charger_probe, | ||
| 362 | .remove = max77650_charger_remove, | ||
| 363 | }; | ||
| 364 | module_platform_driver(max77650_charger_driver); | ||
| 365 | |||
| 366 | MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver"); | ||
| 367 | MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); | ||
| 368 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/include/linux/mfd/altera-sysmgr.h b/include/linux/mfd/altera-sysmgr.h new file mode 100644 index 000000000000..b1ef11a83872 --- /dev/null +++ b/include/linux/mfd/altera-sysmgr.h | |||
| @@ -0,0 +1,29 @@ | |||
| 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 | |||
| 8 | #ifndef __LINUX_MFD_ALTERA_SYSMGR_H__ | ||
| 9 | #define __LINUX_MFD_ALTERA_SYSMGR_H__ | ||
| 10 | |||
| 11 | #include <linux/err.h> | ||
| 12 | #include <linux/errno.h> | ||
| 13 | #include <linux/firmware/intel/stratix10-smc.h> | ||
| 14 | |||
| 15 | struct device_node; | ||
| 16 | |||
| 17 | #ifdef CONFIG_MFD_ALTERA_SYSMGR | ||
| 18 | struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, | ||
| 19 | const char *property); | ||
| 20 | #else | ||
| 21 | static inline struct regmap * | ||
| 22 | altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np, | ||
| 23 | const char *property) | ||
| 24 | { | ||
| 25 | return ERR_PTR(-ENOTSUPP); | ||
| 26 | } | ||
| 27 | #endif | ||
| 28 | |||
| 29 | #endif /* __LINUX_MFD_ALTERA_SYSMGR_H__ */ | ||
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h index 8f2a8918bfa3..cfa78bb4990f 100644 --- a/include/linux/mfd/cros_ec.h +++ b/include/linux/mfd/cros_ec.h | |||
| @@ -23,7 +23,10 @@ | |||
| 23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
| 24 | 24 | ||
| 25 | #define CROS_EC_DEV_NAME "cros_ec" | 25 | #define CROS_EC_DEV_NAME "cros_ec" |
| 26 | #define CROS_EC_DEV_FP_NAME "cros_fp" | ||
| 26 | #define CROS_EC_DEV_PD_NAME "cros_pd" | 27 | #define CROS_EC_DEV_PD_NAME "cros_pd" |
| 28 | #define CROS_EC_DEV_TP_NAME "cros_tp" | ||
| 29 | #define CROS_EC_DEV_ISH_NAME "cros_ish" | ||
| 27 | 30 | ||
| 28 | /* | 31 | /* |
| 29 | * The EC is unresponsive for a time after a reboot command. Add a | 32 | * The EC is unresponsive for a time after a reboot command. Add a |
| @@ -120,6 +123,7 @@ struct cros_ec_command { | |||
| 120 | * @pkt_xfer: Send packet to EC and get response. | 123 | * @pkt_xfer: Send packet to EC and get response. |
| 121 | * @lock: One transaction at a time. | 124 | * @lock: One transaction at a time. |
| 122 | * @mkbp_event_supported: True if this EC supports the MKBP event protocol. | 125 | * @mkbp_event_supported: True if this EC supports the MKBP event protocol. |
| 126 | * @host_sleep_v1: True if this EC supports the sleep v1 command. | ||
| 123 | * @event_notifier: Interrupt event notifier for transport devices. | 127 | * @event_notifier: Interrupt event notifier for transport devices. |
| 124 | * @event_data: Raw payload transferred with the MKBP event. | 128 | * @event_data: Raw payload transferred with the MKBP event. |
| 125 | * @event_size: Size in bytes of the event data. | 129 | * @event_size: Size in bytes of the event data. |
| @@ -153,6 +157,7 @@ struct cros_ec_device { | |||
| 153 | struct cros_ec_command *msg); | 157 | struct cros_ec_command *msg); |
| 154 | struct mutex lock; | 158 | struct mutex lock; |
| 155 | bool mkbp_event_supported; | 159 | bool mkbp_event_supported; |
| 160 | bool host_sleep_v1; | ||
| 156 | struct blocking_notifier_head event_notifier; | 161 | struct blocking_notifier_head event_notifier; |
| 157 | 162 | ||
| 158 | struct ec_response_get_next_event_v1 event_data; | 163 | struct ec_response_get_next_event_v1 event_data; |
diff --git a/include/linux/mfd/cros_ec_commands.h b/include/linux/mfd/cros_ec_commands.h index fc91082d4c35..dcec96f01879 100644 --- a/include/linux/mfd/cros_ec_commands.h +++ b/include/linux/mfd/cros_ec_commands.h | |||
| @@ -840,7 +840,7 @@ enum ec_feature_code { | |||
| 840 | * (Common Smart Battery System Interface Specification) | 840 | * (Common Smart Battery System Interface Specification) |
| 841 | */ | 841 | */ |
| 842 | EC_FEATURE_SMART_BATTERY = 18, | 842 | EC_FEATURE_SMART_BATTERY = 18, |
| 843 | /* EC can dectect when the host hangs. */ | 843 | /* EC can detect when the host hangs. */ |
| 844 | EC_FEATURE_HANG_DETECT = 19, | 844 | EC_FEATURE_HANG_DETECT = 19, |
| 845 | /* Report power information, for pit only */ | 845 | /* Report power information, for pit only */ |
| 846 | EC_FEATURE_PMU = 20, | 846 | EC_FEATURE_PMU = 20, |
| @@ -852,10 +852,42 @@ enum ec_feature_code { | |||
| 852 | EC_FEATURE_USB_MUX = 23, | 852 | EC_FEATURE_USB_MUX = 23, |
| 853 | /* Motion Sensor code has an internal software FIFO */ | 853 | /* Motion Sensor code has an internal software FIFO */ |
| 854 | EC_FEATURE_MOTION_SENSE_FIFO = 24, | 854 | EC_FEATURE_MOTION_SENSE_FIFO = 24, |
| 855 | /* Support temporary secure vstore */ | ||
| 856 | EC_FEATURE_VSTORE = 25, | ||
| 857 | /* EC decides on USB-C SS mux state, muxes configured by host */ | ||
| 858 | EC_FEATURE_USBC_SS_MUX_VIRTUAL = 26, | ||
| 855 | /* EC has RTC feature that can be controlled by host commands */ | 859 | /* EC has RTC feature that can be controlled by host commands */ |
| 856 | EC_FEATURE_RTC = 27, | 860 | EC_FEATURE_RTC = 27, |
| 861 | /* The MCU exposes a Fingerprint sensor */ | ||
| 862 | EC_FEATURE_FINGERPRINT = 28, | ||
| 863 | /* The MCU exposes a Touchpad */ | ||
| 864 | EC_FEATURE_TOUCHPAD = 29, | ||
| 865 | /* The MCU has RWSIG task enabled */ | ||
| 866 | EC_FEATURE_RWSIG = 30, | ||
| 867 | /* EC has device events support */ | ||
| 868 | EC_FEATURE_DEVICE_EVENT = 31, | ||
| 869 | /* EC supports the unified wake masks for LPC/eSPI systems */ | ||
| 870 | EC_FEATURE_UNIFIED_WAKE_MASKS = 32, | ||
| 871 | /* EC supports 64-bit host events */ | ||
| 872 | EC_FEATURE_HOST_EVENT64 = 33, | ||
| 873 | /* EC runs code in RAM (not in place, a.k.a. XIP) */ | ||
| 874 | EC_FEATURE_EXEC_IN_RAM = 34, | ||
| 857 | /* EC supports CEC commands */ | 875 | /* EC supports CEC commands */ |
| 858 | EC_FEATURE_CEC = 35, | 876 | EC_FEATURE_CEC = 35, |
| 877 | /* EC supports tight sensor timestamping. */ | ||
| 878 | EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36, | ||
| 879 | /* | ||
| 880 | * EC supports tablet mode detection aligned to Chrome and allows | ||
| 881 | * setting of threshold by host command using | ||
| 882 | * MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE. | ||
| 883 | */ | ||
| 884 | EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37, | ||
| 885 | /* EC supports audio codec. */ | ||
| 886 | EC_FEATURE_AUDIO_CODEC = 38, | ||
| 887 | /* EC Supports SCP. */ | ||
| 888 | EC_FEATURE_SCP = 39, | ||
| 889 | /* The MCU is an Integrated Sensor Hub */ | ||
| 890 | EC_FEATURE_ISH = 40, | ||
| 859 | }; | 891 | }; |
| 860 | 892 | ||
| 861 | #define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32)) | 893 | #define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32)) |
| @@ -2729,6 +2761,63 @@ struct ec_params_host_sleep_event { | |||
| 2729 | uint8_t sleep_event; | 2761 | uint8_t sleep_event; |
| 2730 | } __packed; | 2762 | } __packed; |
| 2731 | 2763 | ||
| 2764 | /* | ||
| 2765 | * Use a default timeout value (CONFIG_SLEEP_TIMEOUT_MS) for detecting sleep | ||
| 2766 | * transition failures | ||
| 2767 | */ | ||
| 2768 | #define EC_HOST_SLEEP_TIMEOUT_DEFAULT 0 | ||
| 2769 | |||
| 2770 | /* Disable timeout detection for this sleep transition */ | ||
| 2771 | #define EC_HOST_SLEEP_TIMEOUT_INFINITE 0xFFFF | ||
| 2772 | |||
| 2773 | struct ec_params_host_sleep_event_v1 { | ||
| 2774 | /* The type of sleep being entered or exited. */ | ||
| 2775 | uint8_t sleep_event; | ||
| 2776 | |||
| 2777 | /* Padding */ | ||
| 2778 | uint8_t reserved; | ||
| 2779 | union { | ||
| 2780 | /* Parameters that apply for suspend messages. */ | ||
| 2781 | struct { | ||
| 2782 | /* | ||
| 2783 | * The timeout in milliseconds between when this message | ||
| 2784 | * is received and when the EC will declare sleep | ||
| 2785 | * transition failure if the sleep signal is not | ||
| 2786 | * asserted. | ||
| 2787 | */ | ||
| 2788 | uint16_t sleep_timeout_ms; | ||
| 2789 | } suspend_params; | ||
| 2790 | |||
| 2791 | /* No parameters for non-suspend messages. */ | ||
| 2792 | }; | ||
| 2793 | } __packed; | ||
| 2794 | |||
| 2795 | /* A timeout occurred when this bit is set */ | ||
| 2796 | #define EC_HOST_RESUME_SLEEP_TIMEOUT 0x80000000 | ||
| 2797 | |||
| 2798 | /* | ||
| 2799 | * The mask defining which bits correspond to the number of sleep transitions, | ||
| 2800 | * as well as the maximum number of suspend line transitions that will be | ||
| 2801 | * reported back to the host. | ||
| 2802 | */ | ||
| 2803 | #define EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK 0x7FFFFFFF | ||
| 2804 | |||
| 2805 | struct ec_response_host_sleep_event_v1 { | ||
| 2806 | union { | ||
| 2807 | /* Response fields that apply for resume messages. */ | ||
| 2808 | struct { | ||
| 2809 | /* | ||
| 2810 | * The number of sleep power signal transitions that | ||
| 2811 | * occurred since the suspend message. The high bit | ||
| 2812 | * indicates a timeout occurred. | ||
| 2813 | */ | ||
| 2814 | uint32_t sleep_transitions; | ||
| 2815 | } resume_response; | ||
| 2816 | |||
| 2817 | /* No response fields for non-resume messages. */ | ||
| 2818 | }; | ||
| 2819 | } __packed; | ||
| 2820 | |||
| 2732 | /*****************************************************************************/ | 2821 | /*****************************************************************************/ |
| 2733 | /* Smart battery pass-through */ | 2822 | /* Smart battery pass-through */ |
| 2734 | 2823 | ||
diff --git a/include/linux/mfd/da9063/core.h b/include/linux/mfd/da9063/core.h index 71b09154e2db..5cd06ab26352 100644 --- a/include/linux/mfd/da9063/core.h +++ b/include/linux/mfd/da9063/core.h | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
| 1 | /* | 2 | /* |
| 2 | * Definitions for DA9063 MFD driver | 3 | * Definitions for DA9063 MFD driver |
| 3 | * | 4 | * |
| @@ -5,12 +6,6 @@ | |||
| 5 | * | 6 | * |
| 6 | * Author: Michal Hajduk, Dialog Semiconductor | 7 | * Author: Michal Hajduk, Dialog Semiconductor |
| 7 | * Author: Krystian Garbaciak, Dialog Semiconductor | 8 | * Author: Krystian Garbaciak, Dialog Semiconductor |
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the | ||
| 11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 12 | * option) any later version. | ||
| 13 | * | ||
| 14 | */ | 9 | */ |
| 15 | 10 | ||
| 16 | #ifndef __MFD_DA9063_CORE_H__ | 11 | #ifndef __MFD_DA9063_CORE_H__ |
diff --git a/include/linux/mfd/da9063/registers.h b/include/linux/mfd/da9063/registers.h index 5d42859cb441..ba706b0e28c2 100644 --- a/include/linux/mfd/da9063/registers.h +++ b/include/linux/mfd/da9063/registers.h | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
| 1 | /* | 2 | /* |
| 2 | * Registers definition for DA9063 modules | 3 | * Registers definition for DA9063 modules |
| 3 | * | 4 | * |
| @@ -5,12 +6,6 @@ | |||
| 5 | * | 6 | * |
| 6 | * Author: Michal Hajduk, Dialog Semiconductor | 7 | * Author: Michal Hajduk, Dialog Semiconductor |
| 7 | * Author: Krystian Garbaciak, Dialog Semiconductor | 8 | * Author: Krystian Garbaciak, Dialog Semiconductor |
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by the | ||
| 11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 12 | * option) any later version. | ||
| 13 | * | ||
| 14 | */ | 9 | */ |
| 15 | 10 | ||
| 16 | #ifndef _DA9063_REG_H | 11 | #ifndef _DA9063_REG_H |
| @@ -215,9 +210,9 @@ | |||
| 215 | 210 | ||
| 216 | /* DA9063 Configuration registers */ | 211 | /* DA9063 Configuration registers */ |
| 217 | /* OTP */ | 212 | /* OTP */ |
| 218 | #define DA9063_REG_OPT_COUNT 0x101 | 213 | #define DA9063_REG_OTP_CONT 0x101 |
| 219 | #define DA9063_REG_OPT_ADDR 0x102 | 214 | #define DA9063_REG_OTP_ADDR 0x102 |
| 220 | #define DA9063_REG_OPT_DATA 0x103 | 215 | #define DA9063_REG_OTP_DATA 0x103 |
| 221 | 216 | ||
| 222 | /* Customer Trim and Configuration */ | 217 | /* Customer Trim and Configuration */ |
| 223 | #define DA9063_REG_T_OFFSET 0x104 | 218 | #define DA9063_REG_T_OFFSET 0x104 |
diff --git a/include/linux/mfd/max77620.h b/include/linux/mfd/max77620.h index ad2a9a852aea..82407fe85ca2 100644 --- a/include/linux/mfd/max77620.h +++ b/include/linux/mfd/max77620.h | |||
| @@ -136,8 +136,8 @@ | |||
| 136 | #define MAX77620_FPS_PERIOD_MIN_US 40 | 136 | #define MAX77620_FPS_PERIOD_MIN_US 40 |
| 137 | #define MAX20024_FPS_PERIOD_MIN_US 20 | 137 | #define MAX20024_FPS_PERIOD_MIN_US 20 |
| 138 | 138 | ||
| 139 | #define MAX77620_FPS_PERIOD_MAX_US 2560 | 139 | #define MAX20024_FPS_PERIOD_MAX_US 2560 |
| 140 | #define MAX20024_FPS_PERIOD_MAX_US 5120 | 140 | #define MAX77620_FPS_PERIOD_MAX_US 5120 |
| 141 | 141 | ||
| 142 | #define MAX77620_REG_FPS_GPIO1 0x54 | 142 | #define MAX77620_REG_FPS_GPIO1 0x54 |
| 143 | #define MAX77620_REG_FPS_GPIO2 0x55 | 143 | #define MAX77620_REG_FPS_GPIO2 0x55 |
| @@ -324,6 +324,7 @@ enum max77620_fps_src { | |||
| 324 | enum max77620_chip_id { | 324 | enum max77620_chip_id { |
| 325 | MAX77620, | 325 | MAX77620, |
| 326 | MAX20024, | 326 | MAX20024, |
| 327 | MAX77663, | ||
| 327 | }; | 328 | }; |
| 328 | 329 | ||
| 329 | struct max77620_chip { | 330 | struct max77620_chip { |
diff --git a/include/linux/mfd/max77650.h b/include/linux/mfd/max77650.h new file mode 100644 index 000000000000..c809e211a8cd --- /dev/null +++ b/include/linux/mfd/max77650.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2018 BayLibre SAS | ||
| 4 | * Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> | ||
| 5 | * | ||
| 6 | * Common definitions for MAXIM 77650/77651 charger/power-supply. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef MAX77650_H | ||
| 10 | #define MAX77650_H | ||
| 11 | |||
| 12 | #include <linux/bits.h> | ||
| 13 | |||
| 14 | #define MAX77650_REG_INT_GLBL 0x00 | ||
| 15 | #define MAX77650_REG_INT_CHG 0x01 | ||
| 16 | #define MAX77650_REG_STAT_CHG_A 0x02 | ||
| 17 | #define MAX77650_REG_STAT_CHG_B 0x03 | ||
| 18 | #define MAX77650_REG_ERCFLAG 0x04 | ||
| 19 | #define MAX77650_REG_STAT_GLBL 0x05 | ||
| 20 | #define MAX77650_REG_INTM_GLBL 0x06 | ||
| 21 | #define MAX77650_REG_INTM_CHG 0x07 | ||
| 22 | #define MAX77650_REG_CNFG_GLBL 0x10 | ||
| 23 | #define MAX77650_REG_CID 0x11 | ||
| 24 | #define MAX77650_REG_CNFG_GPIO 0x12 | ||
| 25 | #define MAX77650_REG_CNFG_CHG_A 0x18 | ||
| 26 | #define MAX77650_REG_CNFG_CHG_B 0x19 | ||
| 27 | #define MAX77650_REG_CNFG_CHG_C 0x1a | ||
| 28 | #define MAX77650_REG_CNFG_CHG_D 0x1b | ||
| 29 | #define MAX77650_REG_CNFG_CHG_E 0x1c | ||
| 30 | #define MAX77650_REG_CNFG_CHG_F 0x1d | ||
| 31 | #define MAX77650_REG_CNFG_CHG_G 0x1e | ||
| 32 | #define MAX77650_REG_CNFG_CHG_H 0x1f | ||
| 33 | #define MAX77650_REG_CNFG_CHG_I 0x20 | ||
| 34 | #define MAX77650_REG_CNFG_SBB_TOP 0x28 | ||
| 35 | #define MAX77650_REG_CNFG_SBB0_A 0x29 | ||
| 36 | #define MAX77650_REG_CNFG_SBB0_B 0x2a | ||
| 37 | #define MAX77650_REG_CNFG_SBB1_A 0x2b | ||
| 38 | #define MAX77650_REG_CNFG_SBB1_B 0x2c | ||
| 39 | #define MAX77650_REG_CNFG_SBB2_A 0x2d | ||
| 40 | #define MAX77650_REG_CNFG_SBB2_B 0x2e | ||
| 41 | #define MAX77650_REG_CNFG_LDO_A 0x38 | ||
| 42 | #define MAX77650_REG_CNFG_LDO_B 0x39 | ||
| 43 | #define MAX77650_REG_CNFG_LED0_A 0x40 | ||
| 44 | #define MAX77650_REG_CNFG_LED1_A 0x41 | ||
| 45 | #define MAX77650_REG_CNFG_LED2_A 0x42 | ||
| 46 | #define MAX77650_REG_CNFG_LED0_B 0x43 | ||
| 47 | #define MAX77650_REG_CNFG_LED1_B 0x44 | ||
| 48 | #define MAX77650_REG_CNFG_LED2_B 0x45 | ||
| 49 | #define MAX77650_REG_CNFG_LED_TOP 0x46 | ||
| 50 | |||
| 51 | #define MAX77650_CID_MASK GENMASK(3, 0) | ||
| 52 | #define MAX77650_CID_BITS(_reg) (_reg & MAX77650_CID_MASK) | ||
| 53 | |||
| 54 | #define MAX77650_CID_77650A 0x03 | ||
| 55 | #define MAX77650_CID_77650C 0x0a | ||
| 56 | #define MAX77650_CID_77651A 0x06 | ||
| 57 | #define MAX77650_CID_77651B 0x08 | ||
| 58 | |||
| 59 | #endif /* MAX77650_H */ | ||
diff --git a/include/linux/mfd/stmfx.h b/include/linux/mfd/stmfx.h new file mode 100644 index 000000000000..d890595b89b6 --- /dev/null +++ b/include/linux/mfd/stmfx.h | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2019 STMicroelectronics | ||
| 4 | * Author(s): Amelie Delaunay <amelie.delaunay@st.com>. | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef MFD_STMFX_H | ||
| 8 | #define MFX_STMFX_H | ||
| 9 | |||
| 10 | #include <linux/regmap.h> | ||
| 11 | |||
| 12 | /* General */ | ||
| 13 | #define STMFX_REG_CHIP_ID 0x00 /* R */ | ||
| 14 | #define STMFX_REG_FW_VERSION_MSB 0x01 /* R */ | ||
| 15 | #define STMFX_REG_FW_VERSION_LSB 0x02 /* R */ | ||
| 16 | #define STMFX_REG_SYS_CTRL 0x40 /* RW */ | ||
| 17 | /* IRQ output management */ | ||
| 18 | #define STMFX_REG_IRQ_OUT_PIN 0x41 /* RW */ | ||
| 19 | #define STMFX_REG_IRQ_SRC_EN 0x42 /* RW */ | ||
| 20 | #define STMFX_REG_IRQ_PENDING 0x08 /* R */ | ||
| 21 | #define STMFX_REG_IRQ_ACK 0x44 /* RW */ | ||
| 22 | /* GPIO management */ | ||
| 23 | #define STMFX_REG_IRQ_GPI_PENDING1 0x0C /* R */ | ||
| 24 | #define STMFX_REG_IRQ_GPI_PENDING2 0x0D /* R */ | ||
| 25 | #define STMFX_REG_IRQ_GPI_PENDING3 0x0E /* R */ | ||
| 26 | #define STMFX_REG_GPIO_STATE1 0x10 /* R */ | ||
| 27 | #define STMFX_REG_GPIO_STATE2 0x11 /* R */ | ||
| 28 | #define STMFX_REG_GPIO_STATE3 0x12 /* R */ | ||
| 29 | #define STMFX_REG_IRQ_GPI_SRC1 0x48 /* RW */ | ||
| 30 | #define STMFX_REG_IRQ_GPI_SRC2 0x49 /* RW */ | ||
| 31 | #define STMFX_REG_IRQ_GPI_SRC3 0x4A /* RW */ | ||
| 32 | #define STMFX_REG_IRQ_GPI_EVT1 0x4C /* RW */ | ||
| 33 | #define STMFX_REG_IRQ_GPI_EVT2 0x4D /* RW */ | ||
| 34 | #define STMFX_REG_IRQ_GPI_EVT3 0x4E /* RW */ | ||
| 35 | #define STMFX_REG_IRQ_GPI_TYPE1 0x50 /* RW */ | ||
| 36 | #define STMFX_REG_IRQ_GPI_TYPE2 0x51 /* RW */ | ||
| 37 | #define STMFX_REG_IRQ_GPI_TYPE3 0x52 /* RW */ | ||
| 38 | #define STMFX_REG_IRQ_GPI_ACK1 0x54 /* RW */ | ||
| 39 | #define STMFX_REG_IRQ_GPI_ACK2 0x55 /* RW */ | ||
| 40 | #define STMFX_REG_IRQ_GPI_ACK3 0x56 /* RW */ | ||
| 41 | #define STMFX_REG_GPIO_DIR1 0x60 /* RW */ | ||
| 42 | #define STMFX_REG_GPIO_DIR2 0x61 /* RW */ | ||
| 43 | #define STMFX_REG_GPIO_DIR3 0x62 /* RW */ | ||
| 44 | #define STMFX_REG_GPIO_TYPE1 0x64 /* RW */ | ||
| 45 | #define STMFX_REG_GPIO_TYPE2 0x65 /* RW */ | ||
| 46 | #define STMFX_REG_GPIO_TYPE3 0x66 /* RW */ | ||
| 47 | #define STMFX_REG_GPIO_PUPD1 0x68 /* RW */ | ||
| 48 | #define STMFX_REG_GPIO_PUPD2 0x69 /* RW */ | ||
| 49 | #define STMFX_REG_GPIO_PUPD3 0x6A /* RW */ | ||
| 50 | #define STMFX_REG_GPO_SET1 0x6C /* RW */ | ||
| 51 | #define STMFX_REG_GPO_SET2 0x6D /* RW */ | ||
| 52 | #define STMFX_REG_GPO_SET3 0x6E /* RW */ | ||
| 53 | #define STMFX_REG_GPO_CLR1 0x70 /* RW */ | ||
| 54 | #define STMFX_REG_GPO_CLR2 0x71 /* RW */ | ||
| 55 | #define STMFX_REG_GPO_CLR3 0x72 /* RW */ | ||
| 56 | |||
| 57 | #define STMFX_REG_MAX 0xB0 | ||
| 58 | |||
| 59 | /* MFX boot time is around 10ms, so after reset, we have to wait this delay */ | ||
| 60 | #define STMFX_BOOT_TIME_MS 10 | ||
| 61 | |||
| 62 | /* STMFX_REG_CHIP_ID bitfields */ | ||
| 63 | #define STMFX_REG_CHIP_ID_MASK GENMASK(7, 0) | ||
| 64 | |||
| 65 | /* STMFX_REG_SYS_CTRL bitfields */ | ||
| 66 | #define STMFX_REG_SYS_CTRL_GPIO_EN BIT(0) | ||
| 67 | #define STMFX_REG_SYS_CTRL_TS_EN BIT(1) | ||
| 68 | #define STMFX_REG_SYS_CTRL_IDD_EN BIT(2) | ||
| 69 | #define STMFX_REG_SYS_CTRL_ALTGPIO_EN BIT(3) | ||
| 70 | #define STMFX_REG_SYS_CTRL_SWRST BIT(7) | ||
| 71 | |||
| 72 | /* STMFX_REG_IRQ_OUT_PIN bitfields */ | ||
| 73 | #define STMFX_REG_IRQ_OUT_PIN_TYPE BIT(0) /* 0-OD 1-PP */ | ||
| 74 | #define STMFX_REG_IRQ_OUT_PIN_POL BIT(1) /* 0-active LOW 1-active HIGH */ | ||
| 75 | |||
| 76 | /* STMFX_REG_IRQ_(SRC_EN/PENDING/ACK) bit shift */ | ||
| 77 | enum stmfx_irqs { | ||
| 78 | STMFX_REG_IRQ_SRC_EN_GPIO = 0, | ||
| 79 | STMFX_REG_IRQ_SRC_EN_IDD, | ||
| 80 | STMFX_REG_IRQ_SRC_EN_ERROR, | ||
| 81 | STMFX_REG_IRQ_SRC_EN_TS_DET, | ||
| 82 | STMFX_REG_IRQ_SRC_EN_TS_NE, | ||
| 83 | STMFX_REG_IRQ_SRC_EN_TS_TH, | ||
| 84 | STMFX_REG_IRQ_SRC_EN_TS_FULL, | ||
| 85 | STMFX_REG_IRQ_SRC_EN_TS_OVF, | ||
| 86 | STMFX_REG_IRQ_SRC_MAX, | ||
| 87 | }; | ||
| 88 | |||
| 89 | enum stmfx_functions { | ||
| 90 | STMFX_FUNC_GPIO = BIT(0), /* GPIO[15:0] */ | ||
| 91 | STMFX_FUNC_ALTGPIO_LOW = BIT(1), /* aGPIO[3:0] */ | ||
| 92 | STMFX_FUNC_ALTGPIO_HIGH = BIT(2), /* aGPIO[7:4] */ | ||
| 93 | STMFX_FUNC_TS = BIT(3), | ||
| 94 | STMFX_FUNC_IDD = BIT(4), | ||
| 95 | }; | ||
| 96 | |||
| 97 | /** | ||
| 98 | * struct stmfx_ddata - STMFX MFD structure | ||
| 99 | * @device: device reference used for logs | ||
| 100 | * @map: register map | ||
| 101 | * @vdd: STMFX power supply | ||
| 102 | * @irq_domain: IRQ domain | ||
| 103 | * @lock: IRQ bus lock | ||
| 104 | * @irq_src: cache of IRQ_SRC_EN register for bus_lock | ||
| 105 | * @bkp_sysctrl: backup of SYS_CTRL register for suspend/resume | ||
| 106 | * @bkp_irqoutpin: backup of IRQ_OUT_PIN register for suspend/resume | ||
| 107 | */ | ||
| 108 | struct stmfx { | ||
| 109 | struct device *dev; | ||
| 110 | struct regmap *map; | ||
| 111 | struct regulator *vdd; | ||
| 112 | struct irq_domain *irq_domain; | ||
| 113 | struct mutex lock; /* IRQ bus lock */ | ||
| 114 | u8 irq_src; | ||
| 115 | #ifdef CONFIG_PM | ||
| 116 | u8 bkp_sysctrl; | ||
| 117 | u8 bkp_irqoutpin; | ||
| 118 | #endif | ||
| 119 | }; | ||
| 120 | |||
| 121 | int stmfx_function_enable(struct stmfx *stmfx, u32 func); | ||
| 122 | int stmfx_function_disable(struct stmfx *stmfx, u32 func); | ||
| 123 | #endif | ||
diff --git a/include/linux/mfd/syscon/atmel-matrix.h b/include/linux/mfd/syscon/atmel-matrix.h index 8293c3e2a82a..f61cd127a852 100644 --- a/include/linux/mfd/syscon/atmel-matrix.h +++ b/include/linux/mfd/syscon/atmel-matrix.h | |||
| @@ -1,12 +1,8 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
| 1 | /* | 2 | /* |
| 2 | * Copyright (C) 2014 Atmel Corporation. | 3 | * Copyright (C) 2014 Atmel Corporation. |
| 3 | * | 4 | * |
| 4 | * Memory Controllers (MATRIX, EBI) - System peripherals registers. | 5 | * Memory Controllers (MATRIX, EBI) - System peripherals registers. |
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | */ | 6 | */ |
| 11 | 7 | ||
| 12 | #ifndef _LINUX_MFD_SYSCON_ATMEL_MATRIX_H | 8 | #ifndef _LINUX_MFD_SYSCON_ATMEL_MATRIX_H |
diff --git a/include/linux/mfd/syscon/atmel-mc.h b/include/linux/mfd/syscon/atmel-mc.h index afd9b8f1e363..99c56205c410 100644 --- a/include/linux/mfd/syscon/atmel-mc.h +++ b/include/linux/mfd/syscon/atmel-mc.h | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
| 1 | /* | 2 | /* |
| 2 | * Copyright (C) 2005 Ivan Kokshaysky | 3 | * Copyright (C) 2005 Ivan Kokshaysky |
| 3 | * Copyright (C) SAN People | 4 | * Copyright (C) SAN People |
| @@ -5,11 +6,6 @@ | |||
| 5 | * Memory Controllers (MC, EBI, SMC, SDRAMC, BFC) - System peripherals | 6 | * Memory Controllers (MC, EBI, SMC, SDRAMC, BFC) - System peripherals |
| 6 | * registers. | 7 | * registers. |
| 7 | * Based on AT91RM9200 datasheet revision E. | 8 | * Based on AT91RM9200 datasheet revision E. |
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | */ | 9 | */ |
| 14 | 10 | ||
| 15 | #ifndef _LINUX_MFD_SYSCON_ATMEL_MC_H_ | 11 | #ifndef _LINUX_MFD_SYSCON_ATMEL_MC_H_ |
diff --git a/include/linux/mfd/syscon/atmel-smc.h b/include/linux/mfd/syscon/atmel-smc.h index 7a367f34b66a..e9e24f4c4578 100644 --- a/include/linux/mfd/syscon/atmel-smc.h +++ b/include/linux/mfd/syscon/atmel-smc.h | |||
| @@ -1,3 +1,4 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 1 | /* | 2 | /* |
| 2 | * Atmel SMC (Static Memory Controller) register offsets and bit definitions. | 3 | * Atmel SMC (Static Memory Controller) register offsets and bit definitions. |
| 3 | * | 4 | * |
| @@ -5,10 +6,6 @@ | |||
| 5 | * Copyright (C) 2014 Free Electrons | 6 | * Copyright (C) 2014 Free Electrons |
| 6 | * | 7 | * |
| 7 | * Author: Boris Brezillon <boris.brezillon@free-electrons.com> | 8 | * Author: Boris Brezillon <boris.brezillon@free-electrons.com> |
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | 9 | */ |
| 13 | 10 | ||
| 14 | #ifndef _LINUX_MFD_SYSCON_ATMEL_SMC_H_ | 11 | #ifndef _LINUX_MFD_SYSCON_ATMEL_SMC_H_ |
diff --git a/include/linux/mfd/syscon/atmel-st.h b/include/linux/mfd/syscon/atmel-st.h index 8acf1ec1fa32..5b6013d0c440 100644 --- a/include/linux/mfd/syscon/atmel-st.h +++ b/include/linux/mfd/syscon/atmel-st.h | |||
| @@ -1,14 +1,10 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ | ||
| 1 | /* | 2 | /* |
| 2 | * Copyright (C) 2005 Ivan Kokshaysky | 3 | * Copyright (C) 2005 Ivan Kokshaysky |
| 3 | * Copyright (C) SAN People | 4 | * Copyright (C) SAN People |
| 4 | * | 5 | * |
| 5 | * System Timer (ST) - System peripherals registers. | 6 | * System Timer (ST) - System peripherals registers. |
| 6 | * Based on AT91RM9200 datasheet revision E. | 7 | * Based on AT91RM9200 datasheet revision E. |
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | */ | 8 | */ |
| 13 | 9 | ||
| 14 | #ifndef _LINUX_MFD_SYSCON_ATMEL_ST_H | 10 | #ifndef _LINUX_MFD_SYSCON_ATMEL_ST_H |
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index c1b25f5e386d..f232c8130d00 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | |||
| @@ -410,6 +410,15 @@ | |||
| 410 | #define IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK (0x3 << 17) | 410 | #define IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK (0x3 << 17) |
| 411 | #define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_EXT (0x3 << 13) | 411 | #define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_EXT (0x3 << 13) |
| 412 | 412 | ||
| 413 | #define IMX6SX_GPR2_MQS_OVERSAMPLE_MASK (0x1 << 26) | ||
| 414 | #define IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT (26) | ||
| 415 | #define IMX6SX_GPR2_MQS_EN_MASK (0x1 << 25) | ||
| 416 | #define IMX6SX_GPR2_MQS_EN_SHIFT (25) | ||
| 417 | #define IMX6SX_GPR2_MQS_SW_RST_MASK (0x1 << 24) | ||
| 418 | #define IMX6SX_GPR2_MQS_SW_RST_SHIFT (24) | ||
| 419 | #define IMX6SX_GPR2_MQS_CLK_DIV_MASK (0xFF << 16) | ||
| 420 | #define IMX6SX_GPR2_MQS_CLK_DIV_SHIFT (16) | ||
| 421 | |||
| 413 | #define IMX6SX_GPR4_FEC_ENET1_STOP_REQ (0x1 << 3) | 422 | #define IMX6SX_GPR4_FEC_ENET1_STOP_REQ (0x1 << 3) |
| 414 | #define IMX6SX_GPR4_FEC_ENET2_STOP_REQ (0x1 << 4) | 423 | #define IMX6SX_GPR4_FEC_ENET2_STOP_REQ (0x1 << 4) |
| 415 | 424 | ||
