summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/msm/msm.txt1
-rw-r--r--Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt82
-rw-r--r--Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt10
-rw-r--r--Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt26
-rw-r--r--arch/arm/boot/dts/qcom/Makefile3
-rw-r--r--arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi23
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi4
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi8
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd.dts2
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi13
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi37
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt.dtsi32
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-rumi.dts29
-rw-r--r--arch/arm64/Kconfig.platforms1
-rw-r--r--arch/arm64/configs/msm-perf_defconfig8
-rw-r--r--arch/arm64/configs/msm_defconfig7
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig9
-rw-r--r--arch/arm64/configs/msmcortex_defconfig10
-rw-r--r--arch/um/configs/x86_64_um_defconfig2
-rw-r--r--drivers/base/regmap/regmap-debugfs.c1
-rw-r--r--drivers/clk/msm/clock-alpha-pll.c2
-rw-r--r--drivers/clk/msm/clock-gpu-cobalt.c7
-rw-r--r--drivers/clk/msm/clock-local2.c50
-rw-r--r--drivers/clk/msm/clock-mmss-cobalt.c168
-rw-r--r--drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c10
-rw-r--r--drivers/gpu/msm/kgsl_pool.c9
-rw-r--r--drivers/iommu/io-pgtable-fast.c3
-rw-r--r--drivers/iommu/iommu-debug.c4
-rw-r--r--drivers/leds/leds-qpnp-flash-v2.c680
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp.h2
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp40.c3
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c159
-rw-r--r--drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c9
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c56
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c30
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c36
-rw-r--r--drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h3
-rw-r--r--drivers/media/platform/msm/vidc/msm_smem.c19
-rw-r--r--drivers/media/platform/msm/vidc/msm_venc.c72
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc.c20
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_common.c32
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_internal.h1
-rw-r--r--drivers/media/platform/msm/vidc/venus_hfi.c27
-rw-r--r--drivers/mfd/qcom-i2c-pmic.c23
-rw-r--r--drivers/misc/qseecom.c9
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c16
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/p2p.c6
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h1
-rw-r--r--drivers/net/wireless/cnss/cnss_common.c2
-rw-r--r--drivers/net/wireless/cnss/cnss_common.h40
-rw-r--r--drivers/net/wireless/cnss/cnss_pci.c4
-rw-r--r--drivers/net/wireless/cnss/cnss_sdio.c4
-rw-r--r--drivers/platform/msm/ipa/ipa_rm.c20
-rw-r--r--drivers/platform/msm/ipa/ipa_rm_resource.c5
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c26
-rw-r--r--drivers/power/qcom-charger/smb-lib.c16
-rw-r--r--drivers/soc/qcom/icnss.c54
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr_tal_glink.c1
-rw-r--r--drivers/thermal/msm_lmh_dcvs.c10
-rw-r--r--drivers/usb/dwc3/core.c4
-rw-r--r--drivers/usb/gadget/function/f_gsi.c15
-rw-r--r--drivers/usb/gadget/function/f_gsi.h3
-rw-r--r--drivers/usb/host/xhci-plat.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.c115
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_edid.h18
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_pp.c42
-rw-r--r--include/dt-bindings/clock/msm-clocks-cobalt.h9
-rw-r--r--include/linux/inet_lro.h89
-rw-r--r--include/linux/leds-qpnp-flash-v2.h27
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/media/videobuf2-core.h2
-rw-r--r--include/net/cnss.h32
-rw-r--r--include/net/cnss_common.h73
-rw-r--r--include/soc/qcom/clock-local2.h1
-rw-r--r--include/uapi/linux/videodev2.h2
-rw-r--r--include/uapi/media/msm_sde_rotator.h14
-rw-r--r--kernel/sched/core.c1
-rw-r--r--kernel/sched/fair.c9
-rw-r--r--net/ipv4/inet_lro.c316
-rw-r--r--net/wireless/nl80211.c8
-rwxr-xr-xsound/soc/codecs/Kconfig2
-rwxr-xr-xsound/soc/codecs/wcd9335.c121
-rw-r--r--sound/soc/msm/msmcobalt.c237
-rw-r--r--sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c2
-rw-r--r--sound/soc/msm/qdsp6v2/q6core.c35
-rw-r--r--sound/usb/Kconfig8
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/card.c2
-rw-r--r--sound/usb/stream.c5
-rw-r--r--sound/usb/usb_audio_qmi_svc.c1122
-rw-r--r--sound/usb/usb_audio_qmi_v01.c565
-rw-r--r--sound/usb/usb_audio_qmi_v01.h103
-rw-r--r--sound/usb/usbaudio.h2
97 files changed, 4288 insertions, 670 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index 1c0dfa43952c..a35a8f0d6622 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -255,6 +255,7 @@ compatible = "qcom,msmhamster-rumi"
compatible = "qcom,msmhamster-cdp"
compatible = "qcom,msmhamster-mtp"
compatible = "qcom,msmfalcon-sim"
+compatible = "qcom,msmfalcon-rumi"
compatible = "qcom,msm8952-rumi"
compatible = "qcom,msm8952-sim"
compatible = "qcom,msm8952-qrd"
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
index f1a8c77c8387..1102cb5d4f6f 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt
@@ -6,6 +6,8 @@ camera sensor when background light is dim to capture good
picture. It can also be used for flashlight/torch application.
It is part of PMIC on Qualcomm Technologies Inc. reference platforms.
+Main node:
+
Required properties:
- compatible : Should be "qcom,qpnp-flash-led-v2"
- reg : Base address and size for flash LED modules
@@ -14,10 +16,17 @@ Optional properties:
- qcom,hdrm-auto-mode : Boolean type to select headroom auto mode enabled or not
- qcom,isc-delay : Integer type to specify short circuit delay. Valid values are 32, 64,
128, 192. Unit is us.
+- qcom,hw-strobe-option : Integer type to specify hardware strobe option. Based on the specified
+ value, additional GPIO configuration may be required to provide strobing
+ support. Supported values are:
+ 0: Flash strobe is used for LED1, LED2, LED3
+ 1: Flash strobe is used for LED1, LED2 and GPIO10 is used for LED3
+ 2: Flash strobe is used for LED1; GPIO9 is used for LED2; GPIO10 is used for LED3
+
+Child node: Contains settings for each individual LED. Each LED channel needs a flash node and
+torch node for itself, and an individual switch node to serve as an overall switch.
-Required properties inside child node. Child node contains settings for each individual LED.
-Each LED channel needs a flash node and torch node for itself, and an individual switch node to
-serve as an overall switch.
+Required Properties:
- label : Type of led that will be used, either "flash", "torch", or "switch.
- qcom,led-name : Name of the LED.
- qcom,default-led-trigger : Trigger for the camera flash and torch. Accepted values are
@@ -34,8 +43,12 @@ serve as an overall switch.
- qcom,duration-ms : Required property for flash nodes but not needed for torch. Integer
type specifying flash duration. Values are from 10ms to 1280ms with
10ms resolution. This is not required for switch node.
+- qcom,led-mask : Required property for switch nodes. Bitmask to indicate which leds are
+ controlled by this switch node. Accepted values are in the range 1 to 7,
+ inclusive. Example:
+ qcom,led-mask = <4>; /* This switch node controls the flash2/torch2 led. */
-Optional properties inside child node:
+Optional properties:
- qcom,current-ma : operational current intensity for LED in mA. Accepted values are a
positive integer in the range of 0 to qcom,max-current inclusive.
- qcom,ires-ua : Integer type to specify current resolution. Accepted values should be
@@ -44,15 +57,35 @@ Optional properties inside child node:
with 25mV resolution. Default setting is 325mV
- qcom,hdrm-vol-hi-lo-win-mv : Integer type to specify headroom voltage swing range. Values are
from 0mV to 375mV with 25mV resolution. Default setting is 100mV.
-- pinctrl-names : This should be defined if a target uses pinctrl framework and there is GPIO
- requirement for flash LEDs. See "pinctrl" in
- Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt. It should specify
- the names of the configs that pinctrl can install in driver.
- Following are the pinctrl configs that can be installed:
- "led_enable" : Enablement configuration of pins. This should specify active
- config defined in each pin or pin group.
- "led_disable" : Disablement configuration of pins. This should specify inactive
- config defined in each pin or pin groups.
+- pinctrl-names : Name of the pinctrl configuration that will be used when external GPIOs
+ are used for enabling/disabling, HW strobing of flash LEDs. For more
+ information on using pinctrl, please refer
+ Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt
+ Following are the pinctrl configs that can be specified:
+ "led_enable" : pinctrl config to enable led. This should specify the active
+ configuration defined for each pin or pin group.
+ "led_disable" : pinctrl config to disable led. This should specify the sleep
+ configuration defined for each pin or pin group.
+ "strobe_enable" : pinctrl config to enable hw-strobe. This should specify the
+ active configuration defined for each pin or pin group.
+ "strobe_disable" : pinctrl config to disable hw-strobe. This should specify the
+ sleep configuration defined for each pin or pin group.
+- qcom,hw-strobe-gpio : phandle to specify GPIO for hardware strobing. This is used when there is no
+ pinctrl support or PMIC GPIOs are used.
+- qcom,hw-strobe-sel : Boolean property to enable hardware strobe. If not defined, software strobe
+ will be used.
+- qcom,hw-strobe-edge-trigger : Boolean property to select trigger type. If defined, hw-strobe is set to
+ be edge triggered. Otherwise, it is level triggered.
+- qcom,hw-strobe-active-low : Boolean property to select strobe signal polarity. If defined, hw-strobe
+ signal polarity is set to active-low, else it is active-high.
+- reg<n> : reg<n> (<n> represents number. e.g. 0,1,2,..) subnode is to add support for
+ multiple power sources. This subnode should only be specified for switch nodes.
+ Required property inside regulator node:
+ - regulator-name : Name of the regulator which has to be used for this
+ switch node.
+ Optional property inside regulator node:
+ - max-voltage-uv : This specifies max voltage of regulator. Some switch
+ or boost regulator does not need this property.
Example:
qcom,leds@d300 {
@@ -151,11 +184,28 @@ Example:
pinctrl-1 = <&led_disable>;
};
- pmi8998_switch: qcom,led_switch {
+ pmi8998_switch0: qcom,led_switch_0 {
+ label = "switch";
+ qcom,led-name = "led:switch_0";
+ qcom,led-mask = <3>;
+ qcom,default-led-trigger =
+ "switch0_trigger";
+ reg0 {
+ regulator-name = "pmicobalt_bob";
+ max-voltage-uv = <3600000>;
+ };
+ };
+
+ pmi8998_switch1: qcom,led_switch_1 {
label = "switch";
- qcom,led-name = "led:switch";
+ qcom,led-name = "led:switch_1";
+ qcom,led-mask = <4>;
qcom,default-led-trigger =
- "switch_trigger";
+ "switch1_trigger";
+ reg0 {
+ regulator-name = "pmicobalt_bob";
+ max-voltage-uv = <3600000>;
+ };
};
};
diff --git a/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt b/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt
index 9c7c856ea42b..7e9aee1a96b3 100644
--- a/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt
+++ b/Documentation/devicetree/bindings/mfd/qcom-i2c-pmic.txt
@@ -32,29 +32,29 @@ Platform independent properties:
Definition: 7-bit I2C address of the device.
- interrupt-parent
- Usage: required
+ Usage: optional
Value type: <phandle>
Definition: phandle of the interrupt controller which services the
summary interrupt.
- interrupts
- Usage: required
+ Usage: optional
Value type: <prop-encoded-array>
Definition: Summary interrupt specifier.
- interrupt-controller
- Usage: required
+ Usage: optional
Value type: <empty>
Definition: Boolean flag which indicates this device node is an
interrupt controller.
- #interrupt-cells
- Usage: required
+ Usage: optional
Value type: <u32>
Definition: Number of cells to encode an interrupt source.
- qcom,periph-map
- Usage: required
+ Usage: optional
Value type: <prop-encoded-array>
Definition: A list of u32 arrays. This provides a mapping between the
summary status register bits and peripheral addresses.
diff --git a/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt b/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt
new file mode 100644
index 000000000000..9d3fb78f96a7
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom-usb-audio-qmi-dev.txt
@@ -0,0 +1,26 @@
+QTI USB Audio QMI Device
+
+USB Audio QMI device is used to attach to remote processor IOMMU and
+map USB Audio driver specific memory to iova to share with remote
+processor.
+
+Required Properties:
+
+- compatible : "qcom,usb-audio-qmi-dev"
+
+- iommus : A list of phandle and IOMMU specifier pairs that describe the
+ IOMMU master interfaces of the device.
+
+- qcom,usb-audio-stream-id : Stream id is prepended to iova before passing
+ iova to remote processor. This allows remote processor to access iova.
+
+- qcom,usb-audio-intr-num : Interrupter number for external sub system
+ destination.
+
+Example:
+ usb_audio_qmi_dev {
+ compatible = "qcom,usb-audio-qmi-dev";
+ iommus = <&lpass_q6_smmu 12>;
+ qcom,usb-audio-stream-id = <12>;
+ qcom,usb-audio-intr-num = <1>;
+ };
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index dd955be6c908..a42019b58897 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -116,7 +116,8 @@ dtb-$(CONFIG_ARCH_MSMCOBALT) += msmcobalt-sim.dtb \
dtb-$(CONFIG_ARCH_MSMHAMSTER) += msmhamster-rumi.dtb
-dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb
+dtb-$(CONFIG_ARCH_MSMFALCON) += msmfalcon-sim.dtb \
+ msmfalcon-rumi.dtb
ifeq ($(CONFIG_ARM64),y)
always := $(dtb-y)
diff --git a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi
index 97abec77bed7..ab46221089f3 100644
--- a/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-arm-smmu-cobalt.dtsi
@@ -113,6 +113,7 @@
reg = <0xcd00000 0x40000>;
#iommu-cells = <1>;
qcom,register-save;
+ qcom,no-smr-check;
qcom,skip-init;
#global-interrupts = <2>;
interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
index f5b59e6de558..fad834199be5 100644
--- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
@@ -683,11 +683,26 @@
pinctrl-1 = <&led_disable>;
};
- pmicobalt_switch: qcom,led_switch {
+ pmicobalt_switch0: qcom,led_switch_0 {
label = "switch";
- qcom,led-name = "led:switch";
- qcom,default-led-trigger =
- "switch_trigger";
+ qcom,led-name = "led:switch_0";
+ qcom,led-mask = <3>;
+ qcom,default-led-trigger = "switch0_trigger";
+ reg0 {
+ regulator-name = "pmicobalt_bob";
+ max-voltage-uv = <3600000>;
+ };
+ };
+
+ pmicobalt_switch1: qcom,led_switch_1 {
+ label = "switch";
+ qcom,led-name = "led:switch_1";
+ qcom,led-mask = <4>;
+ qcom,default-led-trigger = "switch1_trigger";
+ reg0 {
+ regulator-name = "pmicobalt_bob";
+ max-voltage-uv = <3600000>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
index ae878c7f5bac..b414a215cbaa 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi
@@ -30,6 +30,7 @@
sound-9335 {
compatible = "qcom,msmcobalt-asoc-snd-tasha";
qcom,model = "msmcobalt-tasha-snd-card";
+ qcom,hdmi-audio-rx;
qcom,audio-routing =
"AIF4 VI", "MCLK",
@@ -98,8 +99,9 @@
"msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398",
"msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401",
"msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673";
- asoc-codec = <&stub_codec>;
- asoc-codec-names = "msm-stub-codec.1";
+ asoc-codec = <&stub_codec>, <&hdmi_audio>;
+ asoc-codec-names = "msm-stub-codec.1",
+ "msm-hdmi-audio-codec-rx";
qcom,wsa-max-devs = <2>;
qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
<&wsa881x_213>, <&wsa881x_214>;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi
index 83b55da92fa2..3ed038069319 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-cdp.dtsi
@@ -16,7 +16,7 @@
cell-index = <0>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmicobalt_flash0 &pmicobalt_flash1>;
- qcom,switch-source = <&pmicobalt_switch>;
+ qcom,switch-source = <&pmicobalt_switch0>;
status = "ok";
};
@@ -24,7 +24,7 @@
cell-index = <1>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmicobalt_flash2>;
- qcom,switch-source = <&pmicobalt_switch>;
+ qcom,switch-source = <&pmicobalt_switch1>;
status = "ok";
};
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
index 83b55da92fa2..d152c0049f96 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
@@ -16,7 +16,7 @@
cell-index = <0>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmicobalt_flash0 &pmicobalt_flash1>;
- qcom,switch-source = <&pmicobalt_switch>;
+ qcom,switch-source = <&pmicobalt_switch0>;
status = "ok";
};
@@ -24,7 +24,7 @@
cell-index = <1>;
compatible = "qcom,camera-flash";
qcom,flash-source = <&pmicobalt_flash2>;
- qcom,switch-source = <&pmicobalt_switch>;
+ qcom,switch-source = <&pmicobalt_switch1>;
status = "ok";
};
};
@@ -198,7 +198,7 @@
reg = <0x0>;
qcom,csiphy-sd-index = <0>;
qcom,csid-sd-index = <0>;
- qcom,mount-angle = <90>;
+ qcom,mount-angle = <270>;
qcom,led-flash-src = <&led_flash0>;
qcom,actuator-src = <&actuator0>;
qcom,ois-src = <&ois0>;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi
index 73f612516f84..b5d3a85f9b15 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-pm.dtsi
@@ -382,7 +382,13 @@
<0xff 324>, /* lpass_qca_slimbus_bam_ee1_irq */
<0xff 432>, /* smmu_Cirpt[8] */
<0xff 433>, /* smmu_Cirpt[9] */
- <0xff 461>; /* o_ocimem_nonsec_irq */
+ <0xff 461>, /* o_ocimem_nonsec_irq */
+ <0xff 69>, /* o_pwr_dcvsh_interrupt */
+ <0xff 70>, /* o_perf_dcvsh_interrupt */
+ <0xff 166>, /* o_lm_int_2qgic */
+ <0xff 238>, /* crypto_bam_irq[0] */
+ <0xff 132>; /* qup_irq */
+
qcom,gpio-parent = <&tlmm>;
qcom,gpio-map = <3 1>,
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts
index 9848d6da33a5..d95507b505c2 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dts
@@ -14,7 +14,7 @@
/dts-v1/;
#include "msmcobalt.dtsi"
-#include "msmcobalt-mtp.dtsi"
+#include "msmcobalt-qrd.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM COBALT QRD";
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
new file mode 100644
index 000000000000..1720aca3b298
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmcobalt-qrd.dtsi
@@ -0,0 +1,13 @@
+/* Copyright (c) 2016, 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 "msmcobalt-mtp.dtsi"
diff --git a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
index 1d43d694eee5..9b5f68f60abc 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-regulator.dtsi
@@ -149,6 +149,9 @@
pmcobalt_l1: regulator-l1 {
regulator-min-microvolt = <880000>;
regulator-max-microvolt = <880000>;
+ proxy-supply = <&pmcobalt_l1>;
+ qcom,proxy-consumer-enable;
+ qcom,proxy-consumer-current = <73400>;
status = "okay";
};
};
@@ -158,6 +161,9 @@
pmcobalt_l2: regulator-l2 {
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
+ proxy-supply = <&pmcobalt_l2>;
+ qcom,proxy-consumer-enable;
+ qcom,proxy-consumer-current = <12560>;
status = "okay";
};
};
@@ -298,6 +304,9 @@
pmcobalt_l14: regulator-l14 {
regulator-min-microvolt = <1880000>;
regulator-max-microvolt = <1880000>;
+ proxy-supply = <&pmcobalt_l14>;
+ qcom,proxy-consumer-enable;
+ qcom,proxy-consumer-current = <32000>;
status = "okay";
};
};
@@ -862,23 +871,23 @@
qcom,cpr-open-loop-voltage-fuse-adjustment =
<0 0 0 0>,
- <0 0 0 20000>,
- <0 0 0 20000>,
- <0 0 0 20000>,
- <0 0 0 20000>,
- <0 0 0 20000>,
- <0 0 0 20000>,
- <0 0 0 20000>;
+ <8000 0 0 52000>,
+ <8000 0 0 52000>,
+ <8000 0 0 52000>,
+ <8000 0 0 52000>,
+ <8000 0 0 52000>,
+ <8000 0 0 52000>,
+ <8000 0 0 52000>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
<0 0 0 0>,
- <1000 0 0 21000>,
- <1000 0 0 21000>,
- <1000 0 0 21000>,
- <1000 0 0 21000>,
- <1000 0 0 21000>,
- <1000 0 0 21000>,
- <1000 0 0 21000>;
+ <0 0 0 50000>,
+ <0 0 0 50000>,
+ <0 0 0 50000>,
+ <0 0 0 50000>,
+ <0 0 0 50000>,
+ <0 0 0 50000>,
+ <0 0 0 50000>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
index 8d778ac3f104..19a9c8f844be 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
@@ -258,7 +258,7 @@
removed_regions: removed_regions@85800000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0 0x85800000 0 0x5300000>;
+ reg = <0 0x85800000 0 0x3700000>;
};
peripheral_mem: peripheral_region@91900000 {
@@ -310,6 +310,16 @@
alignment = <0 0x200000>;
size = <0 0x5c00000>;
};
+
+ /* global autoconfigured region for contiguous allocations */
+ linux,cma {
+ compatible = "shared-dma-pool";
+ alloc-ranges = <0 0x00000000 0 0xffffffff>;
+ reusable;
+ alignment = <0 0x400000>;
+ size = <0 0x2000000>;
+ linux,cma-default;
+ };
};
};
@@ -1117,11 +1127,6 @@
label = "adsprpc-smd";
iommus = <&lpass_q6_smmu 11>;
};
- qcom,msm_fastrpc_compute_cb5 {
- compatible = "qcom,msm-fastrpc-compute-cb";
- label = "adsprpc-smd";
- iommus = <&lpass_q6_smmu 12>;
- };
qcom,msm_fastrpc_compute_cb6 {
compatible = "qcom,msm-fastrpc-compute-cb";
label = "adsprpc-smd";
@@ -1906,6 +1911,13 @@
"phy_phy_reset", "ref_clk_src", "ref_clk";
};
+ usb_audio_qmi_dev {
+ compatible = "qcom,usb-audio-qmi-dev";
+ iommus = <&lpass_q6_smmu 12>;
+ qcom,usb-audio-stream-id = <12>;
+ qcom,usb-audio-intr-num = <2>;
+ };
+
dbm_1p5: dbm@a8f8000 {
compatible = "qcom,usb-dbm-1p5";
reg = <0xa8f8000 0x300>;
@@ -2497,6 +2509,12 @@
qcom,rtb-size = <0x100000>;
};
+ qcom,mpm2-sleep-counter@10a3000 {
+ compatible = "qcom,mpm2-sleep-counter";
+ reg = <0x010a3000 0x1000>;
+ clock-frequency = <32768>;
+ };
+
qcom,msm-imem@146bf000 {
compatible = "qcom,msm-imem";
reg = <0x146bf000 0x1000>;
@@ -2758,6 +2776,8 @@
&gdsc_bimc_smmu {
clock-names = "bus_clk";
clocks = <&clock_mmss clk_mmss_bimc_smmu_axi_clk>;
+ proxy-supply = <&gdsc_bimc_smmu>;
+ qcom,proxy-consumer-enable;
status = "ok";
};
diff --git a/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
new file mode 100644
index 000000000000..6631d31bac6d
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/msmfalcon-rumi.dts
@@ -0,0 +1,29 @@
+/* Copyright (c) 2016, 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 "msmfalcon.dtsi"
+#include "msmfalcon-pinctrl.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM FALCON RUMI";
+ compatible = "qcom,msmfalcon-rumi", "qcom,msmfalcon", "qcom,rumi";
+ qcom,board-id = <15 0>;
+};
+
+&uartblsp2dm1 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 4e38de7ddd3e..084b942d102d 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -56,6 +56,7 @@ config ARCH_QCOM
select SOC_BUS
select MSM_IRQ
select THERMAL_WRITABLE_TRIPS
+ select RATIONAL
help
This enables support for the ARMv8 based Qualcomm chipsets.
diff --git a/arch/arm64/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index bf60b4047cb1..fc2cce36bff9 100644
--- a/arch/arm64/configs/msm-perf_defconfig
+++ b/arch/arm64/configs/msm-perf_defconfig
@@ -36,6 +36,9 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_MSM8996=y
@@ -92,6 +95,7 @@ CONFIG_INET6_IPCOMP=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
+# CONFIG_NET_ACTIVITY_STATS is not set
CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_SECMARK=y
@@ -140,7 +144,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
@@ -228,7 +231,6 @@ CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_UID_STAT=y
CONFIG_QSEECOM=y
CONFIG_HDCP_QSEECOM=y
CONFIG_UID_CPUTIME=y
@@ -566,7 +568,6 @@ CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_DEBUG_RODATA=y
CONFIG_DEBUG_ALIGN_RODATA=y
-CONFIG_KEYS=y
CONFIG_PFK=y
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
@@ -574,7 +575,6 @@ CONFIG_SECURITY_SELINUX=y
CONFIG_CRYPTO_ECHAINIV=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_CRYPTO_DEV_QCRYPTO=y
diff --git a/arch/arm64/configs/msm_defconfig b/arch/arm64/configs/msm_defconfig
index 6c37c8fdf0fc..38e489936895 100644
--- a/arch/arm64/configs/msm_defconfig
+++ b/arch/arm64/configs/msm_defconfig
@@ -33,6 +33,9 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_MSM8996=y
@@ -95,6 +98,7 @@ CONFIG_INET6_IPCOMP=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
+# CONFIG_NET_ACTIVITY_STATS is not set
CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_SECMARK=y
@@ -143,7 +147,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
@@ -221,7 +224,6 @@ CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_UID_STAT=y
CONFIG_QSEECOM=y
CONFIG_HDCP_QSEECOM=y
CONFIG_UID_CPUTIME=y
@@ -604,7 +606,6 @@ CONFIG_ARM64_PTDUMP=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_FREE_PAGES_RDONLY=y
CONFIG_KERNEL_TEXT_RDONLY=y
-CONFIG_KEYS=y
CONFIG_PFK=y
CONFIG_SECURITY=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/arm64/configs/msmcortex-perf_defconfig b/arch/arm64/configs/msmcortex-perf_defconfig
index 706d01e147f5..3ee7e7827f63 100644
--- a/arch/arm64/configs/msmcortex-perf_defconfig
+++ b/arch/arm64/configs/msmcortex-perf_defconfig
@@ -35,6 +35,9 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_QCOM=y
CONFIG_ARCH_MSMCOBALT=y
@@ -85,7 +88,6 @@ CONFIG_IP_PNP_DHCP=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
-# CONFIG_INET_LRO is not set
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -95,6 +97,7 @@ CONFIG_INET6_IPCOMP=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
+# CONFIG_NET_ACTIVITY_STATS is not set
CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_SECMARK=y
@@ -143,7 +146,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
@@ -222,7 +224,6 @@ CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_UID_STAT=y
CONFIG_QSEECOM=y
CONFIG_HDCP_QSEECOM=y
CONFIG_SCSI=y
@@ -383,6 +384,7 @@ CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_AUDIO_QMI=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSMCOBALT=y
CONFIG_UHID=y
@@ -540,7 +542,6 @@ CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_DEBUG_SET_MODULE_RONX=y
CONFIG_DEBUG_RODATA=y
CONFIG_DEBUG_ALIGN_RODATA=y
-CONFIG_KEYS=y
CONFIG_PFK=y
CONFIG_SECURITY=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/arm64/configs/msmcortex_defconfig b/arch/arm64/configs/msmcortex_defconfig
index 0b275d433fc3..63f8969399f2 100644
--- a/arch/arm64/configs/msmcortex_defconfig
+++ b/arch/arm64/configs/msmcortex_defconfig
@@ -34,6 +34,9 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PARTITION_ADVANCED=y
# CONFIG_IOSCHED_DEADLINE is not set
@@ -86,7 +89,6 @@ CONFIG_IP_PNP_DHCP=y
CONFIG_INET_AH=y
CONFIG_INET_ESP=y
CONFIG_INET_IPCOMP=y
-# CONFIG_INET_LRO is not set
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
@@ -96,6 +98,7 @@ CONFIG_INET6_IPCOMP=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
+# CONFIG_NET_ACTIVITY_STATS is not set
CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=y
CONFIG_NF_CONNTRACK_SECMARK=y
@@ -144,7 +147,6 @@ CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_NETFILTER_XT_MATCH_POLICY=y
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
-CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
@@ -221,12 +223,10 @@ CONFIG_IPC_ROUTER=y
CONFIG_IPC_ROUTER_SECURITY=y
CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y
CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=40
CONFIG_ZRAM=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_UID_STAT=y
CONFIG_QSEECOM=y
CONFIG_HDCP_QSEECOM=y
CONFIG_UID_CPUTIME=y
@@ -389,6 +389,7 @@ CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_USB_AUDIO=y
+CONFIG_SND_USB_AUDIO_QMI=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_MSMCOBALT=y
CONFIG_UHID=y
@@ -625,7 +626,6 @@ CONFIG_CORESIGHT_TPDA=y
CONFIG_CORESIGHT_TPDM=y
CONFIG_CORESIGHT_QPDI=y
CONFIG_CORESIGHT_SOURCE_DUMMY=y
-CONFIG_KEYS=y
CONFIG_PFK=y
CONFIG_SECURITY=y
CONFIG_SECURITY_SELINUX=y
diff --git a/arch/um/configs/x86_64_um_defconfig b/arch/um/configs/x86_64_um_defconfig
index 078e6d981acd..487b68bad250 100644
--- a/arch/um/configs/x86_64_um_defconfig
+++ b/arch/um/configs/x86_64_um_defconfig
@@ -655,7 +655,7 @@ CONFIG_IPV6_MULTIPLE_TABLES=y
# CONFIG_IPV6_SUBTREES is not set
# CONFIG_IPV6_MROUTE is not set
# CONFIG_ANDROID_PARANOID_NETWORK is not set
-CONFIG_NET_ACTIVITY_STATS=y
+# CONFIG_NET_ACTIVITY_STATS is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NET_PTP_CLASSIFY is not set
# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index f16fa6cc23bc..8d456e3e42a0 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -667,6 +667,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
debugfs_create_x32("address", 0600, map->debugfs,
&map->dump_address);
+ map->dump_count = 1;
debugfs_create_u32("count", 0600, map->debugfs,
&map->dump_count);
debugfs_create_file("data", registers_mode, map->debugfs,
diff --git a/drivers/clk/msm/clock-alpha-pll.c b/drivers/clk/msm/clock-alpha-pll.c
index 5c8c45fe4ff6..b9a1167a790d 100644
--- a/drivers/clk/msm/clock-alpha-pll.c
+++ b/drivers/clk/msm/clock-alpha-pll.c
@@ -1040,7 +1040,7 @@ static enum handoff fabia_alpha_pll_handoff(struct clk *c)
if (!is_locked(pll)) {
if (c->rate && fabia_alpha_pll_set_rate(c, c->rate))
WARN(1, "%s: Failed to configure rate\n", c->dbg_name);
- __init_alpha_pll(c);
+ __init_fabia_alpha_pll(c);
return HANDOFF_DISABLED_CLK;
} else if (pll->fsm_en_mask && !is_fsm_mode(MODE_REG(pll))) {
WARN(1, "%s should be in FSM mode but is not\n", c->dbg_name);
diff --git a/drivers/clk/msm/clock-gpu-cobalt.c b/drivers/clk/msm/clock-gpu-cobalt.c
index 63870aaa487b..ce3e7916e658 100644
--- a/drivers/clk/msm/clock-gpu-cobalt.c
+++ b/drivers/clk/msm/clock-gpu-cobalt.c
@@ -285,9 +285,10 @@ static struct rcg_clk rbbmtimer_clk_src = {
};
static struct clk_freq_tbl ftbl_gfx3d_isense_clk_src[] = {
- F( 40000000, gpucc_gpll0, 15, 0, 0),
- F( 200000000, gpucc_gpll0, 3, 0, 0),
- F( 300000000, gpucc_gpll0, 2, 0, 0),
+ F( 19200000, gpucc_cxo_clk, 1, 0, 0),
+ F( 40000000, gpucc_gpll0, 15, 0, 0),
+ F( 200000000, gpucc_gpll0, 3, 0, 0),
+ F( 300000000, gpucc_gpll0, 2, 0, 0),
F_END
};
diff --git a/drivers/clk/msm/clock-local2.c b/drivers/clk/msm/clock-local2.c
index 55fa76046def..6cf53c78d4d6 100644
--- a/drivers/clk/msm/clock-local2.c
+++ b/drivers/clk/msm/clock-local2.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
+#include <linux/rational.h>
#include <linux/clk.h>
#include <linux/clk/msm-clk-provider.h>
#include <linux/clk/msm-clk.h>
@@ -1735,6 +1736,46 @@ static struct clk *edp_clk_get_parent(struct clk *c)
return freq->src_clk;
}
+static int rcg_clk_set_rate_dp(struct clk *clk, unsigned long rate)
+{
+ struct rcg_clk *rcg = to_rcg_clk(clk);
+ struct clk_freq_tbl *freq_tbl = rcg->current_freq;
+ unsigned long src_rate;
+ unsigned long num, den, flags;
+
+ src_rate = clk_get_rate(clk->parent);
+ if (src_rate <= 0) {
+ pr_err("Invalid RCG parent rate\n");
+ return -EINVAL;
+ }
+
+ rational_best_approximation(src_rate, rate,
+ (unsigned long)(1 << 16) - 1,
+ (unsigned long)(1 << 16) - 1, &den, &num);
+
+ if (!num || !den) {
+ pr_err("Invalid MN values derived for requested rate %lu\n",
+ rate);
+ return -EINVAL;
+ }
+
+ freq_tbl->div_src_val &= ~BM(4, 0);
+ if (num == den) {
+ freq_tbl->m_val = 0;
+ freq_tbl->n_val = 0;
+ } else {
+ freq_tbl->m_val = num;
+ freq_tbl->n_val = ~(den - num);
+ freq_tbl->d_val = ~den;
+ }
+
+ spin_lock_irqsave(&local_clock_reg_lock, flags);
+ if (!is_same_rcg_config(rcg, freq_tbl, true))
+ __set_rate_mnd(rcg, freq_tbl);
+ spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+ return 0;
+}
+
static int gate_clk_enable(struct clk *c)
{
unsigned long flags;
@@ -2291,6 +2332,15 @@ struct clk_ops clk_ops_rcg_edp = {
.list_registers = rcg_hid_clk_list_registers,
};
+struct clk_ops clk_ops_rcg_dp = {
+ .enable = rcg_clk_enable,
+ .disable = rcg_clk_disable,
+ .set_rate = rcg_clk_set_rate_dp,
+ .list_rate = rcg_clk_list_rate,
+ .handoff = pixel_rcg_handoff,
+ .list_registers = rcg_mnd_clk_list_registers,
+};
+
struct clk_ops clk_ops_branch = {
.enable = branch_clk_enable,
.prepare = branch_clk_prepare,
diff --git a/drivers/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c
index 47466ad04311..53c657ef3a25 100644
--- a/drivers/clk/msm/clock-mmss-cobalt.c
+++ b/drivers/clk/msm/clock-mmss-cobalt.c
@@ -46,7 +46,9 @@ static void __iomem *virt_base;
#define mmpll10_pll_out_mm_source_val 4
#define dsi0phypll_mm_source_val 1
#define dsi1phypll_mm_source_val 2
-#define hdmiphypll_mm_source_val 1
+#define hdmiphypll_mm_source_val 1
+#define ext_dp_phy_pll_link_mm_source_val 1
+#define ext_dp_phy_pll_vco_mm_source_val 2
#define FIXDIV(div) (div ? (2 * (div) - 1) : (0))
@@ -61,9 +63,23 @@ static void __iomem *virt_base;
| BVAL(10, 8, s##_mm_source_val), \
}
+#define F_SLEW(f, s_f, s, div, m, n) \
+ { \
+ .freq_hz = (f), \
+ .src_freq = (s_f), \
+ .src_clk = &s.c, \
+ .m_val = (m), \
+ .n_val = ~((n)-(m)) * !!(n), \
+ .d_val = ~(n),\
+ .div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+ | BVAL(10, 8, s##_mm_source_val), \
+ }
+
DEFINE_EXT_CLK(mmsscc_xo, NULL);
DEFINE_EXT_CLK(mmsscc_gpll0, NULL);
DEFINE_EXT_CLK(mmsscc_gpll0_div, NULL);
+DEFINE_EXT_CLK(ext_dp_phy_pll_vco, NULL);
+DEFINE_EXT_CLK(ext_dp_phy_pll_link, NULL);
static DEFINE_VDD_REGULATORS(vdd_dig, VDD_DIG_NUM, 1, vdd_corner, NULL);
@@ -1091,6 +1107,80 @@ static struct rcg_clk dp_aux_clk_src = {
},
};
+static struct clk_freq_tbl ftbl_dp_pixel_clk_src[] = {
+ {
+ .div_src_val = BVAL(10, 8, ext_dp_phy_pll_vco_mm_source_val),
+ .src_clk = &ext_dp_phy_pll_vco.c,
+ },
+ F_END
+};
+
+static struct rcg_clk dp_pixel_clk_src = {
+ .cmd_rcgr_reg = MMSS_DP_PIXEL_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .current_freq = ftbl_dp_pixel_clk_src,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "dp_pixel_clk_src",
+ .parent = &ext_dp_phy_pll_vco.c,
+ .ops = &clk_ops_rcg_dp,
+ VDD_DIG_FMAX_MAP3(LOWER, 148380000, LOW, 296740000,
+ NOMINAL, 593470000),
+ CLK_INIT(dp_pixel_clk_src.c),
+ },
+};
+
+static struct clk_freq_tbl ftbl_dp_link_clk_src[] = {
+ F_SLEW( 162000000, 324000000, ext_dp_phy_pll_link, 2, 0, 0),
+ F_SLEW( 270000000, 540000000, ext_dp_phy_pll_link, 2, 0, 0),
+ F_SLEW( 540000000, 1080000000, ext_dp_phy_pll_link, 2, 0, 0),
+ F_END
+};
+
+static struct rcg_clk dp_link_clk_src = {
+ .cmd_rcgr_reg = MMSS_DP_LINK_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_dp_link_clk_src,
+ .current_freq = ftbl_dp_link_clk_src,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "dp_link_clk_src",
+ .ops = &clk_ops_rcg,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ VDD_DIG_FMAX_MAP3(LOWER, 162000000, LOW, 270000000,
+ NOMINAL, 540000000),
+ CLK_INIT(dp_link_clk_src.c),
+ },
+};
+
+/*
+ * Current understanding is that the DP PLL is going to be configured by using
+ * the set_rate ops for the dp_link_clk_src and dp_pixel_clk_src. When set_rate
+ * is called on this RCG, the rate call never makes it to the external DP
+ * clocks.
+ */
+static struct clk_freq_tbl ftbl_dp_crypto_clk_src[] = {
+ F_MM( 101250000, ext_dp_phy_pll_link, 1, 5, 16),
+ F_MM( 168750000, ext_dp_phy_pll_link, 1, 5, 16),
+ F_MM( 337500000, ext_dp_phy_pll_link, 1, 5, 16),
+ F_END
+};
+
+static struct rcg_clk dp_crypto_clk_src = {
+ .cmd_rcgr_reg = MMSS_DP_CRYPTO_CMD_RCGR,
+ .set_rate = set_rate_mnd,
+ .freq_tbl = ftbl_dp_crypto_clk_src,
+ .current_freq = ftbl_dp_crypto_clk_src,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "dp_crypto_clk_src",
+ .ops = &clk_ops_rcg_mnd,
+ VDD_DIG_FMAX_MAP3(LOWER, 101250000, LOW, 168750000,
+ NOMINAL, 337500000),
+ CLK_INIT(dp_crypto_clk_src.c),
+ },
+};
+
static struct branch_clk mmss_bimc_smmu_ahb_clk = {
.cbcr_reg = MMSS_BIMC_SMMU_AHB_CBCR,
.has_sibling = 1,
@@ -1936,6 +2026,56 @@ static struct branch_clk mmss_mdss_dp_aux_clk = {
},
};
+static struct branch_clk mmss_mdss_dp_pixel_clk = {
+ .cbcr_reg = MMSS_MDSS_DP_PIXEL_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "mmss_mdss_dp_pixel_clk",
+ .parent = &dp_pixel_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_mdss_dp_pixel_clk.c),
+ },
+};
+
+static struct branch_clk mmss_mdss_dp_link_clk = {
+ .cbcr_reg = MMSS_MDSS_DP_LINK_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "mmss_mdss_dp_link_clk",
+ .parent = &dp_link_clk_src.c,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_mdss_dp_link_clk.c),
+ },
+};
+
+/* Reset state of MMSS_MDSS_DP_LINK_INTF_DIV is 0x3 (div-4) */
+static struct branch_clk mmss_mdss_dp_link_intf_clk = {
+ .cbcr_reg = MMSS_MDSS_DP_LINK_INTF_CBCR,
+ .has_sibling = 1,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "mmss_mdss_dp_link_intf_clk",
+ .parent = &dp_link_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_mdss_dp_link_intf_clk.c),
+ },
+};
+
+static struct branch_clk mmss_mdss_dp_crypto_clk = {
+ .cbcr_reg = MMSS_MDSS_DP_CRYPTO_CBCR,
+ .has_sibling = 0,
+ .base = &virt_base,
+ .c = {
+ .dbg_name = "mmss_mdss_dp_crypto_clk",
+ .parent = &dp_crypto_clk_src.c,
+ .ops = &clk_ops_branch,
+ CLK_INIT(mmss_mdss_dp_crypto_clk.c),
+ },
+};
+
static struct branch_clk mmss_mdss_dp_gtc_clk = {
.cbcr_reg = MMSS_MDSS_DP_GTC_CBCR,
.has_sibling = 0,
@@ -2313,10 +2453,14 @@ static struct mux_clk mmss_debug_mux = {
{ &mmss_fd_core_clk.c, 0x0089 },
{ &mmss_fd_core_uar_clk.c, 0x008a },
{ &mmss_fd_ahb_clk.c, 0x008c },
- { &mmss_camss_cphy_csid0_clk.c, 0x008d},
- { &mmss_camss_cphy_csid1_clk.c, 0x008e},
- { &mmss_camss_cphy_csid2_clk.c, 0x008f},
- { &mmss_camss_cphy_csid3_clk.c, 0x0090},
+ { &mmss_camss_cphy_csid0_clk.c, 0x008d },
+ { &mmss_camss_cphy_csid1_clk.c, 0x008e },
+ { &mmss_camss_cphy_csid2_clk.c, 0x008f },
+ { &mmss_camss_cphy_csid3_clk.c, 0x0090 },
+ { &mmss_mdss_dp_link_clk.c, 0x0098 },
+ { &mmss_mdss_dp_link_intf_clk.c, 0x0099 },
+ { &mmss_mdss_dp_crypto_clk.c, 0x009a },
+ { &mmss_mdss_dp_pixel_clk.c, 0x009b },
{ &mmss_mdss_dp_aux_clk.c, 0x009c },
{ &mmss_mdss_dp_gtc_clk.c, 0x009d },
{ &mmss_mdss_byte0_intf_clk.c, 0x00ad },
@@ -2384,6 +2528,11 @@ static struct clk_lookup msm_clocks_mmss_cobalt[] = {
CLK_LIST(pclk1_clk_src),
CLK_LIST(ext_extpclk_clk_src),
CLK_LIST(extpclk_clk_src),
+ CLK_LIST(ext_dp_phy_pll_vco),
+ CLK_LIST(ext_dp_phy_pll_link),
+ CLK_LIST(dp_pixel_clk_src),
+ CLK_LIST(dp_link_clk_src),
+ CLK_LIST(dp_crypto_clk_src),
CLK_LIST(csi0phytimer_clk_src),
CLK_LIST(csi1phytimer_clk_src),
CLK_LIST(csi2phytimer_clk_src),
@@ -2463,6 +2612,10 @@ static struct clk_lookup msm_clocks_mmss_cobalt[] = {
CLK_LIST(mmss_mdss_byte0_intf_div_clk),
CLK_LIST(mmss_mdss_byte1_intf_clk),
CLK_LIST(mmss_mdss_dp_aux_clk),
+ CLK_LIST(mmss_mdss_dp_crypto_clk),
+ CLK_LIST(mmss_mdss_dp_pixel_clk),
+ CLK_LIST(mmss_mdss_dp_link_clk),
+ CLK_LIST(mmss_mdss_dp_link_intf_clk),
CLK_LIST(mmss_mdss_dp_gtc_clk),
CLK_LIST(mmss_mdss_esc0_clk),
CLK_LIST(mmss_mdss_esc1_clk),
@@ -2646,6 +2799,11 @@ int msm_mmsscc_cobalt_probe(struct platform_device *pdev)
ext_extpclk_clk_src.dev = &pdev->dev;
ext_extpclk_clk_src.clk_id = "extpclk_src";
+ ext_dp_phy_pll_link.dev = &pdev->dev;
+ ext_dp_phy_pll_link.clk_id = "dp_link_src";
+ ext_dp_phy_pll_vco.dev = &pdev->dev;
+ ext_dp_phy_pll_vco.clk_id = "dp_vco_div";
+
is_vq = of_device_is_compatible(pdev->dev.of_node,
"qcom,mmsscc-hamster");
if (is_vq)
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
index e6153553e48a..1751f49b798c 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-cobalt.c
@@ -509,7 +509,7 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c)
16);
/* OUTDIV_1:0 field is (log(outdiv, 2)) */
- outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_OUTDIV);
+ outdiv = MDSS_PLL_REG_R(pll->pll_base, PLL_PLL_OUTDIV_RATE);
outdiv &= 0x3;
outdiv = 1 << outdiv;
@@ -521,12 +521,12 @@ static unsigned long dsi_pll_get_vco_rate(struct clk *c)
multiplier = 1 << 18;
pll_freq = dec * (ref_clk * 2);
tmp64 = (ref_clk * 2 * frac);
- pll_freq += do_div(tmp64, multiplier);
+ pll_freq += div_u64(tmp64, multiplier);
- vco_rate = do_div(pll_freq, outdiv);
+ vco_rate = div_u64(pll_freq, outdiv);
- pr_debug("dec=0x%x\n, frac=0x%x, outdiv=%d, vco=%lu\n",
- dec, frac, outdiv, (unsigned long)vco_rate);
+ pr_debug("dec=0x%x, frac=0x%x, outdiv=%d, vco=%llu\n",
+ dec, frac, outdiv, vco_rate);
(void)mdss_pll_resource_enable(pll, false);
diff --git a/drivers/gpu/msm/kgsl_pool.c b/drivers/gpu/msm/kgsl_pool.c
index 48b7b0872425..7fb3b37ac191 100644
--- a/drivers/gpu/msm/kgsl_pool.c
+++ b/drivers/gpu/msm/kgsl_pool.c
@@ -298,17 +298,18 @@ int kgsl_pool_alloc_page(int *page_size, struct page **pages,
return -EINVAL;
pool = _kgsl_get_pool_from_order(order);
- pool_idx = kgsl_pool_idx_lookup(order);
+ if (pool == NULL)
+ return -EINVAL;
- if (pool != NULL)
- page = _kgsl_pool_get_page(pool);
+ pool_idx = kgsl_pool_idx_lookup(order);
+ page = _kgsl_pool_get_page(pool);
/* Allocate a new page if not allocated from pool */
if (page == NULL) {
gfp_t gfp_mask = kgsl_gfp_mask(order);
/* Only allocate non-reserved memory for certain pools */
- if (!pool->allocation_allowed) {
+ if (!pool->allocation_allowed && pool_idx > 0) {
*page_size = PAGE_SIZE <<
kgsl_pools[pool_idx-1].pool_order;
*align = ilog2(*page_size);
diff --git a/drivers/iommu/io-pgtable-fast.c b/drivers/iommu/io-pgtable-fast.c
index 44307f67fd22..9a25ebfdc778 100644
--- a/drivers/iommu/io-pgtable-fast.c
+++ b/drivers/iommu/io-pgtable-fast.c
@@ -420,6 +420,9 @@ av8l_fast_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
struct av8l_fast_io_pgtable *data =
av8l_fast_alloc_pgtable_data(cfg);
+ if (!data)
+ return NULL;
+
/* restrict according to the fast map requirements */
cfg->ias = 32;
cfg->pgsize_bitmap = SZ_4K;
diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c
index a97c082d18d8..c78178c0e1a1 100644
--- a/drivers/iommu/iommu-debug.c
+++ b/drivers/iommu/iommu-debug.c
@@ -1379,7 +1379,7 @@ static int __apply_to_new_mapping(struct seq_file *s,
struct dma_iommu_mapping *mapping;
struct iommu_debug_device *ddev = s->private;
struct device *dev = ddev->dev;
- int ret, fast = 1;
+ int ret = -EINVAL, fast = 1;
phys_addr_t pt_phys;
mapping = arm_iommu_create_mapping(&platform_bus_type, 0, SZ_1G * 4ULL);
@@ -1688,7 +1688,7 @@ static const struct file_operations iommu_debug_atos_fops = {
static ssize_t iommu_debug_map_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *offset)
{
- ssize_t retval;
+ ssize_t retval = -EINVAL;
int ret;
char *comma1, *comma2, *comma3;
char buf[100];
diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 6942a8a74ea9..786ffa822851 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -16,16 +16,20 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/leds-qpnp-flash-v2.h>
#define FLASH_LED_REG_SAFETY_TMR(base) (base + 0x40)
#define FLASH_LED_REG_TGR_CURRENT(base) (base + 0x43)
#define FLASH_LED_REG_MOD_CTRL(base) (base + 0x46)
#define FLASH_LED_REG_IRES(base) (base + 0x47)
+#define FLASH_LED_REG_STROBE_CFG(base) (base + 0x48)
#define FLASH_LED_REG_STROBE_CTRL(base) (base + 0x49)
-#define FLASH_LED_REG_CHANNEL_CTRL(base) (base + 0x4C)
+#define FLASH_LED_EN_LED_CTRL(base) (base + 0x4C)
#define FLASH_LED_REG_HDRM_PRGM(base) (base + 0x4D)
#define FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(base) (base + 0x50)
#define FLASH_LED_REG_ISC_DELAY(base) (base + 0x52)
@@ -33,10 +37,11 @@
#define FLASH_LED_HDRM_MODE_PRGM_MASK GENMASK(7, 0)
#define FLASH_LED_HDRM_VOL_MASK GENMASK(7, 4)
#define FLASH_LED_CURRENT_MASK GENMASK(6, 0)
-#define FLASH_LED_STROBE_CTRL_MASK GENMASK(2, 0)
+#define FLASH_LED_ENABLE_MASK GENMASK(2, 0)
#define FLASH_LED_SAFETY_TMR_MASK GENMASK(7, 0)
#define FLASH_LED_ISC_DELAY_MASK GENMASK(1, 0)
#define FLASH_LED_MOD_CTRL_MASK BIT(7)
+#define FLASH_LED_HW_SW_STROBE_SEL_MASK BIT(2)
#define FLASH_LED_HEADROOM_AUTO_MODE_ENABLED true
#define FLASH_LED_ISC_DELAY_SHIFT 6
@@ -54,7 +59,11 @@
#define FLASH_LED_HDRM_VOL_HI_LO_WIN_DEFAULT_MV 0x04
#define FLASH_LED_HDRM_VOL_BASE_MV 125
#define FLASH_LED_HDRM_VOL_STEP_MV 25
-#define FLASH_LED_STROBE_ENABLE BIT(0)
+#define FLASH_LED_STROBE_CFG_DEFAULT 0x00
+#define FLASH_LED_HW_STROBE_OPTION_1 0x00
+#define FLASH_LED_HW_STROBE_OPTION_2 0x01
+#define FLASH_LED_HW_STROBE_OPTION_3 0x02
+#define FLASH_LED_ENABLE BIT(0)
#define FLASH_LED_MOD_ENABLE BIT(7)
#define FLASH_LED_DISABLE 0x00
#define FLASH_LED_SAFETY_TMR_DISABLED 0x13
@@ -65,11 +74,59 @@ enum flash_led_type {
FLASH_LED_TYPE_TORCH,
};
+enum {
+ LED1 = 0,
+ LED2,
+ LED3,
+};
+
+/*
+ * Configurations for each individual LED
+ */
+struct flash_node_data {
+ struct platform_device *pdev;
+ struct led_classdev cdev;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *gpio_state_active;
+ struct pinctrl_state *gpio_state_suspend;
+ struct pinctrl_state *hw_strobe_state_active;
+ struct pinctrl_state *hw_strobe_state_suspend;
+ int hw_strobe_gpio;
+ int ires_ua;
+ int max_current;
+ int current_ma;
+ u8 duration;
+ u8 id;
+ u8 type;
+ u8 ires;
+ u8 hdrm_val;
+ u8 current_reg_val;
+ u8 trigger;
+ bool led_on;
+};
+
+struct flash_regulator_data {
+ struct regulator *vreg;
+ const char *reg_name;
+ u32 max_volt_uv;
+};
+
+struct flash_switch_data {
+ struct platform_device *pdev;
+ struct led_classdev cdev;
+ struct flash_regulator_data *reg_data;
+ int led_mask;
+ int num_regulators;
+ bool regulator_on;
+ bool enabled;
+};
+
/*
* Flash LED configuration read from device tree
*/
struct flash_led_platform_data {
u8 isc_delay_us;
+ u8 hw_strobe_option;
bool hdrm_auto_mode_en;
};
@@ -83,8 +140,9 @@ struct qpnp_flash_led {
struct flash_node_data *fnode;
struct flash_switch_data *snode;
spinlock_t lock;
- int num_led_nodes;
- int num_avail_leds;
+ int num_fnodes;
+ int num_snodes;
+ int enable;
u16 base;
};
@@ -95,12 +153,13 @@ qpnp_flash_led_masked_write(struct qpnp_flash_led *led, u16 addr, u8 mask,
int rc;
rc = regmap_update_bits(led->regmap, addr, mask, val);
- if (rc)
+ if (rc < 0)
dev_err(&led->pdev->dev,
"Unable to update bits from 0x%02X, rc = %d\n",
addr, rc);
-
- dev_dbg(&led->pdev->dev, "Write 0x%02X to addr 0x%02X\n", val, addr);
+ else
+ dev_dbg(&led->pdev->dev, "Wrote 0x%02X to addr 0x%02X\n",
+ val, addr);
return rc;
}
@@ -116,13 +175,13 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
int rc, i, addr_offset;
u8 val = 0;
- for (i = 0; i < led->num_avail_leds; i++) {
+ for (i = 0; i < led->num_fnodes; i++) {
addr_offset = led->fnode[i].id;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_HDRM_PRGM(led->base + addr_offset),
FLASH_LED_HDRM_MODE_PRGM_MASK,
led->fnode[i].hdrm_val);
- if (rc)
+ if (rc < 0)
return rc;
val |= 0x1 << led->fnode[i].id;
@@ -131,18 +190,92 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_HDRM_AUTO_MODE_CTRL(led->base),
FLASH_LED_HDRM_MODE_PRGM_MASK, val);
- if (rc)
+ if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_ISC_DELAY(led->base),
FLASH_LED_ISC_DELAY_MASK, led->pdata->isc_delay_us);
- if (rc)
+ if (rc < 0)
return rc;
return 0;
}
+static int qpnp_flash_led_hw_strobe_enable(struct flash_node_data *fnode,
+ int hw_strobe_option, bool on)
+{
+ int rc = 0;
+
+ /*
+ * If the LED controlled by this fnode is not GPIO controlled
+ * for the given strobe_option, return.
+ */
+ if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_1)
+ return 0;
+ else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_2
+ && fnode->id != LED3)
+ return 0;
+ else if (hw_strobe_option == FLASH_LED_HW_STROBE_OPTION_3
+ && fnode->id == LED1)
+ return 0;
+
+ if (gpio_is_valid(fnode->hw_strobe_gpio)) {
+ gpio_set_value(fnode->hw_strobe_gpio, on ? 1 : 0);
+ } else if (fnode->hw_strobe_state_active &&
+ fnode->hw_strobe_state_suspend) {
+ rc = pinctrl_select_state(fnode->pinctrl,
+ on ? fnode->hw_strobe_state_active :
+ fnode->hw_strobe_state_suspend);
+ if (rc < 0) {
+ dev_err(&fnode->pdev->dev,
+ "failed to change hw strobe pin state\n");
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_regulator_enable(struct qpnp_flash_led *led,
+ struct flash_switch_data *snode, bool on)
+{
+ int i, rc = 0;
+
+ if (snode->regulator_on == on)
+ return 0;
+
+ if (on == false) {
+ i = snode->num_regulators;
+ goto out;
+ }
+
+ for (i = 0; i < snode->num_regulators; i++) {
+ rc = regulator_enable(snode->reg_data[i].vreg);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "regulator enable failed, rc=%d\n", rc);
+ goto out;
+ }
+ }
+ snode->regulator_on = true;
+
+ return rc;
+
+out:
+ while (i--)
+ regulator_disable(snode->reg_data[i].vreg);
+
+ snode->regulator_on = false;
+ return rc;
+}
+
+static int qpnp_flash_led_get_max_avail_current(struct flash_switch_data *snode,
+ struct qpnp_flash_led *led)
+{
+ return 3750;
+}
+
static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
{
int prgm_current_ma = value;
@@ -159,110 +292,204 @@ static void qpnp_flash_led_node_set(struct flash_node_data *fnode, int value)
fnode->led_on = prgm_current_ma != 0;
}
+static int qpnp_flash_led_switch_disable(struct flash_switch_data *snode)
+{
+ struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+ int i, rc, addr_offset;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_EN_LED_CTRL(led->base),
+ snode->led_mask, FLASH_LED_DISABLE);
+ if (rc < 0)
+ return rc;
+
+ led->enable--;
+ if (led->enable == 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MOD_CTRL(led->base),
+ FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE);
+ if (rc < 0)
+ return rc;
+ }
+
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (!led->fnode[i].led_on ||
+ !(snode->led_mask & BIT(led->fnode[i].id)))
+ continue;
+
+ addr_offset = led->fnode[i].id;
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
+ FLASH_LED_CURRENT_MASK, 0);
+ if (rc < 0)
+ return rc;
+
+ led->fnode[i].led_on = false;
+
+ if (led->fnode[i].pinctrl) {
+ rc = pinctrl_select_state(led->fnode[i].pinctrl,
+ led->fnode[i].gpio_state_suspend);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "failed to disable GPIO, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) {
+ rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
+ led->pdata->hw_strobe_option, false);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Unable to disable hw strobe, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+ }
+
+ qpnp_flash_led_regulator_enable(led, snode, false);
+ snode->enabled = false;
+ return 0;
+}
+
static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
{
struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
int rc, i, addr_offset;
u8 val;
- if (!on)
- goto leds_turn_off;
+ if (snode->enabled == on) {
+ dev_warn(&led->pdev->dev, "Switch node is already %s!\n",
+ on ? "enabled" : "disabled");
+ return 0;
+ }
+
+ if (!on) {
+ rc = qpnp_flash_led_switch_disable(snode);
+ return rc;
+ }
+
+ rc = qpnp_flash_led_regulator_enable(led, snode, true);
+ if (rc < 0)
+ return rc;
+ /* Iterate over all leds for this switch node */
val = 0;
- for (i = 0; i < led->num_led_nodes; i++)
- val |= led->fnode[i].ires << (led->fnode[i].id * 2);
+ for (i = 0; i < led->num_fnodes; i++)
+ if (snode->led_mask & BIT(led->fnode[i].id))
+ val |= led->fnode[i].ires << (led->fnode[i].id * 2);
+
rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_IRES(led->base),
FLASH_LED_CURRENT_MASK, val);
- if (rc)
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_STROBE_CFG(led->base),
+ FLASH_LED_ENABLE_MASK,
+ led->pdata->hw_strobe_option);
+ if (rc < 0)
return rc;
val = 0;
- for (i = 0; i < led->num_avail_leds; i++) {
- if (!led->fnode[i].led_on)
+ for (i = 0; i < led->num_fnodes; i++) {
+ if (!led->fnode[i].led_on ||
+ !(snode->led_mask & BIT(led->fnode[i].id)))
continue;
addr_offset = led->fnode[i].id;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_STROBE_CTRL(led->base + addr_offset),
- FLASH_LED_STROBE_CTRL_MASK, FLASH_LED_STROBE_ENABLE);
- if (rc)
+ FLASH_LED_ENABLE_MASK, led->fnode[i].trigger);
+ if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
FLASH_LED_CURRENT_MASK, led->fnode[i].current_reg_val);
- if (rc)
+ if (rc < 0)
return rc;
rc = qpnp_flash_led_masked_write(led,
FLASH_LED_REG_SAFETY_TMR(led->base + addr_offset),
FLASH_LED_SAFETY_TMR_MASK, led->fnode[i].duration);
- if (rc)
+ if (rc < 0)
return rc;
- val |= FLASH_LED_STROBE_ENABLE << led->fnode[i].id;
+ val |= FLASH_LED_ENABLE << led->fnode[i].id;
if (led->fnode[i].pinctrl) {
rc = pinctrl_select_state(led->fnode[i].pinctrl,
led->fnode[i].gpio_state_active);
- if (rc) {
+ if (rc < 0) {
dev_err(&led->pdev->dev,
"failed to enable GPIO\n");
return rc;
}
}
+
+ if (led->fnode[i].trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) {
+ rc = qpnp_flash_led_hw_strobe_enable(&led->fnode[i],
+ led->pdata->hw_strobe_option, true);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Unable to enable hw strobe\n");
+ return rc;
+ }
+ }
}
- rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_MOD_CTRL(led->base),
+ if (led->enable == 0) {
+ rc = qpnp_flash_led_masked_write(led,
+ FLASH_LED_REG_MOD_CTRL(led->base),
FLASH_LED_MOD_CTRL_MASK, FLASH_LED_MOD_ENABLE);
- if (rc)
- return rc;
+ if (rc < 0)
+ return rc;
+ }
+ led->enable++;
rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_CHANNEL_CTRL(led->base),
- FLASH_LED_STROBE_CTRL_MASK, val);
- if (rc)
+ FLASH_LED_EN_LED_CTRL(led->base),
+ snode->led_mask, val);
+ if (rc < 0)
return rc;
+ snode->enabled = true;
return 0;
+}
-leds_turn_off:
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_CHANNEL_CTRL(led->base),
- FLASH_LED_STROBE_CTRL_MASK, FLASH_LED_DISABLE);
- if (rc)
- return rc;
-
- rc = qpnp_flash_led_masked_write(led, FLASH_LED_REG_MOD_CTRL(led->base),
- FLASH_LED_MOD_CTRL_MASK, FLASH_LED_DISABLE);
- if (rc)
- return rc;
+int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options)
+{
+ struct flash_switch_data *snode =
+ container_of(led_cdev, struct flash_switch_data, cdev);
+ struct qpnp_flash_led *led = dev_get_drvdata(&snode->pdev->dev);
+ int rc, val = 0;
- for (i = 0; i < led->num_led_nodes; i++) {
- if (!led->fnode[i].led_on)
- continue;
+ if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) {
+ dev_err(&led->pdev->dev, "Invalid options %d\n", options);
+ return -EINVAL;
+ }
- addr_offset = led->fnode[i].id;
- rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_TGR_CURRENT(led->base + addr_offset),
- FLASH_LED_CURRENT_MASK, 0);
- if (rc)
+ if (options & ENABLE_REGULATOR) {
+ rc = qpnp_flash_led_regulator_enable(led, snode, true);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "enable regulator failed, rc=%d\n", rc);
return rc;
+ }
+ }
- led->fnode[i].led_on = false;
-
- if (led->fnode[i].pinctrl) {
- rc = pinctrl_select_state(led->fnode[i].pinctrl,
- led->fnode[i].gpio_state_suspend);
- if (rc) {
- dev_err(&led->pdev->dev,
- "failed to disable GPIO\n");
- return rc;
- }
+ if (options & QUERY_MAX_CURRENT) {
+ val = qpnp_flash_led_get_max_avail_current(snode, led);
+ if (val < 0) {
+ dev_err(&led->pdev->dev,
+ "query max current failed, rc=%d\n", val);
+ return val;
}
}
- return 0;
+ return val;
}
static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
@@ -273,7 +500,7 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
struct qpnp_flash_led *led = dev_get_drvdata(&fnode->pdev->dev);
int rc;
- if (!strcmp(led_cdev->name, "led:switch")) {
+ if (!strncmp(led_cdev->name, "led:switch", strlen("led:switch"))) {
snode = container_of(led_cdev, struct flash_switch_data, cdev);
led = dev_get_drvdata(&snode->pdev->dev);
} else {
@@ -282,45 +509,141 @@ static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
}
spin_lock(&led->lock);
- if (!fnode) {
+ if (snode) {
rc = qpnp_flash_led_switch_set(snode, value > 0);
- if (rc) {
+ if (rc < 0)
dev_err(&led->pdev->dev,
"Failed to set flash LED switch\n");
- goto exit;
- }
- } else {
+ } else if (fnode) {
qpnp_flash_led_node_set(fnode, value);
}
-exit:
spin_unlock(&led->lock);
}
+static int qpnp_flash_led_regulator_setup(struct qpnp_flash_led *led,
+ struct flash_switch_data *snode, bool on)
+{
+ int i, rc = 0;
+
+ if (on == false) {
+ i = snode->num_regulators;
+ goto out;
+ }
+
+ for (i = 0; i < snode->num_regulators; i++) {
+ snode->reg_data[i].vreg = regulator_get(snode->cdev.dev,
+ snode->reg_data[i].reg_name);
+ if (IS_ERR(snode->reg_data[i].vreg)) {
+ rc = PTR_ERR(snode->reg_data[i].vreg);
+ dev_err(&led->pdev->dev,
+ "Failed to get regulator, rc=%d\n", rc);
+ goto out;
+ }
+
+ if (regulator_count_voltages(snode->reg_data[i].vreg) > 0) {
+ rc = regulator_set_voltage(snode->reg_data[i].vreg,
+ snode->reg_data[i].max_volt_uv,
+ snode->reg_data[i].max_volt_uv);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "regulator set voltage failed, rc=%d\n",
+ rc);
+ regulator_put(snode->reg_data[i].vreg);
+ goto out;
+ }
+ }
+ }
+
+ return rc;
+
+out:
+ while (i--) {
+ if (regulator_count_voltages(snode->reg_data[i].vreg) > 0)
+ regulator_set_voltage(snode->reg_data[i].vreg, 0,
+ snode->reg_data[i].max_volt_uv);
+
+ regulator_put(snode->reg_data[i].vreg);
+ }
+
+ return rc;
+}
+
+static int qpnp_flash_led_regulator_parse_dt(struct qpnp_flash_led *led,
+ struct flash_switch_data *snode,
+ struct device_node *node) {
+
+ int i = 0, rc = 0, num_regs = 0;
+ struct device_node *temp = NULL;
+ const char *temp_string;
+ u32 val;
+
+ while ((temp = of_get_next_available_child(node, temp))) {
+ if (of_find_property(temp, "regulator-name", NULL))
+ num_regs++;
+ }
+ snode->num_regulators = num_regs;
+
+ if (snode->num_regulators == 0)
+ return 0;
+
+ snode->reg_data = devm_kcalloc(&led->pdev->dev, snode->num_regulators,
+ sizeof(*snode->reg_data),
+ GFP_KERNEL);
+ if (!snode->reg_data)
+ return -ENOMEM;
+
+ for_each_available_child_of_node(node, temp) {
+ rc = of_property_read_string(temp, "regulator-name",
+ &temp_string);
+ if (!rc)
+ snode->reg_data[i].reg_name = temp_string;
+ else {
+ dev_err(&led->pdev->dev,
+ "Unable to read regulator name, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(temp, "max-voltage-uv", &val);
+ if (!rc) {
+ snode->reg_data[i].max_volt_uv = val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev,
+ "Unable to read max voltage, rc=%d\n", rc);
+ return rc;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
struct flash_node_data *fnode, struct device_node *node)
{
const char *temp_string;
int rc;
u32 val;
+ bool strobe_sel = 0, edge_trigger = 0, active_high = 0;
fnode->pdev = led->pdev;
fnode->cdev.brightness_set = qpnp_flash_led_brightness_set;
fnode->cdev.brightness_get = qpnp_flash_led_brightness_get;
rc = of_property_read_string(node, "qcom,led-name", &fnode->cdev.name);
- if (rc) {
+ if (rc < 0) {
dev_err(&led->pdev->dev, "Unable to read flash LED names\n");
return rc;
}
rc = of_property_read_string(node, "label", &temp_string);
if (!rc) {
- if (!strcmp(temp_string, "flash"))
+ if (!strcmp(temp_string, "flash")) {
fnode->type = FLASH_LED_TYPE_FLASH;
- else if (!strcmp(temp_string, "torch"))
+ } else if (!strcmp(temp_string, "torch")) {
fnode->type = FLASH_LED_TYPE_TORCH;
- else {
+ } else {
dev_err(&led->pdev->dev, "Wrong flash LED type\n");
return rc;
}
@@ -339,7 +662,7 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
rc = of_property_read_string(node, "qcom,default-led-trigger",
&fnode->cdev.default_trigger);
- if (rc) {
+ if (rc < 0) {
dev_err(&led->pdev->dev, "Unable to read trigger name\n");
return rc;
}
@@ -429,17 +752,62 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
return rc;
}
+ strobe_sel = of_property_read_bool(node, "qcom,hw-strobe-sel");
+ if (strobe_sel) {
+ edge_trigger = of_property_read_bool(node,
+ "qcom,hw-strobe-edge-trigger");
+ active_high = !of_property_read_bool(node,
+ "qcom,hw-strobe-active-low");
+ }
+ fnode->trigger = (strobe_sel << 2) | (edge_trigger << 1) | active_high;
+
+ if (fnode->trigger & FLASH_LED_HW_SW_STROBE_SEL_MASK) {
+ if (of_find_property(node, "qcom,hw-strobe-gpio", NULL)) {
+ fnode->hw_strobe_gpio = of_get_named_gpio(node,
+ "qcom,hw-strobe-gpio", 0);
+ if (fnode->hw_strobe_gpio < 0) {
+ dev_err(&led->pdev->dev,
+ "Invalid gpio specified\n");
+ return fnode->hw_strobe_gpio;
+ }
+ gpio_direction_output(fnode->hw_strobe_gpio, 0);
+ } else {
+ fnode->hw_strobe_gpio = -1;
+ fnode->hw_strobe_state_active =
+ pinctrl_lookup_state(fnode->pinctrl,
+ "strobe_enable");
+ if (IS_ERR_OR_NULL(fnode->hw_strobe_state_active)) {
+ dev_err(&led->pdev->dev,
+ "No active pin for hardware strobe, rc=%ld\n",
+ PTR_ERR(fnode->hw_strobe_state_active));
+ fnode->hw_strobe_state_active = NULL;
+ }
+
+ fnode->hw_strobe_state_suspend =
+ pinctrl_lookup_state(fnode->pinctrl,
+ "strobe_disable");
+ if (IS_ERR_OR_NULL(fnode->hw_strobe_state_suspend)) {
+ dev_err(&led->pdev->dev,
+ "No suspend pin for hardware strobe, rc=%ld\n",
+ PTR_ERR(fnode->hw_strobe_state_suspend)
+ );
+ fnode->hw_strobe_state_suspend = NULL;
+ }
+ }
+ }
+
rc = led_classdev_register(&led->pdev->dev, &fnode->cdev);
- if (rc) {
+ if (rc < 0) {
dev_err(&led->pdev->dev, "Unable to register led node %d\n",
fnode->id);
return rc;
}
+
fnode->cdev.dev->of_node = node;
fnode->pinctrl = devm_pinctrl_get(fnode->cdev.dev);
if (IS_ERR_OR_NULL(fnode->pinctrl)) {
- dev_err(&led->pdev->dev, "No pinctrl defined\n");
+ dev_warn(&led->pdev->dev, "No pinctrl defined\n");
fnode->pinctrl = NULL;
} else {
fnode->gpio_state_active =
@@ -467,34 +835,64 @@ static int qpnp_flash_led_parse_each_led_dt(struct qpnp_flash_led *led,
}
static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
+ struct flash_switch_data *snode,
struct device_node *node)
{
- int rc;
+ int rc = 0;
- rc = of_property_read_string(node, "qcom,led-name",
- &led->snode->cdev.name);
- if (rc) {
- dev_err(&led->pdev->dev, "Failed to read switch node name\n");
+ rc = of_property_read_string(node, "qcom,led-name", &snode->cdev.name);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Failed to read switch node name, rc=%d\n", rc);
return rc;
}
rc = of_property_read_string(node, "qcom,default-led-trigger",
- &led->snode->cdev.default_trigger);
- if (rc) {
- dev_err(&led->pdev->dev, "Unable to read trigger name\n");
+ &snode->cdev.default_trigger);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Unable to read trigger name, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = of_property_read_u32(node, "qcom,led-mask", &snode->led_mask);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev, "Unable to read led mask rc=%d\n", rc);
return rc;
}
- led->snode->pdev = led->pdev;
- led->snode->cdev.brightness_set = qpnp_flash_led_brightness_set;
- led->snode->cdev.brightness_get = qpnp_flash_led_brightness_get;
- rc = led_classdev_register(&led->pdev->dev, &led->snode->cdev);
- if (rc) {
+ if (snode->led_mask < 1 || snode->led_mask > 7) {
+ dev_err(&led->pdev->dev, "Invalid value for led-mask\n");
+ return -EINVAL;
+ }
+
+ rc = qpnp_flash_led_regulator_parse_dt(led, snode, node);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Unable to parse regulator data, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (snode->num_regulators) {
+ rc = qpnp_flash_led_regulator_setup(led, snode, true);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Unable to setup regulator, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ snode->pdev = led->pdev;
+ snode->cdev.brightness_set = qpnp_flash_led_brightness_set;
+ snode->cdev.brightness_get = qpnp_flash_led_brightness_get;
+ rc = led_classdev_register(&led->pdev->dev, &snode->cdev);
+ if (rc < 0) {
dev_err(&led->pdev->dev,
"Unable to register led switch node\n");
return rc;
}
+ snode->cdev.dev->of_node = node;
return 0;
}
@@ -517,6 +915,14 @@ static int qpnp_flash_led_parse_common_dt(struct qpnp_flash_led *led,
return rc;
}
+ rc = of_property_read_u32(node, "qcom,hw-strobe-option", &val);
+ if (!rc) {
+ led->pdata->hw_strobe_option = (u8)val;
+ } else if (rc != -EINVAL) {
+ dev_err(&led->pdev->dev, "Unable to parse hw strobe option\n");
+ return rc;
+ }
+
return 0;
}
@@ -524,6 +930,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
{
struct qpnp_flash_led *led;
struct device_node *node, *temp;
+ const char *temp_string;
unsigned int base;
int rc, i = 0;
@@ -534,7 +941,7 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
}
rc = of_property_read_u32(node, "reg", &base);
- if (rc) {
+ if (rc < 0) {
dev_err(&pdev->dev, "Couldn't find reg in node %s, rc = %d\n",
node->full_name, rc);
return rc;
@@ -559,56 +966,77 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
return -ENOMEM;
rc = qpnp_flash_led_parse_common_dt(led, node);
- if (rc) {
+ if (rc < 0) {
dev_err(&pdev->dev,
"Failed to parse common flash LED device tree\n");
return rc;
}
- for_each_child_of_node(node, temp)
- led->num_led_nodes++;
- if (!led->num_led_nodes) {
+ for_each_available_child_of_node(node, temp) {
+ rc = of_property_read_string(temp, "label", &temp_string);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Failed to parse label, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (!strcmp("switch", temp_string)) {
+ led->num_snodes++;
+ } else if (!strcmp("flash", temp_string) ||
+ !strcmp("torch", temp_string)) {
+ led->num_fnodes++;
+ } else {
+ dev_err(&pdev->dev,
+ "Invalid label for led node\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!led->num_fnodes) {
dev_err(&pdev->dev, "No LED nodes defined\n");
return -ECHILD;
}
- led->fnode = devm_kzalloc(&pdev->dev,
- sizeof(struct flash_node_data) * (--led->num_led_nodes),
- GFP_KERNEL);
+ led->fnode = devm_kcalloc(&pdev->dev, led->num_fnodes,
+ sizeof(*led->fnode),
+ GFP_KERNEL);
if (!led->fnode)
return -ENOMEM;
+ led->snode = devm_kcalloc(&pdev->dev, led->num_snodes,
+ sizeof(*led->snode),
+ GFP_KERNEL);
+ if (!led->snode)
+ return -ENOMEM;
+
temp = NULL;
- for (i = 0; i < led->num_led_nodes; i++) {
- temp = of_get_next_child(node, temp);
+ for (i = 0; i < led->num_fnodes; i++) {
+ temp = of_get_next_available_child(node, temp);
rc = qpnp_flash_led_parse_each_led_dt(led,
&led->fnode[i], temp);
- if (rc) {
+ if (rc < 0) {
dev_err(&pdev->dev,
- "Unable to parse flash node %d\n", i);
+ "Unable to parse flash node %d rc=%d\n", i, rc);
goto error_led_register;
}
}
- led->num_avail_leds = i;
- led->snode = devm_kzalloc(&pdev->dev,
- sizeof(struct flash_switch_data), GFP_KERNEL);
- if (!led->snode) {
- rc = -ENOMEM;
- goto error_led_register;
- }
-
- temp = of_get_next_child(node, temp);
- rc = qpnp_flash_led_parse_and_register_switch(led, temp);
- if (rc) {
- dev_err(&pdev->dev,
- "Unable to parse and register switch node\n");
- goto error_led_register;
+ for (i = 0; i < led->num_snodes; i++) {
+ temp = of_get_next_available_child(node, temp);
+ rc = qpnp_flash_led_parse_and_register_switch(led,
+ &led->snode[i], temp);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Unable to parse and register switch node, rc=%d\n",
+ rc);
+ goto error_switch_register;
+ }
}
rc = qpnp_flash_led_init_settings(led);
- if (rc) {
- dev_err(&pdev->dev, "Failed to initialize flash LED\n");
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Failed to initialize flash LED, rc=%d\n", rc);
goto error_switch_register;
}
@@ -619,7 +1047,9 @@ static int qpnp_flash_led_probe(struct platform_device *pdev)
return 0;
error_switch_register:
- led_classdev_unregister(&led->snode->cdev);
+ while (i > 0)
+ led_classdev_unregister(&led->snode[--i].cdev);
+ i = led->num_fnodes;
error_led_register:
while (i > 0)
led_classdev_unregister(&led->fnode[--i].cdev);
@@ -630,9 +1060,21 @@ error_led_register:
static int qpnp_flash_led_remove(struct platform_device *pdev)
{
struct qpnp_flash_led *led = dev_get_drvdata(&pdev->dev);
- int i = led->num_led_nodes;
+ int i;
+
+ for (i = 0; i < led->num_snodes; i++) {
+ if (led->snode[i].num_regulators) {
+ if (led->snode[i].regulator_on)
+ qpnp_flash_led_regulator_enable(led,
+ &led->snode[i], false);
+ qpnp_flash_led_regulator_setup(led,
+ &led->snode[i], false);
+ }
+ }
- led_classdev_unregister(&led->snode->cdev);
+ while (i > 0)
+ led_classdev_unregister(&led->snode[--i].cdev);
+ i = led->num_fnodes;
while (i > 0)
led_classdev_unregister(&led->fnode[--i].cdev);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index 95465fb24feb..763b6a575326 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -40,6 +40,7 @@
#define VFE40_8952_VERSION 0x10060000
#define VFE40_8976_VERSION 0x10050000
#define VFE40_8937_VERSION 0x10080000
+#define VFE40_8917_VERSION 0x10080001
#define VFE40_8953_VERSION 0x10090000
#define VFE32_8909_VERSION 0x30600
@@ -652,6 +653,7 @@ struct dual_vfe_resource {
struct msm_vfe_stats_shared_data *stats_data[MAX_VFE];
struct msm_vfe_axi_shared_data *axi_data[MAX_VFE];
uint32_t wm_reload_mask[MAX_VFE];
+ uint32_t epoch_sync_mask;
};
struct master_slave_resource_info {
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index d4f0453d72ff..a76ccc06c9e1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -326,6 +326,7 @@ static void msm_vfe40_init_hardware_reg(struct vfe_device *vfe_dev)
break;
case VFE40_8937_VERSION:
case VFE40_8953_VERSION:
+ case VFE40_8917_VERSION:
default:
ISP_DBG("%s: No special QOS\n", __func__);
}
@@ -1475,6 +1476,7 @@ static void msm_vfe40_axi_cfg_wm_reg(
wm_bit_shift = VFE40_WM_BIT_SHIFT;
} else if (vfe_dev->vfe_hw_version == VFE40_8976_VERSION ||
vfe_dev->vfe_hw_version == VFE40_8937_VERSION ||
+ vfe_dev->vfe_hw_version == VFE40_8917_VERSION ||
vfe_dev->vfe_hw_version == VFE40_8953_VERSION) {
burst_len = VFE40_BURST_LEN_8952_VERSION;
wm_bit_shift = VFE40_WM_BIT_SHIFT_8976_VERSION;
@@ -1986,6 +1988,7 @@ static void msm_vfe40_stats_cfg_ub(struct vfe_device *vfe_dev)
if (vfe_dev->vfe_hw_version == VFE40_8916_VERSION ||
vfe_dev->vfe_hw_version == VFE40_8939_VERSION ||
vfe_dev->vfe_hw_version == VFE40_8937_VERSION ||
+ vfe_dev->vfe_hw_version == VFE40_8917_VERSION ||
vfe_dev->vfe_hw_version == VFE40_8953_VERSION) {
stats_burst_len = VFE40_STATS_BURST_LEN_8916_VERSION;
ub_offset = VFE40_UB_SIZE_8916;
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index fbac6d81ded0..3dd55e02826d 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -540,6 +540,89 @@ static void msm_isp_cfg_framedrop_reg(struct vfe_device *vfe_dev,
}
/**
+ * msm_isp_check_epoch_status() - check the epock signal for framedrop
+ *
+ * @vfe_dev: The h/w on which the epoch signel is reveived
+ * @frame_src: The source of the epoch signal for this frame
+ *
+ * For dual vfe case and pixel stream, if both vfe's epoch signal is
+ * received, this function will return success.
+ * It will also return the vfe1 for further process
+ * For none dual VFE stream or none pixl source, this
+ * funciton will just return success.
+ *
+ * Returns 1 - epoch received is complete.
+ * 0 - epoch reveived is not complete.
+ */
+static int msm_isp_check_epoch_status(struct vfe_device **vfe_dev,
+ enum msm_vfe_input_src frame_src)
+{
+ struct vfe_device *vfe_dev_cur = *vfe_dev;
+ struct vfe_device *vfe_dev_other = NULL;
+ uint32_t vfe_id_other = 0;
+ uint32_t vfe_id_cur = 0;
+ uint32_t epoch_mask = 0;
+ unsigned long flags;
+ int completed = 0;
+
+ spin_lock_irqsave(
+ &vfe_dev_cur->common_data->common_dev_data_lock, flags);
+
+ if (vfe_dev_cur->is_split &&
+ frame_src == VFE_PIX_0) {
+ if (vfe_dev_cur->pdev->id == ISP_VFE0) {
+ vfe_id_cur = ISP_VFE0;
+ vfe_id_other = ISP_VFE1;
+ } else {
+ vfe_id_cur = ISP_VFE1;
+ vfe_id_other = ISP_VFE0;
+ }
+ vfe_dev_other = vfe_dev_cur->common_data->dual_vfe_res->
+ vfe_dev[vfe_id_other];
+
+ if (vfe_dev_cur->common_data->dual_vfe_res->
+ epoch_sync_mask & (1 << vfe_id_cur)) {
+ /* serious scheduling delay */
+ pr_err("Missing epoch: vfe %d, epoch mask 0x%x\n",
+ vfe_dev_cur->pdev->id,
+ vfe_dev_cur->common_data->dual_vfe_res->
+ epoch_sync_mask);
+ goto fatal;
+ }
+
+ vfe_dev_cur->common_data->dual_vfe_res->
+ epoch_sync_mask |= (1 << vfe_id_cur);
+
+ epoch_mask = (1 << vfe_id_cur) | (1 << vfe_id_other);
+ if ((vfe_dev_cur->common_data->dual_vfe_res->
+ epoch_sync_mask & epoch_mask) == epoch_mask) {
+
+ if (vfe_id_other == ISP_VFE0)
+ *vfe_dev = vfe_dev_cur;
+ else
+ *vfe_dev = vfe_dev_other;
+
+ vfe_dev_cur->common_data->dual_vfe_res->
+ epoch_sync_mask &= ~epoch_mask;
+ completed = 1;
+ }
+ } else
+ completed = 1;
+
+ spin_unlock_irqrestore(
+ &vfe_dev_cur->common_data->common_dev_data_lock, flags);
+
+ return completed;
+fatal:
+ spin_unlock_irqrestore(
+ &vfe_dev_cur->common_data->common_dev_data_lock, flags);
+ /* new error event code will be added later */
+ msm_isp_halt_send_error(vfe_dev_cur, ISP_EVENT_PING_PONG_MISMATCH);
+ return 0;
+}
+
+
+/**
* msm_isp_update_framedrop_reg() - Update frame period pattern on h/w
* @vfe_dev: The h/w on which the perion pattern is updated.
* @frame_src: Input source.
@@ -554,10 +637,15 @@ void msm_isp_update_framedrop_reg(struct vfe_device *vfe_dev,
enum msm_vfe_input_src frame_src)
{
int i;
- struct msm_vfe_axi_shared_data *axi_data = &vfe_dev->axi_data;
+ struct msm_vfe_axi_shared_data *axi_data = NULL;
struct msm_vfe_axi_stream *stream_info;
unsigned long flags;
+ if (msm_isp_check_epoch_status(&vfe_dev, frame_src) != 1)
+ return;
+
+ axi_data = &vfe_dev->axi_data;
+
for (i = 0; i < VFE_AXI_SRC_MAX; i++) {
if (SRC_TO_INTF(axi_data->stream_info[i].stream_src) !=
frame_src) {
@@ -1937,6 +2025,13 @@ static void msm_isp_get_camif_update_state_and_halt(
pix_stream_cnt++;
}
+ if (vfe_dev->axi_data.num_active_stream == stream_cfg_cmd->num_streams
+ && (stream_cfg_cmd->cmd == STOP_STREAM ||
+ stream_cfg_cmd->cmd == STOP_IMMEDIATELY))
+ *halt = 1;
+ else
+ *halt = 0;
+
if ((pix_stream_cnt) &&
(axi_data->src_info[VFE_PIX_0].input_mux != EXTERNAL_READ)) {
if (cur_pix_stream_cnt == 0 && pix_stream_cnt &&
@@ -1944,24 +2039,17 @@ static void msm_isp_get_camif_update_state_and_halt(
*camif_update = ENABLE_CAMIF;
else if (cur_pix_stream_cnt &&
(cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
- stream_cfg_cmd->cmd == STOP_STREAM)
- *camif_update = DISABLE_CAMIF;
- else if (cur_pix_stream_cnt &&
- (cur_pix_stream_cnt - pix_stream_cnt) == 0 &&
- stream_cfg_cmd->cmd == STOP_IMMEDIATELY)
- *camif_update = DISABLE_CAMIF_IMMEDIATELY;
+ (stream_cfg_cmd->cmd == STOP_STREAM ||
+ stream_cfg_cmd->cmd == STOP_IMMEDIATELY)) {
+ if (*halt)
+ *camif_update = DISABLE_CAMIF_IMMEDIATELY;
+ else
+ *camif_update = DISABLE_CAMIF;
+ }
else
*camif_update = NO_UPDATE;
} else
*camif_update = NO_UPDATE;
-
- if (vfe_dev->axi_data.num_active_stream == stream_cfg_cmd->num_streams
- && (stream_cfg_cmd->cmd == STOP_STREAM ||
- stream_cfg_cmd->cmd == STOP_IMMEDIATELY))
- *halt = 1;
- else
- *halt = 0;
-
}
static void msm_isp_update_camif_output_count(
@@ -2584,6 +2672,7 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev,
vfe_dev->hw_info->vfe_ops.core_ops.
update_camif_state(vfe_dev, camif_update);
vfe_dev->axi_data.camif_state = CAMIF_ENABLE;
+ vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0;
}
if (wait_for_complete) {
@@ -2645,34 +2734,20 @@ static int msm_isp_stop_axi_stream(struct vfe_device *vfe_dev,
wait_for_complete_for_this_stream = 0;
stream_info->state = STOP_PENDING;
- ISP_DBG("Stop axi Stream 0x%x\n", stream_info->stream_id);
- if (stream_info->stream_src == CAMIF_RAW ||
- stream_info->stream_src == IDEAL_RAW) {
- /* We dont get reg update IRQ for raw snapshot
- * so frame skip cant be ocnfigured
- */
- if ((camif_update != DISABLE_CAMIF_IMMEDIATELY) &&
- (!ext_read))
- wait_for_complete_for_this_stream = 1;
-
- } else if (stream_info->stream_type == BURST_STREAM &&
- stream_info->runtime_num_burst_capture == 0) {
- /* Configure AXI writemasters to stop immediately
- * since for burst case, write masters already skip
- * all frames.
- */
- if (stream_info->stream_src == RDI_INTF_0 ||
- stream_info->stream_src == RDI_INTF_1 ||
- stream_info->stream_src == RDI_INTF_2)
- wait_for_complete_for_this_stream = 1;
- } else {
- if ((camif_update != DISABLE_CAMIF_IMMEDIATELY) &&
- !halt && (!ext_read))
- wait_for_complete_for_this_stream = 1;
- }
- ISP_DBG("%s: vfe_dev %d camif_update %d halt %d wait %d\n",
- __func__, vfe_dev->pdev->id, camif_update, halt,
+
+ if (!halt && !ext_read &&
+ !(stream_info->stream_type == BURST_STREAM &&
+ stream_info->runtime_num_burst_capture == 0))
+ wait_for_complete_for_this_stream = 1;
+
+ ISP_DBG("%s: stream 0x%x, vfe %d camif %d halt %d wait %d\n",
+ __func__,
+ stream_info->stream_id,
+ vfe_dev->pdev->id,
+ camif_update,
+ halt,
wait_for_complete_for_this_stream);
+
intf = SRC_TO_INTF(stream_info->stream_src);
if (!wait_for_complete_for_this_stream ||
stream_info->state == INACTIVE ||
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index 460746089c53..5b12c1239bf4 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -1917,11 +1917,16 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
ISP_DBG("%s open_cnt %u\n", __func__, vfe_dev->vfe_open_cnt);
- if (vfe_dev->common_data == NULL) {
- pr_err("%s: Error in probe. No common_data\n", __func__);
+ if (vfe_dev->common_data == NULL ||
+ vfe_dev->common_data->dual_vfe_res == NULL) {
+ pr_err("%s: Error in probe. No common_data or dual vfe res\n",
+ __func__);
return -EINVAL;
}
+ if (vfe_dev->pdev->id == ISP_VFE0)
+ vfe_dev->common_data->dual_vfe_res->epoch_sync_mask = 0;
+
mutex_lock(&vfe_dev->realtime_mutex);
mutex_lock(&vfe_dev->core_mutex);
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index a7ac094f6c1e..140d33582c87 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -90,10 +90,42 @@ static const struct v4l2_fmtdesc fmtdesc[] = {
.pixelformat = SDE_PIX_FMT_BGRX_8888,
},
{
+ .description = "SDE/XBGR_8888",
+ .pixelformat = SDE_PIX_FMT_XBGR_8888,
+ },
+ {
.description = "RGBA_5551",
.pixelformat = SDE_PIX_FMT_RGBA_5551,
},
{
+ .description = "ARGB_1555",
+ .pixelformat = SDE_PIX_FMT_ARGB_1555,
+ },
+ {
+ .description = "ABGR_1555",
+ .pixelformat = SDE_PIX_FMT_ABGR_1555,
+ },
+ {
+ .description = "BGRA_5551",
+ .pixelformat = SDE_PIX_FMT_BGRA_5551,
+ },
+ {
+ .description = "BGRX_5551",
+ .pixelformat = SDE_PIX_FMT_BGRX_5551,
+ },
+ {
+ .description = "RGBX_5551",
+ .pixelformat = SDE_PIX_FMT_RGBX_5551,
+ },
+ {
+ .description = "XBGR_1555",
+ .pixelformat = SDE_PIX_FMT_XBGR_1555,
+ },
+ {
+ .description = "XRGB_1555",
+ .pixelformat = SDE_PIX_FMT_XRGB_1555,
+ },
+ {
.description = "ARGB_4444",
.pixelformat = SDE_PIX_FMT_ARGB_4444,
},
@@ -102,6 +134,30 @@ static const struct v4l2_fmtdesc fmtdesc[] = {
.pixelformat = SDE_PIX_FMT_RGBA_4444,
},
{
+ .description = "BGRA_4444",
+ .pixelformat = SDE_PIX_FMT_BGRA_4444,
+ },
+ {
+ .description = "ABGR_4444",
+ .pixelformat = SDE_PIX_FMT_ABGR_4444,
+ },
+ {
+ .description = "RGBX_4444",
+ .pixelformat = SDE_PIX_FMT_RGBX_4444,
+ },
+ {
+ .description = "XRGB_4444",
+ .pixelformat = SDE_PIX_FMT_XRGB_4444,
+ },
+ {
+ .description = "BGRX_4444",
+ .pixelformat = SDE_PIX_FMT_BGRX_4444,
+ },
+ {
+ .description = "XBGR_4444",
+ .pixelformat = SDE_PIX_FMT_XBGR_4444,
+ },
+ {
.description = "RGB_888",
.pixelformat = SDE_PIX_FMT_RGB_888,
},
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
index 8e5793362875..5318c9da1277 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_formats.c
@@ -318,6 +318,10 @@ static struct sde_mdp_format_params sde_mdp_format_map[] = {
SDE_PIX_FMT_BGRX_8888, SDE_MDP_FMT_LINEAR,
VALID_ROT_WB_ALL | VALID_MDP_WB_INTF_FORMAT,
0, C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, SDE_MDP_COMPRESS_NONE),
+ FMT_RGB_8888(
+ SDE_PIX_FMT_XBGR_8888, SDE_MDP_FMT_LINEAR,
+ VALID_ROT_WB_ALL | VALID_MDP_WB_INTF_FORMAT,
+ 0, C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, SDE_MDP_COMPRESS_NONE),
FMT_YUV_PSEUDO(SDE_PIX_FMT_Y_CRCB_H2V1, SDE_MDP_FMT_LINEAR,
SDE_MDP_CHROMA_H2V1, SDE_MDP_PIXEL_NORMAL,
@@ -401,10 +405,36 @@ static struct sde_mdp_format_params sde_mdp_format_map[] = {
},
FMT_RGB_1555(SDE_PIX_FMT_RGBA_5551, 1, VALID_ROT_WB_ALL,
C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
+ FMT_RGB_1555(SDE_PIX_FMT_ARGB_1555, 1, VALID_ROT_WB_ALL,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
+ FMT_RGB_1555(SDE_PIX_FMT_ABGR_1555, 1, VALID_ROT_WB_ALL,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
+ FMT_RGB_1555(SDE_PIX_FMT_BGRA_5551, 1, VALID_ROT_WB_ALL,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_1555(SDE_PIX_FMT_BGRX_5551, 0, VALID_ROT_WB_ALL,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_1555(SDE_PIX_FMT_RGBX_5551, 0, VALID_ROT_WB_ALL,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
+ FMT_RGB_1555(SDE_PIX_FMT_XBGR_1555, 0, VALID_ROT_WB_ALL,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
+ FMT_RGB_1555(SDE_PIX_FMT_XRGB_1555, 0, VALID_ROT_WB_ALL,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
FMT_RGB_4444(SDE_PIX_FMT_RGBA_4444, 1, VALID_ROT_WB_ALL,
C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
FMT_RGB_4444(SDE_PIX_FMT_ARGB_4444, 1, VALID_ROT_WB_ALL,
C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
+ FMT_RGB_4444(SDE_PIX_FMT_BGRA_4444, 1, VALID_ROT_WB_ALL,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_4444(SDE_PIX_FMT_ABGR_4444, 1, VALID_ROT_WB_ALL,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
+ FMT_RGB_4444(SDE_PIX_FMT_RGBX_4444, 0, VALID_ROT_WB_ALL,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr),
+ FMT_RGB_4444(SDE_PIX_FMT_XRGB_4444, 0, VALID_ROT_WB_ALL,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA),
+ FMT_RGB_4444(SDE_PIX_FMT_BGRX_4444, 0, VALID_ROT_WB_ALL,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb),
+ FMT_RGB_4444(SDE_PIX_FMT_XBGR_4444, 0, VALID_ROT_WB_ALL,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA),
FMT_RGB_1010102(SDE_PIX_FMT_RGBA_1010102, SDE_MDP_FMT_LINEAR,
VALID_ROT_R3_WB_FORMAT | VALID_MDP_WB_INTF_FORMAT,
1, C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, SDE_MDP_COMPRESS_NONE),
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
index d5388db4a9b1..c141797bcd3c 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3.c
@@ -575,14 +575,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx,
if (rot->irq_num >= 0)
reinit_completion(&ctx->regdma_comp);
- /* enable IRQ for first regdma submission from idle */
- if (atomic_read(&rot->regdma_submit_count) ==
- atomic_read(&rot->regdma_done_count)) {
- SDEROT_DBG("Enable IRQ! regdma submitcnt==donecnt -> %d\n",
- atomic_read(&rot->regdma_submit_count));
- enable_irq(rot->irq_num);
- }
-
/*
* Last ROT command must be ROT_START before REGDMA start
*/
@@ -640,9 +632,6 @@ static u32 sde_hw_rotator_start_regdma(struct sde_hw_rotator_context *ctx,
enableInt | (ts_length << 14) | offset);
}
- /* Update REGDMA submit count */
- atomic_inc(&rot->regdma_submit_count);
-
/* Update command queue write ptr */
sde_hw_rotator_put_regdma_segment(ctx, wrptr);
@@ -731,7 +720,6 @@ static u32 sde_hw_rotator_wait_done_regdma(
u32 last_ts;
u32 int_id;
u32 sts = 0;
- u32 d_count;
unsigned long flags;
if (rot->irq_num >= 0) {
@@ -753,6 +741,8 @@ static u32 sde_hw_rotator_wait_done_regdma(
SDEROT_ERR(
"Timeout wait for regdma interrupt status, ts:%X\n",
ctx->timestamp);
+ SDEROT_ERR("last_isr:0x%X, last_ts:0x%X, rc=%d\n",
+ last_isr, last_ts, rc);
if (status & REGDMA_WATCHDOG_INT)
SDEROT_ERR("REGDMA watchdog interrupt\n");
@@ -784,17 +774,6 @@ static u32 sde_hw_rotator_wait_done_regdma(
status = 0;
}
- /* regardless success or timeout, update done count */
- d_count = atomic_inc_return(&rot->regdma_done_count);
-
- /* disable IRQ if no more regdma submission in queue */
- if (d_count == atomic_read(&rot->regdma_submit_count)) {
- SDEROT_DBG(
- "Disable IRQ!! regdma donecnt==submitcnt -> %d\n",
- d_count);
- disable_irq_nosync(rot->irq_num);
- }
-
spin_unlock_irqrestore(&rot->rotisr_lock, flags);
} else {
int cnt = 200;
@@ -1027,6 +1006,9 @@ static struct sde_rot_hw_resource *sde_hw_rotator_alloc_ext(
sde_hw_rotator_swts_create(resinfo->rot);
}
+ if (resinfo->rot->irq_num >= 0)
+ enable_irq(resinfo->rot->irq_num);
+
SDEROT_DBG("New rotator resource:%p, priority:%d\n",
resinfo, wb_id);
@@ -1053,6 +1035,9 @@ static void sde_hw_rotator_free_ext(struct sde_rot_mgr *mgr,
resinfo, hw->wb_id, atomic_read(&hw->num_active),
hw->pending_count);
+ if (resinfo->rot->irq_num >= 0)
+ disable_irq(resinfo->rot->irq_num);
+
devm_kfree(&mgr->pdev->dev, resinfo);
}
@@ -1505,8 +1490,7 @@ static irqreturn_t sde_hw_rotator_regdmairq_handler(int irq, void *ptr)
ctx->last_regdma_isr_status = isr;
ctx->last_regdma_timestamp = ts;
SDEROT_DBG(
- "regdma complete: ctx:%p, ts:%X, dcount:%X\n",
- ctx, ts, atomic_read(&rot->regdma_done_count));
+ "regdma complete: ctx:%p, ts:%X\n", ctx, ts);
complete_all(&ctx->regdma_comp);
ts = (ts - 1) & SDE_REGDMA_SWTS_MASK;
@@ -1854,8 +1838,6 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
atomic_set(&rot->timestamp[0], 0);
atomic_set(&rot->timestamp[1], 0);
- atomic_set(&rot->regdma_submit_count, 0);
- atomic_set(&rot->regdma_done_count, 0);
ret = sde_rotator_hw_rev_init(rot);
if (ret)
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
index 5196b1351542..610caf16c764 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_internal.h
@@ -263,9 +263,6 @@ struct sde_hw_rotator {
struct completion rot_comp;
struct completion regdma_comp;
- atomic_t regdma_submit_count;
- atomic_t regdma_done_count;
-
spinlock_t rotctx_lock;
spinlock_t rotisr_lock;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 009d8271563d..4ae13944362a 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-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, 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
@@ -462,6 +462,23 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
return mem;
}
+bool msm_smem_compare_buffers(void *clt, int fd, void *priv)
+{
+ struct smem_client *client = clt;
+ struct ion_handle *handle = NULL;
+ bool ret = false;
+
+ if (!clt || !priv) {
+ dprintk(VIDC_ERR, "Invalid params: %p, %p\n",
+ clt, priv);
+ return false;
+ }
+ handle = ion_import_dma_buf(client->clnt, fd);
+ ret = handle == priv;
+ handle ? ion_free(client->clnt, handle) : 0;
+ return ret;
+}
+
static int ion_cache_operations(struct smem_client *client,
struct msm_smem *mem, enum smem_cache_ops cache_op)
{
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 14b62984eae9..5c9dc6a53223 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -1552,52 +1552,6 @@ static int msm_venc_toggle_hier_p(struct msm_vidc_inst *inst, int layers)
return rc;
}
-static int set_bitrate_for_each_layer(struct msm_vidc_inst *inst,
- u32 num_enh_layers, u32 total_bitrate)
-{
- u32 property_id = 0;
- int i = 0, rc = 0;
- struct hfi_device *hdev = NULL;
- struct hal_bitrate bitrate;
- struct hal_enable enable;
- int bitrate_table[3][4] = {
- {50, 50, 0, 0},
- {34, 33, 33, 0},
- {25, 25, 25, 25}
- };
-
- if (!inst || !inst->core || !inst->core->device) {
- dprintk(VIDC_ERR, "%s - invalid input\n", __func__);
- return -EINVAL;
- }
-
- if (!num_enh_layers || num_enh_layers > ARRAY_SIZE(bitrate_table)) {
- dprintk(VIDC_ERR, "%s - invalid number of enh layers: %d\n",
- __func__, num_enh_layers);
- return -EINVAL;
- }
- hdev = inst->core->device;
-
- property_id = HAL_PARAM_VENC_BITRATE_TYPE;
- enable.enable = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_ENABLE;
- rc = call_hfi_op(hdev, session_set_property,
- (void *)inst->session, property_id, &enable);
- if (rc) {
- dprintk(VIDC_ERR, "Failed to set layerwise bitrate\n");
- return false;
- }
-
- for (i = 0; !rc && i <= num_enh_layers; i++) {
- property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
- bitrate.bit_rate = (u32)((total_bitrate *
- bitrate_table[num_enh_layers - 1][i]) / 100);
- bitrate.layer_id = i;
- rc = call_hfi_op(hdev, session_set_property,
- (void *)inst->session, property_id, &bitrate);
- }
- return rc;
-}
-
static inline int msm_venc_power_save_mode_enable(struct msm_vidc_inst *inst)
{
u32 rc = 0;
@@ -2269,26 +2223,10 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
}
case V4L2_CID_MPEG_VIDEO_BITRATE:
{
- struct v4l2_ctrl *hier_p = TRY_GET_CTRL(
- V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS);
-
+ property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
+ bitrate.bit_rate = ctrl->val;
bitrate.layer_id = 0;
- if (hier_p->val &&
- inst->fmts[CAPTURE_PORT]->fourcc ==
- V4L2_PIX_FMT_H264) {
- rc = set_bitrate_for_each_layer(inst,
- hier_p->val, ctrl->val);
- if (rc) {
- dprintk(VIDC_ERR,
- "failed to set bitrate for multiple layers\n");
- rc = -EINVAL;
- }
- } else {
- property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
- bitrate.bit_rate = ctrl->val;
- bitrate.layer_id = 0;
- pdata = &bitrate;
- }
+ pdata = &bitrate;
break;
}
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
@@ -3236,8 +3174,8 @@ static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
bitrate.bit_rate = control[i].value;
property_id = HAL_CONFIG_VENC_TARGET_BITRATE;
pdata = &bitrate;
- dprintk(VIDC_DBG, "layerwise bitrate for %d\n",
- i);
+ dprintk(VIDC_DBG, "bitrate for layer(%d)=%d\n",
+ i, bitrate.bit_rate);
rc = call_hfi_op(hdev, session_set_property,
(void *)inst->session, property_id,
pdata);
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 51be8df7ff35..2dab1f98f30a 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -213,7 +213,9 @@ struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
*plane = 0;
list_for_each_entry(temp, &inst->registeredbufs.list, list) {
for (i = 0; i < min(temp->num_planes, VIDEO_MAX_PLANES); i++) {
- bool fd_matches = fd == temp->fd[i];
+ bool ion_hndl_matches = temp->handle[i] ?
+ msm_smem_compare_buffers(inst->mem_client, fd,
+ temp->handle[i]->smem_priv) : false;
bool device_addr_matches = device_addr ==
temp->device_addr[i];
bool contains_within = CONTAINS(temp->buff_off[i],
@@ -223,7 +225,7 @@ struct buffer_info *get_registered_buf(struct msm_vidc_inst *inst,
temp->buff_off[i], temp->size[i]);
if (!temp->inactive &&
- (fd_matches || device_addr_matches) &&
+ (ion_hndl_matches || device_addr_matches) &&
(contains_within || overlaps)) {
dprintk(VIDC_DBG,
"This memory region is already mapped\n");
@@ -386,13 +388,6 @@ static inline bool is_dynamic_output_buffer_mode(struct v4l2_buffer *b,
}
-static inline bool is_encoder_input_buffer(struct v4l2_buffer *b,
- struct msm_vidc_inst *inst)
-{
- return b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
- inst->session_type == MSM_VIDC_ENCODER;
-}
-
static inline void save_v4l2_buffer(struct v4l2_buffer *b,
struct buffer_info *binfo)
{
@@ -907,8 +902,7 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
for (i = 0; i < b->length; i++) {
if (EXTRADATA_IDX(b->length) &&
- (i == EXTRADATA_IDX(b->length)) &&
- !b->m.planes[i].m.userptr) {
+ i == EXTRADATA_IDX(b->length)) {
continue;
}
buffer_info = device_to_uvaddr(&inst->registeredbufs,
@@ -943,8 +937,8 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
if (rc)
return rc;
- if (is_dynamic_output_buffer_mode(b, inst) ||
- is_encoder_input_buffer(b, inst)) {
+
+ if (is_dynamic_output_buffer_mode(b, inst)) {
buffer_info->dequeued = true;
dprintk(VIDC_DBG, "[DEQUEUED]: fd[0] = %d\n",
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 81a73728fb0c..05bfabce2bb2 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -1704,36 +1704,6 @@ static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq,
return vb;
}
-
-static void handle_dynamic_input_buffer(struct msm_vidc_inst *inst,
- ion_phys_addr_t device_addr)
-{
- struct buffer_info *binfo = NULL, *temp = NULL;
-
- if (inst->session_type == MSM_VIDC_ENCODER) {
- binfo = device_to_uvaddr(&inst->registeredbufs, device_addr);
- if (!binfo) {
- dprintk(VIDC_ERR,
- "%s buffer not found in registered list\n",
- __func__);
- return;
- }
- dprintk(VIDC_DBG,
- "EBD fd[0] = %d -> EBD_ref_released, addr: %pa\n",
- binfo->fd[0], &device_addr);
-
- mutex_lock(&inst->registeredbufs.lock);
- list_for_each_entry(temp, &inst->registeredbufs.list,
- list) {
- if (temp == binfo) {
- binfo->pending_deletion = true;
- break;
- }
- }
- mutex_unlock(&inst->registeredbufs.lock);
- }
-}
-
static void handle_ebd(enum hal_command_response cmd, void *data)
{
struct msm_vidc_cb_data_done *response = data;
@@ -1754,8 +1724,6 @@ static void handle_ebd(enum hal_command_response cmd, void *data)
return;
}
- handle_dynamic_input_buffer(inst, response->input_done.packet_buffer);
-
vb = get_vb_from_device_addr(&inst->bufq[OUTPUT_PORT],
response->input_done.packet_buffer);
if (vb) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
index c127a17b6157..72c1ddcf3a70 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h
@@ -373,6 +373,7 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset,
struct context_bank_info *msm_smem_get_context_bank(void *clt,
bool is_secure, enum hal_buffer buffer_type);
void msm_vidc_fw_unload_handler(struct work_struct *work);
+bool msm_smem_compare_buffers(void *clt, int fd, void *priv);
/* XXX: normally should be in msm_vidc.h, but that's meant for public APIs,
* whereas this is private */
int msm_vidc_destroy(struct msm_vidc_inst *inst);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 5525e35a029f..d19d8b624c19 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -1238,6 +1238,13 @@ static unsigned long __get_clock_rate_with_bitrate(struct clock_info *clock,
break;
}
}
+
+ /*
+ * Current bitrate is higher than max supported load.
+ * Select max frequency to handle this load.
+ */
+ if (i < 0)
+ supported_clk[j] = table[0].freq;
}
for (i = 0; i < data->num_sessions; i++)
@@ -2218,9 +2225,14 @@ static int venus_hfi_core_init(void *device)
if (rc || __iface_cmdq_write(dev, &version_pkt))
dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n");
- if (dev->res->pm_qos_latency_us)
+ if (dev->res->pm_qos_latency_us) {
+#ifdef CONFIG_SMP
+ dev->qos.type = PM_QOS_REQ_AFFINE_IRQ;
+ dev->qos.irq = dev->hal_data->irq;
+#endif
pm_qos_add_request(&dev->qos, PM_QOS_CPU_DMA_LATENCY,
dev->res->pm_qos_latency_us);
+ }
mutex_unlock(&dev->lock);
return rc;
@@ -2244,7 +2256,8 @@ static int venus_hfi_core_release(void *dev)
mutex_lock(&device->lock);
- if (device->res->pm_qos_latency_us)
+ if (device->res->pm_qos_latency_us &&
+ pm_qos_request_active(&device->qos))
pm_qos_remove_request(&device->qos);
__set_state(device, VENUS_STATE_DEINIT);
__unload_fw(device);
@@ -4208,7 +4221,8 @@ static inline int __suspend(struct venus_hfi_device *device)
dprintk(VIDC_DBG, "Entering power collapse\n");
- if (device->res->pm_qos_latency_us)
+ if (device->res->pm_qos_latency_us &&
+ pm_qos_request_active(&device->qos))
pm_qos_remove_request(&device->qos);
rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND);
@@ -4270,9 +4284,14 @@ static inline int __resume(struct venus_hfi_device *device)
*/
__set_threshold_registers(device);
- if (device->res->pm_qos_latency_us)
+ if (device->res->pm_qos_latency_us) {
+#ifdef CONFIG_SMP
+ device->qos.type = PM_QOS_REQ_AFFINE_IRQ;
+ device->qos.irq = device->hal_data->irq;
+#endif
pm_qos_add_request(&device->qos, PM_QOS_CPU_DMA_LATENCY,
device->res->pm_qos_latency_us);
+ }
dprintk(VIDC_INFO, "Resumed from power collapse\n");
exit:
device->skip_pc_count = 0;
diff --git a/drivers/mfd/qcom-i2c-pmic.c b/drivers/mfd/qcom-i2c-pmic.c
index 4d0bdce755a6..9eb75d876577 100644
--- a/drivers/mfd/qcom-i2c-pmic.c
+++ b/drivers/mfd/qcom-i2c-pmic.c
@@ -58,7 +58,6 @@ struct i2c_pmic_periph {
struct i2c_pmic {
struct device *dev;
- struct i2c_client *client;
struct regmap *regmap;
struct irq_domain *domain;
struct i2c_pmic_periph *periph;
@@ -497,25 +496,28 @@ static struct regmap_config i2c_pmic_regmap_config = {
static int i2c_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int rc;
struct i2c_pmic *chip;
+ int rc = 0;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ chip->dev = &client->dev;
chip->regmap = devm_regmap_init_i2c(client, &i2c_pmic_regmap_config);
if (!chip->regmap)
return -ENODEV;
+ i2c_set_clientdata(client, chip);
+ if (!of_property_read_bool(chip->dev->of_node, "interrupt-controller"))
+ goto probe_children;
+
chip->domain = irq_domain_add_tree(client->dev.of_node,
&i2c_pmic_domain_ops, chip);
- if (!chip->domain)
- return -ENOMEM;
-
- chip->client = client;
- chip->dev = &client->dev;
- i2c_set_clientdata(client, chip);
+ if (!chip->domain) {
+ rc = -ENOMEM;
+ goto cleanup;
+ }
rc = i2c_pmic_parse_dt(chip);
if (rc < 0) {
@@ -549,6 +551,8 @@ static int i2c_pmic_probe(struct i2c_client *client,
}
enable_irq_wake(client->irq);
+
+probe_children:
of_platform_populate(chip->dev->of_node, NULL, NULL, chip->dev);
pr_info("I2C PMIC probe successful\n");
return rc;
@@ -565,7 +569,8 @@ static int i2c_pmic_remove(struct i2c_client *client)
struct i2c_pmic *chip = i2c_get_clientdata(client);
of_platform_depopulate(chip->dev);
- irq_domain_remove(chip->domain);
+ if (chip->domain)
+ irq_domain_remove(chip->domain);
i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 1aec5e559dd5..273728482227 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -433,7 +433,6 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
smc_id = TZ_OS_APP_SHUTDOWN_ID;
desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID;
desc.args[0] = req->app_id;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
ret = scm_call2(smc_id, &desc);
break;
}
@@ -2104,6 +2103,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
return 0;
}
+ __qseecom_cleanup_app(data);
+ __qseecom_reentrancy_check_if_no_app_blocked(TZ_OS_APP_SHUTDOWN_ID);
+
if (data->client.app_id > 0) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
@@ -2132,11 +2134,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
}
}
- if (found_dead_app) {
+ if (found_dead_app)
pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
(char *)data->client.app_name);
- __qseecom_cleanup_app(data);
- }
if (unload) {
struct qseecom_unload_app_ireq req;
@@ -2165,7 +2165,6 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
if (resp.result == QSEOS_RESULT_SUCCESS)
pr_debug("App (%d) is unloaded!!\n",
data->client.app_id);
- __qseecom_cleanup_app(data);
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 49eb2e27b11b..18e95148e891 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -378,6 +378,10 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
/* social scan on P2P_DEVICE is handled as p2p search */
if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE &&
wil_p2p_is_social_scan(request)) {
+ if (!wil->p2p.p2p_dev_started) {
+ wil_err(wil, "P2P search requested on stopped P2P device\n");
+ return -EIO;
+ }
wil->scan_request = request;
wil->radio_wdev = wdev;
rc = wil_p2p_search(wil, request);
@@ -1351,6 +1355,7 @@ static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy,
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "%s: entered\n", __func__);
+ wil->p2p.p2p_dev_started = 1;
return 0;
}
@@ -1358,8 +1363,19 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy,
struct wireless_dev *wdev)
{
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ u8 started;
wil_dbg_misc(wil, "%s: entered\n", __func__);
+ mutex_lock(&wil->mutex);
+ started = wil_p2p_stop_discovery(wil);
+ if (started && wil->scan_request) {
+ cfg80211_scan_done(wil->scan_request, 1);
+ wil->scan_request = NULL;
+ wil->radio_wdev = wil->wdev;
+ }
+ mutex_unlock(&wil->mutex);
+
+ wil->p2p.p2p_dev_started = 0;
}
static struct cfg80211_ops wil_cfg80211_ops = {
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index 2a05031ba631..bd4c17ca2484 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -14,10 +14,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/moduleparam.h>
#include <linux/etherdevice.h>
#include "wil6210.h"
#include "txrx.h"
+static bool alt_ifname; /* = false; */
+module_param(alt_ifname, bool, S_IRUGO);
+MODULE_PARM_DESC(alt_ifname, " use an alternate interface name wigigN instead of wlanN");
+
static int wil_open(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -136,6 +141,7 @@ void *wil_if_alloc(struct device *dev)
struct wil6210_priv *wil;
struct ieee80211_channel *ch;
int rc = 0;
+ const char *ifname = alt_ifname ? "wigig%d" : "wlan%d";
wdev = wil_cfg80211_init(dev);
if (IS_ERR(wdev)) {
@@ -160,7 +166,7 @@ void *wil_if_alloc(struct device *dev)
ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
- ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
+ ndev = alloc_netdev(0, ifname, NET_NAME_UNKNOWN, wil_dev_setup);
if (!ndev) {
dev_err(dev, "alloc_netdev_mqs failed\n");
rc = -ENOMEM;
diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c
index 1c9153894dca..213b8259638c 100644
--- a/drivers/net/wireless/ath/wil6210/p2p.c
+++ b/drivers/net/wireless/ath/wil6210/p2p.c
@@ -114,8 +114,10 @@ int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
u8 channel = P2P_DMG_SOCIAL_CHANNEL;
int rc;
- if (chan)
- channel = chan->hw_value;
+ if (!chan)
+ return -EINVAL;
+
+ channel = chan->hw_value;
wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index a67725419c76..cd0bfdf34248 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -461,6 +461,7 @@ struct wil_tid_crypto_rx {
struct wil_p2p_info {
struct ieee80211_channel listen_chan;
u8 discovery_started;
+ u8 p2p_dev_started;
u64 cookie;
struct timer_list discovery_timer; /* listen/search duration */
struct work_struct discovery_expired_work; /* listen/search expire */
diff --git a/drivers/net/wireless/cnss/cnss_common.c b/drivers/net/wireless/cnss/cnss_common.c
index 3639d3245077..498dd87e1a91 100644
--- a/drivers/net/wireless/cnss/cnss_common.c
+++ b/drivers/net/wireless/cnss/cnss_common.c
@@ -21,7 +21,7 @@
#include <linux/mutex.h>
#include <linux/rwsem.h>
#include <net/cnss.h>
-#include <net/cnss_common.h>
+#include "cnss_common.h"
#include <net/cfg80211.h>
enum cnss_dev_bus_type {
diff --git a/drivers/net/wireless/cnss/cnss_common.h b/drivers/net/wireless/cnss/cnss_common.h
new file mode 100644
index 000000000000..db5ed02d47ab
--- /dev/null
+++ b/drivers/net/wireless/cnss/cnss_common.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2016, 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 _NET_CNSS_COMMON_H_
+#define _NET_CNSS_COMMON_H_
+
+#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
+/* max 20mhz channel count */
+#define CNSS_MAX_CH_NUM 45
+
+int cnss_pci_request_bus_bandwidth(int bandwidth);
+int cnss_sdio_request_bus_bandwidth(int bandwidth);
+
+void cnss_sdio_device_crashed(void);
+void cnss_pci_device_crashed(void);
+
+void cnss_pci_device_self_recovery(void);
+void cnss_sdio_device_self_recovery(void);
+
+void *cnss_pci_get_virt_ramdump_mem(unsigned long *size);
+void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size);
+
+void cnss_sdio_schedule_recovery_work(void);
+void cnss_pci_schedule_recovery_work(void);
+
+int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len);
+int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len);
+
+u8 *cnss_pci_get_wlan_mac_address(uint32_t *num);
+u8 *cnss_sdio_get_wlan_mac_address(uint32_t *num);
+#endif /* _NET_CNSS_COMMON_H_ */
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
index 322de8b58cd5..daa7f65690db 100644
--- a/drivers/net/wireless/cnss/cnss_pci.c
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -48,7 +48,7 @@
#include <net/cfg80211.h>
#include <soc/qcom/memory_dump.h>
#include <net/cnss.h>
-#include <net/cnss_common.h>
+#include "cnss_common.h"
#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
#include <net/cnss_prealloc.h>
@@ -2059,7 +2059,6 @@ end:
*num = 0;
return NULL;
}
-EXPORT_SYMBOL(cnss_pci_get_wlan_mac_address);
/**
* cnss_get_wlan_mac_address() - API to return MAC addresses buffer
@@ -2149,7 +2148,6 @@ int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len)
}
return 0;
}
-EXPORT_SYMBOL(cnss_pcie_set_wlan_mac_address);
int cnss_wlan_register_driver(struct cnss_wlan_driver *driver)
{
diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c
index e8833e499bcd..bb64e2149742 100644
--- a/drivers/net/wireless/cnss/cnss_sdio.c
+++ b/drivers/net/wireless/cnss/cnss_sdio.c
@@ -27,7 +27,7 @@
#include <soc/qcom/ramdump.h>
#include <soc/qcom/memory_dump.h>
#include <net/cnss.h>
-#include <net/cnss_common.h>
+#include "cnss_common.h"
#include <linux/pm_qos.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
@@ -1161,14 +1161,12 @@ int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len)
{
return 0;
}
-EXPORT_SYMBOL(cnss_sdio_set_wlan_mac_address);
u8 *cnss_sdio_get_wlan_mac_address(uint32_t *num)
{
*num = 0;
return NULL;
}
-EXPORT_SYMBOL(cnss_sdio_get_wlan_mac_address);
static const struct of_device_id cnss_sdio_dt_match[] = {
{.compatible = "qcom,cnss_sdio"},
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c
index a9813311f156..bf6352452283 100644
--- a/drivers/platform/msm/ipa/ipa_rm.c
+++ b/drivers/platform/msm/ipa/ipa_rm.c
@@ -986,6 +986,8 @@ int ipa_rm_stat(char *buf, int size)
unsigned long flags;
int i, cnt = 0, result = EINVAL;
struct ipa_rm_resource *resource = NULL;
+ u32 sum_bw_prod = 0;
+ u32 sum_bw_cons = 0;
if (!buf || size < 0)
return result;
@@ -1005,6 +1007,24 @@ int ipa_rm_stat(char *buf, int size)
cnt += result;
}
}
+
+ for (i = 0; i < IPA_RM_RESOURCE_PROD_MAX; i++)
+ sum_bw_prod += ipa_rm_ctx->prof_vote.bw_prods[i];
+
+ for (i = 0; i < IPA_RM_RESOURCE_CONS_MAX; i++)
+ sum_bw_cons += ipa_rm_ctx->prof_vote.bw_cons[i];
+
+ result = scnprintf(buf + cnt, size - cnt,
+ "All prod bandwidth: %d, All cons bandwidth: %d\n",
+ sum_bw_prod, sum_bw_cons);
+ cnt += result;
+
+ result = scnprintf(buf + cnt, size - cnt,
+ "Voting: voltage %d, bandwidth %d\n",
+ ipa_rm_ctx->prof_vote.curr_volt,
+ ipa_rm_ctx->prof_vote.curr_bw);
+ cnt += result;
+
result = cnt;
bail:
spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags);
diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c
index cc00f8cf7fb6..0a3f66307eee 100644
--- a/drivers/platform/msm/ipa/ipa_rm_resource.c
+++ b/drivers/platform/msm/ipa/ipa_rm_resource.c
@@ -1133,7 +1133,7 @@ int ipa_rm_resource_producer_print_stat(
nbytes = scnprintf(buf + cnt, size - cnt,
ipa_rm_resource_str(resource->name));
cnt += nbytes;
- nbytes = scnprintf(buf + cnt, size - cnt, "[");
+ nbytes = scnprintf(buf + cnt, size - cnt, "[%d, ", resource->max_bw);
cnt += nbytes;
switch (resource->state) {
@@ -1170,7 +1170,8 @@ int ipa_rm_resource_producer_print_stat(
nbytes = scnprintf(buf + cnt, size - cnt,
ipa_rm_resource_str(consumer->name));
cnt += nbytes;
- nbytes = scnprintf(buf + cnt, size - cnt, "[");
+ nbytes = scnprintf(buf + cnt, size - cnt, "[%d, ",
+ consumer->max_bw);
cnt += nbytes;
switch (consumer->state) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 747ae3d82b68..c553be1ad717 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -218,6 +218,7 @@ static struct {
bool disable_htw;
bool fast_map;
bool s1_bypass;
+ bool use_64_bit_dma_mask;
u32 ipa_base;
u32 ipa_size;
} smmu_info;
@@ -3961,7 +3962,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p,
goto fail_bind;
}
- result = ipa3_init_mem_partition(ipa_dev->of_node);
+ result = ipa3_init_mem_partition(master_dev->of_node);
if (result) {
IPAERR(":ipa3_init_mem_partition failed!\n");
result = -ENODEV;
@@ -4715,7 +4716,7 @@ static int ipa_smmu_uc_cb_probe(struct device *dev)
cb->va_end = cb->va_start + cb->va_size;
IPADBG("UC va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
- if (ipa3_ctx->use_64_bit_dma_mask) {
+ if (smmu_info.use_64_bit_dma_mask) {
if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
IPAERR("DMA set 64bit mask failed\n");
@@ -4826,7 +4827,7 @@ static int ipa_smmu_ap_cb_probe(struct device *dev)
cb->va_end = cb->va_start + cb->va_size;
IPADBG("AP va_start=0x%x va_sise=0x%x\n", cb->va_start, cb->va_size);
- if (ipa3_ctx->use_64_bit_dma_mask) {
+ if (smmu_info.use_64_bit_dma_mask) {
if (dma_set_mask(dev, DMA_BIT_MASK(64)) ||
dma_set_coherent_mask(dev, DMA_BIT_MASK(64))) {
IPAERR("DMA set 64bit mask failed\n");
@@ -5035,6 +5036,9 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
if (of_property_read_bool(pdev_p->dev.of_node,
"qcom,smmu-fast-map"))
smmu_info.fast_map = true;
+ if (of_property_read_bool(pdev_p->dev.of_node,
+ "qcom,use-64-bit-dma-mask"))
+ smmu_info.use_64_bit_dma_mask = true;
smmu_info.arm_smmu = true;
pr_info("IPA smmu_info.s1_bypass=%d smmu_info.fast_map=%d\n",
smmu_info.s1_bypass, smmu_info.fast_map);
@@ -5059,16 +5063,16 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p,
return -EOPNOTSUPP;
}
}
- }
- if (!ipa3_bus_scale_table)
- ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p);
+ if (!ipa3_bus_scale_table)
+ ipa3_bus_scale_table = msm_bus_cl_get_pdata(pdev_p);
- /* Proceed to real initialization */
- result = ipa3_pre_init(&ipa3_res, dev);
- if (result) {
- IPAERR("ipa3_init failed\n");
- return result;
+ /* Proceed to real initialization */
+ result = ipa3_pre_init(&ipa3_res, dev);
+ if (result) {
+ IPAERR("ipa3_init failed\n");
+ return result;
+ }
}
return result;
diff --git a/drivers/power/qcom-charger/smb-lib.c b/drivers/power/qcom-charger/smb-lib.c
index 0465bfac296d..a7bda329cadd 100644
--- a/drivers/power/qcom-charger/smb-lib.c
+++ b/drivers/power/qcom-charger/smb-lib.c
@@ -783,22 +783,16 @@ int smblib_get_prop_batt_health(struct smb_charger *chg,
goto done;
}
- switch (stat & BAT_TEMP_STATUS_MASK) {
- case BAT_TEMP_STATUS_TOO_COLD_BIT:
+ if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT)
val->intval = POWER_SUPPLY_HEALTH_COLD;
- break;
- case BAT_TEMP_STATUS_TOO_HOT_BIT:
+ else if (stat & BAT_TEMP_STATUS_TOO_HOT_BIT)
val->intval = POWER_SUPPLY_HEALTH_OVERHEAT;
- break;
- case BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT:
+ else if (stat & BAT_TEMP_STATUS_COLD_SOFT_LIMIT_BIT)
val->intval = POWER_SUPPLY_HEALTH_COOL;
- break;
- case BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT:
+ else if (stat & BAT_TEMP_STATUS_HOT_SOFT_LIMIT_BIT)
val->intval = POWER_SUPPLY_HEALTH_WARM;
- break;
- default:
+ else
val->intval = POWER_SUPPLY_HEALTH_GOOD;
- }
done:
return rc;
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 5c5bd1975fb3..807349533dd1 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -133,6 +133,7 @@ enum icnss_driver_state {
ICNSS_FW_READY,
ICNSS_DRIVER_PROBED,
ICNSS_FW_TEST_MODE,
+ ICNSS_SUSPEND,
};
struct ce_irq_list {
@@ -2002,6 +2003,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_data *priv)
case ICNSS_FW_TEST_MODE:
seq_puts(s, "FW TEST MODE");
continue;
+ case ICNSS_SUSPEND:
+ seq_puts(s, "DRIVER SUSPENDED");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
@@ -2362,6 +2366,54 @@ static int icnss_remove(struct platform_device *pdev)
return 0;
}
+static int icnss_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ int ret = 0;
+
+ if (!penv) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ icnss_pr_dbg("Driver suspending, state: 0x%lx\n",
+ penv->state);
+
+ if (!penv->ops)
+ goto out;
+
+ if (penv->ops->suspend)
+ ret = penv->ops->suspend(&pdev->dev, state);
+
+out:
+ if (ret == 0)
+ set_bit(ICNSS_SUSPEND, &penv->state);
+ return ret;
+}
+
+static int icnss_resume(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ if (!penv) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ icnss_pr_dbg("Driver resuming, state: 0x%lx\n",
+ penv->state);
+
+ if (!penv->ops)
+ goto out;
+
+ if (penv->ops->resume)
+ ret = penv->ops->resume(&pdev->dev);
+
+out:
+ if (ret == 0)
+ clear_bit(ICNSS_SUSPEND, &penv->state);
+ return ret;
+}
static const struct of_device_id icnss_dt_match[] = {
{.compatible = "qcom,icnss"},
@@ -2373,6 +2425,8 @@ MODULE_DEVICE_TABLE(of, icnss_dt_match);
static struct platform_driver icnss_driver = {
.probe = icnss_probe,
.remove = icnss_remove,
+ .suspend = icnss_suspend,
+ .resume = icnss_resume,
.driver = {
.name = "icnss",
.owner = THIS_MODULE,
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 14e46b38c6df..7e5f1661932f 100644
--- a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
+++ b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
@@ -330,6 +330,7 @@ struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest, uint32_t dl,
if (IS_ERR_OR_NULL(apr_ch->handle)) {
pr_err("%s: glink_open failed %s\n", __func__,
svc_names[dest][clnt]);
+ apr_ch->handle = NULL;
goto unlock;
}
diff --git a/drivers/thermal/msm_lmh_dcvs.c b/drivers/thermal/msm_lmh_dcvs.c
index 3c37f0728481..cd45eeccbfe7 100644
--- a/drivers/thermal/msm_lmh_dcvs.c
+++ b/drivers/thermal/msm_lmh_dcvs.c
@@ -44,11 +44,13 @@
#define MSM_LIMITS_ALGO_MODE_ENABLE 0x454E424C
#define MSM_LIMITS_HI_THRESHOLD 0x48494748
-#define MSM_LIMITS_LO_THRESHOLD 0x4C4F5700
+#define MSM_LIMITS_ARM_THRESHOLD 0x41524D00
#define MSM_LIMITS_CLUSTER_0 0x6370302D
#define MSM_LIMITS_CLUSTER_1 0x6370312D
+#define MSM_LIMITS_HIGH_THRESHOLD_VAL 95000
+#define MSM_LIMITS_ARM_THRESHOLD_VAL 65000
#define MSM_LIMITS_POLLING_DELAY_MS 10
#define MSM_LIMITS_CLUSTER_0_REQ 0x179C1B04
#define MSM_LIMITS_CLUSTER_1_REQ 0x179C3B04
@@ -203,7 +205,7 @@ static int lmh_activate_trip(struct thermal_zone_device *dev,
hw->temp_limits[LIMITS_TRIP_HI])
return -EINVAL;
- thresh = (trip == LIMITS_TRIP_LO) ? MSM_LIMITS_LO_THRESHOLD :
+ thresh = (trip == LIMITS_TRIP_LO) ? MSM_LIMITS_ARM_THRESHOLD :
MSM_LIMITS_HI_THRESHOLD;
temp = hw->temp_limits[trip];
@@ -306,11 +308,11 @@ static int msm_lmh_dcvs_probe(struct platform_device *pdev)
if (ret)
return ret;
- hw->default_lo.temp = 65000;
+ hw->default_lo.temp = MSM_LIMITS_ARM_THRESHOLD_VAL;
hw->default_lo.trip = THERMAL_TRIP_CONFIGURABLE_LOW;
hw->default_lo.notify = trip_notify;
- hw->default_hi.temp = 95000;
+ hw->default_hi.temp = MSM_LIMITS_HIGH_THRESHOLD_VAL;
hw->default_hi.trip = THERMAL_TRIP_CONFIGURABLE_HI;
hw->default_hi.notify = trip_notify;
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a395097a2098..7585c603cb3d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -1021,8 +1021,8 @@ static int dwc3_probe(struct platform_device *pdev)
/* will be enabled in dwc3_msm_resume() */
irq_set_status_flags(irq, IRQ_NOAUTOEN);
- ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3",
- dwc);
+ ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt,
+ IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index d79e85979e40..468a7bcd8dbd 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -2459,12 +2459,12 @@ static int gsi_bind(struct usb_configuration *c, struct usb_function *f)
info.ss_desc_hdr = ecm_gsi_ss_function;
info.in_epname = "gsi-epin";
info.out_epname = "gsi-epout";
- gsi->d_port.in_aggr_size = GSI_IN_ECM_AGGR_SIZE;
+ gsi->d_port.in_aggr_size = GSI_ECM_AGGR_SIZE;
info.in_req_buf_len = GSI_IN_BUFF_SIZE;
info.in_req_num_buf = num_in_bufs;
- gsi->d_port.out_aggr_size = GSI_OUT_AGGR_SIZE;
+ gsi->d_port.out_aggr_size = GSI_ECM_AGGR_SIZE;
info.out_req_buf_len = GSI_OUT_ECM_BUF_LEN;
- info.out_req_num_buf = num_out_bufs;
+ info.out_req_num_buf = GSI_ECM_NUM_OUT_BUFFERS;
info.notify_buf_len = GSI_CTRL_NOTIFY_BUFF_LEN;
/* export host's Ethernet address in CDC format */
@@ -2574,11 +2574,16 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f)
if (gsi->prot_id == IPA_USB_MBIM)
mbim_gsi_ext_config_desc.function.subCompatibleID[0] = 0;
- if (gadget_is_superspeed(c->cdev->gadget))
+ if (gadget_is_superspeed(c->cdev->gadget)) {
usb_free_descriptors(f->ss_descriptors);
- if (gadget_is_dualspeed(c->cdev->gadget))
+ f->ss_descriptors = NULL;
+ }
+ if (gadget_is_dualspeed(c->cdev->gadget)) {
usb_free_descriptors(f->hs_descriptors);
+ f->hs_descriptors = NULL;
+ }
usb_free_descriptors(f->fs_descriptors);
+ f->fs_descriptors = NULL;
if (gsi->c_port.notify) {
kfree(gsi->c_port.notify_req->buf);
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index eb42feff0712..d56012779c78 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -38,12 +38,13 @@
#define GSI_NUM_IN_BUFFERS 7
#define GSI_IN_BUFF_SIZE 2048
#define GSI_NUM_OUT_BUFFERS 7
+#define GSI_ECM_NUM_OUT_BUFFERS 31
#define GSI_OUT_AGGR_SIZE 24576
#define GSI_IN_RNDIS_AGGR_SIZE 9216
#define GSI_IN_MBIM_AGGR_SIZE 16384
#define GSI_IN_RMNET_AGGR_SIZE 16384
-#define GSI_IN_ECM_AGGR_SIZE 2048
+#define GSI_ECM_AGGR_SIZE 2048
#define GSI_OUT_MBIM_BUF_LEN 16384
#define GSI_OUT_RMNET_BUF_LEN 16384
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 197757c20102..8125a8f96311 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -237,11 +237,11 @@ static int xhci_plat_probe(struct platform_device *pdev)
goto put_usb3_hcd;
}
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
if (ret)
goto disable_usb_phy;
- ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
if (ret)
goto dealloc_usb2_hcd;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.c b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
index 77d7c04e6f0e..6a6cdc8b502c 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.c
@@ -67,6 +67,13 @@ enum edid_sink_mode {
SINK_MODE_HDMI
};
+enum luminance_value {
+ NO_LUMINANCE_DATA = 3,
+ MAXIMUM_LUMINANCE = 4,
+ FRAME_AVERAGE_LUMINANCE = 5,
+ MINIMUM_LUMINANCE = 6
+};
+
enum data_block_types {
RESERVED,
AUDIO_DATA_BLOCK,
@@ -82,6 +89,7 @@ enum extended_data_block_types {
VIDEO_CAPABILITY_DATA_BLOCK = 0x0,
VENDOR_SPECIFIC_VIDEO_DATA_BLOCK = 0x01,
HDMI_VIDEO_DATA_BLOCK = 0x04,
+ HDR_STATIC_METADATA_DATA_BLOCK = 0x06,
Y420_VIDEO_DATA_BLOCK = 0x0E,
VIDEO_FORMAT_PREFERENCE_DATA_BLOCK = 0x0D,
Y420_CAPABILITY_MAP_DATA_BLOCK = 0x0F,
@@ -143,11 +151,13 @@ struct hdmi_edid_ctrl {
char vendor_id[EDID_VENDOR_ID_SIZE];
bool keep_resv_timings;
bool edid_override;
+ bool hdr_supported;
struct hdmi_edid_sink_data sink_data;
struct hdmi_edid_init_data init_data;
struct hdmi_edid_sink_caps sink_caps;
struct hdmi_edid_override_data override_data;
+ struct hdmi_edid_hdr_data hdr_data;
};
static bool hdmi_edid_is_mode_supported(struct hdmi_edid_ctrl *edid_ctrl,
@@ -203,6 +213,14 @@ static int hdmi_edid_reset_parser(struct hdmi_edid_ctrl *edid_ctrl)
if (!edid_ctrl->keep_resv_timings)
hdmi_reset_resv_timing_info();
+ /* reset HDR related data */
+ edid_ctrl->hdr_supported = false;
+ edid_ctrl->hdr_data.eotf = 0;
+ edid_ctrl->hdr_data.descriptor = 0;
+ edid_ctrl->hdr_data.max_luminance = 0;
+ edid_ctrl->hdr_data.avg_luminance = 0;
+ edid_ctrl->hdr_data.min_luminance = 0;
+
return 0;
}
@@ -762,6 +780,30 @@ err:
}
static DEVICE_ATTR(add_res, S_IWUSR, NULL, hdmi_edid_sysfs_wta_add_resolution);
+static ssize_t hdmi_edid_sysfs_rda_hdr_data(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret;
+ struct hdmi_edid_ctrl *edid_ctrl = hdmi_edid_get_ctrl(dev);
+
+ if (!edid_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ ret = scnprintf(buf, PAGE_SIZE, "%d, %u, %u, %u, %u, %u\n",
+ edid_ctrl->hdr_supported,
+ edid_ctrl->hdr_data.eotf,
+ edid_ctrl->hdr_data.descriptor,
+ edid_ctrl->hdr_data.max_luminance,
+ edid_ctrl->hdr_data.avg_luminance,
+ edid_ctrl->hdr_data.min_luminance);
+ DEV_DBG("%s: '%s'\n", __func__, buf);
+
+ return ret;
+}
+static DEVICE_ATTR(hdr_data, S_IRUGO, hdmi_edid_sysfs_rda_hdr_data, NULL);
+
static struct attribute *hdmi_edid_fs_attrs[] = {
&dev_attr_edid_modes.attr,
&dev_attr_pa.attr,
@@ -775,6 +817,7 @@ static struct attribute *hdmi_edid_fs_attrs[] = {
&dev_attr_res_info.attr,
&dev_attr_res_info_data.attr,
&dev_attr_add_res.attr,
+ &dev_attr_hdr_data.attr,
NULL,
};
@@ -899,6 +942,47 @@ static void hdmi_edid_parse_Y420VDB(struct hdmi_edid_ctrl *edid_ctrl,
}
}
+static bool hdmi_edid_is_luminance_value_present(u32 block_length,
+ enum luminance_value value)
+{
+ return block_length > NO_LUMINANCE_DATA && value <= block_length;
+}
+
+static void hdmi_edid_parse_hdrdb(struct hdmi_edid_ctrl *edid_ctrl,
+ const u8 *data_block)
+{
+ u8 len = 0;
+
+ if (!edid_ctrl || !data_block) {
+ pr_err("%s: invalid input\n", __func__);
+ return;
+ }
+
+ /* Byte 1: Length of Data Block */
+ len = data_block[0] & 0x1F;
+
+ /* Byte 3: Electro-Optical Transfer Functions */
+ edid_ctrl->hdr_data.eotf = data_block[2] & 0x3F;
+
+ /* Byte 4: Static Metadata Descriptors */
+ edid_ctrl->hdr_data.descriptor = data_block[3] & 0x1;
+
+ /* Byte 5: Desired Content Maximum Luminance */
+ if (hdmi_edid_is_luminance_value_present(len, MAXIMUM_LUMINANCE))
+ edid_ctrl->hdr_data.max_luminance =
+ data_block[MAXIMUM_LUMINANCE];
+
+ /* Byte 6: Desired Content Max Frame-average Luminance */
+ if (hdmi_edid_is_luminance_value_present(len, FRAME_AVERAGE_LUMINANCE))
+ edid_ctrl->hdr_data.avg_luminance =
+ data_block[FRAME_AVERAGE_LUMINANCE];
+
+ /* Byte 7: Desired Content Min Luminance */
+ if (hdmi_edid_is_luminance_value_present(len, MINIMUM_LUMINANCE))
+ edid_ctrl->hdr_data.min_luminance =
+ data_block[MINIMUM_LUMINANCE];
+}
+
static void hdmi_edid_parse_Y420CMDB(struct hdmi_edid_ctrl *edid_ctrl,
const u8 *in_buf)
{
@@ -1045,6 +1129,12 @@ static void hdmi_edid_extract_extended_data_blocks(
__func__, etag[2]);
hdmi_edid_parse_Y420VDB(edid_ctrl, etag);
break;
+ case HDR_STATIC_METADATA_DATA_BLOCK:
+ DEV_DBG("%s found HDR Static Metadata. Byte 3 = 0x%x",
+ __func__, etag[2]);
+ hdmi_edid_parse_hdrdb(edid_ctrl, etag);
+ edid_ctrl->hdr_supported = true;
+ break;
default:
DEV_DBG("%s: Tag Code %d not supported\n",
__func__, etag[1]);
@@ -2355,6 +2445,31 @@ u8 hdmi_edid_get_deep_color(void *input)
return edid_ctrl->deep_color;
}
+/**
+ * hdmi_edid_get_hdr_data() - get the HDR capabiliies of the sink
+ * @input: edid parser data
+ *
+ * This API returns HDR info associated with the sink:
+ * electro-optical transfer function, static metadata descriptor,
+ * desired content max luminance data, desired content max
+ * frame-average luminance data, and desired content min luminance
+ * data.
+ *
+ * Return: HDR data.
+ */
+void hdmi_edid_get_hdr_data(void *input,
+ struct hdmi_edid_hdr_data *hdr_data)
+{
+ struct hdmi_edid_ctrl *edid_ctrl = (struct hdmi_edid_ctrl *)input;
+
+ if (!edid_ctrl || !hdr_data) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return;
+ }
+
+ hdr_data = &edid_ctrl->hdr_data;
+}
+
bool hdmi_edid_is_s3d_mode_supported(void *input, u32 video_mode, u32 s3d_mode)
{
int i;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_edid.h b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
index 7b4b2dccc802..c818f3fc0d19 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_edid.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_edid.h
@@ -28,6 +28,22 @@ struct hdmi_edid_init_data {
u32 buf_size;
};
+/*
+ * struct hdmi_edid_hdr_data - HDR Static Metadata
+ * @eotf: Electro-Optical Transfer Function
+ * @descriptor: Static Metadata Descriptor
+ * @max_luminance: Desired Content Maximum Luminance
+ * @avg_luminance: Desired Content Frame-average Luminance
+ * @min_luminance: Desired Content Minimum Luminance
+ */
+struct hdmi_edid_hdr_data {
+ u32 eotf;
+ u32 descriptor;
+ u32 max_luminance;
+ u32 avg_luminance;
+ u32 min_luminance;
+};
+
int hdmi_edid_parser(void *edid_ctrl);
u32 hdmi_edid_get_raw_data(void *edid_ctrl, u8 *buf, u32 size);
u8 hdmi_edid_get_sink_scaninfo(void *edid_ctrl, u32 resolution);
@@ -44,5 +60,7 @@ void *hdmi_edid_init(struct hdmi_edid_init_data *init_data);
bool hdmi_edid_is_s3d_mode_supported(void *input,
u32 video_mode, u32 s3d_mode);
u8 hdmi_edid_get_deep_color(void *edid_ctrl);
+void hdmi_edid_get_hdr_data(void *edid_ctrl,
+ struct hdmi_edid_hdr_data *hdr_data);
#endif /* __HDMI_EDID_H__ */
diff --git a/drivers/video/fbdev/msm/mdss_mdp_pp.c b/drivers/video/fbdev/msm/mdss_mdp_pp.c
index 634569786af4..c4cbc220baf8 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_pp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_pp.c
@@ -3118,8 +3118,8 @@ static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out,
mutex_lock(&ad->lock);
if (!mfd->ad_bl_level)
mfd->ad_bl_level = bl_in;
- if (!(ad->state & PP_AD_STATE_RUN)) {
- pr_debug("AD is not running.\n");
+ if (!(ad->sts & PP_STS_ENABLE)) {
+ pr_debug("AD is not enabled.\n");
mutex_unlock(&ad->lock);
return -EPERM;
}
@@ -3142,22 +3142,27 @@ static int pp_ad_calc_bl(struct msm_fb_data_type *mfd, int bl_in, int *bl_out,
return ret;
}
- ret = pp_ad_attenuate_bl(ad, temp, &temp);
- if (ret) {
- pr_err("Failed to attenuate BL: %d\n", ret);
- mutex_unlock(&ad->lock);
- return ret;
- }
- ad_bl_out = temp;
+ if (ad->init.alpha > 0) {
+ ret = pp_ad_attenuate_bl(ad, temp, &temp);
+ if (ret) {
+ pr_err("Failed to attenuate BL: %d\n", ret);
+ mutex_unlock(&ad->lock);
+ return ret;
+ }
+ ad_bl_out = temp;
- ret = pp_ad_linearize_bl(ad, temp, &temp, MDP_PP_AD_BL_LINEAR_INV);
- if (ret) {
- pr_err("Failed to inverse linearize BL: %d\n", ret);
- mutex_unlock(&ad->lock);
- return ret;
+ ret = pp_ad_linearize_bl(ad, temp, &temp,
+ MDP_PP_AD_BL_LINEAR_INV);
+ if (ret) {
+ pr_err("Failed to inverse linearize BL: %d\n", ret);
+ mutex_unlock(&ad->lock);
+ return ret;
+ }
+ *bl_out = temp;
+ } else {
+ ad_bl_out = temp;
}
- *bl_out = temp;
if (pp_ad_bl_threshold_check(ad->init.al_thresh, ad->init.alpha_base,
ad->last_bl, ad_bl_out)) {
mfd->ad_bl_level = ad_bl_out;
@@ -6212,6 +6217,8 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
ad->sts &= ~PP_AD_STS_DIRTY_DATA;
ad->state |= PP_AD_STATE_DATA;
pr_debug("dirty data, last_bl = %d\n", ad->last_bl);
+ if (!bl_mfd->ad_bl_level)
+ bl_mfd->ad_bl_level = bl_mfd->bl_level;
bl = bl_mfd->ad_bl_level;
if (ad->last_bl != bl) {
@@ -6299,6 +6306,7 @@ static int mdss_mdp_ad_setup(struct msm_fb_data_type *mfd)
memset(&ad->cfg, 0, sizeof(struct mdss_ad_cfg));
bl_mfd->ext_bl_ctrl = 0;
bl_mfd->ext_ad_ctrl = -1;
+ bl_mfd->ad_bl_level = 0;
}
ad->state &= ~PP_AD_STATE_RUN;
}
@@ -6403,7 +6411,7 @@ static void pp_ad_cfg_lut(char __iomem *addr, u32 *data)
}
/* must call this function from within ad->lock */
-static int pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out)
+static int pp_ad_attenuate_bl(struct mdss_ad_info *ad, u32 bl, u32 *bl_out)
{
u32 shift = 0, ratio_temp = 0;
u32 n, lut_interval, bl_att;
@@ -7420,8 +7428,8 @@ static int pp_mfd_ad_release_all(struct msm_fb_data_type *mfd)
ad->mfd = NULL;
ad->bl_mfd = NULL;
ad->state = 0;
- cancel_work_sync(&ad->calc_work);
mutex_unlock(&ad->lock);
+ cancel_work_sync(&ad->calc_work);
ctl = mfd_to_ctl(mfd);
if (ctl && ctl->ops.remove_vsync_handler)
diff --git a/include/dt-bindings/clock/msm-clocks-cobalt.h b/include/dt-bindings/clock/msm-clocks-cobalt.h
index d3cfc622b323..5cdeb01a173b 100644
--- a/include/dt-bindings/clock/msm-clocks-cobalt.h
+++ b/include/dt-bindings/clock/msm-clocks-cobalt.h
@@ -306,6 +306,11 @@
#define clk_csi2_clk_src 0x4113589f
#define clk_csi3_clk_src 0xfd934012
#define clk_fd_core_clk_src 0xe4799ab7
+#define clk_ext_dp_phy_pll_vco 0x441b576b
+#define clk_ext_dp_phy_pll_link 0xea12644c
+#define clk_dp_link_clk_src 0x370d0626
+#define clk_dp_crypto_clk_src 0xf8faa811
+#define clk_dp_pixel_clk_src 0xf5dfbabf
#define clk_ext_extpclk_clk_src 0xe5b273af
#define clk_ext_pclk0_clk_src 0x087c1612
#define clk_ext_pclk1_clk_src 0x8067c5a3
@@ -405,6 +410,10 @@
#define clk_mmss_mdss_byte1_intf_clk 0xcf654d8e
#define clk_mmss_mdss_byte1_intf_div_clk 0xcdf334c5
#define clk_mmss_mdss_dp_aux_clk 0x23125eb6
+#define clk_mmss_mdss_dp_crypto_clk 0x9a072d4e
+#define clk_mmss_mdss_dp_link_clk 0x8dd302d1
+#define clk_mmss_mdss_dp_link_intf_clk 0x70e386e6
+#define clk_mmss_mdss_dp_pixel_clk 0xb707b765
#define clk_mmss_mdss_dp_gtc_clk 0xb59c151a
#define clk_mmss_mdss_esc0_clk 0x5721ff83
#define clk_mmss_mdss_esc1_clk 0xc3d0376b
diff --git a/include/linux/inet_lro.h b/include/linux/inet_lro.h
index 9a715cfa1fe3..365fb3be7ee7 100644
--- a/include/linux/inet_lro.h
+++ b/include/linux/inet_lro.h
@@ -81,6 +81,7 @@ struct net_lro_mgr {
#define LRO_F_EXTRACT_VLAN_ID 2 /* Set flag if VLAN IDs are extracted
from received packets and eth protocol
is still ETH_P_8021Q */
+#define LRO_F_NI 4 /* If not NAPI, Pass packets to stack via NI */
/*
* Set for generated SKBs that are not added to
@@ -122,6 +123,50 @@ struct net_lro_mgr {
};
/*
+ * Large Receive Offload (LRO) information provided by the driver
+ *
+ * Fields must be set by driver when using the lro_receive_skb_ext()
+ */
+struct net_lro_info {
+ /* bitmask indicating the supported fields */
+ unsigned long valid_fields;
+ /*
+ * Driver has checked the LRO eligibilty of the skb
+ */
+ #define LRO_ELIGIBILITY_CHECKED (1 << 0)
+ /*
+ * Driver has provided the TCP payload checksum
+ */
+ #define LRO_TCP_DATA_CSUM (1 << 1)
+ /*
+ * Driver has extracted the TCP window from the skb
+ * The value is in network format
+ */
+ #define LRO_TCP_WIN (1 << 2)
+ /*
+ * Driver has extracted the TCP sequence number from skb
+ * The value is in network format
+ */
+ #define LRO_TCP_SEQ_NUM (1 << 3)
+ /*
+ * Driver has extracted the TCP ack number from the skb
+ * The value is in network format
+ */
+ #define LRO_TCP_ACK_NUM (1 << 4)
+ /*
+ * Driver has provided the LRO descriptor
+ */
+ #define LRO_DESC (1 << 5)
+
+ bool lro_eligible;
+ __wsum tcp_data_csum;
+ __be16 tcp_win;
+ __be32 tcp_seq_num;
+ __be32 tcp_ack_num;
+ struct net_lro_desc *lro_desc;
+};
+
+/*
* Processes a SKB
*
* @lro_mgr: LRO manager to use
@@ -133,10 +178,54 @@ struct net_lro_mgr {
void lro_receive_skb(struct net_lro_mgr *lro_mgr,
struct sk_buff *skb,
void *priv);
+
+/*
+ * Processes an SKB
+ *
+ * This API provides means to pass any LRO information that has already
+ * been extracted by the driver
+ *
+ * @lro_mgr: LRO manager to use
+ * @skb: SKB to aggregate
+ * @priv: Private data that may be used by driver functions
+ * (for example get_tcp_ip_hdr)
+ * @lro_info: LRO information extracted by the driver
+ */
+
+void lro_receive_skb_ext(struct net_lro_mgr *lro_mgr,
+ struct sk_buff *skb,
+ void *priv,
+ struct net_lro_info *lro_info);
+
+/*
+ * Processes a fragment list
+ *
+ * This functions aggregate fragments and generate SKBs do pass
+ * the packets to the stack.
+ *
+ * @lro_mgr: LRO manager to use
+ * @frags: Fragment to be processed. Must contain entire header in first
+ * element.
+ * @len: Length of received data
+ * @true_size: Actual size of memory the fragment is consuming
+ * @priv: Private data that may be used by driver functions
+ * (for example get_tcp_ip_hdr)
+ */
+
+void lro_receive_frags(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size, void *priv, __wsum sum);
+
/*
* Forward all aggregated SKBs held by lro_mgr to network stack
*/
void lro_flush_all(struct net_lro_mgr *lro_mgr);
+void lro_flush_pkt(struct net_lro_mgr *lro_mgr,
+ struct iphdr *iph, struct tcphdr *tcph);
+
+void lro_flush_desc(struct net_lro_mgr *lro_mgr,
+ struct net_lro_desc *lro_desc);
+
#endif
diff --git a/include/linux/leds-qpnp-flash-v2.h b/include/linux/leds-qpnp-flash-v2.h
index ae36a163ed21..47fd0699a9c1 100644
--- a/include/linux/leds-qpnp-flash-v2.h
+++ b/include/linux/leds-qpnp-flash-v2.h
@@ -16,30 +16,9 @@
#include <linux/leds.h>
#include "leds.h"
-/*
- * Configurations for each individual LED
- */
-struct flash_node_data {
- struct platform_device *pdev;
- struct led_classdev cdev;
- struct pinctrl *pinctrl;
- struct pinctrl_state *gpio_state_active;
- struct pinctrl_state *gpio_state_suspend;
- int ires_ua;
- int max_current;
- int current_ma;
- u8 duration;
- u8 id;
- u8 type;
- u8 ires;
- u8 hdrm_val;
- u8 current_reg_val;
- bool led_on;
-};
+#define ENABLE_REGULATOR BIT(0)
+#define QUERY_MAX_CURRENT BIT(1)
-struct flash_switch_data {
- struct platform_device *pdev;
- struct led_classdev cdev;
-};
+int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options);
#endif
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 61a5c00e66cd..06dd540192c7 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1482,6 +1482,7 @@ struct task_struct {
u32 init_load_pct;
u64 last_wake_ts;
u64 last_switch_out_ts;
+ u64 last_cpu_selected_ts;
struct related_thread_group *grp;
struct list_head grp_list;
u64 cpu_cycles;
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 647ebfe5174f..4984d372b04b 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -17,7 +17,7 @@
#include <linux/poll.h>
#include <linux/dma-buf.h>
-#define VB2_MAX_FRAME (32)
+#define VB2_MAX_FRAME (64)
#define VB2_MAX_PLANES (8)
enum vb2_memory {
diff --git a/include/net/cnss.h b/include/net/cnss.h
index 78d68fd22ded..ab9b50100504 100644
--- a/include/net/cnss.h
+++ b/include/net/cnss.h
@@ -15,7 +15,6 @@
#include <linux/device.h>
#include <linux/skbuff.h>
#include <linux/pci.h>
-#include <net/cnss_common.h>
#include <linux/mmc/sdio_func.h>
#ifdef CONFIG_CNSS
@@ -212,4 +211,35 @@ extern int cnss_wlan_query_oob_status(void);
extern int cnss_wlan_register_oob_irq_handler(oob_irq_handler_t handler,
void *pm_oob);
extern int cnss_wlan_unregister_oob_irq_handler(void *pm_oob);
+
+
+extern void cnss_dump_stack(struct task_struct *task);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
+extern void cnss_init_work(struct work_struct *work, work_func_t func);
+extern void cnss_flush_delayed_work(void *dwork);
+extern void cnss_flush_work(void *work);
+extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec);
+extern void cnss_pm_wake_lock_release(struct wakeup_source *ws);
+extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws);
+extern void cnss_get_monotonic_boottime(struct timespec *ts);
+extern void cnss_get_boottime(struct timespec *ts);
+extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t
+ func);
+extern int cnss_vendor_cmd_reply(struct sk_buff *skb);
+extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu);
+extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count);
+extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 *ch_count,
+ u16 buf_len);
+extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len);
+extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len);
+extern int cnss_common_request_bus_bandwidth(struct device *dev, int
+ bandwidth);
+extern void cnss_common_device_crashed(struct device *dev);
+extern void cnss_common_device_self_recovery(struct device *dev);
+extern void *cnss_common_get_virt_ramdump_mem(struct device *dev, unsigned long
+ *size);
+extern void cnss_common_schedule_recovery_work(struct device *dev);
+extern int cnss_common_set_wlan_mac_address(struct device *dev, const u8 *in,
+ uint32_t len);
+extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
#endif /* _NET_CNSS_H_ */
diff --git a/include/net/cnss_common.h b/include/net/cnss_common.h
deleted file mode 100644
index c5175a190b37..000000000000
--- a/include/net/cnss_common.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* Copyright (c) 2016, 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 _NET_CNSS_COMMON_H_
-#define _NET_CNSS_COMMON_H_
-
-#ifdef CONFIG_CNSS
-
-#define MAX_FIRMWARE_SIZE (1 * 1024 * 1024)
-/* max 20mhz channel count */
-#define CNSS_MAX_CH_NUM 45
-
-extern int cnss_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count);
-extern int cnss_get_wlan_unsafe_channel(u16 *unsafe_ch_list,
- u16 *ch_count, u16 buf_len);
-
-extern int cnss_wlan_set_dfs_nol(const void *info, u16 info_len);
-extern int cnss_wlan_get_dfs_nol(void *info, u16 info_len);
-
-extern void cnss_init_work(struct work_struct *work, work_func_t func);
-extern void cnss_flush_work(void *work);
-extern void cnss_flush_delayed_work(void *dwork);
-extern void cnss_pm_wake_lock_timeout(struct wakeup_source *ws, ulong msec);
-extern void cnss_pm_wake_lock_release(struct wakeup_source *ws);
-extern void cnss_pm_wake_lock_destroy(struct wakeup_source *ws);
-extern void cnss_get_monotonic_boottime(struct timespec *ts);
-extern void cnss_get_boottime(struct timespec *ts);
-extern void cnss_init_delayed_work(struct delayed_work *work, work_func_t func);
-extern int cnss_vendor_cmd_reply(struct sk_buff *skb);
-extern int cnss_set_cpus_allowed_ptr(struct task_struct *task, ulong cpu);
-extern void cnss_dump_stack(struct task_struct *task);
-
-int cnss_pci_request_bus_bandwidth(int bandwidth);
-int cnss_sdio_request_bus_bandwidth(int bandwidth);
-extern int cnss_common_request_bus_bandwidth(struct device *dev,
- int bandwidth);
-
-void cnss_sdio_device_crashed(void);
-void cnss_pci_device_crashed(void);
-extern void cnss_common_device_crashed(struct device *dev);
-
-void cnss_pci_device_self_recovery(void);
-void cnss_sdio_device_self_recovery(void);
-extern void cnss_common_device_self_recovery(struct device *dev);
-
-void *cnss_pci_get_virt_ramdump_mem(unsigned long *size);
-void *cnss_sdio_get_virt_ramdump_mem(unsigned long *size);
-extern void *cnss_common_get_virt_ramdump_mem(struct device *dev,
- unsigned long *size);
-
-void cnss_sdio_schedule_recovery_work(void);
-void cnss_pci_schedule_recovery_work(void);
-extern void cnss_common_schedule_recovery_work(struct device *dev);
-
-extern int cnss_pcie_set_wlan_mac_address(const u8 *in, uint32_t len);
-extern int cnss_sdio_set_wlan_mac_address(const u8 *in, uint32_t len);
-extern int cnss_common_set_wlan_mac_address(struct device *dev,
- const u8 *in, uint32_t len);
-
-u8 *cnss_pci_get_wlan_mac_address(uint32_t *num);
-u8 *cnss_sdio_get_wlan_mac_address(uint32_t *num);
-extern u8 *cnss_common_get_wlan_mac_address(struct device *dev, uint32_t *num);
-#endif
-#endif /* _NET_CNSS_COMMON_H_ */
diff --git a/include/soc/qcom/clock-local2.h b/include/soc/qcom/clock-local2.h
index 7f785cf4d3a2..4f2fa36e920f 100644
--- a/include/soc/qcom/clock-local2.h
+++ b/include/soc/qcom/clock-local2.h
@@ -255,6 +255,7 @@ extern struct clk_ops clk_ops_branch_hw_ctl;
extern struct clk_ops clk_ops_vote;
extern struct clk_ops clk_ops_rcg_hdmi;
extern struct clk_ops clk_ops_rcg_edp;
+extern struct clk_ops clk_ops_rcg_dp;
extern struct clk_ops clk_ops_byte;
extern struct clk_ops clk_ops_pixel;
extern struct clk_ops clk_ops_byte_multiparent;
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index c7bb78a0d57b..46b0402a730f 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -70,7 +70,7 @@
* Common stuff for both V4L1 and V4L2
* Moved from videodev.h
*/
-#define VIDEO_MAX_FRAME 32
+#define VIDEO_MAX_FRAME 64
#define VIDEO_MAX_PLANES 8
/*
diff --git a/include/uapi/media/msm_sde_rotator.h b/include/uapi/media/msm_sde_rotator.h
index d771959f2e03..461a171a42c1 100644
--- a/include/uapi/media/msm_sde_rotator.h
+++ b/include/uapi/media/msm_sde_rotator.h
@@ -13,9 +13,23 @@
#define SDE_PIX_FMT_BGRA_8888 V4L2_PIX_FMT_ARGB32
#define SDE_PIX_FMT_RGBX_8888 v4l2_fourcc('X', 'B', '2', '4')
#define SDE_PIX_FMT_BGRX_8888 V4L2_PIX_FMT_XRGB32
+#define SDE_PIX_FMT_XBGR_8888 v4l2_fourcc('R', 'X', '2', '4')
#define SDE_PIX_FMT_RGBA_5551 v4l2_fourcc('R', 'A', '1', '5')
+#define SDE_PIX_FMT_ARGB_1555 V4L2_PIX_FMT_ARGB555
+#define SDE_PIX_FMT_ABGR_1555 v4l2_fourcc('A', 'B', '1', '5')
+#define SDE_PIX_FMT_BGRA_5551 v4l2_fourcc('B', 'A', '1', '5')
+#define SDE_PIX_FMT_BGRX_5551 v4l2_fourcc('B', 'X', '1', '5')
+#define SDE_PIX_FMT_RGBX_5551 v4l2_fourcc('R', 'X', '1', '5')
+#define SDE_PIX_FMT_XBGR_1555 v4l2_fourcc('X', 'B', '1', '5')
+#define SDE_PIX_FMT_XRGB_1555 V4L2_PIX_FMT_XRGB555
#define SDE_PIX_FMT_ARGB_4444 V4L2_PIX_FMT_ARGB444
#define SDE_PIX_FMT_RGBA_4444 v4l2_fourcc('R', 'A', '1', '2')
+#define SDE_PIX_FMT_BGRA_4444 v4l2_fourcc('B', 'A', '1', '2')
+#define SDE_PIX_FMT_ABGR_4444 v4l2_fourcc('A', 'B', '1', '2')
+#define SDE_PIX_FMT_RGBX_4444 v4l2_fourcc('R', 'X', '1', '2')
+#define SDE_PIX_FMT_XRGB_4444 V4L2_PIX_FMT_XRGB444
+#define SDE_PIX_FMT_BGRX_4444 v4l2_fourcc('B', 'X', '1', '2')
+#define SDE_PIX_FMT_XBGR_4444 v4l2_fourcc('X', 'B', '1', '2')
#define SDE_PIX_FMT_RGB_888 V4L2_PIX_FMT_RGB24
#define SDE_PIX_FMT_BGR_888 V4L2_PIX_FMT_BGR24
#define SDE_PIX_FMT_RGB_565 V4L2_PIX_FMT_RGB565
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 2fd5c5688dd0..631dbb0a7041 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3056,6 +3056,7 @@ static inline void mark_task_starting(struct task_struct *p)
wallclock = sched_ktime_clock();
p->ravg.mark_start = p->last_wake_ts = wallclock;
+ p->last_cpu_selected_ts = wallclock;
p->last_switch_out_ts = 0;
update_task_cpu_cycles(p, cpu_of(rq));
}
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index b9ee3dc4a1a6..859416724e5a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2678,6 +2678,9 @@ static unsigned int __read_mostly
sched_short_sleep_task_threshold = 2000 * NSEC_PER_USEC;
unsigned int __read_mostly sysctl_sched_select_prev_cpu_us = 2000;
+static unsigned int __read_mostly
+sched_long_cpu_selection_threshold = 100 * NSEC_PER_MSEC;
+
unsigned int __read_mostly sysctl_sched_restrict_cluster_spill;
void update_up_down_migrate(void)
@@ -3455,6 +3458,7 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats)
struct sched_cluster *cluster;
if (env->boost_type != SCHED_BOOST_NONE || env->reason ||
+ !task->ravg.mark_start ||
env->need_idle || !sched_short_sleep_task_threshold)
return false;
@@ -3463,6 +3467,10 @@ bias_to_prev_cpu(struct cpu_select_env *env, struct cluster_cpu_stats *stats)
unlikely(!cpu_active(prev_cpu)))
return false;
+ if (task->ravg.mark_start - task->last_cpu_selected_ts >=
+ sched_long_cpu_selection_threshold)
+ return false;
+
/*
* This function should be used by task wake up path only as it's
* assuming p->last_switch_out_ts as last sleep time.
@@ -3604,6 +3612,7 @@ retry:
if (stats.best_capacity_cpu >= 0)
target = stats.best_capacity_cpu;
}
+ p->last_cpu_selected_ts = sched_ktime_clock();
out:
rcu_read_unlock();
diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c
index f17ea49b28fb..8f26145c34e2 100644
--- a/net/ipv4/inet_lro.c
+++ b/net/ipv4/inet_lro.c
@@ -145,20 +145,37 @@ static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len)
}
static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
- struct iphdr *iph, struct tcphdr *tcph)
+ struct iphdr *iph, struct tcphdr *tcph,
+ struct net_lro_info *lro_info)
{
int nr_frags;
__be32 *ptr;
u32 tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
+ u64 hw_marked = 0;
+
+ if (lro_info)
+ hw_marked = lro_info->valid_fields;
nr_frags = skb_shinfo(skb)->nr_frags;
lro_desc->parent = skb;
lro_desc->next_frag = &(skb_shinfo(skb)->frags[nr_frags]);
lro_desc->iph = iph;
lro_desc->tcph = tcph;
- lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len;
- lro_desc->tcp_ack = tcph->ack_seq;
- lro_desc->tcp_window = tcph->window;
+
+ if (hw_marked & LRO_TCP_SEQ_NUM)
+ lro_desc->tcp_next_seq = lro_info->tcp_seq_num + tcp_data_len;
+ else
+ lro_desc->tcp_next_seq = ntohl(tcph->seq) + tcp_data_len;
+
+ if (hw_marked & LRO_TCP_ACK_NUM)
+ lro_desc->tcp_ack = htonl(lro_info->tcp_ack_num);
+ else
+ lro_desc->tcp_ack = tcph->ack_seq;
+
+ if (hw_marked & LRO_TCP_WIN)
+ lro_desc->tcp_window = htons(lro_info->tcp_win);
+ else
+ lro_desc->tcp_window = tcph->window;
lro_desc->pkt_aggr_cnt = 1;
lro_desc->ip_tot_len = ntohs(iph->tot_len);
@@ -173,8 +190,11 @@ static void lro_init_desc(struct net_lro_desc *lro_desc, struct sk_buff *skb,
lro_desc->mss = tcp_data_len;
lro_desc->active = 1;
- lro_desc->data_csum = lro_tcp_data_csum(iph, tcph,
- tcp_data_len);
+ if (hw_marked & LRO_TCP_DATA_CSUM)
+ lro_desc->data_csum = lro_info->tcp_data_csum;
+ else
+ lro_desc->data_csum = lro_tcp_data_csum(iph, tcph,
+ tcp_data_len);
}
static inline void lro_clear_desc(struct net_lro_desc *lro_desc)
@@ -183,16 +203,29 @@ static inline void lro_clear_desc(struct net_lro_desc *lro_desc)
}
static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
- struct tcphdr *tcph, int tcp_data_len)
+ struct tcphdr *tcph, int tcp_data_len,
+ struct net_lro_info *lro_info)
{
struct sk_buff *parent = lro_desc->parent;
__be32 *topt;
+ u64 hw_marked = 0;
+
+ if (lro_info)
+ hw_marked = lro_info->valid_fields;
lro_desc->pkt_aggr_cnt++;
lro_desc->ip_tot_len += tcp_data_len;
lro_desc->tcp_next_seq += tcp_data_len;
- lro_desc->tcp_window = tcph->window;
- lro_desc->tcp_ack = tcph->ack_seq;
+
+ if (hw_marked & LRO_TCP_WIN)
+ lro_desc->tcp_window = htons(lro_info->tcp_win);
+ else
+ lro_desc->tcp_window = tcph->window;
+
+ if (hw_marked & LRO_TCP_ACK_NUM)
+ lro_desc->tcp_ack = htonl(lro_info->tcp_ack_num);
+ else
+ lro_desc->tcp_ack = tcph->ack_seq;
/* don't update tcp_rcv_tsval, would not work with PAWS */
if (lro_desc->tcp_saw_tstamp) {
@@ -200,10 +233,17 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
lro_desc->tcp_rcv_tsecr = *(topt + 2);
}
- lro_desc->data_csum = csum_block_add(lro_desc->data_csum,
- lro_tcp_data_csum(iph, tcph,
- tcp_data_len),
- parent->len);
+ if (hw_marked & LRO_TCP_DATA_CSUM)
+ lro_desc->data_csum = csum_block_add(lro_desc->data_csum,
+ lro_info->tcp_data_csum,
+ parent->len);
+ else
+ lro_desc->data_csum =
+ csum_block_add(lro_desc->data_csum,
+ lro_tcp_data_csum(iph,
+ tcph,
+ tcp_data_len),
+ parent->len);
parent->len += tcp_data_len;
parent->data_len += tcp_data_len;
@@ -212,12 +252,13 @@ static void lro_add_common(struct net_lro_desc *lro_desc, struct iphdr *iph,
}
static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb,
- struct iphdr *iph, struct tcphdr *tcph)
+ struct iphdr *iph, struct tcphdr *tcph,
+ struct net_lro_info *lro_info)
{
struct sk_buff *parent = lro_desc->parent;
int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
- lro_add_common(lro_desc, iph, tcph, tcp_data_len);
+ lro_add_common(lro_desc, iph, tcph, tcp_data_len, lro_info);
skb_pull(skb, (skb->len - tcp_data_len));
parent->truesize += skb->truesize;
@@ -230,6 +271,29 @@ static void lro_add_packet(struct net_lro_desc *lro_desc, struct sk_buff *skb,
lro_desc->last_skb = skb;
}
+static void lro_add_frags(struct net_lro_desc *lro_desc,
+ int len, int hlen, int truesize,
+ struct skb_frag_struct *skb_frags,
+ struct iphdr *iph, struct tcphdr *tcph)
+{
+ struct sk_buff *skb = lro_desc->parent;
+ int tcp_data_len = TCP_PAYLOAD_LENGTH(iph, tcph);
+
+ lro_add_common(lro_desc, iph, tcph, tcp_data_len, NULL);
+
+ skb->truesize += truesize;
+
+ skb_frags[0].page_offset += hlen;
+ skb_frag_size_sub(&skb_frags[0], hlen);
+
+ while (tcp_data_len > 0) {
+ *lro_desc->next_frag = *skb_frags;
+ tcp_data_len -= skb_frag_size(skb_frags);
+ lro_desc->next_frag++;
+ skb_frags++;
+ skb_shinfo(skb)->nr_frags++;
+ }
+}
static int lro_check_tcp_conn(struct net_lro_desc *lro_desc,
struct iphdr *iph,
@@ -284,6 +348,8 @@ static void lro_flush(struct net_lro_mgr *lro_mgr,
if (lro_mgr->features & LRO_F_NAPI)
netif_receive_skb(lro_desc->parent);
+ else if (lro_mgr->features & LRO_F_NI)
+ netif_rx_ni(lro_desc->parent);
else
netif_rx(lro_desc->parent);
@@ -292,12 +358,13 @@ static void lro_flush(struct net_lro_mgr *lro_mgr,
}
static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
- void *priv)
+ void *priv, struct net_lro_info *lro_info)
{
struct net_lro_desc *lro_desc;
struct iphdr *iph;
struct tcphdr *tcph;
u64 flags;
+ u64 hw_marked = 0;
int vlan_hdr_len = 0;
if (!lro_mgr->get_skb_header ||
@@ -308,7 +375,14 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
if (!(flags & LRO_IPV4) || !(flags & LRO_TCP))
goto out;
- lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
+ if (lro_info)
+ hw_marked = lro_info->valid_fields;
+
+ if (hw_marked & LRO_DESC)
+ lro_desc = lro_info->lro_desc;
+ else
+ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
+
if (!lro_desc)
goto out;
@@ -317,22 +391,38 @@ static int __lro_proc_skb(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
vlan_hdr_len = VLAN_HLEN;
if (!lro_desc->active) { /* start new lro session */
- if (lro_tcp_ip_check(iph, tcph, skb->len - vlan_hdr_len, NULL))
- goto out;
+ if (hw_marked & LRO_ELIGIBILITY_CHECKED) {
+ if (!lro_info->lro_eligible)
+ goto out;
+ } else {
+ if (lro_tcp_ip_check(iph, tcph,
+ skb->len - vlan_hdr_len, NULL))
+ goto out;
+ }
skb->ip_summed = lro_mgr->ip_summed_aggr;
- lro_init_desc(lro_desc, skb, iph, tcph);
+ lro_init_desc(lro_desc, skb, iph, tcph, lro_info);
LRO_INC_STATS(lro_mgr, aggregated);
return 0;
}
- if (lro_desc->tcp_next_seq != ntohl(tcph->seq))
- goto out2;
+ if (hw_marked & LRO_TCP_SEQ_NUM) {
+ if (lro_desc->tcp_next_seq != lro_info->tcp_seq_num)
+ goto out2;
+ } else {
+ if (lro_desc->tcp_next_seq != ntohl(tcph->seq))
+ goto out2;
+ }
- if (lro_tcp_ip_check(iph, tcph, skb->len, lro_desc))
- goto out2;
+ if (hw_marked & LRO_ELIGIBILITY_CHECKED) {
+ if (!lro_info->lro_eligible)
+ goto out2;
+ } else {
+ if (lro_tcp_ip_check(iph, tcph, skb->len, lro_desc))
+ goto out2;
+ }
- lro_add_packet(lro_desc, skb, iph, tcph);
+ lro_add_packet(lro_desc, skb, iph, tcph, lro_info);
LRO_INC_STATS(lro_mgr, aggregated);
if ((lro_desc->pkt_aggr_cnt >= lro_mgr->max_aggr) ||
@@ -348,19 +438,161 @@ out:
return 1;
}
+static struct sk_buff *lro_gen_skb(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size,
+ void *mac_hdr,
+ int hlen, __wsum sum,
+ u32 ip_summed)
+{
+ struct sk_buff *skb;
+ struct skb_frag_struct *skb_frags;
+ int data_len = len;
+ int hdr_len = min(len, hlen);
+
+ skb = netdev_alloc_skb(lro_mgr->dev, hlen + lro_mgr->frag_align_pad);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, lro_mgr->frag_align_pad);
+ skb->len = len;
+ skb->data_len = len - hdr_len;
+ skb->truesize += true_size;
+ skb->tail += hdr_len;
+
+ memcpy(skb->data, mac_hdr, hdr_len);
+
+ skb_frags = skb_shinfo(skb)->frags;
+ while (data_len > 0) {
+ *skb_frags = *frags;
+ data_len -= skb_frag_size(frags);
+ skb_frags++;
+ frags++;
+ skb_shinfo(skb)->nr_frags++;
+ }
+
+ skb_shinfo(skb)->frags[0].page_offset += hdr_len;
+ skb_frag_size_sub(&skb_shinfo(skb)->frags[0], hdr_len);
+
+ skb->ip_summed = ip_summed;
+ skb->csum = sum;
+ skb->protocol = eth_type_trans(skb, lro_mgr->dev);
+ return skb;
+}
+
+static struct sk_buff *__lro_proc_segment(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size,
+ void *priv, __wsum sum)
+{
+ struct net_lro_desc *lro_desc;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ struct sk_buff *skb;
+ u64 flags;
+ void *mac_hdr;
+ int mac_hdr_len;
+ int hdr_len = LRO_MAX_PG_HLEN;
+ int vlan_hdr_len = 0;
+
+ if (!lro_mgr->get_frag_header ||
+ lro_mgr->get_frag_header(frags, (void *)&mac_hdr, (void *)&iph,
+ (void *)&tcph, &flags, priv)) {
+ mac_hdr = skb_frag_address(frags);
+ goto out1;
+ }
+
+ if (!(flags & LRO_IPV4) || !(flags & LRO_TCP))
+ goto out1;
+
+ hdr_len = (int)((void *)(tcph) + TCP_HDR_LEN(tcph) - mac_hdr);
+ mac_hdr_len = (int)((void *)(iph) - mac_hdr);
+
+ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
+ if (!lro_desc)
+ goto out1;
+
+ if (!lro_desc->active) { /* start new lro session */
+ if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, NULL))
+ goto out1;
+
+ skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr,
+ hdr_len, 0, lro_mgr->ip_summed_aggr);
+ if (!skb)
+ goto out;
+
+ if ((skb->protocol == htons(ETH_P_8021Q)) &&
+ !(lro_mgr->features & LRO_F_EXTRACT_VLAN_ID))
+ vlan_hdr_len = VLAN_HLEN;
+
+ iph = (void *)(skb->data + vlan_hdr_len);
+ tcph = (void *)((u8 *)skb->data + vlan_hdr_len
+ + IP_HDR_LEN(iph));
+
+ lro_init_desc(lro_desc, skb, iph, tcph, NULL);
+ LRO_INC_STATS(lro_mgr, aggregated);
+ return NULL;
+ }
+
+ if (lro_desc->tcp_next_seq != ntohl(tcph->seq))
+ goto out2;
+
+ if (lro_tcp_ip_check(iph, tcph, len - mac_hdr_len, lro_desc))
+ goto out2;
+
+ lro_add_frags(lro_desc, len, hdr_len, true_size, frags, iph, tcph);
+ LRO_INC_STATS(lro_mgr, aggregated);
+
+ if ((skb_shinfo(lro_desc->parent)->nr_frags >= lro_mgr->max_aggr) ||
+ lro_desc->parent->len > (0xFFFF - lro_mgr->dev->mtu))
+ lro_flush(lro_mgr, lro_desc);
+
+ return NULL;
+
+out2: /* send aggregated packets to the stack */
+ lro_flush(lro_mgr, lro_desc);
+
+out1: /* Original packet has to be posted to the stack */
+ skb = lro_gen_skb(lro_mgr, frags, len, true_size, mac_hdr,
+ hdr_len, sum, lro_mgr->ip_summed);
+out:
+ return skb;
+}
+
void lro_receive_skb(struct net_lro_mgr *lro_mgr,
struct sk_buff *skb,
void *priv)
{
- if (__lro_proc_skb(lro_mgr, skb, priv)) {
+ if (__lro_proc_skb(lro_mgr, skb, priv, NULL)) {
if (lro_mgr->features & LRO_F_NAPI)
netif_receive_skb(skb);
+ else if (lro_mgr->features & LRO_F_NI)
+ netif_rx_ni(skb);
else
netif_rx(skb);
}
}
EXPORT_SYMBOL(lro_receive_skb);
+void lro_receive_frags(struct net_lro_mgr *lro_mgr,
+ struct skb_frag_struct *frags,
+ int len, int true_size, void *priv, __wsum sum)
+{
+ struct sk_buff *skb;
+
+ skb = __lro_proc_segment(lro_mgr, frags, len, true_size, priv, sum);
+ if (!skb)
+ return;
+
+ if (lro_mgr->features & LRO_F_NAPI)
+ netif_receive_skb(skb);
+ else if (lro_mgr->features & LRO_F_NI)
+ netif_rx_ni(skb);
+ else
+ netif_rx(skb);
+}
+EXPORT_SYMBOL(lro_receive_frags);
+
void lro_flush_all(struct net_lro_mgr *lro_mgr)
{
int i;
@@ -372,3 +604,35 @@ void lro_flush_all(struct net_lro_mgr *lro_mgr)
}
}
EXPORT_SYMBOL(lro_flush_all);
+
+void lro_flush_pkt(struct net_lro_mgr *lro_mgr, struct iphdr *iph,
+ struct tcphdr *tcph)
+{
+ struct net_lro_desc *lro_desc;
+
+ lro_desc = lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph);
+ if (lro_desc && lro_desc->active)
+ lro_flush(lro_mgr, lro_desc);
+}
+EXPORT_SYMBOL(lro_flush_pkt);
+
+void lro_flush_desc(struct net_lro_mgr *lro_mgr, struct net_lro_desc *lro_desc)
+{
+ if (lro_desc->active)
+ lro_flush(lro_mgr, lro_desc);
+}
+EXPORT_SYMBOL(lro_flush_desc);
+
+void lro_receive_skb_ext(struct net_lro_mgr *lro_mgr, struct sk_buff *skb,
+ void *priv, struct net_lro_info *lro_info)
+{
+ if (__lro_proc_skb(lro_mgr, skb, priv, lro_info)) {
+ if (lro_mgr->features & LRO_F_NAPI)
+ netif_receive_skb(skb);
+ else if (lro_mgr->features & LRO_F_NI)
+ netif_rx_ni(skb);
+ else
+ netif_rx(skb);
+ }
+}
+EXPORT_SYMBOL(lro_receive_skb_ext);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 816c9075ba3c..ad4b729262fd 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3456,16 +3456,16 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
params.smps_mode = NL80211_SMPS_OFF;
}
+ params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
+ if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ])
+ return -EOPNOTSUPP;
+
if (info->attrs[NL80211_ATTR_ACL_POLICY]) {
params.acl = parse_acl_data(&rdev->wiphy, info);
if (IS_ERR(params.acl))
return PTR_ERR(params.acl);
}
- params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
- if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ])
- return -EOPNOTSUPP;
-
wdev_lock(wdev);
err = rdev_start_ap(rdev, dev, &params);
if (!err) {
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 913bc0e06098..2963d00ea6e5 100755
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -967,7 +967,7 @@ config SND_SOC_MSM_STUB
config SND_SOC_MSM_HDMI_CODEC_RX
bool "HDMI Audio Playback"
- depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996)
+ depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSMCOBALT)
help
HDMI audio drivers should be built only if the platform
supports hdmi panel.
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index f496559f0632..d8787ed249db 100755
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -349,6 +349,12 @@ enum {
CPE_NOMINAL,
HPH_PA_DELAY,
SB_CLK_GEAR,
+ ANC_MIC_AMIC1,
+ ANC_MIC_AMIC2,
+ ANC_MIC_AMIC3,
+ ANC_MIC_AMIC4,
+ ANC_MIC_AMIC5,
+ ANC_MIC_AMIC6,
};
enum {
@@ -576,6 +582,7 @@ static struct snd_soc_dai_driver tasha_dai[];
static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv);
static int tasha_config_compander(struct snd_soc_codec *, int, int);
+static void tasha_codec_set_tx_hold(struct snd_soc_codec *, u16, bool);
/* Hold instance to soundwire platform device */
struct tasha_swr_ctrl_data {
@@ -3775,7 +3782,7 @@ static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w,
WCD9335_CDC_ANC0_IIR_COEFF_2_CTL);
anc_writes_size = anc_cal_size / 2;
snd_soc_update_bits(codec,
- WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x38);
+ WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x39, 0x39);
} else if (!strcmp(w->name, "RX INT2 DAC") ||
!strcmp(w->name, "RX INT4 DAC")) {
tasha_realign_anc_coeff(codec,
@@ -3783,7 +3790,7 @@ static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w,
WCD9335_CDC_ANC1_IIR_COEFF_2_CTL);
i = anc_cal_size / 2;
snd_soc_update_bits(codec,
- WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x38);
+ WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x39, 0x39);
}
for (; i < anc_writes_size; i++) {
@@ -3793,16 +3800,23 @@ static int tasha_codec_enable_anc(struct snd_soc_dapm_widget *w,
if (!strcmp(w->name, "RX INT1 DAC") ||
!strcmp(w->name, "RX INT3 DAC")) {
snd_soc_update_bits(codec,
- WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x38, 0x00);
+ WCD9335_CDC_ANC0_CLK_RESET_CTL, 0x08, 0x08);
} else if (!strcmp(w->name, "RX INT2 DAC") ||
!strcmp(w->name, "RX INT4 DAC")) {
snd_soc_update_bits(codec,
- WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x38, 0x00);
+ WCD9335_CDC_ANC1_CLK_RESET_CTL, 0x08, 0x08);
}
if (!hwdep_cal)
release_firmware(fw);
break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* Remove ANC Rx from reset */
+ snd_soc_update_bits(codec, WCD9335_CDC_ANC0_CLK_RESET_CTL,
+ 0x08, 0x00);
+ snd_soc_update_bits(codec, WCD9335_CDC_ANC1_CLK_RESET_CTL,
+ 0x08, 0x00);
+ break;
case SND_SOC_DAPM_POST_PMD:
if (!strcmp(w->name, "ANC HPHL PA") ||
!strcmp(w->name, "ANC EAR PA") ||
@@ -3842,6 +3856,22 @@ err:
return ret;
}
+static void tasha_codec_clear_anc_tx_hold(struct tasha_priv *tasha)
+{
+ if (test_and_clear_bit(ANC_MIC_AMIC1, &tasha->status_mask))
+ tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC1, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC2, &tasha->status_mask))
+ tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC2, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC3, &tasha->status_mask))
+ tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC3, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC4, &tasha->status_mask))
+ tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC4, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC5, &tasha->status_mask))
+ tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC5, false);
+ if (test_and_clear_bit(ANC_MIC_AMIC6, &tasha->status_mask))
+ tasha_codec_set_tx_hold(tasha->codec, WCD9335_ANA_AMIC6, false);
+}
+
static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha,
int mode, int event)
{
@@ -3860,6 +3890,13 @@ static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha,
scale_val = 0x1;
break;
}
+ if (tasha->anc_func) {
+ /* Clear Tx FE HOLD if both PAs are enabled */
+ if ((snd_soc_read(tasha->codec, WCD9335_ANA_HPH) &
+ 0xC0) == 0xC0) {
+ tasha_codec_clear_anc_tx_hold(tasha);
+ }
+ }
break;
case SND_SOC_DAPM_PRE_PMD:
scale_val = 0x6;
@@ -3926,9 +3963,20 @@ static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if ((!(strcmp(w->name, "ANC HPHR PA"))) &&
+ (test_bit(HPH_PA_DELAY, &tasha->status_mask))) {
+ snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0xC0, 0xC0);
+ }
set_bit(HPH_PA_DELAY, &tasha->status_mask);
break;
case SND_SOC_DAPM_POST_PMU:
+ if ((snd_soc_read(codec, WCD9335_ANA_HPH) & 0xC0) != 0xC0)
+ /*
+ * If PA_EN is not set (potentially in ANC case) then
+ * do nothing for POST_PMU and let left channel handle
+ * everything.
+ */
+ break;
/*
* 7ms sleep is required after PA is enabled as per
* HW requirement
@@ -3946,13 +3994,31 @@ static int tasha_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec,
WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
0x10, 0x00);
+
+ if (!(strcmp(w->name, "ANC HPHR PA"))) {
+ /* Do everything needed for left channel */
+ snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CTL,
+ 0x10, 0x00);
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_read(codec,
+ WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) &
+ 0x10)
+ snd_soc_update_bits(codec,
+ WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+ 0x10, 0x00);
+ /* Remove ANC Rx from reset */
+ ret = tasha_codec_enable_anc(w, kcontrol, event);
+ }
tasha_codec_override(codec, hph_mode, event);
break;
+
case SND_SOC_DAPM_PRE_PMD:
blocking_notifier_call_chain(&tasha->notifier,
WCD_EVENT_PRE_HPHR_PA_OFF,
&tasha->mbhc);
tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
+ if (!(strcmp(w->name, "ANC HPHR PA")))
+ snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0x40, 0x00);
break;
case SND_SOC_DAPM_POST_PMD:
/* 5ms sleep is required after PA is disabled as per
@@ -3988,9 +4054,20 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
+ if ((!(strcmp(w->name, "ANC HPHL PA"))) &&
+ (test_bit(HPH_PA_DELAY, &tasha->status_mask))) {
+ snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0xC0, 0xC0);
+ }
set_bit(HPH_PA_DELAY, &tasha->status_mask);
break;
case SND_SOC_DAPM_POST_PMU:
+ if ((snd_soc_read(codec, WCD9335_ANA_HPH) & 0xC0) != 0xC0)
+ /*
+ * If PA_EN is not set (potentially in ANC case) then
+ * do nothing for POST_PMU and let right channel handle
+ * everything.
+ */
+ break;
/*
* 7ms sleep is required after PA is enabled as per
* HW requirement
@@ -4009,6 +4086,22 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec,
WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
0x10, 0x00);
+
+ if (!(strcmp(w->name, "ANC HPHL PA"))) {
+ /* Do everything needed for right channel */
+ snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_CTL,
+ 0x10, 0x00);
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_read(codec,
+ WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) &
+ 0x10)
+ snd_soc_update_bits(codec,
+ WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+ 0x10, 0x00);
+
+ /* Remove ANC Rx from reset */
+ ret = tasha_codec_enable_anc(w, kcontrol, event);
+ }
tasha_codec_override(codec, hph_mode, event);
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -4016,6 +4109,8 @@ static int tasha_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
WCD_EVENT_PRE_HPHL_PA_OFF,
&tasha->mbhc);
tasha_codec_hph_post_pa_config(tasha, hph_mode, event);
+ if (!(strcmp(w->name, "ANC HPHL PA")))
+ snd_soc_update_bits(codec, WCD9335_ANA_HPH, 0x80, 0x00);
break;
case SND_SOC_DAPM_POST_PMD:
/* 5ms sleep is required after PA is disabled as per
@@ -4083,6 +4178,9 @@ static int tasha_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec,
lineout_mix_vol_reg,
0x10, 0x00);
+ if (!(strcmp(w->name, "ANC LINEOUT1 PA")) ||
+ !(strcmp(w->name, "ANC LINEOUT2 PA")))
+ ret = tasha_codec_enable_anc(w, kcontrol, event);
tasha_codec_override(codec, CLS_AB, event);
break;
case SND_SOC_DAPM_POST_PMD:
@@ -5394,8 +5492,8 @@ static int tasha_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w,
{
int adc_mux_n = w->shift;
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
int amic_n;
- u16 amic_reg;
dev_dbg(codec->dev, "%s: event: %d\n", __func__, event);
@@ -5403,8 +5501,13 @@ static int tasha_codec_tx_adc_cfg(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
amic_n = tasha_codec_find_amic_input(codec, adc_mux_n);
if (amic_n) {
- amic_reg = WCD9335_ANA_AMIC1 + amic_n - 1;
- tasha_codec_set_tx_hold(codec, amic_reg, false);
+ /*
+ * Prevent ANC Rx pop by leaving Tx FE in HOLD
+ * state until PA is up. Track AMIC being used
+ * so we can release the HOLD later.
+ */
+ set_bit(ANC_MIC_AMIC1 + amic_n - 1,
+ &tasha->status_mask);
}
break;
default:
@@ -10512,11 +10615,11 @@ static const struct snd_soc_dapm_widget tasha_dapm_widgets[] = {
tasha_codec_enable_ear_pa,
SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("ANC HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0,
+ SND_SOC_DAPM_PGA_E("ANC HPHL PA", SND_SOC_NOPM, 0, 0, NULL, 0,
tasha_codec_enable_hphl_pa,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_PGA_E("ANC HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0,
+ SND_SOC_DAPM_PGA_E("ANC HPHR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
tasha_codec_enable_hphr_pa,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
diff --git a/sound/soc/msm/msmcobalt.c b/sound/soc/msm/msmcobalt.c
index e4ad523bacb7..955a886e3fdc 100644
--- a/sound/soc/msm/msmcobalt.c
+++ b/sound/soc/msm/msmcobalt.c
@@ -89,13 +89,7 @@ enum {
SLIM_TX_MAX,
};
-struct slim_ch_config {
- u32 sample_rate;
- u32 bit_format;
- u32 channels;
-};
-
-struct usb_be_config {
+struct dev_config {
u32 sample_rate;
u32 bit_format;
u32 channels;
@@ -122,7 +116,7 @@ struct msm_asoc_wcd93xx_codec {
};
/* Default configuration of slimbus channels */
-static struct slim_ch_config slim_rx_cfg[] = {
+static struct dev_config slim_rx_cfg[] = {
[SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
@@ -133,7 +127,7 @@ static struct slim_ch_config slim_rx_cfg[] = {
[SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
};
-static struct slim_ch_config slim_tx_cfg[] = {
+static struct dev_config slim_tx_cfg[] = {
[SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
@@ -145,18 +139,24 @@ static struct slim_ch_config slim_tx_cfg[] = {
[SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
};
-static struct usb_be_config usb_rx_cfg = {
+static struct dev_config usb_rx_cfg = {
.sample_rate = SAMPLING_RATE_48KHZ,
.bit_format = SNDRV_PCM_FORMAT_S16_LE,
.channels = 2,
};
-static struct usb_be_config usb_tx_cfg = {
+static struct dev_config usb_tx_cfg = {
.sample_rate = SAMPLING_RATE_48KHZ,
.bit_format = SNDRV_PCM_FORMAT_S16_LE,
.channels = 1,
};
+static struct dev_config hdmi_rx_cfg = {
+ .sample_rate = SAMPLING_RATE_48KHZ,
+ .bit_format = SNDRV_PCM_FORMAT_S16_LE,
+ .channels = 2,
+};
+
static int msm_vi_feed_tx_ch = 2;
static const char *const slim_rx_ch_text[] = {"One", "Two"};
static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four",
@@ -169,10 +169,14 @@ static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16",
"KHZ_96", "KHZ_192"};
static char const *bt_sco_sample_rate_text[] = {"KHZ_8", "KHZ_16"};
static const char *const usb_ch_text[] = {"One", "Two"};
+static char const *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+ "Six", "Seven", "Eight"};
static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025",
"KHZ_16", "KHZ_22P05",
"KHZ_32", "KHZ_44P1", "KHZ_48",
"KHZ_96", "KHZ_192"};
+static char const *hdmi_rx_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text);
@@ -182,12 +186,14 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_chs, hdmi_rx_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text);
@@ -195,6 +201,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(bt_sco_sample_rate, bt_sco_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(hdmi_rx_sample_rate, hdmi_rx_sample_rate_text);
static struct platform_device *spdev;
@@ -565,9 +572,9 @@ static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol,
if (ch_num < 0)
return ch_num;
- slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
+ slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1;
pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__,
- ch_num, slim_rx_cfg[ch_num].channels);
+ ch_num, slim_tx_cfg[ch_num].channels);
return 1;
}
@@ -914,6 +921,130 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol,
return rc;
}
+static int hdmi_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ switch (hdmi_rx_cfg.bit_format) {
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: hdmi_rx_cfg = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 1:
+ hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ hdmi_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: hdmi_rx_cfg.bit_format = %d, ucontrol value = %ld\n",
+ __func__, hdmi_rx_cfg.bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__,
+ hdmi_rx_cfg.channels);
+ ucontrol->value.integer.value[0] = hdmi_rx_cfg.channels - 2;
+
+ return 0;
+}
+
+static int hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ hdmi_rx_cfg.channels = ucontrol->value.integer.value[0] + 2;
+ if (hdmi_rx_cfg.channels > 8) {
+ pr_err("%s: channels %d exceeded 8.Limiting to max chs-8\n",
+ __func__, hdmi_rx_cfg.channels);
+ hdmi_rx_cfg.channels = 8;
+ }
+ pr_debug("%s: hdmi_rx_cfg.channels = %d\n", __func__,
+ hdmi_rx_cfg.channels);
+
+ return 1;
+}
+
+static int hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val = 0;
+
+ switch (hdmi_rx_cfg.sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: hdmi_rx_sample_rate = %d\n", __func__,
+ hdmi_rx_cfg.sample_rate);
+
+ return 0;
+}
+
+static int hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: ucontrol value = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ hdmi_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ hdmi_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ hdmi_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ;
+ }
+
+ pr_debug("%s: hdmi_rx_cfg.sample_rate = %d\n", __func__,
+ hdmi_rx_cfg.sample_rate);
+
+ return 0;
+}
+
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs,
msm_slim_rx_ch_get, msm_slim_rx_ch_put),
@@ -931,6 +1062,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
usb_audio_rx_ch_get, usb_audio_rx_ch_put),
SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
usb_audio_tx_ch_get, usb_audio_tx_ch_put),
+ SOC_ENUM_EXT("HDMI_RX Channels", hdmi_rx_chs,
+ hdmi_rx_ch_get, hdmi_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format,
slim_rx_bit_format_get, slim_rx_bit_format_put),
SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format,
@@ -943,6 +1076,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
usb_audio_rx_format_get, usb_audio_rx_format_put),
SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
usb_audio_tx_format_get, usb_audio_tx_format_put),
+ SOC_ENUM_EXT("HDMI_RX Bit Format", hdmi_rx_format,
+ hdmi_rx_format_get, hdmi_rx_format_put),
SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate,
slim_rx_sample_rate_get, slim_rx_sample_rate_put),
SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate,
@@ -960,6 +1095,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
usb_audio_tx_sample_rate_get,
usb_audio_tx_sample_rate_put),
+ SOC_ENUM_EXT("HDMI_RX SampleRate", hdmi_rx_sample_rate,
+ hdmi_rx_sample_rate_get,
+ hdmi_rx_sample_rate_put),
};
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec,
@@ -1147,6 +1285,15 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
channels->min = channels->max = usb_tx_cfg.channels;
break;
+ case MSM_BACKEND_DAI_HDMI_RX:
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ hdmi_rx_cfg.bit_format);
+ if (channels->max < 2)
+ channels->min = channels->max = 2;
+ rate->min = rate->max = hdmi_rx_cfg.sample_rate;
+ channels->min = channels->max = hdmi_rx_cfg.channels;
+ break;
+
default:
rate->min = rate->max = SAMPLING_RATE_48KHZ;
break;
@@ -1246,6 +1393,13 @@ static int msm_adsp_power_up_config(struct snd_soc_codec *codec)
pr_debug("%s: ADSP Audio is ready\n", __func__);
adsp_ready = 1;
break;
+ } else {
+ /*
+ * ADSP will be coming up after subsystem restart and
+ * it might not be fully up when the control reaches
+ * here. So, wait for 50msec before checking ADSP state
+ */
+ msleep(50);
}
} while (time_after(timeout, jiffies));
@@ -2761,12 +2915,31 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
},
};
+static struct snd_soc_dai_link hdmi_be_dai_link[] = {
+ /* HDMI BACK END DAI Link */
+ {
+ .name = LPASS_BE_HDMI,
+ .stream_name = "HDMI Playback",
+ .cpu_dai_name = "msm-dai-q6-hdmi.8",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-hdmi-audio-codec-rx",
+ .codec_dai_name = "msm_hdmi_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_HDMI_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_tasha_dai_links[
ARRAY_SIZE(msm_common_dai_links) +
ARRAY_SIZE(msm_tasha_fe_dai_links) +
ARRAY_SIZE(msm_common_be_dai_links) +
ARRAY_SIZE(msm_tasha_be_dai_links) +
- ARRAY_SIZE(msm_wcn_be_dai_links)];
+ ARRAY_SIZE(msm_wcn_be_dai_links) +
+ ARRAY_SIZE(hdmi_be_dai_link)];
static int msm_snd_card_late_probe(struct snd_soc_card *card)
{
@@ -3083,10 +3256,9 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
{
struct snd_soc_card *card = NULL;
struct snd_soc_dai_link *dailink;
- int len_1, len_2, len_3, len_4;
+ int len_1, len_2, len_3;
int total_links;
const struct of_device_id *match;
- bool use_wcn_btfm = false;
match = of_match_node(msmcobalt_asoc_machine_of_match, dev->of_node);
if (!match) {
@@ -3095,26 +3267,12 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
return NULL;
}
- if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
- use_wcn_btfm = true;
- dev_dbg(dev, "%s(): WCN BTFM support present\n", __func__);
- } else {
- dev_dbg(dev, "%s(): No WCN BTFM support\n", __func__);
- }
-
if (!strcmp(match->data, "tasha_codec")) {
card = &snd_soc_card_tasha_msm;
len_1 = ARRAY_SIZE(msm_common_dai_links);
len_2 = len_1 + ARRAY_SIZE(msm_tasha_fe_dai_links);
len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
- len_4 = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links);
- if (use_wcn_btfm) {
- total_links = len_4 +
- ARRAY_SIZE(msm_wcn_be_dai_links);
- } else {
- total_links = len_4;
- }
-
+ total_links = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links);
memcpy(msm_tasha_dai_links,
msm_common_dai_links,
sizeof(msm_common_dai_links));
@@ -3127,10 +3285,23 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
memcpy(msm_tasha_dai_links + len_3,
msm_tasha_be_dai_links,
sizeof(msm_tasha_be_dai_links));
- if (use_wcn_btfm)
- memcpy(msm_tasha_dai_links + len_4,
+
+ if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) {
+ dev_dbg(dev, "%s(): WCN BTFM support present\n",
+ __func__);
+ memcpy(msm_tasha_dai_links + total_links,
msm_wcn_be_dai_links,
sizeof(msm_wcn_be_dai_links));
+ total_links += ARRAY_SIZE(msm_wcn_be_dai_links);
+ }
+
+ if (of_property_read_bool(dev->of_node, "qcom,hdmi-audio-rx")) {
+ dev_dbg(dev, "%s(): HDMI support present\n", __func__);
+ memcpy(msm_tasha_dai_links + total_links,
+ hdmi_be_dai_link,
+ sizeof(hdmi_be_dai_link));
+ total_links += ARRAY_SIZE(hdmi_be_dai_link);
+ }
dailink = msm_tasha_dai_links;
} else if (!strcmp(match->data, "stub_codec")) {
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 7d1dfa8f3a75..4fb61470f118 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -9928,7 +9928,7 @@ static struct platform_driver msm_routing_pcm_driver = {
int msm_routing_check_backend_enabled(int fedai_id)
{
int i;
- if (fedai_id >= MSM_FRONTEND_DAI_MM_MAX_ID) {
+ if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
/* bad ID assigned in machine driver */
pr_err("%s: bad MM ID\n", __func__);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/q6core.c b/sound/soc/msm/qdsp6v2/q6core.c
index cc26af528aba..cc7616f1d897 100644
--- a/sound/soc/msm/qdsp6v2/q6core.c
+++ b/sound/soc/msm/qdsp6v2/q6core.c
@@ -357,14 +357,14 @@ int core_dts_eagle_set(int size, char *data)
}
size_aligned4byte = (size+3) & 0xFFFFFFFC;
+ mutex_lock(&(q6core_lcl.cmd_lock));
ocm_core_open();
if (q6core_lcl.core_handle_q) {
payload = kzalloc(sizeof(struct adsp_dts_eagle) +
size_aligned4byte, GFP_KERNEL);
if (!payload) {
- pr_err("DTS_EAGLE_CORE - %s: out of memory (aligned size %i).\n",
- __func__, size_aligned4byte);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto exit;
}
payload->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -387,6 +387,9 @@ int core_dts_eagle_set(int size, char *data)
}
kfree(payload);
}
+
+exit:
+ mutex_unlock(&(q6core_lcl.cmd_lock));
return rc;
}
@@ -401,6 +404,7 @@ int core_dts_eagle_get(int id, int size, char *data)
__func__, size, data);
return -EINVAL;
}
+ mutex_lock(&(q6core_lcl.cmd_lock));
ocm_core_open();
if (q6core_lcl.core_handle_q) {
ah.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
@@ -415,9 +419,8 @@ int core_dts_eagle_get(int id, int size, char *data)
generic_get_data = kzalloc(sizeof(struct generic_get_data_)
+ size, GFP_KERNEL);
if (!generic_get_data) {
- pr_err("DTS_EAGLE_CORE - %s: error allocating memory of size %i\n",
- __func__, size);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto exit;
}
rc = apr_send_pkt(q6core_lcl.core_handle_q,
@@ -425,7 +428,7 @@ int core_dts_eagle_get(int id, int size, char *data)
if (rc < 0) {
pr_err("DTS_EAGLE_CORE - %s: failed op[0x%x]rc[%d]\n",
__func__, ah.opcode, rc);
- goto fail_cmd_2;
+ goto exit;
}
rc = wait_event_timeout(q6core_lcl.bus_bw_req_wait,
@@ -435,7 +438,7 @@ int core_dts_eagle_get(int id, int size, char *data)
pr_err("DTS_EAGLE_CORE - %s: EAGLE get params timed out\n",
__func__);
rc = -EINVAL;
- goto fail_cmd_2;
+ goto exit;
}
if (generic_get_data->valid) {
rc = 0;
@@ -447,9 +450,10 @@ int core_dts_eagle_get(int id, int size, char *data)
}
}
-fail_cmd_2:
+exit:
kfree(generic_get_data);
generic_get_data = NULL;
+ mutex_unlock(&(q6core_lcl.cmd_lock));
return rc;
}
@@ -496,6 +500,7 @@ bool q6core_is_adsp_ready(void)
hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE;
+ mutex_lock(&(q6core_lcl.cmd_lock));
ocm_core_open();
q6core_lcl.bus_bw_resp_received = 0;
rc = apr_send_pkt(q6core_lcl.core_handle_q, (uint32_t *)&hdr);
@@ -515,6 +520,7 @@ bool q6core_is_adsp_ready(void)
}
bail:
pr_debug("%s: leave, rc %d, adsp ready %d\n", __func__, rc, ret);
+ mutex_unlock(&(q6core_lcl.cmd_lock));
return ret;
}
@@ -692,6 +698,11 @@ static int q6core_send_custom_topologies(void)
struct cal_block_data *cal_block = NULL;
struct avcs_cmd_register_topologies reg_top;
+ if (!q6core_is_adsp_ready()) {
+ pr_err("%s: ADSP is not ready!\n", __func__);
+ return -ENODEV;
+ }
+
memset(&reg_top, 0, sizeof(reg_top));
mutex_lock(&q6core_lcl.cal_data[CUST_TOP_CAL]->lock);
mutex_lock(&q6core_lcl.cmd_lock);
@@ -708,12 +719,6 @@ static int q6core_send_custom_topologies(void)
goto unlock;
}
- if (!q6core_is_adsp_ready()) {
- pr_err("%s: ADSP is not ready!\n", __func__);
- ret = -ENODEV;
- goto unlock;
- }
-
q6core_dereg_all_custom_topologies();
ret = q6core_map_memory_regions(&cal_block->cal_data.paddr, 0,
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index a452ad7cec40..f32cfa40c192 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -162,5 +162,13 @@ config SND_BCD2000
source "sound/usb/line6/Kconfig"
+config SND_USB_AUDIO_QMI
+ tristate "USB Audio QMI Service driver"
+ depends on MSM_QMI_INTERFACE
+ help
+ Starts USB Audio QMI server to communicate with remote entity
+ to perform operations like enable or disable particular audio
+ stream on a connected USB device.
+
endif # SND_USB
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 2d2d122b069f..d2ac0386d3da 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -26,3 +26,4 @@ obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
obj-$(CONFIG_SND_USB_LINE6) += line6/
+obj-$(CONFIG_SND_USB_AUDIO_QMI) += usb_audio_qmi_v01.o usb_audio_qmi_svc.o
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 0a189d3b5efa..e94f4d2f2620 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -387,6 +387,7 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip)
list_for_each_entry_safe(ep, n, &chip->ep_list, list)
snd_usb_endpoint_free(ep);
+ mutex_destroy(&chip->dev_lock);
mutex_destroy(&chip->mutex);
kfree(chip);
return 0;
@@ -442,6 +443,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
}
mutex_init(&chip->mutex);
+ mutex_init(&chip->dev_lock);
init_waitqueue_head(&chip->shutdown_wait);
chip->index = idx;
chip->dev = dev;
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 8ee14f2365e7..81172a395e55 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -69,9 +69,14 @@ static void snd_usb_audio_stream_free(struct snd_usb_stream *stream)
static void snd_usb_audio_pcm_free(struct snd_pcm *pcm)
{
struct snd_usb_stream *stream = pcm->private_data;
+ struct snd_usb_audio *chip;
+
if (stream) {
+ mutex_lock(&stream->chip->dev_lock);
+ chip = stream->chip;
stream->pcm = NULL;
snd_usb_audio_stream_free(stream);
+ mutex_unlock(&chip->dev_lock);
}
}
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
new file mode 100644
index 000000000000..9d2b75876bfe
--- /dev/null
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -0,0 +1,1122 @@
+/* Copyright (c) 2016, 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 <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/usb/audio.h>
+#include <linux/uaccess.h>
+#include <sound/pcm.h>
+#include <sound/core.h>
+#include <sound/asound.h>
+#include <linux/usb.h>
+#include <linux/qmi_encdec.h>
+#include <soc/qcom/msm_qmi_interface.h>
+#include <linux/iommu.h>
+#include <linux/qcom_iommu.h>
+#include <linux/platform_device.h>
+
+#include "usbaudio.h"
+#include "card.h"
+#include "helper.h"
+#include "pcm.h"
+#include "usb_audio_qmi_v01.h"
+
+#define SND_PCM_CARD_NUM_MASK 0xffff0000
+#define SND_PCM_DEV_NUM_MASK 0xff00
+#define SND_PCM_STREAM_DIRECTION 0xff
+
+#define PREPEND_SID_TO_IOVA(iova, sid) (u64)(((u64)(iova)) | \
+ (((u64)sid) << 32))
+
+/* event ring iova base address */
+#define IOVA_BASE 0x1000
+
+#define IOVA_DCBA_BASE 0x2000
+#define IOVA_XFER_RING_BASE (IOVA_DCBA_BASE + PAGE_SIZE * (SNDRV_CARDS + 1))
+#define IOVA_XFER_BUF_BASE (IOVA_XFER_RING_BASE + PAGE_SIZE * SNDRV_CARDS * 32)
+#define IOVA_XFER_RING_MAX (IOVA_XFER_BUF_BASE - PAGE_SIZE)
+#define IOVA_XFER_BUF_MAX (0xfffff000 - PAGE_SIZE)
+
+#define MAX_XFER_BUFF_LEN (2 * PAGE_SIZE)
+
+struct iova_info {
+ struct list_head list;
+ unsigned long start_iova;
+ size_t size;
+ bool in_use;
+};
+
+struct intf_info {
+ unsigned long data_xfer_ring_va;
+ size_t data_xfer_ring_size;
+ unsigned long sync_xfer_ring_va;
+ size_t sync_xfer_ring_size;
+ unsigned long xfer_buf_va;
+ size_t xfer_buf_size;
+ phys_addr_t xfer_buf_pa;
+ u8 *xfer_buf;
+ bool in_use;
+};
+
+struct uaudio_dev {
+ struct usb_device *udev;
+ unsigned int card_num;
+ atomic_t in_use;
+ struct kref kref;
+ unsigned long dcba_iova;
+ size_t dcba_size;
+ wait_queue_head_t disconnect_wq;
+
+ /* interface specific */
+ int num_intf;
+ struct intf_info *info;
+};
+
+static struct uaudio_dev uadev[SNDRV_CARDS];
+
+struct uaudio_qmi_dev {
+ struct device *dev;
+ u32 sid;
+ u32 intr_num;
+ struct iommu_domain *domain;
+
+ /* list to keep track of available iova */
+ struct list_head dcba_list;
+ size_t dcba_iova_size;
+ unsigned long curr_dcba_iova;
+ struct list_head xfer_ring_list;
+ size_t xfer_ring_iova_size;
+ unsigned long curr_xfer_ring_iova;
+ struct list_head xfer_buf_list;
+ size_t xfer_buf_iova_size;
+ unsigned long curr_xfer_buf_iova;
+ /* bit fields representing pcm card enabled */
+ unsigned long card_slot;
+ /* cache event ring phys addr */
+ u64 er_phys_addr;
+};
+
+static struct uaudio_qmi_dev *uaudio_qdev;
+
+struct uaudio_qmi_svc {
+ struct qmi_handle *uaudio_svc_hdl;
+ void *curr_conn;
+ struct work_struct recv_msg_work;
+ struct workqueue_struct *uaudio_wq;
+ ktime_t t_request_recvd;
+ ktime_t t_resp_sent;
+};
+
+static struct uaudio_qmi_svc *uaudio_svc;
+
+static struct msg_desc uaudio_stream_req_desc = {
+ .max_msg_len = QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN,
+ .msg_id = QMI_UAUDIO_STREAM_REQ_V01,
+ .ei_array = qmi_uaudio_stream_req_msg_v01_ei,
+};
+
+static struct msg_desc uaudio_stream_resp_desc = {
+ .max_msg_len = QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN,
+ .msg_id = QMI_UAUDIO_STREAM_RESP_V01,
+ .ei_array = qmi_uaudio_stream_resp_msg_v01_ei,
+};
+
+enum mem_type {
+ MEM_EVENT_RING,
+ MEM_DCBA,
+ MEM_XFER_RING,
+ MEM_XFER_BUF,
+};
+
+static unsigned long uaudio_get_iova(unsigned long *curr_iova,
+ size_t *curr_iova_size, struct list_head *head, size_t size)
+{
+ struct iova_info *info, *new_info = NULL;
+ struct list_head *curr_head;
+ unsigned long va = 0;
+ size_t tmp_size = size;
+ bool found = false;
+
+ if (size % PAGE_SIZE) {
+ pr_err("%s: size %zu is not page size multiple\n", __func__,
+ size);
+ goto done;
+ }
+
+ if (size > *curr_iova_size) {
+ pr_err("%s: size %zu > curr size %zu\n", __func__, size,
+ *curr_iova_size);
+ goto done;
+ }
+ if (*curr_iova_size == 0) {
+ pr_err("%s: iova mapping is full\n", __func__);
+ goto done;
+ }
+
+ list_for_each_entry(info, head, list) {
+ /* exact size iova_info */
+ if (!info->in_use && info->size == size) {
+ info->in_use = true;
+ va = info->start_iova;
+ *curr_iova_size -= size;
+ found = true;
+ pr_debug("%s: exact size :%zu found\n", __func__, size);
+ goto done;
+ } else if (!info->in_use && tmp_size >= info->size) {
+ if (!new_info)
+ new_info = info;
+ pr_debug("%s: partial size: %zu found\n", __func__,
+ info->size);
+ tmp_size -= info->size;
+ if (tmp_size)
+ continue;
+
+ va = new_info->start_iova;
+ for (curr_head = &new_info->list; curr_head !=
+ &info->list; curr_head = curr_head->next) {
+ new_info = list_entry(curr_head, struct
+ iova_info, list);
+ new_info->in_use = true;
+ }
+ info->in_use = true;
+ *curr_iova_size -= size;
+ found = true;
+ goto done;
+ } else {
+ /* iova region in use */
+ new_info = NULL;
+ tmp_size = size;
+ }
+ }
+
+ info = kzalloc(sizeof(struct iova_info), GFP_KERNEL);
+ if (!info) {
+ va = 0;
+ goto done;
+ }
+
+ va = info->start_iova = *curr_iova;
+ info->size = size;
+ info->in_use = true;
+ *curr_iova += size;
+ *curr_iova_size -= size;
+ found = true;
+ list_add_tail(&info->list, head);
+
+done:
+ if (!found)
+ pr_err("%s: unable to find %zu size iova\n", __func__, size);
+ else
+ pr_debug("%s: va:%lu curr_iova:%lu curr_iova_size:%zu\n",
+ __func__, va, *curr_iova, *curr_iova_size);
+
+ return va;
+}
+
+static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa,
+ size_t size)
+{
+ unsigned long va = 0;
+ bool map = true;
+ int ret;
+
+ switch (mtype) {
+ case MEM_EVENT_RING:
+ va = IOVA_BASE;
+ /* er already mapped */
+ if (uaudio_qdev->er_phys_addr == pa)
+ map = false;
+ break;
+ case MEM_DCBA:
+ va = uaudio_get_iova(&uaudio_qdev->curr_dcba_iova,
+ &uaudio_qdev->dcba_iova_size, &uaudio_qdev->dcba_list, size);
+ break;
+ case MEM_XFER_RING:
+ va = uaudio_get_iova(&uaudio_qdev->curr_xfer_ring_iova,
+ &uaudio_qdev->xfer_ring_iova_size, &uaudio_qdev->xfer_ring_list,
+ size);
+ break;
+ case MEM_XFER_BUF:
+ va = uaudio_get_iova(&uaudio_qdev->curr_xfer_buf_iova,
+ &uaudio_qdev->xfer_buf_iova_size, &uaudio_qdev->xfer_buf_list,
+ size);
+ break;
+ default:
+ pr_err("%s: unknown mem type %d\n", __func__, mtype);
+ }
+
+ if (!va)
+ map = false;
+
+ if (!map)
+ goto done;
+
+ pr_debug("%s: map pa %pa to iova %lu for memtype %d\n", __func__, &pa,
+ va, mtype);
+ ret = iommu_map(uaudio_qdev->domain, va, pa, size,
+ IOMMU_READ | IOMMU_WRITE | IOMMU_DEVICE);
+ if (ret)
+ pr_err("%s:failed to map pa:%pa iova:%lu memtype:%d ret:%d\n",
+ __func__, &pa, va, mtype, ret);
+done:
+ return va;
+}
+
+static void uaudio_put_iova(unsigned long va, size_t size, struct list_head
+ *head, size_t *curr_iova_size)
+{
+ struct iova_info *info;
+ size_t tmp_size = size;
+ bool found = false;
+
+ list_for_each_entry(info, head, list) {
+ if (info->start_iova == va) {
+ if (!info->in_use) {
+ pr_err("%s: va %lu is not in use\n", __func__,
+ va);
+ return;
+ }
+ found = true;
+ info->in_use = false;
+ if (info->size == size)
+ goto done;
+ }
+
+ if (found && tmp_size >= info->size) {
+ info->in_use = false;
+ tmp_size -= info->size;
+ if (!tmp_size)
+ goto done;
+ }
+ }
+
+ if (!found) {
+ pr_err("%s: unable to find the va %lu\n", __func__, va);
+ return;
+ }
+done:
+ *curr_iova_size += size;
+ pr_debug("%s: curr_iova_size %zu\n", __func__, *curr_iova_size);
+}
+
+static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va,
+ size_t size)
+{
+ size_t umap_size;
+ bool unmap = true;
+
+ if (!va || !size)
+ return;
+
+ switch (mtype) {
+ case MEM_EVENT_RING:
+ if (uaudio_qdev->er_phys_addr)
+ uaudio_qdev->er_phys_addr = 0;
+ else
+ unmap = false;
+ break;
+ case MEM_DCBA:
+ uaudio_put_iova(va, size, &uaudio_qdev->dcba_list,
+ &uaudio_qdev->dcba_iova_size);
+ break;
+ case MEM_XFER_RING:
+ uaudio_put_iova(va, size, &uaudio_qdev->xfer_ring_list,
+ &uaudio_qdev->xfer_ring_iova_size);
+ break;
+ case MEM_XFER_BUF:
+ uaudio_put_iova(va, size, &uaudio_qdev->xfer_buf_list,
+ &uaudio_qdev->xfer_buf_iova_size);
+ break;
+ default:
+ pr_err("%s: unknown mem type %d\n", __func__, mtype);
+ unmap = false;
+ }
+
+ if (!unmap)
+ return;
+
+ pr_debug("%s: unmap iova %lu for memtype %d\n", __func__, va, mtype);
+
+ umap_size = iommu_unmap(uaudio_qdev->domain, va, size);
+ if (umap_size != size)
+ pr_err("%s: unmapped size %zu for iova %lu\n", __func__,
+ umap_size, va);
+}
+
+static int prepare_qmi_response(struct snd_usb_substream *subs,
+ struct qmi_uaudio_stream_resp_msg_v01 *resp, u32 xfer_buf_len,
+ int card_num)
+{
+ int ret = -ENODEV;
+ struct usb_interface *iface;
+ struct usb_host_interface *alts;
+ struct usb_interface_descriptor *altsd;
+ struct usb_host_endpoint *ep;
+ struct uac_format_type_i_continuous_descriptor *fmt;
+ struct uac_format_type_i_discrete_descriptor *fmt_v1;
+ struct uac_format_type_i_ext_descriptor *fmt_v2;
+ struct uac1_as_header_descriptor *as;
+ struct uac1_ac_header_descriptor *ac;
+ int protocol;
+ u8 *xfer_buf;
+ u32 len, mult, remainder;
+ unsigned long va, tr_data_va = 0, tr_sync_va = 0, dcba_va = 0,
+ xfer_buf_va = 0;
+ phys_addr_t xhci_pa, xfer_buf_pa;
+
+ iface = usb_ifnum_to_if(subs->dev, subs->interface);
+ if (!iface) {
+ pr_err("%s: interface # %d does not exist\n", __func__,
+ subs->interface);
+ goto err;
+ }
+
+ alts = &iface->altsetting[subs->altset_idx];
+ altsd = get_iface_desc(alts);
+ protocol = altsd->bInterfaceProtocol;
+
+ /* get format type */
+ fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+ UAC_FORMAT_TYPE);
+ if (!fmt) {
+ pr_err("%s: %u:%d : no UAC_FORMAT_TYPE desc\n", __func__,
+ subs->interface, subs->altset_idx);
+ goto err;
+ }
+
+ if (protocol == UAC_VERSION_1) {
+ as = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+ UAC_AS_GENERAL);
+ if (!as) {
+ pr_err("%s: %u:%d : no UAC_AS_GENERAL desc\n", __func__,
+ subs->interface, subs->altset_idx);
+ goto err;
+ }
+ resp->bDelay = as->bDelay;
+ fmt_v1 = (struct uac_format_type_i_discrete_descriptor *)fmt;
+ resp->bSubslotSize = fmt_v1->bSubframeSize;
+ } else if (protocol == UAC_VERSION_2) {
+ fmt_v2 = (struct uac_format_type_i_ext_descriptor *)fmt;
+ resp->bSubslotSize = fmt_v2->bSubslotSize;
+ } else {
+ pr_err("%s: unknown protocol version %x\n", __func__, protocol);
+ goto err;
+ }
+
+ ac = snd_usb_find_csint_desc(alts->extra,
+ alts->extralen,
+ NULL, UAC_HEADER);
+ if (!ac) {
+ pr_err("%s: %u:%d : no UAC_HEADER desc\n", __func__,
+ subs->interface, subs->altset_idx);
+ goto err;
+ }
+ resp->bcdADC = ac->bcdADC;
+
+ resp->slot_id = subs->dev->slot_id;
+
+ memcpy(&resp->std_as_opr_intf_desc, &alts->desc, sizeof(alts->desc));
+
+ ep = usb_pipe_endpoint(subs->dev, subs->data_endpoint->pipe);
+ if (!ep) {
+ pr_err("%s: data ep # %d context is null\n", __func__,
+ subs->data_endpoint->ep_num);
+ goto err;
+ }
+ memcpy(&resp->std_as_data_ep_desc, &ep->desc, sizeof(ep->desc));
+
+ xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep);
+ if (!xhci_pa) {
+ pr_err("%s:failed to get data ep ring dma address\n", __func__);
+ goto err;
+ }
+
+ resp->xhci_mem_info.tr_data.pa = xhci_pa;
+
+ if (subs->sync_endpoint) {
+ ep = usb_pipe_endpoint(subs->dev, subs->sync_endpoint->pipe);
+ if (!ep) {
+ pr_err("%s: sync ep # %d context is null\n", __func__,
+ subs->sync_endpoint->ep_num);
+ goto err;
+ }
+ memcpy(&resp->std_as_sync_ep_desc, &ep->desc, sizeof(ep->desc));
+ xhci_pa = usb_get_xfer_ring_dma_addr(subs->dev, ep);
+ if (!xhci_pa) {
+ pr_err("%s:failed to get sync ep ring dma address\n",
+ __func__);
+ goto err;
+ }
+ resp->xhci_mem_info.tr_sync.pa = xhci_pa;
+ }
+
+ resp->interrupter_num = uaudio_qdev->intr_num;
+
+ /* map xhci data structures PA memory to iova */
+
+ /* event ring */
+ ret = usb_sec_event_ring_setup(subs->dev, resp->interrupter_num);
+ if (ret) {
+ pr_err("%s: failed to setup sec event ring ret %d\n", __func__,
+ ret);
+ goto err;
+ }
+ xhci_pa = usb_get_sec_event_ring_dma_addr(subs->dev,
+ resp->interrupter_num);
+ if (!xhci_pa) {
+ pr_err("%s: failed to get sec event ring dma address\n",
+ __func__);
+ goto err;
+ }
+
+ va = uaudio_iommu_map(MEM_EVENT_RING, xhci_pa, PAGE_SIZE);
+ if (!va)
+ goto err;
+
+ resp->xhci_mem_info.evt_ring.va = PREPEND_SID_TO_IOVA(va,
+ uaudio_qdev->sid);
+ resp->xhci_mem_info.evt_ring.pa = xhci_pa;
+ resp->xhci_mem_info.evt_ring.size = PAGE_SIZE;
+ uaudio_qdev->er_phys_addr = xhci_pa;
+
+ /* dcba */
+ xhci_pa = usb_get_dcba_dma_addr(subs->dev);
+ if (!xhci_pa) {
+ pr_err("%s:failed to get dcba dma address\n", __func__);
+ goto unmap_er;
+ }
+
+ if (!uadev[card_num].dcba_iova) { /* mappped per usb device */
+ va = uaudio_iommu_map(MEM_DCBA, xhci_pa, PAGE_SIZE);
+ if (!va)
+ goto unmap_er;
+
+ uadev[card_num].dcba_iova = va;
+ uadev[card_num].dcba_size = PAGE_SIZE;
+ }
+
+ dcba_va = uadev[card_num].dcba_iova;
+ resp->xhci_mem_info.dcba.va = PREPEND_SID_TO_IOVA(dcba_va,
+ uaudio_qdev->sid);
+ resp->xhci_mem_info.dcba.pa = xhci_pa;
+ resp->xhci_mem_info.dcba.size = PAGE_SIZE;
+
+ /* data transfer ring */
+ xhci_pa = resp->xhci_mem_info.tr_data.pa;
+ va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE);
+ if (!va)
+ goto unmap_dcba;
+
+ tr_data_va = va;
+ resp->xhci_mem_info.tr_data.va = PREPEND_SID_TO_IOVA(va,
+ uaudio_qdev->sid);
+ resp->xhci_mem_info.tr_data.size = PAGE_SIZE;
+
+ /* sync transfer ring */
+ if (!resp->xhci_mem_info.tr_sync.pa)
+ goto skip_sync;
+
+ xhci_pa = resp->xhci_mem_info.tr_sync.pa;
+ va = uaudio_iommu_map(MEM_XFER_RING, xhci_pa, PAGE_SIZE);
+ if (!va)
+ goto unmap_data;
+
+ tr_sync_va = va;
+ resp->xhci_mem_info.tr_sync.va = PREPEND_SID_TO_IOVA(va,
+ uaudio_qdev->sid);
+ resp->xhci_mem_info.tr_sync.size = PAGE_SIZE;
+
+skip_sync:
+ /* xfer buffer, multiple of 4K only */
+ if (!xfer_buf_len)
+ xfer_buf_len = PAGE_SIZE;
+
+ mult = xfer_buf_len / PAGE_SIZE;
+ remainder = xfer_buf_len % PAGE_SIZE;
+ len = mult * PAGE_SIZE;
+ len += remainder ? PAGE_SIZE : 0;
+
+ if (len > MAX_XFER_BUFF_LEN) {
+ pr_err("%s: req buf len %d > max buf len %lu, setting %lu\n",
+ __func__, len, MAX_XFER_BUFF_LEN, MAX_XFER_BUFF_LEN);
+ len = MAX_XFER_BUFF_LEN;
+ }
+
+ xfer_buf = usb_alloc_coherent(subs->dev, len, GFP_KERNEL, &xfer_buf_pa);
+ if (!xfer_buf)
+ goto unmap_sync;
+
+ resp->xhci_mem_info.xfer_buff.pa = xfer_buf_pa;
+ resp->xhci_mem_info.xfer_buff.size = len;
+
+ va = uaudio_iommu_map(MEM_XFER_BUF, xfer_buf_pa, len);
+ if (!va)
+ goto unmap_sync;
+
+ xfer_buf_va = va;
+ resp->xhci_mem_info.xfer_buff.va = PREPEND_SID_TO_IOVA(va,
+ uaudio_qdev->sid);
+
+ if (!atomic_read(&uadev[card_num].in_use)) {
+ kref_init(&uadev[card_num].kref);
+ init_waitqueue_head(&uadev[card_num].disconnect_wq);
+ uadev[card_num].num_intf =
+ subs->dev->config->desc.bNumInterfaces;
+ uadev[card_num].info =
+ kzalloc(sizeof(struct intf_info) *
+ uadev[card_num].num_intf, GFP_KERNEL);
+ if (!uadev[card_num].info) {
+ ret = -ENOMEM;
+ goto unmap_xfer_buf;
+ }
+ uadev[card_num].udev = subs->dev;
+ atomic_set(&uadev[card_num].in_use, 1);
+ } else {
+ kref_get(&uadev[card_num].kref);
+ }
+
+ if (uadev[card_num].info[subs->interface].in_use) {
+ pr_err("%s interface# %d already in use card# %d\n", __func__,
+ subs->interface, card_num);
+ goto unmap_xfer_buf;
+ }
+
+ uadev[card_num].card_num = card_num;
+
+ /* cache intf specific info to use it for unmap and free xfer buf */
+ uadev[card_num].info[subs->interface].data_xfer_ring_va = tr_data_va;
+ uadev[card_num].info[subs->interface].data_xfer_ring_size = PAGE_SIZE;
+ uadev[card_num].info[subs->interface].sync_xfer_ring_va = tr_sync_va;
+ uadev[card_num].info[subs->interface].sync_xfer_ring_size = PAGE_SIZE;
+ uadev[card_num].info[subs->interface].xfer_buf_va = xfer_buf_va;
+ uadev[card_num].info[subs->interface].xfer_buf_pa = xfer_buf_pa;
+ uadev[card_num].info[subs->interface].xfer_buf_size = len;
+ uadev[card_num].info[subs->interface].xfer_buf = xfer_buf;
+ uadev[card_num].info[subs->interface].in_use = true;
+
+ set_bit(card_num, &uaudio_qdev->card_slot);
+
+ return 0;
+
+unmap_xfer_buf:
+ uaudio_iommu_unmap(MEM_XFER_BUF, xfer_buf_va, len);
+unmap_sync:
+ usb_free_coherent(subs->dev, len, xfer_buf, xfer_buf_pa);
+ uaudio_iommu_unmap(MEM_XFER_RING, tr_sync_va, PAGE_SIZE);
+unmap_data:
+ uaudio_iommu_unmap(MEM_XFER_RING, tr_data_va, PAGE_SIZE);
+unmap_dcba:
+ uaudio_iommu_unmap(MEM_DCBA, dcba_va, PAGE_SIZE);
+unmap_er:
+ uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+err:
+ return ret;
+}
+
+void uaudio_disconnect_cb(struct snd_usb_audio *chip)
+{
+ int ret, if_idx;
+ struct uaudio_dev *dev;
+ int card_num = chip->card_num;
+
+ pr_debug("%s: for card# %d\n", __func__, card_num);
+
+ mutex_lock(&chip->dev_lock);
+ if (card_num >= SNDRV_CARDS) {
+ pr_err("%s: invalid card number\n", __func__);
+ goto done;
+ }
+
+ dev = &uadev[card_num];
+ if (atomic_read(&dev->in_use)) {
+ ret = wait_event_interruptible(dev->disconnect_wq,
+ !atomic_read(&dev->in_use));
+ if (ret < 0) {
+ pr_debug("%s: failed with ret %d\n", __func__, ret);
+ goto done;
+ }
+ }
+
+ /* clean up */
+ if (!dev->udev) {
+ pr_debug("%s: no clean up required\n", __func__);
+ goto done;
+ }
+
+ /* free xfer buffer and unmap xfer ring and buf per interface */
+ for (if_idx = 0; if_idx < dev->num_intf; if_idx++) {
+ if (!dev->info[if_idx].in_use)
+ continue;
+ usb_free_coherent(dev->udev,
+ dev->info[if_idx].xfer_buf_size,
+ dev->info[if_idx].xfer_buf,
+ dev->info[if_idx].xfer_buf_pa);
+
+ uaudio_iommu_unmap(MEM_XFER_RING,
+ dev->info[if_idx].data_xfer_ring_va,
+ dev->info[if_idx].data_xfer_ring_size);
+ dev->info[if_idx].data_xfer_ring_va = 0;
+ dev->info[if_idx].data_xfer_ring_size = 0;
+
+ uaudio_iommu_unmap(MEM_XFER_RING,
+ dev->info[if_idx].sync_xfer_ring_va,
+ dev->info[if_idx].sync_xfer_ring_size);
+ dev->info[if_idx].sync_xfer_ring_va = 0;
+ dev->info[if_idx].sync_xfer_ring_size = 0;
+
+ uaudio_iommu_unmap(MEM_XFER_BUF,
+ dev->info[if_idx].xfer_buf_va,
+ dev->info[if_idx].xfer_buf_size);
+ dev->info[if_idx].xfer_buf_va = 0;
+ dev->info[if_idx].xfer_buf_size = 0;
+ pr_debug("%s: release resources: intf# %d card# %d\n", __func__,
+ if_idx, card_num);
+ }
+
+ /* iommu_unmap dcba iova for a usb device */
+ uaudio_iommu_unmap(MEM_DCBA, dev->dcba_iova, dev->dcba_size);
+
+ dev->dcba_iova = 0;
+ dev->dcba_size = 0;
+ dev->num_intf = 0;
+
+ /* free interface info */
+ kfree(dev->info);
+ dev->info = NULL;
+
+ clear_bit(card_num, &uaudio_qdev->card_slot);
+
+ /* all audio devices are disconnected */
+ if (!uaudio_qdev->card_slot) {
+ uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+ usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
+ pr_debug("%s: all audio devices disconnected\n", __func__);
+ }
+
+ dev->udev = NULL;
+done:
+ mutex_unlock(&chip->dev_lock);
+}
+
+static void uaudio_dev_release(struct kref *kref)
+{
+ struct uaudio_dev *dev = container_of(kref, struct uaudio_dev, kref);
+
+ pr_debug("%s for dev %p\n", __func__, dev);
+
+ atomic_set(&dev->in_use, 0);
+
+ clear_bit(dev->card_num, &uaudio_qdev->card_slot);
+
+ /* all audio devices are disconnected */
+ if (!uaudio_qdev->card_slot) {
+ usb_sec_event_ring_cleanup(dev->udev, uaudio_qdev->intr_num);
+ uaudio_iommu_unmap(MEM_EVENT_RING, IOVA_BASE, PAGE_SIZE);
+ pr_debug("%s: all audio devices disconnected\n", __func__);
+ }
+
+ wake_up(&dev->disconnect_wq);
+}
+
+static int handle_uaudio_stream_req(void *req_h, void *req)
+{
+ struct qmi_uaudio_stream_req_msg_v01 *req_msg;
+ struct qmi_uaudio_stream_resp_msg_v01 resp = {0};
+ struct snd_usb_substream *subs;
+ struct snd_usb_audio *chip = NULL;
+ struct uaudio_qmi_svc *svc = uaudio_svc;
+ struct intf_info *info;
+ u8 pcm_card_num, pcm_dev_num, direction;
+ int intf_num = -1, ret = 0;
+
+ req_msg = (struct qmi_uaudio_stream_req_msg_v01 *)req;
+
+ direction = req_msg->usb_token & SND_PCM_STREAM_DIRECTION;
+ pcm_dev_num = (req_msg->usb_token & SND_PCM_DEV_NUM_MASK) >> 8;
+ pcm_card_num = (req_msg->usb_token & SND_PCM_CARD_NUM_MASK) >> 16;
+
+ pr_debug("%s:card#:%d dev#:%d dir:%d en:%d fmt:%d rate:%d #ch:%d\n",
+ __func__, pcm_card_num, pcm_dev_num, direction, req_msg->enable,
+ req_msg->audio_format, req_msg->bit_rate,
+ req_msg->number_of_ch);
+
+ if (pcm_card_num >= SNDRV_CARDS) {
+ pr_err("%s: invalid card # %u", __func__, pcm_card_num);
+ ret = -EINVAL;
+ goto response;
+ }
+
+ subs = find_snd_usb_substream(pcm_card_num, pcm_dev_num, direction,
+ &chip, uaudio_disconnect_cb);
+ if (!subs || !chip || atomic_read(&chip->shutdown)) {
+ pr_err("%s: can't find substream for card# %u, dev# %u dir%u\n",
+ __func__, pcm_card_num, pcm_dev_num, direction);
+ ret = -ENODEV;
+ goto response;
+ }
+
+ mutex_lock(&chip->dev_lock);
+ intf_num = subs->interface;
+ if (atomic_read(&chip->shutdown) || !subs->stream || !subs->stream->pcm
+ || !subs->stream->chip) {
+ ret = -ENODEV;
+ mutex_unlock(&chip->dev_lock);
+ goto response;
+ }
+
+ subs->pcm_format = req_msg->audio_format;
+ subs->channels = req_msg->number_of_ch;
+ subs->cur_rate = req_msg->bit_rate;
+
+ ret = snd_usb_enable_audio_stream(subs, req_msg->enable);
+
+ if (!ret && req_msg->enable)
+ ret = prepare_qmi_response(subs, &resp, req_msg->xfer_buff_size,
+ pcm_card_num);
+
+ mutex_unlock(&chip->dev_lock);
+
+response:
+ if (!req_msg->enable && ret != -EINVAL) {
+ if (intf_num >= 0) {
+ mutex_lock(&chip->dev_lock);
+ info = &uadev[pcm_card_num].info[intf_num];
+ uaudio_iommu_unmap(MEM_XFER_RING,
+ info->data_xfer_ring_va,
+ info->data_xfer_ring_size);
+ info->data_xfer_ring_va = 0;
+ info->data_xfer_ring_size = 0;
+
+ uaudio_iommu_unmap(MEM_XFER_RING,
+ info->sync_xfer_ring_va,
+ info->sync_xfer_ring_size);
+ info->sync_xfer_ring_va = 0;
+ info->sync_xfer_ring_size = 0;
+
+ uaudio_iommu_unmap(MEM_XFER_BUF,
+ info->xfer_buf_va,
+ info->xfer_buf_size);
+ info->xfer_buf_va = 0;
+
+ usb_free_coherent(uadev[pcm_card_num].udev,
+ info->xfer_buf_size,
+ info->xfer_buf,
+ info->xfer_buf_pa);
+ info->xfer_buf_size = 0;
+ info->xfer_buf = NULL;
+ info->xfer_buf_pa = 0;
+ info->in_use = false;
+ pr_debug("%s:release resources: intf# %d card# %d\n",
+ __func__, intf_num, pcm_card_num);
+ mutex_unlock(&chip->dev_lock);
+ }
+ if (atomic_read(&uadev[pcm_card_num].in_use))
+ kref_put(&uadev[pcm_card_num].kref,
+ uaudio_dev_release);
+ }
+
+ resp.status = ret;
+ ret = qmi_send_resp_from_cb(svc->uaudio_svc_hdl, svc->curr_conn, req_h,
+ &uaudio_stream_resp_desc, &resp, sizeof(resp));
+
+ svc->t_resp_sent = ktime_get();
+
+ pr_debug("%s: t_resp sent - t_req recvd (in ms) %lld\n", __func__,
+ ktime_to_ms(ktime_sub(svc->t_resp_sent, svc->t_request_recvd)));
+
+ return ret;
+}
+
+static int uaudio_qmi_svc_connect_cb(struct qmi_handle *handle,
+ void *conn_h)
+{
+ struct uaudio_qmi_svc *svc = uaudio_svc;
+
+ if (svc->uaudio_svc_hdl != handle || !conn_h) {
+ pr_err("%s: handle mismatch\n", __func__);
+ return -EINVAL;
+ }
+ if (svc->curr_conn) {
+ pr_err("%s: Service is busy\n", __func__);
+ return -ECONNREFUSED;
+ }
+ svc->curr_conn = conn_h;
+ return 0;
+}
+
+static int uaudio_qmi_svc_disconnect_cb(struct qmi_handle *handle,
+ void *conn_h)
+{
+ struct uaudio_qmi_svc *svc = uaudio_svc;
+
+ if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) {
+ pr_err("%s: handle mismatch\n", __func__);
+ return -EINVAL;
+ }
+
+ svc->curr_conn = NULL;
+ return 0;
+}
+
+static int uaudio_qmi_svc_req_cb(struct qmi_handle *handle, void *conn_h,
+ void *req_h, unsigned int msg_id, void *req)
+{
+ int ret;
+ struct uaudio_qmi_svc *svc = uaudio_svc;
+
+ if (svc->uaudio_svc_hdl != handle || svc->curr_conn != conn_h) {
+ pr_err("%s: handle mismatch\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (msg_id) {
+ case QMI_UAUDIO_STREAM_REQ_V01:
+ ret = handle_uaudio_stream_req(req_h, req);
+ break;
+
+ default:
+ ret = -ENOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static int uaudio_qmi_svc_req_desc_cb(unsigned int msg_id,
+ struct msg_desc **req_desc)
+{
+ int ret;
+
+ pr_debug("%s: msg_id %d\n", __func__, msg_id);
+
+ switch (msg_id) {
+ case QMI_UAUDIO_STREAM_REQ_V01:
+ *req_desc = &uaudio_stream_req_desc;
+ ret = sizeof(struct qmi_uaudio_stream_req_msg_v01);
+ break;
+
+ default:
+ ret = -ENOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static void uaudio_qmi_svc_recv_msg(struct work_struct *w)
+{
+ int ret;
+ struct uaudio_qmi_svc *svc = container_of(w, struct uaudio_qmi_svc,
+ recv_msg_work);
+
+ do {
+ pr_debug("%s: Notified about a Receive Event", __func__);
+ } while ((ret = qmi_recv_msg(svc->uaudio_svc_hdl)) == 0);
+
+ if (ret != -ENOMSG)
+ pr_err("%s: Error receiving message\n", __func__);
+}
+
+static void uaudio_qmi_svc_ntfy(struct qmi_handle *handle,
+ enum qmi_event_type event, void *priv)
+{
+ struct uaudio_qmi_svc *svc = uaudio_svc;
+
+ pr_debug("%s: event %d", __func__, event);
+
+ svc->t_request_recvd = ktime_get();
+
+ switch (event) {
+ case QMI_RECV_MSG:
+ queue_work(svc->uaudio_wq, &svc->recv_msg_work);
+ break;
+ default:
+ break;
+ }
+}
+
+static struct qmi_svc_ops_options uaudio_svc_ops_options = {
+ .version = 1,
+ .service_id = UAUDIO_STREAM_SERVICE_ID_V01,
+ .service_vers = UAUDIO_STREAM_SERVICE_VERS_V01,
+ .connect_cb = uaudio_qmi_svc_connect_cb,
+ .disconnect_cb = uaudio_qmi_svc_disconnect_cb,
+ .req_desc_cb = uaudio_qmi_svc_req_desc_cb,
+ .req_cb = uaudio_qmi_svc_req_cb,
+};
+
+static int uaudio_qmi_plat_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *node = pdev->dev.of_node;
+
+ uaudio_qdev = devm_kzalloc(&pdev->dev, sizeof(struct uaudio_qmi_dev),
+ GFP_KERNEL);
+ if (!uaudio_qdev)
+ return -ENOMEM;
+
+ uaudio_qdev->dev = &pdev->dev;
+
+ ret = of_property_read_u32(node, "qcom,usb-audio-stream-id",
+ &uaudio_qdev->sid);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read sid.\n");
+ return -ENODEV;
+ }
+
+ ret = of_property_read_u32(node, "qcom,usb-audio-intr-num",
+ &uaudio_qdev->intr_num);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read intr num.\n");
+ return -ENODEV;
+ }
+
+ uaudio_qdev->domain = iommu_domain_alloc(msm_iommu_get_bus(&pdev->dev));
+ if (!uaudio_qdev) {
+ dev_err(&pdev->dev, "failed to callocate iommu domin\n");
+ return -ENODEV;
+ }
+
+ /* attach to external processor iommu */
+ ret = iommu_attach_device(uaudio_qdev->domain, &pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to attach device ret = %d\n", ret);
+ goto free_domain;
+ }
+
+ /* initialize dcba, xfer ring and xfer buf iova list */
+ INIT_LIST_HEAD(&uaudio_qdev->dcba_list);
+ uaudio_qdev->curr_dcba_iova = IOVA_DCBA_BASE;
+ uaudio_qdev->dcba_iova_size = SNDRV_CARDS * PAGE_SIZE;
+
+ INIT_LIST_HEAD(&uaudio_qdev->xfer_ring_list);
+ uaudio_qdev->curr_xfer_ring_iova = IOVA_XFER_RING_BASE;
+ uaudio_qdev->xfer_ring_iova_size =
+ IOVA_XFER_RING_MAX - IOVA_XFER_RING_BASE;
+
+ INIT_LIST_HEAD(&uaudio_qdev->xfer_buf_list);
+ uaudio_qdev->curr_xfer_buf_iova = IOVA_XFER_BUF_BASE;
+ uaudio_qdev->xfer_buf_iova_size =
+ IOVA_XFER_BUF_MAX - IOVA_XFER_BUF_BASE;
+
+ return 0;
+
+free_domain:
+ iommu_domain_free(uaudio_qdev->domain);
+ return ret;
+}
+
+static int uaudio_qmi_plat_remove(struct platform_device *pdev)
+{
+ iommu_detach_device(uaudio_qdev->domain, &pdev->dev);
+ iommu_domain_free(uaudio_qdev->domain);
+ uaudio_qdev->domain = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id of_uaudio_matach[] = {
+ {
+ .compatible = "qcom,usb-audio-qmi-dev",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_uaudio_matach);
+
+static struct platform_driver uaudio_qmi_driver = {
+ .probe = uaudio_qmi_plat_probe,
+ .remove = uaudio_qmi_plat_remove,
+ .driver = {
+ .name = "uaudio-qmi",
+ .of_match_table = of_uaudio_matach,
+ },
+};
+
+static int uaudio_qmi_svc_init(void)
+{
+ int ret;
+ struct uaudio_qmi_svc *svc;
+
+ svc = kzalloc(sizeof(struct uaudio_qmi_svc), GFP_KERNEL);
+ if (!svc)
+ return -ENOMEM;
+
+ svc->uaudio_wq = create_singlethread_workqueue("uaudio_svc");
+ if (!svc->uaudio_wq) {
+ ret = -ENOMEM;
+ goto free_svc;
+ }
+
+ svc->uaudio_svc_hdl = qmi_handle_create(uaudio_qmi_svc_ntfy, NULL);
+ if (!svc->uaudio_svc_hdl) {
+ pr_err("%s: Error creating svc_hdl\n", __func__);
+ ret = -EFAULT;
+ goto destroy_uaudio_wq;
+ }
+
+ ret = qmi_svc_register(svc->uaudio_svc_hdl, &uaudio_svc_ops_options);
+ if (ret < 0) {
+ pr_err("%s:Error registering uaudio svc %d\n", __func__, ret);
+ goto destroy_svc_handle;
+ }
+
+ INIT_WORK(&svc->recv_msg_work, uaudio_qmi_svc_recv_msg);
+
+ uaudio_svc = svc;
+
+ return 0;
+
+destroy_svc_handle:
+ qmi_handle_destroy(svc->uaudio_svc_hdl);
+destroy_uaudio_wq:
+ destroy_workqueue(svc->uaudio_wq);
+free_svc:
+ kfree(svc);
+ return ret;
+}
+
+static void uaudio_qmi_svc_exit(void)
+{
+ struct uaudio_qmi_svc *svc = uaudio_svc;
+
+ qmi_svc_unregister(svc->uaudio_svc_hdl);
+ flush_workqueue(svc->uaudio_wq);
+ qmi_handle_destroy(svc->uaudio_svc_hdl);
+ destroy_workqueue(svc->uaudio_wq);
+ kfree(svc);
+ uaudio_svc = NULL;
+}
+
+static int __init uaudio_qmi_plat_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&uaudio_qmi_driver);
+ if (ret)
+ return ret;
+
+ return uaudio_qmi_svc_init();
+}
+
+static void __exit uaudio_qmi_plat_exit(void)
+{
+ uaudio_qmi_svc_exit();
+ platform_driver_unregister(&uaudio_qmi_driver);
+}
+
+module_init(uaudio_qmi_plat_init);
+module_exit(uaudio_qmi_plat_exit);
+
+MODULE_DESCRIPTION("USB AUDIO QMI Service Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/usb/usb_audio_qmi_v01.c b/sound/usb/usb_audio_qmi_v01.c
new file mode 100644
index 000000000000..31b1ba74d5c7
--- /dev/null
+++ b/sound/usb/usb_audio_qmi_v01.c
@@ -0,0 +1,565 @@
+ /* Copyright (c) 2016, 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/qmi_encdec.h>
+
+#include <soc/qcom/msm_qmi_interface.h>
+
+#include "usb_audio_qmi_v01.h"
+
+static struct elem_info mem_info_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct mem_info_v01,
+ va),
+ },
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint64_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct mem_info_v01,
+ pa),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct mem_info_v01,
+ size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info apps_mem_info_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct mem_info_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct apps_mem_info_v01,
+ evt_ring),
+ .ei_array = mem_info_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct mem_info_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct apps_mem_info_v01,
+ tr_data),
+ .ei_array = mem_info_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct mem_info_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct apps_mem_info_v01,
+ tr_sync),
+ .ei_array = mem_info_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct mem_info_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct apps_mem_info_v01,
+ xfer_buff),
+ .ei_array = mem_info_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct mem_info_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct apps_mem_info_v01,
+ dcba),
+ .ei_array = mem_info_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info usb_endpoint_descriptor_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ bLength),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ bDescriptorType),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ bEndpointAddress),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ bmAttributes),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ wMaxPacketSize),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ bInterval),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ bRefresh),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_endpoint_descriptor_v01,
+ bSynchAddress),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info usb_interface_descriptor_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bLength),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bDescriptorType),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bInterfaceNumber),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bAlternateSetting),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bNumEndpoints),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bInterfaceClass),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bInterfaceSubClass),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ bInterfaceProtocol),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct usb_interface_descriptor_v01,
+ iInterface),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info qmi_uaudio_stream_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ priv_data),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ enable),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ usb_token),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x04,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ audio_format),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x05,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ number_of_ch),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x06,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ bit_rate),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x07,
+ .offset = offsetof(struct qmi_uaudio_stream_req_msg_v01,
+ xfer_buff_size),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ priv_data),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ status),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ slot_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x04,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ bSubslotSize),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct usb_interface_descriptor_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x05,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ std_as_opr_intf_desc),
+ .ei_array = usb_interface_descriptor_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct usb_endpoint_descriptor_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x06,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ std_as_data_ep_desc),
+ .ei_array = usb_endpoint_descriptor_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct usb_endpoint_descriptor_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x07,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ std_as_sync_ep_desc),
+ .ei_array = usb_endpoint_descriptor_v01_ei,
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x08,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ bDelay),
+ },
+ {
+ .data_type = QMI_UNSIGNED_2_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint16_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x09,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ bcdADC),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct apps_mem_info_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x0A,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ xhci_mem_info),
+ .ei_array = apps_mem_info_v01_ei,
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x0B,
+ .offset = offsetof(
+ struct qmi_uaudio_stream_resp_msg_v01,
+ interrupter_num),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ usb_token),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ priv_data),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x03,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ status),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x04,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ slot_id),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x05,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ bSubslotSize),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct usb_interface_descriptor_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x06,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ std_as_opr_intf_desc),
+ .ei_array = usb_interface_descriptor_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct usb_endpoint_descriptor_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x07,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ std_as_data_ep_desc),
+ .ei_array = usb_endpoint_descriptor_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct usb_endpoint_descriptor_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x08,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ std_as_sync_ep_desc),
+ .ei_array = usb_endpoint_descriptor_v01_ei,
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct apps_mem_info_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x09,
+ .offset = offsetof(struct qmi_uaudio_stream_ind_msg_v01,
+ xhci_mem_info),
+ .ei_array = apps_mem_info_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .is_array = QMI_COMMON_TLV_TYPE,
+ },
+};
diff --git a/sound/usb/usb_audio_qmi_v01.h b/sound/usb/usb_audio_qmi_v01.h
new file mode 100644
index 000000000000..7ad1ab8a61a9
--- /dev/null
+++ b/sound/usb/usb_audio_qmi_v01.h
@@ -0,0 +1,103 @@
+ /* Copyright (c) 2016, 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 USB_QMI_V01_H
+#define USB_QMI_V01_H
+
+#define UAUDIO_STREAM_SERVICE_ID_V01 0x41C
+#define UAUDIO_STREAM_SERVICE_VERS_V01 0x01
+
+#define QMI_UAUDIO_STREAM_RESP_V01 0x0001
+#define QMI_UAUDIO_STREAM_REQ_V01 0x0001
+#define QMI_UADUIO_STREAM_IND_V01 0x0001
+
+
+struct mem_info_v01 {
+ uint64_t va;
+ uint64_t pa;
+ uint32_t size;
+};
+
+struct apps_mem_info_v01 {
+ struct mem_info_v01 evt_ring;
+ struct mem_info_v01 tr_data;
+ struct mem_info_v01 tr_sync;
+ struct mem_info_v01 xfer_buff;
+ struct mem_info_v01 dcba;
+};
+
+struct usb_endpoint_descriptor_v01 {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+ uint8_t bRefresh;
+ uint8_t bSynchAddress;
+};
+
+struct usb_interface_descriptor_v01 {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+};
+
+struct qmi_uaudio_stream_req_msg_v01 {
+ uint32_t priv_data;
+ uint8_t enable;
+ uint32_t usb_token;
+ uint32_t audio_format;
+ uint32_t number_of_ch;
+ uint32_t bit_rate;
+ uint32_t xfer_buff_size;
+};
+#define QMI_UAUDIO_STREAM_REQ_MSG_V01_MAX_MSG_LEN 46
+extern struct elem_info qmi_uaudio_stream_req_msg_v01_ei[];
+
+struct qmi_uaudio_stream_resp_msg_v01 {
+ uint32_t priv_data;
+ uint32_t status;
+ uint32_t slot_id;
+ uint8_t bSubslotSize;
+ struct usb_interface_descriptor_v01 std_as_opr_intf_desc;
+ struct usb_endpoint_descriptor_v01 std_as_data_ep_desc;
+ struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc;
+ uint8_t bDelay;
+ uint16_t bcdADC;
+ struct apps_mem_info_v01 xhci_mem_info;
+ uint8_t interrupter_num;
+};
+#define QMI_UAUDIO_STREAM_RESP_MSG_V01_MAX_MSG_LEN 177
+extern struct elem_info qmi_uaudio_stream_resp_msg_v01_ei[];
+
+struct qmi_uaudio_stream_ind_msg_v01 {
+ uint32_t usb_token;
+ uint32_t priv_data;
+ uint32_t status;
+ uint32_t slot_id;
+ uint8_t bSubslotSize;
+ struct usb_interface_descriptor_v01 std_as_opr_intf_desc;
+ struct usb_endpoint_descriptor_v01 std_as_data_ep_desc;
+ struct usb_endpoint_descriptor_v01 std_as_sync_ep_desc;
+ struct apps_mem_info_v01 xhci_mem_info;
+};
+#define QMI_UAUDIO_STREAM_IND_MSG_V01_MAX_MSG_LEN 171
+extern struct elem_info qmi_uaudio_stream_ind_msg_v01_ei[];
+
+#endif
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 207ddb26f4ed..b776122d0ca9 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -60,6 +60,8 @@ struct snd_usb_audio {
bool autoclock; /* from the 'autoclock' module param */
struct usb_host_interface *ctrl_intf; /* the audio control interface */
+
+ struct mutex dev_lock; /* to protect any race with disconnect */
int card_num; /* cache pcm card number to use upon disconnect */
void (*disconnect_cb)(struct snd_usb_audio *chip);
};