Merge "msm_serial_hs: Add flush state machine for UART Tx Transfer" into msm-3.4
diff --git a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
index a33d833..d8784db 100644
--- a/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
+++ b/Documentation/devicetree/bindings/arm/msm/spm-v2.txt
@@ -40,6 +40,7 @@
- qcom,saw2-spm-cmd-ret: The Retention command sequence
- qcom,saw2-spm-cmd-spc: The Standalone PC command sequence
- qcom,saw2-spm-cmd-pc: The Power Collapse command sequence
+- qcom,saw2-spm-cmd-gdhs: L2 GDHS command sequence
Example:
qcom,spm@f9089000 {
@@ -56,11 +57,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
diff --git a/Documentation/devicetree/bindings/pil/pil-mba.txt b/Documentation/devicetree/bindings/pil/pil-mba.txt
new file mode 100644
index 0000000..7aafd219
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-mba.txt
@@ -0,0 +1,27 @@
+Qualcomm Modem Boot Authenticator Peripheral Image Loader
+
+pil-mba is a peripheral image loader (PIL) driver. It is used for loading
+modem images using the self-authenticating hardware and software features
+of the Modem Boot Authenticator.
+
+Required properties:
+- compatible: Must be "qcom,pil-mba"
+- reg: Two pairs of physical base addresses and sizes. The
+ first corresponds to the Relay Message Buffer (RMB)
+ register base. The second specifies the address at which
+ the primary modem image metadata should be stored.
+- qcom,firmware-name: Base name of the firmware image. Ex. "modem"
+
+Optional properties:
+- qcom,depends-on: firmware-name of a prerequisite image that must already
+ be running.
+
+Example:
+ qcom,mba@fc820000 {
+ compatible = "qcom,pil-mba";
+ reg = <0xfc820000 0x0020>,
+ <0x0d1f0000 0x4000>;
+
+ qcom,firmware-name = "modem";
+ qcom,depends-on = "mba";
+ };
diff --git a/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
new file mode 100644
index 0000000..95e7f88
--- /dev/null
+++ b/Documentation/devicetree/bindings/pil/pil-q6v5-mss.txt
@@ -0,0 +1,32 @@
+Qualcomm MSS QDSP6v5 Peripheral Image Loader
+
+pil-qdsp6v5-mss is a peripheral image loader (PIL) driver. It is used for
+loading QDSP6v5 (Hexagon) firmware images for modem subsystems into memory and
+preparing the subsystem's processor to execute code. It's also responsible for
+shutting down the processor when it's not needed.
+
+Required properties:
+- compatible: Must be "qcom,pil-q6v5-mss"
+- reg: Four pairs of physical base addresses and region sizes of
+ memory mapped registers. The first region corresponds to
+ QDSP6SS_PUB, the second to the bus port halt register
+ base, the third to the MSS_RELAY_MSG_BUFFER base, and the
+ fourth to the MSS_RESTART register.
+- vdd_mss-supply: Reference to the regulator that supplies the processor.
+- qcom,firmware-name: Base name of the firmware image. Ex. "mdsp"
+- qcom,pil-self-auth: <0> if the hardware does not require self-authenticating
+ images and self-authentication is not desired;
+ <1> if the hardware requires self-authenticating images.
+
+Example:
+ qcom,mss@fc880000 {
+ compatible = "qcom,pil-q6v5-mss";
+ reg = <0xfc880000 0x100>,
+ <0xfd485000 0x400>,
+ <0xfc820000 0x020>,
+ <0xfc401680 0x004>;
+ vdd_mss-supply = <&pm8841_s3>;
+
+ qcom,firmware-name = "mba";
+ qcom,pil-self-auth = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt
new file mode 100644
index 0000000..8b17ba9
--- /dev/null
+++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt
@@ -0,0 +1,10 @@
+* QSEECOM (Qualcomm Secure Execution Environment Communicator)
+
+Required properties:
+- compatible : Should be "qcom,qseecom"
+
+Example:
+
+ qcom,qseecom@fe806000 {
+ compatible = "qcom,qseecom";
+ };
diff --git a/Documentation/tzcom.txt b/Documentation/tzcom.txt
deleted file mode 100644
index 7472dee..0000000
--- a/Documentation/tzcom.txt
+++ /dev/null
@@ -1,181 +0,0 @@
-Introduction
-============
-
-The tzcom (TrustZone Communicator) device driver provides IOCTLs for userspace
-to communicate with TrustZone Operating Environment (TZBSP) using Secure
-Channel Manager (SCM) interface. It also provides a way for TZBSP to utilize
-services in HLOS.
-
-Hardware description
-====================
-
-The hardware interaction is specified in Secure Channel Manager for TZBSP design
-document. This driver exercises the SCM interface (scm_call).
-
-Software description
-====================
-
-This driver is a character device driver and following operations are registered:
-- tzcom_open()
-- tzcom_release()
-- tzcom_ioctl()
-
-
-This driver provides following IOCTL methods:
- TZCOM_IOCTL_REGISTER_SERVICE_REQ - to register HLOS service
- TZCOM_IOCTL_UNREGISTER_SERVICE_REQ - to unregister HLOS service
- TZCOM_IOCTL_SEND_CMD_REQ - send a command to a service
- TZCOM_IOCTL_READ_NEXT_CMD_REQ - wait for a cmd from TZBSP to use HLOS service
- TZCOM_IOCTL_CONTINUE_CMD_REQ - continue the last incomplete cmd on TZBSP
-
-TZCOM_IOCTL_REGISTER_SERVICE_REQ sequence diagram:
-
- +--------------+ +---------------+
- | USERSPACE | | TZCOM |
- +------+-------+ +-------+-------+
- | REGISTER_SERVICE |
- |----------------->| ___
- | |,-' ``.
- | + verify &`.
- | | add |
- | | service |
- | | to a list|
- | registered |<-.._,,,,/
- |<-----------------|
- | |
-
-TZCOM_IOCTL_READ_NEXT_CMD_REQ, TZCOM_IOCTL_SEND_CMD_REQ and
-TZCOM_IOCTL_CONTINUE_CMD_REQ sequence:
-
- +--------------+ +---------------+ +-------------+ +----------------+
- | USERSPACE | | TZCOM | | SCM | | TZBSP |
- +---+--+-------+ +-------+-------+ +------+------+ +-------+--------+
- | | READ_NEXT_CMD | | |
- +--|----------------->| | |
- | | |.--------. | |
- | | || BLOCKED| | |
- | | |`--------' | |
- | | | | |
- | | | | |
- | | SEND_CMD | | |
- | +----------------->| | |
- | | | scm_call | |
- | | +---------------->| SEND_CMD |
- | | | +---------------->|
- | | | | cmd incomplete |
- | | | scm_call returns|<----------------+
- | | |<----------------+ |
- | | | | |
- | | |,-'''-. | |
- | | + READ `. | |
- | | | NEXT | | |
- | | | CMD / | |
- | | READ_NEXT_CMD ret|<.____,' | |
- |<-|------------------+ | |
- ,---. | | | | |
- / \ | | | | |
-/perform\| | | | |
- received) | | | |
-\command/| | | | |
- \ / | | | | |
- `---' | | | | |
- | | | | |
- | | CONTINUE_CMD | | |
- +--|----------------->| | |
- | | returns | _,... | |
- | | immediately |' `. | |
- | | | fill in`. | |
- | | | incomplete | |
- | | | cmd ; | |
- | |<-...---' | |
- | | scm_call | |
- | +---------------->| SEND_CMD |
- | | +---------------->|
- | | | cmd complete |
- | | scm_call returns|<----------------+
- |SEND_CMD return |<----------------+ |
- |<-----------------+ | |
- | | | |
-
-
-
-There are three shared buffers between TZCOM driver and TZBSP.
-1) For command and response buffers for SEND_CMD requests
-2) For commands originated from TZBSP and their corresponding responses
-3) For debug service
-
-When calling IOCTL_SEND_CMD_REQ from userspace, command request and response
-buffers are initialized and provided in the IOCTL arguments. Where request and
-response buffers will be passed as an arguments to the smc_call method.
-
-The requests are synchronous. The driver will put the process to sleep,
-waiting for the completion of the requests using wait_for_completion().
-
-This driver uses kmalloc for shared buffer pools which get initialized at driver
-initialization. There are three buffers each 20 KB. If any of the buffers fail
-to initialize then driver will fail to load. Assumption is the allocated
-memory for buffers is contiguous.
-
-
-Design
-======
-
-The goal of this driver is to provide a communication API for the userspace
-application to execute services in TrustZone as well as TrustZone operating
-environment to access services in HLOS.
-
-Currently TZ->HLOS communication happens from a blocking call to READ_NEXT_CMD
-that is initiated from the userspace and on receiving a command request from TZ
-service, command is placed on a queue to unblock READ_NEXT_CMD call. This could
-have been solved by using a callback, but the practice of invoking callbacks in
-userspace from kernel is discouraged.
-
-Power Management
-================
-
-n/a
-
-SMP/multi-core
-==============
-
-TZCOM allows multiple services being registered from HLOS and multiple processes
-or threads can call IOCTL_READ_NEXT_MSG. These services will block until new
-data arrives on the shared buffer (buffer #2 as mentioned in Software
-Description). This is achieved using wait queues.
-
-Security
-========
-
-Please refer to Security Channel Manager design document.
-
-Performance
-===========
-
-Every scm_call is a context switch between non-trusted and trusted operating
-environment. There are no performance related matrix for scm_call available as
-of now.
-
-Interface
-=========
-
-This driver will have a /dev/tzcom node and following IOCTL calls can be made.
-
-Userspace API (ioctl calls):
- TZCOM_IOCTL_REGISTER_SERVICE_REQ - to register HLOS service
- TZCOM_IOCTL_UNREGISTER_SERVICE_REQ - to unregister HLOS service
- TZCOM_IOCTL_SEND_CMD_REQ - send a command to a service
- TZCOM_IOCTL_READ_NEXT_CMD_REQ - wait for a cmd from TZBSP to use HLOS service
- TZCOM_IOCTL_CONTINUE_CMD_REQ - continue the last incomplete cmd on TZBSP
-
-
-Dependencies
-============
-
-This driver interacts with Trustzone operating environment, thus depends on
-the TZBSP supported architecture.
-
-
-To do
-=====
-
-TBD
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index 523c9b0..b157e95 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -153,13 +153,13 @@
status = "disabled";
qcom,ctl@2600 {
- reg = <0x2300 0x100>;
+ reg = <0x2600 0x100>;
};
qcom,ps@2700 {
- reg = <0x2400 0x100>;
+ reg = <0x2700 0x100>;
};
qcom,freq@2800 {
- reg = <0x2500 0x100>;
+ reg = <0x2800 0x100>;
};
};
diff --git a/arch/arm/boot/dts/msm9625.dts b/arch/arm/boot/dts/msm9625.dts
index d5aed00..6c007fb 100644
--- a/arch/arm/boot/dts/msm9625.dts
+++ b/arch/arm/boot/dts/msm9625.dts
@@ -33,12 +33,23 @@
reg = <0xfd510000 0x4000>;
};
- timer {
+ timer: msm-qtimer@f9021000 {
compatible = "qcom,msm-qtimer", "arm,armv7-timer";
+ reg = <0xF9021000 0x1000>;
interrupts = <0 7 0>;
+ irq-is-not-percpu;
clock-frequency = <5000000>;
};
+ qcom,sps@f9980000 {
+ compatible = "qcom,msm_sps";
+ reg = <0xf9984000 0x15000>,
+ <0xf9999000 0xb000>,
+ <0xfe800000 0x4800>;
+ interrupts = <0 94 0>;
+ qcom,device-type = <2>;
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index 0d0c587..a926aa3 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -155,7 +155,7 @@
};
pm8941_l13: regulator@4c00 {
- regulator-min-microvolt = <2950000>;
+ regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <2950000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
index dff1973..3f1a2ac 100644
--- a/arch/arm/boot/dts/msmcopper-rumi.dts
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -38,14 +38,6 @@
qcom,sdcc-clk-rates = <400000 19200000>;
};
- qcom,sdcc@f9864000 {
- status = "disable";
- };
-
- qcom,sdcc@f98e4000 {
- status = "disable";
- };
-
qcom,sps@f998000 {
status = "disable";
};
diff --git a/arch/arm/boot/dts/msmcopper-sim.dts b/arch/arm/boot/dts/msmcopper-sim.dts
index ae3f2dd..ab6b8ba 100644
--- a/arch/arm/boot/dts/msmcopper-sim.dts
+++ b/arch/arm/boot/dts/msmcopper-sim.dts
@@ -17,22 +17,4 @@
/ {
model = "Qualcomm MSM Copper Simulator";
compatible = "qcom,msmcopper-sim", "qcom,msmcopper";
-
- qcom,sdcc@f9824000 {
- qcom,sdcc-disable_cmd23;
- };
-
- qcom,sdcc@f98a4000 {
- status = "disable";
- };
-
- qcom,sdcc@f9864000 {
- qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000 200000000>;
- qcom,sdcc-sup-voltages = <2950 2950>;
- qcom,sdcc-disable_cmd23;
- };
-
- qcom,sdcc@f98e4000 {
- status = "disable";
- };
};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 60f59d3..77cbbe0 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -111,6 +111,7 @@
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
qcom,sdcc-sup-voltages = <1800 1800>;
qcom,sdcc-bus-width = <4>;
+ status = "disable";
};
qcom,sdcc@f98e4000 {
@@ -122,6 +123,7 @@
qcom,sdcc-clk-rates = <400000 25000000 50000000 100000000>;
qcom,sdcc-sup-voltages = <1800 1800>;
qcom,sdcc-bus-width = <4>;
+ status = "disable";
};
qcom,sps@f9980000 {
@@ -272,8 +274,13 @@
qcom,ssusb@F9200000 {
compatible = "qcom,dwc-usb3-msm";
- reg = <0xF9200000 0xCCFF>;
+ reg = <0xF9200000 0xFA000>;
interrupts = <0 131 0>;
+ SSUSB_VDDCX-supply = <&pm8841_s2>;
+ SSUSB_1p8-supply = <&pm8941_l6>;
+ HSUSB_VDDCX-supply = <&pm8841_s2>;
+ HSUSB_1p8-supply = <&pm8941_l6>;
+ HSUSB_3p3-supply = <&pm8941_l24>;
qcom,dwc-usb3-msm-dbm-eps = <4>;
};
@@ -289,6 +296,74 @@
qcom,firmware-name = "adsp";
};
+ qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ };
+
+ qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ qcom,msm-pcm-lpa {
+ compatible = "qcom,msm-pcm-lpa";
+ };
+
+ qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
+ qcom,msm-cpudai-auxpcm-mode = <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>;
+ qcom,msm-cpudai-auxpcm-quant = <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+
+ qcom,msm-dai-q6-rx {
+ qcom,msm-dai-q6-id = <4106>;
+ };
+ qcom,msm-dai-q6-tx {
+ qcom,msm-dai-q6-id = <4107>;
+ };
+ };
+
+ qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ qcom,mss@fc880000 {
+ compatible = "qcom,pil-q6v5-mss";
+ reg = <0xfc880000 0x100>,
+ <0xfd485000 0x400>,
+ <0xfc820000 0x020>,
+ <0xfc401680 0x004>;
+ vdd_mss-supply = <&pm8841_s3>;
+
+ qcom,firmware-name = "mba";
+ qcom,pil-self-auth = <1>;
+ };
+
+ qcom,mba@fc820000 {
+ compatible = "qcom,pil-mba";
+ reg = <0xfc820000 0x0020>,
+ <0x0d1fc000 0x4000>;
+
+ qcom,firmware-name = "modem";
+ qcom,depends-on = "mba";
+ };
+
qcom,pronto@fb21b000 {
compatible = "qcom,pil-pronto";
reg = <0xfb21b000 0x3000>,
@@ -313,4 +388,8 @@
compatible = "qcom,msm-rng";
reg = <0xf9bff000 0x200>;
};
+
+ qcom,qseecom@fe806000 {
+ compatible = "qcom,qseecom";
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
index 0da3200..79cb95c 100644
--- a/arch/arm/boot/dts/msmcopper_pm.dtsi
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -27,11 +27,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -49,11 +49,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -71,11 +71,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -93,11 +93,11 @@
qcom,saw2-avs-dly= <0>;
qcom,saw2-spm-dly= <0x20000400>;
qcom,saw2-spm-ctl = <0x1>;
- qcom,spm-cmd-wfi = [03 0b 0f];
- qcom,spm-cmd-spc = [00 20 50 80 60 70 10 92
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 50 80 60 70 10 92
a0 b0 03 68 70 3b 92 a0 b0
82 2b 50 10 30 02 22 30 0f];
- qcom,spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
+ qcom,saw2-spm-cmd-pc = [00 20 10 92 a0 b0 07 3b 92
a0 b0 82 10 30 02 22 30 0f];
};
@@ -123,12 +123,12 @@
qcom,vctl-timeout-us = <50>;
qcom,vctl-port = <0x0>; /* TODO: */
qcom,phase-port = <0x1>; /* TODO: */
- qcom,spm-cmd-ret = [0b 00 20 03 22 00 0f];
- qcom,spm-cmd-spc = [00 20 32 60 70 80 42 03
- 78 80 44 22 50 3b 60 02 32
- 50 0f];
- qcom,spm-cmd-pc = [00 10 32 60 70 80 b0 11 42
- 07 01 b0 78 80 12 44 a0 50
+ qcom,saw2-spm-cmd-ret = [0b 00 20 03 22 00 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 20 32 60 70 80 0b 42 07
+ 78 80 44 22 50 3b 60 02 32
+ 50 0f];
+ qcom,saw2-spm-cmd-pc = [00 10 32 60 70 80 b0 11 0b
+ 42 07 01 b0 78 80 12 44 a0 50
3b 60 02 32 a0 50 0f];
};
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 54a8392..174a799 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -248,28 +248,17 @@
u32 enabled;
unsigned long pending[32];
void __iomem *base = gic_data_dist_base(gic);
-#ifdef CONFIG_ARCH_MSM8625
- unsigned long flags;
-#endif
if (!msm_show_resume_irq_mask)
return;
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock_irqsave(&irq_controller_lock, flags);
-#else
raw_spin_lock(&irq_controller_lock);
-#endif
for (i = 0; i * 32 < gic->max_irq; i++) {
enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
pending[i] &= enabled;
}
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
-#else
- raw_spin_lock(&irq_controller_lock);
-#endif
+ raw_spin_unlock(&irq_controller_lock);
for (i = find_first_bit(pending, gic->max_irq);
i < gic->max_irq;
@@ -283,22 +272,14 @@
{
unsigned int i;
void __iomem *base = gic_data_dist_base(gic);
-#ifdef CONFIG_ARCH_MSM8625
- unsigned long flags;
-#endif
+
gic_show_resume_irq(gic);
for (i = 0; i * 32 < gic->max_irq; i++) {
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_lock_irqsave(&irq_controller_lock, flags);
-#endif
/* disable all of them */
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
/* enable the enabled set */
writel_relaxed(gic->enabled_irqs[i],
base + GIC_DIST_ENABLE_SET + i * 4);
-#ifdef CONFIG_ARCH_MSM8625
- raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
-#endif
}
mb();
}
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 18f6d7f..4ba55de 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -32,6 +32,8 @@
CONFIG_MSM_SMD_PKG3=y
# CONFIG_MSM_SMD_DEBUG is not set
CONFIG_MSM_ONCRPCROUTER=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_ONCRPCROUTER_DEBUG is not set
# CONFIG_MSM_HW3D is not set
# CONFIG_QSD_AUDIO is not set
@@ -86,6 +88,7 @@
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
+CONFIG_MTD_UBI=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=8
CONFIG_BLK_DEV_RAM_SIZE=16384
@@ -159,6 +162,7 @@
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_UBIFS_FS=m
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index 4707556..ad1b6a6 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -32,6 +32,8 @@
CONFIG_MSM_SMD=y
CONFIG_MSM_SMD_PKG3=y
CONFIG_MSM_ONCRPCROUTER=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
# CONFIG_QSD_AUDIO is not set
# CONFIG_SURF_FFA_GPIO_KEYPAD is not set
@@ -85,6 +87,7 @@
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
+CONFIG_MTD_UBI=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=8
CONFIG_BLK_DEV_RAM_SIZE=16384
@@ -158,6 +161,7 @@
CONFIG_TMPFS=y
CONFIG_YAFFS_FS=y
CONFIG_YAFFS_DISABLE_TAGS_ECC=y
+CONFIG_UBIFS_FS=m
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 148f17f..a978c30 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -10,7 +10,6 @@
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
CONFIG_CGROUP_SCHED=y
-# CONFIG_FAIR_GROUP_SCHED is not set
CONFIG_RT_GROUP_SCHED=y
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
@@ -45,9 +44,10 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_PIL_LPASS_QDSP6V5=y
-CONFIG_MSM_TZ_LOG=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_MSM_PIL_MBA=y
CONFIG_MSM_PIL_PRONTO=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_TZ_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_OCMEM=y
CONFIG_NO_HZ=y
@@ -68,19 +68,32 @@
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-# CONFIG_SUSPEND is not set
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
+CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
CONFIG_IPV6=y
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_ROUTE_INFO=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
CONFIG_IPV6_MIP6=y
CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_IPV6_SUBTREES=y
@@ -95,8 +108,13 @@
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
+CONFIG_KS8851=m
# CONFIG_MSM_RMNET is not set
+CONFIG_DUMMY=y
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
CONFIG_INPUT_JOYSTICK=y
@@ -107,6 +125,7 @@
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM=y
CONFIG_DCC_TTY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
@@ -163,11 +182,13 @@
CONFIG_SPS=y
CONFIG_SPS_SUPPORT_BAMDMA=y
CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_MSM_IOMMU=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT4_FS=y
+CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_NLS_CODEPAGE_437=y
@@ -192,6 +213,7 @@
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_ARC4=y
CONFIG_CRYPTO_DES=y
@@ -199,4 +221,7 @@
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
-CONFIG_HW_RANDOM_MSM=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_MSM8974=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index afea042..a163829 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -192,6 +192,7 @@
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
+CONFIG_TUN=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
CONFIG_LIBRA_SDIOIF=m
@@ -227,6 +228,7 @@
CONFIG_BATTERY_MSM=y
CONFIG_SENSORS_MSM_ADC=y
CONFIG_MARIMBA_CORE=y
+CONFIG_REGULATOR_MSM_GPIO=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
@@ -243,6 +245,7 @@
CONFIG_S5K4E1=y
CONFIG_DW9712_ACT=y
CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_OV8825=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_OV7692=y
@@ -338,6 +341,5 @@
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 7e24b0d..d8e2e3c 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -192,6 +192,7 @@
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
+CONFIG_TUN=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
CONFIG_LIBRA_SDIOIF=m
@@ -228,6 +229,7 @@
CONFIG_BATTERY_MSM=y
CONFIG_SENSORS_MSM_ADC=y
CONFIG_MARIMBA_CORE=y
+CONFIG_REGULATOR_MSM_GPIO=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_DEV=y
@@ -244,6 +246,7 @@
CONFIG_S5K4E1=y
CONFIG_DW9712_ACT=y
CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_OV8825=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
CONFIG_OV7692=y
@@ -346,6 +349,5 @@
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRC_CCITT=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index 4000a0f..7de7fee 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -207,6 +207,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_MSM_RMNET_SDIO=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
@@ -260,6 +261,7 @@
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_VIDEOBUF2_MSM_MEM=y
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_RADIO_TAVARUA=y
CONFIG_MSM_KGSL=y
CONFIG_VIDEO_OUTPUT_CONTROL=y
@@ -272,6 +274,7 @@
CONFIG_FB_MSM_TRIPLE_BUFFER=y
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@@ -369,7 +372,6 @@
CONFIG_DEBUG_INFO=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index fdcd566..bead86e 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -208,6 +208,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_MSM_RMNET_SDIO=y
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
@@ -274,6 +275,7 @@
CONFIG_FB_MSM_TRIPLE_BUFFER=y
CONFIG_FB_MSM_MDP40=y
CONFIG_FB_MSM_OVERLAY=y
+CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM=y
CONFIG_FB_MSM_HDMI_ADV7520_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
@@ -377,7 +379,6 @@
CONFIG_DEBUG_PAGEALLOC=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index d5b4007..fe30dc8 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -248,6 +248,7 @@
CONFIG_DM_UEVENT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_MSM_RMNET_SDIO=y
CONFIG_SMC91X=y
CONFIG_SMC911X=y
@@ -415,7 +416,6 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
-CONFIG_MSM_IOMMU=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -443,7 +443,6 @@
CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 5e2c1a8..45339ee 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -249,6 +249,7 @@
CONFIG_DM_UEVENT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_MSM_RMNET_SDIO=y
CONFIG_SMC91X=y
CONFIG_SMC911X=y
@@ -417,7 +418,6 @@
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
-CONFIG_MSM_IOMMU=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -455,7 +455,6 @@
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 74d31b3..57e644d 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -66,7 +66,6 @@
CONFIG_MSM_SMD_PKG4=y
CONFIG_MSM_PCIE=y
CONFIG_MSM_BAM_DMUX=y
-CONFIG_MSM_RMNET_SMUX=y
CONFIG_MSM_DSPS=y
CONFIG_MSM_IPC_ROUTER=y
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
@@ -91,6 +90,7 @@
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_QDSS=y
CONFIG_MSM_SLEEP_STATS=y
+CONFIG_MSM_EBI_ERP=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L2_ERP_2BIT_PANIC=y
CONFIG_MSM_DCVS=y
@@ -256,9 +256,11 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_KS8851=m
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
+CONFIG_MSM_RMNET_SMUX=y
CONFIG_SMC91X=y
CONFIG_SMC911X=y
CONFIG_SMSC911X=y
@@ -308,7 +310,6 @@
CONFIG_SMB349_CHARGER=y
CONFIG_PM8921_CHARGER=y
CONFIG_PM8921_BMS=y
-CONFIG_PM8921_BCL=y
CONFIG_SENSORS_PM8XXX_ADC=y
CONFIG_SENSORS_EPM_ADC=y
CONFIG_THERMAL=y
@@ -388,6 +389,7 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_EHCI_MSM_HOST4=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DEBUG=y
@@ -475,7 +477,6 @@
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index 07a3f91..ca8a909 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -91,6 +91,7 @@
CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y
CONFIG_MSM_RTB=y
CONFIG_MSM_RTB_SEPARATE_CPUS=y
+CONFIG_MSM_EBI_ERP=y
CONFIG_MSM_CACHE_ERP=y
CONFIG_MSM_L1_ERR_PANIC=y
CONFIG_MSM_L2_ERP_PRINT_ACCESS_ERRORS=y
@@ -261,6 +262,7 @@
CONFIG_DM_CRYPT=y
CONFIG_NETDEVICES=y
CONFIG_DUMMY=y
+CONFIG_TUN=y
CONFIG_KS8851=m
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
@@ -390,6 +392,7 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_EHCI_MSM_HSIC=y
+CONFIG_USB_EHCI_MSM_HOST4=y
CONFIG_USB_ACM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_STORAGE_DEBUG=y
@@ -492,7 +495,6 @@
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_PID_IN_CONTEXTIDR=y
-CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=m
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index 89fb888..bb3554b 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -1,7 +1,7 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
-CONFIG_SPARSE_IRQ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_CGROUPS=y
@@ -28,6 +28,7 @@
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_MSM=y
CONFIG_ARCH_MSM9625=y
# CONFIG_MSM_STACKED_MEMORY is not set
@@ -51,7 +52,6 @@
# CONFIG_SUSPEND is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
-CONFIG_MISC_DEVICES=y
# CONFIG_ANDROID_PMEM is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
@@ -67,20 +67,17 @@
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HWMON is not set
-# CONFIG_MFD_SUPPORT is not set
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_PARTITION_ADVANCED=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_PREEMPT is not set
@@ -88,6 +85,9 @@
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_BAMDMA=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
CONFIG_KEYS=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_CBC=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 2098288..99ee2de 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -4,7 +4,7 @@
#include <linux/ioport.h>
struct arch_timer {
- struct resource res[2];
+ struct resource res[3];
};
#ifdef CONFIG_ARM_ARCH_TIMER
diff --git a/arch/arm/include/asm/mach/mmc.h b/arch/arm/include/asm/mach/mmc.h
index 745a3a4..4bcbfc2 100644
--- a/arch/arm/include/asm/mach/mmc.h
+++ b/arch/arm/include/asm/mach/mmc.h
@@ -59,8 +59,7 @@
*/
struct msm_mmc_slot_reg_data {
struct msm_mmc_reg_data *vdd_data; /* keeps VDD/VCC regulator info */
- struct msm_mmc_reg_data *vccq_data; /* keeps VCCQ regulator info */
- struct msm_mmc_reg_data *vddp_data; /* keeps VDD Pad regulator info */
+ struct msm_mmc_reg_data *vdd_io_data; /* keeps VDD IO regulator info */
};
struct msm_mmc_gpio {
@@ -147,10 +146,9 @@
unsigned int msmsdcc_fmid;
unsigned int msmsdcc_fmax;
bool nonremovable;
- bool pclk_src_dfab;
unsigned int mpm_sdiowakeup_int;
unsigned int wpswitch_gpio;
- unsigned char wpswitch_polarity;
+ bool is_wpswitch_active_low;
struct msm_mmc_slot_reg_data *vreg_data;
int is_sdio_al_client;
unsigned int *sup_clk_table;
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index 2fecc60..a40f81e 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -25,7 +25,9 @@
ARM_PERF_PMU_ID_CA7,
ARM_PERF_PMU_ID_SCORPION,
ARM_PERF_PMU_ID_SCORPIONMP,
+ ARM_PERF_PMU_ID_SCORPIONMP_L2,
ARM_PERF_PMU_ID_KRAIT,
+ ARM_PERF_PMU_ID_KRAIT_L2,
ARM_NUM_PMU_IDS,
};
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 1e54b58..37cbfcb 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -21,7 +21,7 @@
*/
enum arm_pmu_type {
ARM_PMU_DEVICE_CPU = 0,
- ARM_PMU_DEVICE_L2 = 1,
+ ARM_PMU_DEVICE_L2CC = 1,
ARM_NUM_PMU_DEVICES,
};
@@ -129,11 +129,13 @@
u64 max_period;
struct platform_device *plat_device;
struct pmu_hw_events *(*get_hw_events)(void);
+ int (*test_set_event_constraints)(struct perf_event *event);
+ int (*clear_event_constraints)(struct perf_event *event);
};
#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type);
u64 armpmu_event_update(struct perf_event *event,
struct hw_perf_event *hwc,
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c
index 81a9a71..87bb7d3 100644
--- a/arch/arm/kernel/arch_timer.c
+++ b/arch/arm/kernel/arch_timer.c
@@ -19,6 +19,7 @@
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
+#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -32,8 +33,43 @@
static unsigned long arch_timer_rate;
static int arch_timer_ppi;
static int arch_timer_ppi2;
+static int is_irq_percpu;
static struct clock_event_device __percpu **arch_timer_evt;
+static void __iomem *timer_base;
+
+static u32 timer_reg_read_cp15(int reg);
+static void timer_reg_write_cp15(int reg, u32 val);
+static inline cycle_t counter_get_cntpct_cp15(void);
+static inline cycle_t counter_get_cntvct_cp15(void);
+
+static u32 timer_reg_read_mem(int reg);
+static void timer_reg_write_mem(int reg, u32 val);
+static inline cycle_t counter_get_cntpct_mem(void);
+static inline cycle_t counter_get_cntvct_mem(void);
+
+struct arch_timer_operations {
+ void (*reg_write)(int, u32);
+ u32 (*reg_read)(int);
+ cycle_t (*get_cntpct)(void);
+ cycle_t (*get_cntvct)(void);
+};
+
+static struct arch_timer_operations arch_timer_ops_cp15 = {
+ .reg_read = &timer_reg_read_cp15,
+ .reg_write = &timer_reg_write_cp15,
+ .get_cntpct = &counter_get_cntpct_cp15,
+ .get_cntvct = &counter_get_cntvct_cp15,
+};
+
+static struct arch_timer_operations arch_timer_ops_mem = {
+ .reg_read = &timer_reg_read_mem,
+ .reg_write = &timer_reg_write_mem,
+ .get_cntpct = &counter_get_cntpct_mem,
+ .get_cntvct = &counter_get_cntvct_mem,
+};
+
+static struct arch_timer_operations *arch_specific_timer = &arch_timer_ops_cp15;
/*
* Architected system timer support.
@@ -47,7 +83,29 @@
#define ARCH_TIMER_REG_FREQ 1
#define ARCH_TIMER_REG_TVAL 2
-static void arch_timer_reg_write(int reg, u32 val)
+/* Iomapped Register Offsets */
+#define QTIMER_CNTP_LOW_REG 0x000
+#define QTIMER_CNTP_HIGH_REG 0x004
+#define QTIMER_CNTV_LOW_REG 0x008
+#define QTIMER_CNTV_HIGH_REG 0x00C
+#define QTIMER_CTRL_REG 0x02C
+#define QTIMER_FREQ_REG 0x010
+#define QTIMER_CNTP_TVAL_REG 0x028
+#define QTIMER_CNTV_TVAL_REG 0x038
+
+static void timer_reg_write_mem(int reg, u32 val)
+{
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ __raw_writel(val, timer_base + QTIMER_CTRL_REG);
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ __raw_writel(val, timer_base + QTIMER_CNTP_TVAL_REG);
+ break;
+ }
+}
+
+static void timer_reg_write_cp15(int reg, u32 val)
{
switch (reg) {
case ARCH_TIMER_REG_CTRL:
@@ -61,7 +119,28 @@
isb();
}
-static u32 arch_timer_reg_read(int reg)
+static u32 timer_reg_read_mem(int reg)
+{
+ u32 val;
+
+ switch (reg) {
+ case ARCH_TIMER_REG_CTRL:
+ val = __raw_readl(timer_base + QTIMER_CTRL_REG);
+ break;
+ case ARCH_TIMER_REG_FREQ:
+ val = __raw_readl(timer_base + QTIMER_FREQ_REG);
+ break;
+ case ARCH_TIMER_REG_TVAL:
+ val = __raw_readl(timer_base + QTIMER_CNTP_TVAL_REG);
+ break;
+ default:
+ BUG();
+ }
+
+ return val;
+}
+
+static u32 timer_reg_read_cp15(int reg)
{
u32 val;
@@ -87,10 +166,11 @@
struct clock_event_device *evt;
unsigned long ctrl;
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+ ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
ctrl |= ARCH_TIMER_CTRL_IT_MASK;
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+ arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL,
+ ctrl);
evt = *__this_cpu_ptr(arch_timer_evt);
evt->event_handler(evt);
return IRQ_HANDLED;
@@ -103,9 +183,9 @@
{
unsigned long ctrl;
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+ ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+ arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
}
static void arch_timer_set_mode(enum clock_event_mode mode,
@@ -126,12 +206,12 @@
{
unsigned long ctrl;
- ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL);
+ ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
ctrl |= ARCH_TIMER_CTRL_ENABLE;
ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl);
- arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt);
+ arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
+ arch_specific_timer->reg_write(ARCH_TIMER_REG_TVAL, evt);
return 0;
}
@@ -168,19 +248,16 @@
static int local_timer_is_architected(void)
{
return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
- ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
+ ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
}
static int arch_timer_available(void)
{
unsigned long freq;
- if (!local_timer_is_architected())
- return -ENXIO;
-
if (arch_timer_rate == 0) {
- arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0);
- freq = arch_timer_reg_read(ARCH_TIMER_REG_FREQ);
+ arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, 0);
+ freq = arch_specific_timer->reg_read(ARCH_TIMER_REG_FREQ);
/* Check the timer frequency. */
if (freq == 0) {
@@ -196,33 +273,57 @@
return 0;
}
-static inline cycle_t arch_counter_get_cntpct(void)
+static inline cycle_t counter_get_cntpct_mem(void)
{
- u32 cvall, cvalh;
+ u32 cvall, cvalh, thigh;
- asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
+ do {
+ cvalh = __raw_readl(timer_base + QTIMER_CNTP_HIGH_REG);
+ cvall = __raw_readl(timer_base + QTIMER_CNTP_LOW_REG);
+ thigh = __raw_readl(timer_base + QTIMER_CNTP_HIGH_REG);
+ } while (cvalh != thigh);
return ((cycle_t) cvalh << 32) | cvall;
}
-static inline cycle_t arch_counter_get_cntvct(void)
+static inline cycle_t counter_get_cntpct_cp15(void)
+{
+ u32 cvall, cvalh;
+
+ asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
+ return ((cycle_t) cvalh << 32) | cvall;
+}
+
+static inline cycle_t counter_get_cntvct_mem(void)
+{
+ u32 cvall, cvalh, thigh;
+
+ do {
+ cvalh = __raw_readl(timer_base + QTIMER_CNTV_HIGH_REG);
+ cvall = __raw_readl(timer_base + QTIMER_CNTV_LOW_REG);
+ thigh = __raw_readl(timer_base + QTIMER_CNTV_HIGH_REG);
+ } while (cvalh != thigh);
+
+ return ((cycle_t) cvalh << 32) | cvall;
+}
+
+static inline cycle_t counter_get_cntvct_cp15(void)
{
u32 cvall, cvalh;
asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
-
return ((cycle_t) cvalh << 32) | cvall;
}
static cycle_t arch_counter_read(struct clocksource *cs)
{
- return arch_counter_get_cntpct();
+ return arch_specific_timer->get_cntpct();
}
#ifdef ARCH_HAS_READ_CURRENT_TIMER
int read_current_timer(unsigned long *timer_val)
{
- *timer_val = (unsigned long)arch_counter_get_cntpct();
+ *timer_val = (unsigned long)arch_specific_timer->get_cntpct();
return 0;
}
#endif
@@ -239,7 +340,7 @@
{
cycle_t cntvct;
- cntvct = arch_counter_get_cntvct();
+ cntvct = arch_specific_timer->get_cntvct();
/*
* The sched_clock infrastructure only knows about counters
@@ -273,6 +374,11 @@
{
int err;
+ if (timer_base)
+ arch_specific_timer = &arch_timer_ops_mem;
+ else if (!local_timer_is_architected())
+ return -ENXIO;
+
err = arch_timer_available();
if (err)
return err;
@@ -289,8 +395,12 @@
set_delay_fn(read_current_timer_delay_loop);
#endif
- err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
+ if (is_irq_percpu)
+ err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
"arch_timer", arch_timer_evt);
+ else
+ err = request_irq(arch_timer_ppi, arch_timer_handler, 0,
+ "arch_timer", arch_timer_evt);
if (err) {
pr_err("arch_timer: can't register interrupt %d (%d)\n",
arch_timer_ppi, err);
@@ -298,8 +408,13 @@
}
if (arch_timer_ppi2) {
- err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler,
- "arch_timer", arch_timer_evt);
+ if (is_irq_percpu)
+ err = request_percpu_irq(arch_timer_ppi2,
+ arch_timer_handler, "arch_timer",
+ arch_timer_evt);
+ else
+ err = request_irq(arch_timer_ppi2, arch_timer_handler,
+ 0, "arch_timer", arch_timer_evt);
if (err) {
pr_err("arch_timer: can't register interrupt %d (%d)\n",
arch_timer_ppi2, err);
@@ -336,6 +451,16 @@
if (at->res[1].start > 0 && (at->res[1].flags & IORESOURCE_IRQ))
arch_timer_ppi2 = at->res[1].start;
+ if (at->res[2].start > 0 && at->res[2].end > 0 &&
+ (at->res[2].flags & IORESOURCE_MEM))
+ timer_base = ioremap(at->res[2].start,
+ resource_size(&at->res[2]));
+
+ if (!timer_base) {
+ pr_err("arch_timer: cant map timer base\n");
+ return -ENOMEM;
+ }
+
return arch_timer_common_register();
}
@@ -366,6 +491,20 @@
pr_err("arch_timer: interrupt not specified in timer node\n");
return -ENODEV;
}
+
+ if (of_get_address(np, 0, NULL, NULL)) {
+ timer_base = of_iomap(np, 0);
+ if (!timer_base) {
+ pr_err("arch_timer: cant map timer base\n");
+ return -ENOMEM;
+ }
+ }
+
+ if (of_get_property(np, "irq-is-not-percpu", NULL))
+ is_irq_percpu = 0;
+ else
+ is_irq_percpu = 1;
+
arch_timer_ppi = ret;
ret = irq_of_parse_and_map(np, 1);
if (ret > 0)
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index af6e7e6..e37b28b 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -28,6 +28,8 @@
#include <asm/pmu.h>
#include <asm/stacktrace.h>
+#include <linux/cpu_pm.h>
+
/*
* ARMv6 supports a maximum of 3 events, starting from index 0. If we add
* another platform that supports more, we need to increase this to be the
@@ -271,6 +273,10 @@
hw_events->events[idx] = NULL;
clear_bit(idx, hw_events->used_mask);
+ /* Clear event constraints. */
+ if (armpmu->clear_event_constraints)
+ armpmu->clear_event_constraints(event);
+
perf_event_update_userpage(event);
}
@@ -284,6 +290,17 @@
int err = 0;
perf_pmu_disable(event->pmu);
+ /*
+ * Tests if event is constrained. If not sets it so that next
+ * collision can be detected.
+ */
+ if (armpmu->test_set_event_constraints)
+ if (armpmu->test_set_event_constraints(event) < 0) {
+ pr_err("Event: %llx failed constraint check.\n",
+ event->attr.config);
+ event->state = PERF_EVENT_STATE_OFF;
+ goto out;
+ }
/* If we don't have a space for the counter then finish early. */
idx = armpmu->get_event_idx(hw_events, hwc);
@@ -383,10 +400,7 @@
{
int i, irq, irqs;
struct platform_device *pmu_device = armpmu->plat_device;
-#if 0
- struct arm_pmu_platdata *plat =
- dev_get_platdata(&pmu_device->dev);
-#endif
+
irqs = min(pmu_device->num_resources, num_possible_cpus());
for (i = 0; i < irqs; ++i) {
@@ -394,13 +408,6 @@
continue;
irq = platform_get_irq(pmu_device, i);
armpmu->free_pmu_irq(irq);
-#if 0
- if (irq >= 0) {
- if (plat && plat->disable_irq)
- plat->disable_irq(irq);
- free_irq(irq, armpmu);
- }
-#endif
}
release_pmu(armpmu->type);
@@ -462,19 +469,6 @@
return err;
}
-#if 0
- err = request_irq(irq, handle_irq,
- IRQF_DISABLED | IRQF_NOBALANCING,
- "arm-pmu", armpmu);
- if (err) {
- pr_err("unable to request IRQ%d for ARM PMU counters\n",
- irq);
- armpmu_release_hardware(armpmu);
- return err;
- } else if (plat && plat->enable_irq)
- plat->enable_irq(irq);
-#endif
-
cpumask_set_cpu(i, &armpmu->active_irqs);
}
@@ -538,6 +532,7 @@
return -EPERM;
}
+
/*
* Store the event encoding into the config_base field.
*/
@@ -616,7 +611,7 @@
armpmu->stop();
}
-static void __init armpmu_init(struct arm_pmu *armpmu)
+static void armpmu_init(struct arm_pmu *armpmu)
{
atomic_set(&armpmu->active_events, 0);
mutex_init(&armpmu->reserve_mutex);
@@ -633,7 +628,7 @@
};
}
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
{
armpmu_init(armpmu);
return perf_pmu_register(&armpmu->pmu, name, type);
@@ -644,6 +639,7 @@
#include "perf_event_v6.c"
#include "perf_event_v7.c"
#include "perf_event_msm_krait.c"
+#include "perf_event_msm.c"
/*
* Ensure the PMU has sane values out of reset.
@@ -734,10 +730,76 @@
return NOTIFY_OK;
}
+static void armpmu_update_counters(void)
+{
+ struct pmu_hw_events *hw_events;
+ int idx;
+
+ if (!cpu_pmu)
+ return;
+
+ hw_events = cpu_pmu->get_hw_events();
+
+ for (idx = 0; idx <= cpu_pmu->num_events; ++idx) {
+ struct perf_event *event = hw_events->events[idx];
+
+ if (!event)
+ continue;
+
+ armpmu_read(event);
+ }
+}
+
+static int cpu_has_active_perf(void)
+{
+ struct pmu_hw_events *hw_events;
+ int enabled;
+
+ if (!cpu_pmu)
+ return 0;
+
+ hw_events = cpu_pmu->get_hw_events();
+ enabled = bitmap_weight(hw_events->used_mask, cpu_pmu->num_events);
+
+ if (enabled)
+ /*Even one event's existence is good enough.*/
+ return 1;
+
+ return 0;
+}
+
static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
.notifier_call = pmu_cpu_notify,
};
+/*TODO: Unify with pending patch from ARM */
+static int perf_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
+ void *v)
+{
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ if (cpu_has_active_perf()) {
+ armpmu_update_counters();
+ perf_pmu_disable(&cpu_pmu->pmu);
+ }
+ break;
+
+ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ if (cpu_has_active_perf() && cpu_pmu->reset) {
+ cpu_pmu->reset(NULL);
+ perf_pmu_enable(&cpu_pmu->pmu);
+ }
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block perf_cpu_pm_notifier_block = {
+ .notifier_call = perf_cpu_pm_notifier,
+};
+
/*
* CPU PMU identification and registration.
*/
@@ -790,11 +852,11 @@
} else if (0x51 == implementor) {
switch (part_number) {
case 0x00F0: /* 8x50 & 7x30*/
-// cpu_pmu = armv7_scorpion_pmu_init();
+ cpu_pmu = armv7_scorpion_pmu_init();
break;
case 0x02D0: /* 8x60 */
// fabricmon_pmu_init();
-// cpu_pmu = armv7_scorpionmp_pmu_init();
+ cpu_pmu = armv7_scorpionmp_pmu_init();
// scorpionmp_l2_pmu_init();
break;
case 0x0490: /* 8960 sim */
@@ -814,6 +876,7 @@
cpu_pmu_init(cpu_pmu);
register_cpu_notifier(&pmu_cpu_notifier);
armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
+ cpu_pm_register_notifier(&perf_cpu_pm_notifier_block);
} else {
pr_info("no hardware support available\n");
}
diff --git a/arch/arm/kernel/perf_event_msm.c b/arch/arm/kernel/perf_event_msm.c
index 0ca5164..46fa8fe 100644
--- a/arch/arm/kernel/perf_event_msm.c
+++ b/arch/arm/kernel/perf_event_msm.c
@@ -12,7 +12,7 @@
*/
#include <linux/cpumask.h>
-
+#include <asm/cp15.h>
#include <asm/vfp.h>
#include <asm/system.h>
#include "../vfp/vfpinstr.h"
@@ -143,12 +143,16 @@
* combined.
*/
[C(OP_READ)] = {
- [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS,
- [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL,
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_WRITE)] = {
- [C(RESULT_ACCESS)] = ARMV7_PERFCTR_DCACHE_ACCESS,
- [C(RESULT_MISS)] = ARMV7_PERFCTR_DCACHE_REFILL,
+ [C(RESULT_ACCESS)]
+ = ARMV7_PERFCTR_L1_DCACHE_ACCESS,
+ [C(RESULT_MISS)]
+ = ARMV7_PERFCTR_L1_DCACHE_REFILL,
},
[C(OP_PREFETCH)] = {
[C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
@@ -236,6 +240,13 @@
},
};
+static int msm_scorpion_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &armv7_scorpion_perf_map,
+ &armv7_scorpion_perf_cache_map, 0xfffff);
+}
+
+
struct scorpion_evt {
/*
* The scorpion_evt_type field corresponds to the actual Scorpion
@@ -483,9 +494,9 @@
u32 v_orig_val;
u32 f_orig_val;
- /* CPACR Enable CP10 access */
+ /* CPACR Enable CP10 and CP11 access */
v_orig_val = get_copro_access();
- venum_new_val = v_orig_val | CPACC_SVC(10);
+ venum_new_val = v_orig_val | CPACC_SVC(10) | CPACC_SVC(11);
set_copro_access(venum_new_val);
/* Store orig venum val */
__get_cpu_var(venum_orig_val) = v_orig_val;
@@ -551,17 +562,13 @@
static void scorpion_clear_pmuregs(void)
{
- unsigned long flags;
-
scorpion_write_lpm0(0);
scorpion_write_lpm1(0);
scorpion_write_lpm2(0);
scorpion_write_l2lpm(0);
- raw_spin_lock_irqsave(&pmu_lock, flags);
scorpion_pre_vlpm();
scorpion_write_vlpm(0);
scorpion_post_vlpm();
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
}
static void scorpion_clearpmu(u32 grp, u32 val, u32 evt_code)
@@ -585,9 +592,11 @@
u32 gr;
unsigned long event;
struct scorpion_evt evtinfo;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+
/* Disable counter and interrupt */
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Disable counter */
armv7_pmnc_disable_counter(idx);
@@ -596,7 +605,7 @@
* Clear lpm code (if destined for PMNx counters)
* We don't need to set the event if it's a cycle count
*/
- if (idx != ARMV7_CYCLE_COUNTER) {
+ if (idx != ARMV7_IDX_CYCLE_COUNTER) {
val = hwc->config_base;
val &= SCORPION_EVTYPE_EVENT;
@@ -613,10 +622,11 @@
armv7_pmnc_disable_intens(idx);
scorpion_dis_out:
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
-static void scorpion_pmu_enable_event(struct hw_perf_event *hwc, int idx)
+static void scorpion_pmu_enable_event(struct hw_perf_event *hwc,
+ int idx, int cpu)
{
unsigned long flags;
u32 val = 0;
@@ -624,12 +634,13 @@
unsigned long event;
struct scorpion_evt evtinfo;
unsigned long long prev_count = local64_read(&hwc->prev_count);
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
/*
* Enable counter and interrupt, and set the counter to count
* the event that we're interested in.
*/
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Disable counter */
armv7_pmnc_disable_counter(idx);
@@ -638,7 +649,7 @@
* Set event (if destined for PMNx counters)
* We don't need to set the event if it's a cycle count
*/
- if (idx != ARMV7_CYCLE_COUNTER) {
+ if (idx != ARMV7_IDX_CYCLE_COUNTER) {
val = hwc->config_base;
val &= SCORPION_EVTYPE_EVENT;
@@ -673,59 +684,12 @@
armv7_pmnc_enable_counter(idx);
scorpion_out:
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
-}
-
-static void enable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
-
- enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
-}
-
-static void disable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
-
- disable_percpu_irq(irq);
-}
-
-static int
-msm_request_irq(int irq, irq_handler_t *handle_irq)
-{
- int err = 0;
- int cpu;
-
- err = request_percpu_irq(irq, *handle_irq, "armpmu",
- &cpu_hw_events);
-
- if (!err) {
- for_each_cpu(cpu, cpu_online_mask) {
- smp_call_function_single(cpu,
- enable_irq_callback, &irq, 1);
- }
- }
-
- return err;
-}
-
-static void
-msm_free_irq(int irq)
-{
- int cpu;
-
- if (irq >= 0) {
- for_each_cpu(cpu, cpu_online_mask) {
- smp_call_function_single(cpu,
- disable_irq_callback, &irq, 1);
- }
- free_percpu_irq(irq, &cpu_hw_events);
- }
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void scorpion_pmu_reset(void *info)
{
- u32 idx, nb_cnt = armpmu->num_events;
+ u32 idx, nb_cnt = cpu_pmu->num_events;
/* Stop all counters and their interrupts */
for (idx = 1; idx < nb_cnt; ++idx) {
@@ -751,7 +715,7 @@
.disable = scorpion_pmu_disable_event,
.read_counter = armv7pmu_read_counter,
.write_counter = armv7pmu_write_counter,
- .raw_event_mask = 0xFFFFF,
+ .map_event = msm_scorpion_map_event,
.get_event_idx = armv7pmu_get_event_idx,
.start = armv7pmu_start,
.stop = armv7pmu_stop,
@@ -759,33 +723,29 @@
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init armv7_scorpion_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpion_pmu_init(void)
{
scorpion_pmu.id = ARM_PERF_PMU_ID_SCORPION;
scorpion_pmu.name = "ARMv7 Scorpion";
- scorpion_pmu.cache_map = &armv7_scorpion_perf_cache_map;
- scorpion_pmu.event_map = &armv7_scorpion_perf_map;
scorpion_pmu.num_events = armv7_read_num_pmnc_events();
scorpion_clear_pmuregs();
return &scorpion_pmu;
}
-static const struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
{
scorpion_pmu.id = ARM_PERF_PMU_ID_SCORPIONMP;
scorpion_pmu.name = "ARMv7 Scorpion-MP";
- scorpion_pmu.cache_map = &armv7_scorpion_perf_cache_map;
- scorpion_pmu.event_map = &armv7_scorpion_perf_map;
scorpion_pmu.num_events = armv7_read_num_pmnc_events();
scorpion_clear_pmuregs();
return &scorpion_pmu;
}
#else
-static const struct arm_pmu *__init armv7_scorpion_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpion_pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
+static struct arm_pmu *__init armv7_scorpionmp_pmu_init(void)
{
return NULL;
}
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 8dbd047..1b115b4 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -58,6 +58,17 @@
static u32 krait_ver, evt_index;
static u32 krait_max_l1_reg;
+
+/*
+ * Every 4 bytes represents a prefix.
+ * Every nibble represents a register.
+ * Every bit represents a group within a register.
+ *
+ * This supports up to 4 groups per register, upto 8
+ * registers per prefix and upto 2 prefixes.
+ */
+static DEFINE_PER_CPU(u64, pmu_bitmap);
+
static const unsigned armv7_krait_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
[PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED,
@@ -556,6 +567,58 @@
}
}
+/*
+ * We check for column exclusion constraints here.
+ * Two events cant have same reg and same group.
+ */
+static int msm_test_set_ev_constraint(struct perf_event *event)
+{
+ u32 krait_evt_type = event->attr.config & KRAIT_EVENT_MASK;
+ u8 prefix = (krait_evt_type & 0xF0000) >> 16;
+ u8 reg = (krait_evt_type & 0x0F000) >> 12;
+ u8 group = krait_evt_type & 0x0000F;
+ u64 cpu_pmu_bitmap = __get_cpu_var(pmu_bitmap);
+ u64 bitmap_t;
+
+ /* Return if non MSM event. */
+ if (!prefix)
+ return 0;
+
+ bitmap_t = 1 << (((prefix - 1) * 32) + (reg * 4) + group);
+
+ /* Set it if not already set. */
+ if (!(cpu_pmu_bitmap & bitmap_t)) {
+ cpu_pmu_bitmap |= bitmap_t;
+ __get_cpu_var(pmu_bitmap) = cpu_pmu_bitmap;
+ return 1;
+ }
+ /* Bit is already set. Constraint failed. */
+ return -EPERM;
+}
+
+static int msm_clear_ev_constraint(struct perf_event *event)
+{
+ u32 krait_evt_type = event->attr.config & KRAIT_EVENT_MASK;
+ u8 prefix = (krait_evt_type & 0xF0000) >> 16;
+ u8 reg = (krait_evt_type & 0x0F000) >> 12;
+ u8 group = krait_evt_type & 0x0000F;
+ u64 cpu_pmu_bitmap = __get_cpu_var(pmu_bitmap);
+ u64 bitmap_t;
+
+ /* Return if non MSM event. */
+ if (!prefix)
+ return 0;
+
+ bitmap_t = 1 << (((prefix - 1) * 32) + (reg * 4) + group);
+
+ /* Clear constraint bit. */
+ cpu_pmu_bitmap &= ~(bitmap_t);
+
+ __get_cpu_var(pmu_bitmap) = cpu_pmu_bitmap;
+
+ return 1;
+}
+
static struct arm_pmu krait_pmu = {
.handle_irq = armv7pmu_handle_irq,
.request_pmu_irq = msm_request_irq,
@@ -568,6 +631,8 @@
.start = armv7pmu_start,
.stop = armv7pmu_stop,
.reset = krait_pmu_reset,
+ .test_set_event_constraints = msm_test_set_ev_constraint,
+ .clear_event_constraints = msm_clear_ev_constraint,
.max_period = (1LLU << 32) - 1,
};
diff --git a/arch/arm/kernel/perf_event_msm_krait_l2.c b/arch/arm/kernel/perf_event_msm_krait_l2.c
deleted file mode 100644
index baa05ac..0000000
--- a/arch/arm/kernel/perf_event_msm_krait_l2.c
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * Copyright (c) 2011, 2012 Code Aurora Forum. 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.
- */
-#ifdef CONFIG_ARCH_MSM_KRAIT
-
-#include <linux/irq.h>
-
-#include <mach/msm-krait-l2-accessors.h>
-
-#define MAX_L2_PERIOD ((1ULL << 32) - 1)
-#define MAX_KRAIT_L2_CTRS 5
-
-#define L2PMCCNTR 0x409
-#define L2PMCCNTCR 0x408
-#define L2PMCCNTSR 0x40A
-#define L2CYCLE_CTR_BIT 31
-#define L2CYCLE_CTR_EVENT_IDX 4
-#define L2CYCLE_CTR_RAW_CODE 0xfe
-
-#define L2PMOVSR 0x406
-
-#define L2PMCR 0x400
-#define L2PMCR_RESET_ALL 0x6
-#define L2PMCR_GLOBAL_ENABLE 0x1
-#define L2PMCR_GLOBAL_DISABLE 0x0
-
-#define L2PMCNTENSET 0x403
-#define L2PMCNTENCLR 0x402
-
-#define L2PMINTENSET 0x405
-#define L2PMINTENCLR 0x404
-
-#define IA_L2PMXEVCNTCR_BASE 0x420
-#define IA_L2PMXEVTYPER_BASE 0x424
-#define IA_L2PMRESX_BASE 0x410
-#define IA_L2PMXEVFILTER_BASE 0x423
-#define IA_L2PMXEVCNTR_BASE 0x421
-
-/* event format is -e rsRCCG See get_event_desc() */
-
-#define EVENT_REG_MASK 0xf000
-#define EVENT_GROUPSEL_MASK 0x000f
-#define EVENT_GROUPCODE_MASK 0x0ff0
-#define EVENT_REG_SHIFT 12
-#define EVENT_GROUPCODE_SHIFT 4
-
-#define RESRX_VALUE_EN 0x80000000
-
-static struct platform_device *l2_pmu_device;
-
-struct hw_krait_l2_pmu {
- struct perf_event *events[MAX_KRAIT_L2_CTRS];
- unsigned long active_mask[BITS_TO_LONGS(MAX_KRAIT_L2_CTRS)];
- raw_spinlock_t lock;
-};
-
-struct hw_krait_l2_pmu hw_krait_l2_pmu;
-
-struct event_desc {
- int event_groupsel;
- int event_reg;
- int event_group_code;
-};
-
-void get_event_desc(u64 config, struct event_desc *evdesc)
-{
- /* L2PMEVCNTRX */
- evdesc->event_reg = (config & EVENT_REG_MASK) >> EVENT_REG_SHIFT;
- /* Group code (row ) */
- evdesc->event_group_code =
- (config & EVENT_GROUPCODE_MASK) >> EVENT_GROUPCODE_SHIFT;
- /* Group sel (col) */
- evdesc->event_groupsel = (config & EVENT_GROUPSEL_MASK);
-
- pr_debug("%s: reg: %x, group_code: %x, groupsel: %x\n", __func__,
- evdesc->event_reg, evdesc->event_group_code,
- evdesc->event_groupsel);
-}
-
-static void set_evcntcr(int ctr)
-{
- u32 evtcr_reg = (ctr * 16) + IA_L2PMXEVCNTCR_BASE;
-
- set_l2_indirect_reg(evtcr_reg, 0x0);
-}
-
-static void set_evtyper(int event_groupsel, int event_reg, int ctr)
-{
- u32 evtype_reg = (ctr * 16) + IA_L2PMXEVTYPER_BASE;
- u32 evtype_val = event_groupsel + (4 * event_reg);
-
- set_l2_indirect_reg(evtype_reg, evtype_val);
-}
-
-static void set_evres(int event_groupsel, int event_reg, int event_group_code)
-{
- u32 group_reg = event_reg + IA_L2PMRESX_BASE;
- u32 group_val =
- RESRX_VALUE_EN | (event_group_code << (8 * event_groupsel));
- u32 resr_val;
- u32 group_byte = 0xff;
- u32 group_mask = ~(group_byte << (8 * event_groupsel));
-
- resr_val = get_l2_indirect_reg(group_reg);
- resr_val &= group_mask;
- resr_val |= group_val;
-
- set_l2_indirect_reg(group_reg, resr_val);
-}
-
-static void set_evfilter_task_mode(int ctr)
-{
- u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
- u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
-
- set_l2_indirect_reg(filter_reg, filter_val);
-}
-
-static void set_evfilter_sys_mode(int ctr)
-{
- u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
- u32 filter_val = 0x000f003f;
-
- set_l2_indirect_reg(filter_reg, filter_val);
-}
-
-static void enable_intenset(u32 idx)
-{
- if (idx == L2CYCLE_CTR_EVENT_IDX)
- set_l2_indirect_reg(L2PMINTENSET, 1 << L2CYCLE_CTR_BIT);
- else
- set_l2_indirect_reg(L2PMINTENSET, 1 << idx);
-}
-
-static void disable_intenclr(u32 idx)
-{
- if (idx == L2CYCLE_CTR_EVENT_IDX)
- set_l2_indirect_reg(L2PMINTENCLR, 1 << L2CYCLE_CTR_BIT);
- else
- set_l2_indirect_reg(L2PMINTENCLR, 1 << idx);
-}
-
-static void enable_counter(u32 idx)
-{
- if (idx == L2CYCLE_CTR_EVENT_IDX)
- set_l2_indirect_reg(L2PMCNTENSET, 1 << L2CYCLE_CTR_BIT);
- else
- set_l2_indirect_reg(L2PMCNTENSET, 1 << idx);
-}
-
-static void disable_counter(u32 idx)
-{
- if (idx == L2CYCLE_CTR_EVENT_IDX)
- set_l2_indirect_reg(L2PMCNTENCLR, 1 << L2CYCLE_CTR_BIT);
- else
- set_l2_indirect_reg(L2PMCNTENCLR, 1 << idx);
-}
-
-static u64 read_counter(u32 idx)
-{
- u32 val;
- u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
-
- if (idx == L2CYCLE_CTR_EVENT_IDX)
- val = get_l2_indirect_reg(L2PMCCNTR);
- else
- val = get_l2_indirect_reg(counter_reg);
-
- return val;
-}
-
-static void write_counter(u32 idx, u32 val)
-{
- u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
-
- if (idx == L2CYCLE_CTR_EVENT_IDX)
- set_l2_indirect_reg(L2PMCCNTR, val);
- else
- set_l2_indirect_reg(counter_reg, val);
-}
-
-static int
-pmu_event_set_period(struct perf_event *event,
- struct hw_perf_event *hwc, int idx)
-{
- s64 left = local64_read(&hwc->period_left);
- s64 period = hwc->sample_period;
- int ret = 0;
-
- if (unlikely(left <= -period)) {
- left = period;
- local64_set(&hwc->period_left, left);
- hwc->last_period = period;
- ret = 1;
- }
-
- if (unlikely(left <= 0)) {
- left += period;
- local64_set(&hwc->period_left, left);
- hwc->last_period = period;
- ret = 1;
- }
-
- if (left > (s64) MAX_L2_PERIOD)
- left = MAX_L2_PERIOD;
-
- local64_set(&hwc->prev_count, (u64)-left);
-
- write_counter(idx, (u64) (-left) & 0xffffffff);
-
- perf_event_update_userpage(event);
-
- return ret;
-}
-
-static u64
-pmu_event_update(struct perf_event *event, struct hw_perf_event *hwc, int idx,
- int overflow)
-{
- u64 prev_raw_count, new_raw_count;
- u64 delta;
-
-again:
- prev_raw_count = local64_read(&hwc->prev_count);
- new_raw_count = read_counter(idx);
-
- if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
- new_raw_count) != prev_raw_count)
- goto again;
-
- new_raw_count &= MAX_L2_PERIOD;
- prev_raw_count &= MAX_L2_PERIOD;
-
- if (overflow)
- delta = MAX_L2_PERIOD - prev_raw_count + new_raw_count;
- else
- delta = new_raw_count - prev_raw_count;
-
- local64_add(delta, &event->count);
- local64_sub(delta, &hwc->period_left);
-
- pr_debug("%s: new: %lld, prev: %lld, event: %ld count: %lld\n",
- __func__, new_raw_count, prev_raw_count,
- hwc->config_base, local64_read(&event->count));
-
- return new_raw_count;
-}
-
-static void krait_l2_read(struct perf_event *event)
-{
- struct hw_perf_event *hwc = &event->hw;
-
- pmu_event_update(event, hwc, hwc->idx, 0);
-}
-
-static void krait_l2_stop_counter(struct perf_event *event, int flags)
-{
- struct hw_perf_event *hwc = &event->hw;
- int idx = hwc->idx;
-
- if (!(hwc->state & PERF_HES_STOPPED)) {
- disable_intenclr(idx);
- disable_counter(idx);
-
- pmu_event_update(event, hwc, idx, 0);
- hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
- }
-
- pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, hwc->config_base,
- idx);
-}
-
-static void krait_l2_start_counter(struct perf_event *event, int flags)
-{
- struct hw_perf_event *hwc = &event->hw;
- int idx = hwc->idx;
- struct event_desc evdesc;
-
- if (flags & PERF_EF_RELOAD)
- WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
-
- hwc->state = 0;
-
- pmu_event_set_period(event, hwc, idx);
-
- if (hwc->config_base == L2CYCLE_CTR_RAW_CODE)
- goto out;
-
- set_evcntcr(idx);
-
- memset(&evdesc, 0, sizeof(evdesc));
-
- get_event_desc(hwc->config_base, &evdesc);
-
- set_evtyper(evdesc.event_groupsel, evdesc.event_reg, idx);
-
- set_evres(evdesc.event_groupsel, evdesc.event_reg,
- evdesc.event_group_code);
-
- if (event->cpu < 0)
- set_evfilter_task_mode(idx);
- else
- set_evfilter_sys_mode(idx);
-
-out:
- enable_intenset(idx);
- enable_counter(idx);
-
- pr_debug
- ("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
- __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
-}
-
-static void krait_l2_del_event(struct perf_event *event, int flags)
-{
- struct hw_perf_event *hwc = &event->hw;
- int idx = hwc->idx;
- unsigned long iflags;
-
- raw_spin_lock_irqsave(&hw_krait_l2_pmu.lock, iflags);
-
- clear_bit(idx, (long unsigned int *)(&hw_krait_l2_pmu.active_mask));
-
- krait_l2_stop_counter(event, PERF_EF_UPDATE);
- hw_krait_l2_pmu.events[idx] = NULL;
- hwc->idx = -1;
-
- raw_spin_unlock_irqrestore(&hw_krait_l2_pmu.lock, iflags);
-
- pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
-
- perf_event_update_userpage(event);
-}
-
-static int krait_l2_add_event(struct perf_event *event, int flags)
-{
- int ctr = 0;
- struct hw_perf_event *hwc = &event->hw;
- unsigned long iflags;
- int err = 0;
-
- perf_pmu_disable(event->pmu);
-
- raw_spin_lock_irqsave(&hw_krait_l2_pmu.lock, iflags);
-
- /* Cycle counter has a resrvd index */
- if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
- if (hw_krait_l2_pmu.events[L2CYCLE_CTR_EVENT_IDX]) {
- pr_err("%s: Stale cycle ctr event ptr !\n", __func__);
- err = -EINVAL;
- goto out;
- }
- hwc->idx = L2CYCLE_CTR_EVENT_IDX;
- hw_krait_l2_pmu.events[L2CYCLE_CTR_EVENT_IDX] = event;
- set_bit(L2CYCLE_CTR_EVENT_IDX,
- (long unsigned int *)&hw_krait_l2_pmu.active_mask);
- goto skip_ctr_loop;
- }
-
- for (ctr = 0; ctr < MAX_KRAIT_L2_CTRS - 1; ctr++) {
- if (!hw_krait_l2_pmu.events[ctr]) {
- hwc->idx = ctr;
- hw_krait_l2_pmu.events[ctr] = event;
- set_bit(ctr,
- (long unsigned int *)
- &hw_krait_l2_pmu.active_mask);
- break;
- }
- }
-
- if (hwc->idx < 0) {
- err = -ENOSPC;
- pr_err("%s: No space for event: %llx!!\n", __func__,
- event->attr.config);
- goto out;
- }
-
-skip_ctr_loop:
-
- disable_counter(hwc->idx);
-
- hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
-
- if (flags & PERF_EF_START)
- krait_l2_start_counter(event, PERF_EF_RELOAD);
-
- perf_event_update_userpage(event);
-
- pr_debug("%s: event: %ld, ctr: %d added from cpu:%d\n",
- __func__, hwc->config_base, hwc->idx, smp_processor_id());
-out:
- raw_spin_unlock_irqrestore(&hw_krait_l2_pmu.lock, iflags);
-
- /* Resume the PMU even if this event could not be added */
- perf_pmu_enable(event->pmu);
-
- return err;
-}
-
-static void krait_l2_pmu_enable(struct pmu *pmu)
-{
- isb();
- set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_ENABLE);
-}
-
-static void krait_l2_pmu_disable(struct pmu *pmu)
-{
- set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_DISABLE);
- isb();
-}
-
-u32 get_reset_pmovsr(void)
-{
- int val;
-
- val = get_l2_indirect_reg(L2PMOVSR);
- /* reset it */
- val &= 0xffffffff;
- set_l2_indirect_reg(L2PMOVSR, val);
-
- return val;
-}
-
-static irqreturn_t krait_l2_handle_irq(int irq_num, void *dev)
-{
- unsigned long pmovsr;
- struct perf_sample_data data;
- struct pt_regs *regs;
- struct perf_event *event;
- struct hw_perf_event *hwc;
- int bitp;
- int idx = 0;
-
- pmovsr = get_reset_pmovsr();
-
- if (!(pmovsr & 0xffffffff))
- return IRQ_NONE;
-
- regs = get_irq_regs();
-
- perf_sample_data_init(&data, 0);
-
- raw_spin_lock(&hw_krait_l2_pmu.lock);
-
- while (pmovsr) {
- bitp = __ffs(pmovsr);
-
- if (bitp == L2CYCLE_CTR_BIT)
- idx = L2CYCLE_CTR_EVENT_IDX;
- else
- idx = bitp;
-
- event = hw_krait_l2_pmu.events[idx];
-
- if (!event)
- goto next;
-
- if (!test_bit(idx, hw_krait_l2_pmu.active_mask))
- goto next;
-
- hwc = &event->hw;
- pmu_event_update(event, hwc, idx, 1);
- data.period = event->hw.last_period;
-
- if (!pmu_event_set_period(event, hwc, idx))
- goto next;
-
- if (perf_event_overflow(event, 0, &data, regs))
- disable_counter(hwc->idx);
-next:
- pmovsr &= (pmovsr - 1);
- }
-
- raw_spin_unlock(&hw_krait_l2_pmu.lock);
-
- irq_work_run();
-
- return IRQ_HANDLED;
-}
-
-static atomic_t active_l2_events = ATOMIC_INIT(0);
-static DEFINE_MUTEX(krait_pmu_reserve_mutex);
-
-static int pmu_reserve_hardware(void)
-{
- int i, err = -ENODEV, irq;
-
- l2_pmu_device = reserve_pmu(ARM_PMU_DEVICE_L2);
-
- if (IS_ERR(l2_pmu_device)) {
- pr_warning("unable to reserve pmu\n");
- return PTR_ERR(l2_pmu_device);
- }
-
- if (l2_pmu_device->num_resources < 1) {
- pr_err("no irqs for PMUs defined\n");
- return -ENODEV;
- }
-
- if (strncmp(l2_pmu_device->name, "l2-arm-pmu", 6)) {
- pr_err("Incorrect pdev reserved !\n");
- return -EINVAL;
- }
-
- for (i = 0; i < l2_pmu_device->num_resources; ++i) {
- irq = platform_get_irq(l2_pmu_device, i);
- if (irq < 0)
- continue;
-
- err = request_irq(irq, krait_l2_handle_irq,
- IRQF_DISABLED | IRQF_NOBALANCING,
- "krait-l2-pmu", NULL);
- if (err) {
- pr_warning("unable to request IRQ%d for Krait L2 perf "
- "counters\n", irq);
- break;
- }
-
- irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
- }
-
- if (err) {
- for (i = i - 1; i >= 0; --i) {
- irq = platform_get_irq(l2_pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
- release_pmu(l2_pmu_device);
- l2_pmu_device = NULL;
- }
-
- return err;
-}
-
-static void pmu_release_hardware(void)
-{
- int i, irq;
-
- for (i = l2_pmu_device->num_resources - 1; i >= 0; --i) {
- irq = platform_get_irq(l2_pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
-
- krait_l2_pmu_disable(NULL);
-
- release_pmu(l2_pmu_device);
- l2_pmu_device = NULL;
-}
-
-static void pmu_perf_event_destroy(struct perf_event *event)
-{
- if (atomic_dec_and_mutex_lock
- (&active_l2_events, &krait_pmu_reserve_mutex)) {
- pmu_release_hardware();
- mutex_unlock(&krait_pmu_reserve_mutex);
- }
-}
-
-static int krait_l2_event_init(struct perf_event *event)
-{
- int err = 0;
- struct hw_perf_event *hwc = &event->hw;
- int status = 0;
-
- switch (event->attr.type) {
- case PERF_TYPE_SHARED:
- break;
-
- default:
- return -ENOENT;
- }
-
- hwc->idx = -1;
-
- event->destroy = pmu_perf_event_destroy;
-
- if (!atomic_inc_not_zero(&active_l2_events)) {
- /* 0 active events */
- mutex_lock(&krait_pmu_reserve_mutex);
- err = pmu_reserve_hardware();
- mutex_unlock(&krait_pmu_reserve_mutex);
- if (!err)
- atomic_inc(&active_l2_events);
- else
- return err;
- }
-
- hwc->config = 0;
- hwc->event_base = 0;
-
- /* Check if we came via perf default syms */
- if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
- hwc->config_base = L2CYCLE_CTR_RAW_CODE;
- else
- hwc->config_base = event->attr.config;
-
- /* Only one CPU can control the cycle counter */
- if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
- /* Check if its already running */
- status = get_l2_indirect_reg(L2PMCCNTSR);
- if (status == 0x2) {
- err = -ENOSPC;
- goto out;
- }
- }
-
- if (!hwc->sample_period) {
- hwc->sample_period = MAX_L2_PERIOD;
- hwc->last_period = hwc->sample_period;
- local64_set(&hwc->period_left, hwc->sample_period);
- }
-
- pr_debug("%s: event: %lld init'd\n", __func__, event->attr.config);
-
-out:
- if (err < 0)
- pmu_perf_event_destroy(event);
-
- return err;
-}
-
-static struct pmu krait_l2_pmu = {
- .pmu_enable = krait_l2_pmu_enable,
- .pmu_disable = krait_l2_pmu_disable,
- .event_init = krait_l2_event_init,
- .add = krait_l2_add_event,
- .del = krait_l2_del_event,
- .start = krait_l2_start_counter,
- .stop = krait_l2_stop_counter,
- .read = krait_l2_read,
-};
-
-static const struct arm_pmu *__init krait_l2_pmu_init(void)
-{
- /* Register our own PMU here */
- perf_pmu_register(&krait_l2_pmu, "Krait L2", PERF_TYPE_SHARED);
-
- memset(&hw_krait_l2_pmu, 0, sizeof(hw_krait_l2_pmu));
-
- /* Reset all ctrs */
- set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
-
- /* Avoid spurious interrupt if any */
- get_reset_pmovsr();
-
- raw_spin_lock_init(&hw_krait_l2_pmu.lock);
-
- /* Don't return an arm_pmu here */
- return NULL;
-}
-#else
-
-static const struct arm_pmu *__init krait_l2_pmu_init(void)
-{
- return NULL;
-}
-#endif
diff --git a/arch/arm/kernel/perf_event_msm_l2.c b/arch/arm/kernel/perf_event_msm_l2.c
deleted file mode 100644
index 26753d8..0000000
--- a/arch/arm/kernel/perf_event_msm_l2.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/*
- * Copyright (c) 2011, 2012 Code Aurora Forum. 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.
- */
-#ifdef CONFIG_ARCH_MSM8X60
-
-#include <linux/irq.h>
-
-#define MAX_BB_L2_PERIOD ((1ULL << 32) - 1)
-#define MAX_BB_L2_CTRS 5
-#define BB_L2CYCLE_CTR_BIT 31
-#define BB_L2CYCLE_CTR_EVENT_IDX 4
-#define BB_L2CYCLE_CTR_RAW_CODE 0xfe
-#define SCORPIONL2_PMNC_E (1 << 0) /* Enable all counters */
-#define SCORPION_L2_EVT_PREFIX 3
-#define SCORPION_MAX_L2_REG 4
-
-/*
- * Lock to protect r/m/w sequences to the L2 PMU.
- */
-DEFINE_RAW_SPINLOCK(bb_l2_pmu_lock);
-
-static struct platform_device *bb_l2_pmu_device;
-
-struct hw_bb_l2_pmu {
- struct perf_event *events[MAX_BB_L2_CTRS];
- unsigned long active_mask[BITS_TO_LONGS(MAX_BB_L2_CTRS)];
- raw_spinlock_t lock;
-};
-
-struct hw_bb_l2_pmu hw_bb_l2_pmu;
-
-struct bb_l2_scorp_evt {
- u32 evt_type;
- u32 val;
- u8 grp;
- u32 evt_type_act;
-};
-
-enum scorpion_perf_types {
- SCORPIONL2_TOTAL_BANK_REQ = 0x90,
- SCORPIONL2_DSIDE_READ = 0x91,
- SCORPIONL2_DSIDE_WRITE = 0x92,
- SCORPIONL2_ISIDE_READ = 0x93,
- SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
- SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
- SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
- SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
- SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
- SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
- SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
- SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
- SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
- SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
- SCORPIONL2_BARRIERS = 0x9e,
- SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
- SCORPIONL2_MVA_POC = 0xa0,
- SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
- SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
- SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
- SCORPIONL2_ISIDE_READ_HITS = 0xa4,
- SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
- SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
- SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
- SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
- SCORPIONL2_L2LINE_LOCKED = 0xa9,
- SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
- SCORPIONL2_CACHE_MVA_POC = 0xab,
- SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
- SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
- SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
- SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
- SCORPIONL2_PMBUS_MPAAF = 0xb0,
- SCORPIONL2_PMBUS_MPWDAF = 0xb1,
- SCORPIONL2_PMBUS_MPBRT = 0xb2,
- SCORPIONL2_CPU0_GRANT = 0xb3,
- SCORPIONL2_CPU1_GRANT = 0xb4,
- SCORPIONL2_CPU0_NOGRANT = 0xb5,
- SCORPIONL2_CPU1_NOGRANT = 0xb6,
- SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
- SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
- SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
- SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
- SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
- SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
- SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
- SCORPIONL2_L2EM_STREX_PASS = 0xbe,
- SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
- SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
- SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
- SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
- SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
- SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
- SCORPIONL2_CPU0_CLAMPED = 0xc5,
- SCORPIONL2_CPU1_CLAMPED = 0xc6,
- SCORPIONL2_CPU0_WAIT = 0xc7,
- SCORPIONL2_CPU1_WAIT = 0xc8,
- SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
- SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
- SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
- SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
- SCORPIONL2_AXI_READ = 0xcd,
- SCORPIONL2_AXI_WRITE = 0xce,
-
- SCORPIONL2_1BEAT_WRITE = 0xcf,
- SCORPIONL2_2BEAT_WRITE = 0xd0,
- SCORPIONL2_4BEAT_WRITE = 0xd1,
- SCORPIONL2_8BEAT_WRITE = 0xd2,
- SCORPIONL2_12BEAT_WRITE = 0xd3,
- SCORPIONL2_16BEAT_WRITE = 0xd4,
- SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
- SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
- SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
- SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
- SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
- SCORPIONL2_CSYS_READ_2BEAT = 0xda,
- SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
- SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
- SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
- SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
- SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
- SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
- SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
- SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
- SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
- SCORPIONL2_LDREX_REQ = 0xe4,
- SCORPIONL2_STREX_PASS = 0xe5,
- SCORPIONL2_STREX_FAIL = 0xe6,
- SCORPIONL2_CPREAD = 0xe7,
- SCORPIONL2_CPWRITE = 0xe8,
- SCORPIONL2_BARRIER_REQ = 0xe9,
- SCORPIONL2_AXI_READ_SLVPORT = 0xea,
- SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
- SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
- SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
- SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
- SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
- SCORPIONL2_SNOOPED_IC = 0xf0,
- SCORPIONL2_SNOOPED_BP = 0xf1,
- SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
- SCORPIONL2_SNOOPED_TLB = 0xf3,
- BB_L2_MAX_EVT,
-};
-
-static const struct bb_l2_scorp_evt sc_evt[] = {
- {SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
- {SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
- {SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
- {SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
- {SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
- {SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
- {SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
- {SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
- {SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
- {SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
- {SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
- {SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
- {SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
- {SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
- {SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
- {SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
- {SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
- {SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
- {SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
- {SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
- {SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
- {SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
- {SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
- {SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
- {SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
- {SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
- {SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
- {SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
- {SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
- {SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
- {SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
- {SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
- {SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
- {SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
- {SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
-
- {SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
- {SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
- {SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
- {SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
- {SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
- {SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
- {SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
- {SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
- {SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
- {SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
- {SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
- {SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
- {SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
- {SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
- {SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
- {SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
- {SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
- {SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
- {SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
- {SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
- {SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
- {SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
- {SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
- {SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
- {SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
- {SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
-
- {SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
- {SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
- {SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
- {SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
- {SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
- {SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
- {SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
- {SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
- {SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
- {SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
- {SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
- {SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
- {SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
- {SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
- {SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
- {SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
- {SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
- {SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
- {SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
- {SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
- {SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
- {SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
- {SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
- {SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
- {SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
- {SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
- {SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
- {SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
- {SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
-
- {SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
- {SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
- {SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
- {SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
-
- {SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
- {SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
- {SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
- {SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
- {SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
- {SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
-};
-
-static u32 bb_l2_read_l2pm0(void)
-{
- u32 val;
- asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
- return val;
-}
-
-static void bb_l2_write_l2pm0(u32 val)
-{
- asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm1(void)
-{
- u32 val;
- asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
- return val;
-}
-
-static void bb_l2_write_l2pm1(u32 val)
-{
- asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm2(void)
-{
- u32 val;
- asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
- return val;
-}
-
-static void bb_l2_write_l2pm2(u32 val)
-{
- asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm3(void)
-{
- u32 val;
- asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
- return val;
-}
-
-static void bb_l2_write_l2pm3(u32 val)
-{
- asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
-}
-
-static u32 bb_l2_read_l2pm4(void)
-{
- u32 val;
- asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
- return val;
-}
-
-static void bb_l2_write_l2pm4(u32 val)
-{
- asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
-}
-
-struct bb_scorpion_access_funcs {
- u32(*read) (void);
- void (*write) (u32);
- void (*pre) (void);
- void (*post) (void);
-};
-
-struct bb_scorpion_access_funcs bb_l2_func[] = {
- {bb_l2_read_l2pm0, bb_l2_write_l2pm0, NULL, NULL},
- {bb_l2_read_l2pm1, bb_l2_write_l2pm1, NULL, NULL},
- {bb_l2_read_l2pm2, bb_l2_write_l2pm2, NULL, NULL},
- {bb_l2_read_l2pm3, bb_l2_write_l2pm3, NULL, NULL},
- {bb_l2_read_l2pm4, bb_l2_write_l2pm4, NULL, NULL},
-};
-
-#define COLMN0MASK 0x000000ff
-#define COLMN1MASK 0x0000ff00
-#define COLMN2MASK 0x00ff0000
-
-static u32 bb_l2_get_columnmask(u32 setval)
-{
- if (setval & COLMN0MASK)
- return 0xffffff00;
- else if (setval & COLMN1MASK)
- return 0xffff00ff;
- else if (setval & COLMN2MASK)
- return 0xff00ffff;
- else
- return 0x80ffffff;
-}
-
-static void bb_l2_evt_setup(u32 gr, u32 setval)
-{
- u32 val;
- if (bb_l2_func[gr].pre)
- bb_l2_func[gr].pre();
- val = bb_l2_get_columnmask(setval) & bb_l2_func[gr].read();
- val = val | setval;
- bb_l2_func[gr].write(val);
- if (bb_l2_func[gr].post)
- bb_l2_func[gr].post();
-}
-
-#define BB_L2_EVT_START_IDX 0x90
-#define BB_L2_INV_EVTYPE 0
-
-static unsigned int get_bb_l2_evtinfo(unsigned int evt_type,
- struct bb_l2_scorp_evt *evtinfo)
-{
- u32 idx;
- u8 prefix;
- u8 reg;
- u8 code;
- u8 group;
-
- prefix = (evt_type & 0xF0000) >> 16;
- if (prefix == SCORPION_L2_EVT_PREFIX) {
- reg = (evt_type & 0x0F000) >> 12;
- code = (evt_type & 0x00FF0) >> 4;
- group = evt_type & 0x0000F;
-
- if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
- return BB_L2_INV_EVTYPE;
-
- evtinfo->val = 0x80000000 | (code << (group * 8));
- evtinfo->grp = reg;
- evtinfo->evt_type_act = group | (reg << 2);
- return evtinfo->evt_type_act;
- }
-
- if (evt_type < BB_L2_EVT_START_IDX || evt_type >= BB_L2_MAX_EVT)
- return BB_L2_INV_EVTYPE;
- idx = evt_type - BB_L2_EVT_START_IDX;
- if (sc_evt[idx].evt_type == evt_type) {
- evtinfo->val = sc_evt[idx].val;
- evtinfo->grp = sc_evt[idx].grp;
- evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
- return sc_evt[idx].evt_type_act;
- }
- return BB_L2_INV_EVTYPE;
-}
-
-static inline void bb_l2_pmnc_write(unsigned long val)
-{
- val &= 0xff;
- asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
-}
-
-static inline unsigned long bb_l2_pmnc_read(void)
-{
- u32 val;
- asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
- return val;
-}
-
-static void bb_l2_set_evcntcr(void)
-{
- u32 val = 0x0;
- asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
-}
-
-static inline void bb_l2_set_evtyper(int ctr, int val)
-{
- /* select ctr */
- asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
-
- /* write into EVTYPER */
- asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
-}
-
-static void bb_l2_set_evfilter_task_mode(void)
-{
- u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
-
- asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
-}
-
-static void bb_l2_set_evfilter_sys_mode(void)
-{
- u32 filter_val = 0x000f003f;
-
- asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
-}
-
-static void bb_l2_enable_intenset(u32 idx)
-{
- if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
- asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
- (1 << BB_L2CYCLE_CTR_BIT));
- } else {
- asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
- }
-}
-
-static void bb_l2_disable_intenclr(u32 idx)
-{
- if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
- asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
- (1 << BB_L2CYCLE_CTR_BIT));
- } else {
- asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
- }
-}
-
-static void bb_l2_enable_counter(u32 idx)
-{
- if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
- asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
- (1 << BB_L2CYCLE_CTR_BIT));
- } else {
- asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
- }
-}
-
-static void bb_l2_disable_counter(u32 idx)
-{
- if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
- asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
- (1 << BB_L2CYCLE_CTR_BIT));
-
- } else {
- asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
- }
-}
-
-static u64 bb_l2_read_counter(u32 idx)
-{
- u32 val;
- unsigned long flags;
-
- if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
- asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
- } else {
- raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
- asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
-
- /* read val from counter */
- asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
- raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
- }
-
- return val;
-}
-
-static void bb_l2_write_counter(u32 idx, u32 val)
-{
- unsigned long flags;
-
- if (idx == BB_L2CYCLE_CTR_EVENT_IDX) {
- asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
- } else {
- raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
- /* select counter */
- asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
-
- /* write val into counter */
- asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
- raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
- }
-}
-
-static int
-bb_pmu_event_set_period(struct perf_event *event,
- struct hw_perf_event *hwc, int idx)
-{
- s64 left = local64_read(&hwc->period_left);
- s64 period = hwc->sample_period;
- int ret = 0;
-
- if (unlikely(left <= -period)) {
- left = period;
- local64_set(&hwc->period_left, left);
- hwc->last_period = period;
- ret = 1;
- }
-
- if (unlikely(left <= 0)) {
- left += period;
- local64_set(&hwc->period_left, left);
- hwc->last_period = period;
- ret = 1;
- }
-
- if (left > (s64) MAX_BB_L2_PERIOD)
- left = MAX_BB_L2_PERIOD;
-
- local64_set(&hwc->prev_count, (u64)-left);
-
- bb_l2_write_counter(idx, (u64) (-left) & 0xffffffff);
-
- perf_event_update_userpage(event);
-
- return ret;
-}
-
-static u64
-bb_pmu_event_update(struct perf_event *event, struct hw_perf_event *hwc,
- int idx, int overflow)
-{
- u64 prev_raw_count, new_raw_count;
- u64 delta;
-
-again:
- prev_raw_count = local64_read(&hwc->prev_count);
- new_raw_count = bb_l2_read_counter(idx);
-
- if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
- new_raw_count) != prev_raw_count)
- goto again;
-
- new_raw_count &= MAX_BB_L2_PERIOD;
- prev_raw_count &= MAX_BB_L2_PERIOD;
-
- if (overflow) {
- delta = MAX_BB_L2_PERIOD - prev_raw_count + new_raw_count;
- pr_err("%s: delta: %lld\n", __func__, delta);
- } else
- delta = new_raw_count - prev_raw_count;
-
- local64_add(delta, &event->count);
- local64_sub(delta, &hwc->period_left);
-
- pr_debug("%s: new: %lld, prev: %lld, event: %ld count: %lld\n",
- __func__, new_raw_count, prev_raw_count,
- hwc->config_base, local64_read(&event->count));
-
- return new_raw_count;
-}
-
-static void bb_l2_read(struct perf_event *event)
-{
- struct hw_perf_event *hwc = &event->hw;
-
- bb_pmu_event_update(event, hwc, hwc->idx, 0);
-}
-
-static void bb_l2_stop_counter(struct perf_event *event, int flags)
-{
- struct hw_perf_event *hwc = &event->hw;
- int idx = hwc->idx;
-
- if (!(hwc->state & PERF_HES_STOPPED)) {
- bb_l2_disable_intenclr(idx);
- bb_l2_disable_counter(idx);
-
- bb_pmu_event_update(event, hwc, idx, 0);
- hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
- }
-
- pr_debug("%s: event: %ld ctr: %d stopped\n", __func__, hwc->config_base,
- idx);
-}
-
-static void bb_l2_start_counter(struct perf_event *event, int flags)
-{
- struct hw_perf_event *hwc = &event->hw;
- int idx = hwc->idx;
- struct bb_l2_scorp_evt evtinfo;
- int evtype = hwc->config_base;
- int ev_typer;
- unsigned long iflags;
- int cpu_id = smp_processor_id();
-
- if (flags & PERF_EF_RELOAD)
- WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
-
- hwc->state = 0;
-
- bb_pmu_event_set_period(event, hwc, idx);
-
- if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE)
- goto out;
-
- memset(&evtinfo, 0, sizeof(evtinfo));
-
- ev_typer = get_bb_l2_evtinfo(evtype, &evtinfo);
-
- raw_spin_lock_irqsave(&bb_l2_pmu_lock, iflags);
-
- bb_l2_set_evtyper(idx, ev_typer);
-
- bb_l2_set_evcntcr();
-
- if (event->cpu < 0)
- bb_l2_set_evfilter_task_mode();
- else
- bb_l2_set_evfilter_sys_mode();
-
- bb_l2_evt_setup(evtinfo.grp, evtinfo.val);
-
- raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, iflags);
-
-out:
-
- bb_l2_enable_intenset(idx);
-
- bb_l2_enable_counter(idx);
-
- pr_debug("%s: idx: %d, event: %d, val: %x, cpu: %d\n",
- __func__, idx, evtype, evtinfo.val, cpu_id);
-}
-
-static void bb_l2_del_event(struct perf_event *event, int flags)
-{
- struct hw_perf_event *hwc = &event->hw;
- int idx = hwc->idx;
- unsigned long iflags;
-
- raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
-
- clear_bit(idx, (long unsigned int *)(&hw_bb_l2_pmu.active_mask));
-
- bb_l2_stop_counter(event, PERF_EF_UPDATE);
- hw_bb_l2_pmu.events[idx] = NULL;
- hwc->idx = -1;
-
- raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
-
- pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
-
- perf_event_update_userpage(event);
-}
-
-static int bb_l2_add_event(struct perf_event *event, int flags)
-{
- int ctr = 0;
- struct hw_perf_event *hwc = &event->hw;
- unsigned long iflags;
- int err = 0;
-
- perf_pmu_disable(event->pmu);
-
- raw_spin_lock_irqsave(&hw_bb_l2_pmu.lock, iflags);
-
- /* Cycle counter has a resrvd index */
- if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
- if (hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX]) {
- pr_err("%s: Stale cycle ctr event ptr !\n", __func__);
- err = -EINVAL;
- goto out;
- }
- hwc->idx = BB_L2CYCLE_CTR_EVENT_IDX;
- hw_bb_l2_pmu.events[BB_L2CYCLE_CTR_EVENT_IDX] = event;
- set_bit(BB_L2CYCLE_CTR_EVENT_IDX,
- (long unsigned int *)&hw_bb_l2_pmu.active_mask);
- goto skip_ctr_loop;
- }
-
- for (ctr = 0; ctr < MAX_BB_L2_CTRS - 1; ctr++) {
- if (!hw_bb_l2_pmu.events[ctr]) {
- hwc->idx = ctr;
- hw_bb_l2_pmu.events[ctr] = event;
- set_bit(ctr, (long unsigned int *)
- &hw_bb_l2_pmu.active_mask);
- break;
- }
- }
-
- if (hwc->idx < 0) {
- err = -ENOSPC;
- pr_err("%s: No space for event: %llx!!\n", __func__,
- event->attr.config);
- goto out;
- }
-
-skip_ctr_loop:
-
- bb_l2_disable_counter(hwc->idx);
-
- hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
-
- if (flags & PERF_EF_START)
- bb_l2_start_counter(event, PERF_EF_RELOAD);
-
- perf_event_update_userpage(event);
-
- pr_debug("%s: event: %ld, ctr: %d added from cpu:%d\n",
- __func__, hwc->config_base, hwc->idx, smp_processor_id());
-out:
- raw_spin_unlock_irqrestore(&hw_bb_l2_pmu.lock, iflags);
-
- /* Resume the PMU even if this event could not be added */
- perf_pmu_enable(event->pmu);
-
- return err;
-}
-
-static void bb_l2_pmu_enable(struct pmu *pmu)
-{
- unsigned long flags;
- isb();
- raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
- /* Enable all counters */
- bb_l2_pmnc_write(bb_l2_pmnc_read() | SCORPIONL2_PMNC_E);
- raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
-}
-
-static void bb_l2_pmu_disable(struct pmu *pmu)
-{
- unsigned long flags;
- raw_spin_lock_irqsave(&bb_l2_pmu_lock, flags);
- /* Disable all counters */
- bb_l2_pmnc_write(bb_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
- raw_spin_unlock_irqrestore(&bb_l2_pmu_lock, flags);
- isb();
-}
-
-static inline u32 bb_l2_get_reset_pmovsr(void)
-{
- u32 val;
-
- /* Read */
- asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
-
- /* Write to clear flags */
- val &= 0xffffffff;
- asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
-
- return val;
-}
-
-static irqreturn_t bb_l2_handle_irq(int irq_num, void *dev)
-{
- unsigned long pmovsr;
- struct perf_sample_data data;
- struct pt_regs *regs;
- struct perf_event *event;
- struct hw_perf_event *hwc;
- int bitp;
- int idx = 0;
-
- pmovsr = bb_l2_get_reset_pmovsr();
-
- if (!(pmovsr & 0xffffffff))
- return IRQ_NONE;
-
- regs = get_irq_regs();
-
- perf_sample_data_init(&data, 0);
-
- raw_spin_lock(&hw_bb_l2_pmu.lock);
-
- while (pmovsr) {
- bitp = __ffs(pmovsr);
-
- if (bitp == BB_L2CYCLE_CTR_BIT)
- idx = BB_L2CYCLE_CTR_EVENT_IDX;
- else
- idx = bitp;
-
- event = hw_bb_l2_pmu.events[idx];
-
- if (!event)
- goto next;
-
- if (!test_bit(idx, hw_bb_l2_pmu.active_mask))
- goto next;
-
- hwc = &event->hw;
- bb_pmu_event_update(event, hwc, idx, 1);
- data.period = event->hw.last_period;
-
- if (!bb_pmu_event_set_period(event, hwc, idx))
- goto next;
-
- if (perf_event_overflow(event, 0, &data, regs))
- bb_l2_disable_counter(hwc->idx);
-next:
- pmovsr &= (pmovsr - 1);
- }
-
- raw_spin_unlock(&hw_bb_l2_pmu.lock);
-
- irq_work_run();
-
- return IRQ_HANDLED;
-}
-
-static atomic_t active_bb_l2_events = ATOMIC_INIT(0);
-static DEFINE_MUTEX(bb_pmu_reserve_mutex);
-
-static int bb_pmu_reserve_hardware(void)
-{
- int i, err = -ENODEV, irq;
-
- bb_l2_pmu_device = reserve_pmu(ARM_PMU_DEVICE_L2);
-
- if (IS_ERR(bb_l2_pmu_device)) {
- pr_warning("unable to reserve pmu\n");
- return PTR_ERR(bb_l2_pmu_device);
- }
-
- if (bb_l2_pmu_device->num_resources < 1) {
- pr_err("no irqs for PMUs defined\n");
- return -ENODEV;
- }
-
- if (strncmp(bb_l2_pmu_device->name, "l2-arm-pmu", 6)) {
- pr_err("Incorrect pdev reserved !\n");
- return -EINVAL;
- }
-
- for (i = 0; i < bb_l2_pmu_device->num_resources; ++i) {
- irq = platform_get_irq(bb_l2_pmu_device, i);
- if (irq < 0)
- continue;
-
- err = request_irq(irq, bb_l2_handle_irq,
- IRQF_DISABLED | IRQF_NOBALANCING,
- "bb-l2-pmu", NULL);
- if (err) {
- pr_warning("unable to request IRQ%d for Krait L2 perf "
- "counters\n", irq);
- break;
- }
-
- irq_get_chip(irq)->irq_unmask(irq_get_irq_data(irq));
- }
-
- if (err) {
- for (i = i - 1; i >= 0; --i) {
- irq = platform_get_irq(bb_l2_pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
- release_pmu(bb_l2_pmu_device);
- bb_l2_pmu_device = NULL;
- }
-
- return err;
-}
-
-static void bb_pmu_release_hardware(void)
-{
- int i, irq;
-
- for (i = bb_l2_pmu_device->num_resources - 1; i >= 0; --i) {
- irq = platform_get_irq(bb_l2_pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
-
- bb_l2_pmu_disable(NULL);
-
- release_pmu(bb_l2_pmu_device);
- bb_l2_pmu_device = NULL;
-}
-
-static void bb_pmu_perf_event_destroy(struct perf_event *event)
-{
- if (atomic_dec_and_mutex_lock
- (&active_bb_l2_events, &bb_pmu_reserve_mutex)) {
- bb_pmu_release_hardware();
- mutex_unlock(&bb_pmu_reserve_mutex);
- }
-}
-
-static int bb_l2_event_init(struct perf_event *event)
-{
- int err = 0;
- struct hw_perf_event *hwc = &event->hw;
- int status = 0;
-
- switch (event->attr.type) {
- case PERF_TYPE_SHARED:
- break;
-
- default:
- return -ENOENT;
- }
-
- hwc->idx = -1;
-
- event->destroy = bb_pmu_perf_event_destroy;
-
- if (!atomic_inc_not_zero(&active_bb_l2_events)) {
- /* 0 active events */
- mutex_lock(&bb_pmu_reserve_mutex);
- err = bb_pmu_reserve_hardware();
- mutex_unlock(&bb_pmu_reserve_mutex);
- if (!err)
- atomic_inc(&active_bb_l2_events);
- else
- return err;
- }
-
- hwc->config = 0;
- hwc->event_base = 0;
-
- /* Check if we came via perf default syms */
- if (event->attr.config == PERF_COUNT_HW_L2_CYCLES)
- hwc->config_base = BB_L2CYCLE_CTR_RAW_CODE;
- else
- hwc->config_base = event->attr.config;
-
- /* Only one CPU can control the cycle counter */
- if (hwc->config_base == BB_L2CYCLE_CTR_RAW_CODE) {
- /* Check if its already running */
- asm volatile ("mrc p15, 3, %0, c15, c4, 6" : "=r" (status));
- if (status == 0x2) {
- err = -ENOSPC;
- goto out;
- }
- }
-
- if (!hwc->sample_period) {
- hwc->sample_period = MAX_BB_L2_PERIOD;
- hwc->last_period = hwc->sample_period;
- local64_set(&hwc->period_left, hwc->sample_period);
- }
-
- pr_debug("%s: event: %lld init'd\n", __func__, event->attr.config);
-
-out:
- if (err < 0)
- bb_pmu_perf_event_destroy(event);
-
- return err;
-}
-
-static struct pmu bb_l2_pmu = {
- .pmu_enable = bb_l2_pmu_enable,
- .pmu_disable = bb_l2_pmu_disable,
- .event_init = bb_l2_event_init,
- .add = bb_l2_add_event,
- .del = bb_l2_del_event,
- .start = bb_l2_start_counter,
- .stop = bb_l2_stop_counter,
- .read = bb_l2_read,
-};
-
-static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
-{
- /* Register our own PMU here */
- perf_pmu_register(&bb_l2_pmu, "BB L2", PERF_TYPE_SHARED);
-
- memset(&hw_bb_l2_pmu, 0, sizeof(hw_bb_l2_pmu));
-
- /* Avoid spurious interrupts at startup */
- bb_l2_get_reset_pmovsr();
-
- raw_spin_lock_init(&hw_bb_l2_pmu.lock);
-
- /* Don't return an arm_pmu here */
- return NULL;
-}
-#else
-
-static const struct arm_pmu *__init scorpionmp_l2_pmu_init(void)
-{
- return NULL;
-}
-
-#endif
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index cbdb51a..304520b 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -227,7 +227,7 @@
config ARCH_MSMCOPPER
bool "MSM Copper"
select ARCH_MSM_KRAITMP
- select GPIO_MSM_V2
+ select GPIO_MSM_V3
select ARM_GIC
select CPU_V7
select MSM_SCM if SMP
@@ -242,6 +242,9 @@
select SPARSE_IRQ
select MSM_RPM_SMD
select REGULATOR
+ select MSM_QDSP6_APR
+ select MSM_QDSP6V2_CODECS
+ select MSM_AUDIO_QDSP6V2 if SND_SOC
config ARCH_FSM9XXX
bool "FSM9XXX"
@@ -1841,8 +1844,22 @@
tristate "LPASS QDSP6v5 (Hexagon) Boot Support"
depends on MSM_PIL
help
- Support for booting and shutting down QDSP6v5 processors (Hexagon)
- processors in low power audio subsystems.
+ Support for booting and shutting down QDSP6v5 (Hexagon) processors
+ in low power audio subsystems.
+
+config MSM_PIL_MSS_QDSP6V5
+ tristate "MSS QDSP6v5 (Hexagon) Boot Support"
+ depends on MSM_PIL
+ help
+ Support for booting and shutting down QDSP6v5 (Hexagon) processors
+ in modem subsystems.
+
+config MSM_PIL_MBA
+ tristate "Support for modem self-authentication"
+ depends on MSM_PIL_MSS_QDSP6V5
+ help
+ Support for booting self-authenticating modems using the Modem Boot
+ Authenticator.
config MSM_PIL_RIVA
tristate "RIVA (WCNSS) Boot Support"
@@ -2159,6 +2176,15 @@
used by audio driver to configure QDSP6's
ASM, ADM and AFE.
+config MSM_QDSP6V2_CODECS
+ bool "Audio QDSP6V2 APR support"
+ depends on MSM_SMD
+ help
+ Enable Audio codecs with APR IPC protocol support between
+ application processor and QDSP6 for B-family. APR is
+ used by audio driver to configure QDSP6's
+ ASM, ADM and AFE.
+
config MSM_AUDIO_QDSP6
bool "QDSP6 HW Audio support"
select SND_SOC_MSM_QDSP6_INTF
@@ -2167,6 +2193,16 @@
Enable HW audio support in QDSP6.
QDSP6 can support HW encoder & decoder and audio processing
+config MSM_AUDIO_QDSP6V2
+ bool "QDSP6V2 HW Audio support"
+ select SND_SOC_MSM_QDSP6V2_INTF
+ help
+ Enable HW audio support in QDSP6V2.
+ QDSP6V2 can support HW encoder & decoder and
+ audio processing. It will enable support for
+ AAC, AMRNB, AMRWB, EVRC, MP3, QCELP among
+ others.
+
config MSM_ULTRASOUND
bool "MSM ultrasound support"
depends on MSM_AUDIO_QDSP6
@@ -2243,6 +2279,16 @@
separately. This will guarantee that the last acesses for each cpu
will be logged but there will be fewer entries per cpu
+config MSM_EBI_ERP
+ bool "External Bus Interface (EBI) error reporting"
+ help
+ Say 'Y' here to enable reporting of external bus interface errors to
+ the kernel log. Information such as the offending address and
+ transaction type will be logged. This may be useful for debugging
+ seemingly broken memory accesses.
+
+ For production builds, you should probably say 'N' here.
+
config MSM_CACHE_ERP
bool "Cache / CPU error reporting"
depends on ARCH_MSM_KRAIT
@@ -2264,6 +2310,16 @@
For production builds, you should probably say 'N' here.
+config MSM_L1_ERR_LOG
+ bool "Log CPU ERP events to system memory"
+ depends on MSM_CACHE_ERP
+ help
+ Enable logging CPU ERP events to an area of memory that will be
+ preserved across a system reset. This may be useful for detecting and
+ troubleshooting ERP-related system crashes in the field.
+
+ For production builds, you may want to say 'Y' here.
+
config MSM_L2_ERP_PRINT_ACCESS_ERRORS
bool "Report L2 master port slave/decode errors in kernel log"
depends on MSM_CACHE_ERP
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 44bef1b..1896059 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -25,7 +25,8 @@
obj-y += acpuclock.o
obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o clock-pll.o
obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o
+obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
+obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
ifndef CONFIG_MSM_SMP
@@ -70,6 +71,8 @@
obj-$(CONFIG_MSM_PIL_QDSP6V3) += pil-q6v3.o
obj-$(CONFIG_MSM_PIL_QDSP6V4) += pil-q6v4.o
obj-$(CONFIG_MSM_PIL_LPASS_QDSP6V5) += pil-q6v5.o pil-q6v5-lpass.o
+obj-$(CONFIG_MSM_PIL_MSS_QDSP6V5) += pil-q6v5.o pil-q6v5-mss.o
+obj-$(CONFIG_MSM_PIL_MBA) += pil-mba.o
obj-$(CONFIG_MSM_PIL_RIVA) += pil-riva.o
obj-$(CONFIG_MSM_PIL_TZAPPS) += pil-tzapps.o
obj-$(CONFIG_MSM_PIL_VIDC) += pil-vidc.o
@@ -153,6 +156,7 @@
obj-$(CONFIG_MSM_QDSP6) += qdsp6/
obj-$(CONFIG_MSM8X60_AUDIO) += qdsp6v2/
obj-$(CONFIG_MSM_AUDIO_QDSP6) += qdsp6v2/
+obj-$(CONFIG_MSM_AUDIO_QDSP6V2) += qdsp6v2/
obj-$(CONFIG_MSM_HW3D) += hw3d.o
obj-$(CONFIG_PM) += pm-boot.o
obj-$(CONFIG_MSM_PM8X60) += pm-8x60.o pm-data.o
@@ -286,7 +290,7 @@
obj-$(CONFIG_ARCH_MSM9615) += clock-local.o clock-9615.o acpuclock-9615.o clock-rpm.o clock-pll.o
obj-$(CONFIG_ARCH_MSMCOPPER) += board-copper.o board-dt.o board-copper-regulator.o board-copper-gpiomux.o
obj-$(CONFIG_ARCH_MSMCOPPER) += acpuclock-krait.o acpuclock-copper.o
-obj-$(CONFIG_ARCH_MSMCOPPER) += clock-local2.o clock-pll.o clock-copper.o
+obj-$(CONFIG_ARCH_MSMCOPPER) += clock-local2.o clock-pll.o clock-copper.o clock-rpm.o clock-voter.o
obj-$(CONFIG_ARCH_MSMCOPPER) += gdsc.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
@@ -328,7 +332,8 @@
ifdef CONFIG_VCM
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
-obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem.o ocmem_allocator.o ocmem_notifier.o
+obj-$(CONFIG_MSM_OCMEM) += ocmem_sched.o ocmem_api.o
obj-$(CONFIG_ARCH_MSM7X27) += gpiomux-7x27.o gpiomux-v1.o gpiomux.o
obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
@@ -362,6 +367,7 @@
obj-$(CONFIG_ARCH_MSM8960) += mdm2.o mdm_common.o
obj-$(CONFIG_MSM_RTB) += msm_rtb.o
obj-$(CONFIG_MSM_CACHE_ERP) += cache_erp.o
+obj-$(CONFIG_MSM_EBI_ERP) += ebi_erp.o
obj-$(CONFIG_MSM_CACHE_DUMP) += msm_cache_dump.o
obj-$(CONFIG_MSM_HSIC_SYSMON) += hsic_sysmon.o
diff --git a/arch/arm/mach-msm/acpuclock-7627.c b/arch/arm/mach-msm/acpuclock-7627.c
index 7c2c556..f9ff226 100644
--- a/arch/arm/mach-msm/acpuclock-7627.c
+++ b/arch/arm/mach-msm/acpuclock-7627.c
@@ -18,6 +18,7 @@
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/string.h>
@@ -27,6 +28,8 @@
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/sort.h>
+#include <linux/platform_device.h>
+
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
@@ -402,7 +405,7 @@
#ifdef CONFIG_CPU_FREQ_MSM
static struct cpufreq_frequency_table freq_table[NR_CPUS][20];
-static void __init cpufreq_table_init(void)
+static void __devinit cpufreq_table_init(void)
{
int cpu;
for_each_possible_cpu(cpu) {
@@ -693,7 +696,7 @@
return rc;
}
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
{
struct clkctl_acpu_speed *speed;
uint32_t div, sel, reg_clksel;
@@ -775,7 +778,7 @@
* Clock driver initialization
*---------------------------------------------------------------------------*/
#define MHZ 1000000
-static void __init select_freq_plan(void)
+static void __devinit select_freq_plan(void)
{
unsigned long pll_mhz[ACPU_PLL_END];
struct pll_freq_tbl_map *t;
@@ -835,7 +838,7 @@
* Hardware requires the CPU to be dropped to less than MAX_WAIT_FOR_IRQ_KHZ
* before entering a wait for irq low-power mode. Find a suitable rate.
*/
-static unsigned long __init find_wait_for_irq_khz(void)
+static unsigned long __devinit find_wait_for_irq_khz(void)
{
unsigned long found_khz = 0;
int i;
@@ -847,7 +850,7 @@
return found_khz;
}
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
{
int i = 0, cpu;
const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -868,7 +871,7 @@
}
}
-static void __init precompute_stepping(void)
+static void __devinit precompute_stepping(void)
{
int i, step_idx;
@@ -909,7 +912,7 @@
}
}
-static void __init print_acpu_freq_tbl(void)
+static void __devinit print_acpu_freq_tbl(void)
{
struct clkctl_acpu_speed *t;
short down_idx[ACPU_PLL_END];
@@ -947,15 +950,17 @@
.switch_time_us = 50,
};
-static int __init acpuclk_7627_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_7627_probe(struct platform_device *pdev)
{
+ const struct acpuclk_pdata *pdata = pdev->dev.platform_data;
+
pr_info("%s()\n", __func__);
drv_state.ebi1_clk = clk_get(NULL, "ebi1_acpu_clk");
BUG_ON(IS_ERR(drv_state.ebi1_clk));
mutex_init(&drv_state.lock);
- drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
+ drv_state.max_speed_delta_khz = pdata->max_speed_delta_khz;
select_freq_plan();
acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
precompute_stepping();
@@ -970,23 +975,16 @@
return 0;
}
-struct acpuclk_soc_data acpuclk_7x27_soc_data __initdata = {
- .max_speed_delta_khz = 400000,
- .init = acpuclk_7627_init,
+static struct platform_driver acpuclk_7627_driver = {
+ .probe = acpuclk_7627_probe,
+ .driver = {
+ .name = "acpuclk-7627",
+ .owner = THIS_MODULE,
+ },
};
-struct acpuclk_soc_data acpuclk_7x27a_soc_data __initdata = {
- .max_speed_delta_khz = 400000,
- .init = acpuclk_7627_init,
-};
-
-struct acpuclk_soc_data acpuclk_7x27aa_soc_data __initdata = {
- .max_speed_delta_khz = 504000,
- .init = acpuclk_7627_init,
-};
-
-struct acpuclk_soc_data acpuclk_8625_soc_data __initdata = {
- /* TODO: Need to update speed delta from H/w Team */
- .max_speed_delta_khz = 604800,
- .init = acpuclk_7627_init,
-};
+static int __init acpuclk_7627_init(void)
+{
+ return platform_driver_register(&acpuclk_7627_driver);
+}
+postcore_initcall(acpuclk_7627_init);
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 29b0065..b49613e 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -16,6 +16,7 @@
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/string.h>
@@ -25,6 +26,7 @@
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/sort.h>
+#include <linux/platform_device.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include <asm/mach-types.h>
@@ -315,7 +317,7 @@
* Clock driver initialization
*---------------------------------------------------------------------------*/
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
{
struct clkctl_acpu_speed *s;
uint32_t div, sel, src_num;
@@ -393,7 +395,7 @@
}
/* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
{
int i;
const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -431,7 +433,7 @@
* Truncate the frequency table at the current PLL2 rate and determine the
* backup PLL to use when scaling PLL2.
*/
-void __init pll2_fixup(void)
+void __devinit pll2_fixup(void)
{
struct clkctl_acpu_speed *speed = acpu_freq_tbl;
u8 pll2_l = readl_relaxed(PLL2_L_VAL_ADDR) & 0xFF;
@@ -453,7 +455,7 @@
#define RPM_BYPASS_MASK (1 << 3)
#define PMIC_MODE_MASK (1 << 4)
-static void __init populate_plls(void)
+static void __devinit populate_plls(void)
{
acpuclk_sources[PLL_1] = clk_get_sys("acpu", "pll1_clk");
BUG_ON(IS_ERR(acpuclk_sources[PLL_1]));
@@ -479,7 +481,7 @@
.switch_time_us = 50,
};
-static int __init acpuclk_7x30_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_7x30_probe(struct platform_device *pdev)
{
pr_info("%s()\n", __func__);
@@ -494,6 +496,16 @@
return 0;
}
-struct acpuclk_soc_data acpuclk_7x30_soc_data __initdata = {
- .init = acpuclk_7x30_init,
+static struct platform_driver acpuclk_7x30_driver = {
+ .probe = acpuclk_7x30_probe,
+ .driver = {
+ .name = "acpuclk-7x30",
+ .owner = THIS_MODULE,
+ },
};
+
+static int __init acpuclk_7x30_init(void)
+{
+ return platform_driver_register(&acpuclk_7x30_driver);
+}
+postcore_initcall(acpuclk_7x30_init);
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index f467aba..d29fee6 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -22,6 +23,7 @@
#include <linux/cpufreq.h>
#include <linux/cpu.h>
#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
#include <asm/mach-types.h>
#include <asm/cpu.h>
@@ -105,6 +107,14 @@
HFPLL_VDD_NOM
};
+enum pvs {
+ PVS_SLOW,
+ PVS_NOM,
+ PVS_FAST,
+ PVS_FASTER,
+ NUM_PVS
+};
+
struct vreg {
const char name[15];
const unsigned int max_vdd;
@@ -602,7 +612,7 @@
};
/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl_8064[] = {
+static struct acpu_level acpu_freq_tbl_8064_slow[] = {
{ 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
{ 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
{ 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
@@ -629,6 +639,60 @@
{ 0, { 0 } }
};
+static struct acpu_level acpu_freq_tbl_8064_nom[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 925000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 925000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 950000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 950000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 975000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 975000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1025000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1025000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1050000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1050000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1075000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1075000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1125000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1125000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1150000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1150000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1175000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1175000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1187500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1187500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1200000 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_8064_fast[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 850000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 850000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 875000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 875000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 900000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 900000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 925000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 925000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 975000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 975000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1000000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1000000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1025000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1025000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1075000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1075000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1100000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1100000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1125000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1125000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1137500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1137500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1150000 },
+ { 0, { 0 } }
+};
+
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
#undef L2
#define L2(x) (&l2_freq_tbl_8930[(x)])
@@ -653,27 +717,80 @@
};
/* TODO: Update core voltages when data is available. */
-static struct acpu_level acpu_freq_tbl_8930[] = {
- { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 925000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 925000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 937500 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 962500 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 987500 },
+static struct acpu_level acpu_freq_tbl_8930_slow[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 975000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 975000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 1000000 },
{ 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 1000000 },
{ 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1025000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1037500 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1062500 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1087500 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1025000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1075000 },
{ 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1125000 },
- { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(16), 1137500 },
- { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1162500 },
- { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1187500 },
- { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1200000 },
- { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1225000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1100000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1125000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1175000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1200000 },
+ { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1225000 },
+ { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1237500 },
{ 0, { 0 } }
};
+static struct acpu_level acpu_freq_tbl_8930_nom[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 925000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 925000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 950000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 950000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 975000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 975000 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1000000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 1000000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1050000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1050000 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1075000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1075000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1100000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1100000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1150000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1150000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1175000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1175000 },
+ { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1200000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1200000 },
+ { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1212500 },
+ { 0, { 0 } }
+};
+
+static struct acpu_level acpu_freq_tbl_8930_fast[] = {
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 900000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 900000 },
+ { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(6), 900000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(6), 900000 },
+ { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(6), 925000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(6), 925000 },
+ { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 950000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(6), 950000 },
+ { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(11), 1000000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(11), 1000000 },
+ { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(11), 1025000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1025000 },
+ { 1, { 972000, HFPLL, 1, 0, 0x24 }, L2(11), 1050000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(11), 1050000 },
+ { 1, { 1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1100000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1100000 },
+ { 1, { 1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1125000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1125000 },
+ { 1, { 1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1150000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1150000 },
+ { 1, { 1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1162500 },
+ { 0, { 0 } }
+};
/* TODO: Update vdd_dig, vdd_mem and bw when data is available. */
#undef L2
#define L2(x) (&l2_freq_tbl_8627[(x)])
@@ -711,6 +828,32 @@
{ 0, { 0 } }
};
+static struct acpu_level *acpu_freq_tbl_8960_v1[NUM_PVS] __initdata = {
+ [PVS_SLOW] = acpu_freq_tbl_8960_kraitv1_slow,
+ [PVS_NOM] = acpu_freq_tbl_8960_kraitv1_nom_fast,
+ [PVS_FAST] = acpu_freq_tbl_8960_kraitv1_nom_fast,
+};
+
+static struct acpu_level *acpu_freq_tbl_8960_v2[NUM_PVS] __initdata = {
+ [PVS_SLOW] = acpu_freq_tbl_8960_kraitv2_slow,
+ [PVS_NOM] = acpu_freq_tbl_8960_kraitv2_nom,
+ [PVS_FAST] = acpu_freq_tbl_8960_kraitv2_fast,
+};
+
+/* TODO: update the faster table when data is available */
+static struct acpu_level *acpu_freq_tbl_8064[NUM_PVS] __initdata = {
+ [PVS_SLOW] = acpu_freq_tbl_8064_slow,
+ [PVS_NOM] = acpu_freq_tbl_8064_nom,
+ [PVS_FAST] = acpu_freq_tbl_8064_fast,
+ [PVS_FASTER] = acpu_freq_tbl_8064_fast,
+};
+
+static struct acpu_level *acpu_freq_tbl_8930_pvs[NUM_PVS] __initdata = {
+ [PVS_SLOW] = acpu_freq_tbl_8930_slow,
+ [PVS_NOM] = acpu_freq_tbl_8930_nom,
+ [PVS_FAST] = acpu_freq_tbl_8930_fast,
+};
+
static unsigned long acpuclk_8960_get_rate(int cpu)
{
return scalable[cpu].current_speed->khz;
@@ -1416,57 +1559,60 @@
tbl->vdd_core = 1150000;
}
+static enum pvs __init get_pvs(void)
+{
+ uint32_t pte_efuse, pvs;
+
+ pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
+ pvs = (pte_efuse >> 10) & 0x7;
+ if (pvs == 0x7)
+ pvs = (pte_efuse >> 13) & 0x7;
+
+ switch (pvs) {
+ case 0x0:
+ case 0x7:
+ pr_info("ACPU PVS: Slow\n");
+ return PVS_SLOW;
+ case 0x1:
+ pr_info("ACPU PVS: Nominal\n");
+ return PVS_NOM;
+ case 0x3:
+ pr_info("ACPU PVS: Fast\n");
+ return PVS_FAST;
+ case 0x4:
+ if (cpu_is_apq8064()) {
+ pr_info("ACPU PVS: Faster\n");
+ return PVS_FASTER;
+ }
+ default:
+ pr_warn("ACPU PVS: Unknown. Defaulting to slow\n");
+ return PVS_SLOW;
+ }
+}
+
static struct acpu_level * __init select_freq_plan(void)
{
struct acpu_level *l, *max_acpu_level = NULL;
/* Select frequency tables. */
if (cpu_is_msm8960()) {
- uint32_t pte_efuse, pvs;
- struct acpu_level *v1, *v2;
-
- pte_efuse = readl_relaxed(QFPROM_PTE_EFUSE_ADDR);
- pvs = (pte_efuse >> 10) & 0x7;
- if (pvs == 0x7)
- pvs = (pte_efuse >> 13) & 0x7;
-
- switch (pvs) {
- case 0x0:
- case 0x7:
- pr_info("ACPU PVS: Slow\n");
- v1 = acpu_freq_tbl_8960_kraitv1_slow;
- v2 = acpu_freq_tbl_8960_kraitv2_slow;
- break;
- case 0x1:
- pr_info("ACPU PVS: Nominal\n");
- v1 = acpu_freq_tbl_8960_kraitv1_nom_fast;
- v2 = acpu_freq_tbl_8960_kraitv2_nom;
- break;
- case 0x3:
- pr_info("ACPU PVS: Fast\n");
- v1 = acpu_freq_tbl_8960_kraitv1_nom_fast;
- v2 = acpu_freq_tbl_8960_kraitv2_fast;
- break;
- default:
- pr_warn("ACPU PVS: Unknown. Defaulting to slow.\n");
- v1 = acpu_freq_tbl_8960_kraitv1_slow;
- v2 = acpu_freq_tbl_8960_kraitv2_slow;
- break;
- }
+ enum pvs pvs_id = get_pvs();
scalable = scalable_8960;
if (cpu_is_krait_v1()) {
- acpu_freq_tbl = v1;
+ acpu_freq_tbl = acpu_freq_tbl_8960_v1[pvs_id];
l2_freq_tbl = l2_freq_tbl_8960_kraitv1;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv1);
} else {
- acpu_freq_tbl = v2;
+ acpu_freq_tbl = acpu_freq_tbl_8960_v2[pvs_id];
l2_freq_tbl = l2_freq_tbl_8960_kraitv2;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv2);
}
} else if (cpu_is_apq8064()) {
+ enum pvs pvs_id = get_pvs();
+
scalable = scalable_8064;
- acpu_freq_tbl = acpu_freq_tbl_8064;
+ acpu_freq_tbl = acpu_freq_tbl_8064[pvs_id];
l2_freq_tbl = l2_freq_tbl_8064;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8064);
} else if (cpu_is_msm8627()) {
@@ -1475,13 +1621,16 @@
l2_freq_tbl = l2_freq_tbl_8627;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8627);
} else if (cpu_is_msm8930()) {
+ enum pvs pvs_id = get_pvs();
+
scalable = scalable_8930;
- acpu_freq_tbl = acpu_freq_tbl_8930;
+ acpu_freq_tbl = acpu_freq_tbl_8930_pvs[pvs_id];
l2_freq_tbl = l2_freq_tbl_8930;
l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8930);
} else {
BUG();
}
+ BUG_ON(!acpu_freq_tbl);
if (krait_needs_vmin())
kraitv2_apply_vmin(acpu_freq_tbl);
@@ -1502,7 +1651,7 @@
.wait_for_irq_khz = STBY_KHZ,
};
-static int __init acpuclk_8960_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_8960_probe(struct platform_device *pdev)
{
struct acpu_level *max_acpu_level = select_freq_plan();
@@ -1520,14 +1669,15 @@
return 0;
}
-struct acpuclk_soc_data acpuclk_8960_soc_data __initdata = {
- .init = acpuclk_8960_init,
+static struct platform_driver acpuclk_8960_driver = {
+ .driver = {
+ .name = "acpuclk-8960",
+ .owner = THIS_MODULE,
+ },
};
-struct acpuclk_soc_data acpuclk_8930_soc_data __initdata = {
- .init = acpuclk_8960_init,
-};
-
-struct acpuclk_soc_data acpuclk_8064_soc_data __initdata = {
- .init = acpuclk_8960_init,
-};
+static int __init acpuclk_8960_init(void)
+{
+ return platform_driver_probe(&acpuclk_8960_driver, acpuclk_8960_probe);
+}
+device_initcall(acpuclk_8960_init);
diff --git a/arch/arm/mach-msm/acpuclock-8x50.c b/arch/arm/mach-msm/acpuclock-8x50.c
index cde5a14..996f883 100644
--- a/arch/arm/mach-msm/acpuclock-8x50.c
+++ b/arch/arm/mach-msm/acpuclock-8x50.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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
@@ -12,6 +12,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -20,6 +21,7 @@
#include <linux/cpufreq.h>
#include <linux/clk.h>
#include <linux/mfd/tps65023.h>
+#include <linux/platform_device.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
@@ -130,7 +132,7 @@
#ifdef CONFIG_CPU_FREQ_MSM
static struct cpufreq_frequency_table freq_table[20];
-static void __init cpufreq_table_init(void)
+static void __devinit cpufreq_table_init(void)
{
unsigned int i;
unsigned int freq_cnt = 0;
@@ -504,7 +506,7 @@
return rc;
}
-static void __init acpuclk_hw_init(void)
+static void __devinit acpuclk_hw_init(void)
{
struct clkctl_acpu_speed *speed;
uint32_t div, sel, regval;
@@ -582,7 +584,7 @@
#define PLL0_M_VAL_ADDR (MSM_CLK_CTL_BASE + 0x308)
-static void __init acpu_freq_tbl_fixup(void)
+static void __devinit acpu_freq_tbl_fixup(void)
{
void __iomem *ct_csr_base;
uint32_t tcsr_spare2, pll0_m_val;
@@ -645,7 +647,7 @@
}
/* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
+static void __devinit lpj_init(void)
{
int i;
const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
@@ -657,7 +659,7 @@
}
#ifdef CONFIG_MSM_CPU_AVS
-static int __init acpu_avs_init(int (*set_vdd) (int), int khz)
+static int __devinit acpu_avs_init(int (*set_vdd) (int), int khz)
{
int i;
int freq_count = 0;
@@ -704,7 +706,7 @@
.switch_time_us = 20,
};
-static int __init acpuclk_8x50_init(struct acpuclk_soc_data *soc_data)
+static int __devinit acpuclk_8x50_probe(struct platform_device *pdev)
{
mutex_init(&drv_state.lock);
drv_state.acpu_set_vdd = qsd8x50_tps65023_set_dcdc1;
@@ -736,6 +738,16 @@
return 0;
}
-struct acpuclk_soc_data acpuclk_8x50_soc_data __initdata = {
- .init = acpuclk_8x50_init,
+static struct platform_driver acpuclk_8x50_driver = {
+ .probe = acpuclk_8x50_probe,
+ .driver = {
+ .name = "acpuclk-8x50",
+ .owner = THIS_MODULE,
+ },
};
+
+static int __init acpuclk_8x50_init(void)
+{
+ return platform_driver_register(&acpuclk_8x50_driver);
+}
+postcore_initcall(acpuclk_8x50_init);
diff --git a/arch/arm/mach-msm/acpuclock-8x60.c b/arch/arm/mach-msm/acpuclock-8x60.c
index 48efa18..ef34b3c 100644
--- a/arch/arm/mach-msm/acpuclock-8x60.c
+++ b/arch/arm/mach-msm/acpuclock-8x60.c
@@ -11,6 +11,7 @@
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -20,6 +21,7 @@
#include <linux/cpufreq.h>
#include <linux/cpu.h>
#include <linux/regulator/consumer.h>
+#include <linux/platform_device.h>
#include <asm/cpu.h>
@@ -734,7 +736,7 @@
}
/* AVS needs SAW_VCTL to be intitialized correctly, before enable,
- * and is not initialized at acpuclk_init().
+ * and is not initialized during probe.
*/
if (reason == SETRATE_CPUFREQ)
AVS_DISABLE(cpu);
@@ -1062,7 +1064,7 @@
.wait_for_irq_khz = MAX_AXI,
};
-static int __init acpuclk_8x60_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_8x60_probe(struct platform_device *pdev)
{
struct clkctl_acpu_speed *max_freq;
int cpu;
@@ -1091,6 +1093,15 @@
return 0;
}
-struct acpuclk_soc_data acpuclk_8x60_soc_data __initdata = {
- .init = acpuclk_8x60_init,
+static struct platform_driver acpuclk_8x60_driver = {
+ .driver = {
+ .name = "acpuclk-8x60",
+ .owner = THIS_MODULE,
+ },
};
+
+static int __init acpuclk_8x60_init(void)
+{
+ return platform_driver_probe(&acpuclk_8x60_driver, acpuclk_8x60_probe);
+}
+device_initcall(acpuclk_8x60_init);
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index 8882f41..db7bab3 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -14,6 +14,7 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/delay.h>
@@ -22,6 +23,7 @@
#include <linux/errno.h>
#include <linux/cpufreq.h>
#include <linux/clk.h>
+#include <linux/platform_device.h>
#include <asm/cpu.h>
@@ -39,7 +41,6 @@
#define REG_CLKDIV_1 (MSM_APCS_GLB_BASE + 0x14)
#define REG_CLKOUTSEL (MSM_APCS_GLB_BASE + 0x18)
-#define MAX_VDD_CPU 1150000
#define MAX_VDD_MEM 1150000
enum clk_src {
@@ -111,12 +112,12 @@
static uint32_t bus_perf_client;
static struct clkctl_acpu_speed acpu_freq_tbl[] = {
- { 0, 19200, SRC_CXO, 0, 0, 950000, 1050000, 0 },
- { 1, 138000, SRC_PLL0, 6, 1, 950000, 1050000, 2 },
- { 1, 276000, SRC_PLL0, 6, 0, 1050000, 1050000, 2 },
- { 1, 384000, SRC_PLL8, 3, 0, 1150000, 1150000, 4 },
+ { 0, 19200, SRC_CXO, 0, 0, RPM_VREG_CORNER_LOW, 1050000, 0 },
+ { 1, 138000, SRC_PLL0, 6, 1, RPM_VREG_CORNER_LOW, 1050000, 2 },
+ { 1, 276000, SRC_PLL0, 6, 0, RPM_VREG_CORNER_NOMINAL, 1050000, 2 },
+ { 1, 384000, SRC_PLL8, 3, 0, RPM_VREG_CORNER_HIGH, 1150000, 4 },
/* The row below may be changed at runtime depending on hw rev. */
- { 1, 440000, SRC_PLL9, 2, 0, 1150000, 1150000, 4 },
+ { 1, 440000, SRC_PLL9, 2, 0, RPM_VREG_CORNER_HIGH, 1150000, 4 },
{ 0 }
};
@@ -171,8 +172,8 @@
return rc;
}
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER1,
- vdd_cpu, MAX_VDD_CPU, 0);
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+ RPM_VREG_VOTER1, vdd_cpu, RPM_VREG_CORNER_HIGH, 0);
if (rc)
pr_err("vdd_cpu increase failed (%d)\n", rc);
@@ -185,8 +186,9 @@
int ret;
/* Update CPU voltage. */
- ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER1,
- vdd_cpu, MAX_VDD_CPU, 0);
+ ret = rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+ RPM_VREG_VOTER1, vdd_cpu, RPM_VREG_CORNER_HIGH, 0);
+
if (ret) {
pr_err("vdd_cpu decrease failed (%d)\n", ret);
return;
@@ -306,7 +308,7 @@
.wait_for_irq_khz = 19200,
};
-static int __init acpuclk_9615_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_9615_probe(struct platform_device *pdev)
{
unsigned long max_cpu_khz = 0;
int i;
@@ -351,6 +353,15 @@
return 0;
}
-struct acpuclk_soc_data acpuclk_9615_soc_data __initdata = {
- .init = acpuclk_9615_init,
+static struct platform_driver acpuclk_9615_driver = {
+ .driver = {
+ .name = "acpuclk-9615",
+ .owner = THIS_MODULE,
+ },
};
+
+static int __init acpuclk_9615_init(void)
+{
+ return platform_driver_probe(&acpuclk_9615_driver, acpuclk_9615_probe);
+}
+device_initcall(acpuclk_9615_init);
diff --git a/arch/arm/mach-msm/acpuclock-fsm9xxx.c b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
index 3cdc58d..af1c0eb 100644
--- a/arch/arm/mach-msm/acpuclock-fsm9xxx.c
+++ b/arch/arm/mach-msm/acpuclock-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -11,8 +11,10 @@
*
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
#include <mach/board.h>
#include "acpuclock.h"
@@ -40,13 +42,22 @@
.get_rate = acpuclk_9xxx_get_rate,
};
-static int __init acpuclk_9xxx_init(struct acpuclk_soc_data *soc_data)
+static int __init acpuclk_9xxx_probe(struct platform_device *pdev)
{
acpuclk_register(&acpuclk_9xxx_data);
pr_info("ACPU running at %lu KHz\n", acpuclk_get_rate(0));
return 0;
}
-struct acpuclk_soc_data acpuclk_9xxx_soc_data __initdata = {
- .init = acpuclk_9xxx_init,
+static struct platform_driver acpuclk_9xxx_driver = {
+ .driver = {
+ .name = "acpuclk-9xxx",
+ .owner = THIS_MODULE,
+ },
};
+
+static int __init acpuclk_9xxx_init(void)
+{
+ return platform_driver_probe(&acpuclk_9xxx_driver, acpuclk_9xxx_probe);
+}
+device_initcall(acpuclk_9xxx_init);
diff --git a/arch/arm/mach-msm/acpuclock.c b/arch/arm/mach-msm/acpuclock.c
index 91071c4..be056e6 100644
--- a/arch/arm/mach-msm/acpuclock.c
+++ b/arch/arm/mach-msm/acpuclock.c
@@ -53,24 +53,7 @@
return rate;
}
-void __init acpuclk_register(struct acpuclk_data *data)
+void __devinit acpuclk_register(struct acpuclk_data *data)
{
acpuclk_data = data;
}
-
-int __init acpuclk_init(struct acpuclk_soc_data *soc_data)
-{
- int rc;
-
- if (!soc_data->init)
- return -EINVAL;
-
- rc = soc_data->init(soc_data);
- if (rc)
- return rc;
-
- if (!acpuclk_data)
- return -ENODEV;
-
- return 0;
-}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
index c5f0ee3..e73a2af 100644
--- a/arch/arm/mach-msm/acpuclock.h
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -31,12 +31,11 @@
};
/**
- * struct acpuclk_soc_data - SoC data for acpuclk_init()
+ * struct acpuclk_pdata - Platform data for acpuclk
*/
-struct acpuclk_soc_data {
+struct acpuclk_pdata {
unsigned long max_speed_delta_khz;
unsigned int max_axi_khz;
- int (*init)(struct acpuclk_soc_data *);
};
/**
@@ -91,25 +90,4 @@
*/
void acpuclk_register(struct acpuclk_data *data);
-/**
- * acpuclk_init() - acpuclock driver initialization function
- *
- * Return 0 for success.
- */
-int acpuclk_init(struct acpuclk_soc_data *);
-
-/* SoC-specific acpuclock initialization functions. */
-extern struct acpuclk_soc_data acpuclk_7x27_soc_data;
-extern struct acpuclk_soc_data acpuclk_7x27a_soc_data;
-extern struct acpuclk_soc_data acpuclk_7x27aa_soc_data;
-extern struct acpuclk_soc_data acpuclk_7x30_soc_data;
-extern struct acpuclk_soc_data acpuclk_8x50_soc_data;
-extern struct acpuclk_soc_data acpuclk_8x60_soc_data;
-extern struct acpuclk_soc_data acpuclk_8960_soc_data;
-extern struct acpuclk_soc_data acpuclk_9xxx_soc_data;
-extern struct acpuclk_soc_data acpuclk_9615_soc_data;
-extern struct acpuclk_soc_data acpuclk_8930_soc_data;
-extern struct acpuclk_soc_data acpuclk_8064_soc_data;
-extern struct acpuclk_soc_data acpuclk_8625_soc_data;
-
#endif
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 2d1f787..c37491d 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -334,17 +334,11 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
.csid_core = 0,
- .is_csiphy = 1,
- .is_csid = 1,
- .is_ispif = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
.csid_core = 1,
- .is_csiphy = 1,
- .is_csid = 1,
- .is_ispif = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 71ad49a..101a26d 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -58,11 +58,15 @@
};
#define LVDS_CHIMEI_PANEL_NAME "lvds_chimei_wxga"
+#define LVDS_FRC_PANEL_NAME "lvds_frc_fhd"
#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
#define HDMI_PANEL_NAME "hdmi_msm"
#define TVOUT_PANEL_NAME "tvout_msm"
+#define LVDS_PIXEL_MAP_PATTERN_1 1
+#define LVDS_PIXEL_MAP_PATTERN_2 2
+
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
static unsigned char hdmi_is_primary = 1;
#else
@@ -98,12 +102,18 @@
strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
PANEL_NAME_MAX_LEN)))
return 0;
- } else if (machine_is_apq8064_cdp() ||
- machine_is_mpq8064_dtv()) {
+ } else if (machine_is_apq8064_cdp()) {
if (!strncmp(name, LVDS_CHIMEI_PANEL_NAME,
strnlen(LVDS_CHIMEI_PANEL_NAME,
PANEL_NAME_MAX_LEN)))
return 0;
+ } else if (machine_is_mpq8064_dtv()) {
+ if (!strncmp(name, LVDS_FRC_PANEL_NAME,
+ strnlen(LVDS_FRC_PANEL_NAME,
+ PANEL_NAME_MAX_LEN))) {
+ set_mdp_clocks_for_wuxga();
+ return 0;
+ }
}
if (!strncmp(name, HDMI_PANEL_NAME,
@@ -283,12 +293,16 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
static int hdmi_cec_power(int on);
+static int hdmi_gpio_config(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -599,7 +613,9 @@
u32 ver = socinfo_get_version();
if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
(SOCINFO_VERSION_MINOR(ver) == 0))
- return 1;
+ return LVDS_PIXEL_MAP_PATTERN_1;
+ } else if (machine_is_mpq8064_dtv()) {
+ return LVDS_PIXEL_MAP_PATTERN_2;
}
return 0;
}
@@ -624,6 +640,23 @@
}
};
+#define FRC_GPIO_UPDATE (SX150X_EXP4_GPIO_BASE + 8)
+#define FRC_GPIO_RESET (SX150X_EXP4_GPIO_BASE + 9)
+#define FRC_GPIO_PWR (SX150X_EXP4_GPIO_BASE + 10)
+
+static int lvds_frc_gpio[] = {FRC_GPIO_UPDATE, FRC_GPIO_RESET, FRC_GPIO_PWR};
+static struct lvds_panel_platform_data lvds_frc_pdata = {
+ .gpio = lvds_frc_gpio,
+};
+
+static struct platform_device lvds_frc_panel_device = {
+ .name = "lvds_frc_fhd",
+ .id = 0,
+ .dev = {
+ .platform_data = &lvds_frc_pdata,
+ }
+};
+
static int dsi2lvds_gpio[2] = {
LPM_CHANNEL,/* Backlight PWM-ID=0 for PMIC-GPIO#24 */
0x1F08 /* DSI2LVDS Bridge GPIO Output, mask=0x1f, out=0x08 */
@@ -687,8 +720,22 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
+
static int hdmi_enable_5v(int on)
{
/* TBD: PM8921 regulator instead of 8901 */
@@ -736,7 +783,6 @@
static struct regulator *reg_8921_lvs7, *reg_8921_s4, *reg_ext_3p3v;
static int prev_on;
int rc;
- int pmic_gpio14 = PM8921_GPIO_PM_TO_SYS(14);
if (on == prev_on)
return 0;
@@ -793,20 +839,61 @@
rc = regulator_enable(reg_ext_3p3v);
if (rc) {
pr_err("enable reg_ext_3p3v failed, rc=%d\n", rc);
- return -ENODEV;
+ return rc;
}
rc = regulator_enable(reg_8921_lvs7);
if (rc) {
pr_err("'%s' regulator enable failed, rc=%d\n",
"hdmi_vdda", rc);
- return rc;
+ goto error1;
}
rc = regulator_enable(reg_8921_s4);
if (rc) {
pr_err("'%s' regulator enable failed, rc=%d\n",
"hdmi_lvl_tsl", rc);
- return rc;
+ goto error2;
}
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ rc = regulator_disable(reg_ext_3p3v);
+ if (rc) {
+ pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_8921_lvs7);
+ if (rc) {
+ pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ rc = regulator_disable(reg_8921_s4);
+ if (rc) {
+ pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
+ return -ENODEV;
+ }
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+
+error2:
+ regulator_disable(reg_8921_lvs7);
+error1:
+ regulator_disable(reg_ext_3p3v);
+ return rc;
+}
+
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+ int pmic_gpio14 = PM8921_GPIO_PM_TO_SYS(14);
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
rc = gpio_request(HDMI_DDC_CLK_GPIO, "HDMI_DDC_CLK");
if (rc) {
pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
@@ -844,27 +931,10 @@
gpio_set_value_cansleep(pmic_gpio14, 1);
gpio_free(pmic_gpio14);
}
-
- rc = regulator_disable(reg_ext_3p3v);
- if (rc) {
- pr_err("disable reg_ext_3p3v failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_8921_lvs7);
- if (rc) {
- pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
- return -ENODEV;
- }
- rc = regulator_disable(reg_8921_s4);
- if (rc) {
- pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
- return -ENODEV;
- }
pr_debug("%s(off): success\n", __func__);
}
prev_on = on;
-
return 0;
error4:
@@ -874,8 +944,6 @@
error2:
gpio_free(HDMI_DDC_CLK_GPIO);
error1:
- regulator_disable(reg_8921_lvs7);
- regulator_disable(reg_8921_s4);
return rc;
}
@@ -921,6 +989,8 @@
platform_device_register(&mipi_dsi2lvds_bridge_device);
if (machine_is_apq8064_mtp())
platform_device_register(&mipi_dsi_toshiba_panel_device);
+ if (machine_is_mpq8064_dtv())
+ platform_device_register(&lvds_frc_panel_device);
msm_fb_register_device("mdp", &mdp_pdata);
msm_fb_register_device("lvds", &lvds_pdata);
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 877c9fc..fc886ed 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -126,7 +126,6 @@
PM8921_GPIO_INPUT(38, PM_GPIO_PULL_UP_30),
/* TABLA CODEC RESET */
PM8921_GPIO_OUTPUT(34, 1, MED),
- PM8921_GPIO_INPUT(31, PM_GPIO_PULL_NO),
PM8921_GPIO_OUTPUT(13, 0, HIGH), /* PCIE_CLK_PWR_EN */
};
@@ -237,11 +236,16 @@
14, 10, 6, 4, 1
};
+/*
+ * Note: There is a bug in LPG module that results in incorrect
+ * behavior of pattern when LUT index 0 is used. So effectively
+ * there are 63 usable LUT entries.
+ */
static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
.duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
.num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
- .start_idx = 0,
+ .start_idx = 1,
};
static struct pm8xxx_led_config pm8921_led_configs[] = {
@@ -360,6 +364,7 @@
static struct pm8xxx_ccadc_platform_data
apq8064_pm8xxx_ccadc_pdata = {
.r_sense = 10,
+ .calib_delay_ms = 600000,
};
static struct pm8921_bms_platform_data
@@ -368,7 +373,6 @@
.r_sense = 10,
.i_test = 2500,
.v_failure = 3000,
- .calib_delay_ms = 600000,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
};
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 40222b8..622b213 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -54,7 +54,7 @@
};
VREG_CONSUMERS(L7) = {
REGULATOR_SUPPLY("8921_l7", NULL),
- REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.3"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.3"),
};
VREG_CONSUMERS(L8) = {
REGULATOR_SUPPLY("8921_l8", NULL),
@@ -162,7 +162,7 @@
};
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8921_s4", NULL),
- REGULATOR_SUPPLY("sdc_vccq", "msm_sdcc.1"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.1"),
REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"),
REGULATOR_SUPPLY("CDC_VDD_CP", "tabla-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla-slim"),
@@ -265,9 +265,6 @@
REGULATOR_SUPPLY("ext_ts_sw", NULL),
REGULATOR_SUPPLY("vdd_ana", "3-005b"),
};
-VREG_CONSUMERS(FRC_5V) = {
- REGULATOR_SUPPLY("frc_5v", NULL),
-};
VREG_CONSUMERS(AVC_1P2V) = {
REGULATOR_SUPPLY("avc_1p2v", NULL),
};
@@ -519,7 +516,6 @@
struct gpio_regulator_platform_data
mpq8064_gpio_regulator_pdata[] __devinitdata = {
- GPIO_VREG(FRC_5V, "frc_5v", "frc_5v_en", SX150X_GPIO(4, 10), NULL),
GPIO_VREG(AVC_1P2V, "avc_1p2v", "avc_1p2v_en", SX150X_GPIO(4, 2), NULL),
GPIO_VREG(AVC_1P8V, "avc_1p8v", "avc_1p8v_en", SX150X_GPIO(4, 4), NULL),
GPIO_VREG(AVC_2P2V, "avc_2p2v", "avc_2p2v_en",
@@ -532,15 +528,15 @@
/* SAW regulator constraints */
struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(S5, "8921_s5", 950000, 1300000);
+ SAW_VREG_INIT(S5, "8921_s5", 850000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6 =
- SAW_VREG_INIT(S6, "8921_s6", 950000, 1300000);
+ SAW_VREG_INIT(S6, "8921_s6", 850000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0 =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(8821_S0, "8821_s0", 950000, 1300000);
+ SAW_VREG_INIT(8821_S0, "8821_s0", 850000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8821_s1 =
- SAW_VREG_INIT(8821_S1, "8821_s1", 950000, 1300000);
+ SAW_VREG_INIT(8821_S1, "8821_s1", 850000, 1300000);
/* PM8921 regulator constraints */
struct pm8xxx_regulator_platform_data
@@ -564,7 +560,7 @@
RPM_SMPS(S2, 0, 1, 0, 1300000, 1300000, NULL, 0, 1p60, NONE, NONE),
RPM_SMPS(S3, 0, 1, 1, 500000, 1150000, NULL, 100000, 4p80, NONE, NONE),
RPM_SMPS(S4, 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60, AUTO, AUTO),
- RPM_SMPS(S7, 0, 1, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
+ RPM_SMPS(S7, 0, 0, 0, 1300000, 1300000, NULL, 100000, 3p20, NONE, NONE),
RPM_SMPS(S8, 0, 1, 0, 2200000, 2200000, NULL, 0, 1p60, NONE, NONE),
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
@@ -589,8 +585,8 @@
RPM_LDO(L22, 0, 1, 0, 2600000, 2600000, NULL, 0, 0),
RPM_LDO(L23, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
RPM_LDO(L24, 0, 1, 1, 750000, 1150000, "8921_s1", 10000, 10000),
- RPM_LDO(L25, 1, 1, 0, 1225000, 1225000, "8921_s1", 10000, 10000),
- RPM_LDO(L27, 0, 1, 0, 1100000, 1100000, "8921_s7", 0, 0),
+ RPM_LDO(L25, 1, 1, 0, 1250000, 1250000, "8921_s1", 10000, 10000),
+ RPM_LDO(L27, 0, 0, 0, 1100000, 1100000, "8921_s7", 0, 0),
RPM_LDO(L28, 0, 1, 0, 1050000, 1050000, "8921_s7", 0, 0),
RPM_LDO(L29, 0, 1, 0, 2000000, 2000000, NULL, 0, 0),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 193fc4a..a53f771 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -56,23 +56,19 @@
}
};
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+/* SDCC controllers may require voting for VDD IO voltage */
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
/* SDCC1 : eMMC card connected */
[SDCC1] = {
- .name = "sdc_vccq",
+ .name = "sdc_vdd_io",
.always_on = 1,
.high_vol_level = 1800000,
.low_vol_level = 1800000,
.hpm_uA = 200000, /* 200mA */
- }
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+ },
/* SDCC3 : External card slot connected */
[SDCC3] = {
- .name = "sdc_vddp",
+ .name = "sdc_vdd_io",
.high_vol_level = 2950000,
.low_vol_level = 1850000,
.always_on = 1,
@@ -92,12 +88,12 @@
/* SDCC1 : eMMC card connected */
[SDCC1] = {
.vdd_data = &mmc_vdd_reg_data[SDCC1],
- .vccq_data = &mmc_vccq_reg_data[SDCC1],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
},
/* SDCC3 : External card slot connected */
[SDCC3] = {
.vdd_data = &mmc_vdd_reg_data[SDCC3],
- .vddp_data = &mmc_vddp_reg_data[SDCC3],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC3],
}
};
@@ -251,7 +247,6 @@
#endif
.sup_clk_table = sdc1_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
- .pclk_src_dfab = 1,
.nonremovable = 1,
.pin_data = &mmc_slot_pin_data[SDCC1],
.vreg_data = &mmc_slot_vreg_data[SDCC1],
@@ -274,7 +269,6 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc2_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc2_sup_clk_rates),
- .pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC2],
.sdiowakeup_irq = MSM_GPIO_TO_INT(61),
.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
@@ -294,11 +288,10 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc3_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
- .pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC3],
.vreg_data = &mmc_slot_vreg_data[SDCC3],
.wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(17),
- .wpswitch_polarity = 1,
+ .is_wpswitch_active_low = true,
.status_gpio = 26,
.status_irq = MSM_GPIO_TO_INT(26),
.irq_flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
@@ -326,7 +319,6 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc4_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc4_sup_clk_rates),
- .pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC4],
.sdiowakeup_irq = MSM_GPIO_TO_INT(65),
.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
@@ -362,14 +354,33 @@
if (apq8064_sdc3_pdata) {
if (!machine_is_apq8064_cdp()) {
apq8064_sdc3_pdata->wpswitch_gpio = 0;
- apq8064_sdc3_pdata->wpswitch_polarity = 0;
+ apq8064_sdc3_pdata->is_wpswitch_active_low = false;
}
if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
machine_is_mpq8064_dtv()) {
+ int rc;
+ struct pm_gpio sd_card_det_init_cfg = {
+ .direction = PM_GPIO_DIR_IN,
+ .output_buffer = PM_GPIO_OUT_BUF_CMOS,
+ .pull = PM_GPIO_PULL_UP_30,
+ .vin_sel = PM_GPIO_VIN_S4,
+ .out_strength = PM_GPIO_STRENGTH_NO,
+ .function = PM_GPIO_FUNC_NORMAL,
+ };
+
apq8064_sdc3_pdata->status_gpio =
PM8921_GPIO_PM_TO_SYS(31);
apq8064_sdc3_pdata->status_irq =
PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 31);
+ rc = pm8xxx_gpio_config(apq8064_sdc3_pdata->status_gpio,
+ &sd_card_det_init_cfg);
+ if (rc) {
+ pr_info("%s: SD_CARD_DET GPIO%d config "
+ "failed(%d)\n", __func__,
+ apq8064_sdc3_pdata->status_gpio, rc);
+ apq8064_sdc3_pdata->status_gpio = 0;
+ apq8064_sdc3_pdata->status_irq = 0;
+ }
}
apq8064_add_sdcc(3, apq8064_sdc3_pdata);
}
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 806bbd8..1d231ef 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -74,7 +74,6 @@
#include "msm_watchdog.h"
#include "board-8064.h"
-#include "acpuclock.h"
#include "spm.h"
#include <mach/mpm.h>
#include "rpm_resources.h"
@@ -1027,13 +1026,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
@@ -1094,13 +1093,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1225000,
- .max_uV = 1225000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
@@ -2110,6 +2109,7 @@
};
static struct platform_device *common_devices[] __initdata = {
+ &msm8960_device_acpuclk,
&apq8064_device_dmov,
&apq8064_device_qup_spi_gsbi5,
&apq8064_device_ext_5v_vreg,
@@ -2187,8 +2187,10 @@
&apq_cpudai_stub,
&apq_cpudai_slimbus_1_rx,
&apq_cpudai_slimbus_1_tx,
+ &apq_cpudai_slimbus_2_rx,
&apq_cpudai_slimbus_2_tx,
&apq_cpudai_slimbus_3_rx,
+ &apq_cpudai_slimbus_3_tx,
&apq8064_rpm_device,
&apq8064_rpm_log_device,
&apq8064_rpm_stat_device,
@@ -2208,6 +2210,8 @@
&apq8064_cpu_idle_device,
&apq8064_msm_gov_device,
&apq8064_device_cache_erp,
+ &msm8960_device_ebi1_ch0_erp,
+ &msm8960_device_ebi1_ch1_erp,
&epm_adc_device,
&apq8064_qdss_device,
&msm_etb_device,
@@ -2247,16 +2251,6 @@
};
static struct platform_device
-mpq8064_device_ext_5v_frc_vreg __devinitdata = {
- .name = GPIO_REGULATOR_DEV_NAME,
- .id = SX150X_GPIO(4, 10),
- .dev = {
- .platform_data =
- &mpq8064_gpio_regulator_pdata[GPIO_VREG_ID_FRC_5V],
- },
-};
-
-static struct platform_device
mpq8064_device_ext_1p2_buck_vreg __devinitdata = {
.name = GPIO_REGULATOR_DEV_NAME,
.id = SX150X_GPIO(4, 2),
@@ -2345,7 +2339,6 @@
&msm_rotator_device,
#endif
&gpio_ir_recv_pdev,
- &mpq8064_device_ext_5v_frc_vreg,
&mpq8064_device_ext_1p2_buck_vreg,
&mpq8064_device_ext_1p8_buck_vreg,
&mpq8064_device_ext_2p2_buck_vreg,
@@ -2918,7 +2911,6 @@
ARRAY_SIZE(apq8064_slim_devices));
apq8064_init_dsps();
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
- acpuclk_init(&acpuclk_8064_soc_data);
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
diff --git a/arch/arm/mach-msm/board-8064.h b/arch/arm/mach-msm/board-8064.h
index 39c367f..a241ab3 100644
--- a/arch/arm/mach-msm/board-8064.h
+++ b/arch/arm/mach-msm/board-8064.h
@@ -45,12 +45,11 @@
#define GPIO_VREG_ID_EXT_TS_SW 2
#define GPIO_VREG_ID_EXT_MPP8 3
-#define GPIO_VREG_ID_FRC_5V 0
-#define GPIO_VREG_ID_AVC_1P2V 1
-#define GPIO_VREG_ID_AVC_1P8V 2
-#define GPIO_VREG_ID_AVC_2P2V 3
-#define GPIO_VREG_ID_AVC_5V 4
-#define GPIO_VREG_ID_AVC_3P3V 5
+#define GPIO_VREG_ID_AVC_1P2V 0
+#define GPIO_VREG_ID_AVC_1P8V 1
+#define GPIO_VREG_ID_AVC_2P2V 2
+#define GPIO_VREG_ID_AVC_5V 3
+#define GPIO_VREG_ID_AVC_3P3V 4
#define APQ8064_EXT_3P3V_REG_EN_GPIO 77
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index e7f0e68..6ee315c 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -342,17 +342,11 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
.csid_core = 0,
- .is_csiphy = 1,
- .is_csid = 1,
- .is_ispif = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
.csid_core = 1,
- .is_csiphy = 1,
- .is_csid = 1,
- .is_ispif = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index e18e40d..8a837d6 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -516,12 +516,16 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
static int hdmi_cec_power(int on);
+static int hdmi_gpio_config(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -594,7 +598,21 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
+
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
@@ -674,30 +692,8 @@
"hdmi_avdd", rc);
return rc;
}
- rc = gpio_request(100, "HDMI_DDC_CLK");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_CLK", 100, rc);
- goto error1;
- }
- rc = gpio_request(101, "HDMI_DDC_DATA");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_DATA", 101, rc);
- goto error2;
- }
- rc = gpio_request(102, "HDMI_HPD");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_HPD", 102, rc);
- goto error3;
- }
pr_debug("%s(on): success\n", __func__);
} else {
- gpio_free(100);
- gpio_free(101);
- gpio_free(102);
-
rc = regulator_disable(reg_8038_l23);
if (rc) {
pr_err("disable reg_8038_l23 failed, rc=%d\n", rc);
@@ -714,13 +710,50 @@
prev_on = on;
return 0;
+}
-error3:
- gpio_free(101);
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
+ rc = gpio_request(100, "HDMI_DDC_CLK");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_CLK", 100, rc);
+ return rc;
+ }
+ rc = gpio_request(101, "HDMI_DDC_DATA");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_DATA", 101, rc);
+ goto error1;
+ }
+ rc = gpio_request(102, "HDMI_HPD");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_HPD", 102, rc);
+ goto error2;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(100);
+ gpio_free(101);
+ gpio_free(102);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+ return 0;
+
error2:
- gpio_free(100);
+ gpio_free(101);
error1:
- regulator_disable(reg_8038_l23);
+ gpio_free(100);
return rc;
}
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index c7ab260..000f080 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -624,6 +624,22 @@
},
};
+static struct gpiomux_setting sd_det_line = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm8930_sd_det_config[] __initdata = {
+ {
+ .gpio = 94, /* SD Card Detect Line */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &sd_det_line,
+ [GPIOMUX_ACTIVE] = &sd_det_line,
+ },
+ },
+};
+
int __init msm8930_init_gpiomux(void)
{
int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -687,5 +703,9 @@
msm_gpiomux_install(msm8960_mdp_vsync_configs,
ARRAY_SIZE(msm8960_mdp_vsync_configs));
+
+ msm_gpiomux_install(msm8930_sd_det_config,
+ ARRAY_SIZE(msm8930_sd_det_config));
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index cf7a829..e6a13b1 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -274,11 +274,16 @@
14, 10, 6, 4, 1
};
+/*
+ * Note: There is a bug in LPG module that results in incorrect
+ * behavior of pattern when LUT index 0 is used. So effectively
+ * there are 63 usable LUT entries.
+ */
static struct pm8xxx_pwm_duty_cycles pm8038_led0_pwm_duty_cycles = {
.duty_pcts = (int *)&pm8038_led0_pwm_duty_pcts,
.num_duty_pcts = ARRAY_SIZE(pm8038_led0_pwm_duty_pcts),
.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
- .start_idx = 0,
+ .start_idx = 1,
};
static struct pm8xxx_led_config pm8038_led_configs[] = {
@@ -323,6 +328,7 @@
static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
.r_sense = 10,
+ .calib_delay_ms = 600000,
};
static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
@@ -338,7 +344,6 @@
.r_sense = 10,
.i_test = 2500,
.v_failure = 3000,
- .calib_delay_ms = 600000,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
};
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index 2f24c95..5bee8a2 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -80,7 +80,7 @@
REGULATOR_SUPPLY("vdd_dig", "3-004a"),
REGULATOR_SUPPLY("iris_vddio", "wcnss_wlan.0"),
REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"),
- REGULATOR_SUPPLY("sdc_vccq", "msm_sdcc.1"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.1"),
REGULATOR_SUPPLY("VDDIO_CDC", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_TX", "sitar-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "sitar-slim"),
@@ -129,7 +129,7 @@
};
VREG_CONSUMERS(L22) = {
REGULATOR_SUPPLY("8038_l22", NULL),
- REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.3"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.3"),
};
VREG_CONSUMERS(L23) = {
REGULATOR_SUPPLY("8038_l23", NULL),
@@ -485,7 +485,7 @@
RPM_LDO(L15, 0, 1, 0, 1800000, 2950000, NULL, 0, 0),
RPM_LDO(L17, 0, 1, 0, 1800000, 2950000, NULL, 0, 0),
RPM_LDO(L18, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
- RPM_LDO(L20, 1, 1, 0, 1200000, 1200000, "8038_s2", 10000, 10000),
+ RPM_LDO(L20, 1, 1, 0, 1250000, 1250000, "8038_s2", 10000, 10000),
RPM_LDO(L21, 0, 1, 0, 1900000, 1900000, "8038_s4", 0, 0),
RPM_LDO(L22, 1, 1, 0, 1850000, 2950000, NULL, 10000, 10000),
RPM_LDO(L23, 1, 1, 1, 1800000, 1800000, "8038_s4", 0, 0),
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index 52a11bc..739b1c7 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -53,27 +53,35 @@
.name = "sdc_vdd",
.high_vol_level = 2950000,
.low_vol_level = 2950000,
- .hpm_uA = 800000, /* 800mA */
- }
-};
-
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
- /* SDCC1 : eMMC card connected */
- [SDCC1] = {
- .name = "sdc_vccq",
+ /*
+ * Normally this is not an always ON regulator. On this
+ * platform, unfortunately the sd detect line is connected
+ * to this via esd circuit and so turn this off/on while card
+ * is not present causes the sd detect line to toggle
+ * continuously. This is expected to be fixed in the newer
+ * hardware revisions - maybe once that is done, this can be
+ * reverted.
+ */
.always_on = 1,
- .high_vol_level = 1800000,
- .low_vol_level = 1800000,
- .hpm_uA = 200000, /* 200mA */
+ .lpm_sup = 1,
+ .hpm_uA = 800000, /* 800mA */
+ .lpm_uA = 9000,
}
};
/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
+ /* SDCC1 : eMMC card connected */
+ [SDCC1] = {
+ .name = "sdc_vdd_io",
+ .always_on = 1,
+ .high_vol_level = 1800000,
+ .low_vol_level = 1800000,
+ .hpm_uA = 200000, /* 200mA */
+ },
/* SDCC3 : External card slot connected */
[SDCC3] = {
- .name = "sdc_vddp",
+ .name = "sdc_vdd_io",
.high_vol_level = 2950000,
.low_vol_level = 1850000,
.always_on = 1,
@@ -93,12 +101,12 @@
/* SDCC1 : eMMC card connected */
[SDCC1] = {
.vdd_data = &mmc_vdd_reg_data[SDCC1],
- .vccq_data = &mmc_vccq_reg_data[SDCC1],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
},
/* SDCC3 : External card slot connected */
[SDCC3] = {
.vdd_data = &mmc_vdd_reg_data[SDCC3],
- .vddp_data = &mmc_vddp_reg_data[SDCC3],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC3],
}
};
@@ -212,7 +220,7 @@
#define MSM_MPM_PIN_SDC3_DAT1 21
static unsigned int sdc1_sup_clk_rates[] = {
- 400000, 24000000, 48000000,
+ 400000, 24000000, 48000000, 96000000
};
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
@@ -231,7 +239,6 @@
#endif
.sup_clk_table = sdc1_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
- .pclk_src_dfab = 1,
.nonremovable = 1,
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.pin_data = &mmc_slot_pin_data[SDCC1],
@@ -246,14 +253,13 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc3_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
- .pclk_src_dfab = 1,
#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT
/*TODO: Insert right replacement for PM8038 */
#ifndef MSM8930_PHASE_2
.wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
#else
.wpswitch_gpio = 66,
- .wpswitch_polarity = 1,
+ .is_wpswitch_active_low = true,
#endif
#endif
.vreg_data = &mmc_slot_vreg_data[SDCC3],
@@ -282,6 +288,16 @@
void __init msm8930_init_mmc(void)
{
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ /*
+ * When eMMC runs in DDR mode on CDP platform, we have
+ * seen instability due to DATA CRC errors. These errors are
+ * attributed to long physical path between MSM and eMMC on CDP.
+ * So let's not enable the DDR mode on CDP platform but let other
+ * platforms take advantage of eMMC DDR mode.
+ */
+ if (!machine_is_msm8930_cdp())
+ msm8960_sdc1_data.uhs_caps |= (MMC_CAP_1_8V_DDR |
+ MMC_CAP_UHS_DDR50);
/* SDC1 : eMMC card connected */
msm_add_sdcc(1, &msm8960_sdc1_data);
#endif
@@ -289,7 +305,7 @@
/* SDC3: External card slot */
if (!machine_is_msm8930_cdp()) {
msm8960_sdc3_data.wpswitch_gpio = 0;
- msm8960_sdc3_data.wpswitch_polarity = 0;
+ msm8960_sdc3_data.is_wpswitch_active_low = false;
}
msm_add_sdcc(3, &msm8960_sdc3_data);
#endif
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 98d9f3a..e075630 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -86,7 +86,6 @@
#include <mach/cpuidle.h>
#include "rpm_resources.h"
#include <mach/mpm.h>
-#include "acpuclock.h"
#include "smd_private.h"
#include "pm-boot.h"
#include "msm_watchdog.h"
@@ -126,6 +125,7 @@
#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define HOLE_SIZE 0x20000
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
@@ -138,7 +138,7 @@
#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_HEAP_NUM 8
#endif
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* 2MB - 128Kb */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
@@ -146,10 +146,11 @@
#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
-#define MSM8930_FIXED_AREA_START 0xa0000000
+#define MSM_MM_FW_SIZE (0x200000 - HOLE_SIZE) /*2MB -128Kb */
+#define MSM8930_FIXED_AREA_START (0xa0000000 - (MSM_ION_MM_FW_SIZE + \
+ HOLE_SIZE))
#define MAX_FIXED_AREA_SIZE 0x10000000
-#define MSM_MM_FW_SIZE 0x200000
-#define MSM8930_FW_START (MSM8930_FIXED_AREA_START - MSM_MM_FW_SIZE)
+#define MSM8930_FW_START MSM8930_FIXED_AREA_START
#else
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
@@ -560,7 +561,8 @@
return;
if (msm8930_fmem_pdata.size) {
- msm8930_fmem_pdata.reserved_size_low = fixed_low_size;
+ msm8930_fmem_pdata.reserved_size_low = fixed_low_size +
+ HOLE_SIZE;
msm8930_fmem_pdata.reserved_size_high = fixed_high_size;
}
@@ -572,7 +574,7 @@
msm8930_reserve_fixed_area(fixed_size);
fixed_low_start = MSM8930_FIXED_AREA_START;
- fixed_middle_start = fixed_low_start + fixed_low_size;
+ fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
fixed_high_start = fixed_middle_start + fixed_middle_size;
for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
@@ -580,11 +582,13 @@
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
+ struct ion_cp_heap_pdata *pdata = NULL;
switch (heap->type) {
case ION_HEAP_TYPE_CP:
- fixed_position = ((struct ion_cp_heap_pdata *)
- heap->extra_data)->fixed_position;
+ pdata =
+ (struct ion_cp_heap_pdata *)heap->extra_data;
+ fixed_position = pdata->fixed_position;
break;
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
@@ -600,6 +604,9 @@
break;
case FIXED_MIDDLE:
heap->base = fixed_middle_start;
+ pdata->secure_base = fixed_middle_start
+ - HOLE_SIZE;
+ pdata->secure_size = HOLE_SIZE + heap->size;
break;
case FIXED_HIGH:
heap->base = fixed_high_start;
@@ -778,13 +785,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
@@ -842,13 +849,13 @@
{
.name = "VDDD_CDC_D",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_D_CUR_MAX,
},
{
.name = "CDC_VDDA_A_1P2V",
.min_uV = 1200000,
- .max_uV = 1200000,
+ .max_uV = 1250000,
.optimum_uA = WCD9XXX_VDDD_CDC_A_CUR_MAX,
},
},
@@ -1010,6 +1017,55 @@
#define QCE_SHARE_CE_RESOURCE 1
#define QCE_CE_SHARED 0
+/* Begin Bus scaling definitions */
+static struct msm_bus_vectors crypto_hw_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT1,
+ .dst = MSM_BUS_SLAVE_GSBI1_UART,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors crypto_hw_active_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 70000000UL,
+ .ib = 70000000UL,
+ },
+ {
+ .src = MSM_BUS_MASTER_ADM_PORT1,
+ .dst = MSM_BUS_SLAVE_GSBI1_UART,
+ .ab = 2480000000UL,
+ .ib = 2480000000UL,
+ },
+};
+
+static struct msm_bus_paths crypto_hw_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(crypto_hw_init_vectors),
+ crypto_hw_init_vectors,
+ },
+ {
+ ARRAY_SIZE(crypto_hw_active_vectors),
+ crypto_hw_active_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata crypto_hw_bus_scale_pdata = {
+ crypto_hw_bus_scale_usecases,
+ ARRAY_SIZE(crypto_hw_bus_scale_usecases),
+ .name = "cryptohw",
+};
+/* End Bus Scaling Definitions*/
+
static struct resource qcrypto_resources[] = {
[0] = {
.start = QCE_0_BASE,
@@ -1072,6 +1128,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = &crypto_hw_bus_scale_pdata,
};
static struct platform_device qcrypto_device = {
@@ -1094,6 +1151,7 @@
.shared_ce_resource = QCE_SHARE_CE_RESOURCE,
.hw_key_support = QCE_HW_KEY_SUPPORT,
.sha_hmac = QCE_SHA_HMAC_SUPPORT,
+ .bus_scale_table = &crypto_hw_bus_scale_pdata,
};
static struct platform_device qcedev_device = {
@@ -1194,6 +1252,7 @@
[23] = MSM_GPIO_TO_INT(85),
[24] = MSM_GPIO_TO_INT(83),
[25] = USB1_HS_IRQ,
+ [26] = MSM_GPIO_TO_INT(6),
[27] = HDMI_IRQ,
[29] = MSM_GPIO_TO_INT(10),
[30] = MSM_GPIO_TO_INT(102),
@@ -1207,15 +1266,15 @@
[38] = MSM_GPIO_TO_INT(50),
[39] = MSM_GPIO_TO_INT(42),
[41] = MSM_GPIO_TO_INT(62),
- [42] = MSM_GPIO_TO_INT(76),
- [43] = MSM_GPIO_TO_INT(75),
+ [42] = MSM_GPIO_TO_INT(8),
+ [43] = MSM_GPIO_TO_INT(33),
[44] = MSM_GPIO_TO_INT(70),
[45] = MSM_GPIO_TO_INT(69),
[46] = MSM_GPIO_TO_INT(67),
[47] = MSM_GPIO_TO_INT(65),
- [48] = MSM_GPIO_TO_INT(58),
- [49] = MSM_GPIO_TO_INT(54),
- [50] = MSM_GPIO_TO_INT(52),
+ [48] = MSM_GPIO_TO_INT(55),
+ [49] = MSM_GPIO_TO_INT(74),
+ [50] = MSM_GPIO_TO_INT(98),
[51] = MSM_GPIO_TO_INT(49),
[52] = MSM_GPIO_TO_INT(40),
[53] = MSM_GPIO_TO_INT(37),
@@ -1975,6 +2034,7 @@
};
static struct platform_device *common_devices[] __initdata = {
+ &msm8960_device_acpuclk,
&msm8960_device_dmov,
&msm_device_smd,
&msm8960_device_uart_gsbi5,
@@ -2373,7 +2433,6 @@
msm8930_init_cam();
#endif
msm8930_init_mmc();
- acpuclk_init(&acpuclk_8930_soc_data);
mxt_init_vkeys_8930();
register_i2c_devices();
msm8930_init_fb();
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 9c25b78..b6c03a4 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -399,25 +399,16 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
.csid_core = 0,
- .is_csiphy = 1,
- .is_csid = 1,
- .is_ispif = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
.csid_core = 1,
- .is_csiphy = 1,
- .is_csid = 1,
- .is_ispif = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
{
.csid_core = 2,
- .is_csiphy = 1,
- .is_csid = 1,
- .is_ispif = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
},
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index a9b2a59..c1017a9 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -717,12 +717,16 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
static int hdmi_cec_power(int on);
+static int hdmi_gpio_config(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -784,7 +788,21 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
+
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
#endif
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
@@ -885,30 +903,8 @@
"hdmi_vcc", rc);
return rc;
}
- rc = gpio_request(100, "HDMI_DDC_CLK");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_CLK", 100, rc);
- goto error1;
- }
- rc = gpio_request(101, "HDMI_DDC_DATA");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_DDC_DATA", 101, rc);
- goto error2;
- }
- rc = gpio_request(102, "HDMI_HPD");
- if (rc) {
- pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
- "HDMI_HPD", 102, rc);
- goto error3;
- }
pr_debug("%s(on): success\n", __func__);
} else {
- gpio_free(100);
- gpio_free(101);
- gpio_free(102);
-
rc = regulator_disable(reg_8921_l23);
if (rc) {
pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
@@ -930,14 +926,50 @@
prev_on = on;
return 0;
+}
-error3:
- gpio_free(101);
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
+ rc = gpio_request(100, "HDMI_DDC_CLK");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_CLK", 100, rc);
+ return rc;
+ }
+ rc = gpio_request(101, "HDMI_DDC_DATA");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_DDC_DATA", 101, rc);
+ goto error1;
+ }
+ rc = gpio_request(102, "HDMI_HPD");
+ if (rc) {
+ pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
+ "HDMI_HPD", 102, rc);
+ goto error2;
+ }
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ gpio_free(100);
+ gpio_free(101);
+ gpio_free(102);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+ return 0;
+
error2:
- gpio_free(100);
+ gpio_free(101);
error1:
- regulator_disable(reg_8921_l23);
- regulator_disable(reg_8921_s4);
+ gpio_free(100);
return rc;
}
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index ea1ab58..19564e9 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -442,9 +442,8 @@
.r_sense = 10,
.i_test = 2500,
.v_failure = 3000,
- .calib_delay_ms = 600000,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
- .rconn_mohm = 30,
+ .rconn_mohm = 18,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
@@ -529,11 +528,16 @@
14, 10, 6, 4, 1
};
+/*
+ * Note: There is a bug in LPG module that results in incorrect
+ * behavior of pattern when LUT index 0 is used. So effectively
+ * there are 63 usable LUT entries.
+ */
static struct pm8xxx_pwm_duty_cycles pm8921_led0_pwm_duty_cycles = {
.duty_pcts = (int *)&pm8921_led0_pwm_duty_pcts,
.num_duty_pcts = ARRAY_SIZE(pm8921_led0_pwm_duty_pcts),
.duty_ms = PM8XXX_LED_PWM_DUTY_MS,
- .start_idx = 0,
+ .start_idx = 1,
};
static struct pm8xxx_led_config pm8921_led_configs[] = {
@@ -562,6 +566,7 @@
static struct pm8xxx_ccadc_platform_data pm8xxx_ccadc_pdata = {
.r_sense = 10,
+ .calib_delay_ms = 600000,
};
/**
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index 93c72ea..bc5a892 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -53,7 +53,7 @@
};
VREG_CONSUMERS(L7) = {
REGULATOR_SUPPLY("8921_l7", NULL),
- REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.3"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.3"),
};
VREG_CONSUMERS(L8) = {
REGULATOR_SUPPLY("8921_l8", NULL),
@@ -162,9 +162,9 @@
};
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8921_s4", NULL),
- REGULATOR_SUPPLY("sdc_vccq", "msm_sdcc.1"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.1"),
REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.2"),
- REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.4"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.4"),
REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"),
REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"),
REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"),
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index 1279b75..4b09f82 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -65,23 +65,19 @@
}
};
-/* Only slots having eMMC card will require VCCQ voltage */
-static struct msm_mmc_reg_data mmc_vccq_reg_data[1] = {
+/* SDCC controllers may require voting for IO operating voltage */
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
/* SDCC1 : eMMC card connected */
[SDCC1] = {
- .name = "sdc_vccq",
+ .name = "sdc_vdd_io",
.always_on = 1,
.high_vol_level = 1800000,
.low_vol_level = 1800000,
.hpm_uA = 200000, /* 200mA */
- }
-};
-
-/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+ },
/* SDCC3 : External card slot connected */
[SDCC3] = {
- .name = "sdc_vddp",
+ .name = "sdc_vdd_io",
.high_vol_level = 2950000,
.low_vol_level = 1850000,
.always_on = 1,
@@ -97,7 +93,7 @@
},
/* SDCC4 : SDIO slot connected */
[SDCC4] = {
- .name = "sdc_vddp",
+ .name = "sdc_vdd_io",
.high_vol_level = 1800000,
.low_vol_level = 1800000,
.always_on = 1,
@@ -111,7 +107,7 @@
/* SDCC1 : eMMC card connected */
[SDCC1] = {
.vdd_data = &mmc_vdd_reg_data[SDCC1],
- .vccq_data = &mmc_vccq_reg_data[SDCC1],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
},
/* SDCC2 : SDIO card slot connected */
[SDCC2] = {
@@ -120,11 +116,11 @@
/* SDCC3 : External card slot connected */
[SDCC3] = {
.vdd_data = &mmc_vdd_reg_data[SDCC3],
- .vddp_data = &mmc_vddp_reg_data[SDCC3],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC3],
},
/* SDCC4 : SDIO card slot connected */
[SDCC4] = {
- .vddp_data = &mmc_vddp_reg_data[SDCC4],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC4],
},
};
@@ -275,7 +271,7 @@
#define MSM_MPM_PIN_SDC3_DAT1 21
static unsigned int sdc1_sup_clk_rates[] = {
- 400000, 24000000, 48000000
+ 400000, 24000000, 48000000, 96000000
};
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
@@ -294,7 +290,6 @@
#endif
.sup_clk_table = sdc1_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
- .pclk_src_dfab = 1,
.nonremovable = 1,
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.pin_data = &mmc_slot_pin_data[SDCC1],
@@ -313,7 +308,6 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc2_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc2_sup_clk_rates),
- .pclk_src_dfab = 1,
.vreg_data = &mmc_slot_vreg_data[SDCC2],
.pin_data = &mmc_slot_pin_data[SDCC2],
.sdiowakeup_irq = MSM_GPIO_TO_INT(90),
@@ -327,7 +321,6 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc3_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
- .pclk_src_dfab = 1,
#ifdef CONFIG_MMC_MSM_SDC3_WP_SUPPORT
.wpswitch_gpio = PM8921_GPIO_PM_TO_SYS(16),
#endif
@@ -358,7 +351,6 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc4_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc4_sup_clk_rates),
- .pclk_src_dfab = 1,
.vreg_data = &mmc_slot_vreg_data[SDCC4],
.pin_data = &mmc_slot_pin_data[SDCC4],
.sdiowakeup_irq = MSM_GPIO_TO_INT(85),
@@ -369,6 +361,16 @@
void __init msm8960_init_mmc(void)
{
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
+ /*
+ * When eMMC runs in DDR mode on CDP platform, we have
+ * seen instability due to DATA CRC errors. These errors are
+ * attributed to long physical path between MSM and eMMC on CDP.
+ * So let's not enable the DDR mode on CDP platform but let other
+ * platforms take advantage of eMMC DDR mode.
+ */
+ if (!machine_is_msm8960_cdp())
+ msm8960_sdc1_data.uhs_caps |= (MMC_CAP_1_8V_DDR |
+ MMC_CAP_UHS_DDR50);
/* SDC1 : eMMC card connected */
msm_add_sdcc(1, &msm8960_sdc1_data);
#endif
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index e0831fb..22ef940 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -50,6 +50,7 @@
#include <asm/mach/mmc.h>
#include <mach/board.h>
+#include <mach/msm_tspp.h>
#include <mach/msm_iomap.h>
#include <mach/msm_spi.h>
#include <mach/msm_serial_hs.h>
@@ -96,7 +97,6 @@
#include <mach/cpuidle.h>
#include "rpm_resources.h"
#include <mach/mpm.h>
-#include "acpuclock.h"
#include "smd_private.h"
#include "pm-boot.h"
#include "msm_watchdog.h"
@@ -144,6 +144,7 @@
#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define HOLE_SIZE 0x20000
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
@@ -156,7 +157,7 @@
#define MSM_ION_QSECOM_SIZE 0x600000 /* (6MB) */
#define MSM_ION_HEAP_NUM 8
#endif
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
+#define MSM_ION_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* 128kb */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
@@ -164,10 +165,11 @@
#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
-#define MSM8960_FIXED_AREA_START 0xa0000000
+#define MSM_MM_FW_SIZE (0x200000 - HOLE_SIZE) /* 2mb -128kb*/
+#define MSM8960_FIXED_AREA_START (0xa0000000 - (MSM_ION_MM_FW_SIZE + \
+ HOLE_SIZE))
#define MAX_FIXED_AREA_SIZE 0x10000000
-#define MSM_MM_FW_SIZE 0x200000
-#define MSM8960_FW_START (MSM8960_FIXED_AREA_START - MSM_MM_FW_SIZE)
+#define MSM8960_FW_START MSM8960_FIXED_AREA_START
static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
#else
@@ -640,7 +642,8 @@
return;
if (msm8960_fmem_pdata.size) {
- msm8960_fmem_pdata.reserved_size_low = fixed_low_size;
+ msm8960_fmem_pdata.reserved_size_low = fixed_low_size +
+ HOLE_SIZE;
msm8960_fmem_pdata.reserved_size_high = fixed_high_size;
}
@@ -652,7 +655,7 @@
msm8960_reserve_fixed_area(fixed_size);
fixed_low_start = MSM8960_FIXED_AREA_START;
- fixed_middle_start = fixed_low_start + fixed_low_size;
+ fixed_middle_start = fixed_low_start + fixed_low_size + HOLE_SIZE;
fixed_high_start = fixed_middle_start + fixed_middle_size;
for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
@@ -660,11 +663,13 @@
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
+ struct ion_cp_heap_pdata *pdata = NULL;
switch (heap->type) {
case ION_HEAP_TYPE_CP:
- fixed_position = ((struct ion_cp_heap_pdata *)
- heap->extra_data)->fixed_position;
+ pdata =
+ (struct ion_cp_heap_pdata *)heap->extra_data;
+ fixed_position = pdata->fixed_position;
break;
case ION_HEAP_TYPE_CARVEOUT:
fixed_position = ((struct ion_co_heap_pdata *)
@@ -680,6 +685,9 @@
break;
case FIXED_MIDDLE:
heap->base = fixed_middle_start;
+ pdata->secure_base = fixed_middle_start
+ - HOLE_SIZE;
+ pdata->secure_size = HOLE_SIZE + heap->size;
break;
case FIXED_HIGH:
heap->base = fixed_high_start;
@@ -1284,6 +1292,87 @@
.peripheral_platform_device = NULL,
};
+#define MSM_TSIF0_PHYS (0x18200000)
+#define MSM_TSIF1_PHYS (0x18201000)
+#define MSM_TSIF_SIZE (0x200)
+#define MSM_TSPP_PHYS (0x18202000)
+#define MSM_TSPP_SIZE (0x1000)
+#define MSM_TSPP_BAM_PHYS (0x18204000)
+#define MSM_TSPP_BAM_SIZE (0x2000)
+
+#define TSIF_0_CLK GPIO_CFG(75, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_EN GPIO_CFG(76, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_DATA GPIO_CFG(77, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_SYNC GPIO_CFG(82, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_CLK GPIO_CFG(79, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_EN GPIO_CFG(80, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_DATA GPIO_CFG(81, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_SYNC GPIO_CFG(78, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif_gpios[] = {
+ { .gpio_cfg = TSIF_0_CLK, .label = "tsif0_clk", },
+ { .gpio_cfg = TSIF_0_EN, .label = "tsif0_en", },
+ { .gpio_cfg = TSIF_0_DATA, .label = "tsif0_data", },
+ { .gpio_cfg = TSIF_0_SYNC, .label = "tsif0_sync", },
+ { .gpio_cfg = TSIF_1_CLK, .label = "tsif1_clk", },
+ { .gpio_cfg = TSIF_1_EN, .label = "tsif1_en", },
+ { .gpio_cfg = TSIF_1_DATA, .label = "tsif1_data", },
+ { .gpio_cfg = TSIF_1_SYNC, .label = "tsif1_sync", },
+};
+
+static struct resource tspp_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ .start = TSIF_TSPP_IRQ,
+ .end = TSIF1_IRQ,
+ },
+ [1] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF0_PHYS,
+ .end = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [2] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF1_PHYS,
+ .end = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [3] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_PHYS,
+ .end = MSM_TSPP_PHYS + MSM_TSPP_SIZE - 1,
+ },
+ [4] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSPP_BAM_PHYS,
+ .end = MSM_TSPP_BAM_PHYS + MSM_TSPP_BAM_SIZE - 1,
+ },
+};
+
+static struct msm_tspp_platform_data tspp_platform_data = {
+ .num_gpios = ARRAY_SIZE(tsif_gpios),
+ .gpios = tsif_gpios,
+ .tsif_pclk = "tsif_pclk",
+ .tsif_ref_clk = "tsif_ref_clk",
+};
+
+static struct platform_device msm_device_tspp = {
+ .name = "msm_tspp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tspp_resources),
+ .resource = tspp_resources,
+ .dev = {
+ .platform_data = &tspp_platform_data
+ },
+};
+
#define MSM_SHARED_RAM_PHYS 0x80000000
static void __init msm8960_map_io(void)
@@ -2418,6 +2507,7 @@
#endif
static struct platform_device *common_devices[] __initdata = {
+ &msm8960_device_acpuclk,
&msm8960_device_dmov,
&msm_device_smd,
&msm_device_uart_dm6,
@@ -2466,7 +2556,6 @@
&msm_device_vidc,
&msm_device_bam_dmux,
&msm_fm_platform_init,
-
#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
#ifdef CONFIG_MSM_USE_TSIF1
&msm_device_tsif[1],
@@ -2474,7 +2563,7 @@
&msm_device_tsif[0],
#endif
#endif
-
+ &msm_device_tspp,
#ifdef CONFIG_HW_RANDOM_MSM
&msm_device_rng,
#endif
@@ -2498,6 +2587,8 @@
&msm8960_cpu_idle_device,
&msm8960_msm_gov_device,
&msm8960_device_cache_erp,
+ &msm8960_device_ebi1_ch0_erp,
+ &msm8960_device_ebi1_ch1_erp,
&msm8960_cache_dump_device,
&msm8960_iommu_domain_device,
&msm_tsens_device,
@@ -2521,6 +2612,7 @@
&msm_pcm_routing,
&msm_cpudai0,
&msm_cpudai1,
+ &msm8960_cpudai_slimbus_2_rx,
&msm8960_cpudai_slimbus_2_tx,
&msm_cpudai_hdmi_rx,
&msm_cpudai_bt_rx,
@@ -2558,6 +2650,9 @@
#ifdef CONFIG_MSM_GEMINI
&msm8960_gemini_device,
#endif
+#ifdef CONFIG_MSM_MERCURY
+ &msm8960_mercury_device,
+#endif
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -2577,6 +2672,7 @@
&msm_pcm_routing,
&msm_cpudai0,
&msm_cpudai1,
+ &msm8960_cpudai_slimbus_2_rx,
&msm8960_cpudai_slimbus_2_tx,
&msm_cpudai_hdmi_rx,
&msm_cpudai_bt_rx,
@@ -2595,6 +2691,9 @@
#ifdef CONFIG_MSM_GEMINI
&msm8960_gemini_device,
#endif
+#ifdef CONFIG_MSM_MERCURY
+ &msm8960_mercury_device,
+#endif
&msm_voice,
&msm_voip,
&msm_lpa_pcm,
@@ -2961,7 +3060,6 @@
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8960_pm8921_gpio_mpp_init();
platform_add_devices(sim_devices, ARRAY_SIZE(sim_devices));
- acpuclk_init(&acpuclk_8960_soc_data);
msm8960_device_qup_spi_gsbi1.dev.platform_data =
&msm8960_qup_spi_gsbi1_pdata;
@@ -3074,7 +3172,6 @@
msm8960_init_cam();
#endif
msm8960_init_mmc();
- acpuclk_init(&acpuclk_8960_soc_data);
if (machine_is_msm8960_liquid())
mxt_init_hw_liquid();
register_i2c_devices();
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 7ed350d..2561def 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -61,7 +61,7 @@
};
VREG_CONSUMERS(L13) = {
REGULATOR_SUPPLY("8018_l13", NULL),
- REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.1"),
+ REGULATOR_SUPPLY("sdc_vdd_io", "msm_sdcc.1"),
};
VREG_CONSUMERS(L14) = {
REGULATOR_SUPPLY("8018_l14", NULL),
@@ -69,9 +69,6 @@
};
VREG_CONSUMERS(S1) = {
REGULATOR_SUPPLY("8018_s1", NULL),
- REGULATOR_SUPPLY("HSUSB_VDDCX", "msm_otg"),
- REGULATOR_SUPPLY("HSIC_VDDCX", "msm_hsic_peripheral"),
- REGULATOR_SUPPLY("HSIC_VDDCX", "msm_hsic_host"),
};
VREG_CONSUMERS(S2) = {
REGULATOR_SUPPLY("8018_s2", NULL),
@@ -117,6 +114,11 @@
REGULATOR_SUPPLY("ext_2p95v", NULL),
REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.1"),
};
+VREG_CONSUMERS(VDD_DIG_CORNER) = {
+ REGULATOR_SUPPLY("hsusb_vdd_dig", "msm_otg"),
+ REGULATOR_SUPPLY("hsic_vdd_dig", "msm_hsic_peripheral"),
+ REGULATOR_SUPPLY("hsic_vdd_dig", "msm_hsic_host"),
+};
#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
_apply_uV, _pull_down, _always_on, _supply_regulator, \
@@ -262,6 +264,16 @@
RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
_supply_regulator, 0)
+#define RPM_CORNER(_id, _always_on, _sleep_selectable, _min_uV, _max_uV, \
+ _supply_regulator) \
+ RPM_INIT(_id, _min_uV, _max_uV, 0, REGULATOR_CHANGE_VOLTAGE \
+ | REGULATOR_CHANGE_STATUS, 0, _max_uV, 0, 0, 0, \
+ RPM_VREG_PIN_CTRL_NONE, NONE, RPM_VREG_PIN_FN_9615_NONE, \
+ RPM_VREG_FORCE_MODE_9615_NONE, \
+ RPM_VREG_FORCE_MODE_9615_NONE, RPM_VREG_POWER_MODE_9615_PWM, \
+ RPM_VREG_STATE_OFF, _sleep_selectable, _always_on, \
+ _supply_regulator, 0)
+
/* Pin control initialization */
#define RPM_PC_INIT(_id, _always_on, _pin_fn, _pin_ctrl, _supply_regulator) \
{ \
@@ -316,7 +328,7 @@
/* ID a_on pd ss min_uV max_uV supply sys_uA init_ip */
RPM_LDO(L2, 1, 1, 0, 1800000, 1800000, NULL, 0, 10000),
- RPM_LDO(L3, 0, 1, 0, 1800000, 1800000, NULL, 0, 0),
+ RPM_LDO(L3, 1, 1, 0, 1800000, 1800000, NULL, 0, 0),
RPM_LDO(L4, 0, 1, 0, 3075000, 3075000, NULL, 0, 0),
RPM_LDO(L5, 0, 1, 0, 2850000, 2850000, NULL, 0, 0),
RPM_LDO(L6, 0, 1, 0, 1800000, 2850000, NULL, 0, 0),
@@ -331,6 +343,10 @@
/* ID a_on pd ss supply */
RPM_VS(LVS1, 0, 1, 0, "8018_s3"),
+
+ /* ID a_on ss min_corner max_corner supply */
+ RPM_CORNER(VDD_DIG_CORNER, 0, 1, RPM_VREG_CORNER_NONE,
+ RPM_VREG_CORNER_HIGH, NULL),
};
int msm_pm8018_regulator_pdata_len __devinitdata =
@@ -342,5 +358,5 @@
.num_regulators = ARRAY_SIZE(msm_rpm_regulator_init_data),
.version = RPM_VREG_VERSION_9615,
.vreg_id_vdd_mem = RPM_VREG_ID_PM8018_L9,
- .vreg_id_vdd_dig = RPM_VREG_ID_PM8018_S1,
+ .vreg_id_vdd_dig = RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
};
diff --git a/arch/arm/mach-msm/board-9615-storage.c b/arch/arm/mach-msm/board-9615-storage.c
index 5bdeb94..2025bd0 100644
--- a/arch/arm/mach-msm/board-9615-storage.c
+++ b/arch/arm/mach-msm/board-9615-storage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -54,10 +54,10 @@
};
/* All SDCC controllers may require voting for VDD PAD voltage */
-static struct msm_mmc_reg_data mmc_vddp_reg_data[MAX_SDCC_CONTROLLER] = {
+static struct msm_mmc_reg_data mmc_vdd_io_reg_data[MAX_SDCC_CONTROLLER] = {
/* SDCC1 : External card slot connected */
[SDCC1] = {
- .name = "sdc_vddp",
+ .name = "sdc_vdd_io",
.high_vol_level = 2950000,
.low_vol_level = 1850000,
.always_on = true,
@@ -77,7 +77,7 @@
/* SDCC1 : External card slot connected */
[SDCC1] = {
.vdd_data = &mmc_vdd_reg_data[SDCC1],
- .vddp_data = &mmc_vddp_reg_data[SDCC1],
+ .vdd_io_data = &mmc_vdd_io_reg_data[SDCC1],
}
};
@@ -176,7 +176,6 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc1_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
- .pclk_src_dfab = true,
.vreg_data = &mmc_slot_vreg_data[SDCC1],
.pin_data = &mmc_slot_pin_data[SDCC1],
#ifdef CONFIG_MMC_MSM_CARD_HW_DETECTION
@@ -205,7 +204,6 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc2_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc2_sup_clk_rates),
- .pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC2],
.sdiowakeup_irq = MSM_GPIO_TO_INT(GPIO_SDC2_DAT1_WAKEUP),
.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index df114a3..1089d61 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -50,7 +50,6 @@
#include "devices.h"
#include "board-9615.h"
#include "pm.h"
-#include "acpuclock.h"
#include "pm-boot.h"
#include <mach/gpiomux.h>
@@ -471,14 +470,6 @@
},
};
-static struct i2c_registry msm9615_i2c_devices[] __initdata = {
- {
- I2C_SURF | I2C_FFA | I2C_FLUID,
- MSM_9615_GSBI5_QUP_I2C_BUS_ID,
- wcd9xxx_device_info,
- ARRAY_SIZE(wcd9xxx_device_info),
- },
-};
/*
* MDM9x15 I2S.
*/
@@ -561,6 +552,17 @@
};
#endif
+static struct i2c_registry msm9615_i2c_devices[] __initdata = {
+#ifdef CONFIG_WCD9310_CODEC
+ {
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_9615_GSBI5_QUP_I2C_BUS_ID,
+ wcd9xxx_device_info,
+ ARRAY_SIZE(wcd9xxx_device_info),
+ },
+#endif
+};
+
static struct slim_boardinfo msm_slim_devices[] = {
/* add slimbus slaves as needed */
#ifdef CONFIG_WCD9310_CODEC
@@ -847,6 +849,7 @@
};
static struct platform_device *common_devices[] = {
+ &msm9615_device_acpuclk,
&msm9615_device_dmov,
&msm_device_smd,
#ifdef CONFIG_LTC4088_CHARGER
@@ -897,6 +900,8 @@
&msm_pcm_afe,
&msm_cpudai_auxpcm_rx,
&msm_cpudai_auxpcm_tx,
+ &msm_cpudai_sec_auxpcm_rx,
+ &msm_cpudai_sec_auxpcm_tx,
#if defined(CONFIG_CRYPTO_DEV_QCRYPTO) || \
defined(CONFIG_CRYPTO_DEV_QCRYPTO_MODULE)
@@ -974,7 +979,6 @@
msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm9615_pm8xxx_gpio_mpp_init();
- acpuclk_init(&acpuclk_9615_soc_data);
/* Ensure ar6000pm device is registered before MMC/SDC */
msm9615_init_ar6000pm();
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index a8094e1..4dda0b7 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -46,6 +46,7 @@
#include "clock.h"
#include "devices.h"
#include "spm.h"
+#include "modem_notifier.h"
#define MSM_KERNEL_EBI1_MEM_SIZE 0x280000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -421,33 +422,6 @@
platform_device_register(&copper_device_tz_log);
}
-/*
- * Used to satisfy dependencies for devices that need to be
- * run early or in a particular order. Most likely your device doesn't fall
- * into this category, and thus the driver should not be added here. The
- * EPROBE_DEFER can satisfy most dependency problems.
- */
-void __init msm_copper_add_drivers(void)
-{
- msm_smd_init();
- msm_rpm_driver_init();
- rpm_regulator_smd_driver_init();
- msm_spm_device_init();
- regulator_stub_init();
-}
-
-static struct of_device_id irq_match[] __initdata = {
- { .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
- { .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
- { .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
- {}
-};
-
-void __init msm_copper_init_irq(void)
-{
- of_irq_init(irq_match);
-}
-
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("xo", XO_CLK, NULL, OFF),
CLK_DUMMY("xo", XO_CLK, "pil_pronto", OFF),
@@ -476,11 +450,45 @@
.size = ARRAY_SIZE(msm_clocks_dummy),
};
+/*
+ * Used to satisfy dependencies for devices that need to be
+ * run early or in a particular order. Most likely your device doesn't fall
+ * into this category, and thus the driver should not be added here. The
+ * EPROBE_DEFER can satisfy most dependency problems.
+ */
+void __init msm_copper_add_drivers(void)
+{
+ msm_init_modem_notifier_list();
+ msm_smd_init();
+ msm_rpm_driver_init();
+ rpm_regulator_smd_driver_init();
+ msm_spm_device_init();
+ regulator_stub_init();
+ if (machine_is_copper_rumi())
+ msm_clock_init(&msm_dummy_clock_init_data);
+ else
+ msm_clock_init(&msmcopper_clock_init_data);
+}
+
+static struct of_device_id irq_match[] __initdata = {
+ { .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
+ { .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+ { .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
+ {}
+};
+
+void __init msm_copper_init_irq(void)
+{
+ of_irq_init(irq_match);
+}
+
static struct of_dev_auxdata msm_copper_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
"msm_otg", NULL),
+ OF_DEV_AUXDATA("qcom,dwc-usb3-msm", 0xF9200000, \
+ "msm_dwc3", NULL),
OF_DEV_AUXDATA("qcom,spi-qup-v2", 0xF9924000, \
"spi_qsd.1", NULL),
OF_DEV_AUXDATA("qcom,spmi-pmic-arb", 0xFC4C0000, \
@@ -495,10 +503,14 @@
"msm_sdcc.4", NULL),
OF_DEV_AUXDATA("qcom,pil-q6v5-lpass", 0xFE200000, \
"pil-q6v5-lpass", NULL),
+ OF_DEV_AUXDATA("qcom,pil-q6v5-mss", 0xFC880000, "pil-q6v5-mss", NULL),
+ OF_DEV_AUXDATA("qcom,pil-mba", 0xFC820000, "pil-mba", NULL),
OF_DEV_AUXDATA("qcom,pil-pronto", 0xFB21B000, \
"pil_pronto", NULL),
OF_DEV_AUXDATA("qcom,msm-rng", 0xF9BFF000, \
"msm_rng", NULL),
+ OF_DEV_AUXDATA("qcom,qseecom", 0xFE806000, \
+ "qseecom", NULL),
{}
};
@@ -506,11 +518,6 @@
{
msm_copper_init_gpiomux();
- if (machine_is_copper_rumi())
- msm_clock_init(&msm_dummy_clock_init_data);
- else
- msm_clock_init(&msmcopper_clock_init_data);
-
*adata = msm_copper_auxdata_lookup;
regulator_has_full_constraints();
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 6ad3cef..b071353 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -38,7 +38,6 @@
#include <mach/socinfo.h>
#include "devices.h"
#include "timer.h"
-#include "acpuclock.h"
#include "pm.h"
#include "spm.h"
#include <linux/regulator/consumer.h>
@@ -804,11 +803,17 @@
},
};
+static struct platform_device fsm9xxx_device_acpuclk = {
+ .name = "acpuclk-9xxx",
+ .id = -1,
+};
+
/*
* Devices
*/
static struct platform_device *devices[] __initdata = {
+ &fsm9xxx_device_acpuclk,
&msm_device_smd,
&msm_device_dmov,
&msm_device_nand,
@@ -873,8 +878,6 @@
static void __init fsm9xxx_init(void)
{
- acpuclk_init(&acpuclk_9xxx_soc_data);
-
regulator_has_full_constraints();
#if defined(CONFIG_I2C_SSBI) || defined(CONFIG_MSM_SSBI)
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 3270d19..3ab5ba0 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -120,19 +120,32 @@
{"usb2", REG_LDO, 1800000, 1800000, 0},
};
+static struct camera_vreg_t ov5647_gpio_vreg[] = {
+ {"cam_ov5647_avdd", REG_GPIO, 0, 0, 0},
+ {"cam_ov5647_vdd", REG_GPIO, 0, 0, 0},
+};
+
+static struct camera_vreg_t ov8825_gpio_vreg[] = {
+ {"cam_ov8825_avdd", REG_GPIO, 0, 0, 0},
+ {"cam_ov8825_vdd", REG_GPIO, 0, 0, 0},
+};
+
+static struct camera_vreg_t ov7692_gpio_vreg[] = {
+ {"cam_ov7692_avdd", REG_GPIO, 0, 0, 0},
+ {"cam_ov7692_vdd", REG_GPIO, 0, 0, 0},
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
struct msm_camera_device_platform_data msm_camera_device_data_csi1[] = {
{
.csid_core = 1,
- .is_csic = 1,
.ioclk = {
.vfe_clk_rate = 192000000,
},
},
{
.csid_core = 1,
- .is_csic = 1,
.ioclk = {
.vfe_clk_rate = 266667000,
},
@@ -142,14 +155,12 @@
struct msm_camera_device_platform_data msm_camera_device_data_csi0[] = {
{
.csid_core = 0,
- .is_csic = 1,
.ioclk = {
.vfe_clk_rate = 192000000,
},
},
{
.csid_core = 0,
- .is_csic = 1,
.ioclk = {
.vfe_clk_rate = 266667000,
},
@@ -184,7 +195,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
.sensor_name = "s5k4e1",
.sensor_reset_enable = 1,
- .pmic_gpio_enable = 0,
.pdata = &msm_camera_device_data_csi1[0],
.flash_data = &flash_s5k4e1,
.sensor_platform_info = &sensor_board_info_s5k4e1,
@@ -210,8 +220,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
.sensor_name = "ov7692",
.sensor_reset_enable = 0,
- .pmic_gpio_enable = 1,
- .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU1_CAM_VGA_RESET_N,
.sensor_pwd = GPIO_SKU1_CAM_VGA_SHDN,
.pdata = &msm_camera_device_data_csi0[0],
@@ -254,8 +262,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_ov5647_data = {
.sensor_name = "ov5647",
.sensor_reset_enable = 1,
- .pmic_gpio_enable = 1,
- .sensor_lcd_gpio_onoff = lcd_camera_power_onoff,
.sensor_reset = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
.sensor_pwd = GPIO_SKU3_CAM_5MP_SHDN_N,
.pdata = &msm_camera_device_data_csi1[0],
@@ -268,6 +274,37 @@
};
#endif
+
+static struct msm_camera_gpio_conf gpio_conf_ov8825 = {
+ .camera_off_table = camera_off_gpio_table,
+ .camera_on_table = camera_on_gpio_table,
+ .gpio_no_mux = 1,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov8825 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov8825 = {
+ .mount_angle = 90,
+ .cam_vreg = msm_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_cam_vreg),
+ .gpio_conf = &gpio_conf_ov8825,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov8825_data = {
+ .sensor_name = "ov8825",
+ .sensor_reset_enable = 1,
+ .pmic_gpio_enable = 1,
+ .sensor_reset = GPIO_SKU3_CAM_5MP_CAMIF_RESET,
+ .sensor_pwd = GPIO_SKU3_CAM_5MP_SHDN_N,
+ .pdata = &msm_camera_device_data_csi1[1],
+ .flash_data = &flash_ov8825,
+ .sensor_platform_info = &sensor_board_info_ov8825,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+};
+
#ifdef CONFIG_MT9E013
static struct msm_camera_sensor_flash_data flash_mt9e013 = {
.flash_type = MSM_CAMERA_FLASH_LED,
@@ -284,7 +321,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
.sensor_name = "mt9e013",
.sensor_reset_enable = 1,
- .pmic_gpio_enable = 0,
.pdata = &msm_camera_device_data_csi1[1],
.flash_data = &flash_mt9e013,
.sensor_platform_info = &sensor_board_info_mt9e013,
@@ -310,7 +346,6 @@
static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
.sensor_name = "ov9726",
.sensor_reset_enable = 0,
- .pmic_gpio_enable = 0,
.pdata = &msm_camera_device_data_csi0[0],
.flash_data = &flash_ov9726,
.sensor_platform_info = &sensor_board_info_ov9726,
@@ -340,6 +375,24 @@
sensor_board_info_ov7692.num_vreg = 0;
sensor_board_info_ov5647.cam_vreg = NULL;
sensor_board_info_ov5647.num_vreg = 0;
+ sensor_board_info_ov8825.cam_vreg = NULL;
+ sensor_board_info_ov8825.num_vreg = 0;
+
+ }
+ if (machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()) {
+ sensor_board_info_ov7692.cam_vreg =
+ ov7692_gpio_vreg;
+ sensor_board_info_ov7692.num_vreg =
+ ARRAY_SIZE(ov7692_gpio_vreg);
+ sensor_board_info_ov5647.cam_vreg =
+ ov5647_gpio_vreg;
+ sensor_board_info_ov5647.num_vreg =
+ ARRAY_SIZE(ov5647_gpio_vreg);
+ sensor_board_info_ov8825.cam_vreg =
+ ov8825_gpio_vreg;
+ sensor_board_info_ov8825.num_vreg =
+ ARRAY_SIZE(ov8825_gpio_vreg);
}
platform_device_register(&msm_camera_server);
if (machine_is_msm8625_surf() || machine_is_msm8625_evb()
@@ -381,6 +434,10 @@
.platform_data = &msm_camera_sensor_ov5647_data,
},
{
+ I2C_BOARD_INFO("ov8825", 0x6C >> 3),
+ .platform_data = &msm_camera_sensor_ov8825_data,
+ },
+ {
I2C_BOARD_INFO("sc628a", 0x6E),
},
};
@@ -955,6 +1012,7 @@
#ifdef CONFIG_WEBCAM_OV7692_QRD
&msm_camera_sensor_ov7692,
#endif
+ &msm_camera_sensor_ov8825,
};
#endif
@@ -987,6 +1045,7 @@
ARRAY_SIZE(cam_exp_i2c_info));
}
+#ifndef CONFIG_MSM_CAMERA_V4L2
#define LCD_CAMERA_LDO_2V8 35 /* SKU1&SKU3 2.8V LDO */
#define SKU3_LCD_CAMERA_LDO_1V8 40 /* SKU3 1.8V LDO */
#define SKU7_LCD_CAMERA_LDO_1V8 58 /* SKU7 1.8V LDO */
@@ -1085,6 +1144,7 @@
return rc;
}
EXPORT_SYMBOL(lcd_camera_power_onoff);
+#endif
void __init msm7627a_camera_init(void)
{
@@ -1105,7 +1165,6 @@
GPIO_SKU7_CAM_5MP_SHDN_N;
msm_camera_sensor_ov5647_data.sensor_reset =
GPIO_SKU7_CAM_5MP_CAMIF_RESET;
-
}
/* LCD and camera power (VREG & LDO) init */
@@ -1113,8 +1172,9 @@
|| machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7()) {
-
+#ifndef CONFIG_MSM_CAMERA_V4L2
lcd_camera_power_init();
+#endif
evb_camera_gpio_cfg();
}
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index bd38f30..3da68ad 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -497,12 +497,10 @@
} else if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
if (!strncmp(name, "lcdc_truly_hvga_ips3p2335_pt", 28))
ret = 0;
- } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+ machine_is_msm8625_evt()) {
if (!strncmp(name, "mipi_cmd_nt35510_wvga", 21))
ret = 0;
- } else if (machine_is_msm8625_evt()) {
- if (!strncmp(name, "mipi_video_nt35510_wvga", 23))
- ret = 0;
}
#if !defined(CONFIG_FB_MSM_LCDC_AUTO_DETECT) && \
@@ -579,90 +577,98 @@
};
#endif
-static int evb_backlight_control(int level)
+static int evb_backlight_control(int level, int mode)
{
int i = 0;
- int remainder;
+ int remainder, ret = 0;
+
/* device address byte = 0x72 */
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ if (!mode) {
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
- /* t-EOS and t-start */
- gpio_set_value(96, 0);
- ndelay(4200);
- gpio_set_value(96, 1);
- ndelay(9000);
+ /* t-EOS and t-start */
+ gpio_set_value(96, 0);
+ ndelay(4200);
+ gpio_set_value(96, 1);
+ ndelay(9000);
- /* data byte */
- /* RFA = 0 */
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ /* data byte */
+ /* RFA = 0 */
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
- /* Address bits */
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ /* Address bits */
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
- /* Data bits */
- for (i = 0; i < 5; i++) {
- remainder = (level) & (16);
- if (remainder) {
- gpio_set_value(96, 0);
- udelay(33);
- gpio_set_value(96, 1);
- udelay(67);
- } else {
- gpio_set_value(96, 0);
- udelay(67);
- gpio_set_value(96, 1);
- udelay(33);
+ /* Data bits */
+ for (i = 0; i < 5; i++) {
+ remainder = (level) & (16);
+ if (remainder) {
+ gpio_set_value(96, 0);
+ udelay(33);
+ gpio_set_value(96, 1);
+ udelay(67);
+ } else {
+ gpio_set_value(96, 0);
+ udelay(67);
+ gpio_set_value(96, 1);
+ udelay(33);
+ }
+ level = level << 1;
}
- level = level << 1;
+
+ /* t-EOS */
+ gpio_set_value(96, 0);
+ ndelay(12000);
+ gpio_set_value(96, 1);
+ } else {
+ ret = pmapp_disp_backlight_set_brightness(level);
+ if (ret)
+ pr_err("%s: can't set lcd backlight!\n", __func__);
}
- /* t-EOS */
- gpio_set_value(96, 0);
- ndelay(12000);
- gpio_set_value(96, 1);
- return 0;
+ return ret;
}
static int mipi_NT35510_rotate_panel(void)
@@ -687,7 +693,7 @@
};
static struct msm_panel_common_pdata mipi_NT35510_pdata = {
- .pmic_backlight = evb_backlight_control,
+ .backlight = evb_backlight_control,
.rotate_panel = mipi_NT35510_rotate_panel,
};
@@ -700,7 +706,7 @@
};
static struct msm_panel_common_pdata mipi_NT35516_pdata = {
- .pmic_backlight = evb_backlight_control,
+ .backlight = evb_backlight_control,
};
static struct platform_device mipi_dsi_NT35516_panel_device = {
@@ -1140,54 +1146,30 @@
static int mipi_dsi_panel_qrd3_power(int on)
{
int rc = 0;
+ static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
if (!qrd3_dsi_gpio_initialized) {
+ pmapp_disp_backlight_init();
rc = gpio_request(GPIO_QRD3_LCD_BACKLIGHT_EN,
"qrd3_gpio_bkl_en");
if (rc < 0)
return rc;
- rc = gpio_request(GPIO_QRD3_LCD_EXT_2V85_EN,
- "qrd3_gpio_ext_2v85_en");
- if (rc < 0)
- return rc;
-
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_EXT_2V85_EN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("failed QRD3 GPIO_QRD3_LCD_EXT_2V85_EN tlmm config\n");
- return rc;
+ gpio_reg_2p85v = regulator_get(&msm8625_mipi_dsi_device.dev,
+ "lcd_vdd");
+ if (IS_ERR(gpio_reg_2p85v)) {
+ pr_err("%s:ext_2p85v regulator get failed", __func__);
+ return -EINVAL;
}
- rc = gpio_direction_output(GPIO_QRD3_LCD_EXT_2V85_EN, 1);
- if (rc < 0) {
- pr_err("failed to enable external 2V85\n");
- gpio_free(GPIO_QRD3_LCD_EXT_2V85_EN);
- return rc;
+ gpio_reg_1p8v = regulator_get(&msm8625_mipi_dsi_device.dev,
+ "lcd_vddi");
+ if (IS_ERR(gpio_reg_1p8v)) {
+ pr_err("%s:ext_1p8v regulator get failed", __func__);
+ return -EINVAL;
}
- rc = gpio_request(GPIO_QRD3_LCD_EXT_1V8_EN,
- "qrd3_gpio_ext_1v8_en");
- if (rc < 0)
- return rc;
-
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_EXT_1V8_EN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
- GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("failed QRD3 GPIO_QRD3_LCD_EXT_1V8_EN tlmm config\n");
- return rc;
- }
-
- rc = gpio_direction_output(GPIO_QRD3_LCD_EXT_1V8_EN, 1);
- if (rc < 0) {
- pr_err("failed to enable external 1v8\n");
- gpio_free(GPIO_QRD3_LCD_EXT_1V8_EN);
- return rc;
- }
-
- qrd3_dsi_gpio_initialized = 1;
+ qrd3_dsi_gpio_initialized = 1;
}
if (on) {
@@ -1204,7 +1186,7 @@
gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
return rc;
}
-
+ /*Toggle Backlight GPIO*/
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
udelay(190);
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 0);
@@ -1212,18 +1194,17 @@
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
/* 1 wire mode starts from this low to high transition */
udelay(50);
- } else {
- gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
- GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
- GPIO_CFG_DISABLE);
- }
- gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_2V85_EN, !!on);
- gpio_set_value_cansleep(GPIO_QRD3_LCD_EXT_1V8_EN, !!on);
+ /*Enable EXT_2.85 and 1.8 regulators*/
+ rc = regulator_enable(gpio_reg_2p85v);
+ if (rc < 0)
+ pr_err("%s: reg enable failed\n", __func__);
+ rc = regulator_enable(gpio_reg_1p8v);
+ if (rc < 0)
+ pr_err("%s: reg enable failed\n", __func__);
- if (on) {
+ /*Configure LCD Bridge reset*/
rc = gpio_tlmm_config(qrd3_mipi_dsi_gpio[0], GPIO_CFG_ENABLE);
-
if (rc < 0) {
pr_err("Failed to enable LCD Bridge reset enable\n");
return rc;
@@ -1237,18 +1218,32 @@
return rc;
}
+ /*Toggle Bridge Reset GPIO*/
msleep(20);
gpio_set_value_cansleep(GPIO_QRD3_LCD_BRDG_RESET_N, 0);
msleep(20);
gpio_set_value_cansleep(GPIO_QRD3_LCD_BRDG_RESET_N, 1);
msleep(20);
+
} else {
+ gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
+ GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+ GPIO_CFG_DISABLE);
+
gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BRDG_RESET_N, 0,
GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
GPIO_CFG_DISABLE);
+
+ rc = regulator_disable(gpio_reg_2p85v);
+ if (rc < 0)
+ pr_err("%s: reg disable failed\n", __func__);
+ rc = regulator_disable(gpio_reg_1p8v);
+ if (rc < 0)
+ pr_err("%s: reg disable failed\n", __func__);
+
}
- return rc;
+ return rc;
}
static int mipi_dsi_panel_power(int on)
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 07b7ab0..0949c5f 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -327,13 +327,16 @@
}
gpio_set_value(gpio_wlan_sys_rest_en, 0);
} else {
- gpio_request(gpio_wlan_sys_rest_en, "WLAN_DEEP_SLEEP_N");
- rc = setup_wlan_gpio(on);
- if (rc) {
- pr_err("%s: wlan_set_gpio = %d\n", __func__, rc);
- goto set_gpio_fail;
+ rc = gpio_request(gpio_wlan_sys_rest_en, "WLAN_DEEP_SLEEP_N");
+ if (!rc) {
+ rc = setup_wlan_gpio(on);
+ if (rc) {
+ pr_err("%s: setup_wlan_gpio = %d\n",
+ __func__, rc);
+ goto set_gpio_fail;
+ }
+ gpio_free(gpio_wlan_sys_rest_en);
}
- gpio_free(gpio_wlan_sys_rest_en);
}
/* GPIO_WLAN_3V3_EN is only required for the QRD7627a */
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index d42458f..a7fed3e 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -65,7 +65,6 @@
#include "board-msm7627-regulator.h"
#include "devices.h"
#include "clock.h"
-#include "acpuclock.h"
#include "msm-keypad-devices.h"
#include "pm.h"
#include "pm-boot.h"
@@ -1775,7 +1774,7 @@
}
}
#endif
- acpuclk_init(&acpuclk_7x27_soc_data);
+ platform_device_register(&msm7x27_device_acpuclk);
usb_mpp_init();
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 1c32b5e..dc473e6 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -162,7 +162,7 @@
#define MSM_PMEM_MDP_SIZE 0x2300000
#define MSM7x25A_MSM_PMEM_MDP_SIZE 0x1500000
-#define MSM_PMEM_ADSP_SIZE 0x1100000
+#define MSM_PMEM_ADSP_SIZE 0x1200000
#define MSM7x25A_MSM_PMEM_ADSP_SIZE 0xB91000
#endif
@@ -650,7 +650,12 @@
u32 low_voltage = msm_psy_batt_data.voltage_min_design;
u32 high_voltage = msm_psy_batt_data.voltage_max_design;
- return (current_voltage - low_voltage) * 100
+ if (current_voltage <= low_voltage)
+ return 0;
+ else if (current_voltage >= high_voltage)
+ return 100;
+ else
+ return (current_voltage - low_voltage) * 100
/ (high_voltage - low_voltage);
}
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 8abcef0..2834f24 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -95,15 +95,31 @@
#define MSM_PMEM_SF_SIZE 0x1700000
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
-#define MSM_FB_SIZE 0x780000
+#define MSM_FB_PRIM_BUF_SIZE (864 * 480 * 4 * 3) /* 4bpp * 3 Pages */
#else
-#define MSM_FB_SIZE 0x500000
+#define MSM_FB_PRIM_BUF_SIZE (864 * 480 * 4 * 2) /* 4bpp * 2 Pages */
#endif
/*
* Reserve space for double buffered full screen
* res V4L2 video overlay - i.e. 1280x720x1.5x2
*/
#define MSM_V4L2_VIDEO_OVERLAY_BUF_SIZE 2764800
+
+#ifdef CONFIG_FB_MSM_HDMI_ADV7520_PANEL
+#define MSM_FB_EXT_BUF_SIZE (1280 * 720 * 2 * 1) /* 2 bpp x 1 page */
+#else
+#define MSM_FB_EXT_BUF_SIZE 0
+#endif
+
+#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
+/* width x height x 3 bpp x 2 frame buffer */
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((864 * 480 * 3 * 2), 4096)
+#else
+#define MSM_FB_OVERLAY0_WRITEBACK_SIZE 0
+#endif
+
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+
#define MSM_PMEM_ADSP_SIZE 0x1E00000
#define MSM_FLUID_PMEM_ADSP_SIZE 0x2800000
#define PMEM_KERNEL_EBI0_SIZE 0x600000
@@ -864,7 +880,6 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
.csid_core = 0,
- .is_csic = 1,
.is_vpe = 1,
.ioclk = {
.vfe_clk_rate = 153600000,
@@ -4533,6 +4548,7 @@
.mdp_core_clk_table = mdp_core_clk_rate_table,
.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
.mdp_rev = MDP_REV_40,
+ .mem_hid = MEMTYPE_EBI0,
};
static int lcd_panel_spi_gpio_num[] = {
@@ -6940,7 +6956,7 @@
msm7x30_init_uart2();
#endif
msm_spm_init(&msm_spm_data, 1);
- acpuclk_init(&acpuclk_7x30_soc_data);
+ platform_device_register(&msm7x30_device_acpuclk);
if (machine_is_msm7x30_surf() || machine_is_msm7x30_fluid())
msm7x30_cfg_smsc911x();
@@ -7095,7 +7111,7 @@
}
early_param("pmem_sf_size", pmem_sf_size_setup);
-static unsigned fb_size = MSM_FB_SIZE;
+static unsigned fb_size;
static int __init fb_size_setup(char *p)
{
fb_size = memparse(p, NULL);
@@ -7176,10 +7192,17 @@
#endif
}
+static void __init reserve_mdp_memory(void)
+{
+ mdp_pdata.ov0_wb_size = MSM_FB_OVERLAY0_WRITEBACK_SIZE;
+ msm7x30_reserve_table[mdp_pdata.mem_hid].size += mdp_pdata.ov0_wb_size;
+}
+
static void __init msm7x30_calculate_reserve_sizes(void)
{
size_pmem_devices();
reserve_pmem_memory();
+ reserve_mdp_memory();
}
static int msm7x30_paddr_to_memtype(unsigned int paddr)
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index 32d5530..cd95630 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -361,7 +361,6 @@
static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
{
.csid_core = 0,
- .is_csic = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
.ioclk = {
@@ -370,7 +369,6 @@
},
{
.csid_core = 1,
- .is_csic = 1,
.is_vpe = 1,
.cam_bus_scale_table = &cam_bus_client_pdata,
.ioclk = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 57f2077..098ad6e 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -100,7 +100,6 @@
#include "peripheral-loader.h"
#include <linux/platform_data/qcom_crypto_device.h>
#include "rpm_resources.h"
-#include "acpuclock.h"
#include "pm-boot.h"
#include "board-storage-common-a.h"
@@ -2604,7 +2603,7 @@
#define MSM_FB_EXT_BUF_SIZE \
(roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
#else
-#define MSM_FB_EXT_BUFT_SIZE 0
+#define MSM_FB_EXT_BUF_SIZE 0
#endif
/* Note: must be multiple of 4096 */
@@ -2650,11 +2649,19 @@
#define USER_SMI_SIZE (MSM_SMI_SIZE - KERNEL_SMI_SIZE)
#define MSM_PMEM_SMIPOOL_SIZE USER_SMI_SIZE
+#define MSM_ION_HOLE_SIZE SZ_128K /* (128KB) */
+#define MSM_MM_FW_SIZE (0x200000 - MSM_ION_HOLE_SIZE) /*(2MB-128KB)*/
+#define MSM_ION_MM_SIZE 0x3800000 /* (56MB) */
+#define MSM_ION_MFC_SIZE SZ_8K
+
+#define MSM_MM_FW_BASE MSM_SMI_BASE
+#define MSM_ION_HOLE_BASE (MSM_MM_FW_BASE + MSM_MM_FW_SIZE)
+#define MSM_ION_MM_BASE (MSM_ION_HOLE_BASE + MSM_ION_HOLE_SIZE)
+#define MSM_ION_MFC_BASE (MSM_ION_MM_BASE + MSM_ION_MM_SIZE)
+
#define MSM_ION_SF_SIZE 0x4000000 /* 64MB */
#define MSM_ION_CAMERA_SIZE MSM_PMEM_ADSP_SIZE
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
-#define MSM_ION_MM_SIZE 0x3c00000 /* (60MB) Must be a multiple of 64K */
-#define MSM_ION_MFC_SIZE SZ_8K
+
#ifdef CONFIG_FB_MSM_OVERLAY1_WRITEBACK
#define MSM_ION_WB_SIZE 0xC00000 /* 12MB */
#else
@@ -3075,13 +3082,17 @@
static int hdmi_enable_5v(int on);
static int hdmi_core_power(int on, int show);
+static int hdmi_gpio_config(int on);
static int hdmi_cec_power(int on);
+static int hdmi_panel_power(int on);
static struct msm_hdmi_platform_data hdmi_msm_data = {
.irq = HDMI_IRQ,
.enable_5v = hdmi_enable_5v,
.core_power = hdmi_core_power,
.cec_power = hdmi_cec_power,
+ .panel_power = hdmi_panel_power,
+ .gpio_config = hdmi_gpio_config,
};
static struct platform_device hdmi_msm_device = {
@@ -5123,6 +5134,7 @@
};
static struct platform_device *surf_devices[] __initdata = {
+ &msm8x60_device_acpuclk,
&msm_device_smd,
&msm_device_uart_dm12,
&msm_pil_q6v3,
@@ -5289,6 +5301,8 @@
.request_region = request_smi_region,
.release_region = release_smi_region,
.setup_region = setup_smi_region,
+ .secure_base = MSM_ION_HOLE_BASE,
+ .secure_size = MSM_ION_HOLE_SIZE + MSM_ION_MM_SIZE,
.iommu_map_all = 1,
.iommu_2x_map_domain = VIDEO_DOMAIN,
};
@@ -5306,9 +5320,8 @@
.align = PAGE_SIZE,
};
-static struct ion_co_heap_pdata fw_co_ion_pdata = {
+static struct ion_co_heap_pdata hole_co_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
- .align = SZ_128K,
};
static struct ion_co_heap_pdata co_ion_pdata = {
@@ -5341,6 +5354,7 @@
.id = ION_CP_MM_HEAP_ID,
.type = ION_HEAP_TYPE_CP,
.name = ION_MM_HEAP_NAME,
+ .base = MSM_ION_MM_BASE,
.size = MSM_ION_MM_SIZE,
.memory_type = ION_SMI_TYPE,
.extra_data = (void *) &cp_mm_ion_pdata,
@@ -5349,14 +5363,16 @@
.id = ION_MM_FIRMWARE_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_MM_FIRMWARE_HEAP_NAME,
- .size = MSM_ION_MM_FW_SIZE,
+ .base = MSM_ION_HOLE_BASE,
+ .size = MSM_ION_HOLE_SIZE,
.memory_type = ION_SMI_TYPE,
- .extra_data = (void *) &fw_co_ion_pdata,
+ .extra_data = (void *) &hole_co_ion_pdata,
},
{
.id = ION_CP_MFC_HEAP_ID,
.type = ION_HEAP_TYPE_CP,
.name = ION_MFC_HEAP_NAME,
+ .base = MSM_ION_MFC_BASE,
.size = MSM_ION_MFC_SIZE,
.memory_type = ION_SMI_TYPE,
.extra_data = (void *) &cp_mfc_ion_pdata,
@@ -5425,12 +5441,7 @@
.size = KERNEL_SMI_SIZE,
.flags = MEMTYPE_FLAGS_FIXED,
},
- /* User space SMI memory pool for video core */
- /* used for encoder, decoder input & output buffers */
[MEMTYPE_SMI] = {
- .start = USER_SMI_BASE,
- .limit = USER_SMI_SIZE,
- .flags = MEMTYPE_FLAGS_FIXED,
},
[MEMTYPE_EBI0] = {
.flags = MEMTYPE_FLAGS_1M_ALIGN,
@@ -5475,9 +5486,6 @@
}
msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
- msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
- msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
- msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_CAMERA_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_WB_SIZE;
msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
@@ -8385,7 +8393,6 @@
.msmsdcc_fmid = 24000000,
.msmsdcc_fmax = 48000000,
.nonremovable = 1,
- .pclk_src_dfab = 1,
.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
#endif
@@ -8400,7 +8407,6 @@
.msmsdcc_fmid = 24000000,
.msmsdcc_fmax = 48000000,
.nonremovable = 0,
- .pclk_src_dfab = 1,
.register_status_notify = sdc2_register_status_notify,
#ifdef CONFIG_MSM_SDIO_AL
.is_sdio_al_client = 1,
@@ -8425,7 +8431,6 @@
.msmsdcc_fmid = 24000000,
.msmsdcc_fmax = 48000000,
.nonremovable = 0,
- .pclk_src_dfab = 1,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC3_DAT1,
.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
@@ -8440,7 +8445,6 @@
.msmsdcc_fmid = 24000000,
.msmsdcc_fmax = 48000000,
.nonremovable = 0,
- .pclk_src_dfab = 1,
.mpm_sdiowakeup_int = MSM_MPM_PIN_SDC4_DAT1,
.msm_bus_voting_data = &sps_to_ddr_bus_voting_data,
};
@@ -8456,7 +8460,6 @@
.msmsdcc_fmid = 24000000,
.msmsdcc_fmax = 48000000,
.nonremovable = 0,
- .pclk_src_dfab = 1,
.register_status_notify = sdc5_register_status_notify,
#ifdef CONFIG_MSM_SDIO_AL
.is_sdio_al_client = 1,
@@ -9007,6 +9010,29 @@
"8058_l16", rc);
return rc;
}
+ pr_debug("%s(on): success\n", __func__);
+ } else {
+ rc = regulator_disable(reg_8058_l16);
+ if (rc)
+ pr_warning("'%s' regulator disable failed, rc=%d\n",
+ "8058_l16", rc);
+ pr_debug("%s(off): success\n", __func__);
+ }
+
+ prev_on = on;
+
+ return 0;
+}
+
+static int hdmi_gpio_config(int on)
+{
+ int rc = 0;
+ static int prev_on;
+
+ if (on == prev_on)
+ return 0;
+
+ if (on) {
rc = gpio_request(170, "HDMI_DDC_CLK");
if (rc) {
pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
@@ -9025,20 +9051,15 @@
"HDMI_HPD", 172, rc);
goto error3;
}
- pr_info("%s(on): success\n", __func__);
+ pr_debug("%s(on): success\n", __func__);
} else {
gpio_free(170);
gpio_free(171);
gpio_free(172);
- rc = regulator_disable(reg_8058_l16);
- if (rc)
- pr_warning("'%s' regulator disable failed, rc=%d\n",
- "8058_l16", rc);
- pr_info("%s(off): success\n", __func__);
+ pr_debug("%s(off): success\n", __func__);
}
prev_on = on;
-
return 0;
error3:
@@ -9046,7 +9067,6 @@
error2:
gpio_free(170);
error1:
- regulator_disable(reg_8058_l16);
return rc;
}
@@ -9095,6 +9115,18 @@
return rc;
}
+static int hdmi_panel_power(int on)
+{
+ int rc;
+
+ pr_debug("%s: HDMI Core: %s\n", __func__, (on ? "ON" : "OFF"));
+ rc = hdmi_core_power(on, 1);
+ if (rc)
+ rc = hdmi_cec_power(on);
+
+ pr_debug("%s: HDMI Core: %s Success\n", __func__, (on ? "ON" : "OFF"));
+ return rc;
+}
#undef _GET_REGULATOR
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
@@ -9517,6 +9549,7 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
+ .lcdc_power_save = hdmi_panel_power,
};
static struct msm_bus_paths dtv_hdmi_prim_bus_scale_usecases[] = {
@@ -10306,9 +10339,6 @@
*/
msm8x60_init_buses();
platform_add_devices(early_devices, ARRAY_SIZE(early_devices));
- /* CPU frequency control is not supported on simulated targets. */
- if (!machine_is_msm8x60_rumi3() && !machine_is_msm8x60_sim())
- acpuclk_init(&acpuclk_8x60_soc_data);
/*
* Enable EBI2 only for boards which make use of it. Leave
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 7708310..9c80c8b 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -32,6 +32,7 @@
#include <linux/input/ft5x06_ts.h>
#include <linux/msm_adc.h>
#include <linux/fmem.h>
+#include <linux/regulator/msm-gpio-regulator.h>
#include <asm/mach/mmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -129,7 +130,7 @@
#ifdef CONFIG_ARCH_MSM7X27A
#define MSM_PMEM_MDP_SIZE 0x2300000
-#define MSM_PMEM_ADSP_SIZE 0x1100000
+#define MSM_PMEM_ADSP_SIZE 0x1200000
#endif
static struct android_usb_platform_data android_usb_pdata = {
@@ -595,7 +596,12 @@
u32 low_voltage = msm_psy_batt_data.voltage_min_design;
u32 high_voltage = msm_psy_batt_data.voltage_max_design;
- return (current_voltage - low_voltage) * 100
+ if (current_voltage <= low_voltage)
+ return 0;
+ else if (current_voltage >= high_voltage)
+ return 100;
+ else
+ return (current_voltage - low_voltage) * 100
/ (high_voltage - low_voltage);
}
@@ -631,6 +637,64 @@
.dev = { .platform_data = &fmem_pdata },
};
+#define GPIO_VREG_INIT(_id, _reg_name, _gpio_label, _gpio, _active_low) \
+ [GPIO_VREG_ID_##_id] = { \
+ .init_data = { \
+ .constraints = { \
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
+ }, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(vreg_consumers_##_id), \
+ .consumer_supplies = vreg_consumers_##_id, \
+ }, \
+ .regulator_name = _reg_name, \
+ .active_low = _active_low, \
+ .gpio_label = _gpio_label, \
+ .gpio = _gpio, \
+ }
+
+#define GPIO_VREG_ID_EXT_2P85V 0
+#define GPIO_VREG_ID_EXT_1P8V 1
+
+static struct regulator_consumer_supply vreg_consumers_EXT_2P85V[] = {
+ REGULATOR_SUPPLY("cam_ov5647_avdd", "0-006c"),
+ REGULATOR_SUPPLY("cam_ov7692_avdd", "0-0078"),
+ REGULATOR_SUPPLY("cam_ov8825_avdd", "0-000d"),
+ REGULATOR_SUPPLY("lcd_vdd", "mipi_dsi.1"),
+};
+
+static struct regulator_consumer_supply vreg_consumers_EXT_1P8V[] = {
+ REGULATOR_SUPPLY("cam_ov5647_vdd", "0-006c"),
+ REGULATOR_SUPPLY("cam_ov7692_vdd", "0-0078"),
+ REGULATOR_SUPPLY("cam_ov8825_vdd", "0-000d"),
+ REGULATOR_SUPPLY("lcd_vddi", "mipi_dsi.1"),
+};
+
+/* GPIO regulator constraints */
+static struct gpio_regulator_platform_data msm_gpio_regulator_pdata[] = {
+ GPIO_VREG_INIT(EXT_2P85V, "ext_2p85v", "ext_2p85v_en", 35, 0),
+ GPIO_VREG_INIT(EXT_1P8V, "ext_1p8v", "ext_1p8v_en", 40, 0),
+};
+
+/* GPIO regulator */
+static struct platform_device qrd_msm8625_vreg_gpio_ext_2p85v __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 35,
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_2P85V],
+ },
+};
+
+static struct platform_device qrd_msm8625_vreg_gpio_ext_1p8v __devinitdata = {
+ .name = GPIO_REGULATOR_DEV_NAME,
+ .id = 40,
+ .dev = {
+ .platform_data =
+ &msm_gpio_regulator_pdata[GPIO_VREG_ID_EXT_1P8V],
+ },
+};
+
static struct platform_device *common_devices[] __initdata = {
&android_usb_device,
&android_pmem_device,
@@ -672,6 +736,8 @@
&msm8625_device_otg,
&msm8625_device_gadget_peripheral,
&msm8625_kgsl_3d0,
+ &qrd_msm8625_vreg_gpio_ext_2p85v,
+ &qrd_msm8625_vreg_gpio_ext_1p8v,
};
static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 6a39316..4df4266 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -2409,7 +2409,7 @@
{
msm_clock_init(&qds8x50_clock_init_data);
qsd8x50_cfg_smc91x();
- acpuclk_init(&acpuclk_8x50_soc_data);
+ platform_device_register(&msm8x50_device_acpuclk);
msm_hsusb_pdata.swfi_latency =
msm_pm_data
diff --git a/arch/arm/mach-msm/cache_erp.c b/arch/arm/mach-msm/cache_erp.c
index 97225ac..4d7ce12 100644
--- a/arch/arm/mach-msm/cache_erp.c
+++ b/arch/arm/mach-msm/cache_erp.c
@@ -35,6 +35,9 @@
/* Print a message for everything but TLB MH events */
#define CESR_PRINT_MASK 0x000000FF
+/* Log everything but TLB MH events */
+#define CESR_LOG_EVENT_MASK 0x000000FF
+
#define L2ESR_IND_ADDR 0x204
#define L2ESYNR0_IND_ADDR 0x208
#define L2ESYNR1_IND_ADDR 0x209
@@ -87,6 +90,9 @@
#define MODULE_NAME "msm_cache_erp"
+#define ERP_LOG_MAGIC_ADDR 0x748
+#define ERP_LOG_MAGIC 0x11C39893
+
struct msm_l1_err_stats {
unsigned int dctpe;
unsigned int dcdpe;
@@ -114,6 +120,10 @@
static int l1_erp_irq, l2_erp_irq;
static struct proc_dir_entry *procfs_entry;
+#ifdef CONFIG_MSM_L1_ERR_LOG
+static struct proc_dir_entry *procfs_log_entry;
+#endif
+
static inline unsigned int read_cesr(void)
{
unsigned int cesr;
@@ -192,6 +202,48 @@
return len;
}
+#ifdef CONFIG_MSM_L1_ERR_LOG
+static int proc_read_log(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ char *p = page;
+ int len, log_value;
+ log_value = __raw_readl(MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR) ==
+ ERP_LOG_MAGIC ? 1 : 0;
+
+ p += snprintf(p, PAGE_SIZE, "%d\n", log_value);
+
+ len = (p - page) - off;
+ if (len < 0)
+ len = 0;
+
+ *eof = (len <= count) ? 1 : 0;
+ *start = page + off;
+
+ return len;
+}
+
+static void log_cpu_event(void)
+{
+ __raw_writel(ERP_LOG_MAGIC, MSM_IMEM_BASE + ERP_LOG_MAGIC_ADDR);
+ mb();
+}
+
+static int procfs_event_log_init(void)
+{
+ procfs_log_entry = create_proc_entry("cpu/msm_erp_log", S_IRUGO, NULL);
+
+ if (!procfs_log_entry)
+ return -ENODEV;
+ procfs_log_entry->read_proc = proc_read_log;
+ return 0;
+}
+
+#else
+static inline void log_cpu_event(void) { }
+static inline int procfs_event_log_init(void) { return 0; }
+#endif
+
static irqreturn_t msm_l1_erp_irq(int irq, void *dev_id)
{
struct msm_l1_err_stats *l1_stats = dev_id;
@@ -199,6 +251,7 @@
unsigned int i_cesynr, d_cesynr;
unsigned int cpu = smp_processor_id();
int print_regs = cesr & CESR_PRINT_MASK;
+ int log_event = cesr & CESR_LOG_EVENT_MASK;
void *const saw_bases[] = {
MSM_SAW0_BASE,
@@ -271,6 +324,9 @@
pr_alert("D-side CESYNR = 0x%08x\n", d_cesynr);
}
+ if (log_event)
+ log_cpu_event();
+
/* Clear the interrupt bits we processed */
write_cesr(cesr);
@@ -459,6 +515,11 @@
put_online_cpus();
procfs_entry->read_proc = proc_read_status;
+
+ ret = procfs_event_log_init();
+ if (ret)
+ pr_err("Failed to create procfs node for ERP log access\n");
+
return 0;
fail_l2:
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 7b4ca29..5867eef 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -934,6 +934,7 @@
.c = {
.dbg_name = "gfx2d0_p_clk",
.ops = &clk_ops_branch,
+ .flags = CLKFLAG_SKIP_HANDOFF,
CLK_INIT(gfx2d0_p_clk.c),
},
};
@@ -952,6 +953,7 @@
.c = {
.dbg_name = "gfx2d1_p_clk",
.ops = &clk_ops_branch,
+ .flags = CLKFLAG_SKIP_HANDOFF,
CLK_INIT(gfx2d1_p_clk.c),
},
};
@@ -3346,6 +3348,7 @@
.c = {
.dbg_name = "gfx2d0_clk",
.ops = &clk_ops_rcg,
+ .flags = CLKFLAG_SKIP_HANDOFF,
VDD_DIG_FMAX_MAP3(LOW, 100000000, NOMINAL, 200000000,
HIGH, 228571000),
CLK_INIT(gfx2d0_clk.c),
@@ -3390,6 +3393,7 @@
.c = {
.dbg_name = "gfx2d1_clk",
.ops = &clk_ops_rcg,
+ .flags = CLKFLAG_SKIP_HANDOFF,
VDD_DIG_FMAX_MAP3(LOW, 100000000, NOMINAL, 200000000,
HIGH, 228571000),
CLK_INIT(gfx2d1_clk.c),
@@ -4598,13 +4602,17 @@
static DEFINE_CLK_VOTER(dfab_bam_dmux_clk, &dfab_clk.c, 0);
static DEFINE_CLK_VOTER(dfab_scm_clk, &dfab_clk.c, 0);
static DEFINE_CLK_VOTER(dfab_qseecom_clk, &dfab_clk.c, 0);
-static DEFINE_CLK_VOTER(dfab_tzcom_clk, &dfab_clk.c, 0);
static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_acpu_a_clk, &afab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_msmbus_a_clk, &afab_a_clk.c, LONG_MAX);
+
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
u32 test_vector;
@@ -5030,8 +5038,25 @@
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
@@ -5041,7 +5066,7 @@
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
@@ -5283,7 +5308,6 @@
CLK_LOOKUP("bus_clk", dfab_bam_dmux_clk.c, "BAM_RMNT"),
CLK_LOOKUP("bus_clk", dfab_scm_clk.c, "scm"),
CLK_LOOKUP("bus_clk", dfab_qseecom_clk.c, "qseecom"),
- CLK_LOOKUP("bus_clk", dfab_tzcom_clk.c, "tzcom"),
CLK_LOOKUP("alt_core_clk", usb_hsic_xcvr_fs_clk.c, "msm_hsic_host"),
CLK_LOOKUP("phy_clk", usb_hsic_hsic_clk.c, "msm_hsic_host"),
@@ -5313,6 +5337,8 @@
CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "pil_vidc"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
@@ -5336,8 +5362,25 @@
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
@@ -5347,7 +5390,7 @@
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
@@ -5486,7 +5529,8 @@
CLK_LOOKUP("mem_clk", imem_axi_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "msm_gemini.0"),
CLK_LOOKUP("core_clk", ijpeg_clk.c, "footswitch-8x60.3"),
- CLK_LOOKUP("core_clk", jpegd_clk.c, ""),
+ CLK_LOOKUP("core_clk", jpegd_clk.c, "msm_mercury.0"),
+ CLK_LOOKUP("iface_clk", jpegd_p_clk.c, "msm_mercury.0"),
CLK_LOOKUP("core_clk", mdp_clk.c, "mdp.0"),
CLK_LOOKUP("core_clk", mdp_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("vsync_clk", mdp_vsync_clk.c, "mdp.0"),
@@ -5608,9 +5652,10 @@
CLK_LOOKUP("bus_clk", dfab_bam_dmux_clk.c, "BAM_RMNT"),
CLK_LOOKUP("bus_clk", dfab_scm_clk.c, "scm"),
CLK_LOOKUP("bus_clk", dfab_qseecom_clk.c, "qseecom"),
- CLK_LOOKUP("bus_clk", dfab_tzcom_clk.c, "tzcom"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
@@ -5633,8 +5678,25 @@
CLK_LOOKUP("pll4", pll4_clk.c, NULL),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
@@ -5644,7 +5706,7 @@
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
CLK_LOOKUP("bus_a_clk", mmfab_a_clk.c, "msm_mm_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
@@ -5885,6 +5947,8 @@
CLK_LOOKUP("bus_clk", dfab_qseecom_clk.c, "qseecom"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("l2_mclk", l2_m_clk, ""),
CLK_LOOKUP("krait0_mclk", krait0_m_clk, ""),
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index 7aed579..74d71a2 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -700,6 +700,7 @@
.c = {
.dbg_name = "gfx2d0_p_clk",
.ops = &clk_ops_branch,
+ .flags = CLKFLAG_SKIP_HANDOFF,
CLK_INIT(gfx2d0_p_clk.c),
},
};
@@ -716,6 +717,7 @@
.c = {
.dbg_name = "gfx2d1_p_clk",
.ops = &clk_ops_branch,
+ .flags = CLKFLAG_SKIP_HANDOFF,
CLK_INIT(gfx2d1_p_clk.c),
},
};
@@ -2178,6 +2180,7 @@
.c = {
.dbg_name = "gfx2d0_clk",
.ops = &clk_ops_rcg,
+ .flags = CLKFLAG_SKIP_HANDOFF,
VDD_DIG_FMAX_MAP3(LOW, 100000000, NOMINAL, 200000000,
HIGH, 228571000),
CLK_INIT(gfx2d0_clk.c),
@@ -2222,6 +2225,7 @@
.c = {
.dbg_name = "gfx2d1_clk",
.ops = &clk_ops_rcg,
+ .flags = CLKFLAG_SKIP_HANDOFF,
VDD_DIG_FMAX_MAP3(LOW, 100000000, NOMINAL, 200000000,
HIGH, 228571000),
CLK_INIT(gfx2d1_clk.c),
@@ -3117,6 +3121,11 @@
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ebi1_adm0_clk, &ebi1_clk.c, 0);
static DEFINE_CLK_VOTER(ebi1_adm1_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_acpu_a_clk, &afab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(afab_msmbus_a_clk, &afab_a_clk.c, LONG_MAX);
+
static DEFINE_CLK_MEASURE(sc0_m_clk);
static DEFINE_CLK_MEASURE(sc1_m_clk);
static DEFINE_CLK_MEASURE(l2_m_clk);
@@ -3479,8 +3488,27 @@
CLK_LOOKUP("pll4", pll4_clk.c, "pil_qdsp6v3"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", afab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", mmfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", smi_clk.c, ""),
+ CLK_LOOKUP("mem_clk", smi_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", afab_clk.c, "msm_apps_fab"),
- CLK_LOOKUP("bus_a_clk", afab_a_clk.c, "msm_apps_fab"),
+ CLK_LOOKUP("bus_a_clk", afab_msmbus_a_clk.c, "msm_apps_fab"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
CLK_LOOKUP("bus_a_clk", sfab_a_clk.c, "msm_sys_fab"),
CLK_LOOKUP("bus_clk", sfpb_clk.c, "msm_sys_fpb"),
@@ -3490,16 +3518,10 @@
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("smi_clk", smi_clk.c, "msm_bus"),
CLK_LOOKUP("smi_a_clk", smi_a_clk.c, "msm_bus"),
- CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
- CLK_LOOKUP("dfab_clk", dfab_clk.c, NULL),
- CLK_LOOKUP("dfab_a_clk", dfab_a_clk.c, NULL),
- CLK_LOOKUP("mmfpb_clk", mmfpb_clk.c, NULL),
- CLK_LOOKUP("mmfpb_a_clk", mmfpb_a_clk.c, NULL),
-
CLK_LOOKUP("core_clk", gp0_clk.c, ""),
CLK_LOOKUP("core_clk", gp1_clk.c, ""),
CLK_LOOKUP("core_clk", gp2_clk.c, ""),
@@ -3713,6 +3735,8 @@
CLK_LOOKUP("mem_clk", ebi1_adm0_clk.c, "msm_dmov.0"),
CLK_LOOKUP("mem_clk", ebi1_adm1_clk.c, "msm_dmov.1"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", afab_acpu_a_clk.c, ""),
CLK_LOOKUP("sc0_mclk", sc0_m_clk, ""),
CLK_LOOKUP("sc1_mclk", sc1_m_clk, ""),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 66d849a..a2e0bc9 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -135,6 +135,9 @@
#define LCC_PCM_MD_REG REG_LPA(0x0058)
#define LCC_PCM_NS_REG REG_LPA(0x0054)
#define LCC_PCM_STATUS_REG REG_LPA(0x005C)
+#define LCC_SEC_PCM_MD_REG REG_LPA(0x00F4)
+#define LCC_SEC_PCM_NS_REG REG_LPA(0x00F0)
+#define LCC_SEC_PCM_STATUS_REG REG_LPA(0x00F8)
#define LCC_PLL0_STATUS_REG REG_LPA(0x0018)
#define LCC_SPARE_I2S_MIC_MD_REG REG_LPA(0x007C)
#define LCC_SPARE_I2S_MIC_NS_REG REG_LPA(0x0078)
@@ -184,15 +187,15 @@
static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
{
- static const int vdd_uv[] = {
- [VDD_DIG_NONE] = 0,
- [VDD_DIG_LOW] = 945000,
- [VDD_DIG_NOMINAL] = 1050000,
- [VDD_DIG_HIGH] = 1150000
+ static const int vdd_corner[] = {
+ [VDD_DIG_NONE] = RPM_VREG_CORNER_NONE,
+ [VDD_DIG_LOW] = RPM_VREG_CORNER_LOW,
+ [VDD_DIG_NOMINAL] = RPM_VREG_CORNER_NOMINAL,
+ [VDD_DIG_HIGH] = RPM_VREG_CORNER_HIGH,
};
- return rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_S1, RPM_VREG_VOTER3,
- vdd_uv[level], vdd_uv[VDD_DIG_HIGH], 1);
+ return rpm_vreg_set_voltage(RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+ RPM_VREG_VOTER3, vdd_corner[level], RPM_VREG_CORNER_HIGH, 1);
}
static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
@@ -1267,6 +1270,32 @@
},
};
+static struct rcg_clk sec_pcm_clk = {
+ .b = {
+ .ctl_reg = LCC_SEC_PCM_NS_REG,
+ .en_mask = BIT(11),
+ .reset_reg = LCC_SEC_PCM_NS_REG,
+ .reset_mask = BIT(13),
+ .halt_reg = LCC_SEC_PCM_STATUS_REG,
+ .halt_check = ENABLE,
+ .halt_bit = 0,
+ },
+ .ns_reg = LCC_SEC_PCM_NS_REG,
+ .md_reg = LCC_SEC_PCM_MD_REG,
+ .root_en_mask = BIT(9),
+ .ns_mask = BM(31, 16) | BIT(10) | BM(6, 0),
+ .mnd_en_mask = BIT(8),
+ .set_rate = set_rate_mnd,
+ .freq_tbl = clk_tbl_pcm,
+ .current_freq = &rcg_dummy_freq,
+ .c = {
+ .dbg_name = "sec_pcm_clk",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP1(LOW, 24576000),
+ CLK_INIT(sec_pcm_clk.c),
+ },
+};
+
static struct rcg_clk audio_slimbus_clk = {
.b = {
.ctl_reg = LCC_SLIMBUS_NS_REG,
@@ -1338,7 +1367,11 @@
static DEFINE_CLK_VOTER(dfab_msmbus_clk, &dfab_clk.c, 0);
static DEFINE_CLK_VOTER(dfab_msmbus_a_clk, &dfab_a_clk.c, 0);
static DEFINE_CLK_VOTER(ebi1_msmbus_clk, &ebi1_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_msmbus_a_clk, &ebi1_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ebi1_acpu_a_clk, &ebi1_a_clk.c, LONG_MAX);
static DEFINE_CLK_VOTER(ebi1_adm_clk, &ebi1_clk.c, 0);
+static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(sfab_acpu_a_clk, &sfab_a_clk.c, LONG_MAX);
#ifdef CONFIG_DEBUG_FS
struct measure_sel {
@@ -1588,19 +1621,24 @@
CLK_LOOKUP("measure", measure_clk.c, "debug"),
+ CLK_LOOKUP("bus_clk", cfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cfpb_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", dfab_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ebi1_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfpb_a_clk.c, ""),
+
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
- CLK_LOOKUP("bus_a_clk", sfab_a_clk.c, "msm_sys_fab"),
+ CLK_LOOKUP("bus_a_clk", sfab_msmbus_a_clk.c, "msm_sys_fab"),
CLK_LOOKUP("mem_clk", ebi1_msmbus_clk.c, "msm_bus"),
- CLK_LOOKUP("mem_a_clk", ebi1_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("mem_a_clk", ebi1_msmbus_a_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_clk", dfab_msmbus_clk.c, "msm_bus"),
CLK_LOOKUP("dfab_a_clk", dfab_msmbus_a_clk.c, "msm_bus"),
- CLK_LOOKUP("bus_clk", sfpb_clk.c, NULL),
- CLK_LOOKUP("bus_a_clk", sfpb_a_clk.c, NULL),
- CLK_LOOKUP("bus_clk", cfpb_clk.c, NULL),
- CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, NULL),
- CLK_LOOKUP("ebi1_clk", ebi1_clk.c, NULL),
-
CLK_LOOKUP("core_clk", gp0_clk.c, ""),
CLK_LOOKUP("core_clk", gp1_clk.c, ""),
CLK_LOOKUP("core_clk", gp2_clk.c, ""),
@@ -1673,6 +1711,8 @@
"msm-dai-q6.4"),
CLK_LOOKUP("pcm_clk", pcm_clk.c, "msm-dai-q6.2"),
CLK_LOOKUP("pcm_clk", pcm_clk.c, "msm-dai-q6.3"),
+ CLK_LOOKUP("sec_pcm_clk", sec_pcm_clk.c, "msm-dai-q6.12"),
+ CLK_LOOKUP("sec_pcm_clk", sec_pcm_clk.c, "msm-dai-q6.13"),
CLK_LOOKUP("sps_slimbus_clk", sps_slimbus_clk.c, NULL),
CLK_LOOKUP("core_clk", audio_slimbus_clk.c, "msm_slim_ctrl.1"),
@@ -1682,6 +1722,8 @@
CLK_LOOKUP("dfab_clk", dfab_sps_clk.c, "msm_sps"),
CLK_LOOKUP("bus_clk", dfab_bam_dmux_clk.c, "BAM_RMNT"),
CLK_LOOKUP("mem_clk", ebi1_adm_clk.c, "msm_dmov"),
+ CLK_LOOKUP("mem_clk", ebi1_acpu_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", sfab_acpu_a_clk.c, ""),
CLK_LOOKUP("iface_clk", ce1_p_clk.c, "qce.0"),
CLK_LOOKUP("iface_clk", ce1_p_clk.c, "qcrypto.0"),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index fc0b0af..5727c34 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -23,6 +23,8 @@
#include "clock-local2.h"
#include "clock-pll.h"
+#include "clock-rpm.h"
+#include "clock-voter.h"
enum {
GCC_BASE,
@@ -713,6 +715,37 @@
},
};
+#define RPM_BUS_CLK_TYPE 0x316b6c63
+#define RPM_MEM_CLK_TYPE 0x326b6c63
+
+#define PNOC_ID 0x0
+#define SNOC_ID 0x1
+#define CNOC_ID 0x2
+
+#define BIMC_ID 0x0
+#define OCMEM_ID 0x1
+
+DEFINE_CLK_RPM_SMD(pnoc_clk, pnoc_a_clk, RPM_BUS_CLK_TYPE, PNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(snoc_clk, snoc_a_clk, RPM_BUS_CLK_TYPE, SNOC_ID, NULL);
+DEFINE_CLK_RPM_SMD(cnoc_clk, cnoc_a_clk, RPM_BUS_CLK_TYPE, CNOC_ID, NULL);
+
+DEFINE_CLK_RPM_SMD(bimc_clk, bimc_a_clk, RPM_MEM_CLK_TYPE, BIMC_ID, NULL);
+DEFINE_CLK_RPM_SMD(ocmemgx_clk, ocmemgx_a_clk, RPM_MEM_CLK_TYPE, OCMEM_ID,
+ NULL);
+
+static DEFINE_CLK_VOTER(pnoc_msmbus_clk, &pnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_clk, &snoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_clk, &cnoc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(pnoc_msmbus_a_clk, &pnoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(snoc_msmbus_a_clk, &snoc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(cnoc_msmbus_a_clk, &cnoc_a_clk.c, LONG_MAX);
+
+static DEFINE_CLK_VOTER(bimc_msmbus_clk, &bimc_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_msmbus_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(bimc_acpu_a_clk, &bimc_a_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_msmbus_clk, &ocmemgx_clk.c, LONG_MAX);
+static DEFINE_CLK_VOTER(ocmemgx_msmbus_a_clk, &ocmemgx_a_clk.c, LONG_MAX);
+
static struct clk_freq_tbl ftbl_gcc_usb30_master_clk[] = {
F(125000000, gpll0, 1, 5, 24),
F_END
@@ -2199,28 +2232,6 @@
},
};
-static struct clk_freq_tbl ftbl_mmss_ahb_clk[] = {
- F_MM(19200000, cxo, 1, 0, 0),
- F_MM(40000000, gpll0, 15, 0, 0),
- F_MM(80000000, mmpll0, 10, 0, 0),
- F_END,
-};
-
-/* TODO: This may go away (may be controlled by the RPM). */
-static struct rcg_clk ahb_clk_src = {
- .cmd_rcgr_reg = 0x5000,
- .set_rate = set_rate_hid,
- .freq_tbl = ftbl_mmss_ahb_clk,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[MMSS_BASE],
- .c = {
- .dbg_name = "ahb_clk_src",
- .ops = &clk_ops_rcg,
- VDD_DIG_FMAX_MAP2(LOW, 40000000, NOMINAL, 80000000),
- CLK_INIT(ahb_clk_src.c),
- },
-};
-
static struct clk_freq_tbl ftbl_mmss_axi_clk[] = {
F_MM( 19200000, cxo, 1, 0, 0),
F_MM(150000000, gpll0, 4, 0, 0),
@@ -2244,6 +2255,29 @@
},
};
+static struct clk_freq_tbl ftbl_ocmemnoc_clk[] = {
+ F_MM( 19200000, cxo, 1, 0, 0),
+ F_MM(150000000, gpll0, 4, 0, 0),
+ F_MM(333330000, mmpll1, 3, 0, 0),
+ F_MM(400000000, mmpll0, 2, 0, 0),
+ F_END
+};
+
+struct rcg_clk ocmemnoc_clk_src = {
+ .cmd_rcgr_reg = OCMEMNOC_CMD_RCGR,
+ .set_rate = set_rate_hid,
+ .freq_tbl = ftbl_ocmemnoc_clk,
+ .current_freq = &rcg_dummy_freq,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "ocmemnoc_clk_src",
+ .ops = &clk_ops_rcg,
+ VDD_DIG_FMAX_MAP3(LOW, 150000000, NOMINAL, 333330000,
+ HIGH, 400000000),
+ CLK_INIT(ocmemnoc_clk_src.c),
+ },
+};
+
static struct clk_freq_tbl ftbl_camss_csi0_3_clk[] = {
F_MM(100000000, gpll0, 6, 0, 0),
F_MM(200000000, mmpll0, 4, 0, 0),
@@ -2869,7 +2903,6 @@
static struct branch_clk camss_cci_cci_ahb_clk = {
.cbcr_reg = CAMSS_CCI_CCI_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2893,7 +2926,6 @@
static struct branch_clk camss_csi0_ahb_clk = {
.cbcr_reg = CAMSS_CSI0_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2953,7 +2985,6 @@
static struct branch_clk camss_csi1_ahb_clk = {
.cbcr_reg = CAMSS_CSI1_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3013,7 +3044,6 @@
static struct branch_clk camss_csi2_ahb_clk = {
.cbcr_reg = CAMSS_CSI2_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3073,7 +3103,6 @@
static struct branch_clk camss_csi3_ahb_clk = {
.cbcr_reg = CAMSS_CSI3_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3181,7 +3210,6 @@
static struct branch_clk camss_ispif_ahb_clk = {
.cbcr_reg = CAMSS_ISPIF_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3229,7 +3257,6 @@
static struct branch_clk camss_jpeg_jpeg_ahb_clk = {
.cbcr_reg = CAMSS_JPEG_JPEG_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3253,6 +3280,7 @@
static struct branch_clk camss_jpeg_jpeg_ocmemnoc_clk = {
.cbcr_reg = CAMSS_JPEG_JPEG_OCMEMNOC_CBCR,
+ .parent = &ocmemnoc_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3312,7 +3340,6 @@
static struct branch_clk camss_micro_ahb_clk = {
.cbcr_reg = CAMSS_MICRO_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3360,7 +3387,6 @@
static struct branch_clk camss_top_ahb_clk = {
.cbcr_reg = CAMSS_TOP_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3372,7 +3398,6 @@
static struct branch_clk camss_vfe_cpp_ahb_clk = {
.cbcr_reg = CAMSS_VFE_CPP_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3420,7 +3445,6 @@
static struct branch_clk camss_vfe_vfe_ahb_clk = {
.cbcr_reg = CAMSS_VFE_VFE_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3444,6 +3468,7 @@
static struct branch_clk camss_vfe_vfe_ocmemnoc_clk = {
.cbcr_reg = CAMSS_VFE_VFE_OCMEMNOC_CBCR,
+ .parent = &ocmemnoc_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3455,7 +3480,6 @@
static struct branch_clk mdss_ahb_clk = {
.cbcr_reg = MDSS_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3575,7 +3599,6 @@
static struct branch_clk mdss_hdmi_ahb_clk = {
.cbcr_reg = MDSS_HDMI_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3659,7 +3682,6 @@
static struct branch_clk mmss_misc_ahb_clk = {
.cbcr_reg = MMSS_MISC_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3671,7 +3693,6 @@
static struct branch_clk mmss_mmssnoc_ahb_clk = {
.cbcr_reg = MMSS_MMSSNOC_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3683,7 +3704,6 @@
static struct branch_clk mmss_mmssnoc_bto_ahb_clk = {
.cbcr_reg = MMSS_MMSSNOC_BTO_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3696,7 +3716,8 @@
static struct branch_clk mmss_mmssnoc_axi_clk = {
.cbcr_reg = MMSS_MMSSNOC_AXI_CBCR,
.parent = &axi_clk_src.c,
- .has_sibling = 1,
+ /* The bus driver needs set_rate to go through to the parent */
+ .has_sibling = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
.dbg_name = "mmss_mmssnoc_axi_clk",
@@ -3717,9 +3738,21 @@
},
};
+struct branch_clk ocmemnoc_clk = {
+ .cbcr_reg = OCMEMNOC_CBCR,
+ .parent = &ocmemnoc_clk_src.c,
+ .has_sibling = 0,
+ .bcr_reg = 0x50b0,
+ .base = &virt_bases[MMSS_BASE],
+ .c = {
+ .dbg_name = "ocmemnoc_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(ocmemnoc_clk.c),
+ },
+};
+
static struct branch_clk venus0_ahb_clk = {
.cbcr_reg = VENUS0_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3743,6 +3776,7 @@
static struct branch_clk venus0_ocmemnoc_clk = {
.cbcr_reg = VENUS0_OCMEMNOC_CBCR,
+ .parent = &ocmemnoc_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3777,7 +3811,6 @@
static struct branch_clk oxilicx_ahb_clk = {
.cbcr_reg = OXILICX_AHB_CBCR,
- .parent = &ahb_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -3966,7 +3999,6 @@
static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
- .parent = &audio_core_lpaif_codec_spkr_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
@@ -3980,7 +4012,7 @@
.cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
.parent = &audio_core_lpaif_codec_spkr_clk_src.c,
.has_sibling = 1,
- .max_div = 16,
+ .max_div = 15,
.base = &virt_bases[LPASS_BASE],
.c = {
.dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
@@ -4003,7 +4035,6 @@
static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
.cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
- .parent = &audio_core_lpaif_pri_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
@@ -4017,7 +4048,7 @@
.cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
.parent = &audio_core_lpaif_pri_clk_src.c,
.has_sibling = 1,
- .max_div = 16,
+ .max_div = 15,
.base = &virt_bases[LPASS_BASE],
.c = {
.dbg_name = "audio_core_lpaif_pri_ibit_clk",
@@ -4040,7 +4071,6 @@
static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
.cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
- .parent = &audio_core_lpaif_sec_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
@@ -4054,7 +4084,7 @@
.cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
.parent = &audio_core_lpaif_sec_clk_src.c,
.has_sibling = 1,
- .max_div = 16,
+ .max_div = 15,
.base = &virt_bases[LPASS_BASE],
.c = {
.dbg_name = "audio_core_lpaif_sec_ibit_clk",
@@ -4077,7 +4107,6 @@
static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
.cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
- .parent = &audio_core_lpaif_ter_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
@@ -4091,7 +4120,7 @@
.cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
.parent = &audio_core_lpaif_ter_clk_src.c,
.has_sibling = 1,
- .max_div = 16,
+ .max_div = 15,
.base = &virt_bases[LPASS_BASE],
.c = {
.dbg_name = "audio_core_lpaif_ter_ibit_clk",
@@ -4114,7 +4143,6 @@
static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
- .parent = &audio_core_lpaif_quad_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
@@ -4128,7 +4156,7 @@
.cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
.parent = &audio_core_lpaif_quad_clk_src.c,
.has_sibling = 1,
- .max_div = 16,
+ .max_div = 15,
.base = &virt_bases[LPASS_BASE],
.c = {
.dbg_name = "audio_core_lpaif_quad_ibit_clk",
@@ -4139,7 +4167,6 @@
static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
- .parent = &audio_core_lpaif_pcm0_clk_src.c,
.has_sibling = 1,
.base = &virt_bases[LPASS_BASE],
.c = {
@@ -4153,7 +4180,6 @@
.cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
.parent = &audio_core_lpaif_pcm0_clk_src.c,
.has_sibling = 1,
- .max_div = 16,
.base = &virt_bases[LPASS_BASE],
.c = {
.dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
@@ -4178,7 +4204,6 @@
.cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
.parent = &audio_core_lpaif_pcm1_clk_src.c,
.has_sibling = 1,
- .max_div = 16,
.base = &virt_bases[LPASS_BASE],
.c = {
.dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
@@ -4310,6 +4335,7 @@
{&gcc_usb_hsic_system_clk.c, GCC_BASE, 0x0061},
{&mmss_mmssnoc_ahb_clk.c, MMSS_BASE, 0x0001},
{&mmss_mmssnoc_axi_clk.c, MMSS_BASE, 0x0004},
+ {&ocmemnoc_clk.c, MMSS_BASE, 0x0007},
{&camss_cci_cci_ahb_clk.c, MMSS_BASE, 0x002e},
{&camss_cci_cci_clk.c, MMSS_BASE, 0x002d},
{&camss_csi0_ahb_clk.c, MMSS_BASE, 0x0042},
@@ -4577,6 +4603,8 @@
static struct clk_lookup msm_clocks_copper[] = {
CLK_LOOKUP("xo", cxo_clk_src.c, "msm_otg"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-lpass"),
+ CLK_LOOKUP("xo", cxo_clk_src.c, "pil-q6v5-mss"),
+ CLK_LOOKUP("xo", cxo_clk_src.c, "pil-mba"),
CLK_LOOKUP("xo", cxo_clk_src.c, "pil_pronto"),
CLK_LOOKUP("measure", measure_clk.c, "debug"),
@@ -4650,18 +4678,17 @@
CLK_LOOKUP("iface_clk", gcc_tsif_ahb_clk.c, ""),
CLK_LOOKUP("ref_clk", gcc_tsif_ref_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_usb30_mock_utmi_clk.c, ""),
- CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_otg"),
- CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, ""),
- CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_usb_hsic_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_usb_hsic_io_cal_clk.c, ""),
- CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, ""),
+ CLK_LOOKUP("core_clk", gcc_usb30_master_clk.c, "msm_dwc3"),
+ CLK_LOOKUP("utmi_clk", gcc_usb30_mock_utmi_clk.c, "msm_dwc3"),
+ CLK_LOOKUP("iface_clk", gcc_usb_hs_ahb_clk.c, "msm_otg"),
+ CLK_LOOKUP("core_clk", gcc_usb_hs_system_clk.c, "msm_otg"),
+ CLK_LOOKUP("iface_clk", gcc_usb_hsic_ahb_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("phy_clk", gcc_usb_hsic_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("cal_clk", gcc_usb_hsic_io_cal_clk.c, "msm_hsic_host"),
+ CLK_LOOKUP("core_clk", gcc_usb_hsic_system_clk.c, "msm_hsic_host"),
/* Multimedia clocks */
CLK_LOOKUP("bus_clk_src", axi_clk_src.c, ""),
- CLK_LOOKUP("bus_clk_src", ahb_clk_src.c, ""),
CLK_LOOKUP("bus_clk", mmss_mmssnoc_ahb_clk.c, ""),
CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, ""),
CLK_LOOKUP("core_clk", mdss_edpaux_clk.c, ""),
@@ -4773,20 +4800,46 @@
CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, ""),
- CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, ""),
+ CLK_LOOKUP("core_clk", mss_xo_q6_clk.c, "pil-q6v5-mss"),
+ CLK_LOOKUP("bus_clk", mss_bus_q6_clk.c, "pil-q6v5-mss"),
+ CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
+ CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "pil-q6v5-mss"),
CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "pil-q6v5-lpass"),
CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, "pil-q6v5-lpass"),
- CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
- CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
CLK_LOOKUP("core_clk", gcc_prng_ahb_clk.c, "msm_rng"),
/* TODO: Remove dummy clocks as soon as they become unnecessary */
- CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
- CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
CLK_DUMMY("dfab_clk", DFAB_CLK, "msm_sps", OFF),
CLK_DUMMY("mem_clk", NULL, "msm_sps", OFF),
CLK_DUMMY("bus_clk", NULL, "scm", OFF),
+ CLK_DUMMY("bus_clk", NULL, "qseecom", OFF),
+
+ CLK_LOOKUP("bus_clk", snoc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pnoc_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cnoc_clk.c, ""),
+ CLK_LOOKUP("mem_clk", bimc_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ocmemgx_clk.c, ""),
+ CLK_LOOKUP("bus_clk", snoc_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pnoc_a_clk.c, ""),
+ CLK_LOOKUP("bus_clk", cnoc_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", bimc_a_clk.c, ""),
+ CLK_LOOKUP("mem_clk", ocmemgx_a_clk.c, ""),
+
+ CLK_LOOKUP("bus_clk", cnoc_msmbus_clk.c, "msm_config_noc"),
+ CLK_LOOKUP("bus_a_clk", cnoc_msmbus_a_clk.c, "msm_config_noc"),
+ CLK_LOOKUP("bus_clk", snoc_msmbus_clk.c, "msm_sys_noc"),
+ CLK_LOOKUP("bus_a_clk", snoc_msmbus_a_clk.c, "msm_sys_noc"),
+ CLK_LOOKUP("bus_clk", pnoc_msmbus_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("bus_a_clk", pnoc_msmbus_a_clk.c, "msm_periph_noc"),
+ CLK_LOOKUP("mem_clk", bimc_msmbus_clk.c, "msm_bimc"),
+ CLK_LOOKUP("mem_a_clk", bimc_msmbus_a_clk.c, "msm_bimc"),
+ CLK_LOOKUP("mem_clk", bimc_acpu_a_clk.c, ""),
+ CLK_LOOKUP("ocmem_clk", ocmemgx_msmbus_clk.c, "msm_bus"),
+ CLK_LOOKUP("ocmem_a_clk", ocmemgx_msmbus_a_clk.c, "msm_bus"),
+ CLK_LOOKUP("bus_clk", ocmemnoc_clk.c, "msm_ocmem_noc"),
+ CLK_LOOKUP("bus_a_clk", ocmemnoc_clk.c, "msm_ocmem_noc"),
+ CLK_LOOKUP("bus_clk", mmss_mmssnoc_axi_clk.c, "msm_mmss_noc"),
+ CLK_LOOKUP("bus_a_clk", mmss_mmssnoc_axi_clk.c, "msm_mmss_noc"),
};
static struct pll_config_regs gpll0_regs __initdata = {
@@ -4981,7 +5034,6 @@
static void __init msmcopper_clock_post_init(void)
{
- clk_set_rate(&ahb_clk_src.c, 80000000);
clk_set_rate(&axi_clk_src.c, 333330000);
/* Set rates for single-rate clocks. */
diff --git a/arch/arm/mach-msm/clock-dss-8960.c b/arch/arm/mach-msm/clock-dss-8960.c
index 8331899..7f3646f 100644
--- a/arch/arm/mach-msm/clock-dss-8960.c
+++ b/arch/arm/mach-msm/clock-dss-8960.c
@@ -97,6 +97,7 @@
{
unsigned int val;
u32 ahb_en_reg, ahb_enabled;
+ unsigned int timeout_count;
ahb_en_reg = readl_relaxed(AHB_EN_REG);
ahb_enabled = ahb_en_reg & BIT(4);
@@ -110,6 +111,12 @@
writel_relaxed(0x8D, HDMI_PHY_PLL_LOCKDET_CFG2);
writel_relaxed(0x10, HDMI_PHY_PLL_LOCKDET_CFG0);
writel_relaxed(0x1A, HDMI_PHY_PLL_LOCKDET_CFG1);
+ /* Wait for a short time before de-asserting
+ * to allow the hardware to complete its job.
+ * This much of delay should be fine for hardware
+ * to assert and de-assert.
+ */
+ udelay(10);
/* De-assert PLL S/W reset */
writel_relaxed(0x0D, HDMI_PHY_PLL_LOCKDET_CFG2);
@@ -118,6 +125,11 @@
/* Assert PHY S/W reset */
writel_relaxed(val, HDMI_PHY_REG_12);
val &= ~BIT(5);
+ /* Wait for a short time before de-asserting
+ to allow the hardware to complete its job.
+ This much of delay should be fine for hardware
+ to assert and de-assert. */
+ udelay(10);
/* De-assert PHY S/W reset */
writel_relaxed(val, HDMI_PHY_REG_12);
writel_relaxed(0x3f, HDMI_PHY_REG_2);
@@ -135,8 +147,32 @@
writel_relaxed(val, HDMI_PHY_PLL_PWRDN_B);
writel_relaxed(0x80, HDMI_PHY_REG_2);
- while (!(readl_relaxed(HDMI_PHY_PLL_STATUS0) & BIT(0)))
- cpu_relax();
+ timeout_count = 1000;
+ while (!(readl_relaxed(HDMI_PHY_PLL_STATUS0) & BIT(0)) &&
+ timeout_count) {
+ if (--timeout_count == 0) {
+ /*
+ * PLL has still not locked.
+ * Do a software reset and try again
+ * Assert PLL S/W reset first
+ */
+ writel_relaxed(0x8D, HDMI_PHY_PLL_LOCKDET_CFG2);
+
+ /* Wait for a short time before de-asserting
+ * to allow the hardware to complete its job.
+ * This much of delay should be fine for hardware
+ * to assert and de-assert.
+ */
+ udelay(10);
+ writel_relaxed(0x0D, HDMI_PHY_PLL_LOCKDET_CFG2);
+ timeout_count = 1000;
+
+ pr_err("%s: PLL not locked after %d iterations\n",
+ __func__, timeout_count);
+ pr_err("%s: Asserting PLL S/W reset & trying again\n",
+ __func__);
+ }
+ }
if (!ahb_enabled)
writel_relaxed(ahb_en_reg & ~BIT(4), AHB_EN_REG);
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index 4f365fa..b5ae4ab 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -464,10 +464,7 @@
if (nf->freq_hz == FREQ_END)
return -EINVAL;
- /* Check if frequency is actually changed. */
cf = clk->current_freq;
- if (nf == cf)
- return 0;
if (clk->enabled) {
/* Enable source clock dependency for the new freq. */
@@ -613,10 +610,8 @@
ns_val = readl_relaxed(clk->ns_reg) & ns_mask;
for (freq = clk->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
if ((freq->ns_val & ns_mask) == ns_val &&
- (!freq->md_val || freq->md_val == md_val)) {
- pr_info("%s rate=%d\n", clk->c.dbg_name, freq->freq_hz);
+ (!freq->md_val || freq->md_val == md_val))
break;
- }
}
if (freq->freq_hz == FREQ_END)
return HANDOFF_UNKNOWN_RATE;
@@ -881,9 +876,6 @@
if (rate > clk->max_div)
return -EINVAL;
- /* Check if frequency is actually changed. */
- if (rate == clk->cur_div)
- return 0;
spin_lock(&local_clock_reg_lock);
reg_val = readl_relaxed(clk->ns_reg);
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index cf45e63..9fe9591 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -166,10 +166,7 @@
if (nf->freq_hz == FREQ_END)
return -EINVAL;
- /* Check if frequency is actually changed. */
cf = rcg->current_freq;
- if (nf == cf)
- return 0;
if (rcg->c.count) {
/* TODO: Modify to use the prepare API */
@@ -285,7 +282,6 @@
if (freq->d_val != d_regval)
continue;
}
- pr_info("%s rate=%lu\n", rcg->c.dbg_name, freq->freq_hz);
break;
}
@@ -412,6 +408,19 @@
return -EPERM;
}
+static long branch_clk_round_rate(struct clk *c, unsigned long rate)
+{
+ struct branch_clk *branch = to_branch_clk(c);
+
+ if (branch->max_div)
+ return rate <= (branch->max_div) ? rate : -EPERM;
+
+ if (!branch->has_sibling)
+ return clk_round_rate(branch->parent, rate);
+
+ return -EPERM;
+}
+
static unsigned long branch_clk_get_rate(struct clk *c)
{
struct branch_clk *branch = to_branch_clk(c);
@@ -451,7 +460,6 @@
cbcr_regval = readl_relaxed(CBCR_REG(branch));
if ((cbcr_regval & CBCR_BRANCH_OFF_BIT))
return HANDOFF_DISABLED_CLK;
- pr_info("%s enabled.\n", branch->c.dbg_name);
if (branch->parent) {
if (branch->parent->ops->handoff)
@@ -462,17 +470,12 @@
}
static int __branch_clk_reset(void __iomem *bcr_reg,
- enum clk_reset_action action, const char *name)
+ enum clk_reset_action action)
{
int ret = 0;
unsigned long flags;
u32 reg_val;
- if (!bcr_reg) {
- WARN("clk_reset called on an unsupported clock (%s)\n", name);
- return -EPERM;
- }
-
spin_lock_irqsave(&local_clock_reg_lock, flags);
reg_val = readl_relaxed(bcr_reg);
switch (action) {
@@ -497,7 +500,13 @@
static int branch_clk_reset(struct clk *c, enum clk_reset_action action)
{
struct branch_clk *branch = to_branch_clk(c);
- return __branch_clk_reset(BCR_REG(branch), action, c->dbg_name);
+
+ if (!branch->bcr_reg) {
+ WARN("clk_reset called on an unsupported clock (%s)\n",
+ c->dbg_name);
+ return -EPERM;
+ }
+ return __branch_clk_reset(BCR_REG(branch), action);
}
/*
@@ -506,7 +515,13 @@
static int local_vote_clk_reset(struct clk *c, enum clk_reset_action action)
{
struct local_vote_clk *vclk = to_local_vote_clk(c);
- return __branch_clk_reset(BCR_REG(vclk), action, c->dbg_name);
+
+ if (!vclk->bcr_reg) {
+ WARN("clk_reset called on an unsupported clock (%s)\n",
+ c->dbg_name);
+ return -EPERM;
+ }
+ return __branch_clk_reset(BCR_REG(vclk), action);
}
static int local_vote_clk_enable(struct clk *c)
@@ -549,7 +564,6 @@
vote_regval = readl_relaxed(VOTE_REG(vclk));
if (!(vote_regval & vclk->en_mask))
return HANDOFF_DISABLED_CLK;
- pr_info("%s enabled.\n", vclk->c.dbg_name);
return HANDOFF_ENABLED_CLK;
}
@@ -579,6 +593,7 @@
.set_rate = branch_clk_set_rate,
.get_rate = branch_clk_get_rate,
.list_rate = branch_clk_list_rate,
+ .round_rate = branch_clk_round_rate,
.reset = branch_clk_reset,
.get_parent = branch_clk_get_parent,
.handoff = branch_clk_handoff,
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index 09c16c7..83940cf 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -323,6 +323,7 @@
CLK_LOOKUP("cam_clk", cam_m_clk.c, "0-0010"),
CLK_LOOKUP("cam_clk", cam_m_clk.c, "0-0078"),
CLK_LOOKUP("cam_clk", cam_m_clk.c, "0-006c"),
+ CLK_LOOKUP("cam_clk", cam_m_clk.c, "0-000d"),
CLK_LOOKUP("csi_clk", csi0_clk.c, "msm_camera_ov9726.0"),
CLK_LOOKUP("csi_pclk", csi0_p_clk.c, "msm_camera_ov9726.0"),
CLK_LOOKUP("csi_vfe_clk", csi0_vfe_clk.c, "msm_camera_ov9726.0"),
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index ae87bb7..ab57cf8 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -18,13 +18,89 @@
#include "clock.h"
#include "clock-rpm.h"
+#define __clk_rpmrs_set_rate(r, value, ctx, noirq) \
+ ((r)->rpmrs_data->set_rate_fn((r), (value), (ctx), (noirq)))
+
+#define clk_rpmrs_set_rate_sleep(r, value) \
+ __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_sleep_id, 0)
+
+#define clk_rpmrs_set_rate_sleep_noirq(r, value) \
+ __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_sleep_id, 1)
+
+#define clk_rpmrs_set_rate_active(r, value) \
+ __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_active_id, 0)
+
+#define clk_rpmrs_set_rate_active_noirq(r, value) \
+ __clk_rpmrs_set_rate((r), (value), (r)->rpmrs_data->ctx_active_id, 1)
+
+static int clk_rpmrs_set_rate(struct rpm_clk *r, uint32_t value,
+ uint32_t context, int noirq)
+{
+ struct msm_rpm_iv_pair iv = {
+ .id = r->rpm_clk_id,
+ .value = value,
+ };
+ if (noirq)
+ return msm_rpmrs_set_noirq(context, &iv, 1);
+ else
+ return msm_rpmrs_set(context, &iv, 1);
+}
+
+static int clk_rpmrs_get_rate(struct rpm_clk *r)
+{
+ int rc;
+ struct msm_rpm_iv_pair iv = { .id = r->rpm_status_id, };
+ rc = msm_rpm_get_status(&iv, 1);
+ return (rc < 0) ? rc : iv.value * 1000;
+}
+
+#define RPM_SMD_KEY_CLOCK_SET_RATE 0x007A484B
+
+static int clk_rpmrs_set_rate_smd(struct rpm_clk *r, uint32_t value,
+ uint32_t context, int noirq)
+{
+ struct msm_rpm_kvp kvp = {
+ .key = RPM_SMD_KEY_CLOCK_SET_RATE,
+ .data = (void *)&value,
+ .length = sizeof(value),
+ };
+
+ if (noirq)
+ return msm_rpm_send_message_noirq(context,
+ r->rpm_res_type, r->rpm_clk_id, &kvp, 1);
+ else
+ return msm_rpm_send_message(context, r->rpm_res_type,
+ r->rpm_clk_id, &kvp, 1);
+}
+
+struct clk_rpmrs_data {
+ int (*set_rate_fn)(struct rpm_clk *r, uint32_t value,
+ uint32_t context, int noirq);
+ int (*get_rate_fn)(struct rpm_clk *r);
+ int ctx_active_id;
+ int ctx_sleep_id;
+};
+
+struct clk_rpmrs_data clk_rpmrs_data = {
+ .set_rate_fn = clk_rpmrs_set_rate,
+ .get_rate_fn = clk_rpmrs_get_rate,
+ .ctx_active_id = MSM_RPM_CTX_SET_0,
+ .ctx_sleep_id = MSM_RPM_CTX_SET_SLEEP,
+};
+
+struct clk_rpmrs_data clk_rpmrs_data_smd = {
+ .set_rate_fn = clk_rpmrs_set_rate_smd,
+ .ctx_active_id = MSM_RPM_CTX_ACTIVE_SET,
+ .ctx_sleep_id = MSM_RPM_CTX_SLEEP_SET,
+};
+
static DEFINE_SPINLOCK(rpm_clock_lock);
static int rpm_clk_enable(struct clk *clk)
{
unsigned long flags;
struct rpm_clk *r = to_rpm_clk(clk);
- struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id };
+ uint32_t value;
int rc = 0;
unsigned long this_khz, this_sleep_khz;
unsigned long peer_khz = 0, peer_sleep_khz = 0;
@@ -45,21 +121,23 @@
peer_sleep_khz = peer->last_set_sleep_khz;
}
- iv.value = max(this_khz, peer_khz);
+ value = max(this_khz, peer_khz);
if (r->branch)
- iv.value = !!iv.value;
+ value = !!value;
- rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+ rc = clk_rpmrs_set_rate_active_noirq(r, value);
if (rc)
goto out;
- iv.value = max(this_sleep_khz, peer_sleep_khz);
+ value = max(this_sleep_khz, peer_sleep_khz);
if (r->branch)
- iv.value = !!iv.value;
- rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
+ value = !!value;
+
+ rc = clk_rpmrs_set_rate_sleep_noirq(r, value);
if (rc) {
- iv.value = peer_khz;
- msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+ /* Undo the active set vote and restore it to peer_khz */
+ value = peer_khz;
+ rc = clk_rpmrs_set_rate_active_noirq(r, value);
}
out:
@@ -79,7 +157,7 @@
spin_lock_irqsave(&rpm_clock_lock, flags);
if (r->last_set_khz) {
- struct msm_rpm_iv_pair iv = { .id = r->rpm_clk_id };
+ uint32_t value;
struct rpm_clk *peer = r->peer;
unsigned long peer_khz = 0, peer_sleep_khz = 0;
int rc;
@@ -90,13 +168,13 @@
peer_sleep_khz = peer->last_set_sleep_khz;
}
- iv.value = r->branch ? !!peer_khz : peer_khz;
- rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+ value = r->branch ? !!peer_khz : peer_khz;
+ rc = clk_rpmrs_set_rate_active_noirq(r, value);
if (rc)
goto out;
- iv.value = r->branch ? !!peer_sleep_khz : peer_sleep_khz;
- rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
+ value = r->branch ? !!peer_sleep_khz : peer_sleep_khz;
+ rc = clk_rpmrs_set_rate_sleep_noirq(r, value);
}
r->enabled = false;
out:
@@ -116,10 +194,6 @@
spin_lock_irqsave(&rpm_clock_lock, flags);
- /* Ignore duplicate requests. */
- if (r->last_set_khz == this_khz)
- goto out;
-
/* Active-only clocks don't care what the rate is during sleep. So,
* they vote for zero. */
if (r->active_only)
@@ -128,25 +202,23 @@
this_sleep_khz = this_khz;
if (r->enabled) {
- struct msm_rpm_iv_pair iv;
+ uint32_t value;
struct rpm_clk *peer = r->peer;
unsigned long peer_khz = 0, peer_sleep_khz = 0;
- iv.id = r->rpm_clk_id;
-
/* Take peer clock's rate into account only if it's enabled. */
if (peer->enabled) {
peer_khz = peer->last_set_khz;
peer_sleep_khz = peer->last_set_sleep_khz;
}
- iv.value = max(this_khz, peer_khz);
- rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_0, &iv, 1);
+ value = max(this_khz, peer_khz);
+ rc = clk_rpmrs_set_rate_active_noirq(r, value);
if (rc)
goto out;
- iv.value = max(this_sleep_khz, peer_sleep_khz);
- rc = msm_rpmrs_set_noirq(MSM_RPM_CTX_SET_SLEEP, &iv, 1);
+ value = max(this_sleep_khz, peer_sleep_khz);
+ rc = clk_rpmrs_set_rate_sleep_noirq(r, value);
}
if (!rc) {
r->last_set_khz = this_khz;
@@ -162,13 +234,10 @@
static unsigned long rpm_clk_get_rate(struct clk *clk)
{
struct rpm_clk *r = to_rpm_clk(clk);
- struct msm_rpm_iv_pair iv = { r->rpm_status_id };
- int rc;
-
- rc = msm_rpm_get_status(&iv, 1);
- if (rc < 0)
- return rc;
- return iv.value * 1000;
+ if (r->rpmrs_data->get_rate_fn)
+ return r->rpmrs_data->get_rate_fn(r);
+ else
+ return clk->rate;
}
static int rpm_clk_is_enabled(struct clk *clk)
@@ -187,6 +256,29 @@
return false;
}
+static enum handoff rpm_clk_handoff(struct clk *clk)
+{
+ struct rpm_clk *r = to_rpm_clk(clk);
+ struct msm_rpm_iv_pair iv = { r->rpm_status_id };
+ int rc;
+
+ /*
+ * Querying an RPM clock's status will return 0 unless the clock's
+ * rate has previously been set through the RPM. When handing off,
+ * assume these clocks are enabled (unless the RPM call fails) so
+ * child clocks of these RPM clocks can still be handed off.
+ */
+ rc = msm_rpm_get_status(&iv, 1);
+ if (rc < 0)
+ return HANDOFF_DISABLED_CLK;
+
+ r->last_set_khz = iv.value;
+ r->last_set_sleep_khz = iv.value;
+ clk->rate = iv.value * 1000;
+
+ return HANDOFF_ENABLED_CLK;
+}
+
struct clk_ops clk_ops_rpm = {
.enable = rpm_clk_enable,
.disable = rpm_clk_disable,
@@ -195,10 +287,12 @@
.is_enabled = rpm_clk_is_enabled,
.round_rate = rpm_clk_round_rate,
.is_local = rpm_clk_is_local,
+ .handoff = rpm_clk_handoff,
};
struct clk_ops clk_ops_rpm_branch = {
.enable = rpm_clk_enable,
.disable = rpm_clk_disable,
.is_local = rpm_clk_is_local,
+ .handoff = rpm_clk_handoff,
};
diff --git a/arch/arm/mach-msm/clock-rpm.h b/arch/arm/mach-msm/clock-rpm.h
index b0d5693..b2358bc 100644
--- a/arch/arm/mach-msm/clock-rpm.h
+++ b/arch/arm/mach-msm/clock-rpm.h
@@ -15,12 +15,15 @@
#define __ARCH_ARM_MACH_MSM_CLOCK_RPM_H
#include <mach/rpm.h>
+#include <mach/rpm-smd.h>
struct clk_ops;
+struct clk_rpmrs_data;
extern struct clk_ops clk_ops_rpm;
extern struct clk_ops clk_ops_rpm_branch;
struct rpm_clk {
+ const int rpm_res_type;
const int rpm_clk_id;
const int rpm_status_id;
const bool active_only;
@@ -29,6 +32,7 @@
unsigned last_set_sleep_khz;
bool enabled;
bool branch; /* true: RPM only accepts 1 for ON and 0 for OFF */
+ struct clk_rpmrs_data *rpmrs_data;
struct rpm_clk *peer;
struct clk c;
@@ -39,12 +43,17 @@
return container_of(clk, struct rpm_clk, c);
}
-#define DEFINE_CLK_RPM(name, active, r_id, dep) \
+extern struct clk_rpmrs_data clk_rpmrs_data;
+extern struct clk_rpmrs_data clk_rpmrs_data_smd;
+
+#define __DEFINE_CLK_RPM(name, active, type, r_id, stat_id, dep, rpmrsdata) \
static struct rpm_clk active; \
static struct rpm_clk name = { \
- .rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
- .rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
.peer = &active, \
+ .rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm, \
.flags = CLKFLAG_SKIP_AUTO_OFF, \
@@ -54,10 +63,12 @@
}, \
}; \
static struct rpm_clk active = { \
- .rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
- .rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
.peer = &name, \
.active_only = true, \
+ .rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm, \
.flags = CLKFLAG_SKIP_AUTO_OFF, \
@@ -67,15 +78,18 @@
}, \
};
-#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
+#define __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, stat_id, r, \
+ rpmrsdata) \
static struct rpm_clk active; \
static struct rpm_clk name = { \
- .rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
- .rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
.peer = &active, \
.last_set_khz = ((r) / 1000), \
.last_set_sleep_khz = ((r) / 1000), \
.branch = true, \
+ .rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm_branch, \
.flags = CLKFLAG_SKIP_AUTO_OFF, \
@@ -86,12 +100,14 @@
}, \
}; \
static struct rpm_clk active = { \
- .rpm_clk_id = MSM_RPM_ID_##r_id##_CLK, \
- .rpm_status_id = MSM_RPM_STATUS_ID_##r_id##_CLK, \
+ .rpm_res_type = (type), \
+ .rpm_clk_id = (r_id), \
+ .rpm_status_id = (stat_id), \
.peer = &name, \
.last_set_khz = ((r) / 1000), \
.active_only = true, \
.branch = true, \
+ .rpmrs_data = (rpmrsdata),\
.c = { \
.ops = &clk_ops_rpm_branch, \
.flags = CLKFLAG_SKIP_AUTO_OFF, \
@@ -102,4 +118,19 @@
}, \
};
+#define DEFINE_CLK_RPM(name, active, r_id, dep) \
+ __DEFINE_CLK_RPM(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
+ MSM_RPM_STATUS_ID_##r_id##_CLK, dep, &clk_rpmrs_data)
+
+#define DEFINE_CLK_RPM_BRANCH(name, active, r_id, r) \
+ __DEFINE_CLK_RPM_BRANCH(name, active, 0, MSM_RPM_ID_##r_id##_CLK, \
+ MSM_RPM_STATUS_ID_##r_id##_CLK, r, &clk_rpmrs_data)
+
+#define DEFINE_CLK_RPM_SMD(name, active, type, r_id, dep) \
+ __DEFINE_CLK_RPM(name, active, type, r_id, 0, dep, &clk_rpmrs_data_smd)
+
+#define DEFINE_CLK_RPM_SMD_BRANCH(name, active, type, r_id, dep) \
+ __DEFINE_CLK_RPM_BRANCH(name, active, type, r_id, 0, dep, \
+ &clk_rpmrs_data_smd)
+
#endif
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index fb5b580..8bf98fa 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -21,10 +21,17 @@
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/list.h>
#include <trace/events/power.h>
#include "clock.h"
+struct handoff_clk {
+ struct list_head list;
+ struct clk *clk;
+};
+static LIST_HEAD(handoff_list);
+
/* Find the voltage level required for a given rate. */
static int find_vdd_level(struct clk *clk, unsigned long rate)
{
@@ -203,18 +210,8 @@
ret = clk->ops->enable(clk);
if (ret)
goto err_enable_clock;
- } else if (clk->flags & CLKFLAG_HANDOFF_RATE) {
- /*
- * The clock was already enabled by handoff code so there is no
- * need to enable it again here. Clearing the handoff flag will
- * prevent the lateinit handoff code from disabling the clock if
- * a client driver still has it enabled.
- */
- clk->flags &= ~CLKFLAG_HANDOFF_RATE;
- goto out;
}
clk->count++;
-out:
spin_unlock_irqrestore(&clk->lock, flags);
return 0;
@@ -320,7 +317,7 @@
int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long start_rate, flags;
- int rc;
+ int rc = 0;
if (IS_ERR_OR_NULL(clk))
return -EINVAL;
@@ -329,6 +326,11 @@
return -ENOSYS;
spin_lock_irqsave(&clk->lock, flags);
+
+ /* Return early if the rate isn't going to change */
+ if (clk->rate == rate)
+ goto out;
+
trace_clock_set_rate(clk->dbg_name, rate, smp_processor_id());
if (clk->count) {
start_rate = clk->rate;
@@ -347,7 +349,7 @@
if (!rc)
clk->rate = rate;
-
+out:
spin_unlock_irqrestore(&clk->lock, flags);
return rc;
@@ -417,6 +419,58 @@
static struct clock_init_data __initdata *clk_init_data;
+static enum handoff __init __handoff_clk(struct clk *clk)
+{
+ enum handoff ret;
+ struct handoff_clk *h;
+ unsigned long rate;
+ int err = 0;
+
+ /*
+ * Tree roots don't have parents, but need to be handed off. So,
+ * terminate recursion by returning "enabled". Also return "enabled"
+ * for clocks with non-zero enable counts since they must have already
+ * been handed off.
+ */
+ if (clk == NULL || clk->count)
+ return HANDOFF_ENABLED_CLK;
+
+ /* Clocks without handoff functions are assumed to be disabled. */
+ if (!clk->ops->handoff || (clk->flags & CLKFLAG_SKIP_HANDOFF))
+ return HANDOFF_DISABLED_CLK;
+
+ /*
+ * Handoff functions for children must be called before their parents'
+ * so that the correct parent is returned by the clk_get_parent() below.
+ */
+ ret = clk->ops->handoff(clk);
+ if (ret == HANDOFF_ENABLED_CLK) {
+ ret = __handoff_clk(clk_get_parent(clk));
+ if (ret == HANDOFF_ENABLED_CLK) {
+ h = kmalloc(sizeof(*h), GFP_KERNEL);
+ if (!h) {
+ err = -ENOMEM;
+ goto out;
+ }
+ err = clk_prepare_enable(clk);
+ if (err)
+ goto out;
+ rate = clk_get_rate(clk);
+ if (rate)
+ pr_debug("%s rate=%lu\n", clk->dbg_name, rate);
+ h->clk = clk;
+ list_add_tail(&h->list, &handoff_list);
+ }
+ }
+out:
+ if (err) {
+ pr_err("%s handoff failed (%d)\n", clk->dbg_name, err);
+ kfree(h);
+ ret = HANDOFF_DISABLED_CLK;
+ }
+ return ret;
+}
+
void __init msm_clock_init(struct clock_init_data *data)
{
unsigned n;
@@ -443,14 +497,8 @@
* Detect and preserve initial clock state until clock_late_init() or
* a driver explicitly changes it, whichever is first.
*/
- for (n = 0; n < num_clocks; n++) {
- clk = clock_tbl[n].clk;
- if (clk->ops->handoff && !(clk->flags & CLKFLAG_HANDOFF_RATE) &&
- (clk->ops->handoff(clk) == HANDOFF_ENABLED_CLK)) {
- clk->flags |= CLKFLAG_HANDOFF_RATE;
- clk_prepare_enable(clk);
- }
- }
+ for (n = 0; n < num_clocks; n++)
+ __handoff_clk(clock_tbl[n].clk);
clkdev_add_table(clock_tbl, num_clocks);
@@ -466,13 +514,13 @@
static int __init clock_late_init(void)
{
unsigned n, count = 0;
+ struct handoff_clk *h, *h_temp;
unsigned long flags;
int ret = 0;
clock_debug_init(clk_init_data);
for (n = 0; n < clk_init_data->size; n++) {
struct clk *clk = clk_init_data->table[n].clk;
- bool handoff = false;
clock_debug_add(clk);
spin_lock_irqsave(&clk->lock, flags);
@@ -482,19 +530,16 @@
clk->ops->auto_off(clk);
}
}
- if (clk->flags & CLKFLAG_HANDOFF_RATE) {
- clk->flags &= ~CLKFLAG_HANDOFF_RATE;
- handoff = true;
- }
spin_unlock_irqrestore(&clk->lock, flags);
- /*
- * Calling this outside the lock is safe since
- * it doesn't need to be atomic with the flag change.
- */
- if (handoff)
- clk_disable_unprepare(clk);
}
pr_info("clock_late_init() disabled %d unused clocks\n", count);
+
+ list_for_each_entry_safe(h, h_temp, &handoff_list, list) {
+ clk_disable_unprepare(h->clk);
+ list_del(&h->list);
+ kfree(h);
+ }
+
if (clk_init_data->late_init)
ret = clk_init_data->late_init();
return ret;
diff --git a/arch/arm/mach-msm/clock.h b/arch/arm/mach-msm/clock.h
index 1be05ad..03d5790 100644
--- a/arch/arm/mach-msm/clock.h
+++ b/arch/arm/mach-msm/clock.h
@@ -29,10 +29,10 @@
#define CLKFLAG_NOINVERT 0x00000002
#define CLKFLAG_NONEST 0x00000004
#define CLKFLAG_NORESET 0x00000008
-#define CLKFLAG_HANDOFF_RATE 0x00000010
#define CLKFLAG_HWCG 0x00000020
#define CLKFLAG_RETAIN 0x00000040
#define CLKFLAG_NORETAIN 0x00000080
+#define CLKFLAG_SKIP_HANDOFF 0x00000100
#define CLKFLAG_SKIP_AUTO_OFF 0x00000200
#define CLKFLAG_MIN 0x00000400
#define CLKFLAG_MAX 0x00000800
diff --git a/arch/arm/mach-msm/cpufreq.c b/arch/arm/mach-msm/cpufreq.c
index 63534a4..0fa1e2d 100644
--- a/arch/arm/mach-msm/cpufreq.c
+++ b/arch/arm/mach-msm/cpufreq.c
@@ -19,6 +19,7 @@
#include <linux/earlysuspend.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <linux/cpufreq.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
@@ -27,6 +28,7 @@
#include <linux/sched.h>
#include <linux/suspend.h>
#include <mach/socinfo.h>
+#include <mach/cpufreq.h>
#include "acpuclock.h"
@@ -50,10 +52,33 @@
static DEFINE_PER_CPU(struct cpufreq_suspend_t, cpufreq_suspend);
+struct cpu_freq {
+ uint32_t max;
+ uint32_t min;
+ uint32_t allowed_max;
+ uint32_t allowed_min;
+ uint32_t limits_init;
+};
+
+static DEFINE_PER_CPU(struct cpu_freq, cpu_freq_info);
+
static int set_cpu_freq(struct cpufreq_policy *policy, unsigned int new_freq)
{
int ret = 0;
struct cpufreq_freqs freqs;
+ struct cpu_freq *limit = &per_cpu(cpu_freq_info, policy->cpu);
+
+ if (limit->limits_init) {
+ if (new_freq > limit->allowed_max) {
+ new_freq = limit->allowed_max;
+ pr_debug("max: limiting freq to %d\n", new_freq);
+ }
+
+ if (new_freq < limit->allowed_min) {
+ new_freq = limit->allowed_min;
+ pr_debug("min: limiting freq to %d\n", new_freq);
+ }
+ }
freqs.old = policy->cur;
freqs.new = new_freq;
@@ -158,6 +183,72 @@
return 0;
}
+static unsigned int msm_cpufreq_get_freq(unsigned int cpu)
+{
+ return acpuclk_get_rate(cpu);
+}
+
+static inline int msm_cpufreq_limits_init(void)
+{
+ int cpu = 0;
+ int i = 0;
+ struct cpufreq_frequency_table *table = NULL;
+ uint32_t min = (uint32_t) -1;
+ uint32_t max = 0;
+ struct cpu_freq *limit = NULL;
+
+ for_each_possible_cpu(cpu) {
+ limit = &per_cpu(cpu_freq_info, cpu);
+ table = cpufreq_frequency_get_table(cpu);
+ if (table == NULL) {
+ pr_err("%s: error reading cpufreq table for cpu %d\n",
+ __func__, cpu);
+ continue;
+ }
+ for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
+ if (table[i].frequency > max)
+ max = table[i].frequency;
+ if (table[i].frequency < min)
+ min = table[i].frequency;
+ }
+ limit->allowed_min = min;
+ limit->allowed_max = max;
+ limit->min = min;
+ limit->max = max;
+ limit->limits_init = 1;
+ }
+
+ return 0;
+}
+
+int msm_cpufreq_set_freq_limits(uint32_t cpu, uint32_t min, uint32_t max)
+{
+ struct cpu_freq *limit = &per_cpu(cpu_freq_info, cpu);
+
+ if (!limit->limits_init)
+ msm_cpufreq_limits_init();
+
+ if ((min != MSM_CPUFREQ_NO_LIMIT) &&
+ min >= limit->min && min <= limit->max)
+ limit->allowed_min = min;
+ else
+ limit->allowed_min = limit->min;
+
+
+ if ((max != MSM_CPUFREQ_NO_LIMIT) &&
+ max <= limit->max && max >= limit->min)
+ limit->allowed_max = max;
+ else
+ limit->allowed_max = limit->max;
+
+ pr_debug("%s: Limiting cpu %d min = %d, max = %d\n",
+ __func__, cpu,
+ limit->allowed_min, limit->allowed_max);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_cpufreq_set_freq_limits);
+
static int __cpuinit msm_cpufreq_init(struct cpufreq_policy *policy)
{
int cur_freq;
@@ -274,6 +365,7 @@
.init = msm_cpufreq_init,
.verify = msm_cpufreq_verify,
.target = msm_cpufreq_target,
+ .get = msm_cpufreq_get_freq,
.name = "msm",
.attr = msm_freq_attr,
};
@@ -300,4 +392,3 @@
}
late_initcall(msm_cpufreq_register);
-
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index 1382632..66ce30e 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -608,6 +608,11 @@
.id = 0x4003,
};
+struct platform_device apq_cpudai_slimbus_2_rx = {
+ .name = "msm-dai-q6",
+ .id = 0x4004,
+};
+
struct platform_device apq_cpudai_slimbus_2_tx = {
.name = "msm-dai-q6",
.id = 0x4005,
@@ -618,6 +623,11 @@
.id = 0x4006,
};
+struct platform_device apq_cpudai_slimbus_3_tx = {
+ .name = "msm-dai-q6",
+ .id = 0x4007,
+};
+
static struct resource resources_ssbi_pmic1[] = {
{
.start = MSM_PMIC1_SSBI_CMD_PHYS,
@@ -1051,6 +1061,59 @@
},
};
+static struct msm_bus_vectors vidc_venc_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
+static struct msm_bus_vectors vidc_vdec_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_VIDEO_DEC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
+
static struct msm_bus_paths vidc_bus_client_config[] = {
{
ARRAY_SIZE(vidc_init_vectors),
@@ -1080,6 +1143,14 @@
ARRAY_SIZE(vidc_vdec_1080p_vectors),
vidc_vdec_1080p_vectors,
},
+ {
+ ARRAY_SIZE(vidc_venc_1080p_turbo_vectors),
+ vidc_venc_1080p_turbo_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_vdec_1080p_turbo_vectors),
+ vidc_vdec_1080p_turbo_vectors,
+ },
};
static struct msm_bus_scale_pdata vidc_bus_client_data = {
@@ -1663,6 +1734,21 @@
.bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
};
+static struct fs_driver_data mdp_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { .name = "vsync_clk" },
+ { .name = "lut_clk" },
+ { .name = "tv_src_clk" },
+ { .name = "tv_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_MDP_PORT0,
+ .bus_port1 = MSM_BUS_MASTER_MDP_PORT1,
+};
+
static struct fs_driver_data rot_fs_data = {
.clks = (struct fs_clk_data[]){
{ .name = "core_clk" },
@@ -1715,6 +1801,7 @@
};
struct platform_device *apq8064_footswitch[] __initdata = {
+ FS_8X60(FS_MDP, "vdd", "mdp.0", &mdp_fs_data),
FS_8X60(FS_ROT, "vdd", "msm_rotator.0", &rot_fs_data),
FS_8X60(FS_IJPEG, "vdd", "msm_gemini.0", &ijpeg_fs_data),
FS_8X60(FS_VFE, "fs_vfe", NULL, &vfe_fs_data),
@@ -2018,6 +2105,16 @@
/* Sensors DSPS platform data */
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x4000
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x100000
+#define PPSS_SMEM_BASE 0x80000000
+#define PPSS_SMEM_SIZE 0x200000
#define PPSS_REG_PHYS_BASE 0x12080000
static struct dsps_clk_info dsps_clks[] = {};
@@ -2036,6 +2133,16 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
+ .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+ .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+ .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+ .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+ .pipe_start = PPSS_DSPS_PIPE_BASE,
+ .pipe_size = PPSS_DSPS_PIPE_SIZE,
+ .ddr_start = PPSS_DSPS_DDR_BASE,
+ .ddr_size = PPSS_DSPS_DDR_SIZE,
+ .smem_start = PPSS_SMEM_BASE,
+ .smem_size = PPSS_SMEM_SIZE,
.signature = DSPS_SIGNATURE,
};
@@ -2270,13 +2377,21 @@
},
};
-
static struct msm_bus_vectors vcap_480_vectors[] = {
{
.src = MSM_BUS_MASTER_VIDEO_CAP,
.dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 1280 * 720 * 3 * 60,
- .ib = 1280 * 720 * 3 * 60 * 1.5,
+ .ab = 480 * 720 * 3 * 60,
+ .ib = 480 * 720 * 3 * 60 * 1.5,
+ },
+};
+
+static struct msm_bus_vectors vcap_576_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VIDEO_CAP,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 576 * 720 * 3 * 60,
+ .ib = 576 * 720 * 3 * 60 * 1.5,
},
};
@@ -2308,6 +2423,10 @@
vcap_480_vectors,
},
{
+ ARRAY_SIZE(vcap_576_vectors),
+ vcap_576_vectors,
+ },
+ {
ARRAY_SIZE(vcap_720_vectors),
vcap_720_vectors,
},
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index 2c4687f..c480bba 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -127,7 +127,6 @@
MSM_RPM_MAP(8930, CXO_BUFFERS, CXO_BUFFERS, 1),
MSM_RPM_MAP(8930, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
MSM_RPM_MAP(8930, HDMI_SWITCH, HDMI_SWITCH, 1),
- MSM_RPM_MAP(8930, DDR_DMM_0, DDR_DMM, 2),
MSM_RPM_MAP(8930, QDSS_CLK, QDSS_CLK, 1),
MSM_RPM_MAP(8930, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
@@ -232,8 +231,6 @@
MSM_RPM_STATUS_ID_MAP(8930, CXO_BUFFERS),
MSM_RPM_STATUS_ID_MAP(8930, USB_OTG_SWITCH),
MSM_RPM_STATUS_ID_MAP(8930, HDMI_SWITCH),
- MSM_RPM_STATUS_ID_MAP(8930, DDR_DMM_0),
- MSM_RPM_STATUS_ID_MAP(8930, DDR_DMM_1),
MSM_RPM_STATUS_ID_MAP(8930, QDSS_CLK),
MSM_RPM_STATUS_ID_MAP(8930, VOLTAGE_CORNER),
},
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index be364e7..550a283 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -202,6 +202,11 @@
},
};
+struct platform_device msm8960_device_acpuclk = {
+ .name = "acpuclk-8960",
+ .id = -1,
+};
+
#define SHARED_IMEM_TZ_BASE 0x2a03f720
static struct resource tzlog_resources[] = {
{
@@ -577,6 +582,58 @@
.ib = 10000000,
},
};
+static struct msm_bus_vectors vidc_venc_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
+static struct msm_bus_vectors vidc_vdec_1080p_turbo_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 222298112,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_HD_CODEC_PORT1,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 330301440,
+ .ib = 3522000000U,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 700000000,
+ },
+ {
+ .src = MSM_BUS_MASTER_AMPSS_M0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2500000,
+ .ib = 10000000,
+ },
+};
static struct msm_bus_paths vidc_bus_client_config[] = {
{
@@ -607,6 +664,14 @@
ARRAY_SIZE(vidc_vdec_1080p_vectors),
vidc_vdec_1080p_vectors,
},
+ {
+ ARRAY_SIZE(vidc_venc_1080p_turbo_vectors),
+ vidc_vdec_1080p_turbo_vectors,
+ },
+ {
+ ARRAY_SIZE(vidc_vdec_1080p_turbo_vectors),
+ vidc_vdec_1080p_turbo_vectors,
+ },
};
static struct msm_bus_scale_pdata vidc_bus_client_data = {
@@ -1841,6 +1906,11 @@
.id = 0x4001,
};
+struct platform_device msm8960_cpudai_slimbus_2_rx = {
+ .name = "msm-dai-q6",
+ .id = 0x4004,
+};
+
struct platform_device msm8960_cpudai_slimbus_2_tx = {
.name = "msm-dai-q6",
.id = 0x4005,
@@ -2939,6 +3009,27 @@
};
#endif
+#ifdef CONFIG_MSM_MERCURY
+static struct resource msm_mercury_resources[] = {
+ {
+ .start = 0x05000000,
+ .end = 0x05000000 + SZ_1M - 1,
+ .name = "mercury_resource_base",
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = JPEGD_IRQ,
+ .end = JPEGD_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+struct platform_device msm8960_mercury_device = {
+ .name = "msm_mercury",
+ .resource = msm_mercury_resources,
+ .num_resources = ARRAY_SIZE(msm_mercury_resources),
+};
+#endif
+
struct msm_rpm_platform_data msm8960_rpm_data __initdata = {
.reg_base_addrs = {
[MSM_RPM_PAGE_STATUS] = MSM_RPM_BASE,
@@ -3246,6 +3337,16 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x4000
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x100000
+#define PPSS_SMEM_BASE 0x80000000
+#define PPSS_SMEM_SIZE 0x200000
#define PPSS_REG_PHYS_BASE 0x12080000
static struct dsps_clk_info dsps_clks[] = {};
@@ -3264,6 +3365,16 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.dsps_pwr_ctl_en = 1,
+ .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+ .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+ .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+ .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+ .pipe_start = PPSS_DSPS_PIPE_BASE,
+ .pipe_size = PPSS_DSPS_PIPE_SIZE,
+ .ddr_start = PPSS_DSPS_DDR_BASE,
+ .ddr_size = PPSS_DSPS_DDR_SIZE,
+ .smem_start = PPSS_SMEM_BASE,
+ .smem_size = PPSS_SMEM_SIZE,
.signature = DSPS_SIGNATURE,
};
@@ -3274,7 +3385,6 @@
.name = "ppss_reg",
.flags = IORESOURCE_MEM,
},
-
{
.start = PPSS_WDOG_TIMER_IRQ,
.end = PPSS_WDOG_TIMER_IRQ,
@@ -3383,6 +3493,44 @@
#endif
+static struct resource msm_ebi1_ch0_erp_resources[] = {
+ {
+ .start = HSDDRX_EBI1CH0_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = 0x00A40000,
+ .end = 0x00A40000 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8960_device_ebi1_ch0_erp = {
+ .name = "msm_ebi_erp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_ebi1_ch0_erp_resources),
+ .resource = msm_ebi1_ch0_erp_resources,
+};
+
+static struct resource msm_ebi1_ch1_erp_resources[] = {
+ {
+ .start = HSDDRX_EBI1CH1_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = 0x00D40000,
+ .end = 0x00D40000 + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device msm8960_device_ebi1_ch1_erp = {
+ .name = "msm_ebi_erp",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(msm_ebi1_ch1_erp_resources),
+ .resource = msm_ebi1_ch1_erp_resources,
+};
+
static int msm8960_LPM_latency = 1000; /* >100 usec for WFI */
struct platform_device msm8960_cpu_idle_device = {
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 85d00eb..06d8653 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -107,6 +107,11 @@
},
};
+struct platform_device msm9615_device_acpuclk = {
+ .name = "acpuclk-9615",
+ .id = -1,
+};
+
#define MSM_USB_BAM_BASE 0x12502000
#define MSM_USB_BAM_SIZE SZ_16K
#define MSM_HSIC_BAM_BASE 0x12542000
@@ -492,6 +497,44 @@
},
};
+struct msm_dai_auxpcm_pdata sec_auxpcm_pdata = {
+ .clk = "sec_pcm_clk",
+ .mode_8k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 2048000,
+ },
+ .mode_16k = {
+ .mode = AFE_PCM_CFG_MODE_PCM,
+ .sync = AFE_PCM_CFG_SYNC_INT,
+ .frame = AFE_PCM_CFG_FRM_256BPF,
+ .quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD,
+ .slot = 0,
+ .data = AFE_PCM_CFG_CDATAOE_MASTER,
+ .pcm_clk_rate = 4096000,
+ }
+};
+
+struct platform_device msm_cpudai_sec_auxpcm_rx = {
+ .name = "msm-dai-q6",
+ .id = 12,
+ .dev = {
+ .platform_data = &sec_auxpcm_pdata,
+ },
+};
+
+struct platform_device msm_cpudai_sec_auxpcm_tx = {
+ .name = "msm-dai-q6",
+ .id = 13,
+ .dev = {
+ .platform_data = &sec_auxpcm_pdata,
+ },
+};
+
struct platform_device msm_cpu_fe = {
.name = "msm-dai-fe",
.id = -1,
@@ -997,6 +1040,7 @@
MSM_RPM_MAP(9615, CXO_BUFFERS, CXO_BUFFERS, 1),
MSM_RPM_MAP(9615, USB_OTG_SWITCH, USB_OTG_SWITCH, 1),
MSM_RPM_MAP(9615, HDMI_SWITCH, HDMI_SWITCH, 1),
+ MSM_RPM_MAP(9615, VOLTAGE_CORNER, VOLTAGE_CORNER, 1),
},
.target_status = {
MSM_RPM_STATUS_ID_MAP(9615, VERSION_MAJOR),
@@ -1062,6 +1106,7 @@
MSM_RPM_STATUS_ID_MAP(9615, CXO_BUFFERS),
MSM_RPM_STATUS_ID_MAP(9615, USB_OTG_SWITCH),
MSM_RPM_STATUS_ID_MAP(9615, HDMI_SWITCH),
+ MSM_RPM_STATUS_ID_MAP(9615, VOLTAGE_CORNER),
},
.target_ctrl_id = {
MSM_RPM_CTRL_MAP(9615, VERSION_MAJOR),
@@ -1242,17 +1287,17 @@
[MSM_RPMRS_VDD_MEM_MAX] = 1150000,
},
.vdd_dig_levels = {
- [MSM_RPMRS_VDD_DIG_RET_LOW] = 500000,
- [MSM_RPMRS_VDD_DIG_RET_HIGH] = 750000,
- [MSM_RPMRS_VDD_DIG_ACTIVE] = 950000,
- [MSM_RPMRS_VDD_DIG_MAX] = 1150000,
+ [MSM_RPMRS_VDD_DIG_RET_LOW] = 0,
+ [MSM_RPMRS_VDD_DIG_RET_HIGH] = 0,
+ [MSM_RPMRS_VDD_DIG_ACTIVE] = 1,
+ [MSM_RPMRS_VDD_DIG_MAX] = 3,
},
.vdd_mask = 0x7FFFFF,
.rpmrs_target_id = {
[MSM_RPMRS_ID_PXO_CLK] = MSM_RPM_ID_CXO_CLK,
[MSM_RPMRS_ID_L2_CACHE_CTL] = MSM_RPM_ID_LAST,
- [MSM_RPMRS_ID_VDD_DIG_0] = MSM_RPM_ID_PM8018_S1_0,
- [MSM_RPMRS_ID_VDD_DIG_1] = MSM_RPM_ID_PM8018_S1_1,
+ [MSM_RPMRS_ID_VDD_DIG_0] = MSM_RPM_ID_VOLTAGE_CORNER,
+ [MSM_RPMRS_ID_VDD_DIG_1] = MSM_RPM_ID_LAST,
[MSM_RPMRS_ID_VDD_MEM_0] = MSM_RPM_ID_PM8018_L9_0,
[MSM_RPMRS_ID_VDD_MEM_1] = MSM_RPM_ID_PM8018_L9_1,
[MSM_RPMRS_ID_RPM_CTL] = MSM_RPM_ID_RPM_CTL,
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index ffd10fa..4619cca 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -27,6 +27,7 @@
#include "devices.h"
#include "footswitch.h"
+#include "acpuclock.h"
#include <asm/mach/flash.h>
@@ -431,6 +432,16 @@
msm_pm_set_irq_extns(&msm7x27_pm_irq_calls);
}
+static struct acpuclk_pdata msm7x27_acpuclk_pdata = {
+ .max_speed_delta_khz = 400000,
+};
+
+struct platform_device msm7x27_device_acpuclk = {
+ .name = "acpuclk-7627",
+ .id = -1,
+ .dev.platform_data = &msm7x27_acpuclk_pdata,
+};
+
#define MSM_SDC1_BASE 0xA0400000
#define MSM_SDC2_BASE 0xA0500000
#define MSM_SDC3_BASE 0xA0600000
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 4654606..b3454cd 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -211,6 +211,37 @@
},
};
+static struct acpuclk_pdata msm7x27a_acpuclk_pdata = {
+ .max_speed_delta_khz = 400000,
+};
+
+struct platform_device msm7x27a_device_acpuclk = {
+ .name = "acpuclk-7627",
+ .id = -1,
+ .dev.platform_data = &msm7x27a_acpuclk_pdata,
+};
+
+static struct acpuclk_pdata msm7x27aa_acpuclk_pdata = {
+ .max_speed_delta_khz = 504000,
+};
+
+struct platform_device msm7x27aa_device_acpuclk = {
+ .name = "acpuclk-7627",
+ .id = -1,
+ .dev.platform_data = &msm7x27aa_acpuclk_pdata,
+};
+
+static struct acpuclk_pdata msm8625_acpuclk_pdata = {
+ /* TODO: Need to update speed delta from H/w Team */
+ .max_speed_delta_khz = 604800,
+};
+
+struct platform_device msm8625_device_acpuclk = {
+ .name = "acpuclk-7627",
+ .id = -1,
+ .dev.platform_data = &msm8625_acpuclk_pdata,
+};
+
struct platform_device msm_device_smd = {
.name = "msm_smd",
.id = -1,
@@ -1445,7 +1476,7 @@
},
};
-static struct platform_device msm8625_mipi_dsi_device = {
+struct platform_device msm8625_mipi_dsi_device = {
.name = "mipi_dsi",
.id = 1,
.num_resources = ARRAY_SIZE(msm8625_mipi_dsi_resources),
@@ -1623,16 +1654,15 @@
msm_clock_init(&msm7x27a_clock_init_data);
if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
- acpuclk_init(&acpuclk_7x27aa_soc_data);
+ platform_device_register(&msm7x27aa_device_acpuclk);
else if (cpu_is_msm8625()) {
if (msm8625_cpu_id() == MSM8625)
- acpuclk_init(&acpuclk_7x27aa_soc_data);
+ platform_device_register(&msm7x27aa_device_acpuclk);
else if (msm8625_cpu_id() == MSM8625A)
- acpuclk_init(&acpuclk_8625_soc_data);
- } else {
- acpuclk_init(&acpuclk_7x27a_soc_data);
- }
-
+ platform_device_register(&msm8625_device_acpuclk);
+ } else {
+ platform_device_register(&msm7x27a_device_acpuclk);
+ }
return 0;
}
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index de70429..ff747e2 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -42,6 +42,11 @@
#include "pm.h"
#include "irq.h"
+struct platform_device msm7x30_device_acpuclk = {
+ .name = "acpuclk-7x30",
+ .id = -1,
+};
+
/* EBI THERMAL DRIVER */
static struct resource msm_ebi0_thermal_resources[] = {
{
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index d622af2..d8bf054 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -163,6 +163,11 @@
},
};
+struct platform_device msm8x60_device_acpuclk = {
+ .name = "acpuclk-8x60",
+ .id = -1,
+};
+
#ifdef CONFIG_MSM_DSPS
#define GSBI12_DEV (&msm_dsps_device.dev)
#else
@@ -1568,6 +1573,16 @@
/* Sensors DSPS platform data */
#ifdef CONFIG_MSM_DSPS
+#define PPSS_DSPS_TCM_CODE_BASE 0x12000000
+#define PPSS_DSPS_TCM_CODE_SIZE 0x28000
+#define PPSS_DSPS_TCM_BUF_BASE 0x12040000
+#define PPSS_DSPS_TCM_BUF_SIZE 0x4000
+#define PPSS_DSPS_PIPE_BASE 0x12800000
+#define PPSS_DSPS_PIPE_SIZE 0x0 /* 8660 V2 does not use PIPE memory */
+#define PPSS_DSPS_DDR_BASE 0x8fe00000
+#define PPSS_DSPS_DDR_SIZE 0x0 /* 8660 V2 does not use DDR memory */
+#define PPSS_SMEM_BASE 0x40000000
+#define PPSS_SMEM_SIZE 0x4000
#define PPSS_REG_PHYS_BASE 0x12080000
#define MHZ (1000*1000)
@@ -1631,6 +1646,16 @@
.regs = dsps_regs,
.regs_num = ARRAY_SIZE(dsps_regs),
.init = dsps_init1,
+ .tcm_code_start = PPSS_DSPS_TCM_CODE_BASE,
+ .tcm_code_size = PPSS_DSPS_TCM_CODE_SIZE,
+ .tcm_buf_start = PPSS_DSPS_TCM_BUF_BASE,
+ .tcm_buf_size = PPSS_DSPS_TCM_BUF_SIZE,
+ .pipe_start = PPSS_DSPS_PIPE_BASE,
+ .pipe_size = PPSS_DSPS_PIPE_SIZE,
+ .ddr_start = PPSS_DSPS_DDR_BASE,
+ .ddr_size = PPSS_DSPS_DDR_SIZE,
+ .smem_start = PPSS_SMEM_BASE,
+ .smem_size = PPSS_SMEM_SIZE,
.signature = DSPS_SIGNATURE,
};
@@ -2266,7 +2291,8 @@
#endif
.disable_dmx = 0,
.disable_fullhd = 0,
- .cont_mode_dpb_count = 8
+ .cont_mode_dpb_count = 8,
+ .disable_turbo = 1,
};
struct platform_device msm_device_vidc = {
diff --git a/arch/arm/mach-msm/devices-qsd8x50.c b/arch/arm/mach-msm/devices-qsd8x50.c
index ee8a2cf..2ecc852 100644
--- a/arch/arm/mach-msm/devices-qsd8x50.c
+++ b/arch/arm/mach-msm/devices-qsd8x50.c
@@ -34,6 +34,11 @@
#include <mach/rpc_hsusb.h>
#include "pm.h"
+struct platform_device msm8x50_device_acpuclk = {
+ .name = "acpuclk-8x50",
+ .id = -1,
+};
+
static struct resource resources_uart1[] = {
{
.start = INT_UART1,
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index f180aa5..ea47727 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -65,6 +65,7 @@
extern struct platform_device msm8960_device_qup_i2c_gsbi12;
extern struct platform_device msm8960_device_qup_spi_gsbi1;
extern struct platform_device msm8960_gemini_device;
+extern struct platform_device msm8960_mercury_device;
extern struct platform_device msm8960_device_i2c_mux_gsbi4;
extern struct platform_device msm8960_device_csiphy0;
extern struct platform_device msm8960_device_csiphy1;
@@ -76,6 +77,8 @@
extern struct platform_device msm8960_device_vfe;
extern struct platform_device msm8960_device_vpe;
extern struct platform_device msm8960_device_cache_erp;
+extern struct platform_device msm8960_device_ebi1_ch0_erp;
+extern struct platform_device msm8960_device_ebi1_ch1_erp;
extern struct platform_device apq8064_device_uart_gsbi1;
extern struct platform_device apq8064_device_uart_gsbi3;
@@ -202,6 +205,7 @@
extern struct platform_device msm_cpudai0;
extern struct platform_device msm_cpudai1;
extern struct platform_device mpq_cpudai_sec_i2s_rx;
+extern struct platform_device msm8960_cpudai_slimbus_2_rx;
extern struct platform_device msm8960_cpudai_slimbus_2_tx;
extern struct platform_device msm_cpudai_hdmi_rx;
extern struct platform_device msm_cpudai_bt_rx;
@@ -210,6 +214,8 @@
extern struct platform_device msm_cpudai_fm_tx;
extern struct platform_device msm_cpudai_auxpcm_rx;
extern struct platform_device msm_cpudai_auxpcm_tx;
+extern struct platform_device msm_cpudai_sec_auxpcm_rx;
+extern struct platform_device msm_cpudai_sec_auxpcm_tx;
extern struct platform_device msm_cpu_fe;
extern struct platform_device msm_stub_codec;
extern struct platform_device msm_voice;
@@ -267,8 +273,10 @@
extern struct platform_device apq_cpudai_stub;
extern struct platform_device apq_cpudai_slimbus_1_rx;
extern struct platform_device apq_cpudai_slimbus_1_tx;
+extern struct platform_device apq_cpudai_slimbus_2_rx;
extern struct platform_device apq_cpudai_slimbus_2_tx;
extern struct platform_device apq_cpudai_slimbus_3_rx;
+extern struct platform_device apq_cpudai_slimbus_3_tx;
extern struct platform_device apq_cpudai_slim_4_rx;
extern struct platform_device apq_cpudai_slim_4_tx;
@@ -294,6 +302,7 @@
extern struct platform_device msm_kgsl_2d1;
extern struct platform_device msm_mipi_dsi1_device;
+extern struct platform_device msm8625_mipi_dsi_device;
extern struct platform_device msm_lvds_device;
extern struct platform_device msm_ebi2_lcdc_device;
@@ -403,3 +412,13 @@
extern struct platform_device mdm_sglte_device;
extern struct platform_device apq_device_tz_log;
+
+extern struct platform_device msm7x27_device_acpuclk;
+extern struct platform_device msm7x27a_device_acpuclk;
+extern struct platform_device msm7x27aa_device_acpuclk;
+extern struct platform_device msm7x30_device_acpuclk;
+extern struct platform_device msm8625_device_acpuclk;
+extern struct platform_device msm8x50_device_acpuclk;
+extern struct platform_device msm8x60_device_acpuclk;
+extern struct platform_device msm8960_device_acpuclk;
+extern struct platform_device msm9615_device_acpuclk;
diff --git a/arch/arm/mach-msm/ebi_erp.c b/arch/arm/mach-msm/ebi_erp.c
new file mode 100644
index 0000000..cd9119d
--- /dev/null
+++ b/arch/arm/mach-msm/ebi_erp.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/cpu.h>
+
+#define MODULE_NAME "msm_ebi_erp"
+
+#define EBI_ERR_ADDR 0x100
+#define SLV_ERR_APACKET_0 0x108
+#define SLV_ERR_APACKET_1 0x10C
+#define SLV_ERR_CNTL 0x114
+
+#define CNTL_ERR_OCCURRED BIT(4)
+#define CNTL_CLEAR_ERR BIT(8)
+#define CNTL_IRQ_EN BIT(12)
+
+#define AMID_MASK 0xFFFF
+#define ERR_AWRITE BIT(0)
+#define ERR_AOOOWR BIT(1)
+#define ERR_AOOORD BIT(2)
+#define ERR_APTORNS BIT(3)
+#define ERR_ALOCK_SHIFT 6
+#define ERR_ALOCK_MASK 0x3
+#define ERR_ATYPE_SHIFT 8
+#define ERR_ATYPE_MASK 0xF
+#define ERR_ABURST BIT(12)
+#define ERR_ASIZE_SHIFT 13
+#define ERR_ASIZE_MASK 0x7
+#define ERR_ATID_SHIFT 16
+#define ERR_ATID_MASK 0xFF
+#define ERR_ALEN_SHIFT 24
+#define ERR_ALEN_MASK 0xF
+
+#define ERR_CODE_DECODE_ERROR BIT(0)
+#define ERR_CODE_MPU_ERROR BIT(1)
+
+struct msm_ebi_erp_data {
+ void __iomem *base;
+ struct device *dev;
+};
+
+static const char *err_lock_types[4] = {
+ "normal",
+ "exclusive",
+ "locked",
+ "barrier",
+};
+
+static const char *err_sizes[8] = {
+ "byte",
+ "half word",
+ "word",
+ "double word",
+ "reserved_4",
+ "reserved_5",
+ "reserved_6",
+ "reserved_7",
+};
+
+static irqreturn_t msm_ebi_irq(int irq, void *dev_id)
+{
+ struct msm_ebi_erp_data *drvdata = dev_id;
+ void __iomem *base = drvdata->base;
+ unsigned int err_addr, err_apacket0, err_apacket1, err_cntl;
+
+ err_addr = readl_relaxed(base + EBI_ERR_ADDR);
+ err_apacket0 = readl_relaxed(base + SLV_ERR_APACKET_0);
+ err_apacket1 = readl_relaxed(base + SLV_ERR_APACKET_1);
+ err_cntl = readl_relaxed(base + SLV_ERR_CNTL);
+
+ if (!(err_cntl & CNTL_ERR_OCCURRED))
+ return IRQ_NONE;
+
+ pr_alert("EBI error detected!\n");
+ pr_alert("\tDevice = %s\n", dev_name(drvdata->dev));
+ pr_alert("\tERR_ADDR = 0x%08x\n", err_addr);
+ pr_alert("\tAPACKET0 = 0x%08x\n", err_apacket0);
+ pr_alert("\tAPACKET1 = 0x%08x\n", err_apacket1);
+ pr_alert("\tERR_CNTL = 0x%08x\n", err_cntl);
+
+ pr_alert("\tAMID = 0x%08x\n", err_apacket0 & AMID_MASK);
+ pr_alert("\tType = %s, %s, %s\n",
+ err_apacket1 & ERR_AWRITE ? "write" : "read",
+ err_sizes[(err_apacket1 >> ERR_ASIZE_SHIFT) & ERR_ASIZE_MASK],
+ err_apacket1 & ERR_APTORNS ? "non-secure" : "secure");
+
+ pr_alert("\tALOCK = %s\n",
+ err_lock_types[(err_apacket1 >> ERR_ALOCK_SHIFT) & ERR_ALOCK_MASK]);
+
+ pr_alert("\tABURST = %s\n", err_apacket1 & ERR_ABURST ?
+ "increment" : "wrap");
+
+ pr_alert("\tCODE = %s %s\n", err_cntl & ERR_CODE_DECODE_ERROR ?
+ "decode error" : "",
+ err_cntl & ERR_CODE_MPU_ERROR ?
+ "mpu error" : "");
+ err_cntl |= CNTL_CLEAR_ERR;
+ writel_relaxed(err_cntl, base + SLV_ERR_CNTL);
+ mb(); /* Ensure interrupt is cleared before returning */
+ return IRQ_HANDLED;
+}
+
+static int __devinit msm_ebi_erp_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ struct msm_ebi_erp_data *drvdata;
+ int ret, irq;
+ unsigned int err_cntl;
+
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
+ drvdata->dev = &pdev->dev;
+ platform_set_drvdata(pdev, drvdata);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -EINVAL;
+
+ drvdata->base = devm_ioremap(&pdev->dev, r->start, resource_size(r));
+ if (!drvdata->base)
+ return -ENOMEM;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, msm_ebi_irq, IRQF_TRIGGER_HIGH,
+ dev_name(&pdev->dev), drvdata);
+ if (ret)
+ return ret;
+
+ /* Enable the interrupt */
+ err_cntl = readl_relaxed(drvdata->base + SLV_ERR_CNTL);
+ err_cntl |= CNTL_IRQ_EN;
+ writel_relaxed(err_cntl, drvdata->base + SLV_ERR_CNTL);
+ mb(); /* Ensure interrupt is enabled before returning */
+ return 0;
+}
+
+static int msm_ebi_erp_remove(struct platform_device *pdev)
+{
+ struct msm_ebi_erp_data *drvdata = platform_get_drvdata(pdev);
+ unsigned int err_cntl;
+
+ /* Disable the interrupt */
+ err_cntl = readl_relaxed(drvdata->base + SLV_ERR_CNTL);
+ err_cntl &= ~CNTL_IRQ_EN;
+ writel_relaxed(err_cntl, drvdata->base + SLV_ERR_CNTL);
+ mb(); /* Ensure interrupt is disabled before returning */
+ return 0;
+}
+
+static struct platform_driver msm_ebi_erp_driver = {
+ .probe = msm_ebi_erp_probe,
+ .remove = __devexit_p(msm_ebi_erp_remove),
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_ebi_erp_init(void)
+{
+ return platform_driver_register(&msm_ebi_erp_driver);
+}
+
+static void __exit msm_ebi_erp_exit(void)
+{
+ platform_driver_unregister(&msm_ebi_erp_driver);
+}
+
+
+module_init(msm_ebi_erp_init);
+module_exit(msm_ebi_erp_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MSM cache error reporting driver");
diff --git a/arch/arm/mach-msm/headsmp.S b/arch/arm/mach-msm/headsmp.S
index 50d2060..e5ad312 100644
--- a/arch/arm/mach-msm/headsmp.S
+++ b/arch/arm/mach-msm/headsmp.S
@@ -27,10 +27,6 @@
sub r4, r4, r5 @ determine virtual/phys offsets
add r6, r6, r4 @ apply
pen:
- wfe
- dsb @ ensure subsequent access is
- @ after event
-
ldr r7, [r6] @ pen_rel has cpu to remove from reset
cmp r7, r0 @ are we lucky?
bne pen
diff --git a/arch/arm/mach-msm/hsic_sysmon.c b/arch/arm/mach-msm/hsic_sysmon.c
index 2dedbac..07a9dbb 100644
--- a/arch/arm/mach-msm/hsic_sysmon.c
+++ b/arch/arm/mach-msm/hsic_sysmon.c
@@ -139,14 +139,13 @@
}
if (!hs->ifc) {
- dev_err(&hs->udev->dev, "can't %s, device disconnected\n",
- opstr);
+ pr_err("can't %s, device disconnected", opstr);
return -ENODEV;
}
ret = usb_autopm_get_interface(hs->ifc);
if (ret < 0) {
- dev_err(&hs->udev->dev, "can't %s, autopm_get failed:%d\n",
+ dev_err(&hs->ifc->dev, "can't %s, autopm_get failed:%d\n",
opstr, ret);
return ret;
}
@@ -159,7 +158,7 @@
atomic_dec(&hs->dbg_pending[op]);
if (ret)
- dev_err(&hs->udev->dev,
+ dev_err(&hs->ifc->dev,
"can't %s, usb_bulk_msg failed, err:%d\n", opstr, ret);
else
atomic_add(*actual_len, &hs->dbg_bytecnt[op]);
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 5e2eaf1..460eefc 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -61,10 +61,6 @@
struct msm_camera_io_ext ioext;
struct msm_camera_io_clk ioclk;
uint8_t csid_core;
- uint8_t is_csiphy;
- uint8_t is_csic;
- uint8_t is_csid;
- uint8_t is_ispif;
uint8_t is_vpe;
struct msm_bus_scale_pdata *cam_bus_scale_table;
};
@@ -187,6 +183,7 @@
enum camera_vreg_type {
REG_LDO,
REG_VS,
+ REG_GPIO,
};
struct camera_vreg_t {
@@ -294,7 +291,6 @@
enum msm_sensor_type sensor_type;
struct msm_actuator_info *actuator_info;
int pmic_gpio_enable;
- int (*sensor_lcd_gpio_onoff)(int on);
struct msm_eeprom_info *eeprom_info;
};
@@ -389,6 +385,7 @@
int (*backlight_level)(int level, int max, int min);
int (*pmic_backlight)(int level);
int (*rotate_panel)(void);
+ int (*backlight) (int level, int mode);
int (*panel_num)(void);
void (*panel_config_gpio)(int);
int (*vga_switch)(int select_vga);
@@ -485,6 +482,8 @@
int (*enable_5v)(int on);
int (*core_power)(int on, int show);
int (*cec_power)(int on);
+ int (*panel_power)(int on);
+ int (*gpio_config)(int on);
int (*init_irq)(void);
bool (*check_hdcp_hw_support)(void);
};
@@ -524,6 +523,7 @@
struct msm_bus_scale_pdata *vidc_bus_client_pdata;
#endif
int cont_mode_dpb_count;
+ int disable_turbo;
};
struct vcap_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index 87e7de1..d8543f3 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -114,52 +114,6 @@
STEREO_RAW_SNAP_STARTED,
};
-enum msm_ispif_intftype {
- PIX0,
- RDI0,
- PIX1,
- RDI1,
- PIX2,
- RDI2,
-};
-
-enum msm_ispif_vc {
- VC0,
- VC1,
- VC2,
- VC3,
-};
-
-enum msm_ispif_cid {
- CID0,
- CID1,
- CID2,
- CID3,
- CID4,
- CID5,
- CID6,
- CID7,
- CID8,
- CID9,
- CID10,
- CID11,
- CID12,
- CID13,
- CID14,
- CID15,
-};
-
-struct msm_ispif_params {
- uint8_t intftype;
- uint16_t cid_mask;
- uint8_t csid;
-};
-
-struct msm_ispif_params_list {
- uint32_t len;
- struct msm_ispif_params params[3];
-};
-
struct msm_vpe_phy_info {
uint32_t sbuf_phy;
uint32_t planar0_off;
@@ -172,12 +126,6 @@
uint32_t frame_id;
};
-struct msm_camera_csid_vc_cfg {
- uint8_t cid;
- uint8_t dt;
- uint8_t decode_format;
-};
-
struct msm_camera_csid_lut_params {
uint8_t num_cid;
struct msm_camera_csid_vc_cfg *vc_cfg;
@@ -209,18 +157,6 @@
#define VFE31_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5)
#endif
-#define CSI_EMBED_DATA 0x12
-#define CSI_RESERVED_DATA_0 0x13
-#define CSI_YUV422_8 0x1E
-#define CSI_RAW8 0x2A
-#define CSI_RAW10 0x2B
-#define CSI_RAW12 0x2C
-
-#define CSI_DECODE_6BIT 0
-#define CSI_DECODE_8BIT 1
-#define CSI_DECODE_10BIT 2
-#define CSI_DECODE_DPCM_10_8_10 5
-
struct msm_vfe_phy_info {
uint32_t sbuf_phy;
uint32_t planar0_off;
diff --git a/arch/arm/mach-msm/include/mach/cpufreq.h b/arch/arm/mach-msm/include/mach/cpufreq.h
new file mode 100644
index 0000000..8c2be11
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/cpufreq.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H
+#define __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H
+
+#define MSM_CPUFREQ_NO_LIMIT 0xFFFFFFFF
+
+#ifdef CONFIG_CPU_FREQ_MSM
+
+/**
+ * msm_cpufreq_set_freq_limit() - Set max/min freq limits on cpu
+ *
+ * @cpu: The cpu core for which the limits apply
+ * @max: The max frequency allowed
+ * @min: The min frequency allowed
+ *
+ * If the @max or @min is set to MSM_CPUFREQ_NO_LIMIT, the limit
+ * will default to the CPUFreq limit.
+ *
+ * returns 0 on success, errno on failure
+ */
+extern int msm_cpufreq_set_freq_limits(
+ uint32_t cpu, uint32_t min, uint32_t max);
+#else
+static inline int msm_cpufreq_set_freq_limits(
+ uint32_t cpu, uint32_t min, uint32_t max)
+{
+ return -ENOSYS;
+}
+#endif
+
+#endif /* __ARCH_ARM_MACH_MSM_MACH_CPUFREQ_H */
diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h
index 8aed079..1d32003 100644
--- a/arch/arm/mach-msm/include/mach/gpio.h
+++ b/arch/arm/mach-msm/include/mach/gpio.h
@@ -178,7 +178,7 @@
TLMM_PULL_SDC1_DATA,
};
-#ifdef CONFIG_GPIO_MSM_V2
+#if defined(CONFIG_GPIO_MSM_V2) || defined(CONFIG_GPIO_MSM_V3)
void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str);
void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull);
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
index 6d27d69..8cd8620 100644
--- a/arch/arm/mach-msm/include/mach/irqs-copper.h
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -35,7 +35,7 @@
#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 105)
#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
-#define NR_GPIO_IRQS 156
+#define NR_GPIO_IRQS 146
#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
#define NR_BOARD_IRQS NR_QPNP_IRQS
#define NR_TLMM_MSM_DIR_CONN_IRQ 8
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index fdf6786..d630799 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -41,7 +41,7 @@
#define NR_MSM_IRQS 288
#define NR_GPIO_IRQS 152
#define NR_PM8921_IRQS 256
-#define NR_PM8821_IRQS 64
+#define NR_PM8821_IRQS 112
#define NR_WCD9XXX_IRQS 49
#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
#define NR_GPIO_EXPANDER_IRQS 64
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index 956d44e..0c556b5 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.h
@@ -39,6 +39,8 @@
const struct msm_bus_board_algorithm *board_algo;
int hw_sel;
void *hw_data;
+ uint32_t qos_freq;
+ bool virt;
};
enum msm_bus_bw_tier_type {
diff --git a/arch/arm/mach-msm/include/mach/msm_dsps.h b/arch/arm/mach-msm/include/mach/msm_dsps.h
index cfb2024..32a4f15 100644
--- a/arch/arm/mach-msm/include/mach/msm_dsps.h
+++ b/arch/arm/mach-msm/include/mach/msm_dsps.h
@@ -75,6 +75,16 @@
* @regs_num - number of regulators.
* @dsps_pwr_ctl_en - to enable DSPS to do power control if set 1
* otherwise the apps will do power control
+ * @tcm_code_start - start of the TCM code region as physical address
+ * @tcm_code_size - size of the TCM code region in bytes
+ * @tcm_buf_start - start of the TCM buf region as physical address
+ * @tcm_buf_size - size of the TCM buf region in bytes
+ * @pipe_start - start of the PIPE region as physical address
+ * @pipe_size - size of the PIPE region in bytes
+ * @ddr_start - start of the DDR region as physical address
+ * @ddr_size - size of the DDR region in bytes
+ * @smem_start - start of the smem region as physical address
+ * @smem_size - size of the smem region in bytes
* @signature - signature for validity check.
*/
struct msm_dsps_platform_data {
@@ -87,6 +97,16 @@
int regs_num;
int dsps_pwr_ctl_en;
void (*init)(struct msm_dsps_platform_data *data);
+ int tcm_code_start;
+ int tcm_code_size;
+ int tcm_buf_start;
+ int tcm_buf_size;
+ int pipe_start;
+ int pipe_size;
+ int ddr_start;
+ int ddr_size;
+ int smem_start;
+ int smem_size;
u32 signature;
};
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
index 57e794f..2455e93 100644
--- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio.h
@@ -36,7 +36,16 @@
int hdmi_audio_packet_enable(bool on);
void hdmi_msm_audio_sample_rate_reset(int rate);
int hdmi_msm_audio_get_sample_rate(void);
+
+#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
int hdmi_msm_audio_info_setup(bool enabled, u32 num_of_channels,
u32 channel_allocation, u32 level_shift, bool down_mix);
-
+#else
+static inline int hdmi_msm_audio_info_setup(bool enabled,
+ u32 num_of_channels, u32 channel_allocation, u32 level_shift,
+ bool down_mix)
+{
+ return 0;
+}
+#endif
#endif /* __MSM_HDMI_AUDIO_H*/
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index fbb8502..e19f39d 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -95,7 +95,7 @@
#define SMSM_WLAN_TX_RINGS_EMPTY 0x00000200
#define SMSM_WLAN_TX_ENABLE 0x00000400
-#define SMSM_ERR_SRV_READY 0x00008000
+#define SMSM_SUBSYS2AP_STATUS 0x00008000
#ifdef CONFIG_MSM_SMD
void *smem_alloc(unsigned id, unsigned size);
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
index bf7c338..b0475ed 100644
--- a/arch/arm/mach-msm/include/mach/ocmem.h
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -41,7 +41,7 @@
};
struct ocmem_map_list {
- int num_chunks;
+ unsigned num_chunks;
struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
};
@@ -84,9 +84,14 @@
int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+/* Obtain the maximum quota for the client */
+unsigned long get_max_quota(int client_id);
+
/* Allocation APIs */
struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size);
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size);
+
struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size);
struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
index daf32a5..dd976ea 100644
--- a/arch/arm/mach-msm/include/mach/ocmem_priv.h
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -24,6 +24,9 @@
#define OCMEM_PHYS_BASE 0xFEC00000
#define OCMEM_PHYS_SIZE 0x180000
+#define TO_OCMEM 0x1
+#define TO_DDR 0x2
+
struct ocmem_zone;
struct ocmem_zone_ops {
@@ -45,6 +48,19 @@
struct ocmem_zone_ops *z_ops;
};
+enum op_code {
+ SCHED_NOP = 0x0,
+ SCHED_ALLOCATE,
+ SCHED_FREE,
+ SCHED_GROW,
+ SCHED_SHRINK,
+ SCHED_MAP,
+ SCHED_UNMAP,
+ SCHED_EVICT,
+ SCHED_RESTORE,
+ SCHED_DUMP,
+};
+
struct ocmem_req {
struct rw_semaphore rw_sem;
/* Chain in sched queue */
@@ -60,6 +76,8 @@
/* reverse pointers */
struct ocmem_zone *zone;
struct ocmem_buf *buffer;
+ struct ocmem_map_list *mlist;
+ enum op_code op;
unsigned long state;
/* Request assignments */
unsigned long req_start;
@@ -73,9 +91,55 @@
struct ocmem_req *req;
};
+static inline struct ocmem_buf *handle_to_buffer(struct ocmem_handle *handle)
+{
+ if (handle)
+ return &handle->buffer;
+ else
+ return NULL;
+}
+
+static inline struct ocmem_handle *buffer_to_handle(struct ocmem_buf *buffer)
+{
+ if (buffer)
+ return container_of(buffer, struct ocmem_handle, buffer);
+ else
+ return NULL;
+}
+
+static inline struct ocmem_req *handle_to_req(struct ocmem_handle *handle)
+{
+ if (handle)
+ return handle->req;
+ else
+ return NULL;
+}
+
+static inline struct ocmem_handle *req_to_handle(struct ocmem_req *req)
+{
+ if (req && req->buffer)
+ return container_of(req->buffer, struct ocmem_handle, buffer);
+ else
+ return NULL;
+}
+
struct ocmem_zone *get_zone(unsigned);
+unsigned long offset_to_phys(unsigned long);
+unsigned long phys_to_offset(unsigned long);
unsigned long allocate_head(struct ocmem_zone *, unsigned long);
int free_head(struct ocmem_zone *, unsigned long, unsigned long);
unsigned long allocate_tail(struct ocmem_zone *, unsigned long);
int free_tail(struct ocmem_zone *, unsigned long, unsigned long);
+
+int ocmem_notifier_init(void);
+int check_notifier(int);
+int dispatch_notification(int, enum ocmem_notif_type, struct ocmem_buf *);
+
+int ocmem_sched_init(void);
+int process_allocate(int, struct ocmem_handle *, unsigned long, unsigned long,
+ unsigned long, bool, bool);
+int process_free(int, struct ocmem_handle *);
+int process_xfer(int, struct ocmem_handle *, struct ocmem_map_list *,
+ int direction);
+unsigned long process_quota(int);
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
index a55dee6..65cf647 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_acdb.h
@@ -14,8 +14,11 @@
#define _AUDIO_ACDB_H
#include <linux/msm_audio_acdb.h>
+#ifdef CONFIG_ARCH_MSMCOPPER
+#include <sound/q6adm-v2.h>
+#else
#include <sound/q6adm.h>
-
+#endif
enum {
RX_CAL,
TX_CAL,
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
index bd303b2..f747a80 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/usf.h
@@ -68,12 +68,23 @@
#define USF_POINT_EPOS_FORMAT 0
#define USF_RAW_FORMAT 1
+/* Indexes of event types, produced by the calculators */
+#define USF_TSC_EVENT_IND 0
+#define USF_TSC_PTR_EVENT_IND 1
+#define USF_MOUSE_EVENT_IND 2
+#define USF_KEYBOARD_EVENT_IND 3
+#define USF_MAX_EVENT_IND 4
+
/* Types of events, produced by the calculators */
#define USF_NO_EVENT 0
-#define USF_TSC_EVENT 1
-#define USF_MOUSE_EVENT 2
-#define USF_KEYBOARD_EVENT 4
-#define USF_ALL_EVENTS (USF_TSC_EVENT | USF_MOUSE_EVENT | USF_KEYBOARD_EVENT)
+#define USF_TSC_EVENT (1 << USF_TSC_EVENT_IND)
+#define USF_TSC_PTR_EVENT (1 << USF_TSC_PTR_EVENT_IND)
+#define USF_MOUSE_EVENT (1 << USF_MOUSE_EVENT_IND)
+#define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND)
+#define USF_ALL_EVENTS (USF_TSC_EVENT |\
+ USF_TSC_PTR_EVENT |\
+ USF_MOUSE_EVENT |\
+ USF_KEYBOARD_EVENT)
/* min, max array dimension */
#define MIN_MAX_DIM 2
@@ -152,9 +163,6 @@
/* Info specific for RX*/
};
-
-#define USF_PIX_COORDINATE 0 /* unit is pixel */
-#define USF_CMM_COORDINATE 1 /* unit is 0.01 mm */
struct point_event_type {
/* Pen coordinates (x, y, z) in units, defined by <coordinates_type> */
int coordinates[COORDINATES_DIM];
@@ -162,8 +170,6 @@
int inclinations[TILTS_DIM];
/* [0-1023] (10bits); 0 - pen up */
uint32_t pressure;
-/* 0 - mapped in the display pixel. 1 - raw in 0.01 mm (only for log); */
- uint8_t coordinates_type;
};
/* Mouse buttons, supported by USF */
@@ -189,8 +195,8 @@
uint32_t seq_num;
/* Event generation system time */
uint32_t timestamp;
-/* Destination input event type (e.g. touch screen, mouse, key) */
- uint16_t event_type;
+/* Destination input event type index (e.g. touch screen, mouse, key) */
+ uint16_t event_type_ind;
union {
struct point_event_type point_event;
struct mouse_event_type mouse_event;
diff --git a/arch/arm/mach-msm/include/mach/rpm-8930.h b/arch/arm/mach-msm/include/mach/rpm-8930.h
index 5ec3a74..6fd9cf4 100644
--- a/arch/arm/mach-msm/include/mach/rpm-8930.h
+++ b/arch/arm/mach-msm/include/mach/rpm-8930.h
@@ -240,10 +240,8 @@
MSM_RPM_8930_ID_CXO_BUFFERS = 164,
MSM_RPM_8930_ID_USB_OTG_SWITCH = 165,
MSM_RPM_8930_ID_HDMI_SWITCH = 166,
- MSM_RPM_8930_ID_DDR_DMM_0 = 167,
- MSM_RPM_8930_ID_DDR_DMM_1 = 168,
- MSM_RPM_8930_ID_QDSS_CLK = 168,
- MSM_RPM_8930_ID_VOLTAGE_CORNER = 169,
+ MSM_RPM_8930_ID_QDSS_CLK = 167,
+ MSM_RPM_8930_ID_VOLTAGE_CORNER = 168,
MSM_RPM_8930_ID_LAST = MSM_RPM_8930_ID_VOLTAGE_CORNER,
};
@@ -353,10 +351,8 @@
MSM_RPM_8930_STATUS_ID_CXO_BUFFERS = 105,
MSM_RPM_8930_STATUS_ID_USB_OTG_SWITCH = 106,
MSM_RPM_8930_STATUS_ID_HDMI_SWITCH = 107,
- MSM_RPM_8930_STATUS_ID_DDR_DMM_0 = 108,
- MSM_RPM_8930_STATUS_ID_DDR_DMM_1 = 109,
- MSM_RPM_8930_STATUS_ID_QDSS_CLK = 110,
- MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER = 111,
+ MSM_RPM_8930_STATUS_ID_QDSS_CLK = 108,
+ MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER = 109,
MSM_RPM_8930_STATUS_ID_LAST = MSM_RPM_8930_STATUS_ID_VOLTAGE_CORNER,
};
diff --git a/arch/arm/mach-msm/include/mach/rpm-9615.h b/arch/arm/mach-msm/include/mach/rpm-9615.h
index 6ae7bae..4ca5eea 100644
--- a/arch/arm/mach-msm/include/mach/rpm-9615.h
+++ b/arch/arm/mach-msm/include/mach/rpm-9615.h
@@ -72,8 +72,9 @@
MSM_RPM_9615_SEL_CXO_BUFFERS = 81,
MSM_RPM_9615_SEL_USB_OTG_SWITCH = 82,
MSM_RPM_9615_SEL_HDMI_SWITCH = 83,
+ MSM_RPM_9615_SEL_VOLTAGE_CORNER = 87,
- MSM_RPM_9615_SEL_LAST = MSM_RPM_9615_SEL_HDMI_SWITCH,
+ MSM_RPM_9615_SEL_LAST = MSM_RPM_9615_SEL_VOLTAGE_CORNER,
};
/* RPM resource (4 byte) word ID enum */
@@ -162,8 +163,9 @@
MSM_RPM_9615_ID_CXO_BUFFERS = 105,
MSM_RPM_9615_ID_USB_OTG_SWITCH = 106,
MSM_RPM_9615_ID_HDMI_SWITCH = 107,
+ MSM_RPM_9615_ID_VOLTAGE_CORNER = 109,
- MSM_RPM_9615_ID_LAST = MSM_RPM_9615_ID_HDMI_SWITCH,
+ MSM_RPM_9615_ID_LAST = MSM_RPM_9615_ID_VOLTAGE_CORNER,
};
/* RPM status ID enum */
@@ -231,8 +233,9 @@
MSM_RPM_9615_STATUS_ID_CXO_BUFFERS = 60,
MSM_RPM_9615_STATUS_ID_USB_OTG_SWITCH = 61,
MSM_RPM_9615_STATUS_ID_HDMI_SWITCH = 62,
+ MSM_RPM_9615_STATUS_ID_VOLTAGE_CORNER = 64,
- MSM_RPM_9615_STATUS_ID_LAST = MSM_RPM_9615_STATUS_ID_HDMI_SWITCH,
+ MSM_RPM_9615_STATUS_ID_LAST = MSM_RPM_9615_STATUS_ID_VOLTAGE_CORNER,
};
#endif /* __ARCH_ARM_MACH_MSM_RPM_9615_H */
diff --git a/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
index f5fa8ca..6a7fae5 100644
--- a/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
+++ b/arch/arm/mach-msm/include/mach/rpm-regulator-9615.h
@@ -107,7 +107,8 @@
RPM_VREG_ID_PM8018_S4,
RPM_VREG_ID_PM8018_S5,
RPM_VREG_ID_PM8018_LVS1,
- RPM_VREG_ID_PM8018_MAX_REAL = RPM_VREG_ID_PM8018_LVS1,
+ RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
+ RPM_VREG_ID_PM8018_MAX_REAL = RPM_VREG_ID_PM8018_VDD_DIG_CORNER,
/* The following are IDs for regulator devices to enable pin control. */
RPM_VREG_ID_PM8018_L2_PC,
diff --git a/arch/arm/mach-msm/include/mach/rpm-smd.h b/arch/arm/mach-msm/include/mach/rpm-smd.h
index ff58fed..0239e36 100644
--- a/arch/arm/mach-msm/include/mach/rpm-smd.h
+++ b/arch/arm/mach-msm/include/mach/rpm-smd.h
@@ -236,6 +236,20 @@
return 0;
}
+
+static inline int msm_rpm_send_message(enum msm_rpm_set set, uint32_t rsc_type,
+ uint32_t rsc_id, struct msm_rpm_kvp *kvp, int nelems)
+{
+ return 0;
+}
+
+static inline int msm_rpm_send_message_noirq(enum msm_rpm_set set,
+ uint32_t rsc_type, uint32_t rsc_id, struct msm_rpm_kvp *kvp,
+ int nelems)
+{
+ return 0;
+}
+
static inline int msm_rpm_wait_for_ack(uint32_t msg_id)
{
return 0;
diff --git a/arch/arm/mach-msm/include/mach/rpm.h b/arch/arm/mach-msm/include/mach/rpm.h
index 98621be..de4c9d9 100644
--- a/arch/arm/mach-msm/include/mach/rpm.h
+++ b/arch/arm/mach-msm/include/mach/rpm.h
@@ -899,6 +899,8 @@
extern struct msm_rpm_platform_data msm8930_rpm_data;
extern struct msm_rpm_platform_data apq8064_rpm_data;
+#if defined(CONFIG_MSM_RPM)
+
int msm_rpm_local_request_is_outstanding(void);
int msm_rpm_get_status(struct msm_rpm_iv_pair *status, int count);
int msm_rpm_set(int ctx, struct msm_rpm_iv_pair *req, int count);
@@ -938,4 +940,70 @@
int msm_rpm_unregister_notification(struct msm_rpm_notification *n);
int msm_rpm_init(struct msm_rpm_platform_data *data);
+#else
+
+static inline int msm_rpm_local_request_is_outstanding(void)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_get_status(struct msm_rpm_iv_pair *status, int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_set(int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_set_noirq(int ctx, struct msm_rpm_iv_pair *req,
+ int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_set_nosleep(
+ int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_clear(int ctx, struct msm_rpm_iv_pair *req,
+ int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_clear_noirq(int ctx, struct msm_rpm_iv_pair *req,
+ int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_clear_nosleep(
+ int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_register_notification(struct msm_rpm_notification *n,
+ struct msm_rpm_iv_pair *req, int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_unregister_notification(
+ struct msm_rpm_notification *n)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpm_init(struct msm_rpm_platform_data *data)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_RPM */
+
#endif /* __ARCH_ARM_MACH_MSM_RPM_H */
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 86e06a4..e35d99b 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -34,7 +34,7 @@
.virtual = (unsigned long) MSM_##name##_BASE, \
.pfn = __phys_to_pfn(chip##_##name##_PHYS), \
.length = chip##_##name##_SIZE, \
- .type = MT_DEVICE_NONSHARED, \
+ .type = MT_DEVICE, \
}
#define MSM_DEVICE(name) MSM_CHIP_DEVICE(name, MSM)
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index e7287c1..a7e06ba 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -99,6 +99,8 @@
{
int ret;
struct scatterlist *sglist;
+ int prot = IOMMU_WRITE | IOMMU_READ;
+ prot |= cached ? IOMMU_CACHE : 0;
sglist = vmalloc(sizeof(*sglist));
if (!sglist) {
@@ -111,7 +113,7 @@
sglist->offset = 0;
sglist->dma_address = phys;
- ret = iommu_map_range(domain, iova, sglist, size, cached);
+ ret = iommu_map_range(domain, iova, sglist, size, prot);
if (ret) {
pr_err("%s: could not map extra %lx in domain %p\n",
__func__, iova, domain);
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 6fa435a..c0bff63 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -472,19 +472,19 @@
return port_ptr;
}
+/*
+ * Should be called with local_ports_lock locked
+ */
static struct msm_ipc_port *msm_ipc_router_lookup_local_port(uint32_t port_id)
{
int key = (port_id & (LP_HASH_SIZE - 1));
struct msm_ipc_port *port_ptr;
- mutex_lock(&local_ports_lock);
list_for_each_entry(port_ptr, &local_ports[key], list) {
if (port_ptr->this_port.port_id == port_id) {
- mutex_unlock(&local_ports_lock);
return port_ptr;
}
}
- mutex_unlock(&local_ports_lock);
return NULL;
}
@@ -1432,16 +1432,19 @@
resume_tx_node_id = hdr->dst_node_id;
resume_tx_port_id = hdr->dst_port_id;
+ rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
+ hdr->src_port_id);
+
+ mutex_lock(&local_ports_lock);
port_ptr = msm_ipc_router_lookup_local_port(hdr->dst_port_id);
if (!port_ptr) {
pr_err("%s: No local port id %08x\n", __func__,
hdr->dst_port_id);
+ mutex_unlock(&local_ports_lock);
release_pkt(pkt);
goto process_done;
}
- rport_ptr = msm_ipc_router_lookup_remote_port(hdr->src_node_id,
- hdr->src_port_id);
if (!rport_ptr) {
rport_ptr = msm_ipc_router_create_remote_port(
hdr->src_node_id,
@@ -1449,6 +1452,7 @@
if (!rport_ptr) {
pr_err("%s: Remote port %08x:%08x creation failed\n",
__func__, hdr->src_node_id, hdr->src_port_id);
+ mutex_unlock(&local_ports_lock);
goto process_done;
}
}
@@ -1459,7 +1463,9 @@
list_add_tail(&pkt->list, &port_ptr->port_rx_q);
wake_up(&port_ptr->port_rx_wait_q);
mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&local_ports_lock);
} else {
+ mutex_lock(&port_ptr->port_rx_q_lock);
src_addr = kmalloc(sizeof(struct msm_ipc_port_addr),
GFP_KERNEL);
if (src_addr) {
@@ -1467,8 +1473,10 @@
src_addr->port_id = hdr->src_port_id;
}
skb_pull(head_skb, IPC_ROUTER_HDR_SIZE);
+ mutex_unlock(&local_ports_lock);
port_ptr->notify(MSM_IPC_ROUTER_READ_CB, pkt->pkt_fragment_q,
src_addr, port_ptr->priv);
+ mutex_unlock(&port_ptr->port_rx_q_lock);
pkt->pkt_fragment_q = NULL;
src_addr = NULL;
release_pkt(pkt);
@@ -1628,9 +1636,11 @@
hdr->dst_port_id = port_id;
pkt->length += IPC_ROUTER_HDR_SIZE;
+ mutex_lock(&local_ports_lock);
port_ptr = msm_ipc_router_lookup_local_port(port_id);
if (!port_ptr) {
pr_err("%s: Local port %d not present\n", __func__, port_id);
+ mutex_unlock(&local_ports_lock);
release_pkt(pkt);
return -ENODEV;
}
@@ -1640,6 +1650,7 @@
list_add_tail(&pkt->list, &port_ptr->port_rx_q);
wake_up(&port_ptr->port_rx_wait_q);
mutex_unlock(&port_ptr->port_rx_q_lock);
+ mutex_unlock(&local_ports_lock);
return pkt->length;
}
@@ -1932,6 +1943,10 @@
return -EINVAL;
if (port_ptr->type == SERVER_PORT || port_ptr->type == CLIENT_PORT) {
+ mutex_lock(&local_ports_lock);
+ list_del(&port_ptr->list);
+ mutex_unlock(&local_ports_lock);
+
if (port_ptr->type == SERVER_PORT) {
msg.cmd = IPC_ROUTER_CTRL_CMD_REMOVE_SERVER;
msg.srv.service = port_ptr->port_name.service;
@@ -1950,6 +1965,10 @@
}
broadcast_ctl_msg(&msg);
broadcast_ctl_msg_locally(&msg);
+ } else if (port_ptr->type == CONTROL_PORT) {
+ mutex_lock(&control_ports_lock);
+ list_del(&port_ptr->list);
+ mutex_unlock(&control_ports_lock);
}
mutex_lock(&port_ptr->port_rx_q_lock);
@@ -1969,17 +1988,6 @@
msm_ipc_router_destroy_server(server,
port_ptr->this_port.node_id,
port_ptr->this_port.port_id);
- mutex_lock(&local_ports_lock);
- list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
- } else if (port_ptr->type == CLIENT_PORT) {
- mutex_lock(&local_ports_lock);
- list_del(&port_ptr->list);
- mutex_unlock(&local_ports_lock);
- } else if (port_ptr->type == CONTROL_PORT) {
- mutex_lock(&control_ports_lock);
- list_del(&port_ptr->list);
- mutex_unlock(&control_ports_lock);
}
wake_lock_destroy(&port_ptr->port_rx_wake_lock);
@@ -2023,7 +2031,7 @@
}
int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
- struct msm_ipc_port_addr *srv_addr,
+ struct msm_ipc_server_info *srv_info,
int num_entries_in_array,
uint32_t lookup_mask)
{
@@ -2036,8 +2044,8 @@
return -EINVAL;
}
- if (num_entries_in_array && !srv_addr) {
- pr_err("%s: srv_addr NULL\n", __func__);
+ if (num_entries_in_array && !srv_info) {
+ pr_err("%s: srv_info NULL\n", __func__);
return -EINVAL;
}
@@ -2054,10 +2062,14 @@
list_for_each_entry(server_port,
&server->server_port_list, list) {
if (i < num_entries_in_array) {
- srv_addr[i].node_id =
+ srv_info[i].node_id =
server_port->server_addr.node_id;
- srv_addr[i].port_id =
+ srv_info[i].port_id =
server_port->server_addr.port_id;
+ srv_info[i].service =
+ server->name.service;
+ srv_info[i].instance =
+ server->name.instance;
}
i++;
}
diff --git a/arch/arm/mach-msm/ipc_router.h b/arch/arm/mach-msm/ipc_router.h
index a90be23..07bc5e0 100644
--- a/arch/arm/mach-msm/ipc_router.h
+++ b/arch/arm/mach-msm/ipc_router.h
@@ -185,7 +185,7 @@
int msm_ipc_router_get_curr_pkt_size(struct msm_ipc_port *port_ptr);
int msm_ipc_router_bind_control_port(struct msm_ipc_port *port_ptr);
int msm_ipc_router_lookup_server_name(struct msm_ipc_port_name *srv_name,
- struct msm_ipc_port_addr *port_addr,
+ struct msm_ipc_server_info *srv_info,
int num_entries_in_array,
uint32_t lookup_mask);
int msm_ipc_router_close_port(struct msm_ipc_port *port_ptr);
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index d82ffe5..d3917f1 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -367,8 +367,8 @@
struct sock *sk = sock->sk;
struct msm_ipc_port *port_ptr;
struct server_lookup_args server_arg;
- struct msm_ipc_port_addr *port_addr = NULL;
- unsigned int n, port_addr_sz = 0;
+ struct msm_ipc_server_info *srv_info = NULL;
+ unsigned int n, srv_info_sz = 0;
int ret;
if (!sk)
@@ -409,33 +409,33 @@
break;
}
if (server_arg.num_entries_in_array) {
- port_addr_sz = server_arg.num_entries_in_array *
- sizeof(*port_addr);
- port_addr = kmalloc(port_addr_sz, GFP_KERNEL);
- if (!port_addr) {
+ srv_info_sz = server_arg.num_entries_in_array *
+ sizeof(*srv_info);
+ srv_info = kmalloc(srv_info_sz, GFP_KERNEL);
+ if (!srv_info) {
ret = -ENOMEM;
break;
}
}
ret = msm_ipc_router_lookup_server_name(&server_arg.port_name,
- port_addr, server_arg.num_entries_in_array,
+ srv_info, server_arg.num_entries_in_array,
server_arg.lookup_mask);
if (ret < 0) {
pr_err("%s: Server not found\n", __func__);
ret = -ENODEV;
- kfree(port_addr);
+ kfree(srv_info);
break;
}
server_arg.num_entries_found = ret;
ret = copy_to_user((void *)arg, &server_arg,
sizeof(server_arg));
- if (port_addr_sz) {
+ if (srv_info_sz) {
ret = copy_to_user((void *)(arg + sizeof(server_arg)),
- port_addr, port_addr_sz);
+ srv_info, srv_info_sz);
if (ret)
ret = -EFAULT;
- kfree(port_addr);
+ kfree(srv_info);
}
break;
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index ffff782..74bf25d 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -45,6 +45,7 @@
#define MDM_MODEM_DELTA 100
#define MDM_BOOT_TIMEOUT 60000L
#define MDM_RDUMP_TIMEOUT 60000L
+#define MDM2AP_STATUS_TIMEOUT_MS 60000L
static int mdm_debug_on;
static struct workqueue_struct *mdm_queue;
@@ -90,6 +91,22 @@
static DECLARE_WORK(sfr_reason_work, mdm_restart_reason_fn);
+static void mdm2ap_status_check(struct work_struct *work)
+{
+ /*
+ * If the mdm modem did not pull the MDM2AP_STATUS gpio
+ * high then call subsystem_restart.
+ */
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0) {
+ pr_err("%s: MDM2AP_STATUS gpio did not go high\n",
+ __func__);
+ mdm_drv->mdm_ready = 0;
+ subsystem_restart(EXTERNAL_MODEM);
+ }
+}
+
+static DECLARE_DELAYED_WORK(mdm2ap_status_check_work, mdm2ap_status_check);
+
long mdm_modem_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
@@ -131,6 +148,14 @@
complete(&mdm_boot);
else
first_boot = 0;
+
+ /* Start a timer to check that the mdm2ap_status gpio
+ * goes high.
+ */
+
+ if (gpio_get_value(mdm_drv->mdm2ap_status_gpio) == 0)
+ schedule_delayed_work(&mdm2ap_status_check_work,
+ msecs_to_jiffies(MDM2AP_STATUS_TIMEOUT_MS));
break;
case RAM_DUMP_DONE:
pr_debug("%s: mdm done collecting RAM dumps\n", __func__);
@@ -256,6 +281,7 @@
mdm_drv->mdm_ready = 0;
subsystem_restart(EXTERNAL_MODEM);
} else if (value == 1) {
+ cancel_delayed_work(&mdm2ap_status_check_work);
pr_info("%s: status = 1: mdm is now ready\n", __func__);
queue_work(mdm_queue, &mdm_status_work);
}
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 4922007..5d02bda 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -63,6 +63,12 @@
wmb();
}
+static void restart_modem(void)
+{
+ log_modem_sfr();
+ subsystem_restart("modem");
+}
+
static void modem_wdog_check(struct work_struct *work)
{
void __iomem *q6_sw_wdog_addr;
@@ -75,8 +81,7 @@
regval = readl_relaxed(q6_sw_wdog_addr);
if (!regval) {
pr_err("modem-8960: Modem watchdog wasn't activated!. Restarting the modem now.\n");
- log_modem_sfr();
- subsystem_restart("modem");
+ restart_modem();
}
iounmap(q6_sw_wdog_addr);
@@ -84,47 +89,6 @@
static DECLARE_DELAYED_WORK(modem_wdog_check_work, modem_wdog_check);
-static void modem_sw_fatal_fn(struct work_struct *work)
-{
- uint32_t panic_smsm_states = SMSM_RESET | SMSM_SYSTEM_DOWNLOAD;
- uint32_t reset_smsm_states = SMSM_SYSTEM_REBOOT_USR |
- SMSM_SYSTEM_PWRDWN_USR;
- uint32_t modem_state;
-
- pr_err("Watchdog bite received from modem SW!\n");
-
- modem_state = smsm_get_state(SMSM_MODEM_STATE);
-
- if (modem_state & panic_smsm_states) {
-
- pr_err("Modem SMSM state changed to SMSM_RESET.\n"
- "Probable err_fatal on the modem. "
- "Calling subsystem restart...\n");
- log_modem_sfr();
- subsystem_restart("modem");
-
- } else if (modem_state & reset_smsm_states) {
-
- pr_err("%s: User-invoked system reset/powerdown. "
- "Resetting the SoC now.\n",
- __func__);
- kernel_restart(NULL);
- } else {
- log_modem_sfr();
- subsystem_restart("modem");
- }
-}
-
-static void modem_fw_fatal_fn(struct work_struct *work)
-{
- pr_err("Watchdog bite received from modem FW!\n");
- log_modem_sfr();
- subsystem_restart("modem");
-}
-
-static DECLARE_WORK(modem_sw_fatal_work, modem_sw_fatal_fn);
-static DECLARE_WORK(modem_fw_fatal_work, modem_fw_fatal_fn);
-
static void smsm_state_cb(void *data, uint32_t old_state, uint32_t new_state)
{
/* Ignore if we're the one that set SMSM_RESET */
@@ -133,8 +97,7 @@
if (new_state & SMSM_RESET) {
pr_err("Probable fatal error on the modem.\n");
- log_modem_sfr();
- subsystem_restart("modem");
+ restart_modem();
}
}
@@ -252,19 +215,15 @@
static irqreturn_t modem_wdog_bite_irq(int irq, void *dev_id)
{
- int ret;
-
switch (irq) {
case Q6SW_WDOG_EXPIRED_IRQ:
- ret = schedule_work(&modem_sw_fatal_work);
- disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
- disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+ pr_err("Watchdog bite received from modem software!\n");
+ restart_modem();
break;
case Q6FW_WDOG_EXPIRED_IRQ:
- ret = schedule_work(&modem_fw_fatal_work);
- disable_irq_nosync(Q6SW_WDOG_EXPIRED_IRQ);
- disable_irq_nosync(Q6FW_WDOG_EXPIRED_IRQ);
+ pr_err("Watchdog bite received from modem firmware!\n");
+ restart_modem();
break;
break;
diff --git a/arch/arm/mach-msm/modem_notifier.c b/arch/arm/mach-msm/modem_notifier.c
index d92098b..2f4f6af 100644
--- a/arch/arm/mach-msm/modem_notifier.c
+++ b/arch/arm/mach-msm/modem_notifier.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2010, 2012, Code Aurora Forum. 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
@@ -193,8 +193,15 @@
}
#endif
-static int __init init_modem_notifier_list(void)
+int __init msm_init_modem_notifier_list(void)
{
+ static bool registered;
+
+ if (registered)
+ return 0;
+
+ registered = true;
+
srcu_init_notifier_head(&modem_notifier_list);
modem_notifier_debugfs_init();
#if defined(DEBUG)
@@ -210,4 +217,4 @@
return 0;
}
-module_init(init_modem_notifier_list);
+module_init(msm_init_modem_notifier_list);
diff --git a/arch/arm/mach-msm/modem_notifier.h b/arch/arm/mach-msm/modem_notifier.h
index 1bd2d6d..e39c163 100644
--- a/arch/arm/mach-msm/modem_notifier.h
+++ b/arch/arm/mach-msm/modem_notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2010, 2012, Code Aurora Forum. 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
@@ -30,5 +30,6 @@
extern void modem_queue_start_reset_notify(void);
extern void modem_queue_end_reset_notify(void);
extern void modem_queue_smsm_init_notify(void);
+extern int __init msm_init_modem_notifier_list(void);
#endif /* _MODEM_NOTIFIER_H */
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index 061998c..766856c 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -1,7 +1,8 @@
#
# Makefile for msm-bus driver specific files
#
-obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o msm_bus_rpm.o
+obj-y += msm_bus_core.o msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o
+obj-y += msm_bus_rpm.o msm_bus_bimc.o msm_bus_noc.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o
obj-$(CONFIG_ARCH_MSM8960) += msm_bus_board_8960.o
obj-$(CONFIG_ARCH_MSM9615) += msm_bus_board_9615.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
new file mode 100644
index 0000000..823f14d
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.c
@@ -0,0 +1,1990 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+
+#define pr_fmt(fmt) "AXI: BIMC: %s(): " fmt, __func__
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <mach/msm_bus_board.h>
+#include "msm_bus_core.h"
+#include "msm_bus_bimc.h"
+
+enum msm_bus_bimc_slave_block {
+ SLAVE_BLOCK_RESERVED = 0,
+ SLAVE_BLOCK_SLAVE_WAY,
+ SLAVE_BLOCK_XPU,
+ SLAVE_BLOCK_ARBITER,
+ SLAVE_BLOCK_SCMO,
+};
+
+
+/* Misc module */
+
+#define MISC_REG_BASE(b) ((b) + 0x00000000)
+
+#define MISC_HW_VERSION_ADDR(b) (MISC_REG_BASE(b) + 0x0000000)
+enum bimc_misc_hw_version {
+ MISC_HW_VERSION_RMSK = 0xffffff,
+ MISC_HW_VERSION_MAJOR_BMSK = 0xff0000,
+ MISC_HW_VERSION_MAJOR_SHFT = 0x10,
+ MISC_HW_VERSION_MINOR_BMSK = 0xff00,
+ MISC_HW_VERSION_MINOR_SHFT = 0x8,
+ MISC_HW_VERSION_STEP_BMSK = 0xff,
+ MISC_HW_VERSION_STEP_SHFT = 0x0,
+};
+
+#define MISC_CORE_INFO_ADDR(b) (MISC_REG_BASE(b) + 0x00000004)
+enum bimc_misc_core_info {
+ MISC_CORE_INFO_RMSK = 0xffffffff,
+ MISC_CORE_INFO_CORE_INFO_BMSK = 0xffffffff,
+ MISC_CORE_INFO_CORE_INFO_SHFT = 0x0,
+};
+
+#define MISC_HW_INFO_ADDR(b) (MISC_REG_BASE(b) + 0x00000008)
+enum bimc_misc_hw_info {
+ MISC_HW_INFO_RMSK = 0xffffffff,
+ MISC_HW_INFO_HW_MAJOR_BMSK = 0xff000000,
+ MISC_HW_INFO_HW_MAJOR_SHFT = 0x18,
+ MISC_HW_INFO_HW_BRANCH_BMSK = 0xff0000,
+ MISC_HW_INFO_HW_BRANCH_SHFT = 0x10,
+ MISC_HW_INFO_HW_MINOR_BMSK = 0xff00,
+ MISC_HW_INFO_HW_MINOR_SHFT = 0x8,
+ MISC_HW_INFO_HW_ECO_BMSK = 0xff,
+ MISC_HW_INFO_HW_ECO_SHFT = 0x0,
+};
+
+#define MISC_CORE_CLK_SEL_ADDR(b) \
+ (MISC_REG_BASE(b) + 0x00000020)
+enum bimc_misc_core_clk_sel {
+ MISC_CORE_CLK_SEL_RMSK = 0x3,
+ MISC_CORE_CLK_SEL_CLK_2X_MODE_BMSK = 0x2,
+ MISC_CORE_CLK_SEL_CLK_2X_MODE_SHFT = 0x1,
+ MISC_CORE_CLK_SEL_CLK_2X_MODE_CTRL_EN_BMSK = 0x1,
+ MISC_CORE_CLK_SEL_CLK_2X_MODE_CTRL_EN_SHFT = 0x0,
+};
+
+#define MISC_CLK_PERIOD_ADDR(b) \
+ (MISC_REG_BASE(b) + 0x00000024)
+enum bimc_misc_bimc_clk_preiod {
+ MISC_CLK_PERIOD_RMSK = 0xff,
+ MISC_CLK_PERIOD_CORE_CLK_PERIOD_BMSK = 0xff,
+ MISC_CLK_PERIOD_CORE_CLK_PERIOD_SHFT = 0x0,
+};
+
+#define MISC_SCMOn_LOCAL_CGC_THRESH_ADDR(b, n) \
+ (MISC_REG_BASE(b) + 0x00000100 + 0x4 * (n))
+enum bimc_misc_scm0n_local_cgc_thresh {
+ MISC_SCMOn_LOCAL_CGC_THRESH_RMSK = 0x800000ff,
+ MISC_SCMOn_LOCAL_CGC_THRESH_MAXn = 1,
+ MISC_SCMOn_LOCAL_CGC_THRESH_EN_BMSK = 0x80000000,
+ MISC_SCMOn_LOCAL_CGC_THRESH_EN_SHFT = 0x1f,
+ MISC_SCMOn_LOCAL_CGC_THRESH_THRESH_VAL_BMSK = 0xff,
+ MISC_SCMOn_LOCAL_CGC_THRESH_THRESH_VAL_SHFT = 0x0,
+};
+
+#define MISC_DPEn_LOCAL_CGC_THRESH_ADDR(b, n) \
+ (MISC_REG_BASE(b) + 0x00000140 + 0x4 * (n))
+enum bimc_misc_dpen_local_cgc_thresh {
+ MISC_DPEn_LOCAL_CGC_THRESH_RMSK = 0x800000ff,
+ MISC_DPEn_LOCAL_CGC_THRESH_MAXn = 1,
+ MISC_DPEn_LOCAL_CGC_THRESH_EN_BMSK = 0x80000000,
+ MISC_DPEn_LOCAL_CGC_THRESH_EN_SHFT = 0x1f,
+ MISC_DPEn_LOCAL_CGC_THRESH_THRESH_VAL_BMSK = 0xff,
+ MISC_DPEn_LOCAL_CGC_THRESH_THRESH_VAL_SHFT = 0x0,
+};
+
+#define MISC_MPORT_LOCAL_CGC_THRESH_ADDR(b) \
+ (MISC_REG_BASE(b) + 0x00000180)
+enum bimc_misc_mport_local_cgc_thresh {
+ MISC_MPORT_LOCAL_CGC_THRESH_RMSK = 0x800000ff,
+ MISC_MPORT_LOCAL_CGC_THRESH_EN_BMSK = 0x80000000,
+ MISC_MPORT_LOCAL_CGC_THRESH_EN_SHFT = 0x1f,
+ MISC_MPORT_LOCAL_CGC_THRESH_THRESH_VAL_BMSK = 0xff,
+ MISC_MPORT_LOCAL_CGC_THRESH_THRESH_VAL_SHFT = 0x0,
+};
+
+#define MISC_SWAY_LOCAL_CGC_THRESH_ADDR(b) \
+ (MISC_REG_BASE(b) + 0x000001c0)
+enum bimc_misc_sway_local_cgc_thresh {
+ MISC_SWAY_LOCAL_CGC_THRESH_RMSK = 0x800000ff,
+ MISC_SWAY_LOCAL_CGC_THRESH_EN_BMSK = 0x80000000,
+ MISC_SWAY_LOCAL_CGC_THRESH_EN_SHFT = 0x1f,
+ MISC_SWAY_LOCAL_CGC_THRESH_THRESH_VAL_BMSK = 0xff,
+ MISC_SWAY_LOCAL_CGC_THRESH_THRESH_VAL_SHFT = 0x0,
+};
+
+#define MISC_SCMOn_CGC_THRESH_ADDR(b, n) \
+ (MISC_REG_BASE(b) + 0x00000200 + 0x4 * (n))
+enum bimc_misc_scmon_cgc_thresh {
+ MISC_SCMOn_CGC_THRESH_RMSK = 0x800000ff,
+ MISC_SCMOn_CGC_THRESH_MAXn = 1,
+ MISC_SCMOn_CGC_THRESH_EN_BMSK = 0x80000000,
+ MISC_SCMOn_CGC_THRESH_EN_SHFT = 0x1f,
+ MISC_SCMOn_CGC_THRESH_THRESH_VAL_BMSK = 0xff,
+ MISC_SCMOn_CGC_THRESH_THRESH_VAL_SHFT = 0x0,
+};
+
+#define MISC_SCMOn_DYN_CLK_CTRL_ADDR(b, n) \
+ (MISC_REG_BASE(b) + 0x00000240 + 0x4 * (n))
+enum bimc_misc_scmon_dyn_clk_ctrl {
+ MISC_SCMOn_DYN_CLK_CTRL_RMSK = 0x3,
+ MISC_SCMOn_DYN_CLK_CTRL_MAXn = 1,
+ MISC_SCMOn_DYN_CLK_CTRL_CGC_EN_BMSK = 0x2,
+ MISC_SCMOn_DYN_CLK_CTRL_CGC_EN_SHFT = 0x1,
+ MISC_SCMOn_DYN_CLK_CTRL_CLK_EN_BMSK = 0x1,
+ MISC_SCMOn_DYN_CLK_CTRL_CLK_EN_SHFT = 0x0,
+};
+
+#define MISC_DPEn_CGC_THRESH_ADDR(b, n) \
+ (MISC_REG_BASE(b) + 0x00000280 + 0x4 * (n))
+enum bimc_misc_dpen_cgc_thresh {
+ MISC_DPEn_CGC_THRESH_RMSK = 0x800000ff,
+ MISC_DPEn_CGC_THRESH_MAXn = 1,
+ MISC_DPEn_CGC_THRESH_EN_BMSK = 0x80000000,
+ MISC_DPEn_CGC_THRESH_EN_SHFT = 0x1f,
+ MISC_DPEn_CGC_THRESH_THRESH_VAL_BMSK = 0xff,
+ MISC_DPEn_CGC_THRESH_THRESH_VAL_SHFT = 0x0,
+};
+
+#define MISC_DPEn_DYN_CLK_CTRL_ADDR(b, n) \
+ (MISC_REG_BASE(b) + 0x000002c0 + 0x4 * (n))
+enum bimc_misc_dpen_dyn_clk_ctrl {
+ MISC_DPEn_DYN_CLK_CTRL_RMSK = 0x3,
+ MISC_DPEn_DYN_CLK_CTRL_MAXn = 1,
+ MISC_DPEn_DYN_CLK_CTRL_CGC_EN_BMSK = 0x2,
+ MISC_DPEn_DYN_CLK_CTRL_CGC_EN_SHFT = 0x1,
+ MISC_DPEn_DYN_CLK_CTRL_CLK_EN_BMSK = 0x1,
+ MISC_DPEn_DYN_CLK_CTRL_CLK_EN_SHFT = 0x0,
+};
+
+/* BIMC Global registers */
+
+#define GLOBAL_1_REG_BASE(b) ((b) + 0x00001000)
+
+#define GLOBAL_1_COMPONENT_INFO_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000000)
+enum bimc_global_1_component_info {
+ GLOBAL_1_COMPONENT_INFO_RMSK = 0xffff,
+ GLOBAL_1_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00,
+ GLOBAL_1_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8,
+ GLOBAL_1_COMPONENT_INFO_TYPE_BMSK = 0xff,
+ GLOBAL_1_COMPONENT_INFO_TYPE_SHFT = 0x0,
+};
+
+#define VERSION_INFO_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000010)
+enum bimc_version_info {
+ VERSION_INFO_RMSK = 0xffff,
+ VERSION_INFO_MAJOR_BMSK = 0xf0000000,
+ VERSION_INFO_MAJOR_SHFT = 0x1c,
+ VERSION_INFO_BRANCH_BMSK = 0xfff0000,
+ VERSION_INFO_BRANCH_SHFT = 0x10,
+ VERSION_INFO_MINOR_BMSK = 0xff00,
+ VERSION_INFO_MINOR_SHFT = 0x8,
+ VERSION_INFO_ECO_BMSK = 0xff,
+ VERSION_INFO_ECO_SHFT = 0x0,
+};
+
+#define HW_VERSION_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000014)
+enum bimc_hw_version {
+ HW_VERSION_RMSK = 0xffffffff,
+ HW_VERSION_MAJOR_BMSK = 0xf0000000,
+ HW_VERSION_MAJOR_SHFT = 0x1c,
+ HW_VERSION_MINOR_BMSK = 0xfff0000,
+ HW_VERSION_MINOR_SHFT = 0x10,
+ HW_VERSION_STEP_BMSK = 0xffff,
+ HW_VERSION_STEP_SHFT = 0x0,
+};
+
+#define BRIC_CONFIG_INFO_0_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000020)
+enum bimc_bric_config_info_0 {
+ BRIC_CONFIG_INFO_0_RMSK = 0xffffffff,
+ BRIC_CONFIG_INFO_0_ADDR_WIDTH_BMSK = 0xff000000,
+ BRIC_CONFIG_INFO_0_ADDR_WIDTH_SHFT = 0x18,
+ BRIC_CONFIG_INFO_0_BUSID_BMSK = 0xff0000,
+ BRIC_CONFIG_INFO_0_BUSID_SHFT = 0x10,
+ BRIC_CONFIG_INFO_0_NUM_SWAYS_BMSK = 0xff00,
+ BRIC_CONFIG_INFO_0_NUM_SWAYS_SHFT = 0x8,
+ BRIC_CONFIG_INFO_0_NUM_MPORTS_BMSK = 0xff,
+ BRIC_CONFIG_INFO_0_NUM_MPORTS_SHFT = 0x0,
+};
+
+#define BRIC_CONFIG_INFO_1_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000030)
+enum bimc_bric_config_info_1 {
+ BRIC_CONFIG_INFO_1_RMSK = 0xffffffff,
+ BRIC_CONFIG_INFO_1_DATA_WIDTH_BMSK = 0xffff0000,
+ BRIC_CONFIG_INFO_1_DATA_WIDTH_SHFT = 0x10,
+ BRIC_CONFIG_INFO_1_TID_WIDTH_BMSK = 0xff00,
+ BRIC_CONFIG_INFO_1_TID_WIDTH_SHFT = 0x8,
+ BRIC_CONFIG_INFO_1_MID_WIDTH_BMSK = 0xff,
+ BRIC_CONFIG_INFO_1_MID_WIDTH_SHFT = 0x0,
+};
+
+#define MP_INT_STATUS_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000100)
+enum bimc_mp_int_status {
+ MP_INT_STATUS_RMSK = 0x7f,
+ MP_INT_STATUS_MASTERPORT_BMSK = 0x7f,
+ MP_INT_STATUS_MASTERPORT_SHFT = 0x0,
+};
+
+#define MP_INT_CLR_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000108)
+enum bimc_mp_int_clr {
+ MP_INT_CLR_RMSK = 0x7f,
+ MP_INT_CLR_MASTERPORT_BMSK = 0x7f,
+ MP_INT_CLR_MASTERPORT_SHFT = 0x0,
+};
+
+#define MP_INT_EN_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x0000010c)
+enum bimc_mp_int_en {
+ MP_INT_EN_RMSK = 0x7f,
+ MP_INT_EN_MASTERPORT_BMSK = 0x7f,
+ MP_INT_EN_MASTERPORT_SHFT = 0x0,
+};
+
+#define SW_INT_STATUS_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000110)
+enum bimc_sw_int_status {
+ SW_INT_STATUS_RMSK = 0x1f,
+ SW_INT_STATUS_MASTERPORT_BMSK = 0x1f,
+ SW_INT_STATUS_MASTERPORT_SHFT = 0x0,
+};
+
+#define SW_INT_CLR_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000118)
+enum bimc_sw_int_clr {
+ SW_INT_CLR_RMSK = 0x1f,
+ SW_INT_CLR_MASTERPORT_BMSK = 0x1f,
+ SW_INT_CLR_MASTERPORT_SHFT = 0x0,
+};
+
+#define SW_INT_EN_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x0000011c)
+enum bimc_sw_int_en {
+ SW_INT_EN_RMSK = 0x1f,
+ SW_INT_EN_MASTERPORT_BMSK = 0x1f,
+ SW_INT_EN_MASTERPORT_SHFT = 0x0,
+};
+
+#define REF_TIMER_CONFIG_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000200)
+enum bimc_ref_timer_config {
+ REF_TIMER_CONFIG_RMSK = 0xffff,
+ REF_TIMER_CONFIG_MASTERPORT_BMSK = 0xffff,
+ REF_TIMER_CONFIG_MASTERPORT_SHFT = 0x0,
+};
+
+#define DEBUG_SEL_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x00000210)
+enum bimc_debug_sel {
+ DEBUG_SEL_RMSK = 0xffffffff,
+ DEBUG_SEL_COMPONENT_BMSK = 0xff000000,
+ DEBUG_SEL_COMPONENT_SHFT = 0x18,
+ DEBUG_SEL_INSTANCE_BMSK = 0xff0000,
+ DEBUG_SEL_INSTANCE_SHFT = 0x10,
+ DEBUG_SEL_SEL_BMSK = 0xffff,
+ DEBUG_SEL_SEL_SHFT = 0x0,
+};
+
+/* BIMC Global 2 */
+
+#define GLOBAL2_REG_BASE(b) ((b) + 0x00002000)
+
+#define GLOBAL2_COMPONENT_INFO_ADDR(b) \
+ (GLOBAL2_REG_BASE(b) + 0x00000000)
+enum bimc_global2_component_info {
+ GLOBAL2_COMPONENT_INFO_RMSK = 0xffff,
+ GLOBAL2_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00,
+ GLOBAL2_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8,
+ GLOBAL2_COMPONENT_INFO_TYPE_BMSK = 0xff,
+ GLOBAL2_COMPONENT_INFO_TYPE_SHFT = 0x0,
+};
+
+#define DEFAULT_SEGMENT_CONFIG_ADDR(b) \
+ (GLOBAL1_REG_BASE(b) + 0x000001f0)
+enum bimc_default_segment_config {
+ DEFAULT_SEGMENT_CONFIG_RMSK = 0xf00f,
+ DEFAULT_SEGMENT_CONFIG_REDIRECT_BMSK = 0xf0000,
+ DEFAULT_SEGMENT_CONFIG_REDIRECT_SHFT = 0x10,
+ DEFAULT_SEGMENT_CONFIG_DEFAULT_BMSK = 0xf,
+ DEFAULT_SEGMENT_CONFIG_DEFAULT_SHFT = 0x0,
+};
+
+#define SEGMENTn_ADDR_BASEm_LOWER_ADDR(b, n, m) \
+ (GLOBAL2_REG_BASE(b) + 0x00000200 + 0x80 * (n) + 0x10 * (m))
+enum bimc_segmentn_addr_basem_lower {
+ SEGMENTn_ADDR_BASEm_LOWER_RMSK = 0xfff0040f,
+ SEGMENTn_ADDR_BASEm_LOWER_MAXn = 4,
+ SEGMENTn_ADDR_BASEm_LOWER_BASE_31_20_BMSK = 0xfff00000,
+ SEGMENTn_ADDR_BASEm_LOWER_BASE_31_20_SHFT = 0x14,
+ SEGMENTn_ADDR_BASEm_LOWER_BASE_10_BMSK = 0x400,
+ SEGMENTn_ADDR_BASEm_LOWER_BASE_10_SHFT = 0xa,
+ SEGMENTn_ADDR_BASEm_LOWER_EN_BMSK = 0x1,
+ SEGMENTn_ADDR_BASEm_LOWER_EN_SHFT = 0x0,
+};
+
+#define SEGMENTn_ADDR_BASEm_UPPER_ADDR(b, n, m) \
+ (GLOBAL2_REG_BASE(b) + 0x00000204 + 0x80 * (n) + 0x10 * (m))
+enum bimc_segmentn_addr_basem_upper {
+ SEGMENTn_ADDR_BASEm_UPPER_RMSK = 0xf,
+ SEGMENTn_ADDR_BASEm_UPPER_MAXn = 4,
+};
+
+#define SEGMENTn_ADDR_MASKm_LOWER_ADDR(b, n, m) \
+ (GLOBAL2_REG_BASE(b) + 0x00000208 + 0x80 * (n) + 0x10 * (m))
+enum bimc_segmentn_addr_maskm_lower {
+ SEGMENTn_ADDR_MASKm_LOWER_RMSK = 0xfff00400,
+ SEGMENTn_ADDR_MASKm_LOWER_MAXn = 4,
+ SEGMENTn_ADDR_MASKm_LOWER_MASK_31_20_BMSK = 0xfff00000,
+ SEGMENTn_ADDR_MASKm_LOWER_MASK_31_20_SHFT = 0x14,
+ SEGMENTn_ADDR_MASKm_LOWER_MASK_10_BMSK = 0x400,
+ SEGMENTn_ADDR_MASKm_LOWER_MASK_10_SHFT = 0xa,
+};
+
+#define SEGMENTn_ADDR_MASKm_UPPER_ADDR(b, n, m) \
+ (GLOBAL2_REG_BASE(b) + 0x0000020c + 0x80 * (n) + 0x10 * (m))
+enum bimc_segmentn_addr_maskm_upper {
+ SEGMENTn_ADDR_MASKm_UPPER_RMSK = 0xf,
+ SEGMENTn_ADDR_MASKm_UPPER_MAXn = 4,
+};
+
+/* M_Generic */
+
+#define M_REG_BASE(b) ((b) + 0x00008000)
+
+#define M_COMPONENT_INFO_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000000)
+enum bimc_m_component_info {
+ M_COMPONENT_INFO_RMSK = 0xffffff,
+ M_COMPONENT_INFO_INSTANCE_BMSK = 0xff0000,
+ M_COMPONENT_INFO_INSTANCE_SHFT = 0x10,
+ M_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00,
+ M_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8,
+ M_COMPONENT_INFO_TYPE_BMSK = 0xff,
+ M_COMPONENT_INFO_TYPE_SHFT = 0x0,
+};
+
+#define M_CONFIG_INFO_0_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000020)
+enum bimc_m_config_info_0 {
+ M_CONFIG_INFO_0_RMSK = 0xff00ffff,
+ M_CONFIG_INFO_0_SYNC_MODE_BMSK = 0xff000000,
+ M_CONFIG_INFO_0_SYNC_MODE_SHFT = 0x18,
+ M_CONFIG_INFO_0_CONNECTION_TYPE_BMSK = 0xff00,
+ M_CONFIG_INFO_0_CONNECTION_TYPE_SHFT = 0x8,
+ M_CONFIG_INFO_0_FUNC_BMSK = 0xff,
+ M_CONFIG_INFO_0_FUNC_SHFT = 0x0,
+};
+
+#define M_CONFIG_INFO_1_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000030)
+enum bimc_m_config_info_1 {
+ M_CONFIG_INFO_1_RMSK = 0xffffffff,
+ M_CONFIG_INFO_1_SWAY_CONNECTIVITY_BMSK = 0xffffffff,
+ M_CONFIG_INFO_1_SWAY_CONNECTIVITY_SHFT = 0x0,
+};
+
+#define M_CONFIG_INFO_2_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000040)
+enum bimc_m_config_info_2 {
+ M_CONFIG_INFO_2_RMSK = 0xffffffff,
+ M_CONFIG_INFO_2_M_DATA_WIDTH_BMSK = 0xffff0000,
+ M_CONFIG_INFO_2_M_DATA_WIDTH_SHFT = 0x10,
+ M_CONFIG_INFO_2_M_TID_WIDTH_BMSK = 0xff00,
+ M_CONFIG_INFO_2_M_TID_WIDTH_SHFT = 0x8,
+ M_CONFIG_INFO_2_M_MID_WIDTH_BMSK = 0xff,
+ M_CONFIG_INFO_2_M_MID_WIDTH_SHFT = 0x0,
+};
+
+#define M_CONFIG_INFO_3_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000050)
+enum bimc_m_config_info_3 {
+ M_CONFIG_INFO_3_RMSK = 0xffffffff,
+ M_CONFIG_INFO_3_RCH_DEPTH_BMSK = 0xff000000,
+ M_CONFIG_INFO_3_RCH_DEPTH_SHFT = 0x18,
+ M_CONFIG_INFO_3_BCH_DEPTH_BMSK = 0xff0000,
+ M_CONFIG_INFO_3_BCH_DEPTH_SHFT = 0x10,
+ M_CONFIG_INFO_3_WCH_DEPTH_BMSK = 0xff00,
+ M_CONFIG_INFO_3_WCH_DEPTH_SHFT = 0x8,
+ M_CONFIG_INFO_3_ACH_DEPTH_BMSK = 0xff,
+ M_CONFIG_INFO_3_ACH_DEPTH_SHFT = 0x0,
+};
+
+#define M_CONFIG_INFO_4_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000060)
+enum bimc_m_config_info_4 {
+ M_CONFIG_INFO_4_RMSK = 0xffff,
+ M_CONFIG_INFO_4_REORDER_BUF_DEPTH_BMSK = 0xff00,
+ M_CONFIG_INFO_4_REORDER_BUF_DEPTH_SHFT = 0x8,
+ M_CONFIG_INFO_4_REORDER_TABLE_DEPTH_BMSK = 0xff,
+ M_CONFIG_INFO_4_REORDER_TABLE_DEPTH_SHFT = 0x0,
+};
+
+#define M_CONFIG_INFO_5_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000070)
+enum bimc_m_config_info_5 {
+ M_CONFIG_INFO_5_RMSK = 0x111,
+ M_CONFIG_INFO_5_MP2ARB_PIPELINE_EN_BMSK = 0x100,
+ M_CONFIG_INFO_5_MP2ARB_PIPELINE_EN_SHFT = 0x8,
+ M_CONFIG_INFO_5_MPBUF_PIPELINE_EN_BMSK = 0x10,
+ M_CONFIG_INFO_5_MPBUF_PIPELINE_EN_SHFT = 0x4,
+ M_CONFIG_INFO_5_M2MP_PIPELINE_EN_BMSK = 0x1,
+ M_CONFIG_INFO_5_M2MP_PIPELINE_EN_SHFT = 0x0,
+};
+
+#define M_INT_STATUS_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000100)
+enum bimc_m_int_status {
+ M_INT_STATUS_RMSK = 0x3,
+};
+
+#define M_INT_CLR_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000108)
+enum bimc_m_int_clr {
+ M_INT_CLR_RMSK = 0x3,
+};
+
+#define M_INT_EN_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x0000010c)
+enum bimc_m_int_en {
+ M_INT_EN_RMSK = 0x3,
+};
+
+#define M_CLK_CTRL_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000200)
+enum bimc_m_clk_ctrl {
+ M_CLK_CTRL_RMSK = 0x3,
+ M_CLK_CTRL_MAS_CLK_GATING_EN_BMSK = 0x2,
+ M_CLK_CTRL_MAS_CLK_GATING_EN_SHFT = 0x1,
+ M_CLK_CTRL_CORE_CLK_GATING_EN_BMSK = 0x1,
+ M_CLK_CTRL_CORE_CLK_GATING_EN_SHFT = 0x0,
+};
+
+#define M_MODE_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000210)
+enum bimc_m_mode {
+ M_MODE_RMSK = 0xf0000001,
+ M_MODE_WR_GATHER_BEATS_BMSK = 0xf0000000,
+ M_MODE_WR_GATHER_BEATS_SHFT = 0x1c,
+ M_MODE_ORDERING_MODEL_BMSK = 0x1,
+ M_MODE_ORDERING_MODEL_SHFT = 0x0,
+};
+
+#define M_PRIOLVL_OVERRIDE_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000220)
+enum bimc_m_priolvl_override {
+ M_PRIOLVL_OVERRIDE_RMSK = 0x301,
+ M_PRIOLVL_OVERRIDE_BMSK = 0x300,
+ M_PRIOLVL_OVERRIDE_SHFT = 0x8,
+ M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK = 0x1,
+ M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT = 0x0,
+};
+
+#define M_RD_CMD_OVERRIDE_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230)
+enum bimc_m_read_command_override {
+ M_RD_CMD_OVERRIDE_RMSK = 0x37f3f,
+ M_RD_CMD_OVERRIDE_AREQPRIO_BMSK = 0x300000,
+ M_RD_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18,
+ M_RD_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000,
+ M_RD_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10,
+ M_RD_CMD_OVERRIDE_ATRANSIENT_BMSK = 0x1000,
+ M_RD_CMD_OVERRIDE_ATRANSIENT_SHFT = 0xc,
+ M_RD_CMD_OVERRIDE_ASHARED_BMSK = 0x800,
+ M_RD_CMD_OVERRIDE_ASHARED_SHFT = 0xb,
+ M_RD_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400,
+ M_RD_CMD_OVERRIDE_AREDIRECT_SHFT = 0xa,
+ M_RD_CMD_OVERRIDE_AOOO_BMSK = 0x200,
+ M_RD_CMD_OVERRIDE_AOOO_SHFT = 0x9,
+ M_RD_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100,
+ M_RD_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x40,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x6,
+ M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK = 0x20,
+ M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT = 0x5,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4,
+ M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8,
+ M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT = 0x3,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK = 0x4,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT = 0x2,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK = 0x2,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT = 0x1,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK = 0x1,
+ M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT = 0x0,
+};
+
+#define M_WR_CMD_OVERRIDE_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240)
+enum bimc_m_write_command_override {
+ M_WR_CMD_OVERRIDE_RMSK = 0x37f3f,
+ M_WR_CMD_OVERRIDE_AREQPRIO_BMSK = 0x30000,
+ M_WR_CMD_OVERRIDE_AREQPRIO_SHFT = 0x10,
+ M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x7000,
+ M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT = 0xc,
+ M_WR_CMD_OVERRIDE_ASHARED_BMSK = 0x800,
+ M_WR_CMD_OVERRIDE_ASHARED_SHFT = 0xb,
+ M_WR_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400,
+ M_WR_CMD_OVERRIDE_AREDIRECT_SHFT = 0xa,
+ M_WR_CMD_OVERRIDE_AOOO_BMSK = 0x200,
+ M_WR_CMD_OVERRIDE_AOOO_SHFT = 0x9,
+ M_WR_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100,
+ M_WR_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x20,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x5,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4,
+ M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8,
+ M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT = 0x3,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK = 0x4,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT = 0x2,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK = 0x2,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT = 0x1,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK = 0x1,
+ M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT = 0x0,
+};
+
+#define M_BKE_EN_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000300)
+enum bimc_m_bke_en {
+ M_BKE_EN_RMSK = 0x1,
+ M_BKE_EN_EN_BMSK = 0x1,
+ M_BKE_EN_EN_SHFT = 0x0,
+};
+
+/* Grant Period registers */
+#define M_BKE_GP_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000304)
+enum bimc_m_bke_grant_period {
+ M_BKE_GP_RMSK = 0x3ff,
+ M_BKE_GP_GP_BMSK = 0x3ff,
+ M_BKE_GP_GP_SHFT = 0x0,
+};
+
+/* Grant count registers */
+#define M_BKE_GC_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000308)
+enum bimc_m_bke_grant_count {
+ M_BKE_GC_RMSK = 0xffff,
+ M_BKE_GC_GC_BMSK = 0xffff,
+ M_BKE_GC_GC_SHFT = 0x0,
+};
+
+/* Threshold High Registers */
+#define M_BKE_THH_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000320)
+enum bimc_m_bke_thresh_high {
+ M_BKE_THH_RMSK = 0xffff,
+ M_BKE_THH_THRESH_BMSK = 0xffff,
+ M_BKE_THH_THRESH_SHFT = 0x0,
+};
+
+/* Threshold Medium Registers */
+#define M_BKE_THM_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000324)
+enum bimc_m_bke_thresh_medium {
+ M_BKE_THM_RMSK = 0xffff,
+ M_BKE_THM_THRESH_BMSK = 0xffff,
+ M_BKE_THM_THRESH_SHFT = 0x0,
+};
+
+/* Threshold Low Registers */
+#define M_BKE_THL_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000328)
+enum bimc_m_bke_thresh_low {
+ M_BKE_THL_RMSK = 0xffff,
+ M_BKE_THL_THRESH_BMSK = 0xffff,
+ M_BKE_THL_THRESH_SHFT = 0x0,
+};
+
+#define M_BKE_HEALTH_0_CONFIG_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000340)
+enum bimc_m_bke_health_0 {
+ M_BKE_HEALTH_0_CONFIG_RMSK = 0x80000303,
+ M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK = 0x80000000,
+ M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT = 0x1f,
+ M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK = 0x300,
+ M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT = 0x8,
+ M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK = 0x3,
+ M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT = 0x0,
+};
+
+#define M_BKE_HEALTH_1_CONFIG_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000344)
+enum bimc_m_bke_health_1 {
+ M_BKE_HEALTH_1_CONFIG_RMSK = 0x80000303,
+ M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_BMSK = 0x80000000,
+ M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_SHFT = 0x1f,
+ M_BKE_HEALTH_1_CONFIG_AREQPRIO_BMSK = 0x300,
+ M_BKE_HEALTH_1_CONFIG_AREQPRIO_SHFT = 0x8,
+ M_BKE_HEALTH_1_CONFIG_PRIOLVL_BMSK = 0x3,
+ M_BKE_HEALTH_1_CONFIG_PRIOLVL_SHFT = 0x0,
+};
+
+#define M_BKE_HEALTH_2_CONFIG_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000348)
+enum bimc_m_bke_health_2 {
+ M_BKE_HEALTH_2_CONFIG_RMSK = 0x80000303,
+ M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_BMSK = 0x80000000,
+ M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_SHFT = 0x1f,
+ M_BKE_HEALTH_2_CONFIG_AREQPRIO_BMSK = 0x300,
+ M_BKE_HEALTH_2_CONFIG_AREQPRIO_SHFT = 0x8,
+ M_BKE_HEALTH_2_CONFIG_PRIOLVL_BMSK = 0x3,
+ M_BKE_HEALTH_2_CONFIG_PRIOLVL_SHFT = 0x0,
+};
+
+#define M_BKE_HEALTH_3_CONFIG_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x0000034c)
+enum bimc_m_bke_health_3 {
+ M_BKE_HEALTH_3_CONFIG_RMSK = 0x303,
+ M_BKE_HEALTH_3_CONFIG_AREQPRIO_BMSK = 0x300,
+ M_BKE_HEALTH_3_CONFIG_AREQPRIO_SHFT = 0x8,
+ M_BKE_HEALTH_3_CONFIG_PRIOLVL_BMSK = 0x3,
+ M_BKE_HEALTH_3_CONFIG_PRIOLVL_SHFT = 0x0,
+};
+
+#define M_BUF_STATUS_ADDR(b, n) \
+ (M_REG_BASE(b) + (0x4000 * (n)) + 0x00000400)
+enum bimc_m_buf_status {
+ M_BUF_STATUS_RMSK = 0xf03f030,
+ M_BUF_STATUS_RCH_DATA_WR_FULL_BMSK = 0x8000000,
+ M_BUF_STATUS_RCH_DATA_WR_FULL_SHFT = 0x1b,
+ M_BUF_STATUS_RCH_DATA_WR_EMPTY_BMSK = 0x4000000,
+ M_BUF_STATUS_RCH_DATA_WR_EMPTY_SHFT = 0x1a,
+ M_BUF_STATUS_RCH_CTRL_WR_FULL_BMSK = 0x2000000,
+ M_BUF_STATUS_RCH_CTRL_WR_FULL_SHFT = 0x19,
+ M_BUF_STATUS_RCH_CTRL_WR_EMPTY_BMSK = 0x1000000,
+ M_BUF_STATUS_RCH_CTRL_WR_EMPTY_SHFT = 0x18,
+ M_BUF_STATUS_BCH_WR_FULL_BMSK = 0x20000,
+ M_BUF_STATUS_BCH_WR_FULL_SHFT = 0x11,
+ M_BUF_STATUS_BCH_WR_EMPTY_BMSK = 0x10000,
+ M_BUF_STATUS_BCH_WR_EMPTY_SHFT = 0x10,
+ M_BUF_STATUS_WCH_DATA_RD_FULL_BMSK = 0x8000,
+ M_BUF_STATUS_WCH_DATA_RD_FULL_SHFT = 0xf,
+ M_BUF_STATUS_WCH_DATA_RD_EMPTY_BMSK = 0x4000,
+ M_BUF_STATUS_WCH_DATA_RD_EMPTY_SHFT = 0xe,
+ M_BUF_STATUS_WCH_CTRL_RD_FULL_BMSK = 0x2000,
+ M_BUF_STATUS_WCH_CTRL_RD_FULL_SHFT = 0xd,
+ M_BUF_STATUS_WCH_CTRL_RD_EMPTY_BMSK = 0x1000,
+ M_BUF_STATUS_WCH_CTRL_RD_EMPTY_SHFT = 0xc,
+ M_BUF_STATUS_ACH_RD_FULL_BMSK = 0x20,
+ M_BUF_STATUS_ACH_RD_FULL_SHFT = 0x5,
+ M_BUF_STATUS_ACH_RD_EMPTY_BMSK = 0x10,
+ M_BUF_STATUS_ACH_RD_EMPTY_SHFT = 0x4,
+};
+/*BIMC Generic */
+
+#define S_REG_BASE(b) ((b) + 0x00048000)
+
+#define S_COMPONENT_INFO_ADDR(b, n) \
+ (S_REG_BASE(b) + (0x8000 * (n)) + 0x00000000)
+enum bimc_s_component_info {
+ S_COMPONENT_INFO_RMSK = 0xffffff,
+ S_COMPONENT_INFO_INSTANCE_BMSK = 0xff0000,
+ S_COMPONENT_INFO_INSTANCE_SHFT = 0x10,
+ S_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00,
+ S_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8,
+ S_COMPONENT_INFO_TYPE_BMSK = 0xff,
+ S_COMPONENT_INFO_TYPE_SHFT = 0x0,
+};
+
+#define S_HW_INFO_ADDR(b, n) \
+ (S_REG_BASE(b) + (0x80000 * (n)) + 0x00000010)
+enum bimc_s_hw_info {
+ S_HW_INFO_RMSK = 0xffffffff,
+ S_HW_INFO_MAJOR_BMSK = 0xff000000,
+ S_HW_INFO_MAJOR_SHFT = 0x18,
+ S_HW_INFO_BRANCH_BMSK = 0xff0000,
+ S_HW_INFO_BRANCH_SHFT = 0x10,
+ S_HW_INFO_MINOR_BMSK = 0xff00,
+ S_HW_INFO_MINOR_SHFT = 0x8,
+ S_HW_INFO_ECO_BMSK = 0xff,
+ S_HW_INFO_ECO_SHFT = 0x0,
+};
+
+
+/* S_SCMO_GENERIC */
+
+#define S_SCMO_REG_BASE(b) ((b) + 0x00048000)
+
+#define S_SCMO_CONFIG_INFO_0_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000020)
+enum bimc_s_scmo_config_info_0 {
+ S_SCMO_CONFIG_INFO_0_RMSK = 0xffffffff,
+ S_SCMO_CONFIG_INFO_0_DATA_WIDTH_BMSK = 0xffff0000,
+ S_SCMO_CONFIG_INFO_0_DATA_WIDTH_SHFT = 0x10,
+ S_SCMO_CONFIG_INFO_0_TID_WIDTH_BMSK = 0xff00,
+ S_SCMO_CONFIG_INFO_0_TID_WIDTH_SHFT = 0x8,
+ S_SCMO_CONFIG_INFO_0_MID_WIDTH_BMSK = 0xff,
+ S_SCMO_CONFIG_INFO_0_MID_WIDTH_SHFT = 0x0,
+};
+
+#define S_SCMO_CONFIG_INFO_1_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000030)
+enum bimc_s_scmo_config_info_1 {
+ S_SCMO_CONFIG_INFO_1_RMSK = 0xffffffff,
+ S_SCMO_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK = 0xffffffff,
+ S_SCMO_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT = 0x0,
+};
+
+#define S_SCMO_CONFIG_INFO_2_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000040)
+enum bimc_s_scmo_config_info_2 {
+ S_SCMO_CONFIG_INFO_2_RMSK = 0xff00ff,
+ S_SCMO_CONFIG_INFO_2_NUM_GLOBAL_MONS_BMSK = 0xff0000,
+ S_SCMO_CONFIG_INFO_2_NUM_GLOBAL_MONS_SHFT = 0x10,
+ S_SCMO_CONFIG_INFO_2_VMID_WIDTH_BMSK = 0xff,
+ S_SCMO_CONFIG_INFO_2_VMID_WIDTH_SHFT = 0x0,
+};
+
+#define S_SCMO_CONFIG_INFO_3_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000050)
+enum bimc_s_scmo_config_info_3 {
+ S_SCMO_CONFIG_INFO_3_RMSK = 0xffffffff,
+ S_SCMO_CONFIG_INFO_3_RCH0_CTRL_DEPTH_BMSK = 0xff000000,
+ S_SCMO_CONFIG_INFO_3_RCH0_CTRL_DEPTH_SHFT = 0x18,
+ S_SCMO_CONFIG_INFO_3_RCH0_DEPTH_BMSK = 0xff0000,
+ S_SCMO_CONFIG_INFO_3_RCH0_DEPTH_SHFT = 0x10,
+ S_SCMO_CONFIG_INFO_3_BCH_DEPTH_BMSK = 0xff00,
+ S_SCMO_CONFIG_INFO_3_BCH_DEPTH_SHFT = 0x8,
+ S_SCMO_CONFIG_INFO_3_WCH_DEPTH_BMSK = 0xff,
+ S_SCMO_CONFIG_INFO_3_WCH_DEPTH_SHFT = 0x0,
+};
+
+#define S_SCMO_CONFIG_INFO_4_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000060)
+enum bimc_s_scmo_config_info_4 {
+ S_SCMO_CONFIG_INFO_4_RMSK = 0xffff,
+ S_SCMO_CONFIG_INFO_4_RCH1_CTRL_DEPTH_BMSK = 0xff00,
+ S_SCMO_CONFIG_INFO_4_RCH1_CTRL_DEPTH_SHFT = 0x8,
+ S_SCMO_CONFIG_INFO_4_RCH1_DEPTH_BMSK = 0xff,
+ S_SCMO_CONFIG_INFO_4_RCH1_DEPTH_SHFT = 0x0,
+};
+
+#define S_SCMO_CONFIG_INFO_5_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000070)
+enum bimc_s_scmo_config_info_5 {
+ S_SCMO_CONFIG_INFO_5_RMSK = 0xffff,
+ S_SCMO_CONFIG_INFO_5_DPE_CQ_DEPTH_BMSK = 0xff00,
+ S_SCMO_CONFIG_INFO_5_DPE_CQ_DEPTH_SHFT = 0x8,
+ S_SCMO_CONFIG_INFO_5_DDR_BUS_WIDTH_BMSK = 0xff,
+ S_SCMO_CONFIG_INFO_5_DDR_BUS_WIDTH_SHFT = 0x0,
+};
+
+#define S_SCMO_CONFIG_INFO_6_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000080)
+enum bimc_s_scmo_config_info_6 {
+ S_SCMO_CONFIG_INFO_6_RMSK = 0x1111,
+ S_SCMO_CONFIG_INFO_6_WBUFC_PIPE_BMSK = 0x1000,
+ S_SCMO_CONFIG_INFO_6_WBUFC_PIPE_SHFT = 0xc,
+ S_SCMO_CONFIG_INFO_6_RDOPT_PIPE_BMSK = 0x100,
+ S_SCMO_CONFIG_INFO_6_RDOPT_PIPE_SHFT = 0x8,
+ S_SCMO_CONFIG_INFO_6_ACHAN_INTF_PIPE_BMSK = 0x10,
+ S_SCMO_CONFIG_INFO_6_ACHAN_INTF_PIPE_SHFT = 0x4,
+ S_SCMO_CONFIG_INFO_6_ADDR_DECODE_HT_BMSK = 0x1,
+ S_SCMO_CONFIG_INFO_6_ADDR_DECODE_HT_SHFT = 0x0,
+};
+
+#define S_SCMO_INT_STATUS_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000100)
+enum bimc_s_scmo_int_status {
+ S_SCMO_INT_STATUS_RMSK = 0x1,
+ S_SCMO_INT_STATUS_ERR_OCCURED_BMSK = 0x1,
+ S_SCMO_INT_STATUS_ERR_OCCURED_SHFT = 0x0,
+};
+
+#define S_SCMO_INT_CLR_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000108)
+enum bimc_s_scmo_int_clr {
+ S_SCMO_INT_CLR_RMSK = 0x1,
+ S_SCMO_INT_CLR_IRQ_CLR_BMSK = 0x1,
+ S_SCMO_INT_CLR_IRQ_CLR_SHFT = 0x0,
+};
+
+#define S_SCMO_INT_EN_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000010c)
+enum bimc_s_scmo_int_en {
+ S_SCMO_INT_EN_RMSK = 0x1,
+ S_SCMO_INT_EN_IRQ_EN_BMSK = 0x1,
+ S_SCMO_INT_EN_IRQ_EN_SHFT = 0x0,
+};
+
+#define S_SCMO_ESYN_ADDR_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000120)
+enum bimc_s_scmo_esyn_addr {
+ S_SCMO_ESYN_ADDR_RMSK = 0xffffffff,
+ S_SCMO_ESYN_ADDR_ESYN_ADDR_ERR_ADDR_BMSK = 0xffffffff,
+ S_SCMO_ESYN_ADDR_ESYN_ADDR_ERR_ADDR_SHFT = 0x0,
+};
+
+#define S_SCMO_ESYN_APACKET_0_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000128)
+enum bimc_s_scmo_esyn_apacket_0 {
+ S_SCMO_ESYN_APACKET_0_RMSK = 0xff1fffff,
+ S_SCMO_ESYN_APACKET_0_ERR_ATID_BMSK = 0xff000000,
+ S_SCMO_ESYN_APACKET_0_ERR_ATID_SHFT = 0x18,
+ S_SCMO_ESYN_APACKET_0_ERR_AVMID_BMSK = 0x1f0000,
+ S_SCMO_ESYN_APACKET_0_ERR_AVMID_SHFT = 0x10,
+ S_SCMO_ESYN_APACKET_0_ERR_AMID_BMSK = 0xffff,
+ S_SCMO_ESYN_APACKET_0_ERR_AMID_SHFT = 0x0,
+};
+
+#define S_SCMO_ESYN_APACKET_1_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000012c)
+enum bimc_s_scmo_esyn_apacket_1 {
+ S_SCMO_ESYN_APACKET_1_RMSK = 0x10ff117,
+ S_SCMO_ESYN_APACKET_1_ERR_CODE_BMSK = 0x1000000,
+ S_SCMO_ESYN_APACKET_1_ERR_CODE_SHFT = 0x18,
+ S_SCMO_ESYN_APACKET_1_ERR_ALEN_BMSK = 0xf0000,
+ S_SCMO_ESYN_APACKET_1_ERR_ALEN_SHFT = 0x10,
+ S_SCMO_ESYN_APACKET_1_ERR_ASIZE_BMSK = 0xe000,
+ S_SCMO_ESYN_APACKET_1_ERR_ASIZE_SHFT = 0xd,
+ S_SCMO_ESYN_APACKET_1_ERR_ABURST_BMSK = 0x1000,
+ S_SCMO_ESYN_APACKET_1_ERR_ABURST_SHFT = 0xc,
+ S_SCMO_ESYN_APACKET_1_ERR_AEXCLUSIVE_BMSK = 0x100,
+ S_SCMO_ESYN_APACKET_1_ERR_AEXCLUSIVE_SHFT = 0x8,
+ S_SCMO_ESYN_APACKET_1_ERR_APRONTS_BMSK = 0x10,
+ S_SCMO_ESYN_APACKET_1_ERR_APRONTS_SHFT = 0x4,
+ S_SCMO_ESYN_APACKET_1_ERR_AOOORD_BMSK = 0x4,
+ S_SCMO_ESYN_APACKET_1_ERR_AOOORD_SHFT = 0x2,
+ S_SCMO_ESYN_APACKET_1_ERR_AOOOWR_BMSK = 0x2,
+ S_SCMO_ESYN_APACKET_1_ERR_AOOOWR_SHFT = 0x1,
+ S_SCMO_ESYN_APACKET_1_ERR_AWRITE_BMSK = 0x1,
+ S_SCMO_ESYN_APACKET_1_ERR_AWRITE_SHFT = 0x0,
+};
+
+#define S_SCMO_CLK_CTRL_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000200)
+enum bimc_s_scmo_clk_ctrl {
+ S_SCMO_CLK_CTRL_RMSK = 0xffff1111,
+ S_SCMO_CLK_CTRL_PEN_CMD_CG_EN_BMSK = 0x10000,
+ S_SCMO_CLK_CTRL_PEN_CMD_CG_EN_SHFT = 0x10,
+ S_SCMO_CLK_CTRL_RCH_CG_EN_BMSK = 0x1000,
+ S_SCMO_CLK_CTRL_RCH_CG_EN_SHFT = 0xc,
+ S_SCMO_CLK_CTRL_FLUSH_CG_EN_BMSK = 0x100,
+ S_SCMO_CLK_CTRL_FLUSH_CG_EN_SHFT = 0x8,
+ S_SCMO_CLK_CTRL_WCH_CG_EN_BMSK = 0x10,
+ S_SCMO_CLK_CTRL_WCH_CG_EN_SHFT = 0x4,
+ S_SCMO_CLK_CTRL_ACH_CG_EN_BMSK = 0x1,
+ S_SCMO_CLK_CTRL_ACH_CG_EN_SHFT = 0x0,
+};
+
+#define S_SCMO_SLV_INTERLEAVE_CFG_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000400)
+enum bimc_s_scmo_slv_interleave_cfg {
+ S_SCMO_SLV_INTERLEAVE_CFG_RMSK = 0xff,
+ S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS1_BMSK = 0x10,
+ S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS1_SHFT = 0x4,
+ S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS0_BMSK = 0x1,
+ S_SCMO_SLV_INTERLEAVE_CFG_INTERLEAVE_CS0_SHFT = 0x0,
+};
+
+#define S_SCMO_ADDR_BASE_CSn_ADDR(b, n, o) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000410 + 0x4 * (o))
+enum bimc_s_scmo_addr_base_csn {
+ S_SCMO_ADDR_BASE_CSn_RMSK = 0xffff,
+ S_SCMO_ADDR_BASE_CSn_MAXn = 1,
+ S_SCMO_ADDR_BASE_CSn_ADDR_BASE_BMSK = 0xfc,
+ S_SCMO_ADDR_BASE_CSn_ADDR_BASE_SHFT = 0x2,
+};
+
+#define S_SCMO_ADDR_MAP_CSn_ADDR(b, n, o) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000420 + 0x4 * (o))
+enum bimc_s_scmo_addr_map_csn {
+ S_SCMO_ADDR_MAP_CSn_RMSK = 0xffff,
+ S_SCMO_ADDR_MAP_CSn_MAXn = 1,
+ S_SCMO_ADDR_MAP_CSn_RANK_EN_BMSK = 0x8000,
+ S_SCMO_ADDR_MAP_CSn_RANK_EN_SHFT = 0xf,
+ S_SCMO_ADDR_MAP_CSn_ADDR_MODE_BMSK = 0x1000,
+ S_SCMO_ADDR_MAP_CSn_ADDR_MODE_SHFT = 0xc,
+ S_SCMO_ADDR_MAP_CSn_BANK_SIZE_BMSK = 0x100,
+ S_SCMO_ADDR_MAP_CSn_BANK_SIZE_SHFT = 0x8,
+ S_SCMO_ADDR_MAP_CSn_ROW_SIZE_BMSK = 0x30,
+ S_SCMO_ADDR_MAP_CSn_ROW_SIZE_SHFT = 0x4,
+ S_SCMO_ADDR_MAP_CSn_COL_SIZE_BMSK = 0x3,
+ S_SCMO_ADDR_MAP_CSn_COL_SIZE_SHFT = 0x0,
+};
+
+#define S_SCMO_ADDR_MASK_CSn_ADDR(b, n, o) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000430 + 0x4 * (0))
+enum bimc_s_scmo_addr_mask_csn {
+ S_SCMO_ADDR_MASK_CSn_RMSK = 0xffff,
+ S_SCMO_ADDR_MASK_CSn_MAXn = 1,
+ S_SCMO_ADDR_MASK_CSn_ADDR_MASK_BMSK = 0xfc,
+ S_SCMO_ADDR_MASK_CSn_ADDR_MASK_SHFT = 0x2,
+};
+
+#define S_SCMO_SLV_STATUS_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000450)
+enum bimc_s_scmo_slv_status {
+ S_SCMO_SLV_STATUS_RMSK = 0xff3,
+ S_SCMO_SLV_STATUS_GLOBAL_MONS_IN_USE_BMSK = 0xff0,
+ S_SCMO_SLV_STATUS_GLOBAL_MONS_IN_USE_SHFT = 0x4,
+ S_SCMO_SLV_STATUS_SLAVE_IDLE_BMSK = 0x3,
+ S_SCMO_SLV_STATUS_SLAVE_IDLE_SHFT = 0x0,
+};
+
+#define S_SCMO_CMD_BUF_CFG_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000500)
+enum bimc_s_scmo_cmd_buf_cfg {
+ S_SCMO_CMD_BUF_CFG_RMSK = 0xf1f,
+ S_SCMO_CMD_BUF_CFG_CMD_ORDERING_BMSK = 0x300,
+ S_SCMO_CMD_BUF_CFG_CMD_ORDERING_SHFT = 0x8,
+ S_SCMO_CMD_BUF_CFG_HP_CMD_AREQPRIO_MAP_BMSK = 0x10,
+ S_SCMO_CMD_BUF_CFG_HP_CMD_AREQPRIO_MAP_SHFT = 0x4,
+ S_SCMO_CMD_BUF_CFG_HP_CMD_Q_DEPTH_BMSK = 0x7,
+ S_SCMO_CMD_BUF_CFG_HP_CMD_Q_DEPTH_SHFT = 0x0,
+};
+
+#define S_SCM_CMD_BUF_STATUS_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000520)
+enum bimc_s_scm_cmd_buf_status {
+ S_SCMO_CMD_BUF_STATUS_RMSK = 0x77,
+ S_SCMO_CMD_BUF_STATUS_HP_CMD_BUF_ENTRIES_IN_USE_BMSK = 0x70,
+ S_SCMO_CMD_BUF_STATUS_HP_CMD_BUF_ENTRIES_IN_USE_SHFT = 0x4,
+ S_SCMO_CMD_BUF_STATUS_LP_CMD_BUF_ENTRIES_IN_USE_BMSK = 0x7,
+ S_SCMO_CMD_BUF_STATUS_LP_CMD_BUF_ENTRIES_IN_USE_SHFT = 0x0,
+};
+
+#define S_SCMO_RCH_SEL_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000540)
+enum bimc_s_scmo_rch_sel {
+ S_SCMO_RCH_SEL_RMSK = 0xffffffff,
+ S_SCMO_CMD_BUF_STATUS_RCH_PORTS_BMSK = 0xffffffff,
+ S_SCMO_CMD_BUF_STATUS_RCH_PORTS_SHFT = 0x0,
+};
+
+#define S_SCMO_RCH_BKPR_CFG_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000544)
+enum bimc_s_scmo_rch_bkpr_cfg {
+ S_SCMO_RCH_BKPR_CFG_RMSK = 0xffffffff,
+ S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_HI_TH_BMSK = 0x3f000000,
+ S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_HI_TH_SHFT = 0x18,
+ S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_LO_TH_BMSK = 0x3f0000,
+ S_SCMO_RCH_BKPR_CFG_RCH1_FIFO_BKPR_LO_TH_SHFT = 0x10,
+ S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_HI_TH_BMSK = 0x3f00,
+ S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_HI_TH_SHFT = 0x8,
+ S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_LO_TH_BMSK = 0x3f,
+ S_SCMO_RCH_BKPR_CFG_RCH0_FIFO_BKPR_LO_TH_SHFT = 0x0,
+};
+
+#define S_SCMO_RCH_STATUS_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000560)
+enum bimc_s_scmo_rch_status {
+ S_SCMO_RCH_STATUS_RMSK = 0x33333,
+ S_SCMO_RCH_STATUS_PRQ_FIFO_FULL_BMSK = 0x20000,
+ S_SCMO_RCH_STATUS_PRQ_FIFO_FULL_SHFT = 0x11,
+ S_SCMO_RCH_STATUS_PRQ_FIFO_EMPTY_BMSK = 0x10000,
+ S_SCMO_RCH_STATUS_PRQ_FIFO_EMPTY_SHFT = 0x10,
+ S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_FULL_BMSK = 0x2000,
+ S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_FULL_SHFT = 0xd,
+ S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_EMPTY_BMSK = 0x1000,
+ S_SCMO_RCH_STATUS_RCH1_QUAL_FIFO_EMPTY_SHFT = 0xc,
+ S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_FULL_BMSK = 0x200,
+ S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_FULL_SHFT = 0x9,
+ S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_EMPTY_BMSK = 0x100,
+ S_SCMO_RCH_STATUS_RCH1_DATA_FIFO_EMPTY_SHFT = 0x8,
+ S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_FULL_BMSK = 0x20,
+ S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_FULL_SHFT = 0x5,
+ S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_EMPTY_BMSK = 0x10,
+ S_SCMO_RCH_STATUS_RCH0_QUAL_FIFO_EMPTY_SHFT = 0x4,
+ S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_FULL_BMSK = 0x2,
+ S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_FULL_SHFT = 0x1,
+ S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_EMPTY_BMSK = 0x1,
+ S_SCMO_RCH_STATUS_RCH0_DATA_FIFO_EMPTY_SHFT = 0x0,
+};
+
+#define S_SCMO_WCH_BUF_CFG_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000580)
+enum bimc_s_scmo_wch_buf_cfg {
+ S_SCMO_WCH_BUF_CFG_RMSK = 0xff,
+ S_SCMO_WCH_BUF_CFG_WRITE_BLOCK_READ_BMSK = 0x10,
+ S_SCMO_WCH_BUF_CFG_WRITE_BLOCK_READ_SHFT = 0x4,
+ S_SCMO_WCH_BUF_CFG_COALESCE_EN_BMSK = 0x1,
+ S_SCMO_WCH_BUF_CFG_COALESCE_EN_SHFT = 0x0,
+};
+
+#define S_SCMO_WCH_STATUS_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005a0)
+enum bimc_s_scmo_wch_status {
+ S_SCMO_WCH_STATUS_RMSK = 0x333,
+ S_SCMO_WCH_STATUS_BRESP_FIFO_FULL_BMSK = 0x200,
+ S_SCMO_WCH_STATUS_BRESP_FIFO_FULL_SHFT = 0x9,
+ S_SCMO_WCH_STATUS_BRESP_FIFO_EMPTY_BMSK = 0x100,
+ S_SCMO_WCH_STATUS_BRESP_FIFO_EMPTY_SHFT = 0x8,
+ S_SCMO_WCH_STATUS_WDATA_FIFO_FULL_BMSK = 0x20,
+ S_SCMO_WCH_STATUS_WDATA_FIFO_FULL_SHFT = 0x5,
+ S_SCMO_WCH_STATUS_WDATA_FIFO_EMPTY_BMSK = 0x10,
+ S_SCMO_WCH_STATUS_WDATA_FIFO_EMPTY_SHFT = 0x4,
+ S_SCMO_WCH_STATUS_WBUF_FULL_BMSK = 0x2,
+ S_SCMO_WCH_STATUS_WBUF_FULL_SHFT = 0x1,
+ S_SCMO_WCH_STATUS_WBUF_EMPTY_BMSK = 0x1,
+ S_SCMO_WCH_STATUS_WBUF_EMPTY_SHFT = 0x0,
+};
+
+#define S_SCMO_FLUSH_CFG_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005c0)
+enum bimc_s_scmo_flush_cfg {
+ S_SCMO_FLUSH_CFG_RMSK = 0xffffffff,
+ S_SCMO_FLUSH_CFG_FLUSH_IN_ORDER_BMSK = 0x10000000,
+ S_SCMO_FLUSH_CFG_FLUSH_IN_ORDER_SHFT = 0x1c,
+ S_SCMO_FLUSH_CFG_FLUSH_IDLE_DELAY_BMSK = 0x3ff0000,
+ S_SCMO_FLUSH_CFG_FLUSH_IDLE_DELAY_SHFT = 0x10,
+ S_SCMO_FLUSH_CFG_FLUSH_UPPER_LIMIT_BMSK = 0xf00,
+ S_SCMO_FLUSH_CFG_FLUSH_UPPER_LIMIT_SHFT = 0x8,
+ S_SCMO_FLUSH_CFG_FLUSH_LOWER_LIMIT_BMSK = 0xf,
+ S_SCMO_FLUSH_CFG_FLUSH_LOWER_LIMIT_SHFT = 0x0,
+};
+
+#define S_SCMO_FLUSH_CMD_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x000005c4)
+enum bimc_s_scmo_flush_cmd {
+ S_SCMO_FLUSH_CMD_RMSK = 0xf,
+ S_SCMO_FLUSH_CMD_FLUSH_ALL_BUF_BMSK = 0x3,
+ S_SCMO_FLUSH_CMD_FLUSH_ALL_BUF_SHFT = 0x0,
+};
+
+#define S_SCMO_CMD_OPT_CFG0_ADDR(b, n) \
+ (S_SCM0_REG_BASE(b) + (0x8000 * (n)) + 0x00000700)
+enum bimc_s_scmo_cmd_opt_cfg0 {
+ S_SCMO_CMD_OPT_CFG0_RMSK = 0xffffff,
+ S_SCMO_CMD_OPT_CFG0_IGNORE_BANK_UNAVL_BMSK = 0x100000,
+ S_SCMO_CMD_OPT_CFG0_IGNORE_BANK_UNAVL_SHFT = 0x14,
+ S_SCMO_CMD_OPT_CFG0_MASK_CMDOUT_PRI_BMSK = 0x10000,
+ S_SCMO_CMD_OPT_CFG0_MASK_CMDOUT_PRI_SHFT = 0x10,
+ S_SCMO_CMD_OPT_CFG0_DPE_CMD_REORDERING_BMSK = 0x1000,
+ S_SCMO_CMD_OPT_CFG0_DPE_CMD_REORDERING_SHFT = 0xc,
+ S_SCMO_CMD_OPT_CFG0_WR_OPT_EN_BMSK = 0x100,
+ S_SCMO_CMD_OPT_CFG0_WR_OPT_EN_SHFT = 0x8,
+ S_SCMO_CMD_OPT_CFG0_RD_OPT_EN_BMSK = 0x10,
+ S_SCMO_CMD_OPT_CFG0_RD_OPT_EN_SHFT = 0x4,
+ S_SCMO_CMD_OPT_CFG0_PAGE_MGMT_POLICY_BMSK = 0x1,
+ S_SCMO_CMD_OPT_CFG0_PAGE_MGMT_POLICY_SHFT = 0x0,
+};
+
+#define S_SCMO_CMD_OPT_CFG1_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000704)
+enum bimc_s_scmo_cmd_opt_cfg1 {
+ S_SCMO_CMD_OPT_CFG1_RMSK = 0xffffffff,
+ S_SCMO_CMD_OPT_CFG1_HSTP_CMD_TIMEOUT_BMSK = 0x1f000000,
+ S_SCMO_CMD_OPT_CFG1_HSTP_CMD_TIMEOUT_SHFT = 0x18,
+ S_SCMO_CMD_OPT_CFG1_HP_CMD_TIMEOUT_BMSK = 0x1f0000,
+ S_SCMO_CMD_OPT_CFG1_HP_CMD_TIMEOUT_SHFT = 0x10,
+ S_SCMO_CMD_OPT_CFG1_MP_CMD_TIMEOUT_BMSK = 0x1f00,
+ S_SCMO_CMD_OPT_CFG1_MP_CMD_TIMEOUT_SHFT = 0x8,
+ S_SCMO_CMD_OPT_CFG1_LP_CMD_TIMEOUT_BMSK = 0x1f,
+ S_SCMO_CMD_OPT_CFG1_LP_CMD_TIMEOUT_SHFT = 0x0,
+};
+
+#define S_SCMO_CMD_OPT_CFG2_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x00000708)
+enum bimc_s_scmo_cmd_opt_cfg2 {
+ S_SCMO_CMD_OPT_CFG2_RMSK = 0xff,
+ S_SCMO_CMD_OPT_CFG2_RWOPT_CMD_TIMEOUT_BMSK = 0xf,
+ S_SCMO_CMD_OPT_CFG2_RWOPT_CMD_TIMEOUT_SHFT = 0x0,
+};
+
+#define S_SCMO_CMD_OPT_CFG3_ADDR(b, n) \
+ (S_SCMO_REG_BASE(b) + (0x8000 * (n)) + 0x0000070c)
+enum bimc_s_scmo_cmd_opt_cfg3 {
+ S_SCMO_CMD_OPT_CFG3_RMSK = 0xff,
+ S_SCMO_CMD_OPT_CFG3_FLUSH_CMD_TIMEOUT_BMSK = 0xf,
+ S_SCMO_CMD_OPT_CFG3_FLUSH_CMD_TIMEOUT_SHFT = 0x0,
+};
+
+/* S_SWAY_GENERIC */
+#define S_SWAY_REG_BASE(b) ((b) + 0x00048000)
+
+#define S_SWAY_CONFIG_INFO_0_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000020)
+enum bimc_s_sway_config_info_0 {
+ S_SWAY_CONFIG_INFO_0_RMSK = 0xff0000ff,
+ S_SWAY_CONFIG_INFO_0_SYNC_MODE_BMSK = 0xff000000,
+ S_SWAY_CONFIG_INFO_0_SYNC_MODE_SHFT = 0x18,
+ S_SWAY_CONFIG_INFO_0_FUNC_BMSK = 0xff,
+ S_SWAY_CONFIG_INFO_0_FUNC_SHFT = 0x0,
+};
+
+#define S_SWAY_CONFIG_INFO_1_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000030)
+enum bimc_s_sway_config_info_1 {
+ S_SWAY_CONFIG_INFO_1_RMSK = 0xffffffff,
+ S_SWAY_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK = 0xffffffff,
+ S_SWAY_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT = 0x0,
+};
+
+#define S_SWAY_CONFIG_INFO_2_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000040)
+enum bimc_s_sway_config_info_2 {
+ S_SWAY_CONFIG_INFO_2_RMSK = 0xffff0000,
+ S_SWAY_CONFIG_INFO_2_MPORT_CONNECTIVITY_BMSK = 0xffff0000,
+ S_SWAY_CONFIG_INFO_2_MPORT_CONNECTIVITY_SHFT = 0x10,
+};
+
+#define S_SWAY_CONFIG_INFO_3_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000050)
+enum bimc_s_sway_config_info_3 {
+ S_SWAY_CONFIG_INFO_3_RMSK = 0xffffffff,
+ S_SWAY_CONFIG_INFO_3_RCH0_DEPTH_BMSK = 0xff000000,
+ S_SWAY_CONFIG_INFO_3_RCH0_DEPTH_SHFT = 0x18,
+ S_SWAY_CONFIG_INFO_3_BCH_DEPTH_BMSK = 0xff0000,
+ S_SWAY_CONFIG_INFO_3_BCH_DEPTH_SHFT = 0x10,
+ S_SWAY_CONFIG_INFO_3_WCH_DEPTH_BMSK = 0xff,
+ S_SWAY_CONFIG_INFO_3_WCH_DEPTH_SHFT = 0x0,
+};
+
+#define S_SWAY_CONFIG_INFO_4_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000060)
+enum bimc_s_sway_config_info_4 {
+ S_SWAY_CONFIG_INFO_4_RMSK = 0x800000ff,
+ S_SWAY_CONFIG_INFO_4_DUAL_RCH_EN_BMSK = 0x80000000,
+ S_SWAY_CONFIG_INFO_4_DUAL_RCH_EN_SHFT = 0x1f,
+ S_SWAY_CONFIG_INFO_4_RCH1_DEPTH_BMSK = 0xff,
+ S_SWAY_CONFIG_INFO_4_RCH1_DEPTH_SHFT = 0x0,
+};
+
+#define S_SWAY_CONFIG_INFO_5_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000070)
+enum bimc_s_sway_config_info_5 {
+ S_SWAY_CONFIG_INFO_5_RMSK = 0x800000ff,
+ S_SWAY_CONFIG_INFO_5_QCH_EN_BMSK = 0x80000000,
+ S_SWAY_CONFIG_INFO_5_QCH_EN_SHFT = 0x1f,
+ S_SWAY_CONFIG_INFO_5_QCH_DEPTH_BMSK = 0xff,
+ S_SWAY_CONFIG_INFO_5_QCH_DEPTH_SHFT = 0x0,
+};
+
+#define S_SWAY_CONFIG_INFO_6_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000080)
+enum bimc_s_sway_config_info_6 {
+ S_SWAY_CONFIG_INFO_6_RMSK = 0x1,
+ S_SWAY_CONFIG_INFO_6_S2SW_PIPELINE_EN_BMSK = 0x1,
+ S_SWAY_CONFIG_INFO_6_S2SW_PIPELINE_EN_SHFT = 0x0,
+};
+
+#define S_SWAY_INT_STATUS_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000100)
+enum bimc_s_sway_int_status {
+ S_SWAY_INT_STATUS_RMSK = 0x3,
+ S_SWAY_INT_STATUS_RFU_BMSK = 0x3,
+ S_SWAY_INT_STATUS_RFU_SHFT = 0x0,
+};
+
+#define S_SWAY_INT_CLR_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000108)
+enum bimc_s_sway_int_clr {
+ S_SWAY_INT_CLR_RMSK = 0x3,
+ S_SWAY_INT_CLR_RFU_BMSK = 0x3,
+ S_SWAY_INT_CLR_RFU_SHFT = 0x0,
+};
+
+
+#define S_SWAY_INT_EN_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x0000010c)
+enum bimc_s_sway_int_en {
+ S_SWAY_INT_EN_RMSK = 0x3,
+ S_SWAY_INT_EN_RFU_BMSK = 0x3,
+ S_SWAY_INT_EN_RFU_SHFT = 0x0,
+};
+
+#define S_SWAY_CLK_CTRL_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000200)
+enum bimc_s_sway_clk_ctrl {
+ S_SWAY_CLK_CTRL_RMSK = 0x3,
+ S_SWAY_CLK_CTRL_SLAVE_CLK_GATING_EN_BMSK = 0x2,
+ S_SWAY_CLK_CTRL_SLAVE_CLK_GATING_EN_SHFT = 0x1,
+ S_SWAY_CLK_CTRL_CORE_CLK_GATING_EN_BMSK = 0x1,
+ S_SWAY_CLK_CTRL_CORE_CLK_GATING_EN_SHFT = 0x0,
+};
+
+#define S_SWAY_RCH_SEL_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000210)
+enum bimc_s_sway_rch_sel {
+ S_SWAY_RCH_SEL_RMSK = 0x7f,
+ S_SWAY_RCH_SEL_UNUSED_BMSK = 0x7f,
+ S_SWAY_RCH_SEL_UNUSED_SHFT = 0x0,
+};
+
+
+#define S_SWAY_MAX_OUTSTANDING_REQS_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000220)
+enum bimc_s_sway_max_outstanding_reqs {
+ S_SWAY_MAX_OUTSTANDING_REQS_RMSK = 0xffff,
+ S_SWAY_MAX_OUTSTANDING_REQS_WRITE_BMSK = 0xff00,
+ S_SWAY_MAX_OUTSTANDING_REQS_WRITE_SHFT = 0x8,
+ S_SWAY_MAX_OUTSTANDING_REQS_READ_BMSK = 0xff,
+ S_SWAY_MAX_OUTSTANDING_REQS_READ_SHFT = 0x0,
+};
+
+
+#define S_SWAY_BUF_STATUS_0_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000400)
+enum bimc_s_sway_buf_status_0 {
+ S_SWAY_BUF_STATUS_0_RMSK = 0xf0300f03,
+ S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_FULL_BMSK = 0x80000000,
+ S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_FULL_SHFT = 0x1f,
+ S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_EMPTY_BMSK = 0x40000000,
+ S_SWAY_BUF_STATUS_0_RCH0_DATA_RD_EMPTY_SHFT = 0x1e,
+ S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_FULL_BMSK = 0x20000000,
+ S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_FULL_SHFT = 0x1d,
+ S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_EMPTY_BMSK = 0x10000000,
+ S_SWAY_BUF_STATUS_0_RCH0_CTRL_RD_EMPTY_SHFT = 0x1c,
+ S_SWAY_BUF_STATUS_0_BCH_RD_FULL_BMSK = 0x200000,
+ S_SWAY_BUF_STATUS_0_BCH_RD_FULL_SHFT = 0x15,
+ S_SWAY_BUF_STATUS_0_BCH_RD_EMPTY_BMSK = 0x100000,
+ S_SWAY_BUF_STATUS_0_BCH_RD_EMPTY_SHFT = 0x14,
+ S_SWAY_BUF_STATUS_0_WCH_DATA_WR_FULL_BMSK = 0x800,
+ S_SWAY_BUF_STATUS_0_WCH_DATA_WR_FULL_SHFT = 0xb,
+ S_SWAY_BUF_STATUS_0_WCH_DATA_WR_EMPTY_BMSK = 0x400,
+ S_SWAY_BUF_STATUS_0_WCH_DATA_WR_EMPTY_SHFT = 0xa,
+ S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_FULL_BMSK = 0x200,
+ S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_FULL_SHFT = 0x9,
+ S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_EMPTY_BMSK = 0x100,
+ S_SWAY_BUF_STATUS_0_WCH_CTRL_WR_EMPTY_SHFT = 0x8,
+ S_SWAY_BUF_STATUS_0_ACH_WR_FULL_BMSK = 0x2,
+ S_SWAY_BUF_STATUS_0_ACH_WR_FULL_SHFT = 0x1,
+ S_SWAY_BUF_STATUS_0_ACH_WR_EMPTY_BMSK = 0x1,
+ S_SWAY_BUF_STATUS_0_ACH_WR_EMPTY_SHFT = 0x0,
+};
+
+#define S_SWAY_BUF_STATUS_1_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000410)
+enum bimc_s_sway_buf_status_1 {
+ S_SWAY_BUF_STATUS_1_RMSK = 0xf0,
+ S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_FULL_BMSK = 0x80,
+ S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_FULL_SHFT = 0x7,
+ S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_EMPTY_BMSK = 0x40,
+ S_SWAY_BUF_STATUS_1_RCH1_DATA_RD_EMPTY_SHFT = 0x6,
+ S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_FULL_BMSK = 0x20,
+ S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_FULL_SHFT = 0x5,
+ S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_EMPTY_BMSK = 0x10,
+ S_SWAY_BUF_STATUS_1_RCH1_CTRL_RD_EMPTY_SHFT = 0x4,
+};
+
+#define S_SWAY_BUF_STATUS_2_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000420)
+enum bimc_s_sway_buf_status_2 {
+ S_SWAY_BUF_STATUS_2_RMSK = 0x30,
+ S_SWAY_BUF_STATUS_2_QCH_RD_FULL_BMSK = 0x20,
+ S_SWAY_BUF_STATUS_2_QCH_RD_FULL_SHFT = 0x5,
+ S_SWAY_BUF_STATUS_2_QCH_RD_EMPTY_BMSK = 0x10,
+ S_SWAY_BUF_STATUS_2_QCH_RD_EMPTY_SHFT = 0x4,
+};
+
+/* S_ARB_GENERIC */
+
+#define S_ARB_REG_BASE(b) ((b) + 0x00049000)
+
+#define S_ARB_COMPONENT_INFO_ADDR(b, n) \
+ (S_SWAY_REG_BASE(b) + (0x8000 * (n)) + 0x00000000)
+enum bimc_s_arb_component_info {
+ S_ARB_COMPONENT_INFO_RMSK = 0xffffff,
+ S_ARB_COMPONENT_INFO_INSTANCE_BMSK = 0xff0000,
+ S_ARB_COMPONENT_INFO_INSTANCE_SHFT = 0x10,
+ S_ARB_COMPONENT_INFO_SUB_TYPE_BMSK = 0xff00,
+ S_ARB_COMPONENT_INFO_SUB_TYPE_SHFT = 0x8,
+ S_ARB_COMPONENT_INFO_TYPE_BMSK = 0xff,
+ S_ARB_COMPONENT_INFO_TYPE_SHFT = 0x0,
+};
+
+#define S_ARB_CONFIG_INFO_0_ADDR(b, n) \
+ (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000020)
+enum bimc_s_arb_config_info_0 {
+ S_ARB_CONFIG_INFO_0_RMSK = 0x800000ff,
+ S_ARB_CONFIG_INFO_0_ARB2SW_PIPELINE_EN_BMSK = 0x80000000,
+ S_ARB_CONFIG_INFO_0_ARB2SW_PIPELINE_EN_SHFT = 0x1f,
+ S_ARB_CONFIG_INFO_0_FUNC_BMSK = 0xff,
+ S_ARB_CONFIG_INFO_0_FUNC_SHFT = 0x0,
+};
+
+#define S_ARB_CONFIG_INFO_1_ADDR(b, n) \
+ (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000030)
+enum bimc_s_arb_config_info_1 {
+ S_ARB_CONFIG_INFO_1_RMSK = 0xffffffff,
+ S_ARB_CONFIG_INFO_1_MPORT_CONNECTIVITY_BMSK = 0xffffffff,
+ S_ARB_CONFIG_INFO_1_MPORT_CONNECTIVITY_SHFT = 0x0,
+};
+
+#define S_ARB_CLK_CTRL_ADDR(b) \
+ (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000200)
+enum bimc_s_arb_clk_ctrl {
+ S_ARB_CLK_CTRL_RMSK = 0x1,
+ S_ARB_CLK_CTRL_SLAVE_CLK_GATING_EN_BMSK = 0x2,
+ S_ARB_CLK_CTRL_SLAVE_CLK_GATING_EN_SHFT = 0x1,
+ S_ARB_CLK_CTRL_CORE_CLK_GATING_EN_BMSK = 0x1,
+ S_ARB_CLK_CTRL_CORE_CLK_GATING_EN_SHFT = 0x0,
+ S_ARB_CLK_CTRL_CLK_GATING_EN_BMSK = 0x1,
+ S_ARB_CLK_CTRL_CLK_GATING_EN_SHFT = 0x0,
+};
+
+#define S_ARB_MODE_ADDR(b, n) \
+ (S_ARB_REG_BASE(b) + (0x8000 * (n)) + 0x00000210)
+enum bimc_s_arb_mode {
+ S_ARB_MODE_RMSK = 0xf0000001,
+ S_ARB_MODE_WR_GRANTS_AHEAD_BMSK = 0xf0000000,
+ S_ARB_MODE_WR_GRANTS_AHEAD_SHFT = 0x1c,
+ S_ARB_MODE_PRIO_RR_EN_BMSK = 0x1,
+ S_ARB_MODE_PRIO_RR_EN_SHFT = 0x0,
+};
+
+#define BKE_HEALTH_MASK \
+ (M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK |\
+ M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK |\
+ M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK)
+
+#define BKE_HEALTH_VAL(limit, areq, plvl) \
+ ((((limit) << M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT) & \
+ M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK) | \
+ (((areq) << M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT) & \
+ M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK) | \
+ (((plvl) << M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT) & \
+ M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK))
+
+#define MAX_GRANT_PERIOD \
+ (M_BKE_GP_GP_BMSK >> \
+ M_BKE_GP_GP_SHFT)
+
+#define MAX_GC \
+ (M_BKE_GC_GC_BMSK >> \
+ M_BKE_GC_GC_SHFT)
+
+static int bimc_div(uint64_t *a, uint32_t b)
+{
+ if ((*a > 0) && (*a < b))
+ return 1;
+ else
+ return do_div(*a, b);
+}
+
+#define ENABLE(val) ((val) == 1 ? 1 : 0)
+void msm_bus_bimc_set_mas_clk_gate(struct msm_bus_bimc_info *binfo,
+ uint32_t mas_index, struct msm_bus_bimc_clk_gate *bgate)
+{
+ uint32_t val, mask, reg_val;
+ void __iomem *addr;
+
+ reg_val = readl_relaxed(M_CLK_CTRL_ADDR(binfo->base,
+ mas_index)) & M_CLK_CTRL_RMSK;
+ addr = M_CLK_CTRL_ADDR(binfo->base, mas_index);
+ mask = (M_CLK_CTRL_MAS_CLK_GATING_EN_BMSK |
+ M_CLK_CTRL_CORE_CLK_GATING_EN_BMSK);
+ val = (bgate->core_clk_gate_en <<
+ M_CLK_CTRL_MAS_CLK_GATING_EN_SHFT) |
+ bgate->port_clk_gate_en;
+ writel_relaxed(((reg_val & (~mask)) | (val & mask)), addr);
+ /* Ensure clock gating enable mask is set before exiting */
+ wmb();
+}
+
+void msm_bus_bimc_arb_en(struct msm_bus_bimc_info *binfo,
+ uint32_t slv_index, bool en)
+{
+ uint32_t reg_val, reg_mask_val, enable, val;
+
+ reg_mask_val = (readl_relaxed(S_ARB_CONFIG_INFO_0_ADDR(binfo->
+ base, slv_index)) & S_ARB_CONFIG_INFO_0_FUNC_BMSK)
+ >> S_ARB_CONFIG_INFO_0_FUNC_SHFT;
+ enable = ENABLE(en);
+ val = enable << S_ARB_MODE_PRIO_RR_EN_SHFT;
+ if (reg_mask_val == BIMC_ARB_MODE_PRIORITY_RR) {
+ reg_val = readl_relaxed(S_ARB_CONFIG_INFO_0_ADDR(binfo->
+ base, slv_index)) & S_ARB_MODE_RMSK;
+ writel_relaxed(((reg_val & (~(S_ARB_MODE_PRIO_RR_EN_BMSK))) |
+ (val & S_ARB_MODE_PRIO_RR_EN_BMSK)),
+ S_ARB_MODE_ADDR(binfo->base, slv_index));
+ /* Ensure arbitration mode is set before returning */
+ wmb();
+ }
+}
+
+static void set_qos_mode(void __iomem *baddr, uint32_t index, uint32_t val0,
+ uint32_t val1, uint32_t val2)
+{
+ uint32_t reg_val, val;
+
+ reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(baddr,
+ index)) & M_PRIOLVL_OVERRIDE_RMSK;
+ val = val0 << M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT;
+ writel_relaxed(((reg_val & ~(M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK))
+ | (val & M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)),
+ M_PRIOLVL_OVERRIDE_ADDR(baddr, index));
+ reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(baddr, index)) &
+ M_RD_CMD_OVERRIDE_RMSK;
+ val = val1 << M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT;
+ writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK
+ )) | (val & M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)),
+ M_RD_CMD_OVERRIDE_ADDR(baddr, index));
+ reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR(baddr, index)) &
+ M_WR_CMD_OVERRIDE_RMSK;
+ val = val2 << M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT;
+ writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK
+ )) | (val & M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)),
+ M_WR_CMD_OVERRIDE_ADDR(baddr, index));
+ /* Ensure the priority register writes go through */
+ wmb();
+}
+
+static void msm_bus_bimc_set_qos_mode(struct msm_bus_bimc_info *binfo,
+ uint32_t mas_index, uint8_t qmode_sel)
+{
+ uint32_t reg_val, val;
+
+ switch (qmode_sel) {
+ case BIMC_QOS_MODE_FIXED:
+ reg_val = readl_relaxed(M_BKE_EN_ADDR(binfo->base,
+ mas_index)) & M_BKE_EN_RMSK;
+ writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)),
+ M_BKE_EN_ADDR(binfo->base, mas_index));
+ /* Ensure that the book-keeping register writes
+ * go through before setting QoS mode.
+ * QoS mode registers might write beyond 1K
+ * boundary in future
+ */
+ wmb();
+ set_qos_mode(binfo->base, mas_index, 1, 1, 1);
+ break;
+
+ case BIMC_QOS_MODE_BYPASS:
+ reg_val = readl_relaxed(M_BKE_EN_ADDR(binfo->base,
+ mas_index)) & M_BKE_EN_RMSK;
+ writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)),
+ M_BKE_EN_ADDR(binfo->base, mas_index));
+ /* Ensure that the book-keeping register writes
+ * go through before setting QoS mode.
+ * QoS mode registers might write beyond 1K
+ * boundary in future
+ */
+ wmb();
+ set_qos_mode(binfo->base, mas_index, 0, 0, 0);
+ break;
+
+ case BIMC_QOS_MODE_REGULATOR:
+ case BIMC_QOS_MODE_LIMITER:
+ set_qos_mode(binfo->base, mas_index, 0, 0, 0);
+ reg_val = readl_relaxed(M_BKE_EN_ADDR(binfo->base,
+ mas_index)) & M_BKE_EN_RMSK;
+ val = 1 << M_BKE_EN_EN_SHFT;
+ /* Ensure that the book-keeping register writes
+ * go through before setting QoS mode.
+ * QoS mode registers might write beyond 1K
+ * boundary in future
+ */
+ wmb();
+ writel_relaxed(((reg_val & (~M_BKE_EN_EN_BMSK)) | (val &
+ M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(binfo->base,
+ mas_index));
+ break;
+ default:
+ break;
+ }
+}
+
+static void set_qos_prio_rl(void __iomem *addr, uint32_t rmsk,
+ uint8_t index, struct msm_bus_bimc_qos_mode *qmode)
+{
+ uint32_t reg_val, val0, val;
+
+ /* Note, addr is already passed with right mas_index */
+ reg_val = readl_relaxed(addr) & rmsk;
+ val0 = BKE_HEALTH_VAL(qmode->rl.qhealth[index].limit_commands,
+ qmode->rl.qhealth[index].areq_prio,
+ qmode->rl.qhealth[index].prio_level);
+ val = (reg_val & (~(BKE_HEALTH_MASK) | (val0 & BKE_HEALTH_MASK)));
+ writel_relaxed(val, addr);
+ /* Ensure that priority for regulator/limiter modes are
+ * set before returning
+ */
+ wmb();
+
+}
+
+static void msm_bus_bimc_set_qos_prio(struct msm_bus_bimc_info *binfo,
+ uint32_t mas_index, uint8_t qmode_sel,
+ struct msm_bus_bimc_qos_mode *qmode)
+{
+ uint32_t reg_val, val;
+
+ switch (qmode_sel) {
+ case BIMC_QOS_MODE_FIXED:
+ reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(binfo->
+ base, mas_index)) & M_PRIOLVL_OVERRIDE_RMSK;
+ val = qmode->fixed.prio_level <<
+ M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT;
+ writel_relaxed(((reg_val &
+ ~(M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)) | (val
+ & M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)),
+ M_PRIOLVL_OVERRIDE_ADDR(binfo->base, mas_index));
+
+ reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(binfo->
+ base, mas_index)) & M_RD_CMD_OVERRIDE_RMSK;
+ val = qmode->fixed.areq_prio_rd <<
+ M_RD_CMD_OVERRIDE_AREQPRIO_SHFT;
+ writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_AREQPRIO_BMSK))
+ | (val & M_RD_CMD_OVERRIDE_AREQPRIO_BMSK)),
+ M_RD_CMD_OVERRIDE_ADDR(binfo->base, mas_index));
+
+ reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR(binfo->
+ base, mas_index)) & M_WR_CMD_OVERRIDE_RMSK;
+ val = qmode->fixed.areq_prio_wr <<
+ M_WR_CMD_OVERRIDE_AREQPRIO_SHFT;
+ writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_AREQPRIO_BMSK))
+ | (val & M_WR_CMD_OVERRIDE_AREQPRIO_BMSK)),
+ M_WR_CMD_OVERRIDE_ADDR(binfo->base, mas_index));
+ /* Ensure that fixed mode register writes go through
+ * before returning
+ */
+ wmb();
+ break;
+
+ case BIMC_QOS_MODE_REGULATOR:
+ case BIMC_QOS_MODE_LIMITER:
+ set_qos_prio_rl(M_BKE_HEALTH_3_CONFIG_ADDR(binfo->base,
+ mas_index), M_BKE_HEALTH_3_CONFIG_RMSK, 3, qmode);
+ set_qos_prio_rl(M_BKE_HEALTH_2_CONFIG_ADDR(binfo->base,
+ mas_index), M_BKE_HEALTH_2_CONFIG_RMSK, 2, qmode);
+ set_qos_prio_rl(M_BKE_HEALTH_1_CONFIG_ADDR(binfo->base,
+ mas_index), M_BKE_HEALTH_1_CONFIG_RMSK, 1, qmode);
+ set_qos_prio_rl(M_BKE_HEALTH_1_CONFIG_ADDR(binfo->base,
+ mas_index), M_BKE_HEALTH_0_CONFIG_RMSK, 0 , qmode);
+ break;
+ case BIMC_QOS_MODE_BYPASS:
+ default:
+ break;
+ }
+}
+
+static void set_qos_bw_regs(void __iomem *baddr, uint32_t mas_index,
+ long int th, long int tm, long int tl, uint32_t gp,
+ uint32_t gc, bool bke_en)
+{
+ uint32_t reg_val, val;
+
+ /* Disable BKE before writing to registers as per spec */
+ reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
+ M_BKE_EN_RMSK;
+ writel_relaxed((reg_val & ~(M_BKE_EN_EN_BMSK)),
+ M_BKE_EN_ADDR(baddr, mas_index));
+
+ /* Write values of registers calculated */
+ reg_val = readl_relaxed(M_BKE_GP_ADDR(baddr, mas_index))
+ & M_BKE_GP_RMSK;
+ val = gp << M_BKE_GP_GP_SHFT;
+ writel_relaxed(((reg_val & ~(M_BKE_GP_GP_BMSK)) | (val &
+ M_BKE_GP_GP_BMSK)), M_BKE_GP_ADDR(baddr, mas_index));
+
+ reg_val = readl_relaxed(M_BKE_GC_ADDR(baddr, mas_index)) &
+ M_BKE_GC_RMSK;
+ val = gc << M_BKE_GC_GC_SHFT;
+ writel_relaxed(((reg_val & ~(M_BKE_GC_GC_BMSK)) | (val &
+ M_BKE_GC_GC_BMSK)), M_BKE_GC_ADDR(baddr, mas_index));
+
+ reg_val = readl_relaxed(M_BKE_THH_ADDR(baddr, mas_index)) &
+ M_BKE_THH_RMSK;
+ val = th << M_BKE_THH_THRESH_SHFT;
+ writel_relaxed(((reg_val & ~(M_BKE_THH_THRESH_BMSK)) | (val &
+ M_BKE_THH_THRESH_BMSK)), M_BKE_THH_ADDR(baddr, mas_index));
+
+ reg_val = readl_relaxed(M_BKE_THM_ADDR(baddr, mas_index)) &
+ M_BKE_THM_RMSK;
+ val = tm << M_BKE_THM_THRESH_SHFT;
+ writel_relaxed(((reg_val & ~(M_BKE_THM_THRESH_BMSK)) | (val &
+ M_BKE_THM_THRESH_BMSK)), M_BKE_THM_ADDR(baddr, mas_index));
+
+ reg_val = readl_relaxed(M_BKE_THL_ADDR(baddr, mas_index)) &
+ M_BKE_THL_RMSK;
+ val = tl << M_BKE_THL_THRESH_SHFT;
+ writel_relaxed(((reg_val & ~(M_BKE_THL_THRESH_BMSK)) |
+ (val & M_BKE_THL_THRESH_BMSK)), M_BKE_THL_ADDR(baddr,
+ mas_index));
+
+ /* Set BKE enable to the value it was */
+ reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index)) &
+ M_BKE_EN_RMSK;
+ val = bke_en << M_BKE_EN_EN_SHFT;
+ writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
+ M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
+ /* Ensure that all bandwidth register writes have completed
+ * before returning
+ */
+ wmb();
+}
+
+static void msm_bus_bimc_set_qos_bw(struct msm_bus_bimc_info *binfo,
+ uint32_t mas_index, struct msm_bus_bimc_qos_bw *qbw)
+{
+ uint32_t bke_en;
+
+ /* Validate QOS Frequency */
+ if (binfo->qos_freq == 0) {
+ MSM_BUS_DBG("Zero frequency\n");
+ return;
+ }
+
+ /* Get enable bit for BKE before programming the period */
+ bke_en = (readl_relaxed(M_BKE_EN_ADDR(binfo->base, mas_index)) &
+ M_BKE_EN_EN_BMSK) >> M_BKE_EN_EN_SHFT;
+
+ /* Only calculate if there's a requested bandwidth and window */
+ if (qbw->bw && qbw->ws) {
+ uint64_t th, tm, tl;
+ uint32_t gp, gc, data_width;
+ uint64_t gp_nominal, gp_required, gp_calc, data, temp;
+ uint64_t win = qbw->ws * binfo->qos_freq;
+ temp = win;
+ /*
+ * Calculate nominal grant period defined by requested
+ * window size.
+ * Ceil this value to max grant period.
+ */
+ bimc_div(&temp, 1000000);
+ gp_nominal = min_t(uint64_t, MAX_GRANT_PERIOD, temp);
+ /*
+ * Calculate max window size, defined by bw request.
+ * Units: (KHz, MB/s)
+ */
+ data_width = (readl_relaxed(M_CONFIG_INFO_2_ADDR(
+ binfo->base, mas_index)) &
+ M_CONFIG_INFO_2_M_DATA_WIDTH_BMSK) >>
+ M_CONFIG_INFO_2_M_DATA_WIDTH_SHFT;
+
+ /* If unspecified, use data-width 8 by default */
+ if (!data_width)
+ data_width = 8;
+
+ gp_calc = MAX_GC * data_width * binfo->qos_freq * 1000;
+ gp_required = gp_calc;
+ bimc_div(&gp_required, qbw->bw);
+
+ /* User min of two grant periods */
+ gp = min_t(uint64_t, gp_nominal, gp_required);
+
+ /* Calculate bandwith in grants and ceil. */
+ temp = qbw->bw * gp;
+ data = data_width * binfo->qos_freq * 1000;
+ bimc_div(&temp, data);
+ gc = min_t(uint64_t, MAX_GC, temp);
+
+ /* Calculate thresholds */
+ th = qbw->bw - qbw->thh;
+ tm = qbw->bw - qbw->thm;
+ tl = qbw->bw - qbw->thl;
+
+ th = th * gp;
+ bimc_div(&th, data);
+ tm = tm * gp;
+ bimc_div(&tm, data);
+ tl = tl * gp;
+ bimc_div(&tl, data);
+
+ MSM_BUS_DBG("BIMC: BW: mas_index: %d, th: %llu tm: %llu\n",
+ mas_index, th, tm);
+ MSM_BUS_DBG("BIMC: tl: %llu gp:%u gc: %u bke_en: %u\n",
+ tl, gp, gc, bke_en);
+ set_qos_bw_regs(binfo->base, mas_index, th, tm, tl, gp,
+ gc, bke_en);
+ } else
+ /* Clear bandwidth registers */
+ set_qos_bw_regs(binfo->base, mas_index, 0, 0, 0, 0, 0,
+ bke_en);
+}
+
+static int msm_bus_bimc_allocate_commit_data(struct msm_bus_fabric_registration
+ *fab_pdata, void **cdata, int ctx)
+{
+ struct msm_bus_bimc_commit **cd = (struct msm_bus_bimc_commit **)cdata;
+ struct msm_bus_bimc_info *binfo =
+ (struct msm_bus_bimc_info *)fab_pdata->hw_data;
+
+ MSM_BUS_DBG("Allocating BIMC commit data\n");
+ *cd = kzalloc(sizeof(struct msm_bus_bimc_commit), GFP_KERNEL);
+ if (!*cd) {
+ MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
+ return -ENOMEM;
+ }
+
+ (*cd)->mas = binfo->cdata[ctx].mas;
+ (*cd)->slv = binfo->cdata[ctx].slv;
+
+ return 0;
+}
+
+static void *msm_bus_bimc_allocate_bimc_data(struct platform_device *pdev,
+ struct msm_bus_fabric_registration *fab_pdata)
+{
+ struct resource *bimc_mem;
+ struct resource *bimc_io;
+ struct msm_bus_bimc_info *binfo;
+ int i;
+
+ MSM_BUS_DBG("Allocating BIMC data\n");
+ binfo = kzalloc(sizeof(struct msm_bus_bimc_info), GFP_KERNEL);
+ if (!binfo) {
+ WARN(!binfo, "Couldn't alloc mem for bimc_info\n");
+ return NULL;
+ }
+
+ binfo->qos_freq = fab_pdata->qos_freq;
+
+ binfo->params.nmasters = fab_pdata->nmasters;
+ binfo->params.nslaves = fab_pdata->nslaves;
+ binfo->params.bus_id = fab_pdata->id;
+
+ for (i = 0; i < NUM_CTX; i++) {
+ binfo->cdata[i].mas = kzalloc(sizeof(struct
+ msm_bus_node_hw_info) * fab_pdata->nmasters * 2,
+ GFP_KERNEL);
+ if (!binfo->cdata[i].mas) {
+ MSM_BUS_ERR("Couldn't alloc mem for bimc master hw\n");
+ kfree(binfo);
+ return NULL;
+ }
+
+ binfo->cdata[i].slv = kzalloc(sizeof(struct
+ msm_bus_node_hw_info) * fab_pdata->nslaves * 2,
+ GFP_KERNEL);
+ if (!binfo->cdata[i].slv) {
+ MSM_BUS_DBG("Couldn't alloc mem for bimc slave hw\n");
+ kfree(binfo->cdata[i].mas);
+ kfree(binfo);
+ return NULL;
+ }
+ }
+
+ bimc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!bimc_mem && !fab_pdata->virt) {
+ MSM_BUS_ERR("Cannot get BIMC Base address\n");
+ kfree(binfo);
+ return NULL;
+ }
+
+ bimc_io = request_mem_region(bimc_mem->start,
+ resource_size(bimc_mem), pdev->name);
+ if (!bimc_io) {
+ MSM_BUS_ERR("BIMC memory unavailable\n");
+ kfree(binfo);
+ return NULL;
+ }
+
+ binfo->base = ioremap(bimc_mem->start, resource_size(bimc_mem));
+ if (!binfo->base) {
+ MSM_BUS_ERR("IOremap failed for BIMC!\n");
+ release_mem_region(bimc_mem->start, resource_size(bimc_mem));
+ kfree(binfo);
+ return NULL;
+ }
+
+ fab_pdata->hw_data = (void *)binfo;
+ return (void *)binfo;
+}
+
+static void free_commit_data(void *cdata)
+{
+ struct msm_bus_bimc_commit *cd = (struct msm_bus_bimc_commit *)cdata;
+
+ kfree(cd->mas);
+ kfree(cd->slv);
+ kfree(cd);
+}
+
+static void msm_bus_bimc_update_bw(struct msm_bus_inode_info *hop,
+ struct msm_bus_inode_info *info,
+ struct msm_bus_fabric_registration *fab_pdata,
+ void *sel_cdata, int *master_tiers,
+ long int add_bw)
+{
+ struct msm_bus_bimc_info *binfo;
+ struct msm_bus_bimc_qos_bw qbw;
+ int i;
+ long int bw;
+ int ports = info->node_info->num_mports;
+ struct msm_bus_bimc_commit *sel_cd =
+ (struct msm_bus_bimc_commit *)sel_cdata;
+
+ MSM_BUS_DBG("BIMC: Update bw for ID %d, with IID: %d: %ld\n",
+ info->node_info->id, info->node_info->priv_id, add_bw);
+
+ binfo = (struct msm_bus_bimc_info *)fab_pdata->hw_data;
+ if (!info->node_info->qport) {
+ MSM_BUS_DBG("No qos ports to update!\n");
+ return;
+ }
+
+ if (info->node_info->num_mports == 0) {
+ MSM_BUS_DBG("BIMC: Skip Master BW\n");
+ goto skip_mas_bw;
+ }
+
+ bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
+ ports = INTERLEAVED_VAL(fab_pdata, ports);
+
+ for (i = 0; i < ports; i++) {
+ MSM_BUS_DBG("qport: %d\n", info->node_info->qport[i]);
+ sel_cd->mas[info->node_info->masterp[i]].bw += bw;
+ sel_cd->mas[info->node_info->masterp[i]].hw_id =
+ info->node_info->mas_hw_id;
+ qbw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
+ qbw.ws = info->node_info->ws;
+ /* Threshold low = 90% of bw */
+ qbw.thl = (90 * bw) / 100;
+ /* Threshold medium = bw */
+ qbw.thm = bw;
+ /* Threshold high = 10% more than bw */
+ qbw.thh = (110 * bw) / 100;
+ /* Check if info is a shared master.
+ * If it is, mark it dirty
+ * If it isn't, then set QOS Bandwidth
+ **/
+ MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %ld\n",
+ info->node_info->priv_id,
+ sel_cd->mas[info->node_info->masterp[i]].bw);
+ if (info->node_info->hw_sel == MSM_BUS_RPM)
+ sel_cd->mas[info->node_info->masterp[i]].dirty = 1;
+ else
+ msm_bus_bimc_set_qos_bw(binfo,
+ info->node_info->qport[i], &qbw);
+ }
+
+skip_mas_bw:
+ ports = hop->node_info->num_sports;
+ MSM_BUS_DBG("BIMC: ID: %d, Sports: %d\n", hop->node_info->priv_id,
+ ports);
+ if (ports)
+ bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
+ else
+ return;
+
+ for (i = 0; i < ports; i++) {
+ sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
+ sel_cd->slv[hop->node_info->slavep[i]].hw_id =
+ hop->node_info->slv_hw_id;
+ MSM_BUS_DBG("BIMC: Update slave_bw: ID: %d -> %ld\n",
+ hop->node_info->priv_id,
+ sel_cd->slv[hop->node_info->slavep[i]].bw);
+ MSM_BUS_DBG("BIMC: Update slave_bw: index: %d\n",
+ hop->node_info->slavep[i]);
+ /* Check if hop is a shared slave.
+ * If it is, mark it dirty
+ * If it isn't, then nothing to be done as the
+ * slaves are in bypass mode.
+ **/
+ if (hop->node_info->hw_sel == MSM_BUS_RPM) {
+ MSM_BUS_DBG("Slave dirty: %d, slavep: %d\n",
+ hop->node_info->priv_id,
+ hop->node_info->slavep[i]);
+ sel_cd->slv[hop->node_info->slavep[i]].dirty = 1;
+ }
+ }
+}
+
+static int msm_bus_bimc_commit(struct msm_bus_fabric_registration
+ *fab_pdata, void *hw_data, void **cdata)
+{
+ MSM_BUS_DBG("\nReached BIMC Commit\n");
+ return 0;
+}
+
+static int msm_bus_bimc_mas_init(struct msm_bus_bimc_info *binfo,
+ struct msm_bus_inode_info *info)
+{
+ int i;
+ struct msm_bus_bimc_qos_mode *qmode;
+ qmode = kzalloc(sizeof(struct msm_bus_bimc_qos_mode),
+ GFP_KERNEL);
+ if (!qmode) {
+ MSM_BUS_WARN("Couldn't alloc prio data for node: %d\n",
+ info->node_info->id);
+ return -ENOMEM;
+ }
+
+ switch (info->node_info->mode) {
+ case BIMC_QOS_MODE_FIXED:
+ qmode->fixed.prio_level = info->node_info->prio_lvl;
+ qmode->fixed.areq_prio_rd = info->node_info->prio_rd;
+ qmode->fixed.areq_prio_wr = info->node_info->prio_wr;
+ break;
+ default:
+ break;
+ }
+
+ info->hw_data = (void *)qmode;
+ if (!info->node_info->qport) {
+ MSM_BUS_DBG("No QoS Ports to init\n");
+ return 0;
+ }
+
+ for (i = 0; i < info->node_info->num_mports; i++) {
+ /* If in bypass mode, update priority */
+ if (info->node_info->mode != BIMC_QOS_MODE_BYPASS)
+ msm_bus_bimc_set_qos_prio(binfo, info->node_info->
+ qport[i], info->node_info->mode, qmode);
+
+ /* If in fixed mode, update bandwidth */
+ if (info->node_info->mode != BIMC_QOS_MODE_FIXED) {
+ struct msm_bus_bimc_qos_bw qbw;
+ qbw.ws = info->node_info->ws;
+ msm_bus_bimc_set_qos_bw(binfo,
+ info->node_info->qport[i], &qbw);
+ }
+
+ /* set mode */
+ msm_bus_bimc_set_qos_mode(binfo, info->node_info->qport[i],
+ info->node_info->mode);
+ }
+
+ return 0;
+}
+
+static void msm_bus_bimc_node_init(void *hw_data,
+ struct msm_bus_inode_info *info)
+{
+ struct msm_bus_bimc_info *binfo =
+ (struct msm_bus_bimc_info *)hw_data;
+
+ if (!IS_SLAVE(info->node_info->priv_id))
+ msm_bus_bimc_mas_init(binfo, info);
+}
+
+static int msm_bus_bimc_port_halt(uint32_t haltid, uint8_t mport)
+{
+ return 0;
+}
+
+static int msm_bus_bimc_port_unhalt(uint32_t haltid, uint8_t mport)
+{
+ return 0;
+}
+
+
+int msm_bus_bimc_hw_init(struct msm_bus_fabric_registration *pdata,
+ struct msm_bus_hw_algorithm *hw_algo)
+{
+ /* Set interleaving to true by default */
+ MSM_BUS_DBG("\nInitializing BIMC...\n");
+ pdata->il_flag = true;
+ hw_algo->allocate_commit_data = msm_bus_bimc_allocate_commit_data;
+ hw_algo->allocate_hw_data = msm_bus_bimc_allocate_bimc_data;
+ hw_algo->node_init = msm_bus_bimc_node_init;
+ hw_algo->free_commit_data = free_commit_data;
+ hw_algo->update_bw = msm_bus_bimc_update_bw;
+ hw_algo->commit = msm_bus_bimc_commit;
+ hw_algo->port_halt = msm_bus_bimc_port_halt;
+ hw_algo->port_unhalt = msm_bus_bimc_port_unhalt;
+ /* BIMC slaves are shared. Slave registers are set through RPM */
+ if (!pdata->ahb)
+ pdata->rpm_enabled = 1;
+ return 0;
+}
+
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_bimc.h b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.h
new file mode 100644
index 0000000..249e8bb
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_bimc.h
@@ -0,0 +1,125 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 _ARCH_ARM_MACH_MSM_BUS_BIMC_H
+#define _ARCH_ARM_MACH_MSM_BUS_BIMC_H
+
+struct msm_bus_bimc_params {
+ uint32_t bus_id;
+ uint32_t addr_width;
+ uint32_t data_width;
+ uint32_t nmasters;
+ uint32_t nslaves;
+};
+
+struct msm_bus_bimc_commit {
+ struct msm_bus_node_hw_info *mas;
+ struct msm_bus_node_hw_info *slv;
+};
+
+struct msm_bus_bimc_info {
+ void __iomem *base;
+ uint32_t base_addr;
+ uint32_t qos_freq;
+ struct msm_bus_bimc_params params;
+ struct msm_bus_bimc_commit cdata[NUM_CTX];
+};
+
+struct msm_bus_bimc_node {
+ uint32_t conn_mask;
+ uint32_t data_width;
+ uint8_t slv_arb_mode;
+};
+
+enum msm_bus_bimc_arb_mode {
+ BIMC_ARB_MODE_RR = 0,
+ BIMC_ARB_MODE_PRIORITY_RR,
+ BIMC_ARB_MODE_TIERED_RR,
+};
+
+
+enum msm_bus_bimc_interleave {
+ BIMC_INTERLEAVE_NONE = 0,
+ BIMC_INTERLEAVE_ODD,
+ BIMC_INTERLEAVE_EVEN,
+};
+
+struct msm_bus_bimc_slave_seg {
+ bool enable;
+ uint64_t start_addr;
+ uint64_t seg_size;
+ uint8_t interleave;
+};
+
+enum msm_bus_bimc_qos_mode_type {
+ BIMC_QOS_MODE_FIXED = 0,
+ BIMC_QOS_MODE_LIMITER,
+ BIMC_QOS_MODE_BYPASS,
+ BIMC_QOS_MODE_REGULATOR,
+};
+
+struct msm_bus_bimc_qos_health {
+ bool limit_commands;
+ uint32_t areq_prio;
+ uint32_t prio_level;
+};
+
+struct msm_bus_bimc_mode_fixed {
+ uint32_t prio_level;
+ uint32_t areq_prio_rd;
+ uint32_t areq_prio_wr;
+};
+
+struct msm_bus_bimc_mode_rl {
+ uint8_t qhealthnum;
+ struct msm_bus_bimc_qos_health qhealth[4];
+};
+
+struct msm_bus_bimc_qos_mode {
+ uint8_t mode;
+ struct msm_bus_bimc_mode_fixed fixed;
+ struct msm_bus_bimc_mode_rl rl;
+};
+
+struct msm_bus_bimc_qos_bw {
+ uint64_t bw; /* bw is in Bytes/sec */
+ uint32_t ws; /* Window size in nano seconds*/
+ uint64_t thh; /* Threshold high, bytes per second */
+ uint64_t thm; /* Threshold medium, bytes per second */
+ uint64_t thl; /* Threshold low, bytes per second */
+};
+
+struct msm_bus_bimc_clk_gate {
+ bool core_clk_gate_en;
+ bool arb_clk_gate_en; /* For arbiter */
+ bool port_clk_gate_en; /* For regs on BIMC core clock */
+};
+
+void msm_bus_bimc_set_slave_seg(struct msm_bus_bimc_info *binfo,
+ uint32_t slv_index, uint32_t seg_index,
+ struct msm_bus_bimc_slave_seg *bsseg);
+void msm_bus_bimc_set_slave_clk_gate(struct msm_bus_bimc_info *binfo,
+ uint32_t slv_index, struct msm_bus_bimc_clk_gate *bgate);
+void msm_bus_bimc_set_mas_clk_gate(struct msm_bus_bimc_info *binfo,
+ uint32_t mas_index, struct msm_bus_bimc_clk_gate *bgate);
+void msm_bus_bimc_arb_en(struct msm_bus_bimc_info *binfo,
+ uint32_t slv_index, bool en);
+void msm_bus_bimc_get_params(struct msm_bus_bimc_info *binfo,
+ struct msm_bus_bimc_params *params);
+void msm_bus_bimc_get_mas_params(struct msm_bus_bimc_info *binfo,
+ uint32_t mas_index, struct msm_bus_bimc_node *mparams);
+void msm_bus_bimc_get_slv_params(struct msm_bus_bimc_info *binfo,
+ uint32_t slv_index, struct msm_bus_bimc_node *sparams);
+bool msm_bus_bimc_get_arb_en(struct msm_bus_bimc_info *binfo,
+ uint32_t slv_index);
+
+#endif /*_ARCH_ARM_MACH_MSM_BUS_BIMC_H*/
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 341fda8..a9d6e4f 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
@@ -46,13 +46,22 @@
MSM_BUS_DBG_OP = 1,
};
+enum msm_bus_hw_sel {
+ MSM_BUS_RPM = 0,
+ MSM_BUS_NOC,
+ MSM_BUS_BIMC,
+};
+
extern struct bus_type msm_bus_type;
struct msm_bus_node_info {
unsigned int id;
unsigned int priv_id;
+ unsigned int mas_hw_id;
+ unsigned int slv_hw_id;
int gateway;
int *masterp;
+ int *qport;
int num_mports;
int *slavep;
int num_sports;
@@ -65,6 +74,12 @@
unsigned int buswidth;
unsigned int ws;
unsigned int mode;
+ unsigned int perm_mode;
+ unsigned int prio_lvl;
+ unsigned int prio_rd;
+ unsigned int prio_wr;
+ unsigned int prio1;
+ unsigned int prio0;
};
struct path_node {
@@ -105,6 +120,12 @@
void *hw_data;
};
+struct msm_bus_node_hw_info {
+ bool dirty;
+ unsigned int hw_id;
+ unsigned long bw;
+};
+
struct msm_bus_hw_algorithm {
int (*allocate_commit_data)(struct msm_bus_fabric_registration
*fab_pdata, void **cdata, int ctx);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 8c015d1..3671916 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -594,12 +594,22 @@
struct msm_bus_hw_algorithm *hw_algo)
{
int ret = 0;
- ret = msm_bus_rpm_hw_init(pdata, hw_algo);
- if (ret) {
- MSM_BUS_ERR("RPM initialization failed\n");
- ret = -EINVAL;
- }
+ switch (pdata->hw_sel) {
+ case MSM_BUS_NOC:
+ msm_bus_noc_hw_init(pdata, hw_algo);
+ break;
+ case MSM_BUS_BIMC:
+ msm_bus_bimc_hw_init(pdata, hw_algo);
+ break;
+ default:
+ ret = msm_bus_rpm_hw_init(pdata, hw_algo);
+ if (ret) {
+ MSM_BUS_ERR("RPM initialization failed\n");
+ ret = -EINVAL;
+ }
+ break;
+ }
return ret;
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.c b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
new file mode 100644
index 0000000..5179d2a
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.c
@@ -0,0 +1,613 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+
+#define pr_fmt(fmt) "AXI: NOC: %s(): " fmt, __func__
+
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <mach/msm_bus_board.h>
+#include "msm_bus_core.h"
+#include "msm_bus_noc.h"
+
+/* NOC_QOS generic */
+#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
+#define SAT_SCALE 16 /* 16 bytes minimum for saturation */
+#define BW_SCALE 256 /* 1/256 byte per cycle unit */
+#define MAX_BW_FIELD (NOC_QOS_BWn_BW_BMSK >> NOC_QOS_BWn_BW_SHFT)
+#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)
+
+#define NOC_QOS_REG_BASE(b) ((b) + 0x00003000)
+
+#define NOC_QOS_ID_COREIDn_ADDR(b, n) (NOC_QOS_REG_BASE(b) + 0x80 * (n))
+enum noc_qos_id_coreidn {
+ NOC_QOS_ID_COREIDn_RMSK = 0xffffffff,
+ NOC_QOS_ID_COREIDn_MAXn = 32,
+ NOC_QOS_ID_COREIDn_CORECHSUM_BMSK = 0xffffff00,
+ NOC_QOS_ID_COREIDn_CORECHSUM_SHFT = 0x8,
+ NOC_QOS_ID_COREIDn_CORETYPEID_BMSK = 0xff,
+ NOC_QOS_ID_COREIDn_CORETYPEID_SHFT = 0x0,
+};
+
+#define NOC_QOS_ID_REVISIONIDn_ADDR(b, n) \
+ (NOC_QOS_REG_BASE(b) + 0x4 + 0x80 * (n))
+enum noc_qos_id_revisionidn {
+ NOC_QOS_ID_REVISIONIDn_RMSK = 0xffffffff,
+ NOC_QOS_ID_REVISIONIDn_MAXn = 32,
+ NOC_QOS_ID_REVISIONIDn_FLEXNOCID_BMSK = 0xffffff00,
+ NOC_QOS_ID_REVISIONIDn_FLEXNOCID_SHFT = 0x8,
+ NOC_QOS_ID_REVISIONIDn_USERID_BMSK = 0xff,
+ NOC_QOS_ID_REVISIONIDn_USERID_SHFT = 0x0,
+};
+
+#define NOC_QOS_PRIORITYn_ADDR(b, n) \
+ (NOC_QOS_REG_BASE(b) + 0x8 + 0x80 * (n))
+enum noc_qos_id_priorityn {
+ NOC_QOS_PRIORITYn_RMSK = 0x0000000f,
+ NOC_QOS_PRIORITYn_MAXn = 32,
+ NOC_QOS_PRIORITYn_P1_BMSK = 0xc,
+ NOC_QOS_PRIORITYn_P1_SHFT = 0x2,
+ NOC_QOS_PRIORITYn_P0_BMSK = 0x3,
+ NOC_QOS_PRIORITYn_P0_SHFT = 0x0,
+};
+
+#define NOC_QOS_MODEn_ADDR(b, n) \
+ (NOC_QOS_REG_BASE(b) + 0xC + 0x80 * (n))
+enum noc_qos_id_moden_rmsk {
+ NOC_QOS_MODEn_RMSK = 0x00000003,
+ NOC_QOS_MODEn_MAXn = 32,
+ NOC_QOS_MODEn_MODE_BMSK = 0x3,
+ NOC_QOS_MODEn_MODE_SHFT = 0x0,
+};
+
+#define NOC_QOS_BWn_ADDR(b, n) \
+ (NOC_QOS_REG_BASE(b) + 0x10 + 0x80 * (n))
+enum noc_qos_id_bwn {
+ NOC_QOS_BWn_RMSK = 0x0000ffff,
+ NOC_QOS_BWn_MAXn = 32,
+ NOC_QOS_BWn_BW_BMSK = 0xffff,
+ NOC_QOS_BWn_BW_SHFT = 0x0,
+};
+
+/* QOS Saturation registers */
+#define NOC_QOS_SATn_ADDR(b, n) \
+ (NOC_QOS_REG_BASE(b) + 0x14 + 0x80 * (n))
+enum noc_qos_id_saturationn {
+ NOC_QOS_SATn_RMSK = 0x000003ff,
+ NOC_QOS_SATn_MAXn = 32,
+ NOC_QOS_SATn_SAT_BMSK = 0x3ff,
+ NOC_QOS_SATn_SAT_SHFT = 0x0,
+};
+
+static int noc_div(uint64_t *a, uint32_t b)
+{
+ if ((*a > 0) && (*a < b))
+ return 1;
+ else
+ return do_div(*a, b);
+}
+
+/**
+ * Calculates bw hardware is using from register values
+ * bw returned is in bytes/sec
+ */
+static uint64_t noc_bw(uint32_t bw_field, uint32_t qos_freq)
+{
+ uint64_t res;
+ uint32_t rem, scale;
+
+ res = 2 * qos_freq * bw_field;
+ scale = BW_SCALE * 1000;
+ rem = noc_div(&res, scale);
+ MSM_BUS_DBG("NOC: Calculated bw: %llu\n", res * 1000000ULL);
+ return res * 1000000ULL;
+}
+
+static uint32_t noc_bw_ceil(long int bw_field, uint32_t qos_freq)
+{
+ uint64_t bw_temp = 2 * qos_freq * bw_field;
+ uint32_t scale = 1000 * BW_SCALE;
+ noc_div(&bw_temp, scale);
+ return bw_temp * 1000000;
+}
+#define MAX_BW(timebase) noc_bw_ceil(MAX_BW_FIELD, (timebase))
+
+/**
+ * Calculates ws hardware is using from register values
+ * ws returned is in nanoseconds
+ */
+static uint32_t noc_ws(uint64_t bw, uint32_t sat, uint32_t qos_freq)
+{
+ if (bw && qos_freq) {
+ uint32_t bwf = bw * qos_freq;
+ uint64_t scale = 1000000000000LL * BW_SCALE *
+ SAT_SCALE * sat;
+ noc_div(&scale, bwf);
+ MSM_BUS_DBG("NOC: Calculated ws: %llu\n", scale);
+ return scale;
+ }
+
+ return 0;
+}
+#define MAX_WS(bw, timebase) noc_ws((bw), MAX_SAT_FIELD, (timebase))
+
+/* Calculate bandwidth field value for requested bandwidth */
+static uint32_t noc_bw_field(uint64_t bw, uint32_t qos_freq)
+{
+ uint32_t bw_field = 0;
+
+ if (bw) {
+ uint32_t rem;
+ uint64_t bw_capped = min_t(uint64_t, bw, MAX_BW(qos_freq));
+ uint64_t bwc = bw_capped * BW_SCALE;
+ uint64_t qf = 2 * qos_freq * 1000;
+
+ rem = noc_div(&bwc, qf);
+ bw_field = (uint32_t)min_t(uint64_t, bwc, MAX_BW_FIELD);
+ }
+
+ MSM_BUS_DBG("NOC: bw_field: %u\n", bw_field);
+ return bw_field;
+}
+
+static uint32_t noc_sat_field(uint64_t bw, uint32_t ws, uint32_t qos_freq)
+{
+ uint32_t sat_field = 0, win;
+
+ if (bw) {
+ /* Limit to max bw and scale bw to 100 KB increments */
+ uint64_t tbw, tscale;
+ uint64_t bw_scaled = min_t(uint64_t, bw, MAX_BW(qos_freq));
+ uint32_t rem = noc_div(&bw_scaled, 100000);
+
+ /**
+ * Calculate saturation from windows size.
+ * WS must be at least one arb period.
+ * Saturation must not exceed max field size
+ *
+ * Bandwidth is in 100KB increments
+ * Window size is in ns
+ * qos_freq is in KHz
+ */
+ win = max(ws, 1000000 / qos_freq);
+ tbw = bw_scaled * win * qos_freq;
+ tscale = 10000000ULL * BW_SCALE * SAT_SCALE;
+ rem = noc_div(&tbw, tscale);
+ sat_field = (uint32_t)min_t(uint64_t, tbw, MAX_SAT_FIELD);
+ }
+
+ MSM_BUS_DBG("NOC: sat_field: %d\n", sat_field);
+ return sat_field;
+}
+
+static void noc_set_qos_mode(struct msm_bus_noc_info *ninfo, uint32_t mport,
+ uint8_t mode)
+{
+ if (mode < NOC_QOS_MODE_MAX &&
+ ((1 << mode) & ninfo->mas_modes[mport])) {
+ uint32_t reg_val;
+
+ reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
+ mport)) & NOC_QOS_MODEn_RMSK;
+ writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) |
+ (mode & NOC_QOS_MODEn_MODE_BMSK)),
+ NOC_QOS_MODEn_ADDR(ninfo->base, mport));
+ }
+ /* Ensure qos mode is set before exiting */
+ wmb();
+}
+
+static void noc_set_qos_priority(struct msm_bus_noc_info *ninfo, uint32_t mport,
+ struct msm_bus_noc_qos_priority *priority)
+{
+ uint32_t reg_val, val;
+
+ reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport))
+ & NOC_QOS_PRIORITYn_RMSK;
+ val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT;
+ writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) |
+ (val & NOC_QOS_PRIORITYn_P1_BMSK)),
+ NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport));
+
+ reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport))
+ & NOC_QOS_PRIORITYn_RMSK;
+ writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) |
+ (priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)),
+ NOC_QOS_PRIORITYn_ADDR(ninfo->base, mport));
+ /* Ensure qos priority is set before exiting */
+ wmb();
+}
+
+static void msm_bus_noc_set_qos_bw(struct msm_bus_noc_info *ninfo,
+ uint32_t mport, uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
+{
+ uint32_t reg_val, val, mode;
+
+ if (!ninfo->qos_freq) {
+ MSM_BUS_DBG("Zero QoS Freq\n");
+ return;
+ }
+
+
+ /* If Limiter or Regulator modes are not supported, bw not available*/
+ if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
+ NOC_QOS_PERM_MODE_REGULATOR)) {
+ uint32_t bw_val = noc_bw_field(qbw->bw, ninfo->qos_freq);
+ uint32_t sat_val = noc_sat_field(qbw->bw, qbw->ws,
+ ninfo->qos_freq);
+
+ MSM_BUS_DBG("NOC: BW: perm_mode: %d bw_val: %d, sat_val: %d\n",
+ perm_mode, bw_val, sat_val);
+ /*
+ * If in Limiter/Regulator mode, first go to fixed mode.
+ * Clear QoS accumulator
+ **/
+ mode = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
+ mport)) & NOC_QOS_MODEn_MODE_BMSK;
+ if (mode == NOC_QOS_MODE_REGULATOR || mode ==
+ NOC_QOS_MODE_LIMITER) {
+ reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->
+ base, mport));
+ val = NOC_QOS_MODE_FIXED;
+ writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
+ | (val & NOC_QOS_MODEn_MODE_BMSK),
+ NOC_QOS_MODEn_ADDR(ninfo->base, mport));
+ }
+
+ reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->base, mport));
+ val = bw_val << NOC_QOS_BWn_BW_SHFT;
+ writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) |
+ (val & NOC_QOS_BWn_BW_BMSK)),
+ NOC_QOS_BWn_ADDR(ninfo->base, mport));
+
+ MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val &
+ (~NOC_QOS_BWn_BW_BMSK)) | (val &
+ NOC_QOS_BWn_BW_BMSK)));
+
+ reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->base,
+ mport));
+ val = sat_val << NOC_QOS_SATn_SAT_SHFT;
+ writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) |
+ (val & NOC_QOS_SATn_SAT_BMSK)),
+ NOC_QOS_SATn_ADDR(ninfo->base, mport));
+
+ MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val &
+ (~NOC_QOS_SATn_SAT_BMSK)) | (val &
+ NOC_QOS_SATn_SAT_BMSK)));
+
+ /* Set mode back to what it was initially */
+ reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
+ mport));
+ writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
+ | (mode & NOC_QOS_MODEn_MODE_BMSK),
+ NOC_QOS_MODEn_ADDR(ninfo->base, mport));
+ /* Ensure that all writes for bandwidth registers have
+ * completed before returning
+ */
+ wmb();
+ }
+}
+
+uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
+ uint32_t mport)
+{
+ if (NOC_QOS_MODES_ALL_PERM == ninfo->mas_modes[mport])
+ return readl_relaxed(NOC_QOS_MODEn_ADDR(ninfo->base,
+ mport)) & NOC_QOS_MODEn_MODE_BMSK;
+ else
+ return 31 - __CLZ(ninfo->mas_modes[mport] &
+ NOC_QOS_MODES_ALL_PERM);
+}
+
+void msm_bus_noc_get_qos_priority(struct msm_bus_noc_info *ninfo,
+ uint32_t mport, struct msm_bus_noc_qos_priority *priority)
+{
+ priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
+ mport)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
+ NOC_QOS_PRIORITYn_P1_SHFT;
+
+ priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(ninfo->base,
+ mport)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
+ NOC_QOS_PRIORITYn_P0_SHFT;
+}
+
+void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
+ uint32_t mport, struct msm_bus_noc_qos_bw *qbw)
+{
+ if (ninfo->mas_modes[mport] & (NOC_QOS_PERM_MODE_LIMITER |
+ NOC_QOS_PERM_MODE_REGULATOR)) {
+ uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(ninfo->
+ base, mport)) & NOC_QOS_BWn_BW_BMSK;
+ uint32_t sat = readl_relaxed(NOC_QOS_SATn_ADDR(ninfo->
+ base, mport)) & NOC_QOS_SATn_SAT_BMSK;
+
+ qbw->bw = noc_bw(bw_val, ninfo->qos_freq);
+ qbw->ws = noc_ws(qbw->bw, sat, ninfo->qos_freq);
+ } else {
+ qbw->bw = 0;
+ qbw->ws = 0;
+ }
+}
+
+static int msm_bus_noc_mas_init(struct msm_bus_noc_info *ninfo,
+ struct msm_bus_inode_info *info)
+{
+ int i;
+ struct msm_bus_noc_qos_priority *prio;
+ prio = kzalloc(sizeof(struct msm_bus_noc_qos_priority),
+ GFP_KERNEL);
+ if (!prio) {
+ MSM_BUS_WARN("Couldn't alloc prio data for node: %d\n",
+ info->node_info->id);
+ return -ENOMEM;
+ }
+
+ prio->read_prio = info->node_info->prio_rd;
+ prio->write_prio = info->node_info->prio_wr;
+ prio->p1 = info->node_info->prio1;
+ prio->p0 = info->node_info->prio0;
+ info->hw_data = (void *)prio;
+
+ if (!info->node_info->qport) {
+ MSM_BUS_DBG("No QoS Ports to init\n");
+ return 0;
+ }
+
+ for (i = 0; i < info->node_info->num_mports; i++) {
+ if (info->node_info->mode != NOC_QOS_MODE_BYPASS)
+ noc_set_qos_priority(ninfo, info->node_info->qport[i],
+ prio);
+
+ if (info->node_info->mode != NOC_QOS_MODE_FIXED) {
+ struct msm_bus_noc_qos_bw qbw;
+ qbw.ws = info->node_info->ws;
+ qbw.bw = 0;
+ msm_bus_noc_set_qos_bw(ninfo, info->node_info->qport[i],
+ info->node_info->perm_mode, &qbw);
+ }
+
+ noc_set_qos_mode(ninfo, info->node_info->qport[i], info->
+ node_info->mode);
+ }
+
+ return 0;
+}
+
+static void msm_bus_noc_node_init(void *hw_data,
+ struct msm_bus_inode_info *info)
+{
+ struct msm_bus_noc_info *ninfo =
+ (struct msm_bus_noc_info *)hw_data;
+
+ if (!IS_SLAVE(info->node_info->priv_id))
+ msm_bus_noc_mas_init(ninfo, info);
+}
+
+static int msm_bus_noc_allocate_commit_data(struct msm_bus_fabric_registration
+ *fab_pdata, void **cdata, int ctx)
+{
+ struct msm_bus_noc_commit **cd = (struct msm_bus_noc_commit **)cdata;
+ struct msm_bus_noc_info *ninfo =
+ (struct msm_bus_noc_info *)fab_pdata->hw_data;
+
+ *cd = kzalloc(sizeof(struct msm_bus_noc_commit), GFP_KERNEL);
+ if (!*cd) {
+ MSM_BUS_DBG("Couldn't alloc mem for cdata\n");
+ return -ENOMEM;
+ }
+
+ (*cd)->mas = ninfo->cdata[ctx].mas;
+ (*cd)->slv = ninfo->cdata[ctx].slv;
+
+ return 0;
+}
+
+static void *msm_bus_noc_allocate_noc_data(struct platform_device *pdev,
+ struct msm_bus_fabric_registration *fab_pdata)
+{
+ struct resource *noc_mem;
+ struct resource *noc_io;
+ struct msm_bus_noc_info *ninfo;
+ int i;
+
+ ninfo = kzalloc(sizeof(struct msm_bus_noc_info), GFP_KERNEL);
+ if (!ninfo) {
+ MSM_BUS_DBG("Couldn't alloc mem for noc info\n");
+ return NULL;
+ }
+
+ ninfo->nmasters = fab_pdata->nmasters;
+ ninfo->nqos_masters = fab_pdata->nmasters;
+ ninfo->nslaves = fab_pdata->nslaves;
+ ninfo->qos_freq = fab_pdata->qos_freq;
+ ninfo->mas_modes = kzalloc(sizeof(uint32_t) * fab_pdata->nmasters,
+ GFP_KERNEL);
+ if (!ninfo->mas_modes) {
+ MSM_BUS_DBG("Couldn't alloc mem for noc master-modes\n");
+ return NULL;
+ }
+
+ for (i = 0; i < NUM_CTX; i++) {
+ ninfo->cdata[i].mas = kzalloc(sizeof(struct
+ msm_bus_node_hw_info) * fab_pdata->nmasters * 2,
+ GFP_KERNEL);
+ if (!ninfo->cdata[i].mas) {
+ MSM_BUS_DBG("Couldn't alloc mem for noc master-bw\n");
+ kfree(ninfo->mas_modes);
+ kfree(ninfo);
+ return NULL;
+ }
+
+ ninfo->cdata[i].slv = kzalloc(sizeof(struct
+ msm_bus_node_hw_info) * fab_pdata->nslaves * 2,
+ GFP_KERNEL);
+ if (!ninfo->cdata[i].slv) {
+ MSM_BUS_DBG("Couldn't alloc mem for noc master-bw\n");
+ kfree(ninfo->cdata[i].mas);
+ goto err;
+ }
+ }
+
+ /* If it's a virtual fabric, don't get memory info */
+ if (fab_pdata->virt)
+ goto skip_mem;
+
+ noc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!noc_mem && !fab_pdata->virt) {
+ MSM_BUS_ERR("Cannot get NoC Base address\n");
+ goto err;
+ }
+
+ noc_io = request_mem_region(noc_mem->start,
+ resource_size(noc_mem), pdev->name);
+ if (!noc_io) {
+ MSM_BUS_ERR("NoC memory unavailable\n");
+ goto err;
+ }
+
+ ninfo->base = ioremap(noc_mem->start, resource_size(noc_mem));
+ if (!ninfo->base) {
+ MSM_BUS_ERR("IOremap failed for NoC!\n");
+ release_mem_region(noc_mem->start, resource_size(noc_mem));
+ goto err;
+ }
+
+skip_mem:
+ fab_pdata->hw_data = (void *)ninfo;
+ return (void *)ninfo;
+
+err:
+ kfree(ninfo->mas_modes);
+ kfree(ninfo);
+ return NULL;
+}
+
+static void free_commit_data(void *cdata)
+{
+ struct msm_bus_noc_commit *cd = (struct msm_bus_noc_commit *)cdata;
+
+ kfree(cd->mas);
+ kfree(cd->slv);
+ kfree(cd);
+}
+
+static void msm_bus_noc_update_bw(struct msm_bus_inode_info *hop,
+ struct msm_bus_inode_info *info,
+ struct msm_bus_fabric_registration *fab_pdata,
+ void *sel_cdata, int *master_tiers,
+ long int add_bw)
+{
+ struct msm_bus_noc_info *ninfo;
+ struct msm_bus_noc_qos_bw qos_bw;
+ int i, ports;
+ long int bw;
+ struct msm_bus_noc_commit *sel_cd =
+ (struct msm_bus_noc_commit *)sel_cdata;
+
+ ninfo = (struct msm_bus_noc_info *)fab_pdata->hw_data;
+ if (!ninfo->qos_freq) {
+ MSM_BUS_DBG("NOC: No qos frequency to update bw\n");
+ return;
+ }
+
+ if (!info->node_info->qport) {
+ MSM_BUS_DBG("NOC: No QoS Ports to update bw\n");
+ return;
+ }
+
+ ports = info->node_info->num_mports;
+ qos_bw.ws = info->node_info->ws;
+
+ bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
+
+ MSM_BUS_DBG("NOC: Update bw for: %d: %ld\n",
+ info->node_info->priv_id, add_bw);
+ for (i = 0; i < ports; i++) {
+ sel_cd->mas[info->node_info->masterp[i]].bw += bw;
+ sel_cd->mas[info->node_info->masterp[i]].hw_id =
+ info->node_info->mas_hw_id;
+ qos_bw.bw = sel_cd->mas[info->node_info->masterp[i]].bw;
+ MSM_BUS_DBG("NOC: Update mas_bw for ID: %d, BW: %ld, QoS: %u\n",
+ info->node_info->priv_id,
+ sel_cd->mas[info->node_info->masterp[i]].bw,
+ qos_bw.ws);
+ /* Check if info is a shared master.
+ * If it is, mark it dirty
+ * If it isn't, then set QOS Bandwidth
+ **/
+ if (info->node_info->hw_sel == MSM_BUS_RPM)
+ sel_cd->mas[info->node_info->masterp[i]].dirty = 1;
+ else
+ msm_bus_noc_set_qos_bw(ninfo,
+ info->node_info->qport[i],
+ info->node_info->perm_mode, &qos_bw);
+ }
+
+ ports = hop->node_info->num_sports;
+ if (ports == 0) {
+ MSM_BUS_ERR("\nDIVIDE BY 0, hop: %d\n",
+ hop->node_info->priv_id);
+ return;
+ }
+ bw = INTERLEAVED_BW(fab_pdata, add_bw, ports);
+ for (i = 0; i < ports; i++) {
+ sel_cd->slv[hop->node_info->slavep[i]].bw += bw;
+ sel_cd->slv[hop->node_info->slavep[i]].hw_id =
+ hop->node_info->slv_hw_id;
+ MSM_BUS_DBG("NOC: Update slave_bw for ID: %d -> %ld\n",
+ hop->node_info->priv_id,
+ sel_cd->slv[hop->node_info->slavep[i]].bw);
+ MSM_BUS_DBG("NOC: Update slave_bw for hw_id: %d, index: %d\n",
+ hop->node_info->slv_hw_id, hop->node_info->slavep[i]);
+ /* Check if hop is a shared slave.
+ * If it is, mark it dirty
+ * If it isn't, then nothing to be done as the
+ * slaves are in bypass mode.
+ **/
+ if (hop->node_info->hw_sel == MSM_BUS_RPM)
+ sel_cd->slv[hop->node_info->slavep[i]].dirty = 1;
+ }
+}
+
+static int msm_bus_noc_commit(struct msm_bus_fabric_registration
+ *fab_pdata, void *hw_data, void **cdata)
+{
+ MSM_BUS_DBG("\nReached NOC Commit\n");
+ return 0;
+}
+
+static int msm_bus_noc_port_halt(uint32_t haltid, uint8_t mport)
+{
+ return 0;
+}
+
+static int msm_bus_noc_port_unhalt(uint32_t haltid, uint8_t mport)
+{
+ return 0;
+}
+
+int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
+ struct msm_bus_hw_algorithm *hw_algo)
+{
+ /* Set interleaving to true by default */
+ pdata->il_flag = true;
+ hw_algo->allocate_commit_data = msm_bus_noc_allocate_commit_data;
+ hw_algo->allocate_hw_data = msm_bus_noc_allocate_noc_data;
+ hw_algo->node_init = msm_bus_noc_node_init;
+ hw_algo->free_commit_data = free_commit_data;
+ hw_algo->update_bw = msm_bus_noc_update_bw;
+ hw_algo->commit = msm_bus_noc_commit;
+ hw_algo->port_halt = msm_bus_noc_port_halt;
+ hw_algo->port_unhalt = msm_bus_noc_port_unhalt;
+
+ return 0;
+}
+
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_noc.h b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
new file mode 100644
index 0000000..407d3ec
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_noc.h
@@ -0,0 +1,73 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 _ARCH_ARM_MACH_MSM_BUS_BIMC_H
+#define _ARCH_ARM_MACH_MSM_BUS_BIMC_H
+
+enum msm_bus_noc_qos_mode_type {
+ NOC_QOS_MODE_FIXED = 0,
+ NOC_QOS_MODE_LIMITER,
+ NOC_QOS_MODE_BYPASS,
+ NOC_QOS_MODE_REGULATOR,
+ NOC_QOS_MODE_MAX,
+};
+
+enum msm_bus_noc_qos_mode_perm {
+ NOC_QOS_PERM_MODE_FIXED = (1 << NOC_QOS_MODE_FIXED),
+ NOC_QOS_PERM_MODE_LIMITER = (1 << NOC_QOS_MODE_LIMITER),
+ NOC_QOS_PERM_MODE_BYPASS = (1 << NOC_QOS_MODE_BYPASS),
+ NOC_QOS_PERM_MODE_REGULATOR = (1 << NOC_QOS_MODE_REGULATOR),
+};
+
+#define NOC_QOS_MODES_ALL_PERM (NOC_QOS_PERM_MODE_FIXED | \
+ NOC_QOS_PERM_MODE_LIMITER | NOC_QOS_PERM_MODE_BYPASS | \
+ NOC_QOS_PERM_MODE_REGULATOR)
+
+struct msm_bus_noc_commit {
+ struct msm_bus_node_hw_info *mas;
+ struct msm_bus_node_hw_info *slv;
+};
+
+struct msm_bus_noc_info {
+ void __iomem *base;
+ uint32_t base_addr;
+ uint32_t nmasters;
+ uint32_t nqos_masters;
+ uint32_t nslaves;
+ uint32_t qos_freq; /* QOS Clock in KHz */
+ uint32_t *mas_modes;
+ struct msm_bus_noc_commit cdata[NUM_CTX];
+};
+
+struct msm_bus_noc_qos_priority {
+ uint32_t high_prio;
+ uint32_t low_prio;
+ uint32_t read_prio;
+ uint32_t write_prio;
+ uint32_t p1;
+ uint32_t p0;
+};
+
+struct msm_bus_noc_qos_bw {
+ uint64_t bw; /* Bandwidth in bytes per second */
+ uint32_t ws; /* Window size in nano seconds */
+};
+
+void msm_bus_noc_init(struct msm_bus_noc_info *ninfo);
+uint8_t msm_bus_noc_get_qos_mode(struct msm_bus_noc_info *ninfo,
+ uint32_t mport);
+void msm_bus_noc_get_qos_priority(struct msm_bus_noc_info *ninfo,
+ uint32_t mport, struct msm_bus_noc_qos_priority *qprio);
+void msm_bus_noc_get_qos_bw(struct msm_bus_noc_info *ninfo,
+ uint32_t mport, struct msm_bus_noc_qos_bw *qbw);
+
+#endif /*_ARCH_ARM_MACH_MSM_BUS_NOC_H */
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 057665b..eda22e1 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.c
@@ -15,6 +15,8 @@
*
*/
+#include <asm/atomic.h>
+
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -39,10 +41,11 @@
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
+#include "ramdump.h"
#include "timer.h"
#define DRV_NAME "msm_dsps"
-#define DRV_VERSION "3.02"
+#define DRV_VERSION "4.01"
#define PPSS_PAUSE_REG 0x1804
@@ -58,8 +61,14 @@
* @cdev - character device for user interface.
* @pdata - platform data.
* @pil - handle to DSPS Firmware loader.
+ * @dspsfw_ramdump_dev - handle to ramdump device for DSPS
+ * @dspsfw_ramdump_segments - Ramdump segment information for DSPS
+ * @smem_ramdump_dev - handle to ramdump device for smem
+ * @smem_ramdump_segments - Ramdump segment information for smem
* @is_on - DSPS is on.
* @ref_count - open/close reference count.
+ * @wdog_irq - DSPS Watchdog IRQ
+ * @crash_in_progress - 1 if crash recovery is in progress
* @ppss_base - ppss registers virtual base address.
*/
struct dsps_drv {
@@ -73,9 +82,17 @@
void *pil;
+ void *dspsfw_ramdump_dev;
+ struct ramdump_segment dspsfw_ramdump_segments[4];
+
+ void *smem_ramdump_dev;
+ struct ramdump_segment smem_ramdump_segments[1];
+
int is_on;
int ref_count;
+ int wdog_irq;
+ atomic_t crash_in_progress;
void __iomem *ppss_base;
};
@@ -89,8 +106,7 @@
*/
static int dsps_crash_shutdown_g;
-
-static void dsps_fatal_handler(struct work_struct *work);
+static void dsps_restart_handler(void);
/**
* Load DSPS Firmware.
@@ -210,7 +226,7 @@
}
- ret = clk_enable(clock);
+ ret = clk_prepare_enable(clock);
if (ret) {
pr_err("%s: enable clk %s err %d.",
__func__, name, ret);
@@ -299,7 +315,7 @@
if (clock == NULL)
continue;
- clk_disable(clock);
+ clk_disable_unprepare(clock);
}
return -ENODEV;
@@ -329,7 +345,7 @@
const char *name = drv->pdata->clks[i].name;
pr_debug("%s: set clk %s off.", __func__, name);
- clk_disable(drv->pdata->clks[i].clock);
+ clk_disable_unprepare(drv->pdata->clks[i].clock);
}
for (i = 0; i < drv->pdata->regs_num; i++)
@@ -360,7 +376,28 @@
return 0;
}
-static DECLARE_WORK(dsps_fatal_work, dsps_fatal_handler);
+/**
+ *
+ * Log subsystem restart failure reason
+ */
+static void dsps_log_sfr(void)
+{
+ const char dflt_reason[] = "Died too early due to unknown reason";
+ char *smem_reset_reason;
+ unsigned smem_reset_size;
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_DSPS0,
+ &smem_reset_size);
+ if (smem_reset_reason != NULL && smem_reset_reason[0] != 0) {
+ smem_reset_reason[smem_reset_size-1] = 0;
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, smem_reset_reason);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ } else
+ pr_err("%s: DSPS failure: %s\nResetting DSPS\n",
+ __func__, dflt_reason);
+}
/**
* Watchdog interrupt handler
@@ -368,9 +405,9 @@
*/
static irqreturn_t dsps_wdog_bite_irq(int irq, void *dev_id)
{
- pr_debug("%s\n", __func__);
- (void)schedule_work(&dsps_fatal_work);
- disable_irq_nosync(irq);
+ pr_err("%s\n", __func__);
+ dsps_log_sfr();
+ dsps_restart_handler();
return IRQ_HANDLED;
}
@@ -406,7 +443,9 @@
ret = put_user(val, (u32 __user *) arg);
break;
case DSPS_IOCTL_RESET:
- dsps_fatal_handler(NULL);
+ pr_err("%s: User-initiated DSPS reset.\nResetting DSPS\n",
+ __func__);
+ dsps_restart_handler();
ret = 0;
break;
default:
@@ -498,21 +537,52 @@
ppss_wdog = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
"ppss_wdog");
if (ppss_wdog) {
- ret = request_irq(ppss_wdog->start, dsps_wdog_bite_irq,
+ drv->wdog_irq = ppss_wdog->start;
+ ret = request_irq(drv->wdog_irq, dsps_wdog_bite_irq,
IRQF_TRIGGER_RISING, "dsps_wdog", NULL);
if (ret) {
pr_err("%s: request_irq fail %d\n", __func__, ret);
goto request_irq_err;
}
} else {
+ drv->wdog_irq = -1;
pr_debug("%s: ppss_wdog not supported.\n", __func__);
}
+ drv->dspsfw_ramdump_segments[0].address = drv->pdata->tcm_code_start;
+ drv->dspsfw_ramdump_segments[0].size = drv->pdata->tcm_code_size;
+ drv->dspsfw_ramdump_segments[1].address = drv->pdata->tcm_buf_start;
+ drv->dspsfw_ramdump_segments[1].size = drv->pdata->tcm_buf_size;
+ drv->dspsfw_ramdump_segments[2].address = drv->pdata->pipe_start;
+ drv->dspsfw_ramdump_segments[2].size = drv->pdata->pipe_size;
+ drv->dspsfw_ramdump_segments[3].address = drv->pdata->ddr_start;
+ drv->dspsfw_ramdump_segments[3].size = drv->pdata->ddr_size;
+
+ drv->dspsfw_ramdump_dev = create_ramdump_device("dsps");
+ if (!drv->dspsfw_ramdump_dev) {
+ pr_err("%s: create_ramdump_device(\"dsps\") fail\n",
+ __func__);
+ goto create_ramdump_err;
+ }
+
+ drv->smem_ramdump_segments[0].address = drv->pdata->smem_start;
+ drv->smem_ramdump_segments[0].size = drv->pdata->smem_size;
+ drv->smem_ramdump_dev = create_ramdump_device("smem");
+ if (!drv->smem_ramdump_dev) {
+ pr_err("%s: create_ramdump_device(\"smem\") fail\n",
+ __func__);
+ goto create_ramdump_err;
+ }
+
if (drv->pdata->init)
drv->pdata->init(drv->pdata);
return 0;
+create_ramdump_err:
+ disable_irq_nosync(drv->wdog_irq);
+ free_irq(drv->wdog_irq, NULL);
+
request_irq_err:
iounmap(drv->ppss_base);
@@ -600,6 +670,8 @@
}
}
+ free_irq(drv->wdog_irq, NULL);
+
iounmap(drv->ppss_base);
}
@@ -646,22 +718,16 @@
* Fatal error handler
* Resets DSPS.
*/
-static void dsps_fatal_handler(struct work_struct *work)
+static void dsps_restart_handler(void)
{
- uint32_t dsps_state;
+ pr_debug("%s: Restart lvl %d\n",
+ __func__, get_restart_level());
- dsps_state = smsm_get_state(SMSM_DSPS_STATE);
-
- pr_debug("%s: DSPS state 0x%x\n", __func__, dsps_state);
-
- if (dsps_state & SMSM_RESET) {
- pr_err("%s: DSPS fatal error detected. Resetting\n",
- __func__);
- panic("DSPS fatal error detected.");
+ if (atomic_add_return(1, &drv->crash_in_progress) > 1) {
+ pr_err("%s: DSPS already resetting. Count %d\n", __func__,
+ atomic_read(&drv->crash_in_progress));
} else {
- pr_debug("%s: User-initiated DSPS reset. Resetting\n",
- __func__);
- panic("User-initiated DSPS reset.");
+ subsystem_restart("dsps");
}
}
@@ -680,12 +746,9 @@
dsps_crash_shutdown_g = 0;
return;
}
-
if (new_state & SMSM_RESET) {
- pr_err
- ("%s: SMSM_RESET state detected. restarting the DSPS\n",
- __func__);
- panic("SMSM_RESET state detected.");
+ dsps_log_sfr();
+ dsps_restart_handler();
}
}
@@ -697,7 +760,10 @@
static int dsps_shutdown(const struct subsys_data *subsys)
{
pr_debug("%s\n", __func__);
- dsps_unload();
+ disable_irq_nosync(drv->wdog_irq);
+ dsps_suspend();
+ pil_force_shutdown(drv->pdata->pil_name);
+ dsps_power_off_handler();
return 0;
}
@@ -709,11 +775,11 @@
static int dsps_powerup(const struct subsys_data *subsys)
{
pr_debug("%s\n", __func__);
- if (dsps_load(drv->pdata->pil_name) != 0) {
- pr_err("%s: fail to restart DSPS after reboot\n",
- __func__);
- return 1;
- }
+ dsps_power_on_handler();
+ pil_force_boot(drv->pdata->pil_name);
+ atomic_set(&drv->crash_in_progress, 0);
+ enable_irq(drv->wdog_irq);
+ dsps_resume();
return 0;
}
@@ -736,8 +802,34 @@
*/
static int dsps_ramdump(int enable, const struct subsys_data *subsys)
{
+ int ret = 0;
pr_debug("%s\n", __func__);
- return 0;
+
+ if (enable) {
+ if (drv->dspsfw_ramdump_dev != NULL) {
+ ret = do_ramdump(drv->dspsfw_ramdump_dev,
+ drv->dspsfw_ramdump_segments,
+ ARRAY_SIZE(drv->dspsfw_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump DSPS memory (rc = %d).\n",
+ __func__, ret);
+ goto dsps_ramdump_out;
+ }
+ }
+ if (drv->smem_ramdump_dev != NULL) {
+ ret = do_ramdump(drv->smem_ramdump_dev,
+ drv->smem_ramdump_segments,
+ ARRAY_SIZE(drv->smem_ramdump_segments));
+ if (ret < 0) {
+ pr_err("%s: Unable to dump smem memory (rc = %d).\n",
+ __func__, ret);
+ goto dsps_ramdump_out;
+ }
+ }
+ }
+
+dsps_ramdump_out:
+ return ret;
}
static struct subsys_data dsps_ssrops = {
@@ -768,6 +860,8 @@
pr_err("%s: kzalloc fail.\n", __func__);
goto alloc_err;
}
+ atomic_set(&drv->crash_in_progress, 0);
+
drv->pdata = pdev->dev.platform_data;
drv->dev_class = class_create(THIS_MODULE, DRV_NAME);
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 2cff7f0..7ac3f74 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -247,29 +247,6 @@
schedule_delayed_work_on(0, &dogwork_struct, delay_time);
}
-static int msm_watchdog_remove(struct platform_device *pdev)
-{
- if (enable) {
- __raw_writel(0, msm_tmr0_base + WDT0_EN);
- mb();
- if (has_vic) {
- free_irq(WDT0_ACCSCSSNBARK_INT, 0);
- } else {
- disable_percpu_irq(WDT0_ACCSCSSNBARK_INT);
- if (!appsbark_fiq) {
- free_percpu_irq(WDT0_ACCSCSSNBARK_INT,
- percpu_pdata);
- free_percpu(percpu_pdata);
- }
- }
- enable = 0;
- /* In case we got suspended mid-exit */
- __raw_writel(0, msm_tmr0_base + WDT0_EN);
- }
- printk(KERN_INFO "MSM Watchdog Exit - Deactivated\n");
- return 0;
-}
-
static irqreturn_t wdog_bark_handler(int irq, void *dev_id)
{
unsigned long nanosec_rem;
@@ -445,7 +422,6 @@
static struct platform_driver msm_watchdog_driver = {
.probe = msm_watchdog_probe,
- .remove = msm_watchdog_remove,
.driver = {
.name = MODULE_NAME,
.owner = THIS_MODULE,
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
index 69e39df..43c7fc8 100644
--- a/arch/arm/mach-msm/ocmem.c
+++ b/arch/arm/mach-msm/ocmem.c
@@ -23,6 +23,15 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+/* This code is to temporarily work around the default state of OCMEM
+ regions in Virtio. These registers will be read from DT in a subsequent
+ patch which initializes the regions to appropriate default state.
+*/
+
+#define OCMEM_REGION_CTL_BASE 0xFDD0003C
+#define OCMEM_REGION_CTL_SIZE 0xC
+#define REGION_ENABLE 0x00003333
+
struct ocmem_partition {
const char *name;
int id;
@@ -97,6 +106,25 @@
return -EINVAL;
}
+inline unsigned long phys_to_offset(unsigned long addr)
+{
+ if (!ocmem_pdata)
+ return 0;
+ if (addr < ocmem_pdata->base ||
+ addr > (ocmem_pdata->base + ocmem_pdata->size))
+ return 0;
+ return addr - ocmem_pdata->base;
+}
+
+inline unsigned long offset_to_phys(unsigned long offset)
+{
+ if (!ocmem_pdata)
+ return 0;
+ if (offset > ocmem_pdata->size)
+ return 0;
+ return offset + ocmem_pdata->base;
+}
+
static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
{
struct ocmem_plat_data *pdata = NULL;
@@ -252,6 +280,7 @@
static int __devinit msm_ocmem_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ void *ocmem_region_vbase = NULL;
if (!pdev->dev.of_node->child) {
dev_info(dev, "Missing Configuration in Device Tree\n");
@@ -273,6 +302,20 @@
if (ocmem_zone_init(pdev))
return -EBUSY;
+ if (ocmem_notifier_init())
+ return -EBUSY;
+
+ if (ocmem_sched_init())
+ return -EBUSY;
+
+ ocmem_region_vbase = devm_ioremap_nocache(dev, OCMEM_REGION_CTL_BASE,
+ OCMEM_REGION_CTL_SIZE);
+ if (!ocmem_region_vbase)
+ return -EBUSY;
+ /* Enable all the 3 regions until we have support for power features */
+ writel_relaxed(REGION_ENABLE, ocmem_region_vbase);
+ writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 4);
+ writel_relaxed(REGION_ENABLE, ocmem_region_vbase + 8);
dev_info(dev, "initialized successfully\n");
return 0;
}
diff --git a/arch/arm/mach-msm/ocmem_api.c b/arch/arm/mach-msm/ocmem_api.c
new file mode 100644
index 0000000..bed13de
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_api.c
@@ -0,0 +1,327 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/slab.h>
+#include <mach/ocmem_priv.h>
+
+static inline int check_id(int id)
+{
+ return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
+}
+
+static struct ocmem_handle *generate_handle(void)
+{
+ struct ocmem_handle *handle = NULL;
+
+ handle = kzalloc(sizeof(struct ocmem_handle), GFP_KERNEL);
+ if (!handle) {
+ pr_err("ocmem: Unable to generate buffer handle\n");
+ return NULL;
+ }
+ mutex_init(&handle->handle_mutex);
+ return handle;
+}
+
+static int free_handle(struct ocmem_handle *handle)
+{
+ if (!handle)
+ return -EINVAL;
+
+ mutex_destroy(&handle->handle_mutex);
+ kfree(handle);
+ handle = NULL;
+ return 0;
+}
+
+static int __ocmem_free(int id, struct ocmem_buf *buf)
+{
+ int ret = 0;
+ struct ocmem_handle *handle = buffer_to_handle(buf);
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_free(id, handle);
+ mutex_unlock(&handle->handle_mutex);
+
+ if (ret)
+ return -EINVAL;
+
+ free_handle(handle);
+ return 0;
+}
+
+static struct ocmem_buf *__ocmem_allocate_range(int id, unsigned long min,
+ unsigned long max, unsigned long step, bool block, bool wait)
+{
+ struct ocmem_handle *handle = NULL;
+ int ret = 0;
+
+ handle = generate_handle();
+ if (!handle) {
+ pr_err("ocmem: Unable to generate handle\n");
+ return NULL;
+ }
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_allocate(id, handle, min, max, step, block, wait);
+ mutex_unlock(&handle->handle_mutex);
+ if (ret) {
+ pr_err("ocmem allocation failed\n");
+ free_handle(handle);
+ return NULL;
+ } else
+ return handle_to_buffer(handle);
+}
+
+struct ocmem_buf *ocmem_allocate(int client_id, unsigned long size)
+{
+ bool can_block = false;
+ bool can_wait = true;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ if (size < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested size %lx must be at least %x\n",
+ size, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+
+ return __ocmem_allocate_range(client_id, size, size,
+ size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nowait(int client_id, unsigned long size)
+{
+ bool can_block = false;
+ bool can_wait = false;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ if (size < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested size %lx must be at least %x\n",
+ size, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, size must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+ return __ocmem_allocate_range(client_id, size, size,
+ size, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_range(int client_id, unsigned long min,
+ unsigned long goal, unsigned long step)
+{
+ bool can_block = true;
+ bool can_wait = false;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return NULL;
+ }
+
+ if (min < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested min size %lx must be at least %x\n",
+ min, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(min | goal | step, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+
+ return __ocmem_allocate_range(client_id, min, goal,
+ step, can_block, can_wait);
+}
+
+struct ocmem_buf *ocmem_allocate_nb(int client_id, unsigned long size)
+{
+ bool can_block = true;
+ bool can_wait = false;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return NULL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return NULL;
+ }
+
+ if (size < OCMEM_MIN_ALLOC) {
+ pr_err("ocmem: requested size %lx must be at least %x\n",
+ size, OCMEM_MIN_ALLOC);
+ return NULL;
+ }
+
+ if (!IS_ALIGNED(size, OCMEM_MIN_ALIGN)) {
+ pr_err("ocmem: Invalid alignment, args must be %x aligned\n",
+ OCMEM_MIN_ALIGN);
+ return NULL;
+ }
+
+ return __ocmem_allocate_range(client_id, 0, size, size,
+ can_block, can_wait);
+
+}
+
+int ocmem_free(int client_id, struct ocmem_buf *buffer)
+{
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ if (!buffer) {
+ pr_err("ocmem: Invalid buffer\n");
+ return -EINVAL;
+ }
+
+ return __ocmem_free(client_id, buffer);
+}
+
+int pre_validate_chunk_list(struct ocmem_map_list *list)
+{
+ int i = 0;
+ struct ocmem_chunk *chunks;
+
+ if (!list)
+ return -EINVAL;
+
+ if (list->num_chunks > OCMEM_MAX_CHUNKS || list->num_chunks == 0)
+ return -EINVAL;
+
+ chunks = list->chunks;
+
+ if (!chunks)
+ return -EINVAL;
+
+ for (i = 0; i < list->num_chunks; i++) {
+ if (!chunks[i].ddr_paddr ||
+ chunks[i].size < MIN_CHUNK_SIZE)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int ocmem_map(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+ int ret = 0;
+ struct ocmem_handle *handle = NULL;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return -EINVAL;
+ }
+
+ if (!buffer) {
+ pr_err("ocmem: Invalid buffer\n");
+ return -EINVAL;
+ }
+
+ if (!pre_validate_chunk_list(list))
+ return -EINVAL;
+
+ handle = buffer_to_handle(buffer);
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_xfer(client_id, handle, list, TO_OCMEM);
+ mutex_unlock(&handle->handle_mutex);
+ return ret;
+}
+
+int ocmem_unmap(int client_id, struct ocmem_buf *buffer,
+ struct ocmem_map_list *list)
+{
+
+ int ret = 0;
+ struct ocmem_handle *handle = NULL;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return -EINVAL;
+ }
+
+ /* Asynchronous API requires notifier registration */
+ if (!check_notifier(client_id)) {
+ pr_err("ocmem: No notifier registered for client %d\n",
+ client_id);
+ return -EINVAL;
+ }
+
+ if (!buffer) {
+ pr_err("ocmem: Invalid buffer\n");
+ return -EINVAL;
+ }
+
+ if (!pre_validate_chunk_list(list))
+ return -EINVAL;
+
+ handle = buffer_to_handle(buffer);
+
+ if (!handle)
+ return -EINVAL;
+
+ mutex_lock(&handle->handle_mutex);
+ ret = process_xfer(client_id, handle, list, TO_DDR);
+ mutex_unlock(&handle->handle_mutex);
+ return ret;
+}
+
+unsigned long get_max_quota(int client_id)
+{
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid client id: %d\n", client_id);
+ return 0x0;
+ }
+ return process_quota(client_id);
+}
diff --git a/arch/arm/mach-msm/ocmem_notifier.c b/arch/arm/mach-msm/ocmem_notifier.c
new file mode 100644
index 0000000..58ad3d9
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_notifier.c
@@ -0,0 +1,137 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 <mach/ocmem_priv.h>
+#include <linux/hardirq.h>
+
+static unsigned notifier_threshold;
+
+/* Protect the notifier structure below */
+DEFINE_MUTEX(nc_lock);
+
+struct ocmem_notifier {
+ int owner;
+ struct atomic_notifier_head nc;
+ unsigned listeners;
+} notifiers[OCMEM_CLIENT_MAX];
+
+static int check_id(int id)
+{
+ return (id < OCMEM_CLIENT_MAX && id >= OCMEM_GRAPHICS);
+}
+
+int check_notifier(int id)
+{
+ int ret = 0;
+
+ if (!check_id(id))
+ return 0;
+
+ mutex_lock(&nc_lock);
+ ret = notifiers[id].listeners;
+ mutex_unlock(&nc_lock);
+ return ret;
+}
+
+int ocmem_notifier_init(void)
+{
+ int id;
+ /* Maximum notifiers for each subsystem */
+ notifier_threshold = 1;
+ mutex_lock(&nc_lock);
+ for (id = 0; id < OCMEM_CLIENT_MAX; id++) {
+ notifiers[id].owner = id;
+ ATOMIC_INIT_NOTIFIER_HEAD(¬ifiers[id].nc);
+ notifiers[id].listeners = 0;
+ }
+ mutex_unlock(&nc_lock);
+ return 0;
+}
+
+/* Broadcast a notification to listeners */
+int dispatch_notification(int id, enum ocmem_notif_type notif,
+ struct ocmem_buf *buf)
+{
+ int ret = 0;
+ struct ocmem_notifier *nc_hndl = NULL;
+ mutex_lock(&nc_lock);
+ nc_hndl = ¬ifiers[id];
+ if (nc_hndl->listeners == 0) {
+ /* Send an error so that the scheduler can clean up */
+ mutex_unlock(&nc_lock);
+ return -EINVAL;
+ }
+ ret = atomic_notifier_call_chain(¬ifiers[id].nc, notif, buf);
+ mutex_unlock(&nc_lock);
+ return ret;
+}
+
+void *ocmem_notifier_register(int client_id, struct notifier_block *nb)
+{
+
+ int ret = 0;
+ struct ocmem_notifier *nc_hndl = NULL;
+
+ if (!check_id(client_id)) {
+ pr_err("ocmem: Invalid Client id\n");
+ return NULL;
+ }
+
+ if (!nb) {
+ pr_err("ocmem: Invalid Notifier Block\n");
+ return NULL;
+ }
+
+ mutex_lock(&nc_lock);
+
+ nc_hndl = ¬ifiers[client_id];
+
+ if (nc_hndl->listeners >= notifier_threshold) {
+ pr_err("ocmem: Max notifiers already registered\n");
+ mutex_unlock(&nc_lock);
+ return NULL;
+ }
+
+ ret = atomic_notifier_chain_register(&nc_hndl->nc, nb);
+
+ if (ret < 0) {
+ mutex_unlock(&nc_lock);
+ return NULL;
+ }
+
+ nc_hndl->listeners++;
+ pr_info("ocmem: Notifier registered for %d\n", client_id);
+ mutex_unlock(&nc_lock);
+ return nc_hndl;
+}
+EXPORT_SYMBOL(ocmem_notifier_register);
+
+int ocmem_notifier_unregister(void *hndl, struct notifier_block *nb)
+{
+
+ int ret = 0;
+
+ struct ocmem_notifier *nc_hndl = (struct ocmem_notifier *) hndl;
+
+ if (!nc_hndl) {
+ pr_err("ocmem: Invalid notification handle\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&nc_lock);
+ ret = atomic_notifier_chain_unregister(&nc_hndl->nc, nb);
+ nc_hndl->listeners--;
+ mutex_unlock(&nc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(ocmem_notifier_unregister);
diff --git a/arch/arm/mach-msm/ocmem_sched.c b/arch/arm/mach-msm/ocmem_sched.c
new file mode 100644
index 0000000..10a267c
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem_sched.c
@@ -0,0 +1,1255 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.h>
+#include <linux/idr.h>
+#include <linux/genalloc.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <mach/ocmem_priv.h>
+
+enum request_states {
+ R_FREE = 0x0, /* request is not allocated */
+ R_PENDING, /* request has a pending operation */
+ R_ALLOCATED, /* request has been allocated */
+ R_MUST_GROW, /* request must grow as a part of pending operation */
+ R_MUST_SHRINK, /* request must shrink as a part of pending operation */
+ R_MUST_MAP, /* request must be mapped before being used */
+ R_MUST_UNMAP, /* request must be unmapped when not being used */
+ R_MAPPED, /* request is mapped and actively used by client */
+ R_UNMAPPED, /* request is not mapped, so it's not in active use */
+ R_EVICTED, /* request is evicted and must be restored */
+};
+
+#define SET_STATE(x, val) (set_bit((val), &(x)->state))
+#define CLEAR_STATE(x, val) (clear_bit((val), &(x)->state))
+#define TEST_STATE(x, val) (test_bit((val), &(x)->state))
+
+enum op_res {
+ OP_COMPLETE = 0x0,
+ OP_RESCHED,
+ OP_PARTIAL,
+ OP_FAIL = ~0x0,
+};
+
+/* Represents various client priorities */
+/* Note: More than one client can share a priority level */
+enum client_prio {
+ MIN_PRIO = 0x0,
+ NO_PRIO = MIN_PRIO,
+ PRIO_SENSORS = 0x1,
+ PRIO_BLAST = 0x1,
+ PRIO_LP_AUDIO = 0x1,
+ PRIO_HP_AUDIO = 0x2,
+ PRIO_VOICE = 0x3,
+ PRIO_GFX_GROWTH = 0x4,
+ PRIO_VIDEO = 0x5,
+ PRIO_GFX = 0x6,
+ PRIO_OCMEM = 0x7,
+ MAX_OCMEM_PRIO = PRIO_OCMEM + 1,
+};
+
+static struct list_head sched_queue[MAX_OCMEM_PRIO];
+static struct mutex sched_queue_mutex;
+
+/* The duration in msecs before a pending operation is scheduled
+ * This allows an idle window between use case boundaries where various
+ * hardware state changes can occur. The value will be tweaked on actual
+ * hardware.
+*/
+#define SCHED_DELAY 10
+
+/* OCMEM Operational modes */
+enum ocmem_client_modes {
+ OCMEM_PERFORMANCE = 1,
+ OCMEM_PASSIVE,
+ OCMEM_LOW_POWER,
+ OCMEM_MODE_MAX = OCMEM_LOW_POWER
+};
+
+/* OCMEM Addressing modes */
+enum ocmem_interconnects {
+ OCMEM_BLOCKED = 0,
+ OCMEM_PORT = 1,
+ OCMEM_OCMEMNOC = 2,
+ OCMEM_SYSNOC = 3,
+};
+
+/**
+ * Primary OCMEM Arbitration Table
+ **/
+struct ocmem_table {
+ int client_id;
+ int priority;
+ int mode;
+ int hw_interconnect;
+} ocmem_client_table[OCMEM_CLIENT_MAX] = {
+ {OCMEM_GRAPHICS, PRIO_GFX, OCMEM_PERFORMANCE, OCMEM_PORT},
+ {OCMEM_VIDEO, PRIO_VIDEO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+ {OCMEM_CAMERA, NO_PRIO, OCMEM_PERFORMANCE, OCMEM_OCMEMNOC},
+ {OCMEM_HP_AUDIO, PRIO_HP_AUDIO, OCMEM_PASSIVE, OCMEM_BLOCKED},
+ {OCMEM_VOICE, PRIO_VOICE, OCMEM_PASSIVE, OCMEM_BLOCKED},
+ {OCMEM_LP_AUDIO, PRIO_LP_AUDIO, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+ {OCMEM_SENSORS, PRIO_SENSORS, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+ {OCMEM_BLAST, PRIO_BLAST, OCMEM_LOW_POWER, OCMEM_SYSNOC},
+};
+
+static struct rb_root sched_tree;
+static struct mutex sched_mutex;
+
+/* A region represents a continuous interval in OCMEM address space */
+struct ocmem_region {
+ /* Chain in Interval Tree */
+ struct rb_node region_rb;
+ /* Hash map of requests */
+ struct idr region_idr;
+ unsigned long r_start;
+ unsigned long r_end;
+ unsigned long r_sz;
+ /* Highest priority of all requests served by this region */
+ int max_prio;
+};
+
+/* Is OCMEM tightly coupled to the client ?*/
+static inline int is_tcm(int id)
+{
+ if (ocmem_client_table[id].hw_interconnect == OCMEM_PORT ||
+ ocmem_client_table[id].hw_interconnect == OCMEM_OCMEMNOC)
+ return 1;
+ else
+ return 0;
+}
+
+static inline int is_blocked(int id)
+{
+ return ocmem_client_table[id].hw_interconnect == OCMEM_BLOCKED ? 1 : 0;
+}
+
+/* Returns the address that can be used by a device core to access OCMEM */
+static unsigned long device_address(int id, unsigned long addr)
+{
+ int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+ unsigned long ret_addr = 0x0;
+
+ switch (hw_interconnect) {
+ case OCMEM_PORT:
+ ret_addr = phys_to_offset(addr);
+ break;
+ case OCMEM_OCMEMNOC:
+ case OCMEM_SYSNOC:
+ ret_addr = addr;
+ break;
+ case OCMEM_BLOCKED:
+ ret_addr = 0x0;
+ break;
+ }
+ return ret_addr;
+}
+
+/* Returns the address as viewed by the core */
+static unsigned long core_address(int id, unsigned long addr)
+{
+ int hw_interconnect = ocmem_client_table[id].hw_interconnect;
+ unsigned long ret_addr = 0x0;
+
+ switch (hw_interconnect) {
+ case OCMEM_PORT:
+ ret_addr = offset_to_phys(addr);
+ break;
+ case OCMEM_OCMEMNOC:
+ case OCMEM_SYSNOC:
+ ret_addr = addr;
+ break;
+ case OCMEM_BLOCKED:
+ ret_addr = 0x0;
+ break;
+ }
+ return ret_addr;
+}
+
+static int insert_region(struct ocmem_region *region)
+{
+
+ struct rb_root *root = &sched_tree;
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+ struct ocmem_region *tmp = NULL;
+ unsigned long addr = region->r_start;
+
+ while (*p) {
+ parent = *p;
+ tmp = rb_entry(parent, struct ocmem_region, region_rb);
+
+ if (tmp->r_end > addr) {
+ if (tmp->r_start <= addr)
+ break;
+ p = &(*p)->rb_left;
+ } else if (tmp->r_end <= addr)
+ p = &(*p)->rb_right;
+ }
+ rb_link_node(®ion->region_rb, parent, p);
+ rb_insert_color(®ion->region_rb, root);
+ return 0;
+}
+
+static int remove_region(struct ocmem_region *region)
+{
+ struct rb_root *root = &sched_tree;
+ rb_erase(®ion->region_rb, root);
+ return 0;
+}
+
+static struct ocmem_req *ocmem_create_req(void)
+{
+ struct ocmem_req *p = NULL;
+
+ p = kzalloc(sizeof(struct ocmem_req), GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ INIT_LIST_HEAD(&p->zone_list);
+ INIT_LIST_HEAD(&p->sched_list);
+ init_rwsem(&p->rw_sem);
+ SET_STATE(p, R_FREE);
+ return p;
+}
+
+static int ocmem_destroy_req(struct ocmem_req *req)
+{
+ kfree(req);
+ return 0;
+}
+
+static struct ocmem_region *create_region(void)
+{
+ struct ocmem_region *p = NULL;
+
+ p = kzalloc(sizeof(struct ocmem_region), GFP_KERNEL);
+ if (!p)
+ return NULL;
+ idr_init(&p->region_idr);
+ p->r_start = p->r_end = p->r_sz = 0x0;
+ p->max_prio = NO_PRIO;
+ return p;
+}
+
+static int destroy_region(struct ocmem_region *region)
+{
+ kfree(region);
+ return 0;
+}
+
+static int attach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+ int ret, id;
+
+ while (1) {
+ if (idr_pre_get(®ion->region_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ ret = idr_get_new_above(®ion->region_idr, req, 1, &id);
+
+ if (ret != -EAGAIN)
+ break;
+ }
+
+ if (!ret) {
+ req->req_id = id;
+ pr_debug("ocmem: request %p(id:%d) attached to region %p\n",
+ req, id, region);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int detach_req(struct ocmem_region *region, struct ocmem_req *req)
+{
+ idr_remove(®ion->region_idr, req->req_id);
+ return 0;
+}
+
+static int populate_region(struct ocmem_region *region, struct ocmem_req *req)
+{
+ region->r_start = req->req_start;
+ region->r_end = req->req_end;
+ region->r_sz = req->req_end - req->req_start + 1;
+ return 0;
+}
+
+static int region_req_count(int id, void *ptr, void *data)
+{
+ int *count = data;
+ *count = *count + 1;
+ return 0;
+}
+
+static int req_count(struct ocmem_region *region)
+{
+ int count = 0;
+ idr_for_each(®ion->region_idr, region_req_count, &count);
+ return count;
+}
+
+static int compute_max_prio(int id, void *ptr, void *data)
+{
+ int *max = data;
+ struct ocmem_req *req = ptr;
+
+ if (req->prio > *max)
+ *max = req->prio;
+ return 0;
+}
+
+static int update_region_prio(struct ocmem_region *region)
+{
+ int max_prio;
+ if (req_count(region) != 0) {
+ idr_for_each(®ion->region_idr, compute_max_prio, &max_prio);
+ region->max_prio = max_prio;
+ } else {
+ region->max_prio = NO_PRIO;
+ }
+ pr_debug("ocmem: Updating prio of region %p as %d\n",
+ region, max_prio);
+
+ return 0;
+}
+
+static struct ocmem_region *find_region(unsigned long addr)
+{
+ struct ocmem_region *region = NULL;
+ struct rb_node *rb_node = NULL;
+
+ rb_node = sched_tree.rb_node;
+
+ while (rb_node) {
+ struct ocmem_region *tmp_region = NULL;
+ tmp_region = rb_entry(rb_node, struct ocmem_region, region_rb);
+
+ if (tmp_region->r_end > addr) {
+ region = tmp_region;
+ if (tmp_region->r_start <= addr)
+ break;
+ rb_node = rb_node->rb_left;
+ } else {
+ rb_node = rb_node->rb_right;
+ }
+ }
+ return region;
+}
+
+static struct ocmem_region *find_region_intersection(unsigned long start,
+ unsigned long end)
+{
+
+ struct ocmem_region *region = NULL;
+ region = find_region(start);
+ if (region && end <= region->r_start)
+ region = NULL;
+ return region;
+}
+
+static struct ocmem_region *find_region_match(unsigned long start,
+ unsigned long end)
+{
+
+ struct ocmem_region *region = NULL;
+ region = find_region(start);
+ if (region && start == region->r_start && end == region->r_end)
+ return region;
+ return NULL;
+}
+
+static struct ocmem_req *find_req_match(int owner, struct ocmem_region *region)
+{
+ struct ocmem_req *req = NULL;
+
+ if (!region)
+ return NULL;
+
+ req = idr_find(®ion->region_idr, owner);
+
+ return req;
+}
+
+/* Must be called with req->sem held */
+static inline int is_mapped(struct ocmem_req *req)
+{
+ return TEST_STATE(req, R_MAPPED);
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_unmap(struct ocmem_req *req)
+{
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req) {
+ pr_err("Could not find backing region for req");
+ goto invalid_op_error;
+ }
+
+ if (matched_req != req) {
+ pr_err("Request does not match backing req");
+ goto invalid_op_error;
+ }
+
+ if (!is_mapped(req)) {
+ pr_err("Request is not currently mapped");
+ goto invalid_op_error;
+ }
+
+ /* Update the request state */
+ CLEAR_STATE(req, R_MAPPED);
+ SET_STATE(req, R_MUST_MAP);
+
+ return OP_COMPLETE;
+
+invalid_op_error:
+ return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_map(struct ocmem_req *req)
+{
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req) {
+ pr_err("Could not find backing region for req");
+ goto invalid_op_error;
+ }
+
+ if (matched_req != req) {
+ pr_err("Request does not match backing req");
+ goto invalid_op_error;
+ }
+
+ /* Update the request state */
+ CLEAR_STATE(req, R_MUST_MAP);
+ SET_STATE(req, R_MAPPED);
+
+ return OP_COMPLETE;
+
+invalid_op_error:
+ return OP_FAIL;
+}
+
+static int do_map(struct ocmem_req *req)
+{
+ int rc = 0;
+
+ mutex_lock(&sched_mutex);
+ rc = __sched_map(req);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int do_unmap(struct ocmem_req *req)
+{
+ int rc = 0;
+
+ mutex_lock(&sched_mutex);
+ rc = __sched_unmap(req);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* process map is a wrapper where power control will be added later */
+static int process_map(struct ocmem_req *req, unsigned long start,
+ unsigned long end)
+{
+ return do_map(req);
+}
+
+/* process unmap is a wrapper where power control will be added later */
+static int process_unmap(struct ocmem_req *req, unsigned long start,
+ unsigned long end)
+{
+ return do_unmap(req);
+}
+
+static int __sched_grow(struct ocmem_req *req, bool can_block)
+{
+ unsigned long min = req->req_min;
+ unsigned long max = req->req_max;
+ unsigned long step = req->req_step;
+ int owner = req->owner;
+ unsigned long curr_sz = 0;
+ unsigned long growth_sz = 0;
+ unsigned long curr_start = 0;
+ enum client_prio prio = req->prio;
+ unsigned long alloc_addr = 0x0;
+ bool retry;
+ struct ocmem_region *spanned_r = NULL;
+ struct ocmem_region *overlap_r = NULL;
+
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ struct ocmem_zone *zone = get_zone(owner);
+ struct ocmem_region *region = NULL;
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req) {
+ pr_err("Could not find backing region for req");
+ goto invalid_op_error;
+ }
+
+ if (matched_req != req) {
+ pr_err("Request does not match backing req");
+ goto invalid_op_error;
+ }
+
+ curr_sz = matched_req->req_sz;
+ curr_start = matched_req->req_start;
+ growth_sz = matched_req->req_max - matched_req->req_sz;
+
+ pr_debug("Attempting to grow req %p from %lx to %lx\n",
+ req, matched_req->req_sz, matched_req->req_max);
+
+ retry = false;
+
+ pr_debug("ocmem: GROW: growth size %lx\n", growth_sz);
+
+retry_next_step:
+
+ spanned_r = NULL;
+ overlap_r = NULL;
+
+ spanned_r = find_region(zone->z_head);
+ overlap_r = find_region_intersection(zone->z_head,
+ zone->z_head + growth_sz);
+
+ if (overlap_r == NULL) {
+ /* no conflicting regions, schedule this region */
+ zone->z_ops->free(zone, curr_start, curr_sz);
+ alloc_addr = zone->z_ops->allocate(zone, curr_sz + growth_sz);
+
+ if (alloc_addr < 0) {
+ pr_err("ocmem: zone allocation operation failed\n");
+ goto internal_error;
+ }
+
+ curr_sz += growth_sz;
+ /* Detach the region from the interval tree */
+ /* This is to guarantee that any change in size
+ * causes the tree to be rebalanced if required */
+
+ detach_req(matched_region, req);
+ if (req_count(matched_region) == 0) {
+ remove_region(matched_region);
+ region = matched_region;
+ } else {
+ region = create_region();
+ if (!region) {
+ pr_err("ocmem: Unable to create region\n");
+ goto region_error;
+ }
+ }
+
+ /* update the request */
+ req->req_start = alloc_addr;
+ /* increment the size to reflect new length */
+ req->req_sz = curr_sz;
+ req->req_end = alloc_addr + req->req_sz - 1;
+
+ /* update request state */
+ CLEAR_STATE(req, R_MUST_GROW);
+ SET_STATE(req, R_ALLOCATED);
+ SET_STATE(req, R_MUST_MAP);
+ req->op = SCHED_MAP;
+
+ /* update the region with new req */
+ attach_req(region, req);
+ populate_region(region, req);
+ update_region_prio(region);
+
+ /* update the tree with new region */
+ if (insert_region(region)) {
+ pr_err("ocmem: Failed to insert the region\n");
+ goto region_error;
+ }
+
+ if (retry) {
+ SET_STATE(req, R_MUST_GROW);
+ SET_STATE(req, R_PENDING);
+ req->op = SCHED_GROW;
+ return OP_PARTIAL;
+ }
+ } else if (spanned_r != NULL && overlap_r != NULL) {
+ /* resolve conflicting regions based on priority */
+ if (overlap_r->max_prio < prio) {
+ /* Growth cannot be triggered unless a previous
+ * client of lower priority was evicted */
+ pr_err("ocmem: Invalid growth scheduled\n");
+ /* This is serious enough to fail */
+ BUG();
+ return OP_FAIL;
+ } else if (overlap_r->max_prio > prio) {
+ if (min == max) {
+ /* Cannot grow at this time, try later */
+ SET_STATE(req, R_PENDING);
+ SET_STATE(req, R_MUST_GROW);
+ return OP_RESCHED;
+ } else {
+ /* Try to grow in steps */
+ growth_sz -= step;
+ /* We are OOM at this point so need to retry */
+ if (growth_sz <= curr_sz) {
+ SET_STATE(req, R_PENDING);
+ SET_STATE(req, R_MUST_GROW);
+ return OP_RESCHED;
+ }
+ retry = true;
+ pr_debug("ocmem: Attempting with reduced size %lx\n",
+ growth_sz);
+ goto retry_next_step;
+ }
+ } else {
+ pr_err("ocmem: grow: New Region %p Existing %p\n",
+ matched_region, overlap_r);
+ pr_err("ocmem: Undetermined behavior\n");
+ /* This is serious enough to fail */
+ BUG();
+ }
+ } else if (spanned_r == NULL && overlap_r != NULL) {
+ goto err_not_supported;
+ }
+
+ return OP_COMPLETE;
+
+err_not_supported:
+ pr_err("ocmem: Scheduled unsupported operation\n");
+ return OP_FAIL;
+region_error:
+ zone->z_ops->free(zone, alloc_addr, curr_sz);
+ detach_req(region, req);
+ update_region_prio(region);
+ /* req is going to be destroyed by the caller anyways */
+internal_error:
+ destroy_region(region);
+invalid_op_error:
+ return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_free(struct ocmem_req *req)
+{
+ int owner = req->owner;
+ int ret = 0;
+
+ struct ocmem_req *matched_req = NULL;
+ struct ocmem_region *matched_region = NULL;
+
+ struct ocmem_zone *zone = get_zone(owner);
+
+ BUG_ON(!zone);
+
+ matched_region = find_region_match(req->req_start, req->req_end);
+ matched_req = find_req_match(req->req_id, matched_region);
+
+ if (!matched_region || !matched_req)
+ goto invalid_op_error;
+ if (matched_req != req)
+ goto invalid_op_error;
+
+ ret = zone->z_ops->free(zone,
+ matched_req->req_start, matched_req->req_sz);
+
+ if (ret < 0)
+ goto err_op_fail;
+
+ detach_req(matched_region, matched_req);
+ update_region_prio(matched_region);
+ if (req_count(matched_region) == 0) {
+ remove_region(matched_region);
+ destroy_region(matched_region);
+ }
+
+ /* Update the request */
+ req->req_start = 0x0;
+ req->req_sz = 0x0;
+ req->req_end = 0x0;
+ SET_STATE(req, R_FREE);
+ return OP_COMPLETE;
+invalid_op_error:
+ pr_err("ocmem: free: Failed to find matching region\n");
+err_op_fail:
+ pr_err("ocmem: free: Failed\n");
+ return OP_FAIL;
+}
+
+/* Must be called with sched_mutex held */
+static int __sched_allocate(struct ocmem_req *req, bool can_block,
+ bool can_wait)
+{
+ unsigned long min = req->req_min;
+ unsigned long max = req->req_max;
+ unsigned long step = req->req_step;
+ int owner = req->owner;
+ unsigned long sz = max;
+ enum client_prio prio = req->prio;
+ unsigned long alloc_addr = 0x0;
+ bool retry;
+
+ struct ocmem_region *spanned_r = NULL;
+ struct ocmem_region *overlap_r = NULL;
+
+ struct ocmem_zone *zone = get_zone(owner);
+ struct ocmem_region *region = NULL;
+
+ BUG_ON(!zone);
+
+ if (min > (zone->z_end - zone->z_start)) {
+ pr_err("ocmem: requested minimum size exceeds quota\n");
+ goto invalid_op_error;
+ }
+
+ if (max > (zone->z_end - zone->z_start)) {
+ pr_err("ocmem: requested maximum size exceeds quota\n");
+ goto invalid_op_error;
+ }
+
+ if (min > zone->z_free) {
+ pr_err("ocmem: out of memory for zone %d\n", owner);
+ goto invalid_op_error;
+ }
+
+ region = create_region();
+
+ if (!region) {
+ pr_err("ocmem: Unable to create region\n");
+ goto invalid_op_error;
+ }
+
+ retry = false;
+
+ pr_debug("ocmem: ALLOCATE: request size %lx\n", sz);
+
+retry_next_step:
+
+ spanned_r = NULL;
+ overlap_r = NULL;
+
+ spanned_r = find_region(zone->z_head);
+ overlap_r = find_region_intersection(zone->z_head, zone->z_head + sz);
+
+ if (overlap_r == NULL) {
+ /* no conflicting regions, schedule this region */
+ alloc_addr = zone->z_ops->allocate(zone, sz);
+
+ if (alloc_addr < 0) {
+ pr_err("Zone Allocation operation failed\n");
+ goto internal_error;
+ }
+
+ /* update the request */
+ req->req_start = alloc_addr;
+ req->req_end = alloc_addr + sz - 1;
+ req->req_sz = sz;
+ req->zone = zone;
+
+ /* update request state */
+ CLEAR_STATE(req, R_FREE);
+ SET_STATE(req, R_ALLOCATED);
+ SET_STATE(req, R_MUST_MAP);
+ req->op = SCHED_NOP;
+
+ /* attach the request to the region */
+ attach_req(region, req);
+ populate_region(region, req);
+ update_region_prio(region);
+
+ /* update the tree with new region */
+ if (insert_region(region)) {
+ pr_err("ocmem: Failed to insert the region\n");
+ zone->z_ops->free(zone, alloc_addr, sz);
+ detach_req(region, req);
+ update_region_prio(region);
+ /* req will be destroyed by the caller */
+ goto internal_error;
+ }
+
+ if (retry) {
+ SET_STATE(req, R_MUST_GROW);
+ SET_STATE(req, R_PENDING);
+ req->op = SCHED_GROW;
+ return OP_PARTIAL;
+ }
+ } else if (spanned_r != NULL && overlap_r != NULL) {
+ /* resolve conflicting regions based on priority */
+ if (overlap_r->max_prio < prio) {
+ if (min == max) {
+ pr_err("ocmem: Requires eviction support\n");
+ goto err_not_supported;
+ } else {
+ /* Try to allocate atleast >= 'min' immediately */
+ sz -= step;
+ if (sz < min)
+ goto err_out_of_mem;
+ retry = true;
+ pr_debug("ocmem: Attempting with reduced size %lx\n",
+ sz);
+ goto retry_next_step;
+ }
+ } else if (overlap_r->max_prio > prio) {
+ if (can_block == true) {
+ SET_STATE(req, R_PENDING);
+ SET_STATE(req, R_MUST_GROW);
+ return OP_RESCHED;
+ } else {
+ if (min == max) {
+ pr_err("Cannot allocate %lx synchronously\n",
+ sz);
+ goto err_out_of_mem;
+ } else {
+ sz -= step;
+ if (sz < min)
+ goto err_out_of_mem;
+ retry = true;
+ pr_debug("ocmem: Attempting reduced size %lx\n",
+ sz);
+ goto retry_next_step;
+ }
+ }
+ } else {
+ pr_err("ocmem: Undetermined behavior\n");
+ pr_err("ocmem: New Region %p Existing %p\n", region,
+ overlap_r);
+ /* This is serious enough to fail */
+ BUG();
+ }
+ } else if (spanned_r == NULL && overlap_r != NULL)
+ goto err_not_supported;
+
+ return OP_COMPLETE;
+
+err_not_supported:
+ pr_err("ocmem: Scheduled unsupported operation\n");
+ return OP_FAIL;
+
+err_out_of_mem:
+ pr_err("ocmem: Out of memory during allocation\n");
+internal_error:
+ destroy_region(region);
+invalid_op_error:
+ return OP_FAIL;
+}
+
+static int sched_enqueue(struct ocmem_req *priv)
+{
+ struct ocmem_req *next = NULL;
+ mutex_lock(&sched_queue_mutex);
+ list_add_tail(&priv->sched_list, &sched_queue[priv->owner]);
+ pr_debug("enqueued req %p\n", priv);
+ list_for_each_entry(next, &sched_queue[priv->owner], sched_list) {
+ pr_debug("pending requests for client %p\n", next);
+ }
+ mutex_unlock(&sched_queue_mutex);
+ return 0;
+}
+
+static struct ocmem_req *ocmem_fetch_req(void)
+{
+ int i;
+ struct ocmem_req *req = NULL;
+ struct ocmem_req *next = NULL;
+
+ mutex_lock(&sched_queue_mutex);
+ for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++) {
+ if (list_empty(&sched_queue[i]))
+ continue;
+ list_for_each_entry_safe(req, next, &sched_queue[i], sched_list)
+ {
+ if (req) {
+ pr_debug("ocmem: Fetched pending request %p\n",
+ req);
+ list_del(&req->sched_list);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&sched_queue_mutex);
+ return req;
+}
+
+int process_xfer(int id, struct ocmem_handle *handle,
+ struct ocmem_map_list *list, int direction)
+{
+
+ return 0;
+}
+
+unsigned long process_quota(int id)
+{
+ struct ocmem_zone *zone = NULL;
+
+ if (is_blocked(id))
+ return 0;
+
+ zone = get_zone(id);
+
+ if (zone && zone->z_pool)
+ return zone->z_end - zone->z_start;
+ else
+ return 0;
+}
+
+static int do_grow(struct ocmem_req *req)
+{
+ struct ocmem_buf *buffer = NULL;
+ bool can_block = true;
+ int rc = 0;
+
+ down_write(&req->rw_sem);
+ buffer = req->buffer;
+
+ /* Take the scheduler mutex */
+ mutex_lock(&sched_mutex);
+ rc = __sched_grow(req, can_block);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ goto err_op_fail;
+
+ if (rc == OP_RESCHED) {
+ pr_debug("ocmem: Enqueue this allocation");
+ sched_enqueue(req);
+ }
+
+ else if (rc == OP_COMPLETE || rc == OP_PARTIAL) {
+ buffer->addr = device_address(req->owner, req->req_start);
+ buffer->len = req->req_sz;
+ }
+
+ up_write(&req->rw_sem);
+ return 0;
+err_op_fail:
+ up_write(&req->rw_sem);
+ return -EINVAL;
+}
+
+static int process_grow(struct ocmem_req *req)
+{
+ int rc = 0;
+
+ /* Attempt to grow the region */
+ rc = do_grow(req);
+
+ if (rc < 0)
+ return -EINVAL;
+
+ /* Map the newly grown region */
+ if (is_tcm(req->owner)) {
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
+ }
+
+ /* Notify the client about the buffer growth */
+ rc = dispatch_notification(req->owner, OCMEM_ALLOC_GROW, req->buffer);
+ if (rc < 0) {
+ pr_err("No notifier callback to cater for req %p event: %d\n",
+ req, OCMEM_ALLOC_GROW);
+ BUG();
+ }
+ return 0;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work);
+DECLARE_DELAYED_WORK(ocmem_sched_thread, ocmem_sched_wk_func);
+
+static int ocmem_schedule_pending(void)
+{
+ schedule_delayed_work(&ocmem_sched_thread,
+ msecs_to_jiffies(SCHED_DELAY));
+ return 0;
+}
+
+static int do_free(struct ocmem_req *req)
+{
+ int rc = 0;
+ struct ocmem_buf *buffer = req->buffer;
+
+ down_write(&req->rw_sem);
+
+ if (is_mapped(req)) {
+ pr_err("ocmem: Buffer needs to be unmapped before free\n");
+ goto err_free_fail;
+ }
+
+ /* Grab the sched mutex */
+ mutex_lock(&sched_mutex);
+ rc = __sched_free(req);
+ mutex_unlock(&sched_mutex);
+
+ switch (rc) {
+
+ case OP_COMPLETE:
+ buffer->addr = 0x0;
+ buffer->len = 0x0;
+ break;
+ case OP_FAIL:
+ default:
+ goto err_free_fail;
+ break;
+ }
+
+ up_write(&req->rw_sem);
+ return 0;
+err_free_fail:
+ up_write(&req->rw_sem);
+ pr_err("ocmem: freeing req %p failed\n", req);
+ return -EINVAL;
+}
+
+int process_free(int id, struct ocmem_handle *handle)
+{
+ struct ocmem_req *req = NULL;
+ struct ocmem_buf *buffer = NULL;
+ int rc = 0;
+
+ if (is_blocked(id)) {
+ pr_err("Client %d cannot request free\n", id);
+ return -EINVAL;
+ }
+
+ req = handle_to_req(handle);
+ buffer = handle_to_buffer(handle);
+
+ if (!req)
+ return -EINVAL;
+
+ if (req->req_start != core_address(id, buffer->addr)) {
+ pr_err("Invalid buffer handle passed for free\n");
+ return -EINVAL;
+ }
+
+ if (is_tcm(req->owner)) {
+ rc = process_unmap(req, req->req_start, req->req_end);
+ if (rc < 0)
+ return -EINVAL;
+ }
+
+ rc = do_free(req);
+
+ if (rc < 0)
+ return -EINVAL;
+
+ ocmem_destroy_req(req);
+ handle->req = NULL;
+
+ ocmem_schedule_pending();
+ return 0;
+}
+
+static int do_allocate(struct ocmem_req *req, bool can_block, bool can_wait)
+{
+ int rc = 0;
+ struct ocmem_buf *buffer = req->buffer;
+
+ down_write(&req->rw_sem);
+
+ /* Take the scheduler mutex */
+ mutex_lock(&sched_mutex);
+ rc = __sched_allocate(req, can_block, can_wait);
+ mutex_unlock(&sched_mutex);
+
+ if (rc == OP_FAIL)
+ goto err_allocate_fail;
+
+ if (rc == OP_RESCHED) {
+ buffer->addr = 0x0;
+ buffer->len = 0x0;
+ pr_debug("ocmem: Enqueuing req %p\n", req);
+ sched_enqueue(req);
+ } else if (rc == OP_PARTIAL) {
+ buffer->addr = device_address(req->owner, req->req_start);
+ buffer->len = req->req_sz;
+ pr_debug("ocmem: Enqueuing req %p\n", req);
+ sched_enqueue(req);
+ } else if (rc == OP_COMPLETE) {
+ buffer->addr = device_address(req->owner, req->req_start);
+ buffer->len = req->req_sz;
+ }
+
+ up_write(&req->rw_sem);
+ return 0;
+err_allocate_fail:
+ up_write(&req->rw_sem);
+ return -EINVAL;
+}
+
+
+int process_allocate(int id, struct ocmem_handle *handle,
+ unsigned long min, unsigned long max,
+ unsigned long step, bool can_block, bool can_wait)
+{
+
+ struct ocmem_req *req = NULL;
+ struct ocmem_buf *buffer = NULL;
+ int rc = 0;
+
+ /* sanity checks */
+ if (is_blocked(id)) {
+ pr_err("Client %d cannot request allocation\n", id);
+ return -EINVAL;
+ }
+
+ if (handle->req != NULL) {
+ pr_err("Invalid handle passed in\n");
+ return -EINVAL;
+ }
+
+ buffer = handle_to_buffer(handle);
+ BUG_ON(buffer == NULL);
+
+ /* prepare a request structure to represent this transaction */
+ req = ocmem_create_req();
+ if (!req)
+ return -ENOMEM;
+
+ req->owner = id;
+ req->req_min = min;
+ req->req_max = max;
+ req->req_step = step;
+ req->prio = ocmem_client_table[id].priority;
+ req->op = SCHED_ALLOCATE;
+ req->buffer = buffer;
+
+ rc = do_allocate(req, can_block, can_wait);
+
+ if (rc < 0)
+ goto do_allocate_error;
+
+ handle->req = req;
+
+ if (is_tcm(id)) {
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ goto map_error;
+ }
+
+ return 0;
+
+map_error:
+ handle->req = NULL;
+ do_free(req);
+do_allocate_error:
+ ocmem_destroy_req(req);
+ return -EINVAL;
+}
+
+int process_delayed_allocate(struct ocmem_req *req)
+{
+
+ struct ocmem_handle *handle = NULL;
+ int rc = 0;
+ int id = req->owner;
+
+ handle = req_to_handle(req);
+ BUG_ON(handle == NULL);
+
+ rc = do_allocate(req, true, false);
+
+ if (rc < 0)
+ goto do_allocate_error;
+
+ if (is_tcm(id)) {
+ rc = process_map(req, req->req_start, req->req_end);
+ if (rc < 0)
+ goto map_error;
+ }
+
+ /* Notify the client about the buffer growth */
+ rc = dispatch_notification(id, OCMEM_ALLOC_GROW, req->buffer);
+ if (rc < 0) {
+ pr_err("No notifier callback to cater for req %p event: %d\n",
+ req, OCMEM_ALLOC_GROW);
+ BUG();
+ }
+ return 0;
+
+map_error:
+ handle->req = NULL;
+ do_free(req);
+do_allocate_error:
+ ocmem_destroy_req(req);
+ return -EINVAL;
+}
+
+static void ocmem_sched_wk_func(struct work_struct *work)
+{
+
+ struct ocmem_buf *buffer = NULL;
+ struct ocmem_handle *handle = NULL;
+ struct ocmem_req *req = ocmem_fetch_req();
+
+ if (!req) {
+ pr_debug("No Pending Requests found\n");
+ return;
+ }
+
+ pr_debug("ocmem: sched_wk pending req %p\n", req);
+ handle = req_to_handle(req);
+ buffer = handle_to_buffer(handle);
+ BUG_ON(req->op == SCHED_NOP);
+
+ switch (req->op) {
+ case SCHED_GROW:
+ process_grow(req);
+ break;
+ case SCHED_ALLOCATE:
+ process_delayed_allocate(req);
+ break;
+ default:
+ pr_err("ocmem: Unknown operation encountered\n");
+ break;
+ }
+ return;
+}
+
+int ocmem_sched_init(void)
+{
+ int i = 0;
+ sched_tree = RB_ROOT;
+ mutex_init(&sched_mutex);
+ mutex_init(&sched_queue_mutex);
+ for (i = MIN_PRIO; i < MAX_OCMEM_PRIO; i++)
+ INIT_LIST_HEAD(&sched_queue[i]);
+
+ return 0;
+}
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
new file mode 100644
index 0000000..d82f4dd
--- /dev/null
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2011, 2012 Code Aurora Forum. 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/irq.h>
+#include <asm/pmu.h>
+#include <linux/platform_device.h>
+
+#include <mach/msm-krait-l2-accessors.h>
+
+#define MAX_L2_PERIOD ((1ULL << 32) - 1)
+#define MAX_KRAIT_L2_CTRS 5
+
+#define L2PMCCNTR 0x409
+#define L2PMCCNTCR 0x408
+#define L2PMCCNTSR 0x40A
+#define L2CYCLE_CTR_BIT 31
+#define L2CYCLE_CTR_EVENT_IDX 4
+#define L2CYCLE_CTR_RAW_CODE 0xfe
+
+#define L2PMOVSR 0x406
+
+#define L2PMCR 0x400
+#define L2PMCR_RESET_ALL 0x6
+#define L2PMCR_GLOBAL_ENABLE 0x1
+#define L2PMCR_GLOBAL_DISABLE 0x0
+
+#define L2PMCNTENSET 0x403
+#define L2PMCNTENCLR 0x402
+
+#define L2PMINTENSET 0x405
+#define L2PMINTENCLR 0x404
+
+#define IA_L2PMXEVCNTCR_BASE 0x420
+#define IA_L2PMXEVTYPER_BASE 0x424
+#define IA_L2PMRESX_BASE 0x410
+#define IA_L2PMXEVFILTER_BASE 0x423
+#define IA_L2PMXEVCNTR_BASE 0x421
+
+/* event format is -e rsRCCG See get_event_desc() */
+
+#define EVENT_REG_MASK 0xf000
+#define EVENT_GROUPSEL_MASK 0x000f
+#define EVENT_GROUPCODE_MASK 0x0ff0
+#define EVENT_REG_SHIFT 12
+#define EVENT_GROUPCODE_SHIFT 4
+
+#define RESRX_VALUE_EN 0x80000000
+
+static u32 l2_orig_filter_prefix = 0x000f0030;
+
+static u32 pmu_type;
+
+static struct arm_pmu krait_l2_pmu;
+
+static struct perf_event *l2_events[MAX_KRAIT_L2_CTRS];
+static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_KRAIT_L2_CTRS)];
+
+static struct pmu_hw_events krait_l2_pmu_hw_events = {
+ .events = l2_events,
+ .used_mask = l2_used_mask,
+ .pmu_lock = __RAW_SPIN_LOCK_UNLOCKED(krait_l2_pmu_hw_events.pmu_lock),
+};
+
+struct event_desc {
+ int event_groupsel;
+ int event_reg;
+ int event_group_code;
+};
+
+static struct pmu_hw_events *krait_l2_get_hw_events(void)
+{
+ return &krait_l2_pmu_hw_events;
+}
+
+void get_event_desc(u64 config, struct event_desc *evdesc)
+{
+ /* L2PMEVCNTRX */
+ evdesc->event_reg = (config & EVENT_REG_MASK) >> EVENT_REG_SHIFT;
+ /* Group code (row ) */
+ evdesc->event_group_code =
+ (config & EVENT_GROUPCODE_MASK) >> EVENT_GROUPCODE_SHIFT;
+ /* Group sel (col) */
+ evdesc->event_groupsel = (config & EVENT_GROUPSEL_MASK);
+
+ pr_debug("%s: reg: %x, group_code: %x, groupsel: %x\n", __func__,
+ evdesc->event_reg, evdesc->event_group_code,
+ evdesc->event_groupsel);
+}
+
+static void set_evcntcr(int ctr)
+{
+ u32 evtcr_reg = (ctr * 16) + IA_L2PMXEVCNTCR_BASE;
+
+ set_l2_indirect_reg(evtcr_reg, 0x0);
+}
+
+static void set_evtyper(int event_groupsel, int event_reg, int ctr)
+{
+ u32 evtype_reg = (ctr * 16) + IA_L2PMXEVTYPER_BASE;
+ u32 evtype_val = event_groupsel + (4 * event_reg);
+
+ set_l2_indirect_reg(evtype_reg, evtype_val);
+}
+
+static void set_evres(int event_groupsel, int event_reg, int event_group_code)
+{
+ u32 group_reg = event_reg + IA_L2PMRESX_BASE;
+ u32 group_val =
+ RESRX_VALUE_EN | (event_group_code << (8 * event_groupsel));
+ u32 resr_val;
+ u32 group_byte = 0xff;
+ u32 group_mask = ~(group_byte << (8 * event_groupsel));
+
+ resr_val = get_l2_indirect_reg(group_reg);
+ resr_val &= group_mask;
+ resr_val |= group_val;
+
+ set_l2_indirect_reg(group_reg, resr_val);
+}
+
+static void set_evfilter_task_mode(int ctr)
+{
+ u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
+ u32 filter_val = l2_orig_filter_prefix | 1 << smp_processor_id();
+
+ set_l2_indirect_reg(filter_reg, filter_val);
+}
+
+static void set_evfilter_sys_mode(int ctr)
+{
+ u32 filter_reg = (ctr * 16) + IA_L2PMXEVFILTER_BASE;
+ u32 filter_val = l2_orig_filter_prefix | 0xf;
+
+ set_l2_indirect_reg(filter_reg, filter_val);
+}
+
+static void enable_intenset(u32 idx)
+{
+ if (idx == L2CYCLE_CTR_EVENT_IDX)
+ set_l2_indirect_reg(L2PMINTENSET, 1 << L2CYCLE_CTR_BIT);
+ else
+ set_l2_indirect_reg(L2PMINTENSET, 1 << idx);
+}
+
+static void disable_intenclr(u32 idx)
+{
+ if (idx == L2CYCLE_CTR_EVENT_IDX)
+ set_l2_indirect_reg(L2PMINTENCLR, 1 << L2CYCLE_CTR_BIT);
+ else
+ set_l2_indirect_reg(L2PMINTENCLR, 1 << idx);
+}
+
+static void enable_counter(u32 idx)
+{
+ if (idx == L2CYCLE_CTR_EVENT_IDX)
+ set_l2_indirect_reg(L2PMCNTENSET, 1 << L2CYCLE_CTR_BIT);
+ else
+ set_l2_indirect_reg(L2PMCNTENSET, 1 << idx);
+}
+
+static void disable_counter(u32 idx)
+{
+ if (idx == L2CYCLE_CTR_EVENT_IDX)
+ set_l2_indirect_reg(L2PMCNTENCLR, 1 << L2CYCLE_CTR_BIT);
+ else
+ set_l2_indirect_reg(L2PMCNTENCLR, 1 << idx);
+}
+
+static u32 krait_l2_read_counter(int idx)
+{
+ u32 val;
+ u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
+
+ if (idx == L2CYCLE_CTR_EVENT_IDX)
+ val = get_l2_indirect_reg(L2PMCCNTR);
+ else
+ val = get_l2_indirect_reg(counter_reg);
+
+ return val;
+}
+
+static void krait_l2_write_counter(int idx, u32 val)
+{
+ u32 counter_reg = (idx * 16) + IA_L2PMXEVCNTR_BASE;
+
+ if (idx == L2CYCLE_CTR_EVENT_IDX)
+ set_l2_indirect_reg(L2PMCCNTR, val);
+ else
+ set_l2_indirect_reg(counter_reg, val);
+}
+
+static void krait_l2_stop_counter(struct hw_perf_event *hwc, int idx)
+{
+ disable_intenclr(idx);
+ disable_counter(idx);
+
+ pr_debug("%s: event: %ld ctr: %d stopped\n", __func__,
+ hwc->config_base, idx);
+}
+
+static void krait_l2_enable(struct hw_perf_event *hwc, int idx, int cpu)
+{
+ struct event_desc evdesc;
+ unsigned long iflags;
+
+ raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+ if (hwc->config_base == L2CYCLE_CTR_RAW_CODE)
+ goto out;
+
+ set_evcntcr(idx);
+
+ memset(&evdesc, 0, sizeof(evdesc));
+
+ get_event_desc(hwc->config_base, &evdesc);
+
+ set_evtyper(evdesc.event_groupsel, evdesc.event_reg, idx);
+
+ set_evres(evdesc.event_groupsel, evdesc.event_reg,
+ evdesc.event_group_code);
+
+ if (cpu < 0)
+ set_evfilter_task_mode(idx);
+ else
+ set_evfilter_sys_mode(idx);
+
+out:
+ enable_intenset(idx);
+ enable_counter(idx);
+
+ raw_spin_unlock_irqrestore(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+ pr_debug("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
+ __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
+}
+
+static void krait_l2_disable(struct hw_perf_event *hwc, int idx)
+{
+ unsigned long iflags;
+
+ raw_spin_lock_irqsave(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+ krait_l2_stop_counter(hwc, idx);
+
+ raw_spin_unlock_irqrestore(&krait_l2_pmu_hw_events.pmu_lock, iflags);
+
+ pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
+
+}
+
+static int krait_l2_get_event_idx(struct pmu_hw_events *cpuc,
+ struct hw_perf_event *hwc)
+{
+ int ctr = 0;
+
+ if (hwc->config_base == L2CYCLE_CTR_RAW_CODE) {
+ if (!test_and_set_bit(L2CYCLE_CTR_EVENT_IDX, cpuc->used_mask))
+ return L2CYCLE_CTR_EVENT_IDX;
+ }
+
+ for (ctr = 0; ctr < MAX_KRAIT_L2_CTRS - 1; ctr++) {
+ if (!test_and_set_bit(ctr, cpuc->used_mask))
+ return ctr;
+ }
+
+ return -EAGAIN;
+}
+
+static void krait_l2_start(void)
+{
+ isb();
+ set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_ENABLE);
+}
+
+static void krait_l2_stop(void)
+{
+ set_l2_indirect_reg(L2PMCR, L2PMCR_GLOBAL_DISABLE);
+ isb();
+}
+
+u32 get_reset_pmovsr(void)
+{
+ int val;
+
+ val = get_l2_indirect_reg(L2PMOVSR);
+ /* reset it */
+ val &= 0xffffffff;
+ set_l2_indirect_reg(L2PMOVSR, val);
+
+ return val;
+}
+
+static irqreturn_t krait_l2_handle_irq(int irq_num, void *dev)
+{
+ unsigned long pmovsr;
+ struct perf_sample_data data;
+ struct pt_regs *regs;
+ struct perf_event *event;
+ struct hw_perf_event *hwc;
+ int bitp;
+ int idx = 0;
+
+ pmovsr = get_reset_pmovsr();
+
+ if (!(pmovsr & 0xffffffff))
+ return IRQ_NONE;
+
+ regs = get_irq_regs();
+
+ perf_sample_data_init(&data, 0);
+
+ while (pmovsr) {
+ bitp = __ffs(pmovsr);
+
+ if (bitp == L2CYCLE_CTR_BIT)
+ idx = L2CYCLE_CTR_EVENT_IDX;
+ else
+ idx = bitp;
+
+ event = krait_l2_pmu_hw_events.events[idx];
+
+ if (!event)
+ goto next;
+
+ if (!test_bit(idx, krait_l2_pmu_hw_events.used_mask))
+ goto next;
+
+ hwc = &event->hw;
+
+ armpmu_event_update(event, hwc, idx);
+
+ data.period = event->hw.last_period;
+
+ if (!armpmu_event_set_period(event, hwc, idx))
+ goto next;
+
+ if (perf_event_overflow(event, &data, regs))
+ disable_counter(hwc->idx);
+next:
+ pmovsr &= (pmovsr - 1);
+ }
+
+ irq_work_run();
+
+ return IRQ_HANDLED;
+}
+
+static int krait_l2_map_event(struct perf_event *event)
+{
+ if (pmu_type > 0 && pmu_type == event->attr.type)
+ return event->attr.config & 0xfffff;
+ else
+ return -ENOENT;
+}
+
+static int
+krait_l2_pmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
+{
+ return request_irq(irq, *handle_irq,
+ IRQF_DISABLED | IRQF_NOBALANCING,
+ "krait-l2-armpmu", NULL);
+}
+
+static void
+krait_l2_pmu_generic_free_irq(int irq)
+{
+ if (irq >= 0)
+ free_irq(irq, NULL);
+}
+
+static struct arm_pmu krait_l2_pmu = {
+ .id = ARM_PERF_PMU_ID_KRAIT_L2,
+ .type = ARM_PMU_DEVICE_L2CC,
+ .name = "Krait L2CC PMU",
+ .start = krait_l2_start,
+ .stop = krait_l2_stop,
+ .handle_irq = krait_l2_handle_irq,
+ .request_pmu_irq = krait_l2_pmu_generic_request_irq,
+ .free_pmu_irq = krait_l2_pmu_generic_free_irq,
+ .enable = krait_l2_enable,
+ .disable = krait_l2_disable,
+ .get_event_idx = krait_l2_get_event_idx,
+ .read_counter = krait_l2_read_counter,
+ .write_counter = krait_l2_write_counter,
+ .map_event = krait_l2_map_event,
+ .max_period = (1LLU << 32) - 1,
+ .get_hw_events = krait_l2_get_hw_events,
+ .num_events = MAX_KRAIT_L2_CTRS,
+};
+
+static int __devinit krait_l2_pmu_device_probe(struct platform_device *pdev)
+{
+ krait_l2_pmu.plat_device = pdev;
+
+ if (!armpmu_register(&krait_l2_pmu, "krait-l2", -1))
+ pmu_type = krait_l2_pmu.pmu.type;
+
+ return 0;
+}
+
+static struct platform_driver krait_l2_pmu_driver = {
+ .driver = {
+ .name = "l2-arm-pmu",
+ },
+ .probe = krait_l2_pmu_device_probe,
+};
+
+static int __init register_krait_l2_pmu_driver(void)
+{
+ /* Reset all ctrs */
+ set_l2_indirect_reg(L2PMCR, L2PMCR_RESET_ALL);
+
+ /* Avoid spurious interrupt if any */
+ get_reset_pmovsr();
+
+ return platform_driver_register(&krait_l2_pmu_driver);
+}
+device_initcall(register_krait_l2_pmu_driver);
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
new file mode 100644
index 0000000..3310d92
--- /dev/null
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -0,0 +1,760 @@
+/*
+ * Copyright (c) 2011, 2012 Code Aurora Forum. 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/irq.h>
+#include <asm/pmu.h>
+#include <linux/platform_device.h>
+
+
+#define MAX_SCORPION_L2_CTRS 5
+#define SCORPION_L2CYCLE_CTR_BIT 31
+#define SCORPION_L2CYCLE_CTR_EVENT_IDX 4
+#define SCORPION_L2CYCLE_CTR_RAW_CODE 0xfe
+#define SCORPIONL2_PMNC_E (1 << 0) /* Enable all counters */
+#define SCORPION_L2_EVT_PREFIX 3
+#define SCORPION_MAX_L2_REG 4
+
+static u32 pmu_type;
+
+static struct arm_pmu scorpion_l2_pmu;
+
+static struct perf_event *l2_events[MAX_SCORPION_L2_CTRS];
+static unsigned long l2_used_mask[BITS_TO_LONGS(MAX_SCORPION_L2_CTRS)];
+
+static struct pmu_hw_events scorpion_l2_pmu_hw_events = {
+ .events = l2_events,
+ .used_mask = l2_used_mask,
+ .pmu_lock =
+ __RAW_SPIN_LOCK_UNLOCKED(scorpion_l2_pmu_hw_events.pmu_lock),
+};
+
+struct scorpion_l2_scorp_evt {
+ u32 evt_type;
+ u32 val;
+ u8 grp;
+ u32 evt_type_act;
+};
+
+enum scorpion_perf_types {
+ SCORPIONL2_TOTAL_BANK_REQ = 0x90,
+ SCORPIONL2_DSIDE_READ = 0x91,
+ SCORPIONL2_DSIDE_WRITE = 0x92,
+ SCORPIONL2_ISIDE_READ = 0x93,
+ SCORPIONL2_L2CACHE_ISIDE_READ = 0x94,
+ SCORPIONL2_L2CACHE_BANK_REQ = 0x95,
+ SCORPIONL2_L2CACHE_DSIDE_READ = 0x96,
+ SCORPIONL2_L2CACHE_DSIDE_WRITE = 0x97,
+ SCORPIONL2_L2NOCACHE_DSIDE_WRITE = 0x98,
+ SCORPIONL2_L2NOCACHE_ISIDE_READ = 0x99,
+ SCORPIONL2_L2NOCACHE_TOTAL_REQ = 0x9a,
+ SCORPIONL2_L2NOCACHE_DSIDE_READ = 0x9b,
+ SCORPIONL2_DSIDE_READ_NOL1 = 0x9c,
+ SCORPIONL2_L2CACHE_WRITETHROUGH = 0x9d,
+ SCORPIONL2_BARRIERS = 0x9e,
+ SCORPIONL2_HARDWARE_TABLE_WALKS = 0x9f,
+ SCORPIONL2_MVA_POC = 0xa0,
+ SCORPIONL2_L2CACHE_HW_TABLE_WALKS = 0xa1,
+ SCORPIONL2_SETWAY_CACHE_OPS = 0xa2,
+ SCORPIONL2_DSIDE_WRITE_HITS = 0xa3,
+ SCORPIONL2_ISIDE_READ_HITS = 0xa4,
+ SCORPIONL2_CACHE_DSIDE_READ_NOL1 = 0xa5,
+ SCORPIONL2_TOTAL_CACHE_HITS = 0xa6,
+ SCORPIONL2_CACHE_MATCH_MISS = 0xa7,
+ SCORPIONL2_DREAD_HIT_L1_DATA = 0xa8,
+ SCORPIONL2_L2LINE_LOCKED = 0xa9,
+ SCORPIONL2_HW_TABLE_WALK_HIT = 0xaa,
+ SCORPIONL2_CACHE_MVA_POC = 0xab,
+ SCORPIONL2_L2ALLOC_DWRITE_MISS = 0xac,
+ SCORPIONL2_CORRECTED_TAG_ARRAY = 0xad,
+ SCORPIONL2_CORRECTED_DATA_ARRAY = 0xae,
+ SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY = 0xaf,
+ SCORPIONL2_PMBUS_MPAAF = 0xb0,
+ SCORPIONL2_PMBUS_MPWDAF = 0xb1,
+ SCORPIONL2_PMBUS_MPBRT = 0xb2,
+ SCORPIONL2_CPU0_GRANT = 0xb3,
+ SCORPIONL2_CPU1_GRANT = 0xb4,
+ SCORPIONL2_CPU0_NOGRANT = 0xb5,
+ SCORPIONL2_CPU1_NOGRANT = 0xb6,
+ SCORPIONL2_CPU0_LOSING_ARB = 0xb7,
+ SCORPIONL2_CPU1_LOSING_ARB = 0xb8,
+ SCORPIONL2_SLAVEPORT_NOGRANT = 0xb9,
+ SCORPIONL2_SLAVEPORT_BPQ_FULL = 0xba,
+ SCORPIONL2_SLAVEPORT_LOSING_ARB = 0xbb,
+ SCORPIONL2_SLAVEPORT_GRANT = 0xbc,
+ SCORPIONL2_SLAVEPORT_GRANTLOCK = 0xbd,
+ SCORPIONL2_L2EM_STREX_PASS = 0xbe,
+ SCORPIONL2_L2EM_STREX_FAIL = 0xbf,
+ SCORPIONL2_LDREX_RESERVE_L2EM = 0xc0,
+ SCORPIONL2_SLAVEPORT_LDREX = 0xc1,
+ SCORPIONL2_CPU0_L2EM_CLEARED = 0xc2,
+ SCORPIONL2_CPU1_L2EM_CLEARED = 0xc3,
+ SCORPIONL2_SLAVEPORT_L2EM_CLEARED = 0xc4,
+ SCORPIONL2_CPU0_CLAMPED = 0xc5,
+ SCORPIONL2_CPU1_CLAMPED = 0xc6,
+ SCORPIONL2_CPU0_WAIT = 0xc7,
+ SCORPIONL2_CPU1_WAIT = 0xc8,
+ SCORPIONL2_CPU0_NONAMBAS_WAIT = 0xc9,
+ SCORPIONL2_CPU1_NONAMBAS_WAIT = 0xca,
+ SCORPIONL2_CPU0_DSB_WAIT = 0xcb,
+ SCORPIONL2_CPU1_DSB_WAIT = 0xcc,
+ SCORPIONL2_AXI_READ = 0xcd,
+ SCORPIONL2_AXI_WRITE = 0xce,
+
+ SCORPIONL2_1BEAT_WRITE = 0xcf,
+ SCORPIONL2_2BEAT_WRITE = 0xd0,
+ SCORPIONL2_4BEAT_WRITE = 0xd1,
+ SCORPIONL2_8BEAT_WRITE = 0xd2,
+ SCORPIONL2_12BEAT_WRITE = 0xd3,
+ SCORPIONL2_16BEAT_WRITE = 0xd4,
+ SCORPIONL2_1BEAT_DSIDE_READ = 0xd5,
+ SCORPIONL2_2BEAT_DSIDE_READ = 0xd6,
+ SCORPIONL2_4BEAT_DSIDE_READ = 0xd7,
+ SCORPIONL2_8BEAT_DSIDE_READ = 0xd8,
+ SCORPIONL2_CSYS_READ_1BEAT = 0xd9,
+ SCORPIONL2_CSYS_READ_2BEAT = 0xda,
+ SCORPIONL2_CSYS_READ_4BEAT = 0xdb,
+ SCORPIONL2_CSYS_READ_8BEAT = 0xdc,
+ SCORPIONL2_4BEAT_IFETCH_READ = 0xdd,
+ SCORPIONL2_8BEAT_IFETCH_READ = 0xde,
+ SCORPIONL2_CSYS_WRITE_1BEAT = 0xdf,
+ SCORPIONL2_CSYS_WRITE_2BEAT = 0xe0,
+ SCORPIONL2_AXI_READ_DATA_BEAT = 0xe1,
+ SCORPIONL2_AXI_WRITE_EVT1 = 0xe2,
+ SCORPIONL2_AXI_WRITE_EVT2 = 0xe3,
+ SCORPIONL2_LDREX_REQ = 0xe4,
+ SCORPIONL2_STREX_PASS = 0xe5,
+ SCORPIONL2_STREX_FAIL = 0xe6,
+ SCORPIONL2_CPREAD = 0xe7,
+ SCORPIONL2_CPWRITE = 0xe8,
+ SCORPIONL2_BARRIER_REQ = 0xe9,
+ SCORPIONL2_AXI_READ_SLVPORT = 0xea,
+ SCORPIONL2_AXI_WRITE_SLVPORT = 0xeb,
+ SCORPIONL2_AXI_READ_SLVPORT_DATABEAT = 0xec,
+ SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT = 0xed,
+ SCORPIONL2_SNOOPKILL_PREFILTER = 0xee,
+ SCORPIONL2_SNOOPKILL_FILTEROUT = 0xef,
+ SCORPIONL2_SNOOPED_IC = 0xf0,
+ SCORPIONL2_SNOOPED_BP = 0xf1,
+ SCORPIONL2_SNOOPED_BARRIERS = 0xf2,
+ SCORPIONL2_SNOOPED_TLB = 0xf3,
+ SCORPION_L2_MAX_EVT,
+};
+
+static const struct scorpion_l2_scorp_evt sc_evt[] = {
+ {SCORPIONL2_TOTAL_BANK_REQ, 0x80000001, 0, 0x00},
+ {SCORPIONL2_DSIDE_READ, 0x80000100, 0, 0x01},
+ {SCORPIONL2_DSIDE_WRITE, 0x80010000, 0, 0x02},
+ {SCORPIONL2_ISIDE_READ, 0x81000000, 0, 0x03},
+ {SCORPIONL2_L2CACHE_ISIDE_READ, 0x80000002, 0, 0x00},
+ {SCORPIONL2_L2CACHE_BANK_REQ, 0x80000200, 0, 0x01},
+ {SCORPIONL2_L2CACHE_DSIDE_READ, 0x80020000, 0, 0x02},
+ {SCORPIONL2_L2CACHE_DSIDE_WRITE, 0x82000000, 0, 0x03},
+ {SCORPIONL2_L2NOCACHE_DSIDE_WRITE, 0x80000003, 0, 0x00},
+ {SCORPIONL2_L2NOCACHE_ISIDE_READ, 0x80000300, 0, 0x01},
+ {SCORPIONL2_L2NOCACHE_TOTAL_REQ, 0x80030000, 0, 0x02},
+ {SCORPIONL2_L2NOCACHE_DSIDE_READ, 0x83000000, 0, 0x03},
+ {SCORPIONL2_DSIDE_READ_NOL1, 0x80000004, 0, 0x00},
+ {SCORPIONL2_L2CACHE_WRITETHROUGH, 0x80000400, 0, 0x01},
+ {SCORPIONL2_BARRIERS, 0x84000000, 0, 0x03},
+ {SCORPIONL2_HARDWARE_TABLE_WALKS, 0x80000005, 0, 0x00},
+ {SCORPIONL2_MVA_POC, 0x80000500, 0, 0x01},
+ {SCORPIONL2_L2CACHE_HW_TABLE_WALKS, 0x80050000, 0, 0x02},
+ {SCORPIONL2_SETWAY_CACHE_OPS, 0x85000000, 0, 0x03},
+ {SCORPIONL2_DSIDE_WRITE_HITS, 0x80000006, 0, 0x00},
+ {SCORPIONL2_ISIDE_READ_HITS, 0x80000600, 0, 0x01},
+ {SCORPIONL2_CACHE_DSIDE_READ_NOL1, 0x80060000, 0, 0x02},
+ {SCORPIONL2_TOTAL_CACHE_HITS, 0x86000000, 0, 0x03},
+ {SCORPIONL2_CACHE_MATCH_MISS, 0x80000007, 0, 0x00},
+ {SCORPIONL2_DREAD_HIT_L1_DATA, 0x87000000, 0, 0x03},
+ {SCORPIONL2_L2LINE_LOCKED, 0x80000008, 0, 0x00},
+ {SCORPIONL2_HW_TABLE_WALK_HIT, 0x80000800, 0, 0x01},
+ {SCORPIONL2_CACHE_MVA_POC, 0x80080000, 0, 0x02},
+ {SCORPIONL2_L2ALLOC_DWRITE_MISS, 0x88000000, 0, 0x03},
+ {SCORPIONL2_CORRECTED_TAG_ARRAY, 0x80001A00, 0, 0x01},
+ {SCORPIONL2_CORRECTED_DATA_ARRAY, 0x801A0000, 0, 0x02},
+ {SCORPIONL2_CORRECTED_REPLACEMENT_ARRAY, 0x9A000000, 0, 0x03},
+ {SCORPIONL2_PMBUS_MPAAF, 0x80001C00, 0, 0x01},
+ {SCORPIONL2_PMBUS_MPWDAF, 0x801C0000, 0, 0x02},
+ {SCORPIONL2_PMBUS_MPBRT, 0x9C000000, 0, 0x03},
+
+ {SCORPIONL2_CPU0_GRANT, 0x80000001, 1, 0x04},
+ {SCORPIONL2_CPU1_GRANT, 0x80000100, 1, 0x05},
+ {SCORPIONL2_CPU0_NOGRANT, 0x80020000, 1, 0x06},
+ {SCORPIONL2_CPU1_NOGRANT, 0x82000000, 1, 0x07},
+ {SCORPIONL2_CPU0_LOSING_ARB, 0x80040000, 1, 0x06},
+ {SCORPIONL2_CPU1_LOSING_ARB, 0x84000000, 1, 0x07},
+ {SCORPIONL2_SLAVEPORT_NOGRANT, 0x80000007, 1, 0x04},
+ {SCORPIONL2_SLAVEPORT_BPQ_FULL, 0x80000700, 1, 0x05},
+ {SCORPIONL2_SLAVEPORT_LOSING_ARB, 0x80070000, 1, 0x06},
+ {SCORPIONL2_SLAVEPORT_GRANT, 0x87000000, 1, 0x07},
+ {SCORPIONL2_SLAVEPORT_GRANTLOCK, 0x80000008, 1, 0x04},
+ {SCORPIONL2_L2EM_STREX_PASS, 0x80000009, 1, 0x04},
+ {SCORPIONL2_L2EM_STREX_FAIL, 0x80000900, 1, 0x05},
+ {SCORPIONL2_LDREX_RESERVE_L2EM, 0x80090000, 1, 0x06},
+ {SCORPIONL2_SLAVEPORT_LDREX, 0x89000000, 1, 0x07},
+ {SCORPIONL2_CPU0_L2EM_CLEARED, 0x800A0000, 1, 0x06},
+ {SCORPIONL2_CPU1_L2EM_CLEARED, 0x8A000000, 1, 0x07},
+ {SCORPIONL2_SLAVEPORT_L2EM_CLEARED, 0x80000B00, 1, 0x05},
+ {SCORPIONL2_CPU0_CLAMPED, 0x8000000E, 1, 0x04},
+ {SCORPIONL2_CPU1_CLAMPED, 0x80000E00, 1, 0x05},
+ {SCORPIONL2_CPU0_WAIT, 0x800F0000, 1, 0x06},
+ {SCORPIONL2_CPU1_WAIT, 0x8F000000, 1, 0x07},
+ {SCORPIONL2_CPU0_NONAMBAS_WAIT, 0x80000010, 1, 0x04},
+ {SCORPIONL2_CPU1_NONAMBAS_WAIT, 0x80001000, 1, 0x05},
+ {SCORPIONL2_CPU0_DSB_WAIT, 0x80000014, 1, 0x04},
+ {SCORPIONL2_CPU1_DSB_WAIT, 0x80001400, 1, 0x05},
+
+ {SCORPIONL2_AXI_READ, 0x80000001, 2, 0x08},
+ {SCORPIONL2_AXI_WRITE, 0x80000100, 2, 0x09},
+ {SCORPIONL2_1BEAT_WRITE, 0x80010000, 2, 0x0a},
+ {SCORPIONL2_2BEAT_WRITE, 0x80010000, 2, 0x0b},
+ {SCORPIONL2_4BEAT_WRITE, 0x80000002, 2, 0x08},
+ {SCORPIONL2_8BEAT_WRITE, 0x80000200, 2, 0x09},
+ {SCORPIONL2_12BEAT_WRITE, 0x80020000, 2, 0x0a},
+ {SCORPIONL2_16BEAT_WRITE, 0x82000000, 2, 0x0b},
+ {SCORPIONL2_1BEAT_DSIDE_READ, 0x80000003, 2, 0x08},
+ {SCORPIONL2_2BEAT_DSIDE_READ, 0x80000300, 2, 0x09},
+ {SCORPIONL2_4BEAT_DSIDE_READ, 0x80030000, 2, 0x0a},
+ {SCORPIONL2_8BEAT_DSIDE_READ, 0x83000000, 2, 0x0b},
+ {SCORPIONL2_CSYS_READ_1BEAT, 0x80000004, 2, 0x08},
+ {SCORPIONL2_CSYS_READ_2BEAT, 0x80000400, 2, 0x09},
+ {SCORPIONL2_CSYS_READ_4BEAT, 0x80040000, 2, 0x0a},
+ {SCORPIONL2_CSYS_READ_8BEAT, 0x84000000, 2, 0x0b},
+ {SCORPIONL2_4BEAT_IFETCH_READ, 0x80000005, 2, 0x08},
+ {SCORPIONL2_8BEAT_IFETCH_READ, 0x80000500, 2, 0x09},
+ {SCORPIONL2_CSYS_WRITE_1BEAT, 0x80050000, 2, 0x0a},
+ {SCORPIONL2_CSYS_WRITE_2BEAT, 0x85000000, 2, 0x0b},
+ {SCORPIONL2_AXI_READ_DATA_BEAT, 0x80000600, 2, 0x09},
+ {SCORPIONL2_AXI_WRITE_EVT1, 0x80060000, 2, 0x0a},
+ {SCORPIONL2_AXI_WRITE_EVT2, 0x86000000, 2, 0x0b},
+ {SCORPIONL2_LDREX_REQ, 0x80000007, 2, 0x08},
+ {SCORPIONL2_STREX_PASS, 0x80000700, 2, 0x09},
+ {SCORPIONL2_STREX_FAIL, 0x80070000, 2, 0x0a},
+ {SCORPIONL2_CPREAD, 0x80000008, 2, 0x08},
+ {SCORPIONL2_CPWRITE, 0x80000800, 2, 0x09},
+ {SCORPIONL2_BARRIER_REQ, 0x88000000, 2, 0x0b},
+
+ {SCORPIONL2_AXI_READ_SLVPORT, 0x80000001, 3, 0x0c},
+ {SCORPIONL2_AXI_WRITE_SLVPORT, 0x80000100, 3, 0x0d},
+ {SCORPIONL2_AXI_READ_SLVPORT_DATABEAT, 0x80010000, 3, 0x0e},
+ {SCORPIONL2_AXI_WRITE_SLVPORT_DATABEAT, 0x81000000, 3, 0x0f},
+
+ {SCORPIONL2_SNOOPKILL_PREFILTER, 0x80000001, 4, 0x10},
+ {SCORPIONL2_SNOOPKILL_FILTEROUT, 0x80000100, 4, 0x11},
+ {SCORPIONL2_SNOOPED_IC, 0x80000002, 4, 0x10},
+ {SCORPIONL2_SNOOPED_BP, 0x80000200, 4, 0x11},
+ {SCORPIONL2_SNOOPED_BARRIERS, 0x80020000, 4, 0x12},
+ {SCORPIONL2_SNOOPED_TLB, 0x82000000, 4, 0x13},
+};
+
+static struct pmu_hw_events *scorpion_l2_get_hw_events(void)
+{
+ return &scorpion_l2_pmu_hw_events;
+}
+static u32 scorpion_l2_read_l2pm0(void)
+{
+ u32 val;
+ asm volatile ("mrc p15, 3, %0, c15, c7, 0" : "=r" (val));
+ return val;
+}
+
+static void scorpion_l2_write_l2pm0(u32 val)
+{
+ asm volatile ("mcr p15, 3, %0, c15, c7, 0" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm1(void)
+{
+ u32 val;
+ asm volatile ("mrc p15, 3, %0, c15, c7, 1" : "=r" (val));
+ return val;
+}
+
+static void scorpion_l2_write_l2pm1(u32 val)
+{
+ asm volatile ("mcr p15, 3, %0, c15, c7, 1" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm2(void)
+{
+ u32 val;
+ asm volatile ("mrc p15, 3, %0, c15, c7, 2" : "=r" (val));
+ return val;
+}
+
+static void scorpion_l2_write_l2pm2(u32 val)
+{
+ asm volatile ("mcr p15, 3, %0, c15, c7, 2" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm3(void)
+{
+ u32 val;
+ asm volatile ("mrc p15, 3, %0, c15, c7, 3" : "=r" (val));
+ return val;
+}
+
+static void scorpion_l2_write_l2pm3(u32 val)
+{
+ asm volatile ("mcr p15, 3, %0, c15, c7, 3" : : "r" (val));
+}
+
+static u32 scorpion_l2_read_l2pm4(void)
+{
+ u32 val;
+ asm volatile ("mrc p15, 3, %0, c15, c7, 4" : "=r" (val));
+ return val;
+}
+
+static void scorpion_l2_write_l2pm4(u32 val)
+{
+ asm volatile ("mcr p15, 3, %0, c15, c7, 4" : : "r" (val));
+}
+
+struct scorpion_scorpion_access_funcs {
+ u32(*read) (void);
+ void (*write) (u32);
+ void (*pre) (void);
+ void (*post) (void);
+};
+
+struct scorpion_scorpion_access_funcs scorpion_l2_func[] = {
+ {scorpion_l2_read_l2pm0, scorpion_l2_write_l2pm0, NULL, NULL},
+ {scorpion_l2_read_l2pm1, scorpion_l2_write_l2pm1, NULL, NULL},
+ {scorpion_l2_read_l2pm2, scorpion_l2_write_l2pm2, NULL, NULL},
+ {scorpion_l2_read_l2pm3, scorpion_l2_write_l2pm3, NULL, NULL},
+ {scorpion_l2_read_l2pm4, scorpion_l2_write_l2pm4, NULL, NULL},
+};
+
+#define COLMN0MASK 0x000000ff
+#define COLMN1MASK 0x0000ff00
+#define COLMN2MASK 0x00ff0000
+
+static u32 scorpion_l2_get_columnmask(u32 setval)
+{
+ if (setval & COLMN0MASK)
+ return 0xffffff00;
+ else if (setval & COLMN1MASK)
+ return 0xffff00ff;
+ else if (setval & COLMN2MASK)
+ return 0xff00ffff;
+ else
+ return 0x80ffffff;
+}
+
+static void scorpion_l2_evt_setup(u32 gr, u32 setval)
+{
+ u32 val;
+ if (scorpion_l2_func[gr].pre)
+ scorpion_l2_func[gr].pre();
+ val = scorpion_l2_get_columnmask(setval) & scorpion_l2_func[gr].read();
+ val = val | setval;
+ scorpion_l2_func[gr].write(val);
+ if (scorpion_l2_func[gr].post)
+ scorpion_l2_func[gr].post();
+}
+
+#define SCORPION_L2_EVT_START_IDX 0x90
+#define SCORPION_L2_INV_EVTYPE 0
+
+static unsigned int get_scorpion_l2_evtinfo(unsigned int evt_type,
+ struct scorpion_l2_scorp_evt *evtinfo)
+{
+ u32 idx;
+ u8 prefix;
+ u8 reg;
+ u8 code;
+ u8 group;
+
+ prefix = (evt_type & 0xF0000) >> 16;
+ if (prefix == SCORPION_L2_EVT_PREFIX) {
+ reg = (evt_type & 0x0F000) >> 12;
+ code = (evt_type & 0x00FF0) >> 4;
+ group = evt_type & 0x0000F;
+
+ if ((group > 3) || (reg > SCORPION_MAX_L2_REG))
+ return SCORPION_L2_INV_EVTYPE;
+
+ evtinfo->val = 0x80000000 | (code << (group * 8));
+ evtinfo->grp = reg;
+ evtinfo->evt_type_act = group | (reg << 2);
+ return evtinfo->evt_type_act;
+ }
+
+ if (evt_type < SCORPION_L2_EVT_START_IDX
+ || evt_type >= SCORPION_L2_MAX_EVT)
+ return SCORPION_L2_INV_EVTYPE;
+
+ idx = evt_type - SCORPION_L2_EVT_START_IDX;
+
+ if (sc_evt[idx].evt_type == evt_type) {
+ evtinfo->val = sc_evt[idx].val;
+ evtinfo->grp = sc_evt[idx].grp;
+ evtinfo->evt_type_act = sc_evt[idx].evt_type_act;
+ return sc_evt[idx].evt_type_act;
+ }
+ return SCORPION_L2_INV_EVTYPE;
+}
+
+static inline void scorpion_l2_pmnc_write(unsigned long val)
+{
+ val &= 0xff;
+ asm volatile ("mcr p15, 3, %0, c15, c4, 0" : : "r" (val));
+}
+
+static inline unsigned long scorpion_l2_pmnc_read(void)
+{
+ u32 val;
+ asm volatile ("mrc p15, 3, %0, c15, c4, 0" : "=r" (val));
+ return val;
+}
+
+static void scorpion_l2_set_evcntcr(void)
+{
+ u32 val = 0x0;
+ asm volatile ("mcr p15, 3, %0, c15, c6, 4" : : "r" (val));
+}
+
+static inline void scorpion_l2_set_evtyper(int ctr, int val)
+{
+ /* select ctr */
+ asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (ctr));
+
+ /* write into EVTYPER */
+ asm volatile ("mcr p15, 3, %0, c15, c6, 7" : : "r" (val));
+}
+
+static void scorpion_l2_set_evfilter_task_mode(void)
+{
+ u32 filter_val = 0x000f0030 | 1 << smp_processor_id();
+
+ asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void scorpion_l2_set_evfilter_sys_mode(void)
+{
+ u32 filter_val = 0x000f003f;
+
+ asm volatile ("mcr p15, 3, %0, c15, c6, 3" : : "r" (filter_val));
+}
+
+static void scorpion_l2_enable_intenset(u32 idx)
+{
+ if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+ asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r"
+ (1 << SCORPION_L2CYCLE_CTR_BIT));
+ } else {
+ asm volatile ("mcr p15, 3, %0, c15, c5, 1" : : "r" (1 << idx));
+ }
+}
+
+static void scorpion_l2_disable_intenclr(u32 idx)
+{
+ if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+ asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r"
+ (1 << SCORPION_L2CYCLE_CTR_BIT));
+ } else {
+ asm volatile ("mcr p15, 3, %0, c15, c5, 0" : : "r" (1 << idx));
+ }
+}
+
+static void scorpion_l2_enable_counter(u32 idx)
+{
+ if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+ asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r"
+ (1 << SCORPION_L2CYCLE_CTR_BIT));
+ } else {
+ asm volatile ("mcr p15, 3, %0, c15, c4, 3" : : "r" (1 << idx));
+ }
+}
+
+static void scorpion_l2_disable_counter(u32 idx)
+{
+ if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+ asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r"
+ (1 << SCORPION_L2CYCLE_CTR_BIT));
+ } else {
+ asm volatile ("mcr p15, 3, %0, c15, c4, 2" : : "r" (1 << idx));
+ }
+}
+
+static u32 scorpion_l2_read_counter(int idx)
+{
+ u32 val;
+ unsigned long iflags;
+
+ if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+ asm volatile ("mrc p15, 3, %0, c15, c4, 5" : "=r" (val));
+ } else {
+ raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
+ iflags);
+ asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+ /* read val from counter */
+ asm volatile ("mrc p15, 3, %0, c15, c6, 5" : "=r" (val));
+ raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
+ iflags);
+ }
+
+ return val;
+}
+
+static void scorpion_l2_write_counter(int idx, u32 val)
+{
+ unsigned long iflags;
+
+ if (idx == SCORPION_L2CYCLE_CTR_EVENT_IDX) {
+ asm volatile ("mcr p15, 3, %0, c15, c4, 5" : : "r" (val));
+ } else {
+ raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock,
+ iflags);
+
+ /* select counter */
+ asm volatile ("mcr p15, 3, %0, c15, c6, 0" : : "r" (idx));
+
+ /* write val into counter */
+ asm volatile ("mcr p15, 3, %0, c15, c6, 5" : : "r" (val));
+ raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock,
+ iflags);
+ }
+}
+
+static void scorpion_l2_stop_counter(struct hw_perf_event *hwc, int idx)
+{
+ scorpion_l2_disable_intenclr(idx);
+ scorpion_l2_disable_counter(idx);
+ pr_debug("%s: event: %ld ctr: %d stopped\n", __func__,
+ hwc->config_base, idx);
+}
+
+static void scorpion_l2_enable(struct hw_perf_event *hwc, int idx, int cpu)
+{
+ struct scorpion_l2_scorp_evt evtinfo;
+ int evtype = hwc->config_base;
+ int ev_typer;
+ unsigned long iflags;
+
+ raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+ if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE)
+ goto out;
+
+ memset(&evtinfo, 0, sizeof(evtinfo));
+
+ ev_typer = get_scorpion_l2_evtinfo(evtype, &evtinfo);
+
+ scorpion_l2_set_evtyper(idx, ev_typer);
+
+ scorpion_l2_set_evcntcr();
+
+ if (cpu < 0)
+ scorpion_l2_set_evfilter_task_mode();
+ else
+ scorpion_l2_set_evfilter_sys_mode();
+
+ scorpion_l2_evt_setup(evtinfo.grp, evtinfo.val);
+
+out:
+
+ scorpion_l2_enable_intenset(idx);
+
+ scorpion_l2_enable_counter(idx);
+
+ raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+ pr_debug("%s: ctr: %d group: %ld group_code: %lld started from cpu:%d\n",
+ __func__, idx, hwc->config_base, hwc->config, smp_processor_id());
+}
+
+static void scorpion_l2_disable(struct hw_perf_event *hwc, int idx)
+{
+ unsigned long iflags;
+
+ raw_spin_lock_irqsave(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+ scorpion_l2_stop_counter(hwc, idx);
+
+ raw_spin_unlock_irqrestore(&scorpion_l2_pmu_hw_events.pmu_lock, iflags);
+
+ pr_debug("%s: event: %ld deleted\n", __func__, hwc->config_base);
+}
+
+static int scorpion_l2_get_event_idx(struct pmu_hw_events *cpuc,
+ struct hw_perf_event *hwc)
+{
+ int ctr = 0;
+
+ if (hwc->config_base == SCORPION_L2CYCLE_CTR_RAW_CODE) {
+ if (!test_and_set_bit(SCORPION_L2CYCLE_CTR_EVENT_IDX,
+ cpuc->used_mask))
+ return SCORPION_L2CYCLE_CTR_EVENT_IDX;
+ }
+
+ for (ctr = 0; ctr < MAX_SCORPION_L2_CTRS - 1; ctr++) {
+ if (!test_and_set_bit(ctr, cpuc->used_mask))
+ return ctr;
+ }
+
+ return -EAGAIN;
+}
+
+static void scorpion_l2_start(void)
+{
+ isb();
+ /* Enable all counters */
+ scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() | SCORPIONL2_PMNC_E);
+}
+
+static void scorpion_l2_stop(void)
+{
+ /* Disable all counters */
+ scorpion_l2_pmnc_write(scorpion_l2_pmnc_read() & ~SCORPIONL2_PMNC_E);
+ isb();
+}
+
+static inline u32 scorpion_l2_get_reset_pmovsr(void)
+{
+ u32 val;
+
+ /* Read */
+ asm volatile ("mrc p15, 3, %0, c15, c4, 1" : "=r" (val));
+
+ /* Write to clear flags */
+ val &= 0xffffffff;
+ asm volatile ("mcr p15, 3, %0, c15, c4, 1" : : "r" (val));
+
+ return val;
+}
+
+static irqreturn_t scorpion_l2_handle_irq(int irq_num, void *dev)
+{
+ unsigned long pmovsr;
+ struct perf_sample_data data;
+ struct pt_regs *regs;
+ struct perf_event *event;
+ struct hw_perf_event *hwc;
+ int bitp;
+ int idx = 0;
+
+ pmovsr = scorpion_l2_get_reset_pmovsr();
+
+ if (!(pmovsr & 0xffffffff))
+ return IRQ_NONE;
+
+ regs = get_irq_regs();
+
+ perf_sample_data_init(&data, 0);
+
+ while (pmovsr) {
+ bitp = __ffs(pmovsr);
+
+ if (bitp == SCORPION_L2CYCLE_CTR_BIT)
+ idx = SCORPION_L2CYCLE_CTR_EVENT_IDX;
+ else
+ idx = bitp;
+
+ event = scorpion_l2_pmu_hw_events.events[idx];
+
+ if (!event)
+ goto next;
+
+ if (!test_bit(idx, scorpion_l2_pmu_hw_events.used_mask))
+ goto next;
+
+ hwc = &event->hw;
+
+ armpmu_event_update(event, hwc, idx);
+
+ data.period = event->hw.last_period;
+
+ if (!armpmu_event_set_period(event, hwc, idx))
+ goto next;
+
+ if (perf_event_overflow(event, &data, regs))
+ scorpion_l2_disable_counter(hwc->idx);
+next:
+ pmovsr &= (pmovsr - 1);
+ }
+
+ irq_work_run();
+
+ return IRQ_HANDLED;
+}
+
+static int scorpion_l2_map_event(struct perf_event *event)
+{
+ if (pmu_type > 0 && pmu_type == event->attr.type)
+ return event->attr.config & 0xfffff;
+ else
+ return -ENOENT;
+}
+
+static int
+scorpion_l2_pmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
+{
+ return request_irq(irq, *handle_irq,
+ IRQF_DISABLED | IRQF_NOBALANCING,
+ "scorpion-l2-armpmu", NULL);
+}
+
+static void
+scorpion_l2_pmu_generic_free_irq(int irq)
+{
+ if (irq >= 0)
+ free_irq(irq, NULL);
+}
+
+static struct arm_pmu scorpion_l2_pmu = {
+ .id = ARM_PERF_PMU_ID_SCORPIONMP_L2,
+ .type = ARM_PMU_DEVICE_L2CC,
+ .name = "Scorpion L2CC PMU",
+ .start = scorpion_l2_start,
+ .stop = scorpion_l2_stop,
+ .handle_irq = scorpion_l2_handle_irq,
+ .request_pmu_irq = scorpion_l2_pmu_generic_request_irq,
+ .free_pmu_irq = scorpion_l2_pmu_generic_free_irq,
+ .enable = scorpion_l2_enable,
+ .disable = scorpion_l2_disable,
+ .read_counter = scorpion_l2_read_counter,
+ .get_event_idx = scorpion_l2_get_event_idx,
+ .write_counter = scorpion_l2_write_counter,
+ .map_event = scorpion_l2_map_event,
+ .max_period = (1LLU << 32) - 1,
+ .get_hw_events = scorpion_l2_get_hw_events,
+ .num_events = MAX_SCORPION_L2_CTRS,
+};
+
+static int __devinit scorpion_l2_pmu_device_probe(struct platform_device *pdev)
+{
+ scorpion_l2_pmu.plat_device = pdev;
+
+ if (!armpmu_register(&scorpion_l2_pmu, "scorpion-l2", -1))
+ pmu_type = scorpion_l2_pmu.pmu.type;
+
+ return 0;
+}
+
+static struct platform_driver scorpion_l2_pmu_driver = {
+ .driver = {
+ .name = "l2-arm-pmu",
+ },
+ .probe = scorpion_l2_pmu_device_probe,
+};
+
+static int __init register_scorpion_l2_pmu_driver(void)
+{
+ /* Avoid spurious interrupt if any */
+ scorpion_l2_get_reset_pmovsr();
+
+ return platform_driver_register(&scorpion_l2_pmu_driver);
+}
+device_initcall(register_scorpion_l2_pmu_driver);
diff --git a/arch/arm/mach-msm/pil-mba.c b/arch/arm/mach-msm/pil-mba.c
new file mode 100644
index 0000000..7405ab9
--- /dev/null
+++ b/arch/arm/mach-msm/pil-mba.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+
+#include "peripheral-loader.h"
+
+#define RMB_MBA_COMMAND 0x08
+#define RMB_MBA_STATUS 0x0C
+#define RMB_PMI_META_DATA 0x10
+#define RMB_PMI_CODE_START 0x14
+#define RMB_PMI_CODE_LENGTH 0x18
+
+#define CMD_META_DATA_READY 0x1
+#define CMD_LOAD_READY 0x2
+
+#define STATUS_META_DATA_AUTH_SUCCESS 0x3
+#define STATUS_AUTH_COMPLETE 0x4
+#define STATUS_ERROR_MASK BIT(31)
+
+#define AUTH_TIMEOUT_US 10000000
+#define PROXY_TIMEOUT_MS 10000
+#define POLL_INTERVAL_US 50
+
+struct mba_data {
+ void __iomem *reg_base;
+ void __iomem *metadata_base;
+ unsigned long metadata_phys;
+ struct pil_device *pil;
+ struct clk *xo;
+ u32 img_length;
+};
+
+static int pil_mba_make_proxy_votes(struct pil_desc *pil)
+{
+ int ret;
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+
+ ret = clk_prepare_enable(drv->xo);
+ if (ret) {
+ dev_err(pil->dev, "Failed to enable XO\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void pil_mba_remove_proxy_votes(struct pil_desc *pil)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+ clk_disable_unprepare(drv->xo);
+}
+
+static int pil_mba_init_image(struct pil_desc *pil,
+ const u8 *metadata, size_t size)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+ u32 status;
+ int ret;
+
+ /* Copy metadata to assigned shared buffer location */
+ memcpy(drv->metadata_base, metadata, size);
+
+ /* Initialize length counter to 0 */
+ writel_relaxed(0, drv->reg_base + RMB_PMI_CODE_LENGTH);
+ drv->img_length = 0;
+
+ /* Pass address of meta-data to the MBA and perform authentication */
+ writel_relaxed(drv->metadata_phys, drv->reg_base + RMB_PMI_META_DATA);
+ writel_relaxed(CMD_META_DATA_READY, drv->reg_base + RMB_MBA_COMMAND);
+ ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
+ status == STATUS_META_DATA_AUTH_SUCCESS,
+ POLL_INTERVAL_US, AUTH_TIMEOUT_US);
+ if (ret)
+ dev_err(pil->dev, "MBA authentication timed out\n");
+
+ return ret;
+}
+
+static int pil_mba_verify_blob(struct pil_desc *pil, u32 phy_addr,
+ size_t size)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+
+ /* Begin image authentication */
+ if (drv->img_length == 0) {
+ writel_relaxed(phy_addr, drv->reg_base + RMB_PMI_CODE_START);
+ writel_relaxed(CMD_LOAD_READY, drv->reg_base + RMB_MBA_COMMAND);
+ }
+ /* Increment length counter */
+ drv->img_length += size;
+ writel_relaxed(drv->img_length, drv->reg_base + RMB_PMI_CODE_LENGTH);
+
+ return readl_relaxed(drv->reg_base + RMB_MBA_STATUS)
+ & STATUS_ERROR_MASK;
+}
+
+static int pil_mba_auth(struct pil_desc *pil)
+{
+ struct mba_data *drv = dev_get_drvdata(pil->dev);
+ int ret;
+ u32 status;
+
+ /* Wait for all segments to be authenticated or an error to occur */
+ ret = readl_poll_timeout(drv->reg_base + RMB_MBA_STATUS, status,
+ status == STATUS_AUTH_COMPLETE ||
+ status & STATUS_ERROR_MASK,
+ 50, AUTH_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ if (status & STATUS_ERROR_MASK)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int pil_mba_shutdown(struct pil_desc *pil)
+{
+ return 0;
+}
+
+static struct pil_reset_ops pil_mba_ops = {
+ .init_image = pil_mba_init_image,
+ .proxy_vote = pil_mba_make_proxy_votes,
+ .proxy_unvote = pil_mba_remove_proxy_votes,
+ .verify_blob = pil_mba_verify_blob,
+ .auth_and_reset = pil_mba_auth,
+ .shutdown = pil_mba_shutdown,
+};
+
+static int __devinit pil_mba_driver_probe(struct platform_device *pdev)
+{
+ struct mba_data *drv;
+ struct resource *res;
+ struct pil_desc *desc;
+ int ret;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, drv);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+ drv->reg_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->reg_base)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ drv->metadata_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->metadata_base)
+ return -ENOMEM;
+ drv->metadata_phys = res->start;
+ }
+
+ desc = devm_kzalloc(&pdev->dev, sizeof(*desc), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ ret = of_property_read_string(pdev->dev.of_node, "qcom,firmware-name",
+ &desc->name);
+ if (ret)
+ return ret;
+
+ of_property_read_string(pdev->dev.of_node, "qcom,depends-on",
+ &desc->depends_on);
+
+ drv->xo = devm_clk_get(&pdev->dev, "xo");
+ if (IS_ERR(drv->xo))
+ return PTR_ERR(drv->xo);
+
+ desc->dev = &pdev->dev;
+ desc->ops = &pil_mba_ops;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ return 0;
+}
+
+static int __devexit pil_mba_driver_exit(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id mba_match_table[] = {
+ { .compatible = "qcom,pil-mba" },
+ {}
+};
+
+struct platform_driver pil_mba_driver = {
+ .probe = pil_mba_driver_probe,
+ .remove = __devexit_p(pil_mba_driver_exit),
+ .driver = {
+ .name = "pil-mba",
+ .of_match_table = mba_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_mba_init(void)
+{
+ return platform_driver_register(&pil_mba_driver);
+}
+module_init(pil_mba_init);
+
+static void __exit pil_mba_exit(void)
+{
+ platform_driver_unregister(&pil_mba_driver);
+}
+module_exit(pil_mba_exit);
+
+MODULE_DESCRIPTION("Support for modem boot using the Modem Boot Authenticator");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5-mss.c b/arch/arm/mach-msm/pil-q6v5-mss.c
new file mode 100644
index 0000000..e279f99
--- /dev/null
+++ b/arch/arm/mach-msm/pil-q6v5-mss.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/elf.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+
+#include <mach/clk.h>
+
+#include "peripheral-loader.h"
+#include "pil-q6v5.h"
+
+/* Q6 Register Offsets */
+#define QDSP6SS_RST_EVB 0x010
+
+/* AXI Halting Registers */
+#define MSS_Q6_HALT_BASE 0x180
+#define MSS_MODEM_HALT_BASE 0x200
+#define MSS_NC_HALT_BASE 0x280
+
+/* RMB Status Register Values */
+#define STATUS_PBL_SUCCESS 0x1
+#define STATUS_XPU_UNLOCKED 0x1
+#define STATUS_XPU_UNLOCKED_SCRIBBLED 0x2
+
+/* PBL/MBA interface registers */
+#define RMB_MBA_IMAGE 0x00
+#define RMB_PBL_STATUS 0x04
+#define RMB_MBA_STATUS 0x0C
+
+#define PBL_MBA_WAIT_TIMEOUT_US 100000
+#define PROXY_TIMEOUT_MS 10000
+#define POLL_INTERVAL_US 50
+
+static int pil_mss_power_up(struct device *dev)
+{
+ int ret;
+ struct q6v5_data *drv = dev_get_drvdata(dev);
+
+ ret = regulator_enable(drv->vreg);
+ if (ret)
+ dev_err(dev, "Failed to enable regulator.\n");
+
+ return ret;
+}
+
+static int pil_mss_power_down(struct device *dev)
+{
+ struct q6v5_data *drv = dev_get_drvdata(dev);
+
+ return regulator_disable(drv->vreg);
+}
+
+static int wait_for_mba_ready(struct device *dev)
+{
+ struct q6v5_data *drv = dev_get_drvdata(dev);
+ int ret;
+ u32 status;
+
+ /* Wait for PBL completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_PBL_STATUS, status,
+ status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+ if (ret) {
+ dev_err(dev, "PBL boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_PBL_SUCCESS) {
+ dev_err(dev, "PBL returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ /* Wait for MBA completion. */
+ ret = readl_poll_timeout(drv->rmb_base + RMB_MBA_STATUS, status,
+ status != 0, POLL_INTERVAL_US, PBL_MBA_WAIT_TIMEOUT_US);
+ if (ret) {
+ dev_err(dev, "MBA boot timed out\n");
+ return ret;
+ }
+ if (status != STATUS_XPU_UNLOCKED &&
+ status != STATUS_XPU_UNLOCKED_SCRIBBLED) {
+ dev_err(dev, "MBA returned unexpected status %d\n", status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int pil_mss_shutdown(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_Q6_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_MODEM_HALT_BASE);
+ pil_q6v5_halt_axi_port(pil, drv->axi_halt_base + MSS_NC_HALT_BASE);
+
+ /*
+ * If the shutdown function is called before the reset function, clocks
+ * and power will not be enabled yet. Enable them here so that register
+ * writes performed during the shutdown succeed.
+ */
+ if (drv->is_booted == false) {
+ pil_mss_power_up(pil->dev);
+ pil_q6v5_enable_clks(pil);
+ }
+ pil_q6v5_shutdown(pil);
+
+ pil_q6v5_disable_clks(pil);
+ pil_mss_power_down(pil->dev);
+
+ writel_relaxed(1, drv->restart_reg);
+
+ drv->is_booted = false;
+
+ return 0;
+}
+
+static int pil_mss_reset(struct pil_desc *pil)
+{
+ struct q6v5_data *drv = dev_get_drvdata(pil->dev);
+ int ret;
+
+ writel_relaxed(0, drv->restart_reg);
+ mb();
+
+ /*
+ * Bring subsystem out of reset and enable required
+ * regulators and clocks.
+ */
+ ret = pil_mss_power_up(pil->dev);
+ if (ret)
+ goto err_power;
+
+ ret = pil_q6v5_enable_clks(pil);
+ if (ret)
+ goto err_clks;
+
+ /* Program Image Address */
+ if (drv->self_auth)
+ writel_relaxed(drv->start_addr, drv->rmb_base + RMB_MBA_IMAGE);
+ else
+ writel_relaxed((drv->start_addr >> 4) & 0x0FFFFFF0,
+ drv->reg_base + QDSP6SS_RST_EVB);
+
+ ret = pil_q6v5_reset(pil);
+ if (ret)
+ goto err_q6v5_reset;
+
+ /* Wait for MBA to start. Check for PBL and MBA errors while waiting. */
+ if (drv->self_auth) {
+ ret = wait_for_mba_ready(pil->dev);
+ if (ret)
+ goto err_auth;
+ }
+
+ drv->is_booted = true;
+
+ return 0;
+
+err_auth:
+ pil_q6v5_shutdown(pil);
+err_q6v5_reset:
+ pil_q6v5_disable_clks(pil);
+err_clks:
+ pil_mss_power_down(pil->dev);
+err_power:
+ return ret;
+}
+
+static struct pil_reset_ops pil_mss_ops = {
+ .init_image = pil_q6v5_init_image,
+ .proxy_vote = pil_q6v5_make_proxy_votes,
+ .proxy_unvote = pil_q6v5_remove_proxy_votes,
+ .auth_and_reset = pil_mss_reset,
+ .shutdown = pil_mss_shutdown,
+};
+
+static int __devinit pil_mss_driver_probe(struct platform_device *pdev)
+{
+ struct q6v5_data *drv;
+ struct pil_desc *desc;
+ struct resource *res;
+ int ret;
+
+ desc = pil_q6v5_init(pdev);
+ if (IS_ERR(desc))
+ return PTR_ERR(desc);
+ drv = platform_get_drvdata(pdev);
+ if (drv == NULL)
+ return -ENODEV;
+
+ desc->ops = &pil_mss_ops;
+ desc->owner = THIS_MODULE;
+ desc->proxy_timeout = PROXY_TIMEOUT_MS;
+
+ of_property_read_u32(pdev->dev.of_node, "qcom,pil-self-auth",
+ &drv->self_auth);
+ if (drv->self_auth) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ drv->rmb_base = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->rmb_base)
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ drv->restart_reg = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (!drv->restart_reg)
+ return -ENOMEM;
+
+ drv->vreg = devm_regulator_get(&pdev->dev, "vdd_mss");
+ if (IS_ERR(drv->vreg))
+ return PTR_ERR(drv->vreg);
+
+ ret = regulator_set_voltage(drv->vreg, 1150000, 1150000);
+ if (ret)
+ dev_err(&pdev->dev, "Failed to set regulator's voltage.\n");
+
+ ret = regulator_set_optimum_mode(drv->vreg, 100000);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set regulator's mode.\n");
+ return ret;
+ }
+
+ drv->mem_clk = devm_clk_get(&pdev->dev, "mem_clk");
+ if (IS_ERR(drv->mem_clk))
+ return PTR_ERR(drv->mem_clk);
+
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil))
+ return PTR_ERR(drv->pil);
+
+ return 0;
+}
+
+static int __devexit pil_mss_driver_exit(struct platform_device *pdev)
+{
+ struct q6v5_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
+ return 0;
+}
+
+static struct of_device_id mss_match_table[] = {
+ { .compatible = "qcom,pil-q6v5-mss" },
+ {}
+};
+
+static struct platform_driver pil_mss_driver = {
+ .probe = pil_mss_driver_probe,
+ .remove = __devexit_p(pil_mss_driver_exit),
+ .driver = {
+ .name = "pil-q6v5-mss",
+ .of_match_table = mss_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pil_mss_init(void)
+{
+ return platform_driver_register(&pil_mss_driver);
+}
+module_init(pil_mss_init);
+
+static void __exit pil_mss_exit(void)
+{
+ platform_driver_unregister(&pil_mss_driver);
+}
+module_exit(pil_mss_exit);
+
+MODULE_DESCRIPTION("Support for booting modem subsystems with QDSP6v5 Hexagon processors");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 6a96990..a362a7e3 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -121,9 +121,16 @@
ret = clk_prepare_enable(drv->bus_clk);
if (ret)
goto err_bus_clk;
+ if (drv->mem_clk) {
+ ret = clk_prepare_enable(drv->mem_clk);
+ if (ret)
+ goto err_mem_clk;
+ }
return 0;
+err_mem_clk:
+ clk_disable_unprepare(drv->bus_clk);
err_bus_clk:
clk_disable_unprepare(drv->core_clk);
err_core_clk:
@@ -139,6 +146,7 @@
clk_disable_unprepare(drv->bus_clk);
clk_disable_unprepare(drv->core_clk);
+ clk_disable_unprepare(drv->mem_clk);
clk_reset(drv->core_clk, CLK_RESET_ASSERT);
}
EXPORT_SYMBOL(pil_q6v5_disable_clks);
diff --git a/arch/arm/mach-msm/pil-q6v5.h b/arch/arm/mach-msm/pil-q6v5.h
index a9a8d07..e0d7a20 100644
--- a/arch/arm/mach-msm/pil-q6v5.h
+++ b/arch/arm/mach-msm/pil-q6v5.h
@@ -24,8 +24,10 @@
struct clk *xo;
struct clk *bus_clk;
struct clk *core_clk;
+ struct clk *mem_clk;
void __iomem *axi_halt_base;
void __iomem *rmb_base;
+ void __iomem *restart_reg;
unsigned long start_addr;
struct regulator *vreg;
bool is_booted;
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index b40c0c7..49e63aa 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -202,8 +202,6 @@
pen_release = cpu_logical_map(cpu);
__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
- __asm__("sev");
- mb();
/*
* Send the secondary CPU a soft interrupt, thereby causing
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index f6105af1..079ed9c 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -41,7 +41,7 @@
}
#ifdef CONFIG_MSM_SCM
-static int __init msm_pm_tz_boot_init(void)
+static int __devinit msm_pm_tz_boot_init(void)
{
int flag = 0;
if (num_possible_cpus() == 1)
@@ -72,7 +72,7 @@
unsigned long entry) {}
#endif
-static int __init msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
+static int __devinit msm_pm_boot_reset_vector_init(uint32_t *reset_vector)
{
if (!reset_vector)
return -ENODEV;
@@ -110,7 +110,7 @@
}
#define BOOT_REMAP_ENABLE BIT(0)
-int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
+int __devinit msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
{
int ret = 0;
unsigned long entry;
diff --git a/arch/arm/mach-msm/pm-stats.c b/arch/arm/mach-msm/pm-stats.c
index 936820a..675febb 100644
--- a/arch/arm/mach-msm/pm-stats.c
+++ b/arch/arm/mach-msm/pm-stats.c
@@ -188,18 +188,19 @@
int ret;
unsigned long flags;
unsigned int cpu;
+ size_t len = strnlen(MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET));
if (count < sizeof(MSM_PM_STATS_RESET)) {
ret = -EINVAL;
goto write_proc_failed;
}
- if (copy_from_user(buf, buffer, sizeof(MSM_PM_STATS_RESET))) {
+ if (copy_from_user(buf, buffer, len)) {
ret = -EFAULT;
goto write_proc_failed;
}
- if (memcmp(buf, MSM_PM_STATS_RESET, sizeof(MSM_PM_STATS_RESET))) {
+ if (strncmp(buf, MSM_PM_STATS_RESET, len)) {
ret = -EINVAL;
goto write_proc_failed;
}
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index 1f82468..5e339da 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -33,7 +33,7 @@
static struct platform_device l2_pmu_device = {
.name = "l2-arm-pmu",
- .id = ARM_PMU_DEVICE_L2,
+ .id = ARM_PMU_DEVICE_L2CC,
.resource = l2_pmu_resource,
.num_resources = ARRAY_SIZE(l2_pmu_resource),
};
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 6f5ccbf..b485058 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -865,7 +865,8 @@
unsigned msg_id;
unsigned msg_length;
#ifdef CONFIG_DEBUG_FS
- uint16_t *ptr;
+ uint16_t *ptr16;
+ uint32_t *ptr32;
int ii;
#endif /* CONFIG_DEBUG_FS */
void (*func)(void *, size_t);
@@ -909,12 +910,20 @@
return 0;
}
#ifdef CONFIG_DEBUG_FS
- if (rdump > 0) {
- ptr = read_event_addr;
+ if (rdump > 0 &&
+ (dsp_addr >= (void *)(MSM_AD5_BASE + QDSP_RAMC_OFFSET))) {
+ ptr32 = read_event_addr;
+ pr_info("D->A\n");
+ pr_info("m_id = %x id = %x\n", module->id, msg_id);
+ for (ii = 0; ii < msg_length/4; ii++)
+ pr_info("%x ", ptr32[ii]);
+ pr_info("\n");
+ } else if (rdump > 0) {
+ ptr16 = read_event_addr;
pr_info("D->A\n");
pr_info("m_id = %x id = %x\n", module->id, msg_id);
for (ii = 0; ii < msg_length/2; ii++)
- pr_info("%x ", ptr[ii]);
+ pr_info("%x ", ptr16[ii]);
pr_info("\n");
}
#endif /* CONFIG_DEBUG_FS */
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index 2011c42..03dd295 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -387,9 +387,10 @@
msm_rpc_setup_req(&rhdr, audio->rpc_prog, audio->rpc_ver,
SND_VOC_REC_STOP_PROC);
rc = msm_rpc_write(audio->sndept, &rhdr, sizeof(rhdr));
- wait_event_timeout(audio->wait, audio->stopped == 0,
+ rc = wait_event_timeout(audio->wait, audio->stopped == 1,
1 * HZ);
- audio->stopped = 1;
+ if (rc == 0)
+ audio->stopped = 1;
wake_up(&audio->read_wait);
audmgr_disable(&audio->audmgr);
audio->enabled = 0;
@@ -456,7 +457,9 @@
if ((rec_status == RPC_VOC_REC_STAT_DATA) ||
(rec_status == RPC_VOC_REC_STAT_DONE)) {
if (datacb_data->pkt.fw_data.fw_ptr_status &&
- be32_to_cpu(datacb_data->pkt.fw_data.rec_length)) {
+ be32_to_cpu(datacb_data->pkt.fw_data.rec_length) &&
+ be32_to_cpu(datacb_data->pkt.fw_data.rec_length)
+ <= MAX_FRAME_SIZE) {
MM_DBG("Copy FW link:rec_buf_size \
= 0x%08x, rec_length=0x%08x\n",
@@ -479,7 +482,10 @@
datacb_data->pkt.fw_data.rec_num_frames);
mutex_unlock(&audio->dsp_lock);
} else if (datacb_data->pkt.rw_data.rw_ptr_status &&
- be32_to_cpu(datacb_data->pkt.rw_data.rec_length)) {
+ be32_to_cpu(datacb_data->pkt.rw_data.rec_length) &&
+ be32_to_cpu(datacb_data->pkt.rw_data.rec_length)
+ <= MAX_FRAME_SIZE) {
+
MM_DBG("Copy RW link:rec_buf_size \
=0x%08x, rec_length=0x%08x\n",
be32_to_cpu( \
@@ -500,6 +506,15 @@
be32_to_cpu(
datacb_data->pkt.rw_data.rec_num_frames);
mutex_unlock(&audio->dsp_lock);
+ } else {
+ MM_ERR("FW: ptr_status %d, rec_length=0x%08x,"
+ "RW: ptr_status %d, rec_length=0x%08x\n",
+ datacb_data->pkt.rw_data.fw_ptr_status, \
+ be32_to_cpu( \
+ datacb_data->pkt.fw_data.rec_length), \
+ datacb_data->pkt.rw_data.fw_ptr_status, \
+ be32_to_cpu( \
+ datacb_data->pkt.fw_data.rec_length));
}
if (rec_status != RPC_VOC_REC_STAT_DONE) {
/* Not end of record */
@@ -521,6 +536,7 @@
} else {
/* Indication record stopped gracefully */
MM_DBG("End Of Voice Record\n");
+ audio->stopped = 1;
wake_up(&audio->wait);
}
} else if (rec_status == RPC_VOC_REC_STAT_PAUSED) {
diff --git a/arch/arm/mach-msm/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
index cee8f04..2ea1bc9 100644
--- a/arch/arm/mach-msm/qdsp6v2/Makefile
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -1,4 +1,3 @@
-obj-y += rtac.o
ifdef CONFIG_ARCH_MSM8X60
obj-y += audio_dev_ctl.o
obj-y += board-msm8x60-audio.o
@@ -13,10 +12,15 @@
endif
obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
obj-y += audio_acdb.o
-ifndef CONFIG_ARCH_MSM9615
-obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
-obj-y += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
-obj-$(CONFIG_MSM_QDSP6_CODECS) += q6audio_v1.o q6audio_v1_aio.o
-obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
-obj-y += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+ifdef CONFIG_ARCH_MSM9615
+obj-y += rtac.o
endif
+obj-$(CONFIG_MSM_QDSP6_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += rtac.o q6audio_v1.o q6audio_v1_aio.o
+obj-$(CONFIG_MSM_QDSP6_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o audio_utils_aio.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += rtac_v2.o q6audio_v2.o q6audio_v2_aio.o
+obj-$(CONFIG_MSM_QDSP6V2_CODECS) += audio_mp3.o audio_amrnb.o audio_amrwb.o audio_evrc.o audio_qcelp.o amrwb_in.o
+obj-$(CONFIG_MSM_ULTRASOUND) += ultrasound/
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index db0a96e..0591a71 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -840,6 +840,10 @@
.step = SOFT_VOLUME_STEP,
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
+ if (softpause.rampingcurve == SOFT_PAUSE_CURVE_LINEAR)
+ softpause.step = SOFT_PAUSE_STEP_LINEAR;
+ if (softvol.rampingcurve == SOFT_VOLUME_CURVE_LINEAR)
+ softvol.step = SOFT_VOLUME_STEP_LINEAR;
audio->out_enabled = 1;
audio->out_needed = 1;
rc = q6asm_set_volume(audio->ac, audio->volume);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
index e108de5..fc20847 100644
--- a/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_common.h
@@ -15,8 +15,13 @@
#ifndef __Q6_AUDIO_COMMON_H__
#define __Q6_AUDIO_COMMON_H__
+#ifdef CONFIG_ARCH_MSMCOPPER
+#include <sound/apr_audio-v2.h>
+#include <sound/q6asm-v2.h>
+#else
#include <sound/apr_audio.h>
#include <sound/q6asm.h>
+#endif
void q6_audio_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c
new file mode 100644
index 0000000..0db1ef4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils.h"
+
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_in *audio = (struct q6audio_in *)priv;
+ unsigned long flags;
+
+ pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+
+ spin_lock_irqsave(&audio->dsp_lock, flags);
+ switch (opcode) {
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ audio_in_get_dsp_frames(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_WRITE_DONE_V2:
+ atomic_inc(&audio->in_count);
+ wake_up(&audio->write_wait);
+ break;
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ audio->eos_rsp = 1;
+ wake_up(&audio->read_wait);
+ break;
+ case ASM_STREAM_CMDRSP_GET_PP_PARAMS_V2:
+ break;
+ case ASM_SESSION_EVENTX_OVERFLOW:
+ pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+ __func__, audio->ac->session);
+ break;
+ default:
+ pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+ audio->ac->session, opcode);
+ break;
+ }
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+void audio_in_get_dsp_frames(void *priv,
+ uint32_t token, uint32_t *payload)
+{
+ struct q6audio_in *audio = (struct q6audio_in *)priv;
+ uint32_t index;
+
+ index = token;
+ pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
+ __func__, audio->ac->session, token, payload[9],
+ payload[5]);
+ pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
+ audio->ac->session, payload[7], payload[6]);
+ pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
+ audio->ac->session, payload[8], payload[10]);
+ pr_debug("%s:session id %d: enc_framesotal_size=0x%8x\n", __func__,
+ audio->ac->session, payload[4]);
+
+ audio->out_frame_info[index][0] = payload[9];
+ audio->out_frame_info[index][1] = payload[5];
+
+ /* statistics of read */
+ atomic_add(payload[4], &audio->in_bytes);
+ atomic_add(payload[9], &audio->in_samples);
+
+ if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
+ atomic_inc(&audio->out_count);
+ wake_up(&audio->read_wait);
+ }
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
new file mode 100644
index 0000000..aab7b19
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6audio_v2_aio.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include "audio_utils_aio.h"
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+
+ pr_debug("%s:opcode = %x token = 0x%x\n", __func__, opcode, token);
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2:
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+ case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+ case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+ audio_aio_cb(opcode, token, payload, audio);
+ break;
+ default:
+ pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+ break;
+ }
+}
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv/*struct q6audio_aio *audio*/)
+{
+ struct q6audio_aio *audio = (struct q6audio_aio *)priv;
+ union msm_audio_event_payload e_payload;
+
+ switch (opcode) {
+ case ASM_DATA_EVENT_WRITE_DONE_V2:
+ pr_debug("%s[%p]:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+ __func__, audio, token);
+ audio_aio_async_write_ack(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_READ_DONE_V2:
+ pr_debug("%s[%p]:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+ __func__, audio, token);
+ audio_aio_async_read_ack(audio, token, payload);
+ break;
+ case ASM_DATA_EVENT_RENDERED_EOS:
+ /* EOS Handle */
+ pr_debug("%s[%p]:ASM_DATA_CMDRSP_EOS\n", __func__, audio);
+ if (audio->feedback) { /* Non-Tunnel mode */
+ audio->eos_rsp = 1;
+ /* propagate input EOS i/p buffer,
+ after receiving DSP acknowledgement */
+ if (audio->eos_flag &&
+ (audio->eos_write_payload.aio_buf.buf_addr)) {
+ audio_aio_post_event(audio,
+ AUDIO_EVENT_WRITE_DONE,
+ audio->eos_write_payload);
+ memset(&audio->eos_write_payload , 0,
+ sizeof(union msm_audio_event_payload));
+ audio->eos_flag = 0;
+ }
+ } else { /* Tunnel mode */
+ audio->eos_rsp = 1;
+ wake_up(&audio->write_wait);
+ wake_up(&audio->cmd_wait);
+ }
+ break;
+ case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2:
+ case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+ pr_debug("%s[%p]:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
+ __func__, audio, payload[0], payload[1], opcode);
+ break;
+ case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+ case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY:
+
+ pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0]-sr = %d, payload[1]-chl = %d, payload[2] = %d, payload[3] = %d\n",
+ __func__, audio, payload[0],
+ payload[1], payload[2], payload[3]);
+
+ pr_debug("%s[%p]: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, sr(prev) = %d, chl(prev) = %d,",
+ __func__, audio, audio->pcm_cfg.sample_rate,
+ audio->pcm_cfg.channel_count);
+
+ audio->pcm_cfg.sample_rate = payload[0];
+ audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
+ e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
+ e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
+ audio_aio_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/rtac.c b/arch/arm/mach-msm/qdsp6v2/rtac.c
index 4ce9b030..8808375 100644
--- a/arch/arm/mach-msm/qdsp6v2/rtac.c
+++ b/arch/arm/mach-msm/qdsp6v2/rtac.c
@@ -22,8 +22,8 @@
#include <asm/atomic.h>
#include <mach/qdsp6v2/audio_acdb.h>
#include <mach/qdsp6v2/rtac.h>
-#include <sound/q6asm.h>
-#include <sound/q6adm.h>
+#include "q6audio_common.h"
+#include <sound/q6afe.h>
#ifndef CONFIG_RTAC
@@ -400,10 +400,8 @@
memcpy(rtac_adm_buffer, &payload_size, sizeof(u32));
if (payload_size != 0) {
if (payload_size > rtac_adm_user_buf_size) {
- pr_err("%s: Buffer set not big enough for "
- "returned data, buf size = %d, "
- "ret data = %d\n", __func__,
- rtac_adm_user_buf_size, payload_size);
+ pr_err("%s: Buffer set not big enough for returned data, buf size = %d,ret data = %d\n",
+ __func__, rtac_adm_user_buf_size, payload_size);
goto done;
}
memcpy(rtac_adm_buffer + sizeof(u32), payload, payload_size);
@@ -414,20 +412,20 @@
u32 send_adm_apr(void *buf, u32 opcode)
{
- s32 result;
- u32 count = 0;
- u32 bytes_returned = 0;
- u32 port_index = 0;
- u32 copp_id;
- u32 payload_size;
- struct apr_hdr adm_params;
+ s32 result;
+ u32 count = 0;
+ u32 bytes_returned = 0;
+ u32 port_index = 0;
+ u32 copp_id;
+ u32 payload_size;
+ struct apr_hdr adm_params;
pr_debug("%s\n", __func__);
if (copy_from_user(&count, (void *)buf, sizeof(count))) {
- pr_err("%s: Copy to user failed! buf = 0x%x\n",
- __func__, (unsigned int)buf);
- result = -EFAULT;
- goto done;
+ pr_err("%s: Copy to user failed! buf = 0x%x\n",
+ __func__, (unsigned int)buf);
+ result = -EFAULT;
+ goto done;
}
if (count <= 0) {
@@ -443,9 +441,8 @@
if (payload_size > MAX_PAYLOAD_SIZE) {
-
- pr_err("%s: Invalid payload size = %d\n",
- __func__, payload_size);
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
goto done;
}
@@ -521,9 +518,9 @@
if (rtac_adm_payload_size != 0) {
if (copy_to_user(buf, rtac_adm_buffer,
- rtac_adm_payload_size + sizeof(u32))) {
- pr_err("%s: Could not copy buffer to user,"
- "size = %d\n", __func__, payload_size);
+ rtac_adm_payload_size + sizeof(u32))) {
+ pr_err("%s: Could not copy buffer to user, size = %d\n",
+ __func__, payload_size);
goto done;
}
}
@@ -573,10 +570,8 @@
memcpy(rtac_asm_buffer, &payload_size, sizeof(u32));
if (payload_size) {
if (payload_size > rtac_asm_user_buf_size) {
- pr_err("%s: Buffer set not big enough for "
- "returned data, buf size = %d, "
- "ret data = %d\n", __func__,
- rtac_asm_user_buf_size, payload_size);
+ pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+ __func__, rtac_asm_user_buf_size, payload_size);
goto done;
}
memcpy(rtac_asm_buffer + sizeof(u32), payload, payload_size);
@@ -587,19 +582,19 @@
u32 send_rtac_asm_apr(void *buf, u32 opcode)
{
- s32 result;
- u32 count = 0;
- u32 bytes_returned = 0;
- u32 session_id = 0;
- u32 payload_size;
- struct apr_hdr asm_params;
+ s32 result;
+ u32 count = 0;
+ u32 bytes_returned = 0;
+ u32 session_id = 0;
+ u32 payload_size;
+ struct apr_hdr asm_params;
pr_debug("%s\n", __func__);
if (copy_from_user(&count, (void *)buf, sizeof(count))) {
- pr_err("%s: Copy to user failed! buf = 0x%x\n",
- __func__, (unsigned int)buf);
- result = -EFAULT;
- goto done;
+ pr_err("%s: Copy to user failed! buf = 0x%x\n",
+ __func__, (unsigned int)buf);
+ result = -EFAULT;
+ goto done;
}
if (count <= 0) {
@@ -614,9 +609,8 @@
}
if (payload_size > MAX_PAYLOAD_SIZE) {
-
- pr_err("%s: Invalid payload size = %d\n",
- __func__, payload_size);
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
goto done;
}
@@ -643,7 +637,7 @@
/* Copy buffer to in-band payload */
if (copy_from_user(rtac_asm_buffer + sizeof(asm_params),
- buf + 3 * sizeof(u32), payload_size)) {
+ buf + 3 * sizeof(u32), payload_size)) {
pr_err("%s: Could not copy payload from user buffer\n",
__func__);
goto err;
@@ -691,9 +685,9 @@
if (rtac_asm_payload_size != 0) {
if (copy_to_user(buf, rtac_asm_buffer,
- rtac_asm_payload_size + sizeof(u32))) {
- pr_err("%s: Could not copy buffer to user,"
- "size = %d\n", __func__, payload_size);
+ rtac_asm_payload_size + sizeof(u32))) {
+ pr_err("%s: Could not copy buffer to user,size = %d\n",
+ __func__, payload_size);
goto done;
}
}
@@ -715,7 +709,6 @@
void rtac_set_voice_handle(u32 mode, void *handle)
{
pr_debug("%s\n", __func__);
-
mutex_lock(&rtac_voice_apr_mutex);
rtac_voice_apr_data[mode].apr_handle = handle;
mutex_unlock(&rtac_voice_apr_mutex);
@@ -724,7 +717,7 @@
bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
{
if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
- (mode >= RTAC_VOICE_MODES))
+ (mode >= RTAC_VOICE_MODES))
return false;
pr_debug("%s\n", __func__);
@@ -743,10 +736,8 @@
memcpy(rtac_voice_buffer, &payload_size, sizeof(u32));
if (payload_size) {
if (payload_size > rtac_voice_user_buf_size) {
- pr_err("%s: Buffer set not big enough for "
- "returned data, buf size = %d, "
- "ret data = %d\n", __func__,
- rtac_voice_user_buf_size, payload_size);
+ pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+ __func__, rtac_voice_user_buf_size, payload_size);
goto done;
}
memcpy(rtac_voice_buffer + sizeof(u32), payload, payload_size);
@@ -757,19 +748,19 @@
u32 send_voice_apr(u32 mode, void *buf, u32 opcode)
{
- s32 result;
- u32 count = 0;
- u32 bytes_returned = 0;
- u32 payload_size;
- u16 dest_port;
- struct apr_hdr voice_params;
+ s32 result;
+ u32 count = 0;
+ u32 bytes_returned = 0;
+ u32 payload_size;
+ u16 dest_port;
+ struct apr_hdr voice_params;
pr_debug("%s\n", __func__);
if (copy_from_user(&count, (void *)buf, sizeof(count))) {
- pr_err("%s: Copy to user failed! buf = 0x%x\n",
- __func__, (unsigned int)buf);
- result = -EFAULT;
- goto done;
+ pr_err("%s: Copy to user failed! buf = 0x%x\n",
+ __func__, (unsigned int)buf);
+ result = -EFAULT;
+ goto done;
}
if (count <= 0) {
@@ -785,7 +776,7 @@
if (payload_size > MAX_PAYLOAD_SIZE) {
pr_err("%s: Invalid payload size = %d\n",
- __func__, payload_size);
+ __func__, payload_size);
goto done;
}
@@ -812,7 +803,7 @@
/* Copy buffer to in-band payload */
if (copy_from_user(rtac_voice_buffer + sizeof(voice_params),
- buf + 3 * sizeof(u32), payload_size)) {
+ buf + 3 * sizeof(u32), payload_size)) {
pr_err("%s: Could not copy payload from user buffer\n",
__func__);
goto err;
@@ -860,8 +851,8 @@
if (rtac_voice_payload_size != 0) {
if (copy_to_user(buf, rtac_voice_buffer,
rtac_voice_payload_size + sizeof(u32))) {
- pr_err("%s: Could not copy buffer to user,"
- "size = %d\n", __func__, payload_size);
+ pr_err("%s: Could not copy buffer to user,size = %d\n",
+ __func__, payload_size);
goto done;
}
}
@@ -972,7 +963,7 @@
mutex_init(&rtac_adm_mutex);
mutex_init(&rtac_adm_apr_mutex);
- rtac_adm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+ rtac_adm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
if (rtac_adm_buffer == NULL) {
pr_err("%s: Could not allocate payload of size = %d\n",
__func__, RTAC_BUF_SIZE);
@@ -987,10 +978,11 @@
}
mutex_init(&rtac_asm_apr_mutex);
- rtac_asm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+ rtac_asm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
if (rtac_asm_buffer == NULL) {
pr_err("%s: Could not allocate payload of size = %d\n",
__func__, RTAC_BUF_SIZE);
+ kzfree(rtac_adm_buffer);
goto nomem;
}
@@ -1004,10 +996,12 @@
mutex_init(&rtac_voice_mutex);
mutex_init(&rtac_voice_apr_mutex);
- rtac_voice_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+ rtac_voice_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
if (rtac_voice_buffer == NULL) {
pr_err("%s: Could not allocate payload of size = %d\n",
__func__, RTAC_BUF_SIZE);
+ kzfree(rtac_adm_buffer);
+ kzfree(rtac_asm_buffer);
goto nomem;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/rtac_v2.c b/arch/arm/mach-msm/qdsp6v2/rtac_v2.c
new file mode 100644
index 0000000..2d0607c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/rtac_v2.c
@@ -0,0 +1,1019 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/msm_audio_acdb.h>
+#include <asm/atomic.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/qdsp6v2/rtac.h>
+#include "q6audio_common.h"
+#include <sound/q6afe-v2.h>
+
+#ifndef CONFIG_RTAC
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id) {}
+void rtac_remove_adm_device(u32 port_id) {}
+void rtac_remove_popp_from_adm_devices(u32 popp_id) {}
+void rtac_set_adm_handle(void *handle) {}
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+ {return false; }
+void rtac_set_asm_handle(u32 session_id, void *handle) {}
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+ u32 payload_size) {return false; }
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+ u32 tx_afe_port, u32 session_id) {}
+void rtac_remove_voice(u32 cvs_handle) {}
+void rtac_set_voice_handle(u32 mode, void *handle) {}
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload,
+ u32 payload_size) {return false; }
+
+#else
+
+#define VOICE_CMD_SET_PARAM 0x00011006
+#define VOICE_CMD_GET_PARAM 0x00011007
+#define VOICE_EVT_GET_PARAM_ACK 0x00011008
+
+/* Max size of payload (buf size - apr header) */
+#define MAX_PAYLOAD_SIZE 4076
+#define RTAC_MAX_ACTIVE_DEVICES 4
+#define RTAC_MAX_ACTIVE_VOICE_COMBOS 2
+#define RTAC_MAX_ACTIVE_POPP 8
+#define RTAC_BUF_SIZE 4096
+
+#define TIMEOUT_MS 1000
+
+/* APR data */
+struct rtac_apr_data {
+ void *apr_handle;
+ atomic_t cmd_state;
+ wait_queue_head_t cmd_wait;
+};
+
+static struct rtac_apr_data rtac_adm_apr_data;
+static struct rtac_apr_data rtac_asm_apr_data[SESSION_MAX+1];
+static struct rtac_apr_data rtac_voice_apr_data[RTAC_VOICE_MODES];
+
+
+/* ADM info & APR */
+struct rtac_adm_data {
+ uint32_t topology_id;
+ uint32_t afe_port;
+ uint32_t copp;
+ uint32_t num_of_popp;
+ uint32_t popp[RTAC_MAX_ACTIVE_POPP];
+};
+
+struct rtac_adm {
+ uint32_t num_of_dev;
+ struct rtac_adm_data device[RTAC_MAX_ACTIVE_DEVICES];
+};
+static struct rtac_adm rtac_adm_data;
+static u32 rtac_adm_payload_size;
+static u32 rtac_adm_user_buf_size;
+static u8 *rtac_adm_buffer;
+
+
+/* ASM APR */
+static u32 rtac_asm_payload_size;
+static u32 rtac_asm_user_buf_size;
+static u8 *rtac_asm_buffer;
+
+
+/* Voice info & APR */
+struct rtac_voice_data {
+ uint32_t tx_topology_id;
+ uint32_t rx_topology_id;
+ uint32_t tx_afe_port;
+ uint32_t rx_afe_port;
+ uint16_t cvs_handle;
+ uint16_t cvp_handle;
+};
+
+struct rtac_voice {
+ uint32_t num_of_voice_combos;
+ struct rtac_voice_data voice[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+};
+
+static struct rtac_voice rtac_voice_data;
+static u32 rtac_voice_payload_size;
+static u32 rtac_voice_user_buf_size;
+static u8 *rtac_voice_buffer;
+static u32 voice_session_id[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+
+
+struct mutex rtac_adm_mutex;
+struct mutex rtac_adm_apr_mutex;
+struct mutex rtac_asm_apr_mutex;
+struct mutex rtac_voice_mutex;
+struct mutex rtac_voice_apr_mutex;
+
+static int rtac_open(struct inode *inode, struct file *f)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static int rtac_release(struct inode *inode, struct file *f)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+/* ADM Info */
+void add_popp(u32 dev_idx, u32 port_id, u32 popp_id)
+{
+ u32 i = 0;
+
+ for (; i < rtac_adm_data.device[dev_idx].num_of_popp; i++)
+ if (rtac_adm_data.device[dev_idx].popp[i] == popp_id)
+ goto done;
+
+ if (rtac_adm_data.device[dev_idx].num_of_popp ==
+ RTAC_MAX_ACTIVE_POPP) {
+ pr_err("%s, Max POPP!\n", __func__);
+ goto done;
+ }
+ rtac_adm_data.device[dev_idx].popp[
+ rtac_adm_data.device[dev_idx].num_of_popp++] = popp_id;
+done:
+ return;
+}
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id)
+{
+ u32 i = 0;
+ pr_debug("%s: port_id = %d, popp_id = %d\n", __func__, port_id,
+ popp_id);
+
+ mutex_lock(&rtac_adm_mutex);
+ if (rtac_adm_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
+ pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+ goto done;
+ }
+
+ /* Check if device already added */
+ if (rtac_adm_data.num_of_dev != 0) {
+ for (; i < rtac_adm_data.num_of_dev; i++) {
+ if (rtac_adm_data.device[i].afe_port == port_id) {
+ add_popp(i, port_id, popp_id);
+ goto done;
+ }
+ if (rtac_adm_data.device[i].num_of_popp ==
+ RTAC_MAX_ACTIVE_POPP) {
+ pr_err("%s, Max POPP!\n", __func__);
+ goto done;
+ }
+ }
+ }
+
+ /* Add device */
+ rtac_adm_data.num_of_dev++;
+
+ if (path_id == ADM_PATH_PLAYBACK)
+ rtac_adm_data.device[i].topology_id =
+ get_adm_rx_topology();
+ else
+ rtac_adm_data.device[i].topology_id =
+ get_adm_tx_topology();
+ rtac_adm_data.device[i].afe_port = port_id;
+ rtac_adm_data.device[i].copp = copp_id;
+ rtac_adm_data.device[i].popp[
+ rtac_adm_data.device[i].num_of_popp++] = popp_id;
+done:
+ mutex_unlock(&rtac_adm_mutex);
+ return;
+}
+
+static void shift_adm_devices(u32 dev_idx)
+{
+ for (; dev_idx < rtac_adm_data.num_of_dev; dev_idx++) {
+ memcpy(&rtac_adm_data.device[dev_idx],
+ &rtac_adm_data.device[dev_idx + 1],
+ sizeof(rtac_adm_data.device[dev_idx]));
+ memset(&rtac_adm_data.device[dev_idx + 1], 0,
+ sizeof(rtac_adm_data.device[dev_idx]));
+ }
+}
+
+static void shift_popp(u32 copp_idx, u32 popp_idx)
+{
+ for (; popp_idx < rtac_adm_data.device[copp_idx].num_of_popp;
+ popp_idx++) {
+ memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx],
+ &rtac_adm_data.device[copp_idx].popp[popp_idx + 1],
+ sizeof(uint32_t));
+ memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1], 0,
+ sizeof(uint32_t));
+ }
+}
+
+void rtac_remove_adm_device(u32 port_id)
+{
+ s32 i;
+ pr_debug("%s: port_id = %d\n", __func__, port_id);
+
+ mutex_lock(&rtac_adm_mutex);
+ /* look for device */
+ for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+ if (rtac_adm_data.device[i].afe_port == port_id) {
+ memset(&rtac_adm_data.device[i], 0,
+ sizeof(rtac_adm_data.device[i]));
+ rtac_adm_data.num_of_dev--;
+
+ if (rtac_adm_data.num_of_dev >= 1) {
+ shift_adm_devices(i);
+ break;
+ }
+ }
+ }
+
+ mutex_unlock(&rtac_adm_mutex);
+ return;
+}
+
+void rtac_remove_popp_from_adm_devices(u32 popp_id)
+{
+ s32 i, j;
+ pr_debug("%s: popp_id = %d\n", __func__, popp_id);
+
+ mutex_lock(&rtac_adm_mutex);
+
+ for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+ for (j = 0; j < rtac_adm_data.device[i].num_of_popp; j++) {
+ if (rtac_adm_data.device[i].popp[j] == popp_id) {
+ rtac_adm_data.device[i].popp[j] = 0;
+ rtac_adm_data.device[i].num_of_popp--;
+ shift_popp(i, j);
+ }
+ }
+ }
+
+ mutex_unlock(&rtac_adm_mutex);
+}
+
+/* Voice Info */
+static void set_rtac_voice_data(int idx, u32 cvs_handle, u32 cvp_handle,
+ u32 rx_afe_port, u32 tx_afe_port,
+ u32 session_id)
+{
+ rtac_voice_data.voice[idx].tx_topology_id = get_voice_tx_topology();
+ rtac_voice_data.voice[idx].rx_topology_id = get_voice_rx_topology();
+ rtac_voice_data.voice[idx].tx_afe_port = tx_afe_port;
+ rtac_voice_data.voice[idx].rx_afe_port = rx_afe_port;
+ rtac_voice_data.voice[idx].cvs_handle = cvs_handle;
+ rtac_voice_data.voice[idx].cvp_handle = cvp_handle;
+
+ /* Store session ID for voice RTAC */
+ voice_session_id[idx] = session_id;
+}
+
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+ u32 tx_afe_port, u32 session_id)
+{
+ u32 i = 0;
+ pr_debug("%s\n", __func__);
+ mutex_lock(&rtac_voice_mutex);
+
+ if (rtac_voice_data.num_of_voice_combos ==
+ RTAC_MAX_ACTIVE_VOICE_COMBOS) {
+ pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+ goto done;
+ }
+
+ /* Check if device already added */
+ if (rtac_voice_data.num_of_voice_combos != 0) {
+ for (; i < rtac_voice_data.num_of_voice_combos; i++) {
+ if (rtac_voice_data.voice[i].cvs_handle ==
+ cvs_handle) {
+ set_rtac_voice_data(i, cvs_handle, cvp_handle,
+ rx_afe_port, tx_afe_port,
+ session_id);
+ goto done;
+ }
+ }
+ }
+
+ /* Add device */
+ rtac_voice_data.num_of_voice_combos++;
+ set_rtac_voice_data(i, cvs_handle, cvp_handle,
+ rx_afe_port, tx_afe_port,
+ session_id);
+done:
+ mutex_unlock(&rtac_voice_mutex);
+ return;
+}
+
+static void shift_voice_devices(u32 idx)
+{
+ for (; idx < rtac_voice_data.num_of_voice_combos - 1; idx++) {
+ memcpy(&rtac_voice_data.voice[idx],
+ &rtac_voice_data.voice[idx + 1],
+ sizeof(rtac_voice_data.voice[idx]));
+ voice_session_id[idx] = voice_session_id[idx + 1];
+ }
+}
+
+void rtac_remove_voice(u32 cvs_handle)
+{
+ u32 i = 0;
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&rtac_voice_mutex);
+ /* look for device */
+ for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+ if (rtac_voice_data.voice[i].cvs_handle == cvs_handle) {
+ shift_voice_devices(i);
+ rtac_voice_data.num_of_voice_combos--;
+ memset(&rtac_voice_data.voice[
+ rtac_voice_data.num_of_voice_combos], 0,
+ sizeof(rtac_voice_data.voice
+ [rtac_voice_data.num_of_voice_combos]));
+ voice_session_id[rtac_voice_data.num_of_voice_combos]
+ = 0;
+ break;
+ }
+ }
+ mutex_unlock(&rtac_voice_mutex);
+ return;
+}
+
+static int get_voice_index(u32 cvs_handle)
+{
+ u32 i;
+
+ for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+ if (rtac_voice_data.voice[i].cvs_handle == cvs_handle)
+ return i;
+ }
+
+ pr_err("%s: No voice index for CVS handle %d found returning 0\n",
+ __func__, cvs_handle);
+ return 0;
+}
+
+
+/* ADM APR */
+void rtac_set_adm_handle(void *handle)
+{
+ pr_debug("%s: handle = %d\n", __func__, (unsigned int)handle);
+
+ mutex_lock(&rtac_adm_apr_mutex);
+ rtac_adm_apr_data.apr_handle = handle;
+ mutex_unlock(&rtac_adm_apr_mutex);
+}
+
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+{
+ pr_debug("%s:cmd_state = %d\n", __func__,
+ atomic_read(&rtac_adm_apr_data.cmd_state));
+ if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
+ return false;
+
+ /* Offset data for in-band payload */
+ rtac_copy_adm_payload_to_user(payload, payload_size);
+ atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+ wake_up(&rtac_adm_apr_data.cmd_wait);
+ return true;
+}
+
+void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size)
+{
+ pr_debug("%s\n", __func__);
+ rtac_adm_payload_size = payload_size;
+
+ memcpy(rtac_adm_buffer, &payload_size, sizeof(u32));
+ if (payload_size != 0) {
+ if (payload_size > rtac_adm_user_buf_size) {
+ pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+ __func__, rtac_adm_user_buf_size, payload_size);
+ goto done;
+ }
+ memcpy(rtac_adm_buffer + sizeof(u32), payload, payload_size);
+ }
+done:
+ return;
+}
+
+u32 send_adm_apr(void *buf, u32 opcode)
+{
+ s32 result;
+ u32 count = 0;
+ u32 bytes_returned = 0;
+ u32 port_index = 0;
+ u32 copp_id;
+ u32 payload_size;
+ struct apr_hdr adm_params;
+ pr_debug("%s\n", __func__);
+
+ if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+ pr_err("%s: Copy to user failed! buf = 0x%x\n",
+ __func__, (unsigned int)buf);
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (count <= 0) {
+ pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+ goto done;
+ }
+
+ if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy payload size from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+
+ if (payload_size > MAX_PAYLOAD_SIZE) {
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
+ goto done;
+ }
+
+ if (copy_from_user(&copp_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy port id from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ for (port_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
+ if (adm_get_copp_id(port_index) == copp_id)
+ break;
+ }
+ if (port_index >= AFE_MAX_PORTS) {
+ pr_err("%s: Could not find port index for copp = %d\n",
+ __func__, copp_id);
+ goto done;
+ }
+
+ mutex_lock(&rtac_adm_apr_mutex);
+ if (rtac_adm_apr_data.apr_handle == NULL) {
+ pr_err("%s: APR not initialized\n", __func__);
+ goto err;
+ }
+
+ /* Set globals for copy of returned payload */
+ rtac_adm_user_buf_size = count;
+ /* Copy buffer to in-band payload */
+ if (copy_from_user(rtac_adm_buffer + sizeof(adm_params),
+ buf + 3 * sizeof(u32), payload_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ goto err;
+ }
+
+ /* Pack header */
+ adm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ adm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ payload_size);
+ adm_params.src_svc = APR_SVC_ADM;
+ adm_params.src_domain = APR_DOMAIN_APPS;
+ adm_params.src_port = copp_id;
+ adm_params.dest_svc = APR_SVC_ADM;
+ adm_params.dest_domain = APR_DOMAIN_ADSP;
+ adm_params.dest_port = copp_id;
+ adm_params.token = copp_id;
+ adm_params.opcode = opcode;
+
+ memcpy(rtac_adm_buffer, &adm_params, sizeof(adm_params));
+ atomic_set(&rtac_adm_apr_data.cmd_state, 1);
+
+ pr_debug("%s: Sending RTAC command size = %d\n",
+ __func__, adm_params.pkt_size);
+
+ result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
+ (uint32_t *)rtac_adm_buffer);
+ if (result < 0) {
+ pr_err("%s: Set params failed port = %d, copp = %d\n",
+ __func__, port_index, copp_id);
+ goto err;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(rtac_adm_apr_data.cmd_wait,
+ (atomic_read(&rtac_adm_apr_data.cmd_state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ mutex_unlock(&rtac_adm_apr_mutex);
+ if (!result) {
+ pr_err("%s: Set params timed out port = %d, copp = %d\n",
+ __func__, port_index, copp_id);
+ goto done;
+ }
+
+ if (rtac_adm_payload_size != 0) {
+ if (copy_to_user(buf, rtac_adm_buffer,
+ rtac_adm_payload_size + sizeof(u32))) {
+ pr_err("%s: Could not copy buffer to user,size = %d\n",
+ __func__, payload_size);
+ goto done;
+ }
+ }
+
+ /* Return data written for SET & data read for GET */
+ if (opcode == ADM_CMD_GET_PP_PARAMS_V5)
+ bytes_returned = rtac_adm_payload_size;
+ else
+ bytes_returned = payload_size;
+done:
+ return bytes_returned;
+err:
+ mutex_unlock(&rtac_adm_apr_mutex);
+ return bytes_returned;
+}
+
+
+/* ASM APR */
+void rtac_set_asm_handle(u32 session_id, void *handle)
+{
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&rtac_asm_apr_mutex);
+ rtac_asm_apr_data[session_id].apr_handle = handle;
+ mutex_unlock(&rtac_asm_apr_mutex);
+}
+
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+ u32 payload_size)
+{
+ if (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) != 1)
+ return false;
+
+ pr_debug("%s\n", __func__);
+ /* Offset data for in-band payload */
+ rtac_copy_asm_payload_to_user(payload, payload_size);
+ atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 0);
+ wake_up(&rtac_asm_apr_data[session_id].cmd_wait);
+ return true;
+}
+
+void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size)
+{
+ pr_debug("%s\n", __func__);
+ rtac_asm_payload_size = payload_size;
+
+ memcpy(rtac_asm_buffer, &payload_size, sizeof(u32));
+ if (payload_size) {
+ if (payload_size > rtac_asm_user_buf_size) {
+ pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+ __func__, rtac_asm_user_buf_size, payload_size);
+ goto done;
+ }
+ memcpy(rtac_asm_buffer + sizeof(u32), payload, payload_size);
+ }
+done:
+ return;
+}
+
+u32 send_rtac_asm_apr(void *buf, u32 opcode)
+{
+ s32 result;
+ u32 count = 0;
+ u32 bytes_returned = 0;
+ u32 session_id = 0;
+ u32 payload_size;
+ struct apr_hdr asm_params;
+ pr_debug("%s\n", __func__);
+
+ if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+ pr_err("%s: Copy to user failed! buf = 0x%x\n",
+ __func__, (unsigned int)buf);
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (count <= 0) {
+ pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+ goto done;
+ }
+
+ if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy payload size from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if (payload_size > MAX_PAYLOAD_SIZE) {
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
+ goto done;
+ }
+
+ if (copy_from_user(&session_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy session id from user buffer\n",
+ __func__);
+ goto done;
+ }
+ if (session_id > (SESSION_MAX + 1)) {
+ pr_err("%s: Invalid Session = %d\n", __func__, session_id);
+ goto done;
+ }
+
+ mutex_lock(&rtac_asm_apr_mutex);
+ if (session_id < SESSION_MAX+1) {
+ if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
+ pr_err("%s: APR not initialized\n", __func__);
+ goto err;
+ }
+ }
+
+ /* Set globals for copy of returned payload */
+ rtac_asm_user_buf_size = count;
+
+ /* Copy buffer to in-band payload */
+ if (copy_from_user(rtac_asm_buffer + sizeof(asm_params),
+ buf + 3 * sizeof(u32), payload_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ goto err;
+ }
+
+ /* Pack header */
+ asm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ asm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ payload_size);
+ asm_params.src_svc = q6asm_get_apr_service_id(session_id);
+ asm_params.src_domain = APR_DOMAIN_APPS;
+ asm_params.src_port = (session_id << 8) | 0x0001;
+ asm_params.dest_svc = APR_SVC_ASM;
+ asm_params.dest_domain = APR_DOMAIN_ADSP;
+ asm_params.dest_port = (session_id << 8) | 0x0001;
+ asm_params.token = session_id;
+ asm_params.opcode = opcode;
+
+ memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
+ if (session_id < SESSION_MAX+1)
+ atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+
+ pr_debug("%s: Sending RTAC command size = %d, session_id=%d\n",
+ __func__, asm_params.pkt_size, session_id);
+
+ result = apr_send_pkt(rtac_asm_apr_data[session_id].apr_handle,
+ (uint32_t *)rtac_asm_buffer);
+ if (result < 0) {
+ pr_err("%s: Set params failed session = %d\n",
+ __func__, session_id);
+ goto err;
+ }
+
+ /* Wait for the callback */
+ result = wait_event_timeout(rtac_asm_apr_data[session_id].cmd_wait,
+ (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) == 0),
+ 5 * HZ);
+ mutex_unlock(&rtac_asm_apr_mutex);
+ if (!result) {
+ pr_err("%s: Set params timed out session = %d\n",
+ __func__, session_id);
+ goto done;
+ }
+
+ if (rtac_asm_payload_size != 0) {
+ if (copy_to_user(buf, rtac_asm_buffer,
+ rtac_asm_payload_size + sizeof(u32))) {
+ pr_err("%s: Could not copy buffer to user,size = %d\n",
+ __func__, payload_size);
+ goto done;
+ }
+ }
+
+ /* Return data written for SET & data read for GET */
+ if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS_V2)
+ bytes_returned = rtac_asm_payload_size;
+ else
+ bytes_returned = payload_size;
+done:
+ return bytes_returned;
+err:
+ mutex_unlock(&rtac_asm_apr_mutex);
+ return bytes_returned;
+}
+
+
+/* Voice APR */
+void rtac_set_voice_handle(u32 mode, void *handle)
+{
+ pr_debug("%s\n", __func__);
+
+ mutex_lock(&rtac_voice_apr_mutex);
+ rtac_voice_apr_data[mode].apr_handle = handle;
+ mutex_unlock(&rtac_voice_apr_mutex);
+}
+
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
+{
+ if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
+ (mode >= RTAC_VOICE_MODES))
+ return false;
+
+ pr_debug("%s\n", __func__);
+ /* Offset data for in-band payload */
+ rtac_copy_voice_payload_to_user(payload, payload_size);
+ atomic_set(&rtac_voice_apr_data[mode].cmd_state, 0);
+ wake_up(&rtac_voice_apr_data[mode].cmd_wait);
+ return true;
+}
+
+void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size)
+{
+ pr_debug("%s\n", __func__);
+ rtac_voice_payload_size = payload_size;
+
+ memcpy(rtac_voice_buffer, &payload_size, sizeof(u32));
+ if (payload_size) {
+ if (payload_size > rtac_voice_user_buf_size) {
+ pr_err("%s: Buffer set not big enough for returned data, buf size = %d, ret data = %d\n",
+ __func__, rtac_voice_user_buf_size, payload_size);
+ goto done;
+ }
+ memcpy(rtac_voice_buffer + sizeof(u32), payload, payload_size);
+ }
+done:
+ return;
+}
+
+u32 send_voice_apr(u32 mode, void *buf, u32 opcode)
+{
+ s32 result;
+ u32 count = 0;
+ u32 bytes_returned = 0;
+ u32 payload_size;
+ u16 dest_port;
+ struct apr_hdr voice_params;
+ pr_debug("%s\n", __func__);
+
+ if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+ pr_err("%s: Copy to user failed! buf = 0x%x\n",
+ __func__, (unsigned int)buf);
+ result = -EFAULT;
+ goto done;
+ }
+
+ if (count <= 0) {
+ pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+ goto done;
+ }
+
+ if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy payload size from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if (payload_size > MAX_PAYLOAD_SIZE) {
+ pr_err("%s: Invalid payload size = %d\n",
+ __func__, payload_size);
+ goto done;
+ }
+
+ if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
+ pr_err("%s: Could not copy port id from user buffer\n",
+ __func__);
+ goto done;
+ }
+
+ if ((mode != RTAC_CVP) && (mode != RTAC_CVS)) {
+ pr_err("%s: Invalid Mode for APR, mode = %d\n",
+ __func__, mode);
+ goto done;
+ }
+
+ mutex_lock(&rtac_voice_apr_mutex);
+ if (rtac_voice_apr_data[mode].apr_handle == NULL) {
+ pr_err("%s: APR not initialized\n", __func__);
+ goto err;
+ }
+
+ /* Set globals for copy of returned payload */
+ rtac_voice_user_buf_size = count;
+
+ /* Copy buffer to in-band payload */
+ if (copy_from_user(rtac_voice_buffer + sizeof(voice_params),
+ buf + 3 * sizeof(u32), payload_size)) {
+ pr_err("%s: Could not copy payload from user buffer\n",
+ __func__);
+ goto err;
+ }
+
+ /* Pack header */
+ voice_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(20), APR_PKT_VER);
+ voice_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ payload_size);
+ voice_params.src_svc = 0;
+ voice_params.src_domain = APR_DOMAIN_APPS;
+ voice_params.src_port = voice_session_id[
+ get_voice_index(dest_port)];
+ voice_params.dest_svc = 0;
+ voice_params.dest_domain = APR_DOMAIN_MODEM;
+ voice_params.dest_port = dest_port;
+ voice_params.token = 0;
+ voice_params.opcode = opcode;
+
+ memcpy(rtac_voice_buffer, &voice_params, sizeof(voice_params));
+ atomic_set(&rtac_voice_apr_data[mode].cmd_state, 1);
+
+ pr_debug("%s: Sending RTAC command size = %d, opcode = %x\n",
+ __func__, voice_params.pkt_size, opcode);
+
+ result = apr_send_pkt(rtac_voice_apr_data[mode].apr_handle,
+ (uint32_t *)rtac_voice_buffer);
+ if (result < 0) {
+ pr_err("%s: apr_send_pkt failed opcode = %x\n",
+ __func__, opcode);
+ goto err;
+ }
+ /* Wait for the callback */
+ result = wait_event_timeout(rtac_voice_apr_data[mode].cmd_wait,
+ (atomic_read(&rtac_voice_apr_data[mode].cmd_state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ mutex_unlock(&rtac_voice_apr_mutex);
+ if (!result) {
+ pr_err("%s: apr_send_pkt timed out opcode = %x\n",
+ __func__, opcode);
+ goto done;
+ }
+
+ if (rtac_voice_payload_size != 0) {
+ if (copy_to_user(buf, rtac_voice_buffer,
+ rtac_voice_payload_size + sizeof(u32))) {
+ pr_err("%s: Could not copy buffer to user, size = %d\n",
+ __func__, payload_size);
+ goto done;
+ }
+ }
+
+ /* Return data written for SET & data read for GET */
+ if (opcode == VOICE_CMD_GET_PARAM)
+ bytes_returned = rtac_voice_payload_size;
+ else
+ bytes_returned = payload_size;
+done:
+ return bytes_returned;
+err:
+ mutex_unlock(&rtac_voice_apr_mutex);
+ return bytes_returned;
+}
+
+
+
+static long rtac_ioctl(struct file *f,
+ unsigned int cmd, unsigned long arg)
+{
+ s32 result = 0;
+ pr_debug("%s\n", __func__);
+
+ if (arg == 0) {
+ pr_err("%s: No data sent to driver!\n", __func__);
+ result = -EFAULT;
+ goto done;
+ }
+
+ switch (cmd) {
+ case AUDIO_GET_RTAC_ADM_INFO:
+ if (copy_to_user((void *)arg, &rtac_adm_data,
+ sizeof(rtac_adm_data)))
+ pr_err("%s: Could not copy to userspace!\n", __func__);
+ else
+ result = sizeof(rtac_adm_data);
+ break;
+ case AUDIO_GET_RTAC_VOICE_INFO:
+ if (copy_to_user((void *)arg, &rtac_voice_data,
+ sizeof(rtac_voice_data)))
+ pr_err("%s: Could not copy to userspace!\n", __func__);
+ else
+ result = sizeof(rtac_voice_data);
+ break;
+ case AUDIO_GET_RTAC_ADM_CAL:
+ result = send_adm_apr((void *)arg, ADM_CMD_GET_PP_PARAMS_V5);
+ break;
+ case AUDIO_SET_RTAC_ADM_CAL:
+ result = send_adm_apr((void *)arg, ADM_CMD_SET_PP_PARAMS_V5);
+ break;
+ case AUDIO_GET_RTAC_ASM_CAL:
+ result = send_rtac_asm_apr((void *)arg,
+ ASM_STREAM_CMD_GET_PP_PARAMS_V2);
+ break;
+ case AUDIO_SET_RTAC_ASM_CAL:
+ result = send_rtac_asm_apr((void *)arg,
+ ASM_STREAM_CMD_SET_PP_PARAMS_V2);
+ break;
+ case AUDIO_GET_RTAC_CVS_CAL:
+ result = send_voice_apr(RTAC_CVS, (void *)arg,
+ VOICE_CMD_GET_PARAM);
+ break;
+ case AUDIO_SET_RTAC_CVS_CAL:
+ result = send_voice_apr(RTAC_CVS, (void *)arg,
+ VOICE_CMD_SET_PARAM);
+ break;
+ case AUDIO_GET_RTAC_CVP_CAL:
+ result = send_voice_apr(RTAC_CVP, (void *)arg,
+ VOICE_CMD_GET_PARAM);
+ break;
+ case AUDIO_SET_RTAC_CVP_CAL:
+ result = send_voice_apr(RTAC_CVP, (void *)arg,
+ VOICE_CMD_SET_PARAM);
+ break;
+ default:
+ pr_err("%s: Invalid IOCTL, command = %d!\n",
+ __func__, cmd);
+ }
+done:
+ return result;
+}
+
+
+static const struct file_operations rtac_fops = {
+ .owner = THIS_MODULE,
+ .open = rtac_open,
+ .release = rtac_release,
+ .unlocked_ioctl = rtac_ioctl,
+};
+
+struct miscdevice rtac_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "msm_rtac",
+ .fops = &rtac_fops,
+};
+
+static int __init rtac_init(void)
+{
+ int i = 0;
+ pr_debug("%s\n", __func__);
+
+ /* ADM */
+ memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
+ rtac_adm_apr_data.apr_handle = NULL;
+ atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+ init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
+ mutex_init(&rtac_adm_mutex);
+ mutex_init(&rtac_adm_apr_mutex);
+
+ rtac_adm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+ if (rtac_adm_buffer == NULL) {
+ pr_err("%s: Could not allocate payload of size = %d\n",
+ __func__, RTAC_BUF_SIZE);
+ goto nomem;
+ }
+
+ /* ASM */
+ for (i = 0; i < SESSION_MAX+1; i++) {
+ rtac_asm_apr_data[i].apr_handle = NULL;
+ atomic_set(&rtac_asm_apr_data[i].cmd_state, 0);
+ init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait);
+ }
+ mutex_init(&rtac_asm_apr_mutex);
+
+ rtac_asm_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+ if (rtac_asm_buffer == NULL) {
+ pr_err("%s: Could not allocate payload of size = %d\n",
+ __func__, RTAC_BUF_SIZE);
+ kzfree(rtac_adm_buffer);
+ goto nomem;
+ }
+
+ /* Voice */
+ memset(&rtac_voice_data, 0, sizeof(rtac_voice_data));
+ for (i = 0; i < RTAC_VOICE_MODES; i++) {
+ rtac_voice_apr_data[i].apr_handle = NULL;
+ atomic_set(&rtac_voice_apr_data[i].cmd_state, 0);
+ init_waitqueue_head(&rtac_voice_apr_data[i].cmd_wait);
+ }
+ mutex_init(&rtac_voice_mutex);
+ mutex_init(&rtac_voice_apr_mutex);
+
+ rtac_voice_buffer = kzalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+ if (rtac_voice_buffer == NULL) {
+ pr_err("%s: Could not allocate payload of size = %d\n",
+ __func__, RTAC_BUF_SIZE);
+ kzfree(rtac_adm_buffer);
+ kzfree(rtac_asm_buffer);
+ goto nomem;
+ }
+
+ return misc_register(&rtac_misc);
+nomem:
+ return -ENOMEM;
+}
+
+module_init(rtac_init);
+
+MODULE_DESCRIPTION("MSM 8x60 Real-Time Audio Calibration driver");
+MODULE_LICENSE("GPL v2");
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
index f75af16..0b38ec2 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
@@ -220,7 +220,7 @@
goto err_clk;
}
- clk_enable(drv->ecodec_clk);
+ clk_prepare_enable(drv->ecodec_clk);
clk_reset(drv->ecodec_clk, CLK_RESET_DEASSERT);
@@ -260,7 +260,7 @@
pr_info("%s: closing all devices\n", __func__);
- clk_disable(drv->ecodec_clk);
+ clk_disable_unprepare(drv->ecodec_clk);
aux_pcm_gpios_free();
afe_close(PCM_RX);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
index 41ef88c..e266d7a 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
@@ -325,7 +325,7 @@
goto error_invalid_freq;
}
- clk_enable(drv->rx_osrclk);
+ clk_prepare_enable(drv->rx_osrclk);
drv->rx_bitclk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
if (IS_ERR(drv->rx_bitclk))
pr_err("%s clock Error\n", __func__);
@@ -345,7 +345,7 @@
pr_err("ERROR setting m clock1\n");
goto error_adie;
}
- clk_enable(drv->rx_bitclk);
+ clk_prepare_enable(drv->rx_bitclk);
if (icodec->data->voltage_on)
icodec->data->voltage_on();
@@ -412,7 +412,7 @@
error_pamp:
error_adie:
- clk_disable(drv->rx_osrclk);
+ clk_disable_unprepare(drv->rx_osrclk);
error_invalid_freq:
pr_err("%s: encounter error\n", __func__);
@@ -455,7 +455,7 @@
goto error_invalid_freq;
}
- clk_enable(drv->tx_osrclk);
+ clk_prepare_enable(drv->tx_osrclk);
drv->tx_bitclk = clk_get_sys(NULL, "i2s_mic_bit_clk");
if (IS_ERR(drv->tx_bitclk))
pr_err("%s clock Error\n", __func__);
@@ -471,7 +471,7 @@
} else
trc = clk_set_rate(drv->tx_bitclk, 8);
- clk_enable(drv->tx_bitclk);
+ clk_prepare_enable(drv->tx_bitclk);
/* Enable ADIE */
trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
@@ -580,8 +580,8 @@
if (icodec->data->voltage_off)
icodec->data->voltage_off();
- clk_disable(drv->rx_bitclk);
- clk_disable(drv->rx_osrclk);
+ clk_disable_unprepare(drv->rx_bitclk);
+ clk_disable_unprepare(drv->rx_osrclk);
msm_snddev_rx_mclk_free();
@@ -611,8 +611,8 @@
afe_close(icodec->data->copp_id);
- clk_disable(drv->tx_bitclk);
- clk_disable(drv->tx_osrclk);
+ clk_disable_unprepare(drv->tx_bitclk);
+ clk_disable_unprepare(drv->tx_osrclk);
msm_snddev_tx_mclk_free();
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
index 75a7411..4cf18b3 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
@@ -194,7 +194,7 @@
pr_err("ERROR setting osr clock\n");
return -ENODEV;
}
- clk_enable(drv->tx_osrclk);
+ clk_prepare_enable(drv->tx_osrclk);
/* set up bit clk */
drv->tx_bitclk = clk_get_sys(NULL, "mi2s_bit_clk");
@@ -204,10 +204,10 @@
rc = clk_set_rate(drv->tx_bitclk, 8);
if (IS_ERR_VALUE(rc)) {
pr_err("ERROR setting bit clock\n");
- clk_disable(drv->tx_osrclk);
+ clk_disable_unprepare(drv->tx_osrclk);
return -ENODEV;
}
- clk_enable(drv->tx_bitclk);
+ clk_prepare_enable(drv->tx_bitclk);
afe_config.mi2s.bitwidth = 16;
@@ -336,8 +336,8 @@
error_invalid_data:
- clk_disable(drv->tx_bitclk);
- clk_disable(drv->tx_osrclk);
+ clk_disable_unprepare(drv->tx_bitclk);
+ clk_disable_unprepare(drv->tx_osrclk);
return -EINVAL;
}
@@ -358,8 +358,8 @@
return -EIO;
}
afe_close(snddev_mi2s_data->copp_id);
- clk_disable(mi2s_drv->tx_bitclk);
- clk_disable(mi2s_drv->tx_osrclk);
+ clk_disable_unprepare(mi2s_drv->tx_bitclk);
+ clk_disable_unprepare(mi2s_drv->tx_osrclk);
mi2s_gpios_free();
diff --git a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
index 614339b..a8773ea 100644
--- a/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
+++ b/arch/arm/mach-msm/qdsp6v2/ultrasound/usf.c
@@ -27,7 +27,8 @@
#include "usfcdev.h"
/* The driver version*/
-#define DRV_VERSION "1.3.1"
+#define DRV_VERSION "1.4.0"
+#define USF_VERSION_ID 0x0140
/* Standard timeout in the asynchronous ops */
#define USF_TIMEOUT_JIFFIES (1*HZ) /* 1 sec */
@@ -108,8 +109,8 @@
uint16_t dev_ind;
/* Event types, supported by device */
uint16_t event_types;
- /* The device is "input" module registered client */
- struct input_dev *input_if;
+ /* The input devices are "input" module registered clients */
+ struct input_dev *input_ifs[USF_MAX_EVENT_IND];
/* The event source */
int event_src;
/* Bitmap of types of events, conflicting to USF's ones */
@@ -118,6 +119,23 @@
uint16_t conflicting_event_filters;
};
+struct usf_input_dev_type {
+ /* Input event type, supported by the input device */
+ uint16_t event_type;
+ /* Input device name */
+ const char *input_dev_name;
+ /* Input device registration function */
+ int (*prepare_dev)(uint16_t, struct usf_type *,
+ struct us_input_info_type *,
+ const char *);
+ /* Input event notification function */
+ void (*notify_event)(struct usf_type *,
+ uint16_t,
+ struct usf_event_type *
+ );
+};
+
+
/* The MAX number of the supported devices */
#define MAX_DEVS_NUMBER 1
@@ -131,9 +149,197 @@
/* The opened devices container */
static int s_opened_devs[MAX_DEVS_NUMBER];
-#define USF_NAME_PREFIX "USF_"
+#define USF_NAME_PREFIX "usf_"
#define USF_NAME_PREFIX_SIZE 4
+
+static struct input_dev *allocate_dev(uint16_t ind, const char *name)
+{
+ struct input_dev *in_dev = input_allocate_device();
+
+ if (in_dev == NULL) {
+ pr_err("%s: input_allocate_device() failed\n", __func__);
+ } else {
+ /* Common part configuration */
+ in_dev->name = name;
+ in_dev->phys = NULL;
+ in_dev->id.bustype = BUS_HOST;
+ in_dev->id.vendor = 0x0001;
+ in_dev->id.product = 0x0001;
+ in_dev->id.version = USF_VERSION_ID;
+ }
+ return in_dev;
+}
+
+static int prepare_tsc_input_device(uint16_t ind,
+ struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ in_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(in_dev, ABS_X,
+ input_info->tsc_x_dim[MIN_IND],
+ input_info->tsc_x_dim[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_Y,
+ input_info->tsc_y_dim[MIN_IND],
+ input_info->tsc_y_dim[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_DISTANCE,
+ input_info->tsc_z_dim[MIN_IND],
+ input_info->tsc_z_dim[MAX_IND],
+ 0, 0);
+
+ input_set_abs_params(in_dev, ABS_PRESSURE,
+ input_info->tsc_pressure[MIN_IND],
+ input_info->tsc_pressure[MAX_IND],
+ 0, 0);
+
+ input_set_abs_params(in_dev, ABS_TILT_X,
+ input_info->tsc_x_tilt[MIN_IND],
+ input_info->tsc_x_tilt[MAX_IND],
+ 0, 0);
+ input_set_abs_params(in_dev, ABS_TILT_Y,
+ input_info->tsc_y_tilt[MIN_IND],
+ input_info->tsc_y_tilt[MAX_IND],
+ 0, 0);
+
+ return 0;
+}
+
+static int prepare_mouse_input_device(uint16_t ind, struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
+
+ in_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
+ BIT_MASK(BTN_RIGHT) |
+ BIT_MASK(BTN_MIDDLE);
+ in_dev->relbit[0] = BIT_MASK(REL_X) |
+ BIT_MASK(REL_Y) |
+ BIT_MASK(REL_Z);
+
+ return 0;
+}
+
+static int prepare_keyboard_input_device(
+ uint16_t ind,
+ struct usf_type *usf_info,
+ struct us_input_info_type *input_info,
+ const char *name)
+{
+ struct input_dev *in_dev = allocate_dev(ind, name);
+
+ if (in_dev == NULL)
+ return -ENOMEM;
+
+ usf_info->input_ifs[ind] = in_dev;
+ in_dev->evbit[0] |= BIT_MASK(EV_KEY);
+ /* All keys are permitted */
+ memset(in_dev->keybit, 0xff, sizeof(in_dev->keybit));
+
+ return 0;
+}
+
+static void notify_tsc_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct point_event_type *pe = &(event->event_data.point_event);
+
+ input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
+ input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
+ input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
+
+ input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
+ input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
+
+ input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
+ input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
+
+ if (usf_info->event_src)
+ input_report_key(input_if, usf_info->event_src, 1);
+
+ input_sync(input_if);
+
+ pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
+ __func__,
+ pe->coordinates[X_IND],
+ pe->coordinates[Y_IND],
+ pe->coordinates[Z_IND],
+ pe->inclinations[X_IND],
+ pe->inclinations[Y_IND],
+ pe->pressure);
+}
+
+static void notify_mouse_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct mouse_event_type *me = &(event->event_data.mouse_event);
+
+ input_report_rel(input_if, REL_X, me->rels[X_IND]);
+ input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
+ input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
+
+ input_report_key(input_if, BTN_LEFT,
+ me->buttons_states & USF_BUTTON_LEFT_MASK);
+ input_report_key(input_if, BTN_MIDDLE,
+ me->buttons_states & USF_BUTTON_MIDDLE_MASK);
+ input_report_key(input_if, BTN_RIGHT,
+ me->buttons_states & USF_BUTTON_RIGHT_MASK);
+
+ input_sync(input_if);
+
+ pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
+ __func__, me->rels[X_IND],
+ me->rels[Y_IND], me->buttons_states);
+}
+
+static void notify_key_event(struct usf_type *usf_info,
+ uint16_t if_ind,
+ struct usf_event_type *event)
+{
+ struct input_dev *input_if = usf_info->input_ifs[if_ind];
+ struct key_event_type *ke = &(event->event_data.key_event);
+
+ input_report_key(input_if, ke->key, ke->key_state);
+ input_sync(input_if);
+ pr_debug("%s: key event: key[%d], state[%d]\n",
+ __func__,
+ ke->key,
+ ke->key_state);
+
+}
+
+static struct usf_input_dev_type s_usf_input_devs[] = {
+ {USF_TSC_EVENT, "usf_tsc",
+ prepare_tsc_input_device, notify_tsc_event},
+ {USF_TSC_PTR_EVENT, "usf_tsc_ptr",
+ prepare_tsc_input_device, notify_tsc_event},
+ {USF_MOUSE_EVENT, "usf_mouse",
+ prepare_mouse_input_device, notify_mouse_event},
+ {USF_KEYBOARD_EVENT, "usf_kb",
+ prepare_keyboard_input_device, notify_key_event},
+};
+
static void usf_rx_cb(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
@@ -386,8 +592,8 @@
struct us_input_info_type *input_info)
{
int rc = 0;
- struct input_dev *input_dev = NULL;
bool ret = true;
+ uint16_t ind = 0;
if ((usf_info == NULL) ||
(input_info == NULL) ||
@@ -396,194 +602,75 @@
return -EINVAL;
}
- if (usf_info->input_if != NULL) {
- pr_err("%s: input_if is already allocated\n", __func__);
- return -EFAULT;
- }
-
- input_dev = input_allocate_device();
- if (input_dev == NULL) {
- pr_err("%s: input_allocate_device() failed\n", __func__);
- return -ENOMEM;
- }
-
- /* Common part configuration */
- input_dev->name = (const char *)(usf_info->usf_tx.client_name);
- input_dev->phys = NULL;
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x0001;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0001;
-
- if (input_info->event_types & USF_TSC_EVENT) {
- /* TSC part configuration */
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
- input_set_abs_params(input_dev, ABS_X,
- input_info->tsc_x_dim[MIN_IND],
- input_info->tsc_x_dim[MAX_IND],
- 0, 0);
- input_set_abs_params(input_dev, ABS_Y,
- input_info->tsc_y_dim[MIN_IND],
- input_info->tsc_y_dim[MAX_IND],
- 0, 0);
- input_set_abs_params(input_dev, ABS_DISTANCE,
- input_info->tsc_z_dim[MIN_IND],
- input_info->tsc_z_dim[MAX_IND],
- 0, 0);
-
- input_set_abs_params(input_dev, ABS_PRESSURE,
- input_info->tsc_pressure[MIN_IND],
- input_info->tsc_pressure[MAX_IND], 0, 0);
-
- input_set_abs_params(input_dev, ABS_TILT_X,
- input_info->tsc_x_tilt[MIN_IND],
- input_info->tsc_x_tilt[MAX_IND],
- 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_Y,
- input_info->tsc_y_tilt[MIN_IND],
- input_info->tsc_y_tilt[MAX_IND],
- 0, 0);
- }
-
- if (input_info->event_types & USF_MOUSE_EVENT) {
- /* Mouse part configuration */
- input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
-
- input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
- BIT_MASK(BTN_RIGHT) |
- BIT_MASK(BTN_MIDDLE);
- input_dev->relbit[0] = BIT_MASK(REL_X) |
- BIT_MASK(REL_Y) |
- BIT_MASK(REL_Z);
- }
-
- if (input_info->event_types & USF_KEYBOARD_EVENT) {
- /* Keyboard part configuration */
- input_dev->evbit[0] |= BIT_MASK(EV_KEY);
-
- /* All keys are permitted */
- memset(input_dev->keybit, 0xff, sizeof(input_dev->keybit));
- }
-
if (input_info->event_src < ARRAY_SIZE(s_event_src_map))
- usf_info->event_src = s_event_src_map[input_info->event_src];
+ usf_info->event_src =
+ s_event_src_map[input_info->event_src];
else
usf_info->event_src = 0;
- if (usf_info->event_src)
- input_set_capability(input_dev, EV_KEY, usf_info->event_src);
+ for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+ if (usf_info->input_ifs[ind] != NULL) {
+ pr_err("%s: input_if[%d] is already allocated\n",
+ __func__, ind);
+ return -EFAULT;
+ }
+ if ((input_info->event_types &
+ s_usf_input_devs[ind].event_type) &&
+ s_usf_input_devs[ind].prepare_dev) {
+ rc = (*s_usf_input_devs[ind].prepare_dev)(
+ ind,
+ usf_info,
+ input_info,
+ s_usf_input_devs[ind].input_dev_name);
+ if (rc)
+ return rc;
- rc = input_register_device(input_dev);
- if (rc) {
- pr_err("%s: input_register_device() failed; rc=%d\n",
- __func__, rc);
- input_free_device(input_dev);
- } else {
- usf_info->input_if = input_dev;
- usf_info->event_types = input_info->event_types;
- pr_debug("%s: input device[%s] was registered\n",
- __func__, input_dev->name);
- ret = usf_register_conflicting_events(
- input_info->conflicting_event_types);
- if (ret)
- usf_info->conflicting_event_types =
- input_info->conflicting_event_types;
- }
- return rc;
+ if (usf_info->event_src)
+ input_set_capability(usf_info->input_ifs[ind],
+ EV_KEY,
+ usf_info->event_src);
+
+ rc = input_register_device(usf_info->input_ifs[ind]);
+ if (rc) {
+ pr_err("%s: input_reg_dev() failed; rc=%d\n",
+ __func__, rc);
+ input_free_device(usf_info->input_ifs[ind]);
+ usf_info->input_ifs[ind] = NULL;
+ } else {
+ usf_info->event_types |=
+ s_usf_input_devs[ind].event_type;
+ pr_debug("%s: input device[%s] was registered\n",
+ __func__,
+ s_usf_input_devs[ind].input_dev_name);
+ }
+ } /* supported event */
+ } /* event types loop */
+
+ ret = usf_register_conflicting_events(
+ input_info->conflicting_event_types);
+ if (ret)
+ usf_info->conflicting_event_types =
+ input_info->conflicting_event_types;
+
+ return 0;
}
-static void notify_tsc_event(struct usf_type *usf_info,
- struct point_event_type *pe)
-{
- struct input_dev *input_if = usf_info->input_if;
-
- input_report_abs(input_if, ABS_X, pe->coordinates[X_IND]);
- input_report_abs(input_if, ABS_Y, pe->coordinates[Y_IND]);
- input_report_abs(input_if, ABS_DISTANCE, pe->coordinates[Z_IND]);
-
- input_report_abs(input_if, ABS_TILT_X, pe->inclinations[X_IND]);
- input_report_abs(input_if, ABS_TILT_Y, pe->inclinations[Y_IND]);
-
- input_report_abs(input_if, ABS_PRESSURE, pe->pressure);
- input_report_key(input_if, BTN_TOUCH, !!(pe->pressure));
-
- if (usf_info->event_src)
- input_report_key(input_if, usf_info->event_src, 1);
-
- input_sync(input_if);
-
- pr_debug("%s: TSC event: xyz[%d;%d;%d], incl[%d;%d], pressure[%d]\n",
- __func__,
- pe->coordinates[X_IND],
- pe->coordinates[Y_IND],
- pe->coordinates[Z_IND],
- pe->inclinations[X_IND],
- pe->inclinations[Y_IND],
- pe->pressure);
-}
-
-static void notify_mouse_event(struct input_dev *input_if,
- struct mouse_event_type *me)
-{
- if (me == NULL) {
- pr_err("%s: mouse event is NULL\n", __func__);
- return;
- }
-
- input_report_rel(input_if, REL_X, me->rels[X_IND]);
- input_report_rel(input_if, REL_Y, me->rels[Y_IND]);
- input_report_rel(input_if, REL_Z, me->rels[Z_IND]);
-
- input_report_key(input_if, BTN_LEFT,
- me->buttons_states & USF_BUTTON_LEFT_MASK);
- input_report_key(input_if, BTN_MIDDLE,
- me->buttons_states & USF_BUTTON_MIDDLE_MASK);
- input_report_key(input_if, BTN_RIGHT,
- me->buttons_states & USF_BUTTON_RIGHT_MASK);
-
- input_sync(input_if);
-
- pr_debug("%s: mouse event: dx[%d], dy[%d], buttons_states[%d]\n",
- __func__, me->rels[X_IND],
- me->rels[Y_IND], me->buttons_states);
-}
-
-static void notify_key_event(struct input_dev *input_if,
- struct key_event_type *ke)
-{
- if (ke == NULL) {
- pr_err("%s: key event is NULL\n", __func__);
- return;
- }
-
- input_report_key(input_if, ke->key, ke->key_state);
- input_sync(input_if);
- pr_debug("%s: key event: key[%d], state[%d]\n",
- __func__,
- ke->key,
- ke->key_state);
-
-}
static void handle_input_event(struct usf_type *usf_info,
uint16_t event_counter,
struct usf_event_type *event)
{
- struct input_dev *input_if = NULL;
uint16_t ind = 0;
uint16_t events_num = 0;
struct usf_event_type usf_events[USF_EVENTS_PORTION_SIZE];
int rc = 0;
- if ((usf_info == NULL) || (usf_info->input_if == NULL) ||
+ if ((usf_info == NULL) ||
(event == NULL) || (!event_counter)) {
return;
}
- input_if = usf_info->input_if;
-
while (event_counter > 0) {
if (event_counter > USF_EVENTS_PORTION_SIZE) {
events_num = USF_EVENTS_PORTION_SIZE;
@@ -602,26 +689,17 @@
}
for (ind = 0; ind < events_num; ++ind) {
struct usf_event_type *p_event = &usf_events[ind];
- if (p_event->event_type & USF_TSC_EVENT) {
- struct point_event_type *pe =
- &(p_event->event_data.point_event);
- if (pe->coordinates_type ==
- USF_PIX_COORDINATE)
- notify_tsc_event(usf_info, pe);
- else
- pr_debug("%s: wrong coord type: %d",
- __func__,
- pe->coordinates_type);
- continue;
- }
- if (p_event->event_type & USF_MOUSE_EVENT) {
- notify_mouse_event(input_if,
- &(p_event->event_data.mouse_event));
- continue;
- }
- if (p_event->event_type & USF_KEYBOARD_EVENT)
- notify_key_event(input_if,
- &(p_event->event_data.key_event));
+ uint16_t if_ind = p_event->event_type_ind;
+
+ if ((if_ind >= USF_MAX_EVENT_IND) ||
+ (usf_info->input_ifs[if_ind] == NULL))
+ continue; /* event isn't supported */
+
+ if (s_usf_input_devs[if_ind].notify_event)
+ (*s_usf_input_devs[if_ind].notify_event)(
+ usf_info,
+ if_ind,
+ p_event);
} /* loop in the portion */
} /* all events loop */
}
@@ -1051,13 +1129,20 @@
static void usf_release_input(struct usf_type *usf)
{
- if (usf->input_if != NULL) {
+ uint16_t ind = 0;
+
+ for (ind = 0; ind < USF_MAX_EVENT_IND; ++ind) {
+ if (usf->input_ifs[ind] == NULL)
+ continue;
+
usf_unregister_conflicting_events(
usf->conflicting_event_types);
usf->conflicting_event_types = 0;
- input_unregister_device(usf->input_if);
- usf->input_if = NULL;
- pr_debug("%s input_unregister_device\n", __func__);
+ input_unregister_device(usf->input_ifs[ind]);
+ usf->input_ifs[ind] = NULL;
+ pr_debug("%s input_unregister_device[%s]\n",
+ __func__,
+ s_usf_input_devs[ind].input_dev_name);
}
} /* usf_release_input */
diff --git a/arch/arm/mach-msm/rpm-regulator-9615.c b/arch/arm/mach-msm/rpm-regulator-9615.c
index 23c0ee3..82ac3d8 100644
--- a/arch/arm/mach-msm/rpm-regulator-9615.c
+++ b/arch/arm/mach-msm/rpm-regulator-9615.c
@@ -50,6 +50,11 @@
.hpm = REQUEST_MEMBER(0, 0x00000C00, 10),
};
+static struct rpm_vreg_parts corner_parts = {
+ .request_len = 1,
+ .uV = REQUEST_MEMBER(0, 0x00000003, 0),
+};
+
/* Physically available PMIC regulator voltage setpoint ranges */
static struct vreg_range pldo_ranges[] = {
VOLTAGE_RANGE( 750000, 1487500, 12500),
@@ -72,16 +77,22 @@
VOLTAGE_RANGE(1500000, 3075000, 25000),
};
+static struct vreg_range corner_ranges[] = {
+ VOLTAGE_RANGE(RPM_VREG_CORNER_NONE, RPM_VREG_CORNER_HIGH, 1),
+};
+
static struct vreg_set_points pldo_set_points = SET_POINTS(pldo_ranges);
static struct vreg_set_points nldo_set_points = SET_POINTS(nldo_ranges);
static struct vreg_set_points nldo1200_set_points = SET_POINTS(nldo1200_ranges);
static struct vreg_set_points smps_set_points = SET_POINTS(smps_ranges);
+static struct vreg_set_points corner_set_points = SET_POINTS(corner_ranges);
static struct vreg_set_points *all_set_points[] = {
&pldo_set_points,
&nldo_set_points,
&nldo1200_set_points,
&smps_set_points,
+ &corner_set_points,
};
#define LDO(_id, _name, _name_pc, _ranges, _hpm_min_load) \
@@ -127,6 +138,19 @@
.rdesc_pc.name = _name_pc, \
}
+#define CORNER(_id, _rpm_id, _name, _ranges) \
+ [RPM_VREG_ID_PM8018_##_id] = { \
+ .req = { \
+ [0] = { .id = MSM_RPM_ID_##_rpm_id, }, \
+ [1] = { .id = -1, }, \
+ }, \
+ .type = RPM_REGULATOR_TYPE_CORNER, \
+ .set_points = &_ranges##_set_points, \
+ .part = &corner_parts, \
+ .id = RPM_VREG_ID_PM8018_##_id, \
+ .rdesc.name = _name, \
+ }
+
static struct vreg vregs[] = {
LDO(L2, "8018_l2", "8018_l2_pc", pldo, LDO_50),
LDO(L3, "8018_l3", "8018_l3_pc", pldo, LDO_50),
@@ -149,6 +173,8 @@
SMPS(S5, "8018_s5", "8018_s5_pc", smps, SMPS_1500),
LVS(LVS1, "8018_lvs1", "8018_lvs1_pc"),
+
+ CORNER(VDD_DIG_CORNER, VOLTAGE_CORNER, "vdd_dig_corner", corner),
};
static const char *pin_control_label[] = {
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index b892d05..152b6e5 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -762,10 +762,11 @@
struct rpm_vreg *rpm_vreg;
regulator = regulator_get(dev, supply);
- if (regulator == NULL) {
- pr_err("could not find regulator for: dev=%s, id=%s\n",
- (dev ? dev_name(dev) : ""), (supply ? supply : ""));
- return ERR_PTR(-ENODEV);
+ if (IS_ERR(regulator)) {
+ pr_err("could not find regulator for: dev=%s, supply=%s, rc=%ld\n",
+ (dev ? dev_name(dev) : ""), (supply ? supply : ""),
+ PTR_ERR(regulator));
+ return ERR_CAST(regulator);
}
framework_reg = regulator_get_drvdata(regulator);
@@ -818,7 +819,7 @@
static int rpm_regulator_check_input(struct rpm_regulator *regulator)
{
- if (regulator == NULL || regulator->rpm_vreg == NULL) {
+ if (IS_ERR_OR_NULL(regulator) || regulator->rpm_vreg == NULL) {
pr_err("invalid rpm_regulator pointer\n");
return -EINVAL;
}
@@ -1142,7 +1143,7 @@
reg->set_active = !!(val & RPM_SET_CONFIG_ACTIVE);
reg->set_sleep = !!(val & RPM_SET_CONFIG_SLEEP);
- init_data = of_get_regulator_init_data(dev);
+ init_data = of_get_regulator_init_data(dev, node);
if (init_data == NULL) {
dev_err(dev, "%s: unable to allocate memory\n", __func__);
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/rpm_resources.h b/arch/arm/mach-msm/rpm_resources.h
index d594405..46d6d94 100644
--- a/arch/arm/mach-msm/rpm_resources.h
+++ b/arch/arm/mach-msm/rpm_resources.h
@@ -102,6 +102,8 @@
unsigned int rpmrs_target_id[MSM_RPMRS_ID_LAST];
};
+#if defined(CONFIG_MSM_RPM)
+
int msm_rpmrs_set(int ctx, struct msm_rpm_iv_pair *req, int count);
int msm_rpmrs_set_noirq(int ctx, struct msm_rpm_iv_pair *req, int count);
int msm_rpmrs_set_bits_noirq(int ctx, struct msm_rpm_iv_pair *req, int count,
@@ -139,4 +141,74 @@
void msm_rpmrs_show_resources(void);
int msm_rpmrs_levels_init(struct msm_rpmrs_platform_data *data);
+#else
+
+static inline int msm_rpmrs_set(int ctx, struct msm_rpm_iv_pair *req,
+ int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpmrs_set_noirq(int ctx, struct msm_rpm_iv_pair *req,
+ int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpmrs_set_bits_noirq(int ctx, struct msm_rpm_iv_pair *req,
+ int count, int *mask)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpmrs_set_nosleep(
+ int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpmrs_clear(int ctx, struct msm_rpm_iv_pair *req,
+ int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpmrs_clear_noirq(int ctx, struct msm_rpm_iv_pair *req,
+ int count)
+{
+ return -ENODEV;
+}
+
+static inline int msm_rpmrs_clear_nosleep(
+ int ctx, struct msm_rpm_iv_pair *req, int count)
+{
+ return -ENODEV;
+}
+
+static inline struct msm_rpmrs_limits *msm_rpmrs_lowest_limits(
+ bool from_idle, enum msm_pm_sleep_mode sleep_mode, uint32_t latency_us,
+ uint32_t sleep_us)
+{
+ return NULL;
+}
+
+static inline int msm_rpmrs_enter_sleep(uint32_t sclk_count,
+ struct msm_rpmrs_limits *limits, bool from_idle, bool notify_rpm)
+{
+ return -ENODEV;
+}
+
+static inline void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm, bool collapsed)
+{
+ return;
+}
+
+static inline int msm_rpmrs_levels_init(struct msm_rpmrs_platform_data *data)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_MSM_RPM */
+
#endif /* __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H */
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index b9cba8c..8d567f8 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -76,6 +76,7 @@
struct wake_lock pa_wake_lock; /* Packet Arrival Wake lock*/
struct work_struct packet_arrival_work;
struct spinlock pa_spinlock;
+ int wakelock_locked;
} *smd_pkt_devp[NUM_SMD_PKT_PORTS];
struct class *smd_pkt_classp;
@@ -233,16 +234,19 @@
static void packet_arrival_worker(struct work_struct *work)
{
struct smd_pkt_dev *smd_pkt_devp;
+ unsigned long flags;
smd_pkt_devp = container_of(work, struct smd_pkt_dev,
packet_arrival_work);
mutex_lock(&smd_pkt_devp->ch_lock);
- if (smd_pkt_devp->ch) {
+ spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
+ if (smd_pkt_devp->ch && smd_pkt_devp->wakelock_locked) {
D_READ("%s locking smd_pkt_dev id:%d wakelock\n",
__func__, smd_pkt_devp->i);
wake_lock_timeout(&smd_pkt_devp->pa_wake_lock,
WAKELOCK_TIMEOUT);
}
+ spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
mutex_unlock(&smd_pkt_devp->ch_lock);
}
@@ -398,6 +402,7 @@
if (smd_pkt_devp->poll_mode &&
!smd_cur_packet_size(smd_pkt_devp->ch)) {
wake_unlock(&smd_pkt_devp->pa_wake_lock);
+ smd_pkt_devp->wakelock_locked = 0;
smd_pkt_devp->poll_mode = 0;
D_READ("%s unlocked smd_pkt_dev id:%d wakelock\n",
__func__, smd_pkt_devp->i);
@@ -570,10 +575,11 @@
}
/* here we have a packet of size sz ready */
- wake_up(&smd_pkt_devp->ch_read_wait_queue);
spin_lock_irqsave(&smd_pkt_devp->pa_spinlock, flags);
wake_lock(&smd_pkt_devp->pa_wake_lock);
+ smd_pkt_devp->wakelock_locked = 1;
spin_unlock_irqrestore(&smd_pkt_devp->pa_spinlock, flags);
+ wake_up(&smd_pkt_devp->ch_read_wait_queue);
schedule_work(&smd_pkt_devp->packet_arrival_work);
D_READ("%s: wake_up smd_pkt_dev id:%d\n", __func__, smd_pkt_devp->i);
}
@@ -907,6 +913,7 @@
smd_pkt_devp->has_reset = 0;
smd_pkt_devp->do_reset_notification = 0;
+ smd_pkt_devp->wakelock_locked = 0;
wake_lock_destroy(&smd_pkt_devp->pa_wake_lock);
D_STATUS("Finished %s on smd_pkt_dev id:%d\n",
__func__, smd_pkt_devp->i);
@@ -962,6 +969,7 @@
init_waitqueue_head(&smd_pkt_devp[i]->ch_write_wait_queue);
smd_pkt_devp[i]->is_open = 0;
smd_pkt_devp[i]->poll_mode = 0;
+ smd_pkt_devp[i]->wakelock_locked = 0;
init_waitqueue_head(&smd_pkt_devp[i]->ch_opened_wait_queue);
spin_lock_init(&smd_pkt_devp[i]->pa_spinlock);
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index a77efe0..6e81be6 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -238,7 +238,7 @@
}
#endif
-static int __init msm_spm_dev_probe(struct platform_device *pdev)
+static int __devinit msm_spm_dev_probe(struct platform_device *pdev)
{
int ret = 0;
int cpu = 0;
@@ -282,14 +282,22 @@
uint32_t notify_rpm;
};
- struct mode_of mode_of_data[] = {
- {"qcom,spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
- {"qcom,spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
- {"qcom,spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
- {"qcom,spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
+ struct mode_of of_cpu_modes[] = {
+ {"qcom,saw2-spm-cmd-wfi", MSM_SPM_MODE_CLOCK_GATING, 0},
+ {"qcom,saw2-spm-cmd-ret", MSM_SPM_MODE_POWER_RETENTION, 0},
+ {"qcom,saw2-spm-cmd-spc", MSM_SPM_MODE_POWER_COLLAPSE, 0},
+ {"qcom,saw2-spm-cmd-pc", MSM_SPM_MODE_POWER_COLLAPSE, 1},
};
- BUG_ON(ARRAY_SIZE(mode_of_data) > MSM_SPM_MODE_NR);
+ struct mode_of of_l2_modes[] = {
+ {"qcom,saw2-spm-cmd-ret", MSM_SPM_L2_MODE_RETENTION, 1},
+ {"qcom,saw2-spm-cmd-gdhs", MSM_SPM_L2_MODE_GDHS, 1},
+ {"qcom,saw2-spm-cmd-pc", MSM_SPM_L2_MODE_POWER_COLLAPSE, 1},
+ };
+
+ struct mode_of *mode_of_data;
+ int num_modes;
+
memset(&spm_data, 0, sizeof(struct msm_spm_platform_data));
memset(&modes, 0,
(MSM_SPM_MODE_NR - 2) * sizeof(struct msm_spm_seq_entry));
@@ -339,7 +347,22 @@
spm_data.reg_init_values[spm_of_data[i].id] = val;
}
- for (i = 0; i < ARRAY_SIZE(mode_of_data); i++) {
+ /*
+ * Device with id 0..NR_CPUS are SPM for apps cores
+ * Device with id 0xFFFF is for L2 SPM.
+ */
+ if (cpu >= 0 && cpu < num_possible_cpus()) {
+ mode_of_data = of_cpu_modes;
+ num_modes = ARRAY_SIZE(of_cpu_modes);
+ dev = &per_cpu(msm_cpu_spm_device, cpu);
+
+ } else {
+ mode_of_data = of_l2_modes;
+ num_modes = ARRAY_SIZE(of_l2_modes);
+ dev = &msm_spm_l2_device;
+ }
+
+ for (i = 0; i < num_modes; i++) {
key = mode_of_data[i].key;
modes[mode_count].cmd =
(uint8_t *)of_get_property(node, key, &len);
@@ -353,16 +376,8 @@
spm_data.modes = modes;
spm_data.num_modes = mode_count;
- /*
- * Device with id 0..NR_CPUS are SPM for apps cores
- * Device with id 0xFFFF is for L2 SPM.
- */
- if (cpu >= 0 && cpu < num_possible_cpus())
- dev = &per_cpu(msm_cpu_spm_device, cpu);
- else
- dev = &msm_spm_l2_device;
-
ret = msm_spm_dev_init(dev, &spm_data);
+
if (ret < 0)
pr_warn("%s():failed core-id:%u ret:%d\n", __func__, cpu, ret);
@@ -374,12 +389,12 @@
return -EFAULT;
}
-static __initdata struct of_device_id msm_spm_match_table[] = {
+static struct of_device_id msm_spm_match_table[] = {
{.compatible = "qcom,spm-v2"},
{},
};
-static __initdata struct platform_driver msm_spm_device_driver = {
+static struct platform_driver msm_spm_device_driver = {
.probe = msm_spm_dev_probe,
.driver = {
.name = "spm-v2",
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 90948ea..793ef7f 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.c
@@ -28,12 +28,9 @@
#include "ramdump.h"
#define MODULE_NAME "wcnss_8960"
+#define MAX_BUF_SIZE 0x51
-static void riva_smsm_cb_fn(struct work_struct *);
-static DECLARE_WORK(riva_smsm_cb_work, riva_smsm_cb_fn);
-static void riva_fatal_fn(struct work_struct *);
-static DECLARE_WORK(riva_fatal_work, riva_fatal_fn);
static struct delayed_work cancel_vote_work;
static void *riva_ramdump_dev;
@@ -41,51 +38,70 @@
static int ss_restart_inprogress;
static int enable_riva_ssr;
-static void riva_smsm_cb_fn(struct work_struct *work)
-{
- if (!enable_riva_ssr)
- panic(MODULE_NAME ": SMSM reset request received from Riva");
- else
- subsystem_restart("riva");
-}
-
static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
uint32_t new_state)
{
- if (!(new_state & SMSM_RESET))
- return;
+ char *smem_reset_reason;
+ char buffer[MAX_BUF_SIZE];
+ unsigned smem_reset_size;
+ unsigned size;
riva_crash = true;
- pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
+
+ pr_err("%s: smsm state changed\n", MODULE_NAME);
+
+ if (!(new_state & SMSM_RESET))
+ return;
if (ss_restart_inprogress) {
pr_err("%s: Ignoring smsm reset req, restart in progress\n",
MODULE_NAME);
return;
}
- ss_restart_inprogress = true;
- schedule_work(&riva_smsm_cb_work);
-}
-static void riva_fatal_fn(struct work_struct *work)
-{
if (!enable_riva_ssr)
- panic(MODULE_NAME ": Watchdog bite received from Riva");
- else
- subsystem_restart("riva");
+ panic(MODULE_NAME ": SMSM reset request received from Riva");
+
+ smem_reset_reason = smem_get_entry(SMEM_SSR_REASON_WCNSS0,
+ &smem_reset_size);
+
+ if (!smem_reset_reason || !smem_reset_size) {
+ pr_err("%s: wcnss subsystem failure reason: %s\n",
+ __func__, "(unknown, smem_get_entry failed)");
+ } else if (!smem_reset_reason[0]) {
+ pr_err("%s: wcnss subsystem failure reason: %s\n",
+ __func__, "(unknown, init string found)");
+ } else {
+ size = smem_reset_size < MAX_BUF_SIZE ? smem_reset_size :
+ (MAX_BUF_SIZE - 1);
+ memcpy(buffer, smem_reset_reason, size);
+ buffer[size] = '\0';
+ pr_err("%s: wcnss subsystem failure reason: %s\n",
+ __func__, buffer);
+ memset(smem_reset_reason, 0, smem_reset_size);
+ wmb();
+ }
+
+ ss_restart_inprogress = true;
+ subsystem_restart("riva");
}
static irqreturn_t riva_wdog_bite_irq_hdlr(int irq, void *dev_id)
{
- int ret;
+ riva_crash = true;
if (ss_restart_inprogress) {
pr_err("%s: Ignoring riva bite irq, restart in progress\n",
MODULE_NAME);
return IRQ_HANDLED;
}
+
+ if (!enable_riva_ssr)
+ panic(MODULE_NAME ": Watchdog bite received from Riva");
+
ss_restart_inprogress = true;
- ret = schedule_work(&riva_fatal_work);
+ subsystem_restart("riva");
+
return IRQ_HANDLED;
}
@@ -203,8 +219,8 @@
ret = smsm_state_cb_register(SMSM_WCNSS_STATE, SMSM_RESET,
smsm_state_cb_hdlr, 0);
if (ret < 0) {
- pr_err("%s: Unable to register smsm callback for Riva Reset!"
- " (%d)\n", MODULE_NAME, ret);
+ pr_err("%s: Unable to register smsm callback for Riva Reset! %d\n",
+ MODULE_NAME, ret);
goto out;
}
ret = request_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ,
@@ -212,8 +228,8 @@
"riva_wdog", NULL);
if (ret < 0) {
- pr_err("%s: Unable to register for Riva bite interrupt"
- " (%d)\n", MODULE_NAME, ret);
+ pr_err("%s: Unable to register for Riva bite interrupt (%d)\n",
+ MODULE_NAME, ret);
goto out;
}
ret = riva_restart_init();
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 4387287..e62af21 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/user.h>
+#include <linux/proc_fs.h>
#include <asm/cp15.h>
#include <asm/cputype.h>
@@ -87,6 +88,11 @@
}
/*
+ * Used for reporting emulation statistics via /proc
+ */
+static atomic64_t vfp_bounce_count = ATOMIC64_INIT(0);
+
+/*
* Per-thread VFP initialization.
*/
static void vfp_thread_flush(struct thread_info *thread)
@@ -337,6 +343,7 @@
u32 fpscr, orig_fpscr, fpsid, exceptions;
pr_debug("VFP: bounce: trigger %08x fpexc %08x\n", trigger, fpexc);
+ atomic64_inc(&vfp_bounce_count);
/*
* At this point, FPEXC can have the following configuration:
@@ -648,6 +655,26 @@
return NOTIFY_OK;
}
+#ifdef CONFIG_PROC_FS
+static int proc_read_status(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ char *p = page;
+ int len;
+
+ p += snprintf(p, PAGE_SIZE, "%llu\n", atomic64_read(&vfp_bounce_count));
+
+ len = (p - page) - off;
+ if (len < 0)
+ len = 0;
+
+ *eof = (len <= count) ? 1 : 0;
+ *start = page + off;
+
+ return len;
+}
+#endif
+
/*
* VFP support code initialisation.
*/
@@ -655,7 +682,9 @@
{
unsigned int vfpsid;
unsigned int cpu_arch = cpu_architecture();
-
+#ifdef CONFIG_PROC_FS
+ static struct proc_dir_entry *procfs_entry;
+#endif
if (cpu_arch >= CPU_ARCH_ARMv6)
on_each_cpu(vfp_enable, NULL, 1);
@@ -724,6 +753,16 @@
elf_hwcap |= HWCAP_VFPv4;
}
}
+
+#ifdef CONFIG_PROC_FS
+ procfs_entry = create_proc_entry("cpu/vfp_bounce", S_IRUGO, NULL);
+
+ if (procfs_entry)
+ procfs_entry->read_proc = proc_read_status;
+ else
+ pr_err("Failed to create procfs node for VFP bounce reporting\n");
+#endif
+
return 0;
}
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index 5e1d7af..aed71c0 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -34,7 +34,15 @@
#define GENLOCK_LOG_ERR(fmt, args...) \
pr_err("genlock: %s: " fmt, __func__, ##args)
+/* The genlock magic stored in the kernel private data is used to protect
+ * against the possibility of user space passing a valid fd to a
+ * non-genlock file for genlock_attach_lock()
+ */
+#define GENLOCK_MAGIC_OK 0xD2EAD10C
+#define GENLOCK_MAGIC_BAD 0xD2EADBAD
+
struct genlock {
+ unsigned int magic; /* Magic for attach verification */
struct list_head active; /* List of handles holding lock */
spinlock_t lock; /* Spinlock to protect the lock internals */
wait_queue_head_t queue; /* Holding pen for processes pending lock */
@@ -56,7 +64,7 @@
* released while another process tries to attach it
*/
-static DEFINE_SPINLOCK(genlock_file_lock);
+static DEFINE_SPINLOCK(genlock_ref_lock);
static void genlock_destroy(struct kref *kref)
{
@@ -68,10 +76,9 @@
* still active after the lock gets released
*/
- spin_lock(&genlock_file_lock);
if (lock->file)
lock->file->private_data = NULL;
- spin_unlock(&genlock_file_lock);
+ lock->magic = GENLOCK_MAGIC_BAD;
kfree(lock);
}
@@ -130,6 +137,7 @@
init_waitqueue_head(&lock->queue);
spin_lock_init(&lock->lock);
+ lock->magic = GENLOCK_MAGIC_OK;
lock->state = _UNLOCKED;
/*
@@ -203,21 +211,30 @@
* released and then attached
*/
- spin_lock(&genlock_file_lock);
+ spin_lock(&genlock_ref_lock);
lock = file->private_data;
- spin_unlock(&genlock_file_lock);
fput(file);
if (lock == NULL) {
GENLOCK_LOG_ERR("File descriptor is invalid\n");
- return ERR_PTR(-EINVAL);
+ goto fail_invalid;
+ }
+
+ if (lock->magic != GENLOCK_MAGIC_OK) {
+ GENLOCK_LOG_ERR("Magic is invalid - 0x%X\n", lock->magic);
+ goto fail_invalid;
}
handle->lock = lock;
kref_get(&lock->refcount);
+ spin_unlock(&genlock_ref_lock);
return lock;
+
+fail_invalid:
+ spin_unlock(&genlock_ref_lock);
+ return ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL(genlock_attach_lock);
@@ -595,7 +612,9 @@
}
spin_unlock_irqrestore(&handle->lock->lock, flags);
+ spin_lock(&genlock_ref_lock);
kref_put(&handle->lock->refcount, genlock_destroy);
+ spin_unlock(&genlock_ref_lock);
handle->lock = NULL;
handle->active = 0;
}
diff --git a/drivers/bluetooth/hci_ibs.c b/drivers/bluetooth/hci_ibs.c
index 2a6f3f8..6845020 100644
--- a/drivers/bluetooth/hci_ibs.c
+++ b/drivers/bluetooth/hci_ibs.c
@@ -5,7 +5,7 @@
* protocol extension to H4.
*
* Copyright (C) 2007 Texas Instruments, Inc.
- * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010, 2012 Code Aurora Forum. All rights reserved.
*
* Acknowledgements:
* This file is based on hci_ll.c, which was...
@@ -37,7 +37,9 @@
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
+#include <linux/ftrace.h>
#include <linux/poll.h>
+#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/tty.h>
@@ -92,6 +94,15 @@
HCI_IBS_RX_VOTE_CLOCK_OFF,
};
+/* HCI_IBS state for the WorkQueue */
+enum hci_ibs_wq_state_e {
+ HCI_IBS_WQ_INIT_STATE = 0,
+ HCI_IBS_WQ_TX_VOTE_OFF,
+ HCI_IBS_WQ_RX_VOTE_OFF,
+ HCI_IBS_WQ_AWAKE_RX,
+ HCI_IBS_WQ_AWAKE_DEVICE,
+};
+
static unsigned long wake_retrans = 1;
static unsigned long tx_idle_delay = (HZ * 2);
@@ -112,6 +123,11 @@
unsigned long rx_vote; /* clock must be on for RX */
struct timer_list tx_idle_timer;
struct timer_list wake_retrans_timer;
+ struct workqueue_struct *workqueue;
+ struct work_struct ws_ibs;
+ unsigned long ibs_wq_state;
+ void *ibs_hu; /* keeps the hci_uart pointer for reference */
+
/* debug */
unsigned long ibs_sent_wacks;
unsigned long ibs_sent_slps;
@@ -242,6 +258,56 @@
return err;
}
+static void ibs_wq(struct work_struct *work)
+{
+ unsigned long flags = 0;
+ struct ibs_struct *ibs = container_of(work, struct ibs_struct,
+ ws_ibs);
+ struct hci_uart *hu = (struct hci_uart *)ibs->ibs_hu;
+
+ BT_DBG("hu %p, ibs_wq state: %lu\n", hu, ibs->ibs_wq_state);
+
+ /* lock hci_ibs state */
+ spin_lock_irqsave(&ibs->hci_ibs_lock, flags);
+
+ switch (ibs->ibs_wq_state) {
+ case HCI_IBS_WQ_AWAKE_DEVICE:
+ /* Vote for serial clock */
+ ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
+
+ /* send wake indication to device */
+ if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0)
+ BT_ERR("cannot send WAKE to device");
+
+ ibs->ibs_sent_wakes++; /* debug */
+
+ /* start retransmit timer */
+ mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
+ break;
+ case HCI_IBS_WQ_AWAKE_RX:
+ ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
+ ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
+
+ if (send_hci_ibs_cmd(HCI_IBS_WAKE_ACK, hu) < 0)
+ BT_ERR("cannot acknowledge device wake up");
+
+ ibs->ibs_sent_wacks++; /* debug */
+ /* actually send the packets */
+ hci_uart_tx_wakeup(hu);
+ break;
+ case HCI_IBS_WQ_RX_VOTE_OFF:
+ ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+ break;
+ case HCI_IBS_WQ_TX_VOTE_OFF:
+ ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
+ break;
+ default:
+ BT_DBG("Invalid state in ibs workqueue");
+ break;
+ }
+ spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+}
+
static void hci_ibs_tx_idle_timeout(unsigned long arg)
{
struct hci_uart *hu = (struct hci_uart *) arg;
@@ -282,7 +348,9 @@
spin_lock_irqsave_nested(&ibs->hci_ibs_lock,
flags, SINGLE_DEPTH_NESTING);
- ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_OFF, hu);
+ /* vote off tx clock */
+ ibs->ibs_wq_state = HCI_IBS_WQ_TX_VOTE_OFF;
+ queue_work(ibs->workqueue, &ibs->ws_ibs);
out:
spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
}
@@ -336,6 +404,16 @@
skb_queue_head_init(&ibs->txq);
skb_queue_head_init(&ibs->tx_wait_q);
spin_lock_init(&ibs->hci_ibs_lock);
+ ibs->workqueue = create_singlethread_workqueue("ibs_wq");
+ if (!ibs->workqueue) {
+ BT_ERR("IBS Workqueue not initialized properly");
+ kfree(ibs);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&ibs->ws_ibs, ibs_wq);
+ ibs->ibs_hu = (void *)hu;
+ ibs->ibs_wq_state = HCI_IBS_WQ_INIT_STATE;
/* Assume we start with both sides asleep -- extra wakes OK */
ibs->tx_ibs_state = HCI_IBS_TX_ASLEEP;
@@ -432,6 +510,8 @@
skb_queue_purge(&ibs->txq);
del_timer(&ibs->tx_idle_timer);
del_timer(&ibs->wake_retrans_timer);
+ destroy_workqueue(ibs->workqueue);
+ ibs->ibs_hu = NULL;
kfree_skb(ibs->rx_skb);
@@ -463,9 +543,11 @@
/* Make sure clock is on - we may have turned clock off since
* receiving the wake up indicator
*/
- ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_ON, hu);
- ibs->rx_ibs_state = HCI_IBS_RX_AWAKE;
- /* deliberate fall-through */
+ /* awake rx clock */
+ ibs->ibs_wq_state = HCI_IBS_WQ_AWAKE_RX;
+ queue_work(ibs->workqueue, &ibs->ws_ibs);
+ spin_unlock_irqrestore(&ibs->hci_ibs_lock, flags);
+ return;
case HCI_IBS_RX_AWAKE:
/* Always acknowledge device wake up,
* sending IBS message doesn't count as TX ON.
@@ -510,7 +592,9 @@
case HCI_IBS_RX_AWAKE:
/* update state */
ibs->rx_ibs_state = HCI_IBS_RX_ASLEEP;
- ibs_msm_serial_clock_vote(HCI_IBS_RX_VOTE_CLOCK_OFF, hu);
+ /* vote off rx clock under workqueue */
+ ibs->ibs_wq_state = HCI_IBS_WQ_RX_VOTE_OFF;
+ queue_work(ibs->workqueue, &ibs->ws_ibs);
break;
case HCI_IBS_RX_ASLEEP:
/* deliberate fall-through */
@@ -595,20 +679,12 @@
case HCI_IBS_TX_ASLEEP:
BT_DBG("device asleep, waking up and queueing packet");
- ibs_msm_serial_clock_vote(HCI_IBS_TX_VOTE_CLOCK_ON, hu);
/* save packet for later */
skb_queue_tail(&ibs->tx_wait_q, skb);
- /* awake device */
- if (send_hci_ibs_cmd(HCI_IBS_WAKE_IND, hu) < 0) {
- BT_ERR("cannot send WAKE to device");
- break;
- }
- ibs->ibs_sent_wakes++; /* debug */
-
- /* start retransmit timer */
- mod_timer(&ibs->wake_retrans_timer, jiffies + wake_retrans);
-
ibs->tx_ibs_state = HCI_IBS_TX_WAKING;
+ /* schedule a work queue to wake up device */
+ ibs->ibs_wq_state = HCI_IBS_WQ_AWAKE_DEVICE;
+ queue_work(ibs->workqueue, &ibs->ws_ibs);
break;
case HCI_IBS_TX_WAKING:
diff --git a/drivers/char/diag/Kconfig b/drivers/char/diag/Kconfig
index 53df29b..8f8707f 100644
--- a/drivers/char/diag/Kconfig
+++ b/drivers/char/diag/Kconfig
@@ -32,10 +32,10 @@
menu "HSIC support for DIAG"
-config DIAG_HSIC_PIPE
+config DIAG_BRIDGE_CODE
depends on USB_QCOM_DIAG_BRIDGE
default y
- bool "Enable 9K DIAG traffic over HSIC"
+ bool "Enable QSC/9K DIAG traffic over SMUX/HSIC"
help
- HSIC Transport Layer for DIAG Router
+ SMUX/HSIC Transport Layer for DIAG Router
endmenu
diff --git a/drivers/char/diag/Makefile b/drivers/char/diag/Makefile
index 3181d29..ea75ffd 100644
--- a/drivers/char/diag/Makefile
+++ b/drivers/char/diag/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_DIAG_CHAR) := diagchar.o
obj-$(CONFIG_DIAG_SDIO_PIPE) += diagfwd_sdio.o
-obj-$(CONFIG_DIAG_HSIC_PIPE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_hsic.o
+obj-$(CONFIG_DIAG_BRIDGE_CODE) += diagfwd_smux.o
diagchar-objs := diagchar_core.o diagchar_hdlc.o diagfwd.o diagmem.o diagfwd_cntl.o diag_dci.o
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 5cbf888..2860055 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -16,6 +16,7 @@
#include <linux/diagchar.h>
#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
@@ -115,6 +116,23 @@
queue_work(driver->diag_wq, &(driver->diag_read_smd_dci_work));
}
+void diag_dci_notify_client(int peripheral_mask)
+{
+ int i, stat;
+
+ /* Notify the DCI process that the peripheral DCI Channel is up */
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].list & peripheral_mask) {
+ pr_debug("diag: sending signal now\n");
+ stat = send_sig(driver->dci_notify_tbl[i].signal_type,
+ driver->dci_notify_tbl[i].client, 0);
+ if (stat)
+ pr_err("diag: Err send sig stat: %d\n", stat);
+ break;
+ }
+ } /* end of loop for all DCI clients */
+}
+
static int diag_dci_probe(struct platform_device *pdev)
{
int err = 0;
@@ -125,6 +143,8 @@
if (err)
pr_err("diag: cannot open DCI port, Id = %d, err ="
" %d\n", pdev->id, err);
+ else
+ diag_dci_notify_client(DIAG_CON_MPSS);
}
return err;
}
@@ -302,6 +322,12 @@
if (driver->dci_tbl == NULL)
goto err;
}
+ if (driver->dci_notify_tbl == NULL) {
+ driver->dci_notify_tbl = kzalloc(MAX_DCI_CLIENT *
+ sizeof(struct dci_notification_tbl), GFP_KERNEL);
+ if (driver->dci_notify_tbl == NULL)
+ goto err;
+ }
if (driver->apps_dci_buf == NULL) {
driver->apps_dci_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
if (driver->apps_dci_buf == NULL)
@@ -316,6 +342,7 @@
err:
pr_err("diag: Could not initialize diag DCI buffers");
kfree(driver->dci_tbl);
+ kfree(driver->dci_notify_tbl);
kfree(driver->apps_dci_buf);
kfree(driver->buf_in_dci);
kfree(driver->write_ptr_dci);
@@ -328,6 +355,7 @@
driver->ch_dci = 0;
platform_driver_unregister(&msm_diag_dci_driver);
kfree(driver->dci_tbl);
+ kfree(driver->dci_notify_tbl);
kfree(driver->apps_dci_buf);
kfree(driver->buf_in_dci);
kfree(driver->write_ptr_dci);
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index cc6e0cf..c0b82df 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -22,6 +22,12 @@
int tag;
};
+struct dci_notification_tbl {
+ struct task_struct *client;
+ uint16_t list; /* bit mask */
+ int signal_type;
+};
+
#define DIAG_CON_APSS (0x0001) /* Bit mask for APSS */
#define DIAG_CON_MPSS (0x0002) /* Bit mask for MPSS */
#define DIAG_CON_LPASS (0x0004) /* Bit mask for LPASS */
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 49d687d..6a7b931 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -18,6 +18,7 @@
#include <linux/mempool.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
+#include <linux/sched.h>
#include <mach/msm_smd.h>
#include <asm/atomic.h>
#include <asm/mach-types.h>
@@ -41,6 +42,7 @@
#define SDIO_DATA 4
#define WCNSS_DATA 5
#define HSIC_DATA 6
+#define SMUX_DATA 7
#define MODEM_PROC 0
#define APPS_PROC 1
#define QDSP_PROC 2
@@ -138,6 +140,7 @@
int use_device_tree;
/* DCI related variables */
struct diag_dci_tbl *dci_tbl;
+ struct dci_notification_tbl *dci_notify_tbl;
int dci_tag;
int dci_client_id;
struct mutex dci_mutex;
@@ -254,24 +257,30 @@
struct diag_request *usb_read_mdm_ptr;
struct diag_request *write_ptr_mdm;
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ /* SGLTE variables */
+ int lcid;
+ unsigned char *buf_in_smux;
+ int in_busy_smux;
+ int diag_smux_enabled;
+ /* HSIC variables */
unsigned char *buf_in_hsic;
- unsigned char *usb_buf_mdm_out;
- int hsic_initialized;
int hsic_ch;
int hsic_device_enabled;
int hsic_device_opened;
int hsic_suspend;
- int read_len_mdm;
int in_busy_hsic_read_on_device;
int in_busy_hsic_write_on_device;
int in_busy_hsic_write;
int in_busy_hsic_read;
- int usb_mdm_connected;
- struct usb_diag_ch *mdm_ch;
- struct workqueue_struct *diag_hsic_wq;
- struct work_struct diag_read_mdm_work;
struct work_struct diag_read_hsic_work;
+ /* USB MDM channel variables */
+ int usb_mdm_connected;
+ int read_len_mdm;
+ unsigned char *usb_buf_mdm_out;
+ struct usb_diag_ch *mdm_ch;
+ struct workqueue_struct *diag_bridge_wq;
+ struct work_struct diag_read_mdm_work;
struct work_struct diag_disconnect_work;
struct work_struct diag_usb_read_complete_work;
struct diag_request *usb_read_mdm_ptr;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 58a8676..547f42f 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -32,8 +32,9 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
#include "diagfwd_sdio.h"
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
#include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
#endif
#include <linux/timer.h>
@@ -234,9 +235,9 @@
if (driver->logging_process_id == current->tgid) {
driver->logging_mode = USB_MODE;
diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
diagfwd_cancel_hsic();
- diagfwd_connect_hsic(0);
+ diagfwd_connect_bridge(0);
#endif
}
#endif /* DIAG over USB */
@@ -342,6 +343,7 @@
int success = -1;
void *temp_buf;
uint16_t support_list = 0;
+ struct dci_notification_tbl *notify_params;
if (iocmd == DIAG_IOCTL_COMMAND_REG) {
struct bindpkt_params_per_process *pkt_params =
@@ -412,13 +414,23 @@
} else if (iocmd == DIAG_IOCTL_DCI_REG) {
if (driver->dci_state == DIAG_DCI_NO_REG)
return DIAG_DCI_NO_REG;
- /* use the 'list' later on to notify user space */
if (driver->num_dci_client >= MAX_DCI_CLIENT)
return DIAG_DCI_NO_REG;
+ notify_params = (struct dci_notification_tbl *) ioarg;
mutex_lock(&driver->dci_mutex);
driver->num_dci_client++;
pr_debug("diag: id = %d\n", driver->dci_client_id);
driver->dci_client_id++;
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].client == NULL) {
+ driver->dci_notify_tbl[i].client = current;
+ driver->dci_notify_tbl[i].list =
+ notify_params->list;
+ driver->dci_notify_tbl[i].signal_type =
+ notify_params->signal_type;
+ break;
+ }
+ }
mutex_unlock(&driver->dci_mutex);
return driver->dci_client_id;
} else if (iocmd == DIAG_IOCTL_DCI_DEINIT) {
@@ -432,6 +444,12 @@
success = i;
}
}
+ for (i = 0; i < MAX_DCI_CLIENT; i++) {
+ if (driver->dci_notify_tbl[i].client == current) {
+ driver->dci_notify_tbl[i].client = NULL;
+ break;
+ }
+ }
/* if any registrations were deleted successfully OR a valid
client_id was sent in DEINIT call , then its DCI client */
if (success >= 0 || ioarg)
@@ -481,8 +499,8 @@
#ifdef CONFIG_DIAG_SDIO_PIPE
driver->in_busy_sdio = 1;
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_disconnect_bridge(0);
#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
@@ -509,22 +527,22 @@
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_connect_bridge(0);
#endif
}
#ifdef CONFIG_DIAG_OVER_USB
else if (temp == USB_MODE && driver->logging_mode
== NO_LOGGING_MODE) {
diagfwd_disconnect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_disconnect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_disconnect_bridge(0);
#endif
} else if (temp == NO_LOGGING_MODE && driver->logging_mode
== USB_MODE) {
diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_connect_hsic(0);
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ diagfwd_connect_bridge(0);
#endif
} else if (temp == USB_MODE && driver->logging_mode
== MEMORY_DEVICE_MODE) {
@@ -552,16 +570,16 @@
queue_work(driver->diag_sdio_wq,
&(driver->diag_read_sdio_work));
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
diagfwd_cancel_hsic();
- diagfwd_connect_hsic(0);
+ diagfwd_connect_bridge(0);
#endif
} else if (temp == MEMORY_DEVICE_MODE &&
driver->logging_mode == USB_MODE) {
diagfwd_connect();
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
diagfwd_cancel_hsic();
- diagfwd_connect_hsic(0);
+ diagfwd_connect_bridge(0);
#endif
}
#endif /* DIAG over USB */
@@ -720,7 +738,7 @@
driver->in_busy_sdio = 0;
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
pr_debug("diag: Copy data to user space %d\n",
driver->in_busy_hsic_write_on_device);
if (driver->in_busy_hsic_write_on_device == 1) {
@@ -898,7 +916,7 @@
}
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
/* send masks to 9k too */
if (driver->hsic_ch && (payload_size > 0)) {
/* wait sending mask updates if HSIC ch not ready */
@@ -1199,6 +1217,18 @@
inline void diag_sdio_fn(int type) {}
#endif
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+void diag_bridge_fn(int type)
+{
+ if (type == INIT)
+ diagfwd_bridge_init();
+ else if (type == EXIT)
+ diagfwd_bridge_exit();
+}
+#else
+inline void diag_bridge_fn(int type) {}
+#endif
+
static int __init diagchar_init(void)
{
dev_t dev;
@@ -1243,9 +1273,7 @@
diagfwd_cntl_init();
driver->dci_state = diag_dci_init();
diag_sdio_fn(INIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_hsic_init();
-#endif
+ diag_bridge_fn(INIT);
pr_debug("diagchar initializing ..\n");
driver->num = 1;
driver->name = ((void *)driver) + sizeof(struct diagchar_dev);
@@ -1279,9 +1307,7 @@
diagfwd_exit();
diagfwd_cntl_exit();
diag_sdio_fn(EXIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_hsic_exit();
-#endif
+ diag_bridge_fn(EXIT);
return -1;
}
@@ -1294,9 +1320,7 @@
diagfwd_exit();
diagfwd_cntl_exit();
diag_sdio_fn(EXIT);
-#ifdef CONFIG_DIAG_HSIC_PIPE
- diagfwd_hsic_exit();
-#endif
+ diag_bridge_fn(EXIT);
diag_debugfs_cleanup();
diagchar_cleanup();
printk(KERN_INFO "done diagchar exit\n");
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 4ac2643..69aa411 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -49,7 +49,7 @@
unsigned char diag_debug_buf[1024];
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
-smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
+smd_channel_t *ch_temp = NULL, *chqdsp_temp = NULL, *ch_wcnss_temp = NULL;
int diag_event_num_bytes;
int diag_event_config;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
@@ -300,12 +300,12 @@
&(driver->diag_read_sdio_work));
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
else if (proc_num == HSIC_DATA) {
driver->in_busy_hsic_read = 0;
driver->in_busy_hsic_write_on_device = 0;
if (driver->hsic_ch)
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&(driver->diag_read_hsic_work));
}
#endif
@@ -352,7 +352,7 @@
"while USB write\n");
}
#endif
-#ifdef CONFIG_DIAG_HSIC_PIPE
+#ifdef CONFIG_DIAG_BRIDGE_CODE
else if (proc_num == HSIC_DATA) {
if (driver->hsic_device_enabled) {
write_ptr->buf = buf;
@@ -360,6 +360,10 @@
} else
pr_err("diag: Incorrect hsic data "
"while USB write\n");
+ } else if (proc_num == SMUX_DATA) {
+ write_ptr->buf = buf;
+ pr_debug("diag: writing SMUX data\n");
+ err = usb_diag_write(driver->mdm_ch, write_ptr);
}
#endif
APPEND_DEBUG('d');
@@ -922,8 +926,10 @@
{
uint16_t subsys_cmd_code;
int subsys_id, ssid_first, ssid_last, ssid_range;
- int packet_type = 1, i, cmd_code, rt_mask;
+ int packet_type = 1, i, cmd_code;
+ int rt_mask, rt_first_ssid, rt_last_ssid, rt_mask_size;
unsigned char *temp = buf;
+ uint8_t *rt_mask_ptr;
int data_type;
#if defined(CONFIG_DIAG_OVER_USB)
int payload_length;
@@ -983,6 +989,38 @@
return 0;
}
#endif
+ } /* Get runtime message mask */
+ else if ((*buf == 0x7d) && (*(buf+1) == 0x3)) {
+ ssid_first = *(uint16_t *)(buf + 2);
+ ssid_last = *(uint16_t *)(buf + 4);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (!(driver->ch) && chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x7d;
+ driver->apps_rsp_buf[1] = 0x3;
+ *(uint16_t *)(driver->apps_rsp_buf+2) = ssid_first;
+ *(uint16_t *)(driver->apps_rsp_buf+4) = ssid_last;
+ driver->apps_rsp_buf[6] = 0x1; /* Success Status */
+ driver->apps_rsp_buf[7] = 0x0;
+ rt_mask_ptr = driver->msg_masks;
+ while (*(uint32_t *)(rt_mask_ptr + 4)) {
+ rt_first_ssid = *(uint32_t *)rt_mask_ptr;
+ rt_mask_ptr += 4;
+ rt_last_ssid = *(uint32_t *)rt_mask_ptr;
+ rt_mask_ptr += 4;
+ if (ssid_first == rt_first_ssid && ssid_last ==
+ rt_last_ssid) {
+ rt_mask_size = 4 * (rt_last_ssid -
+ rt_first_ssid + 1);
+ memcpy(driver->apps_rsp_buf+8,
+ rt_mask_ptr, rt_mask_size);
+ ENCODE_RSP_AND_SEND(8+rt_mask_size-1);
+ return 0;
+ }
+ rt_mask_ptr += MAX_SSID_PER_RANGE*4;
+ }
+ } else
+ buf = temp;
+#endif
} /* Set runtime message mask */
else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
ssid_first = *(uint16_t *)(buf + 2);
@@ -1695,7 +1733,8 @@
driver->ch = 0;
return;
} else if (event == SMD_EVENT_OPEN) {
- driver->ch = ch_temp;
+ if (ch_temp)
+ driver->ch = ch_temp;
}
queue_work(driver->diag_wq, &(driver->diag_read_smd_work));
}
@@ -1709,7 +1748,8 @@
driver->chqdsp = 0;
return;
} else if (event == SMD_EVENT_OPEN) {
- driver->chqdsp = chqdsp_temp;
+ if (chqdsp_temp)
+ driver->chqdsp = chqdsp_temp;
}
queue_work(driver->diag_wq, &(driver->diag_read_smd_qdsp_work));
}
@@ -1723,7 +1763,8 @@
driver->ch_wcnss = 0;
return;
} else if (event == SMD_EVENT_OPEN) {
- driver->ch_wcnss = ch_wcnss_temp;
+ if (ch_wcnss_temp)
+ driver->ch_wcnss = ch_wcnss_temp;
}
queue_work(driver->diag_wq, &(driver->diag_read_smd_wcnss_work));
}
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index a3c6f26..fedcf03 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -16,9 +16,11 @@
#include <linux/diagchar.h>
#include <linux/sched.h>
#include <linux/err.h>
+#include <linux/ratelimit.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
+#include <linux/smux.h>
#include <asm/current.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
@@ -28,6 +30,7 @@
#include "diagchar.h"
#include "diagfwd.h"
#include "diagfwd_hsic.h"
+#include "diagfwd_smux.h"
static void diag_read_hsic_work_fn(struct work_struct *work)
{
@@ -53,7 +56,7 @@
err = diag_bridge_read((char *)driver->buf_in_hsic,
IN_BUF_SIZE);
if (err) {
- pr_err("DIAG: Error initiating HSIC read, err: %d\n",
+ pr_err_ratelimited("DIAG: Error initiating HSIC read, err: %d\n",
err);
/*
* If the error is recoverable, then clear
@@ -61,7 +64,7 @@
* read on the next frame. Otherwise, don't
* resubmit a read on the next frame.
*/
- if ((-ESHUTDOWN) != err)
+ if ((-ENODEV) != err)
driver->in_busy_hsic_read = 0;
}
}
@@ -71,7 +74,8 @@
* the next read
*/
if (!driver->in_busy_hsic_read)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
static void diag_hsic_read_complete_callback(void *ctxt, char *buf,
@@ -114,7 +118,8 @@
if (!driver->in_busy_hsic_write_on_device && ((driver->logging_mode
== MEMORY_DEVICE_MODE) || (driver->usb_mdm_connected &&
!driver->hsic_suspend)))
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
static void diag_hsic_write_complete_callback(void *ctxt, char *buf,
@@ -132,7 +137,7 @@
pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
if (driver->usb_mdm_connected)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+ queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
}
static int diag_hsic_suspend(void *ctxt)
@@ -157,7 +162,8 @@
if (!driver->in_busy_hsic_write_on_device && (driver->logging_mode
== MEMORY_DEVICE_MODE || driver->usb_mdm_connected))
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
static struct diag_bridge_ops hsic_diag_bridge_ops = {
@@ -209,42 +215,48 @@
return 0;
}
-/* diagfwd_connect_hsic is called when the USB mdm channel is connected */
-int diagfwd_connect_hsic(int process_cable)
+/* diagfwd_connect_bridge is called when the USB mdm channel is connected */
+int diagfwd_connect_bridge(int process_cable)
{
int err;
- pr_debug("DIAG in %s\n", __func__);
+ pr_debug("diag: in %s\n", __func__);
/* If the usb cable is being connected */
if (process_cable) {
err = usb_diag_alloc_req(driver->mdm_ch, N_MDM_WRITE,
N_MDM_READ);
if (err)
- pr_err("DIAG: unable to alloc USB req on mdm"
+ pr_err("diag: unable to alloc USB req on mdm"
" ch err:%d\n", err);
driver->usb_mdm_connected = 1;
}
- driver->in_busy_hsic_write_on_device = 0;
- driver->in_busy_hsic_read_on_device = 0;
- driver->in_busy_hsic_write = 0;
- driver->in_busy_hsic_read = 0;
+ if (driver->hsic_device_enabled) {
+ driver->in_busy_hsic_write_on_device = 0;
+ driver->in_busy_hsic_read_on_device = 0;
+ driver->in_busy_hsic_write = 0;
+ driver->in_busy_hsic_read = 0;
+ } else if (driver->diag_smux_enabled) {
+ driver->in_busy_smux = 0;
+ diagfwd_connect_smux();
+ return 0;
+ }
/* If the hsic (diag_bridge) platform device is not open */
if (driver->hsic_device_enabled) {
if (!driver->hsic_device_opened) {
err = diag_bridge_open(&hsic_diag_bridge_ops);
if (err) {
- pr_err("DIAG: HSIC channel open error: %d\n",
+ pr_err("diag: HSIC channel open error: %d\n",
err);
} else {
- pr_debug("DIAG: opened HSIC channel\n");
+ pr_debug("diag: opened HSIC channel\n");
driver->hsic_device_opened = 1;
}
} else {
- pr_debug("DIAG: HSIC channel already open\n");
+ pr_debug("diag: HSIC channel already open\n");
}
/*
@@ -256,24 +268,25 @@
/* Poll USB mdm channel to check for data */
if (driver->logging_mode == USB_MODE)
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&driver->diag_read_mdm_work);
/* Poll HSIC channel to check for data */
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
} else {
/* The hsic device driver has not yet been enabled */
- pr_info("DIAG: HSIC channel not yet enabled\n");
+ pr_info("diag: HSIC channel not yet enabled\n");
}
return 0;
}
/*
- * diagfwd_disconnect_hsic is called when the USB mdm channel
+ * diagfwd_disconnect_bridge is called when the USB mdm channel
* is disconnected
*/
-int diagfwd_disconnect_hsic(int process_cable)
+int diagfwd_disconnect_bridge(int process_cable)
{
pr_debug("DIAG in %s\n", __func__);
@@ -284,12 +297,19 @@
}
if (driver->logging_mode != MEMORY_DEVICE_MODE) {
- driver->in_busy_hsic_write_on_device = 1;
- driver->in_busy_hsic_read_on_device = 1;
- driver->in_busy_hsic_write = 1;
- driver->in_busy_hsic_read = 1;
- /* Turn off communication over usb mdm and hsic */
- return diag_hsic_close();
+ if (driver->hsic_device_enabled) {
+ driver->in_busy_hsic_write_on_device = 1;
+ driver->in_busy_hsic_read_on_device = 1;
+ driver->in_busy_hsic_write = 1;
+ driver->in_busy_hsic_read = 1;
+ /* Turn off communication over usb mdm and hsic */
+ return diag_hsic_close();
+ } else if (driver->diag_smux_enabled) {
+ driver->in_busy_smux = 1;
+ driver->lcid = LCID_INVALID;
+ /* Turn off communication over usb mdm and smux */
+ msm_smux_close(LCID_VALID);
+ }
}
return 0;
}
@@ -313,18 +333,23 @@
APPEND_DEBUG('q');
/* Read data from the hsic */
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq, &driver->diag_read_hsic_work);
return 0;
}
/* Called after the asychronous usb_diag_read() on mdm channel is complete */
-static int diagfwd_read_complete_hsic(struct diag_request *diag_read_ptr)
+static int diagfwd_read_complete_bridge(struct diag_request *diag_read_ptr)
{
/* The read of the usb driver on the mdm (not hsic) has completed */
driver->in_busy_hsic_read_on_device = 0;
driver->read_len_mdm = diag_read_ptr->actual;
+ if (driver->diag_smux_enabled) {
+ diagfwd_read_complete_smux();
+ return 0;
+ }
+ /* If SMUX not enabled, check for HSIC */
if (!driver->hsic_ch) {
pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
return 0;
@@ -349,14 +374,15 @@
err = diag_bridge_write(driver->usb_buf_mdm_out,
driver->read_len_mdm);
if (err) {
- pr_err("DIAG: mdm data on hsic write err: %d\n", err);
+ pr_err_ratelimited("DIAG: mdm data on hsic write err: %d\n",
+ err);
/*
* If the error is recoverable, then clear
* the write flag, so we will resubmit a
* write on the next frame. Otherwise, don't
* resubmit a write on the next frame.
*/
- if ((-ESHUTDOWN) != err)
+ if ((-ENODEV) != err)
driver->in_busy_hsic_write = 0;
}
}
@@ -366,30 +392,34 @@
* hsic channel
*/
if (!driver->in_busy_hsic_write)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+ queue_work(driver->diag_bridge_wq, &driver->diag_read_mdm_work);
return 0;
}
-static void diagfwd_hsic_notifier(void *priv, unsigned event,
+static void diagfwd_bridge_notifier(void *priv, unsigned event,
struct diag_request *d_req)
{
switch (event) {
case USB_DIAG_CONNECT:
- diagfwd_connect_hsic(1);
+ diagfwd_connect_bridge(1);
break;
case USB_DIAG_DISCONNECT:
- queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_disconnect_work);
break;
case USB_DIAG_READ_DONE:
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&driver->diag_usb_read_complete_work);
break;
case USB_DIAG_WRITE_DONE:
- diagfwd_write_complete_hsic();
+ if (driver->hsic_device_enabled)
+ diagfwd_write_complete_hsic();
+ else if (driver->diag_smux_enabled)
+ diagfwd_write_complete_smux();
break;
default:
- pr_err("DIAG in %s: Unknown event from USB diag:%u\n",
+ pr_err("diag: in %s: Unknown event from USB diag:%u\n",
__func__, event);
break;
}
@@ -397,16 +427,33 @@
static void diag_usb_read_complete_fn(struct work_struct *w)
{
- diagfwd_read_complete_hsic(driver->usb_read_mdm_ptr);
+ diagfwd_read_complete_bridge(driver->usb_read_mdm_ptr);
}
static void diag_disconnect_work_fn(struct work_struct *w)
{
- diagfwd_disconnect_hsic(1);
+ diagfwd_disconnect_bridge(1);
}
static void diag_read_mdm_work_fn(struct work_struct *work)
{
+ int ret;
+ if (driver->diag_smux_enabled) {
+ if (driver->lcid && driver->usb_buf_mdm_out &&
+ (driver->read_len_mdm > 0)) {
+ ret = msm_smux_write(driver->lcid, NULL,
+ driver->usb_buf_mdm_out, driver->read_len_mdm);
+ if (ret)
+ pr_err("diag: writing to SMUX ch, r = %d,"
+ "lcid = %d\n", ret, driver->lcid);
+ }
+ driver->usb_read_mdm_ptr->buf = driver->usb_buf_mdm_out;
+ driver->usb_read_mdm_ptr->length = USB_MAX_OUT_BUF;
+ usb_diag_read(driver->mdm_ch, driver->usb_read_mdm_ptr);
+ return;
+ }
+
+ /* if SMUX not enabled, check for HSIC */
if (!driver->hsic_ch) {
pr_err("DIAG in %s: driver->hsic_ch == 0\n", __func__);
return;
@@ -434,7 +481,8 @@
* queue up the reading of data from the mdm channel
*/
if (!driver->in_busy_hsic_read_on_device)
- queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_mdm_work);
}
static int diag_hsic_probe(struct platform_device *pdev)
@@ -442,31 +490,10 @@
int err = 0;
pr_debug("diag: in %s\n", __func__);
if (!driver->hsic_device_enabled) {
- driver->read_len_mdm = 0;
if (driver->buf_in_hsic == NULL)
driver->buf_in_hsic = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
- if (driver->buf_in_hsic == NULL)
- goto err;
- if (driver->usb_buf_mdm_out == NULL)
- driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
- GFP_KERNEL);
- if (driver->usb_buf_mdm_out == NULL)
- goto err;
- if (driver->write_ptr_mdm == NULL)
- driver->write_ptr_mdm = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->write_ptr_mdm == NULL)
- goto err;
- if (driver->usb_read_mdm_ptr == NULL)
- driver->usb_read_mdm_ptr = kzalloc(
- sizeof(struct diag_request), GFP_KERNEL);
- if (driver->usb_read_mdm_ptr == NULL)
- goto err;
-#ifdef CONFIG_DIAG_OVER_USB
- INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
-#endif
INIT_WORK(&(driver->diag_read_hsic_work),
- diag_read_hsic_work_fn);
+ diag_read_hsic_work_fn);
driver->hsic_device_enabled = 1;
}
@@ -495,25 +522,16 @@
if (driver->usb_mdm_connected) {
/* Poll USB mdm channel to check for data */
- queue_work(driver->diag_hsic_wq,
+ queue_work(driver->diag_bridge_wq,
&driver->diag_read_mdm_work);
}
/* Poll HSIC channel to check for data */
- queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
+ queue_work(driver->diag_bridge_wq,
+ &driver->diag_read_hsic_work);
}
return err;
-err:
- pr_err("DIAG could not initialize buf for HSIC\n");
- kfree(driver->buf_in_hsic);
- kfree(driver->usb_buf_mdm_out);
- kfree(driver->write_ptr_mdm);
- kfree(driver->usb_read_mdm_ptr);
- if (driver->diag_hsic_wq)
- destroy_workqueue(driver->diag_hsic_wq);
-
- return -ENOMEM;
}
static int diag_hsic_remove(struct platform_device *pdev)
@@ -550,55 +568,93 @@
},
};
-void diagfwd_hsic_init(void)
+void diagfwd_bridge_init(void)
{
int ret;
- pr_debug("DIAG in %s\n", __func__);
+ pr_debug("diag: in %s\n", __func__);
+ driver->diag_bridge_wq = create_singlethread_workqueue(
+ "diag_bridge_wq");
+ driver->read_len_mdm = 0;
+ if (driver->usb_buf_mdm_out == NULL)
+ driver->usb_buf_mdm_out = kzalloc(USB_MAX_OUT_BUF,
+ GFP_KERNEL);
+ if (driver->usb_buf_mdm_out == NULL)
+ goto err;
+ if (driver->write_ptr_mdm == NULL)
+ driver->write_ptr_mdm = kzalloc(
+ sizeof(struct diag_request), GFP_KERNEL);
+ if (driver->write_ptr_mdm == NULL)
+ goto err;
+ if (driver->usb_read_mdm_ptr == NULL)
+ driver->usb_read_mdm_ptr = kzalloc(
+ sizeof(struct diag_request), GFP_KERNEL);
+ if (driver->usb_read_mdm_ptr == NULL)
+ goto err;
- driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+#ifdef CONFIG_DIAG_OVER_USB
+ INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
+#endif
INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
INIT_WORK(&(driver->diag_usb_read_complete_work),
diag_usb_read_complete_fn);
-
#ifdef CONFIG_DIAG_OVER_USB
- driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
+ driver->mdm_ch = usb_diag_open(DIAG_MDM, driver,
+ diagfwd_bridge_notifier);
if (IS_ERR(driver->mdm_ch)) {
- pr_err("DIAG Unable to open USB diag MDM channel\n");
+ pr_err("diag: Unable to open USB diag MDM channel\n");
goto err;
}
#endif
+#ifdef CONFIG_DIAG_BRIDGE_CODE
+ INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
+ INIT_WORK(&(driver->diag_usb_read_complete_work),
+ diag_usb_read_complete_fn);
+ /* register HSIC device */
ret = platform_driver_register(&msm_hsic_ch_driver);
if (ret)
- pr_err("DIAG could not register HSIC device, ret: %d\n", ret);
- else
- driver->hsic_initialized = 1;
-
+ pr_err("diag: could not register HSIC device, ret: %d\n", ret);
+ /* register SMUX device */
+ ret = platform_driver_register(&msm_diagfwd_smux_driver);
+ if (ret)
+ pr_err("diag: could not register SMUX device, ret: %d\n", ret);
+#endif
return;
err:
- pr_err("DIAG could not initialize for HSIC execution\n");
-}
-
-void diagfwd_hsic_exit(void)
-{
- pr_debug("DIAG in %s\n", __func__);
-
- if (driver->hsic_initialized)
- diag_hsic_close();
-
-#ifdef CONFIG_DIAG_OVER_USB
- if (driver->usb_mdm_connected)
- usb_diag_free_req(driver->mdm_ch);
-#endif
- platform_driver_unregister(&msm_hsic_ch_driver);
-#ifdef CONFIG_DIAG_OVER_USB
- usb_diag_close(driver->mdm_ch);
-#endif
- kfree(driver->buf_in_hsic);
+ pr_err("diag: Could not initialize for bridge forwarding\n");
kfree(driver->usb_buf_mdm_out);
kfree(driver->write_ptr_mdm);
kfree(driver->usb_read_mdm_ptr);
- destroy_workqueue(driver->diag_hsic_wq);
+ if (driver->diag_bridge_wq)
+ destroy_workqueue(driver->diag_bridge_wq);
- driver->hsic_device_enabled = 0;
+ return;
+}
+
+void diagfwd_bridge_exit(void)
+{
+ pr_debug("diag: in %s\n", __func__);
+
+ if (driver->hsic_device_enabled) {
+ diag_hsic_close();
+ kfree(driver->buf_in_hsic);
+ driver->hsic_device_enabled = 0;
+ }
+ if (driver->diag_smux_enabled) {
+ driver->lcid = LCID_INVALID;
+ kfree(driver->buf_in_smux);
+ driver->diag_smux_enabled = 0;
+ }
+ platform_driver_unregister(&msm_hsic_ch_driver);
+ platform_driver_unregister(&msm_diagfwd_smux_driver);
+ /* destroy USB MDM specific variables */
+#ifdef CONFIG_DIAG_OVER_USB
+ if (driver->usb_mdm_connected)
+ usb_diag_free_req(driver->mdm_ch);
+ usb_diag_close(driver->mdm_ch);
+#endif
+ kfree(driver->usb_buf_mdm_out);
+ kfree(driver->write_ptr_mdm);
+ kfree(driver->usb_read_mdm_ptr);
+ destroy_workqueue(driver->diag_bridge_wq);
}
diff --git a/drivers/char/diag/diagfwd_hsic.h b/drivers/char/diag/diagfwd_hsic.h
index a47ee26..b189c94 100644
--- a/drivers/char/diag/diagfwd_hsic.h
+++ b/drivers/char/diag/diagfwd_hsic.h
@@ -17,11 +17,11 @@
#define N_MDM_WRITE 1 /* Upgrade to 2 with ping pong buffer */
#define N_MDM_READ 1
-void __init diagfwd_hsic_init(void);
-int diagfwd_connect_hsic(int);
-int diagfwd_disconnect_hsic(int);
+int diagfwd_connect_bridge(int);
+int diagfwd_disconnect_bridge(int);
int diagfwd_write_complete_hsic(void);
int diagfwd_cancel_hsic(void);
-void diagfwd_hsic_exit(void);
+void diagfwd_bridge_init(void);
+void diagfwd_bridge_exit(void);
#endif
diff --git a/drivers/char/diag/diagfwd_smux.c b/drivers/char/diag/diagfwd_smux.c
new file mode 100644
index 0000000..8bbc67e
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.c
@@ -0,0 +1,156 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/termios.h>
+#include <linux/slab.h>
+#include <linux/diagchar.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <mach/usbdiag.h>
+#include "diagchar.h"
+#include "diagfwd.h"
+#include "diagfwd_smux.h"
+
+void diag_smux_event(void *priv, int event_type, const void *metadata)
+{
+ unsigned char *rx_buf;
+ int len;
+
+ switch (event_type) {
+ case SMUX_CONNECTED:
+ pr_debug("diag: SMUX_CONNECTED received\n");
+ driver->in_busy_smux = 0;
+ /* read data from USB MDM channel & Initiate first write */
+ queue_work(driver->diag_bridge_wq,
+ &(driver->diag_read_mdm_work));
+ break;
+ case SMUX_DISCONNECTED:
+ pr_info("diag: SMUX_DISCONNECTED received\n");
+ break;
+ case SMUX_WRITE_DONE:
+ pr_debug("diag: SMUX Write done\n");
+ break;
+ case SMUX_WRITE_FAIL:
+ pr_info("diag: SMUX Write Failed\n");
+ break;
+ case SMUX_READ_FAIL:
+ pr_info("diag: SMUX Read Failed\n");
+ break;
+ case SMUX_READ_DONE:
+ len = ((struct smux_meta_read *)metadata)->len;
+ rx_buf = ((struct smux_meta_read *)metadata)->buffer;
+ driver->write_ptr_mdm->length = len;
+ diag_device_write(driver->buf_in_smux, SMUX_DATA,
+ driver->write_ptr_mdm);
+ break;
+ };
+}
+
+int diagfwd_write_complete_smux(void)
+{
+ pr_debug("diag: clear in_busy_smux\n");
+ driver->in_busy_smux = 0;
+ return 0;
+}
+
+int diagfwd_read_complete_smux(void)
+{
+ queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+ return 0;
+}
+
+int diag_get_rx_buffer(void *priv, void **pkt_priv, void **buffer, int size)
+{
+ if (!driver->in_busy_smux) {
+ *pkt_priv = (void *)0x1234;
+ *buffer = driver->buf_in_smux;
+ pr_debug("diag: set in_busy_smux as 1\n");
+ driver->in_busy_smux = 1;
+ } else {
+ pr_debug("diag: read buffer for SMUX is BUSY\n");
+ return -EAGAIN;
+ }
+ return 0;
+}
+
+static int diagfwd_smux_runtime_suspend(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: suspending...\n");
+ return 0;
+}
+
+static int diagfwd_smux_runtime_resume(struct device *dev)
+{
+ dev_dbg(dev, "pm_runtime: resuming...\n");
+ return 0;
+}
+
+static const struct dev_pm_ops diagfwd_smux_dev_pm_ops = {
+ .runtime_suspend = diagfwd_smux_runtime_suspend,
+ .runtime_resume = diagfwd_smux_runtime_resume,
+};
+
+int diagfwd_connect_smux(void)
+{
+ void *priv = NULL;
+ int ret = 0;
+
+ if (driver->lcid == LCID_INVALID) {
+ ret = msm_smux_open(LCID_VALID, priv, diag_smux_event,
+ diag_get_rx_buffer);
+ if (!ret) {
+ driver->lcid = LCID_VALID;
+ msm_smux_tiocm_set(driver->lcid, TIOCM_DTR, 0);
+ pr_info("diag: open SMUX ch, r = %d\n", ret);
+ } else {
+ pr_err("diag: failed to open SMUX ch, r = %d\n", ret);
+ }
+ }
+ /* Poll USB channel to check for data*/
+ queue_work(driver->diag_bridge_wq, &(driver->diag_read_mdm_work));
+ return ret;
+}
+
+static int diagfwd_smux_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ pr_info("diag: SMUX probe called\n");
+ driver->lcid = LCID_INVALID;
+ driver->diag_smux_enabled = 1;
+ if (driver->buf_in_smux == NULL) {
+ driver->buf_in_smux = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
+ if (driver->buf_in_smux == NULL)
+ goto err;
+ }
+ /* Only required for Local loopback test
+ * ret = msm_smux_set_ch_option(LCID_VALID,
+ SMUX_CH_OPTION_LOCAL_LOOPBACK, 0);
+ * if (ret)
+ * pr_err("diag: error setting SMUX ch option, r = %d\n", ret);
+ */
+ ret = diagfwd_connect_smux();
+ return ret;
+
+err:
+ pr_err("diag: Could not initialize SMUX buffer\n");
+ kfree(driver->buf_in_smux);
+ return ret;
+}
+
+struct platform_driver msm_diagfwd_smux_driver = {
+ .probe = diagfwd_smux_probe,
+ .driver = {
+ .name = "SMUX_DIAG",
+ .owner = THIS_MODULE,
+ .pm = &diagfwd_smux_dev_pm_ops,
+ },
+};
diff --git a/drivers/char/diag/diagfwd_smux.h b/drivers/char/diag/diagfwd_smux.h
new file mode 100644
index 0000000..e78b7ed
--- /dev/null
+++ b/drivers/char/diag/diagfwd_smux.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 DIAGFWD_SMUX_H
+#define DIAGFWD_SMUX_H
+
+#include <linux/smux.h>
+#define LCID_VALID SMUX_USB_DIAG_0
+#define LCID_INVALID 0
+
+int diagfwd_read_complete_smux(void);
+int diagfwd_write_complete_smux(void);
+int diagfwd_connect_smux(void);
+extern struct platform_driver msm_diagfwd_smux_driver;
+
+#endif
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 5997405..5798c94 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -837,15 +837,16 @@
struct cpu_dbs_info_s *this_dbs_info;
unsigned int cpu = smp_processor_id();
+ get_online_cpus();
+
if (lock_policy_rwsem_write(cpu) < 0)
- return;
+ goto bail_acq_sema_failed;
this_dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
policy = this_dbs_info->cur_policy;
if (!policy) {
/* CPU not using ondemand governor */
- unlock_policy_rwsem_write(cpu);
- return;
+ goto bail_incorrect_governor;
}
if (policy->cur < policy->max) {
@@ -856,7 +857,13 @@
this_dbs_info->prev_cpu_idle = get_cpu_idle_time(cpu,
&this_dbs_info->prev_cpu_wall);
}
+
+bail_incorrect_governor:
unlock_policy_rwsem_write(cpu);
+
+bail_acq_sema_failed:
+ put_online_cpus();
+ return;
}
static void dbs_input_event(struct input_handle *handle, unsigned int type,
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index ef077a5..0dcf1a4 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -124,6 +124,15 @@
Qualcomm MSM chips. Most of the pins on the MSM can be
selected for GPIO, and are controlled by this driver.
+config GPIO_MSM_V3
+ tristate "Qualcomm MSM GPIO v3"
+ depends on GPIOLIB && ARCH_MSM
+ help
+ Say yes here to support the GPIO interface on ARM v7 based
+ Qualcomm MSM chips for v3 version of the interface. Most of
+ the pins on the MSM can be selected for GPIO, and are
+ controlled by this driver.
+
config GPIO_FSM9XXX
tristate "Qualcomm FSM GPIO"
depends on GPIOLIB && ARCH_MSM
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index babd44d..d15b628 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -33,7 +33,8 @@
obj-$(CONFIG_GPIO_MPC5200) += gpio-mpc5200.o
obj-$(CONFIG_GPIO_MPC8XXX) += gpio-mpc8xxx.o
obj-$(CONFIG_GPIO_MSM_V1) += gpio-msm-v1.o
-obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-v2.o
+obj-$(CONFIG_GPIO_MSM_V2) += gpio-msm-common.o gpio-msm-v2.o
+obj-$(CONFIG_GPIO_MSM_V3) += gpio-msm-common.o gpio-msm-v3.o
obj-$(CONFIG_GPIO_FSM9XXX) += gpio-fsm9xxx.o
obj-$(CONFIG_GPIO_MXC) += gpio-mxc.o
obj-$(CONFIG_GPIO_MXS) += gpio-mxs.o
diff --git a/drivers/gpio/gpio-msm-common.c b/drivers/gpio/gpio-msm-common.c
new file mode 100644
index 0000000..9a9a783
--- /dev/null
+++ b/drivers/gpio/gpio-msm-common.c
@@ -0,0 +1,629 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/err.h>
+
+#include <asm/mach/irq.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/gpiomux.h>
+#include <mach/mpm.h>
+#include "gpio-msm-common.h"
+
+enum msm_tlmm_register {
+ SDC4_HDRV_PULL_CTL = 0x20a0,
+ SDC3_HDRV_PULL_CTL = 0x20a4,
+ SDC1_HDRV_PULL_CTL = 0x20a0,
+};
+
+struct tlmm_field_cfg {
+ enum msm_tlmm_register reg;
+ u8 off;
+};
+
+static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
+ {SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK */
+ {SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD */
+ {SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
+ {SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK */
+ {SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD */
+ {SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
+ {SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK */
+ {SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD */
+ {SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
+};
+
+static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
+ {SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD */
+ {SDC4_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC4_DATA */
+ {SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK */
+ {SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD */
+ {SDC3_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC3_DATA */
+ {SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK */
+ {SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD */
+ {SDC1_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC1_DATA */
+};
+
+/*
+ * Supported arch specific irq extension.
+ * Default make them NULL.
+ */
+struct irq_chip msm_gpio_irq_extn = {
+ .irq_eoi = NULL,
+ .irq_mask = NULL,
+ .irq_unmask = NULL,
+ .irq_retrigger = NULL,
+ .irq_set_type = NULL,
+ .irq_set_wake = NULL,
+ .irq_disable = NULL,
+};
+
+/**
+ * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
+ *
+ * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
+ * keeping track of which gpios are unmasked as irq sources, we avoid
+ * having to do __raw_readl calls on hundreds of iomapped registers each time
+ * the summary interrupt fires in order to locate the active interrupts.
+ *
+ * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
+ * as wakeup sources. When the device is suspended, interrupts which are
+ * not wakeup sources are disabled.
+ *
+ * @dual_edge_irqs: a bitmap used to track which irqs are configured
+ * as dual-edge, as this is not supported by the hardware and requires
+ * some special handling in the driver.
+ */
+struct msm_gpio_dev {
+ struct gpio_chip gpio_chip;
+ DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
+ DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
+ DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
+ struct irq_domain domain;
+};
+
+static DEFINE_SPINLOCK(tlmm_lock);
+
+static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
+{
+ return container_of(chip, struct msm_gpio_dev, gpio_chip);
+}
+
+static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ int rc;
+ rc = __msm_gpio_get_inout(offset);
+ mb();
+ return rc;
+}
+
+static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+ __msm_gpio_set_inout(offset, val);
+ mb();
+}
+
+static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ __msm_gpio_set_config_direction(offset, 1, 0);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+ return 0;
+}
+
+static int msm_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset,
+ int val)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ __msm_gpio_set_config_direction(offset, 0, val);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
+ struct irq_domain *domain = &g_dev->domain;
+ return domain->irq_base + (offset - chip->base);
+}
+
+static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
+{
+ struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
+ struct irq_domain *domain = &g_dev->domain;
+ return irq - domain->irq_base;
+}
+#else
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ return MSM_GPIO_TO_INT(offset - chip->base);
+}
+
+static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
+{
+ return irq - MSM_GPIO_TO_INT(chip->base);
+}
+#endif
+
+static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return msm_gpiomux_get(chip->base + offset);
+}
+
+static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ msm_gpiomux_put(chip->base + offset);
+}
+
+static struct msm_gpio_dev msm_gpio = {
+ .gpio_chip = {
+ .label = "msmgpio",
+ .base = 0,
+ .ngpio = NR_MSM_GPIOS,
+ .direction_input = msm_gpio_direction_input,
+ .direction_output = msm_gpio_direction_output,
+ .get = msm_gpio_get,
+ .set = msm_gpio_set,
+ .to_irq = msm_gpio_to_irq,
+ .request = msm_gpio_request,
+ .free = msm_gpio_free,
+ },
+};
+
+static void switch_mpm_config(struct irq_data *d, unsigned val)
+{
+ /* switch the configuration in the mpm as well */
+ if (!msm_gpio_irq_extn.irq_set_type)
+ return;
+
+ if (val)
+ msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
+ else
+ msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
+}
+
+/* For dual-edge interrupts in software, since the hardware has no
+ * such support:
+ *
+ * At appropriate moments, this function may be called to flip the polarity
+ * settings of both-edge irq lines to try and catch the next edge.
+ *
+ * The attempt is considered successful if:
+ * - the status bit goes high, indicating that an edge was caught, or
+ * - the input value of the gpio doesn't change during the attempt.
+ * If the value changes twice during the process, that would cause the first
+ * test to fail but would force the second, as two opposite
+ * transitions would cause a detection no matter the polarity setting.
+ *
+ * The do-loop tries to sledge-hammer closed the timing hole between
+ * the initial value-read and the polarity-write - if the line value changes
+ * during that window, an interrupt is lost, the new polarity setting is
+ * incorrect, and the first success test will fail, causing a retry.
+ *
+ * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
+ */
+static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
+{
+ int loop_limit = 100;
+ unsigned val, val2, intstat;
+
+ do {
+ val = __msm_gpio_get_inout(gpio);
+ __msm_gpio_set_polarity(gpio, val);
+ val2 = __msm_gpio_get_inout(gpio);
+ intstat = __msm_gpio_get_intr_status(gpio);
+ if (intstat || val == val2) {
+ switch_mpm_config(d, val);
+ return;
+ }
+ } while (loop_limit-- > 0);
+ pr_err("%s: dual-edge irq failed to stabilize, %#08x != %#08x\n",
+ __func__, val, val2);
+}
+
+static void msm_gpio_irq_ack(struct irq_data *d)
+{
+ int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+
+ __msm_gpio_set_intr_status(gpio);
+ if (test_bit(gpio, msm_gpio.dual_edge_irqs))
+ msm_gpio_update_dual_edge_pos(d, gpio);
+ mb();
+}
+
+static void msm_gpio_irq_mask(struct irq_data *d)
+{
+ int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ __msm_gpio_set_intr_cfg_enable(gpio, 0);
+ __clear_bit(gpio, msm_gpio.enabled_irqs);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+ if (msm_gpio_irq_extn.irq_mask)
+ msm_gpio_irq_extn.irq_mask(d);
+
+}
+
+static void msm_gpio_irq_unmask(struct irq_data *d)
+{
+ int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ __set_bit(gpio, msm_gpio.enabled_irqs);
+ __msm_gpio_set_intr_cfg_enable(gpio, 1);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+ if (msm_gpio_irq_extn.irq_mask)
+ msm_gpio_irq_extn.irq_unmask(d);
+}
+
+static void msm_gpio_irq_disable(struct irq_data *d)
+{
+ if (msm_gpio_irq_extn.irq_disable)
+ msm_gpio_irq_extn.irq_disable(d);
+}
+
+static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+
+ if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
+ if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+ __set_bit(gpio, msm_gpio.dual_edge_irqs);
+ else
+ __clear_bit(gpio, msm_gpio.dual_edge_irqs);
+ } else {
+ __irq_set_handler_locked(d->irq, handle_level_irq);
+ __clear_bit(gpio, msm_gpio.dual_edge_irqs);
+ }
+
+ __msm_gpio_set_intr_cfg_type(gpio, flow_type);
+
+ if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+ msm_gpio_update_dual_edge_pos(d, gpio);
+
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+ if (msm_gpio_irq_extn.irq_set_type)
+ msm_gpio_irq_extn.irq_set_type(d, flow_type);
+
+ return 0;
+}
+
+/*
+ * When the summary IRQ is raised, any number of GPIO lines may be high.
+ * It is the job of the summary handler to find all those GPIO lines
+ * which have been set as summary IRQ lines and which are triggered,
+ * and to call their interrupt handlers.
+ */
+static irqreturn_t msm_summary_irq_handler(int irq, void *data)
+{
+ unsigned long i;
+ struct irq_desc *desc = irq_to_desc(irq);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
+
+ for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
+ i < NR_MSM_GPIOS;
+ i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
+ if (__msm_gpio_get_intr_status(i))
+ generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
+ i));
+ }
+
+ chained_irq_exit(chip, desc);
+ return IRQ_HANDLED;
+}
+
+static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
+
+ if (on) {
+ if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
+ irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
+ set_bit(gpio, msm_gpio.wake_irqs);
+ } else {
+ clear_bit(gpio, msm_gpio.wake_irqs);
+ if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
+ irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
+ }
+
+ if (msm_gpio_irq_extn.irq_set_wake)
+ msm_gpio_irq_extn.irq_set_wake(d, on);
+
+ return 0;
+}
+
+static struct irq_chip msm_gpio_irq_chip = {
+ .name = "msmgpio",
+ .irq_mask = msm_gpio_irq_mask,
+ .irq_unmask = msm_gpio_irq_unmask,
+ .irq_ack = msm_gpio_irq_ack,
+ .irq_set_type = msm_gpio_irq_set_type,
+ .irq_set_wake = msm_gpio_irq_set_wake,
+ .irq_disable = msm_gpio_irq_disable,
+};
+
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
+ * category than their parent, so it won't report false recursion.
+ */
+static struct lock_class_key msm_gpio_lock_class;
+
+static int __devinit msm_gpio_probe(void)
+{
+ int i, irq, ret;
+
+ spin_lock_init(&tlmm_lock);
+ bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
+ bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
+ bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
+ ret = gpiochip_add(&msm_gpio.gpio_chip);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
+ irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+ irq_set_lockdep_class(irq, &msm_gpio_lock_class);
+ irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
+ handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+
+ ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
+ IRQF_TRIGGER_HIGH, "msmgpio", NULL);
+ if (ret) {
+ pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
+ ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int __devexit msm_gpio_remove(void)
+{
+ int ret = gpiochip_remove(&msm_gpio.gpio_chip);
+
+ if (ret < 0)
+ return ret;
+
+ irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int msm_gpio_suspend(void)
+{
+ unsigned long irq_flags;
+ unsigned long i;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
+ __msm_gpio_set_intr_cfg_enable(i, 0);
+
+ for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
+ __msm_gpio_set_intr_cfg_enable(i, 1);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+ return 0;
+}
+
+void msm_gpio_show_resume_irq(void)
+{
+ unsigned long irq_flags;
+ int i, irq, intstat;
+
+ if (!msm_show_resume_irq_mask)
+ return;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
+ intstat = __msm_gpio_get_intr_status(i);
+ if (intstat) {
+ irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
+ pr_warning("%s: %d triggered\n",
+ __func__, irq);
+ }
+ }
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+}
+
+static void msm_gpio_resume(void)
+{
+ unsigned long irq_flags;
+ unsigned long i;
+
+ msm_gpio_show_resume_irq();
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
+ __msm_gpio_set_intr_cfg_enable(i, 0);
+
+ for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
+ __msm_gpio_set_intr_cfg_enable(i, 1);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+}
+#else
+#define msm_gpio_suspend NULL
+#define msm_gpio_resume NULL
+#endif
+
+static struct syscore_ops msm_gpio_syscore_ops = {
+ .suspend = msm_gpio_suspend,
+ .resume = msm_gpio_resume,
+};
+
+static int __init msm_gpio_init(void)
+{
+ msm_gpio_probe();
+ register_syscore_ops(&msm_gpio_syscore_ops);
+ return 0;
+}
+
+static void __exit msm_gpio_exit(void)
+{
+ unregister_syscore_ops(&msm_gpio_syscore_ops);
+ msm_gpio_remove();
+}
+
+postcore_initcall(msm_gpio_init);
+module_exit(msm_gpio_exit);
+
+static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
+ unsigned id, unsigned width, unsigned val)
+{
+ unsigned long irqflags;
+ u32 mask = (1 << width) - 1;
+ u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
+ u32 reg_val;
+
+ spin_lock_irqsave(&tlmm_lock, irqflags);
+ reg_val = __raw_readl(reg);
+ reg_val &= ~(mask << configs[id].off);
+ reg_val |= (val & mask) << configs[id].off;
+ __raw_writel(reg_val, reg);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irqflags);
+}
+
+void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
+{
+ msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
+}
+EXPORT_SYMBOL(msm_tlmm_set_hdrive);
+
+void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
+{
+ msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
+}
+EXPORT_SYMBOL(msm_tlmm_set_pull);
+
+int gpio_tlmm_config(unsigned config, unsigned disable)
+{
+ unsigned gpio = GPIO_PIN(config);
+
+ if (gpio > NR_MSM_GPIOS)
+ return -EINVAL;
+
+ __gpio_tlmm_config(config);
+ mb();
+
+ return 0;
+}
+EXPORT_SYMBOL(gpio_tlmm_config);
+
+int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+ unsigned int input_polarity)
+{
+ unsigned long irq_flags;
+
+ if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
+ return -EINVAL;
+
+ spin_lock_irqsave(&tlmm_lock, irq_flags);
+ __msm_gpio_install_direct_irq(gpio, irq, input_polarity);
+ mb();
+ spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(msm_gpio_install_direct_irq);
+
+#ifdef CONFIG_OF
+static int msm_gpio_domain_dt_translate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec,
+ unsigned int intsize,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ if (d->of_node != controller)
+ return -EINVAL;
+ if (intsize != 2)
+ return -EINVAL;
+
+ /* hwirq value */
+ *out_hwirq = intspec[0];
+
+ /* irq flags */
+ *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
+ return 0;
+}
+
+static struct irq_domain_ops msm_gpio_irq_domain_ops = {
+ .dt_translate = msm_gpio_domain_dt_translate,
+};
+
+int __init msm_gpio_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ struct irq_domain *domain = &msm_gpio.domain;
+ int start;
+
+ start = irq_domain_find_free_range(0, NR_MSM_GPIOS);
+ domain->irq_base = irq_alloc_descs(start, 0, NR_MSM_GPIOS,
+ numa_node_id());
+ if (IS_ERR_VALUE(domain->irq_base)) {
+ WARN(1, "Cannot allocate irq_descs @ IRQ%d\n", start);
+ return domain->irq_base;
+ }
+
+ domain->nr_irq = NR_MSM_GPIOS;
+ domain->of_node = of_node_get(node);
+ domain->priv = &msm_gpio;
+ domain->ops = &msm_gpio_irq_domain_ops;
+ irq_domain_add(domain);
+ msm_gpio.gpio_chip.of_node = of_node_get(node);
+ pr_debug("%s: irq_base = %u\n", __func__, domain->irq_base);
+
+ return 0;
+}
+#endif
+
+MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
+MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("sysdev:msmgpio");
diff --git a/drivers/gpio/gpio-msm-common.h b/drivers/gpio/gpio-msm-common.h
new file mode 100644
index 0000000..c9ea3da
--- /dev/null
+++ b/drivers/gpio/gpio-msm-common.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 __ARCH_ARM_MACH_MSM_GPIO_COMMON_H
+#define __ARCH_ARM_MACH_MSM_GPIO_COMMON_H
+
+extern int msm_show_resume_irq_mask;
+
+unsigned __msm_gpio_get_inout(unsigned gpio);
+void __msm_gpio_set_inout(unsigned gpio, unsigned val);
+void __msm_gpio_set_config_direction(unsigned gpio, int input, int val);
+void __msm_gpio_set_polarity(unsigned gpio, unsigned val);
+unsigned __msm_gpio_get_intr_status(unsigned gpio);
+void __msm_gpio_set_intr_status(unsigned gpio);
+unsigned __msm_gpio_get_intr_config(unsigned gpio);
+void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val);
+void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type);
+void __gpio_tlmm_config(unsigned config);
+void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+ unsigned int input_polarity);
+#endif
diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c
index ad436e0..bac9f8a 100644
--- a/drivers/gpio/gpio-msm-v2.c
+++ b/drivers/gpio/gpio-msm-v2.c
@@ -12,23 +12,15 @@
*/
#include <linux/bitmap.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/syscore_ops.h>
-#include <linux/irqdomain.h>
-#include <linux/of.h>
-#include <linux/err.h>
-
-#include <asm/mach/irq.h>
+#include <linux/irq.h>
#include <mach/msm_iomap.h>
#include <mach/gpiomux.h>
-#include <mach/mpm.h>
+#include "gpio-msm-common.h"
/* Bits of interest in the GPIO_IN_OUT register.
*/
@@ -75,54 +67,6 @@
DC_IRQ_ENABLE = BIT(3),
};
-enum msm_tlmm_register {
- SDC4_HDRV_PULL_CTL = 0x20a0,
- SDC3_HDRV_PULL_CTL = 0x20a4,
- SDC1_HDRV_PULL_CTL = 0x20a0,
-};
-
-struct tlmm_field_cfg {
- enum msm_tlmm_register reg;
- u8 off;
-};
-
-static const struct tlmm_field_cfg tlmm_hdrv_cfgs[] = {
- {SDC4_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC4_CLK */
- {SDC4_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC4_CMD */
- {SDC4_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC4_DATA */
- {SDC3_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC3_CLK */
- {SDC3_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC3_CMD */
- {SDC3_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC3_DATA */
- {SDC1_HDRV_PULL_CTL, 6}, /* TLMM_HDRV_SDC1_CLK */
- {SDC1_HDRV_PULL_CTL, 3}, /* TLMM_HDRV_SDC1_CMD */
- {SDC1_HDRV_PULL_CTL, 0}, /* TLMM_HDRV_SDC1_DATA */
-};
-
-static const struct tlmm_field_cfg tlmm_pull_cfgs[] = {
- {SDC4_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC4_CMD */
- {SDC4_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC4_DATA */
- {SDC3_HDRV_PULL_CTL, 14}, /* TLMM_PULL_SDC3_CLK */
- {SDC3_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC3_CMD */
- {SDC3_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC3_DATA */
- {SDC1_HDRV_PULL_CTL, 13}, /* TLMM_PULL_SDC1_CLK */
- {SDC1_HDRV_PULL_CTL, 11}, /* TLMM_PULL_SDC1_CMD */
- {SDC1_HDRV_PULL_CTL, 9}, /* TLMM_PULL_SDC1_DATA */
-};
-
-/*
- * Supported arch specific irq extension.
- * Default make them NULL.
- */
-struct irq_chip msm_gpio_irq_extn = {
- .irq_eoi = NULL,
- .irq_mask = NULL,
- .irq_unmask = NULL,
- .irq_retrigger = NULL,
- .irq_set_type = NULL,
- .irq_set_wake = NULL,
- .irq_disable = NULL,
-};
-
/*
* When a GPIO triggers, two separate decisions are made, controlled
* by two separate flags.
@@ -147,37 +91,6 @@
#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
-/**
- * struct msm_gpio_dev: the MSM8660 SoC GPIO device structure
- *
- * @enabled_irqs: a bitmap used to optimize the summary-irq handler. By
- * keeping track of which gpios are unmasked as irq sources, we avoid
- * having to do __raw_readl calls on hundreds of iomapped registers each time
- * the summary interrupt fires in order to locate the active interrupts.
- *
- * @wake_irqs: a bitmap for tracking which interrupt lines are enabled
- * as wakeup sources. When the device is suspended, interrupts which are
- * not wakeup sources are disabled.
- *
- * @dual_edge_irqs: a bitmap used to track which irqs are configured
- * as dual-edge, as this is not supported by the hardware and requires
- * some special handling in the driver.
- */
-struct msm_gpio_dev {
- struct gpio_chip gpio_chip;
- DECLARE_BITMAP(enabled_irqs, NR_MSM_GPIOS);
- DECLARE_BITMAP(wake_irqs, NR_MSM_GPIOS);
- DECLARE_BITMAP(dual_edge_irqs, NR_MSM_GPIOS);
- struct irq_domain domain;
-};
-
-static DEFINE_SPINLOCK(tlmm_lock);
-
-static inline struct msm_gpio_dev *to_msm_gpio_dev(struct gpio_chip *chip)
-{
- return container_of(chip, struct msm_gpio_dev, gpio_chip);
-}
-
static inline void set_gpio_bits(unsigned n, void __iomem *reg)
{
__raw_writel(__raw_readl(reg) | n, reg);
@@ -188,498 +101,113 @@
__raw_writel(__raw_readl(reg) & ~n, reg);
}
-static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+unsigned __msm_gpio_get_inout(unsigned gpio)
{
- int rc;
- rc = __raw_readl(GPIO_IN_OUT(offset)) & BIT(GPIO_IN_BIT);
- mb();
- return rc;
+ return __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
}
-static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+void __msm_gpio_set_inout(unsigned gpio, unsigned val)
{
- __raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(offset));
- mb();
+ __raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(gpio));
}
-static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+void __msm_gpio_set_config_direction(unsigned gpio, int input, int val)
{
- unsigned long irq_flags;
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
- clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
- return 0;
+ if (input)
+ clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+ else {
+ __msm_gpio_set_inout(gpio, val);
+ set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+ }
}
-static int msm_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset,
- int val)
+void __msm_gpio_set_polarity(unsigned gpio, unsigned val)
{
- unsigned long irq_flags;
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
- msm_gpio_set(chip, offset, val);
- set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(offset));
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
- return 0;
-}
-
-#ifdef CONFIG_OF
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
- struct irq_domain *domain = &g_dev->domain;
- return domain->irq_base + (offset - chip->base);
-}
-
-static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
-{
- struct msm_gpio_dev *g_dev = to_msm_gpio_dev(chip);
- struct irq_domain *domain = &g_dev->domain;
- return irq - domain->irq_base;
-}
-#else
-static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- return MSM_GPIO_TO_INT(offset - chip->base);
-}
-
-static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq)
-{
- return irq - MSM_GPIO_TO_INT(chip->base);
-}
-#endif
-
-static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- return msm_gpiomux_get(chip->base + offset);
-}
-
-static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- msm_gpiomux_put(chip->base + offset);
-}
-
-static struct msm_gpio_dev msm_gpio = {
- .gpio_chip = {
- .label = "msmgpio",
- .base = 0,
- .ngpio = NR_MSM_GPIOS,
- .direction_input = msm_gpio_direction_input,
- .direction_output = msm_gpio_direction_output,
- .get = msm_gpio_get,
- .set = msm_gpio_set,
- .to_irq = msm_gpio_to_irq,
- .request = msm_gpio_request,
- .free = msm_gpio_free,
- },
-};
-
-static void switch_mpm_config(struct irq_data *d, unsigned val)
-{
- /* switch the configuration in the mpm as well */
- if (!msm_gpio_irq_extn.irq_set_type)
- return;
-
if (val)
- msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_FALLING);
+ clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
else
- msm_gpio_irq_extn.irq_set_type(d, IRQF_TRIGGER_RISING);
+ set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
}
-/* For dual-edge interrupts in software, since the hardware has no
- * such support:
- *
- * At appropriate moments, this function may be called to flip the polarity
- * settings of both-edge irq lines to try and catch the next edge.
- *
- * The attempt is considered successful if:
- * - the status bit goes high, indicating that an edge was caught, or
- * - the input value of the gpio doesn't change during the attempt.
- * If the value changes twice during the process, that would cause the first
- * test to fail but would force the second, as two opposite
- * transitions would cause a detection no matter the polarity setting.
- *
- * The do-loop tries to sledge-hammer closed the timing hole between
- * the initial value-read and the polarity-write - if the line value changes
- * during that window, an interrupt is lost, the new polarity setting is
- * incorrect, and the first success test will fail, causing a retry.
- *
- * Algorithm comes from Google's msmgpio driver, see mach-msm/gpio.c.
- */
-static void msm_gpio_update_dual_edge_pos(struct irq_data *d, unsigned gpio)
+unsigned __msm_gpio_get_intr_status(unsigned gpio)
{
- int loop_limit = 100;
- unsigned val, val2, intstat;
-
- do {
- val = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
- if (val)
- clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
- else
- set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
- val2 = __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
- intstat = __raw_readl(GPIO_INTR_STATUS(gpio)) &
+ return __raw_readl(GPIO_INTR_STATUS(gpio)) &
BIT(INTR_STATUS_BIT);
- if (intstat || val == val2) {
- switch_mpm_config(d, val);
- return;
- }
- } while (loop_limit-- > 0);
- pr_err("%s: dual-edge irq failed to stabilize, "
- "interrupts dropped. %#08x != %#08x\n",
- __func__, val, val2);
}
-static void msm_gpio_irq_ack(struct irq_data *d)
+void __msm_gpio_set_intr_status(unsigned gpio)
{
- int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-
__raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
- if (test_bit(gpio, msm_gpio.dual_edge_irqs))
- msm_gpio_update_dual_edge_pos(d, gpio);
- mb();
}
-static void __msm_gpio_irq_mask(unsigned int gpio)
+unsigned __msm_gpio_get_intr_config(unsigned gpio)
{
- __raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
- clr_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
+ return __raw_readl(GPIO_INTR_CFG(gpio));
}
-static void msm_gpio_irq_mask(struct irq_data *d)
+void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val)
{
- int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
- unsigned long irq_flags;
+ if (val) {
+ set_gpio_bits(INTR_ENABLE, GPIO_INTR_CFG(gpio));
+ __raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
- spin_lock_irqsave(&tlmm_lock, irq_flags);
- __msm_gpio_irq_mask(gpio);
- __clear_bit(gpio, msm_gpio.enabled_irqs);
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
- if (msm_gpio_irq_extn.irq_mask)
- msm_gpio_irq_extn.irq_mask(d);
-
-}
-
-static void __msm_gpio_irq_unmask(unsigned int gpio)
-{
- set_gpio_bits(INTR_RAW_STATUS_EN | INTR_ENABLE, GPIO_INTR_CFG(gpio));
- __raw_writel(TARGET_PROC_SCORPION, GPIO_INTR_CFG_SU(gpio));
-}
-
-static void msm_gpio_irq_unmask(struct irq_data *d)
-{
- int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
- unsigned long irq_flags;
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
- __set_bit(gpio, msm_gpio.enabled_irqs);
- __msm_gpio_irq_unmask(gpio);
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
- if (msm_gpio_irq_extn.irq_mask)
- msm_gpio_irq_extn.irq_unmask(d);
-}
-
-static void msm_gpio_irq_disable(struct irq_data *d)
-{
- if (msm_gpio_irq_extn.irq_disable)
- msm_gpio_irq_extn.irq_disable(d);
-}
-
-static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
- int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
- unsigned long irq_flags;
- uint32_t bits;
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
-
- bits = __raw_readl(GPIO_INTR_CFG(gpio));
-
- if (flow_type & IRQ_TYPE_EDGE_BOTH) {
- bits |= INTR_DECT_CTL_EDGE;
- __irq_set_handler_locked(d->irq, handle_edge_irq);
- if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- __set_bit(gpio, msm_gpio.dual_edge_irqs);
- else
- __clear_bit(gpio, msm_gpio.dual_edge_irqs);
} else {
- bits &= ~INTR_DECT_CTL_EDGE;
- __irq_set_handler_locked(d->irq, handle_level_irq);
- __clear_bit(gpio, msm_gpio.dual_edge_irqs);
+ __raw_writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio));
+ clr_gpio_bits(INTR_ENABLE, GPIO_INTR_CFG(gpio));
}
+}
- if (flow_type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
- bits |= INTR_POL_CTL_HI;
+void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
+{
+ unsigned cfg;
+
+ cfg = __msm_gpio_get_intr_config(gpio);
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ cfg |= INTR_DECT_CTL_EDGE;
else
- bits &= ~INTR_POL_CTL_HI;
+ cfg &= ~INTR_DECT_CTL_EDGE;
- __raw_writel(bits, GPIO_INTR_CFG(gpio));
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+ cfg |= INTR_POL_CTL_HI;
+ else
+ cfg &= ~INTR_POL_CTL_HI;
- if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
- msm_gpio_update_dual_edge_pos(d, gpio);
+ /* RAW_STATUS_EN is left on for all gpio irqs. Due to the
+ * internal circuitry of TLMM, toggling the RAW_STATUS
+ * could cause the INTR_STATUS to be set for EDGE interrupts.
+ */
+ cfg |= INTR_RAW_STATUS_EN;
+ __raw_writel(cfg, GPIO_INTR_CFG(gpio));
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
+ /* Sometimes it might take a little while to update
+ * the interrupt status after the RAW_STATUS is enabled
+ */
+ udelay(5);
- if (msm_gpio_irq_extn.irq_set_type)
- msm_gpio_irq_extn.irq_set_type(d, flow_type);
+ /* Clear the interrupt status to clear out any spurious
+ * irq as a result of the above operation
+ */
+ __msm_gpio_set_intr_status(gpio);
- return 0;
}
-/*
- * When the summary IRQ is raised, any number of GPIO lines may be high.
- * It is the job of the summary handler to find all those GPIO lines
- * which have been set as summary IRQ lines and which are triggered,
- * and to call their interrupt handlers.
- */
-static irqreturn_t msm_summary_irq_handler(int irq, void *data)
-{
- unsigned long i;
- struct irq_desc *desc = irq_to_desc(irq);
- struct irq_chip *chip = irq_desc_get_chip(desc);
-
- chained_irq_enter(chip, desc);
-
- for (i = find_first_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
- i < NR_MSM_GPIOS;
- i = find_next_bit(msm_gpio.enabled_irqs, NR_MSM_GPIOS, i + 1)) {
- if (__raw_readl(GPIO_INTR_STATUS(i)) & BIT(INTR_STATUS_BIT))
- generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
- i));
- }
-
- chained_irq_exit(chip, desc);
- return IRQ_HANDLED;
-}
-
-static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
-{
- int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq);
-
- if (on) {
- if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
- irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 1);
- set_bit(gpio, msm_gpio.wake_irqs);
- } else {
- clear_bit(gpio, msm_gpio.wake_irqs);
- if (bitmap_empty(msm_gpio.wake_irqs, NR_MSM_GPIOS))
- irq_set_irq_wake(TLMM_MSM_SUMMARY_IRQ, 0);
- }
-
- if (msm_gpio_irq_extn.irq_set_wake)
- msm_gpio_irq_extn.irq_set_wake(d, on);
-
- return 0;
-}
-
-static struct irq_chip msm_gpio_irq_chip = {
- .name = "msmgpio",
- .irq_mask = msm_gpio_irq_mask,
- .irq_unmask = msm_gpio_irq_unmask,
- .irq_ack = msm_gpio_irq_ack,
- .irq_set_type = msm_gpio_irq_set_type,
- .irq_set_wake = msm_gpio_irq_set_wake,
- .irq_disable = msm_gpio_irq_disable,
-};
-
-/*
- * This lock class tells lockdep that GPIO irqs are in a different
- * category than their parent, so it won't report false recursion.
- */
-static struct lock_class_key msm_gpio_lock_class;
-
-static int __devinit msm_gpio_probe(void)
-{
- int i, irq, ret;
-
- spin_lock_init(&tlmm_lock);
- bitmap_zero(msm_gpio.enabled_irqs, NR_MSM_GPIOS);
- bitmap_zero(msm_gpio.wake_irqs, NR_MSM_GPIOS);
- bitmap_zero(msm_gpio.dual_edge_irqs, NR_MSM_GPIOS);
- ret = gpiochip_add(&msm_gpio.gpio_chip);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < msm_gpio.gpio_chip.ngpio; ++i) {
- irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
- irq_set_lockdep_class(irq, &msm_gpio_lock_class);
- irq_set_chip_and_handler(irq, &msm_gpio_irq_chip,
- handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
-
- ret = request_irq(TLMM_MSM_SUMMARY_IRQ, msm_summary_irq_handler,
- IRQF_TRIGGER_HIGH, "msmgpio", NULL);
- if (ret) {
- pr_err("Request_irq failed for TLMM_MSM_SUMMARY_IRQ - %d\n",
- ret);
- return ret;
- }
- return 0;
-}
-
-static int __devexit msm_gpio_remove(void)
-{
- int ret = gpiochip_remove(&msm_gpio.gpio_chip);
-
- if (ret < 0)
- return ret;
-
- irq_set_handler(TLMM_MSM_SUMMARY_IRQ, NULL);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int msm_gpio_suspend(void)
-{
- unsigned long irq_flags;
- unsigned long i;
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
- for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
- __msm_gpio_irq_mask(i);
-
- for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
- __msm_gpio_irq_unmask(i);
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
- return 0;
-}
-
-extern int msm_show_resume_irq_mask;
-
-void msm_gpio_show_resume_irq(void)
-{
- unsigned long irq_flags;
- int i, irq, intstat;
-
- if (!msm_show_resume_irq_mask)
- return;
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
- for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS) {
- intstat = __raw_readl(GPIO_INTR_STATUS(i)) &
- BIT(INTR_STATUS_BIT);
- if (intstat) {
- irq = msm_gpio_to_irq(&msm_gpio.gpio_chip, i);
- pr_warning("%s: %d triggered\n",
- __func__, irq);
- }
- }
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-}
-
-static void msm_gpio_resume(void)
-{
- unsigned long irq_flags;
- unsigned long i;
-
- msm_gpio_show_resume_irq();
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
- for_each_set_bit(i, msm_gpio.wake_irqs, NR_MSM_GPIOS)
- __msm_gpio_irq_mask(i);
-
- for_each_set_bit(i, msm_gpio.enabled_irqs, NR_MSM_GPIOS)
- __msm_gpio_irq_unmask(i);
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-}
-#else
-#define msm_gpio_suspend NULL
-#define msm_gpio_resume NULL
-#endif
-
-static struct syscore_ops msm_gpio_syscore_ops = {
- .suspend = msm_gpio_suspend,
- .resume = msm_gpio_resume,
-};
-
-static int __init msm_gpio_init(void)
-{
- msm_gpio_probe();
- register_syscore_ops(&msm_gpio_syscore_ops);
- return 0;
-}
-
-static void __exit msm_gpio_exit(void)
-{
- unregister_syscore_ops(&msm_gpio_syscore_ops);
- msm_gpio_remove();
-}
-
-postcore_initcall(msm_gpio_init);
-module_exit(msm_gpio_exit);
-
-static void msm_tlmm_set_field(const struct tlmm_field_cfg *configs,
- unsigned id, unsigned width, unsigned val)
-{
- unsigned long irqflags;
- u32 mask = (1 << width) - 1;
- u32 __iomem *reg = MSM_TLMM_BASE + configs[id].reg;
- u32 reg_val;
-
- spin_lock_irqsave(&tlmm_lock, irqflags);
- reg_val = __raw_readl(reg);
- reg_val &= ~(mask << configs[id].off);
- reg_val |= (val & mask) << configs[id].off;
- __raw_writel(reg_val, reg);
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irqflags);
-}
-
-void msm_tlmm_set_hdrive(enum msm_tlmm_hdrive_tgt tgt, int drv_str)
-{
- msm_tlmm_set_field(tlmm_hdrv_cfgs, tgt, 3, drv_str);
-}
-EXPORT_SYMBOL(msm_tlmm_set_hdrive);
-
-void msm_tlmm_set_pull(enum msm_tlmm_pull_tgt tgt, int pull)
-{
- msm_tlmm_set_field(tlmm_pull_cfgs, tgt, 2, pull);
-}
-EXPORT_SYMBOL(msm_tlmm_set_pull);
-
-int gpio_tlmm_config(unsigned config, unsigned disable)
+void __gpio_tlmm_config(unsigned config)
{
uint32_t flags;
unsigned gpio = GPIO_PIN(config);
- if (gpio > NR_MSM_GPIOS)
- return -EINVAL;
-
flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
((GPIO_FUNC(config) << 2) & (0xf << 2)) |
((GPIO_PULL(config) & 0x3));
__raw_writel(flags, GPIO_CONFIG(gpio));
- mb();
-
- return 0;
}
-EXPORT_SYMBOL(gpio_tlmm_config);
-int msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
unsigned int input_polarity)
{
- unsigned long irq_flags;
uint32_t bits;
- if (gpio >= NR_MSM_GPIOS || irq >= NR_TLMM_MSM_DIR_CONN_IRQ)
- return -EINVAL;
-
- spin_lock_irqsave(&tlmm_lock, irq_flags);
-
__raw_writel(__raw_readl(GPIO_CONFIG(gpio)) | BIT(GPIO_OE_BIT),
GPIO_CONFIG(gpio));
__raw_writel(__raw_readl(GPIO_INTR_CFG(gpio)) &
@@ -692,66 +220,4 @@
if (input_polarity)
bits |= DC_POLARITY_HI;
__raw_writel(bits, DIR_CONN_INTR_CFG_SU(irq));
-
- mb();
- spin_unlock_irqrestore(&tlmm_lock, irq_flags);
-
- return 0;
}
-EXPORT_SYMBOL(msm_gpio_install_direct_irq);
-
-#ifdef CONFIG_OF
-static int msm_gpio_domain_dt_translate(struct irq_domain *d,
- struct device_node *controller,
- const u32 *intspec,
- unsigned int intsize,
- unsigned long *out_hwirq,
- unsigned int *out_type)
-{
- if (d->of_node != controller)
- return -EINVAL;
- if (intsize != 2)
- return -EINVAL;
-
- /* hwirq value */
- *out_hwirq = intspec[0];
-
- /* irq flags */
- *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK;
- return 0;
-}
-
-static struct irq_domain_ops msm_gpio_irq_domain_ops = {
- .dt_translate = msm_gpio_domain_dt_translate,
-};
-
-int __init msm_gpio_of_init(struct device_node *node,
- struct device_node *parent)
-{
- struct irq_domain *domain = &msm_gpio.domain;
- int start;
-
- start = irq_domain_find_free_range(0, NR_MSM_GPIOS);
- domain->irq_base = irq_alloc_descs(start, 0, NR_MSM_GPIOS,
- numa_node_id());
- if (IS_ERR_VALUE(domain->irq_base)) {
- WARN(1, "Cannot allocate irq_descs @ IRQ%d\n", start);
- return domain->irq_base;
- }
-
- domain->irq_base = irq_domain_find_free_range(0, NR_MSM_GPIOS);
- domain->nr_irq = NR_MSM_GPIOS;
- domain->of_node = of_node_get(node);
- domain->priv = &msm_gpio;
- domain->ops = &msm_gpio_irq_domain_ops;
- irq_domain_add(domain);
- pr_debug("%s: irq_base = %u\n", __func__, domain->irq_base);
-
- return 0;
-}
-#endif
-
-MODULE_AUTHOR("Gregory Bean <gbean@codeaurora.org>");
-MODULE_DESCRIPTION("Driver for Qualcomm MSM TLMMv2 SoC GPIOs");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("sysdev:msmgpio");
diff --git a/drivers/gpio/gpio-msm-v3.c b/drivers/gpio/gpio-msm-v3.c
new file mode 100644
index 0000000..6086de3
--- /dev/null
+++ b/drivers/gpio/gpio-msm-v3.c
@@ -0,0 +1,232 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/msm_iomap.h>
+#include <mach/gpiomux.h>
+#include "gpio-msm-common.h"
+
+/* Bits of interest in the GPIO_IN_OUT register.
+ */
+enum {
+ GPIO_IN_BIT = 0,
+ GPIO_OUT_BIT = 1
+};
+
+/* Bits of interest in the GPIO_INTR_STATUS register.
+ */
+enum {
+ INTR_STATUS_BIT = 0,
+};
+
+/* Bits of interest in the GPIO_CFG register.
+ */
+enum {
+ GPIO_OE_BIT = 9,
+};
+
+/* Bits of interest in the GPIO_INTR_CFG register.
+ */
+enum {
+ INTR_ENABLE_BIT = 0,
+ INTR_POL_CTL_BIT = 1,
+ INTR_DECT_CTL_BIT = 2,
+ INTR_RAW_STATUS_EN_BIT = 4,
+ INTR_TARGET_PROC_BIT = 5,
+ INTR_DIR_CONN_EN_BIT = 8,
+};
+
+/*
+ * There is no 'DC_POLARITY_LO' because the GIC is incapable
+ * of asserting on falling edge or level-low conditions. Even though
+ * the registers allow for low-polarity inputs, the case can never arise.
+ */
+enum {
+ DC_GPIO_SEL_BIT = 0,
+ DC_POLARITY_BIT = 8,
+};
+
+/*
+ * When a GPIO triggers, two separate decisions are made, controlled
+ * by two separate flags.
+ *
+ * - First, INTR_RAW_STATUS_EN controls whether or not the GPIO_INTR_STATUS
+ * register for that GPIO will be updated to reflect the triggering of that
+ * gpio. If this bit is 0, this register will not be updated.
+ * - Second, INTR_ENABLE controls whether an interrupt is triggered.
+ *
+ * If INTR_ENABLE is set and INTR_RAW_STATUS_EN is NOT set, an interrupt
+ * can be triggered but the status register will not reflect it.
+ */
+#define INTR_RAW_STATUS_EN BIT(INTR_RAW_STATUS_EN_BIT)
+#define INTR_ENABLE BIT(INTR_ENABLE_BIT)
+#define INTR_POL_CTL_HI BIT(INTR_POL_CTL_BIT)
+#define INTR_DIR_CONN_EN BIT(INTR_DIR_CONN_EN_BIT)
+#define DC_POLARITY_HI BIT(DC_POLARITY_BIT)
+
+#define INTR_TARGET_PROC_APPS (4 << INTR_TARGET_PROC_BIT)
+#define INTR_TARGET_PROC_NONE (7 << INTR_TARGET_PROC_BIT)
+
+#define INTR_DECT_CTL_LEVEL (0 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_POS_EDGE (1 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_NEG_EDGE (2 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_DUAL_EDGE (3 << INTR_DECT_CTL_BIT)
+#define INTR_DECT_CTL_MASK (3 << INTR_DECT_CTL_BIT)
+
+#define GPIO_CONFIG(gpio) (MSM_TLMM_BASE + 0x1000 + (0x10 * (gpio)))
+#define GPIO_IN_OUT(gpio) (MSM_TLMM_BASE + 0x1004 + (0x10 * (gpio)))
+#define GPIO_INTR_CFG(gpio) (MSM_TLMM_BASE + 0x1008 + (0x10 * (gpio)))
+#define GPIO_INTR_STATUS(gpio) (MSM_TLMM_BASE + 0x100c + (0x10 * (gpio)))
+#define GPIO_DIR_CONN_INTR(intr) (MSM_TLMM_BASE + 0x2800 + (0x04 * (intr)))
+
+static inline void set_gpio_bits(unsigned n, void __iomem *reg)
+{
+ __raw_writel(__raw_readl(reg) | n, reg);
+}
+
+static inline void clr_gpio_bits(unsigned n, void __iomem *reg)
+{
+ __raw_writel(__raw_readl(reg) & ~n, reg);
+}
+
+unsigned __msm_gpio_get_inout(unsigned gpio)
+{
+ return __raw_readl(GPIO_IN_OUT(gpio)) & BIT(GPIO_IN_BIT);
+}
+
+void __msm_gpio_set_inout(unsigned gpio, unsigned val)
+{
+ __raw_writel(val ? BIT(GPIO_OUT_BIT) : 0, GPIO_IN_OUT(gpio));
+}
+
+void __msm_gpio_set_config_direction(unsigned gpio, int input, int val)
+{
+ if (input) {
+ clr_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+ } else {
+ __msm_gpio_set_inout(gpio, val);
+ set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+ }
+}
+
+void __msm_gpio_set_polarity(unsigned gpio, unsigned val)
+{
+ if (val)
+ clr_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
+ else
+ set_gpio_bits(INTR_POL_CTL_HI, GPIO_INTR_CFG(gpio));
+}
+
+unsigned __msm_gpio_get_intr_status(unsigned gpio)
+{
+ return __raw_readl(GPIO_INTR_STATUS(gpio)) &
+ BIT(INTR_STATUS_BIT);
+}
+
+void __msm_gpio_set_intr_status(unsigned gpio)
+{
+ __raw_writel(BIT(INTR_STATUS_BIT), GPIO_INTR_STATUS(gpio));
+}
+
+unsigned __msm_gpio_get_intr_config(unsigned gpio)
+{
+ return __raw_readl(GPIO_INTR_CFG(gpio));
+}
+
+void __msm_gpio_set_intr_cfg_enable(unsigned gpio, unsigned val)
+{
+ unsigned cfg;
+
+ cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+ if (val) {
+ cfg &= ~(INTR_TARGET_PROC_NONE | INTR_DIR_CONN_EN);
+ cfg |= INTR_ENABLE | INTR_TARGET_PROC_APPS;
+ } else {
+ cfg &= ~(INTR_TARGET_PROC_APPS | INTR_ENABLE);
+ cfg |= INTR_TARGET_PROC_NONE;
+ }
+ __raw_writel(cfg, GPIO_INTR_CFG(gpio));
+}
+
+void __msm_gpio_set_intr_cfg_type(unsigned gpio, unsigned type)
+{
+ unsigned cfg;
+
+ cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+ cfg &= ~INTR_DECT_CTL_MASK;
+ if (type == IRQ_TYPE_EDGE_RISING)
+ cfg |= INTR_DECT_CTL_POS_EDGE;
+ else if (type == IRQ_TYPE_EDGE_FALLING)
+ cfg |= INTR_DECT_CTL_NEG_EDGE;
+ else if (type == IRQ_TYPE_EDGE_BOTH)
+ cfg |= INTR_DECT_CTL_DUAL_EDGE;
+ else
+ cfg |= INTR_DECT_CTL_LEVEL;
+
+ if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_HIGH))
+ cfg |= INTR_POL_CTL_HI;
+ else
+ cfg &= ~INTR_POL_CTL_HI;
+
+ /* RAW_STATUS_EN is left on for all gpio irqs. Due to the
+ * internal circuitry of TLMM, toggling the RAW_STATUS
+ * could cause the INTR_STATUS to be set for EDGE interrupts.
+ */
+ cfg |= INTR_RAW_STATUS_EN;
+ __raw_writel(cfg, GPIO_INTR_CFG(gpio));
+
+ /* Sometimes it might take a little while to update
+ * the interrupt status after the RAW_STATUS is enabled
+ */
+ udelay(5);
+
+ /* Clear the interrupt status to clear out any spurious
+ * irq as a result of the above operation
+ */
+ __msm_gpio_set_intr_status(gpio);
+}
+
+void __gpio_tlmm_config(unsigned config)
+{
+ unsigned flags;
+ unsigned gpio = GPIO_PIN(config);
+
+ flags = ((GPIO_DIR(config) << 9) & (0x1 << 9)) |
+ ((GPIO_DRVSTR(config) << 6) & (0x7 << 6)) |
+ ((GPIO_FUNC(config) << 2) & (0xf << 2)) |
+ ((GPIO_PULL(config) & 0x3));
+ __raw_writel(flags, GPIO_CONFIG(gpio));
+}
+
+void __msm_gpio_install_direct_irq(unsigned gpio, unsigned irq,
+ unsigned int input_polarity)
+{
+ unsigned cfg;
+
+ set_gpio_bits(BIT(GPIO_OE_BIT), GPIO_CONFIG(gpio));
+ cfg = __raw_readl(GPIO_INTR_CFG(gpio));
+ cfg &= ~(INTR_TARGET_PROC_NONE | INTR_RAW_STATUS_EN | INTR_ENABLE);
+ cfg |= INTR_TARGET_PROC_APPS | INTR_DIR_CONN_EN;
+ __raw_writel(cfg, GPIO_INTR_CFG(gpio));
+
+ cfg = gpio;
+ if (input_polarity)
+ cfg |= DC_POLARITY_HI;
+ __raw_writel(cfg, GPIO_DIR_CONN_INTR(irq));
+}
diff --git a/drivers/gpio/qpnp-gpio.c b/drivers/gpio/qpnp-gpio.c
index d9a23e1..97859e5 100644
--- a/drivers/gpio/qpnp-gpio.c
+++ b/drivers/gpio/qpnp-gpio.c
@@ -22,6 +22,8 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
+#include <linux/export.h>
+#include <linux/module.h>
#include <linux/qpnp/gpio.h>
#include <linux/export.h>
@@ -504,27 +506,26 @@
}
static int qpnp_gpio_of_gpio_xlate(struct gpio_chip *gpio_chip,
- struct device_node *np,
- const void *gpio_spec, u32 *flags)
+ const struct of_phandle_args *gpio_spec,
+ u32 *flags)
{
struct qpnp_gpio_chip *q_chip = dev_get_drvdata(gpio_chip->dev);
struct qpnp_gpio_spec *q_spec;
- const __be32 *gpio = gpio_spec;
- u32 n = be32_to_cpup(gpio);
if (WARN_ON(gpio_chip->of_gpio_n_cells < 2)) {
pr_err("of_gpio_n_cells < 2\n");
return -EINVAL;
}
- q_spec = qpnp_pmic_gpio_get_spec(q_chip, n);
+ q_spec = qpnp_pmic_gpio_get_spec(q_chip, gpio_spec->args[0]);
if (!q_spec) {
- pr_err("no such PMIC gpio %u in device topology\n", n);
+ pr_err("no such PMIC gpio %u in device topology\n",
+ gpio_spec->args[0]);
return -EINVAL;
}
if (flags)
- *flags = be32_to_cpu(gpio[1]);
+ *flags = gpio_spec->args[1];
return q_spec->gpio_chip_idx;
}
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 7e84aa7..5c7ab3a 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -1898,7 +1898,8 @@
mutex_unlock(&dev->lock);
}
-int ion_secure_heap(struct ion_device *dev, int heap_id)
+int ion_secure_heap(struct ion_device *dev, int heap_id, int version,
+ void *data)
{
struct rb_node *n;
int ret_val = 0;
@@ -1915,7 +1916,7 @@
if (ION_HEAP(heap->id) != heap_id)
continue;
if (heap->ops->secure_heap)
- ret_val = heap->ops->secure_heap(heap);
+ ret_val = heap->ops->secure_heap(heap, version, data);
else
ret_val = -EINVAL;
break;
@@ -1924,7 +1925,8 @@
return ret_val;
}
-int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
+ void *data)
{
struct rb_node *n;
int ret_val = 0;
@@ -1941,7 +1943,7 @@
if (ION_HEAP(heap->id) != heap_id)
continue;
if (heap->ops->secure_heap)
- ret_val = heap->ops->unsecure_heap(heap);
+ ret_val = heap->ops->unsecure_heap(heap, version, data);
else
ret_val = -EINVAL;
break;
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index a857988a..c5e9caf 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -40,6 +40,7 @@
#include <asm/mach/map.h>
#include <asm/cacheflush.h>
+#include "msm/ion_cp_common.h"
/**
* struct ion_cp_heap - container for the heap and shared heap data
@@ -97,6 +98,7 @@
int iommu_map_all;
int iommu_2x_map_domain;
unsigned int has_outer_cache;
+ atomic_t protect_cnt;
};
enum {
@@ -105,10 +107,12 @@
};
static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
- unsigned int permission_type);
+ unsigned int permission_type, int version,
+ void *data);
static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
- unsigned int permission_type);
+ unsigned int permission_type, int version,
+ void *data);
/**
* Get the total number of kernel mappings.
@@ -125,13 +129,13 @@
* the correct FMEM state if this heap is a reusable heap.
* Must be called with heap->lock locked.
*/
-static int ion_cp_protect(struct ion_heap *heap)
+static int ion_cp_protect(struct ion_heap *heap, int version, void *data)
{
struct ion_cp_heap *cp_heap =
container_of(heap, struct ion_cp_heap, heap);
int ret_value = 0;
- if (cp_heap->heap_protected == HEAP_NOT_PROTECTED) {
+ if (atomic_inc_return(&cp_heap->protect_cnt) == 1) {
/* Make sure we are in C state when the heap is protected. */
if (cp_heap->reusable && !cp_heap->allocated_bytes) {
ret_value = fmem_set_state(FMEM_C_STATE);
@@ -140,7 +144,8 @@
}
ret_value = ion_cp_protect_mem(cp_heap->secure_base,
- cp_heap->secure_size, cp_heap->permission_type);
+ cp_heap->secure_size, cp_heap->permission_type,
+ version, data);
if (ret_value) {
pr_err("Failed to protect memory for heap %s - "
"error code: %d\n", heap->name, ret_value);
@@ -150,6 +155,7 @@
pr_err("%s: unable to transition heap to T-state\n",
__func__);
}
+ atomic_dec(&cp_heap->protect_cnt);
} else {
cp_heap->heap_protected = HEAP_PROTECTED;
pr_debug("Protected heap %s @ 0x%lx\n",
@@ -157,6 +163,9 @@
}
}
out:
+ pr_debug("%s: protect count is %d\n", __func__,
+ atomic_read(&cp_heap->protect_cnt));
+ BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0);
return ret_value;
}
@@ -165,15 +174,15 @@
* the correct FMEM state if this heap is a reusable heap.
* Must be called with heap->lock locked.
*/
-static void ion_cp_unprotect(struct ion_heap *heap)
+static void ion_cp_unprotect(struct ion_heap *heap, int version, void *data)
{
struct ion_cp_heap *cp_heap =
container_of(heap, struct ion_cp_heap, heap);
- if (cp_heap->heap_protected == HEAP_PROTECTED) {
+ if (atomic_dec_and_test(&cp_heap->protect_cnt)) {
int error_code = ion_cp_unprotect_mem(
cp_heap->secure_base, cp_heap->secure_size,
- cp_heap->permission_type);
+ cp_heap->permission_type, version, data);
if (error_code) {
pr_err("Failed to un-protect memory for heap %s - "
"error code: %d\n", heap->name, error_code);
@@ -189,6 +198,9 @@
}
}
}
+ pr_debug("%s: protect count is %d\n", __func__,
+ atomic_read(&cp_heap->protect_cnt));
+ BUG_ON(atomic_read(&cp_heap->protect_cnt) < 0);
}
ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap,
@@ -641,14 +653,14 @@
return 0;
}
-int ion_cp_secure_heap(struct ion_heap *heap)
+int ion_cp_secure_heap(struct ion_heap *heap, int version, void *data)
{
int ret_value;
struct ion_cp_heap *cp_heap =
container_of(heap, struct ion_cp_heap, heap);
mutex_lock(&cp_heap->lock);
if (cp_heap->umap_count == 0 && cp_heap->kmap_cached_count == 0) {
- ret_value = ion_cp_protect(heap);
+ ret_value = ion_cp_protect(heap, version, data);
} else {
pr_err("ION cannot secure heap with outstanding mappings: "
"User space: %lu, kernel space (cached): %lu\n",
@@ -660,13 +672,13 @@
return ret_value;
}
-int ion_cp_unsecure_heap(struct ion_heap *heap)
+int ion_cp_unsecure_heap(struct ion_heap *heap, int version, void *data)
{
int ret_value = 0;
struct ion_cp_heap *cp_heap =
container_of(heap, struct ion_cp_heap, heap);
mutex_lock(&cp_heap->lock);
- ion_cp_unprotect(heap);
+ ion_cp_unprotect(heap, version, data);
mutex_unlock(&cp_heap->lock);
return ret_value;
}
@@ -925,6 +937,7 @@
cp_heap->secure_base = cp_heap->base;
cp_heap->secure_size = heap_data->size;
cp_heap->has_outer_cache = heap_data->has_outer_cache;
+ atomic_set(&cp_heap->protect_cnt, 0);
if (heap_data->extra_data) {
struct ion_cp_heap_pdata *extra_data =
heap_data->extra_data;
@@ -991,8 +1004,7 @@
unsigned char lock;
} __attribute__ ((__packed__));
-
-static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+static int ion_cp_protect_mem_v1(unsigned int phy_base, unsigned int size,
unsigned int permission_type)
{
struct cp_lock_msg cmd;
@@ -1005,7 +1017,7 @@
&cmd, sizeof(cmd), NULL, 0);
}
-static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+static int ion_cp_unprotect_mem_v1(unsigned int phy_base, unsigned int size,
unsigned int permission_type)
{
struct cp_lock_msg cmd;
@@ -1017,3 +1029,70 @@
return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
&cmd, sizeof(cmd), NULL, 0);
}
+
+#define V2_CHUNK_SIZE SZ_1M
+
+static int ion_cp_change_mem_v2(unsigned int phy_base, unsigned int size,
+ void *data, int lock)
+{
+ enum cp_mem_usage usage = (enum cp_mem_usage) data;
+ unsigned long *chunk_list;
+ int nchunks;
+ int ret;
+ int i;
+
+ if (usage < 0 || usage >= MAX_USAGE)
+ return -EINVAL;
+
+ if (!IS_ALIGNED(size, V2_CHUNK_SIZE)) {
+ pr_err("%s: heap size is not aligned to %x\n",
+ __func__, V2_CHUNK_SIZE);
+ return -EINVAL;
+ }
+
+ nchunks = size / V2_CHUNK_SIZE;
+
+ chunk_list = allocate_contiguous_ebi(sizeof(unsigned long)*nchunks,
+ SZ_4K, 0);
+ if (!chunk_list)
+ return -ENOMEM;
+
+ for (i = 0; i < nchunks; i++)
+ chunk_list[i] = phy_base + i * V2_CHUNK_SIZE;
+
+ ret = ion_cp_change_chunks_state(memory_pool_node_paddr(chunk_list),
+ nchunks, V2_CHUNK_SIZE, usage, lock);
+
+ free_contiguous_memory(chunk_list);
+ return ret;
+}
+
+static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+ unsigned int permission_type, int version,
+ void *data)
+{
+ switch (version) {
+ case ION_CP_V1:
+ return ion_cp_protect_mem_v1(phy_base, size, permission_type);
+ case ION_CP_V2:
+ return ion_cp_change_mem_v2(phy_base, size, data,
+ SCM_CP_PROTECT);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+ unsigned int permission_type, int version,
+ void *data)
+{
+ switch (version) {
+ case ION_CP_V1:
+ return ion_cp_unprotect_mem_v1(phy_base, size, permission_type);
+ case ION_CP_V2:
+ return ion_cp_change_mem_v2(phy_base, size, data,
+ SCM_CP_UNPROTECT);
+ default:
+ return -EINVAL;
+ }
+}
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index 621144b..9ea6f2b 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -196,7 +196,7 @@
data->mapped_size, align,
&data->iova_addr);
- if (!data->iova_addr)
+ if (ret)
goto out;
domain = msm_get_iommu_domain(domain_num);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 6d636ee..6940e2f 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -158,8 +158,8 @@
void (*unmap_iommu)(struct ion_iommu_map *data);
int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
const struct rb_root *mem_map);
- int (*secure_heap)(struct ion_heap *heap);
- int (*unsecure_heap)(struct ion_heap *heap);
+ int (*secure_heap)(struct ion_heap *heap, int version, void *data);
+ int (*unsecure_heap)(struct ion_heap *heap, int version, void *data);
};
/**
diff --git a/drivers/gpu/ion/msm/Makefile b/drivers/gpu/ion/msm/Makefile
index bedd8d2..1893405 100644
--- a/drivers/gpu/ion/msm/Makefile
+++ b/drivers/gpu/ion/msm/Makefile
@@ -1 +1 @@
-obj-y += msm_ion.o
+obj-y += msm_ion.o ion_cp_common.o
diff --git a/drivers/gpu/ion/msm/ion_cp_common.c b/drivers/gpu/ion/msm/ion_cp_common.c
new file mode 100644
index 0000000..b274ba2
--- /dev/null
+++ b/drivers/gpu/ion/msm/ion_cp_common.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Google, Inc
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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/types.h>
+#include <mach/scm.h>
+
+#include "ion_cp_common.h"
+
+#define MEM_PROTECT_LOCK_ID 0x05
+
+struct cp2_mem_chunks {
+ unsigned int *chunk_list;
+ unsigned int chunk_list_size;
+ unsigned int chunk_size;
+} __attribute__ ((__packed__));
+
+struct cp2_lock_req {
+ struct cp2_mem_chunks chunks;
+ unsigned int mem_usage;
+ unsigned int lock;
+} __attribute__ ((__packed__));
+
+int ion_cp_change_chunks_state(unsigned long chunks, unsigned int nchunks,
+ unsigned int chunk_size,
+ enum cp_mem_usage usage,
+ int lock)
+{
+ struct cp2_lock_req request;
+
+ request.mem_usage = usage;
+ request.lock = lock;
+
+ request.chunks.chunk_list = (unsigned int *)chunks;
+ request.chunks.chunk_list_size = nchunks;
+ request.chunks.chunk_size = chunk_size;
+
+ return scm_call(SCM_SVC_CP, MEM_PROTECT_LOCK_ID,
+ &request, sizeof(request), NULL, 0);
+
+}
+
diff --git a/drivers/gpu/ion/msm/ion_cp_common.h b/drivers/gpu/ion/msm/ion_cp_common.h
new file mode 100644
index 0000000..69dd19e
--- /dev/null
+++ b/drivers/gpu/ion/msm/ion_cp_common.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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 ION_CP_COMMON_H
+#define ION_CP_COMMON_H
+
+#include <asm-generic/errno-base.h>
+#include <linux/ion.h>
+
+#define ION_CP_V1 1
+#define ION_CP_V2 2
+
+#if defined(CONFIG_ION_MSM)
+/*
+ * ion_cp2_protect_mem - secures memory via trustzone
+ *
+ * @chunks - physical address of the array containing the chunks to
+ * be locked down
+ * @nchunks - number of entries in the array
+ * @chunk_size - size of each memory chunk
+ * @usage - usage hint
+ * @lock - 1 for lock, 0 for unlock
+ *
+ * return value is the result of the scm call
+ */
+int ion_cp_change_chunks_state(unsigned long chunks, unsigned int nchunks,
+ unsigned int chunk_size, enum cp_mem_usage usage,
+ int lock);
+
+#else
+static inline int ion_cp_change_chunks_state(unsigned long chunks,
+ unsigned int nchunks, unsigned int chunk_size,
+ enum cp_mem_usage usage, int lock)
+{
+ return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index f6a4cf4..eec3fe0 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -21,6 +21,7 @@
#include <mach/ion.h>
#include <mach/msm_memtypes.h>
#include "../ion_priv.h"
+#include "ion_cp_common.h"
static struct ion_device *idev;
static int num_heaps;
@@ -35,16 +36,28 @@
int msm_ion_secure_heap(int heap_id)
{
- return ion_secure_heap(idev, heap_id);
+ return ion_secure_heap(idev, heap_id, ION_CP_V1, NULL);
}
EXPORT_SYMBOL(msm_ion_secure_heap);
int msm_ion_unsecure_heap(int heap_id)
{
- return ion_unsecure_heap(idev, heap_id);
+ return ion_unsecure_heap(idev, heap_id, ION_CP_V1, NULL);
}
EXPORT_SYMBOL(msm_ion_unsecure_heap);
+int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+ return ion_secure_heap(idev, heap_id, ION_CP_V2, (void *)usage);
+}
+EXPORT_SYMBOL(msm_ion_secure_heap_2_0);
+
+int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+ return ion_unsecure_heap(idev, heap_id, ION_CP_V2, (void *)usage);
+}
+EXPORT_SYMBOL(msm_ion_unsecure_heap_2_0);
+
int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
void *vaddr, unsigned long len, unsigned int cmd)
{
diff --git a/drivers/gpu/msm/a3xx_reg.h b/drivers/gpu/msm/a3xx_reg.h
index 35af06e..bd58b4e 100644
--- a/drivers/gpu/msm/a3xx_reg.h
+++ b/drivers/gpu/msm/a3xx_reg.h
@@ -46,6 +46,7 @@
#define A3XX_RBBM_HW_VERSION 0x000
#define A3XX_RBBM_HW_RELEASE 0x001
#define A3XX_RBBM_HW_CONFIGURATION 0x002
+#define A3XX_RBBM_CLOCK_CTL 0x010
#define A3XX_RBBM_SP_HYST_CNT 0x012
#define A3XX_RBBM_SW_RESET_CMD 0x018
#define A3XX_RBBM_AHB_CTL0 0x020
@@ -248,10 +249,6 @@
#define A3XX_VBIF_ARB_CTL 0x303C
#define A3XX_VBIF_OUT_AXI_AOOO_EN 0x305E
#define A3XX_VBIF_OUT_AXI_AOOO 0x305F
-#define A3XX_VBIF_ERR_PENDING 0x3064
-#define A3XX_VBIF_ERR_MASK 0x3066
-#define A3XX_VBIF_ERR_CLEAR 0x3067
-#define A3XX_VBIF_ERR_INFO 0x3068
/* Bit flags for RBBM_CTL */
#define RBBM_RBBM_CTL_RESET_PWR_CTR1 (1 << 1)
@@ -511,4 +508,7 @@
#define RBBM_BLOCK_ID_MARB_2 0x2a
#define RBBM_BLOCK_ID_MARB_3 0x2b
+/* RBBM_CLOCK_CTL default value */
+#define A3XX_RBBM_CLOCK_CTL_DEFAULT 0x00000000
+
#endif
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 66baee1..4991a2e 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -156,7 +156,7 @@
"a225_pm4.fw", "a225_pfp.fw", &adreno_a2xx_gpudev,
1536, 768, 3, SZ_512K },
/* A3XX doesn't use the pix_shader_start */
- { ADRENO_REV_A305, 3, 0, 5, 0,
+ { ADRENO_REV_A305, 3, 0, 5, ANY_ID,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_256K },
/* A3XX doesn't use the pix_shader_start */
@@ -254,7 +254,7 @@
int sizedwords = 0;
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct kgsl_memdesc **reg_map_desc;
- void *reg_map_array;
+ void *reg_map_array = NULL;
int num_iommu_units, i;
if (!adreno_dev->drawctxt_active)
@@ -500,8 +500,9 @@
* thing and set the chip_id based on the SoC
*/
+ unsigned int version = socinfo_get_version();
+
if (cpu_is_apq8064()) {
- unsigned int version = socinfo_get_version();
/* A320 */
majorid = 2;
@@ -518,10 +519,21 @@
else
patchid = 0;
} else if (cpu_is_msm8930()) {
+
/* A305 */
majorid = 0;
minorid = 5;
- patchid = 0;
+
+ /*
+ * V1.2 has some GPU work arounds that we need to communicate
+ * up to user space via the patchid
+ */
+
+ if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
+ (SOCINFO_VERSION_MINOR(version) == 2))
+ patchid = 2;
+ else
+ patchid = 0;
}
return (0x03 << 24) | (majorid << 16) | (minorid << 8) | patchid;
@@ -1580,10 +1592,17 @@
adreno_dev->gpudev->irq_control(adreno_dev, state);
}
-static unsigned int adreno_gpuid(struct kgsl_device *device)
+static unsigned int adreno_gpuid(struct kgsl_device *device,
+ unsigned int *chipid)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ /* Some applications need to know the chip ID too, so pass
+ * that as a parameter */
+
+ if (chipid != NULL)
+ *chipid = adreno_dev->chip_id;
+
/* Standard KGSL gpuid format:
* top word is 0x0002 for 2D or 0x0003 for 3D
* Bottom word is core specific identifer
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 4ce56a4..feaa36f 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -46,6 +46,8 @@
#define ADRENO_ISTORE_START 0x5000 /* Istore offset */
+#define ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW 50
+
enum adreno_gpurev {
ADRENO_REV_UNKNOWN = 0,
ADRENO_REV_A200 = 200,
@@ -90,11 +92,14 @@
unsigned int reg_rbbm_status;
unsigned int reg_cp_pfp_ucode_data;
unsigned int reg_cp_pfp_ucode_addr;
+ /* keeps track of when we need to execute the draw workaround code */
+ int ctx_switches_since_last_draw;
/* GPU specific function hooks */
int (*ctxt_create)(struct adreno_device *, struct adreno_context *);
void (*ctxt_save)(struct adreno_device *, struct adreno_context *);
void (*ctxt_restore)(struct adreno_device *, struct adreno_context *);
+ void (*ctxt_draw_workaround)(struct adreno_device *);
irqreturn_t (*irq_handler)(struct adreno_device *);
void (*irq_control)(struct adreno_device *, int);
void * (*snapshot)(struct adreno_device *, void *, int *, int);
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index 7ccfd3f..d846d3d 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -1450,11 +1450,61 @@
return ret;
}
+static void a2xx_drawctxt_workaround(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ unsigned int cmd[11];
+ unsigned int *cmds = &cmd[0];
+
+ if (adreno_is_a225(adreno_dev)) {
+ adreno_dev->gpudev->ctx_switches_since_last_draw++;
+ /* If there have been > than
+ * ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW calls to context
+ * switches w/o gmem being saved then we need to execute
+ * this workaround */
+ if (adreno_dev->gpudev->ctx_switches_since_last_draw >
+ ADRENO_NUM_CTX_SWITCH_ALLOWED_BEFORE_DRAW)
+ adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
+ else
+ return;
+ /*
+ * Issue an empty draw call to avoid possible hangs due to
+ * repeated idles without intervening draw calls.
+ * On adreno 225 the PC block has a cache that is only
+ * flushed on draw calls and repeated idles can make it
+ * overflow. The gmem save path contains draw calls so
+ * this workaround isn't needed there.
+ */
+ *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
+ *cmds++ = (0x4 << 16) | (REG_PA_SU_SC_MODE_CNTL - 0x2000);
+ *cmds++ = 0;
+ *cmds++ = cp_type3_packet(CP_DRAW_INDX, 5);
+ *cmds++ = 0;
+ *cmds++ = 1<<14;
+ *cmds++ = 0;
+ *cmds++ = device->mmu.setstate_memory.gpuaddr;
+ *cmds++ = 0;
+ *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
+ *cmds++ = 0x00000000;
+ } else {
+ /* On Adreno 20x/220, if the events for shader space reuse
+ * gets dropped, the CP block would wait indefinitely.
+ * Sending CP_SET_SHADER_BASES packet unblocks the CP from
+ * this wait.
+ */
+ *cmds++ = cp_type3_packet(CP_SET_SHADER_BASES, 1);
+ *cmds++ = adreno_encode_istore_size(adreno_dev)
+ | adreno_dev->pix_shader_start;
+ }
+
+ adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
+ &cmd[0], cmds - cmd);
+}
+
static void a2xx_drawctxt_save(struct adreno_device *adreno_dev,
struct adreno_context *context)
{
struct kgsl_device *device = &adreno_dev->dev;
- unsigned int cmd[22];
if (context == NULL)
return;
@@ -1499,33 +1549,11 @@
adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_NONE,
context->chicken_restore, 3);
}
+ adreno_dev->gpudev->ctx_switches_since_last_draw = 0;
context->flags |= CTXT_FLAGS_GMEM_RESTORE;
- } else if (adreno_is_a225(adreno_dev)) {
- unsigned int *cmds = &cmd[0];
- /*
- * Issue an empty draw call to avoid possible hangs due to
- * repeated idles without intervening draw calls.
- * On adreno 225 the PC block has a cache that is only
- * flushed on draw calls and repeated idles can make it
- * overflow. The gmem save path contains draw calls so
- * this workaround isn't needed there.
- */
- *cmds++ = cp_type3_packet(CP_SET_CONSTANT, 2);
- *cmds++ = (0x4 << 16) | (REG_PA_SU_SC_MODE_CNTL - 0x2000);
- *cmds++ = 0;
- *cmds++ = cp_type3_packet(CP_DRAW_INDX, 5);
- *cmds++ = 0;
- *cmds++ = 1<<14;
- *cmds++ = 0;
- *cmds++ = device->mmu.setstate_memory.gpuaddr;
- *cmds++ = 0;
- *cmds++ = cp_type3_packet(CP_WAIT_FOR_IDLE, 1);
- *cmds++ = 0x00000000;
-
- adreno_ringbuffer_issuecmds(device, KGSL_CMD_FLAGS_PMODE,
- &cmd[0], 11);
- }
+ } else if (adreno_is_a2xx(adreno_dev))
+ a2xx_drawctxt_workaround(adreno_dev);
}
static void a2xx_drawctxt_restore(struct adreno_device *adreno_dev,
@@ -1983,6 +2011,7 @@
.ctxt_create = a2xx_drawctxt_create,
.ctxt_save = a2xx_drawctxt_save,
.ctxt_restore = a2xx_drawctxt_restore,
+ .ctxt_draw_workaround = a2xx_drawctxt_workaround,
.irq_handler = a2xx_irq_handler,
.irq_control = a2xx_irq_control,
.snapshot = a2xx_snapshot,
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 09eae17..58a0963 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -433,6 +433,9 @@
unsigned int *cmds = tmp_ctx.cmd;
unsigned int *start = cmds;
+ *cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
+ *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 3);
*cmds++ = CP_REG(A3XX_RB_MODE_CONTROL);
@@ -1162,6 +1165,9 @@
unsigned int *cmds = tmp_ctx.cmd;
unsigned int *start = cmds;
+ *cmds++ = cp_type0_packet(A3XX_RBBM_CLOCK_CTL, 1);
+ *cmds++ = A3XX_RBBM_CLOCK_CTL_DEFAULT;
+
*cmds++ = cp_type3_packet(CP_SET_CONSTANT, 5);
*cmds++ = CP_REG(A3XX_HLSQ_CONTROL_0_REG);
/* HLSQ_CONTROL_0_REG */
@@ -2336,39 +2342,6 @@
adreno_ringbuffer_submit(rb);
}
-#define VBIF_MAX_CLIENTS 6
-
-static void a3xx_vbif_callback(struct adreno_device *adreno_dev,
- unsigned int status)
-{
- struct kgsl_device *device = &adreno_dev->dev;
- int i;
- char str[80], *ptr = str;
- int slen = sizeof(str) - 1;
-
- KGSL_DRV_INFO(device, "VBIF error | status=%X\n",
- status);
-
- for (i = 0; i < VBIF_MAX_CLIENTS; i++) {
- if (status & (1 << i)) {
- unsigned int err;
- int ret;
-
- adreno_regwrite(device, A3XX_VBIF_ERR_INFO, i);
- adreno_regread(device, A3XX_VBIF_ERR_INFO, &err);
-
- ret = snprintf(ptr, slen, "%d:%8.8X ", i, err);
- ptr += ret;
- slen -= ret;
- }
- }
-
- KGSL_DRV_INFO(device, "%s\n", str);
-
- /* Clear the errors */
- adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, status);
-}
-
static void a3xx_err_callback(struct adreno_device *adreno_dev, int bit)
{
struct kgsl_device *device = &adreno_dev->dev;
@@ -2442,37 +2415,35 @@
static void a3xx_cp_callback(struct adreno_device *adreno_dev, int irq)
{
- struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ struct kgsl_device *device = &adreno_dev->dev;
if (irq == A3XX_INT_CP_RB_INT) {
unsigned int context_id;
- kgsl_sharedmem_readl(&adreno_dev->dev.memstore,
- &context_id,
+ kgsl_sharedmem_readl(&device->memstore, &context_id,
KGSL_MEMSTORE_OFFSET(KGSL_MEMSTORE_GLOBAL,
current_context));
if (context_id < KGSL_MEMSTORE_MAX) {
- kgsl_sharedmem_writel(&rb->device->memstore,
+ kgsl_sharedmem_writel(&device->memstore,
KGSL_MEMSTORE_OFFSET(context_id,
ts_cmp_enable), 0);
wmb();
}
- KGSL_CMD_WARN(rb->device, "ringbuffer rb interrupt\n");
+ KGSL_CMD_WARN(device, "ringbuffer rb interrupt\n");
}
- wake_up_interruptible_all(&rb->device->wait_queue);
+ wake_up_interruptible_all(&device->wait_queue);
/* Schedule work to free mem and issue ibs */
- queue_work(rb->device->work_queue, &rb->device->ts_expired_ws);
+ queue_work(device->work_queue, &device->ts_expired_ws);
- atomic_notifier_call_chain(&rb->device->ts_notifier_list,
- rb->device->id, NULL);
+ atomic_notifier_call_chain(&device->ts_notifier_list,
+ device->id, NULL);
}
#define A3XX_IRQ_CALLBACK(_c) { .func = _c }
#define A3XX_INT_MASK \
((1 << A3XX_INT_RBBM_AHB_ERROR) | \
- (1 << A3XX_INT_RBBM_REG_TIMEOUT) | \
(1 << A3XX_INT_RBBM_ATB_BUS_OVERFLOW) | \
(1 << A3XX_INT_CP_T0_PACKET_IN_IB) | \
(1 << A3XX_INT_CP_OPCODE_ERROR) | \
@@ -2545,15 +2516,6 @@
if (status)
adreno_regwrite(&adreno_dev->dev, A3XX_RBBM_INT_CLEAR_CMD,
status);
-
- /* Check for VBIF errors */
- adreno_regread(&adreno_dev->dev, A3XX_VBIF_ERR_PENDING, &status);
-
- if (status) {
- a3xx_vbif_callback(adreno_dev, status);
- ret = IRQ_HANDLED;
- }
-
return ret;
}
@@ -2561,17 +2523,10 @@
{
struct kgsl_device *device = &adreno_dev->dev;
- if (state) {
+ if (state)
adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, A3XX_INT_MASK);
-
- /* Enable VBIF interrupts - write 0 to enable them all */
- adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0);
- /* Clear outstanding VBIF errors */
- adreno_regwrite(device, A3XX_VBIF_ERR_CLEAR, 0x3F);
- } else {
+ else
adreno_regwrite(device, A3XX_RBBM_INT_0_MASK, 0);
- adreno_regwrite(device, A3XX_VBIF_ERR_MASK, 0xFFFFFFFF);
- }
}
static unsigned int a3xx_busy_cycles(struct adreno_device *adreno_dev)
@@ -2671,6 +2626,7 @@
.ctxt_create = a3xx_drawctxt_create,
.ctxt_save = a3xx_drawctxt_save,
.ctxt_restore = a3xx_drawctxt_restore,
+ .ctxt_draw_workaround = NULL,
.rb_init = a3xx_rb_init,
.irq_control = a3xx_irq_control,
.irq_handler = a3xx_irq_handler,
diff --git a/drivers/gpu/msm/adreno_a3xx_snapshot.c b/drivers/gpu/msm/adreno_a3xx_snapshot.c
index c8c7c44..60aab64 100644
--- a/drivers/gpu/msm/adreno_a3xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a3xx_snapshot.c
@@ -19,6 +19,29 @@
#define DEBUG_SECTION_SZ(_dwords) (((_dwords) * sizeof(unsigned int)) \
+ sizeof(struct kgsl_snapshot_debug))
+#define SHADER_MEMORY_SIZE 0x4000
+
+static int a3xx_snapshot_shader_memory(struct kgsl_device *device,
+ void *snapshot, int remain, void *priv)
+{
+ struct kgsl_snapshot_debug *header = snapshot;
+ unsigned int *data = snapshot + sizeof(*header);
+ int i;
+
+ if (remain < DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE)) {
+ SNAPSHOT_ERR_NOMEM(device, "SHADER MEMORY");
+ return 0;
+ }
+
+ header->type = SNAPSHOT_DEBUG_SHADER_MEMORY;
+ header->size = SHADER_MEMORY_SIZE;
+
+ for (i = 0; i < SHADER_MEMORY_SIZE; i++)
+ adreno_regread(device, 0x4000 + i, &data[i]);
+
+ return DEBUG_SECTION_SZ(SHADER_MEMORY_SIZE);
+}
+
#define VPC_MEMORY_BANKS 4
#define VPC_MEMORY_SIZE 512
@@ -272,6 +295,12 @@
KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
a3xx_snapshot_cp_meq, NULL);
+ /* Shader working/shadow memory */
+ snapshot = kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUG, snapshot, remain,
+ a3xx_snapshot_shader_memory, NULL);
+
+
/* CP PFP and PM4 */
/* Reading these will hang the GPU if it isn't already hung */
diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c
index 0d15fb9..267fd45 100644
--- a/drivers/gpu/msm/adreno_drawctxt.c
+++ b/drivers/gpu/msm/adreno_drawctxt.c
@@ -199,7 +199,7 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct adreno_context *drawctxt;
- if (context == NULL)
+ if (context == NULL || context->devctxt == NULL)
return;
drawctxt = context->devctxt;
@@ -270,8 +270,13 @@
}
/* already current? */
- if (adreno_dev->drawctxt_active == drawctxt)
+ if (adreno_dev->drawctxt_active == drawctxt) {
+ if (adreno_dev->gpudev->ctxt_draw_workaround &&
+ adreno_is_a225(adreno_dev))
+ adreno_dev->gpudev->ctxt_draw_workaround(
+ adreno_dev);
return;
+ }
KGSL_CTXT_INFO(device, "from %p to %p flags %d\n",
adreno_dev->drawctxt_active, drawctxt, flags);
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index fb44b25..016862b 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -203,7 +203,14 @@
#define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
#define type0_pkt_offset(pkt) ((pkt) & 0x7FFF)
-#define pkt_is_type3(pkt) (((pkt) & 0xC0000000) == CP_TYPE3_PKT)
+/*
+ * Check both for the type3 opcode and make sure that the reserved bits [1:7]
+ * and 15 are 0
+ */
+
+#define pkt_is_type3(pkt) \
+ ((((pkt) & 0xC0000000) == CP_TYPE3_PKT) && \
+ (((pkt) & 0x80FE) == 0))
#define cp_type3_opcode(pkt) (((pkt) >> 8) & 0xFF)
#define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a0907d7..08a01b0 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -161,6 +161,22 @@
static unsigned int sp_vs_pvt_mem_addr;
static unsigned int sp_fs_pvt_mem_addr;
+/*
+ * Each load state block has two possible types. Each type has a different
+ * number of dwords per unit. Use this handy lookup table to make sure
+ * we dump the right amount of data from the indirect buffer
+ */
+
+static int load_state_unit_sizes[7][2] = {
+ { 2, 4 },
+ { 0, 1 },
+ { 2, 4 },
+ { 0, 1 },
+ { 8, 2 },
+ { 8, 2 },
+ { 8, 2 },
+};
+
static void ib_parse_load_state(struct kgsl_device *device, unsigned int *pkt,
unsigned int ptbase)
{
@@ -170,11 +186,9 @@
* The object here is to find indirect shaders i.e - shaders loaded from
* GPU memory instead of directly in the command. These should be added
* to the list of memory objects to dump. So look at the load state
- * call and see if 1) the shader block is a shader (block = 4, 5 or 6)
- * 2) that the block is indirect (source = 4). If these all match then
- * add the memory address to the list. The size of the object will
- * differ depending on the type. Type 0 (instructions) are 8 dwords per
- * unit and type 1 (constants) are 2 dwords per unit.
+ * if the block is indirect (source = 4). If so then add the memory
+ * address to the list. The size of the object differs depending on the
+ * type per the load_state_unit_sizes array above.
*/
if (type3_pkt_size(pkt[0]) < 2)
@@ -192,9 +206,13 @@
source = (pkt[1] >> 16) & 0x07;
type = pkt[2] & 0x03;
- if ((block == 4 || block == 5 || block == 6) && source == 4) {
- int unitsize = (type == 0) ? 8 : 2;
- int ret;
+ if (source == 4) {
+ int unitsize, ret;
+
+ if (type == 0)
+ unitsize = load_state_unit_sizes[block][0];
+ else
+ unitsize = load_state_unit_sizes[block][1];
/* Freeze the GPU buffer containing the shader */
@@ -528,7 +546,6 @@
unsigned int ptbase, rptr, *rbptr, ibbase;
int index, size, i;
int parse_ibs = 0, ib_parse_start;
- int skip_pktsize = 1;
/* Get the physical address of the MMU pagetable */
ptbase = kgsl_mmu_get_current_ptbase(&device->mmu);
@@ -541,13 +558,14 @@
/*
* Figure out the window of ringbuffer data to dump. First we need to
- * find where the last processed IB ws submitted
+ * find where the last processed IB ws submitted. Start walking back
+ * from the rptr
*/
index = rptr;
rbptr = rb->buffer_desc.hostptr;
- while (index != rb->wptr) {
+ do {
index--;
if (index < 0) {
@@ -563,7 +581,7 @@
if (adreno_cmd_is_ib(rbptr[index]) &&
rbptr[index + 1] == ibbase)
break;
- }
+ } while (index != rb->wptr);
/*
* index points at the last submitted IB. We can only trust that the
@@ -636,18 +654,15 @@
* try to adust for that by modifying the rptr to match a
* packet boundary. Unfortunately for us, it is hard to tell
* which dwords are legitimate type0 header and which are just
- * random data so just walk over type0 packets until we get
- * to the first type3, and from that point on start checking the
- * size of the packet and adjusting accordingly
+ * random data so only do the adjustments for type3 packets
*/
- if (skip_pktsize && pkt_is_type3(rbptr[index]))
- skip_pktsize = 0;
-
- if (skip_pktsize == 0) {
- unsigned int pktsize = type3_pkt_size(rbptr[index]);
+ if (pkt_is_type3(rbptr[index])) {
+ unsigned int pktsize =
+ type3_pkt_size(rbptr[index]);
if (index + pktsize > rptr)
- rptr = (index + pktsize) % rb->sizedwords;
+ rptr = (index + pktsize) %
+ rb->sizedwords;
}
/*
@@ -674,6 +689,12 @@
adreno_find_ctxtmem(device, ptbase, ibaddr,
ibsize);
+ /* IOMMU uses a NOP IB placed in setsate memory */
+ if (NULL == memdesc)
+ if (kgsl_gpuaddr_in_memdesc(
+ &device->mmu.setstate_memory,
+ ibaddr, ibsize))
+ memdesc = &device->mmu.setstate_memory;
/*
* The IB from CP_IB1_BASE and the IBs for legacy
* context switch go into the snapshot all
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index e789733..5883f08 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2523,7 +2523,7 @@
}
status = kgsl_allocate_contiguous(&device->memstore,
- sizeof(struct kgsl_devmemstore));
+ KGSL_MEMSTORE_SIZE);
if (status != 0) {
KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
@@ -2598,9 +2598,17 @@
kgsl_drm_exit();
kgsl_cffdump_destroy();
kgsl_core_debugfs_close();
- kgsl_sharedmem_uninit_sysfs();
- device_unregister(&kgsl_driver.virtdev);
+ /*
+ * We call kgsl_sharedmem_uninit_sysfs() and device_unregister()
+ * only if kgsl_driver.virtdev has been populated.
+ * We check at least one member of kgsl_driver.virtdev to
+ * see if it is not NULL (and thus, has been populated).
+ */
+ if (kgsl_driver.virtdev.class) {
+ kgsl_sharedmem_uninit_sysfs();
+ device_unregister(&kgsl_driver.virtdev);
+ }
if (kgsl_driver.class) {
class_destroy(kgsl_driver.class);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 64acff8..932c995 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -90,7 +90,7 @@
void (*power_stats)(struct kgsl_device *device,
struct kgsl_power_stats *stats);
void (*irqctrl)(struct kgsl_device *device, int state);
- unsigned int (*gpuid)(struct kgsl_device *device);
+ unsigned int (*gpuid)(struct kgsl_device *device, unsigned int *chipid);
void * (*snapshot)(struct kgsl_device *device, void *snapshot,
int *remain, int hang);
irqreturn_t (*irq_handler)(struct kgsl_device *device);
@@ -287,9 +287,10 @@
return device->ftbl->idle(device, timeout);
}
-static inline unsigned int kgsl_gpuid(struct kgsl_device *device)
+static inline unsigned int kgsl_gpuid(struct kgsl_device *device,
+ unsigned int *chipid)
{
- return device->ftbl->gpuid(device);
+ return device->ftbl->gpuid(device, chipid);
}
static inline unsigned int kgsl_readtimestamp(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index febb265..e42c7b6 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -82,7 +82,8 @@
return -ENOSYS;
}
- ptbase = iommu_get_pt_base_addr(domain);
+ ptbase = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
+ iommu_dev->ctx_id, TTBR0);
fsr = KGSL_IOMMU_GET_IOMMU_REG(iommu_unit->reg_map.hostptr,
iommu_dev->ctx_id, FSR);
@@ -836,6 +837,10 @@
{
unsigned int pt_base;
struct kgsl_iommu *iommu = mmu->priv;
+ /* We cannot enable or disable the clocks in interrupt context, this
+ function is called from interrupt context if there is an axi error */
+ if (in_interrupt())
+ return 0;
/* Return the current pt base by reading IOMMU pt_base register */
kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
pt_base = readl_relaxed(iommu->iommu_units[0].reg_map.hostptr +
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index ff9f0b8..5216b34 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -761,7 +761,7 @@
return 0;
spin_lock(&pt->lock);
- if (pt->tlb_flags && (1<<id)) {
+ if (pt->tlb_flags & (1<<id)) {
result = KGSL_MMUFLAGS_TLBFLUSH;
pt->tlb_flags &= ~(1<<id);
}
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 8935b29..824d806 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -35,6 +35,56 @@
struct list_head node;
};
+struct snapshot_obj_itr {
+ void *buf; /* Buffer pointer to write to */
+ int pos; /* Current position in the sequence */
+ loff_t offset; /* file offset to start writing from */
+ size_t remain; /* Bytes remaining in buffer */
+ size_t write; /* Bytes written so far */
+};
+
+static void obj_itr_init(struct snapshot_obj_itr *itr, void *buf,
+ loff_t offset, size_t remain)
+{
+ itr->buf = buf;
+ itr->offset = offset;
+ itr->remain = remain;
+ itr->pos = 0;
+ itr->write = 0;
+}
+
+static int obj_itr_out(struct snapshot_obj_itr *itr, void *src, int size)
+{
+ if (itr->remain == 0)
+ return 0;
+
+ if ((itr->pos + size) <= itr->offset)
+ goto done;
+
+ /* Handle the case that offset is in the middle of the buffer */
+
+ if (itr->offset > itr->pos) {
+ src += (itr->offset - itr->pos);
+ size -= (itr->offset - itr->pos);
+
+ /* Advance pos to the offset start */
+ itr->pos = itr->offset;
+ }
+
+ if (size > itr->remain)
+ size = itr->remain;
+
+ memcpy(itr->buf, src, size);
+
+ itr->buf += size;
+ itr->write += size;
+ itr->remain -= size;
+
+done:
+ itr->pos += size;
+ return size;
+}
+
/* idr_for_each function to count the number of contexts */
static int snapshot_context_count(int id, void *ptr, void *data)
@@ -182,76 +232,46 @@
(sizeof(struct kgsl_snapshot_section_header) + \
sizeof(struct kgsl_snapshot_gpu_object))
-#define GPU_OBJ_SECTION_SIZE(_o) \
- (GPU_OBJ_HEADER_SZ + ((_o)->size))
-
static int kgsl_snapshot_dump_object(struct kgsl_device *device,
- struct kgsl_snapshot_object *obj, void *buf,
- unsigned int off, unsigned int count)
+ struct kgsl_snapshot_object *obj, struct snapshot_obj_itr *itr)
{
- unsigned char headers[GPU_OBJ_HEADER_SZ];
- struct kgsl_snapshot_section_header *sect =
- (struct kgsl_snapshot_section_header *) headers;
- struct kgsl_snapshot_gpu_object *header =
- (struct kgsl_snapshot_gpu_object *) (headers + sizeof(*sect));
- int ret = 0;
+ struct kgsl_snapshot_section_header sect;
+ struct kgsl_snapshot_gpu_object header;
+ int ret;
- /* Construct a local copy of the headers */
+ sect.magic = SNAPSHOT_SECTION_MAGIC;
+ sect.id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
- sect->magic = SNAPSHOT_SECTION_MAGIC;
- sect->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
- sect->size = GPU_OBJ_SECTION_SIZE(obj);
+ /*
+ * Header size is in dwords, object size is in bytes -
+ * round up if the object size isn't dword aligned
+ */
- header->type = obj->type;
+ sect.size = GPU_OBJ_HEADER_SZ + ALIGN(obj->size, 4);
- /* Header size is in dwords, object size is in bytes */
- header->size = obj->size >> 2;
- header->gpuaddr = obj->gpuaddr;
- header->ptbase = obj->ptbase;
+ ret = obj_itr_out(itr, §, sizeof(sect));
+ if (ret == 0)
+ return 0;
- /* Copy out any part of the header block that is needed */
+ header.size = ALIGN(obj->size, 4) >> 2;
+ header.gpuaddr = obj->gpuaddr;
+ header.ptbase = obj->ptbase;
+ header.type = obj->type;
- if (off < GPU_OBJ_HEADER_SZ) {
- int size = count < GPU_OBJ_HEADER_SZ - off ?
- count : GPU_OBJ_HEADER_SZ - off;
+ ret = obj_itr_out(itr, &header, sizeof(header));
+ if (ret == 0)
+ return 0;
- memcpy(buf, headers + off, size);
+ ret = obj_itr_out(itr, obj->entry->memdesc.hostptr + obj->offset,
+ obj->size);
+ if (ret == 0)
+ return 0;
- count -= size;
- ret += size;
- }
+ /* Pad the end to a dword boundary if we need to */
- /* Now copy whatever part of the data is needed */
-
- if (off < (GPU_OBJ_HEADER_SZ + obj->size)) {
- int offset;
- int size = count < obj->size ? count : obj->size;
-
- /*
- * If the desired gpuaddr isn't at the beginning of the region,
- * then offset the source pointer
- */
-
- offset = obj->offset;
-
- /*
- * Then adjust it to account for the offset for the output
- * buffer.
- */
-
- if (off > GPU_OBJ_HEADER_SZ) {
- int loff = (off - GPU_OBJ_HEADER_SZ);
-
- /* Adjust the size so we don't walk off the end */
-
- if ((loff + size) > obj->size)
- size = obj->size - loff;
-
- offset += loff;
- }
-
- memcpy(buf + ret, obj->entry->memdesc.hostptr + offset, size);
- ret += size;
+ if (obj->size % 4) {
+ unsigned int dummy = 0;
+ ret = obj_itr_out(itr, &dummy, obj->size % 4);
}
return ret;
@@ -488,7 +508,7 @@
header->magic = SNAPSHOT_MAGIC;
- header->gpuid = kgsl_gpuid(device);
+ header->gpuid = kgsl_gpuid(device, &header->chipid);
/* Get a pointer to the first section (right after the header) */
snapshot = ((void *) device->snapshot) + sizeof(*header);
@@ -539,7 +559,9 @@
{
struct kgsl_device *device = kobj_to_device(kobj);
struct kgsl_snapshot_object *obj, *tmp;
- unsigned int size, src, dst = 0;
+ struct kgsl_snapshot_section_header head;
+ struct snapshot_obj_itr itr;
+ int ret;
if (device == NULL)
return 0;
@@ -551,80 +573,46 @@
/* Get the mutex to keep things from changing while we are dumping */
mutex_lock(&device->mutex);
- if (off < device->snapshot_size) {
- size = count < (device->snapshot_size - off) ?
- count : device->snapshot_size - off;
+ obj_itr_init(&itr, buf, off, count);
- memcpy(buf, device->snapshot + off, size);
+ ret = obj_itr_out(&itr, device->snapshot, device->snapshot_size);
- count -= size;
- dst += size;
- }
-
- if (count == 0)
+ if (ret == 0)
goto done;
- src = device->snapshot_size;
+ list_for_each_entry(obj, &device->snapshot_obj_list, node)
+ kgsl_snapshot_dump_object(device, obj, &itr);
- list_for_each_entry(obj, &device->snapshot_obj_list, node) {
+ {
+ head.magic = SNAPSHOT_SECTION_MAGIC;
+ head.id = KGSL_SNAPSHOT_SECTION_END;
+ head.size = sizeof(head);
- int objsize = GPU_OBJ_SECTION_SIZE(obj);
- int offset;
-
- /* If the offset is beyond this object, then move on */
-
- if (off >= (src + objsize)) {
- src += objsize;
- continue;
- }
-
- /* Adjust the offset to be relative to the object */
- offset = (off >= src) ? (off - src) : 0;
-
- size = kgsl_snapshot_dump_object(device, obj, buf + dst,
- offset, count);
-
- count -= size;
- dst += size;
-
- if (count == 0)
- goto done;
-
- /* Move on to the next object - update src accordingly */
- src += objsize;
+ obj_itr_out(&itr, &head, sizeof(head));
}
- /* Add the end section */
+ /*
+ * Make sure everything has been written out before destroying things.
+ * The best way to confirm this is to go all the way through without
+ * writing any bytes - so only release if we get this far and
+ * itr->write is 0
+ */
- if (off < (src + sizeof(struct kgsl_snapshot_section_header))) {
- if (count >= sizeof(struct kgsl_snapshot_section_header)) {
- struct kgsl_snapshot_section_header *head =
- (void *) (buf + dst);
+ if (itr.write == 0) {
+ list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list,
+ node)
+ kgsl_snapshot_put_object(device, obj);
- head->magic = SNAPSHOT_SECTION_MAGIC;
- head->id = KGSL_SNAPSHOT_SECTION_END;
- head->size = sizeof(*head);
+ if (device->snapshot_frozen)
+ KGSL_DRV_ERR(device, "Snapshot objects released\n");
- dst += sizeof(*head);
- } else {
- goto done;
- }
+ device->snapshot_frozen = 0;
}
- /* Release the buffers and unfreeze the snapshot */
-
- list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list, node)
- kgsl_snapshot_put_object(device, obj);
-
- if (device->snapshot_frozen)
- KGSL_DRV_ERR(device, "Snapshot objects released\n");
-
- device->snapshot_frozen = 0;
-
done:
mutex_unlock(&device->mutex);
- return dst;
+ return itr.write;
}
/* Show the timestamp of the last collected snapshot */
diff --git a/drivers/gpu/msm/kgsl_snapshot.h b/drivers/gpu/msm/kgsl_snapshot.h
index 304f4bb..d54afcf 100644
--- a/drivers/gpu/msm/kgsl_snapshot.h
+++ b/drivers/gpu/msm/kgsl_snapshot.h
@@ -18,7 +18,8 @@
/* Snapshot header */
-#define SNAPSHOT_MAGIC 0x504D0001
+/* High word is static, low word is snapshot version ID */
+#define SNAPSHOT_MAGIC 0x504D0002
/* GPU ID scheme:
* [16:31] - core identifer (0x0002 for 2D or 0x0003 for 3D)
@@ -28,6 +29,8 @@
struct kgsl_snapshot_header {
__u32 magic; /* Magic identifier */
__u32 gpuid; /* GPU ID - see above */
+ /* Added in snapshot version 2 */
+ __u32 chipid; /* Chip ID from the GPU */
} __packed;
/* Section header */
@@ -140,6 +143,7 @@
#define SNAPSHOT_DEBUG_CP_PM4_RAM 8
#define SNAPSHOT_DEBUG_CP_PFP_RAM 9
#define SNAPSHOT_DEBUG_CP_ROQ 10
+#define SNAPSHOT_DEBUG_SHADER_MEMORY 11
struct kgsl_snapshot_debug {
int type; /* Type identifier for the attached tata */
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 60231f6..3eff40f 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -143,7 +143,7 @@
),
TP_printk(
- "d_name=%s context_id=%u curr_ts=%u timestamp=0x%x timeout=%u",
+ "d_name=%s context_id=%u curr_ts=0x%x timestamp=0x%x timeout=%u",
__get_str(device_name),
__entry->context_id,
__entry->curr_ts,
@@ -175,7 +175,7 @@
),
TP_printk(
- "d_name=%s curr_ts=%u result=%d",
+ "d_name=%s curr_ts=0x%x result=%d",
__get_str(device_name),
__entry->curr_ts,
__entry->result
@@ -386,7 +386,7 @@
TP_printk(
"d_name=%s gpuaddr=0x%08x size=%d type=%d ctx=%u"
- " curr_ts=0x%08x free_ts=0x%08x",
+ " curr_ts=0x%x free_ts=0x%x",
__get_str(device_name),
__entry->gpuaddr,
__entry->size,
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index f4bbf69..bc2685c 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -896,8 +896,11 @@
}
}
-static unsigned int z180_gpuid(struct kgsl_device *device)
+static unsigned int z180_gpuid(struct kgsl_device *device, unsigned int *chipid)
{
+ if (chipid != NULL)
+ *chipid = 0;
+
/* Standard KGSL gpuid format:
* top word is 0x0002 for 2D or 0x0003 for 3D
* Bottom word is core specific identifer
diff --git a/drivers/i2c/busses/i2c-msm.c b/drivers/i2c/busses/i2c-msm.c
index b753fd0..4b48a69 100644
--- a/drivers/i2c/busses/i2c-msm.c
+++ b/drivers/i2c/busses/i2c-msm.c
@@ -636,7 +636,7 @@
spin_lock_init(&dev->lock);
platform_set_drvdata(pdev, dev);
- clk_enable(clk);
+ clk_prepare_enable(clk);
if (pdata->rmutex) {
struct remote_mutex_id rmid;
@@ -697,7 +697,8 @@
/* Config GPIOs for primary and secondary lines */
pdata->msm_i2c_config_gpio(dev->adap_pri.nr, 1);
pdata->msm_i2c_config_gpio(dev->adap_aux.nr, 1);
- clk_disable(dev->clk);
+ clk_disable_unprepare(dev->clk);
+ clk_prepare(dev->clk);
setup_timer(&dev->pwr_timer, msm_i2c_pwr_timer, (unsigned long) dev);
return 0;
@@ -706,7 +707,7 @@
i2c_del_adapter(&dev->adap_pri);
i2c_del_adapter(&dev->adap_aux);
err_i2c_add_adapter_failed:
- clk_disable(clk);
+ clk_disable_unprepare(clk);
iounmap(dev->base);
err_ioremap_failed:
kfree(dev);
@@ -736,6 +737,7 @@
free_irq(dev->irq, dev);
i2c_del_adapter(&dev->adap_pri);
i2c_del_adapter(&dev->adap_aux);
+ clk_unprepare(dev->clk);
clk_put(dev->clk);
iounmap(dev->base);
kfree(dev);
@@ -759,6 +761,7 @@
del_timer_sync(&dev->pwr_timer);
if (dev->clk_state != 0)
msm_i2c_pwr_mgmt(dev, 0);
+ clk_unprepare(dev->clk);
}
return 0;
@@ -767,6 +770,7 @@
static int msm_i2c_resume(struct platform_device *pdev)
{
struct msm_i2c_dev *dev = platform_get_drvdata(pdev);
+ clk_prepare(dev->clk);
dev->suspended = 0;
return 0;
}
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index 5403c57..8b6e172 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -40,6 +40,8 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/input/mpu3050.h>
+#include <linux/regulator/consumer.h>
#define MPU3050_CHIP_ID 0x69
@@ -112,8 +114,81 @@
struct i2c_client *client;
struct device *dev;
struct input_dev *idev;
+ struct mpu3050_gyro_platform_data *platform_data;
+ struct delayed_work input_work;
+ u32 use_poll;
};
+struct sensor_regulator {
+ struct regulator *vreg;
+ const char *name;
+ u32 min_uV;
+ u32 max_uV;
+};
+
+struct sensor_regulator mpu_vreg[] = {
+ {NULL, "vdd", 2100000, 3600000},
+ {NULL, "vlogic", 1800000, 1800000},
+};
+
+static int mpu3050_config_regulator(struct i2c_client *client, bool on)
+{
+ int rc = 0, i;
+ int num_reg = sizeof(mpu_vreg) / sizeof(struct sensor_regulator);
+
+ if (on) {
+ for (i = 0; i < num_reg; i++) {
+ mpu_vreg[i].vreg = regulator_get(&client->dev,
+ mpu_vreg[i].name);
+ if (IS_ERR(mpu_vreg[i].vreg)) {
+ rc = PTR_ERR(mpu_vreg[i].vreg);
+ pr_err("%s:regulator get failed rc=%d\n",
+ __func__, rc);
+ goto error_vdd;
+ }
+
+ if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
+ rc = regulator_set_voltage(mpu_vreg[i].vreg,
+ mpu_vreg[i].min_uV, mpu_vreg[i].max_uV);
+ if (rc) {
+ pr_err("%s:set_voltage failed rc=%d\n",
+ __func__, rc);
+ regulator_put(mpu_vreg[i].vreg);
+ goto error_vdd;
+ }
+ }
+
+ rc = regulator_enable(mpu_vreg[i].vreg);
+ if (rc) {
+ pr_err("%s: regulator_enable failed rc =%d\n",
+ __func__,
+ rc);
+
+ if (regulator_count_voltages(
+ mpu_vreg[i].vreg) > 0) {
+ regulator_set_voltage(mpu_vreg[i].vreg,
+ 0, mpu_vreg[i].max_uV);
+ }
+ regulator_put(mpu_vreg[i].vreg);
+ goto error_vdd;
+ }
+ }
+ return rc;
+ } else {
+ i = num_reg;
+ }
+error_vdd:
+ while (--i >= 0) {
+ if (regulator_count_voltages(mpu_vreg[i].vreg) > 0) {
+ regulator_set_voltage(mpu_vreg[i].vreg, 0,
+ mpu_vreg[i].max_uV);
+ }
+ regulator_disable(mpu_vreg[i].vreg);
+ regulator_put(mpu_vreg[i].vreg);
+ }
+ return rc;
+}
+
/**
* mpu3050_xyz_read_reg - read the axes values
* @buffer: provide register addr and get register
@@ -179,11 +254,21 @@
{
u8 value;
+ if (val) {
+ mpu3050_config_regulator(client, 1);
+ udelay(10);
+ }
+
value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
value = (value & ~MPU3050_PWR_MGM_MASK) |
(((val << MPU3050_PWR_MGM_POS) & MPU3050_PWR_MGM_MASK) ^
MPU3050_PWR_MGM_MASK);
i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, value);
+
+ if (!val) {
+ udelay(10);
+ mpu3050_config_regulator(client, 0);
+ }
}
/**
@@ -210,6 +295,9 @@
pm_runtime_put(sensor->dev);
return error;
}
+ if (sensor->use_poll)
+ schedule_delayed_work(&sensor->input_work,
+ msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
return 0;
}
@@ -225,6 +313,9 @@
{
struct mpu3050_sensor *sensor = input_get_drvdata(input);
+ if (sensor->use_poll)
+ cancel_delayed_work_sync(&sensor->input_work);
+
pm_runtime_put(sensor->dev);
}
@@ -252,6 +343,33 @@
}
/**
+ * mpu3050_input_work_fn - polling work
+ * @work: the work struct
+ *
+ * Called by the work queue; read sensor data and generate an input
+ * event
+ */
+static void mpu3050_input_work_fn(struct work_struct *work)
+{
+ struct mpu3050_sensor *sensor;
+ struct axis_data axis;
+
+ sensor = container_of((struct delayed_work *)work,
+ struct mpu3050_sensor, input_work);
+
+ mpu3050_read_xyz(sensor->client, &axis);
+
+ input_report_abs(sensor->idev, ABS_X, axis.x);
+ input_report_abs(sensor->idev, ABS_Y, axis.y);
+ input_report_abs(sensor->idev, ABS_Z, axis.z);
+ input_sync(sensor->idev);
+
+ if (sensor->use_poll)
+ schedule_delayed_work(&sensor->input_work,
+ msecs_to_jiffies(MPU3050_DEFAULT_POLL_INTERVAL));
+}
+
+/**
* mpu3050_hw_init - initialize hardware
* @sensor: the sensor
*
@@ -325,6 +443,7 @@
sensor->client = client;
sensor->dev = &client->dev;
sensor->idev = idev;
+ sensor->platform_data = client->dev.platform_data;
mpu3050_set_power_mode(client, 1);
msleep(10);
@@ -365,14 +484,22 @@
if (error)
goto err_pm_set_suspended;
- error = request_threaded_irq(client->irq,
+ if (client->irq == 0) {
+ INIT_DELAYED_WORK(&sensor->input_work, mpu3050_input_work_fn);
+ sensor->use_poll = 1;
+ } else {
+ sensor->use_poll = 0;
+
+ error = request_threaded_irq(client->irq,
NULL, mpu3050_interrupt_thread,
IRQF_TRIGGER_RISING,
"mpu3050", sensor);
- if (error) {
- dev_err(&client->dev,
- "can't get IRQ %d, error %d\n", client->irq, error);
- goto err_pm_set_suspended;
+ if (error) {
+ dev_err(&client->dev,
+ "can't get IRQ %d, error %d\n",
+ client->irq, error);
+ goto err_pm_set_suspended;
+ }
}
error = input_register_device(idev);
@@ -387,7 +514,8 @@
return 0;
err_free_irq:
- free_irq(client->irq, sensor);
+ if (client->irq > 0)
+ free_irq(client->irq, sensor);
err_pm_set_suspended:
pm_runtime_set_suspended(&client->dev);
err_free_mem:
diff --git a/drivers/input/touchscreen/atmel_maxtouch.c b/drivers/input/touchscreen/atmel_maxtouch.c
index 52f1f4a..9bdeb51 100644
--- a/drivers/input/touchscreen/atmel_maxtouch.c
+++ b/drivers/input/touchscreen/atmel_maxtouch.c
@@ -2034,6 +2034,7 @@
mxt_debug(DEBUG_INFO, "maXTouch driver setting abs parameters\n");
set_bit(BTN_TOUCH, input->keybit);
+ set_bit(INPUT_PROP_DIRECT, input->propbit);
/* Single touch */
input_set_abs_params(input, ABS_X, mxt->min_x_val,
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 7fe5498..23317d6 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -266,6 +266,9 @@
#define MXT_X_INVERT (1 << 1)
#define MXT_Y_INVERT (1 << 2)
+/* Touch suppression */
+#define MXT_TCHSUP_ACTIVE (1 << 0)
+
/* Touchscreen absolute values */
#define MXT_MAX_AREA 0xff
@@ -343,6 +346,8 @@
u8 t9_min_reportid;
u8 t15_max_reportid;
u8 t15_min_reportid;
+ u8 t42_max_reportid;
+ u8 t42_min_reportid;
u8 cfg_version[MXT_CFG_VERSION_LEN];
int cfg_version_idx;
int t38_start_addr;
@@ -887,6 +892,25 @@
data->keyarray_old = data->keyarray_new;
}
+static void mxt_release_all(struct mxt_data *data)
+{
+ int id;
+
+ for (id = 0; id < MXT_MAX_FINGER; id++)
+ if (data->finger[id].status)
+ data->finger[id].status = MXT_RELEASE;
+
+ mxt_input_report(data, 0);
+}
+
+static void mxt_handle_touch_supression(struct mxt_data *data, u8 status)
+{
+ dev_dbg(&data->client->dev, "touch suppression\n");
+ /* release all touches */
+ if (status & MXT_TCHSUP_ACTIVE)
+ mxt_release_all(data);
+}
+
static irqreturn_t mxt_interrupt(int irq, void *dev_id)
{
struct mxt_data *data = dev_id;
@@ -921,6 +945,9 @@
else if (reportid >= data->t15_min_reportid &&
reportid <= data->t15_max_reportid)
mxt_handle_key_array(data, &message);
+ else if (reportid >= data->t42_min_reportid &&
+ reportid <= data->t42_max_reportid)
+ mxt_handle_touch_supression(data, message.message[0]);
else
mxt_dump_message(dev, &message);
} while (reportid != 0xff);
@@ -1283,6 +1310,7 @@
struct mxt_object *t7_object;
struct mxt_object *t9_object;
struct mxt_object *t15_object;
+ struct mxt_object *t42_object;
int error;
/* Store T7 and T9 locally, used in suspend/resume operations */
@@ -1322,6 +1350,16 @@
}
}
+ /* Store T42 min and max report ids */
+ t42_object = mxt_get_object(data, MXT_PROCI_TOUCHSUPPRESSION_T42);
+ if (!t42_object)
+ dev_dbg(&client->dev, "T42 object is not available\n");
+ else {
+ data->t42_max_reportid = t42_object->max_reportid;
+ data->t42_min_reportid = t42_object->max_reportid -
+ t42_object->num_report_ids + 1;
+ }
+
return 0;
}
@@ -2258,6 +2296,7 @@
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
/* For single touch */
input_set_abs_params(input_dev, ABS_X,
diff --git a/drivers/input/touchscreen/cyttsp-i2c-qc.c b/drivers/input/touchscreen/cyttsp-i2c-qc.c
index e82dd13..5af4534 100644
--- a/drivers/input/touchscreen/cyttsp-i2c-qc.c
+++ b/drivers/input/touchscreen/cyttsp-i2c-qc.c
@@ -2510,6 +2510,8 @@
set_bit(EV_ABS, input_device->evbit);
set_bit(BTN_TOUCH, input_device->keybit);
set_bit(BTN_2, input_device->keybit);
+ set_bit(INPUT_PROP_DIRECT, input_device->propbit);
+
if (ts->platform_data->use_gestures)
set_bit(BTN_3, input_device->keybit);
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index c9905a4..ffeb8fe 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -445,6 +445,7 @@
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
+ __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
pdata->x_max, 0, 0);
diff --git a/drivers/iommu/msm_iommu-v2.c b/drivers/iommu/msm_iommu-v2.c
index 10d0b66..2ae9f28 100644
--- a/drivers/iommu/msm_iommu-v2.c
+++ b/drivers/iommu/msm_iommu-v2.c
@@ -23,6 +23,8 @@
#include <linux/iommu.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <asm/sizes.h>
@@ -70,6 +72,7 @@
struct msm_priv *priv = domain->priv;
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
+ int ret = 0;
int asid;
list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
@@ -78,15 +81,21 @@
iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
BUG_ON(!iommu_drvdata);
+
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret)
+ goto fail;
+
asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
SET_TLBIVA(iommu_drvdata->base, ctx_drvdata->num,
asid | (va & CB_TLBIVA_VA));
mb();
+ __disable_clocks(iommu_drvdata);
}
-
- return 0;
+fail:
+ return ret;
}
static int __flush_iotlb(struct iommu_domain *domain)
@@ -94,6 +103,7 @@
struct msm_priv *priv = domain->priv;
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
+ int ret = 0;
int asid;
list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
@@ -102,14 +112,56 @@
iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
BUG_ON(!iommu_drvdata);
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret)
+ goto fail;
+
asid = GET_CB_CONTEXTIDR_ASID(iommu_drvdata->base,
ctx_drvdata->num);
SET_TLBIASID(iommu_drvdata->base, ctx_drvdata->num, asid);
mb();
+ __disable_clocks(iommu_drvdata);
}
- return 0;
+fail:
+ return ret;
+}
+
+static void __reset_iommu(void __iomem *base)
+{
+ int i;
+
+ SET_ACR(base, 0);
+ SET_NSACR(base, 0);
+ SET_CR2(base, 0);
+ SET_NSCR2(base, 0);
+ SET_GFAR(base, 0);
+ SET_GFSRRESTORE(base, 0);
+ SET_TLBIALLNSNH(base, 0);
+ SET_PMCR(base, 0);
+ SET_SCR1(base, 0);
+ SET_SSDR_N(base, 0, 0);
+
+ for (i = 0; i < MAX_NUM_SMR; i++)
+ SET_SMR_VALID(base, i, 0);
+
+ mb();
+}
+
+static void __program_iommu(void __iomem *base)
+{
+ __reset_iommu(base);
+
+ SET_CR0_SMCFCFG(base, 1);
+ SET_CR0_USFCFG(base, 1);
+ SET_CR0_STALLD(base, 1);
+ SET_CR0_GCFGFIE(base, 1);
+ SET_CR0_GCFGFRE(base, 1);
+ SET_CR0_GFIE(base, 1);
+ SET_CR0_GFRE(base, 1);
+ SET_CR0_CLIENTPD(base, 0);
+ mb(); /* Make sure writes complete before returning */
}
static void __reset_context(void __iomem *base, int ctx)
@@ -129,11 +181,12 @@
}
static void __program_context(void __iomem *base, int ctx, int ncb,
- phys_addr_t pgtable, int redirect)
+ phys_addr_t pgtable, int redirect,
+ u32 *sids, int len)
{
unsigned int prrr, nmrr;
unsigned int pn;
- int i, j, found;
+ int i, j, found, num = 0;
__reset_context(base, ctx);
@@ -172,6 +225,30 @@
SET_CB_TTBR0_RGN(base, ctx, 1); /* WB, WA */
}
+ /* Program the M2V tables for this context */
+ for (i = 0; i < len / sizeof(*sids); i++) {
+ for (; num < MAX_NUM_SMR; num++)
+ if (GET_SMR_VALID(base, num) == 0)
+ break;
+ BUG_ON(num >= MAX_NUM_SMR);
+
+ SET_SMR_VALID(base, num, 1);
+ SET_SMR_MASK(base, num, 0);
+ SET_SMR_ID(base, num, sids[i]);
+
+ /* Set VMID = 0 */
+ SET_S2CR_N(base, num, 0);
+ SET_S2CR_CBNDX(base, num, ctx);
+ /* Set security bit override to be Non-secure */
+ SET_S2CR_NSCFG(base, sids[i], 3);
+
+ SET_CBAR_N(base, ctx, 0);
+ /* Stage 1 Context with Stage 2 bypass */
+ SET_CBAR_TYPE(base, ctx, 1);
+ /* Route page faults to the non-secure interrupt */
+ SET_CBAR_IRPTNDX(base, ctx, 1);
+ }
+
/* Find if this page table is used elsewhere, and re-use ASID */
found = 0;
for (i = 0; i < ncb; i++)
@@ -244,13 +321,33 @@
mutex_unlock(&msm_iommu_lock);
}
+static int msm_iommu_ctx_attached(struct device *dev)
+{
+ struct platform_device *pdev;
+ struct device_node *child;
+ struct msm_iommu_ctx_drvdata *ctx;
+
+ for_each_child_of_node(dev->of_node, child) {
+ pdev = of_find_device_by_node(child);
+
+ ctx = dev_get_drvdata(&pdev->dev);
+ if (ctx->attached_domain) {
+ of_node_put(child);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
struct msm_priv *priv;
struct msm_iommu_drvdata *iommu_drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
struct msm_iommu_ctx_drvdata *tmp_drvdata;
- int ret = 0;
+ u32 sids[MAX_NUM_SMR];
+ int len = 0, ret;
mutex_lock(&msm_iommu_lock);
@@ -278,15 +375,26 @@
goto fail;
}
+ of_get_property(dev->of_node, "qcom,iommu-ctx-sids", &len);
+ BUG_ON(len >= sizeof(sids));
+ if (of_property_read_u32_array(dev->of_node, "qcom,iommu-ctx-sids",
+ sids, len / sizeof(*sids))) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
ret = __enable_clocks(iommu_drvdata);
if (ret)
goto fail;
+ if (!msm_iommu_ctx_attached(dev->parent))
+ __program_iommu(iommu_drvdata->base);
+
__program_context(iommu_drvdata->base, ctx_drvdata->num,
iommu_drvdata->ncb, __pa(priv->pt.fl_table),
- priv->pt.redirect);
-
+ priv->pt.redirect, sids, len);
__disable_clocks(iommu_drvdata);
+
list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
ctx_drvdata->attached_domain = domain;
@@ -322,6 +430,7 @@
__reset_context(iommu_drvdata->base, ctx_drvdata->num);
__disable_clocks(iommu_drvdata);
+
list_del_init(&ctx_drvdata->attached_elm);
ctx_drvdata->attached_domain = NULL;
@@ -427,7 +536,7 @@
struct msm_iommu_ctx_drvdata *ctx_drvdata;
unsigned int par;
void __iomem *base;
- phys_addr_t pa = 0;
+ phys_addr_t ret = 0;
int ctx;
mutex_lock(&msm_iommu_lock);
@@ -443,25 +552,33 @@
base = iommu_drvdata->base;
ctx = ctx_drvdata->num;
+ ret = __enable_clocks(iommu_drvdata);
+ if (ret) {
+ ret = 0; /* 0 indicates translation failed */
+ goto fail;
+ }
+
SET_ATS1PR(base, ctx, va & CB_ATS1PR_ADDR);
mb();
while (GET_CB_ATSR_ACTIVE(base, ctx))
cpu_relax();
par = GET_PAR(base, ctx);
+ __disable_clocks(iommu_drvdata);
+
if (par & CB_PAR_F) {
- pa = 0;
+ ret = 0;
} else {
/* We are dealing with a supersection */
- if (par & CB_PAR_SS)
- pa = (par & 0xFF000000) | (va & 0x00FFFFFF);
+ if (ret & CB_PAR_SS)
+ ret = (par & 0xFF000000) | (va & 0x00FFFFFF);
else /* Upper 20 bits from PAR, lower 12 from VA */
- pa = (par & 0xFFFFF000) | (va & 0x00000FFF);
+ ret = (par & 0xFFFFF000) | (va & 0x00000FFF);
}
fail:
mutex_unlock(&msm_iommu_lock);
- return pa;
+ return ret;
}
static int msm_iommu_domain_has_cap(struct iommu_domain *domain,
@@ -501,7 +618,7 @@
struct msm_iommu_drvdata *drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata;
unsigned int fsr;
- int ret = IRQ_NONE;
+ int ret;
mutex_lock(&msm_iommu_lock);
@@ -513,6 +630,12 @@
ctx_drvdata = dev_get_drvdata(&pdev->dev);
BUG_ON(!ctx_drvdata);
+ ret = __enable_clocks(drvdata);
+ if (ret) {
+ ret = IRQ_NONE;
+ goto fail;
+ }
+
fsr = GET_FSR(drvdata->base, ctx_drvdata->num);
if (fsr) {
if (!ctx_drvdata->attached_domain) {
@@ -537,6 +660,8 @@
} else
ret = IRQ_NONE;
+ __disable_clocks(drvdata);
+fail:
mutex_unlock(&msm_iommu_lock);
return ret;
}
diff --git a/drivers/iommu/msm_iommu_dev-v2.c b/drivers/iommu/msm_iommu_dev-v2.c
index e690ada..d6858de 100644
--- a/drivers/iommu/msm_iommu_dev-v2.c
+++ b/drivers/iommu/msm_iommu_dev-v2.c
@@ -29,27 +29,6 @@
#include <mach/iommu_hw-v2.h>
#include <mach/iommu.h>
-static void msm_iommu_reset(void __iomem *base)
-{
- int i;
-
- SET_ACR(base, 0);
- SET_NSACR(base, 0);
- SET_CR2(base, 0);
- SET_NSCR2(base, 0);
- SET_GFAR(base, 0);
- SET_GFSRRESTORE(base, 0);
- SET_TLBIALLNSNH(base, 0);
- SET_PMCR(base, 0);
- SET_SCR1(base, 0);
- SET_SSDR_N(base, 0, 0);
-
- for (i = 0; i < MAX_NUM_SMR; i++)
- SET_SMR_VALID(base, i, 0);
-
- mb();
-}
-
static int msm_iommu_parse_dt(struct platform_device *pdev,
struct msm_iommu_drvdata *drvdata)
{
@@ -119,17 +98,6 @@
} else
drvdata->clk = NULL;
- msm_iommu_reset(drvdata->base);
-
- SET_CR0_SMCFCFG(drvdata->base, 1);
- SET_CR0_USFCFG(drvdata->base, 1);
- SET_CR0_STALLD(drvdata->base, 1);
- SET_CR0_GCFGFIE(drvdata->base, 1);
- SET_CR0_GCFGFRE(drvdata->base, 1);
- SET_CR0_GFIE(drvdata->base, 1);
- SET_CR0_GFRE(drvdata->base, 1);
- SET_CR0_CLIENTPD(drvdata->base, 0);
-
ret = msm_iommu_parse_dt(pdev, drvdata);
if (ret)
goto fail_clk;
@@ -173,13 +141,10 @@
}
static int msm_iommu_ctx_parse_dt(struct platform_device *pdev,
- struct msm_iommu_drvdata *drvdata,
struct msm_iommu_ctx_drvdata *ctx_drvdata)
{
struct resource *r, rp;
- u32 sids[MAX_NUM_SMR];
- int num = 0;
- int irq, i, ret, len = 0;
+ int irq, ret;
irq = platform_get_irq(pdev, 0);
if (irq > 0) {
@@ -212,53 +177,17 @@
&ctx_drvdata->name))
ctx_drvdata->name = dev_name(&pdev->dev);
- of_get_property(pdev->dev.of_node, "qcom,iommu-ctx-sids", &len);
- BUG_ON(len >= sizeof(sids));
- if (of_property_read_u32_array(pdev->dev.of_node, "qcom,iommu-ctx-sids",
- sids, len / sizeof(*sids)))
- return -EINVAL;
-
- /* Program the M2V tables for this context */
- for (i = 0; i < len / sizeof(*sids); i++) {
- for (; num < MAX_NUM_SMR; num++)
- if (GET_SMR_VALID(drvdata->base, num) == 0)
- break;
- BUG_ON(num >= MAX_NUM_SMR);
-
- SET_SMR_VALID(drvdata->base, num, 1);
- SET_SMR_MASK(drvdata->base, num, 0);
- SET_SMR_ID(drvdata->base, num, sids[i]);
-
- /* Set VMID = 0 */
- SET_S2CR_N(drvdata->base, num, 0);
- SET_S2CR_CBNDX(drvdata->base, num, ctx_drvdata->num);
- /* Set security bit override to be Non-secure */
- SET_S2CR_NSCFG(drvdata->base, sids[i], 3);
-
- SET_CBAR_N(drvdata->base, ctx_drvdata->num, 0);
- /* Stage 1 Context with Stage 2 bypass */
- SET_CBAR_TYPE(drvdata->base, ctx_drvdata->num, 1);
- /* Route page faults to the non-secure interrupt */
- SET_CBAR_IRPTNDX(drvdata->base, ctx_drvdata->num, 1);
- }
- mb();
-
return 0;
}
static int __devinit msm_iommu_ctx_probe(struct platform_device *pdev)
{
- struct msm_iommu_drvdata *drvdata;
struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
int ret;
if (!pdev->dev.parent)
return -EINVAL;
- drvdata = dev_get_drvdata(pdev->dev.parent);
- if (!drvdata)
- return -ENODEV;
-
ctx_drvdata = devm_kzalloc(&pdev->dev, sizeof(*ctx_drvdata),
GFP_KERNEL);
if (!ctx_drvdata)
@@ -268,27 +197,11 @@
INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
platform_set_drvdata(pdev, ctx_drvdata);
- ret = clk_prepare_enable(drvdata->pclk);
- if (ret)
- return ret;
-
- if (drvdata->clk) {
- ret = clk_prepare_enable(drvdata->clk);
- if (ret) {
- clk_disable_unprepare(drvdata->pclk);
- return ret;
- }
- }
-
- ret = msm_iommu_ctx_parse_dt(pdev, drvdata, ctx_drvdata);
+ ret = msm_iommu_ctx_parse_dt(pdev, ctx_drvdata);
if (!ret)
dev_info(&pdev->dev, "context %s using bank %d\n",
dev_name(&pdev->dev), ctx_drvdata->num);
- if (drvdata->clk)
- clk_disable_unprepare(drvdata->clk);
- clk_disable_unprepare(drvdata->pclk);
-
return ret;
}
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index c15609f..971cf10 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -120,6 +120,8 @@
/*PS repeatcount for PS Tx */
int ps_repeatcount;
int enable_optimized_srch_alg;
+ unsigned char spur_table_size;
+ struct fm_spur_data spur_data;
};
/**************************************************************************
@@ -147,6 +149,10 @@
enum radio_state_t state);
static int tavarua_request_irq(struct tavarua_device *radio);
static void start_pending_xfr(struct tavarua_device *radio);
+static int update_spur_table(struct tavarua_device *radio);
+static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
+ unsigned long offset, unsigned char *buf);
+
/* work function */
static void read_int_stat(struct work_struct *work);
@@ -1025,6 +1031,35 @@
FMDBG("write PHY_TXGAIN is successful");
complete(&radio->sync_req_done);
break;
+ case (XFR_POKE_COMPLETE | LSH_DATA(ONE_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(TWO_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(THREE_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(FOUR_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(FIVE_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(SIX_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(SEVEN_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(EIGHT_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(NINE_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(TEN_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(ELEVEN_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(TWELVE_BYTE, 1)):
+ case (XFR_POKE_COMPLETE | LSH_DATA(THIRTEEN_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(ONE_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(TWO_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(THREE_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(FOUR_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(FIVE_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(SIX_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(SEVEN_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(EIGHT_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(NINE_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(TEN_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(ELEVEN_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(TWELVE_BYTE, 1)):
+ case (XFR_PEEK_COMPLETE | LSH_DATA(THIRTEEN_BYTE, 1)):
+ FMDBG("XFR interrupt for PEEK/POKE complete\n");
+ complete(&radio->sync_req_done);
+ break;
default:
FMDERR("UNKNOWN XFR = %d\n", xfr_status);
}
@@ -2158,6 +2193,7 @@
wait_for_completion(&radio->shutdown_done);
radio->handle_irq = 1;
radio->lp_mode = 1;
+ radio->spur_table_size = 0;
atomic_inc(&radio->users);
radio->marimba->mod_id = SLAVE_ID_BAHAMA;
flush_workqueue(radio->wqueue);
@@ -2481,6 +2517,135 @@
return retval;
}
+
+static int update_spur_table(struct tavarua_device *radio)
+{
+ unsigned char xfr_buf[XFR_REG_NUM];
+ unsigned char size = 0, tbl_size = 0;
+ int index = 0, offset = 0, addr = 0x0, val = 0;
+ int retval = 0, temp = 0, cnt = 0, j = 0;
+
+ memset(xfr_buf, 0x0, XFR_REG_NUM);
+
+ /* Read the SPUR Table Size */
+ retval = xfr_rdwr_data(radio, XFR_READ, 1, SPUR_TABLE_ADDR, &tbl_size);
+ if (retval < 0) {
+ FMDERR("%s: Failed to read SPUR table size\n", __func__);
+ return retval;
+ }
+
+ /* Calculate the new SPUR Register address */
+ val = addr = (SPUR_TABLE_START_ADDR + (tbl_size * 3));
+
+ /* Save the SPUR Table length configured by user*/
+ temp = radio->spur_table_size;
+
+ /* COnfigure the new spur table length */
+ size = (radio->spur_table_size + tbl_size);
+ retval = xfr_rdwr_data(radio, XFR_WRITE, 1, SPUR_TABLE_ADDR, &size);
+ if (retval < 0) {
+ FMDERR("%s: Failed to configure SPUR table size\n", __func__);
+ return retval;
+ }
+
+ /* Program the spur table entries */
+ for (cnt = 0; cnt < (temp / 4); cnt++) {
+ offset = 0;
+ for (j = 0; j < 4; j++) {
+ xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
+ radio->spur_data.freq[index]), 1);
+ xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
+ radio->spur_data.freq[index]), 0);
+ xfr_buf[offset++] =
+ radio->spur_data.rmssi[index];
+ index++;
+ }
+ retval = xfr_rdwr_data(radio, XFR_WRITE, (SPUR_DATA_SIZE * 4),
+ addr, xfr_buf);
+ if (retval < 0) {
+ FMDERR("%s: Failed to program SPUR frequencies\n",
+ __func__);
+ return retval;
+ }
+ addr += (SPUR_DATA_SIZE * 4);
+ }
+
+ /* Program the additional SPUR Frequencies */
+ temp = radio->spur_table_size;
+ temp = (temp % 4);
+ if (temp > 0) {
+ offset = 0;
+ for (j = 0; j < temp; j++) {
+ xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
+ radio->spur_data.freq[index]), 1);
+ xfr_buf[offset++] = GET_FREQ(COMPUTE_SPUR(
+ radio->spur_data.freq[index]), 0);
+ xfr_buf[offset++] =
+ radio->spur_data.rmssi[index];
+ index++;
+ }
+ size = (temp * SPUR_DATA_SIZE);
+ retval = xfr_rdwr_data(radio, XFR_WRITE, size, addr, xfr_buf);
+ if (retval < 0) {
+ FMDERR("%s: Failed to program SPUR frequencies\n",
+ __func__);
+ return retval;
+ }
+ }
+
+ return retval;
+}
+
+static int xfr_rdwr_data(struct tavarua_device *radio, int op, int size,
+ unsigned long offset, unsigned char *buf) {
+
+ unsigned char xfr_buf[XFR_REG_NUM];
+ int retval = 0, temp = 0;
+
+ memset(xfr_buf, 0x0, XFR_REG_NUM);
+ temp = size;
+
+ xfr_buf[XFR_MODE_OFFSET] = (size << 1);
+ xfr_buf[XFR_ADDR_MSB_OFFSET] = GET_FREQ(offset, 1);
+ xfr_buf[XFR_ADDR_LSB_OFFSET] = GET_FREQ(offset, 0);
+
+ if (op == XFR_READ) {
+ xfr_buf[XFR_MODE_OFFSET] |= (XFR_PEEK_MODE);
+ size = 3;
+ } else if (op == XFR_WRITE) {
+ xfr_buf[XFR_MODE_OFFSET] |= (XFR_POKE_MODE);
+ memcpy(&xfr_buf[XFR_DATA_OFFSET], buf, size);
+ size += 3;
+ }
+
+ retval = tavarua_write_registers(radio, XFRCTRL, xfr_buf, size);
+ if (retval < 0) {
+ FMDERR("%s: Failed to performXFR operation\n", __func__);
+ return retval;
+ }
+
+ size = temp;
+
+ /*Wait for the XFR interrupt */
+ init_completion(&radio->sync_req_done);
+ if (!wait_for_completion_timeout(&radio->sync_req_done,
+ msecs_to_jiffies(WAIT_TIMEOUT))) {
+ FMDERR("Timeout: No XFR interrupt");
+ }
+
+ if (op == XFR_READ) {
+ retval = tavarua_read_registers(radio, XFRDAT0, size);
+ if (retval < 0) {
+ FMDERR("%s: Failed to read the XFR data\n", __func__);
+ return retval;
+ }
+ if (buf != NULL)
+ memcpy(buf, &radio->registers[XFRDAT0], size);
+ }
+
+ return retval;
+}
+
static int peek_MPX_DCC(struct tavarua_device *radio)
{
int retval = 0;
@@ -3001,6 +3166,7 @@
}
/* check if off */
else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
+ radio->spur_table_size = 0;
FMDBG("%s: turning off...\n", __func__);
tavarua_write_register(radio, RDCTRL, ctrl->value);
/* flush the event and work queues */
@@ -3299,8 +3465,20 @@
case V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION:
case V4L2_CID_PRIVATE_SINR_THRESHOLD:
case V4L2_CID_PRIVATE_SINR_SAMPLES:
+ case V4L2_CID_PRIVATE_SPUR_SELECTION:
retval = 0;
break;
+ case V4L2_CID_PRIVATE_SPUR_FREQ:
+ radio->spur_data.freq[radio->spur_table_size] =
+ ctrl->value;
+ break;
+ case V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI:
+ radio->spur_data.rmssi[radio->spur_table_size++] =
+ ctrl->value;
+ break;
+ case V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE:
+ retval = update_spur_table(radio);
+ break;
default:
retval = -EINVAL;
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 3416c91..d7dc67d 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -28,6 +28,7 @@
struct rc_dev *rcdev;
unsigned int gpio_nr;
bool active_low;
+ int can_sleep;
};
static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
@@ -37,7 +38,10 @@
int rc = 0;
enum raw_event_type type = IR_SPACE;
- gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
+ if (gpio_dev->can_sleep)
+ gval = gpio_get_value_cansleep(gpio_dev->gpio_nr);
+ else
+ gval = gpio_get_value(gpio_dev->gpio_nr);
if (gval < 0)
goto err_get_value;
@@ -96,6 +100,9 @@
rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
if (rc < 0)
goto err_gpio_request;
+
+ gpio_dev->can_sleep = gpio_cansleep(pdata->gpio_nr);
+
rc = gpio_direction_input(pdata->gpio_nr);
if (rc < 0)
goto err_gpio_direction_input;
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 3c9431a..a3fe1c8 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -149,6 +149,10 @@
break;
data->state = STATE_TRAILER_SPACE;
+
+ if (data->is_nec_x)
+ goto rc_data;
+
return 0;
case STATE_TRAILER_SPACE:
@@ -157,7 +161,7 @@
if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
break;
-
+rc_data:
address = bitrev8((data->bits >> 24) & 0xff);
not_address = bitrev8((data->bits >> 16) & 0xff);
command = bitrev8((data->bits >> 8) & 0xff);
diff --git a/drivers/media/rc/keymaps/rc-samsung-necx.c b/drivers/media/rc/keymaps/rc-samsung-necx.c
index 6cf837f..1a3d6be 100644
--- a/drivers/media/rc/keymaps/rc-samsung-necx.c
+++ b/drivers/media/rc/keymaps/rc-samsung-necx.c
@@ -32,7 +32,7 @@
{ 0x70707, KEY_VOLUMEUP},
{ 0x7070b, KEY_VOLUMEDOWN},
{ 0x70760, KEY_UP},
- { 0x70768, KEY_ENTER}, /* ok */
+ { 0x70768, KEY_ENTER},
{ 0x70761, KEY_DOWN},
{ 0x70765, KEY_LEFT},
{ 0x70762, KEY_RIGHT},
@@ -44,15 +44,18 @@
{ 0x70748, KEY_FORWARD},
{ 0x7074a, KEY_PAUSE},
{ 0x70703, KEY_SLEEP},
- { 0x7076c, KEY_A}, /* search */
- { 0x70714, KEY_B}, /* camera */
- { 0x70715, KEY_C},
- { 0x70716, KEY_D},
+ { 0x7076c, KEY_RED},
+ { 0x70714, KEY_GREEN},
+ { 0x70715, KEY_YELLOW},
+ { 0x70716, KEY_BLUE},
{ 0x70758, KEY_BACK},
{ 0x7071a, KEY_MENU},
{ 0x7076b, KEY_LIST},
- { 0x70701, KEY_SCREENLOCK},
- { 0x7071f, KEY_HOME},
+ { 0x70701, KEY_TV2},
+ { 0x7071f, KEY_INFO},
+ { 0x7071b, KEY_TV},
+ { 0x7078b, KEY_AUX},
+ { 0x7078c, KEY_MEDIA},
};
diff --git a/drivers/media/rc/keymaps/rc-ue-rf4ce.c b/drivers/media/rc/keymaps/rc-ue-rf4ce.c
index 71c5505..ea982a8 100644
--- a/drivers/media/rc/keymaps/rc-ue-rf4ce.c
+++ b/drivers/media/rc/keymaps/rc-ue-rf4ce.c
@@ -25,7 +25,7 @@
{ 0x0d, KEY_EXIT },
{ 0x72, KEY_TV },
{ 0x73, KEY_VIDEO },
- { 0x74, KEY_COMPOSE },
+ { 0x74, KEY_PC },
{ 0x71, KEY_AUX },
{ 0x45, KEY_STOP },
{ 0x0b, KEY_LIST },
@@ -43,18 +43,20 @@
{ 0x30, KEY_CHANNELUP },
{ 0x31, KEY_CHANNELDOWN },
- { 0x20, KEY_NUMERIC_0 },
- { 0x21, KEY_NUMERIC_1 },
- { 0x22, KEY_NUMERIC_2 },
- { 0x23, KEY_NUMERIC_3 },
- { 0x24, KEY_NUMERIC_4 },
- { 0x25, KEY_NUMERIC_5 },
- { 0x26, KEY_NUMERIC_6 },
- { 0x27, KEY_NUMERIC_7 },
- { 0x28, KEY_NUMERIC_8 },
- { 0x29, KEY_NUMERIC_9 },
- { 0x34, KEY_INSERT },
+ { 0x20, KEY_0 },
+ { 0x21, KEY_1 },
+ { 0x22, KEY_2 },
+ { 0x23, KEY_3 },
+ { 0x24, KEY_4 },
+ { 0x25, KEY_5 },
+ { 0x26, KEY_6 },
+ { 0x27, KEY_7 },
+ { 0x28, KEY_8 },
+ { 0x29, KEY_9 },
+ { 0x34, KEY_TV2 },
{ 0x2b, KEY_ENTER },
+ { 0x35, KEY_INFO },
+ { 0x09, KEY_MENU },
};
static struct rc_map_list ue_rf4ce_map = {
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index ab4a6f2..5ffc133 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -199,6 +199,15 @@
bool "Sensor ov2720 (Omnivision 2MP)"
depends on MSM_CAMERA
+config OV8825
+ bool "Sensor ov8825 (Omnivision 8M)"
+ depends on MSM_CAMERA
+ ---help---
+ Support for OV8825 sensor driver.
+ It is a Bayer 8MP sensor with auto focus and it supports
+ two mipi lanes, required for msm8625 platform.
+ Say Y here if this is msm8625 variant platform.
+
config VB6801
bool "Sensor vb6801"
depends on MSM_CAMERA && !ARCH_MSM8X60 && !MSM_CAMERA_V4L2
@@ -239,6 +248,12 @@
---help---
Enable support for Gemini Jpeg Engine
+config MSM_MERCURY
+ tristate "Qualcomm MSM Mercury Jpeg Decoder Engine support"
+ depends on MSM_CAMERA && ARCH_MSM8960
+ ---help---
+ Enable support for Mercury Jpeg Engine
+
config MSM_VPE
tristate "Qualcomm MSM Video Pre-processing Engine support"
depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
@@ -246,6 +261,16 @@
---help---
Enable support for Video Pre-processing Engine
+config MSM_CAM_IRQ_ROUTER
+ bool "Enable MSM CAM IRQ Router"
+ depends on MSM_CAMERA
+ ---help---
+ Enable IRQ Router for Camera. Depending on the
+ configuration, this module can handle the
+ interrupts from multiple camera hardware
+ cores and composite them into a single
+ interrupt to the MSM.
+
config QUP_EXCLUSIVE_TO_CAMERA
bool "QUP exclusive to camera"
depends on MSM_CAMERA
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index e4d4081..431da2e 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -7,7 +7,6 @@
obj-$(CONFIG_MSM_CAMERA) += io/
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
- EXTRA_CFLAGS += -Idrivers/media/video/msm/io
EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
EXTRA_CFLAGS += -Idrivers/media/video/msm/sensors
EXTRA_CFLAGS += -Idrivers/media/video/msm/actuators
@@ -15,10 +14,11 @@
obj-$(CONFIG_MSM_CAMERA) += msm_isp.o msm.o msm_mem.o msm_mctl.o msm_mctl_buf.o msm_mctl_pp.o
obj-$(CONFIG_MSM_CAMERA) += server/ eeprom/ sensors/ actuators/ csi/
obj-$(CONFIG_MSM_CAMERA) += msm_gesture.o
+ obj-$(CONFIG_MSM_CAM_IRQ_ROUTER) += msm_camirq_router.o
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
-obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/
+obj-$(CONFIG_MSM_CAMERA) += msm_axi_qos.o gemini/ mercury/
obj-$(CONFIG_MSM_CAMERA_FLASH) += flash.o
obj-$(CONFIG_ARCH_MSM_ARM11) += msm_vfe7x.o
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index e5d5966..f7cb408 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -1,6 +1,7 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
EXTRA_CFLAGS += -Idrivers/media/video/msm
-obj-$(CONFIG_ARCH_MSM8960) += msm_csiphy.o msm_csid.o msm_ispif.o
-obj-$(CONFIG_ARCH_MSM7X27A) += msm_csic.o
-obj-$(CONFIG_ARCH_MSM8X60) += msm_csic.o
-obj-$(CONFIG_ARCH_MSM7X30) += msm_csic.o
+obj-$(CONFIG_ARCH_MSM8960) += msm_csi2_register.o msm_csiphy.o msm_csid.o msm_ispif.o
+obj-$(CONFIG_ARCH_MSM7X27A) += msm_csic_register.o msm_csic.o
+obj-$(CONFIG_ARCH_MSM8X60) += msm_csic_register.o msm_csic.o
+obj-$(CONFIG_ARCH_MSM7X30) += msm_csic_register.o msm_csic.o
+
diff --git a/drivers/media/video/msm/csi/msm_csi2_register.c b/drivers/media/video/msm/csi/msm_csi2_register.c
new file mode 100644
index 0000000..7b85ded
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csi2_register.c
@@ -0,0 +1,67 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/device.h>
+#include "msm.h"
+#include "msm_csi_register.h"
+
+int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
+ int core_index,
+ int (*msm_mctl_subdev_match_core)(struct device *, void *))
+{
+ int rc = -ENODEV;
+ struct device_driver *driver;
+ struct device *dev;
+
+ /* register csiphy subdev */
+ driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
+
+ dev = driver_find_device(driver, NULL, (void *)core_index,
+ msm_mctl_subdev_match_core);
+ if (!dev)
+ goto out;
+
+ p_mctl->csiphy_sdev = dev_get_drvdata(dev);
+
+ /* register csid subdev */
+ driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
+
+ dev = driver_find_device(driver, NULL, (void *)core_index,
+ msm_mctl_subdev_match_core);
+ if (!dev)
+ goto out;
+
+ p_mctl->csid_sdev = dev_get_drvdata(dev);
+
+ /* register ispif subdev */
+ driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
+
+ dev = driver_find_device(driver, NULL, 0,
+ msm_mctl_subdev_match_core);
+ if (!dev)
+ goto out;
+
+ p_mctl->ispif_sdev = dev_get_drvdata(dev);
+ rc = 0;
+ return rc;
+out:
+ p_mctl->ispif_sdev = NULL;
+ return rc;
+}
+
diff --git a/drivers/media/video/msm/csi/msm_csi_register.h b/drivers/media/video/msm/csi/msm_csi_register.h
new file mode 100644
index 0000000..578b609
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csi_register.h
@@ -0,0 +1,16 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
+ int core_index,
+ int (*msm_mctl_subdev_match_core)(struct device *, void *));
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index a217f9d..dbb4f32 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -388,6 +388,8 @@
{
struct csic_device *new_csic_dev;
int rc = 0;
+ struct msm_cam_subdev_info sd_info;
+
CDBG("%s: device id = %d\n", __func__, pdev->id);
new_csic_dev = kzalloc(sizeof(struct csic_device), GFP_KERNEL);
if (!new_csic_dev) {
@@ -455,8 +457,11 @@
iounmap(new_csic_dev->base);
new_csic_dev->base = NULL;
+ sd_info.sdev_type = CSIC_DEV;
+ sd_info.sd_index = pdev->id;
+ sd_info.irq_num = new_csic_dev->irq->start;
msm_cam_register_subdev_node(
- &new_csic_dev->subdev, CSIC_DEV, pdev->id);
+ &new_csic_dev->subdev, &sd_info);
return 0;
diff --git a/drivers/media/video/msm/csi/msm_csic_register.c b/drivers/media/video/msm/csi/msm_csic_register.c
new file mode 100644
index 0000000..7ccaff2
--- /dev/null
+++ b/drivers/media/video/msm/csi/msm_csic_register.c
@@ -0,0 +1,45 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/device.h>
+#include "msm.h"
+#include "msm_csi_register.h"
+
+int msm_csi_register_subdevs(struct msm_cam_media_controller *p_mctl,
+ int core_index,
+ int (*msm_mctl_subdev_match_core)(struct device *, void *))
+{
+ int rc = -ENODEV;
+ struct device_driver *driver;
+ struct device *dev;
+
+ driver = driver_find(MSM_CSIC_DRV_NAME, &platform_bus_type);
+ if (!driver)
+ goto out;
+
+ dev = driver_find_device(driver, NULL, (void *)core_index,
+ msm_mctl_subdev_match_core);
+ if (!dev)
+ goto out;
+
+ p_mctl->csic_sdev = dev_get_drvdata(dev);
+
+ rc = 0;
+ p_mctl->ispif_sdev = NULL;
+ return rc;
+
+out:
+ p_mctl->ispif_sdev = NULL;
+ return rc;
+}
+
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index bb2a1d4..1ab4e66 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -298,6 +298,8 @@
static int __devinit csid_probe(struct platform_device *pdev)
{
struct csid_device *new_csid_dev;
+ struct msm_cam_subdev_info sd_info;
+
int rc = 0;
CDBG("%s: device id = %d\n", __func__, pdev->id);
new_csid_dev = kzalloc(sizeof(struct csid_device), GFP_KERNEL);
@@ -338,7 +340,10 @@
}
new_csid_dev->pdev = pdev;
- msm_cam_register_subdev_node(&new_csid_dev->subdev, CSID_DEV, pdev->id);
+ sd_info.sdev_type = CSID_DEV;
+ sd_info.sd_index = pdev->id;
+ sd_info.irq_num = new_csid_dev->irq->start;
+ msm_cam_register_subdev_node(&new_csid_dev->subdev, &sd_info);
return 0;
csid_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_csiphy.c b/drivers/media/video/msm/csi/msm_csiphy.c
index e25660b..4693a8a 100644
--- a/drivers/media/video/msm/csi/msm_csiphy.c
+++ b/drivers/media/video/msm/csi/msm_csiphy.c
@@ -282,6 +282,8 @@
{
struct csiphy_device *new_csiphy_dev;
int rc = 0;
+ struct msm_cam_subdev_info sd_info;
+
CDBG("%s: device id = %d\n", __func__, pdev->id);
new_csiphy_dev = kzalloc(sizeof(struct csiphy_device), GFP_KERNEL);
if (!new_csiphy_dev) {
@@ -333,8 +335,11 @@
disable_irq(new_csiphy_dev->irq->start);
new_csiphy_dev->pdev = pdev;
+ sd_info.sdev_type = CSIPHY_DEV;
+ sd_info.sd_index = pdev->id;
+ sd_info.irq_num = new_csiphy_dev->irq->start;
msm_cam_register_subdev_node(
- &new_csiphy_dev->subdev, CSIPHY_DEV, pdev->id);
+ &new_csiphy_dev->subdev, &sd_info);
return 0;
csiphy_no_resource:
diff --git a/drivers/media/video/msm/csi/msm_ispif.c b/drivers/media/video/msm/csi/msm_ispif.c
index 23982dd..0f16bbf 100644
--- a/drivers/media/video/msm/csi/msm_ispif.c
+++ b/drivers/media/video/msm/csi/msm_ispif.c
@@ -571,16 +571,51 @@
}
}
+static long msm_ispif_cmd(struct v4l2_subdev *sd, void *arg)
+{
+ long rc = 0;
+ struct ispif_cfg_data cdata;
+
+ if (copy_from_user(&cdata, (void *)arg, sizeof(struct ispif_cfg_data)))
+ return -EFAULT;
+ CDBG("%s cfgtype = %d\n", __func__, cdata.cfgtype);
+ switch (cdata.cfgtype) {
+ case ISPIF_INIT:
+ CDBG("%s csid_version = %x\n", __func__,
+ cdata.cfg.csid_version);
+ rc = msm_ispif_init(&cdata.cfg.csid_version);
+ break;
+ case ISPIF_SET_CFG:
+ CDBG("%s len = %d, intftype = %d,.cid_mask = %d, csid = %d\n",
+ __func__,
+ cdata.cfg.ispif_params.len,
+ cdata.cfg.ispif_params.params[0].intftype,
+ cdata.cfg.ispif_params.params[0].cid_mask,
+ cdata.cfg.ispif_params.params[0].csid);
+ rc = msm_ispif_config(&cdata.cfg.ispif_params);
+ break;
+
+ case ISPIF_SET_ON_FRAME_BOUNDARY:
+ case ISPIF_SET_OFF_FRAME_BOUNDARY:
+ case ISPIF_SET_OFF_IMMEDIATELY:
+ rc = msm_ispif_subdev_video_s_stream(sd, cdata.cfg.cmd);
+ break;
+ case ISPIF_RELEASE:
+ msm_ispif_release(sd);
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
static long msm_ispif_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd,
void *arg)
{
switch (cmd) {
case VIDIOC_MSM_ISPIF_CFG:
- return msm_ispif_config((struct msm_ispif_params_list *)arg);
- case VIDIOC_MSM_ISPIF_INIT:
- return msm_ispif_init((uint32_t *)arg);
- case VIDIOC_MSM_ISPIF_RELEASE:
- msm_ispif_release(sd);
+ return msm_ispif_cmd(sd, arg);
default:
return -ENOIOCTLCMD;
}
@@ -605,6 +640,8 @@
static int __devinit ispif_probe(struct platform_device *pdev)
{
int rc = 0;
+ struct msm_cam_subdev_info sd_info;
+
CDBG("%s\n", __func__);
ispif = kzalloc(sizeof(struct ispif_device), GFP_KERNEL);
if (!ispif) {
@@ -652,7 +689,10 @@
}
ispif->pdev = pdev;
- msm_cam_register_subdev_node(&ispif->subdev, ISPIF_DEV, pdev->id);
+ sd_info.sdev_type = ISPIF_DEV;
+ sd_info.sd_index = pdev->id;
+ sd_info.irq_num = ispif->irq->start;
+ msm_cam_register_subdev_node(&ispif->subdev, &sd_info);
return 0;
ispif_no_mem:
diff --git a/drivers/media/video/msm/csi/msm_ispif.h b/drivers/media/video/msm/csi/msm_ispif.h
index 8f1dd12..7b301ba 100644
--- a/drivers/media/video/msm/csi/msm_ispif.h
+++ b/drivers/media/video/msm/csi/msm_ispif.h
@@ -43,25 +43,7 @@
};
#define VIDIOC_MSM_ISPIF_CFG \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_ispif_params)
-
-#define VIDIOC_MSM_ISPIF_INIT \
- _IO('V', BASE_VIDIOC_PRIVATE + 2)
-
-#define VIDIOC_MSM_ISPIF_RELEASE \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct v4l2_subdev*)
-
-#define ISPIF_STREAM(intf, action) (((intf)<<ISPIF_S_STREAM_SHIFT)+(action))
-#define ISPIF_ON_FRAME_BOUNDARY (0x01 << 0)
-#define ISPIF_OFF_FRAME_BOUNDARY (0x01 << 1)
-#define ISPIF_OFF_IMMEDIATELY (0x01 << 2)
-#define ISPIF_S_STREAM_SHIFT 4
-
-
-#define PIX_0 (0x01 << 0)
-#define RDI_0 (0x01 << 1)
-#define PIX_1 (0x01 << 2)
-#define RDI_1 (0x01 << 3)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 18, struct ispif_cfg_data*)
void msm_ispif_vfe_get_cid(uint8_t intftype, char *cids, int *num);
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index 7c4021d..54c59f8 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -17,15 +17,16 @@
#include <linux/pwm.h>
#include <linux/pmic8058-pwm.h>
#include <linux/hrtimer.h>
-#include <linux/i2c.h>
#include <linux/export.h>
#include <mach/pmic.h>
#include <mach/camera.h>
#include <mach/gpio.h>
+#include "msm_camera_i2c.h"
struct i2c_client *sx150x_client;
struct timer_list timer_flash;
static struct msm_camera_sensor_info *sensor_data;
+static struct msm_camera_i2c_client i2c_client;
enum msm_cam_flash_stat{
MSM_CAM_FLASH_OFF,
MSM_CAM_FLASH_ON,
@@ -33,47 +34,6 @@
static struct i2c_client *sc628a_client;
-static int32_t flash_i2c_txdata(struct i2c_client *client,
- unsigned char *txdata, int length)
-{
- struct i2c_msg msg[] = {
- {
- .addr = client->addr >> 1,
- .flags = 0,
- .len = length,
- .buf = txdata,
- },
- };
- if (i2c_transfer(client->adapter, msg, 1) < 0) {
- CDBG("flash_i2c_txdata faild 0x%x\n", client->addr >> 1);
- return -EIO;
- }
-
- return 0;
-}
-
-static int32_t flash_i2c_write_b(struct i2c_client *client,
- uint8_t baddr, uint8_t bdata)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[2];
- if (!client)
- return -ENOTSUPP;
-
- memset(buf, 0, sizeof(buf));
- buf[0] = baddr;
- buf[1] = bdata;
-
- rc = flash_i2c_txdata(client, buf, 2);
- if (rc < 0) {
- CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
- baddr, bdata);
- }
- usleep_range(4000, 5000);
-
- return rc;
-}
-
static const struct i2c_device_id sc628a_i2c_id[] = {
{"sc628a", 0},
{ }
@@ -128,8 +88,10 @@
}
tps61310_client = client;
-
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
if (rc < 0) {
tps61310_client = NULL;
goto probe_failure;
@@ -431,10 +393,18 @@
break;
case MSM_CAMERA_LED_OFF:
- if (sc628a_client)
- rc = flash_i2c_write_b(sc628a_client, 0x02, 0x00);
- if (tps61310_client)
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x00);
+ if (sc628a_client) {
+ i2c_client.client = sc628a_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (tps61310_client) {
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
gpio_set_value_cansleep(external->led_en, 0);
gpio_set_value_cansleep(external->led_flash_en, 0);
break;
@@ -443,20 +413,36 @@
gpio_set_value_cansleep(external->led_en, 1);
gpio_set_value_cansleep(external->led_flash_en, 1);
usleep_range(2000, 3000);
- if (sc628a_client)
- rc = flash_i2c_write_b(sc628a_client, 0x02, 0x06);
- if (tps61310_client)
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x86);
+ if (sc628a_client) {
+ i2c_client.client = sc628a_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x06,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (tps61310_client) {
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x86,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
break;
case MSM_CAMERA_LED_HIGH:
gpio_set_value_cansleep(external->led_en, 1);
gpio_set_value_cansleep(external->led_flash_en, 1);
usleep_range(2000, 3000);
- if (sc628a_client)
- rc = flash_i2c_write_b(sc628a_client, 0x02, 0x49);
- if (tps61310_client)
- rc = flash_i2c_write_b(tps61310_client, 0x01, 0x8B);
+ if (sc628a_client) {
+ i2c_client.client = sc628a_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x02, 0x49,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (tps61310_client) {
+ i2c_client.client = tps61310_client;
+ i2c_client.addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+ rc = msm_camera_i2c_write(&i2c_client, 0x01, 0x8B,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ }
break;
default:
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.h b/drivers/media/video/msm/gemini/msm_gemini_platform.h
index 4542129..eb6b9f0 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.h
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.h
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/ion.h>
+#include <linux/iommu.h>
void msm_gemini_platform_p2v(struct file *file,
struct ion_handle **ionhandle);
uint32_t msm_gemini_platform_v2p(int fd, uint32_t len, struct file **file,
diff --git a/drivers/media/video/msm/gemini/msm_gemini_sync.c b/drivers/media/video/msm/gemini/msm_gemini_sync.c
index fe7c99f..b55ec18 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_sync.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_sync.c
@@ -453,6 +453,7 @@
{
struct msm_gemini_core_buf *buf_p;
struct msm_gemini_buf buf_cmd;
+ int rc = 0;
if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_gemini_buf))) {
GMN_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
@@ -469,17 +470,25 @@
(int) buf_cmd.vaddr, buf_cmd.y_len);
if (pgmn_dev->op_mode == MSM_GEMINI_MODE_REALTIME_ENCODE) {
- buf_p->y_buffer_addr = buf_cmd.y_off;
+ rc = msm_iommu_map_contig_buffer(
+ (unsigned long)buf_cmd.y_off, CAMERA_DOMAIN, GEN_POOL,
+ ((buf_cmd.y_len + buf_cmd.cbcr_len + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&buf_p->y_buffer_addr);
+ if (rc < 0) {
+ pr_err("%s iommu mapping failed with error %d\n",
+ __func__, rc);
+ kfree(buf_p);
+ return rc;
+ }
} else {
buf_p->y_buffer_addr = msm_gemini_platform_v2p(buf_cmd.fd,
buf_cmd.y_len + buf_cmd.cbcr_len, &buf_p->file,
&buf_p->handle) + buf_cmd.offset;
}
buf_p->y_len = buf_cmd.y_len;
-
buf_p->cbcr_buffer_addr = buf_p->y_buffer_addr + buf_cmd.y_len;
buf_p->cbcr_len = buf_cmd.cbcr_len;
-
buf_p->num_of_mcu_rows = buf_cmd.num_of_mcu_rows;
GMN_DBG("%s: y_addr=%x,y_len=%x,cbcr_addr=%x,cbcr_len=%x\n", __func__,
buf_p->y_buffer_addr, buf_p->y_len, buf_p->cbcr_buffer_addr,
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index 64df7fb..611eecd 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -1,9 +1,9 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
-obj-$(CONFIG_MSM_CAMERA) += msm_camera_io_util.o
EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_CAMERA) += msm_camera_io_util.o msm_camera_i2c.o
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
- obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_i2c_mux.o
+ obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c_mux.o
obj-$(CONFIG_ARCH_MSM7X27A) += msm_io_7x27a_v4l2.o
obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o
obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index 6f45637..cecf9b0 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -165,6 +165,31 @@
return rc;
}
+int32_t msm_camera_i2c_set_write_mask_data(struct msm_camera_i2c_client *client,
+ uint16_t addr, uint16_t data, int16_t mask,
+ enum msm_camera_i2c_data_type data_type)
+{
+ int32_t rc;
+ uint16_t reg_data;
+ CDBG("%s\n", __func__);
+ if (mask == -1)
+ return 0;
+ if (mask == 0)
+ rc = msm_camera_i2c_write(client, addr, data, data_type);
+ else{
+ rc = msm_camera_i2c_read(client, addr, ®_data, data_type);
+ if (rc < 0) {
+ CDBG("%s read fail\n", __func__);
+ return rc;
+ }
+ reg_data = reg_data & mask;
+ reg_data = (reg_data | (data & (~mask)));
+ rc = msm_camera_i2c_write(client, addr, reg_data, data_type);
+ if (rc < 0)
+ CDBG("%s write fail\n", __func__);
+ }
+ return rc;
+}
int32_t msm_camera_i2c_compare(struct msm_camera_i2c_client *client,
uint16_t addr, uint16_t data,
@@ -291,6 +316,13 @@
reg_conf_tbl->reg_data,
MSM_CAMERA_I2C_WORD_DATA, 0);
break;
+ case MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA:
+ rc = msm_camera_i2c_set_write_mask_data(client,
+ reg_conf_tbl->reg_addr,
+ reg_conf_tbl->reg_data,
+ reg_conf_tbl->mask,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ break;
default:
pr_err("%s: Unsupport data type: %d\n",
__func__, dt);
@@ -402,7 +434,6 @@
if (i >= conf->num_index)
return rc;
-
rc = msm_sensor_write_all_conf_array(client,
&conf->conf[i*conf->num_conf], conf->num_conf);
@@ -426,4 +457,3 @@
return rc;
}
-
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.h b/drivers/media/video/msm/io/msm_camera_i2c.h
index 2fbf5ca..01c8259 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.h
+++ b/drivers/media/video/msm/io/msm_camera_i2c.h
@@ -42,6 +42,7 @@
MSM_CAMERA_I2C_UNSET_BYTE_MASK,
MSM_CAMERA_I2C_SET_WORD_MASK,
MSM_CAMERA_I2C_UNSET_WORD_MASK,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA,
};
enum msm_camera_i2c_cmd_type {
@@ -52,6 +53,7 @@
struct msm_camera_i2c_reg_conf {
uint16_t reg_addr;
uint16_t reg_data;
+ int16_t mask;
enum msm_camera_i2c_data_type dt;
enum msm_camera_i2c_cmd_type cmd_type;
};
diff --git a/drivers/media/video/msm/io/msm_io_vfe31.c b/drivers/media/video/msm/io/msm_io_vfe31.c
index 0c0c450..8c733a0 100644
--- a/drivers/media/video/msm/io/msm_io_vfe31.c
+++ b/drivers/media/video/msm/io/msm_io_vfe31.c
@@ -247,7 +247,7 @@
}
if (!IS_ERR(clk))
- clk_enable(clk);
+ clk_prepare_enable(clk);
else
rc = -1;
return rc;
@@ -303,10 +303,11 @@
}
if (!IS_ERR(clk)) {
- clk_disable(clk);
+ clk_disable_unprepare(clk);
clk_put(clk);
- } else
+ } else {
rc = -1;
+ }
return rc;
}
diff --git a/drivers/media/video/msm/mercury/Makefile b/drivers/media/video/msm/mercury/Makefile
new file mode 100644
index 0000000..ce4c86d
--- /dev/null
+++ b/drivers/media/video/msm/mercury/Makefile
@@ -0,0 +1,3 @@
+GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+EXTRA_CFLAGS += -Idrivers/media/video/msm
+obj-$(CONFIG_MSM_MERCURY) += msm_mercury_dev.o msm_mercury_core.o msm_mercury_hw.o msm_mercury_platform.o msm_mercury_sync.o
diff --git a/drivers/media/video/msm/mercury/msm_mercury_common.h b/drivers/media/video/msm/mercury/msm_mercury_common.h
new file mode 100644
index 0000000..f5939c1
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_common.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MSM_MERCURY_COMMON_H
+#define MSM_MERCURY_COMMON_H
+
+#define MSM_MERCURY_DEBUG
+#ifdef MSM_MERCURY_DEBUG
+#define MCR_DBG(fmt, args...) pr_debug(fmt, ##args)
+#else
+#define MCR_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define MCR_PR_ERR pr_err
+#endif /* MSM_MERCURY_COMMON_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_core.c b/drivers/media/video/msm/mercury/msm_mercury_core.c
new file mode 100644
index 0000000..a91c257
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_core.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include "msm_mercury_hw.h"
+#include "msm_mercury_core.h"
+#include "msm_mercury_platform.h"
+#include "msm_mercury_common.h"
+
+static int reset_done_ack;
+static spinlock_t reset_lock;
+static wait_queue_head_t reset_wait;
+
+int mercury_core_reset(void)
+{
+ struct clk *clk = NULL;
+
+ /*Resettting MMSS Fabric*/
+
+ clk = clk_get(NULL, "jpegd_clk");
+
+ if (!IS_ERR(clk))
+ clk_enable(clk);
+
+ msm_bus_axi_porthalt(MSM_BUS_MASTER_JPEG_DEC);
+ clk_reset(clk, CLK_RESET_ASSERT);
+
+ /*need to have some delay here, there is no
+ other way to know if hardware reset is complete*/
+ usleep_range(1000, 1200);
+
+ msm_bus_axi_portunhalt(MSM_BUS_MASTER_JPEG_DEC);
+ clk_reset(clk, CLK_RESET_DEASSERT);
+
+ return 0;
+}
+
+int msm_mercury_core_reset(void)
+{
+ unsigned long flags;
+ int rc = 0;
+ int tm = 500;/*500ms*/
+ MCR_DBG("\n%s\n(%d)%s()\n", __FILE__, __LINE__, __func__);
+
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ msm_mercury_hw_reset();
+ rc = wait_event_interruptible_timeout(reset_wait,
+ reset_done_ack,
+ msecs_to_jiffies(tm));
+
+ if (!reset_done_ack) {
+ MCR_DBG("%s: reset ACK failed %d", __func__, rc);
+ return -EBUSY;
+ }
+
+ MCR_DBG("(%d)%s() reset_done_ack rc %d\n\n", __LINE__, __func__, rc);
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 0;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ return 0;
+}
+
+void msm_mercury_core_init(void)
+{
+ init_waitqueue_head(&reset_wait);
+ spin_lock_init(&reset_lock);
+}
+
+static int (*msm_mercury_irq_handler) (int, void *, void *);
+
+irqreturn_t msm_mercury_core_irq(int irq_num, void *context)
+{
+ void *data = NULL;
+ unsigned long flags;
+ uint16_t mcr_rd_irq;
+ uint16_t mcr_wr_irq;
+ uint32_t jpeg_status;
+
+ MCR_DBG("\n(%d)%s() irq_number = %d", __LINE__, __func__, irq_num);
+
+ spin_lock_irqsave(&reset_lock, flags);
+ reset_done_ack = 1;
+ spin_unlock_irqrestore(&reset_lock, flags);
+
+ msm_mercury_hw_irq_get_status(&mcr_rd_irq, &mcr_wr_irq);
+ msm_mercury_hw_get_jpeg_status(&jpeg_status);
+ MCR_DBG("mercury_rd_irq = 0x%08X\n", mcr_rd_irq);
+ MCR_DBG("mercury_wr_irq = 0x%08X\n", mcr_wr_irq);
+ MCR_DBG("jpeg_status = 0x%08X\n", jpeg_status);
+ if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_SW_RESET_ACK) {
+ MCR_DBG("*** SW Reset IRQ received ***\n");
+ wake_up(&reset_wait);
+ msm_mercury_hw_wr_irq_clear(MSM_MERCURY_HW_IRQ_SW_RESET_ACK);
+ }
+ if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_WR_ERR_ACK) {
+ MCR_DBG(" *** Error IRQ received ***\n");
+ msm_mercury_irq_handler(MSM_MERCURY_HW_IRQ_WR_ERR_ACK,
+ context, data);
+ }
+ if (mcr_wr_irq & MSM_MERCURY_HW_IRQ_WR_EOI_ACK) {
+ MCR_DBG(" *** WE_EOI IRQ received ***\n");
+ msm_mercury_irq_handler(MSM_MERCURY_HW_IRQ_WR_EOI_ACK,
+ context, data);
+ }
+ return IRQ_HANDLED;
+}
+
+void msm_mercury_core_irq_install(int (*irq_handler) (int, void *, void *))
+{
+ msm_mercury_irq_handler = irq_handler;
+}
+
+void msm_mercury_core_irq_remove(void)
+{
+ msm_mercury_irq_handler = NULL;
+}
diff --git a/drivers/media/video/msm/mercury/msm_mercury_core.h b/drivers/media/video/msm/mercury/msm_mercury_core.h
new file mode 100644
index 0000000..e374cee
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_core.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MSM_MERCURY_CORE_H
+#define MSM_MERCURY_CORE_H
+
+#include <linux/interrupt.h>
+#include "msm_mercury_hw.h"
+
+#define msm_mercury_core_buf msm_mercury_hw_buf
+
+irqreturn_t msm_mercury_core_irq(int irq_num, void *context);
+
+void msm_mercury_core_irq_install(int (*irq_handler) (int, void *, void *));
+void msm_mercury_core_irq_remove(void);
+
+int msm_mercury_core_reset(void);
+void msm_mercury_core_init(void);
+
+#endif /* MSM_MERCURY_CORE_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_dev.c b/drivers/media/video/msm/mercury/msm_mercury_dev.c
new file mode 100644
index 0000000..df32b26
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_dev.c
@@ -0,0 +1,256 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_mercury.h>
+#include <mach/board.h>
+#include "msm_mercury_sync.h"
+#include "msm_mercury_common.h"
+#include "msm.h"
+
+#define MSM_MERCURY_NAME "mercury"
+
+static int msm_mercury_open(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_mercury_device *pmercury_dev = container_of(inode->i_cdev,
+ struct msm_mercury_device, cdev);
+ filp->private_data = pmercury_dev;
+
+ MCR_DBG("\n---(%d)%s()\n", __LINE__, __func__);
+
+ rc = __msm_mercury_open(pmercury_dev);
+
+ MCR_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pmercury_dev->open_count);
+
+ return rc;
+}
+
+static int msm_mercury_release(struct inode *inode, struct file *filp)
+{
+ int rc;
+
+ struct msm_mercury_device *pmercury_dev = filp->private_data;
+
+ MCR_DBG("\n---(%d)%s()\n", __LINE__, __func__);
+
+ rc = __msm_mercury_release(pmercury_dev);
+
+ MCR_DBG("%s:%d] %s open_count = %d\n", __func__, __LINE__,
+ filp->f_path.dentry->d_name.name, pmercury_dev->open_count);
+ return rc;
+}
+
+static long msm_mercury_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg) {
+ int rc;
+ struct msm_mercury_device *pmercury_dev = filp->private_data;
+ rc = __msm_mercury_ioctl(pmercury_dev, cmd, arg);
+ return rc;
+}
+
+static const struct file_operations msm_mercury_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_mercury_open,
+ .release = msm_mercury_release,
+ .unlocked_ioctl = msm_mercury_ioctl,
+};
+
+static struct class *msm_mercury_class;
+static dev_t msm_mercury_devno;
+static struct msm_mercury_device *msm_mercury_device_p;
+
+int msm_mercury_subdev_init(struct v4l2_subdev *mercury_sd)
+{
+ int rc;
+ struct msm_mercury_device *pgmn_dev =
+ (struct msm_mercury_device *)mercury_sd->host_priv;
+
+ MCR_DBG("%s:%d: mercury_sd=0x%x pgmn_dev=0x%x\n",
+ __func__, __LINE__, (uint32_t)mercury_sd, (uint32_t)pgmn_dev);
+ rc = __msm_mercury_open(pgmn_dev);
+ MCR_DBG("%s:%d: rc=%d\n",
+ __func__, __LINE__, rc);
+ return rc;
+}
+
+static long msm_mercury_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ long rc;
+ struct msm_mercury_device *pgmn_dev =
+ (struct msm_mercury_device *)sd->host_priv;
+
+ MCR_DBG("%s: cmd=%d\n", __func__, cmd);
+
+ MCR_DBG("%s: pgmn_dev 0x%x", __func__, (uint32_t)pgmn_dev);
+
+ MCR_DBG("%s: Calling __msm_mercury_ioctl\n", __func__);
+
+ rc = __msm_mercury_ioctl(pgmn_dev, cmd, (unsigned long)arg);
+ pr_debug("%s: X\n", __func__);
+ return rc;
+}
+
+void msm_mercury_subdev_release(struct v4l2_subdev *mercury_sd)
+{
+ int rc;
+ struct msm_mercury_device *pgmn_dev =
+ (struct msm_mercury_device *)mercury_sd->host_priv;
+ MCR_DBG("%s:pgmn_dev=0x%x", __func__, (uint32_t)pgmn_dev);
+ rc = __msm_mercury_release(pgmn_dev);
+ MCR_DBG("%s:rc=%d", __func__, rc);
+}
+
+static const struct v4l2_subdev_core_ops msm_mercury_subdev_core_ops = {
+ .ioctl = msm_mercury_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_mercury_subdev_ops = {
+ .core = &msm_mercury_subdev_core_ops,
+};
+
+static int msm_mercury_init(struct platform_device *pdev)
+{
+ int rc = -1;
+ struct device *dev;
+
+ MCR_DBG("%s:\n", __func__);
+ msm_mercury_device_p = __msm_mercury_init(pdev);
+ if (msm_mercury_device_p == NULL) {
+ MCR_PR_ERR("%s: initialization failed\n", __func__);
+ goto fail;
+ }
+
+ v4l2_subdev_init(&msm_mercury_device_p->subdev,
+ &msm_mercury_subdev_ops);
+ v4l2_set_subdev_hostdata(&msm_mercury_device_p->subdev,
+ msm_mercury_device_p);
+ pr_debug("%s: msm_mercury_device_p 0x%x", __func__,
+ (uint32_t)msm_mercury_device_p);
+ MCR_DBG("%s:mercury: platform_set_drvdata\n", __func__);
+ platform_set_drvdata(pdev, &msm_mercury_device_p->subdev);
+
+ rc = alloc_chrdev_region(&msm_mercury_devno, 0, 1, MSM_MERCURY_NAME);
+ if (rc < 0) {
+ MCR_PR_ERR("%s: failed to allocate chrdev\n", __func__);
+ goto fail_1;
+ }
+
+ if (!msm_mercury_class) {
+ msm_mercury_class = class_create(THIS_MODULE, MSM_MERCURY_NAME);
+ if (IS_ERR(msm_mercury_class)) {
+ rc = PTR_ERR(msm_mercury_class);
+ MCR_PR_ERR("%s: create device class failed\n",
+ __func__);
+ goto fail_2;
+ }
+ }
+
+ dev = device_create(msm_mercury_class, NULL,
+ MKDEV(MAJOR(msm_mercury_devno), MINOR(msm_mercury_devno)), NULL,
+ "%s%d", MSM_MERCURY_NAME, 0);
+
+ if (IS_ERR(dev)) {
+ MCR_PR_ERR("%s: error creating device\n", __func__);
+ rc = -ENODEV;
+ goto fail_3;
+ }
+
+ cdev_init(&msm_mercury_device_p->cdev, &msm_mercury_fops);
+ msm_mercury_device_p->cdev.owner = THIS_MODULE;
+ msm_mercury_device_p->cdev.ops =
+ (const struct file_operations *) &msm_mercury_fops;
+ rc = cdev_add(&msm_mercury_device_p->cdev, msm_mercury_devno, 1);
+ if (rc < 0) {
+ MCR_PR_ERR("%s: error adding cdev\n", __func__);
+ rc = -ENODEV;
+ goto fail_4;
+ }
+
+ MCR_DBG("%s %s: success\n", __func__, MSM_MERCURY_NAME);
+
+ return rc;
+
+fail_4:
+ device_destroy(msm_mercury_class, msm_mercury_devno);
+
+fail_3:
+ class_destroy(msm_mercury_class);
+
+fail_2:
+ unregister_chrdev_region(msm_mercury_devno, 1);
+
+fail_1:
+ __msm_mercury_exit(msm_mercury_device_p);
+
+fail:
+ return rc;
+}
+
+static void msm_mercury_exit(void)
+{
+ cdev_del(&msm_mercury_device_p->cdev);
+ device_destroy(msm_mercury_class, msm_mercury_devno);
+ class_destroy(msm_mercury_class);
+ unregister_chrdev_region(msm_mercury_devno, 1);
+
+ __msm_mercury_exit(msm_mercury_device_p);
+}
+
+static int __msm_mercury_probe(struct platform_device *pdev)
+{
+ return msm_mercury_init(pdev);
+}
+
+static int __msm_mercury_remove(struct platform_device *pdev)
+{
+ msm_mercury_exit();
+ return 0;
+}
+
+static struct platform_driver msm_mercury_driver = {
+ .probe = __msm_mercury_probe,
+ .remove = __msm_mercury_remove,
+ .driver = {
+ .name = MSM_MERCURY_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_mercury_driver_init(void)
+{
+ int rc;
+ rc = platform_driver_register(&msm_mercury_driver);
+ return rc;
+}
+
+static void __exit msm_mercury_driver_exit(void)
+{
+ platform_driver_unregister(&msm_mercury_driver);
+}
+
+MODULE_DESCRIPTION("msm mercury jpeg driver");
+
+module_init(msm_mercury_driver_init);
+module_exit(msm_mercury_driver_exit);
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.c b/drivers/media/video/msm/mercury/msm_mercury_hw.c
new file mode 100644
index 0000000..7bc4abe
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.c
@@ -0,0 +1,361 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/delay.h>
+#include <linux/io.h>
+#include "msm_mercury_hw.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_hw_reg.h"
+#include "msm_mercury_macros.h"
+
+static void *mercury_region_base;
+static uint32_t mercury_region_size;
+
+
+void msm_mercury_hw_write(struct msm_mercury_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t old_data, new_data;
+
+ paddr = mercury_region_base + hw_cmd_p->offset;
+
+ if (hw_cmd_p->mask == 0xffffffff) {
+ old_data = 0;
+ } else {
+ old_data = readl_relaxed(paddr);
+ old_data &= ~hw_cmd_p->mask;
+ }
+
+ new_data = hw_cmd_p->data & hw_cmd_p->mask;
+ new_data |= old_data;
+ writel_relaxed(new_data, paddr);
+}
+
+uint32_t msm_mercury_hw_read(struct msm_mercury_hw_cmd *hw_cmd_p)
+{
+ uint32_t *paddr;
+ uint32_t data;
+
+ paddr = mercury_region_base + hw_cmd_p->offset;
+
+ data = readl_relaxed(paddr);
+ data &= hw_cmd_p->mask;
+
+ MCR_DBG("MERCURY_READ: offset=0x%04X data=0x%08X\n",
+ hw_cmd_p->offset, data);
+
+ return data;
+}
+
+void msm_mercury_hw_start_decode(void)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kread(JPEG_STATUS);
+ mercury_kread(RTDMA_JPEG_RD_STA_ACK);
+ mercury_kread(RTDMA_JPEG_WR_STA_ACK);
+ mercury_kread(RTDMA_JPEG_RD_BUF_Y_PNTR);
+ mercury_kread(RTDMA_JPEG_WR_BUF_Y_PNTR);
+ mercury_kread(RTDMA_JPEG_WR_BUF_U_PNTR);
+ mercury_kwrite(RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO, (7<<2));
+ return;
+}
+
+void msm_mercury_hw_bitstream_buf_cfg(uint32_t bitstream_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_RD_BUF_Y_PNTR, bitstream_buf_addr);
+ return;
+}
+
+
+void msm_mercury_hw_output_y_buf_cfg(uint32_t y_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_BUF_Y_PNTR, y_buf_addr);
+ return;
+}
+
+void msm_mercury_hw_output_u_buf_cfg(uint32_t u_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_BUF_U_PNTR, u_buf_addr);
+ return;
+}
+
+void msm_mercury_hw_output_v_buf_cfg(uint32_t v_buf_addr)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_BUF_V_PNTR, v_buf_addr);
+ return;
+}
+
+int msm_mercury_hw_wait(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ uint32_t data;
+ uint32_t wait_data = hw_cmd_p->data & hw_cmd_p->mask;
+
+ data = msm_mercury_hw_read(hw_cmd_p);
+ if (data != wait_data) {
+ while (tm) {
+ udelay(m_us);
+ data = msm_mercury_hw_read(hw_cmd_p);
+ if (data == wait_data)
+ break;
+ tm--;
+ }
+ }
+ hw_cmd_p->data = data;
+ return tm;
+}
+
+void msm_mercury_hw_irq_get_status(uint16_t *rd_irq, uint16_t *wr_irq)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ rmb();
+ mercury_kread(RTDMA_JPEG_RD_STA_ACK);
+ *rd_irq = hw_cmd.data;
+
+ mercury_kread(RTDMA_JPEG_WR_STA_ACK);
+ *wr_irq = hw_cmd.data;
+ rmb();
+}
+
+void msm_mercury_hw_get_jpeg_status(uint32_t *jpeg_status)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ rmb();
+ mercury_kread(JPEG_STATUS);
+ *jpeg_status = hw_cmd.data;
+ rmb();
+}
+
+uint32_t msm_mercury_get_restartInterval(void)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ rmb();
+ mercury_kread(JPEG_DRI);
+ rmb();
+ return hw_cmd.data;
+
+}
+
+void msm_mercury_hw_rd_irq_clear(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+}
+
+void msm_mercury_hw_wr_irq_clear(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+}
+
+void msm_mercury_hw_set_rd_irq_mask(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_RD_INT_EN, val);
+}
+
+void msm_mercury_hw_set_wr_irq_mask(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+}
+
+void msm_mercury_set_jpeg_ctl_common(uint32_t val)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ mercury_kwrite(JPEG_CTRL_COMMON, val);
+}
+
+void msm_mercury_hw_reset(void)
+{
+ uint32_t val;
+ struct msm_mercury_hw_cmd hw_cmd;
+
+ wmb();
+ /* disable all interrupts*/
+ mercury_kwrite(RTDMA_JPEG_RD_INT_EN, 0);
+
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, 0);
+
+ /* clear pending interrupts*/
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK,
+ SW_RESET_ABORT_RDY_ACK,
+ ERR_ACK, 1, 1);
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_RD_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+
+ /* enable SWResetAbortRdyInt for core reset*/
+ val = 0;
+ MEM_OUTF(&val, RTDMA_JPEG_WR_INT_EN, SW_RESET_ABORT_RDY_EN, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+
+ /* Reset Core from MMSS Fabric*/
+ mercury_core_reset();
+
+ /* disable all interrupts*/
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, 0);
+
+ /* clear pending interrupts*/
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK,
+ SW_RESET_ABORT_RDY_ACK,
+ ERR_ACK, 1, 1);
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_STA_ACK, val);
+
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_RD_STA_ACK, EOF_ACK, SOF_ACK, 1, 1);
+ mercury_kwrite(RTDMA_JPEG_RD_STA_ACK, val);
+
+ /* enable neccessary interrupt source*/
+ val = 0;
+ MEM_OUTF2(&val, RTDMA_JPEG_WR_INT_EN, EOF_EN, ERR_EN, 1, 1);
+ MEM_OUTF(&val, RTDMA_JPEG_WR_INT_EN, SW_RESET_ABORT_RDY_EN, 1);
+ mercury_kwrite(RTDMA_JPEG_WR_INT_EN, val);
+
+ wmb();
+
+}
+
+void msm_mercury_hw_init(void *base, int size)
+{
+ mercury_region_base = base;
+ mercury_region_size = size;
+}
+
+
+void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us)
+{
+ int tm = hw_cmd_p->n;
+ while (tm) {
+ udelay(m_us);
+ tm--;
+ }
+}
+
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds)
+{
+ int is_copy_to_user = -1;
+ uint32_t data;
+ if (m_cmds > 1)
+ MCR_DBG("m_cmds = %d\n", m_cmds);
+
+ while (m_cmds--) {
+ if (hw_cmd_p->offset > mercury_region_size) {
+ MCR_PR_ERR("%s:%d] %d exceed hw region %d\n",
+ __func__, __LINE__, hw_cmd_p->offset,
+ mercury_region_size);
+ return -EFAULT;
+ }
+
+ switch (hw_cmd_p->type) {
+ case MSM_MERCURY_HW_CMD_TYPE_READ:
+ hw_cmd_p->data = msm_mercury_hw_read(hw_cmd_p);
+ is_copy_to_user = 1;
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_WRITE:
+ msm_mercury_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_WRITE_OR:
+ data = msm_mercury_hw_read(hw_cmd_p);
+ hw_cmd_p->data = (hw_cmd_p->data & hw_cmd_p->mask) |
+ data;
+ msm_mercury_hw_write(hw_cmd_p);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_UWAIT:
+ msm_mercury_hw_wait(hw_cmd_p, 1);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_MWAIT:
+ msm_mercury_hw_wait(hw_cmd_p, 1000);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_UDELAY:
+ msm_mercury_hw_delay(hw_cmd_p, 1);
+ break;
+
+ case MSM_MERCURY_HW_CMD_TYPE_MDELAY:
+ msm_mercury_hw_delay(hw_cmd_p, 1000);
+ break;
+
+ default:
+ MCR_DBG("wrong hw command type\n");
+ break;
+ }
+
+ hw_cmd_p++;
+ }
+ return is_copy_to_user;
+}
+
+void msm_mercury_hw_region_dump(int size)
+{
+ uint32_t *p;
+ uint8_t *p8;
+
+ MCR_DBG("(%d)%s()\n", __LINE__, __func__);
+ if (size > mercury_region_size)
+ MCR_DBG("%s:%d] wrong region dump size\n",
+ __func__, __LINE__);
+
+ p = (uint32_t *) mercury_region_base;
+ while (size >= 16) {
+ MCR_DBG("0x%08X] %08X %08X %08X %08X\n",
+ mercury_region_size - size,
+ readl_relaxed(p), readl_relaxed(p+1),
+ readl_relaxed(p+2), readl_relaxed(p+3));
+ p += 4;
+ size -= 16;
+ }
+
+ if (size > 0) {
+ uint32_t d;
+ MCR_DBG("0x%08X] ", mercury_region_size - size);
+ while (size >= 4) {
+ MCR_DBG("%08X ", readl_relaxed(p++));
+ size -= 4;
+ }
+
+ d = readl_relaxed(p);
+ p8 = (uint8_t *) &d;
+ while (size) {
+ MCR_DBG("%02X", *p8++);
+ size--;
+ }
+
+ MCR_DBG("\n");
+ }
+}
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw.h b/drivers/media/video/msm/mercury/msm_mercury_hw.h
new file mode 100644
index 0000000..f6e3e49
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MSM_MERCURY_HW_H
+#define MSM_MERCURY_HW_H
+
+#include <media/msm_mercury.h>
+
+/*number of pel per block (horiz/vert)*/
+#define JPEGDEC_BLOCK_SIZE (8)
+/* Hardware alignment*/
+#define JPEGDEC_HW_ALIGN (8)
+#define JPEGDEC_HW_SAMPLING_RATIO_MAX (4)
+
+#define MSM_MERCURY_HW_IRQ_SW_RESET_ACK (1<<3)
+#define MSM_MERCURY_HW_IRQ_WR_ERR_ACK (1<<2)
+#define MSM_MERCURY_HW_IRQ_WR_EOI_ACK (1<<1)
+#define MSM_MERCURY_HW_IRQ_WR_SOF_ACK (1<<0)
+
+#define MSM_MERCURY_HW_IRQ_RD_EOF_ACK (1<<1)
+#define MSM_MERCURY_HW_IRQ_RD_SOF_ACK (1<<0)
+
+extern int mercury_core_reset(void);
+
+struct msm_mercury_hw_buf {
+ struct msm_mercury_buf vbuf;
+ struct file *file;
+ uint32_t framedone_len;
+ uint32_t y_buffer_addr;
+ uint32_t y_len;
+ uint32_t cbcr_buffer_addr;
+ uint32_t cbcr_len;
+ uint32_t num_of_mcu_rows;
+ struct msm_mapped_buffer *msm_buffer;
+ int *subsystem_id;
+ struct ion_handle *handle;
+};
+
+
+void msm_mercury_hw_reset(void);
+void msm_mercury_hw_init(void *base, int size);
+void msm_mercury_hw_rd_irq_clear(uint32_t val);
+void msm_mercury_hw_wr_irq_clear(uint32_t val);
+
+uint32_t msm_mercury_hw_read(struct msm_mercury_hw_cmd *hw_cmd_p);
+void msm_mercury_hw_write(struct msm_mercury_hw_cmd *hw_cmd_p);
+int msm_mercury_hw_wait(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
+void msm_mercury_hw_delay(struct msm_mercury_hw_cmd *hw_cmd_p, int m_us);
+int msm_mercury_hw_exec_cmds(struct msm_mercury_hw_cmd *hw_cmd_p, int m_cmds);
+void msm_mercury_hw_region_dump(int size);
+
+
+void msm_mercury_hw_irq_get_status(uint16_t *rd_irq, uint16_t *wr_irq);
+void msm_mercury_hw_start_decode(void);
+void msm_mercury_hw_get_jpeg_status(uint32_t *jpeg_status);
+void msm_mercury_hw_output_y_buf_cfg(uint32_t y_buf_addr);
+void msm_mercury_hw_output_u_buf_cfg(uint32_t u_buf_addr);
+void msm_mercury_hw_output_v_buf_cfg(uint32_t v_buf_addr);
+void msm_mercury_hw_bitstream_buf_cfg(uint32_t bitstream_buf_addr);
+
+#endif /* MSM_MERCURY_HW_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h b/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h
new file mode 100644
index 0000000..671bc66
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_hw_reg.h
@@ -0,0 +1,715 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MSM_MERCURY_HW_REG_H
+#define MSM_MERCURY_HW_REG_H
+
+
+#define JPEGD_BASE 0x00000000
+
+/* Register ADDR, RMSK, and SHFT*/
+/* RW */
+#define JPEG_CTRL_COMMON JPEG_CTRL_COMMON
+#define HWIO_JPEG_CTRL_COMMON_ADDR (JPEGD_BASE+0x00000000)
+#define HWIO_JPEG_CTRL_COMMON__POR 0x00000000
+#define HWIO_JPEG_CTRL_COMMON__RMSK 0x0000001F
+#define HWIO_JPEG_CTRL_COMMON__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_ZZ_OVERRIDE_EN__BMSK 0x00000010
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_ZZ_OVERRIDE_EN__SHFT 4
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_MODE__BMSK 0x0000000F
+#define HWIO_JPEG_CTRL_COMMON__JPEG_CTRL_COMMON_MODE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+/* RW */
+#define JPEG_CTRL_ENCODE JPEG_CTRL_ENCODE
+#define HWIO_JPEG_CTRL_ENCODE_ADDR (JPEGD_BASE+0x00000008)
+#define HWIO_JPEG_CTRL_ENCODE__POR 0x00000000
+#define HWIO_JPEG_CTRL_ENCODE__RMSK 0x00000010
+#define HWIO_JPEG_CTRL_ENCODE__SHFT 4
+/* Register Element MIN and MAX*/
+#define HWIO_JPEG_CTRL_ENCODE___S 4
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CTRL_ENCODE__JPEG_CTRL_ENCODE_EOI_MARKER_EN__BMSK 0x00000010
+#define HWIO_JPEG_CTRL_ENCODE__JPEG_CTRL_ENCODE_EOI_MARKER_EN__SHFT 4
+
+/* Register Field FMSK and SHFT*/
+#define JPEG_STATUS JPEG_STATUS
+#define HWIO_JPEG_STATUS_ADDR (JPEGD_BASE+0x00000010)
+#define HWIO_JPEG_STATUS__POR 0x00000000
+#define HWIO_JPEG_STATUS__RMSK 0x00003FF0
+#define HWIO_JPEG_STATUS__SHFT 4
+/* Register Element MIN and MAX*/
+#define HWIO_JPEG_STATUS___S 4
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_STATUS__JPEG_STATUS_REGISTER_TIMEOUT__BMSK 0x00002000
+#define HWIO_JPEG_STATUS__JPEG_STATUS_REGISTER_TIMEOUT__SHFT 13
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_EOI__BMSK 0x00001000
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_EOI__SHFT 12
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_UNESCAPED_FF__BMSK 0x00000800
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_UNESCAPED_FF__SHFT 11
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_HUFFCODE__BMSK 0x00000400
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_HUFFCODE__SHFT 10
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_MARKER__BMSK 0x00000200
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_INV_MARKER__SHFT 9
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_SEQ__BMSK 0x00000100
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_SEQ__SHFT 8
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_OVRFLW__BMSK 0x00000080
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_OVRFLW__SHFT 7
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_UNDFLW__BMSK 0x00000040
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_RSTRT_UNDFLW__SHFT 6
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_OVRFLW__BMSK 0x00000020
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_OVRFLW__SHFT 5
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_UNDFLW__BMSK 0x00000010
+#define HWIO_JPEG_STATUS__JPEG_STATUS_DHDQ_ERR_SCAN_UNDFLW__SHFT 4
+
+/* Register ADDR, RMSK, and SHFT*/
+/* R */
+#define JPEG_SOF_REG_0 JPEG_SOF_REG_0
+#define HWIO_JPEG_SOF_REG_0_ADDR /* RW */ (JPEGD_BASE+0x00000014)
+#define HWIO_JPEG_SOF_REG_0__POR 0x00000000
+#define HWIO_JPEG_SOF_REG_0__RMSK 0x000000FF
+#define HWIO_JPEG_SOF_REG_0__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_0__JPEG_SOF_REG_0_NF__BMSK 0x000000FF
+#define HWIO_JPEG_SOF_REG_0__JPEG_SOF_REG_0_NF__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOF_REG_1 JPEG_SOF_REG_1
+#define HWIO_JPEG_SOF_REG_1_ADDR /* RW */ (JPEGD_BASE+0x00000018)
+#define HWIO_JPEG_SOF_REG_1__POR 0x00000000
+#define HWIO_JPEG_SOF_REG_1__RMSK 0x00FFFFFF
+#define HWIO_JPEG_SOF_REG_1__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_C__BMSK 0x00FF0000
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_C__SHFT 16
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_H__BMSK 0x0000F000
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_H__SHFT 12
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_V__BMSK 0x00000F00
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_V__SHFT 8
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_TQ__BMSK 0x000000FF
+#define HWIO_JPEG_SOF_REG_1__JPEG_SOF_REG_1_TQ__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOF_REG_2 JPEG_SOF_REG_2
+#define HWIO_JPEG_SOF_REG_2_ADDR /* RW */ (JPEGD_BASE+0x0000001C)
+#define HWIO_JPEG_SOF_REG_2__POR 0x00000000
+#define HWIO_JPEG_SOF_REG_2__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_SOF_REG_2__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_Y__BMSK 0xFFFF0000
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_Y__SHFT 16
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_X__BMSK 0x0000FFFF
+#define HWIO_JPEG_SOF_REG_2__JPEG_SOF_REG_2_X__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOS_REG_0 JPEG_SOS_REG_0
+#define HWIO_JPEG_SOS_REG_0_ADDR /* RW */ (JPEGD_BASE+0x00000020)
+#define HWIO_JPEG_SOS_REG_0__POR 0x00000000
+#define HWIO_JPEG_SOS_REG_0__RMSK 0xFF000000
+#define HWIO_JPEG_SOS_REG_0__SHFT 24
+/*Register Element MIN and MAX*/
+#define HWIO_JPEG_SOS_REG_0___S 24
+#define HWIO_JPEG_SOS_REG_0___S 24
+#define HWIO_JPEG_SOS_REG_0___S 24
+#define HWIO_JPEG_SOS_REG_0___S 24
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOS_REG_0__JPEG_SOS_REG_0_NS__BMSK 0xFF000000
+#define HWIO_JPEG_SOS_REG_0__JPEG_SOS_REG_0_NS__SHFT 24
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SOS_REG_1 JPEG_SOS_REG_1
+#define HWIO_JPEG_SOS_REG_1_ADDR /* RW */ (JPEGD_BASE+0x00000024)
+#define HWIO_JPEG_SOS_REG_1__POR 0x00000000
+#define HWIO_JPEG_SOS_REG_1__RMSK 0x0000FFFF
+#define HWIO_JPEG_SOS_REG_1__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_CS__BMSK 0x0000FF00
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_CS__SHFT 8
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TD__BMSK 0x000000F0
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TD__SHFT 4
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TA__BMSK 0x0000000F
+#define HWIO_JPEG_SOS_REG_1__JPEG_SOS_REG_1_TA__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_QT_IDX JPEG_QT_IDX
+#define HWIO_JPEG_QT_IDX_ADDR (JPEGD_BASE+0x00000030)
+#define HWIO_JPEG_QT_IDX__POR 0x00000000
+#define HWIO_JPEG_QT_IDX__RMSK 0x0000FFFF
+#define HWIO_JPEG_QT_IDX__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_1__BMSK 0x0000FF00
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_1__SHFT 8
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_0__BMSK 0x000000FF
+#define HWIO_JPEG_QT_IDX__JPEG_QT_IDX_TABLE_0__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DQT JPEG_DQT
+#define HWIO_JPEG_DQT_ADDR /* RW */ (JPEGD_BASE+0x00000034)
+#define HWIO_JPEG_DQT__POR 0x00000000
+#define HWIO_JPEG_DQT__RMSK 0x0F00FFFF
+#define HWIO_JPEG_DQT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DQT__JPEG_DQT_TQ__BMSK 0x0F000000
+#define HWIO_JPEG_DQT__JPEG_DQT_TQ__SHFT 24
+#define HWIO_JPEG_DQT__JPEG_DQT_QK__BMSK 0x0000FFFF
+#define HWIO_JPEG_DQT__JPEG_DQT_QK__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DRI JPEG_DRI
+#define HWIO_JPEG_DRI_ADDR /* RW */ (JPEGD_BASE+0x00000040)
+#define HWIO_JPEG_DRI__POR 0x00000000
+#define HWIO_JPEG_DRI__RMSK 0x0000FFFF
+#define HWIO_JPEG_DRI__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DRI__JPEG_DRI_RI__BMSK 0x0000FFFF
+#define HWIO_JPEG_DRI__JPEG_DRI_RI__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_REG_0 JPEG_DHT_REG_0
+#define HWIO_JPEG_DHT_REG_0_ADDR /* RW */ (JPEGD_BASE+0x00000050)
+#define HWIO_JPEG_DHT_REG_0__POR 0x00000000
+#define HWIO_JPEG_DHT_REG_0__RMSK 0x000000FF
+#define HWIO_JPEG_DHT_REG_0__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TH__BMSK 0x000000F0
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TH__SHFT 4
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TC__BMSK 0x0000000F
+#define HWIO_JPEG_DHT_REG_0__JPEG_DHT_REG_0_TC__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_IDX JPEG_DHT_IDX
+#define HWIO_JPEG_DHT_IDX_ADDR /* RW */ (JPEGD_BASE+0x00000054)
+#define HWIO_JPEG_DHT_IDX__POR 0x00000000
+#define HWIO_JPEG_DHT_IDX__RMSK 0x00000FFF
+#define HWIO_JPEG_DHT_IDX__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_CCC_MAX__BMSK 0x00000F00
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_CCC_MAX__SHFT 8
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_VIJ__BMSK 0x000000FF
+#define HWIO_JPEG_DHT_IDX__JPEG_DHT_IDX_VIJ__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_REG_1 JPEG_DHT_REG_1
+#define HWIO_JPEG_DHT_REG_1_ADDR /* RW */ (JPEGD_BASE+0x00000058)
+#define HWIO_JPEG_DHT_REG_1__POR 0x00000000
+#define HWIO_JPEG_DHT_REG_1__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_DHT_REG_1__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_0__BMSK 0xFF000000
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_0__SHFT 24
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_1__BMSK 0x00FF0000
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_1__SHFT 16
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_2__BMSK 0x0000FF00
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_2__SHFT 8
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_3__BMSK 0x000000FF
+#define HWIO_JPEG_DHT_REG_1__JPEG_DHT_REG_1_VIJ_3__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DHT_CCC_MAX JPEG_DHT_CCC_MAX
+#define HWIO_JPEG_DHT_CCC_MAX_ADDR /* RW */ (JPEGD_BASE+0x0000005C)
+#define HWIO_JPEG_DHT_CCC_MAX__POR 0x00000000
+#define HWIO_JPEG_DHT_CCC_MAX__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_DHT_CCC_MAX__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__BMSK 0xFFFF0000
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__SHFT 16
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__BMSK 0x0000FFFF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__BMSK 0xFFFF0000
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_MAX__SHFT 16
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__BMSK 0x0000FFFF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_CCC_MAX_CCC__SHFT 0
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_LI__BMSK 0x000000FF
+#define HWIO_JPEG_DHT_CCC_MAX__JPEG_DHT_LI__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DEC_SCALE JPEG_DEC_SCALE
+#define HWIO_JPEG_DEC_SCALE_ADDR /* RW */ (JPEGD_BASE+0x00000060)
+#define HWIO_JPEG_DEC_SCALE__POR 0x00000000
+#define HWIO_JPEG_DEC_SCALE__RMSK 0x00000003
+#define HWIO_JPEG_DEC_SCALE__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DEC_SCALE__JPEG_DEC_SCALE_RATIO__BMSK 0x00000003
+#define HWIO_JPEG_DEC_SCALE__JPEG_DEC_SCALE_RATIO__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_CONVERT JPEG_CONVERT
+#define HWIO_JPEG_CONVERT_ADDR /* RW */ (JPEGD_BASE+0x00000064)
+#define HWIO_JPEG_CONVERT__POR 0x00000000
+#define HWIO_JPEG_CONVERT__RMSK 0xFFFF13FF
+#define HWIO_JPEG_CONVERT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CB_VALUE__BMSK 0xFF000000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CB_VALUE__SHFT 24
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CR_VALUE__BMSK 0x00FF0000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONO_CR_VALUE__SHFT 16
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CLAMP_EN__BMSK 0x00001000
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CLAMP_EN__SHFT 12
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CBCR_SWITCH__BMSK 0x00000200
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_CBCR_SWITCH__SHFT 9
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONOCHROME_EN__BMSK 0x00000100
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MONOCHROME_EN__SHFT 8
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MEM_ORG__BMSK 0x000000C0
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_MEM_ORG__SHFT 6
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_422_MCU_TYPE__BMSK 0x00000030
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_422_MCU_TYPE__SHFT 4
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_OUTPUT_FORMAT__BMSK 0x0000000C
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_OUTPUT_FORMAT__SHFT 2
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_INPUT_FORMAT__BMSK 0x00000003
+#define HWIO_JPEG_CONVERT__JPEG_CONVERT_INPUT_FORMAT__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_ENC_BYTE_CNT JPEG_ENC_BYTE_CNT
+#define HWIO_JPEG_ENC_BYTE_CNT_ADDR /* RW */ (JPEGD_BASE+0x00000070)
+#define HWIO_JPEG_ENC_BYTE_CNT__POR 0x00000000
+#define HWIO_JPEG_ENC_BYTE_CNT__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_ENC_BYTE_CNT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_ENC_BYTE_CNT__JPEG_ENC_BYTE_CNT_TOT__BMSK 0xFFFFFFFF
+#define HWIO_JPEG_ENC_BYTE_CNT__JPEG_ENC_BYTE_CNT_TOT__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_DEBUG JPEG_DEBUG
+#define HWIO_JPEG_DEBUG_ADDR /* RW */ (JPEGD_BASE+0x00000080)
+#define HWIO_JPEG_DEBUG__POR 0x4A504547
+#define HWIO_JPEG_DEBUG__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_DEBUG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_DEBUG__JPEG_DEBUG__BMSK 0xFFFFFFFF
+#define HWIO_JPEG_DEBUG__JPEG_DEBUG__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_SPARE JPEG_SPARE
+#define HWIO_JPEG_SPARE_ADDR /* RW */ (JPEGD_BASE+0x00000084)
+#define HWIO_JPEG_SPARE__POR 0x00000000
+#define HWIO_JPEG_SPARE__RMSK 0xFFFFFFFF
+#define HWIO_JPEG_SPARE__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_SPARE__JPEG_SPARE_00__BMSK 0xFFFFFFFF
+#define HWIO_JPEG_SPARE__JPEG_SPARE_00__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEG_REGISTER_TIMEOUT JPEG_REGISTER_TIMEOUT
+#define HWIO_JPEG_REGISTER_TIMEOUT_ADDR (JPEGD_BASE+0x00000088)
+#define HWIO_JPEG_REGISTER_TIMEOUT__POR 0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__RMSK 0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEG_REGISTER_TIMEOUT__JPEG_TIMEOUT_VALUE__BMSK 0x0000FFFF
+#define HWIO_JPEG_REGISTER_TIMEOUT__JPEG_TIMEOUT_VALUE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_STATUS_BUS_DATA JPEGD_STATUS_BUS_DATA
+#define HWIO_JPEGD_STATUS_BUS_DATA_ADDR /* RW */ (JPEGD_BASE+0x00000258)
+#define HWIO_JPEGD_STATUS_BUS_DATA__POR 0x00000000
+#define HWIO_JPEGD_STATUS_BUS_DATA__RMSK 0xFFFFFFFF
+#define HWIO_JPEGD_STATUS_BUS_DATA__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_STATUS_BUS_DATA__STATUS_BUS_DATA__BMSK 0xFFFFFFFF
+#define HWIO_JPEGD_STATUS_BUS_DATA__STATUS_BUS_DATA__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_STATUS_BUS_CONFIG JPEGD_STATUS_BUS_CONFIG
+#define HWIO_JPEGD_STATUS_BUS_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x0000025C)
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__POR 0x00000000
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__RMSK 0x0000001F
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__STATUS_BUS_SEL__BMSK 0x0000001F
+#define HWIO_JPEGD_STATUS_BUS_CONFIG__STATUS_BUS_SEL__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_AXI_CONFIG RTDMA_JPEG_AXI_CONFIG
+#define HWIO_RTDMA_JPEG_AXI_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x00000260)
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__POR 0x00000024
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__RMSK 0x00000FFF
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_WR__BMSK 0x00000800
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_WR__SHFT 11
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_RD__BMSK 0x00000400
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__OUT_OF_ORDER_RD__SHFT 10
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__BOUND_LIMIT__BMSK 0x00000300
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__BOUND_LIMIT__SHFT 8
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_TIMEOUT__BMSK 0x000000F0
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_TIMEOUT__SHFT 4
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_MAX_BLEN__BMSK 0x0000000F
+#define HWIO_RTDMA_JPEG_AXI_CONFIG__PACK_MAX_BLEN__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define JPEGD_CLK_CONTROL JPEGD_CLK_CONTROL
+#define HWIO_JPEGD_CLK_CONTROL_ADDR /* RW */ (JPEGD_BASE+0x00000264)
+#define HWIO_JPEGD_CLK_CONTROL__POR 0x00000005
+#define HWIO_JPEGD_CLK_CONTROL__RMSK 0x0000000F
+#define HWIO_JPEGD_CLK_CONTROL__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKIDLE__BMSK 0x00000008
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKIDLE__SHFT 3
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKON__BMSK 0x00000004
+#define HWIO_JPEGD_CLK_CONTROL__JPEG_CLKON__SHFT 2
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKIDLE__BMSK 0x00000002
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKIDLE__SHFT 1
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKON__BMSK 0x00000001
+#define HWIO_JPEGD_CLK_CONTROL__AXI_CLKON__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_CONFIG RTDMA_JPEG_WR_BUF_CONFIG
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x00000200)
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__RMSK 0x0000001F
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__BUF_FORMAT__BMSK 0x0000001C
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__BUF_FORMAT__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__NUM_OF_PLANES__BMSK 0x00000003
+#define HWIO_RTDMA_JPEG_WR_BUF_CONFIG__NUM_OF_PLANES__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_OP RTDMA_JPEG_WR_OP
+#define HWIO_RTDMA_JPEG_WR_OP_ADDR /* RW */ (JPEGD_BASE+0x00000204)
+#define HWIO_RTDMA_JPEG_WR_OP__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_OP__RMSK 0x00000013
+#define HWIO_RTDMA_JPEG_WR_OP__SHFT 0
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_OP__ALIGN__BMSK 0x00000010
+#define HWIO_RTDMA_JPEG_WR_OP__ALIGN__SHFT 4
+#define HWIO_RTDMA_JPEG_WR_OP__FLIP__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_OP__FLIP__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_OP__MIRROR__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_OP__MIRROR__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_Y_PNTR RTDMA_JPEG_WR_BUF_Y_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR_ADDR (JPEGD_BASE+0x00000208)
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__SHFT 3
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_Y_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_U_PNTR RTDMA_JPEG_WR_BUF_U_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR_ADDR /* RW */ (JPEGD_BASE+0x0000020C)
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_U_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_V_PNTR RTDMA_JPEG_WR_BUF_V_PNTR
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR_ADDR (JPEGD_BASE+0x00000210)
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_WR_BUF_V_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUF_PITCH RTDMA_JPEG_WR_BUF_PITCH
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH_ADDR /* RW */ (JPEGD_BASE+0x00000214)
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__RMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__PITCH__BMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_WR_BUF_PITCH__PITCH__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_PLANE_SIZE RTDMA_JPEG_WR_PLANE_SIZE
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE_ADDR /* RW */ (JPEGD_BASE+0x00000218)
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__RMSK 0x1FFF1FFF
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_VSIZE__BMSK 0x1FFF0000
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_VSIZE__SHFT 16
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_HSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_PLANE_SIZE__PLANE_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BLOCK_SIZE RTDMA_JPEG_WR_BLOCK_SIZE
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE_ADDR /* RW */ (JPEGD_BASE+0x0000021C)
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__RMSK 0x00000FFF
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_VSIZE__BMSK 0x00000FC0
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_VSIZE__SHFT 6
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_HSIZE__BMSK 0x0000003F
+#define HWIO_RTDMA_JPEG_WR_BLOCK_SIZE__BLOCK_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_BUFFER_SIZE RTDMA_JPEG_WR_BUFFER_SIZE
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE_ADDR /* RW */ (JPEGD_BASE+0x00000220)
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__RMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__BUFFER_VSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_WR_BUFFER_SIZE__BUFFER_VSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_STA_ACK RTDMA_JPEG_WR_STA_ACK
+#define HWIO_RTDMA_JPEG_WR_STA_ACK_ADDR /* RW */ (JPEGD_BASE+0x00000224)
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__RMSK 0x0000000F
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_STA__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_STA__SHFT 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_ACK__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SW_RESET_ABORT_RDY_ACK__SHFT 3
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_STA__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_STA__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_ACK__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__ERR_ACK__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_STA__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_STA__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_ACK__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__EOF_ACK__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_STA__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_STA__SHFT 0
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_ACK__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_STA_ACK__SOF_ACK__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_WR_INT_EN RTDMA_JPEG_WR_INT_EN
+#define HWIO_RTDMA_JPEG_WR_INT_EN_ADDR /* W */ (JPEGD_BASE+0x00000228)
+#define HWIO_RTDMA_JPEG_WR_INT_EN__POR 0x00000000
+#define HWIO_RTDMA_JPEG_WR_INT_EN__RMSK 0x0000000F
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SW_RESET_ABORT_RDY_EN__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SW_RESET_ABORT_RDY_EN__SHFT 3
+#define HWIO_RTDMA_JPEG_WR_INT_EN__ERR_EN__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_WR_INT_EN__ERR_EN__SHFT 2
+#define HWIO_RTDMA_JPEG_WR_INT_EN__EOF_EN__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_WR_INT_EN__EOF_EN__SHFT 1
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SOF_EN__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_WR_INT_EN__SOF_EN__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_CONFIG RTDMA_JPEG_RD_BUF_CONFIG
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG_ADDR /* RW */ (JPEGD_BASE+0x00000100)
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__RMSK 0x0000001F
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__BUF_FORMAT__BMSK 0x0000001C
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__BUF_FORMAT__SHFT 2
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__NUM_OF_PLANES__BMSK 0x00000003
+#define HWIO_RTDMA_JPEG_RD_BUF_CONFIG__NUM_OF_PLANES__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT, W */
+#define RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO_ADDR (JPEGD_BASE+0x00000104)
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__RMSK 0x0000001C
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__SHFT 2
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO___S 2
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_APPLY__BMSK 0x00000010
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_APPLY__SHFT 4
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_EOF__BMSK 0x00000008
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_EOF__SHFT 3
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_SOF__BMSK 0x00000004
+#define HWIO_RTDMA_JPEG_RD_BUF_MNGR_BUF_ID_FIFO__BUF_SOF__SHFT 2
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_Y_PNTR RTDMA_JPEG_RD_BUF_Y_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR_ADDR /* RW */ (JPEGD_BASE+0x0000010C)
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_Y_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_U_PNTR RTDMA_JPEG_RD_BUF_U_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR_ADDR /* RW */ (JPEGD_BASE+0x00000110)
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_U_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_V_PNTR RTDMA_JPEG_RD_BUF_V_PNTR
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR_ADDR /* RW */ (JPEGD_BASE+0x00000114)
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__RMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__PNTR__BMSK 0xFFFFFFF8
+#define HWIO_RTDMA_JPEG_RD_BUF_V_PNTR__PNTR__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUF_PITCH RTDMA_JPEG_RD_BUF_PITCH
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH_ADDR /* RW */ (JPEGD_BASE+0x00000118)
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__RMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__SHFT 3
+
+/* Register Element MIN and MAX*/
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH___S 3
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__PITCH__BMSK 0x00003FF8
+#define HWIO_RTDMA_JPEG_RD_BUF_PITCH__PITCH__SHFT 3
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_PLANE_SIZE RTDMA_JPEG_RD_PLANE_SIZE
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE_ADDR /* RW */ (JPEGD_BASE+0x0000011C)
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__RMSK 0x1FFF1FFF
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_VSIZE__BMSK 0x1FFF0000
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_VSIZE__SHFT 16
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_HSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_PLANE_SIZE__PLANE_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BLOCK_SIZE RTDMA_JPEG_RD_BLOCK_SIZE
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE_ADDR /* RW */ (JPEGD_BASE+0x00000120)
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__POR 0x000003CF
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__RMSK 0x00000FFF
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_VSIZE__BMSK 0x00000FC0
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_VSIZE__SHFT 6
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_HSIZE__BMSK 0x0000003F
+#define HWIO_RTDMA_JPEG_RD_BLOCK_SIZE__BLOCK_HSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_BUFFER_SIZE RTDMA_JPEG_RD_BUFFER_SIZE
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE_ADDR (JPEGD_BASE+0x00000124)
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__RMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__BUFFER_VSIZE__BMSK 0x00001FFF
+#define HWIO_RTDMA_JPEG_RD_BUFFER_SIZE__BUFFER_VSIZE__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_STA_ACK RTDMA_JPEG_RD_STA_ACK
+#define HWIO_RTDMA_JPEG_RD_STA_ACK_ADDR (JPEGD_BASE+0x00000128)
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__RMSK 0x00000003
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_STA__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_STA__SHFT 1
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_STA__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_STA__SHFT 0
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_ACK__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__EOF_ACK__SHFT 1
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_ACK__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_RD_STA_ACK__SOF_ACK__SHFT 0
+
+/* Register ADDR, RMSK, and SHFT*/
+#define RTDMA_JPEG_RD_INT_EN RTDMA_JPEG_RD_INT_EN
+#define HWIO_RTDMA_JPEG_RD_INT_EN_ADDR /* W */ (JPEGD_BASE+0x0000012C)
+#define HWIO_RTDMA_JPEG_RD_INT_EN__POR 0x00000000
+#define HWIO_RTDMA_JPEG_RD_INT_EN__RMSK 0x00000003
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SHFT 0
+
+/* Register Field FMSK and SHFT*/
+#define HWIO_RTDMA_JPEG_RD_INT_EN__EOF_EN__BMSK 0x00000002
+#define HWIO_RTDMA_JPEG_RD_INT_EN__EOF_EN__SHFT 1
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SOF_EN__BMSK 0x00000001
+#define HWIO_RTDMA_JPEG_RD_INT_EN__SOF_EN__SHFT 0
+
+#endif /* MSM_MERCURY_HW_REG_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_macros.h b/drivers/media/video/msm/mercury/msm_mercury_macros.h
new file mode 100644
index 0000000..33c4f9a
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_macros.h
@@ -0,0 +1,118 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MSM_MERCURY_MACROS_H
+#define MSM_MERCURY_MACROS_H
+
+#include <media/msm_mercury.h>
+
+#define mercury_kread(reg) \
+ hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_READ; \
+ hw_cmd.n = 1; \
+ hw_cmd.offset = HWIO_##reg##_ADDR; \
+ hw_cmd.mask = HWIO_##reg##__RMSK; \
+ hw_cmd.data = 0x0; \
+ msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+
+#define mercury_kwrite(reg, val) \
+ hw_cmd.offset = HWIO_##reg##_ADDR; \
+ hw_cmd.mask = HWIO_##reg##__RMSK; \
+ hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_WRITE; \
+ hw_cmd.n = 1; \
+ hw_cmd.data = val; \
+ msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+
+#define GET_FVAL(val, reg, field) ((val & HWIO_FMSK(reg, field)) >> \
+ HWIO_SHFT(reg, field))
+
+#define byte unsigned char
+#define word unsigned short
+#define dword unsigned long
+
+#define inp(port) (*((dword *) (port)))
+#define inpb(port) (*((byte *) (port)))
+#define inpw(port) (*((word *) (port)))
+#define inpdw(port) (*((dword *)(port)))
+
+#define outp(port, val) (*((dword *) (port)) = ((dword) (val)))
+#define outpb(port, val) (*((byte *) (port)) = ((byte) (val)))
+#define outpw(port, val) (*((word *) (port)) = ((word) (val)))
+#define outpdw(port, val) (*((dword *) (port)) = ((dword) (val)))
+
+
+#define in_byte(addr) (inp(addr))
+#define in_byte_masked(addr, mask) (inp(addr) & (byte)mask)
+#define out_byte(addr, val) outp(addr, val)
+#define in_word(addr) (inpw(addr))
+#define in_word_masked(addr, mask) (inpw(addr) & (word)mask)
+#define out_word(addr, val) outpw(addr, val)
+#define in_dword(addr) (inpdw(addr))
+#define in_dword_masked(addr, mask) (inpdw(addr) & mask)
+#define out_dword(addr, val) outpdw(addr, val)
+
+/* shadowed, masked output for write-only registers */
+#define out_byte_masked(io, mask, val, shadow) \
+ do { \
+ shadow = (shadow & (word)(~(mask))) | \
+ ((word)((val) & (mask))); \
+ (void) out_byte(io, shadow);\
+ } while (0);
+
+#define out_word_masked(io, mask, val, shadow) \
+ do { \
+ shadow = (shadow & (word)(~(mask))) | \
+ ((word)((val) & (mask))); \
+ (void) out_word(io, shadow); \
+ } while (0);
+
+#define out_dword_masked(io, mask, val, shadow) \
+ do { \
+ shadow = (shadow & (dword)(~(mask))) | \
+ ((dword)((val) & (mask))); \
+ (void) out_dword(io, shadow);\
+ } while (0);
+
+#define out_byte_masked_ns(io, mask, val, current_reg_content) \
+ (void) out_byte(io, ((current_reg_content & \
+ (word)(~(mask))) | ((word)((val) & (mask)))))
+
+#define out_word_masked_ns(io, mask, val, current_reg_content) \
+ (void) out_word(io, ((current_reg_content & \
+ (word)(~(mask))) | ((word)((val) & (mask)))))
+
+#define out_dword_masked_ns(io, mask, val, current_reg_content) \
+ (void) out_dword(io, ((current_reg_content & \
+ (dword)(~(mask))) | ((dword)((val) & (mask)))))
+
+#define MEM_INF(val, reg, field) ((val & HWIO_FMSK(reg, field)) >> \
+ HWIO_SHFT(reg, field))
+
+#define MEM_OUTF(mem, reg, field, val)\
+ out_dword_masked_ns(mem, HWIO_FMSK(reg, field), \
+ (unsigned int)val<<HWIO_SHFT(reg, field), in_dword(mem))
+
+#define MEM_OUTF2(mem, reg, field2, field1, val2, val1) \
+ out_dword_masked_ns(mem, (HWIO_FMSK(reg, field2)| \
+ HWIO_FMSK(reg, field1)), \
+ (((unsigned int)val2<<HWIO_SHFT(reg, field2))| \
+ ((unsigned int)val1<<HWIO_SHFT(reg, field1))), in_dword(mem))
+
+#define MEM_OUTF3(mem, reg, fld3, fld2, fld1, val3, val2, val1) \
+ out_dword_masked_ns(mem, (HWIO_FMSK(reg, fld3)| \
+ HWIO_FMSK(reg, fld2)|HWIO_FMSK(reg, fld1)), \
+ (((unsigned int)val3<<HWIO_SHFT(reg, fld3))| \
+ ((unsigned int)val2<<HWIO_SHFT(reg, fld2))| \
+ ((unsigned int)val1<<HWIO_SHFT(reg, fld1))), in_dword(mem))
+
+#define HWIO_FMSK(reg, field) HWIO_##reg##__##field##__BMSK
+#define HWIO_SHFT(reg, field) HWIO_##reg##__##field##__SHFT
+#endif
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.c b/drivers/media/video/msm/mercury/msm_mercury_platform.c
new file mode 100644
index 0000000..9366ef3
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/pm_qos_params.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/android_pmem.h>
+#include <mach/clk.h>
+#include <mach/camera.h>
+#include <mach/msm_subsystem_map.h>
+
+#include "msm_mercury_platform.h"
+#include "msm_mercury_sync.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_hw.h"
+
+
+struct ion_client *mercury_client;
+
+static struct msm_cam_clk_info mercury_jpegd_clk_info[] = {
+ {"core_clk", 200000000},
+ {"iface_clk", -1}
+};
+
+void msm_mercury_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle)
+{
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
+ GEN_POOL);
+ ion_free(mercury_client, *ionhandle);
+ *ionhandle = NULL;
+#elif CONFIG_ANDROID_PMEM
+ put_pmem_file(file);
+#endif
+}
+
+uint32_t msm_mercury_platform_v2p(int fd, uint32_t len,
+ struct file **file_p,
+ struct ion_handle **ionhandle)
+{
+ unsigned long paddr;
+ unsigned long size;
+ int rc;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ *ionhandle = ion_import_fd(mercury_client, fd);
+ if (IS_ERR_OR_NULL(*ionhandle))
+ return 0;
+
+ rc = ion_map_iommu(mercury_client, *ionhandle, CAMERA_DOMAIN,
+ GEN_POOL, SZ_4K, 0, &paddr,
+ (unsigned long *)&size, UNCACHED, 0);
+#elif CONFIG_ANDROID_PMEM
+ unsigned long kvstart;
+ rc = get_pmem_file(fd, &paddr, &kvstart, &size, file_p);
+#else
+ rc = 0;
+ paddr = 0;
+ size = 0;
+#endif
+ if (rc < 0) {
+ MCR_PR_ERR("%s: get_pmem_file fd %d error %d\n", __func__, fd,
+ rc);
+ goto error1;
+ }
+
+ /* validate user input */
+ if (len > size) {
+ MCR_PR_ERR("%s: invalid offset + len\n", __func__);
+ goto error1;
+ }
+
+ return paddr;
+error1:
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_free(mercury_client, *ionhandle);
+#endif
+ return 0;
+}
+
+int msm_mercury_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context)
+{
+ int rc = 0;
+ int mercury_irq;
+ struct resource *mercury_mem, *mercury_io, *mercury_irq_res;
+ void *mercury_base;
+ struct msm_mercury_device *pmercury_dev =
+ (struct msm_mercury_device *) context;
+
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+
+ mercury_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mercury_mem) {
+ MCR_PR_ERR("%s: no mem resource?\n", __func__);
+ return -ENODEV;
+ }
+
+ mercury_irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!mercury_irq_res) {
+ MCR_PR_ERR("no irq resource?\n");
+ return -ENODEV;
+ }
+ mercury_irq = mercury_irq_res->start;
+
+ mercury_io = request_mem_region(mercury_mem->start,
+ resource_size(mercury_mem), pdev->name);
+ if (!mercury_io) {
+ MCR_PR_ERR("%s: region already claimed\n", __func__);
+ return -EBUSY;
+ }
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ mercury_base = ioremap(mercury_mem->start,
+ resource_size(mercury_mem));
+ if (!mercury_base) {
+ rc = -ENOMEM;
+ MCR_PR_ERR("%s: ioremap failed\n", __func__);
+ goto fail1;
+ }
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+
+ rc = msm_cam_clk_enable(&pmercury_dev->pdev->dev,
+ mercury_jpegd_clk_info, pmercury_dev->mercury_clk,
+ ARRAY_SIZE(mercury_jpegd_clk_info), 1);
+ if (rc < 0)
+ MCR_PR_ERR("%s:%d] rc = %d\n", __func__, __LINE__, rc);
+
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ msm_mercury_hw_init(mercury_base, resource_size(mercury_mem));
+ rc = request_irq(mercury_irq, handler, IRQF_TRIGGER_RISING,
+ "mercury", context);
+ if (rc) {
+ MCR_PR_ERR("%s: request_irq failed, %d\n", __func__,
+ mercury_irq);
+ goto fail3;
+ }
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ *mem = mercury_mem;
+ *base = mercury_base;
+ *irq = mercury_irq;
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ mercury_client = msm_ion_client_create(-1, "camera/mercury");
+#endif
+ MCR_PR_ERR("%s:%d] success\n", __func__, __LINE__);
+ return rc;
+fail3:
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ msm_cam_clk_enable(&pmercury_dev->pdev->dev, mercury_jpegd_clk_info,
+ pmercury_dev->mercury_clk,
+ ARRAY_SIZE(mercury_jpegd_clk_info), 0);
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ iounmap(mercury_base);
+fail1:
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ release_mem_region(mercury_mem->start, resource_size(mercury_mem));
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ return rc;
+}
+
+int msm_mercury_platform_release(struct resource *mem, void *base,
+ int irq, void *context)
+{
+ int result = 0;
+ struct msm_mercury_device *pmercury_dev =
+ (struct msm_mercury_device *) context;
+
+ free_irq(irq, context);
+ msm_cam_clk_enable(&pmercury_dev->pdev->dev, mercury_jpegd_clk_info,
+ pmercury_dev->mercury_clk, ARRAY_SIZE(mercury_jpegd_clk_info),
+ 0);
+ iounmap(base);
+ release_mem_region(mem->start, resource_size(mem));
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_client_destroy(mercury_client);
+#endif
+ MCR_DBG("%s:%d] success\n", __func__, __LINE__);
+ return result;
+}
+
diff --git a/drivers/media/video/msm/mercury/msm_mercury_platform.h b/drivers/media/video/msm/mercury/msm_mercury_platform.h
new file mode 100644
index 0000000..8f4a7e3
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_platform.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MSM_MERCURY_PLATFORM_H
+#define MSM_MERCURY_PLATFORM_H
+
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/ion.h>
+
+int msm_mercury_platform_clk_enable(void);
+int msm_mercury_platform_clk_disable(void);
+
+void msm_mercury_platform_p2v(struct file *file,
+ struct ion_handle **ionhandle);
+
+uint32_t msm_mercury_platform_v2p(int fd, uint32_t len, struct file **file,
+ struct ion_handle **ionhandle);
+
+int msm_mercury_platform_init(struct platform_device *pdev,
+ struct resource **mem,
+ void **base,
+ int *irq,
+ irqreturn_t (*handler) (int, void *),
+ void *context);
+
+int msm_mercury_platform_release(struct resource *mem, void *base, int irq,
+ void *context);
+
+#endif /* MSM_MERCURY_PLATFORM_H */
diff --git a/drivers/media/video/msm/mercury/msm_mercury_sync.c b/drivers/media/video/msm/mercury/msm_mercury_sync.c
new file mode 100644
index 0000000..31fb8b4
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_sync.c
@@ -0,0 +1,614 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/sched.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <media/msm_mercury.h>
+
+#include "msm_mercury_sync.h"
+#include "msm_mercury_core.h"
+#include "msm_mercury_platform.h"
+#include "msm_mercury_common.h"
+#include "msm_mercury_macros.h"
+#include "msm_mercury_hw_reg.h"
+
+static struct msm_mercury_core_buf out_buf_local;
+static struct msm_mercury_core_buf in_buf_local;
+
+/*************** queue helper ****************/
+inline void msm_mercury_q_init(char const *name, struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, name);
+ q_p->name = name;
+ spin_lock_init(&q_p->lck);
+ INIT_LIST_HEAD(&q_p->q);
+ init_waitqueue_head(&q_p->wait);
+ q_p->unblck = 0;
+}
+
+inline void *msm_mercury_q_out(struct msm_mercury_q *q_p)
+{
+ unsigned long flags;
+ struct msm_mercury_q_entry *q_entry_p = NULL;
+ void *data = NULL;
+
+ MCR_DBG("(%d)%s() %s\n", __LINE__, __func__, q_p->name);
+ spin_lock_irqsave(&q_p->lck, flags);
+ if (!list_empty(&q_p->q)) {
+ q_entry_p = list_first_entry(&q_p->q,
+ struct msm_mercury_q_entry,
+ list);
+ list_del_init(&q_entry_p->list);
+ }
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ if (q_entry_p) {
+ data = q_entry_p->data;
+ kfree(q_entry_p);
+ } else {
+ MCR_DBG("%s:%d] %s no entry\n", __func__, __LINE__, q_p->name);
+ }
+
+ return data;
+}
+
+inline int msm_mercury_q_in(struct msm_mercury_q *q_p, void *data)
+{
+ unsigned long flags;
+
+ struct msm_mercury_q_entry *q_entry_p;
+
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+
+ q_entry_p = kmalloc(sizeof(struct msm_mercury_q_entry), GFP_ATOMIC);
+ if (!q_entry_p) {
+ MCR_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+ q_entry_p->data = data;
+
+ spin_lock_irqsave(&q_p->lck, flags);
+ list_add_tail(&q_entry_p->list, &q_p->q);
+ spin_unlock_irqrestore(&q_p->lck, flags);
+
+ return 0;
+}
+
+inline int msm_mercury_q_in_buf(struct msm_mercury_q *q_p,
+ struct msm_mercury_core_buf *buf)
+{
+ struct msm_mercury_core_buf *buf_p;
+
+ MCR_DBG("%s:%d]\n", __func__, __LINE__);
+ buf_p = kmalloc(sizeof(struct msm_mercury_core_buf), GFP_ATOMIC);
+ if (!buf_p) {
+ MCR_PR_ERR("%s: no mem\n", __func__);
+ return -EFAULT;
+ }
+
+ memcpy(buf_p, buf, sizeof(struct msm_mercury_core_buf));
+
+ msm_mercury_q_in(q_p, buf_p);
+ return 0;
+}
+
+inline int msm_mercury_q_wait(struct msm_mercury_q *q_p)
+{
+ int tm = MAX_SCHEDULE_TIMEOUT; /* 500ms */
+ int rc;
+
+ MCR_DBG("%s:%d %s wait\n", __func__, __LINE__, q_p->name);
+ rc = wait_event_interruptible_timeout(q_p->wait,
+ (!list_empty_careful(&q_p->q) || q_p->unblck),
+ msecs_to_jiffies(tm));
+
+ MCR_DBG("%s:%d %s wait done (rc=%d)\n", __func__,
+ __LINE__, q_p->name, rc);
+ if (list_empty_careful(&q_p->q)) {
+ if (rc == 0) {
+ rc = -ETIMEDOUT;
+ MCR_PR_ERR("%s:%d] %s timeout\n", __func__,
+ __LINE__, q_p->name);
+ } else if (q_p->unblck) {
+ MCR_DBG("%s:%d %s unblock is true", __func__,
+ __LINE__, q_p->name);
+ rc = q_p->unblck;
+ q_p->unblck = 0;
+ } else if (rc < 0) {
+ MCR_PR_ERR("%s:%d %s rc %d\n", __func__, __LINE__,
+ q_p->name, rc);
+ }
+ }
+ return rc;
+}
+
+inline int msm_mercury_q_wakeup(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_mercury_q_wr_eoi(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = MSM_MERCURY_EVT_FRAMEDONE;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_mercury_q_wr_err(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = MSM_MERCURY_EVT_ERR;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline int msm_mercury_q_unblock(struct msm_mercury_q *q_p)
+{
+ MCR_DBG("%s:%d] Wake up %s\n", __func__, __LINE__, q_p->name);
+ q_p->unblck = MSM_MERCURY_EVT_UNBLOCK;
+ wake_up(&q_p->wait);
+ return 0;
+}
+
+inline void msm_mercury_q_cleanup(struct msm_mercury_q *q_p)
+{
+ void *data;
+ MCR_DBG("\n%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ do {
+ data = msm_mercury_q_out(q_p);
+ if (data) {
+ MCR_DBG("%s:%d] %s\n", __func__, __LINE__, q_p->name);
+ kfree(data);
+ }
+ } while (data);
+ q_p->unblck = 0;
+}
+
+/*************** event queue ****************/
+int msm_mercury_framedone_irq(struct msm_mercury_device *pmercury_dev)
+{
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_mercury_q_unblock(&pmercury_dev->evt_q);
+
+ MCR_DBG("%s:%d] Exit\n", __func__, __LINE__);
+ return 0;
+}
+
+int msm_mercury_evt_get(struct msm_mercury_device *pmercury_dev,
+ void __user *arg)
+{
+ struct msm_mercury_ctrl_cmd ctrl_cmd;
+ int rc = 0;
+
+ MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+ ctrl_cmd.type = (uint32_t)msm_mercury_q_wait(&pmercury_dev->evt_q);
+
+ rc = copy_to_user(arg, &ctrl_cmd, sizeof(ctrl_cmd));
+
+ if (rc) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_mercury_evt_get_unblock(struct msm_mercury_device *pmercury_dev)
+{
+ MCR_DBG("--(%d)%s() Enter\n", __LINE__, __func__);
+ msm_mercury_q_unblock(&pmercury_dev->evt_q);
+ return 0;
+}
+
+int msm_mercury_output_buf_cfg(struct msm_mercury_device *pmercury_dev,
+ void __user *arg)
+{
+ struct msm_mercury_buf buf_cmd;
+
+
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_mercury_buf))) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ out_buf_local.y_buffer_addr = msm_mercury_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len, &out_buf_local.file, &out_buf_local.handle);
+ out_buf_local.cbcr_buffer_addr = out_buf_local.y_buffer_addr +
+ buf_cmd.y_len;
+
+ if (!out_buf_local.y_buffer_addr) {
+ MCR_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ msm_mercury_hw_output_y_buf_cfg(out_buf_local.y_buffer_addr);
+ msm_mercury_hw_output_u_buf_cfg(out_buf_local.cbcr_buffer_addr);
+
+ MCR_DBG("(%d)%s()\n y_buf=0x%08X, y_len=0x%08X, vaddr=0x%08X\n"
+ " u_buf=0x%08X, u_len=0x%08X\n\n", __LINE__, __func__,
+ out_buf_local.y_buffer_addr, buf_cmd.y_len, (int) buf_cmd.vaddr,
+ out_buf_local.cbcr_buffer_addr, buf_cmd.cbcr_len);
+
+ return 0;
+}
+
+int msm_mercury_input_buf_cfg(struct msm_mercury_device *pmercury_dev,
+ void __user *arg)
+{
+ struct msm_mercury_buf buf_cmd;
+
+
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ if (copy_from_user(&buf_cmd, arg, sizeof(struct msm_mercury_buf))) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ in_buf_local.y_buffer_addr = msm_mercury_platform_v2p(buf_cmd.fd,
+ buf_cmd.y_len, &in_buf_local.file, &in_buf_local.handle);
+
+ if (!in_buf_local.y_buffer_addr) {
+ MCR_PR_ERR("%s:%d] v2p wrong\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ msm_mercury_hw_bitstream_buf_cfg(in_buf_local.y_buffer_addr);
+
+ MCR_DBG("(%d)%s()\n bitstream_buf=0x%08X, len=0x%08X, vaddr=0x%08X\n",
+ __LINE__, __func__, in_buf_local.y_buffer_addr, buf_cmd.y_len,
+ (int) buf_cmd.vaddr);
+
+ return 0;
+}
+
+int msm_mercury_output_get(struct msm_mercury_device *pmercury_dev,
+ void __user *to)
+{
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_mercury_platform_p2v(out_buf_local.file, &out_buf_local.handle);
+ return 0;
+}
+
+int msm_mercury_input_get(struct msm_mercury_device *pmercury_dev,
+ void __user *to)
+{
+
+
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ msm_mercury_platform_p2v(in_buf_local.file, &in_buf_local.handle);
+ return 0;
+}
+
+int msm_mercury_ioctl_dump_regs(void)
+{
+ uint32_t mercury_regs[] = {
+ 0x0000, 0x0008, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024,
+ 0x0030, 0x0034, 0x0040, 0x0050, 0x0054, 0x0058, 0x005C, 0x0060,
+ 0x0064, 0x0070, 0x0080, 0x0084, 0x0088, 0x0258, 0x025C, 0x0260,
+ 0x0264, 0x0200, 0x0204, 0x0208, 0x020C, 0x0210, 0x0214, 0x0218,
+ 0x021C, 0x0220, 0x0224, 0x0228, 0x0100, 0x0104, 0x010C, 0x0110,
+ 0x0114, 0x0118, 0x011C, 0x0120, 0x0124, 0x0128, 0x012C};
+
+ struct msm_mercury_hw_cmd hw_cmd;
+ int len = sizeof(mercury_regs)/4;
+ int i;
+
+ MCR_DBG("\n%s\n (%d)%s()\n", __FILE__, __LINE__, __func__);
+
+ hw_cmd.mask = 0xFFFFFFFF;
+ hw_cmd.type = MSM_MERCURY_HW_CMD_TYPE_READ;
+ hw_cmd.n = 1;
+
+ for (i = 0; i < len; i++) {
+ hw_cmd.offset = mercury_regs[i];
+ msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+ }
+
+ return 0;
+}
+
+int msm_mercury_ioctl_magic_code(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ int rc = 0;
+
+ rc = copy_from_user(&hw_cmd, arg, sizeof(struct msm_mercury_hw_cmd));
+ if (rc) {
+ printk(KERN_ERR "%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ hw_cmd.data = 0x600D600D;
+ rc = copy_to_user(arg, &hw_cmd, sizeof(hw_cmd));
+
+ if (rc) {
+ printk(KERN_ERR "%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+int msm_mercury_irq(int event, void *context, void *data)
+{
+ struct msm_mercury_device *pmercury_dev =
+ (struct msm_mercury_device *) context;
+
+ switch (event) {
+ case MSM_MERCURY_HW_IRQ_SW_RESET_ACK:
+ /* wake up evt_q*/
+ MCR_DBG("(%d)%s Wake up event q from Reset IRQ\n", __LINE__,
+ __func__);
+ msm_mercury_q_wakeup(&pmercury_dev->evt_q);
+ break;
+ case MSM_MERCURY_HW_IRQ_WR_EOI_ACK:
+ /*wake up evt_q*/
+ MCR_DBG("%d%s Wake up eventq from WR_EOI IRQ\n", __LINE__,
+ __func__);
+ msm_mercury_q_wr_eoi(&pmercury_dev->evt_q);
+ break;
+ case MSM_MERCURY_HW_IRQ_WR_ERR_ACK:
+ MCR_DBG("(%d)%s Wake up eventq from WR_ERR IRQ\n",
+ __LINE__, __func__);
+ msm_mercury_q_wr_err(&pmercury_dev->evt_q);
+ break;
+ default:
+ MCR_DBG("(%d)%s (default) Wake up event q from WR_ERR IRQ\n",
+ __LINE__, __func__);
+ msm_mercury_q_wr_err(&pmercury_dev->evt_q);
+ }
+ return 0;
+}
+
+int __msm_mercury_open(struct msm_mercury_device *pmercury_dev)
+{
+ int rc = 0;
+
+ mutex_lock(&pmercury_dev->lock);
+ if (pmercury_dev->open_count) {
+ /* only open once */
+ MCR_PR_ERR("%s:%d] busy\n", __func__, __LINE__);
+ mutex_unlock(&pmercury_dev->lock);
+ return -EBUSY;
+ }
+ pmercury_dev->open_count++;
+ mutex_unlock(&pmercury_dev->lock);
+
+ msm_mercury_core_irq_install(msm_mercury_irq);
+
+ rc = msm_mercury_platform_init(pmercury_dev->pdev,
+ &pmercury_dev->mem, &pmercury_dev->base,
+ &pmercury_dev->irq, msm_mercury_core_irq, pmercury_dev);
+ if (rc) {
+ MCR_PR_ERR("%s:%d] platform_init fail %d\n", __func__,
+ __LINE__, rc);
+ return rc;
+ }
+
+ MCR_DBG("\n%s:%d] platform resources - mem 0x%p, base 0x%p, irq %d\n",
+ __func__, __LINE__, pmercury_dev->mem, pmercury_dev->base,
+ pmercury_dev->irq);
+
+ msm_mercury_q_cleanup(&pmercury_dev->evt_q);
+ msm_mercury_core_init();
+
+ MCR_DBG("\n%s:%d] success\n", __func__, __LINE__);
+ return rc;
+}
+
+int __msm_mercury_release(struct msm_mercury_device *pmercury_dev)
+{
+ MCR_DBG("%s:%d] Enter\n", __func__, __LINE__);
+ mutex_lock(&pmercury_dev->lock);
+ if (!pmercury_dev->open_count) {
+ MCR_PR_ERR(KERN_ERR "%s: not opened\n", __func__);
+ mutex_unlock(&pmercury_dev->lock);
+ return -EINVAL;
+ }
+ pmercury_dev->open_count--;
+ mutex_unlock(&pmercury_dev->lock);
+
+ msm_mercury_q_cleanup(&pmercury_dev->evt_q);
+
+ if (pmercury_dev->open_count)
+ MCR_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+ if (pmercury_dev->open_count)
+ MCR_PR_ERR(KERN_ERR "%s: multiple opens\n", __func__);
+
+
+ msm_mercury_platform_release(pmercury_dev->mem, pmercury_dev->base,
+ pmercury_dev->irq, pmercury_dev);
+
+ return 0;
+}
+
+int msm_mercury_ioctl_hw_cmd(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ struct msm_mercury_hw_cmd hw_cmd;
+ int is_copy_to_user;
+ int rc = 0;
+
+ rc = copy_from_user(&hw_cmd, arg, sizeof(struct msm_mercury_hw_cmd));
+ if (rc) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ is_copy_to_user = msm_mercury_hw_exec_cmds(&hw_cmd, 1);
+ if (is_copy_to_user >= 0) {
+ rc = copy_to_user(arg, &hw_cmd, sizeof(hw_cmd));
+
+ if (rc) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ int is_copy_to_user;
+ int len;
+ uint32_t m;
+ struct msm_mercury_hw_cmds *hw_cmds_p;
+ struct msm_mercury_hw_cmd *hw_cmd_p;
+
+ if (copy_from_user(&m, arg, sizeof(m))) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ return -EFAULT;
+ }
+
+ len = sizeof(struct msm_mercury_hw_cmds) +
+ sizeof(struct msm_mercury_hw_cmd) * (m - 1);
+ hw_cmds_p = kmalloc(len, GFP_KERNEL);
+ if (!hw_cmds_p) {
+ MCR_PR_ERR("[%d]%s() no mem %d\n", __LINE__, __func__, len);
+ return -EFAULT;
+ }
+
+ if (copy_from_user(hw_cmds_p, arg, len)) {
+ MCR_PR_ERR("[%d]%s Fail to copy hw_cmds of len %d from user\n",
+ __LINE__, __func__, len);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+
+ hw_cmd_p = (struct msm_mercury_hw_cmd *) &(hw_cmds_p->hw_cmd);
+
+ is_copy_to_user = msm_mercury_hw_exec_cmds(hw_cmd_p, m);
+
+ if (is_copy_to_user >= 0) {
+ if (copy_to_user(arg, hw_cmds_p, len)) {
+ MCR_PR_ERR("%s:%d] failed\n", __func__, __LINE__);
+ kfree(hw_cmds_p);
+ return -EFAULT;
+ }
+ }
+ kfree(hw_cmds_p);
+ return 0;
+}
+
+int msm_mercury_ioctl_reset(struct msm_mercury_device *pmercury_dev,
+ void * __user arg)
+{
+ int rc = 0;
+
+ MCR_DBG("(%d)%s() Enter\n", __LINE__, __func__);
+ rc = msm_mercury_core_reset();
+
+ return rc;
+}
+
+long __msm_mercury_ioctl(struct msm_mercury_device *pmercury_dev,
+ unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+
+ switch (cmd) {
+ case MSM_MCR_IOCTL_GET_HW_VERSION:
+ rc = msm_mercury_ioctl_magic_code(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_RESET:
+ rc = msm_mercury_ioctl_reset(pmercury_dev, (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_EVT_GET:
+ rc = msm_mercury_evt_get(pmercury_dev, (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_EVT_GET_UNBLOCK:
+ rc = msm_mercury_evt_get_unblock(pmercury_dev);
+ break;
+
+ case MSM_MCR_IOCTL_HW_CMD:
+ rc = msm_mercury_ioctl_hw_cmd(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_HW_CMDS:
+ rc = msm_mercury_ioctl_hw_cmds(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_INPUT_BUF_CFG:
+ rc = msm_mercury_input_buf_cfg(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_OUTPUT_BUF_CFG:
+ rc = msm_mercury_output_buf_cfg(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_OUTPUT_GET:
+ rc = msm_mercury_output_get(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_INPUT_GET:
+ rc = msm_mercury_input_get(pmercury_dev,
+ (void __user *) arg);
+ break;
+
+ case MSM_MCR_IOCTL_TEST_DUMP_REGION:
+ rc = msm_mercury_ioctl_dump_regs();
+ break;
+
+ default:
+ printk(KERN_ERR "(%d)%s() cmd = %d not supported\n",
+ __LINE__, __func__, _IOC_NR(cmd));
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+struct msm_mercury_device *__msm_mercury_init(struct platform_device *pdev)
+{
+ struct msm_mercury_device *pmercury_dev;
+ pmercury_dev = kzalloc(sizeof(struct msm_mercury_device), GFP_ATOMIC);
+ if (!pmercury_dev) {
+ printk(KERN_ERR "%s:%d]no mem\n", __func__, __LINE__);
+ return NULL;
+ }
+
+ mutex_init(&pmercury_dev->lock);
+
+ pmercury_dev->pdev = pdev;
+
+ msm_mercury_q_init("evt_q", &pmercury_dev->evt_q);
+
+ return pmercury_dev;
+}
+
+int __msm_mercury_exit(struct msm_mercury_device *pmercury_dev)
+{
+ mutex_destroy(&pmercury_dev->lock);
+ kfree(pmercury_dev);
+ return 0;
+}
+
diff --git a/drivers/media/video/msm/mercury/msm_mercury_sync.h b/drivers/media/video/msm/mercury/msm_mercury_sync.h
new file mode 100644
index 0000000..f392907
--- /dev/null
+++ b/drivers/media/video/msm/mercury/msm_mercury_sync.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MSM_MERCURY_SYNC_H
+#define MSM_MERCURY_SYNC_H
+
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/cdev.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm_mercury_core.h"
+
+struct msm_mercury_q {
+ char const *name;
+ struct list_head q;
+ spinlock_t lck;
+ wait_queue_head_t wait;
+ int unblck;
+};
+
+struct msm_mercury_q_entry {
+ struct list_head list;
+ void *data;
+};
+
+struct msm_mercury_device {
+ struct platform_device *pdev;
+ struct resource *mem;
+ int irq;
+ void *base;
+ struct clk *mercury_clk[2];
+ struct device *device;
+ struct cdev cdev;
+ struct mutex lock;
+ char open_count;
+ uint8_t op_mode;
+
+ /* event queue including frame done & err indications*/
+ struct msm_mercury_q evt_q;
+ struct v4l2_subdev subdev;
+
+};
+
+int __msm_mercury_open(struct msm_mercury_device *pmcry_dev);
+int __msm_mercury_release(struct msm_mercury_device *pmcry_dev);
+
+long __msm_mercury_ioctl(struct msm_mercury_device *pmcry_dev,
+ unsigned int cmd, unsigned long arg);
+
+struct msm_mercury_device *__msm_mercury_init(struct platform_device *pdev);
+int __msm_mercury_exit(struct msm_mercury_device *pmcry_dev);
+int msm_mercury_ioctl_hw_cmds(struct msm_mercury_device *pmcry_dev,
+ void * __user arg);
+int msm_mercury_ioctl_hw_cmds_wo(struct msm_mercury_device *pmcry_dev,
+ void * __user arg);
+#endif /* MSM_MERCURY_SYNC_H */
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 09511b1..d34b8e1 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -108,6 +108,25 @@
return rc;
}
+static int msm_camera_v4l2_private_s_ctrl(struct file *f, void *pctx,
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr)
+{
+ int rc = -EINVAL;
+ struct msm_cam_v4l2_device *pcam = video_drvdata(f);
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ pcam_inst = container_of(f->private_data,
+ struct msm_cam_v4l2_dev_inst, eventHandle);
+ WARN_ON(pctx != f->private_data);
+ mutex_lock(&pcam->vid_lock);
+ switch (ioctl_ptr->id) {
+ case MSM_V4L2_PID_CTRL_CMD:
+ rc = msm_server_proc_ctrl_cmd(pcam, ioctl_ptr, 1);
+ break;
+ }
+ mutex_unlock(&pcam->vid_lock);
+ return rc;
+}
+
static int msm_camera_v4l2_s_ctrl(struct file *f, void *pctx,
struct v4l2_control *ctrl)
{
@@ -127,17 +146,6 @@
__func__, pcam_inst, pcam_inst->my_index);
pcam_inst->is_mem_map_inst = 1;
break;
- case MSM_V4L2_PID_MMAP_ENTRY:
- if (copy_from_user(&pcam_inst->mem_map,
- (void *)ctrl->value,
- sizeof(struct msm_mem_map_info))) {
- rc = -EFAULT;
- } else
- D("%s:mmap entry:cookie=0x%x,mem_type=%d,len=%d\n",
- __func__, pcam_inst->mem_map.cookie,
- pcam_inst->mem_map.mem_type,
- pcam_inst->mem_map.length);
- break;
default:
if (ctrl->id == MSM_V4L2_PID_CAM_MODE)
pcam->op_mode = ctrl->value;
@@ -685,6 +693,22 @@
return rc;
}
+static long msm_camera_v4l2_private_ioctl(struct file *file, void *fh,
+ bool valid_prio, int cmd,
+ void *arg)
+{
+ int rc = -EINVAL;
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;
+ D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
+
+ switch (cmd) {
+ case MSM_CAM_V4L2_IOCTL_PRIVATE_S_CTRL:
+ rc = msm_camera_v4l2_private_s_ctrl(file, fh, ioctl_ptr);
+ break;
+ }
+ return rc;
+}
+
/* v4l2_ioctl_ops */
static const struct v4l2_ioctl_ops g_msm_ioctl_ops = {
.vidioc_querycap = msm_camera_v4l2_querycap,
@@ -724,6 +748,7 @@
/* event subscribe/unsubscribe */
.vidioc_subscribe_event = msm_camera_v4l2_subscribe_event,
.vidioc_unsubscribe_event = msm_camera_v4l2_unsubscribe_event,
+ .vidioc_default = msm_camera_v4l2_private_ioctl,
};
/* v4l2_file_operations */
@@ -1252,6 +1277,7 @@
struct msm_camera_sensor_info *sdata;
struct msm_cam_v4l2_device *pcam;
struct msm_sensor_ctrl_t *s_ctrl;
+ struct msm_cam_subdev_info sd_info;
D("%s for %s\n", __func__, sensor_sd->name);
@@ -1296,8 +1322,11 @@
}
msm_server_update_sensor_info(pcam, sdata);
+ sd_info.sdev_type = SENSOR_DEV;
+ sd_info.sd_index = vnode_count;
+ sd_info.irq_num = 0;
/* register the subdevice, must be done for callbacks */
- rc = msm_cam_register_subdev_node(sensor_sd, SENSOR_DEV, vnode_count);
+ rc = msm_cam_register_subdev_node(sensor_sd, &sd_info);
if (rc < 0) {
D("%s sensor sub device register failed\n",
__func__);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 8500d47..d0322d1 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -20,6 +20,7 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <linux/pm_qos.h>
+#include <linux/wakelock.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
@@ -32,16 +33,22 @@
#include <mach/camera.h>
#include <media/msm_isp.h>
#include <linux/ion.h>
+#include <linux/iommu.h>
#include <media/msm_gestures.h>
#define MSM_V4L2_DIMENSION_SIZE 96
#define MAX_DEV_NAME_LEN 50
-#define ERR_USER_COPY(to) pr_debug("%s(%d): copy %s user\n", \
+#define ERR_USER_COPY(to) pr_err("%s(%d): copy %s user\n", \
__func__, __LINE__, ((to) ? "to" : "from"))
#define ERR_COPY_FROM_USER() ERR_USER_COPY(0)
#define ERR_COPY_TO_USER() ERR_USER_COPY(1)
+#define COPY_FROM_USER(error, dest, src, size) \
+ (error = (copy_from_user(dest, src, size) ? -EFAULT : 0))
+#define COPY_TO_USER(error, dest, src, size) \
+ (error = (copy_to_user(dest, src, size) ? -EFAULT : 0))
+
#define MSM_CSIPHY_DRV_NAME "msm_csiphy"
#define MSM_CSID_DRV_NAME "msm_csid"
#define MSM_CSIC_DRV_NAME "msm_csic"
@@ -49,15 +56,18 @@
#define MSM_VFE_DRV_NAME "msm_vfe"
#define MSM_VPE_DRV_NAME "msm_vpe"
#define MSM_GEMINI_DRV_NAME "msm_gemini"
+#define MSM_MERCURY_DRV_NAME "msm_mercury"
#define MSM_I2C_MUX_DRV_NAME "msm_cam_i2c_mux"
+#define MSM_IRQ_ROUTER_DRV_NAME "msm_cam_irq_router"
#define MAX_NUM_CSIPHY_DEV 3
-#define MAX_NUM_CSID_DEV 3
+#define MAX_NUM_CSID_DEV 4
#define MAX_NUM_CSIC_DEV 3
#define MAX_NUM_ISPIF_DEV 1
#define MAX_NUM_VFE_DEV 2
#define MAX_NUM_AXI_DEV 2
#define MAX_NUM_VPE_DEV 1
+#define MAX_NUM_JPEG_DEV 3
enum msm_cam_subdev_type {
CSIPHY_DEV,
@@ -71,6 +81,7 @@
ACTUATOR_DEV,
EEPROM_DEV,
GESTURE_DEV,
+ IRQ_ROUTER_DEV,
};
/* msm queue management APIs*/
@@ -99,6 +110,7 @@
qcmd = list_first_entry(&__q->list, \
struct msm_queue_cmd, member); \
list_del_init(&qcmd->member); \
+ kfree(qcmd->command); \
free_qcmd(qcmd); \
}; \
spin_unlock_irqrestore(&__q->lock, flags); \
@@ -120,6 +132,7 @@
struct msm_free_buf {
uint8_t num_planes;
+ int32_t image_mode;
uint32_t ch_paddr[VIDEO_MAX_PLANES];
uint32_t vb;
};
@@ -137,14 +150,11 @@
/* message id for v4l2_subdev_notify*/
enum msm_camera_v4l2_subdev_notify {
- NOTIFY_CID_CHANGE, /* arg = msm_camera_csid_params */
NOTIFY_ISP_MSG_EVT, /* arg = enum ISP_MESSAGE_ID */
NOTIFY_VFE_MSG_OUT, /* arg = struct isp_msg_output */
NOTIFY_VFE_MSG_STATS, /* arg = struct isp_msg_stats */
NOTIFY_VFE_MSG_COMP_STATS, /* arg = struct msm_stats_buf */
NOTIFY_VFE_BUF_EVT, /* arg = struct msm_vfe_resp */
- NOTIFY_ISPIF_STREAM, /* arg = enable parameter for s_stream */
- NOTIFY_VPE_MSG_EVT,
NOTIFY_PCLK_CHANGE, /* arg = pclk */
NOTIFY_CSIPHY_CFG, /* arg = msm_camera_csiphy_params */
NOTIFY_CSID_CFG, /* arg = msm_camera_csid_params */
@@ -203,6 +213,7 @@
struct msm_pp_frame src_frame;
struct msm_pp_frame dest_frame;
struct msm_mctl_pp_frame_cmd pp_frame_cmd;
+ struct msm_cam_media_controller *p_mctl;
};
struct msm_mctl_pp_ctrl {
@@ -258,7 +269,7 @@
uint8_t opencnt; /*mctl ref count*/
const char *apps_id; /*ID for app that open this session*/
struct mutex lock;
- struct pm_qos_request idle_pm_qos; /*avoid low power mode when active*/
+ struct wake_lock wake_lock; /*avoid low power mode when active*/
struct pm_qos_request pm_qos_req_list;
struct msm_mctl_pp_info pp_info;
struct msm_mctl_stats_t stats_info; /*stats pmem info*/
@@ -271,6 +282,12 @@
/*sensor info*/
struct msm_camera_sensor_info *sdata;
+
+ /*IOMMU mapped IMEM addresses*/
+ uint32_t ping_imem_y;
+ uint32_t ping_imem_cbcr;
+ uint32_t pong_imem_y;
+ uint32_t pong_imem_cbcr;
};
/* abstract camera device represents a VFE and connected sensor */
@@ -284,7 +301,8 @@
unsigned int cmd, unsigned long arg);
int (*isp_notify)(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
- void (*isp_release)(struct v4l2_subdev *sd);
+ void (*isp_release)(struct msm_cam_media_controller *mctl,
+ struct v4l2_subdev *sd);
int (*isp_pp_cmd)(struct msm_cam_media_controller *pmctl,
struct msm_mctl_pp_cmd, void *data);
@@ -390,6 +408,15 @@
struct msm_mem_map_info mem_map;
};
+struct msm_cam_subdev_info {
+ uint8_t sdev_type;
+ /* Subdev index. For eg: CSIPHY0, CSIPHY1 etc */
+ uint8_t sd_index;
+ /* This device/subdev's interrupt number, assigned
+ * from the hardware document. */
+ uint8_t irq_num;
+};
+
/* 2 for camera, 1 for gesture */
#define MAX_NUM_ACTIVE_CAMERA 3
@@ -406,6 +433,68 @@
uint32_t handle;
};
+struct msm_cam_server_irqmap_entry {
+ int irq_num;
+ int irq_idx;
+ uint8_t cam_hw_idx;
+ uint8_t is_composite;
+};
+
+struct intr_table_entry {
+ /* irq_num as understood by msm.
+ * Unique for every camera hw core & target. Use a mapping function
+ * to map this irq number to its equivalent index in camera side. */
+ int irq_num;
+ /* Camera hw core idx, in case of non-composite IRQs*/
+ uint8_t cam_hw_idx;
+ /* Camera hw core mask, in case of composite IRQs. */
+ uint32_t cam_hw_mask;
+ /* Each interrupt is mapped to an index, which is used
+ * to add/delete entries into the lookup table. Both the information
+ * are needed in the lookup table to avoid another subdev call into
+ * the IRQ Router subdev to get the irq_idx in the interrupt context */
+ int irq_idx;
+ /* Is this irq composite? */
+ uint8_t is_composite;
+ /* IRQ Trigger type: TRIGGER_RAISING, TRIGGER_HIGH, etc. */
+ uint32_t irq_trigger_type;
+ /* If IRQ Router hw is present,
+ * this field holds the number of camera hw core
+ * which are bundled together in the above
+ * interrupt. > 1 in case of composite irqs.
+ * If IRQ Router hw is not present, this field should be set to 1. */
+ int num_hwcore;
+ /* Pointers to the subdevs composited in this
+ * irq. If not composite, the 0th index stores the subdev to which
+ * this irq needs to be dispatched to. */
+ struct v4l2_subdev *subdev_list[CAMERA_SS_IRQ_MAX];
+ /* Device requesting the irq. */
+ const char *dev_name;
+ /* subdev private data, if any */
+ void *data;
+};
+
+struct irqmgr_intr_lkup_table {
+ /* Individual(hw) interrupt lookup table:
+ * This table is populated during initialization and doesnt
+ * change, unless the IRQ Router has been configured
+ * for composite IRQs. If the IRQ Router has been configured
+ * for composite IRQs, the is_composite field of that IRQ will
+ * be set to 1(default 0). And when there is an interrupt on
+ * that line, the composite interrupt lookup table is used
+ * for handling the interrupt. */
+ struct intr_table_entry ind_intr_tbl[CAMERA_SS_IRQ_MAX];
+
+ /* Composite interrupt lookup table:
+ * This table can be dynamically modified based on the usecase.
+ * If the usecase requires two or more HW core IRQs to be bundled
+ * into a single composite IRQ, then this table is populated
+ * accordingly. Also when this is done, the composite field
+ * in the intr_lookup_table has to be updated to reflect that
+ * the irq 'irq_num' will now be triggered in composite mode. */
+ struct intr_table_entry comp_intr_tbl[CAMERA_SS_IRQ_MAX];
+};
+
/* abstract camera server device for all sensor successfully probed*/
struct msm_cam_server_dev {
@@ -451,9 +540,18 @@
struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];
struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];
struct v4l2_subdev *gesture_device;
-};
+ struct v4l2_subdev *irqr_device;
-/* camera server related functions */
+ spinlock_t intr_table_lock;
+ struct irqmgr_intr_lkup_table irq_lkup_table;
+ /* Stores the pointer to the subdev when the individual
+ * subdevices register themselves with the server. This
+ * will be used while dispatching composite irqs. The
+ * cam_hw_idx will serve as the index into this array to
+ * dispatch the irq to the corresponding subdev. */
+ struct v4l2_subdev *subdev_table[MSM_CAM_HW_MAX];
+ struct msm_cam_server_irqmap_entry hw_irqmap[CAMERA_SS_IRQ_MAX];
+};
/* ISP related functions */
void msm_isp_vfe_dev_init(struct v4l2_subdev *vd);
@@ -568,7 +666,7 @@
void __user *arg);
void msm_release_ion_client(struct kref *ref);
int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
- enum msm_cam_subdev_type sdev_type, uint8_t index);
+ struct msm_cam_subdev_info *sd_info);
int msm_server_open_client(int *p_qidx);
int msm_server_send_ctrl(struct msm_ctrl_cmd *out, int ctrl_id);
int msm_server_close_client(int idx);
@@ -577,6 +675,10 @@
int msm_cam_server_close_mctl_session(struct msm_cam_v4l2_device *pcam);
long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
unsigned int cmd, unsigned long evt);
+int msm_mctl_pp_get_vpe_buf_info(struct msm_mctl_pp_frame_info *zoom);
+void msm_queue_init(struct msm_device_queue *queue, const char *name);
+void msm_enqueue(struct msm_device_queue *queue, struct list_head *entry);
+void msm_drain_eventq(struct msm_device_queue *queue);
#endif /* __KERNEL__ */
#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
index ec1e253..9f32bfe 100644
--- a/drivers/media/video/msm/msm_camera.c
+++ b/drivers/media/video/msm/msm_camera.c
@@ -3747,7 +3747,7 @@
if (!sync->core_powered_on && !is_controlnode) {
pm_qos_update_request(&sync->idle_pm_qos,
- msm_cpuidle_get_deep_idle_latency());
+ msm_cpuidle_get_deep_idle_latency());
msm_camvfe_fn_init(&sync->vfefn, sync);
if (sync->vfefn.vfe_init) {
@@ -3962,7 +3962,7 @@
msm_queue_init(&sync->vpe_q, "vpe");
pm_qos_add_request(&sync->idle_pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ PM_QOS_DEFAULT_VALUE);
rc = msm_camio_probe_on(pdev);
if (rc < 0) {
diff --git a/drivers/media/video/msm/msm_camirq_router.c b/drivers/media/video/msm/msm_camirq_router.c
new file mode 100644
index 0000000..52dd175
--- /dev/null
+++ b/drivers/media/video/msm/msm_camirq_router.c
@@ -0,0 +1,266 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/interrupt.h>
+#include <mach/irqs.h>
+#include <media/msm_isp.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include "msm.h"
+#include "server/msm_cam_server.h"
+#include "msm_camirq_router.h"
+
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
+static void msm_irqrouter_update_irqmap_entry(
+ struct msm_cam_server_irqmap_entry *entry,
+ int is_composite, int irq_idx, int cam_hw_idx)
+{
+ int rc = 0;
+ entry->irq_idx = irq_idx;
+ entry->is_composite = is_composite;
+ entry->cam_hw_idx = cam_hw_idx;
+ rc = msm_cam_server_update_irqmap(entry);
+ if (rc < 0)
+ pr_err("%s Error updating irq %d information ",
+ __func__, irq_idx);
+}
+
+static void msm_irqrouter_send_default_irqmap(
+ struct irqrouter_ctrl_type *irqrouter_ctrl)
+{
+ struct msm_cam_server_irqmap_entry *irqmap =
+ &irqrouter_ctrl->def_hw_irqmap[0];
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_0],
+ 0, CAMERA_SS_IRQ_0, MSM_CAM_HW_MICRO);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_1],
+ 0, CAMERA_SS_IRQ_1, MSM_CAM_HW_CCI);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_2],
+ 0, CAMERA_SS_IRQ_2, MSM_CAM_HW_CSI0);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_3],
+ 0, CAMERA_SS_IRQ_3, MSM_CAM_HW_CSI1);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_4],
+ 0, CAMERA_SS_IRQ_4, MSM_CAM_HW_CSI2);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_5],
+ 0, CAMERA_SS_IRQ_5, MSM_CAM_HW_CSI3);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_6],
+ 0, CAMERA_SS_IRQ_6, MSM_CAM_HW_ISPIF);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_7],
+ 0, CAMERA_SS_IRQ_7, MSM_CAM_HW_CPP);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_8],
+ 0, CAMERA_SS_IRQ_8, MSM_CAM_HW_VFE0);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_9],
+ 0, CAMERA_SS_IRQ_9, MSM_CAM_HW_VFE1);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_10],
+ 0, CAMERA_SS_IRQ_10, MSM_CAM_HW_JPEG0);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_11],
+ 0, CAMERA_SS_IRQ_11, MSM_CAM_HW_JPEG1);
+
+ msm_irqrouter_update_irqmap_entry(&irqmap[CAMERA_SS_IRQ_12],
+ 0, CAMERA_SS_IRQ_12, MSM_CAM_HW_JPEG2);
+}
+
+static int msm_irqrouter_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+ /* Only one object of IRQ Router allowed. */
+ if (atomic_read(&irqrouter_ctrl->active) != 0) {
+ pr_err("%s IRQ router is already opened\n", __func__);
+ return -EINVAL;
+ }
+
+ D("%s E ", __func__);
+ atomic_inc(&irqrouter_ctrl->active);
+
+ return 0;
+}
+
+static int msm_irqrouter_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+ if (atomic_read(&irqrouter_ctrl->active) == 0) {
+ pr_err("%s IRQ router is already closed\n", __func__);
+ return -EINVAL;
+ }
+ D("%s E ", __func__);
+ atomic_dec(&irqrouter_ctrl->active);
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_irqrouter_internal_ops = {
+ .open = msm_irqrouter_open,
+ .close = msm_irqrouter_close,
+};
+
+long msm_irqrouter_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct irqrouter_ctrl_type *irqrouter_ctrl = v4l2_get_subdevdata(sd);
+ struct msm_camera_irq_cfg *irq_cfg;
+ struct intr_table_entry irq_req;
+ int rc = 0;
+
+ /* Handle all IRQ Router Subdev IOCTLs here.
+ * Userspace sends the composite irq configuration.
+ * IRQ Router subdev then configures the registers to group
+ * together individual core hw irqs into a composite IRQ
+ * to the MSM IRQ controller. It also registers them with
+ * the irq manager in the camera server. */
+ switch (cmd) {
+ case MSM_IRQROUTER_CFG_COMPIRQ:
+ COPY_FROM_USER(rc, &irq_cfg, (void __user *)arg,
+ sizeof(struct msm_camera_irq_cfg));
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ break;
+ }
+
+ if (!irq_cfg ||
+ (irq_cfg->irq_idx < CAMERA_SS_IRQ_0) ||
+ (irq_cfg->irq_idx >= CAMERA_SS_IRQ_MAX)) {
+ pr_err("%s Invalid input", __func__);
+ return -EINVAL;
+ } else {
+ irq_req.cam_hw_mask = irq_cfg->cam_hw_mask;
+ irq_req.irq_idx = irq_cfg->irq_idx;
+ irq_req.irq_num =
+ irqrouter_ctrl->def_hw_irqmap[irq_cfg->irq_idx].irq_num;
+ irq_req.is_composite = 1;
+ irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+ irq_req.num_hwcore = irq_cfg->num_hwcore;
+ irq_req.data = NULL;
+ rc = msm_cam_server_request_irq(&irq_req);
+ if (rc < 0) {
+ pr_err("%s Error requesting comp irq %d ",
+ __func__, irq_req.irq_idx);
+ return rc;
+ }
+ irqrouter_ctrl->def_hw_irqmap
+ [irq_cfg->irq_idx].is_composite = 1;
+ }
+ break;
+ default:
+ pr_err("%s Invalid cmd %d ", __func__, cmd);
+ break;
+ }
+
+ return rc;
+}
+
+static const struct v4l2_subdev_core_ops msm_irqrouter_subdev_core_ops = {
+ .ioctl = msm_irqrouter_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_irqrouter_subdev_ops = {
+ .core = &msm_irqrouter_subdev_core_ops,
+};
+
+static int __devinit irqrouter_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct irqrouter_ctrl_type *irqrouter_ctrl;
+ struct msm_cam_subdev_info sd_info;
+
+ D("%s: device id = %d\n", __func__, pdev->id);
+
+ irqrouter_ctrl = kzalloc(sizeof(struct irqrouter_ctrl_type),
+ GFP_KERNEL);
+ if (!irqrouter_ctrl) {
+ pr_err("%s: not enough memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ v4l2_subdev_init(&irqrouter_ctrl->subdev, &msm_irqrouter_subdev_ops);
+ irqrouter_ctrl->subdev.internal_ops = &msm_irqrouter_internal_ops;
+ irqrouter_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(irqrouter_ctrl->subdev.name,
+ sizeof(irqrouter_ctrl->subdev.name), "msm_irqrouter");
+ v4l2_set_subdevdata(&irqrouter_ctrl->subdev, irqrouter_ctrl);
+ irqrouter_ctrl->pdev = pdev;
+
+ msm_irqrouter_send_default_irqmap(irqrouter_ctrl);
+
+ media_entity_init(&irqrouter_ctrl->subdev.entity, 0, NULL, 0);
+ irqrouter_ctrl->subdev.entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ irqrouter_ctrl->subdev.entity.group_id = IRQ_ROUTER_DEV;
+ irqrouter_ctrl->subdev.entity.name = pdev->name;
+
+ sd_info.sdev_type = IRQ_ROUTER_DEV;
+ sd_info.sd_index = 0;
+ sd_info.irq_num = 0;
+ /* Now register this subdev with the camera server. */
+ rc = msm_cam_register_subdev_node(&irqrouter_ctrl->subdev, &sd_info);
+ if (rc < 0) {
+ pr_err("%s Error registering irqr subdev %d", __func__, rc);
+ goto error;
+ }
+ irqrouter_ctrl->subdev.entity.revision =
+ irqrouter_ctrl->subdev.devnode->num;
+ atomic_set(&irqrouter_ctrl->active, 0);
+
+ platform_set_drvdata(pdev, &irqrouter_ctrl->subdev);
+
+ return rc;
+error:
+ kfree(irqrouter_ctrl);
+ return rc;
+}
+
+static int __exit irqrouter_exit(struct platform_device *pdev)
+{
+ kfree(irqrouter_ctrl);
+ return 0;
+}
+
+static struct platform_driver msm_irqrouter_driver = {
+ .probe = irqrouter_probe,
+ .remove = irqrouter_exit,
+ .driver = {
+ .name = MSM_IRQ_ROUTER_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_irqrouter_init_module(void)
+{
+ return platform_driver_register(&msm_irqrouter_driver);
+}
+
+static void __exit msm_irqrouter_exit_module(void)
+{
+ platform_driver_unregister(&msm_irqrouter_driver);
+}
+
+module_init(msm_irqrouter_init_module);
+module_exit(msm_irqrouter_exit_module);
+MODULE_DESCRIPTION("msm camera irq router");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_camirq_router.h b/drivers/media/video/msm/msm_camirq_router.h
new file mode 100644
index 0000000..2c9cb73
--- /dev/null
+++ b/drivers/media/video/msm/msm_camirq_router.h
@@ -0,0 +1,206 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 __MSM_CAM_IRQROUTER_H__
+#define __MSM_CAM_IRQROUTER_H__
+
+#include <linux/bitops.h>
+
+/* Camera SS common registers defines - Start */
+/* These registers are not directly related to
+ * IRQ Router, but are common to the Camera SS.
+ * IRQ Router registers dont have a unique base address
+ * in the memory mapped address space. It is offset from
+ * the Camera SS base address. So keep the common Camera
+ * SS registers also in the IRQ Router subdev for now. */
+
+/* READ ONLY: Camera Subsystem HW version */
+#define CAMSS_HW_VERSION 0x00000000
+
+/* Bits 4:0 of this register can be used to select a desired
+ * camera core test bus to drive the Camera_SS test bus output */
+#define CAMSS_TESTBUS_SEL 0x00000004
+
+/* Bits 4:0 of this register is used to allow either Microcontroller
+ * or the CCI drive the corresponding GPIO output.
+ * For eg: Setting bit 0 of this register allows Microcontroller to
+ * drive GPIO #0. Clearing the bit allows CCI to drive GPIO #0. */
+#define CAMSS_GPIO_MUX_SEL 0x00000008
+
+/* Bit 0 of this register is used to set the default AHB master
+ * for the AHB Arbiter. 0 - AHB Master 0, 1 - AHB Master 1*/
+#define CAMSS_AHB_ARB_CTL 0x0000000C
+
+/* READ ONLY */
+#define CAMSS_XPU2_STATUS 0x00000010
+
+/* Select the appropriate CSI clock for CSID Pixel pipes */
+#define CAMSS_CSI_PIX_CLK_MUX_SEL 0x00000020
+#define CAMSS_CSI_PIX_CLK_CGC_EN 0x00000024
+
+/* Select the appropriate CSI clock for CSID RDI pipes */
+#define CAMSS_CSI_RDI_CLK_MUX_SEL 0x00000028
+#define CAMSS_CSI_RDI_CLK_CGC_EN 0x0000002C
+
+/* Select the appropriate CSI clock for CSI Phy0 */
+#define CAMSS_CSI_PHY_0_CLK_MUX_SEL 0x00000030
+#define CAMSS_CSI_PHY_0_CLK_CGC_EN 0x00000034
+
+/* Select the appropriate CSI clock for CSI Phy1 */
+#define CAMSS_CSI_PHY_1_CLK_MUX_SEL 0x00000038
+#define CAMSS_CSI_PHY_1_CLK_CGC_EN 0x0000003C
+
+/* Select the appropriate CSI clock for CSI Phy2 */
+#define CAMSS_CSI_PHY_2_CLK_MUX_SEL 0x00000040
+#define CAMSS_CSI_PHY_2_CLK_CGC_EN 0x00000044
+/* Camera SS common registers defines - End */
+
+/* IRQ Router registers defines - Start */
+/* This register is used to reset the composite
+ * IRQ outputs of the Camera_SS IRQ Router */
+#define CAMSS_IRQ_COMPOSITE_RESET_CTRL 0x00000060
+
+/* By default, this 'allows' the interrupts from
+ * Micro to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_0 0x00000064
+
+/* By default, this 'allows' the interrupts from
+ * CCI to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_1 0x00000068
+
+/* By default, this 'allows' the interrupts from
+ * CSI_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_2 0x0000006C
+
+/* By default, this 'allows' the interrupts from
+ * CSI_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_3 0x00000070
+
+/* By default, this 'allows' the interrupts from
+ * CSI_2 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_4 0x00000074
+
+/* By default, this 'allows' the interrupts from
+ * CSI_3 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_5 0x00000078
+
+/* By default, this 'allows' the interrupts from
+ * ISPIF to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_6 0x0000007C
+
+/* By default, this 'allows' the interrupts from
+ * CPP to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_7 0x00000080
+
+/* By default, this 'allows' the interrupts from
+ * VFE_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_8 0x00000084
+
+/* By default, this 'allows' the interrupts from
+ * VFE_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_9 0x00000088
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_0 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_10 0x0000008C
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_1 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_11 0x00000090
+
+/* By default, this 'allows' the interrupts from
+ * JPEG_2 to pass through, unless configured in
+ * composite mode. */
+#define CAMSS_IRQ_COMPOSITE_MASK_12 0x00000094
+
+/* The following IRQ_COMPOSITE_MICRO_MASK registers
+ * allow the interrupts from the individual hw
+ * cores to be composited into an IRQ for Micro. */
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_0 0x000000A4
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_1 0x000000A8
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_2 0x000000AC
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_3 0x000000B0
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_4 0x000000B4
+#define CAMSS_IRQ_COMPOSITE_MICRO_MASK_5 0x000000B8
+/* IRQ Router register defines - End */
+
+/* Writing this mask will reset all the composite
+ * IRQs of the Camera_SS IRQ Router */
+#define CAMSS_IRQ_COMPOSITE_RESET_MASK 0x003F1FFF
+
+/* Use this to enable Micro IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_MICRO_IRQ_IN_COMPOSITE BIT(0)
+/* Use this to enable CCI IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CCI_IRQ_IN_COMPOSITE BIT(1)
+/* Use this to enable CSI0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI0_IRQ_IN_COMPOSITE BIT(2)
+/* Use this to enable CSI1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI1_IRQ_IN_COMPOSITE BIT(3)
+/* Use this to enable CSI2 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI2_IRQ_IN_COMPOSITE BIT(4)
+/* Use this to enable CSI3 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CSI3_IRQ_IN_COMPOSITE BIT(5)
+/* Use this to enable ISPIF IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_ISPIF_IRQ_IN_COMPOSITE BIT(6)
+/* Use this to enable CPP IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_CPP_IRQ_IN_COMPOSITE BIT(7)
+/* Use this to enable VFE0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_VFE0_IRQ_IN_COMPOSITE BIT(8)
+/* Use this to enable VFE1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_VFE1_IRQ_IN_COMPOSITE BIT(9)
+/* Use this to enable JPEG0 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG0_IRQ_IN_COMPOSITE BIT(10)
+/* Use this to enable JPEG1 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG1_IRQ_IN_COMPOSITE BIT(11)
+/* Use this to enable JPEG2 IRQ from IRQ Router
+ * composite interrupt */
+#define ENABLE_JPEG2_IRQ_IN_COMPOSITE BIT(12)
+
+struct irqrouter_ctrl_type {
+ /* v4l2 subdev */
+ struct v4l2_subdev subdev;
+ struct platform_device *pdev;
+
+ void __iomem *irqr_dev_base;
+
+ struct resource *irqr_dev_mem;
+ struct resource *irqr_dev_io;
+ atomic_t active;
+ struct msm_cam_server_irqmap_entry def_hw_irqmap[CAMERA_SS_IRQ_MAX];
+};
+
+#endif /* __MSM_CAM_IRQROUTER_H__ */
diff --git a/drivers/media/video/msm/msm_gesture.c b/drivers/media/video/msm/msm_gesture.c
index 6b81d15..5777cb5 100644
--- a/drivers/media/video/msm/msm_gesture.c
+++ b/drivers/media/video/msm/msm_gesture.c
@@ -455,6 +455,8 @@
struct msm_gesture_ctrl *p_gesture_ctrl = &g_gesture_ctrl;
struct v4l2_subdev *gesture_subdev =
kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ struct msm_cam_subdev_info sd_info;
+
D("%s\n", __func__);
if (!gesture_subdev) {
pr_err("%s: no enough memory\n", __func__);
@@ -475,7 +477,10 @@
/* events */
gesture_subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
- msm_cam_register_subdev_node(gesture_subdev, GESTURE_DEV, 0);
+ sd_info.sdev_type = GESTURE_DEV;
+ sd_info.sd_index = 0;
+ sd_info.irq_num = 0;
+ msm_cam_register_subdev_node(gesture_subdev, &sd_info);
gesture_subdev->entity.revision = gesture_subdev->devnode->num;
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 148f8b5..834c9b0 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -146,7 +146,7 @@
static int msm_isp_notify_VFE_BUF_EVT(struct v4l2_subdev *sd, void *arg)
{
- int rc = -EINVAL, image_mode;
+ int rc = -EINVAL;
struct msm_vfe_resp *vdata = (struct msm_vfe_resp *)arg;
struct msm_free_buf free_buf, temp_free_buf;
struct msm_camvfe_params vfe_params;
@@ -154,16 +154,22 @@
struct msm_cam_media_controller *pmctl =
(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
struct msm_cam_v4l2_device *pcam = pmctl->pcam_ptr;
-
- int vfe_id = vdata->evt_msg.msg_id;
+ struct msm_frame_info *frame_info =
+ (struct msm_frame_info *)vdata->evt_msg.data;
+ uint32_t vfe_id, image_mode;
if (!pcam) {
pr_debug("%s pcam is null. return\n", __func__);
msm_isp_sync_free(vdata);
return rc;
}
- /* Convert the vfe msg to the image mode */
- image_mode = msm_isp_vfe_msg_to_img_mode(pmctl, vfe_id);
- BUG_ON(image_mode < 0);
+ if (frame_info) {
+ vfe_id = frame_info->path;
+ image_mode = frame_info->image_mode;
+ } else {
+ vfe_id = vdata->evt_msg.msg_id;
+ image_mode = msm_isp_vfe_msg_to_img_mode(pmctl, vfe_id);
+ }
+
switch (vdata->type) {
case VFE_MSG_V32_START:
case VFE_MSG_V32_START_RECORDING:
@@ -211,9 +217,9 @@
case VFE_MSG_V32_JPEG_CAPTURE:
D("%s:VFE_MSG_V32_JPEG_CAPTURE vdata->type %d\n", __func__,
vdata->type);
- free_buf.num_planes = 1;
- free_buf.ch_paddr[0] = IMEM_Y_PING_OFFSET;
- free_buf.ch_paddr[1] = IMEM_CBCR_PING_OFFSET;
+ free_buf.num_planes = 2;
+ free_buf.ch_paddr[0] = pmctl->ping_imem_y;
+ free_buf.ch_paddr[1] = pmctl->ping_imem_cbcr;
cfgcmd.cmd_type = CMD_CONFIG_PING_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
@@ -222,8 +228,8 @@
__func__, free_buf.ch_paddr[0], free_buf.ch_paddr[1]);
rc = v4l2_subdev_call(sd, core, ioctl, 0, &vfe_params);
/* Write the same buffer into PONG */
- free_buf.ch_paddr[0] = IMEM_Y_PONG_OFFSET;
- free_buf.ch_paddr[1] = IMEM_CBCR_PONG_OFFSET;
+ free_buf.ch_paddr[0] = pmctl->pong_imem_y;
+ free_buf.ch_paddr[1] = pmctl->pong_imem_cbcr;
cfgcmd.cmd_type = CMD_CONFIG_PONG_ADDR;
cfgcmd.value = &vfe_id;
vfe_params.vfe_cfg = &cfgcmd;
@@ -302,45 +308,49 @@
}
case NOTIFY_VFE_MSG_OUT: {
uint8_t msgid;
+ int32_t image_mode = -1;
struct isp_msg_output *isp_output =
(struct isp_msg_output *)arg;
- switch (isp_output->output_id) {
- case MSG_ID_OUTPUT_P:
- msgid = VFE_MSG_OUTPUT_P;
- break;
- case MSG_ID_OUTPUT_V:
- msgid = VFE_MSG_OUTPUT_V;
- break;
- case MSG_ID_OUTPUT_T:
- msgid = VFE_MSG_OUTPUT_T;
- break;
- case MSG_ID_OUTPUT_S:
- msgid = VFE_MSG_OUTPUT_S;
- break;
- case MSG_ID_OUTPUT_PRIMARY:
- msgid = VFE_MSG_OUTPUT_PRIMARY;
- break;
- case MSG_ID_OUTPUT_SECONDARY:
- msgid = VFE_MSG_OUTPUT_SECONDARY;
- break;
- default:
- pr_err("%s: Invalid VFE output id: %d\n",
- __func__, isp_output->output_id);
- rc = -EINVAL;
- break;
+ if (isp_output->buf.image_mode < 0) {
+ switch (isp_output->output_id) {
+ case MSG_ID_OUTPUT_P:
+ msgid = VFE_MSG_OUTPUT_P;
+ break;
+ case MSG_ID_OUTPUT_V:
+ msgid = VFE_MSG_OUTPUT_V;
+ break;
+ case MSG_ID_OUTPUT_T:
+ msgid = VFE_MSG_OUTPUT_T;
+ break;
+ case MSG_ID_OUTPUT_S:
+ msgid = VFE_MSG_OUTPUT_S;
+ break;
+ case MSG_ID_OUTPUT_PRIMARY:
+ msgid = VFE_MSG_OUTPUT_PRIMARY;
+ break;
+ case MSG_ID_OUTPUT_SECONDARY:
+ msgid = VFE_MSG_OUTPUT_SECONDARY;
+ break;
+ default:
+ pr_err("%s: Invalid VFE output id: %d\n",
+ __func__, isp_output->output_id);
+ rc = -EINVAL;
+ break;
+ }
+ if (!rc)
+ image_mode =
+ msm_isp_vfe_msg_to_img_mode(pmctl, msgid);
+ } else {
+ image_mode = isp_output->buf.image_mode;
}
-
- if (!rc) {
- isp_event->isp_data.isp_msg.msg_id =
- isp_output->output_id;
- isp_event->isp_data.isp_msg.frame_id =
- isp_output->frameCounter;
- buf = isp_output->buf;
- msgid = msm_isp_vfe_msg_to_img_mode(pmctl, msgid);
- BUG_ON(msgid < 0);
- msm_mctl_buf_done(pmctl, msgid,
- &buf, isp_output->frameCounter);
- }
+ isp_event->isp_data.isp_msg.msg_id =
+ isp_output->output_id;
+ isp_event->isp_data.isp_msg.frame_id =
+ isp_output->frameCounter;
+ buf = isp_output->buf;
+ BUG_ON(image_mode < 0);
+ msm_mctl_buf_done(pmctl, image_mode,
+ &buf, isp_output->frameCounter);
}
break;
case NOTIFY_VFE_MSG_COMP_STATS: {
@@ -467,19 +477,54 @@
return -EINVAL;
}
+ rc = msm_iommu_map_contig_buffer(
+ (unsigned long)IMEM_Y_PING_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&mctl->ping_imem_y);
+ mctl->ping_imem_cbcr = mctl->ping_imem_y + IMEM_Y_SIZE;
+ if (rc < 0) {
+ pr_err("%s: ping iommu mapping returned error %d\n",
+ __func__, rc);
+ mctl->ping_imem_y = 0;
+ mctl->ping_imem_cbcr = 0;
+ }
+ msm_iommu_map_contig_buffer(
+ (unsigned long)IMEM_Y_PONG_OFFSET, CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)),
+ SZ_4K, IOMMU_WRITE | IOMMU_READ,
+ (unsigned long *)&mctl->pong_imem_y);
+ mctl->pong_imem_cbcr = mctl->pong_imem_y + IMEM_Y_SIZE;
+ if (rc < 0) {
+ pr_err("%s: pong iommu mapping returned error %d\n",
+ __func__, rc);
+ mctl->pong_imem_y = 0;
+ mctl->pong_imem_cbcr = 0;
+ }
+
rc = msm_vfe_subdev_init(sd, mctl);
if (rc < 0) {
pr_err("%s: vfe_init failed at %d\n",
- __func__, rc);
+ __func__, rc);
}
return rc;
}
-static void msm_isp_release(
+static void msm_isp_release(struct msm_cam_media_controller *mctl,
struct v4l2_subdev *sd)
{
D("%s\n", __func__);
msm_vfe_subdev_release(sd);
+ msm_iommu_unmap_contig_buffer(mctl->ping_imem_y,
+ CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+ msm_iommu_unmap_contig_buffer(mctl->pong_imem_y,
+ CAMERA_DOMAIN, GEN_POOL,
+ ((IMEM_Y_SIZE + IMEM_CBCR_SIZE + 4095) & (~4095)));
+ mctl->ping_imem_y = 0;
+ mctl->ping_imem_cbcr = 0;
+ mctl->pong_imem_y = 0;
+ mctl->pong_imem_cbcr = 0;
}
static int msm_config_vfe(struct v4l2_subdev *sd,
@@ -626,6 +671,8 @@
case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC:
case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS:
case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC:
+ case CMD_AXI_START:
+ case CMD_AXI_STOP:
/* Dont need to pass buffer information.
* subdev will get the buffer from media
* controller free queue.
@@ -707,13 +754,6 @@
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
- case MSM_CAM_IOCTL_PICT_PP_DONE:
- /* Release the preview of snapshot frame
- * that was grabbed.
- */
- /*rc = msm_pp_release(pmsm->sync, arg);*/
- break;
-
case MSM_CAM_IOCTL_CONFIG_VFE:
/* Coming from config thread for update */
rc = msm_config_vfe(sd, pmctl, argp);
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 716575a..cdfad3b 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -20,6 +20,7 @@
#include <linux/videodev2.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
+#include <linux/wakelock.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
@@ -27,8 +28,6 @@
#include <linux/android_pmem.h>
-#include <mach/cpuidle.h>
-
#include "msm.h"
#include "msm_cam_server.h"
#include "msm_csid.h"
@@ -40,6 +39,7 @@
#include "msm_vpe.h"
#include "msm_vfe32.h"
#include "msm_camera_eeprom.h"
+#include "msm_csi_register.h"
#ifdef CONFIG_MSM_CAMERA_DEBUG
#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -48,7 +48,6 @@
#endif
#define MSM_V4L2_SWFI_LATENCY 3
-
/* VFE required buffer number for streaming */
static struct msm_isp_color_fmt msm_isp_formats[] = {
{
@@ -163,6 +162,8 @@
info.mount_angle = sdata->sensor_platform_info->mount_angle;
info.actuator_enabled = sdata->actuator_info ? 1 : 0;
info.strobe_flash_enabled = sdata->strobe_flash_data ? 1 : 0;
+ info.ispif_supported = mctl->ispif_sdev ? 1 : 0;
+
/* copy back to user space */
if (copy_to_user((void *)arg,
&info,
@@ -401,6 +402,10 @@
else
rc = p_mctl->isp_sdev->isp_config(p_mctl, cmd, arg);
break;
+ case MSM_CAM_IOCTL_ISPIF_IO_CFG:
+ rc = v4l2_subdev_call(p_mctl->ispif_sdev,
+ core, ioctl, VIDIOC_MSM_ISPIF_CFG, argp);
+ break;
default:
/* ISP config*/
D("%s:%d: go to default. Calling msm_isp_config\n",
@@ -436,62 +441,12 @@
(struct msm_camera_sensor_info *) s_ctrl->sensordata;
struct msm_camera_device_platform_data *pdata = sinfo->pdata;
- if (pdata->is_csiphy) {
- /* register csiphy subdev */
- driver = driver_find(MSM_CSIPHY_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
-
- dev = driver_find_device(driver, NULL, (void *)core_index,
+ rc = msm_csi_register_subdevs(p_mctl, core_index,
msm_mctl_subdev_match_core);
- if (!dev)
+
+ if (rc < 0)
goto out;
- p_mctl->csiphy_sdev = dev_get_drvdata(dev);
- }
-
- if (pdata->is_csic) {
- /* register csic subdev */
- driver = driver_find(MSM_CSIC_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
-
- dev = driver_find_device(driver, NULL, (void *)core_index,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->csic_sdev = dev_get_drvdata(dev);
- }
-
- if (pdata->is_csid) {
- /* register csid subdev */
- driver = driver_find(MSM_CSID_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
-
- dev = driver_find_device(driver, NULL, (void *)core_index,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->csid_sdev = dev_get_drvdata(dev);
- }
-
- if (pdata->is_ispif) {
- /* register ispif subdev */
- driver = driver_find(MSM_ISPIF_DRV_NAME, &platform_bus_type);
- if (!driver)
- goto out;
-
- dev = driver_find_device(driver, NULL, 0,
- msm_mctl_subdev_match_core);
- if (!dev)
- goto out;
-
- p_mctl->ispif_sdev = dev_get_drvdata(dev);
- }
-
/* register vfe subdev */
driver = driver_find(MSM_VFE_DRV_NAME, &platform_bus_type);
if (!driver)
@@ -569,9 +524,9 @@
mutex_lock(&p_mctl->lock);
/* open sub devices - once only*/
if (!p_mctl->opencnt) {
+ struct msm_sensor_csi_info csi_info;
uint32_t csid_version;
- pm_qos_update_request(&p_mctl->idle_pm_qos,
- msm_cpuidle_get_deep_idle_latency());
+ wake_lock(&p_mctl->wake_lock);
csid_core = camdev->csid_core;
rc = msm_mctl_register_subdevs(p_mctl, csid_core);
@@ -596,7 +551,7 @@
goto act_power_up_failed;
}
- if (camdev->is_csiphy) {
+ if (p_mctl->csiphy_sdev) {
rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_INIT, NULL);
if (rc < 0) {
@@ -606,7 +561,7 @@
}
}
- if (camdev->is_csid) {
+ if (p_mctl->csid_sdev) {
rc = v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
VIDIOC_MSM_CSID_INIT, &csid_version);
if (rc < 0) {
@@ -614,9 +569,10 @@
__func__, rc);
goto csid_init_failed;
}
+ csi_info.is_csic = 0;
}
- if (camdev->is_csic) {
+ if (p_mctl->csic_sdev) {
rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
VIDIOC_MSM_CSIC_INIT, &csid_version);
if (rc < 0) {
@@ -624,6 +580,16 @@
__func__, rc);
goto csic_init_failed;
}
+ csi_info.is_csic = 1;
+ }
+
+ csi_info.csid_version = csid_version;
+ rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
+ VIDIOC_MSM_SENSOR_CSID_INFO, &csi_info);
+ if (rc < 0) {
+ pr_err("%s: sensor csi version failed %d\n",
+ __func__, rc);
+ goto msm_csi_version;
}
/* ISP first*/
@@ -657,22 +623,12 @@
}
}
- if (camdev->is_ispif) {
- rc = v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
- VIDIOC_MSM_ISPIF_INIT, &csid_version);
- if (rc < 0) {
- pr_err("%s: ispif initialization failed %d\n",
- __func__, rc);
- goto ispif_init_failed;
- }
- }
- if (camdev->is_ispif) {
- pm_qos_add_request(&p_mctl->pm_qos_req_list,
- PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
- pm_qos_update_request(&p_mctl->pm_qos_req_list,
- MSM_V4L2_SWFI_LATENCY);
- }
+ pm_qos_add_request(&p_mctl->pm_qos_req_list,
+ PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&p_mctl->pm_qos_req_list,
+ MSM_V4L2_SWFI_LATENCY);
+
p_mctl->apps_id = apps_id;
p_mctl->opencnt++;
} else {
@@ -682,11 +638,6 @@
return rc;
-ispif_init_failed:
- if (camdev->is_vpe)
- if (v4l2_subdev_call(p_mctl->vpe_sdev, core, ioctl,
- VIDIOC_MSM_VPE_RELEASE, NULL) < 0)
- pr_err("%s: vpe release failed %d\n", __func__, rc);
vpe_init_failed:
if (p_mctl->axi_sdev)
if (v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
@@ -694,19 +645,20 @@
pr_err("%s: axi release failed %d\n", __func__, rc);
axi_init_failed:
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
- p_mctl->isp_sdev->isp_release(p_mctl->isp_sdev->sd);
+ p_mctl->isp_sdev->isp_release(p_mctl, p_mctl->isp_sdev->sd);
+msm_csi_version:
isp_open_failed:
- if (camdev->is_csic)
+ if (p_mctl->csic_sdev)
if (v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
VIDIOC_MSM_CSIC_RELEASE, NULL) < 0)
pr_err("%s: csic release failed %d\n", __func__, rc);
csic_init_failed:
- if (camdev->is_csid)
+ if (p_mctl->csid_sdev)
if (v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
VIDIOC_MSM_CSID_RELEASE, NULL) < 0)
pr_err("%s: csid release failed %d\n", __func__, rc);
csid_init_failed:
- if (camdev->is_csiphy)
+ if (p_mctl->csiphy_sdev)
if (v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_RELEASE, NULL) < 0)
pr_err("%s: csiphy release failed %d\n", __func__, rc);
@@ -720,7 +672,7 @@
pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
sensor_sdev_failed:
register_sdev_failed:
- pm_qos_update_request(&p_mctl->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+ wake_unlock(&p_mctl->wake_lock);
mutex_unlock(&p_mctl->lock);
return rc;
}
@@ -736,12 +688,7 @@
v4l2_subdev_call(p_mctl->sensor_sdev, core, ioctl,
VIDIOC_MSM_SENSOR_RELEASE, NULL);
- if (camdev->is_ispif) {
- v4l2_subdev_call(p_mctl->ispif_sdev, core, ioctl,
- VIDIOC_MSM_ISPIF_RELEASE, NULL);
- }
-
- if (camdev->is_csic) {
+ if (p_mctl->csic_sdev) {
v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
VIDIOC_MSM_CSIC_RELEASE, NULL);
}
@@ -757,31 +704,31 @@
}
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
- p_mctl->isp_sdev->isp_release(
+ p_mctl->isp_sdev->isp_release(p_mctl,
p_mctl->isp_sdev->sd);
- if (camdev->is_csid) {
+ if (p_mctl->csid_sdev) {
v4l2_subdev_call(p_mctl->csid_sdev, core, ioctl,
VIDIOC_MSM_CSID_RELEASE, NULL);
}
- if (camdev->is_csiphy) {
+ if (p_mctl->csiphy_sdev) {
v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_RELEASE, NULL);
}
- if (camdev->is_ispif) {
- pm_qos_update_request(&p_mctl->pm_qos_req_list,
- PM_QOS_DEFAULT_VALUE);
- pm_qos_remove_request(&p_mctl->pm_qos_req_list);
- }
-
- if (p_mctl->act_sdev)
+ if (p_mctl->act_sdev) {
v4l2_subdev_call(p_mctl->act_sdev, core, s_power, 0);
+ p_mctl->act_sdev = NULL;
+ }
v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
- pm_qos_update_request(&p_mctl->idle_pm_qos, PM_QOS_DEFAULT_VALUE);
+ pm_qos_update_request(&p_mctl->pm_qos_req_list,
+ PM_QOS_DEFAULT_VALUE);
+ pm_qos_remove_request(&p_mctl->pm_qos_req_list);
+
+ wake_unlock(&p_mctl->wake_lock);
return rc;
}
@@ -865,8 +812,7 @@
return -EINVAL;
}
- pm_qos_add_request(&pmctl->idle_pm_qos, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
+ wake_lock_init(&pmctl->wake_lock, WAKE_LOCK_SUSPEND, "msm_camera");
mutex_init(&pmctl->lock);
pmctl->opencnt = 0;
@@ -906,7 +852,7 @@
}
mutex_destroy(&pmctl->lock);
- pm_qos_remove_request(&pmctl->idle_pm_qos);
+ wake_lock_destroy(&pmctl->wake_lock);
msm_cam_server_free_mctl(pcam->mctl_handle);
return rc;
}
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 1088a54..eade6f1 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -454,7 +454,7 @@
image_mode, fbuf,
&frame_id, 1);
D("%s mctl node buf done %d\n", __func__, 0);
- return -EINVAL;
+ return rc;
} else {
pr_err("%s Invalid instance, dropping buffer\n",
__func__);
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index f4c04bb..844a3ff 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -36,18 +36,6 @@
#define D(fmt, args...) do {} while (0)
#endif
-
-static int msm_mctl_pp_vpe_ioctl(struct v4l2_subdev *vpe_sd,
- struct msm_mctl_pp_cmd *cmd, void *data)
-{
- int rc = 0;
- struct msm_mctl_pp_params parm;
- parm.cmd = cmd;
- parm.data = data;
- rc = v4l2_subdev_call(vpe_sd, core, ioctl, VIDIOC_MSM_VPE_CFG, &parm);
- return rc;
-}
-
static int msm_mctl_pp_buf_divert(
struct msm_cam_media_controller *pmctl,
struct msm_cam_v4l2_dev_inst *pcam_inst,
@@ -384,244 +372,6 @@
return -EINVAL;
}
-int msm_mctl_pp_proc_vpe_cmd(
- struct msm_cam_media_controller *p_mctl,
- struct msm_mctl_pp_cmd *pp_cmd)
-{
- int rc = 0, idx;
- void __user *argp = (void __user *)pp_cmd->value;
- struct msm_cam_v4l2_dev_inst *pcam_inst;
-
- switch (pp_cmd->id) {
- case VPE_CMD_INIT:
- case VPE_CMD_DEINIT:
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- break;
- case VPE_CMD_DISABLE:
- case VPE_CMD_RESET:
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- break;
- case VPE_CMD_ENABLE: {
- struct msm_vpe_clock_rate clk_rate;
- if (sizeof(struct msm_vpe_clock_rate) !=
- pp_cmd->length) {
- pr_err("%s: vpe cmd size mismatch "
- "(id=%d, length = %d, expect size = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(struct msm_vpe_clock_rate));
- rc = -EINVAL;
- break;
- }
- if (copy_from_user(&clk_rate, pp_cmd->value,
- sizeof(struct msm_vpe_clock_rate))) {
- pr_err("%s:clk_rate copy failed", __func__);
- return -EFAULT;
- }
- pp_cmd->value = (void *)&clk_rate;
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- pp_cmd->value = argp;
- break;
- }
- case VPE_CMD_FLUSH: {
- struct msm_vpe_flush_frame_buffer flush_buf;
- if (sizeof(struct msm_vpe_flush_frame_buffer) !=
- pp_cmd->length) {
- D("%s: size mismatch(id=%d, len = %d, expected = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(struct msm_vpe_flush_frame_buffer));
- rc = -EINVAL;
- break;
- }
- if (copy_from_user(
- &flush_buf, pp_cmd->value, sizeof(flush_buf)))
- return -EFAULT;
- pp_cmd->value = (void *)&flush_buf;
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- if (rc == 0) {
- if (copy_to_user((void *)argp,
- &flush_buf,
- sizeof(flush_buf))) {
- ERR_COPY_TO_USER();
- rc = -EFAULT;
- }
- pp_cmd->value = argp;
- }
- }
- break;
- case VPE_CMD_OPERATION_MODE_CFG: {
- struct msm_vpe_op_mode_cfg op_mode_cfg;
- if (sizeof(struct msm_vpe_op_mode_cfg) !=
- pp_cmd->length) {
- D("%s: size mismatch(id=%d, len = %d, expected = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(struct msm_vpe_op_mode_cfg));
- rc = -EINVAL;
- break;
- }
- if (copy_from_user(&op_mode_cfg,
- pp_cmd->value,
- sizeof(op_mode_cfg)))
- return -EFAULT;
- pp_cmd->value = (void *)&op_mode_cfg;
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- break;
- }
- case VPE_CMD_INPUT_PLANE_CFG: {
- struct msm_vpe_input_plane_cfg input_cfg;
- if (sizeof(struct msm_vpe_input_plane_cfg) !=
- pp_cmd->length) {
- D("%s: mismatch(id=%d, len = %d, expected = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(struct msm_vpe_input_plane_cfg));
- rc = -EINVAL;
- break;
- }
- if (copy_from_user(
- &input_cfg, pp_cmd->value, sizeof(input_cfg)))
- return -EFAULT;
- pp_cmd->value = (void *)&input_cfg;
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- break;
- }
- case VPE_CMD_OUTPUT_PLANE_CFG: {
- struct msm_vpe_output_plane_cfg output_cfg;
- if (sizeof(struct msm_vpe_output_plane_cfg) !=
- pp_cmd->length) {
- D("%s: size mismatch(id=%d, len = %d, expected = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(struct msm_vpe_output_plane_cfg));
- rc = -EINVAL;
- break;
- }
- if (copy_from_user(&output_cfg, pp_cmd->value,
- sizeof(output_cfg))) {
- D("%s: cannot copy pp_cmd->value, size=%d",
- __func__, pp_cmd->length);
- return -EFAULT;
- }
- pp_cmd->value = (void *)&output_cfg;
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- break;
- }
- case VPE_CMD_INPUT_PLANE_UPDATE: {
- struct msm_vpe_input_plane_update_cfg input_update_cfg;
- if (sizeof(struct msm_vpe_input_plane_update_cfg) !=
- pp_cmd->length) {
- D("%s: size mismatch(id=%d, len = %d, expected = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(struct msm_vpe_input_plane_update_cfg));
- rc = -EINVAL;
- break;
- }
- if (copy_from_user(&input_update_cfg, pp_cmd->value,
- sizeof(input_update_cfg)))
- return -EFAULT;
- pp_cmd->value = (void *)&input_update_cfg;
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- break;
- }
- case VPE_CMD_SCALE_CFG_TYPE: {
- struct msm_vpe_scaler_cfg scaler_cfg;
- if (sizeof(struct msm_vpe_scaler_cfg) !=
- pp_cmd->length) {
- D("%s: size mismatch(id=%d, len = %d, expected = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(struct msm_vpe_scaler_cfg));
- rc = -EINVAL;
- break;
- }
- if (copy_from_user(&scaler_cfg, pp_cmd->value,
- sizeof(scaler_cfg)))
- return -EFAULT;
- pp_cmd->value = (void *)&scaler_cfg;
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, NULL);
- break;
- }
- case VPE_CMD_ZOOM: {
- struct msm_mctl_pp_frame_info *zoom;
- zoom = kmalloc(sizeof(struct msm_mctl_pp_frame_info),
- GFP_ATOMIC);
- if (!zoom) {
- rc = -ENOMEM;
- break;
- }
- if (sizeof(zoom->pp_frame_cmd) != pp_cmd->length) {
- D("%s: size mismatch(id=%d, len = %d, expected = %d",
- __func__, pp_cmd->id, pp_cmd->length,
- sizeof(zoom->pp_frame_cmd));
- rc = -EINVAL;
- kfree(zoom);
- break;
- }
- if (copy_from_user(&zoom->pp_frame_cmd, pp_cmd->value,
- sizeof(zoom->pp_frame_cmd))) {
- kfree(zoom);
- return -EFAULT;
- }
- D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x",
- __func__, zoom->pp_frame_cmd.src_buf_handle,
- zoom->pp_frame_cmd.dest_buf_handle,
- zoom->pp_frame_cmd.cookie,
- zoom->pp_frame_cmd.vpe_output_action,
- zoom->pp_frame_cmd.path);
- idx = msm_mctl_pp_path_to_inst_index(p_mctl->pcam_ptr,
- zoom->pp_frame_cmd.path);
- if (idx < 0) {
- pr_err("%s Invalid path, returning\n", __func__);
- kfree(zoom);
- return idx;
- }
- pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
- if (!pcam_inst) {
- pr_err("%s Invalid instance, returning\n", __func__);
- kfree(zoom);
- return -EINVAL;
- }
- zoom->user_cmd = pp_cmd->id;
- rc = msm_mctl_pp_get_phy_addr(pcam_inst,
- zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
- if (rc) {
- kfree(zoom);
- break;
- }
- rc = msm_mctl_pp_get_phy_addr(pcam_inst,
- zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
- if (rc) {
- kfree(zoom);
- break;
- }
- rc = msm_mctl_pp_copy_timestamp_and_frame_id(
- zoom->pp_frame_cmd.src_buf_handle,
-
- zoom->pp_frame_cmd.dest_buf_handle);
- if (rc) {
- kfree(zoom);
- break;
- }
- rc = msm_mctl_pp_vpe_ioctl(
- p_mctl->vpe_sdev, pp_cmd, (void *)zoom);
- if (rc) {
- kfree(zoom);
- break;
- }
- break;
- }
- default:
- rc = -1;
- break;
- }
- return rc;
-}
-
static int msm_mctl_pp_path_to_img_mode(int path)
{
switch (path) {
@@ -717,9 +467,6 @@
return -EFAULT;
switch (pp_cmd.type) {
- case MSM_PP_CMD_TYPE_VPE:
- rc = msm_mctl_pp_proc_vpe_cmd(p_mctl, &pp_cmd.cmd);
- break;
case MSM_PP_CMD_TYPE_MCTL:
rc = msm_mctl_pp_proc_cmd(p_mctl, &pp_cmd.cmd);
break;
@@ -739,71 +486,6 @@
return rc;
}
-int msm_mctl_pp_notify(struct msm_cam_media_controller *p_mctl,
- struct msm_mctl_pp_frame_info *pp_frame_info)
-{
- struct msm_mctl_pp_frame_cmd *pp_frame_cmd;
- pp_frame_cmd = &pp_frame_info->pp_frame_cmd;
-
- D("%s: msm_cam_evt_divert_frame=%d",
- __func__, sizeof(struct msm_mctl_pp_event_info));
- if ((MSM_MCTL_PP_VPE_FRAME_TO_APP &
- pp_frame_cmd->vpe_output_action)) {
- struct msm_free_buf done_frame;
- int img_mode =
- msm_mctl_pp_path_to_img_mode(
- pp_frame_cmd->path);
- if (img_mode < 0) {
- pr_err("%s Invalid image mode\n", __func__);
- return img_mode;
- }
- done_frame.ch_paddr[0] =
- pp_frame_info->dest_frame.sp.phy_addr;
- done_frame.vb =
- pp_frame_info->dest_frame.handle;
- msm_mctl_buf_done_pp(
- p_mctl, img_mode, &done_frame, 0, 0);
- D("%s: vpe done to app, vb=0x%x, path=%d, phy=0x%x",
- __func__, done_frame.vb,
- pp_frame_cmd->path, done_frame.ch_paddr[0]);
- }
- if ((MSM_MCTL_PP_VPE_FRAME_ACK &
- pp_frame_cmd->vpe_output_action)) {
- struct v4l2_event v4l2_evt;
- struct msm_mctl_pp_event_info *pp_event_info;
- struct msm_isp_event_ctrl *isp_event;
- isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl),
- GFP_ATOMIC);
- if (!isp_event) {
- pr_err("%s Insufficient memory.", __func__);
- return -ENOMEM;
- }
- memset(&v4l2_evt, 0, sizeof(v4l2_evt));
- *((uint32_t *)v4l2_evt.u.data) = (uint32_t)isp_event;
-
- /* Get hold of pp event info struct inside event ctrl.*/
- pp_event_info = &(isp_event->isp_data.pp_event_info);
-
- pp_event_info->event = MCTL_PP_EVENT_CMD_ACK;
- pp_event_info->ack.cmd = pp_frame_info->user_cmd;
- pp_event_info->ack.status = 0;
- pp_event_info->ack.cookie = pp_frame_cmd->cookie;
- v4l2_evt.id = 0;
- v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
- MSM_CAM_RESP_MCTL_PP_EVENT;
-
- v4l2_event_queue(
- p_mctl->config_device->
- config_stat_event_queue.pvdev,
- &v4l2_evt);
- D("%s: ack to daemon, cookie=0x%x, event = 0x%x",
- __func__, pp_frame_info->pp_frame_cmd.cookie,
- v4l2_evt.type);
- }
- kfree(pp_frame_info); /* free mem */
- return 0;
-}
-
int msm_mctl_pp_reserve_free_frame(
struct msm_cam_media_controller *p_mctl,
void __user *arg)
@@ -1027,3 +709,54 @@
return rc;
}
+
+int msm_mctl_pp_get_vpe_buf_info(struct msm_mctl_pp_frame_info *zoom)
+{
+ struct msm_cam_media_controller *p_mctl;
+ struct msm_cam_v4l2_dev_inst *pcam_inst;
+ int rc = 0, idx;
+
+ if (!zoom || !zoom->p_mctl) {
+ pr_err("%s Invalid input, not sending buffer to VPE ",
+ __func__);
+ return -EINVAL;
+ }
+ p_mctl = zoom->p_mctl;
+ idx = msm_mctl_pp_path_to_inst_index(p_mctl->pcam_ptr,
+ zoom->pp_frame_cmd.path);
+ if (idx < 0) {
+ pr_err("%s Invalid path, returning\n", __func__);
+ return idx;
+ }
+ pcam_inst = p_mctl->pcam_ptr->dev_inst[idx];
+ if (!pcam_inst) {
+ pr_err("%s Invalid instance, returning\n", __func__);
+ return -EINVAL;
+ }
+
+ rc = msm_mctl_pp_get_phy_addr(pcam_inst,
+ zoom->pp_frame_cmd.src_buf_handle, &zoom->src_frame);
+ if (rc) {
+ pr_err("%s Error getting buffer address for src frame\n",
+ __func__);
+ return rc;
+ }
+
+ rc = msm_mctl_pp_get_phy_addr(pcam_inst,
+ zoom->pp_frame_cmd.dest_buf_handle, &zoom->dest_frame);
+ if (rc) {
+ pr_err("%s Error getting buffer address for dest frame\n",
+ __func__);
+ return rc;
+ }
+
+ rc = msm_mctl_pp_copy_timestamp_and_frame_id(
+ zoom->pp_frame_cmd.src_buf_handle,
+ zoom->pp_frame_cmd.dest_buf_handle);
+ if (rc < 0) {
+ pr_err("%s Error copying timestamp info\n",
+ __func__);
+ return rc;
+ }
+ return rc;
+}
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
index a010817..885cd90 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -367,7 +367,7 @@
static void vfe31_stop(void)
{
-
+ uint8_t axiBusyFlag = true;
unsigned long flags;
atomic_set(&vfe31_ctrl->vstate, 0);
@@ -397,52 +397,6 @@
* at any time. stop camif immediately. */
msm_camera_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
-}
-
-void axi_start(void)
-{
- switch (vfe31_ctrl->operation_mode) {
- case VFE_OUTPUTS_PREVIEW:
- case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
- if (vfe31_ctrl->outpath.output_mode &
- VFE31_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
- } else if (vfe31_ctrl->outpath.output_mode &
- VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
- }
- break;
- default:
- if (vfe31_ctrl->outpath.output_mode &
- VFE31_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
- } else if (vfe31_ctrl->outpath.output_mode &
- VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
- msm_camera_io_w(1, vfe31_ctrl->vfebase +
- vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
- }
- break;
- }
-}
-
-void axi_stop(void)
-{
- uint8_t axiBusyFlag = true;
/* axi halt command. */
msm_camera_io_w(AXI_HALT,
vfe31_ctrl->vfebase + VFE_AXI_CMD);
@@ -466,15 +420,18 @@
vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
}
-static void vfe31_subdev_notify(int id, int path)
+static void vfe31_subdev_notify(int id, int path, int image_mode)
{
struct msm_vfe_resp rp;
+ struct msm_frame_info frame_info;
unsigned long flags;
spin_lock_irqsave(&vfe31_ctrl->sd_notify_lock, flags);
memset(&rp, 0, sizeof(struct msm_vfe_resp));
CDBG("vfe31_subdev_notify : msgId = %d\n", id);
rp.evt_msg.type = MSM_CAMERA_MSG;
- rp.evt_msg.msg_id = path;
+ frame_info.image_mode = image_mode;
+ frame_info.path = path;
+ rp.evt_msg.data = &frame_info;
rp.type = id;
v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
@@ -488,10 +445,12 @@
ch_info = axi_cfg + V31_AXI_CFG_LEN;
vfe31_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
vfe31_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
- vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out0.image_mode = 0x0000FFFF & (*ch_info++ >> 16);
vfe31_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
vfe31_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
- vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out1.image_mode = 0x0000FFFF & (*ch_info++ >> 16);
vfe31_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
vfe31_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
vfe31_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
@@ -999,6 +958,43 @@
}
msm_camera_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ switch (vfe31_ctrl->operation_mode) {
+ case VFE_OUTPUTS_PREVIEW:
+ case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
+ }
+ break;
+ default:
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
+ }
+ break;
+ }
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
vfe31_start_common();
@@ -1177,7 +1173,14 @@
{
struct vfe31_output_ch *outch = NULL;
struct msm_free_buf *b = NULL;
- vfe31_subdev_notify(id, path);
+ uint32_t image_mode = 0;
+
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ image_mode = vfe31_ctrl->outpath.out0.image_mode;
+ else
+ image_mode = vfe31_ctrl->outpath.out1.image_mode;
+
+ vfe31_subdev_notify(id, path, image_mode);
outch = vfe31_get_ch(path);
if (outch->free_buf.ch_paddr[0])
b = &outch->free_buf;
@@ -1187,7 +1190,14 @@
{
struct vfe31_output_ch *outch = NULL;
int rc = 0;
- vfe31_subdev_notify(id, path);
+ uint32_t image_mode = 0;
+
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ image_mode = vfe31_ctrl->outpath.out0.image_mode;
+ else
+ image_mode = vfe31_ctrl->outpath.out1.image_mode;
+
+ vfe31_subdev_notify(id, path, image_mode);
outch = vfe31_get_ch(path);
if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
/* Configure Preview Ping Pong */
@@ -2604,11 +2614,13 @@
}
}
static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
- uint32_t ch0_paddr, uint32_t ch1_paddr, uint32_t ch2_paddr)
+ uint32_t ch0_paddr, uint32_t ch1_paddr,
+ uint32_t ch2_paddr, uint32_t image_mode)
{
struct isp_msg_output msg;
msg.output_id = msgid;
+ msg.buf.image_mode = image_mode;
msg.buf.ch_paddr[0] = ch0_paddr;
msg.buf.ch_paddr[1] = ch1_paddr;
msg.buf.ch_paddr[2] = ch2_paddr;
@@ -2690,7 +2702,8 @@
vfe_send_outmsg(&vfe31_ctrl->subdev,
MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
- ch1_paddr, ch2_paddr);
+ ch1_paddr, ch2_paddr,
+ vfe31_ctrl->outpath.out0.image_mode);
if (vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED)
vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
@@ -2762,7 +2775,8 @@
vfe_send_outmsg(&vfe31_ctrl->subdev,
MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
- ch1_paddr, ch2_paddr);
+ ch1_paddr, ch2_paddr,
+ vfe31_ctrl->outpath.out1.image_mode);
} else {
vfe31_ctrl->outpath.out1.frame_drop_cnt++;
CDBG("path_irq_1 - no free buffer!\n");
@@ -3582,11 +3596,11 @@
break;
case CMD_AXI_START:
- axi_start();
+ /* No need to decouple AXI/VFE for VFE3.1*/
break;
case CMD_AXI_STOP:
- axi_stop();
+ /* No need to decouple AXI/VFE for VFE3.1*/
break;
default:
@@ -3830,7 +3844,10 @@
static int __devinit vfe31_probe(struct platform_device *pdev)
{
int rc = 0;
+ struct msm_cam_subdev_info sd_info;
+
CDBG("%s: device id = %d\n", __func__, pdev->id);
+
vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL);
if (!vfe31_ctrl) {
pr_err("%s: no enough memory\n", __func__);
@@ -3902,7 +3919,10 @@
disable_irq(vfe31_ctrl->vfeirq->start);
vfe31_ctrl->pdev = pdev;
- msm_cam_register_subdev_node(&vfe31_ctrl->subdev, VFE_DEV, 0);
+ sd_info.sdev_type = VFE_DEV;
+ sd_info.sd_index = 0;
+ sd_info.irq_num = vfe31_ctrl->vfeirq->start;
+ msm_cam_register_subdev_node(&vfe31_ctrl->subdev, &sd_info);
return 0;
vfe31_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
index e94f286..739d157 100644
--- a/drivers/media/video/msm/msm_vfe31_v4l2.h
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -695,7 +695,7 @@
struct vfe31_output_ch {
struct list_head free_buf_queue;
spinlock_t free_buf_lock;
- uint16_t output_fmt;
+ uint16_t image_mode;
int8_t ch0;
int8_t ch1;
int8_t ch2;
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index 98c1ca0..9382292 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -25,30 +25,30 @@
#include <media/msm_isp.h>
#include "msm.h"
+#include "msm_cam_server.h"
#include "msm_vfe32.h"
atomic_t irq_cnt;
#define VFE32_AXI_OFFSET 0x0050
-#define vfe32_get_ch_ping_addr(chn) \
- (msm_camera_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
-#define vfe32_get_ch_pong_addr(chn) \
- (msm_camera_io_r(vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
-#define vfe32_get_ch_addr(ping_pong, chn) \
- (((ping_pong) & (1 << (chn))) == 0 ? \
- vfe32_get_ch_pong_addr(chn) : vfe32_get_ch_ping_addr(chn))
+#define vfe32_get_ch_ping_addr(base, chn) \
+ (msm_camera_io_r((base) + 0x0050 + 0x18 * (chn)))
+#define vfe32_get_ch_pong_addr(base, chn) \
+ (msm_camera_io_r((base) + 0x0050 + 0x18 * (chn) + 4))
+#define vfe32_get_ch_addr(ping_pong, base, chn) \
+ ((((ping_pong) & (1 << (chn))) == 0) ? \
+ (vfe32_get_ch_pong_addr((base), chn)) : \
+ (vfe32_get_ch_ping_addr((base), chn)))
-#define vfe32_put_ch_ping_addr(chn, addr) \
- (msm_camera_io_w((addr), vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
-#define vfe32_put_ch_pong_addr(chn, addr) \
- (msm_camera_io_w((addr), \
- vfe32_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
-#define vfe32_put_ch_addr(ping_pong, chn, addr) \
+#define vfe32_put_ch_ping_addr(base, chn, addr) \
+ (msm_camera_io_w((addr), (base) + 0x0050 + 0x18 * (chn)))
+#define vfe32_put_ch_pong_addr(base, chn, addr) \
+ (msm_camera_io_w((addr), (base) + 0x0050 + 0x18 * (chn) + 4))
+#define vfe32_put_ch_addr(ping_pong, base, chn, addr) \
(((ping_pong) & (1 << (chn))) == 0 ? \
- vfe32_put_ch_pong_addr((chn), (addr)) : \
- vfe32_put_ch_ping_addr((chn), (addr)))
+ vfe32_put_ch_pong_addr((base), (chn), (addr)) : \
+ vfe32_put_ch_ping_addr((base), (chn), (addr)))
-static struct vfe32_ctrl_type *vfe32_ctrl;
static uint32_t vfe_clk_rate;
struct vfe32_isr_queue_cmd {
@@ -357,112 +357,124 @@
"DEMOSAICV3_UPDATE",
};
-static void vfe32_stop(void)
+static void vfe32_stop(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- atomic_set(&vfe32_ctrl->vstate, 0);
+ atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
/* for reset hw modules, and send msg when reset_irq comes.*/
- spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
- vfe32_ctrl->stop_ack_pending = TRUE;
- spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+ spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
+ vfe32_ctrl->share_ctrl->stop_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
/* disable all interrupts. */
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* clear all pending interrupts*/
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(1,
- vfe32_ctrl->vfebase + VFE_IRQ_CMD);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
/* in either continuous or snapshot mode, stop command can be issued
* at any time. stop camif immediately. */
msm_camera_io_w(CAMIF_COMMAND_STOP_IMMEDIATELY,
- vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
-
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
}
-static void vfe32_subdev_notify(int id, int path)
+static void vfe32_subdev_notify(int id, int path, int image_mode,
+ struct v4l2_subdev *sd, struct vfe_share_ctrl_t *share_ctrl)
{
struct msm_vfe_resp rp;
+ struct msm_frame_info frame_info;
unsigned long flags = 0;
- spin_lock_irqsave(&vfe32_ctrl->sd_notify_lock, flags);
+ spin_lock_irqsave(&share_ctrl->sd_notify_lock, flags);
CDBG("vfe32_subdev_notify : msgId = %d\n", id);
memset(&rp, 0, sizeof(struct msm_vfe_resp));
rp.evt_msg.type = MSM_CAMERA_MSG;
- rp.evt_msg.msg_id = path;
+ frame_info.image_mode = image_mode;
+ frame_info.path = path;
+ rp.evt_msg.data = &frame_info;
rp.type = id;
- v4l2_subdev_notify(&vfe32_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
- spin_unlock_irqrestore(&vfe32_ctrl->sd_notify_lock, flags);
+ v4l2_subdev_notify(sd, NOTIFY_VFE_BUF_EVT, &rp);
+ spin_unlock_irqrestore(&share_ctrl->sd_notify_lock, flags);
}
-static int vfe32_config_axi(int mode, uint32_t *ao)
+static int vfe32_config_axi(
+ struct axi_ctrl_t *axi_ctrl, int mode, uint32_t *ao)
{
uint32_t *ch_info;
uint32_t *axi_cfg = ao+V32_AXI_BUS_FMT_OFF;
/* Update the corresponding write masters for each output*/
ch_info = axi_cfg + V32_AXI_CFG_LEN;
- vfe32_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
- vfe32_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
- vfe32_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
- vfe32_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
- vfe32_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
- vfe32_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
- vfe32_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
- vfe32_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
- vfe32_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+ axi_ctrl->share_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out0.ch1 =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out0.image_mode =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out1.ch1 =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out1.image_mode =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+ axi_ctrl->share_ctrl->outpath.out2.ch1 =
+ 0x0000FFFF & (*ch_info++ >> 16);
+ axi_ctrl->share_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
switch (mode) {
case OUTPUT_PRIM:
- vfe32_ctrl->outpath.output_mode =
+ axi_ctrl->share_ctrl->outpath.output_mode =
VFE32_OUTPUT_MODE_PRIMARY;
break;
case OUTPUT_PRIM_ALL_CHNLS:
- vfe32_ctrl->outpath.output_mode =
+ axi_ctrl->share_ctrl->outpath.output_mode =
VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
break;
case OUTPUT_PRIM|OUTPUT_SEC:
- vfe32_ctrl->outpath.output_mode =
+ axi_ctrl->share_ctrl->outpath.output_mode =
VFE32_OUTPUT_MODE_PRIMARY;
- vfe32_ctrl->outpath.output_mode |=
+ axi_ctrl->share_ctrl->outpath.output_mode |=
VFE32_OUTPUT_MODE_SECONDARY;
break;
case OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS:
- vfe32_ctrl->outpath.output_mode =
+ axi_ctrl->share_ctrl->outpath.output_mode =
VFE32_OUTPUT_MODE_PRIMARY;
- vfe32_ctrl->outpath.output_mode |=
+ axi_ctrl->share_ctrl->outpath.output_mode |=
VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
break;
case OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC:
- vfe32_ctrl->outpath.output_mode =
+ axi_ctrl->share_ctrl->outpath.output_mode =
VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
- vfe32_ctrl->outpath.output_mode |=
+ axi_ctrl->share_ctrl->outpath.output_mode |=
VFE32_OUTPUT_MODE_SECONDARY;
break;
default:
pr_err("%s Invalid AXI mode %d ", __func__, mode);
return -EINVAL;
}
- msm_camera_io_w(*ao, vfe32_ctrl->vfebase +
+ msm_camera_io_w(*ao, axi_ctrl->share_ctrl->vfebase +
VFE_BUS_IO_FORMAT_CFG);
- msm_camera_io_memcpy(vfe32_ctrl->vfebase +
+ msm_camera_io_memcpy(axi_ctrl->share_ctrl->vfebase +
vfe32_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
vfe32_cmd[VFE_CMD_AXI_OUT_CFG].length - V32_AXI_CH_INF_LEN
- V32_AXI_BUS_FMT_LEN);
return 0;
}
-static void vfe32_reset_internal_variables(void)
+static void vfe32_reset_internal_variables(
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
vfe32_ctrl->vfeImaskCompositePacked = 0;
@@ -470,9 +482,9 @@
vfe32_ctrl->start_ack_pending = FALSE;
atomic_set(&irq_cnt, 0);
- spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
- vfe32_ctrl->stop_ack_pending = FALSE;
- spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+ spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
+ vfe32_ctrl->share_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
vfe32_ctrl->reset_ack_pending = FALSE;
@@ -481,17 +493,17 @@
spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
vfe32_ctrl->recording_state = VFE_STATE_IDLE;
- vfe32_ctrl->liveshot_state = VFE_STATE_IDLE;
+ vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
- atomic_set(&vfe32_ctrl->vstate, 0);
+ atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
/* 0 for continuous mode, 1 for snapshot mode */
- vfe32_ctrl->operation_mode = 0;
- vfe32_ctrl->outpath.output_mode = 0;
- vfe32_ctrl->vfe_capture_count = 0;
+ vfe32_ctrl->share_ctrl->operation_mode = 0;
+ vfe32_ctrl->share_ctrl->outpath.output_mode = 0;
+ vfe32_ctrl->share_ctrl->vfe_capture_count = 0;
/* this is unsigned 32 bit integer. */
- vfe32_ctrl->vfeFrameId = 0;
+ vfe32_ctrl->share_ctrl->vfeFrameId = 0;
/* Stats control variables. */
memset(&(vfe32_ctrl->afStatsControl), 0,
sizeof(struct vfe_stats_control));
@@ -516,30 +528,30 @@
vfe32_ctrl->snapshot_frame_cnt = 0;
}
-static void vfe32_reset(void)
+static void vfe32_reset(struct vfe32_ctrl_type *vfe32_ctrl)
{
- vfe32_reset_internal_variables();
+ vfe32_reset_internal_variables(vfe32_ctrl);
/* disable all interrupts. vfeImaskLocal is also reset to 0
* to begin with. */
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_DISABLE_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* clear all pending interrupts*/
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
msm_camera_io_w(VFE_CLEAR_ALL_IRQS,
- vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
/* Ensure the write order while writing
to the command register using the barrier */
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_IRQ_CMD);
+ msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
/* enable reset_ack interrupt. */
msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
* is done, hardware interrupt will be generated. VFE ist processes
@@ -549,409 +561,516 @@
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(VFE_RESET_UPON_RESET_CMD,
- vfe32_ctrl->vfebase + VFE_GLOBAL_RESET);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
}
-static int vfe32_operation_config(uint32_t *cmd)
+static int vfe32_operation_config(uint32_t *cmd,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t *p = cmd;
- vfe32_ctrl->operation_mode = *p;
- vfe32_ctrl->stats_comp = *(++p);
+ vfe32_ctrl->share_ctrl->operation_mode = *p;
+ vfe32_ctrl->share_ctrl->stats_comp = *(++p);
vfe32_ctrl->hfr_mode = *(++p);
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_CFG);
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_MODULE_CFG);
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_PIXEL_IF_CFG);
- if (msm_camera_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CFG);
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_PIXEL_IF_CFG);
+ if (msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+ V32_GET_HW_VERSION_OFF) ==
VFE33_HW_NUMBER) {
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_RDI0_CFG);
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_RDI1_CFG);
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_RDI0_CFG);
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_RDI1_CFG);
} else {
++p;
++p;
}
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_REALIGN_BUF);
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_CHROMA_UP);
- msm_camera_io_w(*(++p), vfe32_ctrl->vfebase + VFE_STATS_CFG);
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REALIGN_BUF);
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CHROMA_UP);
+ msm_camera_io_w(*(++p),
+ vfe32_ctrl->share_ctrl->vfebase + VFE_STATS_CFG);
return 0;
}
-static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_awb_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
uint32_t *ptr = in->statsBuf;
uint32_t addr;
addr = ptr[0];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AWB_WR_PING_ADDR);
addr = ptr[1];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AWB_WR_PONG_ADDR);
vfe32_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_aec_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
uint32_t *ptr = in->statsBuf;
uint32_t addr;
addr = ptr[0];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PING_ADDR);
addr = ptr[1];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AEC_WR_PONG_ADDR);
vfe32_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_af_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
uint32_t *ptr = in->statsBuf;
uint32_t addr;
addr = ptr[0];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AF_WR_PING_ADDR);
addr = ptr[1];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_AF_WR_PONG_ADDR);
vfe32_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_ihist_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
uint32_t *ptr = in->statsBuf;
uint32_t addr;
addr = ptr[0];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_WR_PING_ADDR);
addr = ptr[1];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_HIST_WR_PONG_ADDR);
vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_rs_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
uint32_t *ptr = in->statsBuf;
uint32_t addr;
addr = ptr[0];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_RS_WR_PING_ADDR);
addr = ptr[1];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_RS_WR_PONG_ADDR);
vfe32_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+static uint32_t vfe_stats_cs_buf_init(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_buf *in)
{
uint32_t *ptr = in->statsBuf;
uint32_t addr;
addr = ptr[0];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_CS_WR_PING_ADDR);
addr = ptr[1];
msm_camera_io_w(addr,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_BUS_STATS_CS_WR_PONG_ADDR);
vfe32_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
return 0;
}
-static void vfe32_start_common(void)
+static void vfe32_start_common(struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t irq_mask = 0x00E00021;
vfe32_ctrl->start_ack_pending = TRUE;
CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
- vfe32_ctrl->operation_mode, vfe32_ctrl->outpath.output_mode);
- if (vfe32_ctrl->stats_comp)
+ vfe32_ctrl->share_ctrl->operation_mode,
+ vfe32_ctrl->share_ctrl->outpath.output_mode);
+ if (vfe32_ctrl->share_ctrl->stats_comp)
irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
else
irq_mask |= 0x000FE000;
- msm_camera_io_w(irq_mask, vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_camera_io_w(irq_mask,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* Ensure the write order while writing
to the command register using the barrier */
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ msm_camera_io_w_mb(1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
-
- atomic_set(&vfe32_ctrl->vstate, 1);
+ atomic_set(&vfe32_ctrl->share_ctrl->vstate, 1);
}
-static int vfe32_start_recording(struct msm_cam_media_controller *pmctl)
+static int vfe32_start_recording(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_VIDEO);
vfe32_ctrl->recording_state = VFE_STATE_START_REQUESTED;
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
return 0;
}
-static int vfe32_stop_recording(struct msm_cam_media_controller *pmctl)
+static int vfe32_stop_recording(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
vfe32_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
return 0;
}
-static void vfe32_start_liveshot(struct msm_cam_media_controller *pmctl)
+static void vfe32_start_liveshot(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
/* Hardcode 1 live snapshot for now. */
- vfe32_ctrl->outpath.out0.capture_cnt = 1;
- vfe32_ctrl->vfe_capture_count = vfe32_ctrl->outpath.out0.capture_cnt;
+ vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt = 1;
+ vfe32_ctrl->share_ctrl->vfe_capture_count =
+ vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt;
- vfe32_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
+ msm_camera_io_w_mb(1, vfe32_ctrl->
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
}
-static int vfe32_zsl(struct msm_cam_media_controller *pmctl)
+static int vfe32_zsl(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t irq_comp_mask = 0;
/* capture command is valid for both idle and active state. */
irq_comp_mask =
- msm_camera_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_r(vfe32_ctrl->
+ share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
CDBG("%s:op mode %d O/P Mode %d\n", __func__,
- vfe32_ctrl->operation_mode, vfe32_ctrl->outpath.output_mode);
+ vfe32_ctrl->share_ctrl->operation_mode,
+ vfe32_ctrl->share_ctrl->outpath.output_mode);
- if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PRIMARY) {
- irq_comp_mask |= ((0x1 << (vfe32_ctrl->outpath.out0.ch0)) |
- (0x1 << (vfe32_ctrl->outpath.out0.ch1)));
- } else if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (
+ (0x1 << (vfe32_ctrl->share_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe32_ctrl->share_ctrl->outpath.out0.ch1)));
+ } else if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
- irq_comp_mask |= ((0x1 << (vfe32_ctrl->outpath.out0.ch0)) |
- (0x1 << (vfe32_ctrl->outpath.out0.ch1)) |
- (0x1 << (vfe32_ctrl->outpath.out0.ch2)));
+ irq_comp_mask |= (
+ (0x1 << (vfe32_ctrl->share_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe32_ctrl->share_ctrl->outpath.out0.ch1)) |
+ (0x1 << (vfe32_ctrl->share_ctrl->outpath.out0.ch2)));
}
- if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_SECONDARY) {
- irq_comp_mask |= ((0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8)) |
- (0x1 << (vfe32_ctrl->outpath.out1.ch1 + 8)));
- } else if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= ((0x1 << (vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1 + 8)));
+ } else if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
- irq_comp_mask |= ((0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8)) |
- (0x1 << (vfe32_ctrl->outpath.out1.ch1 + 8)) |
- (0x1 << (vfe32_ctrl->outpath.out1.ch2 + 8)));
+ irq_comp_mask |= (
+ (0x1 << (vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1 + 8)) |
+ (0x1 << (vfe32_ctrl->
+ share_ctrl->outpath.out1.ch2 + 8)));
}
- if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- } else if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch2]);
}
- if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
- } else if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY) {
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ } else if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch2]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch2]);
}
- msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
- vfe32_start_common();
+ msm_camera_io_w(irq_comp_mask,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ vfe32_start_common(vfe32_ctrl);
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_ZSL);
- msm_camera_io_w(1, vfe32_ctrl->vfebase + 0x18C);
- msm_camera_io_w(1, vfe32_ctrl->vfebase + 0x188);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x188);
return 0;
}
static int vfe32_capture_raw(
struct msm_cam_media_controller *pmctl,
+ struct vfe32_ctrl_type *vfe32_ctrl,
uint32_t num_frames_capture)
{
uint32_t irq_comp_mask = 0;
- vfe32_ctrl->outpath.out0.capture_cnt = num_frames_capture;
- vfe32_ctrl->vfe_capture_count = num_frames_capture;
+ vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt = num_frames_capture;
+ vfe32_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
irq_comp_mask =
- msm_camera_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
- if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PRIMARY) {
- irq_comp_mask |= (0x1 << (vfe32_ctrl->outpath.out0.ch0));
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |=
+ (0x1 << (vfe32_ctrl->share_ctrl->outpath.out0.ch0));
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
}
- msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_w(irq_comp_mask,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
- vfe32_start_common();
+ vfe32_start_common(vfe32_ctrl);
return 0;
}
static int vfe32_capture(
struct msm_cam_media_controller *pmctl,
- uint32_t num_frames_capture)
+ uint32_t num_frames_capture,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t irq_comp_mask = 0;
/* capture command is valid for both idle and active state. */
- vfe32_ctrl->outpath.out1.capture_cnt = num_frames_capture;
- if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) {
- vfe32_ctrl->outpath.out0.capture_cnt =
+ vfe32_ctrl->share_ctrl->outpath.out1.capture_cnt = num_frames_capture;
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG) {
+ vfe32_ctrl->share_ctrl->outpath.out0.capture_cnt =
num_frames_capture;
}
- vfe32_ctrl->vfe_capture_count = num_frames_capture;
+ vfe32_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
irq_comp_mask = msm_camera_io_r(
- vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
- if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
- if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN) {
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
- irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 |
- 0x1 << vfe32_ctrl->outpath.out0.ch1);
+ irq_comp_mask |= (0x1 << vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1);
}
- if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY) {
irq_comp_mask |=
- (0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8) |
- 0x1 << (vfe32_ctrl->outpath.out1.ch1 + 8));
+ (0x1 << (vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1 + 8));
}
- if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1]);
}
- if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1]);
}
}
- vfe32_ctrl->vfe_capture_count = num_frames_capture;
+ vfe32_ctrl->share_ctrl->vfe_capture_count = num_frames_capture;
- msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
- msm_camera_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_w(irq_comp_mask,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
- vfe32_start_common();
+ vfe32_start_common(vfe32_ctrl);
/* for debug */
- msm_camera_io_w(1, vfe32_ctrl->vfebase + 0x18C);
- msm_camera_io_w(1, vfe32_ctrl->vfebase + 0x188);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x18C);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase + 0x188);
return 0;
}
-static int vfe32_start(struct msm_cam_media_controller *pmctl)
+static int vfe32_start(
+ struct msm_cam_media_controller *pmctl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t irq_comp_mask = 0;
irq_comp_mask =
- msm_camera_io_r(vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+ VFE_IRQ_COMP_MASK);
- if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_PRIMARY) {
- irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 |
- 0x1 << vfe32_ctrl->outpath.out0.ch1);
- } else if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (
+ 0x1 << vfe32_ctrl->share_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe32_ctrl->share_ctrl->outpath.out0.ch1);
+ } else if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
- irq_comp_mask |= (0x1 << vfe32_ctrl->outpath.out0.ch0 |
- 0x1 << vfe32_ctrl->outpath.out0.ch1 |
- 0x1 << vfe32_ctrl->outpath.out0.ch2);
+ irq_comp_mask |= (
+ 0x1 << vfe32_ctrl->share_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe32_ctrl->share_ctrl->outpath.out0.ch1 |
+ 0x1 << vfe32_ctrl->share_ctrl->outpath.out0.ch2);
}
- if (vfe32_ctrl->outpath.output_mode & VFE32_OUTPUT_MODE_SECONDARY) {
- irq_comp_mask |= (0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8) |
- 0x1 << (vfe32_ctrl->outpath.out1.ch1 + 8));
- } else if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
+ VFE32_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= (
+ 0x1 << (vfe32_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe32_ctrl->share_ctrl->outpath.out1.ch1 + 8));
+ } else if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
- irq_comp_mask |= (0x1 << (vfe32_ctrl->outpath.out1.ch0 + 8) |
- 0x1 << (vfe32_ctrl->outpath.out1.ch1 + 8) |
- 0x1 << (vfe32_ctrl->outpath.out1.ch2 + 8));
+ irq_comp_mask |= (
+ 0x1 << (vfe32_ctrl->share_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe32_ctrl->share_ctrl->outpath.out1.ch1 + 8) |
+ 0x1 << (vfe32_ctrl->share_ctrl->outpath.out1.ch2 + 8));
}
- msm_camera_io_w(irq_comp_mask, vfe32_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camera_io_w(irq_comp_mask,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_IRQ_COMP_MASK);
msm_camio_bus_scale_cfg(
pmctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
- vfe32_start_common();
+ vfe32_start_common(vfe32_ctrl);
return 0;
}
-static void vfe32_update(void)
+static void vfe32_update(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
uint32_t value = 0;
if (vfe32_ctrl->update_linear) {
if (!msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1))
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF1))
msm_camera_io_w(1,
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF1);
else
msm_camera_io_w(0,
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF1);
vfe32_ctrl->update_linear = false;
}
if (vfe32_ctrl->update_rolloff) {
- value = msm_camera_io_r(vfe32_ctrl->vfebase +
+ value = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
V33_PCA_ROLL_OFF_CFG_OFF1);
value ^= V33_PCA_ROLL_OFF_LUT_BANK_SEL_MASK;
- msm_camera_io_w(value, vfe32_ctrl->vfebase +
+ msm_camera_io_w(value, vfe32_ctrl->share_ctrl->vfebase +
V33_PCA_ROLL_OFF_CFG_OFF1);
vfe32_ctrl->update_rolloff = false;
}
if (vfe32_ctrl->update_la) {
- if (!msm_camera_io_r(vfe32_ctrl->vfebase + V32_LA_OFF))
+ if (!msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + V32_LA_OFF))
msm_camera_io_w(1,
- vfe32_ctrl->vfebase + V32_LA_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_LA_OFF);
else
msm_camera_io_w(0,
- vfe32_ctrl->vfebase + V32_LA_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_LA_OFF);
vfe32_ctrl->update_la = false;
}
if (vfe32_ctrl->update_gamma) {
- value = msm_camera_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF);
+ value = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + V32_RGB_G_OFF);
value ^= V32_GAMMA_LUT_BANK_SEL_MASK;
- msm_camera_io_w(value, vfe32_ctrl->vfebase + V32_RGB_G_OFF);
+ msm_camera_io_w(value,
+ vfe32_ctrl->share_ctrl->vfebase + V32_RGB_G_OFF);
vfe32_ctrl->update_gamma = false;
}
@@ -960,11 +1079,12 @@
spin_unlock_irqrestore(&vfe32_ctrl->update_ack_lock, flags);
/* Ensure the write order while writing
to the command register using the barrier */
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
return;
}
-static void vfe32_sync_timer_stop(void)
+static void vfe32_sync_timer_stop(struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t value = 0;
vfe32_ctrl->sync_timer_state = 0;
@@ -976,10 +1096,13 @@
value = 0x40000;
/* Timer Stop */
- msm_camera_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF);
+ msm_camera_io_w(value,
+ vfe32_ctrl->share_ctrl->vfebase + V32_SYNC_TIMER_OFF);
}
-static void vfe32_sync_timer_start(const uint32_t *tbl)
+static void vfe32_sync_timer_start(
+ const uint32_t *tbl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
/* set bit 8 for auto increment. */
uint32_t value = 1;
@@ -1001,14 +1124,17 @@
}
/* Timer Start */
- msm_camera_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF);
+ msm_camera_io_w(value,
+ vfe32_ctrl->share_ctrl->vfebase + V32_SYNC_TIMER_OFF);
/* Sync Timer Line Start */
value = *tbl++;
- msm_camera_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF +
+ msm_camera_io_w(value,
+ vfe32_ctrl->share_ctrl->vfebase + V32_SYNC_TIMER_OFF +
4 + ((vfe32_ctrl->sync_timer_number) * 12));
/* Sync Timer Pixel Start */
value = *tbl++;
- msm_camera_io_w(value, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF +
+ msm_camera_io_w(value,
+ vfe32_ctrl->share_ctrl->vfebase + V32_SYNC_TIMER_OFF +
8 + ((vfe32_ctrl->sync_timer_number) * 12));
/* Sync Timer Pixel Duration */
value = *tbl++;
@@ -1016,87 +1142,99 @@
val = 10000000 / val;
val = value * 10000 / val;
CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
- msm_camera_io_w(val, vfe32_ctrl->vfebase + V32_SYNC_TIMER_OFF +
+ msm_camera_io_w(val,
+ vfe32_ctrl->share_ctrl->vfebase + V32_SYNC_TIMER_OFF +
12 + ((vfe32_ctrl->sync_timer_number) * 12));
/* Timer0 Active High/LOW */
value = *tbl++;
msm_camera_io_w(value,
- vfe32_ctrl->vfebase + V32_SYNC_TIMER_POLARITY_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_SYNC_TIMER_POLARITY_OFF);
/* Selects sync timer 0 output to drive onto timer1 port */
value = 0;
- msm_camera_io_w(value, vfe32_ctrl->vfebase + V32_TIMER_SELECT_OFF);
+ msm_camera_io_w(value,
+ vfe32_ctrl->share_ctrl->vfebase + V32_TIMER_SELECT_OFF);
}
-static void vfe32_program_dmi_cfg(enum VFE32_DMI_RAM_SEL bankSel)
+static void vfe32_program_dmi_cfg(
+ enum VFE32_DMI_RAM_SEL bankSel,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
/* set bit 8 for auto increment. */
uint32_t value = VFE_DMI_CFG_DEFAULT;
value += (uint32_t)bankSel;
CDBG("%s: banksel = %d\n", __func__, bankSel);
- msm_camera_io_w(value, vfe32_ctrl->vfebase + VFE_DMI_CFG);
+ msm_camera_io_w(value, vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_CFG);
/* by default, always starts with offset 0.*/
- msm_camera_io_w(0, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
}
-static void vfe32_write_gamma_cfg(enum VFE32_DMI_RAM_SEL channel_sel,
- const uint32_t *tbl)
+static void vfe32_write_gamma_cfg(
+ enum VFE32_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
int i;
uint32_t value, value1, value2;
- vfe32_program_dmi_cfg(channel_sel);
+ vfe32_program_dmi_cfg(channel_sel, vfe32_ctrl);
for (i = 0 ; i < (VFE32_GAMMA_NUM_ENTRIES/2) ; i++) {
value = *tbl++;
value1 = value & 0x0000FFFF;
value2 = (value & 0xFFFF0000)>>16;
msm_camera_io_w((value1),
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
msm_camera_io_w((value2),
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
}
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
}
-static void vfe32_read_gamma_cfg(enum VFE32_DMI_RAM_SEL channel_sel,
- uint32_t *tbl)
+static void vfe32_read_gamma_cfg(
+ enum VFE32_DMI_RAM_SEL channel_sel,
+ uint32_t *tbl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
int i;
- vfe32_program_dmi_cfg(channel_sel);
+ vfe32_program_dmi_cfg(channel_sel, vfe32_ctrl);
CDBG("%s: Gamma table channel: %d\n", __func__, channel_sel);
for (i = 0 ; i < VFE32_GAMMA_NUM_ENTRIES ; i++) {
- *tbl = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ *tbl = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
CDBG("%s: %08x\n", __func__, *tbl);
tbl++;
}
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
}
-static void vfe32_write_la_cfg(enum VFE32_DMI_RAM_SEL channel_sel,
- const uint32_t *tbl)
+static void vfe32_write_la_cfg(
+ enum VFE32_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t i;
uint32_t value, value1, value2;
- vfe32_program_dmi_cfg(channel_sel);
+ vfe32_program_dmi_cfg(channel_sel, vfe32_ctrl);
for (i = 0 ; i < (VFE32_LA_TABLE_LENGTH/2) ; i++) {
value = *tbl++;
value1 = value & 0x0000FFFF;
value2 = (value & 0xFFFF0000)>>16;
msm_camera_io_w((value1),
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
msm_camera_io_w((value2),
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
}
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
}
-static struct vfe32_output_ch *vfe32_get_ch(int path)
+static struct vfe32_output_ch *vfe32_get_ch(
+ int path, struct vfe_share_ctrl_t *share_ctrl)
{
struct vfe32_output_ch *ch = NULL;
if (path == VFE_MSG_OUTPUT_PRIMARY)
- ch = &vfe32_ctrl->outpath.out0;
+ ch = &share_ctrl->outpath.out0;
else if (path == VFE_MSG_OUTPUT_SECONDARY)
- ch = &vfe32_ctrl->outpath.out1;
+ ch = &share_ctrl->outpath.out1;
else
pr_err("%s: Invalid path %d\n", __func__,
path);
@@ -1104,44 +1242,67 @@
BUG_ON(ch == NULL);
return ch;
}
-static struct msm_free_buf *vfe32_check_free_buffer(int id, int path)
+static struct msm_free_buf *vfe32_check_free_buffer(
+ int id, int path, struct axi_ctrl_t *axi_ctrl)
{
struct vfe32_output_ch *outch = NULL;
struct msm_free_buf *b = NULL;
- vfe32_subdev_notify(id, path);
- outch = vfe32_get_ch(path);
+ uint32_t image_mode = 0;
+
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ image_mode = axi_ctrl->share_ctrl->outpath.out0.image_mode;
+ else
+ image_mode = axi_ctrl->share_ctrl->outpath.out1.image_mode;
+
+ vfe32_subdev_notify(id, path, image_mode,
+ &axi_ctrl->subdev, axi_ctrl->share_ctrl);
+ outch = vfe32_get_ch(path, axi_ctrl->share_ctrl);
if (outch->free_buf.ch_paddr[0])
b = &outch->free_buf;
return b;
}
-static int vfe32_configure_pingpong_buffers(int id, int path)
+static int vfe32_configure_pingpong_buffers(
+ int id, int path, struct vfe32_ctrl_type *vfe32_ctrl)
{
struct vfe32_output_ch *outch = NULL;
int rc = 0;
- vfe32_subdev_notify(id, path);
- outch = vfe32_get_ch(path);
+ uint32_t image_mode = 0;
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ image_mode = vfe32_ctrl->share_ctrl->outpath.out0.image_mode;
+ else
+ image_mode = vfe32_ctrl->share_ctrl->outpath.out1.image_mode;
+
+ vfe32_subdev_notify(id, path, image_mode,
+ &vfe32_ctrl->subdev, vfe32_ctrl->share_ctrl);
+ outch = vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
/* Configure Preview Ping Pong */
pr_info("%s Configure ping/pong address for %d",
__func__, path);
- vfe32_put_ch_ping_addr(outch->ch0,
+ vfe32_put_ch_ping_addr(
+ vfe32_ctrl->share_ctrl->vfebase, outch->ch0,
outch->ping.ch_paddr[0]);
- vfe32_put_ch_pong_addr(outch->ch0,
+ vfe32_put_ch_pong_addr(
+ vfe32_ctrl->share_ctrl->vfebase, outch->ch0,
outch->pong.ch_paddr[0]);
- if (vfe32_ctrl->operation_mode !=
+ if (vfe32_ctrl->share_ctrl->operation_mode !=
VFE_OUTPUTS_RAW) {
- vfe32_put_ch_ping_addr(outch->ch1,
+ vfe32_put_ch_ping_addr(
+ vfe32_ctrl->share_ctrl->vfebase, outch->ch1,
outch->ping.ch_paddr[1]);
- vfe32_put_ch_pong_addr(outch->ch1,
+ vfe32_put_ch_pong_addr(
+ vfe32_ctrl->share_ctrl->vfebase, outch->ch1,
outch->pong.ch_paddr[1]);
}
if (outch->ping.num_planes > 2)
- vfe32_put_ch_ping_addr(outch->ch2,
+ vfe32_put_ch_ping_addr(
+ vfe32_ctrl->share_ctrl->vfebase, outch->ch2,
outch->ping.ch_paddr[2]);
if (outch->pong.num_planes > 2)
- vfe32_put_ch_pong_addr(outch->ch2,
+ vfe32_put_ch_pong_addr(
+ vfe32_ctrl->share_ctrl->vfebase, outch->ch2,
outch->pong.ch_paddr[2]);
/* avoid stale info */
@@ -1154,37 +1315,41 @@
return rc;
}
-static void vfe32_write_linear_cfg(enum VFE32_DMI_RAM_SEL channel_sel,
- const uint32_t *tbl)
+static void vfe32_write_linear_cfg(
+ enum VFE32_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl, struct vfe32_ctrl_type *vfe32_ctrl)
{
uint32_t i;
- vfe32_program_dmi_cfg(channel_sel);
+ vfe32_program_dmi_cfg(channel_sel, vfe32_ctrl);
/* for loop for configuring LUT. */
for (i = 0 ; i < VFE32_LINEARIZATON_TABLE_LENGTH ; i++) {
- msm_camera_io_w(*tbl, vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ msm_camera_io_w(*tbl,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
tbl++;
}
CDBG("done writing to linearization table\n");
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
}
static void vfe32_send_isp_msg(
- struct vfe32_ctrl_type *vctrl,
+ struct v4l2_subdev *sd,
+ uint32_t vfeFrameId,
uint32_t isp_msg_id)
{
struct isp_msg_event isp_msg_evt;
isp_msg_evt.msg_id = isp_msg_id;
- isp_msg_evt.sof_count = vfe32_ctrl->vfeFrameId;
- v4l2_subdev_notify(&vctrl->subdev,
+ isp_msg_evt.sof_count = vfeFrameId;
+ v4l2_subdev_notify(sd,
NOTIFY_ISP_MSG_EVT,
(void *)&isp_msg_evt);
}
static int vfe32_proc_general(
struct msm_cam_media_controller *pmctl,
- struct msm_isp_cmd *cmd)
+ struct msm_isp_cmd *cmd,
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
int i , rc = 0;
uint32_t old_val = 0 , new_val = 0;
@@ -1199,32 +1364,34 @@
case VFE_CMD_RESET:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- vfe32_reset();
+ vfe32_reset(vfe32_ctrl);
break;
case VFE_CMD_START:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- if ((vfe32_ctrl->operation_mode ==
+ if ((vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
- (vfe32_ctrl->operation_mode ==
+ (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_PREVIEW))
/* Configure primary channel */
rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_V32_START, VFE_MSG_OUTPUT_PRIMARY);
+ VFE_MSG_V32_START, VFE_MSG_OUTPUT_PRIMARY,
+ vfe32_ctrl);
else
/* Configure secondary channel */
rc = vfe32_configure_pingpong_buffers(
- VFE_MSG_V32_START, VFE_MSG_OUTPUT_SECONDARY);
+ VFE_MSG_V32_START, VFE_MSG_OUTPUT_SECONDARY,
+ vfe32_ctrl);
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
" for preview", __func__);
rc = -EINVAL;
goto proc_general_done;
}
- rc = vfe32_start(pmctl);
+ rc = vfe32_start(pmctl, vfe32_ctrl);
break;
case VFE_CMD_UPDATE:
- vfe32_update();
+ vfe32_update(vfe32_ctrl);
break;
case VFE_CMD_CAPTURE_RAW:
pr_info("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
@@ -1233,15 +1400,16 @@
rc = -EFAULT;
goto proc_general_done;
}
- rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_CAPTURE,
- VFE_MSG_OUTPUT_PRIMARY);
+ rc = vfe32_configure_pingpong_buffers(
+ VFE_MSG_V32_CAPTURE, VFE_MSG_OUTPUT_PRIMARY,
+ vfe32_ctrl);
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
" for snapshot", __func__);
rc = -EINVAL;
goto proc_general_done;
}
- rc = vfe32_capture_raw(pmctl, snapshot_cnt);
+ rc = vfe32_capture_raw(pmctl, vfe32_ctrl, snapshot_cnt);
break;
case VFE_CMD_CAPTURE:
if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
@@ -1250,8 +1418,10 @@
goto proc_general_done;
}
- if (vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) {
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG) {
if (snapshot_cnt != 1) {
pr_err("only support 1 inline snapshot\n");
rc = -EINVAL;
@@ -1260,12 +1430,14 @@
/* Configure primary channel for JPEG */
rc = vfe32_configure_pingpong_buffers(
VFE_MSG_V32_JPEG_CAPTURE,
- VFE_MSG_OUTPUT_PRIMARY);
+ VFE_MSG_OUTPUT_PRIMARY,
+ vfe32_ctrl);
} else {
/* Configure primary channel */
rc = vfe32_configure_pingpong_buffers(
VFE_MSG_V32_CAPTURE,
- VFE_MSG_OUTPUT_PRIMARY);
+ VFE_MSG_OUTPUT_PRIMARY,
+ vfe32_ctrl);
}
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
@@ -1274,41 +1446,44 @@
goto proc_general_done;
}
/* Configure secondary channel */
- rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_CAPTURE,
- VFE_MSG_OUTPUT_SECONDARY);
+ rc = vfe32_configure_pingpong_buffers(
+ VFE_MSG_V32_CAPTURE, VFE_MSG_OUTPUT_SECONDARY,
+ vfe32_ctrl);
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
" for secondary output", __func__);
rc = -EINVAL;
goto proc_general_done;
}
- rc = vfe32_capture(pmctl, snapshot_cnt);
+ rc = vfe32_capture(pmctl, snapshot_cnt, vfe32_ctrl);
break;
case VFE_CMD_START_RECORDING:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- if (vfe32_ctrl->operation_mode ==
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_PREVIEW_AND_VIDEO)
rc = vfe32_configure_pingpong_buffers(
VFE_MSG_V32_START_RECORDING,
- VFE_MSG_OUTPUT_SECONDARY);
- else if (vfe32_ctrl->operation_mode ==
+ VFE_MSG_OUTPUT_SECONDARY,
+ vfe32_ctrl);
+ else if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_VIDEO_AND_PREVIEW)
rc = vfe32_configure_pingpong_buffers(
VFE_MSG_V32_START_RECORDING,
- VFE_MSG_OUTPUT_PRIMARY);
+ VFE_MSG_OUTPUT_PRIMARY,
+ vfe32_ctrl);
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
" for video", __func__);
rc = -EINVAL;
goto proc_general_done;
}
- rc = vfe32_start_recording(pmctl);
+ rc = vfe32_start_recording(pmctl, vfe32_ctrl);
break;
case VFE_CMD_STOP_RECORDING:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- rc = vfe32_stop_recording(pmctl);
+ rc = vfe32_stop_recording(pmctl, vfe32_ctrl);
break;
case VFE_CMD_OPERATION_CFG: {
if (cmd->length != V32_OPERATION_CFG_LEN) {
@@ -1322,7 +1497,7 @@
rc = -EFAULT;
goto proc_general_done;
}
- rc = vfe32_operation_config(cmdp);
+ rc = vfe32_operation_config(cmdp, vfe32_ctrl);
}
break;
@@ -1338,12 +1513,14 @@
rc = -EFAULT;
goto proc_general_done;
}
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val |= AE_BG_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1359,12 +1536,14 @@
rc = -EFAULT;
goto proc_general_done;
}
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
+ VFE_MODULE_CFG);
old_val |= AF_BF_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1380,12 +1559,14 @@
rc = -EFAULT;
goto proc_general_done;
}
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val |= AWB_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1402,12 +1583,14 @@
rc = -EFAULT;
goto proc_general_done;
}
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val |= IHIST_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1426,7 +1609,8 @@
goto proc_general_done;
}
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1444,7 +1628,8 @@
goto proc_general_done;
}
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1454,7 +1639,7 @@
cmdp = kmalloc(cmd->length, GFP_ATOMIC);
/* Incrementing with 4 so as to point to the 2nd Register as
the 2nd register has the mce_enable bit */
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase +
+ old_val = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
V32_CHROMA_SUP_OFF + 4);
if (!cmdp) {
rc = -ENOMEM;
@@ -1471,21 +1656,22 @@
old_val &= MCE_EN_MASK;
new_val = new_val | old_val;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 4,
- &new_val, 4);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_CHROMA_SUP_OFF + 4, &new_val, 4);
cmdp_local += 1;
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase +
+ old_val = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
V32_CHROMA_SUP_OFF + 8);
new_val = *cmdp_local;
old_val &= MCE_Q_K_MASK;
new_val = new_val | old_val;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 8,
- &new_val, 4);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_CHROMA_SUP_OFF + 8, &new_val, 4);
cmdp_local += 1;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp_local, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1503,31 +1689,31 @@
goto proc_general_done;
}
cmdp_local = cmdp;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF,
- cmdp_local, 4);
+ msm_camera_io_memcpy(vfe32_ctrl->share_ctrl->vfebase +
+ V32_CHROMA_SUP_OFF, cmdp_local, 4);
cmdp_local += 1;
new_val = *cmdp_local;
/* Incrementing with 4 so as to point to the 2nd Register as
* the 2nd register has the mce_enable bit
*/
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase +
+ old_val = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
V32_CHROMA_SUP_OFF + 4);
old_val &= ~MCE_EN_MASK;
new_val = new_val | old_val;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 4,
- &new_val, 4);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_CHROMA_SUP_OFF + 4, &new_val, 4);
cmdp_local += 1;
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase +
+ old_val = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
V32_CHROMA_SUP_OFF + 8);
new_val = *cmdp_local;
old_val &= ~MCE_Q_K_MASK;
new_val = new_val | old_val;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_CHROMA_SUP_OFF + 8,
- &new_val, 4);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_CHROMA_SUP_OFF + 8, &new_val, 4);
}
break;
case VFE_CMD_BLACK_LEVEL_CFG:
@@ -1547,27 +1733,28 @@
}
cmdp_local = cmdp;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp_local, 16);
cmdp_local += 4;
- vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe32_ctrl);
/* for loop for extrcting init table. */
for (i = 0; i < (V32_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); i++) {
msm_camera_io_w(*cmdp_local ,
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
cmdp_local++;
}
CDBG("done writing init table\n");
/* by default, always starts with offset 0. */
msm_camera_io_w(V32_MESH_ROLL_OFF_DELTA_TABLE_OFFSET,
- vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
/* for loop for extracting delta table. */
for (i = 0; i < (V32_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); i++) {
msm_camera_io_w(*cmdp_local,
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_DATA_LO);
cmdp_local++;
}
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
}
break;
@@ -1584,27 +1771,29 @@
goto proc_general_done;
}
cmdp_local = cmdp;
- vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe32_ctrl);
CDBG("%s: Mesh Rolloff init Table\n", __func__);
for (i = 0; i < (V32_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); i++) {
*cmdp_local =
msm_camera_io_r(
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
CDBG("%s: %08x\n", __func__, *cmdp_local);
cmdp_local++;
}
msm_camera_io_w(V32_MESH_ROLL_OFF_DELTA_TABLE_OFFSET,
- vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
CDBG("%s: Mesh Rolloff Delta Table\n", __func__);
for (i = 0; i < (V32_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); i++) {
*cmdp_local =
msm_camera_io_r(
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
CDBG("%s: %08x\n", __func__, *cmdp_local);
cmdp_local++;
}
CDBG("done reading delta table\n");
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
if (copy_to_user((void __user *)(cmd->value), cmdp,
temp1)) {
rc = -EFAULT;
@@ -1626,11 +1815,13 @@
}
cmdp_local = cmdp;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp_local, (vfe32_cmd[cmd->id].length));
cmdp_local += 1;
- vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, cmdp_local);
+ vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+ cmdp_local, vfe32_ctrl);
break;
case VFE_CMD_LA_UPDATE: {
@@ -1648,13 +1839,14 @@
}
cmdp_local = cmdp + 1;
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + V32_LA_OFF);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + V32_LA_OFF);
if (old_val != 0x0)
vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
- cmdp_local);
+ cmdp_local, vfe32_ctrl);
else
vfe32_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
- cmdp_local);
+ cmdp_local, vfe32_ctrl);
}
vfe32_ctrl->update_la = true;
break;
@@ -1671,19 +1863,24 @@
goto proc_general_done;
}
cmdp_local = cmdp;
- if (msm_camera_io_r(vfe32_ctrl->vfebase + V32_LA_OFF))
- vfe32_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1);
+ if (msm_camera_io_r(vfe32_ctrl->
+ share_ctrl->vfebase + V32_LA_OFF))
+ vfe32_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+ vfe32_ctrl);
else
- vfe32_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0);
+ vfe32_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+ vfe32_ctrl);
for (i = 0 ; i < (VFE32_LA_TABLE_LENGTH / 2) ; i++) {
*cmdp_local =
msm_camera_io_r(
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
- *cmdp_local |= (msm_camera_io_r(vfe32_ctrl->vfebase +
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
+ *cmdp_local |= (msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase +
VFE_DMI_DATA_LO)) << 16;
cmdp_local++;
}
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
if (copy_to_user((void __user *)(cmd->value), cmdp,
temp1)) {
rc = -EFAULT;
@@ -1703,22 +1900,23 @@
rc = -EFAULT;
goto proc_general_done;
}
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_SCE_OFF,
- cmdp, V32_SCE_LEN);
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_SCE_OFF,
+ cmdp, V32_SCE_LEN);
}
break;
case VFE_CMD_LIVESHOT:
/* Configure primary channel */
rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_CAPTURE,
- VFE_MSG_OUTPUT_PRIMARY);
+ VFE_MSG_OUTPUT_PRIMARY, vfe32_ctrl);
if (rc < 0) {
pr_err("%s error configuring pingpong buffers"
" for primary output", __func__);
rc = -EINVAL;
goto proc_general_done;
}
- vfe32_start_liveshot(pmctl);
+ vfe32_start_liveshot(pmctl, vfe32_ctrl);
break;
case VFE_CMD_LINEARIZATION_CFG:
@@ -1734,15 +1932,18 @@
}
cmdp_local = cmdp;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1,
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF1,
cmdp_local, V32_LINEARIZATION_LEN1);
cmdp_local += 4;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF2,
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF2,
cmdp_local, V32_LINEARIZATION_LEN2);
cmdp_local = cmdp + 17;
- vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK0, cmdp_local);
+ vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK0,
+ cmdp_local, vfe32_ctrl);
break;
case VFE_CMD_LINEARIZATION_UPDATE:
@@ -1759,21 +1960,26 @@
cmdp_local = cmdp;
cmdp_local++;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1 + 4,
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF1 + 4,
cmdp_local, (V32_LINEARIZATION_LEN1 - 4));
cmdp_local += 3;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF2,
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF2,
cmdp_local, V32_LINEARIZATION_LEN2);
cmdp_local = cmdp + 17;
/*extracting the bank select*/
old_val = msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF1);
if (old_val != 0x0)
- vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK0, cmdp_local);
+ vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK0,
+ cmdp_local, vfe32_ctrl);
else
- vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK1, cmdp_local);
+ vfe32_write_linear_cfg(BLACK_LUT_RAM_BANK1,
+ cmdp_local, vfe32_ctrl);
vfe32_ctrl->update_linear = true;
break;
@@ -1790,18 +1996,20 @@
}
cmdp_local = cmdp;
if (msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_LINEARIZATION_OFF1))
- vfe32_program_dmi_cfg(BLACK_LUT_RAM_BANK1);
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_LINEARIZATION_OFF1))
+ vfe32_program_dmi_cfg(BLACK_LUT_RAM_BANK1, vfe32_ctrl);
else
- vfe32_program_dmi_cfg(BLACK_LUT_RAM_BANK0);
+ vfe32_program_dmi_cfg(BLACK_LUT_RAM_BANK0, vfe32_ctrl);
CDBG("%s: Linearization Table\n", __func__);
for (i = 0 ; i < VFE32_LINEARIZATON_TABLE_LENGTH ; i++) {
*cmdp_local = msm_camera_io_r(
- vfe32_ctrl->vfebase + VFE_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_DMI_DATA_LO);
CDBG("%s: %08x\n", __func__, *cmdp_local);
cmdp_local++;
}
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
if (copy_to_user((void __user *)(cmd->value), cmdp,
temp1)) {
rc = -EFAULT;
@@ -1829,15 +2037,17 @@
new_val = *cmdp_local;
old_val = msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
old_val &= DEMOSAIC_MASK;
new_val = new_val | old_val;
*cmdp_local = new_val;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
cmdp_local, V32_DEMOSAICV3_0_LEN);
cmdp_local += 1;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_1_OFF,
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_1_OFF,
cmdp_local, V32_DEMOSAICV3_1_LEN);
break;
@@ -1862,22 +2072,25 @@
new_val = *cmdp_local;
old_val = msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
old_val &= DEMOSAIC_MASK;
new_val = new_val | old_val;
*cmdp_local = new_val;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
cmdp_local, V32_DEMOSAICV3_0_LEN);
/* As the address space is not contiguous increment by 2
* before copying to next address space */
cmdp_local += 1;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_1_OFF,
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_1_OFF,
cmdp_local, 2 * V32_DEMOSAICV3_0_LEN);
/* As the address space is not contiguous increment by 2
* before copying to next address space */
cmdp_local += 2;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_2_OFF,
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_2_OFF,
cmdp_local, 2 * V32_DEMOSAICV3_0_LEN);
break;
@@ -1902,17 +2115,19 @@
new_val = *cmdp_local;
old_val = msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
old_val &= ABF_MASK;
new_val = new_val | old_val;
*cmdp_local = new_val;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
- cmdp_local, 4);
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
+ cmdp_local, 4);
cmdp_local += 1;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp_local, (vfe32_cmd[cmd->id].length));
}
break;
@@ -1934,16 +2149,18 @@
new_val = *cmdp_local;
old_val = msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
old_val &= DBCC_MASK;
new_val = new_val | old_val;
*cmdp_local = new_val;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
- cmdp_local, 4);
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF,
+ cmdp_local, 4);
cmdp_local += 1;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp_local, (vfe32_cmd[cmd->id].length));
break;
@@ -1964,28 +2181,28 @@
new_val = *cmdp_local;
old_val = msm_camera_io_r(
- vfe32_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
+ vfe32_ctrl->share_ctrl->vfebase + V32_DEMOSAICV3_0_OFF);
old_val &= DBPC_MASK;
new_val = new_val | old_val;
*cmdp_local = new_val;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase +
+ msm_camera_io_memcpy(vfe32_ctrl->share_ctrl->vfebase +
V32_DEMOSAICV3_0_OFF,
cmdp_local, V32_DEMOSAICV3_LEN);
cmdp_local += 1;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase +
+ msm_camera_io_memcpy(vfe32_ctrl->share_ctrl->vfebase +
V32_DEMOSAICV3_DBPC_CFG_OFF,
cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
cmdp_local += 1;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase +
+ msm_camera_io_memcpy(vfe32_ctrl->share_ctrl->vfebase +
V32_DEMOSAICV3_DBPC_CFG_OFF0,
cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
cmdp_local += 1;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase +
+ msm_camera_io_memcpy(vfe32_ctrl->share_ctrl->vfebase +
V32_DEMOSAICV3_DBPC_CFG_OFF1,
cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
cmdp_local += 1;
- msm_camera_io_memcpy(vfe32_ctrl->vfebase +
+ msm_camera_io_memcpy(vfe32_ctrl->share_ctrl->vfebase +
V32_DEMOSAICV3_DBPC_CFG_OFF2,
cmdp_local, V32_DEMOSAICV3_DBPC_LEN);
break;
@@ -2002,13 +2219,14 @@
rc = -EFAULT;
goto proc_general_done;
}
- msm_camera_io_memcpy(vfe32_ctrl->vfebase + V32_RGB_G_OFF,
+ msm_camera_io_memcpy(
+ vfe32_ctrl->share_ctrl->vfebase + V32_RGB_G_OFF,
cmdp, 4);
cmdp += 1;
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
+ vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp, vfe32_ctrl);
+ vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp, vfe32_ctrl);
+ vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp, vfe32_ctrl);
}
cmdp -= 1;
break;
@@ -2025,16 +2243,23 @@
goto proc_general_done;
}
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + V32_RGB_G_OFF);
cmdp += 1;
if (old_val != 0x0) {
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
+ vfe32_write_gamma_cfg(
+ RGBLUT_RAM_CH0_BANK0, cmdp, vfe32_ctrl);
+ vfe32_write_gamma_cfg(
+ RGBLUT_RAM_CH1_BANK0, cmdp, vfe32_ctrl);
+ vfe32_write_gamma_cfg(
+ RGBLUT_RAM_CH2_BANK0, cmdp, vfe32_ctrl);
} else {
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1, cmdp);
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1, cmdp);
- vfe32_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1, cmdp);
+ vfe32_write_gamma_cfg(
+ RGBLUT_RAM_CH0_BANK1, cmdp, vfe32_ctrl);
+ vfe32_write_gamma_cfg(
+ RGBLUT_RAM_CH1_BANK1, cmdp, vfe32_ctrl);
+ vfe32_write_gamma_cfg(
+ RGBLUT_RAM_CH2_BANK1, cmdp, vfe32_ctrl);
}
}
vfe32_ctrl->update_gamma = TRUE;
@@ -2054,12 +2279,14 @@
}
cmdp_local = cmdp;
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + V32_RGB_G_OFF);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + V32_RGB_G_OFF);
temp2 = old_val ? RGBLUT_RAM_CH0_BANK1 :
RGBLUT_RAM_CH0_BANK0;
for (i = 0; i < 3; i++) {
vfe32_read_gamma_cfg(temp2,
- cmdp_local + (VFE32_GAMMA_NUM_ENTRIES * i));
+ cmdp_local + (VFE32_GAMMA_NUM_ENTRIES * i),
+ vfe32_ctrl);
temp2 += 2;
}
if (copy_to_user((void __user *)(cmd->value), cmdp,
@@ -2070,54 +2297,60 @@
break;
case VFE_CMD_STATS_AWB_STOP: {
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~AWB_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
case VFE_CMD_STATS_AE_STOP: {
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~AE_BG_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
case VFE_CMD_STATS_AF_STOP: {
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~AF_BF_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
case VFE_CMD_STATS_IHIST_STOP: {
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~IHIST_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
case VFE_CMD_STATS_RS_STOP: {
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~RS_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
case VFE_CMD_STATS_CS_STOP: {
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= ~CS_ENABLE_MASK;
msm_camera_io_w(old_val,
- vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
}
break;
case VFE_CMD_STOP:
pr_info("vfe32_proc_general: cmdID = %s\n",
vfe32_general_cmd[cmd->id]);
- vfe32_stop();
+ vfe32_stop(vfe32_ctrl);
break;
case VFE_CMD_SYNC_TIMER_SETTING:
@@ -2131,7 +2364,7 @@
rc = -EFAULT;
goto proc_general_done;
}
- vfe32_sync_timer_start(cmdp);
+ vfe32_sync_timer_start(cmdp, vfe32_ctrl);
break;
case VFE_CMD_MODULE_CFG: {
@@ -2147,27 +2380,29 @@
goto proc_general_done;
}
*cmdp &= ~STATS_ENABLE_MASK;
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_MODULE_CFG);
old_val &= STATS_ENABLE_MASK;
*cmdp |= old_val;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
}
break;
case VFE_CMD_ZSL:
rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_START,
- VFE_MSG_OUTPUT_PRIMARY);
+ VFE_MSG_OUTPUT_PRIMARY, vfe32_ctrl);
if (rc < 0)
goto proc_general_done;
rc = vfe32_configure_pingpong_buffers(VFE_MSG_V32_START,
- VFE_MSG_OUTPUT_SECONDARY);
+ VFE_MSG_OUTPUT_SECONDARY, vfe32_ctrl);
if (rc < 0)
goto proc_general_done;
- rc = vfe32_zsl(pmctl);
+ rc = vfe32_zsl(pmctl, vfe32_ctrl);
break;
case VFE_CMD_ASF_CFG:
@@ -2183,11 +2418,13 @@
goto proc_general_done;
}
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
cmdp_local = cmdp + V32_ASF_LEN/4;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V32_ASF_SPECIAL_EFX_CFG_OFF,
+ vfe32_ctrl->share_ctrl->vfebase +
+ V32_ASF_SPECIAL_EFX_CFG_OFF,
cmdp_local, V32_ASF_SPECIAL_EFX_CFG_LEN);
break;
@@ -2209,37 +2446,44 @@
cmdp_local++;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V33_PCA_ROLL_OFF_CFG_OFF1,
+ vfe32_ctrl->share_ctrl->vfebase +
+ V33_PCA_ROLL_OFF_CFG_OFF1,
cmdp_local, V33_PCA_ROLL_OFF_CFG_LEN1);
cmdp_local += 4;
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + V33_PCA_ROLL_OFF_CFG_OFF2,
+ vfe32_ctrl->share_ctrl->vfebase +
+ V33_PCA_ROLL_OFF_CFG_OFF2,
cmdp_local, V33_PCA_ROLL_OFF_CFG_LEN2);
cmdp_local += 3;
CDBG("%s: start writing RollOff Ram0 table\n", __func__);
- vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0);
- msm_camera_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe32_ctrl);
+ msm_camera_io_w(temp1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
msm_camera_io_w(*(cmdp_local + 1),
- vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE33_DMI_DATA_HI);
msm_camera_io_w(*cmdp_local,
- vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE33_DMI_DATA_LO);
cmdp_local += 2;
}
CDBG("%s: end writing RollOff Ram0 table\n", __func__);
CDBG("%s: start writing RollOff Ram1 table\n", __func__);
- vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0);
- msm_camera_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0, vfe32_ctrl);
+ msm_camera_io_w(temp1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
msm_camera_io_w(*cmdp_local,
- vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE33_DMI_DATA_LO);
cmdp_local += 2;
}
CDBG("%s: end writing RollOff Ram1 table\n", __func__);
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
break;
case VFE_CMD_PCA_ROLL_OFF_UPDATE:
@@ -2259,41 +2503,46 @@
temp1 = *cmdp_local;
cmdp_local += 8;
- temp2 = msm_camera_io_r(vfe32_ctrl->vfebase +
+ temp2 = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
V33_PCA_ROLL_OFF_CFG_OFF1)
& V33_PCA_ROLL_OFF_LUT_BANK_SEL_MASK;
CDBG("%s: start writing RollOff Ram0 table\n", __func__);
if (temp2)
- vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe32_ctrl);
else
- vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK1);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK1, vfe32_ctrl);
- msm_camera_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+ msm_camera_io_w(temp1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
msm_camera_io_w(*(cmdp_local + 1),
- vfe32_ctrl->vfebase + VFE33_DMI_DATA_HI);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE33_DMI_DATA_HI);
msm_camera_io_w(*cmdp_local,
- vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE33_DMI_DATA_LO);
cmdp_local += 2;
}
CDBG("%s: end writing RollOff Ram0 table\n", __func__);
CDBG("%s: start writing RollOff Ram1 table\n", __func__);
if (temp2)
- vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0, vfe32_ctrl);
else
- vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK1);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK1, vfe32_ctrl);
- msm_camera_io_w(temp1, vfe32_ctrl->vfebase + VFE_DMI_ADDR);
+ msm_camera_io_w(temp1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DMI_ADDR);
for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE ; i++) {
msm_camera_io_w(*cmdp_local,
- vfe32_ctrl->vfebase + VFE33_DMI_DATA_LO);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE33_DMI_DATA_LO);
cmdp_local += 2;
}
CDBG("%s: end writing RollOff Ram1 table\n", __func__);
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
vfe32_ctrl->update_rolloff = true;
break;
case VFE_CMD_GET_PCA_ROLLOFF_TABLE:
@@ -2308,33 +2557,37 @@
goto proc_general_done;
}
cmdp_local = cmdp;
- old_val = msm_camera_io_r(vfe32_ctrl->vfebase +
+ old_val = msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
V33_PCA_ROLL_OFF_CFG_OFF1) &
V33_PCA_ROLL_OFF_LUT_BANK_SEL_MASK;
if (old_val)
- vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK1);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK1, vfe32_ctrl);
else
- vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM0_BANK0, vfe32_ctrl);
CDBG("%s: PCA Rolloff Ram0\n", __func__);
for (i = 0 ; i < V33_PCA_ROLL_OFF_TABLE_SIZE * 2; i++) {
temp2 = (i == (V33_PCA_ROLL_OFF_TABLE_SIZE));
if (old_val && temp2)
- vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK1);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK1,
+ vfe32_ctrl);
else if (!old_val && temp2)
- vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0);
+ vfe32_program_dmi_cfg(ROLLOFF_RAM1_BANK0,
+ vfe32_ctrl);
- *cmdp_local = msm_camera_io_r(vfe32_ctrl->vfebase +
+ *cmdp_local = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase +
VFE33_DMI_DATA_LO);
*(cmdp_local + 1) =
- msm_camera_io_r(vfe32_ctrl->vfebase +
+ msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase +
VFE33_DMI_DATA_HI);
CDBG("%s: %08x%08x\n", __func__,
*(cmdp_local + 1), *cmdp_local);
cmdp_local += 2;
}
- vfe32_program_dmi_cfg(NO_MEM_SELECTED);
+ vfe32_program_dmi_cfg(NO_MEM_SELECTED, vfe32_ctrl);
if (copy_to_user((void __user *)(cmd->value), cmdp,
temp1)) {
rc = -EFAULT;
@@ -2352,7 +2605,7 @@
goto proc_general_done;
}
*cmdp = msm_camera_io_r(
- vfe32_ctrl->vfebase+V32_GET_HW_VERSION_OFF);
+ vfe32_ctrl->share_ctrl->vfebase+V32_GET_HW_VERSION_OFF);
if (copy_to_user((void __user *)(cmd->value), cmdp,
V32_GET_HW_VERSION_LEN)) {
rc = -EFAULT;
@@ -2360,7 +2613,8 @@
}
break;
case VFE_CMD_GET_REG_DUMP:
- temp1 = sizeof(uint32_t) * vfe32_ctrl->register_total;
+ temp1 = sizeof(uint32_t) *
+ vfe32_ctrl->share_ctrl->register_total;
if (cmd->length != temp1) {
rc = -EINVAL;
goto proc_general_done;
@@ -2370,11 +2624,12 @@
rc = -ENOMEM;
goto proc_general_done;
}
- msm_camera_io_dump(
- vfe32_ctrl->vfebase, vfe32_ctrl->register_total*4);
+ msm_camera_io_dump(vfe32_ctrl->share_ctrl->vfebase,
+ vfe32_ctrl->share_ctrl->register_total*4);
CDBG("%s: %p %p %d\n", __func__, (void *)cmdp,
- vfe32_ctrl->vfebase, temp1);
- memcpy_fromio((void *)cmdp, vfe32_ctrl->vfebase, temp1);
+ vfe32_ctrl->share_ctrl->vfebase, temp1);
+ memcpy_fromio((void *)cmdp,
+ vfe32_ctrl->share_ctrl->vfebase, temp1);
if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) {
rc = -EFAULT;
goto proc_general_done;
@@ -2399,7 +2654,8 @@
}
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
vfe32_ctrl->frame_skip_cnt = ((uint32_t)
*cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
@@ -2423,7 +2679,8 @@
goto proc_general_done;
}
msm_camera_io_memcpy(
- vfe32_ctrl->vfebase + vfe32_cmd[cmd->id].offset,
+ vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_cmd[cmd->id].offset,
cmdp, (vfe32_cmd[cmd->id].length));
break;
@@ -2435,10 +2692,11 @@
return rc;
}
-static void vfe32_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
+static void vfe32_stats_af_ack(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
{
unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->stats_comp ?
+ spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
&vfe32_ctrl->comp_stats_ack_lock :
&vfe32_ctrl->af_ack_lock);
spin_lock_irqsave(lock, flags);
@@ -2447,10 +2705,11 @@
spin_unlock_irqrestore(lock, flags);
}
-static void vfe32_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
+static void vfe32_stats_awb_ack(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
{
unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->stats_comp ?
+ spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
&vfe32_ctrl->comp_stats_ack_lock :
&vfe32_ctrl->awb_ack_lock);
spin_lock_irqsave(lock, flags);
@@ -2459,10 +2718,11 @@
spin_unlock_irqrestore(lock, flags);
}
-static void vfe32_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
+static void vfe32_stats_aec_ack(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
{
unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->stats_comp ?
+ spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
&vfe32_ctrl->comp_stats_ack_lock :
&vfe32_ctrl->aec_ack_lock);
spin_lock_irqsave(lock, flags);
@@ -2471,10 +2731,11 @@
spin_unlock_irqrestore(lock, flags);
}
-static void vfe32_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
+static void vfe32_stats_ihist_ack(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
{
unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->stats_comp ?
+ spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
&vfe32_ctrl->comp_stats_ack_lock :
&vfe32_ctrl->ihist_ack_lock);
spin_lock_irqsave(lock, flags);
@@ -2482,10 +2743,11 @@
vfe32_ctrl->ihistStatsControl.ackPending = FALSE;
spin_unlock_irqrestore(lock, flags);
}
-static void vfe32_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
+static void vfe32_stats_rs_ack(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
{
unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->stats_comp ?
+ spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
&vfe32_ctrl->comp_stats_ack_lock :
&vfe32_ctrl->rs_ack_lock);
spin_lock_irqsave(lock, flags);
@@ -2493,10 +2755,11 @@
vfe32_ctrl->rsStatsControl.ackPending = FALSE;
spin_unlock_irqrestore(lock, flags);
}
-static void vfe32_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
+static void vfe32_stats_cs_ack(
+ struct vfe32_ctrl_type *vfe32_ctrl, struct vfe_cmd_stats_ack *pAck)
{
unsigned long flags;
- spinlock_t *lock = (vfe32_ctrl->stats_comp ?
+ spinlock_t *lock = (vfe32_ctrl->share_ctrl->stats_comp ?
&vfe32_ctrl->comp_stats_ack_lock :
&vfe32_ctrl->cs_ack_lock);
spin_lock_irqsave(lock, flags);
@@ -2505,73 +2768,85 @@
spin_unlock_irqrestore(lock, flags);
}
-static inline void vfe32_read_irq_status(struct vfe32_irq_status *out)
+static inline void vfe32_read_irq_status(
+ struct axi_ctrl_t *axi_ctrl, struct vfe32_irq_status *out)
{
uint32_t *temp;
memset(out, 0, sizeof(struct vfe32_irq_status));
- temp = (uint32_t *)(vfe32_ctrl->vfebase + VFE_IRQ_STATUS_0);
+ temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_0);
out->vfeIrqStatus0 = msm_camera_io_r(temp);
- temp = (uint32_t *)(vfe32_ctrl->vfebase + VFE_IRQ_STATUS_1);
+ temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_IRQ_STATUS_1);
out->vfeIrqStatus1 = msm_camera_io_r(temp);
- temp = (uint32_t *)(vfe32_ctrl->vfebase + VFE_CAMIF_STATUS);
+ temp = (uint32_t *)(axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
out->camifStatus = msm_camera_io_r(temp);
CDBG("camifStatus = 0x%x\n", out->camifStatus);
/* clear the pending interrupt of the same kind.*/
msm_camera_io_w(out->vfeIrqStatus0,
- vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_0);
msm_camera_io_w(out->vfeIrqStatus1,
- vfe32_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CLEAR_1);
/* Ensure the write order while writing
to the command register using the barrier */
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_IRQ_CMD);
+ msm_camera_io_w_mb(1, axi_ctrl->share_ctrl->vfebase + VFE_IRQ_CMD);
}
-static void vfe32_process_reg_update_irq(void)
+static void vfe32_process_reg_update_irq(
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
if (vfe32_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
- if (vfe32_ctrl->operation_mode ==
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- } else if (vfe32_ctrl->operation_mode ==
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1]);
}
vfe32_ctrl->recording_state = VFE_STATE_STARTED;
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w_mb(1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
CDBG("start video triggered .\n");
} else if (vfe32_ctrl->recording_state ==
VFE_STATE_STOP_REQUESTED) {
- if (vfe32_ctrl->operation_mode ==
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- } else if (vfe32_ctrl->operation_mode ==
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out1.ch1]);
}
CDBG("stop video triggered .\n");
}
if (vfe32_ctrl->start_ack_pending == TRUE) {
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_START_ACK);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_START_ACK);
vfe32_ctrl->start_ack_pending = FALSE;
} else {
if (vfe32_ctrl->recording_state ==
@@ -2581,10 +2856,12 @@
* when we process the next reg update irq.
*/
msm_camera_io_w_mb(1,
- vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
} else if (vfe32_ctrl->recording_state ==
VFE_STATE_STOPPED) {
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_STOP_REC_ACK);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_STOP_REC_ACK);
vfe32_ctrl->recording_state = VFE_STATE_IDLE;
}
spin_lock_irqsave(&vfe32_ctrl->update_ack_lock, flags);
@@ -2592,80 +2869,102 @@
vfe32_ctrl->update_ack_pending = FALSE;
spin_unlock_irqrestore(
&vfe32_ctrl->update_ack_lock, flags);
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_UPDATE_ACK);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_UPDATE_ACK);
} else {
spin_unlock_irqrestore(
&vfe32_ctrl->update_ack_lock, flags);
}
}
- if (vfe32_ctrl->liveshot_state == VFE_STATE_START_REQUESTED) {
+ if (vfe32_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_START_REQUESTED) {
pr_info("%s enabling liveshot output\n", __func__);
- if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- vfe32_ctrl->liveshot_state = VFE_STATE_STARTED;
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ vfe32_ctrl->share_ctrl->liveshot_state =
+ VFE_STATE_STARTED;
}
}
- if (vfe32_ctrl->liveshot_state == VFE_STATE_STARTED) {
- vfe32_ctrl->vfe_capture_count--;
- if (!vfe32_ctrl->vfe_capture_count)
- vfe32_ctrl->liveshot_state = VFE_STATE_STOP_REQUESTED;
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
- } else if (vfe32_ctrl->liveshot_state == VFE_STATE_STOP_REQUESTED) {
+ if (vfe32_ctrl->share_ctrl->liveshot_state == VFE_STATE_STARTED) {
+ vfe32_ctrl->share_ctrl->vfe_capture_count--;
+ if (!vfe32_ctrl->share_ctrl->vfe_capture_count)
+ vfe32_ctrl->share_ctrl->liveshot_state =
+ VFE_STATE_STOP_REQUESTED;
+ msm_camera_io_w_mb(1, vfe32_ctrl->
+ share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } else if (vfe32_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOP_REQUESTED) {
CDBG("%s: disabling liveshot output\n", __func__);
- if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- vfe32_ctrl->liveshot_state = VFE_STATE_STOPPED;
- msm_camera_io_w_mb(1, vfe32_ctrl->vfebase +
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[vfe32_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ vfe32_ctrl->share_ctrl->liveshot_state =
+ VFE_STATE_STOPPED;
+ msm_camera_io_w_mb(1, vfe32_ctrl->share_ctrl->vfebase +
VFE_REG_UPDATE_CMD);
}
- } else if (vfe32_ctrl->liveshot_state == VFE_STATE_STOPPED) {
- vfe32_ctrl->liveshot_state = VFE_STATE_IDLE;
+ } else if (vfe32_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOPPED) {
+ vfe32_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
}
- if ((vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) ||
- (vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB) ||
- (vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) ||
- (vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB)) {
+ if ((vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN) ||
+ (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB) ||
+ (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG) ||
+ (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB)) {
/* in snapshot mode */
/* later we need to add check for live snapshot mode. */
if (vfe32_ctrl->frame_skip_pattern & (0x1 <<
(vfe32_ctrl->snapshot_frame_cnt %
vfe32_ctrl->frame_skip_cnt))) {
- vfe32_ctrl->vfe_capture_count--;
+ vfe32_ctrl->share_ctrl->vfe_capture_count--;
/* if last frame to be captured: */
- if (vfe32_ctrl->vfe_capture_count == 0) {
+ if (vfe32_ctrl->share_ctrl->vfe_capture_count == 0) {
/* stop the bus output:write master enable = 0*/
- if (vfe32_ctrl->outpath.output_mode &
- VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode
+ & VFE32_OUTPUT_MODE_PRIMARY) {
+ msm_camera_io_w(0,
+ vfe32_ctrl->share_ctrl->vfebase+
vfe32_AXI_WM_CFG[vfe32_ctrl->
- outpath.out0.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(0,
+ vfe32_ctrl->share_ctrl->vfebase+
vfe32_AXI_WM_CFG[vfe32_ctrl->
- outpath.out0.ch1]);
+ share_ctrl->outpath.out0.ch1]);
}
- if (vfe32_ctrl->outpath.output_mode &
+ if (vfe32_ctrl->share_ctrl->outpath.output_mode&
VFE32_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
+ msm_camera_io_w(0,
+ vfe32_ctrl->share_ctrl->vfebase+
vfe32_AXI_WM_CFG[vfe32_ctrl->
- outpath.out1.ch0]);
- msm_camera_io_w(0, vfe32_ctrl->vfebase +
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(0,
+ vfe32_ctrl->share_ctrl->vfebase+
vfe32_AXI_WM_CFG[vfe32_ctrl->
- outpath.out1.ch1]);
+ share_ctrl->outpath.out1.ch1]);
}
msm_camera_io_w_mb
(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
- vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
vfe32_ctrl->snapshot_frame_cnt = -1;
vfe32_ctrl->frame_skip_cnt = 31;
vfe32_ctrl->frame_skip_pattern = 0xffffffff;
@@ -2673,116 +2972,143 @@
} /*if frame is not being dropped*/
vfe32_ctrl->snapshot_frame_cnt++;
/* then do reg_update. */
- msm_camera_io_w(1, vfe32_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camera_io_w(1,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_REG_UPDATE_CMD);
} /* if snapshot mode. */
}
-static void vfe32_set_default_reg_values(void)
+static void vfe32_set_default_reg_values(
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
- msm_camera_io_w(0x800080, vfe32_ctrl->vfebase + VFE_DEMUX_GAIN_0);
- msm_camera_io_w(0x800080, vfe32_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+ msm_camera_io_w(0x800080,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+ msm_camera_io_w(0x800080,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_DEMUX_GAIN_1);
/* What value should we program CGC_OVERRIDE to? */
- msm_camera_io_w(0xFFFFF, vfe32_ctrl->vfebase + VFE_CGC_OVERRIDE);
+ msm_camera_io_w(0xFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CGC_OVERRIDE);
/* default frame drop period and pattern */
- msm_camera_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
- msm_camera_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
- msm_camera_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
- msm_camera_io_w(0x1f, vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
+ msm_camera_io_w(0x1f,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
msm_camera_io_w(0xFFFFFFFF,
- vfe32_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
- msm_camera_io_w(0, vfe32_ctrl->vfebase + VFE_CLAMP_MIN);
- msm_camera_io_w(0xFFFFFF, vfe32_ctrl->vfebase + VFE_CLAMP_MAX);
+ vfe32_ctrl->share_ctrl->vfebase +
+ VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+ msm_camera_io_w(0, vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MIN);
+ msm_camera_io_w(0xFFFFFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CLAMP_MAX);
/* stats UB config */
msm_camera_io_w(0x3980007,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
msm_camera_io_w(0x3A00007,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
msm_camera_io_w(0x3A8000F,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
msm_camera_io_w(0x3B80007,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
msm_camera_io_w(0x3C0001F,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
msm_camera_io_w(0x3E0001F,
- vfe32_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
}
-static void vfe32_process_reset_irq(void)
+static void vfe32_process_reset_irq(
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
- atomic_set(&vfe32_ctrl->vstate, 0);
+ atomic_set(&vfe32_ctrl->share_ctrl->vstate, 0);
- spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
- if (vfe32_ctrl->stop_ack_pending) {
- vfe32_ctrl->stop_ack_pending = FALSE;
- spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_STOP_ACK);
+ spin_lock_irqsave(&vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
+ if (vfe32_ctrl->share_ctrl->stop_ack_pending) {
+ vfe32_ctrl->share_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_STOP_ACK);
} else {
- spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+ spin_unlock_irqrestore(
+ &vfe32_ctrl->share_ctrl->stop_flag_lock, flags);
/* this is from reset command. */
- vfe32_set_default_reg_values();
+ vfe32_set_default_reg_values(vfe32_ctrl);
/* reload all write masters. (frame & line)*/
- msm_camera_io_w(0x7FFF, vfe32_ctrl->vfebase + VFE_BUS_CMD);
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_RESET_ACK);
+ msm_camera_io_w(0x7FFF,
+ vfe32_ctrl->share_ctrl->vfebase + VFE_BUS_CMD);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_RESET_ACK);
}
}
-static void vfe32_process_camif_sof_irq(void)
+static void vfe32_process_camif_sof_irq(
+ struct vfe32_ctrl_type *vfe32_ctrl)
{
- if (vfe32_ctrl->operation_mode ==
+ if (vfe32_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_RAW) {
if (vfe32_ctrl->start_ack_pending) {
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_START_ACK);
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
+ MSG_ID_START_ACK);
vfe32_ctrl->start_ack_pending = FALSE;
}
- vfe32_ctrl->vfe_capture_count--;
+ vfe32_ctrl->share_ctrl->vfe_capture_count--;
/* if last frame to be captured: */
- if (vfe32_ctrl->vfe_capture_count == 0) {
+ if (vfe32_ctrl->share_ctrl->vfe_capture_count == 0) {
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
- vfe32_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ vfe32_ctrl->share_ctrl->vfebase + VFE_CAMIF_COMMAND);
}
} /* if raw snapshot mode. */
if ((vfe32_ctrl->hfr_mode != HFR_MODE_OFF) &&
- (vfe32_ctrl->operation_mode == VFE_MODE_OF_OPERATION_VIDEO) &&
- (vfe32_ctrl->vfeFrameId % vfe32_ctrl->hfr_mode != 0)) {
- vfe32_ctrl->vfeFrameId++;
+ (vfe32_ctrl->share_ctrl->operation_mode ==
+ VFE_MODE_OF_OPERATION_VIDEO) &&
+ (vfe32_ctrl->share_ctrl->vfeFrameId %
+ vfe32_ctrl->hfr_mode != 0)) {
+ vfe32_ctrl->share_ctrl->vfeFrameId++;
CDBG("Skip the SOF notification when HFR enabled\n");
return;
}
- vfe32_ctrl->vfeFrameId++;
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_SOF_ACK);
- CDBG("camif_sof_irq, frameId = %d\n", vfe32_ctrl->vfeFrameId);
+ vfe32_ctrl->share_ctrl->vfeFrameId++;
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId, MSG_ID_SOF_ACK);
+ CDBG("camif_sof_irq, frameId = %d\n",
+ vfe32_ctrl->share_ctrl->vfeFrameId);
if (vfe32_ctrl->sync_timer_state) {
if (vfe32_ctrl->sync_timer_repeat_count == 0)
- vfe32_sync_timer_stop();
+ vfe32_sync_timer_stop(vfe32_ctrl);
else
vfe32_ctrl->sync_timer_repeat_count--;
}
}
-static void vfe32_process_error_irq(uint32_t errStatus)
+static void vfe32_process_error_irq(
+ struct axi_ctrl_t *axi_ctrl, uint32_t errStatus)
{
uint32_t reg_value;
if (errStatus & VFE32_IMASK_CAMIF_ERROR) {
pr_err("vfe32_irq: camif errors\n");
reg_value = msm_camera_io_r(
- vfe32_ctrl->vfebase + VFE_CAMIF_STATUS);
+ axi_ctrl->share_ctrl->vfebase + VFE_CAMIF_STATUS);
pr_err("camifStatus = 0x%x\n", reg_value);
- vfe32_send_isp_msg(vfe32_ctrl, MSG_ID_CAMIF_ERROR);
+ vfe32_send_isp_msg(&axi_ctrl->subdev,
+ axi_ctrl->share_ctrl->vfeFrameId, MSG_ID_CAMIF_ERROR);
}
if (errStatus & VFE32_IMASK_BHIST_OVWR)
@@ -2806,7 +3132,7 @@
if (errStatus & VFE32_IMASK_VIOLATION) {
pr_err("vfe32_irq: violation interrupt\n");
reg_value = msm_camera_io_r(
- vfe32_ctrl->vfebase + VFE_VIOLATION_STATUS);
+ axi_ctrl->share_ctrl->vfebase + VFE_VIOLATION_STATUS);
pr_err("%s: violationStatus = 0x%x\n", __func__, reg_value);
}
@@ -2856,24 +3182,28 @@
pr_err("vfe32_irq: axi error\n");
}
-static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
- uint32_t ch0_paddr, uint32_t ch1_paddr, uint32_t ch2_paddr)
+static void vfe_send_outmsg(
+ struct axi_ctrl_t *axi_ctrl, uint8_t msgid,
+ uint32_t ch0_paddr, uint32_t ch1_paddr,
+ uint32_t ch2_paddr, uint32_t image_mode)
{
struct isp_msg_output msg;
msg.output_id = msgid;
+ msg.buf.image_mode = image_mode;
msg.buf.ch_paddr[0] = ch0_paddr;
msg.buf.ch_paddr[1] = ch1_paddr;
msg.buf.ch_paddr[2] = ch2_paddr;
- msg.frameCounter = vfe32_ctrl->vfeFrameId;
+ msg.frameCounter = axi_ctrl->share_ctrl->vfeFrameId;
- v4l2_subdev_notify(&vfe32_ctrl->subdev,
+ v4l2_subdev_notify(&axi_ctrl->subdev,
NOTIFY_VFE_MSG_OUT,
&msg);
return;
}
-static void vfe32_process_output_path_irq_0(void)
+static void vfe32_process_output_path_irq_0(
+ struct axi_ctrl_t *axi_ctrl)
{
uint32_t ping_pong;
uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
@@ -2881,7 +3211,7 @@
struct msm_free_buf *free_buf = NULL;
free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
- VFE_MSG_OUTPUT_PRIMARY);
+ VFE_MSG_OUTPUT_PRIMARY, axi_ctrl);
/* we render frames in the following conditions:
1. Continuous mode and the free buffer is avaialable.
@@ -2889,73 +3219,92 @@
when pending snapshot count is <=1, then no need to use
free buffer.
*/
- out_bool = ((vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe32_ctrl->operation_mode == VFE_OUTPUTS_RAW ||
- vfe32_ctrl->liveshot_state == VFE_STATE_STARTED ||
- vfe32_ctrl->liveshot_state == VFE_STATE_STOP_REQUESTED ||
- vfe32_ctrl->liveshot_state == VFE_STATE_STOPPED) &&
- (vfe32_ctrl->vfe_capture_count <= 1)) || free_buf;
+ out_bool = (
+ (axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ axi_ctrl->share_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STARTED ||
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOP_REQUESTED ||
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOPPED) &&
+ (axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+ free_buf;
if (out_bool) {
- ping_pong = msm_camera_io_r(vfe32_ctrl->vfebase +
+ ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
VFE_BUS_PING_PONG_STATUS);
/* Channel 0*/
- ch0_paddr = vfe32_get_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out0.ch0);
+ ch0_paddr = vfe32_get_ch_addr(
+ ping_pong, axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch0);
/* Channel 1*/
- ch1_paddr = vfe32_get_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out0.ch1);
+ ch1_paddr = vfe32_get_ch_addr(
+ ping_pong, axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch1);
/* Channel 2*/
- ch2_paddr = vfe32_get_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out0.ch2);
+ ch2_paddr = vfe32_get_ch_addr(
+ ping_pong, axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch2);
CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
ch0_paddr, ch1_paddr, ch2_paddr);
if (free_buf) {
/* Y channel */
vfe32_put_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out0.ch0,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch0,
free_buf->ch_paddr[0]);
/* Chroma channel */
vfe32_put_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out0.ch1,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch1,
free_buf->ch_paddr[1]);
if (free_buf->num_planes > 2)
vfe32_put_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out0.ch2,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out0.ch2,
free_buf->ch_paddr[2]);
}
- if (vfe32_ctrl->operation_mode ==
+ if (axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_THUMB_AND_MAIN ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_THUMB_AND_JPEG ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_RAW ||
- vfe32_ctrl->liveshot_state == VFE_STATE_STOPPED)
- vfe32_ctrl->outpath.out0.capture_cnt--;
+ axi_ctrl->share_ctrl->liveshot_state ==
+ VFE_STATE_STOPPED)
+ axi_ctrl->share_ctrl->outpath.out0.capture_cnt--;
- vfe_send_outmsg(&vfe32_ctrl->subdev,
+ vfe_send_outmsg(axi_ctrl,
MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
- ch1_paddr, ch2_paddr);
+ ch1_paddr, ch2_paddr,
+ axi_ctrl->share_ctrl->outpath.out0.image_mode);
- if (vfe32_ctrl->liveshot_state == VFE_STATE_STOPPED)
- vfe32_ctrl->liveshot_state = VFE_STATE_IDLE;
+ if (axi_ctrl->share_ctrl->liveshot_state == VFE_STATE_STOPPED)
+ axi_ctrl->share_ctrl->liveshot_state = VFE_STATE_IDLE;
} else {
- vfe32_ctrl->outpath.out0.frame_drop_cnt++;
+ axi_ctrl->share_ctrl->outpath.out0.frame_drop_cnt++;
CDBG("path_irq_0 - no free buffer!\n");
}
}
-static void vfe32_process_output_path_irq_1(void)
+static void vfe32_process_output_path_irq_1(
+ struct axi_ctrl_t *axi_ctrl)
{
uint32_t ping_pong;
uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
@@ -2964,81 +3313,91 @@
struct msm_free_buf *free_buf = NULL;
free_buf = vfe32_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
- VFE_MSG_OUTPUT_SECONDARY);
- out_bool = ((vfe32_ctrl->operation_mode ==
+ VFE_MSG_OUTPUT_SECONDARY, axi_ctrl);
+ out_bool = ((axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_THUMB_AND_MAIN ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_RAW ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_JPEG_AND_THUMB) &&
- (vfe32_ctrl->vfe_capture_count <= 1)) || free_buf;
+ (axi_ctrl->share_ctrl->vfe_capture_count <= 1)) ||
+ free_buf;
if (out_bool) {
- ping_pong = msm_camera_io_r(vfe32_ctrl->vfebase +
+ ping_pong = msm_camera_io_r(axi_ctrl->share_ctrl->vfebase +
VFE_BUS_PING_PONG_STATUS);
/* Y channel */
ch0_paddr = vfe32_get_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out1.ch0);
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch0);
/* Chroma channel */
ch1_paddr = vfe32_get_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out1.ch1);
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch1);
ch2_paddr = vfe32_get_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out1.ch2);
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch2);
CDBG("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
__func__, ch0_paddr, ch1_paddr, ch2_paddr);
if (free_buf) {
/* Y channel */
vfe32_put_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out1.ch0,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch0,
free_buf->ch_paddr[0]);
/* Chroma channel */
vfe32_put_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out1.ch1,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch1,
free_buf->ch_paddr[1]);
if (free_buf->num_planes > 2)
vfe32_put_ch_addr(ping_pong,
- vfe32_ctrl->outpath.out1.ch2,
+ axi_ctrl->share_ctrl->vfebase,
+ axi_ctrl->share_ctrl->outpath.out1.ch2,
free_buf->ch_paddr[2]);
}
- if (vfe32_ctrl->operation_mode ==
+ if (axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_THUMB_AND_MAIN ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_RAW ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_JPEG_AND_THUMB)
- vfe32_ctrl->outpath.out1.capture_cnt--;
+ axi_ctrl->share_ctrl->outpath.out1.capture_cnt--;
- vfe_send_outmsg(&vfe32_ctrl->subdev,
+ vfe_send_outmsg(axi_ctrl,
MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
- ch1_paddr, ch2_paddr);
+ ch1_paddr, ch2_paddr,
+ axi_ctrl->share_ctrl->outpath.out1.image_mode);
+
} else {
- vfe32_ctrl->outpath.out1.frame_drop_cnt++;
+ axi_ctrl->share_ctrl->outpath.out1.frame_drop_cnt++;
CDBG("path_irq_1 - no free buffer!\n");
}
}
-static uint32_t vfe32_process_stats_irq_common(uint32_t statsNum,
- uint32_t newAddr) {
-
+static uint32_t vfe32_process_stats_irq_common(
+ struct vfe32_ctrl_type *vfe32_ctrl,
+ uint32_t statsNum, uint32_t newAddr)
+{
uint32_t pingpongStatus;
uint32_t returnAddr;
uint32_t pingpongAddr;
/* must be 0=ping, 1=pong */
pingpongStatus =
- ((msm_camera_io_r(vfe32_ctrl->vfebase +
+ ((msm_camera_io_r(vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_PING_PONG_STATUS))
& ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
/* stats bits starts at 7 */
CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
pingpongAddr =
- ((uint32_t)(vfe32_ctrl->vfebase +
+ ((uint32_t)(vfe32_ctrl->share_ctrl->vfebase +
VFE_BUS_STATS_PING_PONG_BASE)) +
(3*statsNum)*4 + (1-pingpongStatus)*4;
returnAddr = msm_camera_io_r((uint32_t *)pingpongAddr);
@@ -3047,14 +3406,15 @@
}
static void
-vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
+vfe_send_stats_msg(struct vfe32_ctrl_type *vfe32_ctrl,
+ uint32_t bufAddress, uint32_t statsNum)
{
unsigned long flags;
/* fill message with right content. */
/* @todo This is causing issues, need further investigate */
/* spin_lock_irqsave(&ctrl->state_lock, flags); */
struct isp_msg_stats msgStats;
- msgStats.frameCounter = vfe32_ctrl->vfeFrameId;
+ msgStats.frameCounter = vfe32_ctrl->share_ctrl->vfeFrameId;
msgStats.buffer = bufAddress;
switch (statsNum) {
@@ -3114,12 +3474,13 @@
return;
}
-static void vfe_send_comp_stats_msg(uint32_t status_bits)
+static void vfe_send_comp_stats_msg(
+ struct vfe32_ctrl_type *vfe32_ctrl, uint32_t status_bits)
{
struct msm_stats_buf msgStats;
uint32_t temp;
- msgStats.frame_id = vfe32_ctrl->vfeFrameId;
+ msgStats.frame_id = vfe32_ctrl->share_ctrl->vfeFrameId;
msgStats.status_bits = status_bits;
msgStats.aec.buff = vfe32_ctrl->aecStatsControl.bufToRender;
@@ -3130,7 +3491,8 @@
msgStats.rs.buff = vfe32_ctrl->rsStatsControl.bufToRender;
msgStats.cs.buff = vfe32_ctrl->csStatsControl.bufToRender;
- temp = msm_camera_io_r(vfe32_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG);
+ temp = msm_camera_io_r(
+ vfe32_ctrl->share_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG);
msgStats.awb_ymin = (0xFF00 & temp) >> 8;
v4l2_subdev_notify(&vfe32_ctrl->subdev,
@@ -3138,18 +3500,18 @@
&msgStats);
}
-static void vfe32_process_stats_ae_irq(void)
+static void vfe32_process_stats_ae_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
spin_lock_irqsave(&vfe32_ctrl->aec_ack_lock, flags);
if (!(vfe32_ctrl->aecStatsControl.ackPending)) {
spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
vfe32_ctrl->aecStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsAeNum,
+ vfe32_process_stats_irq_common(vfe32_ctrl, statsAeNum,
vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
- vfe_send_stats_msg(vfe32_ctrl->aecStatsControl.bufToRender,
- statsAeNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->aecStatsControl.bufToRender, statsAeNum);
} else{
spin_unlock_irqrestore(&vfe32_ctrl->aec_ack_lock, flags);
vfe32_ctrl->aecStatsControl.droppedStatsFrameCount++;
@@ -3158,18 +3520,18 @@
}
}
-static void vfe32_process_stats_awb_irq(void)
+static void vfe32_process_stats_awb_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
spin_lock_irqsave(&vfe32_ctrl->awb_ack_lock, flags);
if (!(vfe32_ctrl->awbStatsControl.ackPending)) {
spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
vfe32_ctrl->awbStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsAwbNum,
+ vfe32_process_stats_irq_common(vfe32_ctrl, statsAwbNum,
vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
- vfe_send_stats_msg(vfe32_ctrl->awbStatsControl.bufToRender,
- statsAwbNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->awbStatsControl.bufToRender, statsAwbNum);
} else{
spin_unlock_irqrestore(&vfe32_ctrl->awb_ack_lock, flags);
vfe32_ctrl->awbStatsControl.droppedStatsFrameCount++;
@@ -3178,18 +3540,18 @@
}
}
-static void vfe32_process_stats_af_irq(void)
+static void vfe32_process_stats_af_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
unsigned long flags;
spin_lock_irqsave(&vfe32_ctrl->af_ack_lock, flags);
if (!(vfe32_ctrl->afStatsControl.ackPending)) {
spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
vfe32_ctrl->afStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsAfNum,
+ vfe32_process_stats_irq_common(vfe32_ctrl, statsAfNum,
vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
- vfe_send_stats_msg(vfe32_ctrl->afStatsControl.bufToRender,
- statsAfNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->afStatsControl.bufToRender, statsAfNum);
} else{
spin_unlock_irqrestore(&vfe32_ctrl->af_ack_lock, flags);
vfe32_ctrl->afStatsControl.droppedStatsFrameCount++;
@@ -3198,15 +3560,17 @@
}
}
-static void vfe32_process_stats_ihist_irq(void)
+static void vfe32_process_stats_ihist_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
if (!(vfe32_ctrl->ihistStatsControl.ackPending)) {
vfe32_ctrl->ihistStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsIhistNum,
+ vfe32_process_stats_irq_common(
+ vfe32_ctrl, statsIhistNum,
vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
- vfe_send_stats_msg(vfe32_ctrl->ihistStatsControl.bufToRender,
- statsIhistNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->ihistStatsControl.bufToRender,
+ statsIhistNum);
} else {
vfe32_ctrl->ihistStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3214,15 +3578,15 @@
}
}
-static void vfe32_process_stats_rs_irq(void)
+static void vfe32_process_stats_rs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
if (!(vfe32_ctrl->rsStatsControl.ackPending)) {
vfe32_ctrl->rsStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsRsNum,
+ vfe32_process_stats_irq_common(vfe32_ctrl, statsRsNum,
vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
- vfe_send_stats_msg(vfe32_ctrl->rsStatsControl.bufToRender,
- statsRsNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->rsStatsControl.bufToRender, statsRsNum);
} else {
vfe32_ctrl->rsStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3230,15 +3594,15 @@
}
}
-static void vfe32_process_stats_cs_irq(void)
+static void vfe32_process_stats_cs_irq(struct vfe32_ctrl_type *vfe32_ctrl)
{
if (!(vfe32_ctrl->csStatsControl.ackPending)) {
vfe32_ctrl->csStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsCsNum,
+ vfe32_process_stats_irq_common(vfe32_ctrl, statsCsNum,
vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
- vfe_send_stats_msg(vfe32_ctrl->csStatsControl.bufToRender,
- statsCsNum);
+ vfe_send_stats_msg(vfe32_ctrl,
+ vfe32_ctrl->csStatsControl.bufToRender, statsCsNum);
} else {
vfe32_ctrl->csStatsControl.droppedStatsFrameCount++;
CDBG("%s: droppedStatsFrameCount = %d", __func__,
@@ -3246,7 +3610,8 @@
}
}
-static void vfe32_process_stats(uint32_t status_bits)
+static void vfe32_process_stats(struct vfe32_ctrl_type *vfe32_ctrl,
+ uint32_t status_bits)
{
unsigned long flags;
int32_t process_stats = false;
@@ -3257,7 +3622,8 @@
if (!vfe32_ctrl->aecStatsControl.ackPending) {
vfe32_ctrl->aecStatsControl.ackPending = TRUE;
vfe32_ctrl->aecStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsAeNum,
+ vfe32_process_stats_irq_common(
+ vfe32_ctrl, statsAeNum,
vfe32_ctrl->aecStatsControl.nextFrameAddrBuf);
process_stats = true;
} else{
@@ -3272,7 +3638,8 @@
if (!vfe32_ctrl->awbStatsControl.ackPending) {
vfe32_ctrl->awbStatsControl.ackPending = TRUE;
vfe32_ctrl->awbStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsAwbNum,
+ vfe32_process_stats_irq_common(
+ vfe32_ctrl, statsAwbNum,
vfe32_ctrl->awbStatsControl.nextFrameAddrBuf);
process_stats = true;
} else{
@@ -3288,7 +3655,8 @@
if (!vfe32_ctrl->afStatsControl.ackPending) {
vfe32_ctrl->afStatsControl.ackPending = TRUE;
vfe32_ctrl->afStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsAfNum,
+ vfe32_process_stats_irq_common(
+ vfe32_ctrl, statsAfNum,
vfe32_ctrl->afStatsControl.nextFrameAddrBuf);
process_stats = true;
} else {
@@ -3303,7 +3671,8 @@
if (!vfe32_ctrl->ihistStatsControl.ackPending) {
vfe32_ctrl->ihistStatsControl.ackPending = TRUE;
vfe32_ctrl->ihistStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsIhistNum,
+ vfe32_process_stats_irq_common(
+ vfe32_ctrl, statsIhistNum,
vfe32_ctrl->ihistStatsControl.nextFrameAddrBuf);
process_stats = true;
} else {
@@ -3318,7 +3687,8 @@
if (!vfe32_ctrl->rsStatsControl.ackPending) {
vfe32_ctrl->rsStatsControl.ackPending = TRUE;
vfe32_ctrl->rsStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsRsNum,
+ vfe32_process_stats_irq_common(
+ vfe32_ctrl, statsRsNum,
vfe32_ctrl->rsStatsControl.nextFrameAddrBuf);
process_stats = true;
} else {
@@ -3329,12 +3699,12 @@
vfe32_ctrl->rsStatsControl.bufToRender = 0;
}
-
if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
if (!vfe32_ctrl->csStatsControl.ackPending) {
vfe32_ctrl->csStatsControl.ackPending = TRUE;
vfe32_ctrl->csStatsControl.bufToRender =
- vfe32_process_stats_irq_common(statsCsNum,
+ vfe32_process_stats_irq_common(
+ vfe32_ctrl, statsCsNum,
vfe32_ctrl->csStatsControl.nextFrameAddrBuf);
process_stats = true;
} else {
@@ -3347,83 +3717,89 @@
spin_unlock_irqrestore(&vfe32_ctrl->comp_stats_ack_lock, flags);
if (process_stats)
- vfe_send_comp_stats_msg(status_bits);
+ vfe_send_comp_stats_msg(vfe32_ctrl, status_bits);
return;
}
-static void vfe32_process_stats_irq(uint32_t irqstatus)
+static void vfe32_process_stats_irq(
+ struct vfe32_ctrl_type *vfe32_ctrl, uint32_t irqstatus)
{
uint32_t status_bits = VFE_COM_STATUS & irqstatus;
if ((vfe32_ctrl->hfr_mode != HFR_MODE_OFF) &&
- (vfe32_ctrl->vfeFrameId % vfe32_ctrl->hfr_mode != 0)) {
+ (vfe32_ctrl->share_ctrl->vfeFrameId %
+ vfe32_ctrl->hfr_mode != 0)) {
CDBG("Skip the stats when HFR enabled\n");
return;
}
- vfe32_process_stats(status_bits);
+ vfe32_process_stats(vfe32_ctrl, status_bits);
return;
}
-static void vfe32_process_irq(uint32_t irqstatus)
+static void vfe32_process_irq(
+ struct vfe32_ctrl_type *vfe32_ctrl, uint32_t irqstatus)
{
if (irqstatus &
VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
- vfe32_process_stats_irq(irqstatus);
+ vfe32_process_stats_irq(vfe32_ctrl, irqstatus);
return;
}
switch (irqstatus) {
case VFE_IRQ_STATUS0_CAMIF_SOF_MASK:
CDBG("irq camifSofIrq\n");
- vfe32_process_camif_sof_irq();
+ vfe32_process_camif_sof_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_REG_UPDATE_MASK:
CDBG("irq regUpdateIrq\n");
- vfe32_process_reg_update_irq();
+ vfe32_process_reg_update_irq(vfe32_ctrl);
break;
case VFE_IMASK_WHILE_STOPPING_1:
CDBG("irq resetAckIrq\n");
- vfe32_process_reset_irq();
+ vfe32_process_reset_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_STATS_AEC:
CDBG("Stats AEC irq occured.\n");
- vfe32_process_stats_ae_irq();
+ vfe32_process_stats_ae_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_STATS_AWB:
CDBG("Stats AWB irq occured.\n");
- vfe32_process_stats_awb_irq();
+ vfe32_process_stats_awb_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_STATS_AF:
CDBG("Stats AF irq occured.\n");
- vfe32_process_stats_af_irq();
+ vfe32_process_stats_af_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_STATS_IHIST:
CDBG("Stats IHIST irq occured.\n");
- vfe32_process_stats_ihist_irq();
+ vfe32_process_stats_ihist_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_STATS_RS:
CDBG("Stats RS irq occured.\n");
- vfe32_process_stats_rs_irq();
+ vfe32_process_stats_rs_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_STATS_CS:
CDBG("Stats CS irq occured.\n");
- vfe32_process_stats_cs_irq();
+ vfe32_process_stats_cs_irq(vfe32_ctrl);
break;
case VFE_IRQ_STATUS0_SYNC_TIMER0:
CDBG("SYNC_TIMER 0 irq occured.\n");
- vfe32_send_isp_msg(vfe32_ctrl,
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_SYNC_TIMER0_DONE);
break;
case VFE_IRQ_STATUS0_SYNC_TIMER1:
CDBG("SYNC_TIMER 1 irq occured.\n");
- vfe32_send_isp_msg(vfe32_ctrl,
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_SYNC_TIMER1_DONE);
break;
case VFE_IRQ_STATUS0_SYNC_TIMER2:
CDBG("SYNC_TIMER 2 irq occured.\n");
- vfe32_send_isp_msg(vfe32_ctrl,
+ vfe32_send_isp_msg(&vfe32_ctrl->subdev,
+ vfe32_ctrl->share_ctrl->vfeFrameId,
MSG_ID_SYNC_TIMER2_DONE);
break;
default:
@@ -3474,11 +3850,12 @@
NOTIFY_VFE_IRQ,
(void *)VFE_IMASK_WHILE_STOPPING_1);
- if (atomic_read(&vfe32_ctrl->vstate)) {
+ if (atomic_read(&axi_ctrl->share_ctrl->vstate)) {
if (qcmd->vfeInterruptStatus1 &
VFE32_IMASK_ERROR_ONLY_1) {
pr_err("irq errorIrq\n");
vfe32_process_error_irq(
+ axi_ctrl,
qcmd->vfeInterruptStatus1 &
VFE32_IMASK_ERROR_ONLY_1);
}
@@ -3487,7 +3864,7 @@
(void *)qcmd->vfeInterruptStatus0);
/* then process stats irq. */
- if (vfe32_ctrl->stats_comp) {
+ if (axi_ctrl->share_ctrl->stats_comp) {
/* process stats comb interrupt. */
if (qcmd->vfeInterruptStatus0 &
VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
@@ -3567,7 +3944,7 @@
CDBG("vfe_parse_irq\n");
- vfe32_read_irq_status(&irq);
+ vfe32_read_irq_status(axi_ctrl, &irq);
if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
@@ -3581,12 +3958,12 @@
return IRQ_HANDLED;
}
- spin_lock_irqsave(&vfe32_ctrl->stop_flag_lock, flags);
- if (vfe32_ctrl->stop_ack_pending) {
+ spin_lock_irqsave(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
+ if (axi_ctrl->share_ctrl->stop_ack_pending) {
irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1;
}
- spin_unlock_irqrestore(&vfe32_ctrl->stop_flag_lock, flags);
+ spin_unlock_irqrestore(&axi_ctrl->share_ctrl->stop_flag_lock, flags);
CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
irq.vfeIrqStatus0, irq.vfeIrqStatus1);
@@ -3603,11 +3980,24 @@
return IRQ_HANDLED;
}
+int msm_axi_subdev_isr_routine(struct v4l2_subdev *sd,
+ u32 status, bool *handled)
+{
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ irqreturn_t ret;
+ pr_info("%s E ", __func__);
+ ret = vfe32_parse_irq(axi_ctrl->vfeirq->start, axi_ctrl);
+ *handled = TRUE;
+ return 0;
+}
+
static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int subdev_cmd, void *arg)
{
struct msm_cam_media_controller *pmctl =
(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
+ struct vfe32_ctrl_type *vfe32_ctrl =
+ (struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
struct msm_isp_cmd vfecmd;
struct msm_camvfe_params *vfe_params =
(struct msm_camvfe_params *)arg;
@@ -3619,8 +4009,14 @@
struct vfe_cmd_stats_buf *scfg = NULL;
struct msm_pmem_region *regptr = NULL;
struct vfe_cmd_stats_ack *sack = NULL;
+
+ if (!vfe32_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return -EFAULT;
+ }
+
if (cmd->cmd_type == CMD_VFE_PROCESS_IRQ) {
- vfe32_process_irq((uint32_t) data);
+ vfe32_process_irq(vfe32_ctrl, (uint32_t) data);
return rc;
} else if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
@@ -3688,22 +4084,22 @@
/* individual */
switch (cmd->cmd_type) {
case CMD_STATS_AEC_ENABLE:
- rc = vfe_stats_aec_buf_init(scfg);
+ rc = vfe_stats_aec_buf_init(vfe32_ctrl, scfg);
break;
case CMD_STATS_AF_ENABLE:
- rc = vfe_stats_af_buf_init(scfg);
+ rc = vfe_stats_af_buf_init(vfe32_ctrl, scfg);
break;
case CMD_STATS_AWB_ENABLE:
- rc = vfe_stats_awb_buf_init(scfg);
+ rc = vfe_stats_awb_buf_init(vfe32_ctrl, scfg);
break;
case CMD_STATS_IHIST_ENABLE:
- rc = vfe_stats_ihist_buf_init(scfg);
+ rc = vfe_stats_ihist_buf_init(vfe32_ctrl, scfg);
break;
case CMD_STATS_RS_ENABLE:
- rc = vfe_stats_rs_buf_init(scfg);
+ rc = vfe_stats_rs_buf_init(vfe32_ctrl, scfg);
break;
case CMD_STATS_CS_ENABLE:
- rc = vfe_stats_cs_buf_init(scfg);
+ rc = vfe_stats_cs_buf_init(vfe32_ctrl, scfg);
break;
default:
pr_err("%s Unsupported cmd type %d",
@@ -3714,50 +4110,51 @@
}
switch (cmd->cmd_type) {
case CMD_GENERAL:
- rc = vfe32_proc_general(pmctl, &vfecmd);
+ rc = vfe32_proc_general(pmctl, &vfecmd, vfe32_ctrl);
break;
-
case CMD_CONFIG_PING_ADDR: {
int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch = vfe32_get_ch(path);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
outch->ping = *((struct msm_free_buf *)data);
}
break;
case CMD_CONFIG_PONG_ADDR: {
int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch = vfe32_get_ch(path);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
outch->pong = *((struct msm_free_buf *)data);
}
break;
case CMD_CONFIG_FREE_BUF_ADDR: {
int path = *((int *)cmd->value);
- struct vfe32_output_ch *outch = vfe32_get_ch(path);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, vfe32_ctrl->share_ctrl);
outch->free_buf = *((struct msm_free_buf *)data);
}
break;
-
case CMD_SNAP_BUF_RELEASE:
break;
case CMD_STATS_AEC_BUF_RELEASE:
- vfe32_stats_aec_ack(sack);
+ vfe32_stats_aec_ack(vfe32_ctrl, sack);
break;
case CMD_STATS_AF_BUF_RELEASE:
- vfe32_stats_af_ack(sack);
+ vfe32_stats_af_ack(vfe32_ctrl, sack);
break;
case CMD_STATS_AWB_BUF_RELEASE:
- vfe32_stats_awb_ack(sack);
+ vfe32_stats_awb_ack(vfe32_ctrl, sack);
break;
case CMD_STATS_IHIST_BUF_RELEASE:
- vfe32_stats_ihist_ack(sack);
+ vfe32_stats_ihist_ack(vfe32_ctrl, sack);
break;
case CMD_STATS_RS_BUF_RELEASE:
- vfe32_stats_rs_ack(sack);
+ vfe32_stats_rs_ack(vfe32_ctrl, sack);
break;
case CMD_STATS_CS_BUF_RELEASE:
- vfe32_stats_cs_ack(sack);
+ vfe32_stats_cs_ack(vfe32_ctrl, sack);
break;
default:
pr_err("%s Unsupported AXI configuration %x ", __func__,
@@ -3816,17 +4213,16 @@
v4l2_set_subdev_hostdata(sd, mctl);
spin_lock_init(&axi_ctrl->tasklet_lock);
INIT_LIST_HEAD(&axi_ctrl->tasklet_q);
+ spin_lock_init(&axi_ctrl->share_ctrl->sd_notify_lock);
- axi_ctrl->vfebase = ioremap(axi_ctrl->vfemem->start,
+ axi_ctrl->share_ctrl->vfebase = ioremap(axi_ctrl->vfemem->start,
resource_size(axi_ctrl->vfemem));
- if (!axi_ctrl->vfebase) {
+ if (!axi_ctrl->share_ctrl->vfebase) {
rc = -ENOMEM;
pr_err("%s: vfe ioremap failed\n", __func__);
goto remap_failed;
}
- vfe32_ctrl->vfebase = axi_ctrl->vfebase;
-
if (axi_ctrl->fs_vfe == NULL) {
axi_ctrl->fs_vfe =
regulator_get(&axi_ctrl->pdev->dev, "fs_vfe");
@@ -3854,11 +4250,12 @@
msm_camio_bus_scale_cfg(
mctl->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
- if (msm_camera_io_r(vfe32_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
+ if (msm_camera_io_r(
+ axi_ctrl->share_ctrl->vfebase + V32_GET_HW_VERSION_OFF) ==
VFE32_HW_NUMBER)
- vfe32_ctrl->register_total = VFE32_REGISTER_TOTAL;
+ axi_ctrl->share_ctrl->register_total = VFE32_REGISTER_TOTAL;
else
- vfe32_ctrl->register_total = VFE33_REGISTER_TOTAL;
+ axi_ctrl->share_ctrl->register_total = VFE33_REGISTER_TOTAL;
enable_irq(axi_ctrl->vfeirq->start);
@@ -3868,8 +4265,8 @@
regulator_put(axi_ctrl->fs_vfe);
axi_ctrl->fs_vfe = NULL;
fs_failed:
- iounmap(axi_ctrl->vfebase);
- axi_ctrl->vfebase = NULL;
+ iounmap(axi_ctrl->share_ctrl->vfebase);
+ axi_ctrl->share_ctrl->vfebase = NULL;
remap_failed:
disable_irq(axi_ctrl->vfeirq->start);
return rc;
@@ -3879,9 +4276,11 @@
struct msm_cam_media_controller *mctl)
{
int rc = 0;
+ struct vfe32_ctrl_type *vfe32_ctrl =
+ (struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
v4l2_set_subdev_hostdata(sd, mctl);
- spin_lock_init(&vfe32_ctrl->stop_flag_lock);
+ spin_lock_init(&vfe32_ctrl->share_ctrl->stop_flag_lock);
spin_lock_init(&vfe32_ctrl->state_lock);
spin_lock_init(&vfe32_ctrl->io_lock);
spin_lock_init(&vfe32_ctrl->update_ack_lock);
@@ -3893,7 +4292,6 @@
spin_lock_init(&vfe32_ctrl->rs_ack_lock);
spin_lock_init(&vfe32_ctrl->cs_ack_lock);
spin_lock_init(&vfe32_ctrl->comp_stats_ack_lock);
- spin_lock_init(&vfe32_ctrl->sd_notify_lock);
vfe32_ctrl->update_linear = false;
vfe32_ctrl->update_rolloff = false;
@@ -3909,6 +4307,11 @@
struct msm_cam_media_controller *pmctl =
(struct msm_cam_media_controller *)v4l2_get_subdev_hostdata(sd);
struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return;
+ }
+
CDBG("%s, free_irq\n", __func__);
disable_irq(axi_ctrl->vfeirq->start);
tasklet_kill(&axi_ctrl->vfe32_tasklet);
@@ -3919,8 +4322,8 @@
regulator_put(axi_ctrl->fs_vfe);
axi_ctrl->fs_vfe = NULL;
}
- iounmap(axi_ctrl->vfebase);
- axi_ctrl->vfebase = NULL;
+ iounmap(axi_ctrl->share_ctrl->vfebase);
+ axi_ctrl->share_ctrl->vfebase = NULL;
if (atomic_read(&irq_cnt))
pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
@@ -3931,78 +4334,92 @@
void msm_vfe_subdev_release(struct v4l2_subdev *sd)
{
- vfe32_ctrl->vfebase = 0;
+ struct vfe32_ctrl_type *vfe32_ctrl =
+ (struct vfe32_ctrl_type *)v4l2_get_subdevdata(sd);
+ if (!vfe32_ctrl->share_ctrl->vfebase)
+ vfe32_ctrl->share_ctrl->vfebase = NULL;
}
-void axi_start(void)
+void axi_start(struct axi_ctrl_t *axi_ctrl)
{
- switch (vfe32_ctrl->operation_mode) {
+ switch (axi_ctrl->share_ctrl->operation_mode) {
case VFE_OUTPUTS_PREVIEW:
case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
- if (vfe32_ctrl->outpath.output_mode &
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- } else if (vfe32_ctrl->outpath.output_mode &
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch1]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out0.ch2]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch1]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out0.ch2]);
}
break;
default:
- if (vfe32_ctrl->outpath.output_mode &
+ if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
- } else if (vfe32_ctrl->outpath.output_mode &
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ } else if (axi_ctrl->share_ctrl->outpath.output_mode &
VFE32_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch0]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch1]);
- msm_camera_io_w(1, vfe32_ctrl->vfebase +
- vfe32_AXI_WM_CFG[vfe32_ctrl->outpath.out1.ch2]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch0]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch1]);
+ msm_camera_io_w(1, axi_ctrl->share_ctrl->vfebase +
+ vfe32_AXI_WM_CFG[axi_ctrl->
+ share_ctrl->outpath.out1.ch2]);
}
break;
}
}
-void axi_stop(void)
+void axi_stop(struct axi_ctrl_t *axi_ctrl)
{
uint8_t axiBusyFlag = true;
- /* axi halt command. */
+ /* axi halt command. */
msm_camera_io_w(AXI_HALT,
- vfe32_ctrl->vfebase + VFE_AXI_CMD);
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
wmb();
while (axiBusyFlag) {
- if (msm_camera_io_r(vfe32_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
+ if (msm_camera_io_r(
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_STATUS) & 0x1)
axiBusyFlag = false;
}
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(AXI_HALT_CLEAR,
- vfe32_ctrl->vfebase + VFE_AXI_CMD);
+ axi_ctrl->share_ctrl->vfebase + VFE_AXI_CMD);
/* after axi halt, then ok to apply global reset. */
/* enable reset_ack and async timer interrupt only while
stopping the pipeline.*/
msm_camera_io_w(0xf0000000,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_0);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_0);
msm_camera_io_w(VFE_IMASK_WHILE_STOPPING_1,
- vfe32_ctrl->vfebase + VFE_IRQ_MASK_1);
+ axi_ctrl->share_ctrl->vfebase + VFE_IRQ_MASK_1);
/* Ensure the write order while writing
to the command register using the barrier */
msm_camera_io_w_mb(VFE_RESET_UPON_STOP_CMD,
- vfe32_ctrl->vfebase + VFE_GLOBAL_RESET);
+ axi_ctrl->share_ctrl->vfebase + VFE_GLOBAL_RESET);
}
static int msm_axi_config(struct v4l2_subdev *sd, void __user *arg)
@@ -4010,7 +4427,12 @@
struct msm_vfe_cfg_cmd cfgcmd;
struct msm_isp_cmd vfecmd;
int rc = 0;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return -EFAULT;
+ }
if (NULL != arg) {
if (copy_from_user(&cfgcmd, arg, sizeof(cfgcmd))) {
ERR_COPY_FROM_USER();
@@ -4043,7 +4465,7 @@
rc = -EFAULT;
break;
}
- vfe32_config_axi(OUTPUT_PRIM, axio);
+ vfe32_config_axi(axi_ctrl, OUTPUT_PRIM, axio);
kfree(axio);
}
break;
@@ -4062,7 +4484,7 @@
rc = -EFAULT;
break;
}
- vfe32_config_axi(OUTPUT_PRIM_ALL_CHNLS, axio);
+ vfe32_config_axi(axi_ctrl, OUTPUT_PRIM_ALL_CHNLS, axio);
kfree(axio);
}
break;
@@ -4081,7 +4503,7 @@
rc = -EFAULT;
break;
}
- vfe32_config_axi(OUTPUT_PRIM|OUTPUT_SEC, axio);
+ vfe32_config_axi(axi_ctrl, OUTPUT_PRIM|OUTPUT_SEC, axio);
kfree(axio);
}
break;
@@ -4100,7 +4522,8 @@
rc = -EFAULT;
break;
}
- vfe32_config_axi(OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
+ vfe32_config_axi(axi_ctrl,
+ OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
kfree(axio);
}
break;
@@ -4119,7 +4542,8 @@
rc = -EFAULT;
break;
}
- vfe32_config_axi(OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
+ vfe32_config_axi(axi_ctrl,
+ OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
kfree(axio);
}
break;
@@ -4128,10 +4552,10 @@
__func__, cfgcmd.cmd_type);
break;
case CMD_AXI_START:
- axi_start();
+ axi_start(axi_ctrl);
break;
case CMD_AXI_STOP:
- axi_stop();
+ axi_stop(axi_ctrl);
break;
default:
pr_err("%s Unsupported AXI configuration %x ", __func__,
@@ -4143,43 +4567,95 @@
static void msm_axi_process_irq(struct v4l2_subdev *sd, void *arg)
{
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
uint32_t irqstatus = (uint32_t) arg;
+
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return;
+ }
/* next, check output path related interrupts. */
if (irqstatus &
VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
CDBG("Image composite done 0 irq occured.\n");
- vfe32_process_output_path_irq_0();
+ vfe32_process_output_path_irq_0(axi_ctrl);
}
if (irqstatus &
VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
CDBG("Image composite done 1 irq occured.\n");
- vfe32_process_output_path_irq_1();
+ vfe32_process_output_path_irq_1(axi_ctrl);
}
/* in snapshot mode if done then send
snapshot done message */
- if (vfe32_ctrl->operation_mode ==
+ if (axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_THUMB_AND_MAIN ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_MAIN_AND_THUMB ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_THUMB_AND_JPEG ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_JPEG_AND_THUMB ||
- vfe32_ctrl->operation_mode ==
+ axi_ctrl->share_ctrl->operation_mode ==
VFE_OUTPUTS_RAW) {
- if ((vfe32_ctrl->outpath.out0.capture_cnt == 0)
- && (vfe32_ctrl->outpath.out1.
+ if ((axi_ctrl->share_ctrl->outpath.out0.capture_cnt == 0)
+ && (axi_ctrl->share_ctrl->outpath.out1.
capture_cnt == 0)) {
msm_camera_io_w_mb(
CAMIF_COMMAND_STOP_IMMEDIATELY,
- vfe32_ctrl->vfebase +
+ axi_ctrl->share_ctrl->vfebase +
VFE_CAMIF_COMMAND);
- vfe32_send_isp_msg(vfe32_ctrl,
+ vfe32_send_isp_msg(&axi_ctrl->subdev,
+ axi_ctrl->share_ctrl->vfeFrameId,
MSG_ID_SNAPSHOT_DONE);
}
}
}
+static int msm_axi_buf_cfg(struct v4l2_subdev *sd, void __user *arg)
+{
+ struct msm_camvfe_params *vfe_params =
+ (struct msm_camvfe_params *)arg;
+ struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+ struct axi_ctrl_t *axi_ctrl = v4l2_get_subdevdata(sd);
+ void *data = vfe_params->data;
+ int rc = 0;
+
+ if (!axi_ctrl->share_ctrl->vfebase) {
+ pr_err("%s: base address unmapped\n", __func__);
+ return -EFAULT;
+ }
+
+ switch (cmd->cmd_type) {
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, axi_ctrl->share_ctrl);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, axi_ctrl->share_ctrl);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe32_output_ch *outch =
+ vfe32_get_ch(path, axi_ctrl->share_ctrl);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
+ break;
+ default:
+ pr_err("%s Unsupported AXI Buf config %x ", __func__,
+ cmd->cmd_type);
+ }
+ return rc;
+};
+
static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
static long msm_axi_subdev_ioctl(struct v4l2_subdev *sd,
@@ -4198,6 +4674,10 @@
msm_axi_process_irq(sd, arg);
rc = 0;
break;
+ case VIDIOC_MSM_AXI_BUF_CFG:
+ msm_axi_buf_cfg(sd, arg);
+ rc = 0;
+ break;
case VIDIOC_MSM_AXI_RELEASE:
msm_axi_subdev_release(sd);
rc = 0;
@@ -4210,6 +4690,7 @@
static const struct v4l2_subdev_core_ops msm_axi_subdev_core_ops = {
.ioctl = msm_axi_subdev_ioctl,
+ .interrupt_service_routine = msm_axi_subdev_isr_routine,
};
static const struct v4l2_subdev_video_ops msm_axi_subdev_video_ops = {
@@ -4227,14 +4708,39 @@
{
int rc = 0;
struct axi_ctrl_t *axi_ctrl;
+ struct vfe32_ctrl_type *vfe32_ctrl;
+ struct vfe_share_ctrl_t *share_ctrl;
+ struct intr_table_entry irq_req;
+ struct msm_cam_subdev_info sd_info;
+
CDBG("%s: device id = %d\n", __func__, pdev->id);
- vfe32_ctrl = kzalloc(sizeof(struct vfe32_ctrl_type), GFP_KERNEL);
- if (!vfe32_ctrl) {
+
+ share_ctrl = kzalloc(sizeof(struct vfe_share_ctrl_t), GFP_KERNEL);
+ if (!share_ctrl) {
pr_err("%s: no enough memory\n", __func__);
return -ENOMEM;
}
axi_ctrl = kzalloc(sizeof(struct axi_ctrl_t), GFP_KERNEL);
+ if (!axi_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ kfree(share_ctrl);
+ return -ENOMEM;
+ }
+
+ vfe32_ctrl = kzalloc(sizeof(struct vfe32_ctrl_type), GFP_KERNEL);
+ if (!vfe32_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ kfree(share_ctrl);
+ kfree(axi_ctrl);
+ return -ENOMEM;
+ }
+
+ share_ctrl->axi_ctrl = axi_ctrl;
+ share_ctrl->vfe32_ctrl = vfe32_ctrl;
+ axi_ctrl->share_ctrl = share_ctrl;
+ vfe32_ctrl->share_ctrl = share_ctrl;
+
v4l2_subdev_init(&axi_ctrl->subdev, &msm_axi_subdev_ops);
axi_ctrl->subdev.internal_ops = &msm_axi_internal_ops;
axi_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -4242,7 +4748,11 @@
sizeof(axi_ctrl->subdev.name), "axi");
v4l2_set_subdevdata(&axi_ctrl->subdev, axi_ctrl);
axi_ctrl->pdev = pdev;
- msm_cam_register_subdev_node(&axi_ctrl->subdev, AXI_DEV, 0);
+
+ sd_info.sdev_type = AXI_DEV;
+ sd_info.sd_index = 0;
+ sd_info.irq_num = 0;
+ msm_cam_register_subdev_node(&axi_ctrl->subdev, &sd_info);
v4l2_subdev_init(&vfe32_ctrl->subdev, &msm_vfe_subdev_ops);
vfe32_ctrl->subdev.internal_ops = &msm_vfe_internal_ops;
@@ -4275,23 +4785,49 @@
goto vfe32_no_resource;
}
- rc = request_irq(axi_ctrl->vfeirq->start, vfe32_parse_irq,
- IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
- if (rc < 0) {
- release_mem_region(axi_ctrl->vfemem->start,
- resource_size(axi_ctrl->vfemem));
- pr_err("%s: irq request fail\n", __func__);
- rc = -EBUSY;
+ /* Request for this device irq from the camera server. If the
+ * IRQ Router is present on this target, the interrupt will be
+ * handled by the camera server and the interrupt service
+ * routine called. If the request_irq call returns ENXIO, then
+ * the IRQ Router hardware is not present on this target. We
+ * have to request for the irq ourselves and register the
+ * appropriate interrupt handler. */
+ irq_req.cam_hw_idx = MSM_CAM_HW_VFE0;
+ irq_req.dev_name = "vfe";
+ irq_req.irq_idx = CAMERA_SS_IRQ_8;
+ irq_req.irq_num = axi_ctrl->vfeirq->start;
+ irq_req.is_composite = 0;
+ irq_req.irq_trigger_type = IRQF_TRIGGER_RISING;
+ irq_req.num_hwcore = 1;
+ irq_req.subdev_list[0] = &axi_ctrl->subdev;
+ irq_req.data = (void *)axi_ctrl;
+ rc = msm_cam_server_request_irq(&irq_req);
+ if (rc == -ENXIO) {
+ /* IRQ Router hardware is not present on this hardware.
+ * Request for the IRQ and register the interrupt handler. */
+ rc = request_irq(axi_ctrl->vfeirq->start, vfe32_parse_irq,
+ IRQF_TRIGGER_RISING, "vfe", axi_ctrl);
+ if (rc < 0) {
+ release_mem_region(axi_ctrl->vfemem->start,
+ resource_size(axi_ctrl->vfemem));
+ pr_err("%s: irq request fail\n", __func__);
+ rc = -EBUSY;
+ goto vfe32_no_resource;
+ }
+ disable_irq(axi_ctrl->vfeirq->start);
+ } else if (rc < 0) {
+ pr_err("%s Error registering irq ", __func__);
goto vfe32_no_resource;
}
- disable_irq(axi_ctrl->vfeirq->start);
-
tasklet_init(&axi_ctrl->vfe32_tasklet,
axi32_do_tasklet, (unsigned long)axi_ctrl);
vfe32_ctrl->pdev = pdev;
- msm_cam_register_subdev_node(&vfe32_ctrl->subdev, VFE_DEV, 0);
+ sd_info.sdev_type = VFE_DEV;
+ sd_info.sd_index = 0;
+ sd_info.irq_num = axi_ctrl->vfeirq->start;
+ msm_cam_register_subdev_node(&vfe32_ctrl->subdev, &sd_info);
return 0;
vfe32_no_resource:
diff --git a/drivers/media/video/msm/msm_vfe32.h b/drivers/media/video/msm/msm_vfe32.h
index d1faded..d5da432 100644
--- a/drivers/media/video/msm/msm_vfe32.h
+++ b/drivers/media/video/msm/msm_vfe32.h
@@ -741,7 +741,7 @@
struct vfe32_output_ch {
struct list_head free_buf_queue;
spinlock_t free_buf_lock;
- uint16_t output_fmt;
+ uint16_t image_mode;
int8_t ch0;
int8_t ch1;
int8_t ch2;
@@ -900,6 +900,30 @@
uint32_t droppedStatsFrameCount;
uint32_t bufToRender;
};
+struct axi_ctrl_t;
+struct vfe32_ctrl_type;
+
+struct vfe_share_ctrl_t {
+ void __iomem *vfebase;
+ uint32_t register_total;
+
+ atomic_t vstate;
+ uint32_t vfeFrameId;
+ uint32_t stats_comp;
+ spinlock_t stop_flag_lock;
+ int8_t stop_ack_pending;
+ enum vfe_output_state liveshot_state;
+ uint32_t vfe_capture_count;
+
+ uint16_t operation_mode; /* streaming or snapshot */
+ struct vfe32_output_path outpath;
+
+ uint32_t ref_count;
+ spinlock_t sd_notify_lock;
+
+ struct axi_ctrl_t *axi_ctrl;
+ struct vfe32_ctrl_type *vfe32_ctrl;
+};
struct axi_ctrl_t {
struct v4l2_subdev subdev;
@@ -908,7 +932,6 @@
spinlock_t tasklet_lock;
struct list_head tasklet_q;
- void __iomem *vfebase;
void *syncdata;
struct resource *vfemem;
@@ -916,15 +939,12 @@
struct regulator *fs_vfe;
struct clk *vfe_clk[3];
struct tasklet_struct vfe32_tasklet;
+ struct vfe_share_ctrl_t *share_ctrl;
};
struct vfe32_ctrl_type {
- uint16_t operation_mode; /* streaming or snapshot */
- struct vfe32_output_path outpath;
-
uint32_t vfeImaskCompositePacked;
- spinlock_t stop_flag_lock;
spinlock_t update_ack_lock;
spinlock_t state_lock;
spinlock_t io_lock;
@@ -941,7 +961,6 @@
void *extdata;
int8_t start_ack_pending;
- int8_t stop_ack_pending;
int8_t reset_ack_pending;
int8_t update_ack_pending;
enum vfe_output_state recording_state;
@@ -949,19 +968,13 @@
int8_t update_rolloff;
int8_t update_la;
int8_t update_gamma;
- enum vfe_output_state liveshot_state;
- void __iomem *vfebase;
- uint32_t register_total;
+ struct vfe_share_ctrl_t *share_ctrl;
- uint32_t stats_comp;
- atomic_t vstate;
- uint32_t vfe_capture_count;
uint32_t sync_timer_repeat_count;
uint32_t sync_timer_state;
uint32_t sync_timer_number;
- uint32_t vfeFrameId;
uint32_t output1Pattern;
uint32_t output1Period;
uint32_t output2Pattern;
@@ -978,7 +991,6 @@
/* v4l2 subdev */
struct v4l2_subdev subdev;
struct platform_device *pdev;
- spinlock_t sd_notify_lock;
uint32_t hfr_mode;
uint32_t frame_skip_cnt;
uint32_t frame_skip_pattern;
@@ -1015,4 +1027,7 @@
#define VIDIOC_MSM_AXI_IRQ \
_IOWR('V', BASE_VIDIOC_PRIVATE + 21, void *)
+#define VIDIOC_MSM_AXI_BUF_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 22, void *)
+
#endif /* __MSM_VFE32_H__ */
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 135ad20..398621f 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -370,6 +370,7 @@
struct isp_msg_output msg;
msg.output_id = msgid;
+ msg.buf.image_mode = -1;
msg.buf.ch_paddr[0] = ch0_paddr;
msg.buf.ch_paddr[1] = ch1_paddr;
msg.frameCounter = vfe2x_ctrl->vfeFrameId;
@@ -859,6 +860,7 @@
CDBG("vfe2x_subdev_notify : msgId = %d\n", id);
rp.evt_msg.type = MSM_CAMERA_MSG;
rp.evt_msg.msg_id = path;
+ rp.evt_msg.data = NULL;
rp.type = id;
v4l2_subdev_notify(&vfe2x_ctrl->subdev, NOTIFY_VFE_BUF_EVT, &rp);
spin_unlock_irqrestore(&vfe2x_ctrl->sd_notify_lock, flags);
@@ -1264,6 +1266,16 @@
vfestopped = 1;
spin_lock_irqsave(&vfe2x_ctrl->table_lock,
flags);
+ if (op_mode & SNAPSHOT_MASK_MODE) {
+ vfe2x_ctrl->stop_pending = 0;
+ vfe2x_send_isp_msg(vfe2x_ctrl,
+ msgs_map[MSG_STOP_ACK].
+ isp_id);
+ spin_unlock_irqrestore(
+ &vfe2x_ctrl->table_lock,
+ flags);
+ return 0;
+ }
if ((!list_empty(&vfe2x_ctrl->table_q)) ||
vfe2x_ctrl->tableack_pending) {
CDBG("stop pending\n");
@@ -1783,6 +1795,8 @@
static int __devinit vfe2x_probe(struct platform_device *pdev)
{
+ struct msm_cam_subdev_info sd_info;
+
CDBG("%s: device id = %d\n", __func__, pdev->id);
vfe2x_ctrl = kzalloc(sizeof(struct vfe2x_ctrl_type), GFP_KERNEL);
if (!vfe2x_ctrl) {
@@ -1799,7 +1813,10 @@
platform_set_drvdata(pdev, &vfe2x_ctrl->subdev);
vfe2x_ctrl->pdev = pdev;
- msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, VFE_DEV, 0);
+ sd_info.sdev_type = VFE_DEV;
+ sd_info.sd_index = 0;
+ sd_info.irq_num = 0;
+ msm_cam_register_subdev_node(&vfe2x_ctrl->subdev, &sd_info);
return 0;
}
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index f9ce74b..fb22cf9 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -30,14 +30,19 @@
#include "msm.h"
#include "msm_vpe.h"
+#ifdef CONFIG_MSM_CAMERA_DEBUG
+#define D(fmt, args...) pr_debug("msm_vpe: " fmt, ##args)
+#else
+#define D(fmt, args...) do {} while (0)
+#endif
+
static int vpe_enable(uint32_t);
static int vpe_disable(void);
static int vpe_update_scaler(struct msm_pp_crop *pcrop);
struct vpe_ctrl_type *vpe_ctrl;
static atomic_t vpe_init_done = ATOMIC_INIT(0);
-static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
- struct msm_mctl_pp_frame_info *pp_frame_info);
+static int msm_vpe_do_pp(struct msm_mctl_pp_frame_info *pp_frame_info);
static long long vpe_do_div(long long num, long long den)
{
@@ -57,8 +62,7 @@
msm_camera_io_dump(vpe_ctrl->vpebase + 0x50400, 0x10);
/* this triggers the operation. */
- msm_camera_io_w(1, vpe_ctrl->vpebase + VPE_DL0_START_OFFSET);
- wmb();
+ msm_camera_io_w_mb(1, vpe_ctrl->vpebase + VPE_DL0_START_OFFSET);
return 0;
}
@@ -72,7 +76,7 @@
static void vpe_config_axi_default(void)
{
msm_camera_io_w(0x25, vpe_ctrl->vpebase + VPE_AXI_ARB_2_OFFSET);
- CDBG("%s: yaddr %ld cbcraddr %ld", __func__,
+ D("%s: yaddr %ld cbcraddr %ld", __func__,
vpe_ctrl->out_y_addr, vpe_ctrl->out_cbcr_addr);
if (!vpe_ctrl->out_y_addr || !vpe_ctrl->out_cbcr_addr)
return;
@@ -81,7 +85,6 @@
/* for video CbCr address */
msm_camera_io_w(vpe_ctrl->out_cbcr_addr,
vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET);
-
}
static int vpe_reset(void)
@@ -92,7 +95,7 @@
spin_lock_irqsave(&vpe_ctrl->lock, flags);
if (vpe_ctrl->state == VPE_STATE_IDLE) {
- CDBG("%s: VPE already disabled.", __func__);
+ D("%s: VPE already disabled.", __func__);
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
return rc;
}
@@ -101,7 +104,7 @@
vpe_reset_state_variables();
vpe_version = msm_camera_io_r(
vpe_ctrl->vpebase + VPE_HW_VERSION_OFFSET);
- CDBG("vpe_version = 0x%x\n", vpe_version);
+ D("vpe_version = 0x%x\n", vpe_version);
/* disable all interrupts.*/
msm_camera_io_w(0, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET);
/* clear all pending interrupts*/
@@ -139,13 +142,13 @@
rot_flag = msm_camera_io_r(vpe_ctrl->vpebase +
VPE_OP_MODE_OFFSET) & 0xE00;
if (pinfo != NULL) {
- CDBG("%s: Crop info in2_w = %d, in2_h = %d "
+ D("%s: Crop info in2_w = %d, in2_h = %d "
"out2_w = %d out2_h = %d\n",
__func__, pcrop->src_w, pcrop->src_h,
pcrop->dst_w, pcrop->dst_h);
rc = vpe_update_scaler(pcrop);
}
- CDBG("return rc = %d rot_flag = %d\n", rc, rot_flag);
+ D("return rc = %d rot_flag = %d\n", rc, rot_flag);
rc |= rot_flag;
return rc;
@@ -200,7 +203,7 @@
vpe_ctrl->out_w = w;
vpe_ctrl->out_h = h;
}
- CDBG("%s: out_w=%d, out_h=%d", __func__, vpe_ctrl->out_w,
+ D("%s: out_w=%d, out_h=%d", __func__, vpe_ctrl->out_w,
vpe_ctrl->out_h);
return 0;
}
@@ -239,7 +242,7 @@
out_ROI_width = pcrop->dst_w;
out_ROI_height = pcrop->dst_h;
- CDBG("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
+ D("src w = 0x%x, h=0x%x, dst w = 0x%x, h =0x%x.\n",
src_ROI_width, src_ROI_height, out_ROI_width,
out_ROI_height);
src_roi = (src_ROI_height << 16) + src_ROI_width;
@@ -249,12 +252,12 @@
src_x = pcrop->src_x;
src_y = pcrop->src_y;
- CDBG("src_x = %d, src_y=%d.\n", src_x, src_y);
+ D("src_x = %d, src_y=%d.\n", src_x, src_y);
src_xy = src_y*(1<<16) + src_x;
msm_camera_io_w(src_xy, vpe_ctrl->vpebase +
VPE_SRC_XY_OFFSET);
- CDBG("src_xy = %d, src_roi=%d.\n", src_xy, src_roi);
+ D("src_xy = %d, src_roi=%d.\n", src_xy, src_roi);
/* decide whether to use FIR or M/N for scaling */
if ((out_ROI_width == 1 && src_ROI_width < 4) ||
@@ -387,9 +390,9 @@
} else if (scale_unit_sel_y == 1) /* M over N scalar */
phase_init_y = 0;
- CDBG("phase step x = %d, step y = %d.\n",
+ D("phase step x = %d, step y = %d.\n",
phase_step_x, phase_step_y);
- CDBG("phase init x = %d, init y = %d.\n",
+ D("phase init x = %d, init y = %d.\n",
phase_init_x, phase_init_y);
msm_camera_io_w(phase_step_x, vpe_ctrl->vpebase +
@@ -416,24 +419,40 @@
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
return busy;
}
+
static int msm_send_frame_to_vpe(void)
{
int rc = 0;
unsigned long flags;
+ unsigned long srcP0, srcP1, outP0, outP1;
+ struct msm_mctl_pp_frame_info *frame = vpe_ctrl->pp_frame_info;
spin_lock_irqsave(&vpe_ctrl->lock, flags);
- msm_camera_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->src_frame.sp.y_off),
- vpe_ctrl->vpebase + VPE_SRCP0_ADDR_OFFSET);
- msm_camera_io_w((vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off),
- vpe_ctrl->vpebase + VPE_SRCP1_ADDR_OFFSET);
- msm_camera_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->dest_frame.sp.y_off),
- vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET);
- msm_camera_io_w((vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
- vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off),
- vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET);
+ if (frame->src_frame.num_planes > 1) {
+ srcP0 = vpe_ctrl->pp_frame_info->src_frame.mp[0].phy_addr +
+ vpe_ctrl->pp_frame_info->src_frame.mp[0].data_offset;
+ srcP1 = vpe_ctrl->pp_frame_info->src_frame.mp[1].phy_addr +
+ vpe_ctrl->pp_frame_info->src_frame.mp[1].data_offset;
+ outP0 = vpe_ctrl->pp_frame_info->dest_frame.mp[0].phy_addr +
+ vpe_ctrl->pp_frame_info->dest_frame.mp[0].data_offset;
+ outP1 = vpe_ctrl->pp_frame_info->dest_frame.mp[1].phy_addr +
+ vpe_ctrl->pp_frame_info->dest_frame.mp[1].data_offset;
+ } else {
+ srcP0 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->src_frame.sp.y_off;
+ srcP1 = vpe_ctrl->pp_frame_info->src_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->src_frame.sp.cbcr_off;
+ outP0 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->dest_frame.sp.y_off;
+ outP1 = vpe_ctrl->pp_frame_info->dest_frame.sp.phy_addr +
+ vpe_ctrl->pp_frame_info->dest_frame.sp.cbcr_off;
+ }
+
+ msm_camera_io_w(srcP0, vpe_ctrl->vpebase + VPE_SRCP0_ADDR_OFFSET);
+ msm_camera_io_w(srcP1, vpe_ctrl->vpebase + VPE_SRCP1_ADDR_OFFSET);
+ msm_camera_io_w(outP0, vpe_ctrl->vpebase + VPE_OUTP0_ADDR_OFFSET);
+ msm_camera_io_w(outP1, vpe_ctrl->vpebase + VPE_OUTP1_ADDR_OFFSET);
+
vpe_ctrl->state = VPE_STATE_ACTIVE;
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
vpe_start();
@@ -443,27 +462,33 @@
static void vpe_send_outmsg(void)
{
unsigned long flags;
- struct msm_vpe_resp rp;
- memset(&rp, 0, sizeof(rp));
+ struct v4l2_event v4l2_evt;
+ struct msm_queue_cmd *event_qcmd;
spin_lock_irqsave(&vpe_ctrl->lock, flags);
if (vpe_ctrl->state == VPE_STATE_IDLE) {
pr_err("%s VPE is in IDLE state. Ignore the ack msg", __func__);
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
return;
}
- rp.type = vpe_ctrl->pp_frame_info->pp_frame_cmd.path;
- rp.extdata = (void *)vpe_ctrl->pp_frame_info;
- rp.extlen = sizeof(*vpe_ctrl->pp_frame_info);
- vpe_ctrl->state = VPE_STATE_INIT; /* put it back to idle. */
+ event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC);
+ atomic_set(&event_qcmd->on_heap, 1);
+ event_qcmd->command = (void *)vpe_ctrl->pp_frame_info;
vpe_ctrl->pp_frame_info = NULL;
+ vpe_ctrl->state = VPE_STATE_INIT; /* put it back to idle. */
+
+ /* Enqueue the event payload. */
+ msm_enqueue(&vpe_ctrl->eventData_q, &event_qcmd->list_eventdata);
+ /* Now queue the event. */
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MCTL_PP_EVENT;
+ v4l2_evt.id = 0;
+ v4l2_event_queue(vpe_ctrl->subdev.devnode, &v4l2_evt);
+
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
- v4l2_subdev_notify(&vpe_ctrl->subdev,
- NOTIFY_VPE_MSG_EVT, (void *)&rp);
}
static void vpe_do_tasklet(unsigned long data)
{
- CDBG("%s: irq_status = 0x%x",
+ D("%s: irq_status = 0x%x",
__func__, vpe_ctrl->irq_status);
if (vpe_ctrl->irq_status & 0x1)
vpe_send_outmsg();
@@ -478,7 +503,7 @@
msm_camera_io_w_mb(vpe_ctrl->irq_status, vpe_ctrl->vpebase +
VPE_INTR_CLEAR_OFFSET);
msm_camera_io_w(0, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET);
- CDBG("%s: vpe_parse_irq =0x%x.\n", __func__, vpe_ctrl->irq_status);
+ D("%s: vpe_parse_irq =0x%x.\n", __func__, vpe_ctrl->irq_status);
tasklet_schedule(&vpe_tasklet);
return IRQ_HANDLED;
}
@@ -492,7 +517,7 @@
{
int rc = 0;
unsigned long flags = 0;
- CDBG("%s", __func__);
+ D("%s", __func__);
/* don't change the order of clock and irq.*/
spin_lock_irqsave(&vpe_ctrl->lock, flags);
if (vpe_ctrl->state != VPE_STATE_IDLE) {
@@ -536,10 +561,10 @@
{
int rc = 0;
unsigned long flags = 0;
- CDBG("%s", __func__);
+ D("%s", __func__);
spin_lock_irqsave(&vpe_ctrl->lock, flags);
if (vpe_ctrl->state == VPE_STATE_IDLE) {
- CDBG("%s: VPE already disabled", __func__);
+ D("%s: VPE already disabled", __func__);
spin_unlock_irqrestore(&vpe_ctrl->lock, flags);
return rc;
}
@@ -559,8 +584,7 @@
return rc;
}
-static int msm_vpe_do_pp(struct msm_mctl_pp_cmd *cmd,
- struct msm_mctl_pp_frame_info *pp_frame_info)
+static int msm_vpe_do_pp(struct msm_mctl_pp_frame_info *pp_frame_info)
{
int rc = 0;
unsigned long flags;
@@ -577,7 +601,7 @@
vpe_ctrl->pp_frame_info = pp_frame_info;
msm_vpe_cfg_update(
&vpe_ctrl->pp_frame_info->pp_frame_cmd.crop);
- CDBG("%s Sending frame idx %d id %d to VPE ", __func__,
+ D("%s Sending frame idx %d id %d to VPE ", __func__,
pp_frame_info->src_frame.buf_idx,
pp_frame_info->src_frame.frame_id);
rc = msm_send_frame_to_vpe();
@@ -590,7 +614,7 @@
struct msm_cam_media_controller *mctl)
{
int rc = 0;
- CDBG("%s:begin", __func__);
+ D("%s:begin", __func__);
if (atomic_read(&vpe_init_done)) {
pr_err("%s: VPE has been initialized", __func__);
return -EBUSY;
@@ -604,7 +628,7 @@
}
v4l2_set_subdev_hostdata(sd, mctl);
spin_lock_init(&vpe_ctrl->lock);
- CDBG("%s:end", __func__);
+ D("%s:end", __func__);
return rc;
}
EXPORT_SYMBOL(msm_vpe_subdev_init);
@@ -646,84 +670,312 @@
}
EXPORT_SYMBOL(msm_vpe_subdev_release);
-static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
- unsigned int subdev_cmd, void *arg)
+static int msm_vpe_process_vpe_cmd(struct msm_vpe_cfg_cmd *vpe_cmd)
{
- struct msm_mctl_pp_params *vpe_params;
- struct msm_mctl_pp_cmd *cmd;
int rc = 0;
- if (subdev_cmd == VIDIOC_MSM_VPE_INIT) {
+ switch (vpe_cmd->cmd_type) {
+ case VPE_CMD_RESET:
+ rc = vpe_reset();
+ break;
+
+ case VPE_CMD_OPERATION_MODE_CFG: {
+ struct msm_vpe_op_mode_cfg op_mode_cfg;
+ if (sizeof(struct msm_vpe_op_mode_cfg) != vpe_cmd->length) {
+ pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
+ __func__, vpe_cmd->cmd_type, vpe_cmd->length,
+ sizeof(struct msm_vpe_op_mode_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ COPY_FROM_USER(rc, &op_mode_cfg, (void __user *)vpe_cmd->value,
+ sizeof(op_mode_cfg));
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ break;
+ }
+
+ vpe_cmd->value = (void *)&op_mode_cfg;
+ rc = vpe_operation_config(vpe_cmd->value);
+ break;
+ }
+
+ case VPE_CMD_INPUT_PLANE_CFG: {
+ struct msm_vpe_input_plane_cfg input_cfg;
+ if (sizeof(struct msm_vpe_input_plane_cfg) != vpe_cmd->length) {
+ pr_err("%s: mismatch cmd = %d, len = %d, expected = %d",
+ __func__, vpe_cmd->cmd_type, vpe_cmd->length,
+ sizeof(struct msm_vpe_input_plane_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ COPY_FROM_USER(rc, &input_cfg, (void __user *)vpe_cmd->value,
+ sizeof(input_cfg));
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ break;
+ }
+
+ vpe_cmd->value = (void *)&input_cfg;
+ vpe_input_plane_config(vpe_cmd->value);
+ break;
+ }
+
+ case VPE_CMD_OUTPUT_PLANE_CFG: {
+ struct msm_vpe_output_plane_cfg output_cfg;
+ if (sizeof(struct msm_vpe_output_plane_cfg) !=
+ vpe_cmd->length) {
+ pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
+ __func__, vpe_cmd->cmd_type, vpe_cmd->length,
+ sizeof(struct msm_vpe_output_plane_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ COPY_FROM_USER(rc, &output_cfg, (void __user *)vpe_cmd->value,
+ sizeof(output_cfg));
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ break;
+ }
+
+ vpe_cmd->value = (void *)&output_cfg;
+ vpe_output_plane_config(vpe_cmd->value);
+ break;
+ }
+
+ case VPE_CMD_SCALE_CFG_TYPE:{
+ struct msm_vpe_scaler_cfg scaler_cfg;
+ if (sizeof(struct msm_vpe_scaler_cfg) != vpe_cmd->length) {
+ pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
+ __func__, vpe_cmd->cmd_type, vpe_cmd->length,
+ sizeof(struct msm_vpe_scaler_cfg));
+ rc = -EINVAL;
+ break;
+ }
+ COPY_FROM_USER(rc, &scaler_cfg, (void __user *)vpe_cmd->value,
+ sizeof(scaler_cfg));
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ break;
+ }
+
+ vpe_cmd->value = (void *)&scaler_cfg;
+ vpe_update_scale_coef(vpe_cmd->value);
+ break;
+ }
+
+ case VPE_CMD_ZOOM: {
+ struct msm_mctl_pp_frame_info *zoom;
+ zoom = kmalloc(sizeof(struct msm_mctl_pp_frame_info),
+ GFP_ATOMIC);
+ if (!zoom) {
+ pr_err("%s Not enough memory ", __func__);
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (sizeof(zoom->pp_frame_cmd) != vpe_cmd->length) {
+ pr_err("%s: size mismatch id=%d, len=%d, expected=%d",
+ __func__, vpe_cmd->cmd_type, vpe_cmd->length,
+ sizeof(zoom->pp_frame_cmd));
+ rc = -EINVAL;
+ kfree(zoom);
+ break;
+ }
+ COPY_FROM_USER(rc, &zoom->pp_frame_cmd,
+ (void __user *)vpe_cmd->value,
+ sizeof(zoom->pp_frame_cmd));
+ if (rc) {
+ ERR_COPY_FROM_USER();
+ kfree(zoom);
+ break;
+ }
+
+ zoom->user_cmd = vpe_cmd->cmd_type;
+ zoom->p_mctl = v4l2_get_subdev_hostdata(&vpe_ctrl->subdev);
+ D("%s: src=0x%x, dest=0x%x,cookie=0x%x,action=0x%x,path=0x%x",
+ __func__, zoom->pp_frame_cmd.src_buf_handle,
+ zoom->pp_frame_cmd.dest_buf_handle,
+ zoom->pp_frame_cmd.cookie,
+ zoom->pp_frame_cmd.vpe_output_action,
+ zoom->pp_frame_cmd.path);
+ rc = msm_mctl_pp_get_vpe_buf_info(zoom);
+ if (rc < 0) {
+ pr_err("%s Error getting buffer info from mctl rc = %d",
+ __func__, rc);
+ kfree(zoom);
+ break;
+ }
+ rc = msm_vpe_do_pp(zoom);
+ break;
+ }
+
+ case VPE_CMD_ENABLE: {
+ struct msm_vpe_clock_rate clk_rate;
+ int turbo_mode;
+ if (sizeof(struct msm_vpe_clock_rate) != vpe_cmd->length) {
+ pr_err("%s: size mismatch cmd=%d, len=%d, expected=%d",
+ __func__, vpe_cmd->cmd_type, vpe_cmd->length,
+ sizeof(struct msm_vpe_clock_rate));
+ rc = -EINVAL;
+ break;
+ }
+ if (copy_from_user(&clk_rate, (void __user *)vpe_cmd->value,
+ sizeof(struct msm_vpe_clock_rate))) {
+ pr_err("%s:clk_rate copy failed", __func__);
+ return -EFAULT;
+ }
+ turbo_mode = (int)clk_rate.rate;
+ rc = turbo_mode ? vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
+ vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
+ break;
+ }
+
+ case VPE_CMD_DISABLE:
+ rc = vpe_disable();
+ break;
+
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static long msm_vpe_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct msm_vpe_cfg_cmd *vpe_cmd;
+ int rc = 0;
+
+ switch (cmd) {
+ case VIDIOC_MSM_VPE_INIT: {
struct msm_cam_media_controller *mctl =
(struct msm_cam_media_controller *)arg;
msm_vpe_subdev_init(sd, mctl);
- } else if (subdev_cmd == VIDIOC_MSM_VPE_RELEASE) {
+ break;
+ }
+
+ case VIDIOC_MSM_VPE_RELEASE:
msm_vpe_subdev_release();
- } else if (subdev_cmd == VIDIOC_MSM_VPE_CFG) {
- vpe_params = (struct msm_mctl_pp_params *)arg;
- cmd = vpe_params->cmd;
- switch (cmd->id) {
- case VPE_CMD_INIT:
- case VPE_CMD_DEINIT:
- break;
- case VPE_CMD_RESET:
- rc = vpe_reset();
- break;
- case VPE_CMD_OPERATION_MODE_CFG:
- rc = vpe_operation_config(cmd->value);
- break;
- case VPE_CMD_INPUT_PLANE_CFG:
- vpe_input_plane_config(cmd->value);
- break;
- case VPE_CMD_OUTPUT_PLANE_CFG:
- vpe_output_plane_config(cmd->value);
- break;
- case VPE_CMD_SCALE_CFG_TYPE:
- vpe_update_scale_coef(cmd->value);
- break;
- case VPE_CMD_ZOOM: {
- rc = msm_vpe_do_pp(cmd,
- (struct msm_mctl_pp_frame_info *)vpe_params->data);
+ break;
+
+ case MSM_CAM_V4L2_IOCTL_CFG_VPE: {
+ vpe_cmd = (struct msm_vpe_cfg_cmd *)arg;
+ rc = msm_vpe_process_vpe_cmd(vpe_cmd);
+ if (rc < 0) {
+ pr_err("%s Error processing VPE cmd %d ",
+ __func__, vpe_cmd->cmd_type);
break;
}
- case VPE_CMD_ENABLE: {
- struct msm_vpe_clock_rate *clk_rate = cmd->value;
- int turbo_mode = (int)clk_rate->rate;
- rc = turbo_mode ?
- vpe_enable(VPE_TURBO_MODE_CLOCK_RATE) :
- vpe_enable(VPE_NORMAL_MODE_CLOCK_RATE);
- break;
+ break;
}
- case VPE_CMD_DISABLE:
- rc = vpe_disable();
- break;
- case VPE_CMD_INPUT_PLANE_UPDATE:
- case VPE_CMD_FLUSH:
- default:
- break;
+
+ case MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD: {
+ struct msm_device_queue *queue = &vpe_ctrl->eventData_q;
+ struct msm_queue_cmd *event_qcmd;
+ struct msm_mctl_pp_event_info pp_event_info;
+ struct msm_mctl_pp_frame_info *pp_frame_info;
+ struct msm_camera_v4l2_ioctl_t *v4l2_ioctl = arg;
+
+ event_qcmd = msm_dequeue(queue, list_eventdata);
+ if (!event_qcmd) {
+ pr_err("%s No events in the queue", __func__);
+ return -EFAULT;
}
- CDBG("%s: end, id = %d, rc = %d", __func__, cmd->id, rc);
+ pp_frame_info = event_qcmd->command;
+ pp_event_info.event = MCTL_PP_EVENT_CMD_ACK;
+ pp_event_info.ack.cmd = pp_frame_info->user_cmd;
+ pp_event_info.ack.status = 0;
+ pp_event_info.ack.cookie = pp_frame_info->pp_frame_cmd.cookie;
+ D("%s Sending payload %d %d %d", __func__,
+ pp_event_info.ack.cmd, pp_event_info.ack.status,
+ pp_event_info.ack.cookie);
+ if (copy_to_user((void __user *)v4l2_ioctl->ioctl_ptr,
+ &pp_event_info,
+ sizeof(struct msm_mctl_pp_event_info)))
+ pr_err("%s EVENTPAYLOAD Copy to user failed ",
+ __func__);
+ kfree(pp_frame_info);
+ kfree(event_qcmd);
+ break;
+ }
+
+ default:
+ break;
}
return rc;
}
+int msm_vpe_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ D("%s E\n", __func__);
+ return v4l2_event_subscribe(fh, sub, VPE_SUBDEV_MAX_EVENTS);
+}
+
+int msm_vpe_subdev_unsubscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ D("%s E\n", __func__);
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
static const struct v4l2_subdev_core_ops msm_vpe_subdev_core_ops = {
.ioctl = msm_vpe_subdev_ioctl,
+ .subscribe_event = msm_vpe_subdev_subscribe_event,
+ .unsubscribe_event = msm_vpe_subdev_unsubscribe_event,
};
static const struct v4l2_subdev_ops msm_vpe_subdev_ops = {
.core = &msm_vpe_subdev_core_ops,
};
-static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops;
+static int msm_vpe_subdev_open(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct vpe_ctrl_type *vpe_ctrl = v4l2_get_subdevdata(sd);
+ /* Only one client of VPE allowed. */
+ if (atomic_read(&vpe_ctrl->active) != 0) {
+ pr_err("%s already opened\n", __func__);
+ return -EINVAL;
+ }
-static int __devinit vpe_probe(struct platform_device *pdev)
+ D("%s E ", __func__);
+ atomic_inc(&vpe_ctrl->active);
+ return 0;
+}
+
+static int msm_vpe_subdev_close(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh)
+{
+ struct vpe_ctrl_type *vpe_ctrl = v4l2_get_subdevdata(sd);
+ if (atomic_read(&vpe_ctrl->active) == 0) {
+ pr_err("%s already closed\n", __func__);
+ return -EINVAL;
+ }
+
+ D("%s E ", __func__);
+ /* Drain the payload queue. */
+ msm_queue_drain(&vpe_ctrl->eventData_q, list_eventdata);
+ atomic_dec(&vpe_ctrl->active);
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops msm_vpe_internal_ops = {
+ .open = msm_vpe_subdev_open,
+ .close = msm_vpe_subdev_close,
+};
+
+static int __devinit msm_vpe_probe(struct platform_device *pdev)
{
int rc = 0;
- CDBG("%s: device id = %d\n", __func__, pdev->id);
+ struct msm_cam_subdev_info sd_info;
+
+ D("%s: device id = %d\n", __func__, pdev->id);
vpe_ctrl = kzalloc(sizeof(struct vpe_ctrl_type), GFP_KERNEL);
if (!vpe_ctrl) {
- pr_err("%s: no enough memory\n", __func__);
+ pr_err("%s: not enough memory\n", __func__);
return -ENOMEM;
}
@@ -734,6 +986,13 @@
snprintf(vpe_ctrl->subdev.name, sizeof(vpe_ctrl->subdev.name), "vpe");
platform_set_drvdata(pdev, &vpe_ctrl->subdev);
+ media_entity_init(&vpe_ctrl->subdev.entity, 0, NULL, 0);
+ vpe_ctrl->subdev.entity.type = MEDIA_ENT_T_DEVNODE_V4L;
+ vpe_ctrl->subdev.entity.group_id = VPE_DEV;
+ vpe_ctrl->subdev.entity.name = vpe_ctrl->subdev.name;
+
+ vpe_ctrl->subdev.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+
vpe_ctrl->vpemem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "vpe");
if (!vpe_ctrl->vpemem) {
@@ -769,17 +1028,25 @@
disable_irq(vpe_ctrl->vpeirq->start);
+ atomic_set(&vpe_ctrl->active, 0);
vpe_ctrl->pdev = pdev;
- msm_cam_register_subdev_node(&vpe_ctrl->subdev, VPE_DEV, pdev->id);
+ sd_info.sdev_type = VPE_DEV;
+ sd_info.sd_index = pdev->id;
+ sd_info.irq_num = vpe_ctrl->vpeirq->start;
+ msm_cam_register_subdev_node(&vpe_ctrl->subdev, &sd_info);
+ vpe_ctrl->subdev.entity.revision = vpe_ctrl->subdev.devnode->num;
+ msm_queue_init(&vpe_ctrl->eventData_q, "ackevents");
+
return 0;
vpe_no_resource:
+ pr_err("%s: VPE Probe failed.\n", __func__);
kfree(vpe_ctrl);
return 0;
}
-struct platform_driver vpe_driver = {
- .probe = vpe_probe,
+struct platform_driver msm_vpe_driver = {
+ .probe = msm_vpe_probe,
.driver = {
.name = MSM_VPE_DRV_NAME,
.owner = THIS_MODULE,
@@ -788,9 +1055,15 @@
static int __init msm_vpe_init_module(void)
{
- return platform_driver_register(&vpe_driver);
+ return platform_driver_register(&msm_vpe_driver);
+}
+
+static void __exit msm_vpe_exit_module(void)
+{
+ platform_driver_unregister(&msm_vpe_driver);
}
module_init(msm_vpe_init_module);
+module_exit(msm_vpe_exit_module);
MODULE_DESCRIPTION("VPE driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 0d14626..5cf0309 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -79,8 +79,8 @@
#define VPE_DEFAULT_SCALE_CONFIG 0x3c
#define VPE_NORMAL_MODE_CLOCK_RATE 150000000
-#define VPE_TURBO_MODE_CLOCK_RATE 200000000
-
+#define VPE_TURBO_MODE_CLOCK_RATE 200000000
+#define VPE_SUBDEV_MAX_EVENTS 30
/**************************************************/
/*********** End of command id ********************/
@@ -119,6 +119,8 @@
struct regulator *fs_vpe;
struct clk *vpe_clk[2];
struct msm_mctl_pp_frame_info *pp_frame_info;
+ atomic_t active;
+ struct msm_device_queue eventData_q; /*V4L2 Event Payload Queue*/
};
/*
diff --git a/drivers/media/video/msm/msm_vpe1.c b/drivers/media/video/msm/msm_vpe1.c
index 4f97c43..df3630a 100644
--- a/drivers/media/video/msm/msm_vpe1.c
+++ b/drivers/media/video/msm/msm_vpe1.c
@@ -16,6 +16,7 @@
#include <mach/irqs.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/module.h>
#include "msm_vpe1.h"
#include <linux/pm_qos.h>
#include <linux/clk.h>
diff --git a/drivers/media/video/msm/mt9d112.c b/drivers/media/video/msm/mt9d112.c
index a7b5156..4dd0285 100644
--- a/drivers/media/video/msm/mt9d112.c
+++ b/drivers/media/video/msm/mt9d112.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
+#include <linux/module.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include "mt9d112.h"
diff --git a/drivers/media/video/msm/mt9p012.h b/drivers/media/video/msm/mt9p012.h
index 0579813..3df98b7 100644
--- a/drivers/media/video/msm/mt9p012.h
+++ b/drivers/media/video/msm/mt9p012.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -15,6 +15,7 @@
#define MT9T012_H
#include <linux/types.h>
+#include <mach/board.h>
extern struct mt9p012_reg mt9p012_regs; /* from mt9p012_reg.c */
diff --git a/drivers/media/video/msm/mt9p012_km.h b/drivers/media/video/msm/mt9p012_km.h
index aefabd4..0feb331 100644
--- a/drivers/media/video/msm/mt9p012_km.h
+++ b/drivers/media/video/msm/mt9p012_km.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -15,6 +15,7 @@
#define MT9P012_KM_H
#include <linux/types.h>
+#include <mach/board.h>
extern struct mt9p012_km_reg mt9p012_km_regs; /* from mt9p012_km_reg.c */
diff --git a/drivers/media/video/msm/mt9t013.c b/drivers/media/video/msm/mt9t013.c
index e1f6167..b4b5bdd 100644
--- a/drivers/media/video/msm/mt9t013.c
+++ b/drivers/media/video/msm/mt9t013.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -18,6 +18,7 @@
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include <mach/camera.h>
diff --git a/drivers/media/video/msm/mt9t013.h b/drivers/media/video/msm/mt9t013.h
index f6b7c28..6afcb2d 100644
--- a/drivers/media/video/msm/mt9t013.h
+++ b/drivers/media/video/msm/mt9t013.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -15,6 +15,7 @@
#define MT9T013_H
#include <linux/types.h>
+#include <mach/board.h>
extern struct mt9t013_reg mt9t013_regs; /* from mt9t013_reg.c */
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index ea36bf6..5f3f6dd 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -5,6 +5,7 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
obj-$(CONFIG_OV5647) += ov5647_v4l2.o
+obj-$(CONFIG_OV8825) += ov8825_v4l2.o
obj-$(CONFIG_IMX074) += imx074_v4l2.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
obj-$(CONFIG_IMX091) += imx091.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 7e41418..3d23337 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -277,6 +277,7 @@
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t imx074_regs = {
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
index 70c3f6e..49442e9 100644
--- a/drivers/media/video/msm/sensors/imx091.c
+++ b/drivers/media/video/msm/sensors/imx091.c
@@ -304,6 +304,7 @@
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t imx091_regs = {
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index 5b9eb31..8ab3963 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -246,9 +246,6 @@
{
int32_t rc = 0;
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
- PIX_0, ISPIF_OFF_IMMEDIATELY));
s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
msleep(30);
if (update_type == MSM_SENSOR_REG_INIT) {
@@ -268,8 +265,6 @@
v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_CSID_CFG,
&s_ctrl->curr_csi_params->csid_params);
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_CID_CHANGE, NULL);
mb();
v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_CSIPHY_CFG,
@@ -281,9 +276,6 @@
v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
NOTIFY_PCLK_CHANGE, &s_ctrl->msm_sensor_reg->
output_settings[res].op_pixel_clk);
- v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
- NOTIFY_ISPIF_STREAM, (void *)ISPIF_STREAM(
- PIX_0, ISPIF_ON_FRAME_BOUNDARY));
s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
msleep(30);
}
@@ -303,7 +295,7 @@
s_ctrl->msm_sensor_reg->
output_settings[res].line_length_pclk;
- if (s_ctrl->sensordata->pdata->is_csic ||
+ if (s_ctrl->is_csic ||
!s_ctrl->sensordata->csi_if)
rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
MSM_SENSOR_UPDATE_PERIODIC, res);
@@ -330,7 +322,7 @@
s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
s_ctrl->cam_mode = mode;
- if (s_ctrl->sensordata->pdata->is_csic ||
+ if (s_ctrl->is_csic ||
!s_ctrl->sensordata->csi_if)
rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
MSM_SENSOR_REG_INIT, 0);
@@ -383,11 +375,32 @@
return s_ctrl->func_tbl->sensor_config(s_ctrl, argp);
case VIDIOC_MSM_SENSOR_RELEASE:
return msm_sensor_release(s_ctrl);
+ case VIDIOC_MSM_SENSOR_CSID_INFO: {
+ struct msm_sensor_csi_info *csi_info =
+ (struct msm_sensor_csi_info *)arg;
+ s_ctrl->csid_version = csi_info->csid_version;
+ s_ctrl->is_csic = csi_info->is_csic;
+ return 0;
+ }
default:
return -ENOIOCTLCMD;
}
}
+int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+ struct csi_lane_params_t *sensor_output_info)
+{
+ sensor_output_info->csi_lane_assign = s_ctrl->sensordata->
+ sensor_platform_info->csi_lane_params->csi_lane_assign;
+ sensor_output_info->csi_lane_mask = s_ctrl->sensordata->
+ sensor_platform_info->csi_lane_params->csi_lane_mask;
+ sensor_output_info->csi_if = s_ctrl->sensordata->csi_if;
+ sensor_output_info->csid_core = s_ctrl->sensordata->
+ pdata[0].csid_core;
+ sensor_output_info->csid_version = s_ctrl->csid_version;
+ return 0;
+}
+
int32_t msm_sensor_config(struct msm_sensor_ctrl_t *s_ctrl, void __user *argp)
{
struct sensor_cfg_data cdata;
@@ -489,6 +502,37 @@
rc = -EFAULT;
break;
+ case CFG_START_STREAM:
+ if (s_ctrl->func_tbl->sensor_start_stream == NULL) {
+ rc = -EFAULT;
+ break;
+ }
+ s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+ break;
+
+ case CFG_STOP_STREAM:
+ if (s_ctrl->func_tbl->sensor_stop_stream == NULL) {
+ rc = -EFAULT;
+ break;
+ }
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+ break;
+
+ case CFG_GET_CSI_PARAMS:
+ if (s_ctrl->func_tbl->sensor_get_csi_params == NULL) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = s_ctrl->func_tbl->sensor_get_csi_params(
+ s_ctrl,
+ &cdata.cfg.csi_lane_params);
+
+ if (copy_to_user((void *)argp,
+ &cdata,
+ sizeof(struct sensor_cfg_data)))
+ rc = -EFAULT;
+ break;
+
default:
rc = -EFAULT;
break;
@@ -770,8 +814,7 @@
struct v4l2_control *ctrl)
{
int rc = -1, i = 0;
- struct msm_sensor_ctrl_t *s_ctrl =
- (struct msm_sensor_ctrl_t *) sd->dev_priv;
+ struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
struct msm_sensor_v4l2_ctrl_info_t *v4l2_ctrl =
s_ctrl->msm_sensor_v4l2_ctrl_info;
@@ -779,10 +822,10 @@
CDBG("%d\n", ctrl->id);
if (v4l2_ctrl == NULL)
return rc;
-
for (i = 0; i < s_ctrl->num_v4l2_ctrl; i++) {
if (v4l2_ctrl[i].ctrl_id == ctrl->id) {
if (v4l2_ctrl[i].s_v4l2_ctrl != NULL) {
+ CDBG("\n calling msm_sensor_s_ctrl_by_enum\n");
rc = v4l2_ctrl[i].s_v4l2_ctrl(
s_ctrl,
&s_ctrl->msm_sensor_v4l2_ctrl_info[i],
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index c5fbea2..b1e584d 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -84,6 +84,7 @@
struct msm_camera_i2c_conf_array *init_settings;
uint8_t init_size;
struct msm_camera_i2c_conf_array *mode_settings;
+ struct msm_camera_i2c_conf_array *no_effect_settings;
struct msm_sensor_output_info_t *output_settings;
uint8_t num_conf;
};
@@ -136,6 +137,13 @@
int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
int (*sensor_adjust_frame_lines)
(struct msm_sensor_ctrl_t *s_ctrl, uint16_t res);
+ int32_t (*sensor_get_csi_params)(struct msm_sensor_ctrl_t *,
+ struct csi_lane_params_t *);
+};
+
+struct msm_sensor_csi_info {
+ uint32_t csid_version;
+ uint8_t is_csic;
};
struct msm_sensor_ctrl_t {
@@ -151,6 +159,8 @@
struct msm_sensor_reg_t *msm_sensor_reg;
struct msm_sensor_v4l2_ctrl_info_t *msm_sensor_v4l2_ctrl_info;
uint16_t num_v4l2_ctrl;
+ uint32_t csid_version;
+ uint8_t is_csic;
uint16_t curr_line_length_pclk;
uint16_t curr_frame_length_lines;
@@ -240,11 +250,10 @@
long msm_sensor_subdev_ioctl(struct v4l2_subdev *sd,
unsigned int cmd, void *arg);
-struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
+int32_t msm_sensor_get_csi_params(struct msm_sensor_ctrl_t *s_ctrl,
+ struct csi_lane_params_t *sensor_output_info);
-#if defined(CONFIG_OV5647)
- extern int lcd_camera_power_onoff(int on);
-#endif
+struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
#define VIDIOC_MSM_SENSOR_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE + 10, void __user *)
@@ -252,4 +261,7 @@
#define VIDIOC_MSM_SENSOR_RELEASE \
_IO('V', BASE_VIDIOC_PRIVATE + 11)
+#define VIDIOC_MSM_SENSOR_CSID_INFO\
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 12, struct msm_sensor_csi_info *)
+
#endif
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index e6e2d52..69a5498 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -472,6 +472,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t mt9e013_regs = {
diff --git a/drivers/media/video/msm/sensors/mt9m114_v4l2.c b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
index 2184806..806bcc2 100644
--- a/drivers/media/video/msm/sensors/mt9m114_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9m114_v4l2.c
@@ -1268,6 +1268,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t mt9m114_regs = {
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 40867fb..03f1af1 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -784,6 +784,7 @@
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t ov2720_regs = {
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index aac2f2b..d192563 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -458,7 +458,7 @@
CDBG(KERN_ERR "snapshot exposure seting 0x%x, 0x%x, %d"
, gain, line, line);
s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
- if (line > 1964 && line <= 1968) {
+ if (line > 1964) {
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines,
(uint8_t)((line+4) >> 8),
@@ -556,10 +556,10 @@
static int32_t ov5647_write_prev_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t gain, uint32_t line)
{
-
- static uint16_t max_line = 984;
u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
uint8_t gain_lsb, gain_hsb;
+ uint32_t fl_lines = s_ctrl->curr_frame_length_lines;
+ uint8_t offset = s_ctrl->sensor_exp_gain_info->vert_offset;
CDBG(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
gain, line, line);
@@ -567,33 +567,23 @@
gain_lsb = (uint8_t) (gain);
gain_hsb = (uint8_t)((gain & 0x300)>>8);
+ fl_lines = (fl_lines * s_ctrl->fps_divider) / Q10;
+
s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
/* adjust frame rate */
- if (line > 980 && line <= 984) {
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ if (line > (fl_lines - offset))
+ fl_lines = line + offset;
+
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines,
- (uint8_t)((line+4) >> 8),
+ (uint8_t)(fl_lines >> 8),
MSM_CAMERA_I2C_BYTE_DATA);
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
- (uint8_t)((line+4) & 0x00FF),
+ (uint8_t)(fl_lines & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
- max_line = line + 4;
- } else if (max_line > 984) {
-
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_output_reg_addr->frame_length_lines,
- (uint8_t)(984 >> 8),
- MSM_CAMERA_I2C_BYTE_DATA);
-
- msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
- s_ctrl->sensor_output_reg_addr->frame_length_lines + 1 ,
- (uint8_t)(984 & 0x00FF),
- MSM_CAMERA_I2C_BYTE_DATA);
- max_line = 984;
- }
line = line<<4;
/* ov5647 need this operation */
@@ -653,8 +643,6 @@
}
s_ctrl = client->dev.platform_data;
- if (s_ctrl->sensordata->pmic_gpio_enable)
- lcd_camera_power_onoff(0);
return rc;
}
@@ -726,11 +714,6 @@
gpio_direction_output(info->sensor_pwd, 1);
gpio_direction_output(info->sensor_reset, 0);
usleep_range(10000, 11000);
- if (info->pmic_gpio_enable) {
- info->pmic_gpio_enable = 0;
- lcd_camera_power_onoff(1);
- }
- usleep_range(10000, 11000);
rc = msm_sensor_power_up(s_ctrl);
if (rc < 0) {
CDBG("%s: msm_sensor_power_up failed\n", __func__);
@@ -825,6 +808,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = ov5647_sensor_power_up,
.sensor_power_down = ov5647_sensor_power_down,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t ov5647_regs = {
diff --git a/drivers/media/video/msm/sensors/ov7692_v4l2.c b/drivers/media/video/msm/sensors/ov7692_v4l2.c
index e7970d5..c25eba9 100644
--- a/drivers/media/video/msm/sensors/ov7692_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_v4l2.c
@@ -17,6 +17,10 @@
DEFINE_MUTEX(ov7692_mut);
static struct msm_sensor_ctrl_t ov7692_s_ctrl;
+static int effect_value = CAMERA_EFFECT_OFF;
+static unsigned int SAT_U = 0x80; /* DEFAULT SATURATION VALUES*/
+static unsigned int SAT_V = 0x80; /* DEFAULT SATURATION VALUES*/
+
static struct msm_camera_i2c_reg_conf ov7692_start_settings[] = {
{0x0e, 0x00},
};
@@ -168,6 +172,58 @@
ARRAY_SIZE(ov7692_full_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
+static struct msm_camera_i2c_reg_conf ov7692_saturation[][4] = {
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x00, 0x00}, {0xd9, 0x00, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL0*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x10, 0x00}, {0xd9, 0x10, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL1*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x20, 0x00}, {0xd9, 0x20, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL2*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x30, 0x00}, {0xd9, 0x30, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL3*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x40, 0x00}, {0xd9, 0x40, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL4*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x50, 0x00}, {0xd9, 0x50, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL5*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x60, 0x00}, {0xd9, 0x60, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL6*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x70, 0x00}, {0xd9, 0x70, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL7*/
+ {{0x81, 0x33, 0xCC}, {0xd8, 0x80, 0x00}, {0xd9, 0x80, 0x00},
+ {0xd2, 0x02, 0x00},}, /* SATURATION LEVEL8*/
+};
+static struct msm_camera_i2c_conf_array ov7692_saturation_confs[][1] = {
+ {{ov7692_saturation[0], ARRAY_SIZE(ov7692_saturation[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[1], ARRAY_SIZE(ov7692_saturation[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[2], ARRAY_SIZE(ov7692_saturation[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[3], ARRAY_SIZE(ov7692_saturation[3]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[4], ARRAY_SIZE(ov7692_saturation[4]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[5], ARRAY_SIZE(ov7692_saturation[5]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[6], ARRAY_SIZE(ov7692_saturation[6]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[7], ARRAY_SIZE(ov7692_saturation[7]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_saturation[8], ARRAY_SIZE(ov7692_saturation[8]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+static int ov7692_saturation_enum_map[] = {
+ MSM_V4L2_SATURATION_L0,
+ MSM_V4L2_SATURATION_L1,
+ MSM_V4L2_SATURATION_L2,
+ MSM_V4L2_SATURATION_L3,
+ MSM_V4L2_SATURATION_L4,
+ MSM_V4L2_SATURATION_L5,
+ MSM_V4L2_SATURATION_L6,
+ MSM_V4L2_SATURATION_L7,
+ MSM_V4L2_SATURATION_L8,
+};
static struct msm_sensor_output_info_t ov7692_dimensions[] = {
{
.x_output = 0x280,
@@ -180,6 +236,562 @@
},
};
+static struct msm_camera_i2c_enum_conf_array ov7692_saturation_enum_confs = {
+ .conf = &ov7692_saturation_confs[0][0],
+ .conf_enum = ov7692_saturation_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_saturation_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_saturation_confs),
+ .num_conf = ARRAY_SIZE(ov7692_saturation_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_contrast[][16] = {
+ {{0xb2, 0x29}, {0xa3, 0x55}, {0xa4, 0x5b}, {0xa5, 0x67}, {0xa6, 0x7e},
+ {0xa7, 0x89}, {0xa8, 0x93}, {0xa9, 0x9c}, {0xaa, 0xa4},
+ {0xab, 0xac}, {0xac, 0xb3}, {0xad, 0xbe}, {0xae, 0xc7},
+ {0xaf, 0xd5}, {0xb0, 0xdd}, {0xb1, 0xe1},}, /* CONTRAST L0*/
+ {{0xb2, 0x20}, {0xa3, 0x43}, {0xa4, 0x4a}, {0xa5, 0x58}, {0xa6, 0x73},
+ {0xa7, 0x80}, {0xa8, 0x8b}, {0xa9, 0x96}, {0xaa, 0x9f},
+ {0xab, 0xa8}, {0xac, 0xb1}, {0xad, 0xbe}, {0xae, 0xc9},
+ {0xaf, 0xd8}, {0xb0, 0xe2}, {0xb1, 0xe8},}, /* CONTRAST L1*/
+ {{0xb2, 0x18}, {0xa3, 0x31}, {0xa4, 0x39}, {0xa5, 0x4a}, {0xa6, 0x68},
+ {0xa7, 0x77}, {0xa8, 0x84}, {0xa9, 0x90}, {0xaa, 0x9b},
+ {0xab, 0xa5}, {0xac, 0xaf}, {0xad, 0xbe}, {0xae, 0xca},
+ {0xaf, 0xdc}, {0xb0, 0xe7}, {0xb1, 0xee},}, /* CONTRAST L2*/
+ {{0xb2, 0x10}, {0xa3, 0x1f}, {0xa4, 0x28}, {0xa5, 0x3b}, {0xa6, 0x5d},
+ {0xa7, 0x6e}, {0xa8, 0x7d}, {0xa9, 0x8a}, {0xaa, 0x96},
+ {0xab, 0xa2}, {0xac, 0xad}, {0xad, 0xbe}, {0xae, 0xcc},
+ {0xaf, 0xe0}, {0xb0, 0xed}, {0xb1, 0xf4},}, /* CONTRAST L3*/
+ {{0xb2, 0x6}, {0xa3, 0xb}, {0xa4, 0x15}, {0xa5, 0x2a}, {0xa6, 0x51},
+ {0xa7, 0x63}, {0xa8, 0x74}, {0xa9, 0x83}, {0xaa, 0x91},
+ {0xab, 0x9e}, {0xac, 0xaa}, {0xad, 0xbe}, {0xae, 0xce},
+ {0xaf, 0xe5}, {0xb0, 0xf3}, {0xb1, 0xfb},}, /* CONTRAST L4*/
+ {{0xb2, 0xc}, {0xa3, 0x4}, {0xa4, 0xc}, {0xa5, 0x1f}, {0xa6, 0x45},
+ {0xa7, 0x58}, {0xa8, 0x6b}, {0xa9, 0x7c}, {0xaa, 0x8d},
+ {0xab, 0x9d}, {0xac, 0xac}, {0xad, 0xc3}, {0xae, 0xd2},
+ {0xaf, 0xe8}, {0xb0, 0xf2}, {0xb1, 0xf7},}, /* CONTRAST L5*/
+ {{0xb2, 0x1}, {0xa3, 0x2}, {0xa4, 0x9}, {0xa5, 0x1a}, {0xa6, 0x3e},
+ {0xa7, 0x4a}, {0xa8, 0x59}, {0xa9, 0x6a}, {0xaa, 0x79},
+ {0xab, 0x8e}, {0xac, 0xa4}, {0xad, 0xc1}, {0xae, 0xdb},
+ {0xaf, 0xf4}, {0xb0, 0xff}, {0xb1, 0xff},}, /* CONTRAST L6*/
+ {{0xb2, 0xc}, {0xa3, 0x4}, {0xa4, 0x8}, {0xa5, 0x17}, {0xa6, 0x27},
+ {0xa7, 0x3d}, {0xa8, 0x54}, {0xa9, 0x60}, {0xaa, 0x77},
+ {0xab, 0x85}, {0xac, 0xa4}, {0xad, 0xc6}, {0xae, 0xd2},
+ {0xaf, 0xe9}, {0xb0, 0xf0}, {0xb1, 0xf7},}, /* CONTRAST L7*/
+ {{0xb2, 0x1}, {0xa3, 0x4}, {0xa4, 0x4}, {0xa5, 0x7}, {0xa6, 0xb},
+ {0xa7, 0x17}, {0xa8, 0x2a}, {0xa9, 0x41}, {0xaa, 0x59},
+ {0xab, 0x6b}, {0xac, 0x8b}, {0xad, 0xb1}, {0xae, 0xd2},
+ {0xaf, 0xea}, {0xb0, 0xf4}, {0xb1, 0xff},}, /* CONTRAST L8*/
+};
+
+static struct msm_camera_i2c_conf_array ov7692_contrast_confs[][1] = {
+ {{ov7692_contrast[0], ARRAY_SIZE(ov7692_contrast[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[1], ARRAY_SIZE(ov7692_contrast[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[2], ARRAY_SIZE(ov7692_contrast[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[3], ARRAY_SIZE(ov7692_contrast[3]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[4], ARRAY_SIZE(ov7692_contrast[4]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[5], ARRAY_SIZE(ov7692_contrast[5]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[6], ARRAY_SIZE(ov7692_contrast[6]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[7], ARRAY_SIZE(ov7692_contrast[7]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_contrast[8], ARRAY_SIZE(ov7692_contrast[8]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+
+static int ov7692_contrast_enum_map[] = {
+ MSM_V4L2_CONTRAST_L0,
+ MSM_V4L2_CONTRAST_L1,
+ MSM_V4L2_CONTRAST_L2,
+ MSM_V4L2_CONTRAST_L3,
+ MSM_V4L2_CONTRAST_L4,
+ MSM_V4L2_CONTRAST_L5,
+ MSM_V4L2_CONTRAST_L6,
+ MSM_V4L2_CONTRAST_L7,
+ MSM_V4L2_CONTRAST_L8,
+};
+
+static struct msm_camera_i2c_enum_conf_array ov7692_contrast_enum_confs = {
+ .conf = &ov7692_contrast_confs[0][0],
+ .conf_enum = ov7692_contrast_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_contrast_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_contrast_confs),
+ .num_conf = ARRAY_SIZE(ov7692_contrast_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+static struct msm_camera_i2c_reg_conf ov7692_sharpness[][2] = {
+ {{0xb4, 0x20, 0xDF}, {0xb6, 0x00, 0xE0},}, /* SHARPNESS LEVEL 0*/
+ {{0xb4, 0x20, 0xDF}, {0xb6, 0x01, 0xE0},}, /* SHARPNESS LEVEL 1*/
+ {{0xb4, 0x00, 0xDF}, {0xb6, 0x00, 0xE0},}, /* SHARPNESS LEVEL 2*/
+ {{0xb4, 0x20, 0xDF}, {0xb6, 0x66, 0xE0},}, /* SHARPNESS LEVEL 3*/
+ {{0xb4, 0x20, 0xDF}, {0xb6, 0x99, 0xE0},}, /* SHARPNESS LEVEL 4*/
+ {{0xb4, 0x20, 0xDF}, {0xb6, 0xcc, 0xE0},}, /* SHARPNESS LEVEL 5*/
+};
+
+static struct msm_camera_i2c_conf_array ov7692_sharpness_confs[][1] = {
+ {{ov7692_sharpness[0], ARRAY_SIZE(ov7692_sharpness[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_sharpness[1], ARRAY_SIZE(ov7692_sharpness[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_sharpness[2], ARRAY_SIZE(ov7692_sharpness[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_sharpness[3], ARRAY_SIZE(ov7692_sharpness[3]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_sharpness[4], ARRAY_SIZE(ov7692_sharpness[4]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_sharpness[5], ARRAY_SIZE(ov7692_sharpness[5]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+static int ov7692_sharpness_enum_map[] = {
+ MSM_V4L2_SHARPNESS_L0,
+ MSM_V4L2_SHARPNESS_L1,
+ MSM_V4L2_SHARPNESS_L2,
+ MSM_V4L2_SHARPNESS_L3,
+ MSM_V4L2_SHARPNESS_L4,
+ MSM_V4L2_SHARPNESS_L5,
+};
+
+static struct msm_camera_i2c_enum_conf_array ov7692_sharpness_enum_confs = {
+ .conf = &ov7692_sharpness_confs[0][0],
+ .conf_enum = ov7692_sharpness_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_sharpness_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_sharpness_confs),
+ .num_conf = ARRAY_SIZE(ov7692_sharpness_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_exposure[][3] = {
+ {{0x24, 0x50}, {0x25, 0x40}, {0x26, 0xa2},}, /*EXPOSURECOMPENSATIONN2*/
+ {{0x24, 0x70}, {0x25, 0x60}, {0x26, 0xa2},}, /*EXPOSURECOMPENSATIONN1*/
+ {{0x24, 0x86}, {0x25, 0x76}, {0x26, 0xb3},}, /*EXPOSURECOMPENSATIOND*/
+ {{0x24, 0xa8}, {0x25, 0xa0}, {0x26, 0xc4},}, /*EXPOSURECOMPENSATIONp1*/
+ {{0x24, 0xc0}, {0x25, 0xb8}, {0x26, 0xe6},}, /*EXPOSURECOMPENSATIONP2*/
+};
+
+static struct msm_camera_i2c_conf_array ov7692_exposure_confs[][1] = {
+ {{ov7692_exposure[0], ARRAY_SIZE(ov7692_exposure[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_exposure[1], ARRAY_SIZE(ov7692_exposure[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_exposure[2], ARRAY_SIZE(ov7692_exposure[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_exposure[3], ARRAY_SIZE(ov7692_exposure[3]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_exposure[4], ARRAY_SIZE(ov7692_exposure[4]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+static int ov7692_exposure_enum_map[] = {
+ MSM_V4L2_EXPOSURE_N2,
+ MSM_V4L2_EXPOSURE_N1,
+ MSM_V4L2_EXPOSURE_D,
+ MSM_V4L2_EXPOSURE_P1,
+ MSM_V4L2_EXPOSURE_P2,
+};
+
+static struct msm_camera_i2c_enum_conf_array ov7692_exposure_enum_confs = {
+ .conf = &ov7692_exposure_confs[0][0],
+ .conf_enum = ov7692_exposure_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_exposure_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_exposure_confs),
+ .num_conf = ARRAY_SIZE(ov7692_exposure_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_iso[][1] = {
+ {{0x14, 0x20, 0x8F},}, /*ISO_AUTO*/
+ {{0x14, 0x20, 0x8F},}, /*ISO_DEBLUR*/
+ {{0x14, 0x00, 0x8F},}, /*ISO_100*/
+ {{0x14, 0x10, 0x8F},}, /*ISO_200*/
+ {{0x14, 0x20, 0x8F},}, /*ISO_400*/
+ {{0x14, 0x30, 0x8F},}, /*ISO_800*/
+ {{0x14, 0x40, 0x8F},}, /*ISO_1600*/
+};
+
+
+static struct msm_camera_i2c_conf_array ov7692_iso_confs[][1] = {
+ {{ov7692_iso[0], ARRAY_SIZE(ov7692_iso[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_iso[1], ARRAY_SIZE(ov7692_iso[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_iso[2], ARRAY_SIZE(ov7692_iso[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_iso[3], ARRAY_SIZE(ov7692_iso[3]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_iso[4], ARRAY_SIZE(ov7692_iso[4]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_iso[5], ARRAY_SIZE(ov7692_iso[5]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+static int ov7692_iso_enum_map[] = {
+ MSM_V4L2_ISO_AUTO ,
+ MSM_V4L2_ISO_DEBLUR,
+ MSM_V4L2_ISO_100,
+ MSM_V4L2_ISO_200,
+ MSM_V4L2_ISO_400,
+ MSM_V4L2_ISO_800,
+ MSM_V4L2_ISO_1600,
+};
+
+
+static struct msm_camera_i2c_enum_conf_array ov7692_iso_enum_confs = {
+ .conf = &ov7692_iso_confs[0][0],
+ .conf_enum = ov7692_iso_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_iso_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_iso_confs),
+ .num_conf = ARRAY_SIZE(ov7692_iso_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_no_effect[] = {
+ {0x81, 0x00, 0xDF},
+ {0x28, 0x00,},
+ {0xd2, 0x00,},
+ {0xda, 0x80,},
+ {0xdb, 0x80,},
+};
+
+static struct msm_camera_i2c_conf_array ov7692_no_effect_confs[] = {
+ {&ov7692_no_effect[0],
+ ARRAY_SIZE(ov7692_no_effect), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_special_effect[][5] = {
+ {{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x80,},
+ {0xdb, 0x80,},}, /*for special effect OFF*/
+ {{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x80,},
+ {0xdb, 0x80,},}, /*for special effect MONO*/
+ {{0x81, 0x20, 0xDF}, {0x28, 0x80,}, {0xd2, 0x40,}, {0xda, 0x80,},
+ {0xdb, 0x80,},}, /*for special efefct Negative*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*Solarize is not supported by sensor*/
+ {{0x81, 0x20, 0xDF}, {0x28, 0x00,}, {0xd2, 0x18,}, {0xda, 0x40,},
+ {0xdb, 0xa0,},}, /*for sepia*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /* Posteraize not supported */
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /* White board not supported*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*Blackboard not supported*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*Aqua not supported*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*Emboss not supported */
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*sketch not supported*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*Neon not supported*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*MAX value*/
+};
+
+static struct msm_camera_i2c_conf_array ov7692_special_effect_confs[][1] = {
+ {{ov7692_special_effect[0], ARRAY_SIZE(ov7692_special_effect[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[1], ARRAY_SIZE(ov7692_special_effect[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[2], ARRAY_SIZE(ov7692_special_effect[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[3], ARRAY_SIZE(ov7692_special_effect[3]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[4], ARRAY_SIZE(ov7692_special_effect[4]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[5], ARRAY_SIZE(ov7692_special_effect[5]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[6], ARRAY_SIZE(ov7692_special_effect[6]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[7], ARRAY_SIZE(ov7692_special_effect[7]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[8], ARRAY_SIZE(ov7692_special_effect[8]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[9], ARRAY_SIZE(ov7692_special_effect[9]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[10], ARRAY_SIZE(ov7692_special_effect[10]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[11], ARRAY_SIZE(ov7692_special_effect[11]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_special_effect[12], ARRAY_SIZE(ov7692_special_effect[12]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+static int ov7692_special_effect_enum_map[] = {
+ MSM_V4L2_EFFECT_OFF,
+ MSM_V4L2_EFFECT_MONO,
+ MSM_V4L2_EFFECT_NEGATIVE,
+ MSM_V4L2_EFFECT_SOLARIZE,
+ MSM_V4L2_EFFECT_SEPIA,
+ MSM_V4L2_EFFECT_POSTERAIZE,
+ MSM_V4L2_EFFECT_WHITEBOARD,
+ MSM_V4L2_EFFECT_BLACKBOARD,
+ MSM_V4L2_EFFECT_AQUA,
+ MSM_V4L2_EFFECT_EMBOSS,
+ MSM_V4L2_EFFECT_SKETCH,
+ MSM_V4L2_EFFECT_NEON,
+ MSM_V4L2_EFFECT_MAX,
+};
+
+static struct msm_camera_i2c_enum_conf_array
+ ov7692_special_effect_enum_confs = {
+ .conf = &ov7692_special_effect_confs[0][0],
+ .conf_enum = ov7692_special_effect_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_special_effect_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_special_effect_confs),
+ .num_conf = ARRAY_SIZE(ov7692_special_effect_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_antibanding[][2] = {
+ {{0x13, 0x20, 0xDF}, {0x14, 0x16, 0xE8},}, /*ANTIBANDING 60HZ*/
+ {{0x13, 0x20, 0xDF}, {0x14, 0x17, 0xE8},}, /*ANTIBANDING 50HZ*/
+ {{0x13, 0x20, 0xDF}, {0x14, 0x14, 0xE8},}, /* ANTIBANDING AUTO*/
+};
+
+
+static struct msm_camera_i2c_conf_array ov7692_antibanding_confs[][1] = {
+ {{ov7692_antibanding[0], ARRAY_SIZE(ov7692_antibanding[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_antibanding[1], ARRAY_SIZE(ov7692_antibanding[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_antibanding[2], ARRAY_SIZE(ov7692_antibanding[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+static int ov7692_antibanding_enum_map[] = {
+ MSM_V4L2_POWER_LINE_60HZ,
+ MSM_V4L2_POWER_LINE_50HZ,
+ MSM_V4L2_POWER_LINE_AUTO,
+};
+
+
+static struct msm_camera_i2c_enum_conf_array ov7692_antibanding_enum_confs = {
+ .conf = &ov7692_antibanding_confs[0][0],
+ .conf_enum = ov7692_antibanding_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_antibanding_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_antibanding_confs),
+ .num_conf = ARRAY_SIZE(ov7692_antibanding_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+
+static struct msm_camera_i2c_reg_conf ov7692_wb_oem[][4] = {
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},},/*WHITEBALNACE OFF*/
+ {{0x13, 0xf7}, {0x15, 0x00},}, /*WHITEBALNACE AUTO*/
+ {{0x13, 0xf5}, {0x01, 0x56}, {0x02, 0x50},
+ {0x15, 0x00},}, /*WHITEBALNACE CUSTOM*/
+ {{0x13, 0xf5}, {0x01, 0x66}, {0x02, 0x40},
+ {0x15, 0x00},}, /*INCANDISCENT*/
+ {{-1, -1, -1}, {-1, -1, -1}, {-1, -1, -1},
+ {-1, -1, -1},}, /*FLOURESECT NOT SUPPORTED */
+ {{0x13, 0xf5}, {0x01, 0x43}, {0x02, 0x5d},
+ {0x15, 0x00},}, /*DAYLIGHT*/
+ {{0x13, 0xf5}, {0x01, 0x48}, {0x02, 0x63},
+ {0x15, 0x00},}, /*CLOUDY*/
+};
+
+static struct msm_camera_i2c_conf_array ov7692_wb_oem_confs[][1] = {
+ {{ov7692_wb_oem[0], ARRAY_SIZE(ov7692_wb_oem[0]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_wb_oem[1], ARRAY_SIZE(ov7692_wb_oem[1]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_wb_oem[2], ARRAY_SIZE(ov7692_wb_oem[2]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_wb_oem[3], ARRAY_SIZE(ov7692_wb_oem[3]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_wb_oem[4], ARRAY_SIZE(ov7692_wb_oem[4]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_wb_oem[5], ARRAY_SIZE(ov7692_wb_oem[5]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+ {{ov7692_wb_oem[6], ARRAY_SIZE(ov7692_wb_oem[6]), 0,
+ MSM_CAMERA_I2C_SET_BYTE_WRITE_MASK_DATA},},
+};
+
+static int ov7692_wb_oem_enum_map[] = {
+ MSM_V4L2_WB_OFF,
+ MSM_V4L2_WB_AUTO ,
+ MSM_V4L2_WB_CUSTOM,
+ MSM_V4L2_WB_INCANDESCENT,
+ MSM_V4L2_WB_FLUORESCENT,
+ MSM_V4L2_WB_DAYLIGHT,
+ MSM_V4L2_WB_CLOUDY_DAYLIGHT,
+};
+
+static struct msm_camera_i2c_enum_conf_array ov7692_wb_oem_enum_confs = {
+ .conf = &ov7692_wb_oem_confs[0][0],
+ .conf_enum = ov7692_wb_oem_enum_map,
+ .num_enum = ARRAY_SIZE(ov7692_wb_oem_enum_map),
+ .num_index = ARRAY_SIZE(ov7692_wb_oem_confs),
+ .num_conf = ARRAY_SIZE(ov7692_wb_oem_confs[0]),
+ .data_type = MSM_CAMERA_I2C_BYTE_DATA,
+};
+
+
+int ov7692_saturation_msm_sensor_s_ctrl_by_enum(
+ struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+ int rc = 0;
+ if (effect_value == CAMERA_EFFECT_OFF) {
+ rc = msm_sensor_write_enum_conf_array(
+ s_ctrl->sensor_i2c_client,
+ ctrl_info->enum_cfg_settings, value);
+ }
+ if (value <= MSM_V4L2_SATURATION_L8)
+ SAT_U = SAT_V = value * 0x10;
+ CDBG("--CAMERA-- %s ...(End)\n", __func__);
+ return rc;
+}
+
+
+int ov7692_contrast_msm_sensor_s_ctrl_by_enum(
+ struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+ int rc = 0;
+ if (effect_value == CAMERA_EFFECT_OFF) {
+ rc = msm_sensor_write_enum_conf_array(
+ s_ctrl->sensor_i2c_client,
+ ctrl_info->enum_cfg_settings, value);
+ }
+ return rc;
+}
+
+int ov7692_sharpness_msm_sensor_s_ctrl_by_enum(
+ struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+ int rc = 0;
+ if (effect_value == CAMERA_EFFECT_OFF) {
+ rc = msm_sensor_write_enum_conf_array(
+ s_ctrl->sensor_i2c_client,
+ ctrl_info->enum_cfg_settings, value);
+ }
+ return rc;
+}
+
+int ov7692_effect_msm_sensor_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+ int rc = 0;
+ effect_value = value;
+ if (effect_value == CAMERA_EFFECT_OFF) {
+ rc = msm_sensor_write_conf_array(
+ s_ctrl->sensor_i2c_client,
+ s_ctrl->msm_sensor_reg->no_effect_settings, 0);
+ if (rc < 0) {
+ CDBG("write faield\n");
+ return rc;
+ }
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0xda, SAT_U,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0xdb, SAT_V,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ } else {
+ rc = msm_sensor_write_enum_conf_array(
+ s_ctrl->sensor_i2c_client,
+ ctrl_info->enum_cfg_settings, value);
+ }
+ return rc;
+}
+
+int ov7692_antibanding_msm_sensor_s_ctrl_by_enum(
+ struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+ int rc = 0;
+ return rc;
+}
+
+int ov7692_msm_sensor_s_ctrl_by_enum(struct msm_sensor_ctrl_t *s_ctrl,
+ struct msm_sensor_v4l2_ctrl_info_t *ctrl_info, int value)
+{
+ int rc = 0;
+ rc = msm_sensor_write_enum_conf_array(
+ s_ctrl->sensor_i2c_client,
+ ctrl_info->enum_cfg_settings, value);
+ if (rc < 0) {
+ CDBG("write faield\n");
+ return rc;
+ }
+ return rc;
+}
+
+struct msm_sensor_v4l2_ctrl_info_t ov7692_v4l2_ctrl_info[] = {
+ {
+ .ctrl_id = V4L2_CID_SATURATION,
+ .min = MSM_V4L2_SATURATION_L0,
+ .max = MSM_V4L2_SATURATION_L8,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_saturation_enum_confs,
+ .s_v4l2_ctrl = ov7692_saturation_msm_sensor_s_ctrl_by_enum,
+ },
+ {
+ .ctrl_id = V4L2_CID_CONTRAST,
+ .min = MSM_V4L2_CONTRAST_L0,
+ .max = MSM_V4L2_CONTRAST_L8,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_contrast_enum_confs,
+ .s_v4l2_ctrl = ov7692_contrast_msm_sensor_s_ctrl_by_enum,
+ },
+ {
+ .ctrl_id = V4L2_CID_SHARPNESS,
+ .min = MSM_V4L2_SHARPNESS_L0,
+ .max = MSM_V4L2_SHARPNESS_L5,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_sharpness_enum_confs,
+ .s_v4l2_ctrl = ov7692_sharpness_msm_sensor_s_ctrl_by_enum,
+ },
+ {
+ .ctrl_id = V4L2_CID_EXPOSURE,
+ .min = MSM_V4L2_EXPOSURE_N2,
+ .max = MSM_V4L2_EXPOSURE_P2,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_exposure_enum_confs,
+ .s_v4l2_ctrl = ov7692_msm_sensor_s_ctrl_by_enum,
+ },
+ {
+ .ctrl_id = MSM_V4L2_PID_ISO,
+ .min = MSM_V4L2_ISO_AUTO,
+ .max = MSM_V4L2_ISO_1600,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_iso_enum_confs,
+ .s_v4l2_ctrl = ov7692_msm_sensor_s_ctrl_by_enum,
+ },
+ {
+ .ctrl_id = V4L2_CID_SPECIAL_EFFECT,
+ .min = MSM_V4L2_EFFECT_OFF,
+ .max = MSM_V4L2_EFFECT_NEGATIVE,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_special_effect_enum_confs,
+ .s_v4l2_ctrl = ov7692_effect_msm_sensor_s_ctrl_by_enum,
+ },
+ {
+ .ctrl_id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .min = MSM_V4L2_POWER_LINE_60HZ,
+ .max = MSM_V4L2_POWER_LINE_AUTO,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_antibanding_enum_confs,
+ .s_v4l2_ctrl = ov7692_antibanding_msm_sensor_s_ctrl_by_enum,
+ },
+ {
+ .ctrl_id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ .min = MSM_V4L2_WB_OFF,
+ .max = MSM_V4L2_WB_CLOUDY_DAYLIGHT,
+ .step = 1,
+ .enum_cfg_settings = &ov7692_wb_oem_enum_confs,
+ .s_v4l2_ctrl = ov7692_msm_sensor_s_ctrl_by_enum,
+ },
+
+};
static struct msm_camera_csi_params ov7692_csi_params = {
.data_format = CSI_8BIT,
@@ -234,6 +846,8 @@
}
static struct v4l2_subdev_core_ops ov7692_subdev_core_ops = {
+ .s_ctrl = msm_sensor_v4l2_s_ctrl,
+ .queryctrl = msm_sensor_v4l2_query_ctrl,
.ioctl = msm_sensor_subdev_ioctl,
.s_power = msm_sensor_power,
};
@@ -247,44 +861,6 @@
.video = &ov7692_subdev_video_ops,
};
-int32_t ov7692_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
-{
- int32_t rc = 0;
- struct msm_camera_sensor_info *info = NULL;
-
- info = s_ctrl->sensordata;
- if (info->pmic_gpio_enable) {
- info->sensor_lcd_gpio_onoff(1);
- usleep_range(5000, 5100);
- }
-
- rc = msm_sensor_power_up(s_ctrl);
- if (rc < 0) {
- CDBG("%s: msm_sensor_power_up failed\n", __func__);
- return rc;
- }
-
- return rc;
-}
-
-int32_t ov7692_sensor_power_down(struct msm_sensor_ctrl_t *s_ctrl)
-{
- int32_t rc = 0;
- struct msm_camera_sensor_info *info = NULL;
-
- rc = msm_sensor_power_down(s_ctrl);
- if (rc < 0)
- CDBG("%s: msm_sensor_power_down failed\n", __func__);
-
- info = s_ctrl->sensordata;
- if (info->pmic_gpio_enable) {
- info->pmic_gpio_enable = 0;
- info->sensor_lcd_gpio_onoff(0);
- usleep_range(5000, 5100);
- }
- return rc;
-}
-
static struct msm_sensor_fn_t ov7692_func_tbl = {
.sensor_start_stream = msm_sensor_start_stream,
.sensor_stop_stream = msm_sensor_stop_stream,
@@ -293,8 +869,9 @@
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
.sensor_config = msm_sensor_config,
- .sensor_power_up = ov7692_sensor_power_up,
- .sensor_power_down = ov7692_sensor_power_down,
+ .sensor_power_up = msm_sensor_power_up,
+ .sensor_power_down = msm_sensor_power_down,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t ov7692_regs = {
@@ -306,12 +883,15 @@
.init_settings = &ov7692_init_conf[0],
.init_size = ARRAY_SIZE(ov7692_init_conf),
.mode_settings = &ov7692_confs[0],
+ .no_effect_settings = &ov7692_no_effect_confs[0],
.output_settings = &ov7692_dimensions[0],
.num_conf = ARRAY_SIZE(ov7692_confs),
};
static struct msm_sensor_ctrl_t ov7692_s_ctrl = {
.msm_sensor_reg = &ov7692_regs,
+ .msm_sensor_v4l2_ctrl_info = ov7692_v4l2_ctrl_info,
+ .num_v4l2_ctrl = ARRAY_SIZE(ov7692_v4l2_ctrl_info),
.sensor_i2c_client = &ov7692_sensor_i2c_client,
.sensor_i2c_addr = 0x78,
.sensor_output_reg_addr = &ov7692_reg_addr,
diff --git a/drivers/media/video/msm/sensors/ov8825_v4l2.c b/drivers/media/video/msm/sensors/ov8825_v4l2.c
new file mode 100644
index 0000000..9f09208
--- /dev/null
+++ b/drivers/media/video/msm/sensors/ov8825_v4l2.c
@@ -0,0 +1,968 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 "msm_sensor.h"
+#include "msm.h"
+#define SENSOR_NAME "ov8825"
+#define PLATFORM_DRIVER_NAME "msm_camera_ov8825"
+#define ov8825_obj ov8825_##obj
+
+/* TO DO - Currently ov5647 typical values are used
+ * Need to get the exact values */
+#define OV8825_RG_RATIO_TYPICAL_VALUE 64 /* R/G of typical camera module */
+#define OV8825_BG_RATIO_TYPICAL_VALUE 105 /* B/G of typical camera module */
+
+DEFINE_MUTEX(ov8825_mut);
+static struct msm_sensor_ctrl_t ov8825_s_ctrl;
+
+struct otp_struct {
+ uint8_t customer_id;
+ uint8_t module_integrator_id;
+ uint8_t lens_id;
+ uint8_t rg_ratio;
+ uint8_t bg_ratio;
+ uint8_t user_data[5];
+} st_ov8825_otp;
+
+static struct msm_camera_i2c_reg_conf ov8825_start_settings[] = {
+ {0x0100, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov8825_stop_settings[] = {
+ {0x0100, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf ov8825_groupon_settings[] = {
+ {0x3208, 0x00},
+};
+
+static struct msm_camera_i2c_reg_conf ov8825_groupoff_settings[] = {
+ {0x3208, 0x10},
+ {0x3208, 0xA0},
+};
+
+static struct msm_camera_i2c_reg_conf ov8825_prev_settings[] = {
+ {0x3003, 0xce}, /*PLL_CTRL0*/
+ {0x3004, 0xd4}, /*PLL_CTRL1*/
+ {0x3005, 0x00}, /*PLL_CTRL2*/
+ {0x3006, 0x10}, /*PLL_CTRL3*/
+ {0x3007, 0x3b}, /*PLL_CTRL4*/
+ {0x3011, 0x01}, /*MIPI_Lane_4_Lane*/
+ {0x3012, 0x80}, /*SC_PLL CTRL_S0*/
+ {0x3013, 0x39}, /*SC_PLL CTRL_S1*/
+ {0x3104, 0x20}, /*SCCB_PLL*/
+ {0x3106, 0x15}, /*SRB_CTRL*/
+ {0x3501, 0x4e}, /*AEC_HIGH*/
+ {0x3502, 0xa0}, /*AEC_LOW*/
+ {0x350b, 0x1f}, /*AGC*/
+ {0x3600, 0x06}, /*ANACTRL0*/
+ {0x3601, 0x34}, /*ANACTRL1*/
+ {0x3700, 0x20}, /*SENCTROL0 Sensor control*/
+ {0x3702, 0x50}, /*SENCTROL2 Sensor control*/
+ {0x3703, 0xcc}, /*SENCTROL3 Sensor control*/
+ {0x3704, 0x19}, /*SENCTROL4 Sensor control*/
+ {0x3705, 0x14}, /*SENCTROL5 Sensor control*/
+ {0x3706, 0x4b}, /*SENCTROL6 Sensor control*/
+ {0x3707, 0x63}, /*SENCTROL7 Sensor control*/
+ {0x3708, 0x84}, /*SENCTROL8 Sensor control*/
+ {0x3709, 0x40}, /*SENCTROL9 Sensor control*/
+ {0x370a, 0x12}, /*SENCTROLA Sensor control*/
+ {0x370e, 0x00}, /*SENCTROLE Sensor control*/
+ {0x3711, 0x0f}, /*SENCTROL11 Sensor control*/
+ {0x3712, 0x9c}, /*SENCTROL12 Sensor control*/
+ {0x3724, 0x01}, /*Reserved*/
+ {0x3725, 0x92}, /*Reserved*/
+ {0x3726, 0x01}, /*Reserved*/
+ {0x3727, 0xa9}, /*Reserved*/
+ {0x3800, 0x00}, /*HS(HREF start High)*/
+ {0x3801, 0x00}, /*HS(HREF start Low)*/
+ {0x3802, 0x00}, /*VS(Vertical start High)*/
+ {0x3803, 0x00}, /*VS(Vertical start Low)*/
+ {0x3804, 0x0c}, /*HW = 3295*/
+ {0x3805, 0xdf}, /*HW*/
+ {0x3806, 0x09}, /*VH = 2459*/
+ {0x3807, 0x9b}, /*VH*/
+ {0x3808, 0x06}, /*ISPHO = 1632*/
+ {0x3809, 0x60}, /*ISPHO*/
+ {0x380a, 0x04}, /*ISPVO = 1224*/
+ {0x380b, 0xc8}, /*ISPVO*/
+ {0x380c, 0x0d}, /*HTS = 3516*/
+ {0x380d, 0xbc}, /*HTS*/
+ {0x380e, 0x04}, /*VTS = 1264*/
+ {0x380f, 0xf0}, /*VTS*/
+ {0x3810, 0x00}, /*HOFF = 8*/
+ {0x3811, 0x08}, /*HOFF*/
+ {0x3812, 0x00}, /*VOFF = 4*/
+ {0x3813, 0x04}, /*VOFF*/
+ {0x3814, 0x31}, /*X INC*/
+ {0x3815, 0x31}, /*Y INC*/
+ {0x3820, 0x81}, /*Timing Reg20:Vflip*/
+ {0x3821, 0x17}, /*Timing Reg21:Hmirror*/
+ {0x3f00, 0x00}, /*PSRAM Ctrl0*/
+ {0x3f01, 0xfc}, /*PSRAM Ctrl1*/
+ {0x3f05, 0x10}, /*PSRAM Ctrl5*/
+ {0x4600, 0x04}, /*VFIFO Ctrl0*/
+ {0x4601, 0x00}, /*VFIFO Read ST High*/
+ {0x4602, 0x30}, /*VFIFO Read ST Low*/
+ {0x4837, 0x28}, /*MIPI PCLK PERIOD*/
+ {0x5068, 0x00}, /*HSCALE_CTRL*/
+ {0x506a, 0x00}, /*VSCALE_CTRL*/
+ {0x5c00, 0x80}, /*PBLC CTRL00*/
+ {0x5c01, 0x00}, /*PBLC CTRL01*/
+ {0x5c02, 0x00}, /*PBLC CTRL02*/
+ {0x5c03, 0x00}, /*PBLC CTRL03*/
+ {0x5c04, 0x00}, /*PBLC CTRL04*/
+ {0x5c08, 0x10}, /*PBLC CTRL08*/
+ {0x6900, 0x61}, /*CADC CTRL00*/
+};
+
+static struct msm_camera_i2c_reg_conf ov8825_snap_settings[] = {
+ {0x3003, 0xce}, /*PLL_CTRL0*/
+ {0x3004, 0xd8}, /*PLL_CTRL1*/
+ {0x3005, 0x00}, /*PLL_CTRL2*/
+ {0x3006, 0x10}, /*PLL_CTRL3*/
+ {0x3007, 0x3b}, /*PLL_CTRL4*/
+ {0x3011, 0x01}, /*MIPI_Lane_4_Lane*/
+ {0x3012, 0x81}, /*SC_PLL CTRL_S0*/
+ {0x3013, 0x39}, /*SC_PLL CTRL_S1*/
+ {0x3104, 0x20}, /*SCCB_PLL*/
+ {0x3106, 0x11}, /*SRB_CTRL*/
+ {0x3501, 0x9a}, /*AEC_HIGH*/
+ {0x3502, 0xa0}, /*AEC_LOW*/
+ {0x350b, 0x1f}, /*AGC*/
+ {0x3600, 0x07}, /*ANACTRL0*/
+ {0x3601, 0x33}, /*ANACTRL1*/
+ {0x3700, 0x10}, /*SENCTROL0 Sensor control*/
+ {0x3702, 0x28}, /*SENCTROL2 Sensor control*/
+ {0x3703, 0x6c}, /*SENCTROL3 Sensor control*/
+ {0x3704, 0x8d}, /*SENCTROL4 Sensor control*/
+ {0x3705, 0x0a}, /*SENCTROL5 Sensor control*/
+ {0x3706, 0x27}, /*SENCTROL6 Sensor control*/
+ {0x3707, 0x63}, /*SENCTROL7 Sensor control*/
+ {0x3708, 0x40}, /*SENCTROL8 Sensor control*/
+ {0x3709, 0x20}, /*SENCTROL9 Sensor control*/
+ {0x370a, 0x12}, /*SENCTROLA Sensor control*/
+ {0x370e, 0x00}, /*SENCTROLE Sensor control*/
+ {0x3711, 0x07}, /*SENCTROL11 Sensor control*/
+ {0x3712, 0x4e}, /*SENCTROL12 Sensor control*/
+ {0x3724, 0x00}, /*Reserved*/
+ {0x3725, 0xd4}, /*Reserved*/
+ {0x3726, 0x00}, /*Reserved*/
+ {0x3727, 0xe1}, /*Reserved*/
+ {0x3800, 0x00}, /*HS(HREF start High)*/
+ {0x3801, 0x00}, /*HS(HREF start Low)*/
+ {0x3802, 0x00}, /*VS(Vertical start Hgh)*/
+ {0x3803, 0x00}, /*VS(Vertical start Low)*/
+ {0x3804, 0x0c}, /*HW = 3295*/
+ {0x3805, 0xdf}, /*HW*/
+ {0x3806, 0x09}, /*VH = 2459*/
+ {0x3807, 0x9b}, /*VH*/
+ {0x3808, 0x0c}, /*ISPHO = 1632*/
+ {0x3809, 0xc0}, /*ISPHO*/
+ {0x380a, 0x09}, /*ISPVO = 1224*/
+ {0x380b, 0x90}, /*ISPVO*/
+ {0x380c, 0x0e}, /*HTS = 3516*/
+ {0x380d, 0x00}, /*HTS*/
+ {0x380e, 0x09}, /*VTS = 1264*/
+ {0x380f, 0xb0}, /*VTS*/
+ {0x3810, 0x00}, /*HOFF = 8*/
+ {0x3811, 0x10}, /*HOFF*/
+ {0x3812, 0x00}, /*VOFF = 4*/
+ {0x3813, 0x06}, /*VOFF*/
+ {0x3814, 0x11}, /*X INC*/
+ {0x3815, 0x11}, /*Y INC*/
+ {0x3820, 0x80}, /*Timing Reg20:Vflip*/
+ {0x3821, 0x16}, /*Timing Reg21:Hmirror*/
+ {0x3f00, 0x02}, /*PSRAM Ctrl0*/
+ {0x3f01, 0xfc}, /*PSRAM Ctrl1*/
+ {0x3f05, 0x10}, /*PSRAM Ctrl5*/
+ {0x4600, 0x04}, /*VFIFO Ctrl0*/
+ {0x4601, 0x00}, /*VFIFO Read ST High*/
+ {0x4602, 0x78}, /*VFIFO Read ST Low*/
+ {0x4837, 0x28}, /*MIPI PCLK PERIOD*/
+ {0x5068, 0x00}, /*HSCALE_CTRL*/
+ {0x506a, 0x00}, /*VSCALE_CTRL*/
+ {0x5c00, 0x80}, /*PBLC CTRL00*/
+ {0x5c01, 0x00}, /*PBLC CTRL01*/
+ {0x5c02, 0x00}, /*PBLC CTRL02*/
+ {0x5c03, 0x00}, /*PBLC CTRL03*/
+ {0x5c04, 0x00}, /*PBLC CTRL04*/
+ {0x5c08, 0x10}, /*PBLC CTRL08*/
+ {0x6900, 0x61}, /*CADC CTRL00*/
+};
+
+
+static struct msm_camera_i2c_reg_conf ov8825_reset_settings[] = {
+ {0x0103, 0x01},
+};
+
+static struct msm_camera_i2c_reg_conf ov8825_recommend_settings[] = {
+ {0x3000, 0x16},
+ {0x3001, 0x00},
+ {0x3002, 0x6c},
+ {0x300d, 0x00},
+ {0x301f, 0x09},
+ {0x3010, 0x00},
+ {0x3018, 0x00},
+ {0x3300, 0x00},
+ {0x3500, 0x00},
+ {0x3503, 0x07},
+ {0x3509, 0x00},
+ {0x3602, 0x42},
+ {0x3603, 0x5c},
+ {0x3604, 0x98},
+ {0x3605, 0xf5},
+ {0x3609, 0xb4},
+ {0x360a, 0x7c},
+ {0x360b, 0xc9},
+ {0x360c, 0x0b},
+ {0x3612, 0x00},
+ {0x3613, 0x02},
+ {0x3614, 0x0f},
+ {0x3615, 0x00},
+ {0x3616, 0x03},
+ {0x3617, 0xa1},
+ {0x3618, 0x00},
+ {0x3619, 0x00},
+ {0x361a, 0xB0},
+ {0x361b, 0x04},
+ {0x3701, 0x44},
+ {0x370b, 0x01},
+ {0x370c, 0x50},
+ {0x370d, 0x00},
+ {0x3816, 0x02},
+ {0x3817, 0x40},
+ {0x3818, 0x00},
+ {0x3819, 0x40},
+ {0x3b1f, 0x00},
+ {0x3d00, 0x00},
+ {0x3d01, 0x00},
+ {0x3d02, 0x00},
+ {0x3d03, 0x00},
+ {0x3d04, 0x00},
+ {0x3d05, 0x00},
+ {0x3d06, 0x00},
+ {0x3d07, 0x00},
+ {0x3d08, 0x00},
+ {0x3d09, 0x00},
+ {0x3d0a, 0x00},
+ {0x3d0b, 0x00},
+ {0x3d0c, 0x00},
+ {0x3d0d, 0x00},
+ {0x3d0e, 0x00},
+ {0x3d0f, 0x00},
+ {0x3d10, 0x00},
+ {0x3d11, 0x00},
+ {0x3d12, 0x00},
+ {0x3d13, 0x00},
+ {0x3d14, 0x00},
+ {0x3d15, 0x00},
+ {0x3d16, 0x00},
+ {0x3d17, 0x00},
+ {0x3d18, 0x00},
+ {0x3d19, 0x00},
+ {0x3d1a, 0x00},
+ {0x3d1b, 0x00},
+ {0x3d1c, 0x00},
+ {0x3d1d, 0x00},
+ {0x3d1e, 0x00},
+ {0x3d1f, 0x00},
+ {0x3d80, 0x00},
+ {0x3d81, 0x00},
+ {0x3d84, 0x00},
+ {0x3f06, 0x00},
+ {0x3f07, 0x00},
+ {0x4000, 0x29},
+ {0x4001, 0x02},
+ {0x4002, 0x45},
+ {0x4003, 0x08},
+ {0x4004, 0x04},
+ {0x4005, 0x18},
+ {0x4300, 0xff},
+ {0x4303, 0x00},
+ {0x4304, 0x08},
+ {0x4307, 0x00},
+ {0x4800, 0x04},
+ {0x4801, 0x0f},
+ {0x4843, 0x02},
+ {0x5000, 0x06},
+ {0x5001, 0x00},
+ {0x5002, 0x00},
+ {0x501f, 0x00},
+ {0x5780, 0xfc},
+ {0x5c05, 0x00},
+ {0x5c06, 0x00},
+ {0x5c07, 0x80},
+ {0x6700, 0x05},
+ {0x6701, 0x19},
+ {0x6702, 0xfd},
+ {0x6703, 0xd7},
+ {0x6704, 0xff},
+ {0x6705, 0xff},
+ {0x6800, 0x10},
+ {0x6801, 0x02},
+ {0x6802, 0x90},
+ {0x6803, 0x10},
+ {0x6804, 0x59},
+ {0x6901, 0x04},
+ {0x5800, 0x0f},
+ {0x5801, 0x0d},
+ {0x5802, 0x09},
+ {0x5803, 0x0a},
+ {0x5804, 0x0d},
+ {0x5805, 0x14},
+ {0x5806, 0x0a},
+ {0x5807, 0x04},
+ {0x5808, 0x03},
+ {0x5809, 0x03},
+ {0x580a, 0x05},
+ {0x580b, 0x0a},
+ {0x580c, 0x05},
+ {0x580d, 0x02},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x05},
+ {0x5812, 0x09},
+ {0x5813, 0x03},
+ {0x5814, 0x01},
+ {0x5815, 0x01},
+ {0x5816, 0x04},
+ {0x5817, 0x09},
+ {0x5818, 0x09},
+ {0x5819, 0x08},
+ {0x581a, 0x06},
+ {0x581b, 0x06},
+ {0x581c, 0x08},
+ {0x581d, 0x06},
+ {0x581e, 0x33},
+ {0x581f, 0x11},
+ {0x5820, 0x0e},
+ {0x5821, 0x0f},
+ {0x5822, 0x11},
+ {0x5823, 0x3f},
+ {0x5824, 0x08},
+ {0x5825, 0x46},
+ {0x5826, 0x46},
+ {0x5827, 0x46},
+ {0x5828, 0x46},
+ {0x5829, 0x46},
+ {0x582a, 0x42},
+ {0x582b, 0x42},
+ {0x582c, 0x44},
+ {0x582d, 0x46},
+ {0x582e, 0x46},
+ {0x582f, 0x60},
+ {0x5830, 0x62},
+ {0x5831, 0x42},
+ {0x5832, 0x46},
+ {0x5833, 0x46},
+ {0x5834, 0x44},
+ {0x5835, 0x44},
+ {0x5836, 0x44},
+ {0x5837, 0x48},
+ {0x5838, 0x28},
+ {0x5839, 0x46},
+ {0x583a, 0x48},
+ {0x583b, 0x68},
+ {0x583c, 0x28},
+ {0x583d, 0xae},
+ {0x5842, 0x00},
+ {0x5843, 0xef},
+ {0x5844, 0x01},
+ {0x5845, 0x3f},
+ {0x5846, 0x01},
+ {0x5847, 0x3f},
+ {0x5848, 0x00},
+ {0x5849, 0xd5},
+ {0x3503, 0x07},
+ {0x3500, 0x00},
+ {0x3501, 0x27},
+ {0x3502, 0x00},
+ {0x350b, 0xff},
+ {0x3400, 0x04},
+ {0x3401, 0x00},
+ {0x3402, 0x04},
+ {0x3403, 0x00},
+ {0x3404, 0x04},
+ {0x3405, 0x00},
+ {0x3406, 0x01},
+ {0x5001, 0x01},
+ {0x5000, 0x86},/* enable lens compensation and dpc */
+ /* LENC setting 70% */
+ {0x5800, 0x21},
+ {0x5801, 0x10},
+ {0x5802, 0x09},
+ {0x5803, 0x0a},
+ {0x5804, 0x0f},
+ {0x5805, 0x23},
+ {0x5806, 0x08},
+ {0x5807, 0x04},
+ {0x5808, 0x04},
+ {0x5809, 0x04},
+ {0x580a, 0x04},
+ {0x580b, 0x0a},
+ {0x580c, 0x04},
+ {0x580d, 0x02},
+ {0x580e, 0x00},
+ {0x580f, 0x00},
+ {0x5810, 0x03},
+ {0x5811, 0x06},
+ {0x5812, 0x05},
+ {0x5813, 0x02},
+ {0x5814, 0x00},
+ {0x5815, 0x00},
+ {0x5816, 0x03},
+ {0x5817, 0x06},
+ {0x5818, 0x09},
+ {0x5819, 0x05},
+ {0x581a, 0x04},
+ {0x581b, 0x04},
+ {0x581c, 0x05},
+ {0x581d, 0x0a},
+ {0x581e, 0x24},
+ {0x581f, 0x11},
+ {0x5820, 0x0a},
+ {0x5821, 0x0a},
+ {0x5822, 0x10},
+ {0x5823, 0x27},
+ {0x5824, 0x2a},
+ {0x5825, 0x58},
+ {0x5826, 0x28},
+ {0x5827, 0x28},
+ {0x5828, 0x28},
+ {0x5829, 0x28},
+ {0x582a, 0x46},
+ {0x582b, 0x44},
+ {0x582c, 0x46},
+ {0x582d, 0x46},
+ {0x582e, 0x28},
+ {0x582f, 0x62},
+ {0x5830, 0x60},
+ {0x5831, 0x42},
+ {0x5832, 0x28},
+ {0x5833, 0x48},
+ {0x5834, 0x46},
+ {0x5835, 0x46},
+ {0x5836, 0x26},
+ {0x5837, 0x46},
+ {0x5838, 0x28},
+ {0x5839, 0x48},
+ {0x583a, 0x28},
+ {0x583b, 0x28},
+ {0x583c, 0x26},
+ {0x583d, 0x9d},
+};
+
+static struct v4l2_subdev_info ov8825_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+ /* more can be supported, to be added later */
+};
+
+static struct msm_camera_i2c_conf_array ov8825_init_conf[] = {
+ {&ov8825_reset_settings[0],
+ ARRAY_SIZE(ov8825_reset_settings), 50, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov8825_recommend_settings[0],
+ ARRAY_SIZE(ov8825_recommend_settings), 0, MSM_CAMERA_I2C_BYTE_DATA}
+};
+
+static struct msm_camera_i2c_conf_array ov8825_confs[] = {
+ {&ov8825_snap_settings[0],
+ ARRAY_SIZE(ov8825_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov8825_prev_settings[0],
+ ARRAY_SIZE(ov8825_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+};
+
+static struct msm_sensor_output_info_t ov8825_dimensions[] = {
+ {
+ .x_output = 0xCC0,
+ .y_output = 0x990,
+ .line_length_pclk = 0xE00,
+ .frame_length_lines = 0x9B0,
+ .vt_pixel_clk = 133400000,
+ .op_pixel_clk = 176000000,
+ .binning_factor = 1,
+ },
+ {
+ .x_output = 0x660,
+ .y_output = 0x4C8,
+ .line_length_pclk = 0x6DE,
+ .frame_length_lines = 0x505,
+ .vt_pixel_clk = 66700000,
+ .op_pixel_clk = 88000000,
+ .binning_factor = 2,
+ },
+};
+
+static struct msm_camera_csi_params ov8825_csi_params = {
+ .data_format = CSI_10BIT,
+ .lane_cnt = 2,
+ .lane_assign = 0xe4,
+ .dpcm_scheme = 0,
+ .settle_cnt = 14,
+};
+
+static struct msm_camera_csi_params *ov8825_csi_params_array[] = {
+ &ov8825_csi_params,
+ &ov8825_csi_params,
+};
+
+static struct msm_sensor_output_reg_addr_t ov8825_reg_addr = {
+ .x_output = 0x3808,
+ .y_output = 0x380a,
+ .line_length_pclk = 0x380c,
+ .frame_length_lines = 0x380e,
+};
+
+static struct msm_sensor_id_info_t ov8825_id_info = {
+ .sensor_id_reg_addr = 0x300A,
+ .sensor_id = 0x8825,
+};
+
+static struct msm_sensor_exp_gain_info_t ov8825_exp_gain_info = {
+ .coarse_int_time_addr = 0x3501,
+ .global_gain_addr = 0x350A,
+ .vert_offset = 6,
+};
+
+/********************************************
+ * index: index of otp group. (0, 1, 2)
+ * return value:
+ * 0, group index is empty
+ * 1, group index has invalid data
+ * 2, group index has valid data
+ **********************************************/
+uint16_t ov8825_check_otp_wb(struct msm_sensor_ctrl_t *s_ctrl, uint16_t index)
+{
+ uint16_t temp, i;
+ uint16_t address;
+
+ /* clear otp buffer */
+
+ /* select otp bank 0 */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x3d84, 0x08,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* load otp into buffer */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x3d81, 0x01,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* read from group [index] */
+ address = 0x3d05 + index * 9;
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, address, &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* disable otp read */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x3d81, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* clear otp buffer */
+ for (i = 0; i < 32; i++) {
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, (0x3d00+i),
+ 0x00, MSM_CAMERA_I2C_BYTE_DATA);
+ }
+
+ if (!temp)
+ return 0;
+ else if ((!(temp & 0x80)) && (temp & 0x7f))
+ return 2;
+ else
+ return 1;
+}
+
+void ov8825_read_otp_wb(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t index, struct otp_struct *potp)
+{
+ uint16_t temp, i;
+ uint16_t address;
+
+ /* select otp bank 0 */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x3d84, 0x08,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* load otp data into buffer */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x3d81, 0x01,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* read otp data from 0x3d00 - 0x3d1f*/
+ address = 0x3d05 + index * 9;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, address, &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ potp->module_integrator_id = temp;
+ potp->customer_id = temp & 0x7f;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+1), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->lens_id = temp;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+2), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->rg_ratio = temp;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+3), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->bg_ratio = temp;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+4), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->user_data[0] = temp;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+5), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->user_data[1] = temp;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+6), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->user_data[2] = temp;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+7), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->user_data[3] = temp;
+
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client, (address+8), &temp,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ potp->user_data[4] = temp;
+
+ CDBG("%s customer_id = 0x%02x\r\n", __func__, potp->customer_id);
+ CDBG("%s lens_id = 0x%02x\r\n", __func__, potp->lens_id);
+ CDBG("%s rg_ratio = 0x%02x\r\n", __func__, potp->rg_ratio);
+ CDBG("%s bg_ratio = 0x%02x\r\n", __func__, potp->bg_ratio);
+ CDBG("%s user_data[0] = 0x%02x\r\n", __func__, potp->user_data[0]);
+ CDBG("%s user_data[1] = 0x%02x\r\n", __func__, potp->user_data[1]);
+ CDBG("%s user_data[2] = 0x%02x\r\n", __func__, potp->user_data[2]);
+ CDBG("%s user_data[3] = 0x%02x\r\n", __func__, potp->user_data[3]);
+ CDBG("%s user_data[4] = 0x%02x\r\n", __func__, potp->user_data[4]);
+
+ /* disable otp read */
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x3d81, 0x00,
+ MSM_CAMERA_I2C_BYTE_DATA);
+
+ /* clear otp buffer */
+ for (i = 0; i < 32; i++)
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, (0x3d00+i),
+ 0x00, MSM_CAMERA_I2C_BYTE_DATA);
+}
+
+/**********************************************
+ * r_gain, sensor red gain of AWB, 0x400 =1
+ * g_gain, sensor green gain of AWB, 0x400 =1
+ * b_gain, sensor blue gain of AWB, 0x400 =1
+ ***********************************************/
+void ov8825_update_awb_gain(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t r_gain, uint16_t g_gain, uint16_t b_gain)
+{
+ CDBG("%s r_gain = 0x%04x\r\n", __func__, r_gain);
+ CDBG("%s g_gain = 0x%04x\r\n", __func__, g_gain);
+ CDBG("%s b_gain = 0x%04x\r\n", __func__, b_gain);
+ if (r_gain > 0x400) {
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x5186,
+ (r_gain>>8), MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x5187,
+ (r_gain&0xff), MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (g_gain > 0x400) {
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x5188,
+ (g_gain>>8), MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x5189,
+ (g_gain&0xff), MSM_CAMERA_I2C_BYTE_DATA);
+ }
+ if (b_gain > 0x400) {
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x518a,
+ (b_gain>>8), MSM_CAMERA_I2C_BYTE_DATA);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x518b,
+ (b_gain&0xff), MSM_CAMERA_I2C_BYTE_DATA);
+ }
+}
+
+/**************************************************
+ * call this function after OV8825 initialization
+ * return value:
+ * 0, update success
+ * 1, no OTP
+ ***************************************************/
+uint16_t ov8825_update_otp(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ uint16_t i;
+ uint16_t otp_index;
+ uint16_t temp;
+ uint16_t r_gain, g_gain, b_gain, g_gain_r, g_gain_b;
+
+ /* R/G and B/G of current camera module is read out from sensor OTP */
+ /* check first OTP with valid data */
+ for (i = 0; i < 3; i++) {
+ temp = ov8825_check_otp_wb(s_ctrl, i);
+ if (temp == 2) {
+ otp_index = i;
+ break;
+ }
+ }
+ if (i == 3) {
+ /* no valid wb OTP data */
+ CDBG("no valid wb OTP data\r\n");
+ return 1;
+ }
+ ov8825_read_otp_wb(s_ctrl, otp_index, &st_ov8825_otp);
+ /* calculate g_gain */
+ /* 0x400 = 1x gain */
+ if (st_ov8825_otp.bg_ratio < OV8825_BG_RATIO_TYPICAL_VALUE) {
+ if (st_ov8825_otp.rg_ratio < OV8825_RG_RATIO_TYPICAL_VALUE) {
+ g_gain = 0x400;
+ b_gain = 0x400 *
+ OV8825_BG_RATIO_TYPICAL_VALUE /
+ st_ov8825_otp.bg_ratio;
+ r_gain = 0x400 *
+ OV8825_RG_RATIO_TYPICAL_VALUE /
+ st_ov8825_otp.rg_ratio;
+ } else {
+ r_gain = 0x400;
+ g_gain = 0x400 *
+ st_ov8825_otp.rg_ratio /
+ OV8825_RG_RATIO_TYPICAL_VALUE;
+ b_gain = g_gain *
+ OV8825_BG_RATIO_TYPICAL_VALUE /
+ st_ov8825_otp.bg_ratio;
+ }
+ } else {
+ if (st_ov8825_otp.rg_ratio < OV8825_RG_RATIO_TYPICAL_VALUE) {
+ b_gain = 0x400;
+ g_gain = 0x400 *
+ st_ov8825_otp.bg_ratio /
+ OV8825_BG_RATIO_TYPICAL_VALUE;
+ r_gain = g_gain *
+ OV8825_RG_RATIO_TYPICAL_VALUE /
+ st_ov8825_otp.rg_ratio;
+ } else {
+ g_gain_b = 0x400 *
+ st_ov8825_otp.bg_ratio /
+ OV8825_BG_RATIO_TYPICAL_VALUE;
+ g_gain_r = 0x400 *
+ st_ov8825_otp.rg_ratio /
+ OV8825_RG_RATIO_TYPICAL_VALUE;
+ if (g_gain_b > g_gain_r) {
+ b_gain = 0x400;
+ g_gain = g_gain_b;
+ r_gain = g_gain *
+ OV8825_RG_RATIO_TYPICAL_VALUE /
+ st_ov8825_otp.rg_ratio;
+ } else {
+ r_gain = 0x400;
+ g_gain = g_gain_r;
+ b_gain = g_gain *
+ OV8825_BG_RATIO_TYPICAL_VALUE /
+ st_ov8825_otp.bg_ratio;
+ }
+ }
+ }
+ ov8825_update_awb_gain(s_ctrl, r_gain, g_gain, b_gain);
+ return 0;
+}
+
+static int32_t ov8825_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t gain, uint32_t line)
+{
+ uint32_t fl_lines, offset;
+ uint8_t int_time[3];
+
+ fl_lines =
+ (s_ctrl->curr_frame_length_lines * s_ctrl->fps_divider) / Q10;
+ offset = s_ctrl->sensor_exp_gain_info->vert_offset;
+ if (line > (fl_lines - offset))
+ fl_lines = line + offset;
+ CDBG("ov8825_write_exp_gain: %d %d %d\n", fl_lines, gain, line);
+ s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->frame_length_lines, fl_lines,
+ MSM_CAMERA_I2C_WORD_DATA);
+ int_time[0] = line >> 12;
+ int_time[1] = line >> 4;
+ int_time[2] = line << 4;
+ msm_camera_i2c_write_seq(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr-1,
+ &int_time[0], 3);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->global_gain_addr, gain,
+ MSM_CAMERA_I2C_WORD_DATA);
+ s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
+ return 0;
+}
+
+static const struct i2c_device_id ov8825_i2c_id[] = {
+ {SENSOR_NAME, (kernel_ulong_t)&ov8825_s_ctrl},
+ { }
+};
+
+int32_t ov8825_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
+{
+ int32_t rc = 0;
+ struct msm_camera_sensor_info *info = NULL;
+
+ info = s_ctrl->sensordata;
+ gpio_direction_output(info->sensor_pwd, 0);
+ gpio_direction_output(info->sensor_reset, 0);
+ usleep_range(10000, 11000);
+ rc = msm_sensor_power_up(s_ctrl);
+ if (rc < 0) {
+ CDBG("%s: msm_sensor_power_up failed\n", __func__);
+ return rc;
+ }
+ /* turn on ldo and vreg */
+ gpio_direction_output(info->sensor_pwd, 1);
+ msleep(20);
+ gpio_direction_output(info->sensor_reset, 1);
+ msleep(40);
+ return rc;
+}
+
+static struct i2c_driver ov8825_i2c_driver = {
+ .id_table = ov8825_i2c_id,
+ .probe = msm_sensor_i2c_probe,
+ .driver = {
+ .name = SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client ov8825_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+
+
+static int __init msm_sensor_init_module(void)
+{
+ return i2c_add_driver(&ov8825_i2c_driver);
+}
+
+static struct v4l2_subdev_core_ops ov8825_subdev_core_ops = {
+ .ioctl = msm_sensor_subdev_ioctl,
+ .s_power = msm_sensor_power,
+};
+
+static struct v4l2_subdev_video_ops ov8825_subdev_video_ops = {
+ .enum_mbus_fmt = msm_sensor_v4l2_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov8825_subdev_ops = {
+ .core = &ov8825_subdev_core_ops,
+ .video = &ov8825_subdev_video_ops,
+};
+
+int32_t ov8825_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
+ int update_type, int res)
+{
+ int32_t rc = 0;
+ static int csi_config;
+
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+ msleep(30);
+ if (update_type == MSM_SENSOR_REG_INIT) {
+ CDBG("Register INIT\n");
+ s_ctrl->curr_csi_params = NULL;
+ msm_sensor_enable_debugfs(s_ctrl);
+ msm_sensor_write_init_settings(s_ctrl);
+ CDBG("Update OTP\n");
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x100, 0x1,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ msleep(66);
+ ov8825_update_otp(s_ctrl);
+ usleep_range(10000, 11000);
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client, 0x100, 0x0,
+ MSM_CAMERA_I2C_BYTE_DATA);
+ csi_config = 0;
+ } else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
+ CDBG("PERIODIC : %d\n", res);
+ msm_sensor_write_conf_array(
+ s_ctrl->sensor_i2c_client,
+ s_ctrl->msm_sensor_reg->mode_settings, res);
+ msleep(30);
+ if (!csi_config) {
+ s_ctrl->curr_csic_params = s_ctrl->csic_params[res];
+ CDBG("CSI config in progress\n");
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_CSIC_CFG,
+ s_ctrl->curr_csic_params);
+ CDBG("CSI config is done\n");
+ mb();
+ msleep(30);
+ csi_config = 1;
+ }
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_PCLK_CHANGE,
+ &s_ctrl->sensordata->pdata->ioclk.vfe_clk_rate);
+
+ s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
+ msleep(50);
+ }
+ return rc;
+}
+
+static struct msm_sensor_fn_t ov8825_func_tbl = {
+ .sensor_start_stream = msm_sensor_start_stream,
+ .sensor_stop_stream = msm_sensor_stop_stream,
+ .sensor_group_hold_on = msm_sensor_group_hold_on,
+ .sensor_group_hold_off = msm_sensor_group_hold_off,
+ .sensor_set_fps = msm_sensor_set_fps,
+ .sensor_write_exp_gain = ov8825_write_exp_gain,
+ .sensor_write_snapshot_exp_gain = ov8825_write_exp_gain,
+ .sensor_csi_setting = ov8825_sensor_setting,
+ .sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
+ .sensor_mode_init = msm_sensor_mode_init,
+ .sensor_get_output_info = msm_sensor_get_output_info,
+ .sensor_config = msm_sensor_config,
+ .sensor_power_up = ov8825_sensor_power_up,
+ .sensor_power_down = msm_sensor_power_down,
+};
+
+static struct msm_sensor_reg_t ov8825_regs = {
+ .default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
+ .start_stream_conf = ov8825_start_settings,
+ .start_stream_conf_size = ARRAY_SIZE(ov8825_start_settings),
+ .stop_stream_conf = ov8825_stop_settings,
+ .stop_stream_conf_size = ARRAY_SIZE(ov8825_stop_settings),
+ .group_hold_on_conf = ov8825_groupon_settings,
+ .group_hold_on_conf_size = ARRAY_SIZE(ov8825_groupon_settings),
+ .group_hold_off_conf = ov8825_groupoff_settings,
+ .group_hold_off_conf_size = ARRAY_SIZE(ov8825_groupoff_settings),
+ .init_settings = &ov8825_init_conf[0],
+ .init_size = ARRAY_SIZE(ov8825_init_conf),
+ .mode_settings = &ov8825_confs[0],
+ .output_settings = &ov8825_dimensions[0],
+ .num_conf = ARRAY_SIZE(ov8825_confs),
+};
+
+static struct msm_sensor_ctrl_t ov8825_s_ctrl = {
+ .msm_sensor_reg = &ov8825_regs,
+ .sensor_i2c_client = &ov8825_sensor_i2c_client,
+ .sensor_i2c_addr = 0x6C,
+ .sensor_output_reg_addr = &ov8825_reg_addr,
+ .sensor_id_info = &ov8825_id_info,
+ .sensor_exp_gain_info = &ov8825_exp_gain_info,
+ .cam_mode = MSM_SENSOR_MODE_INVALID,
+ .csic_params = &ov8825_csi_params_array[0],
+ .msm_sensor_mutex = &ov8825_mut,
+ .sensor_i2c_driver = &ov8825_i2c_driver,
+ .sensor_v4l2_subdev_info = ov8825_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8825_subdev_info),
+ .sensor_v4l2_subdev_ops = &ov8825_subdev_ops,
+ .func_tbl = &ov8825_func_tbl,
+};
+
+module_init(msm_sensor_init_module);
+MODULE_DESCRIPTION("Omnivison 8MP Bayer sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
index 61c693e..27a8b38 100644
--- a/drivers/media/video/msm/sensors/ov9726_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -236,6 +236,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t ov9726_regs = {
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index debda88..d7aeb74 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -80,7 +80,7 @@
{0x0202, 0x06}, /* coarse_integration_time */
{0x0203, 0x00}, /* coarse_integration_time */
{0x0340, 0x09}, /* frame_length_lines */
- {0x0341, 0x98}, /* frame_length_lines */
+ {0x0341, 0x6C}, /* frame_length_lines */
{0x0342, 0x11}, /* line_length_pck */
{0x0343, 0x80}, /* line_length_pck */
{0x0344, 0x00}, /* x_addr_start */
@@ -489,7 +489,7 @@
.x_output = 1984,
.y_output = 1508,
.line_length_pclk = 4480,
- .frame_length_lines = 2456,
+ .frame_length_lines = 2412,
.vt_pixel_clk = 330000000,
.op_pixel_clk = 320000000,
.binning_factor = 1,
@@ -653,6 +653,7 @@
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
.sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t s5k3l1yx_regs = {
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index 2d25824..e90390e 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -487,6 +487,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_get_csi_params = msm_sensor_get_csi_params,
};
static struct msm_sensor_reg_t s5k4e1_regs = {
diff --git a/drivers/media/video/msm/server/msm_cam_server.c b/drivers/media/video/msm/server/msm_cam_server.c
index 8d004f6..dfa7fbe 100644
--- a/drivers/media/video/msm/server/msm_cam_server.c
+++ b/drivers/media/video/msm/server/msm_cam_server.c
@@ -34,7 +34,7 @@
static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
unsigned int notification, void *arg);
-static void msm_queue_init(struct msm_device_queue *queue, const char *name)
+void msm_queue_init(struct msm_device_queue *queue, const char *name)
{
D("%s\n", __func__);
spin_lock_init(&queue->lock);
@@ -45,7 +45,7 @@
init_waitqueue_head(&queue->wait);
}
-static void msm_enqueue(struct msm_device_queue *queue,
+void msm_enqueue(struct msm_device_queue *queue,
struct list_head *entry)
{
unsigned long flags;
@@ -62,7 +62,7 @@
spin_unlock_irqrestore(&queue->lock, flags);
}
-static void msm_drain_eventq(struct msm_device_queue *queue)
+void msm_drain_eventq(struct msm_device_queue *queue)
{
unsigned long flags;
struct msm_queue_cmd *qcmd;
@@ -560,55 +560,52 @@
}
int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
- struct v4l2_control *ctrl, int is_set_cmd)
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr, int is_set_cmd)
{
int rc = 0;
- struct msm_ctrl_cmd ctrlcmd, *tmp_cmd;
+ struct msm_ctrl_cmd ctrlcmd, tmp_cmd, *cmd_ptr;
uint8_t *ctrl_data = NULL;
- void __user *uptr_cmd;
- void __user *uptr_value;
uint32_t cmd_len = sizeof(struct msm_ctrl_cmd);
uint32_t value_len;
- tmp_cmd = (struct msm_ctrl_cmd *)ctrl->value;
- uptr_cmd = (void __user *)ctrl->value;
- uptr_value = (void __user *)tmp_cmd->value;
- value_len = tmp_cmd->length;
-
- D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
- __func__, tmp_cmd->type, (uint32_t)uptr_cmd, cmd_len,
- (uint32_t)uptr_value, tmp_cmd->length);
-
- ctrl_data = kzalloc(value_len+cmd_len, GFP_KERNEL);
- if (ctrl_data == 0) {
- pr_err("%s could not allocate memory\n", __func__);
- rc = -ENOMEM;
- goto end;
- }
- tmp_cmd = (struct msm_ctrl_cmd *)ctrl_data;
- if (copy_from_user((void *)ctrl_data, uptr_cmd,
- cmd_len)) {
+ if (copy_from_user(&tmp_cmd,
+ (void __user *)ioctl_ptr->ioctl_ptr, cmd_len)) {
pr_err("%s: copy_from_user failed.\n", __func__);
rc = -EINVAL;
goto end;
}
- tmp_cmd->value = (void *)(ctrl_data+cmd_len);
- if (uptr_value && tmp_cmd->length > 0) {
- if (copy_from_user((void *)tmp_cmd->value, uptr_value,
- value_len)) {
- pr_err("%s: copy_from_user failed, size=%d\n",
- __func__, value_len);
+ value_len = tmp_cmd.length;
+ ctrl_data = kzalloc(value_len+cmd_len, GFP_KERNEL);
+ if (!ctrl_data) {
+ pr_err("%s could not allocate memory\n", __func__);
+ rc = -ENOMEM;
+ goto end;
+ }
+
+ cmd_ptr = (struct msm_ctrl_cmd *) ctrl_data;
+ *cmd_ptr = tmp_cmd;
+ if (tmp_cmd.value && tmp_cmd.length > 0) {
+ cmd_ptr->value = (void *)(ctrl_data+cmd_len);
+ if (copy_from_user((void *)cmd_ptr->value,
+ (void __user *)tmp_cmd.value,
+ value_len)) {
+ pr_err("%s: copy_from_user failed.\n", __func__);
rc = -EINVAL;
goto end;
}
- } else
- tmp_cmd->value = NULL;
+ } else {
+ cmd_ptr->value = NULL;
+ }
+
+ D("%s: cmd type = %d, up1=0x%x, ulen1=%d, up2=0x%x, ulen2=%d\n",
+ __func__, tmp_cmd.type, (uint32_t)ioctl_ptr->ioctl_ptr, cmd_len,
+ (uint32_t)tmp_cmd.value, tmp_cmd.length);
ctrlcmd.type = MSM_V4L2_SET_CTRL_CMD;
ctrlcmd.length = cmd_len + value_len;
ctrlcmd.value = (void *)ctrl_data;
- if (tmp_cmd->timeout_ms > 0)
- ctrlcmd.timeout_ms = tmp_cmd->timeout_ms;
+ if (tmp_cmd.timeout_ms > 0)
+ ctrlcmd.timeout_ms = tmp_cmd.timeout_ms;
else
ctrlcmd.timeout_ms = 1000;
ctrlcmd.vnode_id = pcam->vnode_id;
@@ -618,17 +615,17 @@
rc = msm_server_control(&g_server_dev, &ctrlcmd);
D("%s: msm_server_control rc=%d\n", __func__, rc);
if (rc == 0) {
- if (uptr_value && tmp_cmd->length > 0 &&
- copy_to_user((void __user *)uptr_value,
- (void *)(ctrl_data+cmd_len), tmp_cmd->length)) {
+ if (tmp_cmd.value && tmp_cmd.length > 0 &&
+ copy_to_user((void __user *)tmp_cmd.value,
+ (void *)(ctrl_data+cmd_len), tmp_cmd.length)) {
pr_err("%s: copy_to_user failed, size=%d\n",
- __func__, tmp_cmd->length);
+ __func__, tmp_cmd.length);
rc = -EINVAL;
goto end;
}
- tmp_cmd->value = uptr_value;
- if (copy_to_user((void __user *)uptr_cmd,
- (void *)tmp_cmd, cmd_len)) {
+
+ if (copy_to_user((void __user *)ioctl_ptr->ioctl_ptr,
+ (void *)&tmp_cmd, cmd_len)) {
pr_err("%s: copy_to_user failed in cpy, size=%d\n",
__func__, cmd_len);
rc = -EINVAL;
@@ -637,8 +634,8 @@
}
end:
D("%s: END, type = %d, vaddr = 0x%x, vlen = %d, status = %d, rc = %d\n",
- __func__, tmp_cmd->type, (uint32_t)tmp_cmd->value,
- tmp_cmd->length, tmp_cmd->status, rc);
+ __func__, tmp_cmd.type, (uint32_t)tmp_cmd.value,
+ tmp_cmd.length, tmp_cmd.status, rc);
kfree(ctrl_data);
return rc;
}
@@ -655,8 +652,6 @@
pr_err("%s Invalid control\n", __func__);
return -EINVAL;
}
- if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
- return msm_server_proc_ctrl_cmd(pcam, ctrl, 1);
memset(ctrl_data, 0, sizeof(ctrl_data));
@@ -687,8 +682,6 @@
pr_err("%s Invalid control\n", __func__);
return -EINVAL;
}
- if (ctrl->id == MSM_V4L2_PID_CTRL_CMD)
- return msm_server_proc_ctrl_cmd(pcam, ctrl, 0);
memset(ctrl_data, 0, sizeof(ctrl_data));
@@ -1372,9 +1365,7 @@
struct msm_camera_device_platform_data *camdev;
uint8_t csid_core = 0;
- if (notification == NOTIFY_CID_CHANGE ||
- notification == NOTIFY_ISPIF_STREAM ||
- notification == NOTIFY_PCLK_CHANGE ||
+ if (notification == NOTIFY_PCLK_CHANGE ||
notification == NOTIFY_CSIPHY_CFG ||
notification == NOTIFY_CSID_CFG ||
notification == NOTIFY_CSIC_CFG) {
@@ -1385,30 +1376,6 @@
}
switch (notification) {
- case NOTIFY_CID_CHANGE:
- /* reconfig the ISPIF*/
- if (g_server_dev.ispif_device) {
- struct msm_ispif_params_list ispif_params;
- ispif_params.len = 1;
- ispif_params.params[0].intftype = PIX0;
- ispif_params.params[0].cid_mask = 0x0001;
- ispif_params.params[0].csid = csid_core;
-
- rc = v4l2_subdev_call(
- g_server_dev.ispif_device, core, ioctl,
- VIDIOC_MSM_ISPIF_CFG, &ispif_params);
- if (rc < 0)
- return;
- }
- break;
- case NOTIFY_ISPIF_STREAM:
- /* call ISPIF stream on/off */
- rc = v4l2_subdev_call(g_server_dev.ispif_device, video,
- s_stream, (int)arg);
- if (rc < 0)
- return;
-
- break;
case NOTIFY_ISP_MSG_EVT:
case NOTIFY_VFE_MSG_OUT:
case NOTIFY_VFE_MSG_STATS:
@@ -1421,16 +1388,6 @@
g_server_dev.vfe_device[0], notification, arg);
}
break;
- case NOTIFY_VPE_MSG_EVT: {
- struct msm_cam_media_controller *pmctl =
- (struct msm_cam_media_controller *)
- v4l2_get_subdev_hostdata(sd);
- struct msm_vpe_resp *vdata = (struct msm_vpe_resp *)arg;
- msm_mctl_pp_notify(pmctl,
- (struct msm_mctl_pp_frame_info *)
- vdata->extdata);
- break;
- }
case NOTIFY_VFE_IRQ:{
struct msm_vfe_cfg_cmd cfg_cmd;
struct msm_camvfe_params vfe_params;
@@ -1478,20 +1435,379 @@
}
return;
-}
-
-void msm_cam_release_subdev_node(struct video_device *vdev)
-{
- struct v4l2_subdev *sd = video_get_drvdata(vdev);
- sd->devnode = NULL;
- kfree(vdev);
+}
+
+void msm_cam_release_subdev_node(struct video_device *vdev)
+{
+ struct v4l2_subdev *sd = video_get_drvdata(vdev);
+ sd->devnode = NULL;
+ kfree(vdev);
+}
+
+/* Helper function to get the irq_idx corresponding
+ * to the irq_num. */
+int get_irq_idx_from_irq_num(int irq_num)
+{
+ int i;
+ for (i = 0; i < CAMERA_SS_IRQ_MAX; i++)
+ if (irq_num == g_server_dev.hw_irqmap[i].irq_num)
+ return g_server_dev.hw_irqmap[i].irq_idx;
+
+ return -EINVAL;
+}
+
+static irqreturn_t msm_camera_server_parse_irq(int irq_num, void *data)
+{
+ unsigned long flags;
+ int irq_idx, i, rc;
+ u32 status = 0;
+ struct intr_table_entry *ind_irq_tbl;
+ struct intr_table_entry *comp_irq_tbl;
+ bool subdev_handled = 0;
+
+ irq_idx = get_irq_idx_from_irq_num(irq_num);
+ if (irq_idx < 0) {
+ pr_err("server_parse_irq: no clients for irq #%d. returning ",
+ irq_num);
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+ ind_irq_tbl = &g_server_dev.irq_lkup_table.ind_intr_tbl[0];
+ comp_irq_tbl = &g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+ if (ind_irq_tbl[irq_idx].is_composite) {
+ for (i = 0; i < comp_irq_tbl[irq_idx].num_hwcore; i++) {
+ if (comp_irq_tbl[irq_idx].subdev_list[i]) {
+ rc = v4l2_subdev_call(
+ comp_irq_tbl[irq_idx].subdev_list[i],
+ core, interrupt_service_routine,
+ status, &subdev_handled);
+ if ((rc < 0) || !subdev_handled) {
+ pr_err("server_parse_irq:Error\n"
+ "handling irq %d rc = %d",
+ irq_num, rc);
+ /* Dispatch the irq to the remaining
+ * subdevs in the list. */
+ continue;
+ }
+ }
+ }
+ } else {
+ rc = v4l2_subdev_call(ind_irq_tbl[irq_idx].subdev_list[0],
+ core, interrupt_service_routine,
+ status, &subdev_handled);
+ if ((rc < 0) || !subdev_handled) {
+ pr_err("server_parse_irq: Error handling irq %d rc = %d",
+ irq_num, rc);
+ spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+ flags);
+ return IRQ_HANDLED;
+ }
+ }
+ spin_unlock_irqrestore(&g_server_dev.intr_table_lock, flags);
+ return IRQ_HANDLED;
+}
+
+/* Helper function to get the irq_idx corresponding
+ * to the camera hwcore. This function should _only_
+ * be invoked when the IRQ Router is configured
+ * non-composite mode. */
+int get_irq_idx_from_camhw_idx(int cam_hw_idx)
+{
+ int i;
+ for (i = 0; i < MSM_CAM_HW_MAX; i++)
+ if (cam_hw_idx == g_server_dev.hw_irqmap[i].cam_hw_idx)
+ return g_server_dev.hw_irqmap[i].irq_idx;
+
+ return -EINVAL;
+}
+
+static inline void update_compirq_subdev_info(
+ struct intr_table_entry *irq_entry,
+ uint32_t cam_hw_mask, uint8_t cam_hw_id,
+ int *num_hwcore)
+{
+ if (cam_hw_mask & (0x1 << cam_hw_id)) {
+ /* If the mask has been set for this cam hwcore
+ * update the subdev ptr......*/
+ irq_entry->subdev_list[cam_hw_id] =
+ g_server_dev.subdev_table[cam_hw_id];
+ (*num_hwcore)++;
+ } else {
+ /*....else, just clear it, so that the irq will
+ * not be dispatched to this hw. */
+ irq_entry->subdev_list[cam_hw_id] = NULL;
+ }
+}
+
+static int msm_server_update_composite_irq_info(
+ struct intr_table_entry *irq_req)
+{
+ int num_hwcore = 0, rc = 0;
+ struct intr_table_entry *comp_irq_tbl =
+ &g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+
+ comp_irq_tbl[irq_req->irq_idx].is_composite = 1;
+ comp_irq_tbl[irq_req->irq_idx].irq_trigger_type =
+ irq_req->irq_trigger_type;
+ comp_irq_tbl[irq_req->irq_idx].num_hwcore = irq_req->num_hwcore;
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_MICRO, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_CCI, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_CSI0, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_CSI1, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_CSI2, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_CSI3, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_ISPIF, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_CPP, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_VFE0, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_VFE1, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_JPEG0, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_JPEG1, &num_hwcore);
+
+ update_compirq_subdev_info(&comp_irq_tbl[irq_req->irq_idx],
+ irq_req->cam_hw_mask, MSM_CAM_HW_JPEG2, &num_hwcore);
+
+ if (num_hwcore != irq_req->num_hwcore) {
+ pr_warn("%s Mismatch!! requested cam hwcores: %d, Mask set %d",
+ __func__, irq_req->num_hwcore, num_hwcore);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_cam_server_request_irq(void *arg)
+{
+ unsigned long flags;
+ int rc = 0;
+ struct intr_table_entry *irq_req = (struct intr_table_entry *)arg;
+ struct intr_table_entry *ind_irq_tbl =
+ &g_server_dev.irq_lkup_table.ind_intr_tbl[0];
+ struct intr_table_entry *comp_irq_tbl =
+ &g_server_dev.irq_lkup_table.comp_intr_tbl[0];
+
+ if (!irq_req || !irq_req->irq_num || !irq_req->num_hwcore) {
+ pr_err("%s Invalid input ", __func__);
+ return -EINVAL;
+ }
+
+ if (!g_server_dev.irqr_device) {
+ /* This either means, the current target does not
+ * have a IRQ Router hw or the IRQ Router device is
+ * not probed yet. The latter should not happen.
+ * In any case, just return back without updating
+ * the interrupt lookup table. */
+ pr_info("%s IRQ Router hw is not present. ", __func__);
+ return -ENXIO;
+ }
+
+ if (irq_req->is_composite) {
+ if (irq_req->irq_idx >= CAMERA_SS_IRQ_0 &&
+ irq_req->irq_idx < CAMERA_SS_IRQ_MAX) {
+ spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+ /* Update the composite irq information into
+ * the composite irq lookup table.... */
+ if (msm_server_update_composite_irq_info(irq_req)) {
+ pr_err("%s Invalid configuration", __func__);
+ spin_unlock_irqrestore(
+ &g_server_dev.intr_table_lock, flags);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+ flags);
+ /*...and then update the corresponding entry
+ * in the individual irq lookup table to indicate
+ * that this IRQ is a composite irq and needs to be
+ * sent to multiple subdevs. */
+ ind_irq_tbl[irq_req->irq_idx].is_composite = 1;
+ rc = request_irq(comp_irq_tbl[irq_req->irq_idx].irq_num,
+ msm_camera_server_parse_irq,
+ irq_req->irq_trigger_type,
+ ind_irq_tbl[irq_req->irq_idx].dev_name,
+ ind_irq_tbl[irq_req->irq_idx].data);
+ if (rc < 0) {
+ pr_err("%s: request_irq failed for %s\n",
+ __func__, irq_req->dev_name);
+ return -EBUSY;
+ }
+ } else {
+ pr_err("%s Invalid irq_idx %d ",
+ __func__, irq_req->irq_idx);
+ return -EINVAL;
+ }
+ } else {
+ if (irq_req->cam_hw_idx >= MSM_CAM_HW_MICRO &&
+ irq_req->cam_hw_idx < MSM_CAM_HW_MAX) {
+ /* Update the irq information into
+ * the individual irq lookup table.... */
+ irq_req->irq_idx =
+ get_irq_idx_from_camhw_idx(irq_req->cam_hw_idx);
+ if (irq_req->cam_hw_idx < 0) {
+ pr_err("%s Invalid hw index %d ", __func__,
+ irq_req->cam_hw_idx);
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&g_server_dev.intr_table_lock, flags);
+ /* Make sure the composite irq is not configured for
+ * this IRQ already. */
+ BUG_ON(ind_irq_tbl[irq_req->irq_idx].is_composite);
+
+ ind_irq_tbl[irq_req->irq_idx] = *irq_req;
+ /* irq_num is stored inside the server's hw_irqmap
+ * during the device subdevice registration. */
+ ind_irq_tbl[irq_req->irq_idx].irq_num =
+ g_server_dev.hw_irqmap[irq_req->irq_idx].irq_num;
+
+ /*...and clear the corresponding entry in the
+ * compsoite irq lookup table to indicate that this
+ * IRQ will only be dispatched to single subdev. */
+ memset(&comp_irq_tbl[irq_req->irq_idx], 0,
+ sizeof(struct intr_table_entry));
+ D("%s Saving Entry %d %d %d %p",
+ __func__,
+ ind_irq_tbl[irq_req->cam_hw_idx].irq_num,
+ ind_irq_tbl[irq_req->cam_hw_idx].cam_hw_idx,
+ ind_irq_tbl[irq_req->cam_hw_idx].is_composite,
+ ind_irq_tbl[irq_req->cam_hw_idx].subdev_list[0]);
+
+ spin_unlock_irqrestore(&g_server_dev.intr_table_lock,
+ flags);
+
+ rc = request_irq(ind_irq_tbl[irq_req->irq_idx].irq_num,
+ msm_camera_server_parse_irq,
+ irq_req->irq_trigger_type,
+ ind_irq_tbl[irq_req->irq_idx].dev_name,
+ ind_irq_tbl[irq_req->irq_idx].data);
+ if (rc < 0) {
+ pr_err("%s: request_irq failed for %s\n",
+ __func__, irq_req->dev_name);
+ return -EBUSY;
+ }
+ } else {
+ pr_err("%s Invalid hw index %d ", __func__,
+ irq_req->cam_hw_idx);
+ return -EINVAL;
+ }
+ }
+ D("%s Successfully requested for IRQ for device %s ", __func__,
+ irq_req->dev_name);
+ return rc;
+}
+
+int msm_cam_server_update_irqmap(
+ struct msm_cam_server_irqmap_entry *irqmap_entry)
+{
+ if (!irqmap_entry || (irqmap_entry->irq_idx < CAMERA_SS_IRQ_0 ||
+ irqmap_entry->irq_idx >= CAMERA_SS_IRQ_MAX)) {
+ pr_err("%s Invalid irqmap entry ", __func__);
+ return -EINVAL;
+ }
+ g_server_dev.hw_irqmap[irqmap_entry->irq_idx] = *irqmap_entry;
+ return 0;
+}
+
+static int msm_cam_server_register_subdev(struct v4l2_device *v4l2_dev,
+ struct v4l2_subdev *sd)
+{
+ int rc = 0;
+ struct video_device *vdev;
+
+ if (v4l2_dev == NULL || sd == NULL || !sd->name[0]) {
+ pr_err("%s Invalid input ", __func__);
+ return -EINVAL;
+ }
+
+ rc = v4l2_device_register_subdev(v4l2_dev, sd);
+ if (rc < 0) {
+ pr_err("%s v4l2 subdev register failed for %s ret = %d",
+ __func__, sd->name, rc);
+ return rc;
+ }
+
+ /* Register a device node for every subdev marked with the
+ * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
+ */
+ if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
+ return rc;
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev) {
+ pr_err("%s Not enough memory ", __func__);
+ rc = -ENOMEM;
+ goto clean_up;
+ }
+
+ video_set_drvdata(vdev, sd);
+ strlcpy(vdev->name, sd->name, sizeof(vdev->name));
+ vdev->v4l2_dev = v4l2_dev;
+ vdev->fops = &v4l2_subdev_fops;
+ vdev->release = msm_cam_release_subdev_node;
+ rc = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
+ sd->owner);
+ if (rc < 0) {
+ pr_err("%s Error registering video device %s", __func__,
+ sd->name);
+ kfree(vdev);
+ goto clean_up;
+ }
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ sd->entity.info.v4l.major = VIDEO_MAJOR;
+ sd->entity.info.v4l.minor = vdev->minor;
+#endif
+ sd->devnode = vdev;
+ return 0;
+
+clean_up:
+ if (sd->devnode)
+ video_unregister_device(sd->devnode);
+ return rc;
+}
+
+static int msm_cam_server_fill_sdev_irqnum(int cam_hw_idx,
+ int irq_num)
+{
+ int rc = 0, irq_idx;
+ irq_idx = get_irq_idx_from_camhw_idx(cam_hw_idx);
+ if (irq_idx < 0) {
+ pr_err("%s Invalid cam_hw_idx %d ", __func__, cam_hw_idx);
+ rc = -EINVAL;
+ } else {
+ g_server_dev.hw_irqmap[irq_idx].irq_num = irq_num;
+ }
+ return rc;
}
int msm_cam_register_subdev_node(struct v4l2_subdev *sd,
- enum msm_cam_subdev_type sdev_type, uint8_t index)
+ struct msm_cam_subdev_info *sd_info)
{
- struct video_device *vdev;
- int err = 0;
+ int err = 0, cam_hw_idx;
+ uint8_t sdev_type, index;
+
+ sdev_type = sd_info->sdev_type;
+ index = sd_info->sd_index;
switch (sdev_type) {
case CSIPHY_DEV:
@@ -1509,7 +1825,13 @@
err = -EINVAL;
break;
}
+ cam_hw_idx = MSM_CAM_HW_CSI0 + index;
g_server_dev.csid_device[index] = sd;
+ if (g_server_dev.irqr_device) {
+ g_server_dev.subdev_table[cam_hw_idx] = sd;
+ err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
+ sd_info->irq_num);
+ }
break;
case CSIC_DEV:
@@ -1523,6 +1845,11 @@
case ISPIF_DEV:
g_server_dev.ispif_device = sd;
+ if (g_server_dev.irqr_device) {
+ g_server_dev.subdev_table[cam_hw_idx] = sd;
+ err = msm_cam_server_fill_sdev_irqnum(MSM_CAM_HW_ISPIF,
+ sd_info->irq_num);
+ }
break;
case VFE_DEV:
@@ -1531,7 +1858,13 @@
err = -EINVAL;
break;
}
+ cam_hw_idx = MSM_CAM_HW_VFE0 + index;
g_server_dev.vfe_device[index] = sd;
+ if (g_server_dev.irqr_device) {
+ g_server_dev.subdev_table[cam_hw_idx] = sd;
+ err = msm_cam_server_fill_sdev_irqnum(cam_hw_idx,
+ sd_info->irq_num);
+ }
break;
case VPE_DEV:
@@ -1555,6 +1888,9 @@
case GESTURE_DEV:
g_server_dev.gesture_device = sd;
break;
+ case IRQ_ROUTER_DEV:
+ g_server_dev.irqr_device = sd;
+ break;
default:
break;
}
@@ -1562,49 +1898,11 @@
if (err < 0)
return err;
- err = v4l2_device_register_subdev(&g_server_dev.v4l2_dev, sd);
- if (err < 0) {
- pr_err("%s v4l2 subdev register failed for %d ret = %d",
- __func__, sdev_type, err);
- return err;
- }
-
- /* Register a device node for every subdev marked with the
- * V4L2_SUBDEV_FL_HAS_DEVNODE flag.
- */
- if (!(sd->flags & V4L2_SUBDEV_FL_HAS_DEVNODE))
- return err;
-
- vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
- if (!vdev) {
- err = -ENOMEM;
- goto clean_up;
- }
-
- video_set_drvdata(vdev, sd);
- strlcpy(vdev->name, sd->name, sizeof(vdev->name));
- vdev->v4l2_dev = &g_server_dev.v4l2_dev;
- vdev->fops = &v4l2_subdev_fops;
- vdev->release = msm_cam_release_subdev_node;
- err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1,
- sd->owner);
- if (err < 0) {
- kfree(vdev);
- goto clean_up;
- }
-#if defined(CONFIG_MEDIA_CONTROLLER)
- sd->entity.info.v4l.major = VIDEO_MAJOR;
- sd->entity.info.v4l.minor = vdev->minor;
-#endif
- sd->devnode = vdev;
- return 0;
-
-clean_up:
- if (sd->devnode)
- video_unregister_device(sd->devnode);
- return err;
+ err = msm_cam_server_register_subdev(&g_server_dev.v4l2_dev, sd);
+ return err;
}
+
static int msm_setup_server_dev(struct platform_device *pdev)
{
int rc = -ENODEV, i;
@@ -1647,6 +1945,9 @@
mutex_init(&g_server_dev.server_lock);
mutex_init(&g_server_dev.server_queue_lock);
+ spin_lock_init(&g_server_dev.intr_table_lock);
+ memset(&g_server_dev.irq_lkup_table, 0,
+ sizeof(struct irqmgr_intr_lkup_table));
g_server_dev.pcam_active = NULL;
g_server_dev.camera_info.num_cameras = 0;
atomic_set(&g_server_dev.number_pcam_active, 0);
@@ -1803,16 +2104,20 @@
struct v4l2_event v4l2_evt;
struct msm_isp_event_ctrl *isp_event;
- isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
- if (!isp_event) {
- pr_err("%s Insufficient memory. return", __func__);
- return -ENOMEM;
- }
+ void *ctrlcmd_data;
+
event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
if (!event_qcmd) {
pr_err("%s Insufficient memory. return", __func__);
- kfree(isp_event);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto event_qcmd_alloc_fail;
+ }
+
+ isp_event = kzalloc(sizeof(struct msm_isp_event_ctrl), GFP_KERNEL);
+ if (!isp_event) {
+ pr_err("%s Insufficient memory. return", __func__);
+ rc = -ENOMEM;
+ goto isp_event_alloc_fail;
}
D("%s\n", __func__);
@@ -1825,12 +2130,23 @@
server_dev->server_queue[out->queue_idx].evt_id =
server_dev->server_evt_id;
v4l2_evt.type = V4L2_EVENT_PRIVATE_START + ctrl_id;
+ v4l2_evt.id = 0;
v4l2_evt.u.data[0] = out->queue_idx;
/* setup event object to transfer the command; */
isp_event->resptype = MSM_CAM_RESP_V4L2;
isp_event->isp_data.ctrl = *out;
isp_event->isp_data.ctrl.evt_id = server_dev->server_evt_id;
+ if (out->value != NULL && out->length != 0) {
+ ctrlcmd_data = kzalloc(out->length, GFP_KERNEL);
+ if (!ctrlcmd_data) {
+ rc = -ENOMEM;
+ goto ctrlcmd_alloc_fail;
+ }
+ memcpy(ctrlcmd_data, out->value, out->length);
+ isp_event->isp_data.ctrl.value = ctrlcmd_data;
+ }
+
atomic_set(&event_qcmd->on_heap, 1);
event_qcmd->command = isp_event;
@@ -1854,7 +2170,8 @@
if (!rc)
rc = -ETIMEDOUT;
if (rc < 0) {
- kfree(isp_event);
+ if (++server_dev->server_evt_id == 0)
+ server_dev->server_evt_id++;
pr_err("%s: wait_event error %d\n", __func__, rc);
return rc;
}
@@ -1875,7 +2192,6 @@
kfree(ctrlcmd);
free_qcmd(rcmd);
- kfree(isp_event);
D("%s: rc %d\n", __func__, rc);
/* rc is the time elapsed. */
if (rc >= 0) {
@@ -1888,6 +2204,13 @@
rc = -EINVAL;
}
return rc;
+
+ctrlcmd_alloc_fail:
+ kfree(isp_event);
+isp_event_alloc_fail:
+ kfree(event_qcmd);
+event_qcmd_alloc_fail:
+ return rc;
}
int msm_server_close_client(int idx)
diff --git a/drivers/media/video/msm/server/msm_cam_server.h b/drivers/media/video/msm/server/msm_cam_server.h
index 2fe4c2b..8a02d32 100644
--- a/drivers/media/video/msm/server/msm_cam_server.h
+++ b/drivers/media/video/msm/server/msm_cam_server.h
@@ -36,7 +36,7 @@
int msm_server_get_usecount(void);
int32_t msm_find_free_queue(void);
int msm_server_proc_ctrl_cmd(struct msm_cam_v4l2_device *pcam,
- struct v4l2_control *ctrl, int is_set_cmd);
+ struct msm_camera_v4l2_ioctl_t *ioctl_ptr, int is_set_cmd);
int msm_server_s_ctrl(struct msm_cam_v4l2_device *pcam,
struct v4l2_control *ctrl);
int msm_server_g_ctrl(struct msm_cam_v4l2_device *pcam,
@@ -61,5 +61,7 @@
struct v4l2_event_subscription *sub);
int msm_server_get_crop(struct msm_cam_v4l2_device *pcam,
int idx, struct v4l2_crop *crop);
-
+int msm_cam_server_request_irq(void *arg);
+int msm_cam_server_update_irqmap(
+ struct msm_cam_server_irqmap_entry *entry);
#endif /* _MSM_CAM_SERVER_H */
diff --git a/drivers/media/video/msm/sn12m0pz.c b/drivers/media/video/msm/sn12m0pz.c
index 2eabb3c..c39e97f 100644
--- a/drivers/media/video/msm/sn12m0pz.c
+++ b/drivers/media/video/msm/sn12m0pz.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -17,6 +17,7 @@
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include <mach/camera.h>
diff --git a/drivers/media/video/msm/vx6953.c b/drivers/media/video/msm/vx6953.c
index 3b8f14c..f933a76 100644
--- a/drivers/media/video/msm/vx6953.c
+++ b/drivers/media/video/msm/vx6953.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -16,6 +16,7 @@
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
+#include <linux/module.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include <mach/camera.h>
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index c94fa13..a5f2634 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -1297,17 +1297,33 @@
return rc;
}
static long venc_set_max_perf_level(struct video_client_ctx *client_ctx,
- int val)
+ __s32 value)
{
int rc = 0;
struct vcd_property_hdr vcd_property_hdr;
struct vcd_property_perf_level perf;
+ int level = 0;
+
+ switch (value) {
+ case V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE:
+ level = VCD_PERF_LEVEL2;
+ break;
+ case V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO:
+ level = VCD_PERF_LEVEL_TURBO;
+ break;
+ default:
+ WFD_MSG_ERR("Unknown performance level: %d\n", value);
+ rc = -ENOTSUPP;
+ goto err_set_perf_level;
+ }
+
vcd_property_hdr.prop_id = VCD_REQ_PERF_LEVEL;
vcd_property_hdr.sz =
sizeof(struct vcd_property_perf_level);
- perf.level = VCD_PERF_LEVEL2;
+ perf.level = level;
rc = vcd_set_property(client_ctx->vcd_handle,
&vcd_property_hdr, &perf);
+err_set_perf_level:
return rc;
}
static long venc_set_header_mode(struct video_client_ctx *client_ctx,
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
index 25b5c5c..bdace3c 100644
--- a/drivers/media/video/msm_vidc/msm_smem.c
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -69,6 +69,8 @@
struct ion_handle *hndl;
size_t len;
int rc = 0;
+ if (size == 0)
+ goto skip_mem_alloc;
flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
hndl = ion_alloc(client->clnt, size, align, flags);
if (IS_ERR_OR_NULL(hndl)) {
@@ -96,6 +98,7 @@
fail_map:
ion_free(client->clnt, hndl);
fail_shared_mem_alloc:
+skip_mem_alloc:
return rc;
}
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
index 1c646dd..6cd9e6b 100644
--- a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -28,6 +28,7 @@
#include "msm_smem.h"
#define BASE_DEVICE_NUMBER 32
+#define MAX_EVENTS 30
struct msm_vidc_drv *vidc_driver;
@@ -215,21 +216,20 @@
int rc;
struct buffer_info *bi;
struct v4l2_buffer buffer_info;
+ struct v4l2_plane plane;
v4l2_inst = get_v4l2_inst(file, NULL);
if (b->count == 0) {
list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
bi = list_entry(ptr, struct buffer_info, list);
if (bi->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
buffer_info.type = bi->type;
- buffer_info.m.planes[0].reserved[0] =
- bi->fd;
- buffer_info.m.planes[0].reserved[1] =
- bi->buff_off;
- buffer_info.m.planes[0].length = bi->size;
- buffer_info.m.planes[0].m.userptr =
- bi->uvaddr;
+ plane.reserved[0] = bi->fd;
+ plane.reserved[1] = bi->buff_off;
+ plane.length = bi->size;
+ plane.m.userptr = bi->uvaddr;
+ buffer_info.m.planes = &plane;
buffer_info.length = 1;
- pr_err("Releasing buffer: %d, %d, %d\n",
+ pr_info("Releasing buffer: %d, %d, %d\n",
buffer_info.m.planes[0].reserved[0],
buffer_info.m.planes[0].reserved[1],
buffer_info.m.planes[0].length);
@@ -359,9 +359,7 @@
struct v4l2_event_subscription *sub)
{
int rc = 0;
- if (sub->type == V4L2_EVENT_ALL)
- sub->type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
- rc = v4l2_event_subscribe(fh, sub, 0);
+ rc = v4l2_event_subscribe(fh, sub, MAX_EVENTS);
return rc;
}
@@ -445,7 +443,7 @@
INIT_LIST_HEAD(&core->instances);
mutex_init(&core->sync_lock);
spin_lock_init(&core->lock);
- core->base_addr = 0x34f00000;
+ core->base_addr = 0x14f00000;
core->state = VIDC_CORE_UNINIT;
for (i = SYS_MSG_INDEX(SYS_MSG_START);
i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
index ed99d35..ec93628 100644
--- a/drivers/media/video/msm_vidc/msm_venc.c
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -348,7 +348,7 @@
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
.name = "H.264 Loop Filter Mode",
- .type = V4L2_CTRL_TYPE_INTEGER,
+ .type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
.maximum = L_MODE,
.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
@@ -375,7 +375,9 @@
static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
{
- return ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+ int sz = ((height + 31) & (~31)) * ((width + 31) & (~31)) * 3/2;
+ sz = (sz + 4095) & (~4095);
+ return sz;
}
static struct hal_quantization
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
index a11f817..11fbcf4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc.c
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -186,7 +186,7 @@
void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write)
{
- return NULL;
+ return (void *)0xdeadbeef;
}
void vidc_put_userptr(void *buf_priv)
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
index 52f1dca..9b617aa 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_common.c
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -183,21 +183,9 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct video_device *vdev;
- struct v4l2_event dqevent;
- struct msm_vidc_core *core;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
- core = inst->core;
- if (inst->session_type == MSM_VIDC_ENCODER)
- vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
- else
- vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
- dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
- dqevent.u.data[0] = (uint8_t)MSM_VIDC_OPEN_DONE;
- v4l2_event_queue(vdev, &dqevent);
- return;
} else {
pr_err("Failed to get valid response for session init\n");
}
@@ -207,24 +195,17 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct video_device *vdev;
struct v4l2_event dqevent;
struct msm_vidc_cb_event *event_notify;
- struct msm_vidc_core *core;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- core = inst->core;
- if (inst->session_type == MSM_VIDC_ENCODER)
- vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
- else
- vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
- dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
- dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_EVENT_CHANGE;
+ dqevent.type = V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED;
+ dqevent.id = 0;
event_notify = (struct msm_vidc_cb_event *) response->data;
inst->reconfig_height = event_notify->height;
inst->reconfig_width = event_notify->width;
inst->in_reconfig = true;
- v4l2_event_queue(vdev, &dqevent);
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
return;
} else {
pr_err("Failed to get valid response for event_change\n");
@@ -262,20 +243,9 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct video_device *vdev;
- struct v4l2_event dqevent;
- struct msm_vidc_core *core;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
- core = inst->core;
- if (inst->session_type == MSM_VIDC_ENCODER)
- vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
- else
- vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
- dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
- dqevent.u.data[0] = (uint8_t)MSM_VIDC_START_DONE;
- v4l2_event_queue(vdev, &dqevent);
} else {
pr_err("Failed to get valid response for start\n");
}
@@ -285,20 +255,9 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct video_device *vdev;
- struct v4l2_event dqevent;
- struct msm_vidc_core *core;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
- core = inst->core;
- if (inst->session_type == MSM_VIDC_ENCODER)
- vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
- else
- vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
- dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
- dqevent.u.data[0] = (uint8_t)MSM_VIDC_STOP_DONE;
- v4l2_event_queue(vdev, &dqevent);
} else {
pr_err("Failed to get valid response for stop\n");
}
@@ -320,19 +279,12 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct video_device *vdev;
struct v4l2_event dqevent;
- struct msm_vidc_core *core;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
- core = inst->core;
- if (inst->session_type == MSM_VIDC_ENCODER)
- vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
- else
- vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
- dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
- dqevent.u.data[0] = (uint8_t)MSM_VIDC_DECODER_FLUSH_DONE;
- v4l2_event_queue(vdev, &dqevent);
+ dqevent.type = V4L2_EVENT_MSM_VIDC_FLUSH_DONE;
+ dqevent.id = 0;
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
} else {
pr_err("Failed to get valid response for flush\n");
}
@@ -343,20 +295,13 @@
{
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
- struct video_device *vdev;
struct v4l2_event dqevent;
- struct msm_vidc_core *core;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
signal_session_msg_receipt(cmd, inst);
- core = inst->core;
- if (inst->session_type == MSM_VIDC_ENCODER)
- vdev = &core->vdev[MSM_VIDC_ENCODER].vdev;
- else
- vdev = &core->vdev[MSM_VIDC_DECODER].vdev;
- dqevent.type = V4L2_EVENT_PRIVATE_START + V4L2_EVENT_VIDC_BASE;
- dqevent.u.data[0] = (uint8_t)MSM_VIDC_CLOSE_DONE;
- v4l2_event_queue(vdev, &dqevent);
+ dqevent.type = V4L2_EVENT_MSM_VIDC_CLOSE_DONE;
+ dqevent.id = 0;
+ v4l2_event_queue_fh(&inst->event_handler, &dqevent);
} else {
pr_err("Failed to get valid response for session close\n");
}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
index fb1ab58..fb8fbc4 100644
--- a/drivers/media/video/msm_vidc/msm_vidc_internal.h
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -75,11 +75,6 @@
MSM_VIDC_CORE_UNINIT,
};
-enum vidc_resposes_id {
- MSM_VIDC_DECODER_FLUSH_DONE = 0x11,
- MSM_VIDC_DECODER_EVENT_CHANGE,
-};
-
struct buf_info {
struct list_head list;
struct vb2_buffer *buf;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.c b/drivers/media/video/msm_vidc/vidc_hal.c
index 1f33c2c..13a319d9 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.c
+++ b/drivers/media/video/msm_vidc/vidc_hal.c
@@ -84,8 +84,8 @@
{
struct hfi_cmd_session_release_buffer_packet *pkt =
(struct hfi_cmd_session_release_buffer_packet *)packet;
- if ((pkt->buffer_type == HAL_BUFFER_OUTPUT) ||
- (pkt->buffer_type == HAL_BUFFER_OUTPUT2)) {
+ if ((pkt->buffer_type == HFI_BUFFER_OUTPUT) ||
+ (pkt->buffer_type == HFI_BUFFER_OUTPUT2)) {
struct hfi_buffer_info *buff;
buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
buff->buffer_addr -= HFI_VIRTIO_FW_BIAS;
@@ -824,8 +824,7 @@
}
HAL_MSG_INFO("IN func: %s, with property id: %d", __func__, ptype);
- pkt->size = sizeof(struct hfi_cmd_session_set_property_packet)
- - sizeof(u32);
+ pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
pkt->session_id = (u32) session;
pkt->num_properties = 1;
diff --git a/drivers/media/video/msm_vidc/vidc_hal.h b/drivers/media/video/msm_vidc/vidc_hal.h
index 166ed0d..15441f4 100644
--- a/drivers/media/video/msm_vidc/vidc_hal.h
+++ b/drivers/media/video/msm_vidc/vidc_hal.h
@@ -1153,7 +1153,7 @@
enum HFI_COMMAND packet_type;
u32 session_id;
u32 num_properties;
- u32 rg_property_data[1];
+ u32 rg_property_data[0];
};
struct hfi_cmd_session_get_property_packet {
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 9719307..db0dbc2 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -32,6 +32,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
#include <linux/regulator/consumer.h>
#include <mach/clk.h>
#include <linux/clk.h>
@@ -58,6 +59,228 @@
printk(KERN_DEBUG "VCAP: " fmt, ## arg); \
} while (0)
+int vcap_reg_powerup(struct vcap_dev *dev)
+{
+ dev->fs_vcap = regulator_get(NULL, "fs_vcap");
+ if (IS_ERR(dev->fs_vcap)) {
+ pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
+ PTR_ERR(dev->fs_vcap));
+ dev->fs_vcap = NULL;
+ return -EINVAL;
+ } else if (regulator_enable(dev->fs_vcap)) {
+ pr_err("%s: Regulator FS_VCAP enable failed\n", __func__);
+ regulator_put(dev->fs_vcap);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void vcap_reg_powerdown(struct vcap_dev *dev)
+{
+ if (dev->fs_vcap == NULL)
+ return;
+ regulator_disable(dev->fs_vcap);
+ regulator_put(dev->fs_vcap);
+ dev->fs_vcap = NULL;
+ return;
+}
+
+int config_gpios(int on, struct vcap_platform_data *pdata)
+{
+ int i, ret;
+ int num_gpios = pdata->num_gpios;
+ unsigned *gpios = pdata->gpios;
+
+ dprintk(4, "GPIO config start\n");
+ if (on) {
+ for (i = 0; i < num_gpios; i++) {
+ ret = gpio_request(gpios[i], "vcap:vc");
+ if (ret) {
+ pr_err("VCAP: failed at GPIO %d to request\n",
+ gpios[i]);
+ goto gpio_failed;
+ }
+ ret = gpio_direction_input(gpios[i]);
+ if (ret) {
+ pr_err("VCAP: failed at GPIO %d to set to input\n",
+ gpios[i]);
+ i++;
+ goto gpio_failed;
+ }
+ }
+ } else {
+ for (i = 0; i < num_gpios; i++)
+ gpio_free(gpios[i]);
+ }
+ dprintk(4, "GPIO config exit\n");
+ return 0;
+gpio_failed:
+ for (i--; i >= 0; i--)
+ gpio_free(gpios[i]);
+ return -EINVAL;
+}
+
+int vcap_clk_powerup(struct vcap_dev *dev, struct device *ddev,
+ unsigned long rate)
+{
+ int ret = 0;
+
+ dev->vcap_clk = clk_get(ddev, "core_clk");
+ if (IS_ERR(dev->vcap_clk)) {
+ dev->vcap_clk = NULL;
+ pr_err("%s: Could not clk_get core_clk\n", __func__);
+ clk_put(dev->vcap_clk);
+ dev->vcap_clk = NULL;
+ return -EINVAL;
+ }
+
+ clk_prepare(dev->vcap_clk);
+ ret = clk_enable(dev->vcap_clk);
+ if (ret) {
+ pr_err("%s: Failed core clk_enable %d\n", __func__, ret);
+ goto fail_vcap_clk_unprep;
+ }
+
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate < 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ goto fail_vcap_clk;
+ }
+ ret = clk_set_rate(dev->vcap_clk, rate);
+ if (ret < 0) {
+ pr_err("%s: Failed core set_rate %d\n", __func__, ret);
+ goto fail_vcap_clk;
+ }
+
+ dev->vcap_npl_clk = clk_get(ddev, "vcap_npl_clk");
+ if (IS_ERR(dev->vcap_npl_clk)) {
+ dev->vcap_npl_clk = NULL;
+ pr_err("%s: Could not clk_get npl\n", __func__);
+ clk_put(dev->vcap_npl_clk);
+ dev->vcap_npl_clk = NULL;
+ goto fail_vcap_clk;
+ }
+
+ clk_prepare(dev->vcap_npl_clk);
+ ret = clk_enable(dev->vcap_npl_clk);
+ if (ret) {
+ pr_err("%s:Failed npl clk_enable %d\n", __func__, ret);
+ goto fail_vcap_npl_clk_unprep;
+ }
+
+ dev->vcap_p_clk = clk_get(ddev, "iface_clk");
+ if (IS_ERR(dev->vcap_p_clk)) {
+ dev->vcap_p_clk = NULL;
+ pr_err("%s: Could not clk_get pix(AHB)\n", __func__);
+ clk_put(dev->vcap_p_clk);
+ dev->vcap_p_clk = NULL;
+ goto fail_vcap_npl_clk;
+ }
+
+ clk_prepare(dev->vcap_p_clk);
+ ret = clk_enable(dev->vcap_p_clk);
+ if (ret) {
+ pr_err("%s: Failed pix(AHB) clk_enable %d\n", __func__, ret);
+ goto fail_vcap_p_clk_unprep;
+ }
+ return 0;
+
+fail_vcap_p_clk_unprep:
+ clk_unprepare(dev->vcap_p_clk);
+ clk_put(dev->vcap_p_clk);
+ dev->vcap_p_clk = NULL;
+
+fail_vcap_npl_clk:
+ clk_disable(dev->vcap_npl_clk);
+fail_vcap_npl_clk_unprep:
+ clk_unprepare(dev->vcap_npl_clk);
+ clk_put(dev->vcap_npl_clk);
+ dev->vcap_npl_clk = NULL;
+
+fail_vcap_clk:
+ clk_disable(dev->vcap_clk);
+fail_vcap_clk_unprep:
+ clk_unprepare(dev->vcap_clk);
+ clk_put(dev->vcap_clk);
+ dev->vcap_clk = NULL;
+ return -EINVAL;
+}
+
+void vcap_clk_powerdown(struct vcap_dev *dev)
+{
+ if (dev->vcap_p_clk != NULL) {
+ clk_disable(dev->vcap_p_clk);
+ clk_unprepare(dev->vcap_p_clk);
+ clk_put(dev->vcap_p_clk);
+ dev->vcap_p_clk = NULL;
+ }
+
+ if (dev->vcap_npl_clk != NULL) {
+ clk_disable(dev->vcap_npl_clk);
+ clk_unprepare(dev->vcap_npl_clk);
+ clk_put(dev->vcap_npl_clk);
+ dev->vcap_npl_clk = NULL;
+ }
+
+ if (dev->vcap_clk != NULL) {
+ clk_disable(dev->vcap_clk);
+ clk_unprepare(dev->vcap_clk);
+ clk_put(dev->vcap_clk);
+ dev->vcap_clk = NULL;
+ }
+}
+
+int vcap_get_bus_client_handle(struct vcap_dev *dev)
+{
+ struct msm_bus_scale_pdata *vcap_axi_client_pdata =
+ dev->vcap_pdata->bus_client_pdata;
+ dev->bus_client_handle =
+ msm_bus_scale_register_client(vcap_axi_client_pdata);
+
+ return 0;
+}
+
+int vcap_enable(struct vcap_dev *dev, struct device *ddev,
+ unsigned long rate)
+{
+ int rc;
+
+ rc = vcap_reg_powerup(dev);
+ if (rc < 0)
+ goto reg_failed;
+ rc = vcap_clk_powerup(dev, ddev, rate);
+ if (rc < 0)
+ goto clk_failed;
+ rc = vcap_get_bus_client_handle(dev);
+ if (rc < 0)
+ goto bus_r_failed;
+ rc = config_gpios(1, dev->vcap_pdata);
+ if (rc < 0)
+ goto gpio_failed;
+ return 0;
+
+gpio_failed:
+ msm_bus_scale_unregister_client(dev->bus_client_handle);
+ dev->bus_client_handle = 0;
+bus_r_failed:
+ vcap_clk_powerdown(dev);
+clk_failed:
+ vcap_reg_powerdown(dev);
+reg_failed:
+ return rc;
+}
+
+int vcap_disable(struct vcap_dev *dev)
+{
+ config_gpios(0, dev->vcap_pdata);
+
+ msm_bus_scale_unregister_client(dev->bus_client_handle);
+ dev->bus_client_handle = 0;
+ vcap_clk_powerdown(dev);
+ vcap_reg_powerdown(dev);
+ return 0;
+}
+
enum vcap_op_mode determine_mode(struct vcap_client_data *cd)
{
if (cd->set_cap == 1 && cd->set_vp_o == 0 &&
@@ -502,7 +725,7 @@
int size;
struct vcap_priv_fmt *priv_fmt;
struct v4l2_format_vc_ext *vc_format;
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
priv_fmt = (struct vcap_priv_fmt *) f->fmt.raw_data;
@@ -511,8 +734,6 @@
vc_format = (struct v4l2_format_vc_ext *) &priv_fmt->u.timing;
c_data->vc_format = *vc_format;
- config_vc_format(c_data);
-
size = (c_data->vc_format.hactive_end -
c_data->vc_format.hactive_start);
@@ -525,11 +746,9 @@
size *= (c_data->vc_format.vactive_end -
c_data->vc_format.vactive_start);
priv_fmt->u.timing.sizeimage = size;
- vcap_ctrl->vc_client = c_data;
c_data->set_cap = true;
break;
case VP_IN_TYPE:
- vcap_ctrl->vp_client = c_data;
c_data->vp_in_fmt.width = priv_fmt->u.pix.width;
c_data->vp_in_fmt.height = priv_fmt->u.pix.height;
c_data->vp_in_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
@@ -546,7 +765,6 @@
c_data->set_decode = true;
break;
case VP_OUT_TYPE:
- vcap_ctrl->vp_client = c_data;
c_data->vp_out_fmt.width = priv_fmt->u.pix.width;
c_data->vp_out_fmt.height = priv_fmt->u.pix.height;
c_data->vp_out_fmt.pixfmt = priv_fmt->u.pix.pixelformat;
@@ -572,7 +790,7 @@
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *rb)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
int rc;
dprintk(3, "In Req Buf %08x\n", (unsigned int)rb->type);
@@ -631,7 +849,7 @@
static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
switch (p->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -645,7 +863,7 @@
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
struct vb2_buffer *vb;
struct vb2_queue *q;
int rc;
@@ -706,7 +924,7 @@
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
int rc;
dprintk(3, "In DQ Buf %08x\n", (unsigned int)p->type);
@@ -764,10 +982,33 @@
return 0;
}
+int request_bus_bw(struct vcap_dev *dev, unsigned long rate)
+{
+ struct msm_bus_paths *bus_vectors;
+ int idx, length;
+ bus_vectors = dev->vcap_pdata->bus_client_pdata->usecase;
+ length = dev->vcap_pdata->bus_client_pdata->num_usecases;
+ idx = 0;
+ do {
+ if (rate <= bus_vectors[idx].vectors[0].ab)
+ break;
+ idx++;
+ } while (idx < length);
+ if (idx == length) {
+ pr_err("VCAP: Defaulting to highest BW request\n");
+ idx--;
+ }
+ msm_bus_scale_client_update_request(dev->bus_client_handle, idx);
+ return 0;
+}
+
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
+ struct vcap_dev *dev = c_data->dev;
+ unsigned long flags;
int rc;
+ unsigned long rate;
dprintk(3, "In Stream ON\n");
if (determine_mode(c_data) != c_data->op_mode) {
@@ -777,25 +1018,97 @@
switch (c_data->op_mode) {
case VC_VCAP_OP:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (dev->vc_resource) {
+ pr_err("VCAP Err: %s: VC resource taken", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 1;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+
c_data->dev->vc_client = c_data;
+
+ if (!c_data->vc_format.clk_freq) {
+ rc = -EINVAL;
+ goto free_res;
+ }
+
+ rate = c_data->vc_format.clk_freq;
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate <= 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ rc = -EINVAL;
+ goto free_res;
+ }
+ rc = clk_set_rate(dev->vcap_clk, rate);
+ if (rc < 0)
+ goto free_res;
+
+ rate = (c_data->vc_format.hactive_end -
+ c_data->vc_format.hactive_start);
+
+ if (c_data->vc_format.color_space)
+ rate *= 3;
+ else
+ rate *= 2;
+
+ rate *= (c_data->vc_format.vactive_end -
+ c_data->vc_format.vactive_start);
+ rate *= c_data->vc_format.frame_rate;
+ if (rate == 0)
+ goto free_res;
+
+ rc = request_bus_bw(dev, rate);
+ if (rc < 0)
+ goto free_res;
+
config_vc_format(c_data);
- return vb2_streamon(&c_data->vc_vidq, i);
+ rc = vb2_streamon(&c_data->vc_vidq, i);
+ if (rc < 0)
+ goto free_res;
+ break;
case VP_VCAP_OP:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (dev->vp_resource) {
+ pr_err("VCAP Err: %s: VP resource taken", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vp_resource = 1;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ c_data->dev->vp_client = c_data;
+
+ rate = 160000000;
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate <= 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ rc = -EINVAL;
+ goto free_res;
+ }
+ rc = clk_set_rate(dev->vcap_clk, rate);
+ if (rc < 0)
+ goto free_res;
+
+ rate = c_data->vp_out_fmt.width *
+ c_data->vp_out_fmt.height * 240;
+ rc = request_bus_bw(dev, rate);
+ if (rc < 0)
+ goto free_res;
+
rc = streamon_validate_q(&c_data->vp_in_vidq);
if (rc < 0)
- return rc;
+ goto free_res;
rc = streamon_validate_q(&c_data->vp_out_vidq);
if (rc < 0)
- return rc;
-
- c_data->dev->vp_client = c_data;
+ goto free_res;
rc = config_vp_format(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
rc = init_motion_buf(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
if (c_data->vid_vp_action.nr_enabled) {
rc = init_nr_buf(c_data);
if (rc < 0)
@@ -803,6 +1116,7 @@
}
c_data->vid_vp_action.vp_state = VP_FRAME1;
+ c_data->streaming = 1;
rc = vb2_streamon(&c_data->vp_in_vidq,
V4L2_BUF_TYPE_INTERLACED_IN_DECODER);
@@ -813,39 +1127,85 @@
V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (rc < 0)
goto s_on_deinit_nr_buf;
- return rc;
+ break;
case VC_AND_VP_VCAP_OP:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (dev->vc_resource || dev->vp_resource) {
+ pr_err("VCAP Err: %s: VC/VP resource taken",
+ __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 1;
+ dev->vp_resource = 1;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ c_data->dev->vc_client = c_data;
+ c_data->dev->vp_client = c_data;
+
+ if (!c_data->vc_format.clk_freq) {
+ rc = -EINVAL;
+ goto free_res;
+ }
+
+ rate = c_data->vc_format.clk_freq;
+ rate = clk_round_rate(dev->vcap_clk, rate);
+ if (rate <= 0) {
+ pr_err("%s: Failed core rnd_rate\n", __func__);
+ rc = -EINVAL;
+ goto free_res;
+ }
+ rc = clk_set_rate(dev->vcap_clk, rate);
+ if (rc < 0)
+ goto free_res;
+
+ rate = (c_data->vc_format.hactive_end -
+ c_data->vc_format.hactive_start);
+
+ if (c_data->vc_format.color_space)
+ rate *= 3;
+ else
+ rate *= 2;
+
+ rate *= (c_data->vc_format.vactive_end -
+ c_data->vc_format.vactive_start);
+ rate *= c_data->vc_format.frame_rate;
+ rate *= 2;
+ if (rate == 0)
+ goto free_res;
+
+ rc = request_bus_bw(dev, rate);
+ if (rc < 0)
+ goto free_res;
+
rc = streamon_validate_q(&c_data->vc_vidq);
if (rc < 0)
return rc;
rc = streamon_validate_q(&c_data->vp_in_vidq);
if (rc < 0)
- return rc;
+ goto free_res;
rc = streamon_validate_q(&c_data->vp_out_vidq);
if (rc < 0)
- return rc;
-
- c_data->dev->vc_client = c_data;
- c_data->dev->vp_client = c_data;
- c_data->dev->vc_to_vp_work.cd = c_data;
+ goto free_res;
rc = config_vc_format(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
rc = config_vp_format(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
rc = init_motion_buf(c_data);
if (rc < 0)
- return rc;
+ goto free_res;
+
if (c_data->vid_vp_action.nr_enabled) {
rc = init_nr_buf(c_data);
if (rc < 0)
goto s_on_deinit_m_buf;
}
- c_data->streaming = 1;
+ c_data->dev->vc_to_vp_work.cd = c_data;
c_data->vid_vp_action.vp_state = VP_FRAME1;
+ c_data->streaming = 1;
/* These stream on calls should not fail */
rc = vb2_streamon(&c_data->vc_vidq,
@@ -862,7 +1222,7 @@
V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (rc < 0)
goto s_on_deinit_nr_buf;
- return rc;
+ break;
default:
pr_err("VCAP Error: %s: Operation Mode type", __func__);
return -ENOTRECOVERABLE;
@@ -874,6 +1234,21 @@
deinit_nr_buf(c_data);
s_on_deinit_m_buf:
deinit_motion_buf(c_data);
+free_res:
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (c_data->op_mode == VC_VCAP_OP) {
+ dev->vc_resource = 0;
+ c_data->dev->vc_client = NULL;
+ } else if (c_data->op_mode == VP_VCAP_OP) {
+ dev->vp_resource = 0;
+ c_data->dev->vp_client = NULL;
+ } else if (c_data->op_mode == VC_AND_VP_VCAP_OP) {
+ c_data->dev->vc_client = NULL;
+ c_data->dev->vp_client = NULL;
+ dev->vc_resource = 0;
+ dev->vp_resource = 0;
+ }
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
return rc;
}
@@ -893,22 +1268,51 @@
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
+ struct vcap_dev *dev = c_data->dev;
+ unsigned long flags;
int rc;
switch (c_data->op_mode) {
case VC_VCAP_OP:
+ if (c_data != dev->vc_client) {
+ pr_err("VCAP Err: %s: VC held by other client",
+ __func__);
+ return -EBUSY;
+ }
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (!dev->vc_resource) {
+ pr_err("VCAP Err: %s: VC res not acquired", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 0;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
rc = vb2_streamoff(&c_data->vc_vidq, i);
if (rc >= 0)
atomic_set(&c_data->dev->vc_enabled, 0);
return rc;
case VP_VCAP_OP:
+ if (c_data != dev->vp_client) {
+ pr_err("VCAP Err: %s: VP held by other client",
+ __func__);
+ return -EBUSY;
+ }
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (!dev->vp_resource) {
+ pr_err("VCAP Err: %s: VP res not acquired", __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vp_resource = 0;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
rc = streamoff_validate_q(&c_data->vp_in_vidq);
if (rc < 0)
return rc;
rc = streamoff_validate_q(&c_data->vp_out_vidq);
if (rc < 0)
return rc;
+ c_data->streaming = 0;
/* These stream on calls should not fail */
rc = vb2_streamoff(&c_data->vp_in_vidq,
@@ -927,6 +1331,21 @@
atomic_set(&c_data->dev->vp_enabled, 0);
return rc;
case VC_AND_VP_VCAP_OP:
+ if (c_data != dev->vp_client || c_data != dev->vc_client) {
+ pr_err("VCAP Err: %s: VC/VP held by other client",
+ __func__);
+ return -EBUSY;
+ }
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ if (!(dev->vc_resource || dev->vp_resource)) {
+ pr_err("VCAP Err: %s: VC or VP res not acquired",
+ __func__);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ return -EBUSY;
+ }
+ dev->vc_resource = 0;
+ dev->vp_resource = 0;
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
rc = streamoff_validate_q(&c_data->vc_vidq);
if (rc < 0)
return rc;
@@ -967,6 +1386,36 @@
return 0;
}
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ int rc;
+ if (sub->type == V4L2_EVENT_ALL) {
+ sub->type = V4L2_EVENT_PRIVATE_START +
+ VCAP_GENERIC_NOTIFY_EVENT;
+ sub->id = 0;
+ do {
+ rc = v4l2_event_subscribe(fh, sub, 16);
+ if (rc < 0) {
+ sub->type = V4L2_EVENT_ALL;
+ v4l2_event_unsubscribe(fh, sub);
+ return rc;
+ }
+ sub->type++;
+ } while (sub->type !=
+ V4L2_EVENT_PRIVATE_START + VCAP_MAX_NOTIFY_EVENT);
+ } else {
+ rc = v4l2_event_subscribe(fh, sub, 16);
+ }
+ return rc;
+}
+
+static int vidioc_unsubscribe_event(struct v4l2_fh *fh,
+ struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
/* VCAP fops */
static void *vcap_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
unsigned long size, int write)
@@ -995,6 +1444,7 @@
struct vcap_dev *dev = video_drvdata(file);
struct vcap_client_data *c_data;
struct vb2_queue *q;
+ unsigned long flags;
int ret;
c_data = kzalloc(sizeof(*c_data), GFP_KERNEL);
if (!dev)
@@ -1047,10 +1497,29 @@
INIT_LIST_HEAD(&c_data->vid_vc_action.active);
INIT_LIST_HEAD(&c_data->vid_vp_action.in_active);
INIT_LIST_HEAD(&c_data->vid_vp_action.out_active);
- file->private_data = c_data;
+ v4l2_fh_init(&c_data->vfh, dev->vfd);
+ v4l2_fh_add(&c_data->vfh);
+
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ atomic_inc(&dev->open_clients);
+ ret = atomic_read(&dev->open_clients);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ if (ret == 1) {
+ ret = vcap_enable(dev, dev->ddev, 54860000);
+ if (ret < 0) {
+ pr_err("Err: %s: Power on vcap failed", __func__);
+ goto vcap_power_failed;
+ }
+ }
+
+ file->private_data = &c_data->vfh;
return 0;
+vcap_power_failed:
+ v4l2_fh_del(&c_data->vfh);
+ v4l2_fh_exit(&c_data->vfh);
+ vb2_queue_release(&c_data->vp_out_vidq);
vp_out_q_failed:
vb2_queue_release(&c_data->vp_in_vidq);
vp_in_q_failed:
@@ -1062,12 +1531,29 @@
static int vcap_close(struct file *file)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_dev *dev = video_drvdata(file);
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
+ unsigned long flags;
+ int ret;
+
+ if (c_data == NULL)
+ return 0;
+
+ spin_lock_irqsave(&dev->dev_slock, flags);
+ atomic_dec(&dev->open_clients);
+ ret = atomic_read(&dev->open_clients);
+ spin_unlock_irqrestore(&dev->dev_slock, flags);
+ if (ret == 0)
+ vcap_disable(dev);
+ v4l2_fh_del(&c_data->vfh);
+ v4l2_fh_exit(&c_data->vfh);
vb2_queue_release(&c_data->vp_out_vidq);
vb2_queue_release(&c_data->vp_in_vidq);
vb2_queue_release(&c_data->vc_vidq);
- c_data->dev->vc_client = NULL;
- c_data->dev->vp_client = NULL;
+ if (c_data->dev->vc_client == c_data)
+ c_data->dev->vc_client = NULL;
+ if (c_data->dev->vp_client == c_data)
+ c_data->dev->vp_client = NULL;
kfree(c_data);
return 0;
}
@@ -1103,29 +1589,35 @@
static unsigned int vcap_poll(struct file *file,
struct poll_table_struct *wait)
{
- struct vcap_client_data *c_data = file->private_data;
+ struct vcap_client_data *c_data = to_client_data(file->private_data);
struct vb2_queue *q;
unsigned int mask = 0;
+ dprintk(1, "Enter slect/poll\n");
+
switch (c_data->op_mode) {
case VC_VCAP_OP:
q = &c_data->vc_vidq;
- return vb2_poll(q, file, wait);
+ mask = vb2_poll(q, file, wait);
+ break;
case VP_VCAP_OP:
q = &c_data->vp_in_vidq;
mask = poll_work(q, file, wait, 0);
q = &c_data->vp_out_vidq;
mask |= poll_work(q, file, wait, 1);
- return mask;
+ break;
case VC_AND_VP_VCAP_OP:
q = &c_data->vp_out_vidq;
mask = poll_work(q, file, wait, 0);
- return mask;
+ break;
default:
pr_err("VCAP Error: %s: Unknown operation mode", __func__);
return POLLERR;
}
- return 0;
+ if (v4l2_event_pending(&c_data->vfh))
+ mask |= POLLPRI;
+ poll_wait(file, &(c_data->vfh.wait), wait);
+ return mask;
}
/* V4L2 and video device structures */
@@ -1153,6 +1645,9 @@
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
+
+ .vidioc_subscribe_event = vidioc_subscribe_event,
+ .vidioc_unsubscribe_event = vidioc_unsubscribe_event,
};
static struct video_device vcap_template = {
@@ -1162,220 +1657,6 @@
.release = video_device_release,
};
-int vcap_reg_powerup(struct vcap_dev *dev)
-{
- dev->fs_vcap = regulator_get(NULL, "fs_vcap");
- if (IS_ERR(dev->fs_vcap)) {
- pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
- PTR_ERR(dev->fs_vcap));
- dev->fs_vcap = NULL;
- return -EINVAL;
- } else if (regulator_enable(dev->fs_vcap)) {
- pr_err("%s: Regulator FS_VCAP enable failed\n", __func__);
- regulator_put(dev->fs_vcap);
- return -EINVAL;
- }
- return 0;
-}
-
-void vcap_reg_powerdown(struct vcap_dev *dev)
-{
- if (dev->fs_vcap == NULL)
- return;
- regulator_disable(dev->fs_vcap);
- regulator_put(dev->fs_vcap);
- dev->fs_vcap = NULL;
- return;
-}
-
-int config_gpios(int on, struct vcap_platform_data *pdata)
-{
- int i, ret;
- int num_gpios = pdata->num_gpios;
- unsigned *gpios = pdata->gpios;
-
- if (on) {
- for (i = 0; i < num_gpios; i++) {
- ret = gpio_request(gpios[i], "vcap:vc");
- if (ret) {
- pr_err("VCAP: failed at GPIO %d to request\n",
- gpios[i]);
- goto gpio_failed;
- }
- ret = gpio_direction_input(gpios[i]);
- if (ret) {
- pr_err("VCAP: failed at GPIO %d to set to input\n",
- gpios[i]);
- i++;
- goto gpio_failed;
- }
- }
- } else {
- for (i = 0; i < num_gpios; i++)
- gpio_free(gpios[i]);
- }
- dprintk(2, "GPIO config done\n");
- return 0;
-gpio_failed:
- for (i--; i >= 0; i--)
- gpio_free(gpios[i]);
- return -EINVAL;
-}
-
-int vcap_clk_powerup(struct vcap_dev *dev, struct device *ddev)
-{
- int ret = 0;
-
- dev->vcap_clk = clk_get(ddev, "core_clk");
- if (IS_ERR(dev->vcap_clk)) {
- dev->vcap_clk = NULL;
- pr_err("%s: Could not clk_get core_clk\n", __func__);
- clk_put(dev->vcap_clk);
- dev->vcap_clk = NULL;
- return -EINVAL;
- }
-
- clk_prepare(dev->vcap_clk);
- ret = clk_enable(dev->vcap_clk);
- if (ret) {
- pr_err("%s: Failed core clk_enable %d\n", __func__, ret);
- goto fail_vcap_clk_unprep;
- }
-
- clk_set_rate(dev->vcap_clk, 160000000);
- if (ret) {
- pr_err("%s: Failed core set_rate %d\n", __func__, ret);
- goto fail_vcap_clk;
- }
-
- dev->vcap_npl_clk = clk_get(ddev, "vcap_npl_clk");
- if (IS_ERR(dev->vcap_npl_clk)) {
- dev->vcap_npl_clk = NULL;
- pr_err("%s: Could not clk_get npl\n", __func__);
- clk_put(dev->vcap_npl_clk);
- dev->vcap_npl_clk = NULL;
- goto fail_vcap_clk;
- }
-
- clk_prepare(dev->vcap_npl_clk);
- ret = clk_enable(dev->vcap_npl_clk);
- if (ret) {
- pr_err("%s:Failed npl clk_enable %d\n", __func__, ret);
- goto fail_vcap_npl_clk_unprep;
- }
-
- dev->vcap_p_clk = clk_get(ddev, "iface_clk");
- if (IS_ERR(dev->vcap_p_clk)) {
- dev->vcap_p_clk = NULL;
- pr_err("%s: Could not clk_get pix(AHB)\n", __func__);
- clk_put(dev->vcap_p_clk);
- dev->vcap_p_clk = NULL;
- goto fail_vcap_npl_clk;
- }
-
- clk_prepare(dev->vcap_p_clk);
- ret = clk_enable(dev->vcap_p_clk);
- if (ret) {
- pr_err("%s: Failed pix(AHB) clk_enable %d\n", __func__, ret);
- goto fail_vcap_p_clk_unprep;
- }
- return 0;
-
-fail_vcap_p_clk_unprep:
- clk_unprepare(dev->vcap_p_clk);
- clk_put(dev->vcap_p_clk);
- dev->vcap_p_clk = NULL;
-
-fail_vcap_npl_clk:
- clk_disable(dev->vcap_npl_clk);
-fail_vcap_npl_clk_unprep:
- clk_unprepare(dev->vcap_npl_clk);
- clk_put(dev->vcap_npl_clk);
- dev->vcap_npl_clk = NULL;
-
-fail_vcap_clk:
- clk_disable(dev->vcap_clk);
-fail_vcap_clk_unprep:
- clk_unprepare(dev->vcap_clk);
- clk_put(dev->vcap_clk);
- dev->vcap_clk = NULL;
- return -EINVAL;
-}
-
-void vcap_clk_powerdown(struct vcap_dev *dev)
-{
- if (dev->vcap_p_clk != NULL) {
- clk_disable(dev->vcap_p_clk);
- clk_unprepare(dev->vcap_p_clk);
- clk_put(dev->vcap_p_clk);
- dev->vcap_p_clk = NULL;
- }
-
- if (dev->vcap_npl_clk != NULL) {
- clk_disable(dev->vcap_npl_clk);
- clk_unprepare(dev->vcap_npl_clk);
- clk_put(dev->vcap_npl_clk);
- dev->vcap_npl_clk = NULL;
- }
-
- if (dev->vcap_clk != NULL) {
- clk_disable(dev->vcap_clk);
- clk_unprepare(dev->vcap_clk);
- clk_put(dev->vcap_clk);
- dev->vcap_clk = NULL;
- }
-}
-
-int vcap_get_bus_client_handle(struct vcap_dev *dev)
-{
- struct msm_bus_scale_pdata *vcap_axi_client_pdata =
- dev->vcap_pdata->bus_client_pdata;
- dev->bus_client_handle =
- msm_bus_scale_register_client(vcap_axi_client_pdata);
-
- return 0;
-}
-
-int vcap_enable(struct vcap_dev *dev, struct device *ddev)
-{
- int rc;
-
- rc = vcap_reg_powerup(dev);
- if (rc < 0)
- goto reg_failed;
- rc = vcap_clk_powerup(dev, ddev);
- if (rc < 0)
- goto clk_failed;
- rc = vcap_get_bus_client_handle(dev);
- if (rc < 0)
- goto bus_r_failed;
- config_gpios(1, dev->vcap_pdata);
- if (rc < 0)
- goto gpio_failed;
- return 0;
-
-gpio_failed:
- msm_bus_scale_unregister_client(dev->bus_client_handle);
- dev->bus_client_handle = 0;
-bus_r_failed:
- vcap_clk_powerdown(dev);
-clk_failed:
- vcap_reg_powerdown(dev);
-reg_failed:
- return rc;
-}
-
-int vcap_disable(struct vcap_dev *dev)
-{
- config_gpios(0, dev->vcap_pdata);
-
- msm_bus_scale_unregister_client(dev->bus_client_handle);
- dev->bus_client_handle = 0;
- vcap_clk_powerdown(dev);
- vcap_reg_powerdown(dev);
- return 0;
-}
-
static irqreturn_t vcap_vp_handler(int irq_num, void *data)
{
return vp_handler(vcap_ctrl);
@@ -1465,10 +1746,10 @@
if (ret)
goto free_resource;
- ret = vcap_enable(dev, &pdev->dev);
+ ret = vcap_enable(dev, &pdev->dev, 54860000);
if (ret)
goto unreg_dev;
- msm_bus_scale_client_update_request(dev->bus_client_handle, 3);
+ msm_bus_scale_client_update_request(dev->bus_client_handle, 0);
ret = detect_vc(dev);
@@ -1504,6 +1785,10 @@
atomic_set(&dev->vc_enabled, 0);
atomic_set(&dev->vp_enabled, 0);
+ atomic_set(&dev->open_clients, 0);
+ dev->ddev = &pdev->dev;
+ spin_lock_init(&dev->dev_slock);
+ vcap_disable(dev);
dprintk(1, "Exit probe succesfully");
return 0;
diff --git a/drivers/media/video/vcap_vc.c b/drivers/media/video/vcap_vc.c
index 2c4a243..ad0718e 100644
--- a/drivers/media/video/vcap_vc.c
+++ b/drivers/media/video/vcap_vc.c
@@ -22,6 +22,7 @@
#include <mach/clk.h>
#include <linux/clk.h>
+#include <media/v4l2-event.h>
#include <media/vcap_v4l2.h>
#include <media/vcap_fmt.h>
#include "vcap_vc.h"
@@ -113,14 +114,40 @@
struct vcap_buffer *buf;
struct vb2_buffer *vb = NULL;
struct vcap_client_data *c_data;
-
+ struct v4l2_event v4l2_evt;
irq = readl_relaxed(VCAP_VC_INT_STATUS);
dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
- vc_buf_status = irq & VC_BUFFER_WRITTEN;
+ v4l2_evt.id = 0;
+ if (irq & 0x8000200) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_PIX_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ if (irq & 0x40000200) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_LINE_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ if (irq & 0x20000200) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_VSYNC_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ if (irq & 0x00000800) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_NPL_OFLOW_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ if (irq & 0x00000400) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_LBUF_OFLOW_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ vc_buf_status = irq & VC_BUFFER_WRITTEN;
dprintk(1, "Done buf status = %d\n", vc_buf_status);
if (vc_buf_status == VC_NO_BUF) {
@@ -139,8 +166,11 @@
spin_lock(&dev->vc_client->cap_slock);
if (list_empty(&dev->vc_client->vid_vc_action.active)) {
/* Just leave we have no new queued buffers */
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
spin_unlock(&dev->vc_client->cap_slock);
+ writel_relaxed(irq, VCAP_VC_INT_CLEAR);
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_BUF_OVERWRITE_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
dprintk(1, "We have no more avilable buffers\n");
return IRQ_HANDLED;
}
@@ -166,6 +196,9 @@
spin_lock(&dev->vc_client->cap_slock);
if (list_empty(&dev->vc_client->vid_vc_action.active)) {
spin_unlock(&dev->vc_client->cap_slock);
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_BUF_OVERWRITE_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
writel_relaxed(irq, VCAP_VC_INT_CLEAR);
return IRQ_HANDLED;
}
@@ -187,8 +220,11 @@
spin_lock(&dev->vc_client->cap_slock);
vb = &dev->vc_client->vid_vc_action.buf2->vb;
if (list_empty(&dev->vc_client->vid_vc_action.active)) {
- writel_relaxed(irq, VCAP_VC_INT_CLEAR);
spin_unlock(&dev->vc_client->cap_slock);
+ writel_relaxed(irq, VCAP_VC_INT_CLEAR);
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_BUF_OVERWRITE_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
return IRQ_HANDLED;
}
buf = list_entry(dev->vc_client->vid_vc_action.active.next,
diff --git a/drivers/media/video/vcap_vp.c b/drivers/media/video/vcap_vp.c
index f8dfdc1..1b503ba 100644
--- a/drivers/media/video/vcap_vp.c
+++ b/drivers/media/video/vcap_vp.c
@@ -20,6 +20,7 @@
#include <mach/clk.h>
#include <linux/clk.h>
+#include <media/v4l2-event.h>
#include <media/vcap_v4l2.h>
#include <media/vcap_fmt.h>
#include "vcap_vp.h"
@@ -254,13 +255,35 @@
{
struct vcap_client_data *c_data;
struct vp_action *vp_act;
+ struct v4l2_event v4l2_evt;
uint32_t irq;
int rc;
irq = readl_relaxed(VCAP_VP_INT_STATUS);
+ if (irq & 0x02000000) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VP_REG_R_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ if (irq & 0x01000000) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VC_LINE_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ if (irq & 0x00020000) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VP_IN_HEIGHT_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+ if (irq & 0x00010000) {
+ v4l2_evt.type = V4L2_EVENT_PRIVATE_START +
+ VCAP_VP_IN_WIDTH_ERR_EVENT;
+ v4l2_event_queue(dev->vfd, &v4l2_evt);
+ }
+
dprintk(1, "%s: irq=0x%08x\n", __func__, irq);
- if (!irq & VP_PIC_DONE) {
+ if (!(irq & VP_PIC_DONE)) {
writel_relaxed(irq, VCAP_VP_INT_CLEAR);
pr_err("VP IRQ shows some error\n");
return IRQ_HANDLED;
@@ -530,7 +553,7 @@
chroma_fmt << 11 | 0x2 << 4, VCAP_VP_IN_CONFIG);
chroma_fmt = 0;
- if (c_data->vp_in_fmt.pixfmt == V4L2_PIX_FMT_NV16)
+ if (c_data->vp_out_fmt.pixfmt == V4L2_PIX_FMT_NV16)
chroma_fmt = 1;
writel_relaxed((c_data->vp_in_fmt.width / 16) << 20 |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7c61bf3..8c392fc 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -936,6 +936,14 @@
This is required to use certain other PM 8xxx features, such as GPIO
and MPP.
+config MFD_PM8821_IRQ
+ bool "Support for Qualcomm PM8821 IRQ features"
+ default y if MFD_PM8821_CORE
+ help
+ This is the IRQ driver for Qualcomm PM 8821 PMIC chips.
+
+ This is required to use certain other PM 8821 features, such as MPPs.
+
config TPS65911_COMPARATOR
tristate
@@ -1035,6 +1043,18 @@
read/write capability to registers which are part of the
WCD9310 core and gives the ability to use the WCD9310 codec.
+config WCD9320_CODEC
+ tristate "WCD9320 Codec"
+ select SLIMBUS
+ select MFD_CORE
+ help
+ Enables the WCD9xxx codec core driver. The core driver provides
+ read/write capability to registers which are part of the
+ WCD9320 core and gives the ability to use the WCD9320 codec.
+ The WCD9320 codec support either I2C/I2S or Slimbus for
+ control and data exchnage with master processor.
+
+
config MFD_RC5T583
bool "Ricoh RC5T583 Power Management system device"
depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e81e4b1..07552c8 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -80,6 +80,8 @@
obj-$(CONFIG_WCD9310_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
obj-$(CONFIG_WCD9304_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
+obj-$(CONFIG_WCD9320_CODEC) += wcd9xxx-core.o wcd9xxx-irq.o wcd9xxx-slimslave.o
+
ifeq ($(CONFIG_SA1100_ASSABET),y)
obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o
@@ -137,6 +139,7 @@
obj-$(CONFIG_MFD_PM8018_CORE) += pm8018-core.o
obj-$(CONFIG_MFD_PM8038_CORE) += pm8038-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
+obj-$(CONFIG_MFD_PM8821_IRQ) += pm8821-irq.o
obj-$(CONFIG_MFD_PM8XXX_DEBUG) += pm8xxx-debug.o
obj-$(CONFIG_MFD_PM8XXX_PWM) += pm8xxx-pwm.o
obj-$(CONFIG_MFD_PM8XXX_MISC) += pm8xxx-misc.o
diff --git a/drivers/mfd/marimba-tsadc.c b/drivers/mfd/marimba-tsadc.c
index 8a7b781..32b93e1 100644
--- a/drivers/mfd/marimba-tsadc.c
+++ b/drivers/mfd/marimba-tsadc.c
@@ -437,7 +437,7 @@
struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
if (tsadc->clk_enabled == true) {
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
tsadc->clk_enabled = false;
}
@@ -462,7 +462,7 @@
marimba_tsadc_configure(tsadc_dev);
fail_shutdown:
if (tsadc->clk_enabled == false) {
- ret = clk_enable(tsadc->codec_ssbi);
+ ret = clk_prepare_enable(tsadc->codec_ssbi);
if (ret == 0)
tsadc->clk_enabled = true;
}
@@ -475,7 +475,7 @@
struct marimba_tsadc *tsadc = dev_get_drvdata(dev);
if (tsadc->clk_enabled == false) {
- rc = clk_enable(tsadc->codec_ssbi);
+ rc = clk_prepare_enable(tsadc->codec_ssbi);
if (rc != 0) {
pr_err("%s: Clk enable failed\n", __func__);
return rc;
@@ -515,7 +515,7 @@
tsadc->pdata->marimba_tsadc_power(0);
fail_tsadc_power:
if (tsadc->clk_enabled == true) {
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
tsadc->clk_enabled = false;
}
return rc;
@@ -591,7 +591,7 @@
rc = PTR_ERR(tsadc->codec_ssbi);
goto fail_clk_get;
}
- rc = clk_enable(tsadc->codec_ssbi);
+ rc = clk_prepare_enable(tsadc->codec_ssbi);
if (rc != 0)
goto fail_clk_enable;
@@ -623,7 +623,7 @@
return rc;
fail_add_subdev:
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
fail_clk_enable:
clk_put(tsadc->codec_ssbi);
@@ -647,7 +647,7 @@
device_init_wakeup(&pdev->dev, 0);
if (tsadc->clk_enabled == true)
- clk_disable(tsadc->codec_ssbi);
+ clk_disable_unprepare(tsadc->codec_ssbi);
clk_put(tsadc->codec_ssbi);
diff --git a/drivers/mfd/pm8038-core.c b/drivers/mfd/pm8038-core.c
index 4271a2a..8fef786 100644
--- a/drivers/mfd/pm8038-core.c
+++ b/drivers/mfd/pm8038-core.c
@@ -36,6 +36,9 @@
#define REG_SPK_BASE 0x253
#define REG_SPK_REGISTERS 3
+#define REG_TEMP_ALARM_CTRL 0x01B
+#define REG_TEMP_ALARM_PWM 0x09B
+
#define PM8038_VERSION_MASK 0xFFF0
#define PM8038_VERSION_VALUE 0x09F0
#define PM8038_REVISION_MASK 0x000F
@@ -300,6 +303,30 @@
.pdata_size = sizeof("pm8038-dbg"),
};
+static const struct resource thermal_alarm_cell_resources[] __devinitconst = {
+ SINGLE_IRQ_RESOURCE("pm8038_tempstat_irq", PM8038_TEMPSTAT_IRQ),
+ SINGLE_IRQ_RESOURCE("pm8038_overtemp_irq", PM8038_OVERTEMP_IRQ),
+};
+
+static struct pm8xxx_tm_core_data thermal_alarm_cdata = {
+ .adc_channel = CHANNEL_DIE_TEMP,
+ .adc_type = PM8XXX_TM_ADC_PM8XXX_ADC,
+ .reg_addr_temp_alarm_ctrl = REG_TEMP_ALARM_CTRL,
+ .reg_addr_temp_alarm_pwm = REG_TEMP_ALARM_PWM,
+ .tm_name = "pm8038_tz",
+ .irq_name_temp_stat = "pm8038_tempstat_irq",
+ .irq_name_over_temp = "pm8038_overtemp_irq",
+};
+
+static struct mfd_cell thermal_alarm_cell __devinitdata = {
+ .name = PM8XXX_TM_DEV_NAME,
+ .id = -1,
+ .resources = thermal_alarm_cell_resources,
+ .num_resources = ARRAY_SIZE(thermal_alarm_cell_resources),
+ .platform_data = &thermal_alarm_cdata,
+ .pdata_size = sizeof(struct pm8xxx_tm_core_data),
+};
+
static struct pm8xxx_vreg regulator_data[] = {
/* name pc_name ctrl test hpm_min */
NLDO1200("8038_l1", 0x0AE, 0x0AF, LDO_1200),
@@ -606,6 +633,14 @@
goto bail;
}
}
+
+ ret = mfd_add_devices(pmic->dev, 0, &thermal_alarm_cell, 1, NULL,
+ irq_base);
+ if (ret) {
+ pr_err("Failed to add thermal alarm subdevice ret=%d\n", ret);
+ goto bail;
+ }
+
return 0;
bail:
if (pmic->irq_chip) {
diff --git a/drivers/mfd/pm8821-core.c b/drivers/mfd/pm8821-core.c
index df9d2e1..1d3c927a 100644
--- a/drivers/mfd/pm8821-core.c
+++ b/drivers/mfd/pm8821-core.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -27,7 +27,7 @@
#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
#define REG_MPP_BASE 0x050
-#define REG_IRQ_BASE 0x1BB
+#define REG_IRQ_BASE 0x100
#define PM8821_VERSION_MASK 0xFFF0
#define PM8821_VERSION_VALUE 0x0BF0
@@ -86,7 +86,7 @@
const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
- return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
+ return pm8821_get_irq_stat(pmic->irq_chip, irq);
}
static enum pm8xxx_version pm8821_get_version(const struct device *dev)
@@ -154,7 +154,7 @@
pdata->irq_pdata->irq_cdata.nirqs = PM8821_NR_IRQS;
pdata->irq_pdata->irq_cdata.base_addr = REG_IRQ_BASE;
irq_base = pdata->irq_pdata->irq_base;
- irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+ irq_chip = pm8821_irq_init(pmic->dev, pdata->irq_pdata);
if (IS_ERR(irq_chip)) {
pr_err("Failed to init interrupts ret=%ld\n",
@@ -186,7 +186,7 @@
return 0;
bail:
if (pmic->irq_chip) {
- pm8xxx_irq_exit(pmic->irq_chip);
+ pm8821_irq_exit(pmic->irq_chip);
pmic->irq_chip = NULL;
}
return ret;
@@ -281,7 +281,7 @@
if (pmic)
mfd_remove_devices(pmic->dev);
if (pmic->irq_chip) {
- pm8xxx_irq_exit(pmic->irq_chip);
+ pm8821_irq_exit(pmic->irq_chip);
pmic->irq_chip = NULL;
}
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/mfd/pm8821-irq.c b/drivers/mfd/pm8821-irq.c
new file mode 100644
index 0000000..2dcc792
--- /dev/null
+++ b/drivers/mfd/pm8821-irq.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/export.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/pm8821-irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define PM8821_TOTAL_IRQ_MASTERS 2
+#define PM8821_BLOCKS_PER_MASTER 7
+#define PM8821_IRQ_MASTER1_SET 0x01
+#define PM8821_IRQ_CLEAR_OFFSET 0x01
+#define PM8821_IRQ_RT_STATUS_OFFSET 0x0F
+#define PM8821_IRQ_MASK_REG_OFFSET 0x08
+#define SSBI_REG_ADDR_IRQ_MASTER0 0x30
+#define SSBI_REG_ADDR_IRQ_MASTER1 0xB0
+
+#define SSBI_REG_ADDR_IRQ_IT_STATUS(master_base, block) (master_base + block)
+
+/*
+ * Block 0 does not exist in PM8821 IRQ SSBI address space,
+ * IRQ0 is assigned to bit0 of block1.
+ */
+#define SSBI_REG_ADDR_IRQ_IT_CLEAR(master_base, block) \
+ (master_base + PM8821_IRQ_CLEAR_OFFSET + block)
+
+#define SSBI_REG_ADDR_IRQ_RT_STATUS(master_base, block) \
+ (master_base + PM8821_IRQ_RT_STATUS_OFFSET + block)
+
+#define SSBI_REG_ADDR_IRQ_MASK(master_base, block) \
+ (master_base + PM8821_IRQ_MASK_REG_OFFSET + block)
+
+struct pm_irq_chip {
+ struct device *dev;
+ spinlock_t pm_irq_lock;
+ unsigned int base_addr;
+ unsigned int devirq;
+ unsigned int irq_base;
+ unsigned int num_irqs;
+ int masters[PM8821_TOTAL_IRQ_MASTERS];
+};
+
+static int pm8821_irq_masked_write(struct pm_irq_chip *chip, u16 addr,
+ u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = pm8xxx_readb(chip->dev, addr, ®);
+ if (rc) {
+ pr_err("read failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+
+ reg &= ~mask;
+ reg |= val & mask;
+
+ rc = pm8xxx_writeb(chip->dev, addr, reg);
+ if (rc) {
+ pr_err("write failed addr = %03X, rc = %d\n", addr, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int pm8821_read_master_irq(const struct pm_irq_chip *chip,
+ int m, u8 *master)
+{
+ return pm8xxx_readb(chip->dev, chip->masters[m], master);
+}
+
+static int pm8821_read_block_irq(struct pm_irq_chip *chip, int master,
+ u8 block, u8 *bits)
+{
+ int rc;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_IT_STATUS(chip->masters[master], block), bits);
+ if (rc)
+ pr_err("Failed Reading Status rc=%d\n", rc);
+
+ spin_unlock(&chip->pm_irq_lock);
+ return rc;
+}
+
+
+static int pm8821_irq_block_handler(struct pm_irq_chip *chip,
+ int master_number, int block)
+{
+ int pmirq, irq, i, ret;
+ u8 bits;
+
+ ret = pm8821_read_block_irq(chip, master_number, block, &bits);
+ if (ret) {
+ pr_err("Failed reading %d block ret=%d", block, ret);
+ return ret;
+ }
+ if (!bits) {
+ pr_err("block bit set in master but no irqs: %d", block);
+ return 0;
+ }
+
+ /* Convert block offset to global block number */
+ block += (master_number * PM8821_BLOCKS_PER_MASTER) - 1;
+
+ /* Check IRQ bits */
+ for (i = 0; i < 8; i++) {
+ if (bits & BIT(i)) {
+ pmirq = (block << 3) + i;
+ irq = pmirq + chip->irq_base;
+ generic_handle_irq(irq);
+ }
+ }
+ return 0;
+}
+
+static int pm8821_irq_read_master(struct pm_irq_chip *chip,
+ int master_number, u8 master_val)
+{
+ int ret = 0;
+ int block;
+
+ for (block = 1; block < 8; block++) {
+ if (master_val & BIT(block)) {
+ ret |= pm8821_irq_block_handler(chip,
+ master_number, block);
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t pm8821_irq_handler(int irq, void *data)
+{
+ struct pm_irq_chip *chip = data;
+ int ret;
+ u8 master;
+
+ ret = pm8821_read_master_irq(chip, 0, &master);
+ if (ret) {
+ pr_err("Failed to read master 0 ret=%d\n", ret);
+ return ret;
+ }
+
+ if (master & ~PM8821_IRQ_MASTER1_SET)
+ pm8821_irq_read_master(chip, 0, master);
+
+ if (!(master & PM8821_IRQ_MASTER1_SET))
+ goto done;
+
+ ret = pm8821_read_master_irq(chip, 1, &master);
+ if (ret) {
+ pr_err("Failed to read master 1 ret=%d\n", ret);
+ return ret;
+ }
+
+ pm8821_irq_read_master(chip, 1, master);
+
+done:
+ return IRQ_HANDLED;
+}
+
+static void pm8821_irq_mask(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int irq_bit, rc;
+ u8 block, master;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+ BIT(irq_bit), BIT(irq_bit));
+
+ if (rc)
+ pr_err("Failed to read/write mask IRQ:%d rc=%d\n", pmirq, rc);
+
+ spin_unlock(&chip->pm_irq_lock);
+}
+
+static void pm8821_irq_mask_ack(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int irq_bit, rc;
+ u8 block, master;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+ BIT(irq_bit), BIT(irq_bit));
+
+ if (rc) {
+ pr_err("Failed to read/write mask IRQ:%d rc=%d\n", pmirq, rc);
+ goto fail;
+ }
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_IT_CLEAR(chip->masters[master], block),
+ BIT(irq_bit), BIT(irq_bit));
+
+ if (rc) {
+ pr_err("Failed to read/write IT_CLEAR IRQ:%d rc=%d\n",
+ pmirq, rc);
+ }
+
+fail:
+ spin_unlock(&chip->pm_irq_lock);
+}
+
+static void pm8821_irq_unmask(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int irq_bit, rc;
+ u8 block, master;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ irq_bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock(&chip->pm_irq_lock);
+
+ rc = pm8821_irq_masked_write(chip,
+ SSBI_REG_ADDR_IRQ_MASK(chip->masters[master], block),
+ BIT(irq_bit), ~BIT(irq_bit));
+
+ if (rc)
+ pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc);
+
+ spin_unlock(&chip->pm_irq_lock);
+}
+
+static int pm8821_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ /*
+ * PM8821 IRQ controller does not have explicit software support for
+ * IRQ flow type.
+ */
+ return 0;
+}
+
+static int pm8821_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ return 0;
+}
+
+static int pm8821_irq_read_line(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+
+ return pm8821_get_irq_stat(chip, d->irq);
+}
+
+static struct irq_chip pm_irq_chip = {
+ .name = "pm8821-irq",
+ .irq_mask = pm8821_irq_mask,
+ .irq_mask_ack = pm8821_irq_mask_ack,
+ .irq_unmask = pm8821_irq_unmask,
+ .irq_set_type = pm8821_irq_set_type,
+ .irq_set_wake = pm8821_irq_set_wake,
+ .irq_read_line = pm8821_irq_read_line,
+ .flags = IRQCHIP_MASK_ON_SUSPEND,
+};
+
+/**
+ * pm8821_get_irq_stat - get the status of the irq line
+ * @chip: pointer to identify a pmic irq controller
+ * @irq: the irq number
+ *
+ * The pm8821 gpio and mpp rely on the interrupt block to read
+ * the values on their pins. This function is to facilitate reading
+ * the status of a gpio or an mpp line. The caller has to convert the
+ * gpio number to irq number.
+ *
+ * RETURNS:
+ * an int indicating the value read on that line
+ */
+int pm8821_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+ int pmirq, rc;
+ u8 block, bits, bit, master;
+ unsigned long flags;
+
+ if (chip == NULL || irq < chip->irq_base
+ || irq >= chip->irq_base + chip->num_irqs)
+ return -EINVAL;
+
+ pmirq = irq - chip->irq_base;
+
+ block = pmirq >> 3;
+ master = block / PM8821_BLOCKS_PER_MASTER;
+ bit = pmirq % 8;
+ block %= PM8821_BLOCKS_PER_MASTER;
+
+ spin_lock_irqsave(&chip->pm_irq_lock, flags);
+
+ rc = pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_RT_STATUS(chip->masters[master], block),
+ &bits);
+ if (rc) {
+ pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
+ irq, pmirq, block, rc);
+ goto bail_out;
+ }
+
+ rc = (bits & BIT(bit)) ? 1 : 0;
+
+bail_out:
+ spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pm8821_get_irq_stat);
+
+struct pm_irq_chip * __devinit pm8821_irq_init(struct device *dev,
+ const struct pm8xxx_irq_platform_data *pdata)
+{
+ struct pm_irq_chip *chip;
+ int devirq, rc, blocks, masters;
+ unsigned int pmirq;
+
+ if (!pdata) {
+ pr_err("No platform data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ devirq = pdata->devirq;
+ if (devirq < 0) {
+ pr_err("missing devirq\n");
+ rc = devirq;
+ return ERR_PTR(-EINVAL);
+ }
+
+ chip = kzalloc(sizeof(struct pm_irq_chip)
+ + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
+ if (!chip) {
+ pr_err("Cannot alloc pm_irq_chip struct\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ chip->dev = dev;
+ chip->devirq = devirq;
+ chip->irq_base = pdata->irq_base;
+ chip->num_irqs = pdata->irq_cdata.nirqs;
+ chip->base_addr = pdata->irq_cdata.base_addr;
+ blocks = DIV_ROUND_UP(pdata->irq_cdata.nirqs, 8);
+ masters = DIV_ROUND_UP(blocks, PM8821_BLOCKS_PER_MASTER);
+ chip->masters[0] = chip->base_addr + SSBI_REG_ADDR_IRQ_MASTER0;
+ chip->masters[1] = chip->base_addr + SSBI_REG_ADDR_IRQ_MASTER1;
+
+ if (masters != PM8821_TOTAL_IRQ_MASTERS) {
+ pr_err("Unequal number of masters, passed: %d, "
+ "should have been: %d\n", masters, PM8821_TOTAL_IRQ_MASTERS);
+ kfree(chip);
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_lock_init(&chip->pm_irq_lock);
+
+ for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
+ irq_set_chip_and_handler(chip->irq_base + pmirq,
+ &pm_irq_chip, handle_level_irq);
+ irq_set_chip_data(chip->irq_base + pmirq, chip);
+#ifdef CONFIG_ARM
+ set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
+#else
+ irq_set_noprobe(chip->irq_base + pmirq);
+#endif
+ }
+
+ if (devirq != 0) {
+ rc = request_irq(devirq, pm8821_irq_handler,
+ pdata->irq_trigger_flag, "pm8821_sec_irq", chip);
+ if (rc) {
+ pr_err("failed to request_irq for %d rc=%d\n",
+ devirq, rc);
+ kfree(chip);
+ return ERR_PTR(rc);
+ } else
+ irq_set_irq_wake(devirq, 1);
+ }
+
+ return chip;
+}
+
+int pm8821_irq_exit(struct pm_irq_chip *chip)
+{
+ irq_set_chained_handler(chip->devirq, NULL);
+ kfree(chip);
+ return 0;
+}
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index bbb2509..021dcf1 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -31,7 +31,8 @@
#define WCD9XXX_SLIM_RW_MAX_TRIES 3
#define MAX_WCD9XXX_DEVICE 4
-#define WCD9XXX_I2C_MODE 0x03
+#define TABLA_I2C_MODE 0x03
+#define SITAR_I2C_MODE 0x01
struct wcd9xxx_i2c {
struct i2c_client *client;
@@ -351,15 +352,15 @@
* care of now only tabla.
*/
pr_debug("%s : Read codec version using I2C\n", __func__);
- if (TABLA_IS_1_X(wcd9xxx->version)) {
+ if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5)) {
+ wcd9xxx_dev = sitar_devs;
+ wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
+ } else if (TABLA_IS_1_X(wcd9xxx->version)) {
wcd9xxx_dev = tabla1x_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla1x_devs);
} else if (TABLA_IS_2_0(wcd9xxx->version)) {
wcd9xxx_dev = tabla_devs;
wcd9xxx_dev_size = ARRAY_SIZE(tabla_devs);
- } else {
- wcd9xxx_dev = sitar_devs;
- wcd9xxx_dev_size = ARRAY_SIZE(sitar_devs);
}
}
@@ -712,8 +713,10 @@
struct wcd9xxx_pdata *pdata = client->dev.platform_data;
int val = 0;
int ret = 0;
+ int i2c_mode = 0;
static int device_id;
+ pr_info("%s\n", __func__);
if (wcd9xxx_intf == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
pr_info("tabla card is already detected in slimbus mode\n");
return -ENODEV;
@@ -765,10 +768,13 @@
/*read the tabla status before initializing the device type*/
ret = wcd9xxx_read(wcd9xxx, WCD9XXX_A_CHIP_STATUS, 1, &val, 0);
- if ((ret < 0) || (val != WCD9XXX_I2C_MODE)) {
- pr_err("failed to read the wcd9xxx status\n");
- goto err_device_init;
- }
+ if (!strncmp(wcd9xxx_modules[0].client->name, "sitar", 5))
+ i2c_mode = SITAR_I2C_MODE;
+ else if (!strncmp(wcd9xxx_modules[0].client->name, "tabla", 5))
+ i2c_mode = TABLA_I2C_MODE;
+
+ if ((ret < 0) || (val != i2c_mode))
+ pr_err("failed to read the wcd9xxx status ret = %d\n", ret);
ret = wcd9xxx_device_init(wcd9xxx, wcd9xxx->irq);
if (ret) {
@@ -1107,16 +1113,25 @@
.suspend = wcd9xxx_slim_suspend,
};
-#define TABLA_I2C_TOP_LEVEL 0
-#define TABLA_I2C_ANALOG 1
-#define TABLA_I2C_DIGITAL_1 2
-#define TABLA_I2C_DIGITAL_2 3
+#define WCD9XXX_I2C_TOP_LEVEL 0
+#define WCD9XXX_I2C_ANALOG 1
+#define WCD9XXX_I2C_DIGITAL_1 2
+#define WCD9XXX_I2C_DIGITAL_2 3
static struct i2c_device_id tabla_id_table[] = {
- {"tabla top level", TABLA_I2C_TOP_LEVEL},
- {"tabla analog", TABLA_I2C_TOP_LEVEL},
- {"tabla digital1", TABLA_I2C_TOP_LEVEL},
- {"tabla digital2", TABLA_I2C_TOP_LEVEL},
+ {"tabla top level", WCD9XXX_I2C_TOP_LEVEL},
+ {"tabla analog", WCD9XXX_I2C_ANALOG},
+ {"tabla digital1", WCD9XXX_I2C_DIGITAL_1},
+ {"tabla digital2", WCD9XXX_I2C_DIGITAL_2},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, tabla_id_table);
+
+static struct i2c_device_id sitar_id_table[] = {
+ {"sitar top level", WCD9XXX_I2C_TOP_LEVEL},
+ {"sitar analog", WCD9XXX_I2C_ANALOG},
+ {"sitar digital1", WCD9XXX_I2C_DIGITAL_1},
+ {"sitar digital2", WCD9XXX_I2C_DIGITAL_2},
{}
};
MODULE_DEVICE_TABLE(i2c, tabla_id_table);
@@ -1133,9 +1148,21 @@
.suspend = wcd9xxx_i2c_suspend,
};
+static struct i2c_driver sitar_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "sitar-i2c-core",
+ },
+ .id_table = sitar_id_table,
+ .probe = wcd9xxx_i2c_probe,
+ .remove = __devexit_p(wcd9xxx_i2c_remove),
+ .resume = wcd9xxx_i2c_resume,
+ .suspend = wcd9xxx_i2c_suspend,
+};
+
static int __init wcd9xxx_init(void)
{
- int ret1, ret2, ret3, ret4, ret5;
+ int ret1, ret2, ret3, ret4, ret5, ret6;
ret1 = slim_driver_register(&tabla_slim_driver);
if (ret1 != 0)
@@ -1157,7 +1184,11 @@
if (ret5 != 0)
pr_err("Failed to register sitar SB driver: %d\n", ret5);
- return (ret1 && ret2 && ret3 && ret4 && ret5) ? -1 : 0;
+ ret6 = i2c_add_driver(&sitar_i2c_driver);
+ if (ret6 != 0)
+ pr_err("failed to add the I2C driver\n");
+
+ return (ret1 && ret2 && ret3 && ret4 && ret5 && ret6) ? -1 : 0;
}
module_init(wcd9xxx_init);
diff --git a/drivers/mfd/wcd9xxx-slimslave.c b/drivers/mfd/wcd9xxx-slimslave.c
index 538ca7c..889c416 100644
--- a/drivers/mfd/wcd9xxx-slimslave.c
+++ b/drivers/mfd/wcd9xxx-slimslave.c
@@ -472,6 +472,12 @@
grph = rx[idx].grph;
}
+ /* slim_disconnect_port */
+ ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
+ if (ret < 0) {
+ pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
+ __func__, ret);
+ }
/* slim_control_ch (REMOVE) */
ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
if (ret < 0) {
@@ -510,7 +516,12 @@
sph[i] = tx[idx].sph;
grph = tx[idx].grph;
}
-
+ /* slim_disconnect_port */
+ ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
+ if (ret < 0) {
+ pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
+ __func__, ret);
+ }
/* slim_control_ch (REMOVE) */
ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
if (ret < 0) {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1c2f018..3c28447 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -628,14 +628,6 @@
PMIC8058. Driver interface to program registers of the ADC over
AMUX channels, devices on programmable MPP's and xotherm.
-config TZCOM
- tristate "Trustzone Communicator driver"
- default n
- help
- Provides a communication interface between userspace and
- TrustZone Operating Environment (TZBSP) using Secure Channel
- Manager (SCM) interface.
-
config QSEECOM
tristate "Qualcomm Secure Execution Communicator driver"
help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b628976..be3d0a0 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -69,6 +69,5 @@
obj-$(CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN) \
+= msm_migrate_pages.o
obj-$(CONFIG_PMIC8058_XOADC) += pmic8058-xoadc.o
-obj-$(CONFIG_TZCOM) += tzcom.o
obj-$(CONFIG_QSEECOM) += qseecom.o
obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 4c92ee5..d5afe8d 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1717,19 +1717,22 @@
}
/* register client for bus scaling */
- qseecom_platform_support = (struct msm_bus_scale_pdata *)
- pdev->dev.platform_data;
- qsee_perf_client = msm_bus_scale_register_client(
- qseecom_platform_support);
- if (!qsee_perf_client) {
- pr_err("Unable to register bus client\n");
- } else {
- qseecom_bus_clk = clk_get(class_dev, "bus_clk");
- if (IS_ERR(qseecom_bus_clk)) {
- qseecom_bus_clk = NULL;
- } else if (qseecom_bus_clk != NULL) {
- pr_debug("Enabled DFAB clock");
- clk_set_rate(qseecom_bus_clk, 64000000);
+ if (!pdev->dev.of_node) {
+ qseecom_platform_support = (struct msm_bus_scale_pdata *)
+ pdev->dev.platform_data;
+ qsee_perf_client = msm_bus_scale_register_client(
+ qseecom_platform_support);
+
+ if (!qsee_perf_client) {
+ pr_err("Unable to register bus client\n");
+ } else {
+ qseecom_bus_clk = clk_get(class_dev, "bus_clk");
+ if (IS_ERR(qseecom_bus_clk)) {
+ qseecom_bus_clk = NULL;
+ } else if (qseecom_bus_clk != NULL) {
+ pr_debug("Enabled DFAB clock");
+ clk_set_rate(qseecom_bus_clk, 64000000);
+ }
}
}
return 0;
@@ -1750,12 +1753,20 @@
return 0;
};
+static struct of_device_id qseecom_match[] = {
+ {
+ .compatible = "qcom,qseecom",
+ },
+ {}
+};
+
static struct platform_driver qseecom_plat_driver = {
.probe = qseecom_probe,
.remove = qseecom_remove,
.driver = {
.name = "qseecom",
.owner = THIS_MODULE,
+ .of_match_table = qseecom_match,
},
};
diff --git a/drivers/misc/tzcom.c b/drivers/misc/tzcom.c
deleted file mode 100644
index 3b943c8..0000000
--- a/drivers/misc/tzcom.c
+++ /dev/null
@@ -1,1248 +0,0 @@
-/* Qualcomm TrustZone communicator driver
- *
- * Copyright (c) 2011-2012, Code Aurora Forum. 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.
- */
-
-#define KMSG_COMPONENT "TZCOM"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/platform_device.h>
-#include <linux/debugfs.h>
-#include <linux/cdev.h>
-#include <linux/uaccess.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/android_pmem.h>
-#include <linux/io.h>
-#include <linux/ion.h>
-#include <linux/tzcom.h>
-#include <linux/clk.h>
-#include <mach/scm.h>
-#include <mach/peripheral-loader.h>
-#include <mach/msm_bus.h>
-#include <mach/msm_bus_board.h>
-#include <mach/socinfo.h>
-#include "tzcomi.h"
-
-#define TZCOM_DEV "tzcom"
-
-#define TZSCHEDULER_CMD_ID 1 /* CMD id of the trustzone scheduler */
-
-#undef PDEBUG
-#define PDEBUG(fmt, args...) pr_debug("%s(%i, %s): " fmt "\n", \
- __func__, current->pid, current->comm, ## args)
-
-#undef PERR
-#define PERR(fmt, args...) pr_err("%s(%i, %s): " fmt "\n", \
- __func__, current->pid, current->comm, ## args)
-
-#undef PWARN
-#define PWARN(fmt, args...) pr_warning("%s(%i, %s): " fmt "\n", \
- __func__, current->pid, current->comm, ## args)
-
-
-static uint32_t tzcom_perf_client;
-static struct class *driver_class;
-static dev_t tzcom_device_no;
-static struct cdev tzcom_cdev;
-struct ion_client *ion_clnt;
-static u8 *sb_in_virt;
-static s32 sb_in_phys;
-static size_t sb_in_length = 20 * SZ_1K;
-static u8 *sb_out_virt;
-static s32 sb_out_phys;
-static size_t sb_out_length = 20 * SZ_1K;
-
-static void *pil;
-
-static atomic_t svc_instance_ctr = ATOMIC_INIT(0);
-static DEFINE_MUTEX(sb_in_lock);
-static DEFINE_MUTEX(sb_out_lock);
-static DEFINE_MUTEX(send_cmd_lock);
-static DEFINE_MUTEX(tzcom_bw_mutex);
-static int tzcom_bw_count;
-static struct clk *tzcom_bus_clk;
-struct tzcom_callback_list {
- struct list_head list;
- struct tzcom_callback callback;
-};
-
-struct tzcom_registered_svc_list {
- struct list_head list;
- struct tzcom_register_svc_op_req svc;
- wait_queue_head_t next_cmd_wq;
- int next_cmd_flag;
-};
-
-struct tzcom_data_t {
- struct list_head callback_list_head;
- struct mutex callback_list_lock;
- struct list_head registered_svc_list_head;
- spinlock_t registered_svc_list_lock;
- wait_queue_head_t cont_cmd_wq;
- int cont_cmd_flag;
- u32 handled_cmd_svc_instance_id;
- int abort;
- wait_queue_head_t abort_wq;
- atomic_t ioctl_count;
-};
-
-static int tzcom_enable_bus_scaling(void)
-{
- int ret = 0;
- if (!tzcom_perf_client)
- return -EINVAL;
-
- if (IS_ERR_OR_NULL(tzcom_bus_clk))
- return -EINVAL;
-
- mutex_lock(&tzcom_bw_mutex);
- if (!tzcom_bw_count) {
- ret = msm_bus_scale_client_update_request(
- tzcom_perf_client, 1);
- if (ret) {
- pr_err("Bandwidth request failed (%d)\n", ret);
- } else {
- ret = clk_enable(tzcom_bus_clk);
- if (ret)
- pr_err("Clock enable failed\n");
- }
- }
- if (ret)
- msm_bus_scale_client_update_request(tzcom_perf_client, 0);
- else
- tzcom_bw_count++;
- mutex_unlock(&tzcom_bw_mutex);
- return ret;
-}
-
-static void tzcom_disable_bus_scaling(void)
-{
- if (!tzcom_perf_client)
- return ;
-
- if (IS_ERR_OR_NULL(tzcom_bus_clk))
- return ;
-
- mutex_lock(&tzcom_bw_mutex);
- if (tzcom_bw_count > 0)
- if (tzcom_bw_count-- == 1) {
- msm_bus_scale_client_update_request(tzcom_perf_client,
- 0);
- clk_disable(tzcom_bus_clk);
- }
- mutex_unlock(&tzcom_bw_mutex);
-}
-
-static int tzcom_scm_call(const void *cmd_buf, size_t cmd_len,
- void *resp_buf, size_t resp_len)
-{
- return scm_call(SCM_SVC_TZSCHEDULER, TZSCHEDULER_CMD_ID,
- cmd_buf, cmd_len, resp_buf, resp_len);
-}
-
-static s32 tzcom_virt_to_phys(u8 *virt)
-{
- if (virt >= sb_in_virt &&
- virt < (sb_in_virt + sb_in_length)) {
- return sb_in_phys + (virt - sb_in_virt);
- } else if (virt >= sb_out_virt &&
- virt < (sb_out_virt + sb_out_length)) {
- return sb_out_phys + (virt - sb_out_virt);
- } else {
- return virt_to_phys(virt);
- }
-}
-
-static u8 *tzcom_phys_to_virt(s32 phys)
-{
- if (phys >= sb_in_phys &&
- phys < (sb_in_phys + sb_in_length)) {
- return sb_in_virt + (phys - sb_in_phys);
- } else if (phys >= sb_out_phys &&
- phys < (sb_out_phys + sb_out_length)) {
- return sb_out_virt + (phys - sb_out_phys);
- } else {
- return phys_to_virt(phys);
- }
-}
-
-static int __tzcom_is_svc_unique(struct tzcom_data_t *data,
- struct tzcom_register_svc_op_req svc)
-{
- struct tzcom_registered_svc_list *ptr;
- int unique = 1;
- unsigned long flags;
-
- spin_lock_irqsave(&data->registered_svc_list_lock, flags);
- list_for_each_entry(ptr, &data->registered_svc_list_head, list) {
- if (ptr->svc.svc_id == svc.svc_id) {
- PERR("Service id: %u is already registered",
- ptr->svc.svc_id);
- unique = 0;
- break;
- } else if (svc.cmd_id_low >= ptr->svc.cmd_id_low &&
- svc.cmd_id_low <= ptr->svc.cmd_id_high) {
- PERR("Cmd id low falls in the range of another"
- "registered service");
- unique = 0;
- break;
- } else if (svc.cmd_id_high >= ptr->svc.cmd_id_low &&
- svc.cmd_id_high <= ptr->svc.cmd_id_high) {
- PERR("Cmd id high falls in the range of another"
- "registered service");
- unique = 0;
- break;
- }
- }
- spin_unlock_irqrestore(&data->registered_svc_list_lock, flags);
- return unique;
-}
-
-static int tzcom_register_service(struct tzcom_data_t *data, void __user *argp)
-{
- int ret;
- unsigned long flags;
- struct tzcom_register_svc_op_req rcvd_svc;
- struct tzcom_registered_svc_list *new_entry;
-
- ret = copy_from_user(&rcvd_svc, argp, sizeof(rcvd_svc));
-
- if (ret) {
- PERR("copy_from_user failed");
- return ret;
- }
-
- PDEBUG("svc_id: %u, cmd_id_low: %u, cmd_id_high: %u",
- rcvd_svc.svc_id, rcvd_svc.cmd_id_low,
- rcvd_svc.cmd_id_high);
- if (!__tzcom_is_svc_unique(data, rcvd_svc)) {
- PERR("Provided service is not unique");
- return -EINVAL;
- }
-
- rcvd_svc.instance_id = atomic_inc_return(&svc_instance_ctr);
-
- ret = copy_to_user(argp, &rcvd_svc, sizeof(rcvd_svc));
- if (ret) {
- PERR("copy_to_user failed");
- return ret;
- }
-
- new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
- if (!new_entry) {
- PERR("kmalloc failed");
- return -ENOMEM;
- }
- memcpy(&new_entry->svc, &rcvd_svc, sizeof(rcvd_svc));
- new_entry->next_cmd_flag = 0;
- init_waitqueue_head(&new_entry->next_cmd_wq);
-
- spin_lock_irqsave(&data->registered_svc_list_lock, flags);
- list_add_tail(&new_entry->list, &data->registered_svc_list_head);
- spin_unlock_irqrestore(&data->registered_svc_list_lock, flags);
-
-
- return ret;
-}
-
-static int tzcom_unregister_service(struct tzcom_data_t *data,
- void __user *argp)
-{
- int ret = 0;
- unsigned long flags;
- struct tzcom_unregister_svc_op_req req;
- struct tzcom_registered_svc_list *ptr, *next;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- PERR("copy_from_user failed");
- return ret;
- }
-
- spin_lock_irqsave(&data->registered_svc_list_lock, flags);
- list_for_each_entry_safe(ptr, next, &data->registered_svc_list_head,
- list) {
- if (req.svc_id == ptr->svc.svc_id &&
- req.instance_id == ptr->svc.instance_id) {
- wake_up_all(&ptr->next_cmd_wq);
- list_del(&ptr->list);
- kfree(ptr);
- spin_unlock_irqrestore(&data->registered_svc_list_lock,
- flags);
- return 0;
- }
- }
- spin_unlock_irqrestore(&data->registered_svc_list_lock, flags);
-
- return -EINVAL;
-}
-
-static int __tzcom_is_cont_cmd(struct tzcom_data_t *data)
-{
- int ret;
- ret = (data->cont_cmd_flag != 0);
- return ret || data->abort;
-}
-
-/**
- * +---------+ +-----+ +-----------------+
- * | TZCOM | | SCM | | TZCOM_SCHEDULER |
- * +----+----+ +--+--+ +--------+--------+
- * | | |
- * | scm_call | |
- * |------------------------------------->| |
- * | cmd_buf = struct tzcom_command { | |
- * | cmd_type, |------------------>|
- * +------+------------- sb_in_cmd_addr, | |
- * | | sb_in_cmd_len | |
- * | | } | |
- * | | resp_buf = struct tzcom_response { | |
- * | cmd_status, | |
- * | +---------- sb_in_rsp_addr, | |
- * | | sb_in_rsp_len |<------------------|
- * | | }
- * | | struct tzcom_callback {---------+
- * | | uint32_t cmd_id; |
- * | | uint32_t sb_out_cb_data_len;|
- * | +---------------+ uint32_t sb_out_cb_data_off;|
- * | | } |
- * | _________________________|_______________________________ |
- * | +-----------------------+| +----------------------+ |
- * +--->+ copy from req.cmd_buf |+>| copy to req.resp_buf | |
- * +-----------------------+ +----------------------+ |
- * _________________________________________________________ |
- * INPUT SHARED BUFFER |
- * +------------------------------------------------------------------------+
- * | _________________________________________________________
- * | +---------------------------------------------+
- * +->| cmd_id | data_len | data_off | data... |
- * +---------------------------------------------+
- * |<------------>|copy to next_cmd.req_buf
- * _________________________________________________________
- * OUTPUT SHARED BUFFER
- */
-static int __tzcom_send_cmd(struct tzcom_data_t *data,
- struct tzcom_send_cmd_op_req *req)
-{
- int ret = 0;
- unsigned long flags;
- u32 reqd_len_sb_in = 0;
- u32 reqd_len_sb_out = 0;
- struct tzcom_command cmd;
- struct tzcom_response resp;
- struct tzcom_callback *next_callback;
- void *cb_data = NULL;
- struct tzcom_callback_list *new_entry;
- struct tzcom_callback *cb;
- size_t new_entry_len = 0;
- struct tzcom_registered_svc_list *ptr_svc;
-
- if (req->cmd_buf == NULL || req->resp_buf == NULL) {
- PERR("cmd buffer or response buffer is null");
- return -EINVAL;
- }
-
- if (req->cmd_len <= 0 || req->resp_len <= 0 ||
- req->cmd_len > sb_in_length || req->resp_len > sb_in_length) {
- PERR("cmd buffer length or "
- "response buffer length not valid");
- return -EINVAL;
- }
- PDEBUG("received cmd_req.req: 0x%p",
- req->cmd_buf);
- PDEBUG("received cmd_req.rsp size: %u, ptr: 0x%p",
- req->resp_len,
- req->resp_buf);
-
- reqd_len_sb_in = req->cmd_len + req->resp_len;
- if (reqd_len_sb_in > sb_in_length) {
- PDEBUG("Not enough memory to fit cmd_buf and "
- "resp_buf. Required: %u, Available: %u",
- reqd_len_sb_in, sb_in_length);
- return -ENOMEM;
- }
-
- /* Copy req->cmd_buf to SB in and set
- * req->resp_buf to SB in + cmd_len
- */
- mutex_lock(&sb_in_lock);
- PDEBUG("Before memcpy on sb_in");
- memcpy(sb_in_virt, req->cmd_buf, req->cmd_len);
- PDEBUG("After memcpy on sb_in");
-
- /* cmd_type will always be a new here */
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *) tzcom_virt_to_phys(sb_in_virt);
- cmd.sb_in_cmd_len = req->cmd_len;
-
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
- resp.sb_in_rsp_addr = (u8 *) tzcom_virt_to_phys(sb_in_virt +
- req->cmd_len);
- resp.sb_in_rsp_len = req->resp_len;
-
- PDEBUG("before call tzcom_scm_call, cmd_id = : %u", req->cmd_id);
- PDEBUG("before call tzcom_scm_call, sizeof(cmd) = : %u", sizeof(cmd));
-
- ret = tzcom_scm_call((const void *) &cmd, sizeof(cmd),
- &resp, sizeof(resp));
- mutex_unlock(&sb_in_lock);
-
- if (ret) {
- PERR("tzcom_scm_call failed with err: %d", ret);
- return ret;
- }
-
- while (resp.cmd_status != TZ_SCHED_STATUS_COMPLETE) {
- /*
- * If cmd is incomplete, get the callback cmd out from SB out
- * and put it on the list
- */
- PDEBUG("cmd_status is incomplete.");
- next_callback = (struct tzcom_callback *)sb_out_virt;
-
- mutex_lock(&sb_out_lock);
- reqd_len_sb_out = sizeof(*next_callback)
- + next_callback->sb_out_cb_data_len;
- if (reqd_len_sb_out > sb_out_length ||
- reqd_len_sb_out < sizeof(*next_callback) ||
- next_callback->sb_out_cb_data_len > sb_out_length) {
- PERR("Incorrect callback data length"
- " Required: %u, Available: %u, Min: %u",
- reqd_len_sb_out, sb_out_length,
- sizeof(*next_callback));
- mutex_unlock(&sb_out_lock);
- return -ENOMEM;
- }
-
- /* Assumption is cb_data_off is sizeof(tzcom_callback) */
- new_entry_len = sizeof(*new_entry)
- + next_callback->sb_out_cb_data_len;
- new_entry = kmalloc(new_entry_len, GFP_KERNEL);
- if (!new_entry) {
- PERR("kmalloc failed");
- mutex_unlock(&sb_out_lock);
- return -ENOMEM;
- }
-
- cb = &new_entry->callback;
- cb->cmd_id = next_callback->cmd_id;
- cb->sb_out_cb_data_len = next_callback->sb_out_cb_data_len;
- cb->sb_out_cb_data_off = sizeof(*cb);
-
- cb_data = (u8 *)next_callback
- + next_callback->sb_out_cb_data_off;
- memcpy((u8 *)cb + cb->sb_out_cb_data_off, cb_data,
- next_callback->sb_out_cb_data_len);
- mutex_unlock(&sb_out_lock);
-
- mutex_lock(&data->callback_list_lock);
- list_add_tail(&new_entry->list, &data->callback_list_head);
- mutex_unlock(&data->callback_list_lock);
-
- /*
- * We don't know which service can handle the command. so we
- * wake up all blocking services and let them figure out if
- * they can handle the given command.
- */
- spin_lock_irqsave(&data->registered_svc_list_lock, flags);
- list_for_each_entry(ptr_svc,
- &data->registered_svc_list_head, list) {
- ptr_svc->next_cmd_flag = 1;
- wake_up_interruptible(&ptr_svc->next_cmd_wq);
- }
- spin_unlock_irqrestore(&data->registered_svc_list_lock,
- flags);
-
- PDEBUG("waking up next_cmd_wq and "
- "waiting for cont_cmd_wq");
- if (wait_event_interruptible(data->cont_cmd_wq,
- __tzcom_is_cont_cmd(data))) {
- PWARN("Interrupted: exiting send_cmd loop");
- return -ERESTARTSYS;
- }
-
- if (data->abort) {
- PERR("Aborting driver");
- return -ENODEV;
- }
- data->cont_cmd_flag = 0;
- cmd.cmd_type = TZ_SCHED_CMD_PENDING;
- mutex_lock(&sb_in_lock);
- ret = tzcom_scm_call((const void *) &cmd, sizeof(cmd), &resp,
- sizeof(resp));
- mutex_unlock(&sb_in_lock);
- if (ret) {
- PERR("tzcom_scm_call failed with err: %d", ret);
- return ret;
- }
- }
-
- mutex_lock(&sb_in_lock);
- resp.sb_in_rsp_addr = sb_in_virt + cmd.sb_in_cmd_len;
- resp.sb_in_rsp_len = req->resp_len;
- memcpy(req->resp_buf, resp.sb_in_rsp_addr, resp.sb_in_rsp_len);
- /* Zero out memory for security purpose */
- memset(sb_in_virt, 0, reqd_len_sb_in);
- mutex_unlock(&sb_in_lock);
-
- return ret;
-}
-
-
-static int tzcom_send_cmd(struct tzcom_data_t *data, void __user *argp)
-{
- int ret = 0;
- struct tzcom_send_cmd_op_req req;
-
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- PERR("copy_from_user failed");
- return ret;
- }
- ret = __tzcom_send_cmd(data, &req);
- if (ret)
- return ret;
-
- PDEBUG("sending cmd_req->rsp "
- "size: %u, ptr: 0x%p", req.resp_len,
- req.resp_buf);
- ret = copy_to_user(argp, &req, sizeof(req));
- if (ret) {
- PDEBUG("copy_to_user failed");
- return ret;
- }
- return ret;
-}
-
-static int __tzcom_send_cmd_req_clean_up(
- struct tzcom_send_cmd_fd_op_req *req)
-{
- char *field;
- uint32_t *update;
- int ret = 0;
- int i = 0;
-
- for (i = 0; i < MAX_ION_FD; i++) {
- if (req->ifd_data[i].fd != 0) {
- field = (char *)req->cmd_buf +
- req->ifd_data[i].cmd_buf_offset;
- update = (uint32_t *) field;
- *update = 0;
- }
- }
- return ret;
-}
-
-static int __tzcom_update_with_phy_addr(
- struct tzcom_send_cmd_fd_op_req *req)
-{
- struct ion_handle *ihandle;
- char *field;
- uint32_t *update;
- ion_phys_addr_t pa;
- int ret = 0;
- int i = 0;
- uint32_t length;
-
- for (i = 0; i < MAX_ION_FD; i++) {
- if (req->ifd_data[i].fd != 0) {
- /* Get the handle of the shared fd */
- ihandle = ion_import_fd(ion_clnt, req->ifd_data[i].fd);
- if (ihandle == NULL) {
- PERR("Ion client can't retrieve the handle\n");
- return -ENOMEM;
- }
- field = (char *) req->cmd_buf +
- req->ifd_data[i].cmd_buf_offset;
- update = (uint32_t *) field;
-
- /* Populate the cmd data structure with the phys_addr */
- ret = ion_phys(ion_clnt, ihandle, &pa, &length);
- if (ret)
- return -ENOMEM;
-
- *update = (uint32_t)pa;
- ion_free(ion_clnt, ihandle);
- }
- }
- return ret;
-}
-
-static int tzcom_send_cmd_with_fd(struct tzcom_data_t *data,
- void __user *argp)
-{
- int ret = 0;
- struct tzcom_send_cmd_fd_op_req req;
- struct tzcom_send_cmd_op_req send_cmd_req;
-
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- PERR("copy_from_user failed");
- return ret;
- }
-
- send_cmd_req.cmd_id = req.cmd_id;
- send_cmd_req.cmd_buf = req.cmd_buf;
- send_cmd_req.cmd_len = req.cmd_len;
- send_cmd_req.resp_buf = req.resp_buf;
- send_cmd_req.resp_len = req.resp_len;
-
- ret = __tzcom_update_with_phy_addr(&req);
- if (ret)
- return ret;
- ret = __tzcom_send_cmd(data, &send_cmd_req);
- __tzcom_send_cmd_req_clean_up(&req);
-
- if (ret)
- return ret;
-
- PDEBUG("sending cmd_req->rsp "
- "size: %u, ptr: 0x%p", req.resp_len,
- req.resp_buf);
- ret = copy_to_user(argp, &req, sizeof(req));
- if (ret) {
- PDEBUG("copy_to_user failed");
- return ret;
- }
- return ret;
-}
-
-static struct tzcom_registered_svc_list *__tzcom_find_svc(
- struct tzcom_data_t *data,
- uint32_t instance_id)
-{
- struct tzcom_registered_svc_list *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&data->registered_svc_list_lock, flags);
- list_for_each_entry(entry,
- &data->registered_svc_list_head, list) {
- if (entry->svc.instance_id == instance_id)
- break;
- }
- spin_unlock_irqrestore(&data->registered_svc_list_lock, flags);
-
- return entry;
-}
-
-static int __tzcom_copy_cmd(struct tzcom_data_t *data,
- struct tzcom_next_cmd_op_req *req,
- struct tzcom_registered_svc_list *ptr_svc)
-{
- int found = 0;
- int ret = -EAGAIN;
- struct tzcom_callback_list *entry, *next;
- struct tzcom_callback *cb;
-
- PDEBUG("In here");
- mutex_lock(&data->callback_list_lock);
- PDEBUG("Before looping through cmd and svc lists.");
- list_for_each_entry_safe(entry, next, &data->callback_list_head, list) {
- cb = &entry->callback;
- if (req->svc_id == ptr_svc->svc.svc_id &&
- req->instance_id == ptr_svc->svc.instance_id &&
- cb->cmd_id >= ptr_svc->svc.cmd_id_low &&
- cb->cmd_id <= ptr_svc->svc.cmd_id_high) {
- PDEBUG("Found matching entry");
- found = 1;
- if (cb->sb_out_cb_data_len <= req->req_len) {
- PDEBUG("copying cmd buffer %p to req "
- "buffer %p, length: %u",
- (u8 *)cb + cb->sb_out_cb_data_off,
- req->req_buf, cb->sb_out_cb_data_len);
- req->cmd_id = cb->cmd_id;
- ret = copy_to_user(req->req_buf,
- (u8 *)cb + cb->sb_out_cb_data_off,
- cb->sb_out_cb_data_len);
- if (ret) {
- PERR("copy_to_user failed");
- break;
- }
- list_del(&entry->list);
- kfree(entry);
- ret = 0;
- } else {
- PERR("callback data buffer is "
- "larger than provided buffer."
- "Required: %u, Provided: %u",
- cb->sb_out_cb_data_len,
- req->req_len);
- ret = -ENOMEM;
- }
- break;
- }
- }
- PDEBUG("After looping through cmd and svc lists.");
- mutex_unlock(&data->callback_list_lock);
- return ret;
-}
-
-static int __tzcom_is_next_cmd(struct tzcom_data_t *data,
- struct tzcom_registered_svc_list *svc)
-{
- int ret;
- ret = (svc->next_cmd_flag != 0);
- return ret || data->abort;
-}
-
-static int tzcom_read_next_cmd(struct tzcom_data_t *data, void __user *argp)
-{
- int ret = 0;
- struct tzcom_next_cmd_op_req req;
- struct tzcom_registered_svc_list *this_svc;
-
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- PERR("copy_from_user failed");
- return ret;
- }
-
- if (req.instance_id > atomic_read(&svc_instance_ctr)) {
- PERR("Invalid instance_id for the request");
- return -EINVAL;
- }
-
- if (!req.req_buf || req.req_len == 0) {
- PERR("Invalid request buffer or buffer length");
- return -EINVAL;
- }
-
- PDEBUG("Before next_cmd loop");
- this_svc = __tzcom_find_svc(data, req.instance_id);
-
- while (1) {
- PDEBUG("Before wait_event next_cmd.");
- if (wait_event_interruptible(this_svc->next_cmd_wq,
- __tzcom_is_next_cmd(data, this_svc))) {
- PWARN("Interrupted: exiting wait_next_cmd loop");
- /* woken up for different reason */
- return -ERESTARTSYS;
- }
-
- if (data->abort) {
- PERR("Aborting driver");
- return -ENODEV;
- }
- PDEBUG("After wait_event next_cmd.");
- this_svc->next_cmd_flag = 0;
-
- ret = __tzcom_copy_cmd(data, &req, this_svc);
- if (ret == 0) {
- PDEBUG("Successfully found svc for cmd");
- data->handled_cmd_svc_instance_id = req.instance_id;
- break;
- } else if (ret == -ENOMEM) {
- PERR("Not enough memory");
- return ret;
- }
- }
- ret = copy_to_user(argp, &req, sizeof(req));
- if (ret) {
- PERR("copy_to_user failed");
- return ret;
- }
- PDEBUG("copy_to_user is done.");
- return ret;
-}
-
-static int tzcom_cont_cmd(struct tzcom_data_t *data, void __user *argp)
-{
- int ret = 0;
- struct tzcom_cont_cmd_op_req req;
- ret = copy_from_user(&req, argp, sizeof(req));
- if (ret) {
- PERR("copy_from_user failed");
- return ret;
- }
-
- /*
- * Only the svc instance that handled the cmd (in read_next_cmd method)
- * can call continue cmd
- */
- if (data->handled_cmd_svc_instance_id != req.instance_id) {
- PWARN("Only the service instance that handled the last "
- "callback can continue cmd. "
- "Expected: %u, Received: %u",
- data->handled_cmd_svc_instance_id,
- req.instance_id);
- return -EINVAL;
- }
-
- if (req.resp_buf) {
- mutex_lock(&sb_out_lock);
- memcpy(sb_out_virt, req.resp_buf, req.resp_len);
- mutex_unlock(&sb_out_lock);
- }
-
- data->cont_cmd_flag = 1;
- wake_up_interruptible(&data->cont_cmd_wq);
- return ret;
-}
-
-static int tzcom_abort(struct tzcom_data_t *data)
-{
- int ret = 0;
- unsigned long flags;
- struct tzcom_registered_svc_list *lsvc, *nsvc;
- if (data->abort) {
- PERR("Already aborting");
- return -EINVAL;
- }
-
- data->abort = 1;
-
- PDEBUG("Waking up cont_cmd_wq");
- wake_up_all(&data->cont_cmd_wq);
-
- spin_lock_irqsave(&data->registered_svc_list_lock, flags);
- PDEBUG("Before waking up service wait queues");
- list_for_each_entry_safe(lsvc, nsvc,
- &data->registered_svc_list_head, list) {
- wake_up_all(&lsvc->next_cmd_wq);
- }
- spin_unlock_irqrestore(&data->registered_svc_list_lock, flags);
-
- PDEBUG("ioctl_count before loop: %d", atomic_read(&data->ioctl_count));
- while (atomic_read(&data->ioctl_count) > 0) {
- if (wait_event_interruptible(data->abort_wq,
- atomic_read(&data->ioctl_count) <= 0)) {
- PERR("Interrupted from abort");
- ret = -ERESTARTSYS;
- break;
- }
- }
- return ret;
-}
-
-static long tzcom_ioctl(struct file *file, unsigned cmd,
- unsigned long arg)
-{
- int ret = 0;
- struct tzcom_data_t *tzcom_data = file->private_data;
- void __user *argp = (void __user *) arg;
- PDEBUG("enter tzcom_ioctl()");
- if (tzcom_data->abort) {
- PERR("Aborting tzcom driver");
- return -ENODEV;
- }
-
- switch (cmd) {
- case TZCOM_IOCTL_REGISTER_SERVICE_REQ: {
- PDEBUG("ioctl register_service_req()");
- atomic_inc(&tzcom_data->ioctl_count);
- ret = tzcom_register_service(tzcom_data, argp);
- atomic_dec(&tzcom_data->ioctl_count);
- wake_up_interruptible(&tzcom_data->abort_wq);
- if (ret)
- PERR("failed tzcom_register_service: %d", ret);
- break;
- }
- case TZCOM_IOCTL_UNREGISTER_SERVICE_REQ: {
- PDEBUG("ioctl unregister_service_req()");
- atomic_inc(&tzcom_data->ioctl_count);
- ret = tzcom_unregister_service(tzcom_data, argp);
- atomic_dec(&tzcom_data->ioctl_count);
- wake_up_interruptible(&tzcom_data->abort_wq);
- if (ret)
- PERR("failed tzcom_unregister_service: %d", ret);
- break;
- }
- case TZCOM_IOCTL_SEND_CMD_REQ: {
- PDEBUG("ioctl send_cmd_req()");
- /* Only one client allowed here at a time */
- mutex_lock(&send_cmd_lock);
- atomic_inc(&tzcom_data->ioctl_count);
- ret = tzcom_send_cmd(tzcom_data, argp);
- atomic_dec(&tzcom_data->ioctl_count);
- wake_up_interruptible(&tzcom_data->abort_wq);
- mutex_unlock(&send_cmd_lock);
- if (ret)
- PERR("failed tzcom_send_cmd: %d", ret);
- break;
- }
- case TZCOM_IOCTL_SEND_CMD_FD_REQ: {
- PDEBUG("ioctl send_cmd_req()");
- /* Only one client allowed here at a time */
- mutex_lock(&send_cmd_lock);
- atomic_inc(&tzcom_data->ioctl_count);
- ret = tzcom_send_cmd_with_fd(tzcom_data, argp);
- atomic_dec(&tzcom_data->ioctl_count);
- wake_up_interruptible(&tzcom_data->abort_wq);
- mutex_unlock(&send_cmd_lock);
- if (ret)
- PERR("failed tzcom_send_cmd: %d", ret);
- break;
- }
- case TZCOM_IOCTL_READ_NEXT_CMD_REQ: {
- PDEBUG("ioctl read_next_cmd_req()");
- atomic_inc(&tzcom_data->ioctl_count);
- ret = tzcom_read_next_cmd(tzcom_data, argp);
- atomic_dec(&tzcom_data->ioctl_count);
- wake_up_interruptible(&tzcom_data->abort_wq);
- if (ret)
- PERR("failed tzcom_read_next: %d", ret);
- break;
- }
- case TZCOM_IOCTL_CONTINUE_CMD_REQ: {
- PDEBUG("ioctl continue_cmd_req()");
- atomic_inc(&tzcom_data->ioctl_count);
- ret = tzcom_cont_cmd(tzcom_data, argp);
- atomic_dec(&tzcom_data->ioctl_count);
- wake_up_interruptible(&tzcom_data->abort_wq);
- if (ret)
- PERR("failed tzcom_cont_cmd: %d", ret);
- break;
- }
- case TZCOM_IOCTL_ABORT_REQ: {
- PDEBUG("ioctl abort_req()");
- ret = tzcom_abort(tzcom_data);
- if (ret)
- PERR("failed tzcom_abort: %d", ret);
- break;
- }
- default:
- return -EINVAL;
- }
- return ret;
-}
-
-static int tzcom_open(struct inode *inode, struct file *file)
-{
- int ret;
- long pil_error;
- struct tz_pr_init_sb_req_s sb_out_init_req;
- struct tz_pr_init_sb_rsp_s sb_out_init_rsp;
- void *rsp_addr_virt;
- struct tzcom_command cmd;
- struct tzcom_response resp;
- struct tzcom_data_t *tzcom_data;
-
- PDEBUG("In here");
-
- ret = tzcom_enable_bus_scaling();
-
- if (pil == NULL) {
- pil = pil_get("tzapps");
- if (IS_ERR(pil)) {
- PERR("Playready PIL image load failed");
- pil_error = PTR_ERR(pil);
- pil = NULL;
- return pil_error;
- }
- PDEBUG("tzapps image loaded successfully");
- }
-
- sb_out_init_req.pr_cmd = TZ_SCHED_CMD_ID_INIT_SB_OUT;
- sb_out_init_req.sb_len = sb_out_length;
- sb_out_init_req.sb_ptr = tzcom_virt_to_phys(sb_out_virt);
- PDEBUG("sb_out_init_req { pr_cmd: %d, sb_len: %u, "
- "sb_ptr (phys): 0x%x }",
- sb_out_init_req.pr_cmd,
- sb_out_init_req.sb_len,
- sb_out_init_req.sb_ptr);
-
- mutex_lock(&sb_in_lock);
- PDEBUG("Before memcpy on sb_in");
- memcpy(sb_in_virt, &sb_out_init_req, sizeof(sb_out_init_req));
- PDEBUG("After memcpy on sb_in");
-
- /* It will always be a new cmd from this method */
- cmd.cmd_type = TZ_SCHED_CMD_NEW;
- cmd.sb_in_cmd_addr = (u8 *) tzcom_virt_to_phys(sb_in_virt);
- cmd.sb_in_cmd_len = sizeof(sb_out_init_req);
- PDEBUG("tzcom_command { cmd_type: %u, sb_in_cmd_addr: %p, "
- "sb_in_cmd_len: %u }",
- cmd.cmd_type, cmd.sb_in_cmd_addr, cmd.sb_in_cmd_len);
-
- resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
-
- PDEBUG("Before scm_call for sb_init");
- ret = tzcom_scm_call(&cmd, sizeof(cmd), &resp, sizeof(resp));
- if (ret) {
- PERR("tzcom_scm_call failed with err: %d", ret);
- return ret;
- }
- PDEBUG("After scm_call for sb_init");
-
- PDEBUG("tzcom_response after scm cmd_status: %u", resp.cmd_status);
- if (resp.cmd_status == TZ_SCHED_STATUS_COMPLETE) {
- resp.sb_in_rsp_addr = (u8 *)cmd.sb_in_cmd_addr +
- cmd.sb_in_cmd_len;
- resp.sb_in_rsp_len = sizeof(sb_out_init_rsp);
- PDEBUG("tzcom_response sb_in_rsp_addr: %p, sb_in_rsp_len: %u",
- resp.sb_in_rsp_addr, resp.sb_in_rsp_len);
- rsp_addr_virt = tzcom_phys_to_virt((unsigned long)
- resp.sb_in_rsp_addr);
- PDEBUG("Received response phys: %p, virt: %p",
- resp.sb_in_rsp_addr, rsp_addr_virt);
- memcpy(&sb_out_init_rsp, rsp_addr_virt, resp.sb_in_rsp_len);
- } else {
- PERR("Error with SB initialization");
- mutex_unlock(&sb_in_lock);
- return -EPERM;
- }
- mutex_unlock(&sb_in_lock);
-
- PDEBUG("sb_out_init_rsp { pr_cmd: %d, ret: %d }",
- sb_out_init_rsp.pr_cmd, sb_out_init_rsp.ret);
-
- if (sb_out_init_rsp.ret) {
- PERR("sb_out_init_req failed: %d", sb_out_init_rsp.ret);
- return -EPERM;
- }
-
- tzcom_data = kmalloc(sizeof(*tzcom_data), GFP_KERNEL);
- if (!tzcom_data) {
- PERR("kmalloc failed");
- return -ENOMEM;
- }
- file->private_data = tzcom_data;
-
- INIT_LIST_HEAD(&tzcom_data->callback_list_head);
- mutex_init(&tzcom_data->callback_list_lock);
-
- INIT_LIST_HEAD(&tzcom_data->registered_svc_list_head);
- spin_lock_init(&tzcom_data->registered_svc_list_lock);
-
- init_waitqueue_head(&tzcom_data->cont_cmd_wq);
- tzcom_data->cont_cmd_flag = 0;
- tzcom_data->handled_cmd_svc_instance_id = 0;
- tzcom_data->abort = 0;
- init_waitqueue_head(&tzcom_data->abort_wq);
- atomic_set(&tzcom_data->ioctl_count, 0);
- return 0;
-}
-
-static int tzcom_release(struct inode *inode, struct file *file)
-{
- struct tzcom_data_t *tzcom_data = file->private_data;
- struct tzcom_callback_list *lcb, *ncb;
- struct tzcom_registered_svc_list *lsvc, *nsvc;
- unsigned long flags;
- PDEBUG("In here");
-
- if (!tzcom_data->abort) {
- PDEBUG("Calling abort");
- tzcom_abort(tzcom_data);
- }
-
- PDEBUG("Before removing callback list");
- mutex_lock(&tzcom_data->callback_list_lock);
- list_for_each_entry_safe(lcb, ncb,
- &tzcom_data->callback_list_head, list) {
- list_del(&lcb->list);
- kfree(lcb);
- }
- mutex_unlock(&tzcom_data->callback_list_lock);
- PDEBUG("After removing callback list");
-
- PDEBUG("Before removing svc list");
- spin_lock_irqsave(&tzcom_data->registered_svc_list_lock, flags);
- list_for_each_entry_safe(lsvc, nsvc,
- &tzcom_data->registered_svc_list_head, list) {
- list_del(&lsvc->list);
- kfree(lsvc);
- }
- spin_unlock_irqrestore(&tzcom_data->registered_svc_list_lock, flags);
- PDEBUG("After removing svc list");
- if (pil != NULL) {
- pil_put(pil);
- pil = NULL;
- }
- PDEBUG("Freeing tzcom data");
- kfree(tzcom_data);
- tzcom_disable_bus_scaling();
- return 0;
-}
-
-static struct msm_bus_paths tzcom_bw_table[] = {
- {
- .vectors = (struct msm_bus_vectors[]){
- {
- .src = MSM_BUS_MASTER_SPS,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- },
- },
- .num_paths = 1,
- },
- {
- .vectors = (struct msm_bus_vectors[]){
- {
- .src = MSM_BUS_MASTER_SPS,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ib = (492 * 8) * 1000000UL,
- .ab = (492 * 8) * 100000UL,
- },
- },
- .num_paths = 1,
- },
-
-};
-
-static struct msm_bus_scale_pdata tzcom_bus_pdata = {
- .usecase = tzcom_bw_table,
- .num_usecases = ARRAY_SIZE(tzcom_bw_table),
- .name = "tzcom",
-};
-static const struct file_operations tzcom_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = tzcom_ioctl,
- .open = tzcom_open,
- .release = tzcom_release
-};
-
-static int __init tzcom_init(void)
-{
- int rc;
- struct device *class_dev;
-
- PDEBUG("Hello tzcom");
-
- rc = alloc_chrdev_region(&tzcom_device_no, 0, 1, TZCOM_DEV);
- if (rc < 0) {
- PERR("alloc_chrdev_region failed %d", rc);
- return rc;
- }
-
- driver_class = class_create(THIS_MODULE, TZCOM_DEV);
- if (IS_ERR(driver_class)) {
- rc = -ENOMEM;
- PERR("class_create failed %d", rc);
- goto unregister_chrdev_region;
- }
-
- class_dev = device_create(driver_class, NULL, tzcom_device_no, NULL,
- TZCOM_DEV);
- if (!class_dev) {
- PERR("class_device_create failed %d", rc);
- rc = -ENOMEM;
- goto class_destroy;
- }
-
- cdev_init(&tzcom_cdev, &tzcom_fops);
- tzcom_cdev.owner = THIS_MODULE;
-
- rc = cdev_add(&tzcom_cdev, MKDEV(MAJOR(tzcom_device_no), 0), 1);
- if (rc < 0) {
- PERR("cdev_add failed %d", rc);
- goto class_device_destroy;
- }
-
- sb_in_phys = pmem_kalloc(sb_in_length, PMEM_MEMTYPE_EBI1 |
- PMEM_ALIGNMENT_4K);
- if (IS_ERR((void *)sb_in_phys)) {
- PERR("could not allocte in kernel pmem buffers for sb_in");
- sb_in_phys = 0;
- rc = -ENOMEM;
- goto class_device_destroy;
- }
- PDEBUG("physical_addr for sb_in: 0x%x", sb_in_phys);
-
- sb_in_virt = (u8 *) ioremap((unsigned long)sb_in_phys,
- sb_in_length);
- if (!sb_in_virt) {
- PERR("Shared buffer IN allocation failed.");
- rc = -ENOMEM;
- goto class_device_destroy;
- }
- PDEBUG("sb_in virt address: %p, phys address: 0x%x",
- sb_in_virt, tzcom_virt_to_phys(sb_in_virt));
-
- sb_out_phys = pmem_kalloc(sb_out_length, PMEM_MEMTYPE_EBI1 |
- PMEM_ALIGNMENT_4K);
- if (IS_ERR((void *)sb_out_phys)) {
- PERR("could not allocte in kernel pmem buffers for sb_out");
- sb_out_phys = 0;
- rc = -ENOMEM;
- goto class_device_destroy;
- }
- PDEBUG("physical_addr for sb_out: 0x%x", sb_out_phys);
-
- sb_out_virt = (u8 *) ioremap((unsigned long)sb_out_phys,
- sb_out_length);
- if (!sb_out_virt) {
- PERR("Shared buffer OUT allocation failed.");
- rc = -ENOMEM;
- goto class_device_destroy;
- }
- PDEBUG("sb_out virt address: %p, phys address: 0x%x",
- sb_out_virt, tzcom_virt_to_phys(sb_out_virt));
- ion_clnt = msm_ion_client_create(0x03, "tzcom");
- /* Initialized in tzcom_open */
- pil = NULL;
-
- tzcom_perf_client = msm_bus_scale_register_client(
- &tzcom_bus_pdata);
- if (!tzcom_perf_client)
- pr_err("Unable to register bus client");
-
- tzcom_bus_clk = clk_get(class_dev, "bus_clk");
- if (IS_ERR(tzcom_bus_clk)) {
- tzcom_bus_clk = NULL;
- } else if (tzcom_bus_clk != NULL) {
- pr_debug("Enabled DFAB clock\n");
- clk_set_rate(tzcom_bus_clk, 64000000);
- }
- return 0;
-
-class_device_destroy:
- if (sb_in_virt)
- iounmap(sb_in_virt);
- if (sb_in_phys)
- pmem_kfree(sb_in_phys);
- if (sb_out_virt)
- iounmap(sb_out_virt);
- if (sb_out_phys)
- pmem_kfree(sb_out_phys);
- device_destroy(driver_class, tzcom_device_no);
-class_destroy:
- class_destroy(driver_class);
-unregister_chrdev_region:
- unregister_chrdev_region(tzcom_device_no, 1);
- return rc;
-}
-
-static void __exit tzcom_exit(void)
-{
- PDEBUG("Goodbye tzcom");
- if (sb_in_virt)
- iounmap(sb_in_virt);
- if (sb_in_phys)
- pmem_kfree(sb_in_phys);
- if (sb_out_virt)
- iounmap(sb_out_virt);
- if (sb_out_phys)
- pmem_kfree(sb_out_phys);
- if (pil != NULL) {
- pil_put(pil);
- pil = NULL;
- }
- clk_put(tzcom_bus_clk);
- device_destroy(driver_class, tzcom_device_no);
- class_destroy(driver_class);
- unregister_chrdev_region(tzcom_device_no, 1);
- ion_client_destroy(ion_clnt);
-}
-
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Sachin Shah <sachins@codeaurora.org>");
-MODULE_DESCRIPTION("Qualcomm TrustZone Communicator");
-MODULE_VERSION("1.00");
-
-module_init(tzcom_init);
-module_exit(tzcom_exit);
diff --git a/drivers/misc/tzcomi.h b/drivers/misc/tzcomi.h
deleted file mode 100644
index 33634cf..0000000
--- a/drivers/misc/tzcomi.h
+++ /dev/null
@@ -1,112 +0,0 @@
-/* Qualcomm TrustZone communicator driver
- *
- * Copyright (c) 2011, Code Aurora Forum. 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 __TZCOMI_H_
-#define __TZCOMI_H_
-
-#include <linux/types.h>
-
-enum tz_sched_cmd_id {
- TZ_SCHED_CMD_ID_INVALID = 0,
- TZ_SCHED_CMD_ID_INIT_SB_OUT, /**< Initialize the shared buffer */
- TZ_SCHED_CMD_ID_INIT_SB_LOG, /**< Initialize the logging shared buf */
- TZ_SCHED_CMD_ID_UNKNOWN = 0x7FFFFFFE,
- TZ_SCHED_CMD_ID_MAX = 0x7FFFFFFF
-};
-
-enum tz_sched_cmd_type {
- TZ_SCHED_CMD_INVALID = 0,
- TZ_SCHED_CMD_NEW, /** New TZ Scheduler Command */
- TZ_SCHED_CMD_PENDING, /** Pending cmd...sched will restore stack */
- TZ_SCHED_CMD_COMPLETE, /** TZ sched command is complete */
- TZ_SCHED_CMD_MAX = 0x7FFFFFFF
-};
-
-enum tz_sched_cmd_status {
- TZ_SCHED_STATUS_INCOMPLETE = 0,
- TZ_SCHED_STATUS_COMPLETE,
- TZ_SCHED_STATUS_MAX = 0x7FFFFFFF
-};
-
-/** Command structure for initializing shared buffers (SB_OUT
- and SB_LOG)
-*/
-__packed struct tz_pr_init_sb_req_s {
- /** First 4 bytes should always be command id
- * from enum tz_sched_cmd_id */
- uint32_t pr_cmd;
- /** Pointer to the physical location of sb_out buffer */
- uint32_t sb_ptr;
- /** length of shared buffer */
- uint32_t sb_len;
-};
-
-
-__packed struct tz_pr_init_sb_rsp_s {
- /** First 4 bytes should always be command id
- * from enum tz_sched_cmd_id */
- uint32_t pr_cmd;
- /** Return code, 0 for success, Approp error code otherwise */
- int32_t ret;
-};
-
-
-/**
- * struct tzcom_command - tzcom command buffer
- * @cmd_type: value from enum tz_sched_cmd_type
- * @sb_in_cmd_addr: points to physical location of command
- * buffer
- * @sb_in_cmd_len: length of command buffer
- */
-__packed struct tzcom_command {
- uint32_t cmd_type;
- uint8_t *sb_in_cmd_addr;
- uint32_t sb_in_cmd_len;
-};
-
-/**
- * struct tzcom_response - tzcom response buffer
- * @cmd_status: value from enum tz_sched_cmd_status
- * @sb_in_rsp_addr: points to physical location of response
- * buffer
- * @sb_in_rsp_len: length of command response
- */
-__packed struct tzcom_response {
- uint32_t cmd_status;
- uint8_t *sb_in_rsp_addr;
- uint32_t sb_in_rsp_len;
-};
-
-/**
- * struct tzcom_callback - tzcom callback buffer
- * @cmd_id: command to run in registered service
- * @sb_out_rsp_addr: points to physical location of response
- * buffer
- * @sb_in_cmd_len: length of command response
- *
- * A callback buffer would be laid out in sb_out as follows:
- *
- * --------------------- <--- struct tzcom_callback
- * | callback header |
- * --------------------- <--- tzcom_callback.sb_out_cb_data_off
- * | callback data |
- * ---------------------
- */
-__packed struct tzcom_callback {
- uint32_t cmd_id;
- uint32_t sb_out_cb_data_len;
- uint32_t sb_out_cb_data_off;
-};
-
-#endif /* __TZCOMI_H_ */
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 990faeb..1331aa4 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -606,7 +606,6 @@
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
- unsigned int timeout_us;
struct scatterlist sg;
@@ -626,23 +625,12 @@
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- data.timeout_ns = card->csd.tacc_ns * 100;
- data.timeout_clks = card->csd.tacc_clks * 100;
-
- timeout_us = data.timeout_ns / 1000;
- timeout_us += data.timeout_clks * 1000 /
- (card->host->ios.clock / 1000);
-
- if (timeout_us > 100000) {
- data.timeout_ns = 100000000;
- data.timeout_clks = 0;
- }
-
data.blksz = 4;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
+ mmc_set_data_timeout(&data, card);
mrq.cmd = &cmd;
mrq.data = &data;
@@ -918,9 +906,7 @@
goto retry;
if (!err)
mmc_blk_reset_success(md, type);
- spin_lock_irq(&md->lock);
- __blk_end_request(req, err, blk_rq_bytes(req));
- spin_unlock_irq(&md->lock);
+ blk_end_request(req, err, blk_rq_bytes(req));
return err ? 0 : 1;
}
@@ -989,9 +975,7 @@
if (!err)
mmc_blk_reset_success(md, type);
out:
- spin_lock_irq(&md->lock);
- __blk_end_request(req, err, blk_rq_bytes(req));
- spin_unlock_irq(&md->lock);
+ blk_end_request(req, err, blk_rq_bytes(req));
return err ? 0 : 1;
}
@@ -1030,9 +1014,7 @@
__func__);
out:
- spin_lock_irq(&md->lock);
- __blk_end_request(req, err, blk_rq_bytes(req));
- spin_unlock_irq(&md->lock);
+ blk_end_request(req, err, blk_rq_bytes(req));
return err ? 0 : 1;
}
@@ -1047,9 +1029,7 @@
if (ret)
ret = -EIO;
- spin_lock_irq(&md->lock);
- __blk_end_request_all(req, ret);
- spin_unlock_irq(&md->lock);
+ blk_end_request_all(req, ret);
return ret ? 0 : 1;
}
@@ -1402,6 +1382,7 @@
if (mq->num_of_potential_packed_wr_reqs >
mq->num_wr_reqs_to_start_packing)
mq->wr_packing_enabled = true;
+ mq->num_of_potential_packed_wr_reqs = 0;
return;
}
@@ -1672,15 +1653,11 @@
blocks = mmc_sd_num_wr_blocks(card);
if (blocks != (u32)-1) {
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, blocks << 9);
- spin_unlock_irq(&md->lock);
+ ret = blk_end_request(req, 0, blocks << 9);
}
} else {
if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
- spin_unlock_irq(&md->lock);
+ ret = blk_end_request(req, 0, brq->data.bytes_xfered);
}
}
return ret;
@@ -1689,7 +1666,6 @@
static int mmc_blk_end_packed_req(struct mmc_queue *mq,
struct mmc_queue_req *mq_rq)
{
- struct mmc_blk_data *md = mq->data;
struct request *prq;
int idx = mq_rq->packed_fail_idx, i = 0;
int ret = 0;
@@ -1709,9 +1685,7 @@
return ret;
}
list_del_init(&prq->queuelist);
- spin_lock_irq(&md->lock);
- __blk_end_request(prq, 0, blk_rq_bytes(prq));
- spin_unlock_irq(&md->lock);
+ blk_end_request(prq, 0, blk_rq_bytes(prq));
i++;
}
@@ -1777,10 +1751,8 @@
ret = mmc_blk_end_packed_req(mq, mq_rq);
break;
} else {
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0,
+ ret = blk_end_request(req, 0,
brq->data.bytes_xfered);
- spin_unlock_irq(&md->lock);
}
/*
@@ -1833,10 +1805,8 @@
* time, so we only reach here after trying to
* read a single sector.
*/
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, -EIO,
+ ret = blk_end_request(req, -EIO,
brq->data.blksz);
- spin_unlock_irq(&md->lock);
if (!ret)
goto start_new_req;
break;
@@ -1866,20 +1836,16 @@
cmd_abort:
if (mq_rq->packed_cmd == MMC_PACKED_NONE) {
- spin_lock_irq(&md->lock);
if (mmc_card_removed(card))
req->cmd_flags |= REQ_QUIET;
while (ret)
- ret = __blk_end_request(req, -EIO,
+ ret = blk_end_request(req, -EIO,
blk_rq_cur_bytes(req));
- spin_unlock_irq(&md->lock);
} else {
while (!list_empty(&mq_rq->packed_list)) {
prq = list_entry_rq(mq_rq->packed_list.next);
list_del_init(&prq->queuelist);
- spin_lock_irq(&md->lock);
- __blk_end_request(prq, -EIO, blk_rq_bytes(prq));
- spin_unlock_irq(&md->lock);
+ blk_end_request(prq, -EIO, blk_rq_bytes(prq));
}
mmc_blk_clear_packed(mq_rq);
}
@@ -1932,9 +1898,7 @@
ret = mmc_blk_part_switch(card, md);
if (ret) {
if (req) {
- spin_lock_irq(&md->lock);
- __blk_end_request_all(req, -EIO);
- spin_unlock_irq(&md->lock);
+ blk_end_request_all(req, -EIO);
}
ret = 0;
goto out;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 3438bc91..b5ffe94 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -235,6 +235,36 @@
return err;
}
+static void mmc_select_card_type(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
+ unsigned int caps = host->caps, caps2 = host->caps2;
+ unsigned int hs_max_dtr = 0;
+
+ if (card_type & EXT_CSD_CARD_TYPE_26)
+ hs_max_dtr = MMC_HIGH_26_MAX_DTR;
+
+ if (caps & MMC_CAP_MMC_HIGHSPEED &&
+ card_type & EXT_CSD_CARD_TYPE_52)
+ hs_max_dtr = MMC_HIGH_52_MAX_DTR;
+
+ if ((caps & MMC_CAP_1_8V_DDR &&
+ card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
+ (caps & MMC_CAP_1_2V_DDR &&
+ card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
+ hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+
+ if ((caps2 & MMC_CAP2_HS200_1_8V_SDR &&
+ card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
+ (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
+ card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
+ hs_max_dtr = MMC_HS200_MAX_DTR;
+
+ card->ext_csd.hs_max_dtr = hs_max_dtr;
+ card->ext_csd.card_type = card_type;
+}
+
/*
* Decode extended CSD.
*/
@@ -284,56 +314,9 @@
if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
mmc_card_set_blockaddr(card);
}
+
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
- switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
- case EXT_CSD_CARD_TYPE_SDR_ALL:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
- break;
- case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
- break;
- case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
- break;
- case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
- EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
- break;
- case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
- EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
- break;
- case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
- EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
- break;
- case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 52000000;
- break;
- case EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 26000000;
- break;
- default:
- /* MMC v4 spec says this cannot happen */
- pr_warning("%s: card is mmc v4 but doesn't "
- "support any high-speed modes.\n",
- mmc_hostname(card->host));
- }
+ mmc_select_card_type(card);
card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
card->ext_csd.raw_erase_timeout_mult =
@@ -1472,7 +1455,15 @@
err = mmc_poweroff_notify(host, MMC_PW_OFF_NOTIFY_SHORT);
} else {
if (mmc_card_can_sleep(host))
- err = mmc_card_sleep(host);
+ /*
+ * If sleep command has error it doesn't mean host
+ * cannot suspend, but a deeper low power state
+ * transition for the card has failed. Ignore
+ * sleep errors so that the suspend is not aborted.
+ * In error case, mmc_resume() takes care of
+ * complete intialization of the card.
+ */
+ mmc_card_sleep(host);
else if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
}
@@ -1529,7 +1520,7 @@
if (card && card->ext_csd.rev >= 3) {
err = mmc_card_sleepawake(host, 1);
if (err < 0)
- pr_debug("%s: Error %d while putting card into sleep",
+ pr_warn("%s: Error %d while putting card into sleep",
mmc_hostname(host), err);
}
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index ac8b164..edf4400 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -376,8 +376,8 @@
{
host->curr.data = NULL;
host->curr.got_dataend = 0;
- host->curr.wait_for_auto_prog_done = 0;
- host->curr.got_auto_prog_done = 0;
+ host->curr.wait_for_auto_prog_done = false;
+ host->curr.got_auto_prog_done = false;
writel_relaxed(readl_relaxed(host->base + MMCIDATACTRL) &
(~(MCI_DPSM_ENABLE)), host->base + MMCIDATACTRL);
msmsdcc_sync_reg_wr(host); /* Allow the DPSM to be reset */
@@ -1118,7 +1118,7 @@
host->curr.xfer_remain = host->curr.xfer_size;
host->curr.data_xfered = 0;
host->curr.got_dataend = 0;
- host->curr.got_auto_prog_done = 0;
+ host->curr.got_auto_prog_done = false;
datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
@@ -1173,6 +1173,9 @@
clks = (unsigned long long)data->timeout_ns * host->clk_rate;
do_div(clks, 1000000000UL);
timeout = data->timeout_clks + (unsigned int)clks*2 ;
+ WARN(!timeout,
+ "%s: data timeout is zero. timeout_ns=0x%x, timeout_clks=0x%x\n",
+ mmc_hostname(host->mmc), data->timeout_ns, data->timeout_clks);
if (host->is_dma_mode && (datactrl & MCI_DPSM_DMAENABLE)) {
/* Use ADM (Application Data Mover) HW for Data transfer */
@@ -1644,7 +1647,7 @@
host->curr.cmd = cmd;
} else {
host->prog_enable = 0;
- host->curr.wait_for_auto_prog_done = 0;
+ host->curr.wait_for_auto_prog_done = false;
if (host->dummy_52_needed)
host->dummy_52_needed = 0;
if (cmd->data && cmd->error)
@@ -1808,7 +1811,7 @@
/* Check for prog done */
if (host->curr.wait_for_auto_prog_done &&
(status & MCI_PROGDONE))
- host->curr.got_auto_prog_done = 1;
+ host->curr.got_auto_prog_done = true;
/* Check for data done */
if (!host->curr.got_dataend && (status & MCI_DATAEND))
@@ -2026,35 +2029,26 @@
msecs_to_jiffies(host->curr.req_tout_ms)));
host->curr.mrq = mrq;
+ if (mrq->sbc) {
+ mrq->sbc->mrq = mrq;
+ mrq->sbc->data = mrq->data;
+ }
+
if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
- if (mrq->cmd->opcode == SD_IO_RW_EXTENDED ||
- mrq->cmd->opcode == 54) {
- if (!host->sdcc_version)
+ if (host->sdcc_version) {
+ if (!mrq->stop)
+ host->curr.wait_for_auto_prog_done = true;
+ } else {
+ if ((mrq->cmd->opcode == SD_IO_RW_EXTENDED) ||
+ (mrq->cmd->opcode == 54))
host->dummy_52_needed = 1;
- else
- /*
- * SDCCv4 supports AUTO_PROG_DONE bit for SDIO
- * write operations using CMD53 and CMD54.
- * Setting this bit with CMD53 would
- * automatically triggers PROG_DONE interrupt
- * without the need of sending dummy CMD52.
- */
- host->curr.wait_for_auto_prog_done = 1;
- } else if (mrq->cmd->opcode == MMC_WRITE_BLOCK &&
- host->sdcc_version) {
- host->curr.wait_for_auto_prog_done = 1;
}
+
if ((mrq->cmd->opcode == MMC_WRITE_BLOCK) ||
(mrq->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK))
host->curr.use_wr_data_pend = true;
}
- if (mrq->data && mrq->sbc) {
- mrq->sbc->mrq = mrq;
- mrq->sbc->data = mrq->data;
- if (mrq->data->flags & MMC_DATA_WRITE)
- host->curr.wait_for_auto_prog_done = 1;
- }
msmsdcc_request_start(host, mrq);
spin_unlock_irqrestore(&host->lock, flags);
@@ -2136,7 +2130,7 @@
{
int rc = 0;
struct msm_mmc_slot_reg_data *curr_slot;
- struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
+ struct msm_mmc_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
struct device *dev = mmc_dev(host->mmc);
curr_slot = host->plat->vreg_data;
@@ -2144,8 +2138,7 @@
goto out;
curr_vdd_reg = curr_slot->vdd_data;
- curr_vccq_reg = curr_slot->vccq_data;
- curr_vddp_reg = curr_slot->vddp_data;
+ curr_vdd_io_reg = curr_slot->vdd_io_data;
if (is_init) {
/*
@@ -2157,16 +2150,11 @@
if (rc)
goto out;
}
- if (curr_vccq_reg) {
- rc = msmsdcc_vreg_init_reg(curr_vccq_reg, dev);
+ if (curr_vdd_io_reg) {
+ rc = msmsdcc_vreg_init_reg(curr_vdd_io_reg, dev);
if (rc)
goto vdd_reg_deinit;
}
- if (curr_vddp_reg) {
- rc = msmsdcc_vreg_init_reg(curr_vddp_reg, dev);
- if (rc)
- goto vccq_reg_deinit;
- }
rc = msmsdcc_vreg_reset(host);
if (rc)
pr_err("msmsdcc.%d vreg reset failed (%d)\n",
@@ -2174,14 +2162,11 @@
goto out;
} else {
/* Deregister all regulators from regulator framework */
- goto vddp_reg_deinit;
+ goto vdd_io_reg_deinit;
}
-vddp_reg_deinit:
- if (curr_vddp_reg)
- msmsdcc_vreg_deinit_reg(curr_vddp_reg);
-vccq_reg_deinit:
- if (curr_vccq_reg)
- msmsdcc_vreg_deinit_reg(curr_vccq_reg);
+vdd_io_reg_deinit:
+ if (curr_vdd_io_reg)
+ msmsdcc_vreg_deinit_reg(curr_vdd_io_reg);
vdd_reg_deinit:
if (curr_vdd_reg)
msmsdcc_vreg_deinit_reg(curr_vdd_reg);
@@ -2254,16 +2239,14 @@
{
int rc = 0, i;
struct msm_mmc_slot_reg_data *curr_slot;
- struct msm_mmc_reg_data *curr_vdd_reg, *curr_vccq_reg, *curr_vddp_reg;
- struct msm_mmc_reg_data *vreg_table[3];
+ struct msm_mmc_reg_data *vreg_table[2];
curr_slot = host->plat->vreg_data;
if (!curr_slot)
goto out;
- curr_vdd_reg = vreg_table[0] = curr_slot->vdd_data;
- curr_vccq_reg = vreg_table[1] = curr_slot->vccq_data;
- curr_vddp_reg = vreg_table[2] = curr_slot->vddp_data;
+ vreg_table[0] = curr_slot->vdd_data;
+ vreg_table[1] = curr_slot->vdd_io_data;
for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
if (vreg_table[i]) {
@@ -2294,70 +2277,53 @@
return rc;
}
-static int msmsdcc_set_vddp_level(struct msmsdcc_host *host, int level)
+enum vdd_io_level {
+ /* set vdd_io_data->low_vol_level */
+ VDD_IO_LOW,
+ /* set vdd_io_data->high_vol_level */
+ VDD_IO_HIGH,
+ /*
+ * set whatever there in voltage_level (third argument) of
+ * msmsdcc_set_vdd_io_vol() function.
+ */
+ VDD_IO_SET_LEVEL,
+};
+
+static int msmsdcc_set_vdd_io_vol(struct msmsdcc_host *host,
+ enum vdd_io_level level,
+ unsigned int voltage_level)
{
int rc = 0;
+ int set_level;
if (host->plat->vreg_data) {
- struct msm_mmc_reg_data *vddp_reg =
- host->plat->vreg_data->vddp_data;
+ struct msm_mmc_reg_data *vdd_io_reg =
+ host->plat->vreg_data->vdd_io_data;
- if (vddp_reg && vddp_reg->is_enabled)
- rc = msmsdcc_vreg_set_voltage(vddp_reg, level, level);
+ if (vdd_io_reg && vdd_io_reg->is_enabled) {
+ switch (level) {
+ case VDD_IO_LOW:
+ set_level = vdd_io_reg->low_vol_level;
+ break;
+ case VDD_IO_HIGH:
+ set_level = vdd_io_reg->high_vol_level;
+ break;
+ case VDD_IO_SET_LEVEL:
+ set_level = voltage_level;
+ break;
+ default:
+ pr_err("%s: %s: invalid argument level = %d",
+ mmc_hostname(host->mmc), __func__,
+ level);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = msmsdcc_vreg_set_voltage(vdd_io_reg,
+ set_level, set_level);
+ }
}
- return rc;
-}
-
-static inline int msmsdcc_set_vddp_low_vol(struct msmsdcc_host *host)
-{
- struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
- int rc = 0;
-
- if (curr_slot && curr_slot->vddp_data) {
- rc = msmsdcc_set_vddp_level(host,
- curr_slot->vddp_data->low_vol_level);
-
- if (rc)
- pr_err("%s: %s: failed to change vddp level to %d",
- mmc_hostname(host->mmc), __func__,
- curr_slot->vddp_data->low_vol_level);
- }
-
- return rc;
-}
-
-static inline int msmsdcc_set_vddp_high_vol(struct msmsdcc_host *host)
-{
- struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
- int rc = 0;
-
- if (curr_slot && curr_slot->vddp_data) {
- rc = msmsdcc_set_vddp_level(host,
- curr_slot->vddp_data->high_vol_level);
-
- if (rc)
- pr_err("%s: %s: failed to change vddp level to %d",
- mmc_hostname(host->mmc), __func__,
- curr_slot->vddp_data->high_vol_level);
- }
-
- return rc;
-}
-
-static inline int msmsdcc_set_vccq_vol(struct msmsdcc_host *host, int level)
-{
- struct msm_mmc_slot_reg_data *curr_slot = host->plat->vreg_data;
- int rc = 0;
-
- if (curr_slot && curr_slot->vccq_data) {
- rc = msmsdcc_vreg_set_voltage(curr_slot->vccq_data,
- level, level);
- if (rc)
- pr_err("%s: %s: failed to change vccq level to %d",
- mmc_hostname(host->mmc), __func__, level);
- }
-
+out:
return rc;
}
@@ -2375,8 +2341,8 @@
static inline void msmsdcc_setup_clocks(struct msmsdcc_host *host, bool enable)
{
if (enable) {
- if (!IS_ERR_OR_NULL(host->dfab_pclk))
- clk_prepare_enable(host->dfab_pclk);
+ if (!IS_ERR_OR_NULL(host->bus_clk))
+ clk_prepare_enable(host->bus_clk);
if (!IS_ERR(host->pclk))
clk_prepare_enable(host->pclk);
clk_prepare_enable(host->clk);
@@ -2388,8 +2354,8 @@
clk_disable_unprepare(host->clk);
if (!IS_ERR(host->pclk))
clk_disable_unprepare(host->pclk);
- if (!IS_ERR_OR_NULL(host->dfab_pclk))
- clk_disable_unprepare(host->dfab_pclk);
+ if (!IS_ERR_OR_NULL(host->bus_clk))
+ clk_disable_unprepare(host->bus_clk);
}
}
@@ -2582,11 +2548,11 @@
pwr = MCI_PWR_OFF;
msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_DISABLE);
/*
- * As VDD pad rail is always on, set low voltage for VDD
- * pad rail when slot is unused (when card is not present
- * or during system suspend).
+ * If VDD IO rail is always on, set low voltage for VDD
+ * IO rail when slot is not in use (like when card is not
+ * present or during system suspend).
*/
- msmsdcc_set_vddp_low_vol(host);
+ msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
msmsdcc_setup_pins(host, false);
break;
case MMC_POWER_UP:
@@ -2594,7 +2560,7 @@
pwr = MCI_PWR_UP;
msmsdcc_cfg_mpm_sdiowakeup(host, SDC_DAT1_ENABLE);
- msmsdcc_set_vddp_high_vol(host);
+ msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
msmsdcc_setup_pins(host, true);
break;
case MMC_POWER_ON:
@@ -2911,13 +2877,14 @@
DBG(host, "ios->clock = %u\n", ios->clock);
spin_lock_irqsave(&host->lock, flags);
if (!host->sdcc_irq_disabled) {
- spin_unlock_irqrestore(&host->lock, flags);
- disable_irq(host->core_irqres->start);
- spin_lock_irqsave(&host->lock, flags);
+ disable_irq_nosync(host->core_irqres->start);
host->sdcc_irq_disabled = 1;
}
spin_unlock_irqrestore(&host->lock, flags);
+ /* Make sure sdcc core irq is synchronized */
+ synchronize_irq(host->core_irqres->start);
+
pwr = msmsdcc_setup_pwr(host, ios);
spin_lock_irqsave(&host->lock, flags);
@@ -3095,7 +3062,7 @@
msleep(300);
status = gpio_get_value_cansleep(
host->plat->wpswitch_gpio);
- status ^= !host->plat->wpswitch_polarity;
+ status ^= !host->plat->is_wpswitch_active_low;
}
gpio_free(host->plat->wpswitch_gpio);
}
@@ -3298,8 +3265,8 @@
}
#endif
-static int msmsdcc_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
+static int msmsdcc_switch_io_voltage(struct mmc_host *mmc,
+ struct mmc_ios *ios)
{
struct msmsdcc_host *host = mmc_priv(mmc);
unsigned long flags;
@@ -3309,31 +3276,32 @@
host->io_pad_pwr_switch = 0;
spin_unlock_irqrestore(&host->lock, flags);
- /*
- * For eMMC cards, VccQ voltage range must be changed
- * only if it operates in HS200 SDR 1.2V mode or in
- * DDR 1.2V mode.
- */
- if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_120) {
- rc = msmsdcc_set_vccq_vol(host, 1200000);
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_330:
+ /* Set VDD IO to high voltage range (2.7v - 3.6v) */
+ rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_HIGH, 0);
goto out;
- }
-
- if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
- /* Change voltage level of VDDPX to high voltage */
- rc = msmsdcc_set_vddp_high_vol(host);
+ case MMC_SIGNAL_VOLTAGE_180:
+ break;
+ case MMC_SIGNAL_VOLTAGE_120:
+ /*
+ * For eMMC cards, VDD_IO voltage range must be changed
+ * only if it operates in HS200 SDR 1.2V mode or in
+ * DDR 1.2V mode.
+ */
+ rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_SET_LEVEL, 1200000);
goto out;
- } else if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) {
+ default:
/* invalid selection. don't do anything */
rc = -EINVAL;
goto out;
}
- spin_lock_irqsave(&host->lock, flags);
/*
* If we are here means voltage switch from high voltage to
* low voltage is required
*/
+ spin_lock_irqsave(&host->lock, flags);
/*
* Poll on MCIDATIN_3_0 and MCICMDIN bits of MCI_TEST_INPUT
@@ -3353,10 +3321,10 @@
spin_unlock_irqrestore(&host->lock, flags);
/*
- * Switch VDDPX from high voltage to low voltage
- * to change the VDD of the SD IO pads.
+ * Switch VDD Io from high voltage range (2.7v - 3.6v) to
+ * low voltage range (1.7v - 1.95v).
*/
- rc = msmsdcc_set_vddp_low_vol(host);
+ rc = msmsdcc_set_vdd_io_vol(host, VDD_IO_LOW, 0);
if (rc)
goto out;
@@ -3855,7 +3823,7 @@
.set_ios = msmsdcc_set_ios,
.get_ro = msmsdcc_get_ro,
.enable_sdio_irq = msmsdcc_enable_sdio_irq,
- .start_signal_voltage_switch = msmsdcc_start_signal_voltage_switch,
+ .start_signal_voltage_switch = msmsdcc_switch_io_voltage,
.execute_tuning = msmsdcc_execute_tuning
};
@@ -4390,7 +4358,7 @@
}
static ssize_t
-set_polling(struct device *dev, struct device_attribute *attr,
+store_polling(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4414,9 +4382,6 @@
return count;
}
-static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR,
- show_polling, set_polling);
-
static ssize_t
show_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -4429,7 +4394,7 @@
}
static ssize_t
-set_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+store_sdcc_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -4446,20 +4411,6 @@
return count;
}
-static DEVICE_ATTR(max_bus_bw, S_IRUGO | S_IWUSR,
- show_sdcc_to_mem_max_bus_bw, set_sdcc_to_mem_max_bus_bw);
-
-static struct attribute *dev_attrs[] = {
- &dev_attr_max_bus_bw.attr,
- /* if polling is enabled, this will be filled with dev_attr_polling */
- NULL,
- NULL,
-};
-
-static struct attribute_group dev_attr_grp = {
- .attrs = dev_attrs,
-};
-
#ifdef CONFIG_HAS_EARLYSUSPEND
static void msmsdcc_early_suspend(struct early_suspend *h)
{
@@ -4595,7 +4546,7 @@
}
} else {
host->prog_enable = 0;
- host->curr.wait_for_auto_prog_done = 0;
+ host->curr.wait_for_auto_prog_done = false;
msmsdcc_reset_and_restore(host);
msmsdcc_request_end(host, mrq);
}
@@ -4878,21 +4829,17 @@
}
/*
- * Setup SDCC clock if derived from Dayatona
- * fabric core clock.
+ * Setup SDCC bus voter clock.
*/
- if (plat->pclk_src_dfab) {
- host->dfab_pclk = clk_get(&pdev->dev, "bus_clk");
- if (!IS_ERR(host->dfab_pclk)) {
- /* Set the clock rate to 64MHz for max. performance */
- ret = clk_set_rate(host->dfab_pclk, 64000000);
- if (ret)
- goto dfab_pclk_put;
- ret = clk_prepare_enable(host->dfab_pclk);
- if (ret)
- goto dfab_pclk_put;
- } else
- goto dma_free;
+ host->bus_clk = clk_get(&pdev->dev, "bus_clk");
+ if (!IS_ERR_OR_NULL(host->bus_clk)) {
+ /* Vote for max. clk rate for max. performance */
+ ret = clk_set_rate(host->bus_clk, INT_MAX);
+ if (ret)
+ goto bus_clk_put;
+ ret = clk_prepare_enable(host->bus_clk);
+ if (ret)
+ goto bus_clk_put;
}
/*
@@ -4993,9 +4940,10 @@
mmc->f_min = msmsdcc_get_min_sup_clk_rate(host);
mmc->f_max = msmsdcc_get_max_sup_clk_rate(host);
mmc->ocr_avail = plat->ocr_mask;
+ mmc->clkgate_delay = MSM_MMC_CLK_GATE_DELAY;
+
mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
mmc->caps |= plat->mmc_bus_width;
-
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
@@ -5216,14 +5164,30 @@
#if defined(CONFIG_DEBUG_FS)
msmsdcc_dbg_createhost(host);
#endif
- if (!plat->status_irq)
- dev_attrs[1] = &dev_attr_polling.attr;
- ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);
+ host->max_bus_bw.show = show_sdcc_to_mem_max_bus_bw;
+ host->max_bus_bw.store = store_sdcc_to_mem_max_bus_bw;
+ sysfs_attr_init(&host->max_bus_bw.attr);
+ host->max_bus_bw.attr.name = "max_bus_bw";
+ host->max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(&pdev->dev, &host->max_bus_bw);
if (ret)
goto platform_irq_free;
+
+ if (!plat->status_irq) {
+ host->polling.show = show_polling;
+ host->polling.store = store_polling;
+ sysfs_attr_init(&host->polling.attr);
+ host->polling.attr.name = "polling";
+ host->polling.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(&pdev->dev, &host->polling);
+ if (ret)
+ goto remove_max_bus_bw_file;
+ }
return 0;
+ remove_max_bus_bw_file:
+ device_remove_file(&pdev->dev, &host->max_bus_bw);
platform_irq_free:
del_timer_sync(&host->req_tout_timer);
pm_runtime_disable(&(pdev)->dev);
@@ -5263,12 +5227,11 @@
pclk_put:
if (!IS_ERR(host->pclk))
clk_put(host->pclk);
- if (!IS_ERR_OR_NULL(host->dfab_pclk))
- clk_disable_unprepare(host->dfab_pclk);
- dfab_pclk_put:
- if (!IS_ERR_OR_NULL(host->dfab_pclk))
- clk_put(host->dfab_pclk);
- dma_free:
+ if (!IS_ERR_OR_NULL(host->bus_clk))
+ clk_disable_unprepare(host->bus_clk);
+ bus_clk_put:
+ if (!IS_ERR_OR_NULL(host->bus_clk))
+ clk_put(host->bus_clk);
if (host->is_dma_mode) {
if (host->dmares)
dma_free_coherent(NULL,
@@ -5300,8 +5263,9 @@
DBG(host, "Removing SDCC device = %d\n", pdev->id);
plat = host->plat;
+ device_remove_file(&pdev->dev, &host->max_bus_bw);
if (!plat->status_irq)
- sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
+ device_remove_file(&pdev->dev, &host->polling);
del_timer_sync(&host->req_tout_timer);
tasklet_kill(&host->dma_tlet);
@@ -5324,8 +5288,8 @@
clk_put(host->clk);
if (!IS_ERR(host->pclk))
clk_put(host->pclk);
- if (!IS_ERR_OR_NULL(host->dfab_pclk))
- clk_put(host->dfab_pclk);
+ if (!IS_ERR_OR_NULL(host->bus_clk))
+ clk_put(host->bus_clk);
if (host->cpu_dma_latency)
pm_qos_remove_request(&host->pm_qos_req_dma);
@@ -5441,6 +5405,49 @@
#endif
#ifdef CONFIG_PM
+#ifdef CONFIG_MMC_CLKGATE
+static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+ unsigned long flags;
+
+ mmc_host_clk_hold(mmc);
+ spin_lock_irqsave(&mmc->clk_lock, flags);
+ mmc->clk_old = mmc->ios.clock;
+ mmc->ios.clock = 0;
+ mmc->clk_gated = true;
+ spin_unlock_irqrestore(&mmc->clk_lock, flags);
+ mmc_set_ios(mmc);
+ mmc_host_clk_release(mmc);
+}
+
+static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ mmc_host_clk_hold(mmc);
+ mmc->ios.clock = host->clk_rate;
+ mmc_set_ios(mmc);
+ mmc_host_clk_release(mmc);
+}
+#else
+static inline void msmsdcc_gate_clock(struct msmsdcc_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ mmc->ios.clock = 0;
+ mmc_set_ios(mmc);
+}
+
+static inline void msmsdcc_ungate_clock(struct msmsdcc_host *host)
+{
+ struct mmc_host *mmc = host->mmc;
+
+ mmc->ios.clock = host->clk_rate;
+ mmc_set_ios(mmc);
+}
+#endif
+
static int
msmsdcc_runtime_suspend(struct device *dev)
{
@@ -5487,21 +5494,12 @@
spin_unlock_irqrestore(&host->lock, flags);
if (mmc->card && mmc_card_sdio(mmc->card) &&
mmc->ios.clock) {
-#ifdef CONFIG_MMC_CLKGATE
/*
* If SDIO function driver doesn't want
* to power off the card, atleast turn off
* clocks to allow deep sleep (TCXO shutdown).
*/
- mmc_host_clk_hold(mmc);
- spin_lock_irqsave(&mmc->clk_lock, flags);
- mmc->clk_old = mmc->ios.clock;
- mmc->ios.clock = 0;
- mmc->clk_gated = true;
- spin_unlock_irqrestore(&mmc->clk_lock, flags);
- mmc_set_ios(mmc);
- mmc_host_clk_release(mmc);
-#endif
+ msmsdcc_gate_clock(host);
}
}
host->sdcc_suspending = 0;
@@ -5530,10 +5528,7 @@
if (mmc) {
if (mmc->card && mmc_card_sdio(mmc->card) &&
mmc_card_keep_power(mmc)) {
- mmc_host_clk_hold(mmc);
- mmc->ios.clock = host->clk_rate;
- mmc_set_ios(mmc);
- mmc_host_clk_release(mmc);
+ msmsdcc_ungate_clock(host);
}
mmc_resume_host(mmc);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index ecf4950..5531f06 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -212,10 +212,10 @@
#define NR_SG 128
#define MSM_MMC_IDLE_TIMEOUT 5000 /* msecs */
+#define MSM_MMC_CLK_GATE_DELAY 200 /* msecs */
/* Set the request timeout to 10secs */
#define MSM_MMC_REQ_TIMEOUT 10000 /* msecs */
-#define MSM_MMC_DISABLE_TIMEOUT 200 /* msecs */
/*
* Controller HW limitations
@@ -293,8 +293,8 @@
unsigned int xfer_remain; /* Bytes remaining to send */
unsigned int data_xfered; /* Bytes acked by BLKEND irq */
int got_dataend;
- int wait_for_auto_prog_done;
- int got_auto_prog_done;
+ bool wait_for_auto_prog_done;
+ bool got_auto_prog_done;
bool use_wr_data_pend;
int user_pages;
u32 req_tout_ms;
@@ -350,7 +350,7 @@
struct mmc_host *mmc;
struct clk *clk; /* main MMC bus clock */
struct clk *pclk; /* SDCC peripheral bus clock */
- struct clk *dfab_pclk; /* Daytona Fabric SDCC clock */
+ struct clk *bus_clk; /* SDCC bus voter clock */
unsigned int clks_on; /* set if clocks are enabled */
unsigned int eject; /* eject state */
@@ -411,6 +411,8 @@
struct mutex clk_mutex;
bool pending_resume;
struct msmsdcc_msm_bus_vote msm_bus_vote;
+ struct device_attribute max_bus_bw;
+ struct device_attribute polling;
};
int msmsdcc_set_pwrsave(struct mmc_host *mmc, int pwrsave);
diff --git a/drivers/mtd/devices/msm_nand.c b/drivers/mtd/devices/msm_nand.c
index bd36aea..c43abca 100644
--- a/drivers/mtd/devices/msm_nand.c
+++ b/drivers/mtd/devices/msm_nand.c
@@ -1990,20 +1990,74 @@
{
int ret;
struct mtd_oob_ops ops;
+ int (*read_oob)(struct mtd_info *, loff_t, struct mtd_oob_ops *);
- /* printk("msm_nand_read %llx %x\n", from, len); */
+ if (!dual_nand_ctlr_present)
+ read_oob = msm_nand_read_oob;
+ else
+ read_oob = msm_nand_read_oob_dualnandc;
ops.mode = MTD_OPS_PLACE_OOB;
- ops.len = len;
ops.retlen = 0;
ops.ooblen = 0;
- ops.datbuf = buf;
ops.oobbuf = NULL;
- if (!dual_nand_ctlr_present)
- ret = msm_nand_read_oob(mtd, from, &ops);
- else
- ret = msm_nand_read_oob_dualnandc(mtd, from, &ops);
- *retlen = ops.retlen;
+ ret = 0;
+ *retlen = 0;
+
+ if ((from & (mtd->writesize - 1)) == 0 && len == mtd->writesize) {
+ /* reading a page on page boundary */
+ ops.len = len;
+ ops.datbuf = buf;
+ ret = read_oob(mtd, from, &ops);
+ *retlen = ops.retlen;
+ } else if (len > 0) {
+ /* reading any size on any offset. partial page is supported */
+ u8 *bounce_buf;
+ loff_t aligned_from;
+ loff_t offset;
+ size_t actual_len;
+
+ bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
+ if (!bounce_buf) {
+ pr_err("%s: could not allocate memory\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ops.len = mtd->writesize;
+ offset = from & (mtd->writesize - 1);
+ aligned_from = from - offset;
+
+ for (;;) {
+ int no_copy;
+
+ actual_len = mtd->writesize - offset;
+ if (actual_len > len)
+ actual_len = len;
+
+ no_copy = (offset == 0 && actual_len == mtd->writesize);
+ ops.datbuf = (no_copy) ? buf : bounce_buf;
+ ret = read_oob(mtd, aligned_from, &ops);
+ if (ret < 0)
+ break;
+
+ if (!no_copy)
+ memcpy(buf, bounce_buf + offset, actual_len);
+
+ len -= actual_len;
+ *retlen += actual_len;
+ if (len == 0)
+ break;
+
+ buf += actual_len;
+ offset = 0;
+ aligned_from += mtd->writesize;
+ }
+
+ kfree(bounce_buf);
+ }
+
+out:
return ret;
}
@@ -2963,18 +3017,54 @@
{
int ret;
struct mtd_oob_ops ops;
+ int (*write_oob)(struct mtd_info *, loff_t, struct mtd_oob_ops *);
+
+ if (!dual_nand_ctlr_present)
+ write_oob = msm_nand_write_oob;
+ else
+ write_oob = msm_nand_write_oob_dualnandc;
ops.mode = MTD_OPS_PLACE_OOB;
- ops.len = len;
ops.retlen = 0;
ops.ooblen = 0;
- ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
- if (!dual_nand_ctlr_present)
- ret = msm_nand_write_oob(mtd, to, &ops);
- else
- ret = msm_nand_write_oob_dualnandc(mtd, to, &ops);
- *retlen = ops.retlen;
+ ret = 0;
+ *retlen = 0;
+
+ if (!virt_addr_valid(buf) &&
+ ((to | len) & (mtd->writesize - 1)) == 0 &&
+ ((unsigned long) buf & ~PAGE_MASK) + len > PAGE_SIZE) {
+ /*
+ * Handle writing of large size write buffer in vmalloc
+ * address space that does not fit in an MMU page.
+ * The destination address must be on page boundary,
+ * and the size must be multiple of NAND page size.
+ * Writing partial page is not supported.
+ */
+ ops.len = mtd->writesize;
+
+ for (;;) {
+ ops.datbuf = (uint8_t *) buf;
+
+ ret = write_oob(mtd, to, &ops);
+ if (ret < 0)
+ break;
+
+ len -= mtd->writesize;
+ *retlen += mtd->writesize;
+ if (len == 0)
+ break;
+
+ buf += mtd->writesize;
+ to += mtd->writesize;
+ }
+ } else {
+ ops.len = len;
+ ops.datbuf = (uint8_t *) buf;
+ ret = write_oob(mtd, to, &ops);
+ *retlen = ops.retlen;
+ }
+
return ret;
}
@@ -6747,6 +6837,7 @@
mtd->writesize = supported_flash.pagesize * i;
mtd->oobsize = supported_flash.oobsize * i;
mtd->erasesize = supported_flash.blksize * i;
+ mtd->writebufsize = mtd->writesize;
if (!interleave_enable)
mtd_writesize = mtd->writesize;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index 23ba900..c2085c9 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -174,6 +174,8 @@
goto resubmit_int_urb;
}
+ usb_mark_last_busy(udev);
+
if (!dev->resp_available) {
dev->resp_available = true;
wake_up(&dev->open_wait_queue);
@@ -261,6 +263,7 @@
resubmit_int_urb:
/*re-submit int urb to check response available*/
+ usb_mark_last_busy(udev);
status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
if (status)
dev_err(dev->devicep, "%s: Error re-submitting Int URB %d\n",
@@ -796,6 +799,7 @@
dev->intbuf, wMaxPacketSize,
notification_available_cb, dev, interval);
+ usb_mark_last_busy(udev);
return rmnet_usb_ctrl_start_rx(dev);
}
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 2183ee6..9e1e252 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -99,7 +99,7 @@
dev = (struct rmnet_ctrl_dev *)unet->data[1];
if (!dev) {
- dev_err(&unet->udev->dev, "%s: ctrl device not found\n",
+ dev_err(&iface->dev, "%s: ctrl device not found\n",
__func__);
retval = -ENODEV;
goto fail;
@@ -118,7 +118,7 @@
}
/* TBD : do we need to set/clear usbnet->udev->reset_resume*/
} else
- dev_dbg(&unet->udev->dev,
+ dev_dbg(&iface->dev,
"%s: device is busy can not suspend\n", __func__);
fail:
@@ -141,8 +141,7 @@
dev = (struct rmnet_ctrl_dev *)unet->data[1];
if (!dev) {
- dev_err(&unet->udev->dev, "%s: ctrl device not found\n",
- __func__);
+ dev_err(&iface->dev, "%s: ctrl device not found\n", __func__);
retval = -ENODEV;
goto fail;
}
@@ -164,17 +163,15 @@
struct usb_host_endpoint *bulk_in = NULL;
struct usb_host_endpoint *bulk_out = NULL;
struct usb_host_endpoint *int_in = NULL;
- struct usb_device *udev;
int status = 0;
int i;
int numends;
- udev = interface_to_usbdev(iface);
numends = iface->cur_altsetting->desc.bNumEndpoints;
for (i = 0; i < numends; i++) {
endpoint = iface->cur_altsetting->endpoint + i;
if (!endpoint) {
- dev_err(&udev->dev, "%s: invalid endpoint %u\n",
+ dev_err(&iface->dev, "%s: invalid endpoint %u\n",
__func__, i);
status = -EINVAL;
goto out;
@@ -188,7 +185,7 @@
}
if (!bulk_in || !bulk_out || !int_in) {
- dev_err(&udev->dev, "%s: invalid endpoints\n", __func__);
+ dev_err(&iface->dev, "%s: invalid endpoints\n", __func__);
status = -EINVAL;
goto out;
}
@@ -394,7 +391,7 @@
break;
default:
- dev_err(&unet->udev->dev, "[%s] error: "
+ dev_err(&unet->intf->dev, "[%s] error: "
"rmnet_ioct called for unsupported cmd[%d]",
dev->name, cmd);
return -EINVAL;
@@ -507,16 +504,15 @@
const struct usb_device_id *prod)
{
struct usbnet *unet;
- struct usb_device *udev;
struct driver_info *info;
+ struct usb_device *udev;
unsigned int iface_num;
static int first_rmnet_iface_num = -EINVAL;
int status = 0;
- udev = interface_to_usbdev(iface);
iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
if (iface->num_altsetting != 1) {
- dev_err(&udev->dev, "%s invalid num_altsetting %u\n",
+ dev_err(&iface->dev, "%s invalid num_altsetting %u\n",
__func__, iface->num_altsetting);
status = -EINVAL;
goto out;
@@ -528,7 +524,7 @@
status = usbnet_probe(iface, prod);
if (status < 0) {
- dev_err(&udev->dev, "usbnet_probe failed %d\n", status);
+ dev_err(&iface->dev, "usbnet_probe failed %d\n", status);
goto out;
}
unet = usb_get_intfdata(iface);
@@ -558,10 +554,19 @@
status = rmnet_usb_data_debugfs_init(unet);
if (status)
- dev_dbg(&udev->dev, "mode debugfs file is not available\n");
+ dev_dbg(&iface->dev, "mode debugfs file is not available\n");
+
+ udev = unet->udev;
/* allow modem to wake up suspended system */
device_set_wakeup_enable(&udev->dev, 1);
+
+ /* set default autosuspend timeout for modem and roothub */
+ if (udev->parent && !udev->parent->parent) {
+ pm_runtime_set_autosuspend_delay(&udev->dev, 1000);
+ pm_runtime_set_autosuspend_delay(&udev->parent->dev, 200);
+ }
+
out:
return status;
}
@@ -569,23 +574,20 @@
static void rmnet_usb_disconnect(struct usb_interface *intf)
{
struct usbnet *unet;
- struct usb_device *udev;
struct rmnet_ctrl_dev *dev;
- udev = interface_to_usbdev(intf);
- device_set_wakeup_enable(&udev->dev, 0);
-
unet = usb_get_intfdata(intf);
if (!unet) {
- dev_err(&udev->dev, "%s:data device not found\n", __func__);
+ dev_err(&intf->dev, "%s:data device not found\n", __func__);
return;
}
+ device_set_wakeup_enable(&unet->udev->dev, 0);
rmnet_usb_data_debugfs_cleanup(unet);
dev = (struct rmnet_ctrl_dev *)unet->data[1];
if (!dev) {
- dev_err(&udev->dev, "%s:ctrl device not found\n", __func__);
+ dev_err(&intf->dev, "%s:ctrl device not found\n", __func__);
return;
}
unet->data[0] = 0;
diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig
index 23efb00..15e7f3f 100644
--- a/drivers/platform/msm/Kconfig
+++ b/drivers/platform/msm/Kconfig
@@ -13,7 +13,8 @@
config SPS
bool "SPS support"
depends on (HAS_IOMEM && (ARCH_MSM8960 || ARCH_MSM8X60 \
- || ARCH_APQ8064 || ARCH_MSM9615 || ARCH_MSMCOPPER))
+ || ARCH_APQ8064 || ARCH_MSM9615 \
+ || ARCH_MSM9625 || ARCH_MSMCOPPER))
select GENERIC_ALLOCATOR
default n
help
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index fbaea09..1329f6c 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -79,6 +79,8 @@
*/
static struct sps_drv *sps;
+u32 d_type;
+
static void sps_device_de_init(void);
#ifdef CONFIG_DEBUG_FS
@@ -1443,11 +1445,6 @@
{
SPS_DBG("sps:%s.", __func__);
- if (h == NULL) {
- SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
- return SPS_ERROR;
- }
-
if (sps == NULL)
return -ENODEV;
@@ -1461,6 +1458,11 @@
return SPS_ERROR;
}
+ if (h == NULL)
+ SPS_DBG("sps:allocate pipe memory before setup pipe");
+ else
+ SPS_DBG("sps:allocate pipe memory for pipe %d", h->pipe_index);
+
mem_buffer->phys_base = sps_mem_alloc_io(mem_buffer->size);
if (mem_buffer->phys_base == SPS_ADDR_INVALID) {
SPS_ERR("sps:invalid address of allocated memory");
@@ -1481,16 +1483,16 @@
{
SPS_DBG("sps:%s.", __func__);
- if (h == NULL) {
- SPS_ERR("sps:%s:pipe is NULL.\n", __func__);
- return SPS_ERROR;
- }
-
if (mem_buffer == NULL || mem_buffer->phys_base == SPS_ADDR_INVALID) {
SPS_ERR("sps:invalid memory to free");
return SPS_ERROR;
}
+ if (h == NULL)
+ SPS_DBG("sps:free pipe memory.");
+ else
+ SPS_DBG("sps:free pipe memory for pipe %d.", h->pipe_index);
+
sps_mem_free_io(mem_buffer->phys_base, mem_buffer->size);
return 0;
@@ -1928,13 +1930,20 @@
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-dma-res-pipes",
- &sps->bamdma_restricted_pipes)) {
- SPS_ERR("sps:Fail to get restricted bamdma pipes.\n");
- return -EINVAL;
- } else
+ &sps->bamdma_restricted_pipes))
+ SPS_DBG("sps:No restricted bamdma pipes on this target.\n");
+ else
SPS_DBG("sps:bamdma_restricted_pipes=0x%x.",
sps->bamdma_restricted_pipes);
+ if (of_property_read_u32((&pdev->dev)->of_node,
+ "qcom,device-type",
+ &d_type)) {
+ d_type = 1;
+ SPS_DBG("sps:default device type.\n");
+ } else
+ SPS_DBG("sps:device type is %d.", d_type);
+
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (resource) {
sps->bamdma_bam_phys_base = resource->start;
@@ -1959,6 +1968,16 @@
return -ENODEV;
}
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (resource) {
+ sps->pipemem_phys_base = resource->start;
+ sps->pipemem_size = resource_size(resource);
+ SPS_DBG("sps:pipemem.base=0x%x,size=0x%x.",
+ sps->pipemem_phys_base,
+ sps->pipemem_size);
+ } else
+ SPS_DBG("sps:No pipe memory on this target.\n");
+
resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (resource) {
sps->bamdma_irq = resource->start;
@@ -1985,6 +2004,7 @@
} else
SPS_DBG("sps:get data from device tree.");
} else {
+ d_type = 0;
if (get_platform_data(pdev)) {
SPS_ERR("sps:Fail to get platform data.");
return -ENODEV;
@@ -2008,17 +2028,18 @@
goto device_create_err;
}
- sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
- if (IS_ERR(sps->dfab_clk)) {
- SPS_ERR("sps:fail to get dfab_clk.");
- goto clk_err;
- } else {
- ret = clk_set_rate(sps->dfab_clk, 64000000);
- if (ret) {
- SPS_ERR("sps:failed to set dfab_clk rate. "
- "ret=%d", ret);
- clk_put(sps->dfab_clk);
+ if (!d_type) {
+ sps->dfab_clk = clk_get(sps->dev, "dfab_clk");
+ if (IS_ERR(sps->dfab_clk)) {
+ SPS_ERR("sps:fail to get dfab_clk.");
goto clk_err;
+ } else {
+ ret = clk_set_rate(sps->dfab_clk, 64000000);
+ if (ret) {
+ SPS_ERR("sps:failed to set dfab_clk rate.");
+ clk_put(sps->dfab_clk);
+ goto clk_err;
+ }
}
}
@@ -2047,22 +2068,26 @@
}
}
- ret = clk_prepare_enable(sps->dfab_clk);
- if (ret) {
- SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
- goto clk_err;
+ if (!d_type) {
+ ret = clk_prepare_enable(sps->dfab_clk);
+ if (ret) {
+ SPS_ERR("sps:failed to enable dfab_clk. ret=%d", ret);
+ goto clk_err;
+ }
}
#endif
ret = sps_device_init();
if (ret) {
SPS_ERR("sps:sps_device_init err.");
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
- clk_disable_unprepare(sps->dfab_clk);
+ if (!d_type)
+ clk_disable_unprepare(sps->dfab_clk);
#endif
goto sps_device_init_err;
}
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
- clk_disable_unprepare(sps->dfab_clk);
+ if (!d_type)
+ clk_disable_unprepare(sps->dfab_clk);
#endif
sps->is_ready = true;
@@ -2089,7 +2114,8 @@
class_destroy(sps->dev_class);
sps_device_de_init();
- clk_put(sps->dfab_clk);
+ if (!d_type)
+ clk_put(sps->dfab_clk);
clk_put(sps->pmem_clk);
clk_put(sps->bamdma_clk);
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index 1b19b12..fa22f1c 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.c
@@ -104,31 +104,30 @@
*/
int sps_mem_init(u32 pipemem_phys_base, u32 pipemem_size)
{
-#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
int res;
-#endif
+
/* 2^8=128. The desc-fifo and data-fifo minimal allocation. */
int min_alloc_order = 8;
-#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
- iomem_phys = pipemem_phys_base;
- iomem_size = pipemem_size;
+ if ((d_type == 0) || (d_type == 2)) {
+ iomem_phys = pipemem_phys_base;
+ iomem_size = pipemem_size;
- if (iomem_phys == 0) {
- SPS_ERR("sps:Invalid Pipe-Mem address");
- return SPS_ERROR;
- } else {
- iomem_virt = ioremap(iomem_phys, iomem_size);
- if (!iomem_virt) {
- SPS_ERR("sps:Failed to IO map pipe memory.\n");
- return -ENOMEM;
+ if (iomem_phys == 0) {
+ SPS_ERR("sps:Invalid Pipe-Mem address");
+ return SPS_ERROR;
+ } else {
+ iomem_virt = ioremap(iomem_phys, iomem_size);
+ if (!iomem_virt) {
+ SPS_ERR("sps:Failed to IO map pipe memory.\n");
+ return -ENOMEM;
+ }
}
- }
- iomem_offset = 0;
- SPS_DBG("sps:sps_mem_init.iomem_phys=0x%x,iomem_virt=0x%x.",
- iomem_phys, (u32) iomem_virt);
-#endif
+ iomem_offset = 0;
+ SPS_DBG("sps:sps_mem_init.iomem_phys=0x%x,iomem_virt=0x%x.",
+ iomem_phys, (u32) iomem_virt);
+ }
pool = gen_pool_create(min_alloc_order, nid);
@@ -137,11 +136,11 @@
return -ENOMEM;
}
-#ifndef CONFIG_SPS_SUPPORT_NDP_BAM
- res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
- if (res)
- return res;
-#endif
+ if ((d_type == 0) || (d_type == 2)) {
+ res = gen_pool_add(pool, (u32) iomem_virt, iomem_size, nid);
+ if (res)
+ return res;
+ }
return 0;
}
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index e8ab832..5a141ca 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.h
@@ -40,6 +40,8 @@
/* "Clear" value for the connection parameter struct */
#define SPSRM_CLEAR 0xcccccccc
+extern u32 d_type;
+
#ifdef CONFIG_DEBUG_FS
extern u8 debugfs_record_enabled;
extern u8 logging_option;
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b0439bc..73c042d 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -100,8 +100,6 @@
struct sf_lut *rbatt_sf_lut;
int delta_rbatt_mohm;
struct work_struct calib_hkadc_work;
- struct delayed_work calib_ccadc_work;
- unsigned int calib_delay_ms;
unsigned int revision;
unsigned int xoadc_v0625_usb_present;
unsigned int xoadc_v0625_usb_absent;
@@ -1604,18 +1602,6 @@
schedule_work(&the_chip->calib_hkadc_work);
}
-static void calibrate_ccadc_work(struct work_struct *work)
-{
- struct pm8921_bms_chip *chip = container_of(work,
- struct pm8921_bms_chip, calib_ccadc_work.work);
-
- pm8xxx_calib_ccadc();
- calib_hkadc(chip);
- schedule_delayed_work(&chip->calib_ccadc_work,
- round_jiffies_relative(msecs_to_jiffies
- (chip->calib_delay_ms)));
-}
-
int pm8921_bms_get_vsense_avg(int *result)
{
int rc = -EINVAL;
@@ -2601,7 +2587,6 @@
chip->r_sense = pdata->r_sense;
chip->i_test = pdata->i_test;
chip->v_failure = pdata->v_failure;
- chip->calib_delay_ms = pdata->calib_delay_ms;
chip->max_voltage_uv = pdata->max_voltage_uv;
chip->batt_type = pdata->battery_type;
chip->rconn_mohm = pdata->rconn_mohm;
@@ -2655,11 +2640,6 @@
}
check_initial_ocv(chip);
- INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
- /* begin calibration only on chips > 2.0 */
- if (chip->revision >= PM8XXX_REVISION_8921_2p0)
- schedule_delayed_work(&chip->calib_ccadc_work, 0);
-
/* initial hkadc calibration */
schedule_work(&chip->calib_hkadc_work);
/* enable the vbatt reading interrupts for scheduling hkadc calib */
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index c983389..a1561f0 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -3308,6 +3308,9 @@
int rc;
int vdd_safe;
+ /* forcing 19p2mhz before accessing any charger registers */
+ pm8921_chg_force_19p2mhz_clk(chip);
+
rc = pm_chg_masked_write(chip, SYS_CONFIG_2,
BOOT_DONE_BIT, BOOT_DONE_BIT);
if (rc) {
@@ -3501,8 +3504,6 @@
/* Disable EOC FSM processing */
pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, 0x91);
- pm8921_chg_force_19p2mhz_clk(chip);
-
rc = pm_chg_masked_write(chip, CHG_CNTRL, VREF_BATT_THERM_FORCE_ON,
VREF_BATT_THERM_FORCE_ON);
if (rc)
diff --git a/drivers/power/pm8xxx-ccadc.c b/drivers/power/pm8xxx-ccadc.c
index ce72a5b..ef31575 100644
--- a/drivers/power/pm8xxx-ccadc.c
+++ b/drivers/power/pm8xxx-ccadc.c
@@ -70,8 +70,10 @@
u16 ccadc_offset;
int ccadc_gain_uv;
unsigned int revision;
+ unsigned int calib_delay_ms;
int eoc_irq;
int r_sense;
+ struct delayed_work calib_ccadc_work;
};
static struct pm8xxx_ccadc_chip *the_chip;
@@ -334,6 +336,11 @@
u16 result;
int i, rc;
+ if (!the_chip) {
+ pr_err("chip not initialized\n");
+ return;
+ }
+
rc = pm8xxx_readb(the_chip->dev->parent,
ADC_ARB_SECP_CNTRL, &sec_cntrl);
if (rc < 0) {
@@ -473,6 +480,17 @@
}
EXPORT_SYMBOL(pm8xxx_calib_ccadc);
+static void calibrate_ccadc_work(struct work_struct *work)
+{
+ struct pm8xxx_ccadc_chip *chip = container_of(work,
+ struct pm8xxx_ccadc_chip, calib_ccadc_work.work);
+
+ pm8xxx_calib_ccadc();
+ schedule_delayed_work(&chip->calib_ccadc_work,
+ round_jiffies_relative(msecs_to_jiffies
+ (chip->calib_delay_ms)));
+}
+
static irqreturn_t pm8921_bms_ccadc_eoc_handler(int irq, void *data)
{
u8 data_msb, data_lsb;
@@ -671,6 +689,7 @@
chip->revision = pm8xxx_get_revision(chip->dev->parent);
chip->eoc_irq = res->start;
chip->r_sense = pdata->r_sense;
+ chip->calib_delay_ms = pdata->calib_delay_ms;
calib_ccadc_read_offset_and_gain(chip,
&chip->ccadc_gain_uv,
@@ -682,6 +701,10 @@
pr_err("failed to request %d irq rc= %d\n", chip->eoc_irq, rc);
goto free_chip;
}
+
+ INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
+ schedule_delayed_work(&chip->calib_ccadc_work, 0);
+
disable_irq_nosync(chip->eoc_irq);
platform_set_drvdata(pdev, chip);
diff --git a/drivers/power/smb349.c b/drivers/power/smb349.c
index 4c07285..ffc92d5 100644
--- a/drivers/power/smb349.c
+++ b/drivers/power/smb349.c
@@ -86,11 +86,11 @@
int en_n_gpio;
int chg_susp_gpio;
- struct dentry *dent;
- spinlock_t lock;
- struct work_struct hwinit_work;
+ struct dentry *dent;
+ spinlock_t lock;
- struct power_supply dc_psy;
+ struct work_struct chg_work;
+ struct power_supply dc_psy;
};
struct chg_ma_limit_entry {
@@ -244,7 +244,7 @@
{
int addr = (int)data;
int ret;
- u8 temp;
+ u8 temp = 0;
ret = smb349_read_reg(the_smb349_chg->client, addr, &temp);
if (ret) {
@@ -445,16 +445,17 @@
static int smb349_stop_charging(struct smb349_struct *smb349_chg)
{
unsigned long flags;
-
- if (smb349_chg->charging)
- gpio_set_value_cansleep(smb349_chg->en_n_gpio, 0);
+ int rc = 0;
spin_lock_irqsave(&smb349_chg->lock, flags);
pr_debug("stop charging %d\n", smb349_chg->charging);
smb349_chg->charging = 0;
spin_unlock_irqrestore(&smb349_chg->lock, flags);
- power_supply_changed(&smb349_chg->dc_psy);
- return 0;
+
+ if (smb349_chg->charging)
+ rc = schedule_work(&smb349_chg->chg_work);
+
+ return rc;
}
static int smb349_start_charging(struct smb349_struct *smb349_chg)
@@ -463,21 +464,14 @@
int rc;
rc = 0;
- if (!smb349_chg->charging) {
- gpio_set_value_cansleep(smb349_chg->en_n_gpio, 1);
- /*
- * Write non-default values, charger chip reloads from
- * non-volatile memory if it was in suspend mode
- *
- */
- rc = schedule_work(&smb349_chg->hwinit_work);
- }
-
spin_lock_irqsave(&smb349_chg->lock, flags);
pr_debug("start charging %d\n", smb349_chg->charging);
smb349_chg->charging = 1;
spin_unlock_irqrestore(&smb349_chg->lock, flags);
- power_supply_changed(&smb349_chg->dc_psy);
+
+ if (!smb349_chg->charging)
+ rc = schedule_work(&smb349_chg->chg_work);
+
return rc;
}
@@ -522,15 +516,25 @@
return 0;
}
-static void hwinit_worker(struct work_struct *work)
+static void chg_worker(struct work_struct *work)
{
- int ret;
struct smb349_struct *smb349_chg = container_of(work,
- struct smb349_struct, hwinit_work);
+ struct smb349_struct, chg_work);
+ int ret = 0;
- ret = smb349_hwinit(smb349_chg);
+ gpio_set_value_cansleep(smb349_chg->en_n_gpio, smb349_chg->charging);
+
+ /*
+ * Write non-default values, charger chip reloads from
+ * non-volatile memory if it was in suspend mode
+ *
+ */
+ if (smb349_chg->charging)
+ ret = smb349_hwinit(smb349_chg);
if (ret)
pr_err("Failed to re-initilaze registers\n");
+
+ power_supply_changed(&smb349_chg->dc_psy);
}
static int __devinit smb349_init_ext_chg(struct smb349_struct *smb349_chg)
@@ -614,7 +618,7 @@
the_smb349_chg = smb349_chg;
create_debugfs_entries(smb349_chg);
- INIT_WORK(&smb349_chg->hwinit_work, hwinit_worker);
+ INIT_WORK(&smb349_chg->chg_work, chg_worker);
pr_info("OK connector present = %d\n", smb349_chg->present);
return 0;
@@ -634,7 +638,7 @@
const struct smb349_platform_data *pdata;
struct smb349_struct *smb349_chg = i2c_get_clientdata(client);
- flush_work(&smb349_chg->hwinit_work);
+ flush_work(&smb349_chg->chg_work);
pdata = client->dev.platform_data;
power_supply_unregister(&smb349_chg->dc_psy);
gpio_free(pdata->en_n_gpio);
diff --git a/drivers/regulator/msm-gpio-regulator.c b/drivers/regulator/msm-gpio-regulator.c
index 5c99f4c..15e5b53 100644
--- a/drivers/regulator/msm-gpio-regulator.c
+++ b/drivers/regulator/msm-gpio-regulator.c
@@ -42,11 +42,13 @@
/* Request GPIO now if it hasn't been requested before. */
if (!vreg->gpio_requested) {
rc = gpio_request(vreg->gpio, vreg->gpio_label);
- if (rc < 0)
+ if (rc < 0) {
pr_err("failed to request gpio %u (%s), rc=%d\n",
vreg->gpio, vreg->gpio_label, rc);
- else
+ return rc;
+ } else {
vreg->gpio_requested = true;
+ }
rc = gpio_sysfs_set_active_low(vreg->gpio, vreg->active_low);
if (rc < 0)
diff --git a/drivers/spmi/spmi.c b/drivers/spmi/spmi.c
index 3f63532..0342b97 100644
--- a/drivers/spmi/spmi.c
+++ b/drivers/spmi/spmi.c
@@ -20,6 +20,7 @@
#include <linux/platform_device.h>
#include <linux/spmi.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
struct spmii_boardinfo {
struct list_head list;
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index df335d2..d03b4b4 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -25,13 +25,14 @@
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
#include <mach/msm_serial_hs.h>
#include "smux_private.h"
#include "smux_loopback.h"
#define SMUX_NOTIFY_FIFO_SIZE 128
#define SMUX_TX_QUEUE_SIZE 256
-#define SMUX_GET_RX_BUFF_MAX_RETRY_CNT 2
#define SMUX_WM_LOW 2
#define SMUX_WM_HIGH 4
#define SMUX_PKT_LOG_SIZE 80
@@ -49,6 +50,10 @@
/* inactivity timeout for no rx/tx activity */
#define SMUX_INACTIVITY_TIMEOUT_MS 1000
+/* RX get_rx_buffer retry timeout values */
+#define SMUX_RX_RETRY_MIN_MS (1 << 0) /* 1 ms */
+#define SMUX_RX_RETRY_MAX_MS (1 << 10) /* 1024 ms */
+
enum {
MSM_SMUX_DEBUG = 1U << 0,
MSM_SMUX_INFO = 1U << 1,
@@ -73,6 +78,11 @@
pr_info(x); \
} while (0)
+#define SMUX_PWR(x...) do { \
+ if (smux_debug_mask & MSM_SMUX_POWER_INFO) \
+ pr_info(x); \
+} while (0)
+
#define SMUX_LOG_PKT_RX(pkt) do { \
if (smux_debug_mask & MSM_SMUX_PKT) \
smux_log_pkt(pkt, 1); \
@@ -175,6 +185,11 @@
int (*get_rx_buffer)(void *priv, void **pkt_priv, void **buffer,
int size);
+ /* RX Info */
+ struct list_head rx_retry_queue;
+ unsigned rx_retry_queue_cnt;
+ struct delayed_work rx_retry_work;
+
/* TX Info */
spinlock_t tx_lock_lhb2;
struct list_head tx_queue;
@@ -198,25 +213,54 @@
};
/**
+ * Get RX Buffer Retry structure.
+ *
+ * This is used for clients that are unable to provide an RX buffer
+ * immediately. This temporary structure will be used to temporarily hold the
+ * data and perform a retry.
+ */
+struct smux_rx_pkt_retry {
+ struct smux_pkt_t *pkt;
+ struct list_head rx_retry_list;
+ unsigned timeout_in_ms;
+};
+
+/**
+ * Receive worker data structure.
+ *
+ * One instance is created for every call to smux_rx_state_machine.
+ */
+struct smux_rx_worker_data {
+ const unsigned char *data;
+ int len;
+ int flag;
+
+ struct work_struct work;
+ struct completion work_complete;
+};
+
+/**
* Line discipline and module structure.
*
* Only one instance since multiple instances of line discipline are not
* allowed.
*/
struct smux_ldisc_t {
- spinlock_t lock_lha0;
+ struct mutex mutex_lha0;
int is_initialized;
int in_reset;
int ld_open_count;
struct tty_struct *tty;
- /* RX State Machine */
- spinlock_t rx_lock_lha1;
+ /* RX State Machine (singled-threaded access by smux_rx_wq) */
unsigned char recv_buf[SMUX_MAX_PKT_SIZE];
unsigned int recv_len;
unsigned int pkt_remain;
unsigned rx_state;
+
+ /* RX Activity - accessed by multiple threads */
+ spinlock_t rx_lock_lha1;
unsigned rx_activity_flag;
/* TX / Power */
@@ -226,6 +270,7 @@
unsigned pwr_wakeup_delay_us;
unsigned tx_activity_flag;
unsigned powerdown_enabled;
+ struct list_head power_queue;
};
@@ -259,10 +304,13 @@
static DEFINE_SPINLOCK(notify_lock_lhc1);
static struct workqueue_struct *smux_tx_wq;
+static struct workqueue_struct *smux_rx_wq;
static void smux_tx_worker(struct work_struct *work);
static DECLARE_WORK(smux_tx_work, smux_tx_worker);
static void smux_wakeup_worker(struct work_struct *work);
+static void smux_rx_retry_worker(struct work_struct *work);
+static void smux_rx_worker(struct work_struct *work);
static DECLARE_WORK(smux_wakeup_work, smux_wakeup_worker);
static DECLARE_DELAYED_WORK(smux_wakeup_delayed_work, smux_wakeup_worker);
@@ -275,6 +323,13 @@
static void list_channel(struct smux_lch_t *ch);
static int smux_send_status_cmd(struct smux_lch_t *ch);
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt);
+static void smux_flush_tty(void);
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch);
+static int schedule_notify(uint8_t lcid, int event,
+ const union notifier_metadata *metadata);
+static int ssr_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data);
/**
* Convert TTY Error Flags to string for logging purposes.
@@ -321,6 +376,7 @@
smux_notify_wq = create_singlethread_workqueue("smux_notify_wq");
smux_tx_wq = create_singlethread_workqueue("smux_tx_wq");
+ smux_rx_wq = create_singlethread_workqueue("smux_rx_wq");
if (IS_ERR(smux_notify_wq) || IS_ERR(smux_tx_wq)) {
SMUX_DBG("%s: create_singlethread_workqueue ENOMEM\n",
@@ -354,6 +410,10 @@
ch->notify = 0;
ch->get_rx_buffer = 0;
+ INIT_LIST_HEAD(&ch->rx_retry_queue);
+ ch->rx_retry_queue_cnt = 0;
+ INIT_DELAYED_WORK(&ch->rx_retry_work, smux_rx_retry_worker);
+
spin_lock_init(&ch->tx_lock_lhb2);
INIT_LIST_HEAD(&ch->tx_queue);
INIT_LIST_HEAD(&ch->tx_ready_list);
@@ -364,6 +424,83 @@
return 0;
}
+/**
+ * Empty and cleanup all SMUX logical channels for subsystem restart or line
+ * discipline disconnect.
+ */
+static void smux_lch_purge(void)
+{
+ struct smux_lch_t *ch;
+ unsigned long flags;
+ int i;
+
+ /* Empty TX ready list */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ while (!list_empty(&smux.lch_tx_ready_list)) {
+ SMUX_DBG("%s: emptying ready list %p\n",
+ __func__, smux.lch_tx_ready_list.next);
+ ch = list_first_entry(&smux.lch_tx_ready_list,
+ struct smux_lch_t,
+ tx_ready_list);
+ list_del(&ch->tx_ready_list);
+ INIT_LIST_HEAD(&ch->tx_ready_list);
+ }
+
+ /* Purge Power Queue */
+ while (!list_empty(&smux.power_queue)) {
+ struct smux_pkt_t *pkt;
+
+ pkt = list_first_entry(&smux.power_queue,
+ struct smux_pkt_t,
+ list);
+ list_del(&pkt->list);
+ SMUX_DBG("%s: emptying power queue pkt=%p\n",
+ __func__, pkt);
+ smux_free_pkt(pkt);
+ }
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ /* Close all ports */
+ for (i = 0 ; i < SMUX_NUM_LOGICAL_CHANNELS; i++) {
+ ch = &smux_lch[i];
+ SMUX_DBG("%s: cleaning up lcid %d\n", __func__, i);
+
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+
+ /* Purge TX queue */
+ spin_lock(&ch->tx_lock_lhb2);
+ smux_purge_ch_tx_queue(ch);
+ spin_unlock(&ch->tx_lock_lhb2);
+
+ /* Notify user of disconnect and reset channel state */
+ if (ch->local_state == SMUX_LCH_LOCAL_OPENED ||
+ ch->local_state == SMUX_LCH_LOCAL_CLOSING) {
+ union notifier_metadata meta;
+
+ meta.disconnected.is_ssr = smux.in_reset;
+ schedule_notify(ch->lcid, SMUX_DISCONNECTED, &meta);
+ }
+
+ ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+ ch->local_mode = SMUX_LCH_MODE_NORMAL;
+ ch->remote_state = SMUX_LCH_REMOTE_CLOSED;
+ ch->remote_mode = SMUX_LCH_MODE_NORMAL;
+ ch->tx_flow_control = 0;
+
+ /* Purge RX retry queue */
+ if (ch->rx_retry_queue_cnt)
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work, 0);
+
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ }
+
+ /* Flush TX/RX workqueues */
+ SMUX_DBG("%s: flushing tx wq\n", __func__);
+ flush_workqueue(smux_tx_wq);
+ SMUX_DBG("%s: flushing rx wq\n", __func__);
+ flush_workqueue(smux_rx_wq);
+}
+
int smux_assert_lch_id(uint32_t lcid)
{
if (lcid >= SMUX_NUM_LOGICAL_CHANNELS)
@@ -785,7 +922,7 @@
if (!data)
return 0;
- while (len > 0) {
+ while (len > 0 && !smux.in_reset) {
data_written = smux.tty->ops->write(smux.tty, data, len);
if (data_written >= 0) {
len -= data_written;
@@ -799,8 +936,6 @@
if (len)
tty_wait_until_sent(smux.tty,
msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
-
- /* FUTURE - add SSR logic */
}
return 0;
}
@@ -866,19 +1001,19 @@
*/
static void smux_send_byte(char ch)
{
- struct smux_pkt_t pkt;
+ struct smux_pkt_t *pkt;
- smux_init_pkt(&pkt);
+ pkt = smux_alloc_pkt();
+ if (!pkt) {
+ pr_err("%s: alloc failure for byte %x\n", __func__, ch);
+ return;
+ }
+ pkt->hdr.cmd = SMUX_CMD_BYTE;
+ pkt->hdr.flags = ch;
+ pkt->hdr.lcid = SMUX_BROADCAST_LCID;
- pkt.hdr.cmd = SMUX_CMD_BYTE;
- pkt.hdr.flags = ch;
- pkt.hdr.lcid = 0;
- pkt.hdr.flags = ch;
- SMUX_LOG_PKT_TX(&pkt);
- if (!smux_byte_loopback)
- smux_tx_tty(&pkt);
- else
- smux_tx_loopback(&pkt);
+ list_add_tail(&pkt->list, &smux.power_queue);
+ queue_work(smux_tx_wq, &smux_tx_work);
}
/**
@@ -888,8 +1023,6 @@
* @lcid Logical channel ID for packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 locked.
*/
static int smux_receive_byte(char ch, int lcid)
{
@@ -931,8 +1064,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_open_ack(struct smux_pkt_t *pkt)
{
@@ -1021,8 +1152,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_open_cmd(struct smux_pkt_t *pkt)
{
@@ -1030,6 +1159,7 @@
int ret;
struct smux_lch_t *ch;
struct smux_pkt_t *ack_pkt;
+ unsigned long flags;
int tx_ready = 0;
int enable_powerdown = 0;
@@ -1039,7 +1169,7 @@
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
- spin_lock(&ch->state_lock_lhb1);
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_CLOSED) {
SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
@@ -1100,13 +1230,16 @@
}
out:
- spin_unlock(&ch->state_lock_lhb1);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
if (enable_powerdown) {
- spin_lock(&smux.tx_lock_lha2);
- smux.powerdown_enabled = 1;
- SMUX_DBG("%s: enabling power-collapse support\n", __func__);
- spin_unlock(&smux.tx_lock_lha2);
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (!smux.powerdown_enabled) {
+ smux.powerdown_enabled = 1;
+ SMUX_DBG("%s: enabling power-collapse support\n",
+ __func__);
+ }
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
if (tx_ready)
@@ -1121,8 +1254,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_close_cmd(struct smux_pkt_t *pkt)
{
@@ -1131,6 +1262,7 @@
struct smux_lch_t *ch;
struct smux_pkt_t *ack_pkt;
union notifier_metadata meta_disconnected;
+ unsigned long flags;
int tx_ready = 0;
if (pkt->hdr.flags & SMUX_CMD_CLOSE_ACK)
@@ -1140,7 +1272,7 @@
ch = &smux_lch[lcid];
meta_disconnected.disconnected.is_ssr = 0;
- spin_lock(&ch->state_lock_lhb1);
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
if (ch->remote_state == SMUX_LCH_REMOTE_OPENED) {
SMUX_DBG("lcid %d remote state 0x%x -> 0x%x\n", lcid,
SMUX_LCH_REMOTE_OPENED,
@@ -1191,7 +1323,7 @@
ret = -EINVAL;
}
out:
- spin_unlock(&ch->state_lock_lhb1);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
if (tx_ready)
list_channel(ch);
@@ -1204,25 +1336,30 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_data_cmd(struct smux_pkt_t *pkt)
{
uint8_t lcid;
- int ret;
- int i;
+ int ret = 0;
+ int do_retry = 0;
int tmp;
int rx_len;
struct smux_lch_t *ch;
union notifier_metadata metadata;
int remote_loopback;
- int tx_ready = 0;
struct smux_pkt_t *ack_pkt;
unsigned long flags;
- if (!pkt || smux_assert_lch_id(pkt->hdr.lcid))
- return -ENXIO;
+ if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
+ ret = -ENXIO;
+ goto out;
+ }
+
+ rx_len = pkt->hdr.payload_len;
+ if (rx_len == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
@@ -1234,6 +1371,7 @@
pr_err("smux: ch %d error data on local state 0x%x",
lcid, ch->local_state);
ret = -EIO;
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
goto out;
}
@@ -1241,69 +1379,110 @@
pr_err("smux: ch %d error data on remote state 0x%x",
lcid, ch->remote_state);
ret = -EIO;
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
goto out;
}
- rx_len = pkt->hdr.payload_len;
- if (rx_len == 0) {
- ret = -EINVAL;
- goto out;
+ if (!list_empty(&ch->rx_retry_queue)) {
+ do_retry = 1;
+ if ((ch->rx_retry_queue_cnt + 1) > SMUX_RX_RETRY_MAX_PKTS) {
+ /* retry queue full */
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ ret = -ENOMEM;
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ goto out;
+ }
}
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
- for (i = 0; i < SMUX_GET_RX_BUFF_MAX_RETRY_CNT; ++i) {
+ if (remote_loopback) {
+ /* Echo the data back to the remote client. */
+ ack_pkt = smux_alloc_pkt();
+ if (ack_pkt) {
+ ack_pkt->hdr.lcid = lcid;
+ ack_pkt->hdr.cmd = SMUX_CMD_DATA;
+ ack_pkt->hdr.flags = 0;
+ ack_pkt->hdr.payload_len = pkt->hdr.payload_len;
+ if (ack_pkt->hdr.payload_len) {
+ smux_alloc_pkt_payload(ack_pkt);
+ memcpy(ack_pkt->payload, pkt->payload,
+ ack_pkt->hdr.payload_len);
+ }
+ ack_pkt->hdr.pad_len = pkt->hdr.pad_len;
+ smux_tx_queue(ack_pkt, ch, 0);
+ list_channel(ch);
+ } else {
+ pr_err("%s: Remote loopack allocation failure\n",
+ __func__);
+ }
+ } else if (!do_retry) {
+ /* request buffer from client */
metadata.read.pkt_priv = 0;
metadata.read.buffer = 0;
+ tmp = ch->get_rx_buffer(ch->priv,
+ (void **)&metadata.read.pkt_priv,
+ (void **)&metadata.read.buffer,
+ rx_len);
- if (!remote_loopback) {
- tmp = ch->get_rx_buffer(ch->priv,
- (void **)&metadata.read.pkt_priv,
- (void **)&metadata.read.buffer,
+ if (tmp == 0 && metadata.read.buffer) {
+ /* place data into RX buffer */
+ memcpy(metadata.read.buffer, pkt->payload,
rx_len);
- if (tmp == 0 && metadata.read.buffer) {
- /* place data into RX buffer */
- memcpy(metadata.read.buffer, pkt->payload,
- rx_len);
- metadata.read.len = rx_len;
- schedule_notify(lcid, SMUX_READ_DONE,
- &metadata);
- ret = 0;
- break;
- } else if (tmp == -EAGAIN) {
- ret = -ENOMEM;
- } else if (tmp < 0) {
- schedule_notify(lcid, SMUX_READ_FAIL, NULL);
- ret = -ENOMEM;
- break;
- } else if (!metadata.read.buffer) {
- pr_err("%s: get_rx_buffer() buffer is NULL\n",
- __func__);
- ret = -ENOMEM;
- }
- } else {
- /* Echo the data back to the remote client. */
- ack_pkt = smux_alloc_pkt();
- if (ack_pkt) {
- ack_pkt->hdr.lcid = lcid;
- ack_pkt->hdr.cmd = SMUX_CMD_DATA;
- ack_pkt->hdr.flags = 0;
- ack_pkt->hdr.payload_len = pkt->hdr.payload_len;
- ack_pkt->payload = pkt->payload;
- ack_pkt->hdr.pad_len = pkt->hdr.pad_len;
- smux_tx_queue(ack_pkt, ch, 0);
- tx_ready = 1;
- } else {
- pr_err("%s: Remote loopack allocation failure\n",
- __func__);
- }
+ metadata.read.len = rx_len;
+ schedule_notify(lcid, SMUX_READ_DONE,
+ &metadata);
+ } else if (tmp == -EAGAIN ||
+ (tmp == 0 && !metadata.read.buffer)) {
+ /* buffer allocation failed - add to retry queue */
+ do_retry = 1;
+ } else if (tmp < 0) {
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ ret = -ENOMEM;
}
}
+ if (do_retry) {
+ struct smux_rx_pkt_retry *retry;
+
+ retry = kmalloc(sizeof(struct smux_rx_pkt_retry), GFP_KERNEL);
+ if (!retry) {
+ pr_err("%s: retry alloc failure\n", __func__);
+ ret = -ENOMEM;
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ goto out;
+ }
+ INIT_LIST_HEAD(&retry->rx_retry_list);
+ retry->timeout_in_ms = SMUX_RX_RETRY_MIN_MS;
+
+ /* copy packet */
+ retry->pkt = smux_alloc_pkt();
+ if (!retry->pkt) {
+ kfree(retry);
+ pr_err("%s: pkt alloc failure\n", __func__);
+ ret = -ENOMEM;
+ schedule_notify(lcid, SMUX_READ_FAIL, NULL);
+ goto out;
+ }
+ retry->pkt->hdr.lcid = lcid;
+ retry->pkt->hdr.payload_len = pkt->hdr.payload_len;
+ retry->pkt->hdr.pad_len = pkt->hdr.pad_len;
+ if (retry->pkt->hdr.payload_len) {
+ smux_alloc_pkt_payload(retry->pkt);
+ memcpy(retry->pkt->payload, pkt->payload,
+ retry->pkt->hdr.payload_len);
+ }
+
+ /* add to retry queue */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ list_add_tail(&retry->rx_retry_list, &ch->rx_retry_queue);
+ ++ch->rx_retry_queue_cnt;
+ if (ch->rx_retry_queue_cnt == 1)
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+ msecs_to_jiffies(retry->timeout_in_ms));
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ }
+
out:
- spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
-
- if (tx_ready)
- list_channel(ch);
-
return ret;
}
@@ -1322,8 +1501,10 @@
union notifier_metadata metadata;
unsigned long flags;
- if (!pkt || smux_assert_lch_id(pkt->hdr.lcid))
+ if (!pkt || smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid packet or channel id\n", __func__);
return -ENXIO;
+ }
lcid = pkt->hdr.lcid;
ch = &smux_lch[lcid];
@@ -1359,8 +1540,6 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_status_cmd(struct smux_pkt_t *pkt)
{
@@ -1416,20 +1595,18 @@
* @pkt Received packet
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_handle_rx_power_cmd(struct smux_pkt_t *pkt)
{
- int tx_ready = 0;
struct smux_pkt_t *ack_pkt = NULL;
+ unsigned long flags;
- spin_lock(&smux.tx_lock_lha2);
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK) {
/* local sleep request ack */
if (smux.power_state == SMUX_PWR_TURNING_OFF) {
/* Power-down complete, turn off UART */
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF_FLUSH);
smux.power_state = SMUX_PWR_OFF_FLUSH;
queue_work(smux_tx_wq, &smux_inactivity_work);
@@ -1438,37 +1615,41 @@
__func__, smux.power_state);
}
} else {
- /* remote sleep request */
+ /*
+ * Remote sleep request
+ *
+ * Even if we have data pending, we need to transition to the
+ * POWER_OFF state and then perform a wakeup since the remote
+ * side has requested a power-down.
+ *
+ * The state here is set to SMUX_PWR_TURNING_OFF_FLUSH and
+ * the TX thread will set the state to SMUX_PWR_TURNING_OFF
+ * when it sends the packet.
+ */
if (smux.power_state == SMUX_PWR_ON
|| smux.power_state == SMUX_PWR_TURNING_OFF) {
ack_pkt = smux_alloc_pkt();
if (ack_pkt) {
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF_FLUSH);
- /* send power-down request */
+ smux.power_state = SMUX_PWR_TURNING_OFF_FLUSH;
+
+ /* send power-down ack */
ack_pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
ack_pkt->hdr.flags = SMUX_CMD_PWR_CTL_ACK;
- ack_pkt->hdr.lcid = pkt->hdr.lcid;
- smux_tx_queue(ack_pkt,
- &smux_lch[ack_pkt->hdr.lcid], 0);
- tx_ready = 1;
- smux.power_state = SMUX_PWR_TURNING_OFF_FLUSH;
- queue_delayed_work(smux_tx_wq,
- &smux_delayed_inactivity_work,
- msecs_to_jiffies(
- SMUX_INACTIVITY_TIMEOUT_MS));
+ ack_pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+ list_add_tail(&ack_pkt->list,
+ &smux.power_queue);
+ queue_work(smux_tx_wq, &smux_tx_work);
}
} else {
pr_err("%s: sleep request invalid in state %d\n",
__func__, smux.power_state);
}
}
- spin_unlock(&smux.tx_lock_lha2);
-
- if (tx_ready)
- list_channel(&smux_lch[ack_pkt->hdr.lcid]);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
return 0;
}
@@ -1479,29 +1660,47 @@
* @pkt Packet to process
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_dispatch_rx_pkt(struct smux_pkt_t *pkt)
{
- int ret;
+ int ret = -ENXIO;
SMUX_LOG_PKT_RX(pkt);
switch (pkt->hdr.cmd) {
case SMUX_CMD_OPEN_LCH:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_open_cmd(pkt);
break;
case SMUX_CMD_DATA:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_data_cmd(pkt);
break;
case SMUX_CMD_CLOSE_LCH:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_close_cmd(pkt);
break;
case SMUX_CMD_STATUS:
+ if (smux_assert_lch_id(pkt->hdr.lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, pkt->hdr.lcid);
+ break;
+ }
ret = smux_handle_rx_status_cmd(pkt);
break;
@@ -1527,13 +1726,10 @@
* @len Length of the data
*
* @returns 0 for success
- *
- * Called with rx_lock_lha1 already locked.
*/
static int smux_deserialize(unsigned char *data, int len)
{
struct smux_pkt_t recv;
- uint8_t lcid;
smux_init_pkt(&recv);
@@ -1548,12 +1744,6 @@
return -EINVAL;
}
- lcid = recv.hdr.lcid;
- if (smux_assert_lch_id(lcid)) {
- pr_err("%s: invalid channel id %d\n", __func__, lcid);
- return -ENXIO;
- }
-
if (recv.hdr.payload_len)
recv.payload = data + sizeof(struct smux_hdr_t);
@@ -1562,16 +1752,16 @@
/**
* Handle wakeup request byte.
- *
- * Called with rx_lock_lha1 already locked.
*/
static void smux_handle_wakeup_req(void)
{
- spin_lock(&smux.tx_lock_lha2);
+ unsigned long flags;
+
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_OFF
|| smux.power_state == SMUX_PWR_TURNING_ON) {
/* wakeup system */
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_wakeup_work);
@@ -1582,20 +1772,20 @@
} else {
smux_send_byte(SMUX_WAKEUP_ACK);
}
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
/**
* Handle wakeup request ack.
- *
- * Called with rx_lock_lha1 already locked.
*/
static void smux_handle_wakeup_ack(void)
{
- spin_lock(&smux.tx_lock_lha2);
+ unsigned long flags;
+
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_TURNING_ON) {
/* received response to wakeup request */
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_ON);
smux.power_state = SMUX_PWR_ON;
queue_work(smux_tx_wq, &smux_tx_work);
@@ -1607,7 +1797,7 @@
pr_err("%s: wakeup request ack invalid in state %d\n",
__func__, smux.power_state);
}
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
/**
@@ -1617,8 +1807,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_idle(const unsigned char *data,
int len, int *used, int flag)
@@ -1666,8 +1854,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_magic(const unsigned char *data,
int len, int *used, int flag)
@@ -1707,8 +1893,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_hdr(const unsigned char *data,
int len, int *used, int flag)
@@ -1744,8 +1928,6 @@
* @len Length of the data
* @used Return value of length processed
* @flag Error flag - TTY_NORMAL 0 for no failure
- *
- * Called with rx_lock_lha1 locked.
*/
static void smux_rx_handle_pkt_payload(const unsigned char *data,
int len, int *used, int flag)
@@ -1784,47 +1966,20 @@
* @data Pointer to data block
* @len Length of data
* @flag TTY_NORMAL (0) for no error, otherwise TTY Error Flag
- *
- * Called with rx_lock_lha1 locked.
*/
void smux_rx_state_machine(const unsigned char *data,
int len, int flag)
{
- unsigned long flags;
- int used;
- int initial_rx_state;
+ struct smux_rx_worker_data work;
+ work.data = data;
+ work.len = len;
+ work.flag = flag;
+ INIT_WORK_ONSTACK(&work.work, smux_rx_worker);
+ work.work_complete = COMPLETION_INITIALIZER_ONSTACK(work.work_complete);
- SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
- spin_lock_irqsave(&smux.rx_lock_lha1, flags);
- used = 0;
- smux.rx_activity_flag = 1;
- do {
- SMUX_DBG("%s: state %d; %d of %d\n",
- __func__, smux.rx_state, used, len);
- initial_rx_state = smux.rx_state;
-
- switch (smux.rx_state) {
- case SMUX_RX_IDLE:
- smux_rx_handle_idle(data, len, &used, flag);
- break;
- case SMUX_RX_MAGIC:
- smux_rx_handle_magic(data, len, &used, flag);
- break;
- case SMUX_RX_HDR:
- smux_rx_handle_hdr(data, len, &used, flag);
- break;
- case SMUX_RX_PAYLOAD:
- smux_rx_handle_pkt_payload(data, len, &used, flag);
- break;
- default:
- SMUX_DBG("%s: invalid state %d\n",
- __func__, smux.rx_state);
- smux.rx_state = SMUX_RX_IDLE;
- break;
- }
- } while (used < len || smux.rx_state != initial_rx_state);
- spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+ queue_work(smux_rx_wq, &work.work);
+ wait_for_completion(&work.work_complete);
}
/**
@@ -1889,6 +2044,67 @@
}
/**
+ * Flush pending TTY TX data.
+ */
+static void smux_flush_tty(void)
+{
+ if (!smux.tty) {
+ pr_err("%s: ldisc not loaded\n", __func__);
+ return;
+ }
+
+ tty_wait_until_sent(smux.tty,
+ msecs_to_jiffies(TTY_BUFFER_FULL_WAIT_MS));
+
+ if (tty_chars_in_buffer(smux.tty) > 0)
+ pr_err("%s: unable to flush UART queue\n", __func__);
+}
+
+/**
+ * Purge TX queue for logical channel.
+ *
+ * @ch Logical channel pointer
+ *
+ * Must be called with the following spinlocks locked:
+ * state_lock_lhb1
+ * tx_lock_lhb2
+ */
+static void smux_purge_ch_tx_queue(struct smux_lch_t *ch)
+{
+ struct smux_pkt_t *pkt;
+ int send_disconnect = 0;
+
+ while (!list_empty(&ch->tx_queue)) {
+ pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
+ list);
+ list_del(&pkt->list);
+
+ if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
+ /* Open was never sent, just force to closed state */
+ ch->local_state = SMUX_LCH_LOCAL_CLOSED;
+ send_disconnect = 1;
+ } else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
+ /* Notify client of failed write */
+ union notifier_metadata meta_write;
+
+ meta_write.write.pkt_priv = pkt->priv;
+ meta_write.write.buffer = pkt->payload;
+ meta_write.write.len = pkt->hdr.payload_len;
+ schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
+ }
+ smux_free_pkt(pkt);
+ }
+
+ if (send_disconnect) {
+ union notifier_metadata meta_disconnected;
+
+ meta_disconnected.disconnected.is_ssr = smux.in_reset;
+ schedule_notify(ch->lcid, SMUX_DISCONNECTED,
+ &meta_disconnected);
+ }
+}
+
+/**
* Power-up the UART.
*/
static void smux_uart_power_on(void)
@@ -1934,7 +2150,7 @@
unsigned wakeup_delay;
int complete = 0;
- for (;;) {
+ while (!smux.in_reset) {
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_ON) {
/* wakeup complete */
@@ -1990,7 +2206,6 @@
*/
static void smux_inactivity_worker(struct work_struct *work)
{
- int tx_ready = 0;
struct smux_pkt_t *pkt;
unsigned long flags;
@@ -2004,7 +2219,7 @@
/* start power-down sequence */
pkt = smux_alloc_pkt();
if (pkt) {
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state,
SMUX_PWR_TURNING_OFF);
smux.power_state = SMUX_PWR_TURNING_OFF;
@@ -2012,11 +2227,13 @@
/* send power-down request */
pkt->hdr.cmd = SMUX_CMD_PWR_CTL;
pkt->hdr.flags = 0;
- pkt->hdr.lcid = 0;
- smux_tx_queue(pkt,
- &smux_lch[SMUX_TEST_LCID],
- 0);
- tx_ready = 1;
+ pkt->hdr.lcid = SMUX_BROADCAST_LCID;
+ list_add_tail(&pkt->list,
+ &smux.power_queue);
+ queue_work(smux_tx_wq, &smux_tx_work);
+ } else {
+ pr_err("%s: packet alloc failed\n",
+ __func__);
}
}
} else {
@@ -2027,21 +2244,26 @@
smux.tx_activity_flag = 0;
smux.rx_activity_flag = 0;
- spin_unlock(&smux.tx_lock_lha2);
- spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
-
- if (tx_ready)
- list_channel(&smux_lch[SMUX_TEST_LCID]);
-
- if ((smux.power_state == SMUX_PWR_OFF_FLUSH) ||
- (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH)) {
+ if (smux.power_state == SMUX_PWR_OFF_FLUSH) {
/* ready to power-down the UART */
- SMUX_DBG("%s: Power %d->%d\n", __func__,
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
smux.power_state, SMUX_PWR_OFF);
- smux_uart_power_off();
- spin_lock_irqsave(&smux.tx_lock_lha2, flags);
smux.power_state = SMUX_PWR_OFF;
- spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ /* if data is pending, schedule a new wakeup */
+ if (!list_empty(&smux.lch_tx_ready_list) ||
+ !list_empty(&smux.power_queue))
+ queue_work(smux_tx_wq, &smux_tx_work);
+
+ spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+ /* flush UART output queue and power down */
+ smux_flush_tty();
+ smux_uart_power_off();
+ } else {
+ spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
}
/* reschedule inactivity worker */
@@ -2051,6 +2273,167 @@
}
/**
+ * Remove RX retry packet from channel and free it.
+ *
+ * Must be called with state_lock_lhb1 locked.
+ *
+ * @ch Channel for retry packet
+ * @retry Retry packet to remove
+ */
+void smux_remove_rx_retry(struct smux_lch_t *ch,
+ struct smux_rx_pkt_retry *retry)
+{
+ list_del(&retry->rx_retry_list);
+ --ch->rx_retry_queue_cnt;
+ smux_free_pkt(retry->pkt);
+ kfree(retry);
+}
+
+/**
+ * RX worker handles all receive operations.
+ *
+ * @work Work structure contained in TBD structure
+ */
+static void smux_rx_worker(struct work_struct *work)
+{
+ unsigned long flags;
+ int used;
+ int initial_rx_state;
+ struct smux_rx_worker_data *w;
+ const unsigned char *data;
+ int len;
+ int flag;
+
+ w = container_of(work, struct smux_rx_worker_data, work);
+ data = w->data;
+ len = w->len;
+ flag = w->flag;
+
+ spin_lock_irqsave(&smux.rx_lock_lha1, flags);
+ smux.rx_activity_flag = 1;
+ spin_unlock_irqrestore(&smux.rx_lock_lha1, flags);
+
+ SMUX_DBG("%s: %p, len=%d, flag=%d\n", __func__, data, len, flag);
+ used = 0;
+ do {
+ SMUX_DBG("%s: state %d; %d of %d\n",
+ __func__, smux.rx_state, used, len);
+ initial_rx_state = smux.rx_state;
+
+ switch (smux.rx_state) {
+ case SMUX_RX_IDLE:
+ smux_rx_handle_idle(data, len, &used, flag);
+ break;
+ case SMUX_RX_MAGIC:
+ smux_rx_handle_magic(data, len, &used, flag);
+ break;
+ case SMUX_RX_HDR:
+ smux_rx_handle_hdr(data, len, &used, flag);
+ break;
+ case SMUX_RX_PAYLOAD:
+ smux_rx_handle_pkt_payload(data, len, &used, flag);
+ break;
+ default:
+ SMUX_DBG("%s: invalid state %d\n",
+ __func__, smux.rx_state);
+ smux.rx_state = SMUX_RX_IDLE;
+ break;
+ }
+ } while (used < len || smux.rx_state != initial_rx_state);
+
+ complete(&w->work_complete);
+}
+
+/**
+ * RX Retry worker handles retrying get_rx_buffer calls that previously failed
+ * because the client was not ready (-EAGAIN).
+ *
+ * @work Work structure contained in smux_lch_t structure
+ */
+static void smux_rx_retry_worker(struct work_struct *work)
+{
+ struct smux_lch_t *ch;
+ struct smux_rx_pkt_retry *retry;
+ union notifier_metadata metadata;
+ int tmp;
+ unsigned long flags;
+
+ ch = container_of(work, struct smux_lch_t, rx_retry_work.work);
+
+ /* get next retry packet */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ if (ch->local_state != SMUX_LCH_LOCAL_OPENED) {
+ /* port has been closed - remove all retries */
+ while (!list_empty(&ch->rx_retry_queue)) {
+ retry = list_first_entry(&ch->rx_retry_queue,
+ struct smux_rx_pkt_retry,
+ rx_retry_list);
+ smux_remove_rx_retry(ch, retry);
+ }
+ }
+
+ if (list_empty(&ch->rx_retry_queue)) {
+ SMUX_DBG("%s: retry list empty for channel %d\n",
+ __func__, ch->lcid);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ return;
+ }
+ retry = list_first_entry(&ch->rx_retry_queue,
+ struct smux_rx_pkt_retry,
+ rx_retry_list);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+ SMUX_DBG("%s: retrying rx pkt %p\n", __func__, retry);
+ metadata.read.pkt_priv = 0;
+ metadata.read.buffer = 0;
+ tmp = ch->get_rx_buffer(ch->priv,
+ (void **)&metadata.read.pkt_priv,
+ (void **)&metadata.read.buffer,
+ retry->pkt->hdr.payload_len);
+ if (tmp == 0 && metadata.read.buffer) {
+ /* have valid RX buffer */
+ memcpy(metadata.read.buffer, retry->pkt->payload,
+ retry->pkt->hdr.payload_len);
+ metadata.read.len = retry->pkt->hdr.payload_len;
+
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ smux_remove_rx_retry(ch, retry);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+ schedule_notify(ch->lcid, SMUX_READ_DONE, &metadata);
+ } else if (tmp == -EAGAIN ||
+ (tmp == 0 && !metadata.read.buffer)) {
+ /* retry again */
+ retry->timeout_in_ms <<= 1;
+ if (retry->timeout_in_ms > SMUX_RX_RETRY_MAX_MS) {
+ /* timed out */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ smux_remove_rx_retry(ch, retry);
+ schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+ }
+ } else {
+ /* client error - drop packet */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ smux_remove_rx_retry(ch, retry);
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+
+ schedule_notify(ch->lcid, SMUX_READ_FAIL, NULL);
+ }
+
+ /* schedule next retry */
+ spin_lock_irqsave(&ch->state_lock_lhb1, flags);
+ if (!list_empty(&ch->rx_retry_queue)) {
+ retry = list_first_entry(&ch->rx_retry_queue,
+ struct smux_rx_pkt_retry,
+ rx_retry_list);
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work,
+ msecs_to_jiffies(retry->timeout_in_ms));
+ }
+ spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
+}
+
+/**
* Transmit worker handles serializing and transmitting packets onto the
* underlying transport.
*
@@ -2078,12 +2461,68 @@
* inserting after the tail. The locks can then be released
* while the packet is processed.
*/
- for (;;) {
+ while (!smux.in_reset) {
pkt = NULL;
low_wm_notif = 0;
- /* get the next ready channel */
spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+
+ /* handle wakeup if needed */
+ if (smux.power_state == SMUX_PWR_OFF) {
+ if (!list_empty(&smux.lch_tx_ready_list) ||
+ !list_empty(&smux.power_queue)) {
+ /* data to transmit, do wakeup */
+ smux.pwr_wakeup_delay_us = 1;
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
+ smux.power_state,
+ SMUX_PWR_TURNING_ON);
+ smux.power_state = SMUX_PWR_TURNING_ON;
+ spin_unlock_irqrestore(&smux.tx_lock_lha2,
+ flags);
+ smux_uart_power_on();
+ queue_work(smux_tx_wq, &smux_wakeup_work);
+ } else {
+ /* no activity -- stay asleep */
+ spin_unlock_irqrestore(&smux.tx_lock_lha2,
+ flags);
+ }
+ break;
+ }
+
+ /* process any pending power packets */
+ if (!list_empty(&smux.power_queue)) {
+ pkt = list_first_entry(&smux.power_queue,
+ struct smux_pkt_t, list);
+ list_del(&pkt->list);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ /* send the packet */
+ SMUX_LOG_PKT_TX(pkt);
+ if (!smux_byte_loopback) {
+ smux_tx_tty(pkt);
+ smux_flush_tty();
+ } else {
+ smux_tx_loopback(pkt);
+ }
+
+ /* Adjust power state if this is a flush command */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (smux.power_state == SMUX_PWR_TURNING_OFF_FLUSH &&
+ pkt->hdr.cmd == SMUX_CMD_PWR_CTL &&
+ (pkt->hdr.flags & SMUX_CMD_PWR_CTL_ACK)) {
+ SMUX_PWR("%s: Power %d->%d\n", __func__,
+ smux.power_state,
+ SMUX_PWR_OFF_FLUSH);
+ smux.power_state = SMUX_PWR_OFF_FLUSH;
+ queue_work(smux_tx_wq, &smux_inactivity_work);
+ }
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ smux_free_pkt(pkt);
+ continue;
+ }
+
+ /* get the next ready channel */
if (list_empty(&smux.lch_tx_ready_list)) {
/* no ready channels */
SMUX_DBG("%s: no more ready channels, exiting\n",
@@ -2093,28 +2532,12 @@
}
smux.tx_activity_flag = 1;
- if (smux.power_state != SMUX_PWR_ON
- && smux.power_state != SMUX_PWR_TURNING_OFF
- && smux.power_state != SMUX_PWR_TURNING_OFF_FLUSH) {
- /* Link isn't ready to transmit */
- if (smux.power_state == SMUX_PWR_OFF) {
- /* link is off, trigger wakeup */
- smux.pwr_wakeup_delay_us = 1;
- SMUX_DBG("%s: Power %d->%d\n", __func__,
- smux.power_state,
- SMUX_PWR_TURNING_ON);
- smux.power_state = SMUX_PWR_TURNING_ON;
- spin_unlock_irqrestore(&smux.tx_lock_lha2,
- flags);
- smux_uart_power_on();
- queue_work(smux_tx_wq, &smux_wakeup_work);
- } else {
- SMUX_DBG("%s: can not tx with power state %d\n",
- __func__,
- smux.power_state);
- spin_unlock_irqrestore(&smux.tx_lock_lha2,
- flags);
- }
+ if (smux.power_state != SMUX_PWR_ON) {
+ /* channel not ready to transmit */
+ SMUX_DBG("%s: can not tx with power state %d\n",
+ __func__,
+ smux.power_state);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
break;
}
@@ -2355,30 +2778,7 @@
/* Purge TX queue */
spin_lock(&ch->tx_lock_lhb2);
- while (!list_empty(&ch->tx_queue)) {
- pkt = list_first_entry(&ch->tx_queue, struct smux_pkt_t,
- list);
- list_del(&pkt->list);
-
- if (pkt->hdr.cmd == SMUX_CMD_OPEN_LCH) {
- /* Open was never sent, just force to closed state */
- union notifier_metadata meta_disconnected;
-
- ch->local_state = SMUX_LCH_LOCAL_CLOSED;
- meta_disconnected.disconnected.is_ssr = 0;
- schedule_notify(lcid, SMUX_DISCONNECTED,
- &meta_disconnected);
- } else if (pkt->hdr.cmd == SMUX_CMD_DATA) {
- /* Notify client of failed write */
- union notifier_metadata meta_write;
-
- meta_write.write.pkt_priv = pkt->priv;
- meta_write.write.buffer = pkt->payload;
- meta_write.write.len = pkt->hdr.payload_len;
- schedule_notify(ch->lcid, SMUX_WRITE_FAIL, &meta_write);
- }
- smux_free_pkt(pkt);
- }
+ smux_purge_ch_tx_queue(ch);
spin_unlock(&ch->tx_lock_lhb2);
/* Send Close Command */
@@ -2402,6 +2802,10 @@
pr_err("%s: pkt allocation failed\n", __func__);
ret = -ENOMEM;
}
+
+ /* Purge RX retry queue */
+ if (ch->rx_retry_queue_cnt)
+ queue_delayed_work(smux_rx_wq, &ch->rx_retry_work, 0);
}
spin_unlock_irqrestore(&ch->state_lock_lhb1, flags);
@@ -2700,8 +3104,74 @@
}
/**********************************************************************/
+/* Subsystem Restart */
+/**********************************************************************/
+static struct notifier_block ssr_notifier = {
+ .notifier_call = ssr_notifier_cb,
+};
+
+/**
+ * Handle Subsystem Restart (SSR) notifications.
+ *
+ * @this Pointer to ssr_notifier
+ * @code SSR Code
+ * @data Data pointer (not used)
+ */
+static int ssr_notifier_cb(struct notifier_block *this,
+ unsigned long code,
+ void *data)
+{
+ unsigned long flags;
+ int power_off_uart = 0;
+
+ if (code == SUBSYS_BEFORE_SHUTDOWN) {
+ SMUX_DBG("%s: ssr - before shutdown\n", __func__);
+ mutex_lock(&smux.mutex_lha0);
+ smux.in_reset = 1;
+ mutex_unlock(&smux.mutex_lha0);
+ return NOTIFY_DONE;
+ } else if (code != SUBSYS_AFTER_SHUTDOWN) {
+ return NOTIFY_DONE;
+ }
+ SMUX_DBG("%s: ssr - after shutdown\n", __func__);
+
+ /* Cleanup channels */
+ mutex_lock(&smux.mutex_lha0);
+ smux_lch_purge();
+ if (smux.tty)
+ tty_driver_flush_buffer(smux.tty);
+
+ /* Power-down UART */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (smux.power_state != SMUX_PWR_OFF) {
+ SMUX_PWR("%s: SSR - turning off UART\n", __func__);
+ smux.power_state = SMUX_PWR_OFF;
+ power_off_uart = 1;
+ }
+ smux.powerdown_enabled = 0;
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ if (power_off_uart)
+ smux_uart_power_off();
+
+ smux.in_reset = 0;
+ mutex_unlock(&smux.mutex_lha0);
+
+ return NOTIFY_DONE;
+}
+
+/**********************************************************************/
/* Line Discipline Interface */
/**********************************************************************/
+static void smux_pdev_release(struct device *dev)
+{
+ struct platform_device *pdev;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ SMUX_DBG("%s: releasing pdev %p '%s'\n", __func__, pdev, pdev->name);
+ memset(&pdev->dev, 0x0, sizeof(pdev->dev));
+}
+
static int smuxld_open(struct tty_struct *tty)
{
int i;
@@ -2711,66 +3181,95 @@
if (!smux.is_initialized)
return -ENODEV;
- spin_lock_irqsave(&smux.lock_lha0, flags);
+ mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count) {
pr_err("%s: %p multiple instances not supported\n",
__func__, tty);
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
+ mutex_unlock(&smux.mutex_lha0);
return -EEXIST;
}
- ++smux.ld_open_count;
if (tty->ops->write == NULL) {
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
+ pr_err("%s: tty->ops->write already NULL\n", __func__);
+ mutex_unlock(&smux.mutex_lha0);
return -EINVAL;
}
/* connect to TTY */
+ ++smux.ld_open_count;
+ smux.in_reset = 0;
smux.tty = tty;
tty->disc_data = &smux;
tty->receive_room = TTY_RECEIVE_ROOM;
tty_driver_flush_buffer(tty);
/* power-down the UART if we are idle */
- spin_lock(&smux.tx_lock_lha2);
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
if (smux.power_state == SMUX_PWR_OFF) {
- SMUX_DBG("%s: powering off uart\n", __func__);
+ SMUX_PWR("%s: powering off uart\n", __func__);
smux.power_state = SMUX_PWR_OFF_FLUSH;
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
queue_work(smux_tx_wq, &smux_inactivity_work);
} else {
- spin_unlock(&smux.tx_lock_lha2);
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
}
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
/* register platform devices */
for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+ SMUX_DBG("%s: register pdev '%s'\n",
+ __func__, smux_devs[i].name);
+ smux_devs[i].dev.release = smux_pdev_release;
tmp = platform_device_register(&smux_devs[i]);
if (tmp)
pr_err("%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
}
+ mutex_unlock(&smux.mutex_lha0);
return 0;
}
static void smuxld_close(struct tty_struct *tty)
{
unsigned long flags;
+ int power_up_uart = 0;
int i;
- spin_lock_irqsave(&smux.lock_lha0, flags);
+ SMUX_DBG("%s: ldisc unload\n", __func__);
+ mutex_lock(&smux.mutex_lha0);
if (smux.ld_open_count <= 0) {
pr_err("%s: invalid ld count %d\n", __func__,
smux.ld_open_count);
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
+ mutex_unlock(&smux.mutex_lha0);
return;
}
- spin_unlock_irqrestore(&smux.lock_lha0, flags);
-
- for (i = 0; i < ARRAY_SIZE(smux_devs); ++i)
- platform_device_unregister(&smux_devs[i]);
-
+ smux.in_reset = 1;
--smux.ld_open_count;
+
+ /* Cleanup channels */
+ smux_lch_purge();
+
+ /* Unregister platform devices */
+ for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+ SMUX_DBG("%s: unregister pdev '%s'\n",
+ __func__, smux_devs[i].name);
+ platform_device_unregister(&smux_devs[i]);
+ }
+
+ /* Schedule UART power-up if it's down */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (smux.power_state == SMUX_PWR_OFF)
+ power_up_uart = 1;
+ smux.power_state = SMUX_PWR_OFF;
+ smux.powerdown_enabled = 0;
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ if (power_up_uart)
+ smux_uart_power_on();
+
+ /* Disconnect from TTY */
+ smux.tty = NULL;
+ mutex_unlock(&smux.mutex_lha0);
+ SMUX_DBG("%s: ldisc complete\n", __func__);
}
/**
@@ -2879,13 +3378,14 @@
{
int ret;
- spin_lock_init(&smux.lock_lha0);
+ mutex_init(&smux.mutex_lha0);
spin_lock_init(&smux.rx_lock_lha1);
smux.rx_state = SMUX_RX_IDLE;
smux.power_state = SMUX_PWR_OFF;
smux.pwr_wakeup_delay_us = 1;
smux.powerdown_enabled = 0;
+ INIT_LIST_HEAD(&smux.power_queue);
smux.rx_activity_flag = 0;
smux.tx_activity_flag = 0;
smux.recv_len = 0;
@@ -2905,6 +3405,8 @@
return ret;
}
+ subsys_notif_register_notifier("external_modem", &ssr_notifier);
+
ret = lch_init();
if (ret != 0) {
pr_err("%s: lch_init failed\n", __func__);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 59104ed..5735534 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -628,8 +628,8 @@
break;
}
- /* Set timeout to be ~100x the character transmit time */
- msm_hsl_port->tx_timeout = 1000000000 / baud;
+ /* Set timeout to be ~600x the character transmit time */
+ msm_hsl_port->tx_timeout = (1000000000 / baud) * 6;
vid = msm_hsl_port->ver_id;
msm_hsl_write(port, baud_code, regmap[vid][UARTDM_CSR]);
@@ -1220,6 +1220,9 @@
msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
msm_hsl_write(port, UARTDM_CR_TX_EN_BMSK, regmap[vid][UARTDM_CR]);
+ msm_hsl_write(port, 1, regmap[vid][UARTDM_NCF_TX]);
+ msm_hsl_read(port, regmap[vid][UARTDM_NCF_TX]);
+
printk(KERN_INFO "msm_serial_hsl: console setup on port #%d\n",
port->line);
diff --git a/drivers/tty/smux_loopback.c b/drivers/tty/smux_loopback.c
index bf6d50b..c4374bb 100644
--- a/drivers/tty/smux_loopback.c
+++ b/drivers/tty/smux_loopback.c
@@ -174,13 +174,15 @@
}
lcid = pkt->hdr.lcid;
- if (smux_assert_lch_id(lcid)) {
- pr_err("%s: invalid channel id %d\n", __func__, lcid);
- return;
- }
switch (pkt->hdr.cmd) {
case SMUX_CMD_OPEN_LCH:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
break;
@@ -207,6 +209,12 @@
break;
case SMUX_CMD_CLOSE_LCH:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
if (pkt->hdr.flags == SMUX_CMD_CLOSE_ACK)
break;
@@ -232,6 +240,12 @@
break;
case SMUX_CMD_DATA:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
/* Echo back received data */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
@@ -245,6 +259,12 @@
break;
case SMUX_CMD_STATUS:
+ if (smux_assert_lch_id(lcid)) {
+ pr_err("%s: invalid channel id %d\n",
+ __func__, lcid);
+ break;
+ }
+
/* Echo back received status */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
@@ -260,7 +280,7 @@
case SMUX_CMD_PWR_CTL:
/* reply with ack */
smux_init_pkt(&reply_pkt);
- reply_pkt.hdr.lcid = lcid;
+ reply_pkt.hdr.lcid = SMUX_BROADCAST_LCID;
reply_pkt.hdr.cmd = SMUX_CMD_PWR_CTL;
reply_pkt.hdr.flags = SMUX_CMD_PWR_CTL_ACK;
reply_pkt.hdr.payload_len = 0;
diff --git a/drivers/tty/smux_private.h b/drivers/tty/smux_private.h
index 6bd9713..f644ff0 100644
--- a/drivers/tty/smux_private.h
+++ b/drivers/tty/smux_private.h
@@ -16,6 +16,7 @@
#define SMUX_PRIVATE_H
#define SMUX_MAX_PKT_SIZE 8192
+#define SMUX_BROADCAST_LCID 0xFF
/* SMUX Protocol Characters */
#define SMUX_MAGIC 0x33FC
@@ -29,6 +30,9 @@
#define SMUX_UT_ECHO_ACK_OK 0xF1
#define SMUX_UT_ECHO_ACK_FAIL 0xF2
+/* Maximum number of packets in retry queue */
+#define SMUX_RX_RETRY_MAX_PKTS 32
+
struct tty_struct;
/* Packet header. */
diff --git a/drivers/tty/smux_test.c b/drivers/tty/smux_test.c
index 242c66e..62e9465 100644
--- a/drivers/tty/smux_test.c
+++ b/drivers/tty/smux_test.c
@@ -75,9 +75,44 @@
} \
do {} while (0)
+/**
+ * In-range unit test assertion for test cases.
+ *
+ * @a lval
+ * @minv Minimum value
+ * @maxv Maximum value
+ *
+ * Assertion fails if @a is not on the exclusive range minv, maxv
+ * ((@a < @minv) or (@a > @maxv)). In the failure case, the macro
+ * logs the function and line number where the error occurred along
+ * with the values of @a and @minv, @maxv.
+ *
+ * Assumes that the following local variables exist:
+ * @buf - buffer to write failure message to
+ * @i - number of bytes written to buffer
+ * @max - maximum size of the buffer
+ * @failed - set to true if test fails
+ */
+#define UT_ASSERT_INT_IN_RANGE(a, minv, maxv) \
+ if (((a) < (minv)) || ((a) > (maxv))) { \
+ i += scnprintf(buf + i, max - i, \
+ "%s:%d Fail: " #a "(%d) < " #minv "(%d) or " \
+ #a "(%d) > " #maxv "(%d)\n", \
+ __func__, __LINE__, \
+ a, minv, a, maxv); \
+ failed = 1; \
+ break; \
+ } \
+ do {} while (0)
+
+
static unsigned char test_array[] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55,
89, 144, 233};
+/* when 1, forces failure of get_rx_buffer_mock function */
+static int get_rx_buffer_mock_fail;
+
+
/* Used for mapping local to remote TIOCM signals */
struct tiocm_test_vector {
uint32_t input;
@@ -93,7 +128,7 @@
{
void *rx_buf;
- rx_buf = kmalloc(size, GFP_ATOMIC);
+ rx_buf = kmalloc(size, GFP_KERNEL);
*pkt_priv = (void *)0x1234;
*buffer = rx_buf;
@@ -118,6 +153,13 @@
struct smux_meta_write meta;
};
+/* Mock object metadata for get_rx_buffer failure event */
+struct mock_get_rx_buff_event {
+ struct list_head list;
+ int size;
+ unsigned long jiffies;
+};
+
/* Mock object for all SMUX callback events */
struct smux_mock_callback {
int cb_count;
@@ -140,6 +182,10 @@
int event_read_failed;
struct list_head read_events;
+ /* read retry data */
+ int get_rx_buff_retry_count;
+ struct list_head get_rx_buff_retry_events;
+
/* write event data */
int event_write_done;
int event_write_failed;
@@ -156,6 +202,7 @@
init_completion(&cb->cb_completion);
spin_lock_init(&cb->lock);
INIT_LIST_HEAD(&cb->read_events);
+ INIT_LIST_HEAD(&cb->get_rx_buff_retry_events);
INIT_LIST_HEAD(&cb->write_events);
}
@@ -191,6 +238,16 @@
kfree(meta);
}
+ cb->get_rx_buff_retry_count = 0;
+ while (!list_empty(&cb->get_rx_buff_retry_events)) {
+ struct mock_get_rx_buff_event *meta;
+ meta = list_first_entry(&cb->get_rx_buff_retry_events,
+ struct mock_get_rx_buff_event,
+ list);
+ list_del(&meta->list);
+ kfree(meta);
+ }
+
cb->event_write_done = 0;
cb->event_write_failed = 0;
while (!list_empty(&cb->write_events)) {
@@ -229,6 +286,8 @@
"\tevent_read_done=%d\n"
"\tevent_read_failed=%d\n"
"\tread_events=%d\n"
+ "\tget_rx_retry=%d\n"
+ "\tget_rx_retry_events=%d\n"
"\tevent_write_done=%d\n"
"\tevent_write_failed=%d\n"
"\twrite_events=%d\n",
@@ -243,6 +302,8 @@
cb->event_read_done,
cb->event_read_failed,
!list_empty(&cb->read_events),
+ cb->get_rx_buff_retry_count,
+ !list_empty(&cb->get_rx_buff_retry_events),
cb->event_write_done,
cb->event_write_failed,
list_empty(&cb->write_events)
@@ -268,83 +329,105 @@
return;
}
- spin_lock_irqsave(&cb_data_ptr->lock, flags);
switch (event) {
case SMUX_CONNECTED:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_connected;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_DISCONNECTED:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_disconnected;
cb_data_ptr->event_disconnected_ssr =
((struct smux_meta_disconnected *)metadata)->is_ssr;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_READ_DONE:
- ++cb_data_ptr->event_read_done;
read_event_meta = kmalloc(sizeof(struct mock_read_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_read_done;
if (read_event_meta) {
read_event_meta->meta =
*(struct smux_meta_read *)metadata;
list_add_tail(&read_event_meta->list,
&cb_data_ptr->read_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_READ_FAIL:
- ++cb_data_ptr->event_read_failed;
read_event_meta = kmalloc(sizeof(struct mock_read_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_read_failed;
if (read_event_meta) {
- read_event_meta->meta =
+ if (metadata)
+ read_event_meta->meta =
*(struct smux_meta_read *)metadata;
+ else
+ memset(&read_event_meta->meta, 0x0,
+ sizeof(struct smux_meta_read));
list_add_tail(&read_event_meta->list,
&cb_data_ptr->read_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_WRITE_DONE:
- ++cb_data_ptr->event_write_done;
write_event_meta = kmalloc(sizeof(struct mock_write_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_write_done;
if (write_event_meta) {
write_event_meta->meta =
*(struct smux_meta_write *)metadata;
list_add_tail(&write_event_meta->list,
&cb_data_ptr->write_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_WRITE_FAIL:
- ++cb_data_ptr->event_write_failed;
write_event_meta = kmalloc(sizeof(struct mock_write_event),
- GFP_ATOMIC);
+ GFP_KERNEL);
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
+ ++cb_data_ptr->event_write_failed;
if (write_event_meta) {
write_event_meta->meta =
*(struct smux_meta_write *)metadata;
list_add_tail(&write_event_meta->list,
&cb_data_ptr->write_events);
}
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_LOW_WM_HIT:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_low_wm;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_HIGH_WM_HIT:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_high_wm;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
case SMUX_TIOCM_UPDATE:
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->event_tiocm;
cb_data_ptr->tiocm_meta = *(struct smux_meta_tiocm *)metadata;
+ spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
break;
default:
pr_err("%s: unknown event %d\n", __func__, event);
};
+ spin_lock_irqsave(&cb_data_ptr->lock, flags);
++cb_data_ptr->cb_count;
complete(&cb_data_ptr->cb_completion);
spin_unlock_irqrestore(&cb_data_ptr->lock, flags);
@@ -1153,6 +1236,338 @@
return i;
}
+/**
+ * Allocates a new buffer or returns a failure based upon the
+ * global @get_rx_buffer_mock_fail.
+ */
+static int get_rx_buffer_mock(void *priv, void **pkt_priv,
+ void **buffer, int size)
+{
+ void *rx_buf;
+ unsigned long flags;
+ struct smux_mock_callback *cb_ptr;
+
+ cb_ptr = (struct smux_mock_callback *)priv;
+ if (!cb_ptr) {
+ pr_err("%s: no callback data\n", __func__);
+ return -ENXIO;
+ }
+
+ if (get_rx_buffer_mock_fail) {
+ /* force failure and log failure event */
+ struct mock_get_rx_buff_event *meta;
+ meta = kmalloc(sizeof(struct mock_get_rx_buff_event),
+ GFP_KERNEL);
+ if (!meta) {
+ pr_err("%s: unable to allocate metadata\n", __func__);
+ return -ENOMEM;
+ }
+ INIT_LIST_HEAD(&meta->list);
+ meta->size = size;
+ meta->jiffies = jiffies;
+
+ spin_lock_irqsave(&cb_ptr->lock, flags);
+ ++cb_ptr->get_rx_buff_retry_count;
+ list_add_tail(&meta->list, &cb_ptr->get_rx_buff_retry_events);
+ ++cb_ptr->cb_count;
+ complete(&cb_ptr->cb_completion);
+ spin_unlock_irqrestore(&cb_ptr->lock, flags);
+ return -EAGAIN;
+ } else {
+ rx_buf = kmalloc(size, GFP_KERNEL);
+ *pkt_priv = (void *)0x1234;
+ *buffer = rx_buf;
+ return 0;
+ }
+ return 0;
+}
+
+/**
+ * Verify get_rx_buffer callback retry.
+ *
+ * @buf Buffer for status message
+ * @max Size of buffer
+ *
+ * @returns Number of bytes written to @buf
+ */
+static int smux_ut_local_get_rx_buff_retry(char *buf, int max)
+{
+ static struct smux_mock_callback cb_data;
+ static int cb_initialized;
+ int i = 0;
+ int failed = 0;
+ char try_two[] = "try 2";
+ int ret;
+ unsigned long start_j;
+ struct mock_get_rx_buff_event *event;
+ struct mock_read_event *read_event;
+ int try;
+
+ i += scnprintf(buf + i, max - i, "Running %s\n", __func__);
+ pr_err("%s", buf);
+
+ if (!cb_initialized)
+ mock_cb_data_init(&cb_data);
+
+ mock_cb_data_reset(&cb_data);
+ smux_byte_loopback = SMUX_TEST_LCID;
+ while (!failed) {
+ /* open port for loopback */
+ ret = msm_smux_set_ch_option(SMUX_TEST_LCID,
+ SMUX_CH_OPTION_LOCAL_LOOPBACK,
+ 0);
+ UT_ASSERT_INT(ret, ==, 0);
+
+ ret = msm_smux_open(SMUX_TEST_LCID, &cb_data,
+ smux_mock_cb, get_rx_buffer_mock);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ), >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_connected, ==, 1);
+ mock_cb_data_reset(&cb_data);
+
+ /*
+ * Force get_rx_buffer failure for a single RX packet
+ *
+ * The get_rx_buffer calls should follow an exponential
+ * back-off with a maximum timeout of 1024 ms after which we
+ * will get a failure notification.
+ *
+ * Try Post Delay (ms)
+ * 0 -
+ * 1 1
+ * 2 2
+ * 3 4
+ * 4 8
+ * 5 16
+ * 6 32
+ * 7 64
+ * 8 128
+ * 9 256
+ * 10 512
+ * 11 1024
+ * 12 Fail
+ *
+ * All times are limited by the precision of the timer
+ * framework, so ranges are used in the test
+ * verification.
+ */
+ get_rx_buffer_mock_fail = 1;
+ start_j = jiffies;
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)2,
+ try_two, sizeof(try_two));
+ UT_ASSERT_INT(ret, ==, 0);
+
+ /* wait for RX failure event */
+ while (cb_data.event_read_failed == 0) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 2*HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ if (failed)
+ break;
+
+ /* verify retry attempts */
+ UT_ASSERT_INT(cb_data.get_rx_buff_retry_count, ==, 12);
+ event = list_first_entry(&cb_data.get_rx_buff_retry_events,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 0, 0 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 1, 1 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 2, 2 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 4, 4 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 8, 8 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 16, 16 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 32 - 20, 32 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 64 - 20, 64 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 128 - 20, 128 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 256 - 20, 256 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 512 - 20, 512 + 20);
+ start_j = event->jiffies;
+
+ event = list_first_entry(&event->list,
+ struct mock_get_rx_buff_event, list);
+ pr_err("%s: event->jiffies = %d (ms)\n", __func__,
+ jiffies_to_msecs(event->jiffies - start_j));
+ UT_ASSERT_INT_IN_RANGE(
+ jiffies_to_msecs(event->jiffies - start_j),
+ 1024 - 20, 1024 + 20);
+ mock_cb_data_reset(&cb_data);
+
+ /* verify 2nd pending RX packet goes through */
+ get_rx_buffer_mock_fail = 0;
+ INIT_COMPLETION(cb_data.cb_completion);
+ if (cb_data.event_read_done == 0)
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.event_read_done, ==, 1);
+ UT_ASSERT_INT(list_empty(&cb_data.read_events), ==, 0);
+ read_event = list_first_entry(&cb_data.read_events,
+ struct mock_read_event, list);
+ UT_ASSERT_PTR(read_event->meta.pkt_priv, ==, (void *)0x1234);
+ UT_ASSERT_PTR(read_event->meta.buffer, !=, NULL);
+ UT_ASSERT_INT(0, ==, memcmp(read_event->meta.buffer, try_two,
+ sizeof(try_two)));
+ mock_cb_data_reset(&cb_data);
+
+ /* Test maximum retry queue size */
+ get_rx_buffer_mock_fail = 1;
+ for (try = 0; try < (SMUX_RX_RETRY_MAX_PKTS + 1); ++try) {
+ mock_cb_data_reset(&cb_data);
+ ret = msm_smux_write(SMUX_TEST_LCID, (void *)1,
+ test_array, sizeof(test_array));
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ }
+
+ /* should have 32 successful rx packets and 1 failed */
+ while (cb_data.event_read_failed == 0) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 2*HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ if (failed)
+ break;
+
+ get_rx_buffer_mock_fail = 0;
+ while (cb_data.event_read_done < SMUX_RX_RETRY_MAX_PKTS) {
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, 2*HZ),
+ >, 0);
+ INIT_COMPLETION(cb_data.cb_completion);
+ }
+ if (failed)
+ break;
+
+ UT_ASSERT_INT(1, ==, cb_data.event_read_failed);
+ UT_ASSERT_INT(SMUX_RX_RETRY_MAX_PKTS, ==,
+ cb_data.event_read_done);
+ mock_cb_data_reset(&cb_data);
+
+ /* close port */
+ ret = msm_smux_close(SMUX_TEST_LCID);
+ UT_ASSERT_INT(ret, ==, 0);
+ UT_ASSERT_INT(
+ (int)wait_for_completion_timeout(
+ &cb_data.cb_completion, HZ),
+ >, 0);
+ UT_ASSERT_INT(cb_data.cb_count, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected, ==, 1);
+ UT_ASSERT_INT(cb_data.event_disconnected_ssr, ==, 0);
+ break;
+ }
+
+ if (!failed) {
+ i += scnprintf(buf + i, max - i, "\tOK\n");
+ } else {
+ pr_err("%s: Failed\n", __func__);
+ i += scnprintf(buf + i, max - i, "\tFailed\n");
+ i += mock_cb_data_print(&cb_data, buf + i, max - i);
+ msm_smux_close(SMUX_TEST_LCID);
+ }
+ smux_byte_loopback = 0;
+ mock_cb_data_reset(&cb_data);
+ return i;
+}
+
static char debug_buffer[DEBUG_BUFMAX];
static ssize_t debug_read(struct file *file, char __user *buf,
@@ -1214,6 +1629,8 @@
debug_create("ut_local_wm", 0444, dent, smux_ut_local_wm);
debug_create("ut_local_smuxld_receive_buf", 0444, dent,
smux_ut_local_smuxld_receive_buf);
+ debug_create("ut_local_get_rx_buff_retry", 0444, dent,
+ smux_ut_local_get_rx_buff_retry);
return 0;
}
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index d8f741f..882eb97 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,9 +1,8 @@
config USB_DWC3
tristate "DesignWare USB3 DRD Core Support"
- depends on (USB && USB_GADGET)
+ depends on (USB || USB_GADGET)
select USB_OTG_UTILS
select USB_GADGET_DUALSPEED
- select USB_GADGET_SUPERSPEED
select USB_XHCI_PLATFORM
help
Say Y or M here if your system has a Dual Role SuperSpeed
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 3227508..0b46082 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -1,11 +1,13 @@
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
+ccflags-y += -Idrivers/usb/host
obj-$(CONFIG_USB_DWC3) += dwc3.o
dwc3-y := core.o
dwc3-y += host.o
dwc3-y += gadget.o ep0.o
+dwc3-y += dwc3_otg.o
ifneq ($(CONFIG_DEBUG_FS),)
dwc3-y += debugfs.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 99b58d8..1fbfdd8 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -372,6 +372,32 @@
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ /*
+ * Currently, the default and the recommended value for GUSB3PIPECTL
+ * [21:19] in the RTL is 3'b100 or 32 consecutive errors. Based on
+ * analysis and experiments in the lab, it is found that there is a
+ * relatively low probability of getting 32 consecutive word errors
+ * in the presence of random recovered noise (during electrical idle).
+ * This can delay the entry to a low power state such that for
+ * applications where the link stays in a non-U0 state for a short
+ * duration (< 1 microsecond), the local PHY does not enter the low
+ * power state prior to receiving a potential LFPS wakeup. This causes
+ * the PHY CDR (Clock and Data Recovery) operation to be unstable for
+ * some Synopsys PHYs.
+ *
+ * The proposal now is to change the default and the recommended value
+ * for GUSB3PIPECTL[21:19] in the RTL from 3'b100 to a minimum of
+ * 3'b001. Perform the same in software for controllers prior to 2.30a
+ * revision.
+ */
+
+ if (dwc->revision < DWC3_REVISION_230A) {
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg &= ~DWC3_GUSB3PIPECTL_DELAY_P1P2P3;
+ reg |= 1 << __ffs(DWC3_GUSB3PIPECTL_DELAY_P1P2P3);
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+ }
+
ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
if (ret) {
dev_err(dwc->dev, "failed to allocate event buffers\n");
@@ -410,7 +436,6 @@
struct device *dev = &pdev->dev;
int ret = -ENOMEM;
- int irq;
void __iomem *regs;
void *mem;
@@ -425,16 +450,30 @@
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
- dev_err(dev, "missing resource\n");
+ dev_err(dev, "missing IRQ\n");
return -ENODEV;
}
+ dwc->xhci_resources[1] = *res;
- dwc->res = res;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "missing memory resource\n");
+ return -ENODEV;
+ }
+ dwc->xhci_resources[0] = *res;
+ dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
+ DWC3_XHCI_REGS_END;
- res = devm_request_mem_region(dev, res->start, resource_size(res),
+ /*
+ * Request memory region but exclude xHCI regs,
+ * since it will be requested by the xhci-plat driver.
+ */
+ res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START,
+ resource_size(res) - DWC3_GLOBALS_REGS_START,
dev_name(dev));
+
if (!res) {
dev_err(dev, "can't request mem region\n");
return -ENOMEM;
@@ -446,19 +485,12 @@
return -ENOMEM;
}
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "missing IRQ\n");
- return -ENODEV;
- }
-
spin_lock_init(&dwc->lock);
platform_set_drvdata(pdev, dwc);
dwc->regs = regs;
dwc->regs_size = resource_size(res);
dwc->dev = dev;
- dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
@@ -505,15 +537,24 @@
break;
case DWC3_MODE_DRD:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+ ret = dwc3_otg_init(dwc);
+ if (ret) {
+ dev_err(dev, "failed to initialize otg\n");
+ goto err1;
+ }
+
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize host\n");
+ dwc3_otg_exit(dwc);
goto err1;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
dev_err(dev, "failed to initialize gadget\n");
+ dwc3_host_exit(dwc);
+ dwc3_otg_exit(dwc);
goto err1;
}
break;
@@ -542,8 +583,9 @@
dwc3_host_exit(dwc);
break;
case DWC3_MODE_DRD:
- dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
+ dwc3_host_exit(dwc);
+ dwc3_otg_exit(dwc);
break;
default:
/* do nothing */
@@ -576,8 +618,9 @@
dwc3_host_exit(dwc);
break;
case DWC3_MODE_DRD:
- dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
+ dwc3_host_exit(dwc);
+ dwc3_otg_exit(dwc);
break;
default:
/* do nothing */
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 6c7945b..98adff7 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -50,10 +50,13 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include "dwc3_otg.h"
+
/* Global constants */
#define DWC3_ENDPOINTS_NUM 32
+#define DWC3_XHCI_RESOURCES_NUM 2
-#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
+#define DWC3_EVENT_BUFFERS_SIZE (2 * PAGE_SIZE)
#define DWC3_EVENT_TYPE_MASK 0xfe
#define DWC3_EVENT_TYPE_DEV 0
@@ -70,11 +73,22 @@
#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9
#define DWC3_DEVICE_EVENT_CMD_CMPL 10
#define DWC3_DEVICE_EVENT_OVERFLOW 11
+#define DWC3_DEVICE_EVENT_VENDOR_DEV_TEST_LMP 12
#define DWC3_GEVNTCOUNT_MASK 0xfffc
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
+/* DWC3 registers memory space boundries */
+#define DWC3_XHCI_REGS_START 0x0
+#define DWC3_XHCI_REGS_END 0x7fff
+#define DWC3_GLOBALS_REGS_START 0xc100
+#define DWC3_GLOBALS_REGS_END 0xc6ff
+#define DWC3_DEVICE_REGS_START 0xc700
+#define DWC3_DEVICE_REGS_END 0xcbff
+#define DWC3_OTG_REGS_START 0xcc00
+#define DWC3_OTG_REGS_END 0xccff
+
/* Global Registers */
#define DWC3_GSBUSCFG0 0xc100
#define DWC3_GSBUSCFG1 0xc104
@@ -139,8 +153,9 @@
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
-#define DWC3_OEVTEN 0xcc08
-#define DWC3_OSTS 0xcc0C
+#define DWC3_OEVT 0xcc08
+#define DWC3_OEVTEN 0xcc0c
+#define DWC3_OSTS 0xcc10
/* Bit fields */
@@ -172,6 +187,7 @@
/* Global USB3 PIPE Control Register */
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+#define DWC3_GUSB3PIPECTL_DELAY_P1P2P3 (7 << 19)
/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
@@ -182,6 +198,9 @@
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
+/* Global HWPARAMS6 Register */
+#define DWC3_GHWPARAMS6_SRP_SUPPORT (1 << 10)
+
/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
@@ -300,6 +319,37 @@
#define DWC3_DEPCMD_TYPE_BULK 2
#define DWC3_DEPCMD_TYPE_INTR 3
+/* OTG Events Register */
+#define DWC3_OEVT_DEVICEMODE (1 << 31)
+#define DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT (1 << 24)
+#define DWC3_OEVTEN_OTGADEVBHOSTENDEVNT (1 << 20)
+#define DWC3_OEVTEN_OTGADEVHOSTEVNT (1 << 19)
+#define DWC3_OEVTEN_OTGADEVHNPCHNGEVNT (1 << 18)
+#define DWC3_OEVTEN_OTGADEVSRPDETEVNT (1 << 17)
+#define DWC3_OEVTEN_OTGADEVSESSENDDETEVNT (1 << 16)
+#define DWC3_OEVTEN_OTGBDEVBHOSTENDEVNT (1 << 11)
+#define DWC3_OEVTEN_OTGBDEVHNPCHNGEVNT (1 << 10)
+#define DWC3_OEVTEN_OTGBDEVSESSVLDDETEVNT (1 << 9)
+#define DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT (1 << 8)
+
+/* OTG OSTS register */
+#define DWC3_OTG_OSTS_OTGSTATE_SHIFT (8)
+#define DWC3_OTG_OSTS_OTGSTATE (0xF << DWC3_OTG_OSTS_OTGSTATE_SHIFT)
+#define DWC3_OTG_OSTS_PERIPHERALSTATE (1 << 4)
+#define DWC3_OTG_OSTS_XHCIPRTPOWER (1 << 3)
+#define DWC3_OTG_OSTS_BSESVALID (1 << 2)
+#define DWC3_OTG_OSTS_VBUSVALID (1 << 1)
+#define DWC3_OTG_OSTS_CONIDSTS (1 << 0)
+
+/* OTG OSTS register */
+#define DWC3_OTG_OCTL_PERIMODE (1 << 6)
+#define DWC3_OTG_OCTL_PRTPWRCTL (1 << 5)
+#define DWC3_OTG_OCTL_HNPREQ (1 << 4)
+#define DWC3_OTG_OCTL_SESREQ (1 << 3)
+#define DWC3_OTG_OCTL_TERMSELDLPULSE (1 << 2)
+#define DWC3_OTG_OCTL_DEVSETHNPEN (1 << 1)
+#define DWC3_OTG_OCTL_HSTSETHNPEN (1 << 0)
+
/* Structures */
struct dwc3_trb;
@@ -582,8 +632,9 @@
spinlock_t lock;
struct device *dev;
+ struct dwc3_otg *dotg;
struct platform_device *xhci;
- struct resource *res;
+ struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM];
struct dwc3_event_buffer **ev_buffs;
struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
@@ -594,8 +645,6 @@
void __iomem *regs;
size_t regs_size;
- int irq;
-
u32 num_event_buffers;
u32 u1u2;
u32 maximum_speed;
@@ -609,6 +658,7 @@
#define DWC3_REVISION_185A 0x5533185a
#define DWC3_REVISION_188A 0x5533188a
#define DWC3_REVISION_190A 0x5533190a
+#define DWC3_REVISION_230A 0x5533230a
unsigned is_selfpowered:1;
unsigned three_stage_setup:1;
@@ -633,6 +683,12 @@
u8 test_mode;
u8 test_mode_nr;
+
+ /* Indicate if the gadget was powered by the otg driver */
+ bool vbus_active;
+
+ /* Indicate if software connect was issued by the usb_gadget_driver */
+ bool softconnect;
};
/* -------------------------------------------------------------------------- */
@@ -772,6 +828,9 @@
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+int dwc3_otg_init(struct dwc3 *dwc);
+void dwc3_otg_exit(struct dwc3 *dwc);
+
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 4e6091e..d216f17 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/ioport.h>
+#include <linux/clk.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -26,7 +27,11 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/msm_hsusb.h>
+#include <linux/regulator/consumer.h>
+#include <mach/rpm-regulator.h>
+
+#include "dwc3_otg.h"
#include "core.h"
#include "gadget.h"
@@ -79,6 +84,22 @@
#define DBM_MAX_EPS 4
+/* DBM TRB configurations */
+#define DBM_TRB_BIT 0x80000000
+#define DBM_TRB_DATA_SRC 0x40000000
+#define DBM_TRB_DMA 0x20000000
+#define DBM_TRB_EP_NUM(ep) (ep<<24)
+/**
+ * USB QSCRATCH Hardware registers
+ *
+ */
+#define QSCRATCH_REG_OFFSET (0x000F8800)
+#define CHARGING_DET_CTRL_REG (QSCRATCH_REG_OFFSET + 0x18)
+#define CHARGING_DET_OUTPUT_REG (QSCRATCH_REG_OFFSET + 0x1C)
+#define ALT_INTERRUPT_EN_REG (QSCRATCH_REG_OFFSET + 0x20)
+#define HS_PHY_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x24)
+
+
struct dwc3_msm_req_complete {
struct list_head list_item;
struct usb_request *req;
@@ -95,9 +116,59 @@
u8 ep_num_mapping[DBM_MAX_EPS];
const struct usb_ep_ops *original_ep_ops[DWC3_ENDPOINTS_NUM];
struct list_head req_complete_list;
+ struct clk *core_clk;
+ struct regulator *hsusb_3p3;
+ struct regulator *hsusb_1p8;
+ struct regulator *hsusb_vddcx;
+ struct regulator *ssusb_1p8;
+ struct regulator *ssusb_vddcx;
+ enum usb_vdd_type ss_vdd_type;
+ enum usb_vdd_type hs_vdd_type;
+ struct dwc3_charger charger;
+ struct usb_phy *otg_xceiv;
+ struct delayed_work chg_work;
+ enum usb_chg_state chg_state;
+ u8 dcd_retries;
+};
+
+#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
+#define USB_HSPHY_3P3_VOL_MAX 3300000 /* uV */
+#define USB_HSPHY_3P3_HPM_LOAD 16000 /* uA */
+
+#define USB_HSPHY_1P8_VOL_MIN 1800000 /* uV */
+#define USB_HSPHY_1P8_VOL_MAX 1800000 /* uV */
+#define USB_HSPHY_1P8_HPM_LOAD 19000 /* uA */
+
+#define USB_SSPHY_1P8_VOL_MIN 1800000 /* uV */
+#define USB_SSPHY_1P8_VOL_MAX 1800000 /* uV */
+#define USB_SSPHY_1P8_HPM_LOAD 23000 /* uA */
+
+#define USB_PHY_VDD_DIG_VOL_NONE 0 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
+
+enum usb_vdd_value {
+ VDD_NONE = 0,
+ VDD_MIN,
+ VDD_MAX,
+ VDD_VAL_MAX,
+};
+
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+ { /* VDD_CX CORNER Voting */
+ [VDD_NONE] = RPM_VREG_CORNER_NONE,
+ [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
+ [VDD_MAX] = RPM_VREG_CORNER_HIGH,
+ },
+ { /* VDD_CX Voltage Voting */
+ [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
+ [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
+ [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
+ },
};
static struct dwc3_msm *context;
+static u64 dwc3_msm_dma_mask = DMA_BIT_MASK(64);
/**
*
@@ -169,6 +240,34 @@
}
/**
+ * Write register and read back masked value to confirm it is written
+ *
+ * @base - DWC3 base virtual address.
+ * @offset - register offset.
+ * @mask - register bitmask specifying what should be updated
+ * @val - value to write.
+ *
+ */
+static inline void dwc3_msm_write_readback(void *base, u32 offset,
+ const u32 mask, u32 val)
+{
+ u32 write_val, tmp = ioread32(base + offset);
+
+ tmp &= ~mask; /* retain other bits */
+ write_val = tmp | val;
+
+ iowrite32(write_val, base + offset);
+
+ /* Read back to see if val was written */
+ tmp = ioread32(base + offset);
+ tmp &= mask; /* clear other bits */
+
+ if (tmp != val)
+ dev_err(context->dev, "%s: write: %x to QSCRATCH: %x FAILED\n",
+ __func__, val, offset);
+}
+
+/**
* Return DBM EP number which is not already configured.
*
*/
@@ -461,19 +560,12 @@
*/
static int __dwc3_msm_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{
- struct dwc3_trb_hw *trb_hw;
- struct dwc3_trb_hw *trb_link_hw;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
+ struct dwc3_trb *trb_link;
struct dwc3_gadget_ep_cmd_params params;
u32 cmd;
int ret = 0;
- if ((req->request.udc_priv & MSM_IS_FINITE_TRANSFER) &&
- (req->request.length > 0)) {
- /* Map the request to a DMA. */
- dwc3_map_buffer_to_dma(req);
- }
-
/* We push the request to the dep->req_queued list to indicate that
* this request is issued with start transfer. The request will be out
* from this list in 2 cases. The first is that the transfer will be
@@ -485,31 +577,26 @@
list_add_tail(&req->list, &dep->req_queued);
/* First, prepare a normal TRB, point to the fake buffer */
- trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
dep->free_slot++;
- memset(&trb, 0, sizeof(trb));
+ memset(trb, 0, sizeof(*trb));
- req->trb = trb_hw;
-
- trb.bplh = req->request.dma;
- trb.lst = 0;
- trb.trbctl = DWC3_TRBCTL_NORMAL;
- trb.length = req->request.length;
- trb.hwo = true;
-
- dwc3_trb_to_hw(&trb, trb_hw);
- req->trb_dma = dep->trb_pool_dma;
+ req->trb = trb;
+ req->trb_dma = dwc3_trb_dma_offset(dep, trb);
+ trb->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+ DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+ trb->size = DWC3_TRB_SIZE_LENGTH(req->request.length);
+ trb->ctrl = DWC3_TRBCTL_NORMAL | DWC3_TRB_CTRL_HWO | DWC3_TRB_CTRL_CHN;
/* Second, prepare a Link TRB that points to the first TRB*/
- trb_link_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ trb_link = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
dep->free_slot++;
- memset(&trb, 0, sizeof(trb));
- trb.bplh = dep->trb_pool_dma;
- trb.trbctl = DWC3_TRBCTL_LINK_TRB;
- trb.hwo = true;
-
- dwc3_trb_to_hw(&trb, trb_link_hw);
+ trb_link->bpl = lower_32_bits(req->trb_dma);
+ trb_link->bph = DBM_TRB_BIT | DBM_TRB_DATA_SRC |
+ DBM_TRB_DMA | DBM_TRB_EP_NUM(dep->number);
+ trb_link->size = 0;
+ trb_link->ctrl = DWC3_TRBCTL_LINK_TRB | DWC3_TRB_CTRL_HWO;
/*
* Now start the transfer
@@ -524,7 +611,6 @@
"%s: failed to send STARTTRANSFER command\n",
__func__);
- dwc3_unmap_buffer_from_dma(req);
list_del(&req->list);
return ret;
}
@@ -750,6 +836,391 @@
}
EXPORT_SYMBOL(msm_ep_unconfig);
+/* HSPHY */
+static int dwc3_hsusb_config_vddcx(int high)
+{
+ int min_vol, ret;
+ struct dwc3_msm *dwc = context;
+ enum usb_vdd_type vdd_type = context->hs_vdd_type;
+ int max_vol = vdd_val[vdd_type][VDD_MAX];
+
+ min_vol = vdd_val[vdd_type][high ? VDD_MIN : VDD_NONE];
+ ret = regulator_set_voltage(dwc->hsusb_vddcx, min_vol, max_vol);
+ if (ret) {
+ dev_err(dwc->dev, "unable to set voltage for HSUSB_VDDCX\n");
+ return ret;
+ }
+
+ dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
+ min_vol, max_vol);
+
+ return ret;
+}
+
+static int dwc3_hsusb_ldo_init(int init)
+{
+ int rc = 0;
+ struct dwc3_msm *dwc = context;
+
+ if (!init) {
+ regulator_set_voltage(dwc->hsusb_1p8, 0, USB_HSPHY_1P8_VOL_MAX);
+ regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
+ return 0;
+ }
+
+ dwc->hsusb_3p3 = devm_regulator_get(dwc->dev, "HSUSB_3p3");
+ if (IS_ERR(dwc->hsusb_3p3)) {
+ dev_err(dwc->dev, "unable to get hsusb 3p3\n");
+ return PTR_ERR(dwc->hsusb_3p3);
+ }
+
+ rc = regulator_set_voltage(dwc->hsusb_3p3,
+ USB_HSPHY_3P3_VOL_MIN, USB_HSPHY_3P3_VOL_MAX);
+ if (rc) {
+ dev_err(dwc->dev, "unable to set voltage for hsusb 3p3\n");
+ return rc;
+ }
+ dwc->hsusb_1p8 = devm_regulator_get(dwc->dev, "HSUSB_1p8");
+ if (IS_ERR(dwc->hsusb_1p8)) {
+ dev_err(dwc->dev, "unable to get hsusb 1p8\n");
+ rc = PTR_ERR(dwc->hsusb_1p8);
+ goto devote_3p3;
+ }
+ rc = regulator_set_voltage(dwc->hsusb_1p8,
+ USB_HSPHY_1P8_VOL_MIN, USB_HSPHY_1P8_VOL_MAX);
+ if (rc) {
+ dev_err(dwc->dev, "unable to set voltage for hsusb 1p8\n");
+ goto devote_3p3;
+ }
+
+ return 0;
+
+devote_3p3:
+ regulator_set_voltage(dwc->hsusb_3p3, 0, USB_HSPHY_3P3_VOL_MAX);
+
+ return rc;
+}
+
+static int dwc3_hsusb_ldo_enable(int on)
+{
+ int rc = 0;
+ struct dwc3_msm *dwc = context;
+
+ dev_dbg(dwc->dev, "reg (%s)\n", on ? "HPM" : "LPM");
+
+ if (!on)
+ goto disable_regulators;
+
+
+ rc = regulator_set_optimum_mode(dwc->hsusb_1p8, USB_HSPHY_1P8_HPM_LOAD);
+ if (rc < 0) {
+ dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_1p8\n");
+ return rc;
+ }
+
+ rc = regulator_enable(dwc->hsusb_1p8);
+ if (rc) {
+ dev_err(dwc->dev, "Unable to enable HSUSB_1p8\n");
+ goto put_1p8_lpm;
+ }
+
+ rc = regulator_set_optimum_mode(dwc->hsusb_3p3, USB_HSPHY_3P3_HPM_LOAD);
+ if (rc < 0) {
+ dev_err(dwc->dev, "Unable to set HPM of regulator HSUSB_3p3\n");
+ goto disable_1p8;
+ }
+
+ rc = regulator_enable(dwc->hsusb_3p3);
+ if (rc) {
+ dev_err(dwc->dev, "Unable to enable HSUSB_3p3\n");
+ goto put_3p3_lpm;
+ }
+
+ return 0;
+
+disable_regulators:
+ rc = regulator_disable(dwc->hsusb_3p3);
+ if (rc)
+ dev_err(dwc->dev, "Unable to disable HSUSB_3p3\n");
+
+put_3p3_lpm:
+ rc = regulator_set_optimum_mode(dwc->hsusb_3p3, 0);
+ if (rc < 0)
+ dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_3p3\n");
+
+disable_1p8:
+ rc = regulator_disable(dwc->hsusb_1p8);
+ if (rc)
+ dev_err(dwc->dev, "Unable to disable HSUSB_1p8\n");
+
+put_1p8_lpm:
+ rc = regulator_set_optimum_mode(dwc->hsusb_1p8, 0);
+ if (rc < 0)
+ dev_err(dwc->dev, "Unable to set LPM of regulator HSUSB_1p8\n");
+
+ return rc < 0 ? rc : 0;
+}
+
+/* SSPHY */
+static int dwc3_ssusb_config_vddcx(int high)
+{
+ int min_vol, ret;
+ struct dwc3_msm *dwc = context;
+ enum usb_vdd_type vdd_type = context->ss_vdd_type;
+ int max_vol = vdd_val[vdd_type][VDD_MAX];
+
+ min_vol = vdd_val[vdd_type][high ? VDD_MIN : VDD_NONE];
+ ret = regulator_set_voltage(dwc->ssusb_vddcx, min_vol, max_vol);
+ if (ret) {
+ dev_err(dwc->dev, "unable to set voltage for SSUSB_VDDCX\n");
+ return ret;
+ }
+
+ dev_dbg(dwc->dev, "%s: min_vol:%d max_vol:%d\n", __func__,
+ min_vol, max_vol);
+ return ret;
+}
+
+/* 3.3v supply not needed for SS PHY */
+static int dwc3_ssusb_ldo_init(int init)
+{
+ int rc = 0;
+ struct dwc3_msm *dwc = context;
+
+ if (!init) {
+ regulator_set_voltage(dwc->ssusb_1p8, 0, USB_SSPHY_1P8_VOL_MAX);
+ return 0;
+ }
+
+ dwc->ssusb_1p8 = devm_regulator_get(dwc->dev, "SSUSB_1p8");
+ if (IS_ERR(dwc->ssusb_1p8)) {
+ dev_err(dwc->dev, "unable to get ssusb 1p8\n");
+ return PTR_ERR(dwc->ssusb_1p8);
+ }
+ rc = regulator_set_voltage(dwc->ssusb_1p8,
+ USB_SSPHY_1P8_VOL_MIN, USB_SSPHY_1P8_VOL_MAX);
+ if (rc)
+ dev_err(dwc->dev, "unable to set voltage for ssusb 1p8\n");
+
+ return rc;
+}
+
+static int dwc3_ssusb_ldo_enable(int on)
+{
+ int rc = 0;
+ struct dwc3_msm *dwc = context;
+
+ dev_dbg(context->dev, "reg (%s)\n", on ? "HPM" : "LPM");
+
+ if (!on)
+ goto disable_regulators;
+
+
+ rc = regulator_set_optimum_mode(dwc->ssusb_1p8, USB_SSPHY_1P8_HPM_LOAD);
+ if (rc < 0) {
+ dev_err(dwc->dev, "Unable to set HPM of SSUSB_1p8\n");
+ return rc;
+ }
+
+ rc = regulator_enable(dwc->ssusb_1p8);
+ if (rc) {
+ dev_err(dwc->dev, "Unable to enable SSUSB_1p8\n");
+ goto put_1p8_lpm;
+ }
+
+ return 0;
+
+disable_regulators:
+ rc = regulator_disable(dwc->ssusb_1p8);
+ if (rc)
+ dev_err(dwc->dev, "Unable to disable SSUSB_1p8\n");
+
+put_1p8_lpm:
+ rc = regulator_set_optimum_mode(dwc->ssusb_1p8, 0);
+ if (rc < 0)
+ dev_err(dwc->dev, "Unable to set LPM of SSUSB_1p8\n");
+
+ return rc < 0 ? rc : 0;
+}
+
+static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
+{
+ u32 chg_ctrl;
+
+ /* Turn off VDP_SRC */
+ dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
+ msleep(20);
+
+ /* Before proceeding make sure VDP_SRC is OFF */
+ chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
+ if (chg_ctrl & 0x3F)
+ dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
+ __func__, chg_ctrl);
+ /*
+ * Configure DM as current source, DP as current sink
+ * and enable battery charging comparators.
+ */
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x34);
+}
+
+static bool dwc3_chg_det_check_output(struct dwc3_msm *mdwc)
+{
+ u32 chg_det;
+ bool ret = false;
+
+ chg_det = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
+ ret = chg_det & 1;
+
+ return ret;
+}
+
+static void dwc3_chg_enable_primary_det(struct dwc3_msm *mdwc)
+{
+ /*
+ * Configure DP as current source, DM as current sink
+ * and enable battery charging comparators.
+ */
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x30);
+}
+
+static inline bool dwc3_chg_check_dcd(struct dwc3_msm *mdwc)
+{
+ u32 chg_state;
+ bool ret = false;
+
+ chg_state = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_OUTPUT_REG);
+ ret = chg_state & 2;
+
+ return ret;
+}
+
+static inline void dwc3_chg_disable_dcd(struct dwc3_msm *mdwc)
+{
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x0);
+}
+
+static inline void dwc3_chg_enable_dcd(struct dwc3_msm *mdwc)
+{
+ /* Data contact detection enable, DCDENB */
+ dwc3_msm_write_readback(mdwc->base, CHARGING_DET_CTRL_REG, 0x3F, 0x2);
+}
+
+static void dwc3_chg_block_reset(struct dwc3_msm *mdwc)
+{
+ u32 chg_ctrl;
+
+ /* Clear charger detecting control bits */
+ dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
+
+ /* Clear alt interrupt latch and enable bits */
+ dwc3_msm_write_reg(mdwc->base, HS_PHY_IRQ_STAT_REG, 0xFFF);
+ dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x0);
+
+ udelay(100);
+
+ /* Before proceeding make sure charger block is RESET */
+ chg_ctrl = dwc3_msm_read_reg(mdwc->base, CHARGING_DET_CTRL_REG);
+ if (chg_ctrl & 0x3F)
+ dev_err(mdwc->dev, "%s Unable to reset chg_det block: %x\n",
+ __func__, chg_ctrl);
+}
+
+static const char *chg_to_string(enum dwc3_chg_type chg_type)
+{
+ switch (chg_type) {
+ case USB_SDP_CHARGER: return "USB_SDP_CHARGER";
+ case USB_DCP_CHARGER: return "USB_DCP_CHARGER";
+ case USB_CDP_CHARGER: return "USB_CDP_CHARGER";
+ default: return "INVALID_CHARGER";
+ }
+}
+
+#define DWC3_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
+#define DWC3_CHG_DCD_MAX_RETRIES 6 /* Tdcd_tmout = 6 * 100 msec */
+#define DWC3_CHG_PRIMARY_DET_TIME (50 * HZ/1000) /* TVDPSRC_ON */
+#define DWC3_CHG_SECONDARY_DET_TIME (50 * HZ/1000) /* TVDMSRC_ON */
+
+static void dwc3_chg_detect_work(struct work_struct *w)
+{
+ struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm, chg_work.work);
+ bool is_dcd = false, tmout, vout;
+ unsigned long delay;
+
+ dev_dbg(mdwc->dev, "chg detection work\n");
+ switch (mdwc->chg_state) {
+ case USB_CHG_STATE_UNDEFINED:
+ dwc3_chg_block_reset(mdwc);
+ dwc3_chg_enable_dcd(mdwc);
+ mdwc->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
+ mdwc->dcd_retries = 0;
+ delay = DWC3_CHG_DCD_POLL_TIME;
+ break;
+ case USB_CHG_STATE_WAIT_FOR_DCD:
+ is_dcd = dwc3_chg_check_dcd(mdwc);
+ tmout = ++mdwc->dcd_retries == DWC3_CHG_DCD_MAX_RETRIES;
+ if (is_dcd || tmout) {
+ dwc3_chg_disable_dcd(mdwc);
+ dwc3_chg_enable_primary_det(mdwc);
+ delay = DWC3_CHG_PRIMARY_DET_TIME;
+ mdwc->chg_state = USB_CHG_STATE_DCD_DONE;
+ } else {
+ delay = DWC3_CHG_DCD_POLL_TIME;
+ }
+ break;
+ case USB_CHG_STATE_DCD_DONE:
+ vout = dwc3_chg_det_check_output(mdwc);
+ if (vout) {
+ dwc3_chg_enable_secondary_det(mdwc);
+ delay = DWC3_CHG_SECONDARY_DET_TIME;
+ mdwc->chg_state = USB_CHG_STATE_PRIMARY_DONE;
+ } else {
+ mdwc->charger.chg_type = USB_SDP_CHARGER;
+ mdwc->chg_state = USB_CHG_STATE_DETECTED;
+ delay = 0;
+ }
+ break;
+ case USB_CHG_STATE_PRIMARY_DONE:
+ vout = dwc3_chg_det_check_output(mdwc);
+ if (vout)
+ mdwc->charger.chg_type = USB_DCP_CHARGER;
+ else
+ mdwc->charger.chg_type = USB_CDP_CHARGER;
+ mdwc->chg_state = USB_CHG_STATE_SECONDARY_DONE;
+ /* fall through */
+ case USB_CHG_STATE_SECONDARY_DONE:
+ mdwc->chg_state = USB_CHG_STATE_DETECTED;
+ /* fall through */
+ case USB_CHG_STATE_DETECTED:
+ dwc3_chg_block_reset(mdwc);
+ dev_dbg(mdwc->dev, "chg_type = %s\n",
+ chg_to_string(mdwc->charger.chg_type));
+ mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
+ &mdwc->charger);
+ return;
+ default:
+ return;
+ }
+
+ queue_delayed_work(system_nrt_wq, &mdwc->chg_work, delay);
+}
+
+static void dwc3_start_chg_det(struct dwc3_charger *charger, bool start)
+{
+ struct dwc3_msm *mdwc = context;
+
+ if (start == false) {
+ cancel_delayed_work_sync(&mdwc->chg_work);
+ mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
+ charger->chg_type = DWC3_INVALID_CHARGER;
+ return;
+ }
+
+ mdwc->chg_state = USB_CHG_STATE_UNDEFINED;
+ charger->chg_type = DWC3_INVALID_CHARGER;
+ queue_delayed_work(system_nrt_wq, &mdwc->chg_work, 0);
+}
+
+
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -766,35 +1237,128 @@
platform_set_drvdata(pdev, msm);
context = msm;
+ msm->dev = &pdev->dev;
INIT_LIST_HEAD(&msm->req_complete_list);
+ INIT_DELAYED_WORK(&msm->chg_work, dwc3_chg_detect_work);
+
+ /*
+ * DWC3 Core requires its CORE CLK (aka master / bus clk) to
+ * run at 125Mhz in SSUSB mode and >60MHZ for HSUSB mode.
+ */
+ msm->core_clk = devm_clk_get(&pdev->dev, "core_clk");
+ if (IS_ERR(msm->core_clk)) {
+ dev_err(&pdev->dev, "failed to get core_clk\n");
+ return PTR_ERR(msm->core_clk);
+ }
+ clk_set_rate(msm->core_clk, 125000000);
+ clk_prepare_enable(msm->core_clk);
+
+ /* SS PHY */
+ msm->ss_vdd_type = VDDCX_CORNER;
+ msm->ssusb_vddcx = devm_regulator_get(&pdev->dev, "ssusb_vdd_dig");
+ if (IS_ERR(msm->ssusb_vddcx)) {
+ msm->ssusb_vddcx = devm_regulator_get(&pdev->dev,
+ "SSUSB_VDDCX");
+ if (IS_ERR(msm->ssusb_vddcx)) {
+ dev_err(&pdev->dev, "unable to get ssusb vddcx\n");
+ ret = PTR_ERR(msm->ssusb_vddcx);
+ goto disable_core_clk;
+ }
+ msm->ss_vdd_type = VDDCX;
+ dev_dbg(&pdev->dev, "ss_vdd_type: VDDCX\n");
+ }
+
+ ret = dwc3_ssusb_config_vddcx(1);
+ if (ret) {
+ dev_err(&pdev->dev, "ssusb vddcx configuration failed\n");
+ goto disable_core_clk;
+ }
+
+ ret = regulator_enable(context->ssusb_vddcx);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable the ssusb vddcx\n");
+ goto unconfig_ss_vddcx;
+ }
+
+ ret = dwc3_ssusb_ldo_init(1);
+ if (ret) {
+ dev_err(&pdev->dev, "ssusb vreg configuration failed\n");
+ goto disable_ss_vddcx;
+ }
+
+ ret = dwc3_ssusb_ldo_enable(1);
+ if (ret) {
+ dev_err(&pdev->dev, "ssusb vreg enable failed\n");
+ goto free_ss_ldo_init;
+ }
+
+ /* HS PHY */
+ msm->hs_vdd_type = VDDCX_CORNER;
+ msm->hsusb_vddcx = devm_regulator_get(&pdev->dev, "hsusb_vdd_dig");
+ if (IS_ERR(msm->hsusb_vddcx)) {
+ msm->hsusb_vddcx = devm_regulator_get(&pdev->dev,
+ "HSUSB_VDDCX");
+ if (IS_ERR(msm->hsusb_vddcx)) {
+ dev_err(&pdev->dev, "unable to get hsusb vddcx\n");
+ ret = PTR_ERR(msm->ssusb_vddcx);
+ goto disable_ss_ldo;
+ }
+ msm->hs_vdd_type = VDDCX;
+ dev_dbg(&pdev->dev, "hs_vdd_type: VDDCX\n");
+ }
+
+ ret = dwc3_hsusb_config_vddcx(1);
+ if (ret) {
+ dev_err(&pdev->dev, "hsusb vddcx configuration failed\n");
+ goto disable_ss_ldo;
+ }
+
+ ret = regulator_enable(context->hsusb_vddcx);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable the hsusb vddcx\n");
+ goto unconfig_hs_vddcx;
+ }
+
+ ret = dwc3_hsusb_ldo_init(1);
+ if (ret) {
+ dev_err(&pdev->dev, "hsusb vreg configuration failed\n");
+ goto disable_hs_vddcx;
+ }
+
+ ret = dwc3_hsusb_ldo_enable(1);
+ if (ret) {
+ dev_err(&pdev->dev, "hsusb vreg enable failed\n");
+ goto free_hs_ldo_init;
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "missing memory base resource\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto disable_hs_ldo;
}
msm->base = devm_ioremap_nocache(&pdev->dev, res->start,
resource_size(res));
if (!msm->base) {
dev_err(&pdev->dev, "ioremap failed\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto disable_hs_ldo;
}
- dwc3 = platform_device_alloc("dwc3-msm", -1);
+ dwc3 = platform_device_alloc("dwc3", -1);
if (!dwc3) {
dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
- return -ENOMEM;
+ ret = -ENODEV;
+ goto disable_hs_ldo;
}
- dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
-
dwc3->dev.parent = &pdev->dev;
- dwc3->dev.dma_mask = pdev->dev.dma_mask;
+ dwc3->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ dwc3->dev.dma_mask = &dwc3_msm_dma_mask;
dwc3->dev.dma_parms = pdev->dev.dma_parms;
msm->resource_size = resource_size(res);
- msm->dev = &pdev->dev;
msm->dwc3 = dwc3;
if (of_property_read_u32(node, "qcom,dwc-usb3-msm-dbm-eps",
@@ -810,29 +1374,63 @@
"max: %d, dbm_num_eps: %d\n",
DBM_MAX_EPS, msm->dbm_num_eps);
ret = -ENODEV;
- goto err1;
+ goto put_pdev;
}
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
- goto err1;
+ goto put_pdev;
}
ret = platform_device_add(dwc3);
if (ret) {
dev_err(&pdev->dev, "failed to register dwc3 device\n");
- goto err1;
+ goto put_pdev;
}
/* Reset the DBM */
dwc3_msm_dbm_soft_reset();
+ msm->otg_xceiv = usb_get_transceiver();
+ if (msm->otg_xceiv) {
+ msm->charger.start_detection = dwc3_start_chg_det;
+ ret = dwc3_set_charger(msm->otg_xceiv->otg, &msm->charger);
+ if (ret || !msm->charger.notify_detection_complete) {
+ dev_err(&pdev->dev, "failed to register charger: %d\n",
+ ret);
+ goto put_xcvr;
+ }
+ } else {
+ dev_err(&pdev->dev, "%s: No OTG transceiver found\n", __func__);
+ }
+
return 0;
-err1:
+put_xcvr:
+ usb_put_transceiver(msm->otg_xceiv);
+ platform_device_del(dwc3);
+put_pdev:
platform_device_put(dwc3);
+disable_hs_ldo:
+ dwc3_hsusb_ldo_enable(0);
+free_hs_ldo_init:
+ dwc3_hsusb_ldo_init(0);
+disable_hs_vddcx:
+ regulator_disable(context->hsusb_vddcx);
+unconfig_hs_vddcx:
+ dwc3_hsusb_config_vddcx(0);
+disable_ss_ldo:
+ dwc3_ssusb_ldo_enable(0);
+free_ss_ldo_init:
+ dwc3_ssusb_ldo_init(0);
+disable_ss_vddcx:
+ regulator_disable(context->ssusb_vddcx);
+unconfig_ss_vddcx:
+ dwc3_ssusb_config_vddcx(0);
+disable_core_clk:
+ clk_disable_unprepare(msm->core_clk);
return ret;
}
@@ -841,8 +1439,22 @@
{
struct dwc3_msm *msm = platform_get_drvdata(pdev);
+ if (msm->otg_xceiv) {
+ dwc3_start_chg_det(&msm->charger, false);
+ usb_put_transceiver(msm->otg_xceiv);
+ }
platform_device_unregister(msm->dwc3);
+ dwc3_hsusb_ldo_enable(0);
+ dwc3_hsusb_ldo_init(0);
+ regulator_disable(msm->hsusb_vddcx);
+ dwc3_hsusb_config_vddcx(0);
+ dwc3_ssusb_ldo_enable(0);
+ dwc3_ssusb_ldo_init(0);
+ regulator_disable(msm->ssusb_vddcx);
+ dwc3_ssusb_config_vddcx(0);
+ clk_disable_unprepare(msm->core_clk);
+
return 0;
}
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index d7d9c0e..a5c77ad 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -49,7 +49,6 @@
#include <linux/of.h>
#include "core.h"
-#include "io.h"
/*
* All these registers belong to OMAP's Wrapper around the
@@ -143,6 +142,17 @@
u32 dma_status:1;
};
+static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset)
+{
+ return readl_relaxed(base + offset);
+}
+
+static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value)
+{
+ writel_relaxed(value, base + offset);
+}
+
+
static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
{
struct dwc3_omap *omap = _omap;
@@ -150,7 +160,7 @@
spin_lock(&omap->lock);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1);
if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
@@ -184,10 +194,10 @@
if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
dev_dbg(omap->dev, "IDPULLUP Fall\n");
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
- reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
- dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
spin_unlock(&omap->lock);
@@ -270,7 +280,7 @@
omap->base = base;
omap->dwc3 = dwc3;
- reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
utmi_mode = of_get_property(node, "utmi-mode", &size);
if (utmi_mode && size == sizeof(*utmi_mode)) {
@@ -293,10 +303,10 @@
}
}
- dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
/* check the DMA Status */
- reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG);
omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
/* Set No-Idle and No-Standby */
@@ -306,7 +316,7 @@
reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
- dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
@@ -318,7 +328,7 @@
/* enable all IRQs */
reg = USBOTGSS_IRQO_COREIRQ_ST;
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
reg = (USBOTGSS_IRQ1_OEVT |
USBOTGSS_IRQ1_DRVVBUS_RISE |
@@ -330,7 +340,7 @@
USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
USBOTGSS_IRQ1_IDPULLUP_FALL);
- dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+ dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
new file mode 100644
index 0000000..5df030a
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -0,0 +1,664 @@
+/**
+ * dwc3_otg.c - DesignWare USB3 DRD Controller OTG
+ *
+ * Copyright (c) 2012, Code Aurora Forum. 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/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_device.h>
+
+#include "core.h"
+#include "dwc3_otg.h"
+#include "io.h"
+#include "xhci.h"
+
+
+/**
+ * dwc3_otg_set_host_regs - reset dwc3 otg registers to host operation.
+ *
+ * This function sets the OTG registers to work in A-Device host mode.
+ * This function should be called just before entering to A-Device mode.
+ *
+ * @w: Pointer to the dwc3 otg workqueue.
+ */
+static void dwc3_otg_set_host_regs(struct dwc3_otg *dotg)
+{
+ u32 octl;
+
+ /* Set OCTL[6](PeriMode) to 0 (host) */
+ octl = dwc3_readl(dotg->regs, DWC3_OCTL);
+ octl &= ~DWC3_OTG_OCTL_PERIMODE;
+ dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+
+ /*
+ * TODO: add more OTG registers writes for HOST mode here,
+ * see figure 12-10 A-device flow in dwc3 Synopsis spec
+ */
+}
+
+/**
+ * dwc3_otg_set_peripheral_regs - reset dwc3 otg registers to peripheral operation.
+ *
+ * This function sets the OTG registers to work in B-Device peripheral mode.
+ * This function should be called just before entering to B-Device mode.
+ *
+ * @w: Pointer to the dwc3 otg workqueue.
+ */
+static void dwc3_otg_set_peripheral_regs(struct dwc3_otg *dotg)
+{
+ u32 octl;
+
+ /* Set OCTL[6](PeriMode) to 1 (peripheral) */
+ octl = dwc3_readl(dotg->regs, DWC3_OCTL);
+ octl |= DWC3_OTG_OCTL_PERIMODE;
+ dwc3_writel(dotg->regs, DWC3_OCTL, octl);
+
+ /*
+ * TODO: add more OTG registers writes for PERIPHERAL mode here,
+ * see figure 12-19 B-device flow in dwc3 Synopsis spec
+ */
+}
+
+/**
+ * dwc3_otg_start_host - helper function for starting/stoping the host controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @on: start / stop the host controller driver.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_start_host(struct usb_otg *otg, int on)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+ struct usb_hcd *hcd;
+ struct xhci_hcd *xhci;
+ int ret = 0;
+
+ if (!otg->host)
+ return -EINVAL;
+
+ hcd = bus_to_hcd(otg->host);
+ xhci = hcd_to_xhci(hcd);
+ if (on) {
+ dev_dbg(otg->phy->dev, "%s: turn on host %s\n",
+ __func__, otg->host->bus_name);
+ dwc3_otg_set_host_regs(dotg);
+
+ /*
+ * This should be revisited for more testing post-silicon.
+ * In worst case we may need to disconnect the root hub
+ * before stopping the controller so that it does not
+ * interfere with runtime pm/system pm.
+ * We can also consider registering and unregistering xhci
+ * platform device. It is almost similar to add_hcd and
+ * remove_hcd, But we may not use standard set_host method
+ * anymore.
+ */
+ ret = hcd->driver->start(hcd);
+ if (ret) {
+ dev_err(otg->phy->dev,
+ "%s: failed to start primary hcd, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = xhci->shared_hcd->driver->start(xhci->shared_hcd);
+ if (ret) {
+ dev_err(otg->phy->dev,
+ "%s: failed to start secondary hcd, ret=%d\n",
+ __func__, ret);
+ return ret;
+ }
+ } else {
+ dev_dbg(otg->phy->dev, "%s: turn off host %s\n",
+ __func__, otg->host->bus_name);
+ hcd->driver->stop(hcd);
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_otg_set_host - bind/unbind the host controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @host: Pointer to the usb_bus structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (host) {
+ dev_dbg(otg->phy->dev, "%s: set host %s\n",
+ __func__, host->bus_name);
+ otg->host = host;
+
+ /*
+ * Only after both peripheral and host are set then check
+ * OTG sm. This prevents unnecessary activation of the sm
+ * in case the ID is high.
+ */
+ if (otg->gadget)
+ schedule_work(&dotg->sm_work);
+ } else {
+ if (otg->phy->state == OTG_STATE_A_HOST) {
+ dwc3_otg_start_host(otg, 0);
+ otg->host = NULL;
+ otg->phy->state = OTG_STATE_UNDEFINED;
+ schedule_work(&dotg->sm_work);
+ } else {
+ otg->host = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_otg_start_peripheral - bind/unbind the peripheral controller.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @gadget: pointer to the usb_gadget structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (!otg->gadget)
+ return -EINVAL;
+
+ if (on) {
+ dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n",
+ __func__, otg->gadget->name);
+ dwc3_otg_set_peripheral_regs(dotg);
+ usb_gadget_vbus_connect(otg->gadget);
+ } else {
+ dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
+ __func__, otg->gadget->name);
+ usb_gadget_vbus_disconnect(otg->gadget);
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_otg_set_peripheral - bind/unbind the peripheral controller driver.
+ *
+ * @otg: Pointer to the otg_transceiver structure.
+ * @gadget: pointer to the usb_gadget structure.
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int dwc3_otg_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ if (gadget) {
+ dev_dbg(otg->phy->dev, "%s: set gadget %s\n",
+ __func__, gadget->name);
+ otg->gadget = gadget;
+
+ /*
+ * Only after both peripheral and host are set then check
+ * OTG sm. This prevents unnecessary activation of the sm
+ * in case the ID is grounded.
+ */
+ if (otg->host)
+ schedule_work(&dotg->sm_work);
+ } else {
+ if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
+ dwc3_otg_start_peripheral(otg, 0);
+ otg->gadget = NULL;
+ otg->phy->state = OTG_STATE_UNDEFINED;
+ schedule_work(&dotg->sm_work);
+ } else {
+ otg->gadget = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_ext_chg_det_done - callback to handle charger detection completion
+ * @otg: Pointer to the otg transceiver structure
+ * @charger: Pointer to the external charger structure
+ *
+ * Returns 0 on success
+ */
+static void dwc3_ext_chg_det_done(struct usb_otg *otg, struct dwc3_charger *chg)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ /*
+ * Ignore chg_detection notification if BSV has gone off by this time.
+ * STOP chg_det as part of !BSV handling would reset the chg_det flags
+ */
+ if (test_bit(B_SESS_VLD, &dotg->inputs))
+ schedule_work(&dotg->sm_work);
+}
+
+/**
+ * dwc3_set_charger - bind/unbind external charger driver
+ * @otg: Pointer to the otg transceiver structure
+ * @charger: Pointer to the external charger structure
+ *
+ * Returns 0 on success
+ */
+int dwc3_set_charger(struct usb_otg *otg, struct dwc3_charger *charger)
+{
+ struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+
+ dotg->charger = charger;
+ if (charger)
+ charger->notify_detection_complete = dwc3_ext_chg_det_done;
+
+ return 0;
+}
+
+/* IRQs which OTG driver is interested in handling */
+#define DWC3_OEVT_MASK (DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)
+
+/**
+ * dwc3_otg_interrupt - interrupt handler for dwc3 otg events.
+ * @_dotg: Pointer to out controller context structure
+ *
+ * Returns IRQ_HANDLED on success otherwise IRQ_NONE.
+ */
+static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
+{
+ struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
+ u32 osts, oevt_reg;
+ int ret = IRQ_NONE;
+ int handled_irqs = 0;
+
+ oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);
+
+ if (!(oevt_reg & DWC3_OEVT_MASK))
+ return IRQ_NONE;
+
+ osts = dwc3_readl(dotg->regs, DWC3_OSTS);
+
+ if ((oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ||
+ (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)) {
+ /*
+ * ID sts has changed, set inputs later, in the workqueue
+ * function, switch from A to B or from B to A.
+ */
+
+ if (osts & DWC3_OTG_OSTS_CONIDSTS)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (osts & DWC3_OTG_OSTS_BSESVALID)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+
+ schedule_work(&dotg->sm_work);
+
+ handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ?
+ DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT : 0;
+ handled_irqs |= (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) ?
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT : 0;
+
+ ret = IRQ_HANDLED;
+
+ /* Clear the interrupts we handled */
+ dwc3_writel(dotg->regs, DWC3_OEVT, handled_irqs);
+ }
+
+ return ret;
+}
+
+/**
+ * dwc3_otg_init_sm - initialize OTG statemachine input
+ * @dotg: Pointer to the dwc3_otg structure
+ *
+ */
+void dwc3_otg_init_sm(struct dwc3_otg *dotg)
+{
+ u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
+ struct usb_phy *phy = dotg->otg.phy;
+
+ /*
+ * TODO: If using external notifications then wait here till initial
+ * state is reported
+ */
+
+ dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);
+
+ if (osts & DWC3_OTG_OSTS_CONIDSTS)
+ set_bit(ID, &dotg->inputs);
+ else
+ clear_bit(ID, &dotg->inputs);
+
+ if (osts & DWC3_OTG_OSTS_BSESVALID)
+ set_bit(B_SESS_VLD, &dotg->inputs);
+ else
+ clear_bit(B_SESS_VLD, &dotg->inputs);
+}
+
+/**
+ * dwc3_otg_sm_work - workqueue function.
+ *
+ * @w: Pointer to the dwc3 otg workqueue
+ *
+ * NOTE: After any change in phy->state,
+ * we must reschdule the state machine.
+ */
+static void dwc3_otg_sm_work(struct work_struct *w)
+{
+ struct dwc3_otg *dotg = container_of(w, struct dwc3_otg, sm_work);
+ struct usb_phy *phy = dotg->otg.phy;
+ struct dwc3_charger *charger = dotg->charger;
+ bool work = 0;
+
+ dev_dbg(phy->dev, "%s state\n", otg_state_string(phy->state));
+
+ /* Check OTG state */
+ switch (phy->state) {
+ case OTG_STATE_UNDEFINED:
+ dwc3_otg_init_sm(dotg);
+ /* Switch to A or B-Device according to ID / BSV */
+ if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+ dev_dbg(phy->dev, "!id\n");
+ phy->state = OTG_STATE_A_IDLE;
+ work = 1;
+ } else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
+ dev_dbg(phy->dev, "b_sess_vld\n");
+ phy->state = OTG_STATE_B_IDLE;
+ work = 1;
+ } else {
+ phy->state = OTG_STATE_B_IDLE;
+ /* TODO: Enter low power state */
+ }
+ break;
+
+ case OTG_STATE_B_IDLE:
+ if (!test_bit(ID, &dotg->inputs) && phy->otg->host) {
+ dev_dbg(phy->dev, "!id\n");
+ phy->state = OTG_STATE_A_IDLE;
+ work = 1;
+ if (charger) {
+ if (charger->chg_type == DWC3_INVALID_CHARGER)
+ charger->start_detection(dotg->charger,
+ false);
+ else
+ charger->chg_type =
+ DWC3_INVALID_CHARGER;
+ }
+ } else if (test_bit(B_SESS_VLD, &dotg->inputs)) {
+ dev_dbg(phy->dev, "b_sess_vld\n");
+ if (charger) {
+ /* Has charger been detected? If no detect it */
+ switch (charger->chg_type) {
+ case DWC3_DCP_CHARGER:
+ /* TODO: initiate LPM */
+ break;
+ case DWC3_CDP_CHARGER:
+ dwc3_otg_start_peripheral(&dotg->otg,
+ 1);
+ phy->state = OTG_STATE_B_PERIPHERAL;
+ work = 1;
+ break;
+ case DWC3_SDP_CHARGER:
+ dwc3_otg_start_peripheral(&dotg->otg,
+ 1);
+ phy->state = OTG_STATE_B_PERIPHERAL;
+ work = 1;
+ break;
+ default:
+ dev_dbg(phy->dev, "chg_det started\n");
+ charger->start_detection(charger, true);
+ break;
+ }
+ } else {
+ /* no charger registered, start peripheral */
+ if (dwc3_otg_start_peripheral(&dotg->otg, 1)) {
+ /*
+ * Probably set_peripheral not called
+ * yet. We will re-try as soon as it
+ * will be called
+ */
+ dev_err(phy->dev,
+ "unable to start B-device\n");
+ phy->state = OTG_STATE_UNDEFINED;
+ return;
+ }
+ }
+ } else {
+ if (charger) {
+ if (charger->chg_type == DWC3_INVALID_CHARGER)
+ charger->start_detection(dotg->charger,
+ false);
+ else
+ charger->chg_type =
+ DWC3_INVALID_CHARGER;
+ }
+ /* TODO: Enter low power state */
+ }
+ break;
+
+ case OTG_STATE_B_PERIPHERAL:
+ if (!test_bit(B_SESS_VLD, &dotg->inputs) ||
+ !test_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "!id || !bsv\n");
+ dwc3_otg_start_peripheral(&dotg->otg, 0);
+ phy->state = OTG_STATE_B_IDLE;
+ if (charger)
+ charger->chg_type = DWC3_INVALID_CHARGER;
+ work = 1;
+ }
+ break;
+
+ case OTG_STATE_A_IDLE:
+ /* Switch to A-Device*/
+ if (test_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "id\n");
+ phy->state = OTG_STATE_B_IDLE;
+ work = 1;
+ } else {
+ if (dwc3_otg_start_host(&dotg->otg, 1)) {
+ /*
+ * Probably set_host was not called yet.
+ * We will re-try as soon as it will be called
+ */
+ dev_dbg(phy->dev,
+ "unable to start A-device\n");
+ phy->state = OTG_STATE_UNDEFINED;
+ return;
+ }
+ phy->state = OTG_STATE_A_HOST;
+ }
+ break;
+
+ case OTG_STATE_A_HOST:
+ if (test_bit(ID, &dotg->inputs)) {
+ dev_dbg(phy->dev, "id\n");
+ dwc3_otg_start_host(&dotg->otg, 0);
+ phy->state = OTG_STATE_B_IDLE;
+ work = 1;
+ }
+ break;
+
+ default:
+ dev_err(phy->dev, "%s: invalid otg-state\n", __func__);
+
+ }
+
+ if (work)
+ schedule_work(&dotg->sm_work);
+}
+
+
+/**
+ * dwc3_otg_reset - reset dwc3 otg registers.
+ *
+ * @w: Pointer to the dwc3 otg workqueue
+ */
+static void dwc3_otg_reset(struct dwc3_otg *dotg)
+{
+ /*
+ * OCFG[2] - OTG-Version = 1
+ * OCFG[1] - HNPCap = 0
+ * OCFG[0] - SRPCap = 0
+ */
+ dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
+
+ /*
+ * OCTL[6] - PeriMode = 1
+ * OCTL[5] - PrtPwrCtl = 0
+ * OCTL[4] - HNPReq = 0
+ * OCTL[3] - SesReq = 0
+ * OCTL[2] - TermSelDLPulse = 0
+ * OCTL[1] - DevSetHNPEn = 0
+ * OCTL[0] - HstSetHNPEn = 0
+ */
+ dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+
+ /* Clear all otg events (interrupts) indications */
+ dwc3_writel(dotg->regs, DWC3_OEVT, 0xFFFF);
+
+ /* Enable ID/BSV StsChngEn event*/
+ dwc3_writel(dotg->regs, DWC3_OEVTEN,
+ DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT |
+ DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT);
+}
+
+/**
+ * dwc3_otg_init - Initializes otg related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int dwc3_otg_init(struct dwc3 *dwc)
+{
+ u32 reg;
+ int ret = 0;
+ struct dwc3_otg *dotg;
+
+ dev_dbg(dwc->dev, "dwc3_otg_init\n");
+
+ /*
+ * GHWPARAMS6[10] bit is SRPSupport.
+ * This bit also reflects DWC_USB3_EN_OTG
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+ if (!(reg & DWC3_GHWPARAMS6_SRP_SUPPORT)) {
+ /*
+ * No OTG support in the HW core.
+ * We return 0 to indicate no error, since this is acceptable
+ * situation, just continue probe the dwc3 driver without otg.
+ */
+ dev_dbg(dwc->dev, "dwc3_otg address space is not supported\n");
+ return 0;
+ }
+
+ /* Allocate and init otg instance */
+ dotg = kzalloc(sizeof(struct dwc3_otg), GFP_KERNEL);
+ if (!dotg) {
+ dev_err(dwc->dev, "unable to allocate dwc3_otg\n");
+ return -ENOMEM;
+ }
+
+ dotg->irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+ if (dotg->irq < 0) {
+ dev_err(dwc->dev, "%s: missing IRQ\n", __func__);
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ dotg->regs = dwc->regs;
+
+ dotg->otg.set_peripheral = dwc3_otg_set_peripheral;
+ dotg->otg.set_host = dwc3_otg_set_host;
+
+ /* This reference is used by dwc3 modules for checking otg existance */
+ dwc->dotg = dotg;
+
+ dotg->otg.phy = kzalloc(sizeof(struct usb_phy), GFP_KERNEL);
+ if (!dotg->otg.phy) {
+ dev_err(dwc->dev, "unable to allocate dwc3_otg.phy\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ dotg->otg.phy->otg = &dotg->otg;
+ dotg->otg.phy->dev = dwc->dev;
+
+ ret = usb_set_transceiver(dotg->otg.phy);
+ if (ret) {
+ dev_err(dotg->otg.phy->dev,
+ "%s: failed to set transceiver, already exists\n",
+ __func__);
+ goto err2;
+ }
+
+ dwc3_otg_reset(dotg);
+
+ dotg->otg.phy->state = OTG_STATE_UNDEFINED;
+
+ INIT_WORK(&dotg->sm_work, dwc3_otg_sm_work);
+
+ ret = request_irq(dotg->irq, dwc3_otg_interrupt, IRQF_SHARED,
+ "dwc3_otg", dotg);
+ if (ret) {
+ dev_err(dotg->otg.phy->dev, "failed to request irq #%d --> %d\n",
+ dotg->irq, ret);
+ goto err3;
+ }
+
+ return 0;
+
+err3:
+ cancel_work_sync(&dotg->sm_work);
+ usb_set_transceiver(NULL);
+err2:
+ kfree(dotg->otg.phy);
+err1:
+ dwc->dotg = NULL;
+ kfree(dotg);
+
+ return ret;
+}
+
+/**
+ * dwc3_otg_exit
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+void dwc3_otg_exit(struct dwc3 *dwc)
+{
+ struct dwc3_otg *dotg = dwc->dotg;
+
+ /* dotg is null when GHWPARAMS6[10]=SRPSupport=0, see dwc3_otg_init */
+ if (dotg) {
+ if (dotg->charger)
+ dotg->charger->start_detection(dotg->charger, false);
+ cancel_work_sync(&dotg->sm_work);
+ usb_set_transceiver(NULL);
+ free_irq(dotg->irq, dotg);
+ kfree(dotg->otg.phy);
+ kfree(dotg);
+ dwc->dotg = NULL;
+ }
+}
diff --git a/drivers/usb/dwc3/dwc3_otg.h b/drivers/usb/dwc3/dwc3_otg.h
new file mode 100644
index 0000000..0d8b61b
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3_otg.h
@@ -0,0 +1,76 @@
+/**
+ * dwc3_otg.h - DesignWare USB3 DRD Controller OTG
+ *
+ * Copyright (c) 2012, Code Aurora Forum. 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 __LINUX_USB_DWC3_OTG_H
+#define __LINUX_USB_DWC3_OTG_H
+
+#include <linux/workqueue.h>
+
+#include <linux/usb/otg.h>
+
+struct dwc3_charger;
+
+/**
+ * struct dwc3_otg: OTG driver data. Shared by HCD and DCD.
+ * @otg: USB OTG Transceiver structure.
+ * @irq: IRQ number assigned for HSUSB controller.
+ * @regs: ioremapped register base address.
+ * @sm_work: OTG state machine work.
+ * @charger: DWC3 external charger detector
+ * @inputs: OTG state machine inputs
+ */
+struct dwc3_otg {
+ struct usb_otg otg;
+ int irq;
+ void __iomem *regs;
+ struct work_struct sm_work;
+ struct dwc3_charger *charger;
+#define ID 0
+#define B_SESS_VLD 1
+ unsigned long inputs;
+};
+
+/**
+ * USB charger types
+ *
+ * DWC3_INVALID_CHARGER Invalid USB charger.
+ * DWC3_SDP_CHARGER Standard downstream port. Refers to a downstream port
+ * on USB compliant host/hub.
+ * DWC3_DCP_CHARGER Dedicated charger port (AC charger/ Wall charger).
+ * DWC3_CDP_CHARGER Charging downstream port. Enumeration can happen and
+ * IDEV_CHG_MAX can be drawn irrespective of USB state.
+ */
+enum dwc3_chg_type {
+ DWC3_INVALID_CHARGER = 0,
+ DWC3_SDP_CHARGER,
+ DWC3_DCP_CHARGER,
+ DWC3_CDP_CHARGER,
+};
+
+struct dwc3_charger {
+ enum dwc3_chg_type chg_type;
+
+ /* start/stop charger detection, provided by external charger module */
+ void (*start_detection)(struct dwc3_charger *charger, bool start);
+
+ /* to notify OTG about charger detection completion, provided by OTG */
+ void (*notify_detection_complete)(struct usb_otg *otg,
+ struct dwc3_charger *charger);
+};
+
+/* for external charger driver */
+extern int dwc3_set_charger(struct usb_otg *otg, struct dwc3_charger *charger);
+
+#endif /* __LINUX_USB_DWC3_OTG_H */
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 5255fe9..060144f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -49,6 +49,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
#include "core.h"
#include "gadget.h"
@@ -313,7 +314,7 @@
} while (1);
}
-static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb *trb)
{
u32 offset = (char *) trb - (char *) dep->trb_pool;
@@ -1326,7 +1327,59 @@
is_on = !!is_on;
spin_lock_irqsave(&dwc->lock, flags);
+
+ dwc->softconnect = is_on;
+
+ if ((dwc->dotg && !dwc->vbus_active) ||
+ !dwc->gadget_driver) {
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ /*
+ * Need to wait for vbus_session(on) from otg driver or to
+ * the udc_start.
+ */
+ return 0;
+ }
+
dwc3_gadget_run_stop(dwc, is_on);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static int dwc3_gadget_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+ struct dwc3 *dwc = gadget_to_dwc(_gadget);
+ unsigned long flags;
+
+ if (!dwc->dotg)
+ return -EPERM;
+
+ is_active = !!is_active;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ /* Mark that the vbus was powered */
+ dwc->vbus_active = is_active;
+
+ /*
+ * Check if upper level usb_gadget_driver was already registerd with
+ * this udc controller driver (if dwc3_gadget_start was called)
+ */
+ if (dwc->gadget_driver && dwc->softconnect) {
+ if (dwc->vbus_active) {
+ /*
+ * Both vbus was activated by otg and pullup was
+ * signaled by the gadget driver.
+ */
+ dwc3_gadget_run_stop(dwc, 1);
+ } else {
+ dwc3_gadget_run_stop(dwc, 0);
+ }
+ }
+
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@@ -1417,6 +1470,7 @@
.get_frame = dwc3_gadget_get_frame,
.wakeup = dwc3_gadget_wakeup,
.set_selfpowered = dwc3_gadget_set_selfpowered,
+ .vbus_session = dwc3_gadget_vbus_session,
.pullup = dwc3_gadget_pullup,
.udc_start = dwc3_gadget_start,
.udc_stop = dwc3_gadget_stop,
@@ -2153,6 +2207,33 @@
break;
case DWC3_DEVICE_EVENT_OVERFLOW:
dev_vdbg(dwc->dev, "Overflow\n");
+ /*
+ * Controllers prior to 2.30a revision has a bug where
+ * Overflow Event may overwrite an unacknowledged event
+ * in the event buffer. The severity of the issue depends
+ * on the overwritten event type. Add a warning message
+ * saying that an event is overwritten.
+ *
+ * TODO: In future we may need to see if we can re-enumerate
+ * with host.
+ */
+ if (dwc->revision < DWC3_REVISION_230A)
+ dev_warn(dwc->dev, "Unacknowledged event overwritten\n");
+ break;
+ case DWC3_DEVICE_EVENT_VENDOR_DEV_TEST_LMP:
+ /*
+ * Controllers prior to 2.30a revision has a bug, due to which
+ * a vendor device test LMP event can not be filtered. But
+ * this event is not handled in the current code. This is a
+ * special event and 8 bytes of data will follow the event.
+ * Handling this event is tricky when event buffer is almost
+ * full. Moreover this event will not occur in normal scenario
+ * and can only happen with special hosts in testing scenarios.
+ * Add a warning message to indicate that this event is received
+ * which means that event buffer might have corrupted.
+ */
+ if (dwc->revision < DWC3_REVISION_230A)
+ dev_warn(dwc->dev, "Vendor Device Test LMP Received\n");
break;
default:
dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
@@ -2314,8 +2395,7 @@
}
/* Enable all but Start and End of Frame IRQs */
- reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
- DWC3_DEVTEN_EVNTOVERFLOWEN |
+ reg = (DWC3_DEVTEN_EVNTOVERFLOWEN |
DWC3_DEVTEN_CMDCMPLTEN |
DWC3_DEVTEN_ERRTICERREN |
DWC3_DEVTEN_WKUPEVTEN |
@@ -2338,6 +2418,15 @@
goto err7;
}
+ if (dwc->dotg) {
+ /* dwc3 otg driver is active (DRD mode + SRPSupport=1) */
+ ret = otg_set_peripheral(&dwc->dotg->otg, &dwc->gadget);
+ if (ret) {
+ dev_err(dwc->dev, "failed to set peripheral to otg\n");
+ goto err7;
+ }
+ }
+
return 0;
err7:
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index a860008..662682e 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -111,6 +111,8 @@
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+ struct dwc3_trb *trb);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index b108d18..099708b 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -38,20 +38,13 @@
#include <linux/platform_device.h>
#include "core.h"
-
-static struct resource generic_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- },
- {
- .flags = IORESOURCE_MEM,
- },
-};
+#include "xhci.h"
int dwc3_host_init(struct dwc3 *dwc)
{
struct platform_device *xhci;
int ret;
+ struct xhci_plat_data pdata;
xhci = platform_device_alloc("xhci-hcd", -1);
if (!xhci) {
@@ -67,15 +60,19 @@
xhci->dev.dma_parms = dwc->dev->dma_parms;
dwc->xhci = xhci;
+ pdata.vendor = ((dwc->revision & DWC3_GSNPSID_MASK) >>
+ __ffs(DWC3_GSNPSID_MASK) & DWC3_GSNPSREV_MASK);
+ pdata.revision = dwc->revision & DWC3_GSNPSREV_MASK;
- /* setup resources */
- generic_resources[0].start = dwc->irq;
+ ret = platform_device_add_data(xhci, (const void *) &pdata,
+ sizeof(struct xhci_plat_data));
+ if (ret) {
+ dev_err(dwc->dev, "couldn't add pdata to xHCI device\n");
+ goto err1;
+ }
- generic_resources[1].start = dwc->res->start;
- generic_resources[1].end = dwc->res->start + 0x7fff;
-
- ret = platform_device_add_resources(xhci, generic_resources,
- ARRAY_SIZE(generic_resources));
+ ret = platform_device_add_resources(xhci, dwc->xhci_resources,
+ DWC3_XHCI_RESOURCES_NUM);
if (ret) {
dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
goto err1;
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index 071d561..90de7a4 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -41,14 +41,26 @@
#include <linux/io.h>
+#include "core.h"
+
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
{
- return readl(base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ return readl_relaxed(base + (offset - DWC3_GLOBALS_REGS_START));
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
{
- writel(value, base + offset);
+ /*
+ * We requested the mem region starting from the Globals address
+ * space, see dwc3_probe in core.c.
+ * However, the offsets are given starting from xHCI address space.
+ */
+ writel_relaxed(value, base + (offset - DWC3_GLOBALS_REGS_START));
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 14b07e5..95f11c1 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -506,6 +506,32 @@
dynamically linked module called "ci13xxx_msm_hsic" and force all
gadget drivers to also be dynamically linked.
+config USB_DWC3_MSM
+ tristate "DesignWare USB3.0 (DRD) Controller for MSM"
+ depends on ARCH_MSM
+ select USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SELECTED
+ help
+ The DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ integrated into the Qualcomm MSM chipset series, supporting host,
+ device and otg modes of operation. For more information please
+ refer to http://www.qualcomm.com/chipsets.
+
+config USB_DWC3_OMAP
+ tristate "DesignWare USB3.0 (DRD) Controller for OMAP"
+ depends on ARCH_OMAP
+ select USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SUPERSPEED
+ select USB_GADGET_SELECTED
+ help
+ DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ which can be configured for peripheral-only, host-only, hub-only
+ and Dual-Role operation. This Controller was first integrated into
+ the OMAP5 series of processors. More information about the OMAP5
+ version of this controller, refer to http://www.ti.com/omap5.
+
#
# LAST -- dummy/emulated controller
#
@@ -556,8 +582,15 @@
# Selected by UDC drivers that support super-speed opperation
config USB_GADGET_SUPERSPEED
- bool
+ bool "Operate as superspeed"
+ depends on USB_GADGET
depends on USB_GADGET_DUALSPEED
+ default n
+ help
+ When a superspeed peripheral controller is selected
+ (for example DesignWare USB3.0 controller), use this flag to
+ indicate if the device should operate in superspeed(=y)
+ or not.
#
# USB Gadget Drivers
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index eefe95f..be8e6aa 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1546,7 +1546,9 @@
{ \
if (size >= sizeof(buffer)) \
return -EINVAL; \
- return strlcpy(buffer, buf, sizeof(buffer)); \
+ strlcpy(buffer, buf, sizeof(buffer)); \
+ strim(buffer); \
+ return size; \
} \
static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, field ## _show, field ## _store);
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 1cbaa8e..e3c1216 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -56,7 +56,7 @@
if (_udc_ctxt.wake_irq && _udc_ctxt.wake_irq_state) {
disable_irq_wake(_udc_ctxt.wake_irq);
- disable_irq(_udc_ctxt.wake_irq);
+ disable_irq_nosync(_udc_ctxt.wake_irq);
_udc_ctxt.wake_irq_state = false;
}
}
@@ -134,7 +134,7 @@
dev_dbg(&pdev->dev, "_udc_ctxt.gpio_irq = %d and irq = %d\n",
_udc_ctxt.wake_gpio, wake_irq);
ret = request_irq(wake_irq, ci13xxx_msm_resume_irq,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "usb resume", NULL);
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT, "usb resume", NULL);
if (ret < 0) {
dev_err(&pdev->dev, "could not register USB_RESUME IRQ.\n");
goto gpio_free;
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 39d4720..30b45eb 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -30,16 +30,16 @@
#include <mach/clk.h>
#include <mach/msm_iomap.h>
#include <mach/msm_xo.h>
+#include <mach/rpm-regulator.h>
#include "ci13xxx_udc.c"
#define MSM_USB_BASE (mhsic->regs)
#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
-#define USB_PHY_VDD_DIG_VOL_SUSP_MIN 500000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
#define USB_PHY_VDD_DIG_VOL_MIN 1045000 /* uV */
#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
-#define USB_PHY_VDD_DIG_LOAD 49360 /* uA */
#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
#define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000)
#define PHY_RESUME_TIMEOUT_USEC (100 * 1000)
@@ -66,38 +66,56 @@
struct workqueue_struct *wq;
struct work_struct suspend_w;
struct msm_hsic_peripheral_platform_data *pdata;
+ enum usb_vdd_type vdd_type;
+};
+
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+ { /* VDD_CX CORNER Voting */
+ [VDD_NONE] = RPM_VREG_CORNER_NONE,
+ [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
+ [VDD_MAX] = RPM_VREG_CORNER_HIGH,
+ },
+ { /* VDD_CX Voltage Voting */
+ [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
+ [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
+ [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
+ },
};
static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
{
int ret = 0;
+ int none_vol, min_vol, max_vol;
+
+ if (!mhsic->hsic_vddcx) {
+ mhsic->vdd_type = VDDCX_CORNER;
+ mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
+ "hsic_vdd_dig");
+ if (IS_ERR(mhsic->hsic_vddcx)) {
+ mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
+ "HSIC_VDDCX");
+ if (IS_ERR(mhsic->hsic_vddcx)) {
+ dev_err(mhsic->dev, "unable to get hsic vddcx\n");
+ return PTR_ERR(mhsic->hsic_vddcx);
+ }
+ mhsic->vdd_type = VDDCX;
+ }
+ }
+
+ none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
+ min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
+ max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
if (!init)
goto disable_reg;
- mhsic->hsic_vddcx = regulator_get(mhsic->dev, "HSIC_VDDCX");
- if (IS_ERR(mhsic->hsic_vddcx)) {
- dev_err(mhsic->dev, "unable to get hsic vddcx\n");
- return PTR_ERR(mhsic->hsic_vddcx);
- }
-
- ret = regulator_set_voltage(mhsic->hsic_vddcx,
- USB_PHY_VDD_DIG_VOL_MIN,
- USB_PHY_VDD_DIG_VOL_MAX);
+ ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
if (ret) {
dev_err(mhsic->dev, "unable to set the voltage"
"for hsic vddcx\n");
goto reg_set_voltage_err;
}
- ret = regulator_set_optimum_mode(mhsic->hsic_vddcx,
- USB_PHY_VDD_DIG_LOAD);
- if (ret < 0) {
- pr_err("%s: Unable to set optimum mode of the regulator:"
- "VDDCX\n", __func__);
- goto reg_optimum_mode_err;
- }
-
ret = regulator_enable(mhsic->hsic_vddcx);
if (ret) {
dev_err(mhsic->dev, "unable to enable hsic vddcx\n");
@@ -109,12 +127,8 @@
disable_reg:
regulator_disable(mhsic->hsic_vddcx);
reg_enable_err:
- regulator_set_optimum_mode(mhsic->hsic_vddcx, 0);
-reg_optimum_mode_err:
- regulator_set_voltage(mhsic->hsic_vddcx, 0,
- USB_PHY_VDD_DIG_VOL_MIN);
+ regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
reg_set_voltage_err:
- regulator_put(mhsic->hsic_vddcx);
return ret;
@@ -323,6 +337,7 @@
{
int cnt = 0, ret;
u32 val;
+ int none_vol, max_vol;
if (atomic_read(&mhsic->in_lpm)) {
dev_dbg(mhsic->dev, "%s called while in lpm\n", __func__);
@@ -378,11 +393,12 @@
dev_err(mhsic->dev, "%s failed to devote for TCXO %d\n"
, __func__, ret);
- ret = regulator_set_voltage(mhsic->hsic_vddcx,
- USB_PHY_VDD_DIG_VOL_SUSP_MIN,
- USB_PHY_VDD_DIG_VOL_MAX);
+ none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
+ max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
+
+ ret = regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
if (ret < 0)
- dev_err(mhsic->dev, "unable to set vddcx voltage: min:0.5v max:1.32v\n");
+ dev_err(mhsic->dev, "unable to set vddcx voltage for VDD MIN\n");
if (device_may_wakeup(mhsic->dev))
enable_irq_wake(mhsic->irq);
@@ -400,6 +416,7 @@
{
int cnt = 0, ret;
unsigned temp;
+ int min_vol, max_vol;
if (!atomic_read(&mhsic->in_lpm)) {
dev_dbg(mhsic->dev, "%s called while not in lpm\n", __func__);
@@ -407,12 +424,14 @@
}
wake_lock(&mhsic->wlock);
- ret = regulator_set_voltage(mhsic->hsic_vddcx,
- USB_PHY_VDD_DIG_VOL_MIN,
- USB_PHY_VDD_DIG_VOL_MAX);
+
+ min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
+ max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
+
+ ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
if (ret < 0)
dev_err(mhsic->dev,
- "unable to set vddcx voltage: min:1.045v max:1.32v\n");
+ "unable to set nominal vddcx voltage (no VDD MIN)\n");
ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
if (ret)
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index fb86874..8cdc2e9 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -1720,6 +1720,7 @@
if (!mReq->req.no_interrupt)
mReq->ptr->token |= MSM_ETD_IOC;
}
+ mReq->req.dma = 0;
}
mReq->ptr->page[0] = mReq->req.dma;
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 9e3301f..62955c2 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -690,6 +690,14 @@
usb_ep_disable(link->in_ep);
usb_ep_disable(link->out_ep);
if (netif_carrier_ok(net)) {
+ if (config_ep_by_speed(dev->gadget, &link->func,
+ link->in_ep) ||
+ config_ep_by_speed(dev->gadget, &link->func,
+ link->out_ep)) {
+ link->in_ep->desc = NULL;
+ link->out_ep->desc = NULL;
+ return -EINVAL;
+ }
DBG(dev, "host still using in/out endpoints\n");
usb_ep_enable(link->in_ep);
usb_ep_enable(link->out_ep);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 5cc70e0..caf86ca 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -313,7 +313,7 @@
if (!ehci->susp_sof_bug)
ehci_halt(ehci); /* turn off now-idle HC */
- hcd->state = HC_STATE_SUSPENDED;
+ ehci->rh_state = EHCI_RH_SUSPENDED;
if (ehci->reclaim)
end_unlink_async(ehci);
@@ -562,6 +562,10 @@
unsigned long flags;
u32 ppcd = 0;
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (ehci->rh_state != EHCI_RH_RUNNING)
+ return 0;
+
/* init status to no-changes */
buf [0] = 0;
ports = HCS_N_PORTS (ehci->hcs_params);
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 6bd0577..a6b7dee 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -30,16 +30,19 @@
#include <linux/wakelock.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
-#include <mach/msm_bus.h>
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/msm_hsusb.h>
#include <linux/gpio.h>
+#include <linux/spinlock.h>
+
+#include <mach/msm_bus.h>
#include <mach/clk.h>
#include <mach/msm_iomap.h>
#include <mach/msm_xo.h>
#include <linux/spinlock.h>
#include <linux/cpu.h>
+#include <mach/rpm-regulator.h>
#define MSM_USB_BASE (hcd->regs)
@@ -62,6 +65,7 @@
atomic_t pm_usage_cnt;
uint32_t bus_perf_client;
uint32_t wakeup_int_cnt;
+ enum usb_vdd_type vdd_type;
};
static bool debug_bus_voting_enabled = true;
@@ -254,43 +258,59 @@
#define ULPI_IO_TIMEOUT_USEC (10 * 1000)
-#define USB_PHY_VDD_DIG_VOL_SUSP_MIN 500000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_NONE 0 /*uV */
#define USB_PHY_VDD_DIG_VOL_MIN 1000000 /* uV */
#define USB_PHY_VDD_DIG_VOL_MAX 1320000 /* uV */
-#define USB_PHY_VDD_DIG_LOAD 49360 /* uA */
#define HSIC_DBG1_REG 0x38
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+ { /* VDD_CX CORNER Voting */
+ [VDD_NONE] = RPM_VREG_CORNER_NONE,
+ [VDD_MIN] = RPM_VREG_CORNER_NOMINAL,
+ [VDD_MAX] = RPM_VREG_CORNER_HIGH,
+ },
+ { /* VDD_CX Voltage Voting */
+ [VDD_NONE] = USB_PHY_VDD_DIG_VOL_NONE,
+ [VDD_MIN] = USB_PHY_VDD_DIG_VOL_MIN,
+ [VDD_MAX] = USB_PHY_VDD_DIG_VOL_MAX,
+ },
+};
+
static int msm_hsic_init_vddcx(struct msm_hsic_hcd *mehci, int init)
{
int ret = 0;
+ int none_vol, min_vol, max_vol;
+
+ if (!mehci->hsic_vddcx) {
+ mehci->vdd_type = VDDCX_CORNER;
+ mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
+ "hsic_vdd_dig");
+ if (IS_ERR(mehci->hsic_vddcx)) {
+ mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
+ "HSIC_VDDCX");
+ if (IS_ERR(mehci->hsic_vddcx)) {
+ dev_err(mehci->dev, "unable to get hsic vddcx\n");
+ return PTR_ERR(mehci->hsic_vddcx);
+ }
+ mehci->vdd_type = VDDCX;
+ }
+ }
+
+ none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
+ min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
+ max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
if (!init)
goto disable_reg;
- mehci->hsic_vddcx = devm_regulator_get(mehci->dev, "HSIC_VDDCX");
- if (IS_ERR(mehci->hsic_vddcx)) {
- dev_err(mehci->dev, "unable to get hsic vddcx\n");
- return PTR_ERR(mehci->hsic_vddcx);
- }
-
- ret = regulator_set_voltage(mehci->hsic_vddcx,
- USB_PHY_VDD_DIG_VOL_MIN,
- USB_PHY_VDD_DIG_VOL_MAX);
+ ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
if (ret) {
dev_err(mehci->dev, "unable to set the voltage"
"for hsic vddcx\n");
return ret;
}
- ret = regulator_set_optimum_mode(mehci->hsic_vddcx,
- USB_PHY_VDD_DIG_LOAD);
- if (ret < 0) {
- pr_err("%s: Unable to set optimum mode of the regulator:"
- "VDDCX\n", __func__);
- goto reg_optimum_mode_err;
- }
-
ret = regulator_enable(mehci->hsic_vddcx);
if (ret) {
dev_err(mehci->dev, "unable to enable hsic vddcx\n");
@@ -302,10 +322,8 @@
disable_reg:
regulator_disable(mehci->hsic_vddcx);
reg_enable_err:
- regulator_set_optimum_mode(mehci->hsic_vddcx, 0);
-reg_optimum_mode_err:
- regulator_set_voltage(mehci->hsic_vddcx, 0,
- USB_PHY_VDD_DIG_VOL_MIN);
+ regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
+
return ret;
}
@@ -528,6 +546,7 @@
struct usb_hcd *hcd = hsic_to_hcd(mehci);
int cnt = 0, ret;
u32 val;
+ int none_vol, max_vol;
if (atomic_read(&mehci->in_lpm)) {
dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
@@ -593,11 +612,12 @@
clk_disable_unprepare(mehci->cal_clk);
clk_disable_unprepare(mehci->ahb_clk);
- ret = regulator_set_voltage(mehci->hsic_vddcx,
- USB_PHY_VDD_DIG_VOL_SUSP_MIN,
- USB_PHY_VDD_DIG_VOL_MAX);
+ none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
+ max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
+
+ ret = regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
if (ret < 0)
- dev_err(mehci->dev, "unable to set vddcx voltage: min:0.5v max:1.3v\n");
+ dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
if (mehci->bus_perf_client && debug_bus_voting_enabled) {
ret = msm_bus_scale_client_update_request(
@@ -626,6 +646,7 @@
struct usb_hcd *hcd = hsic_to_hcd(mehci);
int cnt = 0, ret;
unsigned temp;
+ int min_vol, max_vol;
if (!atomic_read(&mehci->in_lpm)) {
dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
@@ -648,11 +669,12 @@
"bus bandwidth %d\n", __func__, ret);
}
- ret = regulator_set_voltage(mehci->hsic_vddcx,
- USB_PHY_VDD_DIG_VOL_MIN,
- USB_PHY_VDD_DIG_VOL_MAX);
+ min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
+ max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
+
+ ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
if (ret < 0)
- dev_err(mehci->dev, "unable to set vddcx voltage: min:1v max:1.3v\n");
+ dev_err(mehci->dev, "unable to set nominal vddcx voltage (no VDD MIN)\n");
clk_prepare_enable(mehci->core_clk);
clk_prepare_enable(mehci->phy_clk);
@@ -690,6 +712,13 @@
skip_phy_resume:
+ if (!(readl_relaxed(USB_USBCMD) & CMD_RUN) &&
+ (readl_relaxed(USB_PORTSC) & PORT_SUSPEND)) {
+ writel_relaxed(readl_relaxed(USB_USBCMD) | CMD_RUN ,
+ USB_USBCMD);
+ dbg_log_event(NULL, "Set RS", readl_relaxed(USB_USBCMD));
+ }
+
usb_hcd_resume_root_hub(hcd);
atomic_set(&mehci->in_lpm, 0);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 673ad12..78ece8d 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -343,6 +343,8 @@
/* Write 1 to disable the port */
xhci_writel(xhci, port_status | PORT_PE, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
port_status = xhci_readl(xhci, addr);
xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n",
wIndex, port_status);
@@ -389,6 +391,8 @@
}
/* Change bits are all write 1 to clear */
xhci_writel(xhci, port_status | status, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
port_status = xhci_readl(xhci, addr);
xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
port_change_bit, wIndex, port_status);
@@ -420,6 +424,8 @@
temp &= ~PORT_PLS_MASK;
temp |= PORT_LINK_STROBE | link_state;
xhci_writel(xhci, temp, port_array[port_id]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
@@ -446,6 +452,8 @@
temp &= ~PORT_WKOC_E;
xhci_writel(xhci, temp, port_array[port_id]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
/* Test and clear port RWC bit */
@@ -459,6 +467,8 @@
temp = xhci_port_state_to_neutral(temp);
temp |= port_bit;
xhci_writel(xhci, temp, port_array[port_id]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
}
@@ -721,6 +731,8 @@
*/
xhci_writel(xhci, temp | PORT_POWER,
port_array[wIndex]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
@@ -728,6 +740,8 @@
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
xhci_writel(xhci, temp, port_array[wIndex]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
@@ -743,6 +757,8 @@
case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR;
xhci_writel(xhci, temp, port_array[wIndex]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
temp = xhci_readl(xhci, port_array[wIndex]);
break;
@@ -936,8 +952,11 @@
t2 &= ~PORT_WAKE_BITS;
t1 = xhci_port_state_to_neutral(t1);
- if (t1 != t2)
+ if (t1 != t2) {
xhci_writel(xhci, t2, port_array[port_index]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
+ }
if (hcd->speed != HCD_USB3) {
/* enable remote wake up for USB 2.0 */
@@ -951,6 +970,8 @@
tmp = xhci_readl(xhci, addr);
tmp |= PORT_RWE;
xhci_writel(xhci, tmp, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
}
hcd->state = HC_STATE_SUSPENDED;
@@ -1028,8 +1049,11 @@
xhci, port_index + 1);
if (slot_id)
xhci_ring_device(xhci, slot_id);
- } else
+ } else {
xhci_writel(xhci, temp, port_array[port_index]);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
+ }
if (hcd->speed != HCD_USB3) {
/* disable remote wake up for USB 2.0 */
@@ -1043,6 +1067,8 @@
tmp = xhci_readl(xhci, addr);
tmp &= ~PORT_RWE;
xhci_writel(xhci, tmp, addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
}
}
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index 689bc18..8467dc0 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -14,17 +14,30 @@
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/usb/otg.h>
#include "xhci.h"
+#define SYNOPSIS_DWC3_VENDOR 0x5533
+
+static struct usb_phy *phy;
+
static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
{
+ struct xhci_plat_data *pdata = dev->platform_data;
+
/*
* As of now platform drivers don't provide MSI support so we ensure
* here that the generic code does not try to make a pci_dev from our
* dev struct in order to setup MSI
*/
xhci->quirks |= XHCI_BROKEN_MSI;
+
+ if (!pdata)
+ return;
+ else if (pdata->vendor == SYNOPSIS_DWC3_VENDOR &&
+ pdata->revision < 0x230A)
+ xhci->quirks |= XHCI_PORTSC_DELAY;
}
/* called during probe() after chip reset completes */
@@ -149,6 +162,19 @@
if (ret)
goto put_usb3_hcd;
+ phy = usb_get_transceiver();
+ if (phy && phy->otg) {
+ dev_dbg(&pdev->dev, "%s otg support available\n", __func__);
+ hcd->driver->stop(hcd);
+ ret = otg_set_host(phy->otg, &hcd->self);
+ if (ret) {
+ dev_err(&pdev->dev, "%s otg_set_host failed\n",
+ __func__);
+ usb_put_transceiver(phy);
+ goto put_usb3_hcd;
+ }
+ }
+
return 0;
put_usb3_hcd:
@@ -182,6 +208,11 @@
usb_put_hcd(hcd);
kfree(xhci);
+ if (phy && phy->otg) {
+ otg_set_host(phy->otg, NULL);
+ usb_put_transceiver(phy);
+ }
+
return 0;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 36641a7..2c26998 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -318,16 +318,6 @@
return;
}
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
- int i;
-
- if (xhci->msix_entries) {
- for (i = 0; i < xhci->msix_count; i++)
- synchronize_irq(xhci->msix_entries[i].vector);
- }
-}
-
static int xhci_try_enable_msi(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
@@ -383,11 +373,7 @@
{
}
-static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
-{
-}
-
-#endif
+#endif /* CONFIG_PCI */
/*
* Initialize memory for HCD and xHC (one-time init).
@@ -513,6 +499,13 @@
xhci_dbg(xhci, "xhci_run\n");
+ xhci_dbg(xhci, "Calling HCD init\n");
+ /* Initialize HCD and host controller data structures. */
+ ret = xhci_init(hcd);
+ if (ret)
+ return ret;
+ xhci_dbg(xhci, "Called HCD init\n");
+
ret = xhci_try_enable_msi(hcd);
if (ret)
return ret;
@@ -661,6 +654,23 @@
}
#ifdef CONFIG_PM
+
+#ifdef CONFIG_PCI
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+ int i;
+
+ if (xhci->msix_entries) {
+ for (i = 0; i < xhci->msix_count; i++)
+ synchronize_irq(xhci->msix_entries[i].vector);
+ }
+}
+#else
+static void xhci_msix_sync_irqs(struct xhci_hcd *xhci)
+{
+}
+#endif /* CONFIG_PCI */
+
static void xhci_save_registers(struct xhci_hcd *xhci)
{
xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command);
@@ -3712,6 +3722,8 @@
hird = xhci_calculate_hird_besl(xhci, udev);
temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
xhci_writel(xhci, temp, pm_addr);
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ ndelay(100);
/* Set port link state to U2(L1) */
addr = port_array[port_num];
@@ -3789,6 +3801,7 @@
unsigned int port_num;
unsigned long flags;
int hird;
+ bool delay;
if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
!udev->lpm_capable)
@@ -3801,6 +3814,9 @@
if (udev->usb2_hw_lpm_capable != 1)
return -EPERM;
+ if (xhci->quirks & XHCI_PORTSC_DELAY)
+ delay = true;
+
spin_lock_irqsave(&xhci->lock, flags);
port_array = xhci->usb2_ports;
@@ -3817,12 +3833,18 @@
temp &= ~PORT_HIRD_MASK;
temp |= PORT_HIRD(hird) | PORT_RWE;
xhci_writel(xhci, temp, pm_addr);
+ if (delay)
+ ndelay(100);
temp = xhci_readl(xhci, pm_addr);
temp |= PORT_HLE;
xhci_writel(xhci, temp, pm_addr);
+ if (delay)
+ ndelay(100);
} else {
temp &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK);
xhci_writel(xhci, temp, pm_addr);
+ if (delay)
+ ndelay(100);
}
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -4043,12 +4065,6 @@
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
}
- xhci_dbg(xhci, "Calling HCD init\n");
- /* Initialize HCD and host controller data structures. */
- retval = xhci_init(hcd);
- if (retval)
- goto error;
- xhci_dbg(xhci, "Called HCD init\n");
return 0;
error:
kfree(xhci);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3d69c4b..127b0e9 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1479,6 +1479,21 @@
#define XHCI_RESET_ON_RESUME (1 << 7)
#define XHCI_SW_BW_CHECKING (1 << 8)
#define XHCI_AMD_0x96_HOST (1 << 9)
+/*
+ * In Synopsis DWC3 controller, PORTSC register access involves multiple clock
+ * domains. When the software does a PORTSC write, handshakes are needed
+ * across these clock domains. This results in long access times, especially
+ * for USB 2.0 ports. In order to solve this issue, when the PORTSC write
+ * operations happen on the system bus, the command is latched and system bus
+ * is released immediately. However, the real PORTSC write access will take
+ * some time internally to complete. If the software quickly does a read to the
+ * PORTSC, some fields (port status change related fields like OCC, etc.) may
+ * not have correct value due to the current way of handling these bits.
+ *
+ * The workaround is to give some delay (5 mac2_clk -> UTMI clock = 60 MHz ->
+ * (16.66 ns x 5 = 84ns) ~100ns after writing to the PORTSC register.
+ */
+#define XHCI_PORTSC_DELAY (1 << 10)
unsigned int num_active_eps;
unsigned int limit_active_eps;
/* There are two roothubs to keep track of bus suspend info for */
@@ -1667,6 +1682,11 @@
static inline void xhci_unregister_pci(void) {}
#endif
+struct xhci_plat_data {
+ unsigned vendor;
+ unsigned revision;
+};
+
#if defined(CONFIG_USB_XHCI_PLATFORM) \
|| defined(CONFIG_USB_XHCI_PLATFORM_MODULE)
int xhci_register_plat(void);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 96e5a90..8b762a2 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -11,6 +11,9 @@
* GNU General Public License for more details.
*/
+/* add additional information to our printk's */
+#define pr_fmt(fmt) "%s: " fmt "\n", __func__
+
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -18,6 +21,7 @@
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/platform_device.h>
+#include <linux/ratelimit.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/debugfs.h>
@@ -50,26 +54,37 @@
struct diag_bridge *dev = __dev;
if (!dev) {
- err("dev is null");
+ pr_err("dev is null");
return -ENODEV;
}
dev->ops = ops;
dev->err = 0;
+ kref_get(&dev->kref);
+
return 0;
}
EXPORT_SYMBOL(diag_bridge_open);
+static void diag_bridge_delete(struct kref *kref)
+{
+ struct diag_bridge *dev = container_of(kref, struct diag_bridge, kref);
+
+ usb_put_dev(dev->udev);
+ __dev = 0;
+ kfree(dev);
+}
+
void diag_bridge_close(void)
{
struct diag_bridge *dev = __dev;
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
usb_kill_anchored_urbs(&dev->submitted);
-
dev->ops = 0;
+ kref_put(&dev->kref, diag_bridge_delete);
}
EXPORT_SYMBOL(diag_bridge_close);
@@ -78,13 +93,14 @@
struct diag_bridge *dev = urb->context;
struct diag_bridge_ops *cbs = dev->ops;
- dev_dbg(&dev->udev->dev, "%s: status:%d actual:%d\n", __func__,
+ dev_dbg(&dev->ifc->dev, "%s: status:%d actual:%d\n", __func__,
urb->status, urb->actual_length);
if (urb->status == -EPROTO) {
- dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
- /* save error so that subsequent read/write returns ESHUTDOWN */
+ dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
+ /* save error so that subsequent read/write returns ENODEV */
dev->err = urb->status;
+ kref_put(&dev->kref, diag_bridge_delete);
return;
}
@@ -96,6 +112,7 @@
dev->bytes_to_host += urb->actual_length;
dev->pending_reads--;
+ kref_put(&dev->kref, diag_bridge_delete);
}
int diag_bridge_read(char *data, int size)
@@ -105,33 +122,40 @@
struct diag_bridge *dev = __dev;
int ret;
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ pr_debug("reading %d bytes", size);
- if (!size) {
- dev_err(&dev->udev->dev, "invalid size:%d\n", size);
- return -EINVAL;
+ if (!dev || !dev->ifc) {
+ pr_err("device is disconnected");
+ return -ENODEV;
}
- if (!dev->ifc) {
- dev_err(&dev->udev->dev, "device is disconnected\n");
+ if (!dev->ops) {
+ pr_err("bridge is not open");
return -ENODEV;
}
+ if (!size) {
+ dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
+ return -EINVAL;
+ }
+
/* if there was a previous unrecoverable error, just quit */
if (dev->err)
- return -ESHUTDOWN;
+ return -ENODEV;
+
+ kref_get(&dev->kref);
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- dev_err(&dev->udev->dev, "unable to allocate urb\n");
- return -ENOMEM;
+ dev_err(&dev->ifc->dev, "unable to allocate urb\n");
+ ret = -ENOMEM;
+ goto error;
}
ret = usb_autopm_get_interface(dev->ifc);
- if (ret < 0) {
- dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
- usb_free_urb(urb);
- return ret;
+ if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
+ pr_err_ratelimited("read: autopm_get failed:%d", ret);
+ goto free_error;
}
pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
@@ -142,18 +166,18 @@
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
- dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
+ pr_err_ratelimited("submitting urb failed err:%d", ret);
dev->pending_reads--;
usb_unanchor_urb(urb);
- usb_free_urb(urb);
- usb_autopm_put_interface(dev->ifc);
- return ret;
}
-
usb_autopm_put_interface(dev->ifc);
- usb_free_urb(urb);
- return 0;
+free_error:
+ usb_free_urb(urb);
+error:
+ if (ret) /* otherwise this is done in the completion handler */
+ kref_put(&dev->kref, diag_bridge_delete);
+ return ret;
}
EXPORT_SYMBOL(diag_bridge_read);
@@ -162,14 +186,15 @@
struct diag_bridge *dev = urb->context;
struct diag_bridge_ops *cbs = dev->ops;
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
usb_autopm_put_interface_async(dev->ifc);
if (urb->status == -EPROTO) {
- dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
- /* save error so that subsequent read/write returns ESHUTDOWN */
+ dev_err(&dev->ifc->dev, "%s: proto error\n", __func__);
+ /* save error so that subsequent read/write returns ENODEV */
dev->err = urb->status;
+ kref_put(&dev->kref, diag_bridge_delete);
return;
}
@@ -181,6 +206,7 @@
dev->bytes_to_mdm += urb->actual_length;
dev->pending_writes--;
+ kref_put(&dev->kref, diag_bridge_delete);
}
int diag_bridge_write(char *data, int size)
@@ -190,33 +216,40 @@
struct diag_bridge *dev = __dev;
int ret;
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ pr_debug("writing %d bytes", size);
- if (!size) {
- dev_err(&dev->udev->dev, "invalid size:%d\n", size);
- return -EINVAL;
+ if (!dev || !dev->ifc) {
+ pr_err("device is disconnected");
+ return -ENODEV;
}
- if (!dev->ifc) {
- dev_err(&dev->udev->dev, "device is disconnected\n");
+ if (!dev->ops) {
+ pr_err("bridge is not open");
return -ENODEV;
}
+ if (!size) {
+ dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
+ return -EINVAL;
+ }
+
/* if there was a previous unrecoverable error, just quit */
if (dev->err)
- return -ESHUTDOWN;
+ return -ENODEV;
+
+ kref_get(&dev->kref);
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- err("unable to allocate urb");
- return -ENOMEM;
+ dev_err(&dev->ifc->dev, "unable to allocate urb\n");
+ ret = -ENOMEM;
+ goto error;
}
ret = usb_autopm_get_interface(dev->ifc);
- if (ret < 0) {
- dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
- usb_free_urb(urb);
- return ret;
+ if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
+ pr_err_ratelimited("write: autopm_get failed:%d", ret);
+ goto free_error;
}
pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
@@ -227,30 +260,22 @@
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
- dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
+ pr_err_ratelimited("submitting urb failed err:%d", ret);
dev->pending_writes--;
usb_unanchor_urb(urb);
- usb_free_urb(urb);
usb_autopm_put_interface(dev->ifc);
- return ret;
+ goto free_error;
}
+free_error:
usb_free_urb(urb);
-
- return 0;
+error:
+ if (ret) /* otherwise this is done in the completion handler */
+ kref_put(&dev->kref, diag_bridge_delete);
+ return ret;
}
EXPORT_SYMBOL(diag_bridge_write);
-static void diag_bridge_delete(struct kref *kref)
-{
- struct diag_bridge *dev =
- container_of(kref, struct diag_bridge, kref);
-
- usb_put_dev(dev->udev);
- __dev = 0;
- kfree(dev);
-}
-
#if defined(CONFIG_DEBUG_FS)
#define DEBUG_BUF_SIZE 512
static ssize_t diag_read_stats(struct file *file, char __user *ubuf,
@@ -260,6 +285,9 @@
char *buf;
int ret;
+ if (!dev)
+ return -ENODEV;
+
buf = kzalloc(sizeof(char) * DEBUG_BUF_SIZE, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -286,8 +314,10 @@
{
struct diag_bridge *dev = __dev;
- dev->bytes_to_host = dev->bytes_to_mdm = 0;
- dev->pending_reads = dev->pending_writes = 0;
+ if (dev) {
+ dev->bytes_to_host = dev->bytes_to_mdm = 0;
+ dev->pending_reads = dev->pending_writes = 0;
+ }
return count;
}
@@ -334,7 +364,7 @@
int ret = -ENOMEM;
__u8 ifc_num;
- dbg("%s: id:%lu", __func__, id->driver_info);
+ pr_debug("id:%lu", id->driver_info);
ifc_num = ifc->cur_altsetting->desc.bInterfaceNumber;
@@ -344,12 +374,12 @@
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- pr_err("%s: unable to allocate dev\n", __func__);
+ pr_err("unable to allocate dev");
return -ENOMEM;
}
dev->pdev = platform_device_alloc("diag_bridge", -1);
if (!dev->pdev) {
- pr_err("%s: unable to allocate platform device\n", __func__);
+ pr_err("unable to allocate platform device");
kfree(dev);
return -ENOMEM;
}
@@ -372,7 +402,7 @@
}
if (!(dev->in_epAddr && dev->out_epAddr)) {
- err("could not find bulk in and bulk out endpoints");
+ pr_err("could not find bulk in and bulk out endpoints");
ret = -ENODEV;
goto error;
}
@@ -381,7 +411,7 @@
diag_bridge_debugfs_init();
platform_device_add(dev->pdev);
- dev_dbg(&dev->udev->dev, "%s: complete\n", __func__);
+ dev_dbg(&dev->ifc->dev, "%s: complete\n", __func__);
return 0;
@@ -396,9 +426,10 @@
{
struct diag_bridge *dev = usb_get_intfdata(ifc);
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ dev_dbg(&dev->ifc->dev, "%s:\n", __func__);
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
+ dev->ifc = NULL;
diag_bridge_debugfs_cleanup();
kref_put(&dev->kref, diag_bridge_delete);
usb_set_intfdata(ifc, NULL);
@@ -413,7 +444,7 @@
if (cbs && cbs->suspend) {
ret = cbs->suspend(cbs->ctxt);
if (ret) {
- dev_dbg(&dev->udev->dev,
+ dev_dbg(&dev->ifc->dev,
"%s: diag veto'd suspend\n", __func__);
return ret;
}
@@ -467,7 +498,7 @@
ret = usb_register(&diag_bridge_driver);
if (ret) {
- err("%s: unable to register diag driver", __func__);
+ pr_err("unable to register diag driver");
return ret;
}
diff --git a/drivers/usb/misc/mdm_ctrl_bridge.c b/drivers/usb/misc/mdm_ctrl_bridge.c
index 49591cd..e685233 100644
--- a/drivers/usb/misc/mdm_ctrl_bridge.c
+++ b/drivers/usb/misc/mdm_ctrl_bridge.c
@@ -128,12 +128,10 @@
static void resp_avail_cb(struct urb *urb)
{
struct ctrl_bridge *dev = urb->context;
- struct usb_device *udev;
int status = 0;
int resubmit_urb = 1;
struct bridge *brdg = dev->brdg;
- udev = interface_to_usbdev(dev->intf);
switch (urb->status) {
case 0:
/*success*/
@@ -154,7 +152,7 @@
/*resubmit*/
case -EOVERFLOW:
default:
- dev_dbg(&udev->dev, "%s: non zero urb status = %d\n",
+ dev_dbg(&dev->intf->dev, "%s: non zero urb status = %d\n",
__func__, urb->status);
}
@@ -163,7 +161,7 @@
usb_anchor_urb(dev->inturb, &dev->tx_submitted);
status = usb_submit_urb(dev->inturb, GFP_ATOMIC);
if (status) {
- dev_err(&udev->dev,
+ dev_err(&dev->intf->dev,
"%s: Error re-submitting Int URB %d\n",
__func__, status);
usb_unanchor_urb(dev->inturb);
@@ -175,14 +173,11 @@
{
int status;
struct usb_cdc_notification *ctrl;
- struct usb_device *udev;
struct ctrl_bridge *dev = urb->context;
struct bridge *brdg = dev->brdg;
unsigned int ctrl_bits;
unsigned char *data;
- udev = interface_to_usbdev(dev->intf);
-
switch (urb->status) {
case 0:
/*success*/
@@ -194,7 +189,8 @@
/* unplug */
return;
case -EPIPE:
- dev_err(&udev->dev, "%s: stall on int endpoint\n", __func__);
+ dev_err(&dev->intf->dev,
+ "%s: stall on int endpoint\n", __func__);
/* TBD : halt to be cleared in work */
case -EOVERFLOW:
default:
@@ -209,8 +205,8 @@
switch (ctrl->bNotificationType) {
case USB_CDC_NOTIFY_RESPONSE_AVAILABLE:
dev->resp_avail++;
- usb_fill_control_urb(dev->readurb, udev,
- usb_rcvctrlpipe(udev, 0),
+ usb_fill_control_urb(dev->readurb, dev->udev,
+ usb_rcvctrlpipe(dev->udev, 0),
(unsigned char *)dev->in_ctlreq,
dev->readbuf,
DEFAULT_READ_URB_LENGTH,
@@ -219,7 +215,7 @@
usb_anchor_urb(dev->readurb, &dev->tx_submitted);
status = usb_submit_urb(dev->readurb, GFP_ATOMIC);
if (status) {
- dev_err(&udev->dev,
+ dev_err(&dev->intf->dev,
"%s: Error submitting Read URB %d\n",
__func__, status);
usb_unanchor_urb(dev->readurb);
@@ -227,19 +223,19 @@
}
return;
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
- dev_dbg(&udev->dev, "%s network\n", ctrl->wValue ?
+ dev_dbg(&dev->intf->dev, "%s network\n", ctrl->wValue ?
"connected to" : "disconnected from");
break;
case USB_CDC_NOTIFY_SERIAL_STATE:
dev->notify_ser_state++;
ctrl_bits = get_unaligned_le16(data);
- dev_dbg(&udev->dev, "serial state: %d\n", ctrl_bits);
+ dev_dbg(&dev->intf->dev, "serial state: %d\n", ctrl_bits);
dev->cbits_tohost = ctrl_bits;
if (brdg && brdg->ops.send_cbits)
brdg->ops.send_cbits(brdg->ctx, ctrl_bits);
break;
default:
- dev_err(&udev->dev, "%s: unknown notification %d received:"
+ dev_err(&dev->intf->dev, "%s: unknown notification %d received:"
"index %d len %d data0 %d data1 %d",
__func__, ctrl->bNotificationType, ctrl->wIndex,
ctrl->wLength, data[0], data[1]);
@@ -249,7 +245,7 @@
usb_anchor_urb(urb, &dev->tx_submitted);
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- dev_err(&udev->dev, "%s: Error re-submitting Int URB %d\n",
+ dev_err(&dev->intf->dev, "%s: Error re-submitting Int URB %d\n",
__func__, status);
usb_unanchor_urb(urb);
}
@@ -260,7 +256,7 @@
int retval = 0;
if (!dev->inturb) {
- dev_err(&dev->udev->dev, "%s: inturb is NULL\n", __func__);
+ dev_err(&dev->intf->dev, "%s: inturb is NULL\n", __func__);
return -ENODEV;
}
@@ -268,7 +264,7 @@
usb_anchor_urb(dev->inturb, &dev->tx_submitted);
retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
if (retval < 0) {
- dev_err(&dev->udev->dev,
+ dev_err(&dev->intf->dev,
"%s error submitting int urb %d\n",
__func__, retval);
usb_unanchor_urb(dev->inturb);
@@ -321,7 +317,7 @@
if (!dev || !dev->brdg)
return;
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ dev_dbg(&dev->intf->dev, "%s:\n", __func__);
ctrl_bridge_set_cbits(dev->brdg->ch_id, 0);
usb_unlink_anchored_urbs(&dev->tx_submitted);
@@ -350,7 +346,6 @@
int result;
struct urb *writeurb;
struct usb_ctrlrequest *out_ctlreq;
- struct usb_device *udev;
struct ctrl_bridge *dev;
if (id >= MAX_BRIDGE_DEVICES) {
@@ -365,14 +360,12 @@
goto free_data;
}
- udev = interface_to_usbdev(dev->intf);
-
- dev_dbg(&udev->dev, "%s:[id]:%u: write (%d bytes)\n",
+ dev_dbg(&dev->intf->dev, "%s:[id]:%u: write (%d bytes)\n",
__func__, id, size);
writeurb = usb_alloc_urb(0, GFP_ATOMIC);
if (!writeurb) {
- dev_err(&udev->dev, "%s: error allocating read urb\n",
+ dev_err(&dev->intf->dev, "%s: error allocating read urb\n",
__func__);
result = -ENOMEM;
goto free_data;
@@ -380,7 +373,7 @@
out_ctlreq = kmalloc(sizeof(*out_ctlreq), GFP_ATOMIC);
if (!out_ctlreq) {
- dev_err(&udev->dev,
+ dev_err(&dev->intf->dev,
"%s: error allocating setup packet buffer\n",
__func__);
result = -ENOMEM;
@@ -403,15 +396,15 @@
dev->intf->cur_altsetting->desc.bInterfaceNumber;
out_ctlreq->wLength = cpu_to_le16(size);
- usb_fill_control_urb(writeurb, udev,
- usb_sndctrlpipe(udev, 0),
+ usb_fill_control_urb(writeurb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
(unsigned char *)out_ctlreq,
(void *)data, size,
ctrl_write_callback, dev);
result = usb_autopm_get_interface_async(dev->intf);
if (result < 0) {
- dev_err(&udev->dev, "%s: unable to resume interface: %d\n",
+ dev_err(&dev->intf->dev, "%s: unable to resume interface: %d\n",
__func__, result);
/*
@@ -430,7 +423,7 @@
usb_anchor_urb(writeurb, &dev->tx_submitted);
result = usb_submit_urb(writeurb, GFP_ATOMIC);
if (result < 0) {
- dev_err(&udev->dev, "%s: submit URB error %d\n",
+ dev_err(&dev->intf->dev, "%s: submit URB error %d\n",
__func__, result);
usb_autopm_put_interface_async(dev->intf);
goto unanchor_urb;
@@ -614,14 +607,14 @@
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
- dev_err(&udev->dev, "%s: unable to allocate dev\n",
+ dev_err(&ifc->dev, "%s: unable to allocate dev\n",
__func__);
return -ENOMEM;
}
dev->pdev = platform_device_alloc(ctrl_bridge_names[id], id);
if (!dev->pdev) {
- dev_err(&dev->udev->dev,
- "%s: unable to allocate platform device\n", __func__);
+ dev_err(&ifc->dev, "%s: unable to allocate platform device\n",
+ __func__);
retval = -ENOMEM;
goto nomem;
}
@@ -639,7 +632,7 @@
dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->inturb) {
- dev_err(&udev->dev, "%s: error allocating int urb\n", __func__);
+ dev_err(&ifc->dev, "%s: error allocating int urb\n", __func__);
retval = -ENOMEM;
goto pdev_del;
}
@@ -648,7 +641,7 @@
dev->intbuf = kmalloc(wMaxPacketSize, GFP_KERNEL);
if (!dev->intbuf) {
- dev_err(&udev->dev, "%s: error allocating int buffer\n",
+ dev_err(&ifc->dev, "%s: error allocating int buffer\n",
__func__);
retval = -ENOMEM;
goto free_inturb;
@@ -663,7 +656,7 @@
dev->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->readurb) {
- dev_err(&udev->dev, "%s: error allocating read urb\n",
+ dev_err(&ifc->dev, "%s: error allocating read urb\n",
__func__);
retval = -ENOMEM;
goto free_intbuf;
@@ -671,7 +664,7 @@
dev->readbuf = kmalloc(DEFAULT_READ_URB_LENGTH, GFP_KERNEL);
if (!dev->readbuf) {
- dev_err(&udev->dev, "%s: error allocating read buffer\n",
+ dev_err(&ifc->dev, "%s: error allocating read buffer\n",
__func__);
retval = -ENOMEM;
goto free_rurb;
@@ -679,8 +672,7 @@
dev->in_ctlreq = kmalloc(sizeof(*dev->in_ctlreq), GFP_KERNEL);
if (!dev->in_ctlreq) {
- dev_err(&udev->dev,
- "%s:error allocating setup packet buffer\n",
+ dev_err(&ifc->dev, "%s:error allocating setup packet buffer\n",
__func__);
retval = -ENOMEM;
goto free_rbuf;
@@ -711,7 +703,7 @@
free_inturb:
usb_free_urb(dev->inturb);
pdev_del:
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
nomem:
kfree(dev);
@@ -722,9 +714,9 @@
{
struct ctrl_bridge *dev = __dev[id];
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ dev_dbg(&dev->intf->dev, "%s:\n", __func__);
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
kfree(dev->in_ctlreq);
kfree(dev->readbuf);
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index bf8e5f4..db2f40a 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -208,7 +208,7 @@
/*do not resubmit*/
case -EPIPE:
set_bit(RX_HALT, &dev->flags);
- dev_err(&dev->udev->dev, "%s: epout halted\n", __func__);
+ dev_err(&dev->intf->dev, "%s: epout halted\n", __func__);
schedule_work(&dev->kevent);
/* FALLTHROUGH */
case -ESHUTDOWN:
@@ -309,7 +309,7 @@
return -ENODEV;
}
- dev_dbg(&dev->udev->dev, "%s: dev:%p\n", __func__, dev);
+ dev_dbg(&dev->intf->dev, "%s: dev:%p\n", __func__, dev);
dev->brdg = brdg;
dev->err = 0;
@@ -341,7 +341,7 @@
if (!dev || !dev->brdg)
return;
- dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ dev_dbg(&dev->intf->dev, "%s:\n", __func__);
usb_unlink_anchored_urbs(&dev->tx_active);
usb_unlink_anchored_urbs(&dev->rx_active);
@@ -370,7 +370,7 @@
status = usb_autopm_get_interface(dev->intf);
if (status < 0) {
- dev_err(&dev->udev->dev,
+ dev_err(&dev->intf->dev,
"can't acquire interface, status %d\n", status);
return;
}
@@ -378,7 +378,7 @@
status = usb_clear_halt(dev->udev, dev->bulk_out);
usb_autopm_put_interface(dev->intf);
if (status < 0 && status != -EPIPE && status != -ESHUTDOWN)
- dev_err(&dev->udev->dev,
+ dev_err(&dev->intf->dev,
"can't clear tx halt, status %d\n", status);
else
clear_bit(TX_HALT, &dev->flags);
@@ -389,7 +389,7 @@
status = usb_autopm_get_interface(dev->intf);
if (status < 0) {
- dev_err(&dev->udev->dev,
+ dev_err(&dev->intf->dev,
"can't acquire interface, status %d\n", status);
return;
}
@@ -397,7 +397,7 @@
status = usb_clear_halt(dev->udev, dev->bulk_in);
usb_autopm_put_interface(dev->intf);
if (status < 0 && status != -EPIPE && status != -ESHUTDOWN)
- dev_err(&dev->udev->dev,
+ dev_err(&dev->intf->dev,
"can't clear rx halt, status %d\n", status);
else {
clear_bit(RX_HALT, &dev->flags);
@@ -426,7 +426,7 @@
break;
case -EPIPE:
set_bit(TX_HALT, &dev->flags);
- dev_err(&dev->udev->dev, "%s: epout halted\n", __func__);
+ dev_err(&dev->intf->dev, "%s: epout halted\n", __func__);
schedule_work(&dev->kevent);
/* FALLTHROUGH */
case -ESHUTDOWN:
@@ -474,17 +474,17 @@
if (!brdg)
return -ENODEV;
- dev_dbg(&dev->udev->dev, "%s: write (%d bytes)\n", __func__, skb->len);
+ dev_dbg(&dev->intf->dev, "%s: write (%d bytes)\n", __func__, skb->len);
result = usb_autopm_get_interface(dev->intf);
if (result < 0) {
- dev_err(&dev->udev->dev, "%s: resume failure\n", __func__);
- goto error;
+ dev_err(&dev->intf->dev, "%s: resume failure\n", __func__);
+ goto pm_error;
}
txurb = usb_alloc_urb(0, GFP_KERNEL);
if (!txurb) {
- dev_err(&dev->udev->dev, "%s: error allocating read urb\n",
+ dev_err(&dev->intf->dev, "%s: error allocating read urb\n",
__func__);
result = -ENOMEM;
goto error;
@@ -512,13 +512,13 @@
if (result < 0) {
usb_unanchor_urb(txurb);
atomic_dec(&dev->pending_txurbs);
- dev_err(&dev->udev->dev, "%s: submit URB error %d\n",
+ dev_err(&dev->intf->dev, "%s: submit URB error %d\n",
__func__, result);
goto free_urb;
}
dev->to_modem++;
- dev_dbg(&dev->udev->dev, "%s: pending_txurbs: %u\n", __func__, pending);
+ dev_dbg(&dev->intf->dev, "%s: pending_txurbs: %u\n", __func__, pending);
/* flow control: last urb submitted but return -EBUSY */
if (fctrl_support && pending > fctrl_en_thld) {
@@ -536,7 +536,7 @@
error:
dev->txurb_drp_cnt++;
usb_autopm_put_interface(dev->intf);
-
+pm_error:
return result;
}
EXPORT_SYMBOL(data_bridge_write);
@@ -918,17 +918,17 @@
return -EINVAL;
}
- udev = interface_to_usbdev(iface);
- usb_get_dev(udev);
-
if (!test_bit(iface_num, &id->driver_info))
return -ENODEV;
+ udev = interface_to_usbdev(iface);
+ usb_get_dev(udev);
+
numends = iface->cur_altsetting->desc.bNumEndpoints;
for (i = 0; i < numends; i++) {
endpoint = iface->cur_altsetting->endpoint + i;
if (!endpoint) {
- dev_err(&udev->dev, "%s: invalid endpoint %u\n",
+ dev_err(&iface->dev, "%s: invalid endpoint %u\n",
__func__, i);
status = -EINVAL;
goto out;
@@ -943,20 +943,20 @@
}
if (!bulk_in || !bulk_out || !int_in) {
- dev_err(&udev->dev, "%s: invalid endpoints\n", __func__);
+ dev_err(&iface->dev, "%s: invalid endpoints\n", __func__);
status = -EINVAL;
goto out;
}
status = data_bridge_probe(iface, bulk_in, bulk_out, ch_id);
if (status < 0) {
- dev_err(&udev->dev, "data_bridge_probe failed %d\n", status);
+ dev_err(&iface->dev, "data_bridge_probe failed %d\n", status);
goto out;
}
status = ctrl_bridge_probe(iface, int_in, ch_id);
if (status < 0) {
- dev_err(&udev->dev, "ctrl_bridge_probe failed %d\n", status);
+ dev_err(&iface->dev, "ctrl_bridge_probe failed %d\n", status);
goto free_data_bridge;
}
@@ -965,7 +965,7 @@
return 0;
free_data_bridge:
- platform_device_del(__dev[ch_id]->pdev);
+ platform_device_unregister(__dev[ch_id]->pdev);
usb_set_intfdata(iface, NULL);
kfree(__dev[ch_id]);
__dev[ch_id] = NULL;
@@ -989,7 +989,7 @@
ch_id--;
ctrl_bridge_disconnect(ch_id);
- platform_device_del(dev->pdev);
+ platform_device_unregister(dev->pdev);
usb_set_intfdata(intf, NULL);
__dev[ch_id] = NULL;
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 59f01f6..c0f9346 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -87,13 +87,6 @@
#endif
}
-enum usb_vdd_value {
- VDD_NONE = 0,
- VDD_MIN,
- VDD_MAX,
- VDD_VAL_MAX,
-};
-
static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
{ /* VDD_CX CORNER Voting */
[VDD_NONE] = RPM_VREG_CORNER_NONE,
@@ -838,10 +831,14 @@
clk_disable_unprepare(motg->core_clk);
/* usb phy no more require TCXO clock, hence vote for TCXO disable */
- ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
- if (ret)
- dev_err(phy->dev, "%s failed to devote for "
- "TCXO D0 buffer%d\n", __func__, ret);
+ if (!host_bus_suspend) {
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_OFF);
+ if (ret)
+ dev_err(phy->dev, "%s failed to devote for "
+ "TCXO D0 buffer%d\n", __func__, ret);
+ else
+ motg->lpm_flags |= XO_SHUTDOWN;
+ }
if (motg->caps & ALLOW_PHY_POWER_COLLAPSE &&
!host_bus_suspend && !dcp) {
@@ -886,10 +883,13 @@
wake_lock(&motg->wlock);
/* Vote for TCXO when waking up the phy */
- ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
- if (ret)
- dev_err(phy->dev, "%s failed to vote for "
- "TCXO D0 buffer%d\n", __func__, ret);
+ if (motg->lpm_flags & XO_SHUTDOWN) {
+ ret = msm_xo_mode_vote(motg->xo_handle, MSM_XO_MODE_ON);
+ if (ret)
+ dev_err(phy->dev, "%s failed to vote for "
+ "TCXO D0 buffer%d\n", __func__, ret);
+ motg->lpm_flags &= ~XO_SHUTDOWN;
+ }
clk_prepare_enable(motg->core_clk);
diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h
index de8d490..9811a82 100644
--- a/drivers/usb/serial/usb-wwan.h
+++ b/drivers/usb/serial/usb-wwan.h
@@ -53,6 +53,7 @@
u8 *out_buffer[N_OUT_URB];
unsigned long out_busy; /* Bit vector of URBs in use */
int opened;
+ struct usb_anchor submitted;
struct usb_anchor delayed;
/* Settings for the port */
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 519af39..0c58554 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -252,10 +252,12 @@
} else {
intfdata->in_flight++;
spin_unlock_irqrestore(&intfdata->susp_lock, flags);
+ usb_anchor_urb(this_urb, &portdata->submitted);
err = usb_submit_urb(this_urb, GFP_ATOMIC);
if (err) {
dbg("usb_submit_urb %p (write bulk) failed "
"(%d)", this_urb, err);
+ usb_unanchor_urb(this_urb);
clear_bit(i, &portdata->out_busy);
spin_lock_irqsave(&intfdata->susp_lock, flags);
intfdata->in_flight--;
@@ -281,6 +283,7 @@
{
int err;
int endpoint;
+ struct usb_wwan_port_private *portdata;
struct usb_serial_port *port;
struct tty_struct *tty;
unsigned char *data = urb->transfer_buffer;
@@ -290,6 +293,7 @@
endpoint = usb_pipeendpoint(urb->pipe);
port = urb->context;
+ portdata = usb_get_serial_port_data(port);
if (status) {
dbg("%s: nonzero status: %d on endpoint %02x.",
@@ -308,8 +312,10 @@
/* Resubmit urb so we continue receiving */
if (status != -ESHUTDOWN) {
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
+ usb_unanchor_urb(urb);
if (err != -EPERM) {
printk(KERN_ERR "%s: resubmit read urb failed. "
"(%d)", __func__, err);
@@ -418,8 +424,10 @@
urb = portdata->in_urbs[i];
if (!urb)
continue;
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err) {
+ usb_unanchor_urb(urb);
dbg("%s: submit urb %d failed (%d) %d",
__func__, i, err, urb->transfer_buffer_length);
}
@@ -551,6 +559,7 @@
return 1;
}
init_usb_anchor(&portdata->delayed);
+ init_usb_anchor(&portdata->submitted);
for (j = 0; j < N_IN_URB; j++) {
buffer = kmalloc(IN_BUFLEN, GFP_KERNEL);
@@ -590,7 +599,7 @@
static void stop_read_write_urbs(struct usb_serial *serial)
{
- int i, j;
+ int i;
struct usb_serial_port *port;
struct usb_wwan_port_private *portdata;
@@ -598,10 +607,7 @@
for (i = 0; i < serial->num_ports; ++i) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
- for (j = 0; j < N_IN_URB; j++)
- usb_kill_urb(portdata->in_urbs[j]);
- for (j = 0; j < N_OUT_URB; j++)
- usb_kill_urb(portdata->out_urbs[j]);
+ usb_kill_anchored_urbs(&portdata->submitted);
}
}
@@ -694,10 +700,12 @@
portdata = usb_get_serial_port_data(port);
data = port->serial->private;
while ((urb = usb_get_from_anchor(&portdata->delayed))) {
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (!err) {
data->in_flight++;
} else {
+ usb_unanchor_urb(urb);
/* we have to throw away the rest */
do {
unbusy_queued_urb(urb, portdata);
@@ -736,33 +744,32 @@
spin_lock_irq(&intfdata->susp_lock);
intfdata->suspended = 0;
- spin_unlock_irq(&intfdata->susp_lock);
-
for (i = 0; i < serial->num_ports; i++) {
/* walk all ports */
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
/* skip closed ports */
- spin_lock_irq(&intfdata->susp_lock);
- if (!portdata->opened) {
- spin_unlock_irq(&intfdata->susp_lock);
+ if (!portdata->opened)
continue;
- }
for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j];
+ usb_anchor_urb(urb, &portdata->submitted);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
err("%s: Error %d for bulk URB %d",
__func__, err, i);
+ usb_unanchor_urb(urb);
+ intfdata->suspended = 1;
spin_unlock_irq(&intfdata->susp_lock);
goto err_out;
}
}
play_delayed(port);
- spin_unlock_irq(&intfdata->susp_lock);
}
+ spin_unlock_irq(&intfdata->susp_lock);
+
err_out:
return err;
}
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index b8d1df8..7e078ab 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -84,6 +84,16 @@
Support for MSM MDP HW revision 4.0
Say Y here if this is msm7x30 variant platform.
+config FB_MSM_MDSS
+ bool "MDSS HW"
+ ---help---
+ The Mobile Display Sub System (MDSS) driver supports devices which
+ contain MDSS hardware block.
+
+ The MDSS driver implements frame buffer interface to provide access to
+ the display hardware and provide a way for users to display graphics
+ on connected display panels.
+
config FB_MSM_MDP_NONE
bool "MDP HW None"
---help---
@@ -297,6 +307,11 @@
select FB_MSM_LVDS
default n
+config FB_MSM_LVDS_FRC_FHD
+ bool
+ select FB_MSM_LVDS
+ default n
+
config FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
bool
select FB_MSM_MIPI_DSI_TOSHIBA
@@ -490,6 +505,15 @@
---help---
Support for LVDS Chimei WXGA(1366x768) panel
+config FB_MSM_LVDS_FRC_FHD_PANEL
+ bool "LVDS FRC FHD Panel"
+ select FB_MSM_LVDS_FRC_FHD
+ ---help---
+ Support for LVDS Frc FHD(1920x1080) panel
+ FRC(Frame Rate Converter) uses LVDS as input
+ interface. It is treated as a HDMI panel with
+ 1920x1080 resolution.
+
config FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
depends on FB_MSM_LCDC_HW
bool "MDDI Panel Auto Detect + LCDC Prism WVGA"
@@ -568,6 +592,7 @@
config FB_MSM_LVDS_MIPI_PANEL_DETECT
bool "LVDS + MIPI Panel Auto Detect"
select FB_MSM_LVDS_CHIMEI_WXGA
+ select FB_MSM_LVDS_FRC_FHD
select FB_MSM_MIPI_TOSHIBA_VIDEO_WVGA_PT
select FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT
select FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA
@@ -921,4 +946,8 @@
default n
---help---
Support for EBI2 panel auto detect
+
+if FB_MSM_MDSS
+ source "drivers/video/msm/mdss/Kconfig"
+endif
endif
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index b2ecb08..a0f9e02 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -1,10 +1,12 @@
+ifeq ($(CONFIG_FB_MSM_MDSS),y)
+obj-y += mdss/
+else
obj-y := msm_fb.o
obj-$(CONFIG_FB_MSM_LOGO) += logo.o
obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
ifeq ($(CONFIG_FB_MSM_MDP_HW),y)
-
# MDP
obj-y += mdp.o
@@ -165,6 +167,7 @@
obj-$(CONFIG_FB_MSM_HDMI_ADV7520_PANEL) += adv7520.o
obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
obj-$(CONFIG_FB_MSM_LVDS_CHIMEI_WXGA) += lvds_chimei_wxga.o
+obj-$(CONFIG_FB_MSM_LVDS_FRC_FHD) += lvds_frc_fhd.o
obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += hdmi_msm.o
obj-$(CONFIG_FB_MSM_EXT_INTERFACE_COMMON) += external_common.o
obj-$(CONFIG_FB_MSM_LCDC_TRULY_HVGA_IPS3P2335) += lcdc_truly_ips3p2335.o
@@ -181,15 +184,15 @@
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback_panel.o
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_wfd_writeback.o
obj-$(CONFIG_FB_MSM_WRITEBACK_MSM_PANEL) += mdp4_overlay_writeback.o
-
-obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
-obj-$(CONFIG_MSM_VIDC_720P) += vidc/
else
obj-$(CONFIG_FB_MSM_EBI2) += ebi2_host.o
obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
obj-y += msm_fb_panel.o
obj-$(CONFIG_FB_MSM_EBI2_EPSON_S1D_QVGA_PANEL) += ebi2_epson_s1d_qvga.o
endif
+endif
+obj-$(CONFIG_MSM_VIDC_1080P) += vidc/
+obj-$(CONFIG_MSM_VIDC_720P) += vidc/
clean:
rm *.o .*cmd
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index a372016..03243ac 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -809,7 +809,6 @@
if (!external_common_state->
disp_mode_list.num_of_elements)
hdmi_msm_read_edid();
- hdmi_msm_turn_on();
}
} else {
hdmi_msm_state->hpd_cable_chg_detected = FALSE;
@@ -824,16 +823,14 @@
DEV_INFO("Hdmi state switch to %d: %s\n",
external_common_state->sdev.state, __func__);
if (hpd_state) {
+ /* Build EDID table */
hdmi_msm_read_edid();
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
hdmi_msm_state->reauth = FALSE ;
#endif
- /* Build EDID table */
- hdmi_msm_turn_on();
DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
kobject_uevent(external_common_state->uevent_kobj,
KOBJ_ONLINE);
- hdmi_msm_hdcp_enable();
#ifndef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
/* Send Audio for HDMI Compliance Cases*/
envp[0] = "HDCP_STATE=PASS";
@@ -1312,7 +1309,8 @@
/* HDMI_CTRL */
HDMI_OUTP(0x0000, reg_val);
- DEV_DBG("HDMI Core: %s\n", power_on ? "Enable" : "Disable");
+ DEV_DBG("HDMI Core: %s, HDMI_CTRL=0x%08x\n",
+ power_on ? "Enable" : "Disable", reg_val);
}
static void msm_hdmi_init_ddc(void)
@@ -4105,7 +4103,6 @@
static void hdmi_msm_turn_on(void)
{
- uint32 hpd_ctrl;
uint32 audio_pkt_ctrl, audio_cfg;
/*
* Number of wait iterations for QDSP to disable Audio Engine
@@ -4128,6 +4125,7 @@
msleep(20);
}
+ hdmi_msm_set_mode(FALSE);
mutex_lock(&hdcp_auth_state_mutex);
hdmi_msm_reset_core();
mutex_unlock(&hdcp_auth_state_mutex);
@@ -4147,14 +4145,7 @@
#endif
hdmi_msm_spd_infoframe_packetsetup();
- /* set timeout to 4.1ms (max) for hardware debounce */
- hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
-
- /* Toggle HPD circuit to trigger HPD sense */
- HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
- HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
-
- /* Setup HPD IRQ */
+ /* Set IRQ for HPD */
HDMI_OUTP(0x0254, 4 | (external_common_state->hpd_state ? 0 : 2));
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
@@ -4231,22 +4222,24 @@
static void hdmi_msm_hpd_off(void)
{
+ int rc = 0;
+
if (!hdmi_msm_state->hpd_initialized) {
DEV_DBG("%s: HPD is already OFF, returning\n", __func__);
return;
}
- DEV_DBG("%s: (timer, clk, 5V, core, IRQ off)\n", __func__);
+ DEV_DBG("%s: (timer, 5V, IRQ off)\n", __func__);
del_timer(&hdmi_msm_state->hpd_state_timer);
disable_irq(hdmi_msm_state->irq);
hdmi_msm_set_mode(FALSE);
- hdmi_msm_state->hpd_initialized = FALSE;
- hdmi_msm_powerdown_phy();
- hdmi_msm_state->pd->cec_power(0);
hdmi_msm_state->pd->enable_5v(0);
- hdmi_msm_state->pd->core_power(0, 1);
hdmi_msm_clk(0);
+ rc = hdmi_msm_state->pd->gpio_config(0);
+ if (rc != 0)
+ DEV_INFO("%s: Failed to disable GPIOs. Error=%d\n",
+ __func__, rc);
hdmi_msm_state->hpd_initialized = FALSE;
}
@@ -4262,40 +4255,56 @@
{
static int phy_reset_done;
uint32 hpd_ctrl;
+ int rc = 0;
if (hdmi_msm_state->hpd_initialized) {
- DEV_DBG("%s: HPD is already ON, returning\n", __func__);
- return 0;
+ DEV_DBG("%s: HPD is already ON\n", __func__);
+ } else {
+ rc = hdmi_msm_state->pd->gpio_config(1);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable GPIOs. Error=%d\n",
+ __func__, rc);
+ goto error1;
+ }
+
+ rc = hdmi_msm_clk(1);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable clocks. Error=%d\n",
+ __func__, rc);
+ goto error2;
+ }
+
+ rc = hdmi_msm_state->pd->enable_5v(1);
+ if (rc) {
+ DEV_ERR("%s: Failed to enable 5V regulator. Error=%d\n",
+ __func__, rc);
+ goto error3;
+ }
+ hdmi_msm_dump_regs("HDMI-INIT: ");
+
+ hdmi_msm_set_mode(FALSE);
+ if (!phy_reset_done) {
+ hdmi_phy_reset();
+ phy_reset_done = 1;
+ }
+ hdmi_msm_set_mode(TRUE);
+
+ /* HDMI_USEC_REFTIMER[0x0208] */
+ HDMI_OUTP(0x0208, 0x0001001B);
+
+ /* set timeout to 4.1ms (max) for hardware debounce */
+ hpd_ctrl = HDMI_INP(0x0258) | 0x1FFF;
+
+ /* Toggle HPD circuit to trigger HPD sense */
+ HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
+ HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
+
+ hdmi_msm_state->hpd_initialized = TRUE;
+
+ /* Check HPD State */
+ enable_irq(hdmi_msm_state->irq);
}
- hdmi_msm_clk(1);
- hdmi_msm_state->pd->core_power(1, 1);
- hdmi_msm_state->pd->enable_5v(1);
- hdmi_msm_state->pd->cec_power(1);
- hdmi_msm_dump_regs("HDMI-INIT: ");
- hdmi_msm_set_mode(FALSE);
-
- if (!phy_reset_done) {
- hdmi_phy_reset();
- phy_reset_done = 1;
- }
-
- /* HDMI_USEC_REFTIMER[0x0208] */
- HDMI_OUTP(0x0208, 0x0001001B);
-
- /* Check HPD State */
- enable_irq(hdmi_msm_state->irq);
-
- /* set timeout to 4.1ms (max) for hardware debounce */
- hpd_ctrl = (HDMI_INP(0x0258) & ~0xFFF) | 0xFFF;
-
- /* Toggle HPD circuit to trigger HPD sense */
- HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
- HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
-
- DEV_DBG("%s: (clk, 5V, core, IRQ on) <trigger:%s>\n", __func__,
- trigger_handler ? "true" : "false");
-
if (trigger_handler) {
/* Set HPD state machine: ensure at least 2 readouts */
mutex_lock(&hdmi_msm_state_mutex);
@@ -4310,24 +4319,33 @@
jiffies + HZ/2);
}
- hdmi_msm_state->hpd_initialized = TRUE;
-
- hdmi_msm_set_mode(TRUE);
-
+ DEV_DBG("%s: (IRQ, 5V on) <trigger:%s>\n", __func__,
+ trigger_handler ? "true" : "false");
return 0;
+
+error3:
+ hdmi_msm_clk(0);
+error2:
+ hdmi_msm_state->pd->gpio_config(0);
+error1:
+ return rc;
}
static int hdmi_msm_power_ctrl(boolean enable)
{
- if (!external_common_state->hpd_feature_on)
+ int rc = 0;
+ if (!hdmi_prim_display && !external_common_state->hpd_feature_on)
return 0;
- if (enable)
- hdmi_msm_hpd_on(true);
- else
+ if (enable) {
+ DEV_DBG("%s: Turning HPD ciruitry on\n", __func__);
+ rc = hdmi_msm_hpd_on(true);
+ } else {
+ DEV_DBG("%s: Turning HPD ciruitry off\n", __func__);
hdmi_msm_hpd_off();
+ }
- return 0;
+ return rc;
}
static int hdmi_msm_power_on(struct platform_device *pdev)
@@ -4351,22 +4369,15 @@
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
changed = hdmi_common_get_video_format_from_drv_data(mfd);
- if (!external_common_state->hpd_feature_on || mfd->ref_cnt) {
- int rc = hdmi_msm_hpd_on(true);
- DEV_INFO("HPD: panel power without 'hpd' feature on\n");
- if (rc) {
- DEV_WARN("HPD: activation failed: rc=%d\n", rc);
- return rc;
- }
- }
hdmi_msm_audio_info_setup(TRUE, 0, 0, 0, FALSE);
mutex_lock(&external_common_state_hpd_mutex);
hdmi_msm_state->panel_power_on = TRUE;
- if ((external_common_state->hpd_state && !hdmi_msm_is_power_on())
- || changed) {
+ if (external_common_state->hpd_state && hdmi_msm_is_power_on()) {
+ DEV_DBG("%s: Turning HDMI on\n", __func__);
mutex_unlock(&external_common_state_hpd_mutex);
hdmi_msm_turn_on();
+ hdmi_msm_hdcp_enable();
} else
mutex_unlock(&external_common_state_hpd_mutex);
@@ -4386,8 +4397,6 @@
*/
static int hdmi_msm_power_off(struct platform_device *pdev)
{
- struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
-
if (!hdmi_msm_state->hdmi_app_clk)
return -ENODEV;
@@ -4407,15 +4416,7 @@
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
hdcp_deauthenticate();
#endif
- hdmi_msm_hpd_off();
hdmi_msm_powerdown_phy();
- hdmi_msm_dump_regs("HDMI-OFF: ");
- hdmi_msm_hpd_on(true);
-
- mutex_lock(&external_common_state_hpd_mutex);
- if (!external_common_state->hpd_feature_on || mfd->ref_cnt)
- hdmi_msm_hpd_off();
- mutex_unlock(&external_common_state_hpd_mutex);
hdmi_msm_state->panel_power_on = FALSE;
return 0;
@@ -4530,7 +4531,6 @@
hdmi_msm_state->hpd_state_timer.data = (uint32)NULL;
hdmi_msm_state->hpd_state_timer.expires = 0xffffffffL;
- add_timer(&hdmi_msm_state->hpd_state_timer);
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT
init_timer(&hdmi_msm_state->hdcp_timer);
@@ -4561,11 +4561,10 @@
} else
DEV_ERR("Init FAILED: failed to add fb device\n");
- DEV_INFO("HDMI HPD: ON\n");
-
rc = hdmi_msm_hpd_on(true);
if (rc)
goto error;
+ DEV_INFO("HDMI HPD: ON\n");
if (hdmi_msm_has_hdcp()) {
/* Don't Set Encryption in case of non HDCP builds */
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index 6323423..f5d8201 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -33,6 +33,9 @@
#include "msm_fb.h"
#include "mdp4.h"
+
+#define LVDS_PIXEL_MAP_PATTERN_2 2
+
static int lvds_probe(struct platform_device *pdev);
static int lvds_remove(struct platform_device *pdev);
@@ -65,14 +68,39 @@
usleep(1000);
/* LVDS PHY PLL configuration */
- MDP_OUTP(MDP_BASE + 0xc3004, 0x62);
- MDP_OUTP(MDP_BASE + 0xc3008, 0x30);
- MDP_OUTP(MDP_BASE + 0xc300c, 0xc4);
- MDP_OUTP(MDP_BASE + 0xc3014, 0x10);
- MDP_OUTP(MDP_BASE + 0xc3018, 0x05);
- MDP_OUTP(MDP_BASE + 0xc301c, 0x62);
- MDP_OUTP(MDP_BASE + 0xc3020, 0x41);
- MDP_OUTP(MDP_BASE + 0xc3024, 0x0d);
+ if (mfd->panel_info.clk_rate == 74250000) {
+ MDP_OUTP(MDP_BASE + 0xc3000, 0x08);
+ MDP_OUTP(MDP_BASE + 0xc3004, 0x4c);
+ MDP_OUTP(MDP_BASE + 0xc3008, 0x30);
+ MDP_OUTP(MDP_BASE + 0xc300c, 0xc3);
+ MDP_OUTP(MDP_BASE + 0xc3014, 0x10);
+ MDP_OUTP(MDP_BASE + 0xc3018, 0x04);
+ MDP_OUTP(MDP_BASE + 0xc301c, 0x62);
+ MDP_OUTP(MDP_BASE + 0xc3020, 0x41);
+ MDP_OUTP(MDP_BASE + 0xc3024, 0x0d);
+ MDP_OUTP(MDP_BASE + 0xc3028, 0x07);
+ MDP_OUTP(MDP_BASE + 0xc302c, 0x00);
+ MDP_OUTP(MDP_BASE + 0xc3030, 0x1c);
+ MDP_OUTP(MDP_BASE + 0xc3034, 0x01);
+ MDP_OUTP(MDP_BASE + 0xc3038, 0x00);
+ MDP_OUTP(MDP_BASE + 0xc3040, 0xC0);
+ MDP_OUTP(MDP_BASE + 0xc3044, 0x00);
+ MDP_OUTP(MDP_BASE + 0xc3048, 0x30);
+ MDP_OUTP(MDP_BASE + 0xc304c, 0x00);
+
+ MDP_OUTP(MDP_BASE + 0xc3000, 0x11);
+ MDP_OUTP(MDP_BASE + 0xc3064, 0x05);
+ MDP_OUTP(MDP_BASE + 0xc3050, 0x20);
+ } else {
+ MDP_OUTP(MDP_BASE + 0xc3004, 0x62);
+ MDP_OUTP(MDP_BASE + 0xc3008, 0x30);
+ MDP_OUTP(MDP_BASE + 0xc300c, 0xc4);
+ MDP_OUTP(MDP_BASE + 0xc3014, 0x10);
+ MDP_OUTP(MDP_BASE + 0xc3018, 0x05);
+ MDP_OUTP(MDP_BASE + 0xc301c, 0x62);
+ MDP_OUTP(MDP_BASE + 0xc3020, 0x41);
+ MDP_OUTP(MDP_BASE + 0xc3024, 0x0d);
+ }
MDP_OUTP(MDP_BASE + 0xc3000, 0x01);
/* Wait until LVDS PLL is locked and ready */
@@ -99,22 +127,42 @@
if (lvds_pdata &&
lvds_pdata->lvds_pixel_remap &&
lvds_pdata->lvds_pixel_remap()) {
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
- MDP_OUTP(MDP_BASE + 0xc2014, 0x05080001);
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
- MDP_OUTP(MDP_BASE + 0xc2018, 0x00020304);
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
- MDP_OUTP(MDP_BASE + 0xc201c, 0x1011090a);
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
- MDP_OUTP(MDP_BASE + 0xc2020, 0x000b0c0d);
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
- MDP_OUTP(MDP_BASE + 0xc2024, 0x191a1213);
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
- MDP_OUTP(MDP_BASE + 0xc2028, 0x00141518);
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
- MDP_OUTP(MDP_BASE + 0xc202c, 0x171b0607);
- /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
- MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16);
+ if (lvds_pdata->lvds_pixel_remap() ==
+ LVDS_PIXEL_MAP_PATTERN_2) {
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2014, 0x070A1B1B);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2018, 0x00040506);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc201c, 0x12131B1B);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2020, 0x000B0C0D);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2024, 0x191A1B1B);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2028, 0x00141518);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc202c, 0x171B1B1B);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16);
+ } else {
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2014, 0x05080001);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2018, 0x00020304);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc201c, 0x1011090a);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D1_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2020, 0x000b0c0d);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc2024, 0x191a1213);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2028, 0x00141518);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
+ MDP_OUTP(MDP_BASE + 0xc202c, 0x171b0607);
+ /* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
+ MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16);
+ }
} else {
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D0_3_TO_0 */
MDP_OUTP(MDP_BASE + 0xc2014, 0x03040508);
@@ -135,7 +183,7 @@
}
if (mfd->panel_info.lvds.channel_mode ==
LVDS_DUAL_CHANNEL_MODE) {
- lvds_intf = 0x0001ff80;
+ lvds_intf = 0x0003ff80;
lvds_phy_cfg0 = BIT(6) | BIT(7);
if (mfd->panel_info.lvds.channel_swap)
lvds_intf |= BIT(4);
@@ -159,7 +207,7 @@
if (mfd->panel_info.lvds.channel_mode ==
LVDS_DUAL_CHANNEL_MODE) {
- lvds_intf = 0x00017788;
+ lvds_intf = 0x00037788;
lvds_phy_cfg0 = BIT(6) | BIT(7);
if (mfd->panel_info.lvds.channel_swap)
lvds_intf |= BIT(4);
diff --git a/drivers/video/msm/lvds_frc_fhd.c b/drivers/video/msm/lvds_frc_fhd.c
new file mode 100644
index 0000000..7739588
--- /dev/null
+++ b/drivers/video/msm/lvds_frc_fhd.c
@@ -0,0 +1,201 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 <mach/gpio.h>
+#include "msm_fb.h"
+
+static struct lvds_panel_platform_data *frc_pdata;
+static struct platform_device *frc_fbpdev;
+static int gpio_update; /* 268 */
+static int gpio_reset; /* 269 */
+static int gpio_pwr; /* 270 */
+
+static int lvds_frc_panel_on(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = gpio_request(gpio_pwr, "frc_pwr");
+ if (ret) {
+ pr_err("%s: gpio_pwr=%d, gpio_request failed\n",
+ __func__, gpio_pwr);
+ goto panel_on_exit;
+ }
+ ret = gpio_request(gpio_update, "frc_update");
+ if (ret) {
+ pr_err("%s: gpio_update=%d, gpio_request failed\n",
+ __func__, gpio_update);
+ goto panel_on_exit1;
+ }
+ ret = gpio_request(gpio_reset, "frc_reset");
+ if (ret) {
+ pr_err("%s: gpio_reset=%d, gpio_request failed\n",
+ __func__, gpio_reset);
+ goto panel_on_exit2;
+ }
+
+ gpio_direction_output(gpio_reset, 1);
+ gpio_direction_output(gpio_pwr, 0);
+ gpio_direction_output(gpio_update, 0);
+ usleep(1000);
+ gpio_direction_output(gpio_reset, 0);
+ usleep(1000);
+ gpio_direction_output(gpio_pwr, 1);
+ usleep(1000);
+ gpio_direction_output(gpio_update, 1);
+ usleep(1000);
+ gpio_direction_output(gpio_reset, 1);
+ usleep(1000);
+ gpio_free(gpio_reset);
+panel_on_exit2:
+ gpio_free(gpio_update);
+panel_on_exit1:
+ gpio_free(gpio_pwr);
+panel_on_exit:
+ return ret;
+}
+
+static int lvds_frc_panel_off(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = gpio_request(gpio_pwr, "frc_pwr");
+ if (ret) {
+ pr_err("%s: gpio_pwr=%d, gpio_request failed\n",
+ __func__, gpio_pwr);
+ goto panel_off_exit;
+ }
+ ret = gpio_request(gpio_update, "frc_update");
+ if (ret) {
+ pr_err("%s: gpio_update=%d, gpio_request failed\n",
+ __func__, gpio_update);
+ goto panel_off_exit1;
+ }
+ ret = gpio_request(gpio_reset, "frc_reset");
+ if (ret) {
+ pr_err("%s: gpio_reset=%d, gpio_request failed\n",
+ __func__, gpio_reset);
+ goto panel_off_exit2;
+ }
+ gpio_direction_output(gpio_reset, 0);
+ usleep(1000);
+ gpio_direction_output(gpio_update, 0);
+ usleep(1000);
+ gpio_direction_output(gpio_pwr, 0);
+ usleep(1000);
+ gpio_free(gpio_reset);
+panel_off_exit2:
+ gpio_free(gpio_update);
+panel_off_exit1:
+ gpio_free(gpio_pwr);
+panel_off_exit:
+ return ret;
+}
+
+static int __devinit lvds_frc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+
+ if (pdev->id == 0) {
+ frc_pdata = pdev->dev.platform_data;
+ if (frc_pdata != NULL) {
+ gpio_update = frc_pdata->gpio[0];
+ gpio_reset = frc_pdata->gpio[1];
+ gpio_pwr = frc_pdata->gpio[2];
+ pr_info("%s: power=%d update=%d reset=%d\n",
+ __func__, gpio_pwr, gpio_update, gpio_reset);
+ }
+ return 0;
+ }
+
+ frc_fbpdev = msm_fb_add_device(pdev);
+ if (!frc_fbpdev) {
+ dev_err(&pdev->dev, "failed to add msm_fb device\n");
+ rc = -ENODEV;
+ goto probe_exit;
+ }
+
+probe_exit:
+ return rc;
+}
+
+static struct platform_driver this_driver = {
+ .probe = lvds_frc_probe,
+ .driver = {
+ .name = "lvds_frc_fhd",
+ },
+};
+
+static struct msm_fb_panel_data lvds_frc_panel_data = {
+ .on = lvds_frc_panel_on,
+ .off = lvds_frc_panel_off,
+};
+
+static struct platform_device this_device = {
+ .name = "lvds_frc_fhd",
+ .id = 1,
+ .dev = {
+ .platform_data = &lvds_frc_panel_data,
+ }
+};
+
+static int __init lvds_frc_fhd_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+ if (msm_fb_detect_client("lvds_frc_fhd"))
+ return 0;
+
+ ret = platform_driver_register(&this_driver);
+ if (ret)
+ return ret;
+
+ pinfo = &lvds_frc_panel_data.panel_info;
+ pinfo->xres = 1920;
+ pinfo->yres = 1080;
+ MSM_FB_SINGLE_MODE_PANEL(pinfo);
+ pinfo->type = LVDS_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 24;
+ pinfo->fb_num = 2;
+ pinfo->clk_rate = 74250000;
+ pinfo->bl_max = 255;
+ pinfo->bl_min = 1;
+
+ /*
+ * use hdmi 1080p60 setting, for dual channel mode,
+ * horizontal length is half.
+ */
+ pinfo->lcdc.h_back_porch = 148/2;
+ pinfo->lcdc.h_front_porch = 88/2;
+ pinfo->lcdc.h_pulse_width = 44/2;
+ pinfo->lcdc.v_back_porch = 36;
+ pinfo->lcdc.v_front_porch = 4;
+ pinfo->lcdc.v_pulse_width = 5;
+ pinfo->lcdc.underflow_clr = 0xff;
+ pinfo->lcdc.hsync_skew = 0;
+ pinfo->lvds.channel_mode = LVDS_DUAL_CHANNEL_MODE;
+ pinfo->lcdc.is_sync_active_high = TRUE;
+
+ /* Set border color, padding only for reducing active display region */
+ pinfo->lcdc.border_clr = 0x0;
+ pinfo->lcdc.xres_pad = 0;
+ pinfo->lcdc.yres_pad = 0;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+
+ return ret;
+}
+
+module_init(lvds_frc_fhd_init);
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 7fd2d91..cad6e02 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -88,12 +88,13 @@
struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */
struct workqueue_struct *mdp_hist_wq; /*mdp histogram wq */
+bool mdp_pp_initialized = FALSE;
static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
static struct delayed_work mdp_pipe_ctrl_worker;
static boolean mdp_suspended = FALSE;
-static DEFINE_MUTEX(mdp_suspend_mutex);
+DEFINE_MUTEX(mdp_suspend_mutex);
#ifdef CONFIG_FB_MSM_MDP40
struct mdp_dma_data dma2_data;
@@ -219,10 +220,28 @@
mutex_unlock(&mdp_hist_lut_list_mutex);
}
-static int mdp_hist_lut_init(void)
+static int mdp_hist_lut_destroy(void)
{
struct mdp_hist_lut_mgmt *temp;
struct list_head *pos, *q;
+
+ mutex_lock(&mdp_hist_lut_list_mutex);
+ list_for_each_safe(pos, q, &mdp_hist_lut_list) {
+ temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
+ list_del(pos);
+ kfree(temp);
+ }
+ mutex_unlock(&mdp_hist_lut_list_mutex);
+ return 0;
+}
+
+static int mdp_hist_lut_init(void)
+{
+ struct mdp_hist_lut_mgmt *temp;
+
+ if (mdp_pp_initialized)
+ return -EEXIST;
+
INIT_LIST_HEAD(&mdp_hist_lut_list);
if (mdp_rev >= MDP_REV_30) {
@@ -253,13 +272,7 @@
return 0;
exit_list:
- mutex_lock(&mdp_hist_lut_list_mutex);
- list_for_each_safe(pos, q, &mdp_hist_lut_list) {
- temp = list_entry(pos, struct mdp_hist_lut_mgmt, list);
- list_del(pos);
- kfree(temp);
- }
- mutex_unlock(&mdp_hist_lut_list_mutex);
+ mdp_hist_lut_destroy();
exit:
pr_err("Failed initializing histogram LUT memory\n");
return -ENOMEM;
@@ -682,10 +695,30 @@
kfree(mgmt->c0);
}
+static int mdp_histogram_destroy(void)
+{
+ struct mdp_hist_mgmt *temp;
+ int i;
+
+ for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
+ temp = mdp_hist_mgmt_array[i];
+ if (!temp)
+ continue;
+ mdp_hist_del_mgmt(temp);
+ kfree(temp);
+ mdp_hist_mgmt_array[i] = NULL;
+ }
+ return 0;
+}
+
static int mdp_histogram_init(void)
{
struct mdp_hist_mgmt *temp;
int i, ret;
+
+ if (mdp_pp_initialized)
+ return -EEXIST;
+
mdp_hist_wq = alloc_workqueue("mdp_hist_wq",
WQ_NON_REENTRANT | WQ_UNBOUND, 0);
@@ -731,14 +764,7 @@
return 0;
exit_list:
- for (i = 0; i < MDP_HIST_MGMT_MAX; i++) {
- temp = mdp_hist_mgmt_array[i];
- if (!temp)
- continue;
- mdp_hist_del_mgmt(temp);
- kfree(temp);
- mdp_hist_mgmt_array[i] = NULL;
- }
+ mdp_histogram_destroy();
exit:
return -ENOMEM;
}
@@ -888,6 +914,7 @@
goto error;
}
+ mutex_lock(&mgmt->mdp_do_hist_mutex);
mutex_lock(&mgmt->mdp_hist_mutex);
if (mgmt->mdp_is_hist_start == TRUE) {
pr_err("%s histogram already started\n", __func__);
@@ -907,6 +934,7 @@
error_lock:
mutex_unlock(&mgmt->mdp_hist_mutex);
+ mutex_unlock(&mgmt->mdp_do_hist_mutex);
error:
return ret;
}
@@ -923,6 +951,7 @@
goto error;
}
+ mutex_lock(&mgmt->mdp_do_hist_mutex);
mutex_lock(&mgmt->mdp_hist_mutex);
if (mgmt->mdp_is_hist_start == FALSE) {
pr_err("%s histogram already stopped\n", __func__);
@@ -943,10 +972,12 @@
mutex_unlock(&mgmt->mdp_hist_mutex);
cancel_work_sync(&mgmt->mdp_histogram_worker);
+ mutex_unlock(&mgmt->mdp_do_hist_mutex);
return ret;
error_lock:
mutex_unlock(&mgmt->mdp_hist_mutex);
+ mutex_unlock(&mgmt->mdp_do_hist_mutex);
error:
return ret;
}
@@ -1068,21 +1099,31 @@
goto error;
}
- switch (mgmt->block) {
- case MDP_BLOCK_DMA_P:
- case MDP_BLOCK_DMA_S:
- ret = _mdp_histogram_read_dma_data(mgmt);
- break;
- case MDP_BLOCK_VG_1:
- case MDP_BLOCK_VG_2:
- ret = _mdp_histogram_read_vg_data(mgmt);
- break;
- default:
- pr_err("%s, invalid MDP block = %d\n", __func__, mgmt->block);
+ if (mgmt->hist == NULL) {
+ if ((mgmt->mdp_is_hist_init == TRUE) &&
+ ((!completion_done(&mgmt->mdp_hist_comp)) &&
+ waitqueue_active(&mgmt->mdp_hist_comp.wait)))
+ pr_err("mgmt->hist invalid NULL\n");
ret = -EINVAL;
- goto error;
}
+ if (!ret) {
+ switch (mgmt->block) {
+ case MDP_BLOCK_DMA_P:
+ case MDP_BLOCK_DMA_S:
+ ret = _mdp_histogram_read_dma_data(mgmt);
+ break;
+ case MDP_BLOCK_VG_1:
+ case MDP_BLOCK_VG_2:
+ ret = _mdp_histogram_read_vg_data(mgmt);
+ break;
+ default:
+ pr_err("%s, invalid MDP block = %d\n", __func__,
+ mgmt->block);
+ ret = -EINVAL;
+ goto error;
+ }
+ }
/*
* if read was triggered by an underrun or failed copying,
* don't wake up readers
@@ -1142,11 +1183,13 @@
return ret;
}
+#define MDP_HISTOGRAM_TIMEOUT_MS 84 /*5 Frames*/
static int mdp_do_histogram(struct fb_info *info,
struct mdp_histogram_data *hist)
{
struct mdp_hist_mgmt *mgmt = NULL;
int ret = 0;
+ unsigned long timeout = (MDP_HISTOGRAM_TIMEOUT_MS * HZ) / 1000;
ret = mdp_histogram_block2mgmt(hist->block, &mgmt);
if (ret) {
@@ -1191,9 +1234,17 @@
mgmt->hist = hist;
mutex_unlock(&mgmt->mdp_hist_mutex);
- if (wait_for_completion_killable(&mgmt->mdp_hist_comp)) {
- pr_err("%s(): histogram bin collection killed", __func__);
- ret = -EINVAL;
+ ret = wait_for_completion_killable_timeout(&mgmt->mdp_hist_comp,
+ timeout);
+ if (ret <= 0) {
+ if (!ret) {
+ mgmt->hist = NULL;
+ ret = -ETIMEDOUT;
+ pr_debug("%s: bin collection timedout", __func__);
+ } else {
+ mgmt->hist = NULL;
+ pr_debug("%s: bin collection interrupted", __func__);
+ }
goto error;
}
@@ -1573,16 +1624,7 @@
__mdp_histogram_kickoff(mgmt);
if (isr & INTR_HIST_DONE) {
- if ((waitqueue_active(&mgmt->mdp_hist_comp.wait))
- && (mgmt->hist != NULL)) {
- if (!queue_work(mdp_hist_wq,
- &mgmt->mdp_histogram_worker)) {
- pr_err("%s %d- can't queue hist_read\n",
- __func__, mgmt->block);
- }
- } else {
- __mdp_histogram_reset(mgmt);
- }
+ queue_work(mdp_hist_wq, &mgmt->mdp_histogram_worker);
}
}
@@ -1887,7 +1929,7 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
if (mdp_rev >= MDP_REV_41 && mfd->panel.type == MIPI_CMD_PANEL)
- mdp_dsi_cmd_overlay_suspend();
+ mdp_dsi_cmd_overlay_suspend(mfd);
return ret;
}
@@ -1897,7 +1939,6 @@
#ifdef CONFIG_FB_MSM_MDP40
struct msm_fb_data_type *mfd;
- mdp4_overlay_ctrl_db_reset();
mfd = platform_get_drvdata(pdev);
@@ -2256,6 +2297,7 @@
/* initialize Post Processing data*/
mdp_hist_lut_init();
mdp_histogram_init();
+ mdp_pp_initialized = TRUE;
/* add panel data */
if (platform_device_add_data
@@ -2575,17 +2617,6 @@
return rc;
}
-unsigned int mdp_check_suspended(void)
-{
- unsigned int ret;
-
- mutex_lock(&mdp_suspend_mutex);
- ret = mdp_suspended;
- mutex_unlock(&mdp_suspend_mutex);
-
- return ret;
-}
-
void mdp_footswitch_ctrl(boolean on)
{
mutex_lock(&mdp_suspend_mutex);
@@ -2652,7 +2683,6 @@
#ifdef CONFIG_FB_MSM_DTV
mdp4_dtv_set_black_screen();
#endif
- mdp4_iommu_detach();
mdp_footswitch_ctrl(FALSE);
}
@@ -2669,6 +2699,12 @@
{
if (footswitch != NULL)
regulator_put(footswitch);
+
+ /*free post processing memory*/
+ mdp_histogram_destroy();
+ mdp_hist_lut_destroy();
+ mdp_pp_initialized = FALSE;
+
iounmap(msm_mdp_base);
pm_runtime_disable(&pdev->dev);
#ifdef CONFIG_MSM_BUS_SCALING
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index b104b33..e60b24e 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -801,7 +801,6 @@
void mdp_histogram_handle_isr(struct mdp_hist_mgmt *mgmt);
void __mdp_histogram_kickoff(struct mdp_hist_mgmt *mgmt);
void __mdp_histogram_reset(struct mdp_hist_mgmt *mgmt);
-unsigned int mdp_check_suspended(void);
void mdp_footswitch_ctrl(boolean on);
#ifdef CONFIG_FB_MSM_MDP303
@@ -825,14 +824,10 @@
#endif
#ifndef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
{
/* empty */
}
-static inline void mdp4_iommu_detach(void)
-{
- /* empty */
-}
#endif
int mdp_ppp_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req);
@@ -841,5 +836,12 @@
unsigned long srcp0_addr, unsigned long srcp0_size,
unsigned long srcp1_addr, unsigned long srcp1_size);
+#ifdef CONFIG_FB_MSM_DTV
void mdp_vid_quant_set(void);
+#else
+static inline void mdp_vid_quant_set(void)
+{
+ /* empty */
+}
+#endif
#endif /* MDP_H */
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index a7161fe..1557eed 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -173,6 +173,7 @@
MDP4_MIXER_STAGE0, /* zorder 0 */
MDP4_MIXER_STAGE1, /* zorder 1 */
MDP4_MIXER_STAGE2, /* zorder 2 */
+ MDP4_MIXER_STAGE3, /* zorder 3 */
MDP4_MIXER_STAGE_MAX
};
@@ -256,6 +257,19 @@
u8 mark_unmap;
};
+struct blend_cfg {
+ u32 op;
+ u32 bg_alpha;
+ u32 fg_alpha;
+ u32 co3_sel;
+ u32 transp_low0;
+ u32 transp_low1;
+ u32 transp_high0;
+ u32 transp_high1;
+ int solidfill;
+ struct mdp4_overlay_pipe *solidfill_pipe;
+};
+
struct mdp4_overlay_pipe {
uint32 pipe_used;
uint32 pipe_type; /* rgb, video/graphic */
@@ -403,6 +417,7 @@
void mdp4_intr_clear_set(ulong clear, ulong set);
void mdp4_dma_p_cfg(void);
unsigned is_mdp4_hw_reset(void);
+void mdp4_overlay_cfg_init(void);
void mdp4_hw_init(void);
void mdp4_isr_read(int);
void mdp4_clear_lcdc(void);
@@ -417,6 +432,7 @@
uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe);
uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe);
void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
#ifdef CONFIG_FB_MSM_DTV
void mdp4_overlay_dtv_start(void);
@@ -430,6 +446,7 @@
struct mdp4_overlay_pipe *pipe);
void mdp4_dma_e_done_dtv(void);
void mdp4_overlay_dtv_wait4vsync(void);
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe);
#else
static inline void mdp4_overlay_dtv_start(void)
{
@@ -472,6 +489,10 @@
{
return;
}
+static inline void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ /* empty */
+}
#endif
void mdp4_dtv_set_black_screen(void);
@@ -506,7 +527,7 @@
int mdp4_overlay_dsi_state_get(void);
void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_blend_setup(int mixer);
struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage);
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
@@ -519,6 +540,7 @@
int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req);
int mdp4_overlay_unset(struct fb_info *info, int ndx);
+int mdp4_overlay_unset_mixer(int mixer);
int mdp4_overlay_play_wait(struct fb_info *info,
struct msmfb_overlay_data *req);
int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req);
@@ -533,7 +555,7 @@
void mdp4_overlay0_done_lcdc(struct mdp_dma_data *dma);
void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma);
void mdp4_dma_s_done_mddi(void);
-void mdp4_dma_p_done_mddi(void);
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma);
void mdp4_dma_p_done_dsi(struct mdp_dma_data *dma);
void mdp4_dma_p_done_dsi_video(struct mdp_dma_data *dma);
void mdp4_dma_p_done_lcdc(void);
@@ -557,10 +579,32 @@
{
/* empty */
}
+static inline void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+ /* empty */
+}
static inline void mdp4_mddi_overlay_restore(void)
{
/* empty */
}
+static inline void mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
+{
+ /*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+ /*empty*/
+}
+static inline void mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ /* empty */
+}
+static inline void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ /* empty*/
+}
#endif
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
@@ -590,6 +634,7 @@
struct msmfb_overlay_blt *req);
int mdp4_dsi_video_overlay_blt_offset(struct msm_fb_data_type *mfd,
struct msmfb_overlay_blt *req);
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe);
#ifdef CONFIG_FB_MSM_MDP40
static inline void mdp3_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
@@ -598,6 +643,13 @@
}
#endif
#else
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req);
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req);
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd);
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd);
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
static inline int mdp4_dsi_overlay_blt_start(struct msm_fb_data_type *mfd)
{
return -ENODEV;
@@ -630,6 +682,10 @@
{
return -ENODEV;
}
+static inline void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ /* empty */
+}
#endif
void mdp4_lcdc_overlay_blt(struct msm_fb_data_type *mfd,
@@ -640,9 +696,6 @@
void mdp4_lcdc_overlay_blt_stop(struct msm_fb_data_type *mfd);
void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd);
void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd);
-
-int mdp4_mddi_overlay_blt_offset(int *off);
-void mdp4_mddi_overlay_blt(ulong addr);
void mdp4_overlay_panel_mode(int mixer_num, uint32 mode);
void mdp4_overlay_panel_mode_unset(int mixer_num, uint32 mode);
int mdp4_overlay_mixer_play(int mixer_num);
@@ -664,7 +717,7 @@
void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
void mdp4_dsi_cmd_overlay_restore(void);
-void mdp_dsi_cmd_overlay_suspend(void);
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd);
#else
static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
{
@@ -688,7 +741,7 @@
/* empty */
}
#ifdef CONFIG_FB_MSM_MDP40
-static inline void mdp_dsi_cmd_overlay_suspend(void)
+static inline void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
{
/* empty */
}
@@ -701,6 +754,7 @@
struct mdp4_overlay_pipe *pipe);
void mdp4_dsi_cmd_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe);
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe);
void mdp4_overlay_panel_3d(int mixer_num, uint32 panel_3d);
int mdp4_overlay_3d_sbys(struct fb_info *info, struct msmfb_overlay_3d *req);
@@ -721,7 +775,7 @@
void mdp4_overlay_dsi_video_wait4vsync(struct msm_fb_data_type *mfd);
void mdp4_primary_vsync_dsi_video(void);
uint32_t mdp4_ss_table_value(int8_t param, int8_t index);
-void mdp4_overlay_ctrl_db_reset(void);
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe);
int mdp4_overlay_writeback_on(struct platform_device *pdev);
int mdp4_overlay_writeback_off(struct platform_device *pdev);
@@ -759,7 +813,6 @@
int mdp4_igc_lut_config(struct mdp_igc_lut_data *cfg);
void mdp4_iommu_unmap(struct mdp4_overlay_pipe *pipe);
void mdp4_iommu_attach(void);
-void mdp4_iommu_detach(void);
int mdp4_v4l2_overlay_set(struct fb_info *info, struct mdp_overlay *req,
struct mdp4_overlay_pipe **ppipe);
void mdp4_v4l2_overlay_clear(struct mdp4_overlay_pipe *pipe);
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index f0353bd..bd0ce2f 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -137,6 +137,12 @@
clk_prepare_enable(ebi1_clk);
}
#endif
+
+ if (dtv_pdata && dtv_pdata->lcdc_power_save)
+ dtv_pdata->lcdc_power_save(1);
+ if (dtv_pdata && dtv_pdata->lcdc_gpio_config)
+ ret = dtv_pdata->lcdc_gpio_config(1);
+
mfd = platform_get_drvdata(pdev);
ret = clk_set_rate(tv_src_clk, mfd->fbi->var.pixclock);
@@ -158,11 +164,6 @@
if (mdp_tv_clk)
clk_prepare_enable(mdp_tv_clk);
- if (dtv_pdata && dtv_pdata->lcdc_power_save)
- dtv_pdata->lcdc_power_save(1);
- if (dtv_pdata && dtv_pdata->lcdc_gpio_config)
- ret = dtv_pdata->lcdc_gpio_config(1);
-
ret = panel_next_on(pdev);
return ret;
}
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 6d4e44b..2a15506 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -46,8 +46,12 @@
struct mdp4_overlay_ctrl {
struct mdp4_overlay_pipe plist[OVERLAY_PIPE_MAX];
struct mdp4_overlay_pipe *stage[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
+ struct mdp4_overlay_pipe *baselayer[MDP4_MIXER_MAX];
+ struct blend_cfg blend[MDP4_MIXER_MAX][MDP4_MIXER_STAGE_MAX];
uint32 mixer_cfg[MDP4_MIXER_MAX];
+ uint32 flush[MDP4_MIXER_MAX];
uint32 cs_controller;
+ uint32 hw_version;
uint32 panel_3d;
uint32 panel_mode;
uint32 mixer0_played;
@@ -198,14 +202,6 @@
}
}
-void mdp4_overlay_ctrl_db_reset(void)
-{
- int i;
-
- for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++)
- ctrl->mixer_cfg[i] = 0;
-}
-
int mdp4_overlay_mixer_play(int mixer_num)
{
if (mixer_num == MDP4_MIXER2)
@@ -236,6 +232,20 @@
return ctrl->panel_mode;
}
+void mdp4_overlay_cfg_init(void)
+{
+ if (ctrl->hw_version == 0) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ ctrl->hw_version = inpdw(MDP_BASE + 0x0); /* MDP_HW_VERSION */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ }
+
+ if (ctrl->hw_version >= 0x0402030b) {
+ /* MDP_LAYERMIXER_IN_CFG_UPDATE_METHOD */
+ outpdw(MDP_BASE + 0x100fc, 0x01);
+ }
+}
+
void mdp4_overlay_dmae_cfg(struct msm_fb_data_type *mfd, int atv)
{
uint32 dmae_cfg_reg;
@@ -847,6 +857,8 @@
case MDP_YCRCB_H1V1:
case MDP_YCBCR_H1V1:
return OVERLAY_TYPE_VIDEO;
+ case MDP_RGB_BORDERFILL:
+ return OVERLAY_TYPE_BF;
default:
mdp4_stat.err_format++;
return -ERANGE;
@@ -1120,6 +1132,9 @@
pipe->element2 = C2_R_Cr; /* R */
}
pipe->bpp = 3; /* 3 bpp */
+ case MDP_RGB_BORDERFILL:
+ pipe->alpha_enable = 0;
+ pipe->alpha = 0;
break;
default:
/* not likely */
@@ -1441,13 +1456,13 @@
return -ENODEV;
cnt = 0;
- ndx = 1; /* ndx 0 if not used */
-
+ ndx = MDP4_MIXER_STAGE_BASE;
for ( ; ndx < MDP4_MIXER_STAGE_MAX; ndx++) {
pipe = ctrl->stage[mixer_num][ndx];
if (pipe == NULL)
continue;
info->z_order = pipe->mixer_stage - MDP4_MIXER_STAGE0;
+ /* z_order == -1, means base layer */
info->ptype = pipe->pipe_type;
info->pnum = pipe->pipe_num;
info->pndx = pipe->pipe_ndx;
@@ -1458,331 +1473,458 @@
return cnt;
}
-static void mdp4_overlay_bg_solidfill_clear(uint32 mixer_num)
-{
- struct mdp4_overlay_pipe *bg_pipe;
- unsigned char *rgb_base;
- uint32 rgb_src_format;
- int pnum;
-
- bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
- MDP4_MIXER_STAGE_BASE);
- if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_BF) {
- bg_pipe = mdp4_overlay_stage_pipe(mixer_num,
- MDP4_MIXER_STAGE0);
- }
-
- if (bg_pipe && bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
- rgb_src_format = mdp4_overlay_format(bg_pipe);
- if (!(rgb_src_format & MDP4_FORMAT_SOLID_FILL)) {
- pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
- rgb_base = MDP_BASE + MDP4_RGB_BASE;
- rgb_base += MDP4_RGB_OFF * pnum;
- outpdw(rgb_base + 0x50, rgb_src_format);
- outpdw(rgb_base + 0x0058, bg_pipe->op_mode);
- mdp4_overlay_reg_flush(bg_pipe, 0);
- }
- }
-}
-
-void mdp4_mixer_pipe_cleanup(int mixer)
-{
- struct mdp4_overlay_pipe *pipe;
- int j;
-
- for (j = MDP4_MIXER_STAGE_MAX - 1; j > MDP4_MIXER_STAGE_BASE; j--) {
- pipe = ctrl->stage[mixer][j];
- if (pipe == NULL)
- continue;
- pr_debug("%s(): pipe %u\n", __func__, pipe->pipe_ndx);
- mdp4_mixer_stage_down(pipe);
- mdp4_overlay_pipe_free(pipe);
- }
-}
-
static void mdp4_mixer_stage_commit(int mixer)
{
struct mdp4_overlay_pipe *pipe;
- int i, j, off;
- u32 data = 0, stage, flush_bits = 0, pipe_cnt = 0, pull_mode = 0;
- u32 cfg[MDP4_MIXER_MAX];
+ int i, num;
+ u32 data, stage;
+ int off;
+ unsigned long flags;
- if (mixer == MDP4_MIXER0)
- flush_bits |= 0x1;
- else if (mixer == MDP4_MIXER1)
- flush_bits |= 0x2;
+ data = 0;
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pipe = ctrl->stage[mixer][i];
+ if (pipe == NULL)
+ continue;
+ pr_debug("%s: mixer=%d ndx=%d stage=%d\n", __func__,
+ mixer, pipe->pipe_ndx, i);
+ stage = pipe->mixer_stage;
+ if (mixer >= MDP4_MIXER1)
+ stage += 8;
+ stage <<= (4 * pipe->pipe_num);
+ data |= stage;
+ }
- for (i = MDP4_MIXER0; i < MDP4_MIXER_MAX; i++) {
- cfg[i] = 0;
- for (j = MDP4_MIXER_STAGE_BASE; j < MDP4_MIXER_STAGE_MAX; j++) {
- pipe = ctrl->stage[i][j];
- if (pipe == NULL)
- break;
- stage = pipe->mixer_stage;
- if (i >= MDP4_MIXER1)
- stage += 8;
- stage <<= (4 * pipe->pipe_num);
- cfg[i] |= stage;
- pipe_cnt++;
+ mdp4_mixer_blend_setup(mixer);
- mdp4_mixer_blend_setup(pipe);
+ off = 0;
+ if (data != ctrl->mixer_cfg[mixer]) {
+ ctrl->mixer_cfg[mixer] = data;
+ if (mixer >= MDP4_MIXER2) {
+ /* MDP_LAYERMIXER2_IN_CFG */
+ off = 0x100f0;
+ } else {
+ /* mixer 0 or 1 */
+ num = mixer + 1;
+ num &= 0x01;
+ data |= ctrl->mixer_cfg[num];
+ off = 0x10100;
}
+ pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
+ mixer, data, ctrl->flush[mixer]);
}
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- if (ctrl->mixer_cfg[mixer] != cfg[mixer]) {
- if ((ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) ||
- (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1])) {
- off = 0x10100;
- if (ctrl->mixer_cfg[MDP4_MIXER0] != cfg[MDP4_MIXER0]) {
- flush_bits |= 0x1;
- ctrl->mixer_cfg[MDP4_MIXER0] = cfg[MDP4_MIXER0];
+ local_irq_save(flags);
+ if (off)
+ outpdw(MDP_BASE + off, data);
- if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
- (ctrl->panel_mode & MDP4_PANEL_LCDC))
- pull_mode = 1;
- }
- if (ctrl->mixer_cfg[MDP4_MIXER1] != cfg[MDP4_MIXER1]) {
- flush_bits |= 0x2;
- ctrl->mixer_cfg[MDP4_MIXER1] = cfg[MDP4_MIXER1];
-
- pull_mode = 1;
- }
-
- data = cfg[MDP4_MIXER0] | cfg[MDP4_MIXER1];
-
- pr_debug("%s: mixer=%d data=%x flush=%x\n", __func__,
- mixer, data, flush_bits);
-
- outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
- if (pull_mode) {
- outpdw(MDP_BASE + 0x18000, flush_bits);
- /* wait for vsync on both pull mode interfaces */
- msleep(20);
- }
- }
-
- if (ctrl->mixer_cfg[MDP4_MIXER2] != cfg[MDP4_MIXER2]) {
- off = 0x100F0;
- ctrl->mixer_cfg[MDP4_MIXER2] = cfg[MDP4_MIXER2];
- data = cfg[MDP4_MIXER2];
-
- pr_debug("%s: mixer=%d data=%x\n", __func__,
- mixer, data);
-
- outpdw(MDP_BASE + off, data); /* LAYERMIXER_IN_CFG */
- }
- } else {
- if (mixer == MDP4_MIXER0) {
- if ((ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) ||
- (ctrl->panel_mode & MDP4_PANEL_LCDC))
- pull_mode = 1;
- } else if (mixer == MDP4_MIXER1) {
- pull_mode = 1;
- }
-
- if (pull_mode)
- outpdw(MDP_BASE + 0x18000, flush_bits);
+ if (ctrl->flush[mixer]) {
+ outpdw(MDP_BASE + 0x18000, ctrl->flush[mixer]);
+ ctrl->flush[mixer] = 0;
}
+ local_irq_restore(flags);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
- if (data && pipe_cnt == 1)
- mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
}
+
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
{
- struct mdp4_overlay_pipe *spipe;
- int mixer;
+ struct mdp4_overlay_pipe *pp;
+ int i, mixer;
mixer = pipe->mixer_num;
- spipe = ctrl->stage[mixer][pipe->mixer_stage];
- if ((spipe != NULL) && (spipe->pipe_num != pipe->pipe_num)) {
- mdp4_stat.err_stage++;
- return;
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pp = ctrl->stage[mixer][i];
+ if (pp == pipe) {
+ ctrl->stage[mixer][i] = NULL;
+ break;
+ }
}
ctrl->stage[mixer][pipe->mixer_stage] = pipe; /* keep it */
- if (!(pipe->flags & MDP_OV_PLAY_NOWAIT))
+ if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+ pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+ __func__, mixer, pipe->pipe_ndx,
+ pipe->mixer_stage, pipe->flags);
mdp4_mixer_stage_commit(mixer);
+ }
}
void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
{
- struct mdp4_overlay_pipe *spipe;
+ struct mdp4_overlay_pipe *pp;
+ int i, mixer;
- spipe = ctrl->stage[pipe->mixer_num][pipe->mixer_stage];
- if (spipe == NULL) /* not running */
+ mixer = pipe->mixer_num;
+
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pp = ctrl->stage[mixer][i];
+ if (pp == pipe)
+ ctrl->stage[mixer][i] = NULL; /* clear it */
+ }
+
+ if (!(pipe->flags & MDP_OV_PLAY_NOWAIT)) {
+ pr_debug("%s: mixer=%d ndx=%d stage=%d flags=%x\n",
+ __func__, pipe->mixer_num, pipe->pipe_ndx,
+ pipe->mixer_stage, pipe->flags);
+ mdp4_mixer_stage_commit(pipe->mixer_num);
+ }
+}
+/*
+ * mixer0: rgb3: border color at register 0x15004, 0x15008
+ * mixer1: vg3: border color at register 0x1D004, 0x1D008
+ * mixer2: xxx: border color at register 0x8D004, 0x8D008
+ */
+void mdp4_overlay_borderfill_stage_up(struct mdp4_overlay_pipe *pipe)
+{
+ struct mdp4_overlay_pipe *bspipe;
+ int ptype, pnum, pndx, mixer;
+ int format, alpha_enable, alpha;
+
+ if (pipe->pipe_type != OVERLAY_TYPE_BF)
return;
- ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL; /* clear it */
+ mixer = pipe->mixer_num;
- mdp4_mixer_stage_commit(pipe->mixer_num);
+ if (ctrl->baselayer[mixer])
+ return;
+
+ bspipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+
+ /* save original base layer */
+ ctrl->baselayer[mixer] = bspipe;
+
+ pipe->alpha = 0; /* make sure bf pipe has alpha 0 */
+ ptype = pipe->pipe_type;
+ pnum = pipe->pipe_num;
+ pndx = pipe->pipe_ndx;
+ format = pipe->src_format;
+ alpha_enable = pipe->alpha_enable;
+ alpha = pipe->alpha;
+ *pipe = *bspipe; /* keep base layer configuration */
+ pipe->pipe_type = ptype;
+ pipe->pipe_num = pnum;
+ pipe->pipe_ndx = pndx;
+ pipe->src_format = format;
+ pipe->alpha_enable = alpha_enable;
+ pipe->alpha = alpha;
+
+ /* free original base layer pipe to be sued as normal pipe */
+ bspipe->pipe_used = 0;
+
+ if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO)
+ mdp4_dsi_video_base_swap(pipe);
+ else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
+ mdp4_lcdc_base_swap(pipe);
+ else if (ctrl->panel_mode & MDP4_PANEL_DTV)
+ mdp4_dtv_base_swap(pipe);
+
+ mdp4_overlay_reg_flush(bspipe, 1);
+ /* borderfill pipe as base layer */
+ mdp4_mixer_stage_up(pipe);
}
-void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe)
+void mdp4_overlay_borderfill_stage_down(struct mdp4_overlay_pipe *pipe)
{
- struct mdp4_overlay_pipe *bg_pipe;
- unsigned char *overlay_base, *rgb_base;
- uint32 c0, c1, c2, blend_op, constant_color = 0, rgb_src_format;
- uint32 fg_color3_out, fg_alpha = 0, bg_alpha = 0;
- int off, pnum;
+ struct mdp4_overlay_pipe *bspipe;
+ int ptype, pnum, pndx, mixer;
+ int format, alpha_enable, alpha;
- if (pipe->mixer_stage == MDP4_MIXER_STAGE_BASE)
+ if (pipe->pipe_type != OVERLAY_TYPE_BF)
return;
+ mixer = pipe->mixer_num;
+
+ /* retrieve original base layer */
+ bspipe = ctrl->baselayer[mixer];
+ if (bspipe == NULL) {
+ pr_err("%s: no base layer at mixer=%d\n",
+ __func__, mixer);
+ return;
+ }
+
+ ptype = bspipe->pipe_type;
+ pnum = bspipe->pipe_num;
+ pndx = bspipe->pipe_ndx;
+ format = bspipe->src_format;
+ alpha_enable = bspipe->alpha_enable;
+ alpha = bspipe->alpha;
+ *bspipe = *pipe; /* restore base layer configuration */
+ bspipe->pipe_type = ptype;
+ bspipe->pipe_num = pnum;
+ bspipe->pipe_ndx = pndx;
+ bspipe->src_format = format;
+ bspipe->alpha_enable = alpha_enable;
+ bspipe->alpha = alpha;
+
+ bspipe->pipe_used++; /* mark base layer pipe used */
+
+ ctrl->baselayer[mixer] = NULL;
+
+ /* free borderfill pipe */
+ pipe->pipe_used = 0;
+
+ mdp4_dsi_video_base_swap(bspipe);
+
+ /* free borderfill pipe */
+ mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_down(pipe);
+ mdp4_overlay_pipe_free(pipe);
+
+ /* stage up base layer */
+ mdp4_overlay_reg_flush(bspipe, 1);
+ /* restore original base layer */
+ mdp4_mixer_stage_up(bspipe);
+}
+
+
+static struct mdp4_overlay_pipe *mdp4_background_layer(int mixer,
+ struct mdp4_overlay_pipe *sp)
+{
+ struct mdp4_overlay_pipe *pp;
+ struct mdp4_overlay_pipe *kp;
+ int i;
+
+ kp = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+ for (i = MDP4_MIXER_STAGE_BASE; i < MDP4_MIXER_STAGE_MAX; i++) {
+ pp = ctrl->stage[mixer][i];
+ if (pp == NULL)
+ continue;
+ if (pp == sp)
+ break;
+
+ if ((pp->dst_x <= sp->dst_x) &&
+ ((pp->dst_x + pp->dst_w) >= (sp->dst_x + sp->dst_w))) {
+ if ((pp->dst_y <= sp->dst_y) &&
+ ((pp->dst_y + pp->dst_h) >=
+ (sp->dst_y + sp->dst_h))) {
+ kp = pp;
+ }
+ }
+ }
+ return kp;
+}
+
+static void mdp4_overlay_bg_solidfill(struct blend_cfg *blend)
+{
+ struct mdp4_overlay_pipe *pipe;
+ char *base;
+ u32 op_mode, format;
+ int pnum, ptype;
+
+ pipe = blend->solidfill_pipe;
+ if (pipe == NULL)
+ return;
+
+ if (pipe->pipe_type == OVERLAY_TYPE_BF)
+ return;
+
+ ptype = mdp4_overlay_format2type(pipe->src_format);
+ if (ptype == OVERLAY_TYPE_RGB) {
+ pnum = pipe->pipe_num - OVERLAY_PIPE_RGB1;
+ base = MDP_BASE + MDP4_RGB_BASE;
+ base += MDP4_RGB_OFF * pnum;
+ } else {
+ pnum = pipe->pipe_num - OVERLAY_PIPE_VG1;
+ base = MDP_BASE + MDP4_VIDEO_BASE;
+ base += MDP4_VIDEO_OFF * pnum;
+ }
+
+ format = inpdw(base + 0x50);
+ if (blend->solidfill) {
+ format |= MDP4_FORMAT_SOLID_FILL;
+ /*
+ * If solid fill is enabled, flip and scale
+ * have to be disabled. otherwise, h/w
+ * underruns.
+ */
+ op_mode = inpdw(base + 0x0058);
+ op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
+ op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
+ outpdw(base + 0x0058, op_mode);
+ outpdw(base + 0x1008, 0); /* black */
+ } else {
+ format &= ~MDP4_FORMAT_SOLID_FILL;
+ blend->solidfill_pipe = NULL;
+ }
+
+ outpdw(base + 0x50, format);
+
+ mdp4_overlay_reg_flush(pipe, 0);
+}
+
+/*
+ * D(i+1) = Ks * S + Kd * D(i)
+ */
+void mdp4_mixer_blend_setup(int mixer)
+{
+ struct mdp4_overlay_pipe *d_pipe;
+ struct mdp4_overlay_pipe *s_pipe;
+ struct blend_cfg *blend;
+ int i, off, ptype;
+ int d_alpha, s_alpha;
+ unsigned char *overlay_base;
+ uint32 c0, c1, c2;
+
+
+ d_pipe = ctrl->stage[mixer][MDP4_MIXER_STAGE_BASE];
+ if (d_pipe == NULL) {
+ pr_err("%s: Error: no bg_pipe at mixer=%d\n", __func__, mixer);
+ return;
+ }
+
+ blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE0];
+ for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+ blend->solidfill = 0;
+ blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_ALPHA_BG_CONST);
+ s_pipe = ctrl->stage[mixer][i];
+ if (s_pipe == NULL) {
+ blend++;
+ d_pipe = NULL;
+ d_alpha = 0;
+ continue;
+ }
+ d_pipe = mdp4_background_layer(mixer, s_pipe);
+ d_alpha = d_pipe->alpha_enable;
+ s_alpha = s_pipe->alpha_enable;
+ pr_debug("%s: stage=%d: bg: ndx=%d da=%d dalpha=%x "
+ "fg: ndx=%d sa=%d salpha=%x is_fg=%d\n",
+ __func__, i-2, d_pipe->pipe_ndx, d_alpha, d_pipe->alpha,
+ s_pipe->pipe_ndx, s_alpha, s_pipe->alpha, s_pipe->is_fg);
+
+ /* base on fg's alpha */
+ blend->bg_alpha = 0x0ff - s_pipe->alpha;
+ blend->fg_alpha = s_pipe->alpha;
+ blend->co3_sel = 1; /* use fg alpha */
+
+ if (s_pipe->is_fg) {
+ if (s_pipe->alpha == 0xff) {
+ blend->solidfill = 1;
+ blend->solidfill_pipe = d_pipe;
+ }
+ } else if (s_alpha) {
+ blend->op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
+ MDP4_BLEND_BG_INV_ALPHA);
+ } else if (d_alpha) {
+ ptype = mdp4_overlay_format2type(s_pipe->src_format);
+ if (ptype == OVERLAY_TYPE_VIDEO) {
+ blend->op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_ALPHA_BG_PIXEL |
+ MDP4_BLEND_FG_INV_ALPHA);
+ blend->co3_sel = 0; /* use bg alpha */
+ } else {
+ /* s_pipe is rgb without alpha */
+ blend->op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
+ MDP4_BLEND_BG_ALPHA_BG_CONST);
+ blend->bg_alpha = 0;
+ }
+ }
+
+ if (s_pipe->transp != MDP_TRANSP_NOP) {
+ if (s_pipe->is_fg) {
+ transp_color_key(s_pipe->src_format,
+ s_pipe->transp, &c0, &c1, &c2);
+ /* Fg blocked */
+ blend->op |= MDP4_BLEND_FG_TRANSP_EN;
+ /* lower limit */
+ blend->transp_low0 = (c1 << 16 | c0);
+ blend->transp_low1 = c2;
+ /* upper limit */
+ blend->transp_high0 = (c1 << 16 | c0);
+ blend->transp_high1 = c2;
+ } else {
+ transp_color_key(d_pipe->src_format,
+ s_pipe->transp, &c0, &c1, &c2);
+ /* Fg blocked */
+ blend->op |= MDP4_BLEND_BG_TRANSP_EN;
+ blend--; /* one stage back */
+ /* lower limit */
+ blend->transp_low0 = (c1 << 16 | c0);
+ blend->transp_low1 = c2;
+ /* upper limit */
+ blend->transp_high0 = (c1 << 16 | c0);
+ blend->transp_high1 = c2;
+ blend++; /* back to original stage */
+ }
+ }
+ blend++;
+ }
+
/* mixer numer, /dev/fb0, /dev/fb1, /dev/fb2 */
- if (pipe->mixer_num == MDP4_MIXER2)
+ if (mixer == MDP4_MIXER2)
overlay_base = MDP_BASE + MDP4_OVERLAYPROC2_BASE;/* 0x88000 */
- else if (pipe->mixer_num == MDP4_MIXER1)
+ else if (mixer == MDP4_MIXER1)
overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
else
overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
- /* stage 0 to stage 2 */
- off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0);
-
- bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
- MDP4_MIXER_STAGE_BASE);
- if (bg_pipe == NULL) {
- pr_err("%s: Error: no bg_pipe\n", __func__);
- return;
- }
-
- if (bg_pipe->pipe_type == OVERLAY_TYPE_BF &&
- pipe->mixer_stage > MDP4_MIXER_STAGE0) {
- bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
- MDP4_MIXER_STAGE0);
- }
-
- if (pipe->alpha_enable) {
- /* alpha channel is lost on VG pipe when downscaling */
- if (pipe->pipe_type == OVERLAY_TYPE_VIDEO &&
- (pipe->dst_w < pipe->src_w || pipe->dst_h < pipe->src_h))
- fg_alpha = 0;
- else
- fg_alpha = 1;
- }
-
- if (!fg_alpha && bg_pipe && bg_pipe->alpha_enable) {
- struct mdp4_overlay_pipe *tmp;
- int stage;
-
- bg_alpha = 1;
- /* check all bg layers are opaque to propagate bg alpha */
- stage = bg_pipe->mixer_stage + 1;
- for (; stage < pipe->mixer_stage; stage++) {
- tmp = mdp4_overlay_stage_pipe(pipe->mixer_num, stage);
- if (!tmp || tmp->alpha_enable || tmp->is_fg) {
- bg_alpha = 0;
- break;
- }
- }
- }
-
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ blend = &ctrl->blend[mixer][MDP4_MIXER_STAGE_BASE];
+ /* lower limit */
+ outpdw(overlay_base + 0x180, blend->transp_low0);
+ outpdw(overlay_base + 0x184, blend->transp_low1);
+ /* upper limit */
+ outpdw(overlay_base + 0x188, blend->transp_high0);
+ outpdw(overlay_base + 0x18c, blend->transp_high1);
+ blend++; /* stage0 */
+ for (i = MDP4_MIXER_STAGE0; i < MDP4_MIXER_STAGE_MAX; i++) {
+ off = 20 * i;
+ off = 0x20 * (i - MDP4_MIXER_STAGE0);
+ if (i == MDP4_MIXER_STAGE3)
+ off -= 4;
- blend_op = (MDP4_BLEND_FG_ALPHA_FG_CONST |
- MDP4_BLEND_BG_ALPHA_BG_CONST);
- outpdw(overlay_base + off + 0x108, pipe->alpha);
- outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
- fg_color3_out = 1; /* keep fg alpha by default */
+ if (blend->solidfill_pipe)
+ mdp4_overlay_bg_solidfill(blend);
- if (pipe->is_fg) {
- if (pipe->alpha == 0xff &&
- bg_pipe->pipe_type == OVERLAY_TYPE_RGB) {
- u32 op_mode;
- pnum = bg_pipe->pipe_num - OVERLAY_PIPE_RGB1;
- rgb_base = MDP_BASE + MDP4_RGB_BASE;
- rgb_base += MDP4_RGB_OFF * pnum;
- rgb_src_format = inpdw(rgb_base + 0x50);
- rgb_src_format |= MDP4_FORMAT_SOLID_FILL;
- /*
- * If solid fill is enabled, flip and scale
- * have to be disabled. otherwise, h/w
- * underruns. Also flush the pipe inorder
- * to take solid fill into effect.
- */
- op_mode = inpdw(rgb_base + 0x0058);
- op_mode &= ~(MDP4_OP_FLIP_LR + MDP4_OP_SCALEX_EN);
- op_mode &= ~(MDP4_OP_FLIP_UD + MDP4_OP_SCALEY_EN);
- outpdw(rgb_base + 0x0058, op_mode);
- outpdw(rgb_base + 0x50, rgb_src_format);
- outpdw(rgb_base + 0x1008, constant_color);
- mdp4_overlay_reg_flush(bg_pipe, 0);
- }
- } else if (fg_alpha) {
- blend_op = (MDP4_BLEND_BG_ALPHA_FG_PIXEL |
- MDP4_BLEND_BG_INV_ALPHA);
- fg_color3_out = 1; /* keep fg alpha */
- } else if (bg_alpha) {
- blend_op = (MDP4_BLEND_BG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_ALPHA_BG_PIXEL |
- MDP4_BLEND_FG_INV_ALPHA);
- fg_color3_out = 0; /* keep bg alpha */
- }
-
- if (pipe->transp != MDP_TRANSP_NOP) {
- if (pipe->is_fg) {
- transp_color_key(pipe->src_format, pipe->transp,
- &c0, &c1, &c2);
- /* Fg blocked */
- blend_op |= MDP4_BLEND_FG_TRANSP_EN;
- /* lower limit */
- outpdw(overlay_base + off + 0x110,
- (c1 << 16 | c0));/* low */
- outpdw(overlay_base + off + 0x114, c2);/* low */
+ outpdw(overlay_base + off + 0x108, blend->fg_alpha);
+ outpdw(overlay_base + off + 0x10c, blend->bg_alpha);
+ outpdw(overlay_base + off + 0x104, blend->op);
+ outpdw(overlay_base + (off << 5) + 0x1004, blend->co3_sel);
+ outpdw(overlay_base + off + 0x110, blend->transp_low0);/* low */
+ outpdw(overlay_base + off + 0x114, blend->transp_low1);/* low */
/* upper limit */
- outpdw(overlay_base + off + 0x118,
- (c1 << 16 | c0));
- outpdw(overlay_base + off + 0x11c, c2);
- } else if (bg_pipe) {
- transp_color_key(bg_pipe->src_format,
- pipe->transp, &c0, &c1, &c2);
- /* bg blocked */
- blend_op |= MDP4_BLEND_BG_TRANSP_EN;
- /* lower limit */
- outpdw(overlay_base + 0x180,
- (c1 << 16 | c0));/* low */
- outpdw(overlay_base + 0x184, c2);/* low */
- /* upper limit */
- outpdw(overlay_base + 0x188,
- (c1 << 16 | c0));/* high */
- outpdw(overlay_base + 0x18c, c2);/* high */
- }
+ outpdw(overlay_base + off + 0x118, blend->transp_high0);
+ outpdw(overlay_base + off + 0x11c, blend->transp_high1);
+ blend++;
}
-
- outpdw(overlay_base + off + 0x104, blend_op);
- outpdw(overlay_base + (off << 5) + 0x1004, fg_color3_out);
-
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all)
{
- struct mdp4_overlay_pipe *bg_pipe;
- uint32 bits = 0;
+ int mixer;
+ uint32 *reg;
+
+ mixer = pipe->mixer_num;
+ reg = &ctrl->flush[mixer];
+ *reg |= (1 << (2 + pipe->pipe_num));
if (all) {
- if (pipe->mixer_num == MDP4_MIXER1)
- bits |= 0x02;
+ if (mixer == MDP4_MIXER0)
+ *reg |= 0x01;
else
- bits |= 0x01;
+ *reg |= 0x02;
}
+}
- if (pipe->pipe_num <= OVERLAY_PIPE_RGB2)
- bits |= 1 << (2 + pipe->pipe_num);
- if (pipe->is_fg && pipe->alpha == 0xFF) {
- bg_pipe = mdp4_overlay_stage_pipe(pipe->mixer_num,
- MDP4_MIXER_STAGE_BASE);
- bits |= 1 << (2 + bg_pipe->pipe_num);
- }
+void mdp4_overlay_flush_piggyback(int m0, int m1)
+{
+ u32 data;
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */
- mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ data = ctrl->flush[m0] | ctrl->flush[m1];
+ ctrl->flush[m0] = data;
+}
+
+void mdp4_overlay_reg_flush_reset(struct mdp4_overlay_pipe *pipe)
+{
+ int mixer;
+
+ mixer = pipe->mixer_num;
+ ctrl->flush[mixer] = 0;
}
struct mdp4_overlay_pipe *mdp4_overlay_stage_pipe(int mixer, int stage)
@@ -1810,6 +1952,11 @@
int i;
struct mdp4_overlay_pipe *pipe;
+ if (ptype == OVERLAY_TYPE_BF) {
+ if (!mdp4_overlay_borderfill_supported())
+ return NULL;
+ }
+
for (i = 0; i < OVERLAY_PIPE_MAX; i++) {
pipe = &ctrl->plist[i];
if ((pipe->pipe_used == 0) && ((pipe->pipe_type == ptype) ||
@@ -1951,7 +2098,7 @@
return -ERANGE;
}
- if (req->z_order < 0 || req->z_order > 2) {
+ if (req->z_order < 0 || req->z_order > 3) {
pr_err("%s: z_order=%d out of range!\n", __func__,
req->z_order);
mdp4_stat.err_zorder++;
@@ -2076,12 +2223,12 @@
if (req->id == MSMFB_NEW_REQUEST) { /* new request */
pipe->pipe_used++;
pipe->mixer_num = mixer;
- pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
pr_debug("%s: zorder=%d pipe ndx=%d num=%d\n", __func__,
req->z_order, pipe->pipe_ndx, pipe->pipe_num);
}
+ pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
pipe->src_width = req->src.width & 0x1fff; /* source img width */
pipe->src_height = req->src.height & 0x1fff; /* source img height */
pipe->src_h = req->src_rect.h & 0x07ff;
@@ -2217,6 +2364,8 @@
mdp4_dsi_video_overlay_blt(mfd, req);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
mdp4_lcdc_overlay_blt(mfd, req);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt(mfd, req);
mutex_unlock(&mfd->dma->ov_mutex);
@@ -2238,6 +2387,8 @@
ret = mdp4_dsi_video_overlay_blt_offset(mfd, req);
else if (ctrl->panel_mode & MDP4_PANEL_LCDC)
ret = mdp4_lcdc_overlay_blt_offset(mfd, req);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt_offset(mfd, req);
mutex_unlock(&mfd->dma->ov_mutex);
@@ -2331,7 +2482,14 @@
void mdp4_update_perf_level(u32 perf_level)
{
+ static int first = 1;
+
new_perf_level = perf_level;
+
+ if (first) {
+ first = 0;
+ mdp4_set_perf_level();
+ }
}
void mdp4_set_perf_level(void)
@@ -2365,6 +2523,8 @@
mdp4_dsi_video_blt_start(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_overlay_blt_start(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt_start(mfd);
} else {
if (mfd->panel_info.type == LCDC_PANEL ||
mfd->panel_info.type == LVDS_PANEL)
@@ -2373,6 +2533,8 @@
mdp4_dsi_video_blt_stop(mfd);
else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD)
mdp4_dsi_overlay_blt_stop(mfd);
+ else if (ctrl->panel_mode & MDP4_PANEL_MDDI)
+ mdp4_mddi_overlay_blt_stop(mfd);
}
mfd->ov0_blt_state = mfd->use_ov0_blt;
}
@@ -2413,6 +2575,12 @@
use_blt = 1;
}
+ if (mfd->panel_info.type == MDDI_PANEL) {
+ if ((req->src_rect.h/2) >= req->dst_rect.h ||
+ (req->src_rect.w/2) >= req->dst_rect.w)
+ use_blt = 1;
+ }
+
if (mfd->mdp_rev == MDP_REV_41) {
/*
* writeback (blt) mode to provide work around for
@@ -2539,6 +2707,7 @@
mdp4_set_perf_level();
} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
mdp4_mddi_dma_busy_wait(mfd);
+ mdp4_mddi_blt_dmap_busy_wait(mfd);
mdp4_set_perf_level();
}
} else {
@@ -2553,6 +2722,24 @@
return 0;
}
+int mdp4_overlay_unset_mixer(int mixer)
+{
+ struct mdp4_overlay_pipe *pipe;
+ int i, cnt = 0;
+
+ for (i = MDP4_MIXER_STAGE3; i >= MDP4_MIXER_STAGE_BASE; i--) {
+ pipe = ctrl->stage[mixer][i];
+ if (pipe == NULL)
+ continue;
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
+ mdp4_mixer_stage_down(pipe);
+ mdp4_overlay_pipe_free(pipe);
+ cnt++;
+ }
+
+ return cnt;
+}
+
int mdp4_overlay_unset(struct fb_info *info, int ndx)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -2573,6 +2760,12 @@
return -ENODEV;
}
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ mdp4_overlay_borderfill_stage_down(pipe);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return 0;
+ }
+
if (pipe->mixer_num == MDP4_MIXER2)
ctrl->mixer2_played = 0;
else if (pipe->mixer_num == MDP4_MIXER1)
@@ -2589,21 +2782,17 @@
#else
if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
if (mfd->panel_power_on)
- mdp4_mddi_dma_busy_wait(mfd);
+ mdp4_mddi_blt_dmap_busy_wait(mfd);
}
#endif
}
- if (mfd->mdp_rev >= MDP_REV_41 &&
- mdp4_overlay_is_rgb_type(pipe->src_format) &&
- !mfd->use_ov0_blt && (pipe->mixer_num == MDP4_MIXER0 ||
- hdmi_prim_display)) {
- ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL;
- } else {
- if (pipe->is_fg &&
- !mdp4_overlay_is_rgb_type(pipe->src_format)) {
- mdp4_overlay_bg_solidfill_clear(pipe->mixer_num);
- pipe->is_fg = 0;
+ {
+ mdp4_overlay_reg_flush(pipe, 1);
+
+ if (mfd->use_ov0_blt || pipe->mixer_num == MDP4_MIXER1) {
+ /* unstage pipe forcedly */
+ pipe->flags &= ~MDP_OV_PLAY_NOWAIT;
}
mdp4_mixer_stage_down(pipe);
@@ -2764,6 +2953,12 @@
if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
return -EINTR;
+ if (pipe->pipe_type == OVERLAY_TYPE_BF) {
+ mdp4_overlay_borderfill_stage_up(pipe);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return 0;
+ }
+
img = &req->data;
get_img(img, info, pipe, 0, &start, &len, &srcp0_file,
&ps0_need, &srcp0_ihdl);
@@ -2778,6 +2973,10 @@
pipe->srcp0_addr = addr;
pipe->srcp0_ystride = pipe->src_width * pipe->bpp;
+
+ pr_debug("%s: mixer=%d ndx=%x addr=%x flags=%x\n", __func__,
+ pipe->mixer_num, pipe->pipe_ndx, (int)addr, pipe->flags);
+
if ((req->version_key & VERSION_KEY_MASK) == 0xF9E8D700)
overlay_version = (req->version_key & ~VERSION_KEY_MASK);
@@ -2874,6 +3073,7 @@
if (mfd->use_ov1_blt)
mdp4_overlay1_update_blt_mode(mfd);
+
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
} else {
@@ -2886,11 +3086,7 @@
mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
}
- if ((ctrl->panel_mode & MDP4_PANEL_DTV) ||
- (ctrl->panel_mode & MDP4_PANEL_LCDC) ||
- (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO))
- mdp4_overlay_reg_flush(pipe, 0);
-
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
if (pipe->mixer_num == MDP4_MIXER2) {
@@ -2905,6 +3101,9 @@
ctrl->mixer1_played++;
/* enternal interface */
if (ctrl->panel_mode & MDP4_PANEL_DTV) {
+ if (pipe->flags & MDP_OV_PLAY_NOWAIT)
+ mdp4_overlay_flush_piggyback(MDP4_MIXER0,
+ MDP4_MIXER1);
mdp4_overlay_dtv_start();
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
if (!mfd->use_ov1_blt)
@@ -2933,6 +3132,7 @@
}
#endif
else {
+ mdp4_overlay_reg_flush_reset(pipe);
/* mddi & mipi dsi cmd mode */
if (pipe->flags & MDP_OV_PLAY_NOWAIT) {
mdp4_stat.overlay_play[pipe->mixer_num]++;
@@ -3002,7 +3202,6 @@
},
};
-static int iommu_enabled;
static int mdp_iommu_fault_handler(struct iommu_domain *domain,
struct device *dev, unsigned long iova, int flags)
{
@@ -3012,10 +3211,11 @@
void mdp4_iommu_attach(void)
{
+ static int done;
struct iommu_domain *domain;
int i;
- if (!iommu_enabled) {
+ if (!done) {
for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
int domain_idx;
struct device *ctx = msm_iommu_get_ctx(
@@ -3040,38 +3240,7 @@
continue;
}
}
- pr_debug("Attached MDP IOMMU device\n");
- iommu_enabled = 1;
- }
-}
-
-void mdp4_iommu_detach(void)
-{
- struct iommu_domain *domain;
- int i;
-
- if (!mdp_check_suspended() || mdp4_extn_disp)
- return;
-
- if (iommu_enabled) {
- for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_names); i++) {
- int domain_idx;
- struct device *ctx = msm_iommu_get_ctx(
- msm_iommu_ctx_names[i].name);
-
- if (!ctx)
- continue;
-
- domain_idx = msm_iommu_ctx_names[i].domain;
-
- domain = msm_get_iommu_domain(domain_idx);
- if (!domain)
- continue;
-
- iommu_detach_device(domain, ctx);
- }
- pr_debug("Detached MDP IOMMU device\n");
- iommu_enabled = 0;
+ done = 1;
}
}
@@ -3092,7 +3261,7 @@
return err;
}
- mdp4_mixer_blend_setup(pipe);
+ mdp4_mixer_blend_setup(pipe->mixer_num);
*ppipe = pipe;
return 0;
diff --git a/drivers/video/msm/mdp4_overlay_dsi_cmd.c b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
index a5b4b3e..7ba4e75 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_cmd.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_cmd.c
@@ -114,6 +114,11 @@
}
}
+void mdp4_dsi_cmd_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ dsi_pipe = pipe;
+}
+
void mdp4_overlay_update_dsi_cmd(struct msm_fb_data_type *mfd)
{
MDPIBUF *iBuf = &mfd->ibuf;
@@ -162,6 +167,14 @@
} else {
pipe = dsi_pipe;
}
+
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+
/*
* configure dsi stream id
* dma_p = 0, dma_s = 1
@@ -207,6 +220,8 @@
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -240,6 +255,12 @@
dsi_pipe->src_width_3d = r3d->width;
pipe = dsi_pipe;
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
if (pipe->is_3d)
mdp4_overlay_panel_3d(pipe->mixer_num, MDP4_3D_SIDE_BY_SIDE);
@@ -282,6 +303,8 @@
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+
mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -651,12 +674,22 @@
mdp4_stat.kickoff_ov0++;
}
-void mdp_dsi_cmd_overlay_suspend(void)
+void mdp_dsi_cmd_overlay_suspend(struct msm_fb_data_type *mfd)
{
/* dis-engage rgb0 from mixer0 */
if (dsi_pipe) {
- mdp4_mixer_stage_down(dsi_pipe);
- mdp4_iommu_unmap(dsi_pipe);
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+ /* dsi_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+ dsi_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(dsi_pipe);
+ mdp4_iommu_unmap(dsi_pipe);
+ }
}
}
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index fb71cc1..05c6fe8 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -69,6 +69,11 @@
static void mdp4_overlay_dsi_video_wait4event(struct msm_fb_data_type *mfd,
int intr_done);
+void mdp4_dsi_video_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ dsi_pipe = pipe;
+}
+
int mdp4_dsi_video_on(struct platform_device *pdev)
{
int dsi_width;
@@ -118,8 +123,6 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mdp4_overlay_ctrl_db_reset();
-
fbi = mfd->fbi;
var = &fbi->var;
@@ -192,8 +195,9 @@
mdp4_overlay_dmap_xy(pipe); /* dma_p */
mdp4_overlay_dmap_cfg(mfd, 1);
-
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -291,10 +295,12 @@
int mdp4_dsi_video_off(struct platform_device *pdev)
{
int ret = 0;
+ struct msm_fb_data_type *mfd;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_mixer_pipe_cleanup(dsi_pipe->mixer_num);
MDP_OUTP(MDP_BASE + DSI_VIDEO_BASE, 0);
dsi_video_enabled = 0;
/* MDP cmd block disable */
@@ -308,8 +314,18 @@
/* dis-engage rgb0 from mixer0 */
if (dsi_pipe) {
- mdp4_mixer_stage_down(dsi_pipe);
- mdp4_iommu_unmap(dsi_pipe);
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (dsi_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(dsi_pipe);
+
+ /* dsi_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(dsi_pipe->mixer_num);
+ dsi_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(dsi_pipe);
+ mdp4_iommu_unmap(dsi_pipe);
+ }
}
return ret;
@@ -384,7 +400,6 @@
mdp4_overlay_dmap_cfg(mfd, 1);
mdp4_overlay_reg_flush(pipe, 1);
-
mdp4_mixer_stage_up(pipe);
mb();
@@ -632,7 +647,6 @@
spin_unlock_irqrestore(&mdp_spin_lock, flag);
-
/*
* may need mutex here to sync with whom dsiable
* timing generator
@@ -693,6 +707,12 @@
mutex_lock(&mfd->dma->ov_mutex);
pipe = dsi_pipe;
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
if (mfd->display_iova)
pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -700,7 +720,7 @@
pipe->srcp0_addr = (uint32)(buf + buf_offset);
mdp4_overlay_rgb_setup(pipe);
- mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
mdp4_overlay_dsi_video_start();
mdp4_overlay_dsi_video_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index dd96439..9174bc5 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -56,6 +56,12 @@
static struct mdp4_overlay_pipe *dtv_pipe;
static DECLARE_COMPLETION(dtv_comp);
+void mdp4_dtv_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ if (hdmi_prim_display)
+ dtv_pipe = pipe;
+}
+
static int mdp4_dtv_start(struct msm_fb_data_type *mfd)
{
int dtv_width;
@@ -208,7 +214,6 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_mixer_pipe_cleanup(dtv_pipe->mixer_num);
msleep(20);
MDP_OUTP(MDP_BASE + DTV_BASE, 0);
dtv_enabled = 0;
@@ -234,15 +239,8 @@
mdp_footswitch_ctrl(TRUE);
mdp4_overlay_panel_mode(MDP4_MIXER1, MDP4_PANEL_DTV);
-
- /* Allocate dtv_pipe at dtv_on*/
- if (dtv_pipe == NULL) {
- if (mdp4_overlay_dtv_set(mfd, NULL)) {
- pr_warn("%s: dtv_pipe is NULL, dtv_set failed\n",
- __func__);
- return -EINVAL;
- }
- }
+ if (dtv_pipe != NULL)
+ ret = mdp4_dtv_start(mfd);
ret = panel_next_on(pdev);
if (ret != 0)
@@ -262,19 +260,24 @@
if (dtv_pipe != NULL) {
mdp4_dtv_stop(mfd);
+ if (hdmi_prim_display && mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (dtv_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(dtv_pipe);
- /* delay to make sure the last frame finishes */
- msleep(20);
-
- mdp4_mixer_stage_down(dtv_pipe);
- mdp4_overlay_pipe_free(dtv_pipe);
- mdp4_iommu_unmap(dtv_pipe);
- dtv_pipe = NULL;
+ /* dtv_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(dtv_pipe->mixer_num);
+ dtv_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(dtv_pipe);
+ mdp4_overlay_pipe_free(dtv_pipe);
+ mdp4_iommu_unmap(dtv_pipe);
+ dtv_pipe = NULL;
+ }
}
mdp4_overlay_panel_mode_unset(MDP4_MIXER1, MDP4_PANEL_DTV);
ret = panel_next_off(pdev);
- mdp4_iommu_detach();
mdp_footswitch_ctrl(FALSE);
dev_info(&pdev->dev, "mdp4_overlay_dtv: off");
@@ -610,7 +613,8 @@
*/
temp_src_format = inpdw(rgb_base + 0x0050);
MDP_OUTP(rgb_base + 0x0050, temp_src_format | BIT(22));
- mdp4_overlay_reg_flush(dtv_pipe, 0);
+ mdp4_overlay_reg_flush(dtv_pipe, 1);
+ mdp4_mixer_stage_up(dtv_pipe);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
@@ -665,10 +669,12 @@
if (!change)
return;
- mdp4_overlay_dtv_wait4dmae(mfd);
+ if (dtv_enabled) {
+ mdp4_overlay_dtv_wait4dmae(mfd);
+ MDP_OUTP(MDP_BASE + DTV_BASE, 0); /* stop dtv */
+ msleep(20);
+ }
- MDP_OUTP(MDP_BASE + DTV_BASE, 0); /* stop dtv */
- msleep(20);
mdp4_overlayproc_cfg(dtv_pipe);
mdp4_overlay_dmae_xy(dtv_pipe);
MDP_OUTP(MDP_BASE + DTV_BASE, 1); /* start dtv */
@@ -695,12 +701,28 @@
return;
}
mutex_lock(&mfd->dma->ov_mutex);
+ if (dtv_pipe == NULL) {
+ if (mdp4_overlay_dtv_set(mfd, NULL)) {
+ pr_warn("%s: dtv_pipe == NULL\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+ }
+
pipe = dtv_pipe;
+
+ if (hdmi_prim_display && (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE)) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
+
if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
mdp4_overlay_rgb_setup(pipe);
}
- mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
mdp4_overlay_dtv_start();
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index a1fecb6..fd6d365 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -46,6 +46,11 @@
static struct mdp4_overlay_pipe *lcdc_pipe;
static struct completion lcdc_comp;
+void mdp4_lcdc_base_swap(struct mdp4_overlay_pipe *pipe)
+{
+ lcdc_pipe = pipe;
+}
+
int mdp_lcdc_on(struct platform_device *pdev)
{
int lcdc_width;
@@ -95,8 +100,6 @@
if (mfd->key != MFD_KEY)
return -EINVAL;
- mdp4_overlay_ctrl_db_reset();
-
fbi = mfd->fbi;
var = &fbi->var;
@@ -155,6 +158,8 @@
mdp4_overlay_dmap_cfg(mfd, 1);
mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1);
+ mdp4_mixer_stage_up(pipe);
mdp4_overlayproc_cfg(pipe);
@@ -176,7 +181,12 @@
lcdc_bpp = mfd->panel_info.bpp;
hsync_period =
- hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
+ hsync_pulse_width + h_back_porch + h_front_porch;
+ if ((mfd->panel_info.type == LVDS_PANEL) &&
+ (mfd->panel_info.lvds.channel_mode == LVDS_DUAL_CHANNEL_MODE))
+ hsync_period += lcdc_width / 2;
+ else
+ hsync_period += lcdc_width;
hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
hsync_start_x = hsync_pulse_width + h_back_porch;
hsync_end_x = hsync_period - h_front_porch - 1;
@@ -211,8 +221,13 @@
#ifdef CONFIG_FB_MSM_MDP40
- hsync_polarity = 1;
- vsync_polarity = 1;
+ if (mfd->panel_info.lcdc.is_sync_active_high) {
+ hsync_polarity = 0;
+ vsync_polarity = 0;
+ } else {
+ hsync_polarity = 1;
+ vsync_polarity = 1;
+ }
lcdc_underflow_clr |= 0x80000000; /* enable recovery */
#else
hsync_polarity = 0;
@@ -263,7 +278,6 @@
/* MDP cmd block enable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp4_mixer_pipe_cleanup(lcdc_pipe->mixer_num);
MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
lcdc_enabled = 0;
/* MDP cmd block disable */
@@ -280,8 +294,18 @@
/* dis-engage rgb0 from mixer0 */
if (lcdc_pipe) {
- mdp4_mixer_stage_down(lcdc_pipe);
- mdp4_iommu_unmap(lcdc_pipe);
+ if (mfd->ref_cnt == 0) {
+ /* adb stop */
+ if (lcdc_pipe->pipe_type == OVERLAY_TYPE_BF)
+ mdp4_overlay_borderfill_stage_down(lcdc_pipe);
+
+ /* lcdc_pipe == rgb1 */
+ mdp4_overlay_unset_mixer(lcdc_pipe->mixer_num);
+ lcdc_pipe = NULL;
+ } else {
+ mdp4_mixer_stage_down(lcdc_pipe);
+ mdp4_iommu_unmap(lcdc_pipe);
+ }
}
#ifdef CONFIG_MSM_BUS_SCALING
@@ -494,7 +518,7 @@
}
}
/*
- * make sure the MIPI_DSI_WRITEBACK_SIZE defined at boardfile
+ * make sure the WRITEBACK_SIZE defined at boardfile
* has enough space h * w * 3 * 2
*/
static void mdp4_lcdc_do_blt(struct msm_fb_data_type *mfd, int enable)
@@ -527,9 +551,12 @@
if (!change)
return;
- mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE);
- MDP_OUTP(MDP_BASE + LCDC_BASE, 0); /* stop lcdc */
- msleep(20);
+ if (lcdc_enabled) {
+ mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE);
+ MDP_OUTP(MDP_BASE + LCDC_BASE, 0); /* stop lcdc */
+ msleep(20);
+ }
+
mdp4_overlayproc_cfg(lcdc_pipe);
mdp4_overlay_dmap_xy(lcdc_pipe);
if (lcdc_pipe->blt_addr) {
@@ -585,6 +612,12 @@
mutex_lock(&mfd->dma->ov_mutex);
pipe = lcdc_pipe;
+ if (pipe->pipe_used == 0 ||
+ pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) {
+ pr_err("%s: NOT baselayer\n", __func__);
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return;
+ }
if (mfd->display_iova)
pipe->srcp0_addr = mfd->display_iova + buf_offset;
@@ -592,7 +625,7 @@
pipe->srcp0_addr = (uint32)(buf + buf_offset);
mdp4_overlay_rgb_setup(pipe);
- mdp4_overlay_reg_flush(pipe, 0);
+ mdp4_overlay_reg_flush(pipe, 1);
mdp4_mixer_stage_up(pipe);
mdp4_overlay_lcdc_start();
mdp4_overlay_lcdc_vsync_push(mfd, pipe);
diff --git a/drivers/video/msm/mdp4_overlay_mddi.c b/drivers/video/msm/mdp4_overlay_mddi.c
index 5aa5965..82864918 100644
--- a/drivers/video/msm/mdp4_overlay_mddi.c
+++ b/drivers/video/msm/mdp4_overlay_mddi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2009-2012, Code Aurora Forum. 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
@@ -124,7 +124,6 @@
printk(KERN_INFO "%s: format2type failed\n", __func__);
mddi_pipe = pipe; /* keep it */
- mddi_pipe->blt_end = 1; /* mark as end */
mddi_ld_param = 0;
mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
@@ -163,6 +162,8 @@
(MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
MDP_OUTP(MDP_BASE + 0x00098, 0x01);
+ mdp4_init_writeback_buf(mfd, MDP4_MIXER0);
+ pipe->blt_addr = 0;
} else {
pipe = mddi_pipe;
}
@@ -246,59 +247,82 @@
/* MDP cmd block disable */
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
-
}
-int mdp4_mddi_overlay_blt_offset(int *off)
-{
- if (mdp_hw_revision < MDP4_REVISION_V2_1) { /* need dmas dmap switch */
- if (mddi_pipe->blt_end ||
- (mdp4_overlay_mixer_play(mddi_pipe->mixer_num) == 0)) {
- *off = -1;
- return -EINVAL;
- }
- } else {
- /* no dmas dmap switch */
- if (mddi_pipe->blt_end) {
- *off = -1;
- return -EINVAL;
- }
- }
-
- if (mddi_pipe->blt_cnt & 0x01)
- *off = mddi_pipe->src_height * mddi_pipe->src_width * 3;
- else
- *off = 0;
-
- return 0;
-}
-
-void mdp4_mddi_overlay_blt(ulong addr)
+int mdp4_mddi_overlay_blt_start(struct msm_fb_data_type *mfd)
{
unsigned long flag;
- spin_lock_irqsave(&mdp_spin_lock, flag);
- if (addr) {
- mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
- mdp_intr_mask |= INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
- mddi_pipe->blt_cnt = 0;
- mddi_pipe->blt_end = 0;
- mddi_pipe->blt_addr = addr;
- } else {
- mddi_pipe->blt_end = 1; /* mark as end */
+ pr_debug("%s: blt_end=%d blt_addr=%x pid=%d\n",
+ __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr, current->pid);
+
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER0);
+
+ if (mfd->ov0_wb_buf->phys_addr == 0) {
+ pr_info("%s: no blt_base assigned\n", __func__);
+ return -EBUSY;
}
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (mddi_pipe->blt_addr == 0) {
+ mdp4_mddi_dma_busy_wait(mfd);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mddi_pipe->blt_end = 0;
+ mddi_pipe->blt_cnt = 0;
+ mddi_pipe->ov_cnt = 0;
+ mddi_pipe->dmap_cnt = 0;
+ mddi_pipe->blt_addr = mfd->ov0_wb_buf->phys_addr;
+ mdp4_stat.blt_mddi++;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ return 0;
+}
+
+ return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_stop(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+
+ pr_debug("%s: blt_end=%d blt_addr=%x\n",
+ __func__, mddi_pipe->blt_end, (int)mddi_pipe->blt_addr);
+
+ if ((mddi_pipe->blt_end == 0) && mddi_pipe->blt_addr) {
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mddi_pipe->blt_end = 1; /* mark as end */
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ return 0;
+ }
+
+ return -EBUSY;
+}
+
+int mdp4_mddi_overlay_blt_offset(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ req->offset = 0;
+ req->width = mddi_pipe->src_width;
+ req->height = mddi_pipe->src_height;
+ req->bpp = mddi_pipe->bpp;
+
+ return sizeof(*req);
+}
+
+void mdp4_mddi_overlay_blt(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_blt *req)
+{
+ if (req->enable)
+ mdp4_mddi_overlay_blt_start(mfd);
+ else if (req->enable == 0)
+ mdp4_mddi_overlay_blt_stop(mfd);
+
}
void mdp4_blt_xy_update(struct mdp4_overlay_pipe *pipe)
{
- uint32 off, addr;
+ uint32 off, addr, addr2;
int bpp;
char *overlay_base;
-
if (pipe->blt_addr == 0)
return;
@@ -317,29 +341,62 @@
/* dmap */
MDP_OUTP(MDP_BASE + 0x90008, addr);
+ off = 0;
+ if (pipe->ov_cnt & 0x01)
+ off = pipe->src_height * pipe->src_width * bpp;
+ addr2 = pipe->blt_addr + off;
/* overlay 0 */
overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
- outpdw(overlay_base + 0x000c, addr);
- outpdw(overlay_base + 0x001c, addr);
+ outpdw(overlay_base + 0x000c, addr2);
+ outpdw(overlay_base + 0x001c, addr2);
}
/*
* mdp4_dmap_done_mddi: called from isr
*/
-void mdp4_dma_p_done_mddi(void)
+void mdp4_dma_p_done_mddi(struct mdp_dma_data *dma)
{
- if (mddi_pipe->blt_end) {
- mddi_pipe->blt_addr = 0;
- mdp_intr_mask &= ~INTR_DMA_P_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- mdp4_overlayproc_cfg(mddi_pipe);
- mdp4_overlay_dmap_xy(mddi_pipe);
+ int diff;
+
+ mddi_pipe->dmap_cnt++;
+ diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+ pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+ __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+ if (diff <= 0) {
+ spin_lock(&mdp_spin_lock);
+ dma->dmap_busy = FALSE;
+ complete(&dma->dmap_comp);
+ spin_unlock(&mdp_spin_lock);
+
+ if (mddi_pipe->blt_end) {
+ mddi_pipe->blt_end = 0;
+ mddi_pipe->blt_addr = 0;
+ pr_debug("%s: END, ov_cnt=%d dmap_cnt=%d\n", __func__,
+ mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+ mdp_intr_mask &= ~INTR_DMA_P_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ }
+
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+ mdp_disable_irq_nosync(MDP_DMA2_TERM); /* disable intr */
+ return;
}
- /*
- * single buffer, no need to increase
- * mdd_pipe->dmap_cnt here
- */
+ spin_lock(&mdp_spin_lock);
+ dma->busy = FALSE;
+ spin_unlock(&mdp_spin_lock);
+ complete(&dma->comp);
+ if (busy_wait_cnt)
+ busy_wait_cnt--;
+
+ pr_debug("%s: kickoff dmap\n", __func__);
+
+ mdp4_blt_xy_update(mddi_pipe);
+ /* kick off dmap */
+ outpdw(MDP_BASE + 0x000c, 0x0);
+ mdp4_stat.kickoff_dmap++;
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
}
/*
@@ -347,37 +404,60 @@
*/
void mdp4_overlay0_done_mddi(struct mdp_dma_data *dma)
{
- mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+ int diff;
+ if (mddi_pipe->blt_addr == 0) {
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+ spin_lock(&mdp_spin_lock);
+ dma->busy = FALSE;
+ spin_unlock(&mdp_spin_lock);
+ complete(&dma->comp);
+
+ if (busy_wait_cnt)
+ busy_wait_cnt--;
+ mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+
+ return;
+ }
+
+ /* blt enabled */
+ if (mddi_pipe->blt_end == 0)
+ mddi_pipe->ov_cnt++;
+
+ pr_debug("%s: ov_cnt=%d dmap_cnt=%d\n",
+ __func__, mddi_pipe->ov_cnt, mddi_pipe->dmap_cnt);
+
+ if (mddi_pipe->blt_cnt == 0) {
+ /* first kickoff since blt enabled */
+ mdp_intr_mask |= INTR_DMA_P_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ }
+
+ mddi_pipe->blt_cnt++;
+
+ diff = mddi_pipe->ov_cnt - mddi_pipe->dmap_cnt;
+ if (diff >= 2) {
+ mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
+ return;
+ }
+
+ spin_lock(&mdp_spin_lock);
dma->busy = FALSE;
+ dma->dmap_busy = TRUE;
+ spin_unlock(&mdp_spin_lock);
complete(&dma->comp);
- mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK,
- MDP_BLOCK_POWER_OFF, TRUE);
if (busy_wait_cnt)
busy_wait_cnt--;
- pr_debug("%s: ISR-done\n", __func__);
+ pr_debug("%s: kickoff dmap\n", __func__);
- if (mddi_pipe->blt_addr) {
- if (mddi_pipe->blt_cnt == 0) {
- mdp4_overlayproc_cfg(mddi_pipe);
- mdp4_overlay_dmap_xy(mddi_pipe);
- mddi_pipe->ov_cnt = 0;
- mddi_pipe->dmap_cnt = 0;
- /* BLT start from next frame */
- } else {
- mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON,
- FALSE);
- mdp4_blt_xy_update(mddi_pipe);
- outpdw(MDP_BASE + 0x000c, 0x0); /* start DMAP */
- }
- mddi_pipe->blt_cnt++;
- mddi_pipe->ov_cnt++;
- }
-
-
-
+ mdp4_blt_xy_update(mddi_pipe);
+ mdp_enable_irq(MDP_DMA2_TERM); /* enable intr */
+ /* kick off dmap */
+ outpdw(MDP_BASE + 0x000c, 0x0);
+ mdp4_stat.kickoff_dmap++;
+ mdp_disable_irq_nosync(MDP_OVERLAY0_TERM);
}
void mdp4_mddi_overlay_restore(void)
@@ -392,6 +472,9 @@
if (mddi_mfd && mddi_pipe) {
mdp4_mddi_dma_busy_wait(mddi_mfd);
mdp4_overlay_update_lcd(mddi_mfd);
+
+ if (mddi_pipe->blt_addr)
+ mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
mddi_mfd->dma_update_flag = 1;
}
@@ -399,9 +482,27 @@
mdp4_mddi_overlay_dmas_restore();
}
+void mdp4_mddi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+ int need_wait = 0;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (mfd->dma->dmap_busy == TRUE) {
+ INIT_COMPLETION(mfd->dma->dmap_comp);
+ need_wait++;
+ }
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (need_wait) {
+ /* wait until DMA finishes the current job */
+ wait_for_completion(&mfd->dma->dmap_comp);
+ }
+}
+
/*
* mdp4_mddi_cmd_dma_busy_wait: check mddi link activity
- * dsi link is a shared resource and it can only be used
+ * mddi link is a shared resource and it can only be used
* while it is in idle state.
* ov_mutex need to be acquired before call this function.
*/
@@ -432,7 +533,24 @@
void mdp4_mddi_kickoff_video(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
- pr_debug("%s: pid=%d\n", __func__, current->pid);
+ /*
+ * a video kickoff may happen before UI kickoff after
+ * blt enabled. mdp4_overlay_update_lcd() need
+ * to be called before kickoff.
+ * vice versa for blt disabled.
+ */
+ if (mddi_pipe->blt_addr && mddi_pipe->blt_cnt == 0)
+ mdp4_overlay_update_lcd(mfd); /* first time */
+ else if (mddi_pipe->blt_addr == 0 && mddi_pipe->blt_cnt) {
+ mdp4_overlay_update_lcd(mfd); /* last time */
+ mddi_pipe->blt_cnt = 0;
+ }
+
+ pr_debug("%s: blt_addr=%d blt_cnt=%d\n",
+ __func__, (int)mddi_pipe->blt_addr, mddi_pipe->blt_cnt);
+
+ if (mddi_pipe->blt_addr)
+ mdp4_mddi_blt_dmap_busy_wait(mddi_mfd);
mdp4_mddi_overlay_kickoff(mfd, pipe);
}
@@ -447,11 +565,16 @@
void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
+ unsigned long flag;
/* change mdp clk while mdp is idle` */
mdp4_set_perf_level();
mdp_enable_irq(MDP_OVERLAY0_TERM);
+ spin_lock_irqsave(&mdp_spin_lock, flag);
mfd->dma->busy = TRUE;
+ if (mddi_pipe->blt_addr)
+ mfd->dma->dmap_busy = TRUE;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
/* start OVERLAY pipe */
mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
mdp4_stat.kickoff_ov0++;
@@ -533,7 +656,10 @@
mdp4_set_perf_level();
mdp_enable_irq(MDP_DMA_S_TERM);
- mfd->dma->busy = TRUE;
+
+ if (mddi_pipe->blt_addr == 0)
+ mfd->dma->busy = TRUE;
+
mfd->ibuf_flushed = TRUE;
/* start dma_s pipe */
mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
@@ -561,6 +687,10 @@
if (mfd && mfd->panel_power_on) {
mdp4_mddi_dma_busy_wait(mfd);
+
+ if (mddi_pipe && mddi_pipe->blt_addr)
+ mdp4_mddi_blt_dmap_busy_wait(mfd);
+
mdp4_overlay_update_lcd(mfd);
if (mdp_hw_revision < MDP4_REVISION_V2_1) {
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index b2657cf..f192b12 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -314,6 +314,8 @@
clk_rate = mdp_get_core_clk();
mdp4_fetch_cfg(clk_rate);
+ mdp4_overlay_cfg_init();
+
/* Mark hardware as initialized. Only revisions > v2.1 have a register
* for tracking core reset status. */
if (mdp_hw_revision > MDP4_REVISION_V2_1)
@@ -378,6 +380,7 @@
outpdw(MDP_INTR_CLEAR, isr);
if (isr & INTR_PRIMARY_INTF_UDERRUN) {
+ pr_debug("%s: UNDERRUN -- primary\n", __func__);
mdp4_stat.intr_underrun_p++;
/* When underun occurs mdp clear the histogram registers
that are set before in hw_init so restore them back so
@@ -395,8 +398,10 @@
}
}
- if (isr & INTR_EXTERNAL_INTF_UDERRUN)
+ if (isr & INTR_EXTERNAL_INTF_UDERRUN) {
+ pr_debug("%s: UNDERRUN -- external\n", __func__);
mdp4_stat.intr_underrun_e++;
+ }
isr &= mask;
@@ -522,7 +527,7 @@
}
#else
else { /* MDDI */
- mdp4_dma_p_done_mddi();
+ mdp4_dma_p_done_mddi(dma);
mdp_pipe_ctrl(MDP_DMA2_BLOCK,
MDP_BLOCK_POWER_OFF, TRUE);
complete(&dma->comp);
diff --git a/drivers/video/msm/mdp_debugfs.c b/drivers/video/msm/mdp_debugfs.c
index 7defd82..4a0ea4c 100644
--- a/drivers/video/msm/mdp_debugfs.c
+++ b/drivers/video/msm/mdp_debugfs.c
@@ -437,38 +437,38 @@
len = snprintf(bp, dlen, "frame_push:\n");
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "rgb1: %08lu\t\t",
+ len = snprintf(bp, dlen, "rgb1: %08lu\t",
mdp4_stat.pipe[OVERLAY_PIPE_RGB1]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "rgb2: %08lu\n",
+ len = snprintf(bp, dlen, "rgb2: %08lu\n",
mdp4_stat.pipe[OVERLAY_PIPE_RGB2]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "vg1: %08lu\t\t",
+ len = snprintf(bp, dlen, "vg1 : %08lu\t",
mdp4_stat.pipe[OVERLAY_PIPE_VG1]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "vg2: %08lu\n",
+ len = snprintf(bp, dlen, "vg2 : %08lu\n",
mdp4_stat.pipe[OVERLAY_PIPE_VG2]);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_mixer: %08lu\t", mdp4_stat.err_mixer);
+ len = snprintf(bp, dlen, "err_mixer : %08lu\t", mdp4_stat.err_mixer);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size);
+ len = snprintf(bp, dlen, "err_size : %08lu\n", mdp4_stat.err_size);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_scale: %08lu\t", mdp4_stat.err_scale);
+ len = snprintf(bp, dlen, "err_scale : %08lu\t", mdp4_stat.err_scale);
bp += len;
dlen -= len;
len = snprintf(bp, dlen, "err_format: %08lu\n", mdp4_stat.err_format);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_play: %08lu\t", mdp4_stat.err_play);
+ len = snprintf(bp, dlen, "err_play : %08lu\t", mdp4_stat.err_play);
bp += len;
dlen -= len;
- len = snprintf(bp, dlen, "err_stage: %08lu\n", mdp4_stat.err_stage);
+ len = snprintf(bp, dlen, "err_stage : %08lu\n", mdp4_stat.err_stage);
bp += len;
dlen -= len;
len = snprintf(bp, dlen, "err_underflow: %08lu\n\n",
diff --git a/drivers/video/msm/mdp_ppp_v20.c b/drivers/video/msm/mdp_ppp_v20.c
index d271b85..418528e 100644
--- a/drivers/video/msm/mdp_ppp_v20.c
+++ b/drivers/video/msm/mdp_ppp_v20.c
@@ -2403,7 +2403,10 @@
uint32 width,
uint32 height, int bpp, MDPIBUF *iBuf, int layer)
{
- *src0 += (x + y * width) * bpp;
+ if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO && layer == 0)
+ *src0 += (x + y * ALIGN(width, 32)) * bpp;
+ else
+ *src0 += (x + y * width) * bpp;
/* if it's dest/bg buffer, we need to adjust it for rotation */
if (layer != 0)
@@ -2414,9 +2417,14 @@
* MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
* we need to shift x direction same as y dir for offsite
*/
- *src1 +=
- ((x / h_slice) * h_slice +
- ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+ if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V2_ADRENO
+ && layer == 0)
+ *src1 += ((x / h_slice) * h_slice + ((y == 0) ? 0 :
+ (((y + 1) / v_slice - 1) * (ALIGN(width/2, 32) * 2))))
+ * bpp;
+ else
+ *src1 += ((x / h_slice) * h_slice +
+ ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
/* if it's dest/bg buffer, we need to adjust it for rotation */
if (layer != 0)
diff --git a/drivers/video/msm/mdss/Kconfig b/drivers/video/msm/mdss/Kconfig
new file mode 100644
index 0000000..30351a3
--- /dev/null
+++ b/drivers/video/msm/mdss/Kconfig
@@ -0,0 +1,5 @@
+config FB_MSM_MDSS_WRITEBACK
+ bool "MDSS Writeback Panel"
+ ---help---
+ The MDSS Writeback Panel provides support for routing the output of
+ MDSS frame buffer driver and MDP processing to memory.
diff --git a/drivers/video/msm/mdss/Makefile b/drivers/video/msm/mdss/Makefile
new file mode 100644
index 0000000..2a61f07
--- /dev/null
+++ b/drivers/video/msm/mdss/Makefile
@@ -0,0 +1,6 @@
+mdss-mdp-objs := mdss_mdp.o mdss_mdp_ctl.o mdss_mdp_pipe.o mdss_mdp_util.o
+mdss-mdp-objs += mdss_mdp_intf_writeback.o
+mdss-mdp-objs += mdss_mdp_overlay.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss-mdp.o
+obj-$(CONFIG_FB_MSM_MDSS) += mdss_fb.o
+obj-$(CONFIG_FB_MSM_MDSS_WRITEBACK) += mdss_wb.o
diff --git a/drivers/video/msm/mdss/mdss.h b/drivers/video/msm/mdss/mdss.h
new file mode 100644
index 0000000..aaf6690
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss.h
@@ -0,0 +1,63 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_H
+#define MDSS_H
+
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#define MDSS_REG_WRITE(addr, val) writel_relaxed(val, mdss_reg_base + addr)
+#define MDSS_REG_READ(addr) readl_relaxed(mdss_reg_base + addr)
+
+extern unsigned char *mdss_reg_base;
+
+struct mdss_res_type {
+ u32 rev;
+ u32 mdp_rev;
+ struct clk *mdp_clk;
+ struct clk *mdp_pclk;
+ struct clk *mdp_lut_clk;
+ struct clk *vsync_clk;
+ struct regulator *fs;
+
+ struct workqueue_struct *clk_ctrl_wq;
+ struct delayed_work clk_ctrl_worker;
+
+ u32 irq;
+ u32 irq_mask;
+ u32 irq_ena;
+ u32 irq_buzy;
+
+ u32 clk_ena;
+ u32 suspend;
+ u32 timeout;
+
+ u32 fs_ena;
+ u32 vsync_ena;
+
+ u32 intf;
+ u32 eintf_ena;
+ u32 prim_ptype;
+ u32 res_init;
+ u32 pdev_lcnt;
+ u32 bus_hdl;
+
+ u32 smp_mb_cnt;
+ u32 smp_mb_size;
+ u32 *pipe_type_map;
+ u32 *mixer_type_map;
+};
+extern struct mdss_res_type *mdss_res;
+#endif /* MDSS_H */
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
new file mode 100644
index 0000000..0fedb6c
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -0,0 +1,1231 @@
+/*
+ * Core MDSS framebuffer driver.
+ *
+ * Copyright (C) 2007 Google Incorporated
+ * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/android_pmem.h>
+#include <linux/bootmem.h>
+#include <linux/console.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/leds.h>
+#include <linux/memory.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/msm_mdp.h>
+#include <linux/proc_fs.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+
+#include <mach/board.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
+#define MDSS_FB_NUM 3
+#else
+#define MDSS_FB_NUM 2
+#endif
+
+#define MAX_FBI_LIST 32
+static struct fb_info *fbi_list[MAX_FBI_LIST];
+static int fbi_list_index;
+
+static u32 mdss_fb_pseudo_palette[16] = {
+ 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd);
+static int mdss_fb_open(struct fb_info *info, int user);
+static int mdss_fb_release(struct fb_info *info, int user);
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int mdss_fb_set_par(struct fb_info *info);
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+ int op_enable);
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd);
+static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+
+#define MAX_BACKLIGHT_BRIGHTNESS 255
+static int lcd_backlight_registered;
+
+static void mdss_fb_set_bl_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
+ int bl_lvl;
+
+ if (value > MAX_BACKLIGHT_BRIGHTNESS)
+ value = MAX_BACKLIGHT_BRIGHTNESS;
+
+ /* This maps android backlight level 0 to 255 into
+ driver backlight level 0 to bl_max with rounding */
+ bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
+ /(2 * MAX_BACKLIGHT_BRIGHTNESS);
+
+ if (!bl_lvl && value)
+ bl_lvl = 1;
+
+ mdss_fb_set_backlight(mfd, bl_lvl);
+}
+
+static struct led_classdev backlight_led = {
+ .name = "lcd-backlight",
+ .brightness = MAX_BACKLIGHT_BRIGHTNESS,
+ .brightness_set = mdss_fb_set_bl_brightness,
+};
+
+static ssize_t mdss_fb_get_type(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+
+ switch (mfd->panel_info.type) {
+ case NO_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "no panel\n");
+ break;
+ case HDMI_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "hdmi panel\n");
+ break;
+ case LVDS_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "lvds panel\n");
+ break;
+ case DTV_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "dtv panel\n");
+ break;
+ case MIPI_VIDEO_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "mipi dsi video panel\n");
+ break;
+ case MIPI_CMD_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "mipi dsi cmd panel\n");
+ break;
+ case WRITEBACK_PANEL:
+ ret = snprintf(buf, PAGE_SIZE, "writeback panel\n");
+ break;
+ default:
+ ret = snprintf(buf, PAGE_SIZE, "unknown panel\n");
+ break;
+ }
+
+ return ret;
+}
+
+static DEVICE_ATTR(mdss_fb_type, S_IRUGO, mdss_fb_get_type, NULL);
+static struct attribute *mdss_fb_attrs[] = {
+ &dev_attr_mdss_fb_type.attr,
+ NULL,
+};
+
+static struct attribute_group mdss_fb_attr_group = {
+ .attrs = mdss_fb_attrs,
+};
+
+static int mdss_fb_create_sysfs(struct msm_fb_data_type *mfd)
+{
+ int rc;
+
+ rc = sysfs_create_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
+ if (rc)
+ pr_err("sysfs group creation failed, rc=%d\n", rc);
+ return rc;
+}
+
+static void mdss_fb_remove_sysfs(struct msm_fb_data_type *mfd)
+{
+ sysfs_remove_group(&mfd->fbi->dev->kobj, &mdss_fb_attr_group);
+}
+
+static int mdss_fb_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd = NULL;
+ struct mdss_panel_data *pdata;
+ struct fb_info *fbi;
+ int rc;
+
+ if (fbi_list_index >= MAX_FBI_LIST)
+ return -ENOMEM;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata)
+ return -ENODEV;
+
+ /*
+ * alloc framebuffer info + par data
+ */
+ fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), &pdev->dev);
+ if (fbi == NULL) {
+ pr_err("can't allocate framebuffer info data!\n");
+ return -ENOMEM;
+ }
+
+ mfd = (struct msm_fb_data_type *)fbi->par;
+ mfd->key = MFD_KEY;
+ mfd->fbi = fbi;
+ mfd->panel_info = pdata->panel_info;
+ mfd->panel.type = pdata->panel_info.type;
+ mfd->panel.id = mfd->index;
+ mfd->fb_page = MDSS_FB_NUM;
+ mfd->index = fbi_list_index;
+ mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
+ mfd->panel_info.frame_count = 0;
+ mfd->bl_level = 0;
+ mfd->fb_imgType = MDP_RGBA_8888;
+ mfd->iclient = msm_ion_client_create(-1, pdev->name);
+ if (IS_ERR(mfd->iclient))
+ mfd->iclient = NULL;
+
+ mfd->pdev = pdev;
+
+ mutex_init(&mfd->lock);
+
+ fbi_list[fbi_list_index++] = fbi;
+
+ platform_set_drvdata(pdev, mfd);
+
+ rc = mdss_fb_register(mfd);
+ if (rc)
+ return rc;
+
+ rc = pm_runtime_set_active(mfd->fbi->dev);
+ if (rc < 0)
+ pr_err("pm_runtime: fail to set active.\n");
+ pm_runtime_enable(mfd->fbi->dev);
+
+ /* android supports only one lcd-backlight/lcd for now */
+ if (!lcd_backlight_registered) {
+ if (led_classdev_register(&pdev->dev, &backlight_led))
+ pr_err("led_classdev_register failed\n");
+ else
+ lcd_backlight_registered = 1;
+ }
+
+ mdss_fb_create_sysfs(mfd);
+
+ return 0;
+}
+
+static int mdss_fb_remove(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ mdss_fb_remove_sysfs(mfd);
+
+ pm_runtime_disable(mfd->fbi->dev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (mdss_fb_suspend_sub(mfd))
+ pr_err("msm_fb_remove: can't stop the device %d\n",
+ mfd->index);
+
+ /* remove /dev/fb* */
+ unregister_framebuffer(mfd->fbi);
+
+ if (lcd_backlight_registered) {
+ lcd_backlight_registered = 0;
+ led_classdev_unregister(&backlight_led);
+ }
+
+ return 0;
+}
+
+static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ /*
+ * suspend this channel
+ */
+ mfd->suspend.op_enable = mfd->op_enable;
+ mfd->suspend.panel_power_on = mfd->panel_power_on;
+
+ if (mfd->op_enable) {
+ ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+ mfd->suspend.op_enable);
+ if (ret) {
+ pr_warn("can't turn off display!\n");
+ return ret;
+ }
+ mfd->op_enable = false;
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_PM)
+static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ /* resume state var recover */
+ mfd->op_enable = mfd->suspend.op_enable;
+
+ if (mfd->suspend.panel_power_on) {
+ ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+ mfd->op_enable);
+ if (ret)
+ pr_warn("can't turn on display!\n");
+ }
+
+ return ret;
+}
+
+static int mdss_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct msm_fb_data_type *mfd;
+ int ret = 0;
+
+ pr_debug("mdss_fb_suspend\n");
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ console_lock();
+ fb_set_suspend(mfd->fbi, FBINFO_STATE_SUSPENDED);
+
+ ret = mdss_fb_suspend_sub(mfd);
+ if (ret != 0) {
+ pr_err("failed to suspend! %d\n", ret);
+ fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
+ } else {
+ pdev->dev.power.power_state = state;
+ }
+
+ console_unlock();
+ return ret;
+}
+
+static int mdss_fb_resume(struct platform_device *pdev)
+{
+ /* This resume function is called when interrupt is enabled.
+ */
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+
+ pr_debug("mdss_fb_resume\n");
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ console_lock();
+ ret = mdss_fb_resume_sub(mfd);
+ pdev->dev.power.power_state = PMSG_ON;
+ fb_set_suspend(mfd->fbi, FBINFO_STATE_RUNNING);
+ console_unlock();
+
+ return ret;
+}
+#else
+#define mdss_fb_suspend NULL
+#define mdss_fb_resume NULL
+#endif
+
+#if defined(CONFIG_PM) && defined(CONFIG_SUSPEND)
+static int mdss_fb_ext_suspend(struct device *dev)
+{
+ struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ if (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)
+ ret = mdss_fb_suspend_sub(mfd);
+
+ return ret;
+}
+
+static int mdss_fb_ext_resume(struct device *dev)
+{
+ struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ if (mfd->panel_info.type == HDMI_PANEL ||
+ mfd->panel_info.type == DTV_PANEL)
+ ret = mdss_fb_resume_sub(mfd);
+
+ return ret;
+}
+#else
+#define mdss_fb_ext_suspend NULL
+#define mdss_fb_ext_resume NULL
+#endif
+
+static const struct dev_pm_ops mdss_fb_dev_pm_ops = {
+ .suspend = mdss_fb_ext_suspend,
+ .resume = mdss_fb_ext_resume,
+};
+
+static struct platform_driver mdss_fb_driver = {
+ .probe = mdss_fb_probe,
+ .remove = mdss_fb_remove,
+ .suspend = mdss_fb_suspend,
+ .resume = mdss_fb_resume,
+ .shutdown = NULL,
+ .driver = {
+ .name = "mdss_fb",
+ .pm = &mdss_fb_dev_pm_ops,
+ },
+};
+
+static int unset_bl_level, bl_updated;
+static int bl_level_old;
+
+void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl)
+{
+ struct mdss_panel_data *pdata;
+
+ if (!mfd->panel_power_on || !bl_updated) {
+ unset_bl_level = bkl_lvl;
+ return;
+ } else {
+ unset_bl_level = 0;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ if ((pdata) && (pdata->set_backlight)) {
+ mutex_lock(&mfd->lock);
+ if (bl_level_old == bkl_lvl) {
+ mutex_unlock(&mfd->lock);
+ return;
+ }
+ mfd->bl_level = bkl_lvl;
+ pdata->set_backlight(mfd->bl_level);
+ bl_level_old = mfd->bl_level;
+ mutex_unlock(&mfd->lock);
+ }
+}
+
+void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
+{
+ struct mdss_panel_data *pdata;
+
+ if (unset_bl_level && !bl_updated) {
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+ if ((pdata) && (pdata->set_backlight)) {
+ mutex_lock(&mfd->lock);
+ mfd->bl_level = unset_bl_level;
+ pdata->set_backlight(mfd->bl_level);
+ bl_level_old = unset_bl_level;
+ mutex_unlock(&mfd->lock);
+ bl_updated = 1;
+ }
+ }
+}
+
+static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
+ int op_enable)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int ret = 0;
+
+ if (!op_enable)
+ return -EPERM;
+
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ if (!mfd->panel_power_on) {
+ msleep(20);
+ ret = mfd->on_fnc(mfd);
+ if (ret == 0)
+ mfd->panel_power_on = true;
+ }
+ break;
+
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_POWERDOWN:
+ default:
+ if (mfd->panel_power_on) {
+ int curr_pwr_state;
+
+ mfd->op_enable = false;
+ curr_pwr_state = mfd->panel_power_on;
+ mfd->panel_power_on = false;
+ bl_updated = 0;
+
+ msleep(20);
+ ret = mfd->off_fnc(mfd);
+ if (ret)
+ mfd->panel_power_on = curr_pwr_state;
+
+ mfd->op_enable = true;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int mdss_fb_blank(int blank_mode, struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
+}
+
+/*
+ * Custom Framebuffer mmap() function for MSM driver.
+ * Differs from standard mmap() function by allowing for customized
+ * page-protection.
+ */
+static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ /* Get frame buffer memory range. */
+ unsigned long start = info->fix.smem_start;
+ u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if (off >= len) {
+ /* memory mapped io */
+ off -= len;
+ if (info->var.accel_flags) {
+ mutex_unlock(&info->lock);
+ return -EINVAL;
+ }
+ start = info->fix.mmio_start;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+ }
+
+ /* Set VM flags. */
+ start &= PAGE_MASK;
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ /* This is an IO map - tell maydump to skip this VMA */
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ /* Set VM page protection */
+ if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
+ vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
+ vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
+ vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* Remap the frame buffer I/O range */
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static struct fb_ops mdss_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = mdss_fb_open,
+ .fb_release = mdss_fb_release,
+ .fb_check_var = mdss_fb_check_var, /* vinfo check */
+ .fb_set_par = mdss_fb_set_par, /* set the video mode */
+ .fb_blank = mdss_fb_blank, /* blank display */
+ .fb_pan_display = mdss_fb_pan_display, /* pan display */
+ .fb_ioctl = mdss_fb_ioctl, /* perform fb specific ioctl */
+ .fb_mmap = mdss_fb_mmap,
+};
+
+static u32 mdss_fb_line_length(u32 fb_index, u32 xres, int bpp)
+{
+ /* The adreno GPU hardware requires that the pitch be aligned to
+ 32 pixels for color buffers, so for the cases where the GPU
+ is writing directly to fb0, the framebuffer pitch
+ also needs to be 32 pixel aligned */
+
+ if (fb_index == 0)
+ return ALIGN(xres, 32) * bpp;
+ else
+ return xres * bpp;
+}
+
+static int mdss_fb_alloc_fbmem(struct msm_fb_data_type *mfd)
+{
+ void *virt = NULL;
+ unsigned long phys = 0;
+ size_t size;
+
+ size = PAGE_ALIGN(mfd->fbi->fix.line_length * mfd->panel_info.yres);
+ size *= mfd->fb_page;
+
+ if (mfd->index == 0) {
+ virt = dma_alloc_coherent(NULL, size, (dma_addr_t *) &phys,
+ GFP_KERNEL);
+ if (!virt) {
+ pr_err("unable to alloc fb memory size=%u\n", size);
+ return -ENOMEM;
+ }
+
+ pr_info("allocating %u bytes at %p (%lx phys) for fb %d\n",
+ size, virt, phys, mfd->index);
+ } else {
+ pr_debug("no memory allocated for fb%d\n", mfd->index);
+ size = 0;
+ }
+
+ mfd->fbi->screen_base = virt;
+ mfd->fbi->fix.smem_start = phys;
+ mfd->fbi->fix.smem_len = size;
+
+ return 0;
+}
+
+static int mdss_fb_register(struct msm_fb_data_type *mfd)
+{
+ int ret = -ENODEV;
+ int bpp;
+ struct mdss_panel_info *panel_info = &mfd->panel_info;
+ struct fb_info *fbi = mfd->fbi;
+ struct fb_fix_screeninfo *fix;
+ struct fb_var_screeninfo *var;
+ int *id;
+
+ /*
+ * fb info initialization
+ */
+ fix = &fbi->fix;
+ var = &fbi->var;
+
+ fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */
+ fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */
+ fix->ywrapstep = 0; /* No support */
+ fix->mmio_start = 0; /* No MMIO Address */
+ fix->mmio_len = 0; /* No MMIO Address */
+ fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
+
+ var->xoffset = 0, /* Offset from virtual to visible */
+ var->yoffset = 0, /* resolution */
+ var->grayscale = 0, /* No graylevels */
+ var->nonstd = 0, /* standard pixel format */
+ var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */
+ var->height = -1, /* height of picture in mm */
+ var->width = -1, /* width of picture in mm */
+ var->accel_flags = 0, /* acceleration flags */
+ var->sync = 0, /* see FB_SYNC_* */
+ var->rotate = 0, /* angle we rotate counter clockwise */
+ mfd->op_enable = false;
+
+ switch (mfd->fb_imgType) {
+ case MDP_RGB_565:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->blue.offset = 0;
+ var->green.offset = 5;
+ var->red.offset = 11;
+ var->blue.length = 5;
+ var->green.length = 6;
+ var->red.length = 5;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ bpp = 2;
+ break;
+
+ case MDP_RGB_888:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->blue.offset = 0;
+ var->green.offset = 8;
+ var->red.offset = 16;
+ var->blue.length = 8;
+ var->green.length = 8;
+ var->red.length = 8;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ bpp = 3;
+ break;
+
+ case MDP_ARGB_8888:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->blue.offset = 0;
+ var->green.offset = 8;
+ var->red.offset = 16;
+ var->blue.length = 8;
+ var->green.length = 8;
+ var->red.length = 8;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ bpp = 4;
+ break;
+
+ case MDP_RGBA_8888:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->blue.offset = 8;
+ var->green.offset = 16;
+ var->red.offset = 24;
+ var->blue.length = 8;
+ var->green.length = 8;
+ var->red.length = 8;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 8;
+ bpp = 4;
+ break;
+
+ case MDP_YCRYCB_H2V1:
+ fix->type = FB_TYPE_INTERLEAVED_PLANES;
+ fix->xpanstep = 2;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ /* how about R/G/B offset? */
+ var->blue.offset = 0;
+ var->green.offset = 5;
+ var->red.offset = 11;
+ var->blue.length = 5;
+ var->green.length = 6;
+ var->red.length = 5;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ bpp = 2;
+ break;
+
+ default:
+ pr_err("msm_fb_init: fb %d unkown image type!\n",
+ mfd->index);
+ return ret;
+ }
+
+ fix->type = panel_info->is_3d_panel;
+ fix->line_length = mdss_fb_line_length(mfd->index, panel_info->xres,
+ bpp);
+ mfd->var_xres = panel_info->xres;
+ mfd->var_yres = panel_info->yres;
+
+ var->pixclock = mfd->panel_info.clk_rate;
+ mfd->var_pixclock = var->pixclock;
+
+ var->xres = panel_info->xres;
+ var->yres = panel_info->yres;
+ var->xres_virtual = panel_info->xres;
+ var->yres_virtual = panel_info->yres * mfd->fb_page;
+ var->bits_per_pixel = bpp * 8; /* FrameBuffer color depth */
+
+ /* id field for fb app */
+
+ id = (int *)&mfd->panel;
+
+ snprintf(fix->id, sizeof(fix->id), "mdssfb_%x", (u32) *id);
+
+ fbi->fbops = &mdss_fb_ops;
+ fbi->flags = FBINFO_FLAG_DEFAULT;
+ fbi->pseudo_palette = mdss_fb_pseudo_palette;
+
+ mfd->ref_cnt = 0;
+ mfd->panel_power_on = false;
+
+ if (mdss_fb_alloc_fbmem(mfd)) {
+ pr_err("unable to allocate framebuffer memory\n");
+ return -ENOMEM;
+ }
+
+ mfd->op_enable = true;
+
+ /* cursor memory allocation */
+ if (mfd->cursor_update) {
+ mfd->cursor_buf = dma_alloc_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+ (dma_addr_t *) &mfd->cursor_buf_phys,
+ GFP_KERNEL);
+ if (!mfd->cursor_buf)
+ mfd->cursor_update = 0;
+ }
+
+ if (mfd->lut_update) {
+ ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+ if (ret)
+ pr_err("fb_alloc_cmap() failed!\n");
+ }
+
+ if (register_framebuffer(fbi) < 0) {
+ if (mfd->lut_update)
+ fb_dealloc_cmap(&fbi->cmap);
+
+ if (mfd->cursor_buf)
+ dma_free_coherent(NULL, MDSS_MDP_CURSOR_SIZE,
+ mfd->cursor_buf,
+ (dma_addr_t) mfd->cursor_buf_phys);
+
+ mfd->op_enable = false;
+ return -EPERM;
+ }
+
+ pr_info("FrameBuffer[%d] %dx%d size=%d registered successfully!\n",
+ mfd->index, fbi->var.xres, fbi->var.yres,
+ fbi->fix.smem_len);
+
+ ret = 0;
+
+ return ret;
+}
+
+static int mdss_fb_open(struct fb_info *info, int user)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int result;
+
+ result = pm_runtime_get_sync(info->dev);
+
+ if (result < 0)
+ pr_err("pm_runtime: fail to wake up\n");
+
+
+ if (!mfd->ref_cnt) {
+ result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
+ mfd->op_enable);
+ if (result) {
+ pr_err("mdss_fb_open: can't turn on display!\n");
+ return result;
+ }
+ }
+
+ mfd->ref_cnt++;
+ return 0;
+}
+
+static int mdss_fb_release(struct fb_info *info, int user)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int ret = 0;
+
+ if (!mfd->ref_cnt) {
+ pr_info("try to close unopened fb %d!\n", mfd->index);
+ return -EINVAL;
+ }
+
+ mfd->ref_cnt--;
+
+ if (!mfd->ref_cnt) {
+ ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
+ mfd->op_enable);
+ if (ret) {
+ pr_err("can't turn off display!\n");
+ return ret;
+ }
+ }
+
+ pm_runtime_put(info->dev);
+ return ret;
+}
+
+static int mdss_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if ((!mfd->op_enable) || (!mfd->panel_power_on))
+ return -EPERM;
+
+ if (var->xoffset > (info->var.xres_virtual - info->var.xres))
+ return -EINVAL;
+
+ if (var->yoffset > (info->var.yres_virtual - info->var.yres))
+ return -EINVAL;
+
+ if (info->fix.xpanstep)
+ info->var.xoffset =
+ (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+ if (info->fix.ypanstep)
+ info->var.yoffset =
+ (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+ if (mfd->dma_fnc)
+ mfd->dma_fnc(mfd);
+ else
+ pr_warn("dma function not set for panel type=%d\n",
+ mfd->panel.type);
+
+ mdss_fb_update_backlight(mfd);
+
+ ++mfd->panel_info.frame_count;
+ return 0;
+}
+
+static int mdss_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ u32 len;
+
+ if (var->rotate != FB_ROTATE_UR)
+ return -EINVAL;
+ if (var->grayscale != info->var.grayscale)
+ return -EINVAL;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ if ((var->green.offset != 5) ||
+ !((var->blue.offset == 11)
+ || (var->blue.offset == 0)) ||
+ !((var->red.offset == 11)
+ || (var->red.offset == 0)) ||
+ (var->blue.length != 5) ||
+ (var->green.length != 6) ||
+ (var->red.length != 5) ||
+ (var->blue.msb_right != 0) ||
+ (var->green.msb_right != 0) ||
+ (var->red.msb_right != 0) ||
+ (var->transp.offset != 0) ||
+ (var->transp.length != 0))
+ return -EINVAL;
+ break;
+
+ case 24:
+ if ((var->blue.offset != 0) ||
+ (var->green.offset != 8) ||
+ (var->red.offset != 16) ||
+ (var->blue.length != 8) ||
+ (var->green.length != 8) ||
+ (var->red.length != 8) ||
+ (var->blue.msb_right != 0) ||
+ (var->green.msb_right != 0) ||
+ (var->red.msb_right != 0) ||
+ !(((var->transp.offset == 0) &&
+ (var->transp.length == 0)) ||
+ ((var->transp.offset == 24) &&
+ (var->transp.length == 8))))
+ return -EINVAL;
+ break;
+
+ case 32:
+ /* Figure out if the user meant RGBA or ARGB
+ and verify the position of the RGB components */
+
+ if (var->transp.offset == 24) {
+ if ((var->blue.offset != 0) ||
+ (var->green.offset != 8) ||
+ (var->red.offset != 16))
+ return -EINVAL;
+ } else if (var->transp.offset == 0) {
+ if ((var->blue.offset != 8) ||
+ (var->green.offset != 16) ||
+ (var->red.offset != 24))
+ return -EINVAL;
+ } else
+ return -EINVAL;
+
+ /* Check the common values for both RGBA and ARGB */
+
+ if ((var->blue.length != 8) ||
+ (var->green.length != 8) ||
+ (var->red.length != 8) ||
+ (var->transp.length != 8) ||
+ (var->blue.msb_right != 0) ||
+ (var->green.msb_right != 0) ||
+ (var->red.msb_right != 0))
+ return -EINVAL;
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
+ return -EINVAL;
+
+ len = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
+ if (len > info->fix.smem_len)
+ return -EINVAL;
+
+ if ((var->xres == 0) || (var->yres == 0))
+ return -EINVAL;
+
+ if ((var->xres > mfd->panel_info.xres) ||
+ (var->yres > mfd->panel_info.yres))
+ return -EINVAL;
+
+ if (var->xoffset > (var->xres_virtual - var->xres))
+ return -EINVAL;
+
+ if (var->yoffset > (var->yres_virtual - var->yres))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mdss_fb_set_par(struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct fb_var_screeninfo *var = &info->var;
+ int old_imgType;
+ int blank = 0;
+
+ old_imgType = mfd->fb_imgType;
+ switch (var->bits_per_pixel) {
+ case 16:
+ if (var->red.offset == 0)
+ mfd->fb_imgType = MDP_BGR_565;
+ else
+ mfd->fb_imgType = MDP_RGB_565;
+ break;
+
+ case 24:
+ if ((var->transp.offset == 0) && (var->transp.length == 0))
+ mfd->fb_imgType = MDP_RGB_888;
+ else if ((var->transp.offset == 24) &&
+ (var->transp.length == 8)) {
+ mfd->fb_imgType = MDP_ARGB_8888;
+ info->var.bits_per_pixel = 32;
+ }
+ break;
+
+ case 32:
+ if (var->transp.offset == 24)
+ mfd->fb_imgType = MDP_ARGB_8888;
+ else
+ mfd->fb_imgType = MDP_RGBA_8888;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((mfd->var_pixclock != var->pixclock) ||
+ (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
+ (mfd->var_pixclock != var->pixclock) ||
+ (mfd->var_xres != var->xres) ||
+ (mfd->var_yres != var->yres)))) {
+ mfd->var_xres = var->xres;
+ mfd->var_yres = var->yres;
+ mfd->var_pixclock = var->pixclock;
+ blank = 1;
+ }
+ mfd->fbi->fix.line_length = mdss_fb_line_length(mfd->index, var->xres,
+ var->bits_per_pixel / 8);
+
+ if (blank) {
+ mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
+ mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
+ }
+
+ return 0;
+}
+
+static int mdss_fb_cursor(struct fb_info *info, void __user *p)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct fb_cursor cursor;
+ int ret;
+
+ if (!mfd->cursor_update)
+ return -ENODEV;
+
+ ret = copy_from_user(&cursor, p, sizeof(cursor));
+ if (ret)
+ return ret;
+
+ return mfd->cursor_update(info, &cursor);
+}
+
+static int mdss_fb_set_lut(struct fb_info *info, void __user *p)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct fb_cmap cmap;
+ int ret;
+
+ if (!mfd->lut_update)
+ return -ENODEV;
+
+ ret = copy_from_user(&cmap, p, sizeof(cmap));
+ if (ret)
+ return ret;
+
+ mfd->lut_update(info, &cmap);
+ return 0;
+}
+
+static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ void __user *argp = (void __user *)arg;
+ struct mdp_page_protection fb_page_protection;
+ int ret = -ENOSYS;
+
+ switch (cmd) {
+ case MSMFB_CURSOR:
+ ret = mdss_fb_cursor(info, argp);
+ break;
+
+ case MSMFB_SET_LUT:
+ ret = mdss_fb_set_lut(info, argp);
+ break;
+
+ case MSMFB_GET_PAGE_PROTECTION:
+ fb_page_protection.page_protection =
+ mfd->mdp_fb_page_protection;
+ ret = copy_to_user(argp, &fb_page_protection,
+ sizeof(fb_page_protection));
+ if (ret)
+ return ret;
+ break;
+
+ default:
+ if (mfd->ioctl_handler)
+ ret = mfd->ioctl_handler(mfd, cmd, argp);
+ break;
+ }
+
+ if (ret == -ENOSYS)
+ pr_err("unsupported ioctl (%x)\n", cmd);
+
+ return ret;
+}
+
+int mdss_register_panel(struct mdss_panel_data *pdata)
+{
+ struct platform_device *mdss_fb_dev = NULL;
+ struct msm_fb_data_type *mfd;
+ int rc;
+
+ if (!mdss_res) {
+ pr_err("mdss mdp resources not initialized yet\n");
+ return -ENODEV;
+ }
+
+ mdss_fb_dev = platform_device_alloc("mdss_fb", pdata->panel_info.pdest);
+ if (!mdss_fb_dev) {
+ pr_err("unable to allocate mdss_fb device\n");
+ return -ENOMEM;
+ }
+
+ mdss_fb_dev->dev.platform_data = pdata;
+
+ rc = platform_device_add(mdss_fb_dev);
+ if (rc) {
+ platform_device_put(mdss_fb_dev);
+ pr_err("unable to probe mdss_fb device (%d)\n", rc);
+ return rc;
+ }
+
+ mfd = platform_get_drvdata(mdss_fb_dev);
+ if (!mfd)
+ return -ENODEV;
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ mfd->on_fnc = mdss_mdp_ctl_on;
+ mfd->off_fnc = mdss_mdp_ctl_off;
+
+ rc = mdss_mdp_overlay_init(mfd);
+ if (rc)
+ pr_err("unable to init overlay\n");
+
+ return rc;
+}
+EXPORT_SYMBOL(mdss_register_panel);
+
+int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num)
+{
+ struct fb_info *info;
+
+ if (fb_num > MAX_FBI_LIST)
+ return -EINVAL;
+
+ info = fbi_list[fb_num];
+ if (!info)
+ return -ENOENT;
+
+ *start = info->fix.smem_start;
+ *len = info->fix.smem_len;
+ return 0;
+}
+EXPORT_SYMBOL(mdss_fb_get_phys_info);
+
+int __init mdss_fb_init(void)
+{
+ int rc = -ENODEV;
+
+ if (platform_driver_register(&mdss_fb_driver))
+ return rc;
+
+ return 0;
+}
+
+module_init(mdss_fb_init);
diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
new file mode 100644
index 0000000..a3f0dbe
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -0,0 +1,98 @@
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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 MDSS_FB_H
+#define MDSS_FB_H
+
+#include <linux/ion.h>
+#include <linux/list.h>
+#include <linux/msm_mdp.h>
+#include <linux/types.h>
+
+#include "mdss_mdp.h"
+#include "mdss_panel.h"
+
+#define MSM_FB_DEFAULT_PAGE_SIZE 2
+#define MFD_KEY 0x11161126
+#define MSM_FB_MAX_DEV_LIST 32
+
+#define MSM_FB_ENABLE_DBGFS
+
+#ifndef MAX
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+struct disp_info_type_suspend {
+ int op_enable;
+ int panel_power_on;
+};
+
+struct msm_fb_data_type {
+ u32 key;
+ u32 index;
+ u32 ref_cnt;
+ u32 fb_page;
+
+ struct panel_id panel;
+ struct mdss_panel_info panel_info;
+
+ u32 dest;
+ struct fb_info *fbi;
+
+ int op_enable;
+ u32 fb_imgType;
+
+ int hw_refresh;
+
+ int overlay_play_enable;
+
+ int panel_power_on;
+ struct disp_info_type_suspend suspend;
+
+ int (*on_fnc) (struct msm_fb_data_type *mfd);
+ int (*off_fnc) (struct msm_fb_data_type *mfd);
+ int (*kickoff_fnc) (struct mdss_mdp_ctl *ctl);
+ int (*ioctl_handler) (struct msm_fb_data_type *mfd, u32 cmd, void *arg);
+ void (*dma_fnc) (struct msm_fb_data_type *mfd);
+ int (*cursor_update) (struct fb_info *info,
+ struct fb_cursor *cursor);
+ int (*lut_update) (struct fb_info *info,
+ struct fb_cmap *cmap);
+ int (*do_histogram) (struct fb_info *info,
+ struct mdp_histogram *hist);
+ void *cursor_buf;
+ void *cursor_buf_phys;
+
+ u32 bl_level;
+ struct mutex lock;
+
+ struct platform_device *pdev;
+
+ u32 var_xres;
+ u32 var_yres;
+ u32 var_pixclock;
+
+ u32 mdp_fb_page_protection;
+ struct ion_client *iclient;
+
+ struct mdss_mdp_ctl *ctl;
+};
+
+int mdss_fb_get_phys_info(unsigned long *start, unsigned long *len, int fb_num);
+void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl);
+void mdss_fb_update_backlight(struct msm_fb_data_type *mfd);
+#endif /* MDSS_FB_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp.c b/drivers/video/msm/mdss/mdss_mdp.c
new file mode 100644
index 0000000..d1847c3
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp.c
@@ -0,0 +1,494 @@
+/*
+ * MDSS MDP Interface (used by framebuffer core)
+ *
+ * Copyright (c) 2007-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (C) 2007 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/hrtimer.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/memory_alloc.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/spinlock.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+
+#include <mach/board.h>
+#include <mach/clk.h>
+#include <mach/hardware.h>
+
+#include "mdss.h"
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+/* 1.15 mdp clk factor */
+#define MDP_CLK_FACTOR(rate) (((rate) * 23) / 20)
+
+unsigned char *mdss_reg_base;
+
+struct mdss_res_type *mdss_res;
+static struct msm_panel_common_pdata *mdp_pdata;
+
+static DEFINE_SPINLOCK(mdp_lock);
+static DEFINE_MUTEX(mdp_clk_lock);
+static DEFINE_MUTEX(mdp_suspend_mutex);
+
+u32 mdss_mdp_pipe_type_map[MDSS_MDP_MAX_SSPP] = {
+ MDSS_MDP_PIPE_TYPE_VIG,
+ MDSS_MDP_PIPE_TYPE_VIG,
+ MDSS_MDP_PIPE_TYPE_VIG,
+ MDSS_MDP_PIPE_TYPE_RGB,
+ MDSS_MDP_PIPE_TYPE_RGB,
+ MDSS_MDP_PIPE_TYPE_RGB,
+ MDSS_MDP_PIPE_TYPE_DMA,
+ MDSS_MDP_PIPE_TYPE_DMA,
+};
+
+u32 mdss_mdp_mixer_type_map[MDSS_MDP_MAX_LAYERMIXER] = {
+ MDSS_MDP_MIXER_TYPE_INTF,
+ MDSS_MDP_MIXER_TYPE_INTF,
+ MDSS_MDP_MIXER_TYPE_INTF,
+ MDSS_MDP_MIXER_TYPE_WRITEBACK,
+ MDSS_MDP_MIXER_TYPE_WRITEBACK,
+};
+
+irqreturn_t mdss_irq_handler(int mdss_irq, void *ptr)
+{
+ u32 intr = MDSS_MDP_REG_READ(MDSS_REG_HW_INTR_STATUS);
+
+ mdss_res->irq_buzy = true;
+
+ if (intr & MDSS_INTR_MDP)
+ mdss_mdp_isr(mdss_irq, ptr);
+
+ mdss_res->irq_buzy = false;
+
+ return IRQ_HANDLED;
+}
+
+int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num)
+{
+ u32 irq;
+ unsigned long irq_flags;
+ int ret = 0;
+
+ if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+ intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+ intf_num = intf_num << 1;
+
+ irq = BIT(intr_type + intf_num);
+
+ spin_lock_irqsave(&mdp_lock, irq_flags);
+ if (mdss_res->irq_mask & irq) {
+ pr_warn("MDSS IRQ-0x%x is already set, mask=%x irq=%d\n",
+ irq, mdss_res->irq_mask, mdss_res->irq_ena);
+ ret = -EBUSY;
+ } else {
+ mdss_res->irq_mask |= irq;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, irq);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+ if (!mdss_res->irq_ena) {
+ mdss_res->irq_ena = true;
+ enable_irq(mdss_res->irq);
+ }
+ }
+ spin_unlock_irqrestore(&mdp_lock, irq_flags);
+
+ return ret;
+}
+
+void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num)
+{
+ u32 irq;
+ unsigned long irq_flags;
+
+
+ if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+ intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+ intf_num = intf_num << 1;
+
+ irq = BIT(intr_type + intf_num);
+
+ spin_lock_irqsave(&mdp_lock, irq_flags);
+ if (!(mdss_res->irq_mask & irq)) {
+ pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
+ irq, mdss_res->irq_mask, mdss_res->irq_ena);
+ } else {
+ mdss_res->irq_mask &= ~irq;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+ if (!mdss_res->irq_mask) {
+ mdss_res->irq_ena = false;
+ disable_irq(mdss_res->irq);
+ }
+ }
+ spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num)
+{
+ u32 irq;
+
+ if (intr_type == MDSS_MDP_IRQ_INTF_UNDER_RUN ||
+ intr_type == MDSS_MDP_IRQ_INTF_VSYNC)
+ intf_num = intf_num << 1;
+
+ irq = BIT(intr_type + intf_num);
+
+ spin_lock(&mdp_lock);
+ if (!(mdss_res->irq_mask & irq)) {
+ pr_warn("MDSS IRQ-%x is NOT set, mask=%x irq=%d\n",
+ irq, mdss_res->irq_mask, mdss_res->irq_ena);
+ } else {
+ mdss_res->irq_mask &= ~irq;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_EN, mdss_res->irq_mask);
+ if (!mdss_res->irq_mask) {
+ mdss_res->irq_ena = false;
+ disable_irq_nosync(mdss_res->irq);
+ }
+ }
+ spin_unlock(&mdp_lock);
+}
+
+static void mdss_mdp_clk_ctrl_update(int enable)
+{
+ if (mdss_res->clk_ena == enable)
+ return;
+
+ pr_debug("MDP CLKS %s\n", (enable ? "Enable" : "Disable"));
+ mdss_res->clk_ena = enable;
+}
+
+void mdss_mdp_clk_ctrl(int enable, int isr)
+{
+ static atomic_t clk_ref = ATOMIC_INIT(0);
+ static DEFINE_MUTEX(clk_ctrl_lock);
+ int force_off = 0;
+
+ pr_debug("clk enable=%d isr=%d clk_ref=%d\n", enable, isr,
+ atomic_read(&clk_ref));
+ /*
+ * It is assumed that if isr = TRUE then start = OFF
+ * if start = ON when isr = TRUE it could happen that the usercontext
+ * could turn off the clocks while the interrupt is updating the
+ * power to ON
+ */
+ WARN_ON(isr == true && enable);
+
+ if (enable) {
+ atomic_inc(&clk_ref);
+ } else if (!atomic_add_unless(&clk_ref, -1, 0)) {
+ pr_debug("master power-off req\n");
+ force_off = 1;
+ }
+
+ if (isr) {
+ /* if it's power off send workqueue to turn off clocks */
+ if (mdss_res->clk_ena && !atomic_read(&clk_ref))
+ queue_delayed_work(mdss_res->clk_ctrl_wq,
+ &mdss_res->clk_ctrl_worker,
+ mdss_res->timeout);
+ } else {
+ mutex_lock(&clk_ctrl_lock);
+ if (delayed_work_pending(&mdss_res->clk_ctrl_worker))
+ cancel_delayed_work(&mdss_res->clk_ctrl_worker);
+
+ if (atomic_read(&clk_ref)) {
+ mdss_mdp_clk_ctrl_update(true);
+ } else if (mdss_res->clk_ena) {
+ mutex_lock(&mdp_suspend_mutex);
+ if (force_off || mdss_res->suspend) {
+ mdss_mdp_clk_ctrl_update(false);
+ } else {
+ /* send workqueue to turn off mdp power */
+ queue_delayed_work(mdss_res->clk_ctrl_wq,
+ &mdss_res->clk_ctrl_worker,
+ mdss_res->timeout);
+ }
+ mutex_unlock(&mdp_suspend_mutex);
+ }
+ mutex_unlock(&clk_ctrl_lock);
+ }
+}
+
+static void mdss_mdp_clk_ctrl_workqueue_handler(struct work_struct *work)
+{
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+}
+
+static int mdss_mdp_irq_clk_setup(void)
+{
+ int ret;
+
+ ret = request_irq(mdss_res->irq, mdss_irq_handler, IRQF_DISABLED,
+ "MDSS", 0);
+ if (ret) {
+ pr_err("mdp request_irq() failed!\n");
+ return ret;
+ }
+ disable_irq(mdss_res->irq);
+
+ mdss_res->fs = regulator_get(NULL, "fs_mdp");
+ if (IS_ERR(mdss_res->fs))
+ mdss_res->fs = NULL;
+ else {
+ regulator_enable(mdss_res->fs);
+ mdss_res->fs_ena = true;
+ }
+
+ return 0;
+}
+
+static struct msm_panel_common_pdata *mdss_mdp_populate_pdata(
+ struct device *dev)
+{
+ struct msm_panel_common_pdata *pdata;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ dev_err(dev, "could not allocate memory for pdata\n");
+ return pdata;
+}
+
+static u32 mdss_mdp_res_init(void)
+{
+ u32 rc;
+
+ rc = mdss_mdp_irq_clk_setup();
+ if (rc)
+ return rc;
+
+ mdss_res->clk_ctrl_wq = create_singlethread_workqueue("mdp_clk_wq");
+ INIT_DELAYED_WORK(&mdss_res->clk_ctrl_worker,
+ mdss_mdp_clk_ctrl_workqueue_handler);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_res->rev = MDSS_MDP_REG_READ(MDSS_REG_HW_VERSION);
+ mdss_res->mdp_rev = MDSS_MDP_REG_READ(MDSS_MDP_REG_HW_VERSION);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ mdss_res->smp_mb_cnt = MDSS_MDP_SMP_MMB_BLOCKS;
+ mdss_res->smp_mb_size = MDSS_MDP_SMP_MMB_SIZE;
+ mdss_res->pipe_type_map = mdss_mdp_pipe_type_map;
+ mdss_res->mixer_type_map = mdss_mdp_mixer_type_map;
+
+ pr_info("mdss_revision=%x\n", mdss_res->rev);
+ pr_info("mdp_hw_revision=%x\n", mdss_res->mdp_rev);
+
+ mdss_res->res_init = true;
+ mdss_res->timeout = HZ/20;
+ mdss_res->clk_ena = false;
+ mdss_res->irq_mask = MDSS_MDP_DEFAULT_INTR_MASK;
+ mdss_res->suspend = false;
+ mdss_res->prim_ptype = NO_PANEL;
+ mdss_res->irq_ena = false;
+
+ return 0;
+}
+
+static int mdss_mdp_probe(struct platform_device *pdev)
+{
+ struct resource *mdss_mdp_mres;
+ struct resource *mdss_mdp_ires;
+ resource_size_t size;
+ int rc;
+
+ if (!mdss_res) {
+ mdss_res = devm_kzalloc(&pdev->dev, sizeof(*mdss_res),
+ GFP_KERNEL);
+ if (mdss_res == NULL)
+ return -ENOMEM;
+ }
+
+ if (pdev->dev.of_node) {
+ pdev->id = 0;
+ mdp_pdata = mdss_mdp_populate_pdata(&pdev->dev);
+ mdss_mdp_mres = platform_get_resource(pdev,
+ IORESOURCE_MEM, 0);
+ mdss_mdp_ires = platform_get_resource(pdev,
+ IORESOURCE_IRQ, 0);
+ if (!mdss_mdp_mres || !mdss_mdp_ires) {
+ pr_err("unable to get the MDSS resources");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+ mdss_reg_base = ioremap(mdss_mdp_mres->start,
+ resource_size(mdss_mdp_mres));
+
+ pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+ (int) mdss_mdp_mres->start,
+ (int) mdss_reg_base);
+
+ mdss_res->irq = mdss_mdp_ires->start;
+ } else if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+ mdp_pdata = pdev->dev.platform_data;
+
+ size = resource_size(&pdev->resource[0]);
+ mdss_reg_base = ioremap(pdev->resource[0].start, size);
+
+ pr_info("MDP HW Base phy_Address=0x%x virt=0x%x\n",
+ (int) pdev->resource[0].start,
+ (int) mdss_reg_base);
+
+ mdss_res->irq = platform_get_irq(pdev, 0);
+ if (mdss_res->irq < 0) {
+ pr_err("can not get mdp irq\n");
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+ }
+
+ if (unlikely(!mdss_reg_base)) {
+ rc = -ENOMEM;
+ goto probe_done;
+ }
+
+ rc = mdss_mdp_res_init();
+ if (rc) {
+ pr_err("unable to initialize mdss mdp resources\n");
+ goto probe_done;
+ }
+
+probe_done:
+ if (IS_ERR_VALUE(rc)) {
+ if (mdss_res) {
+ devm_kfree(&pdev->dev, mdss_res);
+ mdss_res = NULL;
+ }
+ }
+
+ return rc;
+}
+
+void mdss_mdp_footswitch_ctrl(int on)
+{
+ mutex_lock(&mdp_suspend_mutex);
+ if (!mdss_res->suspend || mdss_res->eintf_ena || !mdss_res->fs) {
+ mutex_unlock(&mdp_suspend_mutex);
+ return;
+ }
+
+ if (on && !mdss_res->fs_ena) {
+ pr_debug("Enable MDP FS\n");
+ regulator_enable(mdss_res->fs);
+ mdss_res->fs_ena = true;
+ } else if (!on && mdss_res->fs_ena) {
+ pr_debug("Disable MDP FS\n");
+ regulator_disable(mdss_res->fs);
+ mdss_res->fs_ena = false;
+ }
+ mutex_unlock(&mdp_suspend_mutex);
+}
+
+#ifdef CONFIG_PM
+static void mdss_mdp_suspend_sub(void)
+{
+ cancel_delayed_work(&mdss_res->clk_ctrl_worker);
+
+ flush_workqueue(mdss_res->clk_ctrl_wq);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ mutex_lock(&mdp_suspend_mutex);
+ mdss_res->suspend = true;
+ mutex_unlock(&mdp_suspend_mutex);
+}
+
+static int mdss_mdp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (pdev->id == 0) {
+ mdss_mdp_suspend_sub();
+ if (mdss_res->clk_ena) {
+ pr_err("MDP suspend failed\n");
+ return -EBUSY;
+ }
+ mdss_mdp_footswitch_ctrl(false);
+ }
+ return 0;
+}
+
+static int mdss_mdp_resume(struct platform_device *pdev)
+{
+ mdss_mdp_footswitch_ctrl(true);
+ mutex_lock(&mdp_suspend_mutex);
+ mdss_res->suspend = false;
+ mutex_unlock(&mdp_suspend_mutex);
+ return 0;
+}
+#else
+#define mdss_mdp_suspend NULL
+#define mdss_mdp_resume NULL
+#endif
+
+static int mdss_mdp_remove(struct platform_device *pdev)
+{
+ if (mdss_res->fs != NULL)
+ regulator_put(mdss_res->fs);
+ iounmap(mdss_reg_base);
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id mdss_mdp_dt_match[] = {
+ { .compatible = "qcom,mdss_mdp",},
+};
+MODULE_DEVICE_TABLE(of, mdss_mdp_dt_match);
+
+static struct platform_driver mdss_mdp_driver = {
+ .probe = mdss_mdp_probe,
+ .remove = mdss_mdp_remove,
+ .suspend = mdss_mdp_suspend,
+ .resume = mdss_mdp_resume,
+ .shutdown = NULL,
+ .driver = {
+ /*
+ * Driver name must match the device name added in
+ * platform.c.
+ */
+ .name = "mdp",
+ .of_match_table = mdss_mdp_dt_match,
+ },
+};
+
+static int mdss_mdp_register_driver(void)
+{
+ return platform_driver_register(&mdss_mdp_driver);
+}
+
+static int __init mdss_mdp_driver_init(void)
+{
+ int ret;
+
+ ret = mdss_mdp_register_driver();
+ if (ret) {
+ pr_err("mdp_register_driver() failed!\n");
+ return ret;
+ }
+
+ return 0;
+
+}
+
+module_init(mdss_mdp_driver_init);
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
new file mode 100644
index 0000000..c65d5a7
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -0,0 +1,294 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_MDP_H
+#define MDSS_MDP_H
+
+#include <linux/io.h>
+#include <linux/msm_mdp.h>
+#include <linux/platform_device.h>
+
+#include "mdss.h"
+#include "mdss_mdp_hwio.h"
+
+#define MDSS_MDP_DEFAULT_INTR_MASK 0
+#define MDSS_MDP_CURSOR_WIDTH 64
+#define MDSS_MDP_CURSOR_HEIGHT 64
+#define MDSS_MDP_CURSOR_SIZE (MDSS_MDP_CURSOR_WIDTH*MDSS_MDP_CURSOR_WIDTH*4)
+
+#define MDP_CLK_DEFAULT_RATE 37500000
+#define PHASE_STEP_SHIFT 21
+#define MAX_MIXER_WIDTH 2048
+#define MAX_MIXER_HEIGHT 2048
+#define MAX_IMG_WIDTH 0x3FFF
+#define MAX_IMG_HEIGHT 0x3FFF
+#define MIN_DST_W 10
+#define MIN_DST_H 10
+#define MAX_DST_W MAX_MIXER_WIDTH
+#define MAX_DST_H MAX_MIXER_HEIGHT
+#define MAX_PLANES 4
+#define MAX_DOWNSCALE_RATIO 4
+#define MAX_UPSCALE_RATIO 20
+
+#ifdef MDSS_MDP_DEBUG_REG
+static inline void mdss_mdp_reg_write(u32 addr, u32 val)
+{
+ pr_debug("0x%05X = 0x%08X\n", addr, val);
+ MDSS_REG_WRITE(addr, val);
+}
+#define MDSS_MDP_REG_WRITE(addr, val) mdss_mdp_reg_write((u32)addr, (u32)(val))
+static inline u32 mdss_mdp_reg_read(u32 addr)
+{
+ u32 val;
+ val = MDSS_REG_READ(addr);
+ pr_debug("0x%05X = 0x%08X\n", addr, val);
+ return val;
+}
+#define MDSS_MDP_REG_READ(addr) mdss_mdp_reg_read((u32)(addr))
+#else
+#define MDSS_MDP_REG_WRITE(addr, val) MDSS_REG_WRITE((u32)(addr), (u32)(val))
+#define MDSS_MDP_REG_READ(addr) MDSS_REG_READ((u32)(addr))
+#endif
+
+enum mdss_mdp_block_power_state {
+ MDP_BLOCK_POWER_OFF,
+ MDP_BLOCK_POWER_ON
+};
+
+enum mdss_mdp_mixer_type {
+ MDSS_MDP_MIXER_TYPE_UNUSED,
+ MDSS_MDP_MIXER_TYPE_INTF,
+ MDSS_MDP_MIXER_TYPE_WRITEBACK,
+};
+
+enum mdss_mdp_mixer_mux {
+ MDSS_MDP_MIXER_MUX_DEFAULT,
+ MDSS_MDP_MIXER_MUX_LEFT,
+ MDSS_MDP_MIXER_MUX_RIGHT,
+};
+
+enum mdss_mdp_pipe_type {
+ MDSS_MDP_PIPE_TYPE_UNUSED,
+ MDSS_MDP_PIPE_TYPE_VIG,
+ MDSS_MDP_PIPE_TYPE_RGB,
+ MDSS_MDP_PIPE_TYPE_DMA,
+};
+
+enum mdss_mdp_block_type {
+ MDSS_MDP_BLOCK_UNUSED,
+ MDSS_MDP_BLOCK_SSPP,
+ MDSS_MDP_BLOCK_MIXER,
+ MDSS_MDP_BLOCK_DSPP,
+ MDSS_MDP_BLOCK_WB,
+ MDSS_MDP_BLOCK_MAX
+};
+
+struct mdss_mdp_ctl {
+ u32 num;
+ u32 ref_cnt;
+
+ u32 intf_num;
+ u32 intf_type;
+
+ u32 opmode;
+ u32 flush_bits;
+
+ u32 play_cnt;
+
+ u16 width;
+ u16 height;
+ u32 dst_format;
+
+ struct msm_fb_data_type *mfd;
+ struct mdss_mdp_mixer *mixer_left;
+ struct mdss_mdp_mixer *mixer_right;
+ struct mutex lock;
+
+ int (*start_fnc) (struct mdss_mdp_ctl *ctl);
+ int (*stop_fnc) (struct mdss_mdp_ctl *ctl);
+ int (*prepare_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+ int (*display_fnc) (struct mdss_mdp_ctl *ctl, void *arg);
+
+ void *priv_data;
+};
+
+struct mdss_mdp_mixer {
+ u32 num;
+ u32 ref_cnt;
+ u8 type;
+ u8 params_changed;
+
+ u16 width;
+ u16 height;
+ u8 cursor_enabled;
+ u8 rotator_mode;
+
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
+};
+
+struct mdss_mdp_img_rect {
+ u16 x;
+ u16 y;
+ u16 w;
+ u16 h;
+};
+
+struct mdss_mdp_format_params {
+ u32 format;
+ u8 is_yuv;
+
+ u8 frame_format;
+ u8 chroma_sample;
+ u8 solid_fill;
+ u8 fetch_planes;
+ u8 unpack_align_msb; /* 0 to LSB, 1 to MSB */
+ u8 unpack_tight; /* 0 for loose, 1 for tight */
+ u8 unpack_count; /* 0 = 1 component, 1 = 2 component ... */
+ u8 bpp;
+ u8 alpha_enable; /* source has alpha */
+
+ /*
+ * number of bits for source component,
+ * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
+ */
+ u8 a_bit; /* component 3, alpha */
+ u8 r_bit; /* component 2, R_Cr */
+ u8 b_bit; /* component 1, B_Cb */
+ u8 g_bit; /* component 0, G_lumz */
+
+ /*
+ * unpack pattern
+ * A = C3, R = C2, B = C1, G = C0
+ */
+ u8 element3;
+ u8 element2;
+ u8 element1;
+ u8 element0;
+};
+
+struct mdss_mdp_plane_sizes {
+ u32 num_planes;
+ u32 plane_size[MAX_PLANES];
+ u32 total_size;
+ u32 ystride[MAX_PLANES];
+};
+
+struct mdss_mdp_img_data {
+ u32 addr;
+ u32 len;
+ u32 flags;
+ int p_need;
+ struct file *srcp_file;
+ struct ion_handle *srcp_ihdl;
+ struct ion_client *iclient;
+};
+
+struct mdss_mdp_data {
+ u8 num_planes;
+ u8 bwc_enabled;
+ struct mdss_mdp_img_data p[MAX_PLANES];
+};
+
+struct mdss_mdp_pipe {
+ u32 num;
+ u32 type;
+ u32 ndx;
+ atomic_t ref_cnt;
+ u32 play_cnt;
+
+ u32 flags;
+ u32 bwc_mode;
+
+ u16 img_width;
+ u16 img_height;
+ struct mdss_mdp_img_rect src;
+ struct mdss_mdp_img_rect dst;
+
+ struct mdss_mdp_format_params *src_fmt;
+ struct mdss_mdp_plane_sizes src_planes;
+
+ u8 mixer_stage;
+ u8 is_fg;
+ u8 alpha;
+ u32 transp;
+
+ struct msm_fb_data_type *mfd;
+ struct mdss_mdp_mixer *mixer;
+ struct mutex lock;
+
+ struct mdp_overlay req_data;
+ u32 params_changed;
+
+ unsigned long smp[MAX_PLANES];
+};
+
+static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
+ u32 reg, u32 val)
+{
+ int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
+ MDSS_MDP_REG_WRITE(offset + reg, val);
+}
+
+static inline u32 mdss_mdp_ctl_read(struct mdss_mdp_ctl *ctl, u32 reg)
+{
+ int offset = MDSS_MDP_REG_CTL_OFFSET(ctl->num);
+ return MDSS_MDP_REG_READ(offset + reg);
+}
+
+irqreturn_t mdss_mdp_isr(int irq, void *ptr);
+int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
+void mdss_mdp_irq_disable(u32 intr_type, u32 intf_num);
+void mdss_mdp_irq_disable_nosync(u32 intr_type, u32 intf_num);
+int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
+ void (*fnc_ptr)(void *), void *arg);
+
+unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
+int mdss_mdp_vsync_clk_enable(int enable);
+void mdss_mdp_clk_ctrl(int enable, int isr);
+void mdss_mdp_footswitch_ctrl(int on);
+
+int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
+int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
+
+int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd);
+int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd);
+
+struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
+struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
+ int mux, int stage);
+int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
+int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum);
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type);
+struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx);
+int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe);
+void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe);
+
+int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe);
+int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd);
+int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_data *src_data);
+
+int mdss_mdp_data_check(struct mdss_mdp_data *data,
+ struct mdss_mdp_plane_sizes *ps);
+int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
+ struct mdss_mdp_plane_sizes *ps);
+struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format);
+int mdss_mdp_put_img(struct mdss_mdp_img_data *data);
+int mdss_mdp_get_img(struct ion_client *iclient, struct msmfb_data *img,
+ struct mdss_mdp_img_data *data);
+
+#endif /* MDSS_MDP_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
new file mode 100644
index 0000000..d89347e
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -0,0 +1,600 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+static DEFINE_MUTEX(mdss_mdp_ctl_lock);
+static struct mdss_mdp_ctl mdss_mdp_ctl_list[MDSS_MDP_MAX_CTL];
+static struct mdss_mdp_mixer mdss_mdp_mixer_list[MDSS_MDP_MAX_LAYERMIXER];
+
+static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(void)
+{
+ struct mdss_mdp_ctl *ctl = NULL;
+ int cnum;
+
+ mutex_lock(&mdss_mdp_ctl_lock);
+ for (cnum = 0; cnum < MDSS_MDP_MAX_CTL; cnum++) {
+ if (mdss_mdp_ctl_list[cnum].ref_cnt == 0) {
+ ctl = &mdss_mdp_ctl_list[cnum];
+ ctl->num = cnum;
+ ctl->ref_cnt++;
+ mutex_init(&ctl->lock);
+
+ pr_debug("alloc ctl_num=%d\n", ctl->num);
+ break;
+ }
+ }
+ mutex_unlock(&mdss_mdp_ctl_lock);
+
+ return ctl;
+}
+
+static int mdss_mdp_ctl_free(struct mdss_mdp_ctl *ctl)
+{
+ if (!ctl)
+ return -ENODEV;
+
+ pr_debug("free ctl_num=%d ref_cnt=%d\n", ctl->num, ctl->ref_cnt);
+
+ if (!ctl->ref_cnt) {
+ pr_err("called with ref_cnt=0\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&mdss_mdp_ctl_lock);
+ if (--ctl->ref_cnt == 0)
+ memset(ctl, 0, sizeof(*ctl));
+ mutex_unlock(&mdss_mdp_ctl_lock);
+
+ return 0;
+}
+
+static struct mdss_mdp_mixer *mdss_mdp_mixer_alloc(u32 type)
+{
+ struct mdss_mdp_mixer *mixer = NULL;
+ int mnum;
+
+ mutex_lock(&mdss_mdp_ctl_lock);
+ for (mnum = 0; mnum < MDSS_MDP_MAX_LAYERMIXER; mnum++) {
+ if (type == mdss_res->mixer_type_map[mnum] &&
+ mdss_mdp_mixer_list[mnum].ref_cnt == 0) {
+ mixer = &mdss_mdp_mixer_list[mnum];
+ mixer->num = mnum;
+ mixer->ref_cnt++;
+ mixer->params_changed++;
+ mixer->type = type;
+
+ pr_debug("mixer_num=%d\n", mixer->num);
+ break;
+ }
+ }
+ mutex_unlock(&mdss_mdp_ctl_lock);
+
+ return mixer;
+}
+
+static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer)
+{
+ if (!mixer)
+ return -ENODEV;
+
+ pr_debug("free mixer_num=%d ref_cnt=%d\n", mixer->num, mixer->ref_cnt);
+
+ if (!mixer->ref_cnt) {
+ pr_err("called with ref_cnt=0\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&mdss_mdp_ctl_lock);
+ if (--mixer->ref_cnt == 0)
+ memset(mixer, 0, sizeof(*mixer));
+ mutex_unlock(&mdss_mdp_ctl_lock);
+
+ return 0;
+}
+
+static int mdss_mdp_ctl_init(struct msm_fb_data_type *mfd)
+{
+ struct mdss_mdp_ctl *ctl;
+ u32 width, height;
+
+ if (!mfd)
+ return -ENODEV;
+
+ width = mfd->fbi->var.xres;
+ height = mfd->fbi->var.yres;
+
+ if (width > (2 * MAX_MIXER_WIDTH)) {
+ pr_err("unsupported resolution\n");
+ return -EINVAL;
+ }
+
+ ctl = mdss_mdp_ctl_alloc();
+
+ if (!ctl) {
+ pr_err("unable to allocate ctl\n");
+ return -ENOMEM;
+ }
+
+ ctl->mfd = mfd;
+ ctl->width = width;
+ ctl->height = height;
+ ctl->dst_format = mfd->panel_info.out_format;
+
+ ctl->mixer_left = mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+ if (!ctl->mixer_left) {
+ pr_err("unable to allocate layer mixer\n");
+ mdss_mdp_ctl_free(ctl);
+ return -ENOMEM;
+ }
+
+ ctl->mixer_left->width = MIN(width, MAX_MIXER_WIDTH);
+ ctl->mixer_left->height = height;
+ ctl->mixer_left->ctl = ctl;
+
+ width -= ctl->mixer_left->width;
+
+ if (width) {
+ ctl->mixer_right =
+ mdss_mdp_mixer_alloc(MDSS_MDP_MIXER_TYPE_INTF);
+ if (!ctl->mixer_right) {
+ pr_err("unable to allocate layer mixer\n");
+ mdss_mdp_mixer_free(ctl->mixer_left);
+ mdss_mdp_ctl_free(ctl);
+ return -ENOMEM;
+ }
+ ctl->mixer_right->width = width;
+ ctl->mixer_right->height = height;
+ ctl->mixer_right->ctl = ctl;
+ }
+
+ switch (mfd->panel_info.type) {
+ case WRITEBACK_PANEL:
+ ctl->intf_num = MDSS_MDP_NO_INTF;
+ ctl->opmode = MDSS_MDP_CTL_OP_WFD_MODE;
+ ctl->start_fnc = mdss_mdp_writeback_start;
+ break;
+ default:
+ pr_err("unsupported panel type (%d)\n", mfd->panel_info.type);
+ mdss_mdp_ctl_free(ctl);
+ return -EINVAL;
+
+ }
+
+ ctl->opmode |= (ctl->intf_num << 4);
+
+ if (ctl->mixer_right) {
+ ctl->opmode |= MDSS_MDP_CTL_OP_PACK_3D_ENABLE |
+ MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT;
+ }
+
+ mfd->ctl = ctl;
+
+ return 0;
+}
+
+static int mdss_mdp_ctl_destroy(struct msm_fb_data_type *mfd)
+{
+ struct mdss_mdp_ctl *ctl;
+ if (!mfd || !mfd->ctl)
+ return -ENODEV;
+
+ ctl = mfd->ctl;
+ mfd->ctl = NULL;
+
+ if (ctl->mixer_left)
+ mdss_mdp_mixer_free(ctl->mixer_left);
+ if (ctl->mixer_right)
+ mdss_mdp_mixer_free(ctl->mixer_right);
+ mdss_mdp_ctl_free(ctl);
+
+ return 0;
+}
+
+int mdss_mdp_ctl_on(struct msm_fb_data_type *mfd)
+{
+ struct mdss_panel_data *pdata;
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_mdp_mixer *mixer;
+ u32 outsize, temp, off;
+ int ret = 0;
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+ if (!pdata) {
+ pr_err("no panel connected\n");
+ return -ENODEV;
+ }
+
+ if (!mfd->ctl) {
+ if (mdss_mdp_ctl_init(mfd)) {
+ pr_err("unable to initialize ctl\n");
+ return -ENODEV;
+ }
+ }
+ ctl = mfd->ctl;
+
+ mutex_lock(&ctl->lock);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ if (ctl->start_fnc)
+ ret = ctl->start_fnc(ctl);
+ else
+ pr_warn("no start function for ctl=%d type=%d\n", ctl->num,
+ mfd->panel_info.type);
+
+ if (ret) {
+ pr_err("unable to start intf\n");
+ goto start_fail;
+ }
+
+ pr_debug("ctl_num=%d\n", ctl->num);
+
+ mixer = ctl->mixer_left;
+ mixer->params_changed++;
+
+ temp = MDSS_MDP_REG_READ(MDSS_MDP_REG_DISP_INTF_SEL);
+ temp |= (ctl->intf_type << (ctl->intf_num * 8));
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_DISP_INTF_SEL, temp);
+
+ outsize = (mixer->height << 16) | mixer->width;
+ off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+
+ if (ctl->mixer_right) {
+ mixer = ctl->mixer_right;
+ mixer->params_changed++;
+ outsize = (mixer->height << 16) | mixer->width;
+ off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OUT_SIZE, outsize);
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_PACK_3D, 0);
+ }
+
+ ret = pdata->on(pdata);
+
+start_fail:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
+
+int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd)
+{
+ struct mdss_panel_data *pdata;
+ struct mdss_mdp_ctl *ctl;
+ int ret = 0;
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (!mfd->ctl) {
+ pr_err("ctl not initialized\n");
+ return -ENODEV;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+ if (!pdata) {
+ pr_err("no panel connected\n");
+ return -ENODEV;
+ }
+
+ ctl = mfd->ctl;
+
+ pr_debug("ctl_num=%d\n", mfd->ctl->num);
+
+ mutex_lock(&ctl->lock);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ if (ctl->stop_fnc)
+ ret = ctl->stop_fnc(ctl);
+ else
+ pr_warn("no stop func for ctl=%d\n", ctl->num);
+
+ if (ret)
+ pr_warn("error powering off intf ctl=%d\n", ctl->num);
+
+ ret = pdata->off(pdata);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ ctl->play_cnt = 0;
+ mutex_unlock(&ctl->lock);
+
+ mdss_mdp_pipe_release_all(mfd);
+
+ if (!mfd->ref_cnt)
+ mdss_mdp_ctl_destroy(mfd);
+
+
+ return ret;
+}
+
+static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_mixer *mixer)
+{
+ struct mdss_mdp_pipe *pipe, *bgpipe = NULL;
+ u32 off, blend_op, blend_stage;
+ u32 mixercfg = 0, blend_color_out = 0, bgalpha = 0;
+ int stage;
+
+ if (!mixer)
+ return -ENODEV;
+
+ pr_debug("setup mixer=%d\n", mixer->num);
+
+ for (stage = MDSS_MDP_STAGE_BASE; stage < MDSS_MDP_MAX_STAGE; stage++) {
+ pipe = mixer->stage_pipe[stage];
+ if (pipe == NULL) {
+ if (stage == MDSS_MDP_STAGE_BASE)
+ mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
+ continue;
+ }
+
+ if (stage != pipe->mixer_stage) {
+ mixer->stage_pipe[stage] = NULL;
+ continue;
+ }
+ mixercfg |= stage << (3 * pipe->num);
+
+ if (stage == MDSS_MDP_STAGE_BASE) {
+ bgpipe = pipe;
+ if (pipe->src_fmt->alpha_enable)
+ bgalpha = 1;
+ continue;
+ }
+
+ blend_stage = stage - MDSS_MDP_STAGE_0;
+ off = MDSS_MDP_REG_LM_OFFSET(mixer->num) +
+ MDSS_MDP_REG_LM_BLEND_OFFSET(blend_stage);
+
+ if (pipe->is_fg) {
+ bgalpha = 0;
+ if (bgpipe) {
+ mixercfg &= ~(0x7 << (3 * bgpipe->num));
+ mixercfg |= MDSS_MDP_LM_BORDER_COLOR;
+ }
+ blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+ MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+ /* keep fg alpha */
+ blend_color_out |= 1 << (blend_stage + 1);
+
+ pr_debug("pnum=%d stg=%d alpha=IS_FG\n", pipe->num,
+ stage);
+ } else if (pipe->src_fmt->alpha_enable) {
+ bgalpha = 0;
+ blend_op = (MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL |
+ MDSS_MDP_BLEND_BG_INV_ALPHA);
+ /* keep fg alpha */
+ blend_color_out |= 1 << (blend_stage + 1);
+
+ pr_debug("pnum=%d stg=%d alpha=FG PIXEL\n", pipe->num,
+ stage);
+ } else if (bgalpha) {
+ blend_op = (MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL |
+ MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL |
+ MDSS_MDP_BLEND_FG_INV_ALPHA);
+ /* keep bg alpha */
+ pr_debug("pnum=%d stg=%d alpha=BG_PIXEL\n", pipe->num,
+ stage);
+ } else {
+ blend_op = (MDSS_MDP_BLEND_FG_ALPHA_FG_CONST |
+ MDSS_MDP_BLEND_BG_ALPHA_BG_CONST);
+ pr_debug("pnum=%d stg=%d alpha=CONST\n", pipe->num,
+ stage);
+ }
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_op);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA,
+ pipe->alpha);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA,
+ 0xFF - pipe->alpha);
+ }
+
+ if (mixer->cursor_enabled)
+ mixercfg |= MDSS_MDP_LM_CURSOR_OUT;
+
+ pr_debug("mixer=%d mixer_cfg=%x\n", mixer->num, mixercfg);
+
+ ctl->flush_bits |= BIT(6) << mixer->num; /* LAYER_MIXER */
+
+ off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(mixer->num), mixercfg);
+
+ return 0;
+}
+
+struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
+{
+ struct mdss_mdp_mixer *mixer = NULL;
+ if (!ctl)
+ return NULL;
+
+ switch (mux) {
+ case MDSS_MDP_MIXER_MUX_DEFAULT:
+ case MDSS_MDP_MIXER_MUX_LEFT:
+ mixer = ctl->mixer_left;
+ break;
+ case MDSS_MDP_MIXER_MUX_RIGHT:
+ mixer = ctl->mixer_right;
+ break;
+ }
+
+ return mixer;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
+ int mux, int stage)
+{
+ struct mdss_mdp_pipe *pipe = NULL;
+ struct mdss_mdp_mixer *mixer;
+ if (!ctl)
+ return NULL;
+
+ if (mutex_lock_interruptible(&ctl->lock))
+ return NULL;
+
+ mixer = mdss_mdp_mixer_get(ctl, mux);
+ if (mixer)
+ pipe = mixer->stage_pipe[stage];
+ mutex_unlock(&ctl->lock);
+
+ return pipe;
+}
+
+int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)
+{
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_mdp_mixer *mixer;
+
+ if (!pipe)
+ return -EINVAL;
+ mixer = pipe->mixer;
+ if (!mixer)
+ return -EINVAL;
+ ctl = mixer->ctl;
+ if (!ctl)
+ return -EINVAL;
+
+ if (pipe->mixer_stage >= MDSS_MDP_MAX_STAGE) {
+ pr_err("invalid mixer stage\n");
+ return -EINVAL;
+ }
+
+ pr_debug("pnum=%x mixer=%d stage=%d\n", pipe->num, mixer->num,
+ pipe->mixer_stage);
+
+ if (mutex_lock_interruptible(&ctl->lock))
+ return -EINTR;
+
+ if (params_changed) {
+ mixer->params_changed++;
+ mixer->stage_pipe[pipe->mixer_stage] = pipe;
+ }
+
+ if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA)
+ ctl->flush_bits |= BIT(pipe->num) << 5;
+ else /* RGB/VIG pipe */
+ ctl->flush_bits |= BIT(pipe->num);
+
+ mutex_unlock(&ctl->lock);
+
+ return 0;
+}
+
+int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe)
+{
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_mdp_mixer *mixer;
+
+ if (!pipe)
+ return -EINVAL;
+ mixer = pipe->mixer;
+ if (!mixer)
+ return -EINVAL;
+ ctl = mixer->ctl;
+ if (!ctl)
+ return -EINVAL;
+
+ pr_debug("unstage pnum=%d stage=%d mixer=%d\n", pipe->num,
+ pipe->mixer_stage, mixer->num);
+
+ if (mutex_lock_interruptible(&ctl->lock))
+ return -EINTR;
+
+ mixer->params_changed++;
+ mixer->stage_pipe[pipe->mixer_stage] = NULL;
+
+ mutex_unlock(&ctl->lock);
+
+ return 0;
+}
+
+static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer)
+{
+ mixer->params_changed = 0;
+
+ /* skip mixer setup for rotator */
+ if (!mixer->rotator_mode)
+ mdss_mdp_mixer_setup(mixer->ctl, mixer);
+
+ return 0;
+}
+
+int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ int mixer1_changed, mixer2_changed;
+ int ret = 0;
+
+ if (!ctl) {
+ pr_err("display function not set\n");
+ return -ENODEV;
+ }
+
+ pr_debug("commit ctl=%d\n", ctl->num);
+
+ if (mutex_lock_interruptible(&ctl->lock))
+ return -EINTR;
+
+ mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed);
+ mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ if (mixer1_changed || mixer2_changed) {
+ if (ctl->prepare_fnc)
+ ret = ctl->prepare_fnc(ctl, arg);
+ if (ret) {
+ pr_err("error preparing display\n");
+ goto done;
+ }
+
+ if (mixer1_changed)
+ mdss_mdp_mixer_update(ctl->mixer_left);
+ if (mixer2_changed)
+ mdss_mdp_mixer_update(ctl->mixer_right);
+
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode);
+ ctl->flush_bits |= BIT(17); /* CTL */
+ }
+
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, ctl->flush_bits);
+ wmb();
+ ctl->flush_bits = 0;
+
+ if (ctl->display_fnc)
+ ret = ctl->display_fnc(ctl, arg); /* kickoff */
+ if (ret)
+ pr_warn("error displaying frame\n");
+
+ ctl->play_cnt++;
+
+done:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ mutex_unlock(&ctl->lock);
+
+ return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_formats.h b/drivers/video/msm/mdss/mdss_mdp_formats.h
new file mode 100644
index 0000000..07eefc1
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_formats.h
@@ -0,0 +1,328 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_MDP_FORMATS_H
+#define MDSS_MDP_FORMATS_H
+
+#include <linux/msm_mdp.h>
+
+#include "mdss_mdp.h"
+
+#define C3_ALPHA 3 /* alpha */
+#define C2_R_Cr 2 /* R/Cr */
+#define C1_B_Cb 1 /* B/Cb */
+#define C0_G_Y 0 /* G/luma */
+
+static struct mdss_mdp_format_params mdss_mdp_format_map[MDP_IMGTYPE_LIMIT] = {
+ [MDP_RGB_565] = {
+ .format = MDP_RGB_565,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 0,
+ .r_bit = 1, /* R, 5 bits */
+ .b_bit = 1, /* B, 5 bits */
+ .g_bit = 2, /* G, 6 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 2,
+ .element2 = C2_R_Cr,
+ .element1 = C0_G_Y,
+ .element0 = C1_B_Cb,
+ .bpp = 1, /* 2 bpp */
+ },
+ [MDP_BGR_565] = {
+ .format = MDP_BGR_565,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 0,
+ .r_bit = 1, /* R, 5 bits */
+ .b_bit = 1, /* B, 5 bits */
+ .g_bit = 2, /* G, 6 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 2,
+ .element2 = C1_B_Cb,
+ .element1 = C0_G_Y,
+ .element0 = C2_R_Cr,
+ .bpp = 1, /* 2 bpp */
+ },
+ [MDP_RGB_888] = {
+ .format = MDP_RGB_888,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 2,
+ .element2 = C1_B_Cb,
+ .element1 = C0_G_Y,
+ .element0 = C2_R_Cr,
+ .bpp = 2, /* 3 bpp */
+ },
+ [MDP_XRGB_8888] = {
+ .format = MDP_XRGB_8888,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 3, /* alpha, 4 bits */
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 3,
+ .element3 = C1_B_Cb,
+ .element2 = C0_G_Y,
+ .element1 = C2_R_Cr,
+ .element0 = C3_ALPHA,
+ .bpp = 3, /* 4 bpp */
+ },
+ [MDP_ARGB_8888] = {
+ .format = MDP_ARGB_8888,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 3, /* alpha, 4 bits */
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 1,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 3,
+ .element3 = C1_B_Cb,
+ .element2 = C0_G_Y,
+ .element1 = C2_R_Cr,
+ .element0 = C3_ALPHA,
+ .bpp = 3, /* 4 bpp */
+ },
+ [MDP_RGBA_8888] = {
+ .format = MDP_RGBA_8888,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 3, /* alpha, 4 bits */
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 1,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 3,
+ .element3 = C3_ALPHA,
+ .element2 = C1_B_Cb,
+ .element1 = C0_G_Y,
+ .element0 = C2_R_Cr,
+ .bpp = 3, /* 4 bpp */
+ },
+ [MDP_RGBX_8888] = {
+ .format = MDP_RGBX_8888,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 3,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 3,
+ .element3 = C3_ALPHA,
+ .element2 = C1_B_Cb,
+ .element1 = C0_G_Y,
+ .element0 = C2_R_Cr,
+ .bpp = 3, /* 4 bpp */
+ },
+ [MDP_BGRA_8888] = {
+ .format = MDP_BGRA_8888,
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .a_bit = 3, /* alpha, 4 bits */
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 1,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 3,
+ .element3 = C3_ALPHA,
+ .element2 = C2_R_Cr,
+ .element1 = C0_G_Y,
+ .element0 = C1_B_Cb,
+ .bpp = 3, /* 4 bpp */
+ },
+ [MDP_YCRYCB_H2V1] = {
+ .format = MDP_YCRYCB_H2V1,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
+ .chroma_sample = MDSS_MDP_CHROMA_H2V1,
+ .unpack_count = 3,
+ .element3 = C0_G_Y,
+ .element2 = C2_R_Cr,
+ .element1 = C0_G_Y,
+ .element0 = C1_B_Cb,
+ },
+ [MDP_Y_CRCB_H2V1] = {
+ .format = MDP_Y_CRCB_H2V1,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_H2V1,
+ .element1 = C1_B_Cb,
+ .element0 = C2_R_Cr,
+ },
+ [MDP_Y_CBCR_H2V1] = {
+ .format = MDP_Y_CBCR_H2V1,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_H2V1,
+ .element1 = C2_R_Cr,
+ .element0 = C1_B_Cb,
+ },
+ [MDP_Y_CRCB_H1V2] = {
+ .format = MDP_Y_CRCB_H1V2,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_H1V2,
+ .element1 = C1_B_Cb,
+ .element0 = C2_R_Cr,
+ },
+ [MDP_Y_CBCR_H1V2] = {
+ .format = MDP_Y_CBCR_H1V2,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_H1V2,
+ .element1 = C2_R_Cr,
+ .element0 = C1_B_Cb,
+ },
+ [MDP_Y_CRCB_H2V2] = {
+ .format = MDP_Y_CRCB_H2V2,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_420,
+ .element1 = C1_B_Cb,
+ .element0 = C2_R_Cr,
+ },
+ [MDP_Y_CBCR_H2V2] = {
+ .format = MDP_Y_CBCR_H2V2,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PSEUDO_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_420,
+ .element1 = C2_R_Cr,
+ .element0 = C1_B_Cb,
+ },
+ [MDP_Y_CR_CB_H2V2] = {
+ .format = MDP_Y_CR_CB_H2V2,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_420,
+ },
+ [MDP_Y_CB_CR_H2V2] = {
+ .format = MDP_Y_CB_CR_H2V2,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_420,
+ },
+ [MDP_Y_CR_CB_GH2V2] = {
+ .format = MDP_Y_CR_CB_GH2V2,
+ .is_yuv = 1,
+ .a_bit = 0,
+ .r_bit = 3, /* R, 8 bits */
+ .b_bit = 3, /* B, 8 bits */
+ .g_bit = 3, /* G, 8 bits */
+ .alpha_enable = 0,
+ .unpack_tight = 1,
+ .unpack_align_msb = 0,
+ .unpack_count = 1, /* 2 */
+ .bpp = 1, /* 2 bpp */
+ .fetch_planes = MDSS_MDP_PLANE_PLANAR,
+ .chroma_sample = MDSS_MDP_CHROMA_420,
+ },
+};
+#endif
diff --git a/drivers/video/msm/mdss/mdss_mdp_hwio.h b/drivers/video/msm/mdss/mdss_mdp_hwio.h
new file mode 100644
index 0000000..4ca1dce
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_hwio.h
@@ -0,0 +1,430 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 MDSS_MDP_HWIO_H
+#define MDSS_MDP_HWIO_H
+
+#include <linux/bitops.h>
+
+#define MDSS_REG_HW_VERSION 0x0
+#define MDSS_REG_HW_INTR_STATUS 0x10
+
+#define MDSS_INTR_MDP BIT(0)
+#define MDSS_INTR_DSI0 BIT(4)
+#define MDSS_INTR_DSI1 BIT(5)
+#define MDSS_INTR_HDMI BIT(8)
+#define MDSS_INTR_EDP BIT(12)
+
+#define MDSS_MDP_REG_HW_VERSION 0x00100
+#define MDSS_MDP_REG_DISP_INTF_SEL 0x00104
+#define MDSS_MDP_REG_INTR_EN 0x00110
+#define MDSS_MDP_REG_INTR_STATUS 0x00114
+#define MDSS_MDP_REG_INTR_CLEAR 0x00118
+#define MDSS_MDP_REG_HIST_INTR_EN 0x0011C
+#define MDSS_MDP_REG_HIST_INTR_STATUS 0x00120
+#define MDSS_MDP_REG_HIST_INTR_CLEAR 0x00124
+
+#define MDSS_INTF_DSI 0x1
+#define MDSS_INTF_HDMI 0x3
+#define MDSS_INTF_LCDC 0x5
+#define MDSS_INTF_EDP 0x9
+
+#define MDSS_MDP_INTR_WB_0_DONE BIT(0)
+#define MDSS_MDP_INTR_WB_1_DONE BIT(1)
+#define MDSS_MDP_INTR_WB_2_DONE BIT(4)
+#define MDSS_MDP_INTR_PING_PONG_0_DONE BIT(8)
+#define MDSS_MDP_INTR_PING_PONG_1_DONE BIT(9)
+#define MDSS_MDP_INTR_PING_PONG_2_DONE BIT(10)
+#define MDSS_MDP_INTR_PING_PONG_0_RD_PTR BIT(12)
+#define MDSS_MDP_INTR_PING_PONG_1_RD_PTR BIT(13)
+#define MDSS_MDP_INTR_PING_PONG_2_RD_PTR BIT(14)
+#define MDSS_MDP_INTR_PING_PONG_0_WR_PTR BIT(16)
+#define MDSS_MDP_INTR_PING_PONG_1_WR_PTR BIT(17)
+#define MDSS_MDP_INTR_PING_PONG_2_WR_PTR BIT(18)
+#define MDSS_MDP_INTR_PING_PONG_0_AUTOREFRESH_DONE BIT(20)
+#define MDSS_MDP_INTR_PING_PONG_1_AUTOREFRESH_DONE BIT(21)
+#define MDSS_MDP_INTR_PING_PONG_2_AUTOREFRESH_DONE BIT(22)
+#define MDSS_MDP_INTR_INTF_0_UNDERRUN BIT(24)
+#define MDSS_MDP_INTR_INTF_0_VSYNC BIT(25)
+#define MDSS_MDP_INTR_INTF_1_UNDERRUN BIT(26)
+#define MDSS_MDP_INTR_INTF_1_VSYNC BIT(27)
+#define MDSS_MDP_INTR_INTF_2_UNDERRUN BIT(28)
+#define MDSS_MDP_INTR_INTF_2_VSYNC BIT(29)
+#define MDSS_MDP_INTR_INTF_3_UNDERRUN BIT(30)
+#define MDSS_MDP_INTR_INTF_3_VSYNC BIT(31)
+
+enum mdss_mdp_intr_type {
+ MDSS_MDP_IRQ_WB_ROT_COMP = 0,
+ MDSS_MDP_IRQ_WB_WFD = 4,
+ MDSS_MDP_IRQ_PING_PONG_COMP = 8,
+ MDSS_MDP_IRQ_PING_PONG_RD_PTR = 12,
+ MDSS_MDP_IRQ_PING_PONG_WR_PTR = 16,
+ MDSS_MDP_IRQ_PING_PONG_AUTO_REF = 20,
+ MDSS_MDP_IRQ_INTF_UNDER_RUN = 24,
+ MDSS_MDP_IRQ_INTF_VSYNC = 25,
+};
+
+enum mdss_mdp_ctl_index {
+ MDSS_MDP_CTL0,
+ MDSS_MDP_CTL1,
+ MDSS_MDP_CTL2,
+ MDSS_MDP_CTL3,
+ MDSS_MDP_CTL4,
+ MDSS_MDP_MAX_CTL
+};
+
+#define MDSS_MDP_REG_CTL_OFFSET(ctl) (0x00600 + ((ctl) * 0x100))
+
+#define MDSS_MDP_REG_CTL_LAYER(lm) ((lm) * 0x004)
+#define MDSS_MDP_REG_CTL_TOP 0x014
+#define MDSS_MDP_REG_CTL_FLUSH 0x018
+#define MDSS_MDP_REG_CTL_START 0x01C
+#define MDSS_MDP_REG_CTL_PACK_3D 0x020
+
+#define MDSS_MDP_CTL_OP_VIDEO_MODE (0 << 17)
+#define MDSS_MDP_CTL_OP_CMD_MODE (1 << 17)
+
+#define MDSS_MDP_CTL_OP_ROT0_MODE 0x1
+#define MDSS_MDP_CTL_OP_ROT1_MODE 0x2
+#define MDSS_MDP_CTL_OP_WB0_MODE 0x3
+#define MDSS_MDP_CTL_OP_WB1_MODE 0x4
+#define MDSS_MDP_CTL_OP_WFD_MODE 0x5
+
+#define MDSS_MDP_CTL_OP_PACK_3D_ENABLE BIT(19)
+#define MDSS_MDP_CTL_OP_PACK_3D_FRAME_INT (0 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_H_ROW_INT (1 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_V_ROW_INT (2 << 20)
+#define MDSS_MDP_CTL_OP_PACK_3D_COL_INT (3 << 20)
+
+enum mdss_mdp_sspp_index {
+ MDSS_MDP_SSPP_VIG0,
+ MDSS_MDP_SSPP_VIG1,
+ MDSS_MDP_SSPP_VIG2,
+ MDSS_MDP_SSPP_RGB0,
+ MDSS_MDP_SSPP_RGB1,
+ MDSS_MDP_SSPP_RGB2,
+ MDSS_MDP_SSPP_DMA0,
+ MDSS_MDP_SSPP_DMA1,
+ MDSS_MDP_MAX_SSPP
+};
+
+enum mdss_mdp_sspp_fetch_type {
+ MDSS_MDP_PLANE_INTERLEAVED,
+ MDSS_MDP_PLANE_PLANAR,
+ MDSS_MDP_PLANE_PSEUDO_PLANAR,
+};
+
+enum mdss_mdp_sspp_chroma_samp_type {
+ MDSS_MDP_CHROMA_RGB,
+ MDSS_MDP_CHROMA_H2V1,
+ MDSS_MDP_CHROMA_H1V2,
+ MDSS_MDP_CHROMA_420
+};
+
+#define MDSS_MDP_REG_SSPP_OFFSET(pipe) (0x01200 + ((pipe) * 0x400))
+
+#define MDSS_MDP_REG_SSPP_SRC_SIZE 0x000
+#define MDSS_MDP_REG_SSPP_SRC_IMG_SIZE 0x004
+#define MDSS_MDP_REG_SSPP_SRC_XY 0x008
+#define MDSS_MDP_REG_SSPP_OUT_SIZE 0x00C
+#define MDSS_MDP_REG_SSPP_OUT_XY 0x010
+#define MDSS_MDP_REG_SSPP_SRC0_ADDR 0x014
+#define MDSS_MDP_REG_SSPP_SRC1_ADDR 0x018
+#define MDSS_MDP_REG_SSPP_SRC2_ADDR 0x01C
+#define MDSS_MDP_REG_SSPP_SRC3_ADDR 0x020
+#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE0 0x024
+#define MDSS_MDP_REG_SSPP_SRC_YSTRIDE1 0x028
+#define MDSS_MDP_REG_SSPP_STILE_FRAME_SIZE 0x02C
+#define MDSS_MDP_REG_SSPP_SRC_FORMAT 0x030
+#define MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN 0x034
+
+#define MDSS_MDP_REG_SSPP_SRC_OP_MODE 0x038
+#define MDSS_MDP_OP_DEINTERLACE BIT(22)
+#define MDSS_MDP_OP_DEINTERLACE_ODD BIT(23)
+#define MDSS_MDP_OP_FLIP_UD BIT(14)
+#define MDSS_MDP_OP_FLIP_LR BIT(13)
+#define MDSS_MDP_OP_BWC_EN BIT(0)
+#define MDSS_MDP_OP_BWC_LOSSLESS (0 << 1)
+#define MDSS_MDP_OP_BWC_Q_HIGH (1 << 1)
+#define MDSS_MDP_OP_BWC_Q_MED (2 << 1)
+
+#define MDSS_MDP_REG_SSPP_SRC_CONSTANT_COLOR 0x03C
+#define MDSS_MDP_REG_SSPP_FETCH_CONFIG 0x048
+#define MDSS_MDP_REG_SSPP_VC1_RANGE 0x04C
+
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC0_ADDR 0x0A4
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC1_ADDR 0x0A8
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC2_ADDR 0x0AC
+#define MDSS_MDP_REG_SSPP_CURRENT_SRC3_ADDR 0x0B0
+#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C03 0x0B4
+#define MDSS_MDP_REG_SSPP_LINE_SKIP_STEP_C12 0x0B8
+
+#define MDSS_MDP_REG_VIG_OP_MODE 0x200
+#define MDSS_MDP_REG_VIG_QSEED2_CONFIG 0x204
+#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPX 0x210
+#define MDSS_MDP_REG_VIG_QSEED2_C03_PHASESTEPY 0x214
+#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX 0x218
+#define MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY 0x21C
+#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEX 0x220
+#define MDSS_MDP_REG_VIG_QSEED2_C03_INIT_PHASEY 0x224
+#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEX 0x228
+#define MDSS_MDP_REG_VIG_QSEED2_C12_INIT_PHASEY 0x22C
+
+#define MDSS_MDP_REG_SCALE_CONFIG 0x204
+#define MDSS_MDP_REG_SCALE_PHASE_STEP_X 0x210
+#define MDSS_MDP_REG_SCALE_PHASE_STEP_Y 0x214
+#define MDSS_MDP_REG_SCALE_INIT_PHASE_X 0x220
+#define MDSS_MDP_REG_SCALE_INIT_PHASE_Y 0x224
+
+#define MDSS_MDP_REG_VIG_CSC_0_BASE 0x280
+#define MDSS_MDP_REG_VIG_CSC_1_BASE 0x320
+
+#define MDSS_MDP_SCALE_FILTER_NEAREST 0x0
+#define MDSS_MDP_SCALE_FILTER_BIL 0x1
+#define MDSS_MDP_SCALE_FILTER_PCMN 0x2
+#define MDSS_MDP_SCALE_FILTER_CA 0x3
+#define MDSS_MDP_SCALEY_EN BIT(1)
+#define MDSS_MDP_SCALEX_EN BIT(0)
+
+#define MDSS_MDP_NUM_REG_MIXERS 3
+#define MDSS_MDP_NUM_WB_MIXERS 2
+
+enum mdss_mdp_mixer_index {
+ MDSS_MDP_LAYERMIXER0,
+ MDSS_MDP_LAYERMIXER1,
+ MDSS_MDP_LAYERMIXER2,
+ MDSS_MDP_LAYERMIXER3,
+ MDSS_MDP_LAYERMIXER4,
+ MDSS_MDP_MAX_LAYERMIXER
+};
+
+enum mdss_mdp_stage_index {
+ MDSS_MDP_STAGE_UNUSED,
+ MDSS_MDP_STAGE_BASE,
+ MDSS_MDP_STAGE_0,
+ MDSS_MDP_STAGE_1,
+ MDSS_MDP_STAGE_2,
+ MDSS_MDP_STAGE_3,
+ MDSS_MDP_MAX_STAGE
+};
+
+enum mdss_mdp_blend_index {
+ MDSS_MDP_BLEND_STAGE0,
+ MDSS_MDP_BLEND_STAGE1,
+ MDSS_MDP_BLEND_STAGE2,
+ MDSS_MDP_BLEND_STAGE3,
+ MDSS_MDP_MAX_BLEND_STAGE,
+};
+
+#define MDSS_MDP_REG_LM_OFFSET(lm) (0x03200 + ((lm) * 0x400))
+
+#define MDSS_MDP_REG_LM_OP_MODE 0x000
+#define MDSS_MDP_REG_LM_OUT_SIZE 0x004
+#define MDSS_MDP_REG_LM_BORDER_COLOR_0 0x008
+#define MDSS_MDP_REG_LM_BORDER_COLOR_1 0x010
+
+#define MDSS_MDP_REG_LM_BLEND_OFFSET(stage) (0x20 + ((stage) * 0x30))
+#define MDSS_MDP_REG_LM_BLEND_OP 0x00
+#define MDSS_MDP_REG_LM_BLEND_FG_ALPHA 0x04
+#define MDSS_MDP_REG_LM_BLEND_BG_ALPHA 0x08
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW0 0x0C
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_LOW1 0x10
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH0 0x14
+#define MDSS_MDP_REG_LM_BLEND_FG_TRANSP_HIGH1 0x18
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW0 0x1C
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_LOW1 0x20
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH0 0x24
+#define MDSS_MDP_REG_LM_BLEND_BG_TRANSP_HIGH1 0x28
+
+#define MDSS_MDP_REG_LM_CURSOR_IMG_SIZE 0xE0
+#define MDSS_MDP_REG_LM_CURSOR_SIZE 0xE4
+#define MDSS_MDP_REG_LM_CURSOR_XY 0xE8
+#define MDSS_MDP_REG_LM_CURSOR_STRIDE 0xDC
+#define MDSS_MDP_REG_LM_CURSOR_FORMAT 0xEC
+#define MDSS_MDP_REG_LM_CURSOR_BASE_ADDR 0xF0
+#define MDSS_MDP_REG_LM_CURSOR_START_XY 0xF4
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG 0xF8
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM 0xFC
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0 0x100
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1 0x104
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0 0x108
+#define MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1 0x10C
+
+#define MDSS_MDP_LM_BORDER_COLOR (1 << 24)
+#define MDSS_MDP_LM_CURSOR_OUT (1 << 25)
+#define MDSS_MDP_BLEND_FG_ALPHA_FG_CONST (0 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_BG_CONST (1 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_FG_PIXEL (2 << 0)
+#define MDSS_MDP_BLEND_FG_ALPHA_BG_PIXEL (3 << 0)
+#define MDSS_MDP_BLEND_FG_INV_ALPHA (1 << 2)
+#define MDSS_MDP_BLEND_FG_MOD_ALPHA (1 << 3)
+#define MDSS_MDP_BLEND_FG_INV_MOD_ALPHA (1 << 4)
+#define MDSS_MDP_BLEND_FG_TRANSP_EN (1 << 5)
+#define MDSS_MDP_BLEND_BG_ALPHA_FG_CONST (0 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_BG_CONST (1 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_FG_PIXEL (2 << 8)
+#define MDSS_MDP_BLEND_BG_ALPHA_BG_PIXEL (3 << 8)
+#define MDSS_MDP_BLEND_BG_INV_ALPHA (1 << 10)
+#define MDSS_MDP_BLEND_BG_MOD_ALPHA (1 << 11)
+#define MDSS_MDP_BLEND_BG_INV_MOD_ALPHA (1 << 12)
+#define MDSS_MDP_BLEND_BG_TRANSP_EN (1 << 13)
+
+enum mdss_mdp_writeback_index {
+ MDSS_MDP_WRITEBACK0,
+ MDSS_MDP_WRITEBACK1,
+ MDSS_MDP_WRITEBACK2,
+ MDSS_MDP_WRITEBACK3,
+ MDSS_MDP_WRITEBACK4,
+ MDSS_MDP_MAX_WRITEBACK
+};
+
+#define MDSS_MDP_REG_WB_OFFSET(wb) (0x11100 + ((wb) * 0x2000))
+
+#define MDSS_MDP_REG_WB_DST_FORMAT 0x000
+#define MDSS_MDP_REG_WB_DST_OP_MODE 0x004
+#define MDSS_MDP_REG_WB_DST_PACK_PATTERN 0x008
+#define MDSS_MDP_REG_WB_DST0_ADDR 0x00C
+#define MDSS_MDP_REG_WB_DST1_ADDR 0x010
+#define MDSS_MDP_REG_WB_DST2_ADDR 0x014
+#define MDSS_MDP_REG_WB_DST3_ADDR 0x018
+#define MDSS_MDP_REG_WB_DST_YSTRIDE0 0x01C
+#define MDSS_MDP_REG_WB_DST_YSTRIDE1 0x020
+#define MDSS_MDP_REG_WB_DST_YSTRIDE1 0x020
+#define MDSS_MDP_REG_WB_DST_DITHER_BITDEPTH 0x024
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW0 0x030
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW1 0x034
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW2 0x038
+#define MDSS_MDP_REG_WB_DST_MATRIX_ROW3 0x03C
+#define MDSS_MDP_REG_WB_ROTATION_DNSCALER 0x050
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C03 0x060
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_X_C12 0x064
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C03 0x068
+#define MDSS_MDP_REG_WB_N16_INIT_PHASE_Y_C12 0x06C
+#define MDSS_MDP_REG_WB_OUT_SIZE 0x074
+#define MDSS_MDP_REG_WB_ALPHA_X_VALUE 0x078
+#define MDSS_MDP_REG_WB_CSC_BASE 0x260
+
+enum mdss_mdp_dspp_index {
+ MDSS_MDP_DSPP0,
+ MDSS_MDP_DSPP1,
+ MDSS_MDP_DSPP2,
+ MDSS_MDP_MAX_DSPP
+};
+
+enum mdss_mpd_intf_index {
+ MDSS_MDP_NO_INTF,
+ MDSS_MDP_INTF0,
+ MDSS_MDP_INTF1,
+ MDSS_MDP_INTF2,
+ MDSS_MDP_INTF3,
+ MDSS_MDP_MAX_INTF
+};
+
+#define MDSS_MDP_REG_INTF_OFFSET(intf) (0x20F00 + ((intf) * 0x200))
+
+#define MDSS_MDP_REG_INTF_TIMING_ENGINE_EN 0x000
+#define MDSS_MDP_REG_INTF_CONFIG 0x004
+#define MDSS_MDP_REG_INTF_HSYNC_CTL 0x008
+#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F0 0x00C
+#define MDSS_MDP_REG_INTF_VSYNC_PERIOD_F1 0x010
+#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F0 0x014
+#define MDSS_MDP_REG_INTF_VSYNC_PULSE_WIDTH_F1 0x018
+#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F0 0x01C
+#define MDSS_MDP_REG_INTF_DISPLAY_V_START_F1 0x020
+#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F0 0x024
+#define MDSS_MDP_REG_INTF_DISPLAY_V_END_F1 0x028
+#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F0 0x02C
+#define MDSS_MDP_REG_INTF_ACTIVE_V_START_F1 0x030
+#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F0 0x034
+#define MDSS_MDP_REG_INTF_ACTIVE_V_END_F1 0x038
+#define MDSS_MDP_REG_INTF_DISPLAY_HCTL 0x03C
+#define MDSS_MDP_REG_INTF_ACTIVE_HCTL 0x040
+#define MDSS_MDP_REG_INTF_BORDER_COLOR 0x044
+#define MDSS_MDP_REG_INTF_UNDERFLOW_COLOR 0x048
+#define MDSS_MDP_REG_INTF_HSYNC_SKEW 0x04C
+#define MDSS_MDP_REG_INTF_POLARITY_CTL 0x050
+#define MDSS_MDP_REG_INTF_TEST_CTL 0x054
+#define MDSS_MDP_REG_INTF_TP_COLOR0 0x058
+#define MDSS_MDP_REG_INTF_TP_COLOR1 0x05C
+
+#define MDSS_MDP_REG_INTF_DEFLICKER_CONFIG 0x0F0
+#define MDSS_MDP_REG_INTF_DEFLICKER_STRNG_COEFF 0x0F4
+#define MDSS_MDP_REG_INTF_DEFLICKER_WEAK_COEFF 0x0F8
+
+#define MDSS_MDP_REG_INTF_DSI_CMD_MODE_TRIGGER_EN 0x084
+#define MDSS_MDP_REG_INTF_PANEL_FORMAT 0x090
+#define MDSS_MDP_REG_INTF_TPG_ENABLE 0x100
+#define MDSS_MDP_REG_INTF_TPG_MAIN_CONTROL 0x104
+#define MDSS_MDP_REG_INTF_TPG_VIDEO_CONFIG 0x108
+#define MDSS_MDP_REG_INTF_TPG_COMPONENT_LIMITS 0x10C
+#define MDSS_MDP_REG_INTF_TPG_RECTANGLE 0x110
+#define MDSS_MDP_REG_INTF_TPG_INITIAL_VALUE 0x114
+#define MDSS_MDP_REG_INTF_TPG_BLK_WHITE_PATTERN_FRAMES 0x118
+#define MDSS_MDP_REG_INTF_TPG_RGB_MAPPING 0x11C
+
+#define MDSS_MDP_REG_INTF_FRAME_LINE_COUNT_EN 0x0A8
+#define MDSS_MDP_REG_INTF_FRAME_COUNT 0x0AC
+#define MDSS_MDP_REG_INTF_LINE_COUNT 0x0B0
+
+enum mdss_mdp_pingpong_index {
+ MDSS_MDP_PINGPONG0,
+ MDSS_MDP_PINGPONG1,
+ MDSS_MDP_PINGPONG2,
+ MDSS_MDP_MAX_PINGPONG
+};
+
+#define MDSS_MDP_REG_PP_OFFSET(pp) (0x21B00 + ((pp) * 0x100))
+
+#define MDSS_MDP_REG_PP_TEAR_CHECK_EN 0x000
+#define MDSS_MDP_REG_PP_SYNC_CONFIG_VSYNC 0x004
+#define MDSS_MDP_REG_PP_SYNC_CONFIG_HEIGHT 0x008
+#define MDSS_MDP_REG_PP_SYNC_WRCOUNT 0x00C
+#define MDSS_MDP_REG_PP_VSYNC_INIT_VAL 0x010
+#define MDSS_MDP_REG_PP_INT_COUNT_VAL 0x014
+#define MDSS_MDP_REG_PP_SYNC_THRESH 0x018
+#define MDSS_MDP_REG_PP_START_POS 0x01C
+#define MDSS_MDP_REG_PP_RD_PTR_IRQ 0x020
+#define MDSS_MDP_REG_PP_WR_PTR_IRQ 0x024
+#define MDSS_MDP_REG_PP_OUT_LINE_COUNT 0x028
+#define MDSS_MDP_REG_PP_LINE_COUNT 0x02C
+#define MDSS_MDP_REG_PP_AUTOREFRESH_CONFIG 0x030
+
+#define MDSS_MDP_REG_SMP_ALLOC_W0 0x00180
+#define MDSS_MDP_REG_SMP_ALLOC_R0 0x00230
+
+#define MDSS_MDP_SMP_MMB_SIZE 4096
+#define MDSS_MDP_SMP_MMB_BLOCKS 22
+
+enum mdss_mdp_smp_client_index {
+ MDSS_MDP_SMP_CLIENT_UNUSED,
+ MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y,
+ MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CR,
+ MDSS_MDP_SMP_CLIENT_VIG0_FETCH_CB,
+ MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y,
+ MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CR,
+ MDSS_MDP_SMP_CLIENT_VIG1_FETCH_CB,
+ MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y,
+ MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CR,
+ MDSS_MDP_SMP_CLIENT_VIG2_FETCH_CB,
+ MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y,
+ MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CR,
+ MDSS_MDP_SMP_CLIENT_DMA0_FETCH_CB,
+ MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y,
+ MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CR,
+ MDSS_MDP_SMP_CLIENT_DMA1_FETCH_CB,
+ MDSS_MDP_SMP_CLIENT_RGB0_FETCH,
+ MDSS_MDP_SMP_CLIENT_RGB1_FETCH,
+ MDSS_MDP_SMP_CLIENT_RGB2_FETCH,
+};
+
+#endif /* MDSS_MDP_HWIO_H */
diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
new file mode 100644
index 0000000..99d4b4c
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_intf_writeback.c
@@ -0,0 +1,300 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#define ROT_BLK_SIZE 128
+
+enum mdss_mdp_writeback_type {
+ MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
+ MDSS_MDP_WRITEBACK_TYPE_LINE,
+ MDSS_MDP_WRITEBACK_TYPE_WFD,
+};
+
+struct mdss_mdp_writeback_ctx {
+ u32 wb_num;
+ u8 ref_cnt;
+ u8 type;
+
+ u32 intr_type;
+ u32 intf_num;
+
+ u32 opmode;
+ u32 format;
+ u16 width;
+ u16 height;
+ u8 rot90;
+
+ struct completion comp;
+ struct mdss_mdp_plane_sizes dst_planes;
+ struct mdss_mdp_data wb_data;
+};
+
+static struct mdss_mdp_writeback_ctx wb_ctx_list[MDSS_MDP_MAX_WRITEBACK] = {
+ {
+ .type = MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
+ .intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+ .intf_num = 0,
+ },
+ {
+ .type = MDSS_MDP_WRITEBACK_TYPE_ROTATOR,
+ .intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+ .intf_num = 1,
+ },
+ {
+ .type = MDSS_MDP_WRITEBACK_TYPE_LINE,
+ .intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+ .intf_num = 0,
+ },
+ {
+ .type = MDSS_MDP_WRITEBACK_TYPE_LINE,
+ .intr_type = MDSS_MDP_IRQ_WB_ROT_COMP,
+ .intf_num = 1,
+ },
+ {
+ .type = MDSS_MDP_WRITEBACK_TYPE_WFD,
+ .intr_type = MDSS_MDP_IRQ_WB_WFD,
+ .intf_num = 0,
+ },
+};
+
+static void *videomemory;
+
+static int mdss_mdp_writeback_addr_setup(struct mdss_mdp_writeback_ctx *ctx,
+ struct mdss_mdp_data *data)
+{
+ int off, ret;
+
+ if (!data)
+ return -EINVAL;
+
+ pr_debug("wb_num=%d addr=0x%x\n", ctx->wb_num, data->p[0].addr);
+
+ ret = mdss_mdp_data_check(data, &ctx->dst_planes);
+ if (ret)
+ return ret;
+
+ off = MDSS_MDP_REG_WB_OFFSET(ctx->wb_num);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST0_ADDR, data->p[0].addr);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST1_ADDR, data->p[1].addr);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST2_ADDR, data->p[2].addr);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST3_ADDR, data->p[3].addr);
+
+ return 0;
+}
+
+static int mdss_mdp_writeback_format_setup(struct mdss_mdp_writeback_ctx *ctx)
+{
+ struct mdss_mdp_format_params *fmt;
+ u32 dst_format, pattern, ystride0, ystride1, outsize, chroma_samp;
+ int off, ret;
+
+ pr_debug("wb_num=%d format=%d\n", ctx->wb_num, ctx->format);
+
+ mdss_mdp_get_plane_sizes(ctx->format, ctx->width, ctx->height,
+ &ctx->dst_planes);
+
+ fmt = mdss_mdp_get_format_params(ctx->format);
+ if (!fmt) {
+ pr_err("wb format=%d not supported\n", ctx->format);
+ return ret;
+ }
+
+ chroma_samp = fmt->chroma_sample;
+ if (ctx->rot90) {
+ if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
+ chroma_samp = MDSS_MDP_CHROMA_H1V2;
+ else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
+ chroma_samp = MDSS_MDP_CHROMA_H2V1;
+ }
+
+ dst_format = (chroma_samp << 23) |
+ (fmt->fetch_planes << 19) |
+ (fmt->unpack_align_msb << 18) |
+ (fmt->unpack_tight << 17) |
+ (fmt->unpack_count << 12) |
+ (fmt->bpp << 9) |
+ (fmt->alpha_enable << 8) |
+ (fmt->a_bit << 6) |
+ (fmt->r_bit << 4) |
+ (fmt->b_bit << 2) |
+ (fmt->g_bit << 0);
+
+ pattern = (fmt->element3 << 24) |
+ (fmt->element2 << 15) |
+ (fmt->element1 << 8) |
+ (fmt->element0 << 0);
+
+ ystride0 = (ctx->dst_planes.ystride[0]) |
+ (ctx->dst_planes.ystride[1] << 16);
+ ystride1 = (ctx->dst_planes.ystride[2]) |
+ (ctx->dst_planes.ystride[3] << 16);
+ outsize = (ctx->height << 16) | ctx->width;
+
+ off = MDSS_MDP_REG_WB_OFFSET(ctx->wb_num);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_FORMAT, dst_format);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_OP_MODE, ctx->opmode);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_PACK_PATTERN, pattern);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_YSTRIDE0, ystride0);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_DST_YSTRIDE1, ystride1);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_WB_OUT_SIZE, outsize);
+
+ return 0;
+}
+
+static int mdss_mdp_writeback_wfd_setup(struct mdss_mdp_ctl *ctl,
+ struct mdss_mdp_writeback_ctx *ctx)
+{
+ struct msm_fb_data_type *mfd;
+ struct fb_info *fbi;
+ int ret;
+ u32 plane_size;
+
+ mfd = ctl->mfd;
+ fbi = mfd->fbi;
+
+ pr_debug("setup ctl=%d\n", ctl->num);
+
+ ctx->opmode = 0;
+ ctx->format = ctl->dst_format;
+ ctx->width = fbi->var.xres;
+ ctx->height = fbi->var.yres;
+
+ plane_size = ctx->width * ctx->height * fbi->var.bits_per_pixel / 8;
+
+ videomemory = (void *) fbi->fix.smem_start + fbi->fix.smem_len -
+ plane_size;
+
+ ctx->wb_data.num_planes = 1;
+ ctx->wb_data.p[0].addr = (u32) videomemory;
+ ctx->wb_data.p[0].len = plane_size;
+
+ ret = mdss_mdp_writeback_format_setup(ctx);
+ if (ret) {
+ pr_err("format setup failed\n");
+ return ret;
+ }
+
+ ctl->flush_bits |= BIT(16); /* WB */
+
+ return 0;
+}
+
+static int mdss_mdp_writeback_stop(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_writeback_ctx *ctx;
+
+ pr_debug("stop ctl=%d\n", ctl->num);
+
+ ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+ if (ctx) {
+ ctl->priv_data = NULL;
+ ctx->ref_cnt--;
+ }
+
+ return 0;
+}
+
+static void mdss_mdp_writeback_intr_done(void *arg)
+{
+ struct mdss_mdp_writeback_ctx *ctx;
+
+ ctx = (struct mdss_mdp_writeback_ctx *) arg;
+ if (!ctx) {
+ pr_err("invalid ctx\n");
+ return;
+ }
+
+ pr_debug("intr wb_num=%d\n", ctx->wb_num);
+
+ mdss_mdp_irq_disable_nosync(ctx->intr_type, ctx->intf_num);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, true);
+
+ complete_all(&ctx->comp);
+}
+
+static int mdss_mdp_writeback_display(struct mdss_mdp_ctl *ctl, void *arg)
+{
+ struct mdss_mdp_writeback_ctx *ctx;
+ struct mdss_mdp_data *wb_data;
+ u32 flush_bits;
+ int ret;
+
+ ctx = (struct mdss_mdp_writeback_ctx *) ctl->priv_data;
+ if (!ctx)
+ return -ENODEV;
+
+ wb_data = &ctx->wb_data;
+
+ ret = mdss_mdp_writeback_addr_setup(ctx, wb_data);
+ if (ret) {
+ pr_err("writeback data setup error ctl=%d\n", ctl->num);
+ return ret;
+ }
+
+ flush_bits = BIT(16); /* WB */
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_FLUSH, flush_bits);
+
+ INIT_COMPLETION(ctx->comp);
+ mdss_mdp_set_intr_callback(ctx->intr_type, ctx->intf_num,
+ mdss_mdp_writeback_intr_done, ctx);
+ mdss_mdp_irq_enable(ctx->intr_type, ctx->intf_num);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_START, 1);
+ wmb();
+
+ pr_debug("writeback kickoff wb_num=%d\n", ctx->wb_num);
+ wait_for_completion_interruptible(&ctx->comp);
+
+ return 0;
+}
+
+int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl)
+{
+ struct mdss_mdp_writeback_ctx *ctx;
+ u32 mem_sel;
+ int ret = 0;
+
+ pr_debug("start ctl=%d\n", ctl->num);
+
+ mem_sel = (ctl->opmode & 0xF) - 1;
+ if (mem_sel < MDSS_MDP_MAX_WRITEBACK) {
+ ctx = &wb_ctx_list[mem_sel];
+ if (ctx->ref_cnt) {
+ pr_err("writeback in use %d\n", mem_sel);
+ return -EBUSY;
+ }
+ ctx->ref_cnt++;
+ } else {
+ pr_err("invalid writeback mode %d\n", mem_sel);
+ return -EINVAL;
+ }
+ ctl->priv_data = ctx;
+ ctx->wb_num = ctl->num; /* wb num should match ctl num */
+
+ init_completion(&ctx->comp);
+
+ if (ctx->type == MDSS_MDP_WRITEBACK_TYPE_WFD)
+ ret = mdss_mdp_writeback_wfd_setup(ctl, ctx);
+ else /* line mode not supported */
+ return -ENOSYS;
+
+ ctl->stop_fnc = mdss_mdp_writeback_stop;
+ ctl->display_fnc = mdss_mdp_writeback_display;
+
+ return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
new file mode 100644
index 0000000..bd4a974
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -0,0 +1,701 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+
+#define CHECK_BOUNDS(offset, size, max_size) \
+ (((size) > (max_size)) || ((offset) > ((max_size) - (size))))
+
+static int mdss_mdp_overlay_get(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req)
+{
+ struct mdss_mdp_pipe *pipe;
+
+ pipe = mdss_mdp_pipe_get_locked(req->id);
+ if (pipe == NULL) {
+ pr_err("invalid pipe ndx=%x\n", req->id);
+ return -ENODEV;
+ }
+
+ *req = pipe->req_data;
+ mdss_mdp_pipe_unlock(pipe);
+
+ return 0;
+}
+
+static int mdss_mdp_overlay_req_check(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req,
+ struct mdss_mdp_format_params *fmt)
+{
+ u32 xres, yres;
+ u32 dst_w, dst_h;
+
+ xres = mfd->fbi->var.xres;
+ yres = mfd->fbi->var.yres;
+
+ if (req->z_order >= MDSS_MDP_MAX_STAGE) {
+ pr_err("zorder %d out of range\n", req->z_order);
+ return -ERANGE;
+ }
+
+ if (req->src.width > MAX_IMG_WIDTH ||
+ req->src.height > MAX_IMG_HEIGHT ||
+ req->src_rect.w == 0 || req->src_rect.h == 0 ||
+ req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+ req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H ||
+ CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
+ CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height) ||
+ CHECK_BOUNDS(req->dst_rect.x, req->dst_rect.w, xres) ||
+ CHECK_BOUNDS(req->dst_rect.y, req->dst_rect.h, yres)) {
+ pr_err("invalid image img_w=%d img_h=%d\n",
+ req->src.width, req->src.height);
+
+ pr_err("\tsrc_rect=%d,%d,%d,%d dst_rect=%d,%d,%d,%d\n",
+ req->src_rect.x, req->src_rect.y,
+ req->src_rect.w, req->src_rect.h,
+ req->dst_rect.x, req->dst_rect.y,
+ req->dst_rect.w, req->dst_rect.h);
+ return -EINVAL;
+ }
+
+ if (req->flags & MDP_ROT_90) {
+ dst_h = req->dst_rect.w;
+ dst_w = req->dst_rect.h;
+ } else {
+ dst_w = req->dst_rect.w;
+ dst_h = req->dst_rect.h;
+ }
+
+ if ((req->src_rect.w * MAX_UPSCALE_RATIO) < dst_w) {
+ pr_err("too much upscaling Width %d->%d\n",
+ req->src_rect.w, req->dst_rect.w);
+ return -EINVAL;
+ }
+
+ if ((req->src_rect.h * MAX_UPSCALE_RATIO) < dst_h) {
+ pr_err("too much upscaling. Height %d->%d\n",
+ req->src_rect.h, req->dst_rect.h);
+ return -EINVAL;
+ }
+
+ if (req->src_rect.w > (dst_w * MAX_DOWNSCALE_RATIO)) {
+ pr_err("too much downscaling. Width %d->%d\n",
+ req->src_rect.w, req->dst_rect.w);
+ return -EINVAL;
+ }
+
+ if (req->src_rect.h > (dst_h * MAX_DOWNSCALE_RATIO)) {
+ pr_err("too much downscaling. Height %d->%d\n",
+ req->src_rect.h, req->dst_rect.h);
+ return -EINVAL;
+ }
+
+ if (fmt->is_yuv) {
+ if ((req->src_rect.x & 0x1) || (req->src_rect.y & 0x1) ||
+ (req->src_rect.w & 0x1) || (req->src_rect.h & 0x1)) {
+ pr_err("invalid odd src resolution\n");
+ return -EINVAL;
+ }
+ if ((req->dst_rect.x & 0x1) || (req->dst_rect.y & 0x1) ||
+ (req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
+ pr_err("invalid odd dst resolution\n");
+ return -EINVAL;
+ }
+
+ if (((req->src_rect.w * (MAX_UPSCALE_RATIO / 2)) < dst_w) &&
+ (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+ fmt->chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+ pr_err("too much YUV upscaling Width %d->%d\n",
+ req->src_rect.w, req->dst_rect.w);
+ return -EINVAL;
+ }
+
+ if (((req->src_rect.h * (MAX_UPSCALE_RATIO / 2)) < dst_h) &&
+ (fmt->chroma_sample == MDSS_MDP_CHROMA_420 ||
+ fmt->chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+ pr_err("too much YUV upscaling Height %d->%d\n",
+ req->src_rect.h, req->dst_rect.h);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req,
+ struct mdss_mdp_pipe **ppipe)
+{
+ struct mdss_mdp_format_params *fmt;
+ struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_mixer *mixer = NULL;
+ u32 pipe_type, mixer_mux;
+ int ret;
+
+ if (mfd == NULL || mfd->ctl == NULL)
+ return -ENODEV;
+
+ if (req->flags & MDSS_MDP_RIGHT_MIXER)
+ mixer_mux = MDSS_MDP_MIXER_MUX_RIGHT;
+ else
+ mixer_mux = MDSS_MDP_MIXER_MUX_LEFT;
+
+ pr_debug("pipe ctl=%u req id=%x mux=%d\n", mfd->ctl->num, req->id,
+ mixer_mux);
+
+ if (req->flags & MDP_ROT_90) {
+ pr_err("unsupported inline rotation\n");
+ return -ENOTSUPP;
+ }
+
+ fmt = mdss_mdp_get_format_params(req->src.format);
+ if (!fmt) {
+ pr_err("invalid pipe format %d\n", req->src.format);
+ return -EINVAL;
+ }
+
+ ret = mdss_mdp_overlay_req_check(mfd, req, fmt);
+ if (ret)
+ return ret;
+
+ pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux, req->z_order);
+ if (pipe && pipe->ndx != req->id) {
+ pr_err("stage %d taken by pnum=%d\n", req->z_order, pipe->num);
+ return -EBUSY;
+ }
+
+
+ if (req->id == MSMFB_NEW_REQUEST) {
+ mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+ if (!mixer) {
+ pr_err("unable to get mixer\n");
+ return -ENODEV;
+ }
+
+ if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+ pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+ else
+ pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
+
+ pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+
+ /* VIG pipes can also support RGB format */
+ if (!pipe && pipe_type == MDSS_MDP_PIPE_TYPE_RGB) {
+ pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
+ pipe = mdss_mdp_pipe_alloc_locked(pipe_type);
+ }
+
+ if (pipe == NULL) {
+ pr_err("error allocating pipe\n");
+ return -ENOMEM;
+ }
+
+ pipe->mixer = mixer;
+ pipe->mfd = mfd;
+ } else {
+ pipe = mdss_mdp_pipe_get_locked(req->id);
+ if (pipe == NULL) {
+ pr_err("invalid pipe ndx=%x\n", req->id);
+ return -ENODEV;
+ }
+ }
+
+ pipe->flags = req->flags;
+
+ pipe->img_width = req->src.width & 0x3fff;
+ pipe->img_height = req->src.height & 0x3fff;
+ pipe->src.x = req->src_rect.x;
+ pipe->src.y = req->src_rect.y;
+ pipe->src.w = req->src_rect.w;
+ pipe->src.h = req->src_rect.h;
+ pipe->dst.x = req->dst_rect.x;
+ pipe->dst.y = req->dst_rect.y;
+ pipe->dst.w = req->dst_rect.w;
+ pipe->dst.h = req->dst_rect.h;
+
+ pipe->src_fmt = fmt;
+
+ pipe->mixer_stage = req->z_order;
+ pipe->is_fg = req->is_fg;
+ pipe->alpha = req->alpha;
+ pipe->transp = req->transp_mask;
+
+ pipe->req_data = *req;
+
+ pipe->params_changed++;
+
+ req->id = pipe->ndx;
+
+ *ppipe = pipe;
+
+ mdss_mdp_pipe_unlock(pipe);
+
+ return ret;
+}
+
+static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
+ struct mdp_overlay *req)
+{
+ int ret;
+ struct mdss_mdp_pipe *pipe;
+
+ /* userspace zorder start with stage 0 */
+ req->z_order += MDSS_MDP_STAGE_0;
+
+ ret = mdss_mdp_overlay_pipe_setup(mfd, req, &pipe);
+
+ req->z_order -= MDSS_MDP_STAGE_0;
+
+ return ret;
+}
+
+static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
+{
+ struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_pipe *cleanup_pipes[MDSS_MDP_MAX_SSPP];
+ int i, ret = 0, clean_cnt = 0;
+ u32 pipe_ndx, unset_ndx = 0;
+
+ if (!mfd || !mfd->ctl)
+ return -ENODEV;
+
+ pr_debug("unset ndx=%x\n", ndx);
+
+ for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
+ pipe_ndx = BIT(i);
+ if (pipe_ndx & ndx) {
+ unset_ndx |= pipe_ndx;
+ pipe = mdss_mdp_pipe_get_locked(pipe_ndx);
+ if (pipe) {
+ mdss_mdp_mixer_pipe_unstage(pipe);
+ cleanup_pipes[clean_cnt++] = pipe;
+ } else {
+ pr_warn("unknown pipe ndx=%x\n", pipe_ndx);
+ }
+ }
+ }
+
+ if (clean_cnt) {
+ ret = mfd->kickoff_fnc(mfd->ctl);
+
+ for (i = 0; i < clean_cnt; i++)
+ mdss_mdp_pipe_destroy(cleanup_pipes[i]);
+ }
+
+ return ret;
+}
+
+static int mdss_mdp_overlay_play_wait(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_data *req)
+{
+ int ret;
+
+ if (!mfd || !mfd->ctl)
+ return -ENODEV;
+
+ ret = mfd->kickoff_fnc(mfd->ctl);
+ if (!ret)
+ pr_err("error displaying\n");
+
+ return ret;
+}
+
+static int mdss_mdp_overlay_queue(struct msmfb_overlay_data *req,
+ struct mdss_mdp_data *src_data)
+{
+ struct mdss_mdp_pipe *pipe;
+ struct mdss_mdp_ctl *ctl;
+ int ret;
+
+ pipe = mdss_mdp_pipe_get_locked(req->id);
+ if (pipe == NULL) {
+ pr_err("pipe ndx=%x doesn't exist\n", req->id);
+ return -ENODEV;
+ }
+
+ pr_debug("ov queue pnum=%d\n", pipe->num);
+
+ ret = mdss_mdp_pipe_queue_data(pipe, src_data);
+ ctl = pipe->mixer->ctl;
+ mdss_mdp_pipe_unlock(pipe);
+
+ if (ret == 0 && !(pipe->flags & MDP_OV_PLAY_NOWAIT))
+ ret = ctl->mfd->kickoff_fnc(ctl);
+
+
+ return ret;
+}
+
+static int mdss_mdp_overlay_play(struct msm_fb_data_type *mfd,
+ struct msmfb_overlay_data *req)
+{
+ struct mdss_mdp_data src_data;
+ int ret = 0;
+
+ if (mfd == NULL)
+ return -ENODEV;
+
+ pr_debug("play req id=%x\n", req->id);
+
+ memset(&src_data, 0, sizeof(src_data));
+ mdss_mdp_get_img(mfd->iclient, &req->data, &src_data.p[0]);
+ if (src_data.p[0].len == 0) {
+ pr_err("src data pmem error\n");
+ return -ENOMEM;
+ }
+ src_data.num_planes = 1;
+
+ ret = mdss_mdp_overlay_queue(req, &src_data);
+
+ mdss_mdp_put_img(&src_data.p[0]);
+
+ return ret;
+}
+
+static int mdss_mdp_overlay_get_fb_pipe(struct msm_fb_data_type *mfd,
+ struct mdss_mdp_pipe **ppipe,
+ int mixer_mux)
+{
+ struct mdss_mdp_pipe *pipe;
+
+ pipe = mdss_mdp_mixer_stage_pipe(mfd->ctl, mixer_mux,
+ MDSS_MDP_STAGE_BASE);
+ if (pipe == NULL) {
+ struct mdp_overlay req;
+ int ret;
+
+ memset(&req, 0, sizeof(req));
+
+ req.id = MSMFB_NEW_REQUEST;
+ req.src.format = mfd->fb_imgType;
+ req.src.height = mfd->fbi->var.yres;
+ req.src.width = mfd->fbi->var.xres;
+ if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) {
+ if (req.src.width <= MAX_MIXER_WIDTH)
+ return -ENODEV;
+
+ req.flags |= MDSS_MDP_RIGHT_MIXER;
+ req.src_rect.x = MAX_MIXER_WIDTH;
+ req.src_rect.w = req.src.width - MAX_MIXER_WIDTH;
+ } else {
+ req.src_rect.x = 0;
+ req.src_rect.w = MIN(req.src.width, MAX_MIXER_WIDTH);
+ }
+
+ req.src_rect.y = 0;
+ req.src_rect.h = req.src.height;
+ req.dst_rect.x = req.src_rect.x;
+ req.dst_rect.y = 0;
+ req.dst_rect.w = req.src_rect.w;
+ req.dst_rect.h = req.src_rect.h;
+ req.z_order = MDSS_MDP_STAGE_BASE;
+
+ pr_debug("allocating base pipe mux=%d\n", mixer_mux);
+
+ ret = mdss_mdp_overlay_pipe_setup(mfd, &req, &pipe);
+ if (ret)
+ return ret;
+
+ pr_debug("ctl=%d pnum=%d\n", mfd->ctl->num, pipe->num);
+ }
+
+ *ppipe = pipe;
+ return 0;
+}
+
+static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
+{
+ struct mdss_mdp_data data;
+ struct mdss_mdp_pipe *pipe;
+ struct fb_info *fbi;
+ u32 offset;
+ int bpp, ret;
+
+ if (!mfd)
+ return;
+
+ if (!mfd->ctl || !mfd->panel_power_on)
+ return;
+
+ fbi = mfd->fbi;
+
+ if (fbi->fix.smem_len == 0) {
+ pr_warn("fb memory not allocated\n");
+ return;
+ }
+
+ memset(&data, 0, sizeof(data));
+
+ bpp = fbi->var.bits_per_pixel / 8;
+ offset = fbi->var.xoffset * bpp +
+ fbi->var.yoffset * fbi->fix.line_length;
+
+ data.p[0].addr = fbi->fix.smem_start + offset;
+ data.p[0].len = fbi->fix.smem_len - offset;
+ data.num_planes = 1;
+
+ ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe, MDSS_MDP_MIXER_MUX_LEFT);
+ if (ret) {
+ pr_err("unable to allocate base pipe\n");
+ return;
+ }
+
+ mdss_mdp_pipe_lock(pipe);
+ ret = mdss_mdp_pipe_queue_data(pipe, &data);
+ mdss_mdp_pipe_unlock(pipe);
+ if (ret) {
+ pr_err("unable to queue data\n");
+ return;
+ }
+
+ if (fbi->var.xres > MAX_MIXER_WIDTH) {
+ ret = mdss_mdp_overlay_get_fb_pipe(mfd, &pipe,
+ MDSS_MDP_MIXER_MUX_RIGHT);
+ if (ret) {
+ pr_err("unable to allocate right base pipe\n");
+ return;
+ }
+ mdss_mdp_pipe_lock(pipe);
+ ret = mdss_mdp_pipe_queue_data(pipe, &data);
+ mdss_mdp_pipe_unlock(pipe);
+ if (ret) {
+ pr_err("unable to queue right data\n");
+ return;
+ }
+ }
+
+ if (fbi->var.activate & FB_ACTIVATE_VBL)
+ mfd->kickoff_fnc(mfd->ctl);
+}
+
+static int mdss_mdp_hw_cursor_update(struct fb_info *info,
+ struct fb_cursor *cursor)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct mdss_mdp_mixer *mixer;
+ struct fb_image *img = &cursor->image;
+ int calpha_en, transp_en, blendcfg, alpha;
+ int off, ret = 0;
+
+ mixer = mdss_mdp_mixer_get(mfd->ctl, MDSS_MDP_MIXER_MUX_DEFAULT);
+ off = MDSS_MDP_REG_LM_OFFSET(mixer->num);
+
+ if ((img->width > MDSS_MDP_CURSOR_WIDTH) ||
+ (img->height > MDSS_MDP_CURSOR_HEIGHT) ||
+ (img->depth != 32))
+ return -EINVAL;
+
+ pr_debug("mixer=%d enable=%x set=%x\n", mixer->num, cursor->enable,
+ cursor->set);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ blendcfg = MDSS_MDP_REG_READ(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG);
+
+ if (cursor->set & FB_CUR_SETPOS)
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_START_XY,
+ (img->dy << 16) | img->dx);
+
+ if (cursor->set & FB_CUR_SETIMAGE) {
+ ret = copy_from_user(mfd->cursor_buf, img->data,
+ img->width * img->height * 4);
+ if (ret)
+ return ret;
+
+ if (img->bg_color == 0xffffffff)
+ transp_en = 0;
+ else
+ transp_en = 1;
+
+ alpha = (img->fg_color & 0xff000000) >> 24;
+
+ if (alpha)
+ calpha_en = 0x0; /* xrgb */
+ else
+ calpha_en = 0x2; /* argb */
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_SIZE,
+ (img->height << 16) | img->width);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_STRIDE,
+ img->width * 4);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BASE_ADDR,
+ mfd->cursor_buf_phys);
+
+ wmb();
+
+ blendcfg &= ~0x1;
+ blendcfg |= (transp_en << 3) | (calpha_en << 1);
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
+ blendcfg);
+ if (calpha_en)
+ MDSS_MDP_REG_WRITE(off +
+ MDSS_MDP_REG_LM_CURSOR_BLEND_PARAM,
+ alpha);
+
+ if (transp_en) {
+ MDSS_MDP_REG_WRITE(off +
+ MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW0,
+ ((img->bg_color & 0xff00) << 8) |
+ (img->bg_color & 0xff));
+ MDSS_MDP_REG_WRITE(off +
+ MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_LOW1,
+ ((img->bg_color & 0xff0000) >> 16));
+ MDSS_MDP_REG_WRITE(off +
+ MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH0,
+ ((img->bg_color & 0xff00) << 8) |
+ (img->bg_color & 0xff));
+ MDSS_MDP_REG_WRITE(off +
+ MDSS_MDP_REG_LM_CURSOR_BLEND_TRANSP_HIGH1,
+ ((img->bg_color & 0xff0000) >> 16));
+ }
+ }
+
+ if (!cursor->enable != !(blendcfg & 0x1)) {
+ if (cursor->enable)
+ blendcfg |= 0x1;
+ else
+ blendcfg &= ~0x1;
+
+ MDSS_MDP_REG_WRITE(off + MDSS_MDP_REG_LM_CURSOR_BLEND_CONFIG,
+ blendcfg);
+
+ mixer->cursor_enabled = cursor->enable;
+ mixer->params_changed++;
+ }
+
+ mixer->ctl->flush_bits |= BIT(6) << mixer->num;
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return 0;
+}
+
+static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
+{
+ return mdss_mdp_display_commit(ctl, NULL);
+}
+
+static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
+ u32 cmd, void __user *argp)
+{
+ struct mdp_overlay req;
+ int val, ret = -ENOSYS;
+
+ switch (cmd) {
+ case MSMFB_OVERLAY_GET:
+ ret = copy_from_user(&req, argp, sizeof(req));
+ if (!ret) {
+ ret = mdss_mdp_overlay_get(mfd, &req);
+
+ if (!IS_ERR_VALUE(ret))
+ ret = copy_to_user(argp, &req, sizeof(req));
+ }
+
+ if (ret) {
+ pr_err("OVERLAY_GET failed (%d)\n", ret);
+ ret = -EFAULT;
+ }
+ break;
+
+ case MSMFB_OVERLAY_SET:
+ ret = copy_from_user(&req, argp, sizeof(req));
+ if (!ret) {
+ ret = mdss_mdp_overlay_set(mfd, &req);
+
+ if (!IS_ERR_VALUE(ret))
+ ret = copy_to_user(argp, &req, sizeof(req));
+ }
+ if (ret) {
+ pr_err("OVERLAY_SET failed (%d)\n", ret);
+ ret = -EFAULT;
+ }
+ break;
+
+
+ case MSMFB_OVERLAY_UNSET:
+ if (!IS_ERR_VALUE(copy_from_user(&val, argp, sizeof(val))))
+ ret = mdss_mdp_overlay_unset(mfd, val);
+ break;
+
+ case MSMFB_OVERLAY_PLAY_ENABLE:
+ if (!copy_from_user(&val, argp, sizeof(val))) {
+ mfd->overlay_play_enable = val;
+ } else {
+ pr_err("OVERLAY_PLAY_ENABLE failed (%d)\n", ret);
+ ret = -EFAULT;
+ }
+ break;
+
+ case MSMFB_OVERLAY_PLAY:
+ if (mfd->overlay_play_enable) {
+ struct msmfb_overlay_data data;
+
+ ret = copy_from_user(&data, argp, sizeof(data));
+ if (!ret) {
+ ret = mdss_mdp_overlay_play(mfd, &data);
+ if (!IS_ERR_VALUE(ret))
+ mdss_fb_update_backlight(mfd);
+ }
+
+ if (ret) {
+ pr_err("OVERLAY_PLAY failed (%d)\n", ret);
+ ret = -EFAULT;
+ }
+ } else {
+ ret = 0;
+ }
+ break;
+
+ case MSMFB_OVERLAY_PLAY_WAIT:
+ if (mfd->overlay_play_enable) {
+ struct msmfb_overlay_data data;
+
+ ret = copy_from_user(&data, argp, sizeof(data));
+ if (!ret)
+ ret = mdss_mdp_overlay_play_wait(mfd, &data);
+
+ if (ret) {
+ pr_err("OVERLAY_PLAY_WAIT failed (%d)\n", ret);
+ ret = -EFAULT;
+ }
+ } else {
+ ret = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
+{
+ mfd->on_fnc = mdss_mdp_ctl_on;
+ mfd->off_fnc = mdss_mdp_ctl_off;
+ mfd->hw_refresh = true;
+ mfd->lut_update = NULL;
+ mfd->do_histogram = NULL;
+ mfd->overlay_play_enable = true;
+ mfd->cursor_update = mdss_mdp_hw_cursor_update;
+ mfd->dma_fnc = mdss_mdp_overlay_pan_display;
+ mfd->ioctl_handler = mdss_mdp_overlay_ioctl_handler;
+ mfd->kickoff_fnc = mdss_mdp_overlay_kickoff;
+
+ return 0;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_pipe.c b/drivers/video/msm/mdss/mdss_mdp_pipe.c
new file mode 100644
index 0000000..b52cff5
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_pipe.c
@@ -0,0 +1,675 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitmap.h>
+#include <linux/errno.h>
+#include <linux/mutex.h>
+
+#include "mdss_mdp.h"
+
+#define SMP_MB_CNT (mdss_res->smp_mb_cnt)
+
+static DEFINE_MUTEX(mdss_mdp_sspp_lock);
+static DECLARE_BITMAP(mdss_mdp_smp_mmb_pool, MDSS_MDP_SMP_MMB_BLOCKS);
+
+static struct mdss_mdp_pipe mdss_mdp_pipe_list[MDSS_MDP_MAX_SSPP];
+
+static u32 mdss_mdp_smp_mmb_reserve(unsigned long *smp, size_t n)
+{
+ u32 i, mmb;
+
+ /* reserve more blocks if needed, but can't free mmb at this point */
+ for (i = bitmap_weight(smp, SMP_MB_CNT); i < n; i++) {
+ if (bitmap_full(mdss_mdp_smp_mmb_pool, SMP_MB_CNT))
+ break;
+
+ mmb = find_first_zero_bit(mdss_mdp_smp_mmb_pool, SMP_MB_CNT);
+ set_bit(mmb, smp);
+ set_bit(mmb, mdss_mdp_smp_mmb_pool);
+ }
+ return i;
+}
+
+static void mdss_mdp_smp_mmb_set(int client_id, unsigned long *smp)
+{
+ u32 mmb, off, data, s;
+
+ for_each_set_bit(mmb, smp, SMP_MB_CNT) {
+ off = (mmb / 3) * 4;
+ s = (mmb % 3) * 8;
+ data = MDSS_MDP_REG_READ(MDSS_MDP_REG_SMP_ALLOC_W0 + off);
+ data &= ~(0xFF << s);
+ data |= client_id << s;
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_W0 + off, data);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_SMP_ALLOC_R0 + off, data);
+ }
+}
+
+static void mdss_mdp_smp_mmb_free(unsigned long *smp)
+{
+ if (!bitmap_empty(smp, SMP_MB_CNT)) {
+ mdss_mdp_smp_mmb_set(MDSS_MDP_SMP_CLIENT_UNUSED, smp);
+ bitmap_andnot(mdss_mdp_smp_mmb_pool, mdss_mdp_smp_mmb_pool,
+ smp, SMP_MB_CNT);
+ bitmap_zero(smp, SMP_MB_CNT);
+ }
+}
+
+static void mdss_mdp_smp_free(struct mdss_mdp_pipe *pipe)
+{
+ mdss_mdp_smp_mmb_free(&pipe->smp[0]);
+ mdss_mdp_smp_mmb_free(&pipe->smp[1]);
+ mdss_mdp_smp_mmb_free(&pipe->smp[2]);
+}
+
+static int mdss_mdp_smp_reserve(struct mdss_mdp_pipe *pipe)
+{
+ u32 num_blks = 0, reserved = 0;
+ int i;
+
+ if ((pipe->src_planes.num_planes > 1) &&
+ (pipe->type == MDSS_MDP_PIPE_TYPE_RGB))
+ return -EINVAL;
+
+ mutex_lock(&mdss_mdp_sspp_lock);
+ for (i = 0; i < pipe->src_planes.num_planes; i++) {
+ num_blks = DIV_ROUND_UP(2 * pipe->src_planes.ystride[i],
+ mdss_res->smp_mb_size);
+
+ pr_debug("reserving %d mmb for pnum=%d plane=%d\n",
+ num_blks, pipe->num, i);
+ reserved = mdss_mdp_smp_mmb_reserve(&pipe->smp[i], num_blks);
+
+ if (reserved < num_blks)
+ break;
+ }
+
+ if (reserved < num_blks) {
+ pr_err("insufficient MMB blocks\n");
+ mdss_mdp_smp_free(pipe);
+ return -ENOMEM;
+ }
+ mutex_unlock(&mdss_mdp_sspp_lock);
+
+ return 0;
+}
+
+static int mdss_mdp_smp_alloc(struct mdss_mdp_pipe *pipe)
+{
+ u32 client_id;
+ int i;
+
+ switch (pipe->num) {
+ case MDSS_MDP_SSPP_VIG0:
+ client_id = MDSS_MDP_SMP_CLIENT_VIG0_FETCH_Y;
+ break;
+ case MDSS_MDP_SSPP_VIG1:
+ client_id = MDSS_MDP_SMP_CLIENT_VIG1_FETCH_Y;
+ break;
+ case MDSS_MDP_SSPP_VIG2:
+ client_id = MDSS_MDP_SMP_CLIENT_VIG2_FETCH_Y;
+ break;
+ case MDSS_MDP_SSPP_RGB0:
+ client_id = MDSS_MDP_SMP_CLIENT_RGB0_FETCH;
+ break;
+ case MDSS_MDP_SSPP_RGB1:
+ client_id = MDSS_MDP_SMP_CLIENT_RGB1_FETCH;
+ break;
+ case MDSS_MDP_SSPP_RGB2:
+ client_id = MDSS_MDP_SMP_CLIENT_RGB2_FETCH;
+ break;
+ case MDSS_MDP_SSPP_DMA0:
+ client_id = MDSS_MDP_SMP_CLIENT_DMA0_FETCH_Y;
+ break;
+ case MDSS_MDP_SSPP_DMA1:
+ client_id = MDSS_MDP_SMP_CLIENT_DMA1_FETCH_Y;
+ break;
+ default:
+ pr_err("no valid smp client for pnum=%d\n", pipe->num);
+ return -EINVAL;
+ }
+
+ mutex_lock(&mdss_mdp_sspp_lock);
+ for (i = 0; i < pipe->src_planes.num_planes; i++)
+ mdss_mdp_smp_mmb_set(client_id + i, &pipe->smp[i]);
+ mutex_unlock(&mdss_mdp_sspp_lock);
+ return 0;
+}
+
+void mdss_mdp_pipe_unlock(struct mdss_mdp_pipe *pipe)
+{
+ atomic_dec(&pipe->ref_cnt);
+ mutex_unlock(&pipe->lock);
+}
+
+int mdss_mdp_pipe_lock(struct mdss_mdp_pipe *pipe)
+{
+ if (atomic_inc_not_zero(&pipe->ref_cnt)) {
+ if (mutex_lock_interruptible(&pipe->lock)) {
+ atomic_dec(&pipe->ref_cnt);
+ return -EINTR;
+ }
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static struct mdss_mdp_pipe *mdss_mdp_pipe_init(u32 pnum)
+{
+ struct mdss_mdp_pipe *pipe = NULL;
+
+ if (atomic_read(&mdss_mdp_pipe_list[pnum].ref_cnt) == 0) {
+ pipe = &mdss_mdp_pipe_list[pnum];
+ memset(pipe, 0, sizeof(*pipe));
+
+ mutex_init(&pipe->lock);
+ atomic_set(&pipe->ref_cnt, 1);
+
+ if (mdss_mdp_pipe_lock(pipe) == 0) {
+ pipe->num = pnum;
+ pipe->type = mdss_res->pipe_type_map[pnum];
+ pipe->ndx = BIT(pnum);
+
+ pr_debug("ndx=%x pnum=%d\n", pipe->ndx, pipe->num);
+ } else {
+ atomic_set(&pipe->ref_cnt, 0);
+ pipe = NULL;
+ }
+ }
+ return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_pnum(u32 pnum)
+{
+ struct mdss_mdp_pipe *pipe = NULL;
+ mutex_lock(&mdss_mdp_sspp_lock);
+ if (mdss_res->pipe_type_map[pnum] != MDSS_MDP_PIPE_TYPE_UNUSED)
+ pipe = mdss_mdp_pipe_init(pnum);
+ mutex_unlock(&mdss_mdp_sspp_lock);
+ return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_alloc_locked(u32 type)
+{
+ struct mdss_mdp_pipe *pipe = NULL;
+ int pnum;
+
+ mutex_lock(&mdss_mdp_sspp_lock);
+ for (pnum = 0; pnum < MDSS_MDP_MAX_SSPP; pnum++) {
+ if (type == mdss_res->pipe_type_map[pnum]) {
+ pipe = mdss_mdp_pipe_init(pnum);
+ if (pipe)
+ break;
+ }
+ }
+ mutex_unlock(&mdss_mdp_sspp_lock);
+
+ return pipe;
+}
+
+struct mdss_mdp_pipe *mdss_mdp_pipe_get_locked(u32 ndx)
+{
+ struct mdss_mdp_pipe *pipe = NULL;
+ int i;
+
+ if (!ndx)
+ return NULL;
+
+ mutex_lock(&mdss_mdp_sspp_lock);
+ for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
+ pipe = &mdss_mdp_pipe_list[i];
+ if (ndx == pipe->ndx)
+ break;
+ }
+ mutex_unlock(&mdss_mdp_sspp_lock);
+
+ if (i == MDSS_MDP_MAX_SSPP)
+ return NULL;
+
+ if (mdss_mdp_pipe_lock(pipe))
+ return NULL;
+
+ if (pipe->ndx != ndx) {
+ mdss_mdp_pipe_unlock(pipe);
+ pipe = NULL;
+ }
+
+ return pipe;
+}
+
+
+static void mdss_mdp_pipe_free(struct mdss_mdp_pipe *pipe)
+{
+ mdss_mdp_smp_free(pipe);
+ pipe->ndx = 0;
+ atomic_dec(&pipe->ref_cnt);
+ mdss_mdp_pipe_unlock(pipe);
+}
+
+int mdss_mdp_pipe_destroy(struct mdss_mdp_pipe *pipe)
+{
+ pr_debug("ndx=%x pnum=%d ref_cnt=%d\n", pipe->ndx, pipe->num,
+ atomic_read(&pipe->ref_cnt));
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mutex_lock(&mdss_mdp_sspp_lock);
+ mdss_mdp_pipe_free(pipe);
+ mutex_unlock(&mdss_mdp_sspp_lock);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return 0;
+}
+
+int mdss_mdp_pipe_release_all(struct msm_fb_data_type *mfd)
+{
+ struct mdss_mdp_pipe *pipe;
+ int i;
+
+ if (!mfd)
+ return -ENODEV;
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+ mutex_lock(&mdss_mdp_sspp_lock);
+ for (i = 0; i < MDSS_MDP_MAX_SSPP; i++) {
+ pipe = &mdss_mdp_pipe_list[i];
+ if (atomic_read(&pipe->ref_cnt) && pipe->mfd == mfd) {
+ pr_debug("release pnum=%d\n", pipe->num);
+ if (mdss_mdp_pipe_lock(pipe) == 0) {
+ mdss_mdp_mixer_pipe_unstage(pipe);
+ mdss_mdp_pipe_free(pipe);
+ } else {
+ pr_err("unable to lock pipe=%d for release",
+ pipe->num);
+ }
+ }
+ }
+ mutex_unlock(&mdss_mdp_sspp_lock);
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return 0;
+}
+
+static inline void mdss_mdp_pipe_write(struct mdss_mdp_pipe *pipe,
+ u32 reg, u32 val)
+{
+ int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
+ MDSS_MDP_REG_WRITE(offset + reg, val);
+}
+
+static inline u32 mdss_mdp_pipe_read(struct mdss_mdp_pipe *pipe, u32 reg)
+{
+ int offset = MDSS_MDP_REG_SSPP_OFFSET(pipe->num);
+ return MDSS_MDP_REG_READ(offset + reg);
+}
+
+static int mdss_mdp_leading_zero(u32 num)
+{
+ u32 bit = 0x80000000;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if (bit & num)
+ return i;
+ bit >>= 1;
+ }
+
+ return i;
+}
+
+static u32 mdss_mdp_scale_phase_step(int f_num, u32 src, u32 dst)
+{
+ u32 val, s;
+ int n;
+
+ n = mdss_mdp_leading_zero(src);
+ if (n > f_num)
+ n = f_num;
+ s = src << n; /* maximum to reduce lose of resolution */
+ val = s / dst;
+ if (n < f_num) {
+ n = f_num - n;
+ val <<= n;
+ val |= ((s % dst) << n) / dst;
+ }
+
+ return val;
+}
+
+static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe)
+{
+ u32 scale_config = 0;
+ u32 phasex_step = 0, phasey_step = 0;
+ u32 chroma_sample;
+
+ if (pipe->type == MDSS_MDP_PIPE_TYPE_DMA) {
+ if (!(pipe->flags & MDP_ROT_90) && (pipe->dst.h != pipe->src.h
+ || pipe->dst.w != pipe->src.w))
+ return -EINVAL; /* no scaling supported on dma pipes */
+ else
+ return 0;
+ }
+
+ chroma_sample = pipe->src_fmt->chroma_sample;
+
+ if ((pipe->src.h != pipe->dst.h) ||
+ (chroma_sample == MDSS_MDP_CHROMA_420) ||
+ (chroma_sample == MDSS_MDP_CHROMA_H1V2)) {
+ pr_debug("scale y - src_h=%d dst_h=%d\n",
+ pipe->src.h, pipe->dst.h);
+
+ if ((pipe->src.h / MAX_DOWNSCALE_RATIO) > pipe->dst.h) {
+ pr_err("too much downscaling height=%d->%d",
+ pipe->src.h, pipe->dst.h);
+ return -EINVAL;
+ }
+
+ scale_config |= MDSS_MDP_SCALEY_EN;
+
+ if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+ u32 chr_dst_h = pipe->dst.h;
+ if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+ (chroma_sample == MDSS_MDP_CHROMA_H1V2))
+ chr_dst_h *= 2; /* 2x upsample chroma */
+
+ if (pipe->src.h <= pipe->dst.h)
+ scale_config |= /* G/Y, A */
+ (MDSS_MDP_SCALE_FILTER_BIL << 10) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+ else
+ scale_config |= /* G/Y, A */
+ (MDSS_MDP_SCALE_FILTER_PCMN << 10) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+
+ if (pipe->src.h <= chr_dst_h)
+ scale_config |= /* CrCb */
+ (MDSS_MDP_SCALE_FILTER_BIL << 14);
+ else
+ scale_config |= /* CrCb */
+ (MDSS_MDP_SCALE_FILTER_PCMN << 14);
+
+ phasey_step = mdss_mdp_scale_phase_step(
+ PHASE_STEP_SHIFT, pipe->src.h, chr_dst_h);
+
+ mdss_mdp_pipe_write(pipe,
+ MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPY,
+ phasey_step);
+ } else {
+ if (pipe->src.h <= pipe->dst.h)
+ scale_config |= /* RGB, A */
+ (MDSS_MDP_SCALE_FILTER_BIL << 10) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+ else
+ scale_config |= /* RGB, A */
+ (MDSS_MDP_SCALE_FILTER_PCMN << 10) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 18);
+ }
+
+ phasey_step = mdss_mdp_scale_phase_step(
+ PHASE_STEP_SHIFT, pipe->src.h, pipe->dst.h);
+ }
+
+ if ((pipe->src.w != pipe->dst.w) ||
+ (chroma_sample == MDSS_MDP_CHROMA_420) ||
+ (chroma_sample == MDSS_MDP_CHROMA_H2V1)) {
+ pr_debug("scale x - src_w=%d dst_w=%d\n",
+ pipe->src.w, pipe->dst.w);
+
+ if ((pipe->src.w / MAX_DOWNSCALE_RATIO) > pipe->dst.w) {
+ pr_err("too much downscaling width=%d->%d",
+ pipe->src.w, pipe->dst.w);
+ return -EINVAL;
+ }
+
+ scale_config |= MDSS_MDP_SCALEX_EN;
+
+ if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG) {
+ u32 chr_dst_w = pipe->dst.w;
+
+ if ((chroma_sample == MDSS_MDP_CHROMA_420) ||
+ (chroma_sample == MDSS_MDP_CHROMA_H2V1))
+ chr_dst_w *= 2; /* 2x upsample chroma */
+
+ if (pipe->src.w <= pipe->dst.w)
+ scale_config |= /* G/Y, A */
+ (MDSS_MDP_SCALE_FILTER_BIL << 8) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+ else
+ scale_config |= /* G/Y, A */
+ (MDSS_MDP_SCALE_FILTER_PCMN << 8) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+
+ if (pipe->src.w <= chr_dst_w)
+ scale_config |= /* CrCb */
+ (MDSS_MDP_SCALE_FILTER_BIL << 12);
+ else
+ scale_config |= /* CrCb */
+ (MDSS_MDP_SCALE_FILTER_PCMN << 12);
+
+ phasex_step = mdss_mdp_scale_phase_step(
+ PHASE_STEP_SHIFT, pipe->src.w, chr_dst_w);
+ mdss_mdp_pipe_write(pipe,
+ MDSS_MDP_REG_VIG_QSEED2_C12_PHASESTEPX,
+ phasex_step);
+ } else {
+ if (pipe->src.w <= pipe->dst.w)
+ scale_config |= /* RGB, A */
+ (MDSS_MDP_SCALE_FILTER_BIL << 8) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+ else
+ scale_config |= /* RGB, A */
+ (MDSS_MDP_SCALE_FILTER_PCMN << 8) |
+ (MDSS_MDP_SCALE_FILTER_NEAREST << 16);
+ }
+
+ phasex_step = mdss_mdp_scale_phase_step(
+ PHASE_STEP_SHIFT, pipe->src.w, pipe->dst.w);
+ }
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_CONFIG, scale_config);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_X, phasex_step);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SCALE_PHASE_STEP_Y, phasey_step);
+ return 0;
+}
+
+static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe)
+{
+ u32 img_size, src_size, src_xy, dst_size, dst_xy, ystride0, ystride1;
+
+ pr_debug("pnum=%d wh=%dx%d src={%d,%d,%d,%d} dst={%d,%d,%d,%d}\n",
+ pipe->num, pipe->img_width, pipe->img_height,
+ pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h,
+ pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h);
+
+ if (mdss_mdp_scale_setup(pipe))
+ return -EINVAL;
+
+ mdss_mdp_get_plane_sizes(pipe->src_fmt->format, pipe->img_width,
+ pipe->img_height, &pipe->src_planes);
+
+ img_size = (pipe->img_height << 16) | pipe->img_width;
+ src_size = (pipe->src.h << 16) | pipe->src.w;
+ src_xy = (pipe->src.y << 16) | pipe->src.x;
+ dst_size = (pipe->dst.h << 16) | pipe->dst.w;
+ dst_xy = (pipe->dst.y << 16) | pipe->dst.x;
+ ystride0 = (pipe->src_planes.ystride[0]) |
+ (pipe->src_planes.ystride[1] << 16);
+ ystride1 = (pipe->src_planes.ystride[2]) |
+ (pipe->src_planes.ystride[3] << 16);
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_IMG_SIZE, img_size);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_SIZE, src_size);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_XY, src_xy);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_SIZE, dst_size);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_OUT_XY, dst_xy);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE0, ystride0);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_YSTRIDE1, ystride1);
+
+ return 0;
+}
+
+static int mdss_mdp_format_setup(struct mdss_mdp_pipe *pipe)
+{
+ struct mdss_mdp_format_params *fmt;
+ u32 rot90, opmode, chroma_samp;
+
+ fmt = pipe->src_fmt;
+
+ opmode = pipe->bwc_mode;
+ if (pipe->flags & MDP_FLIP_LR)
+ opmode |= MDSS_MDP_OP_FLIP_LR;
+ if (pipe->flags & MDP_FLIP_UD)
+ opmode |= MDSS_MDP_OP_FLIP_UD;
+
+ pr_debug("pnum=%d format=%d opmode=%x\n", pipe->num, fmt->format,
+ opmode);
+
+ rot90 = !!(pipe->flags & MDP_SOURCE_ROTATED_90);
+
+ chroma_samp = fmt->chroma_sample;
+ if (rot90) {
+ if (chroma_samp == MDSS_MDP_CHROMA_H2V1)
+ chroma_samp = MDSS_MDP_CHROMA_H1V2;
+ else if (chroma_samp == MDSS_MDP_CHROMA_H1V2)
+ chroma_samp = MDSS_MDP_CHROMA_H2V1;
+ }
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_FORMAT,
+ (chroma_samp << 23) |
+ (fmt->fetch_planes << 19) |
+ (fmt->unpack_align_msb << 18) |
+ (fmt->unpack_tight << 17) |
+ (fmt->unpack_count << 12) |
+ (rot90 << 11) |
+ (fmt->bpp << 9) |
+ (fmt->alpha_enable << 8) |
+ (fmt->a_bit << 6) |
+ (fmt->r_bit << 4) |
+ (fmt->b_bit << 2) |
+ (fmt->g_bit << 0));
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_UNPACK_PATTERN,
+ (fmt->element3 << 24) |
+ (fmt->element2 << 16) |
+ (fmt->element1 << 8) |
+ (fmt->element0 << 0));
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC_OP_MODE, opmode);
+
+ return 0;
+}
+
+static int mdss_mdp_vig_setup(struct mdss_mdp_pipe *pipe)
+{
+ u32 opmode = 0;
+
+ pr_debug("pnum=%x\n", pipe->num);
+
+ if (pipe->src_fmt->is_yuv)
+ opmode |= (0 << 19) | /* DST_DATA=RGB */
+ (1 << 18) | /* SRC_DATA=YCBCR */
+ (1 << 17); /* CSC_1_EN */
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_VIG_OP_MODE, opmode);
+
+ return 0;
+}
+
+static int mdss_mdp_src_addr_setup(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_data *data)
+{
+ int ret;
+
+ pr_debug("pnum=%d\n", pipe->num);
+
+ if (pipe->type != MDSS_MDP_PIPE_TYPE_DMA)
+ data->bwc_enabled = pipe->bwc_mode;
+
+ ret = mdss_mdp_data_check(data, &pipe->src_planes);
+ if (ret)
+ return ret;
+
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC0_ADDR, data->p[0].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC1_ADDR, data->p[1].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC2_ADDR, data->p[2].addr);
+ mdss_mdp_pipe_write(pipe, MDSS_MDP_REG_SSPP_SRC3_ADDR, data->p[3].addr);
+
+ return 0;
+}
+
+int mdss_mdp_pipe_queue_data(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_data *src_data)
+{
+ int ret = 0;
+ u32 params_changed;
+
+ if (!pipe) {
+ pr_err("pipe not setup properly for queue\n");
+ return -ENODEV;
+ }
+
+ if (!pipe->mixer) {
+ pr_err("pipe mixer not setup properly for queue\n");
+ return -ENODEV;
+ }
+
+ pr_debug("pnum=%x mixer=%d\n", pipe->num, pipe->mixer->num);
+
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+
+ params_changed = pipe->params_changed;
+ if (params_changed) {
+ pipe->params_changed = 0;
+
+ ret = mdss_mdp_image_setup(pipe);
+ if (ret) {
+ pr_err("image setup error for pnum=%d\n", pipe->num);
+ goto done;
+ }
+
+ ret = mdss_mdp_format_setup(pipe);
+ if (ret) {
+ pr_err("format %d setup error pnum=%d\n",
+ pipe->src_fmt->format, pipe->num);
+ goto done;
+ }
+
+ if (pipe->type == MDSS_MDP_PIPE_TYPE_VIG)
+ mdss_mdp_vig_setup(pipe);
+
+ ret = mdss_mdp_smp_reserve(pipe);
+ if (ret) {
+ pr_err("unable to reserve smp for pnum=%d\n",
+ pipe->num);
+ goto done;
+ }
+
+ mdss_mdp_smp_alloc(pipe);
+ }
+
+ ret = mdss_mdp_src_addr_setup(pipe, src_data);
+ if (ret) {
+ pr_err("addr setup error for pnum=%d\n", pipe->num);
+ goto done;
+ }
+
+ mdss_mdp_mixer_pipe_update(pipe, params_changed);
+
+ pipe->play_cnt++;
+
+done:
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+ return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
new file mode 100644
index 0000000..25c9ac4
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -0,0 +1,349 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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.
+ *
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/android_pmem.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/file.h>
+#include <linux/ion.h>
+#include <linux/msm_kgsl.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "mdss_fb.h"
+#include "mdss_mdp.h"
+#include "mdss_mdp_formats.h"
+
+enum {
+ MDP_INTR_VSYNC_INTF_0,
+ MDP_INTR_VSYNC_INTF_1,
+ MDP_INTR_VSYNC_INTF_2,
+ MDP_INTR_VSYNC_INTF_3,
+ MDP_INTR_PING_PONG_0,
+ MDP_INTR_PING_PONG_1,
+ MDP_INTR_PING_PONG_2,
+ MDP_INTR_WB_0,
+ MDP_INTR_WB_1,
+ MDP_INTR_WB_2,
+ MDP_INTR_MAX,
+};
+
+struct intr_callback {
+ void (*func)(void *);
+ void *arg;
+};
+
+struct intr_callback mdp_intr_cb[MDP_INTR_MAX];
+static DEFINE_SPINLOCK(mdss_mdp_intr_lock);
+
+static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num)
+{
+ int index = -1;
+ switch (intr_type) {
+ case MDSS_MDP_IRQ_INTF_VSYNC:
+ index = MDP_INTR_VSYNC_INTF_0 + intf_num;
+ break;
+ case MDSS_MDP_IRQ_PING_PONG_COMP:
+ index = MDP_INTR_PING_PONG_0 + intf_num;
+ break;
+ case MDSS_MDP_IRQ_WB_ROT_COMP:
+ index = MDP_INTR_WB_0 + intf_num;
+ break;
+ case MDSS_MDP_IRQ_WB_WFD:
+ index = MDP_INTR_WB_2 + intf_num;
+ break;
+ }
+
+ return index;
+}
+
+int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
+ void (*fnc_ptr)(void *), void *arg)
+{
+ unsigned long flags;
+ int index, ret;
+
+ index = mdss_mdp_intr2index(intr_type, intf_num);
+ if (index < 0) {
+ pr_warn("invalid intr type=%u intf_num=%u\n",
+ intr_type, intf_num);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&mdss_mdp_intr_lock, flags);
+ if (!mdp_intr_cb[index].func) {
+ mdp_intr_cb[index].func = fnc_ptr;
+ mdp_intr_cb[index].arg = arg;
+ ret = 0;
+ } else {
+ ret = -EBUSY;
+ }
+ spin_unlock_irqrestore(&mdss_mdp_intr_lock, flags);
+
+ return ret;
+}
+
+static inline void mdss_mdp_intr_done(int index)
+{
+ void (*fnc)(void *);
+ void *arg;
+
+ spin_lock(&mdss_mdp_intr_lock);
+ fnc = mdp_intr_cb[index].func;
+ arg = mdp_intr_cb[index].arg;
+ if (fnc != NULL)
+ mdp_intr_cb[index].func = NULL;
+ spin_unlock(&mdss_mdp_intr_lock);
+ if (fnc)
+ fnc(arg);
+}
+
+irqreturn_t mdss_mdp_isr(int irq, void *ptr)
+{
+ u32 isr, mask;
+
+
+ isr = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_STATUS);
+ if (isr == 0)
+ goto done;
+
+ pr_devel("isr=%x\n", isr);
+
+ mask = MDSS_MDP_REG_READ(MDSS_MDP_REG_INTR_EN);
+ MDSS_MDP_REG_WRITE(MDSS_MDP_REG_INTR_CLEAR, isr);
+
+ isr &= mask;
+ if (isr == 0)
+ goto done;
+
+ if (isr & MDSS_MDP_INTR_PING_PONG_0_DONE)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_0);
+
+ if (isr & MDSS_MDP_INTR_PING_PONG_1_DONE)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_1);
+
+ if (isr & MDSS_MDP_INTR_PING_PONG_2_DONE)
+ mdss_mdp_intr_done(MDP_INTR_PING_PONG_2);
+
+ if (isr & MDSS_MDP_INTR_INTF_0_VSYNC)
+ mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0);
+
+ if (isr & MDSS_MDP_INTR_INTF_1_VSYNC)
+ mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_1);
+
+ if (isr & MDSS_MDP_INTR_INTF_2_VSYNC)
+ mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_2);
+
+ if (isr & MDSS_MDP_INTR_INTF_3_VSYNC)
+ mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_3);
+
+ if (isr & MDSS_MDP_INTR_WB_0_DONE)
+ mdss_mdp_intr_done(MDP_INTR_WB_0);
+
+ if (isr & MDSS_MDP_INTR_WB_1_DONE)
+ mdss_mdp_intr_done(MDP_INTR_WB_1);
+
+ if (isr & MDSS_MDP_INTR_WB_2_DONE)
+ mdss_mdp_intr_done(MDP_INTR_WB_2);
+
+done:
+ return IRQ_HANDLED;
+}
+
+struct mdss_mdp_format_params *mdss_mdp_get_format_params(u32 format)
+{
+ struct mdss_mdp_format_params *fmt = NULL;
+ if (format < MDP_IMGTYPE_LIMIT) {
+ fmt = &mdss_mdp_format_map[format];
+ if (fmt->format != format)
+ fmt = NULL;
+ }
+
+ return fmt;
+}
+
+int mdss_mdp_get_plane_sizes(u32 format, u32 w, u32 h,
+ struct mdss_mdp_plane_sizes *ps)
+{
+ struct mdss_mdp_format_params *fmt;
+ int i;
+
+ if (ps == NULL)
+ return -EINVAL;
+
+ if ((w > MAX_IMG_WIDTH) || (h > MAX_IMG_HEIGHT))
+ return -ERANGE;
+
+ fmt = mdss_mdp_get_format_params(format);
+ if (!fmt)
+ return -EINVAL;
+
+ memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
+
+ if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
+ u32 bpp = fmt->bpp + 1;
+ ps->num_planes = 1;
+ ps->plane_size[0] = w * h * bpp;
+ ps->ystride[0] = w * bpp;
+ } else {
+ u8 hmap[] = { 1, 2, 1, 2 };
+ u8 vmap[] = { 1, 1, 2, 2 };
+ u8 horiz, vert;
+
+ horiz = hmap[fmt->chroma_sample];
+ vert = vmap[fmt->chroma_sample];
+
+ if (format == MDP_Y_CR_CB_GH2V2) {
+ ps->plane_size[0] = ALIGN(w, 16) * h;
+ ps->plane_size[1] = ALIGN(w / horiz, 16) * (h / vert);
+ ps->ystride[0] = ALIGN(w, 16);
+ ps->ystride[1] = ALIGN(w / horiz, 16);
+ } else {
+ ps->plane_size[0] = w * h;
+ ps->plane_size[1] = (w / horiz) * (h / vert);
+ ps->ystride[0] = w;
+ ps->ystride[1] = (w / horiz);
+ }
+
+ if (fmt->fetch_planes == MDSS_MDP_PLANE_PSEUDO_PLANAR) {
+ ps->num_planes = 2;
+ ps->plane_size[1] *= 2;
+ ps->ystride[1] *= 2;
+ } else { /* planar */
+ ps->num_planes = 3;
+ ps->plane_size[2] = ps->plane_size[1];
+ ps->ystride[2] = ps->ystride[1];
+ }
+ }
+
+ for (i = 0; i < ps->num_planes; i++)
+ ps->total_size += ps->plane_size[i];
+
+ return 0;
+}
+
+int mdss_mdp_data_check(struct mdss_mdp_data *data,
+ struct mdss_mdp_plane_sizes *ps)
+{
+ if (!ps)
+ return 0;
+
+ if (!data || data->num_planes == 0)
+ return -ENOMEM;
+
+ if (data->bwc_enabled) {
+ return -EPERM; /* not supported */
+ } else {
+ struct mdss_mdp_img_data *prev, *curr;
+ int i;
+
+ pr_debug("srcp0=%x len=%u frame_size=%u\n", data->p[0].addr,
+ data->p[0].len, ps->total_size);
+
+ for (i = 0; i < ps->num_planes; i++) {
+ curr = &data->p[i];
+ if (i >= data->num_planes) {
+ u32 psize = ps->plane_size[i-1];
+ prev = &data->p[i-1];
+ if (prev->len > psize) {
+ curr->len = prev->len - psize;
+ prev->len = psize;
+ }
+ curr->addr = prev->addr + psize;
+ }
+ if (curr->len < ps->plane_size[i]) {
+ pr_err("insufficient mem=%u p=%d len=%u\n",
+ curr->len, i, ps->plane_size[i]);
+ return -ENOMEM;
+ }
+ pr_debug("plane[%d] addr=%x len=%u\n", i,
+ curr->addr, curr->len);
+ }
+ data->num_planes = ps->num_planes;
+ }
+
+ return 0;
+}
+
+int mdss_mdp_put_img(struct mdss_mdp_img_data *data)
+{
+ /* only source may use frame buffer */
+ if (data->flags & MDP_MEMORY_ID_TYPE_FB) {
+ fput_light(data->srcp_file, data->p_need);
+ return 0;
+ }
+ if (data->srcp_file) {
+ put_pmem_file(data->srcp_file);
+ data->srcp_file = NULL;
+ return 0;
+ }
+ if (!IS_ERR_OR_NULL(data->srcp_ihdl)) {
+ ion_free(data->iclient, data->srcp_ihdl);
+ data->iclient = NULL;
+ data->srcp_ihdl = NULL;
+ return 0;
+ }
+
+ return -ENOMEM;
+}
+
+int mdss_mdp_get_img(struct ion_client *iclient, struct msmfb_data *img,
+ struct mdss_mdp_img_data *data)
+{
+ struct file *file;
+ int ret = -EINVAL;
+ int fb_num;
+ unsigned long *start, *len;
+
+ start = (unsigned long *) &data->addr;
+ len = (unsigned long *) &data->len;
+ data->flags = img->flags;
+ data->p_need = 0;
+
+ if (img->flags & MDP_BLIT_SRC_GEM) {
+ data->srcp_file = NULL;
+ ret = kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
+ start, len);
+ } else if (img->flags & MDP_MEMORY_ID_TYPE_FB) {
+ file = fget_light(img->memory_id, &data->p_need);
+ if (file && FB_MAJOR ==
+ MAJOR(file->f_dentry->d_inode->i_rdev)) {
+ data->srcp_file = file;
+ fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
+ ret = mdss_fb_get_phys_info(start, len, fb_num);
+ }
+ } else if (iclient) {
+ data->iclient = iclient;
+ data->srcp_ihdl = ion_import_fd(iclient, img->memory_id);
+ if (IS_ERR_OR_NULL(data->srcp_ihdl))
+ return PTR_ERR(data->srcp_ihdl);
+ ret = ion_phys(iclient, data->srcp_ihdl,
+ start, (size_t *) len);
+ } else {
+ unsigned long vstart;
+ ret = get_pmem_file(img->memory_id, start, &vstart, len,
+ &data->srcp_file);
+ }
+
+ if (!ret && (img->offset < data->len)) {
+ data->addr += img->offset;
+ data->len -= img->offset;
+ } else {
+ mdss_mdp_put_img(data);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
new file mode 100644
index 0000000..3fd943d
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -0,0 +1,176 @@
+/* Copyright (c) 2008-2012, Code Aurora Forum. 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 MDSS_PANEL_H
+#define MDSS_PANEL_H
+
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+/* panel id type */
+struct panel_id {
+ u16 id;
+ u16 type;
+};
+
+/* panel type list */
+#define NO_PANEL 0xffff /* No Panel */
+#define MDDI_PANEL 1 /* MDDI */
+#define EBI2_PANEL 2 /* EBI2 */
+#define LCDC_PANEL 3 /* internal LCDC type */
+#define EXT_MDDI_PANEL 4 /* Ext.MDDI */
+#define TV_PANEL 5 /* TV */
+#define HDMI_PANEL 6 /* HDMI TV */
+#define DTV_PANEL 7 /* DTV */
+#define MIPI_VIDEO_PANEL 8 /* MIPI */
+#define MIPI_CMD_PANEL 9 /* MIPI */
+#define WRITEBACK_PANEL 10 /* Wifi display */
+#define LVDS_PANEL 11 /* LVDS */
+#define EDP_PANEL 12 /* LVDS */
+
+/* panel class */
+enum {
+ DISPLAY_LCD = 0, /* lcd = ebi2/mddi */
+ DISPLAY_LCDC, /* lcdc */
+ DISPLAY_TV, /* TV Out */
+ DISPLAY_EXT_MDDI, /* External MDDI */
+ DISPLAY_WRITEBACK,
+};
+
+/* panel device locaiton */
+enum {
+ DISPLAY_1 = 0, /* attached as first device */
+ DISPLAY_2, /* attached on second device */
+ DISPLAY_3, /* attached on third writeback device */
+ MAX_PHYS_TARGET_NUM,
+};
+
+/* panel info type */
+struct lcd_panel_info {
+ u32 vsync_enable;
+ u32 refx100;
+ u32 v_back_porch;
+ u32 v_front_porch;
+ u32 v_pulse_width;
+ u32 hw_vsync_mode;
+ u32 vsync_notifier_period;
+ u32 rev;
+};
+
+struct lcdc_panel_info {
+ u32 h_back_porch;
+ u32 h_front_porch;
+ u32 h_pulse_width;
+ u32 v_back_porch;
+ u32 v_front_porch;
+ u32 v_pulse_width;
+ u32 border_clr;
+ u32 underflow_clr;
+ u32 hsync_skew;
+ /* Pad width */
+ u32 xres_pad;
+ /* Pad height */
+ u32 yres_pad;
+};
+
+struct mipi_panel_info {
+ char mode; /* video/cmd */
+ char interleave_mode;
+ char crc_check;
+ char ecc_check;
+ char dst_format; /* shared by video and command */
+ char data_lane0;
+ char data_lane1;
+ char data_lane2;
+ char data_lane3;
+ char dlane_swap; /* data lane swap */
+ char rgb_swap;
+ char b_sel;
+ char g_sel;
+ char r_sel;
+ char rx_eot_ignore;
+ char tx_eot_append;
+ char t_clk_post; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
+ char t_clk_pre; /* 0xc0, DSI_CLKOUT_TIMING_CTRL */
+ char vc; /* virtual channel */
+ struct mipi_dsi_phy_ctrl *dsi_phy_db;
+ /* video mode */
+ char pulse_mode_hsa_he;
+ char hfp_power_stop;
+ char hbp_power_stop;
+ char hsa_power_stop;
+ char eof_bllp_power_stop;
+ char bllp_power_stop;
+ char traffic_mode;
+ char frame_rate;
+ /* command mode */
+ char interleave_max;
+ char insert_dcs_cmd;
+ char wr_mem_continue;
+ char wr_mem_start;
+ char te_sel;
+ char stream; /* 0 or 1 */
+ char mdp_trigger;
+ char dma_trigger;
+ u32 dsi_pclk_rate;
+ /* The packet-size should not bet changed */
+ char no_max_pkt_size;
+ /* Clock required during LP commands */
+ char force_clk_lane_hs;
+};
+
+enum lvds_mode {
+ LVDS_SINGLE_CHANNEL_MODE,
+ LVDS_DUAL_CHANNEL_MODE,
+};
+
+struct lvds_panel_info {
+ enum lvds_mode channel_mode;
+ /* Channel swap in dual mode */
+ char channel_swap;
+};
+
+struct mdss_panel_info {
+ u32 xres;
+ u32 yres;
+ u32 bpp;
+ u32 type;
+ u32 wait_cycle;
+ u32 pdest;
+ u32 bl_max;
+ u32 bl_min;
+ u32 fb_num;
+ u32 clk_rate;
+ u32 clk_min;
+ u32 clk_max;
+ u32 frame_count;
+ u32 is_3d_panel;
+ u32 out_format;
+
+ struct lcd_panel_info lcd;
+ struct lcdc_panel_info lcdc;
+ struct mipi_panel_info mipi;
+ struct lvds_panel_info lvds;
+};
+
+struct mdss_panel_data {
+ struct mdss_panel_info panel_info;
+ void (*set_backlight) (u32 bl_level);
+
+ /* function entry chain */
+ int (*on) (struct mdss_panel_data *pdata);
+ int (*off) (struct mdss_panel_data *pdata);
+};
+
+int mdss_register_panel(struct mdss_panel_data *pdata);
+#endif /* MDSS_PANEL_H */
diff --git a/drivers/video/msm/mdss/mdss_wb.c b/drivers/video/msm/mdss/mdss_wb.c
new file mode 100644
index 0000000..3be4525
--- /dev/null
+++ b/drivers/video/msm/mdss/mdss_wb.c
@@ -0,0 +1,111 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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/init.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/msm_mdp.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/version.h>
+
+#include "mdss_panel.h"
+
+static int mdss_wb_on(struct mdss_panel_data *pdata)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static int mdss_wb_off(struct mdss_panel_data *pdata)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static int mdss_wb_parse_dt(struct platform_device *pdev,
+ struct mdss_panel_data *pdata)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 res[2], tmp;
+ int rc;
+
+ rc = of_property_read_u32_array(np, "qcom,mdss_pan_res", res, 2);
+ pdata->panel_info.xres = (!rc ? res[0] : 1280);
+ pdata->panel_info.yres = (!rc ? res[1] : 720);
+
+ rc = of_property_read_u32(np, "qcom,mdss_pan_bpp", &tmp);
+ pdata->panel_info.bpp = (!rc ? tmp : 24);
+
+ return 0;
+}
+
+static int mdss_wb_probe(struct platform_device *pdev)
+{
+ struct mdss_panel_data *pdata = NULL;
+ int rc = 0;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ rc = !mdss_wb_parse_dt(pdev, pdata);
+ if (!rc)
+ return rc;
+
+ pdata->panel_info.type = WRITEBACK_PANEL;
+ pdata->panel_info.clk_rate = 74250000;
+ pdata->panel_info.pdest = DISPLAY_3;
+ pdata->panel_info.out_format = MDP_RGB_888;
+
+ pdata->on = mdss_wb_on;
+ pdata->off = mdss_wb_off;
+ pdev->dev.platform_data = pdata;
+
+ rc = mdss_register_panel(pdata);
+ if (rc) {
+ dev_err(&pdev->dev, "unable to register writeback panel\n");
+ return rc;
+ }
+
+ return rc;
+}
+
+static const struct of_device_id mdss_wb_match[] = {
+ { .compatible = "qcom,mdss_wb", },
+ { { 0 } }
+};
+
+static struct platform_driver mdss_wb_driver = {
+ .probe = mdss_wb_probe,
+ .driver = {
+ .name = "mdss_wb",
+ .of_match_table = mdss_wb_match,
+ },
+};
+
+static int __init mdss_wb_driver_init(void)
+{
+ int rc = 0;
+ rc = platform_driver_register(&mdss_wb_driver);
+ return rc;
+}
+
+module_init(mdss_wb_driver_init);
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index 964df4e..e605aed 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -19,6 +19,8 @@
static struct dsi_buf nt35510_tx_buf;
static struct dsi_buf nt35510_rx_buf;
+static int mipi_nt35510_bl_ctrl;
+
#define NT35510_SLEEP_OFF_DELAY 150
#define NT35510_DISPLAY_ON_DELAY 150
@@ -174,6 +176,9 @@
static char cmd19[3] = {
0xB1, 0xEC, 0x00,
};
+static char cmd19_rotate[3] = {
+ 0xB1, 0xEC, 0x06,
+};
static char cmd20[4] = {
0xBC, 0x05, 0x05, 0x05,
};
@@ -246,6 +251,11 @@
{DTYPE_DCS_WRITE, 1, 0, 0, 10, sizeof(write_ram), write_ram},
};
+static struct dsi_cmd_desc nt35510_cmd_display_on_cmds_rotate[] = {
+ {DTYPE_DCS_LWRITE, 1, 0, 0, 50,
+ sizeof(cmd19_rotate), cmd19_rotate},
+};
+
static char video0[6] = {
0xF0, 0x55, 0xAA, 0x52,
0x08, 0x01,
@@ -489,6 +499,12 @@
mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
nt35510_cmd_display_on_cmds,
ARRAY_SIZE(nt35510_cmd_display_on_cmds));
+
+ if (rotate) {
+ mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
+ nt35510_cmd_display_on_cmds_rotate,
+ ARRAY_SIZE(nt35510_cmd_display_on_cmds_rotate));
+ }
}
return 0;
@@ -514,8 +530,63 @@
return 0;
}
+static ssize_t mipi_nt35510_wta_bl_ctrl(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ int err;
+
+ err = kstrtoint(buf, 0, &mipi_nt35510_bl_ctrl);
+ if (err)
+ return ret;
+
+ pr_info("%s: bl ctrl set to %d\n", __func__, mipi_nt35510_bl_ctrl);
+
+ return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_nt35510_wta_bl_ctrl);
+
+static struct attribute *mipi_nt35510_fs_attrs[] = {
+ &dev_attr_bl_ctrl.attr,
+ NULL,
+};
+
+static struct attribute_group mipi_nt35510_fs_attr_group = {
+ .attrs = mipi_nt35510_fs_attrs,
+};
+
+static int mipi_nt35510_create_sysfs(struct platform_device *pdev)
+{
+ int rc;
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+ if (!mfd) {
+ pr_err("%s: mfd not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi) {
+ pr_err("%s: mfd->fbi not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi->dev) {
+ pr_err("%s: mfd->fbi->dev not found\n", __func__);
+ return -ENODEV;
+ }
+ rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+ &mipi_nt35510_fs_attr_group);
+ if (rc) {
+ pr_err("%s: sysfs group creation failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev)
{
+ struct platform_device *pthisdev = NULL;
pr_debug("%s\n", __func__);
if (pdev->id == 0) {
@@ -525,7 +596,8 @@
return 0;
}
- msm_fb_add_device(pdev);
+ pthisdev = msm_fb_add_device(pdev);
+ mipi_nt35510_create_sysfs(pthisdev);
return 0;
}
@@ -537,6 +609,8 @@
},
};
+static int old_bl_level;
+
static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level;
@@ -544,11 +618,33 @@
bl_level = mfd->bl_level;
if (mipi_nt35510_pdata->bl_lock) {
- spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock, flags);
- mipi_nt35510_pdata->pmic_backlight(bl_level);
- spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock, flags);
- } else
- mipi_nt35510_pdata->pmic_backlight(bl_level);
+ if (!mipi_nt35510_bl_ctrl) {
+ /* Level received is of range 1 to bl_max,
+ We need to convert the levels to 1
+ to 31 */
+ bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+ /(2 * mfd->panel_info.bl_max);
+ if (bl_level == old_bl_level)
+ return;
+
+ if (bl_level == 0)
+ mipi_nt35510_pdata->backlight(0, 1);
+
+ if (old_bl_level == 0)
+ mipi_nt35510_pdata->backlight(50, 1);
+
+ spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock,
+ flags);
+ mipi_nt35510_pdata->backlight(bl_level, 0);
+ spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock,
+ flags);
+ old_bl_level = bl_level;
+ } else {
+ mipi_nt35510_pdata->backlight(bl_level, 1);
+ }
+ } else {
+ mipi_nt35510_pdata->backlight(bl_level, mipi_nt35510_bl_ctrl);
+ }
}
static struct msm_fb_panel_data nt35510_panel_data = {
diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
index f052e93..1524ce6 100644
--- a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
@@ -56,7 +56,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
index 4e97d99..8a364ba 100644
--- a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
@@ -59,7 +59,7 @@
delayed from VSYNC active edge */
pinfo.lcdc.hsync_skew = 0;
pinfo.clk_rate = 499000000;
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
index 7f5ac70..2ebfad4 100644
--- a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -93,7 +93,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 100;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
index e826773..144d9ff 100644
--- a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -105,7 +105,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 100;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index f7f353f..2e65c34 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -574,7 +574,8 @@
mipi_d2l_enable_3d(mfd, false, false);
/* Add I2C driver only after DSI-CLK is running */
- i2c_add_driver(&d2l_i2c_slave_driver);
+ if (d2l_i2c_client == NULL)
+ i2c_add_driver(&d2l_i2c_slave_driver);
pr_info("%s.ret=%d.\n", __func__, ret);
@@ -989,6 +990,8 @@
{
pr_debug("%s.\n", __func__);
+ d2l_i2c_client = NULL;
+
return platform_driver_register(&d2l_driver);
}
diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h
index 4107161..dd446b9 100644
--- a/drivers/video/msm/mipi_toshiba.h
+++ b/drivers/video/msm/mipi_toshiba.h
@@ -21,7 +21,7 @@
int mipi_toshiba_device_register(struct msm_panel_info *pinfo,
u32 channel, u32 panel);
-#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921
+#define MIPI_TOSHIBA_PWM_FREQ_HZ 300
#define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ)
#define MIPI_TOSHIBA_PWM_LEVEL 255
#define MIPI_TOSHIBA_PWM_DUTY_LEVEL \
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
index e465d46..98b24b1 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -19,6 +19,8 @@
static struct dsi_buf truly_tx_buf;
static struct dsi_buf truly_rx_buf;
+static int mipi_truly_bl_ctrl;
+
#define TRULY_CMD_DELAY 0
#define MIPI_SETTING_DELAY 10
#define TRULY_SLEEP_OFF_DELAY 150
@@ -720,8 +722,64 @@
return 0;
}
+static ssize_t mipi_truly_wta_bl_ctrl(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ ssize_t ret = strnlen(buf, PAGE_SIZE);
+ int err;
+
+ err = kstrtoint(buf, 0, &mipi_truly_bl_ctrl);
+ if (err)
+ return ret;
+
+ pr_info("%s: bl ctrl set to %d\n", __func__, mipi_truly_bl_ctrl);
+
+ return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_truly_wta_bl_ctrl);
+
+static struct attribute *mipi_truly_fs_attrs[] = {
+ &dev_attr_bl_ctrl.attr,
+ NULL,
+};
+
+static struct attribute_group mipi_truly_fs_attr_group = {
+ .attrs = mipi_truly_fs_attrs,
+};
+
+static int mipi_truly_create_sysfs(struct platform_device *pdev)
+{
+ int rc;
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+ if (!mfd) {
+ pr_err("%s: mfd not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi) {
+ pr_err("%s: mfd->fbi not found\n", __func__);
+ return -ENODEV;
+ }
+ if (!mfd->fbi->dev) {
+ pr_err("%s: mfd->fbi->dev not found\n", __func__);
+ return -ENODEV;
+ }
+ rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+ &mipi_truly_fs_attr_group);
+ if (rc) {
+ pr_err("%s: sysfs group creation failed, rc=%d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+
static int __devinit mipi_truly_lcd_probe(struct platform_device *pdev)
{
+ struct platform_device *pthisdev = NULL;
int rc = 0;
if (pdev->id == 0) {
@@ -731,7 +789,8 @@
return rc;
}
- msm_fb_add_device(pdev);
+ pthisdev = msm_fb_add_device(pdev);
+ mipi_truly_create_sysfs(pthisdev);
return rc;
}
@@ -743,6 +802,8 @@
},
};
+static int old_bl_level;
+
static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd)
{
int bl_level;
@@ -750,11 +811,33 @@
bl_level = mfd->bl_level;
if (mipi_truly_pdata->bl_lock) {
- spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock, flags);
- mipi_truly_pdata->pmic_backlight(bl_level);
- spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock, flags);
- } else
- mipi_truly_pdata->pmic_backlight(bl_level);
+ if (!mipi_truly_bl_ctrl) {
+ /* Level received is of range 1 to bl_max,
+ We need to convert the levels to 1
+ to 31 */
+ bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+ /(2 * mfd->panel_info.bl_max);
+ if (bl_level == old_bl_level)
+ return;
+
+ if (bl_level == 0)
+ mipi_truly_pdata->backlight(0, 1);
+
+ if (old_bl_level == 0)
+ mipi_truly_pdata->backlight(50, 1);
+
+ spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock,
+ flags);
+ mipi_truly_pdata->backlight(bl_level, 0);
+ spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock,
+ flags);
+ old_bl_level = bl_level;
+ } else {
+ mipi_truly_pdata->backlight(bl_level, 1);
+ }
+ } else {
+ mipi_truly_pdata->backlight(bl_level, mipi_truly_bl_ctrl);
+ }
}
static struct msm_fb_panel_data truly_panel_data = {
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
index de98177..3423241 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
@@ -56,7 +56,7 @@
pinfo.lcdc.border_clr = 0; /* blk */
pinfo.lcdc.underflow_clr = 0xff; /* blue */
pinfo.lcdc.hsync_skew = 0;
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
index ea2ff47..3c0c0b7 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
@@ -59,7 +59,7 @@
pinfo.lcdc.hsync_skew = 0;
pinfo.clk_rate = 699000000;
pinfo.lcd.refx100 = 6000; /* FB driver calc FPS based on this value */
- pinfo.bl_max = 31;
+ pinfo.bl_max = 255;
pinfo.bl_min = 1;
pinfo.fb_num = 2;
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 70c8afc..682a45a 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -747,7 +747,6 @@
void hdmi_msm_reset_core(void)
{
- hdmi_msm_set_mode(FALSE);
hdmi_msm_clk(0);
udelay(5);
hdmi_msm_clk(1);
diff --git a/drivers/video/msm/msm_dss_io_8x60.c b/drivers/video/msm/msm_dss_io_8x60.c
index a1897e3..bb6f710 100644
--- a/drivers/video/msm/msm_dss_io_8x60.c
+++ b/drivers/video/msm/msm_dss_io_8x60.c
@@ -548,7 +548,6 @@
void hdmi_msm_reset_core(void)
{
- hdmi_msm_set_mode(FALSE);
hdmi_msm_clk(0);
udelay(5);
hdmi_msm_clk(1);
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 3ed305b..81a6e50 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -575,9 +575,6 @@
mfd->op_enable);
if (ret)
MSM_FB_INFO("msm_fb_resume: can't turn on display!\n");
- } else {
- if (pdata->power_ctrl)
- pdata->power_ctrl(TRUE);
}
return ret;
@@ -633,29 +630,49 @@
static int msm_fb_ext_suspend(struct device *dev)
{
struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+ struct msm_fb_panel_data *pdata = NULL;
int ret = 0;
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if (mfd->panel_info.type == HDMI_PANEL ||
- mfd->panel_info.type == DTV_PANEL)
+ mfd->panel_info.type == DTV_PANEL) {
ret = msm_fb_suspend_sub(mfd);
+ /* Turn off the HPD circuitry */
+ if (pdata->power_ctrl) {
+ MSM_FB_INFO("%s: Turning off HPD circuitry\n",
+ __func__);
+ pdata->power_ctrl(FALSE);
+ }
+ }
+
return ret;
}
static int msm_fb_ext_resume(struct device *dev)
{
struct msm_fb_data_type *mfd = dev_get_drvdata(dev);
+ struct msm_fb_panel_data *pdata = NULL;
int ret = 0;
if ((!mfd) || (mfd->key != MFD_KEY))
return 0;
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
if (mfd->panel_info.type == HDMI_PANEL ||
- mfd->panel_info.type == DTV_PANEL)
+ mfd->panel_info.type == DTV_PANEL) {
+ /* Turn on the HPD circuitry */
+ if (pdata->power_ctrl) {
+ pdata->power_ctrl(TRUE);
+ MSM_FB_INFO("%s: Turning on HPD circuitry\n",
+ __func__);
+ }
+
ret = msm_fb_resume_sub(mfd);
+ }
return ret;
}
@@ -813,9 +830,6 @@
mfd->panel_power_on = curr_pwr_state;
mfd->op_enable = TRUE;
- } else {
- if (pdata->power_ctrl)
- pdata->power_ctrl(FALSE);
}
break;
}
@@ -1316,7 +1330,7 @@
GEN_POOL,
fbi->fix.smem_len,
SZ_4K,
- 1,
+ 0,
&(mfd->display_iova));
msm_iommu_map_contig_buffer(fbi->fix.smem_start,
@@ -1324,7 +1338,7 @@
GEN_POOL,
fbi->fix.smem_len,
SZ_4K,
- 1,
+ 0,
&(mfd->rotator_iova));
if (!bf_supported || mfd->index == 0)
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 8ccc21c..a2c3db1 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -82,6 +82,7 @@
uint32 xres_pad;
/* Pad height */
uint32 yres_pad;
+ boolean is_sync_active_high;
};
struct mddi_panel_info {
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
index 81b1436..d5b195d 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.c
@@ -473,8 +473,7 @@
u32 vcd_status = VCD_S_SUCCESS;
struct vcd_transc *transc;
transc = (struct vcd_transc *)(ddl->client_data);
- DDL_MSG_LOW("%s: transc = 0x%x, in_use = %u",
- __func__, (u32)ddl->client_data, transc->in_use);
+ DDL_MSG_LOW("%s: transc = 0x%x", __func__, (u32)ddl->client_data);
if (encoder->slice_delivery_info.enable) {
return ddl_encode_frame_batch(ddl_handle,
input_frame,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index ac1ff24..3c082e4 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -228,6 +228,7 @@
[DDL_MAX_NUM_BFRS_FOR_SLICE_BATCH];
u32 num_output_frames;
u32 out_frm_next_frmindex;
+ u32 first_output_frame_tag;
};
struct ddl_encoder_data{
struct ddl_codec_data_hdr hdr;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index 50c3696..8a33512 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
@@ -30,6 +30,9 @@
#define DDL_MAX_FRAME_WIDTH 1920
#define DDL_MAX_FRAME_HEIGHT 1088
+#define DDL_MAX_VC1_FRAME_WIDTH (DDL_MAX_FRAME_WIDTH)
+#define DDL_MAX_VC1_FRAME_HEIGHT (1280)
+
#define MAX_DPB_SIZE_L4PT0_MBS DDL_KILO_BYTE(32)
#define MAX_FRAME_SIZE_L4PT0_MBS DDL_KILO_BYTE(8)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index 64d2976..6fd5656 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -791,7 +791,7 @@
sz_strm = DDL_ALIGN(ddl_get_yuv_buf_size(width, height,
DDL_YUV_BUF_TYPE_LINEAR) + ddl_get_yuv_buf_size(width,
height/2, DDL_YUV_BUF_TYPE_LINEAR), DDL_KILO_BYTE(4));
- sz_mv = DDL_ALIGN(2 * mb_x * mb_y * 8, DDL_KILO_BYTE(2));
+ sz_mv = DDL_ALIGN(2 * mb_x * 8, DDL_KILO_BYTE(2));
if ((codec == VCD_CODEC_MPEG4) ||
(codec == VCD_CODEC_H264)) {
sz_col_zero = DDL_ALIGN(((mb_x * mb_y + 7) / 8) *
@@ -900,7 +900,7 @@
goto fail_enc_free_exit;
}
if (buf_size.sz_pred > 0) {
- enc_bufs->pred.mem_type = DDL_MM_MEM;
+ enc_bufs->pred.mem_type = DDL_FW_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->pred,
buf_size.sz_pred, DDL_KILO_BYTE(2));
if (!ptr)
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index e2c0a2a..58d1f23 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -312,6 +312,20 @@
return process_further;
}
break;
+ case VCD_CODEC_VC1:
+ case VCD_CODEC_VC1_RCV:
+ if ((seq_hdr_info.img_size_x >
+ DDL_MAX_VC1_FRAME_WIDTH) ||
+ (seq_hdr_info.img_size_y >
+ DDL_MAX_VC1_FRAME_HEIGHT)) {
+ DDL_MSG_ERROR("Unsupported VC1 clip: "
+ "Resolution X=%d and Y=%d",
+ seq_hdr_info.img_size_x,
+ seq_hdr_info.img_size_y);
+ ddl_client_fatal_cb(ddl);
+ return process_further;
+ }
+ break;
default:
break;
}
@@ -1703,6 +1717,13 @@
(void)ddl_get_encoded_frame(output_frame,
encoder->codec.codec, encoder->enc_frame_info.enc_frame
);
+ if (!IS_ERR_OR_NULL(output_frame->buff_ion_handle)) {
+ msm_ion_do_cache_op(ddl_context->video_ion_client,
+ output_frame->buff_ion_handle,
+ (unsigned long *) output_frame->virtual,
+ (unsigned long) output_frame->alloc_len,
+ ION_IOC_INV_CACHES);
+ }
ddl_process_encoder_metadata(ddl);
ddl_vidc_encode_dynamic_property(ddl, false);
ddl->input_frame.frm_trans_end = false;
@@ -1774,6 +1795,27 @@
vidc_sm_get_frame_tags(&ddl->shared_mem
[ddl->command_channel],
&output_frame->ip_frm_tag, &bottom_frame_tag);
+
+ if (start_bfr_idx == 0) {
+ encoder->batch_frame.first_output_frame_tag =
+ output_frame->ip_frm_tag;
+ DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
+ __func__, output_frame->ip_frm_tag);
+ if (!output_frame->ip_frm_tag) {
+ DDL_MSG_ERROR("%s: first_output_frame_tag "\
+ "is zero", __func__);
+ }
+ }
+ if (output_frame->ip_frm_tag !=
+ encoder->batch_frame.first_output_frame_tag) {
+ DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
+ "not equal to the first_output_frame_tag[0x%x]\n",
+ __func__, output_frame->ip_frm_tag,
+ encoder->batch_frame.first_output_frame_tag);
+ output_frame->ip_frm_tag =
+ encoder->batch_frame.first_output_frame_tag;
+ }
+
ddl_get_encoded_frame(output_frame,
encoder->codec.codec,
encoder->enc_frame_info.enc_frame);
@@ -1856,6 +1898,27 @@
vidc_sm_get_frame_tags(&ddl->shared_mem
[ddl->command_channel],
&output_frame->ip_frm_tag, &bottom_frame_tag);
+
+ if (start_bfr_idx == 0) {
+ encoder->batch_frame.first_output_frame_tag =
+ output_frame->ip_frm_tag;
+ DDL_MSG_LOW("%s: first_output_frame_tag[0x%x]",
+ __func__, output_frame->ip_frm_tag);
+ if (!output_frame->ip_frm_tag) {
+ DDL_MSG_ERROR("%s: first_output_frame_tag "\
+ "is zero", __func__);
+ }
+ }
+ if (output_frame->ip_frm_tag !=
+ encoder->batch_frame.first_output_frame_tag) {
+ DDL_MSG_ERROR("%s: output_frame->ip_frm_tag[0x%x] is "\
+ "not equal to the first_output_frame_tag[0x%x]\n",
+ __func__, output_frame->ip_frm_tag,
+ encoder->batch_frame.first_output_frame_tag);
+ output_frame->ip_frm_tag =
+ encoder->batch_frame.first_output_frame_tag;
+ }
+
ddl_get_encoded_frame(output_frame,
encoder->codec.codec,
encoder->enc_frame_info.enc_frame);
@@ -1925,6 +1988,10 @@
&ddl->shared_mem[ddl->command_channel],
&output_frame->ip_frm_tag,
&bottom_frame_tag);
+ if (!output_frame->ip_frm_tag) {
+ DDL_MSG_ERROR("%s: output frame tag is zero",
+ __func__);
+ }
ddl_get_encoded_frame(
output_frame,
encoder->codec.codec,
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
index 3827bc1..ab4d51c 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -294,6 +294,11 @@
}
}
break;
+ case VCD_I_SET_TURBO_CLK:
+ {
+ vcd_status = VCD_S_SUCCESS;
+ }
+ break;
case VCD_I_BUFFER_FORMAT:
{
struct vcd_property_buffer_format *tile =
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
index 878db62..839a9c1 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_shared_mem.c
@@ -207,7 +207,7 @@
#define VIDC_SM_MPEG4_ASPECT_RATIO_INFO_SHFT 0x0
#define VIDC_SM_EXTENDED_PAR_ADDR 0x00cc
#define VIDC_SM_EXTENDED_PAR_WIDTH_BMSK 0xffff0000
-#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT 0xf
+#define VIDC_SM_EXTENDED_PAR_WIDTH_SHFT 16
#define VIDC_SM_EXTENDED_PAR_HEIGHT_BMSK 0x0000ffff
#define VIDC_SM_EXTENDED_PAR_HEIGHT_SHFT 0x0
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
index d0cf4e8..14e1331 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_vidc.c
@@ -867,6 +867,7 @@
DDL_MEMSET(encoder->batch_frame.slice_batch_in.align_virtual_addr, 0,
sizeof(struct vidc_1080p_enc_slice_batch_in_param));
encoder->batch_frame.out_frm_next_frmindex = 0;
+ encoder->batch_frame.first_output_frame_tag = 0;
bitstream_size = encoder->batch_frame.output_frame[0].vcd_frm.alloc_len;
encoder->output_buf_req.sz = bitstream_size;
y_addr = DDL_OFFSET(ddl_context->dram_base_b.align_physical_addr,
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
index d90b8ca..a5171f0 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.c
@@ -28,8 +28,8 @@
#define PIL_FW_BASE_ADDR 0x9fe00000
#define PIL_FW_SIZE 0x200000
-static unsigned int vidc_clk_table[3] = {
- 48000000, 133330000, 200000000
+static unsigned int vidc_clk_table[4] = {
+ 48000000, 133330000, 200000000, 228570000,
};
static unsigned int restrk_mmu_subsystem[] = {
MSM_SUBSYSTEM_VIDEO, MSM_SUBSYSTEM_VIDEO_FWARE};
@@ -536,6 +536,9 @@
u32 bus_clk_index, client_type = 0;
int rc = 0;
+ if (dev_ctxt->turbo_mode_set)
+ return rc;
+
cctxt_itr = dev_ctxt->cctxt_list_head;
while (cctxt_itr) {
if (cctxt_itr->decoding)
@@ -544,17 +547,30 @@
enc_perf_level += cctxt_itr->reqd_perf_lvl;
cctxt_itr = cctxt_itr->next;
}
+
if (!enc_perf_level)
client_type = 1;
if (perf_level <= RESTRK_1080P_VGA_PERF_LEVEL)
bus_clk_index = 0;
else if (perf_level <= RESTRK_1080P_720P_PERF_LEVEL)
bus_clk_index = 1;
- else
+ else if (perf_level <= RESTRK_1080P_MAX_PERF_LEVEL)
bus_clk_index = 2;
+ else
+ bus_clk_index = 3;
if (dev_ctxt->reqd_perf_lvl + dev_ctxt->curr_perf_lvl == 0)
bus_clk_index = 2;
+ else if (resource_context.vidc_platform_data->disable_turbo
+ && bus_clk_index == 3) {
+ VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
+ " falling back to 1080p bus\n");
+ bus_clk_index = 2;
+ }
+
+ if (bus_clk_index == 3)
+ dev_ctxt->turbo_mode_set = 1;
+
bus_clk_index = (bus_clk_index << 1) + (client_type + 1);
VCDRES_MSG_LOW("%s(), bus_clk_index = %d", __func__, bus_clk_index);
VCDRES_MSG_LOW("%s(),context.pcl = %x", __func__, resource_context.pcl);
@@ -574,7 +590,20 @@
__func__, dev_ctxt);
return false;
}
+ if (dev_ctxt->turbo_mode_set &&
+ (req_perf_lvl < RESTRK_1080P_TURBO_PERF_LEVEL)) {
+ VCDRES_MSG_MED("%s(): TURBO MODE!!\n", __func__);
+ return true;
+ }
+
VCDRES_MSG_LOW("%s(), req_perf_lvl = %d", __func__, req_perf_lvl);
+
+ if (resource_context.vidc_platform_data->disable_turbo
+ && req_perf_lvl > RESTRK_1080P_MAX_PERF_LEVEL) {
+ VCDRES_MSG_ERROR("%s(): Turbo not supported! dev_ctxt(%p)\n",
+ __func__, dev_ctxt);
+ }
+
#ifdef CONFIG_MSM_BUS_SCALING
if (!res_trk_update_bus_perf_level(dev_ctxt, req_perf_lvl) < 0) {
VCDRES_MSG_ERROR("%s(): update buf perf level failed\n",
@@ -592,10 +621,22 @@
} else if (req_perf_lvl <= RESTRK_1080P_720P_PERF_LEVEL) {
vidc_freq = vidc_clk_table[1];
*pn_set_perf_lvl = RESTRK_1080P_720P_PERF_LEVEL;
+ } else if (req_perf_lvl <= RESTRK_1080P_MAX_PERF_LEVEL) {
+ vidc_freq = vidc_clk_table[2];
+ *pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
} else {
+ vidc_freq = vidc_clk_table[3];
+ *pn_set_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
+ }
+
+ if (resource_context.vidc_platform_data->disable_turbo &&
+ *pn_set_perf_lvl == RESTRK_1080P_TURBO_PERF_LEVEL) {
+ VCDRES_MSG_ERROR("Warning: Turbo mode not supported "
+ " falling back to 1080p clocks\n");
vidc_freq = vidc_clk_table[2];
*pn_set_perf_lvl = RESTRK_1080P_MAX_PERF_LEVEL;
}
+
resource_context.perf_level = *pn_set_perf_lvl;
VCDRES_MSG_MED("VIDC: vidc_freq = %u, req_perf_lvl = %u\n",
vidc_freq, req_perf_lvl);
@@ -969,6 +1010,9 @@
case VCD_PERF_LEVEL2:
res_trk_perf_level = RESTRK_1080P_MAX_PERF_LEVEL;
break;
+ case VCD_PERF_LEVEL_TURBO:
+ res_trk_perf_level = RESTRK_1080P_TURBO_PERF_LEVEL;
+ break;
default:
VCD_MSG_ERROR("Invalid perf level: %d\n", perf_level);
res_trk_perf_level = -EINVAL;
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index bf8607d..01999a4 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -28,6 +28,7 @@
#define RESTRK_1080P_MIN_PERF_LEVEL RESTRK_1080P_VGA_PERF_LEVEL
#define RESTRK_1080P_MAX_PERF_LEVEL RESTRK_1080P_1080P_PERF_LEVEL
+#define RESTRK_1080P_TURBO_PERF_LEVEL (RESTRK_1080P_MAX_PERF_LEVEL + 1)
struct res_trk_context {
struct device *device;
@@ -74,4 +75,8 @@
#define VCDRES_MSG_ERROR(xx_fmt...) printk(KERN_ERR "\n err: " xx_fmt)
#define VCDRES_MSG_FATAL(xx_fmt...) printk(KERN_ERR "\n<FATAL> " xx_fmt)
+#ifdef CONFIG_MSM_BUS_SCALING
+int res_trk_update_bus_perf_level(struct vcd_dev_ctxt *dev_ctxt,
+ u32 perf_level);
+#endif
#endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 11177b8..3076aa1 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -636,6 +636,26 @@
return true;
}
+static u32 vid_dec_set_turbo_clk(struct video_client_ctx *client_ctx)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ u32 vcd_status = VCD_ERR_FAIL;
+ u32 dummy = 0;
+
+ if (!client_ctx)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_SET_TURBO_CLK;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_frame_size);
+
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &dummy);
+
+ if (vcd_status)
+ return false;
+ else
+ return true;
+}
+
static u32 vid_dec_get_frame_resolution(struct video_client_ctx *client_ctx,
struct vdec_picsize *video_resoultion)
{
@@ -1682,6 +1702,11 @@
}
break;
}
+ case VDEC_IOCTL_SET_PERF_CLK:
+ {
+ vid_dec_set_turbo_clk(client_ctx);
+ break;
+ }
case VDEC_IOCTL_FILL_OUTPUT_BUFFER:
{
struct vdec_fillbuffer_cmd fill_buffer_cmd;
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 1b77b67..67917b9 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -252,6 +252,8 @@
/* Timestamp pass-through from input frame */
venc_msg->venc_msg_info.buf.timestamp =
vcd_frame_data->time_stamp;
+ venc_msg->venc_msg_info.buf.sz =
+ vcd_frame_data->alloc_len;
/* Decoded picture width and height */
venc_msg->venc_msg_info.msgdata_size =
@@ -269,7 +271,7 @@
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *) kernel_vaddr,
- (unsigned long)venc_msg->venc_msg_info.buf.len,
+ (unsigned long)venc_msg->venc_msg_info.buf.sz,
ION_IOC_CLEAN_INV_CACHES);
}
}
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index bbbe0cf..43e8d5e 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -1723,6 +1723,7 @@
struct file *file;
s32 buffer_index = -1;
u32 vcd_status = VCD_ERR_FAIL;
+ struct ion_handle *buff_handle = NULL;
struct vcd_frame_data vcd_frame;
@@ -1738,9 +1739,13 @@
memset((void *)&vcd_frame, 0,
sizeof(struct vcd_frame_data));
+ vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
+ pmem_fd, kernel_vaddr, buffer_index,
+ &buff_handle);
vcd_frame.virtual = (u8 *) kernel_vaddr;
vcd_frame.frm_clnt_data = (u32) output_frame_info->clientdata;
vcd_frame.alloc_len = output_frame_info->sz;
+ vcd_frame.buff_ion_handle = buff_handle;
vcd_status = vcd_fill_output_buffer(client_ctx->vcd_handle,
&vcd_frame);
diff --git a/drivers/video/msm/vidc/common/vcd/vcd.h b/drivers/video/msm/vidc/common/vcd/vcd.h
index 3e02030..8f44a56 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd.h
@@ -397,4 +397,5 @@
u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl);
+u32 vcd_set_perf_turbo_level(struct vcd_clnt_ctxt *cctxt);
#endif
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
index 5019d31..7c0d9fe 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_client_sm.c
@@ -541,6 +541,12 @@
}
break;
}
+ case VCD_I_SET_TURBO_CLK:
+ {
+ if (cctxt->sched_clnt_hdl)
+ rc = vcd_set_perf_turbo_level(cctxt);
+ break;
+ }
case VCD_I_INTRA_PERIOD:
{
struct vcd_property_i_period *iperiod =
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_core.h b/drivers/video/msm/vidc/common/vcd/vcd_core.h
index 7ae4f45..5351589 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_core.h
+++ b/drivers/video/msm/vidc/common/vcd/vcd_core.h
@@ -146,7 +146,7 @@
u32 reqd_perf_lvl;
u32 curr_perf_lvl;
u32 set_perf_lvl_pending;
-
+ u32 turbo_mode_set;
};
struct vcd_clnt_status {
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
index d517028..96e729d 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -219,6 +219,7 @@
VCD_DEVICE_STATE_INITING,
ev_code);
}
+ dev_ctxt->turbo_mode_set = 0;
return rc;
}
@@ -758,6 +759,7 @@
client = dev_ctxt->cctxt_list_head;
dev_ctxt->cctxt_list_head = cctxt;
cctxt->next = client;
+ dev_ctxt->turbo_mode_set = 0;
*clnt_cctxt = cctxt;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
index beaa872..33b2300 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_power_sm.c
@@ -15,6 +15,7 @@
#include "vcd_power_sm.h"
#include "vcd_core.h"
#include "vcd.h"
+#include "vcd_res_tracker.h"
u32 vcd_power_event(
struct vcd_dev_ctxt *dev_ctxt,
@@ -297,6 +298,25 @@
return rc;
}
+u32 vcd_set_perf_turbo_level(struct vcd_clnt_ctxt *cctxt)
+{
+ u32 rc = VCD_S_SUCCESS;
+#ifdef CONFIG_MSM_BUS_SCALING
+ struct vcd_dev_ctxt *dev_ctxt = cctxt->dev_ctxt;
+ pr_err("\n Setting Turbo mode !!");
+
+ if (res_trk_update_bus_perf_level(dev_ctxt,
+ RESTRK_1080P_TURBO_PERF_LEVEL) < 0) {
+ pr_err("\n %s(): update buf perf level failed\n",
+ __func__);
+ return false;
+ }
+ dev_ctxt->curr_perf_lvl = RESTRK_1080P_TURBO_PERF_LEVEL;
+ vcd_update_decoder_perf_level(dev_ctxt, RESTRK_1080P_TURBO_PERF_LEVEL);
+#endif
+ return rc;
+}
+
u32 vcd_update_decoder_perf_level(struct vcd_dev_ctxt *dev_ctxt, u32 perf_lvl)
{
u32 rc = VCD_S_SUCCESS;
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 6ca4dbe..f79a147 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
@@ -745,7 +745,8 @@
return VCD_ERR_ILLEGAL_PARM;
}
if (buf_entry->in_use) {
- VCD_MSG_ERROR("\n Buffer is in use and is not flushed");
+ VCD_MSG_ERROR("Buffer is in use and is not flushed: %p, %d\n",
+ buf_entry, buf_entry->in_use);
return VCD_ERR_ILLEGAL_OP;
}
@@ -1043,6 +1044,7 @@
{
u32 rc = VCD_S_SUCCESS;
struct vcd_buffer_entry *buf_entry;
+ struct vcd_buffer_entry *orig_frame = NULL;
VCD_MSG_LOW("vcd_flush_buffers:");
@@ -1066,9 +1068,19 @@
vcd_frame_data),
cctxt,
cctxt->client_data);
+ orig_frame = vcd_find_buffer_pool_entry(
+ &cctxt->in_buf_pool,
+ buf_entry->virtual);
}
- buf_entry->in_use = false;
+ if (orig_frame) {
+ orig_frame->in_use--;
+ if (orig_frame != buf_entry)
+ kfree(buf_entry);
+ } else {
+ buf_entry->in_use = false;
+ VCD_MSG_ERROR("Original frame not found in buffer pool\n");
+ }
VCD_BUFFERPOOL_INUSE_DECREMENT(
cctxt->in_buf_pool.in_use);
buf_entry = NULL;
@@ -2067,8 +2079,8 @@
rc = VCD_ERR_CLIENT_FATAL;
if (VCD_FAILED(rc)) {
- VCD_MSG_FATAL(
- "vcd_validate_io_done_pyld: invalid transaction");
+ VCD_MSG_FATAL("vcd_validate_io_done_pyld: "\
+ "invalid transaction 0x%x", (u32)transc);
} else if (!frame->vcd_frm.virtual &&
status != VCD_ERR_INTRLCD_FIELD_DROP)
rc = VCD_ERR_BAD_POINTER;
@@ -3417,7 +3429,7 @@
struct vcd_property_slice_delivery_info slice_delivery_info;
u32 rc = VCD_S_SUCCESS;
prop_hdr.prop_id = VCD_I_SLICE_DELIVERY_MODE;
- prop_hdr.sz = prop_hdr.sz =
+ prop_hdr.sz =
sizeof(struct vcd_property_slice_delivery_info);
rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr,
&slice_delivery_info);
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index ec9f187..4358a92 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -977,7 +977,7 @@
struct ubifs_budget_req ino_req = { .dirtied_ino = 1,
.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
struct timespec time;
- unsigned int saved_nlink;
+ unsigned int saved_nlink = 0;
/*
* Budget request settings: deletion direntry, new direntry, removing
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 1e1e09f..28c0917 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -436,7 +436,6 @@
header-y += msm_audio_sbc.h
header-y += msm_ipc.h
header-y += msm_charm.h
-header-y += tzcom.h
header-y += qseecom.h
header-y += qcedev.h
header-y += idle_stats_device.h
diff --git a/include/linux/input/mpu3050.h b/include/linux/input/mpu3050.h
new file mode 100644
index 0000000..6006abb
--- /dev/null
+++ b/include/linux/input/mpu3050.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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 __MPU3050_H__
+#define __MPU3050_H__
+
+struct mpu3050_gyro_platform_data {
+ int poll_interval;
+ int min_interval;
+
+ int (*init)(void);
+ void (*exit)(void);
+ int (*power_on)(void);
+ int (*power_off)(void);
+
+ int gpio_int;
+ int gpio_fsync;
+};
+
+#endif /* __MPU3050_H__ */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index d9443ff..fca5517 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -86,6 +86,14 @@
FIXED_HIGH,
};
+enum cp_mem_usage {
+ VIDEO_BITSTREAM = 0x1,
+ VIDEO_PIXEL = 0x2,
+ VIDEO_NONPIXEL = 0x3,
+ MAX_USAGE = 0x4,
+ UNKNOWN = 0x7FFFFFFF,
+};
+
/**
* Flag to use when allocating to indicate that a heap is secure.
*/
@@ -482,22 +490,28 @@
*
* @client - a client that has allocated from the heap heap_id
* @heap_id - heap id to secure.
+ * @version - version of content protection
+ * @data - extra data needed for protection
*
* Secure a heap
* Returns 0 on success
*/
-int ion_secure_heap(struct ion_device *dev, int heap_id);
+int ion_secure_heap(struct ion_device *dev, int heap_id, int version,
+ void *data);
/**
* ion_unsecure_heap - un-secure a heap
*
* @client - a client that has allocated from the heap heap_id
* @heap_id - heap id to un-secure.
+ * @version - version of content protection
+ * @data - extra data needed for protection
*
* Un-secure a heap
* Returns 0 on success
*/
-int ion_unsecure_heap(struct ion_device *dev, int heap_id);
+int ion_unsecure_heap(struct ion_device *dev, int heap_id, int version,
+ void *data);
/**
* msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
@@ -520,6 +534,30 @@
int msm_ion_unsecure_heap(int heap_id);
/**
+ * msm_ion_secure_heap_2_0 - secure a heap using 2.0 APIs
+ * Wrapper around ion_secure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap secured with 3.0 APIs.
+ * Wrapper around ion_unsecure_heap.
+ *
+ * @heap_id - heap id to secure.
+ * @usage - usage hint to TZ
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap_2_0(int heap_id, enum cp_mem_usage usage);
+
+/**
* msm_ion_do_cache_op - do cache operations.
*
* @client - pointer to ION client.
@@ -627,13 +665,15 @@
return;
}
-static inline int ion_secure_heap(struct ion_device *dev, int heap_id)
+static inline int ion_secure_heap(struct ion_device *dev, int heap_id,
+ int version, void *data)
{
return -ENODEV;
}
-static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id,
+ int version, void *data)
{
return -ENODEV;
}
@@ -649,6 +689,17 @@
return -ENODEV;
}
+static inline int msm_ion_secure_heap_2_0(int heap_id, enum cp_mem_usage usage)
+{
+ return -ENODEV;
+}
+
+static inline int msm_ion_unsecure_heap_2_0(int heap_id,
+ enum cp_mem_usage usage)
+{
+ return -ENODEV;
+}
+
static inline int msm_ion_do_cache_op(struct ion_client *client,
struct ion_handle *handle, void *vaddr,
unsigned long len, unsigned int cmd)
diff --git a/include/linux/mfd/pm8xxx/ccadc.h b/include/linux/mfd/pm8xxx/ccadc.h
index 23d0fb0..0bd4cc3 100644
--- a/include/linux/mfd/pm8xxx/ccadc.h
+++ b/include/linux/mfd/pm8xxx/ccadc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. 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
@@ -20,9 +20,11 @@
/**
* struct pm8xxx_ccadc_platform_data -
* @r_sense: sense resistor value in (mOhms)
+ * @calib_delay_ms: how often should the adc calculate gain and offset
*/
struct pm8xxx_ccadc_platform_data {
- int r_sense;
+ int r_sense;
+ unsigned int calib_delay_ms;
};
#define CCADC_READING_RESOLUTION_N_V1 1085069
diff --git a/include/linux/mfd/pm8xxx/mpp.h b/include/linux/mfd/pm8xxx/mpp.h
index 802948b..2a934e5 100644
--- a/include/linux/mfd/pm8xxx/mpp.h
+++ b/include/linux/mfd/pm8xxx/mpp.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -168,7 +168,7 @@
#define PM8921_MPP_DIG_LEVEL_VPH 7
/* Digital Input/Output: level [PM8821] */
-#define PM8821_MPP_DIG_LEVEL_1P8 1
+#define PM8821_MPP_DIG_LEVEL_1P8 0
#define PM8821_MPP_DIG_LEVEL_VPH 7
/* Digital Input/Output: level [PM8018] */
diff --git a/include/linux/mfd/pm8xxx/pm8038.h b/include/linux/mfd/pm8xxx/pm8038.h
index 90557b9..682abc8 100644
--- a/include/linux/mfd/pm8xxx/pm8038.h
+++ b/include/linux/mfd/pm8xxx/pm8038.h
@@ -33,6 +33,7 @@
#include <linux/leds-pm8xxx.h>
#include <linux/mfd/pm8xxx/ccadc.h>
#include <linux/mfd/pm8xxx/spk.h>
+#include <linux/mfd/pm8xxx/tm.h>
#define PM8038_CORE_DEV_NAME "pm8038-core"
@@ -64,6 +65,9 @@
#define PM8038_RESOUT_IRQ PM8038_IRQ_BLOCK_BIT(6, 4)
+#define PM8038_OVERTEMP_IRQ PM8038_IRQ_BLOCK_BIT(4, 2)
+#define PM8038_TEMPSTAT_IRQ PM8038_IRQ_BLOCK_BIT(6, 7)
+
struct pm8038_platform_data {
int irq_base;
struct pm8xxx_gpio_platform_data *gpio_pdata;
diff --git a/include/linux/mfd/pm8xxx/pm8821-irq.h b/include/linux/mfd/pm8xxx/pm8821-irq.h
new file mode 100644
index 0000000..af985e6
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/pm8821-irq.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. 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.
+ */
+/*
+ * Qualcomm PMIC irq 8821 driver header file
+ *
+ */
+
+#ifndef __MFD_PM8821_IRQ_H
+#define __MFD_PM8821_IRQ_H
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/mfd/pm8xxx/irq.h>
+
+#ifdef CONFIG_MFD_PM8821_IRQ
+int pm8821_get_irq_stat(struct pm_irq_chip *chip, int irq);
+struct pm_irq_chip *pm8821_irq_init(struct device *dev,
+ const struct pm8xxx_irq_platform_data *pdata);
+int pm8821_irq_exit(struct pm_irq_chip *chip);
+#else
+static inline int pm8821_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+ return -ENXIO;
+}
+static inline struct pm_irq_chip *pm8821_irq_init(const struct device *dev,
+ const struct pm8xxx_irq_platform_data *pdata)
+{
+ return ERR_PTR(-ENXIO);
+}
+static inline int pm8821_irq_exit(struct pm_irq_chip *chip)
+{
+ return -ENXIO;
+}
+#endif /* CONFIG_MFD_PM8821_IRQ */
+#endif /* __MFD_PM8821_IRQ_H */
diff --git a/include/linux/mfd/pm8xxx/pm8821.h b/include/linux/mfd/pm8xxx/pm8821.h
index 850e8c1..7ed7617 100644
--- a/include/linux/mfd/pm8xxx/pm8821.h
+++ b/include/linux/mfd/pm8xxx/pm8821.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -19,14 +19,19 @@
#define __MFD_PM8821_H
#include <linux/device.h>
-#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/mfd/pm8xxx/pm8821-irq.h>
#include <linux/mfd/pm8xxx/mpp.h>
-#define PM8821_NR_IRQS (64)
+#define PM8821_NR_IRQS (112)
#define PM8821_NR_MPPS (4)
-#define PM8821_MPP_BLOCK_START (16)
-#define PM8821_IRQ_BLOCK_BIT(block, bit) ((block) * 8 + (bit))
+#define PM8821_MPP_BLOCK_START (4)
+
+/*
+ * Block 0 does not exist in PM8821 IRQ SSBI address space,
+ * IRQ0 is assigned to bit0 of block1
+ */
+#define PM8821_IRQ_BLOCK_BIT(block, bit) ((block-1) * 8 + (bit))
/* MPPs [1,N] */
#define PM8821_MPP_IRQ(base, mpp) ((base) + \
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 537e0b5..90c2d99 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -117,7 +117,6 @@
* @i_test: current at which the unusable charger cutoff is to be
* calculated or the peak system current (mA)
* @v_failure: the voltage at which the battery is considered empty(mV)
- * @calib_delay_ms: how often should the adc calculate gain and offset
* @enable_fcc_learning: if set the driver will learn full charge
* capacity of the battery upon end of charge
*/
@@ -127,7 +126,6 @@
unsigned int r_sense;
unsigned int i_test;
unsigned int v_failure;
- unsigned int calib_delay_ms;
unsigned int max_voltage_uv;
unsigned int rconn_mohm;
int enable_fcc_learning;
diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h
index 612b133..2657ec3 100644
--- a/include/linux/mfd/wcd9xxx/core.h
+++ b/include/linux/mfd/wcd9xxx/core.h
@@ -90,6 +90,32 @@
};
+enum {
+ TAIKO_IRQ_SLIMBUS = 0,
+ TAIKO_IRQ_MBHC_REMOVAL,
+ TAIKO_IRQ_MBHC_SHORT_TERM,
+ TAIKO_IRQ_MBHC_PRESS,
+ TAIKO_IRQ_MBHC_RELEASE,
+ TAIKO_IRQ_MBHC_POTENTIAL,
+ TAIKO_IRQ_MBHC_INSERTION,
+ TAIKO_IRQ_BG_PRECHARGE,
+ TAIKO_IRQ_PA1_STARTUP,
+ TAIKO_IRQ_PA2_STARTUP,
+ TAIKO_IRQ_PA3_STARTUP,
+ TAIKO_IRQ_PA4_STARTUP,
+ TAIKO_IRQ_PA5_STARTUP,
+ TAIKO_IRQ_MICBIAS1_PRECHARGE,
+ TAIKO_IRQ_MICBIAS2_PRECHARGE,
+ TAIKO_IRQ_MICBIAS3_PRECHARGE,
+ TAIKO_IRQ_HPH_PA_OCPL_FAULT,
+ TAIKO_IRQ_HPH_PA_OCPR_FAULT,
+ TAIKO_IRQ_EAR_PA_OCPL_FAULT,
+ TAIKO_IRQ_HPH_L_PA_STARTUP,
+ TAIKO_IRQ_HPH_R_PA_STARTUP,
+ TAIKO_IRQ_EAR_PA_STARTUP,
+ TAIKO_NUM_IRQS,
+};
+
enum wcd9xxx_pm_state {
WCD9XXX_PM_SLEEPABLE,
WCD9XXX_PM_AWAKE,
diff --git a/include/linux/mfd/wcd9xxx/pdata.h b/include/linux/mfd/wcd9xxx/pdata.h
index db76294..ba71293 100644
--- a/include/linux/mfd/wcd9xxx/pdata.h
+++ b/include/linux/mfd/wcd9xxx/pdata.h
@@ -34,6 +34,16 @@
#define TABLA_CFILT2_SEL 0x1
#define TABLA_CFILT3_SEL 0x2
+#define TAIKO_CFILT1_SEL 0x0
+#define TAIKO_CFILT2_SEL 0x1
+#define TAIKO_CFILT3_SEL 0x2
+
+#define TAIKO_LDOH_1P95_V 0x0
+#define TAIKO_LDOH_2P35_V 0x1
+#define TAIKO_LDOH_2P75_V 0x2
+#define TAIKO_LDOH_2P85_V 0x3
+
+
#define MAX_AMIC_CHANNEL 7
#define TABLA_OCP_300_MA 0x0
diff --git a/include/linux/mfd/wcd9xxx/wcd9320_registers.h b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
new file mode 100644
index 0000000..5725e6e
--- /dev/null
+++ b/include/linux/mfd/wcd9xxx/wcd9320_registers.h
@@ -0,0 +1,1354 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 WCD9320_REGISTERS_H
+#define WCD9320_REGISTERS_H
+
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+
+#define TAIKO_A_CHIP_CTL WCD9XXX_A_CHIP_CTL
+#define TAIKO_A_CHIP_CTL__POR WCD9XXX_A_CHIP_CTL__POR
+#define TAIKO_A_CHIP_STATUS WCD9XXX_A_CHIP_STATUS
+#define TAIKO_A_CHIP_STATUS__POR WCD9XXX_A_CHIP_STATUS__POR
+#define TAIKO_A_CHIP_ID_BYTE_0 WCD9XXX_A_CHIP_ID_BYTE_0
+#define TAIKO_A_CHIP_ID_BYTE_0__POR WCD9XXX_A_CHIP_ID_BYTE_0__POR
+#define TAIKO_A_CHIP_ID_BYTE_1 WCD9XXX_A_CHIP_ID_BYTE_1
+#define TAIKO_A_CHIP_ID_BYTE_1__POR WCD9XXX_A_CHIP_ID_BYTE_1__POR
+#define TAIKO_A_CHIP_ID_BYTE_2 WCD9XXX_A_CHIP_ID_BYTE_2
+#define TAIKO_A_CHIP_ID_BYTE_2__POR WCD9XXX_A_CHIP_ID_BYTE_2__POR
+#define TAIKO_A_CHIP_ID_BYTE_3 WCD9XXX_A_CHIP_ID_BYTE_3
+#define TAIKO_A_CHIP_ID_BYTE_3__POR WCD9XXX_A_CHIP_ID_BYTE_3__POR
+#define TAIKO_A_CHIP_VERSION WCD9XXX_A_CHIP_VERSION
+#define TAIKO_A_CHIP_VERSION__POR WCD9XXX_A_CHIP_VERSION__POR
+#define TAIKO_A_SB_VERSION WCD9XXX_A_SB_VERSION
+#define TAIKO_A_SB_VERSION__POR WCD9XXX_A_SB_VERSION__POR
+#define TAIKO_A_SLAVE_ID_1 WCD9XXX_A_SLAVE_ID_1
+#define TAIKO_A_SLAVE_ID_1__POR WCD9XXX_A_SLAVE_ID_1__POR
+#define TAIKO_A_SLAVE_ID_2 WCD9XXX_A_SLAVE_ID_2
+#define TAIKO_A_SLAVE_ID_2__POR WCD9XXX_A_SLAVE_ID_2__POR
+#define TAIKO_A_SLAVE_ID_3 WCD9XXX_A_SLAVE_ID_3
+#define TAIKO_A_SLAVE_ID_3__POR WCD9XXX_A_SLAVE_ID_3__POR
+#define TAIKO_A_PIN_CTL_OE0 (0x010)
+#define TAIKO_A_PIN_CTL_OE0__POR (0x00)
+#define TAIKO_A_PIN_CTL_OE1 (0x011)
+#define TAIKO_A_PIN_CTL_OE1__POR (0x00)
+#define TAIKO_A_PIN_CTL_DATA0 (0x012)
+#define TAIKO_A_PIN_CTL_DATA0__POR (0x00)
+#define TAIKO_A_PIN_CTL_DATA1 (0x013)
+#define TAIKO_A_PIN_CTL_DATA1__POR (0x00)
+#define TAIKO_A_HDRIVE_GENERIC (0x018)
+#define TAIKO_A_HDRIVE_GENERIC__POR (0x00)
+#define TAIKO_A_HDRIVE_OVERRIDE (0x019)
+#define TAIKO_A_HDRIVE_OVERRIDE__POR (0x08)
+#define TAIKO_A_ANA_CSR_WAIT_STATE (0x020)
+#define TAIKO_A_ANA_CSR_WAIT_STATE__POR (0x44)
+#define TAIKO_A_PROCESS_MONITOR_CTL0 (0x040)
+#define TAIKO_A_PROCESS_MONITOR_CTL0__POR (0x80)
+#define TAIKO_A_PROCESS_MONITOR_CTL1 (0x041)
+#define TAIKO_A_PROCESS_MONITOR_CTL1__POR (0x00)
+#define TAIKO_A_PROCESS_MONITOR_CTL2 (0x042)
+#define TAIKO_A_PROCESS_MONITOR_CTL2__POR (0x00)
+#define TAIKO_A_PROCESS_MONITOR_CTL3 (0x043)
+#define TAIKO_A_PROCESS_MONITOR_CTL3__POR (0x01)
+#define TAIKO_A_QFUSE_CTL (0x048)
+#define TAIKO_A_QFUSE_CTL__POR (0x00)
+#define TAIKO_A_QFUSE_STATUS (0x049)
+#define TAIKO_A_QFUSE_STATUS__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT0 (0x04A)
+#define TAIKO_A_QFUSE_DATA_OUT0__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT1 (0x04B)
+#define TAIKO_A_QFUSE_DATA_OUT1__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT2 (0x04C)
+#define TAIKO_A_QFUSE_DATA_OUT2__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT3 (0x04D)
+#define TAIKO_A_QFUSE_DATA_OUT3__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT4 (0x04E)
+#define TAIKO_A_QFUSE_DATA_OUT4__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT5 (0x04F)
+#define TAIKO_A_QFUSE_DATA_OUT5__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT6 (0x050)
+#define TAIKO_A_QFUSE_DATA_OUT6__POR (0x00)
+#define TAIKO_A_QFUSE_DATA_OUT7 (0x051)
+#define TAIKO_A_QFUSE_DATA_OUT7__POR (0x00)
+#define TAIKO_A_CDC_CTL WCD9XXX_A_CDC_CTL
+#define TAIKO_A_CDC_CTL__POR WCD9XXX_A_CDC_CTL__POR
+#define TAIKO_A_LEAKAGE_CTL WCD9XXX_A_LEAKAGE_CTL
+#define TAIKO_A_LEAKAGE_CTL__POR WCD9XXX_A_LEAKAGE_CTL__POR
+#define TAIKO_A_INTR_MODE (0x090)
+#define TAIKO_A_INTR_MODE__POR (0x00)
+#define TAIKO_A_INTR_MASK0 (0x094)
+#define TAIKO_A_INTR_MASK0__POR (0xFF)
+#define TAIKO_A_INTR_MASK1 (0x095)
+#define TAIKO_A_INTR_MASK1__POR (0xFF)
+#define TAIKO_A_INTR_MASK2 (0x096)
+#define TAIKO_A_INTR_MASK2__POR (0x3F)
+#define TAIKO_A_INTR_MASK3 (0x097)
+#define TAIKO_A_INTR_MASK3__POR (0x3F)
+#define TAIKO_A_INTR_STATUS0 (0x098)
+#define TAIKO_A_INTR_STATUS0__POR (0x00)
+#define TAIKO_A_INTR_STATUS1 (0x099)
+#define TAIKO_A_INTR_STATUS1__POR (0x00)
+#define TAIKO_A_INTR_STATUS2 (0x09A)
+#define TAIKO_A_INTR_STATUS2__POR (0x00)
+#define TAIKO_A_INTR_STATUS3 (0x09B)
+#define TAIKO_A_INTR_STATUS3__POR (0x00)
+#define TAIKO_A_INTR_CLEAR0 (0x09C)
+#define TAIKO_A_INTR_CLEAR0__POR (0x00)
+#define TAIKO_A_INTR_CLEAR1 (0x09D)
+#define TAIKO_A_INTR_CLEAR1__POR (0x00)
+#define TAIKO_A_INTR_CLEAR2 (0x09E)
+#define TAIKO_A_INTR_CLEAR2__POR (0x00)
+#define TAIKO_A_INTR_CLEAR3 (0x09F)
+#define TAIKO_A_INTR_CLEAR3__POR (0x00)
+#define TAIKO_A_INTR_LEVEL0 (0x0A0)
+#define TAIKO_A_INTR_LEVEL0__POR (0x01)
+#define TAIKO_A_INTR_LEVEL1 (0x0A1)
+#define TAIKO_A_INTR_LEVEL1__POR (0x00)
+#define TAIKO_A_INTR_LEVEL2 (0x0A2)
+#define TAIKO_A_INTR_LEVEL2__POR (0x00)
+#define TAIKO_A_INTR_LEVEL3 (0x0A3)
+#define TAIKO_A_INTR_LEVEL3__POR (0x00)
+#define TAIKO_A_INTR_TEST0 (0x0A4)
+#define TAIKO_A_INTR_TEST0__POR (0x00)
+#define TAIKO_A_INTR_TEST1 (0x0A5)
+#define TAIKO_A_INTR_TEST1__POR (0x00)
+#define TAIKO_A_INTR_TEST2 (0x0A6)
+#define TAIKO_A_INTR_TEST2__POR (0x00)
+#define TAIKO_A_INTR_TEST3 (0x0A7)
+#define TAIKO_A_INTR_TEST3__POR (0x00)
+#define TAIKO_A_INTR_SET0 (0x0A8)
+#define TAIKO_A_INTR_SET0__POR (0x00)
+#define TAIKO_A_INTR_SET1 (0x0A9)
+#define TAIKO_A_INTR_SET1__POR (0x00)
+#define TAIKO_A_INTR_SET2 (0x0AA)
+#define TAIKO_A_INTR_SET2__POR (0x00)
+#define TAIKO_A_INTR_SET3 (0x0AB)
+#define TAIKO_A_INTR_SET3__POR (0x00)
+#define TAIKO_A_INTR_DESTN0 (0x0AC)
+#define TAIKO_A_INTR_DESTN0__POR (0x00)
+#define TAIKO_A_INTR_DESTN1 (0x0AD)
+#define TAIKO_A_INTR_DESTN1__POR (0x00)
+#define TAIKO_A_INTR_DESTN2 (0x0AE)
+#define TAIKO_A_INTR_DESTN2__POR (0x00)
+#define TAIKO_A_INTR_DESTN3 (0x0AF)
+#define TAIKO_A_INTR_DESTN3__POR (0x00)
+#define TAIKO_A_CDC_TX_I2S_SCK_MODE (0x0C0)
+#define TAIKO_A_CDC_TX_I2S_SCK_MODE__POR (0x00)
+#define TAIKO_A_CDC_TX_I2S_WS_MODE (0x0C1)
+#define TAIKO_A_CDC_TX_I2S_WS_MODE__POR (0x00)
+#define TAIKO_A_CDC_DMIC_DATA0_MODE (0x0C4)
+#define TAIKO_A_CDC_DMIC_DATA0_MODE__POR (0x00)
+#define TAIKO_A_CDC_DMIC_CLK0_MODE (0x0C5)
+#define TAIKO_A_CDC_DMIC_CLK0_MODE__POR (0x00)
+#define TAIKO_A_CDC_DMIC_DATA1_MODE (0x0C6)
+#define TAIKO_A_CDC_DMIC_DATA1_MODE__POR (0x00)
+#define TAIKO_A_CDC_DMIC_CLK1_MODE (0x0C7)
+#define TAIKO_A_CDC_DMIC_CLK1_MODE__POR (0x00)
+#define TAIKO_A_CDC_RX_I2S_SCK_MODE (0x0C8)
+#define TAIKO_A_CDC_RX_I2S_SCK_MODE__POR (0x00)
+#define TAIKO_A_CDC_RX_I2S_WS_MODE (0x0C9)
+#define TAIKO_A_CDC_RX_I2S_WS_MODE__POR (0x00)
+#define TAIKO_A_CDC_DMIC_DATA2_MODE (0x0CA)
+#define TAIKO_A_CDC_DMIC_DATA2_MODE__POR (0x00)
+#define TAIKO_A_CDC_DMIC_CLK2_MODE (0x0CB)
+#define TAIKO_A_CDC_DMIC_CLK2_MODE__POR (0x00)
+#define TAIKO_A_CDC_INTR1_MODE (0x0CC)
+#define TAIKO_A_CDC_INTR1_MODE__POR (0x00)
+#define TAIKO_A_CDC_SB_NRZ_SEL_MODE (0x0CD)
+#define TAIKO_A_CDC_SB_NRZ_SEL_MODE__POR (0x00)
+#define TAIKO_A_CDC_INTR2_MODE (0x0CE)
+#define TAIKO_A_CDC_INTR2_MODE__POR (0x00)
+#define TAIKO_A_CDC_RF_PA_ON_MODE (0x0CF)
+#define TAIKO_A_CDC_RF_PA_ON_MODE__POR (0x00)
+#define TAIKO_A_BIAS_REF_CTL (0x100)
+#define TAIKO_A_BIAS_REF_CTL__POR (0x1C)
+#define TAIKO_A_BIAS_CENTRAL_BG_CTL (0x101)
+#define TAIKO_A_BIAS_CENTRAL_BG_CTL__POR (0x50)
+#define TAIKO_A_BIAS_PRECHRG_CTL (0x102)
+#define TAIKO_A_BIAS_PRECHRG_CTL__POR (0x07)
+#define TAIKO_A_BIAS_CURR_CTL_1 (0x103)
+#define TAIKO_A_BIAS_CURR_CTL_1__POR (0x52)
+#define TAIKO_A_BIAS_CURR_CTL_2 (0x104)
+#define TAIKO_A_BIAS_CURR_CTL_2__POR (0x00)
+#define TAIKO_A_BIAS_OSC_BG_CTL (0x105)
+#define TAIKO_A_BIAS_OSC_BG_CTL__POR (0x16)
+#define TAIKO_A_CLK_BUFF_EN1 (0x108)
+#define TAIKO_A_CLK_BUFF_EN1__POR (0x04)
+#define TAIKO_A_CLK_BUFF_EN2 (0x109)
+#define TAIKO_A_CLK_BUFF_EN2__POR (0x02)
+#define TAIKO_A_LDO_H_MODE_1 (0x110)
+#define TAIKO_A_LDO_H_MODE_1__POR (0x65)
+#define TAIKO_A_LDO_H_MODE_2 (0x111)
+#define TAIKO_A_LDO_H_MODE_2__POR (0xA8)
+#define TAIKO_A_LDO_H_LOOP_CTL (0x112)
+#define TAIKO_A_LDO_H_LOOP_CTL__POR (0x6B)
+#define TAIKO_A_LDO_H_COMP_1 (0x113)
+#define TAIKO_A_LDO_H_COMP_1__POR (0x84)
+#define TAIKO_A_LDO_H_COMP_2 (0x114)
+#define TAIKO_A_LDO_H_COMP_2__POR (0xE0)
+#define TAIKO_A_LDO_H_BIAS_1 (0x115)
+#define TAIKO_A_LDO_H_BIAS_1__POR (0x6D)
+#define TAIKO_A_LDO_H_BIAS_2 (0x116)
+#define TAIKO_A_LDO_H_BIAS_2__POR (0xA5)
+#define TAIKO_A_LDO_H_BIAS_3 (0x117)
+#define TAIKO_A_LDO_H_BIAS_3__POR (0x60)
+#define TAIKO_A_VBAT_CLK (0x118)
+#define TAIKO_A_VBAT_CLK__POR (0x03)
+#define TAIKO_A_VBAT_LOOP (0x119)
+#define TAIKO_A_VBAT_LOOP__POR (0x02)
+#define TAIKO_A_VBAT_REF (0x11A)
+#define TAIKO_A_VBAT_REF__POR (0x20)
+#define TAIKO_A_VBAT_ADC_TEST (0x11B)
+#define TAIKO_A_VBAT_ADC_TEST__POR (0x00)
+#define TAIKO_A_VBAT_FE (0x11C)
+#define TAIKO_A_VBAT_FE__POR (0x48)
+#define TAIKO_A_VBAT_BIAS_1 (0x11D)
+#define TAIKO_A_VBAT_BIAS_1__POR (0x03)
+#define TAIKO_A_VBAT_BIAS_2 (0x11E)
+#define TAIKO_A_VBAT_BIAS_2__POR (0x00)
+#define TAIKO_A_VBAT_ADC_DATA_MSB (0x11F)
+#define TAIKO_A_VBAT_ADC_DATA_MSB__POR (0x00)
+#define TAIKO_A_VBAT_ADC_DATA_LSB (0x120)
+#define TAIKO_A_VBAT_ADC_DATA_LSB__POR (0x00)
+#define TAIKO_A_MICB_CFILT_1_CTL (0x128)
+#define TAIKO_A_MICB_CFILT_1_CTL__POR (0x40)
+#define TAIKO_A_MICB_CFILT_1_VAL (0x129)
+#define TAIKO_A_MICB_CFILT_1_VAL__POR (0x80)
+#define TAIKO_A_MICB_CFILT_1_PRECHRG (0x12A)
+#define TAIKO_A_MICB_CFILT_1_PRECHRG__POR (0x38)
+#define TAIKO_A_MICB_1_CTL (0x12B)
+#define TAIKO_A_MICB_1_CTL__POR (0x16)
+#define TAIKO_A_MICB_1_INT_RBIAS (0x12C)
+#define TAIKO_A_MICB_1_INT_RBIAS__POR (0x24)
+#define TAIKO_A_MICB_1_MBHC (0x12D)
+#define TAIKO_A_MICB_1_MBHC__POR (0x01)
+#define TAIKO_A_MICB_CFILT_2_CTL (0x12E)
+#define TAIKO_A_MICB_CFILT_2_CTL__POR (0x40)
+#define TAIKO_A_MICB_CFILT_2_VAL (0x12F)
+#define TAIKO_A_MICB_CFILT_2_VAL__POR (0x80)
+#define TAIKO_A_MICB_CFILT_2_PRECHRG (0x130)
+#define TAIKO_A_MICB_CFILT_2_PRECHRG__POR (0x38)
+#define TAIKO_A_MICB_2_CTL (0x131)
+#define TAIKO_A_MICB_2_CTL__POR (0x16)
+#define TAIKO_A_MICB_2_INT_RBIAS (0x132)
+#define TAIKO_A_MICB_2_INT_RBIAS__POR (0x24)
+#define TAIKO_A_MICB_2_MBHC (0x133)
+#define TAIKO_A_MICB_2_MBHC__POR (0x02)
+#define TAIKO_A_MICB_CFILT_3_CTL (0x134)
+#define TAIKO_A_MICB_CFILT_3_CTL__POR (0x40)
+#define TAIKO_A_MICB_CFILT_3_VAL (0x135)
+#define TAIKO_A_MICB_CFILT_3_VAL__POR (0x80)
+#define TAIKO_A_MICB_CFILT_3_PRECHRG (0x136)
+#define TAIKO_A_MICB_CFILT_3_PRECHRG__POR (0x38)
+#define TAIKO_A_MICB_3_CTL (0x137)
+#define TAIKO_A_MICB_3_CTL__POR (0x16)
+#define TAIKO_A_MICB_3_INT_RBIAS (0x138)
+#define TAIKO_A_MICB_3_INT_RBIAS__POR (0x24)
+#define TAIKO_A_MICB_3_MBHC (0x139)
+#define TAIKO_A_MICB_3_MBHC__POR (0x00)
+#define TAIKO_A_MICB_4_CTL (0x13D)
+#define TAIKO_A_MICB_4_CTL__POR (0x16)
+#define TAIKO_A_MICB_4_INT_RBIAS (0x13E)
+#define TAIKO_A_MICB_4_INT_RBIAS__POR (0x24)
+#define TAIKO_A_MICB_4_MBHC (0x13F)
+#define TAIKO_A_MICB_4_MBHC__POR (0x01)
+#define TAIKO_A_MBHC_INSERT_DETECT (0x14A)
+#define TAIKO_A_MBHC_INSERT_DETECT__POR (0x00)
+#define TAIKO_A_MBHC_INSERT_DET_STATUS (0x14B)
+#define TAIKO_A_MBHC_INSERT_DET_STATUS__POR (0x00)
+#define TAIKO_A_TX_COM_BIAS (0x14C)
+#define TAIKO_A_TX_COM_BIAS__POR (0xF0)
+#define TAIKO_A_MBHC_SCALING_MUX_1 (0x14E)
+#define TAIKO_A_MBHC_SCALING_MUX_1__POR (0x00)
+#define TAIKO_A_MBHC_SCALING_MUX_2 (0x14F)
+#define TAIKO_A_MBHC_SCALING_MUX_2__POR (0x80)
+#define TAIKO_A_MAD_ANA_CTRL (0x150)
+#define TAIKO_A_MAD_ANA_CTRL__POR (0xF1)
+#define TAIKO_A_TX_SUP_SWITCH_CTRL_1 (0x151)
+#define TAIKO_A_TX_SUP_SWITCH_CTRL_1__POR (0x00)
+#define TAIKO_A_TX_SUP_SWITCH_CTRL_2 (0x152)
+#define TAIKO_A_TX_SUP_SWITCH_CTRL_2__POR (0x80)
+#define TAIKO_A_TX_1_2_EN (0x153)
+#define TAIKO_A_TX_1_2_EN__POR (0x00)
+#define TAIKO_A_TX_1_2_TEST_EN (0x154)
+#define TAIKO_A_TX_1_2_TEST_EN__POR (0xCC)
+#define TAIKO_A_TX_1_2_ADC_CH1 (0x155)
+#define TAIKO_A_TX_1_2_ADC_CH1__POR (0x44)
+#define TAIKO_A_TX_1_2_ADC_CH2 (0x156)
+#define TAIKO_A_TX_1_2_ADC_CH2__POR (0x44)
+#define TAIKO_A_TX_1_2_ATEST_REFCTRL (0x157)
+#define TAIKO_A_TX_1_2_ATEST_REFCTRL__POR (0x00)
+#define TAIKO_A_TX_1_2_TEST_CTL (0x158)
+#define TAIKO_A_TX_1_2_TEST_CTL__POR (0x38)
+#define TAIKO_A_TX_1_2_TEST_BLOCK_EN (0x159)
+#define TAIKO_A_TX_1_2_TEST_BLOCK_EN__POR (0xFC)
+#define TAIKO_A_TX_1_2_TXFE_CLKDIV (0x15A)
+#define TAIKO_A_TX_1_2_TXFE_CLKDIV__POR (0x55)
+#define TAIKO_A_TX_1_2_SAR_ERR_CH1 (0x15B)
+#define TAIKO_A_TX_1_2_SAR_ERR_CH1__POR (0x00)
+#define TAIKO_A_TX_1_2_SAR_ERR_CH2 (0x15C)
+#define TAIKO_A_TX_1_2_SAR_ERR_CH2__POR (0x00)
+#define TAIKO_A_TX_3_4_EN (0x15D)
+#define TAIKO_A_TX_3_4_EN__POR (0x00)
+#define TAIKO_A_TX_3_4_TEST_EN (0x15E)
+#define TAIKO_A_TX_3_4_TEST_EN__POR (0xCC)
+#define TAIKO_A_TX_3_4_ADC_CH3 (0x15F)
+#define TAIKO_A_TX_3_4_ADC_CH3__POR (0x44)
+#define TAIKO_A_TX_3_4_ADC_CH4 (0x160)
+#define TAIKO_A_TX_3_4_ADC_CH4__POR (0x44)
+#define TAIKO_A_TX_3_4_ATEST_REFCTRL (0x161)
+#define TAIKO_A_TX_3_4_ATEST_REFCTRL__POR (0x00)
+#define TAIKO_A_TX_3_4_TEST_CTL (0x162)
+#define TAIKO_A_TX_3_4_TEST_CTL__POR (0x38)
+#define TAIKO_A_TX_3_4_TEST_BLOCK_EN (0x163)
+#define TAIKO_A_TX_3_4_TEST_BLOCK_EN__POR (0xFC)
+#define TAIKO_A_TX_3_4_TXFE_CKDIV (0x164)
+#define TAIKO_A_TX_3_4_TXFE_CKDIV__POR (0x55)
+#define TAIKO_A_TX_3_4_SAR_ERR_CH3 (0x165)
+#define TAIKO_A_TX_3_4_SAR_ERR_CH3__POR (0x00)
+#define TAIKO_A_TX_3_4_SAR_ERR_CH4 (0x166)
+#define TAIKO_A_TX_3_4_SAR_ERR_CH4__POR (0x00)
+#define TAIKO_A_TX_5_6_EN (0x167)
+#define TAIKO_A_TX_5_6_EN__POR (0x11)
+#define TAIKO_A_TX_5_6_TEST_EN (0x168)
+#define TAIKO_A_TX_5_6_TEST_EN__POR (0xCC)
+#define TAIKO_A_TX_5_6_ADC_CH5 (0x169)
+#define TAIKO_A_TX_5_6_ADC_CH5__POR (0x44)
+#define TAIKO_A_TX_5_6_ADC_CH6 (0x16A)
+#define TAIKO_A_TX_5_6_ADC_CH6__POR (0x44)
+#define TAIKO_A_TX_5_6_ATEST_REFCTRL (0x16B)
+#define TAIKO_A_TX_5_6_ATEST_REFCTRL__POR (0x00)
+#define TAIKO_A_TX_5_6_TEST_CTL (0x16C)
+#define TAIKO_A_TX_5_6_TEST_CTL__POR (0x38)
+#define TAIKO_A_TX_5_6_TEST_BLOCK_EN (0x16D)
+#define TAIKO_A_TX_5_6_TEST_BLOCK_EN__POR (0xFC)
+#define TAIKO_A_TX_5_6_TXFE_CKDIV (0x16E)
+#define TAIKO_A_TX_5_6_TXFE_CKDIV__POR (0x55)
+#define TAIKO_A_TX_5_6_SAR_ERR_CH5 (0x16F)
+#define TAIKO_A_TX_5_6_SAR_ERR_CH5__POR (0x00)
+#define TAIKO_A_TX_5_6_SAR_ERR_CH6 (0x170)
+#define TAIKO_A_TX_5_6_SAR_ERR_CH6__POR (0x00)
+#define TAIKO_A_TX_7_MBHC_EN (0x171)
+#define TAIKO_A_TX_7_MBHC_EN__POR (0x0C)
+#define TAIKO_A_TX_7_MBHC_ATEST_REFCTRL (0x172)
+#define TAIKO_A_TX_7_MBHC_ATEST_REFCTRL__POR (0x00)
+#define TAIKO_A_TX_7_MBHC_ADC (0x173)
+#define TAIKO_A_TX_7_MBHC_ADC__POR (0x44)
+#define TAIKO_A_TX_7_MBHC_TEST_CTL (0x174)
+#define TAIKO_A_TX_7_MBHC_TEST_CTL__POR (0x38)
+#define TAIKO_A_TX_7_MBHC_SAR_ERR (0x175)
+#define TAIKO_A_TX_7_MBHC_SAR_ERR__POR (0x00)
+#define TAIKO_A_TX_7_TXFE_CLKDIV (0x176)
+#define TAIKO_A_TX_7_TXFE_CLKDIV__POR (0x0B)
+#define TAIKO_A_BUCK_MODE_1 (0x181)
+#define TAIKO_A_BUCK_MODE_1__POR (0x21)
+#define TAIKO_A_BUCK_MODE_2 (0x182)
+#define TAIKO_A_BUCK_MODE_2__POR (0xFF)
+#define TAIKO_A_BUCK_MODE_3 (0x183)
+#define TAIKO_A_BUCK_MODE_3__POR (0xCC)
+#define TAIKO_A_BUCK_MODE_4 (0x184)
+#define TAIKO_A_BUCK_MODE_4__POR (0x3A)
+#define TAIKO_A_BUCK_MODE_5 (0x185)
+#define TAIKO_A_BUCK_MODE_5__POR (0x00)
+#define TAIKO_A_BUCK_CTRL_VCL_1 (0x186)
+#define TAIKO_A_BUCK_CTRL_VCL_1__POR (0x48)
+#define TAIKO_A_BUCK_CTRL_VCL_2 (0x187)
+#define TAIKO_A_BUCK_CTRL_VCL_2__POR (0xA3)
+#define TAIKO_A_BUCK_CTRL_VCL_3 (0x188)
+#define TAIKO_A_BUCK_CTRL_VCL_3__POR (0x82)
+#define TAIKO_A_BUCK_CTRL_CCL_1 (0x189)
+#define TAIKO_A_BUCK_CTRL_CCL_1__POR (0xAB)
+#define TAIKO_A_BUCK_CTRL_CCL_2 (0x18A)
+#define TAIKO_A_BUCK_CTRL_CCL_2__POR (0xDC)
+#define TAIKO_A_BUCK_CTRL_CCL_3 (0x18B)
+#define TAIKO_A_BUCK_CTRL_CCL_3__POR (0x6A)
+#define TAIKO_A_BUCK_CTRL_CCL_4 (0x18C)
+#define TAIKO_A_BUCK_CTRL_CCL_4__POR (0x58)
+#define TAIKO_A_BUCK_CTRL_PWM_DRVR_1 (0x18D)
+#define TAIKO_A_BUCK_CTRL_PWM_DRVR_1__POR (0x50)
+#define TAIKO_A_BUCK_CTRL_PWM_DRVR_2 (0x18E)
+#define TAIKO_A_BUCK_CTRL_PWM_DRVR_2__POR (0x64)
+#define TAIKO_A_BUCK_CTRL_PWM_DRVR_3 (0x18F)
+#define TAIKO_A_BUCK_CTRL_PWM_DRVR_3__POR (0x77)
+#define TAIKO_A_BUCK_TMUX_A_D (0x190)
+#define TAIKO_A_BUCK_TMUX_A_D__POR (0x00)
+#define TAIKO_A_NCP_BUCKREF (0x191)
+#define TAIKO_A_NCP_BUCKREF__POR (0x00)
+#define TAIKO_A_NCP_EN (0x192)
+#define TAIKO_A_NCP_EN__POR (0xFE)
+#define TAIKO_A_NCP_CLK (0x193)
+#define TAIKO_A_NCP_CLK__POR (0x94)
+#define TAIKO_A_NCP_STATIC (0x194)
+#define TAIKO_A_NCP_STATIC__POR (0x28)
+#define TAIKO_A_NCP_VTH_LOW (0x195)
+#define TAIKO_A_NCP_VTH_LOW__POR (0x88)
+#define TAIKO_A_NCP_VTH_HIGH (0x196)
+#define TAIKO_A_NCP_VTH_HIGH__POR (0xA0)
+#define TAIKO_A_NCP_ATEST (0x197)
+#define TAIKO_A_NCP_ATEST__POR (0x00)
+#define TAIKO_A_NCP_DTEST (0x198)
+#define TAIKO_A_NCP_DTEST__POR (0x00)
+#define TAIKO_A_NCP_DLY1 (0x199)
+#define TAIKO_A_NCP_DLY1__POR (0x06)
+#define TAIKO_A_NCP_DLY2 (0x19A)
+#define TAIKO_A_NCP_DLY2__POR (0x06)
+#define TAIKO_A_RX_AUX_SW_CTL (0x19B)
+#define TAIKO_A_RX_AUX_SW_CTL__POR (0x00)
+#define TAIKO_A_RX_PA_AUX_IN_CONN (0x19C)
+#define TAIKO_A_RX_PA_AUX_IN_CONN__POR (0x00)
+#define TAIKO_A_RX_COM_TIMER_DIV (0x19E)
+#define TAIKO_A_RX_COM_TIMER_DIV__POR (0xE8)
+#define TAIKO_A_RX_COM_OCP_CTL (0x19F)
+#define TAIKO_A_RX_COM_OCP_CTL__POR (0x1F)
+#define TAIKO_A_RX_COM_OCP_COUNT (0x1A0)
+#define TAIKO_A_RX_COM_OCP_COUNT__POR (0x77)
+#define TAIKO_A_RX_COM_DAC_CTL (0x1A1)
+#define TAIKO_A_RX_COM_DAC_CTL__POR (0x00)
+#define TAIKO_A_RX_COM_BIAS (0x1A2)
+#define TAIKO_A_RX_COM_BIAS__POR (0x00)
+#define TAIKO_A_RX_HPH_AUTO_CHOP (0x1A4)
+#define TAIKO_A_RX_HPH_AUTO_CHOP__POR (0x38)
+#define TAIKO_A_RX_HPH_CHOP_CTL (0x1A5)
+#define TAIKO_A_RX_HPH_CHOP_CTL__POR (0xB4)
+#define TAIKO_A_RX_HPH_BIAS_PA (0x1A6)
+#define TAIKO_A_RX_HPH_BIAS_PA__POR (0xAA)
+#define TAIKO_A_RX_HPH_BIAS_LDO (0x1A7)
+#define TAIKO_A_RX_HPH_BIAS_LDO__POR (0x87)
+#define TAIKO_A_RX_HPH_BIAS_CNP (0x1A8)
+#define TAIKO_A_RX_HPH_BIAS_CNP__POR (0x8A)
+#define TAIKO_A_RX_HPH_BIAS_WG_OCP (0x1A9)
+#define TAIKO_A_RX_HPH_BIAS_WG_OCP__POR (0x2A)
+#define TAIKO_A_RX_HPH_OCP_CTL (0x1AA)
+#define TAIKO_A_RX_HPH_OCP_CTL__POR (0x68)
+#define TAIKO_A_RX_HPH_CNP_EN (0x1AB)
+#define TAIKO_A_RX_HPH_CNP_EN__POR (0x80)
+#define TAIKO_A_RX_HPH_CNP_WG_CTL (0x1AC)
+#define TAIKO_A_RX_HPH_CNP_WG_CTL__POR (0xDE)
+#define TAIKO_A_RX_HPH_CNP_WG_TIME (0x1AD)
+#define TAIKO_A_RX_HPH_CNP_WG_TIME__POR (0x2A)
+#define TAIKO_A_RX_HPH_L_GAIN (0x1AE)
+#define TAIKO_A_RX_HPH_L_GAIN__POR (0x00)
+#define TAIKO_A_RX_HPH_L_TEST (0x1AF)
+#define TAIKO_A_RX_HPH_L_TEST__POR (0x00)
+#define TAIKO_A_RX_HPH_L_PA_CTL (0x1B0)
+#define TAIKO_A_RX_HPH_L_PA_CTL__POR (0x40)
+#define TAIKO_A_RX_HPH_L_DAC_CTL (0x1B1)
+#define TAIKO_A_RX_HPH_L_DAC_CTL__POR (0x00)
+#define TAIKO_A_RX_HPH_L_ATEST (0x1B2)
+#define TAIKO_A_RX_HPH_L_ATEST__POR (0x00)
+#define TAIKO_A_RX_HPH_L_STATUS (0x1B3)
+#define TAIKO_A_RX_HPH_L_STATUS__POR (0x00)
+#define TAIKO_A_RX_HPH_R_GAIN (0x1B4)
+#define TAIKO_A_RX_HPH_R_GAIN__POR (0x00)
+#define TAIKO_A_RX_HPH_R_TEST (0x1B5)
+#define TAIKO_A_RX_HPH_R_TEST__POR (0x00)
+#define TAIKO_A_RX_HPH_R_PA_CTL (0x1B6)
+#define TAIKO_A_RX_HPH_R_PA_CTL__POR (0x40)
+#define TAIKO_A_RX_HPH_R_DAC_CTL (0x1B7)
+#define TAIKO_A_RX_HPH_R_DAC_CTL__POR (0x00)
+#define TAIKO_A_RX_HPH_R_ATEST (0x1B8)
+#define TAIKO_A_RX_HPH_R_ATEST__POR (0x00)
+#define TAIKO_A_RX_HPH_R_STATUS (0x1B9)
+#define TAIKO_A_RX_HPH_R_STATUS__POR (0x00)
+#define TAIKO_A_RX_EAR_BIAS_PA (0x1BA)
+#define TAIKO_A_RX_EAR_BIAS_PA__POR (0xA6)
+#define TAIKO_A_RX_EAR_BIAS_CMBUFF (0x1BB)
+#define TAIKO_A_RX_EAR_BIAS_CMBUFF__POR (0xA0)
+#define TAIKO_A_RX_EAR_EN (0x1BC)
+#define TAIKO_A_RX_EAR_EN__POR (0x00)
+#define TAIKO_A_RX_EAR_GAIN (0x1BD)
+#define TAIKO_A_RX_EAR_GAIN__POR (0x02)
+#define TAIKO_A_RX_EAR_CMBUFF (0x1BE)
+#define TAIKO_A_RX_EAR_CMBUFF__POR (0x04)
+#define TAIKO_A_RX_EAR_ICTL (0x1BF)
+#define TAIKO_A_RX_EAR_ICTL__POR (0x40)
+#define TAIKO_A_RX_EAR_CCOMP (0x1C0)
+#define TAIKO_A_RX_EAR_CCOMP__POR (0x08)
+#define TAIKO_A_RX_EAR_VCM (0x1C1)
+#define TAIKO_A_RX_EAR_VCM__POR (0x03)
+#define TAIKO_A_RX_EAR_CNP (0x1C2)
+#define TAIKO_A_RX_EAR_CNP__POR (0xF2)
+#define TAIKO_A_RX_EAR_DAC_CTL_ATEST (0x1C3)
+#define TAIKO_A_RX_EAR_DAC_CTL_ATEST__POR (0x00)
+#define TAIKO_A_RX_EAR_STATUS (0x1C5)
+#define TAIKO_A_RX_EAR_STATUS__POR (0x04)
+#define TAIKO_A_RX_LINE_BIAS_PA (0x1C6)
+#define TAIKO_A_RX_LINE_BIAS_PA__POR (0xA8)
+#define TAIKO_A_RX_BUCK_BIAS1 (0x1C7)
+#define TAIKO_A_RX_BUCK_BIAS1__POR (0x42)
+#define TAIKO_A_RX_BUCK_BIAS2 (0x1C8)
+#define TAIKO_A_RX_BUCK_BIAS2__POR (0x84)
+#define TAIKO_A_RX_LINE_COM (0x1C9)
+#define TAIKO_A_RX_LINE_COM__POR (0x80)
+#define TAIKO_A_RX_LINE_CNP_EN (0x1CA)
+#define TAIKO_A_RX_LINE_CNP_EN__POR (0x00)
+#define TAIKO_A_RX_LINE_CNP_WG_CTL (0x1CB)
+#define TAIKO_A_RX_LINE_CNP_WG_CTL__POR (0x00)
+#define TAIKO_A_RX_LINE_CNP_WG_TIME (0x1CC)
+#define TAIKO_A_RX_LINE_CNP_WG_TIME__POR (0x04)
+#define TAIKO_A_RX_LINE_1_GAIN (0x1CD)
+#define TAIKO_A_RX_LINE_1_GAIN__POR (0x00)
+#define TAIKO_A_RX_LINE_1_TEST (0x1CE)
+#define TAIKO_A_RX_LINE_1_TEST__POR (0x00)
+#define TAIKO_A_RX_LINE_1_DAC_CTL (0x1CF)
+#define TAIKO_A_RX_LINE_1_DAC_CTL__POR (0x00)
+#define TAIKO_A_RX_LINE_1_STATUS (0x1D0)
+#define TAIKO_A_RX_LINE_1_STATUS__POR (0x00)
+#define TAIKO_A_RX_LINE_2_GAIN (0x1D1)
+#define TAIKO_A_RX_LINE_2_GAIN__POR (0x00)
+#define TAIKO_A_RX_LINE_2_TEST (0x1D2)
+#define TAIKO_A_RX_LINE_2_TEST__POR (0x00)
+#define TAIKO_A_RX_LINE_2_DAC_CTL (0x1D3)
+#define TAIKO_A_RX_LINE_2_DAC_CTL__POR (0x00)
+#define TAIKO_A_RX_LINE_2_STATUS (0x1D4)
+#define TAIKO_A_RX_LINE_2_STATUS__POR (0x00)
+#define TAIKO_A_RX_LINE_3_GAIN (0x1D5)
+#define TAIKO_A_RX_LINE_3_GAIN__POR (0x00)
+#define TAIKO_A_RX_LINE_3_TEST (0x1D6)
+#define TAIKO_A_RX_LINE_3_TEST__POR (0x00)
+#define TAIKO_A_RX_LINE_3_DAC_CTL (0x1D7)
+#define TAIKO_A_RX_LINE_3_DAC_CTL__POR (0x00)
+#define TAIKO_A_RX_LINE_3_STATUS (0x1D8)
+#define TAIKO_A_RX_LINE_3_STATUS__POR (0x00)
+#define TAIKO_A_RX_LINE_4_GAIN (0x1D9)
+#define TAIKO_A_RX_LINE_4_GAIN__POR (0x00)
+#define TAIKO_A_RX_LINE_4_TEST (0x1DA)
+#define TAIKO_A_RX_LINE_4_TEST__POR (0x00)
+#define TAIKO_A_RX_LINE_4_DAC_CTL (0x1DB)
+#define TAIKO_A_RX_LINE_4_DAC_CTL__POR (0x00)
+#define TAIKO_A_RX_LINE_4_STATUS (0x1DC)
+#define TAIKO_A_RX_LINE_4_STATUS__POR (0x00)
+#define TAIKO_A_RX_LINE_CNP_DBG (0x1DD)
+#define TAIKO_A_RX_LINE_CNP_DBG__POR (0x00)
+#define TAIKO_A_SPKR_DRV_EN (0x1DF)
+#define TAIKO_A_SPKR_DRV_EN__POR (0x6F)
+#define TAIKO_A_SPKR_DRV_GAIN (0x1E0)
+#define TAIKO_A_SPKR_DRV_GAIN__POR (0x00)
+#define TAIKO_A_SPKR_DRV_DAC_CTL (0x1E1)
+#define TAIKO_A_SPKR_DRV_DAC_CTL__POR (0x04)
+#define TAIKO_A_SPKR_DRV_OCP_CTL (0x1E2)
+#define TAIKO_A_SPKR_DRV_OCP_CTL__POR (0x98)
+#define TAIKO_A_SPKR_DRV_CLIP_DET (0x1E3)
+#define TAIKO_A_SPKR_DRV_CLIP_DET__POR (0x48)
+#define TAIKO_A_SPKR_DRV_IEC (0x1E4)
+#define TAIKO_A_SPKR_DRV_IEC__POR (0x20)
+#define TAIKO_A_SPKR_DRV_DBG_DAC (0x1E5)
+#define TAIKO_A_SPKR_DRV_DBG_DAC__POR (0x05)
+#define TAIKO_A_SPKR_DRV_DBG_PA (0x1E6)
+#define TAIKO_A_SPKR_DRV_DBG_PA__POR (0x18)
+#define TAIKO_A_SPKR_DRV_DBG_PWRSTG (0x1E7)
+#define TAIKO_A_SPKR_DRV_DBG_PWRSTG__POR (0x00)
+#define TAIKO_A_SPKR_DRV_BIAS_LDO (0x1E8)
+#define TAIKO_A_SPKR_DRV_BIAS_LDO__POR (0x45)
+#define TAIKO_A_SPKR_DRV_BIAS_INT (0x1E9)
+#define TAIKO_A_SPKR_DRV_BIAS_INT__POR (0xA5)
+#define TAIKO_A_SPKR_DRV_BIAS_PA (0x1EA)
+#define TAIKO_A_SPKR_DRV_BIAS_PA__POR (0x55)
+#define TAIKO_A_SPKR_DRV_STATUS_OCP (0x1EB)
+#define TAIKO_A_SPKR_DRV_STATUS_OCP__POR (0x00)
+#define TAIKO_A_SPKR_DRV_STATUS_PA (0x1EC)
+#define TAIKO_A_SPKR_DRV_STATUS_PA__POR (0x00)
+#define TAIKO_A_SPKR_PROT_EN (0x1ED)
+#define TAIKO_A_SPKR_PROT_EN__POR (0x00)
+#define TAIKO_A_SPKR_PROT_ADC_EN (0x1EE)
+#define TAIKO_A_SPKR_PROT_ADC_EN__POR (0x44)
+#define TAIKO_A_SPKR_PROT_ISENSE_BIAS (0x1EF)
+#define TAIKO_A_SPKR_PROT_ISENSE_BIAS__POR (0x44)
+#define TAIKO_A_SPKR_PROT_VSENSE_BIAS (0x1F0)
+#define TAIKO_A_SPKR_PROT_VSENSE_BIAS__POR (0x44)
+#define TAIKO_A_SPKR_PROT_ADC_ATEST_REFCTRL (0x1F1)
+#define TAIKO_A_SPKR_PROT_ADC_ATEST_REFCTRL__POR (0x00)
+#define TAIKO_A_SPKR_PROT_ADC_TEST_CTL (0x1F2)
+#define TAIKO_A_SPKR_PROT_ADC_TEST_CTL__POR (0x38)
+#define TAIKO_A_SPKR_PROT_TEST_BLOCK_EN (0x1F3)
+#define TAIKO_A_SPKR_PROT_TEST_BLOCK_EN__POR (0xFC)
+#define TAIKO_A_SPKR_PROT_ATEST (0x1F4)
+#define TAIKO_A_SPKR_PROT_ATEST__POR (0x00)
+#define TAIKO_A_SPKR_PROT_V_SAR_ERR (0x1F5)
+#define TAIKO_A_SPKR_PROT_V_SAR_ERR__POR (0x00)
+#define TAIKO_A_SPKR_PROT_I_SAR_ERR (0x1F6)
+#define TAIKO_A_SPKR_PROT_I_SAR_ERR__POR (0x00)
+#define TAIKO_A_SPKR_PROT_LDO_CTRL (0x1F7)
+#define TAIKO_A_SPKR_PROT_LDO_CTRL__POR (0x00)
+#define TAIKO_A_SPKR_PROT_ISENSE_CTRL (0x1F8)
+#define TAIKO_A_SPKR_PROT_ISENSE_CTRL__POR (0x00)
+#define TAIKO_A_SPKR_PROT_VSENSE_CTRL (0x1F9)
+#define TAIKO_A_SPKR_PROT_VSENSE_CTRL__POR (0x00)
+#define TAIKO_A_RC_OSC_FREQ (0x1FA)
+#define TAIKO_A_RC_OSC_FREQ__POR (0x46)
+#define TAIKO_A_RC_OSC_TEST (0x1FB)
+#define TAIKO_A_RC_OSC_TEST__POR (0x0A)
+#define TAIKO_A_RC_OSC_STATUS (0x1FC)
+#define TAIKO_A_RC_OSC_STATUS__POR (0x18)
+#define TAIKO_A_RC_OSC_TUNER (0x1FD)
+#define TAIKO_A_RC_OSC_TUNER__POR (0x00)
+#define TAIKO_A_MBHC_HPH (0x1FE)
+#define TAIKO_A_MBHC_HPH__POR (0x44)
+#define TAIKO_A_CDC_ANC1_B1_CTL (0x200)
+#define TAIKO_A_CDC_ANC1_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_B1_CTL (0x280)
+#define TAIKO_A_CDC_ANC2_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_SHIFT (0x201)
+#define TAIKO_A_CDC_ANC1_SHIFT__POR (0x00)
+#define TAIKO_A_CDC_ANC2_SHIFT (0x281)
+#define TAIKO_A_CDC_ANC2_SHIFT__POR (0x00)
+#define TAIKO_A_CDC_ANC1_IIR_B1_CTL (0x202)
+#define TAIKO_A_CDC_ANC1_IIR_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_IIR_B1_CTL (0x282)
+#define TAIKO_A_CDC_ANC2_IIR_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_IIR_B2_CTL (0x203)
+#define TAIKO_A_CDC_ANC1_IIR_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_IIR_B2_CTL (0x283)
+#define TAIKO_A_CDC_ANC2_IIR_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_IIR_B3_CTL (0x204)
+#define TAIKO_A_CDC_ANC1_IIR_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_IIR_B3_CTL (0x284)
+#define TAIKO_A_CDC_ANC2_IIR_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_LPF_B1_CTL (0x206)
+#define TAIKO_A_CDC_ANC1_LPF_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_LPF_B1_CTL (0x286)
+#define TAIKO_A_CDC_ANC2_LPF_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_LPF_B2_CTL (0x207)
+#define TAIKO_A_CDC_ANC1_LPF_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_LPF_B2_CTL (0x287)
+#define TAIKO_A_CDC_ANC2_LPF_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_SPARE (0x209)
+#define TAIKO_A_CDC_ANC1_SPARE__POR (0x00)
+#define TAIKO_A_CDC_ANC2_SPARE (0x289)
+#define TAIKO_A_CDC_ANC2_SPARE__POR (0x00)
+#define TAIKO_A_CDC_ANC1_SMLPF_CTL (0x20A)
+#define TAIKO_A_CDC_ANC1_SMLPF_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_SMLPF_CTL (0x28A)
+#define TAIKO_A_CDC_ANC2_SMLPF_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_DCFLT_CTL (0x20B)
+#define TAIKO_A_CDC_ANC1_DCFLT_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_DCFLT_CTL (0x28B)
+#define TAIKO_A_CDC_ANC2_DCFLT_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_GAIN_CTL (0x20C)
+#define TAIKO_A_CDC_ANC1_GAIN_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_GAIN_CTL (0x28C)
+#define TAIKO_A_CDC_ANC2_GAIN_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC1_B2_CTL (0x20D)
+#define TAIKO_A_CDC_ANC1_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_ANC2_B2_CTL (0x28D)
+#define TAIKO_A_CDC_ANC2_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX1_VOL_CTL_TIMER (0x220)
+#define TAIKO_A_CDC_TX1_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX2_VOL_CTL_TIMER (0x228)
+#define TAIKO_A_CDC_TX2_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX3_VOL_CTL_TIMER (0x230)
+#define TAIKO_A_CDC_TX3_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX4_VOL_CTL_TIMER (0x238)
+#define TAIKO_A_CDC_TX4_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX5_VOL_CTL_TIMER (0x240)
+#define TAIKO_A_CDC_TX5_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX6_VOL_CTL_TIMER (0x248)
+#define TAIKO_A_CDC_TX6_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX7_VOL_CTL_TIMER (0x250)
+#define TAIKO_A_CDC_TX7_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX8_VOL_CTL_TIMER (0x258)
+#define TAIKO_A_CDC_TX8_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX9_VOL_CTL_TIMER (0x260)
+#define TAIKO_A_CDC_TX9_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX10_VOL_CTL_TIMER (0x268)
+#define TAIKO_A_CDC_TX10_VOL_CTL_TIMER__POR (0x00)
+#define TAIKO_A_CDC_TX1_VOL_CTL_GAIN (0x221)
+#define TAIKO_A_CDC_TX1_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX2_VOL_CTL_GAIN (0x229)
+#define TAIKO_A_CDC_TX2_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX3_VOL_CTL_GAIN (0x231)
+#define TAIKO_A_CDC_TX3_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX4_VOL_CTL_GAIN (0x239)
+#define TAIKO_A_CDC_TX4_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX5_VOL_CTL_GAIN (0x241)
+#define TAIKO_A_CDC_TX5_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX6_VOL_CTL_GAIN (0x249)
+#define TAIKO_A_CDC_TX6_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX7_VOL_CTL_GAIN (0x251)
+#define TAIKO_A_CDC_TX7_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX8_VOL_CTL_GAIN (0x259)
+#define TAIKO_A_CDC_TX8_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX9_VOL_CTL_GAIN (0x261)
+#define TAIKO_A_CDC_TX9_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX10_VOL_CTL_GAIN (0x269)
+#define TAIKO_A_CDC_TX10_VOL_CTL_GAIN__POR (0x00)
+#define TAIKO_A_CDC_TX1_VOL_CTL_CFG (0x222)
+#define TAIKO_A_CDC_TX1_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX2_VOL_CTL_CFG (0x22A)
+#define TAIKO_A_CDC_TX2_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX3_VOL_CTL_CFG (0x232)
+#define TAIKO_A_CDC_TX3_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX4_VOL_CTL_CFG (0x23A)
+#define TAIKO_A_CDC_TX4_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX5_VOL_CTL_CFG (0x242)
+#define TAIKO_A_CDC_TX5_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX6_VOL_CTL_CFG (0x24A)
+#define TAIKO_A_CDC_TX6_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX7_VOL_CTL_CFG (0x252)
+#define TAIKO_A_CDC_TX7_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX8_VOL_CTL_CFG (0x25A)
+#define TAIKO_A_CDC_TX8_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX9_VOL_CTL_CFG (0x262)
+#define TAIKO_A_CDC_TX9_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX10_VOL_CTL_CFG (0x26A)
+#define TAIKO_A_CDC_TX10_VOL_CTL_CFG__POR (0x00)
+#define TAIKO_A_CDC_TX1_MUX_CTL (0x223)
+#define TAIKO_A_CDC_TX1_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX2_MUX_CTL (0x22B)
+#define TAIKO_A_CDC_TX2_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX3_MUX_CTL (0x233)
+#define TAIKO_A_CDC_TX3_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX4_MUX_CTL (0x23B)
+#define TAIKO_A_CDC_TX4_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX5_MUX_CTL (0x243)
+#define TAIKO_A_CDC_TX5_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX6_MUX_CTL (0x24B)
+#define TAIKO_A_CDC_TX6_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX7_MUX_CTL (0x253)
+#define TAIKO_A_CDC_TX7_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX8_MUX_CTL (0x25B)
+#define TAIKO_A_CDC_TX8_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX9_MUX_CTL (0x263)
+#define TAIKO_A_CDC_TX9_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX10_MUX_CTL (0x26B)
+#define TAIKO_A_CDC_TX10_MUX_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX1_CLK_FS_CTL (0x224)
+#define TAIKO_A_CDC_TX1_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX2_CLK_FS_CTL (0x22C)
+#define TAIKO_A_CDC_TX2_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX3_CLK_FS_CTL (0x234)
+#define TAIKO_A_CDC_TX3_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX4_CLK_FS_CTL (0x23C)
+#define TAIKO_A_CDC_TX4_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX5_CLK_FS_CTL (0x244)
+#define TAIKO_A_CDC_TX5_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX6_CLK_FS_CTL (0x24C)
+#define TAIKO_A_CDC_TX6_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX7_CLK_FS_CTL (0x254)
+#define TAIKO_A_CDC_TX7_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX8_CLK_FS_CTL (0x25C)
+#define TAIKO_A_CDC_TX8_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX9_CLK_FS_CTL (0x264)
+#define TAIKO_A_CDC_TX9_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX10_CLK_FS_CTL (0x26C)
+#define TAIKO_A_CDC_TX10_CLK_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX1_DMIC_CTL (0x225)
+#define TAIKO_A_CDC_TX1_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX2_DMIC_CTL (0x22D)
+#define TAIKO_A_CDC_TX2_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX3_DMIC_CTL (0x235)
+#define TAIKO_A_CDC_TX3_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX4_DMIC_CTL (0x23D)
+#define TAIKO_A_CDC_TX4_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX5_DMIC_CTL (0x245)
+#define TAIKO_A_CDC_TX5_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX6_DMIC_CTL (0x24D)
+#define TAIKO_A_CDC_TX6_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX7_DMIC_CTL (0x255)
+#define TAIKO_A_CDC_TX7_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX8_DMIC_CTL (0x25D)
+#define TAIKO_A_CDC_TX8_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX9_DMIC_CTL (0x265)
+#define TAIKO_A_CDC_TX9_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_TX10_DMIC_CTL (0x26D)
+#define TAIKO_A_CDC_TX10_DMIC_CTL__POR (0x00)
+#define TAIKO_A_CDC_DEBUG_B1_CTL (0x278)
+#define TAIKO_A_CDC_DEBUG_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_DEBUG_B2_CTL (0x279)
+#define TAIKO_A_CDC_DEBUG_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_DEBUG_B3_CTL (0x27A)
+#define TAIKO_A_CDC_DEBUG_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_DEBUG_B4_CTL (0x27B)
+#define TAIKO_A_CDC_DEBUG_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_DEBUG_B5_CTL (0x27C)
+#define TAIKO_A_CDC_DEBUG_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_DEBUG_B6_CTL (0x27D)
+#define TAIKO_A_CDC_DEBUG_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_DEBUG_B7_CTL (0x27E)
+#define TAIKO_A_CDC_DEBUG_B7_CTL__POR (0x00)
+#define TAIKO_A_CDC_SRC1_PDA_CFG (0x2A0)
+#define TAIKO_A_CDC_SRC1_PDA_CFG__POR (0x00)
+#define TAIKO_A_CDC_SRC2_PDA_CFG (0x2A8)
+#define TAIKO_A_CDC_SRC2_PDA_CFG__POR (0x00)
+#define TAIKO_A_CDC_SRC1_FS_CTL (0x2A1)
+#define TAIKO_A_CDC_SRC1_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_SRC2_FS_CTL (0x2A9)
+#define TAIKO_A_CDC_SRC2_FS_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B1_CTL (0x2B0)
+#define TAIKO_A_CDC_RX1_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B1_CTL (0x2B8)
+#define TAIKO_A_CDC_RX2_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B1_CTL (0x2C0)
+#define TAIKO_A_CDC_RX3_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B1_CTL (0x2C8)
+#define TAIKO_A_CDC_RX4_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B1_CTL (0x2D0)
+#define TAIKO_A_CDC_RX5_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B1_CTL (0x2D8)
+#define TAIKO_A_CDC_RX6_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B1_CTL (0x2E0)
+#define TAIKO_A_CDC_RX7_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B2_CTL (0x2B1)
+#define TAIKO_A_CDC_RX1_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B2_CTL (0x2B9)
+#define TAIKO_A_CDC_RX2_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B2_CTL (0x2C1)
+#define TAIKO_A_CDC_RX3_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B2_CTL (0x2C9)
+#define TAIKO_A_CDC_RX4_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B2_CTL (0x2D1)
+#define TAIKO_A_CDC_RX5_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B2_CTL (0x2D9)
+#define TAIKO_A_CDC_RX6_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B2_CTL (0x2E1)
+#define TAIKO_A_CDC_RX7_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B3_CTL (0x2B2)
+#define TAIKO_A_CDC_RX1_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B3_CTL (0x2BA)
+#define TAIKO_A_CDC_RX2_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B3_CTL (0x2C2)
+#define TAIKO_A_CDC_RX3_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B3_CTL (0x2CA)
+#define TAIKO_A_CDC_RX4_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B3_CTL (0x2D2)
+#define TAIKO_A_CDC_RX5_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B3_CTL (0x2DA)
+#define TAIKO_A_CDC_RX6_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B3_CTL (0x2E2)
+#define TAIKO_A_CDC_RX7_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B4_CTL (0x2B3)
+#define TAIKO_A_CDC_RX1_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B4_CTL (0x2BB)
+#define TAIKO_A_CDC_RX2_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B4_CTL (0x2C3)
+#define TAIKO_A_CDC_RX3_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B4_CTL (0x2CB)
+#define TAIKO_A_CDC_RX4_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B4_CTL (0x2D3)
+#define TAIKO_A_CDC_RX5_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B4_CTL (0x2DB)
+#define TAIKO_A_CDC_RX6_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B4_CTL (0x2E3)
+#define TAIKO_A_CDC_RX7_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B5_CTL (0x2B4)
+#define TAIKO_A_CDC_RX1_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B5_CTL (0x2BC)
+#define TAIKO_A_CDC_RX2_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B5_CTL (0x2C4)
+#define TAIKO_A_CDC_RX3_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B5_CTL (0x2CC)
+#define TAIKO_A_CDC_RX4_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B5_CTL (0x2D4)
+#define TAIKO_A_CDC_RX5_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B5_CTL (0x2DC)
+#define TAIKO_A_CDC_RX6_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B5_CTL (0x2E4)
+#define TAIKO_A_CDC_RX7_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_B6_CTL (0x2B5)
+#define TAIKO_A_CDC_RX1_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_B6_CTL (0x2BD)
+#define TAIKO_A_CDC_RX2_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_B6_CTL (0x2C5)
+#define TAIKO_A_CDC_RX3_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_B6_CTL (0x2CD)
+#define TAIKO_A_CDC_RX4_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_B6_CTL (0x2D5)
+#define TAIKO_A_CDC_RX5_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_B6_CTL (0x2DD)
+#define TAIKO_A_CDC_RX6_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_B6_CTL (0x2E5)
+#define TAIKO_A_CDC_RX7_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL (0x2B6)
+#define TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL (0x2BE)
+#define TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_VOL_CTL_B1_CTL (0x2C6)
+#define TAIKO_A_CDC_RX3_VOL_CTL_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_VOL_CTL_B1_CTL (0x2CE)
+#define TAIKO_A_CDC_RX4_VOL_CTL_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_VOL_CTL_B1_CTL (0x2D6)
+#define TAIKO_A_CDC_RX5_VOL_CTL_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_VOL_CTL_B1_CTL (0x2DE)
+#define TAIKO_A_CDC_RX6_VOL_CTL_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_VOL_CTL_B1_CTL (0x2E6)
+#define TAIKO_A_CDC_RX7_VOL_CTL_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL (0x2B7)
+#define TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL (0x2BF)
+#define TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL (0x2C7)
+#define TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL (0x2CF)
+#define TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL (0x2D7)
+#define TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL (0x2DF)
+#define TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL (0x2E7)
+#define TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_VBAT_CFG (0x2E8)
+#define TAIKO_A_CDC_VBAT_CFG__POR (0x1A)
+#define TAIKO_A_CDC_VBAT_ADC_CAL1 (0x2E9)
+#define TAIKO_A_CDC_VBAT_ADC_CAL1__POR (0x00)
+#define TAIKO_A_CDC_VBAT_ADC_CAL2 (0x2EA)
+#define TAIKO_A_CDC_VBAT_ADC_CAL2__POR (0x00)
+#define TAIKO_A_CDC_VBAT_ADC_CAL3 (0x2EB)
+#define TAIKO_A_CDC_VBAT_ADC_CAL3__POR (0x04)
+#define TAIKO_A_CDC_VBAT_PK_EST1 (0x2EC)
+#define TAIKO_A_CDC_VBAT_PK_EST1__POR (0xE0)
+#define TAIKO_A_CDC_VBAT_PK_EST2 (0x2ED)
+#define TAIKO_A_CDC_VBAT_PK_EST2__POR (0x01)
+#define TAIKO_A_CDC_VBAT_PK_EST3 (0x2EE)
+#define TAIKO_A_CDC_VBAT_PK_EST3__POR (0x40)
+#define TAIKO_A_CDC_VBAT_RF_PROC1 (0x2EF)
+#define TAIKO_A_CDC_VBAT_RF_PROC1__POR (0x2A)
+#define TAIKO_A_CDC_VBAT_RF_PROC2 (0x2F0)
+#define TAIKO_A_CDC_VBAT_RF_PROC2__POR (0x86)
+#define TAIKO_A_CDC_VBAT_TAC1 (0x2F1)
+#define TAIKO_A_CDC_VBAT_TAC1__POR (0x70)
+#define TAIKO_A_CDC_VBAT_TAC2 (0x2F2)
+#define TAIKO_A_CDC_VBAT_TAC2__POR (0x18)
+#define TAIKO_A_CDC_VBAT_TAC3 (0x2F3)
+#define TAIKO_A_CDC_VBAT_TAC3__POR (0x18)
+#define TAIKO_A_CDC_VBAT_TAC4 (0x2F4)
+#define TAIKO_A_CDC_VBAT_TAC4__POR (0x03)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD1 (0x2F5)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD1__POR (0x01)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD2 (0x2F6)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD2__POR (0x00)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD3 (0x2F7)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD3__POR (0x64)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD4 (0x2F8)
+#define TAIKO_A_CDC_VBAT_GAIN_UPD4__POR (0x01)
+#define TAIKO_A_CDC_VBAT_DEBUG1 (0x2F9)
+#define TAIKO_A_CDC_VBAT_DEBUG1__POR (0x00)
+#define TAIKO_A_CDC_CLK_ANC_RESET_CTL (0x300)
+#define TAIKO_A_CDC_CLK_ANC_RESET_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_RX_RESET_CTL (0x301)
+#define TAIKO_A_CDC_CLK_RX_RESET_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_TX_RESET_B1_CTL (0x302)
+#define TAIKO_A_CDC_CLK_TX_RESET_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_TX_RESET_B2_CTL (0x303)
+#define TAIKO_A_CDC_CLK_TX_RESET_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_DMIC_B1_CTL (0x304)
+#define TAIKO_A_CDC_CLK_DMIC_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_DMIC_B2_CTL (0x305)
+#define TAIKO_A_CDC_CLK_DMIC_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_RX_I2S_CTL (0x306)
+#define TAIKO_A_CDC_CLK_RX_I2S_CTL__POR (0x03)
+#define TAIKO_A_CDC_CLK_TX_I2S_CTL (0x307)
+#define TAIKO_A_CDC_CLK_TX_I2S_CTL__POR (0x03)
+#define TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL (0x308)
+#define TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_OTHR_RESET_B2_CTL (0x309)
+#define TAIKO_A_CDC_CLK_OTHR_RESET_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL (0x30A)
+#define TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL (0x30B)
+#define TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_OTHR_CTL (0x30C)
+#define TAIKO_A_CDC_CLK_OTHR_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL (0x30D)
+#define TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_ANC_CLK_EN_CTL (0x30E)
+#define TAIKO_A_CDC_CLK_ANC_CLK_EN_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_RX_B1_CTL (0x30F)
+#define TAIKO_A_CDC_CLK_RX_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_RX_B2_CTL (0x310)
+#define TAIKO_A_CDC_CLK_RX_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_MCLK_CTL (0x311)
+#define TAIKO_A_CDC_CLK_MCLK_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_PDM_CTL (0x312)
+#define TAIKO_A_CDC_CLK_PDM_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_SD_CTL (0x313)
+#define TAIKO_A_CDC_CLK_SD_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLK_POWER_CTL (0x314)
+#define TAIKO_A_CDC_CLK_POWER_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLSH_B1_CTL (0x320)
+#define TAIKO_A_CDC_CLSH_B1_CTL__POR (0xE4)
+#define TAIKO_A_CDC_CLSH_B2_CTL (0x321)
+#define TAIKO_A_CDC_CLSH_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLSH_B3_CTL (0x322)
+#define TAIKO_A_CDC_CLSH_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CLSH_BUCK_NCP_VARS (0x323)
+#define TAIKO_A_CDC_CLSH_BUCK_NCP_VARS__POR (0x00)
+#define TAIKO_A_CDC_CLSH_IDLE_HPH_THSD (0x324)
+#define TAIKO_A_CDC_CLSH_IDLE_HPH_THSD__POR (0x12)
+#define TAIKO_A_CDC_CLSH_IDLE_EAR_THSD (0x325)
+#define TAIKO_A_CDC_CLSH_IDLE_EAR_THSD__POR (0x0C)
+#define TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD (0x326)
+#define TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR (0x18)
+#define TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD (0x327)
+#define TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR (0x23)
+#define TAIKO_A_CDC_CLSH_K_ADDR (0x328)
+#define TAIKO_A_CDC_CLSH_K_ADDR__POR (0x00)
+#define TAIKO_A_CDC_CLSH_K_DATA (0x329)
+#define TAIKO_A_CDC_CLSH_K_DATA__POR (0xA4)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L (0x32A)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L__POR (0xD7)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U (0x32B)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U__POR (0x05)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L (0x32C)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L__POR (0x60)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U (0x32D)
+#define TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U__POR (0x09)
+#define TAIKO_A_CDC_CLSH_V_PA_HD_EAR (0x32E)
+#define TAIKO_A_CDC_CLSH_V_PA_HD_EAR__POR (0x00)
+#define TAIKO_A_CDC_CLSH_V_PA_HD_HPH (0x32F)
+#define TAIKO_A_CDC_CLSH_V_PA_HD_HPH__POR (0x00)
+#define TAIKO_A_CDC_CLSH_V_PA_MIN_EAR (0x330)
+#define TAIKO_A_CDC_CLSH_V_PA_MIN_EAR__POR (0x00)
+#define TAIKO_A_CDC_CLSH_V_PA_MIN_HPH (0x331)
+#define TAIKO_A_CDC_CLSH_V_PA_MIN_HPH__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B1_CTL (0x340)
+#define TAIKO_A_CDC_IIR1_GAIN_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B1_CTL (0x350)
+#define TAIKO_A_CDC_IIR2_GAIN_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B2_CTL (0x341)
+#define TAIKO_A_CDC_IIR1_GAIN_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B2_CTL (0x351)
+#define TAIKO_A_CDC_IIR2_GAIN_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B3_CTL (0x342)
+#define TAIKO_A_CDC_IIR1_GAIN_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B3_CTL (0x352)
+#define TAIKO_A_CDC_IIR2_GAIN_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B4_CTL (0x343)
+#define TAIKO_A_CDC_IIR1_GAIN_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B4_CTL (0x353)
+#define TAIKO_A_CDC_IIR2_GAIN_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B5_CTL (0x344)
+#define TAIKO_A_CDC_IIR1_GAIN_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B5_CTL (0x354)
+#define TAIKO_A_CDC_IIR2_GAIN_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B6_CTL (0x345)
+#define TAIKO_A_CDC_IIR1_GAIN_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B6_CTL (0x355)
+#define TAIKO_A_CDC_IIR2_GAIN_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B7_CTL (0x346)
+#define TAIKO_A_CDC_IIR1_GAIN_B7_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B7_CTL (0x356)
+#define TAIKO_A_CDC_IIR2_GAIN_B7_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_B8_CTL (0x347)
+#define TAIKO_A_CDC_IIR1_GAIN_B8_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_B8_CTL (0x357)
+#define TAIKO_A_CDC_IIR2_GAIN_B8_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_CTL (0x348)
+#define TAIKO_A_CDC_IIR1_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_CTL (0x358)
+#define TAIKO_A_CDC_IIR2_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL (0x349)
+#define TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL (0x359)
+#define TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_COEF_B1_CTL (0x34A)
+#define TAIKO_A_CDC_IIR1_COEF_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_COEF_B1_CTL (0x35A)
+#define TAIKO_A_CDC_IIR2_COEF_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR1_COEF_B2_CTL (0x34B)
+#define TAIKO_A_CDC_IIR1_COEF_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_IIR2_COEF_B2_CTL (0x35B)
+#define TAIKO_A_CDC_IIR2_COEF_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_TOP_GAIN_UPDATE (0x360)
+#define TAIKO_A_CDC_TOP_GAIN_UPDATE__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B1_CTL (0x368)
+#define TAIKO_A_CDC_COMP0_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B1_CTL (0x370)
+#define TAIKO_A_CDC_COMP1_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B1_CTL (0x378)
+#define TAIKO_A_CDC_COMP2_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B2_CTL (0x369)
+#define TAIKO_A_CDC_COMP0_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B2_CTL (0x371)
+#define TAIKO_A_CDC_COMP1_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B2_CTL (0x379)
+#define TAIKO_A_CDC_COMP2_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B3_CTL (0x36A)
+#define TAIKO_A_CDC_COMP0_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B3_CTL (0x372)
+#define TAIKO_A_CDC_COMP1_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B3_CTL (0x37A)
+#define TAIKO_A_CDC_COMP2_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B4_CTL (0x36B)
+#define TAIKO_A_CDC_COMP0_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B4_CTL (0x373)
+#define TAIKO_A_CDC_COMP1_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B4_CTL (0x37B)
+#define TAIKO_A_CDC_COMP2_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B5_CTL (0x36C)
+#define TAIKO_A_CDC_COMP0_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B5_CTL (0x374)
+#define TAIKO_A_CDC_COMP1_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B5_CTL (0x37C)
+#define TAIKO_A_CDC_COMP2_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_B6_CTL (0x36D)
+#define TAIKO_A_CDC_COMP0_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP1_B6_CTL (0x375)
+#define TAIKO_A_CDC_COMP1_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP2_B6_CTL (0x37D)
+#define TAIKO_A_CDC_COMP2_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS (0x36E)
+#define TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR (0x00)
+#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS (0x376)
+#define TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x00)
+#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS (0x37E)
+#define TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x00)
+#define TAIKO_A_CDC_COMP0_FS_CFG (0x36F)
+#define TAIKO_A_CDC_COMP0_FS_CFG__POR (0x00)
+#define TAIKO_A_CDC_COMP1_FS_CFG (0x377)
+#define TAIKO_A_CDC_COMP1_FS_CFG__POR (0x00)
+#define TAIKO_A_CDC_COMP2_FS_CFG (0x37F)
+#define TAIKO_A_CDC_COMP2_FS_CFG__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX1_B1_CTL (0x380)
+#define TAIKO_A_CDC_CONN_RX1_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX1_B2_CTL (0x381)
+#define TAIKO_A_CDC_CONN_RX1_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX1_B3_CTL (0x382)
+#define TAIKO_A_CDC_CONN_RX1_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX2_B1_CTL (0x383)
+#define TAIKO_A_CDC_CONN_RX2_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX2_B2_CTL (0x384)
+#define TAIKO_A_CDC_CONN_RX2_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX2_B3_CTL (0x385)
+#define TAIKO_A_CDC_CONN_RX2_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX3_B1_CTL (0x386)
+#define TAIKO_A_CDC_CONN_RX3_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX3_B2_CTL (0x387)
+#define TAIKO_A_CDC_CONN_RX3_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX4_B1_CTL (0x388)
+#define TAIKO_A_CDC_CONN_RX4_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX4_B2_CTL (0x389)
+#define TAIKO_A_CDC_CONN_RX4_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX5_B1_CTL (0x38A)
+#define TAIKO_A_CDC_CONN_RX5_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX5_B2_CTL (0x38B)
+#define TAIKO_A_CDC_CONN_RX5_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX6_B1_CTL (0x38C)
+#define TAIKO_A_CDC_CONN_RX6_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX6_B2_CTL (0x38D)
+#define TAIKO_A_CDC_CONN_RX6_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX7_B1_CTL (0x38E)
+#define TAIKO_A_CDC_CONN_RX7_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX7_B2_CTL (0x38F)
+#define TAIKO_A_CDC_CONN_RX7_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX7_B3_CTL (0x390)
+#define TAIKO_A_CDC_CONN_RX7_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_ANC_B1_CTL (0x391)
+#define TAIKO_A_CDC_CONN_ANC_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_ANC_B2_CTL (0x392)
+#define TAIKO_A_CDC_CONN_ANC_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_B1_CTL (0x393)
+#define TAIKO_A_CDC_CONN_TX_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_B2_CTL (0x394)
+#define TAIKO_A_CDC_CONN_TX_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_B3_CTL (0x395)
+#define TAIKO_A_CDC_CONN_TX_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_B4_CTL (0x396)
+#define TAIKO_A_CDC_CONN_TX_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ1_B1_CTL (0x397)
+#define TAIKO_A_CDC_CONN_EQ1_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ1_B2_CTL (0x398)
+#define TAIKO_A_CDC_CONN_EQ1_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ1_B3_CTL (0x399)
+#define TAIKO_A_CDC_CONN_EQ1_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ1_B4_CTL (0x39A)
+#define TAIKO_A_CDC_CONN_EQ1_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ2_B1_CTL (0x39B)
+#define TAIKO_A_CDC_CONN_EQ2_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ2_B2_CTL (0x39C)
+#define TAIKO_A_CDC_CONN_EQ2_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ2_B3_CTL (0x39D)
+#define TAIKO_A_CDC_CONN_EQ2_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_EQ2_B4_CTL (0x39E)
+#define TAIKO_A_CDC_CONN_EQ2_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_SRC1_B1_CTL (0x39F)
+#define TAIKO_A_CDC_CONN_SRC1_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_SRC1_B2_CTL (0x3A0)
+#define TAIKO_A_CDC_CONN_SRC1_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_SRC2_B1_CTL (0x3A1)
+#define TAIKO_A_CDC_CONN_SRC2_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_SRC2_B2_CTL (0x3A2)
+#define TAIKO_A_CDC_CONN_SRC2_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B1_CTL (0x3A3)
+#define TAIKO_A_CDC_CONN_TX_SB_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B2_CTL (0x3A4)
+#define TAIKO_A_CDC_CONN_TX_SB_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B3_CTL (0x3A5)
+#define TAIKO_A_CDC_CONN_TX_SB_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B4_CTL (0x3A6)
+#define TAIKO_A_CDC_CONN_TX_SB_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B5_CTL (0x3A7)
+#define TAIKO_A_CDC_CONN_TX_SB_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B6_CTL (0x3A8)
+#define TAIKO_A_CDC_CONN_TX_SB_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B7_CTL (0x3A9)
+#define TAIKO_A_CDC_CONN_TX_SB_B7_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B8_CTL (0x3AA)
+#define TAIKO_A_CDC_CONN_TX_SB_B8_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B9_CTL (0x3AB)
+#define TAIKO_A_CDC_CONN_TX_SB_B9_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B10_CTL (0x3AC)
+#define TAIKO_A_CDC_CONN_TX_SB_B10_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_TX_SB_B11_CTL (0x3AD)
+#define TAIKO_A_CDC_CONN_TX_SB_B11_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX_SB_B1_CTL (0x3AE)
+#define TAIKO_A_CDC_CONN_RX_SB_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_RX_SB_B2_CTL (0x3AF)
+#define TAIKO_A_CDC_CONN_RX_SB_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_CLSH_CTL (0x3B0)
+#define TAIKO_A_CDC_CONN_CLSH_CTL__POR (0x00)
+#define TAIKO_A_CDC_CONN_MISC (0x3B1)
+#define TAIKO_A_CDC_CONN_MISC__POR (0x01)
+#define TAIKO_A_CDC_CONN_MAD (0x3B2)
+#define TAIKO_A_CDC_CONN_MAD__POR (0x01)
+#define TAIKO_A_CDC_MBHC_EN_CTL (0x3C0)
+#define TAIKO_A_CDC_MBHC_EN_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_FIR_B1_CFG (0x3C1)
+#define TAIKO_A_CDC_MBHC_FIR_B1_CFG__POR (0x00)
+#define TAIKO_A_CDC_MBHC_FIR_B2_CFG (0x3C2)
+#define TAIKO_A_CDC_MBHC_FIR_B2_CFG__POR (0x06)
+#define TAIKO_A_CDC_MBHC_TIMER_B1_CTL (0x3C3)
+#define TAIKO_A_CDC_MBHC_TIMER_B1_CTL__POR (0x03)
+#define TAIKO_A_CDC_MBHC_TIMER_B2_CTL (0x3C4)
+#define TAIKO_A_CDC_MBHC_TIMER_B2_CTL__POR (0x09)
+#define TAIKO_A_CDC_MBHC_TIMER_B3_CTL (0x3C5)
+#define TAIKO_A_CDC_MBHC_TIMER_B3_CTL__POR (0x1E)
+#define TAIKO_A_CDC_MBHC_TIMER_B4_CTL (0x3C6)
+#define TAIKO_A_CDC_MBHC_TIMER_B4_CTL__POR (0x45)
+#define TAIKO_A_CDC_MBHC_TIMER_B5_CTL (0x3C7)
+#define TAIKO_A_CDC_MBHC_TIMER_B5_CTL__POR (0x04)
+#define TAIKO_A_CDC_MBHC_TIMER_B6_CTL (0x3C8)
+#define TAIKO_A_CDC_MBHC_TIMER_B6_CTL__POR (0x78)
+#define TAIKO_A_CDC_MBHC_B1_STATUS (0x3C9)
+#define TAIKO_A_CDC_MBHC_B1_STATUS__POR (0x00)
+#define TAIKO_A_CDC_MBHC_B2_STATUS (0x3CA)
+#define TAIKO_A_CDC_MBHC_B2_STATUS__POR (0x00)
+#define TAIKO_A_CDC_MBHC_B3_STATUS (0x3CB)
+#define TAIKO_A_CDC_MBHC_B3_STATUS__POR (0x00)
+#define TAIKO_A_CDC_MBHC_B4_STATUS (0x3CC)
+#define TAIKO_A_CDC_MBHC_B4_STATUS__POR (0x00)
+#define TAIKO_A_CDC_MBHC_B5_STATUS (0x3CD)
+#define TAIKO_A_CDC_MBHC_B5_STATUS__POR (0x00)
+#define TAIKO_A_CDC_MBHC_B1_CTL (0x3CE)
+#define TAIKO_A_CDC_MBHC_B1_CTL__POR (0xC0)
+#define TAIKO_A_CDC_MBHC_B2_CTL (0x3CF)
+#define TAIKO_A_CDC_MBHC_B2_CTL__POR (0x5D)
+#define TAIKO_A_CDC_MBHC_VOLT_B1_CTL (0x3D0)
+#define TAIKO_A_CDC_MBHC_VOLT_B1_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_VOLT_B2_CTL (0x3D1)
+#define TAIKO_A_CDC_MBHC_VOLT_B2_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_VOLT_B3_CTL (0x3D2)
+#define TAIKO_A_CDC_MBHC_VOLT_B3_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_VOLT_B4_CTL (0x3D3)
+#define TAIKO_A_CDC_MBHC_VOLT_B4_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_VOLT_B5_CTL (0x3D4)
+#define TAIKO_A_CDC_MBHC_VOLT_B5_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_VOLT_B6_CTL (0x3D5)
+#define TAIKO_A_CDC_MBHC_VOLT_B6_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_VOLT_B7_CTL (0x3D6)
+#define TAIKO_A_CDC_MBHC_VOLT_B7_CTL__POR (0xFF)
+#define TAIKO_A_CDC_MBHC_VOLT_B8_CTL (0x3D7)
+#define TAIKO_A_CDC_MBHC_VOLT_B8_CTL__POR (0x07)
+#define TAIKO_A_CDC_MBHC_VOLT_B9_CTL (0x3D8)
+#define TAIKO_A_CDC_MBHC_VOLT_B9_CTL__POR (0xFF)
+#define TAIKO_A_CDC_MBHC_VOLT_B10_CTL (0x3D9)
+#define TAIKO_A_CDC_MBHC_VOLT_B10_CTL__POR (0x7F)
+#define TAIKO_A_CDC_MBHC_VOLT_B11_CTL (0x3DA)
+#define TAIKO_A_CDC_MBHC_VOLT_B11_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_VOLT_B12_CTL (0x3DB)
+#define TAIKO_A_CDC_MBHC_VOLT_B12_CTL__POR (0x80)
+#define TAIKO_A_CDC_MBHC_CLK_CTL (0x3DC)
+#define TAIKO_A_CDC_MBHC_CLK_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_INT_CTL (0x3DD)
+#define TAIKO_A_CDC_MBHC_INT_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_DEBUG_CTL (0x3DE)
+#define TAIKO_A_CDC_MBHC_DEBUG_CTL__POR (0x00)
+#define TAIKO_A_CDC_MBHC_SPARE (0x3DF)
+#define TAIKO_A_CDC_MBHC_SPARE__POR (0x00)
+#define TAIKO_A_CDC_MAD_MAIN_CTL_1 (0x3E0)
+#define TAIKO_A_CDC_MAD_MAIN_CTL_1__POR (0x00)
+#define TAIKO_A_CDC_MAD_MAIN_CTL_2 (0x3E1)
+#define TAIKO_A_CDC_MAD_MAIN_CTL_2__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_1 (0x3E2)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_1__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_2 (0x3E3)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_2__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_3 (0x3E4)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_3__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_4 (0x3E5)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_4__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_5 (0x3E6)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_5__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_6 (0x3E7)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_6__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_7 (0x3E8)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_7__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_8 (0x3E9)
+#define TAIKO_A_CDC_MAD_AUDIO_CTL_8__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR (0x3EA)
+#define TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR__POR (0x00)
+#define TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL (0x3EB)
+#define TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL__POR (0x40)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_1 (0x3EC)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_1__POR (0x00)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_2 (0x3ED)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_2__POR (0x00)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_3 (0x3EE)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_3__POR (0x00)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_4 (0x3EF)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_4__POR (0x00)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_5 (0x3F0)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_5__POR (0x00)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_6 (0x3F1)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_6__POR (0x00)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_7 (0x3F2)
+#define TAIKO_A_CDC_MAD_ULTR_CTL_7__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_1 (0x3F3)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_1__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_2 (0x3F4)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_2__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_3 (0x3F5)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_3__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_4 (0x3F6)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_4__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_5 (0x3F7)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_5__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_6 (0x3F8)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_6__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_7 (0x3F9)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_7__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_8 (0x3FA)
+#define TAIKO_A_CDC_MAD_BEACON_CTL_8__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR (0x3FB)
+#define TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR__POR (0x00)
+#define TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL (0x3FC)
+#define TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL__POR (0x00)
+
+
+/* SLIMBUS Slave Registers */
+#define TAIKO_SLIM_PGD_PORT_INT_EN0 (0x30)
+#define TAIKO_SLIM_PGD_PORT_INT_STATUS0 (0x34)
+#define TAIKO_SLIM_PGD_PORT_INT_CLR0 (0x38)
+#define TAIKO_SLIM_PGD_PORT_INT_SOURCE0 (0x60)
+
+/* Macros for Packing Register Writes into a U32 */
+#define TAIKO_PACKED_REG_SIZE sizeof(u32)
+
+#define TAIKO_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\
+ ((mask & 0xff) << 8)|((reg & 0xffff) << 16))
+
+#define TAIKO_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+ do { \
+ ((reg) = ((packed >> 16) & (0xffff))); \
+ ((mask) = ((packed >> 8) & (0xff))); \
+ ((val) = ((packed) & (0xff))); \
+ } while (0);
+
+#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 3f6d994..19ca831 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -61,6 +61,10 @@
unsigned int generic_cmd6_time; /* Units: 10ms */
unsigned int power_off_longtime; /* Units: ms */
unsigned int hs_max_dtr;
+#define MMC_HIGH_26_MAX_DTR 26000000
+#define MMC_HIGH_52_MAX_DTR 52000000
+#define MMC_HIGH_DDR_MAX_DTR 52000000
+#define MMC_HS200_MAX_DTR 200000000
unsigned int sectors;
unsigned int card_type;
unsigned int hc_erase_size; /* In sectors */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 71484da..447fbbb 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -253,7 +253,6 @@
mmc_pm_flag_t pm_caps; /* supported pm features */
-#ifdef CONFIG_MMC_CLKGATE
int clk_requests; /* internal reference counter */
unsigned int clk_delay; /* number of MCI clk hold cycles */
bool clk_gated; /* clock gated */
@@ -263,7 +262,6 @@
struct mutex clk_gate_mutex; /* mutex for clock gating */
struct device_attribute clkgate_delay_attr;
unsigned long clkgate_delay;
-#endif
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 01f4991..b867c62 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -368,66 +368,6 @@
#define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */
-#define EXT_CSD_CARD_TYPE_SDR_200 (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_SDR_1_2V)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_ALL (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_ALL (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_DDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_DDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_DDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_DDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_2V | \
- EXT_CSD_CARD_TYPE_DDR_52 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_8V | \
- EXT_CSD_CARD_TYPE_DDR_52 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_DDR_1_8V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_DDR_1_2V | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
-#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52 (EXT_CSD_CARD_TYPE_SDR_200 | \
- EXT_CSD_CARD_TYPE_DDR_52 | \
- EXT_CSD_CARD_TYPE_52 | \
- EXT_CSD_CARD_TYPE_26)
-
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
diff --git a/include/linux/msm_ipc.h b/include/linux/msm_ipc.h
index 82f76a6..44fa8eb 100644
--- a/include/linux/msm_ipc.h
+++ b/include/linux/msm_ipc.h
@@ -62,12 +62,19 @@
#define IPC_ROUTER_IOCTL_BIND_CONTROL_PORT \
_IOR(IPC_ROUTER_IOCTL_MAGIC, 4, unsigned int)
+struct msm_ipc_server_info {
+ uint32_t node_id;
+ uint32_t port_id;
+ uint32_t service;
+ uint32_t instance;
+};
+
struct server_lookup_args {
struct msm_ipc_port_name port_name;
int num_entries_in_array;
int num_entries_found;
uint32_t lookup_mask;
- struct msm_ipc_port_addr port_addr[0];
+ struct msm_ipc_server_info srv_info[0];
};
#endif
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index a0af4b5..8b6351f 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -86,6 +86,8 @@
MDP_YCRYCB_H2V1, /* YCrYCb interleave */
MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */
MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */
+ MDP_Y_CRCB_H1V2,
+ MDP_Y_CBCR_H1V2,
MDP_RGBA_8888, /* ARGB 888 */
MDP_BGRA_8888, /* ABGR 888 */
MDP_RGBX_8888, /* RGBX 888 */
@@ -98,9 +100,10 @@
MDP_Y_CBCR_H1V1, /* Y and CbCr, pseduo planer w/ Cb is in MSB */
MDP_YCRCB_H1V1, /* YCrCb interleave */
MDP_YCBCR_H1V1, /* YCbCr interleave */
+ MDP_BGR_565, /* BGR 565 planer */
MDP_IMGTYPE_LIMIT,
- MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */
- MDP_FB_FORMAT, /* framebuffer format */
+ MDP_RGB_BORDERFILL, /* border fill pipe */
+ MDP_FB_FORMAT = MDP_IMGTYPE2_START, /* framebuffer format */
MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */
};
@@ -117,6 +120,8 @@
NUM_HSIC_PARAM,
};
+#define MDSS_MDP_RIGHT_MIXER 0x100
+
/* mdp_blit_req flag values */
#define MDP_ROT_NOP 0
#define MDP_FLIP_LR 0x1
diff --git a/include/linux/msm_vidc_dec.h b/include/linux/msm_vidc_dec.h
index 0c03e13..3d8907a 100644
--- a/include/linux/msm_vidc_dec.h
+++ b/include/linux/msm_vidc_dec.h
@@ -207,6 +207,9 @@
#define VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT \
_IOR(VDEC_IOCTL_MAGIC, 37, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_SET_PERF_CLK \
+ _IOR(VDEC_IOCTL_MAGIC, 38, struct vdec_ioctl_msg)
+
enum vdec_picture {
PICTURE_TYPE_I,
PICTURE_TYPE_P,
diff --git a/include/linux/tzcom.h b/include/linux/tzcom.h
deleted file mode 100644
index 448ab2a..0000000
--- a/include/linux/tzcom.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* Qualcomm TrustZone communicator API */
-
-#ifndef __TZCOM_H_
-#define __TZCOM_H_
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-#define MAX_ION_FD 4
-/**
- * struct tzcom_register_svc_op_req - for register service ioctl request
- * @svc_id - service id (shared between userspace and TZ)
- * @cmd_id_low - low number in cmd_id range (shared between userspace and TZ)
- * @cmd_id_high - high number in cmd_id range (shared between userspace and TZ)
- * @instance_id - unique id for the given service generated by tzcom driver
- */
-struct tzcom_register_svc_op_req {
- uint32_t svc_id; /* in */
- uint32_t cmd_id_low; /* in */
- uint32_t cmd_id_high; /* in */
- uint32_t instance_id; /* out */
-};
-
-/**
- * struct tzcom_unregister_svc_op_req - for unregister service ioctl request
- * @svc_id - service id to unregister (provided in register_service request)
- * @instance_id - instance id generated in register service request
- */
-struct tzcom_unregister_svc_op_req {
- uint32_t svc_id; /* in */
- uint32_t instance_id; /* in */
-};
-
-/**
- * struct tzcom_next_cmd_op_req - for read next command ioctl request
- * @svc_id - has to be a registered svc_id (see @tzcom_register_svc_op_req)
- * @instance_id - unique id for the given service (see @tzcom_register_svc_op_req)
- * @cmd_id - command to execute on the given service, received from TZ
- * @req_len - request buffer length, received from TZ
- * @req - request buffer, received from TZ
- */
-struct tzcom_next_cmd_op_req {
- uint32_t svc_id; /* in */
- uint32_t instance_id; /* in */
- uint32_t cmd_id; /* out */
- unsigned int req_len; /* in/out */
- void *req_buf; /* in/out */
-};
-
-/**
- * struct tzcom_send_cmd_op_req - for send command ioctl request
- * @cmd_id - command to execute on TZBSP side
- * @ifd_data_fd - ion handle to some memory allocated in user space
- * @cmd_buf_offset - command buffer offset
- * @cmd_len - command buffer length
- * @cmd_buf - command buffer
- * @resp_len - response buffer length
- * @resp_buf - response buffer
- */
-struct tzcom_send_cmd_op_req {
- uint32_t cmd_id; /* in */
- unsigned int cmd_len; /* in */
- void *cmd_buf; /* in */
- unsigned int resp_len; /* in/out */
- void *resp_buf; /* in/out */
-};
-
-/**
- * struct tzcom_ion_fd_info - ion fd handle data information
- * @fd - ion handle to some memory allocated in user space
- * @cmd_buf_offset - command buffer offset
- */
-struct tzcom_ion_fd_info {
- int32_t fd;
- uint32_t cmd_buf_offset;
-};
-
-/**
- * struct tzcom_send_cmd_op_req - for send command ioctl request
- * @cmd_id - command to execute on TZBSP side
- * @ifd_data_fd - ion handle to some memory allocated in user space
- * @cmd_buf_offset - command buffer offset
- * @cmd_len - command buffer length
- * @cmd_buf - command buffer
- * @resp_len - response buffer length
- * @resp_buf - response buffer
- */
-struct tzcom_send_cmd_fd_op_req {
- uint32_t cmd_id; /* in */
- struct tzcom_ion_fd_info ifd_data[MAX_ION_FD];
- unsigned int cmd_len; /* in */
- void *cmd_buf; /* in */
- unsigned int resp_len; /* in/out */
- void *resp_buf; /* in/out */
-};
-/**
- * struct tzcom_cont_cmd_op_req - for continue command ioctl request. used
- * as a trigger from HLOS service to notify TZCOM that it's done with its
- * operation and provide the response for TZCOM can continue the incomplete
- * command execution
- * @cmd_id - Command to continue filled in by tzcom as tzcom knows about the
- * last incomplete command.
- * @instance_id - Instance id of the svc
- * @resp_len - Length of the response
- * @resp_buf - Response buffer where the response of the cmd should go.
- */
-struct tzcom_cont_cmd_op_req {
- uint32_t cmd_id; /* out */
- uint32_t instance_id; /* in */
- unsigned int resp_len; /* in */
- void *resp_buf; /* in */
-};
-
-#define TZCOM_IOC_MAGIC 0x97
-
-/* For HLOS service */
-#define TZCOM_IOCTL_REGISTER_SERVICE_REQ \
- _IOWR(TZCOM_IOC_MAGIC, 1, struct tzcom_register_svc_op_req)
-/* For HLOS service */
-#define TZCOM_IOCTL_UNREGISTER_SERVICE_REQ \
- _IOWR(TZCOM_IOC_MAGIC, 2, struct tzcom_unregister_svc_op_req)
-/* For TZ service */
-#define TZCOM_IOCTL_SEND_CMD_REQ \
- _IOWR(TZCOM_IOC_MAGIC, 3, struct tzcom_send_cmd_op_req)
-/* For HLOS service */
-#define TZCOM_IOCTL_READ_NEXT_CMD_REQ \
- _IOWR(TZCOM_IOC_MAGIC, 4, struct tzcom_next_cmd_op_req)
-/* For TZ service */
-#define TZCOM_IOCTL_CONTINUE_CMD_REQ \
- _IOWR(TZCOM_IOC_MAGIC, 5, struct tzcom_cont_cmd_op_req)
-
-#define TZCOM_IOCTL_ABORT_REQ _IO(TZCOM_IOC_MAGIC, 6)
-/* For TZ service */
-#define TZCOM_IOCTL_SEND_CMD_FD_REQ \
- _IOWR(TZCOM_IOC_MAGIC, 7, struct tzcom_send_cmd_fd_op_req)
-#endif /* __TZCOM_H_ */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index e2a0392..5eb1845 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -24,6 +24,7 @@
#include <linux/usb/otg.h>
#include <linux/wakelock.h>
#include <linux/pm_qos.h>
+#include <linux/hrtimer.h>
/*
* The following are bit fields describing the usb_request.udc_priv word.
@@ -160,6 +161,16 @@
};
/**
+ * Used different VDDCX voltage values
+ */
+enum usb_vdd_value {
+ VDD_NONE = 0,
+ VDD_MIN,
+ VDD_MAX,
+ VDD_VAL_MAX,
+};
+
+/**
* struct msm_otg_platform_data - platform device data
* for msm_otg driver.
* @phy_init_seq: PHY configuration sequence. val, reg pairs
@@ -335,6 +346,7 @@
unsigned long lpm_flags;
#define PHY_PWR_COLLAPSED BIT(0)
#define PHY_RETENTIONED BIT(1)
+#define XO_SHUTDOWN BIT(2)
int reset_counter;
unsigned long b_last_se0_sess;
unsigned long tmouts;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index c148b75..63ebdea 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -401,6 +401,7 @@
#define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */
#define V4L2_PIX_FMT_DIVX_311 v4l2_fourcc('D', 'I', 'V', '3') /* DIVX311 */
#define V4L2_PIX_FMT_DIVX v4l2_fourcc('D', 'I', 'V', 'X') /* DIVX */
+#define V4L2_PIX_FMT_VP8 v4l2_fourcc('V', 'P', '8', '0') /* ON2 VP8 stream */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -1274,6 +1275,8 @@
/* last CID + 1 */
#define V4L2_CID_LASTP1 (V4L2_CID_BASE+42)
+#define V4L2_CID_SPECIAL_EFFECT (V4L2_CID_BASE+43)
+/* Minimum number of buffer neede by the device */
/* MPEG-class control IDs defined by V4L2 */
#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1641,6 +1644,10 @@
#define V4L2_CID_MPEG_QCOM_BASE (V4L2_CTRL_CLASS_MPEG | 0x2100)
#define V4L2_CID_MPEG_QCOM_SET_PERF_LEVEL (V4L2_CID_MPEG_QCOM_BASE + 0)
+enum v3l2_mpeg_qcom_perf_level {
+ V4L2_CID_MPEG_QCOM_PERF_LEVEL_PERFORMANCE = 0,
+ V4L2_CID_MPEG_QCOM_PERF_LEVEL_TURBO = 1,
+};
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_MPEG_MFC51_BASE+0)
#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_MPEG_MFC51_BASE+1)
@@ -2288,6 +2295,12 @@
#define V4L2_EVENT_FRAME_SYNC 4
#define V4L2_EVENT_PRIVATE_START 0x08000000
+#define V4L2_EVENT_MSM_VIDC_START (V4L2_EVENT_PRIVATE_START + 0x00001000)
+#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE (V4L2_EVENT_PRIVATE_START + 1)
+#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED \
+ (V4L2_EVENT_PRIVATE_START + 2)
+#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_PRIVATE_START + 3)
+
/* Payload for V4L2_EVENT_VSYNC */
struct v4l2_event_vsync {
/* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
diff --git a/include/media/Kbuild b/include/media/Kbuild
index 03951ce..2a21336 100644
--- a/include/media/Kbuild
+++ b/include/media/Kbuild
@@ -5,3 +5,4 @@
header-y += msm_isp.h
header-y += msm_gemini.h
header-y += msm_gestures.h
+header-y += msm_mercury.h
diff --git a/include/media/msm/vcd_property.h b/include/media/msm/vcd_property.h
index cd00800..acd0fa3 100644
--- a/include/media/msm/vcd_property.h
+++ b/include/media/msm/vcd_property.h
@@ -54,6 +54,7 @@
#define VCD_REQ_PERF_LEVEL (VCD_START_BASE + 0x26)
#define VCD_I_SLICE_DELIVERY_MODE (VCD_START_BASE + 0x27)
#define VCD_I_VOP_TIMING_CONSTANT_DELTA (VCD_START_BASE + 0x28)
+#define VCD_I_SET_TURBO_CLK (VCD_START_BASE + 0x29)
#define VCD_START_REQ (VCD_START_BASE + 0x1000)
#define VCD_I_REQ_IFRAME (VCD_START_REQ + 0x1)
@@ -99,6 +100,7 @@
VCD_PERF_LEVEL0,
VCD_PERF_LEVEL1,
VCD_PERF_LEVEL2,
+ VCD_PERF_LEVEL_TURBO,
};
#define VCD_METADATA_DATANONE 0x001
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 8222b67..320ac8b 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -190,6 +190,9 @@
#define MSM_CAM_IOCTL_EEPROM_IO_CFG \
_IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *)
+#define MSM_CAM_IOCTL_ISPIF_IO_CFG \
+ _IOR(MSM_CAM_IOCTL_MAGIC, 54, struct ispif_cfg_data *)
+
struct msm_mctl_pp_cmd {
int32_t id;
uint16_t length;
@@ -605,6 +608,7 @@
struct ion_allocation_data ion_alloc;
struct ion_fd_data fd_data;
+ int ion_dev_fd;
};
enum msm_st_frame_packing {
@@ -796,7 +800,10 @@
#define CFG_SET_AUTOFLASH 41
#define CFG_SET_EXPOSURE_COMPENSATION 42
#define CFG_SET_ISO 43
-#define CFG_MAX 44
+#define CFG_START_STREAM 44
+#define CFG_STOP_STREAM 45
+#define CFG_GET_CSI_PARAMS 46
+#define CFG_MAX 47
#define MOVE_NEAR 0
@@ -916,6 +923,21 @@
MSM_V4L2_SATURATION_L10,
};
+enum msm_v4l2_contrast_level {
+ MSM_V4L2_CONTRAST_L0,
+ MSM_V4L2_CONTRAST_L1,
+ MSM_V4L2_CONTRAST_L2,
+ MSM_V4L2_CONTRAST_L3,
+ MSM_V4L2_CONTRAST_L4,
+ MSM_V4L2_CONTRAST_L5,
+ MSM_V4L2_CONTRAST_L6,
+ MSM_V4L2_CONTRAST_L7,
+ MSM_V4L2_CONTRAST_L8,
+ MSM_V4L2_CONTRAST_L9,
+ MSM_V4L2_CONTRAST_L10,
+};
+
+
enum msm_v4l2_exposure_level {
MSM_V4L2_EXPOSURE_N2,
MSM_V4L2_EXPOSURE_N1,
@@ -951,16 +973,29 @@
};
enum msm_v4l2_wb_mode {
- MSM_V4L2_WB_MIN_MINUS_1,
- MSM_V4L2_WB_AUTO = 1,
+ MSM_V4L2_WB_OFF,
+ MSM_V4L2_WB_AUTO ,
MSM_V4L2_WB_CUSTOM,
MSM_V4L2_WB_INCANDESCENT,
MSM_V4L2_WB_FLUORESCENT,
MSM_V4L2_WB_DAYLIGHT,
MSM_V4L2_WB_CLOUDY_DAYLIGHT,
- MSM_V4L2_WB_TWILIGHT,
- MSM_V4L2_WB_SHADE,
- MSM_V4L2_WB_OFF,
+};
+
+enum msm_v4l2_special_effect {
+ MSM_V4L2_EFFECT_OFF,
+ MSM_V4L2_EFFECT_MONO,
+ MSM_V4L2_EFFECT_NEGATIVE,
+ MSM_V4L2_EFFECT_SOLARIZE,
+ MSM_V4L2_EFFECT_SEPIA,
+ MSM_V4L2_EFFECT_POSTERAIZE,
+ MSM_V4L2_EFFECT_WHITEBOARD,
+ MSM_V4L2_EFFECT_BLACKBOARD,
+ MSM_V4L2_EFFECT_AQUA,
+ MSM_V4L2_EFFECT_EMBOSS,
+ MSM_V4L2_EFFECT_SKETCH,
+ MSM_V4L2_EFFECT_NEON,
+ MSM_V4L2_EFFECT_MAX,
};
enum msm_v4l2_power_line_frequency {
@@ -1098,6 +1133,112 @@
uint16_t index;
};
+struct msm_camera_csid_vc_cfg {
+ uint8_t cid;
+ uint8_t dt;
+ uint8_t decode_format;
+};
+
+struct csi_lane_params_t {
+ uint8_t csi_lane_assign;
+ uint8_t csi_lane_mask;
+ uint8_t csi_if;
+ uint8_t csid_core;
+ uint32_t csid_version;
+};
+
+#define CSI_EMBED_DATA 0x12
+#define CSI_RESERVED_DATA_0 0x13
+#define CSI_YUV422_8 0x1E
+#define CSI_RAW8 0x2A
+#define CSI_RAW10 0x2B
+#define CSI_RAW12 0x2C
+
+#define CSI_DECODE_6BIT 0
+#define CSI_DECODE_8BIT 1
+#define CSI_DECODE_10BIT 2
+#define CSI_DECODE_DPCM_10_8_10 5
+
+#define ISPIF_STREAM(intf, action) (((intf)<<ISPIF_S_STREAM_SHIFT)+(action))
+#define ISPIF_ON_FRAME_BOUNDARY (0x01 << 0)
+#define ISPIF_OFF_FRAME_BOUNDARY (0x01 << 1)
+#define ISPIF_OFF_IMMEDIATELY (0x01 << 2)
+#define ISPIF_S_STREAM_SHIFT 4
+
+
+#define PIX_0 (0x01 << 0)
+#define RDI_0 (0x01 << 1)
+#define PIX_1 (0x01 << 2)
+#define RDI_1 (0x01 << 3)
+#define PIX_2 (0x01 << 4)
+#define RDI_2 (0x01 << 5)
+
+
+enum msm_ispif_intftype {
+ PIX0,
+ RDI0,
+ PIX1,
+ RDI1,
+ PIX2,
+ RDI2,
+ INTF_MAX,
+};
+
+enum msm_ispif_vc {
+ VC0,
+ VC1,
+ VC2,
+ VC3,
+};
+
+enum msm_ispif_cid {
+ CID0,
+ CID1,
+ CID2,
+ CID3,
+ CID4,
+ CID5,
+ CID6,
+ CID7,
+ CID8,
+ CID9,
+ CID10,
+ CID11,
+ CID12,
+ CID13,
+ CID14,
+ CID15,
+};
+
+struct msm_ispif_params {
+ uint8_t intftype;
+ uint16_t cid_mask;
+ uint8_t csid;
+};
+
+struct msm_ispif_params_list {
+ uint32_t len;
+ struct msm_ispif_params params[4];
+};
+
+enum ispif_cfg_type_t {
+ ISPIF_INIT,
+ ISPIF_SET_CFG,
+ ISPIF_SET_ON_FRAME_BOUNDARY,
+ ISPIF_SET_OFF_FRAME_BOUNDARY,
+ ISPIF_SET_OFF_IMMEDIATELY,
+ ISPIF_RELEASE,
+};
+
+struct ispif_cfg_data {
+ enum ispif_cfg_type_t cfgtype;
+ union {
+ uint32_t csid_version;
+ int cmd;
+ struct msm_ispif_params_list ispif_params;
+ } cfg;
+};
+
struct sensor_cfg_data {
int cfgtype;
int mode;
@@ -1124,6 +1265,7 @@
struct sensor_calib_data calib_info;
struct sensor_output_info_t output_info;
struct msm_eeprom_data_t eeprom_data;
+ struct csi_lane_params_t csi_lane_params;
/* QRD */
uint16_t antibanding;
uint8_t contrast;
@@ -1381,6 +1523,7 @@
uint8_t flash_enabled;
uint8_t strobe_flash_enabled;
uint8_t actuator_enabled;
+ uint8_t ispif_supported;
int8_t total_steps;
uint8_t support_3d;
enum flash_type flashtype;
@@ -1422,25 +1565,95 @@
#define QCAMERA_VNODE_GROUP_ID 2
#define MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t *)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct msm_camera_v4l2_ioctl_t)
#define MSM_CAM_V4L2_IOCTL_GET_CONFIG_INFO \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t *)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 2, struct msm_camera_v4l2_ioctl_t)
#define MSM_CAM_V4L2_IOCTL_GET_MCTL_INFO \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t *)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 3, struct msm_camera_v4l2_ioctl_t)
#define MSM_CAM_V4L2_IOCTL_CTRL_CMD_DONE \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t *)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 4, struct msm_camera_v4l2_ioctl_t)
#define MSM_CAM_V4L2_IOCTL_GET_EVENT_PAYLOAD \
- _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t *)
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t)
#define MSM_CAM_IOCTL_SEND_EVENT \
_IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct v4l2_event)
+#define MSM_CAM_V4L2_IOCTL_CFG_VPE \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_vpe_cfg_cmd)
+
+#define MSM_CAM_V4L2_IOCTL_PRIVATE_S_CTRL \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct msm_camera_v4l2_ioctl_t)
+
struct msm_camera_v4l2_ioctl_t {
+ uint32_t id;
void __user *ioctl_ptr;
+ uint32_t len;
};
+enum msm_camss_irq_idx {
+ CAMERA_SS_IRQ_0,
+ CAMERA_SS_IRQ_1,
+ CAMERA_SS_IRQ_2,
+ CAMERA_SS_IRQ_3,
+ CAMERA_SS_IRQ_4,
+ CAMERA_SS_IRQ_5,
+ CAMERA_SS_IRQ_6,
+ CAMERA_SS_IRQ_7,
+ CAMERA_SS_IRQ_8,
+ CAMERA_SS_IRQ_9,
+ CAMERA_SS_IRQ_10,
+ CAMERA_SS_IRQ_11,
+ CAMERA_SS_IRQ_12,
+ CAMERA_SS_IRQ_MAX
+};
+
+enum msm_cam_hw_idx {
+ MSM_CAM_HW_MICRO,
+ MSM_CAM_HW_CCI,
+ MSM_CAM_HW_CSI0,
+ MSM_CAM_HW_CSI1,
+ MSM_CAM_HW_CSI2,
+ MSM_CAM_HW_CSI3,
+ MSM_CAM_HW_ISPIF,
+ MSM_CAM_HW_CPP,
+ MSM_CAM_HW_VFE0,
+ MSM_CAM_HW_VFE1,
+ MSM_CAM_HW_JPEG0,
+ MSM_CAM_HW_JPEG1,
+ MSM_CAM_HW_JPEG2,
+ MSM_CAM_HW_MAX
+};
+
+struct msm_camera_irq_cfg {
+ /* Bit mask of all the camera hardwares that needs to
+ * be composited into a single IRQ to the MSM.
+ * Current usage: (may be updated based on hw changes)
+ * Bits 31:13 - Reserved.
+ * Bits 12:0
+ * 12 - MSM_CAM_HW_JPEG2
+ * 11 - MSM_CAM_HW_JPEG1
+ * 10 - MSM_CAM_HW_JPEG0
+ * 9 - MSM_CAM_HW_VFE1
+ * 8 - MSM_CAM_HW_VFE0
+ * 7 - MSM_CAM_HW_CPP
+ * 6 - MSM_CAM_HW_ISPIF
+ * 5 - MSM_CAM_HW_CSI3
+ * 4 - MSM_CAM_HW_CSI2
+ * 3 - MSM_CAM_HW_CSI1
+ * 2 - MSM_CAM_HW_CSI0
+ * 1 - MSM_CAM_HW_CCI
+ * 0 - MSM_CAM_HW_MICRO
+ */
+ uint32_t cam_hw_mask;
+ uint8_t irq_idx;
+ uint8_t num_hwcore;
+};
+
+#define MSM_IRQROUTER_CFG_COMPIRQ \
+ _IOWR('V', BASE_VIDIOC_PRIVATE, void __user *)
+
#endif /* __LINUX_MSM_CAMERA_H */
diff --git a/include/media/msm_isp.h b/include/media/msm_isp.h
index cb728a0..333d0df 100644
--- a/include/media/msm_isp.h
+++ b/include/media/msm_isp.h
@@ -327,5 +327,10 @@
#define VFE_OUTPUTS_JPEG_AND_THUMB BIT(9)
#define VFE_OUTPUTS_THUMB_AND_JPEG BIT(10)
+struct msm_frame_info {
+ uint32_t image_mode;
+ uint32_t path;
+};
+
#endif /*__MSM_ISP_H__*/
diff --git a/include/media/msm_mercury.h b/include/media/msm_mercury.h
new file mode 100644
index 0000000..1d14724
--- /dev/null
+++ b/include/media/msm_mercury.h
@@ -0,0 +1,119 @@
+#ifndef __LINUX_MSM_MERCURY_H
+#define __LINUX_MSM_MERCURY_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define MSM_MERCURY_HW_VERSION_REG 0x0004/* this offset does not exist in HW*/
+
+#define OUTPUT_H2V1 0
+#define OUTPUT_H2V2 1
+#define OUTPUT_BYTE 6
+
+#define MSM_MERCURY_MODE_REALTIME_ENCODE 0
+#define MSM_MERCURY_MODE_OFFLINE_ENCODE 1
+#define MSM_MERCURY_MODE_REALTIME_ROTATION 2
+#define MSM_MERCURY_MODE_OFFLINE_ROTATION 3
+
+#define MSM_MERCURY_EVT_RESET 1
+#define MSM_MERCURY_EVT_FRAMEDONE 2
+#define MSM_MERCURY_EVT_ERR 3
+#define MSM_MERCURY_EVT_UNBLOCK 4
+
+#define MSM_MERCURY_HW_CMD_TYPE_READ 0
+#define MSM_MERCURY_HW_CMD_TYPE_WRITE 1
+#define MSM_MERCURY_HW_CMD_TYPE_WRITE_OR 2
+#define MSM_MERCURY_HW_CMD_TYPE_UWAIT 3
+#define MSM_MERCURY_HW_CMD_TYPE_MWAIT 4
+#define MSM_MERCURY_HW_CMD_TYPE_MDELAY 5
+#define MSM_MERCURY_HW_CMD_TYPE_UDELAY 6
+
+#define MSM_MCR_IOCTL_MAGIC 'g'
+
+#define MSM_MCR_IOCTL_GET_HW_VERSION \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 1, struct msm_mercury_hw_cmd *)
+
+#define MSM_MCR_IOCTL_RESET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 2, struct msm_mercury_ctrl_cmd *)
+
+#define MSM_MCR_IOCTL_STOP \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 3, struct msm_mercury_hw_cmds *)
+
+#define MSM_MCR_IOCTL_START \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 4, struct msm_mercury_hw_cmds *)
+
+#define MSM_MCR_IOCTL_INPUT_BUF_CFG \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 5, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_INPUT_GET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 6, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_INPUT_GET_UNBLOCK \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 7, int)
+
+#define MSM_MCR_IOCTL_OUTPUT_BUF_CFG \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 8, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_OUTPUT_GET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 9, struct msm_mercury_buf *)
+
+#define MSM_MCR_IOCTL_OUTPUT_GET_UNBLOCK \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 10, int)
+
+#define MSM_MCR_IOCTL_EVT_GET \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 11, struct msm_mercury_ctrl_cmd *)
+
+#define MSM_MCR_IOCTL_EVT_GET_UNBLOCK \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 12, int)
+
+#define MSM_MCR_IOCTL_HW_CMD \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 13, struct msm_mercury_hw_cmd *)
+
+#define MSM_MCR_IOCTL_HW_CMDS \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 14, struct msm_mercury_hw_cmds *)
+
+#define MSM_MCR_IOCTL_TEST_DUMP_REGION \
+ _IOW(MSM_MCR_IOCTL_MAGIC, 15, unsigned long)
+
+struct msm_mercury_ctrl_cmd {
+ uint32_t type;
+ uint32_t len;
+ void *value;
+};
+
+struct msm_mercury_buf {
+ uint32_t type;
+ int fd;
+ void *vaddr;
+ uint32_t y_off;
+ uint32_t y_len;
+ uint32_t framedone_len;
+ uint32_t cbcr_off;
+ uint32_t cbcr_len;
+ uint32_t num_of_mcu_rows;
+ uint32_t offset;
+};
+
+struct msm_mercury_hw_cmd {
+
+ uint32_t type:4;
+ /* n microseconds of timeout for WAIT */
+ /* n microseconds of time for DELAY */
+ /* repeat n times for READ/WRITE */
+ /* max is 0xFFF, 4095 */
+ uint32_t n:12;
+ uint32_t offset:16;
+ uint32_t mask;
+ union {
+ /* for single READ/WRITE/WAIT, n = 1 */
+ uint32_t data;
+ uint32_t *pdata;/* for multiple READ/WRITE/WAIT, n > 1 */
+ };
+};
+
+struct msm_mercury_hw_cmds {
+ uint32_t m; /* number of elements in the hw_cmd array */
+ struct msm_mercury_hw_cmd hw_cmd[1];
+};
+
+#endif /* __LINUX_MSM_MERCURY_H */
diff --git a/include/media/tavarua.h b/include/media/tavarua.h
index 52194f9..9943287 100644
--- a/include/media/tavarua.h
+++ b/include/media/tavarua.h
@@ -172,6 +172,10 @@
V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */
V4L2_CID_PRIVATE_SINR_THRESHOLD, /* 0x800002F : IRIS */
V4L2_CID_PRIVATE_SINR_SAMPLES, /* 0x8000030 : IRIS */
+ V4L2_CID_PRIVATE_SPUR_FREQ,
+ V4L2_CID_PRIVATE_SPUR_FREQ_RMSSI,
+ V4L2_CID_PRIVATE_SPUR_SELECTION,
+ V4L2_CID_PRIVATE_UPDATE_SPUR_TABLE,
};
@@ -484,4 +488,47 @@
TAVARUA_REGION_OTHER
};
+enum {
+ ONE_BYTE = 1,
+ TWO_BYTE,
+ THREE_BYTE,
+ FOUR_BYTE,
+ FIVE_BYTE,
+ SIX_BYTE,
+ SEVEN_BYTE,
+ EIGHT_BYTE,
+ NINE_BYTE,
+ TEN_BYTE,
+ ELEVEN_BYTE,
+ TWELVE_BYTE,
+ THIRTEEN_BYTE
+};
+#define XFR_READ (0)
+#define XFR_WRITE (1)
+#define XFR_MODE_OFFSET (0)
+#define XFR_ADDR_MSB_OFFSET (1)
+#define XFR_ADDR_LSB_OFFSET (2)
+#define XFR_DATA_OFFSET (3)
+#define SPUR_DATA_SIZE (3)
+#define MAX_SPUR_FREQ_LIMIT (30)
+#define READ_COMPLETE (0x20)
+#define SPUR_TABLE_ADDR (0x0BB7)
+#define SPUR_TABLE_START_ADDR (SPUR_TABLE_ADDR + 1)
+#define XFR_PEEK_COMPLETE (XFR_PEEK_MODE | READ_COMPLETE)
+#define XFR_POKE_COMPLETE (XFR_POKE_MODE)
+
+#define COMPUTE_SPUR(val) ((((val) - (76000)) / (50)))
+#define GET_FREQ(val, bit) ((bit == 1) ? ((val) >> 8) : ((val) & 0xFF))
+
+struct fm_spur_data {
+ int freq[MAX_SPUR_FREQ_LIMIT];
+ __s8 rmssi[MAX_SPUR_FREQ_LIMIT];
+} __packed;
+
+struct fm_def_data_wr_req {
+ __u8 mode;
+ __u8 length;
+ __u8 data[XFR_REG_NUM];
+} __packed;
+
#endif /* __LINUX_TAVARUA_H */
diff --git a/include/media/vcap_fmt.h b/include/media/vcap_fmt.h
index 51b45ac..92240bf1 100644
--- a/include/media/vcap_fmt.h
+++ b/include/media/vcap_fmt.h
@@ -15,7 +15,19 @@
#define VCAP_FMT_H
#define V4L2_BUF_TYPE_INTERLACED_IN_DECODER (V4L2_BUF_TYPE_PRIVATE)
-#define V4L2_BUF_TYPE_VP_OUT (V4L2_BUF_TYPE_PRIVATE + 1)
+
+#define VCAP_GENERIC_NOTIFY_EVENT 0
+#define VCAP_VC_PIX_ERR_EVENT 1
+#define VCAP_VC_LINE_ERR_EVENT 2
+#define VCAP_VC_VSYNC_ERR_EVENT 3
+#define VCAP_VC_NPL_OFLOW_ERR_EVENT 4
+#define VCAP_VC_LBUF_OFLOW_ERR_EVENT 5
+#define VCAP_VC_BUF_OVERWRITE_EVENT 6
+#define VCAP_VP_REG_R_ERR_EVENT 7
+#define VCAP_VP_REG_W_ERR_EVENT 8
+#define VCAP_VP_IN_HEIGHT_ERR_EVENT 9
+#define VCAP_VP_IN_WIDTH_ERR_EVENT 10
+#define VCAP_MAX_NOTIFY_EVENT 11
enum hal_vcap_mode {
HAL_VCAP_MODE_PRO = 0,
@@ -39,7 +51,8 @@
enum hal_vcap_polar d_polar;
enum hal_vcap_color color_space;
- float clk_freq;
+ uint32_t clk_freq;
+ uint32_t frame_rate;
uint32_t vtotal;
uint32_t htotal;
uint32_t hactive_start;
diff --git a/include/media/vcap_v4l2.h b/include/media/vcap_v4l2.h
index 374e681..045c107 100644
--- a/include/media/vcap_v4l2.h
+++ b/include/media/vcap_v4l2.h
@@ -29,6 +29,8 @@
#include <media/vcap_fmt.h>
#include <mach/board.h>
+#define to_client_data(val) container_of(val, struct vcap_client_data, vfh)
+
#define writel_iowmb(val, addr) \
do { \
__iowmb(); \
@@ -146,6 +148,7 @@
struct clk *vcap_clk;
struct clk *vcap_p_clk;
struct clk *vcap_npl_clk;
+ struct device *ddev;
/*struct platform_device *pdev;*/
uint32_t bus_client_handle;
@@ -156,8 +159,10 @@
atomic_t vc_enabled;
atomic_t vp_enabled;
- atomic_t vc_resource;
- atomic_t vp_resource;
+ spinlock_t dev_slock;
+ atomic_t open_clients;
+ bool vc_resource;
+ bool vp_resource;
struct workqueue_struct *vcap_wq;
struct vp_work_t vp_work;
@@ -204,6 +209,8 @@
spinlock_t cap_slock;
bool streaming;
+
+ struct v4l2_fh vfh;
};
struct vcap_hacked_vals {
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 96795a3..ec8d73e 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -59,6 +59,9 @@
#define INT_FM_TX 0x3005 /* index = 29 */
#define RT_PROXY_PORT_001_RX 0x2000 /* index = 30 */
#define RT_PROXY_PORT_001_TX 0x2001 /* index = 31 */
+#define SECONDARY_PCM_RX 12 /* index = 32 */
+#define SECONDARY_PCM_TX 13 /* index = 33 */
+
#define AFE_PORT_INVALID 0xFFFF
#define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index 8cdcc18..f93af1f 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -68,6 +68,8 @@
IDX_INT_FM_TX = 29,
IDX_RT_PROXY_PORT_001_RX = 30,
IDX_RT_PROXY_PORT_001_TX = 31,
+ IDX_SECONDARY_PCM_RX = 32,
+ IDX_SECONDARY_PCM_TX = 33,
AFE_MAX_PORTS
};
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index 54a9187..ee90797 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -81,7 +81,8 @@
#define SESSION_MAX 0x08
#define SOFT_PAUSE_PERIOD 30 /* ramp up/down for 30ms */
-#define SOFT_PAUSE_STEP 2000 /* Step value 2ms or 2000us */
+#define SOFT_PAUSE_STEP_LINEAR 0 /* Step value 0ms or 0us */
+#define SOFT_PAUSE_STEP 2000 /* Step value 2000ms or 2000us */
enum {
SOFT_PAUSE_CURVE_LINEAR = 0,
SOFT_PAUSE_CURVE_EXP,
@@ -89,7 +90,8 @@
};
#define SOFT_VOLUME_PERIOD 30 /* ramp up/down for 30ms */
-#define SOFT_VOLUME_STEP 2000 /* Step value 2ms or 2000us */
+#define SOFT_VOLUME_STEP_LINEAR 0 /* Step value 0ms or 0us */
+#define SOFT_VOLUME_STEP 2000 /* Step value 2000ms or 2000us */
enum {
SOFT_VOLUME_CURVE_LINEAR = 0,
SOFT_VOLUME_CURVE_EXP,
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 4676a02..17fef15 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -241,7 +241,7 @@
struct snd_soc_dai_driver *driver;
/* DAI runtime info */
- unsigned int capture_active:1; /* stream is in use */
+ unsigned int capture_active; /* stream is in use */
unsigned int playback_active:1; /* stream is in use */
unsigned int symmetric_rates:1;
struct snd_pcm_runtime *runtime;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 05e8b06..d5d8541 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -535,7 +535,7 @@
unsigned long page_idx;
unsigned long combined_idx;
unsigned long uninitialized_var(buddy_idx);
- struct page *buddy;
+ struct page *buddy = NULL;
if (unlikely(PageCompound(page)))
if (unlikely(destroy_compound_page(page, order)))
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7719b82..980b846 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -59,10 +59,11 @@
#include <net/bluetooth/amp.h>
bool disable_ertm;
+bool enable_hs;
bool enable_reconfig;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
-static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_A2MP, };
+static u8 l2cap_fc_mask = L2CAP_FC_L2CAP;
struct workqueue_struct *_l2cap_wq;
@@ -754,6 +755,7 @@
if (l2cap_pi(sk)->amp_pref ==
BT_AMP_POLICY_PREFER_AMP &&
+ enable_hs &&
conn->fc_mask & L2CAP_FC_A2MP)
amp_create_physical(conn, sk);
else
@@ -862,6 +864,7 @@
if (l2cap_pi(sk)->amp_pref ==
BT_AMP_POLICY_PREFER_AMP &&
+ enable_hs &&
conn->fc_mask & L2CAP_FC_A2MP)
amp_create_physical(conn, sk);
else
@@ -2723,7 +2726,7 @@
if (!l2cap_pi(sk)->conn)
return;
- if (!(l2cap_pi(sk)->conn->fc_mask & L2CAP_FC_A2MP))
+ if (!(l2cap_pi(sk)->conn->fc_mask & L2CAP_FC_A2MP) || !enable_hs)
return;
if (l2cap_pi(sk)->amp_id == 0) {
@@ -4654,10 +4657,14 @@
L2CAP_INFO_RSP, sizeof(buf), buf);
} else if (type == L2CAP_IT_FIXED_CHAN) {
u8 buf[12];
+ u8 fc_mask = l2cap_fc_mask;
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
- memcpy(buf + 4, l2cap_fixed_chan, 8);
+ if (enable_hs)
+ fc_mask |= L2CAP_FC_A2MP;
+ memset(rsp->data, 0, 8);
+ rsp->data[0] = fc_mask;
l2cap_send_cmd(conn, cmd->ident,
L2CAP_INFO_RSP, sizeof(buf), buf);
} else {
@@ -7367,7 +7374,7 @@
l2cap_data_channel(sk, skb);
bh_unlock_sock(sk);
- } else if (cid == L2CAP_CID_A2MP) {
+ } else if ((cid == L2CAP_CID_A2MP) && enable_hs) {
BT_DBG("A2MP");
amp_conn_ind(conn->hcon, skb);
} else {
@@ -7522,8 +7529,9 @@
if (!status) {
l2cap_pi(sk)->conf_state |=
L2CAP_CONF_CONNECT_PEND;
- if (l2cap_pi(sk)->amp_pref ==
- BT_AMP_POLICY_PREFER_AMP) {
+ if ((l2cap_pi(sk)->amp_pref ==
+ BT_AMP_POLICY_PREFER_AMP) &&
+ enable_hs) {
amp_create_physical(l2cap_pi(sk)->conn,
sk);
} else
@@ -7825,5 +7833,8 @@
module_param(disable_ertm, bool, 0644);
MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
+module_param(enable_hs, bool, 0644);
+MODULE_PARM_DESC(enable_hs, "Enable A2MP protocol");
+
module_param(enable_reconfig, bool, 0644);
MODULE_PARM_DESC(enable_reconfig, "Enable reconfig after initiating AMP move");
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 77a6dd9..deb67f5 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -1634,7 +1634,8 @@
$exec_file =~ /^Kconfig$/) &&
$rawline =~ /^new (file )?mode\s([0-9]+)$/ &&
(oct($2) & 0111)) {
- ERROR("Source file has +x permissions: " .
+ ERROR("EXECUTE_PERMISSIONS",
+ "Source file has +x permissions: " .
"$exec_file\n");
}
$here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
@@ -1647,7 +1648,8 @@
if ($shorttext == IN_SHORTTEXT_BLANKLINE && $line=~/\S/) {
# the subject line was just processed,
# a blank line must be next
- WARN("non-blank line after summary line\n" . $herecurr);
+ WARN("NONBLANK_AFTER_SUMMARY",
+ "non-blank line after summary line\n" . $herecurr);
$shorttext = IN_SHORTTEXT;
# this non-blank line may or may not be commit text -
# a warning has been generated so assume it is commit
@@ -1658,7 +1660,8 @@
if ($shorttext == IN_SHORTTEXT) {
if ($line=~/^---/ || $line=~/^diff.*/) {
if ($commit_text_present == 0) {
- WARN("please add commit text explaining " .
+ WARN("NO_COMMIT_TEXT",
+ "please add commit text explaining " .
"*why* the change is needed\n" .
$herecurr);
}
@@ -1668,7 +1671,8 @@
&& $line !~ /^:([0-7]{6}\s){2}
([[:xdigit:]]+\.*
\s){2}\w+\s\w+/xms) {
- WARN("commit text line over " .
+ WARN("LONG_COMMIT_TEXT",
+ "commit text line over " .
SHORTTEXT_LIMIT .
" characters\n" . $herecurr);
} elsif ($line=~/^\s*change-id:/i ||
@@ -1678,7 +1682,8 @@
# this is a tag, there must be commit
# text by now
if ($commit_text_present == 0) {
- WARN("please add commit text explaining " .
+ WARN("NO_COMMIT_TEXT",
+ "please add commit text explaining " .
"*why* the change is needed\n" .
$herecurr);
# prevent duplicate warnings
@@ -1699,7 +1704,8 @@
$shorttext = IN_SHORTTEXT;
# Check for Subject line followed by a blank line.
if (length($line) != 0) {
- WARN("non-blank line after " .
+ WARN("NONBLANK_AFTER_SUMMARY",
+ "non-blank line after " .
"summary line\n" .
$sublinenr . $here .
"\n" . $subjectline .
@@ -1721,7 +1727,8 @@
$sublinenr = "#$linenr & ";
# Check for Subject line less than line limit
if (length($1) > SHORTTEXT_LIMIT) {
- WARN("summary line over " .
+ WARN("LONG_SUMMARY_LINE",
+ "summary line over " .
SHORTTEXT_LIMIT .
" characters\n" . $herecurr);
}
@@ -1732,7 +1739,8 @@
$shorttext = IN_SHORTTEXT_BLANKLINE;
$shorttext_exspc = 4;
if (length($1) > SHORTTEXT_LIMIT) {
- WARN("summary line over " .
+ WARN("LONG_SUMMARY_LINE",
+ "summary line over " .
SHORTTEXT_LIMIT .
" characters\n" . $herecurr);
}
@@ -1797,13 +1805,14 @@
}
}
if ($line =~ /^\s*signed-off-by:.*(quicinc|qualcomm)\.com/i) {
- WARN("invalid Signed-off-by identity\n" . $line );
+ WARN("BAD_SIGN_OFF",
+ "invalid Signed-off-by identity\n" . $line );
}
}
#check the patch for invalid author credentials
if ($line =~ /^From:.*(quicinc|qualcomm)\.com/) {
- WARN("invalid author identity\n" . $line );
+ WARN("BAD_AUTHOR", "invalid author identity\n" . $line );
}
# Check for wrappage within a valid hunk of the file
@@ -3291,19 +3300,20 @@
# sys_open/read/write/close are not allowed in the kernel
if ($line =~ /\b(sys_(?:open|read|write|close))\b/) {
- ERROR("$1 is inappropriate in kernel code.\n" .
+ ERROR("FILE_OPS", "$1 is inappropriate in kernel code.\n" .
$herecurr);
}
# filp_open is a backdoor for sys_open
if ($line =~ /\b(filp_open)\b/) {
- ERROR("$1 is inappropriate in kernel code.\n" .
+ ERROR("FILE_OPS", "$1 is inappropriate in kernel code.\n" .
$herecurr);
}
# read[bwl] & write[bwl] use too many barriers, use the _relaxed variants
if ($line =~ /\b((?:read|write)[bwl])\b/) {
- ERROR("Use of $1 is deprecated: use $1_relaxed\n\t" .
+ ERROR("NON_RELAXED_IO",
+ "Use of $1 is deprecated: use $1_relaxed\n\t" .
"with appropriate memory barriers instead.\n" .
$herecurr);
}
@@ -3313,7 +3323,8 @@
my ($all, $pref, $suf) = ($1, $2, $3);
$pref =~ s/in/read/;
$pref =~ s/out/write/;
- ERROR("Use of $all is deprecated: use " .
+ ERROR("NON_RELAXED_IO",
+ "Use of $all is deprecated: use " .
"__raw_$pref$suf\n\t" .
"with appropriate memory barriers instead.\n" .
$herecurr);
@@ -3321,7 +3332,8 @@
# dsb is too ARMish, and should usually be mb.
if ($line =~ /\bdsb\b/) {
- WARN("Use of dsb is discouranged: prefer mb.\n" .
+ WARN("ARM_BARRIER",
+ "Use of dsb is discouranged: prefer mb.\n" .
$herecurr);
}
@@ -3329,12 +3341,13 @@
if ($realfile =~ /\/mach-msm\/board-[0-9]+/ &&
$realfile !~ /camera/ && $realfile !~ /gpiomux/ &&
$line =~ /\s*struct msm_gpiomux_config\s*/ ) {
- WARN("Non gpiomux board file cannot have a gpiomux config declarations. Please declare gpiomux configs in board-*-gpiomux.c file.\n" . $herecurr);
+ WARN("GPIOMUX_IN_BOARD",
+ "Non gpiomux board file cannot have a gpiomux config declarations. Please declare gpiomux configs in board-*-gpiomux.c file.\n" . $herecurr);
}
# MSM - check if vreg_xxx function are used
if ($line =~ /\b(vreg_(get|put|set_level|enable|disable))\b/) {
- WARN("Use of $1 API is deprecated: " .
+ WARN("DEPRECATED_VREG_APIS", "Use of $1 API is deprecated: " .
"use regulator APIs\n" . $herecurr);
}
@@ -3354,7 +3367,8 @@
);
foreach my $k (keys %str_fns) {
if ($line =~ /\b$k\b/) {
- ERROR("Use of $k is deprecated: " .
+ ERROR("UNBOUNDED_STRING_FNS",
+ "Use of $k is deprecated: " .
"use $str_fns{$k} instead.\n" .
$herecurr);
}
@@ -3362,13 +3376,15 @@
# warn about #if 0
if ($line =~ /^.\s*\#\s*if\s+0\b/) {
- WARN("if this code is redundant consider removing it\n"
+ WARN("IF_0",
+ "if this code is redundant consider removing it\n"
. $herecurr);
}
# warn about #if 1
if ($line =~ /^.\s*\#\s*if\s+1\b/) {
- WARN("if this code is required consider removing"
+ WARN("IF_1",
+ "if this code is required consider removing"
. " #if 1\n" . $herecurr);
}
@@ -3408,7 +3424,8 @@
# check the patch for use of mdelay
if ($line =~ /\bmdelay\s*\(/) {
- WARN("use of mdelay() found: msleep() is the preferred API.\n" . $line );
+ WARN("MDELAY",
+ "use of mdelay() found: msleep() is the preferred API.\n" . $line );
}
# warn about #ifdefs in C files
@@ -3598,7 +3615,8 @@
# check for return codes on error paths
if ($line =~ /\breturn\s+-\d+/) {
- ERROR("illegal return value, please use an error code\n" . $herecurr);
+ ERROR("NO_ERROR_CODE",
+ "illegal return value, please use an error code\n" . $herecurr);
}
# check for gcc specific __FUNCTION__
diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py
index 3732160..583a5ce 100755
--- a/scripts/gcc-wrapper.py
+++ b/scripts/gcc-wrapper.py
@@ -40,8 +40,9 @@
# force LANG to be set to en_US.UTF-8 to get consistent warnings.
allowed_warnings = set([
- "return_address.c:62",
+ "alignment.c:327",
"mmu.c:602",
+ "return_address.c:62",
])
# Capture the name of the object file, can find it.
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 80204f5..b211ac4 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -292,6 +292,9 @@
config SND_SOC_CS8427
tristate
+config SND_SOC_WCD9320
+ tristate
+
config SND_SOC_WL1273
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 965d6a1..5aabfee 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -51,6 +51,7 @@
snd-soc-wcd9304-objs := wcd9304.o wcd9304-tables.o
snd-soc-wcd9310-objs := wcd9310.o wcd9310-tables.o
snd-soc-cs8427-objs := cs8427.o
+snd-soc-wcd9320-objs := wcd9320.o wcd9320-tables.o
snd-soc-wl1273-objs := wl1273.o
snd-soc-wm1250-ev1-objs := wm1250-ev1.o
snd-soc-wm2000-objs := wm2000.o
@@ -158,6 +159,7 @@
obj-$(CONFIG_SND_SOC_WCD9304) += snd-soc-wcd9304.o
obj-$(CONFIG_SND_SOC_WCD9310) += snd-soc-wcd9310.o
obj-$(CONFIG_SND_SOC_CS8427) += snd-soc-cs8427.o
+obj-$(CONFIG_SND_SOC_WCD9320) += snd-soc-wcd9320.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index c5dbdae..be31953 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -257,6 +257,23 @@
struct sitar_priv *debug_sitar_priv;
#endif
+static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ ucontrol->value.integer.value[0] = sitar->anc_slot;
+ return 0;
+}
+
+static int sitar_put_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ sitar->anc_slot = ucontrol->value.integer.value[0];
+ return 0;
+}
static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -536,6 +553,9 @@
SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
+ SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, sitar_get_anc_slot,
+ sitar_put_anc_slot),
+
SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
@@ -633,11 +653,11 @@
};
static const char *dec1_mux_text[] = {
- "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANCFB1",
+ "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANC1_FB",
};
static const char *dec2_mux_text[] = {
- "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANCFB2",
+ "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANC2_FB",
};
static const char *dec3_mux_text[] = {
@@ -648,6 +668,15 @@
"ZERO", "DMIC4", "ADC1", "ADC2", "ADC3", "DMIC3", "DMIC2", "DMIC1"
};
+static const char const *anc_mux_text[] = {
+ "ZERO", "ADC1", "ADC2", "ADC3", "RSVD1", "RSVD2", "RSVD3",
+ "MBADC", "RSVD4", "DMIC1", "DMIC2", "DMIC3", "DMIC4"
+};
+
+static const char const *anc1_fb_mux_text[] = {
+ "ZERO", "EAR_HPH_L", "EAR_LINE_1",
+};
+
static const char *iir1_inp1_text[] = {
"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
"ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
@@ -710,6 +739,15 @@
static const struct soc_enum dec4_mux_enum =
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
+static const struct soc_enum anc1_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 0, 13, anc_mux_text);
+
+static const struct soc_enum anc2_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B1_CTL, 4, 13, anc_mux_text);
+
+static const struct soc_enum anc1_fb_mux_enum =
+ SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
+
static const struct soc_enum iir1_inp1_mux_enum =
SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
@@ -773,6 +811,15 @@
static const struct snd_kcontrol_new iir1_inp1_mux =
SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+static const struct snd_kcontrol_new anc1_mux =
+ SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
+
+static const struct snd_kcontrol_new anc2_mux =
+ SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
+
+static const struct snd_kcontrol_new anc1_fb_mux =
+ SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
+
static const struct snd_kcontrol_new dac1_switch[] = {
SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
};
@@ -803,27 +850,39 @@
{
struct snd_soc_codec *codec = w->codec;
u16 adc_reg;
+ u8 init_bit_shift;
pr_debug("%s %d\n", __func__, event);
if (w->reg == SITAR_A_TX_1_2_EN)
adc_reg = SITAR_A_TX_1_2_TEST_CTL;
+ else if (w->reg == SITAR_A_TX_3_EN)
+ adc_reg = SITAR_A_TX_3_TEST_CTL;
else {
pr_err("%s: Error, invalid adc register\n", __func__);
return -EINVAL;
}
+ if (w->shift == 3)
+ init_bit_shift = 6;
+ else if (w->shift == 7)
+ init_bit_shift = 7;
+ else {
+ pr_err("%s: Error, invalid init bit postion adc register\n",
+ __func__);
+ return -EINVAL;
+ }
+
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
sitar_codec_enable_adc_block(codec, 1);
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+ 1 << init_bit_shift);
break;
case SND_SOC_DAPM_POST_PMU:
- snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
- 1 << w->shift);
- usleep_range(1000, 1000);
- snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
- usleep_range(1000, 1000);
- snd_soc_update_bits(codec, adc_reg, 0x08, 0x08);
+
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
break;
case SND_SOC_DAPM_POST_PMD:
sitar_codec_enable_adc_block(codec, 0);
@@ -949,6 +1008,115 @@
return 0;
}
+static int sitar_codec_enable_anc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ const char *filename;
+ const struct firmware *fw;
+ int i;
+ int ret;
+ int num_anc_slots;
+ struct anc_header *anc_head;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u32 anc_writes_size = 0;
+ int anc_size_remaining;
+ u32 *anc_ptr;
+ u16 reg;
+ u8 mask, val, old_val;
+
+ pr_debug("%s %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ /* Use the same firmware file as that of WCD9310,
+ * since the register sequences are same for
+ * WCD9310 and WCD9304
+ */
+ filename = "wcd9310/wcd9310_anc.bin";
+
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < sizeof(struct anc_header)) {
+ dev_err(codec->dev, "Not enough data\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ /* First number is the number of register writes */
+ anc_head = (struct anc_header *)(fw->data);
+ anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
+ anc_size_remaining = fw->size - sizeof(struct anc_header);
+ num_anc_slots = anc_head->num_anc_slots;
+
+ if (sitar->anc_slot >= num_anc_slots) {
+ dev_err(codec->dev, "Invalid ANC slot selected\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_anc_slots; i++) {
+
+ if (anc_size_remaining < SITAR_PACKED_REG_SIZE) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+ anc_writes_size = (u32)(*anc_ptr);
+ anc_size_remaining -= sizeof(u32);
+ anc_ptr += 1;
+
+ if (anc_writes_size * SITAR_PACKED_REG_SIZE
+ > anc_size_remaining) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ if (sitar->anc_slot == i)
+ break;
+
+ anc_size_remaining -= (anc_writes_size *
+ SITAR_PACKED_REG_SIZE);
+ anc_ptr += anc_writes_size;
+ }
+ if (i == num_anc_slots) {
+ dev_err(codec->dev, "Selected ANC slot not present\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < anc_writes_size; i++) {
+ SITAR_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
+ mask, val);
+ old_val = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, (old_val & ~mask) |
+ (val & mask));
+ }
+
+ release_firmware(fw);
+
+ /* For Sitar, it is required to enable both Feed-forward
+ * and Feed back clocks to enable ANC
+ */
+ snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x0F);
+
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_CLK_ANC_CLK_EN_CTL, 0x00);
+ break;
+ }
+ return 0;
+}
+
+
static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
@@ -1708,6 +1876,15 @@
SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
&dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+ SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+ SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
+ sitar_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
@@ -1753,6 +1930,20 @@
};
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+ {"RX_I2S_CLK", NULL, "CP"},
+ {"RX_I2S_CLK", NULL, "CDC_CONN"},
+ {"SLIM RX1", NULL, "RX_I2S_CLK"},
+ {"SLIM RX2", NULL, "RX_I2S_CLK"},
+ {"SLIM RX3", NULL, "RX_I2S_CLK"},
+ {"SLIM RX4", NULL, "RX_I2S_CLK"},
+
+ {"SLIM TX1", NULL, "TX_I2S_CLK"},
+ {"SLIM TX2", NULL, "TX_I2S_CLK"},
+ {"SLIM TX3", NULL, "TX_I2S_CLK"},
+ {"SLIM TX4", NULL, "TX_I2S_CLK"},
+};
+
static const struct snd_soc_dapm_route audio_map[] = {
/* Earpiece (RX MIX1) */
{"EAR", NULL, "EAR PA"},
@@ -1767,13 +1958,19 @@
{"LINEOUT2 DAC", NULL, "RX_BIAS"},
{"LINEOUT2", NULL, "LINEOUT2 PA"},
+ {"LINEOUT2 PA", NULL, "CP"},
{"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
{"LINEOUT2 DAC", NULL, "DAC3 MUX"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
+ {"LINEOUT2 PA", NULL, "CP"},
{"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
{"LINEOUT1 DAC", NULL, "DAC2 MUX"},
+ {"ANC1 FB MUX", "EAR_HPH_L", "RX2 MIX1"},
+ {"ANC1 FB MUX", "EAR_LINE_1", "RX3 MIX1"},
+ {"ANC", NULL, "ANC1 FB MUX"},
+
/* Headset (RX MIX1 and RX MIX2) */
{"HEADPHONE", NULL, "HPHL"},
@@ -1805,6 +2002,21 @@
{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+ /* ANC */
+ {"ANC", NULL, "ANC1 MUX"},
+ {"ANC", NULL, "ANC2 MUX"},
+ {"ANC1 MUX", "ADC1", "ADC1"},
+ {"ANC1 MUX", "ADC2", "ADC2"},
+ {"ANC1 MUX", "ADC3", "ADC3"},
+ {"ANC2 MUX", "ADC1", "ADC1"},
+ {"ANC2 MUX", "ADC2", "ADC2"},
+ {"ANC2 MUX", "ADC3", "ADC3"},
+
+ {"ANC", NULL, "CDC_CONN"},
+
+ {"RX2 MIX1", NULL, "ANC"},
+ {"RX3 MIX1", NULL, "ANC"},
+
/* SLIMBUS Connections */
/* Slimbus port 5 is non functional in Sitar 1.0 */
@@ -2420,9 +2632,9 @@
}
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
0x03, tx_fs_rate);
+ } else {
+ sitar->dai[dai->id - 1].rate = params_rate(params);
}
- } else {
- sitar->dai[dai->id - 1].rate = params_rate(params);
}
/**
@@ -2467,9 +2679,9 @@
}
snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
0x03, (rx_fs_rate >> 0x05));
+ } else {
+ sitar->dai[dai->id - 1].rate = params_rate(params);
}
- } else {
- sitar->dai[dai->id - 1].rate = params_rate(params);
}
return 0;
@@ -2516,6 +2728,37 @@
},
};
+static struct snd_soc_dai_driver sitar_i2s_dai[] = {
+ {
+ .name = "sitar_i2s_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9304_RATES,
+ .formats = SITAR_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &sitar_dai_ops,
+ },
+ {
+ .name = "sitar_i2s_tx1",
+ .id = AIF1_CAP,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD9304_RATES,
+ .formats = SITAR_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &sitar_dai_ops,
+ },
+};
+
static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -4440,11 +4683,16 @@
sitar_1_1_reg_defaults[i].val);
}
+
+static const struct sitar_reg_mask_val sitar_i2c_codec_reg_init_val[] = {
+ {WCD9XXX_A_CHIP_CTL, 0x1, 0x1},
+};
+
static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
/* Initialize current threshold to 350MA
* number of wait and run cycles to 4096
*/
- {SITAR_A_RX_HPH_OCP_CTL, 0xF8, 0x60},
+ {SITAR_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
{SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
{SITAR_A_QFUSE_CTL, 0xFF, 0x03},
@@ -4481,6 +4729,15 @@
{SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
};
+static void sitar_i2c_codec_init_reg(struct snd_soc_codec *codec)
+{
+ u32 i;
+ for (i = 0; i < ARRAY_SIZE(sitar_i2c_codec_reg_init_val); i++)
+ snd_soc_update_bits(codec, sitar_i2c_codec_reg_init_val[i].reg,
+ sitar_i2c_codec_reg_init_val[i].mask,
+ sitar_i2c_codec_reg_init_val[i].val);
+}
+
static void sitar_codec_init_reg(struct snd_soc_codec *codec)
{
u32 i;
@@ -4536,6 +4793,9 @@
sitar->pdata = dev_get_platdata(codec->dev->parent);
sitar_update_reg_defaults(codec);
sitar_codec_init_reg(codec);
+ sitar->intf_type = wcd9xxx_get_intf_type();
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
+ sitar_i2c_codec_init_reg(codec);
ret = sitar_handle_pdata(sitar);
if (IS_ERR_VALUE(ret)) {
@@ -4547,6 +4807,12 @@
ARRAY_SIZE(sitar_snd_controls));
snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
ARRAY_SIZE(sitar_dapm_widgets));
+ if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ snd_soc_dapm_new_controls(dapm, sitar_dapm_i2s_widgets,
+ ARRAY_SIZE(sitar_dapm_i2s_widgets));
+ snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+ ARRAY_SIZE(audio_i2s_map));
+ }
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
@@ -4774,8 +5040,12 @@
S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
#endif
- ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
sitar_dai, ARRAY_SIZE(sitar_dai));
+ else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
+ sitar_i2s_dai, ARRAY_SIZE(sitar_i2s_dai));
return ret;
}
static int __devexit sitar_remove(struct platform_device *pdev)
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 4b4dae1..e85e9f5 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -4256,7 +4256,8 @@
continue;
if (!strncmp(w->sname,
tabla_dai[j].playback.stream_name, 13)) {
- --tabla_p->dai[j].ch_act;
+ if (tabla_p->dai[j].ch_act)
+ --tabla_p->dai[j].ch_act;
break;
}
}
@@ -5265,16 +5266,37 @@
wcd9xxx_unlock_sleep(core);
}
+static u16 tabla_get_cfilt_reg(struct snd_soc_codec *codec, u8 cfilt)
+{
+ u16 reg;
+
+ switch (cfilt) {
+ case TABLA_CFILT1_SEL:
+ reg = TABLA_A_MICB_CFILT_1_CTL;
+ break;
+ case TABLA_CFILT2_SEL:
+ reg = TABLA_A_MICB_CFILT_2_CTL;
+ break;
+ case TABLA_CFILT3_SEL:
+ reg = TABLA_A_MICB_CFILT_3_CTL;
+ break;
+ default:
+ BUG();
+ }
+ return reg;
+}
+
void tabla_mbhc_cal(struct snd_soc_codec *codec)
{
struct tabla_priv *tabla;
struct tabla_mbhc_btn_detect_cfg *btn_det;
- u8 cfilt_mode, bg_mode;
+ u8 cfilt_mode, micbias2_cfilt_mode, bg_mode;
u8 ncic, nmeas, navg;
u32 mclk_rate;
u32 dce_wait, sta_wait;
u8 *n_cic;
void *calibration;
+ u16 bias2_ctl;
tabla = snd_soc_codec_get_drvdata(codec);
calibration = tabla->mbhc_cfg.calibration;
@@ -5303,7 +5325,16 @@
* Need to restore defaults once calculation is done.
*/
cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
- snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
+ micbias2_cfilt_mode =
+ snd_soc_read(codec, tabla_get_cfilt_reg(codec,
+ tabla->pdata->micbias.bias2_cfilt_sel));
+ snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
+ TABLA_CFILT_FAST_MODE);
+ snd_soc_update_bits(codec,
+ tabla_get_cfilt_reg(codec,
+ tabla->pdata->micbias.bias2_cfilt_sel),
+ 0x40, TABLA_CFILT_FAST_MODE);
+
bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
0x02);
@@ -5317,6 +5348,12 @@
snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
+ /* MICBIAS2 routing for calibration */
+ bias2_ctl = snd_soc_read(codec, TABLA_A_MICB_2_CTL);
+ snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC, 0x03, TABLA_MICBIAS2);
+ snd_soc_write(codec, TABLA_A_MICB_2_CTL,
+ snd_soc_read(codec, tabla->mbhc_bias_regs.ctl_reg));
+
/* DCE measurement for 0 volts */
snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
@@ -5354,7 +5391,15 @@
tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
/* Restore default settings. */
+ snd_soc_write(codec, TABLA_A_MICB_2_CTL, bias2_ctl);
+ snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC, 0x03,
+ tabla->mbhc_cfg.micbias);
+
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+ snd_soc_update_bits(codec,
+ tabla_get_cfilt_reg(codec,
+ tabla->pdata->micbias.bias2_cfilt_sel), 0x40,
+ micbias2_cfilt_mode);
snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
cfilt_mode);
snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
@@ -5538,6 +5583,10 @@
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
+
+ /* override mbhc's micbias */
+ snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC, 0x03,
+ tabla->mbhc_cfg.micbias);
}
static bool tabla_mbhc_fw_validate(const struct firmware *fw)
@@ -6081,14 +6130,14 @@
int scaled;
struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV);
- int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
+ int num_det = MBHC_NUM_DCE_PLUG_DETECT + 1;
enum tabla_mbhc_plug_type plug_type[num_det];
s16 mb_v[num_det];
s32 mic_mv[num_det];
bool inval;
bool highdelta;
bool ahighv = false, highv;
+ bool gndmicswapped = false;
/* make sure override is on */
WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
@@ -6105,11 +6154,10 @@
* 1st: check if voltage is in invalid range
* 2nd - N-2nd: check voltage range and delta
* N-1st: check voltage range, delta with HPHR GND switch
- * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
+ * Nth: check voltage range with VDDIO switch */
for (i = 0; i < num_det; i++) {
- gndswitch = (i == (num_det - 1 - vddio));
- vddioswitch = (vddio && ((i == num_det - 1) ||
- (i == num_det - 2)));
+ gndswitch = (i == (num_det - 2));
+ vddioswitch = (i == (num_det - 1)) || (i == (num_det - 2));
if (i == 0) {
mb_v[i] = tabla_codec_setup_hs_polling(codec);
mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
@@ -6135,7 +6183,7 @@
* was done with gndswitch, don't compare with DCE
* with gndswitch */
highdelta = tabla_is_inval_ins_delta(codec, scaled,
- mic_mv[i - !gndswitch - vddioswitch],
+ mic_mv[i - 1],
TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV);
inval = (tabla_is_inval_ins_range(codec, mic_mv[i],
highhph, &highv) ||
@@ -6150,9 +6198,13 @@
* good headset is detected but HPHR GND switch makes
* delta difference */
if (i == (num_det - 2) && highdelta && !ahighv)
- plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
- else if (i == (num_det - 1) && inval)
- plug_type[0] = PLUG_TYPE_INVALID;
+ gndmicswapped = true;
+ else if (i == (num_det - 1) && inval) {
+ if (gndmicswapped)
+ plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
+ else
+ plug_type[0] = PLUG_TYPE_INVALID;
+ }
}
pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
"VDDIO %d, inval %d\n", __func__,
diff --git a/sound/soc/codecs/wcd9320-tables.c b/sound/soc/codecs/wcd9320-tables.c
new file mode 100644
index 0000000..68a4670
--- /dev/null
+++ b/sound/soc/codecs/wcd9320-tables.c
@@ -0,0 +1,1359 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/mfd/wcd9xxx/wcd9320_registers.h>
+#include "wcd9320.h"
+
+const u8 taiko_reg_readable[TAIKO_CACHE_SIZE] = {
+ [TAIKO_A_CHIP_CTL] = 1,
+ [TAIKO_A_CHIP_STATUS] = 1,
+ [TAIKO_A_CHIP_ID_BYTE_0] = 1,
+ [TAIKO_A_CHIP_ID_BYTE_1] = 1,
+ [TAIKO_A_CHIP_ID_BYTE_2] = 1,
+ [TAIKO_A_CHIP_ID_BYTE_3] = 1,
+ [TAIKO_A_CHIP_VERSION] = 1,
+ [TAIKO_A_SLAVE_ID_1] = 1,
+ [TAIKO_A_SLAVE_ID_2] = 1,
+ [TAIKO_A_SLAVE_ID_3] = 1,
+ [TAIKO_A_PIN_CTL_OE0] = 1,
+ [TAIKO_A_PIN_CTL_OE1] = 1,
+ [TAIKO_A_PIN_CTL_DATA0] = 1,
+ [TAIKO_A_PIN_CTL_DATA1] = 1,
+ [TAIKO_A_HDRIVE_GENERIC] = 1,
+ [TAIKO_A_HDRIVE_OVERRIDE] = 1,
+ [TAIKO_A_ANA_CSR_WAIT_STATE] = 1,
+ [TAIKO_A_PROCESS_MONITOR_CTL0] = 1,
+ [TAIKO_A_PROCESS_MONITOR_CTL1] = 1,
+ [TAIKO_A_PROCESS_MONITOR_CTL2] = 1,
+ [TAIKO_A_PROCESS_MONITOR_CTL3] = 1,
+ [TAIKO_A_QFUSE_CTL] = 1,
+ [TAIKO_A_QFUSE_STATUS] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT0] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT1] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT2] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT3] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT4] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT5] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT6] = 1,
+ [TAIKO_A_QFUSE_DATA_OUT7] = 1,
+ [TAIKO_A_CDC_CTL] = 1,
+ [TAIKO_A_LEAKAGE_CTL] = 1,
+ [TAIKO_A_INTR_MODE] = 1,
+ [TAIKO_A_INTR_MASK0] = 1,
+ [TAIKO_A_INTR_MASK1] = 1,
+ [TAIKO_A_INTR_MASK2] = 1,
+ [TAIKO_A_INTR_MASK3] = 1,
+ [TAIKO_A_INTR_STATUS0] = 1,
+ [TAIKO_A_INTR_STATUS1] = 1,
+ [TAIKO_A_INTR_STATUS2] = 1,
+ [TAIKO_A_INTR_STATUS3] = 1,
+ [TAIKO_A_INTR_CLEAR0] = 0,
+ [TAIKO_A_INTR_CLEAR1] = 0,
+ [TAIKO_A_INTR_CLEAR2] = 0,
+ [TAIKO_A_INTR_CLEAR3] = 0,
+ [TAIKO_A_INTR_LEVEL0] = 1,
+ [TAIKO_A_INTR_LEVEL1] = 1,
+ [TAIKO_A_INTR_LEVEL2] = 1,
+ [TAIKO_A_INTR_LEVEL3] = 1,
+ [TAIKO_A_INTR_TEST0] = 1,
+ [TAIKO_A_INTR_TEST1] = 1,
+ [TAIKO_A_INTR_TEST2] = 1,
+ [TAIKO_A_INTR_TEST3] = 1,
+ [TAIKO_A_INTR_SET0] = 1,
+ [TAIKO_A_INTR_SET1] = 1,
+ [TAIKO_A_INTR_SET2] = 1,
+ [TAIKO_A_INTR_SET3] = 1,
+ [TAIKO_A_INTR_DESTN0] = 1,
+ [TAIKO_A_INTR_DESTN1] = 1,
+ [TAIKO_A_INTR_DESTN2] = 1,
+ [TAIKO_A_INTR_DESTN3] = 1,
+ [TAIKO_A_CDC_TX_I2S_SCK_MODE] = 1,
+ [TAIKO_A_CDC_TX_I2S_WS_MODE] = 1,
+ [TAIKO_A_CDC_DMIC_DATA0_MODE] = 1,
+ [TAIKO_A_CDC_DMIC_CLK0_MODE] = 1,
+ [TAIKO_A_CDC_DMIC_DATA1_MODE] = 1,
+ [TAIKO_A_CDC_DMIC_CLK1_MODE] = 1,
+ [TAIKO_A_CDC_RX_I2S_SCK_MODE] = 1,
+ [TAIKO_A_CDC_RX_I2S_WS_MODE] = 1,
+ [TAIKO_A_CDC_DMIC_DATA2_MODE] = 1,
+ [TAIKO_A_CDC_DMIC_CLK2_MODE] = 1,
+ [TAIKO_A_CDC_INTR1_MODE] = 1,
+ [TAIKO_A_CDC_SB_NRZ_SEL_MODE] = 1,
+ [TAIKO_A_CDC_INTR2_MODE] = 1,
+ [TAIKO_A_CDC_RF_PA_ON_MODE] = 1,
+ [TAIKO_A_BIAS_REF_CTL] = 1,
+ [TAIKO_A_BIAS_CENTRAL_BG_CTL] = 1,
+ [TAIKO_A_BIAS_PRECHRG_CTL] = 1,
+ [TAIKO_A_BIAS_CURR_CTL_1] = 1,
+ [TAIKO_A_BIAS_CURR_CTL_2] = 1,
+ [TAIKO_A_BIAS_OSC_BG_CTL] = 1,
+ [TAIKO_A_CLK_BUFF_EN1] = 1,
+ [TAIKO_A_CLK_BUFF_EN2] = 1,
+ [TAIKO_A_LDO_H_MODE_1] = 1,
+ [TAIKO_A_LDO_H_MODE_2] = 1,
+ [TAIKO_A_LDO_H_LOOP_CTL] = 1,
+ [TAIKO_A_LDO_H_COMP_1] = 1,
+ [TAIKO_A_LDO_H_COMP_2] = 1,
+ [TAIKO_A_LDO_H_BIAS_1] = 1,
+ [TAIKO_A_LDO_H_BIAS_2] = 1,
+ [TAIKO_A_LDO_H_BIAS_3] = 1,
+ [TAIKO_A_VBAT_CLK] = 1,
+ [TAIKO_A_VBAT_LOOP] = 1,
+ [TAIKO_A_VBAT_REF] = 1,
+ [TAIKO_A_VBAT_ADC_TEST] = 1,
+ [TAIKO_A_VBAT_FE] = 1,
+ [TAIKO_A_VBAT_BIAS_1] = 1,
+ [TAIKO_A_VBAT_BIAS_2] = 1,
+ [TAIKO_A_VBAT_ADC_DATA_MSB] = 1,
+ [TAIKO_A_VBAT_ADC_DATA_LSB] = 1,
+ [TAIKO_A_MICB_CFILT_1_CTL] = 1,
+ [TAIKO_A_MICB_CFILT_1_VAL] = 1,
+ [TAIKO_A_MICB_CFILT_1_PRECHRG] = 1,
+ [TAIKO_A_MICB_1_CTL] = 1,
+ [TAIKO_A_MICB_1_INT_RBIAS] = 1,
+ [TAIKO_A_MICB_1_MBHC] = 1,
+ [TAIKO_A_MICB_CFILT_2_CTL] = 1,
+ [TAIKO_A_MICB_CFILT_2_VAL] = 1,
+ [TAIKO_A_MICB_CFILT_2_PRECHRG] = 1,
+ [TAIKO_A_MICB_2_CTL] = 1,
+ [TAIKO_A_MICB_2_INT_RBIAS] = 1,
+ [TAIKO_A_MICB_2_MBHC] = 1,
+ [TAIKO_A_MICB_CFILT_3_CTL] = 1,
+ [TAIKO_A_MICB_CFILT_3_VAL] = 1,
+ [TAIKO_A_MICB_CFILT_3_PRECHRG] = 1,
+ [TAIKO_A_MICB_3_CTL] = 1,
+ [TAIKO_A_MICB_3_INT_RBIAS] = 1,
+ [TAIKO_A_MICB_3_MBHC] = 1,
+ [TAIKO_A_MICB_4_CTL] = 1,
+ [TAIKO_A_MICB_4_INT_RBIAS] = 1,
+ [TAIKO_A_MICB_4_MBHC] = 1,
+ [TAIKO_A_MBHC_INSERT_DETECT] = 1,
+ [TAIKO_A_MBHC_INSERT_DET_STATUS] = 1,
+ [TAIKO_A_TX_COM_BIAS] = 1,
+ [TAIKO_A_MBHC_SCALING_MUX_1] = 1,
+ [TAIKO_A_MBHC_SCALING_MUX_2] = 1,
+ [TAIKO_A_MAD_ANA_CTRL] = 1,
+ [TAIKO_A_TX_SUP_SWITCH_CTRL_1] = 1,
+ [TAIKO_A_TX_SUP_SWITCH_CTRL_2] = 1,
+ [TAIKO_A_TX_1_2_EN] = 1,
+ [TAIKO_A_TX_1_2_TEST_EN] = 1,
+ [TAIKO_A_TX_1_2_ADC_CH1] = 1,
+ [TAIKO_A_TX_1_2_ADC_CH2] = 1,
+ [TAIKO_A_TX_1_2_ATEST_REFCTRL] = 1,
+ [TAIKO_A_TX_1_2_TEST_CTL] = 1,
+ [TAIKO_A_TX_1_2_TEST_BLOCK_EN] = 1,
+ [TAIKO_A_TX_1_2_TXFE_CLKDIV] = 1,
+ [TAIKO_A_TX_1_2_SAR_ERR_CH1] = 1,
+ [TAIKO_A_TX_1_2_SAR_ERR_CH2] = 1,
+ [TAIKO_A_TX_3_4_EN] = 1,
+ [TAIKO_A_TX_3_4_TEST_EN] = 1,
+ [TAIKO_A_TX_3_4_ADC_CH3] = 1,
+ [TAIKO_A_TX_3_4_ADC_CH4] = 1,
+ [TAIKO_A_TX_3_4_ATEST_REFCTRL] = 1,
+ [TAIKO_A_TX_3_4_TEST_CTL] = 1,
+ [TAIKO_A_TX_3_4_TEST_BLOCK_EN] = 1,
+ [TAIKO_A_TX_3_4_TXFE_CKDIV] = 1,
+ [TAIKO_A_TX_3_4_SAR_ERR_CH3] = 1,
+ [TAIKO_A_TX_3_4_SAR_ERR_CH4] = 1,
+ [TAIKO_A_TX_5_6_EN] = 1,
+ [TAIKO_A_TX_5_6_TEST_EN] = 1,
+ [TAIKO_A_TX_5_6_ADC_CH5] = 1,
+ [TAIKO_A_TX_5_6_ADC_CH6] = 1,
+ [TAIKO_A_TX_5_6_ATEST_REFCTRL] = 1,
+ [TAIKO_A_TX_5_6_TEST_CTL] = 1,
+ [TAIKO_A_TX_5_6_TEST_BLOCK_EN] = 1,
+ [TAIKO_A_TX_5_6_TXFE_CKDIV] = 1,
+ [TAIKO_A_TX_5_6_SAR_ERR_CH5] = 1,
+ [TAIKO_A_TX_5_6_SAR_ERR_CH6] = 1,
+ [TAIKO_A_TX_7_MBHC_EN] = 1,
+ [TAIKO_A_TX_7_MBHC_ATEST_REFCTRL] = 1,
+ [TAIKO_A_TX_7_MBHC_ADC] = 1,
+ [TAIKO_A_TX_7_MBHC_TEST_CTL] = 1,
+ [TAIKO_A_TX_7_MBHC_SAR_ERR] = 1,
+ [TAIKO_A_TX_7_TXFE_CLKDIV] = 1,
+ [TAIKO_A_BUCK_MODE_1] = 1,
+ [TAIKO_A_BUCK_MODE_2] = 1,
+ [TAIKO_A_BUCK_MODE_3] = 1,
+ [TAIKO_A_BUCK_MODE_4] = 1,
+ [TAIKO_A_BUCK_MODE_5] = 1,
+ [TAIKO_A_BUCK_CTRL_VCL_1] = 1,
+ [TAIKO_A_BUCK_CTRL_VCL_2] = 1,
+ [TAIKO_A_BUCK_CTRL_VCL_3] = 1,
+ [TAIKO_A_BUCK_CTRL_CCL_1] = 1,
+ [TAIKO_A_BUCK_CTRL_CCL_2] = 1,
+ [TAIKO_A_BUCK_CTRL_CCL_3] = 1,
+ [TAIKO_A_BUCK_CTRL_CCL_4] = 1,
+ [TAIKO_A_BUCK_CTRL_PWM_DRVR_1] = 1,
+ [TAIKO_A_BUCK_CTRL_PWM_DRVR_2] = 1,
+ [TAIKO_A_BUCK_CTRL_PWM_DRVR_3] = 1,
+ [TAIKO_A_BUCK_TMUX_A_D] = 1,
+ [TAIKO_A_NCP_BUCKREF] = 1,
+ [TAIKO_A_NCP_EN] = 1,
+ [TAIKO_A_NCP_CLK] = 1,
+ [TAIKO_A_NCP_STATIC] = 1,
+ [TAIKO_A_NCP_VTH_LOW] = 1,
+ [TAIKO_A_NCP_VTH_HIGH] = 1,
+ [TAIKO_A_NCP_ATEST] = 1,
+ [TAIKO_A_NCP_DTEST] = 1,
+ [TAIKO_A_NCP_DLY1] = 1,
+ [TAIKO_A_NCP_DLY2] = 1,
+ [TAIKO_A_RX_AUX_SW_CTL] = 1,
+ [TAIKO_A_RX_PA_AUX_IN_CONN] = 1,
+ [TAIKO_A_RX_COM_TIMER_DIV] = 1,
+ [TAIKO_A_RX_COM_OCP_CTL] = 1,
+ [TAIKO_A_RX_COM_OCP_COUNT] = 1,
+ [TAIKO_A_RX_COM_DAC_CTL] = 1,
+ [TAIKO_A_RX_COM_BIAS] = 1,
+ [TAIKO_A_RX_HPH_AUTO_CHOP] = 1,
+ [TAIKO_A_RX_HPH_CHOP_CTL] = 1,
+ [TAIKO_A_RX_HPH_BIAS_PA] = 1,
+ [TAIKO_A_RX_HPH_BIAS_LDO] = 1,
+ [TAIKO_A_RX_HPH_BIAS_CNP] = 1,
+ [TAIKO_A_RX_HPH_BIAS_WG_OCP] = 1,
+ [TAIKO_A_RX_HPH_OCP_CTL] = 1,
+ [TAIKO_A_RX_HPH_CNP_EN] = 1,
+ [TAIKO_A_RX_HPH_CNP_WG_CTL] = 1,
+ [TAIKO_A_RX_HPH_CNP_WG_TIME] = 1,
+ [TAIKO_A_RX_HPH_L_GAIN] = 1,
+ [TAIKO_A_RX_HPH_L_TEST] = 1,
+ [TAIKO_A_RX_HPH_L_PA_CTL] = 1,
+ [TAIKO_A_RX_HPH_L_DAC_CTL] = 1,
+ [TAIKO_A_RX_HPH_L_ATEST] = 1,
+ [TAIKO_A_RX_HPH_L_STATUS] = 1,
+ [TAIKO_A_RX_HPH_R_GAIN] = 1,
+ [TAIKO_A_RX_HPH_R_TEST] = 1,
+ [TAIKO_A_RX_HPH_R_PA_CTL] = 1,
+ [TAIKO_A_RX_HPH_R_DAC_CTL] = 1,
+ [TAIKO_A_RX_HPH_R_ATEST] = 1,
+ [TAIKO_A_RX_HPH_R_STATUS] = 1,
+ [TAIKO_A_RX_EAR_BIAS_PA] = 1,
+ [TAIKO_A_RX_EAR_BIAS_CMBUFF] = 1,
+ [TAIKO_A_RX_EAR_EN] = 1,
+ [TAIKO_A_RX_EAR_GAIN] = 1,
+ [TAIKO_A_RX_EAR_CMBUFF] = 1,
+ [TAIKO_A_RX_EAR_ICTL] = 1,
+ [TAIKO_A_RX_EAR_CCOMP] = 1,
+ [TAIKO_A_RX_EAR_VCM] = 1,
+ [TAIKO_A_RX_EAR_CNP] = 1,
+ [TAIKO_A_RX_EAR_DAC_CTL_ATEST] = 1,
+ [TAIKO_A_RX_EAR_STATUS] = 1,
+ [TAIKO_A_RX_LINE_BIAS_PA] = 1,
+ [TAIKO_A_RX_BUCK_BIAS1] = 1,
+ [TAIKO_A_RX_BUCK_BIAS2] = 1,
+ [TAIKO_A_RX_LINE_COM] = 1,
+ [TAIKO_A_RX_LINE_CNP_EN] = 1,
+ [TAIKO_A_RX_LINE_CNP_WG_CTL] = 1,
+ [TAIKO_A_RX_LINE_CNP_WG_TIME] = 1,
+ [TAIKO_A_RX_LINE_1_GAIN] = 1,
+ [TAIKO_A_RX_LINE_1_TEST] = 1,
+ [TAIKO_A_RX_LINE_1_DAC_CTL] = 1,
+ [TAIKO_A_RX_LINE_1_STATUS] = 1,
+ [TAIKO_A_RX_LINE_2_GAIN] = 1,
+ [TAIKO_A_RX_LINE_2_TEST] = 1,
+ [TAIKO_A_RX_LINE_2_DAC_CTL] = 1,
+ [TAIKO_A_RX_LINE_2_STATUS] = 1,
+ [TAIKO_A_RX_LINE_3_GAIN] = 1,
+ [TAIKO_A_RX_LINE_3_TEST] = 1,
+ [TAIKO_A_RX_LINE_3_DAC_CTL] = 1,
+ [TAIKO_A_RX_LINE_3_STATUS] = 1,
+ [TAIKO_A_RX_LINE_4_GAIN] = 1,
+ [TAIKO_A_RX_LINE_4_TEST] = 1,
+ [TAIKO_A_RX_LINE_4_DAC_CTL] = 1,
+ [TAIKO_A_RX_LINE_4_STATUS] = 1,
+ [TAIKO_A_RX_LINE_CNP_DBG] = 1,
+ [TAIKO_A_SPKR_DRV_EN] = 1,
+ [TAIKO_A_SPKR_DRV_GAIN] = 1,
+ [TAIKO_A_SPKR_DRV_DAC_CTL] = 1,
+ [TAIKO_A_SPKR_DRV_OCP_CTL] = 1,
+ [TAIKO_A_SPKR_DRV_CLIP_DET] = 1,
+ [TAIKO_A_SPKR_DRV_IEC] = 1,
+ [TAIKO_A_SPKR_DRV_DBG_DAC] = 1,
+ [TAIKO_A_SPKR_DRV_DBG_PA] = 1,
+ [TAIKO_A_SPKR_DRV_DBG_PWRSTG] = 1,
+ [TAIKO_A_SPKR_DRV_BIAS_LDO] = 1,
+ [TAIKO_A_SPKR_DRV_BIAS_INT] = 1,
+ [TAIKO_A_SPKR_DRV_BIAS_PA] = 1,
+ [TAIKO_A_SPKR_DRV_STATUS_OCP] = 1,
+ [TAIKO_A_SPKR_DRV_STATUS_PA] = 1,
+ [TAIKO_A_SPKR_PROT_EN] = 1,
+ [TAIKO_A_SPKR_PROT_ADC_EN] = 1,
+ [TAIKO_A_SPKR_PROT_ISENSE_BIAS] = 1,
+ [TAIKO_A_SPKR_PROT_VSENSE_BIAS] = 1,
+ [TAIKO_A_SPKR_PROT_ADC_ATEST_REFCTRL] = 1,
+ [TAIKO_A_SPKR_PROT_ADC_TEST_CTL] = 1,
+ [TAIKO_A_SPKR_PROT_TEST_BLOCK_EN] = 1,
+ [TAIKO_A_SPKR_PROT_ATEST] = 1,
+ [TAIKO_A_SPKR_PROT_V_SAR_ERR] = 1,
+ [TAIKO_A_SPKR_PROT_I_SAR_ERR] = 1,
+ [TAIKO_A_SPKR_PROT_LDO_CTRL] = 1,
+ [TAIKO_A_SPKR_PROT_ISENSE_CTRL] = 1,
+ [TAIKO_A_SPKR_PROT_VSENSE_CTRL] = 1,
+ [TAIKO_A_RC_OSC_FREQ] = 1,
+ [TAIKO_A_RC_OSC_TEST] = 1,
+ [TAIKO_A_RC_OSC_STATUS] = 1,
+ [TAIKO_A_RC_OSC_TUNER] = 1,
+ [TAIKO_A_MBHC_HPH] = 1,
+ [TAIKO_A_CDC_ANC1_B1_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_B1_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_SHIFT] = 1,
+ [TAIKO_A_CDC_ANC2_SHIFT] = 1,
+ [TAIKO_A_CDC_ANC1_IIR_B1_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_IIR_B1_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_IIR_B2_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_IIR_B2_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_IIR_B3_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_IIR_B3_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_LPF_B1_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_LPF_B1_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_LPF_B2_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_LPF_B2_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_SPARE] = 1,
+ [TAIKO_A_CDC_ANC2_SPARE] = 1,
+ [TAIKO_A_CDC_ANC1_SMLPF_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_SMLPF_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_DCFLT_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_DCFLT_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_GAIN_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_GAIN_CTL] = 1,
+ [TAIKO_A_CDC_ANC1_B2_CTL] = 1,
+ [TAIKO_A_CDC_ANC2_B2_CTL] = 1,
+ [TAIKO_A_CDC_TX1_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX2_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX3_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX4_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX5_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX6_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX7_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX8_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX9_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX10_VOL_CTL_TIMER] = 1,
+ [TAIKO_A_CDC_TX1_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX2_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX3_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX4_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX5_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX6_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX7_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX8_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX9_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX10_VOL_CTL_GAIN] = 1,
+ [TAIKO_A_CDC_TX1_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX2_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX3_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX4_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX5_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX6_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX7_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX8_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX9_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX10_VOL_CTL_CFG] = 1,
+ [TAIKO_A_CDC_TX1_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX2_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX3_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX4_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX5_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX6_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX7_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX8_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX9_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX10_MUX_CTL] = 1,
+ [TAIKO_A_CDC_TX1_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX2_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX3_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX4_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX5_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX6_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX7_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX8_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX9_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX10_CLK_FS_CTL] = 1,
+ [TAIKO_A_CDC_TX1_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX2_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX3_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX4_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX5_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX6_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX7_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX8_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX9_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_TX10_DMIC_CTL] = 1,
+ [TAIKO_A_CDC_DEBUG_B1_CTL] = 1,
+ [TAIKO_A_CDC_DEBUG_B2_CTL] = 1,
+ [TAIKO_A_CDC_DEBUG_B3_CTL] = 1,
+ [TAIKO_A_CDC_DEBUG_B4_CTL] = 1,
+ [TAIKO_A_CDC_DEBUG_B5_CTL] = 1,
+ [TAIKO_A_CDC_DEBUG_B6_CTL] = 1,
+ [TAIKO_A_CDC_DEBUG_B7_CTL] = 1,
+ [TAIKO_A_CDC_SRC1_PDA_CFG] = 1,
+ [TAIKO_A_CDC_SRC2_PDA_CFG] = 1,
+ [TAIKO_A_CDC_SRC1_FS_CTL] = 1,
+ [TAIKO_A_CDC_SRC2_FS_CTL] = 1,
+ [TAIKO_A_CDC_RX1_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX2_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX3_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX4_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX5_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX6_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX7_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX1_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX2_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX3_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX4_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX5_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX6_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX7_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX1_B3_CTL] = 1,
+ [TAIKO_A_CDC_RX2_B3_CTL] = 1,
+ [TAIKO_A_CDC_RX3_B3_CTL] = 1,
+ [TAIKO_A_CDC_RX4_B3_CTL] = 1,
+ [TAIKO_A_CDC_RX5_B3_CTL] = 1,
+ [TAIKO_A_CDC_RX6_B3_CTL] = 1,
+ [TAIKO_A_CDC_RX7_B3_CTL] = 1,
+ [TAIKO_A_CDC_RX1_B4_CTL] = 1,
+ [TAIKO_A_CDC_RX2_B4_CTL] = 1,
+ [TAIKO_A_CDC_RX3_B4_CTL] = 1,
+ [TAIKO_A_CDC_RX4_B4_CTL] = 1,
+ [TAIKO_A_CDC_RX5_B4_CTL] = 1,
+ [TAIKO_A_CDC_RX6_B4_CTL] = 1,
+ [TAIKO_A_CDC_RX7_B4_CTL] = 1,
+ [TAIKO_A_CDC_RX1_B5_CTL] = 1,
+ [TAIKO_A_CDC_RX2_B5_CTL] = 1,
+ [TAIKO_A_CDC_RX3_B5_CTL] = 1,
+ [TAIKO_A_CDC_RX4_B5_CTL] = 1,
+ [TAIKO_A_CDC_RX5_B5_CTL] = 1,
+ [TAIKO_A_CDC_RX6_B5_CTL] = 1,
+ [TAIKO_A_CDC_RX7_B5_CTL] = 1,
+ [TAIKO_A_CDC_RX1_B6_CTL] = 1,
+ [TAIKO_A_CDC_RX2_B6_CTL] = 1,
+ [TAIKO_A_CDC_RX3_B6_CTL] = 1,
+ [TAIKO_A_CDC_RX4_B6_CTL] = 1,
+ [TAIKO_A_CDC_RX5_B6_CTL] = 1,
+ [TAIKO_A_CDC_RX6_B6_CTL] = 1,
+ [TAIKO_A_CDC_RX7_B6_CTL] = 1,
+ [TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX3_VOL_CTL_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX4_VOL_CTL_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX5_VOL_CTL_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX6_VOL_CTL_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX7_VOL_CTL_B1_CTL] = 1,
+ [TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL] = 1,
+ [TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL] = 1,
+ [TAIKO_A_CDC_VBAT_CFG] = 1,
+ [TAIKO_A_CDC_VBAT_ADC_CAL1] = 1,
+ [TAIKO_A_CDC_VBAT_ADC_CAL2] = 1,
+ [TAIKO_A_CDC_VBAT_ADC_CAL3] = 1,
+ [TAIKO_A_CDC_VBAT_PK_EST1] = 1,
+ [TAIKO_A_CDC_VBAT_PK_EST2] = 1,
+ [TAIKO_A_CDC_VBAT_PK_EST3] = 1,
+ [TAIKO_A_CDC_VBAT_RF_PROC1] = 1,
+ [TAIKO_A_CDC_VBAT_RF_PROC2] = 1,
+ [TAIKO_A_CDC_VBAT_TAC1] = 1,
+ [TAIKO_A_CDC_VBAT_TAC2] = 1,
+ [TAIKO_A_CDC_VBAT_TAC3] = 1,
+ [TAIKO_A_CDC_VBAT_TAC4] = 1,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD1] = 1,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD2] = 1,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD3] = 1,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD4] = 1,
+ [TAIKO_A_CDC_VBAT_DEBUG1] = 1,
+ [TAIKO_A_CDC_CLK_ANC_RESET_CTL] = 1,
+ [TAIKO_A_CDC_CLK_RX_RESET_CTL] = 1,
+ [TAIKO_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
+ [TAIKO_A_CDC_CLK_TX_RESET_B2_CTL] = 1,
+ [TAIKO_A_CDC_CLK_DMIC_B1_CTL] = 1,
+ [TAIKO_A_CDC_CLK_DMIC_B2_CTL] = 1,
+ [TAIKO_A_CDC_CLK_RX_I2S_CTL] = 1,
+ [TAIKO_A_CDC_CLK_TX_I2S_CTL] = 1,
+ [TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL] = 1,
+ [TAIKO_A_CDC_CLK_OTHR_RESET_B2_CTL] = 1,
+ [TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL] = 1,
+ [TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL] = 1,
+ [TAIKO_A_CDC_CLK_OTHR_CTL] = 1,
+ [TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL] = 1,
+ [TAIKO_A_CDC_CLK_ANC_CLK_EN_CTL] = 1,
+ [TAIKO_A_CDC_CLK_RX_B1_CTL] = 1,
+ [TAIKO_A_CDC_CLK_RX_B2_CTL] = 1,
+ [TAIKO_A_CDC_CLK_MCLK_CTL] = 1,
+ [TAIKO_A_CDC_CLK_PDM_CTL] = 1,
+ [TAIKO_A_CDC_CLK_SD_CTL] = 1,
+ [TAIKO_A_CDC_CLK_POWER_CTL] = 1,
+ [TAIKO_A_CDC_CLSH_B1_CTL] = 1,
+ [TAIKO_A_CDC_CLSH_B2_CTL] = 1,
+ [TAIKO_A_CDC_CLSH_B3_CTL] = 1,
+ [TAIKO_A_CDC_CLSH_BUCK_NCP_VARS] = 1,
+ [TAIKO_A_CDC_CLSH_IDLE_HPH_THSD] = 1,
+ [TAIKO_A_CDC_CLSH_IDLE_EAR_THSD] = 1,
+ [TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD] = 1,
+ [TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD] = 1,
+ [TAIKO_A_CDC_CLSH_K_ADDR] = 1,
+ [TAIKO_A_CDC_CLSH_K_DATA] = 1,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L] = 1,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U] = 1,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L] = 1,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U] = 1,
+ [TAIKO_A_CDC_CLSH_V_PA_HD_EAR] = 1,
+ [TAIKO_A_CDC_CLSH_V_PA_HD_HPH] = 1,
+ [TAIKO_A_CDC_CLSH_V_PA_MIN_EAR] = 1,
+ [TAIKO_A_CDC_CLSH_V_PA_MIN_HPH] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B1_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B1_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B2_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B2_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B3_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B3_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B4_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B4_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B5_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B5_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B6_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B6_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B7_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B7_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_B8_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_B8_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_COEF_B1_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_COEF_B1_CTL] = 1,
+ [TAIKO_A_CDC_IIR1_COEF_B2_CTL] = 1,
+ [TAIKO_A_CDC_IIR2_COEF_B2_CTL] = 1,
+ [TAIKO_A_CDC_TOP_GAIN_UPDATE] = 1,
+ [TAIKO_A_CDC_COMP0_B1_CTL] = 1,
+ [TAIKO_A_CDC_COMP1_B1_CTL] = 1,
+ [TAIKO_A_CDC_COMP2_B1_CTL] = 1,
+ [TAIKO_A_CDC_COMP0_B2_CTL] = 1,
+ [TAIKO_A_CDC_COMP1_B2_CTL] = 1,
+ [TAIKO_A_CDC_COMP2_B2_CTL] = 1,
+ [TAIKO_A_CDC_COMP0_B3_CTL] = 1,
+ [TAIKO_A_CDC_COMP1_B3_CTL] = 1,
+ [TAIKO_A_CDC_COMP2_B3_CTL] = 1,
+ [TAIKO_A_CDC_COMP0_B4_CTL] = 1,
+ [TAIKO_A_CDC_COMP1_B4_CTL] = 1,
+ [TAIKO_A_CDC_COMP2_B4_CTL] = 1,
+ [TAIKO_A_CDC_COMP0_B5_CTL] = 1,
+ [TAIKO_A_CDC_COMP1_B5_CTL] = 1,
+ [TAIKO_A_CDC_COMP2_B5_CTL] = 1,
+ [TAIKO_A_CDC_COMP0_B6_CTL] = 1,
+ [TAIKO_A_CDC_COMP1_B6_CTL] = 1,
+ [TAIKO_A_CDC_COMP2_B6_CTL] = 1,
+ [TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS] = 1,
+ [TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
+ [TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS] = 1,
+ [TAIKO_A_CDC_COMP0_FS_CFG] = 1,
+ [TAIKO_A_CDC_COMP1_FS_CFG] = 1,
+ [TAIKO_A_CDC_COMP2_FS_CFG] = 1,
+ [TAIKO_A_CDC_CONN_RX1_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX1_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX1_B3_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX2_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX2_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX2_B3_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX3_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX3_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX4_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX4_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX5_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX5_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX6_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX6_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX7_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX7_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX7_B3_CTL] = 1,
+ [TAIKO_A_CDC_CONN_ANC_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_ANC_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_B3_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_B4_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ1_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ1_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ1_B3_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ1_B4_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ2_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ2_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ2_B3_CTL] = 1,
+ [TAIKO_A_CDC_CONN_EQ2_B4_CTL] = 1,
+ [TAIKO_A_CDC_CONN_SRC1_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_SRC1_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_SRC2_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_SRC2_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B3_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B4_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B5_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B6_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B7_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B8_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B9_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B10_CTL] = 1,
+ [TAIKO_A_CDC_CONN_TX_SB_B11_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX_SB_B1_CTL] = 1,
+ [TAIKO_A_CDC_CONN_RX_SB_B2_CTL] = 1,
+ [TAIKO_A_CDC_CONN_CLSH_CTL] = 1,
+ [TAIKO_A_CDC_CONN_MISC] = 1,
+ [TAIKO_A_CDC_CONN_MAD] = 1,
+ [TAIKO_A_CDC_MBHC_EN_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_FIR_B1_CFG] = 1,
+ [TAIKO_A_CDC_MBHC_FIR_B2_CFG] = 1,
+ [TAIKO_A_CDC_MBHC_TIMER_B1_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_TIMER_B2_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_TIMER_B3_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_TIMER_B4_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_TIMER_B5_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_TIMER_B6_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_B1_STATUS] = 1,
+ [TAIKO_A_CDC_MBHC_B2_STATUS] = 1,
+ [TAIKO_A_CDC_MBHC_B3_STATUS] = 1,
+ [TAIKO_A_CDC_MBHC_B4_STATUS] = 1,
+ [TAIKO_A_CDC_MBHC_B5_STATUS] = 1,
+ [TAIKO_A_CDC_MBHC_B1_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_B2_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B1_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B2_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B3_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B4_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B5_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B6_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B7_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B8_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B9_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B10_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B11_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_VOLT_B12_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_CLK_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_INT_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_DEBUG_CTL] = 1,
+ [TAIKO_A_CDC_MBHC_SPARE] = 1,
+ [TAIKO_A_CDC_MAD_MAIN_CTL_1] = 1,
+ [TAIKO_A_CDC_MAD_MAIN_CTL_2] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_1] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_2] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_3] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_4] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_5] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_6] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_7] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_8] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR] = 1,
+ [TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL] = 1,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_1] = 1,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_2] = 1,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_3] = 1,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_4] = 1,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_5] = 1,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_6] = 1,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_7] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_1] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_2] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_3] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_4] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_5] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_6] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_7] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_8] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR] = 1,
+ [TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] = 1,
+};
+
+const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE] = {
+ [TAIKO_A_CHIP_CTL] = TAIKO_A_CHIP_CTL__POR,
+ [TAIKO_A_CHIP_STATUS] = TAIKO_A_CHIP_STATUS__POR,
+ [TAIKO_A_CHIP_ID_BYTE_0] = TAIKO_A_CHIP_ID_BYTE_0__POR,
+ [TAIKO_A_CHIP_ID_BYTE_1] = TAIKO_A_CHIP_ID_BYTE_1__POR,
+ [TAIKO_A_CHIP_ID_BYTE_2] = TAIKO_A_CHIP_ID_BYTE_2__POR,
+ [TAIKO_A_CHIP_ID_BYTE_3] = TAIKO_A_CHIP_ID_BYTE_3__POR,
+ [TAIKO_A_CHIP_VERSION] = TAIKO_A_CHIP_VERSION__POR,
+ [TAIKO_A_SLAVE_ID_1] = TAIKO_A_SLAVE_ID_1__POR,
+ [TAIKO_A_SLAVE_ID_2] = TAIKO_A_SLAVE_ID_2__POR,
+ [TAIKO_A_SLAVE_ID_3] = TAIKO_A_SLAVE_ID_3__POR,
+ [TAIKO_A_PIN_CTL_OE0] = TAIKO_A_PIN_CTL_OE0__POR,
+ [TAIKO_A_PIN_CTL_OE1] = TAIKO_A_PIN_CTL_OE1__POR,
+ [TAIKO_A_PIN_CTL_DATA0] = TAIKO_A_PIN_CTL_DATA0__POR,
+ [TAIKO_A_PIN_CTL_DATA1] = TAIKO_A_PIN_CTL_DATA1__POR,
+ [TAIKO_A_HDRIVE_GENERIC] = TAIKO_A_HDRIVE_GENERIC__POR,
+ [TAIKO_A_HDRIVE_OVERRIDE] = TAIKO_A_HDRIVE_OVERRIDE__POR,
+ [TAIKO_A_ANA_CSR_WAIT_STATE] = TAIKO_A_ANA_CSR_WAIT_STATE__POR,
+ [TAIKO_A_PROCESS_MONITOR_CTL0] = TAIKO_A_PROCESS_MONITOR_CTL0__POR,
+ [TAIKO_A_PROCESS_MONITOR_CTL1] = TAIKO_A_PROCESS_MONITOR_CTL1__POR,
+ [TAIKO_A_PROCESS_MONITOR_CTL2] = TAIKO_A_PROCESS_MONITOR_CTL2__POR,
+ [TAIKO_A_PROCESS_MONITOR_CTL3] = TAIKO_A_PROCESS_MONITOR_CTL3__POR,
+ [TAIKO_A_QFUSE_CTL] = TAIKO_A_QFUSE_CTL__POR,
+ [TAIKO_A_QFUSE_STATUS] = TAIKO_A_QFUSE_STATUS__POR,
+ [TAIKO_A_QFUSE_DATA_OUT0] = TAIKO_A_QFUSE_DATA_OUT0__POR,
+ [TAIKO_A_QFUSE_DATA_OUT1] = TAIKO_A_QFUSE_DATA_OUT1__POR,
+ [TAIKO_A_QFUSE_DATA_OUT2] = TAIKO_A_QFUSE_DATA_OUT2__POR,
+ [TAIKO_A_QFUSE_DATA_OUT3] = TAIKO_A_QFUSE_DATA_OUT3__POR,
+ [TAIKO_A_QFUSE_DATA_OUT4] = TAIKO_A_QFUSE_DATA_OUT4__POR,
+ [TAIKO_A_QFUSE_DATA_OUT5] = TAIKO_A_QFUSE_DATA_OUT5__POR,
+ [TAIKO_A_QFUSE_DATA_OUT6] = TAIKO_A_QFUSE_DATA_OUT6__POR,
+ [TAIKO_A_QFUSE_DATA_OUT7] = TAIKO_A_QFUSE_DATA_OUT7__POR,
+ [TAIKO_A_CDC_CTL] = TAIKO_A_CDC_CTL__POR,
+ [TAIKO_A_LEAKAGE_CTL] = TAIKO_A_LEAKAGE_CTL__POR,
+ [TAIKO_A_INTR_MODE] = TAIKO_A_INTR_MODE__POR,
+ [TAIKO_A_INTR_MASK0] = TAIKO_A_INTR_MASK0__POR,
+ [TAIKO_A_INTR_MASK1] = TAIKO_A_INTR_MASK1__POR,
+ [TAIKO_A_INTR_MASK2] = TAIKO_A_INTR_MASK2__POR,
+ [TAIKO_A_INTR_MASK3] = TAIKO_A_INTR_MASK3__POR,
+ [TAIKO_A_INTR_STATUS0] = TAIKO_A_INTR_STATUS0__POR,
+ [TAIKO_A_INTR_STATUS1] = TAIKO_A_INTR_STATUS1__POR,
+ [TAIKO_A_INTR_STATUS2] = TAIKO_A_INTR_STATUS2__POR,
+ [TAIKO_A_INTR_STATUS3] = TAIKO_A_INTR_STATUS3__POR,
+ [TAIKO_A_INTR_CLEAR0] = TAIKO_A_INTR_CLEAR0__POR,
+ [TAIKO_A_INTR_CLEAR1] = TAIKO_A_INTR_CLEAR1__POR,
+ [TAIKO_A_INTR_CLEAR2] = TAIKO_A_INTR_CLEAR2__POR,
+ [TAIKO_A_INTR_CLEAR3] = TAIKO_A_INTR_CLEAR3__POR,
+ [TAIKO_A_INTR_LEVEL0] = TAIKO_A_INTR_LEVEL0__POR,
+ [TAIKO_A_INTR_LEVEL1] = TAIKO_A_INTR_LEVEL1__POR,
+ [TAIKO_A_INTR_LEVEL2] = TAIKO_A_INTR_LEVEL2__POR,
+ [TAIKO_A_INTR_LEVEL3] = TAIKO_A_INTR_LEVEL3__POR,
+ [TAIKO_A_INTR_TEST0] = TAIKO_A_INTR_TEST0__POR,
+ [TAIKO_A_INTR_TEST1] = TAIKO_A_INTR_TEST1__POR,
+ [TAIKO_A_INTR_TEST2] = TAIKO_A_INTR_TEST2__POR,
+ [TAIKO_A_INTR_TEST3] = TAIKO_A_INTR_TEST3__POR,
+ [TAIKO_A_INTR_SET0] = TAIKO_A_INTR_SET0__POR,
+ [TAIKO_A_INTR_SET1] = TAIKO_A_INTR_SET1__POR,
+ [TAIKO_A_INTR_SET2] = TAIKO_A_INTR_SET2__POR,
+ [TAIKO_A_INTR_SET3] = TAIKO_A_INTR_SET3__POR,
+ [TAIKO_A_INTR_DESTN0] = TAIKO_A_INTR_DESTN0__POR,
+ [TAIKO_A_INTR_DESTN1] = TAIKO_A_INTR_DESTN1__POR,
+ [TAIKO_A_INTR_DESTN2] = TAIKO_A_INTR_DESTN2__POR,
+ [TAIKO_A_INTR_DESTN3] = TAIKO_A_INTR_DESTN3__POR,
+ [TAIKO_A_CDC_TX_I2S_SCK_MODE] = TAIKO_A_CDC_TX_I2S_SCK_MODE__POR,
+ [TAIKO_A_CDC_TX_I2S_WS_MODE] = TAIKO_A_CDC_TX_I2S_WS_MODE__POR,
+ [TAIKO_A_CDC_DMIC_DATA0_MODE] = TAIKO_A_CDC_DMIC_DATA0_MODE__POR,
+ [TAIKO_A_CDC_DMIC_CLK0_MODE] = TAIKO_A_CDC_DMIC_CLK0_MODE__POR,
+ [TAIKO_A_CDC_DMIC_DATA1_MODE] = TAIKO_A_CDC_DMIC_DATA1_MODE__POR,
+ [TAIKO_A_CDC_DMIC_CLK1_MODE] = TAIKO_A_CDC_DMIC_CLK1_MODE__POR,
+ [TAIKO_A_CDC_RX_I2S_SCK_MODE] = TAIKO_A_CDC_RX_I2S_SCK_MODE__POR,
+ [TAIKO_A_CDC_RX_I2S_WS_MODE] = TAIKO_A_CDC_RX_I2S_WS_MODE__POR,
+ [TAIKO_A_CDC_DMIC_DATA2_MODE] = TAIKO_A_CDC_DMIC_DATA2_MODE__POR,
+ [TAIKO_A_CDC_DMIC_CLK2_MODE] = TAIKO_A_CDC_DMIC_CLK2_MODE__POR,
+ [TAIKO_A_CDC_INTR1_MODE] = TAIKO_A_CDC_INTR1_MODE__POR,
+ [TAIKO_A_CDC_SB_NRZ_SEL_MODE] = TAIKO_A_CDC_SB_NRZ_SEL_MODE__POR,
+ [TAIKO_A_CDC_INTR2_MODE] = TAIKO_A_CDC_INTR2_MODE__POR,
+ [TAIKO_A_CDC_RF_PA_ON_MODE] = TAIKO_A_CDC_RF_PA_ON_MODE__POR,
+ [TAIKO_A_BIAS_REF_CTL] = TAIKO_A_BIAS_REF_CTL__POR,
+ [TAIKO_A_BIAS_CENTRAL_BG_CTL] = TAIKO_A_BIAS_CENTRAL_BG_CTL__POR,
+ [TAIKO_A_BIAS_PRECHRG_CTL] = TAIKO_A_BIAS_PRECHRG_CTL__POR,
+ [TAIKO_A_BIAS_CURR_CTL_1] = TAIKO_A_BIAS_CURR_CTL_1__POR,
+ [TAIKO_A_BIAS_CURR_CTL_2] = TAIKO_A_BIAS_CURR_CTL_2__POR,
+ [TAIKO_A_BIAS_OSC_BG_CTL] = TAIKO_A_BIAS_OSC_BG_CTL__POR,
+ [TAIKO_A_CLK_BUFF_EN1] = TAIKO_A_CLK_BUFF_EN1__POR,
+ [TAIKO_A_CLK_BUFF_EN2] = TAIKO_A_CLK_BUFF_EN2__POR,
+ [TAIKO_A_LDO_H_MODE_1] = TAIKO_A_LDO_H_MODE_1__POR,
+ [TAIKO_A_LDO_H_MODE_2] = TAIKO_A_LDO_H_MODE_2__POR,
+ [TAIKO_A_LDO_H_LOOP_CTL] = TAIKO_A_LDO_H_LOOP_CTL__POR,
+ [TAIKO_A_LDO_H_COMP_1] = TAIKO_A_LDO_H_COMP_1__POR,
+ [TAIKO_A_LDO_H_COMP_2] = TAIKO_A_LDO_H_COMP_2__POR,
+ [TAIKO_A_LDO_H_BIAS_1] = TAIKO_A_LDO_H_BIAS_1__POR,
+ [TAIKO_A_LDO_H_BIAS_2] = TAIKO_A_LDO_H_BIAS_2__POR,
+ [TAIKO_A_LDO_H_BIAS_3] = TAIKO_A_LDO_H_BIAS_3__POR,
+ [TAIKO_A_VBAT_CLK] = TAIKO_A_VBAT_CLK__POR,
+ [TAIKO_A_VBAT_LOOP] = TAIKO_A_VBAT_LOOP__POR,
+ [TAIKO_A_VBAT_REF] = TAIKO_A_VBAT_REF__POR,
+ [TAIKO_A_VBAT_ADC_TEST] = TAIKO_A_VBAT_ADC_TEST__POR,
+ [TAIKO_A_VBAT_FE] = TAIKO_A_VBAT_FE__POR,
+ [TAIKO_A_VBAT_BIAS_1] = TAIKO_A_VBAT_BIAS_1__POR,
+ [TAIKO_A_VBAT_BIAS_2] = TAIKO_A_VBAT_BIAS_2__POR,
+ [TAIKO_A_VBAT_ADC_DATA_MSB] = TAIKO_A_VBAT_ADC_DATA_MSB__POR,
+ [TAIKO_A_VBAT_ADC_DATA_LSB] = TAIKO_A_VBAT_ADC_DATA_LSB__POR,
+ [TAIKO_A_MICB_CFILT_1_CTL] = TAIKO_A_MICB_CFILT_1_CTL__POR,
+ [TAIKO_A_MICB_CFILT_1_VAL] = TAIKO_A_MICB_CFILT_1_VAL__POR,
+ [TAIKO_A_MICB_CFILT_1_PRECHRG] = TAIKO_A_MICB_CFILT_1_PRECHRG__POR,
+ [TAIKO_A_MICB_1_CTL] = TAIKO_A_MICB_1_CTL__POR,
+ [TAIKO_A_MICB_1_INT_RBIAS] = TAIKO_A_MICB_1_INT_RBIAS__POR,
+ [TAIKO_A_MICB_1_MBHC] = TAIKO_A_MICB_1_MBHC__POR,
+ [TAIKO_A_MICB_CFILT_2_CTL] = TAIKO_A_MICB_CFILT_2_CTL__POR,
+ [TAIKO_A_MICB_CFILT_2_VAL] = TAIKO_A_MICB_CFILT_2_VAL__POR,
+ [TAIKO_A_MICB_CFILT_2_PRECHRG] = TAIKO_A_MICB_CFILT_2_PRECHRG__POR,
+ [TAIKO_A_MICB_2_CTL] = TAIKO_A_MICB_2_CTL__POR,
+ [TAIKO_A_MICB_2_INT_RBIAS] = TAIKO_A_MICB_2_INT_RBIAS__POR,
+ [TAIKO_A_MICB_2_MBHC] = TAIKO_A_MICB_2_MBHC__POR,
+ [TAIKO_A_MICB_CFILT_3_CTL] = TAIKO_A_MICB_CFILT_3_CTL__POR,
+ [TAIKO_A_MICB_CFILT_3_VAL] = TAIKO_A_MICB_CFILT_3_VAL__POR,
+ [TAIKO_A_MICB_CFILT_3_PRECHRG] = TAIKO_A_MICB_CFILT_3_PRECHRG__POR,
+ [TAIKO_A_MICB_3_CTL] = TAIKO_A_MICB_3_CTL__POR,
+ [TAIKO_A_MICB_3_INT_RBIAS] = TAIKO_A_MICB_3_INT_RBIAS__POR,
+ [TAIKO_A_MICB_3_MBHC] = TAIKO_A_MICB_3_MBHC__POR,
+ [TAIKO_A_MICB_4_CTL] = TAIKO_A_MICB_4_CTL__POR,
+ [TAIKO_A_MICB_4_INT_RBIAS] = TAIKO_A_MICB_4_INT_RBIAS__POR,
+ [TAIKO_A_MICB_4_MBHC] = TAIKO_A_MICB_4_MBHC__POR,
+ [TAIKO_A_MBHC_INSERT_DETECT] = TAIKO_A_MBHC_INSERT_DETECT__POR,
+ [TAIKO_A_MBHC_INSERT_DET_STATUS] = TAIKO_A_MBHC_INSERT_DET_STATUS__POR,
+ [TAIKO_A_TX_COM_BIAS] = TAIKO_A_TX_COM_BIAS__POR,
+ [TAIKO_A_MBHC_SCALING_MUX_1] = TAIKO_A_MBHC_SCALING_MUX_1__POR,
+ [TAIKO_A_MBHC_SCALING_MUX_2] = TAIKO_A_MBHC_SCALING_MUX_2__POR,
+ [TAIKO_A_MAD_ANA_CTRL] = TAIKO_A_MAD_ANA_CTRL__POR,
+ [TAIKO_A_TX_SUP_SWITCH_CTRL_1] = TAIKO_A_TX_SUP_SWITCH_CTRL_1__POR,
+ [TAIKO_A_TX_SUP_SWITCH_CTRL_2] = TAIKO_A_TX_SUP_SWITCH_CTRL_2__POR,
+ [TAIKO_A_TX_1_2_EN] = TAIKO_A_TX_1_2_EN__POR,
+ [TAIKO_A_TX_1_2_TEST_EN] = TAIKO_A_TX_1_2_TEST_EN__POR,
+ [TAIKO_A_TX_1_2_ADC_CH1] = TAIKO_A_TX_1_2_ADC_CH1__POR,
+ [TAIKO_A_TX_1_2_ADC_CH2] = TAIKO_A_TX_1_2_ADC_CH2__POR,
+ [TAIKO_A_TX_1_2_ATEST_REFCTRL] = TAIKO_A_TX_1_2_ATEST_REFCTRL__POR,
+ [TAIKO_A_TX_1_2_TEST_CTL] = TAIKO_A_TX_1_2_TEST_CTL__POR,
+ [TAIKO_A_TX_1_2_TEST_BLOCK_EN] = TAIKO_A_TX_1_2_TEST_BLOCK_EN__POR,
+ [TAIKO_A_TX_1_2_TXFE_CLKDIV] = TAIKO_A_TX_1_2_TXFE_CLKDIV__POR,
+ [TAIKO_A_TX_1_2_SAR_ERR_CH1] = TAIKO_A_TX_1_2_SAR_ERR_CH1__POR,
+ [TAIKO_A_TX_1_2_SAR_ERR_CH2] = TAIKO_A_TX_1_2_SAR_ERR_CH2__POR,
+ [TAIKO_A_TX_3_4_EN] = TAIKO_A_TX_3_4_EN__POR,
+ [TAIKO_A_TX_3_4_TEST_EN] = TAIKO_A_TX_3_4_TEST_EN__POR,
+ [TAIKO_A_TX_3_4_ADC_CH3] = TAIKO_A_TX_3_4_ADC_CH3__POR,
+ [TAIKO_A_TX_3_4_ADC_CH4] = TAIKO_A_TX_3_4_ADC_CH4__POR,
+ [TAIKO_A_TX_3_4_ATEST_REFCTRL] = TAIKO_A_TX_3_4_ATEST_REFCTRL__POR,
+ [TAIKO_A_TX_3_4_TEST_CTL] = TAIKO_A_TX_3_4_TEST_CTL__POR,
+ [TAIKO_A_TX_3_4_TEST_BLOCK_EN] = TAIKO_A_TX_3_4_TEST_BLOCK_EN__POR,
+ [TAIKO_A_TX_3_4_TXFE_CKDIV] = TAIKO_A_TX_3_4_TXFE_CKDIV__POR,
+ [TAIKO_A_TX_3_4_SAR_ERR_CH3] = TAIKO_A_TX_3_4_SAR_ERR_CH3__POR,
+ [TAIKO_A_TX_3_4_SAR_ERR_CH4] = TAIKO_A_TX_3_4_SAR_ERR_CH4__POR,
+ [TAIKO_A_TX_5_6_EN] = TAIKO_A_TX_5_6_EN__POR,
+ [TAIKO_A_TX_5_6_TEST_EN] = TAIKO_A_TX_5_6_TEST_EN__POR,
+ [TAIKO_A_TX_5_6_ADC_CH5] = TAIKO_A_TX_5_6_ADC_CH5__POR,
+ [TAIKO_A_TX_5_6_ADC_CH6] = TAIKO_A_TX_5_6_ADC_CH6__POR,
+ [TAIKO_A_TX_5_6_ATEST_REFCTRL] = TAIKO_A_TX_5_6_ATEST_REFCTRL__POR,
+ [TAIKO_A_TX_5_6_TEST_CTL] = TAIKO_A_TX_5_6_TEST_CTL__POR,
+ [TAIKO_A_TX_5_6_TEST_BLOCK_EN] = TAIKO_A_TX_5_6_TEST_BLOCK_EN__POR,
+ [TAIKO_A_TX_5_6_TXFE_CKDIV] = TAIKO_A_TX_5_6_TXFE_CKDIV__POR,
+ [TAIKO_A_TX_5_6_SAR_ERR_CH5] = TAIKO_A_TX_5_6_SAR_ERR_CH5__POR,
+ [TAIKO_A_TX_5_6_SAR_ERR_CH6] = TAIKO_A_TX_5_6_SAR_ERR_CH6__POR,
+ [TAIKO_A_TX_7_MBHC_EN] = TAIKO_A_TX_7_MBHC_EN__POR,
+ [TAIKO_A_TX_7_MBHC_ATEST_REFCTRL] =
+ TAIKO_A_TX_7_MBHC_ATEST_REFCTRL__POR,
+ [TAIKO_A_TX_7_MBHC_ADC] = TAIKO_A_TX_7_MBHC_ADC__POR,
+ [TAIKO_A_TX_7_MBHC_TEST_CTL] = TAIKO_A_TX_7_MBHC_TEST_CTL__POR,
+ [TAIKO_A_TX_7_MBHC_SAR_ERR] = TAIKO_A_TX_7_MBHC_SAR_ERR__POR,
+ [TAIKO_A_TX_7_TXFE_CLKDIV] = TAIKO_A_TX_7_TXFE_CLKDIV__POR,
+ [TAIKO_A_BUCK_MODE_1] = TAIKO_A_BUCK_MODE_1__POR,
+ [TAIKO_A_BUCK_MODE_2] = TAIKO_A_BUCK_MODE_2__POR,
+ [TAIKO_A_BUCK_MODE_3] = TAIKO_A_BUCK_MODE_3__POR,
+ [TAIKO_A_BUCK_MODE_4] = TAIKO_A_BUCK_MODE_4__POR,
+ [TAIKO_A_BUCK_MODE_5] = TAIKO_A_BUCK_MODE_5__POR,
+ [TAIKO_A_BUCK_CTRL_VCL_1] = TAIKO_A_BUCK_CTRL_VCL_1__POR,
+ [TAIKO_A_BUCK_CTRL_VCL_2] = TAIKO_A_BUCK_CTRL_VCL_2__POR,
+ [TAIKO_A_BUCK_CTRL_VCL_3] = TAIKO_A_BUCK_CTRL_VCL_3__POR,
+ [TAIKO_A_BUCK_CTRL_CCL_1] = TAIKO_A_BUCK_CTRL_CCL_1__POR,
+ [TAIKO_A_BUCK_CTRL_CCL_2] = TAIKO_A_BUCK_CTRL_CCL_2__POR,
+ [TAIKO_A_BUCK_CTRL_CCL_3] = TAIKO_A_BUCK_CTRL_CCL_3__POR,
+ [TAIKO_A_BUCK_CTRL_CCL_4] = TAIKO_A_BUCK_CTRL_CCL_4__POR,
+ [TAIKO_A_BUCK_CTRL_PWM_DRVR_1] = TAIKO_A_BUCK_CTRL_PWM_DRVR_1__POR,
+ [TAIKO_A_BUCK_CTRL_PWM_DRVR_2] = TAIKO_A_BUCK_CTRL_PWM_DRVR_2__POR,
+ [TAIKO_A_BUCK_CTRL_PWM_DRVR_3] = TAIKO_A_BUCK_CTRL_PWM_DRVR_3__POR,
+ [TAIKO_A_BUCK_TMUX_A_D] = TAIKO_A_BUCK_TMUX_A_D__POR,
+ [TAIKO_A_NCP_BUCKREF] = TAIKO_A_NCP_BUCKREF__POR,
+ [TAIKO_A_NCP_EN] = TAIKO_A_NCP_EN__POR,
+ [TAIKO_A_NCP_CLK] = TAIKO_A_NCP_CLK__POR,
+ [TAIKO_A_NCP_STATIC] = TAIKO_A_NCP_STATIC__POR,
+ [TAIKO_A_NCP_VTH_LOW] = TAIKO_A_NCP_VTH_LOW__POR,
+ [TAIKO_A_NCP_VTH_HIGH] = TAIKO_A_NCP_VTH_HIGH__POR,
+ [TAIKO_A_NCP_ATEST] = TAIKO_A_NCP_ATEST__POR,
+ [TAIKO_A_NCP_DTEST] = TAIKO_A_NCP_DTEST__POR,
+ [TAIKO_A_NCP_DLY1] = TAIKO_A_NCP_DLY1__POR,
+ [TAIKO_A_NCP_DLY2] = TAIKO_A_NCP_DLY2__POR,
+ [TAIKO_A_RX_AUX_SW_CTL] = TAIKO_A_RX_AUX_SW_CTL__POR,
+ [TAIKO_A_RX_PA_AUX_IN_CONN] = TAIKO_A_RX_PA_AUX_IN_CONN__POR,
+ [TAIKO_A_RX_COM_TIMER_DIV] = TAIKO_A_RX_COM_TIMER_DIV__POR,
+ [TAIKO_A_RX_COM_OCP_CTL] = TAIKO_A_RX_COM_OCP_CTL__POR,
+ [TAIKO_A_RX_COM_OCP_COUNT] = TAIKO_A_RX_COM_OCP_COUNT__POR,
+ [TAIKO_A_RX_COM_DAC_CTL] = TAIKO_A_RX_COM_DAC_CTL__POR,
+ [TAIKO_A_RX_COM_BIAS] = TAIKO_A_RX_COM_BIAS__POR,
+ [TAIKO_A_RX_HPH_AUTO_CHOP] = TAIKO_A_RX_HPH_AUTO_CHOP__POR,
+ [TAIKO_A_RX_HPH_CHOP_CTL] = TAIKO_A_RX_HPH_CHOP_CTL__POR,
+ [TAIKO_A_RX_HPH_BIAS_PA] = TAIKO_A_RX_HPH_BIAS_PA__POR,
+ [TAIKO_A_RX_HPH_BIAS_LDO] = TAIKO_A_RX_HPH_BIAS_LDO__POR,
+ [TAIKO_A_RX_HPH_BIAS_CNP] = TAIKO_A_RX_HPH_BIAS_CNP__POR,
+ [TAIKO_A_RX_HPH_BIAS_WG_OCP] = TAIKO_A_RX_HPH_BIAS_WG_OCP__POR,
+ [TAIKO_A_RX_HPH_OCP_CTL] = TAIKO_A_RX_HPH_OCP_CTL__POR,
+ [TAIKO_A_RX_HPH_CNP_EN] = TAIKO_A_RX_HPH_CNP_EN__POR,
+ [TAIKO_A_RX_HPH_CNP_WG_CTL] = TAIKO_A_RX_HPH_CNP_WG_CTL__POR,
+ [TAIKO_A_RX_HPH_CNP_WG_TIME] = TAIKO_A_RX_HPH_CNP_WG_TIME__POR,
+ [TAIKO_A_RX_HPH_L_GAIN] = TAIKO_A_RX_HPH_L_GAIN__POR,
+ [TAIKO_A_RX_HPH_L_TEST] = TAIKO_A_RX_HPH_L_TEST__POR,
+ [TAIKO_A_RX_HPH_L_PA_CTL] = TAIKO_A_RX_HPH_L_PA_CTL__POR,
+ [TAIKO_A_RX_HPH_L_DAC_CTL] = TAIKO_A_RX_HPH_L_DAC_CTL__POR,
+ [TAIKO_A_RX_HPH_L_ATEST] = TAIKO_A_RX_HPH_L_ATEST__POR,
+ [TAIKO_A_RX_HPH_L_STATUS] = TAIKO_A_RX_HPH_L_STATUS__POR,
+ [TAIKO_A_RX_HPH_R_GAIN] = TAIKO_A_RX_HPH_R_GAIN__POR,
+ [TAIKO_A_RX_HPH_R_TEST] = TAIKO_A_RX_HPH_R_TEST__POR,
+ [TAIKO_A_RX_HPH_R_PA_CTL] = TAIKO_A_RX_HPH_R_PA_CTL__POR,
+ [TAIKO_A_RX_HPH_R_DAC_CTL] = TAIKO_A_RX_HPH_R_DAC_CTL__POR,
+ [TAIKO_A_RX_HPH_R_ATEST] = TAIKO_A_RX_HPH_R_ATEST__POR,
+ [TAIKO_A_RX_HPH_R_STATUS] = TAIKO_A_RX_HPH_R_STATUS__POR,
+ [TAIKO_A_RX_EAR_BIAS_PA] = TAIKO_A_RX_EAR_BIAS_PA__POR,
+ [TAIKO_A_RX_EAR_BIAS_CMBUFF] = TAIKO_A_RX_EAR_BIAS_CMBUFF__POR,
+ [TAIKO_A_RX_EAR_EN] = TAIKO_A_RX_EAR_EN__POR,
+ [TAIKO_A_RX_EAR_GAIN] = TAIKO_A_RX_EAR_GAIN__POR,
+ [TAIKO_A_RX_EAR_CMBUFF] = TAIKO_A_RX_EAR_CMBUFF__POR,
+ [TAIKO_A_RX_EAR_ICTL] = TAIKO_A_RX_EAR_ICTL__POR,
+ [TAIKO_A_RX_EAR_CCOMP] = TAIKO_A_RX_EAR_CCOMP__POR,
+ [TAIKO_A_RX_EAR_VCM] = TAIKO_A_RX_EAR_VCM__POR,
+ [TAIKO_A_RX_EAR_CNP] = TAIKO_A_RX_EAR_CNP__POR,
+ [TAIKO_A_RX_EAR_DAC_CTL_ATEST] = TAIKO_A_RX_EAR_DAC_CTL_ATEST__POR,
+ [TAIKO_A_RX_EAR_STATUS] = TAIKO_A_RX_EAR_STATUS__POR,
+ [TAIKO_A_RX_LINE_BIAS_PA] = TAIKO_A_RX_LINE_BIAS_PA__POR,
+ [TAIKO_A_RX_BUCK_BIAS1] = TAIKO_A_RX_BUCK_BIAS1__POR,
+ [TAIKO_A_RX_BUCK_BIAS2] = TAIKO_A_RX_BUCK_BIAS2__POR,
+ [TAIKO_A_RX_LINE_COM] = TAIKO_A_RX_LINE_COM__POR,
+ [TAIKO_A_RX_LINE_CNP_EN] = TAIKO_A_RX_LINE_CNP_EN__POR,
+ [TAIKO_A_RX_LINE_CNP_WG_CTL] = TAIKO_A_RX_LINE_CNP_WG_CTL__POR,
+ [TAIKO_A_RX_LINE_CNP_WG_TIME] = TAIKO_A_RX_LINE_CNP_WG_TIME__POR,
+ [TAIKO_A_RX_LINE_1_GAIN] = TAIKO_A_RX_LINE_1_GAIN__POR,
+ [TAIKO_A_RX_LINE_1_TEST] = TAIKO_A_RX_LINE_1_TEST__POR,
+ [TAIKO_A_RX_LINE_1_DAC_CTL] = TAIKO_A_RX_LINE_1_DAC_CTL__POR,
+ [TAIKO_A_RX_LINE_1_STATUS] = TAIKO_A_RX_LINE_1_STATUS__POR,
+ [TAIKO_A_RX_LINE_2_GAIN] = TAIKO_A_RX_LINE_2_GAIN__POR,
+ [TAIKO_A_RX_LINE_2_TEST] = TAIKO_A_RX_LINE_2_TEST__POR,
+ [TAIKO_A_RX_LINE_2_DAC_CTL] = TAIKO_A_RX_LINE_2_DAC_CTL__POR,
+ [TAIKO_A_RX_LINE_2_STATUS] = TAIKO_A_RX_LINE_2_STATUS__POR,
+ [TAIKO_A_RX_LINE_3_GAIN] = TAIKO_A_RX_LINE_3_GAIN__POR,
+ [TAIKO_A_RX_LINE_3_TEST] = TAIKO_A_RX_LINE_3_TEST__POR,
+ [TAIKO_A_RX_LINE_3_DAC_CTL] = TAIKO_A_RX_LINE_3_DAC_CTL__POR,
+ [TAIKO_A_RX_LINE_3_STATUS] = TAIKO_A_RX_LINE_3_STATUS__POR,
+ [TAIKO_A_RX_LINE_4_GAIN] = TAIKO_A_RX_LINE_4_GAIN__POR,
+ [TAIKO_A_RX_LINE_4_TEST] = TAIKO_A_RX_LINE_4_TEST__POR,
+ [TAIKO_A_RX_LINE_4_DAC_CTL] = TAIKO_A_RX_LINE_4_DAC_CTL__POR,
+ [TAIKO_A_RX_LINE_4_STATUS] = TAIKO_A_RX_LINE_4_STATUS__POR,
+ [TAIKO_A_RX_LINE_CNP_DBG] = TAIKO_A_RX_LINE_CNP_DBG__POR,
+ [TAIKO_A_SPKR_DRV_EN] = TAIKO_A_SPKR_DRV_EN__POR,
+ [TAIKO_A_SPKR_DRV_GAIN] = TAIKO_A_SPKR_DRV_GAIN__POR,
+ [TAIKO_A_SPKR_DRV_DAC_CTL] = TAIKO_A_SPKR_DRV_DAC_CTL__POR,
+ [TAIKO_A_SPKR_DRV_OCP_CTL] = TAIKO_A_SPKR_DRV_OCP_CTL__POR,
+ [TAIKO_A_SPKR_DRV_CLIP_DET] = TAIKO_A_SPKR_DRV_CLIP_DET__POR,
+ [TAIKO_A_SPKR_DRV_IEC] = TAIKO_A_SPKR_DRV_IEC__POR,
+ [TAIKO_A_SPKR_DRV_DBG_DAC] = TAIKO_A_SPKR_DRV_DBG_DAC__POR,
+ [TAIKO_A_SPKR_DRV_DBG_PA] = TAIKO_A_SPKR_DRV_DBG_PA__POR,
+ [TAIKO_A_SPKR_DRV_DBG_PWRSTG] = TAIKO_A_SPKR_DRV_DBG_PWRSTG__POR,
+ [TAIKO_A_SPKR_DRV_BIAS_LDO] = TAIKO_A_SPKR_DRV_BIAS_LDO__POR,
+ [TAIKO_A_SPKR_DRV_BIAS_INT] = TAIKO_A_SPKR_DRV_BIAS_INT__POR,
+ [TAIKO_A_SPKR_DRV_BIAS_PA] = TAIKO_A_SPKR_DRV_BIAS_PA__POR,
+ [TAIKO_A_SPKR_DRV_STATUS_OCP] = TAIKO_A_SPKR_DRV_STATUS_OCP__POR,
+ [TAIKO_A_SPKR_DRV_STATUS_PA] = TAIKO_A_SPKR_DRV_STATUS_PA__POR,
+ [TAIKO_A_SPKR_PROT_EN] = TAIKO_A_SPKR_PROT_EN__POR,
+ [TAIKO_A_SPKR_PROT_ADC_EN] = TAIKO_A_SPKR_PROT_ADC_EN__POR,
+ [TAIKO_A_SPKR_PROT_ISENSE_BIAS] = TAIKO_A_SPKR_PROT_ISENSE_BIAS__POR,
+ [TAIKO_A_SPKR_PROT_VSENSE_BIAS] = TAIKO_A_SPKR_PROT_VSENSE_BIAS__POR,
+ [TAIKO_A_SPKR_PROT_ADC_ATEST_REFCTRL] =
+ TAIKO_A_SPKR_PROT_ADC_ATEST_REFCTRL__POR,
+ [TAIKO_A_SPKR_PROT_ADC_TEST_CTL] = TAIKO_A_SPKR_PROT_ADC_TEST_CTL__POR,
+ [TAIKO_A_SPKR_PROT_TEST_BLOCK_EN] =
+ TAIKO_A_SPKR_PROT_TEST_BLOCK_EN__POR,
+ [TAIKO_A_SPKR_PROT_ATEST] = TAIKO_A_SPKR_PROT_ATEST__POR,
+ [TAIKO_A_SPKR_PROT_V_SAR_ERR] = TAIKO_A_SPKR_PROT_V_SAR_ERR__POR,
+ [TAIKO_A_SPKR_PROT_I_SAR_ERR] = TAIKO_A_SPKR_PROT_I_SAR_ERR__POR,
+ [TAIKO_A_SPKR_PROT_LDO_CTRL] = TAIKO_A_SPKR_PROT_LDO_CTRL__POR,
+ [TAIKO_A_SPKR_PROT_ISENSE_CTRL] = TAIKO_A_SPKR_PROT_ISENSE_CTRL__POR,
+ [TAIKO_A_SPKR_PROT_VSENSE_CTRL] = TAIKO_A_SPKR_PROT_VSENSE_CTRL__POR,
+ [TAIKO_A_RC_OSC_FREQ] = TAIKO_A_RC_OSC_FREQ__POR,
+ [TAIKO_A_RC_OSC_TEST] = TAIKO_A_RC_OSC_TEST__POR,
+ [TAIKO_A_RC_OSC_STATUS] = TAIKO_A_RC_OSC_STATUS__POR,
+ [TAIKO_A_RC_OSC_TUNER] = TAIKO_A_RC_OSC_TUNER__POR,
+ [TAIKO_A_MBHC_HPH] = TAIKO_A_MBHC_HPH__POR,
+ [TAIKO_A_CDC_ANC1_B1_CTL] = TAIKO_A_CDC_ANC1_B1_CTL__POR,
+ [TAIKO_A_CDC_ANC2_B1_CTL] = TAIKO_A_CDC_ANC2_B1_CTL__POR,
+ [TAIKO_A_CDC_ANC1_SHIFT] = TAIKO_A_CDC_ANC1_SHIFT__POR,
+ [TAIKO_A_CDC_ANC2_SHIFT] = TAIKO_A_CDC_ANC2_SHIFT__POR,
+ [TAIKO_A_CDC_ANC1_IIR_B1_CTL] = TAIKO_A_CDC_ANC1_IIR_B1_CTL__POR,
+ [TAIKO_A_CDC_ANC2_IIR_B1_CTL] = TAIKO_A_CDC_ANC2_IIR_B1_CTL__POR,
+ [TAIKO_A_CDC_ANC1_IIR_B2_CTL] = TAIKO_A_CDC_ANC1_IIR_B2_CTL__POR,
+ [TAIKO_A_CDC_ANC2_IIR_B2_CTL] = TAIKO_A_CDC_ANC2_IIR_B2_CTL__POR,
+ [TAIKO_A_CDC_ANC1_IIR_B3_CTL] = TAIKO_A_CDC_ANC1_IIR_B3_CTL__POR,
+ [TAIKO_A_CDC_ANC2_IIR_B3_CTL] = TAIKO_A_CDC_ANC2_IIR_B3_CTL__POR,
+ [TAIKO_A_CDC_ANC1_LPF_B1_CTL] = TAIKO_A_CDC_ANC1_LPF_B1_CTL__POR,
+ [TAIKO_A_CDC_ANC2_LPF_B1_CTL] = TAIKO_A_CDC_ANC2_LPF_B1_CTL__POR,
+ [TAIKO_A_CDC_ANC1_LPF_B2_CTL] = TAIKO_A_CDC_ANC1_LPF_B2_CTL__POR,
+ [TAIKO_A_CDC_ANC2_LPF_B2_CTL] = TAIKO_A_CDC_ANC2_LPF_B2_CTL__POR,
+ [TAIKO_A_CDC_ANC1_SPARE] = TAIKO_A_CDC_ANC1_SPARE__POR,
+ [TAIKO_A_CDC_ANC2_SPARE] = TAIKO_A_CDC_ANC2_SPARE__POR,
+ [TAIKO_A_CDC_ANC1_SMLPF_CTL] = TAIKO_A_CDC_ANC1_SMLPF_CTL__POR,
+ [TAIKO_A_CDC_ANC2_SMLPF_CTL] = TAIKO_A_CDC_ANC2_SMLPF_CTL__POR,
+ [TAIKO_A_CDC_ANC1_DCFLT_CTL] = TAIKO_A_CDC_ANC1_DCFLT_CTL__POR,
+ [TAIKO_A_CDC_ANC2_DCFLT_CTL] = TAIKO_A_CDC_ANC2_DCFLT_CTL__POR,
+ [TAIKO_A_CDC_ANC1_GAIN_CTL] = TAIKO_A_CDC_ANC1_GAIN_CTL__POR,
+ [TAIKO_A_CDC_ANC2_GAIN_CTL] = TAIKO_A_CDC_ANC2_GAIN_CTL__POR,
+ [TAIKO_A_CDC_ANC1_B2_CTL] = TAIKO_A_CDC_ANC1_B2_CTL__POR,
+ [TAIKO_A_CDC_ANC2_B2_CTL] = TAIKO_A_CDC_ANC2_B2_CTL__POR,
+ [TAIKO_A_CDC_TX1_VOL_CTL_TIMER] = TAIKO_A_CDC_TX1_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX2_VOL_CTL_TIMER] = TAIKO_A_CDC_TX2_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX3_VOL_CTL_TIMER] = TAIKO_A_CDC_TX3_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX4_VOL_CTL_TIMER] = TAIKO_A_CDC_TX4_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX5_VOL_CTL_TIMER] = TAIKO_A_CDC_TX5_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX6_VOL_CTL_TIMER] = TAIKO_A_CDC_TX6_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX7_VOL_CTL_TIMER] = TAIKO_A_CDC_TX7_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX8_VOL_CTL_TIMER] = TAIKO_A_CDC_TX8_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX9_VOL_CTL_TIMER] = TAIKO_A_CDC_TX9_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX10_VOL_CTL_TIMER] = TAIKO_A_CDC_TX10_VOL_CTL_TIMER__POR,
+ [TAIKO_A_CDC_TX1_VOL_CTL_GAIN] = TAIKO_A_CDC_TX1_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX2_VOL_CTL_GAIN] = TAIKO_A_CDC_TX2_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX3_VOL_CTL_GAIN] = TAIKO_A_CDC_TX3_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX4_VOL_CTL_GAIN] = TAIKO_A_CDC_TX4_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX5_VOL_CTL_GAIN] = TAIKO_A_CDC_TX5_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX6_VOL_CTL_GAIN] = TAIKO_A_CDC_TX6_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX7_VOL_CTL_GAIN] = TAIKO_A_CDC_TX7_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX8_VOL_CTL_GAIN] = TAIKO_A_CDC_TX8_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX9_VOL_CTL_GAIN] = TAIKO_A_CDC_TX9_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX10_VOL_CTL_GAIN] = TAIKO_A_CDC_TX10_VOL_CTL_GAIN__POR,
+ [TAIKO_A_CDC_TX1_VOL_CTL_CFG] = TAIKO_A_CDC_TX1_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX2_VOL_CTL_CFG] = TAIKO_A_CDC_TX2_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX3_VOL_CTL_CFG] = TAIKO_A_CDC_TX3_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX4_VOL_CTL_CFG] = TAIKO_A_CDC_TX4_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX5_VOL_CTL_CFG] = TAIKO_A_CDC_TX5_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX6_VOL_CTL_CFG] = TAIKO_A_CDC_TX6_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX7_VOL_CTL_CFG] = TAIKO_A_CDC_TX7_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX8_VOL_CTL_CFG] = TAIKO_A_CDC_TX8_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX9_VOL_CTL_CFG] = TAIKO_A_CDC_TX9_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX10_VOL_CTL_CFG] = TAIKO_A_CDC_TX10_VOL_CTL_CFG__POR,
+ [TAIKO_A_CDC_TX1_MUX_CTL] = TAIKO_A_CDC_TX1_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX2_MUX_CTL] = TAIKO_A_CDC_TX2_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX3_MUX_CTL] = TAIKO_A_CDC_TX3_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX4_MUX_CTL] = TAIKO_A_CDC_TX4_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX5_MUX_CTL] = TAIKO_A_CDC_TX5_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX6_MUX_CTL] = TAIKO_A_CDC_TX6_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX7_MUX_CTL] = TAIKO_A_CDC_TX7_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX8_MUX_CTL] = TAIKO_A_CDC_TX8_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX9_MUX_CTL] = TAIKO_A_CDC_TX9_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX10_MUX_CTL] = TAIKO_A_CDC_TX10_MUX_CTL__POR,
+ [TAIKO_A_CDC_TX1_CLK_FS_CTL] = TAIKO_A_CDC_TX1_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX2_CLK_FS_CTL] = TAIKO_A_CDC_TX2_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX3_CLK_FS_CTL] = TAIKO_A_CDC_TX3_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX4_CLK_FS_CTL] = TAIKO_A_CDC_TX4_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX5_CLK_FS_CTL] = TAIKO_A_CDC_TX5_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX6_CLK_FS_CTL] = TAIKO_A_CDC_TX6_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX7_CLK_FS_CTL] = TAIKO_A_CDC_TX7_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX8_CLK_FS_CTL] = TAIKO_A_CDC_TX8_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX9_CLK_FS_CTL] = TAIKO_A_CDC_TX9_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX10_CLK_FS_CTL] = TAIKO_A_CDC_TX10_CLK_FS_CTL__POR,
+ [TAIKO_A_CDC_TX1_DMIC_CTL] = TAIKO_A_CDC_TX1_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX2_DMIC_CTL] = TAIKO_A_CDC_TX2_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX3_DMIC_CTL] = TAIKO_A_CDC_TX3_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX4_DMIC_CTL] = TAIKO_A_CDC_TX4_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX5_DMIC_CTL] = TAIKO_A_CDC_TX5_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX6_DMIC_CTL] = TAIKO_A_CDC_TX6_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX7_DMIC_CTL] = TAIKO_A_CDC_TX7_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX8_DMIC_CTL] = TAIKO_A_CDC_TX8_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX9_DMIC_CTL] = TAIKO_A_CDC_TX9_DMIC_CTL__POR,
+ [TAIKO_A_CDC_TX10_DMIC_CTL] = TAIKO_A_CDC_TX10_DMIC_CTL__POR,
+ [TAIKO_A_CDC_DEBUG_B1_CTL] = TAIKO_A_CDC_DEBUG_B1_CTL__POR,
+ [TAIKO_A_CDC_DEBUG_B2_CTL] = TAIKO_A_CDC_DEBUG_B2_CTL__POR,
+ [TAIKO_A_CDC_DEBUG_B3_CTL] = TAIKO_A_CDC_DEBUG_B3_CTL__POR,
+ [TAIKO_A_CDC_DEBUG_B4_CTL] = TAIKO_A_CDC_DEBUG_B4_CTL__POR,
+ [TAIKO_A_CDC_DEBUG_B5_CTL] = TAIKO_A_CDC_DEBUG_B5_CTL__POR,
+ [TAIKO_A_CDC_DEBUG_B6_CTL] = TAIKO_A_CDC_DEBUG_B6_CTL__POR,
+ [TAIKO_A_CDC_DEBUG_B7_CTL] = TAIKO_A_CDC_DEBUG_B7_CTL__POR,
+ [TAIKO_A_CDC_SRC1_PDA_CFG] = TAIKO_A_CDC_SRC1_PDA_CFG__POR,
+ [TAIKO_A_CDC_SRC2_PDA_CFG] = TAIKO_A_CDC_SRC2_PDA_CFG__POR,
+ [TAIKO_A_CDC_SRC1_FS_CTL] = TAIKO_A_CDC_SRC1_FS_CTL__POR,
+ [TAIKO_A_CDC_SRC2_FS_CTL] = TAIKO_A_CDC_SRC2_FS_CTL__POR,
+ [TAIKO_A_CDC_RX1_B1_CTL] = TAIKO_A_CDC_RX1_B1_CTL__POR,
+ [TAIKO_A_CDC_RX2_B1_CTL] = TAIKO_A_CDC_RX2_B1_CTL__POR,
+ [TAIKO_A_CDC_RX3_B1_CTL] = TAIKO_A_CDC_RX3_B1_CTL__POR,
+ [TAIKO_A_CDC_RX4_B1_CTL] = TAIKO_A_CDC_RX4_B1_CTL__POR,
+ [TAIKO_A_CDC_RX5_B1_CTL] = TAIKO_A_CDC_RX5_B1_CTL__POR,
+ [TAIKO_A_CDC_RX6_B1_CTL] = TAIKO_A_CDC_RX6_B1_CTL__POR,
+ [TAIKO_A_CDC_RX7_B1_CTL] = TAIKO_A_CDC_RX7_B1_CTL__POR,
+ [TAIKO_A_CDC_RX1_B2_CTL] = TAIKO_A_CDC_RX1_B2_CTL__POR,
+ [TAIKO_A_CDC_RX2_B2_CTL] = TAIKO_A_CDC_RX2_B2_CTL__POR,
+ [TAIKO_A_CDC_RX3_B2_CTL] = TAIKO_A_CDC_RX3_B2_CTL__POR,
+ [TAIKO_A_CDC_RX4_B2_CTL] = TAIKO_A_CDC_RX4_B2_CTL__POR,
+ [TAIKO_A_CDC_RX5_B2_CTL] = TAIKO_A_CDC_RX5_B2_CTL__POR,
+ [TAIKO_A_CDC_RX6_B2_CTL] = TAIKO_A_CDC_RX6_B2_CTL__POR,
+ [TAIKO_A_CDC_RX7_B2_CTL] = TAIKO_A_CDC_RX7_B2_CTL__POR,
+ [TAIKO_A_CDC_RX1_B3_CTL] = TAIKO_A_CDC_RX1_B3_CTL__POR,
+ [TAIKO_A_CDC_RX2_B3_CTL] = TAIKO_A_CDC_RX2_B3_CTL__POR,
+ [TAIKO_A_CDC_RX3_B3_CTL] = TAIKO_A_CDC_RX3_B3_CTL__POR,
+ [TAIKO_A_CDC_RX4_B3_CTL] = TAIKO_A_CDC_RX4_B3_CTL__POR,
+ [TAIKO_A_CDC_RX5_B3_CTL] = TAIKO_A_CDC_RX5_B3_CTL__POR,
+ [TAIKO_A_CDC_RX6_B3_CTL] = TAIKO_A_CDC_RX6_B3_CTL__POR,
+ [TAIKO_A_CDC_RX7_B3_CTL] = TAIKO_A_CDC_RX7_B3_CTL__POR,
+ [TAIKO_A_CDC_RX1_B4_CTL] = TAIKO_A_CDC_RX1_B4_CTL__POR,
+ [TAIKO_A_CDC_RX2_B4_CTL] = TAIKO_A_CDC_RX2_B4_CTL__POR,
+ [TAIKO_A_CDC_RX3_B4_CTL] = TAIKO_A_CDC_RX3_B4_CTL__POR,
+ [TAIKO_A_CDC_RX4_B4_CTL] = TAIKO_A_CDC_RX4_B4_CTL__POR,
+ [TAIKO_A_CDC_RX5_B4_CTL] = TAIKO_A_CDC_RX5_B4_CTL__POR,
+ [TAIKO_A_CDC_RX6_B4_CTL] = TAIKO_A_CDC_RX6_B4_CTL__POR,
+ [TAIKO_A_CDC_RX7_B4_CTL] = TAIKO_A_CDC_RX7_B4_CTL__POR,
+ [TAIKO_A_CDC_RX1_B5_CTL] = TAIKO_A_CDC_RX1_B5_CTL__POR,
+ [TAIKO_A_CDC_RX2_B5_CTL] = TAIKO_A_CDC_RX2_B5_CTL__POR,
+ [TAIKO_A_CDC_RX3_B5_CTL] = TAIKO_A_CDC_RX3_B5_CTL__POR,
+ [TAIKO_A_CDC_RX4_B5_CTL] = TAIKO_A_CDC_RX4_B5_CTL__POR,
+ [TAIKO_A_CDC_RX5_B5_CTL] = TAIKO_A_CDC_RX5_B5_CTL__POR,
+ [TAIKO_A_CDC_RX6_B5_CTL] = TAIKO_A_CDC_RX6_B5_CTL__POR,
+ [TAIKO_A_CDC_RX7_B5_CTL] = TAIKO_A_CDC_RX7_B5_CTL__POR,
+ [TAIKO_A_CDC_RX1_B6_CTL] = TAIKO_A_CDC_RX1_B6_CTL__POR,
+ [TAIKO_A_CDC_RX2_B6_CTL] = TAIKO_A_CDC_RX2_B6_CTL__POR,
+ [TAIKO_A_CDC_RX3_B6_CTL] = TAIKO_A_CDC_RX3_B6_CTL__POR,
+ [TAIKO_A_CDC_RX4_B6_CTL] = TAIKO_A_CDC_RX4_B6_CTL__POR,
+ [TAIKO_A_CDC_RX5_B6_CTL] = TAIKO_A_CDC_RX5_B6_CTL__POR,
+ [TAIKO_A_CDC_RX6_B6_CTL] = TAIKO_A_CDC_RX6_B6_CTL__POR,
+ [TAIKO_A_CDC_RX7_B6_CTL] = TAIKO_A_CDC_RX7_B6_CTL__POR,
+ [TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL] = TAIKO_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
+ [TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL] = TAIKO_A_CDC_RX2_VOL_CTL_B1_CTL__POR,
+ [TAIKO_A_CDC_RX3_VOL_CTL_B1_CTL] = TAIKO_A_CDC_RX3_VOL_CTL_B1_CTL__POR,
+ [TAIKO_A_CDC_RX4_VOL_CTL_B1_CTL] = TAIKO_A_CDC_RX4_VOL_CTL_B1_CTL__POR,
+ [TAIKO_A_CDC_RX5_VOL_CTL_B1_CTL] = TAIKO_A_CDC_RX5_VOL_CTL_B1_CTL__POR,
+ [TAIKO_A_CDC_RX6_VOL_CTL_B1_CTL] = TAIKO_A_CDC_RX6_VOL_CTL_B1_CTL__POR,
+ [TAIKO_A_CDC_RX7_VOL_CTL_B1_CTL] = TAIKO_A_CDC_RX7_VOL_CTL_B1_CTL__POR,
+ [TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL] = TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
+ [TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL] = TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL__POR,
+ [TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL] = TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL__POR,
+ [TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL] = TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL__POR,
+ [TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL] = TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL__POR,
+ [TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL] = TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL__POR,
+ [TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL] = TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL__POR,
+ [TAIKO_A_CDC_VBAT_CFG] = TAIKO_A_CDC_VBAT_CFG__POR,
+ [TAIKO_A_CDC_VBAT_ADC_CAL1] = TAIKO_A_CDC_VBAT_ADC_CAL1__POR,
+ [TAIKO_A_CDC_VBAT_ADC_CAL2] = TAIKO_A_CDC_VBAT_ADC_CAL2__POR,
+ [TAIKO_A_CDC_VBAT_ADC_CAL3] = TAIKO_A_CDC_VBAT_ADC_CAL3__POR,
+ [TAIKO_A_CDC_VBAT_PK_EST1] = TAIKO_A_CDC_VBAT_PK_EST1__POR,
+ [TAIKO_A_CDC_VBAT_PK_EST2] = TAIKO_A_CDC_VBAT_PK_EST2__POR,
+ [TAIKO_A_CDC_VBAT_PK_EST3] = TAIKO_A_CDC_VBAT_PK_EST3__POR,
+ [TAIKO_A_CDC_VBAT_RF_PROC1] = TAIKO_A_CDC_VBAT_RF_PROC1__POR,
+ [TAIKO_A_CDC_VBAT_RF_PROC2] = TAIKO_A_CDC_VBAT_RF_PROC2__POR,
+ [TAIKO_A_CDC_VBAT_TAC1] = TAIKO_A_CDC_VBAT_TAC1__POR,
+ [TAIKO_A_CDC_VBAT_TAC2] = TAIKO_A_CDC_VBAT_TAC2__POR,
+ [TAIKO_A_CDC_VBAT_TAC3] = TAIKO_A_CDC_VBAT_TAC3__POR,
+ [TAIKO_A_CDC_VBAT_TAC4] = TAIKO_A_CDC_VBAT_TAC4__POR,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD1] = TAIKO_A_CDC_VBAT_GAIN_UPD1__POR,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD2] = TAIKO_A_CDC_VBAT_GAIN_UPD2__POR,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD3] = TAIKO_A_CDC_VBAT_GAIN_UPD3__POR,
+ [TAIKO_A_CDC_VBAT_GAIN_UPD4] = TAIKO_A_CDC_VBAT_GAIN_UPD4__POR,
+ [TAIKO_A_CDC_VBAT_DEBUG1] = TAIKO_A_CDC_VBAT_DEBUG1__POR,
+ [TAIKO_A_CDC_CLK_ANC_RESET_CTL] = TAIKO_A_CDC_CLK_ANC_RESET_CTL__POR,
+ [TAIKO_A_CDC_CLK_RX_RESET_CTL] = TAIKO_A_CDC_CLK_RX_RESET_CTL__POR,
+ [TAIKO_A_CDC_CLK_TX_RESET_B1_CTL] =
+ TAIKO_A_CDC_CLK_TX_RESET_B1_CTL__POR,
+ [TAIKO_A_CDC_CLK_TX_RESET_B2_CTL] =
+ TAIKO_A_CDC_CLK_TX_RESET_B2_CTL__POR,
+ [TAIKO_A_CDC_CLK_DMIC_B1_CTL] = TAIKO_A_CDC_CLK_DMIC_B1_CTL__POR,
+ [TAIKO_A_CDC_CLK_DMIC_B2_CTL] = TAIKO_A_CDC_CLK_DMIC_B2_CTL__POR,
+ [TAIKO_A_CDC_CLK_RX_I2S_CTL] = TAIKO_A_CDC_CLK_RX_I2S_CTL__POR,
+ [TAIKO_A_CDC_CLK_TX_I2S_CTL] = TAIKO_A_CDC_CLK_TX_I2S_CTL__POR,
+ [TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL] =
+ TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL__POR,
+ [TAIKO_A_CDC_CLK_OTHR_RESET_B2_CTL] =
+ TAIKO_A_CDC_CLK_OTHR_RESET_B2_CTL__POR,
+ [TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL] =
+ TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL__POR,
+ [TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL] =
+ TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL__POR,
+ [TAIKO_A_CDC_CLK_OTHR_CTL] = TAIKO_A_CDC_CLK_OTHR_CTL__POR,
+ [TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL] =
+ TAIKO_A_CDC_CLK_RDAC_CLK_EN_CTL__POR,
+ [TAIKO_A_CDC_CLK_ANC_CLK_EN_CTL] = TAIKO_A_CDC_CLK_ANC_CLK_EN_CTL__POR,
+ [TAIKO_A_CDC_CLK_RX_B1_CTL] = TAIKO_A_CDC_CLK_RX_B1_CTL__POR,
+ [TAIKO_A_CDC_CLK_RX_B2_CTL] = TAIKO_A_CDC_CLK_RX_B2_CTL__POR,
+ [TAIKO_A_CDC_CLK_MCLK_CTL] = TAIKO_A_CDC_CLK_MCLK_CTL__POR,
+ [TAIKO_A_CDC_CLK_PDM_CTL] = TAIKO_A_CDC_CLK_PDM_CTL__POR,
+ [TAIKO_A_CDC_CLK_SD_CTL] = TAIKO_A_CDC_CLK_SD_CTL__POR,
+ [TAIKO_A_CDC_CLK_POWER_CTL] = TAIKO_A_CDC_CLK_POWER_CTL__POR,
+ [TAIKO_A_CDC_CLSH_B1_CTL] = TAIKO_A_CDC_CLSH_B1_CTL__POR,
+ [TAIKO_A_CDC_CLSH_B2_CTL] = TAIKO_A_CDC_CLSH_B2_CTL__POR,
+ [TAIKO_A_CDC_CLSH_B3_CTL] = TAIKO_A_CDC_CLSH_B3_CTL__POR,
+ [TAIKO_A_CDC_CLSH_BUCK_NCP_VARS] = TAIKO_A_CDC_CLSH_BUCK_NCP_VARS__POR,
+ [TAIKO_A_CDC_CLSH_IDLE_HPH_THSD] = TAIKO_A_CDC_CLSH_IDLE_HPH_THSD__POR,
+ [TAIKO_A_CDC_CLSH_IDLE_EAR_THSD] = TAIKO_A_CDC_CLSH_IDLE_EAR_THSD__POR,
+ [TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD] =
+ TAIKO_A_CDC_CLSH_FCLKONLY_HPH_THSD__POR,
+ [TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD] =
+ TAIKO_A_CDC_CLSH_FCLKONLY_EAR_THSD__POR,
+ [TAIKO_A_CDC_CLSH_K_ADDR] = TAIKO_A_CDC_CLSH_K_ADDR__POR,
+ [TAIKO_A_CDC_CLSH_K_DATA] = TAIKO_A_CDC_CLSH_K_DATA__POR,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L] =
+ TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_L__POR,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U] =
+ TAIKO_A_CDC_CLSH_I_PA_FACT_HPH_U__POR,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L] =
+ TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_L__POR,
+ [TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U] =
+ TAIKO_A_CDC_CLSH_I_PA_FACT_EAR_U__POR,
+ [TAIKO_A_CDC_CLSH_V_PA_HD_EAR] = TAIKO_A_CDC_CLSH_V_PA_HD_EAR__POR,
+ [TAIKO_A_CDC_CLSH_V_PA_HD_HPH] = TAIKO_A_CDC_CLSH_V_PA_HD_HPH__POR,
+ [TAIKO_A_CDC_CLSH_V_PA_MIN_EAR] = TAIKO_A_CDC_CLSH_V_PA_MIN_EAR__POR,
+ [TAIKO_A_CDC_CLSH_V_PA_MIN_HPH] = TAIKO_A_CDC_CLSH_V_PA_MIN_HPH__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B1_CTL] = TAIKO_A_CDC_IIR1_GAIN_B1_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B1_CTL] = TAIKO_A_CDC_IIR2_GAIN_B1_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B2_CTL] = TAIKO_A_CDC_IIR1_GAIN_B2_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B2_CTL] = TAIKO_A_CDC_IIR2_GAIN_B2_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B3_CTL] = TAIKO_A_CDC_IIR1_GAIN_B3_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B3_CTL] = TAIKO_A_CDC_IIR2_GAIN_B3_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B4_CTL] = TAIKO_A_CDC_IIR1_GAIN_B4_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B4_CTL] = TAIKO_A_CDC_IIR2_GAIN_B4_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B5_CTL] = TAIKO_A_CDC_IIR1_GAIN_B5_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B5_CTL] = TAIKO_A_CDC_IIR2_GAIN_B5_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B6_CTL] = TAIKO_A_CDC_IIR1_GAIN_B6_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B6_CTL] = TAIKO_A_CDC_IIR2_GAIN_B6_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B7_CTL] = TAIKO_A_CDC_IIR1_GAIN_B7_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B7_CTL] = TAIKO_A_CDC_IIR2_GAIN_B7_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_B8_CTL] = TAIKO_A_CDC_IIR1_GAIN_B8_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_B8_CTL] = TAIKO_A_CDC_IIR2_GAIN_B8_CTL__POR,
+ [TAIKO_A_CDC_IIR1_CTL] = TAIKO_A_CDC_IIR1_CTL__POR,
+ [TAIKO_A_CDC_IIR2_CTL] = TAIKO_A_CDC_IIR2_CTL__POR,
+ [TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL] =
+ TAIKO_A_CDC_IIR1_GAIN_TIMER_CTL__POR,
+ [TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL] =
+ TAIKO_A_CDC_IIR2_GAIN_TIMER_CTL__POR,
+ [TAIKO_A_CDC_IIR1_COEF_B1_CTL] = TAIKO_A_CDC_IIR1_COEF_B1_CTL__POR,
+ [TAIKO_A_CDC_IIR2_COEF_B1_CTL] = TAIKO_A_CDC_IIR2_COEF_B1_CTL__POR,
+ [TAIKO_A_CDC_IIR1_COEF_B2_CTL] = TAIKO_A_CDC_IIR1_COEF_B2_CTL__POR,
+ [TAIKO_A_CDC_IIR2_COEF_B2_CTL] = TAIKO_A_CDC_IIR2_COEF_B2_CTL__POR,
+ [TAIKO_A_CDC_TOP_GAIN_UPDATE] = TAIKO_A_CDC_TOP_GAIN_UPDATE__POR,
+ [TAIKO_A_CDC_COMP0_B1_CTL] = TAIKO_A_CDC_COMP0_B1_CTL__POR,
+ [TAIKO_A_CDC_COMP1_B1_CTL] = TAIKO_A_CDC_COMP1_B1_CTL__POR,
+ [TAIKO_A_CDC_COMP2_B1_CTL] = TAIKO_A_CDC_COMP2_B1_CTL__POR,
+ [TAIKO_A_CDC_COMP0_B2_CTL] = TAIKO_A_CDC_COMP0_B2_CTL__POR,
+ [TAIKO_A_CDC_COMP1_B2_CTL] = TAIKO_A_CDC_COMP1_B2_CTL__POR,
+ [TAIKO_A_CDC_COMP2_B2_CTL] = TAIKO_A_CDC_COMP2_B2_CTL__POR,
+ [TAIKO_A_CDC_COMP0_B3_CTL] = TAIKO_A_CDC_COMP0_B3_CTL__POR,
+ [TAIKO_A_CDC_COMP1_B3_CTL] = TAIKO_A_CDC_COMP1_B3_CTL__POR,
+ [TAIKO_A_CDC_COMP2_B3_CTL] = TAIKO_A_CDC_COMP2_B3_CTL__POR,
+ [TAIKO_A_CDC_COMP0_B4_CTL] = TAIKO_A_CDC_COMP0_B4_CTL__POR,
+ [TAIKO_A_CDC_COMP1_B4_CTL] = TAIKO_A_CDC_COMP1_B4_CTL__POR,
+ [TAIKO_A_CDC_COMP2_B4_CTL] = TAIKO_A_CDC_COMP2_B4_CTL__POR,
+ [TAIKO_A_CDC_COMP0_B5_CTL] = TAIKO_A_CDC_COMP0_B5_CTL__POR,
+ [TAIKO_A_CDC_COMP1_B5_CTL] = TAIKO_A_CDC_COMP1_B5_CTL__POR,
+ [TAIKO_A_CDC_COMP2_B5_CTL] = TAIKO_A_CDC_COMP2_B5_CTL__POR,
+ [TAIKO_A_CDC_COMP0_B6_CTL] = TAIKO_A_CDC_COMP0_B6_CTL__POR,
+ [TAIKO_A_CDC_COMP1_B6_CTL] = TAIKO_A_CDC_COMP1_B6_CTL__POR,
+ [TAIKO_A_CDC_COMP2_B6_CTL] = TAIKO_A_CDC_COMP2_B6_CTL__POR,
+ [TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS] =
+ TAIKO_A_CDC_COMP0_SHUT_DOWN_STATUS__POR,
+ [TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+ TAIKO_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+ [TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS] =
+ TAIKO_A_CDC_COMP2_SHUT_DOWN_STATUS__POR,
+ [TAIKO_A_CDC_COMP0_FS_CFG] = TAIKO_A_CDC_COMP0_FS_CFG__POR,
+ [TAIKO_A_CDC_COMP1_FS_CFG] = TAIKO_A_CDC_COMP1_FS_CFG__POR,
+ [TAIKO_A_CDC_COMP2_FS_CFG] = TAIKO_A_CDC_COMP2_FS_CFG__POR,
+ [TAIKO_A_CDC_CONN_RX1_B1_CTL] = TAIKO_A_CDC_CONN_RX1_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX1_B2_CTL] = TAIKO_A_CDC_CONN_RX1_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX1_B3_CTL] = TAIKO_A_CDC_CONN_RX1_B3_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX2_B1_CTL] = TAIKO_A_CDC_CONN_RX2_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX2_B2_CTL] = TAIKO_A_CDC_CONN_RX2_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX2_B3_CTL] = TAIKO_A_CDC_CONN_RX2_B3_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX3_B1_CTL] = TAIKO_A_CDC_CONN_RX3_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX3_B2_CTL] = TAIKO_A_CDC_CONN_RX3_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX4_B1_CTL] = TAIKO_A_CDC_CONN_RX4_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX4_B2_CTL] = TAIKO_A_CDC_CONN_RX4_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX5_B1_CTL] = TAIKO_A_CDC_CONN_RX5_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX5_B2_CTL] = TAIKO_A_CDC_CONN_RX5_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX6_B1_CTL] = TAIKO_A_CDC_CONN_RX6_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX6_B2_CTL] = TAIKO_A_CDC_CONN_RX6_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX7_B1_CTL] = TAIKO_A_CDC_CONN_RX7_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX7_B2_CTL] = TAIKO_A_CDC_CONN_RX7_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX7_B3_CTL] = TAIKO_A_CDC_CONN_RX7_B3_CTL__POR,
+ [TAIKO_A_CDC_CONN_ANC_B1_CTL] = TAIKO_A_CDC_CONN_ANC_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_ANC_B2_CTL] = TAIKO_A_CDC_CONN_ANC_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_B1_CTL] = TAIKO_A_CDC_CONN_TX_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_B2_CTL] = TAIKO_A_CDC_CONN_TX_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_B3_CTL] = TAIKO_A_CDC_CONN_TX_B3_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_B4_CTL] = TAIKO_A_CDC_CONN_TX_B4_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ1_B1_CTL] = TAIKO_A_CDC_CONN_EQ1_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ1_B2_CTL] = TAIKO_A_CDC_CONN_EQ1_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ1_B3_CTL] = TAIKO_A_CDC_CONN_EQ1_B3_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ1_B4_CTL] = TAIKO_A_CDC_CONN_EQ1_B4_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ2_B1_CTL] = TAIKO_A_CDC_CONN_EQ2_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ2_B2_CTL] = TAIKO_A_CDC_CONN_EQ2_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ2_B3_CTL] = TAIKO_A_CDC_CONN_EQ2_B3_CTL__POR,
+ [TAIKO_A_CDC_CONN_EQ2_B4_CTL] = TAIKO_A_CDC_CONN_EQ2_B4_CTL__POR,
+ [TAIKO_A_CDC_CONN_SRC1_B1_CTL] = TAIKO_A_CDC_CONN_SRC1_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_SRC1_B2_CTL] = TAIKO_A_CDC_CONN_SRC1_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_SRC2_B1_CTL] = TAIKO_A_CDC_CONN_SRC2_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_SRC2_B2_CTL] = TAIKO_A_CDC_CONN_SRC2_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B1_CTL] = TAIKO_A_CDC_CONN_TX_SB_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B2_CTL] = TAIKO_A_CDC_CONN_TX_SB_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B3_CTL] = TAIKO_A_CDC_CONN_TX_SB_B3_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B4_CTL] = TAIKO_A_CDC_CONN_TX_SB_B4_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B5_CTL] = TAIKO_A_CDC_CONN_TX_SB_B5_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B6_CTL] = TAIKO_A_CDC_CONN_TX_SB_B6_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B7_CTL] = TAIKO_A_CDC_CONN_TX_SB_B7_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B8_CTL] = TAIKO_A_CDC_CONN_TX_SB_B8_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B9_CTL] = TAIKO_A_CDC_CONN_TX_SB_B9_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B10_CTL] = TAIKO_A_CDC_CONN_TX_SB_B10_CTL__POR,
+ [TAIKO_A_CDC_CONN_TX_SB_B11_CTL] = TAIKO_A_CDC_CONN_TX_SB_B11_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX_SB_B1_CTL] = TAIKO_A_CDC_CONN_RX_SB_B1_CTL__POR,
+ [TAIKO_A_CDC_CONN_RX_SB_B2_CTL] = TAIKO_A_CDC_CONN_RX_SB_B2_CTL__POR,
+ [TAIKO_A_CDC_CONN_CLSH_CTL] = TAIKO_A_CDC_CONN_CLSH_CTL__POR,
+ [TAIKO_A_CDC_CONN_MISC] = TAIKO_A_CDC_CONN_MISC__POR,
+ [TAIKO_A_CDC_CONN_MAD] = TAIKO_A_CDC_CONN_MAD__POR,
+ [TAIKO_A_CDC_MBHC_EN_CTL] = TAIKO_A_CDC_MBHC_EN_CTL__POR,
+ [TAIKO_A_CDC_MBHC_FIR_B1_CFG] = TAIKO_A_CDC_MBHC_FIR_B1_CFG__POR,
+ [TAIKO_A_CDC_MBHC_FIR_B2_CFG] = TAIKO_A_CDC_MBHC_FIR_B2_CFG__POR,
+ [TAIKO_A_CDC_MBHC_TIMER_B1_CTL] = TAIKO_A_CDC_MBHC_TIMER_B1_CTL__POR,
+ [TAIKO_A_CDC_MBHC_TIMER_B2_CTL] = TAIKO_A_CDC_MBHC_TIMER_B2_CTL__POR,
+ [TAIKO_A_CDC_MBHC_TIMER_B3_CTL] = TAIKO_A_CDC_MBHC_TIMER_B3_CTL__POR,
+ [TAIKO_A_CDC_MBHC_TIMER_B4_CTL] = TAIKO_A_CDC_MBHC_TIMER_B4_CTL__POR,
+ [TAIKO_A_CDC_MBHC_TIMER_B5_CTL] = TAIKO_A_CDC_MBHC_TIMER_B5_CTL__POR,
+ [TAIKO_A_CDC_MBHC_TIMER_B6_CTL] = TAIKO_A_CDC_MBHC_TIMER_B6_CTL__POR,
+ [TAIKO_A_CDC_MBHC_B1_STATUS] = TAIKO_A_CDC_MBHC_B1_STATUS__POR,
+ [TAIKO_A_CDC_MBHC_B2_STATUS] = TAIKO_A_CDC_MBHC_B2_STATUS__POR,
+ [TAIKO_A_CDC_MBHC_B3_STATUS] = TAIKO_A_CDC_MBHC_B3_STATUS__POR,
+ [TAIKO_A_CDC_MBHC_B4_STATUS] = TAIKO_A_CDC_MBHC_B4_STATUS__POR,
+ [TAIKO_A_CDC_MBHC_B5_STATUS] = TAIKO_A_CDC_MBHC_B5_STATUS__POR,
+ [TAIKO_A_CDC_MBHC_B1_CTL] = TAIKO_A_CDC_MBHC_B1_CTL__POR,
+ [TAIKO_A_CDC_MBHC_B2_CTL] = TAIKO_A_CDC_MBHC_B2_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B1_CTL] = TAIKO_A_CDC_MBHC_VOLT_B1_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B2_CTL] = TAIKO_A_CDC_MBHC_VOLT_B2_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B3_CTL] = TAIKO_A_CDC_MBHC_VOLT_B3_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B4_CTL] = TAIKO_A_CDC_MBHC_VOLT_B4_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B5_CTL] = TAIKO_A_CDC_MBHC_VOLT_B5_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B6_CTL] = TAIKO_A_CDC_MBHC_VOLT_B6_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B7_CTL] = TAIKO_A_CDC_MBHC_VOLT_B7_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B8_CTL] = TAIKO_A_CDC_MBHC_VOLT_B8_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B9_CTL] = TAIKO_A_CDC_MBHC_VOLT_B9_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B10_CTL] = TAIKO_A_CDC_MBHC_VOLT_B10_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B11_CTL] = TAIKO_A_CDC_MBHC_VOLT_B11_CTL__POR,
+ [TAIKO_A_CDC_MBHC_VOLT_B12_CTL] = TAIKO_A_CDC_MBHC_VOLT_B12_CTL__POR,
+ [TAIKO_A_CDC_MBHC_CLK_CTL] = TAIKO_A_CDC_MBHC_CLK_CTL__POR,
+ [TAIKO_A_CDC_MBHC_INT_CTL] = TAIKO_A_CDC_MBHC_INT_CTL__POR,
+ [TAIKO_A_CDC_MBHC_DEBUG_CTL] = TAIKO_A_CDC_MBHC_DEBUG_CTL__POR,
+ [TAIKO_A_CDC_MBHC_SPARE] = TAIKO_A_CDC_MBHC_SPARE__POR,
+ [TAIKO_A_CDC_MAD_MAIN_CTL_1] = TAIKO_A_CDC_MAD_MAIN_CTL_1__POR,
+ [TAIKO_A_CDC_MAD_MAIN_CTL_2] = TAIKO_A_CDC_MAD_MAIN_CTL_2__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_1] = TAIKO_A_CDC_MAD_AUDIO_CTL_1__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_2] = TAIKO_A_CDC_MAD_AUDIO_CTL_2__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_3] = TAIKO_A_CDC_MAD_AUDIO_CTL_3__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_4] = TAIKO_A_CDC_MAD_AUDIO_CTL_4__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_5] = TAIKO_A_CDC_MAD_AUDIO_CTL_5__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_6] = TAIKO_A_CDC_MAD_AUDIO_CTL_6__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_7] = TAIKO_A_CDC_MAD_AUDIO_CTL_7__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_CTL_8] = TAIKO_A_CDC_MAD_AUDIO_CTL_8__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR] =
+ TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_PTR__POR,
+ [TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL] =
+ TAIKO_A_CDC_MAD_AUDIO_IIR_CTL_VAL__POR,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_1] = TAIKO_A_CDC_MAD_ULTR_CTL_1__POR,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_2] = TAIKO_A_CDC_MAD_ULTR_CTL_2__POR,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_3] = TAIKO_A_CDC_MAD_ULTR_CTL_3__POR,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_4] = TAIKO_A_CDC_MAD_ULTR_CTL_4__POR,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_5] = TAIKO_A_CDC_MAD_ULTR_CTL_5__POR,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_6] = TAIKO_A_CDC_MAD_ULTR_CTL_6__POR,
+ [TAIKO_A_CDC_MAD_ULTR_CTL_7] = TAIKO_A_CDC_MAD_ULTR_CTL_7__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_1] = TAIKO_A_CDC_MAD_BEACON_CTL_1__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_2] = TAIKO_A_CDC_MAD_BEACON_CTL_2__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_3] = TAIKO_A_CDC_MAD_BEACON_CTL_3__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_4] = TAIKO_A_CDC_MAD_BEACON_CTL_4__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_5] = TAIKO_A_CDC_MAD_BEACON_CTL_5__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_6] = TAIKO_A_CDC_MAD_BEACON_CTL_6__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_7] = TAIKO_A_CDC_MAD_BEACON_CTL_7__POR,
+ [TAIKO_A_CDC_MAD_BEACON_CTL_8] = TAIKO_A_CDC_MAD_BEACON_CTL_8__POR,
+ [TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR] =
+ TAIKO_A_CDC_MAD_BEACON_IIR_CTL_PTR__POR,
+ [TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL] =
+ TAIKO_A_CDC_MAD_BEACON_IIR_CTL_VAL__POR,
+};
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
new file mode 100644
index 0000000..67a5d8a
--- /dev/null
+++ b/sound/soc/codecs/wcd9320.c
@@ -0,0 +1,7471 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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/init.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/wcd9xxx/core.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
+#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
+#include <linux/mfd/wcd9xxx/pdata.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include "wcd9320.h"
+
+#define WCD9320_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+
+#define NUM_DECIMATORS 10
+#define NUM_INTERPOLATORS 7
+#define BITS_PER_REG 8
+#define TAIKO_CFILT_FAST_MODE 0x00
+#define TAIKO_CFILT_SLOW_MODE 0x40
+#define MBHC_FW_READ_ATTEMPTS 15
+#define MBHC_FW_READ_TIMEOUT 2000000
+
+enum {
+ MBHC_USE_HPHL_TRIGGER = 1,
+ MBHC_USE_MB_TRIGGER = 2
+};
+
+#define MBHC_NUM_DCE_PLUG_DETECT 3
+#define NUM_ATTEMPTS_INSERT_DETECT 25
+#define NUM_ATTEMPTS_TO_REPORT 5
+
+#define TAIKO_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
+ SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED)
+
+#define TAIKO_I2S_MASTER_MODE_MASK 0x08
+
+#define TAIKO_OCP_ATTEMPT 1
+
+#define AIF1_PB 1
+#define AIF1_CAP 2
+#define AIF2_PB 3
+#define AIF2_CAP 4
+#define AIF3_CAP 5
+#define AIF3_PB 6
+
+#define NUM_CODEC_DAIS 6
+#define TAIKO_COMP_DIGITAL_GAIN_OFFSET 3
+
+struct taiko_codec_dai_data {
+ u32 rate;
+ u32 *ch_num;
+ u32 ch_act;
+ u32 ch_tot;
+};
+
+#define TAIKO_MCLK_RATE_12288KHZ 12288000
+#define TAIKO_MCLK_RATE_9600KHZ 9600000
+
+#define TAIKO_FAKE_INS_THRESHOLD_MS 2500
+#define TAIKO_FAKE_REMOVAL_MIN_PERIOD_MS 50
+
+#define TAIKO_MBHC_BUTTON_MIN 0x8000
+
+#define TAIKO_MBHC_FAKE_INSERT_LOW 10
+#define TAIKO_MBHC_FAKE_INSERT_HIGH 80
+#define TAIKO_MBHC_FAKE_INS_HIGH_NO_GPIO 150
+
+#define TAIKO_MBHC_STATUS_REL_DETECTION 0x0C
+
+#define TAIKO_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
+
+#define TAIKO_MBHC_FAKE_INS_DELTA_MV 200
+#define TAIKO_MBHC_FAKE_INS_DELTA_SCALED_MV 300
+
+#define TAIKO_HS_DETECT_PLUG_TIME_MS (5 * 1000)
+#define TAIKO_HS_DETECT_PLUG_INERVAL_MS 100
+
+#define TAIKO_GPIO_IRQ_DEBOUNCE_TIME_US 5000
+
+#define TAIKO_MBHC_GND_MIC_SWAP_THRESHOLD 2
+
+#define TAIKO_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
+#define TAIKO_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+static struct snd_soc_dai_driver taiko_dai[];
+static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
+
+enum taiko_bandgap_type {
+ TAIKO_BANDGAP_OFF = 0,
+ TAIKO_BANDGAP_AUDIO_MODE,
+ TAIKO_BANDGAP_MBHC_MODE,
+};
+
+struct mbhc_micbias_regs {
+ u16 cfilt_val;
+ u16 cfilt_ctl;
+ u16 mbhc_reg;
+ u16 int_rbias;
+ u16 ctl_reg;
+ u8 cfilt_sel;
+};
+
+/* Codec supports 2 IIR filters */
+enum {
+ IIR1 = 0,
+ IIR2,
+ IIR_MAX,
+};
+/* Codec supports 5 bands */
+enum {
+ BAND1 = 0,
+ BAND2,
+ BAND3,
+ BAND4,
+ BAND5,
+ BAND_MAX,
+};
+
+enum {
+ COMPANDER_1 = 0,
+ COMPANDER_2,
+ COMPANDER_MAX,
+};
+
+enum {
+ COMPANDER_FS_8KHZ = 0,
+ COMPANDER_FS_16KHZ,
+ COMPANDER_FS_32KHZ,
+ COMPANDER_FS_48KHZ,
+ COMPANDER_FS_96KHZ,
+ COMPANDER_FS_192KHZ,
+ COMPANDER_FS_MAX,
+};
+
+/* Flags to track of PA and DAC state.
+ * PA and DAC should be tracked separately as AUXPGA loopback requires
+ * only PA to be turned on without DAC being on. */
+enum taiko_priv_ack_flags {
+ TAIKO_HPHL_PA_OFF_ACK = 0,
+ TAIKO_HPHR_PA_OFF_ACK,
+ TAIKO_HPHL_DAC_OFF_ACK,
+ TAIKO_HPHR_DAC_OFF_ACK
+};
+
+
+struct comp_sample_dependent_params {
+ u32 peak_det_timeout;
+ u32 rms_meter_div_fact;
+ u32 rms_meter_resamp_fact;
+};
+
+/* Data used by MBHC */
+struct mbhc_internal_cal_data {
+ u16 dce_z;
+ u16 dce_mb;
+ u16 sta_z;
+ u16 sta_mb;
+ u32 t_sta_dce;
+ u32 t_dce;
+ u32 t_sta;
+ u32 micb_mv;
+ u16 v_ins_hu;
+ u16 v_ins_h;
+ u16 v_b1_hu;
+ u16 v_b1_h;
+ u16 v_b1_huc;
+ u16 v_brh;
+ u16 v_brl;
+ u16 v_no_mic;
+ u8 npoll;
+ u8 nbounce_wait;
+ s16 adj_v_hs_max;
+ u16 adj_v_ins_hu;
+ u16 adj_v_ins_h;
+ s16 v_inval_ins_low;
+ s16 v_inval_ins_high;
+};
+
+struct taiko_reg_address {
+ u16 micb_4_ctl;
+ u16 micb_4_int_rbias;
+ u16 micb_4_mbhc;
+};
+
+enum taiko_mbhc_plug_type {
+ PLUG_TYPE_INVALID = -1,
+ PLUG_TYPE_NONE,
+ PLUG_TYPE_HEADSET,
+ PLUG_TYPE_HEADPHONE,
+ PLUG_TYPE_HIGH_HPH,
+ PLUG_TYPE_GND_MIC_SWAP,
+};
+
+enum taiko_mbhc_state {
+ MBHC_STATE_NONE = -1,
+ MBHC_STATE_POTENTIAL,
+ MBHC_STATE_POTENTIAL_RECOVERY,
+ MBHC_STATE_RELEASE,
+};
+
+struct hpf_work {
+ struct taiko_priv *taiko;
+ u32 decimator;
+ u8 tx_hpf_cut_of_freq;
+ struct delayed_work dwork;
+};
+
+static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
+
+struct taiko_priv {
+ struct snd_soc_codec *codec;
+ struct taiko_reg_address reg_addr;
+ u32 adc_count;
+ u32 cfilt1_cnt;
+ u32 cfilt2_cnt;
+ u32 cfilt3_cnt;
+ u32 rx_bias_count;
+ s32 dmic_1_2_clk_cnt;
+ s32 dmic_3_4_clk_cnt;
+ s32 dmic_5_6_clk_cnt;
+
+ enum taiko_bandgap_type bandgap_type;
+ bool mclk_enabled;
+ bool clock_active;
+ bool config_mode_active;
+ bool mbhc_polling_active;
+ unsigned long mbhc_fake_ins_start;
+ int buttons_pressed;
+ enum taiko_mbhc_state mbhc_state;
+ struct taiko_mbhc_config mbhc_cfg;
+ struct mbhc_internal_cal_data mbhc_data;
+
+ struct wcd9xxx_pdata *pdata;
+ u32 anc_slot;
+
+ bool no_mic_headset_override;
+ /* Delayed work to report long button press */
+ struct delayed_work mbhc_btn_dwork;
+
+ struct mbhc_micbias_regs mbhc_bias_regs;
+ bool mbhc_micbias_switched;
+
+ /* track PA/DAC state */
+ unsigned long hph_pa_dac_state;
+
+ /*track taiko interface type*/
+ u8 intf_type;
+
+ u32 hph_status; /* track headhpone status */
+ /* define separate work for left and right headphone OCP to avoid
+ * additional checking on which OCP event to report so no locking
+ * to ensure synchronization is required
+ */
+ struct work_struct hphlocp_work; /* reporting left hph ocp off */
+ struct work_struct hphrocp_work; /* reporting right hph ocp off */
+
+ u8 hphlocp_cnt; /* headphone left ocp retry */
+ u8 hphrocp_cnt; /* headphone right ocp retry */
+
+ /* Work to perform MBHC Firmware Read */
+ struct delayed_work mbhc_firmware_dwork;
+ const struct firmware *mbhc_fw;
+
+ /* num of slim ports required */
+ struct taiko_codec_dai_data dai[NUM_CODEC_DAIS];
+
+ /*compander*/
+ int comp_enabled[COMPANDER_MAX];
+ u32 comp_fs[COMPANDER_MAX];
+
+ /* Maintain the status of AUX PGA */
+ int aux_pga_cnt;
+ u8 aux_l_gain;
+ u8 aux_r_gain;
+
+ struct delayed_work mbhc_insert_dwork;
+ unsigned long mbhc_last_resume; /* in jiffies */
+
+ u8 current_plug;
+ struct work_struct hs_correct_plug_work;
+ bool hs_detect_work_stop;
+ bool hs_polling_irq_prepared;
+ bool lpi_enabled; /* low power insertion detection */
+ bool in_gpio_handler;
+ /* Currently, only used for mbhc purpose, to protect
+ * concurrent execution of mbhc threaded irq handlers and
+ * kill race between DAPM and MBHC.But can serve as a
+ * general lock to protect codec resource
+ */
+ struct mutex codec_resource_lock;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_poke;
+ struct dentry *debugfs_mbhc;
+#endif
+};
+
+
+static const u32 comp_shift[] = {
+ 0,
+ 2,
+};
+
+static const int comp_rx_path[] = {
+ COMPANDER_1,
+ COMPANDER_1,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_MAX,
+};
+
+static const struct comp_sample_dependent_params comp_samp_params[] = {
+ {
+ .peak_det_timeout = 0x2,
+ .rms_meter_div_fact = 0x8 << 4,
+ .rms_meter_resamp_fact = 0x21,
+ },
+ {
+ .peak_det_timeout = 0x3,
+ .rms_meter_div_fact = 0x9 << 4,
+ .rms_meter_resamp_fact = 0x28,
+ },
+
+ {
+ .peak_det_timeout = 0x5,
+ .rms_meter_div_fact = 0xB << 4,
+ .rms_meter_resamp_fact = 0x28,
+ },
+
+ {
+ .peak_det_timeout = 0x5,
+ .rms_meter_div_fact = 0xB << 4,
+ .rms_meter_resamp_fact = 0x28,
+ },
+};
+
+static unsigned short rx_digital_gain_reg[] = {
+ TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL,
+ TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL,
+ TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL,
+ TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL,
+ TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL,
+ TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL,
+ TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL,
+};
+
+
+static unsigned short tx_digital_gain_reg[] = {
+ TAIKO_A_CDC_TX1_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX2_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX3_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX4_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX5_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX6_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX7_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX8_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX9_VOL_CTL_GAIN,
+ TAIKO_A_CDC_TX10_VOL_CTL_GAIN,
+};
+
+static int taiko_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %d\n", __func__, event);
+
+ /* FIX . need to use CLASS-H controller */
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x01,
+ 0x01);
+ usleep_range(200, 200);
+ snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL,
+ 0x01, 0x01);
+ usleep_range(20, 20);
+ snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x08, 0x08);
+ snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x10, 0x10);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x01,
+ 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_NCP_STATIC, 0x08, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static int taiko_get_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ ucontrol->value.integer.value[0] = taiko->anc_slot;
+ return 0;
+}
+
+static int taiko_put_anc_slot(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ taiko->anc_slot = ucontrol->value.integer.value[0];
+ return 0;
+}
+
+static int taiko_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ ear_pa_gain = snd_soc_read(codec, TAIKO_A_RX_EAR_GAIN);
+
+ ear_pa_gain = ear_pa_gain >> 5;
+
+ if (ear_pa_gain == 0x00) {
+ ucontrol->value.integer.value[0] = 0;
+ } else if (ear_pa_gain == 0x04) {
+ ucontrol->value.integer.value[0] = 1;
+ } else {
+ pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
+ __func__, ear_pa_gain);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
+
+ return 0;
+}
+
+static int taiko_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
+ ucontrol->value.integer.value[0]);
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ ear_pa_gain = 0x00;
+ break;
+ case 1:
+ ear_pa_gain = 0x80;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
+ return 0;
+}
+
+static int taiko_get_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ snd_soc_read(codec, (TAIKO_A_CDC_IIR1_CTL + 16 * iir_idx)) &
+ (1 << band_idx);
+
+ pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int taiko_put_iir_enable_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ /* Mask first 5 bits, 6-8 are reserved */
+ snd_soc_update_bits(codec, (TAIKO_A_CDC_IIR1_CTL + 16 * iir_idx),
+ (1 << band_idx), (value << band_idx));
+
+ pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
+ iir_idx, band_idx, value);
+ return 0;
+}
+static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ int coeff_idx)
+{
+ /* Address does not automatically update if reading */
+ snd_soc_write(codec,
+ (TAIKO_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+
+ /* Mask bits top 2 bits since they are reserved */
+ return ((snd_soc_read(codec,
+ (TAIKO_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24)) &
+ 0x3FFFFFFF;
+}
+
+static int taiko_get_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ ucontrol->value.integer.value[0] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0);
+ ucontrol->value.integer.value[1] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1);
+ ucontrol->value.integer.value[2] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2);
+ ucontrol->value.integer.value[3] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3);
+ ucontrol->value.integer.value[4] =
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4);
+
+ pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[0],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[1],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[2],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[3],
+ __func__, iir_idx, band_idx,
+ (uint32_t)ucontrol->value.integer.value[4]);
+ return 0;
+}
+
+static void set_iir_band_coeff(struct snd_soc_codec *codec,
+ int iir_idx, int band_idx,
+ int coeff_idx, uint32_t value)
+{
+ /* Mask top 3 bits, 6-8 are reserved */
+ /* Update address manually each time */
+ snd_soc_write(codec,
+ (TAIKO_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
+ (band_idx * BAND_MAX + coeff_idx) & 0x1F);
+
+ /* Mask top 2 bits, 7-8 are reserved */
+ snd_soc_write(codec,
+ (TAIKO_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
+ (value >> 24) & 0x3F);
+
+}
+
+static int taiko_put_iir_band_audio_mixer(
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int iir_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->reg;
+ int band_idx = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+
+ set_iir_band_coeff(codec, iir_idx, band_idx, 0,
+ ucontrol->value.integer.value[0]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 1,
+ ucontrol->value.integer.value[1]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 2,
+ ucontrol->value.integer.value[2]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 3,
+ ucontrol->value.integer.value[3]);
+ set_iir_band_coeff(codec, iir_idx, band_idx, 4,
+ ucontrol->value.integer.value[4]);
+
+ pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
+ "%s: IIR #%d band #%d b1 = 0x%x\n"
+ "%s: IIR #%d band #%d b2 = 0x%x\n"
+ "%s: IIR #%d band #%d a1 = 0x%x\n"
+ "%s: IIR #%d band #%d a2 = 0x%x\n",
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 0),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 1),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 2),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 3),
+ __func__, iir_idx, band_idx,
+ get_iir_band_coeff(codec, iir_idx, band_idx, 4));
+ return 0;
+}
+
+static int taiko_compander_gain_offset(
+ struct snd_soc_codec *codec, u32 enable,
+ unsigned int reg, int mask, int event)
+{
+ int pa_mode = snd_soc_read(codec, reg) & mask;
+ int gain_offset = 0;
+ /* if PMU && enable is 1-> offset is 3
+ * if PMU && enable is 0-> offset is 0
+ * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
+ * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
+ */
+
+ if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
+ gain_offset = TAIKO_COMP_DIGITAL_GAIN_OFFSET;
+ if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
+ gain_offset = -TAIKO_COMP_DIGITAL_GAIN_OFFSET;
+ return gain_offset;
+}
+
+
+static int taiko_config_gain_compander(
+ struct snd_soc_codec *codec,
+ u32 compander, u32 enable, int event)
+{
+ int value = 0;
+ int mask = 1 << 4;
+ int gain = 0;
+ int gain_offset;
+ if (compander >= COMPANDER_MAX) {
+ pr_err("%s: Error, invalid compander channel\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
+ value = 1 << 4;
+
+ if (compander == COMPANDER_1) {
+ gain_offset = taiko_compander_gain_offset(codec, enable,
+ TAIKO_A_RX_HPH_L_GAIN, mask, event);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_L_GAIN, mask, value);
+ gain = snd_soc_read(codec, TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = taiko_compander_gain_offset(codec, enable,
+ TAIKO_A_RX_HPH_R_GAIN, mask, event);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_R_GAIN, mask, value);
+ gain = snd_soc_read(codec, TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ } else if (compander == COMPANDER_2) {
+ gain_offset = taiko_compander_gain_offset(codec, enable,
+ TAIKO_A_RX_LINE_1_GAIN, mask, event);
+ snd_soc_update_bits(codec, TAIKO_A_RX_LINE_1_GAIN, mask, value);
+ gain = snd_soc_read(codec, TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = taiko_compander_gain_offset(codec, enable,
+ TAIKO_A_RX_LINE_3_GAIN, mask, event);
+ snd_soc_update_bits(codec, TAIKO_A_RX_LINE_3_GAIN, mask, value);
+ gain = snd_soc_read(codec, TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = taiko_compander_gain_offset(codec, enable,
+ TAIKO_A_RX_LINE_2_GAIN, mask, event);
+ snd_soc_update_bits(codec, TAIKO_A_RX_LINE_2_GAIN, mask, value);
+ gain = snd_soc_read(codec, TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = taiko_compander_gain_offset(codec, enable,
+ TAIKO_A_RX_LINE_4_GAIN, mask, event);
+ snd_soc_update_bits(codec, TAIKO_A_RX_LINE_4_GAIN, mask, value);
+ gain = snd_soc_read(codec, TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ }
+ return 0;
+}
+static int taiko_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->max;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = taiko->comp_enabled[comp];
+
+ return 0;
+}
+
+static int taiko_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->max;
+ int value = ucontrol->value.integer.value[0];
+
+ if (value == taiko->comp_enabled[comp]) {
+ pr_debug("%s: compander #%d enable %d no change\n",
+ __func__, comp, value);
+ return 0;
+ }
+ taiko->comp_enabled[comp] = value;
+ return 0;
+}
+
+
+static int taiko_config_compander(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u32 rate = taiko->comp_fs[w->shift];
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (taiko->comp_enabled[w->shift] != 0) {
+ /* Enable both L/R compander clocks */
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_RX_B2_CTL,
+ 0x03 << comp_shift[w->shift],
+ 0x03 << comp_shift[w->shift]);
+ /* Clar the HALT for the compander*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 0);
+ /* Toggle compander reset bits*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_OTHR_RESET_B2_CTL,
+ 0x03 << comp_shift[w->shift],
+ 0x03 << comp_shift[w->shift]);
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_OTHR_RESET_B2_CTL,
+ 0x03 << comp_shift[w->shift], 0);
+ taiko_config_gain_compander(codec, w->shift, 1, event);
+ /* Update the RMS meter resampling*/
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_COMP1_B3_CTL +
+ w->shift * 8, 0xFF, 0x01);
+ /* Wait for 1ms*/
+ usleep_range(1000, 1000);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* Set sample rate dependent paramater*/
+ if (taiko->comp_enabled[w->shift] != 0) {
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_FS_CFG +
+ w->shift * 8, 0x03, rate);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0x0F,
+ comp_samp_params[rate].peak_det_timeout);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0xF0,
+ comp_samp_params[rate].rms_meter_div_fact);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B3_CTL +
+ w->shift * 8, 0xFF,
+ comp_samp_params[rate].rms_meter_resamp_fact);
+ /* Compander enable -> 0x370/0x378*/
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x03);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Halt the compander*/
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 1 << 2);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Restore the gain */
+ taiko_config_gain_compander(codec, w->shift,
+ taiko->comp_enabled[w->shift], event);
+ /* Disable the compander*/
+ snd_soc_update_bits(codec, TAIKO_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x00);
+ /* Turn off the clock for compander in pair*/
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_B2_CTL,
+ 0x03 << comp_shift[w->shift], 0);
+ break;
+ }
+ return 0;
+}
+
+static const char * const taiko_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
+static const struct soc_enum taiko_ear_pa_gain_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, taiko_ear_pa_gain_text),
+};
+
+/*cut of frequency for high pass filter*/
+static const char * const cf_text[] = {
+ "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
+};
+
+static const struct soc_enum cf_dec1_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec2_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec3_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec4_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec5_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec6_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec7_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec8_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec9_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_dec10_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
+
+static const struct soc_enum cf_rxmix1_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
+
+static const struct soc_enum cf_rxmix2_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
+
+static const struct soc_enum cf_rxmix3_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
+
+static const struct soc_enum cf_rxmix4_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
+
+static const struct soc_enum cf_rxmix5_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
+;
+static const struct soc_enum cf_rxmix6_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
+
+static const struct soc_enum cf_rxmix7_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
+
+static const struct snd_kcontrol_new taiko_snd_controls[] = {
+
+ SOC_ENUM_EXT("EAR PA Gain", taiko_ear_pa_gain_enum[0],
+ taiko_pa_gain_get, taiko_pa_gain_put),
+
+ SOC_SINGLE_TLV("LINEOUT1 Volume", TAIKO_A_RX_LINE_1_GAIN, 0, 12, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", TAIKO_A_RX_LINE_2_GAIN, 0, 12, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT3 Volume", TAIKO_A_RX_LINE_3_GAIN, 0, 12, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT4 Volume", TAIKO_A_RX_LINE_4_GAIN, 0, 12, 1,
+ line_gain),
+
+ SOC_SINGLE_TLV("HPHL Volume", TAIKO_A_RX_HPH_L_GAIN, 0, 12, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", TAIKO_A_RX_HPH_R_GAIN, 0, 12, 1,
+ line_gain),
+
+ SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX3 Digital Volume", TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX5 Digital Volume", TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX6 Digital Volume", TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+ SOC_SINGLE_S8_TLV("RX7 Digital Volume", TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL,
+ -84, 40, digital_gain),
+
+ SOC_SINGLE_S8_TLV("DEC1 Volume", TAIKO_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC2 Volume", TAIKO_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC3 Volume", TAIKO_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC4 Volume", TAIKO_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC5 Volume", TAIKO_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC6 Volume", TAIKO_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC7 Volume", TAIKO_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC8 Volume", TAIKO_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC9 Volume", TAIKO_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
+ digital_gain),
+ SOC_SINGLE_S8_TLV("DEC10 Volume", TAIKO_A_CDC_TX10_VOL_CTL_GAIN, -84,
+ 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAIKO_A_CDC_IIR1_GAIN_B1_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TAIKO_A_CDC_IIR1_GAIN_B2_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TAIKO_A_CDC_IIR1_GAIN_B3_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAIKO_A_CDC_IIR1_GAIN_B4_CTL, -84,
+ 40, digital_gain),
+ SOC_SINGLE_TLV("ADC1 Volume", TAIKO_A_TX_1_2_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC2 Volume", TAIKO_A_TX_1_2_EN, 1, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC3 Volume", TAIKO_A_TX_3_4_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC4 Volume", TAIKO_A_TX_3_4_EN, 1, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC5 Volume", TAIKO_A_TX_5_6_EN, 5, 3, 0, analog_gain),
+ SOC_SINGLE_TLV("ADC6 Volume", TAIKO_A_TX_5_6_EN, 1, 3, 0, analog_gain),
+
+
+ SOC_SINGLE("MICBIAS1 CAPLESS Switch", TAIKO_A_MICB_1_CTL, 4, 1, 1),
+ SOC_SINGLE("MICBIAS2 CAPLESS Switch", TAIKO_A_MICB_2_CTL, 4, 1, 1),
+ SOC_SINGLE("MICBIAS3 CAPLESS Switch", TAIKO_A_MICB_3_CTL, 4, 1, 1),
+ SOC_SINGLE("MICBIAS4 CAPLESS Switch", TAIKO_A_MICB_4_CTL, 4, 1, 1),
+
+ SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, taiko_get_anc_slot,
+ taiko_put_anc_slot),
+ SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
+ SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
+ SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
+ SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
+ SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
+ SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
+ SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
+ SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
+ SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
+ SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
+
+ SOC_SINGLE("TX1 HPF Switch", TAIKO_A_CDC_TX1_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX2 HPF Switch", TAIKO_A_CDC_TX2_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX3 HPF Switch", TAIKO_A_CDC_TX3_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX4 HPF Switch", TAIKO_A_CDC_TX4_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX5 HPF Switch", TAIKO_A_CDC_TX5_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX6 HPF Switch", TAIKO_A_CDC_TX6_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX7 HPF Switch", TAIKO_A_CDC_TX7_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX8 HPF Switch", TAIKO_A_CDC_TX8_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX9 HPF Switch", TAIKO_A_CDC_TX9_MUX_CTL, 3, 1, 0),
+ SOC_SINGLE("TX10 HPF Switch", TAIKO_A_CDC_TX10_MUX_CTL, 3, 1, 0),
+
+ SOC_SINGLE("RX1 HPF Switch", TAIKO_A_CDC_RX1_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX2 HPF Switch", TAIKO_A_CDC_RX2_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX3 HPF Switch", TAIKO_A_CDC_RX3_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX4 HPF Switch", TAIKO_A_CDC_RX4_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX5 HPF Switch", TAIKO_A_CDC_RX5_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX6 HPF Switch", TAIKO_A_CDC_RX6_B5_CTL, 2, 1, 0),
+ SOC_SINGLE("RX7 HPF Switch", TAIKO_A_CDC_RX7_B5_CTL, 2, 1, 0),
+
+ SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
+ SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
+ SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
+ SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
+ SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
+ SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
+ SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
+
+ SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+ SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
+ taiko_get_iir_enable_audio_mixer, taiko_put_iir_enable_audio_mixer),
+
+ SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+ SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
+ taiko_get_iir_band_audio_mixer, taiko_put_iir_band_audio_mixer),
+
+ SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
+ taiko_get_compander, taiko_set_compander),
+ SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
+ taiko_get_compander, taiko_set_compander),
+
+};
+
+static const char * const rx_mix1_text[] = {
+ "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
+ "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_mix2_text[] = {
+ "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
+};
+
+static const char * const rx_dsm_text[] = {
+ "CIC_OUT", "DSM_INV"
+};
+
+static const char * const sb_tx1_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC1"
+};
+
+static const char * const sb_tx2_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC2"
+};
+
+static const char * const sb_tx3_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC3"
+};
+
+static const char * const sb_tx4_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC4"
+};
+
+static const char * const sb_tx5_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC5"
+};
+
+static const char * const sb_tx6_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC6"
+};
+
+static const char * const sb_tx7_to_tx10_mux_text[] = {
+ "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
+ "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10"
+};
+
+static const char * const dec1_mux_text[] = {
+ "ZERO", "DMIC1", "ADC6",
+};
+
+static const char * const dec2_mux_text[] = {
+ "ZERO", "DMIC2", "ADC5",
+};
+
+static const char * const dec3_mux_text[] = {
+ "ZERO", "DMIC3", "ADC4",
+};
+
+static const char * const dec4_mux_text[] = {
+ "ZERO", "DMIC4", "ADC3",
+};
+
+static const char * const dec5_mux_text[] = {
+ "ZERO", "DMIC5", "ADC2",
+};
+
+static const char * const dec6_mux_text[] = {
+ "ZERO", "DMIC6", "ADC1",
+};
+
+static const char * const dec7_mux_text[] = {
+ "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
+};
+
+static const char * const dec8_mux_text[] = {
+ "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
+};
+
+static const char * const dec9_mux_text[] = {
+ "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
+};
+
+static const char * const dec10_mux_text[] = {
+ "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
+};
+
+static const char * const anc_mux_text[] = {
+ "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
+ "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
+};
+
+static const char * const anc1_fb_mux_text[] = {
+ "ZERO", "EAR_HPH_L", "EAR_LINE_1",
+};
+
+static const char * const iir1_inp1_text[] = {
+ "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
+ "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const struct soc_enum rx_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
+
+static const struct soc_enum rx_mix1_inp3_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx3_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
+
+static const struct soc_enum rx4_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx4_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
+
+static const struct soc_enum rx5_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx5_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
+
+static const struct soc_enum rx6_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx6_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
+
+static const struct soc_enum rx7_mix1_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
+
+static const struct soc_enum rx7_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
+
+static const struct soc_enum rx1_mix2_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
+
+static const struct soc_enum rx1_mix2_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
+
+static const struct soc_enum rx2_mix2_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
+
+static const struct soc_enum rx2_mix2_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
+
+static const struct soc_enum rx7_mix2_inp1_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX7_B3_CTL, 0, 5, rx_mix2_text);
+
+static const struct soc_enum rx7_mix2_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_RX7_B3_CTL, 3, 5, rx_mix2_text);
+
+static const struct soc_enum rx4_dsm_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
+
+static const struct soc_enum rx6_dsm_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
+
+static const struct soc_enum sb_tx1_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
+
+static const struct soc_enum sb_tx2_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
+
+static const struct soc_enum sb_tx3_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
+
+static const struct soc_enum sb_tx4_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
+
+static const struct soc_enum sb_tx5_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
+
+static const struct soc_enum sb_tx6_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
+
+static const struct soc_enum sb_tx7_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
+ sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum sb_tx8_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
+ sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum sb_tx9_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
+ sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum sb_tx10_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
+ sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum dec1_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
+
+static const struct soc_enum dec2_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
+
+static const struct soc_enum dec3_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
+
+static const struct soc_enum dec4_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
+
+static const struct soc_enum dec5_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
+
+static const struct soc_enum dec6_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
+
+static const struct soc_enum dec7_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
+
+static const struct soc_enum dec8_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
+
+static const struct soc_enum dec9_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
+
+static const struct soc_enum dec10_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
+
+static const struct soc_enum anc1_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
+
+static const struct soc_enum anc2_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
+
+static const struct soc_enum anc1_fb_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
+
+static const struct soc_enum iir1_inp1_mux_enum =
+ SOC_ENUM_SINGLE(TAIKO_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
+
+static const struct snd_kcontrol_new rx_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_mix1_inp3_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
+ SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
+ SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
+ SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
+ SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
+ SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx7_mix2_inp1_mux =
+ SOC_DAPM_ENUM("RX7 MIX2 INP1 Mux", rx7_mix2_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx7_mix2_inp2_mux =
+ SOC_DAPM_ENUM("RX7 MIX2 INP2 Mux", rx7_mix2_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx4_dsm_mux =
+ SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
+
+static const struct snd_kcontrol_new rx6_dsm_mux =
+ SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
+
+static const struct snd_kcontrol_new sb_tx1_mux =
+ SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx2_mux =
+ SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx3_mux =
+ SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx4_mux =
+ SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx5_mux =
+ SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx6_mux =
+ SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx7_mux =
+ SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx8_mux =
+ SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx9_mux =
+ SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx10_mux =
+ SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
+
+
+static int wcd9320_put_dec_enum(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_dapm_widget *w = wlist->widgets[0];
+ struct snd_soc_codec *codec = w->codec;
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int dec_mux, decimator;
+ char *dec_name = NULL;
+ char *widget_name = NULL;
+ char *temp;
+ u16 tx_mux_ctl_reg;
+ u8 adc_dmic_sel = 0x0;
+ int ret = 0;
+
+ if (ucontrol->value.enumerated.item[0] > e->max - 1)
+ return -EINVAL;
+
+ dec_mux = ucontrol->value.enumerated.item[0];
+
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+ temp = widget_name;
+
+ dec_name = strsep(&widget_name, " ");
+ widget_name = temp;
+ if (!dec_name) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
+ if (ret < 0) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
+ , __func__, w->name, decimator, dec_mux);
+
+
+ switch (decimator) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ if (dec_mux == 1)
+ adc_dmic_sel = 0x1;
+ else
+ adc_dmic_sel = 0x0;
+ break;
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ if ((dec_mux == 1) || (dec_mux == 2))
+ adc_dmic_sel = 0x1;
+ else
+ adc_dmic_sel = 0x0;
+ break;
+ default:
+ pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ tx_mux_ctl_reg = TAIKO_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
+
+ ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+
+out:
+ kfree(widget_name);
+ return ret;
+}
+
+#define WCD9320_DEC_ENUM(xname, xenum) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_enum_double, \
+ .get = snd_soc_dapm_get_enum_double, \
+ .put = wcd9320_put_dec_enum, \
+ .private_value = (unsigned long)&xenum }
+
+static const struct snd_kcontrol_new dec1_mux =
+ WCD9320_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
+
+static const struct snd_kcontrol_new dec2_mux =
+ WCD9320_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
+
+static const struct snd_kcontrol_new dec3_mux =
+ WCD9320_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
+
+static const struct snd_kcontrol_new dec4_mux =
+ WCD9320_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
+
+static const struct snd_kcontrol_new dec5_mux =
+ WCD9320_DEC_ENUM("DEC5 MUX Mux", dec5_mux_enum);
+
+static const struct snd_kcontrol_new dec6_mux =
+ WCD9320_DEC_ENUM("DEC6 MUX Mux", dec6_mux_enum);
+
+static const struct snd_kcontrol_new dec7_mux =
+ WCD9320_DEC_ENUM("DEC7 MUX Mux", dec7_mux_enum);
+
+static const struct snd_kcontrol_new dec8_mux =
+ WCD9320_DEC_ENUM("DEC8 MUX Mux", dec8_mux_enum);
+
+static const struct snd_kcontrol_new dec9_mux =
+ WCD9320_DEC_ENUM("DEC9 MUX Mux", dec9_mux_enum);
+
+static const struct snd_kcontrol_new dec10_mux =
+ WCD9320_DEC_ENUM("DEC10 MUX Mux", dec10_mux_enum);
+
+static const struct snd_kcontrol_new iir1_inp1_mux =
+ SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
+
+static const struct snd_kcontrol_new anc1_mux =
+ SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
+
+static const struct snd_kcontrol_new anc2_mux =
+ SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
+
+static const struct snd_kcontrol_new anc1_fb_mux =
+ SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
+
+static const struct snd_kcontrol_new dac1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_EAR_EN, 5, 1, 0)
+};
+static const struct snd_kcontrol_new hphl_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_pa_mix[] = {
+ SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAIKO_A_RX_PA_AUX_IN_CONN,
+ 7, 1, 0),
+};
+
+static const struct snd_kcontrol_new hphr_pa_mix[] = {
+ SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAIKO_A_RX_PA_AUX_IN_CONN,
+ 6, 1, 0),
+};
+
+static const struct snd_kcontrol_new ear_pa_mix[] = {
+ SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAIKO_A_RX_PA_AUX_IN_CONN,
+ 5, 1, 0),
+};
+static const struct snd_kcontrol_new lineout1_pa_mix[] = {
+ SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAIKO_A_RX_PA_AUX_IN_CONN,
+ 4, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout2_pa_mix[] = {
+ SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAIKO_A_RX_PA_AUX_IN_CONN,
+ 3, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout3_pa_mix[] = {
+ SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAIKO_A_RX_PA_AUX_IN_CONN,
+ 2, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout4_pa_mix[] = {
+ SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAIKO_A_RX_PA_AUX_IN_CONN,
+ 1, 1, 0),
+};
+
+static const struct snd_kcontrol_new lineout3_ground_switch =
+ SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
+
+static const struct snd_kcontrol_new lineout4_ground_switch =
+ SOC_DAPM_SINGLE("Switch", TAIKO_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
+
+static void taiko_codec_enable_adc_block(struct snd_soc_codec *codec,
+ int enable)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s %d\n", __func__, enable);
+
+ if (enable) {
+ taiko->adc_count++;
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
+ } else {
+ taiko->adc_count--;
+ if (!taiko->adc_count)
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_OTHR_CTL,
+ 0x2, 0x0);
+ }
+}
+
+static int taiko_codec_enable_adc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 adc_reg;
+ u8 init_bit_shift;
+
+ pr_debug("%s %d\n", __func__, event);
+
+ if (w->reg == TAIKO_A_TX_1_2_EN)
+ adc_reg = TAIKO_A_TX_1_2_TEST_CTL;
+ else if (w->reg == TAIKO_A_TX_3_4_EN)
+ adc_reg = TAIKO_A_TX_3_4_TEST_CTL;
+ else if (w->reg == TAIKO_A_TX_5_6_EN)
+ adc_reg = TAIKO_A_TX_5_6_TEST_CTL;
+ else {
+ pr_err("%s: Error, invalid adc register\n", __func__);
+ return -EINVAL;
+ }
+
+ if (w->shift == 3)
+ init_bit_shift = 6;
+ else if (w->shift == 7)
+ init_bit_shift = 7;
+ else {
+ pr_err("%s: Error, invalid init bit postion adc register\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ taiko_codec_enable_adc_block(codec, 1);
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
+ 1 << init_bit_shift);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+
+ snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ taiko_codec_enable_adc_block(codec, 0);
+ break;
+ }
+ return 0;
+}
+
+static void taiko_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
+{
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x04,
+ 0x04);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x01,
+ 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x00);
+}
+
+static void taiko_codec_enable_bandgap(struct snd_soc_codec *codec,
+ enum taiko_bandgap_type choice)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ /* TODO lock resources accessed by audio streams and threaded
+ * interrupt handlers
+ */
+
+ pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
+ taiko->bandgap_type);
+
+ if (taiko->bandgap_type == choice)
+ return;
+
+ if ((taiko->bandgap_type == TAIKO_BANDGAP_OFF) &&
+ (choice == TAIKO_BANDGAP_AUDIO_MODE)) {
+ taiko_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == TAIKO_BANDGAP_MBHC_MODE) {
+ /* bandgap mode becomes fast,
+ * mclk should be off or clk buff source souldn't be VBG
+ * Let's turn off mclk always */
+ WARN_ON(snd_soc_read(codec, TAIKO_A_CLK_BUFF_EN2) & (1 << 2));
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x2,
+ 0x2);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x4,
+ 0x4);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x01,
+ 0x01);
+ usleep_range(1000, 1000);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x80,
+ 0x00);
+ } else if ((taiko->bandgap_type == TAIKO_BANDGAP_MBHC_MODE) &&
+ (choice == TAIKO_BANDGAP_AUDIO_MODE)) {
+ snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x00);
+ usleep_range(100, 100);
+ taiko_codec_enable_audio_mode_bandgap(codec);
+ } else if (choice == TAIKO_BANDGAP_OFF) {
+ snd_soc_write(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x00);
+ } else {
+ pr_err("%s: Error, Invalid bandgap settings\n", __func__);
+ }
+ taiko->bandgap_type = choice;
+}
+
+static void taiko_codec_disable_clock_block(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ pr_debug("%s\n", __func__);
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x04, 0x00);
+ usleep_range(50, 50);
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x02, 0x02);
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x05, 0x00);
+ usleep_range(50, 50);
+ taiko->clock_active = false;
+}
+
+static int taiko_codec_mclk_index(const struct taiko_priv *taiko)
+{
+ if (taiko->mbhc_cfg.mclk_rate == TAIKO_MCLK_RATE_12288KHZ)
+ return 0;
+ else if (taiko->mbhc_cfg.mclk_rate == TAIKO_MCLK_RATE_9600KHZ)
+ return 1;
+ else {
+ BUG_ON(1);
+ return -EINVAL;
+ }
+}
+
+static void taiko_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ if (enable) {
+ taiko->rx_bias_count++;
+ if (taiko->rx_bias_count == 1)
+ snd_soc_update_bits(codec, TAIKO_A_RX_COM_BIAS,
+ 0x80, 0x80);
+ } else {
+ taiko->rx_bias_count--;
+ if (!taiko->rx_bias_count)
+ snd_soc_update_bits(codec, TAIKO_A_RX_COM_BIAS,
+ 0x80, 0x00);
+ }
+}
+
+static int taiko_codec_enable_config_mode(struct snd_soc_codec *codec,
+ int enable)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: enable = %d\n", __func__, enable);
+ if (enable) {
+
+ snd_soc_update_bits(codec, TAIKO_A_RC_OSC_FREQ, 0x10, 0);
+ /* bandgap mode to fast */
+ snd_soc_write(codec, TAIKO_A_BIAS_OSC_BG_CTL, 0x17);
+ usleep_range(5, 5);
+ snd_soc_update_bits(codec, TAIKO_A_RC_OSC_FREQ, 0x80,
+ 0x80);
+ snd_soc_update_bits(codec, TAIKO_A_RC_OSC_TEST, 0x80,
+ 0x80);
+ usleep_range(10, 10);
+ snd_soc_update_bits(codec, TAIKO_A_RC_OSC_TEST, 0x80, 0);
+ usleep_range(10000, 10000);
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x08, 0x08);
+
+ } else {
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_OSC_BG_CTL, 0x1,
+ 0);
+ snd_soc_update_bits(codec, TAIKO_A_RC_OSC_FREQ, 0x80, 0);
+ /* clk source to ext clk and clk buff ref to VBG */
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x0C, 0x04);
+ }
+ taiko->config_mode_active = enable ? true : false;
+
+ return 0;
+}
+
+static int taiko_codec_enable_clock_block(struct snd_soc_codec *codec,
+ int config_mode)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+
+ /* transit to RCO requires mclk off */
+ WARN_ON(snd_soc_read(codec, TAIKO_A_CLK_BUFF_EN2) & (1 << 2));
+ if (config_mode) {
+ /* enable RCO and switch to it */
+ taiko_codec_enable_config_mode(codec, 1);
+ snd_soc_write(codec, TAIKO_A_CLK_BUFF_EN2, 0x02);
+ usleep_range(1000, 1000);
+ } else {
+ /* switch to MCLK */
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x08, 0x00);
+
+ if (taiko->mbhc_polling_active) {
+ snd_soc_write(codec, TAIKO_A_CLK_BUFF_EN2, 0x02);
+ taiko_codec_enable_config_mode(codec, 0);
+ }
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x01, 0x01);
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x02, 0x00);
+ /* on MCLK */
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN2, 0x04, 0x04);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
+ usleep_range(50, 50);
+ taiko->clock_active = true;
+ return 0;
+}
+
+static int taiko_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ taiko_codec_enable_bandgap(codec, TAIKO_BANDGAP_AUDIO_MODE);
+ taiko_enable_rx_bias(codec, 1);
+
+ if (taiko->aux_pga_cnt++ == 1
+ && !taiko->mclk_enabled) {
+ taiko_codec_enable_clock_block(codec, 1);
+ pr_debug("AUX PGA enabled RC osc\n");
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ taiko_enable_rx_bias(codec, 0);
+
+ if (taiko->aux_pga_cnt-- == 0) {
+ if (taiko->mbhc_polling_active)
+ taiko_codec_enable_bandgap(codec,
+ TAIKO_BANDGAP_MBHC_MODE);
+ else
+ taiko_codec_enable_bandgap(codec,
+ TAIKO_BANDGAP_OFF);
+
+ if (!taiko->mclk_enabled &&
+ !taiko->mbhc_polling_active) {
+ taiko_codec_enable_clock_block(codec, 0);
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static int taiko_codec_enable_lineout(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ u16 lineout_gain_reg;
+
+ pr_debug("%s %d %s\n", __func__, event, w->name);
+
+ switch (w->shift) {
+ case 0:
+ lineout_gain_reg = TAIKO_A_RX_LINE_1_GAIN;
+ break;
+ case 1:
+ lineout_gain_reg = TAIKO_A_RX_LINE_2_GAIN;
+ break;
+ case 2:
+ lineout_gain_reg = TAIKO_A_RX_LINE_3_GAIN;
+ break;
+ case 3:
+ lineout_gain_reg = TAIKO_A_RX_LINE_4_GAIN;
+ break;
+ default:
+ pr_err("%s: Error, incorrect lineout register value\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
+ __func__, w->name);
+ usleep_range(16000, 16000);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
+
+
+static int taiko_codec_enable_dmic(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u8 dmic_clk_en;
+ u16 dmic_clk_reg;
+ s32 *dmic_clk_cnt;
+ unsigned int dmic;
+ int ret;
+
+ ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
+ if (ret < 0) {
+ pr_err("%s: Invalid DMIC line on the codec\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (dmic) {
+ case 1:
+ case 2:
+ dmic_clk_en = 0x01;
+ dmic_clk_cnt = &(taiko->dmic_1_2_clk_cnt);
+ dmic_clk_reg = TAIKO_A_CDC_CLK_DMIC_B1_CTL;
+ pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
+ __func__, event, dmic, *dmic_clk_cnt);
+
+ break;
+
+ case 3:
+ case 4:
+ dmic_clk_en = 0x10;
+ dmic_clk_cnt = &(taiko->dmic_3_4_clk_cnt);
+ dmic_clk_reg = TAIKO_A_CDC_CLK_DMIC_B1_CTL;
+
+ pr_debug("%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
+ __func__, event, dmic, *dmic_clk_cnt);
+ break;
+
+ case 5:
+ case 6:
+ dmic_clk_en = 0x01;
+ dmic_clk_cnt = &(taiko->dmic_5_6_clk_cnt);
+ dmic_clk_reg = TAIKO_A_CDC_CLK_DMIC_B2_CTL;
+
+ pr_debug("%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
+ __func__, event, dmic, *dmic_clk_cnt);
+
+ break;
+
+ default:
+ pr_err("%s: Invalid DMIC Selection\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ (*dmic_clk_cnt)++;
+ if (*dmic_clk_cnt == 1)
+ snd_soc_update_bits(codec, dmic_clk_reg,
+ dmic_clk_en, dmic_clk_en);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+
+ (*dmic_clk_cnt)--;
+ if (*dmic_clk_cnt == 0)
+ snd_soc_update_bits(codec, dmic_clk_reg,
+ dmic_clk_en, 0);
+ break;
+ }
+ return 0;
+}
+
+static int taiko_codec_enable_anc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ const char *filename;
+ const struct firmware *fw;
+ int i;
+ int ret;
+ int num_anc_slots;
+ struct anc_header *anc_head;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u32 anc_writes_size = 0;
+ int anc_size_remaining;
+ u32 *anc_ptr;
+ u16 reg;
+ u8 mask, val, old_val;
+
+ pr_debug("%s %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ filename = "wcd9320/wcd9320_anc.bin";
+
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < sizeof(struct anc_header)) {
+ dev_err(codec->dev, "Not enough data\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ /* First number is the number of register writes */
+ anc_head = (struct anc_header *)(fw->data);
+ anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
+ anc_size_remaining = fw->size - sizeof(struct anc_header);
+ num_anc_slots = anc_head->num_anc_slots;
+
+ if (taiko->anc_slot >= num_anc_slots) {
+ dev_err(codec->dev, "Invalid ANC slot selected\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_anc_slots; i++) {
+
+ if (anc_size_remaining < TAIKO_PACKED_REG_SIZE) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -EINVAL;
+ }
+ anc_writes_size = (u32)(*anc_ptr);
+ anc_size_remaining -= sizeof(u32);
+ anc_ptr += 1;
+
+ if (anc_writes_size * TAIKO_PACKED_REG_SIZE
+ > anc_size_remaining) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ if (taiko->anc_slot == i)
+ break;
+
+ anc_size_remaining -= (anc_writes_size *
+ TAIKO_PACKED_REG_SIZE);
+ anc_ptr += anc_writes_size;
+ }
+ if (i == num_anc_slots) {
+ dev_err(codec->dev, "Selected ANC slot not present\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < anc_writes_size; i++) {
+ TAIKO_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
+ mask, val);
+ old_val = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, (old_val & ~mask) |
+ (val & mask));
+ }
+ release_firmware(fw);
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, TAIKO_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
+ break;
+ }
+ return 0;
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_codec_start_hs_polling(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ int mbhc_state = taiko->mbhc_state;
+
+ pr_debug("%s: enter\n", __func__);
+ if (!taiko->mbhc_polling_active) {
+ pr_debug("Polling is not active, do not start polling\n");
+ return;
+ }
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x84);
+
+ if (!taiko->no_mic_headset_override) {
+ if (mbhc_state == MBHC_STATE_POTENTIAL) {
+ pr_debug("%s recovering MBHC state macine\n", __func__);
+ taiko->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
+ /* set to max button press threshold */
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B2_CTL,
+ 0x7F);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B1_CTL,
+ 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B4_CTL,
+ 0x7F);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B3_CTL,
+ 0xFF);
+ /* set to max */
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B6_CTL,
+ 0x7F);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B5_CTL,
+ 0xFF);
+ }
+ }
+
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x1);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x1);
+ pr_debug("%s: leave\n", __func__);
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_codec_pause_hs_polling(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: enter\n", __func__);
+ if (!taiko->mbhc_polling_active) {
+ pr_debug("polling not active, nothing to pause\n");
+ return;
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ pr_debug("%s: leave\n", __func__);
+}
+
+static void taiko_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u8 reg_mode_val, cur_mode_val;
+ bool mbhc_was_polling = false;
+
+ if (mode)
+ reg_mode_val = TAIKO_CFILT_FAST_MODE;
+ else
+ reg_mode_val = TAIKO_CFILT_SLOW_MODE;
+
+ cur_mode_val = snd_soc_read(codec,
+ taiko->mbhc_bias_regs.cfilt_ctl) & 0x40;
+
+ if (cur_mode_val != reg_mode_val) {
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ if (taiko->mbhc_polling_active) {
+ taiko_codec_pause_hs_polling(codec);
+ mbhc_was_polling = true;
+ }
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
+ if (mbhc_was_polling)
+ taiko_codec_start_hs_polling(codec);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
+ cur_mode_val, reg_mode_val);
+ } else {
+ pr_debug("%s: CFILT Value is already %x\n",
+ __func__, cur_mode_val);
+ }
+}
+
+static void taiko_codec_update_cfilt_usage(struct snd_soc_codec *codec,
+ u8 cfilt_sel, int inc)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u32 *cfilt_cnt_ptr = NULL;
+ u16 micb_cfilt_reg;
+
+ switch (cfilt_sel) {
+ case TAIKO_CFILT1_SEL:
+ cfilt_cnt_ptr = &taiko->cfilt1_cnt;
+ micb_cfilt_reg = TAIKO_A_MICB_CFILT_1_CTL;
+ break;
+ case TAIKO_CFILT2_SEL:
+ cfilt_cnt_ptr = &taiko->cfilt2_cnt;
+ micb_cfilt_reg = TAIKO_A_MICB_CFILT_2_CTL;
+ break;
+ case TAIKO_CFILT3_SEL:
+ cfilt_cnt_ptr = &taiko->cfilt3_cnt;
+ micb_cfilt_reg = TAIKO_A_MICB_CFILT_3_CTL;
+ break;
+ default:
+ return; /* should not happen */
+ }
+
+ if (inc) {
+ if (!(*cfilt_cnt_ptr)++) {
+ /* Switch CFILT to slow mode if MBHC CFILT being used */
+ if (cfilt_sel == taiko->mbhc_bias_regs.cfilt_sel)
+ taiko_codec_switch_cfilt_mode(codec, 0);
+
+ snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
+ }
+ } else {
+ /* check if count not zero, decrement
+ * then check if zero, go ahead disable cfilter
+ */
+ if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
+ snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
+
+ /* Switch CFILT to fast mode if MBHC CFILT being used */
+ if (cfilt_sel == taiko->mbhc_bias_regs.cfilt_sel)
+ taiko_codec_switch_cfilt_mode(codec, 1);
+ }
+ }
+}
+
+static int taiko_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
+{
+ int rc = -EINVAL;
+ unsigned min_mv, max_mv;
+
+ switch (ldoh_v) {
+ case TAIKO_LDOH_1P95_V:
+ min_mv = 160;
+ max_mv = 1800;
+ break;
+ case TAIKO_LDOH_2P35_V:
+ min_mv = 200;
+ max_mv = 2200;
+ break;
+ case TAIKO_LDOH_2P75_V:
+ min_mv = 240;
+ max_mv = 2600;
+ break;
+ case TAIKO_LDOH_2P85_V:
+ min_mv = 250;
+ max_mv = 2700;
+ break;
+ default:
+ goto done;
+ }
+
+ if (cfilt_mv < min_mv || cfilt_mv > max_mv)
+ goto done;
+
+ for (rc = 4; rc <= 44; rc++) {
+ min_mv = max_mv * (rc) / 44;
+ if (min_mv >= cfilt_mv) {
+ rc -= 4;
+ break;
+ }
+ }
+done:
+ return rc;
+}
+
+static bool taiko_is_hph_pa_on(struct snd_soc_codec *codec)
+{
+ u8 hph_reg_val = 0;
+ hph_reg_val = snd_soc_read(codec, TAIKO_A_RX_HPH_CNP_EN);
+
+ return (hph_reg_val & 0x30) ? true : false;
+}
+
+static bool taiko_is_hph_dac_on(struct snd_soc_codec *codec, int left)
+{
+ u8 hph_reg_val = 0;
+ if (left)
+ hph_reg_val = snd_soc_read(codec,
+ TAIKO_A_RX_HPH_L_DAC_CTL);
+ else
+ hph_reg_val = snd_soc_read(codec,
+ TAIKO_A_RX_HPH_R_DAC_CTL);
+
+ return (hph_reg_val & 0xC0) ? true : false;
+}
+
+static void taiko_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+{
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_codec_drive_v_to_micbias(struct snd_soc_codec *codec,
+ int usec)
+{
+ int cfilt_k_val;
+ bool set = true;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ if (taiko->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
+ taiko->mbhc_micbias_switched) {
+ pr_debug("%s: set mic V to micbias V\n", __func__);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+ taiko_turn_onoff_override(codec, true);
+ while (1) {
+ cfilt_k_val = taiko_find_k_value(
+ taiko->pdata->micbias.ldoh_v,
+ set ? taiko->mbhc_data.micb_mv :
+ VDDIO_MICBIAS_MV);
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.cfilt_val,
+ 0xFC, (cfilt_k_val << 2));
+ if (!set)
+ break;
+ usleep_range(usec, usec);
+ set = false;
+ }
+ taiko_turn_onoff_override(codec, false);
+ }
+}
+
+/* called under codec_resource_lock acquisition */
+static void __taiko_codec_switch_micbias(struct snd_soc_codec *codec,
+ int vddio_switch, bool restartpolling,
+ bool checkpolling)
+{
+ int cfilt_k_val;
+ bool override;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ if (vddio_switch && !taiko->mbhc_micbias_switched &&
+ (!checkpolling || taiko->mbhc_polling_active)) {
+ if (restartpolling)
+ taiko_codec_pause_hs_polling(codec);
+ override = snd_soc_read(codec, TAIKO_A_CDC_MBHC_B1_CTL) & 0x04;
+ if (!override)
+ taiko_turn_onoff_override(codec, true);
+ /* Adjust threshold if Mic Bias voltage changes */
+ if (taiko->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+ cfilt_k_val = taiko_find_k_value(
+ taiko->pdata->micbias.ldoh_v,
+ VDDIO_MICBIAS_MV);
+ usleep_range(10000, 10000);
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.cfilt_val,
+ 0xFC, (cfilt_k_val << 2));
+ usleep_range(10000, 10000);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B1_CTL,
+ taiko->mbhc_data.adj_v_ins_hu & 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B2_CTL,
+ (taiko->mbhc_data.adj_v_ins_hu >> 8) &
+ 0xFF);
+ pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
+ __func__);
+ }
+
+ /* enable MIC BIAS Switch to VDDIO */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x00);
+ if (!override)
+ taiko_turn_onoff_override(codec, false);
+ if (restartpolling)
+ taiko_codec_start_hs_polling(codec);
+
+ taiko->mbhc_micbias_switched = true;
+ pr_debug("%s: VDDIO switch enabled\n", __func__);
+ } else if (!vddio_switch && taiko->mbhc_micbias_switched) {
+ if ((!checkpolling || taiko->mbhc_polling_active) &&
+ restartpolling)
+ taiko_codec_pause_hs_polling(codec);
+ /* Reprogram thresholds */
+ if (taiko->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+ cfilt_k_val = taiko_find_k_value(
+ taiko->pdata->micbias.ldoh_v,
+ taiko->mbhc_data.micb_mv);
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.cfilt_val,
+ 0xFC, (cfilt_k_val << 2));
+ usleep_range(10000, 10000);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B1_CTL,
+ taiko->mbhc_data.v_ins_hu & 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B2_CTL,
+ (taiko->mbhc_data.v_ins_hu >> 8) & 0xFF);
+ pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
+ __func__);
+ }
+
+ /* Disable MIC BIAS Switch to VDDIO */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x00);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x00);
+
+ if ((!checkpolling || taiko->mbhc_polling_active) &&
+ restartpolling)
+ taiko_codec_start_hs_polling(codec);
+
+ taiko->mbhc_micbias_switched = false;
+ pr_debug("%s: VDDIO switch disabled\n", __func__);
+ }
+}
+
+static void taiko_codec_switch_micbias(struct snd_soc_codec *codec,
+ int vddio_switch)
+{
+ return __taiko_codec_switch_micbias(codec, vddio_switch, true, true);
+}
+
+static int taiko_codec_enable_micbias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u16 micb_int_reg;
+ int micb_line;
+ u8 cfilt_sel_val = 0;
+ char *internal1_text = "Internal1";
+ char *internal2_text = "Internal2";
+ char *internal3_text = "Internal3";
+
+ pr_debug("%s %d\n", __func__, event);
+ switch (w->reg) {
+ case TAIKO_A_MICB_1_CTL:
+ micb_int_reg = TAIKO_A_MICB_1_INT_RBIAS;
+ cfilt_sel_val = taiko->pdata->micbias.bias1_cfilt_sel;
+ micb_line = TAIKO_MICBIAS1;
+ break;
+ case TAIKO_A_MICB_2_CTL:
+ micb_int_reg = TAIKO_A_MICB_2_INT_RBIAS;
+ cfilt_sel_val = taiko->pdata->micbias.bias2_cfilt_sel;
+ micb_line = TAIKO_MICBIAS2;
+ break;
+ case TAIKO_A_MICB_3_CTL:
+ micb_int_reg = TAIKO_A_MICB_3_INT_RBIAS;
+ cfilt_sel_val = taiko->pdata->micbias.bias3_cfilt_sel;
+ micb_line = TAIKO_MICBIAS3;
+ break;
+ case TAIKO_A_MICB_4_CTL:
+ micb_int_reg = taiko->reg_addr.micb_4_int_rbias;
+ cfilt_sel_val = taiko->pdata->micbias.bias4_cfilt_sel;
+ micb_line = TAIKO_MICBIAS4;
+ break;
+ default:
+ pr_err("%s: Error, invalid micbias register\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Decide whether to switch the micbias for MBHC */
+ if (w->reg == taiko->mbhc_bias_regs.ctl_reg) {
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ taiko_codec_switch_micbias(codec, 0);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ }
+
+ snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
+ taiko_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
+
+ if (strnstr(w->name, internal1_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+ else if (strnstr(w->name, internal2_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+ else if (strnstr(w->name, internal3_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+
+ usleep_range(20000, 20000);
+
+ if (taiko->mbhc_polling_active &&
+ taiko->mbhc_cfg.micbias == micb_line) {
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ taiko_codec_pause_hs_polling(codec);
+ taiko_codec_start_hs_polling(codec);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ if ((w->reg == taiko->mbhc_bias_regs.ctl_reg) &&
+ taiko_is_hph_pa_on(codec)) {
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ taiko_codec_switch_micbias(codec, 1);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ }
+
+ if (strnstr(w->name, internal1_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
+ else if (strnstr(w->name, internal2_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
+ else if (strnstr(w->name, internal3_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
+
+ taiko_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
+ break;
+ }
+
+ return 0;
+}
+
+
+static void tx_hpf_corner_freq_callback(struct work_struct *work)
+{
+ struct delayed_work *hpf_delayed_work;
+ struct hpf_work *hpf_work;
+ struct taiko_priv *taiko;
+ struct snd_soc_codec *codec;
+ u16 tx_mux_ctl_reg;
+ u8 hpf_cut_of_freq;
+
+ hpf_delayed_work = to_delayed_work(work);
+ hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
+ taiko = hpf_work->taiko;
+ codec = hpf_work->taiko->codec;
+ hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
+
+ tx_mux_ctl_reg = TAIKO_A_CDC_TX1_MUX_CTL +
+ (hpf_work->decimator - 1) * 8;
+
+ pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
+ hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
+}
+
+#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
+#define CF_MIN_3DB_4HZ 0x0
+#define CF_MIN_3DB_75HZ 0x1
+#define CF_MIN_3DB_150HZ 0x2
+
+static int taiko_codec_enable_dec(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ unsigned int decimator;
+ char *dec_name = NULL;
+ char *widget_name = NULL;
+ char *temp;
+ int ret = 0;
+ u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
+ u8 dec_hpf_cut_of_freq;
+ int offset;
+
+
+ pr_debug("%s %d\n", __func__, event);
+
+ widget_name = kstrndup(w->name, 15, GFP_KERNEL);
+ if (!widget_name)
+ return -ENOMEM;
+ temp = widget_name;
+
+ dec_name = strsep(&widget_name, " ");
+ widget_name = temp;
+ if (!dec_name) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
+ if (ret < 0) {
+ pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
+ w->name, dec_name, decimator);
+
+ if (w->reg == TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
+ dec_reset_reg = TAIKO_A_CDC_CLK_TX_RESET_B1_CTL;
+ offset = 0;
+ } else if (w->reg == TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
+ dec_reset_reg = TAIKO_A_CDC_CLK_TX_RESET_B2_CTL;
+ offset = 8;
+ } else {
+ pr_err("%s: Error, incorrect dec\n", __func__);
+ return -EINVAL;
+ }
+
+ tx_vol_ctl_reg = TAIKO_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
+ tx_mux_ctl_reg = TAIKO_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ /* Enableable TX digital mute */
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+
+ snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
+ 1 << w->shift);
+ snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
+
+ dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
+
+ dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
+
+ tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
+ dec_hpf_cut_of_freq;
+
+ if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
+
+ /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+ CF_MIN_3DB_150HZ << 4);
+ }
+
+ /* enable HPF */
+ snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
+
+ break;
+
+ case SND_SOC_DAPM_POST_PMU:
+
+ /* Disable TX digital mute */
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
+
+ if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
+ CF_MIN_3DB_150HZ) {
+
+ schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
+ msecs_to_jiffies(300));
+ }
+ /* apply the digital gain after the decimator is enabled*/
+ if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+ snd_soc_write(codec,
+ tx_digital_gain_reg[w->shift + offset],
+ snd_soc_read(codec,
+ tx_digital_gain_reg[w->shift + offset])
+ );
+
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+
+ snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
+ cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
+ snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
+ (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
+
+ break;
+ }
+out:
+ kfree(widget_name);
+ return ret;
+}
+
+static int taiko_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %d %s\n", __func__, event, w->name);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_RESET_CTL,
+ 1 << w->shift, 1 << w->shift);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_RESET_CTL,
+ 1 << w->shift, 0x0);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* apply the digital gain after the interpolator is enabled*/
+ if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
+ snd_soc_write(codec,
+ rx_digital_gain_reg[w->shift],
+ snd_soc_read(codec,
+ rx_digital_gain_reg[w->shift])
+ );
+ break;
+ }
+ return 0;
+}
+
+static int taiko_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(1000, 1000);
+ break;
+ }
+ return 0;
+}
+
+static int taiko_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ taiko_enable_rx_bias(codec, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ taiko_enable_rx_bias(codec, 0);
+ break;
+ }
+ return 0;
+}
+static int taiko_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static void taiko_snd_soc_jack_report(struct taiko_priv *taiko,
+ struct snd_soc_jack *jack, int status,
+ int mask)
+{
+ /* XXX: wake_lock_timeout()? */
+ snd_soc_jack_report_no_dapm(jack, status, mask);
+}
+
+static void hphocp_off_report(struct taiko_priv *taiko,
+ u32 jack_status, int irq)
+{
+ struct snd_soc_codec *codec;
+ if (!taiko) {
+ pr_err("%s: Bad taiko private data\n", __func__);
+ return;
+ }
+
+ pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
+ codec = taiko->codec;
+ if (taiko->hph_status & jack_status) {
+ taiko->hph_status &= ~jack_status;
+ if (taiko->mbhc_cfg.headset_jack)
+ taiko_snd_soc_jack_report(taiko,
+ taiko->mbhc_cfg.headset_jack,
+ taiko->hph_status,
+ TAIKO_JACK_MASK);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10, 0x10);
+ /* reset retry counter as PA is turned off signifying
+ * start of new OCP detection session
+ */
+ if (TAIKO_IRQ_HPH_PA_OCPL_FAULT)
+ taiko->hphlocp_cnt = 0;
+ else
+ taiko->hphrocp_cnt = 0;
+ wcd9xxx_enable_irq(codec->control_data, irq);
+ }
+}
+
+static void hphlocp_off_report(struct work_struct *work)
+{
+ struct taiko_priv *taiko = container_of(work, struct taiko_priv,
+ hphlocp_work);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHL, TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+}
+
+static void hphrocp_off_report(struct work_struct *work)
+{
+ struct taiko_priv *taiko = container_of(work, struct taiko_priv,
+ hphrocp_work);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHR, TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+}
+
+static int taiko_hph_pa_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u8 mbhc_micb_ctl_val;
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ mbhc_micb_ctl_val = snd_soc_read(codec,
+ taiko->mbhc_bias_regs.ctl_reg);
+
+ if (!(mbhc_micb_ctl_val & 0x80)) {
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ taiko_codec_switch_micbias(codec, 1);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ }
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ /* schedule work is required because at the time HPH PA DAPM
+ * event callback is called by DAPM framework, CODEC dapm mutex
+ * would have been locked while snd_soc_jack_report also
+ * attempts to acquire same lock.
+ */
+ if (w->shift == 5) {
+ clear_bit(TAIKO_HPHL_PA_OFF_ACK,
+ &taiko->hph_pa_dac_state);
+ clear_bit(TAIKO_HPHL_DAC_OFF_ACK,
+ &taiko->hph_pa_dac_state);
+ if (taiko->hph_status & SND_JACK_OC_HPHL)
+ schedule_work(&taiko->hphlocp_work);
+ } else if (w->shift == 4) {
+ clear_bit(TAIKO_HPHR_PA_OFF_ACK,
+ &taiko->hph_pa_dac_state);
+ clear_bit(TAIKO_HPHR_DAC_OFF_ACK,
+ &taiko->hph_pa_dac_state);
+ if (taiko->hph_status & SND_JACK_OC_HPHR)
+ schedule_work(&taiko->hphrocp_work);
+ }
+
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ taiko_codec_switch_micbias(codec, 0);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+
+ pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
+ w->name);
+ usleep_range(10000, 10000);
+ break;
+ }
+ return 0;
+}
+
+static void taiko_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
+ struct mbhc_micbias_regs *micbias_regs)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ unsigned int cfilt;
+
+ switch (taiko->mbhc_cfg.micbias) {
+ case TAIKO_MICBIAS1:
+ cfilt = taiko->pdata->micbias.bias1_cfilt_sel;
+ micbias_regs->mbhc_reg = TAIKO_A_MICB_1_MBHC;
+ micbias_regs->int_rbias = TAIKO_A_MICB_1_INT_RBIAS;
+ micbias_regs->ctl_reg = TAIKO_A_MICB_1_CTL;
+ break;
+ case TAIKO_MICBIAS2:
+ cfilt = taiko->pdata->micbias.bias2_cfilt_sel;
+ micbias_regs->mbhc_reg = TAIKO_A_MICB_2_MBHC;
+ micbias_regs->int_rbias = TAIKO_A_MICB_2_INT_RBIAS;
+ micbias_regs->ctl_reg = TAIKO_A_MICB_2_CTL;
+ break;
+ case TAIKO_MICBIAS3:
+ cfilt = taiko->pdata->micbias.bias3_cfilt_sel;
+ micbias_regs->mbhc_reg = TAIKO_A_MICB_3_MBHC;
+ micbias_regs->int_rbias = TAIKO_A_MICB_3_INT_RBIAS;
+ micbias_regs->ctl_reg = TAIKO_A_MICB_3_CTL;
+ break;
+ case TAIKO_MICBIAS4:
+ cfilt = taiko->pdata->micbias.bias4_cfilt_sel;
+ micbias_regs->mbhc_reg = taiko->reg_addr.micb_4_mbhc;
+ micbias_regs->int_rbias = taiko->reg_addr.micb_4_int_rbias;
+ micbias_regs->ctl_reg = taiko->reg_addr.micb_4_ctl;
+ break;
+ default:
+ /* Should never reach here */
+ pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
+ return;
+ }
+
+ micbias_regs->cfilt_sel = cfilt;
+
+ switch (cfilt) {
+ case TAIKO_CFILT1_SEL:
+ micbias_regs->cfilt_val = TAIKO_A_MICB_CFILT_1_VAL;
+ micbias_regs->cfilt_ctl = TAIKO_A_MICB_CFILT_1_CTL;
+ taiko->mbhc_data.micb_mv = taiko->pdata->micbias.cfilt1_mv;
+ break;
+ case TAIKO_CFILT2_SEL:
+ micbias_regs->cfilt_val = TAIKO_A_MICB_CFILT_2_VAL;
+ micbias_regs->cfilt_ctl = TAIKO_A_MICB_CFILT_2_CTL;
+ taiko->mbhc_data.micb_mv = taiko->pdata->micbias.cfilt2_mv;
+ break;
+ case TAIKO_CFILT3_SEL:
+ micbias_regs->cfilt_val = TAIKO_A_MICB_CFILT_3_VAL;
+ micbias_regs->cfilt_ctl = TAIKO_A_MICB_CFILT_3_CTL;
+ taiko->mbhc_data.micb_mv = taiko->pdata->micbias.cfilt3_mv;
+ break;
+ }
+}
+static const struct snd_soc_dapm_widget taiko_dapm_i2s_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TAIKO_A_CDC_CLK_RX_I2S_CTL,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TAIKO_A_CDC_CLK_TX_I2S_CTL, 4,
+ 0, NULL, 0),
+};
+
+static int taiko_lineout_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
+ break;
+
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
+ break;
+ }
+ return 0;
+}
+
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+ {"RX_I2S_CLK", NULL, "CDC_CONN"},
+ {"SLIM RX1", NULL, "RX_I2S_CLK"},
+ {"SLIM RX2", NULL, "RX_I2S_CLK"},
+ {"SLIM RX3", NULL, "RX_I2S_CLK"},
+ {"SLIM RX4", NULL, "RX_I2S_CLK"},
+
+ {"SLIM TX7", NULL, "TX_I2S_CLK"},
+ {"SLIM TX8", NULL, "TX_I2S_CLK"},
+ {"SLIM TX9", NULL, "TX_I2S_CLK"},
+ {"SLIM TX10", NULL, "TX_I2S_CLK"},
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* SLIMBUS Connections */
+
+ {"SLIM TX1", NULL, "SLIM TX1 MUX"},
+ {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
+
+ {"SLIM TX2", NULL, "SLIM TX2 MUX"},
+ {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
+
+ {"SLIM TX3", NULL, "SLIM TX3 MUX"},
+ {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
+ {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
+ {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
+ {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
+ {"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
+ {"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
+ {"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
+
+ {"SLIM TX4", NULL, "SLIM TX4 MUX"},
+ {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
+
+ {"SLIM TX5", NULL, "SLIM TX5 MUX"},
+ {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
+ {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
+ {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
+ {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
+ {"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
+ {"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
+ {"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
+
+ {"SLIM TX6", NULL, "SLIM TX6 MUX"},
+ {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
+
+ {"SLIM TX7", NULL, "SLIM TX7 MUX"},
+ {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
+ {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
+ {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
+ {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
+ {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
+ {"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
+ {"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
+ {"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
+ {"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
+ {"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
+ {"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
+ {"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
+
+ {"SLIM TX8", NULL, "SLIM TX8 MUX"},
+ {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
+ {"SLIM TX8 MUX", "DEC7", "DEC7 MUX"},
+ {"SLIM TX8 MUX", "DEC8", "DEC8 MUX"},
+ {"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
+ {"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
+
+ {"SLIM TX9", NULL, "SLIM TX9 MUX"},
+ {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
+ {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
+ {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
+ {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
+ {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
+
+ {"SLIM TX10", NULL, "SLIM TX10 MUX"},
+ {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
+ {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
+ {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
+ {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
+ {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
+ {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
+ {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
+ {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
+ {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
+ {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
+
+ /* Earpiece (RX MIX1) */
+ {"EAR", NULL, "EAR PA"},
+ {"EAR PA", NULL, "EAR_PA_MIXER"},
+ {"EAR_PA_MIXER", NULL, "DAC1"},
+ {"DAC1", NULL, "CP"},
+
+ {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
+ {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
+ {"ANC", NULL, "ANC1 FB MUX"},
+
+ /* Headset (RX MIX1 and RX MIX2) */
+ {"HEADPHONE", NULL, "HPHL"},
+ {"HEADPHONE", NULL, "HPHR"},
+
+ {"HPHL", NULL, "HPHL_PA_MIXER"},
+ {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
+
+ {"HPHR", NULL, "HPHR_PA_MIXER"},
+ {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
+
+ {"HPHL DAC", NULL, "CP"},
+ {"HPHR DAC", NULL, "CP"},
+
+ {"ANC", NULL, "ANC1 MUX"},
+ {"ANC", NULL, "ANC2 MUX"},
+ {"ANC1 MUX", "ADC1", "ADC1"},
+ {"ANC1 MUX", "ADC2", "ADC2"},
+ {"ANC1 MUX", "ADC3", "ADC3"},
+ {"ANC1 MUX", "ADC4", "ADC4"},
+ {"ANC2 MUX", "ADC1", "ADC1"},
+ {"ANC2 MUX", "ADC2", "ADC2"},
+ {"ANC2 MUX", "ADC3", "ADC3"},
+ {"ANC2 MUX", "ADC4", "ADC4"},
+
+ {"ANC", NULL, "CDC_CONN"},
+
+ {"DAC1", "Switch", "RX1 CHAIN"},
+ {"HPHL DAC", "Switch", "RX1 CHAIN"},
+ {"HPHR DAC", NULL, "RX2 CHAIN"},
+
+ {"LINEOUT1", NULL, "LINEOUT1 PA"},
+ {"LINEOUT2", NULL, "LINEOUT2 PA"},
+ {"LINEOUT3", NULL, "LINEOUT3 PA"},
+ {"LINEOUT4", NULL, "LINEOUT4 PA"},
+
+ {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
+ {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
+ {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
+ {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
+ {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
+ {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
+ {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
+ {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
+
+ {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
+
+ {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
+ {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
+ {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
+
+ {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
+
+ {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
+ {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
+ {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
+
+ {"RX1 CHAIN", NULL, "RX1 MIX2"},
+ {"RX2 CHAIN", NULL, "RX2 MIX2"},
+ {"RX1 CHAIN", NULL, "ANC"},
+ {"RX2 CHAIN", NULL, "ANC"},
+
+ {"CP", NULL, "RX_BIAS"},
+ {"LINEOUT1 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT2 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT3 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT4 DAC", NULL, "RX_BIAS"},
+
+ {"RX1 MIX1", NULL, "COMP1_CLK"},
+ {"RX2 MIX1", NULL, "COMP1_CLK"},
+ {"RX3 MIX1", NULL, "COMP2_CLK"},
+ {"RX5 MIX1", NULL, "COMP2_CLK"},
+
+
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
+ {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
+ {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
+ {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
+ {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
+ {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
+ {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
+ {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
+ {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
+ {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
+ {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
+ {"RX1 MIX2", NULL, "RX1 MIX1"},
+ {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
+ {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
+ {"RX2 MIX2", NULL, "RX2 MIX1"},
+ {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
+ {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
+ {"RX7 MIX2", NULL, "RX7 MIX1"},
+ {"RX7 MIX2", NULL, "RX7 MIX2 INP1"},
+ {"RX7 MIX2", NULL, "RX7 MIX2 INP2"},
+
+ {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
+ {"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
+ {"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
+ {"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
+ {"RX1 MIX1 INP3", "RX6", "SLIM RX6"},
+ {"RX1 MIX1 INP3", "RX7", "SLIM RX7"},
+ {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX2 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX2 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX3 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX3 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX4 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX4 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX5 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX5 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX5 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX5 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX6 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX6 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX6 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX6 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX7 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX7 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX7 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX7 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX1 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX2 INP2", "IIR1", "IIR1"},
+ {"RX2 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX2 MIX2 INP2", "IIR1", "IIR1"},
+ {"RX7 MIX2 INP1", "IIR1", "IIR1"},
+ {"RX7 MIX2 INP2", "IIR1", "IIR1"},
+
+ /* Decimator Inputs */
+ {"DEC1 MUX", "DMIC1", "DMIC1"},
+ {"DEC1 MUX", "ADC6", "ADC6"},
+ {"DEC1 MUX", NULL, "CDC_CONN"},
+ {"DEC2 MUX", "DMIC2", "DMIC2"},
+ {"DEC2 MUX", "ADC5", "ADC5"},
+ {"DEC2 MUX", NULL, "CDC_CONN"},
+ {"DEC3 MUX", "DMIC3", "DMIC3"},
+ {"DEC3 MUX", "ADC4", "ADC4"},
+ {"DEC3 MUX", NULL, "CDC_CONN"},
+ {"DEC4 MUX", "DMIC4", "DMIC4"},
+ {"DEC4 MUX", "ADC3", "ADC3"},
+ {"DEC4 MUX", NULL, "CDC_CONN"},
+ {"DEC5 MUX", "DMIC5", "DMIC5"},
+ {"DEC5 MUX", "ADC2", "ADC2"},
+ {"DEC5 MUX", NULL, "CDC_CONN"},
+ {"DEC6 MUX", "DMIC6", "DMIC6"},
+ {"DEC6 MUX", "ADC1", "ADC1"},
+ {"DEC6 MUX", NULL, "CDC_CONN"},
+ {"DEC7 MUX", "DMIC1", "DMIC1"},
+ {"DEC7 MUX", "DMIC6", "DMIC6"},
+ {"DEC7 MUX", "ADC1", "ADC1"},
+ {"DEC7 MUX", "ADC6", "ADC6"},
+ {"DEC7 MUX", NULL, "CDC_CONN"},
+ {"DEC8 MUX", "DMIC2", "DMIC2"},
+ {"DEC8 MUX", "DMIC5", "DMIC5"},
+ {"DEC8 MUX", "ADC2", "ADC2"},
+ {"DEC8 MUX", "ADC5", "ADC5"},
+ {"DEC8 MUX", NULL, "CDC_CONN"},
+ {"DEC9 MUX", "DMIC4", "DMIC4"},
+ {"DEC9 MUX", "DMIC5", "DMIC5"},
+ {"DEC9 MUX", "ADC2", "ADC2"},
+ {"DEC9 MUX", "ADC3", "ADC3"},
+ {"DEC9 MUX", NULL, "CDC_CONN"},
+ {"DEC10 MUX", "DMIC3", "DMIC3"},
+ {"DEC10 MUX", "DMIC6", "DMIC6"},
+ {"DEC10 MUX", "ADC1", "ADC1"},
+ {"DEC10 MUX", "ADC4", "ADC4"},
+ {"DEC10 MUX", NULL, "CDC_CONN"},
+
+ /* ADC Connections */
+ {"ADC1", NULL, "AMIC1"},
+ {"ADC2", NULL, "AMIC2"},
+ {"ADC3", NULL, "AMIC3"},
+ {"ADC4", NULL, "AMIC4"},
+ {"ADC5", NULL, "AMIC5"},
+ {"ADC6", NULL, "AMIC6"},
+
+ /* AUX PGA Connections */
+ {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+ {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+ {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+ {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+ {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+ {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+ {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+ {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+ {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+ {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+ {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+ {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+ {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+ {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+ {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+ {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+ {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+ {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+ {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+ {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+ {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+ {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+ {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+ {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+ {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
+ {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
+ {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
+ {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
+ {"AUX_PGA_Left", NULL, "AMIC5"},
+ {"AUX_PGA_Right", NULL, "AMIC6"},
+
+
+ {"IIR1", NULL, "IIR1 INP1 MUX"},
+ {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
+ {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
+ {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
+ {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
+ {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
+ {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
+ {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
+ {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
+ {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
+ {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
+
+ {"MIC BIAS1 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS1 Internal2", NULL, "LDO_H"},
+ {"MIC BIAS1 External", NULL, "LDO_H"},
+ {"MIC BIAS2 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS2 Internal2", NULL, "LDO_H"},
+ {"MIC BIAS2 Internal3", NULL, "LDO_H"},
+ {"MIC BIAS2 External", NULL, "LDO_H"},
+ {"MIC BIAS3 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS3 Internal2", NULL, "LDO_H"},
+ {"MIC BIAS3 External", NULL, "LDO_H"},
+ {"MIC BIAS4 External", NULL, "LDO_H"},
+};
+
+static int taiko_readable(struct snd_soc_codec *ssc, unsigned int reg)
+{
+ return taiko_reg_readable[reg];
+}
+
+static bool taiko_is_digital_gain_register(unsigned int reg)
+{
+ bool rtn = false;
+ switch (reg) {
+ case TAIKO_A_CDC_RX1_VOL_CTL_B2_CTL:
+ case TAIKO_A_CDC_RX2_VOL_CTL_B2_CTL:
+ case TAIKO_A_CDC_RX3_VOL_CTL_B2_CTL:
+ case TAIKO_A_CDC_RX4_VOL_CTL_B2_CTL:
+ case TAIKO_A_CDC_RX5_VOL_CTL_B2_CTL:
+ case TAIKO_A_CDC_RX6_VOL_CTL_B2_CTL:
+ case TAIKO_A_CDC_RX7_VOL_CTL_B2_CTL:
+ case TAIKO_A_CDC_TX1_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX2_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX3_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX4_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX5_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX6_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX7_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX8_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX9_VOL_CTL_GAIN:
+ case TAIKO_A_CDC_TX10_VOL_CTL_GAIN:
+ rtn = true;
+ break;
+ default:
+ break;
+ }
+ return rtn;
+}
+
+static int taiko_volatile(struct snd_soc_codec *ssc, unsigned int reg)
+{
+ /* Registers lower than 0x100 are top level registers which can be
+ * written by the Taiko core driver.
+ */
+
+ if ((reg >= TAIKO_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
+ return 1;
+
+ /* IIR Coeff registers are not cacheable */
+ if ((reg >= TAIKO_A_CDC_IIR1_COEF_B1_CTL) &&
+ (reg <= TAIKO_A_CDC_IIR2_COEF_B2_CTL))
+ return 1;
+
+ /* Digital gain register is not cacheable so we have to write
+ * the setting even it is the same
+ */
+ if (taiko_is_digital_gain_register(reg))
+ return 1;
+
+ /* HPH status registers */
+ if (reg == TAIKO_A_RX_HPH_L_STATUS || reg == TAIKO_A_RX_HPH_R_STATUS)
+ return 1;
+
+ return 0;
+}
+
+#define TAIKO_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+static int taiko_write(struct snd_soc_codec *codec, unsigned int reg,
+ unsigned int value)
+{
+ int ret;
+ BUG_ON(reg > TAIKO_MAX_REGISTER);
+
+ if (!taiko_volatile(codec, reg)) {
+ ret = snd_soc_cache_write(codec, reg, value);
+ if (ret != 0)
+ dev_err(codec->dev, "Cache write to %x failed: %d\n",
+ reg, ret);
+ }
+
+ return wcd9xxx_reg_write(codec->control_data, reg, value);
+}
+static unsigned int taiko_read(struct snd_soc_codec *codec,
+ unsigned int reg)
+{
+ unsigned int val;
+ int ret;
+
+ BUG_ON(reg > TAIKO_MAX_REGISTER);
+
+ if (!taiko_volatile(codec, reg) && taiko_readable(codec, reg) &&
+ reg < codec->driver->reg_cache_size) {
+ ret = snd_soc_cache_read(codec, reg, &val);
+ if (ret >= 0) {
+ return val;
+ } else
+ dev_err(codec->dev, "Cache read from %x failed: %d\n",
+ reg, ret);
+ }
+
+ val = wcd9xxx_reg_read(codec->control_data, reg);
+ return val;
+}
+
+static s16 taiko_get_current_v_ins(struct taiko_priv *taiko, bool hu)
+{
+ s16 v_ins;
+ if ((taiko->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
+ taiko->mbhc_micbias_switched)
+ v_ins = hu ? (s16)taiko->mbhc_data.adj_v_ins_hu :
+ (s16)taiko->mbhc_data.adj_v_ins_h;
+ else
+ v_ins = hu ? (s16)taiko->mbhc_data.v_ins_hu :
+ (s16)taiko->mbhc_data.v_ins_h;
+ return v_ins;
+}
+
+static s16 taiko_get_current_v_hs_max(struct taiko_priv *taiko)
+{
+ s16 v_hs_max;
+ struct taiko_mbhc_plug_type_cfg *plug_type;
+
+ plug_type = TAIKO_MBHC_CAL_PLUG_TYPE_PTR(taiko->mbhc_cfg.calibration);
+ if ((taiko->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
+ taiko->mbhc_micbias_switched)
+ v_hs_max = taiko->mbhc_data.adj_v_hs_max;
+ else
+ v_hs_max = plug_type->v_hs_max;
+ return v_hs_max;
+}
+
+static void taiko_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
+{
+ u8 *n_ready, *n_cic;
+ struct taiko_mbhc_btn_detect_cfg *btn_det;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ const s16 v_ins_hu = taiko_get_current_v_ins(taiko, true);
+
+ btn_det = TAIKO_MBHC_CAL_BTN_DET_PTR(taiko->mbhc_cfg.calibration);
+
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B1_CTL,
+ v_ins_hu & 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B2_CTL,
+ (v_ins_hu >> 8) & 0xFF);
+
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B3_CTL,
+ taiko->mbhc_data.v_b1_hu & 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B4_CTL,
+ (taiko->mbhc_data.v_b1_hu >> 8) & 0xFF);
+
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B5_CTL,
+ taiko->mbhc_data.v_b1_h & 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B6_CTL,
+ (taiko->mbhc_data.v_b1_h >> 8) & 0xFF);
+
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B9_CTL,
+ taiko->mbhc_data.v_brh & 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B10_CTL,
+ (taiko->mbhc_data.v_brh >> 8) & 0xFF);
+
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B11_CTL,
+ taiko->mbhc_data.v_brl & 0xFF);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_VOLT_B12_CTL,
+ (taiko->mbhc_data.v_brl >> 8) & 0xFF);
+
+ n_ready = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_N_READY);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_TIMER_B1_CTL,
+ n_ready[taiko_codec_mclk_index(taiko)]);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_TIMER_B2_CTL,
+ taiko->mbhc_data.npoll);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_TIMER_B3_CTL,
+ taiko->mbhc_data.nbounce_wait);
+ n_cic = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_N_CIC);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_TIMER_B6_CTL,
+ n_cic[taiko_codec_mclk_index(taiko)]);
+}
+
+static int taiko_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wcd9xxx *taiko_core = dev_get_drvdata(dai->codec->dev->parent);
+ pr_debug("%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
+ if ((taiko_core != NULL) &&
+ (taiko_core->dev != NULL) &&
+ (taiko_core->dev->parent != NULL))
+ pm_runtime_get_sync(taiko_core->dev->parent);
+
+ return 0;
+}
+
+static void taiko_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct wcd9xxx *taiko_core = dev_get_drvdata(dai->codec->dev->parent);
+ pr_debug("%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
+ if ((taiko_core != NULL) &&
+ (taiko_core->dev != NULL) &&
+ (taiko_core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(taiko_core->dev->parent);
+ pm_runtime_put(taiko_core->dev->parent);
+ }
+}
+
+int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
+ dapm);
+ if (dapm)
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ if (mclk_enable) {
+ taiko->mclk_enabled = true;
+
+ if (taiko->mbhc_polling_active) {
+ taiko_codec_pause_hs_polling(codec);
+ taiko_codec_disable_clock_block(codec);
+ taiko_codec_enable_bandgap(codec,
+ TAIKO_BANDGAP_AUDIO_MODE);
+ taiko_codec_enable_clock_block(codec, 0);
+ taiko_codec_calibrate_hs_polling(codec);
+ taiko_codec_start_hs_polling(codec);
+ } else {
+ taiko_codec_disable_clock_block(codec);
+ taiko_codec_enable_bandgap(codec,
+ TAIKO_BANDGAP_AUDIO_MODE);
+ taiko_codec_enable_clock_block(codec, 0);
+ }
+ } else {
+
+ if (!taiko->mclk_enabled) {
+ if (dapm)
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ pr_err("Error, MCLK already diabled\n");
+ return -EINVAL;
+ }
+ taiko->mclk_enabled = false;
+
+ if (taiko->mbhc_polling_active) {
+ taiko_codec_pause_hs_polling(codec);
+ taiko_codec_disable_clock_block(codec);
+ taiko_codec_enable_bandgap(codec,
+ TAIKO_BANDGAP_MBHC_MODE);
+ taiko_enable_rx_bias(codec, 1);
+ taiko_codec_enable_clock_block(codec, 1);
+ taiko_codec_calibrate_hs_polling(codec);
+ taiko_codec_start_hs_polling(codec);
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1,
+ 0x05, 0x01);
+ } else {
+ taiko_codec_disable_clock_block(codec);
+ taiko_codec_enable_bandgap(codec,
+ TAIKO_BANDGAP_OFF);
+ }
+ }
+ if (dapm)
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ return 0;
+}
+
+static int taiko_set_dai_sysclk(struct snd_soc_dai *dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ pr_debug("%s\n", __func__);
+ return 0;
+}
+
+static int taiko_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ u8 val = 0;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(dai->codec);
+
+ pr_debug("%s\n", __func__);
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ if (dai->id == AIF1_CAP)
+ snd_soc_update_bits(dai->codec,
+ TAIKO_A_CDC_CLK_TX_I2S_CTL,
+ TAIKO_I2S_MASTER_MODE_MASK, 0);
+ else if (dai->id == AIF1_PB)
+ snd_soc_update_bits(dai->codec,
+ TAIKO_A_CDC_CLK_RX_I2S_CTL,
+ TAIKO_I2S_MASTER_MODE_MASK, 0);
+ }
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* CPU is slave */
+ if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ val = TAIKO_I2S_MASTER_MODE_MASK;
+ if (dai->id == AIF1_CAP)
+ snd_soc_update_bits(dai->codec,
+ TAIKO_A_CDC_CLK_TX_I2S_CTL, val, val);
+ else if (dai->id == AIF1_PB)
+ snd_soc_update_bits(dai->codec,
+ TAIKO_A_CDC_CLK_RX_I2S_CTL, val, val);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int taiko_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(dai->codec);
+ u32 i = 0;
+ if (!tx_slot && !rx_slot) {
+ pr_err("%s: Invalid\n", __func__);
+ return -EINVAL;
+ }
+ pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
+ __func__, dai->name, dai->id, tx_num, rx_num);
+
+ if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
+ for (i = 0; i < rx_num; i++) {
+ taiko->dai[dai->id - 1].ch_num[i] = rx_slot[i];
+ taiko->dai[dai->id - 1].ch_act = 0;
+ taiko->dai[dai->id - 1].ch_tot = rx_num;
+ }
+ } else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP ||
+ dai->id == AIF3_CAP) {
+ for (i = 0; i < tx_num; i++) {
+ taiko->dai[dai->id - 1].ch_num[i] = tx_slot[i];
+ taiko->dai[dai->id - 1].ch_act = 0;
+ taiko->dai[dai->id - 1].ch_tot = tx_num;
+ }
+ }
+ return 0;
+}
+
+static int taiko_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+
+{
+ struct wcd9xxx *taiko = dev_get_drvdata(dai->codec->control_data);
+
+ u32 cnt = 0;
+ u32 tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch[SLIM_MAX_RX_PORTS];
+
+ if (!rx_slot && !tx_slot) {
+ pr_err("%s: Invalid\n", __func__);
+ return -EINVAL;
+ }
+
+ /* for virtual port, codec driver needs to do
+ * housekeeping, for now should be ok
+ */
+ wcd9xxx_get_channel(taiko, rx_ch, tx_ch);
+ if (dai->id == AIF1_PB) {
+ *rx_num = taiko_dai[dai->id - 1].playback.channels_max;
+ while (cnt < *rx_num) {
+ rx_slot[cnt] = rx_ch[cnt];
+ cnt++;
+ }
+ } else if (dai->id == AIF1_CAP) {
+ *tx_num = taiko_dai[dai->id - 1].capture.channels_max;
+ while (cnt < *tx_num) {
+ tx_slot[cnt] = tx_ch[6 + cnt];
+ cnt++;
+ }
+ } else if (dai->id == AIF2_PB) {
+ *rx_num = taiko_dai[dai->id - 1].playback.channels_max;
+ while (cnt < *rx_num) {
+ rx_slot[cnt] = rx_ch[5 + cnt];
+ cnt++;
+ }
+ } else if (dai->id == AIF2_CAP) {
+ *tx_num = taiko_dai[dai->id - 1].capture.channels_max;
+ tx_slot[0] = tx_ch[cnt];
+ tx_slot[1] = tx_ch[1 + cnt];
+ tx_slot[2] = tx_ch[5 + cnt];
+ tx_slot[3] = tx_ch[3 + cnt];
+
+ } else if (dai->id == AIF3_PB) {
+ *rx_num = taiko_dai[dai->id - 1].playback.channels_max;
+ rx_slot[0] = rx_ch[3];
+ rx_slot[1] = rx_ch[4];
+
+ } else if (dai->id == AIF3_CAP) {
+ *tx_num = taiko_dai[dai->id - 1].capture.channels_max;
+ tx_slot[cnt] = tx_ch[2 + cnt];
+ tx_slot[cnt + 1] = tx_ch[4 + cnt];
+ }
+ pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
+ __func__, dai->name, dai->id, *tx_num, *rx_num);
+
+
+ return 0;
+}
+
+static int taiko_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(dai->codec);
+ u8 path, shift;
+ u16 tx_fs_reg, rx_fs_reg;
+ u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+ u32 compander_fs;
+
+ pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
+ dai->name, dai->id, params_rate(params),
+ params_channels(params));
+
+ switch (params_rate(params)) {
+ case 8000:
+ tx_fs_rate = 0x00;
+ rx_fs_rate = 0x00;
+ compander_fs = COMPANDER_FS_8KHZ;
+ break;
+ case 16000:
+ tx_fs_rate = 0x01;
+ rx_fs_rate = 0x20;
+ compander_fs = COMPANDER_FS_16KHZ;
+ break;
+ case 32000:
+ tx_fs_rate = 0x02;
+ rx_fs_rate = 0x40;
+ compander_fs = COMPANDER_FS_32KHZ;
+ break;
+ case 48000:
+ tx_fs_rate = 0x03;
+ rx_fs_rate = 0x60;
+ compander_fs = COMPANDER_FS_48KHZ;
+ break;
+ case 96000:
+ tx_fs_rate = 0x04;
+ rx_fs_rate = 0x80;
+ compander_fs = COMPANDER_FS_96KHZ;
+ break;
+ case 192000:
+ tx_fs_rate = 0x05;
+ rx_fs_rate = 0xA0;
+ compander_fs = COMPANDER_FS_192KHZ;
+ break;
+ default:
+ pr_err("%s: Invalid sampling rate %d\n", __func__,
+ params_rate(params));
+ return -EINVAL;
+ }
+
+
+ /**
+ * If current dai is a tx dai, set sample rate to
+ * all the txfe paths that are currently not active
+ */
+ if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP) ||
+ (dai->id == AIF3_CAP)) {
+
+ tx_state = snd_soc_read(codec,
+ TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL);
+
+ for (path = 1, shift = 0;
+ path <= NUM_DECIMATORS; path++, shift++) {
+
+ if (path == BITS_PER_REG + 1) {
+ shift = 0;
+ tx_state = snd_soc_read(codec,
+ TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL);
+ }
+
+ if (!(tx_state & (1 << shift))) {
+ tx_fs_reg = TAIKO_A_CDC_TX1_CLK_FS_CTL
+ + (BITS_PER_REG*(path-1));
+ snd_soc_update_bits(codec, tx_fs_reg,
+ 0x07, tx_fs_rate);
+ }
+ }
+ if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_TX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_TX_I2S_CTL,
+ 0x07, tx_fs_rate);
+ } else {
+ taiko->dai[dai->id - 1].rate = params_rate(params);
+ }
+ }
+ /**
+ * TODO: Need to handle case where same RX chain takes 2 or more inputs
+ * with varying sample rates
+ */
+
+ /**
+ * If current dai is a rx dai, set sample rate to
+ * all the rx paths that are currently not active
+ */
+ if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
+
+ rx_state = snd_soc_read(codec,
+ TAIKO_A_CDC_CLK_RX_B1_CTL);
+
+ for (path = 1, shift = 0;
+ path <= NUM_INTERPOLATORS; path++, shift++) {
+
+ if (!(rx_state & (1 << shift))) {
+ rx_fs_reg = TAIKO_A_CDC_RX1_B5_CTL
+ + (BITS_PER_REG*(path-1));
+ snd_soc_update_bits(codec, rx_fs_reg,
+ 0xE0, rx_fs_rate);
+ if (comp_rx_path[shift] < COMPANDER_MAX)
+ taiko->comp_fs[comp_rx_path[shift]]
+ = compander_fs;
+ }
+ }
+ if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x20);
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_CLK_RX_I2S_CTL,
+ 0x20, 0x00);
+ break;
+ default:
+ pr_err("invalid format\n");
+ break;
+ }
+ snd_soc_update_bits(codec, TAIKO_A_CDC_CLK_RX_I2S_CTL,
+ 0x03, (rx_fs_rate >> 0x05));
+ } else {
+ taiko->dai[dai->id - 1].rate = params_rate(params);
+ }
+ }
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops taiko_dai_ops = {
+ .startup = taiko_startup,
+ .shutdown = taiko_shutdown,
+ .hw_params = taiko_hw_params,
+ .set_sysclk = taiko_set_dai_sysclk,
+ .set_fmt = taiko_set_dai_fmt,
+ .set_channel_map = taiko_set_channel_map,
+ .get_channel_map = taiko_get_channel_map,
+};
+
+static struct snd_soc_dai_driver taiko_dai[] = {
+ {
+ .name = "taiko_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &taiko_dai_ops,
+ },
+ {
+ .name = "taiko_tx1",
+ .id = AIF1_CAP,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &taiko_dai_ops,
+ },
+ {
+ .name = "taiko_rx2",
+ .id = AIF2_PB,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &taiko_dai_ops,
+ },
+ {
+ .name = "taiko_tx2",
+ .id = AIF2_CAP,
+ .capture = {
+ .stream_name = "AIF2 Capture",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &taiko_dai_ops,
+ },
+ {
+ .name = "taiko_tx3",
+ .id = AIF3_CAP,
+ .capture = {
+ .stream_name = "AIF3 Capture",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &taiko_dai_ops,
+ },
+ {
+ .name = "taiko_rx3",
+ .id = AIF3_PB,
+ .playback = {
+ .stream_name = "AIF3 Playback",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &taiko_dai_ops,
+ },
+};
+
+static struct snd_soc_dai_driver taiko_i2s_dai[] = {
+ {
+ .name = "taiko_i2s_rx1",
+ .id = 1,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &taiko_dai_ops,
+ },
+ {
+ .name = "taiko_i2s_tx1",
+ .id = 2,
+ .capture = {
+ .stream_name = "AIF1 Capture",
+ .rates = WCD9320_RATES,
+ .formats = TAIKO_FORMATS,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 4,
+ },
+ .ops = &taiko_dai_ops,
+ },
+};
+
+static int taiko_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct wcd9xxx *taiko;
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+ u32 j = 0;
+ u32 ret = 0;
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ taiko = codec->control_data;
+ /* Execute the callback only if interface type is slimbus */
+ if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ return 0;
+
+ pr_debug("%s: %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
+ if ((taiko_dai[j].id == AIF1_CAP) ||
+ (taiko_dai[j].id == AIF2_CAP) ||
+ (taiko_dai[j].id == AIF3_CAP))
+ continue;
+ if (!strncmp(w->sname,
+ taiko_dai[j].playback.stream_name, 13)) {
+ ++taiko_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (taiko_p->dai[j].ch_act == taiko_p->dai[j].ch_tot)
+ ret = wcd9xxx_cfg_slim_sch_rx(taiko,
+ taiko_p->dai[j].ch_num,
+ taiko_p->dai[j].ch_tot,
+ taiko_p->dai[j].rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
+ if ((taiko_dai[j].id == AIF1_CAP) ||
+ (taiko_dai[j].id == AIF2_CAP) ||
+ (taiko_dai[j].id == AIF3_CAP))
+ continue;
+ if (!strncmp(w->sname,
+ taiko_dai[j].playback.stream_name, 13)) {
+ --taiko_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (!taiko_p->dai[j].ch_act) {
+ ret = wcd9xxx_close_slim_sch_rx(taiko,
+ taiko_p->dai[j].ch_num,
+ taiko_p->dai[j].ch_tot);
+ usleep_range(15000, 15000);
+ taiko_p->dai[j].rate = 0;
+ memset(taiko_p->dai[j].ch_num, 0, (sizeof(u32)*
+ taiko_p->dai[j].ch_tot));
+ taiko_p->dai[j].ch_tot = 0;
+ }
+ }
+ return ret;
+}
+
+static int taiko_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct wcd9xxx *taiko;
+ struct snd_soc_codec *codec = w->codec;
+ struct taiko_priv *taiko_p = snd_soc_codec_get_drvdata(codec);
+ /* index to the DAI ID, for now hardcoding */
+ u32 j = 0;
+ u32 ret = 0;
+
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ taiko = codec->control_data;
+
+ /* Execute the callback only if interface type is slimbus */
+ if (taiko_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ return 0;
+
+ pr_debug("%s(): %s %d\n", __func__, w->name, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
+ if (taiko_dai[j].id == AIF1_PB ||
+ taiko_dai[j].id == AIF2_PB ||
+ taiko_dai[j].id == AIF3_PB)
+ continue;
+ if (!strncmp(w->sname,
+ taiko_dai[j].capture.stream_name, 13)) {
+ ++taiko_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (taiko_p->dai[j].ch_act == taiko_p->dai[j].ch_tot)
+ ret = wcd9xxx_cfg_slim_sch_tx(taiko,
+ taiko_p->dai[j].ch_num,
+ taiko_p->dai[j].ch_tot,
+ taiko_p->dai[j].rate);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ for (j = 0; j < ARRAY_SIZE(taiko_dai); j++) {
+ if (taiko_dai[j].id == AIF1_PB ||
+ taiko_dai[j].id == AIF2_PB ||
+ taiko_dai[j].id == AIF3_PB)
+ continue;
+ if (!strncmp(w->sname,
+ taiko_dai[j].capture.stream_name, 13)) {
+ --taiko_p->dai[j].ch_act;
+ break;
+ }
+ }
+ if (!taiko_p->dai[j].ch_act) {
+ ret = wcd9xxx_close_slim_sch_tx(taiko,
+ taiko_p->dai[j].ch_num,
+ taiko_p->dai[j].ch_tot);
+ taiko_p->dai[j].rate = 0;
+ memset(taiko_p->dai[j].ch_num, 0, (sizeof(u32)*
+ taiko_p->dai[j].ch_tot));
+ taiko_p->dai[j].ch_tot = 0;
+ }
+ }
+ return ret;
+}
+
+/* Todo: Have seperate dapm widgets for I2S and Slimbus.
+ * Might Need to have callbacks registered only for slimbus
+ */
+static const struct snd_soc_dapm_widget taiko_dapm_widgets[] = {
+ /*RX stuff */
+ SND_SOC_DAPM_OUTPUT("EAR"),
+
+ SND_SOC_DAPM_PGA("EAR PA", TAIKO_A_RX_EAR_EN, 4, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("DAC1", TAIKO_A_RX_EAR_EN, 6, 0, dac1_switch,
+ ARRAY_SIZE(dac1_switch)),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX4", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX5", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Headphone */
+ SND_SOC_DAPM_OUTPUT("HEADPHONE"),
+ SND_SOC_DAPM_PGA_E("HPHL", TAIKO_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
+ taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MIXER("HPHL DAC", TAIKO_A_RX_HPH_L_DAC_CTL, 7, 0,
+ hphl_switch, ARRAY_SIZE(hphl_switch)),
+
+ SND_SOC_DAPM_PGA_E("HPHR", TAIKO_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
+ taiko_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAIKO_A_RX_HPH_R_DAC_CTL, 7, 0,
+ taiko_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Speaker */
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT3"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT4"),
+
+ SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAIKO_A_RX_LINE_CNP_EN, 0, 0, NULL,
+ 0, taiko_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAIKO_A_RX_LINE_CNP_EN, 1, 0, NULL,
+ 0, taiko_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TAIKO_A_RX_LINE_CNP_EN, 2, 0, NULL,
+ 0, taiko_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TAIKO_A_RX_LINE_CNP_EN, 3, 0, NULL,
+ 0, taiko_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAIKO_A_RX_LINE_1_DAC_CTL, 7, 0
+ , taiko_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAIKO_A_RX_LINE_2_DAC_CTL, 7, 0
+ , taiko_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TAIKO_A_RX_LINE_3_DAC_CTL, 7, 0
+ , taiko_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
+ &lineout3_ground_switch),
+ SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TAIKO_A_RX_LINE_4_DAC_CTL, 7, 0
+ , taiko_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
+ &lineout4_ground_switch),
+
+ SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+ 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+ 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX7 MIX2", TAIKO_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+ 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX4 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
+ 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX5 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
+ 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX6 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
+ 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MIXER_E("RX7 MIX1", TAIKO_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
+ 0, taiko_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 3, 0,
+ &rx4_dsm_mux, taiko_codec_reset_interpolator,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TAIKO_A_CDC_CLK_RX_B1_CTL, 5, 0,
+ &rx6_dsm_mux, taiko_codec_reset_interpolator,
+ SND_SOC_DAPM_PRE_PMU),
+
+ SND_SOC_DAPM_MIXER("RX1 CHAIN", TAIKO_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 CHAIN", TAIKO_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp3_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx3_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx4_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx5_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx5_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx6_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx6_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx7_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx7_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx1_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+ &rx1_mix2_inp2_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix2_inp2_mux),
+ SND_SOC_DAPM_MUX("RX7 MIX2 INP1", SND_SOC_NOPM, 0, 0,
+ &rx7_mix2_inp1_mux),
+ SND_SOC_DAPM_MUX("RX7 MIX2 INP2", SND_SOC_NOPM, 0, 0,
+ &rx7_mix2_inp2_mux),
+
+ SND_SOC_DAPM_SUPPLY("CP", TAIKO_A_NCP_EN, 0, 0,
+ taiko_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* TX */
+
+ SND_SOC_DAPM_SUPPLY("CDC_CONN", TAIKO_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
+ 0),
+
+ SND_SOC_DAPM_SUPPLY("LDO_H", TAIKO_A_LDO_H_MODE_1, 7, 0,
+ taiko_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
+ taiko_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
+ taiko_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+
+
+ SND_SOC_DAPM_INPUT("AMIC1"),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAIKO_A_MICB_1_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAIKO_A_MICB_1_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAIKO_A_MICB_1_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
+ taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC3"),
+ SND_SOC_DAPM_ADC_E("ADC3", NULL, TAIKO_A_TX_3_4_EN, 7, 0,
+ taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC4"),
+ SND_SOC_DAPM_ADC_E("ADC4", NULL, TAIKO_A_TX_3_4_EN, 3, 0,
+ taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_INPUT("AMIC5"),
+ SND_SOC_DAPM_ADC_E("ADC5", NULL, TAIKO_A_TX_5_6_EN, 7, 0,
+ taiko_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_INPUT("AMIC6"),
+ SND_SOC_DAPM_ADC_E("ADC6", NULL, TAIKO_A_TX_5_6_EN, 3, 0,
+ taiko_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
+
+ SND_SOC_DAPM_MUX_E("DEC1 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
+ &dec1_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC2 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
+ &dec2_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC3 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
+ &dec3_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC4 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
+ &dec4_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC5 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
+ &dec5_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC6 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
+ &dec6_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC7 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
+ &dec7_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC8 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
+ &dec8_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC9 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
+ &dec9_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX_E("DEC10 MUX", TAIKO_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
+ &dec10_mux, taiko_codec_enable_dec,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+ SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+ SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
+ taiko_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
+ SND_SOC_DAPM_INPUT("AMIC2"),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAIKO_A_MICB_2_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAIKO_A_MICB_2_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAIKO_A_MICB_2_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAIKO_A_MICB_2_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAIKO_A_MICB_3_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAIKO_A_MICB_3_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAIKO_A_MICB_3_CTL, 7, 0,
+ taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TAIKO_A_MICB_4_CTL, 7,
+ 0, taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
+ taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 0, 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
+ 0, 0, taiko_codec_enable_slimtx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ /* Digital Mic Inputs */
+ SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
+ taiko_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* Sidetone */
+ SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
+ SND_SOC_DAPM_PGA("IIR1", TAIKO_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
+
+ /* AUX PGA */
+ SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAIKO_A_RX_AUX_SW_CTL, 7, 0,
+ taiko_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TAIKO_A_RX_AUX_SW_CTL, 6, 0,
+ taiko_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ /* Lineout, ear and HPH PA Mixers */
+
+ SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
+ ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
+
+ SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
+ hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
+
+ SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
+ hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
+
+ SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
+ lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
+
+ SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
+ lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
+
+ SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
+ lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
+
+ SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
+ lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
+
+};
+
+static short taiko_codec_read_sta_result(struct snd_soc_codec *codec)
+{
+ u8 bias_msb, bias_lsb;
+ short bias_value;
+
+ bias_msb = snd_soc_read(codec, TAIKO_A_CDC_MBHC_B3_STATUS);
+ bias_lsb = snd_soc_read(codec, TAIKO_A_CDC_MBHC_B2_STATUS);
+ bias_value = (bias_msb << 8) | bias_lsb;
+ return bias_value;
+}
+
+static short taiko_codec_read_dce_result(struct snd_soc_codec *codec)
+{
+ u8 bias_msb, bias_lsb;
+ short bias_value;
+
+ bias_msb = snd_soc_read(codec, TAIKO_A_CDC_MBHC_B5_STATUS);
+ bias_lsb = snd_soc_read(codec, TAIKO_A_CDC_MBHC_B4_STATUS);
+ bias_value = (bias_msb << 8) | bias_lsb;
+ return bias_value;
+}
+
+static void taiko_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
+{
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
+}
+
+static short __taiko_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+ bool override_bypass, bool noreldetection)
+{
+ short bias_value;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ if (noreldetection)
+ taiko_turn_onoff_rel_detection(codec, false);
+
+ /* Turn on the override */
+ if (!override_bypass)
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
+ if (dce) {
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x4);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ usleep_range(taiko->mbhc_data.t_sta_dce,
+ taiko->mbhc_data.t_sta_dce);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x4);
+ usleep_range(taiko->mbhc_data.t_dce,
+ taiko->mbhc_data.t_dce);
+ bias_value = taiko_codec_read_dce_result(codec);
+ } else {
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x2);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
+ usleep_range(taiko->mbhc_data.t_sta_dce,
+ taiko->mbhc_data.t_sta_dce);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x2);
+ usleep_range(taiko->mbhc_data.t_sta,
+ taiko->mbhc_data.t_sta);
+ bias_value = taiko_codec_read_sta_result(codec);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x0);
+ }
+ /* Turn off the override after measuring mic voltage */
+ if (!override_bypass)
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+
+ if (noreldetection)
+ taiko_turn_onoff_rel_detection(codec, true);
+ wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+
+ return bias_value;
+}
+
+static short taiko_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+ bool norel)
+{
+ return __taiko_codec_sta_dce(codec, dce, false, norel);
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static short taiko_codec_setup_hs_polling(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ short bias_value;
+ u8 cfilt_mode;
+
+ pr_debug("%s: enter, mclk_enabled %d\n", __func__, taiko->mclk_enabled);
+ if (!taiko->mbhc_cfg.calibration) {
+ pr_err("Error, no taiko calibration\n");
+ return -ENODEV;
+ }
+
+ if (!taiko->mclk_enabled) {
+ taiko_codec_disable_clock_block(codec);
+ taiko_codec_enable_bandgap(codec, TAIKO_BANDGAP_MBHC_MODE);
+ taiko_enable_rx_bias(codec, 1);
+ taiko_codec_enable_clock_block(codec, 1);
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_CLK_BUFF_EN1, 0x05, 0x01);
+
+ /* Make sure CFILT is in fast mode, save current mode */
+ cfilt_mode = snd_soc_read(codec, taiko->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
+
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x84);
+
+ snd_soc_update_bits(codec, TAIKO_A_TX_7_MBHC_EN, 0x80, 0x80);
+ snd_soc_update_bits(codec, TAIKO_A_TX_7_MBHC_EN, 0x1F, 0x1C);
+ snd_soc_update_bits(codec, TAIKO_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
+
+ snd_soc_update_bits(codec, TAIKO_A_TX_7_MBHC_EN, 0x80, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+
+ taiko_codec_calibrate_hs_polling(codec);
+
+ /* don't flip override */
+ bias_value = __taiko_codec_sta_dce(codec, 1, true, true);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.cfilt_ctl, 0x40,
+ cfilt_mode);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x13, 0x00);
+
+ return bias_value;
+}
+
+static int taiko_cancel_btn_work(struct taiko_priv *taiko)
+{
+ int r = 0;
+ struct wcd9xxx *core = dev_get_drvdata(taiko->codec->dev->parent);
+
+ if (cancel_delayed_work_sync(&taiko->mbhc_btn_dwork)) {
+ /* if scheduled mbhc_btn_dwork is canceled from here,
+ * we have to unlock from here instead btn_work */
+ wcd9xxx_unlock_sleep(core);
+ r = 1;
+ }
+ return r;
+}
+
+/* called under codec_resource_lock acquisition */
+void taiko_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ u8 wg_time;
+
+ wg_time = snd_soc_read(codec, TAIKO_A_RX_HPH_CNP_WG_TIME) ;
+ wg_time += 1;
+
+ /* If headphone PA is on, check if userspace receives
+ * removal event to sync-up PA's state */
+ if (taiko_is_hph_pa_on(codec)) {
+ pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
+ set_bit(TAIKO_HPHL_PA_OFF_ACK, &taiko->hph_pa_dac_state);
+ set_bit(TAIKO_HPHR_PA_OFF_ACK, &taiko->hph_pa_dac_state);
+ } else {
+ pr_debug("%s PA is off\n", __func__);
+ }
+
+ if (taiko_is_hph_dac_on(codec, 1))
+ set_bit(TAIKO_HPHL_DAC_OFF_ACK, &taiko->hph_pa_dac_state);
+ if (taiko_is_hph_dac_on(codec, 0))
+ set_bit(TAIKO_HPHR_DAC_OFF_ACK, &taiko->hph_pa_dac_state);
+
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_CNP_EN, 0x30, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0x00);
+ usleep_range(wg_time * 1000, wg_time * 1000);
+}
+
+static void taiko_clr_and_turnon_hph_padac(struct taiko_priv *taiko)
+{
+ bool pa_turned_on = false;
+ struct snd_soc_codec *codec = taiko->codec;
+ u8 wg_time;
+
+ wg_time = snd_soc_read(codec, TAIKO_A_RX_HPH_CNP_WG_TIME) ;
+ wg_time += 1;
+
+ if (test_and_clear_bit(TAIKO_HPHR_DAC_OFF_ACK,
+ &taiko->hph_pa_dac_state)) {
+ pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(taiko->codec, TAIKO_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+ if (test_and_clear_bit(TAIKO_HPHL_DAC_OFF_ACK,
+ &taiko->hph_pa_dac_state)) {
+ pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(taiko->codec, TAIKO_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+
+ if (test_and_clear_bit(TAIKO_HPHR_PA_OFF_ACK,
+ &taiko->hph_pa_dac_state)) {
+ pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(taiko->codec, TAIKO_A_RX_HPH_CNP_EN, 0x10,
+ 1 << 4);
+ pa_turned_on = true;
+ }
+ if (test_and_clear_bit(TAIKO_HPHL_PA_OFF_ACK,
+ &taiko->hph_pa_dac_state)) {
+ pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(taiko->codec, TAIKO_A_RX_HPH_CNP_EN, 0x20,
+ 1 << 5);
+ pa_turned_on = true;
+ }
+
+ if (pa_turned_on) {
+ pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
+ __func__);
+ usleep_range(wg_time * 1000, wg_time * 1000);
+ }
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_codec_report_plug(struct snd_soc_codec *codec, int insertion,
+ enum snd_jack_types jack_type)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ if (!insertion) {
+ /* Report removal */
+ taiko->hph_status &= ~jack_type;
+ if (taiko->mbhc_cfg.headset_jack) {
+ /* cancel possibly scheduled btn work and
+ * report release if we reported button press */
+ if (taiko_cancel_btn_work(taiko)) {
+ pr_debug("%s: button press is canceled\n",
+ __func__);
+ } else if (taiko->buttons_pressed) {
+ pr_debug("%s: release of button press%d\n",
+ __func__, jack_type);
+ taiko_snd_soc_jack_report(taiko,
+ taiko->mbhc_cfg.button_jack, 0,
+ taiko->buttons_pressed);
+ taiko->buttons_pressed &=
+ ~TAIKO_JACK_BUTTON_MASK;
+ }
+ pr_debug("%s: Reporting removal %d(%x)\n", __func__,
+ jack_type, taiko->hph_status);
+ taiko_snd_soc_jack_report(taiko,
+ taiko->mbhc_cfg.headset_jack,
+ taiko->hph_status,
+ TAIKO_JACK_MASK);
+ }
+ taiko_set_and_turnoff_hph_padac(codec);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHR,
+ TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ hphocp_off_report(taiko, SND_JACK_OC_HPHL,
+ TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ taiko->current_plug = PLUG_TYPE_NONE;
+ taiko->mbhc_polling_active = false;
+ } else {
+ /* Report insertion */
+ taiko->hph_status |= jack_type;
+
+ if (jack_type == SND_JACK_HEADPHONE)
+ taiko->current_plug = PLUG_TYPE_HEADPHONE;
+ else if (jack_type == SND_JACK_UNSUPPORTED)
+ taiko->current_plug = PLUG_TYPE_GND_MIC_SWAP;
+ else if (jack_type == SND_JACK_HEADSET) {
+ taiko->mbhc_polling_active = true;
+ taiko->current_plug = PLUG_TYPE_HEADSET;
+ }
+ if (taiko->mbhc_cfg.headset_jack) {
+ pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
+ jack_type, taiko->hph_status);
+ taiko_snd_soc_jack_report(taiko,
+ taiko->mbhc_cfg.headset_jack,
+ taiko->hph_status,
+ TAIKO_JACK_MASK);
+ }
+ taiko_clr_and_turnon_hph_padac(taiko);
+ }
+}
+
+static int taiko_codec_enable_hs_detect(struct snd_soc_codec *codec,
+ int insertion, int trigger,
+ bool padac_off)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ int central_bias_enabled = 0;
+ const struct taiko_mbhc_general_cfg *generic =
+ TAIKO_MBHC_CAL_GENERAL_PTR(taiko->mbhc_cfg.calibration);
+ const struct taiko_mbhc_plug_detect_cfg *plug_det =
+ TAIKO_MBHC_CAL_PLUG_DET_PTR(taiko->mbhc_cfg.calibration);
+
+ if (!taiko->mbhc_cfg.calibration) {
+ pr_err("Error, no taiko calibration\n");
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_INT_CTL, 0x1, 0);
+
+ /* Make sure mic bias and Mic line schmitt trigger
+ * are turned OFF
+ */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
+
+ if (insertion) {
+ taiko_codec_switch_micbias(codec, 0);
+
+ /* DAPM can manipulate PA/DAC bits concurrently */
+ if (padac_off == true)
+ taiko_set_and_turnoff_hph_padac(codec);
+
+ if (trigger & MBHC_USE_HPHL_TRIGGER) {
+ /* Enable HPH Schmitt Trigger */
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x11,
+ 0x11);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x0C,
+ plug_det->hph_current << 2);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x02,
+ 0x02);
+ }
+ if (trigger & MBHC_USE_MB_TRIGGER) {
+ /* enable the mic line schmitt trigger */
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.mbhc_reg,
+ 0x60, plug_det->mic_current << 5);
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.ctl_reg, 0x01,
+ 0x00);
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x10);
+ }
+
+ /* setup for insetion detection */
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_INT_CTL, 0x2, 0);
+ } else {
+ pr_debug("setup for removal detection\n");
+ /* Make sure the HPH schmitt trigger is OFF */
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x12, 0x00);
+
+ /* enable the mic line schmitt trigger */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg,
+ 0x01, 0x00);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg, 0x60,
+ plug_det->mic_current << 5);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg,
+ 0x80, 0x80);
+ usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg,
+ 0x10, 0x10);
+
+ /* Setup for low power removal detection */
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
+ }
+
+ if (snd_soc_read(codec, TAIKO_A_CDC_MBHC_B1_CTL) & 0x4) {
+ /* called called by interrupt */
+ if (!(taiko->clock_active)) {
+ taiko_codec_enable_config_mode(codec, 1);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL,
+ 0x06, 0);
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
+ taiko_codec_enable_config_mode(codec, 0);
+ } else
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL,
+ 0x06, 0);
+ }
+
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.int_rbias, 0x80, 0);
+
+ /* If central bandgap disabled */
+ if (!(snd_soc_read(codec, TAIKO_A_PIN_CTL_OE1) & 1)) {
+ snd_soc_update_bits(codec, TAIKO_A_PIN_CTL_OE1, 0x3, 0x3);
+ usleep_range(generic->t_bg_fast_settle,
+ generic->t_bg_fast_settle);
+ central_bias_enabled = 1;
+ }
+
+ /* If LDO_H disabled */
+ if (snd_soc_read(codec, TAIKO_A_PIN_CTL_OE0) & 0x80) {
+ snd_soc_update_bits(codec, TAIKO_A_PIN_CTL_OE0, 0x10, 0);
+ snd_soc_update_bits(codec, TAIKO_A_PIN_CTL_OE0, 0x80, 0x80);
+ usleep_range(generic->t_ldoh, generic->t_ldoh);
+ snd_soc_update_bits(codec, TAIKO_A_PIN_CTL_OE0, 0x80, 0);
+
+ if (central_bias_enabled)
+ snd_soc_update_bits(codec, TAIKO_A_PIN_CTL_OE1, 0x1, 0);
+ }
+
+ snd_soc_update_bits(codec, taiko->reg_addr.micb_4_mbhc, 0x3,
+ taiko->mbhc_cfg.micbias);
+
+ wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
+ return 0;
+}
+
+static u16 taiko_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
+ s16 vin_mv)
+{
+ struct taiko_priv *taiko;
+ s16 diff, zero;
+ u32 mb_mv, in;
+ u16 value;
+
+ taiko = snd_soc_codec_get_drvdata(codec);
+ mb_mv = taiko->mbhc_data.micb_mv;
+
+ if (mb_mv == 0) {
+ pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
+ return -EINVAL;
+ }
+
+ if (dce) {
+ diff = (taiko->mbhc_data.dce_mb) - (taiko->mbhc_data.dce_z);
+ zero = (taiko->mbhc_data.dce_z);
+ } else {
+ diff = (taiko->mbhc_data.sta_mb) - (taiko->mbhc_data.sta_z);
+ zero = (taiko->mbhc_data.sta_z);
+ }
+ in = (u32) diff * vin_mv;
+
+ value = (u16) (in / mb_mv) + zero;
+ return value;
+}
+
+static s32 taiko_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
+ u16 bias_value)
+{
+ struct taiko_priv *taiko;
+ s16 value, z, mb;
+ s32 mv;
+
+ taiko = snd_soc_codec_get_drvdata(codec);
+ value = bias_value;
+ if (dce) {
+ z = (taiko->mbhc_data.dce_z);
+ mb = (taiko->mbhc_data.dce_mb);
+ mv = (value - z) * (s32)taiko->mbhc_data.micb_mv / (mb - z);
+ } else {
+ z = (taiko->mbhc_data.sta_z);
+ mb = (taiko->mbhc_data.sta_mb);
+ mv = (value - z) * (s32)taiko->mbhc_data.micb_mv / (mb - z);
+ }
+
+ return mv;
+}
+
+static void btn_lpress_fn(struct work_struct *work)
+{
+ struct delayed_work *delayed_work;
+ struct taiko_priv *taiko;
+ short bias_value;
+ int dce_mv, sta_mv;
+ struct wcd9xxx *core;
+
+ pr_debug("%s:\n", __func__);
+
+ delayed_work = to_delayed_work(work);
+ taiko = container_of(delayed_work, struct taiko_priv, mbhc_btn_dwork);
+ core = dev_get_drvdata(taiko->codec->dev->parent);
+
+ if (taiko) {
+ if (taiko->mbhc_cfg.button_jack) {
+ bias_value = taiko_codec_read_sta_result(taiko->codec);
+ sta_mv = taiko_codec_sta_dce_v(taiko->codec, 0,
+ bias_value);
+ bias_value = taiko_codec_read_dce_result(taiko->codec);
+ dce_mv = taiko_codec_sta_dce_v(taiko->codec, 1,
+ bias_value);
+ pr_debug("%s: Reporting long button press event\n",
+ __func__);
+ pr_debug("%s: STA: %d, DCE: %d\n", __func__, sta_mv,
+ dce_mv);
+ taiko_snd_soc_jack_report(taiko,
+ taiko->mbhc_cfg.button_jack,
+ taiko->buttons_pressed,
+ taiko->buttons_pressed);
+ }
+ } else {
+ pr_err("%s: Bad taiko private data\n", __func__);
+ }
+
+ pr_debug("%s: leave\n", __func__);
+ wcd9xxx_unlock_sleep(core);
+}
+
+void taiko_mbhc_cal(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko;
+ struct taiko_mbhc_btn_detect_cfg *btn_det;
+ u8 cfilt_mode, bg_mode;
+ u8 ncic, nmeas, navg;
+ u32 mclk_rate;
+ u32 dce_wait, sta_wait;
+ u8 *n_cic;
+ void *calibration;
+
+ taiko = snd_soc_codec_get_drvdata(codec);
+ calibration = taiko->mbhc_cfg.calibration;
+
+ wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ taiko_turn_onoff_rel_detection(codec, false);
+
+ /* First compute the DCE / STA wait times
+ * depending on tunable parameters.
+ * The value is computed in microseconds
+ */
+ btn_det = TAIKO_MBHC_CAL_BTN_DET_PTR(calibration);
+ n_cic = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_N_CIC);
+ ncic = n_cic[taiko_codec_mclk_index(taiko)];
+ nmeas = TAIKO_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
+ navg = TAIKO_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
+ mclk_rate = taiko->mbhc_cfg.mclk_rate;
+ dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
+ sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
+
+ taiko->mbhc_data.t_dce = dce_wait;
+ taiko->mbhc_data.t_sta = sta_wait;
+
+ /* LDOH and CFILT are already configured during pdata handling.
+ * Only need to make sure CFILT and bandgap are in Fast mode.
+ * Need to restore defaults once calculation is done.
+ */
+ cfilt_mode = snd_soc_read(codec, taiko->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
+ bg_mode = snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x02,
+ 0x02);
+
+ /* Micbias, CFILT, LDOH, MBHC MUX mode settings
+ * to perform ADC calibration
+ */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x60,
+ taiko->mbhc_cfg.micbias << 5);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 0x60, 0x60);
+ snd_soc_write(codec, TAIKO_A_TX_7_MBHC_TEST_CTL, 0x78);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
+
+ /* DCE measurement for 0 volts */
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x04);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x81);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x04);
+ usleep_range(taiko->mbhc_data.t_dce, taiko->mbhc_data.t_dce);
+ taiko->mbhc_data.dce_z = taiko_codec_read_dce_result(codec);
+
+ /* DCE measurment for MB voltage */
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x82);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x04);
+ usleep_range(taiko->mbhc_data.t_dce, taiko->mbhc_data.t_dce);
+ taiko->mbhc_data.dce_mb = taiko_codec_read_dce_result(codec);
+
+ /* Sta measuremnt for 0 volts */
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x0A);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x02);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x02);
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x81);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x02);
+ usleep_range(taiko->mbhc_data.t_sta, taiko->mbhc_data.t_sta);
+ taiko->mbhc_data.sta_z = taiko_codec_read_sta_result(codec);
+
+ /* STA Measurement for MB Voltage */
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x82);
+ usleep_range(100, 100);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_EN_CTL, 0x02);
+ usleep_range(taiko->mbhc_data.t_sta, taiko->mbhc_data.t_sta);
+ taiko->mbhc_data.sta_mb = taiko_codec_read_sta_result(codec);
+
+ /* Restore default settings. */
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.cfilt_ctl, 0x40,
+ cfilt_mode);
+ snd_soc_update_bits(codec, TAIKO_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
+
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x84);
+ usleep_range(100, 100);
+
+ wcd9xxx_enable_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL);
+ taiko_turn_onoff_rel_detection(codec, true);
+}
+
+void *taiko_mbhc_cal_btn_det_mp(const struct taiko_mbhc_btn_detect_cfg *btn_det,
+ const enum taiko_mbhc_btn_det_mem mem)
+{
+ void *ret = &btn_det->_v_btn_low;
+
+ switch (mem) {
+ case TAIKO_BTN_DET_GAIN:
+ ret += sizeof(btn_det->_n_cic);
+ case TAIKO_BTN_DET_N_CIC:
+ ret += sizeof(btn_det->_n_ready);
+ case TAIKO_BTN_DET_N_READY:
+ ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
+ case TAIKO_BTN_DET_V_BTN_HIGH:
+ ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
+ case TAIKO_BTN_DET_V_BTN_LOW:
+ /* do nothing */
+ break;
+ default:
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+static s16 taiko_scale_v_micb_vddio(struct taiko_priv *taiko, int v,
+ bool tovddio)
+{
+ int r;
+ int vddio_k, mb_k;
+ vddio_k = taiko_find_k_value(taiko->pdata->micbias.ldoh_v,
+ VDDIO_MICBIAS_MV);
+ mb_k = taiko_find_k_value(taiko->pdata->micbias.ldoh_v,
+ taiko->mbhc_data.micb_mv);
+ if (tovddio)
+ r = v * vddio_k / mb_k;
+ else
+ r = v * mb_k / vddio_k;
+ return r;
+}
+
+static void taiko_mbhc_calc_thres(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko;
+ s16 btn_mv = 0, btn_delta_mv;
+ struct taiko_mbhc_btn_detect_cfg *btn_det;
+ struct taiko_mbhc_plug_type_cfg *plug_type;
+ u16 *btn_high;
+ u8 *n_ready;
+ int i;
+
+ taiko = snd_soc_codec_get_drvdata(codec);
+ btn_det = TAIKO_MBHC_CAL_BTN_DET_PTR(taiko->mbhc_cfg.calibration);
+ plug_type = TAIKO_MBHC_CAL_PLUG_TYPE_PTR(taiko->mbhc_cfg.calibration);
+
+ n_ready = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_N_READY);
+ if (taiko->mbhc_cfg.mclk_rate == TAIKO_MCLK_RATE_12288KHZ) {
+ taiko->mbhc_data.npoll = 4;
+ taiko->mbhc_data.nbounce_wait = 30;
+ } else if (taiko->mbhc_cfg.mclk_rate == TAIKO_MCLK_RATE_9600KHZ) {
+ taiko->mbhc_data.npoll = 7;
+ taiko->mbhc_data.nbounce_wait = 23;
+ }
+
+ taiko->mbhc_data.t_sta_dce = ((1000 * 256) /
+ (taiko->mbhc_cfg.mclk_rate / 1000) *
+ n_ready[taiko_codec_mclk_index(taiko)]) +
+ 10;
+ taiko->mbhc_data.v_ins_hu =
+ taiko_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
+ taiko->mbhc_data.v_ins_h =
+ taiko_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
+
+ taiko->mbhc_data.v_inval_ins_low = TAIKO_MBHC_FAKE_INSERT_LOW;
+ if (taiko->mbhc_cfg.gpio)
+ taiko->mbhc_data.v_inval_ins_high =
+ TAIKO_MBHC_FAKE_INSERT_HIGH;
+ else
+ taiko->mbhc_data.v_inval_ins_high =
+ TAIKO_MBHC_FAKE_INS_HIGH_NO_GPIO;
+
+ if (taiko->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
+ taiko->mbhc_data.adj_v_hs_max =
+ taiko_scale_v_micb_vddio(taiko, plug_type->v_hs_max, true);
+ taiko->mbhc_data.adj_v_ins_hu =
+ taiko_codec_v_sta_dce(codec, STA,
+ taiko->mbhc_data.adj_v_hs_max);
+ taiko->mbhc_data.adj_v_ins_h =
+ taiko_codec_v_sta_dce(codec, DCE,
+ taiko->mbhc_data.adj_v_hs_max);
+ taiko->mbhc_data.v_inval_ins_low =
+ taiko_scale_v_micb_vddio(taiko,
+ taiko->mbhc_data.v_inval_ins_low,
+ false);
+ taiko->mbhc_data.v_inval_ins_high =
+ taiko_scale_v_micb_vddio(taiko,
+ taiko->mbhc_data.v_inval_ins_high,
+ false);
+ }
+
+ btn_high = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_V_BTN_HIGH);
+ for (i = 0; i < btn_det->num_btn; i++)
+ btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
+
+ taiko->mbhc_data.v_b1_h = taiko_codec_v_sta_dce(codec, DCE, btn_mv);
+ btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
+ taiko->mbhc_data.v_b1_hu =
+ taiko_codec_v_sta_dce(codec, STA, btn_delta_mv);
+
+ btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
+
+ taiko->mbhc_data.v_b1_huc =
+ taiko_codec_v_sta_dce(codec, DCE, btn_delta_mv);
+
+ taiko->mbhc_data.v_brh = taiko->mbhc_data.v_b1_h;
+ taiko->mbhc_data.v_brl = TAIKO_MBHC_BUTTON_MIN;
+
+ taiko->mbhc_data.v_no_mic =
+ taiko_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
+}
+
+void taiko_mbhc_init(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko;
+ struct taiko_mbhc_general_cfg *generic;
+ struct taiko_mbhc_btn_detect_cfg *btn_det;
+ int n;
+ u8 *n_cic, *gain;
+
+ taiko = snd_soc_codec_get_drvdata(codec);
+ generic = TAIKO_MBHC_CAL_GENERAL_PTR(taiko->mbhc_cfg.calibration);
+ btn_det = TAIKO_MBHC_CAL_BTN_DET_PTR(taiko->mbhc_cfg.calibration);
+
+ for (n = 0; n < 8; n++) {
+ snd_soc_update_bits(codec,
+ TAIKO_A_CDC_MBHC_FIR_B1_CFG,
+ 0x07, n);
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_FIR_B2_CFG,
+ btn_det->c[n]);
+ }
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B2_CTL, 0x07,
+ btn_det->nc);
+
+ n_cic = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_N_CIC);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
+ n_cic[taiko_codec_mclk_index(taiko)]);
+
+ gain = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_GAIN);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B2_CTL, 0x78,
+ gain[taiko_codec_mclk_index(taiko)] << 3);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
+ generic->mbhc_nsa << 4);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
+ btn_det->n_meas);
+
+ snd_soc_write(codec, TAIKO_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x78,
+ btn_det->mbhc_nsc << 3);
+
+ snd_soc_update_bits(codec, taiko->reg_addr.micb_4_mbhc, 0x03,
+ TAIKO_MICBIAS2);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
+}
+
+static bool taiko_mbhc_fw_validate(const struct firmware *fw)
+{
+ u32 cfg_offset;
+ struct taiko_mbhc_imped_detect_cfg *imped_cfg;
+ struct taiko_mbhc_btn_detect_cfg *btn_cfg;
+
+ if (fw->size < TAIKO_MBHC_CAL_MIN_SIZE)
+ return false;
+
+ /* previous check guarantees that there is enough fw data up
+ * to num_btn
+ */
+ btn_cfg = TAIKO_MBHC_CAL_BTN_DET_PTR(fw->data);
+ cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
+ if (fw->size < (cfg_offset + TAIKO_MBHC_CAL_BTN_SZ(btn_cfg)))
+ return false;
+
+ /* previous check guarantees that there is enough fw data up
+ * to start of impedance detection configuration
+ */
+ imped_cfg = TAIKO_MBHC_CAL_IMPED_DET_PTR(fw->data);
+ cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
+
+ if (fw->size < (cfg_offset + TAIKO_MBHC_CAL_IMPED_MIN_SZ))
+ return false;
+
+ if (fw->size < (cfg_offset + TAIKO_MBHC_CAL_IMPED_SZ(imped_cfg)))
+ return false;
+
+ return true;
+}
+
+/* called under codec_resource_lock acquisition */
+static int taiko_determine_button(const struct taiko_priv *priv,
+ const s32 micmv)
+{
+ s16 *v_btn_low, *v_btn_high;
+ struct taiko_mbhc_btn_detect_cfg *btn_det;
+ int i, btn = -1;
+
+ btn_det = TAIKO_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
+ v_btn_low = taiko_mbhc_cal_btn_det_mp(btn_det, TAIKO_BTN_DET_V_BTN_LOW);
+ v_btn_high = taiko_mbhc_cal_btn_det_mp(btn_det,
+ TAIKO_BTN_DET_V_BTN_HIGH);
+
+ for (i = 0; i < btn_det->num_btn; i++) {
+ if ((v_btn_low[i] <= micmv) && (v_btn_high[i] >= micmv)) {
+ btn = i;
+ break;
+ }
+ }
+
+ if (btn == -1)
+ pr_debug("%s: couldn't find button number for mic mv %d\n",
+ __func__, micmv);
+
+ return btn;
+}
+
+static int taiko_get_button_mask(const int btn)
+{
+ int mask = 0;
+ switch (btn) {
+ case 0:
+ mask = SND_JACK_BTN_0;
+ break;
+ case 1:
+ mask = SND_JACK_BTN_1;
+ break;
+ case 2:
+ mask = SND_JACK_BTN_2;
+ break;
+ case 3:
+ mask = SND_JACK_BTN_3;
+ break;
+ case 4:
+ mask = SND_JACK_BTN_4;
+ break;
+ case 5:
+ mask = SND_JACK_BTN_5;
+ break;
+ case 6:
+ mask = SND_JACK_BTN_6;
+ break;
+ case 7:
+ mask = SND_JACK_BTN_7;
+ break;
+ }
+ return mask;
+}
+
+static irqreturn_t taiko_dce_handler(int irq, void *data)
+{
+ int i, mask;
+ short dce, sta;
+ s32 mv, mv_s, stamv_s;
+ bool vddio;
+ int btn = -1, meas = 0;
+ struct taiko_priv *priv = data;
+ const struct taiko_mbhc_btn_detect_cfg *d =
+ TAIKO_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
+ short btnmeas[d->n_btn_meas + 1];
+ struct snd_soc_codec *codec = priv->codec;
+ struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+ int n_btn_meas = d->n_btn_meas;
+ u8 mbhc_status = snd_soc_read(codec, TAIKO_A_CDC_MBHC_B1_STATUS) & 0x3E;
+
+ pr_debug("%s: enter\n", __func__);
+
+ TAIKO_ACQUIRE_LOCK(priv->codec_resource_lock);
+ if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
+ pr_debug("%s: mbhc is being recovered, skip button press\n",
+ __func__);
+ goto done;
+ }
+
+ priv->mbhc_state = MBHC_STATE_POTENTIAL;
+
+ if (!priv->mbhc_polling_active) {
+ pr_warn("%s: mbhc polling is not active, skip button press\n",
+ __func__);
+ goto done;
+ }
+
+ dce = taiko_codec_read_dce_result(codec);
+ mv = taiko_codec_sta_dce_v(codec, 1, dce);
+
+ /* If GPIO interrupt already kicked in, ignore button press */
+ if (priv->in_gpio_handler) {
+ pr_debug("%s: GPIO State Changed, ignore button press\n",
+ __func__);
+ btn = -1;
+ goto done;
+ }
+
+ vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
+ priv->mbhc_micbias_switched);
+ mv_s = vddio ? taiko_scale_v_micb_vddio(priv, mv, false) : mv;
+
+ if (mbhc_status != TAIKO_MBHC_STATUS_REL_DETECTION) {
+ if (priv->mbhc_last_resume &&
+ !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
+ pr_debug("%s: Button is already released shortly after resume\n",
+ __func__);
+ n_btn_meas = 0;
+ } else {
+ pr_debug("%s: Button is already released without resume",
+ __func__);
+ sta = taiko_codec_read_sta_result(codec);
+ stamv_s = taiko_codec_sta_dce_v(codec, 0, sta);
+ if (vddio)
+ stamv_s = taiko_scale_v_micb_vddio(priv,
+ stamv_s,
+ false);
+ btn = taiko_determine_button(priv, mv_s);
+ if (btn != taiko_determine_button(priv, stamv_s))
+ btn = -1;
+ goto done;
+ }
+ }
+
+ /* determine pressed button */
+ btnmeas[meas++] = taiko_determine_button(priv, mv_s);
+ pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n", __func__,
+ meas - 1, dce, mv, mv_s, btnmeas[meas - 1]);
+ if (n_btn_meas == 0)
+ btn = btnmeas[0];
+ for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
+ dce = taiko_codec_sta_dce(codec, 1, false);
+ mv = taiko_codec_sta_dce_v(codec, 1, dce);
+ mv_s = vddio ? taiko_scale_v_micb_vddio(priv, mv, false) : mv;
+
+ btnmeas[meas] = taiko_determine_button(priv, mv_s);
+ pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n",
+ __func__, meas, dce, mv, mv_s, btnmeas[meas]);
+ /* if large enough measurements are collected,
+ * start to check if last all n_btn_con measurements were
+ * in same button low/high range */
+ if (meas + 1 >= d->n_btn_con) {
+ for (i = 0; i < d->n_btn_con; i++)
+ if ((btnmeas[meas] < 0) ||
+ (btnmeas[meas] != btnmeas[meas - i]))
+ break;
+ if (i == d->n_btn_con) {
+ /* button pressed */
+ btn = btnmeas[meas];
+ break;
+ } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
+ /* if left measurements are less than n_btn_con,
+ * it's impossible to find button number */
+ break;
+ }
+ }
+ }
+
+ if (btn >= 0) {
+ if (priv->in_gpio_handler) {
+ pr_debug(
+ "%s: GPIO already triggered, ignore button press\n",
+ __func__);
+ goto done;
+ }
+ mask = taiko_get_button_mask(btn);
+ priv->buttons_pressed |= mask;
+ wcd9xxx_lock_sleep(core);
+ if (schedule_delayed_work(&priv->mbhc_btn_dwork,
+ msecs_to_jiffies(400)) == 0) {
+ WARN(1, "Button pressed twice without release event\n");
+ wcd9xxx_unlock_sleep(core);
+ }
+ } else {
+ pr_debug("%s: bogus button press, too short press?\n",
+ __func__);
+ }
+
+ done:
+ pr_debug("%s: leave\n", __func__);
+ TAIKO_RELEASE_LOCK(priv->codec_resource_lock);
+ return IRQ_HANDLED;
+}
+
+static int taiko_is_fake_press(struct taiko_priv *priv)
+{
+ int i;
+ int r = 0;
+ struct snd_soc_codec *codec = priv->codec;
+ const int dces = MBHC_NUM_DCE_PLUG_DETECT;
+ s16 mb_v, v_ins_hu, v_ins_h;
+
+ v_ins_hu = taiko_get_current_v_ins(priv, true);
+ v_ins_h = taiko_get_current_v_ins(priv, false);
+
+ for (i = 0; i < dces; i++) {
+ usleep_range(10000, 10000);
+ if (i == 0) {
+ mb_v = taiko_codec_sta_dce(codec, 0, true);
+ pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
+ taiko_codec_sta_dce_v(codec, 0, mb_v));
+ if (mb_v < (s16)priv->mbhc_data.v_b1_hu ||
+ mb_v > v_ins_hu) {
+ r = 1;
+ break;
+ }
+ } else {
+ mb_v = taiko_codec_sta_dce(codec, 1, true);
+ pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
+ taiko_codec_sta_dce_v(codec, 1, mb_v));
+ if (mb_v < (s16)priv->mbhc_data.v_b1_h ||
+ mb_v > v_ins_h) {
+ r = 1;
+ break;
+ }
+ }
+ }
+
+ return r;
+}
+
+static irqreturn_t taiko_release_handler(int irq, void *data)
+{
+ int ret;
+ struct taiko_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+
+ pr_debug("%s: enter\n", __func__);
+
+ TAIKO_ACQUIRE_LOCK(priv->codec_resource_lock);
+ priv->mbhc_state = MBHC_STATE_RELEASE;
+
+ taiko_codec_drive_v_to_micbias(codec, 10000);
+
+ if (priv->buttons_pressed & TAIKO_JACK_BUTTON_MASK) {
+ ret = taiko_cancel_btn_work(priv);
+ if (ret == 0) {
+ pr_debug("%s: Reporting long button release event\n",
+ __func__);
+ if (priv->mbhc_cfg.button_jack)
+ taiko_snd_soc_jack_report(priv,
+ priv->mbhc_cfg.button_jack, 0,
+ priv->buttons_pressed);
+ } else {
+ if (taiko_is_fake_press(priv)) {
+ pr_debug("%s: Fake button press interrupt\n",
+ __func__);
+ } else if (priv->mbhc_cfg.button_jack) {
+ if (priv->in_gpio_handler) {
+ pr_debug("%s: GPIO kicked in, ignore\n",
+ __func__);
+ } else {
+ pr_debug(
+ "%s: Reporting short button press and release\n",
+ __func__);
+ taiko_snd_soc_jack_report(priv,
+ priv->mbhc_cfg.button_jack,
+ priv->buttons_pressed,
+ priv->buttons_pressed);
+ taiko_snd_soc_jack_report(priv,
+ priv->mbhc_cfg.button_jack, 0,
+ priv->buttons_pressed);
+ }
+ }
+ }
+
+ priv->buttons_pressed &= ~TAIKO_JACK_BUTTON_MASK;
+ }
+
+ taiko_codec_calibrate_hs_polling(codec);
+
+ if (priv->mbhc_cfg.gpio)
+ msleep(TAIKO_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
+
+ taiko_codec_start_hs_polling(codec);
+
+ pr_debug("%s: leave\n", __func__);
+ TAIKO_RELEASE_LOCK(priv->codec_resource_lock);
+ return IRQ_HANDLED;
+}
+
+static void taiko_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ const struct taiko_mbhc_general_cfg *generic =
+ TAIKO_MBHC_CAL_GENERAL_PTR(taiko->mbhc_cfg.calibration);
+
+ if (!taiko->mclk_enabled && !taiko->mbhc_polling_active)
+ taiko_codec_enable_config_mode(codec, 1);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
+
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
+
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
+ if (!taiko->mclk_enabled && !taiko->mbhc_polling_active)
+ taiko_codec_enable_config_mode(codec, 0);
+
+ snd_soc_write(codec, TAIKO_A_MBHC_SCALING_MUX_1, 0x00);
+}
+
+static void taiko_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ taiko_codec_shutdown_hs_removal_detect(codec);
+
+ if (!taiko->mclk_enabled) {
+ taiko_codec_disable_clock_block(codec);
+ taiko_codec_enable_bandgap(codec, TAIKO_BANDGAP_OFF);
+ }
+
+ taiko->mbhc_polling_active = false;
+ taiko->mbhc_state = MBHC_STATE_NONE;
+}
+
+static irqreturn_t taiko_hphl_ocp_irq(int irq, void *data)
+{
+ struct taiko_priv *taiko = data;
+ struct snd_soc_codec *codec;
+
+ pr_info("%s: received HPHL OCP irq\n", __func__);
+
+ if (taiko) {
+ codec = taiko->codec;
+ if (taiko->hphlocp_cnt++ < TAIKO_OCP_ATTEMPT) {
+ pr_info("%s: retry\n", __func__);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ } else {
+ wcd9xxx_disable_irq(codec->control_data,
+ TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ taiko->hphlocp_cnt = 0;
+ taiko->hph_status |= SND_JACK_OC_HPHL;
+ if (taiko->mbhc_cfg.headset_jack)
+ taiko_snd_soc_jack_report(taiko,
+ taiko->mbhc_cfg.headset_jack,
+ taiko->hph_status,
+ TAIKO_JACK_MASK);
+ }
+ } else {
+ pr_err("%s: Bad taiko private data\n", __func__);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t taiko_hphr_ocp_irq(int irq, void *data)
+{
+ struct taiko_priv *taiko = data;
+ struct snd_soc_codec *codec;
+
+ pr_info("%s: received HPHR OCP irq\n", __func__);
+
+ if (taiko) {
+ codec = taiko->codec;
+ if (taiko->hphrocp_cnt++ < TAIKO_OCP_ATTEMPT) {
+ pr_info("%s: retry\n", __func__);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10,
+ 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10,
+ 0x10);
+ } else {
+ wcd9xxx_disable_irq(codec->control_data,
+ TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ taiko->hphrocp_cnt = 0;
+ taiko->hph_status |= SND_JACK_OC_HPHR;
+ if (taiko->mbhc_cfg.headset_jack)
+ taiko_snd_soc_jack_report(taiko,
+ taiko->mbhc_cfg.headset_jack,
+ taiko->hph_status,
+ TAIKO_JACK_MASK);
+ }
+ } else {
+ pr_err("%s: Bad taiko private data\n", __func__);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static bool taiko_is_inval_ins_range(struct snd_soc_codec *codec,
+ s32 mic_volt, bool highhph, bool *highv)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ bool invalid = false;
+ s16 v_hs_max;
+
+ /* Perform this check only when the high voltage headphone
+ * needs to be considered as invalid
+ */
+ v_hs_max = taiko_get_current_v_hs_max(taiko);
+ *highv = mic_volt > v_hs_max;
+ if (!highhph && *highv)
+ invalid = true;
+ else if (mic_volt < taiko->mbhc_data.v_inval_ins_high &&
+ (mic_volt > taiko->mbhc_data.v_inval_ins_low))
+ invalid = true;
+
+ return invalid;
+}
+
+static bool taiko_is_inval_ins_delta(struct snd_soc_codec *codec,
+ int mic_volt, int mic_volt_prev,
+ int threshold)
+{
+ return abs(mic_volt - mic_volt_prev) > threshold;
+}
+
+/* called under codec_resource_lock acquisition */
+void taiko_find_plug_and_report(struct snd_soc_codec *codec,
+ enum taiko_mbhc_plug_type plug_type)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ if (plug_type == PLUG_TYPE_HEADPHONE &&
+ taiko->current_plug == PLUG_TYPE_NONE) {
+ /* Nothing was reported previously
+ * report a headphone or unsupported
+ */
+ taiko_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+ taiko_codec_cleanup_hs_polling(codec);
+ } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+ if (taiko->current_plug == PLUG_TYPE_HEADSET)
+ taiko_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+ else if (taiko->current_plug == PLUG_TYPE_HEADPHONE)
+ taiko_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+
+ taiko_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
+ taiko_codec_cleanup_hs_polling(codec);
+ } else if (plug_type == PLUG_TYPE_HEADSET) {
+ /* If Headphone was reported previously, this will
+ * only report the mic line
+ */
+ taiko_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+ msleep(100);
+ taiko_codec_start_hs_polling(codec);
+ } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+ if (taiko->current_plug == PLUG_TYPE_NONE)
+ taiko_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+ taiko_codec_cleanup_hs_polling(codec);
+ pr_debug("setup mic trigger for further detection\n");
+ taiko->lpi_enabled = true;
+ taiko_codec_enable_hs_detect(codec, 1,
+ MBHC_USE_MB_TRIGGER |
+ MBHC_USE_HPHL_TRIGGER,
+ false);
+ } else {
+ WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
+ taiko->current_plug, plug_type);
+ }
+}
+
+/* should be called under interrupt context that hold suspend */
+static void taiko_schedule_hs_detect_plug(struct taiko_priv *taiko)
+{
+ pr_debug("%s: scheduling taiko_hs_correct_gpio_plug\n", __func__);
+ taiko->hs_detect_work_stop = false;
+ wcd9xxx_lock_sleep(taiko->codec->control_data);
+ schedule_work(&taiko->hs_correct_plug_work);
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_cancel_hs_detect_plug(struct taiko_priv *taiko)
+{
+ pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
+ taiko->hs_detect_work_stop = true;
+ wmb();
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ if (cancel_work_sync(&taiko->hs_correct_plug_work)) {
+ pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
+ wcd9xxx_unlock_sleep(taiko->codec->control_data);
+ }
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+}
+
+static bool taiko_hs_gpio_level_remove(struct taiko_priv *taiko)
+{
+ return (gpio_get_value_cansleep(taiko->mbhc_cfg.gpio) !=
+ taiko->mbhc_cfg.gpio_level_insert);
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
+{
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x01, on);
+ if (on)
+ usleep_range(5000, 5000);
+}
+
+/* called under codec_resource_lock acquisition and mbhc override = 1 */
+static enum taiko_mbhc_plug_type
+taiko_codec_get_plug_type(struct snd_soc_codec *codec, bool highhph)
+{
+ int i;
+ bool gndswitch, vddioswitch;
+ int scaled;
+ struct taiko_mbhc_plug_type_cfg *plug_type_ptr;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ const bool vddio = (taiko->mbhc_data.micb_mv != VDDIO_MICBIAS_MV);
+ int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
+ enum taiko_mbhc_plug_type plug_type[num_det];
+ s16 mb_v[num_det];
+ s32 mic_mv[num_det];
+ bool inval;
+ bool highdelta;
+ bool ahighv = false, highv;
+
+ /* make sure override is on */
+ WARN_ON(!(snd_soc_read(codec, TAIKO_A_CDC_MBHC_B1_CTL) & 0x04));
+
+ /* GND and MIC swap detection requires at least 2 rounds of DCE */
+ BUG_ON(num_det < 2);
+
+ plug_type_ptr =
+ TAIKO_MBHC_CAL_PLUG_TYPE_PTR(taiko->mbhc_cfg.calibration);
+
+ plug_type[0] = PLUG_TYPE_INVALID;
+
+ /* performs DCEs for N times
+ * 1st: check if voltage is in invalid range
+ * 2nd - N-2nd: check voltage range and delta
+ * N-1st: check voltage range, delta with HPHR GND switch
+ * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
+ for (i = 0; i < num_det; i++) {
+ gndswitch = (i == (num_det - 1 - vddio));
+ vddioswitch = (vddio && ((i == num_det - 1) ||
+ (i == num_det - 2)));
+ if (i == 0) {
+ mb_v[i] = taiko_codec_setup_hs_polling(codec);
+ mic_mv[i] = taiko_codec_sta_dce_v(codec, 1 , mb_v[i]);
+ inval = taiko_is_inval_ins_range(codec, mic_mv[i],
+ highhph, &highv);
+ ahighv |= highv;
+ scaled = mic_mv[i];
+ } else {
+ if (vddioswitch)
+ __taiko_codec_switch_micbias(taiko->codec, 1,
+ false, false);
+ if (gndswitch)
+ taiko_codec_hphr_gnd_switch(codec, true);
+ mb_v[i] = __taiko_codec_sta_dce(codec, 1, true, true);
+ mic_mv[i] = taiko_codec_sta_dce_v(codec, 1 , mb_v[i]);
+ if (vddioswitch)
+ scaled = taiko_scale_v_micb_vddio(taiko,
+ mic_mv[i],
+ false);
+ else
+ scaled = mic_mv[i];
+ /* !gndswitch & vddioswitch means the previous DCE
+ * was done with gndswitch, don't compare with DCE
+ * with gndswitch */
+ highdelta = taiko_is_inval_ins_delta(codec, scaled,
+ mic_mv[i - !gndswitch - vddioswitch],
+ TAIKO_MBHC_FAKE_INS_DELTA_SCALED_MV);
+ inval = (taiko_is_inval_ins_range(codec, mic_mv[i],
+ highhph, &highv) ||
+ highdelta);
+ ahighv |= highv;
+ if (gndswitch)
+ taiko_codec_hphr_gnd_switch(codec, false);
+ if (vddioswitch)
+ __taiko_codec_switch_micbias(taiko->codec, 0,
+ false, false);
+ /* claim UNSUPPORTED plug insertion when
+ * good headset is detected but HPHR GND switch makes
+ * delta difference */
+ if (i == (num_det - 2) && highdelta && !ahighv)
+ plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
+ else if (i == (num_det - 1) && inval)
+ plug_type[0] = PLUG_TYPE_INVALID;
+ }
+ pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, VDDIO %d, inval %d\n",
+ __func__, i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled,
+ gndswitch, vddioswitch, inval);
+ /* don't need to run further DCEs */
+ if (ahighv && inval)
+ break;
+ mic_mv[i] = scaled;
+ }
+
+ for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
+ i < num_det; i++) {
+ /*
+ * If we are here, means none of the all
+ * measurements are fake, continue plug type detection.
+ * If all three measurements do not produce same
+ * plug type, restart insertion detection
+ */
+ if (mic_mv[i] < plug_type_ptr->v_no_mic) {
+ plug_type[i] = PLUG_TYPE_HEADPHONE;
+ pr_debug("%s: Detect attempt %d, detected Headphone\n",
+ __func__, i);
+ } else if (highhph && (mic_mv[i] > plug_type_ptr->v_hs_max)) {
+ plug_type[i] = PLUG_TYPE_HIGH_HPH;
+ pr_debug(
+ "%s: Detect attempt %d, detected High Headphone\n",
+ __func__, i);
+ } else {
+ plug_type[i] = PLUG_TYPE_HEADSET;
+ pr_debug("%s: Detect attempt %d, detected Headset\n",
+ __func__, i);
+ }
+
+ if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
+ pr_err("%s: Detect attempt %d and %d are not same",
+ __func__, i - 1, i);
+ plug_type[0] = PLUG_TYPE_INVALID;
+ inval = true;
+ break;
+ }
+ }
+
+ pr_debug("%s: Detected plug type %d\n", __func__, plug_type[0]);
+ return plug_type[0];
+}
+
+static void taiko_hs_correct_gpio_plug(struct work_struct *work)
+{
+ struct taiko_priv *taiko;
+ struct snd_soc_codec *codec;
+ int retry = 0, pt_gnd_mic_swap_cnt = 0;
+ bool correction = false;
+ enum taiko_mbhc_plug_type plug_type;
+ unsigned long timeout;
+
+ taiko = container_of(work, struct taiko_priv, hs_correct_plug_work);
+ codec = taiko->codec;
+
+ pr_debug("%s: enter\n", __func__);
+ taiko->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+
+ /* Keep override on during entire plug type correction work.
+ *
+ * This is okay under the assumption that any GPIO irqs which use
+ * MBHC block cancel and sync this work so override is off again
+ * prior to GPIO interrupt handler's MBHC block usage.
+ * Also while this correction work is running, we can guarantee
+ * DAPM doesn't use any MBHC block as this work only runs with
+ * headphone detection.
+ */
+ taiko_turn_onoff_override(codec, true);
+
+ timeout = jiffies + msecs_to_jiffies(TAIKO_HS_DETECT_PLUG_TIME_MS);
+ while (!time_after(jiffies, timeout)) {
+ ++retry;
+ rmb();
+ if (taiko->hs_detect_work_stop) {
+ pr_debug("%s: stop requested\n", __func__);
+ break;
+ }
+
+ msleep(TAIKO_HS_DETECT_PLUG_INERVAL_MS);
+ if (taiko_hs_gpio_level_remove(taiko)) {
+ pr_debug("%s: GPIO value is low\n", __func__);
+ break;
+ }
+
+ /* can race with removal interrupt */
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ plug_type = taiko_codec_get_plug_type(codec, true);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+
+ if (plug_type == PLUG_TYPE_INVALID) {
+ pr_debug("Invalid plug in attempt # %d\n", retry);
+ if (retry == NUM_ATTEMPTS_TO_REPORT &&
+ taiko->current_plug == PLUG_TYPE_NONE) {
+ taiko_codec_report_plug(codec, 1,
+ SND_JACK_HEADPHONE);
+ }
+ } else if (plug_type == PLUG_TYPE_HEADPHONE) {
+ pr_debug("Good headphone detected, continue polling mic\n");
+ if (taiko->current_plug == PLUG_TYPE_NONE)
+ taiko_codec_report_plug(codec, 1,
+ SND_JACK_HEADPHONE);
+ } else {
+ if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+ pt_gnd_mic_swap_cnt++;
+ if (pt_gnd_mic_swap_cnt <
+ TAIKO_MBHC_GND_MIC_SWAP_THRESHOLD)
+ continue;
+ else if (pt_gnd_mic_swap_cnt >
+ TAIKO_MBHC_GND_MIC_SWAP_THRESHOLD) {
+ /* This is due to GND/MIC switch didn't
+ * work, Report unsupported plug */
+ } else if (taiko->mbhc_cfg.swap_gnd_mic) {
+ /* if switch is toggled, check again,
+ * otherwise report unsupported plug */
+ if (taiko->mbhc_cfg.swap_gnd_mic(codec))
+ continue;
+ }
+ } else
+ pt_gnd_mic_swap_cnt = 0;
+
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ /* Turn off override */
+ taiko_turn_onoff_override(codec, false);
+ /* The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
+ */
+ taiko_find_plug_and_report(codec, plug_type);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ pr_debug("Attempt %d found correct plug %d\n", retry,
+ plug_type);
+ correction = true;
+ break;
+ }
+ }
+
+ /* Turn off override */
+ if (!correction)
+ taiko_turn_onoff_override(codec, false);
+
+ taiko->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+ pr_debug("%s: leave\n", __func__);
+ /* unlock sleep */
+ wcd9xxx_unlock_sleep(taiko->codec->control_data);
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_codec_decide_gpio_plug(struct snd_soc_codec *codec)
+{
+ enum taiko_mbhc_plug_type plug_type;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: enter\n", __func__);
+
+ taiko_turn_onoff_override(codec, true);
+ plug_type = taiko_codec_get_plug_type(codec, true);
+ taiko_turn_onoff_override(codec, false);
+
+ if (taiko_hs_gpio_level_remove(taiko)) {
+ pr_debug("%s: GPIO value is low when determining plug\n",
+ __func__);
+ return;
+ }
+
+ if (plug_type == PLUG_TYPE_INVALID ||
+ plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+ taiko_schedule_hs_detect_plug(taiko);
+ } else if (plug_type == PLUG_TYPE_HEADPHONE) {
+ taiko_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+
+ taiko_schedule_hs_detect_plug(taiko);
+ } else {
+ pr_debug("%s: Valid plug found, determine plug type %d\n",
+ __func__, plug_type);
+ taiko_find_plug_and_report(codec, plug_type);
+ }
+}
+
+/* called under codec_resource_lock acquisition */
+static void taiko_codec_detect_plug_type(struct snd_soc_codec *codec)
+{
+ enum taiko_mbhc_plug_type plug_type;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ const struct taiko_mbhc_plug_detect_cfg *plug_det =
+ TAIKO_MBHC_CAL_PLUG_DET_PTR(taiko->mbhc_cfg.calibration);
+
+ /* Turn on the override,
+ * taiko_codec_setup_hs_polling requires override on */
+ taiko_turn_onoff_override(codec, true);
+
+ if (plug_det->t_ins_complete > 20)
+ msleep(plug_det->t_ins_complete);
+ else
+ usleep_range(plug_det->t_ins_complete * 1000,
+ plug_det->t_ins_complete * 1000);
+
+ if (taiko->mbhc_cfg.gpio) {
+ /* Turn off the override */
+ taiko_turn_onoff_override(codec, false);
+ if (taiko_hs_gpio_level_remove(taiko))
+ pr_debug(
+ "%s: GPIO value is low when determining plug\n",
+ __func__);
+ else
+ taiko_codec_decide_gpio_plug(codec);
+ return;
+ }
+
+ plug_type = taiko_codec_get_plug_type(codec, false);
+ taiko_turn_onoff_override(codec, false);
+
+ if (plug_type == PLUG_TYPE_INVALID) {
+ pr_debug("%s: Invalid plug type detected\n", __func__);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+ taiko_codec_cleanup_hs_polling(codec);
+ taiko_codec_enable_hs_detect(codec, 1,
+ MBHC_USE_MB_TRIGGER |
+ MBHC_USE_HPHL_TRIGGER, false);
+ } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+ pr_debug("%s: GND-MIC swapped plug type detected\n", __func__);
+ taiko_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
+ taiko_codec_cleanup_hs_polling(codec);
+ taiko_codec_enable_hs_detect(codec, 0, 0, false);
+ } else if (plug_type == PLUG_TYPE_HEADPHONE) {
+ pr_debug("%s: Headphone Detected\n", __func__);
+ taiko_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+ taiko_codec_cleanup_hs_polling(codec);
+ taiko_codec_enable_hs_detect(codec, 0, 0, false);
+ } else if (plug_type == PLUG_TYPE_HEADSET) {
+ pr_debug("%s: Headset detected\n", __func__);
+ taiko_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+
+ /* avoid false button press detect */
+ msleep(50);
+ taiko_codec_start_hs_polling(codec);
+ }
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void taiko_hs_insert_irq_gpio(struct taiko_priv *priv, bool is_removal)
+{
+ struct snd_soc_codec *codec = priv->codec;
+
+ if (!is_removal) {
+ pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
+
+ rmb();
+ if (priv->lpi_enabled)
+ msleep(100);
+
+ rmb();
+ if (!priv->lpi_enabled) {
+ pr_debug("%s: lpi is disabled\n", __func__);
+ } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
+ priv->mbhc_cfg.gpio_level_insert) {
+ pr_debug(
+ "%s: Valid insertion, detect plug type\n", __func__);
+ taiko_codec_decide_gpio_plug(codec);
+ } else {
+ pr_debug(
+ "%s: Invalid insertion stop plug detection\n",
+ __func__);
+ }
+ } else {
+ pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
+ }
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void taiko_hs_insert_irq_nogpio(struct taiko_priv *priv, bool is_removal,
+ bool is_mb_trigger)
+{
+ int ret;
+ struct snd_soc_codec *codec = priv->codec;
+ struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
+
+ if (is_removal) {
+ /* cancel possiblely running hs detect work */
+ taiko_cancel_hs_detect_plug(priv);
+
+ /*
+ * If headphone is removed while playback is in progress,
+ * it is possible that micbias will be switched to VDDIO.
+ */
+ taiko_codec_switch_micbias(codec, 0);
+ if (priv->current_plug == PLUG_TYPE_HEADPHONE)
+ taiko_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+ else if (priv->current_plug == PLUG_TYPE_GND_MIC_SWAP)
+ taiko_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
+ else
+ WARN(1, "%s: Unexpected current plug type %d\n",
+ __func__, priv->current_plug);
+ taiko_codec_shutdown_hs_removal_detect(codec);
+ taiko_codec_enable_hs_detect(codec, 1,
+ MBHC_USE_MB_TRIGGER |
+ MBHC_USE_HPHL_TRIGGER,
+ true);
+ } else if (is_mb_trigger && !is_removal) {
+ pr_debug("%s: Waiting for Headphone left trigger\n",
+ __func__);
+ wcd9xxx_lock_sleep(core);
+ if (schedule_delayed_work(&priv->mbhc_insert_dwork,
+ usecs_to_jiffies(1000000)) == 0) {
+ pr_err("%s: mbhc_insert_dwork is already scheduled\n",
+ __func__);
+ wcd9xxx_unlock_sleep(core);
+ }
+ taiko_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
+ false);
+ } else {
+ ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
+ if (ret != 0) {
+ pr_debug(
+ "%s: Complete plug insertion, Detecting plug type\n",
+ __func__);
+ taiko_codec_detect_plug_type(codec);
+ wcd9xxx_unlock_sleep(core);
+ } else {
+ wcd9xxx_enable_irq(codec->control_data,
+ TAIKO_IRQ_MBHC_INSERTION);
+ pr_err("%s: Error detecting plug insertion\n",
+ __func__);
+ }
+ }
+}
+
+static irqreturn_t taiko_hs_insert_irq(int irq, void *data)
+{
+ bool is_mb_trigger, is_removal;
+ struct taiko_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+
+ pr_debug("%s: enter\n", __func__);
+ TAIKO_ACQUIRE_LOCK(priv->codec_resource_lock);
+ wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+
+ is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
+ 0x10);
+ is_removal = !!(snd_soc_read(codec, TAIKO_A_CDC_MBHC_INT_CTL) & 0x02);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
+
+ /* Turn off both HPH and MIC line schmitt triggers */
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x13, 0x00);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+
+ if (priv->mbhc_cfg.gpio)
+ taiko_hs_insert_irq_gpio(priv, is_removal);
+ else
+ taiko_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
+
+ TAIKO_RELEASE_LOCK(priv->codec_resource_lock);
+ return IRQ_HANDLED;
+}
+
+static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
+{
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ const struct taiko_mbhc_plug_type_cfg *plug_type =
+ TAIKO_MBHC_CAL_PLUG_TYPE_PTR(taiko->mbhc_cfg.calibration);
+ const s16 v_hs_max = taiko_get_current_v_hs_max(taiko);
+
+ return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
+ && (mic_mv < v_hs_max)) ? true : false;
+}
+
+/* called under codec_resource_lock acquisition
+ * returns true if mic voltage range is back to normal insertion
+ * returns false either if timedout or removed */
+static bool taiko_hs_remove_settle(struct snd_soc_codec *codec)
+{
+ int i;
+ bool timedout, settled = false;
+ s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+ short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+ unsigned long retry = 0, timeout;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ const s16 v_hs_max = taiko_get_current_v_hs_max(taiko);
+
+ timeout = jiffies + msecs_to_jiffies(TAIKO_HS_DETECT_PLUG_TIME_MS);
+ while (!(timedout = time_after(jiffies, timeout))) {
+ retry++;
+ if (taiko->mbhc_cfg.gpio && taiko_hs_gpio_level_remove(taiko)) {
+ pr_debug("%s: GPIO indicates removal\n", __func__);
+ break;
+ }
+
+ if (taiko->mbhc_cfg.gpio) {
+ if (retry > 1)
+ msleep(250);
+ else
+ msleep(50);
+ }
+
+ if (taiko->mbhc_cfg.gpio && taiko_hs_gpio_level_remove(taiko)) {
+ pr_debug("%s: GPIO indicates removal\n", __func__);
+ break;
+ }
+
+ for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+ mb_v[i] = taiko_codec_sta_dce(codec, 1, true);
+ mic_mv[i] = taiko_codec_sta_dce_v(codec, 1 , mb_v[i]);
+ pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
+ __func__, retry, mic_mv[i], mb_v[i]);
+ }
+
+ if (taiko->mbhc_cfg.gpio && taiko_hs_gpio_level_remove(taiko)) {
+ pr_debug("%s: GPIO indicates removal\n", __func__);
+ break;
+ }
+
+ if (taiko->current_plug == PLUG_TYPE_NONE) {
+ pr_debug("%s : headset/headphone is removed\n",
+ __func__);
+ break;
+ }
+
+ for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
+ if (!is_valid_mic_voltage(codec, mic_mv[i]))
+ break;
+
+ if (i == MBHC_NUM_DCE_PLUG_DETECT) {
+ pr_debug("%s: MIC voltage settled\n", __func__);
+ settled = true;
+ msleep(200);
+ break;
+ }
+
+ /* only for non-GPIO remove irq */
+ if (!taiko->mbhc_cfg.gpio) {
+ for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
+ if (mic_mv[i] < v_hs_max)
+ break;
+ if (i == MBHC_NUM_DCE_PLUG_DETECT) {
+ pr_debug("%s: Headset is removed\n", __func__);
+ break;
+ }
+ }
+ }
+
+ if (timedout)
+ pr_debug("%s: Microphone did not settle in %d seconds\n",
+ __func__, TAIKO_HS_DETECT_PLUG_TIME_MS);
+ return settled;
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void taiko_hs_remove_irq_gpio(struct taiko_priv *priv)
+{
+ struct snd_soc_codec *codec = priv->codec;
+
+ if (taiko_hs_remove_settle(codec))
+ taiko_codec_start_hs_polling(codec);
+ pr_debug("%s: remove settle done\n", __func__);
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
+static void taiko_hs_remove_irq_nogpio(struct taiko_priv *priv)
+{
+ short bias_value;
+ bool removed = true;
+ struct snd_soc_codec *codec = priv->codec;
+ const struct taiko_mbhc_general_cfg *generic =
+ TAIKO_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
+ int min_us = TAIKO_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
+
+ if (priv->current_plug != PLUG_TYPE_HEADSET) {
+ pr_debug("%s(): Headset is not inserted, ignore removal\n",
+ __func__);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL,
+ 0x08, 0x08);
+ return;
+ }
+
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
+
+ do {
+ bias_value = taiko_codec_sta_dce(codec, 1, true);
+ pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
+ taiko_codec_sta_dce_v(codec, 1, bias_value), min_us);
+ if (bias_value < taiko_get_current_v_ins(priv, false)) {
+ pr_debug("%s: checking false removal\n", __func__);
+ msleep(500);
+ removed = !taiko_hs_remove_settle(codec);
+ pr_debug("%s: headset %sactually removed\n", __func__,
+ removed ? "" : "not ");
+ break;
+ }
+ min_us -= priv->mbhc_data.t_dce;
+ } while (min_us > 0);
+
+ if (removed) {
+ /* cancel possiblely running hs detect work */
+ taiko_cancel_hs_detect_plug(priv);
+ /*
+ * If this removal is not false, first check the micbias
+ * switch status and switch it to LDOH if it is already
+ * switched to VDDIO.
+ */
+ taiko_codec_switch_micbias(codec, 0);
+
+ taiko_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+ taiko_codec_cleanup_hs_polling(codec);
+ taiko_codec_enable_hs_detect(codec, 1,
+ MBHC_USE_MB_TRIGGER |
+ MBHC_USE_HPHL_TRIGGER,
+ true);
+ } else {
+ taiko_codec_start_hs_polling(codec);
+ }
+}
+
+static irqreturn_t taiko_hs_remove_irq(int irq, void *data)
+{
+ struct taiko_priv *priv = data;
+ bool vddio;
+ pr_debug("%s: enter, removal interrupt\n", __func__);
+
+ TAIKO_ACQUIRE_LOCK(priv->codec_resource_lock);
+ vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
+ priv->mbhc_micbias_switched);
+ if (vddio)
+ __taiko_codec_switch_micbias(priv->codec, 0, false, true);
+
+ if (priv->mbhc_cfg.gpio)
+ taiko_hs_remove_irq_gpio(priv);
+ else
+ taiko_hs_remove_irq_nogpio(priv);
+
+ /* if driver turned off vddio switch and headset is not removed,
+ * turn on the vddio switch back, if headset is removed then vddio
+ * switch is off by time now and shouldn't be turn on again from here */
+ if (vddio && priv->current_plug == PLUG_TYPE_HEADSET)
+ __taiko_codec_switch_micbias(priv->codec, 1, true, true);
+ TAIKO_RELEASE_LOCK(priv->codec_resource_lock);
+
+ return IRQ_HANDLED;
+}
+
+static void taiko_mbhc_insert_work(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct taiko_priv *taiko;
+ struct snd_soc_codec *codec;
+ struct wcd9xxx *taiko_core;
+
+ dwork = to_delayed_work(work);
+ taiko = container_of(dwork, struct taiko_priv, mbhc_insert_dwork);
+ codec = taiko->codec;
+ taiko_core = dev_get_drvdata(codec->dev->parent);
+
+ pr_debug("%s:\n", __func__);
+
+ /* Turn off both HPH and MIC line schmitt triggers */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x13, 0x00);
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+ wcd9xxx_disable_irq_sync(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+ taiko_codec_detect_plug_type(codec);
+ wcd9xxx_unlock_sleep(taiko_core);
+}
+
+static void taiko_hs_gpio_handler(struct snd_soc_codec *codec)
+{
+ bool insert;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ bool is_removed = false;
+
+ pr_debug("%s: enter\n", __func__);
+
+ taiko->in_gpio_handler = true;
+ /* Wait here for debounce time */
+ usleep_range(TAIKO_GPIO_IRQ_DEBOUNCE_TIME_US,
+ TAIKO_GPIO_IRQ_DEBOUNCE_TIME_US);
+
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+
+ /* cancel pending button press */
+ if (taiko_cancel_btn_work(taiko))
+ pr_debug("%s: button press is canceled\n", __func__);
+
+ insert = (gpio_get_value_cansleep(taiko->mbhc_cfg.gpio) ==
+ taiko->mbhc_cfg.gpio_level_insert);
+ if ((taiko->current_plug == PLUG_TYPE_NONE) && insert) {
+ taiko->lpi_enabled = false;
+ wmb();
+
+ /* cancel detect plug */
+ taiko_cancel_hs_detect_plug(taiko);
+
+ /* Disable Mic Bias pull down and HPH Switch to GND */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg, 0x01,
+ 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x01, 0x00);
+ taiko_codec_detect_plug_type(codec);
+ } else if ((taiko->current_plug != PLUG_TYPE_NONE) && !insert) {
+ taiko->lpi_enabled = false;
+ wmb();
+
+ /* cancel detect plug */
+ taiko_cancel_hs_detect_plug(taiko);
+
+ if (taiko->current_plug == PLUG_TYPE_HEADPHONE) {
+ taiko_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+ is_removed = true;
+ } else if (taiko->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
+ taiko_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
+ is_removed = true;
+ } else if (taiko->current_plug == PLUG_TYPE_HEADSET) {
+ taiko_codec_pause_hs_polling(codec);
+ taiko_codec_cleanup_hs_polling(codec);
+ taiko_codec_report_plug(codec, 0, SND_JACK_HEADSET);
+ is_removed = true;
+ }
+
+ if (is_removed) {
+ /* Enable Mic Bias pull down and HPH Switch to GND */
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.ctl_reg, 0x01,
+ 0x01);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x01,
+ 0x01);
+ /* Make sure mic trigger is turned off */
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.ctl_reg,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec,
+ taiko->mbhc_bias_regs.mbhc_reg,
+ 0x90, 0x00);
+ /* Reset MBHC State Machine */
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL,
+ 0x08, 0x08);
+ snd_soc_update_bits(codec, TAIKO_A_CDC_MBHC_CLK_CTL,
+ 0x08, 0x00);
+ /* Turn off override */
+ taiko_turn_onoff_override(codec, false);
+ }
+ }
+
+ taiko->in_gpio_handler = false;
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ pr_debug("%s: leave\n", __func__);
+}
+
+static irqreturn_t taiko_mechanical_plug_detect_irq(int irq, void *data)
+{
+ int r = IRQ_HANDLED;
+ struct snd_soc_codec *codec = data;
+
+ if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
+ pr_warn("%s: failed to hold suspend\n", __func__);
+ r = IRQ_NONE;
+ } else {
+ taiko_hs_gpio_handler(codec);
+ wcd9xxx_unlock_sleep(codec->control_data);
+ }
+
+ return r;
+}
+
+static int taiko_mbhc_init_and_calibrate(struct taiko_priv *taiko)
+{
+ int ret = 0;
+ struct snd_soc_codec *codec = taiko->codec;
+
+ taiko->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+ taiko_mbhc_init(codec);
+ taiko_mbhc_cal(codec);
+ taiko_mbhc_calc_thres(codec);
+ taiko->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+ taiko_codec_calibrate_hs_polling(codec);
+ if (!taiko->mbhc_cfg.gpio) {
+ ret = taiko_codec_enable_hs_detect(codec, 1,
+ MBHC_USE_MB_TRIGGER |
+ MBHC_USE_HPHL_TRIGGER,
+ false);
+
+ if (IS_ERR_VALUE(ret))
+ pr_err("%s: Failed to setup MBHC detection\n",
+ __func__);
+ } else {
+ /* Enable Mic Bias pull down and HPH Switch to GND */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.ctl_reg,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, TAIKO_A_MBHC_HPH, 0x01, 0x01);
+ INIT_WORK(&taiko->hs_correct_plug_work,
+ taiko_hs_correct_gpio_plug);
+ }
+
+ if (!IS_ERR_VALUE(ret)) {
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL, 0x10, 0x10);
+ wcd9xxx_enable_irq(codec->control_data,
+ TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_enable_irq(codec->control_data,
+ TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+
+ if (taiko->mbhc_cfg.gpio) {
+ ret = request_threaded_irq(taiko->mbhc_cfg.gpio_irq,
+ NULL,
+ taiko_mechanical_plug_detect_irq,
+ (IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING),
+ "taiko-gpio", codec);
+ if (!IS_ERR_VALUE(ret)) {
+ ret = enable_irq_wake(taiko->mbhc_cfg.gpio_irq);
+ /* Bootup time detection */
+ taiko_hs_gpio_handler(codec);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static void mbhc_fw_read(struct work_struct *work)
+{
+ struct delayed_work *dwork;
+ struct taiko_priv *taiko;
+ struct snd_soc_codec *codec;
+ const struct firmware *fw;
+ int ret = -1, retry = 0;
+
+ dwork = to_delayed_work(work);
+ taiko = container_of(dwork, struct taiko_priv, mbhc_firmware_dwork);
+ codec = taiko->codec;
+
+ while (retry < MBHC_FW_READ_ATTEMPTS) {
+ retry++;
+ pr_info("%s:Attempt %d to request MBHC firmware\n",
+ __func__, retry);
+ ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
+ codec->dev);
+
+ if (ret != 0) {
+ usleep_range(MBHC_FW_READ_TIMEOUT,
+ MBHC_FW_READ_TIMEOUT);
+ } else {
+ pr_info("%s: MBHC Firmware read succesful\n", __func__);
+ break;
+ }
+ }
+
+ if (ret != 0) {
+ pr_err("%s: Cannot load MBHC firmware use default cal\n",
+ __func__);
+ } else if (taiko_mbhc_fw_validate(fw) == false) {
+ pr_err("%s: Invalid MBHC cal data size use default cal\n",
+ __func__);
+ release_firmware(fw);
+ } else {
+ taiko->mbhc_cfg.calibration = (void *)fw->data;
+ taiko->mbhc_fw = fw;
+ }
+
+ (void) taiko_mbhc_init_and_calibrate(taiko);
+}
+
+int taiko_hs_detect(struct snd_soc_codec *codec,
+ const struct taiko_mbhc_config *cfg)
+{
+ struct taiko_priv *taiko;
+ int rc = 0;
+
+ if (!codec || !cfg->calibration) {
+ pr_err("Error: no codec or calibration\n");
+ return -EINVAL;
+ }
+
+ if (cfg->mclk_rate != TAIKO_MCLK_RATE_12288KHZ) {
+ if (cfg->mclk_rate == TAIKO_MCLK_RATE_9600KHZ)
+ pr_err("Error: clock rate %dHz is not yet supported\n",
+ cfg->mclk_rate);
+ else
+ pr_err("Error: unsupported clock rate %d\n",
+ cfg->mclk_rate);
+ return -EINVAL;
+ }
+
+ taiko = snd_soc_codec_get_drvdata(codec);
+ taiko->mbhc_cfg = *cfg;
+ taiko->in_gpio_handler = false;
+ taiko->current_plug = PLUG_TYPE_NONE;
+ taiko->lpi_enabled = false;
+ taiko_get_mbhc_micbias_regs(codec, &taiko->mbhc_bias_regs);
+
+ /* Put CFILT in fast mode by default */
+ snd_soc_update_bits(codec, taiko->mbhc_bias_regs.cfilt_ctl,
+ 0x40, TAIKO_CFILT_FAST_MODE);
+ INIT_DELAYED_WORK(&taiko->mbhc_firmware_dwork, mbhc_fw_read);
+ INIT_DELAYED_WORK(&taiko->mbhc_btn_dwork, btn_lpress_fn);
+ INIT_WORK(&taiko->hphlocp_work, hphlocp_off_report);
+ INIT_WORK(&taiko->hphrocp_work, hphrocp_off_report);
+ INIT_DELAYED_WORK(&taiko->mbhc_insert_dwork, taiko_mbhc_insert_work);
+
+ if (!taiko->mbhc_cfg.read_fw_bin)
+ rc = taiko_mbhc_init_and_calibrate(taiko);
+ else
+ schedule_delayed_work(&taiko->mbhc_firmware_dwork,
+ usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(taiko_hs_detect);
+
+static unsigned long slimbus_value;
+
+static irqreturn_t taiko_slimbus_irq(int irq, void *data)
+{
+ struct taiko_priv *priv = data;
+ struct snd_soc_codec *codec = priv->codec;
+ int i, j;
+ u8 val;
+
+ for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
+ slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
+ TAIKO_SLIM_PGD_PORT_INT_STATUS0 + i);
+ for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
+ val = wcd9xxx_interface_reg_read(codec->control_data,
+ TAIKO_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
+ if (val & 0x1)
+ pr_err_ratelimited(
+ "overflow error on port %x, value %x\n",
+ i*8 + j, val);
+ if (val & 0x2)
+ pr_err_ratelimited(
+ "underflow error on port %x, value %x\n",
+ i*8 + j, val);
+ }
+ wcd9xxx_interface_reg_write(codec->control_data,
+ TAIKO_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int taiko_handle_pdata(struct taiko_priv *taiko)
+{
+ struct snd_soc_codec *codec = taiko->codec;
+ struct wcd9xxx_pdata *pdata = taiko->pdata;
+ int k1, k2, k3, rc = 0;
+ u8 leg_mode = pdata->amic_settings.legacy_mode;
+ u8 txfe_bypass = pdata->amic_settings.txfe_enable;
+ u8 txfe_buff = pdata->amic_settings.txfe_buff;
+ u8 flag = pdata->amic_settings.use_pdata;
+ u8 i = 0, j = 0;
+ u8 val_txfe = 0, value = 0;
+
+ if (!pdata) {
+ rc = -ENODEV;
+ goto done;
+ }
+
+ /* Make sure settings are correct */
+ if ((pdata->micbias.ldoh_v > TAIKO_LDOH_2P85_V) ||
+ (pdata->micbias.bias1_cfilt_sel > TAIKO_CFILT3_SEL) ||
+ (pdata->micbias.bias2_cfilt_sel > TAIKO_CFILT3_SEL) ||
+ (pdata->micbias.bias3_cfilt_sel > TAIKO_CFILT3_SEL) ||
+ (pdata->micbias.bias4_cfilt_sel > TAIKO_CFILT3_SEL)) {
+ rc = -EINVAL;
+ goto done;
+ }
+
+ /* figure out k value */
+ k1 = taiko_find_k_value(pdata->micbias.ldoh_v,
+ pdata->micbias.cfilt1_mv);
+ k2 = taiko_find_k_value(pdata->micbias.ldoh_v,
+ pdata->micbias.cfilt2_mv);
+ k3 = taiko_find_k_value(pdata->micbias.ldoh_v,
+ pdata->micbias.cfilt3_mv);
+
+ if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
+ rc = -EINVAL;
+ goto done;
+ }
+
+ /* Set voltage level and always use LDO */
+ snd_soc_update_bits(codec, TAIKO_A_LDO_H_MODE_1, 0x0C,
+ (pdata->micbias.ldoh_v << 2));
+
+ snd_soc_update_bits(codec, TAIKO_A_MICB_CFILT_1_VAL, 0xFC,
+ (k1 << 2));
+ snd_soc_update_bits(codec, TAIKO_A_MICB_CFILT_2_VAL, 0xFC,
+ (k2 << 2));
+ snd_soc_update_bits(codec, TAIKO_A_MICB_CFILT_3_VAL, 0xFC,
+ (k3 << 2));
+
+ snd_soc_update_bits(codec, TAIKO_A_MICB_1_CTL, 0x60,
+ (pdata->micbias.bias1_cfilt_sel << 5));
+ snd_soc_update_bits(codec, TAIKO_A_MICB_2_CTL, 0x60,
+ (pdata->micbias.bias2_cfilt_sel << 5));
+ snd_soc_update_bits(codec, TAIKO_A_MICB_3_CTL, 0x60,
+ (pdata->micbias.bias3_cfilt_sel << 5));
+ snd_soc_update_bits(codec, taiko->reg_addr.micb_4_ctl, 0x60,
+ (pdata->micbias.bias4_cfilt_sel << 5));
+
+ for (i = 0; i < 6; j++, i += 2) {
+ if (flag & (0x01 << i)) {
+ value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
+ val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
+ val_txfe = val_txfe |
+ ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_TX_1_2_EN + j * 10,
+ 0x10, value);
+ snd_soc_update_bits(codec,
+ TAIKO_A_TX_1_2_TEST_EN + j * 10,
+ 0x30, val_txfe);
+ }
+ if (flag & (0x01 << (i + 1))) {
+ value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
+ val_txfe = (txfe_bypass &
+ (0x01 << (i + 1))) ? 0x02 : 0x00;
+ val_txfe |= (txfe_buff &
+ (0x01 << (i + 1))) ? 0x01 : 0x00;
+ snd_soc_update_bits(codec, TAIKO_A_TX_1_2_EN + j * 10,
+ 0x01, value);
+ snd_soc_update_bits(codec,
+ TAIKO_A_TX_1_2_TEST_EN + j * 10,
+ 0x03, val_txfe);
+ }
+ }
+ if (flag & 0x40) {
+ value = (leg_mode & 0x40) ? 0x10 : 0x00;
+ value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
+ value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
+ snd_soc_update_bits(codec, TAIKO_A_TX_7_MBHC_EN,
+ 0x13, value);
+ }
+
+ if (pdata->ocp.use_pdata) {
+ /* not defined in CODEC specification */
+ if (pdata->ocp.hph_ocp_limit == 1 ||
+ pdata->ocp.hph_ocp_limit == 5) {
+ rc = -EINVAL;
+ goto done;
+ }
+ snd_soc_update_bits(codec, TAIKO_A_RX_COM_OCP_CTL,
+ 0x0F, pdata->ocp.num_attempts);
+ snd_soc_write(codec, TAIKO_A_RX_COM_OCP_COUNT,
+ ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
+ snd_soc_update_bits(codec, TAIKO_A_RX_HPH_OCP_CTL,
+ 0xE0, (pdata->ocp.hph_ocp_limit << 5));
+ }
+
+ for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
+ if (pdata->regulator[i].min_uV == 1800000 &&
+ pdata->regulator[i].max_uV == 1800000) {
+ snd_soc_write(codec, TAIKO_A_BIAS_REF_CTL,
+ 0x1C);
+ } else if (pdata->regulator[i].min_uV == 2200000 &&
+ pdata->regulator[i].max_uV == 2200000) {
+ snd_soc_write(codec, TAIKO_A_BIAS_REF_CTL,
+ 0x1E);
+ } else {
+ pr_err("%s: unsupported CDC_VDDA_RX voltage\n"
+ "min %d, max %d\n", __func__,
+ pdata->regulator[i].min_uV,
+ pdata->regulator[i].max_uV);
+ rc = -EINVAL;
+ }
+ break;
+ }
+ }
+done:
+ return rc;
+}
+
+static const struct taiko_reg_mask_val taiko_1_0_reg_defaults[] = {
+
+ /* Taiko 1.1 MICBIAS changes */
+ TAIKO_REG_VAL(TAIKO_A_MICB_1_INT_RBIAS, 0x24),
+ TAIKO_REG_VAL(TAIKO_A_MICB_2_INT_RBIAS, 0x24),
+ TAIKO_REG_VAL(TAIKO_A_MICB_3_INT_RBIAS, 0x24),
+
+ /* Taiko 1.1 HPH changes */
+ TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x57),
+ TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_LDO, 0x56),
+
+ /* Taiko 1.1 EAR PA changes */
+ TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0xA6),
+ TAIKO_REG_VAL(TAIKO_A_RX_EAR_GAIN, 0x02),
+ TAIKO_REG_VAL(TAIKO_A_RX_EAR_VCM, 0x03),
+
+
+ /* Taiko 1.1 RX Changes */
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B5_CTL, 0x78),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B5_CTL, 0x78),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX3_B5_CTL, 0x78),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX4_B5_CTL, 0x78),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B5_CTL, 0x78),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B5_CTL, 0x78),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B5_CTL, 0x78),
+
+ /* Taiko 1.1 RX1 and RX2 Changes */
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX1_B6_CTL, 0xA0),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX2_B6_CTL, 0xA0),
+
+ /* Taiko 1.1 RX3 to RX7 Changes */
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX3_B6_CTL, 0x80),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX4_B6_CTL, 0x80),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX5_B6_CTL, 0x80),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX6_B6_CTL, 0x80),
+ TAIKO_REG_VAL(TAIKO_A_CDC_RX7_B6_CTL, 0x80),
+
+};
+
+static void taiko_update_reg_defaults(struct snd_soc_codec *codec)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(taiko_1_0_reg_defaults); i++)
+ snd_soc_write(codec, taiko_1_0_reg_defaults[i].reg,
+ taiko_1_0_reg_defaults[i].val);
+}
+
+static const struct taiko_reg_mask_val taiko_codec_reg_init_val[] = {
+ /* Initialize current threshold to 350MA
+ * number of wait and run cycles to 4096
+ */
+ {TAIKO_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
+ {TAIKO_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
+
+ {TAIKO_A_QFUSE_CTL, 0xFF, 0x03},
+
+ /* Initialize gain registers to use register gain */
+ {TAIKO_A_RX_HPH_L_GAIN, 0x10, 0x10},
+ {TAIKO_A_RX_HPH_R_GAIN, 0x10, 0x10},
+ {TAIKO_A_RX_LINE_1_GAIN, 0x10, 0x10},
+ {TAIKO_A_RX_LINE_2_GAIN, 0x10, 0x10},
+ {TAIKO_A_RX_LINE_3_GAIN, 0x10, 0x10},
+ {TAIKO_A_RX_LINE_4_GAIN, 0x10, 0x10},
+
+ /* Initialize mic biases to differential mode */
+ {TAIKO_A_MICB_1_INT_RBIAS, 0x24, 0x24},
+ {TAIKO_A_MICB_2_INT_RBIAS, 0x24, 0x24},
+ {TAIKO_A_MICB_3_INT_RBIAS, 0x24, 0x24},
+
+
+ /* Use 16 bit sample size for TX1 to TX6 */
+ {TAIKO_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
+ {TAIKO_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
+ {TAIKO_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
+ {TAIKO_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
+ {TAIKO_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
+ {TAIKO_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
+
+ /* Use 16 bit sample size for TX7 to TX10 */
+ {TAIKO_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
+ {TAIKO_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
+ {TAIKO_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
+ {TAIKO_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
+
+ /* Use 16 bit sample size for RX */
+ {TAIKO_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
+ {TAIKO_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
+
+ /*enable HPF filter for TX paths */
+ {TAIKO_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
+ {TAIKO_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
+
+ /* config Decimator for DMIC CLK_MODE_1(4.8Mhz@9.6Mhz mclk) */
+ {TAIKO_A_CDC_TX1_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX2_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX3_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX4_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX5_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX6_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX7_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX8_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX9_DMIC_CTL, 0x7, 0x0},
+ {TAIKO_A_CDC_TX10_DMIC_CTL, 0x7, 0x0},
+
+ /* config DMIC clk to CLK_MODE_1 (4.8Mhz@9.6Mhz mclk) */
+ {TAIKO_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x0},
+ {TAIKO_A_CDC_CLK_DMIC_B2_CTL, 0xEE, 0x0},
+};
+
+static void taiko_codec_init_reg(struct snd_soc_codec *codec)
+{
+ u32 i;
+
+ for (i = 0; i < ARRAY_SIZE(taiko_codec_reg_init_val); i++)
+ snd_soc_update_bits(codec, taiko_codec_reg_init_val[i].reg,
+ taiko_codec_reg_init_val[i].mask,
+ taiko_codec_reg_init_val[i].val);
+}
+
+static void taiko_update_reg_address(struct taiko_priv *priv)
+{
+ struct taiko_reg_address *reg_addr = &priv->reg_addr;
+ reg_addr->micb_4_mbhc = TAIKO_A_MICB_4_MBHC;
+ reg_addr->micb_4_int_rbias = TAIKO_A_MICB_4_INT_RBIAS;
+ reg_addr->micb_4_ctl = TAIKO_A_MICB_4_CTL;
+
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int codec_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t codec_debug_write(struct file *filp,
+ const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+ char lbuf[32];
+ char *buf;
+ int rc;
+ struct taiko_priv *taiko = filp->private_data;
+
+ if (cnt > sizeof(lbuf) - 1)
+ return -EINVAL;
+
+ rc = copy_from_user(lbuf, ubuf, cnt);
+ if (rc)
+ return -EFAULT;
+
+ lbuf[cnt] = '\0';
+ buf = (char *)lbuf;
+ taiko->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
+ false : true;
+ return rc;
+}
+
+static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ const int size = 768;
+ char buffer[size];
+ int n = 0;
+ struct taiko_priv *taiko = file->private_data;
+ struct snd_soc_codec *codec = taiko->codec;
+ const struct mbhc_internal_cal_data *p = &taiko->mbhc_data;
+ const s16 v_ins_hu_cur = taiko_get_current_v_ins(taiko, true);
+ const s16 v_ins_h_cur = taiko_get_current_v_ins(taiko, false);
+
+ n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
+ taiko_codec_sta_dce_v(codec, 1, p->dce_z));
+ n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
+ p->dce_mb, taiko_codec_sta_dce_v(codec, 1, p->dce_mb));
+ n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
+ p->sta_z, taiko_codec_sta_dce_v(codec, 0, p->sta_z));
+ n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
+ p->sta_mb, taiko_codec_sta_dce_v(codec, 0, p->sta_mb));
+ n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
+ n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
+ n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
+ p->micb_mv);
+ n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
+ p->v_ins_hu,
+ taiko_codec_sta_dce_v(codec, 0, p->v_ins_hu),
+ p->v_ins_hu == v_ins_hu_cur ? "*" : "");
+ n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
+ p->v_ins_h, taiko_codec_sta_dce_v(codec, 1, p->v_ins_h),
+ p->v_ins_h == v_ins_h_cur ? "*" : "");
+ n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
+ p->adj_v_ins_hu,
+ taiko_codec_sta_dce_v(codec, 0, p->adj_v_ins_hu),
+ p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
+ n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
+ p->adj_v_ins_h,
+ taiko_codec_sta_dce_v(codec, 1, p->adj_v_ins_h),
+ p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
+ n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
+ p->v_b1_hu, taiko_codec_sta_dce_v(codec, 0, p->v_b1_hu));
+ n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
+ p->v_b1_h, taiko_codec_sta_dce_v(codec, 1, p->v_b1_h));
+ n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
+ p->v_b1_huc,
+ taiko_codec_sta_dce_v(codec, 1, p->v_b1_huc));
+ n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
+ p->v_brh, taiko_codec_sta_dce_v(codec, 1, p->v_brh));
+ n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
+ taiko_codec_sta_dce_v(codec, 0, p->v_brl));
+ n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
+ p->v_no_mic,
+ taiko_codec_sta_dce_v(codec, 0, p->v_no_mic));
+ n += scnprintf(buffer + n, size - n, "npoll = %d\n", p->npoll);
+ n += scnprintf(buffer + n, size - n, "nbounce_wait = %d\n",
+ p->nbounce_wait);
+ n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
+ p->v_inval_ins_low);
+ n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
+ p->v_inval_ins_high);
+ if (taiko->mbhc_cfg.gpio)
+ n += scnprintf(buffer + n, size - n, "GPIO insert = %d\n",
+ taiko_hs_gpio_level_remove(taiko));
+ buffer[n] = 0;
+
+ return simple_read_from_buffer(buf, count, pos, buffer, n);
+}
+
+static const struct file_operations codec_debug_ops = {
+ .open = codec_debug_open,
+ .write = codec_debug_write,
+};
+
+static const struct file_operations codec_mbhc_debug_ops = {
+ .open = codec_debug_open,
+ .read = codec_mbhc_debug_read,
+};
+#endif
+
+static int taiko_codec_probe(struct snd_soc_codec *codec)
+{
+ struct wcd9xxx *control;
+ struct taiko_priv *taiko;
+ struct snd_soc_dapm_context *dapm = &codec->dapm;
+ int ret = 0;
+ int i;
+ int ch_cnt;
+
+ codec->control_data = dev_get_drvdata(codec->dev->parent);
+ control = codec->control_data;
+
+ taiko = kzalloc(sizeof(struct taiko_priv), GFP_KERNEL);
+ if (!taiko) {
+ dev_err(codec->dev, "Failed to allocate private data\n");
+ return -ENOMEM;
+ }
+ for (i = 0 ; i < NUM_DECIMATORS; i++) {
+ tx_hpf_work[i].taiko = taiko;
+ tx_hpf_work[i].decimator = i + 1;
+ INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
+ tx_hpf_corner_freq_callback);
+ }
+
+ /* Make sure mbhc micbias register addresses are zeroed out */
+ memset(&taiko->mbhc_bias_regs, 0,
+ sizeof(struct mbhc_micbias_regs));
+ taiko->mbhc_micbias_switched = false;
+
+ /* Make sure mbhc intenal calibration data is zeroed out */
+ memset(&taiko->mbhc_data, 0,
+ sizeof(struct mbhc_internal_cal_data));
+ taiko->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
+ taiko->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
+ taiko->mbhc_data.t_sta = DEFAULT_STA_WAIT;
+ snd_soc_codec_set_drvdata(codec, taiko);
+
+ taiko->mclk_enabled = false;
+ taiko->bandgap_type = TAIKO_BANDGAP_OFF;
+ taiko->clock_active = false;
+ taiko->config_mode_active = false;
+ taiko->mbhc_polling_active = false;
+ taiko->mbhc_fake_ins_start = 0;
+ taiko->no_mic_headset_override = false;
+ taiko->hs_polling_irq_prepared = false;
+ mutex_init(&taiko->codec_resource_lock);
+ taiko->codec = codec;
+ taiko->mbhc_state = MBHC_STATE_NONE;
+ taiko->mbhc_last_resume = 0;
+ for (i = 0; i < COMPANDER_MAX; i++) {
+ taiko->comp_enabled[i] = 0;
+ taiko->comp_fs[i] = COMPANDER_FS_48KHZ;
+ }
+ taiko->pdata = dev_get_platdata(codec->dev->parent);
+ taiko->intf_type = wcd9xxx_get_intf_type();
+ taiko->aux_pga_cnt = 0;
+ taiko->aux_l_gain = 0x1F;
+ taiko->aux_r_gain = 0x1F;
+ taiko_update_reg_address(taiko);
+ taiko_update_reg_defaults(codec);
+ taiko_codec_init_reg(codec);
+ ret = taiko_handle_pdata(taiko);
+ if (IS_ERR_VALUE(ret)) {
+ pr_err("%s: bad pdata\n", __func__);
+ goto err_pdata;
+ }
+
+ if (taiko->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
+ snd_soc_dapm_new_controls(dapm, taiko_dapm_i2s_widgets,
+ ARRAY_SIZE(taiko_dapm_i2s_widgets));
+ snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+ ARRAY_SIZE(audio_i2s_map));
+ }
+
+ snd_soc_dapm_sync(dapm);
+
+ ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION,
+ taiko_hs_insert_irq, "Headset insert detect", taiko);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ TAIKO_IRQ_MBHC_INSERTION);
+ goto err_insert_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION);
+
+ ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL,
+ taiko_hs_remove_irq, "Headset remove detect", taiko);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ TAIKO_IRQ_MBHC_REMOVAL);
+ goto err_remove_irq;
+ }
+
+ ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL,
+ taiko_dce_handler, "DC Estimation detect", taiko);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ TAIKO_IRQ_MBHC_POTENTIAL);
+ goto err_potential_irq;
+ }
+
+ ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE,
+ taiko_release_handler, "Button Release detect", taiko);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ TAIKO_IRQ_MBHC_RELEASE);
+ goto err_release_irq;
+ }
+
+ ret = wcd9xxx_request_irq(codec->control_data, TAIKO_IRQ_SLIMBUS,
+ taiko_slimbus_irq, "SLIMBUS Slave", taiko);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ TAIKO_IRQ_SLIMBUS);
+ goto err_slimbus_irq;
+ }
+
+ for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
+ wcd9xxx_interface_reg_write(codec->control_data,
+ TAIKO_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
+
+ ret = wcd9xxx_request_irq(codec->control_data,
+ TAIKO_IRQ_HPH_PA_OCPL_FAULT, taiko_hphl_ocp_irq,
+ "HPH_L OCP detect", taiko);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+ goto err_hphl_ocp_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPL_FAULT);
+
+ ret = wcd9xxx_request_irq(codec->control_data,
+ TAIKO_IRQ_HPH_PA_OCPR_FAULT, taiko_hphr_ocp_irq,
+ "HPH_R OCP detect", taiko);
+ if (ret) {
+ pr_err("%s: Failed to request irq %d\n", __func__,
+ TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ goto err_hphr_ocp_irq;
+ }
+ wcd9xxx_disable_irq(codec->control_data, TAIKO_IRQ_HPH_PA_OCPR_FAULT);
+ for (i = 0; i < ARRAY_SIZE(taiko_dai); i++) {
+ switch (taiko_dai[i].id) {
+ case AIF1_PB:
+ ch_cnt = taiko_dai[i].playback.channels_max;
+ break;
+ case AIF1_CAP:
+ ch_cnt = taiko_dai[i].capture.channels_max;
+ break;
+ case AIF2_PB:
+ ch_cnt = taiko_dai[i].playback.channels_max;
+ break;
+ case AIF2_CAP:
+ ch_cnt = taiko_dai[i].capture.channels_max;
+ break;
+ case AIF3_PB:
+ ch_cnt = taiko_dai[i].playback.channels_max;
+ break;
+ case AIF3_CAP:
+ ch_cnt = taiko_dai[i].capture.channels_max;
+ break;
+ default:
+ continue;
+ }
+ taiko->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
+ ch_cnt), GFP_KERNEL);
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ if (ret == 0) {
+ taiko->debugfs_poke =
+ debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, taiko,
+ &codec_debug_ops);
+ taiko->debugfs_mbhc =
+ debugfs_create_file("taiko_mbhc", S_IFREG | S_IRUGO,
+ NULL, taiko, &codec_mbhc_debug_ops);
+ }
+#endif
+ codec->ignore_pmdown_time = 1;
+ return ret;
+
+err_hphr_ocp_irq:
+ wcd9xxx_free_irq(codec->control_data,
+ TAIKO_IRQ_HPH_PA_OCPL_FAULT, taiko);
+err_hphl_ocp_irq:
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_SLIMBUS, taiko);
+err_slimbus_irq:
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE, taiko);
+err_release_irq:
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL, taiko);
+err_potential_irq:
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL, taiko);
+err_remove_irq:
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION, taiko);
+err_insert_irq:
+err_pdata:
+ mutex_destroy(&taiko->codec_resource_lock);
+ kfree(taiko);
+ return ret;
+}
+static int taiko_codec_remove(struct snd_soc_codec *codec)
+{
+ int i;
+ struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_SLIMBUS, taiko);
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_RELEASE, taiko);
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_POTENTIAL, taiko);
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_REMOVAL, taiko);
+ wcd9xxx_free_irq(codec->control_data, TAIKO_IRQ_MBHC_INSERTION, taiko);
+ TAIKO_ACQUIRE_LOCK(taiko->codec_resource_lock);
+ taiko_codec_disable_clock_block(codec);
+ TAIKO_RELEASE_LOCK(taiko->codec_resource_lock);
+ taiko_codec_enable_bandgap(codec, TAIKO_BANDGAP_OFF);
+ if (taiko->mbhc_fw)
+ release_firmware(taiko->mbhc_fw);
+ for (i = 0; i < ARRAY_SIZE(taiko_dai); i++)
+ kfree(taiko->dai[i].ch_num);
+ mutex_destroy(&taiko->codec_resource_lock);
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(taiko->debugfs_poke);
+ debugfs_remove(taiko->debugfs_mbhc);
+#endif
+ kfree(taiko);
+ return 0;
+}
+static struct snd_soc_codec_driver soc_codec_dev_taiko = {
+ .probe = taiko_codec_probe,
+ .remove = taiko_codec_remove,
+
+ .read = taiko_read,
+ .write = taiko_write,
+
+ .readable_register = taiko_readable,
+ .volatile_register = taiko_volatile,
+
+ .reg_cache_size = TAIKO_CACHE_SIZE,
+ .reg_cache_default = taiko_reg_defaults,
+ .reg_word_size = 1,
+
+ .controls = taiko_snd_controls,
+ .num_controls = ARRAY_SIZE(taiko_snd_controls),
+ .dapm_widgets = taiko_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(taiko_dapm_widgets),
+ .dapm_routes = audio_map,
+ .num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+#ifdef CONFIG_PM
+static int taiko_suspend(struct device *dev)
+{
+ dev_dbg(dev, "%s: system suspend\n", __func__);
+ return 0;
+}
+
+static int taiko_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct taiko_priv *taiko = platform_get_drvdata(pdev);
+ dev_dbg(dev, "%s: system resume\n", __func__);
+ taiko->mbhc_last_resume = jiffies;
+ return 0;
+}
+
+static const struct dev_pm_ops taiko_pm_ops = {
+ .suspend = taiko_suspend,
+ .resume = taiko_resume,
+};
+#endif
+
+static int __devinit taiko_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_taiko,
+ taiko_dai, ARRAY_SIZE(taiko_dai));
+ else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_taiko,
+ taiko_i2s_dai, ARRAY_SIZE(taiko_i2s_dai));
+ return ret;
+}
+static int __devexit taiko_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+static struct platform_driver taiko_codec_driver = {
+ .probe = taiko_probe,
+ .remove = taiko_remove,
+ .driver = {
+ .name = "taiko_codec",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &taiko_pm_ops,
+#endif
+ },
+};
+
+static int __init taiko_codec_init(void)
+{
+ return platform_driver_register(&taiko_codec_driver);
+}
+
+static void __exit taiko_codec_exit(void)
+{
+ platform_driver_unregister(&taiko_codec_driver);
+}
+
+module_init(taiko_codec_init);
+module_exit(taiko_codec_exit);
+
+MODULE_DESCRIPTION("Taiko codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9320.h b/sound/soc/codecs/wcd9320.h
new file mode 100644
index 0000000..739ab17
--- /dev/null
+++ b/sound/soc/codecs/wcd9320.h
@@ -0,0 +1,252 @@
+/* Copyright (c) 2012, Code Aurora Forum. 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 WCD9320_H
+#define WCD9320_H
+
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
+
+#define TAIKO_NUM_REGISTERS 0x400
+#define TAIKO_MAX_REGISTER (TAIKO_NUM_REGISTERS-1)
+#define TAIKO_CACHE_SIZE TAIKO_NUM_REGISTERS
+
+#define TAIKO_REG_VAL(reg, val) {reg, 0, val}
+
+#define DEFAULT_DCE_STA_WAIT 55
+#define DEFAULT_DCE_WAIT 60000
+#define DEFAULT_STA_WAIT 5000
+#define VDDIO_MICBIAS_MV 1800
+
+#define STA 0
+#define DCE 1
+
+#define TAIKO_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
+ SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
+ SND_JACK_BTN_4 | SND_JACK_BTN_5 | \
+ SND_JACK_BTN_6 | SND_JACK_BTN_7)
+
+extern const u8 taiko_reg_readable[TAIKO_CACHE_SIZE];
+extern const u8 taiko_reg_defaults[TAIKO_CACHE_SIZE];
+
+enum taiko_micbias_num {
+ TAIKO_MICBIAS1 = 0,
+ TAIKO_MICBIAS2,
+ TAIKO_MICBIAS3,
+ TAIKO_MICBIAS4,
+};
+
+enum taiko_pid_current {
+ TAIKO_PID_MIC_2P5_UA,
+ TAIKO_PID_MIC_5_UA,
+ TAIKO_PID_MIC_10_UA,
+ TAIKO_PID_MIC_20_UA,
+};
+
+struct taiko_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+enum taiko_mbhc_clk_freq {
+ TAIKO_MCLK_12P2MHZ = 0,
+ TAIKO_MCLK_9P6MHZ,
+ TAIKO_NUM_CLK_FREQS,
+};
+
+enum taiko_mbhc_analog_pwr_cfg {
+ TAIKO_ANALOG_PWR_COLLAPSED = 0,
+ TAIKO_ANALOG_PWR_ON,
+ TAIKO_NUM_ANALOG_PWR_CONFIGS,
+};
+
+enum taiko_mbhc_btn_det_mem {
+ TAIKO_BTN_DET_V_BTN_LOW,
+ TAIKO_BTN_DET_V_BTN_HIGH,
+ TAIKO_BTN_DET_N_READY,
+ TAIKO_BTN_DET_N_CIC,
+ TAIKO_BTN_DET_GAIN
+};
+
+struct taiko_mbhc_general_cfg {
+ u8 t_ldoh;
+ u8 t_bg_fast_settle;
+ u8 t_shutdown_plug_rem;
+ u8 mbhc_nsa;
+ u8 mbhc_navg;
+ u8 v_micbias_l;
+ u8 v_micbias;
+ u8 mbhc_reserved;
+ u16 settle_wait;
+ u16 t_micbias_rampup;
+ u16 t_micbias_rampdown;
+ u16 t_supply_bringup;
+} __packed;
+
+struct taiko_mbhc_plug_detect_cfg {
+ u32 mic_current;
+ u32 hph_current;
+ u16 t_mic_pid;
+ u16 t_ins_complete;
+ u16 t_ins_retry;
+ u16 v_removal_delta;
+ u8 micbias_slow_ramp;
+ u8 reserved0;
+ u8 reserved1;
+ u8 reserved2;
+} __packed;
+
+struct taiko_mbhc_plug_type_cfg {
+ u8 av_detect;
+ u8 mono_detect;
+ u8 num_ins_tries;
+ u8 reserved0;
+ s16 v_no_mic;
+ s16 v_av_min;
+ s16 v_av_max;
+ s16 v_hs_min;
+ s16 v_hs_max;
+ u16 reserved1;
+} __packed;
+
+
+struct taiko_mbhc_btn_detect_cfg {
+ s8 c[8];
+ u8 nc;
+ u8 n_meas;
+ u8 mbhc_nsc;
+ u8 n_btn_meas;
+ u8 n_btn_con;
+ u8 num_btn;
+ u8 reserved0;
+ u8 reserved1;
+ u16 t_poll;
+ u16 t_bounce_wait;
+ u16 t_rel_timeout;
+ s16 v_btn_press_delta_sta;
+ s16 v_btn_press_delta_cic;
+ u16 t_btn0_timeout;
+ s16 _v_btn_low[0]; /* v_btn_low[num_btn] */
+ s16 _v_btn_high[0]; /* v_btn_high[num_btn] */
+ u8 _n_ready[TAIKO_NUM_CLK_FREQS];
+ u8 _n_cic[TAIKO_NUM_CLK_FREQS];
+ u8 _gain[TAIKO_NUM_CLK_FREQS];
+} __packed;
+
+struct taiko_mbhc_imped_detect_cfg {
+ u8 _hs_imped_detect;
+ u8 _n_rload;
+ u8 _hph_keep_on;
+ u8 _repeat_rload_calc;
+ u16 _t_dac_ramp_time;
+ u16 _rhph_high;
+ u16 _rhph_low;
+ u16 _rload[0]; /* rload[n_rload] */
+ u16 _alpha[0]; /* alpha[n_rload] */
+ u16 _beta[3];
+} __packed;
+
+struct taiko_mbhc_config {
+ struct snd_soc_jack *headset_jack;
+ struct snd_soc_jack *button_jack;
+ bool read_fw_bin;
+ /* void* calibration contains:
+ * struct taiko_mbhc_general_cfg generic;
+ * struct taiko_mbhc_plug_detect_cfg plug_det;
+ * struct taiko_mbhc_plug_type_cfg plug_type;
+ * struct taiko_mbhc_btn_detect_cfg btn_det;
+ * struct taiko_mbhc_imped_detect_cfg imped_det;
+ * Note: various size depends on btn_det->num_btn
+ */
+ void *calibration;
+ enum taiko_micbias_num micbias;
+ int (*mclk_cb_fn) (struct snd_soc_codec*, int, bool);
+ unsigned int mclk_rate;
+ unsigned int gpio;
+ unsigned int gpio_irq;
+ int gpio_level_insert;
+ /* swap_gnd_mic returns true if extern GND/MIC swap switch toggled */
+ bool (*swap_gnd_mic) (struct snd_soc_codec *);
+};
+
+extern int taiko_hs_detect(struct snd_soc_codec *codec,
+ const struct taiko_mbhc_config *cfg);
+
+struct anc_header {
+ u32 reserved[3];
+ u32 num_anc_slots;
+};
+
+extern int taiko_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
+ bool dapm);
+
+extern void *taiko_mbhc_cal_btn_det_mp(const struct taiko_mbhc_btn_detect_cfg
+ *btn_det,
+ const enum taiko_mbhc_btn_det_mem mem);
+
+#define TAIKO_MBHC_CAL_SIZE(buttons, rload) ( \
+ sizeof(enum taiko_micbias_num) + \
+ sizeof(struct taiko_mbhc_general_cfg) + \
+ sizeof(struct taiko_mbhc_plug_detect_cfg) + \
+ ((sizeof(s16) + sizeof(s16)) * buttons) + \
+ sizeof(struct taiko_mbhc_plug_type_cfg) + \
+ sizeof(struct taiko_mbhc_btn_detect_cfg) + \
+ sizeof(struct taiko_mbhc_imped_detect_cfg) + \
+ ((sizeof(u16) + sizeof(u16)) * rload) \
+ )
+
+#define TAIKO_MBHC_CAL_GENERAL_PTR(cali) ( \
+ (struct taiko_mbhc_general_cfg *) cali)
+#define TAIKO_MBHC_CAL_PLUG_DET_PTR(cali) ( \
+ (struct taiko_mbhc_plug_detect_cfg *) \
+ &(TAIKO_MBHC_CAL_GENERAL_PTR(cali)[1]))
+#define TAIKO_MBHC_CAL_PLUG_TYPE_PTR(cali) ( \
+ (struct taiko_mbhc_plug_type_cfg *) \
+ &(TAIKO_MBHC_CAL_PLUG_DET_PTR(cali)[1]))
+#define TAIKO_MBHC_CAL_BTN_DET_PTR(cali) ( \
+ (struct taiko_mbhc_btn_detect_cfg *) \
+ &(TAIKO_MBHC_CAL_PLUG_TYPE_PTR(cali)[1]))
+#define TAIKO_MBHC_CAL_IMPED_DET_PTR(cali) ( \
+ (struct taiko_mbhc_imped_detect_cfg *) \
+ (((void *)&TAIKO_MBHC_CAL_BTN_DET_PTR(cali)[1]) + \
+ (TAIKO_MBHC_CAL_BTN_DET_PTR(cali)->num_btn * \
+ (sizeof(TAIKO_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_low[0]) + \
+ sizeof(TAIKO_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
+ )
+
+/* minimum size of calibration data assuming there is only one button and
+ * one rload.
+ */
+#define TAIKO_MBHC_CAL_MIN_SIZE ( \
+ sizeof(struct taiko_mbhc_general_cfg) + \
+ sizeof(struct taiko_mbhc_plug_detect_cfg) + \
+ sizeof(struct taiko_mbhc_plug_type_cfg) + \
+ sizeof(struct taiko_mbhc_btn_detect_cfg) + \
+ sizeof(struct taiko_mbhc_imped_detect_cfg) + \
+ (sizeof(u16) * 2))
+
+#define TAIKO_MBHC_CAL_BTN_SZ(cfg_ptr) ( \
+ sizeof(struct taiko_mbhc_btn_detect_cfg) + \
+ (cfg_ptr->num_btn * (sizeof(cfg_ptr->_v_btn_low[0]) + \
+ sizeof(cfg_ptr->_v_btn_high[0]))))
+
+#define TAIKO_MBHC_CAL_IMPED_MIN_SZ ( \
+ sizeof(struct taiko_mbhc_imped_detect_cfg) + \
+ sizeof(u16) * 2)
+
+#define TAIKO_MBHC_CAL_IMPED_SZ(cfg_ptr) ( \
+ sizeof(struct taiko_mbhc_imped_detect_cfg) + \
+ (cfg_ptr->_n_rload * (sizeof(cfg_ptr->_rload[0]) + \
+ sizeof(cfg_ptr->_alpha[0]))))
+
+#endif
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 36cbb23..1125d20 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -105,6 +105,16 @@
help
To add support for SoC audio on MSM8960.
+config SND_SOC_MSM_QDSP6V2_INTF
+ bool "SoC Q6 audio driver for MSMCOPPER"
+ depends on MSM_QDSP6_APR
+ help
+ To add support for SoC audio on MSMCOPPER.
+ This will enable all the platform specific
+ interactions towards DSP. It includes asm,
+ adm and afe interfaces on the DSP.
+
+
config SND_SOC_VOICE
bool "SoC Q6 voice driver for MSM8960"
depends on SND_SOC_MSM_QDSP6_INTF
@@ -119,6 +129,15 @@
help
To add support for MSM QDSP6 Soc Audio.
+config SND_SOC_QDSP6V2
+ tristate "SoC ALSA audio driver for QDSP6V2"
+ select SND_SOC_MSM_QDSP6V2_INTF
+ help
+ To add support for MSM QDSP6V2 Soc Audio.
+ This will enable sound soc platform specific
+ audio drivers. This includes q6asm, q6adm,
+ q6afe interfaces to DSP using apr.
+
config SND_SOC_MSM8960
tristate "SoC Machine driver for MSM8960 and APQ8064 boards"
depends on ARCH_MSM8960 || ARCH_APQ8064
@@ -134,6 +153,20 @@
help
To add support for SoC audio on MSM8960 and APQ8064 boards
+config SND_SOC_MSM8974
+ tristate "SoC Machine driver for MSMCOPPER boards"
+ depends on ARCH_MSMCOPPER
+ select SND_SOC_QDSP6V2
+ select SND_SOC_MSM_STUB
+ select SND_SOC_MSM_HOSTLESS_PCM
+ select SND_DYNAMIC_MINORS
+ help
+ To add support for SoC audio on MSMCOPPER.
+ This will enable sound soc drivers which
+ interfaces with DSP, also it will enable
+ the machine drivers and the corresponding
+ DAI-links.
+
config SND_SOC_MDM9615
tristate "SoC Machine driver for MDM9615 boards"
depends on ARCH_MSM9615
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 353ffd6..2da5c6a 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -18,6 +18,8 @@
#include <linux/gpio.h>
#include <linux/mfd/pm8xxx/pm8921.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/slimbus/slimbus.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
@@ -46,6 +48,8 @@
#define BOTTOM_SPK_AMP_NEG 0x2
#define TOP_SPK_AMP_POS 0x4
#define TOP_SPK_AMP_NEG 0x8
+#define TOP_SPK_AMP 0x10
+
#define GPIO_AUX_PCM_DOUT 43
#define GPIO_AUX_PCM_DIN 44
@@ -65,7 +69,8 @@
SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
SLIM_3_RX_1 = 151, /* External echo-cancellation ref */
SLIM_3_RX_2 = 152, /* External echo-cancellation ref */
- SLIM_3_TX_1 = 147, /* HDMI RX */
+ SLIM_3_TX_1 = 153, /* HDMI RX */
+ SLIM_3_TX_2 = 154, /* HDMI RX */
SLIM_4_TX_1 = 148, /* In-call recording RX */
SLIM_4_TX_2 = 149, /* In-call recording RX */
SLIM_4_RX_1 = 150, /* In-call music delivery TX */
@@ -123,6 +128,8 @@
.gpio_level_insert = 1,
};
+static struct mutex cdc_mclk_mutex;
+
static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
{
int ret = 0;
@@ -201,10 +208,14 @@
usleep_range(4000, 4000);
}
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+ } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
- if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+ pr_debug("%s():top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+ __func__, msm_ext_top_spk_pamp, spk);
+
+ if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
pr_debug("%s() External Top Speaker Ampl already"
"turned on. spk = 0x%08x\n", __func__, spk);
@@ -213,8 +224,9 @@
msm_ext_top_spk_pamp |= spk;
- if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+ if (((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+ (msm_ext_top_spk_pamp & TOP_SPK_AMP)) {
msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
pr_debug("%s: sleeping 4 ms after turning on "
@@ -245,17 +257,31 @@
usleep_range(4000, 4000);
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+ } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+ pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+ __func__, msm_ext_top_spk_pamp, spk);
if (!msm_ext_top_spk_pamp)
return;
+ if ((spk & TOP_SPK_AMP_POS) || (spk & TOP_SPK_AMP_NEG)) {
+
+ msm_ext_top_spk_pamp &= (~(TOP_SPK_AMP_POS |
+ TOP_SPK_AMP_NEG));
+ } else if (spk & TOP_SPK_AMP) {
+ msm_ext_top_spk_pamp &= ~TOP_SPK_AMP;
+ }
+
+ if (msm_ext_top_spk_pamp)
+ return;
+
gpio_direction_output(top_spk_pamp_gpio, 0);
gpio_free(top_spk_pamp_gpio);
msm_ext_top_spk_pamp = 0;
- pr_debug("%s: sleeping 4 ms after turning off external Top"
- " Spkaker Ampl\n", __func__);
+ pr_debug("%s: sleeping 4 ms after ext Top Spek Ampl is off\n",
+ __func__);
usleep_range(4000, 4000);
} else {
@@ -320,6 +346,8 @@
msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top", 12))
+ msm_ext_spk_power_amp_on(TOP_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
@@ -335,6 +363,8 @@
msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top", 12))
+ msm_ext_spk_power_amp_off(TOP_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
@@ -347,35 +377,42 @@
static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm)
{
+ int r = 0;
pr_debug("%s: enable = %d\n", __func__, enable);
+
+ mutex_lock(&cdc_mclk_mutex);
if (enable) {
clk_users++;
pr_debug("%s: clk_users = %d\n", __func__, clk_users);
- if (clk_users != 1)
- return 0;
-
- if (codec_clk) {
- clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
- clk_prepare_enable(codec_clk);
- tabla_mclk_enable(codec, 1, dapm);
- } else {
- pr_err("%s: Error setting Tabla MCLK\n", __func__);
- clk_users--;
- return -EINVAL;
+ if (clk_users == 1) {
+ if (codec_clk) {
+ clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+ clk_prepare_enable(codec_clk);
+ tabla_mclk_enable(codec, 1, dapm);
+ } else {
+ pr_err("%s: Error setting Tabla MCLK\n",
+ __func__);
+ clk_users--;
+ r = -EINVAL;
+ }
}
} else {
- pr_debug("%s: clk_users = %d\n", __func__, clk_users);
- if (clk_users == 0)
- return 0;
- clk_users--;
- if (!clk_users) {
- pr_debug("%s: disabling MCLK. clk_users = %d\n",
+ if (clk_users > 0) {
+ clk_users--;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+ if (clk_users == 0) {
+ pr_debug("%s: disabling MCLK. clk_users = %d\n",
__func__, clk_users);
- tabla_mclk_enable(codec, 0, dapm);
- clk_disable_unprepare(codec_clk);
+ tabla_mclk_enable(codec, 0, dapm);
+ clk_disable_unprepare(codec_clk);
+ }
+ } else {
+ pr_err("%s: Error releasing Tabla MCLK\n", __func__);
+ r = -EINVAL;
}
}
- return 0;
+ mutex_unlock(&cdc_mclk_mutex);
+ return r;
}
static int msm_mclk_event(struct snd_soc_dapm_widget *w,
@@ -434,6 +471,7 @@
SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Top", msm_spkramp_event),
/************ Analog MICs ************/
/**
@@ -468,6 +506,7 @@
{"Ext Spk Top Pos", NULL, "LINEOUT2"},
{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+ {"Ext Spk Top", NULL, "LINEOUT5"},
/************ Analog MIC Paths ************/
@@ -814,7 +853,7 @@
int ret = 0;
unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
- unsigned int user_set_tx_ch = 0;
+ unsigned int num_tx_ch = 0;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -844,19 +883,17 @@
} else {
if (codec_dai->id == 2)
- user_set_tx_ch = msm_slim_0_tx_ch;
- else if (codec_dai->id == 4)
- user_set_tx_ch = params_channels(params);
+ num_tx_ch = msm_slim_0_tx_ch;
else if (codec_dai->id == 5) {
/* DAI 5 is used for external EC reference from codec.
* Since Rx is fed as reference for EC, the config of
* this DAI is based on that of the Rx path.
*/
- user_set_tx_ch = msm_slim_0_rx_ch;
+ num_tx_ch = msm_slim_0_rx_ch;
}
pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
- codec_dai->name, codec_dai->id, user_set_tx_ch);
+ codec_dai->name, codec_dai->id, num_tx_ch);
ret = snd_soc_dai_get_channel_map(codec_dai,
&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
@@ -866,13 +903,13 @@
}
ret = snd_soc_dai_set_channel_map(cpu_dai,
- user_set_tx_ch, tx_ch, 0 , 0);
+ num_tx_ch, tx_ch, 0 , 0);
if (ret < 0) {
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
ret = snd_soc_dai_set_channel_map(codec_dai,
- user_set_tx_ch, tx_ch, 0, 0);
+ num_tx_ch, tx_ch, 0, 0);
if (ret < 0) {
pr_err("%s: failed to set codec channel map\n",
__func__);
@@ -892,6 +929,77 @@
return 0;
}
+static int msm_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ num_rx_ch = params_channels(params);
+
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+
+ num_tx_ch = params_channels(params);
+
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ }
+end:
+ return ret;
+}
+
static int msm_slimbus_1_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -935,6 +1043,7 @@
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret = 0;
unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+ unsigned int tx_ch[2] = {SLIM_3_TX_1, SLIM_3_TX_2};
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
@@ -950,7 +1059,16 @@
goto end;
}
} else {
- pr_err("%s: SLIMBUS_3_TX not defined for this DAI\n", __func__);
+ pr_debug("%s: MDM RX -> SLIMBUS_3_TX -> APQ HDMI ch: %d, %d\n",
+ __func__, tx_ch[0], tx_ch[1]);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 2, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_3 TX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
}
end:
@@ -1147,6 +1265,22 @@
return 0;
}
+static int msm_slim_3_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s()\n", __func__);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ return 0;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1263,8 +1397,12 @@
}
static int msm_startup(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+ __func__, rtd->dai_link->stream_name,
+ rtd->dai_link->cpu_dai_name,
+ rtd->dai_link->codec_dai_name);
return 0;
}
@@ -1281,6 +1419,19 @@
return 0;
}
+static int msm_slimbus_1_startup(struct snd_pcm_substream *substream)
+{
+ struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
+
+ if (slim != NULL)
+ pm_runtime_get_sync(slim->dev.parent);
+
+ return 0;
+}
+
static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
{
@@ -1290,8 +1441,24 @@
static void msm_shutdown(struct snd_pcm_substream *substream)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+ __func__, rtd->dai_link->stream_name,
+ rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
+}
+
+static void msm_slimbus_1_shutdown(struct snd_pcm_substream *substream)
+{
+ struct slim_controller *slim = slim_busnum_to_ctrl(1);
+
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+
+ if (slim != NULL) {
+ pm_runtime_mark_last_busy(slim->dev.parent);
+ pm_runtime_put(slim->dev.parent);
+ }
}
static struct snd_soc_ops msm_be_ops = {
@@ -1306,9 +1473,9 @@
};
static struct snd_soc_ops msm_slimbus_1_be_ops = {
- .startup = msm_startup,
+ .startup = msm_slimbus_1_startup,
.hw_params = msm_slimbus_1_hw_params,
- .shutdown = msm_shutdown,
+ .shutdown = msm_slimbus_1_shutdown,
};
static struct snd_soc_ops msm_slimbus_3_be_ops = {
@@ -1323,6 +1490,13 @@
.shutdown = msm_shutdown,
};
+static struct snd_soc_ops msm_slimbus_2_be_ops = {
+ .startup = msm_startup,
+ .hw_params = msm_slimbus_2_hw_params,
+ .shutdown = msm_shutdown,
+};
+
+
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm_dai[] = {
/* FrontEnd DAI Links */
@@ -1679,18 +1853,30 @@
.be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
.ops = &msm_slimbus_1_be_ops,
},
+ /* Ultrasound TX Back End DAI Link */
{
- .name = "SLIMBUS_2 Hostless",
- .stream_name = "SLIMBUS_2 Hostless",
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
.cpu_dai_name = "msm-dai-q6.16389",
.platform_name = "msm-pcm-hostless",
.codec_name = "tabla_codec",
.codec_dai_name = "tabla_tx2",
.ignore_suspend = 1,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ops = &msm_be_ops,
+ .ops = &msm_slimbus_2_be_ops,
},
-
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_rx3",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm_slimbus_2_be_ops,
+ },
/* Incall Music Back End DAI Link */
{
.name = LPASS_BE_SLIMBUS_4_RX,
@@ -1748,6 +1934,18 @@
.ops = &msm_slimbus_3_be_ops,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
},
+ {
+ .name = LPASS_BE_SLIMBUS_3_TX,
+ .stream_name = "Slimbus3 Capture",
+ .cpu_dai_name = "msm-dai-q6.16391",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ .be_hw_params_fixup = msm_slim_3_tx_be_hw_params_fixup,
+ .ops = &msm_slimbus_3_be_ops,
+ },
};
struct snd_soc_card snd_soc_card_msm = {
@@ -1847,6 +2045,7 @@
} else
msm_headset_gpios_configured = 1;
+ mutex_init(&cdc_mclk_mutex);
return ret;
}
@@ -1863,6 +2062,7 @@
if (mbhc_cfg.gpio)
gpio_free(mbhc_cfg.gpio);
kfree(mbhc_cfg.calibration);
+ mutex_destroy(&cdc_mclk_mutex);
}
module_exit(msm_audio_exit);
diff --git a/sound/soc/msm/mdm9615.c b/sound/soc/msm/mdm9615.c
index 41a9c48..90d8723 100644
--- a/sound/soc/msm/mdm9615.c
+++ b/sound/soc/msm/mdm9615.c
@@ -39,18 +39,23 @@
#define MDM9615_SLIM_0_RX_MAX_CHANNELS 2
#define MDM9615_SLIM_0_TX_MAX_CHANNELS 4
-#define BTSCO_RATE_8KHZ 8000
-#define BTSCO_RATE_16KHZ 16000
+#define SAMPLE_RATE_8KHZ 8000
+#define SAMPLE_RATE_16KHZ 16000
#define BOTTOM_SPK_AMP_POS 0x1
#define BOTTOM_SPK_AMP_NEG 0x2
#define TOP_SPK_AMP_POS 0x4
#define TOP_SPK_AMP_NEG 0x8
-#define GPIO_AUX_PCM_DOUT 63
-#define GPIO_AUX_PCM_DIN 64
-#define GPIO_AUX_PCM_SYNC 65
-#define GPIO_AUX_PCM_CLK 66
+#define GPIO_AUX_PCM_DOUT 23
+#define GPIO_AUX_PCM_DIN 22
+#define GPIO_AUX_PCM_SYNC 21
+#define GPIO_AUX_PCM_CLK 20
+
+#define GPIO_SEC_AUX_PCM_DOUT 28
+#define GPIO_SEC_AUX_PCM_DIN 27
+#define GPIO_SEC_AUX_PCM_SYNC 26
+#define GPIO_SEC_AUX_PCM_CLK 25
#define TABLA_EXT_CLK_RATE 12288000
@@ -144,6 +149,9 @@
#define LPA_IF_REG_BASE (LPA_IF_BASE + 0x00000000)
#define LPASS_SIF_MUX_ADDR (SIF_MUX_REG_BASE + 0x00004000)
#define LPAIF_SPARE_ADDR (LPA_IF_REG_BASE + 0x00000070)
+#define SEC_PCM_PORT_SLC_ADDR 0x00802074
+/* bits 2:0 should be updated with 100 to select SDC2 */
+#define SEC_PCM_PORT_SLC_VALUE 0x4
/* SIF & SPARE MUX Values */
#define MSM_SIF_FUNC_PCM 0
#define MSM_SIF_FUNC_I2S_MIC 1
@@ -168,6 +176,7 @@
static int msm9615_i2s_rx_ch = 1;
static int msm9615_i2s_tx_ch = 1;
static int msm9615_i2s_spk_control;
+
/* SIF mux bit mask & shift */
#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK 0x30000
#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT 0x10
@@ -182,6 +191,8 @@
static u32 spare_shadow;
static u32 sif_shadow;
+static atomic_t msm9615_auxpcm_ref;
+static atomic_t msm9615_sec_auxpcm_ref;
struct msm_i2s_mux_ctl {
const u8 sifconfig;
@@ -240,15 +251,21 @@
static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(3);
static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
+
+void *sif_virt_addr;
+void *secpcm_portslc_virt_addr;
+
static int mdm9615_spk_control;
static int mdm9615_ext_bottom_spk_pamp;
static int mdm9615_ext_top_spk_pamp;
static int mdm9615_slim_0_rx_ch = 1;
static int mdm9615_slim_0_tx_ch = 1;
-static int mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+static int mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
static int mdm9615_btsco_ch = 1;
+static int mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+
static struct clk *codec_clk;
static int clk_users;
@@ -664,6 +681,11 @@
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static const char * const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum mdm9615_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
static int mdm9615_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -715,19 +737,49 @@
{
switch (ucontrol->value.integer.value[0]) {
case 0:
- mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+ mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
break;
case 1:
- mdm9615_btsco_rate = BTSCO_RATE_16KHZ;
+ mdm9615_btsco_rate = SAMPLE_RATE_16KHZ;
break;
default:
- mdm9615_btsco_rate = BTSCO_RATE_8KHZ;
+ mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
break;
}
pr_debug("%s: mdm9615_btsco_rate = %d\n", __func__, mdm9615_btsco_rate);
return 0;
}
+static int mdm9615_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: mdm9615_auxpcm_rate = %d", __func__,
+ mdm9615_auxpcm_rate);
+ ucontrol->value.integer.value[0] = mdm9615_auxpcm_rate;
+ return 0;
+}
+
+static int mdm9615_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+ break;
+ case 1:
+ mdm9615_auxpcm_rate = SAMPLE_RATE_16KHZ;
+ break;
+ default:
+ mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
+ break;
+ }
+ pr_debug("%s: mdm9615_auxpcm_rate = %d\n"
+ "ucontrol->value.integer.value[0] = %d\n", __func__,
+ mdm9615_auxpcm_rate,
+ (int)ucontrol->value.integer.value[0]);
+ return 0;
+}
+
static const struct snd_kcontrol_new tabla_mdm9615_controls[] = {
SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], mdm9615_get_spk,
mdm9615_set_spk),
@@ -737,6 +789,8 @@
mdm9615_slim_0_tx_ch_get, mdm9615_slim_0_tx_ch_put),
SOC_ENUM_EXT("Internal BTSCO SampleRate", mdm9615_btsco_enum[0],
mdm9615_btsco_rate_get, mdm9615_btsco_rate_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", mdm9615_auxpcm_enum[0],
+ mdm9615_auxpcm_rate_get, mdm9615_auxpcm_rate_put),
};
static void *def_tabla_mbhc_cal(void)
@@ -1539,8 +1593,8 @@
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
- /* PCM only supports mono output with 8khz sample rate */
- rate->min = rate->max = 8000;
+ rate->min = rate->max = mdm9615_auxpcm_rate;
+ /* PCM only supports mono output */
channels->min = channels->max = 1;
return 0;
@@ -1601,6 +1655,63 @@
return 0;
}
+static int mdm9615_sec_aux_pcm_get_gpios(void)
+{
+ int ret = 0;
+
+ pr_debug("%s\n", __func__);
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_DOUT, "SEC_AUX PCM DOUT");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM DOUT",
+ __func__, GPIO_SEC_AUX_PCM_DOUT);
+ goto fail_dout;
+ }
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_DIN, "SEC_AUX PCM DIN");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM DIN",
+ __func__, GPIO_SEC_AUX_PCM_DIN);
+ goto fail_din;
+ }
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_SYNC, "SEC_AUX PCM SYNC");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM SYNC",
+ __func__, GPIO_SEC_AUX_PCM_SYNC);
+ goto fail_sync;
+ }
+
+ ret = gpio_request(GPIO_SEC_AUX_PCM_CLK, "SEC_AUX PCM CLK");
+ if (ret < 0) {
+ pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM CLK",
+ __func__, GPIO_SEC_AUX_PCM_CLK);
+ goto fail_clk;
+ }
+
+ return 0;
+
+fail_clk:
+ gpio_free(GPIO_SEC_AUX_PCM_SYNC);
+fail_sync:
+ gpio_free(GPIO_SEC_AUX_PCM_DIN);
+fail_din:
+ gpio_free(GPIO_SEC_AUX_PCM_DOUT);
+fail_dout:
+
+ return ret;
+}
+
+static int mdm9615_sec_aux_pcm_free_gpios(void)
+{
+ gpio_free(GPIO_SEC_AUX_PCM_DIN);
+ gpio_free(GPIO_SEC_AUX_PCM_DOUT);
+ gpio_free(GPIO_SEC_AUX_PCM_SYNC);
+ gpio_free(GPIO_SEC_AUX_PCM_CLK);
+
+ return 0;
+}
+
static int mdm9615_startup(struct snd_pcm_substream *substream)
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
@@ -1608,15 +1719,37 @@
return 0;
}
+void msm9615_config_sif_mux(u8 value)
+{
+ u32 sif_shadow = 0x00000;
+
+ sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK) |
+ (value << LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT);
+ iowrite32(sif_shadow, sif_virt_addr);
+ /* Dont read SIF register. Device crashes. */
+ pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
+}
+
+void msm9615_config_port_select(void)
+{
+ pr_debug("%s() port select defualt = 0x%x\n",
+ __func__, ioread32(secpcm_portslc_virt_addr));
+ iowrite32(SEC_PCM_PORT_SLC_VALUE, secpcm_portslc_virt_addr);
+ pr_debug("%s() port select after updating = 0x%x\n",
+ __func__, ioread32(secpcm_portslc_virt_addr));
+}
+
static int mdm9615_auxpcm_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
pr_debug("%s(): substream = %s\n", __func__, substream->name);
- ret = mdm9615_aux_pcm_get_gpios();
- if (ret < 0) {
- pr_err("%s: Aux PCM GPIO request failed\n", __func__);
- return -EINVAL;
+ if (atomic_inc_return(&msm9615_auxpcm_ref) == 1) {
+ ret = mdm9615_aux_pcm_get_gpios();
+ if (ret < 0) {
+ pr_err("%s: Aux PCM GPIO request failed\n", __func__);
+ return -EINVAL;
+ }
}
return 0;
}
@@ -1625,7 +1758,33 @@
{
pr_debug("%s(): substream = %s\n", __func__, substream->name);
- mdm9615_aux_pcm_free_gpios();
+ if (atomic_dec_return(&msm9615_auxpcm_ref) == 0)
+ mdm9615_aux_pcm_free_gpios();
+}
+
+static int mdm9615_sec_auxpcm_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ if (atomic_inc_return(&msm9615_sec_auxpcm_ref) == 1) {
+ ret = mdm9615_sec_aux_pcm_get_gpios();
+ if (ret < 0) {
+ pr_err("%s: SEC Aux PCM GPIO request failed\n",
+ __func__);
+ return -EINVAL;
+ }
+ msm9615_config_sif_mux(MSM_SIF_FUNC_PCM);
+ msm9615_config_port_select();
+ }
+ return 0;
+}
+
+static void mdm9615_sec_auxpcm_shutdown(struct snd_pcm_substream *substream)
+{
+ pr_debug("%s(): substream = %s\n", __func__, substream->name);
+ if (atomic_dec_return(&msm9615_sec_auxpcm_ref) == 0)
+ mdm9615_sec_aux_pcm_free_gpios();
}
static void mdm9615_shutdown(struct snd_pcm_substream *substream)
@@ -1645,6 +1804,12 @@
.shutdown = mdm9615_auxpcm_shutdown,
};
+static struct snd_soc_ops mdm9615_sec_auxpcm_be_ops = {
+ .startup = mdm9615_sec_auxpcm_startup,
+ .shutdown = mdm9615_sec_auxpcm_shutdown,
+};
+
+
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link mdm9615_dai_common[] = {
/* FrontEnd DAI Links */
@@ -1823,8 +1988,34 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_AUXPCM_TX,
.be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+ .ops = &mdm9615_auxpcm_be_ops,
},
+ /* SECONDARY AUX PCM Backend DAI Links */
+ {
+ .name = LPASS_BE_SEC_AUXPCM_RX,
+ .stream_name = "SEC AUX PCM Playback",
+ .cpu_dai_name = "msm-dai-q6.12",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+ .ops = &mdm9615_sec_auxpcm_be_ops,
+ },
+ {
+ .name = LPASS_BE_SEC_AUXPCM_TX,
+ .stream_name = "SEC AUX PCM Capture",
+ .cpu_dai_name = "msm-dai-q6.13",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
+ .ops = &mdm9615_sec_auxpcm_be_ops,
+ },
};
static struct snd_soc_dai_link mdm9615_dai_i2s_tabla[] = {
@@ -2000,7 +2191,12 @@
snd_soc_card_mdm9615.dai_link = mdm9615_i2s_dai;
snd_soc_card_mdm9615.num_links =
ARRAY_SIZE(mdm9615_i2s_dai);
+ } else{
+ snd_soc_card_mdm9615.dai_link = mdm9615_dai_common;
+ snd_soc_card_mdm9615.num_links =
+ ARRAY_SIZE(mdm9615_dai_common);
}
+
platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
ret = platform_device_add(mdm9615_snd_device);
if (ret) {
@@ -2014,11 +2210,14 @@
} else
mdm9615_headset_gpios_configured = 1;
+ atomic_set(&msm9615_auxpcm_ref, 0);
+ atomic_set(&msm9615_sec_auxpcm_ref, 0);
msm9x15_i2s_ctl.sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
msm9x15_i2s_ctl.spare_virt_addr = ioremap(LPAIF_SPARE_ADDR, 4);
+ sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
+ secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
return ret;
-
}
module_init(mdm9615_audio_init);
@@ -2033,6 +2232,8 @@
kfree(mbhc_cfg.calibration);
iounmap(msm9x15_i2s_ctl.sif_virt_addr);
iounmap(msm9x15_i2s_ctl.spare_virt_addr);
+ iounmap(sif_virt_addr);
+ iounmap(secpcm_portslc_virt_addr);
}
module_exit(mdm9615_audio_exit);
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index 0995300..4ecd8df 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1062,7 +1062,8 @@
.cpu_dai_name = "MultiMedia1",
.platform_name = "msm-pcm-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1075,7 +1076,8 @@
.cpu_dai_name = "MultiMedia2",
.platform_name = "msm-multi-ch-pcm-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1088,7 +1090,8 @@
.cpu_dai_name = "CS-VOICE",
.platform_name = "msm-pcm-voice",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1102,7 +1105,8 @@
.cpu_dai_name = "VoIP",
.platform_name = "msm-voip-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1110,12 +1114,13 @@
.be_id = MSM_FRONTEND_DAI_VOIP,
},
{
- .name = "MSM8960 LPA",
- .stream_name = "LPA",
+ .name = "MSM8960 Media3",
+ .stream_name = "MultiMedia3",
.cpu_dai_name = "MultiMedia3",
- .platform_name = "msm-pcm-lpa",
+ .platform_name = "msm-pcm-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1129,7 +1134,8 @@
.cpu_dai_name = "SLIMBUS0_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1142,7 +1148,8 @@
.cpu_dai_name = "INT_FM_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1173,12 +1180,13 @@
.codec_name = "snd-soc-dummy",
},
{
- .name = "MSM8960 Compr",
- .stream_name = "COMPR",
+ .name = "MSM8960 Compr1",
+ .stream_name = "COMPR1",
.cpu_dai_name = "MultiMedia4",
.platform_name = "msm-compr-dsp",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
.ignore_suspend = 1,
@@ -1191,7 +1199,8 @@
.cpu_dai_name = "VOICE_STUB",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1205,7 +1214,8 @@
.cpu_dai_name = "HDMI_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
@@ -1219,7 +1229,8 @@
.cpu_dai_name = "MI2S_TX_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.codec_dai_name = "snd-soc-dummy-dai",
@@ -1232,13 +1243,70 @@
.cpu_dai_name = "SEC_I2S_RX_HOSTLESS",
.platform_name = "msm-pcm-hostless",
.dynamic = 1,
- .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE, SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
.ignore_suspend = 1,
.ignore_pmdown_time = 1, /* this dainlink has playback support */
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {
+ .name = "MSM8960 Media5",
+ .stream_name = "MultiMedia5",
+ .cpu_dai_name = "MultiMedia5",
+ .platform_name = "msm-multi-ch-pcm-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE,
+ SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* this dailink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA5
+ },
+ {
+ .name = "MSM8960 Media6",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-multi-ch-pcm-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE,
+ SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* this dailink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6
+ },
+ {
+ .name = "MSM8960 Compr2",
+ .stream_name = "COMPR2",
+ .cpu_dai_name = "MultiMedia7",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE,
+ SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* this dailink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA7,
+ },
+ {
+ .name = "MSM8960 Compr3",
+ .stream_name = "COMPR3",
+ .cpu_dai_name = "MultiMedia8",
+ .platform_name = "msm-compr-dsp",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_BESPOKE,
+ SND_SOC_DPCM_TRIGGER_BESPOKE},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1, /* this dailink has playback support */
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA8,
+ },
/* Backend DAI Links */
{
.name = LPASS_BE_SLIMBUS_0_RX,
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index c8d3a71c..56e83d5 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -55,7 +55,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 6,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -157,7 +157,7 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 6,
.rate_min = 8000,
.rate_max = 48000,
},
@@ -172,13 +172,69 @@
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 6,
.rate_min = 8000,
.rate_max = 48000,
},
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia4",
},
+ {
+ .playback = {
+ .stream_name = "MultiMedia5 Playback",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 6,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia5",
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia6 Playback",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 6,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia6",
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia7 Playback",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 6,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia7",
+ },
+ {
+ .playback = {
+ .stream_name = "MultiMedia8 Playback",
+ .rates = (SNDRV_PCM_RATE_8000_48000 |
+ SNDRV_PCM_RATE_KNOT),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 6,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_Multimedia_dai_ops,
+ .name = "MultiMedia8",
+ },
/* FE DAIs created for hostless operation purpose */
{
.playback = {
@@ -370,6 +426,30 @@
.ops = &msm_fe_dai_ops,
.name = "SEC_I2S_RX_HOSTLESS",
},
+ {
+ .playback = {
+ .stream_name = "SGLTE Playback",
+ .aif_name = "SGLTE_DL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .capture = {
+ .stream_name = "SGLTE Capture",
+ .aif_name = "SGLTE_UL",
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_fe_dai_ops,
+ .name = "SGLTE",
+ },
};
static __devinit int msm_fe_dai_dev_probe(struct platform_device *pdev)
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 284320d..b3e5120 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -48,9 +48,11 @@
};
static struct clk *pcm_clk;
+static struct clk *sec_pcm_clk;
static DEFINE_MUTEX(aux_pcm_mutex);
static int aux_pcm_count;
static struct msm_dai_auxpcm_pdata *auxpcm_plat_data;
+static struct msm_dai_auxpcm_pdata *sec_auxpcm_plat_data;
static int msm_dai_q6_mi2s_format_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -558,6 +560,48 @@
return 0;
}
+static int msm_dai_q6_sec_auxpcm_hw_params(
+ struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+ (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+
+ pr_debug("%s\n", __func__);
+ if (params_channels(params) != 1) {
+ dev_err(dai->dev, "SEC AUX PCM supports only mono stream\n");
+ return -EINVAL;
+ }
+ dai_data->channels = params_channels(params);
+
+ dai_data->rate = params_rate(params);
+ switch (dai_data->rate) {
+ case 8000:
+ dai_data->port_config.pcm.mode = auxpcm_pdata->mode_8k.mode;
+ dai_data->port_config.pcm.sync = auxpcm_pdata->mode_8k.sync;
+ dai_data->port_config.pcm.frame = auxpcm_pdata->mode_8k.frame;
+ dai_data->port_config.pcm.quant = auxpcm_pdata->mode_8k.quant;
+ dai_data->port_config.pcm.slot = auxpcm_pdata->mode_8k.slot;
+ dai_data->port_config.pcm.data = auxpcm_pdata->mode_8k.data;
+ break;
+ case 16000:
+ dai_data->port_config.pcm.mode = auxpcm_pdata->mode_16k.mode;
+ dai_data->port_config.pcm.sync = auxpcm_pdata->mode_16k.sync;
+ dai_data->port_config.pcm.frame = auxpcm_pdata->mode_16k.frame;
+ dai_data->port_config.pcm.quant = auxpcm_pdata->mode_16k.quant;
+ dai_data->port_config.pcm.slot = auxpcm_pdata->mode_16k.slot;
+ dai_data->port_config.pcm.data = auxpcm_pdata->mode_16k.data;
+ break;
+ default:
+ dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
@@ -606,6 +650,7 @@
case SLIMBUS_1_TX:
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
rc = msm_dai_q6_slim_bus_hw_params(params, dai,
@@ -682,6 +727,52 @@
mutex_unlock(&aux_pcm_mutex);
}
+static void msm_dai_q6_sec_auxpcm_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int rc = 0;
+
+ pr_debug("%s\n", __func__);
+ mutex_lock(&aux_pcm_mutex);
+
+ if (aux_pcm_count == 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
+ " return\n", __func__, dai->id);
+ mutex_unlock(&aux_pcm_mutex);
+ return;
+ }
+
+ aux_pcm_count--;
+
+ if (aux_pcm_count > 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+ __func__, dai->id, aux_pcm_count);
+ mutex_unlock(&aux_pcm_mutex);
+ return;
+ } else if (aux_pcm_count < 0) {
+ dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+ " aux_pcm_count = %d < 0\n",
+ __func__, dai->id, aux_pcm_count);
+ aux_pcm_count = 0;
+ mutex_unlock(&aux_pcm_mutex);
+ return;
+ }
+
+ pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
+ dai->id, aux_pcm_count);
+
+ clk_disable_unprepare(sec_pcm_clk);
+ rc = afe_close(SECONDARY_PCM_RX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
+
+ rc = afe_close(SECONDARY_PCM_TX);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUX PCM TX port\n");
+
+ mutex_unlock(&aux_pcm_mutex);
+}
+
static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -768,7 +859,7 @@
if (dai_data->rate == 8000) {
pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
} else if (dai_data->rate == 16000) {
- pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ pcm_clk_rate = auxpcm_pdata->mode_16k.pcm_clk_rate;
} else {
dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
dai_data->rate);
@@ -789,6 +880,88 @@
return rc;
}
+static int msm_dai_q6_sec_auxpcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ int rc = 0;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+ (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+ unsigned long pcm_clk_rate;
+
+ pr_info("%s\n", __func__);
+
+ mutex_lock(&aux_pcm_mutex);
+
+ if (aux_pcm_count == 2) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
+ " return.\n", __func__, dai->id);
+ mutex_unlock(&aux_pcm_mutex);
+ return 0;
+ } else if (aux_pcm_count > 2) {
+ dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+ " aux_pcm_count = %d > 2\n",
+ __func__, dai->id, aux_pcm_count);
+ mutex_unlock(&aux_pcm_mutex);
+ return 0;
+ }
+
+ aux_pcm_count++;
+ if (aux_pcm_count == 2) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
+ " increment\n", __func__, dai->id, aux_pcm_count);
+ mutex_unlock(&aux_pcm_mutex);
+ return 0;
+ }
+
+ pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
+ __func__, dai->id, aux_pcm_count);
+
+ rc = afe_q6_interface_prepare();
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to open AFE APR\n");
+
+ /*
+ * For AUX PCM Interface the below sequence of clk
+ * settings and afe_open is a strict requirement.
+ *
+ * Also using afe_open instead of afe_port_start_nowait
+ * to make sure the port is open before deasserting the
+ * clock line. This is required because pcm register is
+ * not written before clock deassert. Hence the hw does
+ * not get updated with new setting if the below clock
+ * assert/deasset and afe_open sequence is not followed.
+ */
+
+ clk_reset(sec_pcm_clk, CLK_RESET_ASSERT);
+
+ afe_open(SECONDARY_PCM_RX, &dai_data->port_config, dai_data->rate);
+
+ afe_open(SECONDARY_PCM_TX, &dai_data->port_config, dai_data->rate);
+ if (dai_data->rate == 8000) {
+ pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ } else if (dai_data->rate == 16000) {
+ pcm_clk_rate = auxpcm_pdata->mode_16k.pcm_clk_rate;
+ } else {
+ dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+ dai_data->rate);
+ return -EINVAL;
+ }
+
+ rc = clk_set_rate(sec_pcm_clk, pcm_clk_rate);
+ if (rc < 0) {
+ pr_err("%s: clk_set_rate failed\n", __func__);
+ return rc;
+ }
+
+ clk_prepare_enable(sec_pcm_clk);
+ clk_reset(sec_pcm_clk, CLK_RESET_DEASSERT);
+
+ mutex_unlock(&aux_pcm_mutex);
+
+ return rc;
+}
+
static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
@@ -940,6 +1113,55 @@
return rc;
}
+static int msm_dai_q6_dai_sec_auxpcm_probe(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data;
+ int rc = 0;
+ struct msm_dai_auxpcm_pdata *auxpcm_pdata =
+ (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
+
+ pr_info("%s\n", __func__);
+
+ mutex_lock(&aux_pcm_mutex);
+
+ if (!sec_auxpcm_plat_data)
+ sec_auxpcm_plat_data = auxpcm_pdata;
+ else if (sec_auxpcm_plat_data != auxpcm_pdata) {
+ dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
+ " same platform data sec_auxpcm_plat_data\n");
+ return -EINVAL;
+ }
+
+ /*
+ * The clk name for AUX PCM operation is passed as platform
+ * data to the cpu driver, since cpu drive is unaware of any
+ * boarc specific configuration.
+ */
+ if (!sec_pcm_clk) {
+
+ sec_pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
+ if (IS_ERR(sec_pcm_clk)) {
+ pr_err("%s: could not get sec_pcm_clk\n", __func__);
+ sec_pcm_clk = NULL;
+ return -ENODEV;
+ }
+ }
+
+ mutex_unlock(&aux_pcm_mutex);
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
+
+ if (!dai_data) {
+ dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+ dai->id);
+ rc = -ENOMEM;
+ } else
+ dev_set_drvdata(dai->dev, dai_data);
+
+ pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
+ return rc;
+}
+
static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
{
struct msm_dai_q6_dai_data *dai_data;
@@ -989,6 +1211,56 @@
return 0;
}
+static int msm_dai_q6_dai_sec_auxpcm_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_dai_data *dai_data;
+ int rc;
+
+ pr_debug("%s\n", __func__);
+ dai_data = dev_get_drvdata(dai->dev);
+
+ mutex_lock(&aux_pcm_mutex);
+
+ if (aux_pcm_count == 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
+ " up and return\n", __func__, dai->id);
+ goto done;
+ }
+
+ aux_pcm_count--;
+
+ if (aux_pcm_count > 0) {
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
+ __func__, dai->id, aux_pcm_count);
+ goto done;
+ } else if (aux_pcm_count < 0) {
+ dev_err(dai->dev, "%s(): ERROR: dai->id %d"
+ " aux_pcm_count = %d < 0\n",
+ __func__, dai->id, aux_pcm_count);
+ goto done;
+ }
+
+ dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
+ "closing afe\n",
+ __func__, dai->id, aux_pcm_count);
+
+ rc = afe_close(SECONDARY_PCM_RX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
+
+ rc = afe_close(SECONDARY_PCM_TX);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
+
+done:
+ kfree(dai_data);
+ snd_soc_unregister_dai(dai->dev);
+
+ mutex_unlock(&aux_pcm_mutex);
+
+ return 0;
+}
+
static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
{
struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
@@ -1164,6 +1436,7 @@
case SLIMBUS_0_TX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
case SLIMBUS_4_TX:
/* channel number to be between 128 and 255. For RX port
* use channel numbers from 138 to 144, for TX port
@@ -1217,6 +1490,13 @@
.shutdown = msm_dai_q6_auxpcm_shutdown,
};
+static struct snd_soc_dai_ops msm_dai_q6_sec_auxpcm_ops = {
+ .prepare = msm_dai_q6_sec_auxpcm_prepare,
+ .trigger = msm_dai_q6_auxpcm_trigger,
+ .hw_params = msm_dai_q6_sec_auxpcm_hw_params,
+ .shutdown = msm_dai_q6_sec_auxpcm_shutdown,
+};
+
static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
@@ -1352,7 +1632,7 @@
};
static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
- .playback = {
+ .capture = {
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
@@ -1381,7 +1661,7 @@
};
static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
- .playback = {
+ .capture = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -1423,6 +1703,34 @@
.remove = msm_dai_q6_dai_auxpcm_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_sec_aux_pcm_rx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_sec_auxpcm_ops,
+ .probe = msm_dai_q6_dai_sec_auxpcm_probe,
+ .remove = msm_dai_q6_dai_sec_auxpcm_remove,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_sec_aux_pcm_tx_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 1,
+ .rate_max = 16000,
+ .rate_min = 8000,
+ },
+ .ops = &msm_dai_q6_sec_auxpcm_ops,
+ .probe = msm_dai_q6_dai_sec_auxpcm_probe,
+ .remove = msm_dai_q6_dai_sec_auxpcm_remove,
+};
+
/* Channel min and max are initialized base on platform data */
static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
.playback = {
@@ -1543,6 +1851,14 @@
&msm_dai_q6_aux_pcm_tx_dai);
break;
+ case SECONDARY_PCM_RX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_sec_aux_pcm_rx_dai);
+ break;
+ case SECONDARY_PCM_TX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_sec_aux_pcm_tx_dai);
+ break;
case SLIMBUS_0_RX:
case SLIMBUS_4_RX:
rc = snd_soc_register_dai(&pdev->dev,
@@ -1550,6 +1866,7 @@
break;
case SLIMBUS_0_TX:
case SLIMBUS_4_TX:
+ case SLIMBUS_3_TX:
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_slimbus_tx_dai);
break;
diff --git a/sound/soc/msm/msm-pcm-afe.c b/sound/soc/msm/msm-pcm-afe.c
index 482cbee..5f3cada 100644
--- a/sound/soc/msm/msm-pcm-afe.c
+++ b/sound/soc/msm/msm-pcm-afe.c
@@ -32,6 +32,7 @@
#include <linux/memory_alloc.h>
#include <mach/msm_subsystem_map.h>
#include "msm-pcm-afe.h"
+#include "msm-pcm-q6.h"
#define MIN_PERIOD_SIZE (128 * 2)
#define MAX_PERIOD_SIZE (128 * 2 * 2 * 6)
@@ -58,6 +59,10 @@
static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt);
static enum hrtimer_restart afe_hrtimer_rec_callback(struct hrtimer *hrt);
+static void q6asm_event_handler(uint32_t opcode,
+ uint32_t token, uint32_t *payload, void *priv)
+{
+}
static enum hrtimer_restart afe_hrtimer_callback(struct hrtimer *hrt)
{
struct pcm_afe_info *prtd =
@@ -319,13 +324,22 @@
runtime->hw = msm_afe_hardware;
prtd->substream = substream;
runtime->private_data = prtd;
- mutex_unlock(&prtd->lock);
+ prtd->audio_client = q6asm_audio_client_alloc(
+ (app_cb)q6asm_event_handler, prtd);
+ if (!prtd->audio_client) {
+ pr_debug("%s: Could not allocate memory\n", __func__);
+ kfree(prtd);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
hrtimer_init(&prtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
prtd->hrt.function = afe_hrtimer_callback;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
prtd->hrt.function = afe_hrtimer_rec_callback;
+ mutex_unlock(&prtd->lock);
+
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
@@ -348,6 +362,7 @@
struct pcm_afe_info *prtd;
struct snd_soc_pcm_runtime *rtd = NULL;
struct snd_soc_dai *dai = NULL;
+ int dir = IN;
int ret = 0;
pr_debug("%s\n", __func__);
@@ -363,10 +378,12 @@
mutex_lock(&prtd->lock);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dir = IN;
ret = afe_unregister_get_events(dai->id);
if (ret < 0)
pr_err("AFE unregister for events failed\n");
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ dir = OUT;
ret = afe_unregister_get_events(dai->id);
if (ret < 0)
pr_err("AFE unregister for events failed\n");
@@ -385,17 +402,14 @@
}
if (dma_buf->area) {
- if (msm_subsystem_unmap_buffer(prtd->mem_buffer) < 0) {
- pr_err("%s: unmap buffer failed\n", __func__);
- prtd->mem_buffer = NULL;
dma_buf->area = NULL;
}
- }
- if (dma_buf->addr)
- free_contiguous_memory_by_paddr(dma_buf->addr);
+ q6asm_audio_client_buf_free_contiguous(dir,
+ prtd->audio_client);
done:
pr_debug("%s: dai->id =%x\n", __func__, dai->id);
+ q6asm_audio_client_free(prtd->audio_client);
mutex_unlock(&prtd->lock);
prtd->prepared--;
kfree(prtd);
@@ -470,57 +484,45 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
struct pcm_afe_info *prtd = runtime->private_data;
- int rc;
- unsigned int flags = 0;
+ struct audio_buffer *buf;
+ int dir, ret;
pr_debug("%s:\n", __func__);
mutex_lock(&prtd->lock);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = IN;
+ else
+ dir = OUT;
+ ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+ prtd->audio_client,
+ runtime->hw.period_bytes_min,
+ runtime->hw.periods_max);
+ if (ret < 0) {
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n", ret);
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+ buf = prtd->audio_client->port[dir].buf;
+ if (buf == NULL || buf[0].data == NULL) {
+ mutex_unlock(&prtd->lock);
+ return -ENOMEM;
+ }
+
+ pr_debug("%s:buf = %p\n", __func__, buf);
dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
dma_buf->dev.dev = substream->pcm->card->dev;
dma_buf->private_data = NULL;
-
- dma_buf->addr = allocate_contiguous_ebi_nomap(
- runtime->hw.buffer_bytes_max, SZ_4K);
- if (!dma_buf->addr) {
+ dma_buf->area = buf[0].data;
+ dma_buf->addr = buf[0].phys;
+ dma_buf->bytes = runtime->hw.buffer_bytes_max;
+ if (!dma_buf->area) {
pr_err("%s:MSM AFE physical memory allocation failed\n",
__func__);
mutex_unlock(&prtd->lock);
return -ENOMEM;
}
-
- flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
-
- prtd->mem_buffer = msm_subsystem_map_buffer(dma_buf->addr,
- runtime->hw.buffer_bytes_max, flags,
- NULL, 0);
- if (IS_ERR((void *) prtd->mem_buffer)) {
- pr_err("%s: map_buffer failed error = %ld\n", __func__,
- PTR_ERR((void *)prtd->mem_buffer));
- free_contiguous_memory_by_paddr(dma_buf->addr);
- mutex_unlock(&prtd->lock);
- return -ENOMEM;
- }
-
- dma_buf->area = prtd->mem_buffer->vaddr;
-
- pr_debug("%s: dma_buf->area: 0x%p, dma_buf->addr: 0x%x", __func__,
- (unsigned int *) dma_buf->area, dma_buf->addr);
-
- if (!dma_buf->area) {
- pr_err("%s: Invalid Virtual address\n", __func__);
- if (prtd->mem_buffer) {
- msm_subsystem_unmap_buffer(prtd->mem_buffer);
- prtd->mem_buffer = NULL;
- dma_buf->area = NULL;
- }
- free_contiguous_memory_by_paddr(dma_buf->addr);
- mutex_unlock(&prtd->lock);
- return -ENOMEM;
- }
-
- dma_buf->bytes = runtime->hw.buffer_bytes_max;
memset(dma_buf->area, 0, runtime->hw.buffer_bytes_max);
prtd->dma_addr = (u32) dma_buf->addr;
@@ -528,11 +530,11 @@
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
- rc = afe_cmd_memory_map(dma_buf->addr, dma_buf->bytes);
- if (rc < 0)
+ ret = afe_cmd_memory_map(dma_buf->addr, dma_buf->bytes);
+ if (ret < 0)
pr_err("fail to map memory to DSP\n");
- return rc;
+ return ret;
}
static snd_pcm_uframes_t msm_afe_pointer(struct snd_pcm_substream *substream)
{
diff --git a/sound/soc/msm/msm-pcm-afe.h b/sound/soc/msm/msm-pcm-afe.h
index 38026d5..9be11f3 100644
--- a/sound/soc/msm/msm-pcm-afe.h
+++ b/sound/soc/msm/msm-pcm-afe.h
@@ -30,7 +30,7 @@
int prepared;
struct hrtimer hrt;
int poll_time;
- struct msm_mapped_buffer *mem_buffer;
+ struct audio_client *audio_client;
};
diff --git a/sound/soc/msm/msm-pcm-lpa.c b/sound/soc/msm/msm-pcm-lpa.c
index c65a7d2..269b49b 100644
--- a/sound/soc/msm/msm-pcm-lpa.c
+++ b/sound/soc/msm/msm-pcm-lpa.c
@@ -109,12 +109,16 @@
break;
} else
atomic_set(&prtd->pending_buffer, 0);
- if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
- break;
+
+ buf = prtd->audio_client->port[IN].buf;
+ if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
+ memset((void *)buf[0].data +
+ (prtd->out_head * prtd->pcm_count),
+ 0, prtd->pcm_count);
+ }
pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
__func__, prtd->pcm_count);
- buf = prtd->audio_client->port[IN].buf;
param.paddr = (unsigned long)buf[0].phys
+ (prtd->out_head * prtd->pcm_count);
param.len = prtd->pcm_count;
@@ -229,10 +233,12 @@
pr_debug("SNDRV_PCM_TRIGGER_START\n");
q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
atomic_set(&prtd->start, 1);
+ atomic_set(&prtd->stop, 0);
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
atomic_set(&prtd->start, 0);
+ atomic_set(&prtd->stop, 1);
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
break;
break;
@@ -320,6 +326,7 @@
prtd->dsp_cnt = 0;
atomic_set(&prtd->pending_buffer, 1);
+ atomic_set(&prtd->stop, 1);
runtime->private_data = prtd;
lpa_audio.prtd = prtd;
lpa_set_volume(lpa_audio.volume);
@@ -363,7 +370,8 @@
To issue EOS to dsp, we need to be run state otherwise
EOS is not honored.
*/
- if (msm_routing_check_backend_enabled(soc_prtd->dai_link->be_id)) {
+ if (msm_routing_check_backend_enabled(soc_prtd->dai_link->be_id) &&
+ (!atomic_read(&prtd->stop))) {
rc = q6asm_run(prtd->audio_client, 0, 0, 0);
atomic_set(&prtd->pending_buffer, 0);
prtd->cmd_ack = 0;
@@ -383,6 +391,7 @@
q6asm_audio_client_buf_free_contiguous(dir,
prtd->audio_client);
+ atomic_set(&prtd->stop, 1);
pr_debug("%s\n", __func__);
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
SNDRV_PCM_STREAM_PLAYBACK);
diff --git a/sound/soc/msm/msm-pcm-q6.h b/sound/soc/msm/msm-pcm-q6.h
index e5551ea..9e743a7 100644
--- a/sound/soc/msm/msm-pcm-q6.h
+++ b/sound/soc/msm/msm-pcm-q6.h
@@ -71,6 +71,7 @@
int close_ack;
int cmd_ack;
atomic_t start;
+ atomic_t stop;
atomic_t out_count;
atomic_t in_count;
atomic_t out_needed;
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 7a269ca..8051c92 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -48,6 +48,7 @@
static int fm_switch_enable;
static int fm_pcmrx_switch_enable;
+static int srs_alsa_ctrl_ever_called;
#define INT_RX_VOL_MAX_STEPS 0x2000
#define INT_RX_VOL_GAIN 0x2000
@@ -120,6 +121,12 @@
static void srs_send_params(int port_id, unsigned int techs,
int param_block_idx) {
+
+ /* only send commands to dsp if srs alsa ctrl was used
+ at least one time */
+ if (!srs_alsa_ctrl_ever_called)
+ return;
+
pr_debug("SRS %s: called, port_id = %d, techs flags = %u,"
" paramblockidx %d", __func__, port_id, techs,
param_block_idx);
@@ -172,9 +179,12 @@
{ SLIMBUS_4_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_4_TX, 0, 0, 0, 0, 0},
{ SLIMBUS_3_RX, 0, 0, 0, 0, 0},
+ { SLIMBUS_3_TX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+ { SECONDARY_PCM_RX, 0, 0, 0, 0, 0},
+ { SECONDARY_PCM_TX, 0, 0, 0, 0, 0},
};
@@ -188,6 +198,15 @@
{INVALID_SESSION, INVALID_SESSION},
/* MULTIMEDIA4 */
{INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA5 */
+ {INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA6 */
+ {INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA7*/
+ {INVALID_SESSION, INVALID_SESSION},
+ /* MULTIMEDIA8 */
+ {INVALID_SESSION, INVALID_SESSION},
+
};
static uint8_t is_be_dai_extproc(int be_dai)
@@ -316,6 +335,8 @@
payload.copp_ids[payload.num_copps++] =
msm_bedais[i].port_id;
+ srs_port_id = msm_bedais[i].port_id;
+ srs_send_params(srs_port_id, 1, 0);
}
}
if (payload.num_copps)
@@ -424,6 +445,8 @@
msm_pcm_routing_build_matrix(val,
fe_dai_map[val][session_type], path_type);
+ srs_port_id = msm_bedais[reg].port_id;
+ srs_send_params(srs_port_id, 1, 0);
}
} else {
if (test_bit(val, &msm_bedais[reg].fe_sessions) &&
@@ -493,6 +516,8 @@
session_id = voc_get_session_id(VOICE_SESSION_NAME);
else if (val == MSM_FRONTEND_DAI_VOLTE)
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (val == MSM_FRONTEND_DAI_SGLTE)
+ session_id = voc_get_session_id(SGLTE_SESSION_NAME);
else
session_id = voc_get_session_id(VOIP_SESSION_NAME);
@@ -799,6 +824,8 @@
unsigned int techs = 0;
unsigned short offset, value, max, index;
+ srs_alsa_ctrl_ever_called = 1;
+
max = sizeof(msm_srs_trumedia_params) >> 1;
index = (unsigned short)((ucontrol->value.integer.value[0] &
SRS_PARAM_INDEX_MASK) >> 31);
@@ -1027,6 +1054,18 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = {
@@ -1042,6 +1081,18 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = {
@@ -1057,6 +1108,18 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_SLIMBUS_0_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_SLIMBUS_0_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_mixer_controls[] = {
@@ -1072,6 +1135,18 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
@@ -1087,6 +1162,18 @@
SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
};
/* incall music delivery mixer */
static const struct snd_kcontrol_new incall_music_delivery_mixer_controls[] = {
@@ -1167,6 +1254,15 @@
msm_routing_put_audio_mixer),
};
+static const struct snd_kcontrol_new sec_auxpcm_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
+};
+
static const struct snd_kcontrol_new mmul1_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
@@ -1180,6 +1276,9 @@
SOC_SINGLE_EXT("AUX_PCM_UL_TX", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_UL_TX", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+ msm_routing_put_audio_mixer),
SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
@@ -1219,6 +1318,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_PRI_I2S_RX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_voice_mixer_controls[] = {
@@ -1231,6 +1333,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_I2S_RX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new slimbus_rx_voice_mixer_controls[] = {
@@ -1243,6 +1348,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_RX ,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new bt_sco_rx_voice_mixer_controls[] = {
@@ -1258,6 +1366,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_INT_BT_SCO_RX ,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new mi2s_rx_voice_mixer_controls[] = {
@@ -1270,6 +1381,9 @@
SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_MI2S_RX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_MI2S_RX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new afe_pcm_rx_voice_mixer_controls[] = {
@@ -1285,6 +1399,9 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AFE_PCM_RX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new aux_pcm_rx_voice_mixer_controls[] = {
@@ -1300,6 +1417,24 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_AUXPCM_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_AUXPCM_RX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
+
+static const struct snd_kcontrol_new sec_aux_pcm_rx_voice_mixer_controls[] = {
+ SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voip", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new hdmi_rx_voice_mixer_controls[] = {
@@ -1312,6 +1447,12 @@
SOC_SINGLE_EXT("VoLTE", MSM_BACKEND_DAI_HDMI_RX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SGLTE", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new stub_rx_mixer_controls[] = {
@@ -1351,6 +1492,9 @@
SOC_SINGLE_EXT("AUX_PCM_TX_Voice", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voice", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_volte_mixer_controls[] = {
@@ -1369,8 +1513,34 @@
SOC_SINGLE_EXT("AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_VoLTE", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
+static const struct snd_kcontrol_new tx_sglte_mixer_controls[] = {
+ SOC_SINGLE_EXT("PRI_TX_SGLTE", MSM_BACKEND_DAI_PRI_I2S_TX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("MI2S_TX_SGLTE", MSM_BACKEND_DAI_MI2S_TX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SLIM_0_TX_SGLTE", MSM_BACKEND_DAI_SLIMBUS_0_TX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX_SGLTE",
+ MSM_BACKEND_DAI_INT_BT_SCO_TX, MSM_FRONTEND_DAI_SGLTE, 1, 0,
+ msm_routing_get_voice_mixer, msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AFE_PCM_TX_SGLTE", MSM_BACKEND_DAI_AFE_PCM_TX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("AUX_PCM_TX_SGLTE", MSM_BACKEND_DAI_AUXPCM_TX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_SGLTE", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_SGLTE, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
+};
static const struct snd_kcontrol_new tx_voip_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX_Voip", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
@@ -1390,6 +1560,9 @@
SOC_SINGLE_EXT("AUX_PCM_TX_Voip", MSM_BACKEND_DAI_AUXPCM_TX,
MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
msm_routing_put_voice_mixer),
+ SOC_SINGLE_EXT("SEC_AUX_PCM_TX_Voip", MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+ MSM_FRONTEND_DAI_VOIP, 1, 0, msm_routing_get_voice_mixer,
+ msm_routing_put_voice_mixer),
};
static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
@@ -1408,6 +1581,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_SLIMBUS_3_TX,
+ MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
+ msm_routing_put_voice_stub_mixer),
};
static const struct snd_kcontrol_new sbus_0_rx_port_mixer_controls[] = {
@@ -1465,6 +1641,9 @@
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_HDMI_RX,
MSM_BACKEND_DAI_MI2S_TX, 1, 0, msm_routing_get_port_mixer,
msm_routing_put_port_mixer),
+ SOC_SINGLE_EXT("SLIM_3_TX", MSM_BACKEND_DAI_HDMI_RX,
+ MSM_BACKEND_DAI_SLIMBUS_3_TX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
};
static const struct snd_kcontrol_new sec_i2s_rx_port_mixer_controls[] = {
@@ -1753,6 +1932,10 @@
SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
@@ -1760,6 +1943,8 @@
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VoLTE_UL", "VoLTE Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SGLTE_DL", "SGLTE Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SGLTE_UL", "SGLTE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOIP_UL", "VoIP Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("SLIM0_DL_HL", "SLIMBUS0_HOSTLESS Playback",
0, 0, 0, 0),
@@ -1817,6 +2002,10 @@
SND_SOC_DAPM_AIF_OUT("AUX_PCM_RX", "AUX PCM Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("AUX_PCM_TX", "AUX PCM Capture", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("SEC_AUX_PCM_RX", "SEC AUX PCM Playback",
+ 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SEC_AUX_PCM_TX", "SEC AUX PCM Capture",
+ 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VOICE_STUB_DL", "VOICE_STUB Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("VOICE_STUB_UL", "VOICE_STUB Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("STUB_RX", "Stub Playback", 0, 0, 0, 0),
@@ -1825,6 +2014,7 @@
SND_SOC_DAPM_AIF_IN("SLIMBUS_1_TX", "Slimbus1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("STUB_1_TX", "Stub1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIMBUS_3_TX", "Slimbus3 Capture", 0, 0, 0, 0),
/* Switch Definitions */
SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1848,6 +2038,8 @@
mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ sec_auxpcm_rx_mixer_controls, ARRAY_SIZE(sec_auxpcm_rx_mixer_controls)),
/* incall */
SND_SOC_DAPM_MIXER("Incall_Music Audio Mixer", SND_SOC_NOPM, 0, 0,
incall_music_delivery_mixer_controls,
@@ -1879,6 +2071,10 @@
SND_SOC_NOPM, 0, 0,
aux_pcm_rx_voice_mixer_controls,
ARRAY_SIZE(aux_pcm_rx_voice_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX_Voice Mixer",
+ SND_SOC_NOPM, 0, 0,
+ sec_aux_pcm_rx_voice_mixer_controls,
+ ARRAY_SIZE(sec_aux_pcm_rx_voice_mixer_controls)),
SND_SOC_DAPM_MIXER("HDMI_RX_Voice Mixer",
SND_SOC_NOPM, 0, 0,
hdmi_rx_voice_mixer_controls,
@@ -1896,6 +2092,9 @@
SND_SOC_DAPM_MIXER("VoLTE_Tx Mixer",
SND_SOC_NOPM, 0, 0, tx_volte_mixer_controls,
ARRAY_SIZE(tx_volte_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SGLTE_Tx Mixer",
+ SND_SOC_NOPM, 0, 0, tx_sglte_mixer_controls,
+ ARRAY_SIZE(tx_sglte_mixer_controls)),
SND_SOC_DAPM_MIXER("INTERNAL_BT_SCO_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
int_bt_sco_rx_mixer_controls, ARRAY_SIZE(int_bt_sco_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("INTERNAL_FM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@@ -1948,24 +2147,40 @@
{"PRI_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"PRI_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"PRI_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"PRI_I2S_RX", NULL, "PRI_RX Audio Mixer"},
{"SEC_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SEC_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SEC_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SEC_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SEC_I2S_RX", NULL, "SEC_RX Audio Mixer"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SLIMBUS_0_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_0_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
{"SLIMBUS_0_RX", NULL, "SLIMBUS_0_RX Audio Mixer"},
{"HDMI Mixer", "MultiMedia1", "MM_DL1"},
{"HDMI Mixer", "MultiMedia2", "MM_DL2"},
{"HDMI Mixer", "MultiMedia3", "MM_DL3"},
{"HDMI Mixer", "MultiMedia4", "MM_DL4"},
+ {"HDMI Mixer", "MultiMedia5", "MM_DL5"},
+ {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
+ {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
+ {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
{"HDMI", NULL, "HDMI Mixer"},
/* incall */
@@ -1990,6 +2205,7 @@
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
+ {"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
@@ -2023,38 +2239,55 @@
{"AUX_PCM_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX Audio Mixer"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX Audio Mixer"},
+
{"PRI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"PRI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"PRI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"PRI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PRI_I2S_RX", NULL, "PRI_RX_Voice Mixer"},
{"SEC_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SEC_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"SEC_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SEC_I2S_RX", NULL, "SEC_RX_Voice Mixer"},
{"SLIM_0_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"SLIM_0_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SLIM_0_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"SLIM_0_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"SLIMBUS_0_RX", NULL, "SLIM_0_RX_Voice Mixer"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"INTERNAL_BT_SCO_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX_Voice Mixer"},
{"AFE_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AFE_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"AFE_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"AFE_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"PCM_RX", NULL, "AFE_PCM_RX_Voice Mixer"},
{"AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"AUX_PCM_RX", NULL, "AUX_PCM_RX_Voice Mixer"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
+ {"SEC_AUX_PCM_RX_Voice Mixer", "Voip", "VOIP_DL"},
+ {"SEC_AUX_PCM_RX", NULL, "SEC_AUX_PCM_RX_Voice Mixer"},
+
{"HDMI_RX_Voice Mixer", "CSVoice", "CS-VOICE_DL1"},
{"HDMI_RX_Voice Mixer", "VoLTE", "VoLTE_DL"},
+ {"HDMI_RX_Voice Mixer", "SGLTE", "SGLTE_DL"},
{"HDMI_RX_Voice Mixer", "Voip", "VOIP_DL"},
{"HDMI", NULL, "HDMI_RX_Voice Mixer"},
{"HDMI", NULL, "HDMI_DL_HL"},
@@ -2065,19 +2298,30 @@
{"Voice_Tx Mixer", "INTERNAL_BT_SCO_TX_Voice", "INT_BT_SCO_TX"},
{"Voice_Tx Mixer", "AFE_PCM_TX_Voice", "PCM_TX"},
{"Voice_Tx Mixer", "AUX_PCM_TX_Voice", "AUX_PCM_TX"},
+ {"Voice_Tx Mixer", "SEC_AUX_PCM_TX_Voice", "SEC_AUX_PCM_TX"},
{"CS-VOICE_UL1", NULL, "Voice_Tx Mixer"},
{"VoLTE_Tx Mixer", "PRI_TX_VoLTE", "PRI_I2S_TX"},
{"VoLTE_Tx Mixer", "SLIM_0_TX_VoLTE", "SLIMBUS_0_TX"},
{"VoLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_VoLTE", "INT_BT_SCO_TX"},
{"VoLTE_Tx Mixer", "AFE_PCM_TX_VoLTE", "PCM_TX"},
{"VoLTE_Tx Mixer", "AUX_PCM_TX_VoLTE", "AUX_PCM_TX"},
+ {"VoLTE_Tx Mixer", "SEC_AUX_PCM_TX_VoLTE", "SEC_AUX_PCM_TX"},
{"VoLTE_UL", NULL, "VoLTE_Tx Mixer"},
+ {"SGLTE_Tx Mixer", "PRI_TX_SGLTE", "PRI_I2S_TX"},
+ {"SGLTE_Tx Mixer", "MI2S_TX_SGLTE", "MI2S_TX"},
+ {"SGLTE_Tx Mixer", "SLIM_0_TX_SGLTE", "SLIMBUS_0_TX"},
+ {"SGLTE_Tx Mixer", "INTERNAL_BT_SCO_TX_SGLTE", "INT_BT_SCO_TX"},
+ {"SGLTE_Tx Mixer", "AFE_PCM_TX_SGLTE", "PCM_TX"},
+ {"SGLTE_Tx Mixer", "AUX_PCM_TX_SGLTE", "AUX_PCM_TX"},
+ {"SGLTE_Tx Mixer", "SEC_AUX_PCM_TX_SGLTE", "SEC_AUX_PCM_TX"},
+ {"SGLTE_UL", NULL, "SGLTE_Tx Mixer"},
{"Voip_Tx Mixer", "PRI_TX_Voip", "PRI_I2S_TX"},
{"Voip_Tx Mixer", "MI2S_TX_Voip", "MI2S_TX"},
{"Voip_Tx Mixer", "SLIM_0_TX_Voip", "SLIMBUS_0_TX"},
{"Voip_Tx Mixer", "INTERNAL_BT_SCO_TX_Voip", "INT_BT_SCO_TX"},
{"Voip_Tx Mixer", "AFE_PCM_TX_Voip", "PCM_TX"},
{"Voip_Tx Mixer", "AUX_PCM_TX_Voip", "AUX_PCM_TX"},
+ {"Voip_Tx Mixer", "SEC_AUX_PCM_TX_Voip", "SEC_AUX_PCM_TX"},
{"VOIP_UL", NULL, "Voip_Tx Mixer"},
{"SLIMBUS_DL_HL", "Switch", "SLIM0_DL_HL"},
@@ -2108,6 +2352,7 @@
{"Voice Stub Tx Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"Voice Stub Tx Mixer", "STUB_1_TX_HL", "STUB_1_TX"},
{"Voice Stub Tx Mixer", "MI2S_TX", "MI2S_TX"},
+ {"Voice Stub Tx Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
{"VOICE_STUB_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -2117,6 +2362,7 @@
{"INTERNAL_BT_SCO_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"MI2S_RX", NULL, "MI2S_RX_Voice Mixer"},
+ {"HDMI_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_3_RX_Voice Mixer", "Voice Stub", "VOICE_STUB_DL"},
{"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX_Voice Mixer"},
@@ -2131,6 +2377,7 @@
{"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
+ {"HDMI_RX Port Mixer", "SLIM_3_TX", "SLIMBUS_3_TX"},
{"HDMI", NULL, "HDMI_RX Port Mixer"},
{"SEC_I2S_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
@@ -2155,6 +2402,8 @@
{"BE_OUT", NULL, "PCM_RX"},
{"PCM_TX", NULL, "BE_IN"},
{"BE_OUT", NULL, "SLIMBUS_3_RX"},
+ {"BE_OUT", NULL, "STUB_RX"},
+ {"STUB_TX", NULL, "BE_IN"},
};
static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index ff073ce..2f213e7 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -26,6 +26,8 @@
#define LPASS_BE_AFE_PCM_TX "RT_PROXY_DAI_002_TX"
#define LPASS_BE_AUXPCM_RX "AUX_PCM_RX"
#define LPASS_BE_AUXPCM_TX "AUX_PCM_TX"
+#define LPASS_BE_SEC_AUXPCM_RX "SEC_AUX_PCM_RX"
+#define LPASS_BE_SEC_AUXPCM_TX "SEC_AUX_PCM_TX"
#define LPASS_BE_VOICE_PLAYBACK_TX "VOICE_PLAYBACK_TX"
#define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_TX"
#define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_RX"
@@ -39,6 +41,7 @@
#define LPASS_BE_SLIMBUS_1_TX "SLIMBUS_1_TX"
#define LPASS_BE_STUB_1_TX "STUB_1_TX"
#define LPASS_BE_SLIMBUS_3_RX "SLIMBUS_3_RX"
+#define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
#define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
#define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
@@ -53,17 +56,22 @@
MSM_FRONTEND_DAI_MULTIMEDIA2,
MSM_FRONTEND_DAI_MULTIMEDIA3,
MSM_FRONTEND_DAI_MULTIMEDIA4,
+ MSM_FRONTEND_DAI_MULTIMEDIA5,
+ MSM_FRONTEND_DAI_MULTIMEDIA6,
+ MSM_FRONTEND_DAI_MULTIMEDIA7,
+ MSM_FRONTEND_DAI_MULTIMEDIA8,
MSM_FRONTEND_DAI_CS_VOICE,
MSM_FRONTEND_DAI_VOIP,
MSM_FRONTEND_DAI_AFE_RX,
MSM_FRONTEND_DAI_AFE_TX,
MSM_FRONTEND_DAI_VOICE_STUB,
MSM_FRONTEND_DAI_VOLTE,
+ MSM_FRONTEND_DAI_SGLTE,
MSM_FRONTEND_DAI_MAX,
};
-#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA4 + 1)
-#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA4
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA8 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA8
enum {
MSM_BACKEND_DAI_PRI_I2S_RX = 0,
@@ -90,9 +98,12 @@
MSM_BACKEND_DAI_SLIMBUS_4_RX,
MSM_BACKEND_DAI_SLIMBUS_4_TX,
MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_SLIMBUS_3_TX,
MSM_BACKEND_DAI_EXTPROC_RX,
MSM_BACKEND_DAI_EXTPROC_TX,
MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+ MSM_BACKEND_DAI_SEC_AUXPCM_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 7bdb4f0..633973e 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -59,6 +59,14 @@
return false;
}
+static int is_sglte(struct msm_voice *psglte)
+{
+ if (psglte == &voice_info[SGLTE_SESSION_INDEX])
+ return true;
+ else
+ return false;
+}
+
static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -93,6 +101,10 @@
voice = &voice_info[VOLTE_SESSION_INDEX];
pr_debug("%s: Open VoLTE Substream Id=%s\n",
__func__, substream->pcm->id);
+ } else if (!strncmp("SGLTE", substream->pcm->id, 5)) {
+ voice = &voice_info[SGLTE_SESSION_INDEX];
+ pr_debug("%s: Open SGLTE Substream Id=%s\n",
+ __func__, substream->pcm->id);
} else {
voice = &voice_info[VOICE_SESSION_INDEX];
pr_debug("%s: Open VOICE Substream Id=%s\n",
@@ -162,6 +174,8 @@
pr_debug("end voice call\n");
if (is_volte(prtd))
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (is_sglte(prtd))
+ session_id = voc_get_session_id(SGLTE_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
voc_end_voice_call(session_id);
@@ -187,6 +201,8 @@
if (prtd->playback_start && prtd->capture_start) {
if (is_volte(prtd))
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (is_sglte(prtd))
+ session_id = voc_get_session_id(SGLTE_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
voc_start_voice_call(session_id);
@@ -217,6 +233,8 @@
pr_debug("%s: cmd = %d\n", __func__, cmd);
if (is_volte(prtd))
session_id = voc_get_session_id(VOLTE_SESSION_NAME);
+ else if (is_sglte(prtd))
+ session_id = voc_get_session_id(SGLTE_SESSION_NAME);
else
session_id = voc_get_session_id(VOICE_SESSION_NAME);
@@ -290,6 +308,23 @@
return 0;
}
+static int msm_sglte_volume_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_sglte_volume_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int volume = ucontrol->value.integer.value[0];
+ pr_debug("%s: volume: %d\n", __func__, volume);
+ voc_set_rx_vol_index(voc_get_session_id(SGLTE_SESSION_NAME),
+ RX_PATH, volume);
+ return 0;
+}
+
static int msm_voice_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -328,6 +363,25 @@
return 0;
}
+static int msm_sglte_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = 0;
+ return 0;
+}
+
+static int msm_sglte_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mute = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+
+ voc_set_tx_mute(voc_get_session_id(SGLTE_SESSION_NAME), TX_PATH, mute);
+
+ return 0;
+}
+
static int msm_voice_rx_device_mute_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -368,6 +422,26 @@
return 0;
}
+static int msm_sglte_rx_device_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ voc_get_rx_device_mute(voc_get_session_id(SGLTE_SESSION_NAME));
+ return 0;
+}
+
+static int msm_sglte_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mute = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+
+ voc_set_rx_device_mute(voc_get_session_id(SGLTE_SESSION_NAME), mute);
+
+ return 0;
+}
+
static const char const *tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
static const struct soc_enum msm_tty_mode_enum[] = {
SOC_ENUM_SINGLE_EXT(4, tty_mode),
@@ -481,6 +555,13 @@
msm_volte_mute_get, msm_volte_mute_put),
SOC_SINGLE_EXT("VoLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
msm_volte_volume_get, msm_volte_volume_put),
+ SOC_SINGLE_EXT("SGLTE Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_sglte_rx_device_mute_get,
+ msm_sglte_rx_device_mute_put),
+ SOC_SINGLE_EXT("SGLTE Tx Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_sglte_mute_get, msm_sglte_mute_put),
+ SOC_SINGLE_EXT("SGLTE Rx Volume", SND_SOC_NOPM, 0, 5, 0,
+ msm_sglte_volume_get, msm_sglte_volume_put),
};
static struct snd_pcm_ops msm_pcm_ops = {
@@ -543,6 +624,7 @@
memset(&voice_info, 0, sizeof(voice_info));
mutex_init(&voice_info[VOICE_SESSION_INDEX].lock);
mutex_init(&voice_info[VOLTE_SESSION_INDEX].lock);
+ mutex_init(&voice_info[SGLTE_SESSION_INDEX].lock);
return platform_driver_register(&msm_pcm_driver);
}
diff --git a/sound/soc/msm/msm-pcm-voice.h b/sound/soc/msm/msm-pcm-voice.h
index aa00577..41aca89 100644
--- a/sound/soc/msm/msm-pcm-voice.h
+++ b/sound/soc/msm/msm-pcm-voice.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011,2012 Code Aurora Forum. 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
@@ -16,6 +16,7 @@
enum {
VOICE_SESSION_INDEX,
VOLTE_SESSION_INDEX,
+ SGLTE_SESSION_INDEX,
VOICE_SESSION_INDEX_MAX,
};
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 0f91665..20ac6e1 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -311,11 +311,11 @@
{"MIC BIAS2 Internal1", NULL, "Headset Mic"},
/* Microphone path */
- {"AMIC1", NULL, "MIC BIAS2 Internal1"},
- {"MIC BIAS2 Internal1", NULL, "ANCLeft Headset Mic"},
+ {"AMIC1", NULL, "MIC BIAS2 External"},
+ {"MIC BIAS2 External", NULL, "ANCLeft Headset Mic"},
- {"AMIC3", NULL, "MIC BIAS2 Internal1"},
- {"MIC BIAS2 Internal1", NULL, "ANCRight Headset Mic"},
+ {"AMIC3", NULL, "MIC BIAS2 External"},
+ {"MIC BIAS2 External", NULL, "ANCRight Headset Mic"},
{"HEADPHONE", NULL, "LDO_H"},
@@ -514,7 +514,7 @@
#undef S
#define S(X, Y) ((SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar_cal)->X) = (Y))
S(v_no_mic, 30);
- S(v_hs_max, 1550);
+ S(v_hs_max, 1650);
#undef S
#define S(X, Y) ((SITAR_MBHC_CAL_BTN_DET_PTR(sitar_cal)->X) = (Y))
S(c[0], 62);
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index bb5d817..2c44b46 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -47,6 +47,7 @@
#define BOTTOM_SPK_AMP_NEG 0x2
#define TOP_SPK_AMP_POS 0x4
#define TOP_SPK_AMP_NEG 0x8
+#define TOP_SPK_AMP 0x10
#define GPIO_AUX_PCM_DOUT 63
#define GPIO_AUX_PCM_DIN 64
@@ -191,10 +192,14 @@
usleep_range(4000, 4000);
}
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+ } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
- if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+ pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+ __func__, msm8960_ext_top_spk_pamp, spk);
+
+ if (((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+ (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+ (msm8960_ext_top_spk_pamp & TOP_SPK_AMP)) {
pr_debug("%s() External Top Speaker Ampl already"
"turned on. spk = 0x%08x\n", __func__, spk);
@@ -203,8 +208,9 @@
msm8960_ext_top_spk_pamp |= spk;
- if ((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
- (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
+ if (((msm8960_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
+ (msm8960_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) ||
+ (msm8960_ext_top_spk_pamp & TOP_SPK_AMP)) {
msm8960_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
pr_debug("%s: sleeping 4 ms after turning on "
@@ -235,17 +241,31 @@
usleep_range(4000, 4000);
- } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
+ } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG | TOP_SPK_AMP)) {
+
+ pr_debug("%s: top_spk_amp_state = 0x%x spk_event = 0x%x\n",
+ __func__, msm8960_ext_top_spk_pamp, spk);
if (!msm8960_ext_top_spk_pamp)
return;
+ if ((spk & TOP_SPK_AMP_POS) || (spk & TOP_SPK_AMP_NEG)) {
+
+ msm8960_ext_top_spk_pamp &= (~(TOP_SPK_AMP_POS |
+ TOP_SPK_AMP_NEG));
+ } else if (spk & TOP_SPK_AMP) {
+ msm8960_ext_top_spk_pamp &= ~TOP_SPK_AMP;
+ }
+
+ if (msm8960_ext_top_spk_pamp)
+ return;
+
gpio_direction_output(top_spk_pamp_gpio, 0);
gpio_free(top_spk_pamp_gpio);
msm8960_ext_top_spk_pamp = 0;
- pr_debug("%s: sleeping 4 ms after turning off external Top"
- " Spkaker Ampl\n", __func__);
+ pr_debug("%s: sleeping 4 ms after ext Top Spek Ampl is off\n",
+ __func__);
usleep_range(4000, 4000);
} else {
@@ -313,6 +333,8 @@
msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
msm8960_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top", 12))
+ msm8960_ext_spk_power_amp_on(TOP_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
@@ -328,6 +350,8 @@
msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
msm8960_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
+ else if (!strncmp(w->name, "Ext Spk Top", 12))
+ msm8960_ext_spk_power_amp_off(TOP_SPK_AMP);
else {
pr_err("%s() Invalid Speaker Widget = %s\n",
__func__, w->name);
@@ -411,6 +435,7 @@
SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm8960_spkramp_event),
SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm8960_spkramp_event),
+ SND_SOC_DAPM_SPK("Ext Spk Top", msm8960_spkramp_event),
SND_SOC_DAPM_MIC("Handset Mic", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
@@ -438,6 +463,7 @@
{"Ext Spk Top Pos", NULL, "LINEOUT2"},
{"Ext Spk Top Neg", NULL, "LINEOUT4"},
+ {"Ext Spk Top", NULL, "LINEOUT5"},
/* Microphone path */
{"AMIC1", NULL, "MIC BIAS1 Internal1"},
@@ -725,8 +751,6 @@
int ret = 0;
unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
- unsigned int user_set_tx_ch = 0;
-
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -754,13 +778,8 @@
}
} else {
- if (codec_dai->id == 2)
- user_set_tx_ch = msm8960_slim_0_tx_ch;
- else if (codec_dai->id == 4)
- user_set_tx_ch = params_channels(params);
-
- pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
- codec_dai->name, codec_dai->id, user_set_tx_ch);
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, msm8960_slim_0_tx_ch);
ret = snd_soc_dai_get_channel_map(codec_dai,
&tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
@@ -769,20 +788,88 @@
goto end;
}
ret = snd_soc_dai_set_channel_map(cpu_dai,
- user_set_tx_ch, tx_ch, 0 , 0);
+ msm8960_slim_0_tx_ch, tx_ch, 0 , 0);
if (ret < 0) {
pr_err("%s: failed to set cpu chan map\n", __func__);
goto end;
}
ret = snd_soc_dai_set_channel_map(codec_dai,
- user_set_tx_ch, tx_ch, 0, 0);
+ msm8960_slim_0_tx_ch, tx_ch, 0, 0);
if (ret < 0) {
pr_err("%s: failed to set codec channel map\n",
__func__);
goto end;
}
+ }
+end:
+ return ret;
+}
+static int msm8960_slimbus_2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+ unsigned int num_tx_ch = 0;
+ unsigned int num_rx_ch = 0;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+
+ num_rx_ch = params_channels(params);
+
+ pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_rx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ num_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+ num_tx_ch = params_channels(params);
+
+ pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__,
+ codec_dai->name, codec_dai->id, num_tx_ch);
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ num_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ num_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
}
end:
return ret;
@@ -1011,8 +1098,11 @@
}
static int msm8960_startup(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ pr_debug("%s(): dai_link_str_name = %s cpu_dai = %s codec_dai = %s\n",
+ __func__, rtd->dai_link->stream_name,
+ rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
return 0;
}
@@ -1038,8 +1128,11 @@
static void msm8960_shutdown(struct snd_pcm_substream *substream)
{
- pr_debug("%s(): substream = %s stream = %d\n", __func__,
- substream->name, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+ pr_debug("%s(): dai_link str_name = %s cpu_dai = %s codec_dai = %s\n",
+ __func__, rtd->dai_link->stream_name,
+ rtd->dai_link->cpu_dai_name, rtd->dai_link->codec_dai_name);
}
static struct snd_soc_ops msm8960_be_ops = {
@@ -1053,6 +1146,12 @@
.shutdown = msm8960_auxpcm_shutdown,
};
+static struct snd_soc_ops msm8960_slimbus_2_be_ops = {
+ .startup = msm8960_startup,
+ .hw_params = msm8960_slimbus_2_hw_params,
+ .shutdown = msm8960_shutdown,
+};
+
/* Digital audio interface glue - connects codec <---> CPU */
static struct snd_soc_dai_link msm8960_dai_common[] = {
/* FrontEnd DAI Links */
@@ -1222,6 +1321,21 @@
.codec_name = "snd-soc-dummy",
.be_id = MSM_FRONTEND_DAI_VOLTE,
},
+ {
+ .name = "SGLTE",
+ .stream_name = "SGLTE",
+ .cpu_dai_name = "SGLTE",
+ .platform_name = "msm-pcm-voice",
+ .dynamic = 1,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_suspend = 1,
+ .ignore_pmdown_time = 1,/* this dainlink has playback support */
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .be_id = MSM_FRONTEND_DAI_SGLTE,
+ },
/* Backend BT/FM DAI Links */
{
.name = LPASS_BE_INT_BT_SCO_RX,
@@ -1396,16 +1510,29 @@
.be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
.ops = &msm8960_be_ops,
},
+ /* Ultrasound TX Back End DAI Link */
{
- .name = "SLIMBUS_2 Hostless",
- .stream_name = "SLIMBUS_2 Hostless",
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
.cpu_dai_name = "msm-dai-q6.16389",
.platform_name = "msm-pcm-hostless",
.codec_name = "tabla1x_codec",
.codec_dai_name = "tabla_tx2",
.ignore_suspend = 1,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ops = &msm8960_be_ops,
+ .ops = &msm8960_slimbus_2_be_ops,
+ },
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tabla1x_codec",
+ .codec_dai_name = "tabla_rx3",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm8960_slimbus_2_be_ops,
},
};
@@ -1438,16 +1565,29 @@
.be_hw_params_fixup = msm8960_slim_0_tx_be_hw_params_fixup,
.ops = &msm8960_be_ops,
},
+ /* Ultrasound TX Back End DAI Link */
{
- .name = "SLIMBUS_2 Hostless",
- .stream_name = "SLIMBUS_2 Hostless",
+ .name = "SLIMBUS_2 Hostless Capture",
+ .stream_name = "SLIMBUS_2 Hostless Capture",
.cpu_dai_name = "msm-dai-q6.16389",
.platform_name = "msm-pcm-hostless",
.codec_name = "tabla_codec",
.codec_dai_name = "tabla_tx2",
.ignore_suspend = 1,
.no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
- .ops = &msm8960_be_ops,
+ .ops = &msm8960_slimbus_2_be_ops,
+ },
+ /* Ultrasound RX Back End DAI Link */
+ {
+ .name = "SLIMBUS_2 Hostless Playback",
+ .stream_name = "SLIMBUS_2 Hostless Playback",
+ .cpu_dai_name = "msm-dai-q6.16388",
+ .platform_name = "msm-pcm-hostless",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_rx3",
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ops = &msm8960_slimbus_2_be_ops,
},
};
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index d47910b..4678ea4 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -21,7 +21,6 @@
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
-#include <sound/soc-dsp.h>
#include <sound/pcm.h>
#include <sound/jack.h>
#include <asm/mach-types.h>
@@ -123,8 +122,8 @@
}
ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, ¶m);
if (ret)
- pr_err("%s: Failed to configure Bottom Spk Ampl"
- " gpio %u\n", __func__, bottom_spk_pamp_gpio);
+ pr_err("%s: Failed to configure Bottom Spk Ampl gpio %u\n",
+ __func__, bottom_spk_pamp_gpio);
else {
pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
gpio_direction_output(bottom_spk_pamp_gpio, 1);
@@ -140,15 +139,15 @@
}
ret = pm8xxx_gpio_config(top_spk_pamp_gpio, ¶m);
if (ret)
- pr_err("%s: Failed to configure Top Spk Ampl"
- " gpio %u\n", __func__, top_spk_pamp_gpio);
+ pr_err("%s: Failed to configure Top Spk Ampl gpio %u\n",
+ __func__, top_spk_pamp_gpio);
else {
pr_debug("%s: enable Top spkr amp gpio\n", __func__);
gpio_direction_output(top_spk_pamp_gpio, 1);
}
} else {
- pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
- " gpio = %u\n", __func__, spk_amp_gpio);
+ pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO. gpio = %u\n",
+ __func__, spk_amp_gpio);
return;
}
}
@@ -160,8 +159,8 @@
if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
- pr_debug("%s() External Bottom Speaker Ampl already "
- "turned on. spk = 0x%08x\n", __func__, spk);
+ pr_debug("%s() External Bottom Speaker Ampl already turned on. spk = 0x%08x\n",
+ __func__, spk);
return;
}
@@ -171,8 +170,8 @@
(msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
- pr_debug("%s: slepping 4 ms after turning on external "
- " Bottom Speaker Ampl\n", __func__);
+ pr_debug("%s: slepping 4 ms after turning on external Bottom Speaker Ampl\n",
+ __func__);
usleep_range(4000, 4000);
}
@@ -181,8 +180,8 @@
if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
- pr_debug("%s() External Top Speaker Ampl already"
- "turned on. spk = 0x%08x\n", __func__, spk);
+ pr_debug("%s() External Top Speaker Ampl already turned on. spk = 0x%08x\n",
+ __func__, spk);
return;
}
@@ -192,8 +191,8 @@
(msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
- pr_debug("%s: sleeping 4 ms after turning on "
- " external Top Speaker Ampl\n", __func__);
+ pr_debug("%s: sleeping 4 ms after turning on external Top Speaker Ampl\n",
+ __func__);
usleep_range(4000, 4000);
}
} else {
@@ -215,8 +214,8 @@
gpio_free(bottom_spk_pamp_gpio);
msm_ext_bottom_spk_pamp = 0;
- pr_debug("%s: sleeping 4 ms after turning off external Bottom"
- " Speaker Ampl\n", __func__);
+ pr_debug("%s: sleeping 4 ms after turning off external Bottom Speaker Ampl\n",
+ __func__);
usleep_range(4000, 4000);
@@ -229,8 +228,8 @@
gpio_free(top_spk_pamp_gpio);
msm_ext_top_spk_pamp = 0;
- pr_debug("%s: sleeping 4 ms after turning off external Top"
- " Spkaker Ampl\n", __func__);
+ pr_debug("%s: sleeping 4 ms after turning off external Top Spkaker Ampl\n",
+ __func__);
usleep_range(4000, 4000);
} else {
@@ -442,9 +441,9 @@
{"MIC BIAS4 External", NULL, "Digital Mic6"},
};
-static const char *spk_function[] = {"Off", "On"};
-static const char *slim0_rx_ch_text[] = {"One", "Two"};
-static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
+static const char *const spk_function[] = {"Off", "On"};
+static const char *const slim0_rx_ch_text[] = {"One", "Two"};
+static const char *const slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
static const struct soc_enum msm_enum[] = {
SOC_ENUM_SINGLE_EXT(2, spk_function),
@@ -452,7 +451,7 @@
SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
};
-static const char *btsco_rate_text[] = {"8000", "16000"};
+static const char *const btsco_rate_text[] = {"8000", "16000"};
static const struct soc_enum msm_btsco_enum[] = {
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
@@ -537,21 +536,6 @@
msm_btsco_rate_get, msm_btsco_rate_put),
};
-static struct snd_soc_dsp_link lpa_fe_media = {
- .playback = true,
- .trigger = {
- SND_SOC_DSP_TRIGGER_POST,
- SND_SOC_DSP_TRIGGER_POST
- },
-};
-static struct snd_soc_dsp_link fe_media = {
- .playback = true,
- .capture = true,
- .trigger = {
- SND_SOC_DSP_TRIGGER_POST,
- SND_SOC_DSP_TRIGGER_POST
- },
-};
static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -654,7 +638,13 @@
.cpu_dai_name = "MultiMedia1",
.platform_name = "msm-pcm-dsp",
.dynamic = 1,
- .dsp_link = &fe_media,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
},
{
@@ -663,7 +653,13 @@
.cpu_dai_name = "MultiMedia3",
.platform_name = "msm-pcm-lpa",
.dynamic = 1,
- .dsp_link = &lpa_fe_media,
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .ignore_suspend = 1,
+ /* this dainlink has playback support */
+ .ignore_pmdown_time = 1,
.be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
},
@@ -679,6 +675,8 @@
.be_id = MSM_BACKEND_DAI_AUXPCM_RX,
.be_hw_params_fixup = msm_auxpcm_be_params_fixup,
.ops = &msm_auxpcm_be_ops,
+ .ignore_pmdown_time = 1,
+ /* this dainlink has playback support */
},
{
.name = LPASS_BE_AUXPCM_TX,
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index 51ef359..7b16adb 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -142,6 +142,7 @@
switch (port_id) {
case PRIMARY_I2S_RX:
case PCM_RX:
+ case SECONDARY_PCM_RX:
case SECONDARY_I2S_RX:
case MI2S_RX:
case HDMI_RX:
@@ -160,6 +161,7 @@
case PRIMARY_I2S_TX:
case PCM_TX:
+ case SECONDARY_PCM_TX:
case SECONDARY_I2S_TX:
case MI2S_TX:
case DIGI_MIC_TX:
@@ -167,6 +169,7 @@
case SLIMBUS_0_TX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_TX:
case INT_FM_TX:
case VOICE_RECORD_RX:
case INT_BT_SCO_TX:
@@ -192,6 +195,8 @@
case PRIMARY_I2S_TX:
case PCM_RX:
case PCM_TX:
+ case SECONDARY_PCM_RX:
+ case SECONDARY_PCM_TX:
case SECONDARY_I2S_RX:
case SECONDARY_I2S_TX:
case MI2S_RX:
@@ -210,6 +215,7 @@
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
case INT_BT_A2DP_RX:
@@ -259,6 +265,8 @@
case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
case PCM_RX: return IDX_PCM_RX;
case PCM_TX: return IDX_PCM_TX;
+ case SECONDARY_PCM_RX: return IDX_SECONDARY_PCM_RX;
+ case SECONDARY_PCM_TX: return IDX_SECONDARY_PCM_TX;
case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
case MI2S_RX: return IDX_MI2S_RX;
@@ -277,6 +285,7 @@
case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
+ case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
@@ -313,6 +322,7 @@
case SLIMBUS_2_RX:
case SLIMBUS_2_TX:
case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
@@ -323,6 +333,8 @@
break;
case PCM_RX:
case PCM_TX:
+ case SECONDARY_PCM_RX:
+ case SECONDARY_PCM_TX:
default:
ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
break;
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index 0c30dc9..f66a01c 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -34,6 +34,7 @@
#define VOC_PATH_PASSIVE 0
#define VOC_PATH_FULL 1
#define VOC_PATH_VOLTE_PASSIVE 2
+#define VOC_PATH_SGLTE_PASSIVE 3
/* CVP CAL Size: 245760 = 240 * 1024 */
#define CVP_CAL_SIZE 245760
@@ -149,6 +150,9 @@
else if (!strncmp(name, "VoLTE session", 13))
session_id =
common.voice[VOC_PATH_VOLTE_PASSIVE].session_id;
+ else if (!strncmp(name, "SGLTE session", 13))
+ session_id =
+ common.voice[VOC_PATH_SGLTE_PASSIVE].session_id;
else
session_id = common.voice[VOC_PATH_FULL].session_id;
@@ -189,6 +193,11 @@
return (session_id == common.voice[VOC_PATH_VOLTE_PASSIVE].session_id);
}
+static bool is_sglte_session(u16 session_id)
+{
+ return (session_id == common.voice[VOC_PATH_SGLTE_PASSIVE].session_id);
+}
+
static int voice_apr_register(void)
{
pr_debug("%s\n", __func__);
@@ -275,8 +284,10 @@
pr_err("%s: apr_mvm is NULL.\n", __func__);
return -EINVAL;
}
- pr_debug("%s: VoLTE command to MVM\n", __func__);
- if (is_volte_session(v->session_id)) {
+ pr_debug("%s: VoLTE/SGLTE command to MVM\n", __func__);
+ if (is_volte_session(v->session_id) ||
+ is_sglte_session(v->session_id)) {
+
mvm_handle = voice_get_mvm_handle(v);
mvm_voice_ctl_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
@@ -350,7 +361,8 @@
if (!mvm_handle) {
if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id)) {
+ is_volte_session(v->session_id) ||
+ is_sglte_session(v->session_id)) {
mvm_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE),
@@ -369,11 +381,15 @@
if (is_volte_session(v->session_id)) {
strlcpy(mvm_session_cmd.mvm_session.name,
"default volte voice",
+ sizeof(mvm_session_cmd.mvm_session.name) - 1);
+ } else if (is_sglte_session(v->session_id)) {
+ strlcpy(mvm_session_cmd.mvm_session.name,
+ "default modem voice2",
sizeof(mvm_session_cmd.mvm_session.name));
} else {
- strlcpy(mvm_session_cmd.mvm_session.name,
+ strlcpy(mvm_session_cmd.mvm_session.name,
"default modem voice",
- sizeof(mvm_session_cmd.mvm_session.name));
+ sizeof(mvm_session_cmd.mvm_session.name) - 1);
}
v->mvm_state = CMD_STATUS_FAIL;
@@ -432,7 +448,8 @@
/* send cmd to create cvs session */
if (!cvs_handle) {
if (is_voice_session(v->session_id) ||
- is_volte_session(v->session_id)) {
+ is_volte_session(v->session_id) ||
+ is_sglte_session(v->session_id)) {
pr_debug("%s: creating CVS passive session\n",
__func__);
@@ -452,11 +469,15 @@
if (is_volte_session(v->session_id)) {
strlcpy(mvm_session_cmd.mvm_session.name,
"default volte voice",
- sizeof(mvm_session_cmd.mvm_session.name));
- } else {
- strlcpy(cvs_session_cmd.cvs_session.name,
- "default modem voice",
+ sizeof(mvm_session_cmd.mvm_session.name) - 1);
+ } else if (is_sglte_session(v->session_id)) {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ "default modem voice2",
sizeof(cvs_session_cmd.cvs_session.name));
+ } else {
+ strlcpy(cvs_session_cmd.cvs_session.name,
+ "default modem voice",
+ sizeof(cvs_session_cmd.cvs_session.name) - 1);
}
v->cvs_state = CMD_STATUS_FAIL;
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 88ab0d5..468aba8 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -16,7 +16,7 @@
#include <linux/ion.h>
#define MAX_VOC_PKT_SIZE 642
-#define SESSION_NAME_LEN 20
+#define SESSION_NAME_LEN 21
#define VOC_REC_UPLINK 0x00
#define VOC_REC_DOWNLINK 0x01
@@ -918,7 +918,7 @@
void *buf;
};
-#define MAX_VOC_SESSIONS 3
+#define MAX_VOC_SESSIONS 4
#define SESSION_ID_BASE 0xFFF0
struct common_data {
@@ -990,6 +990,7 @@
#define VOICE_SESSION_NAME "Voice session"
#define VOIP_SESSION_NAME "VoIP session"
#define VOLTE_SESSION_NAME "VoLTE session"
+#define SGLTE_SESSION_NAME "SGLTE session"
uint16_t voc_get_session_id(char *name);
int voc_start_playback(uint32_t set);
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index daba79d..7723934 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -139,8 +139,7 @@
case ASM_SESSION_CMD_RUN_V2: {
if (!atomic_read(&prtd->pending_buffer))
break;
- pr_debug("%s:writing %d bytes"
- " of buffer[%d] to dsp\n",
+ pr_debug("%s:writing %d bytes of buffer[%d] to dsp\n",
__func__, prtd->pcm_count, prtd->out_head);
buf = prtd->audio_client->port[IN].buf;
pr_debug("%s:writing buffer[%d] from 0x%08x\n",
@@ -367,8 +366,8 @@
rc = q6asm_set_volume(compressed_audio.prtd->audio_client,
volume);
if (rc < 0) {
- pr_err("%s: Send Volume command failed"
- " rc=%d\n", __func__, rc);
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
}
}
compressed_audio.volume = volume;
@@ -489,8 +488,8 @@
runtime->hw.period_bytes_min,
runtime->hw.periods_max);
if (ret < 0) {
- pr_err("Audio Start: Buffer Allocation failed "
- "rc = %d\n", ret);
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+ ret);
return -ENOMEM;
}
buf = prtd->audio_client->port[dir].buf;
@@ -535,12 +534,9 @@
temp = temp * (runtime->rate/1000);
temp = div_u64(temp, 1000);
tstamp.sampling_rate = runtime->rate;
- tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
- tstamp.decoded = (size_t)((temp >> 32) & 0xFFFFFFFF);
tstamp.timestamp = timestamp;
- pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
- "timestamp = %lld,\n",
- __func__, tstamp.rendered, tstamp.decoded,
+ pr_debug("%s: bytes_consumed:,timestamp = %lld,\n",
+ __func__,
tstamp.timestamp);
if (copy_to_user((void *) arg, &tstamp,
sizeof(struct snd_compr_tstamp)))
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
index 2183690..9830300 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.h
@@ -15,7 +15,7 @@
#define _MSM_COMPR_H
#include <sound/apr_audio-v2.h>
#include <sound/q6asm-v2.h>
-#include <sound/snd_compress_params.h>
+#include <sound/compress_params.h>
#include <sound/compress_offload.h>
#include <sound/compress_driver.h>
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
index ee92753..05ef2ce 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-lpa-v2.c
@@ -27,7 +27,7 @@
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/android_pmem.h>
-#include <sound/snd_compress_params.h>
+#include <sound/compress_params.h>
#include <sound/compress_offload.h>
#include <sound/compress_driver.h>
#include <sound/timer.h>
@@ -148,8 +148,7 @@
if (runtime->status->hw_ptr >=
runtime->control->appl_ptr)
break;
- pr_debug("%s:writing %d bytes"
- " of buffer to dsp\n",
+ pr_debug("%s:writing %d bytes of buffer to dsp\n",
__func__, prtd->pcm_count);
buf = prtd->audio_client->port[IN].buf;
param.paddr = (unsigned long)buf[prtd->out_head].phys;
@@ -340,8 +339,8 @@
if (lpa_audio.prtd && lpa_audio.prtd->audio_client) {
rc = q6asm_set_volume(lpa_audio.prtd->audio_client, volume);
if (rc < 0) {
- pr_err("%s: Send Volume command failed"
- " rc=%d\n", __func__, rc);
+ pr_err("%s: Send Volume command failed rc=%d\n",
+ __func__, rc);
}
}
lpa_audio.volume = volume;
@@ -461,8 +460,8 @@
runtime->hw.period_bytes_min,
runtime->hw.periods_max);
if (ret < 0) {
- pr_err("Audio Start: Buffer Allocation failed "
- "rc = %d\n", ret);
+ pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
+ ret);
return -ENOMEM;
}
buf = prtd->audio_client->port[dir].buf;
@@ -509,12 +508,9 @@
temp = temp * (runtime->rate/1000);
temp = div_u64(temp, 1000);
tstamp.sampling_rate = runtime->rate;
- tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
- tstamp.decoded = (size_t)((temp >> 32) & 0xFFFFFFFF);
tstamp.timestamp = timestamp;
- pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
- "timestamp = %lld,\n",
- __func__, tstamp.rendered, tstamp.decoded,
+ pr_debug("%s: bytes_consumed:timestamp = %lld,\n",
+ __func__,
tstamp.timestamp);
if (copy_to_user((void *) arg, &tstamp,
sizeof(struct snd_compr_tstamp)))
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 3a9fbe1..fd3fe6a 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -236,11 +236,24 @@
}
if (codec_dai->driver->ops->startup) {
- ret = codec_dai->driver->ops->startup(substream, codec_dai);
- if (ret < 0) {
- printk(KERN_ERR "asoc: can't open codec %s\n",
- codec_dai->name);
- goto codec_dai_err;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = codec_dai->driver->ops->startup(substream,
+ codec_dai);
+ if (ret < 0) {
+ printk(KERN_ERR "asoc: can't open codec %s\n",
+ codec_dai->name);
+ goto codec_dai_err;
+ }
+ } else {
+ if (!codec_dai->capture_active) {
+ ret = codec_dai->driver->ops->startup(substream,
+ codec_dai);
+ if (ret < 0) {
+ printk(KERN_ERR "can't open codec %s\n",
+ codec_dai->name);
+ goto codec_dai_err;
+ }
+ }
}
}
@@ -456,8 +469,15 @@
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_dai_digital_mute(codec_dai, 1);
- if (cpu_dai->driver->ops->shutdown)
- cpu_dai->driver->ops->shutdown(substream, cpu_dai);
+ if (cpu_dai->driver->ops->shutdown) {
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ codec_dai->driver->ops->shutdown(substream, codec_dai);
+ } else {
+ if (!codec_dai->capture_active)
+ codec_dai->driver->ops->shutdown(substream,
+ codec_dai);
+ }
+ }
if (codec_dai->driver->ops->shutdown)
codec_dai->driver->ops->shutdown(substream, codec_dai);
@@ -485,7 +505,8 @@
}
} else {
/* capture streams can be powered down now */
- snd_soc_dapm_stream_event(rtd,
+ if (!codec_dai->capture_active)
+ snd_soc_dapm_stream_event(rtd,
codec_dai->driver->capture.stream_name,
SND_SOC_DAPM_STREAM_STOP);
}
@@ -557,11 +578,12 @@
snd_soc_dapm_stream_event(rtd,
codec_dai->driver->playback.stream_name,
SND_SOC_DAPM_STREAM_START);
- else
- snd_soc_dapm_stream_event(rtd,
+ else {
+ if (codec_dai->capture_active == 1)
+ snd_soc_dapm_stream_event(rtd,
codec_dai->driver->capture.stream_name,
SND_SOC_DAPM_STREAM_START);
-
+ }
snd_soc_dai_digital_mute(codec_dai, 0);
out:
@@ -594,11 +616,24 @@
}
if (codec_dai->driver->ops->hw_params) {
- ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
- if (ret < 0) {
- printk(KERN_ERR "asoc: can't set codec %s hw params\n",
- codec_dai->name);
- goto codec_err;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = codec_dai->driver->ops->hw_params(substream,
+ params, codec_dai);
+ if (ret < 0) {
+ printk(KERN_ERR "not set codec %s hw params\n",
+ codec_dai->name);
+ goto codec_err;
+ }
+ } else {
+ if (codec_dai->capture_active == 1) {
+ ret = codec_dai->driver->ops->hw_params(
+ substream, params, codec_dai);
+ if (ret < 0) {
+ printk(KERN_ERR "fail: %s hw params\n",
+ codec_dai->name);
+ goto codec_err;
+ }
+ }
}
}
@@ -706,9 +741,19 @@
int ret;
if (codec_dai->driver->ops->trigger) {
- ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
- if (ret < 0)
- return ret;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = codec_dai->driver->ops->trigger(substream,
+ cmd, codec_dai);
+ if (ret < 0)
+ return ret;
+ } else {
+ if (codec_dai->capture_active == 1) {
+ ret = codec_dai->driver->ops->trigger(
+ substream, cmd, codec_dai);
+ if (ret < 0)
+ return ret;
+ }
+ }
}
if (platform->driver->ops && platform->driver->ops->trigger) {
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 1fcf1bb..28e5548 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -30,6 +30,17 @@
return __value(parse_events_text + 1, 16, PE_RAW);
}
+static int sh_raw(void)
+{
+ return __value(parse_events_text + 2, 16, PE_SH_RAW);
+}
+
+static int fab_raw(void)
+{
+ return __value(parse_events_text + 2, 16, PE_FAB_RAW);
+}
+
+
static int str(int token)
{
parse_events_lval.str = strdup(parse_events_text);
@@ -107,6 +118,8 @@
mem: { return PE_PREFIX_MEM; }
r{num_raw_hex} { return raw(); }
+rs{num_raw_hex} { return sh_raw(); }
+rm{num_raw_hex} { return fab_raw(); }
{num_dec} { return value(10); }
{num_hex} { return value(16); }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da..07b292d 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -24,7 +24,7 @@
%}
-%token PE_VALUE PE_VALUE_SYM PE_RAW PE_TERM
+%token PE_VALUE PE_VALUE_SYM PE_RAW PE_SH_RAW PE_FAB_RAW PE_TERM
%token PE_NAME
%token PE_MODIFIER_EVENT PE_MODIFIER_BP
%token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
@@ -33,6 +33,8 @@
%type <num> PE_VALUE
%type <num> PE_VALUE_SYM
%type <num> PE_RAW
+%type <num> PE_SH_RAW
+%type <num> PE_FAB_RAW
%type <num> PE_TERM
%type <str> PE_NAME
%type <str> PE_NAME_CACHE_TYPE
@@ -77,7 +79,9 @@
event_legacy_mem |
event_legacy_tracepoint sep_dc |
event_legacy_numeric sep_dc |
- event_legacy_raw sep_dc
+ event_legacy_raw sep_dc |
+ event_legacy_shared_raw sep_dc |
+ event_legacy_fabric_raw sep_dc
event_pmu:
PE_NAME '/' event_config '/'
@@ -149,6 +153,18 @@
ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL));
}
+event_legacy_shared_raw:
+PE_SH_RAW
+{
+ ABORT_ON(parse_events_add_numeric(list_event, idx, 6, $1, NULL));
+}
+
+event_legacy_fabric_raw:
+PE_FAB_RAW
+{
+ ABORT_ON(parse_events_add_numeric(list_event, idx, 7, $1, NULL));
+}
+
event_config:
event_config ',' event_term
{