summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-07-12 11:28:31 -0600
committerLinux Build Service Account <lnxbuild@localhost>2016-07-12 11:28:32 -0600
commit819b6079c0897725fd8a9dd0fd4402f5c69cb433 (patch)
treebaaa024b549b3d70c59177973302a416c785fed6
parenta36d8398690233636488ffbebbc5bae5349e784d (diff)
parent400520a6e2f06cc7c45e386e769a85d4aded565b (diff)
Promotion of kernel.lnx.4.4-160711.
CRs Change ID Subject -------------------------------------------------------------------------------------------------------------- 1024170 Ie0cfab09192ca6b09ec4fe171aaf544e3fb5f08f ARM: dts: msm: return unused pIMEM Vault memory for msmc 1037857 I95544aaf607887ae34eace8a9b1f18a1375c5c6d ARM: dts: msm: add proxy vote for DSI supplies for msmco 1036737 Ie9bb609f9681580d90e5ec35b89e587758c272d4 ARM: dts: msm: enable audio over HDMI for msmcobalt 1028725 I6cdb366499f9589dff9a42491c7ff357e98d65c5 clk: msm: clock-mmss-cobalt: Add display port clock supp 1026885 1037945 I08d85ef462f09003aaa17f6ebc5d27de7083796f msm: vidc: update the check to ignore extradata plane in 964855 I17fa4f28cc151e3a3ad89d284995a3fa770bec68 leds: qpnp-flash-v2: add callback for max current query 999299 I3e961f4fe1728a32314a3acf7af719374c90d01f qseecom: make change for unload TA 1032294 Ie8a19341831d4ffaea36898a80c71ab25f5daf3c msm: sde: Updating linear format definition for v4l2 rot 1037982 I4f8ec495ae02908d1d8cd7e86148a6d4bd38b198 ARM: dts: msm: Add dts entry mpm2-sleep-counter for MSMC 1024370 Ifb303d7266c98eb94c5eb6f806b7c5e1d95236d3 driver: thermal: Configure ARM threshold instead of low 1039863 I980e39b8c072fc2ec35d84b8698c40c770f7f041 ARM: dts: msm: Add initial device tree files for falcon 1024204 I7d999382dcb6223d84424173a1726c250520ad04 ARM: dts: msm: configure default CMA region for msmcobal 1039560 I20bd718c8cb70029c4dd46c52dbece326b90ef80 msm: ipa3: fix the double ipa3_pre_init issue 1038150 I96010edabd04fef0eeb3cbb0b8f1a11d178d99b5 ASoC: msmcobalt: Fix slimbus tx channel configuration 1036737 Ieef8a2658f9730a9268041ac93ea3958489f2eae msmcobalt: enable audio over HDMI 1032455 I60c60470a649eecd5bacf0b39b20dff58c910897 ARM: dts: msm: Update MPM interrupt mappings for cobalt 1037449 Ie4dd908657573e5110bce65931d5507125da4c40 iommu/iommu-debug:: initialize variables before use 1035411 I597b58b478a35e9c3e3afb1a2ddd20ad87961c1a msm: sde: Correct rotator irq enable mismatch 1024187 Ic4ec03e4fd545d44118c2225a3f8e26901ca1d81 ARM: dts: msm: Add regulator node to flash-led for pmico 1037797 I52b909dd226494987c79ed106ffdf9892d966ef1 mfd: qcom-i2c-pmic: add option to skip irq control 1034091 I7e127d97cdd22409d4e70788a7cf2013593d3bfe msmcobalt: Add delay to check ADSP state during SSR 1018761 Idc368aff7090bcb52ae598faae9f95c1ffe1d4cf arm64: defconfig: msm: enable MODULE_SIG for msm chipset 1026286 Ib975c99b3b87998c357251a37f4862cbbf68697d wil6210: fix chan check in wil_p2p_listen 1036660 I8ccbbc9ef0795397614ad0644fd1f2b5e31e3780 ARM: dts: msm: create a separate dtsi file for msmcobalt 1037449 I9d173756e277c9006220c02c209309167f179609 iommu/io-pgtable-fast: validate data before use 1024187 I1515fba2fb04c0b4d21828af3cea6d322262ab14 leds: qpnp-flash-v2: add regulator support 950797 I2c9b0ba0837f8fec5c320e3117aa3b2f553db6b2 sound: usb: Add support for usb audio qmi service 982931 Ie1cd3ccf777e84665075bc3b6d9fffa7d897de49 wil6210: add module parameter for alternate interface na 1021009 I31a49465545e4b9a562b66bff7353d91817205f2 ARM: dts: msm: Change camera mount angle for msmcobalt 1026885 1037945 Ifd18d8689351c4a6a22c988d359fb413be19e142 msm: vidc: add ion_handle checking before mapping buffer 1039456 I37d91c4f7e5d98333cf6be3c75168e134ae78060 media: videobuf2: Increase max buffers 1034091 I8863185651fde8d29b5b8d8f183544bf0f215dbe ASoC: qdsp6v2: Fix apr registration failure in q6core 1023504 1039037 I053587ae85b36ce0b08fdb5918c0f6b9d678dd24 msm: vidc: Remove forced-setting of layer-wise bitrate f 950797 I1abc80652a167cefa667b914b3a80a87326c3d44 sound: usb: Add support to share iova with remote proces 1024187 Ief6a610c82b7f645966c596f543a1d30f7a40dcc leds: qpnp-flash-v2: add support for strobe configuratio 1035969 I6bab3370caf776de25316da58ca48fcd9fbc4b5e defconfig: arm64: msm: Disable qtaguid and net activity 1018826 I0ba4d62e3723841c3dfccdca210c80cd220f78f7 ASoC: msm: qdsp6v2: Fix FE id check in routing driver 1034091 I53a219b1ebed5bc3593d500d80d580aac6431ab5 drivers: soc: set apr handle to NULL on glink_open error Change-Id: I2513c5f512828858c5dd28d56050967f4d788746 CRs-Fixed: 950797, 1035411, 1037857, 1024370, 964855, 1039456, 982931, 1023504, 1026885, 1028725, 1036660, 1035969, 1036737, 1037982, 1021009, 1037449, 1024204, 1038150, 1024187, 1039863, 1034091, 1039560, 1032455, 1018826, 1024170, 1032294, 999299, 1037945, 1026286, 1037797, 1039037, 1018761
-rw-r--r--Documentation/devicetree/bindings/arm/msm/msm.txt1
-rw-r--r--Documentation/devicetree/bindings/leds/leds-qpnp-flash-v2.txt59
-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-pmicobalt.dtsi7
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-audio.dtsi6
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi2
-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.dtsi9
-rw-r--r--arch/arm/boot/dts/qcom/msmcobalt.dtsi18
-rw-r--r--arch/arm/boot/dts/qcom/msmfalcon-rumi.dts29
-rw-r--r--arch/arm64/configs/msm-perf_defconfig7
-rw-r--r--arch/arm64/configs/msm_defconfig6
-rw-r--r--arch/arm64/configs/msmcortex-perf_defconfig6
-rw-r--r--arch/arm64/configs/msmcortex_defconfig6
-rw-r--r--arch/um/configs/x86_64_um_defconfig2
-rw-r--r--drivers/clk/msm/clock-mmss-cobalt.c130
-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.c348
-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.c9
-rw-r--r--drivers/media/platform/msm/vidc/msm_vidc_internal.h1
-rw-r--r--drivers/mfd/qcom-i2c-pmic.c23
-rw-r--r--drivers/misc/qseecom.c9
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c8
-rw-r--r--drivers/net/wireless/ath/wil6210/p2p.c6
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa.c16
-rw-r--r--drivers/soc/qcom/qdsp6v2/apr_tal_glink.c1
-rw-r--r--drivers/thermal/msm_lmh_dcvs.c10
-rw-r--r--include/dt-bindings/clock/msm-clocks-cobalt.h9
-rw-r--r--include/linux/leds-qpnp-flash-v2.h18
-rw-r--r--include/media/videobuf2-core.h2
-rw-r--r--include/uapi/linux/videodev2.h2
-rw-r--r--include/uapi/media/msm_sde_rotator.h14
-rwxr-xr-xsound/soc/codecs/Kconfig2
-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
55 files changed, 2896 insertions, 237 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..1372e424927f 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
@@ -35,7 +44,7 @@ serve as an overall switch.
type specifying flash duration. Values are from 10ms to 1280ms with
10ms resolution. This is not required for switch node.
-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 +53,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 {
@@ -156,6 +185,10 @@ Example:
qcom,led-name = "led:switch";
qcom,default-led-trigger =
"switch_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-pmicobalt.dtsi b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
index f5b59e6de558..c43ac0320c7a 100644
--- a/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
+++ b/arch/arm/boot/dts/qcom/msm-pmicobalt.dtsi
@@ -686,8 +686,11 @@
pmicobalt_switch: qcom,led_switch {
label = "switch";
qcom,led-name = "led:switch";
- qcom,default-led-trigger =
- "switch_trigger";
+ qcom,default-led-trigger = "switch_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-mtp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
index 83b55da92fa2..92be85073351 100644
--- a/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
+++ b/arch/arm/boot/dts/qcom/msmcobalt-camera-sensor-mtp.dtsi
@@ -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..74de62546c3b 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";
};
};
diff --git a/arch/arm/boot/dts/qcom/msmcobalt.dtsi b/arch/arm/boot/dts/qcom/msmcobalt.dtsi
index 8d778ac3f104..90d1ecd8f29c 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;
+ };
};
};
@@ -2497,6 +2507,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>;
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/configs/msm-perf_defconfig b/arch/arm64/configs/msm-perf_defconfig
index bf60b4047cb1..d41b23eeef67 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
@@ -566,7 +569,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 +576,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..3538ba14671f 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
@@ -604,7 +607,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..67a134a02762 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
@@ -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
@@ -540,7 +543,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..134c18c906ee 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
@@ -96,6 +99,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 +148,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
@@ -625,7 +628,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/clk/msm/clock-mmss-cobalt.c b/drivers/clk/msm/clock-mmss-cobalt.c
index 47466ad04311..66807366d19d 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,57 @@ static struct rcg_clk dp_aux_clk_src = {
},
};
+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 +2003,44 @@ static struct branch_clk mmss_mdss_dp_aux_clk = {
},
};
+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 +2418,13 @@ 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_aux_clk.c, 0x009c },
{ &mmss_mdss_dp_gtc_clk.c, 0x009d },
{ &mmss_mdss_byte0_intf_clk.c, 0x00ad },
@@ -2384,6 +2492,10 @@ 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_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 +2575,9 @@ 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_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 +2761,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/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..068c62a2f27f 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,18 @@ enum flash_led_type {
FLASH_LED_TYPE_TORCH,
};
+enum {
+ LED1 = 0,
+ LED2,
+ LED3,
+};
+
/*
* 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;
};
@@ -143,6 +159,80 @@ static int qpnp_flash_led_init_settings(struct qpnp_flash_led *led)
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) {
+ 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;
@@ -168,6 +258,10 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
if (!on)
goto leds_turn_off;
+ rc = qpnp_flash_led_regulator_enable(led, snode, true);
+ if (rc)
+ return rc;
+
val = 0;
for (i = 0; i < led->num_led_nodes; i++)
val |= led->fnode[i].ires << (led->fnode[i].id * 2);
@@ -176,6 +270,13 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
if (rc)
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)
+ return rc;
+
val = 0;
for (i = 0; i < led->num_avail_leds; i++) {
if (!led->fnode[i].led_on)
@@ -184,7 +285,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
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);
+ FLASH_LED_ENABLE_MASK, led->fnode[i].trigger);
if (rc)
return rc;
@@ -200,7 +301,7 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
if (rc)
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,
@@ -211,6 +312,16 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
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) {
+ 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),
@@ -219,8 +330,8 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
return rc;
rc = qpnp_flash_led_masked_write(led,
- FLASH_LED_REG_CHANNEL_CTRL(led->base),
- FLASH_LED_STROBE_CTRL_MASK, val);
+ FLASH_LED_EN_LED_CTRL(led->base),
+ FLASH_LED_ENABLE_MASK, val);
if (rc)
return rc;
@@ -228,8 +339,8 @@ static int qpnp_flash_led_switch_set(struct flash_switch_data *snode, bool on)
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);
+ FLASH_LED_EN_LED_CTRL(led->base),
+ FLASH_LED_ENABLE_MASK, FLASH_LED_DISABLE);
if (rc)
return rc;
@@ -260,11 +371,56 @@ leds_turn_off:
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) {
+ dev_err(&led->pdev->dev,
+ "Unable to disable hw strobe\n");
+ return rc;
+ }
+ }
}
+ qpnp_flash_led_regulator_enable(led, snode, false);
+
return 0;
}
+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;
+
+ if (!(options & (ENABLE_REGULATOR | QUERY_MAX_CURRENT))) {
+ dev_err(&led->pdev->dev, "Invalid options %d\n", options);
+ return -EINVAL;
+ }
+
+ 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;
+ }
+ }
+
+ 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 val;
+}
+
static void qpnp_flash_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -297,12 +453,111 @@ 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;
@@ -429,6 +684,50 @@ 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) {
dev_err(&led->pdev->dev, "Unable to register led node %d\n",
@@ -469,7 +768,7 @@ 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 device_node *node)
{
- int rc;
+ int rc = 0;
rc = of_property_read_string(node, "qcom,led-name",
&led->snode->cdev.name);
@@ -485,6 +784,21 @@ static int qpnp_flash_led_parse_and_register_switch(struct qpnp_flash_led *led,
return rc;
}
+ rc = qpnp_flash_led_regulator_parse_dt(led, led->snode, node);
+ if (rc < 0) {
+ dev_err(&led->pdev->dev,
+ "Unable to parse regulator data, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (led->snode->num_regulators) {
+ rc = qpnp_flash_led_regulator_setup(led, led->snode, true);
+ if (rc) {
+ dev_err(&led->pdev->dev, "Unable to setup regulator\n");
+ 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;
@@ -517,6 +831,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;
}
@@ -632,6 +954,12 @@ 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;
+ if (led->snode->num_regulators) {
+ if (led->snode->regulator_on)
+ qpnp_flash_led_regulator_enable(led, led->snode, false);
+ qpnp_flash_led_regulator_setup(led, led->snode, false);
+ }
+
led_classdev_unregister(&led->snode->cdev);
while (i > 0)
led_classdev_unregister(&led->fnode[--i].cdev);
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..8a4d5eb561c6 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");
@@ -907,8 +909,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,
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/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/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/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 747ae3d82b68..3f4fc3fe8793 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -5059,16 +5059,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/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/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/leds-qpnp-flash-v2.h b/include/linux/leds-qpnp-flash-v2.h
index ae36a163ed21..1ff8781d3837 100644
--- a/include/linux/leds-qpnp-flash-v2.h
+++ b/include/linux/leds-qpnp-flash-v2.h
@@ -16,6 +16,15 @@
#include <linux/leds.h>
#include "leds.h"
+#define ENABLE_REGULATOR BIT(0)
+#define QUERY_MAX_CURRENT BIT(1)
+
+struct flash_regulator_data {
+ struct regulator *vreg;
+ const char *reg_name;
+ u32 max_volt_uv;
+};
+
/*
* Configurations for each individual LED
*/
@@ -25,6 +34,9 @@ struct flash_node_data {
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;
@@ -34,12 +46,18 @@ struct flash_node_data {
u8 ires;
u8 hdrm_val;
u8 current_reg_val;
+ u8 trigger;
bool led_on;
};
struct flash_switch_data {
struct platform_device *pdev;
struct led_classdev cdev;
+ struct flash_regulator_data *reg_data;
+ u8 num_regulators;
+ bool regulator_on;
};
+int qpnp_flash_led_prepare(struct led_classdev *led_cdev, int options);
+
#endif
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/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/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/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);
};