aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinaro CI <ci_notify@linaro.org>2018-11-08 21:20:22 +0000
committerLinaro CI <ci_notify@linaro.org>2018-11-08 21:20:22 +0000
commitd2b6ef17ae073654a17ca9ebc676c9e7f67f122d (patch)
tree4ace927a119c58ccce33960459ed970bd18b72e6
parent2496bb8a4d12d2923323e0cade7e849fe7edc2d8 (diff)
parent4aedcff1504e2d4242739c8c2c5fdcb2ec20b7db (diff)
Merge remote-tracking branch 'db600c/qcomlt-db600c' into integration-linux-qcomlt
# Conflicts: # drivers/regulator/Kconfig # drivers/regulator/Makefile
-rw-r--r--Documentation/devicetree/bindings/pci/qcom,pcie.txt1
-rw-r--r--Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt31
-rw-r--r--arch/arm/boot/dts/Makefile1
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-db600c.dts572
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c21
-rw-r--r--drivers/regulator/Kconfig12
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/qcom_saw-regulator.c229
8 files changed, 867 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
index 1fd703bd73e0..756cbd69b219 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
@@ -88,6 +88,7 @@
Definition: Should contain the following entries
- "core" Clocks the pcie hw block
- "phy" Clocks the pcie PHY block
+ - "ref" Clocks the pcie refclk
- clock-names:
Usage: required for apq8084/ipq4019
Value type: <stringlist>
diff --git a/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
new file mode 100644
index 000000000000..977fec08b2ae
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/qcom,saw-regulator.txt
@@ -0,0 +1,31 @@
+Qualcomm SAW Regulators
+
+SAW (Subsystem Power Manager and Adaptive Voltage Scaling Wrapper) is a hardware
+block in the Qualcomm chipsets that regulates the power to the CPU cores on devices
+such as APQ8064, MSM8974, APQ8084 and others.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,apq8064-saw2-v1.1-regulator"
+
+Example:
+ saw0: power-controller@2089000 {
+ compatible = "qcom,apq8064-saw2-v1.1-cpu", "qcom,saw2", "syscon", "simple-mfd";
+ reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ saw0_regulator: regulator@2089000 {
+ compatible = "qcom,apq8064-saw2-v1.1-regulator";
+ regulator-always-on;
+ regulator-min-microvolt = <825000>;
+ regulator-max-microvolt = <1250000>;
+ };
+ };
+
+
+ &CPU0 {
+ cpu-supply = <&saw0_regulator>;
+ };
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b0e966d625b9..87ad006b729f 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -788,6 +788,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-apq8064-ifc6410.dtb \
qcom-apq8064-sony-xperia-yuga.dtb \
qcom-apq8064-asus-nexus7-flo.dtb \
+ qcom-apq8064-db600c.dtb \
qcom-apq8074-dragonboard.dtb \
qcom-apq8084-ifc6540.dtb \
qcom-apq8084-mtp.dtb \
diff --git a/arch/arm/boot/dts/qcom-apq8064-db600c.dts b/arch/arm/boot/dts/qcom-apq8064-db600c.dts
new file mode 100644
index 000000000000..1e3895a98727
--- /dev/null
+++ b/arch/arm/boot/dts/qcom-apq8064-db600c.dts
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "qcom-apq8064-v2.0.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+#include <dt-bindings/mfd/qcom-rpm.h>
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
+
+/ {
+ model = "Qualcomm Technologies, Inc. DB600c";
+ compatible = "arrow,apq8064-db600c", "qcom,apq8064";
+
+ aliases {
+ serial0 = &gsbi7_serial;
+ serial1 = &gsbi1_serial;
+ serial2 = &gsbi6_serial;
+ i2c0 = &gsbi2_i2c;
+ i2c1 = &gsbi3_i2c;
+ i2c2 = &gsbi4_i2c;
+ i2c3 = &gsbi7_i2c;
+ spi0 = &gsbi5_spi;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ vph: regulator-fixed@1 {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <4500000>;
+ regulator-max-microvolt = <4500000>;
+ regulator-name = "VPH";
+ regulator-type = "voltage";
+ regulator-boot-on;
+ };
+
+ /* on board fixed 3.3v supply */
+ vcc3v3: vcc3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "VCC3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ };
+
+ clocks {
+ compatible = "simple-bus";
+ pcie_refclk: pcie-refclk {
+ pinctrl-0 = <&pcie_pins>;
+ pinctrl-names = "default";
+ compatible = "gpio-gate-clock";
+ clocks = <&rpmcc RPM_XO_A0>;
+ #clock-cells = <0>;
+ enable-gpios = <&pm8921_gpio 22 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ hdmi-out {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con: endpoint {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
+ };
+
+ soc {
+ pinctrl@800000 {
+ card_detect: card_detect {
+ mux {
+ pins = "gpio26";
+ function = "gpio";
+ bias-disable;
+ };
+ };
+
+ user_leds: user-leds {
+ mux {
+ pins = "gpio6", "gpio7", "gpio35", "gpio86";
+ function = "gpio";
+ };
+
+ conf {
+ pins = "gpio6", "gpio7", "gpio35", "gpio86";
+ function = "gpio";
+ output-low;
+ };
+ };
+
+ i2c1 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ i2c2 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ i2c3 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ i2c4 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ i2c5 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ i2c6 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ i2c7 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ i2c1 {
+ pinconf {
+ drive-strength = <8>;
+ };
+ };
+
+ spi5_default {
+ pinconf {
+ drive-strength = <8>;
+ };
+
+ pinconf_cs {
+ drive-strength = <8>;
+ };
+ };
+ };
+
+ qcom,ssbi@500000 {
+ pmic@0 {
+ gpio@150 {
+ pcie_pins: pcie_pins {
+ pios {
+ pins = "gpio22";
+ function = "normal";
+ power-source = <PM8921_GPIO_VPH>;
+ };
+ };
+ };
+
+ mpps@50 {
+ pcie_perst: pcie-perst {
+ pinconf {
+ pins = "mpp1";
+ function = "digital";
+ power-source = <PM8921_MPP_S4>;
+ output-low;
+ };
+ };
+
+ mpp_leds: mpp-leds {
+ pinconf {
+ pins = "mpp7", "mpp8", "mpp9", "mpp10", "mpp11", "mpp12";
+ function = "digital";
+ power-source = <PM8921_MPP_VPH>;
+ drive-strength = <12>;
+ output-high;
+ };
+ };
+ };
+ };
+ };
+
+ rpm@108000 {
+ regulators {
+ vdd_s1-supply = <&vph>;
+ vdd_s2-supply = <&vph>;
+ vdd_s3-supply = <&vph>;
+ vdd_s4-supply = <&vph>;
+ vdd_s5-supply = <&vph>;
+ vdd_s6-supply = <&vph>;
+ vdd_s7-supply = <&vph>;
+
+ vdd_l1_l2_l12_l18-supply = <&pm8921_s4>;
+ vdd_l3_l15_l17-supply = <&vph>;
+ vdd_l4_l14-supply = <&vph>;
+ vdd_l5_l8_l16-supply = <&vph>;
+ vdd_l6_l7-supply = <&vph>;
+ vdd_l9_l11-supply = <&vph>;
+ vdd_l10_l22-supply = <&vph>;
+ vdd_l21_l23_l29-supply = <&vph>;
+
+ vdd_l24-supply = <&pm8921_s1>;
+ vdd_l25-supply = <&pm8921_s1>;
+ vdd_l26-supply = <&pm8921_s7>;
+ vdd_l27-supply = <&pm8921_s7>;
+ vdd_l28-supply = <&pm8921_s7>;
+
+ vin_lvs1_3_6-supply = <&pm8921_s4>;
+ vin_lvs2-supply = <&pm8921_s1>;
+ vin_lvs4_5_7-supply = <&pm8921_s4>;
+
+ s1 {
+ regulator-always-on;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ qcom,switch-mode-frequency = <3200000>;
+ bias-pull-down;
+ };
+
+ s2 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <1600000>;
+ bias-pull-down;
+ regulator-always-on;
+ };
+
+ s3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ qcom,switch-mode-frequency = <4800000>;
+ };
+
+ s4 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,switch-mode-frequency = <1600000>;
+ qcom,force-mode = <QCOM_RPM_FORCE_MODE_AUTO>;
+ bias-pull-down;
+ regulator-always-on;
+ };
+
+ s7 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ qcom,switch-mode-frequency = <3200000>;
+ };
+
+ l3 {
+ regulator-min-microvolt = <3050000>;
+ regulator-max-microvolt = <3300000>;
+ bias-pull-down;
+ };
+
+ l4 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1800000>;
+ bias-pull-down;
+ };
+
+ l5 {
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <3000000>;
+ bias-pull-down;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ l6 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ bias-pull-down;
+ };
+
+ l7 {
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ /**
+ /**
+ * 1.8v required on LS expansion
+ * for mezzanine boards
+ */
+ l15 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ l23 {
+ regulator-min-microvolt = <1700000>;
+ regulator-max-microvolt = <1900000>;
+ bias-pull-down;
+ };
+
+ l26 {
+ regulator-min-microvolt = < 375000>;
+ regulator-max-microvolt = <1050000>;
+ bias-pull-down;
+ };
+
+ lvs6 {
+ bias-pull-down;
+ };
+
+ lvs7 {
+ bias-pull-down;
+ };
+ };
+ };
+
+ gsbi@12440000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_UART_W_FC>;
+ serial@12450000 {
+ label = "LS-UART1";
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi1_uart_4pins>;
+ };
+ };
+
+ pil_q6v4: pil@28800000 {
+ qcom,pll-supply = <&pm8921_l26>;
+ qcom,pll-uV = <1050000>;
+ };
+
+ gsbi@12480000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_I2C>;
+ i2c@124a0000 {
+ /* On Low speed expansion and Sensors */
+ label = "LS-I2C0";
+ status = "okay";
+ };
+ };
+
+ gsbi@16200000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_I2C>;
+ i2c@16280000 {
+ /* On Low speed expansion */
+ status = "okay";
+ label = "LS-I2C1";
+ clock-frequency = <200000>;
+ eeprom@52 {
+ compatible = "atmel,24c128";
+ reg = <0x52>;
+ pagesize = <64>;
+ };
+ };
+ };
+
+ gsbi@16300000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_I2C>;
+ i2c@16380000 {
+ /* On High speed expansion */
+ label = "HS-CAM-I2C3";
+ status = "okay";
+ };
+ };
+
+ gsbi@1a200000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_SPI>;
+ spi@1a280000 {
+ /* On Low speed expansion */
+ label = "LS-SPI0";
+ status = "okay";
+ num-cs = <1>;
+ cs-gpios = <&tlmm_pinmux 53 0>;
+ spi-sram@0 {
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible= "microchip,mchp23lcv1024";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+ };
+ };
+ };
+
+ gsbi@16500000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_UART_W_FC>;
+ serial@16540000 {
+ label = "BT-UART";
+ status = "okay";
+ pinctrl-name = "default";
+ pinctrl-0 = <&gsbi6_uart_4pins>;
+ };
+ };
+
+
+ /* DEBUG UART */
+ gsbi@16600000 {
+ status = "okay";
+ qcom,mode = <GSBI_PROT_I2C_UART>;
+ serial@16640000 {
+ label = "LS-UART0";
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi7_uart_2pins>;
+
+ };
+
+ i2c@16680000 {
+ /* On High speed expansion */
+ status = "okay";
+ label = "HS-CAM-I2C2";
+ };
+ };
+
+ leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&user_leds>, <&mpp_leds>;
+
+ compatible = "gpio-leds";
+
+ user-led0 {
+ label = "user0-led";
+ gpios = <&pm8921_mpps 9 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ user-led1 {
+ label = "user1-led";
+ gpios = <&pm8921_mpps 10 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+
+ user-led2 {
+ label = "user2-led";
+ gpios = <&pm8921_mpps 11 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc1";
+ default-state = "off";
+ };
+
+ user-led3 {
+ label = "user3-led";
+ gpios = <&pm8921_mpps 12 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "none";
+ default-state = "off";
+ };
+
+ wifi-led {
+ label = "WiFi-led";
+ gpios = <&pm8921_mpps 7 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ linux,default-trigger = "none";
+ };
+
+ bt-led {
+ label = "BT-led";
+ gpios = <&pm8921_mpps 8 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ linux,default-trigger = "none";
+ };
+ };
+
+ pci@1b500000 {
+ status = "okay";
+ vdda-supply = <&pm8921_s3>;
+ vdda_phy-supply = <&pm8921_lvs6>;
+ vdda_refclk-supply = <&vcc3v3>;
+ pinctrl-0 = <&pcie_perst>;
+ pinctrl-names = "default";
+ perst-gpio = <&pm8921_mpps 1 GPIO_ACTIVE_LOW>;
+ clocks = <&gcc PCIE_A_CLK>,
+ <&gcc PCIE_H_CLK>,
+ <&gcc PCIE_PHY_REF_CLK>,
+ <&pcie_refclk>;
+ clock-names = "core", "iface", "phy", "ref";
+ };
+
+ /* OTG */
+ usb@12500000 {
+ status = "okay";
+ dr_mode = "otg";
+ ulpi {
+ phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l4>;
+ };
+ };
+ };
+
+ usb@12520000 {
+ status = "okay";
+ dr_mode = "host";
+ ulpi {
+ phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+ };
+ };
+ };
+
+ usb@12530000 {
+ status = "okay";
+ dr_mode = "host";
+ ulpi {
+ phy {
+ v3p3-supply = <&pm8921_l3>;
+ v1p8-supply = <&pm8921_l23>;
+ };
+ };
+ };
+
+ amba {
+ /* eMMC */
+ sdcc1: sdcc@12400000 {
+ status = "okay";
+ vmmc-supply = <&pm8921_l5>;
+ vqmmc-supply = <&pm8921_s4>;
+ };
+
+ /* External micro SD card */
+ sdcc3: sdcc@12180000 {
+ status = "okay";
+ vmmc-supply = <&pm8921_l6>;
+ vqmmc-supply = <&pm8921_l7>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdcc3_pins &card_detect>;
+ cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ hdmi-tx@4a00000 {
+ status = "okay";
+ core-vdda-supply = <&pm8921_hdmi_switch>;
+ hdmi-mux-supply = <&vcc3v3>;
+
+ hpd-gpio = <&tlmm_pinmux 72 GPIO_ACTIVE_HIGH>;
+
+ ports {
+ port@1 {
+ endpoint {
+ remote-endpoint = <&hdmi_con>;
+ };
+ };
+ };
+ };
+
+ hdmi-phy@4a00400 {
+ status = "okay";
+ core-vdda-supply = <&pm8921_hdmi_switch>;
+ };
+
+ mdp@5100000 {
+ status = "okay";
+
+ ports {
+ port@3 {
+ endpoint {
+ remote-endpoint = <&hdmi_in>;
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index e21ea1a2f6d3..b9f60e4ebb96 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -85,6 +85,7 @@
struct qcom_pcie_resources_2_1_0 {
struct clk *iface_clk;
struct clk *core_clk;
+ struct clk *ref_clk;
struct clk *phy_clk;
struct reset_control *pci_reset;
struct reset_control *axi_reset;
@@ -227,6 +228,15 @@ static int qcom_pcie_get_resources_2_1_0(struct qcom_pcie *pcie)
if (IS_ERR(res->iface_clk))
return PTR_ERR(res->iface_clk);
+ res->ref_clk = devm_clk_get(dev, "ref");
+
+ if (IS_ERR(res->ref_clk)) {
+ if (PTR_ERR(res->ref_clk) == -EPROBE_DEFER)
+ return PTR_ERR(res->ref_clk);
+
+ res->ref_clk = NULL;
+ }
+
res->core_clk = devm_clk_get(dev, "core");
if (IS_ERR(res->core_clk))
return PTR_ERR(res->core_clk);
@@ -265,6 +275,7 @@ static void qcom_pcie_deinit_2_1_0(struct qcom_pcie *pcie)
reset_control_assert(res->por_reset);
reset_control_assert(res->pci_reset);
clk_disable_unprepare(res->iface_clk);
+ clk_disable_unprepare(res->ref_clk);
clk_disable_unprepare(res->core_clk);
clk_disable_unprepare(res->phy_clk);
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
@@ -290,10 +301,16 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
goto err_assert_ahb;
}
+ ret = clk_prepare_enable(res->ref_clk);
+ if (ret) {
+ dev_err(dev, "cannot prepare/enable ref clock\n");
+ goto err_assert_ahb;
+ }
+
ret = clk_prepare_enable(res->iface_clk);
if (ret) {
dev_err(dev, "cannot prepare/enable iface clock\n");
- goto err_assert_ahb;
+ goto err_clk_iface;
}
ret = clk_prepare_enable(res->phy_clk);
@@ -366,6 +383,8 @@ err_clk_core:
clk_disable_unprepare(res->phy_clk);
err_clk_phy:
clk_disable_unprepare(res->iface_clk);
+err_clk_iface:
+ clk_disable_unprepare(res->ref_clk);
err_assert_ahb:
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 926cee0d0b5f..cabcbe982a83 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -698,6 +698,18 @@ config REGULATOR_QCOM_RPMH
control allows for voting on regulator state between multiple
processors within the SoC.
+config REGULATOR_QCOM_SAW
+ tristate "Qualcomm SAW regulator driver"
+ depends on (ARCH_QCOM || COMPILE_TEST) && MFD_SYSCON
+ help
+ If you say yes to this option, support will be included for the
+ regulators providing power to the CPU cores on devices such as
+ APQ8064.
+
+ Say M here if you want to include support for the CPU core voltage
+ regulators as a module. The module will be named
+ "qcom_saw-regulator".
+
config REGULATOR_QCOM_SMD_RPM
tristate "Qualcomm SMD based RPM regulator driver"
depends on QCOM_SMD_RPM
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 72488ef11b8a..499a1620b5e8 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -80,6 +80,7 @@ obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
+obj-$(CONFIG_REGULATOR_QCOM_SAW) += qcom_saw-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
diff --git a/drivers/regulator/qcom_saw-regulator.c b/drivers/regulator/qcom_saw-regulator.c
new file mode 100644
index 000000000000..c1411885680e
--- /dev/null
+++ b/drivers/regulator/qcom_saw-regulator.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016, Linaro Limited. All rights reserved.
+ *
+ * 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.
+ *
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+
+#define SPM_REG_STS_1 0x10
+#define SPM_REG_VCTL 0x14
+#define SPM_REG_PMIC_DATA_0 0x28
+#define SPM_REG_PMIC_DATA_1 0x2c
+#define SPM_REG_RST 0x30
+
+struct saw_vreg {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regulator_desc rdesc;
+ struct regulator_dev *rdev;
+ unsigned int sel;
+};
+
+struct spm_vlevel_data {
+ struct saw_vreg *vreg;
+ unsigned int sel;
+};
+
+static int saw_regulator_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct saw_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->sel;
+}
+
+static void smp_set_vdd(void *data)
+{
+ struct spm_vlevel_data *vdata = (struct spm_vlevel_data *)data;
+ struct saw_vreg *vreg = vdata->vreg;
+ unsigned long new_sel = vdata->sel;
+ u32 val, new_val;
+ u32 vctl, data0, data1;
+ unsigned long timeout;
+
+ if (vreg->sel == new_sel)
+ return;
+
+ regmap_read(vreg->regmap, SPM_REG_VCTL, &vctl);
+ regmap_read(vreg->regmap, SPM_REG_PMIC_DATA_0, &data0);
+ regmap_read(vreg->regmap, SPM_REG_PMIC_DATA_1, &data1);
+
+ /* select the band */
+ val = 0x80 | new_sel;
+
+ vctl &= ~0xff;
+ vctl |= val;
+
+ data0 &= ~0xff;
+ data0 |= val;
+
+ data1 &= ~0x3f;
+ data1 |= val & 0x3f;
+ data1 &= ~0x3f0000;
+ data1 |= ((val & 0x3f) << 16);
+
+ regmap_write(vreg->regmap, SPM_REG_RST, 1);
+ regmap_write(vreg->regmap, SPM_REG_VCTL, vctl);
+ regmap_write(vreg->regmap, SPM_REG_PMIC_DATA_0, data0);
+ regmap_write(vreg->regmap, SPM_REG_PMIC_DATA_1, data1);
+
+ timeout = jiffies + usecs_to_jiffies(100);
+ do {
+ regmap_read(vreg->regmap, SPM_REG_STS_1, &new_val);
+ new_val &= 0xff;
+ if (new_val == val) {
+ vreg->sel = new_sel;
+ return;
+ }
+
+ cpu_relax();
+
+ } while (time_before(jiffies, timeout));
+
+ pr_err("%s: Voltage not changed: %#x\n", __func__, new_val);
+}
+
+static int saw_regulator_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned selector)
+{
+ struct saw_vreg *vreg = rdev_get_drvdata(rdev);
+ struct spm_vlevel_data data;
+ int cpu = rdev_get_id(rdev);
+
+ data.vreg = vreg;
+ data.sel = selector;
+
+ return smp_call_function_single(cpu, smp_set_vdd, &data, true);
+}
+
+static struct regulator_ops saw_regulator_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_voltage_sel = saw_regulator_set_voltage_sel,
+ .get_voltage_sel = saw_regulator_get_voltage_sel,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+};
+
+static struct regulator_desc saw_regulator = {
+ .owner = THIS_MODULE,
+ .type = REGULATOR_VOLTAGE,
+ .ops = &saw_regulator_ops,
+ .linear_ranges = (struct regulator_linear_range[]) {
+ REGULATOR_LINEAR_RANGE(700000, 0, 56, 12500),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 57,
+ .ramp_delay = 1250,
+};
+
+static struct saw_vreg *saw_get_drv(struct platform_device *pdev,
+ int *vreg_cpu)
+{
+ struct saw_vreg *vreg = NULL;
+ struct device_node *cpu_node, *saw_node;
+ int cpu;
+ bool found;
+
+ for_each_possible_cpu(cpu) {
+ cpu_node = of_cpu_device_node_get(cpu);
+ if (!cpu_node)
+ continue;
+ saw_node = of_parse_phandle(cpu_node, "qcom,saw", 0);
+ found = (saw_node == pdev->dev.of_node->parent);
+ of_node_put(saw_node);
+ of_node_put(cpu_node);
+ if (found)
+ break;
+ }
+
+ if (found) {
+ vreg = devm_kzalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
+ if (vreg)
+ *vreg_cpu = cpu;
+ }
+
+ return vreg;
+}
+
+static const struct of_device_id qcom_saw_regulator_match[] = {
+ { .compatible = "qcom,apq8064-saw2-v1.1-regulator" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qcom_saw_regulator_match);
+
+static int qcom_saw_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *saw_np;
+ struct saw_vreg *vreg;
+ struct regulator_config config = { };
+ int ret = 0, cpu = 0;
+ char name[] = "kraitXX";
+
+ vreg = saw_get_drv(pdev, &cpu);
+ if (!vreg)
+ return -EINVAL;
+
+ saw_np = of_get_parent(np);
+ if (!saw_np)
+ return -ENODEV;
+
+ vreg->regmap = syscon_node_to_regmap(saw_np);
+ of_node_put(saw_np);
+ if (IS_ERR(config.regmap))
+ return PTR_ERR(config.regmap);
+
+ snprintf(name, sizeof(name), "krait%d", cpu);
+
+ config.regmap = vreg->regmap;
+ config.dev = &pdev->dev;
+ config.of_node = np;
+ config.driver_data = vreg;
+
+ vreg->rdesc = saw_regulator;
+ vreg->rdesc.id = cpu;
+ vreg->rdesc.name = kstrdup_const(name, GFP_KERNEL);
+ config.init_data = of_get_regulator_init_data(&pdev->dev,
+ pdev->dev.of_node,
+ &vreg->rdesc);
+
+ vreg->rdev = devm_regulator_register(&pdev->dev, &vreg->rdesc, &config);
+ if (IS_ERR(vreg->rdev)) {
+ ret = PTR_ERR(vreg->rdev);
+ dev_err(dev, "failed to register SAW regulator: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver qcom_saw_regulator_driver = {
+ .driver = {
+ .name = "qcom-saw-regulator",
+ .of_match_table = qcom_saw_regulator_match,
+ },
+ .probe = qcom_saw_regulator_probe,
+};
+
+module_platform_driver(qcom_saw_regulator_driver);
+
+MODULE_ALIAS("platform:qcom-saw-regulator");
+MODULE_DESCRIPTION("Qualcomm SAW regulator driver");
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_LICENSE("GPL v2");