Merge "USB: ehci-msm-hsic: Make driver less verbose"
diff --git a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt b/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
deleted file mode 100644
index 01301be..0000000
--- a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-* MSM PC Debug Counters
-
-MSM PC debug counter reserves 16 registers in the IMEM memory space which
-maintains a count on the state of power collapse on each core. This count
-will be useful to debug the power collapse state on each core.
-
-The required nodes for MSM PC Debug Counters are:
-
-- compatible: "qcom,pc-cntr"
-- reg: physical IMEM address reserved for PC counters
-
-Example:
-
-qcom,pc-cntr@fe800000 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe800664 0x40>;
- };
-
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index b429072..a372912 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -5,6 +5,9 @@
the kernel to be notified of idle and suspend states and when called, follows
through the set of instructions in putting the application cores to the lowest
power mode possible.
+The PC debug counter reserves 16 registers in the IMEM memory space which maintains
+a count on the state of power collapse on each core. This count will be useful to
+debug the power collapse state on each core.
The required properties for PM-8x60 are:
@@ -12,17 +15,22 @@
The optional properties are:
+- reg: physical IMEM address reserved for PC counters and the size
- qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
- qcom,pc-mode: Indicates the type of power collapse used by the target. The
- valid values for this are:
+ valid values for this are:
0 (Power collapse terminates in TZ; integrated L2 cache controller)
1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
2 (Power collapse terminates in TZ; external L2 cache controller)
+- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
+ doing power collapse and so the core need to switch to Global PLL before
+ PC.
Example:
-qcom,pm-8x60 {
+qcom,pm-8x60@fe800664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe800664 0x40>;
qcom,pc-mode = <0>;
qcom,use-sync-timer;
};
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 939f77b..4b912f3 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -1,25 +1,51 @@
Qualcomm Serial Peripheral Interface (SPI)
Required properties:
-- compatible : should be "qcom,spi-qup-v2".
-- reg : offset and length of the QUP register map.
-- interrupts : should contain the QUP core interrupt.
-- spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
+- compatible : Should be "qcom,spi-qup-v2".
+- reg : Offset and length of the register regions for the device
+- reg-names : Register region names referenced in reg above.
+ Required register resource entries are:
+ "spi_physical" : Physical address of controller register blocks.
+- interrupts : Interrupt numbers used by this controller
+- interrupt-names : Interrupt resource names referenced in interrupts above.
+ Required interrupt resource entries are:
+ "spi_irq" : QUP-core interrupt.
+- spi-max-frequency : Specifies maximum SPI clock frequency, Units - Hz.
+
+Required alias:
+- The desired bus-number is specified via an alias with the following format
+ 'spi{n}' where n is the bus number.
Optional properties:
-- gpios : specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
+- gpios : Specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
that order.
-- cs-gpios : specifies the gpio pins to be used for chipselects.
+- cs-gpios : Specifies the gpio pins to be used for chipselects.
+- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
+ value is non-zero, the value is the number of words in maximum transfer
+ length.
-SPI slave nodes must be children of the SPI master node and contain
+Optional properties which are required for support of BAM-mode:
+- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
+ version support latest features (e.g. BAM) and then enable them. Should be
+ removed for legacy HW.
+- qcom,use-bam : Boolean. When present, enables BAM-mode.
+- qcom,bam-consumer-pipe-index : BAM consumer-pipe index.
+- qcom,bam-producer-pipe-index : BAM producer-pipe index.
+- reg-names : register region names referenced in reg.
+ Required register resource for BAM are:
+ "spi_bam_physical" : Physical address of BAM for this controller.
+- interrupt-names : interrupt resource names referenced in interrupts.
+ Required interrupt resource from BAM are:
+ "spi_bam_irq" : BAM interrupt used by the controller.
+
+Optional SPI slave nodes must be children of the SPI master node and contain
the following properties.
-- reg : (required) chip select address of device.
-- compatible : (required) name of SPI device following generic names
- recommended practice
+- reg: (required) chip-select address of the device.
+- compatible : (required) Name of SPI device following generic names.
- spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz
-- interrupts : (recommended) should contain the SPI slave interrupt number
+- interrupts : (recommended) Should contain the SPI slave interrupt number
encoded depending on the type of the interrupt controller.
-- interrupt-parent : (recommended) the phandle for the interrupt controller
+- interrupt-parent : (recommended) The phandle for the interrupt controller
that services interrupts for this device.
- spi-cpol : (optional) Empty property indicating device requires inverse
clock polarity (CPOL) mode
@@ -29,18 +55,30 @@
chip select active high
Example:
- spi@f9924000 {
- compatible = "qcom,spi-qup-v2";
- reg = <0xf9924000 0x1000>;
- interrupts = <0 96 0>;
- spi-max-frequency = <24000000>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- device@0 {
- compatible = "spidev";
- reg = <0>;
- spi-max-frequency = <5000000>;
- };
+ aliases {
+ spi0 = &spi_0;
};
+ spi_0: spi@f9923000 {
+ compatible = "qcom,spi-qup-v2";
+
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0x10000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+
+ spi-max-frequency = <19200000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 9 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ qcom,ver-reg-exists;
+ };
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9b9e33..2de5fad 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -419,13 +419,9 @@
<40 95>;
};
- qcom,pc-cntr@fe805664 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe805664 0x40>;
- };
-
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
index 584869d..c974884 100644
--- a/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-iommu.dtsi
@@ -71,6 +71,7 @@
};
venus_sec_bitstream: qcom,iommu-ctx@fdc8d000 {
+ qcom,iommu-ctx-sids = <0x80 0x81 0x82 0x83 0x84>;
label = "venus_sec_bitstream";
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 212812c..e6376d4 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -25,6 +25,11 @@
compatible = "qcom,msm8974";
interrupt-parent = <&intc>;
+ aliases {
+ spi0 = &spi_0;
+ spi7 = &spi_7;
+ };
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -381,9 +386,8 @@
qcom,bam-dma-res-pipes = <6>;
};
- spi_epm: spi@f9966000 {
+ spi_7: spi_epm: spi@f9966000 {
compatible = "qcom,spi-qup-v2";
- cell-index = <7>;
reg = <0xf9966000 0x1000>;
interrupts = <0 104 0>;
spi-max-frequency = <19200000>;
@@ -572,8 +576,7 @@
qcom,i2c-src-freq = <19200000>;
};
- spi@f9923000 {
- cell-index = <0>;
+ spi_0: spi@f9923000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9923000 0x1000>;
interrupts = <0 95 0>;
diff --git a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
new file mode 100644
index 0000000..8702184
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+ model = "Qualcomm MSM 9625V2.1 CDP";
+ compatible = "qcom,msm9625-cdp", "qcom,msm9625";
+ qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
+ <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
+ <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
+
+ i2c@f9925000 {
+ charger@57 {
+ compatible = "summit,smb137c";
+ reg = <0x57>;
+ summit,chg-current-ma = <1500>;
+ summit,term-current-ma = <50>;
+ summit,pre-chg-current-ma = <100>;
+ summit,float-voltage-mv = <4200>;
+ summit,thresh-voltage-mv = <3000>;
+ summit,recharge-thresh-mv = <75>;
+ summit,system-voltage-mv = <4250>;
+ summit,charging-timeout = <382>;
+ summit,pre-charge-timeout = <48>;
+ summit,therm-current-ua = <10>;
+ summit,temperature-min = <4>; /* 0 C */
+ summit,temperature-max = <3>; /* 45 C */
+ };
+ };
+
+ wlan0: qca,wlan {
+ cell-index = <0>;
+ compatible = "qca,ar6004-sdio";
+ qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+ qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+ qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+ };
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ /* ext_2p95v regulator enable config */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,invert = <0>; /* Output low */
+ qcom,out-strength = <1>; /* Low */
+ qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1-mtp.dts b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
new file mode 100644
index 0000000..2dc040c
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. 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.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+ model = "Qualcomm MSM 9625V2.1 MTP";
+ compatible = "qcom,msm9625-mtp", "qcom,msm9625";
+ qcom,msm-id = <134 7 0x20001>, <152 7 0x20001>, <149 7 0x20001>,
+ <150 7 0x20001>, <151 7 0x20001>, <148 7 0x20001>,
+ <173 7 0x20001>, <174 7 0x20001>, <175 7 0x20001>;
+
+ i2c@f9925000 {
+ charger@57 {
+ compatible = "summit,smb137c";
+ reg = <0x57>;
+ summit,chg-current-ma = <1500>;
+ summit,term-current-ma = <50>;
+ summit,pre-chg-current-ma = <100>;
+ summit,float-voltage-mv = <4200>;
+ summit,thresh-voltage-mv = <3000>;
+ summit,recharge-thresh-mv = <75>;
+ summit,system-voltage-mv = <4250>;
+ summit,charging-timeout = <382>;
+ summit,pre-charge-timeout = <48>;
+ summit,therm-current-ua = <10>;
+ summit,temperature-min = <4>; /* 0 C */
+ summit,temperature-max = <3>; /* 45 C */
+ };
+ };
+
+ wlan0: qca,wlan {
+ cell-index = <0>;
+ compatible = "qca,ar6004-sdio";
+ qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+ qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+ qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+ };
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ /* ext_2p95v regulator enable config */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,invert = <0>; /* Output low */
+ qcom,out-strength = <1>; /* Low */
+ qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1.dtsi b/arch/arm/boot/dts/msm9625-v2-1.dtsi
new file mode 100644
index 0000000..c3c2c49
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1.dtsi
@@ -0,0 +1,36 @@
+/* Copyright (c) 2013, The Linux Foundation. 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm9625.dtsi file.
+ */
+
+/include/ "msm9625.dtsi"
+
+/ {
+ qcom,msm-imem@fe807800 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
+ };
+
+ android_usb@fe8078c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfe8078c8 0xc8>;
+ qcom,android-usb-swfi-latency = <100>;
+ };
+};
+
+&ipa_hw {
+ qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d5a33ee..922616c 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -21,6 +21,10 @@
compatible = "qcom,msm9625";
interrupt-parent = <&intc>;
+ aliases {
+ spi0 = &spi_0;
+ };
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -186,8 +190,7 @@
interrupt-names = "bam_irq";
};
- spi@f9924000 {
- cell-index = <0>;
+ spi_0: spi@f9924000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9924000 0x1000>;
interrupts = <0 96 0>;
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 85b1bb3..8fb93d0 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -790,7 +790,7 @@
*/
if (cpu_pmu &&
cpu_pmu->plat_device->dev.platform_data) {
- irq = platform_get_irq(cpu_pmu->plat_device, 1);
+ irq = platform_get_irq(cpu_pmu->plat_device, 0);
smp_call_function_single((int)hcpu,
disable_irq_callback, &irq, 1);
}
@@ -803,7 +803,7 @@
*/
if (cpu_pmu &&
cpu_pmu->plat_device->dev.platform_data) {
- irq = platform_get_irq(cpu_pmu->plat_device, 1);
+ irq = platform_get_irq(cpu_pmu->plat_device, 0);
smp_call_function_single((int)hcpu,
enable_irq_callback, &irq, 1);
}
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b451d08..202b8dd 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -68,6 +68,8 @@
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v1-rumi.dtb
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-cdp.dtb
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-1-cdp.dtb
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index 5b72a3f..dd3f346 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -83,4 +83,5 @@
.pc_temp_ocv_lut = &desay_5200_pc_temp_ocv,
.pc_sf_lut = &desay_5200_pc_sf,
.default_rbatt_mohm = 156,
+ .rbatt_capacitive_mohm = 50,
};
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 824cf6b..0c39df6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -105,4 +105,5 @@
.pc_temp_ocv_lut = &pc_temp_ocv,
.rbatt_sf_lut = &rbatt_sf,
.default_rbatt_mohm = 236,
+ .rbatt_capacitive_mohm = 50,
};
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index a89ea61..beb064b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2723,7 +2723,6 @@
&apq8064_device_uart_gsbi1,
&apq8064_device_uart_gsbi4,
&msm_device_sps_apq8064,
- &msm8064_pc_cntr,
};
static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2888,7 +2887,6 @@
#ifdef CONFIG_MSM_ROTATOR
&msm_rotator_device,
#endif
- &msm8064_pc_cntr,
};
static struct platform_device
@@ -3861,11 +3859,13 @@
if (cpu_is_apq8064ab())
apq8064ab_update_krait_spm();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8064_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
apq8064ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+ platform_device_register(&msm8064_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index d974452..d045040 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -63,11 +63,9 @@
* hardware revisions - maybe once that is done, this can be
* reverted.
*/
- .always_on = 1,
.lpm_sup = 1,
.hpm_uA = 800000, /* 800mA */
.lpm_uA = 9000,
- .reset_at_init = true,
},
};
@@ -311,13 +309,11 @@
* This change to the boards will be true for newer versions of the SoC
* as well.
*/
- if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 1 &&
- SOCINFO_VERSION_MINOR(socinfo_get_version()) >= 2) ||
- machine_is_msm8930_cdp()) {
- msm8960_sdc3_data.vreg_data->vdd_data->always_on = false;
- msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = false;
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) == 1 &&
+ SOCINFO_VERSION_MINOR(socinfo_get_version()) < 2) {
+ msm8960_sdc3_data.vreg_data->vdd_data->always_on = true;
+ msm8960_sdc3_data.vreg_data->vdd_data->reset_at_init = true;
}
-
/* SDC3: External card slot */
if (!machine_is_msm8930_cdp()) {
msm8960_sdc3_data.wpswitch_gpio = 0;
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a8e117f..25ba1aa 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2473,7 +2473,6 @@
&msm8930_iommu_domain_device,
&msm_tsens_device,
&msm8930_cache_dump_device,
- &msm8930_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -2955,11 +2954,14 @@
msm8930_i2c_init();
msm8930_init_gpu();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8930_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
msm8930ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+
+ platform_device_register(&msm8930_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
msm8930_init_buses();
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6524832..95f618a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2955,7 +2955,6 @@
&msm8960_cache_dump_device,
&msm8960_iommu_domain_device,
&msm_tsens_device,
- &msm8960_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -3488,11 +3487,13 @@
if (cpu_is_msm8960ab())
msm8960ab_update_krait_spm();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8960_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
msm8960ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+ platform_device_register(&msm8960_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index c45cf11..02a753a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5299,6 +5299,7 @@
&msm_device_tz_log,
&msm_rtb_device,
&msm8660_iommu_domain_device,
+ &msm8660_pm_8x60,
};
#ifdef CONFIG_ION_MSM
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 77c91b8..e87c7b5 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. 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
@@ -72,18 +72,19 @@
struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
{
int ret = 0;
- int i = 0;
+ int i;
enum msm_pm_sleep_mode pm_mode;
- struct cpuidle_state_usage *st_usage = NULL;
cpu_pm_enter();
- pm_mode = msm_pm_idle_prepare(dev, drv, index);
- dev->last_residency = msm_pm_idle_enter(pm_mode);
+ pm_mode = msm_pm_idle_enter(dev, drv, index);
+
for (i = 0; i < dev->state_count; i++) {
- st_usage = &dev->states_usage[i];
- if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
- == pm_mode) {
+ struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
+ enum msm_pm_sleep_mode last_mode =
+ (enum msm_pm_sleep_mode)cpuidle_get_statedata(st_usage);
+
+ if (last_mode == pm_mode) {
ret = i;
break;
}
@@ -95,7 +96,7 @@
return ret;
}
-static void __init msm_cpuidle_set_states(void)
+static void __devinit msm_cpuidle_set_states(void)
{
int i = 0;
int state_count = 0;
@@ -151,7 +152,7 @@
dev->state_count = state_count; /* Per cpu state count */
}
-int __init msm_cpuidle_init(void)
+int __devinit msm_cpuidle_init(void)
{
unsigned int cpu = 0;
int ret = 0;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f87c540..10ee1e3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -49,6 +49,7 @@
#include <mach/mpm.h>
#include <mach/iommu_domains.h>
#include <mach/msm_cache_dump.h>
+#include "pm.h"
/* Address of GSBI blocks */
#define MSM_GSBI1_PHYS 0x12440000
@@ -120,11 +121,24 @@
},
};
-struct platform_device msm8064_pc_cntr = {
- .name = "pc-cntr",
+static uint32_t msm_pm_cp15_regs[] = {0x4501, 0x5501, 0x6501, 0x7501, 0x0500};
+
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+ .cp15_data.save_cp15 = true,
+ .cp15_data.qsb_pc_vdd = 0x98,
+ .cp15_data.reg_data = &msm_pm_cp15_regs[0],
+ .cp15_data.reg_saved_state_size = ARRAY_SIZE(msm_pm_cp15_regs),
+};
+
+struct platform_device msm8064_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8064_resources_pccntr),
.resource = msm8064_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
static struct msm_watchdog_pdata msm_watchdog_pdata = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index aad512e..6fe8ccb 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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
@@ -32,6 +32,7 @@
#include "rpm_rbcpr_stats.h"
#include "footswitch.h"
#include "acpuclock-krait.h"
+#include "pm.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -48,11 +49,18 @@
},
};
-struct platform_device msm8930_pc_cntr = {
- .name = "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+};
+
+struct platform_device msm8930_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8930_resources_pccntr),
.resource = msm8930_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index c3748fa..6a344be 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -53,6 +53,7 @@
#include <mach/msm_dcvs.h>
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
+#include "pm.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -116,11 +117,18 @@
},
};
-struct platform_device msm8960_pc_cntr = {
- .name = "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+};
+
+struct platform_device msm8960_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8960_resources_pccntr),
.resource = msm8960_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
static struct resource resources_otg[] = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 58416c7..cfa9281 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. 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
@@ -3181,3 +3181,9 @@
.platform_data = &msm8660_iommu_domain_pdata,
}
};
+
+struct platform_device msm8660_pm_8x60 = {
+ .name = "pm-8x60",
+ .id = -1,
+};
+
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index d3810a2..53eca3e 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
/* linux/arch/arm/mach-msm/devices.h
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -113,11 +113,11 @@
extern struct platform_device msm_device_sdc3;
extern struct platform_device msm_device_sdc4;
+extern struct platform_device msm8960_pm_8x60;
+extern struct platform_device msm8064_pm_8x60;
+extern struct platform_device msm8930_pm_8x60;
extern struct platform_device msm9615_pm_8x60;
-
-extern struct platform_device msm8960_pc_cntr;
-extern struct platform_device msm8064_pc_cntr;
-extern struct platform_device msm8930_pc_cntr;
+extern struct platform_device msm8660_pm_8x60;
extern struct platform_device msm_device_gadget_peripheral;
extern struct platform_device msm_device_hsusb_host;
diff --git a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
index 9cd4f3f..a183f0e 100644
--- a/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
+++ b/arch/arm/mach-msm/include/mach/usb_gadget_xport.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -19,6 +19,7 @@
USB_GADGET_XPORT_TTY,
USB_GADGET_XPORT_SDIO,
USB_GADGET_XPORT_SMD,
+ USB_GADGET_XPORT_QTI,
USB_GADGET_XPORT_BAM,
USB_GADGET_XPORT_BAM2BAM,
USB_GADGET_XPORT_BAM2BAM_IPA,
@@ -38,6 +39,8 @@
return "SDIO";
case USB_GADGET_XPORT_SMD:
return "SMD";
+ case USB_GADGET_XPORT_QTI:
+ return "QTI";
case USB_GADGET_XPORT_BAM:
return "BAM";
case USB_GADGET_XPORT_BAM2BAM:
@@ -63,6 +66,8 @@
return USB_GADGET_XPORT_SDIO;
if (!strncasecmp("SMD", name, XPORT_STR_LEN))
return USB_GADGET_XPORT_SMD;
+ if (!strncasecmp("QTI", name, XPORT_STR_LEN))
+ return USB_GADGET_XPORT_QTI;
if (!strncasecmp("BAM", name, XPORT_STR_LEN))
return USB_GADGET_XPORT_BAM;
if (!strncasecmp("BAM2BAM", name, XPORT_STR_LEN))
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index dec62f0..539a4fe 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -66,18 +66,12 @@
atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
MSM_LPM_STATE_ENTER, &sleep_data);
- ret = msm_rpm_enter_sleep();
- if (ret) {
- pr_warn("%s(): RPM failed to enter sleep err:%d\n",
- __func__, ret);
- goto bail;
- }
if (from_idle)
debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_IDLE_LIMITS;
+ MSM_LPM_LVL_DBG_IDLE_LIMITS;
else
debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
if (debug_mask)
pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
@@ -88,6 +82,19 @@
l->vdd_dig_upper_bound);
ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+ if (ret) {
+ pr_warn("%s() LPM resources failed to enter sleep\n",
+ __func__);
+ goto bail;
+ }
+ if (notify_rpm) {
+ ret = msm_rpm_enter_sleep(debug_mask);
+ if (ret) {
+ pr_warn("%s(): RPM failed to enter sleep err:%d\n",
+ __func__, ret);
+ goto bail;
+ }
+ }
bail:
return ret;
}
@@ -95,9 +102,11 @@
static void msm_lpm_exit_sleep(void *limits, bool from_idle,
bool notify_rpm, bool collapsed)
{
- msm_rpm_exit_sleep();
+
msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
from_idle, notify_rpm, collapsed);
+ if (notify_rpm)
+ msm_rpm_exit_sleep();
atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
MSM_LPM_STATE_EXIT, NULL);
}
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 5d7fc94..a62ee92 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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
@@ -668,7 +668,8 @@
}
msm_lpm_get_rpm_notif = true;
- msm_mpm_enter_sleep(sclk_count, from_idle);
+ if (notify_rpm)
+ msm_mpm_enter_sleep(sclk_count, from_idle);
return ret;
}
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index 0db6e68..a8d4fdb 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -37,15 +37,11 @@
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
return -ENOSYS;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
-{
- return -ENOSYS;
-}
-
void msm_pm_enable_retention(bool enable) {}
+
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 8c942ad..bbd0852 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -25,6 +25,7 @@
"0 msm: perf: add debug patch logging framework\n"
"1 Perf: Restore counter after powercollapse for generic ARM PMU's\n"
"2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
+ "3 Perf: Correct irq for CPU hotplug detection\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 7f8d3b9..0263faf 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -167,7 +167,7 @@
/* Assert Q6 resets */
val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
- val = (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
+ val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
/* Kill power at block headswitch */
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 0b08238..b52d284 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -40,7 +41,6 @@
#ifdef CONFIG_VFP
#include <asm/vfp.h>
#endif
-
#include "acpuclock.h"
#include "clock.h"
#include "avs.h"
@@ -54,9 +54,27 @@
#include <mach/event_timer.h>
#define CREATE_TRACE_POINTS
#include "trace_msm_low_power.h"
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
+
+#define SCM_L2_RETENTION (0x2)
+#define SCM_CMD_TERMINATE_PC (0x2)
+
+#define GET_CPU_OF_ATTR(attr) \
+ (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+#define NUM_OF_COUNTERS 3
+#define MAX_BUF_SIZE 512
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+ debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+ msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
enum {
MSM_PM_DEBUG_SUSPEND = BIT(0),
@@ -70,24 +88,12 @@
MSM_PM_DEBUG_HOTPLUG = BIT(8),
};
-static int msm_pm_debug_mask = 1;
-module_param_named(
- debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-static int msm_pm_retention_tz_call;
-
-/******************************************************************************
- * Sleep Modes and Parameters
- *****************************************************************************/
enum {
MSM_PM_MODE_ATTR_SUSPEND,
MSM_PM_MODE_ATTR_IDLE,
MSM_PM_MODE_ATTR_NR,
};
-#define SCM_L2_RETENTION (0x2)
-#define SCM_CMD_TERMINATE_PC (0x2)
-
static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -98,9 +104,6 @@
struct kobj_attribute ka;
};
-#define GET_CPU_OF_ATTR(attr) \
- (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
-
struct msm_pm_sysfs_sleep_mode {
struct kobject *kobj;
struct attribute_group attr_group;
@@ -116,10 +119,15 @@
"standalone_power_collapse",
};
-static struct msm_pm_init_data_type msm_pm_init_data;
static struct hrtimer pm_hrtimer;
static struct msm_pm_sleep_ops pm_sleep_ops;
static bool msm_pm_ldo_retention_enabled = true;
+static bool msm_pm_use_sync_timer;
+static struct msm_pm_cp15_save_data cp15_data;
+static bool msm_pm_retention_calls_tz;
+static uint32_t msm_pm_max_sleep_time;
+static bool msm_no_ramp_down_pc;
+
/*
* Write out the attribute.
*/
@@ -166,9 +174,6 @@
return ret;
}
-/*
- * Read in the new attribute value.
- */
static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
@@ -205,10 +210,7 @@
return ret ? ret : count;
}
-/*
- * Add sysfs entries for one cpu.
- */
-static int __init msm_pm_mode_sysfs_add_cpu(
+static int __devinit msm_pm_mode_sysfs_add_cpu(
unsigned int cpu, struct kobject *modes_kobj)
{
char cpu_name[8];
@@ -291,10 +293,7 @@
return ret;
}
-/*
- * Add sysfs entries for the sleep modes.
- */
-static int __init msm_pm_mode_sysfs_add(void)
+int __devinit msm_pm_mode_sysfs_add(void)
{
struct kobject *module_kobj;
struct kobject *modes_kobj;
@@ -328,10 +327,6 @@
return ret;
}
-/******************************************************************************
- * Configure Hardware before/after Low Power Mode
- *****************************************************************************/
-
/*
* Configure hardware registers in preparation for Apps power down.
*/
@@ -374,22 +369,6 @@
return;
}
-
-/******************************************************************************
- * Suspend Max Sleep Time
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
- msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-#define SCLK_HZ (32768)
-#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
-
-static uint32_t msm_pm_max_sleep_time;
-
/*
* Convert time from nanoseconds to slow clock ticks, then cap it to the
* specified limit
@@ -408,36 +387,21 @@
if (max_sleep_time_ns == 0) {
msm_pm_max_sleep_time = 0;
} else {
- msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+ msm_pm_max_sleep_time =
+ (uint32_t)msm_pm_convert_and_cap_time(
max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
if (msm_pm_max_sleep_time == 0)
msm_pm_max_sleep_time = 1;
}
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+ if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: Requested %lld ns Giving %u sclk ticks\n",
- __func__, max_sleep_time_ns, msm_pm_max_sleep_time);
+ __func__, max_sleep_time_ns,
+ msm_pm_max_sleep_time);
}
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-struct reg_data {
- uint32_t reg;
- uint32_t val;
-};
-
-static struct reg_data reg_saved_state[] = {
- { .reg = 0x4501, },
- { .reg = 0x5501, },
- { .reg = 0x6501, },
- { .reg = 0x7501, },
- { .reg = 0x0500, },
-};
-
-static unsigned int active_vdd;
-static bool msm_pm_save_cp15;
-static const unsigned int pc_vdd = 0x98;
-
static void msm_pm_save_cpu_reg(void)
{
int i;
@@ -455,11 +419,12 @@
* rate. Then restore the active vdd before switching the acpuclk rate.
*/
if (msm_pm_get_l2_flush_flag() == 1) {
- active_vdd = msm_spm_get_vdd(0);
- for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
- reg_saved_state[i].val =
- get_l2_indirect_reg(reg_saved_state[i].reg);
- msm_spm_set_vdd(0, pc_vdd);
+ cp15_data.active_vdd = msm_spm_get_vdd(0);
+ for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+ cp15_data.reg_val[i] =
+ get_l2_indirect_reg(
+ cp15_data.reg_data[i]);
+ msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
}
}
@@ -472,22 +437,20 @@
return;
if (msm_pm_get_l2_flush_flag() == 1) {
- for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
- set_l2_indirect_reg(reg_saved_state[i].reg,
- reg_saved_state[i].val);
- msm_spm_set_vdd(0, active_vdd);
+ for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+ set_l2_indirect_reg(
+ cp15_data.reg_data[i],
+ cp15_data.reg_val[i]);
+ msm_spm_set_vdd(0, cp15_data.active_vdd);
}
}
-static void *msm_pm_idle_rs_limits;
-
static void msm_pm_swfi(void)
{
msm_pm_config_hw_before_swfi();
msm_arch_idle();
}
-
static void msm_pm_retention(void)
{
int ret = 0;
@@ -496,7 +459,7 @@
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
WARN_ON(ret);
- if (msm_pm_retention_tz_call)
+ if (msm_pm_retention_calls_tz)
scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
SCM_L2_RETENTION);
else
@@ -567,7 +530,7 @@
static bool msm_pm_power_collapse(bool from_idle)
{
unsigned int cpu = smp_processor_id();
- unsigned long saved_acpuclk_rate;
+ unsigned long saved_acpuclk_rate = 0;
unsigned int avsdscr;
unsigned int avscsr;
bool collapsed;
@@ -584,28 +547,28 @@
avscsr = avs_get_avscsr();
avs_set_avscsr(0); /* Disable AVS */
- if (cpu_online(cpu))
+ if (cpu_online(cpu) && !msm_no_ramp_down_pc)
saved_acpuclk_rate = acpuclk_power_collapse();
- else
- saved_acpuclk_rate = 0;
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
cpu, __func__, saved_acpuclk_rate);
- if (msm_pm_save_cp15)
+ if (cp15_data.save_cp15)
msm_pm_save_cpu_reg();
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
- if (msm_pm_save_cp15)
+ if (cp15_data.save_cp15)
msm_pm_restore_cpu_reg();
if (cpu_online(cpu)) {
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: restore clock rate to %lu\n",
cpu, __func__, saved_acpuclk_rate);
- if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+ if (!msm_no_ramp_down_pc &&
+ acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
+ < 0)
pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
cpu, __func__, saved_acpuclk_rate);
} else {
@@ -635,15 +598,9 @@
return collapsed;
}
-static void msm_pm_target_init(void)
-{
- if (cpu_is_apq8064())
- msm_pm_save_cp15 = true;
-}
-
static int64_t msm_pm_timer_enter_idle(void)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(tick_nohz_get_sleep_length());
return msm_timer_enter_idle();
@@ -651,7 +608,7 @@
static void msm_pm_timer_exit_idle(bool timer_halted)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return;
msm_timer_exit_idle((int) timer_halted);
@@ -661,7 +618,7 @@
{
int64_t time = 0;
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(ktime_get());
time = msm_timer_get_sclk_time(period);
@@ -673,7 +630,7 @@
static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(ktime_get()) - time;
if (time != 0) {
@@ -765,8 +722,9 @@
}
}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static int msm_pm_idle_prepare(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index,
+ void **msm_pm_idle_rs_limits)
{
int i;
unsigned int power_usage = -1;
@@ -793,9 +751,9 @@
struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
enum msm_pm_sleep_mode mode;
bool allow;
- void *rs_limits = NULL;
uint32_t power;
int idx;
+ void *rs_limits = NULL;
mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
idx = MSM_PM_MODE(dev->cpu, mode);
@@ -805,11 +763,9 @@
switch (mode) {
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- if (num_online_cpus() > 1) {
+ if (num_online_cpus() > 1)
allow = false;
- break;
- }
- /* fall through */
+ break;
case MSM_PM_SLEEP_MODE_RETENTION:
/*
* The Krait BHS regulator doesn't have enough head
@@ -817,62 +773,41 @@
* has disabled retention
*/
if (!msm_pm_ldo_retention_enabled)
- break;
-
- if (!allow)
- break;
-
- if (msm_pm_retention_tz_call &&
- num_online_cpus() > 1) {
allow = false;
- break;
- }
- /* fall through */
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- if (!allow)
- break;
- /* fall through */
-
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- if (!allow)
- break;
- /* fall through */
-
- if (pm_sleep_ops.lowest_limits)
- rs_limits = pm_sleep_ops.lowest_limits(true,
- mode, &time_param, &power);
-
- if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: %s, latency %uus, "
- "sleep %uus, limit %p\n",
- dev->cpu, __func__, state->desc,
- time_param.latency_us,
- time_param.sleep_us, rs_limits);
-
- if (!rs_limits)
+ if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
allow = false;
break;
-
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ break;
default:
allow = false;
break;
}
+ if (!allow)
+ continue;
+
+ if (pm_sleep_ops.lowest_limits)
+ rs_limits = pm_sleep_ops.lowest_limits(true,
+ mode, &time_param, &power);
+
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: allow %s: %d\n",
- dev->cpu, __func__, state->desc, (int)allow);
+ pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
+ dev->cpu, __func__, state->desc,
+ time_param.latency_us,
+ time_param.sleep_us, rs_limits);
+ if (!rs_limits)
+ continue;
- if (allow) {
- if (power < power_usage) {
- power_usage = power;
- modified_time_us = time_param.modified_time_us;
- ret = mode;
- }
-
- if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode)
- msm_pm_idle_rs_limits = rs_limits;
+ if (power < power_usage) {
+ power_usage = power;
+ modified_time_us = time_param.modified_time_us;
+ ret = mode;
+ *msm_pm_idle_rs_limits = rs_limits;
}
+
}
if (modified_time_us && !dev->cpu)
@@ -885,11 +820,27 @@
return ret;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
int64_t time;
- int exit_stat;
bool collapsed = 1;
+ int exit_stat = -1;
+ enum msm_pm_sleep_mode sleep_mode;
+ void *msm_pm_idle_rs_limits = NULL;
+ int sleep_delay = 1;
+ int ret = -ENODEV;
+ int64_t timer_expiration = 0;
+ int notify_rpm = false;
+ bool timer_halted = false;
+
+ sleep_mode = msm_pm_idle_prepare(dev, drv, index,
+ &msm_pm_idle_rs_limits);
+
+ if (!msm_pm_idle_rs_limits) {
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ goto cpuidle_enter_bail;
+ }
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
pr_info("CPU%u: %s: mode %d\n",
@@ -897,6 +848,22 @@
time = ktime_to_ns(ktime_get());
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ notify_rpm = true;
+ timer_expiration = msm_pm_timer_enter_idle();
+
+ sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+ timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+ if (sleep_delay == 0) /* 0 would mean infinite time */
+ sleep_delay = 1;
+ }
+
+ if (pm_sleep_ops.enter_sleep)
+ ret = pm_sleep_ops.enter_sleep(sleep_delay,
+ msm_pm_idle_rs_limits, true, notify_rpm);
+ if (ret)
+ goto cpuidle_enter_bail;
+
switch (sleep_mode) {
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
msm_pm_swfi();
@@ -913,39 +880,16 @@
exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
- int64_t timer_expiration = 0;
- bool timer_halted = false;
- uint32_t sleep_delay;
- int ret = -ENODEV;
- int notify_rpm =
- (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
- timer_expiration = msm_pm_timer_enter_idle();
-
- sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
- timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
- if (sleep_delay == 0) /* 0 would mean infinite time */
- sleep_delay = 1;
-
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
clock_debug_print_enabled();
- if (pm_sleep_ops.enter_sleep)
- ret = pm_sleep_ops.enter_sleep(sleep_delay,
- msm_pm_idle_rs_limits,
- true, notify_rpm);
- if (!ret) {
- collapsed = msm_pm_power_collapse(true);
- timer_halted = true;
+ collapsed = msm_pm_power_collapse(true);
+ timer_halted = true;
- if (pm_sleep_ops.exit_sleep)
- pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
- true, notify_rpm, collapsed);
- }
- msm_pm_timer_exit_idle(timer_halted);
exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ msm_pm_timer_exit_idle(timer_halted);
break;
- }
case MSM_PM_SLEEP_MODE_NOT_SELECTED:
goto cpuidle_enter_bail;
@@ -957,16 +901,24 @@
break;
}
- time = ktime_to_ns(ktime_get()) - time;
- msm_pm_add_stat(exit_stat, time);
- msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
- collapsed);
+ if (pm_sleep_ops.exit_sleep)
+ pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
+ notify_rpm, collapsed);
+ time = ktime_to_ns(ktime_get()) - time;
+ msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
+ if (exit_stat >= 0)
+ msm_pm_add_stat(exit_stat, time);
do_div(time, 1000);
- return (int) time;
+ dev->last_residency = (int) time;
+ return sleep_mode;
cpuidle_enter_bail:
- return 0;
+ dev->last_residency = 0;
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+ msm_pm_timer_exit_idle(timer_halted);
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ return sleep_mode;
}
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
@@ -1060,17 +1012,16 @@
clock_debug_print_enabled();
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
if (msm_pm_sleep_time_override > 0) {
int64_t ns = NSEC_PER_SEC *
(int64_t) msm_pm_sleep_time_override;
msm_pm_set_max_sleep_time(ns);
msm_pm_sleep_time_override = 0;
}
-#endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
+
if (pm_sleep_ops.lowest_limits)
rs_limits = pm_sleep_ops.lowest_limits(false,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
if (rs_limits) {
if (pm_sleep_ops.enter_sleep)
@@ -1104,7 +1055,6 @@
msm_pm_swfi();
}
-
enter_exit:
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: return\n", __func__);
@@ -1112,66 +1062,18 @@
return 0;
}
-static struct platform_suspend_ops msm_pm_ops = {
- .enter = msm_pm_enter,
- .valid = suspend_valid_only_mem,
-};
-
-/******************************************************************************
- * Initialization routine
- *****************************************************************************/
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
{
if (ops)
pm_sleep_ops = *ops;
}
-void __init msm_pm_set_tz_retention_flag(unsigned int flag)
-{
- msm_pm_retention_tz_call = flag;
-}
-
-static int __devinit msm_pc_debug_probe(struct platform_device *pdev)
-{
- struct resource *res = NULL;
- int i ;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto fail;
-
- msm_pc_debug_counters_phys = res->start;
- WARN_ON(resource_size(res) < SZ_64);
- msm_pc_debug_counters = devm_ioremap_nocache(&pdev->dev, res->start,
- resource_size(res));
-
- if (!msm_pc_debug_counters)
- goto fail;
-
- for (i = 0; i < resource_size(res)/4; i++)
- __raw_writel(0, msm_pc_debug_counters + i * 4);
- return 0;
-fail:
- msm_pc_debug_counters = 0;
- msm_pc_debug_counters_phys = 0;
- return -EFAULT;
-}
-
-static struct of_device_id msm_pc_debug_table[] = {
- {.compatible = "qcom,pc-cntr"},
- {},
+static const struct platform_suspend_ops msm_pm_ops = {
+ .enter = msm_pm_enter,
+ .valid = suspend_valid_only_mem,
};
-static struct platform_driver msm_pc_counter_driver = {
- .probe = msm_pc_debug_probe,
- .driver = {
- .name = "pc-cntr",
- .owner = THIS_MODULE,
- .of_match_table = msm_pc_debug_table,
- },
-};
-
-static int __init msm_pm_init(void)
+static int __devinit msm_pm_init(void)
{
pgd_t *pc_pgd;
pmd_t *pmd;
@@ -1186,7 +1088,6 @@
unsigned long exit_phys;
/* Page table for cores to come back up safely. */
-
pc_pgd = pgd_alloc(&init_mm);
if (!pc_pgd)
return -ENOMEM;
@@ -1225,18 +1126,13 @@
msm_pm_mode_sysfs_add();
msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
-
suspend_set_ops(&msm_pm_ops);
- msm_pm_target_init();
hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
msm_cpuidle_init();
- platform_driver_register(&msm_pc_counter_driver);
return 0;
}
-late_initcall(msm_pm_init);
-
static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
{
msm_pm_disable_l2_fn = NULL;
@@ -1249,41 +1145,203 @@
}
}
+struct msm_pc_debug_counters_buffer {
+ void __iomem *reg;
+ u32 len;
+ char buf[MAX_BUF_SIZE];
+};
+
+static inline u32 msm_pc_debug_counters_read_register(
+ void __iomem *reg, int index , int offset)
+{
+ return readl_relaxed(reg + (index * 4 + offset) * 4);
+}
+
+static char *counter_name[] = {
+ "PC Entry Counter",
+ "Warmboot Entry Counter",
+ "PC Bailout Counter"
+};
+
+static int msm_pc_debug_counters_copy(
+ struct msm_pc_debug_counters_buffer *data)
+{
+ int j;
+ u32 stat;
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu) {
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "CPU%d\n", cpu);
+
+ for (j = 0; j < NUM_OF_COUNTERS; j++) {
+ stat = msm_pc_debug_counters_read_register(
+ data->reg, cpu, j);
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "\t%s : %d\n", counter_name[j],
+ stat);
+ }
+
+ }
+
+ return data->len;
+}
+
+static int msm_pc_debug_counters_file_read(struct file *file,
+ char __user *bufu, size_t count, loff_t *ppos)
+{
+ struct msm_pc_debug_counters_buffer *data;
+
+ data = file->private_data;
+
+ if (!data)
+ return -EINVAL;
+
+ if (!bufu || count < 0)
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_WRITE, bufu, count))
+ return -EFAULT;
+
+ if (*ppos >= data->len && data->len == 0)
+ data->len = msm_pc_debug_counters_copy(data);
+
+ return simple_read_from_buffer(bufu, count, ppos,
+ data->buf, data->len);
+}
+
+static int msm_pc_debug_counters_file_open(struct inode *inode,
+ struct file *file)
+{
+ struct msm_pc_debug_counters_buffer *buf;
+ void __iomem *msm_pc_debug_counters_reg;
+
+ msm_pc_debug_counters_reg = inode->i_private;
+
+ if (!msm_pc_debug_counters_reg)
+ return -EINVAL;
+
+ file->private_data = kzalloc(
+ sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
+
+ if (!file->private_data) {
+ pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+ __func__, sizeof(struct msm_pc_debug_counters_buffer));
+
+ return -ENOMEM;
+ }
+
+ buf = file->private_data;
+ buf->reg = msm_pc_debug_counters_reg;
+
+ return 0;
+}
+
+static int msm_pc_debug_counters_file_close(struct inode *inode,
+ struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations msm_pc_debug_counters_fops = {
+ .open = msm_pc_debug_counters_file_open,
+ .read = msm_pc_debug_counters_file_read,
+ .release = msm_pc_debug_counters_file_close,
+ .llseek = no_llseek,
+};
+
static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
{
char *key = NULL;
+ struct dentry *dent = NULL;
uint32_t val = 0;
+ struct resource *res = NULL;
+ int i ;
+ struct msm_pm_init_data_type pdata_local;
int ret = 0;
+ memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ msm_pc_debug_counters_phys = res->start;
+ WARN_ON(resource_size(res) < SZ_64);
+ msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (msm_pc_debug_counters)
+ for (i = 0; i < resource_size(res)/4; i++)
+ __raw_writel(0, msm_pc_debug_counters + i * 4);
+
+ }
+
+ if (!msm_pc_debug_counters) {
+ msm_pc_debug_counters = 0;
+ msm_pc_debug_counters_phys = 0;
+ } else {
+ dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
+ msm_pc_debug_counters,
+ &msm_pc_debug_counters_fops);
+ if (!dent)
+ pr_err("%s: ERROR debugfs_create_file failed\n",
+ __func__);
+ }
+
if (!pdev->dev.of_node) {
struct msm_pm_init_data_type *d = pdev->dev.platform_data;
if (!d)
goto pm_8x60_probe_done;
- msm_pm_init_data.pc_mode = d->pc_mode;
- msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
- msm_pm_init_data.use_sync_timer = d->use_sync_timer;
+ memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
+
} else {
key = "qcom,pc-mode";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
-
if (ret) {
pr_debug("%s: Cannot read %s,defaulting to 0",
__func__, key);
val = MSM_PM_PC_TZ_L2_INT;
ret = 0;
}
-
- msm_pm_init_data.pc_mode = val;
- msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
+ pdata_local.pc_mode = val;
key = "qcom,use-sync-timer";
- msm_pm_init_data.use_sync_timer =
+ pdata_local.use_sync_timer =
of_property_read_bool(pdev->dev.of_node, key);
+
+ key = "qcom,saw-turns-off-pll";
+ msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
+ key);
}
+ if (pdata_local.cp15_data.reg_data &&
+ pdata_local.cp15_data.reg_saved_state_size > 0) {
+ cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
+ pdata_local.cp15_data.reg_saved_state_size,
+ GFP_KERNEL);
+ if (!cp15_data.reg_data)
+ return -ENOMEM;
+
+ cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
+ pdata_local.cp15_data.reg_saved_state_size,
+ GFP_KERNEL);
+ if (cp15_data.reg_val)
+ return -ENOMEM;
+
+ memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
+ pdata_local.cp15_data.reg_saved_state_size *
+ sizeof(uint32_t));
+ }
+
+ msm_pm_set_flush_fn(pdata_local.pc_mode);
+ msm_pm_use_sync_timer = pdata_local.use_sync_timer;
+ msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
+
pm_8x60_probe_done:
+ msm_pm_init();
return ret;
}
@@ -1305,4 +1363,4 @@
{
return platform_driver_register(&msm_pm_8x60_driver);
}
-module_init(msm_pm_8x60_init);
+device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 399194a..af0744c 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -97,8 +97,19 @@
external L2 cache controller */
};
+struct msm_pm_cp15_save_data {
+ bool save_cp15;
+ uint32_t active_vdd;
+ uint32_t qsb_pc_vdd;
+ uint32_t reg_saved_state_size;
+ uint32_t *reg_data;
+ uint32_t *reg_val;
+};
+
struct msm_pm_init_data_type {
enum msm_pm_pc_mode_type pc_mode;
+ bool retention_calls_tz;
+ struct msm_pm_cp15_save_data cp15_data;
bool use_sync_timer;
};
@@ -108,10 +119,9 @@
};
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
void __init msm_pm_set_tz_retention_flag(unsigned int flag);
void msm_pm_enable_retention(bool enable);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 654f547..e6b9549 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -897,6 +897,11 @@
struct audio_client *ac;
struct audio_aio_write_param param;
+ if (!audio || !buf_node) {
+ pr_err("%s NULL pointer audio=[0x%p], buf_node=[0x%p]\n",
+ __func__, audio, buf_node);
+ return;
+ }
pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
__func__, audio, buf_node, buf_node->paddr,
buf_node->buf.data_len,
@@ -922,8 +927,7 @@
if (!audio->buf_cfg.meta_info_enable)
param.flags = 0xFF00;
- if ((buf_node != NULL) &&
- (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET))
+ if (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET)
param.flags |= AUDIO_DEC_EOF_SET;
param.uid = param.paddr;
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index b9815a5..16de77e 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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
@@ -40,8 +40,12 @@
/**
* msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
+ *
+ * @bool - flag to enable print contents of sleep buffer.
+ *
+ * return 0 on success errno on failure.
*/
-int msm_rpm_enter_sleep(void);
+int msm_rpm_enter_sleep(bool print);
/**
* msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 4295fd4..b84ade9 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -32,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/rbtree.h>
#include <mach/socinfo.h>
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
@@ -62,6 +63,9 @@
};
#define DEFAULT_BUFFER_SIZE 256
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define MAX_SLEEP_BUFFER 128
+
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
#define INV_RSC "resource does not exist"
#define ERR "err\0"
@@ -106,6 +110,11 @@
uint32_t data_len;
};
+struct kvp {
+ unsigned int k;
+ unsigned int s;
+};
+
struct msm_rpm_kvp_data {
uint32_t key;
uint32_t nbytes; /* number of bytes */
@@ -113,6 +122,301 @@
bool valid;
};
+struct slp_buf {
+ struct rb_node node;
+ char ubuf[MAX_SLEEP_BUFFER];
+ char *buf;
+ bool valid;
+};
+static struct rb_root tr_root = RB_ROOT;
+
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq);
+static uint32_t msm_rpm_get_next_msg_id(void);
+
+static inline unsigned int get_rsc_type(char *buf)
+{
+ struct rpm_message_header *h;
+ h = (struct rpm_message_header *)
+ (buf + sizeof(struct rpm_request_header));
+ return h->resource_type;
+}
+
+static inline unsigned int get_rsc_id(char *buf)
+{
+ struct rpm_message_header *h;
+ h = (struct rpm_message_header *)
+ (buf + sizeof(struct rpm_request_header));
+ return h->resource_id;
+}
+
+#define get_data_len(buf) \
+ (((struct rpm_message_header *) \
+ (buf + sizeof(struct rpm_request_header)))->data_len)
+
+#define get_req_len(buf) \
+ (((struct rpm_request_header *)(buf))->request_len)
+
+#define get_msg_id(buf) \
+ (((struct rpm_message_header *) \
+ (buf + sizeof(struct rpm_request_header)))->msg_id)
+
+
+static inline int get_buf_len(char *buf)
+{
+ return get_req_len(buf) + sizeof(struct rpm_request_header);
+}
+
+static inline struct kvp *get_first_kvp(char *buf)
+{
+ return (struct kvp *)(buf + sizeof(struct rpm_request_header)
+ + sizeof(struct rpm_message_header));
+}
+
+static inline struct kvp *get_next_kvp(struct kvp *k)
+{
+ return (struct kvp *)((void *)k + sizeof(*k) + k->s);
+}
+
+static inline void *get_data(struct kvp *k)
+{
+ return (void *)k + sizeof(*k);
+}
+
+
+static void delete_kvp(char *msg, struct kvp *d)
+{
+ struct kvp *n;
+ int dec, size;
+
+ n = get_next_kvp(d);
+ dec = (void *)n - (void *)d;
+ size = get_data_len(msg) - ((void *)n - (void *)get_first_kvp(msg));
+
+ memcpy((void *)d, (void *)n, size);
+
+ get_data_len(msg) -= dec;
+ get_req_len(msg) -= dec;
+}
+
+static inline void update_kvp_data(struct kvp *dest, struct kvp *src)
+{
+ memcpy(get_data(dest), get_data(src), src->s);
+}
+
+static void add_kvp(char *buf, struct kvp *n)
+{
+ int inc = sizeof(*n) + n->s;
+ BUG_ON((get_req_len(buf) + inc) > MAX_SLEEP_BUFFER);
+
+ memcpy(buf + get_buf_len(buf), n, inc);
+
+ get_data_len(buf) += inc;
+ get_req_len(buf) += inc;
+}
+
+static struct slp_buf *tr_search(struct rb_root *root, char *slp)
+{
+ unsigned int type = get_rsc_type(slp);
+ unsigned int id = get_rsc_id(slp);
+
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct slp_buf *cur = rb_entry(node, struct slp_buf, node);
+ unsigned int ctype = get_rsc_type(cur->buf);
+ unsigned int cid = get_rsc_id(cur->buf);
+
+ if (type < ctype)
+ node = node->rb_left;
+ else if (type > ctype)
+ node = node->rb_right;
+ else if (id < cid)
+ node = node->rb_left;
+ else if (id > cid)
+ node = node->rb_right;
+ else
+ return cur;
+ }
+ return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct slp_buf *slp)
+{
+ unsigned int type = get_rsc_type(slp->buf);
+ unsigned int id = get_rsc_id(slp->buf);
+
+ struct rb_node **node = &(root->rb_node), *parent = NULL;
+
+ while (*node) {
+ struct slp_buf *curr = rb_entry(*node, struct slp_buf, node);
+ unsigned int ctype = get_rsc_type(curr->buf);
+ unsigned int cid = get_rsc_id(curr->buf);
+
+ parent = *node;
+
+ if (type < ctype)
+ node = &((*node)->rb_left);
+ else if (type > ctype)
+ node = &((*node)->rb_right);
+ else if (id < cid)
+ node = &((*node)->rb_left);
+ else if (id > cid)
+ node = &((*node)->rb_right);
+ else
+ return -EINVAL;
+ }
+
+ rb_link_node(&slp->node, parent, node);
+ rb_insert_color(&slp->node, root);
+ slp->valid = true;
+ return 0;
+}
+
+#define for_each_kvp(buf, k) \
+ for (k = (struct kvp *)get_first_kvp(buf); \
+ ((void *)k - (void *)get_first_kvp(buf)) < get_data_len(buf);\
+ k = get_next_kvp(k))
+
+
+static void tr_update(struct slp_buf *s, char *buf)
+{
+ struct kvp *e, *n;
+
+ for_each_kvp(buf, n) {
+ for_each_kvp(s->buf, e) {
+ if (n->k == e->k) {
+ if (n->s == e->s) {
+ void *e_data = get_data(e);
+ void *n_data = get_data(n);
+ if (memcmp(e_data, n_data, n->s)) {
+ update_kvp_data(e, n);
+ s->valid = true;
+ }
+ } else {
+ delete_kvp(s->buf, e);
+ add_kvp(s->buf, n);
+ s->valid = true;
+ }
+ break;
+ }
+ }
+ }
+}
+
+int msm_rpm_smd_buffer_request(char *buf, int size, gfp_t flag)
+{
+ struct slp_buf *slp;
+ static DEFINE_SPINLOCK(slp_buffer_lock);
+ unsigned long flags;
+
+ if (size > MAX_SLEEP_BUFFER)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&slp_buffer_lock, flags);
+ slp = tr_search(&tr_root, buf);
+
+ if (!slp) {
+ slp = kzalloc(sizeof(struct slp_buf), GFP_ATOMIC);
+ if (!slp) {
+ spin_unlock_irqrestore(&slp_buffer_lock, flags);
+ return -ENOMEM;
+ }
+ slp->buf = PTR_ALIGN(&slp->ubuf[0], sizeof(u32));
+ memcpy(slp->buf, buf, size);
+ if (tr_insert(&tr_root, slp))
+ pr_err("%s(): Error updating sleep request\n",
+ __func__);
+ } else {
+ /* handle unsent requests */
+ tr_update(slp, buf);
+ }
+
+ spin_unlock_irqrestore(&slp_buffer_lock, flags);
+
+ return 0;
+}
+static void msm_rpm_print_sleep_buffer(struct slp_buf *s)
+{
+ char buf[DEBUG_PRINT_BUFFER_SIZE] = {0};
+ int pos;
+ int buflen = DEBUG_PRINT_BUFFER_SIZE;
+ char ch[5] = {0};
+ u32 type;
+ struct kvp *e;
+
+ if (!s)
+ return;
+
+ if (!s->valid)
+ return;
+
+ type = get_rsc_type(s->buf);
+ memcpy(ch, &type, sizeof(u32));
+
+ pos = scnprintf(buf, buflen,
+ "Sleep request type = 0x%08x(%s)",
+ get_rsc_type(s->buf), ch);
+ pos += scnprintf(buf + pos, buflen - pos, " id = 0%x",
+ get_rsc_id(s->buf));
+ for_each_kvp(s->buf, e) {
+ int i;
+ char *data = get_data(e);
+
+ memcpy(ch, &e->k, sizeof(u32));
+
+ pos += scnprintf(buf + pos, buflen - pos,
+ "\n\t\tkey = 0x%08x(%s)",
+ e->k, ch);
+ pos += scnprintf(buf + pos, buflen - pos,
+ " sz= %d data =", e->s);
+
+ for (i = 0; i < e->s; i++)
+ pos += scnprintf(buf + pos, buflen - pos,
+ " 0x%02X", data[i]);
+ }
+ pos += scnprintf(buf + pos, buflen - pos, "\n");
+ printk(buf);
+}
+
+static int msm_rpm_flush_requests(bool print)
+{
+ struct rb_node *t;
+ int ret;
+
+ for (t = rb_first(&tr_root); t; t = rb_next(t)) {
+
+ struct slp_buf *s = rb_entry(t, struct slp_buf, node);
+
+ if (!s->valid)
+ continue;
+
+ if (print)
+ msm_rpm_print_sleep_buffer(s);
+
+ get_msg_id(s->buf) = msm_rpm_get_next_msg_id();
+ ret = msm_rpm_send_smd_buffer(s->buf,
+ get_buf_len(s->buf), true);
+ /* By not adding the message to a wait list we can reduce
+ * latency involved in waiting for a ACK from RPM. The ACK
+ * messages will be processed when we wakeup from sleep but
+ * processing should be minimal
+ * msm_rpm_wait_for_ack_noirq(get_msg_id(s->buf));
+ */
+
+ WARN_ON(ret != get_buf_len(s->buf));
+
+ trace_rpm_send_message(true, MSM_RPM_CTX_SLEEP_SET,
+ get_rsc_type(s->buf),
+ get_rsc_id(s->buf),
+ get_msg_id(s->buf));
+
+ s->valid = false;
+ }
+ return 0;
+
+}
+
+
static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);
static struct msm_rpm_driver_data msm_rpm_data;
@@ -450,7 +754,12 @@
}
elem = NULL;
}
- WARN_ON(!elem);
+ /* Special case where the sleep driver doesn't
+ * wait for ACKs. This would decrease the latency involved with
+ * entering RPM assisted power collapse.
+ */
+ if (!elem)
+ trace_rpm_ack_recd(0, msg_id);
spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
}
@@ -544,8 +853,6 @@
}
}
-#define DEBUG_PRINT_BUFFER_SIZE 512
-
static void msm_rpm_log_request(struct msm_rpm_request *cdata)
{
char buf[DEBUG_PRINT_BUFFER_SIZE];
@@ -677,13 +984,42 @@
pos += scnprintf(buf + pos, buflen - pos, "\n");
printk(buf);
}
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq)
+{
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+ ret = smd_write_avail(msm_rpm_data.ch_info);
+
+ while ((ret = smd_write_avail(msm_rpm_data.ch_info)) < size) {
+ if (ret < 0)
+ break;
+ if (!noirq) {
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
+ flags);
+ cpu_relax();
+ spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+ } else
+ udelay(5);
+ }
+
+ if (ret < 0) {
+ pr_err("%s(): SMD not initialized\n", __func__);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ return ret;
+ }
+
+ ret = smd_write(msm_rpm_data.ch_info, buf, size);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ return ret;
+
+}
static int msm_rpm_send_data(struct msm_rpm_request *cdata,
int msg_type, bool noirq)
{
uint8_t *tmpbuff;
int i, ret, msg_size;
- unsigned long flags;
int req_hdr_sz, msg_hdr_sz;
@@ -695,8 +1031,6 @@
cdata->req_hdr.service_type = msm_rpm_request_service[msg_type];
- cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
-
cdata->req_hdr.request_len = cdata->msg_hdr.data_len + msg_hdr_sz;
msg_size = cdata->req_hdr.request_len + req_hdr_sz;
@@ -714,8 +1048,6 @@
tmpbuff = cdata->buf;
- memcpy(tmpbuff, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
-
tmpbuff += req_hdr_sz + msg_hdr_sz;
for (i = 0; (i < cdata->write_idx); i++) {
@@ -740,6 +1072,17 @@
}
+ memcpy(cdata->buf, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
+
+ if ((cdata->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET) &&
+ !msm_rpm_smd_buffer_request(cdata->buf, msg_size,
+ GFP_FLAG(noirq)))
+ return 1;
+
+ cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
+
+ memcpy(cdata->buf + req_hdr_sz, &cdata->msg_hdr, msg_hdr_sz);
+
if (msm_rpm_debug_mask
& (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW))
msm_rpm_log_request(cdata);
@@ -755,29 +1098,7 @@
msm_rpm_add_wait_list(cdata->msg_hdr.msg_id);
- spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
-
- ret = smd_write_avail(msm_rpm_data.ch_info);
-
- if (ret < 0) {
- pr_err("%s(): SMD not initialized\n", __func__);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
- return 0;
- }
-
- while ((ret < msg_size)) {
- if (!noirq) {
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
- flags);
- cpu_relax();
- spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
- } else
- udelay(5);
- ret = smd_write_avail(msm_rpm_data.ch_info);
- }
-
- ret = smd_write(msm_rpm_data.ch_info, &cdata->buf[0], msg_size);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ ret = msm_rpm_send_smd_buffer(&cdata->buf[0], msg_size, noirq);
if (ret == msg_size) {
trace_rpm_send_message(noirq, cdata->msg_hdr.set,
@@ -958,11 +1279,13 @@
* During power collapse, the rpm driver disables the SMD interrupts to make
* sure that the interrupt doesn't wakes us from sleep.
*/
-int msm_rpm_enter_sleep(void)
+int msm_rpm_enter_sleep(bool print)
{
if (standalone)
return 0;
+ msm_rpm_flush_requests(print);
+
return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
}
EXPORT_SYMBOL(msm_rpm_enter_sleep);
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 19e48759..56623c9 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -134,6 +134,16 @@
uint32_t pmic_die_revision;
};
+struct socinfo_v8 {
+ struct socinfo_v7 v7;
+
+ /* only valid when format==8*/
+ uint32_t pmic_model_1;
+ uint32_t pmic_die_revision_1;
+ uint32_t pmic_model_2;
+ uint32_t pmic_die_revision_2;
+};
+
static union {
struct socinfo_v1 v1;
struct socinfo_v2 v2;
@@ -142,6 +152,7 @@
struct socinfo_v5 v5;
struct socinfo_v6 v6;
struct socinfo_v7 v7;
+ struct socinfo_v8 v8;
} *socinfo;
static enum msm_cpu cpu_of_id[] = {
@@ -865,6 +876,7 @@
device_create_file(msm_soc_device, &msm_soc_attr_vendor);
switch (legacy_format) {
+ case 8:
case 7:
device_create_file(msm_soc_device,
&msm_soc_attr_pmic_model);
@@ -1054,6 +1066,7 @@
socinfo->v5.accessory_chip,
socinfo->v6.hw_platform_subtype);
break;
+ case 8:
case 7:
pr_info("%s: v%u, id=%u, ver=%u.%u, raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n accessory_chip=%u, hw_plat_subtype=%u, pmic_model=%u, pmic_die_revision=%u\n",
__func__,
@@ -1076,7 +1089,11 @@
int __init socinfo_init(void)
{
- socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v7));
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v8));
+
+ if (!socinfo)
+ socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
+ sizeof(struct socinfo_v7));
if (!socinfo)
socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
diff --git a/drivers/gpu/msm/kgsl_drm.c b/drivers/gpu/msm/kgsl_drm.c
index 764b044..ba88a42 100644
--- a/drivers/gpu/msm/kgsl_drm.c
+++ b/drivers/gpu/msm/kgsl_drm.c
@@ -465,8 +465,11 @@
}
ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
- if (ret)
+ if (ret) {
+ drm_gem_object_release(obj);
+ DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
return ret;
+ }
create->handle = handle;
return 0;
@@ -539,6 +542,106 @@
}
int
+kgsl_gem_create_from_ion_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct drm_kgsl_gem_create_from_ion *args = data;
+ struct drm_gem_object *obj;
+ struct ion_handle *ion_handle;
+ struct drm_kgsl_gem_object *priv;
+ struct sg_table *sg_table;
+ struct scatterlist *s;
+ int ret, handle;
+ unsigned long size;
+
+ ion_handle = ion_import_dma_buf(kgsl_drm_ion_client, args->ion_fd);
+ if (IS_ERR_OR_NULL(ion_handle)) {
+ DRM_ERROR("Unable to import dmabuf. Error number = %d\n",
+ (int)PTR_ERR(ion_handle));
+ return -EINVAL;
+ }
+
+ ion_handle_get_size(kgsl_drm_ion_client, ion_handle, &size);
+
+ if (size == 0) {
+ ion_free(kgsl_drm_ion_client, ion_handle);
+ DRM_ERROR(
+ "cannot create GEM object from zero size ION buffer\n");
+ return -EINVAL;
+ }
+
+ obj = drm_gem_object_alloc(dev, size);
+
+ if (obj == NULL) {
+ ion_free(kgsl_drm_ion_client, ion_handle);
+ DRM_ERROR("Unable to allocate the GEM object\n");
+ return -ENOMEM;
+ }
+
+ ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
+ if (ret) {
+ ion_free(kgsl_drm_ion_client, ion_handle);
+ drm_gem_object_release(obj);
+ DRM_ERROR("Unable to initialize GEM object ret = %d\n", ret);
+ return ret;
+ }
+
+ priv = obj->driver_private;
+ priv->ion_handle = ion_handle;
+
+ priv->type = DRM_KGSL_GEM_TYPE_KMEM;
+ list_add(&priv->list, &kgsl_mem_list);
+
+ priv->pagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+
+ priv->memdesc.pagetable = priv->pagetable;
+
+ sg_table = ion_sg_table(kgsl_drm_ion_client,
+ priv->ion_handle);
+ if (IS_ERR_OR_NULL(priv->ion_handle)) {
+ DRM_ERROR("Unable to get ION sg table\n");
+ ion_free(kgsl_drm_ion_client,
+ priv->ion_handle);
+ priv->ion_handle = NULL;
+ kgsl_mmu_putpagetable(priv->pagetable);
+ drm_gem_object_release(obj);
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->memdesc.sg = sg_table->sgl;
+
+ /* Calculate the size of the memdesc from the sglist */
+
+ priv->memdesc.sglen = 0;
+
+ for (s = priv->memdesc.sg; s != NULL; s = sg_next(s)) {
+ priv->memdesc.size += s->length;
+ priv->memdesc.sglen++;
+ }
+
+ ret = kgsl_mmu_map(priv->pagetable, &priv->memdesc,
+ GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ if (ret) {
+ DRM_ERROR("kgsl_mmu_map failed. ret = %d\n", ret);
+ ion_free(kgsl_drm_ion_client,
+ priv->ion_handle);
+ priv->ion_handle = NULL;
+ kgsl_mmu_putpagetable(priv->pagetable);
+ drm_gem_object_release(obj);
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->bufs[0].offset = 0;
+ priv->bufs[0].gpuaddr = priv->memdesc.gpuaddr;
+ priv->flags |= DRM_KGSL_GEM_FLAG_MAPPED;
+
+ args->handle = handle;
+ return 0;
+}
+
+int
kgsl_gem_get_ion_fd_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -563,6 +666,12 @@
if (priv->ion_handle) {
args->ion_fd = ion_share_dma_buf(
kgsl_drm_ion_client, priv->ion_handle);
+ if (args->ion_fd < 0) {
+ DRM_ERROR(
+ "Could not share ion buffer. Error = %d\n",
+ args->ion_fd);
+ ret = -EINVAL;
+ }
} else {
DRM_ERROR("GEM object has no ion memory allocated.\n");
ret = -EINVAL;
@@ -1266,6 +1375,8 @@
DRM_IOCTL_DEF_DRV(KGSL_GEM_MMAP, kgsl_gem_mmap_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_BUFINFO, kgsl_gem_get_bufinfo_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_ION_FD, kgsl_gem_get_ion_fd_ioctl, 0),
+ DRM_IOCTL_DEF_DRV(KGSL_GEM_CREATE_FROM_ION,
+ kgsl_gem_create_from_ion_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_BUFCOUNT,
kgsl_gem_set_bufcount_ioctl, 0),
DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_ACTIVE, kgsl_gem_set_active_ioctl, 0),
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2945b7b..89335f3 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1001,7 +1001,7 @@
}
/* Set the CPU latency to 501usec to allow low latency PC modes */
- pwr->pm_qos_latency = 3;
+ pwr->pm_qos_latency = 501;
pm_runtime_enable(device->parentdev);
register_early_suspend(&device->display_off);
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index c447231..abb5bbc 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1529,7 +1529,7 @@
static ssize_t fwu_sysfs_config_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- unsigned char config_id[8];
+ unsigned char config_id[4];
/* device config id */
fwu->fn_ptr->read(fwu->rmi4_data,
fwu->f34_fd.ctrl_base_addr,
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 4b1b1c7..9f0ad19 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -122,6 +122,7 @@
CPP_DBG("Read failed\n");
tmp = 0xDEADBEEF;
}
+
return tmp;
}
@@ -207,6 +208,48 @@
return IRQ_HANDLED;
}
+static void msm_cpp_boot_hw(struct cpp_device *cpp_dev)
+{
+ disable_irq(cpp_dev->irq->start);
+
+ msm_camera_io_w(0x1, cpp_dev->base + MSM_CPP_MICRO_CLKEN_CTL);
+ msm_camera_io_w(0x1, cpp_dev->base +
+ MSM_CPP_MICRO_BOOT_START);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+
+ /*Trigger MC to jump to start address*/
+ msm_cpp_write(MSM_CPP_CMD_EXEC_JUMP, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_JUMP_ADDRESS, cpp_dev->base);
+
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+ msm_cpp_poll(cpp_dev->base, 0x1);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_JUMP_ACK);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+
+ /*Get Bootloader Version*/
+ msm_cpp_write(MSM_CPP_CMD_GET_BOOTLOADER_VER, cpp_dev->base);
+ pr_info("MC Bootloader Version: 0x%x\n",
+ msm_cpp_read(cpp_dev->base));
+
+ /*Get Firmware Version*/
+ msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_MSG_ID_CMD, cpp_dev->base);
+ msm_cpp_write(0x1, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_CMD_GET_FW_VER, cpp_dev->base);
+ msm_cpp_write(MSM_CPP_MSG_ID_TRAILER, cpp_dev->base);
+
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_CMD);
+ msm_cpp_poll(cpp_dev->base, 0x2);
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_FW_VER);
+ pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
+ msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+ enable_irq(cpp_dev->irq->start);
+ msm_camera_io_w_mb(0x8, cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_MASK);
+ msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
+ MSM_CPP_MICRO_IRQGEN_CLR);
+}
+
static int cpp_init_hardware(struct cpp_device *cpp_dev)
{
int rc = 0;
@@ -261,7 +304,8 @@
}
msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4);
-
+ if (cpp_dev->is_firmware_loaded == 1)
+ msm_cpp_boot_hw(cpp_dev);
return rc;
req_irq_fail:
iounmap(cpp_dev->vbif_base);
@@ -365,6 +409,9 @@
pr_info("CPP FW Version: 0x%x\n", msm_cpp_read(cpp_dev->base));
msm_cpp_poll(cpp_dev->base, MSM_CPP_MSG_ID_TRAILER);
+ /*Disable MC clock*/
+ /*msm_camera_io_w(0x0, cpp_dev->base +
+ MSM_CPP_MICRO_CLKEN_CTL);*/
}
static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
@@ -398,16 +445,6 @@
if (cpp_dev->cpp_open_cnt == 1) {
cpp_init_hardware(cpp_dev);
cpp_init_mem(cpp_dev);
- disable_irq(cpp_dev->irq->start);
-
- cpp_load_fw(cpp_dev);
-
- enable_irq(cpp_dev->irq->start);
-
- msm_camera_io_w_mb(0x8, cpp_dev->base +
- MSM_CPP_MICRO_IRQGEN_MASK);
- msm_camera_io_w_mb(0xFFFF, cpp_dev->base +
- MSM_CPP_MICRO_IRQGEN_CLR);
cpp_dev->state = CPP_STATE_IDLE;
}
mutex_unlock(&cpp_dev->mutex);
@@ -657,6 +694,15 @@
mutex_lock(&cpp_dev->mutex);
CPP_DBG("E cmd: %d\n", cmd);
switch (cmd) {
+ case VIDIOC_MSM_CPP_LOAD_FIRMWARE: {
+ if (cpp_dev->is_firmware_loaded == 0) {
+ disable_irq(cpp_dev->irq->start);
+ cpp_load_fw(cpp_dev);
+ enable_irq(cpp_dev->irq->start);
+ cpp_dev->is_firmware_loaded = 1;
+ }
+ break;
+ }
case VIDIOC_MSM_CPP_CFG:
rc = msm_cpp_cfg(cpp_dev, ioctl_ptr);
break;
@@ -899,6 +945,7 @@
msm_queue_init(&cpp_dev->realtime_q, "frame");
msm_queue_init(&cpp_dev->processing_q, "frame");
cpp_dev->cpp_open_cnt = 0;
+ cpp_dev->is_firmware_loaded = 0;
return rc;
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
index 8deff72..e8e37ed 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h
@@ -131,6 +131,7 @@
struct regulator *fs_cpp;
struct mutex mutex;
enum cpp_state state;
+ uint8_t is_firmware_loaded;
int domain_num;
struct iommu_domain *domain;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 8e2aa30..125c699 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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
@@ -26,7 +26,7 @@
unsigned long align, unsigned long *iova,
unsigned long *buffer_size, int flags)
{
- int rc;
+ int rc = 0;
if (!iova || !buffer_size || !hndl || !clnt) {
dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
clnt, hndl, iova, buffer_size);
@@ -71,6 +71,7 @@
struct ion_handle *hndl;
unsigned long iova = 0;
unsigned long buffer_size = 0;
+ unsigned long ionflags = 0;
int rc = 0;
int align = SZ_4K;
hndl = ion_import_dma_buf(client->clnt, fd);
@@ -84,7 +85,20 @@
mem->domain = domain;
mem->partition_num = partition;
mem->flags = flags;
-
+ rc = ion_handle_get_flags(client->clnt, hndl, &ionflags);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+ goto fail_map;
+ }
+ if (ION_IS_CACHED(ionflags)) {
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+ if (!mem->kvaddr) {
+ dprintk(VIDC_ERR,
+ "Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ }
if (flags & SMEM_SECURE)
align = ALIGN(align, SZ_1M);
@@ -103,7 +117,9 @@
mem->device_addr, mem->size);
return rc;
fail_device_address:
- ion_unmap_kernel(client->clnt, hndl);
+ if (mem->kvaddr)
+ ion_unmap_kernel(client->clnt, hndl);
+fail_map:
ion_free(client->clnt, hndl);
fail_import_fd:
return rc;
@@ -243,31 +259,79 @@
return mem;
}
-static int ion_mem_clean_invalidate(struct smem_client *clt,
- struct msm_smem *mem)
+static int ion_cache_operations(struct smem_client *client,
+ struct msm_smem *mem, enum smem_cache_ops cache_op)
{
- /*
- * Note: We're always mapping into iommu as uncached
- * as a result we don't need to flush/clean anything
- */
- return 0;
+ unsigned long ionflag = 0;
+ int rc = 0;
+ int msm_cache_ops = 0;
+ if (!mem || !client) {
+ dprintk(VIDC_ERR, "Invalid params: %p, %p\n",
+ mem, client);
+ return -EINVAL;
+ }
+ rc = ion_handle_get_flags(client->clnt, mem->smem_priv,
+ &ionflag);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "ion_handle_get_flags failed: %d\n", rc);
+ goto cache_op_failed;
+ }
+ if (ION_IS_CACHED(ionflag)) {
+ switch (cache_op) {
+ case SMEM_CACHE_CLEAN:
+ msm_cache_ops = ION_IOC_CLEAN_CACHES;
+ break;
+ case SMEM_CACHE_INVALIDATE:
+ msm_cache_ops = ION_IOC_INV_CACHES;
+ break;
+ case SMEM_CACHE_CLEAN_INVALIDATE:
+ msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+ break;
+ default:
+ dprintk(VIDC_ERR, "cache operation not supported\n");
+ rc = -EINVAL;
+ goto cache_op_failed;
+ }
+ if (mem->kvaddr) {
+ rc = msm_ion_do_cache_op(client->clnt,
+ (struct ion_handle *)mem->smem_priv,
+ (unsigned long *) mem->kvaddr,
+ (unsigned long)mem->size,
+ msm_cache_ops);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "cache operation failed %d\n", rc);
+ goto cache_op_failed;
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "cache operation failed as no kernel mapping\n");
+ }
+ }
+cache_op_failed:
+ return rc;
}
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops cache_op)
{
struct smem_client *client = clt;
- int rc;
- if (!client || !mem) {
- dprintk(VIDC_ERR, "Invalid client/handle passed\n");
+ int rc = 0;
+ if (!client) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n",
+ client);
return -EINVAL;
}
switch (client->mem_type) {
case SMEM_ION:
- rc = ion_mem_clean_invalidate(client, mem);
+ rc = ion_cache_operations(client, mem, cache_op);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed cache operations: %d\n", rc);
break;
default:
dprintk(VIDC_ERR, "Mem type not supported\n");
- rc = -EINVAL;
break;
}
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 6e40bef..d1c8293 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. 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
@@ -37,6 +37,13 @@
void *smem_priv;
};
+enum smem_cache_ops {
+ SMEM_CACHE_CLEAN,
+ SMEM_CACHE_INVALIDATE,
+ SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
+
void *msm_smem_new_client(enum smem_type mtype);
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
int domain, int partition, int map_kernel);
@@ -44,5 +51,6 @@
void msm_smem_delete_client(void *clt);
struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
domain, int partition, int flags);
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 6480bf5..54047eb 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -181,10 +181,12 @@
err_invalid_input:
return ret;
}
-static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+
+static struct buffer_info *device_to_uvaddr(
+ struct list_head *list, u32 device_addr)
{
- struct buffer_info *temp;
- u32 uvaddr = 0;
+ struct buffer_info *temp = NULL;
+ int found = 0;
int i;
if (!list || !device_addr) {
dprintk(VIDC_ERR, "Invalid input\n");
@@ -198,16 +200,16 @@
== device_addr) {
dprintk(VIDC_INFO,
"Found same fd buffer\n");
- uvaddr = temp->uvaddr[i];
+ found = 1;
break;
}
}
- if (uvaddr)
+ if (found)
break;
}
}
err_invalid_input:
- return uvaddr;
+ return temp;
}
static int msm_v4l2_open(struct file *filp)
@@ -544,9 +546,10 @@
b->m.planes[i].m.userptr = binfo->device_addr[i];
dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
binfo->device_addr[i]);
- if (binfo->handle[i]) {
- rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
- binfo->handle[i]);
+ if (binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_ERR,
"Failed to clean caches: %d\n", rc);
@@ -566,6 +569,7 @@
int i;
struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ struct buffer_info *buffer_info;
if (b->length > VIDEO_MAX_PLANES) {
dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
b->length);
@@ -585,9 +589,10 @@
!b->m.planes[i].m.userptr) {
continue;
}
- b->m.planes[i].m.userptr = device_to_uvaddr(
+ buffer_info = device_to_uvaddr(
&v4l2_inst->registered_bufs,
b->m.planes[i].m.userptr);
+ b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
if (!b->m.planes[i].m.userptr) {
dprintk(VIDC_ERR,
"Failed to find user virtual address, 0x%lx, %d, %d\n",
@@ -595,6 +600,16 @@
rc = -EINVAL;
goto fail_dq_buf;
}
+ if (buffer_info->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to clean caches: %d\n", rc);
+ goto fail_dq_buf;
+ }
+ }
}
fail_dq_buf:
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 12469a5..7a51728 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -913,7 +913,7 @@
case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
return HAL_H264_LEVEL_42;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
- return HAL_H264_LEVEL_3;
+ return HAL_H264_LEVEL_5;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
return HAL_H264_LEVEL_51;
default:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 9f5f5af..6a83334 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -362,9 +362,7 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
struct v4l2_event dqevent;
- struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
- int rc = 0;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
dqevent.id = 0;
@@ -372,16 +370,7 @@
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
- control.id =
- V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
- rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
- if (rc)
- dprintk(VIDC_WARN,
- "Failed to get Smooth streamng flag\n");
- if (!rc && control.value == true)
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
dqevent.type =
@@ -1929,6 +1918,12 @@
rc = -ENOMEM;
goto err_no_mem;
}
+ rc = msm_smem_cache_operations(inst->mem_client,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
dprintk(VIDC_ERR, "Out of memory\n");
@@ -2014,6 +2009,12 @@
rc = -ENOMEM;
goto err_no_mem;
}
+ rc = msm_smem_cache_operations(inst->mem_client,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
dprintk(VIDC_ERR, "Out of memory\n");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 80fc832..52150e9 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -353,20 +353,19 @@
rc = -ENOMEM;
goto fail_smem_alloc;
}
- rc = msm_smem_clean_invalidate(clnt, alloc);
- if (rc) {
- dprintk(VIDC_ERR, "NOTE: Failed to clean caches\n");
- goto fail_clean_cache;
- }
dprintk(VIDC_DBG, "venus_hfi_alloc:ptr=%p,size=%d",
alloc->kvaddr, size);
+ rc = msm_smem_cache_operations(clnt, alloc,
+ SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to clean cache\n");
+ dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+ }
vmem->mem_size = alloc->size;
vmem->mem_data = alloc;
vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
vmem->align_device_addr = (u8 *)alloc->device_addr;
return rc;
-fail_clean_cache:
- msm_smem_free(clnt, alloc);
fail_smem_alloc:
return rc;
}
@@ -2601,6 +2600,12 @@
return -EINVAL;
}
+ rc = venus_hfi_iommu_attach(device);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to attach iommu");
+ goto fail_iommu_attach;
+ }
+
if (!device->resources.fw.cookie)
device->resources.fw.cookie = subsystem_get("venus");
@@ -2620,21 +2625,18 @@
rc = protect_cp_mem(device);
if (rc) {
dprintk(VIDC_ERR, "Failed to protect memory\n");
- goto fail_iommu_attach;
+ goto fail_protect_mem;
}
- rc = venus_hfi_iommu_attach(device);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to attach iommu");
- goto fail_iommu_attach;
- }
return rc;
-fail_iommu_attach:
+fail_protect_mem:
venus_hfi_disable_clks(device);
fail_enable_clks:
subsystem_put(device->resources.fw.cookie);
device->resources.fw.cookie = NULL;
fail_load_fw:
+ venus_hfi_iommu_detach(device);
+fail_iommu_attach:
return rc;
}
@@ -2647,9 +2649,9 @@
return;
}
if (device->resources.fw.cookie) {
- venus_hfi_iommu_detach(device);
venus_hfi_disable_clks(device);
subsystem_put(device->resources.fw.cookie);
+ venus_hfi_iommu_detach(device);
device->resources.fw.cookie = NULL;
}
}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 4ea7013..6c60e04 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -59,12 +59,12 @@
};
static char *taiko_supplies[] = {
- "cdc-vdd-buck", "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
+ WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-tx-h", "cdc-vdd-rx-h", "cdc-vddpx-1",
"cdc-vdd-a-1p2v", "cdc-vddcx-1", "cdc-vddcx-2",
};
static char *tapan_supplies[] = {
- "cdc-vdd-buck", "cdc-vdd-h", "cdc-vdd-px",
+ WCD9XXX_SUPPLY_BUCK_NAME, "cdc-vdd-h", "cdc-vdd-px",
"cdc-vdd-a-1p2v", "cdc-vdd-cx"
};
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 82d58ef..13e23e8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -136,6 +136,7 @@
int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
int rconn_mohm;
+ int rbatt_capacitive_mohm;
struct mutex last_ocv_uv_mutex;
int last_ocv_uv;
int last_ocv_temp_decidegc;
@@ -847,8 +848,8 @@
{
int ibat_ua, vbat_uv, ocv_est_uv;
int rc;
-
- int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+ int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm
+ + chip->rbatt_capacitive_mohm;
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
@@ -917,7 +918,10 @@
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
&vbat_uv);
-
+ /*
+ * don't include rbatt and rbatt_capacitve since we expect this to
+ * be used with a fake battery which does not have internal resistnaces
+ */
ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000;
pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
the_chip->last_ocv_uv = ocv_est_uv;
@@ -1072,6 +1076,10 @@
pr_debug("adding rconn_mohm = %d rbatt = %d\n",
the_chip->rconn_mohm, rbatt);
+ rbatt += the_chip->rbatt_capacitive_mohm;
+ pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
+ the_chip->rbatt_capacitive_mohm, rbatt);
+
if (is_between(20, 10, soc_rbatt))
rbatt = rbatt
+ ((20 - soc_rbatt) * chip->delta_rbatt_mohm) / 10;
@@ -1583,6 +1591,8 @@
}
EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+
static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
int batt_temp,
int chargecycles,
@@ -1597,7 +1607,6 @@
int pc, new_pc;
int batt_temp_degc = batt_temp / 10;
int ocv;
- int count = 0;
rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
rc = div_s64(rc, 100) + cc_uah + uuc_uah;
@@ -1611,17 +1620,55 @@
new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv);
pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
- /* try 10 times to get a close enough pc */
- while (abs(new_pc - pc) > 1 && count++ < 10) {
+ if (abs(new_pc - pc) > 0) {
+ /* Maximum spins to make in while-loop when searching in
+ * full resolution.
+ */
+ const unsigned int max_spin_count =
+ chip->max_voltage_uv / 1000 - chip->v_cutoff + 1;
+ unsigned int count = 0;
int delta_mv = 5;
+ int diff = abs(new_pc - pc);
+ char sign = SIGN(new_pc - pc);
+ char old_sign;
+ int old_diff;
+ int old_ocv;
- if (new_pc > pc)
- delta_mv = -1 * delta_mv;
+ do {
+ count++;
+ old_ocv = ocv;
+ old_diff = diff;
+ old_sign = sign;
- ocv = ocv + delta_mv;
- new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
- batt_temp_degc, ocv);
- pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+ if (new_pc > pc)
+ ocv -= delta_mv;
+ else
+ ocv += delta_mv;
+
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp_degc, ocv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n",
+ new_pc, ocv);
+ diff = abs(new_pc - pc);
+ sign = SIGN(new_pc - pc);
+
+ if (sign != old_sign) {
+ if (delta_mv == 5) {
+ /*
+ * we crossed our desired PC probably
+ * becuase we were overcorrecting
+ */
+ delta_mv = 1;
+ } else {
+ /* we crossed our desired PC even with
+ * 1mV steps, choose the best of two */
+ if (diff > old_diff)
+ ocv = old_ocv;
+
+ break;
+ }
+ }
+ } while (count <= max_spin_count && diff > 0);
}
*ocv_uv = ocv * 1000;
@@ -2869,6 +2916,8 @@
chip->default_rbatt_mohm
= palladium_1500_data.default_rbatt_mohm;
chip->delta_rbatt_mohm = palladium_1500_data.delta_rbatt_mohm;
+ chip->rbatt_capacitive_mohm
+ = palladium_1500_data.rbatt_capacitive_mohm;
return 0;
desay:
chip->fcc = desay_5200_data.fcc;
@@ -2878,6 +2927,8 @@
chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut;
chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
chip->delta_rbatt_mohm = desay_5200_data.delta_rbatt_mohm;
+ chip->rbatt_capacitive_mohm
+ = desay_5200_data.rbatt_capacitive_mohm;
return 0;
}
@@ -3008,9 +3059,9 @@
int ret = 0;
struct pm8921_soc_params raw;
- mutex_lock(&the_chip->bms_output_lock);
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
read_soc_params_raw(the_chip, &raw, 300);
- mutex_unlock(&the_chip->bms_output_lock);
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
*val = 0;
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index b3fd5bc..f87a443 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -295,6 +295,7 @@
bool btc_panic_if_cant_stop_chg;
int stop_chg_upon_expiry;
bool disable_aicl;
+ int usb_type;
};
/* user space parameter to limit usb current */
@@ -1561,7 +1562,7 @@
return 0;
}
- type = the_chip->usb_psy.type;
+ type = the_chip->usb_type;
if (type == POWER_SUPPLY_TYPE_USB_DCP ||
type == POWER_SUPPLY_TYPE_USB_ACA ||
type == POWER_SUPPLY_TYPE_USB_CDP)
@@ -1694,7 +1695,7 @@
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 0;
- if (the_chip->usb_psy.type == POWER_SUPPLY_TYPE_USB)
+ if (the_chip->usb_type == POWER_SUPPLY_TYPE_USB)
val->intval = is_usb_chg_plugged_in(the_chip);
break;
@@ -2360,7 +2361,7 @@
if (type < POWER_SUPPLY_TYPE_USB && type > POWER_SUPPLY_TYPE_BATTERY)
return -EINVAL;
- the_chip->usb_psy.type = type;
+ the_chip->usb_type = type;
power_supply_changed(&the_chip->usb_psy);
power_supply_changed(&the_chip->dc_psy);
return 0;
@@ -4902,6 +4903,7 @@
pm8921_chg_btc_override_init(chip);
chip->stop_chg_upon_expiry = pdata->stop_chg_upon_expiry;
+ chip->usb_type = POWER_SUPPLY_TYPE_UNKNOWN;
chip->usb_psy.name = "usb";
chip->usb_psy.type = POWER_SUPPLY_TYPE_USB;
@@ -4948,9 +4950,6 @@
platform_set_drvdata(pdev, chip);
the_chip = chip;
- /* set initial state of the USB charger type to UNKNOWN */
- power_supply_set_supply_type(&chip->usb_psy, POWER_SUPPLY_TYPE_UNKNOWN);
-
wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 6135e71..7f60128 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2375,7 +2375,7 @@
of_property_read_u32(node, "spi-max-frequency",
&pdata->max_clock_speed);
- of_property_read_u32(node, "infinite_mode",
+ of_property_read_u32(node, "qcom,infinite-mode",
&pdata->infinite_mode);
pdata->ver_reg_exists = of_property_read_bool(node
@@ -2485,13 +2485,12 @@
goto err_probe_exit;
}
- rc = of_property_read_u32(pdev->dev.of_node,
- "cell-index", &pdev->id);
- if (rc)
+ rc = of_alias_get_id(pdev->dev.of_node, "spi");
+ if (rc < 0)
dev_warn(&pdev->dev,
"using default bus_num %d\n", pdev->id);
else
- master->bus_num = pdev->id;
+ master->bus_num = pdev->id = rc;
for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 6df0c96..76d75ea 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -60,6 +60,7 @@
#include "u_smd.c"
#include "u_bam.c"
#include "u_rmnet_ctrl_smd.c"
+#include "u_rmnet_ctrl_qti.c"
#include "u_ctrl_hsic.c"
#include "u_data_hsic.c"
#include "u_ctrl_hsuart.c"
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 935a540..d69e850 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -224,6 +224,16 @@
.bmNetworkCapabilities = 0x20,
};
+static struct usb_cdc_ext_mbb_desc ext_mbb_desc = {
+ .bLength = sizeof ext_mbb_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubType = USB_CDC_EXT_MBB_TYPE,
+
+ .bcdMbbExtendedVersion = cpu_to_le16(0x0100),
+ .bMaxOutstandingCmdMsges = 64,
+ .wMTU = 1500,
+};
+
/* the default data interface has no endpoints ... */
static struct usb_interface_descriptor mbim_data_nop_intf = {
.bLength = sizeof mbim_data_nop_intf,
@@ -286,6 +296,7 @@
(struct usb_descriptor_header *) &mbim_control_intf,
(struct usb_descriptor_header *) &mbim_header_desc,
(struct usb_descriptor_header *) &mbb_desc,
+ (struct usb_descriptor_header *) &ext_mbb_desc,
(struct usb_descriptor_header *) &fs_mbim_notify_desc,
/* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &mbim_data_nop_intf,
@@ -330,6 +341,7 @@
(struct usb_descriptor_header *) &mbim_control_intf,
(struct usb_descriptor_header *) &mbim_header_desc,
(struct usb_descriptor_header *) &mbb_desc,
+ (struct usb_descriptor_header *) &ext_mbb_desc,
(struct usb_descriptor_header *) &hs_mbim_notify_desc,
/* data interface, altsettings 0 and 1 */
(struct usb_descriptor_header *) &mbim_data_nop_intf,
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index e6613e8..0d8fa0f 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -55,6 +55,7 @@
#define NR_RMNET_PORTS 3
static unsigned int nr_rmnet_ports;
static unsigned int no_ctrl_smd_ports;
+static unsigned int no_ctrl_qti_ports;
static unsigned int no_ctrl_hsic_ports;
static unsigned int no_ctrl_hsuart_ports;
static unsigned int no_data_bam_ports;
@@ -402,6 +403,14 @@
return ret;
}
break;
+ case USB_GADGET_XPORT_QTI:
+ ret = gqti_ctrl_connect(&dev->port);
+ if (ret) {
+ pr_err("%s: gqti_ctrl_connect failed: err:%d\n",
+ __func__, ret);
+ return ret;
+ }
+ break;
case USB_GADGET_XPORT_HSIC:
ret = ghsic_ctrl_connect(&dev->port, port_num);
if (ret) {
@@ -436,7 +445,10 @@
if (ret) {
pr_err("%s: gbam_connect failed: err:%d\n",
__func__, ret);
- gsmd_ctrl_disconnect(&dev->port, port_num);
+ if (cxport == USB_GADGET_XPORT_QTI)
+ gqti_ctrl_disconnect(&dev->port);
+ else
+ gsmd_ctrl_disconnect(&dev->port, port_num);
return ret;
}
break;
@@ -484,6 +496,9 @@
case USB_GADGET_XPORT_SMD:
gsmd_ctrl_disconnect(&dev->port, port_num);
break;
+ case USB_GADGET_XPORT_QTI:
+ gqti_ctrl_disconnect(&dev->port);
+ break;
case USB_GADGET_XPORT_HSIC:
ghsic_ctrl_disconnect(&dev->port, port_num);
break;
@@ -1170,6 +1185,7 @@
nr_rmnet_ports = 0;
no_ctrl_smd_ports = 0;
+ no_ctrl_qti_ports = 0;
no_data_bam_ports = 0;
no_data_bam2bam_ports = 0;
no_ctrl_hsic_ports = 0;
@@ -1215,6 +1231,10 @@
rmnet_port->ctrl_xport_num = no_ctrl_smd_ports;
no_ctrl_smd_ports++;
break;
+ case USB_GADGET_XPORT_QTI:
+ rmnet_port->ctrl_xport_num = no_ctrl_qti_ports;
+ no_ctrl_qti_ports++;
+ break;
case USB_GADGET_XPORT_HSIC:
rmnet_port->ctrl_xport_num = no_ctrl_hsic_ports;
no_ctrl_hsic_ports++;
@@ -1268,6 +1288,7 @@
nr_rmnet_ports = 0;
no_ctrl_smd_ports = 0;
+ no_ctrl_qti_ports = 0;
no_data_bam_ports = 0;
no_ctrl_hsic_ports = 0;
no_data_hsic_ports = 0;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 81ba223..cea9369 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. 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
@@ -55,5 +55,7 @@
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
int gsmd_ctrl_setup(unsigned int count);
+int gqti_ctrl_connect(struct grmnet *gr);
+void gqti_ctrl_disconnect(struct grmnet *gr);
#endif /* __U_RMNET_H*/
diff --git a/drivers/usb/gadget/u_rmnet_ctrl_qti.c b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
new file mode 100644
index 0000000..e92978f
--- /dev/null
+++ b/drivers/usb/gadget/u_rmnet_ctrl_qti.c
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. 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/wait.h>
+#include <linux/poll.h>
+#include <linux/usb/rmnet_ctrl_qti.h>
+
+#include "u_rmnet.h"
+
+struct rmnet_ctrl_qti_port {
+ struct grmnet *port_usb;
+
+ bool is_open;
+
+ atomic_t connected;
+ atomic_t line_state;
+
+ atomic_t open_excl;
+ atomic_t read_excl;
+ atomic_t write_excl;
+ atomic_t ioctl_excl;
+
+ wait_queue_head_t read_wq;
+
+ struct list_head cpkt_req_q;
+
+ spinlock_t lock;
+};
+static struct rmnet_ctrl_qti_port *ctrl_port;
+
+static inline int rmnet_ctrl_lock(atomic_t *excl)
+{
+ if (atomic_inc_return(excl) == 1) {
+ return 0;
+ } else {
+ atomic_dec(excl);
+ return -EBUSY;
+ }
+}
+
+static inline void rmnet_ctrl_unlock(atomic_t *excl)
+{
+ atomic_dec(excl);
+}
+
+static void rmnet_ctrl_queue_notify(struct rmnet_ctrl_qti_port *port)
+{
+ unsigned long flags;
+ struct rmnet_ctrl_pkt *cpkt = NULL;
+
+ pr_debug("%s: Queue empty packet for QTI", __func__);
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (!port->is_open) {
+ pr_err("%s: rmnet ctrl file handler %p is not open",
+ __func__, port);
+ spin_unlock_irqrestore(&port->lock, flags);
+ return;
+ }
+
+ cpkt = alloc_rmnet_ctrl_pkt(0, GFP_ATOMIC);
+ if (!cpkt) {
+ pr_err("%s: Unable to allocate reset function pkt\n", __func__);
+ spin_unlock_irqrestore(&port->lock, flags);
+ return;
+ }
+
+ list_add_tail(&cpkt->list, &port->cpkt_req_q);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ pr_debug("%s: Wake up read queue", __func__);
+ wake_up(&port->read_wq);
+}
+
+static int grmnet_ctrl_qti_send_cpkt_tomodem(u8 portno,
+ void *buf, size_t len)
+{
+ unsigned long flags;
+ struct rmnet_ctrl_qti_port *port = ctrl_port;
+ struct rmnet_ctrl_pkt *cpkt;
+
+ if (len > MAX_QTI_PKT_SIZE) {
+ pr_err("given pkt size too big:%d > max_pkt_size:%d\n",
+ len, MAX_QTI_PKT_SIZE);
+ return -EINVAL;
+ }
+
+ cpkt = alloc_rmnet_ctrl_pkt(len, GFP_ATOMIC);
+ if (IS_ERR(cpkt)) {
+ pr_err("%s: Unable to allocate ctrl pkt\n", __func__);
+ return -ENOMEM;
+ }
+
+ memcpy(cpkt->buf, buf, len);
+ cpkt->len = len;
+
+ pr_debug("%s: Add to cpkt_req_q packet with len = %d\n", __func__, len);
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* drop cpkt if port is not open */
+ if (!port->is_open) {
+ pr_err("rmnet file handler %p is not open", port);
+ spin_unlock_irqrestore(&port->lock, flags);
+ free_rmnet_ctrl_pkt(cpkt);
+ return 0;
+ }
+
+ list_add_tail(&cpkt->list, &port->cpkt_req_q);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* wakeup read thread */
+ pr_debug("%s: Wake up read queue", __func__);
+ wake_up(&port->read_wq);
+
+ return 0;
+}
+
+static void
+gqti_ctrl_notify_modem(void *gptr, u8 portno, int val)
+{
+ struct rmnet_ctrl_qti_port *port = ctrl_port;
+
+ atomic_set(&port->line_state, val);
+
+ /* send 0 len pkt to qti to notify state change */
+ rmnet_ctrl_queue_notify(port);
+}
+
+int gqti_ctrl_connect(struct grmnet *gr)
+{
+ struct rmnet_ctrl_qti_port *port;
+ unsigned long flags;
+
+ pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+ if (!gr) {
+ pr_err("%s: grmnet port is null\n", __func__);
+ return -ENODEV;
+ }
+
+ port = ctrl_port;
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->port_usb = gr;
+ gr->send_encap_cmd = grmnet_ctrl_qti_send_cpkt_tomodem;
+ gr->notify_modem = gqti_ctrl_notify_modem;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ atomic_set(&port->connected, 1);
+ wake_up(&port->read_wq);
+
+ if (port && port->port_usb && port->port_usb->connect)
+ port->port_usb->connect(port->port_usb);
+
+ return 0;
+}
+
+void gqti_ctrl_disconnect(struct grmnet *gr)
+{
+ struct rmnet_ctrl_qti_port *port = ctrl_port;
+ unsigned long flags;
+ struct rmnet_ctrl_pkt *cpkt;
+
+ pr_debug("%s: grmnet:%p\n", __func__, gr);
+
+ if (!gr) {
+ pr_err("%s: grmnet port is null\n", __func__);
+ return;
+ }
+
+ if (port && port->port_usb && port->port_usb->disconnect)
+ port->port_usb->disconnect(port->port_usb);
+
+ atomic_set(&port->connected, 0);
+ atomic_set(&port->line_state, 0);
+ spin_lock_irqsave(&port->lock, flags);
+ port->port_usb = 0;
+ gr->send_encap_cmd = 0;
+ gr->notify_modem = 0;
+
+ while (!list_empty(&port->cpkt_req_q)) {
+ cpkt = list_first_entry(&port->cpkt_req_q,
+ struct rmnet_ctrl_pkt, list);
+
+ list_del(&cpkt->list);
+ free_rmnet_ctrl_pkt(cpkt);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* send 0 len pkt to qti to notify state change */
+ rmnet_ctrl_queue_notify(port);
+}
+
+static int rmnet_ctrl_open(struct inode *ip, struct file *fp)
+{
+ unsigned long flags;
+
+ pr_debug("Open rmnet_ctrl_qti device file\n");
+
+ if (rmnet_ctrl_lock(&ctrl_port->open_excl)) {
+ pr_debug("Already opened\n");
+ return -EBUSY;
+ }
+
+ fp->private_data = ctrl_port;
+
+ spin_lock_irqsave(&ctrl_port->lock, flags);
+ ctrl_port->is_open = true;
+ spin_unlock_irqrestore(&ctrl_port->lock, flags);
+
+ return 0;
+}
+
+static int rmnet_ctrl_release(struct inode *ip, struct file *fp)
+{
+ unsigned long flags;
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+
+ pr_debug("Close rmnet control file");
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->is_open = false;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ rmnet_ctrl_unlock(&port->open_excl);
+
+ return 0;
+}
+
+static ssize_t
+rmnet_ctrl_read(struct file *fp, char __user *buf, size_t count, loff_t *pos)
+{
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+ struct rmnet_ctrl_pkt *cpkt = NULL;
+ unsigned long flags;
+ int ret = 0;
+
+ pr_debug("%s: Enter(%d)\n", __func__, count);
+
+ if (count > MAX_QTI_PKT_SIZE) {
+ pr_err("Buffer size is too big %d, should be at most %d\n",
+ count, MAX_QTI_PKT_SIZE);
+ return -EINVAL;
+ }
+
+ if (rmnet_ctrl_lock(&port->read_excl)) {
+ pr_err("Previous reading is not finished yet\n");
+ return -EBUSY;
+ }
+
+ /* block until online */
+ while (!(atomic_read(&port->connected))) {
+ pr_debug("Not connected. Wait.\n");
+ ret = wait_event_interruptible(port->read_wq,
+ atomic_read(&port->connected));
+ if (ret < 0) {
+ rmnet_ctrl_unlock(&port->read_excl);
+ if (ret == -ERESTARTSYS)
+ return -ERESTARTSYS;
+ else
+ return -EINTR;
+ }
+ }
+
+ /* block until a new packet is available */
+ do {
+ spin_lock_irqsave(&port->lock, flags);
+ if (!list_empty(&port->cpkt_req_q))
+ break;
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ pr_debug("%s: Requests list is empty. Wait.\n", __func__);
+ ret = wait_event_interruptible(port->read_wq,
+ !list_empty(&port->cpkt_req_q));
+ if (ret < 0) {
+ pr_debug("Waiting failed\n");
+ rmnet_ctrl_unlock(&port->read_excl);
+ return -ERESTARTSYS;
+ }
+ } while (1);
+
+ cpkt = list_first_entry(&port->cpkt_req_q, struct rmnet_ctrl_pkt,
+ list);
+ list_del(&cpkt->list);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ if (cpkt->len > count) {
+ pr_err("cpkt size too big:%d > buf size:%d\n",
+ cpkt->len, count);
+ rmnet_ctrl_unlock(&port->read_excl);
+ free_rmnet_ctrl_pkt(cpkt);
+ return -ENOMEM;
+ }
+
+ pr_debug("%s: cpkt size:%d\n", __func__, cpkt->len);
+
+
+ rmnet_ctrl_unlock(&port->read_excl);
+
+ ret = copy_to_user(buf, cpkt->buf, cpkt->len);
+ if (ret) {
+ pr_err("copy_to_user failed: err %d\n", ret);
+ ret = -EFAULT;
+ } else {
+ pr_debug("%s: copied %d bytes to user\n", __func__, cpkt->len);
+ ret = cpkt->len;
+ }
+
+ free_rmnet_ctrl_pkt(cpkt);
+
+ return ret;
+}
+
+static ssize_t
+rmnet_ctrl_write(struct file *fp, const char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+ void *kbuf;
+ unsigned long flags;
+ int ret = 0;
+
+ pr_debug("%s: Enter(%d)", __func__, count);
+
+ if (!count) {
+ pr_debug("zero length ctrl pkt\n");
+ return -EINVAL;
+ }
+
+ if (count > MAX_QTI_PKT_SIZE) {
+ pr_debug("given pkt size too big:%d > max_pkt_size:%d\n",
+ count, MAX_QTI_PKT_SIZE);
+ return -EINVAL;
+ }
+
+ if (rmnet_ctrl_lock(&port->write_excl)) {
+ pr_err("Previous writing not finished yet\n");
+ return -EBUSY;
+ }
+
+ if (!atomic_read(&port->connected)) {
+ pr_debug("USB cable not connected\n");
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -EPIPE;
+ }
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf) {
+ pr_err("failed to allocate ctrl pkt\n");
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -ENOMEM;
+ }
+ ret = copy_from_user(kbuf, buf, count);
+ if (ret) {
+ pr_err("copy_from_user failed err:%d\n", ret);
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -EFAULT;
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (port->port_usb && port->port_usb->send_cpkt_response) {
+ ret = port->port_usb->send_cpkt_response(port->port_usb,
+ kbuf, count);
+ if (ret) {
+ pr_err("failed to send ctrl packet. error=%d\n", ret);
+ spin_unlock_irqrestore(&port->lock, flags);
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+ return ret;
+ }
+ } else {
+ pr_err("send_cpkt_response callback is NULL\n");
+ spin_unlock_irqrestore(&port->lock, flags);
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ kfree(kbuf);
+ rmnet_ctrl_unlock(&port->write_excl);
+
+ pr_debug("%s: Exit(%d)", __func__, count);
+
+ return count;
+
+}
+
+static long rmnet_ctrl_ioctl(struct file *fp, unsigned cmd, unsigned long arg)
+{
+ struct rmnet_ctrl_qti_port *port = fp->private_data;
+ int val, ret = 0;
+
+ pr_debug("%s: Received command %d", __func__, cmd);
+
+ if (rmnet_ctrl_lock(&port->ioctl_excl))
+ return -EBUSY;
+
+ switch (cmd) {
+ case FRMNET_CTRL_GET_LINE_STATE:
+ val = atomic_read(&port->line_state);
+ ret = copy_to_user((void __user *)arg, &val, sizeof(val));
+ if (ret) {
+ pr_err("copying to user space failed");
+ ret = -EFAULT;
+ }
+ pr_debug("%s: Sent line_state: %d", __func__,
+ atomic_read(&port->line_state));
+ break;
+ default:
+ pr_err("wrong parameter");
+ ret = -EINVAL;
+ }
+
+ rmnet_ctrl_unlock(&port->ioctl_excl);
+
+ return ret;
+}
+
+static unsigned int rmnet_ctrl_poll(struct file *file, poll_table *wait)
+{
+ struct rmnet_ctrl_qti_port *port = file->private_data;
+ unsigned long flags;
+ unsigned int mask = 0;
+
+ if (!port) {
+ pr_err("%s on a NULL device\n", __func__);
+ return POLLERR;
+ }
+
+ poll_wait(file, &port->read_wq, wait);
+
+ spin_lock_irqsave(&port->lock, flags);
+ if (!list_empty(&port->cpkt_req_q)) {
+ mask |= POLLIN | POLLRDNORM;
+ pr_debug("%s sets POLLIN for rmnet_ctrl_qti_port\n", __func__);
+ }
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return mask;
+}
+
+/* file operations for rmnet device /dev/rmnet_ctrl */
+static const struct file_operations rmnet_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .open = rmnet_ctrl_open,
+ .release = rmnet_ctrl_release,
+ .read = rmnet_ctrl_read,
+ .write = rmnet_ctrl_write,
+ .unlocked_ioctl = rmnet_ctrl_ioctl,
+ .poll = rmnet_ctrl_poll,
+};
+
+static struct miscdevice rmnet_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "rmnet_ctrl",
+ .fops = &rmnet_ctrl_fops,
+};
+
+static int __init gqti_ctrl_init(void)
+{
+ int ret;
+ struct rmnet_ctrl_qti_port *port = NULL;
+
+ port = kzalloc(sizeof(struct rmnet_ctrl_qti_port), GFP_KERNEL);
+ if (!port) {
+ pr_err("Failed to allocate rmnet control device\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&port->cpkt_req_q);
+ spin_lock_init(&port->lock);
+
+ atomic_set(&port->open_excl, 0);
+ atomic_set(&port->read_excl, 0);
+ atomic_set(&port->write_excl, 0);
+ atomic_set(&port->ioctl_excl, 0);
+ atomic_set(&port->connected, 0);
+ atomic_set(&port->line_state, 0);
+
+ init_waitqueue_head(&port->read_wq);
+
+ ctrl_port = port;
+
+ ret = misc_register(&rmnet_device);
+ if (ret) {
+ pr_err("rmnet control driver failed to register");
+ goto fail_init;
+ }
+
+ return ret;
+
+fail_init:
+ kfree(port);
+ ctrl_port = NULL;
+ return ret;
+}
+module_init(gqti_ctrl_init);
+
+static void __exit gqti_ctrl_cleanup(void)
+{
+ misc_deregister(&rmnet_device);
+
+ kfree(ctrl_port);
+ ctrl_port = NULL;
+}
+module_exit(gqti_ctrl_cleanup);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 0922f44..fbae011 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2013, The Linux Foundation. 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
@@ -780,6 +780,7 @@
case MDP_ARGB_8888:
case MDP_RGBA_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
case MDP_RGBX_8888:
case MDP_RGB_565:
case MDP_BGR_565:
@@ -967,6 +968,7 @@
case MDP_ARGB_8888:
case MDP_RGBA_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
case MDP_RGBX_8888:
return OVERLAY_TYPE_RGB;
case MDP_YCRYCB_H2V1:
@@ -1137,6 +1139,23 @@
pipe->element0 = C1_B_Cb; /* B */
pipe->bpp = 4; /* 4 bpp */
break;
+ case MDP_BGRX_8888:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 3; /* alpha, 4 bits */
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 3;
+ pipe->element3 = C3_ALPHA; /* alpha */
+ pipe->element2 = C2_R_Cr; /* R */
+ pipe->element1 = C0_G_Y; /* G */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->bpp = 4; /* 4 bpp */
+ break;
case MDP_YCRYCB_H2V1:
pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
@@ -1324,6 +1343,7 @@
case MDP_XRGB_8888:
case MDP_ARGB_8888:
case MDP_BGRA_8888:
+ case MDP_BGRX_8888:
b_start = 0;
g_start = 8;
r_start = 16;
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 198e2a2..5c89938 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -417,9 +417,6 @@
mfd->op_enable);
if (ret)
pr_warn("can't turn on display!\n");
-
- if (mfd->vsync_pending)
- mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
}
mfd->is_power_setting = false;
complete_all(&mfd->power_set_comp);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 455f725..5158974 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -32,8 +32,6 @@
#define MAX_MIXER_HEIGHT 2400
#define MAX_IMG_WIDTH 0x3FFF
#define MAX_IMG_HEIGHT 0x3FFF
-#define MIN_DST_W 10
-#define MIN_DST_H 10
#define MAX_DST_W MAX_MIXER_WIDTH
#define MAX_DST_H MAX_MIXER_HEIGHT
#define MAX_PLANES 4
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 5e9659f..0c891f9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -57,10 +57,19 @@
struct mdss_mdp_format_params *fmt)
{
u32 xres, yres;
+ u32 min_src_size, min_dst_size;
xres = mfd->fbi->var.xres;
yres = mfd->fbi->var.yres;
+ if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+ min_src_size = fmt->is_yuv ? 2 : 1;
+ min_dst_size = 1;
+ } else {
+ min_src_size = fmt->is_yuv ? 10 : 5;
+ min_dst_size = 2;
+ }
+
if (req->z_order >= MDSS_MDP_MAX_STAGE) {
pr_err("zorder %d out of range\n", req->z_order);
return -ERANGE;
@@ -68,7 +77,7 @@
if (req->src.width > MAX_IMG_WIDTH ||
req->src.height > MAX_IMG_HEIGHT ||
- req->src_rect.w == 0 || req->src_rect.h == 0 ||
+ req->src_rect.w < min_src_size || req->src_rect.h < min_src_size ||
CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) {
pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n",
@@ -78,7 +87,7 @@
return -EOVERFLOW;
}
- if (req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+ if (req->dst_rect.w < min_dst_size || req->dst_rect.h < min_dst_size ||
req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
pr_err("invalid destination resolution (%dx%d)",
req->dst_rect.w, req->dst_rect.h);
@@ -151,10 +160,6 @@
pr_err("invalid odd src resolution or coordinates\n");
return -EINVAL;
}
- if ((req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
- pr_err("invalid odd dst resolution\n");
- return -EINVAL;
- }
}
return 0;
@@ -265,14 +270,16 @@
pipe->params_changed = true;
}
- if (req->id == MSMFB_NEW_REQUEST) {
- mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
- if (!mixer) {
- pr_err("unable to get mixer\n");
- return -ENODEV;
- }
+ mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+ if (!mixer) {
+ pr_err("unable to get mixer\n");
+ return -ENODEV;
+ }
- if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+ if (req->id == MSMFB_NEW_REQUEST) {
+ if (req->flags & MDP_OV_PIPE_FORCE_DMA)
+ pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
+ else if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
else
pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
@@ -308,6 +315,21 @@
pr_err("invalid pipe ndx=%x\n", req->id);
return pipe ? PTR_ERR(pipe) : -ENODEV;
}
+
+ if (pipe->mixer != mixer) {
+ if (!mixer->ctl || (mixer->ctl->mfd != mfd)) {
+ pr_err("Can't switch mixer %d->%d pnum %d!\n",
+ pipe->mixer->num, mixer->num,
+ pipe->num);
+ mdss_mdp_pipe_unmap(pipe);
+ return -EINVAL;
+ }
+ pr_debug("switching pipe mixer %d->%d pnum %d\n",
+ pipe->mixer->num, mixer->num,
+ pipe->num);
+ mdss_mdp_mixer_pipe_unstage(pipe);
+ pipe->mixer = mixer;
+ }
}
pipe->flags = req->flags;
@@ -1308,6 +1330,11 @@
rc = mdss_mdp_ctl_start(mfd->ctl);
if (rc == 0) {
atomic_inc(&ov_active_panels);
+
+ if (mfd->vsync_pending) {
+ mfd->vsync_pending = 0;
+ mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+ }
} else {
mdss_mdp_ctl_destroy(mfd->ctl);
mfd->ctl = NULL;
diff --git a/include/drm/kgsl_drm.h b/include/drm/kgsl_drm.h
index 7ffae9d..41f7c29 100644
--- a/include/drm/kgsl_drm.h
+++ b/include/drm/kgsl_drm.h
@@ -20,6 +20,7 @@
#define DRM_KGSL_GEM_UNLOCK_ON_TS 0x0D
#define DRM_KGSL_GEM_CREATE_FD 0x0E
#define DRM_KGSL_GEM_GET_ION_FD 0x0F
+#define DRM_KGSL_GEM_CREATE_FROM_ION 0x10
#define DRM_IOCTL_KGSL_GEM_CREATE \
DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE, struct drm_kgsl_gem_create)
@@ -80,6 +81,10 @@
DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_GET_ION_FD, \
struct drm_kgsl_gem_get_ion_fd)
+#define DRM_IOCTL_KGSL_GEM_CREATE_FROM_ION \
+DRM_IOWR(DRM_COMMAND_BASE + DRM_KGSL_GEM_CREATE_FROM_ION, \
+struct drm_kgsl_gem_create_from_ion)
+
/* Maximum number of sub buffers per GEM object */
#define DRM_KGSL_GEM_MAX_BUFFERS 2
@@ -199,4 +204,9 @@
uint32_t handle;
};
+struct drm_kgsl_gem_create_from_ion {
+ uint32_t ion_fd;
+ uint32_t handle;
+};
+
#endif
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index 5ff1cfb..f27ceca 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -89,6 +89,8 @@
* readings from bms are not available.
* @delta_rbatt_mohm: the resistance to be added towards lower soc to
* compensate for battery capacitance.
+ * @rbatt_capacitve_mohm: the resistance to be added to compensate for
+ * battery capacitance
*/
struct bms_battery_data {
@@ -100,6 +102,7 @@
struct sf_lut *rbatt_sf_lut;
int default_rbatt_mohm;
int delta_rbatt_mohm;
+ int rbatt_capacitive_mohm;
};
#if defined(CONFIG_PM8921_BMS) || \
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 3ebf091..aed549e 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -29,6 +29,8 @@
(((ver == TABLA_VERSION_1_0) || (ver == TABLA_VERSION_1_1)) ? 1 : 0)
#define TABLA_IS_2_0(ver) ((ver == TABLA_VERSION_2_0) ? 1 : 0)
+#define WCD9XXX_SUPPLY_BUCK_NAME "cdc-vdd-buck"
+
#define SITAR_VERSION_1P0 0
#define SITAR_VERSION_1P1 1
#define SITAR_IS_1P0(ver) \
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index 9c44e8b..412341a 100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -196,4 +196,85 @@
#define WCD9XXX_A_MAD_ANA_CTRL (0x150)
#define WCD9XXX_A_MAD_ANA_CTRL__POR (0xF1)
+
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL (0x30C)
+#define WCD9XXX_A_CDC_CLK_OTHR_CTL__POR (0x00)
+
+/* Class H related common registers */
+#define WCD9XXX_A_BUCK_MODE_1 (0x181)
+#define WCD9XXX_A_BUCK_MODE_1__POR (0x21)
+#define WCD9XXX_A_BUCK_MODE_2 (0x182)
+#define WCD9XXX_A_BUCK_MODE_2__POR (0xFF)
+#define WCD9XXX_A_BUCK_MODE_3 (0x183)
+#define WCD9XXX_A_BUCK_MODE_3__POR (0xCC)
+#define WCD9XXX_A_BUCK_MODE_4 (0x184)
+#define WCD9XXX_A_BUCK_MODE_4__POR (0x3A)
+#define WCD9XXX_A_BUCK_MODE_5 (0x185)
+#define WCD9XXX_A_BUCK_MODE_5__POR (0x00)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1 (0x186)
+#define WCD9XXX_A_BUCK_CTRL_VCL_1__POR (0x48)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2 (0x187)
+#define WCD9XXX_A_BUCK_CTRL_VCL_2__POR (0xA3)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3 (0x188)
+#define WCD9XXX_A_BUCK_CTRL_VCL_3__POR (0x82)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1 (0x189)
+#define WCD9XXX_A_BUCK_CTRL_CCL_1__POR (0xAB)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2 (0x18A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_2__POR (0xDC)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3 (0x18B)
+#define WCD9XXX_A_BUCK_CTRL_CCL_3__POR (0x6A)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4 (0x18C)
+#define WCD9XXX_A_BUCK_CTRL_CCL_4__POR (0x58)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1 (0x18D)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_1__POR (0x50)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2 (0x18E)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_2__POR (0x64)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3 (0x18F)
+#define WCD9XXX_A_BUCK_CTRL_PWM_DRVR_3__POR (0x77)
+#define WCD9XXX_A_BUCK_TMUX_A_D (0x190)
+#define WCD9XXX_A_BUCK_TMUX_A_D__POR (0x00)
+#define WCD9XXX_A_NCP_EN (0x192)
+#define WCD9XXX_A_NCP_EN__POR (0xFE)
+#define WCD9XXX_A_NCP_STATIC (0x194)
+#define WCD9XXX_A_NCP_STATIC__POR (0x28)
+#define WCD9XXX_A_NCP_BUCKREF (0x191)
+#define WCD9XXX_A_NCP_BUCKREF__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL (0x320)
+#define WCD9XXX_A_CDC_CLSH_B1_CTL__POR (0xE4)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL (0x321)
+#define WCD9XXX_A_CDC_CLSH_B2_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL (0x322)
+#define WCD9XXX_A_CDC_CLSH_B3_CTL__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS (0x323)
+#define WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD (0x324)
+#define WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD__POR (0x12)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD (0x325)
+#define WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD__POR (0x0C)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD (0x326)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR (0x18)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD (0x327)
+#define WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR (0x23)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR (0x328)
+#define WCD9XXX_A_CDC_CLSH_K_ADDR__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_K_DATA (0x329)
+#define WCD9XXX_A_CDC_CLSH_K_DATA__POR (0xA4)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L (0x32A)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L__POR (0xD7)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U (0x32B)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U__POR (0x05)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L (0x32C)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L__POR (0x60)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U (0x32D)
+#define WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U__POR (0x09)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR (0x32E)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH (0x32F)
+#define WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR (0x330)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR__POR (0x00)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH (0x331)
+#define WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH__POR (0x00)
+
+
#endif
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
index 471f10a..f0c4915 100644
--- a/include/linux/msm_audio_acdb.h
+++ b/include/linux/msm_audio_acdb.h
@@ -49,6 +49,10 @@
(AUDIO_MAX_COMMON_IOCTL_NUM+21), unsigned)
#define AUDIO_SET_LSM_CAL _IOW(AUDIO_IOCTL_MAGIC, \
(AUDIO_MAX_COMMON_IOCTL_NUM+22), unsigned)
+#define AUDIO_SET_ADM_CUSTOM_TOPOLOGY _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+23), unsigned)
+#define AUDIO_SET_ASM_CUSTOM_TOPOLOGY _IOW(AUDIO_IOCTL_MAGIC, \
+ (AUDIO_MAX_COMMON_IOCTL_NUM+24), unsigned)
#define AUDIO_MAX_ACDB_IOCTL (AUDIO_MAX_COMMON_IOCTL_NUM+30)
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3ec966b..bc35d14 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -114,6 +114,7 @@
MDP_BGR_565, /* BGR 565 planer */
MDP_BGR_888, /* BGR 888 */
MDP_Y_CBCR_H2V2_VENUS,
+ MDP_BGRX_8888, /* BGRX 8888 */
MDP_IMGTYPE_LIMIT,
MDP_RGB_BORDERFILL, /* border fill pipe */
MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */
@@ -166,6 +167,7 @@
#define MDP_BACKEND_COMPOSITION 0x00040000
#define MDP_BORDERFILL_SUPPORTED 0x00010000
#define MDP_SECURE_OVERLAY_SESSION 0x00008000
+#define MDP_OV_PIPE_FORCE_DMA 0x00004000
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
#define MDP_TRANSP_NOP 0xffffffff
diff --git a/include/linux/usb/cdc.h b/include/linux/usb/cdc.h
index 2b39f69..478734f 100644
--- a/include/linux/usb/cdc.h
+++ b/include/linux/usb/cdc.h
@@ -54,6 +54,7 @@
#define USB_CDC_OBEX_TYPE 0x15
#define USB_CDC_NCM_TYPE 0x1a
#define USB_CDC_MBB_TYPE 0x1b /* mbb_desc */
+#define USB_CDC_EXT_MBB_TYPE 0x1c
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct usb_cdc_header_desc {
@@ -203,6 +204,17 @@
__u8 bmNetworkCapabilities;
} __packed;
+/* "Extended MBIM Functional Descriptor" */
+struct usb_cdc_ext_mbb_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __le16 bcdMbbExtendedVersion;
+ __u8 bMaxOutstandingCmdMsges;
+ __le16 wMTU;
+} __packed;
+
/*-------------------------------------------------------------------------*/
/*
diff --git a/include/linux/usb/rmnet_ctrl_qti.h b/include/linux/usb/rmnet_ctrl_qti.h
new file mode 100644
index 0000000..5038396
--- /dev/null
+++ b/include/linux/usb/rmnet_ctrl_qti.h
@@ -0,0 +1,12 @@
+#ifndef __LINUX_USB_U_RMNET_CTRL_QTI_H
+#define __LINUX_USB_U_RMNET_CTRL_QTI_H
+
+#include <linux/ioctl.h>
+
+#define MAX_QTI_PKT_SIZE 2048
+
+#define FRMNET_CTRL_IOCTL_MAGIC 'r'
+#define FRMNET_CTRL_GET_LINE_STATE _IOR(FRMNET_CTRL_IOCTL_MAGIC, 2, int)
+
+
+#endif /* __LINUX_USB_U_RMNET_CTRL_QTI_H */
diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h
index 939c4e3..b003f99 100644
--- a/include/media/msmb_pproc.h
+++ b/include/media/msmb_pproc.h
@@ -102,6 +102,9 @@
#define VIDIOC_MSM_CPP_GET_INST_INFO \
_IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
+#define VIDIOC_MSM_CPP_LOAD_FIRMWARE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
+
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
struct msm_camera_v4l2_ioctl_t {
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index badbd8e..e909195 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -63,6 +63,7 @@
#define BT_SECURITY_LOW 1
#define BT_SECURITY_MEDIUM 2
#define BT_SECURITY_HIGH 3
+#define BT_SECURITY_VERY_HIGH 4
#define BT_DEFER_SETUP 7
#define BT_FLUSHABLE 8
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 4555b08..cad737a 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -6215,6 +6215,22 @@
#define VOICE_CMD_GET_PARAM 0x0001133E
#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+/* Set Q6 topologies */
+#define ASM_CMD_ADD_TOPOLOGIES 0x00010DBE
+#define ADM_CMD_ADD_TOPOLOGIES 0x00010335
+
+/* structure used for both ioctls */
+struct cmd_set_topologies {
+ struct apr_hdr hdr;
+ u32 payload_addr_lsw;
+ /* LSW of parameter data payload address.*/
+ u32 payload_addr_msw;
+ /* MSW of parameter data payload address.*/
+ u32 mem_map_handle;
+ /* Memory map handle returned by mem map command */
+ u32 payload_size;
+ /* Size in bytes of the variable payload in shared memory */
+} __packed;
/* SRS TRUMEDIA start */
/* topology */
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 15d3585..198773c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
@@ -2046,7 +2046,7 @@
sizeof(cp), &cp);
goto unlock;
} else if (!(lmp_ssp_capable(conn)) && conn->auth_initiator &&
- (conn->pending_sec_level == BT_SECURITY_HIGH)) {
+ (conn->pending_sec_level == BT_SECURITY_VERY_HIGH)) {
conn->pending_sec_level = BT_SECURITY_MEDIUM;
}
@@ -2669,6 +2669,12 @@
BT_DBG("Conn pending sec level is %d, ssp is %d, key len is %d",
conn->pending_sec_level, conn->ssp_mode, key->pin_len);
}
+ if (conn && (conn->ssp_mode == 0) &&
+ (conn->pending_sec_level == BT_SECURITY_VERY_HIGH) &&
+ (key->pin_len != 16)) {
+ BT_DBG("Security is high ignoring this key");
+ goto not_found;
+ }
if (key->key_type == 0x04 && conn && conn->auth_type != 0xff &&
(conn->auth_type & 0x01)) {
@@ -2853,14 +2859,14 @@
conn->ssp_mode = (ev->features[0] & 0x01);
/*In case if remote device ssp supported/2.0 device
- reduce the security level to MEDIUM if it is HIGH*/
+ reduce the security level to MEDIUM if it is VERY HIGH*/
if (!conn->ssp_mode && conn->auth_initiator &&
- (conn->pending_sec_level == BT_SECURITY_HIGH))
+ (conn->pending_sec_level == BT_SECURITY_VERY_HIGH))
conn->pending_sec_level = BT_SECURITY_MEDIUM;
if (conn->ssp_mode && conn->auth_initiator &&
conn->io_capability != 0x03) {
- conn->pending_sec_level = BT_SECURITY_HIGH;
+ conn->pending_sec_level = BT_SECURITY_VERY_HIGH;
conn->auth_type = HCI_AT_DEDICATED_BONDING_MITM;
}
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6eab6d0..fd9088a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1,6 +1,6 @@
/*
BlueZ - Bluetooth protocol stack for Linux
- Copyright (c) 2000-2001, 2010-2012 The Linux Foundation. All rights reserved.
+ Copyright (c) 2000-2001, 2010-2013 The Linux Foundation. All rights reserved.
Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Copyright (C) 2010 Google Inc.
@@ -610,6 +610,7 @@
{
if (sk->sk_type == SOCK_RAW) {
switch (l2cap_pi(sk)->sec_level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
return HCI_AT_DEDICATED_BONDING_MITM;
case BT_SECURITY_MEDIUM:
@@ -621,12 +622,14 @@
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
- if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+ l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
return HCI_AT_NO_BONDING_MITM;
else
return HCI_AT_NO_BONDING;
} else {
switch (l2cap_pi(sk)->sec_level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
return HCI_AT_GENERAL_BONDING_MITM;
case BT_SECURITY_MEDIUM:
@@ -7533,7 +7536,8 @@
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
l2cap_sock_clear_timer(sk);
l2cap_sock_set_timer(sk, HZ * 5);
- } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH ||
+ l2cap_pi(sk)->sec_level == BT_SECURITY_VERY_HIGH)
__l2cap_sock_close(sk, ECONNREFUSED);
} else {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index dc4bf2f..d1914ea 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -262,6 +262,7 @@
__u8 auth_type;
switch (d->sec_level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
@@ -2163,7 +2164,8 @@
set_bit(RFCOMM_SEC_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
continue;
- } else if (d->sec_level == BT_SECURITY_HIGH) {
+ } else if (d->sec_level == BT_SECURITY_HIGH ||
+ d->sec_level == BT_SECURITY_VERY_HIGH) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 66cc1f0..216068f 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -707,12 +707,13 @@
break;
}
- if (sec.level > BT_SECURITY_HIGH) {
+ if (sec.level > BT_SECURITY_VERY_HIGH) {
err = -EINVAL;
break;
}
rfcomm_pi(sk)->sec_level = sec.level;
+ BT_DBG("set to %d", sec.level);
break;
case BT_DEFER_SETUP:
@@ -763,6 +764,7 @@
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
break;
case BT_SECURITY_HIGH:
+ case BT_SECURITY_VERY_HIGH:
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
RFCOMM_LM_SECURE;
break;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 517779f..4a83020 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -213,6 +213,7 @@
static __u8 seclevel_to_authreq(__u8 level)
{
switch (level) {
+ case BT_SECURITY_VERY_HIGH:
case BT_SECURITY_HIGH:
return SMP_AUTH_MITM | SMP_AUTH_BONDING;
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 0f14dc3..a09dab3 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -51,7 +51,7 @@
snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
snd-soc-cs8427-objs := cs8427.o
-snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o
+snd-soc-wcd9320-objs := wcd9xxx-resmgr.o wcd9320.o wcd9320-tables.o wcd9xxx-mbhc.o wcd9xxx-common.o
snd-soc-wcd9306-objs := wcd9306.o wcd9306-tables.o
snd-soc-msm8x10-wcd-objs := msm8x10-wcd.o msm8x10-wcd-tables.o
snd-soc-wl1273-objs := wl1273.o
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 1746502..6f601c1 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -36,6 +36,7 @@
#include <linux/gpio.h>
#include "wcd9320.h"
#include "wcd9xxx-resmgr.h"
+#include "wcd9xxx-common.h"
static atomic_t kp_taiko_priv;
static int spkr_drv_wrnd_param_set(const char *val,
@@ -69,6 +70,7 @@
#define TAIKO_SLIM_IRQ_PORT_CLOSED (1 << 2)
#define TAIKO_MCLK_CLK_12P288MHZ 12288000
#define TAIKO_MCLK_CLK_9P6HZ 9600000
+
enum {
AIF1_PB = 0,
AIF1_CAP,
@@ -233,6 +235,10 @@
struct wcd9xxx_resmgr resmgr;
/* mbhc module */
struct wcd9xxx_mbhc mbhc;
+
+ /* class h specific data */
+ struct wcd9xxx_clsh_cdc_data clsh_d;
+
};
static const u32 comp_shift[] = {
@@ -354,73 +360,6 @@
return 0;
}
-static int taiko_codec_enable_class_h_clk(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
-
- pr_debug("%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x01);
- break;
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLSH_B1_CTL, 0x01, 0x00);
- break;
- }
- return 0;
-}
-
-static int taiko_codec_enable_class_h(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
-
- pr_debug("%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x02);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_4, 0xFF, 0xFF);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x04);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x04, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_1, 0x80, 0x80);
- usleep_range(1000, 1000);
- break;
- }
- return 0;
-}
-
-static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
-{
- struct snd_soc_codec *codec = w->codec;
-
- pr_debug("%s %s %d\n", __func__, w->name, event);
-
- switch (event) {
- case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, w->reg, 0x01, 0x01);
- snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
- break;
-
- case SND_SOC_DAPM_POST_PMU:
- usleep_range(1000, 1000);
- break;
-
- case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(codec, w->reg, 0x01, 0x00);
- snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
- break;
- }
- return 0;
-}
-
-
static int taiko_get_anc_slot(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -905,6 +844,17 @@
static const struct soc_enum cf_rxmix7_enum =
SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
+static const char * const class_h_dsm_text[] = {
+ "ZERO", "DSM_HPHL_RX1", "DSM_SPKR_RX7"
+};
+
+static const struct soc_enum class_h_dsm_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_CLSH_CTL, 4, 3, class_h_dsm_text);
+
+static const struct snd_kcontrol_new class_h_dsm_mux =
+ SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
+
+
static const struct snd_kcontrol_new taiko_snd_controls[] = {
SOC_ENUM_EXT("EAR PA Gain", taiko_ear_pa_gain_enum[0],
@@ -1842,11 +1792,12 @@
if (enable) {
taiko->adc_count++;
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+ 0x2, 0x2);
} else {
taiko->adc_count--;
if (!taiko->adc_count)
- snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL,
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
0x2, 0x0);
}
}
@@ -1934,6 +1885,7 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
u16 lineout_gain_reg;
pr_debug("%s %d %s\n", __func__, event, w->name);
@@ -1962,11 +1914,19 @@
snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
break;
case SND_SOC_DAPM_POST_PMU:
- pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+ pr_debug("%s: sleeping 3 ms after %s PA turn on\n",
__func__, w->name);
- usleep_range(16000, 16000);
+ usleep_range(3000, 3000);
break;
case SND_SOC_DAPM_POST_PMD:
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
break;
}
@@ -2515,18 +2475,52 @@
}
return 0;
}
-static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+
+static int taiko_hphl_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
pr_debug("%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x02, 0x02);
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_HPHL,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
break;
case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x02, 0x00);
+ }
+ return 0;
+}
+
+static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x04, 0x04);
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_HPHR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL,
+ 0x04, 0x00);
snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
break;
}
@@ -2539,14 +2533,17 @@
struct snd_soc_codec *codec = w->codec;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
enum wcd9xxx_notify_event e_pre_on, e_post_off;
+ u8 req_clsh_state;
pr_debug("%s: %s event = %d\n", __func__, w->name, event);
if (w->shift == 5) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
} else if (w->shift == 4) {
e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
+ req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
} else {
pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
return -EINVAL;
@@ -2559,29 +2556,27 @@
break;
case SND_SOC_DAPM_POST_PMU:
- usleep_range(10000, 10000);
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ req_clsh_state,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
- usleep_range(10, 10);
+ usleep_range(5000, 5000);
break;
case SND_SOC_DAPM_POST_PMD:
/* Let MBHC module know PA turned off */
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
- /*
- * schedule work is required because at the time HPH PA DAPM
- * event callback is called by DAPM framework, CODEC dapm mutex
- * would have been locked while snd_soc_jack_report also
- * attempts to acquire same lock.
- */
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ req_clsh_state,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+
pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
w->name);
- usleep_range(10000, 10000);
+ usleep_range(5000, 5000);
break;
}
return 0;
@@ -2598,11 +2593,16 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
pr_debug("%s %s %d\n", __func__, w->name, event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ wcd9xxx_clsh_fsm(codec, &taiko->clsh_d,
+ WCD9XXX_CLSH_STATE_LO,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
break;
@@ -2757,15 +2757,11 @@
{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
- /* Change Pump */
- {"CP", NULL, "CLASS_H_CLK"},
-
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
{"EAR PA", NULL, "EAR_PA_MIXER"},
{"EAR_PA_MIXER", NULL, "DAC1"},
- {"DAC1", NULL, "CLASS_H_EAR"},
- {"CLASS_H_EAR", NULL, "CP"},
+ {"DAC1", NULL, "RX_BIAS"},
{"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
{"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
@@ -2777,15 +2773,11 @@
{"HPHL", NULL, "HPHL_PA_MIXER"},
{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+ {"HPHL DAC", NULL, "RX_BIAS"},
{"HPHR", NULL, "HPHR_PA_MIXER"},
{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
-
- {"HPHL DAC", NULL, "CLASS_H_HPH_L"},
- {"CLASS_H_HPH_L", NULL, "CP"},
-
- {"HPHR DAC", NULL, "CLASS_H_HPH_R"},
- {"CLASS_H_HPH_R", NULL, "CP"},
+ {"HPHR DAC", NULL, "RX_BIAS"},
{"ANC", NULL, "ANC1 MUX"},
{"ANC", NULL, "ANC2 MUX"},
@@ -2800,8 +2792,8 @@
{"ANC", NULL, "CDC_CONN"},
- {"DAC1", "Switch", "RX1 CHAIN"},
- {"HPHL DAC", "Switch", "RX1 CHAIN"},
+ {"DAC1", "Switch", "CLASS_H_DSM MUX"},
+ {"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
{"HPHR DAC", NULL, "RX2 CHAIN"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
@@ -2810,30 +2802,20 @@
{"LINEOUT4", NULL, "LINEOUT4 PA"},
{"SPK_OUT", NULL, "SPK PA"},
- {"LINEOUT1 PA", NULL, "CP"},
{"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
{"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
- {"LINEOUT2 PA", NULL, "CP"},
{"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
{"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
- {"LINEOUT3 PA", NULL, "CP"},
{"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
{"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
- {"LINEOUT4 PA", NULL, "CP"},
{"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
{"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
- {"CP", NULL, "CLASS_H_LINEOUTS_PA"},
- {"CLASS_H_LINEOUTS_PA", NULL, "CLASS_H_CLK"},
-
-
-
{"LINEOUT1 DAC", NULL, "RX3 MIX1"},
-
{"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
{"RDAC5 MUX", "DEM4", "RX4 MIX1"},
@@ -2850,12 +2832,13 @@
{"SPK DAC", NULL, "RX7 MIX2"},
{"SPK DAC", NULL, "VDD_SPKDRV"},
+ {"CLASS_H_DSM MUX", "DSM_HPHL_RX1", "RX1 CHAIN"},
+
{"RX1 CHAIN", NULL, "RX1 MIX2"},
{"RX2 CHAIN", NULL, "RX2 MIX2"},
{"RX1 CHAIN", NULL, "ANC"},
{"RX2 CHAIN", NULL, "ANC"},
- {"CLASS_H_CLK", NULL, "RX_BIAS"},
{"LINEOUT1 DAC", NULL, "RX_BIAS"},
{"LINEOUT2 DAC", NULL, "RX_BIAS"},
{"LINEOUT3 DAC", NULL, "RX_BIAS"},
@@ -3986,24 +3969,81 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
pr_debug("%s %s %d\n", __func__, w->name, event);
switch (event) {
- break;
case SND_SOC_DAPM_POST_PMU:
-
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_5, 0x02, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x20, 0x00);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x04, 0x04);
- snd_soc_update_bits(codec, TAIKO_A_BUCK_MODE_3, 0x08, 0x00);
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
usleep_range(5000, 5000);
break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_DISABLE,
+ WCD9XXX_CLSH_EVENT_POST_PA);
+ usleep_range(5000, 5000);
+ }
+ return 0;
+}
+
+static int taiko_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd9xxx_clsh_fsm(codec, &taiko_p->clsh_d,
+ WCD9XXX_CLSH_STATE_EAR,
+ WCD9XXX_CLSH_REQ_ENABLE,
+ WCD9XXX_CLSH_EVENT_PRE_DAC);
+ break;
+ }
+
+ return 0;
+}
+
+static int taiko_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u8 reg_val, zoh_mux_val = 0x00;
+
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ reg_val = snd_soc_read(codec, TAIKO_A_CDC_CONN_CLSH_CTL);
+
+ if ((reg_val & 0x30) == 0x10)
+ zoh_mux_val = 0x04;
+ else if ((reg_val & 0x30) == 0x20)
+ zoh_mux_val = 0x08;
+
+ if (zoh_mux_val != 0x00)
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CONN_CLSH_CTL,
+ 0x0C, zoh_mux_val);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CONN_CLSH_CTL,
+ 0x0C, 0x00);
+ break;
}
return 0;
}
+
/* Todo: Have seperate dapm widgets for I2S and Slimbus.
* Might Need to have callbacks registered only for slimbus
*/
@@ -4012,10 +4052,12 @@
SND_SOC_DAPM_OUTPUT("EAR"),
SND_SOC_DAPM_PGA_E("EAR PA", TAIKO_A_RX_EAR_EN, 4, 0, NULL, 0,
- taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
+ taiko_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
- ARRAY_SIZE(dac1_switch)),
+ SND_SOC_DAPM_MIXER_E("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
+ ARRAY_SIZE(dac1_switch), taiko_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
AIF1_PB, 0, taiko_codec_enable_slimrx,
@@ -4055,8 +4097,9 @@
SND_SOC_DAPM_PGA_E("HPHL", TAIKO_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
- hphl_switch, ARRAY_SIZE(hphl_switch)),
+ SND_SOC_DAPM_MIXER_E("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
+ hphl_switch, ARRAY_SIZE(hphl_switch), taiko_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("HPHR", TAIKO_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
@@ -4192,36 +4235,20 @@
SND_SOC_DAPM_MUX("RDAC7 MUX", SND_SOC_NOPM, 0, 0,
&rx_dac7_mux),
- SND_SOC_DAPM_SUPPLY("CLASS_H_CLK", TAIKO_A_CDC_CLK_OTHR_CTL, 0, 0,
- taiko_codec_enable_class_h_clk, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_PRE_PMD),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_EAR", TAIKO_A_CDC_CLSH_B1_CTL, 4, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_L", TAIKO_A_CDC_CLSH_B1_CTL, 3, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_HPH_R", TAIKO_A_CDC_CLSH_B1_CTL, 2, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CLASS_H_LINEOUTS_PA", SND_SOC_NOPM, 0, 0,
- taiko_codec_enable_class_h, SND_SOC_DAPM_POST_PMU),
-
- SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
- taiko_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
+ &class_h_dsm_mux, taiko_codec_dsm_mux_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
taiko_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 5, 0,
+ SND_SOC_DAPM_SUPPLY("CDC_I2S_RX_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 5, 0,
NULL, 0),
/* TX */
- SND_SOC_DAPM_SUPPLY("CDC_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+ SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
0),
SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
@@ -4540,84 +4567,6 @@
return IRQ_HANDLED;
}
-static const struct taiko_reg_mask_val taiko_1_0_class_h_ear[] = {
-
- /* CLASS-H EAR IDLE_THRESHOLD Table */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_EAR_THSD, 0x26),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD, 0x2C),
-
- /* CLASS-H EAR I_PA_FACT Table. */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xA9),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U, 0x07),
-
- /* CLASS-H EAR Voltage Headroom , Voltage Min. */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_EAR, 0x0D),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_EAR, 0x3A),
-
- /* CLASS-H EAR K values --chnages from load. */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x08),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1B),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x2D),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x36),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x37),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- /** end of Ear PA load 32 */
-};
-
-static const struct taiko_reg_mask_val taiko_1_0_class_h_hph[] = {
-
- /* CLASS-H HPH IDLE_THRESHOLD Table */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_IDLE_HPH_THSD, 0x13),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x19),
-
- /* CLASS-H HPH I_PA_FACT Table */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L, 0x9A),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U, 0x06),
-
- /* CLASS-H HPH Voltage Headroom , Voltage Min */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_HD_HPH, 0x0D),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_V_PA_MIN_HPH, 0x1D),
-
- /* CLASS-H HPH K values --chnages from load .*/
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_ADDR, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0xAE),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x01),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x1C),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x25),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x27),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_K_DATA, 0x00),
-};
-
-static int taiko_config_ear_class_h(struct snd_soc_codec *codec, u32 ear_load)
-{
- u32 i;
-
- if (ear_load != 32)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_ear); i++)
- snd_soc_write(codec, taiko_1_0_class_h_ear[i].reg,
- taiko_1_0_class_h_ear[i].val);
- return 0;
-}
-
-static int taiko_config_hph_class_h(struct snd_soc_codec *codec, u32 hph_load)
-{
- u32 i;
- if (hph_load != 16)
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(taiko_1_0_class_h_hph); i++)
- snd_soc_write(codec, taiko_1_0_class_h_hph[i].reg,
- taiko_1_0_class_h_hph[i].val);
- return 0;
-}
-
static int taiko_handle_pdata(struct taiko_priv *taiko)
{
struct snd_soc_codec *codec = taiko->codec;
@@ -4756,14 +4705,11 @@
0x00 : 0x16);
snd_soc_update_bits(codec, TAIKO_A_MICB_4_CTL, 0x1E, value);
- taiko_config_ear_class_h(codec, 32);
- taiko_config_hph_class_h(codec, 16);
-
done:
return rc;
}
-static const struct taiko_reg_mask_val taiko_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_reg_defaults[] = {
/* set MCLk to 9.6 */
TAIKO_REG_VAL(TAIKO_A_CHIP_CTL, 0x02),
@@ -4772,24 +4718,6 @@
/* EAR PA deafults */
TAIKO_REG_VAL(TAIKO_A_RX_EAR_CMBUFF, 0x05),
- /* BUCK and NCP defaults for EAR and HS */
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_1, 0x5B),
-
- /* CLASS-H defaults for EAR and HS */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_BUCK_NCP_VARS, 0x04),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x01),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x05),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B2_CTL, 0x35),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x30),
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B3_CTL, 0x3B),
-
- /*
- * For CLASS-H, Enable ANC delay buffer,
- * set HPHL and EAR PA ref gain to 0 DB.
- */
- TAIKO_REG_VAL(TAIKO_A_CDC_CLSH_B1_CTL, 0x26),
-
/* RX deafults */
TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
@@ -4811,25 +4739,31 @@
TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
};
-static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
/*
* The following only need to be written for Taiko 1.0 parts.
* Taiko 2.0 will have appropriate defaults for these registers.
*/
/* BUCK default */
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x50),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x50),
+
+ /* Required defaults for class H operation */
+ TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xF4),
+ TAIKO_REG_VAL(TAIKO_A_BIAS_CURR_CTL_2, 0x08),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
/* Choose max non-overlap time for NCP */
TAIKO_REG_VAL(TAIKO_A_NCP_CLK, 0xFC),
/* Use 25mV/50mV for deltap/m to reduce ripple */
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x08),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
/*
* Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
* Note that the other bits of this register will be changed during
* Rx PA bring up.
*/
- TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
/* Reduce HPH DAC bias to 70% */
TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
/*Reduce EAR DAC bias to 70% */
@@ -4858,7 +4792,7 @@
* Don't update TAIKO_A_CHIP_CTL, TAIKO_A_BUCK_CTRL_CCL_1 and
* TAIKO_A_RX_EAR_CMBUFF as those are updated in taiko_reg_defaults
*/
-static const struct taiko_reg_mask_val taiko_2_0_reg_defaults[] = {
+static const struct wcd9xxx_reg_mask_val taiko_2_0_reg_defaults[] = {
TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_2_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_1_2_ADC_IB, 0x44),
@@ -4868,9 +4802,9 @@
TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_6_GAIN, 0x2),
TAIKO_REG_VAL(TAIKO_A_CDC_TX_5_6_ADC_IB, 0x44),
- TAIKO_REG_VAL(TAIKO_A_BUCK_MODE_3, 0xCE),
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_VCL_1, 0x8),
- TAIKO_REG_VAL(TAIKO_A_BUCK_CTRL_CCL_4, 0x51),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x8),
+ TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
@@ -4931,7 +4865,7 @@
}
}
-static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
+static const struct wcd9xxx_reg_mask_val taiko_codec_reg_init_val[] = {
/* Initialize current threshold to 350MA
* number of wait and run cycles to 4096
*/
@@ -4949,9 +4883,6 @@
{TAIKO_A_RX_LINE_4_GAIN, 0x20, 0x20},
{TAIKO_A_SPKR_DRV_GAIN, 0x04, 0x04},
- /* CLASS H config */
- {TAIKO_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
-
/* Use 16 bit sample size for TX1 to TX6 */
{TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
{TAIKO_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
@@ -5101,6 +5032,24 @@
return 0;
}
+static int taiko_codec_get_buck_mv(struct snd_soc_codec *codec)
+{
+ int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ struct wcd9xxx_pdata *pdata = taiko->resmgr.pdata;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (!strncmp(pdata->regulator[i].name,
+ WCD9XXX_SUPPLY_BUCK_NAME,
+ sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
+ buck_volt = pdata->regulator[i].min_uV;
+ break;
+ }
+ }
+ return buck_volt;
+}
+
static int taiko_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -5132,8 +5081,10 @@
tx_hpf_corner_freq_callback);
}
+
snd_soc_codec_set_drvdata(codec, taiko);
+
/* codec resmgr module init */
wcd9xxx = codec->control_data;
pdata = dev_get_platdata(codec->dev->parent);
@@ -5144,6 +5095,9 @@
return ret;
}
+ taiko->clsh_d.buck_mv = taiko_codec_get_buck_mv(codec);
+ wcd9xxx_clsh_init(&taiko->clsh_d);
+
/* init and start mbhc */
ret = wcd9xxx_mbhc_init(&taiko->mbhc, &taiko->resmgr, codec);
if (ret) {
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
index aea31db..89a0b9f 100644
--- a/sound/soc/codecs/wcd9320.h
+++ b/sound/soc/codecs/wcd9320.h
@@ -41,12 +41,6 @@
TAIKO_PID_MIC_20_UA,
};
-struct taiko_reg_mask_val {
- u16 reg;
- u8 mask;
- u8 val;
-};
-
enum taiko_mbhc_analog_pwr_cfg {
TAIKO_ANALOG_PWR_COLLAPSED = 0,
TAIKO_ANALOG_PWR_ON,
diff --git a/sound/soc/codecs/wcd9xxx-common.c b/sound/soc/codecs/wcd9xxx-common.c
new file mode 100644
index 0000000..dbf2e39
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.c
@@ -0,0 +1,591 @@
+/* Copyright (c) 2013, The Linux Foundation. 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/module.h>
+#include <sound/soc.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include "wcd9xxx-common.h"
+
+#define CLSH_COMPUTE_EAR 0x01
+#define CLSH_COMPUTE_HPH_L 0x02
+#define CLSH_COMPUTE_HPH_R 0x03
+
+#define BUCK_VREF_2V 0xFF
+#define BUCK_VREF_1P8V 0xE6
+
+#define NCP_FCLK_LEVEL_8 0x08
+#define NCP_FCLK_LEVEL_5 0x05
+
+#define BUCK_SETTLE_TIME_US 50
+#define NCP_SETTLE_TIME_US 50
+
+static inline void wcd9xxx_enable_clsh_block(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ 0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_anc_delay(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ 0x02, on ? 0x02 : 0x00);
+}
+
+static inline void wcd9xxx_enable_ncp(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+ 0x01, on ? 0x01 : 0x00);
+}
+
+static inline void wcd9xxx_enable_buck(
+ struct snd_soc_codec *codec,
+ bool on)
+{
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+ 0x80, on ? 0x80 : 0x00);
+}
+
+static int cdc_lo_count;
+
+static void (*clsh_state_fp[NUM_CLSH_STATES])
+ (struct snd_soc_codec *,
+ struct wcd9xxx_clsh_cdc_data *,
+ u8 req_state, bool req_type);
+
+static const char *state_to_str(u8 state)
+{
+ if (state == WCD9XXX_CLSH_STATE_IDLE)
+ return "STATE_IDLE";
+ else if (state == WCD9XXX_CLSH_STATE_EAR)
+ return "STATE_EAR";
+ else if (state == WCD9XXX_CLSH_STATE_HPHL)
+ return "STATE_HPH_L";
+ else if (state == WCD9XXX_CLSH_STATE_HPHR)
+ return "STATE_HPH_R";
+ else if (state == (WCD9XXX_CLSH_STATE_HPHL
+ | WCD9XXX_CLSH_STATE_HPHR))
+ return "STATE_HPH_L_R";
+ else if (state == WCD9XXX_CLSH_STATE_LO)
+ return "STATE_LO";
+
+ return "UNKNOWN_STATE";
+}
+
+static void wcd9xxx_cfg_clsh_buck(
+ struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_BUCK_CTRL_CCL_4, 0x0B, 0x00},
+ {WCD9XXX_A_BUCK_CTRL_CCL_1, 0xF0, 0x50},
+ {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x03, 0x00},
+ {WCD9XXX_A_BUCK_CTRL_CCL_3, 0x0B, 0x00},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+ reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Programmed buck parameters", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_common(
+ struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 0, 0},
+ {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, 0x3 << 2, 1 << 2},
+ {WCD9XXX_A_CDC_CLSH_BUCK_NCP_VARS, (0x1 << 4), 0},
+ {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 0), 0x01},
+ {WCD9XXX_A_CDC_CLSH_B2_CTL, (0x3 << 2), (0x01 << 2)},
+ {WCD9XXX_A_CDC_CLSH_B2_CTL, (0xf << 4), (0x03 << 4)},
+ {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 4), (0x03 << 4)},
+ {WCD9XXX_A_CDC_CLSH_B3_CTL, (0xf << 0), (0x0B)},
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 5), (0x01 << 5)},
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 1), (0x01 << 1)},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+ reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Programmed class H controller common parameters",
+ __func__);
+}
+
+static void wcd9xxx_chargepump_request(
+ struct snd_soc_codec *codec, bool on)
+{
+ static int cp_count;
+
+ if (on && (++cp_count == 1)) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+ 0x01, 0x01);
+ dev_info(codec->dev, "%s: Charge Pump enabled, count = %d\n",
+ __func__, cp_count);
+ }
+
+ else if (!on) {
+ if (--cp_count < 0) {
+ dev_dbg(codec->dev, "%s: Unbalanced disable for charge pump\n",
+ __func__);
+ if (snd_soc_read(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL)
+ & 0x01) {
+ dev_info(codec->dev, "%s: Actual chargepump is ON\n",
+ __func__);
+ }
+ cp_count = 0;
+ WARN_ON(1);
+ }
+
+ if (cp_count == 0) {
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLK_OTHR_CTL,
+ 0x01, 0x00);
+ dev_dbg(codec->dev, "%s: Charge pump disabled, count = %d\n",
+ __func__, cp_count);
+ }
+ }
+}
+
+static inline void wcd9xxx_clsh_computation_request(
+ struct snd_soc_codec *codec, int compute_pa, bool on)
+{
+ u8 reg_val, reg_mask;
+
+ switch (compute_pa) {
+ case CLSH_COMPUTE_EAR:
+ reg_mask = 0x10;
+ reg_val = (on ? 0x10 : 0x00);
+ break;
+ case CLSH_COMPUTE_HPH_L:
+ reg_mask = 0x08;
+ reg_val = (on ? 0x08 : 0x00);
+ break;
+ case CLSH_COMPUTE_HPH_R:
+ reg_mask = 0x04;
+ reg_val = (on ? 0x04 : 0x00);
+ break;
+ default:
+ dev_dbg(codec->dev, "%s: class h computation PA request incorrect\n",
+ __func__);
+ return;
+ }
+
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_CLSH_B1_CTL,
+ reg_mask, reg_val);
+
+}
+
+static void wcd9xxx_enable_buck_mode(struct snd_soc_codec *codec,
+ u8 buck_vref)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x03},
+ {WCD9XXX_A_BUCK_MODE_4, 0xFF, buck_vref},
+ {WCD9XXX_A_BUCK_MODE_1, 0x04, 0x04},
+ {WCD9XXX_A_BUCK_MODE_1, 0x08, 0x00},
+ {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x00},
+ {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x00},
+ {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x80},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+ usleep_range(BUCK_SETTLE_TIME_US, BUCK_SETTLE_TIME_US);
+}
+
+static void wcd9xxx_clsh_enable_post_pa(struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_BUCK_MODE_5, 0x02, 0x00},
+ {WCD9XXX_A_NCP_STATIC, 0x20, 0x00},
+ {WCD9XXX_A_BUCK_MODE_3, 0x04, 0x04},
+ {WCD9XXX_A_BUCK_MODE_3, 0x08, 0x08},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: completed clsh mode settings after PA enable\n",
+ __func__);
+
+}
+
+static void wcd9xxx_set_fclk_enable_ncp(struct snd_soc_codec *codec,
+ u8 fclk_level)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_NCP_STATIC, 0x20, 0x20},
+ {WCD9XXX_A_NCP_EN, 0x01, 0x01},
+ };
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x010, 0x00);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x0F, fclk_level);
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ usleep_range(NCP_SETTLE_TIME_US, NCP_SETTLE_TIME_US);
+
+ dev_dbg(codec->dev, "%s: set ncp done\n", __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_ear(struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 7), 0},
+ {WCD9XXX_A_CDC_CLSH_V_PA_HD_EAR, (0x3f << 0), 0x0D},
+ {WCD9XXX_A_CDC_CLSH_V_PA_MIN_EAR, (0x3f << 0), 0x3A},
+
+ /* Under assumption that EAR load is 10.7ohm */
+ {WCD9XXX_A_CDC_CLSH_IDLE_EAR_THSD, (0x3f << 0), 0x26},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_EAR_THSD, (0x3f << 0), 0x2C},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_L, 0xff, 0xA9},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_EAR_U, 0xff, 0x07},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, (0xf << 0), 0x08},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1b},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x2d},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x36},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x37},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ dev_dbg(codec->dev, "%s: Programmed Class H controller EAR specific params\n",
+ __func__);
+}
+
+static void wcd9xxx_cfg_clsh_param_hph(struct snd_soc_codec *codec)
+{
+ int i;
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, (0x1 << 6), 0},
+ {WCD9XXX_A_CDC_CLSH_V_PA_HD_HPH, 0x3f, 0x0D},
+ {WCD9XXX_A_CDC_CLSH_V_PA_MIN_HPH, 0x3f, 0x1D},
+
+ /* Under assumption that HPH load is 16ohm per channel */
+ {WCD9XXX_A_CDC_CLSH_IDLE_HPH_THSD, 0x3f, 0x13},
+ {WCD9XXX_A_CDC_CLSH_FCLKONLY_HPH_THSD, 0x1f, 0x19},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_L, 0xff, 0x97},
+ {WCD9XXX_A_CDC_CLSH_I_PA_FACT_HPH_U, 0xff, 0x05},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, (0x1 << 7), 0},
+ {WCD9XXX_A_CDC_CLSH_K_ADDR, 0x0f, 0},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0xAE},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x01},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x1C},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x24},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x25},
+ {WCD9XXX_A_CDC_CLSH_K_DATA, 0xff, 0x00},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg, reg_set[i].mask,
+ reg_set[i].val);
+ dev_dbg(codec->dev, "%s: Programmed Class H controller HPH specific params\n",
+ __func__);
+}
+
+static void wcd9xxx_clsh_turnoff_postpa
+ (struct snd_soc_codec *codec)
+{
+
+ int i;
+
+ const struct wcd9xxx_reg_mask_val reg_set[] = {
+ {WCD9XXX_A_NCP_EN, 0x01, 0x00},
+ {WCD9XXX_A_BUCK_MODE_1, 0x80, 0x00},
+ {WCD9XXX_A_CDC_CLSH_B1_CTL, 0x10, 0x00},
+ };
+
+ wcd9xxx_chargepump_request(codec, false);
+
+ for (i = 0; i < ARRAY_SIZE(reg_set); i++)
+ snd_soc_update_bits(codec, reg_set[i].reg,
+ reg_set[i].mask, reg_set[i].val);
+
+ wcd9xxx_enable_clsh_block(codec, false);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+}
+
+static void wcd9xxx_clsh_state_idle(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ dev_dbg(codec->dev, "%s: wrong transition, cannot enable IDLE state\n",
+ __func__);
+ } else {
+ if (req_state == WCD9XXX_CLSH_STATE_EAR) {
+ wcd9xxx_clsh_turnoff_postpa(codec);
+ } else if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, false);
+ wcd9xxx_clsh_turnoff_postpa(codec);
+ } else if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, false);
+ wcd9xxx_clsh_turnoff_postpa(codec);
+ } else if (req_state == WCD9XXX_CLSH_STATE_LO) {
+ wcd9xxx_enable_ncp(codec, false);
+ wcd9xxx_enable_buck(codec, false);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_ear(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ wcd9xxx_cfg_clsh_buck(codec);
+ wcd9xxx_cfg_clsh_param_common(codec);
+ wcd9xxx_cfg_clsh_param_ear(codec);
+ wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_EAR, true);
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+ dev_dbg(codec->dev, "%s: Enabled ear mode class h\n", __func__);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to ear\n", __func__);
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_l(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ wcd9xxx_cfg_clsh_buck(codec);
+ wcd9xxx_cfg_clsh_param_common(codec);
+ wcd9xxx_cfg_clsh_param_hph(codec);
+ wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, true);
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+ } else {
+ if (req_state == WCD9XXX_CLSH_STATE_HPHR) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, false);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to hph_l\n",
+ __func__);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_r(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+
+ wcd9xxx_cfg_clsh_buck(codec);
+ wcd9xxx_cfg_clsh_param_common(codec);
+ wcd9xxx_cfg_clsh_param_hph(codec);
+ wcd9xxx_enable_clsh_block(codec, true);
+ wcd9xxx_chargepump_request(codec, true);
+ wcd9xxx_enable_anc_delay(codec, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, true);
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_2V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_8);
+
+ dev_dbg(codec->dev, "%s: Done\n", __func__);
+ } else {
+ if (req_state == WCD9XXX_CLSH_STATE_HPHL) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, false);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to hph_r\n",
+ __func__);
+ }
+ }
+}
+
+static void wcd9xxx_clsh_state_hph_st(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_L, true);
+ wcd9xxx_clsh_computation_request(codec,
+ CLSH_COMPUTE_HPH_R, true);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to hph_st\n", __func__);
+ }
+}
+
+static void wcd9xxx_clsh_state_lo(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ if (is_enable) {
+ if (++cdc_lo_count > 1)
+ return;
+
+ wcd9xxx_enable_buck_mode(codec, BUCK_VREF_1P8V);
+ wcd9xxx_set_fclk_enable_ncp(codec, NCP_FCLK_LEVEL_5);
+
+ if (clsh_d->buck_mv == WCD9XXX_CDC_BUCK_MV_1P8) {
+ wcd9xxx_enable_buck(codec, false);
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_STATIC,
+ 0x20, 0x01);
+ wcd9xxx_enable_ncp(codec, true);
+ msleep(NCP_SETTLE_TIME_US);
+
+ } else {
+ snd_soc_update_bits(codec, WCD9XXX_A_NCP_EN,
+ 0x40, 0x00);
+ wcd9xxx_enable_ncp(codec, true);
+ msleep(NCP_SETTLE_TIME_US);
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_5,
+ 0xFB, (0x02 << 2));
+ }
+ snd_soc_update_bits(codec, WCD9XXX_A_BUCK_MODE_1,
+ 0x04, 0x00);
+ } else {
+ dev_dbg(codec->dev, "%s: stub fallback to lineout\n", __func__);
+ }
+}
+
+static void wcd9xxx_clsh_state_err(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable)
+{
+ dev_dbg(codec->dev, "%s Wrong request for class H state machine requested to %s %s"
+ , __func__, is_enable ? "enable" : "disable",
+ state_to_str(req_state));
+ WARN_ON(1);
+}
+
+void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+ u8 req_state, bool req_type, u8 clsh_event)
+{
+ u8 old_state, new_state;
+
+ switch (clsh_event) {
+
+ case WCD9XXX_CLSH_EVENT_PRE_DAC:
+
+ /* PRE_DAC event should be used only for Enable */
+ BUG_ON(req_type != WCD9XXX_CLSH_REQ_ENABLE);
+
+ old_state = cdc_clsh_d->state;
+ new_state = old_state | req_state;
+
+ (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+ req_state, req_type);
+ cdc_clsh_d->state = new_state;
+ dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+ __func__, state_to_str(old_state),
+ state_to_str(cdc_clsh_d->state));
+
+ break;
+
+ case WCD9XXX_CLSH_EVENT_POST_PA:
+
+ if (req_type == WCD9XXX_CLSH_REQ_DISABLE) {
+ if (req_state == WCD9XXX_CLSH_STATE_LO
+ && --cdc_lo_count > 0)
+ break;
+
+ old_state = cdc_clsh_d->state;
+ new_state = old_state & (~req_state);
+
+ if (new_state < NUM_CLSH_STATES) {
+ (*clsh_state_fp[new_state]) (codec, cdc_clsh_d,
+ req_state, req_type);
+ cdc_clsh_d->state = new_state;
+ dev_info(codec->dev, "%s: ClassH state transition from %s to %s\n",
+ __func__, state_to_str(old_state),
+ state_to_str(cdc_clsh_d->state));
+
+ } else {
+ dev_dbg(codec->dev, "%s: wrong new state = %x\n",
+ __func__, new_state);
+ }
+
+
+ } else if (req_state != WCD9XXX_CLSH_STATE_LO) {
+ wcd9xxx_clsh_enable_post_pa(codec);
+ }
+
+ break;
+ }
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_fsm);
+
+void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh)
+{
+ int i;
+ clsh->state = WCD9XXX_CLSH_STATE_IDLE;
+
+ for (i = 0; i < NUM_CLSH_STATES; i++)
+ clsh_state_fp[i] = wcd9xxx_clsh_state_err;
+
+ clsh_state_fp[WCD9XXX_CLSH_STATE_IDLE] = wcd9xxx_clsh_state_idle;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_EAR] = wcd9xxx_clsh_state_ear;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHL] =
+ wcd9xxx_clsh_state_hph_l;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPHR] =
+ wcd9xxx_clsh_state_hph_r;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_HPH_ST] =
+ wcd9xxx_clsh_state_hph_st;
+ clsh_state_fp[WCD9XXX_CLSH_STATE_LO] = wcd9xxx_clsh_state_lo;
+
+}
+EXPORT_SYMBOL_GPL(wcd9xxx_clsh_init);
+
+MODULE_DESCRIPTION("WCD9XXX Common");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9xxx-common.h b/sound/soc/codecs/wcd9xxx-common.h
new file mode 100644
index 0000000..743ab0c
--- /dev/null
+++ b/sound/soc/codecs/wcd9xxx-common.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2013, The Linux Foundation. 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.
+ */
+
+#ifndef WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CODEC_COMMON
+
+#define WCD9XXX_CLSH_REQ_ENABLE true
+#define WCD9XXX_CLSH_REQ_DISABLE false
+
+#define WCD9XXX_CLSH_EVENT_PRE_DAC 0x01
+#define WCD9XXX_CLSH_EVENT_POST_PA 0x02
+
+/* Basic states for Class H state machine.
+ * represented as a bit mask within a u8 data type
+ * bit 0: EAR mode
+ * bit 1: HPH Left mode
+ * bit 2: HPH Right mode
+ * bit 3: Lineout mode
+ * bit 4: Ultrasound mode
+ */
+#define WCD9XXX_CLSH_STATE_IDLE 0x00
+#define WCD9XXX_CLSH_STATE_EAR (0x01 << 0)
+#define WCD9XXX_CLSH_STATE_HPHL (0x01 << 1)
+#define WCD9XXX_CLSH_STATE_HPHR (0x01 << 2)
+#define WCD9XXX_CLSH_STATE_LO (0x01 << 3)
+#define NUM_CLSH_STATES ((0x01 << 4) - 1)
+
+/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
+#define WCD9XXX_CLSH_STATE_HPH_ST (WCD9XXX_CLSH_STATE_HPHL | \
+ WCD9XXX_CLSH_STATE_HPHR)
+
+
+struct wcd9xxx_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+/* Class H data that the codec driver will maintain */
+struct wcd9xxx_clsh_cdc_data {
+ u8 state;
+ int buck_mv;
+};
+
+
+enum wcd9xxx_buck_volt {
+ WCD9XXX_CDC_BUCK_UNSUPPORTED = 0,
+ WCD9XXX_CDC_BUCK_MV_1P8 = 1800000,
+ WCD9XXX_CDC_BUCK_MV_2P15 = 2150000,
+};
+
+extern void wcd9xxx_clsh_fsm(struct snd_soc_codec *codec,
+ struct wcd9xxx_clsh_cdc_data *cdc_clsh_d,
+ u8 req_state, bool req_type, u8 clsh_event);
+
+extern void wcd9xxx_clsh_init(struct wcd9xxx_clsh_cdc_data *clsh);
+
+#endif
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.c b/sound/soc/msm/qdsp6v2/audio_acdb.c
index 58fdc1b..b71132e 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.c
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.c
@@ -66,6 +66,12 @@
/* VocProc dev cfg cal*/
struct acdb_atomic_cal_block vocproc_dev_cal;
+ /* Custom topology */
+ struct acdb_atomic_cal_block adm_custom_topology;
+ struct acdb_atomic_cal_block asm_custom_topology;
+ atomic_t valid_adm_custom_top;
+ atomic_t valid_asm_custom_top;
+
/* AFE cal */
struct acdb_atomic_cal_block afe_cal[MAX_AUDPROC_TYPES];
@@ -134,6 +140,106 @@
atomic_set(&acdb_data.asm_topology, topology);
}
+void reset_custom_topology_flags(void)
+{
+ atomic_set(&acdb_data.valid_adm_custom_top, 1);
+ atomic_set(&acdb_data.valid_asm_custom_top, 1);
+}
+
+void get_adm_custom_topology(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ if (atomic_read(&acdb_data.valid_adm_custom_top) == 0) {
+ cal_block->cal_size = 0;
+ goto done;
+ }
+ atomic_set(&acdb_data.valid_adm_custom_top, 0);
+
+ cal_block->cal_size =
+ atomic_read(&acdb_data.adm_custom_topology.cal_size);
+ cal_block->cal_paddr =
+ atomic_read(&acdb_data.adm_custom_topology.cal_paddr);
+ cal_block->cal_kvaddr =
+ atomic_read(&acdb_data.adm_custom_topology.cal_kvaddr);
+done:
+ return;
+}
+
+void store_adm_custom_topology(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ (long)atomic64_read(&acdb_data.mem_len));
+ goto done;
+ }
+
+ atomic_set(&acdb_data.adm_custom_topology.cal_size,
+ cal_block->cal_size);
+ atomic_set(&acdb_data.adm_custom_topology.cal_paddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+ atomic_set(&acdb_data.adm_custom_topology.cal_kvaddr,
+ cal_block->cal_offset +
+ atomic64_read(&acdb_data.kvaddr));
+done:
+ return;
+}
+
+void get_asm_custom_topology(struct acdb_cal_block *cal_block)
+{
+ pr_debug("%s\n", __func__);
+
+ if (cal_block == NULL) {
+ pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+ goto done;
+ }
+
+ if (atomic_read(&acdb_data.valid_asm_custom_top) == 0) {
+ cal_block->cal_size = 0;
+ goto done;
+ }
+ atomic_set(&acdb_data.valid_asm_custom_top, 0);
+
+ cal_block->cal_size =
+ atomic_read(&acdb_data.asm_custom_topology.cal_size);
+ cal_block->cal_paddr =
+ atomic_read(&acdb_data.asm_custom_topology.cal_paddr);
+ cal_block->cal_kvaddr =
+ atomic_read(&acdb_data.asm_custom_topology.cal_kvaddr);
+done:
+ return;
+}
+
+void store_asm_custom_topology(struct cal_block *cal_block)
+{
+ pr_debug("%s,\n", __func__);
+
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
+ __func__, cal_block->cal_offset,
+ (long)atomic64_read(&acdb_data.mem_len));
+ goto done;
+ }
+
+ atomic_set(&acdb_data.asm_custom_topology.cal_size,
+ cal_block->cal_size);
+ atomic_set(&acdb_data.asm_custom_topology.cal_paddr,
+ cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+ atomic_set(&acdb_data.asm_custom_topology.cal_kvaddr,
+ cal_block->cal_offset +
+ atomic64_read(&acdb_data.kvaddr));
+done:
+ return;
+}
+
void get_voice_cal_allocation(struct acdb_cal_block *cal_block)
{
cal_block->cal_size = ACDB_TOTAL_VOICE_ALLOCATION;
@@ -672,6 +778,8 @@
__func__);
}
+ atomic_set(&acdb_data.valid_adm_custom_top, 1);
+ atomic_set(&acdb_data.valid_asm_custom_top, 1);
atomic_inc(&usage_count);
return result;
}
@@ -925,6 +1033,12 @@
case AUDIO_SET_LSM_CAL:
store_lsm_cal((struct cal_block *)data);
goto done;
+ case AUDIO_SET_ADM_CUSTOM_TOPOLOGY:
+ store_adm_custom_topology((struct cal_block *)data);
+ goto done;
+ case AUDIO_SET_ASM_CUSTOM_TOPOLOGY:
+ store_asm_custom_topology((struct cal_block *)data);
+ goto done;
default:
pr_err("ACDB=> ACDB ioctl not found!\n");
}
@@ -998,6 +1112,8 @@
memset(&acdb_data, 0, sizeof(acdb_data));
mutex_init(&acdb_data.acdb_mutex);
atomic_set(&usage_count, 0);
+ atomic_set(&acdb_data.valid_adm_custom_top, 1);
+ atomic_set(&acdb_data.valid_asm_custom_top, 1);
return misc_register(&acdb_misc);
}
diff --git a/sound/soc/msm/qdsp6v2/audio_acdb.h b/sound/soc/msm/qdsp6v2/audio_acdb.h
index 8528e3c..0b6110d 100644
--- a/sound/soc/msm/qdsp6v2/audio_acdb.h
+++ b/sound/soc/msm/qdsp6v2/audio_acdb.h
@@ -46,6 +46,9 @@
uint32_t get_adm_rx_topology(void);
uint32_t get_adm_tx_topology(void);
uint32_t get_asm_topology(void);
+void reset_custom_topology_flags(void);
+void get_adm_custom_topology(struct acdb_cal_block *cal_block);
+void get_asm_custom_topology(struct acdb_cal_block *cal_block);
void get_voice_cal_allocation(struct acdb_cal_block *cal_block);
void get_lsm_cal(struct acdb_cal_block *cal_block);
void get_anc_cal(struct acdb_cal_block *cal_block);
diff --git a/sound/soc/msm/qdsp6v2/q6adm.c b/sound/soc/msm/qdsp6v2/q6adm.c
index bc11304..685deef 100644
--- a/sound/soc/msm/qdsp6v2/q6adm.c
+++ b/sound/soc/msm/qdsp6v2/q6adm.c
@@ -46,8 +46,11 @@
/* 0 - (MAX_AUDPROC_TYPES -1): audproc handles */
/* (MAX_AUDPROC_TYPES -1) - (2 * MAX_AUDPROC_TYPES -1): audvol handles */
- atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES)];
+/* + 1 for custom ADM topology */
+ atomic_t mem_map_cal_handles[(2 * MAX_AUDPROC_TYPES) + 1];
atomic_t mem_map_cal_index;
+
+ int set_custom_topology;
};
static struct adm_ctl this_adm;
@@ -309,6 +312,8 @@
atomic_set(&this_adm.copp_stat[i], 0);
}
this_adm.apr = NULL;
+ reset_custom_topology_flags();
+ this_adm.set_custom_topology = 1;
}
pr_debug("Resetting calibration blocks");
for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
@@ -350,6 +355,7 @@
case ADM_CMD_DEVICE_CLOSE_V5:
case ADM_CMD_SHARED_MEM_UNMAP_REGIONS:
case ADM_CMD_MATRIX_MAP_ROUTINGS_V5:
+ case ADM_CMD_ADD_TOPOLOGIES:
pr_debug("%s: Basic callback received, wake up.\n",
__func__);
atomic_set(&this_adm.copp_stat[index], 1);
@@ -435,6 +441,87 @@
return 0;
}
+void send_adm_custom_topology(int port_id)
+{
+ struct acdb_cal_block cal_block;
+ struct cmd_set_topologies adm_top;
+ int index;
+ int result;
+ int size = 4096;
+
+ get_adm_custom_topology(&cal_block);
+ if (cal_block.cal_size == 0) {
+ pr_debug("%s: no cal to send addr= 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+ index = afe_get_port_index(port_id);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: invalid port idx %d portid %#x\n",
+ __func__, index, port_id);
+ goto done;
+ }
+
+ if (this_adm.set_custom_topology) {
+ /* specific index 4 for adm topology memory */
+ atomic_set(&this_adm.mem_map_cal_index, 4);
+
+ /* Only call this once */
+ this_adm.set_custom_topology = 0;
+
+ result = adm_memory_map_regions(port_id, &cal_block.cal_paddr,
+ 0, &size, 1);
+ if (result < 0) {
+ pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+ __func__, cal_block.cal_paddr,
+ cal_block.cal_size);
+ goto done;
+ }
+ }
+
+
+ adm_top.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_top.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(adm_top));
+ adm_top.hdr.src_svc = APR_SVC_ADM;
+ adm_top.hdr.src_domain = APR_DOMAIN_APPS;
+ adm_top.hdr.src_port = port_id;
+ adm_top.hdr.dest_svc = APR_SVC_ADM;
+ adm_top.hdr.dest_domain = APR_DOMAIN_ADSP;
+ adm_top.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+ adm_top.hdr.token = port_id;
+ adm_top.hdr.opcode = ADM_CMD_ADD_TOPOLOGIES;
+ adm_top.payload_addr_lsw = cal_block.cal_paddr;
+ adm_top.payload_addr_msw = 0;
+ adm_top.mem_map_handle = atomic_read(&this_adm.mem_map_cal_handles[4]);
+ adm_top.payload_size = cal_block.cal_size;
+
+ atomic_set(&this_adm.copp_stat[index], 0);
+ pr_debug("%s: Sending ADM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d\n",
+ __func__, adm_top.payload_addr_lsw,
+ adm_top.payload_size);
+ result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_top);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed port = 0x%x payload = 0x%x\n",
+ __func__, port_id, cal_block.cal_paddr);
+ goto done;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(this_adm.wait[index],
+ atomic_read(&this_adm.copp_stat[index]),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!result) {
+ pr_err("%s: Set topologies timed out port = 0x%x, payload = 0x%x\n",
+ __func__, port_id, cal_block.cal_paddr);
+ goto done;
+ }
+
+done:
+ return;
+}
+
static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
{
s32 result = 0;
@@ -684,6 +771,7 @@
rtac_set_adm_handle(this_adm.apr);
}
+ send_adm_custom_topology(port_id);
/* Create a COPP if port id are not enabled */
if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
@@ -1154,6 +1242,7 @@
{
int i = 0;
this_adm.apr = NULL;
+ this_adm.set_custom_topology = 1;
for (i = 0; i < AFE_MAX_PORTS; i++) {
atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 3d8d5eb..b832c41 100644
--- a/sound/soc/msm/qdsp6v2/q6asm.c
+++ b/sound/soc/msm/qdsp6v2/q6asm.c
@@ -106,6 +106,9 @@
static int out_cold_index;
static char *out_buffer;
static char *in_buffer;
+static int set_custom_topology;
+static int topology_map_handle;
+
static int audio_output_latency_dbgfs_open(struct inode *inode,
struct file *file)
{
@@ -341,6 +344,90 @@
return;
}
+void send_asm_custom_topology(struct audio_client *ac)
+{
+ struct acdb_cal_block cal_block;
+ struct cmd_set_topologies asm_top;
+ struct audio_buffer *buf;
+ struct asm_buffer_node *buf_node = NULL;
+ struct list_head *ptr, *next;
+ int result;
+ int size = 4096;
+
+ get_asm_custom_topology(&cal_block);
+ if (cal_block.cal_size == 0) {
+ pr_debug("%s: no cal to send addr= 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+ if (set_custom_topology) {
+ /* Only call this once */
+ set_custom_topology = 0;
+
+ /* Use first asm buf to map memory */
+ buf = kzalloc(sizeof(struct audio_buffer), GFP_KERNEL);
+ if (!buf) {
+ pr_debug("%s: could not allocate temp memory\n",
+ __func__);
+ goto done;
+ }
+ buf[0].phys = cal_block.cal_paddr;
+ ac->port[0].buf = buf;
+
+ result = q6asm_memory_map_regions(ac, 0, size, 1, 1);
+ if (result < 0) {
+ pr_err("%s: mmap did not work! addr = 0x%x, size = %d\n",
+ __func__, cal_block.cal_paddr,
+ cal_block.cal_size);
+ goto done;
+ }
+
+ list_for_each_safe(ptr, next, &ac->port[IN].mem_map_handle) {
+ buf_node = list_entry(ptr, struct asm_buffer_node,
+ list);
+ if (buf_node->buf_addr_lsw == cal_block.cal_paddr) {
+ topology_map_handle = buf_node->mmap_hdl;
+ break;
+ }
+ }
+
+ kfree(buf);
+ }
+
+ q6asm_add_hdr(ac, &asm_top.hdr, APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(asm_top)), TRUE);
+
+ asm_top.hdr.opcode = ASM_CMD_ADD_TOPOLOGIES;
+ asm_top.payload_addr_lsw = cal_block.cal_paddr;
+ asm_top.payload_addr_msw = 0;
+ asm_top.mem_map_handle = topology_map_handle;
+ asm_top.payload_size = cal_block.cal_size;
+
+ pr_debug("%s: Sending ASM_CMD_ADD_TOPOLOGIES payload = 0x%x, size = %d, map handle = 0x%x\n",
+ __func__, asm_top.payload_addr_lsw,
+ asm_top.payload_size, asm_top.mem_map_handle);
+
+ result = apr_send_pkt(ac->apr, (uint32_t *) &asm_top);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed payload = 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+ result = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (result < 0) {
+ pr_err("%s: Set topologies failed payload = 0x%x\n",
+ __func__, cal_block.cal_paddr);
+ goto done;
+ }
+
+
+done:
+ return;
+}
+
int q6asm_audio_client_buf_free(unsigned int dir,
struct audio_client *ac)
{
@@ -563,6 +650,8 @@
atomic_set(&ac->cmd_state, 0);
atomic_set(&ac->nowait_cmd_cnt, 0);
+ send_asm_custom_topology(ac);
+
pr_debug("%s: session[%d]\n", __func__, ac->session);
return ac;
@@ -822,6 +911,8 @@
apr_reset(this_mmap.apr);
atomic_set(&this_mmap.ref_cnt, 0);
this_mmap.apr = NULL;
+ reset_custom_topology_flags();
+ set_custom_topology = 1;
return 0;
}
sid = (data->token >> 8) & 0x0F;
@@ -956,6 +1047,8 @@
(uint32_t *)data->payload, ac->priv);
apr_reset(ac->apr);
ac->apr = NULL;
+ reset_custom_topology_flags();
+ set_custom_topology = 1;
return 0;
}
@@ -997,6 +1090,7 @@
case ASM_STREAM_CMD_OPEN_READWRITE_V2:
case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ case ASM_CMD_ADD_TOPOLOGIES:
pr_debug("%s:Payload = [0x%x]stat[0x%x]\n",
__func__, payload[0], payload[1]);
if (atomic_read(&ac->cmd_state) && wakeup_flag) {
@@ -3564,6 +3658,7 @@
{
pr_debug("%s\n", __func__);
memset(session, 0, sizeof(session));
+ set_custom_topology = 1;
config_debug_fs_init();