mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
- Core Frameworks
- Document (kerneldoc) core mfd_add_devices() API - New Drivers - Add support for Altera SOCFPGA System Manager - Add support for Maxim MAX77650/77651 PMIC - Add support for Maxim MAX77663 PMIC - Add support for ST Multi-Function eXpander (STMFX) - New Device Support - Add support for LEDs to Intel Cherry Trail Whiskey Cove PMIC - Add support for RTC to SAMSUNG Electronics S2MPA01 PMIC - Add support for SAM9X60 to Atmel HLCDC (High-end LCD Controller) - Add support for USB X-Powers AXP 8xx PMICs - Add support for Integrated Sensor Hub (ISH) to ChromeOS EC - Add support for USB PD Logger to ChromeOS EC - Add support for AXP223 to X-Powers AXP series PMICs - Add support for Power Supply to X-Powers AXP 803 PMICs - Add support for Comet Lake to Intel Low Power Subsystem - Add support for Fingerprint MCU to ChromeOS EC - Add support for Touchpad MCU to ChromeOS EC - Move TI LM3532 support to LED - New Functionality - Add/extend DT support; max77650, max77620 - Add support for power-off; max77620 - Add support for clocking; syscon - Add support for host sleep event; cros_ec - 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 -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEdrbJNaO+IJqU8IdIUa+KL4f8d2EFAlzame0ACgkQUa+KL4f8 d2GbBQ//bUoA+hcTo/ZUyQQGmE8axikZ6pacY+Y41pdzzLFoOM3IIz4NpdUF0fP2 6r11zDiM2cL9CuMJl/AMiBv7fifowYykaBUEkkm8n2Cpj/bpLIm8eQy6jf14kqNR gj9sTy/feBcnZhqLLx9x9W9695nRTE4q3g+mDOj5sXRvZxqcPBaNgWkk5a8vtN9V yH2XkQSoK0EvvNWjl3pshp7HdKhX8k1xDZ2ghOi3Yk9JmFlg+wrWEKE4KQ7dDoUa SFXFReIwyleAw4Bc/demT1tSDiNgIPc9ZHtb67dUmDCQgpQqTK/h6WV1JeW1I0vh AM6n2hnogcbVcJdAHtwS5tR6nVahpUQ1V+XhYDyyHNmx6rqW5q2e3xRF75CT4wBZ NMIVaWNlih62Y196Exy+6CANHvJyxL6yRgvXkpfyaf9vYdXUrBRUujxn1PzrbkNJ kJwvZk5yHgg0n5SIV/D4CVy+RHP6uqe4oE4iXNWP5Um06OyVCieqMvoduyGQdLG/ 7Xrflc4EmeqTfWZrnW3ljh6sOBC+MQCfIKgRtvkPQ5EpcNU2VPXeNsAvIIHCpWHy HJY43WRP98DTNyP+/oBrsh56y8n+NwMBcWSmL4tv4cKmGx11bRvp35Mzy1ElPw6Y Zzttsw8Puz2EMmfGdcRwkZW0KWb5sAvJcImCkrjg/13QPHgcPgk= =dTSD -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
ebcf5bb282
@ -11,3 +11,15 @@ Example:
|
||||
reg = <0xffd08000 0x1000>;
|
||||
cpu1-start-addr = <0xffd080c4>;
|
||||
};
|
||||
|
||||
ARM64 - Stratix10
|
||||
Required properties:
|
||||
- compatible : "altr,sys-mgr-s10"
|
||||
- reg : Should contain 1 register range(address and length)
|
||||
for system manager register.
|
||||
|
||||
Example:
|
||||
sysmgr@ffd12000 {
|
||||
compatible = "altr,sys-mgr-s10";
|
||||
reg = <0xffd12000 0x228>;
|
||||
};
|
||||
|
@ -5,10 +5,12 @@ Properties:
|
||||
- " st,stm32mp157-syscfg " - for stm32mp157 based SoCs,
|
||||
second value must be always "syscon".
|
||||
- reg : offset and length of the register set.
|
||||
- clocks: phandle to the syscfg clock
|
||||
|
||||
Example:
|
||||
syscfg: syscon@50020000 {
|
||||
compatible = "st,stm32mp157-syscfg", "syscon";
|
||||
reg = <0x50020000 0x400>;
|
||||
clocks = <&rcc SYSCFG>;
|
||||
};
|
||||
|
||||
|
26
Documentation/devicetree/bindings/input/max77650-onkey.txt
Normal file
26
Documentation/devicetree/bindings/input/max77650-onkey.txt
Normal file
@ -0,0 +1,26 @@
|
||||
Onkey driver for MAX77650 PMIC from Maxim Integrated.
|
||||
|
||||
This module is part of the MAX77650 MFD device. For more details
|
||||
see Documentation/devicetree/bindings/mfd/max77650.txt.
|
||||
|
||||
The onkey controller is represented as a sub-node of the PMIC node on
|
||||
the device tree.
|
||||
|
||||
Required properties:
|
||||
--------------------
|
||||
- compatible: Must be "maxim,max77650-onkey".
|
||||
|
||||
Optional properties:
|
||||
- linux,code: The key-code to be reported when the key is pressed.
|
||||
Defaults to KEY_POWER.
|
||||
- maxim,onkey-slide: The system's button is a slide switch, not the default
|
||||
push button.
|
||||
|
||||
Example:
|
||||
--------
|
||||
|
||||
onkey {
|
||||
compatible = "maxim,max77650-onkey";
|
||||
linux,code = <KEY_END>;
|
||||
maxim,onkey-slide;
|
||||
};
|
57
Documentation/devicetree/bindings/leds/leds-max77650.txt
Normal file
57
Documentation/devicetree/bindings/leds/leds-max77650.txt
Normal file
@ -0,0 +1,57 @@
|
||||
LED driver for MAX77650 PMIC from Maxim Integrated.
|
||||
|
||||
This module is part of the MAX77650 MFD device. For more details
|
||||
see Documentation/devicetree/bindings/mfd/max77650.txt.
|
||||
|
||||
The LED controller is represented as a sub-node of the PMIC node on
|
||||
the device tree.
|
||||
|
||||
This device has three current sinks.
|
||||
|
||||
Required properties:
|
||||
--------------------
|
||||
- compatible: Must be "maxim,max77650-led"
|
||||
- #address-cells: Must be <1>.
|
||||
- #size-cells: Must be <0>.
|
||||
|
||||
Each LED is represented as a sub-node of the LED-controller node. Up to
|
||||
three sub-nodes can be defined.
|
||||
|
||||
Required properties of the sub-node:
|
||||
------------------------------------
|
||||
|
||||
- reg: Must be <0>, <1> or <2>.
|
||||
|
||||
Optional properties of the sub-node:
|
||||
------------------------------------
|
||||
|
||||
- label: See Documentation/devicetree/bindings/leds/common.txt
|
||||
- linux,default-trigger: See Documentation/devicetree/bindings/leds/common.txt
|
||||
|
||||
For more details, please refer to the generic GPIO DT binding document
|
||||
<devicetree/bindings/gpio/gpio.txt>.
|
||||
|
||||
Example:
|
||||
--------
|
||||
|
||||
leds {
|
||||
compatible = "maxim,max77650-led";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
led@0 {
|
||||
reg = <0>;
|
||||
label = "blue:usr0";
|
||||
};
|
||||
|
||||
led@1 {
|
||||
reg = <1>;
|
||||
label = "red:usr1";
|
||||
linux,default-trigger = "heartbeat";
|
||||
};
|
||||
|
||||
led@2 {
|
||||
reg = <2>;
|
||||
label = "green:usr2";
|
||||
};
|
||||
};
|
@ -7,6 +7,7 @@ Required properties:
|
||||
"atmel,sama5d2-hlcdc"
|
||||
"atmel,sama5d3-hlcdc"
|
||||
"atmel,sama5d4-hlcdc"
|
||||
"microchip,sam9x60-hlcdc"
|
||||
- reg: base address and size of the HLCDC device registers.
|
||||
- clock-names: the name of the 3 clocks requested by the HLCDC device.
|
||||
Should contain "periph_clk", "sys_clk" and "slow_clk".
|
||||
|
@ -19,6 +19,8 @@ And these documents for the required sub-node binding details:
|
||||
[4] Clock: ../clock/cirrus,lochnagar.txt
|
||||
[5] Pinctrl: ../pinctrl/cirrus,lochnagar.txt
|
||||
[6] Regulator: ../regulator/cirrus,lochnagar.txt
|
||||
[7] Sound: ../sound/cirrus,lochnagar.txt
|
||||
[8] Hardware Monitor: ../hwmon/cirrus,lochnagar.txt
|
||||
|
||||
Required properties:
|
||||
|
||||
@ -41,6 +43,11 @@ Optional sub-nodes:
|
||||
- Bindings for the regulator components, see [6]. Only available on
|
||||
Lochnagar 2.
|
||||
|
||||
- lochnagar-sc : Binding for the sound card components, see [7].
|
||||
Only available on Lochnagar 2.
|
||||
- lochnagar-hwmon : Binding for the hardware monitor components, see [8].
|
||||
Only available on Lochnagar 2.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- present-gpios : Host present line, indicating the presence of a
|
||||
@ -65,4 +72,14 @@ lochnagar: lochnagar@22 {
|
||||
compatible = "cirrus,lochnagar-pinctrl";
|
||||
...
|
||||
};
|
||||
|
||||
lochnagar-sc {
|
||||
compatible = "cirrus,lochnagar2-soundcard";
|
||||
...
|
||||
};
|
||||
|
||||
lochnagar-hwmon {
|
||||
compatible = "cirrus,lochnagar2-hwmon";
|
||||
...
|
||||
};
|
||||
};
|
||||
|
@ -4,7 +4,8 @@ Required properties:
|
||||
-------------------
|
||||
- compatible: Must be one of
|
||||
"maxim,max77620"
|
||||
"maxim,max20024".
|
||||
"maxim,max20024"
|
||||
"maxim,max77663"
|
||||
- reg: I2C device address.
|
||||
|
||||
Optional properties:
|
||||
@ -17,6 +18,11 @@ Optional properties:
|
||||
IRQ numbers for different interrupt source of MAX77620
|
||||
are defined at dt-bindings/mfd/max77620.h.
|
||||
|
||||
- system-power-controller: Indicates that this PMIC is controlling the
|
||||
system power, see [1] for more details.
|
||||
|
||||
[1] Documentation/devicetree/bindings/power/power-controller.txt
|
||||
|
||||
Optional subnodes and their properties:
|
||||
=======================================
|
||||
|
||||
@ -105,6 +111,7 @@ Optional properties:
|
||||
Here supported time periods by device in microseconds are as follows:
|
||||
MAX77620 supports 40, 80, 160, 320, 640, 1280, 2560 and 5120 microseconds.
|
||||
MAX20024 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds.
|
||||
MAX77663 supports 20, 40, 80, 160, 320, 640, 1280 and 2540 microseconds.
|
||||
|
||||
-maxim,power-ok-control: configure map power ok bit
|
||||
1: Enables POK(Power OK) to control nRST_IO and GPIO1
|
||||
|
46
Documentation/devicetree/bindings/mfd/max77650.txt
Normal file
46
Documentation/devicetree/bindings/mfd/max77650.txt
Normal file
@ -0,0 +1,46 @@
|
||||
MAX77650 ultra low-power PMIC from Maxim Integrated.
|
||||
|
||||
Required properties:
|
||||
-------------------
|
||||
- compatible: Must be "maxim,max77650"
|
||||
- reg: I2C device address.
|
||||
- interrupts: The interrupt on the parent the controller is
|
||||
connected to.
|
||||
- interrupt-controller: Marks the device node as an interrupt controller.
|
||||
- #interrupt-cells: Must be <2>.
|
||||
|
||||
- gpio-controller: Marks the device node as a gpio controller.
|
||||
- #gpio-cells: Must be <2>. The first cell is the pin number and
|
||||
the second cell is used to specify the gpio active
|
||||
state.
|
||||
|
||||
Optional properties:
|
||||
--------------------
|
||||
gpio-line-names: Single string containing the name of the GPIO line.
|
||||
|
||||
The GPIO-controller module is represented as part of the top-level PMIC
|
||||
node. The device exposes a single GPIO line.
|
||||
|
||||
For device-tree bindings of other sub-modules (regulator, power supply,
|
||||
LEDs and onkey) refer to the binding documents under the respective
|
||||
sub-system directories.
|
||||
|
||||
For more details on GPIO bindings, please refer to the generic GPIO DT
|
||||
binding document <devicetree/bindings/gpio/gpio.txt>.
|
||||
|
||||
Example:
|
||||
--------
|
||||
|
||||
pmic@48 {
|
||||
compatible = "maxim,max77650";
|
||||
reg = <0x48>;
|
||||
|
||||
interrupt-controller;
|
||||
interrupt-parent = <&gpio2>;
|
||||
#interrupt-cells = <2>;
|
||||
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
gpio-line-names = "max77650-charger";
|
||||
};
|
28
Documentation/devicetree/bindings/mfd/stmfx.txt
Normal file
28
Documentation/devicetree/bindings/mfd/stmfx.txt
Normal file
@ -0,0 +1,28 @@
|
||||
STMicroelectonics Multi-Function eXpander (STMFX) Core bindings
|
||||
|
||||
ST Multi-Function eXpander (STMFX) is a slave controller using I2C for
|
||||
communication with the main MCU. Its main features are GPIO expansion, main
|
||||
MCU IDD measurement (IDD is the amount of current that flows through VDD) and
|
||||
resistive touchscreen controller.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "st,stmfx-0300".
|
||||
- reg: I2C slave address of the device.
|
||||
- interrupts: interrupt specifier triggered by MFX_IRQ_OUT signal.
|
||||
Please refer to ../interrupt-controller/interrupt.txt
|
||||
|
||||
Optional properties:
|
||||
- drive-open-drain: configure MFX_IRQ_OUT as open drain.
|
||||
- vdd-supply: phandle of the regulator supplying STMFX.
|
||||
|
||||
Example:
|
||||
|
||||
stmfx: stmfx@42 {
|
||||
compatible = "st,stmfx-0300";
|
||||
reg = <0x42>;
|
||||
interrupts = <8 IRQ_TYPE_EDGE_RISING>;
|
||||
interrupt-parent = <&gpioi>;
|
||||
vdd-supply = <&v3v3>;
|
||||
};
|
||||
|
||||
Please refer to ../pinctrl/pinctrl-stmfx.txt for STMFX GPIO expander function bindings.
|
@ -104,8 +104,8 @@ lm3632@11 {
|
||||
regulators {
|
||||
compatible = "ti,lm363x-regulator";
|
||||
|
||||
ti,lcm-en1-gpio = <&pioC 0 GPIO_ACTIVE_HIGH>; /* PC0 */
|
||||
ti,lcm-en2-gpio = <&pioC 1 GPIO_ACTIVE_HIGH>; /* PC1 */
|
||||
enable-gpios = <&pioC 0 GPIO_ACTIVE_HIGH>,
|
||||
<&pioC 1 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
vboost {
|
||||
regulator-name = "lcd_boost";
|
||||
|
116
Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt
Normal file
116
Documentation/devicetree/bindings/pinctrl/pinctrl-stmfx.txt
Normal file
@ -0,0 +1,116 @@
|
||||
STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander bindings
|
||||
|
||||
ST Multi-Function eXpander (STMFX) offers up to 24 GPIOs expansion.
|
||||
Please refer to ../mfd/stmfx.txt for STMFX Core bindings.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "st,stmfx-0300-pinctrl".
|
||||
- #gpio-cells: should be <2>, the first cell is the GPIO number and the second
|
||||
cell is the gpio flags in accordance with <dt-bindings/gpio/gpio.h>.
|
||||
- gpio-controller: marks the device as a GPIO controller.
|
||||
- #interrupt-cells: should be <2>, the first cell is the GPIO number and the
|
||||
second cell is the interrupt flags in accordance with
|
||||
<dt-bindings/interrupt-controller/irq.h>.
|
||||
- interrupt-controller: marks the device as an interrupt controller.
|
||||
- gpio-ranges: specifies the mapping between gpio controller and pin
|
||||
controller pins. Check "Concerning gpio-ranges property" below.
|
||||
Please refer to ../gpio/gpio.txt.
|
||||
|
||||
Please refer to pinctrl-bindings.txt for pin configuration.
|
||||
|
||||
Required properties for pin configuration sub-nodes:
|
||||
- pins: list of pins to which the configuration applies.
|
||||
|
||||
Optional properties for pin configuration sub-nodes (pinconf-generic ones):
|
||||
- bias-disable: disable any bias on the pin.
|
||||
- bias-pull-up: the pin will be pulled up.
|
||||
- bias-pull-pin-default: use the pin-default pull state.
|
||||
- bias-pull-down: the pin will be pulled down.
|
||||
- drive-open-drain: the pin will be driven with open drain.
|
||||
- drive-push-pull: the pin will be driven actively high and low.
|
||||
- output-high: the pin will be configured as an output driving high level.
|
||||
- output-low: the pin will be configured as an output driving low level.
|
||||
|
||||
Note that STMFX pins[15:0] are called "gpio[15:0]", and STMFX pins[23:16] are
|
||||
called "agpio[7:0]". Example, to refer to pin 18 of STMFX, use "agpio2".
|
||||
|
||||
Concerning gpio-ranges property:
|
||||
- if all STMFX pins[24:0] are available (no other STMFX function in use), you
|
||||
should use gpio-ranges = <&stmfx_pinctrl 0 0 24>;
|
||||
- if agpio[3:0] are not available (STMFX Touchscreen function in use), you
|
||||
should use gpio-ranges = <&stmfx_pinctrl 0 0 16>, <&stmfx_pinctrl 20 20 4>;
|
||||
- if agpio[7:4] are not available (STMFX IDD function in use), you
|
||||
should use gpio-ranges = <&stmfx_pinctrl 0 0 20>;
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
stmfx: stmfx@42 {
|
||||
...
|
||||
|
||||
stmfx_pinctrl: stmfx-pin-controller {
|
||||
compatible = "st,stmfx-0300-pinctrl";
|
||||
#gpio-cells = <2>;
|
||||
#interrupt-cells = <2>;
|
||||
gpio-controller;
|
||||
interrupt-controller;
|
||||
gpio-ranges = <&stmfx_pinctrl 0 0 24>;
|
||||
|
||||
joystick_pins: joystick {
|
||||
pins = "gpio0", "gpio1", "gpio2", "gpio3", "gpio4";
|
||||
drive-push-pull;
|
||||
bias-pull-up;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Example of STMFX GPIO consumers:
|
||||
|
||||
joystick {
|
||||
compatible = "gpio-keys";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
pinctrl-0 = <&joystick_pins>;
|
||||
pinctrl-names = "default";
|
||||
button-0 {
|
||||
label = "JoySel";
|
||||
linux,code = <KEY_ENTER>;
|
||||
interrupt-parent = <&stmfx_pinctrl>;
|
||||
interrupts = <0 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
button-1 {
|
||||
label = "JoyDown";
|
||||
linux,code = <KEY_DOWN>;
|
||||
interrupt-parent = <&stmfx_pinctrl>;
|
||||
interrupts = <1 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
button-2 {
|
||||
label = "JoyLeft";
|
||||
linux,code = <KEY_LEFT>;
|
||||
interrupt-parent = <&stmfx_pinctrl>;
|
||||
interrupts = <2 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
button-3 {
|
||||
label = "JoyRight";
|
||||
linux,code = <KEY_RIGHT>;
|
||||
interrupt-parent = <&stmfx_pinctrl>;
|
||||
interrupts = <3 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
button-4 {
|
||||
label = "JoyUp";
|
||||
linux,code = <KEY_UP>;
|
||||
interrupt-parent = <&stmfx_pinctrl>;
|
||||
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
|
||||
};
|
||||
};
|
||||
|
||||
leds {
|
||||
compatible = "gpio-leds";
|
||||
orange {
|
||||
gpios = <&stmfx_pinctrl 17 1>;
|
||||
};
|
||||
|
||||
blue {
|
||||
gpios = <&stmfx_pinctrl 19 1>;
|
||||
};
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
Battery charger driver for MAX77650 PMIC from Maxim Integrated.
|
||||
|
||||
This module is part of the MAX77650 MFD device. For more details
|
||||
see Documentation/devicetree/bindings/mfd/max77650.txt.
|
||||
|
||||
The charger is represented as a sub-node of the PMIC node on the device tree.
|
||||
|
||||
Required properties:
|
||||
--------------------
|
||||
- compatible: Must be "maxim,max77650-charger"
|
||||
|
||||
Optional properties:
|
||||
--------------------
|
||||
- input-voltage-min-microvolt: Minimum CHGIN regulation voltage. Must be one
|
||||
of: 4000000, 4100000, 4200000, 4300000,
|
||||
4400000, 4500000, 4600000, 4700000.
|
||||
- input-current-limit-microamp: CHGIN input current limit (in microamps). Must
|
||||
be one of: 95000, 190000, 285000, 380000,
|
||||
475000.
|
||||
|
||||
Example:
|
||||
--------
|
||||
|
||||
charger {
|
||||
compatible = "maxim,max77650-charger";
|
||||
input-voltage-min-microvolt = <4200000>;
|
||||
input-current-limit-microamp = <285000>;
|
||||
};
|
20
MAINTAINERS
20
MAINTAINERS
@ -710,6 +710,12 @@ L: linux-gpio@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/gpio/gpio-altera.c
|
||||
|
||||
ALTERA SYSTEM MANAGER DRIVER
|
||||
M: Thor Thayer <thor.thayer@linux.intel.com>
|
||||
S: Maintained
|
||||
F: drivers/mfd/altera-sysmgr.c
|
||||
F: include/linux/mfd/altera-sysgmr.h
|
||||
|
||||
ALTERA SYSTEM RESOURCE DRIVER FOR ARRIA10 DEVKIT
|
||||
M: Thor Thayer <thor.thayer@linux.intel.com>
|
||||
S: Maintained
|
||||
@ -9517,6 +9523,20 @@ S: Maintained
|
||||
F: Documentation/devicetree/bindings/iio/proximity/maxbotix,mb1232.txt
|
||||
F: drivers/iio/proximity/mb1232.c
|
||||
|
||||
MAXIM MAX77650 PMIC MFD DRIVER
|
||||
M: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/*/*max77650.txt
|
||||
F: Documentation/devicetree/bindings/*/max77650*.txt
|
||||
F: include/linux/mfd/max77650.h
|
||||
F: drivers/mfd/max77650.c
|
||||
F: drivers/regulator/max77650-regulator.c
|
||||
F: drivers/power/supply/max77650-charger.c
|
||||
F: drivers/input/misc/max77650-onkey.c
|
||||
F: drivers/leds/leds-max77650.c
|
||||
F: drivers/gpio/gpio-max77650.c
|
||||
|
||||
MAXIM MAX77802 PMIC REGULATOR DEVICE DRIVER
|
||||
M: Javier Martinez Canillas <javier@dowhile0.org>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
|
@ -106,6 +106,7 @@ CONFIG_SENSORS_LTC2978_REGULATOR=y
|
||||
CONFIG_WATCHDOG=y
|
||||
CONFIG_DW_WATCHDOG=y
|
||||
CONFIG_MFD_ALTERA_A10SR=y
|
||||
CONFIG_MFD_ALTERA_SYSMGR=y
|
||||
CONFIG_MFD_STMPE=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
|
@ -393,7 +393,7 @@
|
||||
};
|
||||
|
||||
sysmgr: sysmgr@ffd12000 {
|
||||
compatible = "altr,sys-mgr", "syscon";
|
||||
compatible = "altr,sys-mgr-s10","altr,sys-mgr";
|
||||
reg = <0xffd12000 0x228>;
|
||||
};
|
||||
|
||||
|
@ -432,6 +432,7 @@ CONFIG_MESON_WATCHDOG=m
|
||||
CONFIG_RENESAS_WDT=y
|
||||
CONFIG_UNIPHIER_WATCHDOG=y
|
||||
CONFIG_BCM2835_WDT=y
|
||||
CONFIG_MFD_ALTERA_SYSMGR=y
|
||||
CONFIG_MFD_BD9571MWV=y
|
||||
CONFIG_MFD_AXP20X_I2C=y
|
||||
CONFIG_MFD_AXP20X_RSB=y
|
||||
|
@ -1097,6 +1097,13 @@ config GPIO_MAX77620
|
||||
driver also provides interrupt support for each of the gpios.
|
||||
Say yes here to enable the max77620 to be used as gpio controller.
|
||||
|
||||
config GPIO_MAX77650
|
||||
tristate "Maxim MAX77650/77651 GPIO support"
|
||||
depends on MFD_MAX77650
|
||||
help
|
||||
GPIO driver for MAX77650/77651 PMIC from Maxim Semiconductor.
|
||||
These chips have a single pin that can be configured as GPIO.
|
||||
|
||||
config GPIO_MSIC
|
||||
bool "Intel MSIC mixed signal gpio support"
|
||||
depends on (X86 || COMPILE_TEST) && MFD_INTEL_MSIC
|
||||
|
@ -80,6 +80,7 @@ obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
|
||||
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
|
||||
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
|
||||
obj-$(CONFIG_GPIO_MAX77620) += gpio-max77620.o
|
||||
obj-$(CONFIG_GPIO_MAX77650) += gpio-max77650.o
|
||||
obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
|
||||
obj-$(CONFIG_GPIO_MENZ127) += gpio-menz127.o
|
||||
obj-$(CONFIG_GPIO_MERRIFIELD) += gpio-merrifield.o
|
||||
|
190
drivers/gpio/gpio-max77650.c
Normal file
190
drivers/gpio/gpio-max77650.c
Normal file
@ -0,0 +1,190 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2018 BayLibre SAS
|
||||
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
//
|
||||
// GPIO driver for MAXIM 77650/77651 charger/power-supply.
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/mfd/max77650.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MAX77650_GPIO_DIR_MASK BIT(0)
|
||||
#define MAX77650_GPIO_INVAL_MASK BIT(1)
|
||||
#define MAX77650_GPIO_DRV_MASK BIT(2)
|
||||
#define MAX77650_GPIO_OUTVAL_MASK BIT(3)
|
||||
#define MAX77650_GPIO_DEBOUNCE_MASK BIT(4)
|
||||
|
||||
#define MAX77650_GPIO_DIR_OUT 0x00
|
||||
#define MAX77650_GPIO_DIR_IN BIT(0)
|
||||
#define MAX77650_GPIO_OUT_LOW 0x00
|
||||
#define MAX77650_GPIO_OUT_HIGH BIT(3)
|
||||
#define MAX77650_GPIO_DRV_OPEN_DRAIN 0x00
|
||||
#define MAX77650_GPIO_DRV_PUSH_PULL BIT(2)
|
||||
#define MAX77650_GPIO_DEBOUNCE BIT(4)
|
||||
|
||||
#define MAX77650_GPIO_DIR_BITS(_reg) \
|
||||
((_reg) & MAX77650_GPIO_DIR_MASK)
|
||||
#define MAX77650_GPIO_INVAL_BITS(_reg) \
|
||||
(((_reg) & MAX77650_GPIO_INVAL_MASK) >> 1)
|
||||
|
||||
struct max77650_gpio_chip {
|
||||
struct regmap *map;
|
||||
struct gpio_chip gc;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static int max77650_gpio_direction_input(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
return regmap_update_bits(chip->map,
|
||||
MAX77650_REG_CNFG_GPIO,
|
||||
MAX77650_GPIO_DIR_MASK,
|
||||
MAX77650_GPIO_DIR_IN);
|
||||
}
|
||||
|
||||
static int max77650_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
|
||||
int mask, regval;
|
||||
|
||||
mask = MAX77650_GPIO_DIR_MASK | MAX77650_GPIO_OUTVAL_MASK;
|
||||
regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
|
||||
regval |= MAX77650_GPIO_DIR_OUT;
|
||||
|
||||
return regmap_update_bits(chip->map,
|
||||
MAX77650_REG_CNFG_GPIO, mask, regval);
|
||||
}
|
||||
|
||||
static void max77650_gpio_set_value(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
|
||||
int rv, regval;
|
||||
|
||||
regval = value ? MAX77650_GPIO_OUT_HIGH : MAX77650_GPIO_OUT_LOW;
|
||||
|
||||
rv = regmap_update_bits(chip->map, MAX77650_REG_CNFG_GPIO,
|
||||
MAX77650_GPIO_OUTVAL_MASK, regval);
|
||||
if (rv)
|
||||
dev_err(gc->parent, "cannot set GPIO value: %d\n", rv);
|
||||
}
|
||||
|
||||
static int max77650_gpio_get_value(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
|
||||
unsigned int val;
|
||||
int rv;
|
||||
|
||||
rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
return MAX77650_GPIO_INVAL_BITS(val);
|
||||
}
|
||||
|
||||
static int max77650_gpio_get_direction(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
|
||||
unsigned int val;
|
||||
int rv;
|
||||
|
||||
rv = regmap_read(chip->map, MAX77650_REG_CNFG_GPIO, &val);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
return MAX77650_GPIO_DIR_BITS(val);
|
||||
}
|
||||
|
||||
static int max77650_gpio_set_config(struct gpio_chip *gc,
|
||||
unsigned int offset, unsigned long cfg)
|
||||
{
|
||||
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
switch (pinconf_to_config_param(cfg)) {
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
return regmap_update_bits(chip->map,
|
||||
MAX77650_REG_CNFG_GPIO,
|
||||
MAX77650_GPIO_DRV_MASK,
|
||||
MAX77650_GPIO_DRV_OPEN_DRAIN);
|
||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||
return regmap_update_bits(chip->map,
|
||||
MAX77650_REG_CNFG_GPIO,
|
||||
MAX77650_GPIO_DRV_MASK,
|
||||
MAX77650_GPIO_DRV_PUSH_PULL);
|
||||
case PIN_CONFIG_INPUT_DEBOUNCE:
|
||||
return regmap_update_bits(chip->map,
|
||||
MAX77650_REG_CNFG_GPIO,
|
||||
MAX77650_GPIO_DEBOUNCE_MASK,
|
||||
MAX77650_GPIO_DEBOUNCE);
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int max77650_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct max77650_gpio_chip *chip = gpiochip_get_data(gc);
|
||||
|
||||
return chip->irq;
|
||||
}
|
||||
|
||||
static int max77650_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct max77650_gpio_chip *chip;
|
||||
struct device *dev, *parent;
|
||||
struct i2c_client *i2c;
|
||||
|
||||
dev = &pdev->dev;
|
||||
parent = dev->parent;
|
||||
i2c = to_i2c_client(parent);
|
||||
|
||||
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
|
||||
if (!chip)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->map = dev_get_regmap(parent, NULL);
|
||||
if (!chip->map)
|
||||
return -ENODEV;
|
||||
|
||||
chip->irq = platform_get_irq_byname(pdev, "GPI");
|
||||
if (chip->irq < 0)
|
||||
return chip->irq;
|
||||
|
||||
chip->gc.base = -1;
|
||||
chip->gc.ngpio = 1;
|
||||
chip->gc.label = i2c->name;
|
||||
chip->gc.parent = dev;
|
||||
chip->gc.owner = THIS_MODULE;
|
||||
chip->gc.can_sleep = true;
|
||||
|
||||
chip->gc.direction_input = max77650_gpio_direction_input;
|
||||
chip->gc.direction_output = max77650_gpio_direction_output;
|
||||
chip->gc.set = max77650_gpio_set_value;
|
||||
chip->gc.get = max77650_gpio_get_value;
|
||||
chip->gc.get_direction = max77650_gpio_get_direction;
|
||||
chip->gc.set_config = max77650_gpio_set_config;
|
||||
chip->gc.to_irq = max77650_gpio_to_irq;
|
||||
|
||||
return devm_gpiochip_add_data(dev, &chip->gc, chip);
|
||||
}
|
||||
|
||||
static struct platform_driver max77650_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "max77650-gpio",
|
||||
},
|
||||
.probe = max77650_gpio_probe,
|
||||
};
|
||||
module_platform_driver(max77650_gpio_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77650/77651 GPIO driver");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -190,6 +190,15 @@ config INPUT_M68K_BEEP
|
||||
tristate "M68k Beeper support"
|
||||
depends on M68K
|
||||
|
||||
config INPUT_MAX77650_ONKEY
|
||||
tristate "Maxim MAX77650 ONKEY support"
|
||||
depends on MFD_MAX77650
|
||||
help
|
||||
Support the ONKEY of the MAX77650 PMIC as an input device.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called max77650-onkey.
|
||||
|
||||
config INPUT_MAX77693_HAPTIC
|
||||
tristate "MAXIM MAX77693/MAX77843 haptic controller support"
|
||||
depends on (MFD_MAX77693 || MFD_MAX77843) && PWM
|
||||
|
@ -44,6 +44,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
|
||||
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
|
||||
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
|
||||
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
||||
obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
|
||||
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
|
||||
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
|
||||
obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
|
||||
|
121
drivers/input/misc/max77650-onkey.c
Normal file
121
drivers/input/misc/max77650-onkey.c
Normal file
@ -0,0 +1,121 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2018 BayLibre SAS
|
||||
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
//
|
||||
// ONKEY driver for MAXIM 77650/77651 charger/power-supply.
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/max77650.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MAX77650_ONKEY_MODE_MASK BIT(3)
|
||||
#define MAX77650_ONKEY_MODE_PUSH 0x00
|
||||
#define MAX77650_ONKEY_MODE_SLIDE BIT(3)
|
||||
|
||||
struct max77650_onkey {
|
||||
struct input_dev *input;
|
||||
unsigned int code;
|
||||
};
|
||||
|
||||
static irqreturn_t max77650_onkey_falling(int irq, void *data)
|
||||
{
|
||||
struct max77650_onkey *onkey = data;
|
||||
|
||||
input_report_key(onkey->input, onkey->code, 0);
|
||||
input_sync(onkey->input);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t max77650_onkey_rising(int irq, void *data)
|
||||
{
|
||||
struct max77650_onkey *onkey = data;
|
||||
|
||||
input_report_key(onkey->input, onkey->code, 1);
|
||||
input_sync(onkey->input);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int max77650_onkey_probe(struct platform_device *pdev)
|
||||
{
|
||||
int irq_r, irq_f, error, mode;
|
||||
struct max77650_onkey *onkey;
|
||||
struct device *dev, *parent;
|
||||
struct regmap *map;
|
||||
unsigned int type;
|
||||
|
||||
dev = &pdev->dev;
|
||||
parent = dev->parent;
|
||||
|
||||
map = dev_get_regmap(parent, NULL);
|
||||
if (!map)
|
||||
return -ENODEV;
|
||||
|
||||
onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
|
||||
if (!onkey)
|
||||
return -ENOMEM;
|
||||
|
||||
error = device_property_read_u32(dev, "linux,code", &onkey->code);
|
||||
if (error)
|
||||
onkey->code = KEY_POWER;
|
||||
|
||||
if (device_property_read_bool(dev, "maxim,onkey-slide")) {
|
||||
mode = MAX77650_ONKEY_MODE_SLIDE;
|
||||
type = EV_SW;
|
||||
} else {
|
||||
mode = MAX77650_ONKEY_MODE_PUSH;
|
||||
type = EV_KEY;
|
||||
}
|
||||
|
||||
error = regmap_update_bits(map, MAX77650_REG_CNFG_GLBL,
|
||||
MAX77650_ONKEY_MODE_MASK, mode);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
irq_f = platform_get_irq_byname(pdev, "nEN_F");
|
||||
if (irq_f < 0)
|
||||
return irq_f;
|
||||
|
||||
irq_r = platform_get_irq_byname(pdev, "nEN_R");
|
||||
if (irq_r < 0)
|
||||
return irq_r;
|
||||
|
||||
onkey->input = devm_input_allocate_device(dev);
|
||||
if (!onkey->input)
|
||||
return -ENOMEM;
|
||||
|
||||
onkey->input->name = "max77650_onkey";
|
||||
onkey->input->phys = "max77650_onkey/input0";
|
||||
onkey->input->id.bustype = BUS_I2C;
|
||||
input_set_capability(onkey->input, type, onkey->code);
|
||||
|
||||
error = devm_request_any_context_irq(dev, irq_f, max77650_onkey_falling,
|
||||
IRQF_ONESHOT, "onkey-down", onkey);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
error = devm_request_any_context_irq(dev, irq_r, max77650_onkey_rising,
|
||||
IRQF_ONESHOT, "onkey-up", onkey);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
return input_register_device(onkey->input);
|
||||
}
|
||||
|
||||
static struct platform_driver max77650_onkey_driver = {
|
||||
.driver = {
|
||||
.name = "max77650-onkey",
|
||||
},
|
||||
.probe = max77650_onkey_probe,
|
||||
};
|
||||
module_platform_driver(max77650_onkey_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -619,6 +619,12 @@ config LEDS_TLC591XX
|
||||
This option enables support for Texas Instruments TLC59108
|
||||
and TLC59116 LED controllers.
|
||||
|
||||
config LEDS_MAX77650
|
||||
tristate "LED support for Maxim MAX77650 PMIC"
|
||||
depends on LEDS_CLASS && MFD_MAX77650
|
||||
help
|
||||
LEDs driver for MAX77650 family of PMICs from Maxim Integrated.
|
||||
|
||||
config LEDS_MAX77693
|
||||
tristate "LED support for MAX77693 Flash"
|
||||
depends on LEDS_CLASS_FLASH
|
||||
|
@ -62,6 +62,7 @@ obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
|
||||
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
|
||||
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
|
||||
obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
|
||||
obj-$(CONFIG_LEDS_MAX77650) += leds-max77650.o
|
||||
obj-$(CONFIG_LEDS_MAX77693) += leds-max77693.o
|
||||
obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o
|
||||
obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o
|
||||
|
147
drivers/leds/leds-max77650.c
Normal file
147
drivers/leds/leds-max77650.c
Normal file
@ -0,0 +1,147 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2018 BayLibre SAS
|
||||
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
//
|
||||
// LED driver for MAXIM 77650/77651 charger/power-supply.
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/mfd/max77650.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MAX77650_LED_NUM_LEDS 3
|
||||
|
||||
#define MAX77650_LED_A_BASE 0x40
|
||||
#define MAX77650_LED_B_BASE 0x43
|
||||
|
||||
#define MAX77650_LED_BR_MASK GENMASK(4, 0)
|
||||
#define MAX77650_LED_EN_MASK GENMASK(7, 6)
|
||||
|
||||
#define MAX77650_LED_MAX_BRIGHTNESS MAX77650_LED_BR_MASK
|
||||
|
||||
/* Enable EN_LED_MSTR. */
|
||||
#define MAX77650_LED_TOP_DEFAULT BIT(0)
|
||||
|
||||
#define MAX77650_LED_ENABLE GENMASK(7, 6)
|
||||
#define MAX77650_LED_DISABLE 0x00
|
||||
|
||||
#define MAX77650_LED_A_DEFAULT MAX77650_LED_DISABLE
|
||||
/* 100% on duty */
|
||||
#define MAX77650_LED_B_DEFAULT GENMASK(3, 0)
|
||||
|
||||
struct max77650_led {
|
||||
struct led_classdev cdev;
|
||||
struct regmap *map;
|
||||
unsigned int regA;
|
||||
unsigned int regB;
|
||||
};
|
||||
|
||||
static struct max77650_led *max77650_to_led(struct led_classdev *cdev)
|
||||
{
|
||||
return container_of(cdev, struct max77650_led, cdev);
|
||||
}
|
||||
|
||||
static int max77650_led_brightness_set(struct led_classdev *cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
struct max77650_led *led = max77650_to_led(cdev);
|
||||
int val, mask;
|
||||
|
||||
mask = MAX77650_LED_BR_MASK | MAX77650_LED_EN_MASK;
|
||||
|
||||
if (brightness == LED_OFF)
|
||||
val = MAX77650_LED_DISABLE;
|
||||
else
|
||||
val = MAX77650_LED_ENABLE | brightness;
|
||||
|
||||
return regmap_update_bits(led->map, led->regA, mask, val);
|
||||
}
|
||||
|
||||
static int max77650_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *of_node, *child;
|
||||
struct max77650_led *leds, *led;
|
||||
struct device *parent;
|
||||
struct device *dev;
|
||||
struct regmap *map;
|
||||
const char *label;
|
||||
int rv, num_leds;
|
||||
u32 reg;
|
||||
|
||||
dev = &pdev->dev;
|
||||
parent = dev->parent;
|
||||
of_node = dev->of_node;
|
||||
|
||||
if (!of_node)
|
||||
return -ENODEV;
|
||||
|
||||
leds = devm_kcalloc(dev, sizeof(*leds),
|
||||
MAX77650_LED_NUM_LEDS, GFP_KERNEL);
|
||||
if (!leds)
|
||||
return -ENOMEM;
|
||||
|
||||
map = dev_get_regmap(dev->parent, NULL);
|
||||
if (!map)
|
||||
return -ENODEV;
|
||||
|
||||
num_leds = of_get_child_count(of_node);
|
||||
if (!num_leds || num_leds > MAX77650_LED_NUM_LEDS)
|
||||
return -ENODEV;
|
||||
|
||||
for_each_child_of_node(of_node, child) {
|
||||
rv = of_property_read_u32(child, "reg", ®);
|
||||
if (rv || reg >= MAX77650_LED_NUM_LEDS)
|
||||
return -EINVAL;
|
||||
|
||||
led = &leds[reg];
|
||||
led->map = map;
|
||||
led->regA = MAX77650_LED_A_BASE + reg;
|
||||
led->regB = MAX77650_LED_B_BASE + reg;
|
||||
led->cdev.brightness_set_blocking = max77650_led_brightness_set;
|
||||
led->cdev.max_brightness = MAX77650_LED_MAX_BRIGHTNESS;
|
||||
|
||||
label = of_get_property(child, "label", NULL);
|
||||
if (!label) {
|
||||
led->cdev.name = "max77650::";
|
||||
} else {
|
||||
led->cdev.name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"max77650:%s", label);
|
||||
if (!led->cdev.name)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
of_property_read_string(child, "linux,default-trigger",
|
||||
&led->cdev.default_trigger);
|
||||
|
||||
rv = devm_of_led_classdev_register(dev, child, &led->cdev);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv = regmap_write(map, led->regA, MAX77650_LED_A_DEFAULT);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
rv = regmap_write(map, led->regB, MAX77650_LED_B_DEFAULT);
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
return regmap_write(map,
|
||||
MAX77650_REG_CNFG_LED_TOP,
|
||||
MAX77650_LED_TOP_DEFAULT);
|
||||
}
|
||||
|
||||
static struct platform_driver max77650_led_driver = {
|
||||
.driver = {
|
||||
.name = "max77650-led",
|
||||
},
|
||||
.probe = max77650_led_probe,
|
||||
};
|
||||
module_platform_driver(max77650_led_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77650/77651 LED driver");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -16,7 +16,7 @@ config MFD_CS5535
|
||||
depends on PCI && (X86_32 || (X86 && COMPILE_TEST))
|
||||
---help---
|
||||
This is the core driver for CS5535/CS5536 MFD functions. This is
|
||||
necessary for using the board's GPIO and MFGPT functionality.
|
||||
necessary for using the board's GPIO and MFGPT functionality.
|
||||
|
||||
config MFD_ALTERA_A10SR
|
||||
bool "Altera Arria10 DevKit System Resource chip"
|
||||
@ -29,6 +29,16 @@ config MFD_ALTERA_A10SR
|
||||
accessing the external gpio extender (LEDs & buttons) and
|
||||
power supply alarms (hwmon).
|
||||
|
||||
config MFD_ALTERA_SYSMGR
|
||||
bool "Altera SOCFPGA System Manager"
|
||||
depends on (ARCH_SOCFPGA || ARCH_STRATIX10) && OF
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Select this to get System Manager support for all Altera branded
|
||||
SOCFPGAs. The SOCFPGA System Manager handles all SOCFPGAs by
|
||||
using regmap_mmio accesses for ARM32 parts and SMC calls to
|
||||
EL3 for ARM64 parts.
|
||||
|
||||
config MFD_ACT8945A
|
||||
tristate "Active-semi ACT8945A"
|
||||
select MFD_CORE
|
||||
@ -213,13 +223,13 @@ config MFD_CROS_EC
|
||||
protocol for talking to the EC is defined by the bus driver.
|
||||
|
||||
config MFD_CROS_EC_CHARDEV
|
||||
tristate "Chrome OS Embedded Controller userspace device interface"
|
||||
depends on MFD_CROS_EC
|
||||
---help---
|
||||
This driver adds support to talk with the ChromeOS EC from userspace.
|
||||
tristate "Chrome OS Embedded Controller userspace device interface"
|
||||
depends on MFD_CROS_EC
|
||||
---help---
|
||||
This driver adds support to talk with the ChromeOS EC from userspace.
|
||||
|
||||
If you have a supported Chromebook, choose Y or M here.
|
||||
The module will be called cros_ec_dev.
|
||||
If you have a supported Chromebook, choose Y or M here.
|
||||
The module will be called cros_ec_dev.
|
||||
|
||||
config MFD_MADERA
|
||||
tristate "Cirrus Logic Madera codecs"
|
||||
@ -733,6 +743,20 @@ config MFD_MAX77620
|
||||
provides common support for accessing the device; additional drivers
|
||||
must be enabled in order to use the functionality of the device.
|
||||
|
||||
config MFD_MAX77650
|
||||
tristate "Maxim MAX77650/77651 PMIC Support"
|
||||
depends on I2C
|
||||
depends on OF || COMPILE_TEST
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say Y here to add support for Maxim Semiconductor MAX77650 and
|
||||
MAX77651 Power Management ICs. This is the core multifunction
|
||||
driver for interacting with the device. The module name is
|
||||
'max77650'. Additional drivers can be enabled in order to use
|
||||
the following functionalities of the device: GPIO, regulator,
|
||||
charger, LED, onkey.
|
||||
|
||||
config MFD_MAX77686
|
||||
tristate "Maxim Semiconductor MAX77686/802 PMIC Support"
|
||||
depends on I2C
|
||||
@ -867,7 +891,7 @@ config MFD_CPCAP
|
||||
At least Motorola Droid 4 is known to use CPCAP.
|
||||
|
||||
config MFD_VIPERBOARD
|
||||
tristate "Nano River Technologies Viperboard"
|
||||
tristate "Nano River Technologies Viperboard"
|
||||
select MFD_CORE
|
||||
depends on USB
|
||||
default n
|
||||
@ -903,15 +927,15 @@ config PCF50633_ADC
|
||||
tristate "NXP PCF50633 ADC"
|
||||
depends on MFD_PCF50633
|
||||
help
|
||||
Say yes here if you want to include support for ADC in the
|
||||
NXP PCF50633 chip.
|
||||
Say yes here if you want to include support for ADC in the
|
||||
NXP PCF50633 chip.
|
||||
|
||||
config PCF50633_GPIO
|
||||
tristate "NXP PCF50633 GPIO"
|
||||
depends on MFD_PCF50633
|
||||
help
|
||||
Say yes here if you want to include support GPIO for pins on
|
||||
the PCF50633 chip.
|
||||
Say yes here if you want to include support GPIO for pins on
|
||||
the PCF50633 chip.
|
||||
|
||||
config UCB1400_CORE
|
||||
tristate "Philips UCB1400 Core driver"
|
||||
@ -1026,7 +1050,7 @@ config MFD_RN5T618
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to add support for the Ricoh RN5T567,
|
||||
RN5T618, RC5T619 PMIC.
|
||||
RN5T618, RC5T619 PMIC.
|
||||
This driver provides common support for accessing the device,
|
||||
additional drivers must be enabled in order to use the
|
||||
functionality of the device.
|
||||
@ -1079,9 +1103,9 @@ config MFD_SM501_GPIO
|
||||
bool "Export GPIO via GPIO layer"
|
||||
depends on MFD_SM501 && GPIOLIB
|
||||
---help---
|
||||
This option uses the gpio library layer to export the 64 GPIO
|
||||
lines on the SM501. The platform data is used to supply the
|
||||
base number for the first GPIO line to register.
|
||||
This option uses the gpio library layer to export the 64 GPIO
|
||||
lines on the SM501. The platform data is used to supply the
|
||||
base number for the first GPIO line to register.
|
||||
|
||||
config MFD_SKY81452
|
||||
tristate "Skyworks Solutions SKY81452"
|
||||
@ -1096,16 +1120,16 @@ config MFD_SKY81452
|
||||
will be called sky81452.
|
||||
|
||||
config MFD_SMSC
|
||||
bool "SMSC ECE1099 series chips"
|
||||
depends on I2C=y
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the
|
||||
ece1099 chips from SMSC.
|
||||
bool "SMSC ECE1099 series chips"
|
||||
depends on I2C=y
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the
|
||||
ece1099 chips from SMSC.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called smsc.
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called smsc.
|
||||
|
||||
config MFD_SC27XX_PMIC
|
||||
tristate "Spreadtrum SC27xx PMICs"
|
||||
@ -1171,12 +1195,12 @@ config AB8500_CORE
|
||||
This chip embeds various other multimedia funtionalities as well.
|
||||
|
||||
config AB8500_DEBUG
|
||||
bool "Enable debug info via debugfs"
|
||||
depends on AB8500_GPADC && DEBUG_FS
|
||||
default y if DEBUG_FS
|
||||
help
|
||||
Select this option if you want debug information using the debug
|
||||
filesystem, debugfs.
|
||||
bool "Enable debug info via debugfs"
|
||||
depends on AB8500_GPADC && DEBUG_FS
|
||||
default y if DEBUG_FS
|
||||
help
|
||||
Select this option if you want debug information using the debug
|
||||
filesystem, debugfs.
|
||||
|
||||
config AB8500_GPADC
|
||||
bool "ST-Ericsson AB8500 GPADC driver"
|
||||
@ -1907,6 +1931,19 @@ config MFD_STPMIC1
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called stpmic1.
|
||||
|
||||
config MFD_STMFX
|
||||
tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)"
|
||||
depends on I2C
|
||||
depends on OF || COMPILE_TEST
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Support for the STMicroelectronics Multi-Function eXpander.
|
||||
|
||||
This driver provides common support for accessing the device,
|
||||
additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
menu "Multimedia Capabilities Port drivers"
|
||||
depends on ARCH_SA1100
|
||||
|
||||
|
@ -155,6 +155,7 @@ obj-$(CONFIG_MFD_DA9150) += da9150-core.o
|
||||
|
||||
obj-$(CONFIG_MFD_MAX14577) += max14577.o
|
||||
obj-$(CONFIG_MFD_MAX77620) += max77620.o
|
||||
obj-$(CONFIG_MFD_MAX77650) += max77650.o
|
||||
obj-$(CONFIG_MFD_MAX77686) += max77686.o
|
||||
obj-$(CONFIG_MFD_MAX77693) += max77693.o
|
||||
obj-$(CONFIG_MFD_MAX77843) += max77843.o
|
||||
@ -237,6 +238,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI) += intel_soc_pmic_chtdc_ti.o
|
||||
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
|
||||
|
||||
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
|
||||
obj-$(CONFIG_MFD_ALTERA_SYSMGR) += altera-sysmgr.o
|
||||
obj-$(CONFIG_MFD_STPMIC1) += stpmic1.o
|
||||
obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
|
||||
|
||||
@ -246,4 +248,4 @@ obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o
|
||||
obj-$(CONFIG_MFD_SC27XX_PMIC) += sprd-sc27xx-spi.o
|
||||
obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o
|
||||
obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
|
||||
|
||||
obj-$(CONFIG_MFD_STMFX) += stmfx.o
|
||||
|
@ -2587,7 +2587,7 @@ static ssize_t ab8500_unsubscribe_write(struct file *file,
|
||||
}
|
||||
|
||||
/*
|
||||
* - several deubgfs nodes fops
|
||||
* - several debugfs nodes fops
|
||||
*/
|
||||
|
||||
static const struct file_operations ab8500_bank_fops = {
|
||||
|
211
drivers/mfd/altera-sysmgr.c
Normal file
211
drivers/mfd/altera-sysmgr.c
Normal file
@ -0,0 +1,211 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018-2019, Intel Corporation.
|
||||
* Copyright (C) 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Linaro Ltd.
|
||||
*
|
||||
* Based on syscon driver.
|
||||
*/
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mfd/altera-sysmgr.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/**
|
||||
* struct altr_sysmgr - Altera SOCFPGA System Manager
|
||||
* @regmap: the regmap used for System Manager accesses.
|
||||
* @base : the base address for the System Manager
|
||||
*/
|
||||
struct altr_sysmgr {
|
||||
struct regmap *regmap;
|
||||
resource_size_t *base;
|
||||
};
|
||||
|
||||
static struct platform_driver altr_sysmgr_driver;
|
||||
|
||||
/**
|
||||
* s10_protected_reg_write
|
||||
* Write to a protected SMC register.
|
||||
* @base: Base address of System Manager
|
||||
* @reg: Address offset of register
|
||||
* @val: Value to write
|
||||
* Return: INTEL_SIP_SMC_STATUS_OK (0) on success
|
||||
* INTEL_SIP_SMC_REG_ERROR on error
|
||||
* INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported
|
||||
*/
|
||||
static int s10_protected_reg_write(void *base,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
struct arm_smccc_res result;
|
||||
unsigned long sysmgr_base = (unsigned long)base;
|
||||
|
||||
arm_smccc_smc(INTEL_SIP_SMC_REG_WRITE, sysmgr_base + reg,
|
||||
val, 0, 0, 0, 0, 0, &result);
|
||||
|
||||
return (int)result.a0;
|
||||
}
|
||||
|
||||
/**
|
||||
* s10_protected_reg_read
|
||||
* Read the status of a protected SMC register
|
||||
* @base: Base address of System Manager.
|
||||
* @reg: Address of register
|
||||
* @val: Value read.
|
||||
* Return: INTEL_SIP_SMC_STATUS_OK (0) on success
|
||||
* INTEL_SIP_SMC_REG_ERROR on error
|
||||
* INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION if not supported
|
||||
*/
|
||||
static int s10_protected_reg_read(void *base,
|
||||
unsigned int reg, unsigned int *val)
|
||||
{
|
||||
struct arm_smccc_res result;
|
||||
unsigned long sysmgr_base = (unsigned long)base;
|
||||
|
||||
arm_smccc_smc(INTEL_SIP_SMC_REG_READ, sysmgr_base + reg,
|
||||
0, 0, 0, 0, 0, 0, &result);
|
||||
|
||||
*val = (unsigned int)result.a1;
|
||||
|
||||
return (int)result.a0;
|
||||
}
|
||||
|
||||
static struct regmap_config altr_sysmgr_regmap_cfg = {
|
||||
.name = "altr_sysmgr",
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.fast_io = true,
|
||||
.use_single_read = true,
|
||||
.use_single_write = true,
|
||||
};
|
||||
|
||||
/**
|
||||
* sysmgr_match_phandle
|
||||
* Matching function used by driver_find_device().
|
||||
* Return: True if match is found, otherwise false.
|
||||
*/
|
||||
static int sysmgr_match_phandle(struct device *dev, void *data)
|
||||
{
|
||||
return dev->of_node == (struct device_node *)data;
|
||||
}
|
||||
|
||||
/**
|
||||
* altr_sysmgr_regmap_lookup_by_phandle
|
||||
* Find the sysmgr previous configured in probe() and return regmap property.
|
||||
* Return: regmap if found or error if not found.
|
||||
*/
|
||||
struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
|
||||
const char *property)
|
||||
{
|
||||
struct device *dev;
|
||||
struct altr_sysmgr *sysmgr;
|
||||
struct device_node *sysmgr_np;
|
||||
|
||||
if (property)
|
||||
sysmgr_np = of_parse_phandle(np, property, 0);
|
||||
else
|
||||
sysmgr_np = np;
|
||||
|
||||
if (!sysmgr_np)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
dev = driver_find_device(&altr_sysmgr_driver.driver, NULL,
|
||||
(void *)sysmgr_np, sysmgr_match_phandle);
|
||||
of_node_put(sysmgr_np);
|
||||
if (!dev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
sysmgr = dev_get_drvdata(dev);
|
||||
|
||||
return sysmgr->regmap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(altr_sysmgr_regmap_lookup_by_phandle);
|
||||
|
||||
static int sysmgr_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct altr_sysmgr *sysmgr;
|
||||
struct regmap *regmap;
|
||||
struct resource *res;
|
||||
struct regmap_config sysmgr_config = altr_sysmgr_regmap_cfg;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
sysmgr = devm_kzalloc(dev, sizeof(*sysmgr), GFP_KERNEL);
|
||||
if (!sysmgr)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENOENT;
|
||||
|
||||
sysmgr_config.max_register = resource_size(res) -
|
||||
sysmgr_config.reg_stride;
|
||||
if (of_device_is_compatible(np, "altr,sys-mgr-s10")) {
|
||||
/* Need physical address for SMCC call */
|
||||
sysmgr->base = (resource_size_t *)res->start;
|
||||
sysmgr_config.reg_read = s10_protected_reg_read;
|
||||
sysmgr_config.reg_write = s10_protected_reg_write;
|
||||
|
||||
regmap = devm_regmap_init(dev, NULL, sysmgr->base,
|
||||
&sysmgr_config);
|
||||
} else {
|
||||
sysmgr->base = devm_ioremap(dev, res->start,
|
||||
resource_size(res));
|
||||
if (!sysmgr->base)
|
||||
return -ENOMEM;
|
||||
|
||||
sysmgr_config.max_register = res->end - res->start - 3;
|
||||
regmap = devm_regmap_init_mmio(dev, sysmgr->base,
|
||||
&sysmgr_config);
|
||||
}
|
||||
|
||||
if (IS_ERR(regmap)) {
|
||||
pr_err("regmap init failed\n");
|
||||
return PTR_ERR(regmap);
|
||||
}
|
||||
|
||||
sysmgr->regmap = regmap;
|
||||
|
||||
platform_set_drvdata(pdev, sysmgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id altr_sysmgr_of_match[] = {
|
||||
{ .compatible = "altr,sys-mgr" },
|
||||
{ .compatible = "altr,sys-mgr-s10" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, altr_sysmgr_of_match);
|
||||
|
||||
static struct platform_driver altr_sysmgr_driver = {
|
||||
.probe = sysmgr_probe,
|
||||
.driver = {
|
||||
.name = "altr,system_manager",
|
||||
.of_match_table = altr_sysmgr_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init altr_sysmgr_init(void)
|
||||
{
|
||||
return platform_driver_register(&altr_sysmgr_driver);
|
||||
}
|
||||
core_initcall(altr_sysmgr_init);
|
||||
|
||||
static void __exit altr_sysmgr_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&altr_sysmgr_driver);
|
||||
}
|
||||
module_exit(altr_sysmgr_exit);
|
||||
|
||||
MODULE_AUTHOR("Thor Thayer <>");
|
||||
MODULE_DESCRIPTION("SOCFPGA System Manager driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -141,6 +141,7 @@ static const struct of_device_id atmel_hlcdc_match[] = {
|
||||
{ .compatible = "atmel,sama5d2-hlcdc" },
|
||||
{ .compatible = "atmel,sama5d3-hlcdc" },
|
||||
{ .compatible = "atmel,sama5d4-hlcdc" },
|
||||
{ .compatible = "microchip,sam9x60-hlcdc" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, atmel_hlcdc_match);
|
||||
|
@ -65,6 +65,7 @@ static const struct of_device_id axp20x_i2c_of_match[] = {
|
||||
{ .compatible = "x-powers,axp202", .data = (void *)AXP202_ID },
|
||||
{ .compatible = "x-powers,axp209", .data = (void *)AXP209_ID },
|
||||
{ .compatible = "x-powers,axp221", .data = (void *)AXP221_ID },
|
||||
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
|
||||
{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
|
||||
{ },
|
||||
};
|
||||
@ -75,6 +76,7 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
|
||||
{ "axp202", 0 },
|
||||
{ "axp209", 0 },
|
||||
{ "axp221", 0 },
|
||||
{ "axp223", 0 },
|
||||
{ "axp806", 0 },
|
||||
{ },
|
||||
};
|
||||
|
@ -198,6 +198,12 @@ static const struct resource axp22x_usb_power_supply_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
|
||||
};
|
||||
|
||||
/* AXP803 and AXP813/AXP818 share the same interrupts */
|
||||
static const struct resource axp803_usb_power_supply_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_PLUGIN, "VBUS_PLUGIN"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP803_IRQ_VBUS_REMOVAL, "VBUS_REMOVAL"),
|
||||
};
|
||||
|
||||
static const struct resource axp22x_pek_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP22X_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
@ -741,6 +747,11 @@ static const struct mfd_cell axp803_cells[] = {
|
||||
.of_compatible = "x-powers,axp813-ac-power-supply",
|
||||
.num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources),
|
||||
.resources = axp20x_ac_power_supply_resources,
|
||||
}, {
|
||||
.name = "axp20x-usb-power-supply",
|
||||
.num_resources = ARRAY_SIZE(axp803_usb_power_supply_resources),
|
||||
.resources = axp803_usb_power_supply_resources,
|
||||
.of_compatible = "x-powers,axp813-usb-power-supply",
|
||||
},
|
||||
{ .name = "axp20x-regulator" },
|
||||
};
|
||||
@ -793,6 +804,11 @@ static const struct mfd_cell axp813_cells[] = {
|
||||
.of_compatible = "x-powers,axp813-ac-power-supply",
|
||||
.num_resources = ARRAY_SIZE(axp20x_ac_power_supply_resources),
|
||||
.resources = axp20x_ac_power_supply_resources,
|
||||
}, {
|
||||
.name = "axp20x-usb-power-supply",
|
||||
.num_resources = ARRAY_SIZE(axp803_usb_power_supply_resources),
|
||||
.resources = axp803_usb_power_supply_resources,
|
||||
.of_compatible = "x-powers,axp813-usb-power-supply",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -75,20 +75,49 @@ static irqreturn_t ec_irq_thread(int irq, void *data)
|
||||
|
||||
static int cros_ec_sleep_event(struct cros_ec_device *ec_dev, u8 sleep_event)
|
||||
{
|
||||
int ret;
|
||||
struct {
|
||||
struct cros_ec_command msg;
|
||||
struct ec_params_host_sleep_event req;
|
||||
union {
|
||||
struct ec_params_host_sleep_event req0;
|
||||
struct ec_params_host_sleep_event_v1 req1;
|
||||
struct ec_response_host_sleep_event_v1 resp1;
|
||||
} u;
|
||||
} __packed buf;
|
||||
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
|
||||
buf.req.sleep_event = sleep_event;
|
||||
if (ec_dev->host_sleep_v1) {
|
||||
buf.u.req1.sleep_event = sleep_event;
|
||||
buf.u.req1.suspend_params.sleep_timeout_ms =
|
||||
EC_HOST_SLEEP_TIMEOUT_DEFAULT;
|
||||
|
||||
buf.msg.outsize = sizeof(buf.u.req1);
|
||||
if ((sleep_event == HOST_SLEEP_EVENT_S3_RESUME) ||
|
||||
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME))
|
||||
buf.msg.insize = sizeof(buf.u.resp1);
|
||||
|
||||
buf.msg.version = 1;
|
||||
|
||||
} else {
|
||||
buf.u.req0.sleep_event = sleep_event;
|
||||
buf.msg.outsize = sizeof(buf.u.req0);
|
||||
}
|
||||
|
||||
buf.msg.command = EC_CMD_HOST_SLEEP_EVENT;
|
||||
buf.msg.version = 0;
|
||||
buf.msg.outsize = sizeof(buf.req);
|
||||
|
||||
return cros_ec_cmd_xfer(ec_dev, &buf.msg);
|
||||
ret = cros_ec_cmd_xfer(ec_dev, &buf.msg);
|
||||
|
||||
/* For now, report failure to transition to S0ix with a warning. */
|
||||
if (ret >= 0 && ec_dev->host_sleep_v1 &&
|
||||
(sleep_event == HOST_SLEEP_EVENT_S0IX_RESUME))
|
||||
WARN_ONCE(buf.u.resp1.resume_response.sleep_transitions &
|
||||
EC_HOST_RESUME_SLEEP_TIMEOUT,
|
||||
"EC detected sleep transition timeout. Total slp_s0 transitions: %d",
|
||||
buf.u.resp1.resume_response.sleep_transitions &
|
||||
EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
|
@ -385,7 +385,8 @@ static const struct mfd_cell cros_ec_rtc_cells[] = {
|
||||
};
|
||||
|
||||
static const struct mfd_cell cros_usbpd_charger_cells[] = {
|
||||
{ .name = "cros-usbpd-charger" }
|
||||
{ .name = "cros-usbpd-charger" },
|
||||
{ .name = "cros-usbpd-logger" },
|
||||
};
|
||||
|
||||
static const struct mfd_cell cros_ec_platform_cells[] = {
|
||||
@ -418,6 +419,39 @@ static int ec_device_probe(struct platform_device *pdev)
|
||||
device_initialize(&ec->class_dev);
|
||||
cdev_init(&ec->cdev, &fops);
|
||||
|
||||
/* Check whether this is actually a Fingerprint MCU rather than an EC */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_FINGERPRINT)) {
|
||||
dev_info(dev, "CrOS Fingerprint MCU detected.\n");
|
||||
/*
|
||||
* Help userspace differentiating ECs from FP MCU,
|
||||
* regardless of the probing order.
|
||||
*/
|
||||
ec_platform->ec_name = CROS_EC_DEV_FP_NAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether this is actually an Integrated Sensor Hub (ISH)
|
||||
* rather than an EC.
|
||||
*/
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_ISH)) {
|
||||
dev_info(dev, "CrOS ISH MCU detected.\n");
|
||||
/*
|
||||
* Help userspace differentiating ECs from ISH MCU,
|
||||
* regardless of the probing order.
|
||||
*/
|
||||
ec_platform->ec_name = CROS_EC_DEV_ISH_NAME;
|
||||
}
|
||||
|
||||
/* Check whether this is actually a Touchpad MCU rather than an EC */
|
||||
if (cros_ec_check_features(ec, EC_FEATURE_TOUCHPAD)) {
|
||||
dev_info(dev, "CrOS Touchpad MCU detected.\n");
|
||||
/*
|
||||
* Help userspace differentiating ECs from TP MCU,
|
||||
* regardless of the probing order.
|
||||
*/
|
||||
ec_platform->ec_name = CROS_EC_DEV_TP_NAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the class device
|
||||
* Link to the character device for creating the /dev entry
|
||||
|
@ -178,6 +178,7 @@ static const struct reg_default cs47l35_reg_default[] = {
|
||||
{ 0x00000448, 0x0a83 }, /* R1096 (0x448) - eDRE Enable */
|
||||
{ 0x0000044a, 0x0000 }, /* R1098 (0x44a) - eDRE Manual */
|
||||
{ 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
|
||||
{ 0x00000451, 0x0000 }, /* R1105 (0x451) - DAC AEC Control 2 */
|
||||
{ 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
|
||||
{ 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */
|
||||
{ 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */
|
||||
@ -970,6 +971,7 @@ static bool cs47l35_16bit_readable_register(struct device *dev,
|
||||
case MADERA_EDRE_ENABLE:
|
||||
case MADERA_EDRE_MANUAL:
|
||||
case MADERA_DAC_AEC_CONTROL_1:
|
||||
case MADERA_DAC_AEC_CONTROL_2:
|
||||
case MADERA_NOISE_GATE_CONTROL:
|
||||
case MADERA_PDM_SPK1_CTRL_1:
|
||||
case MADERA_PDM_SPK1_CTRL_2:
|
||||
|
@ -263,6 +263,7 @@ static const struct reg_default cs47l90_reg_default[] = {
|
||||
{ 0x00000440, 0x003f }, /* R1088 (0x440) - DRE Enable */
|
||||
{ 0x00000448, 0x003f }, /* R1096 (0x448) - eDRE Enable */
|
||||
{ 0x00000450, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 1 */
|
||||
{ 0x00000451, 0x0000 }, /* R1104 (0x450) - DAC AEC Control 2 */
|
||||
{ 0x00000458, 0x0000 }, /* R1112 (0x458) - Noise Gate Control */
|
||||
{ 0x00000490, 0x0069 }, /* R1168 (0x490) - PDM SPK1 CTRL 1 */
|
||||
{ 0x00000491, 0x0000 }, /* R1169 (0x491) - PDM SPK1 CTRL 2 */
|
||||
@ -1692,6 +1693,7 @@ static bool cs47l90_16bit_readable_register(struct device *dev,
|
||||
case MADERA_DRE_ENABLE:
|
||||
case MADERA_EDRE_ENABLE:
|
||||
case MADERA_DAC_AEC_CONTROL_1:
|
||||
case MADERA_DAC_AEC_CONTROL_2:
|
||||
case MADERA_NOISE_GATE_CONTROL:
|
||||
case MADERA_PDM_SPK1_CTRL_1:
|
||||
case MADERA_PDM_SPK1_CTRL_2:
|
||||
|
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* da9063-core.c: Device access for Dialog DA9063 modules
|
||||
* Device access for Dialog DA9063 modules
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductors Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
@ -7,11 +8,6 @@
|
||||
* Author: Krystian Garbaciak, Dialog Semiconductor
|
||||
* Author: Michal Hajduk, Dialog Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -26,7 +22,6 @@
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#include <linux/mfd/da9063/core.h>
|
||||
#include <linux/mfd/da9063/pdata.h>
|
||||
#include <linux/mfd/da9063/registers.h>
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
@ -165,7 +160,6 @@ static int da9063_clear_fault_log(struct da9063 *da9063)
|
||||
|
||||
int da9063_device_init(struct da9063 *da9063, unsigned int irq)
|
||||
{
|
||||
struct da9063_pdata *pdata = da9063->dev->platform_data;
|
||||
int model, variant_id, variant_code;
|
||||
int ret;
|
||||
|
||||
@ -173,24 +167,10 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
|
||||
if (ret < 0)
|
||||
dev_err(da9063->dev, "Cannot clear fault log\n");
|
||||
|
||||
if (pdata) {
|
||||
da9063->flags = pdata->flags;
|
||||
da9063->irq_base = pdata->irq_base;
|
||||
} else {
|
||||
da9063->flags = 0;
|
||||
da9063->irq_base = -1;
|
||||
}
|
||||
da9063->flags = 0;
|
||||
da9063->irq_base = -1;
|
||||
da9063->chip_irq = irq;
|
||||
|
||||
if (pdata && pdata->init != NULL) {
|
||||
ret = pdata->init(da9063);
|
||||
if (ret != 0) {
|
||||
dev_err(da9063->dev,
|
||||
"Platform initialization failed.\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model);
|
||||
if (ret < 0) {
|
||||
dev_err(da9063->dev, "Cannot read chip model id.\n");
|
||||
|
@ -1,15 +1,10 @@
|
||||
/* da9063-i2c.c: Interrupt support for Dialog DA9063
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* I2C support for Dialog DA9063
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Krystian Garbaciak, Dialog Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -22,7 +17,6 @@
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/da9063/core.h>
|
||||
#include <linux/mfd/da9063/pdata.h>
|
||||
#include <linux/mfd/da9063/registers.h>
|
||||
|
||||
#include <linux/of.h>
|
||||
|
@ -1,15 +1,10 @@
|
||||
/* da9063-irq.c: Interrupts support for Dialog DA9063
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/* Interrupt support for Dialog DA9063
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Michal Hajduk, Dialog Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -19,7 +14,6 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/da9063/core.h>
|
||||
#include <linux/mfd/da9063/pdata.h>
|
||||
|
||||
#define DA9063_REG_EVENT_A_OFFSET 0
|
||||
#define DA9063_REG_EVENT_B_OFFSET 1
|
||||
|
@ -129,6 +129,19 @@ static const struct intel_lpss_platform_info cnl_i2c_info = {
|
||||
};
|
||||
|
||||
static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||
/* CML */
|
||||
{ PCI_VDEVICE(INTEL, 0x02a8), (kernel_ulong_t)&spt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02a9), (kernel_ulong_t)&spt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02aa), (kernel_ulong_t)&spt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02ab), (kernel_ulong_t)&spt_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02c5), (kernel_ulong_t)&cnl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02c6), (kernel_ulong_t)&cnl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02c7), (kernel_ulong_t)&spt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02e8), (kernel_ulong_t)&cnl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02e9), (kernel_ulong_t)&cnl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02ea), (kernel_ulong_t)&cnl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02eb), (kernel_ulong_t)&cnl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x02fb), (kernel_ulong_t)&spt_info },
|
||||
/* BXT A-Step */
|
||||
{ PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x0aae), (kernel_ulong_t)&bxt_i2c_info },
|
||||
|
@ -273,6 +273,9 @@ static void intel_lpss_init_dev(const struct intel_lpss *lpss)
|
||||
{
|
||||
u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN;
|
||||
|
||||
/* Set the device in reset state */
|
||||
writel(0, lpss->priv + LPSS_PRIV_RESETS);
|
||||
|
||||
intel_lpss_deassert_reset(lpss);
|
||||
|
||||
intel_lpss_set_remap_addr(lpss);
|
||||
|
@ -74,16 +74,6 @@ static const struct dmi_system_id dmi_platform_info[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
|
||||
"6ES7647-0AA00-0YA2"),
|
||||
},
|
||||
.driver_data = (void *)400000,
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "SIMATIC IOT2000"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_ASSET_TAG,
|
||||
"6ES7647-0AA00-1YA2"),
|
||||
},
|
||||
.driver_data = (void *)400000,
|
||||
},
|
||||
|
@ -60,6 +60,7 @@ static struct mfd_cell cht_wc_dev[] = {
|
||||
.resources = cht_wc_ext_charger_resources,
|
||||
},
|
||||
{ .name = "cht_wcove_region", },
|
||||
{ .name = "cht_wcove_leds", },
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -37,6 +37,8 @@
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static struct max77620_chip *max77620_scratch;
|
||||
|
||||
static const struct resource gpio_resources[] = {
|
||||
DEFINE_RES_IRQ(MAX77620_IRQ_TOP_GPIO),
|
||||
};
|
||||
@ -111,6 +113,26 @@ static const struct mfd_cell max20024_children[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell max77663_children[] = {
|
||||
{ .name = "max77620-pinctrl", },
|
||||
{ .name = "max77620-clock", },
|
||||
{ .name = "max77663-pmic", },
|
||||
{ .name = "max77620-watchdog", },
|
||||
{
|
||||
.name = "max77620-gpio",
|
||||
.resources = gpio_resources,
|
||||
.num_resources = ARRAY_SIZE(gpio_resources),
|
||||
}, {
|
||||
.name = "max77620-rtc",
|
||||
.resources = rtc_resources,
|
||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||
}, {
|
||||
.name = "max77663-power",
|
||||
.resources = power_resources,
|
||||
.num_resources = ARRAY_SIZE(power_resources),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_range max77620_readable_ranges[] = {
|
||||
regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_DVSSD4),
|
||||
};
|
||||
@ -171,6 +193,35 @@ static const struct regmap_config max20024_regmap_config = {
|
||||
.volatile_table = &max77620_volatile_table,
|
||||
};
|
||||
|
||||
static const struct regmap_range max77663_readable_ranges[] = {
|
||||
regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table max77663_readable_table = {
|
||||
.yes_ranges = max77663_readable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(max77663_readable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range max77663_writable_ranges[] = {
|
||||
regmap_reg_range(MAX77620_REG_CNFGGLBL1, MAX77620_REG_CID5),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table max77663_writable_table = {
|
||||
.yes_ranges = max77663_writable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(max77663_writable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config max77663_regmap_config = {
|
||||
.name = "power-slave",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = MAX77620_REG_CID5 + 1,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.rd_table = &max77663_readable_table,
|
||||
.wr_table = &max77663_writable_table,
|
||||
.volatile_table = &max77620_volatile_table,
|
||||
};
|
||||
|
||||
/*
|
||||
* MAX77620 and MAX20024 has the following steps of the interrupt handling
|
||||
* for TOP interrupts:
|
||||
@ -240,6 +291,9 @@ static int max77620_get_fps_period_reg_value(struct max77620_chip *chip,
|
||||
case MAX77620:
|
||||
fps_min_period = MAX77620_FPS_PERIOD_MIN_US;
|
||||
break;
|
||||
case MAX77663:
|
||||
fps_min_period = MAX20024_FPS_PERIOD_MIN_US;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -274,6 +328,9 @@ static int max77620_config_fps(struct max77620_chip *chip,
|
||||
case MAX77620:
|
||||
fps_max_period = MAX77620_FPS_PERIOD_MAX_US;
|
||||
break;
|
||||
case MAX77663:
|
||||
fps_max_period = MAX20024_FPS_PERIOD_MAX_US;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -375,6 +432,9 @@ static int max77620_initialise_fps(struct max77620_chip *chip)
|
||||
}
|
||||
|
||||
skip_fps:
|
||||
if (chip->chip_id == MAX77663)
|
||||
return 0;
|
||||
|
||||
/* Enable wake on EN0 pin */
|
||||
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
|
||||
MAX77620_ONOFFCNFG2_WK_EN0,
|
||||
@ -423,6 +483,15 @@ static int max77620_read_es_version(struct max77620_chip *chip)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max77620_pm_power_off(void)
|
||||
{
|
||||
struct max77620_chip *chip = max77620_scratch;
|
||||
|
||||
regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG1,
|
||||
MAX77620_ONOFFCNFG1_SFT_RST,
|
||||
MAX77620_ONOFFCNFG1_SFT_RST);
|
||||
}
|
||||
|
||||
static int max77620_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@ -430,6 +499,7 @@ static int max77620_probe(struct i2c_client *client,
|
||||
struct max77620_chip *chip;
|
||||
const struct mfd_cell *mfd_cells;
|
||||
int n_mfd_cells;
|
||||
bool pm_off;
|
||||
int ret;
|
||||
|
||||
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
|
||||
@ -453,6 +523,11 @@ static int max77620_probe(struct i2c_client *client,
|
||||
n_mfd_cells = ARRAY_SIZE(max20024_children);
|
||||
rmap_config = &max20024_regmap_config;
|
||||
break;
|
||||
case MAX77663:
|
||||
mfd_cells = max77663_children;
|
||||
n_mfd_cells = ARRAY_SIZE(max77663_children);
|
||||
rmap_config = &max77663_regmap_config;
|
||||
break;
|
||||
default:
|
||||
dev_err(chip->dev, "ChipID is invalid %d\n", chip->chip_id);
|
||||
return -EINVAL;
|
||||
@ -491,6 +566,12 @@ static int max77620_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_off = of_device_is_system_power_controller(client->dev.of_node);
|
||||
if (pm_off && !pm_power_off) {
|
||||
max77620_scratch = chip;
|
||||
pm_power_off = max77620_pm_power_off;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -546,6 +627,9 @@ static int max77620_i2c_suspend(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (chip->chip_id == MAX77663)
|
||||
goto out;
|
||||
|
||||
/* Disable WK_EN0 */
|
||||
ret = regmap_update_bits(chip->rmap, MAX77620_REG_ONOFFCNFG2,
|
||||
MAX77620_ONOFFCNFG2_WK_EN0, 0);
|
||||
@ -581,7 +665,7 @@ static int max77620_i2c_resume(struct device *dev)
|
||||
* For MAX20024: No need to configure WKEN0 on resume as
|
||||
* it is configured on Init.
|
||||
*/
|
||||
if (chip->chip_id == MAX20024)
|
||||
if (chip->chip_id == MAX20024 || chip->chip_id == MAX77663)
|
||||
goto out;
|
||||
|
||||
/* Enable WK_EN0 */
|
||||
@ -603,6 +687,7 @@ out:
|
||||
static const struct i2c_device_id max77620_id[] = {
|
||||
{"max77620", MAX77620},
|
||||
{"max20024", MAX20024},
|
||||
{"max77663", MAX77663},
|
||||
{},
|
||||
};
|
||||
|
||||
|
232
drivers/mfd/max77650.c
Normal file
232
drivers/mfd/max77650.c
Normal file
@ -0,0 +1,232 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2018 BayLibre SAS
|
||||
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
//
|
||||
// Core MFD driver for MAXIM 77650/77651 charger/power-supply.
|
||||
// Programming manual: https://pdfserv.maximintegrated.com/en/an/AN6428.pdf
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/max77650.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MAX77650_INT_GPI_F_MSK BIT(0)
|
||||
#define MAX77650_INT_GPI_R_MSK BIT(1)
|
||||
#define MAX77650_INT_GPI_MSK \
|
||||
(MAX77650_INT_GPI_F_MSK | MAX77650_INT_GPI_R_MSK)
|
||||
#define MAX77650_INT_nEN_F_MSK BIT(2)
|
||||
#define MAX77650_INT_nEN_R_MSK BIT(3)
|
||||
#define MAX77650_INT_TJAL1_R_MSK BIT(4)
|
||||
#define MAX77650_INT_TJAL2_R_MSK BIT(5)
|
||||
#define MAX77650_INT_DOD_R_MSK BIT(6)
|
||||
|
||||
#define MAX77650_INT_THM_MSK BIT(0)
|
||||
#define MAX77650_INT_CHG_MSK BIT(1)
|
||||
#define MAX77650_INT_CHGIN_MSK BIT(2)
|
||||
#define MAX77650_INT_TJ_REG_MSK BIT(3)
|
||||
#define MAX77650_INT_CHGIN_CTRL_MSK BIT(4)
|
||||
#define MAX77650_INT_SYS_CTRL_MSK BIT(5)
|
||||
#define MAX77650_INT_SYS_CNFG_MSK BIT(6)
|
||||
|
||||
#define MAX77650_INT_GLBL_OFFSET 0
|
||||
#define MAX77650_INT_CHG_OFFSET 1
|
||||
|
||||
#define MAX77650_SBIA_LPM_MASK BIT(5)
|
||||
#define MAX77650_SBIA_LPM_DISABLED 0x00
|
||||
|
||||
enum {
|
||||
MAX77650_INT_GPI,
|
||||
MAX77650_INT_nEN_F,
|
||||
MAX77650_INT_nEN_R,
|
||||
MAX77650_INT_TJAL1_R,
|
||||
MAX77650_INT_TJAL2_R,
|
||||
MAX77650_INT_DOD_R,
|
||||
MAX77650_INT_THM,
|
||||
MAX77650_INT_CHG,
|
||||
MAX77650_INT_CHGIN,
|
||||
MAX77650_INT_TJ_REG,
|
||||
MAX77650_INT_CHGIN_CTRL,
|
||||
MAX77650_INT_SYS_CTRL,
|
||||
MAX77650_INT_SYS_CNFG,
|
||||
};
|
||||
|
||||
static const struct resource max77650_charger_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHG, "CHG"),
|
||||
DEFINE_RES_IRQ_NAMED(MAX77650_INT_CHGIN, "CHGIN"),
|
||||
};
|
||||
|
||||
static const struct resource max77650_gpio_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(MAX77650_INT_GPI, "GPI"),
|
||||
};
|
||||
|
||||
static const struct resource max77650_onkey_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_F, "nEN_F"),
|
||||
DEFINE_RES_IRQ_NAMED(MAX77650_INT_nEN_R, "nEN_R"),
|
||||
};
|
||||
|
||||
static const struct mfd_cell max77650_cells[] = {
|
||||
{
|
||||
.name = "max77650-regulator",
|
||||
.of_compatible = "maxim,max77650-regulator",
|
||||
}, {
|
||||
.name = "max77650-charger",
|
||||
.of_compatible = "maxim,max77650-charger",
|
||||
.resources = max77650_charger_resources,
|
||||
.num_resources = ARRAY_SIZE(max77650_charger_resources),
|
||||
}, {
|
||||
.name = "max77650-gpio",
|
||||
.of_compatible = "maxim,max77650-gpio",
|
||||
.resources = max77650_gpio_resources,
|
||||
.num_resources = ARRAY_SIZE(max77650_gpio_resources),
|
||||
}, {
|
||||
.name = "max77650-led",
|
||||
.of_compatible = "maxim,max77650-led",
|
||||
}, {
|
||||
.name = "max77650-onkey",
|
||||
.of_compatible = "maxim,max77650-onkey",
|
||||
.resources = max77650_onkey_resources,
|
||||
.num_resources = ARRAY_SIZE(max77650_onkey_resources),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_irq max77650_irqs[] = {
|
||||
[MAX77650_INT_GPI] = {
|
||||
.reg_offset = MAX77650_INT_GLBL_OFFSET,
|
||||
.mask = MAX77650_INT_GPI_MSK,
|
||||
.type = {
|
||||
.type_falling_val = MAX77650_INT_GPI_F_MSK,
|
||||
.type_rising_val = MAX77650_INT_GPI_R_MSK,
|
||||
.types_supported = IRQ_TYPE_EDGE_BOTH,
|
||||
},
|
||||
},
|
||||
REGMAP_IRQ_REG(MAX77650_INT_nEN_F,
|
||||
MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_F_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_nEN_R,
|
||||
MAX77650_INT_GLBL_OFFSET, MAX77650_INT_nEN_R_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_TJAL1_R,
|
||||
MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL1_R_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_TJAL2_R,
|
||||
MAX77650_INT_GLBL_OFFSET, MAX77650_INT_TJAL2_R_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_DOD_R,
|
||||
MAX77650_INT_GLBL_OFFSET, MAX77650_INT_DOD_R_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_THM,
|
||||
MAX77650_INT_CHG_OFFSET, MAX77650_INT_THM_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_CHG,
|
||||
MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHG_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_CHGIN,
|
||||
MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_TJ_REG,
|
||||
MAX77650_INT_CHG_OFFSET, MAX77650_INT_TJ_REG_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_CHGIN_CTRL,
|
||||
MAX77650_INT_CHG_OFFSET, MAX77650_INT_CHGIN_CTRL_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_SYS_CTRL,
|
||||
MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CTRL_MSK),
|
||||
REGMAP_IRQ_REG(MAX77650_INT_SYS_CNFG,
|
||||
MAX77650_INT_CHG_OFFSET, MAX77650_INT_SYS_CNFG_MSK),
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip max77650_irq_chip = {
|
||||
.name = "max77650-irq",
|
||||
.irqs = max77650_irqs,
|
||||
.num_irqs = ARRAY_SIZE(max77650_irqs),
|
||||
.num_regs = 2,
|
||||
.status_base = MAX77650_REG_INT_GLBL,
|
||||
.mask_base = MAX77650_REG_INTM_GLBL,
|
||||
.type_in_mask = true,
|
||||
.type_invert = true,
|
||||
.init_ack_masked = true,
|
||||
.clear_on_unmask = true,
|
||||
};
|
||||
|
||||
static const struct regmap_config max77650_regmap_config = {
|
||||
.name = "max77650",
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int max77650_i2c_probe(struct i2c_client *i2c)
|
||||
{
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
struct device *dev = &i2c->dev;
|
||||
struct irq_domain *domain;
|
||||
struct regmap *map;
|
||||
unsigned int val;
|
||||
int rv, id;
|
||||
|
||||
map = devm_regmap_init_i2c(i2c, &max77650_regmap_config);
|
||||
if (IS_ERR(map)) {
|
||||
dev_err(dev, "Unable to initialise I2C Regmap\n");
|
||||
return PTR_ERR(map);
|
||||
}
|
||||
|
||||
rv = regmap_read(map, MAX77650_REG_CID, &val);
|
||||
if (rv) {
|
||||
dev_err(dev, "Unable to read Chip ID\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
id = MAX77650_CID_BITS(val);
|
||||
switch (id) {
|
||||
case MAX77650_CID_77650A:
|
||||
case MAX77650_CID_77650C:
|
||||
case MAX77650_CID_77651A:
|
||||
case MAX77650_CID_77651B:
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "Chip not supported - ID: 0x%02x\n", id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* This IC has a low-power mode which reduces the quiescent current
|
||||
* consumption to ~5.6uA but is only suitable for systems consuming
|
||||
* less than ~2mA. Since this is not likely the case even on
|
||||
* linux-based wearables - keep the chip in normal power mode.
|
||||
*/
|
||||
rv = regmap_update_bits(map,
|
||||
MAX77650_REG_CNFG_GLBL,
|
||||
MAX77650_SBIA_LPM_MASK,
|
||||
MAX77650_SBIA_LPM_DISABLED);
|
||||
if (rv) {
|
||||
dev_err(dev, "Unable to change the power mode\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = devm_regmap_add_irq_chip(dev, map, i2c->irq,
|
||||
IRQF_ONESHOT | IRQF_SHARED, 0,
|
||||
&max77650_irq_chip, &irq_data);
|
||||
if (rv) {
|
||||
dev_err(dev, "Unable to add Regmap IRQ chip\n");
|
||||
return rv;
|
||||
}
|
||||
|
||||
domain = regmap_irq_get_domain(irq_data);
|
||||
|
||||
return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
|
||||
max77650_cells, ARRAY_SIZE(max77650_cells),
|
||||
NULL, 0, domain);
|
||||
}
|
||||
|
||||
static const struct of_device_id max77650_of_match[] = {
|
||||
{ .compatible = "maxim,max77650" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max77650_of_match);
|
||||
|
||||
static struct i2c_driver max77650_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "max77650",
|
||||
.of_match_table = of_match_ptr(max77650_of_match),
|
||||
},
|
||||
.probe_new = max77650_i2c_probe,
|
||||
};
|
||||
module_i2c_driver(max77650_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77650/77651 multi-function core driver");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -269,6 +269,19 @@ fail_alloc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mfd_add_devices - register child devices
|
||||
*
|
||||
* @parent: Pointer to parent device.
|
||||
* @id: Can be PLATFORM_DEVID_AUTO to let the Platform API take care
|
||||
* of device numbering, or will be added to a device's cell_id.
|
||||
* @cells: Array of (struct mfd_cell)s describing child devices.
|
||||
* @n_devs: Number of child devices to register.
|
||||
* @mem_base: Parent register range resource for child devices.
|
||||
* @irq_base: Base of the range of virtual interrupt numbers allocated for
|
||||
* this MFD device. Unused if @domain is specified.
|
||||
* @domain: Interrupt domain to create mappings for hardware interrupts.
|
||||
*/
|
||||
int mfd_add_devices(struct device *parent, int id,
|
||||
const struct mfd_cell *cells, int n_devs,
|
||||
struct resource *mem_base,
|
||||
|
@ -568,14 +568,6 @@ static int rk808_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id rk808_ids[] = {
|
||||
{ "rk805" },
|
||||
{ "rk808" },
|
||||
{ "rk818" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rk808_ids);
|
||||
|
||||
static struct i2c_driver rk808_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "rk808",
|
||||
@ -583,7 +575,6 @@ static struct i2c_driver rk808_i2c_driver = {
|
||||
},
|
||||
.probe = rk808_probe,
|
||||
.remove = rk808_remove,
|
||||
.id_table = rk808_ids,
|
||||
};
|
||||
|
||||
module_i2c_driver(rk808_i2c_driver);
|
||||
|
@ -28,45 +28,33 @@
|
||||
#include <linux/regmap.h>
|
||||
|
||||
static const struct mfd_cell s5m8751_devs[] = {
|
||||
{
|
||||
.name = "s5m8751-pmic",
|
||||
}, {
|
||||
.name = "s5m-charger",
|
||||
}, {
|
||||
.name = "s5m8751-codec",
|
||||
},
|
||||
{ .name = "s5m8751-pmic", },
|
||||
{ .name = "s5m-charger", },
|
||||
{ .name = "s5m8751-codec", },
|
||||
};
|
||||
|
||||
static const struct mfd_cell s5m8763_devs[] = {
|
||||
{
|
||||
.name = "s5m8763-pmic",
|
||||
}, {
|
||||
.name = "s5m-rtc",
|
||||
}, {
|
||||
.name = "s5m-charger",
|
||||
},
|
||||
{ .name = "s5m8763-pmic", },
|
||||
{ .name = "s5m-rtc", },
|
||||
{ .name = "s5m-charger", },
|
||||
};
|
||||
|
||||
static const struct mfd_cell s5m8767_devs[] = {
|
||||
{ .name = "s5m8767-pmic", },
|
||||
{ .name = "s5m-rtc", },
|
||||
{
|
||||
.name = "s5m8767-pmic",
|
||||
}, {
|
||||
.name = "s5m-rtc",
|
||||
}, {
|
||||
.name = "s5m8767-clk",
|
||||
.of_compatible = "samsung,s5m8767-clk",
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mps11_devs[] = {
|
||||
{ .name = "s2mps11-regulator", },
|
||||
{ .name = "s2mps14-rtc", },
|
||||
{
|
||||
.name = "s2mps11-regulator",
|
||||
}, {
|
||||
.name = "s2mps14-rtc",
|
||||
}, {
|
||||
.name = "s2mps11-clk",
|
||||
.of_compatible = "samsung,s2mps11-clk",
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mps13_devs[] = {
|
||||
@ -79,37 +67,30 @@ static const struct mfd_cell s2mps13_devs[] = {
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mps14_devs[] = {
|
||||
{ .name = "s2mps14-regulator", },
|
||||
{ .name = "s2mps14-rtc", },
|
||||
{
|
||||
.name = "s2mps14-regulator",
|
||||
}, {
|
||||
.name = "s2mps14-rtc",
|
||||
}, {
|
||||
.name = "s2mps14-clk",
|
||||
.of_compatible = "samsung,s2mps14-clk",
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mps15_devs[] = {
|
||||
{ .name = "s2mps15-regulator", },
|
||||
{ .name = "s2mps15-rtc", },
|
||||
{
|
||||
.name = "s2mps15-regulator",
|
||||
}, {
|
||||
.name = "s2mps15-rtc",
|
||||
}, {
|
||||
.name = "s2mps13-clk",
|
||||
.of_compatible = "samsung,s2mps13-clk",
|
||||
},
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mpa01_devs[] = {
|
||||
{
|
||||
.name = "s2mpa01-pmic",
|
||||
},
|
||||
{ .name = "s2mpa01-pmic", },
|
||||
{ .name = "s2mps14-rtc", },
|
||||
};
|
||||
|
||||
static const struct mfd_cell s2mpu02_devs[] = {
|
||||
{
|
||||
.name = "s2mpu02-regulator",
|
||||
},
|
||||
{ .name = "s2mpu02-regulator", },
|
||||
};
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
@ -455,6 +455,9 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
|
||||
case S5M8767X:
|
||||
sec_irq_chip = &s5m8767_irq_chip;
|
||||
break;
|
||||
case S2MPA01:
|
||||
sec_irq_chip = &s2mps14_irq_chip;
|
||||
break;
|
||||
case S2MPS11X:
|
||||
sec_irq_chip = &s2mps11_irq_chip;
|
||||
break;
|
||||
|
@ -80,8 +80,6 @@ struct ssbi {
|
||||
int (*write)(struct ssbi *, u16 addr, const u8 *buf, int len);
|
||||
};
|
||||
|
||||
#define to_ssbi(dev) platform_get_drvdata(to_platform_device(dev))
|
||||
|
||||
static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg)
|
||||
{
|
||||
return readl(ssbi->base + reg);
|
||||
@ -243,7 +241,7 @@ err:
|
||||
|
||||
int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len)
|
||||
{
|
||||
struct ssbi *ssbi = to_ssbi(dev);
|
||||
struct ssbi *ssbi = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
@ -257,7 +255,7 @@ EXPORT_SYMBOL_GPL(ssbi_read);
|
||||
|
||||
int ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len)
|
||||
{
|
||||
struct ssbi *ssbi = to_ssbi(dev);
|
||||
struct ssbi *ssbi = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
|
545
drivers/mfd/stmfx.c
Normal file
545
drivers/mfd/stmfx.c
Normal file
@ -0,0 +1,545 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for STMicroelectronics Multi-Function eXpander (STMFX) core
|
||||
*
|
||||
* Copyright (C) 2019 STMicroelectronics
|
||||
* Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/stmfx.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
static bool stmfx_reg_volatile(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case STMFX_REG_SYS_CTRL:
|
||||
case STMFX_REG_IRQ_SRC_EN:
|
||||
case STMFX_REG_IRQ_PENDING:
|
||||
case STMFX_REG_IRQ_GPI_PENDING1:
|
||||
case STMFX_REG_IRQ_GPI_PENDING2:
|
||||
case STMFX_REG_IRQ_GPI_PENDING3:
|
||||
case STMFX_REG_GPIO_STATE1:
|
||||
case STMFX_REG_GPIO_STATE2:
|
||||
case STMFX_REG_GPIO_STATE3:
|
||||
case STMFX_REG_IRQ_GPI_SRC1:
|
||||
case STMFX_REG_IRQ_GPI_SRC2:
|
||||
case STMFX_REG_IRQ_GPI_SRC3:
|
||||
case STMFX_REG_GPO_SET1:
|
||||
case STMFX_REG_GPO_SET2:
|
||||
case STMFX_REG_GPO_SET3:
|
||||
case STMFX_REG_GPO_CLR1:
|
||||
case STMFX_REG_GPO_CLR2:
|
||||
case STMFX_REG_GPO_CLR3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool stmfx_reg_writeable(struct device *dev, unsigned int reg)
|
||||
{
|
||||
return (reg >= STMFX_REG_SYS_CTRL);
|
||||
}
|
||||
|
||||
static const struct regmap_config stmfx_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.reg_stride = 1,
|
||||
.val_bits = 8,
|
||||
.max_register = STMFX_REG_MAX,
|
||||
.volatile_reg = stmfx_reg_volatile,
|
||||
.writeable_reg = stmfx_reg_writeable,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const struct resource stmfx_pinctrl_resources[] = {
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_GPIO),
|
||||
};
|
||||
|
||||
static const struct resource stmfx_idd_resources[] = {
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_IDD),
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_ERROR),
|
||||
};
|
||||
|
||||
static const struct resource stmfx_ts_resources[] = {
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_DET),
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_NE),
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_TH),
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_FULL),
|
||||
DEFINE_RES_IRQ(STMFX_REG_IRQ_SRC_EN_TS_OVF),
|
||||
};
|
||||
|
||||
static struct mfd_cell stmfx_cells[] = {
|
||||
{
|
||||
.of_compatible = "st,stmfx-0300-pinctrl",
|
||||
.name = "stmfx-pinctrl",
|
||||
.resources = stmfx_pinctrl_resources,
|
||||
.num_resources = ARRAY_SIZE(stmfx_pinctrl_resources),
|
||||
},
|
||||
{
|
||||
.of_compatible = "st,stmfx-0300-idd",
|
||||
.name = "stmfx-idd",
|
||||
.resources = stmfx_idd_resources,
|
||||
.num_resources = ARRAY_SIZE(stmfx_idd_resources),
|
||||
},
|
||||
{
|
||||
.of_compatible = "st,stmfx-0300-ts",
|
||||
.name = "stmfx-ts",
|
||||
.resources = stmfx_ts_resources,
|
||||
.num_resources = ARRAY_SIZE(stmfx_ts_resources),
|
||||
},
|
||||
};
|
||||
|
||||
static u8 stmfx_func_to_mask(u32 func)
|
||||
{
|
||||
u8 mask = 0;
|
||||
|
||||
if (func & STMFX_FUNC_GPIO)
|
||||
mask |= STMFX_REG_SYS_CTRL_GPIO_EN;
|
||||
|
||||
if ((func & STMFX_FUNC_ALTGPIO_LOW) || (func & STMFX_FUNC_ALTGPIO_HIGH))
|
||||
mask |= STMFX_REG_SYS_CTRL_ALTGPIO_EN;
|
||||
|
||||
if (func & STMFX_FUNC_TS)
|
||||
mask |= STMFX_REG_SYS_CTRL_TS_EN;
|
||||
|
||||
if (func & STMFX_FUNC_IDD)
|
||||
mask |= STMFX_REG_SYS_CTRL_IDD_EN;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
int stmfx_function_enable(struct stmfx *stmfx, u32 func)
|
||||
{
|
||||
u32 sys_ctrl;
|
||||
u8 mask;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(stmfx->map, STMFX_REG_SYS_CTRL, &sys_ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* IDD and TS have priority in STMFX FW, so if IDD and TS are enabled,
|
||||
* ALTGPIO function is disabled by STMFX FW. If IDD or TS is enabled,
|
||||
* the number of aGPIO available decreases. To avoid GPIO management
|
||||
* disturbance, abort IDD or TS function enable in this case.
|
||||
*/
|
||||
if (((func & STMFX_FUNC_IDD) || (func & STMFX_FUNC_TS)) &&
|
||||
(sys_ctrl & STMFX_REG_SYS_CTRL_ALTGPIO_EN)) {
|
||||
dev_err(stmfx->dev, "ALTGPIO function already enabled\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* If TS is enabled, aGPIO[3:0] cannot be used */
|
||||
if ((func & STMFX_FUNC_ALTGPIO_LOW) &&
|
||||
(sys_ctrl & STMFX_REG_SYS_CTRL_TS_EN)) {
|
||||
dev_err(stmfx->dev, "TS in use, aGPIO[3:0] unavailable\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* If IDD is enabled, aGPIO[7:4] cannot be used */
|
||||
if ((func & STMFX_FUNC_ALTGPIO_HIGH) &&
|
||||
(sys_ctrl & STMFX_REG_SYS_CTRL_IDD_EN)) {
|
||||
dev_err(stmfx->dev, "IDD in use, aGPIO[7:4] unavailable\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
mask = stmfx_func_to_mask(func);
|
||||
|
||||
return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, mask);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stmfx_function_enable);
|
||||
|
||||
int stmfx_function_disable(struct stmfx *stmfx, u32 func)
|
||||
{
|
||||
u8 mask = stmfx_func_to_mask(func);
|
||||
|
||||
return regmap_update_bits(stmfx->map, STMFX_REG_SYS_CTRL, mask, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(stmfx_function_disable);
|
||||
|
||||
static void stmfx_irq_bus_lock(struct irq_data *data)
|
||||
{
|
||||
struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&stmfx->lock);
|
||||
}
|
||||
|
||||
static void stmfx_irq_bus_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
|
||||
|
||||
regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, stmfx->irq_src);
|
||||
|
||||
mutex_unlock(&stmfx->lock);
|
||||
}
|
||||
|
||||
static void stmfx_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
|
||||
|
||||
stmfx->irq_src &= ~BIT(data->hwirq % 8);
|
||||
}
|
||||
|
||||
static void stmfx_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct stmfx *stmfx = irq_data_get_irq_chip_data(data);
|
||||
|
||||
stmfx->irq_src |= BIT(data->hwirq % 8);
|
||||
}
|
||||
|
||||
static struct irq_chip stmfx_irq_chip = {
|
||||
.name = "stmfx-core",
|
||||
.irq_bus_lock = stmfx_irq_bus_lock,
|
||||
.irq_bus_sync_unlock = stmfx_irq_bus_sync_unlock,
|
||||
.irq_mask = stmfx_irq_mask,
|
||||
.irq_unmask = stmfx_irq_unmask,
|
||||
};
|
||||
|
||||
static irqreturn_t stmfx_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct stmfx *stmfx = data;
|
||||
unsigned long n, pending;
|
||||
u32 ack;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(stmfx->map, STMFX_REG_IRQ_PENDING,
|
||||
(u32 *)&pending);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
|
||||
/*
|
||||
* There is no ACK for GPIO, MFX_REG_IRQ_PENDING_GPIO is a logical OR
|
||||
* of MFX_REG_IRQ_GPI _PENDING1/_PENDING2/_PENDING3
|
||||
*/
|
||||
ack = pending & ~BIT(STMFX_REG_IRQ_SRC_EN_GPIO);
|
||||
if (ack) {
|
||||
ret = regmap_write(stmfx->map, STMFX_REG_IRQ_ACK, ack);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
for_each_set_bit(n, &pending, STMFX_REG_IRQ_SRC_MAX)
|
||||
handle_nested_irq(irq_find_mapping(stmfx->irq_domain, n));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int stmfx_irq_map(struct irq_domain *d, unsigned int virq,
|
||||
irq_hw_number_t hwirq)
|
||||
{
|
||||
irq_set_chip_data(virq, d->host_data);
|
||||
irq_set_chip_and_handler(virq, &stmfx_irq_chip, handle_simple_irq);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
irq_set_noprobe(virq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stmfx_irq_unmap(struct irq_domain *d, unsigned int virq)
|
||||
{
|
||||
irq_set_chip_and_handler(virq, NULL, NULL);
|
||||
irq_set_chip_data(virq, NULL);
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops stmfx_irq_ops = {
|
||||
.map = stmfx_irq_map,
|
||||
.unmap = stmfx_irq_unmap,
|
||||
};
|
||||
|
||||
static void stmfx_irq_exit(struct i2c_client *client)
|
||||
{
|
||||
struct stmfx *stmfx = i2c_get_clientdata(client);
|
||||
int hwirq;
|
||||
|
||||
for (hwirq = 0; hwirq < STMFX_REG_IRQ_SRC_MAX; hwirq++)
|
||||
irq_dispose_mapping(irq_find_mapping(stmfx->irq_domain, hwirq));
|
||||
|
||||
irq_domain_remove(stmfx->irq_domain);
|
||||
}
|
||||
|
||||
static int stmfx_irq_init(struct i2c_client *client)
|
||||
{
|
||||
struct stmfx *stmfx = i2c_get_clientdata(client);
|
||||
u32 irqoutpin = 0, irqtrigger;
|
||||
int ret;
|
||||
|
||||
stmfx->irq_domain = irq_domain_add_simple(stmfx->dev->of_node,
|
||||
STMFX_REG_IRQ_SRC_MAX, 0,
|
||||
&stmfx_irq_ops, stmfx);
|
||||
if (!stmfx->irq_domain) {
|
||||
dev_err(stmfx->dev, "Failed to create IRQ domain\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!of_property_read_bool(stmfx->dev->of_node, "drive-open-drain"))
|
||||
irqoutpin |= STMFX_REG_IRQ_OUT_PIN_TYPE;
|
||||
|
||||
irqtrigger = irq_get_trigger_type(client->irq);
|
||||
if ((irqtrigger & IRQ_TYPE_EDGE_RISING) ||
|
||||
(irqtrigger & IRQ_TYPE_LEVEL_HIGH))
|
||||
irqoutpin |= STMFX_REG_IRQ_OUT_PIN_POL;
|
||||
|
||||
ret = regmap_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN, irqoutpin);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_request_threaded_irq(stmfx->dev, client->irq,
|
||||
NULL, stmfx_irq_handler,
|
||||
irqtrigger | IRQF_ONESHOT,
|
||||
"stmfx", stmfx);
|
||||
if (ret)
|
||||
stmfx_irq_exit(client);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmfx_chip_reset(struct stmfx *stmfx)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write(stmfx->map, STMFX_REG_SYS_CTRL,
|
||||
STMFX_REG_SYS_CTRL_SWRST);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msleep(STMFX_BOOT_TIME_MS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmfx_chip_init(struct i2c_client *client)
|
||||
{
|
||||
struct stmfx *stmfx = i2c_get_clientdata(client);
|
||||
u32 id;
|
||||
u8 version[2];
|
||||
int ret;
|
||||
|
||||
stmfx->vdd = devm_regulator_get_optional(&client->dev, "vdd");
|
||||
ret = PTR_ERR_OR_ZERO(stmfx->vdd);
|
||||
if (ret == -ENODEV) {
|
||||
stmfx->vdd = NULL;
|
||||
} else if (ret == -EPROBE_DEFER) {
|
||||
return ret;
|
||||
} else if (ret) {
|
||||
dev_err(&client->dev, "Failed to get VDD regulator: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (stmfx->vdd) {
|
||||
ret = regulator_enable(stmfx->vdd);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "VDD enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_read(stmfx->map, STMFX_REG_CHIP_ID, &id);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Error reading chip ID: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that ID is the complement of the I2C address:
|
||||
* STMFX I2C address follows the 7-bit format (MSB), that's why
|
||||
* client->addr is shifted.
|
||||
*
|
||||
* STMFX_I2C_ADDR| STMFX | Linux
|
||||
* input pin | I2C device address | I2C device address
|
||||
*---------------------------------------------------------
|
||||
* 0 | b: 1000 010x h:0x84 | 0x42
|
||||
* 1 | b: 1000 011x h:0x86 | 0x43
|
||||
*/
|
||||
if (FIELD_GET(STMFX_REG_CHIP_ID_MASK, ~id) != (client->addr << 1)) {
|
||||
dev_err(&client->dev, "Unknown chip ID: %#x\n", id);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(stmfx->map, STMFX_REG_FW_VERSION_MSB,
|
||||
version, ARRAY_SIZE(version));
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Error reading FW version: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "STMFX id: %#x, fw version: %x.%02x\n",
|
||||
id, version[0], version[1]);
|
||||
|
||||
ret = stmfx_chip_reset(stmfx);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Failed to reset chip: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (stmfx->vdd)
|
||||
return regulator_disable(stmfx->vdd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmfx_chip_exit(struct i2c_client *client)
|
||||
{
|
||||
struct stmfx *stmfx = i2c_get_clientdata(client);
|
||||
|
||||
regmap_write(stmfx->map, STMFX_REG_IRQ_SRC_EN, 0);
|
||||
regmap_write(stmfx->map, STMFX_REG_SYS_CTRL, 0);
|
||||
|
||||
if (stmfx->vdd)
|
||||
return regulator_disable(stmfx->vdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct stmfx *stmfx;
|
||||
int ret;
|
||||
|
||||
stmfx = devm_kzalloc(dev, sizeof(*stmfx), GFP_KERNEL);
|
||||
if (!stmfx)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, stmfx);
|
||||
|
||||
stmfx->dev = dev;
|
||||
|
||||
stmfx->map = devm_regmap_init_i2c(client, &stmfx_regmap_config);
|
||||
if (IS_ERR(stmfx->map)) {
|
||||
ret = PTR_ERR(stmfx->map);
|
||||
dev_err(dev, "Failed to allocate register map: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&stmfx->lock);
|
||||
|
||||
ret = stmfx_chip_init(client);
|
||||
if (ret) {
|
||||
if (ret == -ETIMEDOUT)
|
||||
return -EPROBE_DEFER;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (client->irq < 0) {
|
||||
dev_err(dev, "Failed to get IRQ: %d\n", client->irq);
|
||||
ret = client->irq;
|
||||
goto err_chip_exit;
|
||||
}
|
||||
|
||||
ret = stmfx_irq_init(client);
|
||||
if (ret)
|
||||
goto err_chip_exit;
|
||||
|
||||
ret = devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
|
||||
stmfx_cells, ARRAY_SIZE(stmfx_cells), NULL,
|
||||
0, stmfx->irq_domain);
|
||||
if (ret)
|
||||
goto err_irq_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_irq_exit:
|
||||
stmfx_irq_exit(client);
|
||||
err_chip_exit:
|
||||
stmfx_chip_exit(client);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmfx_remove(struct i2c_client *client)
|
||||
{
|
||||
stmfx_irq_exit(client);
|
||||
|
||||
return stmfx_chip_exit(client);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int stmfx_suspend(struct device *dev)
|
||||
{
|
||||
struct stmfx *stmfx = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = regmap_raw_read(stmfx->map, STMFX_REG_SYS_CTRL,
|
||||
&stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_raw_read(stmfx->map, STMFX_REG_IRQ_OUT_PIN,
|
||||
&stmfx->bkp_irqoutpin,
|
||||
sizeof(stmfx->bkp_irqoutpin));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (stmfx->vdd)
|
||||
return regulator_disable(stmfx->vdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_resume(struct device *dev)
|
||||
{
|
||||
struct stmfx *stmfx = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (stmfx->vdd) {
|
||||
ret = regulator_enable(stmfx->vdd);
|
||||
if (ret) {
|
||||
dev_err(stmfx->dev,
|
||||
"VDD enable failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_raw_write(stmfx->map, STMFX_REG_SYS_CTRL,
|
||||
&stmfx->bkp_sysctrl, sizeof(stmfx->bkp_sysctrl));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_OUT_PIN,
|
||||
&stmfx->bkp_irqoutpin,
|
||||
sizeof(stmfx->bkp_irqoutpin));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_raw_write(stmfx->map, STMFX_REG_IRQ_SRC_EN,
|
||||
&stmfx->irq_src, sizeof(stmfx->irq_src));
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stmfx_dev_pm_ops, stmfx_suspend, stmfx_resume);
|
||||
|
||||
static const struct of_device_id stmfx_of_match[] = {
|
||||
{ .compatible = "st,stmfx-0300", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stmfx_of_match);
|
||||
|
||||
static struct i2c_driver stmfx_driver = {
|
||||
.driver = {
|
||||
.name = "stmfx-core",
|
||||
.of_match_table = of_match_ptr(stmfx_of_match),
|
||||
.pm = &stmfx_dev_pm_ops,
|
||||
},
|
||||
.probe = stmfx_probe,
|
||||
.remove = stmfx_remove,
|
||||
};
|
||||
module_i2c_driver(stmfx_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STMFX core driver");
|
||||
MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -148,13 +148,12 @@ static const struct of_device_id sun6i_prcm_dt_ids[] = {
|
||||
|
||||
static int sun6i_prcm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
const struct of_device_id *match;
|
||||
const struct prcm_data *data;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
match = of_match_node(sun6i_prcm_dt_ids, np);
|
||||
match = of_match_node(sun6i_prcm_dt_ids, pdev->dev.of_node);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwspinlock.h>
|
||||
#include <linux/io.h>
|
||||
@ -45,6 +46,7 @@ static const struct regmap_config syscon_regmap_config = {
|
||||
|
||||
static struct syscon *of_syscon_register(struct device_node *np)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct syscon *syscon;
|
||||
struct regmap *regmap;
|
||||
void __iomem *base;
|
||||
@ -119,6 +121,18 @@ static struct syscon *of_syscon_register(struct device_node *np)
|
||||
goto err_regmap;
|
||||
}
|
||||
|
||||
clk = of_clk_get(np, 0);
|
||||
if (IS_ERR(clk)) {
|
||||
ret = PTR_ERR(clk);
|
||||
/* clock is optional */
|
||||
if (ret != -ENOENT)
|
||||
goto err_clk;
|
||||
} else {
|
||||
ret = regmap_mmio_attach_clk(regmap, clk);
|
||||
if (ret)
|
||||
goto err_attach;
|
||||
}
|
||||
|
||||
syscon->regmap = regmap;
|
||||
syscon->np = np;
|
||||
|
||||
@ -128,6 +142,11 @@ static struct syscon *of_syscon_register(struct device_node *np)
|
||||
|
||||
return syscon;
|
||||
|
||||
err_attach:
|
||||
if (!IS_ERR(clk))
|
||||
clk_put(clk);
|
||||
err_clk:
|
||||
regmap_exit(regmap);
|
||||
err_regmap:
|
||||
iounmap(base);
|
||||
err_map:
|
||||
|
@ -82,8 +82,7 @@ struct t7l66xb {
|
||||
|
||||
static int t7l66xb_mmc_enable(struct platform_device *mmc)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
|
||||
struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
|
||||
unsigned long flags;
|
||||
u8 dev_ctl;
|
||||
int ret;
|
||||
@ -108,8 +107,7 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
|
||||
|
||||
static int t7l66xb_mmc_disable(struct platform_device *mmc)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
|
||||
struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
|
||||
unsigned long flags;
|
||||
u8 dev_ctl;
|
||||
|
||||
@ -128,16 +126,14 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
|
||||
|
||||
static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
|
||||
struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
|
||||
}
|
||||
|
||||
static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
|
||||
struct t7l66xb *t7l66xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
|
||||
}
|
||||
|
@ -80,16 +80,14 @@ static int tc6387xb_resume(struct platform_device *dev)
|
||||
|
||||
static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
|
||||
struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state);
|
||||
}
|
||||
|
||||
static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
|
||||
struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state);
|
||||
}
|
||||
@ -97,8 +95,7 @@ static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
|
||||
|
||||
static int tc6387xb_mmc_enable(struct platform_device *mmc)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
|
||||
struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
clk_prepare_enable(tc6387xb->clk32k);
|
||||
|
||||
@ -110,8 +107,7 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
|
||||
|
||||
static int tc6387xb_mmc_disable(struct platform_device *mmc)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
|
||||
struct tc6387xb *tc6387xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
clk_disable_unprepare(tc6387xb->clk32k);
|
||||
|
||||
|
@ -122,14 +122,13 @@ enum {
|
||||
|
||||
static int tc6393xb_nand_enable(struct platform_device *nand)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(nand->dev.parent);
|
||||
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(nand->dev.parent);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&tc6393xb->lock, flags);
|
||||
|
||||
/* SMD buffer on */
|
||||
dev_dbg(&dev->dev, "SMD buffer on\n");
|
||||
dev_dbg(nand->dev.parent, "SMD buffer on\n");
|
||||
tmio_iowrite8(0xff, tc6393xb->scr + SCR_GPI_BCR(1));
|
||||
|
||||
raw_spin_unlock_irqrestore(&tc6393xb->lock, flags);
|
||||
@ -312,8 +311,7 @@ static int tc6393xb_fb_disable(struct platform_device *dev)
|
||||
|
||||
int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(fb->dev.parent);
|
||||
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent);
|
||||
u8 fer;
|
||||
unsigned long flags;
|
||||
|
||||
@ -334,8 +332,7 @@ EXPORT_SYMBOL(tc6393xb_lcd_set_power);
|
||||
|
||||
int tc6393xb_lcd_mode(struct platform_device *fb,
|
||||
const struct fb_videomode *mode) {
|
||||
struct platform_device *dev = to_platform_device(fb->dev.parent);
|
||||
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(fb->dev.parent);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&tc6393xb->lock, flags);
|
||||
@ -351,8 +348,7 @@ EXPORT_SYMBOL(tc6393xb_lcd_mode);
|
||||
|
||||
static int tc6393xb_mmc_enable(struct platform_device *mmc)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0,
|
||||
tc6393xb_mmc_resources[0].start & 0xfffe);
|
||||
@ -362,8 +358,7 @@ static int tc6393xb_mmc_enable(struct platform_device *mmc)
|
||||
|
||||
static int tc6393xb_mmc_resume(struct platform_device *mmc)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0,
|
||||
tc6393xb_mmc_resources[0].start & 0xfffe);
|
||||
@ -373,16 +368,14 @@ static int tc6393xb_mmc_resume(struct platform_device *mmc)
|
||||
|
||||
static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state);
|
||||
}
|
||||
|
||||
static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state)
|
||||
{
|
||||
struct platform_device *dev = to_platform_device(mmc->dev.parent);
|
||||
struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
|
||||
struct tc6393xb *tc6393xb = dev_get_drvdata(mmc->dev.parent);
|
||||
|
||||
tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state);
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ static const struct of_device_id tps65912_spi_of_match_table[] = {
|
||||
{ .compatible = "ti,tps65912", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tps65912_spi_of_match_table);
|
||||
|
||||
static int tps65912_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
|
@ -322,8 +322,19 @@ int twl6040_power(struct twl6040 *twl6040, int on)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Register access can produce errors after power-up unless we
|
||||
* wait at least 8ms based on measurements on duovero.
|
||||
*/
|
||||
usleep_range(10000, 12000);
|
||||
|
||||
/* Sync with the HW */
|
||||
regcache_sync(twl6040->regmap);
|
||||
ret = regcache_sync(twl6040->regmap);
|
||||
if (ret) {
|
||||
dev_err(twl6040->dev, "Failed to sync with the HW: %i\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Default PLL configuration after power up */
|
||||
twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL;
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Adopted from dwmac-sti.c
|
||||
*/
|
||||
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/altera-sysmgr.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_net.h>
|
||||
@ -114,7 +114,8 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *
|
||||
|
||||
dwmac->interface = of_get_phy_mode(np);
|
||||
|
||||
sys_mgr_base_addr = syscon_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
|
||||
sys_mgr_base_addr =
|
||||
altr_sysmgr_regmap_lookup_by_phandle(np, "altr,sysmgr-syscon");
|
||||
if (IS_ERR(sys_mgr_base_addr)) {
|
||||
dev_info(dev, "No sysmgr-syscon node found\n");
|
||||
return PTR_ERR(sys_mgr_base_addr);
|
||||
|
@ -273,6 +273,20 @@ config PINCTRL_ST
|
||||
select PINCONF
|
||||
select GPIOLIB_IRQCHIP
|
||||
|
||||
config PINCTRL_STMFX
|
||||
tristate "STMicroelectronics STMFX GPIO expander pinctrl driver"
|
||||
depends on I2C
|
||||
depends on OF || COMPILE_TEST
|
||||
select GENERIC_PINCONF
|
||||
select GPIOLIB_IRQCHIP
|
||||
select MFD_STMFX
|
||||
help
|
||||
Driver for STMicroelectronics Multi-Function eXpander (STMFX)
|
||||
GPIO expander.
|
||||
This provides a GPIO interface supporting inputs and outputs,
|
||||
and configuring push-pull, open-drain, and can also be used as
|
||||
interrupt-controller.
|
||||
|
||||
config PINCTRL_U300
|
||||
bool "U300 pin controller driver"
|
||||
depends on ARCH_U300
|
||||
|
@ -41,6 +41,7 @@ obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
|
||||
obj-$(CONFIG_PINCTRL_LPC18XX) += pinctrl-lpc18xx.o
|
||||
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
|
||||
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
|
||||
obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o
|
||||
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
|
||||
obj-$(CONFIG_PINCTRL_INGENIC) += pinctrl-ingenic.o
|
||||
obj-$(CONFIG_PINCTRL_RK805) += pinctrl-rk805.o
|
||||
|
819
drivers/pinctrl/pinctrl-stmfx.c
Normal file
819
drivers/pinctrl/pinctrl-stmfx.c
Normal file
@ -0,0 +1,819 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for STMicroelectronics Multi-Function eXpander (STMFX) GPIO expander
|
||||
*
|
||||
* Copyright (C) 2019 STMicroelectronics
|
||||
* Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
|
||||
*/
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/stmfx.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pinctrl/pinconf.h>
|
||||
#include <linux/pinctrl/pinmux.h>
|
||||
|
||||
#include "core.h"
|
||||
#include "pinctrl-utils.h"
|
||||
|
||||
/* GPIOs expander */
|
||||
/* GPIO_STATE1 0x10, GPIO_STATE2 0x11, GPIO_STATE3 0x12 */
|
||||
#define STMFX_REG_GPIO_STATE STMFX_REG_GPIO_STATE1 /* R */
|
||||
/* GPIO_DIR1 0x60, GPIO_DIR2 0x61, GPIO_DIR3 0x63 */
|
||||
#define STMFX_REG_GPIO_DIR STMFX_REG_GPIO_DIR1 /* RW */
|
||||
/* GPIO_TYPE1 0x64, GPIO_TYPE2 0x65, GPIO_TYPE3 0x66 */
|
||||
#define STMFX_REG_GPIO_TYPE STMFX_REG_GPIO_TYPE1 /* RW */
|
||||
/* GPIO_PUPD1 0x68, GPIO_PUPD2 0x69, GPIO_PUPD3 0x6A */
|
||||
#define STMFX_REG_GPIO_PUPD STMFX_REG_GPIO_PUPD1 /* RW */
|
||||
/* GPO_SET1 0x6C, GPO_SET2 0x6D, GPO_SET3 0x6E */
|
||||
#define STMFX_REG_GPO_SET STMFX_REG_GPO_SET1 /* RW */
|
||||
/* GPO_CLR1 0x70, GPO_CLR2 0x71, GPO_CLR3 0x72 */
|
||||
#define STMFX_REG_GPO_CLR STMFX_REG_GPO_CLR1 /* RW */
|
||||
/* IRQ_GPI_SRC1 0x48, IRQ_GPI_SRC2 0x49, IRQ_GPI_SRC3 0x4A */
|
||||
#define STMFX_REG_IRQ_GPI_SRC STMFX_REG_IRQ_GPI_SRC1 /* RW */
|
||||
/* IRQ_GPI_EVT1 0x4C, IRQ_GPI_EVT2 0x4D, IRQ_GPI_EVT3 0x4E */
|
||||
#define STMFX_REG_IRQ_GPI_EVT STMFX_REG_IRQ_GPI_EVT1 /* RW */
|
||||
/* IRQ_GPI_TYPE1 0x50, IRQ_GPI_TYPE2 0x51, IRQ_GPI_TYPE3 0x52 */
|
||||
#define STMFX_REG_IRQ_GPI_TYPE STMFX_REG_IRQ_GPI_TYPE1 /* RW */
|
||||
/* IRQ_GPI_PENDING1 0x0C, IRQ_GPI_PENDING2 0x0D, IRQ_GPI_PENDING3 0x0E*/
|
||||
#define STMFX_REG_IRQ_GPI_PENDING STMFX_REG_IRQ_GPI_PENDING1 /* R */
|
||||
/* IRQ_GPI_ACK1 0x54, IRQ_GPI_ACK2 0x55, IRQ_GPI_ACK3 0x56 */
|
||||
#define STMFX_REG_IRQ_GPI_ACK STMFX_REG_IRQ_GPI_ACK1 /* RW */
|
||||
|
||||
#define NR_GPIO_REGS 3
|
||||
#define NR_GPIOS_PER_REG 8
|
||||
#define get_reg(offset) ((offset) / NR_GPIOS_PER_REG)
|
||||
#define get_shift(offset) ((offset) % NR_GPIOS_PER_REG)
|
||||
#define get_mask(offset) (BIT(get_shift(offset)))
|
||||
|
||||
/*
|
||||
* STMFX pinctrl can have up to 24 pins if STMFX other functions are not used.
|
||||
* Pins availability is managed thanks to gpio-ranges property.
|
||||
*/
|
||||
static const struct pinctrl_pin_desc stmfx_pins[] = {
|
||||
PINCTRL_PIN(0, "gpio0"),
|
||||
PINCTRL_PIN(1, "gpio1"),
|
||||
PINCTRL_PIN(2, "gpio2"),
|
||||
PINCTRL_PIN(3, "gpio3"),
|
||||
PINCTRL_PIN(4, "gpio4"),
|
||||
PINCTRL_PIN(5, "gpio5"),
|
||||
PINCTRL_PIN(6, "gpio6"),
|
||||
PINCTRL_PIN(7, "gpio7"),
|
||||
PINCTRL_PIN(8, "gpio8"),
|
||||
PINCTRL_PIN(9, "gpio9"),
|
||||
PINCTRL_PIN(10, "gpio10"),
|
||||
PINCTRL_PIN(11, "gpio11"),
|
||||
PINCTRL_PIN(12, "gpio12"),
|
||||
PINCTRL_PIN(13, "gpio13"),
|
||||
PINCTRL_PIN(14, "gpio14"),
|
||||
PINCTRL_PIN(15, "gpio15"),
|
||||
PINCTRL_PIN(16, "agpio0"),
|
||||
PINCTRL_PIN(17, "agpio1"),
|
||||
PINCTRL_PIN(18, "agpio2"),
|
||||
PINCTRL_PIN(19, "agpio3"),
|
||||
PINCTRL_PIN(20, "agpio4"),
|
||||
PINCTRL_PIN(21, "agpio5"),
|
||||
PINCTRL_PIN(22, "agpio6"),
|
||||
PINCTRL_PIN(23, "agpio7"),
|
||||
};
|
||||
|
||||
struct stmfx_pinctrl {
|
||||
struct device *dev;
|
||||
struct stmfx *stmfx;
|
||||
struct pinctrl_dev *pctl_dev;
|
||||
struct pinctrl_desc pctl_desc;
|
||||
struct gpio_chip gpio_chip;
|
||||
struct irq_chip irq_chip;
|
||||
struct mutex lock; /* IRQ bus lock */
|
||||
unsigned long gpio_valid_mask;
|
||||
/* Cache of IRQ_GPI_* registers for bus_lock */
|
||||
u8 irq_gpi_src[NR_GPIO_REGS];
|
||||
u8 irq_gpi_type[NR_GPIO_REGS];
|
||||
u8 irq_gpi_evt[NR_GPIO_REGS];
|
||||
u8 irq_toggle_edge[NR_GPIO_REGS];
|
||||
#ifdef CONFIG_PM
|
||||
/* Backup of GPIO_* registers for suspend/resume */
|
||||
u8 bkp_gpio_state[NR_GPIO_REGS];
|
||||
u8 bkp_gpio_dir[NR_GPIO_REGS];
|
||||
u8 bkp_gpio_type[NR_GPIO_REGS];
|
||||
u8 bkp_gpio_pupd[NR_GPIO_REGS];
|
||||
#endif
|
||||
};
|
||||
|
||||
static int stmfx_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
|
||||
u32 reg = STMFX_REG_GPIO_STATE + get_reg(offset);
|
||||
u32 mask = get_mask(offset);
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(pctl->stmfx->map, reg, &value);
|
||||
|
||||
return ret ? ret : !!(value & mask);
|
||||
}
|
||||
|
||||
static void stmfx_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
|
||||
u32 reg = value ? STMFX_REG_GPO_SET : STMFX_REG_GPO_CLR;
|
||||
u32 mask = get_mask(offset);
|
||||
|
||||
regmap_write_bits(pctl->stmfx->map, reg + get_reg(offset),
|
||||
mask, mask);
|
||||
}
|
||||
|
||||
static int stmfx_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
|
||||
u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
|
||||
u32 mask = get_mask(offset);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(pctl->stmfx->map, reg, &val);
|
||||
/*
|
||||
* On stmfx, gpio pins direction is (0)input, (1)output.
|
||||
* .get_direction returns 0=out, 1=in
|
||||
*/
|
||||
|
||||
return ret ? ret : !(val & mask);
|
||||
}
|
||||
|
||||
static int stmfx_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
|
||||
u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
|
||||
u32 mask = get_mask(offset);
|
||||
|
||||
return regmap_write_bits(pctl->stmfx->map, reg, mask, 0);
|
||||
}
|
||||
|
||||
static int stmfx_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gc);
|
||||
u32 reg = STMFX_REG_GPIO_DIR + get_reg(offset);
|
||||
u32 mask = get_mask(offset);
|
||||
|
||||
stmfx_gpio_set(gc, offset, value);
|
||||
|
||||
return regmap_write_bits(pctl->stmfx->map, reg, mask, mask);
|
||||
}
|
||||
|
||||
static int stmfx_pinconf_get_pupd(struct stmfx_pinctrl *pctl,
|
||||
unsigned int offset)
|
||||
{
|
||||
u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset);
|
||||
u32 pupd, mask = get_mask(offset);
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(pctl->stmfx->map, reg, &pupd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !!(pupd & mask);
|
||||
}
|
||||
|
||||
static int stmfx_pinconf_set_pupd(struct stmfx_pinctrl *pctl,
|
||||
unsigned int offset, u32 pupd)
|
||||
{
|
||||
u32 reg = STMFX_REG_GPIO_PUPD + get_reg(offset);
|
||||
u32 mask = get_mask(offset);
|
||||
|
||||
return regmap_write_bits(pctl->stmfx->map, reg, mask, pupd ? mask : 0);
|
||||
}
|
||||
|
||||
static int stmfx_pinconf_get_type(struct stmfx_pinctrl *pctl,
|
||||
unsigned int offset)
|
||||
{
|
||||
u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset);
|
||||
u32 type, mask = get_mask(offset);
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(pctl->stmfx->map, reg, &type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return !!(type & mask);
|
||||
}
|
||||
|
||||
static int stmfx_pinconf_set_type(struct stmfx_pinctrl *pctl,
|
||||
unsigned int offset, u32 type)
|
||||
{
|
||||
u32 reg = STMFX_REG_GPIO_TYPE + get_reg(offset);
|
||||
u32 mask = get_mask(offset);
|
||||
|
||||
return regmap_write_bits(pctl->stmfx->map, reg, mask, type ? mask : 0);
|
||||
}
|
||||
|
||||
static int stmfx_pinconf_get(struct pinctrl_dev *pctldev,
|
||||
unsigned int pin, unsigned long *config)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
||||
u32 param = pinconf_to_config_param(*config);
|
||||
struct pinctrl_gpio_range *range;
|
||||
u32 arg = 0;
|
||||
int ret, dir, type, pupd;
|
||||
|
||||
range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin);
|
||||
if (!range)
|
||||
return -EINVAL;
|
||||
|
||||
dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin);
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
type = stmfx_pinconf_get_type(pctl, pin);
|
||||
if (type < 0)
|
||||
return type;
|
||||
pupd = stmfx_pinconf_get_pupd(pctl, pin);
|
||||
if (pupd < 0)
|
||||
return pupd;
|
||||
|
||||
switch (param) {
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
if ((!dir && (!type || !pupd)) || (dir && !type))
|
||||
arg = 1;
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
if (dir && type && !pupd)
|
||||
arg = 1;
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
if (type && pupd)
|
||||
arg = 1;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
if ((!dir && type) || (dir && !type))
|
||||
arg = 1;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||
if ((!dir && !type) || (dir && type))
|
||||
arg = 1;
|
||||
break;
|
||||
case PIN_CONFIG_OUTPUT:
|
||||
if (dir)
|
||||
return -EINVAL;
|
||||
|
||||
ret = stmfx_gpio_get(&pctl->gpio_chip, pin);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
arg = ret;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
*config = pinconf_to_config_packed(param, arg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
|
||||
unsigned long *configs, unsigned int num_configs)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct pinctrl_gpio_range *range;
|
||||
enum pin_config_param param;
|
||||
u32 arg;
|
||||
int dir, i, ret;
|
||||
|
||||
range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, pin);
|
||||
if (!range) {
|
||||
dev_err(pctldev->dev, "pin %d is not available\n", pin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dir = stmfx_gpio_get_direction(&pctl->gpio_chip, pin);
|
||||
if (dir < 0)
|
||||
return dir;
|
||||
|
||||
for (i = 0; i < num_configs; i++) {
|
||||
param = pinconf_to_config_param(configs[i]);
|
||||
arg = pinconf_to_config_argument(configs[i]);
|
||||
|
||||
switch (param) {
|
||||
case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
|
||||
case PIN_CONFIG_BIAS_DISABLE:
|
||||
case PIN_CONFIG_BIAS_PULL_DOWN:
|
||||
ret = stmfx_pinconf_set_pupd(pctl, pin, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case PIN_CONFIG_BIAS_PULL_UP:
|
||||
ret = stmfx_pinconf_set_pupd(pctl, pin, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
|
||||
if (!dir)
|
||||
ret = stmfx_pinconf_set_type(pctl, pin, 1);
|
||||
else
|
||||
ret = stmfx_pinconf_set_type(pctl, pin, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case PIN_CONFIG_DRIVE_PUSH_PULL:
|
||||
if (!dir)
|
||||
ret = stmfx_pinconf_set_type(pctl, pin, 0);
|
||||
else
|
||||
ret = stmfx_pinconf_set_type(pctl, pin, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
case PIN_CONFIG_OUTPUT:
|
||||
ret = stmfx_gpio_direction_output(&pctl->gpio_chip,
|
||||
pin, arg);
|
||||
if (ret)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stmfx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
|
||||
struct seq_file *s, unsigned int offset)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
|
||||
struct pinctrl_gpio_range *range;
|
||||
int dir, type, pupd, val;
|
||||
|
||||
range = pinctrl_find_gpio_range_from_pin_nolock(pctldev, offset);
|
||||
if (!range)
|
||||
return;
|
||||
|
||||
dir = stmfx_gpio_get_direction(&pctl->gpio_chip, offset);
|
||||
if (dir < 0)
|
||||
return;
|
||||
type = stmfx_pinconf_get_type(pctl, offset);
|
||||
if (type < 0)
|
||||
return;
|
||||
pupd = stmfx_pinconf_get_pupd(pctl, offset);
|
||||
if (pupd < 0)
|
||||
return;
|
||||
val = stmfx_gpio_get(&pctl->gpio_chip, offset);
|
||||
if (val < 0)
|
||||
return;
|
||||
|
||||
if (!dir) {
|
||||
seq_printf(s, "output %s ", val ? "high" : "low");
|
||||
if (type)
|
||||
seq_printf(s, "open drain %s internal pull-up ",
|
||||
pupd ? "with" : "without");
|
||||
else
|
||||
seq_puts(s, "push pull no pull ");
|
||||
} else {
|
||||
seq_printf(s, "input %s ", val ? "high" : "low");
|
||||
if (type)
|
||||
seq_printf(s, "with internal pull-%s ",
|
||||
pupd ? "up" : "down");
|
||||
else
|
||||
seq_printf(s, "%s ", pupd ? "floating" : "analog");
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pinconf_ops stmfx_pinconf_ops = {
|
||||
.pin_config_get = stmfx_pinconf_get,
|
||||
.pin_config_set = stmfx_pinconf_set,
|
||||
.pin_config_dbg_show = stmfx_pinconf_dbg_show,
|
||||
};
|
||||
|
||||
static int stmfx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *stmfx_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
|
||||
unsigned int selector,
|
||||
const unsigned int **pins,
|
||||
unsigned int *num_pins)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static const struct pinctrl_ops stmfx_pinctrl_ops = {
|
||||
.get_groups_count = stmfx_pinctrl_get_groups_count,
|
||||
.get_group_name = stmfx_pinctrl_get_group_name,
|
||||
.get_group_pins = stmfx_pinctrl_get_group_pins,
|
||||
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
|
||||
.dt_free_map = pinctrl_utils_free_map,
|
||||
};
|
||||
|
||||
static void stmfx_pinctrl_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
|
||||
u32 reg = get_reg(data->hwirq);
|
||||
u32 mask = get_mask(data->hwirq);
|
||||
|
||||
pctl->irq_gpi_src[reg] &= ~mask;
|
||||
}
|
||||
|
||||
static void stmfx_pinctrl_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
|
||||
u32 reg = get_reg(data->hwirq);
|
||||
u32 mask = get_mask(data->hwirq);
|
||||
|
||||
pctl->irq_gpi_src[reg] |= mask;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
|
||||
u32 reg = get_reg(data->hwirq);
|
||||
u32 mask = get_mask(data->hwirq);
|
||||
|
||||
if (type == IRQ_TYPE_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
if (type & IRQ_TYPE_EDGE_BOTH) {
|
||||
pctl->irq_gpi_evt[reg] |= mask;
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
} else {
|
||||
pctl->irq_gpi_evt[reg] &= ~mask;
|
||||
irq_set_handler_locked(data, handle_level_irq);
|
||||
}
|
||||
|
||||
if ((type & IRQ_TYPE_EDGE_RISING) || (type & IRQ_TYPE_LEVEL_HIGH))
|
||||
pctl->irq_gpi_type[reg] |= mask;
|
||||
else
|
||||
pctl->irq_gpi_type[reg] &= ~mask;
|
||||
|
||||
/*
|
||||
* In case of (type & IRQ_TYPE_EDGE_BOTH), we need to know current
|
||||
* GPIO value to set the right edge trigger. But in atomic context
|
||||
* here we can't access registers over I2C. That's why (type &
|
||||
* IRQ_TYPE_EDGE_BOTH) will be managed in .irq_sync_unlock.
|
||||
*/
|
||||
|
||||
if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
|
||||
pctl->irq_toggle_edge[reg] |= mask;
|
||||
else
|
||||
pctl->irq_toggle_edge[reg] &= mask;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stmfx_pinctrl_irq_bus_lock(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
|
||||
|
||||
mutex_lock(&pctl->lock);
|
||||
}
|
||||
|
||||
static void stmfx_pinctrl_irq_bus_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gpio_chip = irq_data_get_irq_chip_data(data);
|
||||
struct stmfx_pinctrl *pctl = gpiochip_get_data(gpio_chip);
|
||||
u32 reg = get_reg(data->hwirq);
|
||||
u32 mask = get_mask(data->hwirq);
|
||||
|
||||
/*
|
||||
* In case of IRQ_TYPE_EDGE_BOTH), read the current GPIO value
|
||||
* (this couldn't be done in .irq_set_type because of atomic context)
|
||||
* to set the right irq trigger type.
|
||||
*/
|
||||
if (pctl->irq_toggle_edge[reg] & mask) {
|
||||
if (stmfx_gpio_get(gpio_chip, data->hwirq))
|
||||
pctl->irq_gpi_type[reg] &= ~mask;
|
||||
else
|
||||
pctl->irq_gpi_type[reg] |= mask;
|
||||
}
|
||||
|
||||
regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT,
|
||||
pctl->irq_gpi_evt, NR_GPIO_REGS);
|
||||
regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE,
|
||||
pctl->irq_gpi_type, NR_GPIO_REGS);
|
||||
regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
|
||||
pctl->irq_gpi_src, NR_GPIO_REGS);
|
||||
|
||||
mutex_unlock(&pctl->lock);
|
||||
}
|
||||
|
||||
static void stmfx_pinctrl_irq_toggle_trigger(struct stmfx_pinctrl *pctl,
|
||||
unsigned int offset)
|
||||
{
|
||||
u32 reg = get_reg(offset);
|
||||
u32 mask = get_mask(offset);
|
||||
int val;
|
||||
|
||||
if (!(pctl->irq_toggle_edge[reg] & mask))
|
||||
return;
|
||||
|
||||
val = stmfx_gpio_get(&pctl->gpio_chip, offset);
|
||||
if (val < 0)
|
||||
return;
|
||||
|
||||
if (val) {
|
||||
pctl->irq_gpi_type[reg] &= mask;
|
||||
regmap_write_bits(pctl->stmfx->map,
|
||||
STMFX_REG_IRQ_GPI_TYPE + reg,
|
||||
mask, 0);
|
||||
|
||||
} else {
|
||||
pctl->irq_gpi_type[reg] |= mask;
|
||||
regmap_write_bits(pctl->stmfx->map,
|
||||
STMFX_REG_IRQ_GPI_TYPE + reg,
|
||||
mask, mask);
|
||||
}
|
||||
}
|
||||
|
||||
static irqreturn_t stmfx_pinctrl_irq_thread_fn(int irq, void *dev_id)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = (struct stmfx_pinctrl *)dev_id;
|
||||
struct gpio_chip *gc = &pctl->gpio_chip;
|
||||
u8 pending[NR_GPIO_REGS];
|
||||
u8 src[NR_GPIO_REGS] = {0, 0, 0};
|
||||
unsigned long n, status;
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_IRQ_GPI_PENDING,
|
||||
&pending, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return IRQ_NONE;
|
||||
|
||||
regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
|
||||
src, NR_GPIO_REGS);
|
||||
|
||||
status = *(unsigned long *)pending;
|
||||
for_each_set_bit(n, &status, gc->ngpio) {
|
||||
handle_nested_irq(irq_find_mapping(gc->irq.domain, n));
|
||||
stmfx_pinctrl_irq_toggle_trigger(pctl, n);
|
||||
}
|
||||
|
||||
regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
|
||||
pctl->irq_gpi_src, NR_GPIO_REGS);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_gpio_function_enable(struct stmfx_pinctrl *pctl)
|
||||
{
|
||||
struct pinctrl_gpio_range *gpio_range;
|
||||
struct pinctrl_dev *pctl_dev = pctl->pctl_dev;
|
||||
u32 func = STMFX_FUNC_GPIO;
|
||||
|
||||
pctl->gpio_valid_mask = GENMASK(15, 0);
|
||||
|
||||
gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 16);
|
||||
if (gpio_range) {
|
||||
func |= STMFX_FUNC_ALTGPIO_LOW;
|
||||
pctl->gpio_valid_mask |= GENMASK(19, 16);
|
||||
}
|
||||
|
||||
gpio_range = pinctrl_find_gpio_range_from_pin(pctl_dev, 20);
|
||||
if (gpio_range) {
|
||||
func |= STMFX_FUNC_ALTGPIO_HIGH;
|
||||
pctl->gpio_valid_mask |= GENMASK(23, 20);
|
||||
}
|
||||
|
||||
return stmfx_function_enable(pctl->stmfx, func);
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stmfx *stmfx = dev_get_drvdata(pdev->dev.parent);
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct stmfx_pinctrl *pctl;
|
||||
u32 n;
|
||||
int irq, ret;
|
||||
|
||||
pctl = devm_kzalloc(stmfx->dev, sizeof(*pctl), GFP_KERNEL);
|
||||
if (!pctl)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, pctl);
|
||||
|
||||
pctl->dev = &pdev->dev;
|
||||
pctl->stmfx = stmfx;
|
||||
|
||||
if (!of_find_property(np, "gpio-ranges", NULL)) {
|
||||
dev_err(pctl->dev, "missing required gpio-ranges property\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq <= 0) {
|
||||
dev_err(pctl->dev, "failed to get irq\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
mutex_init(&pctl->lock);
|
||||
|
||||
/* Register pin controller */
|
||||
pctl->pctl_desc.name = "stmfx-pinctrl";
|
||||
pctl->pctl_desc.pctlops = &stmfx_pinctrl_ops;
|
||||
pctl->pctl_desc.confops = &stmfx_pinconf_ops;
|
||||
pctl->pctl_desc.pins = stmfx_pins;
|
||||
pctl->pctl_desc.npins = ARRAY_SIZE(stmfx_pins);
|
||||
pctl->pctl_desc.owner = THIS_MODULE;
|
||||
|
||||
ret = devm_pinctrl_register_and_init(pctl->dev, &pctl->pctl_desc,
|
||||
pctl, &pctl->pctl_dev);
|
||||
if (ret) {
|
||||
dev_err(pctl->dev, "pinctrl registration failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pinctrl_enable(pctl->pctl_dev);
|
||||
if (ret) {
|
||||
dev_err(pctl->dev, "pinctrl enable failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Register gpio controller */
|
||||
pctl->gpio_chip.label = "stmfx-gpio";
|
||||
pctl->gpio_chip.parent = pctl->dev;
|
||||
pctl->gpio_chip.get_direction = stmfx_gpio_get_direction;
|
||||
pctl->gpio_chip.direction_input = stmfx_gpio_direction_input;
|
||||
pctl->gpio_chip.direction_output = stmfx_gpio_direction_output;
|
||||
pctl->gpio_chip.get = stmfx_gpio_get;
|
||||
pctl->gpio_chip.set = stmfx_gpio_set;
|
||||
pctl->gpio_chip.set_config = gpiochip_generic_config;
|
||||
pctl->gpio_chip.base = -1;
|
||||
pctl->gpio_chip.ngpio = pctl->pctl_desc.npins;
|
||||
pctl->gpio_chip.can_sleep = true;
|
||||
pctl->gpio_chip.of_node = np;
|
||||
pctl->gpio_chip.need_valid_mask = true;
|
||||
|
||||
ret = devm_gpiochip_add_data(pctl->dev, &pctl->gpio_chip, pctl);
|
||||
if (ret) {
|
||||
dev_err(pctl->dev, "gpio_chip registration failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = stmfx_pinctrl_gpio_function_enable(pctl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pctl->irq_chip.name = dev_name(pctl->dev);
|
||||
pctl->irq_chip.irq_mask = stmfx_pinctrl_irq_mask;
|
||||
pctl->irq_chip.irq_unmask = stmfx_pinctrl_irq_unmask;
|
||||
pctl->irq_chip.irq_set_type = stmfx_pinctrl_irq_set_type;
|
||||
pctl->irq_chip.irq_bus_lock = stmfx_pinctrl_irq_bus_lock;
|
||||
pctl->irq_chip.irq_bus_sync_unlock = stmfx_pinctrl_irq_bus_sync_unlock;
|
||||
for_each_clear_bit(n, &pctl->gpio_valid_mask, pctl->gpio_chip.ngpio)
|
||||
clear_bit(n, pctl->gpio_chip.valid_mask);
|
||||
|
||||
ret = gpiochip_irqchip_add_nested(&pctl->gpio_chip, &pctl->irq_chip,
|
||||
0, handle_bad_irq, IRQ_TYPE_NONE);
|
||||
if (ret) {
|
||||
dev_err(pctl->dev, "cannot add irqchip to gpiochip\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(pctl->dev, irq, NULL,
|
||||
stmfx_pinctrl_irq_thread_fn,
|
||||
IRQF_ONESHOT,
|
||||
pctl->irq_chip.name, pctl);
|
||||
if (ret) {
|
||||
dev_err(pctl->dev, "cannot request irq%d\n", irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpiochip_set_nested_irqchip(&pctl->gpio_chip, &pctl->irq_chip, irq);
|
||||
|
||||
dev_info(pctl->dev,
|
||||
"%ld GPIOs available\n", hweight_long(pctl->gpio_valid_mask));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct stmfx *stmfx = dev_get_platdata(&pdev->dev);
|
||||
|
||||
return stmfx_function_disable(stmfx,
|
||||
STMFX_FUNC_GPIO |
|
||||
STMFX_FUNC_ALTGPIO_LOW |
|
||||
STMFX_FUNC_ALTGPIO_HIGH);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int stmfx_pinctrl_backup_regs(struct stmfx_pinctrl *pctl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_STATE,
|
||||
&pctl->bkp_gpio_state, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_DIR,
|
||||
&pctl->bkp_gpio_dir, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_TYPE,
|
||||
&pctl->bkp_gpio_type, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_read(pctl->stmfx->map, STMFX_REG_GPIO_PUPD,
|
||||
&pctl->bkp_gpio_pupd, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_restore_regs(struct stmfx_pinctrl *pctl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_DIR,
|
||||
pctl->bkp_gpio_dir, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_TYPE,
|
||||
pctl->bkp_gpio_type, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPIO_PUPD,
|
||||
pctl->bkp_gpio_pupd, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_GPO_SET,
|
||||
pctl->bkp_gpio_state, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_EVT,
|
||||
pctl->irq_gpi_evt, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_TYPE,
|
||||
pctl->irq_gpi_type, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = regmap_bulk_write(pctl->stmfx->map, STMFX_REG_IRQ_GPI_SRC,
|
||||
pctl->irq_gpi_src, NR_GPIO_REGS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_suspend(struct device *dev)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = stmfx_pinctrl_backup_regs(pctl);
|
||||
if (ret) {
|
||||
dev_err(pctl->dev, "registers backup failure\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfx_pinctrl_resume(struct device *dev)
|
||||
{
|
||||
struct stmfx_pinctrl *pctl = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = stmfx_pinctrl_restore_regs(pctl);
|
||||
if (ret) {
|
||||
dev_err(pctl->dev, "registers restoration failure\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(stmfx_pinctrl_dev_pm_ops,
|
||||
stmfx_pinctrl_suspend, stmfx_pinctrl_resume);
|
||||
|
||||
static const struct of_device_id stmfx_pinctrl_of_match[] = {
|
||||
{ .compatible = "st,stmfx-0300-pinctrl", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stmfx_pinctrl_of_match);
|
||||
|
||||
static struct platform_driver stmfx_pinctrl_driver = {
|
||||
.driver = {
|
||||
.name = "stmfx-pinctrl",
|
||||
.of_match_table = stmfx_pinctrl_of_match,
|
||||
.pm = &stmfx_pinctrl_dev_pm_ops,
|
||||
},
|
||||
.probe = stmfx_pinctrl_probe,
|
||||
.remove = stmfx_pinctrl_remove,
|
||||
};
|
||||
module_platform_driver(stmfx_pinctrl_driver);
|
||||
|
||||
MODULE_DESCRIPTION("STMFX pinctrl/GPIO driver");
|
||||
MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -429,6 +429,12 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
|
||||
else
|
||||
ec_dev->mkbp_event_supported = 1;
|
||||
|
||||
/* Probe if host sleep v1 is supported for S0ix failure detection. */
|
||||
ret = cros_ec_get_host_command_version_mask(ec_dev,
|
||||
EC_CMD_HOST_SLEEP_EVENT,
|
||||
&ver_mask);
|
||||
ec_dev->host_sleep_v1 = (ret >= 0 && (ver_mask & EC_VER_MASK(1)));
|
||||
|
||||
/*
|
||||
* Get host event wake mask, assume all events are wake events
|
||||
* if unavailable.
|
||||
|
@ -499,6 +499,13 @@ config CHARGER_DETECTOR_MAX14656
|
||||
Revision 1.2 and can be found e.g. in Kindle 4/5th generation
|
||||
readers and certain LG devices.
|
||||
|
||||
config CHARGER_MAX77650
|
||||
tristate "Maxim MAX77650 battery charger driver"
|
||||
depends on MFD_MAX77650
|
||||
help
|
||||
Say Y to enable support for the battery charger control of MAX77650
|
||||
PMICs.
|
||||
|
||||
config CHARGER_MAX77693
|
||||
tristate "Maxim MAX77693 battery charger driver"
|
||||
depends on MFD_MAX77693
|
||||
|
@ -70,6 +70,7 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
|
||||
obj-$(CONFIG_CHARGER_LTC3651) += ltc3651-charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
|
||||
obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o
|
||||
obj-$(CONFIG_CHARGER_MAX77650) += max77650-charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
|
||||
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
|
||||
|
368
drivers/power/supply/max77650-charger.c
Normal file
368
drivers/power/supply/max77650-charger.c
Normal file
@ -0,0 +1,368 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
//
|
||||
// Copyright (C) 2018 BayLibre SAS
|
||||
// Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
//
|
||||
// Battery charger driver for MAXIM 77650/77651 charger/power-supply.
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mfd/max77650.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define MAX77650_CHARGER_ENABLED BIT(0)
|
||||
#define MAX77650_CHARGER_DISABLED 0x00
|
||||
#define MAX77650_CHARGER_CHG_EN_MASK BIT(0)
|
||||
|
||||
#define MAX77650_CHG_DETAILS_MASK GENMASK(7, 4)
|
||||
#define MAX77650_CHG_DETAILS_BITS(_reg) \
|
||||
(((_reg) & MAX77650_CHG_DETAILS_MASK) >> 4)
|
||||
|
||||
/* Charger is OFF. */
|
||||
#define MAX77650_CHG_OFF 0x00
|
||||
/* Charger is in prequalification mode. */
|
||||
#define MAX77650_CHG_PREQ 0x01
|
||||
/* Charger is in fast-charge constant current mode. */
|
||||
#define MAX77650_CHG_ON_CURR 0x02
|
||||
/* Charger is in JEITA modified fast-charge constant-current mode. */
|
||||
#define MAX77650_CHG_ON_CURR_JEITA 0x03
|
||||
/* Charger is in fast-charge constant-voltage mode. */
|
||||
#define MAX77650_CHG_ON_VOLT 0x04
|
||||
/* Charger is in JEITA modified fast-charge constant-voltage mode. */
|
||||
#define MAX77650_CHG_ON_VOLT_JEITA 0x05
|
||||
/* Charger is in top-off mode. */
|
||||
#define MAX77650_CHG_ON_TOPOFF 0x06
|
||||
/* Charger is in JEITA modified top-off mode. */
|
||||
#define MAX77650_CHG_ON_TOPOFF_JEITA 0x07
|
||||
/* Charger is done. */
|
||||
#define MAX77650_CHG_DONE 0x08
|
||||
/* Charger is JEITA modified done. */
|
||||
#define MAX77650_CHG_DONE_JEITA 0x09
|
||||
/* Charger is suspended due to a prequalification timer fault. */
|
||||
#define MAX77650_CHG_SUSP_PREQ_TIM_FAULT 0x0a
|
||||
/* Charger is suspended due to a fast-charge timer fault. */
|
||||
#define MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT 0x0b
|
||||
/* Charger is suspended due to a battery temperature fault. */
|
||||
#define MAX77650_CHG_SUSP_BATT_TEMP_FAULT 0x0c
|
||||
|
||||
#define MAX77650_CHGIN_DETAILS_MASK GENMASK(3, 2)
|
||||
#define MAX77650_CHGIN_DETAILS_BITS(_reg) \
|
||||
(((_reg) & MAX77650_CHGIN_DETAILS_MASK) >> 2)
|
||||
|
||||
#define MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT 0x00
|
||||
#define MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT 0x01
|
||||
#define MAX77650_CHGIN_OKAY 0x11
|
||||
|
||||
#define MAX77650_CHARGER_CHG_MASK BIT(1)
|
||||
#define MAX77650_CHARGER_CHG_CHARGING(_reg) \
|
||||
(((_reg) & MAX77650_CHARGER_CHG_MASK) > 1)
|
||||
|
||||
#define MAX77650_CHARGER_VCHGIN_MIN_MASK 0xc0
|
||||
#define MAX77650_CHARGER_VCHGIN_MIN_SHIFT(_val) ((_val) << 5)
|
||||
|
||||
#define MAX77650_CHARGER_ICHGIN_LIM_MASK 0x1c
|
||||
#define MAX77650_CHARGER_ICHGIN_LIM_SHIFT(_val) ((_val) << 2)
|
||||
|
||||
struct max77650_charger_data {
|
||||
struct regmap *map;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static enum power_supply_property max77650_charger_properties[] = {
|
||||
POWER_SUPPLY_PROP_STATUS,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_CHARGE_TYPE
|
||||
};
|
||||
|
||||
static const unsigned int max77650_charger_vchgin_min_table[] = {
|
||||
4000000, 4100000, 4200000, 4300000, 4400000, 4500000, 4600000, 4700000
|
||||
};
|
||||
|
||||
static const unsigned int max77650_charger_ichgin_lim_table[] = {
|
||||
95000, 190000, 285000, 380000, 475000
|
||||
};
|
||||
|
||||
static int max77650_charger_set_vchgin_min(struct max77650_charger_data *chg,
|
||||
unsigned int val)
|
||||
{
|
||||
int i, rv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max77650_charger_vchgin_min_table); i++) {
|
||||
if (val == max77650_charger_vchgin_min_table[i]) {
|
||||
rv = regmap_update_bits(chg->map,
|
||||
MAX77650_REG_CNFG_CHG_B,
|
||||
MAX77650_CHARGER_VCHGIN_MIN_MASK,
|
||||
MAX77650_CHARGER_VCHGIN_MIN_SHIFT(i));
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int max77650_charger_set_ichgin_lim(struct max77650_charger_data *chg,
|
||||
unsigned int val)
|
||||
{
|
||||
int i, rv;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(max77650_charger_ichgin_lim_table); i++) {
|
||||
if (val == max77650_charger_ichgin_lim_table[i]) {
|
||||
rv = regmap_update_bits(chg->map,
|
||||
MAX77650_REG_CNFG_CHG_B,
|
||||
MAX77650_CHARGER_ICHGIN_LIM_MASK,
|
||||
MAX77650_CHARGER_ICHGIN_LIM_SHIFT(i));
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int max77650_charger_enable(struct max77650_charger_data *chg)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = regmap_update_bits(chg->map,
|
||||
MAX77650_REG_CNFG_CHG_B,
|
||||
MAX77650_CHARGER_CHG_EN_MASK,
|
||||
MAX77650_CHARGER_ENABLED);
|
||||
if (rv)
|
||||
dev_err(chg->dev, "unable to enable the charger: %d\n", rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int max77650_charger_disable(struct max77650_charger_data *chg)
|
||||
{
|
||||
int rv;
|
||||
|
||||
rv = regmap_update_bits(chg->map,
|
||||
MAX77650_REG_CNFG_CHG_B,
|
||||
MAX77650_CHARGER_CHG_EN_MASK,
|
||||
MAX77650_CHARGER_DISABLED);
|
||||
if (rv)
|
||||
dev_err(chg->dev, "unable to disable the charger: %d\n", rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static irqreturn_t max77650_charger_check_status(int irq, void *data)
|
||||
{
|
||||
struct max77650_charger_data *chg = data;
|
||||
int rv, reg;
|
||||
|
||||
rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
|
||||
if (rv) {
|
||||
dev_err(chg->dev,
|
||||
"unable to read the charger status: %d\n", rv);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
switch (MAX77650_CHGIN_DETAILS_BITS(reg)) {
|
||||
case MAX77650_CHGIN_UNDERVOLTAGE_LOCKOUT:
|
||||
dev_err(chg->dev, "undervoltage lockout detected, disabling charger\n");
|
||||
max77650_charger_disable(chg);
|
||||
break;
|
||||
case MAX77650_CHGIN_OVERVOLTAGE_LOCKOUT:
|
||||
dev_err(chg->dev, "overvoltage lockout detected, disabling charger\n");
|
||||
max77650_charger_disable(chg);
|
||||
break;
|
||||
case MAX77650_CHGIN_OKAY:
|
||||
max77650_charger_enable(chg);
|
||||
break;
|
||||
default:
|
||||
/* May be 0x10 - debouncing */
|
||||
break;
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int max77650_charger_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct max77650_charger_data *chg = power_supply_get_drvdata(psy);
|
||||
int rv, reg;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
if (MAX77650_CHARGER_CHG_CHARGING(reg)) {
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MAX77650_CHG_DETAILS_BITS(reg)) {
|
||||
case MAX77650_CHG_OFF:
|
||||
case MAX77650_CHG_SUSP_PREQ_TIM_FAULT:
|
||||
case MAX77650_CHG_SUSP_FAST_CHG_TIM_FAULT:
|
||||
case MAX77650_CHG_SUSP_BATT_TEMP_FAULT:
|
||||
val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
break;
|
||||
case MAX77650_CHG_PREQ:
|
||||
case MAX77650_CHG_ON_CURR:
|
||||
case MAX77650_CHG_ON_CURR_JEITA:
|
||||
case MAX77650_CHG_ON_VOLT:
|
||||
case MAX77650_CHG_ON_VOLT_JEITA:
|
||||
case MAX77650_CHG_ON_TOPOFF:
|
||||
case MAX77650_CHG_ON_TOPOFF_JEITA:
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
break;
|
||||
case MAX77650_CHG_DONE:
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
break;
|
||||
default:
|
||||
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
val->intval = MAX77650_CHARGER_CHG_CHARGING(reg);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
rv = regmap_read(chg->map, MAX77650_REG_STAT_CHG_B, ®);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
if (!MAX77650_CHARGER_CHG_CHARGING(reg)) {
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (MAX77650_CHG_DETAILS_BITS(reg)) {
|
||||
case MAX77650_CHG_PREQ:
|
||||
case MAX77650_CHG_ON_CURR:
|
||||
case MAX77650_CHG_ON_CURR_JEITA:
|
||||
case MAX77650_CHG_ON_VOLT:
|
||||
case MAX77650_CHG_ON_VOLT_JEITA:
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
|
||||
break;
|
||||
case MAX77650_CHG_ON_TOPOFF:
|
||||
case MAX77650_CHG_ON_TOPOFF_JEITA:
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
|
||||
break;
|
||||
default:
|
||||
val->intval = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct power_supply_desc max77650_battery_desc = {
|
||||
.name = "max77650",
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.get_property = max77650_charger_get_property,
|
||||
.properties = max77650_charger_properties,
|
||||
.num_properties = ARRAY_SIZE(max77650_charger_properties),
|
||||
};
|
||||
|
||||
static int max77650_charger_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct power_supply_config pscfg = {};
|
||||
struct max77650_charger_data *chg;
|
||||
struct power_supply *battery;
|
||||
struct device *dev, *parent;
|
||||
int rv, chg_irq, chgin_irq;
|
||||
unsigned int prop;
|
||||
|
||||
dev = &pdev->dev;
|
||||
parent = dev->parent;
|
||||
|
||||
chg = devm_kzalloc(dev, sizeof(*chg), GFP_KERNEL);
|
||||
if (!chg)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, chg);
|
||||
|
||||
chg->map = dev_get_regmap(parent, NULL);
|
||||
if (!chg->map)
|
||||
return -ENODEV;
|
||||
|
||||
chg->dev = dev;
|
||||
|
||||
pscfg.of_node = dev->of_node;
|
||||
pscfg.drv_data = chg;
|
||||
|
||||
chg_irq = platform_get_irq_byname(pdev, "CHG");
|
||||
if (chg_irq < 0)
|
||||
return chg_irq;
|
||||
|
||||
chgin_irq = platform_get_irq_byname(pdev, "CHGIN");
|
||||
if (chgin_irq < 0)
|
||||
return chgin_irq;
|
||||
|
||||
rv = devm_request_any_context_irq(dev, chg_irq,
|
||||
max77650_charger_check_status,
|
||||
IRQF_ONESHOT, "chg", chg);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
rv = devm_request_any_context_irq(dev, chgin_irq,
|
||||
max77650_charger_check_status,
|
||||
IRQF_ONESHOT, "chgin", chg);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
battery = devm_power_supply_register(dev,
|
||||
&max77650_battery_desc, &pscfg);
|
||||
if (IS_ERR(battery))
|
||||
return PTR_ERR(battery);
|
||||
|
||||
rv = of_property_read_u32(dev->of_node,
|
||||
"input-voltage-min-microvolt", &prop);
|
||||
if (rv == 0) {
|
||||
rv = max77650_charger_set_vchgin_min(chg, prop);
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = of_property_read_u32(dev->of_node,
|
||||
"input-current-limit-microamp", &prop);
|
||||
if (rv == 0) {
|
||||
rv = max77650_charger_set_ichgin_lim(chg, prop);
|
||||
if (rv)
|
||||
return rv;
|
||||
}
|
||||
|
||||
return max77650_charger_enable(chg);
|
||||
}
|
||||
|
||||
static int max77650_charger_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct max77650_charger_data *chg = platform_get_drvdata(pdev);
|
||||
|
||||
return max77650_charger_disable(chg);
|
||||
}
|
||||
|
||||
static struct platform_driver max77650_charger_driver = {
|
||||
.driver = {
|
||||
.name = "max77650-charger",
|
||||
},
|
||||
.probe = max77650_charger_probe,
|
||||
.remove = max77650_charger_remove,
|
||||
};
|
||||
module_platform_driver(max77650_charger_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAXIM 77650/77651 charger driver");
|
||||
MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
29
include/linux/mfd/altera-sysmgr.h
Normal file
29
include/linux/mfd/altera-sysmgr.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2018-2019 Intel Corporation
|
||||
* Copyright (C) 2012 Freescale Semiconductor, Inc.
|
||||
* Copyright (C) 2012 Linaro Ltd.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_ALTERA_SYSMGR_H__
|
||||
#define __LINUX_MFD_ALTERA_SYSMGR_H__
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/firmware/intel/stratix10-smc.h>
|
||||
|
||||
struct device_node;
|
||||
|
||||
#ifdef CONFIG_MFD_ALTERA_SYSMGR
|
||||
struct regmap *altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
|
||||
const char *property);
|
||||
#else
|
||||
static inline struct regmap *
|
||||
altr_sysmgr_regmap_lookup_by_phandle(struct device_node *np,
|
||||
const char *property)
|
||||
{
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __LINUX_MFD_ALTERA_SYSMGR_H__ */
|
@ -23,7 +23,10 @@
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#define CROS_EC_DEV_NAME "cros_ec"
|
||||
#define CROS_EC_DEV_FP_NAME "cros_fp"
|
||||
#define CROS_EC_DEV_PD_NAME "cros_pd"
|
||||
#define CROS_EC_DEV_TP_NAME "cros_tp"
|
||||
#define CROS_EC_DEV_ISH_NAME "cros_ish"
|
||||
|
||||
/*
|
||||
* The EC is unresponsive for a time after a reboot command. Add a
|
||||
@ -120,6 +123,7 @@ struct cros_ec_command {
|
||||
* @pkt_xfer: Send packet to EC and get response.
|
||||
* @lock: One transaction at a time.
|
||||
* @mkbp_event_supported: True if this EC supports the MKBP event protocol.
|
||||
* @host_sleep_v1: True if this EC supports the sleep v1 command.
|
||||
* @event_notifier: Interrupt event notifier for transport devices.
|
||||
* @event_data: Raw payload transferred with the MKBP event.
|
||||
* @event_size: Size in bytes of the event data.
|
||||
@ -153,6 +157,7 @@ struct cros_ec_device {
|
||||
struct cros_ec_command *msg);
|
||||
struct mutex lock;
|
||||
bool mkbp_event_supported;
|
||||
bool host_sleep_v1;
|
||||
struct blocking_notifier_head event_notifier;
|
||||
|
||||
struct ec_response_get_next_event_v1 event_data;
|
||||
|
@ -840,7 +840,7 @@ enum ec_feature_code {
|
||||
* (Common Smart Battery System Interface Specification)
|
||||
*/
|
||||
EC_FEATURE_SMART_BATTERY = 18,
|
||||
/* EC can dectect when the host hangs. */
|
||||
/* EC can detect when the host hangs. */
|
||||
EC_FEATURE_HANG_DETECT = 19,
|
||||
/* Report power information, for pit only */
|
||||
EC_FEATURE_PMU = 20,
|
||||
@ -852,10 +852,42 @@ enum ec_feature_code {
|
||||
EC_FEATURE_USB_MUX = 23,
|
||||
/* Motion Sensor code has an internal software FIFO */
|
||||
EC_FEATURE_MOTION_SENSE_FIFO = 24,
|
||||
/* Support temporary secure vstore */
|
||||
EC_FEATURE_VSTORE = 25,
|
||||
/* EC decides on USB-C SS mux state, muxes configured by host */
|
||||
EC_FEATURE_USBC_SS_MUX_VIRTUAL = 26,
|
||||
/* EC has RTC feature that can be controlled by host commands */
|
||||
EC_FEATURE_RTC = 27,
|
||||
/* The MCU exposes a Fingerprint sensor */
|
||||
EC_FEATURE_FINGERPRINT = 28,
|
||||
/* The MCU exposes a Touchpad */
|
||||
EC_FEATURE_TOUCHPAD = 29,
|
||||
/* The MCU has RWSIG task enabled */
|
||||
EC_FEATURE_RWSIG = 30,
|
||||
/* EC has device events support */
|
||||
EC_FEATURE_DEVICE_EVENT = 31,
|
||||
/* EC supports the unified wake masks for LPC/eSPI systems */
|
||||
EC_FEATURE_UNIFIED_WAKE_MASKS = 32,
|
||||
/* EC supports 64-bit host events */
|
||||
EC_FEATURE_HOST_EVENT64 = 33,
|
||||
/* EC runs code in RAM (not in place, a.k.a. XIP) */
|
||||
EC_FEATURE_EXEC_IN_RAM = 34,
|
||||
/* EC supports CEC commands */
|
||||
EC_FEATURE_CEC = 35,
|
||||
/* EC supports tight sensor timestamping. */
|
||||
EC_FEATURE_MOTION_SENSE_TIGHT_TIMESTAMPS = 36,
|
||||
/*
|
||||
* EC supports tablet mode detection aligned to Chrome and allows
|
||||
* setting of threshold by host command using
|
||||
* MOTIONSENSE_CMD_TABLET_MODE_LID_ANGLE.
|
||||
*/
|
||||
EC_FEATURE_REFINED_TABLET_MODE_HYSTERESIS = 37,
|
||||
/* EC supports audio codec. */
|
||||
EC_FEATURE_AUDIO_CODEC = 38,
|
||||
/* EC Supports SCP. */
|
||||
EC_FEATURE_SCP = 39,
|
||||
/* The MCU is an Integrated Sensor Hub */
|
||||
EC_FEATURE_ISH = 40,
|
||||
};
|
||||
|
||||
#define EC_FEATURE_MASK_0(event_code) (1UL << (event_code % 32))
|
||||
@ -2729,6 +2761,63 @@ struct ec_params_host_sleep_event {
|
||||
uint8_t sleep_event;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Use a default timeout value (CONFIG_SLEEP_TIMEOUT_MS) for detecting sleep
|
||||
* transition failures
|
||||
*/
|
||||
#define EC_HOST_SLEEP_TIMEOUT_DEFAULT 0
|
||||
|
||||
/* Disable timeout detection for this sleep transition */
|
||||
#define EC_HOST_SLEEP_TIMEOUT_INFINITE 0xFFFF
|
||||
|
||||
struct ec_params_host_sleep_event_v1 {
|
||||
/* The type of sleep being entered or exited. */
|
||||
uint8_t sleep_event;
|
||||
|
||||
/* Padding */
|
||||
uint8_t reserved;
|
||||
union {
|
||||
/* Parameters that apply for suspend messages. */
|
||||
struct {
|
||||
/*
|
||||
* The timeout in milliseconds between when this message
|
||||
* is received and when the EC will declare sleep
|
||||
* transition failure if the sleep signal is not
|
||||
* asserted.
|
||||
*/
|
||||
uint16_t sleep_timeout_ms;
|
||||
} suspend_params;
|
||||
|
||||
/* No parameters for non-suspend messages. */
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* A timeout occurred when this bit is set */
|
||||
#define EC_HOST_RESUME_SLEEP_TIMEOUT 0x80000000
|
||||
|
||||
/*
|
||||
* The mask defining which bits correspond to the number of sleep transitions,
|
||||
* as well as the maximum number of suspend line transitions that will be
|
||||
* reported back to the host.
|
||||
*/
|
||||
#define EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK 0x7FFFFFFF
|
||||
|
||||
struct ec_response_host_sleep_event_v1 {
|
||||
union {
|
||||
/* Response fields that apply for resume messages. */
|
||||
struct {
|
||||
/*
|
||||
* The number of sleep power signal transitions that
|
||||
* occurred since the suspend message. The high bit
|
||||
* indicates a timeout occurred.
|
||||
*/
|
||||
uint32_t sleep_transitions;
|
||||
} resume_response;
|
||||
|
||||
/* No response fields for non-resume messages. */
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Smart battery pass-through */
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Definitions for DA9063 MFD driver
|
||||
*
|
||||
@ -5,12 +6,6 @@
|
||||
*
|
||||
* Author: Michal Hajduk, Dialog Semiconductor
|
||||
* Author: Krystian Garbaciak, Dialog Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __MFD_DA9063_CORE_H__
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Registers definition for DA9063 modules
|
||||
*
|
||||
@ -5,12 +6,6 @@
|
||||
*
|
||||
* Author: Michal Hajduk, Dialog Semiconductor
|
||||
* Author: Krystian Garbaciak, Dialog Semiconductor
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _DA9063_REG_H
|
||||
@ -215,9 +210,9 @@
|
||||
|
||||
/* DA9063 Configuration registers */
|
||||
/* OTP */
|
||||
#define DA9063_REG_OPT_COUNT 0x101
|
||||
#define DA9063_REG_OPT_ADDR 0x102
|
||||
#define DA9063_REG_OPT_DATA 0x103
|
||||
#define DA9063_REG_OTP_CONT 0x101
|
||||
#define DA9063_REG_OTP_ADDR 0x102
|
||||
#define DA9063_REG_OTP_DATA 0x103
|
||||
|
||||
/* Customer Trim and Configuration */
|
||||
#define DA9063_REG_T_OFFSET 0x104
|
||||
|
@ -136,8 +136,8 @@
|
||||
#define MAX77620_FPS_PERIOD_MIN_US 40
|
||||
#define MAX20024_FPS_PERIOD_MIN_US 20
|
||||
|
||||
#define MAX77620_FPS_PERIOD_MAX_US 2560
|
||||
#define MAX20024_FPS_PERIOD_MAX_US 5120
|
||||
#define MAX20024_FPS_PERIOD_MAX_US 2560
|
||||
#define MAX77620_FPS_PERIOD_MAX_US 5120
|
||||
|
||||
#define MAX77620_REG_FPS_GPIO1 0x54
|
||||
#define MAX77620_REG_FPS_GPIO2 0x55
|
||||
@ -324,6 +324,7 @@ enum max77620_fps_src {
|
||||
enum max77620_chip_id {
|
||||
MAX77620,
|
||||
MAX20024,
|
||||
MAX77663,
|
||||
};
|
||||
|
||||
struct max77620_chip {
|
||||
|
59
include/linux/mfd/max77650.h
Normal file
59
include/linux/mfd/max77650.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2018 BayLibre SAS
|
||||
* Author: Bartosz Golaszewski <bgolaszewski@baylibre.com>
|
||||
*
|
||||
* Common definitions for MAXIM 77650/77651 charger/power-supply.
|
||||
*/
|
||||
|
||||
#ifndef MAX77650_H
|
||||
#define MAX77650_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
#define MAX77650_REG_INT_GLBL 0x00
|
||||
#define MAX77650_REG_INT_CHG 0x01
|
||||
#define MAX77650_REG_STAT_CHG_A 0x02
|
||||
#define MAX77650_REG_STAT_CHG_B 0x03
|
||||
#define MAX77650_REG_ERCFLAG 0x04
|
||||
#define MAX77650_REG_STAT_GLBL 0x05
|
||||
#define MAX77650_REG_INTM_GLBL 0x06
|
||||
#define MAX77650_REG_INTM_CHG 0x07
|
||||
#define MAX77650_REG_CNFG_GLBL 0x10
|
||||
#define MAX77650_REG_CID 0x11
|
||||
#define MAX77650_REG_CNFG_GPIO 0x12
|
||||
#define MAX77650_REG_CNFG_CHG_A 0x18
|
||||
#define MAX77650_REG_CNFG_CHG_B 0x19
|
||||
#define MAX77650_REG_CNFG_CHG_C 0x1a
|
||||
#define MAX77650_REG_CNFG_CHG_D 0x1b
|
||||
#define MAX77650_REG_CNFG_CHG_E 0x1c
|
||||
#define MAX77650_REG_CNFG_CHG_F 0x1d
|
||||
#define MAX77650_REG_CNFG_CHG_G 0x1e
|
||||
#define MAX77650_REG_CNFG_CHG_H 0x1f
|
||||
#define MAX77650_REG_CNFG_CHG_I 0x20
|
||||
#define MAX77650_REG_CNFG_SBB_TOP 0x28
|
||||
#define MAX77650_REG_CNFG_SBB0_A 0x29
|
||||
#define MAX77650_REG_CNFG_SBB0_B 0x2a
|
||||
#define MAX77650_REG_CNFG_SBB1_A 0x2b
|
||||
#define MAX77650_REG_CNFG_SBB1_B 0x2c
|
||||
#define MAX77650_REG_CNFG_SBB2_A 0x2d
|
||||
#define MAX77650_REG_CNFG_SBB2_B 0x2e
|
||||
#define MAX77650_REG_CNFG_LDO_A 0x38
|
||||
#define MAX77650_REG_CNFG_LDO_B 0x39
|
||||
#define MAX77650_REG_CNFG_LED0_A 0x40
|
||||
#define MAX77650_REG_CNFG_LED1_A 0x41
|
||||
#define MAX77650_REG_CNFG_LED2_A 0x42
|
||||
#define MAX77650_REG_CNFG_LED0_B 0x43
|
||||
#define MAX77650_REG_CNFG_LED1_B 0x44
|
||||
#define MAX77650_REG_CNFG_LED2_B 0x45
|
||||
#define MAX77650_REG_CNFG_LED_TOP 0x46
|
||||
|
||||
#define MAX77650_CID_MASK GENMASK(3, 0)
|
||||
#define MAX77650_CID_BITS(_reg) (_reg & MAX77650_CID_MASK)
|
||||
|
||||
#define MAX77650_CID_77650A 0x03
|
||||
#define MAX77650_CID_77650C 0x0a
|
||||
#define MAX77650_CID_77651A 0x06
|
||||
#define MAX77650_CID_77651B 0x08
|
||||
|
||||
#endif /* MAX77650_H */
|
123
include/linux/mfd/stmfx.h
Normal file
123
include/linux/mfd/stmfx.h
Normal file
@ -0,0 +1,123 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2019 STMicroelectronics
|
||||
* Author(s): Amelie Delaunay <amelie.delaunay@st.com>.
|
||||
*/
|
||||
|
||||
#ifndef MFD_STMFX_H
|
||||
#define MFX_STMFX_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* General */
|
||||
#define STMFX_REG_CHIP_ID 0x00 /* R */
|
||||
#define STMFX_REG_FW_VERSION_MSB 0x01 /* R */
|
||||
#define STMFX_REG_FW_VERSION_LSB 0x02 /* R */
|
||||
#define STMFX_REG_SYS_CTRL 0x40 /* RW */
|
||||
/* IRQ output management */
|
||||
#define STMFX_REG_IRQ_OUT_PIN 0x41 /* RW */
|
||||
#define STMFX_REG_IRQ_SRC_EN 0x42 /* RW */
|
||||
#define STMFX_REG_IRQ_PENDING 0x08 /* R */
|
||||
#define STMFX_REG_IRQ_ACK 0x44 /* RW */
|
||||
/* GPIO management */
|
||||
#define STMFX_REG_IRQ_GPI_PENDING1 0x0C /* R */
|
||||
#define STMFX_REG_IRQ_GPI_PENDING2 0x0D /* R */
|
||||
#define STMFX_REG_IRQ_GPI_PENDING3 0x0E /* R */
|
||||
#define STMFX_REG_GPIO_STATE1 0x10 /* R */
|
||||
#define STMFX_REG_GPIO_STATE2 0x11 /* R */
|
||||
#define STMFX_REG_GPIO_STATE3 0x12 /* R */
|
||||
#define STMFX_REG_IRQ_GPI_SRC1 0x48 /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_SRC2 0x49 /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_SRC3 0x4A /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_EVT1 0x4C /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_EVT2 0x4D /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_EVT3 0x4E /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_TYPE1 0x50 /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_TYPE2 0x51 /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_TYPE3 0x52 /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_ACK1 0x54 /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_ACK2 0x55 /* RW */
|
||||
#define STMFX_REG_IRQ_GPI_ACK3 0x56 /* RW */
|
||||
#define STMFX_REG_GPIO_DIR1 0x60 /* RW */
|
||||
#define STMFX_REG_GPIO_DIR2 0x61 /* RW */
|
||||
#define STMFX_REG_GPIO_DIR3 0x62 /* RW */
|
||||
#define STMFX_REG_GPIO_TYPE1 0x64 /* RW */
|
||||
#define STMFX_REG_GPIO_TYPE2 0x65 /* RW */
|
||||
#define STMFX_REG_GPIO_TYPE3 0x66 /* RW */
|
||||
#define STMFX_REG_GPIO_PUPD1 0x68 /* RW */
|
||||
#define STMFX_REG_GPIO_PUPD2 0x69 /* RW */
|
||||
#define STMFX_REG_GPIO_PUPD3 0x6A /* RW */
|
||||
#define STMFX_REG_GPO_SET1 0x6C /* RW */
|
||||
#define STMFX_REG_GPO_SET2 0x6D /* RW */
|
||||
#define STMFX_REG_GPO_SET3 0x6E /* RW */
|
||||
#define STMFX_REG_GPO_CLR1 0x70 /* RW */
|
||||
#define STMFX_REG_GPO_CLR2 0x71 /* RW */
|
||||
#define STMFX_REG_GPO_CLR3 0x72 /* RW */
|
||||
|
||||
#define STMFX_REG_MAX 0xB0
|
||||
|
||||
/* MFX boot time is around 10ms, so after reset, we have to wait this delay */
|
||||
#define STMFX_BOOT_TIME_MS 10
|
||||
|
||||
/* STMFX_REG_CHIP_ID bitfields */
|
||||
#define STMFX_REG_CHIP_ID_MASK GENMASK(7, 0)
|
||||
|
||||
/* STMFX_REG_SYS_CTRL bitfields */
|
||||
#define STMFX_REG_SYS_CTRL_GPIO_EN BIT(0)
|
||||
#define STMFX_REG_SYS_CTRL_TS_EN BIT(1)
|
||||
#define STMFX_REG_SYS_CTRL_IDD_EN BIT(2)
|
||||
#define STMFX_REG_SYS_CTRL_ALTGPIO_EN BIT(3)
|
||||
#define STMFX_REG_SYS_CTRL_SWRST BIT(7)
|
||||
|
||||
/* STMFX_REG_IRQ_OUT_PIN bitfields */
|
||||
#define STMFX_REG_IRQ_OUT_PIN_TYPE BIT(0) /* 0-OD 1-PP */
|
||||
#define STMFX_REG_IRQ_OUT_PIN_POL BIT(1) /* 0-active LOW 1-active HIGH */
|
||||
|
||||
/* STMFX_REG_IRQ_(SRC_EN/PENDING/ACK) bit shift */
|
||||
enum stmfx_irqs {
|
||||
STMFX_REG_IRQ_SRC_EN_GPIO = 0,
|
||||
STMFX_REG_IRQ_SRC_EN_IDD,
|
||||
STMFX_REG_IRQ_SRC_EN_ERROR,
|
||||
STMFX_REG_IRQ_SRC_EN_TS_DET,
|
||||
STMFX_REG_IRQ_SRC_EN_TS_NE,
|
||||
STMFX_REG_IRQ_SRC_EN_TS_TH,
|
||||
STMFX_REG_IRQ_SRC_EN_TS_FULL,
|
||||
STMFX_REG_IRQ_SRC_EN_TS_OVF,
|
||||
STMFX_REG_IRQ_SRC_MAX,
|
||||
};
|
||||
|
||||
enum stmfx_functions {
|
||||
STMFX_FUNC_GPIO = BIT(0), /* GPIO[15:0] */
|
||||
STMFX_FUNC_ALTGPIO_LOW = BIT(1), /* aGPIO[3:0] */
|
||||
STMFX_FUNC_ALTGPIO_HIGH = BIT(2), /* aGPIO[7:4] */
|
||||
STMFX_FUNC_TS = BIT(3),
|
||||
STMFX_FUNC_IDD = BIT(4),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct stmfx_ddata - STMFX MFD structure
|
||||
* @device: device reference used for logs
|
||||
* @map: register map
|
||||
* @vdd: STMFX power supply
|
||||
* @irq_domain: IRQ domain
|
||||
* @lock: IRQ bus lock
|
||||
* @irq_src: cache of IRQ_SRC_EN register for bus_lock
|
||||
* @bkp_sysctrl: backup of SYS_CTRL register for suspend/resume
|
||||
* @bkp_irqoutpin: backup of IRQ_OUT_PIN register for suspend/resume
|
||||
*/
|
||||
struct stmfx {
|
||||
struct device *dev;
|
||||
struct regmap *map;
|
||||
struct regulator *vdd;
|
||||
struct irq_domain *irq_domain;
|
||||
struct mutex lock; /* IRQ bus lock */
|
||||
u8 irq_src;
|
||||
#ifdef CONFIG_PM
|
||||
u8 bkp_sysctrl;
|
||||
u8 bkp_irqoutpin;
|
||||
#endif
|
||||
};
|
||||
|
||||
int stmfx_function_enable(struct stmfx *stmfx, u32 func);
|
||||
int stmfx_function_disable(struct stmfx *stmfx, u32 func);
|
||||
#endif
|
@ -1,12 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2014 Atmel Corporation.
|
||||
*
|
||||
* Memory Controllers (MATRIX, EBI) - System peripherals registers.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_MFD_SYSCON_ATMEL_MATRIX_H
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2005 Ivan Kokshaysky
|
||||
* Copyright (C) SAN People
|
||||
@ -5,11 +6,6 @@
|
||||
* Memory Controllers (MC, EBI, SMC, SDRAMC, BFC) - System peripherals
|
||||
* registers.
|
||||
* Based on AT91RM9200 datasheet revision E.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_MFD_SYSCON_ATMEL_MC_H_
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Atmel SMC (Static Memory Controller) register offsets and bit definitions.
|
||||
*
|
||||
@ -5,10 +6,6 @@
|
||||
* Copyright (C) 2014 Free Electrons
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_MFD_SYSCON_ATMEL_SMC_H_
|
||||
|
@ -1,14 +1,10 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (C) 2005 Ivan Kokshaysky
|
||||
* Copyright (C) SAN People
|
||||
*
|
||||
* System Timer (ST) - System peripherals registers.
|
||||
* Based on AT91RM9200 datasheet revision E.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_MFD_SYSCON_ATMEL_ST_H
|
||||
|
@ -410,6 +410,15 @@
|
||||
#define IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK (0x3 << 17)
|
||||
#define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_EXT (0x3 << 13)
|
||||
|
||||
#define IMX6SX_GPR2_MQS_OVERSAMPLE_MASK (0x1 << 26)
|
||||
#define IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT (26)
|
||||
#define IMX6SX_GPR2_MQS_EN_MASK (0x1 << 25)
|
||||
#define IMX6SX_GPR2_MQS_EN_SHIFT (25)
|
||||
#define IMX6SX_GPR2_MQS_SW_RST_MASK (0x1 << 24)
|
||||
#define IMX6SX_GPR2_MQS_SW_RST_SHIFT (24)
|
||||
#define IMX6SX_GPR2_MQS_CLK_DIV_MASK (0xFF << 16)
|
||||
#define IMX6SX_GPR2_MQS_CLK_DIV_SHIFT (16)
|
||||
|
||||
#define IMX6SX_GPR4_FEC_ENET1_STOP_REQ (0x1 << 3)
|
||||
#define IMX6SX_GPR4_FEC_ENET2_STOP_REQ (0x1 << 4)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user