- Core Frameworks
- Add the MFD bindings doc to MAINTAINERS - New Drivers - X-Powers AC100 Audio CODEC and RTC - TI LP873x PMIC - Rockchip RK808 PMIC - Samsung Exynos Low Power Audio - New Device Support - Add support for STMPE1600 variant to stmpe - Add support for PM8018 PMIC to pm8921-core - Add support for AXP806 PMIC in axp20x - Add support for AXP209 GPIO in axp20x - New Functionality - Add support for Reset to all STMPE variants - Add support for MKBP event support to cros_ec - Add support for USB to intel_soc_pmic_bxtwc - Add support for IRQs and Power Button to tps65217 - Fix-ups - Clean-up defunct author emails; da9063, max14577 - Kconfig fixups; wm8350-i2c, as3722 - Constify; altera-a10sr, sm501 - Supply PCI IDs; intel-lpss-pci - Improve clocking; qcom_rpm - Fix IRQ probing; ucb1x00-core - Ensure fault log is cleared; da9052 - Remove NO_IRQ check; ucb1x00-core - Supply I2C properties; intel-lpss-acpi, intel-lpss-pci - Non standard declaration; tps65217, max8997-irq - Remove unused code; lp873x, db8500-prcmu, ab8500-debugfs, cros_ec_spi - Make non-modular; altera-a10sr, intel_msic, smsc-ece1099, sun6i-prcm, twl-core, - OF bindings; ac100, stmpe, qcom-pm8xxx, qcom-rpm, rk808, axp20x, lp873x, exynos5433-lpass, act8945a, aspeed-scu, twl6040, arizona - Bug Fixes - Release OF pointer; qcom_rpm - Avoid double shifting in suspend/resume; 88pm80x - Fix 'defined but not used' error; exynos-lpass - Fix 'sleeping whilst attomic'; atmel-hlcdc -----BEGIN PGP SIGNATURE----- iQIcBAABCAAGBQJX9giOAAoJEFGvii+H/Hdh8aEP/iiHosBZsksZ4we8KAdoXkxi x5nnJvS9+4b5yaasSiN8e2xs9YMOlHu1CNZDZ3RJZ+rLusdVeg5ju5p5WED83pvi ltiPMhyqruM3d0rieTRHxeJFmmEf2exwKV3Y+5lo9586dFfJrmGp2AxScId4TtwP CcsjwYRx/WvVfWrv1xWsjd9b1RDlWglt3dcVhdKAQbvPPOy5O4ymXNMFs0DuFyZ+ 2A16sw7hdYenXSvAHlZzS5IqXP9JEeosu3O/mUUZKF3PO55t+KbQBGZiwXoal4gp 1dwrdBjlrZaHcDa5Ra9x+jQ2kxIkyUT44CXKAHa7llTfZQkZIgnv/fWUhB8C5JxU iaqnN9rWQ2MNjt3Us/n1TSJH2kEnSNbzrQixE0n8yjIBsZePWlW2ZpWYRF7GPG2i 2pB8oNz/NdDkKWdosR3ArnseNOKVcC+GtD+mHk0aKMPghPq+gDIRrdM0CFyWeIZE w/Cf+HHZPR0O1VuYZ9bHIhbgnEbz5xUADOtBAdppIBQiNEI/G9lJpG6Ft4FTQoPi CIbnnB/wxxMaEl85rUPYGkxQniuUI5f0tMv3k2ZtAZMKcqn6iXtiIOuXceM2vUdy ze1uddH4HuHLcrJT5x+J72XJL6RXzZKxOqd0b7BcXnvMVFJrWgleH1JQ2WqazAEW il1u28IkFusm/BW/0dps =Ja7p -----END PGP SIGNATURE----- Merge tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd Pull MFD updates from Lee Jones: "Core framework: - Add the MFD bindings doc to MAINTAINERS New drivers: - X-Powers AC100 Audio CODEC and RTC - TI LP873x PMIC - Rockchip RK808 PMIC - Samsung Exynos Low Power Audio New device support: - Add support for STMPE1600 variant to stmpe - Add support for PM8018 PMIC to pm8921-core - Add support for AXP806 PMIC in axp20x - Add support for AXP209 GPIO in axp20x New functionality: - Add support for Reset to all STMPE variants - Add support for MKBP event support to cros_ec - Add support for USB to intel_soc_pmic_bxtwc - Add support for IRQs and Power Button to tps65217 Fix-ups: - Clean-up defunct author emails (da9063, max14577) - Kconfig fixups (wm8350-i2c, as37220 - Constify (altera-a10sr, sm501) - Supply PCI IDs (intel-lpss-pci) - Improve clocking (qcom_rpm) - Fix IRQ probing (ucb1x00-core) - Ensure fault log is cleared (da9052) - Remove NO_IRQ check (ucb1x00-core) - Supply I2C properties (intel-lpss-acpi, intel-lpss-pci) - Non standard declaration (tps65217, max8997-irq) - Remove unused code (lp873x, db8500-prcmu, ab8500-debugfs, cros_ec_spi) - Make non-modular (altera-a10sr, intel_msic, smsc-ece1099, sun6i-prcm, twl-core) - OF bindings (ac100, stmpe, qcom-pm8xxx, qcom-rpm, rk808, axp20x, lp873x, exynos5433-lpass, act8945a, aspeed-scu, twl6040, arizona) Bugfixes: - Release OF pointer (qcom_rpm) - Avoid double shifting in suspend/resume (88pm80x) - Fix 'defined but not used' error (exynos-lpass) - Fix 'sleeping whilst attomic' (atmel-hlcdc)" * tag 'mfd-for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (69 commits) mfd: arizona: Handle probe deferral for reset GPIO mfd: arizona: Remove arizona_of_get_named_gpio helper function mfd: arizona: Add DT options for max_channels_clocked and PDM speaker config mfd: twl6040: Register child device for twl6040-pdmclk mfd: cros_ec_spi: Remove unused variable 'request' mfd: omap-usb-host: Return value is not 'const int' mfd: ab8500-debugfs: Remove 'weak' function suspend_test_wake_cause_interrupt_is_mine() mfd: ab8500-debugfs: Remove ab8500_dump_all_banks_to_mem() mfd: db8500-prcmu: Remove unused *prcmu_set_ddr_opp() calls mfd: ab8500-debugfs: Prevent initialised field from being over-written mfd: max8997-irq: 'inline' should be at the beginning of the declaration mfd: rk808: Fix RK818_IRQ_DISCHG_ILIM initializer mfd: tps65217: Fix nonstandard declaration mfd: lp873x: Remove unused mutex lock from struct lp873x mfd: atmel-hlcdc: Do not sleep in atomic context mfd: exynos-lpass: Mark PM functions as __maybe_unused mfd: intel-lpss: Add default I2C device properties for Apollo Lake mfd: twl-core: Make it explicitly non-modular mfd: sun6i-prcm: Make it explicitly non-modular mfd: smsc-ece1099: Make it explicitly non-modular ...
This commit is contained in:
commit
d042380886
54
Documentation/devicetree/bindings/mfd/ac100.txt
Normal file
54
Documentation/devicetree/bindings/mfd/ac100.txt
Normal file
@ -0,0 +1,54 @@
|
||||
X-Powers AC100 Codec/RTC IC Device Tree bindings
|
||||
|
||||
AC100 is a audio codec and RTC subsystem combo IC. The 2 parts are
|
||||
separated, including power supplies and interrupt lines, but share
|
||||
a common register address space and host interface.
|
||||
|
||||
Required properties:
|
||||
- compatible: "x-powers,ac100"
|
||||
- reg: The I2C slave address or RSB hardware address for the chip
|
||||
- sub-nodes:
|
||||
- codec
|
||||
- compatible: "x-powers,ac100-codec"
|
||||
- interrupt-parent: The parent interrupt controller
|
||||
- interrupts: SoC NMI / GPIO interrupt connected to the
|
||||
IRQ_AUDIO pin
|
||||
- #clock-cells: Shall be 0
|
||||
- clock-output-names: "4M_adda"
|
||||
|
||||
- see clock/clock-bindings.txt for common clock bindings
|
||||
|
||||
- rtc
|
||||
- compatible: "x-powers,ac100-rtc"
|
||||
- interrupt-parent: The parent interrupt controller
|
||||
- interrupts: SoC NMI / GPIO interrupt connected to the
|
||||
IRQ_RTC pin
|
||||
- clocks: A phandle to the codec's "4M_adda" clock
|
||||
- #clock-cells: Shall be 1
|
||||
- clock-output-names: "cko1_rtc", "cko2_rtc", "cko3_rtc"
|
||||
|
||||
- see clock/clock-bindings.txt for common clock bindings
|
||||
|
||||
Example:
|
||||
|
||||
ac100: codec@e89 {
|
||||
compatible = "x-powers,ac100";
|
||||
reg = <0xe89>;
|
||||
|
||||
ac100_codec: codec {
|
||||
compatible = "x-powers,ac100-codec";
|
||||
interrupt-parent = <&r_pio>;
|
||||
interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PL9 */
|
||||
#clock-cells = <0>;
|
||||
clock-output-names = "4M_adda";
|
||||
};
|
||||
|
||||
ac100_rtc: rtc {
|
||||
compatible = "x-powers,ac100-rtc";
|
||||
interrupt-parent = <&nmi_intc>;
|
||||
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&ac100_codec>;
|
||||
#clock-cells = <1>;
|
||||
clock-output-names = "cko1_rtc", "cko2_rtc", "cko3_rtc";
|
||||
};
|
||||
};
|
@ -14,13 +14,6 @@ Example:
|
||||
reg = <0x5b>;
|
||||
status = "okay";
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_charger_chglev>;
|
||||
active-semi,chglev-gpio = <&pioA 12 GPIO_ACTIVE_HIGH>;
|
||||
active-semi,input-voltage-threshold-microvolt = <6600>;
|
||||
active-semi,precondition-timeout = <40>;
|
||||
active-semi,total-timeout = <3>;
|
||||
|
||||
active-semi,vsel-high;
|
||||
|
||||
regulators {
|
||||
@ -73,4 +66,19 @@ Example:
|
||||
regulator-always-on;
|
||||
};
|
||||
};
|
||||
|
||||
charger {
|
||||
compatible = "active-semi,act8945a-charger";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pinctrl_charger_chglev &pinctrl_charger_lbo &pinctrl_charger_irq>;
|
||||
interrupt-parent = <&pioA>;
|
||||
interrupts = <45 GPIO_ACTIVE_LOW>;
|
||||
|
||||
active-semi,chglev-gpios = <&pioA 12 GPIO_ACTIVE_HIGH>;
|
||||
active-semi,lbo-gpios = <&pioA 72 GPIO_ACTIVE_LOW>;
|
||||
active-semi,input-voltage-threshold-microvolt = <6600>;
|
||||
active-semi,precondition-timeout = <40>;
|
||||
active-semi,total-timeout = <3>;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
@ -85,6 +85,24 @@ Optional properties:
|
||||
present, the number of values should be less than or equal to the
|
||||
number of inputs, unspecified inputs will use the chip default.
|
||||
|
||||
- wlf,max-channels-clocked : The maximum number of channels to be clocked on
|
||||
each AIF, useful for I2S systems with multiple data lines being mastered.
|
||||
Specify one cell for each AIF to be configured, specify zero for AIFs that
|
||||
should be handled normally.
|
||||
If present, number of cells must be less than or equal to the number of
|
||||
AIFs. If less than the number of AIFs, for cells that have not been
|
||||
specified the corresponding AIFs will be treated as default setting.
|
||||
|
||||
- wlf,spk-fmt : PDM speaker data format, must contain 2 cells (OUT5 and OUT6).
|
||||
See the datasheet for values.
|
||||
The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
|
||||
wm8998, wm1814)
|
||||
|
||||
- wlf,spk-mute : PDM speaker mute setting, must contain 2 cells (OUT5 and OUT6).
|
||||
See the datasheet for values.
|
||||
The second cell is ignored for codecs that do not have OUT6 (wm5102, wm8997,
|
||||
wm8998, wm1814)
|
||||
|
||||
- DCVDD-supply, MICVDD-supply : Power supplies, only need to be specified if
|
||||
they are being externally supplied. As covered in
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
|
18
Documentation/devicetree/bindings/mfd/aspeed-scu.txt
Normal file
18
Documentation/devicetree/bindings/mfd/aspeed-scu.txt
Normal file
@ -0,0 +1,18 @@
|
||||
The Aspeed System Control Unit manages the global behaviour of the SoC,
|
||||
configuring elements such as clocks, pinmux, and reset.
|
||||
|
||||
Required properties:
|
||||
- compatible: One of:
|
||||
"aspeed,ast2400-scu", "syscon", "simple-mfd"
|
||||
"aspeed,g4-scu", "syscon", "simple-mfd"
|
||||
"aspeed,ast2500-scu", "syscon", "simple-mfd"
|
||||
"aspeed,g5-scu", "syscon", "simple-mfd"
|
||||
|
||||
- reg: contains the offset and length of the SCU memory region
|
||||
|
||||
Example:
|
||||
|
||||
syscon: syscon@1e6e2000 {
|
||||
compatible = "aspeed,ast2400-scu", "syscon", "simple-mfd";
|
||||
reg = <0x1e6e2000 0x1a8>;
|
||||
};
|
@ -10,7 +10,8 @@ axp809 (X-Powers)
|
||||
|
||||
Required properties:
|
||||
- compatible: "x-powers,axp152", "x-powers,axp202", "x-powers,axp209",
|
||||
"x-powers,axp221", "x-powers,axp223", "x-powers,axp809"
|
||||
"x-powers,axp221", "x-powers,axp223", "x-powers,axp806",
|
||||
"x-powers,axp809"
|
||||
- reg: The I2C slave address or RSB hardware address for the AXP chip
|
||||
- interrupt-parent: The parent interrupt controller
|
||||
- interrupts: SoC NMI / GPIO interrupt connected to the PMIC's IRQ pin
|
||||
@ -47,7 +48,6 @@ Optional properties for DCDC regulators:
|
||||
probably makes sense for HiFi audio related
|
||||
applications that aren't battery constrained.
|
||||
|
||||
|
||||
AXP202/AXP209 regulators, type, and corresponding input supply names:
|
||||
|
||||
Regulator Type Supply Name Notes
|
||||
@ -86,6 +86,30 @@ LDO_IO1 : LDO : ips-supply : GPIO 1
|
||||
RTC_LDO : LDO : ips-supply : always on
|
||||
DRIVEVBUS : Enable output : drivevbus-supply : external regulator
|
||||
|
||||
AXP806 regulators, type, and corresponding input supply names:
|
||||
|
||||
Regulator Type Supply Name Notes
|
||||
--------- ---- ----------- -----
|
||||
DCDCA : DC-DC buck : vina-supply : poly-phase capable
|
||||
DCDCB : DC-DC buck : vinb-supply : poly-phase capable
|
||||
DCDCC : DC-DC buck : vinc-supply : poly-phase capable
|
||||
DCDCD : DC-DC buck : vind-supply : poly-phase capable
|
||||
DCDCE : DC-DC buck : vine-supply : poly-phase capable
|
||||
ALDO1 : LDO : aldoin-supply : shared supply
|
||||
ALDO2 : LDO : aldoin-supply : shared supply
|
||||
ALDO3 : LDO : aldoin-supply : shared supply
|
||||
BLDO1 : LDO : bldoin-supply : shared supply
|
||||
BLDO2 : LDO : bldoin-supply : shared supply
|
||||
BLDO3 : LDO : bldoin-supply : shared supply
|
||||
BLDO4 : LDO : bldoin-supply : shared supply
|
||||
CLDO1 : LDO : cldoin-supply : shared supply
|
||||
CLDO2 : LDO : cldoin-supply : shared supply
|
||||
CLDO3 : LDO : cldoin-supply : shared supply
|
||||
SW : On/Off Switch : swin-supply
|
||||
|
||||
Additionally, the AXP806 DC-DC regulators support poly-phase arrangements
|
||||
for higher output current. The possible groupings are: A+B, A+B+C, D+E.
|
||||
|
||||
AXP809 regulators, type, and corresponding input supply names:
|
||||
|
||||
Regulator Type Supply Name Notes
|
||||
|
59
Documentation/devicetree/bindings/mfd/lp873x.txt
Normal file
59
Documentation/devicetree/bindings/mfd/lp873x.txt
Normal file
@ -0,0 +1,59 @@
|
||||
TI LP873X PMIC MFD driver
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,lp8732", "ti,lp8733"
|
||||
- reg: I2C slave address.
|
||||
- gpio-controller: Marks the device node as a GPIO Controller.
|
||||
- #gpio-cells: Should be two. The first cell is the pin number and
|
||||
the second cell is used to specify flags.
|
||||
See ../gpio/gpio.txt for more information.
|
||||
- regulators: List of child nodes that specify the regulator
|
||||
initialization data.
|
||||
Example:
|
||||
|
||||
pmic: lp8733@60 {
|
||||
compatible = "ti,lp8733";
|
||||
reg = <0x60>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
regulators {
|
||||
lp8733_buck0: buck0 {
|
||||
regulator-name = "lp8733-buck0";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <1400000>;
|
||||
regulator-min-microamp = <1500000>;
|
||||
regulator-max-microamp = <4000000>;
|
||||
regulator-ramp-delay = <10000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
|
||||
lp8733_buck1: buck1 {
|
||||
regulator-name = "lp8733-buck1";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <1400000>;
|
||||
regulator-min-microamp = <1500000>;
|
||||
regulator-max-microamp = <4000000>;
|
||||
regulator-ramp-delay = <10000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
lp8733_ldo0: ldo0 {
|
||||
regulator-name = "lp8733-ldo0";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
regulator-boot-on;
|
||||
regulator-always-on;
|
||||
};
|
||||
|
||||
lp8733_ldo1: ldo1 {
|
||||
regulator-name = "lp8733-ldo1";
|
||||
regulator-min-microvolt = <800000>;
|
||||
regulator-max-microvolt = <3000000>;
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
};
|
||||
};
|
||||
};
|
@ -62,6 +62,7 @@ The below bindings specify the set of valid subnodes.
|
||||
"qcom,pm8058-rtc"
|
||||
"qcom,pm8921-rtc"
|
||||
"qcom,pm8941-rtc"
|
||||
"qcom,pm8018-rtc"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
|
@ -13,6 +13,7 @@ frequencies.
|
||||
"qcom,rpm-msm8660"
|
||||
"qcom,rpm-msm8960"
|
||||
"qcom,rpm-ipq8064"
|
||||
"qcom,rpm-mdm9615"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
@ -59,6 +60,7 @@ Regulator nodes are identified by their compatible:
|
||||
"qcom,rpm-pm8058-regulators"
|
||||
"qcom,rpm-pm8901-regulators"
|
||||
"qcom,rpm-pm8921-regulators"
|
||||
"qcom,rpm-pm8018-regulators"
|
||||
|
||||
- vdd_l0_l1_lvs-supply:
|
||||
- vdd_l2_l11_l12-supply:
|
||||
@ -137,6 +139,15 @@ Regulator nodes are identified by their compatible:
|
||||
Definition: reference to regulator supplying the input pin, as
|
||||
described in the data sheet
|
||||
|
||||
- vin_lvs1-supply:
|
||||
- vdd_l7-supply:
|
||||
- vdd_l8-supply:
|
||||
- vdd_l9_l10_l11_l12-supply:
|
||||
Usage: optional (pm8018 only)
|
||||
Value type: <phandle>
|
||||
Definition: reference to regulator supplying the input pin, as
|
||||
described in the data sheet
|
||||
|
||||
The regulator node houses sub-nodes for each regulator within the device. Each
|
||||
sub-node is identified using the node's name, with valid values listed for each
|
||||
of the pmics below.
|
||||
@ -156,6 +167,10 @@ pm8921:
|
||||
l29, lvs1, lvs2, lvs3, lvs4, lvs5, lvs6, lvs7, usb-switch, hdmi-switch,
|
||||
ncp
|
||||
|
||||
pm8018:
|
||||
s1, s2, s3, s4, s5, , l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
|
||||
l12, l14, lvs1
|
||||
|
||||
The content of each sub-node is defined by the standard binding for regulators -
|
||||
see regulator.txt - with additional custom properties described below:
|
||||
|
||||
|
@ -1,7 +1,11 @@
|
||||
RK808 Power Management Integrated Circuit
|
||||
RK8XX Power Management Integrated Circuit
|
||||
|
||||
The rk8xx family current members:
|
||||
rk808
|
||||
rk818
|
||||
|
||||
Required properties:
|
||||
- compatible: "rockchip,rk808"
|
||||
- compatible: "rockchip,rk808", "rockchip,rk818"
|
||||
- reg: I2C slave address
|
||||
- interrupt-parent: The parent interrupt controller.
|
||||
- interrupts: the interrupt outputs of the controller.
|
||||
@ -13,6 +17,8 @@ Optional properties:
|
||||
default output clock name
|
||||
- rockchip,system-power-controller: Telling whether or not this pmic is controlling
|
||||
the system power.
|
||||
|
||||
Optional RK808 properties:
|
||||
- vcc1-supply: The input supply for DCDC_REG1
|
||||
- vcc2-supply: The input supply for DCDC_REG2
|
||||
- vcc3-supply: The input supply for DCDC_REG3
|
||||
@ -29,7 +35,20 @@ Optional properties:
|
||||
the gpio controller. If DVS GPIOs aren't present, voltage changes will happen
|
||||
very quickly with no slow ramp time.
|
||||
|
||||
Regulators: All the regulators of RK808 to be instantiated shall be
|
||||
Optional RK818 properties:
|
||||
- vcc1-supply: The input supply for DCDC_REG1
|
||||
- vcc2-supply: The input supply for DCDC_REG2
|
||||
- vcc3-supply: The input supply for DCDC_REG3
|
||||
- vcc4-supply: The input supply for DCDC_REG4
|
||||
- boost-supply: The input supply for DCDC_BOOST
|
||||
- vcc6-supply: The input supply for LDO_REG1 and LDO_REG2
|
||||
- vcc7-supply: The input supply for LDO_REG3, LDO_REG5 and LDO_REG7
|
||||
- vcc8-supply: The input supply for LDO_REG4, LDO_REG6 and LDO_REG8
|
||||
- vcc9-supply: The input supply for LDO_REG9 and SWITCH_REG
|
||||
- h_5v-supply: The input supply for HDMI_SWITCH
|
||||
- usb-supply: The input supply for OTG_SWITCH
|
||||
|
||||
Regulators: All the regulators of RK8XX to be instantiated shall be
|
||||
listed in a child node named 'regulators'. Each regulator is represented
|
||||
by a child node of the 'regulators' node.
|
||||
|
||||
@ -48,6 +67,18 @@ number as described in RK808 datasheet.
|
||||
- SWITCH_REGn
|
||||
- valid values for n are 1 to 2
|
||||
|
||||
Following regulators of the RK818 PMIC block are supported. Note that
|
||||
the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO
|
||||
number as described in RK818 datasheet.
|
||||
|
||||
- DCDC_REGn
|
||||
- valid values for n are 1 to 4.
|
||||
- LDO_REGn
|
||||
- valid values for n are 1 to 9.
|
||||
- SWITCH_REG
|
||||
- HDMI_SWITCH
|
||||
- OTG_SWITCH
|
||||
|
||||
Standard regulator bindings are used inside regulator subnodes. Check
|
||||
Documentation/devicetree/bindings/regulator/regulator.txt
|
||||
for more details
|
||||
|
@ -0,0 +1,70 @@
|
||||
Samsung Exynos SoC Low Power Audio Subsystem (LPASS)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "samsung,exynos5433-lpass"
|
||||
- reg : should contain the LPASS top SFR region location
|
||||
and size
|
||||
- samsung,pmu-syscon : the phandle to the Power Management Unit node
|
||||
- #address-cells : should be 1
|
||||
- #size-cells : should be 1
|
||||
- ranges : must be present
|
||||
|
||||
Each IP block of the Low Power Audio Subsystem should be specified as
|
||||
an optional sub-node. For "samsung,exynos5433-lpass" compatible this includes:
|
||||
UART, SLIMBUS, PCM, I2S, DMAC, Timers 0...4, VIC, WDT 0...1 devices.
|
||||
|
||||
Bindings of the sub-nodes are described in:
|
||||
../serial/samsung_uart.txt
|
||||
../sound/samsung-i2s.txt
|
||||
../dma/arm-pl330.txt
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
audio-subsystem {
|
||||
compatible = "samsung,exynos5433-lpass";
|
||||
reg = <0x11400000 0x100>, <0x11500000 0x08>;
|
||||
samsung,pmu-syscon = <&pmu_system_controller>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
adma: adma@11420000 {
|
||||
compatible = "arm,pl330", "arm,primecell";
|
||||
reg = <0x11420000 0x1000>;
|
||||
interrupts = <0 73 0>;
|
||||
clocks = <&cmu_aud CLK_ACLK_DMAC>;
|
||||
clock-names = "apb_pclk";
|
||||
#dma-cells = <1>;
|
||||
#dma-channels = <8>;
|
||||
#dma-requests = <32>;
|
||||
};
|
||||
|
||||
i2s0: i2s0@11440000 {
|
||||
compatible = "samsung,exynos7-i2s";
|
||||
reg = <0x11440000 0x100>;
|
||||
dmas = <&adma 0 &adma 2>;
|
||||
dma-names = "tx", "rx";
|
||||
interrupts = <0 70 0>;
|
||||
clocks = <&cmu_aud CLK_PCLK_AUD_I2S>,
|
||||
<&cmu_aud CLK_SCLK_AUD_I2S>,
|
||||
<&cmu_aud CLK_SCLK_I2S_BCLK>;
|
||||
clock-names = "iis", "i2s_opclk0", "i2s_opclk1";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&i2s0_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
serial_3: serial@11460000 {
|
||||
compatible = "samsung,exynos5433-uart";
|
||||
reg = <0x11460000 0x100>;
|
||||
interrupts = <0 67 0>;
|
||||
clocks = <&cmu_aud CLK_PCLK_AUD_UART>,
|
||||
<&cmu_aud CLK_SCLK_AUD_UART>;
|
||||
clock-names = "uart", "clk_uart_baud0";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart_aud_bus>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
@ -12,6 +12,7 @@ Required properties:
|
||||
- interrupt-parent: The parent interrupt controller
|
||||
- gpio-controller:
|
||||
- #gpio-cells = <1>: twl6040 provides GPO lines.
|
||||
- #clock-cells = <0>; twl6040 is a provider of pdmclk which is used by McPDM
|
||||
- twl6040,audpwron-gpio: Power on GPIO line for the twl6040
|
||||
|
||||
- vio-supply: Regulator for the twl6040 VIO supply
|
||||
|
@ -8098,6 +8098,7 @@ MULTIFUNCTION DEVICES (MFD)
|
||||
M: Lee Jones <lee.jones@linaro.org>
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/mfd/
|
||||
F: drivers/mfd/
|
||||
F: include/linux/mfd/
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/input/matrix_keypad.h>
|
||||
@ -44,6 +45,7 @@
|
||||
* @dev: Device pointer
|
||||
* @idev: Input device
|
||||
* @ec: Top level ChromeOS device to use to talk to EC
|
||||
* @notifier: interrupt event notifier for transport devices
|
||||
*/
|
||||
struct cros_ec_keyb {
|
||||
unsigned int rows;
|
||||
@ -57,6 +59,7 @@ struct cros_ec_keyb {
|
||||
struct device *dev;
|
||||
struct input_dev *idev;
|
||||
struct cros_ec_device *ec;
|
||||
struct notifier_block notifier;
|
||||
};
|
||||
|
||||
|
||||
@ -146,67 +149,44 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
|
||||
input_sync(ckdev->idev);
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state)
|
||||
{
|
||||
int ret = 0;
|
||||
struct cros_ec_command *msg;
|
||||
|
||||
msg = kmalloc(sizeof(*msg) + ckdev->cols, GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_MKBP_STATE;
|
||||
msg->insize = ckdev->cols;
|
||||
msg->outsize = 0;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ckdev->ec, msg);
|
||||
if (ret < 0) {
|
||||
dev_err(ckdev->dev, "Error transferring EC message %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memcpy(kb_state, msg->data, ckdev->cols);
|
||||
exit:
|
||||
kfree(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = data;
|
||||
struct cros_ec_device *ec = ckdev->ec;
|
||||
int ret;
|
||||
uint8_t kb_state[ckdev->cols];
|
||||
|
||||
if (device_may_wakeup(ec->dev))
|
||||
pm_wakeup_event(ec->dev, 0);
|
||||
|
||||
ret = cros_ec_keyb_get_state(ckdev, kb_state);
|
||||
if (ret >= 0)
|
||||
cros_ec_keyb_process(ckdev, kb_state, ret);
|
||||
else
|
||||
dev_err(ckdev->dev, "failed to get keyboard state: %d\n", ret);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_open(struct input_dev *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
|
||||
struct cros_ec_device *ec = ckdev->ec;
|
||||
|
||||
return request_threaded_irq(ec->irq, NULL, cros_ec_keyb_irq,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"cros_ec_keyb", ckdev);
|
||||
return blocking_notifier_chain_register(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
}
|
||||
|
||||
static void cros_ec_keyb_close(struct input_dev *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = input_get_drvdata(dev);
|
||||
struct cros_ec_device *ec = ckdev->ec;
|
||||
|
||||
free_irq(ec->irq, ckdev);
|
||||
blocking_notifier_chain_unregister(&ckdev->ec->event_notifier,
|
||||
&ckdev->notifier);
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_work(struct notifier_block *nb,
|
||||
unsigned long queued_during_suspend, void *_notify)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
|
||||
notifier);
|
||||
|
||||
if (ckdev->ec->event_data.event_type != EC_MKBP_EVENT_KEY_MATRIX)
|
||||
return NOTIFY_DONE;
|
||||
/*
|
||||
* If EC is not the wake source, discard key state changes during
|
||||
* suspend.
|
||||
*/
|
||||
if (queued_during_suspend)
|
||||
return NOTIFY_OK;
|
||||
if (ckdev->ec->event_size != ckdev->cols) {
|
||||
dev_err(ckdev->dev,
|
||||
"Discarded incomplete key matrix event.\n");
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
cros_ec_keyb_process(ckdev, ckdev->ec->event_data.data.key_matrix,
|
||||
ckdev->ec->event_size);
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -265,12 +245,8 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!ec->irq) {
|
||||
dev_err(dev, "no EC IRQ specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ckdev->ec = ec;
|
||||
ckdev->notifier.notifier_call = cros_ec_keyb_work;
|
||||
ckdev->dev = dev;
|
||||
dev_set_drvdata(dev, ckdev);
|
||||
|
||||
@ -311,54 +287,6 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* Clear any keys in the buffer */
|
||||
static void cros_ec_keyb_clear_keyboard(struct cros_ec_keyb *ckdev)
|
||||
{
|
||||
uint8_t old_state[ckdev->cols];
|
||||
uint8_t new_state[ckdev->cols];
|
||||
unsigned long duration;
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
* Keep reading until we see that the scan state does not change.
|
||||
* That indicates that we are done.
|
||||
*
|
||||
* Assume that the EC keyscan buffer is at most 32 deep.
|
||||
*/
|
||||
duration = jiffies;
|
||||
ret = cros_ec_keyb_get_state(ckdev, new_state);
|
||||
for (i = 1; !ret && i < 32; i++) {
|
||||
memcpy(old_state, new_state, sizeof(old_state));
|
||||
ret = cros_ec_keyb_get_state(ckdev, new_state);
|
||||
if (0 == memcmp(old_state, new_state, sizeof(old_state)))
|
||||
break;
|
||||
}
|
||||
duration = jiffies - duration;
|
||||
dev_info(ckdev->dev, "Discarded %d keyscan(s) in %dus\n", i,
|
||||
jiffies_to_usecs(duration));
|
||||
}
|
||||
|
||||
static int cros_ec_keyb_resume(struct device *dev)
|
||||
{
|
||||
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* When the EC is not a wake source, then it could not have caused the
|
||||
* resume, so we clear the EC's key scan buffer. If the EC was a
|
||||
* wake source (e.g. the lid is open and the user might press a key to
|
||||
* wake) then the key scan buffer should be preserved.
|
||||
*/
|
||||
if (!ckdev->ec->was_wake_device)
|
||||
cros_ec_keyb_clear_keyboard(ckdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id cros_ec_keyb_of_match[] = {
|
||||
{ .compatible = "google,cros-ec-keyb" },
|
||||
@ -372,7 +300,6 @@ static struct platform_driver cros_ec_keyb_driver = {
|
||||
.driver = {
|
||||
.name = "cros-ec-keyb",
|
||||
.of_match_table = of_match_ptr(cros_ec_keyb_of_match),
|
||||
.pm = &cros_ec_keyb_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -50,7 +50,7 @@ config MFD_AS3711
|
||||
Support for the AS3711 PMIC from AMS
|
||||
|
||||
config MFD_AS3722
|
||||
bool "ams AS3722 Power Management IC"
|
||||
tristate "ams AS3722 Power Management IC"
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
@ -112,6 +112,16 @@ config MFD_BCM590XX
|
||||
help
|
||||
Support for the BCM590xx PMUs from Broadcom
|
||||
|
||||
config MFD_AC100
|
||||
tristate "X-Powers AC100"
|
||||
select MFD_CORE
|
||||
depends on SUNXI_RSB
|
||||
help
|
||||
If you say Y here you get support for the X-Powers AC100 audio codec
|
||||
IC.
|
||||
This driver include only the core APIs. You have to select individual
|
||||
components like codecs or RTC under the corresponding menus.
|
||||
|
||||
config MFD_AXP20X
|
||||
tristate
|
||||
select MFD_CORE
|
||||
@ -281,6 +291,14 @@ config MFD_DLN2
|
||||
etc. must be enabled in order to use the functionality of
|
||||
the device.
|
||||
|
||||
config MFD_EXYNOS_LPASS
|
||||
tristate "Samsung Exynos SoC Low Power Audio Subsystem"
|
||||
select MFD_CORE
|
||||
select REGMAP_MMIO
|
||||
help
|
||||
Select this option to enable support for Samsung Exynos Low Power
|
||||
Audio Subsystem.
|
||||
|
||||
config MFD_MC13XXX
|
||||
tristate
|
||||
depends on (SPI_MASTER || I2C)
|
||||
@ -844,13 +862,13 @@ config MFD_RC5T583
|
||||
different functionality of the device.
|
||||
|
||||
config MFD_RK808
|
||||
tristate "Rockchip RK808 Power Management chip"
|
||||
tristate "Rockchip RK808/RK818 Power Management Chip"
|
||||
depends on I2C && OF
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select REGMAP_IRQ
|
||||
help
|
||||
If you say yes here you get support for the RK808
|
||||
If you say yes here you get support for the RK808 and RK818
|
||||
Power Management chips.
|
||||
This driver provides common support for accessing the device
|
||||
through I2C interface. The device supports multiple sub-devices
|
||||
@ -1206,6 +1224,7 @@ config MFD_TPS65217
|
||||
depends on I2C
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
select IRQ_DOMAIN
|
||||
help
|
||||
If you say yes here you get support for the TPS65217 series of
|
||||
Power Management / White LED chips.
|
||||
@ -1555,6 +1574,7 @@ config MFD_WM8350
|
||||
config MFD_WM8350_I2C
|
||||
bool "Wolfson Microelectronics WM8350 with I2C"
|
||||
select MFD_WM8350
|
||||
select REGMAP_I2C
|
||||
depends on I2C=y
|
||||
help
|
||||
The WM8350 is an integrated audio and power management
|
||||
|
@ -13,6 +13,7 @@ obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o
|
||||
obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
|
||||
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
|
||||
obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o
|
||||
|
||||
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
|
||||
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
|
||||
@ -114,6 +115,8 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o
|
||||
obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
|
||||
obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
|
||||
obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
|
||||
|
||||
obj-$(CONFIG_MFD_AC100) += ac100.o
|
||||
obj-$(CONFIG_MFD_AXP20X) += axp20x.o
|
||||
obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o
|
||||
obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o
|
||||
|
@ -153,14 +153,14 @@ static struct hwreg_cfg hwreg_cfg = {
|
||||
|
||||
#define AB8500_NAME_STRING "ab8500"
|
||||
#define AB8500_ADC_NAME_STRING "gpadc"
|
||||
#define AB8500_NUM_BANKS 24
|
||||
#define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST
|
||||
|
||||
#define AB8500_REV_REG 0x80
|
||||
|
||||
static struct ab8500_prcmu_ranges *debug_ranges;
|
||||
|
||||
static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
||||
[0x0] = {
|
||||
[AB8500_M_FSM_RANK] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
@ -315,7 +315,7 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
||||
},
|
||||
},
|
||||
},
|
||||
[0x9] = {
|
||||
[AB8500_RESERVED] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
@ -386,24 +386,6 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_DEVELOPMENT] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x00,
|
||||
.last = 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_DEBUG] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x05,
|
||||
.last = 0x07,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_AUDIO] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
@ -463,19 +445,29 @@ static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
|
||||
},
|
||||
},
|
||||
},
|
||||
[0x11] = {
|
||||
[AB8500_DEVELOPMENT] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x00,
|
||||
.last = 0x00,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_DEBUG] = {
|
||||
.num_ranges = 1,
|
||||
.range = (struct ab8500_reg_range[]) {
|
||||
{
|
||||
.first = 0x05,
|
||||
.last = 0x07,
|
||||
},
|
||||
},
|
||||
},
|
||||
[AB8500_PROD_TEST] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
[0x12] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
[0x13] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
[0x14] = {
|
||||
[AB8500_STE_TEST] = {
|
||||
.num_ranges = 0,
|
||||
.range = NULL,
|
||||
},
|
||||
@ -1382,60 +1374,6 @@ void ab8500_dump_all_banks(struct device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/* Space for 500 registers. */
|
||||
#define DUMP_MAX_REGS 700
|
||||
static struct ab8500_register_dump
|
||||
{
|
||||
u8 bank;
|
||||
u8 reg;
|
||||
u8 value;
|
||||
} ab8500_complete_register_dump[DUMP_MAX_REGS];
|
||||
|
||||
/* This shall only be called upon kernel panic! */
|
||||
void ab8500_dump_all_banks_to_mem(void)
|
||||
{
|
||||
int i, r = 0;
|
||||
u8 bank;
|
||||
int err = 0;
|
||||
|
||||
pr_info("Saving all ABB registers for crash analysis.\n");
|
||||
|
||||
for (bank = 0; bank < AB8500_NUM_BANKS; bank++) {
|
||||
for (i = 0; i < debug_ranges[bank].num_ranges; i++) {
|
||||
u8 reg;
|
||||
|
||||
for (reg = debug_ranges[bank].range[i].first;
|
||||
reg <= debug_ranges[bank].range[i].last;
|
||||
reg++) {
|
||||
u8 value;
|
||||
|
||||
err = prcmu_abb_read(bank, reg, &value, 1);
|
||||
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
ab8500_complete_register_dump[r].bank = bank;
|
||||
ab8500_complete_register_dump[r].reg = reg;
|
||||
ab8500_complete_register_dump[r].value = value;
|
||||
|
||||
r++;
|
||||
|
||||
if (r >= DUMP_MAX_REGS) {
|
||||
pr_err("%s: too many register to dump!\n",
|
||||
__func__);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (err >= 0)
|
||||
pr_info("Saved all ABB registers.\n");
|
||||
else
|
||||
pr_info("Failed to save all ABB registers.\n");
|
||||
}
|
||||
|
||||
static int ab8500_all_banks_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct seq_file *s;
|
||||
@ -1584,18 +1522,10 @@ static u32 num_interrupts[AB8500_MAX_NR_IRQS];
|
||||
static u32 num_wake_interrupts[AB8500_MAX_NR_IRQS];
|
||||
static int num_interrupt_lines;
|
||||
|
||||
bool __attribute__((weak)) suspend_test_wake_cause_interrupt_is_mine(u32 my_int)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ab8500_debug_register_interrupt(int line)
|
||||
{
|
||||
if (line < num_interrupt_lines) {
|
||||
if (line < num_interrupt_lines)
|
||||
num_interrupts[line]++;
|
||||
if (suspend_test_wake_cause_interrupt_is_mine(irq_ab8500))
|
||||
num_wake_interrupts[line]++;
|
||||
}
|
||||
}
|
||||
|
||||
static int ab8500_interrupts_print(struct seq_file *s, void *p)
|
||||
|
137
drivers/mfd/ac100.c
Normal file
137
drivers/mfd/ac100.c
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* MFD core driver for X-Powers' AC100 Audio Codec IC
|
||||
*
|
||||
* The AC100 is a highly integrated audio codec and RTC subsystem designed
|
||||
* for mobile applications. It has 3 I2S/PCM interfaces, a 2 channel DAC,
|
||||
* a 2 channel ADC with 5 inputs and a builtin mixer. The RTC subsystem has
|
||||
* 3 clock outputs.
|
||||
*
|
||||
* The audio codec and RTC parts are completely separate, sharing only the
|
||||
* host interface for access to its registers.
|
||||
*
|
||||
* Copyright (2016) Chen-Yu Tsai
|
||||
*
|
||||
* Author: Chen-Yu Tsai <wens@csie.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/ac100.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/sunxi-rsb.h>
|
||||
|
||||
static const struct regmap_range ac100_writeable_ranges[] = {
|
||||
regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_I2S_SR_CTRL),
|
||||
regmap_reg_range(AC100_I2S1_CLK_CTRL, AC100_I2S1_MXR_GAIN),
|
||||
regmap_reg_range(AC100_I2S2_CLK_CTRL, AC100_I2S2_MXR_GAIN),
|
||||
regmap_reg_range(AC100_I2S3_CLK_CTRL, AC100_I2S3_SIG_PATH_CTRL),
|
||||
regmap_reg_range(AC100_ADC_DIG_CTRL, AC100_ADC_VOL_CTRL),
|
||||
regmap_reg_range(AC100_HMIC_CTRL1, AC100_HMIC_STATUS),
|
||||
regmap_reg_range(AC100_DAC_DIG_CTRL, AC100_DAC_MXR_GAIN),
|
||||
regmap_reg_range(AC100_ADC_APC_CTRL, AC100_LINEOUT_CTRL),
|
||||
regmap_reg_range(AC100_ADC_DAP_L_CTRL, AC100_ADC_DAP_OPT),
|
||||
regmap_reg_range(AC100_DAC_DAP_CTRL, AC100_DAC_DAP_OPT),
|
||||
regmap_reg_range(AC100_ADC_DAP_ENA, AC100_DAC_DAP_ENA),
|
||||
regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL2),
|
||||
regmap_reg_range(AC100_SRC2_CTRL1, AC100_SRC2_CTRL2),
|
||||
regmap_reg_range(AC100_CLK32K_ANALOG_CTRL, AC100_CLKOUT_CTRL3),
|
||||
regmap_reg_range(AC100_RTC_RST, AC100_RTC_UPD),
|
||||
regmap_reg_range(AC100_ALM_INT_ENA, AC100_ALM_INT_STA),
|
||||
regmap_reg_range(AC100_ALM_SEC, AC100_RTC_GP(15)),
|
||||
};
|
||||
|
||||
static const struct regmap_range ac100_volatile_ranges[] = {
|
||||
regmap_reg_range(AC100_CHIP_AUDIO_RST, AC100_PLL_CTRL2),
|
||||
regmap_reg_range(AC100_HMIC_STATUS, AC100_HMIC_STATUS),
|
||||
regmap_reg_range(AC100_ADC_DAP_L_STA, AC100_ADC_DAP_L_STA),
|
||||
regmap_reg_range(AC100_SRC1_CTRL1, AC100_SRC1_CTRL1),
|
||||
regmap_reg_range(AC100_SRC1_CTRL3, AC100_SRC2_CTRL1),
|
||||
regmap_reg_range(AC100_SRC2_CTRL3, AC100_SRC2_CTRL4),
|
||||
regmap_reg_range(AC100_RTC_RST, AC100_RTC_RST),
|
||||
regmap_reg_range(AC100_RTC_SEC, AC100_ALM_INT_STA),
|
||||
regmap_reg_range(AC100_ALM_SEC, AC100_ALM_UPD),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ac100_writeable_table = {
|
||||
.yes_ranges = ac100_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ac100_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table ac100_volatile_table = {
|
||||
.yes_ranges = ac100_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(ac100_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_config ac100_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 16,
|
||||
.wr_table = &ac100_writeable_table,
|
||||
.volatile_table = &ac100_volatile_table,
|
||||
.max_register = AC100_RTC_GP(15),
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static struct mfd_cell ac100_cells[] = {
|
||||
{
|
||||
.name = "ac100-codec",
|
||||
.of_compatible = "x-powers,ac100-codec",
|
||||
}, {
|
||||
.name = "ac100-rtc",
|
||||
.of_compatible = "x-powers,ac100-rtc",
|
||||
},
|
||||
};
|
||||
|
||||
static int ac100_rsb_probe(struct sunxi_rsb_device *rdev)
|
||||
{
|
||||
struct ac100_dev *ac100;
|
||||
int ret;
|
||||
|
||||
ac100 = devm_kzalloc(&rdev->dev, sizeof(*ac100), GFP_KERNEL);
|
||||
if (!ac100)
|
||||
return -ENOMEM;
|
||||
|
||||
ac100->dev = &rdev->dev;
|
||||
sunxi_rsb_device_set_drvdata(rdev, ac100);
|
||||
|
||||
ac100->regmap = devm_regmap_init_sunxi_rsb(rdev, &ac100_regmap_config);
|
||||
if (IS_ERR(ac100->regmap)) {
|
||||
ret = PTR_ERR(ac100->regmap);
|
||||
dev_err(ac100->dev, "regmap init failed: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(ac100->dev, PLATFORM_DEVID_NONE, ac100_cells,
|
||||
ARRAY_SIZE(ac100_cells), NULL, 0, NULL);
|
||||
if (ret) {
|
||||
dev_err(ac100->dev, "failed to add MFD devices: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ac100_of_match[] = {
|
||||
{ .compatible = "x-powers,ac100" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ac100_of_match);
|
||||
|
||||
static struct sunxi_rsb_driver ac100_rsb_driver = {
|
||||
.driver = {
|
||||
.name = "ac100",
|
||||
.of_match_table = of_match_ptr(ac100_of_match),
|
||||
},
|
||||
.probe = ac100_rsb_probe,
|
||||
};
|
||||
module_sunxi_rsb_driver(ac100_rsb_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Audio codec MFD core driver for AC100");
|
||||
MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -23,6 +23,7 @@ static const struct mfd_cell act8945a_devs[] = {
|
||||
},
|
||||
{
|
||||
.name = "act8945a-charger",
|
||||
.of_compatible = "active-semi,act8945a-charger",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
/*
|
||||
* Altera Arria10 DevKit System Resource MFD Driver
|
||||
*
|
||||
* Author: Thor Thayer <tthayer@opensource.altera.com>
|
||||
*
|
||||
* Copyright Intel Corporation (C) 2014-2016. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
@ -20,7 +24,7 @@
|
||||
|
||||
#include <linux/mfd/altera-a10sr.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/spi/spi.h>
|
||||
|
||||
@ -94,7 +98,7 @@ static bool altr_a10sr_reg_volatile(struct device *dev, unsigned int reg)
|
||||
}
|
||||
}
|
||||
|
||||
const struct regmap_config altr_a10sr_regmap_config = {
|
||||
static const struct regmap_config altr_a10sr_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
@ -152,7 +156,6 @@ static const struct of_device_id altr_a10sr_spi_of_match[] = {
|
||||
{ .compatible = "altr,a10sr" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, altr_a10sr_spi_of_match);
|
||||
|
||||
static struct spi_driver altr_a10sr_spi_driver = {
|
||||
.probe = altr_a10sr_spi_probe,
|
||||
@ -161,9 +164,4 @@ static struct spi_driver altr_a10sr_spi_driver = {
|
||||
.of_match_table = of_match_ptr(altr_a10sr_spi_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_spi_driver(altr_a10sr_spi_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Thor Thayer <tthayer@opensource.altera.com>");
|
||||
MODULE_DESCRIPTION("Altera Arria10 DevKit System Resource MFD Driver");
|
||||
builtin_driver(altr_a10sr_spi_driver, spi_register_driver)
|
||||
|
@ -10,6 +10,7 @@
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -49,7 +50,15 @@ int arizona_clk32k_enable(struct arizona *arizona)
|
||||
case ARIZONA_32KZ_MCLK1:
|
||||
ret = pm_runtime_get_sync(arizona->dev);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
goto err_ref;
|
||||
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK1]);
|
||||
if (ret != 0)
|
||||
goto err_pm;
|
||||
break;
|
||||
case ARIZONA_32KZ_MCLK2:
|
||||
ret = clk_prepare_enable(arizona->mclk[ARIZONA_MCLK2]);
|
||||
if (ret != 0)
|
||||
goto err_ref;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -58,7 +67,9 @@ int arizona_clk32k_enable(struct arizona *arizona)
|
||||
ARIZONA_CLK_32K_ENA);
|
||||
}
|
||||
|
||||
out:
|
||||
err_pm:
|
||||
pm_runtime_put_sync(arizona->dev);
|
||||
err_ref:
|
||||
if (ret != 0)
|
||||
arizona->clk32k_ref--;
|
||||
|
||||
@ -83,6 +94,10 @@ int arizona_clk32k_disable(struct arizona *arizona)
|
||||
switch (arizona->pdata.clk32k_src) {
|
||||
case ARIZONA_32KZ_MCLK1:
|
||||
pm_runtime_put_sync(arizona->dev);
|
||||
clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK1]);
|
||||
break;
|
||||
case ARIZONA_32KZ_MCLK2:
|
||||
clk_disable_unprepare(arizona->mclk[ARIZONA_MCLK2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -735,7 +750,7 @@ static int arizona_suspend(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arizona_suspend_late(struct device *dev)
|
||||
static int arizona_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(dev);
|
||||
|
||||
@ -759,7 +774,7 @@ static int arizona_resume(struct device *dev)
|
||||
{
|
||||
struct arizona *arizona = dev_get_drvdata(dev);
|
||||
|
||||
dev_dbg(arizona->dev, "Late resume, reenabling IRQ\n");
|
||||
dev_dbg(arizona->dev, "Resume, reenabling IRQ\n");
|
||||
enable_irq(arizona->irq);
|
||||
|
||||
return 0;
|
||||
@ -771,10 +786,8 @@ const struct dev_pm_ops arizona_pm_ops = {
|
||||
arizona_runtime_resume,
|
||||
NULL)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume)
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.suspend_late = arizona_suspend_late,
|
||||
.resume_noirq = arizona_resume_noirq,
|
||||
#endif
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(arizona_suspend_noirq,
|
||||
arizona_resume_noirq)
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(arizona_pm_ops);
|
||||
|
||||
@ -790,35 +803,25 @@ unsigned long arizona_of_get_type(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_of_get_type);
|
||||
|
||||
int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
|
||||
bool mandatory)
|
||||
{
|
||||
int gpio;
|
||||
|
||||
gpio = of_get_named_gpio(arizona->dev->of_node, prop, 0);
|
||||
if (gpio < 0) {
|
||||
if (mandatory)
|
||||
dev_err(arizona->dev,
|
||||
"Mandatory DT gpio %s missing/malformed: %d\n",
|
||||
prop, gpio);
|
||||
|
||||
gpio = 0;
|
||||
}
|
||||
|
||||
return gpio;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio);
|
||||
|
||||
static int arizona_of_get_core_pdata(struct arizona *arizona)
|
||||
{
|
||||
struct arizona_pdata *pdata = &arizona->pdata;
|
||||
struct property *prop;
|
||||
const __be32 *cur;
|
||||
u32 val;
|
||||
u32 pdm_val[ARIZONA_MAX_PDM_SPK];
|
||||
int ret, i;
|
||||
int count = 0;
|
||||
|
||||
pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true);
|
||||
pdata->reset = of_get_named_gpio(arizona->dev->of_node, "wlf,reset", 0);
|
||||
if (pdata->reset == -EPROBE_DEFER) {
|
||||
return pdata->reset;
|
||||
} else if (pdata->reset < 0) {
|
||||
dev_err(arizona->dev, "Reset GPIO missing/malformed: %d\n",
|
||||
pdata->reset);
|
||||
|
||||
pdata->reset = 0;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(arizona->dev->of_node,
|
||||
"wlf,gpio-defaults",
|
||||
@ -871,6 +874,35 @@ static int arizona_of_get_core_pdata(struct arizona *arizona)
|
||||
count++;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
of_property_for_each_u32(arizona->dev->of_node,
|
||||
"wlf,max-channels-clocked",
|
||||
prop, cur, val) {
|
||||
if (count == ARRAY_SIZE(pdata->max_channels_clocked))
|
||||
break;
|
||||
|
||||
pdata->max_channels_clocked[count] = val;
|
||||
count++;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_array(arizona->dev->of_node,
|
||||
"wlf,spk-fmt",
|
||||
pdm_val,
|
||||
ARRAY_SIZE(pdm_val));
|
||||
|
||||
if (ret >= 0)
|
||||
for (count = 0; count < ARRAY_SIZE(pdata->spk_fmt); ++count)
|
||||
pdata->spk_fmt[count] = pdm_val[count];
|
||||
|
||||
ret = of_property_read_u32_array(arizona->dev->of_node,
|
||||
"wlf,spk-mute",
|
||||
pdm_val,
|
||||
ARRAY_SIZE(pdm_val));
|
||||
|
||||
if (ret >= 0)
|
||||
for (count = 0; count < ARRAY_SIZE(pdata->spk_mute); ++count)
|
||||
pdata->spk_mute[count] = pdm_val[count];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1000,6 +1032,7 @@ static const struct mfd_cell wm8998_devs[] = {
|
||||
|
||||
int arizona_dev_init(struct arizona *arizona)
|
||||
{
|
||||
const char * const mclk_name[] = { "mclk1", "mclk2" };
|
||||
struct device *dev = arizona->dev;
|
||||
const char *type_name = NULL;
|
||||
unsigned int reg, val, mask;
|
||||
@ -1010,11 +1043,24 @@ int arizona_dev_init(struct arizona *arizona)
|
||||
dev_set_drvdata(arizona->dev, arizona);
|
||||
mutex_init(&arizona->clk_lock);
|
||||
|
||||
if (dev_get_platdata(arizona->dev))
|
||||
if (dev_get_platdata(arizona->dev)) {
|
||||
memcpy(&arizona->pdata, dev_get_platdata(arizona->dev),
|
||||
sizeof(arizona->pdata));
|
||||
else
|
||||
arizona_of_get_core_pdata(arizona);
|
||||
} else {
|
||||
ret = arizona_of_get_core_pdata(arizona);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(arizona->mclk) != ARRAY_SIZE(mclk_name));
|
||||
for (i = 0; i < ARRAY_SIZE(arizona->mclk); i++) {
|
||||
arizona->mclk[i] = devm_clk_get(arizona->dev, mclk_name[i]);
|
||||
if (IS_ERR(arizona->mclk[i])) {
|
||||
dev_info(arizona->dev, "Failed to get %s: %ld\n",
|
||||
mclk_name[i], PTR_ERR(arizona->mclk[i]));
|
||||
arizona->mclk[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
regcache_cache_only(arizona->regmap, true);
|
||||
|
||||
@ -1035,7 +1081,7 @@ int arizona_dev_init(struct arizona *arizona)
|
||||
default:
|
||||
dev_err(arizona->dev, "Unknown device type %d\n",
|
||||
arizona->type);
|
||||
return -EINVAL;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Mark DCVDD as external, LDO1 driver will clear if internal */
|
||||
@ -1121,6 +1167,7 @@ int arizona_dev_init(struct arizona *arizona)
|
||||
break;
|
||||
default:
|
||||
dev_err(arizona->dev, "Unknown device ID: %x\n", reg);
|
||||
ret = -ENODEV;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
@ -1280,12 +1327,14 @@ int arizona_dev_init(struct arizona *arizona)
|
||||
break;
|
||||
default:
|
||||
dev_err(arizona->dev, "Unknown device ID %x\n", reg);
|
||||
ret = -ENODEV;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
if (!subdevs) {
|
||||
dev_err(arizona->dev,
|
||||
"No kernel support for device ID %x\n", reg);
|
||||
ret = -ENODEV;
|
||||
goto err_reset;
|
||||
}
|
||||
|
||||
|
@ -50,8 +50,9 @@ static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg,
|
||||
if (reg <= ATMEL_HLCDC_DIS) {
|
||||
u32 status;
|
||||
|
||||
readl_poll_timeout(hregmap->regs + ATMEL_HLCDC_SR, status,
|
||||
!(status & ATMEL_HLCDC_SIP), 1, 100);
|
||||
readl_poll_timeout_atomic(hregmap->regs + ATMEL_HLCDC_SR,
|
||||
status, !(status & ATMEL_HLCDC_SIP),
|
||||
1, 100);
|
||||
}
|
||||
|
||||
writel(val, hregmap->regs + reg);
|
||||
|
@ -61,6 +61,7 @@ static int axp20x_rsb_remove(struct sunxi_rsb_device *rdev)
|
||||
|
||||
static const struct of_device_id axp20x_rsb_of_match[] = {
|
||||
{ .compatible = "x-powers,axp223", .data = (void *)AXP223_ID },
|
||||
{ .compatible = "x-powers,axp806", .data = (void *)AXP806_ID },
|
||||
{ .compatible = "x-powers,axp809", .data = (void *)AXP809_ID },
|
||||
{ },
|
||||
};
|
||||
|
@ -38,6 +38,7 @@ static const char * const axp20x_model_names[] = {
|
||||
"AXP221",
|
||||
"AXP223",
|
||||
"AXP288",
|
||||
"AXP806",
|
||||
"AXP809",
|
||||
};
|
||||
|
||||
@ -129,6 +130,27 @@ static const struct regmap_access_table axp288_volatile_table = {
|
||||
.n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp806_writeable_ranges[] = {
|
||||
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_DATACACHE(3)),
|
||||
regmap_reg_range(AXP806_PWR_OUT_CTRL1, AXP806_CLDO3_V_CTRL),
|
||||
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ2_EN),
|
||||
regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
|
||||
};
|
||||
|
||||
static const struct regmap_range axp806_volatile_ranges[] = {
|
||||
regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp806_writeable_table = {
|
||||
.yes_ranges = axp806_writeable_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp806_writeable_ranges),
|
||||
};
|
||||
|
||||
static const struct regmap_access_table axp806_volatile_table = {
|
||||
.yes_ranges = axp806_volatile_ranges,
|
||||
.n_yes_ranges = ARRAY_SIZE(axp806_volatile_ranges),
|
||||
};
|
||||
|
||||
static struct resource axp152_pek_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
|
||||
DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
|
||||
@ -278,6 +300,15 @@ static const struct regmap_config axp288_regmap_config = {
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static const struct regmap_config axp806_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.wr_table = &axp806_writeable_table,
|
||||
.volatile_table = &axp806_volatile_table,
|
||||
.max_register = AXP806_VREF_TEMP_WARN_L,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
|
||||
[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
|
||||
|
||||
@ -409,6 +440,21 @@ static const struct regmap_irq axp288_regmap_irqs[] = {
|
||||
INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
|
||||
};
|
||||
|
||||
static const struct regmap_irq axp806_regmap_irqs[] = {
|
||||
INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV1, 0, 0),
|
||||
INIT_REGMAP_IRQ(AXP806, DIE_TEMP_HIGH_LV2, 0, 1),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCA_V_LOW, 0, 3),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCB_V_LOW, 0, 4),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCC_V_LOW, 0, 5),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCD_V_LOW, 0, 6),
|
||||
INIT_REGMAP_IRQ(AXP806, DCDCE_V_LOW, 0, 7),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_LONG, 1, 0),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_SHORT, 1, 1),
|
||||
INIT_REGMAP_IRQ(AXP806, WAKEUP, 1, 4),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_FALL, 1, 5),
|
||||
INIT_REGMAP_IRQ(AXP806, PWROK_RISE, 1, 6),
|
||||
};
|
||||
|
||||
static const struct regmap_irq axp809_regmap_irqs[] = {
|
||||
INIT_REGMAP_IRQ(AXP809, ACIN_OVER_V, 0, 7),
|
||||
INIT_REGMAP_IRQ(AXP809, ACIN_PLUGIN, 0, 6),
|
||||
@ -494,6 +540,18 @@ static const struct regmap_irq_chip axp288_regmap_irq_chip = {
|
||||
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip axp806_regmap_irq_chip = {
|
||||
.name = "axp806",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
.ack_base = AXP20X_IRQ1_STATE,
|
||||
.mask_base = AXP20X_IRQ1_EN,
|
||||
.mask_invert = true,
|
||||
.init_ack_masked = true,
|
||||
.irqs = axp806_regmap_irqs,
|
||||
.num_irqs = ARRAY_SIZE(axp806_regmap_irqs),
|
||||
.num_regs = 2,
|
||||
};
|
||||
|
||||
static const struct regmap_irq_chip axp809_regmap_irq_chip = {
|
||||
.name = "axp809",
|
||||
.status_base = AXP20X_IRQ1_STATE,
|
||||
@ -508,6 +566,9 @@ static const struct regmap_irq_chip axp809_regmap_irq_chip = {
|
||||
|
||||
static struct mfd_cell axp20x_cells[] = {
|
||||
{
|
||||
.name = "axp20x-gpio",
|
||||
.of_compatible = "x-powers,axp209-gpio",
|
||||
}, {
|
||||
.name = "axp20x-pek",
|
||||
.num_resources = ARRAY_SIZE(axp20x_pek_resources),
|
||||
.resources = axp20x_pek_resources,
|
||||
@ -660,12 +721,20 @@ static struct mfd_cell axp288_cells[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp806_cells[] = {
|
||||
{
|
||||
.id = 2,
|
||||
.name = "axp20x-regulator",
|
||||
},
|
||||
};
|
||||
|
||||
static struct mfd_cell axp809_cells[] = {
|
||||
{
|
||||
.name = "axp20x-pek",
|
||||
.num_resources = ARRAY_SIZE(axp809_pek_resources),
|
||||
.resources = axp809_pek_resources,
|
||||
}, {
|
||||
.id = 1,
|
||||
.name = "axp20x-regulator",
|
||||
},
|
||||
};
|
||||
@ -732,6 +801,12 @@ int axp20x_match_device(struct axp20x_dev *axp20x)
|
||||
axp20x->regmap_cfg = &axp288_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
|
||||
break;
|
||||
case AXP806_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp806_cells);
|
||||
axp20x->cells = axp806_cells;
|
||||
axp20x->regmap_cfg = &axp806_regmap_config;
|
||||
axp20x->regmap_irq_chip = &axp806_regmap_irq_chip;
|
||||
break;
|
||||
case AXP809_ID:
|
||||
axp20x->nr_cells = ARRAY_SIZE(axp809_cells);
|
||||
axp20x->cells = axp809_cells;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define CROS_EC_DEV_EC_INDEX 0
|
||||
#define CROS_EC_DEV_PD_INDEX 1
|
||||
@ -49,11 +50,28 @@ static const struct mfd_cell ec_pd_cell = {
|
||||
.pdata_size = sizeof(pd_p),
|
||||
};
|
||||
|
||||
static irqreturn_t ec_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct cros_ec_device *ec_dev = data;
|
||||
int ret;
|
||||
|
||||
if (device_may_wakeup(ec_dev->dev))
|
||||
pm_wakeup_event(ec_dev->dev, 0);
|
||||
|
||||
ret = cros_ec_get_next_event(ec_dev);
|
||||
if (ret > 0)
|
||||
blocking_notifier_call_chain(&ec_dev->event_notifier,
|
||||
0, ec_dev);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
int err = 0;
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
|
||||
|
||||
ec_dev->max_request = sizeof(struct ec_params_hello);
|
||||
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
|
||||
ec_dev->max_passthru = 0;
|
||||
@ -70,13 +88,24 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
|
||||
cros_ec_query_all(ec_dev);
|
||||
|
||||
if (ec_dev->irq) {
|
||||
err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread,
|
||||
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
|
||||
"chromeos-ec", ec_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "Failed to request IRQ %d: %d",
|
||||
ec_dev->irq, err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = mfd_add_devices(ec_dev->dev, PLATFORM_DEVID_AUTO, &ec_cell, 1,
|
||||
NULL, ec_dev->irq, NULL);
|
||||
if (err) {
|
||||
dev_err(dev,
|
||||
"Failed to register Embedded Controller subdevice %d\n",
|
||||
err);
|
||||
return err;
|
||||
goto fail_mfd;
|
||||
}
|
||||
|
||||
if (ec_dev->max_passthru) {
|
||||
@ -94,7 +123,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
dev_err(dev,
|
||||
"Failed to register Power Delivery subdevice %d\n",
|
||||
err);
|
||||
return err;
|
||||
goto fail_mfd;
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,13 +132,18 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
|
||||
if (err) {
|
||||
mfd_remove_devices(dev);
|
||||
dev_err(dev, "Failed to register sub-devices\n");
|
||||
return err;
|
||||
goto fail_mfd;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(dev, "Chrome EC device registered\n");
|
||||
|
||||
return 0;
|
||||
|
||||
fail_mfd:
|
||||
if (ec_dev->irq)
|
||||
free_irq(ec_dev->irq, ec_dev);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_register);
|
||||
|
||||
@ -136,13 +170,31 @@ int cros_ec_suspend(struct cros_ec_device *ec_dev)
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_suspend);
|
||||
|
||||
static void cros_ec_drain_events(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
while (cros_ec_get_next_event(ec_dev) > 0)
|
||||
blocking_notifier_call_chain(&ec_dev->event_notifier,
|
||||
1, ec_dev);
|
||||
}
|
||||
|
||||
int cros_ec_resume(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
enable_irq(ec_dev->irq);
|
||||
|
||||
/*
|
||||
* In some cases, we need to distinguish between events that occur
|
||||
* during suspend if the EC is not a wake source. For example,
|
||||
* keypresses during suspend should be discarded if it does not wake
|
||||
* the system.
|
||||
*
|
||||
* If the EC is not a wake source, drain the event queue and mark them
|
||||
* as "queued during suspend".
|
||||
*/
|
||||
if (ec_dev->wake_enabled) {
|
||||
disable_irq_wake(ec_dev->irq);
|
||||
ec_dev->wake_enabled = 0;
|
||||
} else {
|
||||
cros_ec_drain_events(ec_dev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -366,7 +366,6 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev,
|
||||
static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
|
||||
struct cros_ec_command *ec_msg)
|
||||
{
|
||||
struct ec_host_request *request;
|
||||
struct ec_host_response *response;
|
||||
struct cros_ec_spi *ec_spi = ec_dev->priv;
|
||||
struct spi_transfer trans, trans_delay;
|
||||
@ -378,7 +377,6 @@ static int cros_ec_pkt_xfer_spi(struct cros_ec_device *ec_dev,
|
||||
int ret = 0, final_ret;
|
||||
|
||||
len = cros_ec_prepare_tx(ec_dev, ec_msg);
|
||||
request = (struct ec_host_request *)ec_dev->dout;
|
||||
dev_dbg(ec_dev->dev, "prepared, len=%d\n", len);
|
||||
|
||||
/* If it's too soon to do another transaction, wait */
|
||||
|
@ -167,6 +167,7 @@ static bool da9052_reg_writeable(struct device *dev, unsigned int reg)
|
||||
case DA9052_EVENT_B_REG:
|
||||
case DA9052_EVENT_C_REG:
|
||||
case DA9052_EVENT_D_REG:
|
||||
case DA9052_FAULTLOG_REG:
|
||||
case DA9052_IRQ_MASK_A_REG:
|
||||
case DA9052_IRQ_MASK_B_REG:
|
||||
case DA9052_IRQ_MASK_C_REG:
|
||||
@ -541,6 +542,52 @@ const struct regmap_config da9052_regmap_config = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(da9052_regmap_config);
|
||||
|
||||
static int da9052_clear_fault_log(struct da9052 *da9052)
|
||||
{
|
||||
int ret = 0;
|
||||
int fault_log = 0;
|
||||
|
||||
fault_log = da9052_reg_read(da9052, DA9052_FAULTLOG_REG);
|
||||
if (fault_log < 0) {
|
||||
dev_err(da9052->dev,
|
||||
"Cannot read FAULT_LOG %d\n", fault_log);
|
||||
return fault_log;
|
||||
}
|
||||
|
||||
if (fault_log) {
|
||||
if (fault_log & DA9052_FAULTLOG_TWDERROR)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: TWD_ERROR\n");
|
||||
if (fault_log & DA9052_FAULTLOG_VDDFAULT)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: VDD_FAULT\n");
|
||||
if (fault_log & DA9052_FAULTLOG_VDDSTART)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: VDD_START\n");
|
||||
if (fault_log & DA9052_FAULTLOG_TEMPOVER)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: TEMP_OVER\n");
|
||||
if (fault_log & DA9052_FAULTLOG_KEYSHUT)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: KEY_SHUT\n");
|
||||
if (fault_log & DA9052_FAULTLOG_NSDSET)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: nSD_SHUT\n");
|
||||
if (fault_log & DA9052_FAULTLOG_WAITSET)
|
||||
dev_dbg(da9052->dev,
|
||||
"Fault log entry detected: WAIT_SHUT\n");
|
||||
|
||||
ret = da9052_reg_write(da9052,
|
||||
DA9052_FAULTLOG_REG,
|
||||
0xFF);
|
||||
if (ret < 0)
|
||||
dev_err(da9052->dev,
|
||||
"Cannot reset FAULT_LOG values %d\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int da9052_device_init(struct da9052 *da9052, u8 chip_id)
|
||||
{
|
||||
struct da9052_pdata *pdata = dev_get_platdata(da9052->dev);
|
||||
@ -549,6 +596,10 @@ int da9052_device_init(struct da9052 *da9052, u8 chip_id)
|
||||
mutex_init(&da9052->auxadc_lock);
|
||||
init_completion(&da9052->done);
|
||||
|
||||
ret = da9052_clear_fault_log(da9052);
|
||||
if (ret < 0)
|
||||
dev_warn(da9052->dev, "Cannot clear FAULT_LOG\n");
|
||||
|
||||
if (pdata && pdata->init != NULL)
|
||||
pdata->init(da9052);
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
* Copyright 2012 Dialog Semiconductors Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>,
|
||||
* Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
* 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
|
||||
@ -242,5 +242,6 @@ void da9063_device_exit(struct da9063 *da9063)
|
||||
}
|
||||
|
||||
MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
|
||||
MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>, Michal Hajduk <michal.hajduk@diasemi.com>");
|
||||
MODULE_AUTHOR("Krystian Garbaciak");
|
||||
MODULE_AUTHOR("Michal Hajduk");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
* Copyright 2013 Philipp Zabel, Pengutronix
|
||||
*
|
||||
* Author: Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
* 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
|
||||
|
@ -938,25 +938,6 @@ int db8500_prcmu_get_ddr_opp(void)
|
||||
return readb(PRCM_DDR_SUBSYS_APE_MINBW);
|
||||
}
|
||||
|
||||
/**
|
||||
* db8500_set_ddr_opp - set the appropriate DDR OPP
|
||||
* @opp: The new DDR operating point to which transition is to be made
|
||||
* Returns: 0 on success, non-zero on failure
|
||||
*
|
||||
* This function sets the operating point of the DDR.
|
||||
*/
|
||||
static bool enable_set_ddr_opp;
|
||||
int db8500_prcmu_set_ddr_opp(u8 opp)
|
||||
{
|
||||
if (opp < DDR_100_OPP || opp > DDR_25_OPP)
|
||||
return -EINVAL;
|
||||
/* Changing the DDR OPP can hang the hardware pre-v21 */
|
||||
if (enable_set_ddr_opp)
|
||||
writeb(opp, PRCM_DDR_SUBSYS_APE_MINBW);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Divide the frequency of certain clocks by 2 for APE_50_PARTLY_25_OPP. */
|
||||
static void request_even_slower_clocks(bool enable)
|
||||
{
|
||||
|
@ -209,7 +209,7 @@ static struct device *add_child(struct i2c_client *client, const char *name,
|
||||
status = platform_device_add_data(pdev, pdata, pdata_len);
|
||||
if (status < 0) {
|
||||
dev_dbg(&pdev->dev, "can't add platform_data\n");
|
||||
goto err;
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
@ -222,19 +222,20 @@ static struct device *add_child(struct i2c_client *client, const char *name,
|
||||
status = platform_device_add_resources(pdev, &r, 1);
|
||||
if (status < 0) {
|
||||
dev_dbg(&pdev->dev, "can't add irq\n");
|
||||
goto err;
|
||||
goto put_device;
|
||||
}
|
||||
}
|
||||
|
||||
status = platform_device_add(pdev);
|
||||
if (status)
|
||||
goto put_device;
|
||||
|
||||
err:
|
||||
if (status < 0) {
|
||||
platform_device_put(pdev);
|
||||
dev_err(&client->dev, "can't add %s dev\n", name);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
return &pdev->dev;
|
||||
|
||||
put_device:
|
||||
platform_device_put(pdev);
|
||||
dev_err(&client->dev, "failed to add device %s\n", name);
|
||||
return ERR_PTR(status);
|
||||
}
|
||||
|
||||
static int add_children(struct i2c_client *client)
|
||||
|
185
drivers/mfd/exynos-lpass.c
Normal file
185
drivers/mfd/exynos-lpass.c
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Authors: Inha Song <ideal.song@samsung.com>
|
||||
* Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
*
|
||||
* Samsung Exynos SoC series Low Power Audio Subsystem driver.
|
||||
*
|
||||
* This module provides regmap for the Top SFR region and instantiates
|
||||
* devices for IP blocks like DMAC, I2S, UART.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* LPASS Top register definitions */
|
||||
#define SFR_LPASS_CORE_SW_RESET 0x08
|
||||
#define LPASS_SB_SW_RESET BIT(11)
|
||||
#define LPASS_UART_SW_RESET BIT(10)
|
||||
#define LPASS_PCM_SW_RESET BIT(9)
|
||||
#define LPASS_I2S_SW_RESET BIT(8)
|
||||
#define LPASS_WDT1_SW_RESET BIT(4)
|
||||
#define LPASS_WDT0_SW_RESET BIT(3)
|
||||
#define LPASS_TIMER_SW_RESET BIT(2)
|
||||
#define LPASS_MEM_SW_RESET BIT(1)
|
||||
#define LPASS_DMA_SW_RESET BIT(0)
|
||||
|
||||
#define SFR_LPASS_INTR_CA5_MASK 0x48
|
||||
#define SFR_LPASS_INTR_CPU_MASK 0x58
|
||||
#define LPASS_INTR_APM BIT(9)
|
||||
#define LPASS_INTR_MIF BIT(8)
|
||||
#define LPASS_INTR_TIMER BIT(7)
|
||||
#define LPASS_INTR_DMA BIT(6)
|
||||
#define LPASS_INTR_GPIO BIT(5)
|
||||
#define LPASS_INTR_I2S BIT(4)
|
||||
#define LPASS_INTR_PCM BIT(3)
|
||||
#define LPASS_INTR_SLIMBUS BIT(2)
|
||||
#define LPASS_INTR_UART BIT(1)
|
||||
#define LPASS_INTR_SFR BIT(0)
|
||||
|
||||
struct exynos_lpass {
|
||||
/* pointer to the Power Management Unit regmap */
|
||||
struct regmap *pmu;
|
||||
/* pointer to the LPASS TOP regmap */
|
||||
struct regmap *top;
|
||||
};
|
||||
|
||||
static void exynos_lpass_core_sw_reset(struct exynos_lpass *lpass, int mask)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
regmap_read(lpass->top, SFR_LPASS_CORE_SW_RESET, &val);
|
||||
|
||||
val &= ~mask;
|
||||
regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
|
||||
|
||||
usleep_range(100, 150);
|
||||
|
||||
val |= mask;
|
||||
regmap_write(lpass->top, SFR_LPASS_CORE_SW_RESET, val);
|
||||
}
|
||||
|
||||
static void exynos_lpass_enable(struct exynos_lpass *lpass)
|
||||
{
|
||||
/* Unmask SFR, DMA and I2S interrupt */
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK,
|
||||
LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
|
||||
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK,
|
||||
LPASS_INTR_SFR | LPASS_INTR_DMA | LPASS_INTR_I2S);
|
||||
|
||||
/* Activate related PADs from retention state */
|
||||
regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION,
|
||||
EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR);
|
||||
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_I2S_SW_RESET);
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_DMA_SW_RESET);
|
||||
exynos_lpass_core_sw_reset(lpass, LPASS_MEM_SW_RESET);
|
||||
}
|
||||
|
||||
static void exynos_lpass_disable(struct exynos_lpass *lpass)
|
||||
{
|
||||
/* Mask any unmasked IP interrupt sources */
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CPU_MASK, 0);
|
||||
regmap_write(lpass->top, SFR_LPASS_INTR_CA5_MASK, 0);
|
||||
|
||||
/* Deactivate related PADs from retention state */
|
||||
regmap_write(lpass->pmu, EXYNOS5433_PAD_RETENTION_AUD_OPTION, 0);
|
||||
}
|
||||
|
||||
static const struct regmap_config exynos_lpass_reg_conf = {
|
||||
.reg_bits = 32,
|
||||
.reg_stride = 4,
|
||||
.val_bits = 32,
|
||||
.max_register = 0xfc,
|
||||
.fast_io = true,
|
||||
};
|
||||
|
||||
static int exynos_lpass_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct exynos_lpass *lpass;
|
||||
void __iomem *base_top;
|
||||
struct resource *res;
|
||||
|
||||
lpass = devm_kzalloc(dev, sizeof(*lpass), GFP_KERNEL);
|
||||
if (!lpass)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
base_top = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(base_top))
|
||||
return PTR_ERR(base_top);
|
||||
|
||||
lpass->top = regmap_init_mmio(dev, base_top,
|
||||
&exynos_lpass_reg_conf);
|
||||
if (IS_ERR(lpass->top)) {
|
||||
dev_err(dev, "LPASS top regmap initialization failed\n");
|
||||
return PTR_ERR(lpass->top);
|
||||
}
|
||||
|
||||
lpass->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"samsung,pmu-syscon");
|
||||
if (IS_ERR(lpass->pmu)) {
|
||||
dev_err(dev, "Failed to lookup PMU regmap\n");
|
||||
return PTR_ERR(lpass->pmu);
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, lpass);
|
||||
exynos_lpass_enable(lpass);
|
||||
|
||||
return of_platform_populate(dev->of_node, NULL, NULL, dev);
|
||||
}
|
||||
|
||||
static int __maybe_unused exynos_lpass_suspend(struct device *dev)
|
||||
{
|
||||
struct exynos_lpass *lpass = dev_get_drvdata(dev);
|
||||
|
||||
exynos_lpass_disable(lpass);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused exynos_lpass_resume(struct device *dev)
|
||||
{
|
||||
struct exynos_lpass *lpass = dev_get_drvdata(dev);
|
||||
|
||||
exynos_lpass_enable(lpass);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(lpass_pm_ops, exynos_lpass_suspend,
|
||||
exynos_lpass_resume);
|
||||
|
||||
static const struct of_device_id exynos_lpass_of_match[] = {
|
||||
{ .compatible = "samsung,exynos5433-lpass" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_lpass_of_match);
|
||||
|
||||
static struct platform_driver exynos_lpass_driver = {
|
||||
.driver = {
|
||||
.name = "exynos-lpass",
|
||||
.pm = &lpass_pm_ops,
|
||||
.of_match_table = exynos_lpass_of_match,
|
||||
},
|
||||
.probe = exynos_lpass_probe,
|
||||
};
|
||||
module_platform_driver(exynos_lpass_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Samsung Low Power Audio Subsystem driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -52,6 +52,18 @@ static const struct intel_lpss_platform_info bxt_i2c_info = {
|
||||
.properties = bxt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry apl_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info apl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.properties = apl_i2c_properties,
|
||||
};
|
||||
|
||||
static const struct acpi_device_id intel_lpss_acpi_ids[] = {
|
||||
/* SPT */
|
||||
{ "INT3446", (kernel_ulong_t)&spt_i2c_info },
|
||||
@ -61,7 +73,7 @@ static const struct acpi_device_id intel_lpss_acpi_ids[] = {
|
||||
{ "80860ABC", (kernel_ulong_t)&bxt_info },
|
||||
{ "80860AC2", (kernel_ulong_t)&bxt_info },
|
||||
/* APL */
|
||||
{ "80865AAC", (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ "80865AAC", (kernel_ulong_t)&apl_i2c_info },
|
||||
{ "80865ABC", (kernel_ulong_t)&bxt_info },
|
||||
{ "80865AC2", (kernel_ulong_t)&bxt_info },
|
||||
{ }
|
||||
|
@ -111,6 +111,31 @@ static const struct intel_lpss_platform_info bxt_i2c_info = {
|
||||
.properties = bxt_i2c_properties,
|
||||
};
|
||||
|
||||
static struct property_entry apl_i2c_properties[] = {
|
||||
PROPERTY_ENTRY_U32("i2c-sda-hold-time-ns", 207),
|
||||
PROPERTY_ENTRY_U32("i2c-sda-falling-time-ns", 171),
|
||||
PROPERTY_ENTRY_U32("i2c-scl-falling-time-ns", 208),
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info apl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
.properties = apl_i2c_properties,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info kbl_info = {
|
||||
.clk_rate = 120000000,
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info kbl_uart_info = {
|
||||
.clk_rate = 120000000,
|
||||
.clk_con_id = "baudclk",
|
||||
};
|
||||
|
||||
static const struct intel_lpss_platform_info kbl_i2c_info = {
|
||||
.clk_rate = 133000000,
|
||||
};
|
||||
|
||||
static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||
/* BXT A-Step */
|
||||
{ PCI_VDEVICE(INTEL, 0x0aac), (kernel_ulong_t)&bxt_i2c_info },
|
||||
@ -146,14 +171,14 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0x1aee), (kernel_ulong_t)&bxt_uart_info },
|
||||
|
||||
/* APL */
|
||||
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&bxt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aac), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aae), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab0), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab2), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab4), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab6), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ab8), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5aba), (kernel_ulong_t)&apl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5abc), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5abe), (kernel_ulong_t)&bxt_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0x5ac0), (kernel_ulong_t)&bxt_uart_info },
|
||||
@ -181,6 +206,16 @@ static const struct pci_device_id intel_lpss_pci_ids[] = {
|
||||
{ PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info },
|
||||
/* KBL-H */
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a7), (kernel_ulong_t)&kbl_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a8), (kernel_ulong_t)&kbl_uart_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2a9), (kernel_ulong_t)&kbl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2aa), (kernel_ulong_t)&kbl_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e0), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e1), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e2), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e3), (kernel_ulong_t)&kbl_i2c_info },
|
||||
{ PCI_VDEVICE(INTEL, 0xa2e6), (kernel_ulong_t)&kbl_uart_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/intel_msic.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -449,9 +449,4 @@ static struct platform_driver intel_msic_driver = {
|
||||
.name = "intel_msic",
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(intel_msic_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for Intel MSIC");
|
||||
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
builtin_platform_driver(intel_msic_driver);
|
||||
|
@ -47,6 +47,8 @@
|
||||
#define BXTWC_MIRQLVL1 0x4E0E
|
||||
#define BXTWC_MPWRTNIRQ 0x4E0F
|
||||
|
||||
#define BXTWC_MIRQLVL1_MCHGR BIT(5)
|
||||
|
||||
#define BXTWC_MTHRM0IRQ 0x4E12
|
||||
#define BXTWC_MTHRM1IRQ 0x4E13
|
||||
#define BXTWC_MTHRM2IRQ 0x4E14
|
||||
@ -109,7 +111,7 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = {
|
||||
REGMAP_IRQ_REG(BXTWC_THRM2_IRQ, 2, 0xff),
|
||||
REGMAP_IRQ_REG(BXTWC_BCU_IRQ, 3, 0x1f),
|
||||
REGMAP_IRQ_REG(BXTWC_ADC_IRQ, 4, 0xff),
|
||||
REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x1f),
|
||||
REGMAP_IRQ_REG(BXTWC_CHGR0_IRQ, 5, 0x3f),
|
||||
REGMAP_IRQ_REG(BXTWC_CHGR1_IRQ, 6, 0x1f),
|
||||
REGMAP_IRQ_REG(BXTWC_GPIO0_IRQ, 7, 0xff),
|
||||
REGMAP_IRQ_REG(BXTWC_GPIO1_IRQ, 8, 0x3f),
|
||||
@ -143,6 +145,10 @@ static struct resource adc_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BXTWC_ADC_IRQ, "ADC"),
|
||||
};
|
||||
|
||||
static struct resource usbc_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "USBC"),
|
||||
};
|
||||
|
||||
static struct resource charger_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR0_IRQ, "CHARGER"),
|
||||
DEFINE_RES_IRQ_NAMED(BXTWC_CHGR1_IRQ, "CHARGER1"),
|
||||
@ -169,6 +175,11 @@ static struct mfd_cell bxt_wc_dev[] = {
|
||||
.num_resources = ARRAY_SIZE(thermal_resources),
|
||||
.resources = thermal_resources,
|
||||
},
|
||||
{
|
||||
.name = "bxt_wcove_usbc",
|
||||
.num_resources = ARRAY_SIZE(usbc_resources),
|
||||
.resources = usbc_resources,
|
||||
},
|
||||
{
|
||||
.name = "bxt_wcove_ext_charger",
|
||||
.num_resources = ARRAY_SIZE(charger_resources),
|
||||
@ -403,6 +414,16 @@ static int bxtwc_probe(struct platform_device *pdev)
|
||||
goto err_sysfs;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is known hw bug. Upon reset BIT 5 of register
|
||||
* BXTWC_CHGR_LVL1_IRQ is 0 which is the expected value. However,
|
||||
* later it's set to 1(masked) automatically by hardware. So we
|
||||
* have the software workaround here to unmaksed it in order to let
|
||||
* charger interrutp work.
|
||||
*/
|
||||
regmap_update_bits(pmic->regmap, BXTWC_MIRQLVL1,
|
||||
BXTWC_MIRQLVL1_MCHGR, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
err_sysfs:
|
||||
|
@ -53,8 +53,6 @@ static int lp873x_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_init(&lp873->lock);
|
||||
|
||||
ret = regmap_read(lp873->regmap, LP873X_REG_OTP_REV, &otpid);
|
||||
if (ret) {
|
||||
dev_err(lp873->dev, "Failed to read OTP ID\n");
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2014 Samsung Electronics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
* Krzysztof Kozlowski <krzk@kernel.org>
|
||||
*
|
||||
* 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
|
||||
@ -569,6 +569,6 @@ static void __exit max14577_i2c_exit(void)
|
||||
}
|
||||
module_exit(max14577_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <k.kozlowski@samsung.com>");
|
||||
MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>, Krzysztof Kozlowski <krzk@kernel.org>");
|
||||
MODULE_DESCRIPTION("Maxim 14577/77836 multi-function core driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -139,7 +139,7 @@ static void max8997_irq_sync_unlock(struct irq_data *data)
|
||||
mutex_unlock(&max8997->irqlock);
|
||||
}
|
||||
|
||||
static const inline struct max8997_irq_data *
|
||||
inline static const struct max8997_irq_data *
|
||||
irq_to_max8997_irq(struct max8997_dev *max8997, struct irq_data *data)
|
||||
{
|
||||
return &max8997_irqs[data->hwirq];
|
||||
|
@ -162,7 +162,7 @@ static const char * const port_modes[] = {
|
||||
* provided port mode string as per the port_modes table.
|
||||
* If no match is found it returns -ENODEV
|
||||
*/
|
||||
static const int omap_usbhs_get_dt_port_mode(const char *mode)
|
||||
static int omap_usbhs_get_dt_port_mode(const char *mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -309,6 +309,7 @@ static const struct regmap_config ssbi_regmap_config = {
|
||||
};
|
||||
|
||||
static const struct of_device_id pm8921_id_table[] = {
|
||||
{ .compatible = "qcom,pm8018", },
|
||||
{ .compatible = "qcom,pm8058", },
|
||||
{ .compatible = "qcom,pm8921", },
|
||||
{ }
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/mfd/qcom_rpm.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <dt-bindings/mfd/qcom-rpm.h>
|
||||
|
||||
@ -48,6 +49,7 @@ struct qcom_rpm {
|
||||
struct regmap *ipc_regmap;
|
||||
unsigned ipc_offset;
|
||||
unsigned ipc_bit;
|
||||
struct clk *ramclk;
|
||||
|
||||
struct completion ack;
|
||||
struct mutex lock;
|
||||
@ -388,11 +390,62 @@ static const struct qcom_rpm_data ipq806x_template = {
|
||||
.ack_sel_size = 7,
|
||||
};
|
||||
|
||||
static const struct qcom_rpm_resource mdm9615_rpm_resource_table[] = {
|
||||
[QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 },
|
||||
[QCOM_RPM_SYS_FABRIC_CLK] = { 26, 10, 9, 1 },
|
||||
[QCOM_RPM_DAYTONA_FABRIC_CLK] = { 27, 11, 11, 1 },
|
||||
[QCOM_RPM_SFPB_CLK] = { 28, 12, 12, 1 },
|
||||
[QCOM_RPM_CFPB_CLK] = { 29, 13, 13, 1 },
|
||||
[QCOM_RPM_EBI1_CLK] = { 30, 14, 16, 1 },
|
||||
[QCOM_RPM_APPS_FABRIC_HALT] = { 31, 15, 22, 2 },
|
||||
[QCOM_RPM_APPS_FABRIC_MODE] = { 33, 16, 23, 3 },
|
||||
[QCOM_RPM_APPS_FABRIC_IOCTL] = { 36, 17, 24, 1 },
|
||||
[QCOM_RPM_APPS_FABRIC_ARB] = { 37, 18, 25, 27 },
|
||||
[QCOM_RPM_PM8018_SMPS1] = { 64, 19, 30, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS2] = { 66, 21, 31, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS3] = { 68, 23, 32, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS4] = { 70, 25, 33, 2 },
|
||||
[QCOM_RPM_PM8018_SMPS5] = { 72, 27, 34, 2 },
|
||||
[QCOM_RPM_PM8018_LDO1] = { 74, 29, 35, 2 },
|
||||
[QCOM_RPM_PM8018_LDO2] = { 76, 31, 36, 2 },
|
||||
[QCOM_RPM_PM8018_LDO3] = { 78, 33, 37, 2 },
|
||||
[QCOM_RPM_PM8018_LDO4] = { 80, 35, 38, 2 },
|
||||
[QCOM_RPM_PM8018_LDO5] = { 82, 37, 39, 2 },
|
||||
[QCOM_RPM_PM8018_LDO6] = { 84, 39, 40, 2 },
|
||||
[QCOM_RPM_PM8018_LDO7] = { 86, 41, 41, 2 },
|
||||
[QCOM_RPM_PM8018_LDO8] = { 88, 43, 42, 2 },
|
||||
[QCOM_RPM_PM8018_LDO9] = { 90, 45, 43, 2 },
|
||||
[QCOM_RPM_PM8018_LDO10] = { 92, 47, 44, 2 },
|
||||
[QCOM_RPM_PM8018_LDO11] = { 94, 49, 45, 2 },
|
||||
[QCOM_RPM_PM8018_LDO12] = { 96, 51, 46, 2 },
|
||||
[QCOM_RPM_PM8018_LDO13] = { 98, 53, 47, 2 },
|
||||
[QCOM_RPM_PM8018_LDO14] = { 100, 55, 48, 2 },
|
||||
[QCOM_RPM_PM8018_LVS1] = { 102, 57, 49, 1 },
|
||||
[QCOM_RPM_PM8018_NCP] = { 103, 58, 80, 2 },
|
||||
[QCOM_RPM_CXO_BUFFERS] = { 105, 60, 81, 1 },
|
||||
[QCOM_RPM_USB_OTG_SWITCH] = { 106, 61, 82, 1 },
|
||||
[QCOM_RPM_HDMI_SWITCH] = { 107, 62, 83, 1 },
|
||||
[QCOM_RPM_VOLTAGE_CORNER] = { 109, 64, 87, 1 },
|
||||
};
|
||||
|
||||
static const struct qcom_rpm_data mdm9615_template = {
|
||||
.version = 3,
|
||||
.resource_table = mdm9615_rpm_resource_table,
|
||||
.n_resources = ARRAY_SIZE(mdm9615_rpm_resource_table),
|
||||
.req_ctx_off = 3,
|
||||
.req_sel_off = 11,
|
||||
.ack_ctx_off = 15,
|
||||
.ack_sel_off = 23,
|
||||
.req_sel_size = 4,
|
||||
.ack_sel_size = 7,
|
||||
};
|
||||
|
||||
static const struct of_device_id qcom_rpm_of_match[] = {
|
||||
{ .compatible = "qcom,rpm-apq8064", .data = &apq8064_template },
|
||||
{ .compatible = "qcom,rpm-msm8660", .data = &msm8660_template },
|
||||
{ .compatible = "qcom,rpm-msm8960", .data = &msm8960_template },
|
||||
{ .compatible = "qcom,rpm-ipq8064", .data = &ipq806x_template },
|
||||
{ .compatible = "qcom,rpm-mdm9615", .data = &mdm9615_template },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_rpm_of_match);
|
||||
@ -501,6 +554,20 @@ static int qcom_rpm_probe(struct platform_device *pdev)
|
||||
mutex_init(&rpm->lock);
|
||||
init_completion(&rpm->ack);
|
||||
|
||||
/* Enable message RAM clock */
|
||||
rpm->ramclk = devm_clk_get(&pdev->dev, "ram");
|
||||
if (IS_ERR(rpm->ramclk)) {
|
||||
ret = PTR_ERR(rpm->ramclk);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
/*
|
||||
* Fall through in all other cases, as the clock is
|
||||
* optional. (Does not exist on all platforms.)
|
||||
*/
|
||||
rpm->ramclk = NULL;
|
||||
}
|
||||
clk_prepare_enable(rpm->ramclk); /* Accepts NULL */
|
||||
|
||||
irq_ack = platform_get_irq_byname(pdev, "ack");
|
||||
if (irq_ack < 0) {
|
||||
dev_err(&pdev->dev, "required ack interrupt missing\n");
|
||||
@ -538,6 +605,7 @@ static int qcom_rpm_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
rpm->ipc_regmap = syscon_node_to_regmap(syscon_np);
|
||||
of_node_put(syscon_np);
|
||||
if (IS_ERR(rpm->ipc_regmap))
|
||||
return PTR_ERR(rpm->ipc_regmap);
|
||||
|
||||
@ -620,7 +688,11 @@ static int qcom_rpm_probe(struct platform_device *pdev)
|
||||
|
||||
static int qcom_rpm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct qcom_rpm *rpm = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
clk_disable_unprepare(rpm->ramclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,15 @@
|
||||
/*
|
||||
* MFD core driver for Rockchip RK808
|
||||
* MFD core driver for Rockchip RK808/RK818
|
||||
*
|
||||
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* Author: Chris Zhong <zyw@rock-chips.com>
|
||||
* Author: Zhang Qing <zhangqing@rock-chips.com>
|
||||
*
|
||||
* Copyright (C) 2016 PHYTEC Messtechnik GmbH
|
||||
*
|
||||
* Author: Wadim Egorov <w.egorov@phytec.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
@ -21,6 +25,7 @@
|
||||
#include <linux/mfd/rk808.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct rk808_reg_data {
|
||||
@ -57,6 +62,14 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const struct regmap_config rk818_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = RK818_USB_CTRL_REG,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.volatile_reg = rk808_is_volatile_reg,
|
||||
};
|
||||
|
||||
static const struct regmap_config rk808_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
@ -79,11 +92,21 @@ static const struct mfd_cell rk808s[] = {
|
||||
{
|
||||
.name = "rk808-rtc",
|
||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||
.resources = &rtc_resources[0],
|
||||
.resources = rtc_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rk808_reg_data pre_init_reg[] = {
|
||||
static const struct mfd_cell rk818s[] = {
|
||||
{ .name = "rk808-clkout", },
|
||||
{ .name = "rk808-regulator", },
|
||||
{
|
||||
.name = "rk808-rtc",
|
||||
.num_resources = ARRAY_SIZE(rtc_resources),
|
||||
.resources = rtc_resources,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rk808_reg_data rk808_pre_init_reg[] = {
|
||||
{ RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA },
|
||||
{ RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA },
|
||||
{ RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
|
||||
@ -94,6 +117,24 @@ static const struct rk808_reg_data pre_init_reg[] = {
|
||||
VB_LO_SEL_3500MV },
|
||||
};
|
||||
|
||||
static const struct rk808_reg_data rk818_pre_init_reg[] = {
|
||||
/* improve efficiency */
|
||||
{ RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_250MA },
|
||||
{ RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_250MA },
|
||||
{ RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
|
||||
{ RK818_USB_CTRL_REG, RK818_USB_ILIM_SEL_MASK,
|
||||
RK818_USB_ILMIN_2000MA },
|
||||
/* close charger when usb lower then 3.4V */
|
||||
{ RK818_USB_CTRL_REG, RK818_USB_CHG_SD_VSEL_MASK,
|
||||
(0x7 << 4) },
|
||||
/* no action when vref */
|
||||
{ RK818_H5V_EN_REG, BIT(1), RK818_REF_RDY_CTRL },
|
||||
/* enable HDMI 5V */
|
||||
{ RK818_H5V_EN_REG, BIT(0), RK818_H5V_EN },
|
||||
{ RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT |
|
||||
VB_LO_SEL_3500MV },
|
||||
};
|
||||
|
||||
static const struct regmap_irq rk808_irqs[] = {
|
||||
/* INT_STS */
|
||||
[RK808_IRQ_VOUT_LO] = {
|
||||
@ -136,6 +177,76 @@ static const struct regmap_irq rk808_irqs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct regmap_irq rk818_irqs[] = {
|
||||
/* INT_STS */
|
||||
[RK818_IRQ_VOUT_LO] = {
|
||||
.mask = RK818_IRQ_VOUT_LO_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
[RK818_IRQ_VB_LO] = {
|
||||
.mask = RK818_IRQ_VB_LO_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
[RK818_IRQ_PWRON] = {
|
||||
.mask = RK818_IRQ_PWRON_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
[RK818_IRQ_PWRON_LP] = {
|
||||
.mask = RK818_IRQ_PWRON_LP_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
[RK818_IRQ_HOTDIE] = {
|
||||
.mask = RK818_IRQ_HOTDIE_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
[RK818_IRQ_RTC_ALARM] = {
|
||||
.mask = RK818_IRQ_RTC_ALARM_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
[RK818_IRQ_RTC_PERIOD] = {
|
||||
.mask = RK818_IRQ_RTC_PERIOD_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
[RK818_IRQ_USB_OV] = {
|
||||
.mask = RK818_IRQ_USB_OV_MSK,
|
||||
.reg_offset = 0,
|
||||
},
|
||||
|
||||
/* INT_STS2 */
|
||||
[RK818_IRQ_PLUG_IN] = {
|
||||
.mask = RK818_IRQ_PLUG_IN_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
[RK818_IRQ_PLUG_OUT] = {
|
||||
.mask = RK818_IRQ_PLUG_OUT_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
[RK818_IRQ_CHG_OK] = {
|
||||
.mask = RK818_IRQ_CHG_OK_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
[RK818_IRQ_CHG_TE] = {
|
||||
.mask = RK818_IRQ_CHG_TE_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
[RK818_IRQ_CHG_TS1] = {
|
||||
.mask = RK818_IRQ_CHG_TS1_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
[RK818_IRQ_TS2] = {
|
||||
.mask = RK818_IRQ_TS2_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
[RK818_IRQ_CHG_CVTLIM] = {
|
||||
.mask = RK818_IRQ_CHG_CVTLIM_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
[RK818_IRQ_DISCHG_ILIM] = {
|
||||
.mask = RK818_IRQ_DISCHG_ILIM_MSK,
|
||||
.reg_offset = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip rk808_irq_chip = {
|
||||
.name = "rk808",
|
||||
.irqs = rk808_irqs,
|
||||
@ -148,6 +259,18 @@ static struct regmap_irq_chip rk808_irq_chip = {
|
||||
.init_ack_masked = true,
|
||||
};
|
||||
|
||||
static struct regmap_irq_chip rk818_irq_chip = {
|
||||
.name = "rk818",
|
||||
.irqs = rk818_irqs,
|
||||
.num_irqs = ARRAY_SIZE(rk818_irqs),
|
||||
.num_regs = 2,
|
||||
.irq_reg_stride = 2,
|
||||
.status_base = RK818_INT_STS_REG1,
|
||||
.mask_base = RK818_INT_STS_MSK_REG1,
|
||||
.ack_base = RK818_INT_STS_REG1,
|
||||
.init_ack_masked = true,
|
||||
};
|
||||
|
||||
static struct i2c_client *rk808_i2c_client;
|
||||
static void rk808_device_shutdown(void)
|
||||
{
|
||||
@ -167,54 +290,99 @@ static void rk808_device_shutdown(void)
|
||||
dev_err(&rk808_i2c_client->dev, "power off error!\n");
|
||||
}
|
||||
|
||||
static const struct of_device_id rk808_of_match[] = {
|
||||
{ .compatible = "rockchip,rk808" },
|
||||
{ .compatible = "rockchip,rk818" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk808_of_match);
|
||||
|
||||
static int rk808_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device_node *np = client->dev.of_node;
|
||||
struct rk808 *rk808;
|
||||
const struct rk808_reg_data *pre_init_reg;
|
||||
const struct mfd_cell *cells;
|
||||
int nr_pre_init_regs;
|
||||
int nr_cells;
|
||||
int pm_off = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
|
||||
if (!rk808)
|
||||
return -ENOMEM;
|
||||
|
||||
rk808->variant = i2c_smbus_read_word_data(client, RK808_ID_MSB);
|
||||
if (rk808->variant < 0) {
|
||||
dev_err(&client->dev, "Failed to read the chip id at 0x%02x\n",
|
||||
RK808_ID_MSB);
|
||||
return rk808->variant;
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev, "Chip id: 0x%x\n", (unsigned int)rk808->variant);
|
||||
|
||||
switch (rk808->variant) {
|
||||
case RK808_ID:
|
||||
rk808->regmap_cfg = &rk808_regmap_config;
|
||||
rk808->regmap_irq_chip = &rk808_irq_chip;
|
||||
pre_init_reg = rk808_pre_init_reg;
|
||||
nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
|
||||
cells = rk808s;
|
||||
nr_cells = ARRAY_SIZE(rk808s);
|
||||
break;
|
||||
case RK818_ID:
|
||||
rk808->regmap_cfg = &rk818_regmap_config;
|
||||
rk808->regmap_irq_chip = &rk818_irq_chip;
|
||||
pre_init_reg = rk818_pre_init_reg;
|
||||
nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
|
||||
cells = rk818s;
|
||||
nr_cells = ARRAY_SIZE(rk818s);
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "Unsupported RK8XX ID %lu\n",
|
||||
rk808->variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rk808->i2c = client;
|
||||
i2c_set_clientdata(client, rk808);
|
||||
|
||||
rk808->regmap = devm_regmap_init_i2c(client, rk808->regmap_cfg);
|
||||
if (IS_ERR(rk808->regmap)) {
|
||||
dev_err(&client->dev, "regmap initialization failed\n");
|
||||
return PTR_ERR(rk808->regmap);
|
||||
}
|
||||
|
||||
if (!client->irq) {
|
||||
dev_err(&client->dev, "No interrupt support, no core IRQ\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
|
||||
if (!rk808)
|
||||
return -ENOMEM;
|
||||
|
||||
rk808->regmap = devm_regmap_init_i2c(client, &rk808_regmap_config);
|
||||
if (IS_ERR(rk808->regmap)) {
|
||||
dev_err(&client->dev, "regmap initialization failed\n");
|
||||
return PTR_ERR(rk808->regmap);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pre_init_reg); i++) {
|
||||
ret = regmap_update_bits(rk808->regmap, pre_init_reg[i].addr,
|
||||
pre_init_reg[i].mask,
|
||||
pre_init_reg[i].value);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"0x%x write err\n", pre_init_reg[i].addr);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_add_irq_chip(rk808->regmap, client->irq,
|
||||
IRQF_ONESHOT, -1,
|
||||
&rk808_irq_chip, &rk808->irq_data);
|
||||
rk808->regmap_irq_chip, &rk808->irq_data);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rk808->i2c = client;
|
||||
i2c_set_clientdata(client, rk808);
|
||||
for (i = 0; i < nr_pre_init_regs; i++) {
|
||||
ret = regmap_update_bits(rk808->regmap,
|
||||
pre_init_reg[i].addr,
|
||||
pre_init_reg[i].mask,
|
||||
pre_init_reg[i].value);
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"0x%x write err\n",
|
||||
pre_init_reg[i].addr);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(&client->dev, -1,
|
||||
rk808s, ARRAY_SIZE(rk808s), NULL, 0,
|
||||
ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
|
||||
cells, nr_cells, NULL, 0,
|
||||
regmap_irq_get_domain(rk808->irq_data));
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
|
||||
@ -245,14 +413,9 @@ static int rk808_remove(struct i2c_client *client)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rk808_of_match[] = {
|
||||
{ .compatible = "rockchip,rk808" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rk808_of_match);
|
||||
|
||||
static const struct i2c_device_id rk808_ids[] = {
|
||||
{ "rk808" },
|
||||
{ "rk818" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rk808_ids);
|
||||
@ -272,4 +435,5 @@ module_i2c_driver(rk808_i2c_driver);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
|
||||
MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("RK808 PMIC driver");
|
||||
MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
|
||||
MODULE_DESCRIPTION("RK808/RK818 PMIC driver");
|
||||
|
@ -46,9 +46,6 @@ static void rtsx_usb_sg_timed_out(unsigned long data)
|
||||
|
||||
dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
|
||||
usb_sg_cancel(&ucr->current_sg);
|
||||
|
||||
/* we know the cancellation is caused by time-out */
|
||||
ucr->current_sg.status = -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
|
||||
@ -67,12 +64,15 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
|
||||
ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
|
||||
add_timer(&ucr->sg_timer);
|
||||
usb_sg_wait(&ucr->current_sg);
|
||||
del_timer_sync(&ucr->sg_timer);
|
||||
if (!del_timer_sync(&ucr->sg_timer))
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
ret = ucr->current_sg.status;
|
||||
|
||||
if (act_len)
|
||||
*act_len = ucr->current_sg.bytes;
|
||||
|
||||
return ucr->current_sg.status;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
|
||||
|
@ -1001,7 +1001,7 @@ static int sm501_gpio_output(struct gpio_chip *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct gpio_chip gpio_chip_template = {
|
||||
static const struct gpio_chip gpio_chip_template = {
|
||||
.ngpio = 32,
|
||||
.direction_input = sm501_gpio_input,
|
||||
.direction_output = sm501_gpio_output,
|
||||
|
@ -11,8 +11,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -81,7 +80,6 @@ static const struct i2c_device_id smsc_i2c_id[] = {
|
||||
{ "smscece1099", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, smsc_i2c_id);
|
||||
|
||||
static struct i2c_driver smsc_i2c_driver = {
|
||||
.driver = {
|
||||
@ -90,9 +88,4 @@ static struct i2c_driver smsc_i2c_driver = {
|
||||
.probe = smsc_i2c_probe,
|
||||
.id_table = smsc_i2c_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(smsc_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
|
||||
MODULE_DESCRIPTION("SMSC chip multi-function driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
builtin_i2c_driver(smsc_i2c_driver);
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
struct prcm_data {
|
||||
@ -170,8 +170,4 @@ static struct platform_driver sun6i_prcm_driver = {
|
||||
},
|
||||
.probe = sun6i_prcm_probe,
|
||||
};
|
||||
module_platform_driver(sun6i_prcm_driver);
|
||||
|
||||
MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>");
|
||||
MODULE_DESCRIPTION("Allwinner sun6i PRCM driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
builtin_platform_driver(sun6i_prcm_driver);
|
||||
|
@ -15,22 +15,103 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/tps65217.h>
|
||||
|
||||
static const struct mfd_cell tps65217s[] = {
|
||||
static struct resource charger_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_AC, "AC"),
|
||||
DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_USB, "USB"),
|
||||
};
|
||||
|
||||
static struct resource pb_resources[] = {
|
||||
DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"),
|
||||
};
|
||||
|
||||
struct tps65217_irq {
|
||||
int mask;
|
||||
int interrupt;
|
||||
};
|
||||
|
||||
static const struct tps65217_irq tps65217_irqs[] = {
|
||||
[TPS65217_IRQ_PB] = {
|
||||
.mask = TPS65217_INT_PBM,
|
||||
.interrupt = TPS65217_INT_PBI,
|
||||
},
|
||||
[TPS65217_IRQ_AC] = {
|
||||
.mask = TPS65217_INT_ACM,
|
||||
.interrupt = TPS65217_INT_ACI,
|
||||
},
|
||||
[TPS65217_IRQ_USB] = {
|
||||
.mask = TPS65217_INT_USBM,
|
||||
.interrupt = TPS65217_INT_USBI,
|
||||
},
|
||||
};
|
||||
|
||||
static void tps65217_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
|
||||
mutex_lock(&tps->irq_lock);
|
||||
}
|
||||
|
||||
static void tps65217_irq_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
int ret;
|
||||
|
||||
ret = tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
|
||||
TPS65217_PROTECT_NONE);
|
||||
if (ret != 0)
|
||||
dev_err(tps->dev, "Failed to sync IRQ masks\n");
|
||||
|
||||
mutex_unlock(&tps->irq_lock);
|
||||
}
|
||||
|
||||
static inline const struct tps65217_irq *
|
||||
irq_to_tps65217_irq(struct tps65217 *tps, struct irq_data *data)
|
||||
{
|
||||
return &tps65217_irqs[data->hwirq];
|
||||
}
|
||||
|
||||
static void tps65217_irq_enable(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
|
||||
|
||||
tps->irq_mask &= ~irq_data->mask;
|
||||
}
|
||||
|
||||
static void tps65217_irq_disable(struct irq_data *data)
|
||||
{
|
||||
struct tps65217 *tps = irq_data_get_irq_chip_data(data);
|
||||
const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data);
|
||||
|
||||
tps->irq_mask |= irq_data->mask;
|
||||
}
|
||||
|
||||
static struct irq_chip tps65217_irq_chip = {
|
||||
.irq_bus_lock = tps65217_irq_lock,
|
||||
.irq_bus_sync_unlock = tps65217_irq_sync_unlock,
|
||||
.irq_enable = tps65217_irq_enable,
|
||||
.irq_disable = tps65217_irq_disable,
|
||||
};
|
||||
|
||||
static struct mfd_cell tps65217s[] = {
|
||||
{
|
||||
.name = "tps65217-pmic",
|
||||
.of_compatible = "ti,tps65217-pmic",
|
||||
@ -41,10 +122,96 @@ static const struct mfd_cell tps65217s[] = {
|
||||
},
|
||||
{
|
||||
.name = "tps65217-charger",
|
||||
.num_resources = ARRAY_SIZE(charger_resources),
|
||||
.resources = charger_resources,
|
||||
.of_compatible = "ti,tps65217-charger",
|
||||
},
|
||||
{
|
||||
.name = "tps65217-pwrbutton",
|
||||
.num_resources = ARRAY_SIZE(pb_resources),
|
||||
.resources = pb_resources,
|
||||
.of_compatible = "ti,tps65217-pwrbutton",
|
||||
},
|
||||
};
|
||||
|
||||
static irqreturn_t tps65217_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct tps65217 *tps = data;
|
||||
unsigned int status;
|
||||
bool handled = false;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
ret = tps65217_reg_read(tps, TPS65217_REG_INT, &status);
|
||||
if (ret < 0) {
|
||||
dev_err(tps->dev, "Failed to read IRQ status: %d\n",
|
||||
ret);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) {
|
||||
if (status & tps65217_irqs[i].interrupt) {
|
||||
handle_nested_irq(irq_find_mapping(tps->irq_domain, i));
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (handled)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int tps65217_irq_map(struct irq_domain *h, unsigned int virq,
|
||||
irq_hw_number_t hw)
|
||||
{
|
||||
struct tps65217 *tps = h->host_data;
|
||||
|
||||
irq_set_chip_data(virq, tps);
|
||||
irq_set_chip_and_handler(virq, &tps65217_irq_chip, handle_edge_irq);
|
||||
irq_set_nested_thread(virq, 1);
|
||||
irq_set_parent(virq, tps->irq);
|
||||
irq_set_noprobe(virq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct irq_domain_ops tps65217_irq_domain_ops = {
|
||||
.map = tps65217_irq_map,
|
||||
};
|
||||
|
||||
static int tps65217_irq_init(struct tps65217 *tps, int irq)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_init(&tps->irq_lock);
|
||||
tps->irq = irq;
|
||||
|
||||
/* Mask all interrupt sources */
|
||||
tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM
|
||||
| TPS65217_INT_ACM | TPS65217_INT_USBM);
|
||||
tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask,
|
||||
TPS65217_PROTECT_NONE);
|
||||
|
||||
tps->irq_domain = irq_domain_add_linear(tps->dev->of_node,
|
||||
TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps);
|
||||
if (!tps->irq_domain) {
|
||||
dev_err(tps->dev, "Could not create IRQ domain\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(tps->dev, irq, NULL,
|
||||
tps65217_irq_thread, IRQF_ONESHOT,
|
||||
"tps65217-irq", tps);
|
||||
if (ret) {
|
||||
dev_err(tps->dev, "Failed to request IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tps65217_reg_read: Read a single tps65217 register.
|
||||
*
|
||||
@ -149,11 +316,22 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
|
||||
|
||||
static bool tps65217_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case TPS65217_REG_INT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config tps65217_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = TPS65217_REG_MAX,
|
||||
.volatile_reg = tps65217_volatile_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id tps65217_of_match[] = {
|
||||
@ -205,8 +383,19 @@ static int tps65217_probe(struct i2c_client *client,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (client->irq) {
|
||||
tps65217_irq_init(tps, client->irq);
|
||||
} else {
|
||||
int i;
|
||||
|
||||
/* Don't tell children about IRQ resources which won't fire */
|
||||
for (i = 0; i < ARRAY_SIZE(tps65217s); i++)
|
||||
tps65217s[i].num_resources = 0;
|
||||
}
|
||||
|
||||
ret = devm_mfd_add_devices(tps->dev, -1, tps65217s,
|
||||
ARRAY_SIZE(tps65217s), NULL, 0, NULL);
|
||||
ARRAY_SIZE(tps65217s), NULL, 0,
|
||||
tps->irq_domain);
|
||||
if (ret < 0) {
|
||||
dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -30,7 +30,6 @@
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
@ -1258,7 +1257,6 @@ static const struct i2c_device_id twl_ids[] = {
|
||||
{ "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, twl_ids);
|
||||
|
||||
/* One Client Driver , 4 Clients */
|
||||
static struct i2c_driver twl_driver = {
|
||||
@ -1267,9 +1265,4 @@ static struct i2c_driver twl_driver = {
|
||||
.probe = twl_probe,
|
||||
.remove = twl_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(twl_driver);
|
||||
|
||||
MODULE_AUTHOR("Texas Instruments, Inc.");
|
||||
MODULE_DESCRIPTION("I2C Core interface for TWL");
|
||||
MODULE_LICENSE("GPL");
|
||||
builtin_i2c_driver(twl_driver);
|
||||
|
@ -609,6 +609,7 @@ static const struct regmap_config twl6040_regmap_config = {
|
||||
.writeable_reg = twl6040_writeable_reg,
|
||||
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
.use_single_rw = true,
|
||||
};
|
||||
|
||||
static const struct regmap_irq twl6040_irqs[] = {
|
||||
@ -782,6 +783,11 @@ static int twl6040_probe(struct i2c_client *client,
|
||||
cell->name = "twl6040-gpo";
|
||||
children++;
|
||||
|
||||
/* PDM clock support */
|
||||
cell = &twl6040->cells[children];
|
||||
cell->name = "twl6040-pdmclk";
|
||||
children++;
|
||||
|
||||
/* The chip is powered down so mark regmap to cache only and dirty */
|
||||
regcache_cache_only(twl6040->regmap, true);
|
||||
regcache_mark_dirty(twl6040->regmap);
|
||||
|
@ -446,10 +446,6 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
|
||||
unsigned long mask;
|
||||
|
||||
mask = probe_irq_on();
|
||||
if (!mask) {
|
||||
probe_irq_off(mask);
|
||||
return NO_IRQ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the ADC interrupt.
|
||||
@ -541,7 +537,7 @@ static int ucb1x00_probe(struct mcp *mcp)
|
||||
ucb1x00_enable(ucb);
|
||||
ucb->irq = ucb1x00_detect_irq(ucb);
|
||||
ucb1x00_disable(ucb);
|
||||
if (ucb->irq == NO_IRQ) {
|
||||
if (!ucb->irq) {
|
||||
dev_err(&ucb->dev, "IRQ probe failed\n");
|
||||
ret = -ENODEV;
|
||||
goto err_no_irq;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define EC_COMMAND_RETRIES 50
|
||||
|
||||
@ -234,11 +235,44 @@ static int cros_ec_host_command_proto_query_v2(struct cros_ec_device *ec_dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cros_ec_get_host_command_version_mask(struct cros_ec_device *ec_dev,
|
||||
u16 cmd, u32 *mask)
|
||||
{
|
||||
struct ec_params_get_cmd_versions *pver;
|
||||
struct ec_response_get_cmd_versions *rver;
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
|
||||
msg = kmalloc(sizeof(*msg) + max(sizeof(*rver), sizeof(*pver)),
|
||||
GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_GET_CMD_VERSIONS;
|
||||
msg->insize = sizeof(*rver);
|
||||
msg->outsize = sizeof(*pver);
|
||||
|
||||
pver = (struct ec_params_get_cmd_versions *)msg->data;
|
||||
pver->cmd = cmd;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec_dev, msg);
|
||||
if (ret > 0) {
|
||||
rver = (struct ec_response_get_cmd_versions *)msg->data;
|
||||
*mask = rver->version_mask;
|
||||
}
|
||||
|
||||
kfree(msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int cros_ec_query_all(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
struct device *dev = ec_dev->dev;
|
||||
struct cros_ec_command *proto_msg;
|
||||
struct ec_response_get_protocol_info *proto_info;
|
||||
u32 ver_mask = 0;
|
||||
int ret;
|
||||
|
||||
proto_msg = kzalloc(sizeof(*proto_msg) + sizeof(*proto_info),
|
||||
@ -328,6 +362,15 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Probe if MKBP event is supported */
|
||||
ret = cros_ec_get_host_command_version_mask(ec_dev,
|
||||
EC_CMD_GET_NEXT_EVENT,
|
||||
&ver_mask);
|
||||
if (ret < 0 || ver_mask == 0)
|
||||
ec_dev->mkbp_event_supported = 0;
|
||||
else
|
||||
ec_dev->mkbp_event_supported = 1;
|
||||
|
||||
exit:
|
||||
kfree(proto_msg);
|
||||
return ret;
|
||||
@ -397,3 +440,52 @@ int cros_ec_cmd_xfer_status(struct cros_ec_device *ec_dev,
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_cmd_xfer_status);
|
||||
|
||||
static int get_next_event(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
u8 buffer[sizeof(struct cros_ec_command) + sizeof(ec_dev->event_data)];
|
||||
struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
|
||||
int ret;
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_GET_NEXT_EVENT;
|
||||
msg->insize = sizeof(ec_dev->event_data);
|
||||
msg->outsize = 0;
|
||||
|
||||
ret = cros_ec_cmd_xfer(ec_dev, msg);
|
||||
if (ret > 0) {
|
||||
ec_dev->event_size = ret - 1;
|
||||
memcpy(&ec_dev->event_data, msg->data,
|
||||
sizeof(ec_dev->event_data));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_keyboard_state_event(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
u8 buffer[sizeof(struct cros_ec_command) +
|
||||
sizeof(ec_dev->event_data.data)];
|
||||
struct cros_ec_command *msg = (struct cros_ec_command *)&buffer;
|
||||
|
||||
msg->version = 0;
|
||||
msg->command = EC_CMD_MKBP_STATE;
|
||||
msg->insize = sizeof(ec_dev->event_data.data);
|
||||
msg->outsize = 0;
|
||||
|
||||
ec_dev->event_size = cros_ec_cmd_xfer(ec_dev, msg);
|
||||
ec_dev->event_data.event_type = EC_MKBP_EVENT_KEY_MATRIX;
|
||||
memcpy(&ec_dev->event_data.data, msg->data,
|
||||
sizeof(ec_dev->event_data.data));
|
||||
|
||||
return ec_dev->event_size;
|
||||
}
|
||||
|
||||
int cros_ec_get_next_event(struct cros_ec_device *ec_dev)
|
||||
{
|
||||
if (ec_dev->mkbp_event_supported)
|
||||
return get_next_event(ec_dev);
|
||||
else
|
||||
return get_keyboard_state_event(ec_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(cros_ec_get_next_event);
|
||||
|
@ -643,11 +643,11 @@ config REGULATOR_RC5T583
|
||||
outputs which can be controlled by i2c communication.
|
||||
|
||||
config REGULATOR_RK808
|
||||
tristate "Rockchip RK808 Power regulators"
|
||||
tristate "Rockchip RK808/RK818 Power regulators"
|
||||
depends on MFD_RK808
|
||||
help
|
||||
Select this option to enable the power regulator of ROCKCHIP
|
||||
PMIC RK808.
|
||||
PMIC RK808 and RK818.
|
||||
This driver supports the control of different power rails of device
|
||||
through regulator interface. The device supports multiple DCDC/LDO
|
||||
outputs which can be controlled by i2c communication.
|
||||
|
@ -244,16 +244,64 @@ static const struct regulator_desc axp22x_drivevbus_regulator = {
|
||||
.ops = &axp20x_ops_sw,
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range axp806_dcdca_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(600000, 0x0, 0x32, 10000),
|
||||
REGULATOR_LINEAR_RANGE(1120000, 0x33, 0x47, 20000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range axp806_dcdcd_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2d, 20000),
|
||||
REGULATOR_LINEAR_RANGE(1600000, 0x2e, 0x3f, 100000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range axp806_cldo2_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000),
|
||||
REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000),
|
||||
};
|
||||
|
||||
static const struct regulator_desc axp806_regulators[] = {
|
||||
AXP_DESC_RANGES(AXP806, DCDCA, "dcdca", "vina", axp806_dcdca_ranges,
|
||||
72, AXP806_DCDCA_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
|
||||
BIT(0)),
|
||||
AXP_DESC(AXP806, DCDCB, "dcdcb", "vinb", 1000, 2550, 50,
|
||||
AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(1)),
|
||||
AXP_DESC_RANGES(AXP806, DCDCC, "dcdcc", "vinc", axp806_dcdca_ranges,
|
||||
72, AXP806_DCDCC_V_CTRL, 0x7f, AXP806_PWR_OUT_CTRL1,
|
||||
BIT(2)),
|
||||
AXP_DESC_RANGES(AXP806, DCDCD, "dcdcd", "vind", axp806_dcdcd_ranges,
|
||||
64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1,
|
||||
BIT(3)),
|
||||
AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100,
|
||||
AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
|
||||
AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
|
||||
AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)),
|
||||
AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100,
|
||||
AXP806_ALDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(6)),
|
||||
AXP_DESC(AXP806, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
|
||||
AXP806_ALDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(7)),
|
||||
AXP_DESC(AXP806, BLDO1, "bldo1", "bldoin", 700, 1900, 100,
|
||||
AXP806_BLDO1_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(0)),
|
||||
AXP_DESC(AXP806, BLDO2, "bldo2", "bldoin", 700, 1900, 100,
|
||||
AXP806_BLDO2_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(1)),
|
||||
AXP_DESC(AXP806, BLDO3, "bldo3", "bldoin", 700, 1900, 100,
|
||||
AXP806_BLDO3_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(2)),
|
||||
AXP_DESC(AXP806, BLDO4, "bldo4", "bldoin", 700, 1900, 100,
|
||||
AXP806_BLDO4_V_CTRL, 0x0f, AXP806_PWR_OUT_CTRL2, BIT(3)),
|
||||
AXP_DESC(AXP806, CLDO1, "cldo1", "cldoin", 700, 3300, 100,
|
||||
AXP806_CLDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(4)),
|
||||
AXP_DESC_RANGES(AXP806, CLDO2, "cldo2", "cldoin", axp806_cldo2_ranges,
|
||||
32, AXP806_CLDO2_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2,
|
||||
BIT(5)),
|
||||
AXP_DESC(AXP806, CLDO3, "cldo3", "cldoin", 700, 3300, 100,
|
||||
AXP806_CLDO3_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL2, BIT(6)),
|
||||
AXP_DESC_SW(AXP806, SW, "sw", "swin", AXP806_PWR_OUT_CTRL2, BIT(7)),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range axp809_dcdc4_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(600000, 0x0, 0x2f, 20000),
|
||||
REGULATOR_LINEAR_RANGE(1800000, 0x30, 0x38, 100000),
|
||||
};
|
||||
|
||||
static const struct regulator_linear_range axp809_dldo1_ranges[] = {
|
||||
REGULATOR_LINEAR_RANGE(700000, 0x0, 0x1a, 100000),
|
||||
REGULATOR_LINEAR_RANGE(3400000, 0x1b, 0x1f, 200000),
|
||||
};
|
||||
|
||||
static const struct regulator_desc axp809_regulators[] = {
|
||||
AXP_DESC(AXP809, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
|
||||
AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)),
|
||||
@ -278,7 +326,7 @@ static const struct regulator_desc axp809_regulators[] = {
|
||||
AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)),
|
||||
AXP_DESC(AXP809, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
|
||||
AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
|
||||
AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp809_dldo1_ranges,
|
||||
AXP_DESC_RANGES(AXP809, DLDO1, "dldo1", "dldoin", axp806_cldo2_ranges,
|
||||
32, AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2,
|
||||
BIT(3)),
|
||||
AXP_DESC(AXP809, DLDO2, "dldo2", "dldoin", 700, 3300, 100,
|
||||
@ -302,6 +350,7 @@ static const struct regulator_desc axp809_regulators[] = {
|
||||
static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
|
||||
{
|
||||
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
|
||||
unsigned int reg = AXP20X_DCDC_FREQ;
|
||||
u32 min, max, def, step;
|
||||
|
||||
switch (axp20x->variant) {
|
||||
@ -312,6 +361,14 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
|
||||
def = 1500;
|
||||
step = 75;
|
||||
break;
|
||||
case AXP806_ID:
|
||||
/*
|
||||
* AXP806 DCDC work frequency setting has the same range and
|
||||
* step as AXP22X, but at a different register.
|
||||
* Fall through to the check below.
|
||||
* (See include/linux/mfd/axp20x.h)
|
||||
*/
|
||||
reg = AXP806_DCDC_FREQ_CTRL;
|
||||
case AXP221_ID:
|
||||
case AXP223_ID:
|
||||
case AXP809_ID:
|
||||
@ -343,7 +400,7 @@ static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
|
||||
|
||||
dcdcfreq = (dcdcfreq - min) / step;
|
||||
|
||||
return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ,
|
||||
return regmap_update_bits(axp20x->regmap, reg,
|
||||
AXP20X_FREQ_DCDC_MASK, dcdcfreq);
|
||||
}
|
||||
|
||||
@ -377,6 +434,7 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev)
|
||||
static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
|
||||
{
|
||||
struct axp20x_dev *axp20x = rdev_get_drvdata(rdev);
|
||||
unsigned int reg = AXP20X_DCDC_MODE;
|
||||
unsigned int mask;
|
||||
|
||||
switch (axp20x->variant) {
|
||||
@ -392,6 +450,13 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
|
||||
workmode <<= ffs(mask) - 1;
|
||||
break;
|
||||
|
||||
case AXP806_ID:
|
||||
reg = AXP806_DCDC_MODE_CTRL2;
|
||||
/*
|
||||
* AXP806 DCDC regulator IDs have the same range as AXP22X.
|
||||
* Fall through to the check below.
|
||||
* (See include/linux/mfd/axp20x.h)
|
||||
*/
|
||||
case AXP221_ID:
|
||||
case AXP223_ID:
|
||||
case AXP809_ID:
|
||||
@ -408,7 +473,34 @@ static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 work
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode);
|
||||
return regmap_update_bits(rdev->regmap, reg, mask, workmode);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks whether a regulator is part of a poly-phase
|
||||
* output setup based on the registers settings. Returns true if it is.
|
||||
*/
|
||||
static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id)
|
||||
{
|
||||
u32 reg = 0;
|
||||
|
||||
/* Only AXP806 has poly-phase outputs */
|
||||
if (axp20x->variant != AXP806_ID)
|
||||
return false;
|
||||
|
||||
regmap_read(axp20x->regmap, AXP806_DCDC_MODE_CTRL2, ®);
|
||||
|
||||
switch (id) {
|
||||
case AXP806_DCDCB:
|
||||
return (((reg & GENMASK(7, 6)) == BIT(6)) ||
|
||||
((reg & GENMASK(7, 6)) == BIT(7)));
|
||||
case AXP806_DCDCC:
|
||||
return ((reg & GENMASK(7, 6)) == BIT(7));
|
||||
case AXP806_DCDCE:
|
||||
return !!(reg & BIT(5));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int axp20x_regulator_probe(struct platform_device *pdev)
|
||||
@ -440,6 +532,10 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
|
||||
drivevbus = of_property_read_bool(pdev->dev.parent->of_node,
|
||||
"x-powers,drive-vbus-en");
|
||||
break;
|
||||
case AXP806_ID:
|
||||
regulators = axp806_regulators;
|
||||
nregulators = AXP806_REG_ID_MAX;
|
||||
break;
|
||||
case AXP809_ID:
|
||||
regulators = axp809_regulators;
|
||||
nregulators = AXP809_REG_ID_MAX;
|
||||
@ -457,6 +553,14 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
|
||||
const struct regulator_desc *desc = ®ulators[i];
|
||||
struct regulator_desc *new_desc;
|
||||
|
||||
/*
|
||||
* If this regulator is a slave in a poly-phase setup,
|
||||
* skip it, as its controls are bound to the master
|
||||
* regulator and won't work.
|
||||
*/
|
||||
if (axp20x_is_polyphase_slave(axp20x, i))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Regulators DC1SW and DC5LDO are connected internally,
|
||||
* so we have to handle their supply names separately.
|
||||
|
@ -447,6 +447,44 @@ static struct regulator_ops switch_ops = {
|
||||
.is_enabled = rpm_reg_is_enabled,
|
||||
};
|
||||
|
||||
/*
|
||||
* PM8018 regulators
|
||||
*/
|
||||
static const struct qcom_rpm_reg pm8018_pldo = {
|
||||
.desc.linear_ranges = pldo_ranges,
|
||||
.desc.n_linear_ranges = ARRAY_SIZE(pldo_ranges),
|
||||
.desc.n_voltages = 161,
|
||||
.desc.ops = &uV_ops,
|
||||
.parts = &rpm8960_ldo_parts,
|
||||
.supports_force_mode_auto = false,
|
||||
.supports_force_mode_bypass = false,
|
||||
};
|
||||
|
||||
static const struct qcom_rpm_reg pm8018_nldo = {
|
||||
.desc.linear_ranges = nldo_ranges,
|
||||
.desc.n_linear_ranges = ARRAY_SIZE(nldo_ranges),
|
||||
.desc.n_voltages = 64,
|
||||
.desc.ops = &uV_ops,
|
||||
.parts = &rpm8960_ldo_parts,
|
||||
.supports_force_mode_auto = false,
|
||||
.supports_force_mode_bypass = false,
|
||||
};
|
||||
|
||||
static const struct qcom_rpm_reg pm8018_smps = {
|
||||
.desc.linear_ranges = smps_ranges,
|
||||
.desc.n_linear_ranges = ARRAY_SIZE(smps_ranges),
|
||||
.desc.n_voltages = 154,
|
||||
.desc.ops = &uV_ops,
|
||||
.parts = &rpm8960_smps_parts,
|
||||
.supports_force_mode_auto = false,
|
||||
.supports_force_mode_bypass = false,
|
||||
};
|
||||
|
||||
static const struct qcom_rpm_reg pm8018_switch = {
|
||||
.desc.ops = &switch_ops,
|
||||
.parts = &rpm8960_switch_parts,
|
||||
};
|
||||
|
||||
/*
|
||||
* PM8058 regulators
|
||||
*/
|
||||
@ -755,6 +793,32 @@ struct rpm_regulator_data {
|
||||
const char *supply;
|
||||
};
|
||||
|
||||
static const struct rpm_regulator_data rpm_pm8018_regulators[] = {
|
||||
{ "s1", QCOM_RPM_PM8018_SMPS1, &pm8018_smps, "vdd_s1" },
|
||||
{ "s2", QCOM_RPM_PM8018_SMPS2, &pm8018_smps, "vdd_s2" },
|
||||
{ "s3", QCOM_RPM_PM8018_SMPS3, &pm8018_smps, "vdd_s3" },
|
||||
{ "s4", QCOM_RPM_PM8018_SMPS4, &pm8018_smps, "vdd_s4" },
|
||||
{ "s5", QCOM_RPM_PM8018_SMPS5, &pm8018_smps, "vdd_s5" },
|
||||
|
||||
{ "l2", QCOM_RPM_PM8018_LDO2, &pm8018_pldo, "vdd_l2" },
|
||||
{ "l3", QCOM_RPM_PM8018_LDO3, &pm8018_pldo, "vdd_l3" },
|
||||
{ "l4", QCOM_RPM_PM8018_LDO4, &pm8018_pldo, "vdd_l4" },
|
||||
{ "l5", QCOM_RPM_PM8018_LDO5, &pm8018_pldo, "vdd_l5" },
|
||||
{ "l6", QCOM_RPM_PM8018_LDO6, &pm8018_pldo, "vdd_l7" },
|
||||
{ "l7", QCOM_RPM_PM8018_LDO7, &pm8018_pldo, "vdd_l7" },
|
||||
{ "l8", QCOM_RPM_PM8018_LDO8, &pm8018_nldo, "vdd_l8" },
|
||||
{ "l9", QCOM_RPM_PM8018_LDO9, &pm8921_nldo1200,
|
||||
"vdd_l9_l10_l11_l12" },
|
||||
{ "l10", QCOM_RPM_PM8018_LDO10, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
|
||||
{ "l11", QCOM_RPM_PM8018_LDO11, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
|
||||
{ "l12", QCOM_RPM_PM8018_LDO12, &pm8018_nldo, "vdd_l9_l10_l11_l12" },
|
||||
{ "l14", QCOM_RPM_PM8018_LDO14, &pm8018_pldo, "vdd_l14" },
|
||||
|
||||
{ "lvs1", QCOM_RPM_PM8018_LVS1, &pm8018_switch, "lvs1_in" },
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct rpm_regulator_data rpm_pm8058_regulators[] = {
|
||||
{ "l0", QCOM_RPM_PM8058_LDO0, &pm8058_nldo, "vdd_l0_l1_lvs" },
|
||||
{ "l1", QCOM_RPM_PM8058_LDO1, &pm8058_nldo, "vdd_l0_l1_lvs" },
|
||||
@ -870,6 +934,8 @@ static const struct rpm_regulator_data rpm_pm8921_regulators[] = {
|
||||
};
|
||||
|
||||
static const struct of_device_id rpm_of_match[] = {
|
||||
{ .compatible = "qcom,rpm-pm8018-regulators",
|
||||
.data = &rpm_pm8018_regulators },
|
||||
{ .compatible = "qcom,rpm-pm8058-regulators", .data = &rpm_pm8058_regulators },
|
||||
{ .compatible = "qcom,rpm-pm8901-regulators", .data = &rpm_pm8901_regulators },
|
||||
{ .compatible = "qcom,rpm-pm8921-regulators", .data = &rpm_pm8921_regulators },
|
||||
|
@ -1,11 +1,15 @@
|
||||
/*
|
||||
* Regulator driver for Rockchip RK808
|
||||
* Regulator driver for Rockchip RK808/RK818
|
||||
*
|
||||
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* Author: Chris Zhong <zyw@rock-chips.com>
|
||||
* Author: Zhang Qing <zhangqing@rock-chips.com>
|
||||
*
|
||||
* Copyright (C) 2016 PHYTEC Messtechnik GmbH
|
||||
*
|
||||
* Author: Wadim Egorov <w.egorov@phytec.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
@ -32,6 +36,12 @@
|
||||
#define RK808_BUCK4_VSEL_MASK 0xf
|
||||
#define RK808_LDO_VSEL_MASK 0x1f
|
||||
|
||||
#define RK818_BUCK_VSEL_MASK 0x3f
|
||||
#define RK818_BUCK4_VSEL_MASK 0x1f
|
||||
#define RK818_LDO_VSEL_MASK 0x1f
|
||||
#define RK818_LDO3_ON_VSEL_MASK 0xf
|
||||
#define RK818_BOOST_ON_VSEL_MASK 0xe0
|
||||
|
||||
/* Ramp rate definitions for buck1 / buck2 only */
|
||||
#define RK808_RAMP_RATE_OFFSET 3
|
||||
#define RK808_RAMP_RATE_MASK (3 << RK808_RAMP_RATE_OFFSET)
|
||||
@ -454,6 +464,108 @@ static const struct regulator_desc rk808_reg[] = {
|
||||
RK808_DCDC_EN_REG, BIT(6)),
|
||||
};
|
||||
|
||||
static const struct regulator_desc rk818_reg[] = {
|
||||
{
|
||||
.name = "DCDC_REG1",
|
||||
.supply_name = "vcc1",
|
||||
.of_match = of_match_ptr("DCDC_REG1"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK818_ID_DCDC1,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.min_uV = 712500,
|
||||
.uV_step = 12500,
|
||||
.n_voltages = 64,
|
||||
.vsel_reg = RK818_BUCK1_ON_VSEL_REG,
|
||||
.vsel_mask = RK818_BUCK_VSEL_MASK,
|
||||
.enable_reg = RK818_DCDC_EN_REG,
|
||||
.enable_mask = BIT(0),
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "DCDC_REG2",
|
||||
.supply_name = "vcc2",
|
||||
.of_match = of_match_ptr("DCDC_REG2"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK818_ID_DCDC2,
|
||||
.ops = &rk808_reg_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.min_uV = 712500,
|
||||
.uV_step = 12500,
|
||||
.n_voltages = 64,
|
||||
.vsel_reg = RK818_BUCK2_ON_VSEL_REG,
|
||||
.vsel_mask = RK818_BUCK_VSEL_MASK,
|
||||
.enable_reg = RK818_DCDC_EN_REG,
|
||||
.enable_mask = BIT(1),
|
||||
.owner = THIS_MODULE,
|
||||
}, {
|
||||
.name = "DCDC_REG3",
|
||||
.supply_name = "vcc3",
|
||||
.of_match = of_match_ptr("DCDC_REG3"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK818_ID_DCDC3,
|
||||
.ops = &rk808_switch_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 1,
|
||||
.enable_reg = RK818_DCDC_EN_REG,
|
||||
.enable_mask = BIT(2),
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
RK8XX_DESC(RK818_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3600, 100,
|
||||
RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK,
|
||||
RK818_DCDC_EN_REG, BIT(3), 0),
|
||||
RK8XX_DESC(RK818_ID_BOOST, "DCDC_BOOST", "boost", 4700, 5400, 100,
|
||||
RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK,
|
||||
RK818_DCDC_EN_REG, BIT(4), 0),
|
||||
RK8XX_DESC(RK818_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100,
|
||||
RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
|
||||
BIT(0), 400),
|
||||
RK8XX_DESC(RK818_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100,
|
||||
RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
|
||||
BIT(1), 400),
|
||||
{
|
||||
.name = "LDO_REG3",
|
||||
.supply_name = "vcc7",
|
||||
.of_match = of_match_ptr("LDO_REG3"),
|
||||
.regulators_node = of_match_ptr("regulators"),
|
||||
.id = RK818_ID_LDO3,
|
||||
.ops = &rk808_reg_ops_ranges,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.n_voltages = 16,
|
||||
.linear_ranges = rk808_ldo3_voltage_ranges,
|
||||
.n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
|
||||
.vsel_reg = RK818_LDO3_ON_VSEL_REG,
|
||||
.vsel_mask = RK818_LDO3_ON_VSEL_MASK,
|
||||
.enable_reg = RK818_LDO_EN_REG,
|
||||
.enable_mask = BIT(2),
|
||||
.enable_time = 400,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
RK8XX_DESC(RK818_ID_LDO4, "LDO_REG4", "vcc8", 1800, 3400, 100,
|
||||
RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
|
||||
BIT(3), 400),
|
||||
RK8XX_DESC(RK818_ID_LDO5, "LDO_REG5", "vcc7", 1800, 3400, 100,
|
||||
RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
|
||||
BIT(4), 400),
|
||||
RK8XX_DESC(RK818_ID_LDO6, "LDO_REG6", "vcc8", 800, 2500, 100,
|
||||
RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
|
||||
BIT(5), 400),
|
||||
RK8XX_DESC(RK818_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100,
|
||||
RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
|
||||
BIT(6), 400),
|
||||
RK8XX_DESC(RK818_ID_LDO8, "LDO_REG8", "vcc8", 1800, 3400, 100,
|
||||
RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
|
||||
BIT(7), 400),
|
||||
RK8XX_DESC(RK818_ID_LDO9, "LDO_REG9", "vcc9", 1800, 3400, 100,
|
||||
RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK,
|
||||
RK818_DCDC_EN_REG, BIT(5), 400),
|
||||
RK8XX_DESC_SWITCH(RK818_ID_SWITCH, "SWITCH_REG", "vcc9",
|
||||
RK818_DCDC_EN_REG, BIT(6)),
|
||||
RK8XX_DESC_SWITCH(RK818_ID_HDMI_SWITCH, "HDMI_SWITCH", "h_5v",
|
||||
RK818_H5V_EN_REG, BIT(0)),
|
||||
RK8XX_DESC_SWITCH(RK818_ID_OTG_SWITCH, "OTG_SWITCH", "usb",
|
||||
RK818_DCDC_EN_REG, BIT(7)),
|
||||
};
|
||||
|
||||
static int rk808_regulator_dt_parse_pdata(struct device *dev,
|
||||
struct device *client_dev,
|
||||
struct regmap *map,
|
||||
@ -499,7 +611,8 @@ static int rk808_regulator_probe(struct platform_device *pdev)
|
||||
struct regulator_config config = {};
|
||||
struct regulator_dev *rk808_rdev;
|
||||
struct rk808_regulator_data *pdata;
|
||||
int ret, i;
|
||||
const struct regulator_desc *regulators;
|
||||
int ret, i, nregulators;
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
@ -512,14 +625,29 @@ static int rk808_regulator_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
|
||||
switch (rk808->variant) {
|
||||
case RK808_ID:
|
||||
regulators = rk808_reg;
|
||||
nregulators = RK808_NUM_REGULATORS;
|
||||
break;
|
||||
case RK818_ID:
|
||||
regulators = rk818_reg;
|
||||
nregulators = RK818_NUM_REGULATORS;
|
||||
break;
|
||||
default:
|
||||
dev_err(&client->dev, "unsupported RK8XX ID %lu\n",
|
||||
rk808->variant);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
config.dev = &client->dev;
|
||||
config.driver_data = pdata;
|
||||
config.regmap = rk808->regmap;
|
||||
|
||||
/* Instantiate the regulators */
|
||||
for (i = 0; i < RK808_NUM_REGULATORS; i++) {
|
||||
for (i = 0; i < nregulators; i++) {
|
||||
rk808_rdev = devm_regulator_register(&pdev->dev,
|
||||
&rk808_reg[i], &config);
|
||||
®ulators[i], &config);
|
||||
if (IS_ERR(rk808_rdev)) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register %d regulator\n", i);
|
||||
@ -539,8 +667,9 @@ static struct platform_driver rk808_regulator_driver = {
|
||||
|
||||
module_platform_driver(rk808_regulator_driver);
|
||||
|
||||
MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs");
|
||||
MODULE_AUTHOR("Chris Zhong<zyw@rock-chips.com>");
|
||||
MODULE_AUTHOR("Zhang Qing<zhangqing@rock-chips.com>");
|
||||
MODULE_DESCRIPTION("regulator driver for the RK808/RK818 series PMICs");
|
||||
MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>");
|
||||
MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>");
|
||||
MODULE_AUTHOR("Wadim Egorov <w.egorov@phytec.de>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:rk808-regulator");
|
||||
|
@ -187,6 +187,16 @@ config RTC_DRV_ABX80X
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-abx80x.
|
||||
|
||||
config RTC_DRV_AC100
|
||||
tristate "X-Powers AC100"
|
||||
depends on MFD_AC100
|
||||
help
|
||||
If you say yes here you get support for the real-time clock found
|
||||
in X-Powers AC100 family peripheral ICs.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-ac100.
|
||||
|
||||
config RTC_DRV_AS3722
|
||||
tristate "ams AS3722 RTC driver"
|
||||
depends on MFD_AS3722
|
||||
@ -328,11 +338,11 @@ config RTC_DRV_MAX77686
|
||||
will be called rtc-max77686.
|
||||
|
||||
config RTC_DRV_RK808
|
||||
tristate "Rockchip RK808 RTC"
|
||||
tristate "Rockchip RK808/RK818 RTC"
|
||||
depends on MFD_RK808
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
RTC of RK808 PMIC.
|
||||
RTC of RK808 and RK818 PMIC.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rk808-rtc.
|
||||
|
@ -27,6 +27,7 @@ obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
|
||||
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
|
||||
obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
|
||||
obj-$(CONFIG_RTC_DRV_ABX80X) += rtc-abx80x.o
|
||||
obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
|
||||
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
|
||||
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
|
||||
obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
|
||||
|
627
drivers/rtc/rtc-ac100.c
Normal file
627
drivers/rtc/rtc-ac100.c
Normal file
@ -0,0 +1,627 @@
|
||||
/*
|
||||
* RTC Driver for X-Powers AC100
|
||||
*
|
||||
* Copyright (c) 2016 Chen-Yu Tsai
|
||||
*
|
||||
* Chen-Yu Tsai <wens@csie.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/ac100.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Control register */
|
||||
#define AC100_RTC_CTRL_24HOUR BIT(0)
|
||||
|
||||
/* Clock output register bits */
|
||||
#define AC100_CLKOUT_PRE_DIV_SHIFT 5
|
||||
#define AC100_CLKOUT_PRE_DIV_WIDTH 3
|
||||
#define AC100_CLKOUT_MUX_SHIFT 4
|
||||
#define AC100_CLKOUT_MUX_WIDTH 1
|
||||
#define AC100_CLKOUT_DIV_SHIFT 1
|
||||
#define AC100_CLKOUT_DIV_WIDTH 3
|
||||
#define AC100_CLKOUT_EN BIT(0)
|
||||
|
||||
/* RTC */
|
||||
#define AC100_RTC_SEC_MASK GENMASK(6, 0)
|
||||
#define AC100_RTC_MIN_MASK GENMASK(6, 0)
|
||||
#define AC100_RTC_HOU_MASK GENMASK(5, 0)
|
||||
#define AC100_RTC_WEE_MASK GENMASK(2, 0)
|
||||
#define AC100_RTC_DAY_MASK GENMASK(5, 0)
|
||||
#define AC100_RTC_MON_MASK GENMASK(4, 0)
|
||||
#define AC100_RTC_YEA_MASK GENMASK(7, 0)
|
||||
#define AC100_RTC_YEA_LEAP BIT(15)
|
||||
#define AC100_RTC_UPD_TRIGGER BIT(15)
|
||||
|
||||
/* Alarm (wall clock) */
|
||||
#define AC100_ALM_INT_ENABLE BIT(0)
|
||||
|
||||
#define AC100_ALM_SEC_MASK GENMASK(6, 0)
|
||||
#define AC100_ALM_MIN_MASK GENMASK(6, 0)
|
||||
#define AC100_ALM_HOU_MASK GENMASK(5, 0)
|
||||
#define AC100_ALM_WEE_MASK GENMASK(2, 0)
|
||||
#define AC100_ALM_DAY_MASK GENMASK(5, 0)
|
||||
#define AC100_ALM_MON_MASK GENMASK(4, 0)
|
||||
#define AC100_ALM_YEA_MASK GENMASK(7, 0)
|
||||
#define AC100_ALM_ENABLE_FLAG BIT(15)
|
||||
#define AC100_ALM_UPD_TRIGGER BIT(15)
|
||||
|
||||
/*
|
||||
* The year parameter passed to the driver is usually an offset relative to
|
||||
* the year 1900. This macro is used to convert this offset to another one
|
||||
* relative to the minimum year allowed by the hardware.
|
||||
*
|
||||
* The year range is 1970 - 2069. This range is selected to match Allwinner's
|
||||
* driver.
|
||||
*/
|
||||
#define AC100_YEAR_MIN 1970
|
||||
#define AC100_YEAR_MAX 2069
|
||||
#define AC100_YEAR_OFF (AC100_YEAR_MIN - 1900)
|
||||
|
||||
struct ac100_clkout {
|
||||
struct clk_hw hw;
|
||||
struct regmap *regmap;
|
||||
u8 offset;
|
||||
};
|
||||
|
||||
#define to_ac100_clkout(_hw) container_of(_hw, struct ac100_clkout, hw)
|
||||
|
||||
#define AC100_RTC_32K_NAME "ac100-rtc-32k"
|
||||
#define AC100_RTC_32K_RATE 32768
|
||||
#define AC100_CLKOUT_NUM 3
|
||||
|
||||
static const char * const ac100_clkout_names[AC100_CLKOUT_NUM] = {
|
||||
"ac100-cko1-rtc",
|
||||
"ac100-cko2-rtc",
|
||||
"ac100-cko3-rtc",
|
||||
};
|
||||
|
||||
struct ac100_rtc_dev {
|
||||
struct rtc_device *rtc;
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
int irq;
|
||||
unsigned long alarm;
|
||||
|
||||
struct clk_hw *rtc_32k_clk;
|
||||
struct ac100_clkout clks[AC100_CLKOUT_NUM];
|
||||
struct clk_hw_onecell_data *clk_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clock controls for 3 clock output pins
|
||||
*/
|
||||
|
||||
static const struct clk_div_table ac100_clkout_prediv[] = {
|
||||
{ .val = 0, .div = 1 },
|
||||
{ .val = 1, .div = 2 },
|
||||
{ .val = 2, .div = 4 },
|
||||
{ .val = 3, .div = 8 },
|
||||
{ .val = 4, .div = 16 },
|
||||
{ .val = 5, .div = 32 },
|
||||
{ .val = 6, .div = 64 },
|
||||
{ .val = 7, .div = 122 },
|
||||
{ },
|
||||
};
|
||||
|
||||
/* Abuse the fact that one parent is 32768 Hz, and the other is 4 MHz */
|
||||
static unsigned long ac100_clkout_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct ac100_clkout *clk = to_ac100_clkout(hw);
|
||||
unsigned int reg, div;
|
||||
|
||||
regmap_read(clk->regmap, clk->offset, ®);
|
||||
|
||||
/* Handle pre-divider first */
|
||||
if (prate != AC100_RTC_32K_RATE) {
|
||||
div = (reg >> AC100_CLKOUT_PRE_DIV_SHIFT) &
|
||||
((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1);
|
||||
prate = divider_recalc_rate(hw, prate, div,
|
||||
ac100_clkout_prediv, 0);
|
||||
}
|
||||
|
||||
div = (reg >> AC100_CLKOUT_DIV_SHIFT) &
|
||||
(BIT(AC100_CLKOUT_DIV_WIDTH) - 1);
|
||||
return divider_recalc_rate(hw, prate, div, NULL,
|
||||
CLK_DIVIDER_POWER_OF_TWO);
|
||||
}
|
||||
|
||||
static long ac100_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
unsigned long best_rate = 0, tmp_rate, tmp_prate;
|
||||
int i;
|
||||
|
||||
if (prate == AC100_RTC_32K_RATE)
|
||||
return divider_round_rate(hw, rate, &prate, NULL,
|
||||
AC100_CLKOUT_DIV_WIDTH,
|
||||
CLK_DIVIDER_POWER_OF_TWO);
|
||||
|
||||
for (i = 0; ac100_clkout_prediv[i].div; i++) {
|
||||
tmp_prate = DIV_ROUND_UP(prate, ac100_clkout_prediv[i].val);
|
||||
tmp_rate = divider_round_rate(hw, rate, &tmp_prate, NULL,
|
||||
AC100_CLKOUT_DIV_WIDTH,
|
||||
CLK_DIVIDER_POWER_OF_TWO);
|
||||
|
||||
if (tmp_rate > rate)
|
||||
continue;
|
||||
if (rate - tmp_rate < best_rate - tmp_rate)
|
||||
best_rate = tmp_rate;
|
||||
}
|
||||
|
||||
return best_rate;
|
||||
}
|
||||
|
||||
static int ac100_clkout_determine_rate(struct clk_hw *hw,
|
||||
struct clk_rate_request *req)
|
||||
{
|
||||
struct clk_hw *best_parent;
|
||||
unsigned long best = 0;
|
||||
int i, num_parents = clk_hw_get_num_parents(hw);
|
||||
|
||||
for (i = 0; i < num_parents; i++) {
|
||||
struct clk_hw *parent = clk_hw_get_parent_by_index(hw, i);
|
||||
unsigned long tmp, prate = clk_hw_get_rate(parent);
|
||||
|
||||
tmp = ac100_clkout_round_rate(hw, req->rate, prate);
|
||||
|
||||
if (tmp > req->rate)
|
||||
continue;
|
||||
if (req->rate - tmp < req->rate - best) {
|
||||
best = tmp;
|
||||
best_parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (!best)
|
||||
return -EINVAL;
|
||||
|
||||
req->best_parent_hw = best_parent;
|
||||
req->best_parent_rate = best;
|
||||
req->rate = best;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac100_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long prate)
|
||||
{
|
||||
struct ac100_clkout *clk = to_ac100_clkout(hw);
|
||||
int div = 0, pre_div = 0;
|
||||
|
||||
do {
|
||||
div = divider_get_val(rate * ac100_clkout_prediv[pre_div].div,
|
||||
prate, NULL, AC100_CLKOUT_DIV_WIDTH,
|
||||
CLK_DIVIDER_POWER_OF_TWO);
|
||||
if (div >= 0)
|
||||
break;
|
||||
} while (prate != AC100_RTC_32K_RATE &&
|
||||
ac100_clkout_prediv[++pre_div].div);
|
||||
|
||||
if (div < 0)
|
||||
return div;
|
||||
|
||||
pre_div = ac100_clkout_prediv[pre_div].val;
|
||||
|
||||
regmap_update_bits(clk->regmap, clk->offset,
|
||||
((1 << AC100_CLKOUT_DIV_WIDTH) - 1) << AC100_CLKOUT_DIV_SHIFT |
|
||||
((1 << AC100_CLKOUT_PRE_DIV_WIDTH) - 1) << AC100_CLKOUT_PRE_DIV_SHIFT,
|
||||
(div - 1) << AC100_CLKOUT_DIV_SHIFT |
|
||||
(pre_div - 1) << AC100_CLKOUT_PRE_DIV_SHIFT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac100_clkout_prepare(struct clk_hw *hw)
|
||||
{
|
||||
struct ac100_clkout *clk = to_ac100_clkout(hw);
|
||||
|
||||
return regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN,
|
||||
AC100_CLKOUT_EN);
|
||||
}
|
||||
|
||||
static void ac100_clkout_unprepare(struct clk_hw *hw)
|
||||
{
|
||||
struct ac100_clkout *clk = to_ac100_clkout(hw);
|
||||
|
||||
regmap_update_bits(clk->regmap, clk->offset, AC100_CLKOUT_EN, 0);
|
||||
}
|
||||
|
||||
static int ac100_clkout_is_prepared(struct clk_hw *hw)
|
||||
{
|
||||
struct ac100_clkout *clk = to_ac100_clkout(hw);
|
||||
unsigned int reg;
|
||||
|
||||
regmap_read(clk->regmap, clk->offset, ®);
|
||||
|
||||
return reg & AC100_CLKOUT_EN;
|
||||
}
|
||||
|
||||
static u8 ac100_clkout_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct ac100_clkout *clk = to_ac100_clkout(hw);
|
||||
unsigned int reg;
|
||||
|
||||
regmap_read(clk->regmap, clk->offset, ®);
|
||||
|
||||
return (reg >> AC100_CLKOUT_MUX_SHIFT) & 0x1;
|
||||
}
|
||||
|
||||
static int ac100_clkout_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct ac100_clkout *clk = to_ac100_clkout(hw);
|
||||
|
||||
return regmap_update_bits(clk->regmap, clk->offset,
|
||||
BIT(AC100_CLKOUT_MUX_SHIFT),
|
||||
index ? BIT(AC100_CLKOUT_MUX_SHIFT) : 0);
|
||||
}
|
||||
|
||||
static const struct clk_ops ac100_clkout_ops = {
|
||||
.prepare = ac100_clkout_prepare,
|
||||
.unprepare = ac100_clkout_unprepare,
|
||||
.is_prepared = ac100_clkout_is_prepared,
|
||||
.recalc_rate = ac100_clkout_recalc_rate,
|
||||
.determine_rate = ac100_clkout_determine_rate,
|
||||
.get_parent = ac100_clkout_get_parent,
|
||||
.set_parent = ac100_clkout_set_parent,
|
||||
.set_rate = ac100_clkout_set_rate,
|
||||
};
|
||||
|
||||
static int ac100_rtc_register_clks(struct ac100_rtc_dev *chip)
|
||||
{
|
||||
struct device_node *np = chip->dev->of_node;
|
||||
const char *parents[2] = {AC100_RTC_32K_NAME};
|
||||
int i, ret;
|
||||
|
||||
chip->clk_data = devm_kzalloc(chip->dev, sizeof(*chip->clk_data) +
|
||||
sizeof(*chip->clk_data->hws) *
|
||||
AC100_CLKOUT_NUM,
|
||||
GFP_KERNEL);
|
||||
if (!chip->clk_data)
|
||||
return -ENOMEM;
|
||||
|
||||
chip->rtc_32k_clk = clk_hw_register_fixed_rate(chip->dev,
|
||||
AC100_RTC_32K_NAME,
|
||||
NULL, 0,
|
||||
AC100_RTC_32K_RATE);
|
||||
if (IS_ERR(chip->rtc_32k_clk)) {
|
||||
ret = PTR_ERR(chip->rtc_32k_clk);
|
||||
dev_err(chip->dev, "Failed to register RTC-32k clock: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
parents[1] = of_clk_get_parent_name(np, 0);
|
||||
if (!parents[1]) {
|
||||
dev_err(chip->dev, "Failed to get ADDA 4M clock\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < AC100_CLKOUT_NUM; i++) {
|
||||
struct ac100_clkout *clk = &chip->clks[i];
|
||||
struct clk_init_data init = {
|
||||
.name = ac100_clkout_names[i],
|
||||
.ops = &ac100_clkout_ops,
|
||||
.parent_names = parents,
|
||||
.num_parents = ARRAY_SIZE(parents),
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
clk->regmap = chip->regmap;
|
||||
clk->offset = AC100_CLKOUT_CTRL1 + i;
|
||||
clk->hw.init = &init;
|
||||
|
||||
ret = devm_clk_hw_register(chip->dev, &clk->hw);
|
||||
if (ret) {
|
||||
dev_err(chip->dev, "Failed to register clk '%s': %d\n",
|
||||
init.name, ret);
|
||||
goto err_unregister_rtc_32k;
|
||||
}
|
||||
|
||||
chip->clk_data->hws[i] = &clk->hw;
|
||||
}
|
||||
|
||||
chip->clk_data->num = i;
|
||||
ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, chip->clk_data);
|
||||
if (ret)
|
||||
goto err_unregister_rtc_32k;
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_rtc_32k:
|
||||
clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ac100_rtc_unregister_clks(struct ac100_rtc_dev *chip)
|
||||
{
|
||||
of_clk_del_provider(chip->dev->of_node);
|
||||
clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
|
||||
}
|
||||
|
||||
/**
|
||||
* RTC related bits
|
||||
*/
|
||||
static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)
|
||||
{
|
||||
struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = chip->regmap;
|
||||
u16 reg[7];
|
||||
int ret;
|
||||
|
||||
ret = regmap_bulk_read(regmap, AC100_RTC_SEC, reg, 7);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtc_tm->tm_sec = bcd2bin(reg[0] & AC100_RTC_SEC_MASK);
|
||||
rtc_tm->tm_min = bcd2bin(reg[1] & AC100_RTC_MIN_MASK);
|
||||
rtc_tm->tm_hour = bcd2bin(reg[2] & AC100_RTC_HOU_MASK);
|
||||
rtc_tm->tm_wday = bcd2bin(reg[3] & AC100_RTC_WEE_MASK);
|
||||
rtc_tm->tm_mday = bcd2bin(reg[4] & AC100_RTC_DAY_MASK);
|
||||
rtc_tm->tm_mon = bcd2bin(reg[5] & AC100_RTC_MON_MASK) - 1;
|
||||
rtc_tm->tm_year = bcd2bin(reg[6] & AC100_RTC_YEA_MASK) +
|
||||
AC100_YEAR_OFF;
|
||||
|
||||
return rtc_valid_tm(rtc_tm);
|
||||
}
|
||||
|
||||
static int ac100_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
|
||||
{
|
||||
struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = chip->regmap;
|
||||
int year;
|
||||
u16 reg[8];
|
||||
|
||||
/* our RTC has a limited year range... */
|
||||
year = rtc_tm->tm_year - AC100_YEAR_OFF;
|
||||
if (year < 0 || year > (AC100_YEAR_MAX - 1900)) {
|
||||
dev_err(dev, "rtc only supports year in range %d - %d\n",
|
||||
AC100_YEAR_MIN, AC100_YEAR_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* convert to BCD */
|
||||
reg[0] = bin2bcd(rtc_tm->tm_sec) & AC100_RTC_SEC_MASK;
|
||||
reg[1] = bin2bcd(rtc_tm->tm_min) & AC100_RTC_MIN_MASK;
|
||||
reg[2] = bin2bcd(rtc_tm->tm_hour) & AC100_RTC_HOU_MASK;
|
||||
reg[3] = bin2bcd(rtc_tm->tm_wday) & AC100_RTC_WEE_MASK;
|
||||
reg[4] = bin2bcd(rtc_tm->tm_mday) & AC100_RTC_DAY_MASK;
|
||||
reg[5] = bin2bcd(rtc_tm->tm_mon + 1) & AC100_RTC_MON_MASK;
|
||||
reg[6] = bin2bcd(year) & AC100_RTC_YEA_MASK;
|
||||
/* trigger write */
|
||||
reg[7] = AC100_RTC_UPD_TRIGGER;
|
||||
|
||||
/* Is it a leap year? */
|
||||
if (is_leap_year(year + AC100_YEAR_OFF + 1900))
|
||||
reg[6] |= AC100_RTC_YEA_LEAP;
|
||||
|
||||
return regmap_bulk_write(regmap, AC100_RTC_SEC, reg, 8);
|
||||
}
|
||||
|
||||
static int ac100_rtc_alarm_irq_enable(struct device *dev, unsigned int en)
|
||||
{
|
||||
struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = chip->regmap;
|
||||
unsigned int val;
|
||||
|
||||
val = en ? AC100_ALM_INT_ENABLE : 0;
|
||||
|
||||
return regmap_write(regmap, AC100_ALM_INT_ENA, val);
|
||||
}
|
||||
|
||||
static int ac100_rtc_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = chip->regmap;
|
||||
struct rtc_time *alrm_tm = &alrm->time;
|
||||
u16 reg[7];
|
||||
unsigned int val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(regmap, AC100_ALM_INT_ENA, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
alrm->enabled = !!(val & AC100_ALM_INT_ENABLE);
|
||||
|
||||
ret = regmap_bulk_read(regmap, AC100_ALM_SEC, reg, 7);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
alrm_tm->tm_sec = bcd2bin(reg[0] & AC100_ALM_SEC_MASK);
|
||||
alrm_tm->tm_min = bcd2bin(reg[1] & AC100_ALM_MIN_MASK);
|
||||
alrm_tm->tm_hour = bcd2bin(reg[2] & AC100_ALM_HOU_MASK);
|
||||
alrm_tm->tm_wday = bcd2bin(reg[3] & AC100_ALM_WEE_MASK);
|
||||
alrm_tm->tm_mday = bcd2bin(reg[4] & AC100_ALM_DAY_MASK);
|
||||
alrm_tm->tm_mon = bcd2bin(reg[5] & AC100_ALM_MON_MASK) - 1;
|
||||
alrm_tm->tm_year = bcd2bin(reg[6] & AC100_ALM_YEA_MASK) +
|
||||
AC100_YEAR_OFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct ac100_rtc_dev *chip = dev_get_drvdata(dev);
|
||||
struct regmap *regmap = chip->regmap;
|
||||
struct rtc_time *alrm_tm = &alrm->time;
|
||||
u16 reg[8];
|
||||
int year;
|
||||
int ret;
|
||||
|
||||
/* our alarm has a limited year range... */
|
||||
year = alrm_tm->tm_year - AC100_YEAR_OFF;
|
||||
if (year < 0 || year > (AC100_YEAR_MAX - 1900)) {
|
||||
dev_err(dev, "alarm only supports year in range %d - %d\n",
|
||||
AC100_YEAR_MIN, AC100_YEAR_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* convert to BCD */
|
||||
reg[0] = (bin2bcd(alrm_tm->tm_sec) & AC100_ALM_SEC_MASK) |
|
||||
AC100_ALM_ENABLE_FLAG;
|
||||
reg[1] = (bin2bcd(alrm_tm->tm_min) & AC100_ALM_MIN_MASK) |
|
||||
AC100_ALM_ENABLE_FLAG;
|
||||
reg[2] = (bin2bcd(alrm_tm->tm_hour) & AC100_ALM_HOU_MASK) |
|
||||
AC100_ALM_ENABLE_FLAG;
|
||||
/* Do not enable weekday alarm */
|
||||
reg[3] = bin2bcd(alrm_tm->tm_wday) & AC100_ALM_WEE_MASK;
|
||||
reg[4] = (bin2bcd(alrm_tm->tm_mday) & AC100_ALM_DAY_MASK) |
|
||||
AC100_ALM_ENABLE_FLAG;
|
||||
reg[5] = (bin2bcd(alrm_tm->tm_mon + 1) & AC100_ALM_MON_MASK) |
|
||||
AC100_ALM_ENABLE_FLAG;
|
||||
reg[6] = (bin2bcd(year) & AC100_ALM_YEA_MASK) |
|
||||
AC100_ALM_ENABLE_FLAG;
|
||||
/* trigger write */
|
||||
reg[7] = AC100_ALM_UPD_TRIGGER;
|
||||
|
||||
ret = regmap_bulk_write(regmap, AC100_ALM_SEC, reg, 8);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ac100_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
}
|
||||
|
||||
static irqreturn_t ac100_rtc_irq(int irq, void *data)
|
||||
{
|
||||
struct ac100_rtc_dev *chip = data;
|
||||
struct regmap *regmap = chip->regmap;
|
||||
unsigned int val = 0;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&chip->rtc->ops_lock);
|
||||
|
||||
/* read status */
|
||||
ret = regmap_read(regmap, AC100_ALM_INT_STA, &val);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (val & AC100_ALM_INT_ENABLE) {
|
||||
/* signal rtc framework */
|
||||
rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
|
||||
|
||||
/* clear status */
|
||||
ret = regmap_write(regmap, AC100_ALM_INT_STA, val);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* disable interrupt */
|
||||
ret = ac100_rtc_alarm_irq_enable(chip->dev, 0);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&chip->rtc->ops_lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops ac100_rtc_ops = {
|
||||
.read_time = ac100_rtc_get_time,
|
||||
.set_time = ac100_rtc_set_time,
|
||||
.read_alarm = ac100_rtc_get_alarm,
|
||||
.set_alarm = ac100_rtc_set_alarm,
|
||||
.alarm_irq_enable = ac100_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static int ac100_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ac100_dev *ac100 = dev_get_drvdata(pdev->dev.parent);
|
||||
struct ac100_rtc_dev *chip;
|
||||
int ret;
|
||||
|
||||
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
chip->dev = &pdev->dev;
|
||||
chip->regmap = ac100->regmap;
|
||||
|
||||
chip->irq = platform_get_irq(pdev, 0);
|
||||
if (chip->irq < 0) {
|
||||
dev_err(&pdev->dev, "No IRQ resource\n");
|
||||
return chip->irq;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, chip->irq, NULL,
|
||||
ac100_rtc_irq,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
dev_name(&pdev->dev), chip);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not request IRQ\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* always use 24 hour mode */
|
||||
regmap_write_bits(chip->regmap, AC100_RTC_CTRL, AC100_RTC_CTRL_24HOUR,
|
||||
AC100_RTC_CTRL_24HOUR);
|
||||
|
||||
/* disable counter alarm interrupt */
|
||||
regmap_write(chip->regmap, AC100_ALM_INT_ENA, 0);
|
||||
|
||||
/* clear counter alarm pending interrupts */
|
||||
regmap_write(chip->regmap, AC100_ALM_INT_STA, AC100_ALM_INT_ENABLE);
|
||||
|
||||
chip->rtc = devm_rtc_device_register(&pdev->dev, "rtc-ac100",
|
||||
&ac100_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(chip->rtc)) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
return PTR_ERR(chip->rtc);
|
||||
}
|
||||
|
||||
ret = ac100_rtc_register_clks(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dev_info(&pdev->dev, "RTC enabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ac100_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ac100_rtc_dev *chip = platform_get_drvdata(pdev);
|
||||
|
||||
ac100_rtc_unregister_clks(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ac100_rtc_match[] = {
|
||||
{ .compatible = "x-powers,ac100-rtc" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ac100_rtc_match);
|
||||
|
||||
static struct platform_driver ac100_rtc_driver = {
|
||||
.probe = ac100_rtc_probe,
|
||||
.remove = ac100_rtc_remove,
|
||||
.driver = {
|
||||
.name = "ac100-rtc",
|
||||
.of_match_table = of_match_ptr(ac100_rtc_match),
|
||||
},
|
||||
};
|
||||
module_platform_driver(ac100_rtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("X-Powers AC100 RTC driver");
|
||||
MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -428,6 +428,7 @@ static const struct pm8xxx_rtc_regs pm8941_regs = {
|
||||
*/
|
||||
static const struct of_device_id pm8xxx_id_table[] = {
|
||||
{ .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs },
|
||||
{ .compatible = "qcom,pm8018-rtc", .data = &pm8921_regs },
|
||||
{ .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs },
|
||||
{ .compatible = "qcom,pm8941-rtc", .data = &pm8941_regs },
|
||||
{ },
|
||||
|
@ -147,6 +147,28 @@
|
||||
#define QCOM_RPM_SMB208_S1b 137
|
||||
#define QCOM_RPM_SMB208_S2a 138
|
||||
#define QCOM_RPM_SMB208_S2b 139
|
||||
#define QCOM_RPM_PM8018_SMPS1 140
|
||||
#define QCOM_RPM_PM8018_SMPS2 141
|
||||
#define QCOM_RPM_PM8018_SMPS3 142
|
||||
#define QCOM_RPM_PM8018_SMPS4 143
|
||||
#define QCOM_RPM_PM8018_SMPS5 144
|
||||
#define QCOM_RPM_PM8018_LDO1 145
|
||||
#define QCOM_RPM_PM8018_LDO2 146
|
||||
#define QCOM_RPM_PM8018_LDO3 147
|
||||
#define QCOM_RPM_PM8018_LDO4 148
|
||||
#define QCOM_RPM_PM8018_LDO5 149
|
||||
#define QCOM_RPM_PM8018_LDO6 150
|
||||
#define QCOM_RPM_PM8018_LDO7 151
|
||||
#define QCOM_RPM_PM8018_LDO8 152
|
||||
#define QCOM_RPM_PM8018_LDO9 153
|
||||
#define QCOM_RPM_PM8018_LDO10 154
|
||||
#define QCOM_RPM_PM8018_LDO11 155
|
||||
#define QCOM_RPM_PM8018_LDO12 156
|
||||
#define QCOM_RPM_PM8018_LDO13 157
|
||||
#define QCOM_RPM_PM8018_LDO14 158
|
||||
#define QCOM_RPM_PM8018_LVS1 159
|
||||
#define QCOM_RPM_PM8018_NCP 160
|
||||
#define QCOM_RPM_VOLTAGE_CORNER 161
|
||||
|
||||
/*
|
||||
* Constants used to select force mode for regulators.
|
||||
|
@ -350,7 +350,7 @@ static inline int pm80x_dev_suspend(struct device *dev)
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
set_bit((1 << irq), &chip->wu_flag);
|
||||
set_bit(irq, &chip->wu_flag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -362,7 +362,7 @@ static inline int pm80x_dev_resume(struct device *dev)
|
||||
int irq = platform_get_irq(pdev, 0);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
clear_bit((1 << irq), &chip->wu_flag);
|
||||
clear_bit(irq, &chip->wu_flag);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -63,6 +63,8 @@ enum ab8500_version {
|
||||
#define AB8500_STE_TEST 0x14
|
||||
#define AB8500_OTP_EMUL 0x15
|
||||
|
||||
#define AB8500_DEBUG_FIELD_LAST 0x16
|
||||
|
||||
/*
|
||||
* Interrupts
|
||||
* Values used to index into array ab8500_irq_regoffset[] defined in
|
||||
|
178
include/linux/mfd/ac100.h
Normal file
178
include/linux/mfd/ac100.h
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Functions and registers to access AC100 codec / RTC combo IC.
|
||||
*
|
||||
* Copyright (C) 2016 Chen-Yu Tsai
|
||||
*
|
||||
* Chen-Yu Tsai <wens@csie.org>
|
||||
*
|
||||
* 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_AC100_H
|
||||
#define __LINUX_MFD_AC100_H
|
||||
|
||||
#include <linux/regmap.h>
|
||||
|
||||
struct ac100_dev {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
/* Audio codec related registers */
|
||||
#define AC100_CHIP_AUDIO_RST 0x00
|
||||
#define AC100_PLL_CTRL1 0x01
|
||||
#define AC100_PLL_CTRL2 0x02
|
||||
#define AC100_SYSCLK_CTRL 0x03
|
||||
#define AC100_MOD_CLK_ENA 0x04
|
||||
#define AC100_MOD_RST_CTRL 0x05
|
||||
#define AC100_I2S_SR_CTRL 0x06
|
||||
|
||||
/* I2S1 interface */
|
||||
#define AC100_I2S1_CLK_CTRL 0x10
|
||||
#define AC100_I2S1_SND_OUT_CTRL 0x11
|
||||
#define AC100_I2S1_SND_IN_CTRL 0x12
|
||||
#define AC100_I2S1_MXR_SRC 0x13
|
||||
#define AC100_I2S1_VOL_CTRL1 0x14
|
||||
#define AC100_I2S1_VOL_CTRL2 0x15
|
||||
#define AC100_I2S1_VOL_CTRL3 0x16
|
||||
#define AC100_I2S1_VOL_CTRL4 0x17
|
||||
#define AC100_I2S1_MXR_GAIN 0x18
|
||||
|
||||
/* I2S2 interface */
|
||||
#define AC100_I2S2_CLK_CTRL 0x20
|
||||
#define AC100_I2S2_SND_OUT_CTRL 0x21
|
||||
#define AC100_I2S2_SND_IN_CTRL 0x22
|
||||
#define AC100_I2S2_MXR_SRC 0x23
|
||||
#define AC100_I2S2_VOL_CTRL1 0x24
|
||||
#define AC100_I2S2_VOL_CTRL2 0x25
|
||||
#define AC100_I2S2_VOL_CTRL3 0x26
|
||||
#define AC100_I2S2_VOL_CTRL4 0x27
|
||||
#define AC100_I2S2_MXR_GAIN 0x28
|
||||
|
||||
/* I2S3 interface */
|
||||
#define AC100_I2S3_CLK_CTRL 0x30
|
||||
#define AC100_I2S3_SND_OUT_CTRL 0x31
|
||||
#define AC100_I2S3_SND_IN_CTRL 0x32
|
||||
#define AC100_I2S3_SIG_PATH_CTRL 0x33
|
||||
|
||||
/* ADC digital controls */
|
||||
#define AC100_ADC_DIG_CTRL 0x40
|
||||
#define AC100_ADC_VOL_CTRL 0x41
|
||||
|
||||
/* HMIC plug sensing / key detection */
|
||||
#define AC100_HMIC_CTRL1 0x44
|
||||
#define AC100_HMIC_CTRL2 0x45
|
||||
#define AC100_HMIC_STATUS 0x46
|
||||
|
||||
/* DAC digital controls */
|
||||
#define AC100_DAC_DIG_CTRL 0x48
|
||||
#define AC100_DAC_VOL_CTRL 0x49
|
||||
#define AC100_DAC_MXR_SRC 0x4c
|
||||
#define AC100_DAC_MXR_GAIN 0x4d
|
||||
|
||||
/* Analog controls */
|
||||
#define AC100_ADC_APC_CTRL 0x50
|
||||
#define AC100_ADC_SRC 0x51
|
||||
#define AC100_ADC_SRC_BST_CTRL 0x52
|
||||
#define AC100_OUT_MXR_DAC_A_CTRL 0x53
|
||||
#define AC100_OUT_MXR_SRC 0x54
|
||||
#define AC100_OUT_MXR_SRC_BST 0x55
|
||||
#define AC100_HPOUT_CTRL 0x56
|
||||
#define AC100_ERPOUT_CTRL 0x57
|
||||
#define AC100_SPKOUT_CTRL 0x58
|
||||
#define AC100_LINEOUT_CTRL 0x59
|
||||
|
||||
/* ADC digital audio processing (high pass filter & auto gain control */
|
||||
#define AC100_ADC_DAP_L_STA 0x80
|
||||
#define AC100_ADC_DAP_R_STA 0x81
|
||||
#define AC100_ADC_DAP_L_CTRL 0x82
|
||||
#define AC100_ADC_DAP_R_CTRL 0x83
|
||||
#define AC100_ADC_DAP_L_T_L 0x84 /* Left Target Level */
|
||||
#define AC100_ADC_DAP_R_T_L 0x85 /* Right Target Level */
|
||||
#define AC100_ADC_DAP_L_H_A_C 0x86 /* Left High Avg. Coef */
|
||||
#define AC100_ADC_DAP_L_L_A_C 0x87 /* Left Low Avg. Coef */
|
||||
#define AC100_ADC_DAP_R_H_A_C 0x88 /* Right High Avg. Coef */
|
||||
#define AC100_ADC_DAP_R_L_A_C 0x89 /* Right Low Avg. Coef */
|
||||
#define AC100_ADC_DAP_L_D_T 0x8a /* Left Decay Time */
|
||||
#define AC100_ADC_DAP_L_A_T 0x8b /* Left Attack Time */
|
||||
#define AC100_ADC_DAP_R_D_T 0x8c /* Right Decay Time */
|
||||
#define AC100_ADC_DAP_R_A_T 0x8d /* Right Attack Time */
|
||||
#define AC100_ADC_DAP_N_TH 0x8e /* Noise Threshold */
|
||||
#define AC100_ADC_DAP_L_H_N_A_C 0x8f /* Left High Noise Avg. Coef */
|
||||
#define AC100_ADC_DAP_L_L_N_A_C 0x90 /* Left Low Noise Avg. Coef */
|
||||
#define AC100_ADC_DAP_R_H_N_A_C 0x91 /* Right High Noise Avg. Coef */
|
||||
#define AC100_ADC_DAP_R_L_N_A_C 0x92 /* Right Low Noise Avg. Coef */
|
||||
#define AC100_ADC_DAP_H_HPF_C 0x93 /* High High-Pass-Filter Coef */
|
||||
#define AC100_ADC_DAP_L_HPF_C 0x94 /* Low High-Pass-Filter Coef */
|
||||
#define AC100_ADC_DAP_OPT 0x95 /* AGC Optimum */
|
||||
|
||||
/* DAC digital audio processing (high pass filter & dynamic range control) */
|
||||
#define AC100_DAC_DAP_CTRL 0xa0
|
||||
#define AC100_DAC_DAP_H_HPF_C 0xa1 /* High High-Pass-Filter Coef */
|
||||
#define AC100_DAC_DAP_L_HPF_C 0xa2 /* Low High-Pass-Filter Coef */
|
||||
#define AC100_DAC_DAP_L_H_E_A_C 0xa3 /* Left High Energy Avg Coef */
|
||||
#define AC100_DAC_DAP_L_L_E_A_C 0xa4 /* Left Low Energy Avg Coef */
|
||||
#define AC100_DAC_DAP_R_H_E_A_C 0xa5 /* Right High Energy Avg Coef */
|
||||
#define AC100_DAC_DAP_R_L_E_A_C 0xa6 /* Right Low Energy Avg Coef */
|
||||
#define AC100_DAC_DAP_H_G_D_T_C 0xa7 /* High Gain Delay Time Coef */
|
||||
#define AC100_DAC_DAP_L_G_D_T_C 0xa8 /* Low Gain Delay Time Coef */
|
||||
#define AC100_DAC_DAP_H_G_A_T_C 0xa9 /* High Gain Attack Time Coef */
|
||||
#define AC100_DAC_DAP_L_G_A_T_C 0xaa /* Low Gain Attack Time Coef */
|
||||
#define AC100_DAC_DAP_H_E_TH 0xab /* High Energy Threshold */
|
||||
#define AC100_DAC_DAP_L_E_TH 0xac /* Low Energy Threshold */
|
||||
#define AC100_DAC_DAP_H_G_K 0xad /* High Gain K parameter */
|
||||
#define AC100_DAC_DAP_L_G_K 0xae /* Low Gain K parameter */
|
||||
#define AC100_DAC_DAP_H_G_OFF 0xaf /* High Gain offset */
|
||||
#define AC100_DAC_DAP_L_G_OFF 0xb0 /* Low Gain offset */
|
||||
#define AC100_DAC_DAP_OPT 0xb1 /* DRC optimum */
|
||||
|
||||
/* Digital audio processing enable */
|
||||
#define AC100_ADC_DAP_ENA 0xb4
|
||||
#define AC100_DAC_DAP_ENA 0xb5
|
||||
|
||||
/* SRC control */
|
||||
#define AC100_SRC1_CTRL1 0xb8
|
||||
#define AC100_SRC1_CTRL2 0xb9
|
||||
#define AC100_SRC1_CTRL3 0xba
|
||||
#define AC100_SRC1_CTRL4 0xbb
|
||||
#define AC100_SRC2_CTRL1 0xbc
|
||||
#define AC100_SRC2_CTRL2 0xbd
|
||||
#define AC100_SRC2_CTRL3 0xbe
|
||||
#define AC100_SRC2_CTRL4 0xbf
|
||||
|
||||
/* RTC clk control */
|
||||
#define AC100_CLK32K_ANALOG_CTRL 0xc0
|
||||
#define AC100_CLKOUT_CTRL1 0xc1
|
||||
#define AC100_CLKOUT_CTRL2 0xc2
|
||||
#define AC100_CLKOUT_CTRL3 0xc3
|
||||
|
||||
/* RTC module */
|
||||
#define AC100_RTC_RST 0xc6
|
||||
#define AC100_RTC_CTRL 0xc7
|
||||
#define AC100_RTC_SEC 0xc8 /* second */
|
||||
#define AC100_RTC_MIN 0xc9 /* minute */
|
||||
#define AC100_RTC_HOU 0xca /* hour */
|
||||
#define AC100_RTC_WEE 0xcb /* weekday */
|
||||
#define AC100_RTC_DAY 0xcc /* day */
|
||||
#define AC100_RTC_MON 0xcd /* month */
|
||||
#define AC100_RTC_YEA 0xce /* year */
|
||||
#define AC100_RTC_UPD 0xcf /* update trigger */
|
||||
|
||||
/* RTC alarm */
|
||||
#define AC100_ALM_INT_ENA 0xd0
|
||||
#define AC100_ALM_INT_STA 0xd1
|
||||
#define AC100_ALM_SEC 0xd8
|
||||
#define AC100_ALM_MIN 0xd9
|
||||
#define AC100_ALM_HOU 0xda
|
||||
#define AC100_ALM_WEE 0xdb
|
||||
#define AC100_ALM_DAY 0xdc
|
||||
#define AC100_ALM_MON 0xdd
|
||||
#define AC100_ALM_YEA 0xde
|
||||
#define AC100_ALM_UPD 0xdf
|
||||
|
||||
/* RTC general purpose register 0 ~ 15 */
|
||||
#define AC100_RTC_GP(x) (0xe0 + (x))
|
||||
|
||||
#endif /* __LINUX_MFD_AC100_H */
|
@ -13,6 +13,7 @@
|
||||
#ifndef _WM_ARIZONA_CORE_H
|
||||
#define _WM_ARIZONA_CORE_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -21,6 +22,12 @@
|
||||
|
||||
#define ARIZONA_MAX_CORE_SUPPLIES 2
|
||||
|
||||
enum {
|
||||
ARIZONA_MCLK1,
|
||||
ARIZONA_MCLK2,
|
||||
ARIZONA_NUM_MCLK
|
||||
};
|
||||
|
||||
enum arizona_type {
|
||||
WM5102 = 1,
|
||||
WM5110 = 2,
|
||||
@ -139,6 +146,8 @@ struct arizona {
|
||||
struct mutex clk_lock;
|
||||
int clk32k_ref;
|
||||
|
||||
struct clk *mclk[ARIZONA_NUM_MCLK];
|
||||
|
||||
bool ctrlif_error;
|
||||
|
||||
struct snd_soc_dapm_context *dapm;
|
||||
@ -182,7 +191,4 @@ int cs47l24_patch(struct arizona *arizona);
|
||||
int wm8997_patch(struct arizona *arizona);
|
||||
int wm8998_patch(struct arizona *arizona);
|
||||
|
||||
extern int arizona_of_get_named_gpio(struct arizona *arizona, const char *prop,
|
||||
bool mandatory);
|
||||
|
||||
#endif
|
||||
|
@ -20,6 +20,7 @@ enum {
|
||||
AXP221_ID,
|
||||
AXP223_ID,
|
||||
AXP288_ID,
|
||||
AXP806_ID,
|
||||
AXP809_ID,
|
||||
NR_AXP20X_VARIANTS,
|
||||
};
|
||||
@ -91,6 +92,30 @@ enum {
|
||||
#define AXP22X_ALDO3_V_OUT 0x2a
|
||||
#define AXP22X_CHRG_CTRL3 0x35
|
||||
|
||||
#define AXP806_STARTUP_SRC 0x00
|
||||
#define AXP806_CHIP_ID 0x03
|
||||
#define AXP806_PWR_OUT_CTRL1 0x10
|
||||
#define AXP806_PWR_OUT_CTRL2 0x11
|
||||
#define AXP806_DCDCA_V_CTRL 0x12
|
||||
#define AXP806_DCDCB_V_CTRL 0x13
|
||||
#define AXP806_DCDCC_V_CTRL 0x14
|
||||
#define AXP806_DCDCD_V_CTRL 0x15
|
||||
#define AXP806_DCDCE_V_CTRL 0x16
|
||||
#define AXP806_ALDO1_V_CTRL 0x17
|
||||
#define AXP806_ALDO2_V_CTRL 0x18
|
||||
#define AXP806_ALDO3_V_CTRL 0x19
|
||||
#define AXP806_DCDC_MODE_CTRL1 0x1a
|
||||
#define AXP806_DCDC_MODE_CTRL2 0x1b
|
||||
#define AXP806_DCDC_FREQ_CTRL 0x1c
|
||||
#define AXP806_BLDO1_V_CTRL 0x20
|
||||
#define AXP806_BLDO2_V_CTRL 0x21
|
||||
#define AXP806_BLDO3_V_CTRL 0x22
|
||||
#define AXP806_BLDO4_V_CTRL 0x23
|
||||
#define AXP806_CLDO1_V_CTRL 0x24
|
||||
#define AXP806_CLDO2_V_CTRL 0x25
|
||||
#define AXP806_CLDO3_V_CTRL 0x26
|
||||
#define AXP806_VREF_TEMP_WARN_L 0xf3
|
||||
|
||||
/* Interrupt */
|
||||
#define AXP152_IRQ1_EN 0x40
|
||||
#define AXP152_IRQ2_EN 0x41
|
||||
@ -265,6 +290,26 @@ enum {
|
||||
AXP22X_REG_ID_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
AXP806_DCDCA = 0,
|
||||
AXP806_DCDCB,
|
||||
AXP806_DCDCC,
|
||||
AXP806_DCDCD,
|
||||
AXP806_DCDCE,
|
||||
AXP806_ALDO1,
|
||||
AXP806_ALDO2,
|
||||
AXP806_ALDO3,
|
||||
AXP806_BLDO1,
|
||||
AXP806_BLDO2,
|
||||
AXP806_BLDO3,
|
||||
AXP806_BLDO4,
|
||||
AXP806_CLDO1,
|
||||
AXP806_CLDO2,
|
||||
AXP806_CLDO3,
|
||||
AXP806_SW,
|
||||
AXP806_REG_ID_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
AXP809_DCDC1 = 0,
|
||||
AXP809_DCDC2,
|
||||
@ -414,6 +459,21 @@ enum axp288_irqs {
|
||||
AXP288_IRQ_BC_USB_CHNG,
|
||||
};
|
||||
|
||||
enum axp806_irqs {
|
||||
AXP806_IRQ_DIE_TEMP_HIGH_LV1,
|
||||
AXP806_IRQ_DIE_TEMP_HIGH_LV2,
|
||||
AXP806_IRQ_DCDCA_V_LOW,
|
||||
AXP806_IRQ_DCDCB_V_LOW,
|
||||
AXP806_IRQ_DCDCC_V_LOW,
|
||||
AXP806_IRQ_DCDCD_V_LOW,
|
||||
AXP806_IRQ_DCDCE_V_LOW,
|
||||
AXP806_IRQ_PWROK_LONG,
|
||||
AXP806_IRQ_PWROK_SHORT,
|
||||
AXP806_IRQ_WAKEUP,
|
||||
AXP806_IRQ_PWROK_FALL,
|
||||
AXP806_IRQ_PWROK_RISE,
|
||||
};
|
||||
|
||||
enum axp809_irqs {
|
||||
AXP809_IRQ_ACIN_OVER_V = 1,
|
||||
AXP809_IRQ_ACIN_PLUGIN,
|
||||
|
@ -109,6 +109,10 @@ struct cros_ec_command {
|
||||
* should check msg.result for the EC's result code.
|
||||
* @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.
|
||||
* @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.
|
||||
*/
|
||||
struct cros_ec_device {
|
||||
|
||||
@ -137,6 +141,11 @@ struct cros_ec_device {
|
||||
int (*pkt_xfer)(struct cros_ec_device *ec,
|
||||
struct cros_ec_command *msg);
|
||||
struct mutex lock;
|
||||
bool mkbp_event_supported;
|
||||
struct blocking_notifier_head event_notifier;
|
||||
|
||||
struct ec_response_get_next_event event_data;
|
||||
int event_size;
|
||||
};
|
||||
|
||||
/* struct cros_ec_platform - ChromeOS EC platform information
|
||||
@ -269,6 +278,15 @@ int cros_ec_register(struct cros_ec_device *ec_dev);
|
||||
*/
|
||||
int cros_ec_query_all(struct cros_ec_device *ec_dev);
|
||||
|
||||
/**
|
||||
* cros_ec_get_next_event - Fetch next event from the ChromeOS EC
|
||||
*
|
||||
* @ec_dev: Device to fetch event from
|
||||
*
|
||||
* Returns: 0 on success, Linux error number on failure
|
||||
*/
|
||||
int cros_ec_get_next_event(struct cros_ec_device *ec_dev);
|
||||
|
||||
/* sysfs stuff */
|
||||
extern struct attribute_group cros_ec_attr_group;
|
||||
extern struct attribute_group cros_ec_lightbar_attr_group;
|
||||
|
@ -1793,6 +1793,40 @@ struct ec_result_keyscan_seq_ctrl {
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Command for retrieving the next pending MKBP event from the EC device
|
||||
*
|
||||
* The device replies with UNAVAILABLE if there aren't any pending events.
|
||||
*/
|
||||
#define EC_CMD_GET_NEXT_EVENT 0x67
|
||||
|
||||
enum ec_mkbp_event {
|
||||
/* Keyboard matrix changed. The event data is the new matrix state. */
|
||||
EC_MKBP_EVENT_KEY_MATRIX = 0,
|
||||
|
||||
/* New host event. The event data is 4 bytes of host event flags. */
|
||||
EC_MKBP_EVENT_HOST_EVENT = 1,
|
||||
|
||||
/* New Sensor FIFO data. The event data is fifo_info structure. */
|
||||
EC_MKBP_EVENT_SENSOR_FIFO = 2,
|
||||
|
||||
/* Number of MKBP events */
|
||||
EC_MKBP_EVENT_COUNT,
|
||||
};
|
||||
|
||||
union ec_response_get_next_data {
|
||||
uint8_t key_matrix[13];
|
||||
|
||||
/* Unaligned */
|
||||
uint32_t host_event;
|
||||
} __packed;
|
||||
|
||||
struct ec_response_get_next_event {
|
||||
uint8_t event_type;
|
||||
/* Followed by event data if any */
|
||||
union ec_response_get_next_data data;
|
||||
} __packed;
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Temperature sensor commands */
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
* Krystian Garbaciak <krystian.garbaciak@diasemi.com>
|
||||
* 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
|
||||
|
@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
* Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>
|
||||
* 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
|
||||
|
@ -3,8 +3,8 @@
|
||||
*
|
||||
* Copyright 2012 Dialog Semiconductor Ltd.
|
||||
*
|
||||
* Author: Michal Hajduk <michal.hajduk@diasemi.com>
|
||||
* Krystian Garbaciak <krystian.garbaciak@diasemi.com>
|
||||
* 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
|
||||
|
@ -538,7 +538,6 @@ int db8500_prcmu_get_arm_opp(void);
|
||||
int db8500_prcmu_set_ape_opp(u8 opp);
|
||||
int db8500_prcmu_get_ape_opp(void);
|
||||
int db8500_prcmu_request_ape_opp_100_voltage(bool enable);
|
||||
int db8500_prcmu_set_ddr_opp(u8 opp);
|
||||
int db8500_prcmu_get_ddr_opp(void);
|
||||
|
||||
u32 db8500_prcmu_read(unsigned int reg);
|
||||
@ -594,11 +593,6 @@ static inline int prcmu_release_usb_wakeup_state(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int db8500_prcmu_set_ddr_opp(u8 opp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int db8500_prcmu_get_ddr_opp(void)
|
||||
{
|
||||
return DDR_100_OPP;
|
||||
|
@ -269,10 +269,6 @@ unsigned long prcmu_clock_rate(u8 clock);
|
||||
long prcmu_round_clock_rate(u8 clock, unsigned long rate);
|
||||
int prcmu_set_clock_rate(u8 clock, unsigned long rate);
|
||||
|
||||
static inline int prcmu_set_ddr_opp(u8 opp)
|
||||
{
|
||||
return db8500_prcmu_set_ddr_opp(opp);
|
||||
}
|
||||
static inline int prcmu_get_ddr_opp(void)
|
||||
{
|
||||
return db8500_prcmu_get_ddr_opp();
|
||||
@ -489,11 +485,6 @@ static inline int prcmu_get_arm_opp(void)
|
||||
return ARM_100_OPP;
|
||||
}
|
||||
|
||||
static inline int prcmu_set_ddr_opp(u8 opp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int prcmu_get_ddr_opp(void)
|
||||
{
|
||||
return DDR_100_OPP;
|
||||
|
@ -263,7 +263,6 @@ enum lp873x_regulator_id {
|
||||
struct lp873x {
|
||||
struct device *dev;
|
||||
u8 rev;
|
||||
struct mutex lock; /* lock guarding the data structure */
|
||||
struct regmap *regmap;
|
||||
};
|
||||
#endif /* __LINUX_MFD_LP873X_H */
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2014 Samsung Electrnoics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
* Krzysztof Kozlowski <krzk@kernel.org>
|
||||
*
|
||||
* 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
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (C) 2014 Samsung Electrnoics
|
||||
* Chanwoo Choi <cw00.choi@samsung.com>
|
||||
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
|
||||
* Krzysztof Kozlowski <krzk@kernel.org>
|
||||
*
|
||||
* 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
|
||||
|
@ -1,11 +1,15 @@
|
||||
/*
|
||||
* rk808.h for Rockchip RK808
|
||||
* Register definitions for Rockchip's RK808/RK818 PMIC
|
||||
*
|
||||
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
|
||||
*
|
||||
* Author: Chris Zhong <zyw@rock-chips.com>
|
||||
* Author: Zhang Qing <zhangqing@rock-chips.com>
|
||||
*
|
||||
* Copyright (C) 2016 PHYTEC Messtechnik GmbH
|
||||
*
|
||||
* Author: Wadim Egorov <w.egorov@phytec.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
@ -16,8 +20,8 @@
|
||||
* more details.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_REGULATOR_rk808_H
|
||||
#define __LINUX_REGULATOR_rk808_H
|
||||
#ifndef __LINUX_REGULATOR_RK808_H
|
||||
#define __LINUX_REGULATOR_RK808_H
|
||||
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -65,6 +69,8 @@ enum rk808_reg {
|
||||
#define RK808_RTC_INT_REG 0x12
|
||||
#define RK808_RTC_COMP_LSB_REG 0x13
|
||||
#define RK808_RTC_COMP_MSB_REG 0x14
|
||||
#define RK808_ID_MSB 0x17
|
||||
#define RK808_ID_LSB 0x18
|
||||
#define RK808_CLK32OUT_REG 0x20
|
||||
#define RK808_VB_MON_REG 0x21
|
||||
#define RK808_THERMAL_REG 0x22
|
||||
@ -115,7 +121,92 @@ enum rk808_reg {
|
||||
#define RK808_INT_STS_MSK_REG2 0x4f
|
||||
#define RK808_IO_POL_REG 0x50
|
||||
|
||||
/* IRQ Definitions */
|
||||
/* RK818 */
|
||||
#define RK818_DCDC1 0
|
||||
#define RK818_LDO1 4
|
||||
#define RK818_NUM_REGULATORS 17
|
||||
|
||||
enum rk818_reg {
|
||||
RK818_ID_DCDC1,
|
||||
RK818_ID_DCDC2,
|
||||
RK818_ID_DCDC3,
|
||||
RK818_ID_DCDC4,
|
||||
RK818_ID_BOOST,
|
||||
RK818_ID_LDO1,
|
||||
RK818_ID_LDO2,
|
||||
RK818_ID_LDO3,
|
||||
RK818_ID_LDO4,
|
||||
RK818_ID_LDO5,
|
||||
RK818_ID_LDO6,
|
||||
RK818_ID_LDO7,
|
||||
RK818_ID_LDO8,
|
||||
RK818_ID_LDO9,
|
||||
RK818_ID_SWITCH,
|
||||
RK818_ID_HDMI_SWITCH,
|
||||
RK818_ID_OTG_SWITCH,
|
||||
};
|
||||
|
||||
#define RK818_DCDC_EN_REG 0x23
|
||||
#define RK818_LDO_EN_REG 0x24
|
||||
#define RK818_SLEEP_SET_OFF_REG1 0x25
|
||||
#define RK818_SLEEP_SET_OFF_REG2 0x26
|
||||
#define RK818_DCDC_UV_STS_REG 0x27
|
||||
#define RK818_DCDC_UV_ACT_REG 0x28
|
||||
#define RK818_LDO_UV_STS_REG 0x29
|
||||
#define RK818_LDO_UV_ACT_REG 0x2a
|
||||
#define RK818_DCDC_PG_REG 0x2b
|
||||
#define RK818_LDO_PG_REG 0x2c
|
||||
#define RK818_VOUT_MON_TDB_REG 0x2d
|
||||
#define RK818_BUCK1_CONFIG_REG 0x2e
|
||||
#define RK818_BUCK1_ON_VSEL_REG 0x2f
|
||||
#define RK818_BUCK1_SLP_VSEL_REG 0x30
|
||||
#define RK818_BUCK2_CONFIG_REG 0x32
|
||||
#define RK818_BUCK2_ON_VSEL_REG 0x33
|
||||
#define RK818_BUCK2_SLP_VSEL_REG 0x34
|
||||
#define RK818_BUCK3_CONFIG_REG 0x36
|
||||
#define RK818_BUCK4_CONFIG_REG 0x37
|
||||
#define RK818_BUCK4_ON_VSEL_REG 0x38
|
||||
#define RK818_BUCK4_SLP_VSEL_REG 0x39
|
||||
#define RK818_BOOST_CONFIG_REG 0x3a
|
||||
#define RK818_LDO1_ON_VSEL_REG 0x3b
|
||||
#define RK818_LDO1_SLP_VSEL_REG 0x3c
|
||||
#define RK818_LDO2_ON_VSEL_REG 0x3d
|
||||
#define RK818_LDO2_SLP_VSEL_REG 0x3e
|
||||
#define RK818_LDO3_ON_VSEL_REG 0x3f
|
||||
#define RK818_LDO3_SLP_VSEL_REG 0x40
|
||||
#define RK818_LDO4_ON_VSEL_REG 0x41
|
||||
#define RK818_LDO4_SLP_VSEL_REG 0x42
|
||||
#define RK818_LDO5_ON_VSEL_REG 0x43
|
||||
#define RK818_LDO5_SLP_VSEL_REG 0x44
|
||||
#define RK818_LDO6_ON_VSEL_REG 0x45
|
||||
#define RK818_LDO6_SLP_VSEL_REG 0x46
|
||||
#define RK818_LDO7_ON_VSEL_REG 0x47
|
||||
#define RK818_LDO7_SLP_VSEL_REG 0x48
|
||||
#define RK818_LDO8_ON_VSEL_REG 0x49
|
||||
#define RK818_LDO8_SLP_VSEL_REG 0x4a
|
||||
#define RK818_BOOST_LDO9_ON_VSEL_REG 0x54
|
||||
#define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55
|
||||
#define RK818_DEVCTRL_REG 0x4b
|
||||
#define RK818_INT_STS_REG1 0X4c
|
||||
#define RK818_INT_STS_MSK_REG1 0x4d
|
||||
#define RK818_INT_STS_REG2 0x4e
|
||||
#define RK818_INT_STS_MSK_REG2 0x4f
|
||||
#define RK818_IO_POL_REG 0x50
|
||||
#define RK818_H5V_EN_REG 0x52
|
||||
#define RK818_SLEEP_SET_OFF_REG3 0x53
|
||||
#define RK818_BOOST_LDO9_ON_VSEL_REG 0x54
|
||||
#define RK818_BOOST_LDO9_SLP_VSEL_REG 0x55
|
||||
#define RK818_BOOST_CTRL_REG 0x56
|
||||
#define RK818_DCDC_ILMAX 0x90
|
||||
#define RK818_USB_CTRL_REG 0xa1
|
||||
|
||||
#define RK818_H5V_EN BIT(0)
|
||||
#define RK818_REF_RDY_CTRL BIT(1)
|
||||
#define RK818_USB_ILIM_SEL_MASK 0xf
|
||||
#define RK818_USB_ILMIN_2000MA 0x7
|
||||
#define RK818_USB_CHG_SD_VSEL_MASK 0x70
|
||||
|
||||
/* RK808 IRQ Definitions */
|
||||
#define RK808_IRQ_VOUT_LO 0
|
||||
#define RK808_IRQ_VB_LO 1
|
||||
#define RK808_IRQ_PWRON 2
|
||||
@ -137,6 +228,43 @@ enum rk808_reg {
|
||||
#define RK808_IRQ_PLUG_IN_INT_MSK BIT(0)
|
||||
#define RK808_IRQ_PLUG_OUT_INT_MSK BIT(1)
|
||||
|
||||
/* RK818 IRQ Definitions */
|
||||
#define RK818_IRQ_VOUT_LO 0
|
||||
#define RK818_IRQ_VB_LO 1
|
||||
#define RK818_IRQ_PWRON 2
|
||||
#define RK818_IRQ_PWRON_LP 3
|
||||
#define RK818_IRQ_HOTDIE 4
|
||||
#define RK818_IRQ_RTC_ALARM 5
|
||||
#define RK818_IRQ_RTC_PERIOD 6
|
||||
#define RK818_IRQ_USB_OV 7
|
||||
#define RK818_IRQ_PLUG_IN 8
|
||||
#define RK818_IRQ_PLUG_OUT 9
|
||||
#define RK818_IRQ_CHG_OK 10
|
||||
#define RK818_IRQ_CHG_TE 11
|
||||
#define RK818_IRQ_CHG_TS1 12
|
||||
#define RK818_IRQ_TS2 13
|
||||
#define RK818_IRQ_CHG_CVTLIM 14
|
||||
#define RK818_IRQ_DISCHG_ILIM 15
|
||||
|
||||
#define RK818_IRQ_VOUT_LO_MSK BIT(0)
|
||||
#define RK818_IRQ_VB_LO_MSK BIT(1)
|
||||
#define RK818_IRQ_PWRON_MSK BIT(2)
|
||||
#define RK818_IRQ_PWRON_LP_MSK BIT(3)
|
||||
#define RK818_IRQ_HOTDIE_MSK BIT(4)
|
||||
#define RK818_IRQ_RTC_ALARM_MSK BIT(5)
|
||||
#define RK818_IRQ_RTC_PERIOD_MSK BIT(6)
|
||||
#define RK818_IRQ_USB_OV_MSK BIT(7)
|
||||
#define RK818_IRQ_PLUG_IN_MSK BIT(0)
|
||||
#define RK818_IRQ_PLUG_OUT_MSK BIT(1)
|
||||
#define RK818_IRQ_CHG_OK_MSK BIT(2)
|
||||
#define RK818_IRQ_CHG_TE_MSK BIT(3)
|
||||
#define RK818_IRQ_CHG_TS1_MSK BIT(4)
|
||||
#define RK818_IRQ_TS2_MSK BIT(5)
|
||||
#define RK818_IRQ_CHG_CVTLIM_MSK BIT(6)
|
||||
#define RK818_IRQ_DISCHG_ILIM_MSK BIT(7)
|
||||
|
||||
#define RK818_NUM_IRQ 16
|
||||
|
||||
#define RK808_VBAT_LOW_2V8 0x00
|
||||
#define RK808_VBAT_LOW_2V9 0x01
|
||||
#define RK808_VBAT_LOW_3V0 0x02
|
||||
@ -191,9 +319,17 @@ enum {
|
||||
BOOST_ILMIN_250MA,
|
||||
};
|
||||
|
||||
enum {
|
||||
RK808_ID = 0x0000,
|
||||
RK818_ID = 0x8181,
|
||||
};
|
||||
|
||||
struct rk808 {
|
||||
struct i2c_client *i2c;
|
||||
struct regmap_irq_chip_data *irq_data;
|
||||
struct regmap *regmap;
|
||||
long variant;
|
||||
const struct regmap_config *regmap_cfg;
|
||||
const struct regmap_irq_chip *regmap_irq_chip;
|
||||
};
|
||||
#endif /* __LINUX_REGULATOR_rk808_H */
|
||||
#endif /* __LINUX_REGULATOR_RK808_H */
|
||||
|
@ -43,8 +43,10 @@
|
||||
#define EXYNOS5433_MIPI_PHY2_CONTROL (0x718)
|
||||
|
||||
#define EXYNOS5_PHY_ENABLE BIT(0)
|
||||
|
||||
#define EXYNOS5_MIPI_PHY_S_RESETN BIT(1)
|
||||
#define EXYNOS5_MIPI_PHY_M_RESETN BIT(2)
|
||||
|
||||
#define EXYNOS5433_PAD_RETENTION_AUD_OPTION (0x3028)
|
||||
#define EXYNOS5433_PAD_INITIATE_WAKEUP_FROM_LOWPWR BIT(28)
|
||||
|
||||
#endif /* _LINUX_MFD_SYSCON_PMU_EXYNOS5_H_ */
|
||||
|
@ -73,6 +73,7 @@
|
||||
#define TPS65217_PPATH_AC_CURRENT_MASK 0x0C
|
||||
#define TPS65217_PPATH_USB_CURRENT_MASK 0x03
|
||||
|
||||
#define TPS65217_INT_RESERVEDM BIT(7)
|
||||
#define TPS65217_INT_PBM BIT(6)
|
||||
#define TPS65217_INT_ACM BIT(5)
|
||||
#define TPS65217_INT_USBM BIT(4)
|
||||
@ -233,6 +234,13 @@ struct tps65217_bl_pdata {
|
||||
int dft_brightness;
|
||||
};
|
||||
|
||||
enum tps65217_irq_type {
|
||||
TPS65217_IRQ_PB,
|
||||
TPS65217_IRQ_AC,
|
||||
TPS65217_IRQ_USB,
|
||||
TPS65217_NUM_IRQ
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tps65217_board - packages regulator init data
|
||||
* @tps65217_regulator_data: regulator initialization values
|
||||
@ -258,6 +266,10 @@ struct tps65217 {
|
||||
struct regulator_desc desc[TPS65217_NUM_REGULATOR];
|
||||
struct regmap *regmap;
|
||||
u8 *strobes;
|
||||
struct irq_domain *irq_domain;
|
||||
struct mutex irq_lock;
|
||||
u8 irq_mask;
|
||||
int irq;
|
||||
};
|
||||
|
||||
static inline struct tps65217 *dev_to_tps65217(struct device *dev)
|
||||
|
@ -168,7 +168,7 @@
|
||||
#define TWL6040_VIBROCDET 0x20
|
||||
#define TWL6040_TSHUTDET 0x40
|
||||
|
||||
#define TWL6040_CELLS 3
|
||||
#define TWL6040_CELLS 4
|
||||
|
||||
#define TWL6040_REV_ES1_0 0x00
|
||||
#define TWL6040_REV_ES1_1 0x01 /* Rev ES1.1 and ES1.2 */
|
||||
|
Loading…
Reference in New Issue
Block a user