Merge "msm: LPASS-8960: Retrieve LPASS failure reason" into msm-3.0
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
new file mode 100644
index 0000000..35385d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/lpm-levels.txt
@@ -0,0 +1,47 @@
+* Low Power Management Levels
+
+The application processor in MSM can do a variety of C-States for low power
+management. These C-States are invoked by the CPUIdle framework when the core
+becomes idle. But based on the time available until the next scheduled wakeup,
+the system can do a combination of low power modes of different resources -
+L2, XO, Vdd Dig and Vdd Mem. The combination is captured in the device tree as
+lpm-level. The units for voltage are dependent on the PMIC used on the target
+and are in uV.
+
+The required nodes for lpm-levels are:
+
+- compatible: "qcom,lpm-levels"
+- reg: The numeric level id
+- qcom,mode: The sleep mode of the processor
+- qcom,xo: The state of XO clock.
+- qcom,l2: The state of L2 cache.
+- qcom,vdd-mem-upper-bound: The upper bound value of mem voltage in uV
+- qcom,vdd-mem-lower-bound: The lower bound value of mem voltage in uV
+- qcom,vdd-dig-upper-bound: The upper bound value of dig voltage in uV
+- qcom,vdd-dig-lower-bound: The lower bound value of dig voltage in uV
+- qcom,latency-us: The latency in handling the interrupt if this level was
+ chosen, in uSec
+- qcom,ss-power: The steady state power expelled when the processor is in this
+ level in mWatts
+- qcom,energy-overhead: The energy used up in entering and exiting this level
+ in mWatts.uSec
+- qcom,time-overhead: The time spent in entering and exiting this level in uS
+
+Example:
+
+qcom,lpm-levels {
+ qcom,lpm-level@0 {
+ reg = <0>;
+ qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,latency-us = <100>;
+ qcom,ss-power = <650>;
+ qcom,energy-overhead = <801>;
+ qcom,time-overhead = <200>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-boot.txt b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
new file mode 100644
index 0000000..cce9d0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pm-boot.txt
@@ -0,0 +1,40 @@
+* Power Management boot configuration (pm-boot)
+
+Low power management drivers need to specify the warmboot entry path for the
+application processors to resume from sleep/suspend. The boot configuration
+can vary if the core does/does not support a secure boot mode. The secure
+boot configuration boots the core sets up the core sub system registers and
+calls into the kernel entry point. In the absence of a secure boot mode, the
+core when powered on from reset will need to be configured with the warmboot
+entry pointer. The physical and the virtual address for the entry pointer
+need to provided to the driver.
+
+
+The device tree parameters for pm-boot are:
+
+Required parameters:
+
+- compatible: Must be "qcom,pm-boot"
+- qcom,mode: The mode that the target will use for booting
+ MSM_PM_BOOT_CONFIG_TZ = 0,
+ MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
+ MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT = 2,
+ MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR = 3,
+
+Optional parameters (based on the mode chosen):
+
+- qcom,phy-addr: The physical address that will be used for warmboot entry if
+ the processor remap register can be programmed.
+ Needed for modes = { MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS,
+ MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR }
+- qcom,virt-addr: The virtual address at which the processor start booting from
+ Needed for modes = { MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT,
+ MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR }
+
+
+Example:
+
+ qcom,pm-boot {
+ compatible = "qcom,pm-boot";
+ qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 5839f63..939f77b 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -6,11 +6,41 @@
- interrupts : should contain the QUP core interrupt.
- spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
+Optional properties:
+- gpios : specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
+ that order.
+- cs-gpios : specifies the gpio pins to be used for chipselects.
+
+SPI slave nodes must be children of the SPI master node and contain
+the following properties.
+- reg : (required) chip select address of device.
+- compatible : (required) name of SPI device following generic names
+ recommended practice
+- spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz
+- interrupts : (recommended) should contain the SPI slave interrupt number
+ encoded depending on the type of the interrupt controller.
+- interrupt-parent : (recommended) the phandle for the interrupt controller
+ that services interrupts for this device.
+- spi-cpol : (optional) Empty property indicating device requires inverse
+ clock polarity (CPOL) mode
+- spi-cpha : (optional) Empty property indicating device requires shifted
+ clock phase (CPHA) mode
+- spi-cs-high : (optional) Empty property indicating device requires
+ chip select active high
+
Example:
spi@f9924000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9924000 0x1000>;
- interrupts = <96>;
+ interrupts = <0 96 0>;
spi-max-frequency = <24000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ device@0 {
+ compatible = "spidev";
+ reg = <0>;
+ spi-max-frequency = <5000000>;
+ };
};
diff --git a/Documentation/genlock.txt b/Documentation/genlock.txt
index 6f24a76..cd82614 100644
--- a/Documentation/genlock.txt
+++ b/Documentation/genlock.txt
@@ -34,6 +34,12 @@
space and kernel space to allow a kernel driver to unlock or lock a buffer
on behalf of a user process.
+Locks within a process using a single genlock handle follow the same rules for
+exclusive write locks with multiple readers. Genlock cannot provide deadlock
+protection because the same handle can be used simultaneously by a producer and
+consumer. In practice in the event that the client creates a deadlock an error
+will still be generated when the timeout expires.
+
Kernel API
Access to the genlock API can either be via the in-kernel API or via an
@@ -137,7 +143,12 @@
* GENLOCK_UNLOCK - unlock an existing lock
Pass flags in genlock_lock.flags:
- * GENLOCK_NOBLOCK - Do not block if the lock is already taken
+ * GENLOCK_NOBLOCK - Do not block if the lock is already taken
+ * GENLOCK_WRITE_TO_READ - Convert a write lock that the handle owns to a read
+ lock. For instance graphics may hold a write lock
+ while rendering the back buffer then when swapping
+ convert the lock to a read lock to copy the front
+ buffer in the next frame for preserved buffers.
Pass a timeout value in milliseconds in genlock_lock.timeout.
genlock_lock.flags and genlock_lock.timeout are not used for UNLOCK.
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index 81afa37..523c9b0 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -17,9 +17,9 @@
interrupt-controller;
#interrupt-cells = <3>;
- qcom,pm8841@3 {
+ qcom,pm8841@5 {
spmi-slave-container;
- reg = <0x3>;
+ reg = <0x5>;
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/msmcopper-regulator.dtsi b/arch/arm/boot/dts/msmcopper-regulator.dtsi
index b0c48fc..48d5720 100644
--- a/arch/arm/boot/dts/msmcopper-regulator.dtsi
+++ b/arch/arm/boot/dts/msmcopper-regulator.dtsi
@@ -20,6 +20,7 @@
regulator-max-microvolt = <1300000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -36,6 +37,7 @@
regulator-max-microvolt = <1800000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -52,6 +54,7 @@
regulator-max-microvolt = <1225000>;
qcom,enable-time = <200>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -285,13 +288,14 @@
};
};
- qcom,pm8841@3 {
+ qcom,pm8841@5 {
pm8841_s1: regulator@1400 {
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1150000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -300,6 +304,7 @@
regulator-max-microvolt = <1150000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -324,6 +329,7 @@
regulator-max-microvolt = <1100000>;
qcom,enable-time = <500>;
qcom,pull-down-enable = <1>;
+ regulator-always-on;
status = "okay";
};
@@ -352,4 +358,36 @@
};
};
};
+
+ krait0_vreg: regulator@f9088000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait0";
+ reg = <0xf9088000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait1_vreg: regulator@f9098000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait1";
+ reg = <0xf9098000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait2_vreg: regulator@f90a8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait2";
+ reg = <0xf90a8000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ krait3_vreg: regulator@f90b8000 {
+ compatible = "qcom,krait-regulator";
+ regulator-name = "krait3";
+ reg = <0xf90b8000 0x1000>;
+ regulator-min-microvolt = <500000>;
+ regulator-max-microvolt = <1100000>;
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper-rumi.dts b/arch/arm/boot/dts/msmcopper-rumi.dts
index bb53ff8..8c00535 100644
--- a/arch/arm/boot/dts/msmcopper-rumi.dts
+++ b/arch/arm/boot/dts/msmcopper-rumi.dts
@@ -46,6 +46,27 @@
status = "disable";
};
+ spi@f9923000 {
+ compatible = "qcom,spi-qup-v2";
+ reg = <0xf9923000 0x1000>;
+ interrupts = <0 95 0>;
+ spi-max-frequency = <24000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 9 0>;
+
+ ethernet-switch@2 {
+ compatible = "simtec,ks8851";
+ reg = <2>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <90 0>;
+ spi-max-frequency = <5000000>;
+ };
+ };
+
slim@fe12f000 {
status = "disable";
};
@@ -57,4 +78,16 @@
i2c@f9966000 {
status = "disable";
};
+
+ qcom,ssusb@F9200000 {
+ status = "disable";
+ };
+
+ qcom,lpass@fe200000 {
+ status = "disable";
+ };
+
+ qcom,pronto@fb21b000 {
+ status = "disable";
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper.dtsi b/arch/arm/boot/dts/msmcopper.dtsi
index 7dfa4df..fc9d50a 100644
--- a/arch/arm/boot/dts/msmcopper.dtsi
+++ b/arch/arm/boot/dts/msmcopper.dtsi
@@ -30,16 +30,17 @@
<0xF9002000 0x1000>;
};
- msmgpio: gpio@fd400000 {
+ msmgpio: gpio@fd510000 {
compatible = "qcom,msm-gpio";
interrupt-controller;
#interrupt-cells = <2>;
- reg = <0xfd400000 0x4000>;
+ reg = <0xfd510000 0x4000>;
+ #gpio-cells = <2>;
};
timer {
compatible = "qcom,msm-qtimer", "arm,armv7-timer";
- interrupts = <1 2 0>;
+ interrupts = <1 2 0 1 3 0>;
clock-frequency = <19200000>;
};
@@ -264,4 +265,8 @@
qcom,firmware-name = "wcnss";
};
+
+ qcom,ocmem@fdd00000 {
+ compatible = "qcom,msm_ocmem";
+ };
};
diff --git a/arch/arm/boot/dts/msmcopper_pm.dtsi b/arch/arm/boot/dts/msmcopper_pm.dtsi
index 53ad0d1..0da3200 100644
--- a/arch/arm/boot/dts/msmcopper_pm.dtsi
+++ b/arch/arm/boot/dts/msmcopper_pm.dtsi
@@ -131,4 +131,150 @@
07 01 b0 78 80 12 44 a0 50
3b 60 02 32 a0 50 0f];
};
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-level@0 {
+ reg = <0x0>;
+ qcom,mode = <0>; /* MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,latency-us = <100>;
+ qcom,ss-power = <650>;
+ qcom,energy-overhead = <801>;
+ qcom,time-overhead = <200>;
+ };
+
+ qcom,lpm-level@1 {
+ reg = <0x1>;
+ qcom,mode = <2>; /* MSM_PM_SLEEP_MODE_STANDALONE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <3>; /* ACTIVE */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,latency-us = <2000>;
+ qcom,ss-power = <200>;
+ qcom,energy-overhead = <576000>;
+ qcom,time-overhead = <2000>;
+ };
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,latency-us = <8500>;
+ qcom,ss-power = <51>;
+ qcom,energy-overhead = <1122000>;
+ qcom,time-overhead = <8500>;
+ };
+
+ qcom,lpm-level@3 {
+ reg = <0x3>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,latency-us = <9000>;
+ qcom,ss-power = <51>;
+ qcom,energy-overhead = <1130300>;
+ qcom,time-overhead = <9000>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <1>; /* ON */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-upper-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,latency-us = <10000>;
+ qcom,ss-power = <51>;
+ qcom,energy-overhead = <1130300>;
+ qcom,time-overhead = <10000>;
+ };
+
+ qcom,lpm-level@5 {
+ reg = <0x5>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <1>; /* GDHS */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,latency-us = <12000>;
+ qcom,ss-power = <14>;
+ qcom,energy-overhead = <2205900>;
+ qcom,time-overhead = <12000>;
+ };
+
+ qcom,lpm-level@6 {
+ reg = <0x6>;
+ qcom,mode = <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-mem-lower-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-dig-upper-bound = <1150000>; /* MAX */
+ qcom,vdd-dig-lower-bound = <950000>; /* ACTIVE */
+ qcom,latency-us = <18000>;
+ qcom,ss-power = <12>;
+ qcom,energy-overhead = <2364250>;
+ qcom,time-overhead = <18000>;
+ };
+
+ qcom,lpm-level@7 {
+ reg = <0x7>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <1050000>; /* ACTIVE */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-upper-bound = <950000>; /* ACTIVE */
+ qcom,vdd-dig-lower-bound = <750000>; /* RETIONTION HIGH */
+ qcom,latency-us = <23500>;
+ qcom,ss-power = <10>;
+ qcom,energy-overhead = <2667000>;
+ qcom,time-overhead = <23500>;
+ };
+
+ qcom,lpm-level@8 {
+ reg = <0x8>;
+ qcom,mode= <3>; /* MSM_PM_SLEEP_MODE_POWER_COLLAPSE */
+ qcom,xo = <0>; /* OFF */
+ qcom,l2 = <0>; /* OFF */
+ qcom,vdd-mem-upper-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-mem-lower-bound = <750000>; /* RETENTION LOW */
+ qcom,vdd-dig-upper-bound = <750000>; /* RETENTION HIGH */
+ qcom,vdd-dig-lower-bound = <500000>; /* RETENTION LOW */
+ qcom,latency-us = <29700>;
+ qcom,ss-power = <5>;
+ qcom,energy-overhead = <2867000>;
+ qcom,time-overhead = <30000>;
+ };
+ };
+
+ qcom,pm-boot {
+ compatible = "qcom,pm-boot";
+ qcom,mode = <0>; /* MSM_PM_BOOT_CONFIG_TZ */
+ };
};
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 9952818..bc350a7 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -220,7 +220,7 @@
# CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
CONFIG_DIAG_CHAR=y
# CONFIG_HW_RANDOM is not set
-CONFIG_DCC_TTY=y
+# CONFIG_DCC_TTY is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MSM is not set
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 0c5aa8f..fb5cff7 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -311,6 +311,7 @@
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
@@ -335,6 +336,9 @@
CONFIG_MSM_GEMINI=y
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
+CONFIG_MSM_EEPROM=y
+CONFIG_IMX074_EEPROM=y
+CONFIG_IMX091_EEPROM=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index eee361a..5c01299 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -320,6 +320,7 @@
CONFIG_MFD_PM8921_CORE=y
CONFIG_MFD_PM8821_CORE=y
CONFIG_MFD_PM8038_CORE=y
+CONFIG_MFD_PM8XXX_SPK=y
CONFIG_MFD_PM8XXX_BATT_ALARM=y
CONFIG_WCD9304_CODEC=y
CONFIG_WCD9310_CODEC=y
@@ -344,6 +345,9 @@
CONFIG_MSM_GEMINI=y
CONFIG_S5K3L1YX=y
CONFIG_IMX091=y
+CONFIG_MSM_EEPROM=y
+CONFIG_IMX074_EEPROM=y
+CONFIG_IMX091_EEPROM=y
CONFIG_RADIO_IRIS=y
CONFIG_RADIO_IRIS_TRANSPORT=m
CONFIG_ION=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 601f235..ac9f465 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -162,7 +162,7 @@
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_NETDEVICES=y
-CONFIG_ATH6K_LEGACY=y
+CONFIG_ATH6K_LEGACY_EXT=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
# CONFIG_INPUT_MOUSEDEV is not set
@@ -180,10 +180,8 @@
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
CONFIG_DIAG_CHAR=y
-CONFIG_HVC_DCC=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
-CONFIG_DCC_TTY=y
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MSM is not set
@@ -242,6 +240,7 @@
CONFIG_MMC_EMBEDDED_SDIO=y
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_CLKGATE=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_TEST=m
CONFIG_MMC_MSM=y
@@ -255,6 +254,9 @@
# CONFIG_RTC_INTF_ALARM is not set
# CONFIG_RTC_DRV_MSM is not set
CONFIG_RTC_DRV_PM8XXX=y
+CONFIG_STAGING=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_LOGGER=y
CONFIG_MSM_SSBI=y
CONFIG_SPS=y
CONFIG_USB_BAM=y
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index df30306..773b380 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -109,8 +109,8 @@
#define L2X0_PREFETCH_CTRL_WRAP8_SHIFT 30
#ifndef __ASSEMBLY__
-extern void l2x0_suspend(void);
-extern void l2x0_resume(int collapsed);
+extern void l2cc_suspend(void);
+extern void l2cc_resume(void);
extern void l2x0_cache_sync(void);
extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask);
#if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF)
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 7c7c0bb..4ecc3a4 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -231,6 +231,19 @@
select MSM_PM8X60 if PM
select CPU_HAS_L2_PMU
select HOLES_IN_ZONE if SPARSEMEM
+ select ENABLE_DMM
+ select MEMORY_HOTPLUG if ENABLE_DMM
+ select MEMORY_HOTREMOVE if ENABLE_DMM
+ select ARCH_ENABLE_MEMORY_HOTPLUG if ENABLE_DMM
+ select ARCH_ENABLE_MEMORY_HOTREMOVE if ENABLE_DMM
+ select MIGRATION if ENABLE_DMM
+ select ARCH_MEMORY_PROBE if ENABLE_DMM
+ select ARCH_MEMORY_REMOVE if ENABLE_DMM
+ select FIX_MOVABLE_ZONE if ENABLE_DMM
+ select CLEANCACHE
+ select QCACHE
+ select MIGHT_HAVE_PCI
+ select ARCH_SUPPORTS_MSI
config ARCH_MSMCOPPER
bool "MSM Copper"
@@ -245,6 +258,8 @@
select MSM_PIL
select MSM_SPM_V2
select MSM_L2_SPM
+ select MSM_RPM
+ select MSM_PM8X60 if PM
config ARCH_FSM9XXX
bool "FSM9XXX"
@@ -287,6 +302,18 @@
select MULTI_IRQ_HANDLER
select ARM_TICKET_LOCKS
select MSM_RUN_QUEUE_STATS
+
+config ARCH_MSM9625
+ bool "MSM9625"
+ select ARM_GIC
+ select GIC_SECURE
+ select ARCH_MSM_CORTEX_A5
+ select SMP
+ select MSM_SMP
+ select CPU_V7
+ select MULTI_IRQ_HANDLER
+ select MSM_V2_TLMM
+
endmenu
choice
@@ -530,6 +557,14 @@
help
Support for the Qualcomm MSM8625 Reference Design.
+config MACH_MSM8625_EVT
+ depends on ARCH_MSM8625
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM8625 EVT"
+ help
+ Support for the Qualcomm MSM8625 Reference Design.
+
config MACH_MSM7X30_SURF
depends on ARCH_MSM7X30
depends on !MSM_STACKED_MEMORY
@@ -846,6 +881,7 @@
default "0x80200000" if ARCH_MSM8930
default "0x20200000" if ARCH_MSMCOPPER
default "0x10000000" if ARCH_FSM9XXX
+ default "0x20200000" if ARCH_MSM9625
default "0x00200000" if !MSM_STACKED_MEMORY
default "0x00000000" if ARCH_QSD8X50 && MSM_SOC_REV_A
default "0x20000000" if ARCH_QSD8X50
@@ -1195,6 +1231,13 @@
prompt "Package 4"
endchoice
+config MSM_PCIE
+ bool "MSM PCIe Controller driver"
+ depends on PCI && PCI_MSI
+ help
+ Enables the PCIe functionality by configures PCIe core on
+ MSM chipset and by enabling the ARM PCI framework extension.
+
config MSM_RPC_SDIO_XPRT
depends on MSM_SDIO_AL
default y
@@ -2194,6 +2237,12 @@
instead of pmem. Selecting this may also involve userspace
dependencies as well.
+config MSM_OCMEM
+ bool "MSM On-Chip memory driver (OCMEM)"
+ help
+ Enable support for On-Chip Memory available on certain MSM chipsets.
+ OCMEM is a low latency, high performance pool shared by subsystems.
+
config MSM_RTB
bool "Register tracing"
help
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 3c4b5a8..d633aa7 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -156,6 +156,8 @@
obj-$(CONFIG_MSM_PM) += pm.o
obj-$(CONFIG_MSM_NOPM) += no-pm.o
+obj-$(CONFIG_MSM_PCIE) += pcie.o pcie_irq.o
+
obj-$(CONFIG_MSM_SPM_V1) += spm.o
obj-$(CONFIG_MSM_SPM_V2) += spm-v2.o spm_devices.o
@@ -201,6 +203,7 @@
obj-$(CONFIG_ARCH_MSM8960) += cpuidle.o
obj-$(CONFIG_ARCH_MSM8X60) += cpuidle.o
obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
+ obj-$(CONFIG_ARCH_MSMCOPPER) += cpuidle.o
endif
ifdef CONFIG_MSM_CAMERA_V4L2
@@ -242,6 +245,7 @@
obj-$(CONFIG_MACH_MSM8625_EVB) += board-qrd7627a.o board-7627a-all.o
obj-$(CONFIG_MACH_MSM8625_QRD7) += board-qrd7627a.o board-7627a-all.o
obj-$(CONFIG_MACH_MSM8625_FFA) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_EVT) += board-msm7x27a.o board-7627a-all.o
obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o memory_topology.o
obj-$(CONFIG_ARCH_MSM7X30) += clock-local.o clock-7x30.o acpuclock-7x30.o clock-pll.o
obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
@@ -293,7 +297,14 @@
obj-$(CONFIG_HTC_HEADSET) += htc_headset.o
obj-$(CONFIG_MSM_RMT_STORAGE_CLIENT) += rmt_storage_client.o
obj-$(CONFIG_MSM_SDIO_SMEM) += sdio_smem.o
-obj-$(CONFIG_MSM_RPM) += rpm.o rpm_resources.o
+obj-$(CONFIG_MSM_RPM) += rpm.o
+ifdef CONFIG_MSM_RPM
+ obj-$(CONFIG_ARCH_APQ8064) += rpm_resources.o
+ obj-$(CONFIG_ARCH_MSM8960) += rpm_resources.o
+ obj-$(CONFIG_ARCH_MSM8X60) += rpm_resources.o
+ obj-$(CONFIG_ARCH_MSM9615) += rpm_resources.o
+ obj-$(CONFIG_ARCH_MSMCOPPER) += lpm_levels.o
+endif
obj-$(CONFIG_MSM_MPM) += mpm.o
obj-$(CONFIG_MSM_RPM_STATS_LOG) += rpm_stats.o
obj-$(CONFIG_MSM_RPM_LOG) += rpm_log.o
@@ -307,6 +318,7 @@
ifdef CONFIG_VCM
obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-vcm.o
endif
+obj-$(CONFIG_MSM_OCMEM) += ocmem.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
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index eba5637..d53e471 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -241,6 +241,8 @@
static int disconnect_ack;
static LIST_HEAD(bam_other_notify_funcs);
static DEFINE_MUTEX(smsm_cb_lock);
+static DEFINE_MUTEX(delayed_ul_vote_lock);
+static int need_delayed_ul_vote;
struct outside_notify_func {
void (*notify)(void *, int, unsigned long);
@@ -1593,6 +1595,7 @@
static void ul_wakeup(void)
{
int ret;
+ int do_vote_dfab = 0;
mutex_lock(&wakeup_lock);
if (bam_is_connected) { /* bam got connected before lock grabbed */
@@ -1601,21 +1604,37 @@
return;
}
+ /*
+ * if someone is voting for UL before bam is inited (modem up first
+ * time), set flag for init to kickoff ul wakeup once bam is inited
+ */
+ mutex_lock(&delayed_ul_vote_lock);
+ if (unlikely(!bam_mux_initialized)) {
+ need_delayed_ul_vote = 1;
+ mutex_unlock(&delayed_ul_vote_lock);
+ mutex_unlock(&wakeup_lock);
+ return;
+ }
+ mutex_unlock(&delayed_ul_vote_lock);
+
if (a2_pc_disabled) {
/*
* don't grab the wakelock the first time because it is
* already grabbed when a2 powers on
*/
- if (likely(a2_pc_disabled_wakelock_skipped))
+ if (likely(a2_pc_disabled_wakelock_skipped)) {
grab_wakelock();
- else
+ do_vote_dfab = 1; /* vote must occur after wait */
+ } else {
a2_pc_disabled_wakelock_skipped = 1;
+ }
if (wait_for_dfab) {
ret = wait_for_completion_timeout(
&dfab_unvote_completion, HZ);
BUG_ON(ret == 0);
}
- vote_dfab();
+ if (likely(do_vote_dfab))
+ vote_dfab();
schedule_delayed_work(&ul_timeout_work,
msecs_to_jiffies(UL_TIMEOUT_DELAY));
bam_is_connected = 1;
@@ -2012,7 +2031,13 @@
goto rx_event_reg_failed;
}
+ mutex_lock(&delayed_ul_vote_lock);
bam_mux_initialized = 1;
+ if (need_delayed_ul_vote) {
+ need_delayed_ul_vote = 0;
+ msm_bam_dmux_kickoff_ul_wakeup();
+ }
+ mutex_unlock(&delayed_ul_vote_lock);
toggle_apps_ack();
bam_connection_is_active = 1;
complete_all(&bam_connection_completion);
@@ -2079,6 +2104,14 @@
goto register_bam_failed;
}
a2_device_handle = h;
+
+ mutex_lock(&delayed_ul_vote_lock);
+ bam_mux_initialized = 1;
+ if (need_delayed_ul_vote) {
+ need_delayed_ul_vote = 0;
+ msm_bam_dmux_kickoff_ul_wakeup();
+ }
+ mutex_unlock(&delayed_ul_vote_lock);
toggle_apps_ack();
return 0;
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 24f0f41..36953ef 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -468,6 +468,15 @@
.csi_lane_params = &imx074_csi_lane_params,
};
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+ I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+ .board_info = &imx074_eeprom_i2c_info,
+ .bus_id = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
.sensor_name = "imx074",
.pdata = &msm_camera_csi_device_data[0],
@@ -477,7 +486,9 @@
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
.actuator_info = &msm_act_main_cam_0_info,
+ .eeprom_info = &imx074_eeprom_info,
};
+
static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
.csi_lane_assign = 0xE4,
.csi_lane_mask = 0xF,
@@ -503,6 +514,15 @@
.csi_lane_params = &imx091_csi_lane_params,
};
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+ I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+ .board_info = &imx091_eeprom_i2c_info,
+ .bus_id = APQ_8064_GSBI4_QUP_I2C_BUS_ID,
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
.sensor_name = "imx091",
.pdata = &msm_camera_csi_device_data[0],
@@ -512,6 +532,7 @@
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
.actuator_info = &msm_act_main_cam_1_info,
+ .eeprom_info = &imx091_eeprom_info,
};
static struct camera_vreg_t apq_8064_s5k3l1yx_vreg[] = {
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index ee1a2ae..60bc26c 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -30,32 +30,13 @@
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
/* prim = 1366 x 768 x 3(bpp) x 3(pages) */
-#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1080 * 4 * 3, 0x10000)
+#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1088 * 4 * 3, 0x10000)
#else
/* prim = 1366 x 768 x 3(bpp) x 2(pages) */
-#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1080 * 4 * 2, 0x10000)
+#define MSM_FB_PRIM_BUF_SIZE roundup(1920 * 1088 * 4 * 2, 0x10000)
#endif
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-#define MSM_FB_EXT_BUF_SIZE \
- (roundup((1920 * 1088 * 2), 4096) * 1) /* 2 bpp x 1 page */
-#elif defined(CONFIG_FB_MSM_TVOUT)
-#define MSM_FB_EXT_BUF_SIZE \
- (roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
-#else
-#define MSM_FB_EXT_BUF_SIZE 0
-#endif
-
-#ifdef CONFIG_FB_MSM_WRITEBACK_MSM_PANEL
-#define MSM_FB_WFD_BUF_SIZE \
- (roundup((1280 * 736 * 2), 4096) * 1) /* 2 bpp x 1 page */
-#else
-#define MSM_FB_WFD_BUF_SIZE 0
-#endif
-
-#define MSM_FB_SIZE \
- roundup(MSM_FB_PRIM_BUF_SIZE + \
- MSM_FB_EXT_BUF_SIZE + MSM_FB_WFD_BUF_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
@@ -615,7 +596,7 @@
{
if (machine_is_apq8064_cdp() ||
machine_is_apq8064_liquid()) {
- u32 ver = socinfo_get_platform_version();
+ u32 ver = socinfo_get_version();
if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
(SOCINFO_VERSION_MINOR(ver) == 0))
return 1;
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index f915657..91fd400 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -126,6 +126,7 @@
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),
};
static struct pm8xxx_gpio_init pm8921_mtp_kp_gpios[] __initdata = {
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 01665be..58e83a0 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -559,15 +559,15 @@
RPM_SMPS(S1, 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20, NONE, NONE),
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, 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(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 */
- RPM_LDO(L1, 1, 1, 0, 1100000, 1100000, "8921_s4", 0, 10000),
+ RPM_LDO(L1, 1, 1, 0, 1100000, 1100000, "8921_s4", 0, 1000),
RPM_LDO(L2, 0, 1, 0, 1200000, 1200000, "8921_s4", 0, 0),
RPM_LDO(L3, 0, 1, 0, 3075000, 3075000, NULL, 0, 0),
- RPM_LDO(L4, 1, 1, 0, 1800000, 1800000, NULL, 10000, 10000),
+ RPM_LDO(L4, 1, 1, 0, 1800000, 1800000, NULL, 0, 10000),
RPM_LDO(L5, 0, 1, 0, 2950000, 2950000, NULL, 0, 0),
RPM_LDO(L6, 0, 1, 0, 2950000, 2950000, NULL, 0, 0),
RPM_LDO(L7, 0, 1, 0, 1850000, 2950000, NULL, 0, 0),
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index d91408a..b4e7d35 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -280,6 +280,13 @@
apq8064_sdc3_pdata->wpswitch_gpio = 0;
apq8064_sdc3_pdata->wpswitch_polarity = 0;
}
+ if (machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+ machine_is_mpq8064_dtv()) {
+ apq8064_sdc3_pdata->status_gpio =
+ PM8921_GPIO_PM_TO_SYS(31);
+ apq8064_sdc3_pdata->status_irq =
+ PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 31);
+ }
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 cfaa7da..62f5d70 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -27,6 +27,7 @@
#include <linux/platform_data/qcom_crypto_device.h>
#include <linux/ion.h>
#include <linux/memory.h>
+#include <linux/memblock.h>
#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/cyttsp.h>
#include <linux/i2c/isa1200.h>
@@ -67,6 +68,7 @@
#include <mach/msm_rtb.h>
#include <sound/cs8427.h>
#include <media/gpio-ir-recv.h>
+#include <linux/fmem.h>
#include "msm_watchdog.h"
#include "board-8064.h"
@@ -107,6 +109,11 @@
#define MSM_ION_HEAP_NUM 1
#endif
+#define APQ8064_FIXED_AREA_START 0xa0000000
+#define MAX_FIXED_AREA_SIZE 0x10000000
+#define MSM_MM_FW_SIZE 0x200000
+#define APQ8064_FW_START (APQ8064_FIXED_AREA_START - MSM_MM_FW_SIZE)
+
#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
static int __init pmem_kernel_ebi1_size_setup(char *p)
@@ -187,6 +194,9 @@
#endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
#endif /* CONFIG_ANDROID_PMEM */
+struct fmem_platform_data apq8064_fmem_pdata = {
+};
+
static struct memtype_reserve apq8064_reserve_table[] __initdata = {
[MEMTYPE_SMI] = {
},
@@ -243,26 +253,37 @@
return MEMTYPE_EBI1;
}
+#define FMEM_ENABLED 1
+
#ifdef CONFIG_ION_MSM
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_cp_heap_pdata cp_mm_apq8064_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
.align = PAGE_SIZE,
+ .reusable = FMEM_ENABLED,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_MIDDLE,
};
static struct ion_cp_heap_pdata cp_mfc_apq8064_ion_pdata = {
.permission_type = IPT_TYPE_MFC_SHAREDMEM,
.align = PAGE_SIZE,
+ .reusable = 0,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_HIGH,
};
static struct ion_co_heap_pdata co_apq8064_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
+ .mem_is_fmem = 0,
};
static struct ion_co_heap_pdata fw_co_apq8064_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
.align = SZ_128K,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_LOW,
};
#endif
@@ -352,15 +373,180 @@
};
#endif
+static struct platform_device apq8064_fmem_device = {
+ .name = "fmem",
+ .id = 1,
+ .dev = { .platform_data = &apq8064_fmem_pdata },
+};
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+ unsigned long size)
+{
+ apq8064_reserve_table[mem_type].size += size;
+}
+
+static void __init apq8064_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ int ret;
+
+ if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+ panic("fixed area size is larger than %dM\n",
+ MAX_FIXED_AREA_SIZE >> 20);
+
+ reserve_info->fixed_area_size = fixed_area_size;
+ reserve_info->fixed_area_start = APQ8064_FW_START;
+
+ ret = memblock_remove(reserve_info->fixed_area_start,
+ reserve_info->fixed_area_size);
+ BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
static void __init reserve_ion_memory(void)
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
- apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
- apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
- apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
- apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
- apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
- apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+ unsigned int i;
+ unsigned int reusable_count = 0;
+ unsigned int fixed_size = 0;
+ unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+ unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+ apq8064_fmem_pdata.size = 0;
+ apq8064_fmem_pdata.reserved_size_low = 0;
+ apq8064_fmem_pdata.reserved_size_high = 0;
+ fixed_low_size = 0;
+ fixed_middle_size = 0;
+ fixed_high_size = 0;
+
+ /* We only support 1 reusable heap. Check if more than one heap
+ * is specified as reusable and set as non-reusable if found.
+ */
+ for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+ const struct ion_platform_heap *heap =
+ &(apq8064_ion_pdata.heaps[i]);
+
+ if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+ struct ion_cp_heap_pdata *data = heap->extra_data;
+
+ reusable_count += (data->reusable) ? 1 : 0;
+
+ if (data->reusable && reusable_count > 1) {
+ pr_err("%s: Too many heaps specified as "
+ "reusable. Heap %s was not configured "
+ "as reusable.\n", __func__, heap->name);
+ data->reusable = 0;
+ }
+ }
+ }
+
+ for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+ const struct ion_platform_heap *heap =
+ &(apq8064_ion_pdata.heaps[i]);
+
+ if (heap->extra_data) {
+ int fixed_position = NOT_FIXED;
+ int mem_is_fmem = 0;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_CP:
+ mem_is_fmem = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->mem_is_fmem;
+ fixed_position = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ mem_is_fmem = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->mem_is_fmem;
+ fixed_position = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ default:
+ break;
+ }
+
+ if (fixed_position != NOT_FIXED)
+ fixed_size += heap->size;
+ else
+ reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+ if (fixed_position == FIXED_LOW)
+ fixed_low_size += heap->size;
+ else if (fixed_position == FIXED_MIDDLE)
+ fixed_middle_size += heap->size;
+ else if (fixed_position == FIXED_HIGH)
+ fixed_high_size += heap->size;
+
+ if (mem_is_fmem)
+ apq8064_fmem_pdata.size += heap->size;
+ }
+ }
+
+ if (!fixed_size)
+ return;
+
+ if (apq8064_fmem_pdata.size) {
+ apq8064_fmem_pdata.reserved_size_low = fixed_low_size;
+ apq8064_fmem_pdata.reserved_size_high = fixed_high_size;
+ }
+
+ /* Since the fixed area may be carved out of lowmem,
+ * make sure the length is a multiple of 1M.
+ */
+ fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+ & SECTION_MASK;
+ apq8064_reserve_fixed_area(fixed_size);
+
+ fixed_low_start = APQ8064_FIXED_AREA_START;
+ fixed_middle_start = fixed_low_start + fixed_low_size;
+ fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+ for (i = 0; i < apq8064_ion_pdata.nr; ++i) {
+ struct ion_platform_heap *heap = &(apq8064_ion_pdata.heaps[i]);
+
+ if (heap->extra_data) {
+ int fixed_position = NOT_FIXED;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_CP:
+ fixed_position = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ fixed_position = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ default:
+ break;
+ }
+
+ switch (fixed_position) {
+ case FIXED_LOW:
+ heap->base = fixed_low_start;
+ break;
+ case FIXED_MIDDLE:
+ heap->base = fixed_middle_start;
+ break;
+ case FIXED_HIGH:
+ heap->base = fixed_high_start;
+ break;
+ default:
+ break;
+ }
+ }
+ }
#endif
}
@@ -381,6 +567,7 @@
static struct reserve_info apq8064_reserve_info __initdata = {
.memtype_reserve_table = apq8064_reserve_table,
.calculate_reserve_sizes = apq8064_calculate_reserve_sizes,
+ .reserve_fixed_area = apq8064_reserve_fixed_area,
.paddr_to_memtype = apq8064_paddr_to_memtype,
};
@@ -401,12 +588,14 @@
/* Check if 32 bit overflow occured */
if (high < mb->start)
- high = ~0UL;
+ high = -PAGE_SIZE;
low &= ~(bank_size - 1);
if (high - low <= bank_size)
- return;
+ goto no_dmm;
+
+#ifdef CONFIG_ENABLE_DMM
apq8064_reserve_info.low_unstable_address = mb->start -
MIN_MEMORY_BLOCK_SIZE + mb->size;
apq8064_reserve_info.max_unstable_size = MIN_MEMORY_BLOCK_SIZE;
@@ -416,6 +605,11 @@
apq8064_reserve_info.low_unstable_address,
apq8064_reserve_info.max_unstable_size,
apq8064_reserve_info.bank_size);
+ return;
+#endif
+no_dmm:
+ apq8064_reserve_info.low_unstable_address = high;
+ apq8064_reserve_info.max_unstable_size = 0;
}
static int apq8064_change_memory_power(u64 start, u64 size,
@@ -446,14 +640,29 @@
{
apq8064_set_display_params(prim_panel_name, ext_panel_name);
msm_reserve();
+ if (apq8064_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ if (reserve_info->fixed_area_size) {
+ apq8064_fmem_pdata.phys =
+ reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+ pr_info("mm fw at %lx (fixed) size %x\n",
+ reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+ pr_info("fmem start %lx (fixed) size %lx\n",
+ apq8064_fmem_pdata.phys,
+ apq8064_fmem_pdata.size);
+ }
+#endif
+ }
}
static void __init place_movable_zone(void)
{
+#ifdef CONFIG_ENABLE_DMM
movable_reserved_start = apq8064_reserve_info.low_unstable_address;
movable_reserved_size = apq8064_reserve_info.max_unstable_size;
pr_info("movable zone start %lx size %lx\n",
movable_reserved_start, movable_reserved_size);
+#endif
}
static void __init apq8064_early_reserve(void)
@@ -1051,7 +1260,6 @@
0,
};
-#ifndef CONFIG_MSM_VCAP
#define MXT_TS_GPIO_IRQ 6
#define MXT_TS_PWR_EN_GPIO PM8921_GPIO_PM_TO_SYS(23)
#define MXT_TS_RESET_GPIO 33
@@ -1103,7 +1311,6 @@
.irq = MSM_GPIO_TO_INT(MXT_TS_GPIO_IRQ),
},
};
-#endif
#define CYTTSP_TS_GPIO_IRQ 6
#define CYTTSP_TS_GPIO_SLEEP 33
@@ -1846,13 +2053,14 @@
},
};
-static struct platform_device *common_devices[] __initdata = {
- &apq8064_device_dmov,
-#ifndef CONFIG_MSM_VCAP
+static struct platform_device *common_not_mpq_devices[] __initdata = {
&apq8064_device_qup_i2c_gsbi1,
&apq8064_device_qup_i2c_gsbi3,
&apq8064_device_qup_i2c_gsbi4,
-#endif
+};
+
+static struct platform_device *common_devices[] __initdata = {
+ &apq8064_device_dmov,
&apq8064_device_qup_spi_gsbi5,
&apq8064_device_ext_5v_vreg,
&apq8064_device_ext_mpp8_vreg,
@@ -1867,6 +2075,7 @@
&android_usb_device,
&msm_device_wcnss_wlan,
&msm_device_iris_fm,
+ &apq8064_fmem_device,
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
&apq8064_android_pmem_device,
@@ -1929,6 +2138,7 @@
&apq_cpudai_slimbus_1_rx,
&apq_cpudai_slimbus_1_tx,
&apq_cpudai_slimbus_2_tx,
+ &apq_cpudai_slimbus_3_rx,
&apq8064_rpm_device,
&apq8064_rpm_log_device,
&apq8064_rpm_stat_device,
@@ -2042,6 +2252,11 @@
},
};
+static struct platform_device rc_input_loopback_pdev = {
+ .name = "rc-user-input",
+ .id = -1,
+};
+
static struct platform_device *mpq_devices[] __initdata = {
&msm_device_sps_apq8064,
&mpq8064_device_qup_i2c_gsbi5,
@@ -2058,6 +2273,7 @@
#ifdef CONFIG_MSM_VCAP
&msm8064_device_vcap,
#endif
+ &rc_input_loopback_pdev,
};
static struct msm_spi_platform_data apq8064_qup_spi_gsbi5_pdata = {
@@ -2392,14 +2608,12 @@
smb349_charger_i2c_info,
ARRAY_SIZE(smb349_charger_i2c_info)
},
-#ifndef CONFIG_MSM_VCAP
{
I2C_SURF | I2C_LIQUID,
APQ_8064_GSBI3_QUP_I2C_BUS_ID,
mxt_device_info,
ARRAY_SIZE(mxt_device_info),
},
-#endif
{
I2C_FFA,
APQ_8064_GSBI3_QUP_I2C_BUS_ID,
@@ -2602,6 +2816,10 @@
apq8064_ehci_host_init();
apq8064_init_buses();
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
+ if (!(machine_is_mpq8064_cdp() || machine_is_mpq8064_hrd() ||
+ machine_is_mpq8064_dtv()))
+ platform_add_devices(common_not_mpq_devices,
+ ARRAY_SIZE(common_not_mpq_devices));
enable_ddr3_regulator();
if (machine_is_apq8064_mtp()) {
apq8064_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
@@ -2666,7 +2884,7 @@
}
apq8064_init_fb();
apq8064_init_gpu();
- platform_add_devices(apq8064_fs_devices, apq8064_num_fs_devices);
+ platform_add_devices(apq8064_footswitch, apq8064_num_footswitch);
apq8064_init_cam();
if (machine_is_apq8064_cdp() || machine_is_apq8064_liquid())
diff --git a/arch/arm/mach-msm/board-8930-camera.c b/arch/arm/mach-msm/board-8930-camera.c
index e7992f9..cc5b13c 100644
--- a/arch/arm/mach-msm/board-8930-camera.c
+++ b/arch/arm/mach-msm/board-8930-camera.c
@@ -545,13 +545,21 @@
};
static struct msm_camera_sensor_platform_info sensor_board_info_s5k3l1yx = {
- .mount_angle = 0,
+ .mount_angle = 90,
.cam_vreg = msm_8930_s5k3l1yx_vreg,
.num_vreg = ARRAY_SIZE(msm_8930_s5k3l1yx_vreg),
.gpio_conf = &msm_8930_back_cam_gpio_conf,
.csi_lane_params = &s5k3l1yx_csi_lane_params,
};
+static struct msm_actuator_info msm_act_main_cam_2_info = {
+ .board_info = &msm_act_main_cam_i2c_info,
+ .cam_name = MSM_ACTUATOR_MAIN_CAM_2,
+ .bus_id = MSM_8930_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 0,
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
.sensor_name = "s5k3l1yx",
.pdata = &msm_camera_csi_device_data[0],
@@ -560,6 +568,7 @@
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
+ .actuator_info = &msm_act_main_cam_2_info,
};
static struct platform_device msm_camera_server = {
@@ -572,6 +581,12 @@
msm_gpiomux_install(msm8930_cam_common_configs,
ARRAY_SIZE(msm8930_cam_common_configs));
+ if (machine_is_msm8930_cdp()) {
+ struct msm_camera_sensor_info *s_info;
+ s_info = &msm_camera_sensor_s5k3l1yx_data;
+ s_info->sensor_platform_info->mount_angle = 0;
+ }
+
platform_device_register(&msm_camera_server);
platform_device_register(&msm8960_device_csiphy0);
platform_device_register(&msm8960_device_csiphy1);
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index 42b20b2..6230b65 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -30,29 +30,13 @@
#ifdef CONFIG_FB_MSM_TRIPLE_BUFFER
#define MSM_FB_PRIM_BUF_SIZE \
- (roundup((1376 * 768 * 4), 4096) * 3) /* 4 bpp x 3 pages */
+ (roundup((1920 * 1088 * 4), 4096) * 3) /* 4 bpp x 3 pages */
#else
#define MSM_FB_PRIM_BUF_SIZE \
- (roundup((1376 * 768 * 4), 4096) * 2) /* 4 bpp x 2 pages */
+ (roundup((1920 * 1088 * 4), 4096) * 2) /* 4 bpp x 2 pages */
#endif
-
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-#define MSM_FB_EXT_BUF_SIZE \
- (roundup((1920 * 1088 * 2), 4096) * 1) /* 2 bpp x 1 page */
-#elif defined(CONFIG_FB_MSM_TVOUT)
-#define MSM_FB_EXT_BUF_SIZE \
- (roundup((720 * 576 * 2), 4096) * 2) /* 2 bpp x 2 pages */
-#else
-#define MSM_FB_EXT_BUF_SIZE 0
-#endif
-
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-/* 4 bpp x 2 page HDMI case */
-#define MSM_FB_SIZE roundup((1920 * 1088 * 4 * 2), 4096)
-#else
/* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
-#endif
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1376 * 768 * 3 * 2), 4096)
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 854f318..cd4aff8 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.c
@@ -88,6 +88,12 @@
},
};
+static struct gpiomux_setting audio_mbhc = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
static struct gpiomux_setting gpio_eth_config = {
.pull = GPIOMUX_PULL_NONE,
@@ -374,6 +380,15 @@
},
};
+static struct msm_gpiomux_config msm8960_audio_mbhc_configs[] __initdata = {
+ {
+ .gpio = 37,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &audio_mbhc,
+ },
+ },
+};
+
static struct msm_gpiomux_config msm8960_audio_auxpcm_configs[] __initdata = {
{
.gpio = 63,
@@ -618,6 +633,9 @@
msm_gpiomux_install(msm8960_audio_codec_configs,
ARRAY_SIZE(msm8960_audio_codec_configs));
+ msm_gpiomux_install(msm8960_audio_mbhc_configs,
+ ARRAY_SIZE(msm8960_audio_mbhc_configs));
+
msm_gpiomux_install(msm8960_audio_auxpcm_configs,
ARRAY_SIZE(msm8960_audio_auxpcm_configs));
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index 86c0438..cf7a829 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -329,6 +329,10 @@
.priority = 0,
};
+static struct pm8xxx_spk_platform_data pm8xxx_spk_pdata = {
+ .spk_add_enable = false,
+};
+
static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = {
.battery_type = BATT_UNKNOWN,
.r_sense = 10,
@@ -351,6 +355,7 @@
.adc_pdata = &pm8xxx_adc_pdata,
.leds_pdata = &pm8xxx_leds_pdata,
.ccadc_pdata = &pm8xxx_ccadc_pdata,
+ .spk_pdata = &pm8xxx_spk_pdata,
};
static struct msm_ssbi_platform_data msm8930_ssbi_pm8038_pdata __devinitdata = {
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index ecebfa9..9171749 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -284,6 +284,10 @@
#endif
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
/* SDC3: External card slot */
+ if (!machine_is_msm8930_cdp()) {
+ msm8960_sdc3_data.wpswitch_gpio = 0;
+ msm8960_sdc3_data.wpswitch_polarity = 0;
+ }
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 cbb36a1..28499dd 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -41,6 +41,7 @@
#include <linux/i2c/isa1200.h>
#include <linux/gpio_keys.h>
#include <linux/memory.h>
+#include <linux/memblock.h>
#include <linux/slimbus/slimbus.h>
#include <linux/mfd/wcd9xxx/core.h>
@@ -76,6 +77,7 @@
#include <mach/ion.h>
#include <mach/mdm2.h>
#include <mach/msm_rtb.h>
+#include <linux/fmem.h>
#include "timer.h"
#include "devices.h"
@@ -122,17 +124,33 @@
#else
#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
#endif
-
+#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
+#ifdef CONFIG_MSM_IOMMU
+#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
+#define MSM_ION_SF_SIZE 0x0
+#define MSM_ION_HEAP_NUM 7
+#else
#define MSM_ION_SF_SIZE MSM_PMEM_SIZE
-#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_MM_SIZE MSM_PMEM_ADSP_SIZE
+#define MSM_ION_HEAP_NUM 8
+#endif
+#define MSM_ION_MM_FW_SIZE 0x200000 /* (2MB) */
#define MSM_ION_QSECOM_SIZE 0x300000 /* (3MB) */
#define MSM_ION_MFC_SIZE SZ_8K
#define MSM_ION_AUDIO_SIZE MSM_PMEM_AUDIO_SIZE
-#define MSM_ION_HEAP_NUM 8
+
+#define MSM_LIQUID_ION_MM_SIZE (MSM_ION_MM_SIZE + 0x600000)
+#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 MAX_FIXED_AREA_SIZE 0x10000000
+#define MSM_MM_FW_SIZE 0x200000
+#define MSM8930_FW_START (MSM8930_FIXED_AREA_START - MSM_MM_FW_SIZE)
+
#else
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
@@ -218,6 +236,9 @@
#endif /* CONFIG_MSM_MULTIMEDIA_USE_ION */
#endif /* CONFIG_ANDROID_PMEM */
+struct fmem_platform_data msm8930_fmem_pdata = {
+};
+
#define DSP_RAM_BASE_8960 0x8da00000
#define DSP_RAM_SIZE_8960 0x1800000
static int dspcrashd_pdata_8960 = 0xDEADDEAD;
@@ -294,24 +315,36 @@
return MEMTYPE_EBI1;
}
+#define FMEM_ENABLED 1
#ifdef CONFIG_ION_MSM
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_cp_heap_pdata cp_mm_msm8930_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
.align = PAGE_SIZE,
+ .reusable = FMEM_ENABLED,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_MIDDLE,
};
static struct ion_cp_heap_pdata cp_mfc_msm8930_ion_pdata = {
.permission_type = IPT_TYPE_MFC_SHAREDMEM,
.align = PAGE_SIZE,
+ .reusable = 0,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_HIGH,
};
+
static struct ion_co_heap_pdata co_msm8930_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
+ .mem_is_fmem = 0,
};
+
static struct ion_co_heap_pdata fw_co_msm8930_ion_pdata = {
.adjacent_mem_id = ION_CP_MM_HEAP_ID,
.align = SZ_128K,
+ .mem_is_fmem = FMEM_ENABLED,
+ .fixed_position = FIXED_LOW,
};
#endif
@@ -359,6 +392,7 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &cp_mfc_msm8930_ion_pdata,
},
+#ifndef CONFIG_MSM_IOMMU
{
.id = ION_SF_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
@@ -367,6 +401,7 @@
.memory_type = ION_EBI_TYPE,
.extra_data = (void *) &co_msm8930_ion_pdata,
},
+#endif
{
.id = ION_IOMMU_HEAP_ID,
.type = ION_HEAP_TYPE_IOMMU,
@@ -399,15 +434,180 @@
};
#endif
+struct platform_device msm8930_fmem_device = {
+ .name = "fmem",
+ .id = 1,
+ .dev = { .platform_data = &msm8930_fmem_pdata },
+};
+
+static void __init reserve_mem_for_ion(enum ion_memory_types mem_type,
+ unsigned long size)
+{
+ msm8930_reserve_table[mem_type].size += size;
+}
+
+static void __init msm8930_reserve_fixed_area(unsigned long fixed_area_size)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ int ret;
+
+ if (fixed_area_size > MAX_FIXED_AREA_SIZE)
+ panic("fixed area size is larger than %dM\n",
+ MAX_FIXED_AREA_SIZE >> 20);
+
+ reserve_info->fixed_area_size = fixed_area_size;
+ reserve_info->fixed_area_start = MSM8930_FW_START;
+
+ ret = memblock_remove(reserve_info->fixed_area_start,
+ reserve_info->fixed_area_size);
+ BUG_ON(ret);
+#endif
+}
+
+/**
+ * Reserve memory for ION and calculate amount of reusable memory for fmem.
+ * We only reserve memory for heaps that are not reusable. However, we only
+ * support one reusable heap at the moment so we ignore the reusable flag for
+ * other than the first heap with reusable flag set. Also handle special case
+ * for video heaps (MM,FW, and MFC). Video requires heaps MM and MFC to be
+ * at a higher address than FW in addition to not more than 256MB away from the
+ * base address of the firmware. This means that if MM is reusable the other
+ * two heaps must be allocated in the same region as FW. This is handled by the
+ * mem_is_fmem flag in the platform data. In addition the MM heap must be
+ * adjacent to the FW heap for content protection purposes.
+ */
static void __init reserve_ion_memory(void)
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
- msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
- msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
- msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_FW_SIZE;
- msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
- msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_QSECOM_SIZE;
- msm8930_reserve_table[MEMTYPE_EBI1].size += MSM_ION_AUDIO_SIZE;
+ unsigned int i;
+ unsigned int reusable_count = 0;
+ unsigned int fixed_size = 0;
+ unsigned int fixed_low_size, fixed_middle_size, fixed_high_size;
+ unsigned long fixed_low_start, fixed_middle_start, fixed_high_start;
+
+ msm8930_fmem_pdata.size = 0;
+ msm8930_fmem_pdata.reserved_size_low = 0;
+ msm8930_fmem_pdata.reserved_size_high = 0;
+ fixed_low_size = 0;
+ fixed_middle_size = 0;
+ fixed_high_size = 0;
+
+ /* We only support 1 reusable heap. Check if more than one heap
+ * is specified as reusable and set as non-reusable if found.
+ */
+ for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+ const struct ion_platform_heap *heap =
+ &(msm8930_ion_pdata.heaps[i]);
+
+ if (heap->type == ION_HEAP_TYPE_CP && heap->extra_data) {
+ struct ion_cp_heap_pdata *data = heap->extra_data;
+
+ reusable_count += (data->reusable) ? 1 : 0;
+
+ if (data->reusable && reusable_count > 1) {
+ pr_err("%s: Too many heaps specified as "
+ "reusable. Heap %s was not configured "
+ "as reusable.\n", __func__, heap->name);
+ data->reusable = 0;
+ }
+ }
+ }
+
+ for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+ const struct ion_platform_heap *heap =
+ &(msm8930_ion_pdata.heaps[i]);
+
+ if (heap->extra_data) {
+ int fixed_position = NOT_FIXED;
+ int mem_is_fmem = 0;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_CP:
+ mem_is_fmem = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->mem_is_fmem;
+ fixed_position = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ mem_is_fmem = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->mem_is_fmem;
+ fixed_position = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ default:
+ break;
+ }
+
+ if (fixed_position != NOT_FIXED)
+ fixed_size += heap->size;
+ else
+ reserve_mem_for_ion(MEMTYPE_EBI1, heap->size);
+
+ if (fixed_position == FIXED_LOW)
+ fixed_low_size += heap->size;
+ else if (fixed_position == FIXED_MIDDLE)
+ fixed_middle_size += heap->size;
+ else if (fixed_position == FIXED_HIGH)
+ fixed_high_size += heap->size;
+
+ if (mem_is_fmem)
+ msm8930_fmem_pdata.size += heap->size;
+ }
+ }
+
+ if (!fixed_size)
+ return;
+
+ if (msm8930_fmem_pdata.size) {
+ msm8930_fmem_pdata.reserved_size_low = fixed_low_size;
+ msm8930_fmem_pdata.reserved_size_high = fixed_high_size;
+ }
+
+ /* Since the fixed area may be carved out of lowmem,
+ * make sure the length is a multiple of 1M.
+ */
+ fixed_size = (fixed_size + MSM_MM_FW_SIZE + SECTION_SIZE - 1)
+ & SECTION_MASK;
+ msm8930_reserve_fixed_area(fixed_size);
+
+ fixed_low_start = MSM8930_FIXED_AREA_START;
+ fixed_middle_start = fixed_low_start + fixed_low_size;
+ fixed_high_start = fixed_middle_start + fixed_middle_size;
+
+ for (i = 0; i < msm8930_ion_pdata.nr; ++i) {
+ struct ion_platform_heap *heap = &(msm8930_ion_pdata.heaps[i]);
+
+ if (heap->extra_data) {
+ int fixed_position = NOT_FIXED;
+
+ switch (heap->type) {
+ case ION_HEAP_TYPE_CP:
+ fixed_position = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ case ION_HEAP_TYPE_CARVEOUT:
+ fixed_position = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->fixed_position;
+ break;
+ default:
+ break;
+ }
+
+ switch (fixed_position) {
+ case FIXED_LOW:
+ heap->base = fixed_low_start;
+ break;
+ case FIXED_MIDDLE:
+ heap->base = fixed_middle_start;
+ break;
+ case FIXED_HIGH:
+ heap->base = fixed_high_start;
+ break;
+ default:
+ break;
+ }
+ }
+ }
#endif
}
@@ -428,6 +628,7 @@
static struct reserve_info msm8930_reserve_info __initdata = {
.memtype_reserve_table = msm8930_reserve_table,
.calculate_reserve_sizes = msm8930_calculate_reserve_sizes,
+ .reserve_fixed_area = msm8930_reserve_fixed_area,
.paddr_to_memtype = msm8930_paddr_to_memtype,
};
@@ -448,12 +649,15 @@
/* Check if 32 bit overflow occured */
if (high < mb->start)
- high = ~0UL;
+ high -= PAGE_SIZE;
+
+ if (high < MAX_FIXED_AREA_SIZE + MSM8930_FIXED_AREA_START)
+ panic("fixed area extends beyond end of memory\n");
low &= ~(bank_size - 1);
if (high - low <= bank_size)
- return;
+ goto no_dmm;
msm8930_reserve_info.bank_size = bank_size;
#ifdef CONFIG_ENABLE_DMM
@@ -464,10 +668,11 @@
msm8930_reserve_info.low_unstable_address,
msm8930_reserve_info.max_unstable_size,
msm8930_reserve_info.bank_size);
-#else
- msm8930_reserve_info.low_unstable_address = 0;
- msm8930_reserve_info.max_unstable_size = 0;
+ return;
#endif
+no_dmm:
+ msm8930_reserve_info.low_unstable_address = high;
+ msm8930_reserve_info.max_unstable_size = 0;
}
static void __init place_movable_zone(void)
@@ -490,6 +695,18 @@
static void __init msm8930_reserve(void)
{
msm_reserve();
+ if (msm8930_fmem_pdata.size) {
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+ if (reserve_info->fixed_area_size) {
+ msm8930_fmem_pdata.phys =
+ reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+ pr_info("mm fw at %lx (fixed) size %x\n",
+ reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+ pr_info("fmem start %lx (fixed) size %lx\n",
+ msm8930_fmem_pdata.phys, msm8930_fmem_pdata.size);
+ }
+#endif
+ }
}
static int msm8930_change_memory_power(u64 start, u64 size,
@@ -1740,6 +1957,7 @@
&msm8930_android_pmem_audio_device,
#endif /*CONFIG_MSM_MULTIMEDIA_USE_ION*/
#endif /*CONFIG_ANDROID_PMEM*/
+ &msm8930_fmem_device,
&msm_device_bam_dmux,
&msm_fm_platform_init,
@@ -2068,8 +2286,7 @@
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
msm8930_init_buses();
- platform_add_devices(msm_footswitch_devices,
- msm_num_footswitch_devices);
+ platform_add_devices(msm8930_footswitch, msm8930_num_footswitch);
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
msm8930_add_vidc_device();
/*
diff --git a/arch/arm/mach-msm/board-8960-camera.c b/arch/arm/mach-msm/board-8960-camera.c
index 83e3c8d..371bb53 100644
--- a/arch/arm/mach-msm/board-8960-camera.c
+++ b/arch/arm/mach-msm/board-8960-camera.c
@@ -524,6 +524,15 @@
.csi_lane_params = &imx074_csi_lane_params,
};
+static struct i2c_board_info imx074_eeprom_i2c_info = {
+ I2C_BOARD_INFO("imx074_eeprom", 0x34 << 1),
+};
+
+static struct msm_eeprom_info imx074_eeprom_info = {
+ .board_info = &imx074_eeprom_i2c_info,
+ .bus_id = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
.sensor_name = "imx074",
.pdata = &msm_camera_csi_device_data[0],
@@ -534,6 +543,7 @@
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
.actuator_info = &msm_act_main_cam_0_info,
+ .eeprom_info = &imx074_eeprom_info,
};
static struct camera_vreg_t msm_8960_mt9m114_vreg[] = {
@@ -621,6 +631,14 @@
.csi_lane_params = &s5k3l1yx_csi_lane_params,
};
+static struct msm_actuator_info msm_act_main_cam_2_info = {
+ .board_info = &msm_act_main_cam_i2c_info,
+ .cam_name = MSM_ACTUATOR_MAIN_CAM_2,
+ .bus_id = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 0,
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_s5k3l1yx_data = {
.sensor_name = "s5k3l1yx",
.pdata = &msm_camera_csi_device_data[0],
@@ -629,6 +647,7 @@
.csi_if = 1,
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
+ .actuator_info = &msm_act_main_cam_2_info,
};
static struct msm_camera_csi_lane_params imx091_csi_lane_params = {
@@ -658,6 +677,15 @@
.csi_lane_params = &imx091_csi_lane_params,
};
+static struct i2c_board_info imx091_eeprom_i2c_info = {
+ I2C_BOARD_INFO("imx091_eeprom", 0x21),
+};
+
+static struct msm_eeprom_info imx091_eeprom_info = {
+ .board_info = &imx091_eeprom_i2c_info,
+ .bus_id = MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+};
+
static struct msm_camera_sensor_info msm_camera_sensor_imx091_data = {
.sensor_name = "imx091",
.pdata = &msm_camera_csi_device_data[0],
@@ -667,6 +695,7 @@
.camera_type = BACK_CAMERA_2D,
.sensor_type = BAYER_SENSOR,
.actuator_info = &msm_act_main_cam_1_info,
+ .eeprom_info = &imx091_eeprom_info,
};
static struct pm8xxx_mpp_config_data privacy_light_on_config = {
@@ -727,6 +756,11 @@
msm_camera_8960_ext_power_ctrl;
}
+ if (machine_is_msm8960_fluid()) {
+ msm_camera_sensor_imx091_data.sensor_platform_info->
+ mount_angle = 270;
+ }
+
platform_device_register(&msm_camera_server);
platform_device_register(&msm8960_device_csiphy0);
platform_device_register(&msm8960_device_csiphy1);
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 8c41e8c..b4db968 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -38,20 +38,8 @@
/* 4 bpp x 2 pages */
#endif
-#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
-#define MSM_FB_EXT_BUF_SIZE \
- (roundup((roundup(1920, 32) * roundup(1080, 32) * 2), 4096) * 1)
- /* 2 bpp x 1 page */
-#elif defined(CONFIG_FB_MSM_TVOUT)
-#define MSM_FB_EXT_BUF_SIZE \
- (roundup((roundup(720, 32) * roundup(576, 32) * 2), 4096) * 2)
- /* 2 bpp x 2 pages */
-#else
-#define MSM_FB_EXT_BUF_SIZE 0
-#endif
-
/* Note: must be multiple of 4096 */
-#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE + MSM_FB_EXT_BUF_SIZE, 4096)
+#define MSM_FB_SIZE roundup(MSM_FB_PRIM_BUF_SIZE, 4096)
#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
#define MSM_FB_OVERLAY0_WRITEBACK_SIZE \
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 8b5c693..978eb09 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, 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
@@ -597,6 +597,84 @@
};
#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static struct gpiomux_setting sdcc4_clk_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc4_cmd_data_0_3_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc4_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdcc4_data_1_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm8960_sdcc4_configs[] __initdata = {
+ {
+ /* SDC4_DATA_3 */
+ .gpio = 83,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc4_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+ },
+ },
+ {
+ /* SDC4_DATA_2 */
+ .gpio = 84,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc4_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+ },
+ },
+ {
+ /* SDC4_DATA_1 */
+ .gpio = 85,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc4_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc4_data_1_suspend_cfg,
+ },
+ },
+ {
+ /* SDC4_DATA_0 */
+ .gpio = 86,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc4_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+ },
+ },
+ {
+ /* SDC4_CMD */
+ .gpio = 87,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc4_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+ },
+ },
+ {
+ /* SDC4_CLK */
+ .gpio = 88,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc4_clk_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc4_suspend_cfg,
+ },
+ },
+};
+#endif
+
+
static struct msm_gpiomux_config hap_lvl_shft_config[] __initdata = {
{
.gpio = 47,
@@ -727,6 +805,83 @@
};
#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static struct gpiomux_setting sdcc2_clk_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting sdcc2_cmd_data_0_3_actv_cfg = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct gpiomux_setting sdcc2_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct gpiomux_setting sdcc2_data_1_suspend_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_UP,
+};
+
+static struct msm_gpiomux_config msm8960_sdcc2_configs[] __initdata = {
+ {
+ /* DATA_3 */
+ .gpio = 92,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* DATA_2 */
+ .gpio = 91,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* DATA_1 */
+ .gpio = 90,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_data_1_suspend_cfg,
+ },
+ },
+ {
+ /* DATA_0 */
+ .gpio = 89,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* CMD */
+ .gpio = 97,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_cmd_data_0_3_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+ {
+ /* CLK */
+ .gpio = 98,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &sdcc2_clk_actv_cfg,
+ [GPIOMUX_SUSPENDED] = &sdcc2_suspend_cfg,
+ },
+ },
+};
+#endif
+
int __init msm8960_init_gpiomux(void)
{
int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -758,6 +913,11 @@
msm_gpiomux_install(wcnss_5wire_interface,
ARRAY_SIZE(wcnss_5wire_interface));
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+ msm_gpiomux_install(msm8960_sdcc4_configs,
+ ARRAY_SIZE(msm8960_sdcc4_configs));
+#endif
+
if (machine_is_msm8960_mtp() || machine_is_msm8960_fluid() ||
machine_is_msm8960_liquid() || machine_is_msm8960_cdp())
msm_gpiomux_install(hap_lvl_shft_config,
@@ -798,5 +958,10 @@
msm_gpiomux_install(msm8960_fusion_gsbi_configs,
ARRAY_SIZE(msm8960_fusion_gsbi_configs));
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ msm_gpiomux_install(msm8960_sdcc2_configs,
+ ARRAY_SIZE(msm8960_sdcc2_configs));
+#endif
+
return 0;
}
diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c
index c9a5f77..ea1ab58 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -471,7 +471,7 @@
{
.name = "led:blue",
.flags = PM8XXX_ID_LED_2,
- .default_trigger = "dc-online",
+ .default_trigger = "notification",
},
};
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index ed47ae2..3923ecf 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -163,6 +163,8 @@
VREG_CONSUMERS(S4) = {
REGULATOR_SUPPLY("8921_s4", NULL),
REGULATOR_SUPPLY("sdc_vccq", "msm_sdcc.1"),
+ REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.2"),
+ REGULATOR_SUPPLY("sdc_vddp", "msm_sdcc.4"),
REGULATOR_SUPPLY("riva_vddpx", "wcnss_wlan.0"),
REGULATOR_SUPPLY("hdmi_vcc", "hdmi_msm.0"),
REGULATOR_SUPPLY("VDDIO_CDC", "tabla-slim"),
@@ -193,7 +195,6 @@
};
VREG_CONSUMERS(LVS1) = {
REGULATOR_SUPPLY("8921_lvs1", NULL),
- REGULATOR_SUPPLY("sdc_vdd", "msm_sdcc.4"),
REGULATOR_SUPPLY("iris_vddio", "wcnss_wlan.0"),
};
VREG_CONSUMERS(LVS2) = {
diff --git a/arch/arm/mach-msm/board-8960-storage.c b/arch/arm/mach-msm/board-8960-storage.c
index f39a691..df1d846 100644
--- a/arch/arm/mach-msm/board-8960-storage.c
+++ b/arch/arm/mach-msm/board-8960-storage.c
@@ -46,6 +46,16 @@
.lpm_uA = 9000,
.hpm_uA = 200000, /* 200mA */
},
+ /* SDCC2 : SDIO slot connected */
+ [SDCC2] = {
+ .name = "sdc_vdd",
+ .high_vol_level = 1800000,
+ .low_vol_level = 1800000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ .lpm_uA = 9000,
+ .hpm_uA = 200000, /* 200mA */
+ },
/* SDCC3 : External card slot connected */
[SDCC3] = {
.name = "sdc_vdd",
@@ -84,7 +94,17 @@
* during sleep.
*/
.lpm_uA = 2000,
- }
+ },
+ /* SDCC4 : SDIO slot connected */
+ [SDCC4] = {
+ .name = "sdc_vddp",
+ .high_vol_level = 1800000,
+ .low_vol_level = 1800000,
+ .always_on = 1,
+ .lpm_sup = 1,
+ .hpm_uA = 200000, /* 200mA */
+ .lpm_uA = 2000,
+ },
};
static struct msm_mmc_slot_reg_data mmc_slot_vreg_data[MAX_SDCC_CONTROLLER] = {
@@ -93,11 +113,19 @@
.vdd_data = &mmc_vdd_reg_data[SDCC1],
.vccq_data = &mmc_vccq_reg_data[SDCC1],
},
+ /* SDCC2 : SDIO card slot connected */
+ [SDCC2] = {
+ .vdd_data = &mmc_vdd_reg_data[SDCC2],
+ },
/* SDCC3 : External card slot connected */
[SDCC3] = {
.vdd_data = &mmc_vdd_reg_data[SDCC3],
.vddp_data = &mmc_vddp_reg_data[SDCC3],
- }
+ },
+ /* SDCC4 : SDIO card slot connected */
+ [SDCC4] = {
+ .vddp_data = &mmc_vddp_reg_data[SDCC4],
+ },
};
/* SDC1 pad data */
@@ -186,6 +214,35 @@
},
};
+struct msm_mmc_gpio sdc2_gpio[] = {
+ {92, "sdc2_dat_3"},
+ {91, "sdc2_dat_2"},
+ {90, "sdc2_dat_1"},
+ {89, "sdc2_dat_0"},
+ {97, "sdc2_cmd"},
+ {98, "sdc2_clk"}
+};
+
+struct msm_mmc_gpio sdc4_gpio[] = {
+ {83, "sdc4_dat_3"},
+ {84, "sdc4_dat_2"},
+ {85, "sdc4_dat_1"},
+ {86, "sdc4_dat_0"},
+ {87, "sdc4_cmd"},
+ {88, "sdc4_clk"}
+};
+
+struct msm_mmc_gpio_data mmc_gpio_data[MAX_SDCC_CONTROLLER] = {
+ [SDCC2] = {
+ .gpio = sdc2_gpio,
+ .size = ARRAY_SIZE(sdc2_gpio),
+ },
+ [SDCC4] = {
+ .gpio = sdc4_gpio,
+ .size = ARRAY_SIZE(sdc4_gpio),
+ },
+};
+
static struct msm_mmc_pad_data mmc_pad_data[MAX_SDCC_CONTROLLER] = {
[SDCC1] = {
.pull = &mmc_pad_pull_data[SDCC1],
@@ -201,9 +258,17 @@
[SDCC1] = {
.pad_data = &mmc_pad_data[SDCC1],
},
+ [SDCC2] = {
+ .is_gpio = 1,
+ .gpio_data = &mmc_gpio_data[SDCC2],
+ },
[SDCC3] = {
.pad_data = &mmc_pad_data[SDCC3],
},
+ [SDCC4] = {
+ .is_gpio = 1,
+ .gpio_data = &mmc_gpio_data[SDCC4],
+ },
};
#define MSM_MPM_PIN_SDC1_DAT1 17
@@ -237,6 +302,23 @@
};
#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+static unsigned int sdc2_sup_clk_rates[] = {
+ 400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data msm8960_sdc2_data = {
+ .ocr_mask = MMC_VDD_165_195,
+ .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),
+};
+#endif
+
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
static struct mmc_platform_data msm8960_sdc3_data = {
.ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
@@ -263,14 +345,39 @@
};
#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+static unsigned int sdc4_sup_clk_rates[] = {
+ 400000, 24000000, 48000000
+};
+
+static struct mmc_platform_data msm8960_sdc4_data = {
+ .ocr_mask = MMC_VDD_165_195,
+ .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),
+};
+#endif
+
void __init msm8960_init_mmc(void)
{
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
/* SDC1 : eMMC card connected */
msm_add_sdcc(1, &msm8960_sdc1_data);
#endif
+#ifdef CONFIG_MMC_MSM_SDC2_SUPPORT
+ /* SDC2: SDIO slot for WLAN*/
+ msm_add_sdcc(2, &msm8960_sdc2_data);
+#endif
#ifdef CONFIG_MMC_MSM_SDC3_SUPPORT
/* SDC3: External card slot */
msm_add_sdcc(3, &msm8960_sdc3_data);
#endif
+#ifdef CONFIG_MMC_MSM_SDC4_SUPPORT
+ /* SDC4: SDIO slot for WLAN */
+ msm_add_sdcc(4, &msm8960_sdc4_data);
+#endif
}
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 42dbbee..c103fa8 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -84,6 +84,7 @@
#include <mach/msm_rtb.h>
#include <mach/msm_cache_dump.h>
#include <mach/scm.h>
+#include <mach/iommu_domains.h>
#include <linux/fmem.h>
@@ -146,7 +147,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x65000
#ifdef CONFIG_MSM_IOMMU
-#define MSM_ION_MM_SIZE 0x3800000
+#define MSM_ION_MM_SIZE 0x3800000 /* Need to be multiple of 64K */
#define MSM_ION_SF_SIZE 0x0
#define MSM_ION_QSECOM_SIZE 0x780000 /* (7.5MB) */
#define MSM_ION_HEAP_NUM 7
@@ -349,10 +350,12 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_cp_heap_pdata cp_mm_msm8960_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
- .align = PAGE_SIZE,
+ .align = SZ_64K,
.reusable = FMEM_ENABLED,
.mem_is_fmem = FMEM_ENABLED,
.fixed_position = FIXED_MIDDLE,
+ .iommu_map_all = 1,
+ .iommu_2x_map_domain = VIDEO_DOMAIN,
};
static struct ion_cp_heap_pdata cp_mfc_msm8960_ion_pdata = {
@@ -545,6 +548,7 @@
msm8960_fmem_pdata.size = 0;
msm8960_fmem_pdata.reserved_size_low = 0;
msm8960_fmem_pdata.reserved_size_high = 0;
+ msm8960_fmem_pdata.align = PAGE_SIZE;
fixed_low_size = 0;
fixed_middle_size = 0;
fixed_high_size = 0;
@@ -571,8 +575,11 @@
}
for (i = 0; i < msm8960_ion_pdata.nr; ++i) {
- const struct ion_platform_heap *heap =
+ struct ion_platform_heap *heap =
&(msm8960_ion_pdata.heaps[i]);
+ int align = SZ_4K;
+ int iommu_map_all = 0;
+ int adjacent_mem_id = INVALID_HEAP_ID;
if (heap->extra_data) {
int fixed_position = NOT_FIXED;
@@ -584,17 +591,35 @@
heap->extra_data)->mem_is_fmem;
fixed_position = ((struct ion_cp_heap_pdata *)
heap->extra_data)->fixed_position;
+ align = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->align;
+ iommu_map_all =
+ ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->iommu_map_all;
break;
case ION_HEAP_TYPE_CARVEOUT:
mem_is_fmem = ((struct ion_co_heap_pdata *)
heap->extra_data)->mem_is_fmem;
fixed_position = ((struct ion_co_heap_pdata *)
heap->extra_data)->fixed_position;
+ adjacent_mem_id = ((struct ion_co_heap_pdata *)
+ heap->extra_data)->adjacent_mem_id;
break;
default:
break;
}
+ if (iommu_map_all) {
+ if (heap->size & (SZ_64K-1)) {
+ heap->size = ALIGN(heap->size, SZ_64K);
+ pr_info("Heap %s not aligned to 64K. Adjusting size to %x\n",
+ heap->name, heap->size);
+ }
+ }
+
+ if (mem_is_fmem && adjacent_mem_id != INVALID_HEAP_ID)
+ msm8960_fmem_pdata.align = align;
+
if (fixed_position != NOT_FIXED)
fixed_size += heap->size;
else
@@ -673,21 +698,6 @@
msm8960_mdp_writeback(msm8960_reserve_table);
}
-#if defined(CONFIG_MSM_CACHE_DUMP)
-static struct msm_cache_dump_platform_data msm8960_cache_dump_pdata = {
- .l2_size = L2_BUFFER_SIZE,
-};
-
-static struct platform_device msm8960_cache_dump_device = {
- .name = "msm_cache_dump",
- .id = -1,
- .dev = {
- .platform_data = &msm8960_cache_dump_pdata,
- },
-};
-
-#endif
-
static void __init reserve_cache_dump_memory(void)
{
#ifdef CONFIG_MSM_CACHE_DUMP
@@ -821,15 +831,15 @@
msm_reserve();
if (msm8960_fmem_pdata.size) {
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
- msm8960_fmem_pdata.phys = reserve_info->fixed_area_start +
- MSM_MM_FW_SIZE;
- pr_info("mm fw at %lx (fixed) size %x\n",
- reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
- pr_info("fmem start %lx (fixed) size %lx\n",
- msm8960_fmem_pdata.phys, msm8960_fmem_pdata.size);
-#else
- msm8960_fmem_pdata.phys =
- reserve_memory_for_fmem(msm8960_fmem_pdata.size);
+ if (reserve_info->fixed_area_size) {
+ msm8960_fmem_pdata.phys =
+ reserve_info->fixed_area_start + MSM_MM_FW_SIZE;
+ pr_info("mm fw at %lx (fixed) size %x\n",
+ reserve_info->fixed_area_start, MSM_MM_FW_SIZE);
+ pr_info("fmem start %lx (fixed) size %lx\n",
+ msm8960_fmem_pdata.phys,
+ msm8960_fmem_pdata.size);
+ }
#endif
}
}
@@ -2566,9 +2576,7 @@
&msm8960_cpu_idle_device,
&msm8960_msm_gov_device,
&msm8960_device_cache_erp,
-#ifdef CONFIG_MSM_CACHE_DUMP
&msm8960_cache_dump_device,
-#endif
&msm8960_iommu_domain_device,
&msm_tsens_device,
};
@@ -3124,8 +3132,7 @@
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
msm8960_init_buses();
- platform_add_devices(msm_footswitch_devices,
- msm_num_footswitch_devices);
+ platform_add_devices(msm8960_footswitch, msm8960_num_footswitch);
if (machine_is_msm8960_liquid())
platform_device_register(&msm8960_device_ext_3p3v_vreg);
if (machine_is_msm8960_cdp())
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 6a4c92e..925c5b4 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -21,6 +21,7 @@
#include <mach/rpm-regulator.h>
#include <mach/msm_memtypes.h>
#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
/* Macros assume PMIC GPIOs and MPPs start at 1 */
#define PM8921_GPIO_BASE NR_GPIO_IRQS
@@ -95,3 +96,4 @@
#define MSM_8960_GSBI10_QUP_I2C_BUS_ID 10
extern struct msm_rtb_platform_data msm8960_rtb_pdata;
+extern struct msm_cache_dump_platform_data msm8960_cache_dump_pdata;
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index b128223..a8602d3 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -43,10 +43,11 @@
#include <mach/dma.h>
#include <mach/ion.h>
#include <mach/msm_memtypes.h>
+#include <mach/cpuidle.h>
+#include <mach/usb_bam.h>
#include "timer.h"
#include "devices.h"
#include "board-9615.h"
-#include <mach/cpuidle.h>
#include "pm.h"
#include "acpuclock.h"
#include "pm-boot.h"
@@ -568,6 +569,10 @@
.disable_reset_on_disconnect = true,
};
+static struct msm_hsic_peripheral_platform_data msm_hsic_peripheral_pdata = {
+ .keep_core_clk_on_suspend_workaround = true,
+};
+
#define PID_MAGIC_ID 0x71432909
#define SERIAL_NUM_MAGIC_ID 0x61945374
#define SERIAL_NUMBER_LENGTH 127
@@ -756,6 +761,8 @@
msm_device_otg.dev.platform_data = &msm_otg_pdata;
msm_otg_pdata.phy_init_seq = shelby_phy_init_seq;
+ msm_device_hsic_peripheral.dev.platform_data =
+ &msm_hsic_peripheral_pdata;
msm_device_usb_bam.dev.platform_data = &msm_usb_bam_pdata;
platform_add_devices(common_devices, ARRAY_SIZE(common_devices));
diff --git a/arch/arm/mach-msm/board-copper-gpiomux.c b/arch/arm/mach-msm/board-copper-gpiomux.c
index 50b03fc..0ea33c7 100644
--- a/arch/arm/mach-msm/board-copper-gpiomux.c
+++ b/arch/arm/mach-msm/board-copper-gpiomux.c
@@ -17,6 +17,8 @@
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+#define KS8851_IRQ_GPIO 90
+
static struct gpiomux_setting gpio_uart_config = {
.func = GPIOMUX_FUNC_2,
.drv = GPIOMUX_DRV_16MA,
@@ -24,7 +26,62 @@
.dir = GPIOMUX_OUT_HIGH,
};
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+ .pull = GPIOMUX_PULL_NONE,
+ .drv = GPIOMUX_DRV_8MA,
+ .func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct gpiomux_setting gpio_spi_cs_config = {
+ .func = GPIOMUX_FUNC_4,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_12MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_eth_configs[] = {
+ {
+ .gpio = KS8851_IRQ_GPIO,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ }
+ },
+};
+#endif
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+ {
+ .gpio = 0, /* BLSP1 QUP SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 1, /* BLSP1 QUP SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 3, /* BLSP1 QUP SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 9, /* BLSP1 QUP SPI_CS_N */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_cs_config,
+ },
+ },
+#endif
{
.gpio = 45, /* BLSP8 UART TX */
.settings = {
@@ -49,5 +106,8 @@
return;
}
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+ msm_gpiomux_install(msm_eth_configs, ARRAY_SIZE(msm_eth_configs));
+#endif
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
}
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index e545f12..14efac4 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -27,6 +27,7 @@
#include <linux/android_pmem.h>
#endif
#include <linux/regulator/stub-regulator.h>
+#include <linux/regulator/machine.h>
#include <asm/mach/map.h>
#include <asm/hardware/gic.h>
#include <mach/board.h>
@@ -42,6 +43,7 @@
#include <mach/socinfo.h>
#include "clock.h"
#include "devices.h"
+#include "spm.h"
#define MSM_KERNEL_EBI1_MEM_SIZE 0x280000
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -407,6 +409,8 @@
*/
void __init msm_copper_add_drivers(void)
{
+ msm_smd_init();
+ msm_spm_device_init();
regulator_stub_init();
}
@@ -480,6 +484,8 @@
msm_clock_init(&msmcopper_clock_init_data);
*adata = msm_copper_auxdata_lookup;
+
+ regulator_has_full_constraints();
}
void __init msm_copper_very_early(void)
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index 81abbc0..75d5f15 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -102,7 +102,8 @@
u32 socinfo = socinfo_get_platform_version();
if (machine_is_msm7627a_qrd1())
gpio_bt_sys_rest_en = 114;
- if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt())
gpio_bt_sys_rest_en = 16;
if (machine_is_msm8625_qrd7())
gpio_bt_sys_rest_en = 88;
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 8e64a43..329dcae 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -29,6 +29,9 @@
#define GPIO_SKU3_CAM_5MP_SHDN_N 5 /* PWDN */
#define GPIO_SKU3_CAM_5MP_CAMIF_RESET 6 /* (board_is(EVT))?123:121 RESET */
#define GPIO_SKU3_CAM_5MP_CAM_DRIVER_PWDN 30
+#define GPIO_SKU7_CAM_VGA_SHDN 91
+#define GPIO_SKU7_CAM_5MP_SHDN_N 93 /* PWDN */
+#define GPIO_SKU7_CAM_5MP_CAMIF_RESET 23 /* (board_is(EVT))?123:121 RESET */
#ifdef CONFIG_MSM_CAMERA_V4L2
static uint32_t camera_off_gpio_table[] = {
@@ -73,9 +76,25 @@
};
#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct gpio ov7692_cam_req_gpio[] = {
+ {GPIO_SKU1_CAM_VGA_SHDN, GPIOF_DIR_OUT, "CAM_VGA_SHDN"},
+ {GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_DIR_OUT, "CAM_VGA_RESET"},
+};
+
+static struct msm_gpio_set_tbl ov7692_cam_gpio_set_tbl[] = {
+ {GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_HIGH, 5000},
+ {GPIO_SKU1_CAM_VGA_SHDN, GPIOF_OUT_INIT_LOW, 5000},
+ {GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_HIGH, 5000},
+ {GPIO_SKU1_CAM_VGA_RESET_N, GPIOF_OUT_INIT_LOW, 5000},
+ {40, GPIOF_OUT_INIT_HIGH, 5000},
+ {35, GPIOF_OUT_INIT_HIGH, 5000},
+};
+
static struct msm_camera_gpio_conf gpio_conf_ov7692 = {
- .camera_off_table = camera_off_gpio_table,
- .camera_on_table = camera_on_gpio_table,
+ .cam_gpio_req_tbl = ov7692_cam_req_gpio,
+ .cam_gpio_req_tbl_size = ARRAY_SIZE(ov7692_cam_req_gpio),
+ .cam_gpio_set_tbl = ov7692_cam_gpio_set_tbl,
+ .cam_gpio_set_tbl_size = ARRAY_SIZE(ov7692_cam_gpio_set_tbl),
.gpio_no_mux = 1,
};
#endif
@@ -104,14 +123,38 @@
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,
+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,
+ },
+ },
};
-struct msm_camera_device_platform_data msm_camera_device_data_csi0 = {
- .csid_core = 0,
- .is_csic = 1,
+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,
+ },
+ },
};
static struct i2c_board_info msm_act_main_cam_i2c_info = {
@@ -143,7 +186,7 @@
.sensor_name = "s5k4e1",
.sensor_reset_enable = 1,
.pmic_gpio_enable = 0,
- .pdata = &msm_camera_device_data_csi1,
+ .pdata = &msm_camera_device_data_csi1[0],
.flash_data = &flash_s5k4e1,
.sensor_platform_info = &sensor_board_info_s5k4e1,
.csi_if = 1,
@@ -171,7 +214,7 @@
.pmic_gpio_enable = 1,
.sensor_reset = GPIO_SKU1_CAM_VGA_RESET_N,
.sensor_pwd = GPIO_SKU1_CAM_VGA_SHDN,
- .pdata = &msm_camera_device_data_csi0,
+ .pdata = &msm_camera_device_data_csi0[0],
.flash_data = &flash_ov7692,
.sensor_platform_info = &sensor_board_info_ov7692,
.csi_if = 1,
@@ -214,7 +257,7 @@
.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,
+ .pdata = &msm_camera_device_data_csi1[0],
.flash_data = &flash_ov5647,
.sensor_platform_info = &sensor_board_info_ov5647,
.csi_if = 1,
@@ -241,7 +284,7 @@
.sensor_name = "mt9e013",
.sensor_reset_enable = 1,
.pmic_gpio_enable = 0,
- .pdata = &msm_camera_device_data_csi1,
+ .pdata = &msm_camera_device_data_csi1[1],
.flash_data = &flash_mt9e013,
.sensor_platform_info = &sensor_board_info_mt9e013,
.csi_if = 1,
@@ -267,7 +310,7 @@
.sensor_name = "ov9726",
.sensor_reset_enable = 0,
.pmic_gpio_enable = 0,
- .pdata = &msm_camera_device_data_csi0,
+ .pdata = &msm_camera_device_data_csi0[0],
.flash_data = &flash_ov9726,
.sensor_platform_info = &sensor_board_info_ov9726,
.csi_if = 1,
@@ -298,14 +341,18 @@
sensor_board_info_ov5647.num_vreg = 0;
}
platform_device_register(&msm_camera_server);
- if (machine_is_msm8625_surf() || machine_is_msm8625_evb()) {
+ if (machine_is_msm8625_surf() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
+ || machine_is_msm8625_qrd7()) {
platform_device_register(&msm8625_device_csic0);
platform_device_register(&msm8625_device_csic1);
} else {
platform_device_register(&msm7x27a_device_csic0);
platform_device_register(&msm7x27a_device_csic1);
}
- if (machine_is_msm8625_evb())
+ if (machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
+ || machine_is_msm8625_qrd7())
*(int *) msm7x27a_device_clkctl.dev.platform_data = 1;
platform_device_register(&msm7x27a_device_clkctl);
platform_device_register(&msm7x27a_device_vfe);
@@ -421,71 +468,45 @@
{
int rc = 0;
- rc = gpio_request(GPIO_SKU3_CAM_5MP_SHDN_N, "ov5647");
+ rc = gpio_request(msm_camera_sensor_ov5647_data.sensor_pwd, "ov5647");
if (rc < 0)
- pr_err("%s: gpio_request GPIO_SKU3_CAM_5MP_SHDN_N failed!",
- __func__);
+ pr_err("%s: gpio_request OV5647 sensor_pwd: %d failed!",
+ __func__, msm_camera_sensor_ov5647_data.sensor_pwd);
- pr_debug("gpio_tlmm_config %d\r\n", GPIO_SKU3_CAM_5MP_SHDN_N);
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU3_CAM_5MP_SHDN_N, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+ rc = gpio_tlmm_config(GPIO_CFG(msm_camera_sensor_ov5647_data.sensor_pwd,
+ 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
if (rc < 0) {
pr_err("%s:unable to enable Powr Dwn gpio for main camera!\n",
__func__);
- gpio_free(GPIO_SKU3_CAM_5MP_SHDN_N);
+ gpio_free(msm_camera_sensor_ov5647_data.sensor_pwd);
}
- gpio_direction_output(GPIO_SKU3_CAM_5MP_SHDN_N, 1);
-
- rc = gpio_request(GPIO_SKU3_CAM_5MP_CAMIF_RESET, "ov5647");
+ rc = gpio_direction_output(msm_camera_sensor_ov5647_data.sensor_pwd, 1);
if (rc < 0)
- pr_err("%s: gpio_request GPIO_SKU3_CAM_5MP_CAMIF_RESET failed!",
- __func__);
+ pr_err("%s: unable to set gpio: %d direction for ov5647 camera\n",
+ __func__, msm_camera_sensor_ov5647_data.sensor_pwd);
- pr_debug("gpio_tlmm_config %d\r\n", GPIO_SKU3_CAM_5MP_CAMIF_RESET);
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU3_CAM_5MP_CAMIF_RESET, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+ rc = gpio_request(msm_camera_sensor_ov5647_data.sensor_reset, "ov5647");
+ if (rc < 0)
+ pr_err("%s: gpio_request OV5647 sensor_reset: %d failed!",
+ __func__, msm_camera_sensor_ov5647_data.sensor_reset);
+
+ rc = gpio_tlmm_config(GPIO_CFG(
+ msm_camera_sensor_ov5647_data.sensor_reset,
+ 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN,
+ GPIO_CFG_2MA), GPIO_CFG_ENABLE);
if (rc < 0) {
pr_err("%s: unable to enable reset gpio for main camera!\n",
__func__);
- gpio_free(GPIO_SKU3_CAM_5MP_CAMIF_RESET);
+ gpio_free(msm_camera_sensor_ov5647_data.sensor_reset);
}
- gpio_direction_output(GPIO_SKU3_CAM_5MP_CAMIF_RESET, 1);
-
- rc = gpio_request(GPIO_SKU1_CAM_VGA_SHDN, "ov7692");
+ rc = gpio_direction_output(
+ msm_camera_sensor_ov5647_data.sensor_reset, 1);
if (rc < 0)
- pr_err("%s: gpio_request---GPIO_SKU1_CAM_VGA_SHDN failed!",
- __func__);
-
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU1_CAM_VGA_SHDN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("%s:unable to enable Powr Dwn gpio for frnt camera!\n",
- __func__);
- gpio_free(GPIO_SKU1_CAM_VGA_SHDN);
- }
-
- gpio_direction_output(GPIO_SKU1_CAM_VGA_SHDN, 1);
-
- rc = gpio_request(GPIO_SKU1_CAM_VGA_RESET_N, "ov7692");
- if (rc < 0)
- pr_err("%s: gpio_request---GPIO_SKU1_CAM_VGA_RESET_N failed!",
- __func__);
-
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_SKU1_CAM_VGA_RESET_N, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-
- if (rc < 0) {
- pr_err("%s: unable to enable reset gpio for front camera!\n",
- __func__);
- gpio_free(GPIO_SKU1_CAM_VGA_RESET_N);
- }
- gpio_direction_output(GPIO_SKU1_CAM_VGA_RESET_N, 1);
+ pr_err("%s: unable to set gpio: %d direction for ov5647 camera\n",
+ __func__, msm_camera_sensor_ov5647_data.sensor_reset);
}
@@ -967,6 +988,7 @@
#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 */
static int lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8;
@@ -976,7 +998,10 @@
pr_debug("lcd_camera_power_init\n");
- lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8; /* SKU3 PVT */
+ if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7())
+ lcd_camera_ldo_1v8 = SKU7_LCD_CAMERA_LDO_1V8;
+ else
+ lcd_camera_ldo_1v8 = SKU3_LCD_CAMERA_LDO_1V8;
/* LDO_EXT2V8 */
if (gpio_request(LCD_CAMERA_LDO_2V8, "lcd_camera_ldo_2v8")) {
@@ -1068,8 +1093,28 @@
#endif
pr_debug("msm7627a_camera_init Entered\n");
+
+ if (machine_is_msm7627a_qrd3() || machine_is_msm8625_qrd7()) {
+ ov7692_cam_req_gpio[0].gpio =
+ GPIO_SKU7_CAM_VGA_SHDN;
+ ov7692_cam_gpio_set_tbl[0].gpio = GPIO_SKU7_CAM_VGA_SHDN;
+ ov7692_cam_gpio_set_tbl[1].gpio = GPIO_SKU7_CAM_VGA_SHDN;
+ ov7692_cam_gpio_set_tbl[4].gpio = LCD_CAMERA_LDO_2V8 ;
+ ov7692_cam_gpio_set_tbl[5].gpio = SKU7_LCD_CAMERA_LDO_1V8;
+
+ msm_camera_sensor_ov5647_data.sensor_pwd =
+ 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 */
- if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7()) {
+
lcd_camera_power_init();
evb_camera_gpio_cfg();
}
@@ -1079,7 +1124,11 @@
qrd1_camera_gpio_cfg();
platform_add_devices(camera_devices_qrd,
ARRAY_SIZE(camera_devices_qrd));
- } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ } else if (machine_is_msm7627a_evb()
+ || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7()) {
platform_add_devices(camera_devices_evb,
ARRAY_SIZE(camera_devices_evb));
} else if (machine_is_msm7627a_qrd3())
@@ -1089,7 +1138,10 @@
ARRAY_SIZE(camera_devices_msm));
#endif
if (!machine_is_msm7627a_qrd1() || !machine_is_msm7627a_evb()
- || !machine_is_msm8625_evb())
+ || !machine_is_msm8625_evb()
+ || !machine_is_msm8625_evt()
+ || !machine_is_msm7627a_qrd3()
+ || !machine_is_msm8625_qrd7())
register_i2c_devices();
#ifndef CONFIG_MSM_CAMERA_V4L2
rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
@@ -1115,7 +1167,11 @@
i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
i2c_camera_devices_qrd,
ARRAY_SIZE(i2c_camera_devices_qrd));
- } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ } else if (machine_is_msm7627a_evb()
+ || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
+ || machine_is_msm7627a_qrd3()
+ || machine_is_msm8625_qrd7()) {
pr_debug("machine_is_msm7627a_evb i2c_register_board_info\n");
i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
i2c_camera_devices_evb,
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 2de581b..f44cc9e 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -500,6 +500,9 @@
} else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
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) && \
@@ -662,6 +665,14 @@
return 0;
}
+static int mipi_NT35510_rotate_panel(void)
+{
+ int rotate = 0;
+ if (machine_is_msm8625_evt())
+ rotate = 1;
+
+ return rotate;
+}
static struct msm_panel_common_pdata mipi_truly_pdata = {
.pmic_backlight = mipi_truly_set_bl,
@@ -677,6 +688,7 @@
static struct msm_panel_common_pdata mipi_NT35510_pdata = {
.pmic_backlight = evb_backlight_control,
+ .rotate_panel = mipi_NT35510_rotate_panel,
};
static struct platform_device mipi_dsi_NT35510_panel_device = {
@@ -733,7 +745,8 @@
if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa())
fb_size = MSM7x25A_MSM_FB_SIZE;
- else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt())
fb_size = MSM8x25_MSM_FB_SIZE;
else
fb_size = MSM_FB_SIZE;
@@ -947,7 +960,8 @@
if (machine_is_msm7627a_qrd1())
rc = msm_fb_dsi_client_qrd1_reset();
- else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt())
rc = msm_fb_dsi_client_qrd3_reset();
else
rc = msm_fb_dsi_client_msm_reset();
@@ -1133,20 +1147,6 @@
if (rc < 0)
return rc;
- rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
- GPIO_CFG_ENABLE);
- if (rc < 0) {
- pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
- return rc;
- }
- rc = gpio_direction_output(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
- if (rc < 0) {
- pr_err("failed to enable backlight\n");
- gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
- return rc;
- }
-
rc = gpio_request(GPIO_QRD3_LCD_EXT_2V85_EN,
"qrd3_gpio_ext_2v85_en");
if (rc < 0)
@@ -1191,6 +1191,20 @@
}
if (on) {
+ rc = gpio_tlmm_config(GPIO_CFG(GPIO_QRD3_LCD_BACKLIGHT_EN, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP, GPIO_CFG_2MA),
+ GPIO_CFG_ENABLE);
+ if (rc < 0) {
+ pr_err("failed QRD3 GPIO_BACKLIGHT_EN tlmm config\n");
+ return rc;
+ }
+ rc = gpio_direction_output(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
+ if (rc < 0) {
+ pr_err("failed to enable backlight\n");
+ gpio_free(GPIO_QRD3_LCD_BACKLIGHT_EN);
+ return rc;
+ }
+
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
udelay(190);
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 0);
@@ -1198,8 +1212,11 @@
gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, 1);
/* 1 wire mode starts from this low to high transition */
udelay(50);
- } else
- gpio_set_value_cansleep(GPIO_QRD3_LCD_BACKLIGHT_EN, !!on);
+ } 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);
@@ -1240,7 +1257,8 @@
if (machine_is_msm7627a_qrd1())
rc = mipi_dsi_panel_qrd1_power(on);
- else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt())
rc = mipi_dsi_panel_qrd3_power(on);
else
rc = mipi_dsi_panel_msm_power(on);
@@ -1283,7 +1301,8 @@
if (machine_is_msm7627a_qrd1())
platform_add_devices(qrd_fb_devices,
ARRAY_SIZE(qrd_fb_devices));
- else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()) {
mipi_NT35510_pdata.bl_lock = 1;
mipi_NT35516_pdata.bl_lock = 1;
platform_add_devices(evb_fb_devices,
diff --git a/arch/arm/mach-msm/board-msm7627a-io.c b/arch/arm/mach-msm/board-msm7627a-io.c
index 4df2232..49945d0 100644
--- a/arch/arm/mach-msm/board-msm7627a-io.c
+++ b/arch/arm/mach-msm/board-msm7627a-io.c
@@ -186,6 +186,56 @@
#define MXT_TS_IRQ_GPIO 48
#define MXT_TS_RESET_GPIO 26
+#define MAX_VKEY_LEN 100
+
+static ssize_t mxt_virtual_keys_register(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ char *virtual_keys = __stringify(EV_KEY) ":" __stringify(KEY_MENU) \
+ ":60:840:120:80" ":" __stringify(EV_KEY) \
+ ":" __stringify(KEY_HOME) ":180:840:120:80" \
+ ":" __stringify(EV_KEY) ":" \
+ __stringify(KEY_BACK) ":300:840:120:80" \
+ ":" __stringify(EV_KEY) ":" \
+ __stringify(KEY_SEARCH) ":420:840:120:80" "\n";
+
+ return snprintf(buf, strnlen(virtual_keys, MAX_VKEY_LEN) + 1 , "%s",
+ virtual_keys);
+}
+
+static struct kobj_attribute mxt_virtual_keys_attr = {
+ .attr = {
+ .name = "virtualkeys.atmel_mxt_ts",
+ .mode = S_IRUGO,
+ },
+ .show = &mxt_virtual_keys_register,
+};
+
+static struct attribute *mxt_virtual_key_properties_attrs[] = {
+ &mxt_virtual_keys_attr.attr,
+ NULL,
+};
+
+static struct attribute_group mxt_virtual_key_properties_attr_group = {
+ .attrs = mxt_virtual_key_properties_attrs,
+};
+
+struct kobject *mxt_virtual_key_properties_kobj;
+
+static int mxt_vkey_setup(void)
+{
+ int retval;
+
+ mxt_virtual_key_properties_kobj =
+ kobject_create_and_add("board_properties", NULL);
+ if (mxt_virtual_key_properties_kobj)
+ retval = sysfs_create_group(mxt_virtual_key_properties_kobj,
+ &mxt_virtual_key_properties_attr_group);
+ if (!mxt_virtual_key_properties_kobj || retval)
+ pr_err("failed to create mxt board_properties\n");
+
+ return retval;
+}
static const u8 mxt_config_data[] = {
/* T6 Object */
@@ -232,6 +282,51 @@
80, 100, 15, 3,
};
+static const u8 mxt_config_data_evt[] = {
+ /* T6 Object */
+ 0, 0, 0, 0, 0, 0,
+ /* T38 Object */
+ 20, 0, 0, 0, 0, 0, 0, 0,
+ /* T7 Object */
+ 24, 12, 10,
+ /* T8 Object */
+ 30, 0, 20, 20, 0, 0, 9, 45, 10, 192,
+ /* T9 Object */
+ 3, 0, 0, 18, 11, 0, 16, 60, 3, 1,
+ 0, 1, 1, 0, 10, 10, 10, 10, 107, 3,
+ 223, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 15, 0, 0, 2,
+ /* T15 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+ /* T18 Object */
+ 0, 0,
+ /* T19 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ /* T23 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+ /* T25 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* T40 Object */
+ 17, 0, 0, 30, 30,
+ /* T42 Object */
+ 3, 20, 45, 40, 128, 0, 0, 0,
+ /* T46 Object */
+ 0, 2, 16, 16, 0, 0, 0, 0, 0,
+ /* T47 Object */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* T48 Object */
+ 1, 128, 96, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 6, 6, 0, 0, 63, 4, 64,
+ 10, 0, 32, 5, 0, 38, 0, 8, 0, 0,
+ 0, 0, 0, 0, 16, 65, 3, 1, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+};
+
static struct mxt_config_info mxt_config_array[] = {
{
.config = mxt_config_data,
@@ -715,7 +810,17 @@
i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
synaptic_i2c_clearpad3k,
ARRAY_SIZE(synaptic_i2c_clearpad3k));
- } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb() ||
+ machine_is_msm8625_evt()) {
+ /* Use configuration data for EVT */
+ if (machine_is_msm8625_evt()) {
+ mxt_config_array[0].config = mxt_config_data_evt;
+ mxt_config_array[0].config_length =
+ ARRAY_SIZE(mxt_config_data_evt);
+ mxt_platform_data.panel_maxy = 875;
+ mxt_vkey_setup();
+ }
+
rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
GPIO_CFG_8MA), GPIO_CFG_ENABLE);
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index 946e109..93a430b 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -152,6 +152,7 @@
{
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
|| machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7())
gpio_sdc1_hw_det = 42;
@@ -256,6 +257,7 @@
if (machine_is_msm7627a_qrd1() ||
machine_is_msm7627a_evb() ||
machine_is_msm8625_evb() ||
+ machine_is_msm8625_evt() ||
machine_is_msm7627a_qrd3() ||
machine_is_msm8625_qrd7())
status = !gpio_get_value(gpio_sdc1_hw_det);
diff --git a/arch/arm/mach-msm/board-msm7627a-wlan.c b/arch/arm/mach-msm/board-msm7627a-wlan.c
index 5c2f801..07b7ab0 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -50,6 +50,7 @@
{
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
|| machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7())
gpio_wlan_sys_rest_en = 124;
@@ -234,6 +235,7 @@
*/
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
|| machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7()) {
rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
@@ -312,6 +314,7 @@
*/
if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
|| machine_is_msm8625_evb()
+ || machine_is_msm8625_evt()
|| machine_is_msm7627a_qrd3()
|| machine_is_msm8625_qrd7()) {
rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index ab52665..df4ca83 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -48,6 +48,7 @@
#include <mach/msm_battery.h>
#include <linux/smsc911x.h>
#include <linux/atmel_maxtouch.h>
+#include <linux/fmem.h>
#include <linux/msm_adc.h>
#include "devices.h"
#include "timer.h"
@@ -435,6 +436,9 @@
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
+ .request_region = request_fmem_c_region,
+ .release_region = release_fmem_c_region,
+ .reusable = 1,
};
static struct platform_device android_pmem_adsp_device = {
@@ -563,9 +567,9 @@
(DEC4_FORMAT),
/* Concurrency 6 */
- (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
- (DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
- 0, 0, 0,
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
+ (1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ 0, 0, 0, 0,
/* Concurrency 7 */
(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
@@ -756,6 +760,14 @@
static void msm7x27a_cfg_uart2dm_serial(void) { }
#endif
+struct fmem_platform_data fmem_pdata;
+
+struct platform_device fmem_device = {
+ .name = "fmem",
+ .id = 1,
+ .dev = { .platform_data = &fmem_pdata },
+};
+
static struct platform_device *rumi_sim_devices[] __initdata = {
&msm_device_dmov,
&msm_device_smd,
@@ -793,6 +805,7 @@
&android_pmem_device,
&android_pmem_adsp_device,
&android_pmem_audio_device,
+ &fmem_device,
&msm_device_nand,
&msm_device_snd,
&msm_device_adspdec,
@@ -843,8 +856,19 @@
},
};
+#ifdef CONFIG_ANDROID_PMEM
+static struct android_pmem_platform_data *pmem_pdata_array[] __initdata = {
+ &android_pmem_adsp_pdata,
+ &android_pmem_audio_pdata,
+ &android_pmem_pdata,
+};
+#endif
+
static void __init size_pmem_devices(void)
{
+#ifdef CONFIG_ANDROID_PMEM
+ unsigned int i;
+ unsigned int reusable_count = 0;
if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;
@@ -854,11 +878,30 @@
pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
}
-#ifdef CONFIG_ANDROID_PMEM
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_pdata.size = pmem_mdp_size;
android_pmem_audio_pdata.size = pmem_audio_size;
+
+ fmem_pdata.size = 0;
+
+ /* Find pmem devices that should use FMEM (reusable) memory.
+ */
+ for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
+ struct android_pmem_platform_data *pdata = pmem_pdata_array[i];
+
+ if (!reusable_count && pdata->reusable)
+ fmem_pdata.size += pdata->size;
+
+ reusable_count += (pdata->reusable) ? 1 : 0;
+
+ if (pdata->reusable && reusable_count > 1) {
+ pr_err("%s: Too many PMEM devices specified as reusable. PMEM device %s was not configured as reusable.\n",
+ __func__, pdata->name);
+ pdata->reusable = 0;
+ }
+ }
#endif
+
}
static void __init reserve_memory_for(struct android_pmem_platform_data *p)
@@ -869,9 +912,10 @@
static void __init reserve_pmem_memory(void)
{
#ifdef CONFIG_ANDROID_PMEM
- reserve_memory_for(&android_pmem_adsp_pdata);
- reserve_memory_for(&android_pmem_pdata);
- reserve_memory_for(&android_pmem_audio_pdata);
+ unsigned int i;
+ for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
+ reserve_memory_for(pmem_pdata_array[i]);
+
msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
#endif
}
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
index 743ca4d..32d5530 100644
--- a/arch/arm/mach-msm/board-msm8x60-camera.c
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -23,6 +23,7 @@
#include "devices.h"
#define GPIO_EXT_CAMIF_PWR_EN1 (PM8901_MPP_BASE + PM8901_MPPS + 13)
+#define GPIO_WEB_CAMIF_STANDBY1 (PM8901_MPP_BASE + PM8901_MPPS + 60)
#ifdef CONFIG_MSM_CAMERA_FLASH
#define VFE_CAMIF_TIMER1_GPIO 29
#define VFE_CAMIF_TIMER2_GPIO 30
@@ -388,10 +389,10 @@
{47, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
{48, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
{105, GPIOF_DIR_IN, "STANDBY"},
- {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_DIR_OUT, "CAMIF_PWR_EN"},
};
static struct gpio msm8x60_back_cam_gpio[] = {
+ {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_DIR_OUT, "CAMIF_PWR_EN"},
{106, GPIOF_DIR_OUT, "CAM_RESET"},
};
@@ -448,6 +449,63 @@
.actuator_info = &imx074_actuator_info
};
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_mt9e013 = {
+ .mount_angle = 0,
+ .cam_vreg = msm_8x60_back_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+ .gpio_conf = &msm_8x60_back_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+ .sensor_name = "mt9e013",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_mt9e013,
+ .sensor_platform_info = &sensor_board_info_mt9e013,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+};
+
+static struct gpio ov7692_cam_gpio[] = {
+ {GPIO_WEB_CAMIF_STANDBY1, GPIOF_DIR_OUT, "CAM_EN"},
+};
+
+static struct msm_gpio_set_tbl ov7692_cam_gpio_set_tbl[] = {
+ {GPIO_WEB_CAMIF_STANDBY1, GPIOF_OUT_INIT_LOW, 10000},
+};
+
+static struct msm_camera_gpio_conf ov7692_cam_gpio_conf = {
+ .cam_gpio_common_tbl = msm8x60_common_cam_gpio,
+ .cam_gpio_common_tbl_size = ARRAY_SIZE(msm8x60_common_cam_gpio),
+ .cam_gpio_req_tbl = ov7692_cam_gpio,
+ .cam_gpio_req_tbl_size = ARRAY_SIZE(ov7692_cam_gpio),
+ .cam_gpio_set_tbl = ov7692_cam_gpio_set_tbl,
+ .cam_gpio_set_tbl_size = ARRAY_SIZE(ov7692_cam_gpio_set_tbl),
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+ .flash_type = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_platform_info sensor_board_info_ov7692 = {
+ .mount_angle = 0,
+ .cam_vreg = msm_8x60_back_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+ .gpio_conf = &ov7692_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+ .sensor_name = "ov7692",
+ .pdata = &msm_camera_csi_device_data[1],
+ .flash_data = &flash_ov7692,
+ .sensor_platform_info = &sensor_board_info_ov7692,
+ .csi_if = 1,
+ .camera_type = FRONT_CAMERA_2D,
+};
+
static struct platform_device msm_camera_server = {
.name = "msm_cam_server",
.id = 0,
@@ -468,6 +526,14 @@
I2C_BOARD_INFO("imx074", 0x1A),
.platform_data = &msm_camera_sensor_imx074_data,
},
+ {
+ I2C_BOARD_INFO("mt9e013", 0x6C),
+ .platform_data = &msm_camera_sensor_mt9e013_data,
+ },
+ {
+ I2C_BOARD_INFO("ov7692", 0x78),
+ .platform_data = &msm_camera_sensor_ov7692_data,
+ },
};
struct msm_camera_board_info msm8x60_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 5fc17df..e5a31f2a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -85,6 +85,7 @@
#include <mach/rpm-regulator.h>
#include <mach/restart.h>
#include <mach/board-msm8660.h>
+#include <mach/iommu_domains.h>
#include "devices.h"
#include "devices-msm8x60.h"
@@ -2646,7 +2647,7 @@
#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 0x3600000 /* (54MB) */
+#define MSM_ION_MM_SIZE 0x3600000 /* (54MB) 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 */
@@ -3812,6 +3813,8 @@
static struct regulator_consumer_supply vreg_consumers_PM8058_L15[] = {
REGULATOR_SUPPLY("8058_l15", NULL),
REGULATOR_SUPPLY("cam_vana", "1-001a"),
+ REGULATOR_SUPPLY("cam_vana", "1-006c"),
+ REGULATOR_SUPPLY("cam_vana", "1-0078"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_L16[] = {
REGULATOR_SUPPLY("8058_l16", NULL),
@@ -3843,6 +3846,8 @@
static struct regulator_consumer_supply vreg_consumers_PM8058_L25[] = {
REGULATOR_SUPPLY("8058_l25", NULL),
REGULATOR_SUPPLY("cam_vdig", "1-001a"),
+ REGULATOR_SUPPLY("cam_vdig", "1-006c"),
+ REGULATOR_SUPPLY("cam_vdig", "1-0078"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_S0[] = {
REGULATOR_SUPPLY("8058_s0", NULL),
@@ -3862,6 +3867,8 @@
static struct regulator_consumer_supply vreg_consumers_PM8058_LVS0[] = {
REGULATOR_SUPPLY("8058_lvs0", NULL),
REGULATOR_SUPPLY("cam_vio", "1-001a"),
+ REGULATOR_SUPPLY("cam_vio", "1-006c"),
+ REGULATOR_SUPPLY("cam_vio", "1-0078"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_LVS1[] = {
REGULATOR_SUPPLY("8058_lvs1", NULL),
@@ -5256,10 +5263,12 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
.permission_type = IPT_TYPE_MM_CARVEOUT,
- .align = PAGE_SIZE,
+ .align = SZ_64K,
.request_region = request_smi_region,
.release_region = release_smi_region,
.setup_region = setup_smi_region,
+ .iommu_map_all = 1,
+ .iommu_2x_map_domain = VIDEO_DOMAIN,
};
static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
@@ -5426,6 +5435,23 @@
}
}
+ /* Verify size of heap is a multiple of 64K */
+ for (i = 0; i < ion_pdata.nr; i++) {
+ struct ion_platform_heap *heap = &(ion_pdata.heaps[i]);
+
+ if (heap->extra_data && heap->type == ION_HEAP_TYPE_CP) {
+ int map_all = ((struct ion_cp_heap_pdata *)
+ heap->extra_data)->iommu_map_all;
+
+ if (map_all && (heap->size & (SZ_64K-1))) {
+ heap->size = ALIGN(heap->size, SZ_64K);
+ pr_err("Heap %s size is not a multiple of 64K. Adjusting size to %x\n",
+ heap->name, heap->size);
+
+ }
+ }
+ }
+
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;
@@ -7491,7 +7517,7 @@
"msm_ebi2", "mem_clk");
return;
}
- clk_enable(mem_clk);
+ clk_prepare_enable(mem_clk);
clk_put(mem_clk);
ebi2_cfg_ptr = ioremap_nocache(0x1a100000, sizeof(uint32_t));
@@ -10315,8 +10341,8 @@
machine_is_msm8x60_fusn_ffa() || machine_is_msm8x60_dragon()) {
msm8x60_cfg_smsc911x();
if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1)
- platform_add_devices(msm_footswitch_devices,
- msm_num_footswitch_devices);
+ platform_add_devices(msm8660_footswitch,
+ msm8660_num_footswitch);
platform_add_devices(surf_devices,
ARRAY_SIZE(surf_devices));
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 782bb9e..f565075 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -510,9 +510,9 @@
(DEC4_FORMAT),
/* Concurrency 6 */
- (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|(1<<MSM_ADSP_OP_DM)),
- (DEC1_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
- 0, 0, 0,
+ (DEC0_FORMAT|(1<<MSM_ADSP_MODE_TUNNEL)|
+ (1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
+ 0, 0, 0, 0,
/* Concurrency 7 */
(DEC0_FORMAT|(1<<MSM_ADSP_MODE_NONTUNNEL)|(1<<MSM_ADSP_OP_DM)),
@@ -808,7 +808,8 @@
static void __init add_platform_devices(void)
{
- if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()) {
+ if (machine_is_msm8625_evb() || machine_is_msm8625_qrd7()
+ || machine_is_msm8625_evt()) {
platform_add_devices(msm8625_evb_devices,
ARRAY_SIZE(msm8625_evb_devices));
platform_add_devices(qrd3_devices,
@@ -966,3 +967,13 @@
.init_early = qrd7627a_init_early,
.handle_irq = gic_handle_irq,
MACHINE_END
+MACHINE_START(MSM8625_EVT, "QRD MSM8625 EVT")
+ .boot_params = PHYS_OFFSET + 0x100,
+ .map_io = msm8625_map_io,
+ .reserve = msm8625_reserve,
+ .init_irq = msm8625_init_irq,
+ .init_machine = msm_qrd_init,
+ .timer = &msm_timer,
+ .init_early = qrd7627a_init_early,
+ .handle_irq = gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 1035caf..3a0b87e 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -49,6 +49,7 @@
#define CE3_CORE_CLK_CTL_REG REG(0x36CC)
#define CE3_CLK_SRC_NS_REG REG(0x36C0)
#define DMA_BAM_HCLK_CTL REG(0x25C0)
+#define CLK_HALT_AFAB_SFAB_STATEA_REG REG(0x2FC0)
#define CLK_HALT_AFAB_SFAB_STATEB_REG REG(0x2FC4)
#define CLK_HALT_CFPB_STATEA_REG REG(0x2FCC)
#define CLK_HALT_CFPB_STATEB_REG REG(0x2FD0)
@@ -142,7 +143,9 @@
#define USB_HSIC_XCVR_FS_CLK_NS_REG REG(0x2928)
#define USB_PHY0_RESET_REG REG(0x2E20)
#define PCIE_ALT_REF_CLK_NS_REG REG(0x3860)
+#define PCIE_ACLK_CTL_REG REG(0x22C0)
#define PCIE_HCLK_CTL_REG REG(0x22CC)
+#define PCIE_PCLK_CTL_REG REG(0x22D0)
#define GPLL1_MODE_REG REG(0x3160)
#define GPLL1_L_VAL_REG REG(0x3164)
#define GPLL1_M_VAL_REG REG(0x3168)
@@ -1952,6 +1955,34 @@
},
};
+static struct branch_clk pcie_phy_ref_clk = {
+ .b = {
+ .ctl_reg = PCIE_PCLK_CTL_REG,
+ .en_mask = BIT(4),
+ .halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
+ .halt_bit = 29,
+ },
+ .c = {
+ .dbg_name = "pcie_phy_ref_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(pcie_phy_ref_clk.c),
+ },
+};
+
+static struct branch_clk pcie_a_clk = {
+ .b = {
+ .ctl_reg = PCIE_ACLK_CTL_REG,
+ .en_mask = BIT(4),
+ .halt_reg = CLK_HALT_AFAB_SFAB_STATEA_REG,
+ .halt_bit = 13,
+ },
+ .c = {
+ .dbg_name = "pcie_a_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(pcie_a_clk.c),
+ },
+};
+
static struct branch_clk dma_bam_p_clk = {
.b = {
.ctl_reg = DMA_BAM_HCLK_CTL,
@@ -4575,6 +4606,8 @@
{ TEST_PER_HS(0x26), &q6sw_clk },
{ TEST_PER_HS(0x27), &q6fw_clk },
{ TEST_PER_HS(0x2A), &adm0_clk.c },
+ { TEST_PER_HS(0x2D), &pcie_phy_ref_clk.c },
+ { TEST_PER_HS(0x32), &pcie_a_clk.c },
{ TEST_PER_HS(0x34), &ebi1_clk.c },
{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
{ TEST_PER_HS(0x50), &usb_hsic_hsic_clk.c },
@@ -4960,6 +4993,8 @@
CLK_LOOKUP("iface_clk", sdc3_p_clk.c, "msm_sdcc.3"),
CLK_LOOKUP("iface_clk", sdc4_p_clk.c, "msm_sdcc.4"),
CLK_LOOKUP("iface_clk", pcie_p_clk.c, ""),
+ CLK_LOOKUP("ref_clk", pcie_phy_ref_clk.c, ""),
+ CLK_LOOKUP("bus_clk", pcie_a_clk.c, ""),
CLK_LOOKUP("core_clk", adm0_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", adm0_p_clk.c, "msm_dmov"),
CLK_LOOKUP("iface_clk", pmic_arb0_p_clk.c, ""),
@@ -5077,10 +5112,10 @@
CLK_LOOKUP("vpe_pclk", vpe_p_clk.c, "msm_vpe.0"),
CLK_LOOKUP("iface_clk", vpe_p_clk.c, "footswitch-8x60.9"),
- CLK_LOOKUP("bit_clk", mi2s_bit_clk.c, "msm-dai-q6.6"),
- CLK_LOOKUP("osr_clk", mi2s_osr_clk.c, "msm-dai-q6.6"),
- CLK_LOOKUP("bit_clk", mi2s_bit_clk.c, "msm-dai-q6.7"),
- CLK_LOOKUP("osr_clk", mi2s_osr_clk.c, "msm-dai-q6.7"),
+ CLK_LOOKUP("bit_clk", mi2s_bit_clk.c,
+ "msm-dai-q6-mi2s"),
+ CLK_LOOKUP("osr_clk", mi2s_osr_clk.c,
+ "msm-dai-q6-mi2s"),
CLK_LOOKUP("bit_clk", codec_i2s_mic_bit_clk.c,
"msm-dai-q6.1"),
CLK_LOOKUP("osr_clk", codec_i2s_mic_osr_clk.c,
@@ -5393,10 +5428,10 @@
CLK_LOOKUP("iface_clk", vfe_p_clk.c, "footswitch-8x60.8"),
CLK_LOOKUP("vpe_pclk", vpe_p_clk.c, "msm_vpe.0"),
CLK_LOOKUP("iface_clk", vpe_p_clk.c, "footswitch-8x60.9"),
- CLK_LOOKUP("bit_clk", mi2s_bit_clk.c, "msm-dai-q6.6"),
- CLK_LOOKUP("osr_clk", mi2s_osr_clk.c, "msm-dai-q6.6"),
- CLK_LOOKUP("bit_clk", mi2s_bit_clk.c, "msm-dai-q6.7"),
- CLK_LOOKUP("osr_clk", mi2s_osr_clk.c, "msm-dai-q6.7"),
+ CLK_LOOKUP("bit_clk", mi2s_bit_clk.c,
+ "msm-dai-q6-mi2s"),
+ CLK_LOOKUP("osr_clk", mi2s_osr_clk.c,
+ "msm-dai-q6-mi2s"),
CLK_LOOKUP("bit_clk", codec_i2s_mic_bit_clk.c,
"msm-dai-q6.1"),
CLK_LOOKUP("osr_clk", codec_i2s_mic_osr_clk.c,
@@ -5578,7 +5613,7 @@
CLK_LOOKUP("mem_clk", rpm_msg_ram_p_clk.c, ""),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-001a"),
CLK_LOOKUP("cam_clk", cam1_clk.c, "4-006c"),
- CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0048"),
+ CLK_LOOKUP("cam_clk", cam1_clk.c, "4-0048"),
CLK_LOOKUP("cam_clk", cam2_clk.c, NULL),
CLK_LOOKUP("cam_clk", cam0_clk.c, "4-0020"),
CLK_LOOKUP("csi_src_clk", csi0_src_clk.c, "msm_csid.0"),
diff --git a/arch/arm/mach-msm/clock-copper.c b/arch/arm/mach-msm/clock-copper.c
index 7123ffa..03667d7 100644
--- a/arch/arm/mach-msm/clock-copper.c
+++ b/arch/arm/mach-msm/clock-copper.c
@@ -102,6 +102,7 @@
#define MMSS_DEBUG_CLK_CTL_REG 0x0900
#define LPASS_DEBUG_CLK_CTL_REG 0x29000
#define LPASS_LPA_PLL_VOTE_APPS_REG 0x2000
+#define MSS_DEBUG_CLK_CTL_REG 0x0078
#define USB30_MASTER_CMD_RCGR 0x03D4
#define USB30_MOCK_UTMI_CMD_RCGR 0x03E8
@@ -230,6 +231,7 @@
#define BLSP2_UART5_BCR 0x0BC0
#define BLSP2_QUP6_BCR 0x0C00
#define BLSP2_UART6_BCR 0x0C40
+#define BOOT_ROM_BCR 0x0E00
#define PDM_BCR 0x0CC0
#define PRNG_BCR 0x0D00
#define BAM_DMA_BCR 0x0D40
@@ -280,6 +282,8 @@
#define OXILICX_AXI_CBCR 0x4038
#define OXILI_BCR 0x4020
#define OXILICX_BCR 0x4030
+#define LPASS_Q6SS_BCR 0x6000
+#define MSS_Q6SS_BCR 0x1068
#define OCMEM_SYS_NOC_AXI_CBCR 0x0244
#define OCMEM_NOC_CFG_AHB_CBCR 0x0248
@@ -327,6 +331,7 @@
#define BLSP1_UART6_APPS_CBCR 0x0904
#define BLSP1_UART6_SIM_CBCR 0x0908
#define BLSP2_AHB_CBCR 0x0944
+#define BOOT_ROM_AHB_CBCR 0x0E04
#define BLSP2_QUP1_SPI_APPS_CBCR 0x0984
#define BLSP2_QUP1_I2C_APPS_CBCR 0x0988
#define BLSP2_UART1_APPS_CBCR 0x09C4
@@ -469,6 +474,11 @@
#define MMSS_MISC_AHB_CBCR 0x502C
#define MMSS_S0_AXI_CBCR 0x5064
#define OCMEMNOC_CBCR 0x50B4
+#define LPASS_Q6SS_AHB_LFABIF_CBCR 0x22000
+#define LPASS_Q6SS_XO_CBCR 0x26000
+#define MSS_XO_Q6_CBCR 0x108C
+#define MSS_BUS_Q6_CBCR 0x10A4
+#define MSS_CFG_AHB_CBCR 0x0280
#define APCS_CLOCK_BRANCH_ENA_VOTE 0x1484
#define APCS_CLOCK_SLEEP_ENA_VOTE 0x1488
@@ -1625,6 +1635,19 @@
},
};
+static struct local_vote_clk gcc_boot_rom_ahb_clk = {
+ .cbcr_reg = BOOT_ROM_AHB_CBCR,
+ .vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
+ .en_mask = BIT(10),
+ .bcr_reg = BOOT_ROM_BCR,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_boot_rom_ahb_clk",
+ .ops = &clk_ops_vote,
+ CLK_INIT(gcc_boot_rom_ahb_clk.c),
+ },
+};
+
static struct local_vote_clk gcc_blsp2_ahb_clk = {
.cbcr_reg = BLSP2_AHB_CBCR,
.vote_reg = APCS_CLOCK_BRANCH_ENA_VOTE,
@@ -2225,6 +2248,17 @@
},
};
+static struct branch_clk gcc_mss_cfg_ahb_clk = {
+ .cbcr_reg = MSS_CFG_AHB_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[GCC_BASE],
+ .c = {
+ .dbg_name = "gcc_mss_cfg_ahb_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(gcc_mss_cfg_ahb_clk.c),
+ },
+};
+
static struct clk_freq_tbl ftbl_mmss_ahb_clk[] = {
F_MM(19200000, cxo, 1, 0, 0),
F_MM(40000000, gpll0, 15, 0, 0),
@@ -4291,6 +4325,55 @@
},
};
+static struct branch_clk q6ss_ahb_lfabif_clk = {
+ .cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_ahb_lfabif_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_ahb_lfabif_clk.c),
+ },
+};
+
+static struct branch_clk q6ss_xo_clk = {
+ .cbcr_reg = LPASS_Q6SS_XO_CBCR,
+ .bcr_reg = LPASS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[LPASS_BASE],
+ .c = {
+ .dbg_name = "q6ss_xo_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(q6ss_xo_clk.c),
+ },
+};
+
+static struct branch_clk mss_xo_q6_clk = {
+ .cbcr_reg = MSS_XO_Q6_CBCR,
+ .bcr_reg = MSS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MSS_BASE],
+ .c = {
+ .dbg_name = "mss_xo_q6_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mss_xo_q6_clk.c),
+ .depends = &gcc_mss_cfg_ahb_clk.c,
+ },
+};
+
+static struct branch_clk mss_bus_q6_clk = {
+ .cbcr_reg = MSS_BUS_Q6_CBCR,
+ .bcr_reg = MSS_Q6SS_BCR,
+ .has_sibling = 1,
+ .base = &virt_bases[MSS_BASE],
+ .c = {
+ .dbg_name = "mss_bus_q6_clk",
+ .ops = &clk_ops_branch,
+ CLK_INIT(mss_bus_q6_clk.c),
+ .depends = &gcc_mss_cfg_ahb_clk.c,
+ },
+};
+
#ifdef CONFIG_DEBUG_FS
struct measure_mux_entry {
@@ -4339,6 +4422,8 @@
{&gcc_blsp2_uart4_apps_clk.c, GCC_BASE, 0x00c2},
{&gcc_blsp2_uart5_apps_clk.c, GCC_BASE, 0x00c6},
{&gcc_blsp2_uart6_apps_clk.c, GCC_BASE, 0x00cb},
+ {&gcc_boot_rom_ahb_clk.c, GCC_BASE, 0x0100},
+ {&gcc_mss_cfg_ahb_clk.c, GCC_BASE, 0x0030},
{&gcc_ce1_clk.c, GCC_BASE, 0x0140},
{&gcc_ce2_clk.c, GCC_BASE, 0x0148},
{&gcc_pdm2_clk.c, GCC_BASE, 0x00da},
@@ -4438,6 +4523,11 @@
{&audio_core_lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
{&audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d},
{&audio_core_slimbus_lfabif_clk.c, LPASS_BASE, 0x003e},
+ {&q6ss_xo_clk.c, LPASS_BASE, 0x002b},
+ {&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
+ {&mss_bus_q6_clk.c, MSS_BASE, 0x003c},
+ {&mss_xo_q6_clk.c, MSS_BASE, 0x0007},
+
{&dummy_clk, N_BASES, 0x0000},
};
@@ -4465,6 +4555,7 @@
clk->sample_ticks = 0x10000;
clk->multiplier = 1;
+ writel_relaxed(0, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, MMSS_REG_BASE(MMSS_DEBUG_CLK_CTL_REG));
writel_relaxed(0, GCC_REG_BASE(GCC_DEBUG_CLK_CTL_REG));
@@ -4495,6 +4586,12 @@
writel_relaxed(regval, LPASS_REG_BASE(LPASS_DEBUG_CLK_CTL_REG));
break;
+ case MSS_BASE:
+ clk_sel = 0x32;
+ regval = BVAL(5, 0, measure_mux[i].debug_mux);
+ writel_relaxed(regval, MSS_REG_BASE(MSS_DEBUG_CLK_CTL_REG));
+ break;
+
default:
return -EINVAL;
}
@@ -4807,6 +4904,13 @@
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", q6ss_xo_clk.c, ""),
+ CLK_LOOKUP("bus_clk", q6ss_ahb_lfabif_clk.c, ""),
+ CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, ""),
+ CLK_LOOKUP("bus_clk", gcc_mss_cfg_ahb_clk.c, ""),
+
/* 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),
@@ -5048,6 +5152,9 @@
#define LPASS_CC_PHYS 0xFE000000
#define LPASS_CC_SIZE SZ_256K
+#define MSS_CC_PHYS 0xFC980000
+#define MSS_CC_SIZE SZ_16K
+
static void __init msmcopper_clock_pre_init(void)
{
virt_bases[GCC_BASE] = ioremap(GCC_CC_PHYS, GCC_CC_SIZE);
@@ -5062,6 +5169,10 @@
if (!virt_bases[LPASS_BASE])
panic("clock-copper: Unable to ioremap LPASS_CC memory!");
+ virt_bases[MSS_BASE] = ioremap(MSS_CC_PHYS, MSS_CC_SIZE);
+ if (!virt_bases[MSS_BASE])
+ panic("clock-copper: Unable to ioremap MSS_CC memory!");
+
clk_ops_local_pll.enable = copper_pll_clk_enable;
reg_init();
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index a4750bc..3a232c5 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -238,7 +238,7 @@
spin_lock_irqsave(&pll_reg_lock, flags);
mode = readl_relaxed(PLL_MODE_REG(pll));
/* Disable PLL bypass mode. */
- mode |= BIT(1);
+ mode |= PLL_BYPASSNL;
writel_relaxed(mode, PLL_MODE_REG(pll));
/*
@@ -249,7 +249,7 @@
udelay(10);
/* De-assert active-low PLL reset. */
- mode |= BIT(2);
+ mode |= PLL_RESET_N;
writel_relaxed(mode, PLL_MODE_REG(pll));
/* Wait for pll to enable. */
@@ -266,7 +266,7 @@
}
/* Enable PLL output. */
- mode |= BIT(0);
+ mode |= PLL_OUTCTRL;
writel_relaxed(mode, PLL_MODE_REG(pll));
/* Ensure the write above goes through before returning. */
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 177af8c..4cd9b1c 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -147,7 +147,7 @@
return true;
}
-enum handoff voter_clk_handoff(struct clk *clk)
+static enum handoff voter_clk_handoff(struct clk *clk)
{
/* Apply default rate vote */
if (clk->rate)
@@ -164,4 +164,5 @@
.round_rate = voter_clk_round_rate,
.get_parent = voter_clk_get_parent,
.is_local = voter_clk_is_local,
+ .handoff = voter_clk_handoff,
};
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index b51fb83..f6eee76 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -483,14 +483,15 @@
},
};
-struct msm_mi2s_data mpq_mi2s_tx_data = {
- .sd_lines = MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3,
- .capability = MSM_MI2S_CAP_TX,
+struct msm_mi2s_pdata mpq_mi2s_tx_data = {
+ .rx_sd_lines = 0,
+ .tx_sd_lines = MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 |
+ MSM_MI2S_SD3,
};
struct platform_device mpq_cpudai_mi2s_tx = {
- .name = "msm-dai-q6",
- .id = 7, /*MI2S_TX */
+ .name = "msm-dai-q6-mi2s",
+ .id = -1, /*MI2S_TX */
.dev = {
.platform_data = &mpq_mi2s_tx_data,
},
@@ -581,6 +582,11 @@
.id = 0x4005,
};
+struct platform_device apq_cpudai_slimbus_3_rx = {
+ .name = "msm-dai-q6",
+ .id = 0x4006,
+};
+
static struct resource resources_ssbi_pmic1[] = {
{
.start = MSM_PMIC1_SSBI_CMD_PHYS,
@@ -1060,6 +1066,7 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
.memtype = ION_CP_MM_HEAP_ID,
.enable_ion = 1,
+ .cp_enabled = 1,
#else
.memtype = MEMTYPE_EBI1,
.enable_ion = 0,
@@ -1548,16 +1555,88 @@
.resource = msm_gss_resources,
};
-struct platform_device *apq8064_fs_devices[] = {
- FS_8X60(FS_ROT, "fs_rot"),
- FS_8X60(FS_IJPEG, "fs_ijpeg"),
- FS_8X60(FS_VFE, "fs_vfe"),
- FS_8X60(FS_VPE, "fs_vpe"),
- FS_8X60(FS_GFX3D, "fs_gfx3d"),
- FS_8X60(FS_VED, "fs_ved"),
- FS_8X60(FS_VCAP, "fs_vcap"),
+static struct fs_driver_data gfx3d_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk", .reset_rate = 27000000 },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+ .bus_port1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
};
-unsigned apq8064_num_fs_devices = ARRAY_SIZE(apq8064_fs_devices);
+
+static struct fs_driver_data ijpeg_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_JPEG_ENC,
+};
+
+static struct fs_driver_data rot_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VIDEO_ENC,
+ .bus_port1 = MSM_BUS_MASTER_VIDEO_DEC,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+static struct fs_driver_data vcap_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 },
+ },
+ .bus_port0 = MSM_BUS_MASTER_VIDEO_CAP,
+};
+
+struct platform_device *apq8064_footswitch[] __initdata = {
+ 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),
+ FS_8X60(FS_VPE, "fs_vpe", NULL, &vpe_fs_data),
+ FS_8X60(FS_GFX3D, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
+ FS_8X60(FS_VED, "vdd", "msm_vidc.0", &ved_fs_data),
+ FS_8X60(FS_VCAP, "vdd", "msm_vcap.0", &vcap_fs_data),
+};
+unsigned apq8064_num_footswitch __initdata = ARRAY_SIZE(apq8064_footswitch);
struct msm_rpm_platform_data apq8064_rpm_data __initdata = {
.reg_base_addrs = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index ae97189..4ad73f9 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -28,6 +28,7 @@
#include "devices.h"
#include "rpm_log.h"
#include "rpm_stats.h"
+#include "footswitch.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -352,6 +353,93 @@
.id = MSM_BUS_FAB_CPSS_FPB,
};
+static struct fs_driver_data gfx3d_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk", .reset_rate = 27000000 },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .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" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+ .bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8930_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),
+ FS_8X60(FS_VPE, "fs_vpe", NULL, &vpe_fs_data),
+ FS_8X60(FS_GFX3D, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
+ FS_8X60(FS_VED, "vdd", "msm_vidc.0", &ved_fs_data),
+};
+unsigned msm8930_num_footswitch __initdata = ARRAY_SIZE(msm8930_footswitch);
+
/* MSM Video core device */
#ifdef CONFIG_MSM_BUS_SCALING
static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -598,11 +686,12 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
.memtype = ION_CP_MM_HEAP_ID,
.enable_ion = 1,
+ .cp_enabled = 1,
#else
.memtype = MEMTYPE_EBI1,
.enable_ion = 0,
#endif
- .disable_dmx = 0,
+ .disable_dmx = 1,
.disable_fullhd = 0,
};
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 7fb4b01..f1553b6 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -33,6 +33,7 @@
#include <mach/msm_smd.h>
#include <mach/msm_dcvs.h>
#include <mach/msm_rtb.h>
+#include <mach/msm_cache_dump.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_tsif.h>
@@ -681,7 +682,6 @@
#define MSM_SDC2_BASE 0x12140000
#define MSM_SDC2_DML_BASE (MSM_SDC2_BASE + 0x800)
#define MSM_SDC2_BAM_BASE (MSM_SDC2_BASE + 0x2000)
-#define MSM_SDC2_BASE 0x12140000
#define MSM_SDC3_BASE 0x12180000
#define MSM_SDC3_DML_BASE (MSM_SDC3_BASE + 0x800)
#define MSM_SDC3_BAM_BASE (MSM_SDC3_BASE + 0x2000)
@@ -1977,19 +1977,111 @@
.id = -1,
};
-struct platform_device *msm_footswitch_devices[] = {
- FS_8X60(FS_MDP, "fs_mdp"),
- FS_8X60(FS_ROT, "fs_rot"),
- FS_8X60(FS_IJPEG, "fs_ijpeg"),
- FS_8X60(FS_VFE, "fs_vfe"),
- FS_8X60(FS_VPE, "fs_vpe"),
- FS_8X60(FS_GFX3D, "fs_gfx3d"),
- FS_8X60(FS_GFX2D0, "fs_gfx2d0"),
- FS_8X60(FS_GFX2D1, "fs_gfx2d1"),
- FS_8X60(FS_VED, "fs_ved"),
+static struct fs_driver_data gfx2d0_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
};
-unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+static struct fs_driver_data gfx2d1_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk", .reset_rate = 27000000 },
+ { .name = "iface_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .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" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+ .bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8960_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),
+ FS_8X60(FS_VPE, "fs_vpe", NULL, &vpe_fs_data),
+ FS_8X60(FS_GFX3D, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
+ FS_8X60(FS_GFX2D0, "vdd", "kgsl-2d0.0", &gfx2d0_fs_data),
+ FS_8X60(FS_GFX2D1, "vdd", "kgsl-2d1.1", &gfx2d1_fs_data),
+ FS_8X60(FS_VED, "vdd", "msm_vidc.0", &ved_fs_data),
+};
+unsigned msm8960_num_footswitch __initdata = ARRAY_SIZE(msm8960_footswitch);
#ifdef CONFIG_MSM_ROTATOR
static struct msm_bus_vectors rotator_init_vectors[] = {
@@ -2103,7 +2195,6 @@
.number_of_clocks = ARRAY_SIZE(rotator_clocks),
.hardware_version_number = 0x01020309,
.rotator_clks = rotator_clocks,
- .regulator_name = "fs_rot",
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &rotator_bus_scale_pdata,
#endif
@@ -3528,3 +3619,16 @@
.platform_data = &msm8960_rtb_pdata,
},
};
+
+struct msm_cache_dump_platform_data msm8960_cache_dump_pdata = {
+ .l2_size = L2_BUFFER_SIZE,
+ .l1_size = L1_BUFFER_SIZE,
+};
+
+struct platform_device msm8960_cache_dump_device = {
+ .name = "msm_cache_dump",
+ .id = -1,
+ .dev = {
+ .platform_data = &msm8960_cache_dump_pdata,
+ },
+};
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index d36b8d9..2382510 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -870,7 +870,7 @@
};
struct platform_device *msm_footswitch_devices[] = {
- FS_PCOM(FS_GFX3D, "fs_gfx3d"),
+ FS_PCOM(FS_GFX3D, "vdd", "kgsl-3d0.0"),
};
unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index a9d68a6..2d79f62 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -832,7 +832,7 @@
void __init msm7x25a_kgsl_3d0_init(void)
{
- if (cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+ if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
kgsl_3d0_pdata.num_levels = 2;
kgsl_3d0_pdata.pwrlevel[0].gpu_freq = 133330000;
kgsl_3d0_pdata.pwrlevel[0].bus_freq = 160000000;
@@ -929,7 +929,7 @@
};
struct platform_device *msm_footswitch_devices[] = {
- FS_PCOM(FS_GFX3D, "fs_gfx3d"),
+ FS_PCOM(FS_GFX3D, "vdd", "kgsl-3d0.0"),
};
unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
@@ -1620,7 +1620,7 @@
}
msm_clock_init(&msm7x27a_clock_init_data);
- if (cpu_is_msm7x27aa())
+ if (cpu_is_msm7x27aa() || cpu_is_msm7x25ab())
acpuclk_init(&acpuclk_7x27aa_soc_data);
else if (cpu_is_msm8625()) {
if (msm8625_cpu_id() == MSM8625)
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 234af04..e055579 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1187,7 +1187,6 @@
.number_of_clocks = ARRAY_SIZE(rotator_clocks),
.hardware_version_number = 0x1000303,
.rotator_clks = rotator_clocks,
- .regulator_name = "fs_rot",
};
struct platform_device msm_rotator_device = {
@@ -1345,13 +1344,13 @@
};
struct platform_device *msm_footswitch_devices[] = {
- FS_PCOM(FS_GFX2D0, "fs_gfx2d0"),
- FS_PCOM(FS_GFX3D, "fs_gfx3d"),
- FS_PCOM(FS_MDP, "fs_mdp"),
- FS_PCOM(FS_MFC, "fs_mfc"),
- FS_PCOM(FS_ROT, "fs_rot"),
- FS_PCOM(FS_VFE, "fs_vfe"),
- FS_PCOM(FS_VPE, "fs_vpe"),
+ FS_PCOM(FS_GFX2D0, "vdd", "kgsl-2d0.0"),
+ FS_PCOM(FS_GFX3D, "vdd", "kgsl-3d0.0"),
+ FS_PCOM(FS_MDP, "vdd", "mdp.0"),
+ FS_PCOM(FS_MFC, "fs_mfc", NULL),
+ FS_PCOM(FS_ROT, "vdd", "msm_rotator.0"),
+ FS_PCOM(FS_VFE, "fs_vfe", NULL),
+ FS_PCOM(FS_VPE, "fs_vpe", NULL),
};
unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index e19beb8..d622af2 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1547,7 +1547,6 @@
.number_of_clocks = ARRAY_SIZE(rotator_clocks),
.hardware_version_number = 0x01010307,
.rotator_clks = rotator_clocks,
- .regulator_name = "fs_rot",
#ifdef CONFIG_MSM_BUS_SCALING
.bus_scale_table = &rotator_bus_scale_pdata,
#endif
@@ -2562,18 +2561,112 @@
};
#endif
-struct platform_device *msm_footswitch_devices[] = {
- FS_8X60(FS_IJPEG, "fs_ijpeg"),
- FS_8X60(FS_MDP, "fs_mdp"),
- FS_8X60(FS_ROT, "fs_rot"),
- FS_8X60(FS_VED, "fs_ved"),
- FS_8X60(FS_VFE, "fs_vfe"),
- FS_8X60(FS_VPE, "fs_vpe"),
- FS_8X60(FS_GFX3D, "fs_gfx3d"),
- FS_8X60(FS_GFX2D0, "fs_gfx2d0"),
- FS_8X60(FS_GFX2D1, "fs_gfx2d1"),
+static struct fs_driver_data gfx2d0_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE0,
};
-unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct fs_driver_data gfx2d1_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_2D_CORE1,
+};
+
+static struct fs_driver_data gfx3d_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk", .reset_rate = 27000000 },
+ { .name = "iface_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_GRAPHICS_3D,
+};
+
+static struct fs_driver_data ijpeg_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .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 = "tv_src_clk" },
+ { .name = "tv_clk" },
+ { .name = "pixel_mdp_clk" },
+ { .name = "pixel_lcdc_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" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_ROTATOR,
+};
+
+static struct fs_driver_data ved_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_HD_CODEC_PORT0,
+ .bus_port1 = MSM_BUS_MASTER_HD_CODEC_PORT1,
+};
+
+static struct fs_driver_data vfe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VFE,
+};
+
+static struct fs_driver_data vpe_fs_data = {
+ .clks = (struct fs_clk_data[]){
+ { .name = "core_clk" },
+ { .name = "iface_clk" },
+ { .name = "bus_clk" },
+ { 0 }
+ },
+ .bus_port0 = MSM_BUS_MASTER_VPE,
+};
+
+struct platform_device *msm8660_footswitch[] __initdata = {
+ FS_8X60(FS_IJPEG, "vdd", "msm_gemini.0", &ijpeg_fs_data),
+ FS_8X60(FS_MDP, "vdd", "mdp.0", &mdp_fs_data),
+ FS_8X60(FS_ROT, "vdd", "msm_rotator.0", &rot_fs_data),
+ FS_8X60(FS_VED, "vdd", "msm_vidc.0", &ved_fs_data),
+ FS_8X60(FS_VFE, "fs_vfe", NULL, &vfe_fs_data),
+ FS_8X60(FS_VPE, "fs_vpe", NULL, &vpe_fs_data),
+ FS_8X60(FS_GFX3D, "vdd", "kgsl-3d0.0", &gfx3d_fs_data),
+ FS_8X60(FS_GFX2D0, "vdd", "kgsl-2d0.0", &gfx2d0_fs_data),
+ FS_8X60(FS_GFX2D1, "vdd", "kgsl-2d1.1", &gfx2d1_fs_data),
+};
+unsigned msm8660_num_footswitch __initdata = ARRAY_SIZE(msm8660_footswitch);
struct msm_rpm_platform_data msm8660_rpm_data __initdata = {
.reg_base_addrs = {
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index f7f0611..31142c1 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -264,13 +264,20 @@
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_tx;
+extern struct platform_device apq_cpudai_slimbus_3_rx;
extern struct platform_device apq_cpudai_slim_4_rx;
extern struct platform_device apq_cpudai_slim_4_tx;
extern struct platform_device *msm_footswitch_devices[];
extern unsigned msm_num_footswitch_devices;
-extern struct platform_device *apq8064_fs_devices[];
-extern unsigned apq8064_num_fs_devices;
+extern struct platform_device *msm8660_footswitch[];
+extern unsigned msm8660_num_footswitch;
+extern struct platform_device *msm8960_footswitch[];
+extern unsigned msm8960_num_footswitch;
+extern struct platform_device *apq8064_footswitch[];
+extern unsigned apq8064_num_footswitch;
+extern struct platform_device *msm8930_footswitch[];
+extern unsigned msm8930_num_footswitch;
extern struct platform_device fsm_qfp_fuse_device;
@@ -383,3 +390,5 @@
extern struct platform_device msm8960_rtb_device;
extern struct platform_device msm8930_rtb_device;
extern struct platform_device apq8064_rtb_device;
+
+extern struct platform_device msm8960_cache_dump_device;
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index 4f34443..d433b9e 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -59,19 +59,20 @@
int channel_active;
int sd;
size_t sd_size;
+ struct list_head staged_commands[MSM_DMOV_CHANNEL_COUNT];
struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
- spinlock_t lock;
+ struct mutex lock;
+ spinlock_t list_lock;
unsigned int irq;
struct clk *clk;
struct clk *pclk;
struct clk *ebiclk;
unsigned int clk_ctl;
- struct timer_list timer;
+ struct delayed_work work;
};
-static void msm_dmov_clock_timer(unsigned long);
-static int msm_dmov_clk_toggle(int, int);
+static void msm_dmov_clock_work(struct work_struct *);
#ifdef CONFIG_ARCH_MSM8X60
@@ -163,15 +164,19 @@
{
.crci_conf = adm0_crci_conf,
.chan_conf = adm0_chan_conf,
- .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+ .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
+ .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
.clk_ctl = CLK_DIS,
- .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
+ .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
+ msm_dmov_clock_work),
}, {
.crci_conf = adm1_crci_conf,
.chan_conf = adm1_chan_conf,
- .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+ .lock = __MUTEX_INITIALIZER(dmov_conf[1].lock),
+ .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
.clk_ctl = CLK_DIS,
- .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 1),
+ .work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work,
+ msm_dmov_clock_work),
}
};
#else
@@ -179,9 +184,11 @@
{
.crci_conf = NULL,
.chan_conf = NULL,
- .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
+ .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
+ .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
.clk_ctl = CLK_DIS,
- .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
+ .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
+ msm_dmov_clock_work),
}
};
#endif
@@ -223,103 +230,153 @@
#define PRINT_FLOW(format, args...) \
MSM_DMOV_DPRINTF(MSM_DMOV_PRINT_FLOW, format, args);
-static int msm_dmov_clk_toggle(int adm, int on)
+static int msm_dmov_clk_on(int adm)
{
- int ret = 0;
+ int ret;
- if (on) {
- ret = clk_enable(dmov_conf[adm].clk);
- if (ret)
- goto err;
- if (dmov_conf[adm].pclk) {
- ret = clk_enable(dmov_conf[adm].pclk);
- if (ret) {
- clk_disable(dmov_conf[adm].clk);
- goto err;
- }
+ ret = clk_prepare_enable(dmov_conf[adm].clk);
+ if (ret)
+ return ret;
+ if (dmov_conf[adm].pclk) {
+ ret = clk_prepare_enable(dmov_conf[adm].pclk);
+ if (ret) {
+ clk_disable_unprepare(dmov_conf[adm].clk);
+ return ret;
}
- if (dmov_conf[adm].ebiclk) {
- ret = clk_enable(dmov_conf[adm].ebiclk);
- if (ret) {
- if (dmov_conf[adm].pclk)
- clk_disable(dmov_conf[adm].pclk);
- clk_disable(dmov_conf[adm].clk);
- }
- }
- } else {
- clk_disable(dmov_conf[adm].clk);
- if (dmov_conf[adm].pclk)
- clk_disable(dmov_conf[adm].pclk);
- if (dmov_conf[adm].ebiclk)
- clk_disable(dmov_conf[adm].ebiclk);
}
-err:
+ if (dmov_conf[adm].ebiclk) {
+ ret = clk_prepare_enable(dmov_conf[adm].ebiclk);
+ if (ret) {
+ if (dmov_conf[adm].pclk)
+ clk_disable_unprepare(dmov_conf[adm].pclk);
+ clk_disable_unprepare(dmov_conf[adm].clk);
+ }
+ }
return ret;
}
-static void msm_dmov_clock_timer(unsigned long adm)
+static void msm_dmov_clk_off(int adm)
{
- unsigned long irq_flags;
- spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
- if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
- BUG_ON(dmov_conf[adm].channel_active);
- msm_dmov_clk_toggle(adm, 0);
- dmov_conf[adm].clk_ctl = CLK_DIS;
+ clk_disable_unprepare(dmov_conf[adm].clk);
+ if (dmov_conf[adm].pclk)
+ clk_disable_unprepare(dmov_conf[adm].pclk);
+ if (dmov_conf[adm].ebiclk)
+ clk_disable_unprepare(dmov_conf[adm].ebiclk);
+}
+
+static void msm_dmov_clock_work(struct work_struct *work)
+{
+ struct msm_dmov_conf *conf =
+ container_of(to_delayed_work(work), struct msm_dmov_conf, work);
+ int adm = DMOV_IRQ_TO_ADM(conf->irq);
+ mutex_lock(&conf->lock);
+ if (conf->clk_ctl == CLK_TO_BE_DIS) {
+ BUG_ON(conf->channel_active);
+ msm_dmov_clk_off(adm);
+ conf->clk_ctl = CLK_DIS;
}
- spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+ mutex_unlock(&conf->lock);
}
-void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful)
-{
- int adm = DMOV_ID_TO_ADM(id);
- int ch = DMOV_ID_TO_CHAN(id);
- writel_relaxed((graceful << 31), DMOV_REG(DMOV_FLUSH0(ch), adm));
- wmb();
-}
-EXPORT_SYMBOL(msm_dmov_stop_cmd);
+enum {
+ NOFLUSH = 0,
+ GRACEFUL,
+ NONGRACEFUL,
+};
-void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
+/* Caller must hold the list lock */
+static struct msm_dmov_cmd *start_ready_cmd(unsigned ch, int adm)
{
- unsigned long irq_flags;
- unsigned int status;
+ struct msm_dmov_cmd *cmd;
+
+ if (list_empty(&dmov_conf[adm].ready_commands[ch]))
+ return NULL;
+
+ cmd = list_entry(dmov_conf[adm].ready_commands[ch].next, typeof(*cmd),
+ list);
+ list_del(&cmd->list);
+ if (cmd->exec_func)
+ cmd->exec_func(cmd);
+ list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
+ if (!dmov_conf[adm].channel_active)
+ enable_irq(dmov_conf[adm].irq);
+ dmov_conf[adm].channel_active |= BIT(ch);
+ PRINT_IO("msm dmov enqueue command, %x, ch %d\n", cmd->cmdptr, ch);
+ writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
+
+ return cmd;
+}
+
+static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work)
+{
+ struct msm_dmov_cmd *cmd =
+ container_of(work, struct msm_dmov_cmd, work);
+ unsigned id = cmd->id;
+ unsigned status;
+ unsigned long flags;
int adm = DMOV_ID_TO_ADM(id);
int ch = DMOV_ID_TO_CHAN(id);
- spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+ mutex_lock(&dmov_conf[adm].lock);
if (dmov_conf[adm].clk_ctl == CLK_DIS) {
- status = msm_dmov_clk_toggle(adm, 1);
+ status = msm_dmov_clk_on(adm);
if (status != 0)
goto error;
} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
- del_timer(&dmov_conf[adm].timer);
+ cancel_delayed_work_sync(&dmov_conf[adm].work);
dmov_conf[adm].clk_ctl = CLK_EN;
+ spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
+
+ cmd = list_entry(dmov_conf[adm].staged_commands[ch].next, typeof(*cmd),
+ list);
+ list_del(&cmd->list);
+ list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
if (status & DMOV_STATUS_CMD_PTR_RDY) {
PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
id, status);
- if (cmd->exec_func)
- cmd->exec_func(cmd);
- list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
- if (!dmov_conf[adm].channel_active)
- enable_irq(dmov_conf[adm].irq);
- dmov_conf[adm].channel_active |= 1U << ch;
- PRINT_IO("Writing %x exactly to register", cmd->cmdptr);
- writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
- } else {
- if (!dmov_conf[adm].channel_active) {
- dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+ cmd = start_ready_cmd(ch, adm);
+ /*
+ * We added something to the ready list, and still hold the
+ * list lock. Thus, no need to check for cmd == NULL
+ */
+ if (cmd->toflush) {
+ int flush = (cmd->toflush == GRACEFUL) ? 1 << 31 : 0;
+ writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
}
- if (list_empty(&dmov_conf[adm].active_commands[ch]))
+ } else {
+ cmd->toflush = 0;
+ if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
+ !list_empty(&dmov_conf[adm].ready_commands[ch]))
PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
"status %x\n", id, status);
PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
"%x\n", id, status);
- list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
}
+ if (!dmov_conf[adm].channel_active) {
+ dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+ schedule_delayed_work(&dmov_conf[adm].work, HZ);
+ }
+ spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
error:
- spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+ mutex_unlock(&dmov_conf[adm].lock);
+}
+
+void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
+{
+ int adm = DMOV_ID_TO_ADM(id);
+ int ch = DMOV_ID_TO_CHAN(id);
+ unsigned long flags;
+ cmd->id = id;
+ cmd->toflush = 0;
+ INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work);
+
+ spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
+ list_add_tail(&cmd->list, &dmov_conf[adm].staged_commands[ch]);
+ spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
+
+ schedule_work(&cmd->work);
}
EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
@@ -332,19 +389,24 @@
}
EXPORT_SYMBOL(msm_dmov_enqueue_cmd);
-void msm_dmov_flush(unsigned int id)
+void msm_dmov_flush(unsigned int id, int graceful)
{
unsigned long irq_flags;
int ch = DMOV_ID_TO_CHAN(id);
int adm = DMOV_ID_TO_ADM(id);
- spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+ int flush = graceful ? DMOV_FLUSH_TYPE : 0;
+ struct msm_dmov_cmd *cmd;
+
+ spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
/* XXX not checking if flush cmd sent already */
if (!list_empty(&dmov_conf[adm].active_commands[ch])) {
PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
- writel_relaxed(DMOV_FLUSH_TYPE, DMOV_REG(DMOV_FLUSH0(ch), adm));
+ writel_relaxed(flush, DMOV_REG(DMOV_FLUSH0(ch), adm));
}
+ list_for_each_entry(cmd, &dmov_conf[adm].staged_commands[ch], list)
+ cmd->toflush = graceful ? GRACEFUL : NONGRACEFUL;
/* spin_unlock_irqrestore has the necessary barrier */
- spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+ spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
}
EXPORT_SYMBOL(msm_dmov_flush);
@@ -406,7 +468,7 @@
errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm));
}
-static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
+static irqreturn_t msm_dmov_isr(int irq, void *dev_id)
{
unsigned int int_status;
unsigned int mask;
@@ -419,11 +481,12 @@
struct msm_dmov_cmd *cmd;
int adm = DMOV_IRQ_TO_ADM(irq);
- spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+ mutex_lock(&dmov_conf[adm].lock);
/* read and clear isr */
int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm));
PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
+ spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
while (int_status) {
mask = int_status & -int_status;
ch = fls(mask) - 1;
@@ -491,50 +554,38 @@
ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch),
adm));
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
- if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) &&
- !list_empty(&dmov_conf[adm].ready_commands[ch])) {
- cmd = list_entry(dmov_conf[adm].
- ready_commands[ch].next, typeof(*cmd),
- list);
- list_del(&cmd->list);
- if (cmd->exec_func)
- cmd->exec_func(cmd);
- list_add_tail(&cmd->list,
- &dmov_conf[adm].active_commands[ch]);
- PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
- writel_relaxed(cmd->cmdptr,
- DMOV_REG(DMOV_CMD_PTR(ch), adm));
- }
+ if (ch_status & DMOV_STATUS_CMD_PTR_RDY)
+ start_ready_cmd(ch, adm);
} while (ch_status & DMOV_STATUS_RSLT_VALID);
if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
- list_empty(&dmov_conf[adm].ready_commands[ch]))
+ list_empty(&dmov_conf[adm].ready_commands[ch]))
dmov_conf[adm].channel_active &= ~(1U << ch);
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
}
+ spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
if (!dmov_conf[adm].channel_active && valid) {
disable_irq_nosync(dmov_conf[adm].irq);
dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+ schedule_delayed_work(&dmov_conf[adm].work, HZ);
}
- spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+ mutex_unlock(&dmov_conf[adm].lock);
return valid ? IRQ_HANDLED : IRQ_NONE;
}
static int msm_dmov_suspend_late(struct device *dev)
{
- unsigned long irq_flags;
struct platform_device *pdev = to_platform_device(dev);
int adm = (pdev->id >= 0) ? pdev->id : 0;
- spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+ mutex_lock(&dmov_conf[adm].lock);
if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
BUG_ON(dmov_conf[adm].channel_active);
- del_timer(&dmov_conf[adm].timer);
- msm_dmov_clk_toggle(adm, 0);
+ cancel_delayed_work_sync(&dmov_conf[adm].work);
+ msm_dmov_clk_off(adm);
dmov_conf[adm].clk_ctl = CLK_DIS;
}
- spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
+ mutex_unlock(&dmov_conf[adm].lock);
return 0;
}
@@ -649,8 +700,8 @@
if (!dmov_conf[adm].base)
return -ENOMEM;
- ret = request_irq(dmov_conf[adm].irq, msm_datamover_irq_handler,
- 0, "msmdatamover", NULL);
+ ret = request_threaded_irq(dmov_conf[adm].irq, NULL, msm_dmov_isr,
+ IRQF_ONESHOT, "msmdatamover", NULL);
if (ret) {
PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm,
dmov_conf[adm].irq);
@@ -662,7 +713,7 @@
PRINT_ERROR("Requesting ADM%d clocks failed\n", adm);
goto out_irq;
}
- ret = msm_dmov_clk_toggle(adm, 1);
+ ret = msm_dmov_clk_on(adm);
if (ret) {
PRINT_ERROR("Enabling ADM%d clocks failed\n", adm);
goto out_irq;
@@ -670,6 +721,7 @@
config_datamover(adm);
for (i = 0; i < MSM_DMOV_CHANNEL_COUNT; i++) {
+ INIT_LIST_HEAD(&dmov_conf[adm].staged_commands[i]);
INIT_LIST_HEAD(&dmov_conf[adm].ready_commands[i]);
INIT_LIST_HEAD(&dmov_conf[adm].active_commands[i]);
@@ -678,7 +730,7 @@
DMOV_REG(DMOV_RSLT_CONF(i), adm));
}
wmb();
- msm_dmov_clk_toggle(adm, 0);
+ msm_dmov_clk_off(adm);
return ret;
out_irq:
free_irq(dmov_conf[adm].irq, NULL);
diff --git a/arch/arm/mach-msm/footswitch-8x60.c b/arch/arm/mach-msm/footswitch-8x60.c
index eb334b9..72361a6 100644
--- a/arch/arm/mach-msm/footswitch-8x60.c
+++ b/arch/arm/mach-msm/footswitch-8x60.c
@@ -21,10 +21,8 @@
#include <linux/regulator/machine.h>
#include <linux/clk.h>
#include <mach/msm_iomap.h>
-#include <mach/msm_bus_board.h>
#include <mach/msm_bus.h>
#include <mach/scm-io.h>
-#include <mach/socinfo.h>
#include "clock.h"
#include "footswitch.h"
@@ -51,6 +49,8 @@
#define ENABLE_BIT BIT(8)
#define RETENTION_BIT BIT(9)
+#define GFS_DELAY_CNT 31
+
#define RESET_DELAY_US 1
/* Clock rate to use if one has not previously been set. */
#define DEFAULT_RATE 27000000
@@ -62,14 +62,6 @@
*/
static DEFINE_MUTEX(claim_lock);
-struct clk_data {
- const char *name;
- struct clk *clk;
- unsigned long rate;
- unsigned long reset_rate;
- bool enabled;
-};
-
struct footswitch {
struct regulator_dev *rdev;
struct regulator_desc desc;
@@ -77,15 +69,14 @@
int bus_port0, bus_port1;
bool is_enabled;
bool is_claimed;
- struct clk_data *clk_data;
+ struct fs_clk_data *clk_data;
struct clk *core_clk;
- unsigned int gfs_delay_cnt:5;
};
static int setup_clocks(struct footswitch *fs)
{
int rc = 0;
- struct clk_data *clock;
+ struct fs_clk_data *clock;
long rate;
/*
@@ -124,7 +115,7 @@
static void restore_clocks(struct footswitch *fs)
{
- struct clk_data *clock;
+ struct fs_clk_data *clock;
/* Restore clocks to their orignal states before setup_clocks(). */
for (clock = fs->clk_data; clock->clk; clock++) {
@@ -146,7 +137,7 @@
static int footswitch_enable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
- struct clk_data *clock;
+ struct fs_clk_data *clock;
uint32_t regval, rc = 0;
mutex_lock(&claim_lock);
@@ -232,7 +223,7 @@
static int footswitch_disable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
- struct clk_data *clock;
+ struct fs_clk_data *clock;
uint32_t regval, rc = 0;
/* Return early if already disabled. */
@@ -308,7 +299,7 @@
static int gfx2d_footswitch_enable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
- struct clk_data *clock;
+ struct fs_clk_data *clock;
uint32_t regval, rc = 0;
mutex_lock(&claim_lock);
@@ -384,7 +375,7 @@
static int gfx2d_footswitch_disable(struct regulator_dev *rdev)
{
struct footswitch *fs = rdev_get_drvdata(rdev);
- struct clk_data *clock;
+ struct fs_clk_data *clock;
uint32_t regval, rc = 0;
/* Return early if already disabled. */
@@ -461,108 +452,7 @@
.disable = gfx2d_footswitch_disable,
};
-/*
- * Lists of required clocks for the collapse and restore sequences.
- *
- * Order matters here. Clocks are listed in the same order as their
- * resets will be de-asserted when the core is restored. Also, rate-
- * settable clocks must be listed before any of the branches that
- * are derived from them. Otherwise, the branches may fail to enable
- * if their parent's rate is not yet set.
- */
-
-static struct clk_data gfx2d0_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { 0 }
-};
-
-static struct clk_data gfx2d1_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { 0 }
-};
-
-static struct clk_data gfx3d_8660_clks[] = {
- { .name = "core_clk", .reset_rate = 27000000 },
- { .name = "iface_clk" },
- { 0 }
-};
-
-static struct clk_data gfx3d_8064_clks[] = {
- { .name = "core_clk", .reset_rate = 27000000 },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { 0 }
-};
-
-static struct clk_data ijpeg_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { 0 }
-};
-
-static struct clk_data mdp_8960_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { .name = "vsync_clk" },
- { .name = "lut_clk" },
- { .name = "tv_src_clk" },
- { .name = "tv_clk" },
- { 0 }
-};
-
-static struct clk_data mdp_8660_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { .name = "vsync_clk" },
- { .name = "tv_src_clk" },
- { .name = "tv_clk" },
- { .name = "pixel_mdp_clk" },
- { .name = "pixel_lcdc_clk" },
- { 0 }
-};
-
-static struct clk_data rot_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { 0 }
-};
-
-static struct clk_data ved_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { 0 }
-};
-
-static struct clk_data vfe_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { 0 }
-};
-
-static struct clk_data vpe_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { 0 }
-};
-
-static struct clk_data vcap_clks[] = {
- { .name = "core_clk" },
- { .name = "iface_clk" },
- { .name = "bus_clk" },
- { 0 }
-};
-
-#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg, _dc, _clk_data, \
- _bp1, _bp2) \
+#define FOOTSWITCH(_id, _name, _ops, _gfs_ctl_reg) \
[(_id)] = { \
.desc = { \
.id = (_id), \
@@ -572,51 +462,26 @@
.owner = THIS_MODULE, \
}, \
.gfs_ctl_reg = (_gfs_ctl_reg), \
- .gfs_delay_cnt = (_dc), \
- .clk_data = (_clk_data), \
- .bus_port0 = (_bp1), \
- .bus_port1 = (_bp2), \
}
static struct footswitch footswitches[] = {
- FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops,
- GFX2D0_GFS_CTL_REG, 31, gfx2d0_clks,
- MSM_BUS_MASTER_GRAPHICS_2D_CORE0, 0),
- FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops,
- GFX2D1_GFS_CTL_REG, 31, gfx2d1_clks,
- MSM_BUS_MASTER_GRAPHICS_2D_CORE1, 0),
- FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops,
- GFX3D_GFS_CTL_REG, 31, gfx3d_8660_clks,
- MSM_BUS_MASTER_GRAPHICS_3D, 0),
- FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops,
- GEMINI_GFS_CTL_REG, 31, ijpeg_clks,
- MSM_BUS_MASTER_JPEG_ENC, 0),
- FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops,
- MDP_GFS_CTL_REG, 31, NULL,
- MSM_BUS_MASTER_MDP_PORT0,
- MSM_BUS_MASTER_MDP_PORT1),
- FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops,
- ROT_GFS_CTL_REG, 31, rot_clks,
- MSM_BUS_MASTER_ROTATOR, 0),
- FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops,
- VED_GFS_CTL_REG, 31, ved_clks,
- MSM_BUS_MASTER_HD_CODEC_PORT0,
- MSM_BUS_MASTER_HD_CODEC_PORT1),
- FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops,
- VFE_GFS_CTL_REG, 31, vfe_clks,
- MSM_BUS_MASTER_VFE, 0),
- FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops,
- VPE_GFS_CTL_REG, 31, vpe_clks,
- MSM_BUS_MASTER_VPE, 0),
- FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops,
- VCAP_GFS_CTL_REG, 31, vcap_clks,
- MSM_BUS_MASTER_VIDEO_CAP, 0),
+ FOOTSWITCH(FS_GFX2D0, "fs_gfx2d0", &gfx2d_fs_ops, GFX2D0_GFS_CTL_REG),
+ FOOTSWITCH(FS_GFX2D1, "fs_gfx2d1", &gfx2d_fs_ops, GFX2D1_GFS_CTL_REG),
+ FOOTSWITCH(FS_GFX3D, "fs_gfx3d", &standard_fs_ops, GFX3D_GFS_CTL_REG),
+ FOOTSWITCH(FS_IJPEG, "fs_ijpeg", &standard_fs_ops, GEMINI_GFS_CTL_REG),
+ FOOTSWITCH(FS_MDP, "fs_mdp", &standard_fs_ops, MDP_GFS_CTL_REG),
+ FOOTSWITCH(FS_ROT, "fs_rot", &standard_fs_ops, ROT_GFS_CTL_REG),
+ FOOTSWITCH(FS_VED, "fs_ved", &standard_fs_ops, VED_GFS_CTL_REG),
+ FOOTSWITCH(FS_VFE, "fs_vfe", &standard_fs_ops, VFE_GFS_CTL_REG),
+ FOOTSWITCH(FS_VPE, "fs_vpe", &standard_fs_ops, VPE_GFS_CTL_REG),
+ FOOTSWITCH(FS_VCAP, "fs_vcap", &standard_fs_ops, VCAP_GFS_CTL_REG),
};
static int footswitch_probe(struct platform_device *pdev)
{
struct footswitch *fs;
struct regulator_init_data *init_data;
- struct clk_data *clock;
+ struct fs_driver_data *driver_data;
+ struct fs_clk_data *clock;
uint32_t regval, rc = 0;
if (pdev == NULL)
@@ -625,29 +490,12 @@
if (pdev->id >= MAX_FS)
return -ENODEV;
- fs = &footswitches[pdev->id];
init_data = pdev->dev.platform_data;
-
- if (pdev->id == FS_MDP) {
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064())
- fs->clk_data = mdp_8960_clks;
- else
- fs->clk_data = mdp_8660_clks;
- } else if (pdev->id == FS_GFX3D) {
- if (cpu_is_apq8064()) {
- fs->clk_data = gfx3d_8064_clks;
- fs->bus_port1 = MSM_BUS_MASTER_GRAPHICS_3D_PORT1;
- } else if (cpu_is_msm8930()) {
- fs->clk_data = gfx3d_8064_clks;
- } else {
- fs->clk_data = gfx3d_8660_clks;
- }
- } else if (pdev->id == FS_VED) {
- if (cpu_is_apq8064()) {
- fs->bus_port0 = MSM_BUS_MASTER_VIDEO_ENC;
- fs->bus_port1 = MSM_BUS_MASTER_VIDEO_DEC;
- }
- }
+ driver_data = init_data->driver_data;
+ fs = &footswitches[pdev->id];
+ fs->clk_data = driver_data->clks;
+ fs->bus_port0 = driver_data->bus_port0;
+ fs->bus_port1 = driver_data->bus_port1;
for (clock = fs->clk_data; clock->name; clock++) {
clock->clk = clk_get(&pdev->dev, clock->name);
@@ -667,7 +515,7 @@
* clear so disabling the footswitch will power-collapse the core.
*/
regval = readl_relaxed(fs->gfs_ctl_reg);
- regval |= fs->gfs_delay_cnt;
+ regval |= GFS_DELAY_CNT;
regval &= ~RETENTION_BIT;
writel_relaxed(regval, fs->gfs_ctl_reg);
@@ -692,7 +540,7 @@
static int __devexit footswitch_remove(struct platform_device *pdev)
{
struct footswitch *fs = &footswitches[pdev->id];
- struct clk_data *clock;
+ struct fs_clk_data *clock;
for (clock = fs->clk_data; clock->clk; clock++)
clk_put(clock->clk);
diff --git a/arch/arm/mach-msm/footswitch.h b/arch/arm/mach-msm/footswitch.h
index 4882ff0..1809b2e 100644
--- a/arch/arm/mach-msm/footswitch.h
+++ b/arch/arm/mach-msm/footswitch.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
@@ -30,7 +30,21 @@
#define FS_VCAP 10
#define MAX_FS 11
-#define FS_GENERIC(_drv_name, _id, _name) (&(struct platform_device){ \
+struct fs_clk_data {
+ const char *name;
+ struct clk *clk;
+ unsigned long rate;
+ unsigned long reset_rate;
+ bool enabled;
+};
+
+struct fs_driver_data {
+ int bus_port0, bus_port1;
+ struct fs_clk_data *clks;
+};
+
+#define FS_GENERIC(_drv_name, _id, _name, _dev_id, _data) \
+(&(struct platform_device){ \
.name = (_drv_name), \
.id = (_id), \
.dev = { \
@@ -42,11 +56,14 @@
.num_consumer_supplies = 1, \
.consumer_supplies = \
&(struct regulator_consumer_supply) \
- REGULATOR_SUPPLY((_name), NULL), \
+ REGULATOR_SUPPLY((_name), (_dev_id)), \
+ .driver_data = (_data), \
} \
}, \
})
-#define FS_PCOM(_id, _name) FS_GENERIC("footswitch-pcom", (_id), (_name))
-#define FS_8X60(_id, _name) FS_GENERIC("footswitch-8x60", (_id), (_name))
+#define FS_PCOM(_id, _name, _dev_id) \
+ FS_GENERIC("footswitch-pcom", _id, _name, _dev_id, NULL)
+#define FS_8X60(_id, _name, _dev_id, _data) \
+ FS_GENERIC("footswitch-8x60", _id, _name, _dev_id, _data)
#endif
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index 0028286..b73ddc8 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -44,6 +44,15 @@
skip\@:
.endm
+/* Add NOPs for 8x25 target */
+.macro DELAY_8x25, rept
+#ifdef CONFIG_ARCH_MSM8625
+ .rept \rept
+ nop
+ .endr
+#endif
+.endm
+
ENTRY(msm_arch_idle)
wfi
#ifdef CONFIG_ARCH_MSM8X60
@@ -130,6 +139,7 @@
SET_SMP_COHERENCY OFF
wfi
+ DELAY_8x25 300
mcr p15, 0, r4, c1, c0, 0 /* restore d/i cache */
isb
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index d6476f7..644746e 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -261,6 +261,11 @@
int vcm_enable;
};
+struct msm_eeprom_info {
+ struct i2c_board_info const *board_info;
+ int bus_id;
+};
+
struct msm_camera_sensor_info {
const char *sensor_name;
int sensor_reset_enable;
@@ -283,6 +288,7 @@
enum msm_sensor_type sensor_type;
struct msm_actuator_info *actuator_info;
int pmic_gpio_enable;
+ struct msm_eeprom_info *eeprom_info;
};
struct msm_camera_board_info {
@@ -375,6 +381,7 @@
spinlock_t bl_spinlock;
int (*backlight_level)(int level, int max, int min);
int (*pmic_backlight)(int level);
+ int (*rotate_panel)(void);
int (*panel_num)(void);
void (*panel_config_gpio)(int);
int (*vga_switch)(int select_vga);
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 339a955..ba621e6 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -35,7 +35,10 @@
unsigned int result,
struct msm_dmov_errdata *err);
void (*exec_func)(struct msm_dmov_cmd *cmd);
+ struct work_struct work;
+ unsigned id; /* For internal use */
void *user; /* Pointer for caller's reference */
+ u8 toflush;
};
struct msm_dmov_pdata {
@@ -45,8 +48,7 @@
void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd);
-void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful);
-void msm_dmov_flush(unsigned int id);
+void msm_dmov_flush(unsigned int id, int graceful);
int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
#define DMOV_CRCIS_PER_CONF 10
diff --git a/arch/arm/mach-msm/include/mach/hardware.h b/arch/arm/mach-msm/include/mach/hardware.h
index 2d12609..f1095af 100644
--- a/arch/arm/mach-msm/include/mach/hardware.h
+++ b/arch/arm/mach-msm/include/mach/hardware.h
@@ -1,6 +1,7 @@
/* arch/arm/mach-msm/include/mach/hardware.h
*
* Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 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
@@ -14,5 +15,10 @@
*/
#ifndef __ASM_ARCH_MSM_HARDWARE_H
+#define __ASM_ARCH_MSM_HARDWARE_H
+
+#define PCIBIOS_MIN_IO 0x10000000
+#define PCIBIOS_MIN_MEM 0x10000000
+#define pcibios_assign_all_busses() 1
#endif
diff --git a/arch/arm/mach-msm/include/mach/iommu_domains.h b/arch/arm/mach-msm/include/mach/iommu_domains.h
index 52e70ec..dfb100c 100644
--- a/arch/arm/mach-msm/include/mach/iommu_domains.h
+++ b/arch/arm/mach-msm/include/mach/iommu_domains.h
@@ -75,8 +75,28 @@
extern int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
unsigned long size,
+ unsigned long page_size,
int cached);
+extern void msm_iommu_unmap_extra(struct iommu_domain *domain,
+ unsigned long start_iova,
+ unsigned long size,
+ unsigned long page_size);
+
+extern int msm_iommu_map_contig_buffer(unsigned long phys,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size,
+ unsigned long align,
+ unsigned long cached,
+ unsigned long *iova_val);
+
+
+extern void msm_iommu_unmap_contig_buffer(unsigned long iova,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size);
+
#else
static inline struct iommu_domain
*msm_get_iommu_domain(int subsys_id) { return NULL; }
@@ -101,10 +121,38 @@
static inline int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
unsigned long size,
+ unsigned long page_size,
int cached)
{
return -ENODEV;
}
+
+static inline void msm_iommu_unmap_extra(struct iommu_domain *domain,
+ unsigned long start_iova,
+ unsigned long size,
+ unsigned long page_size)
+{
+}
+
+static inline int msm_iommu_map_contig_buffer(unsigned long phys,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size,
+ unsigned long align,
+ unsigned long cached,
+ unsigned long *iova_val)
+{
+ *iova_val = phys;
+ return 0;
+}
+
+static inline void msm_iommu_unmap_contig_buffer(unsigned long iova,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size)
+{
+ return;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-9625.h b/arch/arm/mach-msm/include/mach/irqs-9625.h
new file mode 100644
index 0000000..91b4d07
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/irqs-9625.h
@@ -0,0 +1,36 @@
+/* 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 __ASM_ARCH_MSM_IRQS_9625_H
+#define __ASM_ARCH_MSM_IRQS_9625_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/*
+ * 0-15: STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+: SPI (shared peripheral interrupts)
+ */
+
+
+#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
+#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
+#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 16)
+#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 208)
+
+#define NR_MSM_IRQS 288
+#define NR_GPIO_IRQS 88
+#define NR_BOARD_IRQS 0
+#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
+#define NR_MSM_GPIOS NR_GPIO_IRQS
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
index c961804..6d27d69 100644
--- a/arch/arm/mach-msm/include/mach/irqs-copper.h
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.h
@@ -31,7 +31,7 @@
#define APCC_QGICL2PERFMONIRPTREQ (GIC_SPI_START + 1)
#define SC_SICL2PERFMONIRPTREQ APCC_QGICL2PERFMONIRPTREQ
-#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 16)
+#define TLMM_MSM_SUMMARY_IRQ (GIC_SPI_START + 208)
#define SPS_BAM_DMA_IRQ (GIC_SPI_START + 105)
#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
diff --git a/arch/arm/mach-msm/include/mach/irqs.h b/arch/arm/mach-msm/include/mach/irqs.h
index ff011a8..bf766f4 100644
--- a/arch/arm/mach-msm/include/mach/irqs.h
+++ b/arch/arm/mach-msm/include/mach/irqs.h
@@ -45,8 +45,14 @@
#define NR_WCD9XXX_IRQS 49
#define NR_TABLA_IRQS NR_WCD9XXX_IRQS
#define NR_GPIO_EXPANDER_IRQS 64
+#ifdef CONFIG_PCI_MSI
+#define NR_PCIE_MSI_IRQS 256
+#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
+ NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS + NR_PCIE_MSI_IRQS)
+#else
#define NR_BOARD_IRQS (NR_PM8921_IRQS + NR_PM8821_IRQS + \
NR_WCD9XXX_IRQS + NR_GPIO_EXPANDER_IRQS)
+#endif
#define NR_TLMM_MSM_DIR_CONN_IRQ 8 /*Need to Verify this Count*/
#define NR_MSM_GPIOS NR_GPIO_IRQS
@@ -56,6 +62,8 @@
#include "irqs-copper.h"
#elif defined(CONFIG_ARCH_MSM9615)
#include "irqs-9615.h"
+#elif defined(CONFIG_ARCH_MSM9625)
+#include "irqs-9625.h"
#elif defined(CONFIG_ARCH_MSM7X30)
#include "irqs-7x30.h"
#elif defined(CONFIG_ARCH_QSD8X50)
@@ -85,4 +93,9 @@
#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
#define MSM_INT_TO_REG(base, irq) (base + irq / 32)
+#if defined(CONFIG_PCI_MSI) && defined(CONFIG_MSM_PCIE)
+#define MSM_PCIE_MSI_INT(n) (NR_MSM_IRQS + NR_GPIO_IRQS + NR_PM8921_IRQS + \
+ NR_PM8821_IRQS + NR_TABLA_IRQS + NR_GPIO_EXPANDER_IRQS + (n))
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9625.h b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
new file mode 100644
index 0000000..493cf36
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9625.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 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.
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_MSM9625_H
+#define __ASM_ARCH_MSM_IOMAP_MSM9625_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * io desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM9625_SHARED_RAM_PHYS 0x18D00000
+
+#define MSM9625_APCS_GCC_PHYS 0xF9011000
+#define MSM9625_APCS_GCC_SIZE SZ_4K
+
+#define MSM9625_TMR_PHYS 0xF9021000
+#define MSM9625_TMR_SIZE SZ_4K
+
+#define MSM9625_TLMM_PHYS 0xFD510000
+#define MSM9625_TLMM_SIZE SZ_16K
+
+#ifdef CONFIG_DEBUG_MSM9625_UART
+#define MSM_DEBUG_UART_BASE IOMEM(0xFA71E000)
+#define MSM_DEBUG_UART_PHYS 0xF991E000
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index 34af610..2676297 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -58,7 +58,8 @@
defined(CONFIG_ARCH_MSM8930) || defined(CONFIG_ARCH_MSM9615) || \
defined(CONFIG_ARCH_MSMCOPPER) || defined(CONFIG_ARCH_MSM7X27) || \
defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X01A) || \
- defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30)
+ defined(CONFIG_ARCH_MSM8625) || defined(CONFIG_ARCH_MSM7X30) || \
+ defined(CONFIG_ARCH_MSM9625)
/* Unified iomap */
@@ -121,6 +122,7 @@
#include "msm_iomap-8064.h"
#include "msm_iomap-9615.h"
#include "msm_iomap-copper.h"
+#include "msm_iomap-9625.h"
#else
/* Legacy single-target iomap */
diff --git a/arch/arm/mach-msm/include/mach/msm_memtypes.h b/arch/arm/mach-msm/include/mach/msm_memtypes.h
index 6f9bed1..7afb38d 100644
--- a/arch/arm/mach-msm/include/mach/msm_memtypes.h
+++ b/arch/arm/mach-msm/include/mach/msm_memtypes.h
@@ -66,5 +66,5 @@
extern struct reserve_info *reserve_info;
-unsigned long __init reserve_memory_for_fmem(unsigned long);
+unsigned long __init reserve_memory_for_fmem(unsigned long, unsigned long);
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_pcie.h b/arch/arm/mach-msm/include/mach/msm_pcie.h
new file mode 100644
index 0000000..008c984
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_pcie.h
@@ -0,0 +1,37 @@
+/* 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 __ASM_ARCH_MSM_PCIE_H
+#define __ASM_ARCH_MSM_PCIE_H
+
+#include <linux/types.h>
+
+/* gpios */
+enum msm_pcie_gpio {
+ MSM_PCIE_GPIO_RST_N,
+ MSM_PCIE_GPIO_PWR_EN,
+ MSM_PCIE_MAX_GPIO
+};
+
+/* gpio info structrue */
+struct msm_pcie_gpio_info_t {
+ char *name;
+ uint32_t num;
+ uint32_t on;
+};
+
+/* msm pcie platfrom data */
+struct msm_pcie_platform {
+ struct msm_pcie_gpio_info_t *gpio;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 2966509..dc633fb 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -295,6 +295,14 @@
* -EINVAL - NULL parameter or non-packet based channel provided
*/
int smd_is_pkt_avail(smd_channel_t *ch);
+
+/*
+ * SMD initialization function that registers for a SMD platform driver.
+ *
+ * returns success on successful driver registration.
+ */
+int __init msm_smd_init(void);
+
#else
static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
@@ -411,6 +419,11 @@
{
return -ENODEV;
}
+
+static inline int __init msm_smd_init(void)
+{
+ return 0;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/msm_smsm.h b/arch/arm/mach-msm/include/mach/msm_smsm.h
index 5c3307e..5b15340 100644
--- a/arch/arm/mach-msm/include/mach/msm_smsm.h
+++ b/arch/arm/mach-msm/include/mach/msm_smsm.h
@@ -94,6 +94,7 @@
#define SMSM_WLAN_TX_RINGS_EMPTY 0x00000200
#define SMSM_WLAN_TX_ENABLE 0x00000400
+#define SMSM_ERR_SRV_READY 0x00008000
void *smem_alloc(unsigned id, unsigned size);
void *smem_alloc2(unsigned id, unsigned size_in);
diff --git a/arch/arm/mach-msm/include/mach/ocmem.h b/arch/arm/mach-msm/include/mach/ocmem.h
new file mode 100644
index 0000000..bf7c338
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem.h
@@ -0,0 +1,109 @@
+/* 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_OCMEM_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_H
+
+#include <asm/page.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+
+#define OCMEM_MIN_ALLOC SZ_64K
+#define OCMEM_MIN_ALIGN SZ_64K
+
+/* Maximum number of slots in DM */
+#define OCMEM_MAX_CHUNKS 32
+#define MIN_CHUNK_SIZE (SZ_1K/8)
+
+struct ocmem_buf {
+ unsigned long addr;
+ unsigned long len;
+};
+
+struct ocmem_buf_attr {
+ unsigned long paddr;
+ unsigned long len;
+};
+
+struct ocmem_chunk {
+ bool ro;
+ unsigned long ddr_paddr;
+ unsigned long size;
+};
+
+struct ocmem_map_list {
+ int num_chunks;
+ struct ocmem_chunk chunks[OCMEM_MAX_CHUNKS];
+};
+
+/* List of clients that allocate/interact with OCMEM */
+/* Must be in sync with client_names */
+enum ocmem_client {
+ /* GMEM clients */
+ OCMEM_GRAPHICS = 0x0,
+ /* TCMEM clients */
+ OCMEM_VIDEO,
+ OCMEM_CAMERA,
+ /* Dummy Clients */
+ OCMEM_HP_AUDIO,
+ OCMEM_VOICE,
+ /* IMEM Clients */
+ OCMEM_LP_AUDIO,
+ OCMEM_SENSORS,
+ OCMEM_BLAST,
+ OCMEM_CLIENT_MAX,
+};
+
+/**
+ * List of OCMEM notification events which will be broadcasted
+ * to clients that optionally register for these notifications
+ * on a per allocation basis.
+ **/
+enum ocmem_notif_type {
+ OCMEM_MAP_DONE = 1,
+ OCMEM_MAP_FAIL,
+ OCMEM_UNMAP_DONE,
+ OCMEM_UNMAP_FAIL,
+ OCMEM_ALLOC_GROW,
+ OCMEM_ALLOC_SHRINK,
+ OCMEM_NOTIF_TYPE_COUNT,
+};
+
+/* APIS */
+/* Notification APIs */
+void *ocmem_notifier_register(int client_id, struct notifier_block *nb);
+
+int ocmem_notifier_unregister(void *notif_hndl, struct notifier_block *nb);
+
+/* Allocation APIs */
+struct ocmem_buf *ocmem_allocate(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,
+ unsigned long goal, unsigned long step);
+
+/* Free APIs */
+int ocmem_free(int client_id, struct ocmem_buf *buf);
+
+/* Dynamic Resize APIs */
+int ocmem_shrink(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size);
+
+int ocmem_expand(int client_id, struct ocmem_buf *buf,
+ unsigned long new_size);
+
+/* Priority Enforcement APIs */
+int ocmem_evict(int client_id);
+
+int ocmem_restore(int client_id);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/ocmem_priv.h b/arch/arm/mach-msm/include/mach/ocmem_priv.h
new file mode 100644
index 0000000..32d46b4
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/ocmem_priv.h
@@ -0,0 +1,77 @@
+/* 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_OCMEM_CORE_H
+#define _ARCH_ARM_MACH_MSM_OCMEM_CORE_H
+
+/** All interfaces in this header should only be used by OCMEM driver
+ * Client drivers should use wrappers available in ocmem.h
+ **/
+
+#include "ocmem.h"
+#include <mach/msm_iomap.h>
+#include <asm/io.h>
+
+#define OCMEM_PHYS_BASE 0xFEC00000
+#define OCMEM_PHYS_SIZE 0x180000
+
+struct ocmem_zone;
+
+struct ocmem_zone_ops {
+ unsigned long (*allocate) (struct ocmem_zone *, unsigned long);
+ int (*free) (struct ocmem_zone *, unsigned long, unsigned long);
+};
+
+struct ocmem_zone {
+ int owner;
+ int active_regions;
+ int max_regions;
+ struct list_head region_list;
+ unsigned long z_start;
+ unsigned long z_end;
+ unsigned long z_head;
+ unsigned long z_tail;
+ unsigned long z_free;
+ struct gen_pool *z_pool;
+ struct ocmem_zone_ops *z_ops;
+};
+
+struct ocmem_req {
+ struct rw_semaphore rw_sem;
+ /* Chain in sched queue */
+ struct list_head sched_list;
+ /* Chain in zone list */
+ struct list_head zone_list;
+ int owner;
+ int prio;
+ uint32_t req_id;
+ unsigned long req_min;
+ unsigned long req_max;
+ unsigned long req_step;
+ /* reverse pointers */
+ struct ocmem_zone *zone;
+ struct ocmem_buf *buffer;
+ unsigned long state;
+ /* Request assignments */
+ unsigned long req_start;
+ unsigned long req_end;
+ unsigned long req_sz;
+};
+
+struct ocmem_handle {
+ struct ocmem_buf buffer;
+ struct mutex handle_mutex;
+ struct ocmem_req *req;
+};
+
+struct ocmem_zone *get_zone(unsigned);
+#endif
diff --git a/arch/arm/mach-msm/include/mach/qdss.h b/arch/arm/mach-msm/include/mach/qdss.h
index 3b236b8..05d8577 100644
--- a/arch/arm/mach-msm/include/mach/qdss.h
+++ b/arch/arm/mach-msm/include/mach/qdss.h
@@ -30,6 +30,7 @@
extern void qdss_put(struct qdss_source *src);
extern int qdss_enable(struct qdss_source *src);
extern void qdss_disable(struct qdss_source *src);
+extern void qdss_disable_sink(void);
extern int qdss_clk_enable(void);
extern void qdss_clk_disable(void);
#else
@@ -37,6 +38,7 @@
static inline void qdss_put(struct qdss_source *src) {}
static inline int qdss_enable(struct qdss_source *src) { return -ENOSYS; }
static inline void qdss_disable(struct qdss_source *src) {}
+static inline void qdss_disable_sink(void) {}
static inline int qdss_clk_enable(void) { return -ENOSYS; }
static inline void qdss_clk_disable(void) {}
#endif
diff --git a/arch/arm/mach-msm/include/mach/socinfo.h b/arch/arm/mach-msm/include/mach/socinfo.h
index ae0ea0c..c0ad65b 100644
--- a/arch/arm/mach-msm/include/mach/socinfo.h
+++ b/arch/arm/mach-msm/include/mach/socinfo.h
@@ -40,11 +40,17 @@
of_machine_is_compatible("qcom,msmcopper-sim")
#define machine_is_copper_rumi() \
of_machine_is_compatible("qcom,msmcopper-rumi")
+#define early_machine_is_msm9625() \
+ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm9625")
+#define machine_is_msm9625() \
+ of_machine_is_compatible("qcom,msm9625")
#else
#define early_machine_is_copper() 0
#define machine_is_copper() 0
#define machine_is_copper_sim() 0
#define machine_is_copper_rumi() 0
+#define early_machine_is_msm9625() 0
+#define machine_is_msm9625() 0
#endif
#define PLATFORM_SUBTYPE_SGLTE 6
@@ -64,6 +70,7 @@
FSM_CPU_9XXX,
MSM_CPU_7X25A,
MSM_CPU_7X25AA,
+ MSM_CPU_7X25AB,
MSM_CPU_8064,
MSM_CPU_8930,
MSM_CPU_7X27AA,
@@ -71,6 +78,7 @@
MSM_CPU_COPPER,
MSM_CPU_8627,
MSM_CPU_8625,
+ MSM_CPU_9625
};
enum msm_cpu socinfo_get_msm_cpu(void);
@@ -170,6 +178,18 @@
#endif
}
+static inline int cpu_is_msm7x25ab(void)
+{
+#ifdef CONFIG_ARCH_MSM7X27A
+ enum msm_cpu cpu = socinfo_get_msm_cpu();
+
+ BUG_ON(cpu == MSM_CPU_UNKNOWN);
+ return cpu == MSM_CPU_7X25AB;
+#else
+ return 0;
+#endif
+}
+
static inline int cpu_is_msm7x30(void)
{
#ifdef CONFIG_ARCH_MSM7X30
diff --git a/arch/arm/mach-msm/include/mach/sps.h b/arch/arm/mach-msm/include/mach/sps.h
index 852c8db..319a3ec 100644
--- a/arch/arm/mach-msm/include/mach/sps.h
+++ b/arch/arm/mach-msm/include/mach/sps.h
@@ -240,6 +240,12 @@
/* SPS_TIMER_MODE_PERIODIC, Not supported by hardware yet */
};
+/* This enum indicates the cases when callback the user of BAM */
+enum sps_callback_case {
+ SPS_CALLBACK_BAM_ERROR_IRQ = 1, /* BAM ERROR IRQ */
+ SPS_CALLBACK_BAM_HRESP_ERR_IRQ, /* Erroneous HResponse */
+};
+
/*
* This enum indicates the command type in a command element
*/
@@ -317,6 +323,9 @@
* @periph_virt_addr - Peripheral base virtual address.
* @periph_virt_size - Size for virtual mapping.
*
+ * @callback - callback function for BAM user.
+ * @user - pointer to user data.
+ *
* @event_threshold - Pipe event threshold.
* @desc_size - Size (bytes) of descriptor FIFO.
* @data_size - Size (bytes) of data FIFO.
@@ -369,6 +378,10 @@
u32 desc_mem_id;
u32 data_mem_id;
+ /* Feedback to BAM user */
+ void (*callback)(enum sps_callback_case, void *);
+ void *user;
+
/* Security properties */
u32 manage;
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index 4caa71b..ec135a3 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.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
@@ -14,6 +14,20 @@
#define _USB_BAM_H_
/**
+ * SPS Pipes direction.
+ *
+ * USB_TO_PEER_PERIPHERAL USB (as Producer) to other
+ * peer peripheral.
+ * PEER_PERIPHERAL_TO_USB Other Peripheral to
+ * USB (as consumer).
+ */
+enum usb_bam_pipe_dir {
+ USB_TO_PEER_PERIPHERAL,
+ PEER_PERIPHERAL_TO_USB,
+};
+
+#ifdef CONFIG_USB_BAM
+/**
* Connect USB-to-Periperal SPS connection.
*
* This function returns the allocated pipes number.
@@ -29,12 +43,31 @@
* @return 0 on success, negative value on error
*
*/
-#ifdef CONFIG_USB_BAM
int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx);
+
+/**
+ * Register a wakeup callback from peer BAM.
+ *
+ * @idx - Connection index.
+ *
+ * @callback - the callback function
+ *
+ * @return 0 on success, negative value on error
+ *
+ */
+int usb_bam_register_wake_cb(u8 idx,
+ int (*callback)(void *), void* param);
#else
-int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+static inline int usb_bam_connect(u8 idx, u8 *src_pipe_idx, u8 *dst_pipe_idx)
+{
+ return -ENODEV;
+}
+
+static inline int usb_bam_register_wake_cb(u8 idx,
+ int (*callback)(void *), void* param)
{
return -ENODEV;
}
#endif
#endif /* _USB_BAM_H_ */
+
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index 7c0de57..59d3a96 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -449,6 +449,29 @@
void __init msm_map_msm8625_io(void) { return; }
#endif /* CONFIG_ARCH_MSM8625 */
+#ifdef CONFIG_ARCH_MSM9625
+static struct map_desc msm9625_io_desc[] __initdata = {
+ MSM_CHIP_DEVICE(APCS_GCC, MSM9625),
+ MSM_CHIP_DEVICE(TLMM, MSM9625),
+ MSM_CHIP_DEVICE(TMR, MSM9625),
+ {
+ .virtual = (unsigned long) MSM_SHARED_RAM_BASE,
+ .length = MSM_SHARED_RAM_SIZE,
+ .type = MT_DEVICE,
+ },
+#ifdef CONFIG_DEBUG_MSM9625_UART
+ MSM_DEVICE(DEBUG_UART),
+#endif
+};
+
+void __init msm_map_msm9625_io(void)
+{
+ msm_shared_ram_phys = MSM9625_SHARED_RAM_PHYS;
+ msm_map_io(msm9625_io_desc, ARRAY_SIZE(msm9625_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM9625 */
+
+
void __iomem *
__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
{
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
index 0652f3b..49a3e6f 100644
--- a/arch/arm/mach-msm/iommu.c
+++ b/arch/arm/mach-msm/iommu.c
@@ -49,9 +49,11 @@
#define MSM_IOMMU_ATTR_CACHED_WT 0x3
-static inline void clean_pte(unsigned long *start, unsigned long *end)
+static inline void clean_pte(unsigned long *start, unsigned long *end,
+ int redirect)
{
- dmac_flush_range(start, end);
+ if (!redirect)
+ dmac_flush_range(start, end);
}
static int msm_iommu_tex_class[4];
@@ -292,6 +294,9 @@
memset(priv->pgtable, 0, SZ_16K);
domain->priv = priv;
+
+ clean_pte(priv->pgtable, priv->pgtable + NUM_FL_PTE, priv->redirect);
+
return 0;
fail_nomem:
@@ -518,8 +523,7 @@
for (i = 0; i < 16; i++)
*(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION
| FL_TYPE_SECT | FL_SHARED | FL_NG | pgprot;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 16);
+ clean_pte(fl_pte, fl_pte + 16, priv->redirect);
}
if (len == SZ_1M) {
@@ -530,8 +534,7 @@
*fl_pte = (pa & 0xFFF00000) | FL_NG | FL_TYPE_SECT | FL_SHARED
| pgprot;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
/* Need a 2nd level table */
@@ -548,12 +551,12 @@
goto fail;
}
memset(sl, 0, SZ_4K);
+ clean_pte(sl, sl + NUM_SL_PTE, priv->redirect);
*fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | \
FL_TYPE_TABLE);
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
if (!(*fl_pte & FL_TYPE_TABLE)) {
@@ -574,8 +577,7 @@
*sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_NG | SL_SHARED
| SL_TYPE_SMALL | pgprot;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 1);
+ clean_pte(sl_pte, sl_pte + 1, priv->redirect);
}
if (len == SZ_64K) {
@@ -591,8 +593,7 @@
*(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_NG
| SL_SHARED | SL_TYPE_LARGE | pgprot;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 16);
+ clean_pte(sl_pte, sl_pte + 16, priv->redirect);
}
ret = __flush_iotlb_va(domain, va);
@@ -652,15 +653,13 @@
for (i = 0; i < 16; i++)
*(fl_pte+i) = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 16);
+ clean_pte(fl_pte, fl_pte + 16, priv->redirect);
}
if (len == SZ_1M) {
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
@@ -671,15 +670,13 @@
for (i = 0; i < 16; i++)
*(sl_pte+i) = 0;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 16);
+ clean_pte(sl_pte, sl_pte + 16, priv->redirect);
}
if (len == SZ_4K) {
*sl_pte = 0;
- if (!priv->redirect)
- clean_pte(sl_pte, sl_pte + 1);
+ clean_pte(sl_pte, sl_pte + 1, priv->redirect);
}
if (len == SZ_4K || len == SZ_64K) {
@@ -692,8 +689,7 @@
free_page((unsigned long)sl_table);
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
}
@@ -773,10 +769,12 @@
}
memset(sl_table, 0, SZ_4K);
+ clean_pte(sl_table, sl_table + NUM_SL_PTE,
+ priv->redirect);
+
*fl_pte = ((((int)__pa(sl_table)) & FL_BASE_MASK) |
FL_TYPE_TABLE);
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
} else
sl_table = (unsigned long *)
__va(((*fl_pte) & FL_BASE_MASK));
@@ -809,8 +807,8 @@
}
}
- if (!priv->redirect)
- clean_pte(sl_table + sl_start, sl_table + sl_offset);
+ clean_pte(sl_table + sl_start, sl_table + sl_offset,
+ priv->redirect);
fl_pte++;
sl_offset = 0;
@@ -854,8 +852,8 @@
sl_end = NUM_SL_PTE;
memset(sl_table + sl_start, 0, (sl_end - sl_start) * 4);
- if (!priv->redirect)
- clean_pte(sl_table + sl_start, sl_table + sl_end);
+ clean_pte(sl_table + sl_start, sl_table + sl_end,
+ priv->redirect);
offset += (sl_end - sl_start) * SZ_4K;
@@ -879,8 +877,7 @@
free_page((unsigned long)sl_table);
*fl_pte = 0;
- if (!priv->redirect)
- clean_pte(fl_pte, fl_pte + 1);
+ clean_pte(fl_pte, fl_pte + 1, priv->redirect);
}
sl_start = 0;
diff --git a/arch/arm/mach-msm/iommu_domains.c b/arch/arm/mach-msm/iommu_domains.c
index 8f4af3b..34c16d1 100644
--- a/arch/arm/mach-msm/iommu_domains.c
+++ b/arch/arm/mach-msm/iommu_domains.c
@@ -22,8 +22,8 @@
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
-/* dummy 4k for overmapping */
-char iommu_dummy[2*PAGE_SIZE-4];
+/* dummy 64K for overmapping */
+char iommu_dummy[2*SZ_64K-4];
struct msm_iommu_domain_state {
struct msm_iommu_domain *domains;
@@ -35,36 +35,122 @@
int msm_iommu_map_extra(struct iommu_domain *domain,
unsigned long start_iova,
unsigned long size,
+ unsigned long page_size,
int cached)
{
- int i, ret = 0;
- struct scatterlist *sglist;
- unsigned int nrpages = PFN_ALIGN(size) >> PAGE_SHIFT;
- struct page *dummy_page = phys_to_page(
- PFN_ALIGN(virt_to_phys(iommu_dummy)));
+ int i, ret_value = 0;
+ unsigned long order = get_order(page_size);
+ unsigned long aligned_size = ALIGN(size, page_size);
+ unsigned long nrpages = aligned_size >> (PAGE_SHIFT + order);
+ unsigned long phy_addr = ALIGN(virt_to_phys(iommu_dummy), page_size);
+ unsigned long temp_iova = start_iova;
- sglist = vmalloc(sizeof(*sglist) * nrpages);
+ for (i = 0; i < nrpages; i++) {
+ int ret = iommu_map(domain, temp_iova, phy_addr, order, cached);
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p, error: %d\n",
+ __func__, start_iova, domain, ret);
+ ret_value = -EAGAIN;
+ goto out;
+ }
+ temp_iova += page_size;
+ }
+ return ret_value;
+out:
+ for (; i > 0; --i) {
+ temp_iova -= page_size;
+ iommu_unmap(domain, start_iova, order);
+ }
+ return ret_value;
+}
+
+void msm_iommu_unmap_extra(struct iommu_domain *domain,
+ unsigned long start_iova,
+ unsigned long size,
+ unsigned long page_size)
+{
+ int i;
+ unsigned long order = get_order(page_size);
+ unsigned long aligned_size = ALIGN(size, page_size);
+ unsigned long nrpages = aligned_size >> (PAGE_SHIFT + order);
+ unsigned long temp_iova = start_iova;
+
+ for (i = 0; i < nrpages; ++i) {
+ iommu_unmap(domain, temp_iova, order);
+ temp_iova += page_size;
+ }
+}
+
+static int msm_iommu_map_iova_phys(struct iommu_domain *domain,
+ unsigned long iova,
+ unsigned long phys,
+ unsigned long size,
+ int cached)
+{
+ int ret;
+ struct scatterlist *sglist;
+
+ sglist = vmalloc(sizeof(*sglist));
if (!sglist) {
ret = -ENOMEM;
goto err1;
}
- sg_init_table(sglist, nrpages);
+ sg_init_table(sglist, 1);
+ sglist->length = size;
+ sglist->offset = 0;
+ sglist->dma_address = phys;
- for (i = 0; i < nrpages; i++)
- sg_set_page(&sglist[i], dummy_page, PAGE_SIZE, 0);
-
- ret = iommu_map_range(domain, start_iova, sglist, size, cached);
+ ret = iommu_map_range(domain, iova, sglist, size, cached);
if (ret) {
pr_err("%s: could not map extra %lx in domain %p\n",
- __func__, start_iova, domain);
+ __func__, iova, domain);
}
vfree(sglist);
err1:
return ret;
+
}
+int msm_iommu_map_contig_buffer(unsigned long phys,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size,
+ unsigned long align,
+ unsigned long cached,
+ unsigned long *iova_val)
+{
+ unsigned long iova;
+ int ret;
+
+ if (size & (align - 1))
+ return -EINVAL;
+
+ iova = msm_allocate_iova_address(domain_no, partition_no, size, align);
+
+ if (!iova)
+ return -ENOMEM;
+
+ ret = msm_iommu_map_iova_phys(msm_get_iommu_domain(domain_no), iova,
+ phys, size, cached);
+
+ if (ret)
+ msm_free_iova_address(iova, domain_no, partition_no, size);
+ else
+ *iova_val = iova;
+
+ return ret;
+}
+
+void msm_iommu_unmap_contig_buffer(unsigned long iova,
+ unsigned int domain_no,
+ unsigned int partition_no,
+ unsigned long size)
+{
+ iommu_unmap_range(msm_get_iommu_domain(domain_no), iova, size);
+ msm_free_iova_address(iova, domain_no, partition_no, size);
+}
struct iommu_domain *msm_get_iommu_domain(int domain_num)
{
diff --git a/arch/arm/mach-msm/ipc_socket.c b/arch/arm/mach-msm/ipc_socket.c
index 6e8c99e..085b87a 100644
--- a/arch/arm/mach-msm/ipc_socket.c
+++ b/arch/arm/mach-msm/ipc_socket.c
@@ -21,6 +21,10 @@
#include <linux/gfp.h>
#include <linux/msm_ipc.h>
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+#include <linux/android_aid.h>
+#endif
+
#include <asm/string.h>
#include <asm/atomic.h>
@@ -39,6 +43,21 @@
static struct proto msm_ipc_proto;
static const struct proto_ops msm_ipc_proto_ops;
+#ifdef CONFIG_ANDROID_PARANOID_NETWORK
+static inline int check_permissions(void)
+{
+ int rc = 0;
+ if (!current_euid() || in_egroup_p(AID_NET_RAW))
+ rc = 1;
+ return rc;
+}
+# else
+static inline int check_permissions(void)
+{
+ return 1;
+}
+#endif
+
static void msm_ipc_router_unload_modem(void *pil)
{
if (pil)
@@ -214,6 +233,11 @@
struct msm_ipc_port *port_ptr;
void *pil;
+ if (!check_permissions()) {
+ pr_err("%s: Do not have permissions\n", __func__);
+ return -EPERM;
+ }
+
if (unlikely(protocol != 0)) {
pr_err("%s: Protocol not supported\n", __func__);
return -EPROTONOSUPPORT;
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
new file mode 100644
index 0000000..48cf3f7
--- /dev/null
+++ b/arch/arm/mach-msm/lpm_levels.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/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <mach/mpm.h>
+#include "rpm_resources.h"
+
+static struct msm_rpmrs_level *msm_lpm_levels;
+static int msm_lpm_level_count;
+
+int msm_rpmrs_enter_sleep(uint32_t sclk_count, struct msm_rpmrs_limits *limits,
+ bool from_idle, bool notify_rpm)
+{
+ /* TODO */
+ return 0;
+}
+
+void msm_rpmrs_exit_sleep(struct msm_rpmrs_limits *limits, bool from_idle,
+ bool notify_rpm, bool collapsed)
+{
+ /* TODO */
+ return;
+}
+
+static bool msm_rpmrs_irqs_detectable(struct msm_rpmrs_limits *limits,
+ bool irqs_detect, bool gpio_detect)
+{
+ /* TODO */
+ return true;
+}
+
+void msm_rpmrs_show_resources(void)
+{
+ /* TODO */
+ return;
+}
+
+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)
+{
+ unsigned int cpu = smp_processor_id();
+ struct msm_rpmrs_level *best_level = NULL;
+ bool irqs_detectable = false;
+ bool gpio_detectable = false;
+ int i;
+
+ if (!msm_lpm_levels)
+ return NULL;
+
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ irqs_detectable = msm_mpm_irqs_detectable(from_idle);
+ gpio_detectable = msm_mpm_gpio_irqs_detectable(from_idle);
+ }
+
+ for (i = 0; i < msm_lpm_level_count; i++) {
+ struct msm_rpmrs_level *level = &msm_lpm_levels[i];
+ uint32_t power;
+
+ if (!level->available)
+ continue;
+
+ if (sleep_mode != level->sleep_mode)
+ continue;
+
+ if (latency_us < level->latency_us)
+ continue;
+
+ if (!msm_rpmrs_irqs_detectable(&level->rs_limits,
+ irqs_detectable, gpio_detectable))
+ continue;
+
+ if (sleep_us <= 1) {
+ power = level->energy_overhead;
+ } else if (sleep_us <= level->time_overhead_us) {
+ power = level->energy_overhead / sleep_us;
+ } else if ((sleep_us >> 10) > level->time_overhead_us) {
+ power = level->steady_state_power;
+ } else {
+ power = level->steady_state_power;
+ power -= (level->time_overhead_us *
+ level->steady_state_power)/sleep_us;
+ power += level->energy_overhead / sleep_us;
+ }
+
+ if (!best_level ||
+ best_level->rs_limits.power[cpu] >= power) {
+ level->rs_limits.latency_us[cpu] = level->latency_us;
+ level->rs_limits.power[cpu] = power;
+ best_level = level;
+ }
+ }
+
+ return best_level ? &best_level->rs_limits : NULL;
+}
+
+static int __devinit msm_lpm_levels_probe(struct platform_device *pdev)
+{
+ struct msm_rpmrs_level *levels = NULL;
+ struct msm_rpmrs_level *level = NULL;
+ struct device_node *node = NULL;
+ char *key = NULL;
+ uint32_t val = 0;
+ int ret = 0;
+ uint32_t num_levels = 0;
+ int idx = 0;
+
+ for_each_child_of_node(pdev->dev.of_node, node)
+ num_levels++;
+
+ levels = kzalloc(num_levels * sizeof(struct msm_rpmrs_level),
+ GFP_KERNEL);
+ if (!levels)
+ return -ENOMEM;
+
+ for_each_child_of_node(pdev->dev.of_node, node) {
+ level = &levels[idx++];
+ level->available = false;
+
+ key = "qcom,mode";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->sleep_mode = val;
+
+ key = "qcom,xo";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->rs_limits.pxo = val;
+
+ key = "qcom,l2";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->rs_limits.l2_cache = val;
+
+ key = "qcom,vdd-dig-upper-bound";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->rs_limits.vdd_dig_upper_bound = val;
+
+ key = "qcom,vdd-dig-lower-bound";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->rs_limits.vdd_dig = val;
+
+ key = "qcom,vdd-mem-upper-bound";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->rs_limits.vdd_mem_upper_bound = val;
+
+ key = "qcom,vdd-mem-lower-bound";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->rs_limits.vdd_mem = val;
+
+ key = "qcom,latency-us";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->latency_us = val;
+
+ key = "qcom,ss-power";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->steady_state_power = val;
+
+ key = "qcom,energy-overhead";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->energy_overhead = val;
+
+ key = "qcom,time-overhead";
+ ret = of_property_read_u32(node, key, &val);
+ if (ret)
+ goto fail;
+ level->time_overhead_us = val;
+
+ level->available = true;
+ }
+
+ msm_lpm_levels = levels;
+ msm_lpm_level_count = idx;
+
+ return 0;
+fail:
+ pr_err("%s: Error in name %s key %s\n", __func__, node->full_name, key);
+ kfree(levels);
+ return -EFAULT;
+}
+
+static struct of_device_id msm_lpm_levels_match_table[] = {
+ {.compatible = "qcom,lpm-levels"},
+ {},
+};
+
+static struct platform_driver msm_lpm_levels_driver = {
+ .probe = msm_lpm_levels_probe,
+ .driver = {
+ .name = "lpm-levels",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_lpm_levels_match_table,
+ },
+};
+
+static int __init msm_lpm_levels_module_init(void)
+{
+ return platform_driver_register(&msm_lpm_levels_driver);
+}
+late_initcall(msm_lpm_levels_module_init);
diff --git a/arch/arm/mach-msm/memory.c b/arch/arm/mach-msm/memory.c
index 0db160e..ccb18b3 100644
--- a/arch/arm/mach-msm/memory.c
+++ b/arch/arm/mach-msm/memory.c
@@ -332,29 +332,6 @@
}
}
-unsigned long __init reserve_memory_for_fmem(unsigned long fmem_size)
-{
- struct membank *mb;
- int ret;
- unsigned long fmem_phys;
-
- if (!fmem_size)
- return 0;
-
- mb = &meminfo.bank[meminfo.nr_banks - 1];
- /*
- * Placing fmem at the top of memory causes multimedia issues.
- * Instead, place it 1 page below the top of memory to prevent
- * the issues from occurring.
- */
- fmem_phys = mb->start + (mb->size - fmem_size) - PAGE_SIZE;
- ret = memblock_remove(fmem_phys, fmem_size);
- BUG_ON(ret);
-
- pr_info("fmem start %lx size %lx\n", fmem_phys, fmem_size);
- return fmem_phys;
-}
-
static void __init initialize_mempools(void)
{
struct mem_pool *mpool;
diff --git a/arch/arm/mach-msm/modem-8960.c b/arch/arm/mach-msm/modem-8960.c
index 7df1c3a..4922007 100644
--- a/arch/arm/mach-msm/modem-8960.c
+++ b/arch/arm/mach-msm/modem-8960.c
@@ -27,6 +27,7 @@
#include <mach/subsystem_restart.h>
#include <mach/subsystem_notif.h>
#include <mach/socinfo.h>
+#include <mach/msm_smsm.h>
#include "smd_private.h"
#include "modem_notifier.h"
@@ -34,6 +35,55 @@
static int crash_shutdown;
+#define MAX_SSR_REASON_LEN 81U
+#define Q6_FW_WDOG_ENABLE 0x08882024
+#define Q6_SW_WDOG_ENABLE 0x08982024
+
+static void log_modem_sfr(void)
+{
+ u32 size;
+ char *smem_reason, reason[MAX_SSR_REASON_LEN];
+
+ smem_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size);
+ if (!smem_reason || !size) {
+ pr_err("modem subsystem failure reason: (unknown, smem_get_entry failed).\n");
+ return;
+ }
+ if (!smem_reason[0]) {
+ pr_err("modem subsystem failure reason: (unknown, init string found).\n");
+ return;
+ }
+
+ size = min(size, MAX_SSR_REASON_LEN-1);
+ memcpy(reason, smem_reason, size);
+ reason[size] = '\0';
+ pr_err("modem subsystem failure reason: %s.\n", reason);
+
+ smem_reason[0] = '\0';
+ wmb();
+}
+
+static void modem_wdog_check(struct work_struct *work)
+{
+ void __iomem *q6_sw_wdog_addr;
+ u32 regval;
+
+ q6_sw_wdog_addr = ioremap_nocache(Q6_SW_WDOG_ENABLE, 4);
+ if (!q6_sw_wdog_addr)
+ panic("Unable to check modem watchdog status.\n");
+
+ 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");
+ }
+
+ iounmap(q6_sw_wdog_addr);
+}
+
+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;
@@ -50,6 +100,7 @@
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) {
@@ -59,7 +110,7 @@
__func__);
kernel_restart(NULL);
} else {
- /* TODO: Bus unlock code/sequence goes _here_ */
+ log_modem_sfr();
subsystem_restart("modem");
}
}
@@ -67,6 +118,7 @@
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");
}
@@ -80,21 +132,24 @@
return;
if (new_state & SMSM_RESET) {
- pr_err("Modem SMSM state changed to SMSM_RESET.\n"
- "Probable err_fatal on the modem. "
- "Calling subsystem restart...\n");
+ pr_err("Probable fatal error on the modem.\n");
+ log_modem_sfr();
subsystem_restart("modem");
}
}
-#define Q6_FW_WDOG_ENABLE 0x08882024
-#define Q6_SW_WDOG_ENABLE 0x08982024
static int modem_shutdown(const struct subsys_data *subsys)
{
void __iomem *q6_fw_wdog_addr;
void __iomem *q6_sw_wdog_addr;
/*
+ * Cancel any pending wdog_check work items, since we're shutting
+ * down anyway.
+ */
+ cancel_delayed_work(&modem_wdog_check_work);
+
+ /*
* Disable the modem watchdog since it keeps running even after the
* modem is shutdown.
*/
@@ -122,12 +177,16 @@
return 0;
}
+#define MODEM_WDOG_CHECK_TIMEOUT_MS 10000
+
static int modem_powerup(const struct subsys_data *subsys)
{
pil_force_boot("modem_fw");
pil_force_boot("modem");
enable_irq(Q6FW_WDOG_EXPIRED_IRQ);
enable_irq(Q6SW_WDOG_EXPIRED_IRQ);
+ schedule_delayed_work(&modem_wdog_check_work,
+ msecs_to_jiffies(MODEM_WDOG_CHECK_TIMEOUT_MS));
return 0;
}
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 404c8f0..191e950 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -26,7 +26,7 @@
#include <mach/memory.h>
#include <mach/msm_iomap.h>
-#define L2C_IMEM_ADDR 0x2a03f014
+#define L2_DUMP_OFFSET 0x14
static unsigned long msm_cache_dump_addr;
@@ -66,9 +66,6 @@
unsigned long buf;
unsigned long size;
} l1_cache_data;
-#ifndef CONFIG_MSM_CACHE_DUMP_ON_PANIC
- unsigned int *imem_loc;
-#endif
void *temp;
unsigned long total_size = d->l1_size + d->l2_size;
@@ -105,9 +102,8 @@
pr_err("%s: could not register L2 buffer ret = %d.\n",
__func__, ret);
#else
- imem_loc = ioremap(L2C_IMEM_ADDR, SZ_4K);
- __raw_writel(msm_cache_dump_addr + d->l1_size, imem_loc);
- iounmap(imem_loc);
+ __raw_writel(msm_cache_dump_addr + d->l1_size,
+ MSM_IMEM_BASE + L2_DUMP_OFFSET);
#endif
atomic_notifier_chain_register(&panic_notifier_list,
diff --git a/arch/arm/mach-msm/ocmem.c b/arch/arm/mach-msm/ocmem.c
new file mode 100644
index 0000000..af39dc3
--- /dev/null
+++ b/arch/arm/mach-msm/ocmem.c
@@ -0,0 +1,304 @@
+/* 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/rbtree.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>
+
+struct ocmem_partition {
+ const char *name;
+ int id;
+ unsigned long p_start;
+ unsigned long p_size;
+ unsigned long p_min;
+};
+
+struct ocmem_plat_data {
+ void __iomem *vbase;
+ unsigned long size;
+ unsigned long base;
+ struct ocmem_partition *parts;
+ int nr_parts;
+};
+
+struct ocmem_zone zones[OCMEM_CLIENT_MAX];
+
+struct ocmem_zone *get_zone(unsigned id)
+{
+ if (id < OCMEM_GRAPHICS || id >= OCMEM_CLIENT_MAX)
+ return NULL;
+ else
+ return &zones[id];
+}
+
+static struct ocmem_plat_data *ocmem_pdata;
+
+#define CLIENT_NAME_MAX 10
+/* Must be in sync with enum ocmem_client */
+static const char *client_names[OCMEM_CLIENT_MAX] = {
+ "graphics",
+ "video",
+ "camera",
+ "hp_audio",
+ "voice",
+ "lp_audio",
+ "sensors",
+ "blast",
+};
+
+struct ocmem_quota_table {
+ const char *name;
+ int id;
+ unsigned long start;
+ unsigned long size;
+ unsigned long min;
+};
+
+/* This static table will go away with device tree support */
+static struct ocmem_quota_table qt[OCMEM_CLIENT_MAX] = {
+ /* name, id, start, size, min */
+ { "graphics", OCMEM_GRAPHICS, 0x0, 0x100000, 0x80000},
+ { "video", OCMEM_VIDEO, 0x100000, 0x80000, 0x55000},
+ { "camera", OCMEM_CAMERA, 0x0, 0x0, 0x0},
+ { "voice", OCMEM_VOICE, 0x0, 0x0, 0x0 },
+ { "hp_audio", OCMEM_HP_AUDIO, 0x0, 0x0, 0x0},
+ { "lp_audio", OCMEM_LP_AUDIO, 0x80000, 0xA0000, 0xA0000},
+ { "blast", OCMEM_BLAST, 0x120000, 0x20000, 0x20000},
+ { "sensors", OCMEM_SENSORS, 0x140000, 0x40000, 0x40000},
+};
+
+static inline int get_id(const char *name)
+{
+ int i = 0;
+ for (i = 0 ; i < OCMEM_CLIENT_MAX; i++) {
+ if (strncmp(name, client_names[i], CLIENT_NAME_MAX) == 0)
+ return i;
+ }
+ return -EINVAL;
+}
+
+static struct ocmem_plat_data *parse_static_config(struct platform_device *pdev)
+{
+ struct ocmem_plat_data *pdata = NULL;
+ struct ocmem_partition *parts = NULL;
+ struct device *dev = &pdev->dev;
+ int nr_parts;
+ int i;
+ int j;
+
+ pdata = devm_kzalloc(dev, sizeof(struct ocmem_plat_data),
+ GFP_KERNEL);
+
+ if (!pdata) {
+ dev_err(dev, "Unable to allocate memory for"
+ " platform data\n");
+ return NULL;
+ }
+
+ for (i = 0 ; i < ARRAY_SIZE(qt); i++)
+ if (qt[i].size != 0x0)
+ nr_parts++;
+
+ if (nr_parts == 0x0) {
+ dev_err(dev, "No valid ocmem partitions\n");
+ return NULL;
+ } else
+ dev_info(dev, "Total partitions = %d\n", nr_parts);
+
+ parts = devm_kzalloc(dev, sizeof(struct ocmem_partition) * nr_parts,
+ GFP_KERNEL);
+
+ if (!parts) {
+ dev_err(dev, "Unable to allocate memory for"
+ " partition data\n");
+ return NULL;
+ }
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(qt); i++) {
+ if (qt[i].size == 0x0) {
+ dev_dbg(dev, "Skipping creation of pool for %s\n",
+ qt[i].name);
+ continue;
+ }
+ parts[j].id = qt[i].id;
+ parts[j].p_size = qt[i].size;
+ parts[j].p_start = qt[i].start;
+ parts[j].p_min = qt[i].min;
+ j++;
+ }
+ BUG_ON(j != nr_parts);
+ pdata->nr_parts = nr_parts;
+ pdata->parts = parts;
+ pdata->base = OCMEM_PHYS_BASE;
+ pdata->size = OCMEM_PHYS_SIZE;
+ return pdata;
+}
+
+static struct ocmem_plat_data *parse_dt_config(struct platform_device *pdev)
+{
+ return NULL;
+}
+
+static int ocmem_zone_init(struct platform_device *pdev)
+{
+
+ int ret = -1;
+ int i = 0;
+ unsigned active_zones = 0;
+
+ struct ocmem_zone *zone = NULL;
+ struct ocmem_zone_ops *z_ops = NULL;
+ struct device *dev = &pdev->dev;
+ unsigned long start;
+ struct ocmem_plat_data *pdata = NULL;
+
+ pdata = platform_get_drvdata(pdev);
+
+ for (i = 0; i < pdata->nr_parts; i++) {
+ struct ocmem_partition *part = &pdata->parts[i];
+ zone = get_zone(part->id);
+
+ dev_dbg(dev, "Partition %d, start %lx, size %lx for %s\n",
+ i, part->p_start, part->p_size,
+ client_names[part->id]);
+
+ if (part->p_size > pdata->size) {
+ dev_alert(dev, "Quota > ocmem_size for id:%d\n",
+ part->id);
+ continue;
+ }
+
+ zone->z_pool = gen_pool_create(PAGE_SHIFT, -1);
+
+ if (!zone->z_pool) {
+ dev_alert(dev, "Creating pool failed for id:%d\n",
+ part->id);
+ return -EBUSY;
+ }
+
+ start = pdata->base + part->p_start;
+ ret = gen_pool_add(zone->z_pool, start,
+ part->p_size, -1);
+
+ if (ret < 0) {
+ gen_pool_destroy(zone->z_pool);
+ dev_alert(dev, "Unable to back pool %d with "
+ "buffer:%lx\n", part->id, part->p_size);
+ return -EBUSY;
+ }
+
+ /* Initialize zone allocators */
+ z_ops = devm_kzalloc(dev, sizeof(struct ocmem_zone_ops),
+ GFP_KERNEL);
+ if (!z_ops) {
+ pr_alert("ocmem: Unable to allocate memory for"
+ "zone ops:%d\n", i);
+ return -EBUSY;
+ }
+
+ /* Initialize zone parameters */
+ zone->z_start = start;
+ zone->z_head = zone->z_start;
+ zone->z_end = start + part->p_size;
+ zone->z_tail = zone->z_end;
+ zone->z_free = part->p_size;
+ zone->owner = part->id;
+ zone->active_regions = 0;
+ zone->max_regions = 0;
+ INIT_LIST_HEAD(&zone->region_list);
+ zone->z_ops = z_ops;
+ active_zones++;
+
+ if (active_zones == 1)
+ pr_info("Physical OCMEM zone layout:\n");
+
+ pr_info(" zone %s\t: 0x%08lx - 0x%08lx (%4ld KB)\n",
+ client_names[part->id], zone->z_start,
+ zone->z_end, part->p_size/SZ_1K);
+ }
+
+ dev_info(dev, "Total active zones = %d\n", active_zones);
+ return 0;
+}
+
+static int __devinit msm_ocmem_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+
+ if (!pdev->dev.of_node->child) {
+ dev_info(dev, "Missing Configuration in Device Tree\n");
+ ocmem_pdata = parse_static_config(pdev);
+ } else {
+ ocmem_pdata = parse_dt_config(pdev);
+ }
+
+ /* Check if we have some configuration data to start */
+ if (!ocmem_pdata)
+ return -ENODEV;
+
+ /* Sanity Checks */
+ BUG_ON(!IS_ALIGNED(ocmem_pdata->size, PAGE_SIZE));
+ BUG_ON(!IS_ALIGNED(ocmem_pdata->base, PAGE_SIZE));
+
+ platform_set_drvdata(pdev, ocmem_pdata);
+
+ if (ocmem_zone_init(pdev))
+ return -EBUSY;
+
+ dev_info(dev, "initialized successfully\n");
+ return 0;
+}
+
+static int __devexit msm_ocmem_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct of_device_id msm_ocmem_dt_match[] = {
+ { .compatible = "qcom,msm_ocmem",
+ },
+ {}
+};
+
+static struct platform_driver msm_ocmem_driver = {
+ .probe = msm_ocmem_probe,
+ .remove = __devexit_p(msm_ocmem_remove),
+ .driver = {
+ .name = "msm_ocmem",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_ocmem_dt_match,
+ },
+};
+
+static int __init ocmem_init(void)
+{
+ return platform_driver_register(&msm_ocmem_driver);
+}
+subsys_initcall(ocmem_init);
+
+static void __exit ocmem_exit(void)
+{
+ platform_driver_unregister(&msm_ocmem_driver);
+}
+module_exit(ocmem_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Support for On-Chip Memory on MSM");
diff --git a/arch/arm/mach-msm/pcie.c b/arch/arm/mach-msm/pcie.c
new file mode 100644
index 0000000..4e2b1083
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.c
@@ -0,0 +1,669 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <asm/mach/pci.h>
+#include <mach/gpiomux.h>
+#include <mach/hardware.h>
+#include <mach/msm_iomap.h>
+
+#include "pcie.h"
+
+/* Root Complex Port vendor/device IDs */
+#define PCIE_VENDOR_ID_RCP 0x17cb
+#define PCIE_DEVICE_ID_RCP 0x0101
+
+#define PCIE20_PARF_PCS_DEEMPH 0x34
+#define PCIE20_PARF_PCS_SWING 0x38
+#define PCIE20_PARF_PHY_CTRL 0x40
+#define PCIE20_PARF_PHY_REFCLK 0x4C
+#define PCIE20_PARF_CONFIG_BITS 0x50
+
+#define PCIE20_ELBI_SYS_CTRL 0x04
+
+#define PCIE20_CAP 0x70
+#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
+
+#define PCIE20_COMMAND_STATUS 0x04
+#define PCIE20_BUSNUMBERS 0x18
+#define PCIE20_MEMORY_BASE_LIMIT 0x20
+
+#define PCIE20_PLR_IATU_VIEWPORT 0x900
+#define PCIE20_PLR_IATU_CTRL1 0x904
+#define PCIE20_PLR_IATU_CTRL2 0x908
+#define PCIE20_PLR_IATU_LBAR 0x90C
+#define PCIE20_PLR_IATU_UBAR 0x910
+#define PCIE20_PLR_IATU_LAR 0x914
+#define PCIE20_PLR_IATU_LTAR 0x918
+#define PCIE20_PLR_IATU_UTAR 0x91c
+
+#define PCIE_RESET (MSM_CLK_CTL_BASE + 0x22dc)
+#define PCIE_SFAB_AXI_S5_FCLK_CTL (MSM_CLK_CTL_BASE + 0x2154)
+
+#define MSM_PCIE_DEV_BAR_ADDR PCIBIOS_MIN_MEM
+#define MSM_PCIE_DEV_CFG_ADDR 0x01000000
+
+#define RD 0
+#define WR 1
+
+/* debug mask sys interface */
+static int msm_pcie_debug_mask;
+module_param_named(debug_mask, msm_pcie_debug_mask,
+ int, S_IRUGO | S_IWUSR | S_IWGRP);
+
+/* resources from device file */
+enum msm_pcie_res {
+ MSM_PCIE_RES_PARF,
+ MSM_PCIE_RES_ELBI,
+ MSM_PCIE_RES_PCIE20,
+ MSM_PCIE_RES_AXI_BAR,
+ MSM_PCIE_RES_AXI_CONF,
+ MSM_PCIE_MAX_RES
+};
+
+/* msm pcie device data */
+static struct msm_pcie_dev_t msm_pcie_dev;
+
+/* regulators */
+static struct msm_pcie_vreg_info_t msm_pcie_vreg_info[MSM_PCIE_MAX_VREG] = {
+ {NULL, "vp_pcie", 1050000, 1050000, 40900},
+ {NULL, "vptx_pcie", 1050000, 1050000, 18200},
+ {NULL, "vdd_pcie_vph", 0, 0, 0},
+ {NULL, "pcie_ext_3p3v", 0, 0, 0}
+};
+
+/* clocks */
+static struct msm_pcie_clk_info_t msm_pcie_clk_info[MSM_PCIE_MAX_CLK] = {
+ {NULL, "bus_clk"},
+ {NULL, "iface_clk"},
+ {NULL, "ref_clk"}
+};
+
+/* resources */
+static struct msm_pcie_res_info_t msm_pcie_res_info[MSM_PCIE_MAX_RES] = {
+ {"parf", 0, 0, 0},
+ {"elbi", 0, 0, 0},
+ {"pcie20", 0, 0, 0},
+ {"axi_bar", 0, 0, 0},
+ {"axi_conf", 0, 0, 0},
+};
+
+int msm_pcie_get_debug_mask(void)
+{
+ return msm_pcie_debug_mask;
+}
+
+static void msm_pcie_write_mask(void __iomem *addr,
+ uint32_t clear_mask, uint32_t set_mask)
+{
+ uint32_t val;
+
+ val = (readl_relaxed(addr) & ~clear_mask) | set_mask;
+ writel_relaxed(val, addr);
+ wmb(); /* ensure data is written to hardware register */
+}
+
+static int msm_pcie_is_link_up(void)
+{
+ return readl_relaxed(msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS) &
+ BIT(29);
+}
+
+static inline int msm_pcie_oper_conf(struct pci_bus *bus, u32 devfn, int oper,
+ int where, int size, u32 *val)
+{
+ uint32_t word_offset, byte_offset, mask;
+ uint32_t rd_val, wr_val;
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+ void __iomem *config_base;
+
+ /*
+ * Only buses 0 and 1 are supported. RC port on bus 0 and EP in bus 1.
+ * For downstream bus (1), make sure link is up
+ */
+ if ((bus->number > 1) || (devfn != 0)) {
+ PCIE_DBG("invalid %s - bus %d devfn %d\n",
+ (oper == RD) ? "rd" : "wr", bus->number, devfn);
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ } else if ((bus->number != 0) && !msm_pcie_is_link_up()) {
+ PCIE_DBG("%s fail, link down - bus %d devfn %d\n",
+ (oper == RD) ? "rd" : "wr", bus->number, devfn);
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ word_offset = where & ~0x3;
+ byte_offset = where & 0x3;
+ mask = (~0 >> (8 * (4 - size))) << (8 * byte_offset);
+
+ config_base = (bus->number == 0) ? dev->pcie20 : dev->axi_conf;
+ rd_val = readl_relaxed(config_base + word_offset);
+
+ if (oper == RD) {
+ *val = ((rd_val & mask) >> (8 * byte_offset));
+
+ PCIE_DBG("%d:0x%02x + 0x%04x[%d] -> 0x%08x; rd 0x%08x\n",
+ bus->number, devfn, where, size, *val, rd_val);
+ } else {
+ wr_val = (rd_val & ~mask) |
+ ((*val << (8 * byte_offset)) & mask);
+ writel_relaxed(wr_val, config_base + word_offset);
+ wmb(); /* ensure config data is written to hardware register */
+
+ PCIE_DBG("%d:0x%02x + 0x%04x[%d] <- 0x%08x;"
+ " rd 0x%08x val 0x%08x\n", bus->number,
+ devfn, where, size, wr_val, rd_val, *val);
+ }
+
+ return 0;
+}
+
+static int msm_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+ int size, u32 *val)
+{
+ return msm_pcie_oper_conf(bus, devfn, RD, where, size, val);
+}
+
+static int msm_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+ int where, int size, u32 val)
+{
+ return msm_pcie_oper_conf(bus, devfn, WR, where, size, &val);
+}
+
+static struct pci_ops msm_pcie_ops = {
+ .read = msm_pcie_rd_conf,
+ .write = msm_pcie_wr_conf,
+};
+
+static int __devinit msm_pcie_gpio_init(void)
+{
+ int rc, i;
+ struct msm_pcie_gpio_info_t *info;
+
+ for (i = 0; i < MSM_PCIE_MAX_GPIO; i++) {
+ info = &msm_pcie_dev.gpio[i];
+
+ rc = gpio_request(info->num, info->name);
+ if (rc) {
+ pr_err("can't get gpio %s; %d\n", info->name, rc);
+ break;
+ }
+
+ rc = gpio_direction_output(info->num, 0);
+ if (rc) {
+ pr_err("can't set gpio direction %s; %d\n",
+ info->name, rc);
+ gpio_free(info->num);
+ break;
+ }
+ }
+
+ if (rc)
+ while (i--)
+ gpio_free(msm_pcie_dev.gpio[i].num);
+
+ return rc;
+}
+
+static void msm_pcie_gpio_deinit(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_GPIO; i++)
+ gpio_free(msm_pcie_dev.gpio[i].num);
+}
+
+static int __devinit msm_pcie_vreg_init(struct device *dev)
+{
+ int i, rc = 0;
+ struct regulator *vreg;
+ struct msm_pcie_vreg_info_t *info;
+
+ for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+ info = &msm_pcie_dev.vreg[i];
+
+ vreg = regulator_get(dev, info->name);
+ if (!vreg || IS_ERR(vreg)) {
+ rc = (PTR_ERR(vreg)) ? PTR_ERR(vreg) : -ENODEV;
+ pr_err("can't get %s; %d\n", info->name, rc);
+ break;
+ }
+
+ if (info->max_v) {
+ rc = regulator_set_voltage(vreg,
+ info->min_v, info->max_v);
+ if (rc) {
+ pr_err("can't set voltage %s; %d\n",
+ info->name, rc);
+ regulator_put(vreg);
+ break;
+ }
+ }
+
+ if (info->opt_mode) {
+ rc = regulator_set_optimum_mode(vreg, info->opt_mode);
+ if (rc < 0) {
+ pr_err("can't set mode %s; %d\n",
+ info->name, rc);
+ regulator_put(vreg);
+ break;
+ }
+ }
+
+ rc = regulator_enable(vreg);
+ if (rc) {
+ pr_err("can't enable %s, %d\n", info->name, rc);
+ regulator_put(vreg);
+ break;
+ }
+ info->hdl = vreg;
+ }
+
+ if (rc)
+ while (i--) {
+ regulator_disable(msm_pcie_dev.vreg[i].hdl);
+ regulator_put(msm_pcie_dev.vreg[i].hdl);
+ msm_pcie_dev.vreg[i].hdl = NULL;
+ }
+
+ return rc;
+}
+
+static void msm_pcie_vreg_deinit(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_VREG; i++) {
+ regulator_disable(msm_pcie_dev.vreg[i].hdl);
+ regulator_put(msm_pcie_dev.vreg[i].hdl);
+ msm_pcie_dev.vreg[i].hdl = NULL;
+ }
+}
+
+static int __devinit msm_pcie_clk_init(struct device *dev)
+{
+ int i, rc = 0;
+ struct clk *clk_hdl;
+ struct msm_pcie_clk_info_t *info;
+
+ for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+ info = &msm_pcie_dev.clk[i];
+
+ clk_hdl = clk_get(dev, info->name);
+ if (!clk_hdl || IS_ERR(clk_hdl)) {
+ rc = (PTR_ERR(clk_hdl)) ? PTR_ERR(clk_hdl) : -ENODEV;
+ pr_err("can't get clk %s; %d\n", info->name, rc);
+ break;
+ }
+ clk_prepare_enable(clk_hdl);
+ info->hdl = clk_hdl;
+ }
+
+ if (rc)
+ while (i--) {
+ clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+ clk_put(msm_pcie_dev.clk[i].hdl);
+ msm_pcie_dev.clk[i].hdl = NULL;
+ }
+
+ return rc;
+}
+
+static void msm_pcie_clk_deinit(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_CLK; i++) {
+ clk_disable_unprepare(msm_pcie_dev.clk[i].hdl);
+ clk_put(msm_pcie_dev.clk[i].hdl);
+ msm_pcie_dev.clk[i].hdl = NULL;
+ }
+}
+
+static void __devinit msm_pcie_config_controller(void)
+{
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+ struct msm_pcie_res_info_t *axi_bar = &dev->res[MSM_PCIE_RES_AXI_BAR];
+ struct msm_pcie_res_info_t *axi_conf = &dev->res[MSM_PCIE_RES_AXI_CONF];
+
+ /*
+ * program and enable address translation region 0 (device config
+ * address space); region type config;
+ * axi config address range to device config address range
+ */
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+ /* ensure that hardware locks the region before programming it */
+ wmb();
+
+ writel_relaxed(4, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+ writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+ writel_relaxed(axi_conf->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+ writel_relaxed(axi_conf->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+ writel_relaxed(MSM_PCIE_DEV_CFG_ADDR,
+ dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+ /* ensure that hardware registers the configuration */
+ wmb();
+
+ /*
+ * program and enable address translation region 2 (device resource
+ * address space); region type memory;
+ * axi device bar address range to device bar address range
+ */
+ writel_relaxed(2, dev->pcie20 + PCIE20_PLR_IATU_VIEWPORT);
+ /* ensure that hardware locks the region before programming it */
+ wmb();
+
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_CTRL1);
+ writel_relaxed(BIT(31), dev->pcie20 + PCIE20_PLR_IATU_CTRL2);
+ writel_relaxed(axi_bar->start, dev->pcie20 + PCIE20_PLR_IATU_LBAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UBAR);
+ writel_relaxed(axi_bar->end, dev->pcie20 + PCIE20_PLR_IATU_LAR);
+ writel_relaxed(MSM_PCIE_DEV_BAR_ADDR,
+ dev->pcie20 + PCIE20_PLR_IATU_LTAR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_PLR_IATU_UTAR);
+ /* ensure that hardware registers the configuration */
+ wmb();
+}
+
+static int __devinit msm_pcie_get_resources(struct platform_device *pdev)
+{
+ int i, rc = 0;
+ struct resource *res;
+ struct msm_pcie_res_info_t *info;
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+
+ for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+ info = &dev->res[i];
+
+ res = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, info->name);
+ if (!res) {
+ pr_err("can't get %s resource\n", info->name);
+ rc = -ENOMEM;
+ break;
+ }
+
+ info->base = ioremap(res->start, resource_size(res));
+ if (!info->base) {
+ pr_err("can't remap %s\n", info->name);
+ rc = -ENOMEM;
+ break;
+ }
+
+ info->start = res->start;
+ info->end = res->end;
+ }
+
+ if (rc) {
+ while (i--) {
+ iounmap(dev->res[i].base);
+ dev->res[i].base = NULL;
+ }
+ } else {
+ dev->parf = dev->res[MSM_PCIE_RES_PARF].base;
+ dev->elbi = dev->res[MSM_PCIE_RES_ELBI].base;
+ dev->pcie20 = dev->res[MSM_PCIE_RES_PCIE20].base;
+ dev->axi_conf = dev->res[MSM_PCIE_RES_AXI_CONF].base;
+ }
+
+ return rc;
+}
+
+static void __devexit msm_pcie_release_resources(void)
+{
+ int i;
+
+ for (i = 0; i < MSM_PCIE_MAX_RES; i++) {
+ iounmap(msm_pcie_dev.res[i].base);
+ msm_pcie_dev.res[i].base = NULL;
+ }
+
+ msm_pcie_dev.parf = NULL;
+ msm_pcie_dev.elbi = NULL;
+ msm_pcie_dev.pcie20 = NULL;
+ msm_pcie_dev.axi_conf = NULL;
+}
+
+static int __devinit msm_pcie_setup(int nr, struct pci_sys_data *sys)
+{
+ int rc;
+ struct msm_pcie_dev_t *dev = &msm_pcie_dev;
+ uint32_t val;
+
+ PCIE_DBG("bus %d\n", nr);
+ if (nr != 0)
+ return 0;
+
+ /* assert PCIe reset link to keep EP in reset */
+ gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+ dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+ /* enable power */
+ rc = msm_pcie_vreg_init(&dev->pdev->dev);
+ if (rc)
+ goto out;
+
+ /* assert PCIe PARF reset while powering the core */
+ msm_pcie_write_mask(PCIE_RESET, 0, BIT(2));
+
+ /* enable clocks */
+ rc = msm_pcie_clk_init(&dev->pdev->dev);
+ if (rc)
+ goto clk_fail;
+
+ /* enable pcie power; wait 3ms for clock to stabilize */
+ gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_PWR_EN].num,
+ dev->gpio[MSM_PCIE_GPIO_PWR_EN].on);
+ usleep(3000);
+
+ /*
+ * de-assert PCIe PARF reset;
+ * wait 1us before accessing PARF registers
+ */
+ msm_pcie_write_mask(PCIE_RESET, BIT(2), 0);
+ udelay(1);
+
+ /* enable PCIe clocks and resets */
+ msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
+
+ /* PARF programming */
+ writel_relaxed(0x282828, dev->parf + PCIE20_PARF_PCS_DEEMPH);
+ writel_relaxed(0x7F7F, dev->parf + PCIE20_PARF_PCS_SWING);
+ writel_relaxed((4<<24), dev->parf + PCIE20_PARF_CONFIG_BITS);
+ /* ensure that hardware registers the PARF configuration */
+ wmb();
+
+ /* enable reference clock */
+ msm_pcie_write_mask(dev->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
+
+ /* enable access to PCIe slave port on system fabric */
+ writel_relaxed(BIT(4), PCIE_SFAB_AXI_S5_FCLK_CTL);
+ /* ensure that access is enabled before proceeding */
+ wmb();
+
+ /* de-assert PICe PHY, Core, POR and AXI clk domain resets */
+ msm_pcie_write_mask(PCIE_RESET, BIT(5), 0);
+ msm_pcie_write_mask(PCIE_RESET, BIT(4), 0);
+ msm_pcie_write_mask(PCIE_RESET, BIT(3), 0);
+ msm_pcie_write_mask(PCIE_RESET, BIT(0), 0);
+
+ /* wait 150ms for clock acquisition */
+ udelay(150);
+
+ /* de-assert PCIe reset link to bring EP out of reset */
+ gpio_set_value_cansleep(dev->gpio[MSM_PCIE_GPIO_RST_N].num,
+ !dev->gpio[MSM_PCIE_GPIO_RST_N].on);
+
+ /* enable link training */
+ msm_pcie_write_mask(dev->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
+
+ /* poll for link to come up for upto 100ms */
+ rc = readl_poll_timeout(
+ (msm_pcie_dev.pcie20 + PCIE20_CAP_LINKCTRLSTATUS),
+ val, (val & BIT(29)), 10000, 100000);
+ if (rc) {
+ pr_err("link initialization failed\n");
+ goto link_fail;
+ } else
+ pr_info("link initialized\n");
+
+ msm_pcie_config_controller();
+ rc = msm_pcie_irq_init(dev);
+ if (!rc)
+ goto out;
+
+link_fail:
+ msm_pcie_clk_deinit();
+clk_fail:
+ msm_pcie_vreg_deinit();
+out:
+ return (rc) ? 0 : 1;
+}
+
+static struct pci_bus __devinit *msm_pcie_scan_bus(int nr,
+ struct pci_sys_data *sys)
+{
+ struct pci_bus *bus = NULL;
+
+ PCIE_DBG("bus %d\n", nr);
+ if (nr == 0)
+ bus = pci_scan_bus(sys->busnr, &msm_pcie_ops, sys);
+
+ return bus;
+}
+
+static int __devinit msm_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ PCIE_DBG("slot %d pin %d\n", slot, pin);
+ return (pin <= 4) ? (PCIE20_INTA + pin - 1) : 0;
+}
+
+static struct hw_pci msm_pci __devinitdata = {
+ .nr_controllers = 1,
+ .swizzle = pci_std_swizzle,
+ .setup = msm_pcie_setup,
+ .scan = msm_pcie_scan_bus,
+ .map_irq = msm_pcie_map_irq,
+};
+
+static int __devinit msm_pcie_probe(struct platform_device *pdev)
+{
+ const struct msm_pcie_platform *pdata;
+ int rc;
+
+ PCIE_DBG("\n");
+
+ msm_pcie_dev.pdev = pdev;
+ pdata = pdev->dev.platform_data;
+ msm_pcie_dev.gpio = pdata->gpio;
+ msm_pcie_dev.vreg = msm_pcie_vreg_info;
+ msm_pcie_dev.clk = msm_pcie_clk_info;
+ msm_pcie_dev.res = msm_pcie_res_info;
+
+ rc = msm_pcie_get_resources(msm_pcie_dev.pdev);
+ if (rc)
+ return rc;
+
+ rc = msm_pcie_gpio_init();
+ if (rc) {
+ msm_pcie_release_resources();
+ return rc;
+ }
+
+ /* kick start ARM PCI configuration framework */
+ pci_common_init(&msm_pci);
+ return 0;
+}
+
+static int __devexit msm_pcie_remove(struct platform_device *pdev)
+{
+ PCIE_DBG("\n");
+
+ msm_pcie_irq_deinit(&msm_pcie_dev);
+ msm_pcie_vreg_deinit();
+ msm_pcie_clk_deinit();
+ msm_pcie_gpio_deinit();
+ msm_pcie_release_resources();
+
+ msm_pcie_dev.pdev = NULL;
+ msm_pcie_dev.vreg = NULL;
+ msm_pcie_dev.clk = NULL;
+ msm_pcie_dev.gpio = NULL;
+ return 0;
+}
+
+static struct platform_driver msm_pcie_driver = {
+ .probe = msm_pcie_probe,
+ .remove = __devexit_p(msm_pcie_remove),
+ .driver = {
+ .name = "msm_pcie",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_pcie_init(void)
+{
+ PCIE_DBG("\n");
+ return platform_driver_register(&msm_pcie_driver);
+}
+subsys_initcall(msm_pcie_init);
+
+/* RC do not represent the right class; set it to PCI_CLASS_BRIDGE_PCI */
+static void __devinit msm_pcie_fixup_header(struct pci_dev *dev)
+{
+ PCIE_DBG("hdr_type %d\n", dev->hdr_type);
+ if (dev->hdr_type == 1)
+ dev->class = (dev->class & 0xff) | (PCI_CLASS_BRIDGE_PCI << 8);
+}
+DECLARE_PCI_FIXUP_HEADER(PCIE_VENDOR_ID_RCP, PCIE_DEVICE_ID_RCP,
+ msm_pcie_fixup_header);
+
+/*
+ * actual physical (BAR) address of the device resources starts from 0x10xxxxxx;
+ * the system axi address for the device resources starts from 0x08xxxxxx;
+ * correct the device resource structure here; address translation unit handles
+ * the required translations
+ */
+static void __devinit msm_pcie_fixup_final(struct pci_dev *dev)
+{
+ int i;
+
+ PCIE_DBG("vendor 0x%x 0x%x\n", dev->vendor, dev->device);
+ for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ if (dev->resource[i].start & 0xFF000000) {
+ dev->resource[i].start &= 0x00FFFFFF;
+ dev->resource[i].start |= 0x08000000;
+ dev->resource[i].end &= 0x00FFFFFF;
+ dev->resource[i].end |= 0x08000000;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, msm_pcie_fixup_final);
diff --git a/arch/arm/mach-msm/pcie.h b/arch/arm/mach-msm/pcie.h
new file mode 100644
index 0000000..4866ec5
--- /dev/null
+++ b/arch/arm/mach-msm/pcie.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_PCIE_H
+#define __ARCH_ARM_MACH_MSM_PCIE_H
+
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <mach/msm_pcie.h>
+
+#define MSM_PCIE_MAX_VREG 4
+#define MSM_PCIE_MAX_CLK 3
+
+#define PCIE_DBG(x...) do { \
+ if (msm_pcie_get_debug_mask()) \
+ pr_info(x); \
+ } while (0)
+
+/* voltage regulator info structrue */
+struct msm_pcie_vreg_info_t {
+ struct regulator *hdl;
+ char *name;
+ uint32_t max_v;
+ uint32_t min_v;
+ uint32_t opt_mode;
+};
+
+/* clock info structure */
+struct msm_pcie_clk_info_t {
+ struct clk *hdl;
+ char *name;
+};
+
+/* resource info structure */
+struct msm_pcie_res_info_t {
+ char *name;
+ uint32_t start;
+ uint32_t end;
+ void __iomem *base;
+};
+
+/* msm pcie device structure */
+struct msm_pcie_dev_t {
+ struct platform_device *pdev;
+
+ struct msm_pcie_vreg_info_t *vreg;
+ struct msm_pcie_gpio_info_t *gpio;
+ struct msm_pcie_clk_info_t *clk;
+ struct msm_pcie_res_info_t *res;
+
+ void __iomem *parf;
+ void __iomem *elbi;
+ void __iomem *pcie20;
+ void __iomem *axi_conf;
+};
+
+extern uint32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev);
+extern void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev);
+extern int msm_pcie_get_debug_mask(void);
+
+#endif
diff --git a/arch/arm/mach-msm/pcie_irq.c b/arch/arm/mach-msm/pcie_irq.c
new file mode 100644
index 0000000..df100db
--- /dev/null
+++ b/arch/arm/mach-msm/pcie_irq.c
@@ -0,0 +1,170 @@
+/* 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.
+ */
+
+/*
+ * MSM PCIe controller IRQ driver.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/pci.h>
+#include <mach/irqs.h>
+
+#include "pcie.h"
+
+/* Any address will do here, as it won't be dereferenced */
+#define MSM_PCIE_MSI_PHY 0xa0000000
+
+#define PCIE20_MSI_CTRL_ADDR (0x820)
+#define PCIE20_MSI_CTRL_UPPER_ADDR (0x824)
+#define PCIE20_MSI_CTRL_INTR_EN (0x828)
+#define PCIE20_MSI_CTRL_INTR_MASK (0x82C)
+#define PCIE20_MSI_CTRL_INTR_STATUS (0x830)
+
+#define PCIE20_MSI_CTRL_MAX 8
+
+static DECLARE_BITMAP(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+
+irqreturn_t handle_msi_irq(int irq, void *data)
+{
+ int i, j;
+ unsigned long val;
+ struct msm_pcie_dev_t *dev = data;
+ void __iomem *ctrl_status;
+
+ /* check for set bits, clear it by setting that bit
+ and trigger corresponding irq */
+ for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++) {
+ ctrl_status = dev->pcie20 +
+ PCIE20_MSI_CTRL_INTR_STATUS + (i * 12);
+
+ val = readl_relaxed(ctrl_status);
+ while (val) {
+ j = find_first_bit(&val, 32);
+ writel_relaxed(BIT(j), ctrl_status);
+ /* ensure that interrupt is cleared (acked) */
+ wmb();
+
+ generic_handle_irq(MSM_PCIE_MSI_INT(j + (32 * i)));
+ val = readl_relaxed(ctrl_status);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+uint32_t __devinit msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
+{
+ int i, rc;
+
+ PCIE_DBG("\n");
+
+ /* program MSI controller and enable all interrupts */
+ writel_relaxed(MSM_PCIE_MSI_PHY, dev->pcie20 + PCIE20_MSI_CTRL_ADDR);
+ writel_relaxed(0, dev->pcie20 + PCIE20_MSI_CTRL_UPPER_ADDR);
+
+ for (i = 0; i < PCIE20_MSI_CTRL_MAX; i++)
+ writel_relaxed(~0, dev->pcie20 +
+ PCIE20_MSI_CTRL_INTR_EN + (i * 12));
+
+ /* ensure that hardware is configured before proceeding */
+ wmb();
+
+ /* register handler for physical MSI interrupt line */
+ rc = request_irq(PCIE20_INT_MSI, handle_msi_irq, IRQF_TRIGGER_RISING,
+ "msm_pcie_msi", dev);
+ if (rc)
+ pr_err("Unable to allocate msi interrupt\n");
+
+ return rc;
+}
+
+void msm_pcie_irq_deinit(struct msm_pcie_dev_t *dev)
+{
+ free_irq(PCIE20_INT_MSI, dev);
+}
+
+void msm_pcie_destroy_irq(unsigned int irq)
+{
+ int pos = irq - MSM_PCIE_MSI_INT(0);
+
+ dynamic_irq_cleanup(irq);
+ clear_bit(pos, msi_irq_in_use);
+}
+
+/* hookup to linux pci msi framework */
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ PCIE_DBG("irq %d deallocated\n", irq);
+ msm_pcie_destroy_irq(irq);
+}
+
+static void msm_pcie_msi_nop(struct irq_data *d)
+{
+ return;
+}
+
+static struct irq_chip pcie_msi_chip = {
+ .name = "msm-pcie-msi",
+ .irq_ack = msm_pcie_msi_nop,
+ .irq_enable = unmask_msi_irq,
+ .irq_disable = mask_msi_irq,
+ .irq_mask = mask_msi_irq,
+ .irq_unmask = unmask_msi_irq,
+};
+
+static int msm_pcie_create_irq(void)
+{
+ int irq, pos;
+
+again:
+ pos = find_first_zero_bit(msi_irq_in_use, NR_PCIE_MSI_IRQS);
+ irq = MSM_PCIE_MSI_INT(pos);
+ if (irq >= (MSM_PCIE_MSI_INT(0) + NR_PCIE_MSI_IRQS))
+ return -ENOSPC;
+
+ if (test_and_set_bit(pos, msi_irq_in_use))
+ goto again;
+
+ dynamic_irq_init(irq);
+ return irq;
+}
+
+/* hookup to linux pci msi framework */
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
+{
+ int irq;
+ struct msi_msg msg;
+
+ irq = msm_pcie_create_irq();
+ if (irq < 0)
+ return irq;
+
+ PCIE_DBG("irq %d allocated\n", irq);
+
+ irq_set_msi_desc(irq, desc);
+
+ /* write msi vector and data */
+ msg.address_hi = 0;
+ msg.address_lo = MSM_PCIE_MSI_PHY;
+ msg.data = irq - MSM_PCIE_MSI_INT(0);
+ write_msi_msg(irq, &msg);
+
+ irq_set_chip_and_handler(irq, &pcie_msi_chip, handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ return 0;
+}
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index fa9159e..0ecea85 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -350,13 +350,14 @@
}
mutex_lock(&pil->lock);
- if (!pil->count++) {
+ if (!pil->count) {
ret = load_image(pil);
if (ret) {
retval = ERR_PTR(ret);
goto err_load;
}
}
+ pil->count++;
pil_set_state(pil, PIL_ONLINE);
mutex_unlock(&pil->lock);
out:
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 668e0c2..b66729b 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -75,8 +75,10 @@
if (machine_is_apq8064_sim())
writel_relaxed(0xf0000, base_ptr+0x04);
- if (machine_is_copper_sim())
- writel_relaxed(0x9, base_ptr+0x04);
+ if (machine_is_copper_sim()) {
+ writel_relaxed(0x800, base_ptr+0x04);
+ writel_relaxed(0x3FFF, base_ptr+0x14);
+ }
mb();
iounmap(base_ptr);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index a22b175..cc17ceb 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -29,6 +29,7 @@
#include <linux/wakelock.h>
#include <linux/delay.h>
#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
#include <mach/system.h>
#include <asm/cacheflush.h>
#include <asm/hardware/gic.h>
@@ -612,6 +613,7 @@
*****************************************************************************/
static struct msm_rpmrs_limits *msm_pm_idle_rs_limits;
+static bool msm_pm_use_qtimer;
static void msm_pm_swfi(void)
{
@@ -637,9 +639,9 @@
{
bool collapsed = 0;
- l2x0_suspend();
+ l2cc_suspend();
collapsed = msm_pm_collapse();
- l2x0_resume(collapsed);
+ l2cc_resume();
return collapsed;
}
@@ -748,12 +750,28 @@
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
- if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
- pr_info("CPU%u: %s: restore clock rate to %lu\n",
- cpu, __func__, saved_acpuclk_rate);
- if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
- pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
- cpu, __func__, saved_acpuclk_rate);
+ if (cpu_online(cpu)) {
+ if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
+ pr_info("CPU%u: %s: restore clock rate to %lu\n",
+ cpu, __func__, saved_acpuclk_rate);
+ if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+ pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
+ cpu, __func__, saved_acpuclk_rate);
+ } else {
+ unsigned int gic_dist_enabled;
+ unsigned int gic_dist_pending;
+ gic_dist_enabled = readl_relaxed(
+ MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_CLEAR);
+ gic_dist_pending = readl_relaxed(
+ MSM_QGIC_DIST_BASE + GIC_DIST_PENDING_SET);
+ mb();
+ gic_dist_pending &= gic_dist_enabled;
+
+ if (gic_dist_pending)
+ pr_err("CPU %d interrupted during hotplug.Pending int 0x%x\n",
+ cpu, gic_dist_pending);
+ }
+
avs_reset_delays(avsdscr_setting);
msm_pm_config_hw_after_power_up();
@@ -765,6 +783,28 @@
return collapsed;
}
+static void msm_pm_qtimer_available(void)
+{
+ if (machine_is_copper())
+ msm_pm_use_qtimer = true;
+}
+
+static int64_t msm_pm_timer_enter_idle(void)
+{
+ if (msm_pm_use_qtimer)
+ return ktime_to_ns(tick_nohz_get_sleep_length());
+
+ return msm_timer_enter_idle();
+}
+
+static void msm_pm_timer_exit_idle(bool timer_halted)
+{
+ if (msm_pm_use_qtimer)
+ return;
+
+ msm_timer_exit_idle((int) timer_halted);
+}
+
/******************************************************************************
* External Idle/Suspend Functions
*****************************************************************************/
@@ -919,7 +959,7 @@
break;
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
- int64_t timer_expiration = msm_timer_enter_idle();
+ int64_t timer_expiration = 0;
bool timer_halted = false;
uint32_t sleep_delay;
int ret;
@@ -927,6 +967,8 @@
(sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
int collapsed;
+ timer_expiration = msm_pm_timer_enter_idle();
+
sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
if (sleep_delay == 0) /* 0 would mean infinite time */
@@ -944,8 +986,8 @@
msm_rpmrs_exit_sleep(msm_pm_idle_rs_limits, true,
notify_rpm, collapsed);
}
+ msm_pm_timer_exit_idle(timer_halted);
- msm_timer_exit_idle((int) timer_halted);
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
#endif
@@ -1132,7 +1174,6 @@
} else
time = 0;
}
-
msm_pm_add_stat(MSM_PM_STAT_SUSPEND, time);
#endif /* CONFIG_MSM_IDLE_STATS */
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
@@ -1176,11 +1217,10 @@
pgd_t *pc_pgd;
pmd_t *pmd;
unsigned long pmdval;
- unsigned int cpu;
#ifdef CONFIG_MSM_IDLE_STATS
+ unsigned int cpu;
struct proc_dir_entry *d_entry;
#endif
-
/* Page table for cores to come back up safely. */
pc_pgd = pgd_alloc(&init_mm);
if (!pc_pgd)
@@ -1258,10 +1298,12 @@
}
#endif /* CONFIG_MSM_IDLE_STATS */
+
msm_pm_mode_sysfs_add();
msm_spm_allow_x_cpu_set_vdd(false);
suspend_set_ops(&msm_pm_ops);
+ msm_pm_qtimer_available();
msm_cpuidle_init();
return 0;
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index b5f0fdc..f6105af1 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -15,6 +15,10 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#include <mach/msm_iomap.h>
#include <mach/socinfo.h>
#include <asm/mach-types.h>
@@ -200,3 +204,69 @@
return ret;
}
+
+static int __devinit msm_pm_boot_probe(struct platform_device *pdev)
+{
+ struct msm_pm_boot_platform_data pdata;
+ char *key = NULL;
+ uint32_t val = 0;
+ int ret = 0;
+ int flag = 0;
+
+ key = "qcom,mode";
+ ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+ if (ret) {
+ pr_err("Unable to read boot mode Err(%d).\n", ret);
+ return -ENODEV;
+ }
+ pdata.mode = val;
+
+ key = "qcom,phy-addr";
+ ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+ if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS)
+ goto fail;
+ if (!ret) {
+ pdata.p_addr = val;
+ flag++;
+ }
+
+ key = "qcom,virt-addr";
+ ret = of_property_read_u32(pdev->dev.of_node, key, &val);
+ if (ret && pdata.mode == MSM_PM_BOOT_CONFIG_RESET_VECTOR_VIRT)
+ goto fail;
+ if (!ret) {
+ pdata.v_addr = (void *)val;
+ flag++;
+ }
+
+ if (pdata.mode == MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR && (flag != 2)) {
+ key = "addresses for boot remap";
+ goto fail;
+ }
+
+ return msm_pm_boot_init(&pdata);
+
+fail:
+ pr_err("Error reading %s\n", key);
+ return -EFAULT;
+}
+
+static struct of_device_id msm_pm_match_table[] = {
+ {.compatible = "qcom,pm-boot"},
+ {},
+};
+
+static struct platform_driver msm_pm_boot_driver = {
+ .probe = msm_pm_boot_probe,
+ .driver = {
+ .name = "pm-boot",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_pm_match_table,
+ },
+};
+
+static int __init msm_pm_boot_module_init(void)
+{
+ return platform_driver_register(&msm_pm_boot_driver);
+}
+module_init(msm_pm_boot_module_init);
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 39e321a..f4bfe23 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -465,7 +465,8 @@
__raw_writel(1, APPS_PWRDOWN);
mb();
} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
- cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+ cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
+ cpu_is_msm7x25ab()) {
__raw_writel(0x7, APPS_CLK_SLEEP_EN);
mb();
__raw_writel(1, APPS_PWRDOWN);
@@ -591,7 +592,8 @@
__raw_writel(0x0f, APPS_CLK_SLEEP_EN);
mb();
} else if (cpu_is_msm7x27a() || cpu_is_msm7x27aa() ||
- cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+ cpu_is_msm7x25a() || cpu_is_msm7x25aa() ||
+ cpu_is_msm7x25ab()) {
__raw_writel(0x7, APPS_CLK_SLEEP_EN);
mb();
}
@@ -1192,7 +1194,7 @@
#endif
#ifdef CONFIG_CACHE_L2X0
- l2x0_suspend();
+ l2cc_suspend();
#endif
collapsed = msm_pm_collapse();
@@ -1203,21 +1205,23 @@
*/
if (cpu_is_msm8625()) {
/*
- * on system reset default value of MPA5_GDFS_CNT_VAL
- * is = 0xFF, later power driver reprogrammed this
- * as: 0x000300FF. Currently based on the value of
- * MPA5_GDFS_CNT_VAL register decide whether it is
- * a modem early exit are not.
+ * on system reset, default value of MPA5_GDFS_CNT_VAL
+ * is = 0x0, later modem reprogram this value to
+ * 0x00030004. Once APPS did a power collapse and
+ * coming out of it expected value of this register
+ * always be 0x00030004. Incase if APPS sees the value
+ * as 0x00030002 consider this case as a modem early
+ * exit.
*/
val = __raw_readl(MSM_CFG_CTL_BASE + 0x38);
- if (val != 0xFF)
- modem_early_exit = 1;
- else
+ if (val != 0x00030002)
power_collapsed = 1;
+ else
+ modem_early_exit = 1;
}
#ifdef CONFIG_CACHE_L2X0
- l2x0_resume(collapsed);
+ l2cc_resume();
#endif
msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1434,14 +1438,14 @@
#ifdef CONFIG_CACHE_L2X0
if (!cpu_is_msm8625())
- l2x0_suspend();
+ l2cc_suspend();
#endif
collapsed = msm_pm_collapse();
#ifdef CONFIG_CACHE_L2X0
if (!cpu_is_msm8625())
- l2x0_resume(collapsed);
+ l2cc_resume();
#endif
msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1950,11 +1954,14 @@
clean_caches((unsigned long)&target_type, sizeof(target_type),
virt_to_phys(&target_type));
- /* Override the DBGNOPOWERDN for each cpu in
- * MPA5_GDFS_CNT_VAL register
+ /*
+ * Configure the MPA5_GDFS_CNT_VAL register for
+ * DBGPWRUPEREQ_OVERRIDE[17:16] = Override the
+ * DBGNOPOWERDN for each cpu.
+ * MPA5_GDFS_CNT_VAL[9:0] = Delay counter for
+ * GDFS control.
*/
- val = __raw_readl((MSM_CFG_CTL_BASE + 0x38));
- val = val | 0x00030000;
+ val = 0x00030002;
__raw_writel(val, (MSM_CFG_CTL_BASE + 0x38));
}
diff --git a/arch/arm/mach-msm/qdsp5/adsp.c b/arch/arm/mach-msm/qdsp5/adsp.c
index 71e0409..6f5ccbf 100644
--- a/arch/arm/mach-msm/qdsp5/adsp.c
+++ b/arch/arm/mach-msm/qdsp5/adsp.c
@@ -34,6 +34,7 @@
#include <linux/wait.h>
#include <linux/wakelock.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <mach/debug_mm.h>
#include <linux/debugfs.h>
@@ -71,6 +72,10 @@
static uint32_t rpc_adsp_rtos_mtoa_vers_comp;
static DEFINE_MUTEX(adsp_open_lock);
+static struct workqueue_struct *msm_adsp_probe_work_queue;
+static void adsp_probe_work(struct work_struct *work);
+static DECLARE_WORK(msm_adsp_probe_work, adsp_probe_work);
+
/* protect interactions with the ADSP command/message queue */
static spinlock_t adsp_cmd_lock;
static spinlock_t adsp_write_lock;
@@ -1230,8 +1235,8 @@
goto fail_rpc_register;
}
- /* start the kernel thread to process the callbacks */
- kthread_run(adsp_rpc_thread, NULL, "kadspd");
+ /* schedule start of kernel thread later using work queue */
+ queue_work(msm_adsp_probe_work_queue, &msm_adsp_probe_work);
for (i = 0; i < count; i++) {
struct msm_adsp_module *mod = adsp_modules + i;
@@ -1271,6 +1276,13 @@
kfree(adsp_info.init_info_ptr);
return rc;
}
+
+static void adsp_probe_work(struct work_struct *work)
+{
+ /* start the kernel thread to process the callbacks */
+ kthread_run(adsp_rpc_thread, NULL, "kadspd");
+}
+
#ifdef CONFIG_DEBUG_FS
static int get_parameters(char *buf, long int *param1, int num_of_par)
{
@@ -1433,6 +1445,9 @@
rpc_adsp_rtos_mtoa_vers_comp = 0x00030001;
#endif
+ msm_adsp_probe_work_queue = create_workqueue("msm_adsp_probe");
+ if (msm_adsp_probe_work_queue == NULL)
+ return -ENOMEM;
msm_adsp_driver.driver.name = msm_adsp_driver_name;
rc = platform_driver_register(&msm_adsp_driver);
MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac.c b/arch/arm/mach-msm/qdsp5/audio_aac.c
index de756eb..8cae321 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac.c
@@ -39,7 +39,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -126,8 +125,8 @@
/* ---- End of Host PCM section */
struct msm_adsp_module *audplay;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
/* configuration to use on next enable */
uint32_t out_sample_rate;
@@ -1509,9 +1508,9 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audaac_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
@@ -1701,10 +1700,7 @@
MM_DBG("pmemsz = %d\n", pmem_sz);
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, \
freeing instance 0x%08x\n",
@@ -1715,7 +1711,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1737,29 +1733,26 @@
MM_ERR("could not allocate read buffers, freeing instance \
0x%08x\n", (int)audio);
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
goto done;
}
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->read_phys,
- PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_read = ioremap(audio->read_phys,
+ PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read buffers, freeing instance \
0x%08x\n", (int)audio);
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
free_contiguous_memory_by_paddr(audio->read_phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
goto done;
}
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->read_phys, (int)audio->read_data);
@@ -1880,9 +1873,9 @@
done:
return rc;
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_aac_in.c b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
index 456a8ff..ab9f15c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_aac_in.c
@@ -40,7 +40,6 @@
#include <mach/msm_rpcrouter.h>
#include <mach/msm_memtypes.h>
#include <mach/iommu.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/iommu_domains.h>
#include <mach/msm_adsp.h>
@@ -141,8 +140,8 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int opened;
int enabled;
@@ -1249,13 +1248,13 @@
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -1355,16 +1354,15 @@
audio->phys = allocate_contiguous_ebi_nomap(dma_size, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, dma_size,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(
+ audio->phys, dma_size);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map DMA buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto evt_error;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate read buffers\n");
rc = -ENOMEM;
@@ -1380,23 +1378,22 @@
if (!audio->out_phys) {
MM_ERR("could not allocate write buffers\n");
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address\n");
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
free_contiguous_memory_by_paddr(\
audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb.c b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
index d66a270..1ad941f 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb.c
@@ -47,7 +47,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -138,8 +137,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
@@ -979,12 +978,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
rc = -ENOMEM;
@@ -994,7 +991,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1298,10 +1295,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrnb_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1494,10 +1491,8 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, freeing \
instance 0x%08x freeing\n", (int)audio);
@@ -1507,7 +1502,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
}
@@ -1595,7 +1590,7 @@
done:
return rc;
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
index 2b4ead9..bec1d4c 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrnb_in.c
@@ -2,7 +2,7 @@
*
* amrnb encoder device
*
- * Copyright (c) 2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 2011-2012 Code Aurora Forum. All rights reserved.
*
* This code is based in part on arch/arm/mach-msm/qdsp5/audio_in.c, which is
* Copyright (C) 2008 Google, Inc.
@@ -44,7 +44,6 @@
#include <mach/msm_rpcrouter.h>
#include <mach/msm_memtypes.h>
#include <mach/iommu.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/iommu_domains.h>
#include <mach/msm_adsp.h>
@@ -146,7 +145,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_write;
uint8_t opened;
uint8_t enabled;
@@ -822,13 +821,15 @@
}
/* Allow only single frame */
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- if (cfg.buffer_size != (FRAME_SIZE - 8))
+ if (cfg.buffer_size != (FRAME_SIZE - 8)) {
rc = -EINVAL;
break;
+ }
} else {
- if (cfg.buffer_size != (AMRNB_FRAME_SIZE + 14))
+ if (cfg.buffer_size != (AMRNB_FRAME_SIZE + 14)) {
rc = -EINVAL;
break;
+ }
}
audio->buffer_size = cfg.buffer_size;
break;
@@ -1206,7 +1207,7 @@
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
@@ -1330,9 +1331,8 @@
dma_size, audio->data, audio->phys);
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address\n");
rc = -ENOMEM;
@@ -1342,7 +1342,7 @@
audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys,
(uint32_t)audio->out_data);
diff --git a/arch/arm/mach-msm/qdsp5/audio_amrwb.c b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
index b566c60..0d3b67a 100644
--- a/arch/arm/mach-msm/qdsp5/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5/audio_amrwb.c
@@ -46,7 +46,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -139,8 +138,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
int wflush; /* Write flush */
@@ -975,12 +974,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map mem for read buf\n");
rc = -ENOMEM;
@@ -989,7 +986,7 @@
} else {
uint8_t index;
uint32_t offset = 0;
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
audio->pcm_feedback = 1;
audio->buf_refresh = 0;
audio->pcm_buf_count =
@@ -1366,10 +1363,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrwb_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1557,10 +1554,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, freeing \
@@ -1571,7 +1565,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1664,7 +1658,7 @@
done:
return rc;
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc.c b/arch/arm/mach-msm/qdsp5/audio_evrc.c
index 86035db..7479e36 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc.c
@@ -41,7 +41,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -135,8 +134,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -965,12 +964,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map mem"
" for read buf\n");
@@ -981,7 +978,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1290,10 +1287,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audevrc_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1485,10 +1482,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, freeing \
instance 0x%08x\n", (int)audio);
@@ -1498,7 +1492,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1588,7 +1582,7 @@
done:
return rc;
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
index 0bdbf5d..05a16da 100644
--- a/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_evrc_in.c
@@ -41,7 +41,6 @@
#include <mach/msm_rpcrouter.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include "audmgr.h"
@@ -144,8 +143,8 @@
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int opened;
int enabled;
@@ -800,13 +799,15 @@
}
/* Allow only single frame */
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- if (cfg.buffer_size != (FRAME_SIZE - 8))
+ if (cfg.buffer_size != (FRAME_SIZE - 8)) {
rc = -EINVAL;
break;
+ }
} else {
- if (cfg.buffer_size != (EVRC_FRAME_SIZE + 14))
+ if (cfg.buffer_size != (EVRC_FRAME_SIZE + 14)) {
rc = -EINVAL;
break;
+ }
}
audio->buffer_size = cfg.buffer_size;
break;
@@ -1189,12 +1190,12 @@
audio->opened = 0;
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -1295,17 +1296,14 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, dma_size,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, dma_size);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map physical address\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto evt_error;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1316,25 +1314,23 @@
if (!audio->out_phys) {
MM_ERR("could not allocate physical write buffers\n");
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address\n");
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
free_contiguous_memory_by_paddr(\
audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
diff --git a/arch/arm/mach-msm/qdsp5/audio_lpa.c b/arch/arm/mach-msm/qdsp5/audio_lpa.c
index dab53dc..a7c2543 100644
--- a/arch/arm/mach-msm/qdsp5/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp5/audio_lpa.c
@@ -46,7 +46,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -553,7 +552,9 @@
struct audpcm_buffer_node *buf_node;
struct list_head *ptr, *next;
union msm_audio_event_payload payload;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
MM_DBG("\n"); /* Macro prints the file name and function */
list_for_each_safe(ptr, next, &audio->out_queue) {
buf_node = list_entry(ptr, struct audpcm_buffer_node, list);
@@ -566,6 +567,7 @@
audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
audio->out_needed = 0;
atomic_set(&audio->out_bytes, 0);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audio_ioport_reset(struct audio *audio)
{
@@ -1221,7 +1223,7 @@
audpcm_reset_event_queue(audio);
MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5/audio_mp3.c b/arch/arm/mach-msm/qdsp5/audio_mp3.c
index f6fa62a..7f72e25 100644
--- a/arch/arm/mach-msm/qdsp5/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5/audio_mp3.c
@@ -39,7 +39,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/msm_memtypes.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
@@ -202,8 +201,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
uint32_t drv_status;
int mfield; /* meta field embedded in data */
@@ -837,7 +836,9 @@
struct audmp3_buffer_node *buf_node;
struct list_head *ptr, *next;
union msm_audio_event_payload payload;
+ unsigned long flags;
+ spin_lock_irqsave(&audio->dsp_lock, flags);
MM_DBG("\n"); /* Macro prints the file name and function */
list_for_each_safe(ptr, next, &audio->out_queue) {
buf_node = list_entry(ptr, struct audmp3_buffer_node, list);
@@ -850,6 +851,7 @@
audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
audio->out_needed = 0;
atomic_set(&audio->out_bytes, 0);
+ spin_unlock_irqrestore(&audio->dsp_lock, flags);
}
static void audio_flush(struct audio *audio)
@@ -1488,12 +1490,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
@@ -1504,7 +1504,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1979,11 +1979,11 @@
audmp3_reset_event_queue(audio);
MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -2178,10 +2178,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write \
buffers, freeing instance \
@@ -2193,7 +2191,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr\
0x%08x\n", audio->phys,\
(int)audio->data);
@@ -2321,7 +2319,7 @@
return rc;
err:
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5/audio_out.c b/arch/arm/mach-msm/qdsp5/audio_out.c
index 8fe8cf66..ef7a70b 100644
--- a/arch/arm/mach-msm/qdsp5/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5/audio_out.c
@@ -593,6 +593,7 @@
audio_flush(audio);
mutex_unlock(&audio->write_lock);
}
+ break;
case AUDIO_SET_CONFIG: {
struct msm_audio_config config;
if (copy_from_user(&config, (void*) arg, sizeof(config))) {
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm.c b/arch/arm/mach-msm/qdsp5/audio_pcm.c
index 6468e93..5cd95f6 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm.c
@@ -46,7 +46,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -187,7 +186,7 @@
/* data allocated for various buffers */
char *data;
int32_t phys;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_write;
uint32_t drv_status;
int wflush; /* Write flush */
@@ -1379,7 +1378,7 @@
audpcm_reset_event_queue(audio);
MM_DBG("pmem area = 0x%8x\n", (unsigned int)audio->data);
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
mutex_unlock(&audio->lock);
@@ -1551,10 +1550,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write\
buffers\n");
@@ -1567,7 +1564,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr\
0x%08x\n", audio->phys,\
(int)audio->data);
@@ -1678,7 +1675,7 @@
return rc;
err:
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
index 16c70ce..851980d 100644
--- a/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_pcm_in.c
@@ -585,7 +585,7 @@
audio->in_head = 0;
audio->in_tail = 0;
audio->in_count = 0;
- for (i = FRAME_NUM-1; i <= 0; i--) {
+ for (i = FRAME_NUM-1; i >= 0; i--) {
audio->in[i].size = 0;
audio->in[i].read = 0;
}
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp.c b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
index 2be5144..667a164 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp.c
@@ -42,7 +42,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
int wflush; /* Write flush */
@@ -966,12 +965,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
rc = -ENOMEM;
@@ -981,7 +978,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1290,10 +1287,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audqcelp_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1483,10 +1480,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, freeing \
instance 0x%08x\n", (int)audio);
@@ -1496,7 +1490,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1586,7 +1580,7 @@
done:
return rc;
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
index a79f721..e6906d0 100644
--- a/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5/audio_qcelp_in.c
@@ -42,7 +42,6 @@
#include <mach/msm_rpcrouter.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include "audmgr.h"
#include <mach/qdsp5/qdsp5audpreproc.h>
@@ -145,8 +144,8 @@
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int opened;
int enabled;
@@ -801,13 +800,15 @@
}
/* Allow only single frame */
if (audio->mode == MSM_AUD_ENC_MODE_TUNNEL) {
- if (cfg.buffer_size != (FRAME_SIZE - 8))
+ if (cfg.buffer_size != (FRAME_SIZE - 8)) {
rc = -EINVAL;
break;
+ }
} else {
- if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14))
+ if (cfg.buffer_size != (QCELP_FRAME_SIZE + 14)) {
rc = -EINVAL;
break;
+ }
}
audio->buffer_size = cfg.buffer_size;
break;
@@ -1191,13 +1192,13 @@
if ((audio->mode == MSM_AUD_ENC_MODE_NONTUNNEL) && \
(audio->out_data)) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -1298,17 +1299,14 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, dma_size,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, dma_size);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map physical address\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto evt_error;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1320,25 +1318,23 @@
if (!audio->out_phys) {
MM_ERR("could not allocate physical write buffers\n");
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address\n");
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
free_contiguous_memory_by_paddr(\
audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("wr buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
diff --git a/arch/arm/mach-msm/qdsp5/audio_wma.c b/arch/arm/mach-msm/qdsp5/audio_wma.c
index 674ee4f..b17cdda 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wma.c
@@ -46,7 +46,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5/qdsp5audppcmdi.h>
#include <mach/qdsp5/qdsp5audppmsg.h>
#include <mach/qdsp5/qdsp5audplaycmdi.h>
@@ -145,8 +144,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -470,6 +469,7 @@
wake_up(&audio->write_wait);
if (audio->pcm_feedback)
audplay_buffer_refresh(audio);
+ break;
case AUDPP_MSG_PCMDMAMISSED:
MM_DBG("PCMDMAMISSED\n");
audio->teos = 1;
@@ -1043,12 +1043,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
rc = -ENOMEM;
@@ -1058,7 +1056,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1435,10 +1433,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwma_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1630,10 +1628,7 @@
MM_DBG("pmemsz = %d\n", pmem_sz);
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, \
freeing instance 0x%08x\n",
@@ -1644,7 +1639,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1753,7 +1748,7 @@
done:
return rc;
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5/audio_wmapro.c b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
index c2a0b93..5e806e6 100644
--- a/arch/arm/mach-msm/qdsp5/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5/audio_wmapro.c
@@ -52,7 +52,6 @@
#include <mach/msm_memtypes.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include "audmgr.h"
@@ -144,8 +143,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -464,6 +463,7 @@
wake_up(&audio->write_wait);
if (audio->pcm_feedback)
audplay_buffer_refresh(audio);
+ break;
case AUDPP_MSG_PCMDMAMISSED:
MM_DBG("PCMDMAMISSED\n");
audio->teos = 1;
@@ -1040,12 +1040,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("map of read buf failed\n");
@@ -1055,8 +1053,7 @@
} else {
uint8_t index;
uint32_t offset = 0;
- audio->read_data =
- audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
audio->pcm_feedback = 1;
audio->buf_refresh = 0;
audio->pcm_buf_count =
@@ -1432,10 +1429,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwmapro_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1627,10 +1624,7 @@
MM_DBG("pmemsz = %d\n", pmem_sz);
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, \
freeing instance 0x%08x\n",
@@ -1641,7 +1635,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1741,7 +1735,7 @@
done:
return rc;
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
index 60b5c20..733b7a1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_a2dp_in.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.
*
* sbc/pcm audio input driver
* Based on the pcm input driver in arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -41,7 +41,6 @@
#include <mach/iommu_domains.h>
#include <mach/msm_adsp.h>
#include <mach/msm_memtypes.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -108,7 +107,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *msm_map;
+ void *msm_map;
int opened;
int enabled;
@@ -849,7 +848,7 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->msm_map);
+ iounmap(audio->msm_map);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -871,9 +870,7 @@
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->msm_map = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->msm_map = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->msm_map)) {
MM_ERR("could not map the phys address to kernel"
"space\n");
@@ -881,7 +878,7 @@
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = (u8 *)audio->msm_map->vaddr;
+ audio->data = (u8 *)audio->msm_map;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac.c b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
index 9069426..32053bf 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+ * 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
@@ -38,7 +38,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -142,8 +141,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1629,9 +1628,9 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audaac_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
mutex_unlock(&audio->lock);
#ifdef CONFIG_DEBUG_FS
@@ -1821,10 +1820,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
audio->map_v_write =
- msm_subsystem_map_buffer(audio->phys,
- pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ ioremap(audio->phys,
+ pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, \
freeing instance 0x%08x\n",
@@ -1835,7 +1832,7 @@
kfree(audio);
goto done;
}
- audio->data = (u8 *)audio->map_v_write->vaddr;
+ audio->data = (u8 *)audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1857,28 +1854,26 @@
MM_ERR("could not allocate read buffers, freeing instance \
0x%08x\n", (int)audio);
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
goto done;
}
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->read_phys,
- PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->read_phys,
+ PCM_BUFSZ_MIN * PCM_BUF_MAX_COUNT);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read phys address, freeing instance \
0x%08x\n", (int)audio);
rc = -ENOMEM;
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
free_contiguous_memory_by_paddr(audio->read_phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
goto done;
}
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
MM_DBG("read buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->read_phys, (int)audio->read_data);
@@ -2000,9 +1995,9 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
index 010fd90..d2b4407 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_aac_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -32,7 +32,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/iommu_domains.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -97,8 +96,8 @@
wait_queue_head_t write_wait;
int32_t out_phys; /* physical address of write buffer */
char *out_data;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int wflush; /*write flush */
@@ -1292,12 +1291,12 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
if (audio->out_data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
@@ -1320,16 +1319,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map DMA buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
@@ -1398,16 +1395,15 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
@@ -1434,7 +1430,7 @@
aac_in_listener, (void *) audio);
if (rc) {
MM_ERR("failed to register device event listener\n");
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c b/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
index 90373f9..89957a4 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_acdb.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
@@ -28,7 +28,6 @@
#include <mach/dal.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/audpp.h>
#include <mach/socinfo.h>
@@ -111,7 +110,7 @@
u16 *pbe_enable_flag;
u32 fluence_extbuff;
u8 *fluence_extbuff_virt;
- struct msm_mapped_buffer *map_v_fluence;
+ void *map_v_fluence;
struct acdb_pbe_block *pbe_blk;
@@ -130,7 +129,7 @@
/* pmem for get acdb blk */
unsigned long get_blk_paddr;
u8 *get_blk_kvaddr;
- struct msm_mapped_buffer *map_v_get_blk;
+ void *map_v_get_blk;
char *build_id;
};
@@ -140,7 +139,7 @@
u32 node_status;
s32 stream_id;
u32 phys_addr_acdb_values;
- struct msm_mapped_buffer *map_v_addr;
+ void *map_v_addr;
u8 *virt_addr_acdb_values;
struct auddev_evt_audcal_info device_info;
};
@@ -237,7 +236,7 @@
struct rtc_acdb_pmem {
u8 *viraddr;
int32_t phys;
- struct msm_mapped_buffer *map_v_rtc;
+ void *map_v_rtc;
};
struct rtc_acdb_data {
@@ -1087,11 +1086,11 @@
rtc_acdb.valid_abid = false;
if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_read->map_v_rtc);
+ iounmap(rtc_read->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_read->phys);
}
if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_write->map_v_rtc);
+ iounmap(rtc_write->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_write->phys);
}
}
@@ -1141,17 +1140,15 @@
result = -ENOMEM;
goto error;
}
- rtc_read->map_v_rtc = msm_subsystem_map_buffer(
- rtc_read->phys,
- PMEM_RTC_ACDB_QUERY_MEM,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ rtc_read->map_v_rtc = ioremap(rtc_read->phys,
+ PMEM_RTC_ACDB_QUERY_MEM);
if (IS_ERR(rtc_read->map_v_rtc)) {
MM_ERR("ACDB Could not map physical address\n");
result = -ENOMEM;
goto error;
}
- rtc_read->viraddr = rtc_read->map_v_rtc->vaddr;
+ rtc_read->viraddr = rtc_read->map_v_rtc;
memset(rtc_read->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
rtc_write->phys = allocate_contiguous_ebi_nomap(PMEM_RTC_ACDB_QUERY_MEM,
@@ -1162,16 +1159,15 @@
result = -ENOMEM;
goto error;
}
- rtc_write->map_v_rtc = msm_subsystem_map_buffer(
- rtc_write->phys, PMEM_RTC_ACDB_QUERY_MEM,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ rtc_write->map_v_rtc = ioremap(rtc_write->phys,
+ PMEM_RTC_ACDB_QUERY_MEM);
if (IS_ERR(rtc_write->map_v_rtc)) {
MM_ERR("ACDB Could not map physical address\n");
result = -ENOMEM;
goto error;
}
- rtc_write->viraddr = rtc_write->map_v_rtc->vaddr;
+ rtc_write->viraddr = rtc_write->map_v_rtc;
memset(rtc_write->viraddr, 0, PMEM_RTC_ACDB_QUERY_MEM);
init_waitqueue_head(&rtc_acdb.wait);
return true;
@@ -1187,11 +1183,11 @@
debugfs_remove(get_set_abid_data_dentry);
}
if (rtc_read->viraddr != NULL || ((void *)rtc_read->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_read->map_v_rtc);
+ iounmap(rtc_read->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_read->phys);
}
if (rtc_write->viraddr != NULL || ((void *)rtc_write->phys) != NULL) {
- msm_subsystem_unmap_buffer(rtc_write->map_v_rtc);
+ iounmap(rtc_write->map_v_rtc);
free_contiguous_memory_by_paddr(rtc_write->phys);
}
return false;
@@ -2544,11 +2540,9 @@
result = -ENOMEM;
goto error;
}
- acdb_cache_tx[i].map_v_addr =
- msm_subsystem_map_buffer(
+ acdb_cache_tx[i].map_v_addr = ioremap(
acdb_cache_tx[i].phys_addr_acdb_values,
- ACDB_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ ACDB_BUF_SIZE);
if (IS_ERR(acdb_cache_tx[i].map_v_addr)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
@@ -2557,15 +2551,14 @@
goto error;
}
acdb_cache_tx[i].virt_addr_acdb_values =
- acdb_cache_tx[i].map_v_addr->vaddr;
+ acdb_cache_tx[i].map_v_addr;
memset(acdb_cache_tx[i].virt_addr_acdb_values, 0,
ACDB_BUF_SIZE);
}
return result;
error:
for (err = 0; err < i; err++) {
- msm_subsystem_unmap_buffer(
- acdb_cache_tx[err].map_v_addr);
+ iounmap(acdb_cache_tx[err].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[err].phys_addr_acdb_values);
}
@@ -2590,11 +2583,8 @@
goto error;
}
acdb_cache_rx[i].map_v_addr =
- msm_subsystem_map_buffer(
- acdb_cache_rx[i].phys_addr_acdb_values,
- ACDB_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ ioremap(acdb_cache_rx[i].phys_addr_acdb_values,
+ ACDB_BUF_SIZE);
if (IS_ERR(acdb_cache_rx[i].map_v_addr)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
@@ -2603,15 +2593,14 @@
goto error;
}
acdb_cache_rx[i].virt_addr_acdb_values =
- acdb_cache_rx[i].map_v_addr->vaddr;
+ acdb_cache_rx[i].map_v_addr;
memset(acdb_cache_rx[i].virt_addr_acdb_values, 0,
ACDB_BUF_SIZE);
}
return result;
error:
for (err = 0; err < i; err++) {
- msm_subsystem_unmap_buffer(
- acdb_cache_rx[err].map_v_addr);
+ iounmap(acdb_cache_rx[err].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[err].phys_addr_acdb_values);
}
@@ -2628,10 +2617,8 @@
result = -ENOMEM;
goto error;
}
- acdb_data.map_v_get_blk = msm_subsystem_map_buffer(
- acdb_data.get_blk_paddr,
- ACDB_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ acdb_data.map_v_get_blk = ioremap(acdb_data.get_blk_paddr,
+ ACDB_BUF_SIZE);
if (IS_ERR(acdb_data.map_v_get_blk)) {
MM_ERR("ACDB=> Could not map physical address\n");
result = -ENOMEM;
@@ -2639,7 +2626,7 @@
acdb_data.get_blk_paddr);
goto error;
}
- acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk->vaddr;
+ acdb_data.get_blk_kvaddr = acdb_data.map_v_get_blk;
memset(acdb_data.get_blk_kvaddr, 0, ACDB_BUF_SIZE);
error:
return result;
@@ -2650,7 +2637,7 @@
u32 i = 0;
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
- msm_subsystem_unmap_buffer(acdb_cache_rx[i].map_v_addr);
+ iounmap(acdb_cache_rx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[i].phys_addr_acdb_values);
}
@@ -2661,7 +2648,7 @@
u32 i = 0;
for (i = 0; i < MAX_AUDREC_SESSIONS; i++) {
- msm_subsystem_unmap_buffer(acdb_cache_tx[i].map_v_addr);
+ iounmap(acdb_cache_tx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[i].phys_addr_acdb_values);
}
@@ -2669,7 +2656,7 @@
static void free_memory_acdb_get_blk(void)
{
- msm_subsystem_unmap_buffer(acdb_data.map_v_get_blk);
+ iounmap(acdb_data.map_v_get_blk);
free_contiguous_memory_by_paddr(acdb_data.get_blk_paddr);
}
@@ -2827,11 +2814,9 @@
result = -ENOMEM;
goto done;
}
- acdb_data.map_v_fluence =
- msm_subsystem_map_buffer(
+ acdb_data.map_v_fluence = ioremap(
acdb_data.fluence_extbuff,
- FLUENCE_BUF_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ FLUENCE_BUF_SIZE);
if (IS_ERR(acdb_data.map_v_fluence)) {
MM_ERR("ACDB=> Could not map physical address\n");
free_memory_acdb_get_blk();
@@ -2852,7 +2837,7 @@
goto done;
} else
acdb_data.fluence_extbuff_virt =
- acdb_data.map_v_fluence->vaddr;
+ acdb_data.map_v_fluence;
done:
return result;
}
@@ -3431,11 +3416,11 @@
for (i = 0; i < MAX_COPP_NODE_SUPPORTED; i++) {
if (i < MAX_AUDREC_SESSIONS) {
- msm_subsystem_unmap_buffer(acdb_cache_tx[i].map_v_addr);
+ iounmap(acdb_cache_tx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_tx[i].phys_addr_acdb_values);
}
- msm_subsystem_unmap_buffer(acdb_cache_rx[i].map_v_addr);
+ iounmap(acdb_cache_rx[i].map_v_addr);
free_contiguous_memory_by_paddr(
acdb_cache_rx[i].phys_addr_acdb_values);
}
@@ -3446,7 +3431,7 @@
kfree(acdb_data.preproc_iir);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.pbe_extbuff);
- msm_subsystem_unmap_buffer(acdb_data.map_v_fluence);
+ iounmap(acdb_data.map_v_fluence);
free_contiguous_memory_by_paddr(
(int32_t)acdb_data.fluence_extbuff);
mutex_destroy(&acdb_data.acdb_mutex);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
index 4b8b7a6..a53128d 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_adpcm.c
@@ -43,7 +43,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -139,8 +138,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
int wflush; /* Write flush */
@@ -1023,12 +1022,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("read buf map fail\n");
rc = -ENOMEM;
@@ -1038,7 +1035,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1420,10 +1417,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audadpcm_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1615,10 +1612,7 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, \
freeing instance 0x%08x\n",
@@ -1629,7 +1623,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1729,7 +1723,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
index a09b71b..5f288dd 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb.c
@@ -44,7 +44,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -993,12 +992,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read phys address\n");
rc = -ENOMEM;
@@ -1007,7 +1004,7 @@
} else {
uint8_t index;
uint32_t offset = 0;
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1317,10 +1314,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrnb_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1512,9 +1509,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, freeing \
instance 0x%08x\n", (int)audio);
@@ -1525,7 +1520,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
}
@@ -1610,7 +1605,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
index bdb5bb1..790c510 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrnb_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -32,7 +32,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/msm_adsp.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
@@ -99,7 +98,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
+ void *map_v_read;
int opened;
int enabled;
@@ -767,7 +766,7 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -788,16 +787,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map DMA buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
index 48e9a9f..b74c054 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_amrwb.c
@@ -45,7 +45,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -136,8 +135,8 @@
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1003,12 +1002,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("Error could not map read"
" phys address\n");
@@ -1018,7 +1015,7 @@
} else {
uint8_t index;
uint32_t offset = 0;
- audio->read_data = audio->map_v_read->vaddr;
+ audio->read_data = audio->map_v_read;
audio->pcm_feedback = 1;
audio->buf_refresh = 0;
audio->pcm_buf_count =
@@ -1401,10 +1398,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audamrwb_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1591,9 +1588,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys buffers, freeing \
instance 0x%08x\n", (int)audio);
@@ -1603,7 +1598,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1692,7 +1687,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
index 9b5694d..8818cbd 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc.c
@@ -40,7 +40,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -132,8 +131,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -982,12 +981,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read"
" phy address\n");
@@ -998,7 +995,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1311,10 +1308,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audevrc_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1505,9 +1502,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("failed to map write physical address, freeing \
instance 0x%08x\n", (int)audio);
@@ -1517,7 +1512,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1604,7 +1599,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
index 50621c9..150e476 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_evrc_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -33,7 +33,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -131,8 +130,8 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int opened;
int enabled;
int running;
@@ -1319,12 +1318,12 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
if (audio->out_data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
@@ -1346,17 +1345,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read physical address\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
@@ -1425,17 +1421,14 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could map write buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
@@ -1461,7 +1454,7 @@
evrc_in_listener, (void *) audio);
if (rc) {
MM_ERR("failed to register device event listener\n");
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
index c639833..a4fc3e3 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_mp3.c
@@ -37,7 +37,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -198,8 +197,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
uint32_t drv_status;
int mfield; /* meta field embedded in data */
@@ -1609,12 +1608,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buffer"
" physical address\n");
@@ -1625,7 +1622,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -2145,11 +2142,11 @@
wake_up(&audio->event_wait);
audmp3_reset_event_queue(audio);
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -2353,10 +2350,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("failed to map write physical"
" address , freeing instance"
@@ -2368,7 +2363,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr\
0x%08x\n", audio->phys,\
(int)audio->data);
@@ -2485,7 +2480,7 @@
msm_adsp_put(audio->audplay);
err:
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_out.c b/arch/arm/mach-msm/qdsp5v2/audio_out.c
index 9a93185..930de03 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_out.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_out.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -36,7 +36,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppcmdi.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/audio_dev_ctl.h>
@@ -86,7 +85,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_write;
int teos; /* valid only if tunnel mode & no data left for decoder */
int opened;
int enabled;
@@ -704,16 +703,13 @@
{
the_audio.phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (the_audio.phys) {
- the_audio.map_v_write = msm_subsystem_map_buffer(
- the_audio.phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ the_audio.map_v_write = ioremap(the_audio.phys, DMASZ);
if (IS_ERR(the_audio.map_v_write)) {
MM_ERR("could not map physical buffers\n");
free_contiguous_memory_by_paddr(the_audio.phys);
return -ENOMEM;
}
- the_audio.data = the_audio.map_v_write->vaddr;
+ the_audio.data = the_audio.map_v_write;
} else {
MM_ERR("could not allocate physical buffers\n");
return -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
index b22820b..613ee57 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm.c
@@ -40,7 +40,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppcmdi.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
@@ -172,7 +171,7 @@
/* data allocated for various buffers */
char *data;
int32_t phys;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_write;
uint32_t drv_status;
int wflush; /* Write flush */
int opened;
@@ -1382,7 +1381,7 @@
wake_up(&audio->event_wait);
audpcm_reset_event_queue(audio);
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
mutex_unlock(&audio->lock);
@@ -1560,10 +1559,8 @@
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz,
SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ audio->map_v_write = ioremap(
+ audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys\
address freeing instance \
@@ -1575,7 +1572,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x \
kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
@@ -1679,7 +1676,7 @@
msm_adsp_put(audio->audplay);
err:
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
}
audpp_adec_free(audio->dec_id);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
index a5a9bd2..ce67ebb 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_pcm_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -33,7 +33,6 @@
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/msm_adsp.h>
#include <mach/socinfo.h>
@@ -113,7 +112,7 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
+ void *map_v_read;
int opened;
int enabled;
@@ -843,7 +842,7 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
@@ -864,16 +863,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map read phys buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate read buffers\n");
rc = -ENOMEM;
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
index ce5d421..c4851d9 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp.c
@@ -41,7 +41,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -128,8 +127,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -984,12 +983,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("failed to map read buf\n");
rc = -ENOMEM;
@@ -999,7 +996,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1313,10 +1310,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audqcelp_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1505,9 +1502,7 @@
kfree(audio);
goto done;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write phys address, freeing \
instance 0x%08x\n", (int)audio);
@@ -1517,7 +1512,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->phys, (int)audio->data);
}
@@ -1604,7 +1599,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
index d34499d..7041bde 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_qcelp_in.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-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
@@ -33,7 +33,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/socinfo.h>
#include <mach/qdsp5v2/qdsp5audreccmdi.h>
#include <mach/qdsp5v2/qdsp5audrecmsg.h>
@@ -133,8 +132,8 @@
/* data allocated for various buffers */
char *data;
dma_addr_t phys;
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int opened;
int enabled;
@@ -1325,12 +1324,12 @@
audio->audrec = NULL;
audio->opened = 0;
if (audio->data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->phys);
audio->data = NULL;
}
if (audio->out_data) {
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
audio->out_data = NULL;
}
@@ -1352,16 +1351,14 @@
}
audio->phys = allocate_contiguous_ebi_nomap(DMASZ, SZ_4K);
if (audio->phys) {
- audio->map_v_read = msm_subsystem_map_buffer(
- audio->phys, DMASZ,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_read = ioremap(audio->phys, DMASZ);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("could not map DMA buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->phys);
goto done;
}
- audio->data = audio->map_v_read->vaddr;
+ audio->data = audio->map_v_read;
} else {
MM_ERR("could not allocate DMA buffers\n");
rc = -ENOMEM;
@@ -1431,16 +1428,14 @@
rc = -ENOMEM;
goto evt_error;
} else {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->out_phys, BUFFER_SIZE,
- MSM_SUBSYSTEM_MAP_KADDR, NULL, 0);
+ audio->map_v_write = ioremap(audio->out_phys, BUFFER_SIZE);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers\n");
rc = -ENOMEM;
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
- audio->out_data = audio->map_v_write->vaddr;
+ audio->out_data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr 0x%08x\n",
audio->out_phys, (int)audio->out_data);
}
@@ -1466,7 +1461,7 @@
qcelp_in_listener, (void *) audio);
if (rc) {
MM_ERR("failed to register device event listener\n");
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->out_phys);
goto evt_error;
}
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wma.c b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
index f29b078..79439e1 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wma.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wma.c
@@ -45,7 +45,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -141,8 +140,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1062,12 +1061,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("read buf alloc fail\n");
rc = -ENOMEM;
@@ -1077,7 +1074,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->buf_refresh = 0;
audio->pcm_buf_count =
config.buffer_count;
@@ -1458,10 +1455,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwma_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1652,10 +1649,7 @@
MM_DBG("pmemsz = %d\n", pmem_sz);
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not allocate write buffers, \
freeing instance 0x%08x\n",
@@ -1666,7 +1660,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1772,7 +1766,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
index cf25359..6672ca0 100644
--- a/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
+++ b/arch/arm/mach-msm/qdsp5v2/audio_wmapro.c
@@ -44,7 +44,6 @@
#include <mach/msm_adsp.h>
#include <mach/iommu.h>
#include <mach/iommu_domains.h>
-#include <mach/msm_subsystem_map.h>
#include <mach/qdsp5v2/qdsp5audppmsg.h>
#include <mach/qdsp5v2/qdsp5audplaycmdi.h>
#include <mach/qdsp5v2/qdsp5audplaymsg.h>
@@ -141,8 +140,8 @@
/* data allocated for various buffers */
char *data;
int32_t phys; /* physical address of write buffer */
- struct msm_mapped_buffer *map_v_read;
- struct msm_mapped_buffer *map_v_write;
+ void *map_v_read;
+ void *map_v_write;
int mfield; /* meta field embedded in data */
int rflush; /* Read flush */
@@ -1074,12 +1073,10 @@
rc = -ENOMEM;
break;
}
- audio->map_v_read = msm_subsystem_map_buffer(
+ audio->map_v_read = ioremap(
audio->read_phys,
config.buffer_size *
- config.buffer_count,
- MSM_SUBSYSTEM_MAP_KADDR
- , NULL, 0);
+ config.buffer_count);
if (IS_ERR(audio->map_v_read)) {
MM_ERR("read buf map fail\n");
rc = -ENOMEM;
@@ -1089,7 +1086,7 @@
uint8_t index;
uint32_t offset = 0;
audio->read_data =
- audio->map_v_read->vaddr;
+ audio->map_v_read;
audio->pcm_feedback = 1;
audio->buf_refresh = 0;
audio->pcm_buf_count =
@@ -1471,10 +1468,10 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audwmapro_reset_event_queue(audio);
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
if (audio->read_data) {
- msm_subsystem_unmap_buffer(audio->map_v_read);
+ iounmap(audio->map_v_read);
free_contiguous_memory_by_paddr(audio->read_phys);
}
mutex_unlock(&audio->lock);
@@ -1665,10 +1662,7 @@
MM_DBG("pmemsz = %d\n", pmem_sz);
audio->phys = allocate_contiguous_ebi_nomap(pmem_sz, SZ_4K);
if (audio->phys) {
- audio->map_v_write = msm_subsystem_map_buffer(
- audio->phys, pmem_sz,
- MSM_SUBSYSTEM_MAP_KADDR,
- NULL, 0);
+ audio->map_v_write = ioremap(audio->phys, pmem_sz);
if (IS_ERR(audio->map_v_write)) {
MM_ERR("could not map write buffers, \
freeing instance 0x%08x\n",
@@ -1679,7 +1673,7 @@
kfree(audio);
goto done;
}
- audio->data = audio->map_v_write->vaddr;
+ audio->data = audio->map_v_write;
MM_DBG("write buf: phy addr 0x%08x kernel addr \
0x%08x\n", audio->phys, (int)audio->data);
break;
@@ -1790,7 +1784,7 @@
event_err:
msm_adsp_put(audio->audplay);
err:
- msm_subsystem_unmap_buffer(audio->map_v_write);
+ iounmap(audio->map_v_write);
free_contiguous_memory_by_paddr(audio->phys);
audpp_adec_free(audio->dec_id);
kfree(audio);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
index ee32b80..8a0ba3e 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -2,7 +2,7 @@
*
* Copyright (C) 2008 Google, Inc.
* Copyright (C) 2008 HTC Corporation
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-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
@@ -16,6 +16,7 @@
*/
#include <linux/msm_audio_aac.h>
+#include <mach/socinfo.h>
#include "audio_utils_aio.h"
#define AUDIO_AAC_DUAL_MONO_INVALID -1
@@ -122,6 +123,14 @@
pr_err("cmd media format block failed\n");
break;
}
+ if (!cpu_is_msm8x60()) {
+ rc = q6asm_set_encdec_chan_map(audio->ac, 2);
+ if (rc < 0) {
+ pr_err("%s: cmd set encdec_chan_map failed\n",
+ __func__);
+ break;
+ }
+ }
rc = audio_aio_enable(audio);
audio->eos_rsp = 0;
audio->eos_flag = 0;
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
index eb394a3..f75af16 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.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
@@ -344,7 +344,7 @@
mutex_init(&drv->dev_lock);
drv->ref_cnt = 0;
- drv->ecodec_clk = clk_get(NULL, "pcm_clk");
+ drv->ecodec_clk = clk_get_sys(NULL, "pcm_clk");
if (IS_ERR(drv->ecodec_clk)) {
pr_err("%s: could not get pcm_clk\n", __func__);
return PTR_ERR(drv->ecodec_clk);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
index 216d982..ea935cc 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.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
@@ -308,7 +308,7 @@
}
msm_snddev_rx_mclk_request();
- drv->rx_osrclk = clk_get(0, "i2s_spkr_osr_clk");
+ drv->rx_osrclk = clk_get_sys(NULL, "i2s_spkr_osr_clk");
if (IS_ERR(drv->rx_osrclk))
pr_err("%s master clock Error\n", __func__);
@@ -320,7 +320,7 @@
}
clk_enable(drv->rx_osrclk);
- drv->rx_bitclk = clk_get(0, "i2s_spkr_bit_clk");
+ drv->rx_bitclk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
if (IS_ERR(drv->rx_bitclk))
pr_err("%s clock Error\n", __func__);
@@ -437,7 +437,7 @@
msm_snddev_tx_mclk_request();
- drv->tx_osrclk = clk_get(0, "i2s_mic_osr_clk");
+ drv->tx_osrclk = clk_get_sys(NULL, "i2s_mic_osr_clk");
if (IS_ERR(drv->tx_osrclk))
pr_err("%s master clock Error\n", __func__);
@@ -449,7 +449,7 @@
}
clk_enable(drv->tx_osrclk);
- drv->tx_bitclk = clk_get(0, "i2s_mic_bit_clk");
+ drv->tx_bitclk = clk_get_sys(NULL, "i2s_mic_bit_clk");
if (IS_ERR(drv->tx_bitclk))
pr_err("%s clock Error\n", __func__);
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
index a99b600..75a7411 100644
--- a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.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
@@ -184,7 +184,7 @@
}
/* set up osr clk */
- drv->tx_osrclk = clk_get(0, "mi2s_osr_clk");
+ drv->tx_osrclk = clk_get_sys(NULL, "mi2s_osr_clk");
if (IS_ERR(drv->tx_osrclk))
pr_err("%s master clock Error\n", __func__);
@@ -197,7 +197,7 @@
clk_enable(drv->tx_osrclk);
/* set up bit clk */
- drv->tx_bitclk = clk_get(0, "mi2s_bit_clk");
+ drv->tx_bitclk = clk_get_sys(NULL, "mi2s_bit_clk");
if (IS_ERR(drv->tx_bitclk))
pr_err("%s clock Error\n", __func__);
diff --git a/arch/arm/mach-msm/qdss-etb.c b/arch/arm/mach-msm/qdss-etb.c
index 96eba26..7837af0 100644
--- a/arch/arm/mach-msm/qdss-etb.c
+++ b/arch/arm/mach-msm/qdss-etb.c
@@ -69,7 +69,7 @@
void __iomem *base;
bool enabled;
bool reading;
- struct mutex mutex;
+ spinlock_t spinlock;
atomic_t in_use;
struct device *dev;
struct kobject *kobj;
@@ -100,11 +100,13 @@
void etb_enable(void)
{
- mutex_lock(&etb.mutex);
+ unsigned long flags;
+
+ spin_lock_irqsave(&etb.spinlock, flags);
__etb_enable();
etb.enabled = true;
dev_info(etb.dev, "ETB enabled\n");
- mutex_unlock(&etb.mutex);
+ spin_unlock_irqrestore(&etb.spinlock, flags);
}
static void __etb_disable(void)
@@ -137,11 +139,13 @@
void etb_disable(void)
{
- mutex_lock(&etb.mutex);
+ unsigned long flags;
+
+ spin_lock_irqsave(&etb.spinlock, flags);
__etb_disable();
etb.enabled = false;
dev_info(etb.dev, "ETB disabled\n");
- mutex_unlock(&etb.mutex);
+ spin_unlock_irqrestore(&etb.spinlock, flags);
}
static void __etb_dump(void)
@@ -200,7 +204,9 @@
void etb_dump(void)
{
- mutex_lock(&etb.mutex);
+ unsigned long flags;
+
+ spin_lock_irqsave(&etb.spinlock, flags);
if (etb.enabled) {
__etb_disable();
__etb_dump();
@@ -208,7 +214,7 @@
dev_info(etb.dev, "ETB dumped\n");
}
- mutex_unlock(&etb.mutex);
+ spin_unlock_irqrestore(&etb.spinlock, flags);
}
static int etb_open(struct inode *inode, struct file *file)
@@ -293,7 +299,7 @@
}
ETB_ATTR(trigger_cntr);
-static int __init etb_sysfs_init(void)
+static int __devinit etb_sysfs_init(void)
{
int ret;
@@ -318,7 +324,7 @@
return ret;
}
-static void __exit etb_sysfs_exit(void)
+static void __devexit etb_sysfs_exit(void)
{
sysfs_remove_file(etb.kobj, &trigger_cntr_attr.attr);
kobject_put(etb.kobj);
@@ -343,7 +349,7 @@
etb.dev = &pdev->dev;
- mutex_init(&etb.mutex);
+ spin_lock_init(&etb.spinlock);
ret = misc_register(&etb_misc);
if (ret)
@@ -363,7 +369,6 @@
err_alloc:
misc_deregister(&etb_misc);
err_misc:
- mutex_destroy(&etb.mutex);
iounmap(etb.base);
err_ioremap:
err_res:
@@ -378,7 +383,6 @@
etb_sysfs_exit();
kfree(etb.buf);
misc_deregister(&etb_misc);
- mutex_destroy(&etb.mutex);
iounmap(etb.base);
return 0;
diff --git a/arch/arm/mach-msm/qdss-etm.c b/arch/arm/mach-msm/qdss-etm.c
index 251db45..61f1c1b 100644
--- a/arch/arm/mach-msm/qdss-etm.c
+++ b/arch/arm/mach-msm/qdss-etm.c
@@ -1120,7 +1120,7 @@
.attrs = etm_attrs,
};
-static int __init etm_sysfs_init(void)
+static int __devinit etm_sysfs_init(void)
{
int ret;
@@ -1148,14 +1148,14 @@
return ret;
}
-static void __exit etm_sysfs_exit(void)
+static void __devexit etm_sysfs_exit(void)
{
sysfs_remove_group(etm.kobj, &etm_attr_grp);
sysfs_remove_file(etm.kobj, &enabled_attr.attr);
kobject_put(etm.kobj);
}
-static bool __init etm_arch_supported(uint8_t arch)
+static bool __devinit etm_arch_supported(uint8_t arch)
{
switch (arch) {
case PFT_ARCH_V1_1:
@@ -1166,7 +1166,7 @@
return true;
}
-static int __init etm_arch_init(void)
+static int __devinit etm_arch_init(void)
{
int ret, i;
/* use cpu 0 for setup */
diff --git a/arch/arm/mach-msm/qdss-funnel.c b/arch/arm/mach-msm/qdss-funnel.c
index 2d80603..52eb2b6 100644
--- a/arch/arm/mach-msm/qdss-funnel.c
+++ b/arch/arm/mach-msm/qdss-funnel.c
@@ -134,7 +134,7 @@
}
FUNNEL_ATTR(priority);
-static int __init funnel_sysfs_init(void)
+static int __devinit funnel_sysfs_init(void)
{
int ret;
@@ -159,7 +159,7 @@
return ret;
}
-static void __exit funnel_sysfs_exit(void)
+static void __devexit funnel_sysfs_exit(void)
{
sysfs_remove_file(funnel.kobj, &priority_attr.attr);
kobject_put(funnel.kobj);
diff --git a/arch/arm/mach-msm/qdss.c b/arch/arm/mach-msm/qdss.c
index cfe65ad..fd1fc2b 100644
--- a/arch/arm/mach-msm/qdss.c
+++ b/arch/arm/mach-msm/qdss.c
@@ -175,6 +175,26 @@
EXPORT_SYMBOL(qdss_disable);
/**
+ * qdss_disable_sink - force disable the current qdss sink(s)
+ *
+ * Force disable the current qdss sink(s) to stop the sink from accepting any
+ * trace generated subsequent to this call. This function should only be used
+ * as a way to stop the sink from getting polluted with trace data that is
+ * uninteresting after an event of interest has occured.
+ *
+ * CONTEXT:
+ * Can be called from atomic or non-atomic context.
+ */
+void qdss_disable_sink(void)
+{
+ if ((qdss.pdata)->afamily) {
+ etb_dump();
+ etb_disable();
+ }
+}
+EXPORT_SYMBOL(qdss_disable_sink);
+
+/**
* qdss_clk_enable - enable qdss clocks
*
* Enables qdss clocks via RPM if they aren't already enabled, otherwise
@@ -270,7 +290,7 @@
}
QDSS_ATTR(max_clk);
-static void __init qdss_add_sources(struct qdss_source *srcs, size_t num)
+static void __devinit qdss_add_sources(struct qdss_source *srcs, size_t num)
{
mutex_lock(&qdss.sources_mutex);
while (num--) {
@@ -302,7 +322,7 @@
return ret;
}
-static void __exit qdss_sysfs_exit(void)
+static void __devexit qdss_sysfs_exit(void)
{
sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
}
diff --git a/arch/arm/mach-msm/restart.c b/arch/arm/mach-msm/restart.c
index 5382102..e45e2c4 100644
--- a/arch/arm/mach-msm/restart.c
+++ b/arch/arm/mach-msm/restart.c
@@ -232,21 +232,10 @@
printk(KERN_ERR "Restarting has failed\n");
}
-static int __init msm_restart_init(void)
+static int __init msm_pmic_restart_init(void)
{
int rc;
-#ifdef CONFIG_MSM_DLOAD_MODE
- atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
- dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
-
- /* Reset detection is switched on below.*/
- set_dload_mode(download_mode);
-#endif
- msm_tmr0_base = msm_timer_get_timer0_base();
- restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
- pm_power_off = msm_power_off;
-
if (pmic_reset_irq != 0) {
rc = request_any_context_irq(pmic_reset_irq,
resout_irq_handler, IRQF_TRIGGER_HIGH,
@@ -260,4 +249,19 @@
return 0;
}
-late_initcall(msm_restart_init);
+late_initcall(msm_pmic_restart_init);
+
+static int __init msm_restart_init(void)
+{
+#ifdef CONFIG_MSM_DLOAD_MODE
+ atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
+ dload_mode_addr = MSM_IMEM_BASE + DLOAD_MODE_ADDR;
+ set_dload_mode(download_mode);
+#endif
+ msm_tmr0_base = msm_timer_get_timer0_base();
+ restart_reason = MSM_IMEM_BASE + RESTART_REASON_ADDR;
+ pm_power_off = msm_power_off;
+
+ return 0;
+}
+early_initcall(msm_restart_init);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index dac0a37..ddc3a8d 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -3483,8 +3483,14 @@
},
};
-static int __init msm_smd_init(void)
+int __init msm_smd_init(void)
{
+ static bool registered;
+
+ if (registered)
+ return 0;
+
+ registered = true;
return platform_driver_register(&msm_smd_driver);
}
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 3faeb37..d811f71 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -247,6 +247,14 @@
[128] = MSM_CPU_8625,
[129] = MSM_CPU_8625,
+ /* 9625 IDs */
+ [130] = MSM_CPU_9625,
+
+ /* 7x25AB IDs */
+ [131] = MSM_CPU_7X25AB,
+ [132] = MSM_CPU_7X25AB,
+ [133] = MSM_CPU_7X25AB,
+
/* Uninitialized IDs are not known to run Linux.
MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
considered as unknown CPU. */
@@ -616,6 +624,10 @@
dummy_socinfo.id = 126;
strlcpy(dummy_socinfo.build_id, "copper - ",
sizeof(dummy_socinfo.build_id));
+ } else if (early_machine_is_msm9625()) {
+ dummy_socinfo.id = 130;
+ strlcpy(dummy_socinfo.build_id, "msm9625 - ",
+ sizeof(dummy_socinfo.build_id));
} else if (machine_is_msm8625_rumi3())
dummy_socinfo.id = 127;
strlcat(dummy_socinfo.build_id, "Dummy socinfo",
diff --git a/arch/arm/mach-msm/spm-v2.c b/arch/arm/mach-msm/spm-v2.c
index 051d4de..b6d5324 100644
--- a/arch/arm/mach-msm/spm-v2.c
+++ b/arch/arm/mach-msm/spm-v2.c
@@ -418,7 +418,7 @@
mb();
}
-int __init msm_spm_drv_init(struct msm_spm_driver_data *dev,
+int __devinit msm_spm_drv_init(struct msm_spm_driver_data *dev,
struct msm_spm_platform_data *data)
{
int i;
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 838ec55..2980811 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -92,7 +92,7 @@
return ret;
}
-static int __init msm_spm_dev_init(struct msm_spm_device *dev,
+static int __devinit msm_spm_dev_init(struct msm_spm_device *dev,
struct msm_spm_platform_data *data)
{
int i, ret = -ENOMEM;
diff --git a/arch/arm/mach-msm/subsystem_map.c b/arch/arm/mach-msm/subsystem_map.c
index d6a17e6..4a1285b 100644
--- a/arch/arm/mach-msm/subsystem_map.c
+++ b/arch/arm/mach-msm/subsystem_map.c
@@ -392,7 +392,8 @@
temp_phys += SZ_4K,
temp_va += SZ_4K) {
ret = iommu_map(d, temp_va, temp_phys,
- get_order(SZ_4K), 0);
+ get_order(SZ_4K),
+ (IOMMU_READ | IOMMU_WRITE));
if (ret) {
pr_err("%s: could not map iommu for"
" domain %p, iova %lx,"
@@ -406,7 +407,8 @@
if (flags & MSM_SUBSYSTEM_MAP_IOMMU_2X)
msm_iommu_map_extra
- (d, temp_va, length, 0);
+ (d, temp_va, length, SZ_4K,
+ (IOMMU_READ | IOMMU_WRITE));
}
}
diff --git a/arch/arm/mach-msm/sysmon.c b/arch/arm/mach-msm/sysmon.c
index 679393d..1305bd1 100644
--- a/arch/arm/mach-msm/sysmon.c
+++ b/arch/arm/mach-msm/sysmon.c
@@ -27,7 +27,8 @@
#include "hsic_sysmon.h"
#include "sysmon.h"
-#define MAX_MSG_LENGTH 50
+#define TX_BUF_SIZE 50
+#define RX_BUF_SIZE 500
#define TIMEOUT_MS 5000
enum transports {
@@ -40,7 +41,7 @@
struct smd_channel *chan;
bool chan_open;
struct completion resp_ready;
- char rx_buf[MAX_MSG_LENGTH];
+ char rx_buf[RX_BUF_SIZE];
enum transports transport;
};
@@ -60,7 +61,8 @@
[SUBSYS_AFTER_POWERUP] = "after_powerup",
};
-static int sysmon_send_smd(struct sysmon_subsys *ss, char *tx_buf, size_t len)
+static int sysmon_send_smd(struct sysmon_subsys *ss, const char *tx_buf,
+ size_t len)
{
int ret;
@@ -78,7 +80,8 @@
return 0;
}
-static int sysmon_send_hsic(struct sysmon_subsys *ss, char *tx_buf, size_t len)
+static int sysmon_send_hsic(struct sysmon_subsys *ss, const char *tx_buf,
+ size_t len)
{
int ret;
size_t actual_len;
@@ -93,11 +96,46 @@
return ret;
}
+static int sysmon_send_msg(struct sysmon_subsys *ss, const char *tx_buf,
+ size_t len)
+{
+ int ret;
+
+ switch (ss->transport) {
+ case TRANSPORT_SMD:
+ ret = sysmon_send_smd(ss, tx_buf, len);
+ break;
+ case TRANSPORT_HSIC:
+ ret = sysmon_send_hsic(ss, tx_buf, len);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ pr_debug("Received response: %s\n", ss->rx_buf);
+
+ return ret;
+}
+
+/**
+ * sysmon_send_event() - Notify a subsystem of another's state change
+ * @dest_ss: ID of subsystem the notification should be sent to
+ * @event_ss: String name of the subsystem that generated the notification
+ * @notif: ID of the notification type (ex. SUBSYS_BEFORE_SHUTDOWN)
+ *
+ * Returns 0 for success, -EINVAL for invalid destination or notification IDs,
+ * -ENODEV if the transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds, but with something other than an acknowledgement.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
enum subsys_notif_type notif)
{
struct sysmon_subsys *ss = &subsys[dest_ss];
- char tx_buf[MAX_MSG_LENGTH];
+ char tx_buf[TX_BUF_SIZE];
int ret;
if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
@@ -109,24 +147,52 @@
notif_name[notif]);
mutex_lock(&ss->lock);
- switch (ss->transport) {
- case TRANSPORT_SMD:
- ret = sysmon_send_smd(ss, tx_buf, strlen(tx_buf));
- break;
- case TRANSPORT_HSIC:
- ret = sysmon_send_hsic(ss, tx_buf, strlen(tx_buf));
- break;
- default:
- ret = -EINVAL;
- }
+ ret = sysmon_send_msg(ss, tx_buf, strlen(tx_buf));
if (ret)
goto out;
- pr_debug("Received response: %s\n", ss->rx_buf);
if (strncmp(ss->rx_buf, "ssr:ack", ARRAY_SIZE(ss->rx_buf)))
ret = -ENOSYS;
- else
- ret = 0;
+out:
+ mutex_unlock(&ss->lock);
+ return ret;
+}
+
+/**
+ * sysmon_get_reason() - Retrieve failure reason from a subsystem.
+ * @dest_ss: ID of subsystem to query
+ * @buf: Caller-allocated buffer for the returned NUL-terminated reason
+ * @len: Length of @buf
+ *
+ * Returns 0 for success, -EINVAL for an invalid destination, -ENODEV if
+ * the SMD transport channel is not open, -ETIMEDOUT if the destination
+ * subsystem does not respond, and -ENOSYS if the destination subsystem
+ * responds with something unexpected.
+ *
+ * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
+ */
+int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len)
+{
+ struct sysmon_subsys *ss = &subsys[dest_ss];
+ const char tx_buf[] = "ssr:retrieve:sfr";
+ const char expect[] = "ssr:return:";
+ size_t prefix_len = ARRAY_SIZE(expect) - 1;
+ int ret;
+
+ if (dest_ss < 0 || dest_ss >= SYSMON_NUM_SS ||
+ buf == NULL || len == 0)
+ return -EINVAL;
+
+ mutex_lock(&ss->lock);
+ ret = sysmon_send_msg(ss, tx_buf, ARRAY_SIZE(tx_buf));
+ if (ret)
+ goto out;
+
+ if (strncmp(ss->rx_buf, expect, prefix_len)) {
+ ret = -ENOSYS;
+ goto out;
+ }
+ strlcpy(buf, ss->rx_buf + prefix_len, len);
out:
mutex_unlock(&ss->lock);
return ret;
diff --git a/arch/arm/mach-msm/sysmon.h b/arch/arm/mach-msm/sysmon.h
index d014187..77c3329 100644
--- a/arch/arm/mach-msm/sysmon.h
+++ b/arch/arm/mach-msm/sysmon.h
@@ -34,22 +34,10 @@
SYSMON_NUM_SS
};
-/**
- * sysmon_send_event() - Notify a subsystem of another's state change.
- * @dest_ss: ID of subsystem the notification should be sent to.
- * @event_ss: String name of the subsystem that generated the notification.
- * @notif: ID of the notification type (ex. SUBSYS_BEFORE_SHUTDOWN)
- *
- * Returns 0 for success, -EINVAL for invalid destination or notification IDs,
- * -ENODEV if the SMD channel is not open, -ETIMEDOUT if the destination
- * subsystem does not respond, and -ENOSYS if the destination subsystem
- * responds, but with something other than an acknowledgement.
- *
- * If CONFIG_MSM_SYSMON_COMM is not defined, always return success (0).
- */
#ifdef CONFIG_MSM_SYSMON_COMM
int sysmon_send_event(enum subsys_id dest_ss, const char *event_ss,
enum subsys_notif_type notif);
+int sysmon_get_reason(enum subsys_id dest_ss, char *buf, size_t len);
#else
static inline int sysmon_send_event(enum subsys_id dest_ss,
const char *event_ss,
@@ -57,6 +45,11 @@
{
return 0;
}
+static inline int sysmon_get_reason(enum subsys_id dest_ss, char *buf,
+ size_t len)
+{
+ return 0;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index ea8356c..0eabd1b 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -214,9 +214,9 @@
global*global_timer_offset;
if (!(clock->flags & MSM_CLOCK_FLAGS_UNSTABLE_COUNT))
- return __raw_readl(addr);
+ return __raw_readl_no_log(addr);
- t1 = __raw_readl(addr);
+ t1 = __raw_readl_no_log(addr);
t2 = __raw_readl_no_log(addr);
if ((t2-t1) <= 1)
return t2;
@@ -981,7 +981,7 @@
if (cpu_is_msm7x01() || cpu_is_msm7x25() || cpu_is_msm7x27() ||
cpu_is_msm7x25a() || cpu_is_msm7x27a() || cpu_is_msm7x25aa() ||
- cpu_is_msm7x27aa() || cpu_is_msm8625()) {
+ cpu_is_msm7x27aa() || cpu_is_msm8625() || cpu_is_msm7x25ab()) {
dgt->shift = MSM_DGT_SHIFT;
dgt->freq = 19200000 >> MSM_DGT_SHIFT;
dgt->clockevent.shift = 32 + MSM_DGT_SHIFT;
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 7da9e6a..368dd7b 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -26,5 +26,6 @@
#else
static inline int64_t msm_timer_enter_idle(void) { return 0; }
static inline void msm_timer_exit_idle(int low_power) { return; }
+static inline int64_t msm_timer_get_sclk_time(int64_t *period) { return 0; }
#endif
#endif
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index db2a9b4..e81f881 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -2,7 +2,7 @@
* arch/arm/mm/cache-l2x0.c - L210/L220 cache controller support
*
* Copyright (C) 2007 ARM Limited
- * Copyright (c) 2009, 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009, 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 as
@@ -30,8 +30,6 @@
#define CACHE_LINE_SIZE 32
static void __iomem *l2x0_base;
-static uint32_t aux_ctrl_save;
-static uint32_t data_latency_ctrl;
static DEFINE_RAW_SPINLOCK(l2x0_lock);
static uint32_t l2x0_way_mask; /* Bitmask of active ways */
@@ -39,6 +37,7 @@
static u32 l2x0_cache_id;
static unsigned int l2x0_sets;
static unsigned int l2x0_ways;
+static void pl310_save(void);
static inline bool is_pl310_rev(int rev)
{
@@ -447,51 +446,9 @@
printk(KERN_INFO "%s cache controller enabled\n", type);
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
ways, cache_id, aux, l2x0_size);
-}
-void l2x0_suspend(void)
-{
- /* Save aux control register value */
- aux_ctrl_save = readl_relaxed(l2x0_base + L2X0_AUX_CTRL);
- data_latency_ctrl = readl_relaxed(l2x0_base + L2X0_DATA_LATENCY_CTRL);
- /* Flush all cache */
- l2x0_flush_all();
- /* Disable the cache */
- writel_relaxed(0, l2x0_base + L2X0_CTRL);
-
- /* Memory barrier */
- dmb();
-}
-
-void l2x0_resume(int collapsed)
-{
- if (collapsed) {
- /* Disable the cache */
- writel_relaxed(0, l2x0_base + L2X0_CTRL);
-
- /* Restore aux control register value */
- writel_relaxed(aux_ctrl_save, l2x0_base + L2X0_AUX_CTRL);
- writel_relaxed(data_latency_ctrl, l2x0_base +
- L2X0_DATA_LATENCY_CTRL);
-
- /* Invalidate the cache */
- l2x0_inv_all();
- /*
- * TBD: make sure that l2xo_inv_all finished
- * before actually enabling the cache. Logically this
- * is not required as cache sync is atomic operation.
- * but on 8x25, observed the random crashes and they go
- * away if we add dmb or disable the L2.
- * keeping this as temporary workaround until root
- * cause is find out.
- */
- dmb();
- }
-
- /* Enable the cache */
- writel_relaxed(1, l2x0_base + L2X0_CTRL);
-
- mb();
+ /* Save the L2X0 contents, as they are not modified else where */
+ pl310_save();
}
#ifdef CONFIG_OF
@@ -562,6 +519,7 @@
l2x0_base + L2X0_ADDR_FILTER_START);
}
}
+#endif
static void pl310_save(void)
{
@@ -637,6 +595,7 @@
l2x0_resume();
}
+#ifdef CONFIG_OF
static const struct l2x0_of_data pl310_data = {
pl310_of_setup,
pl310_save,
@@ -692,3 +651,15 @@
return 0;
}
#endif
+
+void l2cc_suspend(void)
+{
+ l2x0_disable();
+ dmb();
+}
+
+void l2cc_resume(void)
+{
+ pl310_resume();
+ dmb();
+}
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 0aa88ff..ed160f1 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1144,3 +1144,4 @@
msm8625_evb MACH_MSM8625_EVB MSM8625_EVB 4042
msm8625_qrd7 MACH_MSM8625_QRD7 MSM8625_QRD7 4095
msm8625_ffa MACH_MSM8625_FFA MSM8625_FFA 4166
+msm8625_evt MACH_MSM8625_EVT MSM8625_EVT 4193
diff --git a/drivers/base/genlock.c b/drivers/base/genlock.c
index d9cd600..5e1d7af 100644
--- a/drivers/base/genlock.c
+++ b/drivers/base/genlock.c
@@ -307,12 +307,15 @@
if (handle_has_lock(lock, handle)) {
/*
- * If the handle already holds the lock and the type matches,
- * then just increment the active pointer. This allows the
- * handle to do recursive locks
+ * If the handle already holds the lock and the lock type is
+ * a read lock then just increment the active pointer. This
+ * allows the handle to do recursive read locks. Recursive
+ * write locks are not allowed in order to support
+ * synchronization within a process using a single gralloc
+ * handle.
*/
- if (lock->state == op) {
+ if (lock->state == _RDLOCK && op == _RDLOCK) {
handle->active++;
goto done;
}
@@ -321,33 +324,46 @@
* If the handle holds a write lock then the owner can switch
* to a read lock if they want. Do the transition atomically
* then wake up any pending waiters in case they want a read
- * lock too.
+ * lock too. In order to support synchronization within a
+ * process the caller must explicity request to convert the
+ * lock type with the GENLOCK_WRITE_TO_READ flag.
*/
- if (op == _RDLOCK && handle->active == 1) {
- lock->state = _RDLOCK;
- wake_up(&lock->queue);
+ if (flags & GENLOCK_WRITE_TO_READ) {
+ if (lock->state == _WRLOCK && op == _RDLOCK) {
+ lock->state = _RDLOCK;
+ wake_up(&lock->queue);
+ goto done;
+ } else {
+ GENLOCK_LOG_ERR("Invalid state to convert"
+ "write to read\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ } else {
+
+ /*
+ * Check to ensure the caller has not attempted to convert a
+ * write to a read without holding the lock.
+ */
+
+ if (flags & GENLOCK_WRITE_TO_READ) {
+ GENLOCK_LOG_ERR("Handle must have lock to convert"
+ "write to read\n");
+ ret = -EINVAL;
goto done;
}
/*
- * Otherwise the user tried to turn a read into a write, and we
- * don't allow that.
+ * If we request a read and the lock is held by a read, then go
+ * ahead and share the lock
*/
- GENLOCK_LOG_ERR("Trying to upgrade a read lock to a write"
- "lock\n");
- ret = -EINVAL;
- goto done;
+
+ if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
+ goto dolock;
}
- /*
- * If we request a read and the lock is held by a read, then go
- * ahead and share the lock
- */
-
- if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
- goto dolock;
-
/* Treat timeout 0 just like a NOBLOCK flag and return if the
lock cannot be aquired without blocking */
@@ -356,15 +372,26 @@
goto done;
}
- /* Wait while the lock remains in an incompatible state */
+ /*
+ * Wait while the lock remains in an incompatible state
+ * state op wait
+ * -------------------
+ * unlocked n/a no
+ * read read no
+ * read write yes
+ * write n/a yes
+ */
- while (lock->state != _UNLOCKED) {
+ while ((lock->state == _RDLOCK && op == _WRLOCK) ||
+ lock->state == _WRLOCK) {
signed long elapsed;
spin_unlock_irqrestore(&lock->lock, irqflags);
elapsed = wait_event_interruptible_timeout(lock->queue,
- lock->state == _UNLOCKED, ticks);
+ lock->state == _UNLOCKED ||
+ (lock->state == _RDLOCK && op == _RDLOCK),
+ ticks);
spin_lock_irqsave(&lock->lock, irqflags);
@@ -381,7 +408,7 @@
list_add_tail(&handle->entry, &lock->active);
lock->state = op;
- handle->active = 1;
+ handle->active++;
done:
spin_unlock_irqrestore(&lock->lock, irqflags);
@@ -390,7 +417,7 @@
}
/**
- * genlock_lock - Acquire or release a lock
+ * genlock_lock - Acquire or release a lock (depreciated)
* @handle - pointer to the genlock handle that is requesting the lock
* @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
* @flags - flags to control the operation
@@ -403,6 +430,61 @@
uint32_t timeout)
{
struct genlock *lock;
+ unsigned long irqflags;
+
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(handle)) {
+ GENLOCK_LOG_ERR("Invalid handle\n");
+ return -EINVAL;
+ }
+
+ lock = handle->lock;
+
+ if (lock == NULL) {
+ GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
+ return -EINVAL;
+ }
+
+ switch (op) {
+ case GENLOCK_UNLOCK:
+ ret = _genlock_unlock(lock, handle);
+ break;
+ case GENLOCK_RDLOCK:
+ spin_lock_irqsave(&lock->lock, irqflags);
+ if (handle_has_lock(lock, handle)) {
+ /* request the WRITE_TO_READ flag for compatibility */
+ flags |= GENLOCK_WRITE_TO_READ;
+ }
+ spin_unlock_irqrestore(&lock->lock, irqflags);
+ /* fall through to take lock */
+ case GENLOCK_WRLOCK:
+ ret = _genlock_lock(lock, handle, op, flags, timeout);
+ break;
+ default:
+ GENLOCK_LOG_ERR("Invalid lock operation\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(genlock_lock);
+
+/**
+ * genlock_dreadlock - Acquire or release a lock
+ * @handle - pointer to the genlock handle that is requesting the lock
+ * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
+ * @flags - flags to control the operation
+ * @timeout - optional timeout to wait for the lock to come free
+ *
+ * Returns: 0 on success or error code on failure
+ */
+
+int genlock_dreadlock(struct genlock_handle *handle, int op, int flags,
+ uint32_t timeout)
+{
+ struct genlock *lock;
int ret = 0;
@@ -434,7 +516,7 @@
return ret;
}
-EXPORT_SYMBOL(genlock_lock);
+EXPORT_SYMBOL(genlock_dreadlock);
/**
* genlock_wait - Wait for the lock to be released
@@ -657,6 +739,14 @@
return genlock_lock(handle, param.op, param.flags,
param.timeout);
}
+ case GENLOCK_IOC_DREADLOCK: {
+ if (copy_from_user(¶m, (void __user *) arg,
+ sizeof(param)))
+ return -EFAULT;
+
+ return genlock_dreadlock(handle, param.op, param.flags,
+ param.timeout);
+ }
case GENLOCK_IOC_WAIT: {
if (copy_from_user(¶m, (void __user *) arg,
sizeof(param)))
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 656223b..49d687d 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -162,6 +162,7 @@
int count_write_struct_pool;
int used;
/* Buffers for masks */
+ struct mutex diag_cntl_mutex;
struct diag_ctrl_event_mask *event_mask;
struct diag_ctrl_log_mask *log_mask;
struct diag_ctrl_msg_mask *msg_mask;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 4726da1..a7a4a2a 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -22,7 +22,6 @@
#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/of.h>
-#include <linux/spinlock.h>
#include <linux/kmemleak.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
@@ -60,7 +59,6 @@
int num_items;
int index;
};
-spinlock_t diag_cntl_lock;
#define CREATE_MSG_MASK_TBL_ROW(XX) \
do { \
@@ -775,9 +773,9 @@
void *buf = driver->buf_log_mask_update;
int header_size = sizeof(struct diag_ctrl_log_mask);
struct mask_info *ptr = (struct mask_info *)driver->log_masks;
- int i, size, wr_size = -ENOMEM, retry_count = 0;
- unsigned long flags = 0;
+ int i, size, wr_size = -ENOMEM, retry_count = 0, timer;
+ mutex_lock(&driver->diag_cntl_mutex);
for (i = 0; i < MAX_EQUIP_ID; i++) {
size = (ptr->num_items+7)/8;
/* reached null entry */
@@ -798,15 +796,13 @@
size);
if (ch) {
while (retry_count < 3) {
- spin_lock_irqsave(&diag_cntl_lock,
- flags);
wr_size = smd_write(ch, buf,
header_size + size);
- spin_unlock_irqrestore(&diag_cntl_lock,
- flags);
if (wr_size == -ENOMEM) {
retry_count++;
- usleep(20000);
+ for (timer = 0; timer < 5;
+ timer++)
+ udelay(2000);
} else
break;
}
@@ -822,17 +818,19 @@
}
ptr++;
}
+ mutex_unlock(&driver->diag_cntl_mutex);
}
void diag_send_event_mask_update(smd_channel_t *ch, int num_bytes)
{
void *buf = driver->buf_event_mask_update;
int header_size = sizeof(struct diag_ctrl_event_mask);
- int wr_size = -ENOMEM, retry_count = 0;
- unsigned long flags = 0;
+ int wr_size = -ENOMEM, retry_count = 0, timer;
+ mutex_lock(&driver->diag_cntl_mutex);
if (num_bytes == 0) {
pr_debug("diag: event mask not set yet, so no update\n");
+ mutex_unlock(&driver->diag_cntl_mutex);
return;
}
/* send event mask update */
@@ -846,12 +844,11 @@
memcpy(buf+header_size, driver->event_masks, num_bytes);
if (ch) {
while (retry_count < 3) {
- spin_lock_irqsave(&diag_cntl_lock, flags);
wr_size = smd_write(ch, buf, header_size + num_bytes);
- spin_unlock_irqrestore(&diag_cntl_lock, flags);
if (wr_size == -ENOMEM) {
retry_count++;
- usleep(20000);
+ for (timer = 0; timer < 5; timer++)
+ udelay(2000);
} else
break;
}
@@ -860,17 +857,18 @@
wr_size, header_size + num_bytes);
} else
pr_err("diag: ch not valid for event update\n");
+ mutex_unlock(&driver->diag_cntl_mutex);
}
void diag_send_msg_mask_update(smd_channel_t *ch, int updated_ssid_first,
int updated_ssid_last, int proc)
{
void *buf = driver->buf_msg_mask_update;
- int first, last, size = -ENOMEM, retry_count = 0;
+ int first, last, size = -ENOMEM, retry_count = 0, timer;
int header_size = sizeof(struct diag_ctrl_msg_mask);
uint8_t *ptr = driver->msg_masks;
- unsigned long flags = 0;
+ mutex_lock(&driver->diag_cntl_mutex);
while (*(uint32_t *)(ptr + 4)) {
first = *(uint32_t *)ptr;
ptr += 4;
@@ -893,31 +891,31 @@
4 * (driver->msg_mask->msg_mask_size));
if (ch) {
while (retry_count < 3) {
- spin_lock_irqsave(&diag_cntl_lock,
- flags);
size = smd_write(ch, buf, header_size +
4*(driver->msg_mask->msg_mask_size));
- spin_unlock_irqrestore(&diag_cntl_lock,
- flags);
if (size == -ENOMEM) {
retry_count++;
- usleep(20000);
+ for (timer = 0; timer < 5;
+ timer++)
+ udelay(2000);
} else
break;
}
if (size != header_size +
4*(driver->msg_mask->msg_mask_size))
- pr_err("diag: msg mask update fail %d,"
- " tried %d\n", size,
- header_size + 4*(driver->msg_mask->msg_mask_size));
+ pr_err("diag: proc %d, msg mask update "
+ "fail %d, tried %d\n", proc, size,
+ header_size + 4*(driver->msg_mask->msg_mask_size));
else
pr_debug("diag: sending mask update for"
- " ssid first %d, last %d on PROC %d\n", first, last, proc);
+ "ssid first %d, last %d on PROC %d\n", first, last, proc);
} else
- pr_err("diag: ch invalid msg mask update\n");
+ pr_err("diag: proc %d, ch invalid msg mask"
+ "update\n", proc);
}
ptr += MAX_SSID_PER_RANGE*4;
}
+ mutex_unlock(&driver->diag_cntl_mutex);
}
static int diag_process_apps_pkt(unsigned char *buf, int len)
@@ -962,7 +960,6 @@
#endif
} /* Disable log masks */
else if (*buf == 0x73 && *(int *)(buf+4) == 0) {
- buf += 8;
/* Disable mask for each log code */
diag_disable_log_mask();
diag_update_userspace_clients(LOG_MASKS_TYPE);
@@ -975,17 +972,16 @@
*(int *)(driver->apps_rsp_buf + 4) = 0x0;
if (driver->ch_cntl)
diag_send_log_mask_update(driver->ch_cntl,
- *(int *)buf);
+ ALL_EQUIP_ID);
if (driver->chqdsp_cntl)
diag_send_log_mask_update(driver->chqdsp_cntl,
- *(int *)buf);
+ ALL_EQUIP_ID);
if (driver->ch_wcnss_cntl)
diag_send_log_mask_update(driver->ch_wcnss_cntl,
- *(int *)buf);
+ ALL_EQUIP_ID);
ENCODE_RSP_AND_SEND(7);
return 0;
- } else
- buf = temp;
+ }
#endif
} /* Set runtime message mask */
else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
@@ -1792,7 +1788,7 @@
diag_debug_buf_idx = 0;
driver->read_len_legacy = 0;
driver->use_device_tree = has_device_tree();
- spin_lock_init(&diag_cntl_lock);
+ mutex_init(&driver->diag_cntl_mutex);
if (driver->event_mask == NULL) {
driver->event_mask = kzalloc(sizeof(
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index 865fcc2..81a9fa7 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -393,6 +393,8 @@
case MDP_RGB_565:
case MDP_BGR_565:
case MDP_YCRYCB_H2V1:
+ case MDP_YCBCR_H1V1:
+ case MDP_YCRCB_H1V1:
p->num_planes = 1;
p->plane_size[0] = w * h * get_bpp(format);
break;
@@ -1562,7 +1564,8 @@
}
}
- msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
+ msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
+ "vdd");
if (IS_ERR(msm_rotator_dev->regulator))
msm_rotator_dev->regulator = NULL;
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 6823a5a..9597d18 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -632,8 +632,6 @@
return data;
out:
- msm_free_iova_address(data->iova_addr, domain_num, partition_num,
- buffer->size);
kfree(data);
return ERR_PTR(ret);
}
@@ -1495,21 +1493,28 @@
mutex_unlock(&client->lock);
if (copy_to_user((void __user *)arg, &data, sizeof(data)))
return -EFAULT;
+ if (data.fd < 0)
+ return data.fd;
break;
}
case ION_IOC_IMPORT:
{
struct ion_fd_data data;
+ int ret = 0;
if (copy_from_user(&data, (void __user *)arg,
sizeof(struct ion_fd_data)))
return -EFAULT;
data.handle = ion_import_fd(client, data.fd);
- if (IS_ERR(data.handle))
+ if (IS_ERR(data.handle)) {
+ ret = PTR_ERR(data.handle);
data.handle = NULL;
+ }
if (copy_to_user((void __user *)arg, &data,
sizeof(struct ion_fd_data)))
return -EFAULT;
+ if (ret < 0)
+ return ret;
break;
}
case ION_IOC_CUSTOM:
@@ -1563,6 +1568,8 @@
if (!data.handle)
ion_free(client, handle);
+ if (ret < 0)
+ return ret;
break;
}
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index 84789ef..ca2380b 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -274,8 +274,9 @@
struct iommu_domain *domain;
int ret = 0;
unsigned long extra;
- int prot = ION_IS_CACHED(flags) ? 1 : 0;
struct scatterlist *sglist = 0;
+ int prot = IOMMU_WRITE | IOMMU_READ;
+ prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
data->mapped_size = iova_length;
@@ -320,7 +321,8 @@
if (extra) {
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
- ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra,
+ SZ_4K, prot);
if (ret)
goto out2;
}
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
index b383e68..7f57fe6 100644
--- a/drivers/gpu/ion/ion_cp_heap.c
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -60,8 +60,12 @@
* kernel space (un-cached).
* @umap_count: the total number of times this heap has been mapped in
* user space.
+ * @iommu_iova: saved iova when mapping full heap at once.
+ * @iommu_partition: partition used to map full heap.
* @reusable: indicates if the memory should be reused via fmem.
* @reserved_vrange: reserved virtual address range for use with fmem
+ * @iommu_map_all: Indicates whether we should map whole heap into IOMMU.
+ * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
*/
struct ion_cp_heap {
struct ion_heap heap;
@@ -80,8 +84,13 @@
unsigned long kmap_cached_count;
unsigned long kmap_uncached_count;
unsigned long umap_count;
+ unsigned long iommu_iova[MAX_DOMAINS];
+ unsigned long iommu_partition[MAX_DOMAINS];
int reusable;
void *reserved_vrange;
+ int iommu_map_all;
+ int iommu_2x_map_domain;
+
};
enum {
@@ -247,6 +256,30 @@
return offset;
}
+static void iommu_unmap_all(unsigned long domain_num,
+ struct ion_cp_heap *cp_heap)
+{
+ unsigned long left_to_unmap = cp_heap->total_size;
+ unsigned long order = get_order(SZ_64K);
+ unsigned long page_size = SZ_64K;
+
+ struct iommu_domain *domain = msm_get_iommu_domain(domain_num);
+ if (domain) {
+ unsigned long temp_iova = cp_heap->iommu_iova[domain_num];
+
+ while (left_to_unmap) {
+ iommu_unmap(domain, temp_iova, order);
+ temp_iova += page_size;
+ left_to_unmap -= page_size;
+ }
+ if (domain_num == cp_heap->iommu_2x_map_domain)
+ msm_iommu_unmap_extra(domain, temp_iova,
+ cp_heap->total_size, SZ_64K);
+ } else {
+ pr_err("Unable to get IOMMU domain %lu\n", domain_num);
+ }
+}
+
void ion_cp_free(struct ion_heap *heap, ion_phys_addr_t addr,
unsigned long size)
{
@@ -265,6 +298,26 @@
pr_err("%s: unable to transition heap to T-state\n",
__func__);
}
+
+ /* Unmap everything if we previously mapped the whole heap at once. */
+ if (!cp_heap->allocated_bytes) {
+ unsigned int i;
+ for (i = 0; i < MAX_DOMAINS; ++i) {
+ if (cp_heap->iommu_iova[i]) {
+ unsigned long vaddr_len = cp_heap->total_size;
+
+ if (i == cp_heap->iommu_2x_map_domain)
+ vaddr_len <<= 1;
+ iommu_unmap_all(i, cp_heap);
+
+ msm_free_iova_address(cp_heap->iommu_iova[i], i,
+ cp_heap->iommu_partition[i],
+ vaddr_len);
+ }
+ cp_heap->iommu_iova[i] = 0;
+ cp_heap->iommu_partition[i] = 0;
+ }
+ }
mutex_unlock(&cp_heap->lock);
}
@@ -566,6 +619,75 @@
return ret_value;
}
+static int iommu_map_all(unsigned long domain_num, struct ion_cp_heap *cp_heap,
+ int partition, unsigned long prot)
+{
+ unsigned long left_to_map = cp_heap->total_size;
+ unsigned long order = get_order(SZ_64K);
+ unsigned long page_size = SZ_64K;
+ int ret_value = 0;
+ unsigned long virt_addr_len = cp_heap->total_size;
+ struct iommu_domain *domain = msm_get_iommu_domain(domain_num);
+
+ /* If we are mapping into the video domain we need to map twice the
+ * size of the heap to account for prefetch issue in video core.
+ */
+ if (domain_num == cp_heap->iommu_2x_map_domain)
+ virt_addr_len <<= 1;
+
+ if (cp_heap->total_size & (SZ_64K-1)) {
+ pr_err("Heap size is not aligned to 64K, cannot map into IOMMU\n");
+ ret_value = -EINVAL;
+ }
+ if (cp_heap->base & (SZ_64K-1)) {
+ pr_err("Heap physical address is not aligned to 64K, cannot map into IOMMU\n");
+ ret_value = -EINVAL;
+ }
+ if (!ret_value && domain) {
+ unsigned long temp_phys = cp_heap->base;
+ unsigned long temp_iova =
+ msm_allocate_iova_address(domain_num, partition,
+ virt_addr_len, SZ_64K);
+ if (!temp_iova) {
+ pr_err("%s: could not allocate iova from domain %lu, partition %d\n",
+ __func__, domain_num, partition);
+ ret_value = -ENOMEM;
+ goto out;
+ }
+ cp_heap->iommu_iova[domain_num] = temp_iova;
+
+ while (left_to_map) {
+ int ret = iommu_map(domain, temp_iova, temp_phys,
+ order, prot);
+ if (ret) {
+ pr_err("%s: could not map %lx in domain %p, error: %d\n",
+ __func__, temp_iova, domain, ret);
+ ret_value = -EAGAIN;
+ goto free_iova;
+ }
+ temp_iova += page_size;
+ temp_phys += page_size;
+ left_to_map -= page_size;
+ }
+ if (domain_num == cp_heap->iommu_2x_map_domain)
+ ret_value = msm_iommu_map_extra(domain, temp_iova,
+ cp_heap->total_size,
+ SZ_64K, prot);
+ if (ret_value)
+ goto free_iova;
+ } else {
+ pr_err("Unable to get IOMMU domain %lu\n", domain_num);
+ ret_value = -ENOMEM;
+ }
+ goto out;
+
+free_iova:
+ msm_free_iova_address(cp_heap->iommu_iova[domain_num], domain_num,
+ partition, virt_addr_len);
+out:
+ return ret_value;
+}
+
static int ion_cp_heap_map_iommu(struct ion_buffer *buffer,
struct ion_iommu_map *data,
unsigned int domain_num,
@@ -577,8 +699,11 @@
struct iommu_domain *domain;
int ret = 0;
unsigned long extra;
- int prot = ION_IS_CACHED(flags) ? 1 : 0;
struct scatterlist *sglist = 0;
+ struct ion_cp_heap *cp_heap =
+ container_of(buffer->heap, struct ion_cp_heap, heap);
+ int prot = IOMMU_WRITE | IOMMU_READ;
+ prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
data->mapped_size = iova_length;
@@ -587,6 +712,32 @@
return 0;
}
+ if (cp_heap->iommu_iova[domain_num]) {
+ /* Already mapped. */
+ unsigned long offset = buffer->priv_phys - cp_heap->base;
+ data->iova_addr = cp_heap->iommu_iova[domain_num] + offset;
+ return 0;
+ } else if (cp_heap->iommu_map_all) {
+ ret = iommu_map_all(domain_num, cp_heap, partition_num, prot);
+ if (!ret) {
+ unsigned long offset =
+ buffer->priv_phys - cp_heap->base;
+ data->iova_addr =
+ cp_heap->iommu_iova[domain_num] + offset;
+ cp_heap->iommu_partition[domain_num] = partition_num;
+ /*
+ clear delayed map flag so that we don't interfere
+ with this feature (we are already delaying).
+ */
+ data->flags &= ~ION_IOMMU_UNMAP_DELAYED;
+ return 0;
+ } else {
+ cp_heap->iommu_iova[domain_num] = 0;
+ cp_heap->iommu_partition[domain_num] = 0;
+ return ret;
+ }
+ }
+
extra = iova_length - buffer->size;
data->iova_addr = msm_allocate_iova_address(domain_num, partition_num,
@@ -619,7 +770,8 @@
if (extra) {
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
- ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra,
+ SZ_4K, prot);
if (ret)
goto out2;
}
@@ -642,11 +794,20 @@
unsigned int domain_num;
unsigned int partition_num;
struct iommu_domain *domain;
+ struct ion_cp_heap *cp_heap =
+ container_of(data->buffer->heap, struct ion_cp_heap, heap);
if (!msm_use_iommu())
return;
+
domain_num = iommu_map_domain(data);
+
+ /* If we are mapping everything we'll wait to unmap until everything
+ is freed. */
+ if (cp_heap->iommu_iova[domain_num])
+ return;
+
partition_num = iommu_map_partition(data);
domain = msm_get_iommu_domain(domain_num);
@@ -727,7 +888,13 @@
cp_heap->request_region = extra_data->request_region;
if (extra_data->release_region)
cp_heap->release_region = extra_data->release_region;
+ cp_heap->iommu_map_all =
+ extra_data->iommu_map_all;
+ cp_heap->iommu_2x_map_domain =
+ extra_data->iommu_2x_map_domain;
+
}
+
return &cp_heap->heap;
destroy_pool:
diff --git a/drivers/gpu/ion/ion_iommu_heap.c b/drivers/gpu/ion/ion_iommu_heap.c
index baf0a66..312ca42 100644
--- a/drivers/gpu/ion/ion_iommu_heap.c
+++ b/drivers/gpu/ion/ion_iommu_heap.c
@@ -181,8 +181,9 @@
struct iommu_domain *domain;
int ret = 0;
unsigned long extra;
- int prot = ION_IS_CACHED(flags) ? 1 : 0;
struct ion_iommu_priv_data *buffer_data = buffer->priv_virt;
+ int prot = IOMMU_WRITE | IOMMU_READ;
+ prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
BUG_ON(!msm_use_iommu());
@@ -214,7 +215,8 @@
if (extra) {
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
- ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+ prot);
if (ret)
goto out2;
}
diff --git a/drivers/gpu/ion/ion_system_heap.c b/drivers/gpu/ion/ion_system_heap.c
index 9bb240c..ed9ae27 100644
--- a/drivers/gpu/ion/ion_system_heap.c
+++ b/drivers/gpu/ion/ion_system_heap.c
@@ -228,7 +228,8 @@
int npages = buffer->size >> PAGE_SHIFT;
void *vaddr = buffer->priv_virt;
struct scatterlist *sglist = 0;
- int prot = ION_IS_CACHED(flags) ? 1 : 0;
+ int prot = IOMMU_WRITE | IOMMU_READ;
+ prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
if (!ION_IS_CACHED(flags))
return -EINVAL;
@@ -281,7 +282,8 @@
extra_iova_addr = data->iova_addr + buffer->size;
if (extra) {
- ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+ prot);
if (ret)
goto out2;
}
@@ -440,9 +442,10 @@
int ret = 0;
struct iommu_domain *domain;
unsigned long extra;
- int prot = ION_IS_CACHED(flags) ? 1 : 0;
struct scatterlist *sglist = 0;
struct page *page = 0;
+ int prot = IOMMU_WRITE | IOMMU_READ;
+ prot |= ION_IS_CACHED(flags) ? IOMMU_CACHE : 0;
if (!ION_IS_CACHED(flags))
return -EINVAL;
@@ -488,7 +491,8 @@
if (extra) {
unsigned long extra_iova_addr = data->iova_addr + buffer->size;
- ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, prot);
+ ret = msm_iommu_map_extra(domain, extra_iova_addr, extra, SZ_4K,
+ prot);
if (ret)
goto out2;
}
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 15c0ec5..c8bfce3 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -213,6 +213,45 @@
}
}
+static int is_heap_overlapping(const struct ion_platform_heap *heap1,
+ const struct ion_platform_heap *heap2)
+{
+ unsigned long heap1_base = heap1->base;
+ unsigned long heap2_base = heap2->base;
+ unsigned long heap1_end = heap1->base + heap1->size - 1;
+ unsigned long heap2_end = heap2->base + heap2->size - 1;
+
+ if (heap1_base == heap2_base)
+ return 1;
+ if (heap1_base < heap2_base && heap1_end >= heap2_base)
+ return 1;
+ if (heap2_base < heap1_base && heap2_end >= heap1_base)
+ return 1;
+ return 0;
+}
+
+static void check_for_heap_overlap(const struct ion_platform_heap heap_list[],
+ unsigned long nheaps)
+{
+ unsigned long i;
+ unsigned long j;
+
+ for (i = 0; i < nheaps; ++i) {
+ const struct ion_platform_heap *heap1 = &heap_list[i];
+ if (!heap1->base)
+ continue;
+ for (j = i + 1; j < nheaps; ++j) {
+ const struct ion_platform_heap *heap2 = &heap_list[j];
+ if (!heap2->base)
+ continue;
+ if (is_heap_overlapping(heap1, heap2)) {
+ panic("Memory in heap %s overlaps with heap %s\n",
+ heap1->name, heap2->name);
+ }
+ }
+ }
+}
+
static int msm_ion_probe(struct platform_device *pdev)
{
struct ion_platform_data *pdata = pdev->dev.platform_data;
@@ -258,6 +297,8 @@
ion_device_add_heap(idev, heaps[i]);
}
+
+ check_for_heap_overlap(pdata->heaps, num_heaps);
platform_set_drvdata(pdev, idev);
return 0;
diff --git a/drivers/gpu/msm/a2xx_reg.h b/drivers/gpu/msm/a2xx_reg.h
index 4c0bd19..41cb601 100644
--- a/drivers/gpu/msm/a2xx_reg.h
+++ b/drivers/gpu/msm/a2xx_reg.h
@@ -140,24 +140,9 @@
struct rb_edram_info_t f;
};
-#define RBBM_READ_ERROR_UNUSED0_SIZE 2
-#define RBBM_READ_ERROR_READ_ADDRESS_SIZE 15
-#define RBBM_READ_ERROR_UNUSED1_SIZE 13
-#define RBBM_READ_ERROR_READ_REQUESTER_SIZE 1
-#define RBBM_READ_ERROR_READ_ERROR_SIZE 1
-
-struct rbbm_read_error_t {
- unsigned int unused0:RBBM_READ_ERROR_UNUSED0_SIZE;
- unsigned int read_address:RBBM_READ_ERROR_READ_ADDRESS_SIZE;
- unsigned int unused1:RBBM_READ_ERROR_UNUSED1_SIZE;
- unsigned int read_requester:RBBM_READ_ERROR_READ_REQUESTER_SIZE;
- unsigned int read_error:RBBM_READ_ERROR_READ_ERROR_SIZE;
-};
-
-union rbbm_read_error_u {
- unsigned int val:32;
- struct rbbm_read_error_t f;
-};
+#define RBBM_READ_ERROR_ADDRESS_MASK 0x0001fffc
+#define RBBM_READ_ERROR_REQUESTER (1<<30)
+#define RBBM_READ_ERROR_ERROR (1<<31)
#define CP_RB_CNTL_RB_BUFSZ_SIZE 6
#define CP_RB_CNTL_UNUSED0_SIZE 2
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 7c152721..bfbf411 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -69,10 +69,9 @@
static struct adreno_device device_3d0 = {
.dev = {
+ KGSL_DEVICE_COMMON_INIT(device_3d0.dev),
.name = DEVICE_3D0_NAME,
.id = KGSL_DEVICE_3D0,
- .ver_major = DRIVER_VERSION_MAJOR,
- .ver_minor = DRIVER_VERSION_MINOR,
.mh = {
.mharb = ADRENO_CFG_MHARB,
/* Remove 1k boundary check in z470 to avoid a GPU
@@ -90,12 +89,8 @@
.config = ADRENO_MMU_CONFIG,
},
.pwrctrl = {
- .regulator_name = "fs_gfx3d",
.irq_name = KGSL_3D0_IRQ,
},
- .mutex = __MUTEX_INITIALIZER(device_3d0.dev.mutex),
- .state = KGSL_STATE_INIT,
- .active_cnt = 0,
.iomemname = KGSL_3D0_REG_MEMORY,
.ftbl = &adreno_functable,
#ifdef CONFIG_HAS_EARLYSUSPEND
@@ -483,8 +478,6 @@
adreno_dev = ADRENO_DEVICE(device);
device->parentdev = &pdev->dev;
- init_completion(&device->recovery_gate);
-
status = adreno_ringbuffer_init(device);
if (status != 0)
goto error;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 95378a1..a7ea20c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -108,8 +108,10 @@
/* A2XX register sets defined in adreno_a2xx.c */
extern const unsigned int a200_registers[];
extern const unsigned int a220_registers[];
+extern const unsigned int a225_registers[];
extern const unsigned int a200_registers_count;
extern const unsigned int a220_registers_count;
+extern const unsigned int a225_registers_count;
/* A3XX register set defined in adreno_a3xx.c */
extern const unsigned int a3xx_registers[];
diff --git a/drivers/gpu/msm/adreno_a2xx.c b/drivers/gpu/msm/adreno_a2xx.c
index e10edea..eb936f8 100644
--- a/drivers/gpu/msm/adreno_a2xx.c
+++ b/drivers/gpu/msm/adreno_a2xx.c
@@ -55,7 +55,6 @@
0x4000, 0x4003, 0x4800, 0x4805, 0x4900, 0x4900, 0x4908, 0x4908,
};
-/* A220, A225 */
const unsigned int a220_registers[] = {
0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
0x0046, 0x0047, 0x01C0, 0x01C1, 0x01C3, 0x01C8, 0x01D5, 0x01D9,
@@ -85,8 +84,40 @@
0x4900, 0x4900, 0x4908, 0x4908,
};
+const unsigned int a225_registers[] = {
+ 0x0000, 0x0002, 0x0004, 0x000B, 0x003B, 0x003D, 0x0040, 0x0044,
+ 0x0046, 0x0047, 0x013C, 0x013C, 0x0140, 0x014F, 0x01C0, 0x01C1,
+ 0x01C3, 0x01C8, 0x01D5, 0x01D9, 0x01DC, 0x01DD, 0x01EA, 0x01EA,
+ 0x01EE, 0x01F3, 0x01F6, 0x01F7, 0x01FC, 0x01FF, 0x0391, 0x0392,
+ 0x039B, 0x039E, 0x03B2, 0x03B5, 0x03B7, 0x03B7, 0x03F8, 0x03FB,
+ 0x0440, 0x0440, 0x0443, 0x0444, 0x044B, 0x044B, 0x044D, 0x044F,
+ 0x0452, 0x0452, 0x0454, 0x045B, 0x047F, 0x047F, 0x0578, 0x0587,
+ 0x05C9, 0x05C9, 0x05D0, 0x05D0, 0x0601, 0x0604, 0x0606, 0x0609,
+ 0x060B, 0x060E, 0x0613, 0x0614, 0x0A29, 0x0A2B, 0x0A2F, 0x0A31,
+ 0x0A40, 0x0A40, 0x0A42, 0x0A43, 0x0A45, 0x0A45, 0x0A4E, 0x0A4F,
+ 0x0C01, 0x0C1D, 0x0C30, 0x0C30, 0x0C38, 0x0C39, 0x0C3C, 0x0C3C,
+ 0x0C80, 0x0C81, 0x0C88, 0x0C93, 0x0D00, 0x0D03, 0x0D05, 0x0D06,
+ 0x0D08, 0x0D0B, 0x0D34, 0x0D35, 0x0DAE, 0x0DC1, 0x0DC8, 0x0DD4,
+ 0x0DD8, 0x0DD9, 0x0E00, 0x0E00, 0x0E02, 0x0E04, 0x0E17, 0x0E1E,
+ 0x0EC0, 0x0EC9, 0x0ECB, 0x0ECC, 0x0ED0, 0x0ED0, 0x0ED4, 0x0ED7,
+ 0x0EE0, 0x0EE2, 0x0F01, 0x0F02, 0x2000, 0x200F, 0x2080, 0x2082,
+ 0x2100, 0x2109, 0x210C, 0x2114, 0x2180, 0x2184, 0x21F5, 0x21F7,
+ 0x2200, 0x2202, 0x2204, 0x2206, 0x2208, 0x2210, 0x2220, 0x2222,
+ 0x2280, 0x2282, 0x2294, 0x2294, 0x2297, 0x2297, 0x2300, 0x230A,
+ 0x2312, 0x2312, 0x2315, 0x2316, 0x2318, 0x231D, 0x2324, 0x2326,
+ 0x2340, 0x2357, 0x2360, 0x2360, 0x2380, 0x2383, 0x2400, 0x240F,
+ 0x2480, 0x2482, 0x2500, 0x2509, 0x250C, 0x2514, 0x2580, 0x2584,
+ 0x25F5, 0x25F7, 0x2600, 0x2602, 0x2604, 0x2606, 0x2608, 0x2610,
+ 0x2620, 0x2622, 0x2680, 0x2682, 0x2694, 0x2694, 0x2697, 0x2697,
+ 0x2700, 0x270A, 0x2712, 0x2712, 0x2715, 0x2716, 0x2718, 0x271D,
+ 0x2724, 0x2726, 0x2740, 0x2757, 0x2760, 0x2760, 0x2780, 0x2783,
+ 0x4000, 0x4003, 0x4800, 0x4806, 0x4808, 0x4808, 0x4900, 0x4900,
+ 0x4908, 0x4908,
+};
+
const unsigned int a200_registers_count = ARRAY_SIZE(a200_registers) / 2;
const unsigned int a220_registers_count = ARRAY_SIZE(a220_registers) / 2;
+const unsigned int a225_registers_count = ARRAY_SIZE(a225_registers) / 2;
/*
*
@@ -1694,21 +1725,33 @@
{
unsigned int status = 0;
unsigned int rderr = 0;
+ unsigned int addr = 0;
+ const char *source;
adreno_regread(device, REG_RBBM_INT_STATUS, &status);
if (status & RBBM_INT_CNTL__RDERR_INT_MASK) {
- union rbbm_read_error_u rerr;
adreno_regread(device, REG_RBBM_READ_ERROR, &rderr);
- rerr.val = rderr;
- if (rerr.f.read_address == REG_CP_INT_STATUS &&
- rerr.f.read_error &&
- rerr.f.read_requester)
+ source = (rderr & RBBM_READ_ERROR_REQUESTER)
+ ? "host" : "cp";
+ /* convert to dword address */
+ addr = (rderr & RBBM_READ_ERROR_ADDRESS_MASK) >> 2;
+
+ /*
+ * Log CP_INT_STATUS interrupts from the CP at a
+ * lower level because they can happen frequently
+ * and are worked around in a2xx_irq_handler.
+ */
+ if (addr == REG_CP_INT_STATUS &&
+ rderr & RBBM_READ_ERROR_ERROR &&
+ rderr & RBBM_READ_ERROR_REQUESTER)
KGSL_DRV_WARN(device,
- "rbbm read error interrupt: %08x\n", rderr);
+ "rbbm read error interrupt: %s reg: %04X\n",
+ source, addr);
else
KGSL_DRV_CRIT(device,
- "rbbm read error interrupt: %08x\n", rderr);
+ "rbbm read error interrupt: %s reg: %04X\n",
+ source, addr);
}
status &= RBBM_INT_MASK;
diff --git a/drivers/gpu/msm/adreno_a2xx_snapshot.c b/drivers/gpu/msm/adreno_a2xx_snapshot.c
index 091db22..2368264 100644
--- a/drivers/gpu/msm/adreno_a2xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a2xx_snapshot.c
@@ -240,9 +240,12 @@
if (adreno_is_a20x(adreno_dev)) {
regs.regs = (unsigned int *) a200_registers;
regs.count = a200_registers_count;
- } else {
+ } else if (adreno_is_a220(adreno_dev)) {
regs.regs = (unsigned int *) a220_registers;
regs.count = a220_registers_count;
+ } else if (adreno_is_a225(adreno_dev)) {
+ regs.regs = (unsigned int *) a225_registers;
+ regs.count = a225_registers_count;
}
/* Master set of (non debug) registers */
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 8c5d76a..5187eb1 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -2599,7 +2599,7 @@
adreno_regwrite(device, A3XX_RBBM_AHB_CTL1, 0xA6FFFFFF);
/* Turn on the power counters */
- adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00003000);
+ adreno_regwrite(device, A3XX_RBBM_RBBM_CTL, 0x00030000);
/* Turn on hang detection - this spews a lot of useful information
* into the RBBM registers on a hang */
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 9d68c60..ec38f75 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -859,6 +859,9 @@
else if (adreno_is_a22x(adreno_dev))
adreno_dump_regs(device, a220_registers,
a220_registers_count);
+ else if (adreno_is_a225(adreno_dev))
+ adreno_dump_regs(device, a225_registers,
+ a225_registers_count);
else if (adreno_is_a3xx(adreno_dev))
adreno_dump_regs(device, a3xx_registers,
a3xx_registers_count);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index d4089b9..8d900b0 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -337,8 +337,9 @@
if (status != 0)
return status;
+ /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
if (adreno_is_a305(adreno_dev) || adreno_is_a320(adreno_dev))
- adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000F0602);
+ adreno_regwrite(device, REG_CP_QUEUE_THRESHOLDS, 0x000E0602);
rb->rptr = 0;
rb->wptr = 0;
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 072edad..adf2772 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -25,6 +25,8 @@
#include <linux/ashmem.h>
#include <linux/major.h>
#include <linux/ion.h>
+#include <linux/io.h>
+#include <mach/socinfo.h>
#include "kgsl.h"
#include "kgsl_debugfs.h"
@@ -385,7 +387,7 @@
idr_remove(&dev_priv->device->context_idr, id);
}
-static void kgsl_timestamp_expired(struct work_struct *work)
+void kgsl_timestamp_expired(struct work_struct *work)
{
struct kgsl_device *device = container_of(work, struct kgsl_device,
ts_expired_ws);
@@ -415,6 +417,7 @@
mutex_unlock(&device->mutex);
}
+EXPORT_SYMBOL(kgsl_timestamp_expired);
static void kgsl_check_idle_locked(struct kgsl_device *device)
{
@@ -651,6 +654,8 @@
KGSL_PWR_WARN(device, "late resume start\n");
mutex_lock(&device->mutex);
device->pwrctrl.restore_slumber = 0;
+ if (device->pwrscale.policy == NULL)
+ kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
kgsl_pwrctrl_wake(device);
mutex_unlock(&device->mutex);
kgsl_check_idle(device);
@@ -1846,10 +1851,20 @@
kgsl_check_idle(dev_priv->device);
return result;
- error_put_file_ptr:
- if (entry->priv_data)
- fput(entry->priv_data);
-
+error_put_file_ptr:
+ switch (entry->memtype) {
+ case KGSL_MEM_ENTRY_PMEM:
+ case KGSL_MEM_ENTRY_ASHMEM:
+ if (entry->priv_data)
+ fput(entry->priv_data);
+ break;
+ case KGSL_MEM_ENTRY_ION:
+ ion_unmap_dma(kgsl_ion_client, entry->priv_data);
+ ion_free(kgsl_ion_client, entry->priv_data);
+ break;
+ default:
+ break;
+ }
error:
kfree(entry);
kgsl_check_idle(dev_priv->device);
@@ -2322,7 +2337,7 @@
};
EXPORT_SYMBOL(kgsl_driver);
-void kgsl_unregister_device(struct kgsl_device *device)
+static void _unregister_device(struct kgsl_device *device)
{
int minor;
@@ -2331,43 +2346,15 @@
if (device == kgsl_driver.devp[minor])
break;
}
-
- mutex_unlock(&kgsl_driver.devlock);
-
- if (minor == KGSL_DEVICE_MAX)
- return;
-
- kgsl_device_snapshot_close(device);
-
- kgsl_cffdump_close(device->id);
- kgsl_pwrctrl_uninit_sysfs(device);
-
- wake_lock_destroy(&device->idle_wakelock);
- pm_qos_remove_request(&device->pm_qos_req_dma);
-
- idr_destroy(&device->context_idr);
-
- if (device->memstore.hostptr)
- kgsl_sharedmem_free(&device->memstore);
-
- kgsl_mmu_close(device);
-
- if (device->work_queue) {
- destroy_workqueue(device->work_queue);
- device->work_queue = NULL;
+ if (minor != KGSL_DEVICE_MAX) {
+ device_destroy(kgsl_driver.class,
+ MKDEV(MAJOR(kgsl_driver.major), minor));
+ kgsl_driver.devp[minor] = NULL;
}
-
- device_destroy(kgsl_driver.class,
- MKDEV(MAJOR(kgsl_driver.major), minor));
-
- mutex_lock(&kgsl_driver.devlock);
- kgsl_driver.devp[minor] = NULL;
mutex_unlock(&kgsl_driver.devlock);
}
-EXPORT_SYMBOL(kgsl_unregister_device);
-int
-kgsl_register_device(struct kgsl_device *device)
+static int _register_device(struct kgsl_device *device)
{
int minor, ret;
dev_t dev;
@@ -2381,7 +2368,6 @@
break;
}
}
-
mutex_unlock(&kgsl_driver.devlock);
if (minor == KGSL_DEVICE_MAX) {
@@ -2397,75 +2383,17 @@
device->name);
if (IS_ERR(device->dev)) {
+ mutex_lock(&kgsl_driver.devlock);
+ kgsl_driver.devp[minor] = NULL;
+ mutex_unlock(&kgsl_driver.devlock);
ret = PTR_ERR(device->dev);
KGSL_CORE_ERR("device_create(%s): %d\n", device->name, ret);
- goto err_devlist;
+ return ret;
}
dev_set_drvdata(device->parentdev, device);
-
- /* Generic device initialization */
- init_waitqueue_head(&device->wait_queue);
-
- kgsl_cffdump_open(device->id);
-
- init_completion(&device->hwaccess_gate);
- init_completion(&device->suspend_gate);
-
- ATOMIC_INIT_NOTIFIER_HEAD(&device->ts_notifier_list);
-
- setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
- ret = kgsl_create_device_workqueue(device);
- if (ret)
- goto err_devlist;
-
- INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
- INIT_WORK(&device->ts_expired_ws, kgsl_timestamp_expired);
-
- INIT_LIST_HEAD(&device->events);
-
- device->last_expired_ctxt_id = KGSL_CONTEXT_INVALID;
-
- ret = kgsl_mmu_init(device);
- if (ret != 0)
- goto err_dest_work_q;
-
- ret = kgsl_allocate_contiguous(&device->memstore, KGSL_MEMSTORE_SIZE);
- if (ret != 0)
- goto err_close_mmu;
-
- wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
- pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
- PM_QOS_DEFAULT_VALUE);
-
- idr_init(&device->context_idr);
-
- /* Initalize the snapshot engine */
- kgsl_device_snapshot_init(device);
-
- /* sysfs and debugfs initalization - failure here is non fatal */
-
- /* Initialize logging */
- kgsl_device_debugfs_init(device);
-
- /* Initialize common sysfs entries */
- kgsl_pwrctrl_init_sysfs(device);
-
return 0;
-
-err_close_mmu:
- kgsl_mmu_close(device);
-err_dest_work_q:
- destroy_workqueue(device->work_queue);
- device->work_queue = NULL;
-err_devlist:
- mutex_lock(&kgsl_driver.devlock);
- kgsl_driver.devp[minor] = NULL;
- mutex_unlock(&kgsl_driver.devlock);
-
- return ret;
}
-EXPORT_SYMBOL(kgsl_register_device);
int kgsl_device_platform_probe(struct kgsl_device *device)
{
@@ -2475,7 +2403,12 @@
struct platform_device *pdev =
container_of(device->parentdev, struct platform_device, dev);
- pm_runtime_enable(device->parentdev);
+ status = _register_device(device);
+ if (status)
+ return status;
+
+ /* Initialize logging first, so that failures below actually print. */
+ kgsl_device_debugfs_init(device);
status = kgsl_pwrctrl_init(device);
if (status)
@@ -2500,29 +2433,40 @@
device->reg_phys = res->start;
device->reg_len = resource_size(res);
- if (!request_mem_region(device->reg_phys, device->reg_len,
- device->name)) {
+ if (!devm_request_mem_region(device->dev, device->reg_phys,
+ device->reg_len, device->name)) {
KGSL_DRV_ERR(device, "request_mem_region failed\n");
status = -ENODEV;
goto error_pwrctrl_close;
}
- device->reg_virt = ioremap(device->reg_phys, device->reg_len);
+ device->reg_virt = devm_ioremap(device->dev, device->reg_phys,
+ device->reg_len);
if (device->reg_virt == NULL) {
KGSL_DRV_ERR(device, "ioremap failed\n");
status = -ENODEV;
- goto error_release_mem;
+ goto error_pwrctrl_close;
+ }
+ /*acquire interrupt */
+ device->pwrctrl.interrupt_num =
+ platform_get_irq_byname(pdev, device->pwrctrl.irq_name);
+
+ if (device->pwrctrl.interrupt_num <= 0) {
+ KGSL_DRV_ERR(device, "platform_get_irq_byname failed: %d\n",
+ device->pwrctrl.interrupt_num);
+ status = -EINVAL;
+ goto error_pwrctrl_close;
}
- status = request_irq(device->pwrctrl.interrupt_num, kgsl_irq_handler,
- IRQF_TRIGGER_HIGH, device->name, device);
+ status = devm_request_irq(device->dev, device->pwrctrl.interrupt_num,
+ kgsl_irq_handler, IRQF_TRIGGER_HIGH,
+ device->name, device);
if (status) {
KGSL_DRV_ERR(device, "request_irq(%d) failed: %d\n",
device->pwrctrl.interrupt_num, status);
- goto error_iounmap;
+ goto error_pwrctrl_close;
}
- device->pwrctrl.have_irq = 1;
disable_irq(device->pwrctrl.interrupt_num);
KGSL_DRV_INFO(device,
@@ -2532,38 +2476,78 @@
result = kgsl_drm_init(pdev);
if (result)
- goto error_iounmap;
+ goto error_pwrctrl_close;
- status = kgsl_register_device(device);
- if (!status)
- return status;
+ kgsl_cffdump_open(device->id);
- free_irq(device->pwrctrl.interrupt_num, NULL);
- device->pwrctrl.have_irq = 0;
-error_iounmap:
- iounmap(device->reg_virt);
- device->reg_virt = NULL;
-error_release_mem:
- release_mem_region(device->reg_phys, device->reg_len);
+ setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+ status = kgsl_create_device_workqueue(device);
+ if (status)
+ goto error_pwrctrl_close;
+
+ status = kgsl_mmu_init(device);
+ if (status != 0) {
+ KGSL_DRV_ERR(device, "kgsl_mmu_init failed %d\n", status);
+ goto error_dest_work_q;
+ }
+
+ status = kgsl_allocate_contiguous(&device->memstore,
+ sizeof(struct kgsl_devmemstore));
+
+ if (status != 0) {
+ KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
+ status);
+ goto error_close_mmu;
+ }
+
+ wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
+ pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
+ /* Initalize the snapshot engine */
+ kgsl_device_snapshot_init(device);
+
+ /* Initialize common sysfs entries */
+ kgsl_pwrctrl_init_sysfs(device);
+
+ return 0;
+
+error_close_mmu:
+ kgsl_mmu_close(device);
+error_dest_work_q:
+ destroy_workqueue(device->work_queue);
+ device->work_queue = NULL;
error_pwrctrl_close:
kgsl_pwrctrl_close(device);
error:
+ _unregister_device(device);
return status;
}
EXPORT_SYMBOL(kgsl_device_platform_probe);
void kgsl_device_platform_remove(struct kgsl_device *device)
{
- kgsl_unregister_device(device);
+ kgsl_device_snapshot_close(device);
- if (device->reg_virt != NULL) {
- iounmap(device->reg_virt);
- device->reg_virt = NULL;
- release_mem_region(device->reg_phys, device->reg_len);
+ kgsl_cffdump_close(device->id);
+ kgsl_pwrctrl_uninit_sysfs(device);
+
+ wake_lock_destroy(&device->idle_wakelock);
+ pm_qos_remove_request(&device->pm_qos_req_dma);
+
+ idr_destroy(&device->context_idr);
+
+ kgsl_sharedmem_free(&device->memstore);
+
+ kgsl_mmu_close(device);
+
+ if (device->work_queue) {
+ destroy_workqueue(device->work_queue);
+ device->work_queue = NULL;
}
kgsl_pwrctrl_close(device);
- pm_runtime_disable(device->parentdev);
+ _unregister_device(device);
}
EXPORT_SYMBOL(kgsl_device_platform_remove);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 9f80a73..da3e4b2 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -44,7 +44,7 @@
#define KGSL_PAGETABLE_ENTRY_SIZE 4
/* Pagetable Virtual Address base */
-#define KGSL_PAGETABLE_BASE 0x66000000
+#define KGSL_PAGETABLE_BASE 0x10000000
/* Extra accounting entries needed in the pagetable */
#define KGSL_PT_EXTRA_ENTRIES 16
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index b42e606..0964458 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -199,6 +199,26 @@
s64 on_time;
};
+void kgsl_timestamp_expired(struct work_struct *work);
+
+#define KGSL_DEVICE_COMMON_INIT(_dev) \
+ .hwaccess_gate = COMPLETION_INITIALIZER((_dev).hwaccess_gate),\
+ .suspend_gate = COMPLETION_INITIALIZER((_dev).suspend_gate),\
+ .recovery_gate = COMPLETION_INITIALIZER((_dev).recovery_gate),\
+ .ts_notifier_list = ATOMIC_NOTIFIER_INIT((_dev).ts_notifier_list),\
+ .idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
+ kgsl_idle_check),\
+ .ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\
+ kgsl_timestamp_expired),\
+ .context_idr = IDR_INIT((_dev).context_idr),\
+ .events = LIST_HEAD_INIT((_dev).events),\
+ .wait_queue = __WAIT_QUEUE_HEAD_INITIALIZER((_dev).wait_queue),\
+ .mutex = __MUTEX_INITIALIZER((_dev).mutex),\
+ .state = KGSL_STATE_INIT,\
+ .ver_major = DRIVER_VERSION_MAJOR,\
+ .ver_minor = DRIVER_VERSION_MINOR,\
+ .last_expired_ctxt_id = KGSL_CONTEXT_INVALID
+
struct kgsl_context {
uint32_t id;
diff --git a/drivers/gpu/msm/kgsl_gpummu.c b/drivers/gpu/msm/kgsl_gpummu.c
index 5a10654..a477439 100644
--- a/drivers/gpu/msm/kgsl_gpummu.c
+++ b/drivers/gpu/msm/kgsl_gpummu.c
@@ -518,14 +518,6 @@
"for GPUMMU: %x\n", CONFIG_MSM_KGSL_PAGE_TABLE_SIZE);
return -EINVAL;
}
-
- /* allocate memory used for completing r/w operations that
- * cannot be mapped by the MMU
- */
- status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
- if (!status)
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
- mmu->setstate_memory.size);
}
dev_info(mmu->device->dev, "|%s| MMU type set for device is GPUMMU\n",
@@ -725,6 +717,9 @@
.mmu_device_setstate = kgsl_gpummu_default_setstate,
.mmu_pagefault = kgsl_gpummu_pagefault,
.mmu_get_current_ptbase = kgsl_gpummu_get_current_ptbase,
+ .mmu_enable_clk = NULL,
+ .mmu_disable_clk = NULL,
+ .mmu_get_hwpagetable_asid = NULL,
};
struct kgsl_mmu_pt_ops gpummu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index e2a945f..7d527e4 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -24,27 +24,149 @@
#include "kgsl_sharedmem.h"
#include "kgsl_iommu.h"
+/*
+ * kgsl_iommu_disable_clk - Disable iommu clocks
+ * @mmu - Pointer to mmu structure
+ *
+ * Disables iommu clocks
+ * Return - void
+ */
+static void kgsl_iommu_disable_clk(struct kgsl_mmu *mmu)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct msm_iommu_drvdata *iommu_drvdata;
+ int i, j;
+
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++) {
+ if (!iommu_unit->dev[j].clk_enabled)
+ continue;
+ iommu_drvdata = dev_get_drvdata(
+ iommu_unit->dev[j].dev->parent);
+ if (iommu_drvdata->clk)
+ clk_disable_unprepare(iommu_drvdata->clk);
+ clk_disable_unprepare(iommu_drvdata->pclk);
+ iommu_unit->dev[j].clk_enabled = false;
+ }
+ }
+}
+
+/*
+ * kgsl_iommu_enable_clk - Enable iommu clocks
+ * @mmu - Pointer to mmu structure
+ * @ctx_id - The context bank whose clocks are to be turned on
+ *
+ * Enables iommu clocks of a given context
+ * Return: 0 on success else error code
+ */
+static int kgsl_iommu_enable_clk(struct kgsl_mmu *mmu,
+ int ctx_id)
+{
+ int ret = 0;
+ int i, j;
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct msm_iommu_drvdata *iommu_drvdata;
+
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++) {
+ if (iommu_unit->dev[j].clk_enabled ||
+ ctx_id != iommu_unit->dev[j].ctx_id)
+ continue;
+ iommu_drvdata =
+ dev_get_drvdata(iommu_unit->dev[j].dev->parent);
+ ret = clk_prepare_enable(iommu_drvdata->pclk);
+ if (ret)
+ goto done;
+ if (iommu_drvdata->clk) {
+ ret = clk_prepare_enable(iommu_drvdata->clk);
+ if (ret) {
+ clk_disable_unprepare(
+ iommu_drvdata->pclk);
+ goto done;
+ }
+ }
+ iommu_unit->dev[j].clk_enabled = true;
+ }
+ }
+done:
+ if (ret)
+ kgsl_iommu_disable_clk(mmu);
+ return ret;
+}
+
+/*
+ * kgsl_iommu_pt_equal - Check if pagetables are equal
+ * @pt - Pointer to pagetable
+ * @pt_base - Address of a pagetable that the IOMMU register is
+ * programmed with
+ *
+ * Checks whether the pt_base is equal to the base address of
+ * the pagetable which is contained in the pt structure
+ * Return - Non-zero if the pagetable addresses are equal else 0
+ */
static int kgsl_iommu_pt_equal(struct kgsl_pagetable *pt,
unsigned int pt_base)
{
- struct iommu_domain *domain = pt ? pt->priv : NULL;
- return domain && pt_base && ((unsigned int)domain == pt_base);
+ struct kgsl_iommu_pt *iommu_pt = pt ? pt->priv : NULL;
+ unsigned int domain_ptbase = iommu_pt ?
+ iommu_get_pt_base_addr(iommu_pt->domain) : 0;
+ /* Only compare the valid address bits of the pt_base */
+ domain_ptbase &= (KGSL_IOMMU_TTBR0_PA_MASK <<
+ KGSL_IOMMU_TTBR0_PA_SHIFT);
+ pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK <<
+ KGSL_IOMMU_TTBR0_PA_SHIFT);
+ return domain_ptbase && pt_base &&
+ (domain_ptbase == pt_base);
}
+/*
+ * kgsl_iommu_destroy_pagetable - Free up reaources help by a pagetable
+ * @mmu_specific_pt - Pointer to pagetable which is to be freed
+ *
+ * Return - void
+ */
static void kgsl_iommu_destroy_pagetable(void *mmu_specific_pt)
{
- struct iommu_domain *domain = mmu_specific_pt;
- if (domain)
- iommu_domain_free(domain);
+ struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
+ if (iommu_pt->domain)
+ iommu_domain_free(iommu_pt->domain);
+ if (iommu_pt->iommu) {
+ if ((KGSL_IOMMU_ASID_REUSE == iommu_pt->asid) &&
+ iommu_pt->iommu->asid_reuse)
+ iommu_pt->iommu->asid_reuse--;
+ if (!iommu_pt->iommu->asid_reuse ||
+ (KGSL_IOMMU_ASID_REUSE != iommu_pt->asid))
+ clear_bit(iommu_pt->asid, iommu_pt->iommu->asids);
+ }
+ kfree(iommu_pt);
}
+/*
+ * kgsl_iommu_create_pagetable - Create a IOMMU pagetable
+ *
+ * Allocate memory to hold a pagetable and allocate the IOMMU
+ * domain which is the actual IOMMU pagetable
+ * Return - void
+ */
void *kgsl_iommu_create_pagetable(void)
{
- struct iommu_domain *domain = iommu_domain_alloc(0);
- if (!domain)
- KGSL_CORE_ERR("Failed to create iommu domain\n");
+ struct kgsl_iommu_pt *iommu_pt;
- return domain;
+ iommu_pt = kzalloc(sizeof(struct kgsl_iommu_pt), GFP_KERNEL);
+ if (!iommu_pt) {
+ KGSL_CORE_ERR("kzalloc(%d) failed\n",
+ sizeof(struct kgsl_iommu_pt));
+ return NULL;
+ }
+ iommu_pt->domain = iommu_domain_alloc(0);
+ if (!iommu_pt->domain) {
+ KGSL_CORE_ERR("Failed to create iommu domain\n");
+ kfree(iommu_pt);
+ return NULL;
+ }
+ return iommu_pt;
}
/*
@@ -61,25 +183,25 @@
*/
static void kgsl_detach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
{
- struct iommu_domain *domain;
+ struct kgsl_iommu_pt *iommu_pt;
struct kgsl_iommu *iommu = mmu->priv;
int i, j;
BUG_ON(mmu->hwpagetable == NULL);
BUG_ON(mmu->hwpagetable->priv == NULL);
- domain = mmu->hwpagetable->priv;
+ iommu_pt = mmu->hwpagetable->priv;
for (i = 0; i < iommu->unit_count; i++) {
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
if (iommu_unit->dev[j].attached) {
- iommu_detach_device(domain,
+ iommu_detach_device(iommu_pt->domain,
iommu_unit->dev[j].dev);
iommu_unit->dev[j].attached = false;
KGSL_MEM_INFO(mmu->device, "iommu %p detached "
"from user dev of MMU: %p\n",
- domain, mmu);
+ iommu_pt->domain, mmu);
}
}
}
@@ -100,14 +222,14 @@
*/
static int kgsl_attach_pagetable_iommu_domain(struct kgsl_mmu *mmu)
{
- struct iommu_domain *domain;
+ struct kgsl_iommu_pt *iommu_pt;
struct kgsl_iommu *iommu = mmu->priv;
int i, j, ret = 0;
BUG_ON(mmu->hwpagetable == NULL);
BUG_ON(mmu->hwpagetable->priv == NULL);
- domain = mmu->hwpagetable->priv;
+ iommu_pt = mmu->hwpagetable->priv;
/*
* Loop through all the iommu devcies under all iommu units and
@@ -117,7 +239,7 @@
struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
for (j = 0; j < iommu_unit->dev_count; j++) {
if (!iommu_unit->dev[j].attached) {
- ret = iommu_attach_device(domain,
+ ret = iommu_attach_device(iommu_pt->domain,
iommu_unit->dev[j].dev);
if (ret) {
KGSL_MEM_ERR(mmu->device,
@@ -128,8 +250,8 @@
iommu_unit->dev[j].attached = true;
KGSL_MEM_INFO(mmu->device,
"iommu pt %p attached to dev %p, ctx_id %d\n",
- domain, iommu_unit->dev[j].dev,
- iommu_unit->dev[j].ctx_id);
+ iommu_pt->domain, iommu_unit->dev[j].dev,
+ iommu_unit->dev[j].ctx_id);
}
}
}
@@ -225,19 +347,121 @@
return ret;
}
+/*
+ * kgsl_set_register_map - Map the IOMMU regsiters in the memory descriptors
+ * of the respective iommu units
+ * @mmu - Pointer to mmu structure
+ *
+ * Return - 0 on success else error code
+ */
+static int kgsl_set_register_map(struct kgsl_mmu *mmu)
+{
+ struct platform_device *pdev =
+ container_of(mmu->device->parentdev, struct platform_device,
+ dev);
+ struct kgsl_device_platform_data *pdata_dev = pdev->dev.platform_data;
+ struct kgsl_iommu *iommu = mmu->device->mmu.priv;
+ struct kgsl_iommu_unit *iommu_unit;
+ int i = 0, ret = 0;
+
+ for (; i < pdata_dev->iommu_count; i++) {
+ struct kgsl_device_iommu_data data = pdata_dev->iommu_data[i];
+ iommu_unit = &iommu->iommu_units[i];
+ /* set up the IOMMU register map for the given IOMMU unit */
+ if (!data.physstart || !data.physend) {
+ KGSL_CORE_ERR("The register range for IOMMU unit not"
+ " specified\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ iommu_unit->reg_map.hostptr = ioremap(data.physstart,
+ data.physend - data.physstart + 1);
+ if (!iommu_unit->reg_map.hostptr) {
+ KGSL_CORE_ERR("Failed to map SMMU register address "
+ "space from %x to %x\n", data.physstart,
+ data.physend - data.physstart + 1);
+ ret = -ENOMEM;
+ i--;
+ goto err;
+ }
+ iommu_unit->reg_map.size = data.physend - data.physstart + 1;
+ iommu_unit->reg_map.physaddr = data.physstart;
+ memdesc_sg_phys(&iommu_unit->reg_map, data.physstart,
+ iommu_unit->reg_map.size);
+ }
+ iommu->unit_count = pdata_dev->iommu_count;
+ return ret;
+err:
+ /* Unmap any mapped IOMMU regions */
+ for (; i >= 0; i--) {
+ iommu_unit = &iommu->iommu_units[i];
+ iounmap(iommu_unit->reg_map.hostptr);
+ iommu_unit->reg_map.size = 0;
+ iommu_unit->reg_map.physaddr = 0;
+ }
+ return ret;
+}
+
+/*
+ * kgsl_iommu_pt_get_base_addr - Get the address of the pagetable that the
+ * IOMMU ttbr0 register is programmed with
+ * @pt - kgsl pagetable pointer that contains the IOMMU domain pointer
+ *
+ * Return - actual pagetable address that the ttbr0 register is programmed
+ * with
+ */
+static unsigned int kgsl_iommu_pt_get_base_addr(struct kgsl_pagetable *pt)
+{
+ struct kgsl_iommu_pt *iommu_pt = pt->priv;
+ return iommu_get_pt_base_addr(iommu_pt->domain);
+}
+
+/*
+ * kgsl_iommu_get_pt_lsb - Return the lsb of the ttbr0 IOMMU register
+ * @mmu - Pointer to mmu structure
+ * @hostptr - Pointer to the IOMMU register map. This is used to match
+ * the iommu device whose lsb value is to be returned
+ * @ctx_id - The context bank whose lsb valus is to be returned
+ * Return - returns the lsb which is the last 14 bits of the ttbr0 IOMMU
+ * register. ttbr0 is the actual PTBR for of the IOMMU. The last 14 bits
+ * are only programmed once in the beginning when a domain is attached
+ * does not change.
+ */
+static int kgsl_iommu_get_pt_lsb(struct kgsl_mmu *mmu,
+ unsigned int unit_id,
+ enum kgsl_iommu_context_id ctx_id)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int i, j;
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++)
+ if (unit_id == i &&
+ ctx_id == iommu_unit->dev[j].ctx_id)
+ return iommu_unit->dev[j].pt_lsb;
+ }
+ return 0;
+}
+
static void kgsl_iommu_setstate(struct kgsl_mmu *mmu,
struct kgsl_pagetable *pagetable)
{
if (mmu->flags & KGSL_FLAGS_STARTED) {
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct kgsl_iommu_pt *iommu_pt = pagetable->priv;
/* page table not current, then setup mmu to use new
* specified page table
*/
if (mmu->hwpagetable != pagetable) {
- kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
- kgsl_detach_pagetable_iommu_domain(mmu);
+ unsigned int flags = 0;
mmu->hwpagetable = pagetable;
- if (mmu->hwpagetable)
- kgsl_attach_pagetable_iommu_domain(mmu);
+ /* force tlb flush if asid is reused */
+ if (iommu->asid_reuse &&
+ (KGSL_IOMMU_ASID_REUSE == iommu_pt->asid))
+ flags |= KGSL_MMUFLAGS_TLBFLUSH;
+ flags |= kgsl_mmu_pt_get_flags(mmu->hwpagetable,
+ mmu->device->id);
+ kgsl_setstate(mmu, KGSL_MMUFLAGS_PTUPDATE | flags);
}
}
}
@@ -258,36 +482,106 @@
sizeof(struct kgsl_iommu));
return -ENOMEM;
}
+ iommu->asids = kzalloc(BITS_TO_LONGS(KGSL_IOMMU_MAX_ASIDS) *
+ sizeof(unsigned long), GFP_KERNEL);
+ if (!iommu->asids) {
+ KGSL_CORE_ERR("kzalloc(%d) failed\n",
+ sizeof(struct kgsl_iommu));
+ status = -ENOMEM;
+ goto done;
+ }
mmu->priv = iommu;
status = kgsl_get_iommu_ctxt(mmu);
if (status)
goto done;
+ status = kgsl_set_register_map(mmu);
+ if (status)
+ goto done;
dev_info(mmu->device->dev, "|%s| MMU type set for device is IOMMU\n",
__func__);
done:
if (status) {
+ kfree(iommu->asids);
kfree(iommu);
mmu->priv = NULL;
}
return status;
}
+/*
+ * kgsl_iommu_setup_defaultpagetable - Setup the initial defualtpagetable
+ * for iommu. This function is only called once during first start, successive
+ * start do not call this funciton.
+ * @mmu - Pointer to mmu structure
+ *
+ * Create the initial defaultpagetable and setup the iommu mappings to it
+ * Return - 0 on success else error code
+ */
+static int kgsl_iommu_setup_defaultpagetable(struct kgsl_mmu *mmu)
+{
+ int status = 0;
+ int i = 0;
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct kgsl_iommu_pt *iommu_pt;
+
+ mmu->defaultpagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
+ /* Return error if the default pagetable doesn't exist */
+ if (mmu->defaultpagetable == NULL) {
+ status = -ENOMEM;
+ goto err;
+ }
+ /* Map the IOMMU regsiters to only defaultpagetable */
+ for (i = 0; i < iommu->unit_count; i++) {
+ iommu->iommu_units[i].reg_map.priv |= KGSL_MEMFLAGS_GLOBAL;
+ status = kgsl_mmu_map(mmu->defaultpagetable,
+ &(iommu->iommu_units[i].reg_map),
+ GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
+ if (status) {
+ iommu->iommu_units[i].reg_map.priv &=
+ ~KGSL_MEMFLAGS_GLOBAL;
+ goto err;
+ }
+ }
+ /*
+ * The dafault pagetable always has asid 0 assigned by the iommu driver
+ * and asid 1 is assigned to the private context.
+ */
+ iommu_pt = mmu->defaultpagetable->priv;
+ iommu_pt->asid = 0;
+ set_bit(0, iommu->asids);
+ set_bit(1, iommu->asids);
+ return status;
+err:
+ for (i--; i >= 0; i--) {
+ kgsl_mmu_unmap(mmu->defaultpagetable,
+ &(iommu->iommu_units[i].reg_map));
+ iommu->iommu_units[i].reg_map.priv &= ~KGSL_MEMFLAGS_GLOBAL;
+ }
+ if (mmu->defaultpagetable) {
+ kgsl_mmu_putpagetable(mmu->defaultpagetable);
+ mmu->defaultpagetable = NULL;
+ }
+ return status;
+}
+
static int kgsl_iommu_start(struct kgsl_mmu *mmu)
{
int status;
+ struct kgsl_iommu *iommu = mmu->priv;
+ int i, j;
if (mmu->flags & KGSL_FLAGS_STARTED)
return 0;
+ if (mmu->defaultpagetable == NULL) {
+ status = kgsl_iommu_setup_defaultpagetable(mmu);
+ if (status)
+ return -ENOMEM;
+ }
kgsl_regwrite(mmu->device, MH_MMU_CONFIG, 0x00000000);
- if (mmu->defaultpagetable == NULL)
- mmu->defaultpagetable =
- kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
- /* Return error if the default pagetable doesn't exist */
- if (mmu->defaultpagetable == NULL)
- return -ENOMEM;
+
mmu->hwpagetable = mmu->defaultpagetable;
status = kgsl_attach_pagetable_iommu_domain(mmu);
@@ -297,7 +591,42 @@
kgsl_detach_pagetable_iommu_domain(mmu);
mmu->hwpagetable = NULL;
}
+ status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER);
+ if (status) {
+ KGSL_CORE_ERR("clk enable failed\n");
+ goto done;
+ }
+ status = kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_PRIV);
+ if (status) {
+ KGSL_CORE_ERR("clk enable failed\n");
+ goto done;
+ }
+ /* Get the lsb value of pagetables set in the IOMMU ttbr0 register as
+ * that value should not change when we change pagetables, so while
+ * changing pagetables we can use this lsb value of the pagetable w/o
+ * having to read it again
+ */
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit = &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++)
+ iommu_unit->dev[j].pt_lsb = KGSL_IOMMMU_PT_LSB(
+ KGSL_IOMMU_GET_IOMMU_REG(
+ iommu_unit->reg_map.hostptr,
+ iommu_unit->dev[j].ctx_id,
+ TTBR0));
+ }
+ iommu->asid = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[0].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER,
+ CONTEXTIDR);
+ kgsl_iommu_disable_clk(mmu);
+
+done:
+ if (status) {
+ kgsl_iommu_disable_clk(mmu);
+ kgsl_detach_pagetable_iommu_domain(mmu);
+ }
return status;
}
@@ -307,8 +636,7 @@
{
int ret;
unsigned int range = memdesc->size;
- struct iommu_domain *domain = (struct iommu_domain *)
- mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
/* All GPU addresses as assigned are page aligned, but some
functions purturb the gpuaddr with an offset, so apply the
@@ -319,10 +647,10 @@
if (range == 0 || gpuaddr == 0)
return 0;
- ret = iommu_unmap_range(domain, gpuaddr, range);
+ ret = iommu_unmap_range(iommu_pt->domain, gpuaddr, range);
if (ret)
KGSL_CORE_ERR("iommu_unmap_range(%p, %x, %d) failed "
- "with err: %d\n", domain, gpuaddr,
+ "with err: %d\n", iommu_pt->domain, gpuaddr,
range, ret);
return 0;
@@ -336,20 +664,20 @@
{
int ret;
unsigned int iommu_virt_addr;
- struct iommu_domain *domain = mmu_specific_pt;
+ struct kgsl_iommu_pt *iommu_pt = mmu_specific_pt;
- BUG_ON(NULL == domain);
+ BUG_ON(NULL == iommu_pt);
iommu_virt_addr = memdesc->gpuaddr;
- ret = iommu_map_range(domain, iommu_virt_addr, memdesc->sg,
- memdesc->size, 0);
+ ret = iommu_map_range(iommu_pt->domain, iommu_virt_addr, memdesc->sg,
+ memdesc->size, (IOMMU_READ | IOMMU_WRITE));
if (ret) {
KGSL_CORE_ERR("iommu_map_range(%p, %x, %p, %d, %d) "
- "failed with err: %d\n", domain,
+ "failed with err: %d\n", iommu_pt->domain,
iommu_virt_addr, memdesc->sg, memdesc->size,
- 0, ret);
+ (IOMMU_READ | IOMMU_WRITE), ret);
return ret;
}
@@ -383,8 +711,21 @@
static int kgsl_iommu_close(struct kgsl_mmu *mmu)
{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int i;
+ for (i = 0; i < iommu->unit_count; i++) {
+ if (iommu->iommu_units[i].reg_map.gpuaddr)
+ kgsl_mmu_unmap(mmu->defaultpagetable,
+ &(iommu->iommu_units[i].reg_map));
+ if (iommu->iommu_units[i].reg_map.hostptr)
+ iounmap(iommu->iommu_units[i].reg_map.hostptr);
+ kgsl_sg_free(iommu->iommu_units[i].reg_map.sg,
+ iommu->iommu_units[i].reg_map.sglen);
+ }
if (mmu->defaultpagetable)
kgsl_mmu_putpagetable(mmu->defaultpagetable);
+ kfree(iommu->asids);
+ kfree(iommu);
return 0;
}
@@ -392,11 +733,127 @@
static unsigned int
kgsl_iommu_get_current_ptbase(struct kgsl_mmu *mmu)
{
- /* Current base is always the hwpagetables domain as we
- * do not use per process pagetables right not for iommu.
- * This will change when we switch to per process pagetables.
+ unsigned int pt_base;
+ struct kgsl_iommu *iommu = mmu->priv;
+ /* 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 +
+ (KGSL_IOMMU_CONTEXT_USER << KGSL_IOMMU_CTX_SHIFT) +
+ KGSL_IOMMU_TTBR0);
+ kgsl_iommu_disable_clk(mmu);
+ return pt_base & (KGSL_IOMMU_TTBR0_PA_MASK <<
+ KGSL_IOMMU_TTBR0_PA_SHIFT);
+}
+
+/*
+ * kgsl_iommu_get_hwpagetable_asid - Returns asid(application space ID) for a
+ * pagetable
+ * @mmu - Pointer to mmu structure
+ *
+ * Allocates an asid to a IOMMU domain if it does not already have one. asid's
+ * are unique identifiers for pagetable that can be used to selectively flush
+ * tlb entries of the IOMMU unit.
+ * Return - asid to be used with the IOMMU domain
+ */
+static int kgsl_iommu_get_hwpagetable_asid(struct kgsl_mmu *mmu)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ struct kgsl_iommu_pt *iommu_pt = mmu->hwpagetable->priv;
+
+ /*
+ * If the iommu pagetable does not have any asid assigned and is not the
+ * default pagetable then assign asid.
*/
- return (unsigned int)mmu->hwpagetable->priv;
+ if (!iommu_pt->asid && iommu_pt != mmu->defaultpagetable->priv) {
+ iommu_pt->asid = find_first_zero_bit(iommu->asids,
+ KGSL_IOMMU_MAX_ASIDS);
+ /* No free bits means reuse asid */
+ if (iommu_pt->asid >= KGSL_IOMMU_MAX_ASIDS) {
+ iommu_pt->asid = KGSL_IOMMU_ASID_REUSE;
+ iommu->asid_reuse++;
+ }
+ set_bit(iommu_pt->asid, iommu->asids);
+ /*
+ * Store pointer to asids list so that during pagetable destroy
+ * the asid assigned to this pagetable may be cleared
+ */
+ iommu_pt->iommu = iommu;
+ }
+ /* Return the asid + the constant part of asid that never changes */
+ return (iommu_pt->asid & (KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
+ KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT)) +
+ (iommu->asid & ~(KGSL_IOMMU_CONTEXTIDR_ASID_MASK <<
+ KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT));
+}
+
+/*
+ * kgsl_iommu_default_setstate - Change the IOMMU pagetable or flush IOMMU tlb
+ * of the primary context bank
+ * @mmu - Pointer to mmu structure
+ * @flags - Flags indicating whether pagetable has to chnage or tlb is to be
+ * flushed or both
+ *
+ * Based on flags set the new pagetable fo the IOMMU unit or flush it's tlb or
+ * do both by doing direct register writes to the IOMMu registers through the
+ * cpu
+ * Return - void
+ */
+static void kgsl_iommu_default_setstate(struct kgsl_mmu *mmu,
+ uint32_t flags)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
+ int temp;
+ int i;
+ unsigned int pt_base = kgsl_iommu_pt_get_base_addr(
+ mmu->hwpagetable);
+ unsigned int pt_val;
+
+ if (kgsl_iommu_enable_clk(mmu, KGSL_IOMMU_CONTEXT_USER)) {
+ KGSL_DRV_ERR(mmu->device, "Failed to enable iommu clocks\n");
+ return;
+ }
+ /* Mask off the lsb of the pt base address since lsb will not change */
+ pt_base &= (KGSL_IOMMU_TTBR0_PA_MASK << KGSL_IOMMU_TTBR0_PA_SHIFT);
+ if (flags & KGSL_MMUFLAGS_PTUPDATE) {
+ kgsl_idle(mmu->device, KGSL_TIMEOUT_DEFAULT);
+ for (i = 0; i < iommu->unit_count; i++) {
+ /* get the lsb value which should not change when
+ * changing ttbr0 */
+ pt_val = kgsl_iommu_get_pt_lsb(mmu, i,
+ KGSL_IOMMU_CONTEXT_USER);
+ pt_val += pt_base;
+
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, TTBR0, pt_val);
+
+ mb();
+ temp = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, TTBR0);
+ /* Set asid */
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR,
+ kgsl_iommu_get_hwpagetable_asid(mmu));
+ mb();
+ temp = KGSL_IOMMU_GET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CONTEXTIDR);
+ }
+ }
+ /* Flush tlb */
+ if (flags & KGSL_MMUFLAGS_TLBFLUSH) {
+ for (i = 0; i < iommu->unit_count; i++) {
+ KGSL_IOMMU_SET_IOMMU_REG(
+ iommu->iommu_units[i].reg_map.hostptr,
+ KGSL_IOMMU_CONTEXT_USER, CTX_TLBIASID,
+ kgsl_iommu_get_hwpagetable_asid(mmu));
+ mb();
+ }
+ }
+ /* Disable smmu clock */
+ kgsl_iommu_disable_clk(mmu);
}
struct kgsl_mmu_ops iommu_ops = {
@@ -405,9 +862,12 @@
.mmu_start = kgsl_iommu_start,
.mmu_stop = kgsl_iommu_stop,
.mmu_setstate = kgsl_iommu_setstate,
- .mmu_device_setstate = NULL,
+ .mmu_device_setstate = kgsl_iommu_default_setstate,
.mmu_pagefault = NULL,
.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
+ .mmu_enable_clk = kgsl_iommu_enable_clk,
+ .mmu_disable_clk = kgsl_iommu_disable_clk,
+ .mmu_get_hwpagetable_asid = kgsl_iommu_get_hwpagetable_asid,
};
struct kgsl_mmu_pt_ops iommu_pt_ops = {
diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h
index e2033c5..c2e84a6 100644
--- a/drivers/gpu/msm/kgsl_iommu.h
+++ b/drivers/gpu/msm/kgsl_iommu.h
@@ -15,6 +15,21 @@
#include <mach/iommu.h>
+/* IOMMU registers and masks */
+#define KGSL_IOMMU_TTBR0 0x10
+#define KGSL_IOMMU_TTBR1 0x14
+#define KGSL_IOMMU_TTBR0_PA_MASK 0x0003FFFF
+#define KGSL_IOMMU_TTBR0_PA_SHIFT 14
+#define KGSL_IOMMU_CTX_TLBIALL 0x800
+#define KGSL_IOMMU_CONTEXTIDR 0x8
+#define KGSL_IOMMU_CONTEXTIDR_ASID_MASK 0xFF
+#define KGSL_IOMMU_CONTEXTIDR_ASID_SHIFT 0
+#define KGSL_IOMMU_CTX_TLBIASID 0x804
+#define KGSL_IOMMU_CTX_SHIFT 12
+
+#define KGSL_IOMMU_MAX_ASIDS 256
+#define KGSL_IOMMU_ASID_REUSE 2
+
/*
* Max number of iommu units that the gpu core can have
* On APQ8064, KGSL can control a maximum of 2 IOMMU units.
@@ -24,6 +39,22 @@
/* Max number of iommu contexts per IOMMU unit */
#define KGSL_IOMMU_MAX_DEVS_PER_UNIT 2
+/* Macros to read/write IOMMU registers */
+#define KGSL_IOMMU_SET_IOMMU_REG(base_addr, ctx, REG, val) \
+ writel_relaxed(val, base_addr + \
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ KGSL_IOMMU_##REG)
+
+#define KGSL_IOMMU_GET_IOMMU_REG(base_addr, ctx, REG) \
+ readl_relaxed(base_addr + \
+ (ctx << KGSL_IOMMU_CTX_SHIFT) + \
+ KGSL_IOMMU_##REG)
+
+/* Gets the lsb value of pagetable */
+#define KGSL_IOMMMU_PT_LSB(pt_val) \
+ (pt_val & ~(KGSL_IOMMU_TTBR0_PA_MASK << \
+ KGSL_IOMMU_TTBR0_PA_SHIFT))
+
/*
* struct kgsl_iommu_device - Structure holding data about iommu contexts
* @dev: Device pointer to iommu context
@@ -70,6 +101,7 @@
* @asids: A bit structure indicating which id's are presently used
* @asid: Contains the initial value of IOMMU_CONTEXTIDR when a domain
* is first attached
+ * asid_reuse: Holds the number of times the reuse asid is reused
*/
struct kgsl_iommu {
struct kgsl_iommu_unit iommu_units[KGSL_IOMMU_MAX_UNITS];
@@ -78,7 +110,19 @@
struct kgsl_device *device;
unsigned long *asids;
unsigned int asid;
- unsigned int active_ctx;
+ unsigned int asid_reuse;
+};
+
+/*
+ * struct kgsl_iommu_pt - Iommu pagetable structure private to kgsl driver
+ * @domain: Pointer to the iommu domain that contains the iommu pagetable
+ * @iommu: Pointer to iommu structure
+ * @asid: The asid assigned to this domain
+ */
+struct kgsl_iommu_pt {
+ struct iommu_domain *domain;
+ struct kgsl_iommu *iommu;
+ unsigned int asid;
};
#endif
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index e11b119..606d861 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -343,26 +343,30 @@
int kgsl_mmu_init(struct kgsl_device *device)
{
+ int status = 0;
struct kgsl_mmu *mmu = &device->mmu;
mmu->device = device;
+ status = kgsl_allocate_contiguous(&mmu->setstate_memory, PAGE_SIZE);
+ if (status)
+ return status;
+ kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
+ mmu->setstate_memory.size);
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type) {
- int status = 0;
- status = kgsl_allocate_contiguous(&mmu->setstate_memory, 64);
- if (!status) {
- kgsl_sharedmem_set(&mmu->setstate_memory, 0, 0,
- mmu->setstate_memory.size);
- dev_info(device->dev, "|%s| MMU type set for device is "
+ dev_info(device->dev, "|%s| MMU type set for device is "
"NOMMU\n", __func__);
- }
- return status;
+ goto done;
} else if (KGSL_MMU_TYPE_GPU == kgsl_mmu_type)
mmu->mmu_ops = &gpummu_ops;
else if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
mmu->mmu_ops = &iommu_ops;
- return mmu->mmu_ops->mmu_init(mmu);
+ status = mmu->mmu_ops->mmu_init(mmu);
+done:
+ if (status)
+ kgsl_sharedmem_free(&mmu->setstate_memory);
+ return status;
}
EXPORT_SYMBOL(kgsl_mmu_init);
@@ -382,18 +386,35 @@
}
EXPORT_SYMBOL(kgsl_mmu_start);
+static void mh_axi_error(struct kgsl_device *device, const char* type)
+{
+ unsigned int reg, gpu_err, phys_err, pt_base;
+
+ kgsl_regread(device, MH_AXI_ERROR, ®);
+ pt_base = kgsl_mmu_get_current_ptbase(&device->mmu);
+ /*
+ * Read gpu virtual and physical addresses that
+ * caused the error from the debug data.
+ */
+ kgsl_regwrite(device, MH_DEBUG_CTRL, 44);
+ kgsl_regread(device, MH_DEBUG_DATA, &gpu_err);
+ kgsl_regwrite(device, MH_DEBUG_CTRL, 45);
+ kgsl_regread(device, MH_DEBUG_DATA, &phys_err);
+ KGSL_MEM_CRIT(device,
+ "axi %s error: %08x pt %08x gpu %08x phys %08x\n",
+ type, reg, pt_base, gpu_err, phys_err);
+}
+
void kgsl_mh_intrcallback(struct kgsl_device *device)
{
unsigned int status = 0;
- unsigned int reg;
kgsl_regread(device, MH_INTERRUPT_STATUS, &status);
- kgsl_regread(device, MH_AXI_ERROR, ®);
if (status & MH_INTERRUPT_MASK__AXI_READ_ERROR)
- KGSL_MEM_CRIT(device, "axi read error interrupt: %08x\n", reg);
+ mh_axi_error(device, "read");
if (status & MH_INTERRUPT_MASK__AXI_WRITE_ERROR)
- KGSL_MEM_CRIT(device, "axi write error interrupt: %08x\n", reg);
+ mh_axi_error(device, "write");
if (status & MH_INTERRUPT_MASK__MMU_PAGE_FAULT)
device->mmu.mmu_ops->mmu_pagefault(&device->mmu);
@@ -500,11 +521,8 @@
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return (void *)(-1);
-#ifdef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
- if (KGSL_MMU_TYPE_IOMMU == kgsl_mmu_type)
- name = KGSL_MMU_GLOBAL_PT;
-#else
- name = KGSL_MMU_GLOBAL_PT;
+#ifndef CONFIG_KGSL_PER_PROCESS_PAGE_TABLE
+ name = KGSL_MMU_GLOBAL_PT;
#endif
pt = kgsl_get_pagetable(name);
@@ -525,7 +543,8 @@
struct kgsl_device *device = mmu->device;
if (KGSL_MMU_TYPE_NONE == kgsl_mmu_type)
return;
- else if (device->ftbl->setstate)
+ else if (device->ftbl->setstate && (KGSL_MMU_TYPE_IOMMU !=
+ kgsl_mmu_type))
device->ftbl->setstate(device, flags);
else if (mmu->mmu_ops->mmu_device_setstate)
mmu->mmu_ops->mmu_device_setstate(mmu, flags);
@@ -717,12 +736,11 @@
{
struct kgsl_mmu *mmu = &device->mmu;
- if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE) {
- kgsl_sharedmem_free(&mmu->setstate_memory);
+ kgsl_sharedmem_free(&mmu->setstate_memory);
+ if (kgsl_mmu_type == KGSL_MMU_TYPE_NONE)
return 0;
- } else {
+ else
return mmu->mmu_ops->mmu_close(mmu);
- }
}
EXPORT_SYMBOL(kgsl_mmu_close);
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index b476add..24eaba4 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -130,6 +130,11 @@
void (*mmu_pagefault) (struct kgsl_mmu *mmu);
unsigned int (*mmu_get_current_ptbase)
(struct kgsl_mmu *mmu);
+ void (*mmu_disable_clk)
+ (struct kgsl_mmu *mmu);
+ int (*mmu_enable_clk)
+ (struct kgsl_mmu *mmu, int ctx_id);
+ int (*mmu_get_hwpagetable_asid)(struct kgsl_mmu *mmu);
};
struct kgsl_mmu_pt_ops {
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 6fa7da2..3a29d71 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -11,6 +11,7 @@
*
*/
#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
#include <mach/msm_iomap.h>
#include <mach/msm_bus.h>
@@ -403,7 +404,7 @@
trace_kgsl_bus(device, state);
if (pwr->ebi1_clk) {
clk_set_rate(pwr->ebi1_clk, 0);
- clk_disable(pwr->ebi1_clk);
+ clk_disable_unprepare(pwr->ebi1_clk);
}
if (pwr->pcl)
msm_bus_scale_client_update_request(pwr->pcl,
@@ -414,7 +415,7 @@
&pwr->power_flags)) {
trace_kgsl_bus(device, state);
if (pwr->ebi1_clk) {
- clk_enable(pwr->ebi1_clk);
+ clk_prepare_enable(pwr->ebi1_clk);
clk_set_rate(pwr->ebi1_clk,
pwr->pwrlevels[pwr->active_pwrlevel].
bus_freq);
@@ -522,7 +523,7 @@
clk_set_rate(pwr->grp_clks[0], pwr->
pwrlevels[pwr->num_pwrlevels - 1].gpu_freq);
- pwr->gpu_reg = regulator_get(NULL, pwr->regulator_name);
+ pwr->gpu_reg = regulator_get(&pdev->dev, "vdd");
if (IS_ERR(pwr->gpu_reg))
pwr->gpu_reg = NULL;
@@ -552,17 +553,8 @@
}
}
- /*acquire interrupt */
- pwr->interrupt_num =
- platform_get_irq_byname(pdev, pwr->irq_name);
- if (pwr->interrupt_num <= 0) {
- KGSL_PWR_ERR(device, "platform_get_irq_byname failed: %d\n",
- pwr->interrupt_num);
- result = -EINVAL;
- goto done;
- }
-
+ pm_runtime_enable(device->parentdev);
register_early_suspend(&device->display_off);
return result;
@@ -582,16 +574,9 @@
KGSL_PWR_INFO(device, "close device %d\n", device->id);
+ pm_runtime_disable(device->parentdev);
unregister_early_suspend(&device->display_off);
- if (pwr->interrupt_num > 0) {
- if (pwr->have_irq) {
- free_irq(pwr->interrupt_num, NULL);
- pwr->have_irq = 0;
- }
- pwr->interrupt_num = 0;
- }
-
clk_put(pwr->ebi1_clk);
if (pwr->pcl)
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index a677fec..1e5c21c 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.h
@@ -39,7 +39,6 @@
struct kgsl_pwrctrl {
int interrupt_num;
- int have_irq;
struct clk *ebi1_clk;
struct clk *grp_clks[KGSL_MAX_CLKS];
unsigned long power_flags;
@@ -54,7 +53,6 @@
uint32_t pcl;
unsigned int nap_allowed;
unsigned int idle_needed;
- const char *regulator_name;
const char *irq_name;
s64 time;
struct kgsl_busy busy;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
index e0825c3..4daff5f 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_trustzone.c
@@ -180,7 +180,8 @@
struct tz_priv *priv;
/* Trustzone is only valid for some SOCs */
- if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064()))
+ if (!(cpu_is_msm8x60() || cpu_is_msm8960() || cpu_is_apq8064() ||
+ cpu_is_msm8930()))
return -EINVAL;
priv = pwrscale->priv = kzalloc(sizeof(struct tz_priv), GFP_KERNEL);
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index df2ca78..846a9a1 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -132,10 +132,9 @@
static struct z180_device device_2d0 = {
.dev = {
+ KGSL_DEVICE_COMMON_INIT(device_2d0.dev),
.name = DEVICE_2D0_NAME,
.id = KGSL_DEVICE_2D0,
- .ver_major = DRIVER_VERSION_MAJOR,
- .ver_minor = DRIVER_VERSION_MINOR,
.mh = {
.mharb = Z180_CFG_MHARB,
.mh_intf_cfg1 = 0x00032f07,
@@ -150,23 +149,19 @@
.config = Z180_MMU_CONFIG,
},
.pwrctrl = {
- .regulator_name = "fs_gfx2d0",
.irq_name = KGSL_2D0_IRQ,
},
- .mutex = __MUTEX_INITIALIZER(device_2d0.dev.mutex),
- .state = KGSL_STATE_INIT,
- .active_cnt = 0,
.iomemname = KGSL_2D0_REG_MEMORY,
.ftbl = &z180_functable,
},
+ .cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
};
static struct z180_device device_2d1 = {
.dev = {
+ KGSL_DEVICE_COMMON_INIT(device_2d1.dev),
.name = DEVICE_2D1_NAME,
.id = KGSL_DEVICE_2D1,
- .ver_major = DRIVER_VERSION_MAJOR,
- .ver_minor = DRIVER_VERSION_MINOR,
.mh = {
.mharb = Z180_CFG_MHARB,
.mh_intf_cfg1 = 0x00032f07,
@@ -181,15 +176,12 @@
.config = Z180_MMU_CONFIG,
},
.pwrctrl = {
- .regulator_name = "fs_gfx2d1",
.irq_name = KGSL_2D1_IRQ,
},
- .mutex = __MUTEX_INITIALIZER(device_2d1.dev.mutex),
- .state = KGSL_STATE_INIT,
- .active_cnt = 0,
.iomemname = KGSL_2D1_REG_MEMORY,
.ftbl = &z180_functable,
},
+ .cmdwin_lock = __SPIN_LOCK_INITIALIZER(device_2d1.cmdwin_lock),
};
static irqreturn_t z180_irq_handler(struct kgsl_device *device)
@@ -526,7 +518,6 @@
device->parentdev = &pdev->dev;
z180_dev = Z180_DEVICE(device);
- spin_lock_init(&z180_dev->cmdwin_lock);
status = z180_ringbuffer_init(device);
if (status != 0)
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index ee214c3..f41a4ef 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -84,4 +84,8 @@
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
+comment "Qualcomm MPQ adapter"
+ depends on ARCH_MSM && DVB_CORE
+source "drivers/media/dvb/mpq/Kconfig"
+
endif # DVB_CAPTURE_DRIVERS
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index a1a0875..68877c8 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -18,3 +18,5 @@
ngene/
obj-$(CONFIG_DVB_FIREDTV) += firewire/
+obj-$(CONFIG_DVB_MPQ) += mpq/
+
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index eb91fd8..ff0c9d8 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -7,6 +7,8 @@
* Copyright (c) 2000 Nokia Research Center
* Tampere, FINLAND
*
+ * 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
@@ -190,6 +192,14 @@
struct dmx_section_filter * source,
enum dmx_success success);
+typedef int (*dmx_ts_fullness) (
+ struct dmx_ts_feed *source,
+ int required_space);
+
+typedef int (*dmx_section_fullness) (
+ struct dmx_section_filter *source,
+ int required_space);
+
/*--------------------------------------------------------------------------*/
/* DVB Front-End */
/*--------------------------------------------------------------------------*/
@@ -247,7 +257,7 @@
void* priv; /* Pointer to private data of the API client */
int (*open) (struct dmx_demux* demux);
int (*close) (struct dmx_demux* demux);
- int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
+ int (*write) (struct dmx_demux *demux, const char *buf, size_t count);
int (*allocate_ts_feed) (struct dmx_demux* demux,
struct dmx_ts_feed** feed,
dmx_ts_cb callback);
@@ -271,7 +281,20 @@
int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
- int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
+ int (*set_source) (struct dmx_demux *demux, const dmx_source_t *src);
+
+ int (*set_tsp_format) (struct dmx_demux *demux,
+ enum dmx_tsp_format_t tsp_format);
+
+ int (*set_tsp_out_format) (struct dmx_demux *demux,
+ enum dmx_tsp_format_t tsp_format);
+
+ int (*set_playback_mode) (struct dmx_demux *demux,
+ enum dmx_playback_mode_t mode,
+ dmx_ts_fullness ts_fullness_callback,
+ dmx_section_fullness sec_fullness_callback);
+
+ int (*write_cancel) (struct dmx_demux *demux);
int (*get_stc) (struct dmx_demux* demux, unsigned int num,
u64 *stc, unsigned int *base);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index e4b5c03..ed3f731 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -4,6 +4,8 @@
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
+ * 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
@@ -28,6 +30,7 @@
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
+#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include "dmxdev.h"
@@ -81,12 +84,15 @@
break;
}
- ret = wait_event_interruptible(src->queue,
- !dvb_ringbuffer_empty(src) ||
- (src->error != 0));
+ ret = wait_event_interruptible(src->queue, (!src->data) ||
+ !dvb_ringbuffer_empty(src) ||
+ (src->error != 0));
if (ret < 0)
break;
+ if (!src->data)
+ return 0;
+
if (src->error) {
ret = src->error;
dvb_ringbuffer_flush(src);
@@ -104,6 +110,9 @@
buf += ret;
}
+ if (count - todo) /* some data was read? */
+ wake_up_all(&src->queue);
+
return (count - todo) ? (count - todo) : ret;
}
@@ -126,8 +135,11 @@
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front;
+ void *mem;
- dprintk("function : %s\n", __func__);
+ dprintk("function : %s(%X)\n",
+ __func__,
+ (file->f_flags & O_ACCMODE));
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
@@ -145,21 +157,20 @@
}
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- void *mem;
if (!dvbdev->readers) {
mutex_unlock(&dmxdev->mutex);
return -EBUSY;
}
- mem = vmalloc(DVR_BUFFER_SIZE);
+ mem = vmalloc_user(DVR_BUFFER_SIZE);
if (!mem) {
mutex_unlock(&dmxdev->mutex);
return -ENOMEM;
}
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
dvbdev->readers--;
- }
-
- if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+ } else if (!dvbdev->writers) {
+ dmxdev->dvr_in_exit = 0;
+ dmxdev->dvr_processing_input = 0;
dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
if (!dmxdev->demux->write) {
@@ -173,9 +184,22 @@
mutex_unlock(&dmxdev->mutex);
return -EINVAL;
}
+
+ mem = vmalloc_user(DVR_BUFFER_SIZE);
+ if (!mem) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENOMEM;
+ }
+
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, front);
+
+ dvb_ringbuffer_init(&dmxdev->dvr_input_buffer,
+ mem,
+ DVR_BUFFER_SIZE);
+ dvbdev->writers--;
}
+
dvbdev->users++;
mutex_unlock(&dmxdev->mutex);
return 0;
@@ -188,11 +212,6 @@
mutex_lock(&dmxdev->mutex);
- if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
- dmxdev->demux->disconnect_frontend(dmxdev->demux);
- dmxdev->demux->connect_frontend(dmxdev->demux,
- dmxdev->dvr_orig_fe);
- }
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
dvbdev->readers++;
if (dmxdev->dvr_buffer.data) {
@@ -201,6 +220,51 @@
spin_lock_irq(&dmxdev->lock);
dmxdev->dvr_buffer.data = NULL;
spin_unlock_irq(&dmxdev->lock);
+ wake_up_all(&dmxdev->dvr_buffer.queue);
+ vfree(mem);
+ }
+ } else {
+ int i;
+
+ dmxdev->dvr_in_exit = 1;
+ wake_up_all(&dmxdev->dvr_input_buffer.queue);
+
+ /*
+ * There might be dmx filters reading now from DVR
+ * device, in PULL mode, they might be also stalled
+ * on output, signal to them that DVR is exiting.
+ */
+ if (dmxdev->playback_mode == DMX_PB_MODE_PULL) {
+ wake_up_all(&dmxdev->dvr_buffer.queue);
+
+ for (i = 0; i < dmxdev->filternum; i++)
+ if (dmxdev->filter[i].state == DMXDEV_STATE_GO)
+ wake_up_all(
+ &dmxdev->filter[i].buffer.queue);
+ }
+
+ /* notify kernel demux that we are canceling */
+ if (dmxdev->demux->write_cancel)
+ dmxdev->demux->write_cancel(dmxdev->demux);
+
+ /*
+ * Now flush dvr-in workqueue so that no one
+ * would process data from dvr input buffer any more
+ * before it gets freed.
+ */
+ flush_workqueue(dmxdev->dvr_input_workqueue);
+
+ dvbdev->writers++;
+ dmxdev->demux->disconnect_frontend(dmxdev->demux);
+ dmxdev->demux->connect_frontend(dmxdev->demux,
+ dmxdev->dvr_orig_fe);
+
+ if (dmxdev->dvr_input_buffer.data) {
+ void *mem = dmxdev->dvr_input_buffer.data;
+ mb();
+ spin_lock_irq(&dmxdev->dvr_in_lock);
+ dmxdev->dvr_input_buffer.data = NULL;
+ spin_unlock_irq(&dmxdev->dvr_in_lock);
vfree(mem);
}
}
@@ -217,17 +281,20 @@
return 0;
}
-static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+
+static int dvb_dvr_mmap(struct file *filp, struct vm_area_struct *vma)
{
- struct dvb_device *dvbdev = file->private_data;
+ struct dvb_device *dvbdev = filp->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
+ struct dvb_ringbuffer *buffer;
+ int vma_size;
+ int buffer_size;
int ret;
- if (!dmxdev->demux->write)
- return -EOPNOTSUPP;
- if ((file->f_flags & O_ACCMODE) != O_WRONLY)
+ if (((filp->f_flags & O_ACCMODE) == O_RDONLY) &&
+ (vma->vm_flags & VM_WRITE))
return -EINVAL;
+
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
@@ -235,11 +302,114 @@
mutex_unlock(&dmxdev->mutex);
return -ENODEV;
}
- ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+
+ if ((filp->f_flags & O_ACCMODE) == O_RDONLY)
+ buffer = &dmxdev->dvr_buffer;
+ else
+ buffer = &dmxdev->dvr_input_buffer;
+
+ vma_size = vma->vm_end - vma->vm_start;
+
+ /* Make sure requested mapping is not larger than buffer size */
+ buffer_size = buffer->size + (PAGE_SIZE-1);
+ buffer_size = buffer_size & ~(PAGE_SIZE-1);
+
+ if (vma_size != buffer_size) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EINVAL;
+ }
+
+ ret = remap_vmalloc_range(vma, buffer->data, 0);
+ if (ret) {
+ mutex_unlock(&dmxdev->mutex);
+ return ret;
+ }
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_flags |= VM_DONTEXPAND;
+
mutex_unlock(&dmxdev->mutex);
return ret;
}
+static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dvb_device *dvbdev = file->private_data;
+ struct dmxdev *dmxdev = dvbdev->priv;
+ struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
+ int ret;
+ size_t todo;
+ ssize_t free_space;
+
+ if (!dmxdev->demux->write)
+ return -EOPNOTSUPP;
+
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return -EINVAL;
+
+ if ((file->f_flags & O_NONBLOCK) &&
+ (dvb_ringbuffer_free(src) == 0))
+ return -EWOULDBLOCK;
+
+ ret = 0;
+ for (todo = count; todo > 0; todo -= ret) {
+ ret = wait_event_interruptible(src->queue,
+ (!src->data) ||
+ (dvb_ringbuffer_free(src)) ||
+ (src->error != 0) ||
+ (dmxdev->dvr_in_exit));
+
+ if (ret < 0)
+ return ret;
+
+ if (mutex_lock_interruptible(&dmxdev->mutex))
+ return -ERESTARTSYS;
+
+ if (!src->data) {
+ mutex_unlock(&dmxdev->mutex);
+ return 0;
+ }
+
+ if (dmxdev->exit || dmxdev->dvr_in_exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
+ if (src->error) {
+ ret = src->error;
+ dvb_ringbuffer_flush(src);
+ mutex_unlock(&dmxdev->mutex);
+ wake_up_all(&src->queue);
+ return ret;
+ }
+
+ free_space = dvb_ringbuffer_free(src);
+
+ if (free_space > todo)
+ free_space = todo;
+
+ ret = dvb_ringbuffer_write_user(src, buf, free_space);
+
+ if (ret < 0) {
+ mutex_unlock(&dmxdev->mutex);
+ return ret;
+ }
+
+ buf += ret;
+
+ mutex_unlock(&dmxdev->mutex);
+
+ wake_up_all(&src->queue);
+
+ if (!work_pending(&dmxdev->dvr_input_work))
+ queue_work(dmxdev->dvr_input_workqueue,
+ &dmxdev->dvr_input_work);
+ }
+
+ return (count - todo) ? (count - todo) : ret;
+}
+
static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
@@ -254,39 +424,223 @@
buf, count, ppos);
}
-static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
- unsigned long size)
+static void dvr_input_work_func(struct work_struct *worker)
{
- struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+ struct dmxdev *dmxdev =
+ container_of(worker, struct dmxdev, dvr_input_work);
+ struct dvb_ringbuffer *src = &dmxdev->dvr_input_buffer;
+ int ret;
+ size_t todo;
+ size_t split;
+
+ while (1) {
+ /* wait for input */
+ ret = wait_event_interruptible(src->queue,
+ (!src->data) ||
+ (dvb_ringbuffer_avail(src)) ||
+ (src->error != 0) ||
+ (dmxdev->dvr_in_exit));
+
+ if (ret < 0)
+ break;
+
+ spin_lock(&dmxdev->dvr_in_lock);
+
+ if (!src->data || dmxdev->exit || dmxdev->dvr_in_exit) {
+ spin_unlock(&dmxdev->dvr_in_lock);
+ break;
+ }
+
+ if (src->error) {
+ spin_unlock(&dmxdev->dvr_in_lock);
+ wake_up_all(&src->queue);
+ break;
+ }
+
+ dmxdev->dvr_processing_input = 1;
+
+ ret = dvb_ringbuffer_avail(src);
+ todo = ret;
+
+ split = (src->pread + ret > src->size) ?
+ src->size - src->pread :
+ 0;
+
+ /*
+ * In DVR PULL mode, write might block.
+ * Lock on DVR buffer is released before calling to
+ * write, if DVR was released meanwhile, dvr_in_exit is
+ * prompted. Lock is aquired when updating the read pointer
+ * again to preserve read/write pointers consistancy
+ */
+ if (split > 0) {
+ spin_unlock(&dmxdev->dvr_in_lock);
+ dmxdev->demux->write(dmxdev->demux,
+ src->data + src->pread,
+ split);
+
+ if (dmxdev->dvr_in_exit)
+ break;
+
+ spin_lock(&dmxdev->dvr_in_lock);
+
+ todo -= split;
+ DVB_RINGBUFFER_SKIP(src, split);
+ }
+
+ spin_unlock(&dmxdev->dvr_in_lock);
+ dmxdev->demux->write(dmxdev->demux,
+ src->data + src->pread, todo);
+
+ if (dmxdev->dvr_in_exit)
+ break;
+
+ spin_lock(&dmxdev->dvr_in_lock);
+
+ DVB_RINGBUFFER_SKIP(src, todo);
+ dmxdev->dvr_processing_input = 0;
+ spin_unlock(&dmxdev->dvr_in_lock);
+
+ wake_up_all(&src->queue);
+ }
+}
+
+static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
+ unsigned int f_flags,
+ unsigned long size)
+{
+ struct dvb_ringbuffer *buf;
void *newmem;
void *oldmem;
+ spinlock_t *lock;
dprintk("function : %s\n", __func__);
+ if ((f_flags & O_ACCMODE) == O_RDONLY) {
+ buf = &dmxdev->dvr_buffer;
+ lock = &dmxdev->lock;
+ } else {
+ buf = &dmxdev->dvr_input_buffer;
+ lock = &dmxdev->dvr_in_lock;
+ }
+
if (buf->size == size)
return 0;
if (!size)
return -EINVAL;
- newmem = vmalloc(size);
+ newmem = vmalloc_user(size);
if (!newmem)
return -ENOMEM;
oldmem = buf->data;
- spin_lock_irq(&dmxdev->lock);
+ spin_lock_irq(lock);
+
+ if (((f_flags & O_ACCMODE) != O_RDONLY) &&
+ (dmxdev->dvr_processing_input)) {
+ spin_unlock_irq(lock);
+ vfree(oldmem);
+ return -EBUSY;
+ }
+
buf->data = newmem;
buf->size = size;
/* reset and not flush in case the buffer shrinks */
dvb_ringbuffer_reset(buf);
- spin_unlock_irq(&dmxdev->lock);
+
+ spin_unlock_irq(lock);
vfree(oldmem);
return 0;
}
+static int dvb_dvr_get_buffer_status(struct dmxdev *dmxdev,
+ unsigned int f_flags,
+ struct dmx_buffer_status *dmx_buffer_status)
+{
+ struct dvb_ringbuffer *buf;
+ spinlock_t *lock;
+
+ if ((f_flags & O_ACCMODE) == O_RDONLY) {
+ buf = &dmxdev->dvr_buffer;
+ lock = &dmxdev->lock;
+ } else {
+ buf = &dmxdev->dvr_input_buffer;
+ lock = &dmxdev->dvr_in_lock;
+ }
+
+ spin_lock_irq(lock);
+
+ dmx_buffer_status->error = buf->error;
+ if (buf->error)
+ dvb_ringbuffer_flush(buf);
+
+ dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
+ dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
+ dmx_buffer_status->read_offset = buf->pread;
+ dmx_buffer_status->write_offset = buf->pwrite;
+ dmx_buffer_status->size = buf->size;
+
+ spin_unlock_irq(lock);
+
+ return 0;
+}
+
+static int dvb_dvr_release_data(struct dmxdev *dmxdev,
+ unsigned int f_flags,
+ u32 bytes_count)
+{
+ ssize_t buff_fullness;
+
+ if (!(f_flags & O_ACCMODE) == O_RDONLY)
+ return -EINVAL;
+
+ if (!bytes_count)
+ return 0;
+
+ buff_fullness = dvb_ringbuffer_avail(&dmxdev->dvr_buffer);
+
+ if (bytes_count > buff_fullness)
+ return -EINVAL;
+
+ DVB_RINGBUFFER_SKIP(&dmxdev->dvr_buffer, bytes_count);
+ wake_up_all(&dmxdev->dvr_buffer.queue);
+ return 0;
+}
+
+static int dvb_dvr_feed_data(struct dmxdev *dmxdev,
+ unsigned int f_flags,
+ u32 bytes_count)
+{
+ ssize_t free_space;
+ struct dvb_ringbuffer *buffer = &dmxdev->dvr_input_buffer;
+
+ if ((f_flags & O_ACCMODE) == O_RDONLY)
+ return -EINVAL;
+
+ if (!bytes_count)
+ return 0;
+
+ free_space = dvb_ringbuffer_free(buffer);
+
+ if (bytes_count > free_space)
+ return -EINVAL;
+
+ buffer->pwrite =
+ (buffer->pwrite + bytes_count) % buffer->size;
+
+ wake_up_all(&buffer->queue);
+
+ if (!work_pending(&dmxdev->dvr_input_work))
+ queue_work(dmxdev->dvr_input_workqueue,
+ &dmxdev->dvr_input_work);
+
+ return 0;
+}
+
static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
*dmxdevfilter, int state)
{
@@ -309,7 +663,7 @@
if (dmxdevfilter->state >= DMXDEV_STATE_GO)
return -EBUSY;
- newmem = vmalloc(size);
+ newmem = vmalloc_user(size);
if (!newmem)
return -ENOMEM;
@@ -324,6 +678,212 @@
spin_unlock_irq(&dmxdevfilter->dev->lock);
vfree(oldmem);
+ return 0;
+}
+
+static int dvb_dmxdev_set_pes_buffer_size(struct dmxdev_filter *dmxdevfilter,
+ unsigned long size)
+{
+ if (dmxdevfilter->pes_buffer_size == size)
+ return 0;
+ if (!size)
+ return -EINVAL;
+ if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ dmxdevfilter->pes_buffer_size = size;
+
+ return 0;
+}
+
+static int dvb_dmxdev_set_source(struct dmxdev_filter *dmxdevfilter,
+ dmx_source_t *source)
+{
+ struct dmxdev *dev;
+
+ if (dmxdevfilter->state == DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ dev = dmxdevfilter->dev;
+
+ dev->source = *source;
+
+ if (dev->demux->set_source)
+ return dev->demux->set_source(dev->demux, source);
+
+ return 0;
+}
+
+static int dvb_dmxdev_ts_fullness_callback(
+ struct dmx_ts_feed *filter,
+ int required_space)
+{
+ struct dmxdev_filter *dmxdevfilter = filter->priv;
+ struct dvb_ringbuffer *src;
+ int ret;
+
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+ || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+ src = &dmxdevfilter->buffer;
+ else
+ src = &dmxdevfilter->dev->dvr_buffer;
+
+ do {
+ ret = 0;
+
+ if (dmxdevfilter->dev->dvr_in_exit)
+ return -ENODEV;
+
+ spin_lock(&dmxdevfilter->dev->lock);
+
+ if ((!src->data) ||
+ (dmxdevfilter->state != DMXDEV_STATE_GO))
+ ret = -EINVAL;
+ else if (src->error)
+ ret = src->error;
+
+ if (ret) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return ret;
+ }
+
+ if (required_space <= dvb_ringbuffer_free(src)) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ spin_unlock(&dmxdevfilter->dev->lock);
+
+ ret = wait_event_interruptible(src->queue,
+ (!src->data) ||
+ (dvb_ringbuffer_free(src) >= required_space) ||
+ (src->error != 0) ||
+ (dmxdevfilter->state != DMXDEV_STATE_GO) ||
+ dmxdevfilter->dev->dvr_in_exit);
+
+ if (ret < 0)
+ return ret;
+ } while (1);
+}
+
+static int dvb_dmxdev_sec_fullness_callback(
+ struct dmx_section_filter *filter,
+ int required_space)
+{
+ struct dmxdev_filter *dmxdevfilter = filter->priv;
+ struct dvb_ringbuffer *src = &dmxdevfilter->buffer;
+ int ret;
+
+ do {
+ ret = 0;
+
+ if (dmxdevfilter->dev->dvr_in_exit)
+ return -ENODEV;
+
+ spin_lock(&dmxdevfilter->dev->lock);
+
+ if ((!src->data) ||
+ (dmxdevfilter->state != DMXDEV_STATE_GO))
+ ret = -EINVAL;
+ else if (src->error)
+ ret = src->error;
+
+ if (ret) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return ret;
+ }
+
+ if (required_space <= dvb_ringbuffer_free(src)) {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+
+ spin_unlock(&dmxdevfilter->dev->lock);
+
+ ret = wait_event_interruptible(src->queue,
+ (!src->data) ||
+ (dvb_ringbuffer_free(src) >= required_space) ||
+ (src->error != 0) ||
+ (dmxdevfilter->state != DMXDEV_STATE_GO) ||
+ dmxdevfilter->dev->dvr_in_exit);
+
+ if (ret < 0)
+ return ret;
+ } while (1);
+}
+
+static int dvb_dmxdev_set_playback_mode(struct dmxdev_filter *dmxdevfilter,
+ enum dmx_playback_mode_t playback_mode)
+{
+ struct dmxdev *dmxdev = dmxdevfilter->dev;
+
+ if ((playback_mode != DMX_PB_MODE_PUSH) &&
+ (playback_mode != DMX_PB_MODE_PULL))
+ return -EINVAL;
+
+ if (((dmxdev->source < DMX_SOURCE_DVR0) ||
+ !dmxdev->demux->set_playback_mode ||
+ !(dmxdev->capabilities & DMXDEV_CAP_PULL_MODE)) &&
+ (playback_mode == DMX_PB_MODE_PULL))
+ return -EPERM;
+
+ if (dmxdevfilter->state == DMXDEV_STATE_GO)
+ return -EBUSY;
+
+ dmxdev->playback_mode = playback_mode;
+
+ return dmxdev->demux->set_playback_mode(
+ dmxdev->demux,
+ dmxdev->playback_mode,
+ dvb_dmxdev_ts_fullness_callback,
+ dvb_dmxdev_sec_fullness_callback);
+}
+
+static int dvb_dmxdev_get_buffer_status(
+ struct dmxdev_filter *dmxdevfilter,
+ struct dmx_buffer_status *dmx_buffer_status)
+{
+ struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+
+ if (!buf->data)
+ return -EINVAL;
+
+ spin_lock_irq(&dmxdevfilter->dev->lock);
+
+ dmx_buffer_status->error = buf->error;
+ if (buf->error)
+ dvb_ringbuffer_flush(buf);
+
+ dmx_buffer_status->fullness = dvb_ringbuffer_avail(buf);
+ dmx_buffer_status->free_bytes = dvb_ringbuffer_free(buf);
+ dmx_buffer_status->read_offset = buf->pread;
+ dmx_buffer_status->write_offset = buf->pwrite;
+ dmx_buffer_status->size = buf->size;
+
+ spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+ return 0;
+}
+
+static int dvb_dmxdev_release_data(struct dmxdev_filter *dmxdevfilter,
+ u32 bytes_count)
+{
+ ssize_t buff_fullness;
+
+ if (!dmxdevfilter->buffer.data)
+ return -EINVAL;
+
+ if (!bytes_count)
+ return 0;
+
+ buff_fullness = dvb_ringbuffer_avail(&dmxdevfilter->buffer);
+
+ if (bytes_count > buff_fullness)
+ return -EINVAL;
+
+ DVB_RINGBUFFER_SKIP(&dmxdevfilter->buffer, bytes_count);
+
+ wake_up_all(&dmxdevfilter->buffer.queue);
return 0;
}
@@ -336,7 +896,7 @@
spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
spin_unlock_irq(&dmxdevfilter->dev->lock);
- wake_up(&dmxdevfilter->buffer.queue);
+ wake_up_all(&dmxdevfilter->buffer.queue);
}
static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
@@ -362,7 +922,7 @@
int ret;
if (dmxdevfilter->buffer.error) {
- wake_up(&dmxdevfilter->buffer.queue);
+ wake_up_all(&dmxdevfilter->buffer.queue);
return 0;
}
spin_lock(&dmxdevfilter->dev->lock);
@@ -387,7 +947,7 @@
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
dmxdevfilter->state = DMXDEV_STATE_DONE;
spin_unlock(&dmxdevfilter->dev->lock);
- wake_up(&dmxdevfilter->buffer.queue);
+ wake_up_all(&dmxdevfilter->buffer.queue);
return 0;
}
@@ -402,18 +962,34 @@
spin_lock(&dmxdevfilter->dev->lock);
if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
- spin_unlock(&dmxdevfilter->dev->lock);
- return 0;
- }
-
- if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+ if ((dmxdevfilter->dev->capabilities &
+ DMXDEV_CAP_PCR_EXTRACTION) &&
+ ((dmxdevfilter->params.pes.pes_type == DMX_PES_PCR0) ||
+ (dmxdevfilter->params.pes.pes_type == DMX_PES_PCR1) ||
+ (dmxdevfilter->params.pes.pes_type == DMX_PES_PCR2) ||
+ (dmxdevfilter->params.pes.pes_type == DMX_PES_PCR3))) {
+ /*
+ * Support for reporting PCR and STC pairs to user.
+ * Reported data should have the following format:
+ * <8 bit flags><64 bits of STC> <64bits of PCR>
+ * STC and PCR values are in 27MHz.
+ * The current flags that are defined:
+ * 0x00000001: discontinuity_indicator
+ */
+ buffer = &dmxdevfilter->buffer;
+ } else {
+ spin_unlock(&dmxdevfilter->dev->lock);
+ return 0;
+ }
+ } else if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
buffer = &dmxdevfilter->buffer;
else
buffer = &dmxdevfilter->dev->dvr_buffer;
+
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
- wake_up(&buffer->queue);
+ wake_up_all(&buffer->queue);
return 0;
}
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
@@ -424,7 +1000,7 @@
buffer->error = ret;
}
spin_unlock(&dmxdevfilter->dev->lock);
- wake_up(&buffer->queue);
+ wake_up_all(&buffer->queue);
return 0;
}
@@ -534,6 +1110,8 @@
}
dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ wake_up_all(&dmxdevfilter->buffer.queue);
+
return 0;
}
@@ -600,7 +1178,9 @@
tsfeed = feed->ts;
tsfeed->priv = filter;
- ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+ ret = tsfeed->set(tsfeed, feed->pid,
+ ts_type, ts_pes,
+ filter->pes_buffer_size, timeout);
if (ret < 0) {
dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
return ret;
@@ -629,7 +1209,7 @@
dvb_dmxdev_filter_stop(filter);
if (!filter->buffer.data) {
- mem = vmalloc(filter->buffer.size);
+ mem = vmalloc_user(filter->buffer.size);
if (!mem)
return -ENOMEM;
spin_lock_irq(&filter->dev->lock);
@@ -649,7 +1229,6 @@
*secfilter = NULL;
*secfeed = NULL;
-
/* find active filter/feed with same PID */
for (i = 0; i < dmxdev->filternum; i++) {
if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
@@ -763,6 +1342,8 @@
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
init_timer(&dmxdevfilter->timer);
+ dmxdevfilter->pes_buffer_size = 32768;
+
dvbdev->users++;
mutex_unlock(&dmxdev->mutex);
@@ -788,7 +1369,7 @@
}
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
- wake_up(&dmxdevfilter->buffer.queue);
+ wake_up_all(&dmxdevfilter->buffer.queue);
mutex_unlock(&dmxdevfilter->mutex);
mutex_unlock(&dmxdev->mutex);
return 0;
@@ -1023,6 +1604,24 @@
mutex_unlock(&dmxdevfilter->mutex);
break;
+ case DMX_GET_BUFFER_STATUS:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_get_buffer_status(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_RELEASE_DATA:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_release_data(dmxdevfilter, arg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
case DMX_GET_PES_PIDS:
if (!dmxdev->demux->get_pes_pids) {
ret = -EINVAL;
@@ -1040,11 +1639,59 @@
break;
case DMX_SET_SOURCE:
- if (!dmxdev->demux->set_source) {
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+ ret = dvb_dmxdev_set_source(dmxdevfilter, parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_SET_TS_PACKET_FORMAT:
+ if (!dmxdev->demux->set_tsp_format) {
ret = -EINVAL;
break;
}
- ret = dmxdev->demux->set_source(dmxdev->demux, parg);
+
+ if (dmxdevfilter->state >= DMXDEV_STATE_GO) {
+ ret = -EBUSY;
+ break;
+ }
+ ret = dmxdev->demux->set_tsp_format(
+ dmxdev->demux,
+ *(enum dmx_tsp_format_t *)parg);
+ break;
+
+ case DMX_SET_TS_OUT_FORMAT:
+ if (!dmxdev->demux->set_tsp_out_format) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (dmxdevfilter->state >= DMXDEV_STATE_GO) {
+ ret = -EBUSY;
+ break;
+ }
+
+ ret = dmxdev->demux->set_tsp_out_format(
+ dmxdev->demux,
+ *(enum dmx_tsp_format_t *)parg);
+ break;
+
+ case DMX_SET_DECODER_BUFFER_SIZE:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+
+ ret = dvb_dmxdev_set_pes_buffer_size(dmxdevfilter, arg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_SET_PLAYBACK_MODE:
+ ret = dvb_dmxdev_set_playback_mode(
+ dmxdevfilter,
+ *(enum dmx_playback_mode_t *)parg);
break;
case DMX_GET_STC:
@@ -1114,6 +1761,59 @@
return mask;
}
+static int dvb_demux_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct dmxdev_filter *dmxdevfilter = filp->private_data;
+ struct dmxdev *dmxdev = dmxdevfilter->dev;
+ int ret;
+ int vma_size;
+ int buffer_size;
+
+ vma_size = vma->vm_end - vma->vm_start;
+
+ if (vma->vm_flags & VM_WRITE)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&dmxdev->mutex))
+ return -ERESTARTSYS;
+
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ERESTARTSYS;
+ }
+
+ if (!dmxdevfilter->buffer.data) {
+ mutex_unlock(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdev->mutex);
+ return -EINVAL;
+ }
+
+ /* Make sure requested mapping is not larger than buffer size */
+ buffer_size = dmxdevfilter->buffer.size + (PAGE_SIZE-1);
+ buffer_size = buffer_size & ~(PAGE_SIZE-1);
+
+ if (vma_size != buffer_size) {
+ mutex_unlock(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdev->mutex);
+ return -EINVAL;
+ }
+
+ ret = remap_vmalloc_range(vma, dmxdevfilter->buffer.data, 0);
+ if (ret) {
+ mutex_unlock(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdev->mutex);
+ return ret;
+ }
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_flags |= VM_DONTEXPAND;
+
+ mutex_unlock(&dmxdevfilter->mutex);
+ mutex_unlock(&dmxdev->mutex);
+
+ return 0;
+}
+
static int dvb_demux_release(struct inode *inode, struct file *file)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
@@ -1144,6 +1844,7 @@
.release = dvb_demux_release,
.poll = dvb_demux_poll,
.llseek = default_llseek,
+ .mmap = dvb_demux_mmap,
};
static struct dvb_device dvbdev_demux = {
@@ -1166,7 +1867,19 @@
switch (cmd) {
case DMX_SET_BUFFER_SIZE:
- ret = dvb_dvr_set_buffer_size(dmxdev, arg);
+ ret = dvb_dvr_set_buffer_size(dmxdev, file->f_flags, arg);
+ break;
+
+ case DMX_GET_BUFFER_STATUS:
+ ret = dvb_dvr_get_buffer_status(dmxdev, file->f_flags, parg);
+ break;
+
+ case DMX_RELEASE_DATA:
+ ret = dvb_dvr_release_data(dmxdev, file->f_flags, arg);
+ break;
+
+ case DMX_FEED_DATA:
+ ret = dvb_dvr_feed_data(dmxdev, file->f_flags, arg);
break;
default:
@@ -1191,16 +1904,22 @@
dprintk("function : %s\n", __func__);
- poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
-
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
+
if (dmxdev->dvr_buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI);
- } else
- mask |= (POLLOUT | POLLWRNORM | POLLPRI);
+ } else {
+ poll_wait(file, &dmxdev->dvr_input_buffer.queue, wait);
+ if (dmxdev->dvr_input_buffer.error)
+ mask |= (POLLOUT | POLLRDNORM | POLLPRI | POLLERR);
+
+ if (dvb_ringbuffer_free(&dmxdev->dvr_input_buffer))
+ mask |= (POLLOUT | POLLRDNORM | POLLPRI);
+ }
return mask;
}
@@ -1209,6 +1928,7 @@
.owner = THIS_MODULE,
.read = dvb_dvr_read,
.write = dvb_dvr_write,
+ .mmap = dvb_dvr_mmap,
.unlocked_ioctl = dvb_dvr_ioctl,
.open = dvb_dvr_open,
.release = dvb_dvr_release,
@@ -1234,8 +1954,19 @@
if (!dmxdev->filter)
return -ENOMEM;
+ dmxdev->dvr_input_workqueue =
+ create_singlethread_workqueue("dvr_workqueue");
+
+ if (dmxdev->dvr_input_workqueue == NULL) {
+ vfree(dmxdev->filter);
+ return -ENOMEM;
+ }
+
+ dmxdev->playback_mode = DMX_PB_MODE_PUSH;
+
mutex_init(&dmxdev->mutex);
spin_lock_init(&dmxdev->lock);
+ spin_lock_init(&dmxdev->dvr_in_lock);
for (i = 0; i < dmxdev->filternum; i++) {
dmxdev->filter[i].dev = dmxdev;
dmxdev->filter[i].buffer.data = NULL;
@@ -1249,6 +1980,10 @@
dmxdev, DVB_DEVICE_DVR);
dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
+ dvb_ringbuffer_init(&dmxdev->dvr_input_buffer, NULL, 8192);
+
+ INIT_WORK(&dmxdev->dvr_input_work,
+ dvr_input_work_func);
return 0;
}
@@ -1267,6 +2002,9 @@
dmxdev->dvr_dvbdev->users==1);
}
+ flush_workqueue(dmxdev->dvr_input_workqueue);
+ destroy_workqueue(dmxdev->dvr_input_workqueue);
+
dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 02ebe28..82f8f6d 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -4,6 +4,8 @@
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
+ * 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
@@ -32,7 +34,7 @@
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-
+#include <linux/workqueue.h>
#include <linux/dvb/dmx.h>
#include "dvbdev.h"
@@ -83,14 +85,18 @@
struct mutex mutex;
+ /* relevent for decoder PES */
+ unsigned long pes_buffer_size;
+
/* only for sections */
struct timer_list timer;
int todo;
u8 secheader[3];
};
-
struct dmxdev {
+ struct work_struct dvr_input_work;
+
struct dvb_device *dvbdev;
struct dvb_device *dvr_dvbdev;
@@ -99,16 +105,28 @@
int filternum;
int capabilities;
+#define DMXDEV_CAP_DUPLEX 0x1
+#define DMXDEV_CAP_PULL_MODE 0x2
+#define DMXDEV_CAP_PCR_EXTRACTION 0x4
+
+ enum dmx_playback_mode_t playback_mode;
+ dmx_source_t source;
unsigned int exit:1;
-#define DMXDEV_CAP_DUPLEX 1
+ unsigned int dvr_in_exit:1;
+ unsigned int dvr_processing_input:1;
+
struct dmx_frontend *dvr_orig_fe;
struct dvb_ringbuffer dvr_buffer;
+ struct dvb_ringbuffer dvr_input_buffer;
+ struct workqueue_struct *dvr_input_workqueue;
+
#define DVR_BUFFER_SIZE (10*188*1024)
struct mutex mutex;
spinlock_t lock;
+ spinlock_t dvr_in_lock;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index faa3671..966b48d 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -5,6 +5,8 @@
* & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH
*
+ * 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
@@ -50,6 +52,14 @@
MODULE_PARM_DESC(dvb_demux_speedcheck,
"enable transport stream speed check");
+/* counter advancing for each new dvb-demux device */
+static int dvb_demux_index;
+
+static int dvb_demux_performancecheck;
+module_param(dvb_demux_performancecheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_performancecheck,
+ "enable transport stream performance check, reported through debugfs");
+
#define dprintk_tscheck(x...) do { \
if (dvb_demux_tscheck && printk_ratelimit()) \
printk(x); \
@@ -95,6 +105,19 @@
memcpy(d, s, len);
}
+static u32 dvb_dmx_calc_time_delta(struct timespec past_time)
+{
+ struct timespec curr_time, delta_time;
+ u64 delta_time_us;
+
+ curr_time = current_kernel_time();
+ delta_time = timespec_sub(curr_time, past_time);
+ delta_time_us = ((s64)delta_time.tv_sec * USEC_PER_SEC) +
+ delta_time.tv_nsec / 1000;
+
+ return (u32)delta_time_us;
+}
+
/******************************************************************************
* Software filter functions
******************************************************************************/
@@ -120,8 +143,14 @@
printk("missed packet!\n");
*/
- if (buf[1] & 0x40) // PUSI ?
+ /* PUSI ? */
+ if (buf[1] & 0x40) {
feed->peslen = 0xfffa;
+ feed->pusi_seen = 1;
+ }
+
+ if (feed->pusi_seen == 0)
+ return 0;
feed->peslen += count;
@@ -164,10 +193,23 @@
return 0;
if (sec->check_crc) {
+ struct timespec pre_crc_time;
+
+ if (dvb_demux_performancecheck)
+ pre_crc_time = current_kernel_time();
+
section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
if (section_syntax_indicator &&
- demux->check_crc32(feed, sec->secbuf, sec->seclen))
+ demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
+ if (dvb_demux_performancecheck)
+ demux->total_crc_time +=
+ dvb_dmx_calc_time_delta(pre_crc_time);
return -1;
+ }
+
+ if (dvb_demux_performancecheck)
+ demux->total_crc_time +=
+ dvb_dmx_calc_time_delta(pre_crc_time);
}
do {
@@ -351,6 +393,161 @@
return 0;
}
+static inline void dvb_dmx_swfilter_output_packet(
+ struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ u8 time_stamp[4] = {0};
+ struct dvb_demux *demux = feed->demux;
+
+ /*
+ * if we output 192 packet with timestamp at head of packet,
+ * output the timestamp now before the 188 TS packet
+ */
+ if (demux->tsp_out_format == DMX_TSP_FORMAT_192_HEAD)
+ feed->cb.ts(time_stamp, 4, NULL, 0, &feed->feed.ts, DMX_OK);
+
+ feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+
+ /*
+ * if we output 192 packet with timestamp at tail of packet,
+ * output the timestamp now after the 188 TS packet
+ */
+ if (demux->tsp_out_format == DMX_TSP_FORMAT_192_TAIL)
+ feed->cb.ts(time_stamp, 4, NULL, 0, &feed->feed.ts, DMX_OK);
+}
+
+static inline void dvb_dmx_configure_decoder_fullness(
+ struct dvb_demux *demux,
+ int initialize)
+{
+ struct dvb_demux_feed *feed;
+ int j;
+
+ for (j = 0; j < demux->feednum; j++) {
+ feed = &demux->feed[j];
+
+ if ((feed->state != DMX_STATE_GO) ||
+ (feed->type != DMX_TYPE_TS) ||
+ !(feed->ts_type & TS_DECODER))
+ continue;
+
+ if (initialize) {
+ if (demux->decoder_fullness_init)
+ demux->decoder_fullness_init(feed);
+ } else {
+ if (demux->decoder_fullness_abort)
+ demux->decoder_fullness_abort(feed);
+ }
+ }
+}
+
+static inline int dvb_dmx_swfilter_buffer_check(
+ struct dvb_demux *demux,
+ u16 pid)
+{
+ int desired_space;
+ int ret;
+ struct dmx_ts_feed *ts;
+ struct dvb_demux_filter *f;
+ struct dvb_demux_feed *feed;
+ int was_locked;
+ int i, j;
+
+ if (likely(spin_is_locked(&demux->lock)))
+ was_locked = 1;
+ else
+ was_locked = 0;
+
+ /*
+ * Check that there's enough free space for data output.
+ * If there no space, wait for it (block).
+ * Since this function is called while spinlock
+ * is aquired, the lock should be released first.
+ * Once we get control back, lock is aquired back
+ * and checks that the filter is still valid.
+ */
+ for (j = 0; j < demux->feednum; j++) {
+ feed = &demux->feed[j];
+
+ if (demux->sw_filter_abort)
+ return -ENODEV;
+
+ if ((feed->state != DMX_STATE_GO) ||
+ ((feed->pid != pid) && (feed->pid != 0x2000)))
+ continue;
+
+ if (feed->type == DMX_TYPE_TS) {
+ desired_space = 192; /* upper bound */
+ ts = &feed->feed.ts;
+
+ if (feed->ts_type & TS_PACKET) {
+ if (likely(was_locked))
+ spin_unlock(&demux->lock);
+
+ ret = demux->buffer_ctrl.ts(ts, desired_space);
+
+ if (likely(was_locked))
+ spin_lock(&demux->lock);
+
+ if (ret < 0)
+ continue;
+ }
+
+ if (demux->sw_filter_abort)
+ return -ENODEV;
+
+ if (!ts->is_filtering)
+ continue;
+
+ if ((feed->ts_type & TS_DECODER) &&
+ (demux->decoder_fullness_wait)) {
+ if (likely(was_locked))
+ spin_unlock(&demux->lock);
+
+ ret = demux->decoder_fullness_wait(
+ feed,
+ desired_space);
+
+ if (likely(was_locked))
+ spin_lock(&demux->lock);
+
+ if (ret < 0)
+ continue;
+ }
+
+ continue;
+ }
+
+ /* else - section case */
+ desired_space = feed->feed.sec.tsfeedp + 188; /* upper bound */
+ for (i = 0; i < demux->filternum; i++) {
+ if (demux->sw_filter_abort)
+ return -EPERM;
+
+ if (!feed->feed.sec.is_filtering)
+ continue;
+
+ f = &demux->filter[i];
+ if (f->feed != feed)
+ continue;
+
+ if (likely(was_locked))
+ spin_unlock(&demux->lock);
+
+ ret = demux->buffer_ctrl.sec(&f->filter, desired_space);
+
+ if (likely(was_locked))
+ spin_lock(&demux->lock);
+
+ if (ret < 0)
+ break;
+ }
+ }
+
+ return 0;
+}
+
static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
const u8 *buf)
{
@@ -362,8 +559,7 @@
if (feed->ts_type & TS_PAYLOAD_ONLY)
dvb_dmx_swfilter_payload(feed, buf);
else
- feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
- DMX_OK);
+ dvb_dmx_swfilter_output_packet(feed, buf);
}
if (feed->ts_type & TS_DECODER)
if (feed->demux->write_to_decoder)
@@ -446,6 +642,10 @@
/* end check */
};
+ if (demux->playback_mode == DMX_PB_MODE_PULL)
+ if (dvb_dmx_swfilter_buffer_check(demux, pid) < 0)
+ return;
+
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
@@ -457,16 +657,25 @@
if (feed->pid == pid)
dvb_dmx_swfilter_packet_type(feed, buf);
- else if (feed->pid == 0x2000)
- feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+ else if ((feed->pid == 0x2000) &&
+ (feed->feed.ts.is_filtering))
+ dvb_dmx_swfilter_output_packet(feed, buf);
}
}
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
{
+ struct timespec pre_time;
+
+ if (dvb_demux_performancecheck)
+ pre_time = current_kernel_time();
+
spin_lock(&demux->lock);
+ demux->sw_filter_abort = 0;
+ dvb_dmx_configure_decoder_fullness(demux, 1);
+
while (count--) {
if (buf[0] == 0x47)
dvb_dmx_swfilter_packet(demux, buf);
@@ -474,18 +683,24 @@
}
spin_unlock(&demux->lock);
+
+ if (dvb_demux_performancecheck)
+ demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
static inline int find_next_packet(const u8 *buf, int pos, size_t count,
- const int pktsize)
+ const int pktsize, const int leadingbytes)
{
int start = pos, lost;
while (pos < count) {
- if (buf[pos] == 0x47 ||
- (pktsize == 204 && buf[pos] == 0xB8))
+ if ((buf[pos] == 0x47 && !leadingbytes) ||
+ (pktsize == 204 && buf[pos] == 0xB8) ||
+ (pktsize == 192 && leadingbytes &&
+ (pos+leadingbytes < count) &&
+ buf[pos+leadingbytes] == 0x47))
break;
pos++;
}
@@ -495,7 +710,9 @@
/* This garbage is part of a valid packet? */
int backtrack = pos - pktsize;
if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
- (pktsize == 204 && buf[backtrack] == 0xB8)))
+ (pktsize == 204 && buf[backtrack] == 0xB8) ||
+ (pktsize == 192 &&
+ buf[backtrack+leadingbytes] == 0x47)))
return backtrack;
}
@@ -504,13 +721,20 @@
/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
- size_t count, const int pktsize)
+ size_t count, const int pktsize, const int leadingbytes)
{
int p = 0, i, j;
const u8 *q;
+ struct timespec pre_time;
+
+ if (dvb_demux_performancecheck)
+ pre_time = current_kernel_time();
spin_lock(&demux->lock);
+ demux->sw_filter_abort = 0;
+ dvb_dmx_configure_decoder_fullness(demux, 1);
+
if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
i = demux->tsbufp;
j = pktsize - i;
@@ -520,14 +744,22 @@
goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
- if (demux->tsbuf[0] == 0x47) /* double check */
+ if (pktsize == 192 &&
+ leadingbytes &&
+ demux->tsbuf[leadingbytes] == 0x47) /* double check */
+ dvb_dmx_swfilter_packet(demux, demux->tsbuf+4);
+ else if (demux->tsbuf[0] == 0x47) /* double check */
dvb_dmx_swfilter_packet(demux, demux->tsbuf);
demux->tsbufp = 0;
p += j;
}
while (1) {
- p = find_next_packet(buf, p, count, pktsize);
+ p = find_next_packet(buf, p, count, pktsize, leadingbytes);
+
+ if (demux->sw_filter_abort)
+ goto bailout;
+
if (p >= count)
break;
if (count - p < pktsize)
@@ -540,6 +772,10 @@
demux->tsbuf[0] = 0x47;
q = demux->tsbuf;
}
+
+ if (pktsize == 192 && leadingbytes)
+ q = &buf[p+leadingbytes];
+
dvb_dmx_swfilter_packet(demux, q);
p += pktsize;
}
@@ -554,20 +790,55 @@
bailout:
spin_unlock(&demux->lock);
+
+ if (dvb_demux_performancecheck)
+ demux->total_process_time += dvb_dmx_calc_time_delta(pre_time);
}
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
{
- _dvb_dmx_swfilter(demux, buf, count, 188);
+ _dvb_dmx_swfilter(demux, buf, count, 188, 0);
}
EXPORT_SYMBOL(dvb_dmx_swfilter);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
{
- _dvb_dmx_swfilter(demux, buf, count, 204);
+ _dvb_dmx_swfilter(demux, buf, count, 204, 0);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+void dvb_dmx_swfilter_format(
+ struct dvb_demux *demux,
+ const u8 *buf,
+ size_t count,
+ enum dmx_tsp_format_t tsp_format)
+{
+ switch (tsp_format) {
+ case DMX_TSP_FORMAT_188:
+ _dvb_dmx_swfilter(demux, buf, count, 188, 0);
+ break;
+
+ case DMX_TSP_FORMAT_192_TAIL:
+ _dvb_dmx_swfilter(demux, buf, count, 192, 0);
+ break;
+
+ case DMX_TSP_FORMAT_192_HEAD:
+ _dvb_dmx_swfilter(demux, buf, count, 192, 4);
+ break;
+
+ case DMX_TSP_FORMAT_204:
+ _dvb_dmx_swfilter(demux, buf, count, 204, 0);
+ break;
+
+ default:
+ printk(KERN_ERR "%s: invalid TS packet format (format=%d)\n",
+ __func__,
+ tsp_format);
+ break;
+ }
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_format);
+
static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
{
int i;
@@ -778,6 +1049,13 @@
feed->peslen = 0xfffa;
feed->buffer = NULL;
+ /* default behaviour - pass first PES data even if it is
+ * partial PES data from previous PES that we didn't receive its header.
+ * Override this to 0 in your start_feed function in order to handle
+ * first PES differently.
+ */
+ feed->pusi_seen = 1;
+
(*ts_feed) = &feed->feed.ts;
(*ts_feed)->parent = dmx;
(*ts_feed)->priv = NULL;
@@ -1119,30 +1397,54 @@
return 0;
}
-static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
+static int dvbdmx_write(struct dmx_demux *demux, const char *buf, size_t count)
{
struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
- void *p;
if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
return -EINVAL;
- p = memdup_user(buf, count);
- if (IS_ERR(p))
- return PTR_ERR(p);
- if (mutex_lock_interruptible(&dvbdemux->mutex)) {
- kfree(p);
- return -ERESTARTSYS;
- }
- dvb_dmx_swfilter(dvbdemux, p, count);
- kfree(p);
- mutex_unlock(&dvbdemux->mutex);
+ dvb_dmx_swfilter_format(dvbdemux, buf, count, dvbdemux->tsp_format);
if (signal_pending(current))
return -EINTR;
return count;
}
+static int dvbdmx_write_cancel(struct dmx_demux *demux)
+{
+ struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+ spin_lock_irq(&dvbdmx->lock);
+
+ /* cancel any pending wait for decoder's buffers */
+ dvbdmx->sw_filter_abort = 1;
+ dvbdmx->tsbufp = 0;
+ dvb_dmx_configure_decoder_fullness(dvbdmx, 0);
+
+ spin_unlock_irq(&dvbdmx->lock);
+
+ return 0;
+}
+
+static int dvbdmx_set_playback_mode(struct dmx_demux *demux,
+ enum dmx_playback_mode_t mode,
+ dmx_ts_fullness ts_fullness_callback,
+ dmx_section_fullness sec_fullness_callback)
+{
+ struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+ mutex_lock(&dvbdmx->mutex);
+
+ dvbdmx->playback_mode = mode;
+ dvbdmx->buffer_ctrl.ts = ts_fullness_callback;
+ dvbdmx->buffer_ctrl.sec = sec_fullness_callback;
+
+ mutex_unlock(&dvbdmx->mutex);
+
+ return 0;
+}
+
static int dvbdmx_add_frontend(struct dmx_demux *demux,
struct dmx_frontend *frontend)
{
@@ -1214,6 +1516,40 @@
return 0;
}
+static int dvbdmx_set_tsp_format(
+ struct dmx_demux *demux,
+ enum dmx_tsp_format_t tsp_format)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ if ((tsp_format > DMX_TSP_FORMAT_204) ||
+ (tsp_format < DMX_TSP_FORMAT_188))
+ return -EINVAL;
+
+ mutex_lock(&dvbdemux->mutex);
+
+ dvbdemux->tsp_format = tsp_format;
+ mutex_unlock(&dvbdemux->mutex);
+ return 0;
+}
+
+static int dvbdmx_set_tsp_out_format(
+ struct dmx_demux *demux,
+ enum dmx_tsp_format_t tsp_format)
+{
+ struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+ if ((tsp_format > DMX_TSP_FORMAT_192_HEAD) ||
+ (tsp_format < DMX_TSP_FORMAT_188))
+ return -EINVAL;
+
+ mutex_lock(&dvbdemux->mutex);
+
+ dvbdemux->tsp_out_format = tsp_format;
+ mutex_unlock(&dvbdemux->mutex);
+ return 0;
+}
+
int dvb_dmx_init(struct dvb_demux *dvbdemux)
{
int i;
@@ -1232,6 +1568,30 @@
dvbdemux->filter = NULL;
return -ENOMEM;
}
+
+ dvbdemux->total_process_time = 0;
+ dvbdemux->total_crc_time = 0;
+ snprintf(dvbdemux->alias,
+ MAX_DVB_DEMUX_NAME_LEN,
+ "demux%d",
+ dvb_demux_index++);
+
+ dvbdemux->debugfs_demux_dir = debugfs_create_dir(dvbdemux->alias, NULL);
+
+ if (dvbdemux->debugfs_demux_dir != NULL) {
+ debugfs_create_u32(
+ "total_processing_time",
+ S_IRUGO|S_IWUGO,
+ dvbdemux->debugfs_demux_dir,
+ &dvbdemux->total_process_time);
+
+ debugfs_create_u32(
+ "total_crc_time",
+ S_IRUGO|S_IWUGO,
+ dvbdemux->debugfs_demux_dir,
+ &dvbdemux->total_crc_time);
+ }
+
for (i = 0; i < dvbdemux->filternum; i++) {
dvbdemux->filter[i].state = DMX_STATE_FREE;
dvbdemux->filter[i].index = i;
@@ -1258,6 +1618,9 @@
dvbdemux->recording = 0;
dvbdemux->tsbufp = 0;
+ dvbdemux->tsp_format = DMX_TSP_FORMAT_188;
+ dvbdemux->tsp_out_format = DMX_TSP_FORMAT_188;
+
if (!dvbdemux->check_crc32)
dvbdemux->check_crc32 = dvb_dmx_crc32;
@@ -1269,6 +1632,8 @@
dmx->open = dvbdmx_open;
dmx->close = dvbdmx_close;
dmx->write = dvbdmx_write;
+ dmx->write_cancel = dvbdmx_write_cancel;
+ dmx->set_playback_mode = dvbdmx_set_playback_mode;
dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
dmx->release_ts_feed = dvbdmx_release_ts_feed;
dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
@@ -1281,6 +1646,9 @@
dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
dmx->get_pes_pids = dvbdmx_get_pes_pids;
+ dmx->set_tsp_format = dvbdmx_set_tsp_format;
+ dmx->set_tsp_out_format = dvbdmx_set_tsp_out_format;
+
mutex_init(&dvbdemux->mutex);
spin_lock_init(&dvbdemux->lock);
@@ -1291,6 +1659,9 @@
void dvb_dmx_release(struct dvb_demux *dvbdemux)
{
+ if (dvbdemux->debugfs_demux_dir != NULL)
+ debugfs_remove_recursive(dvbdemux->debugfs_demux_dir);
+
vfree(dvbdemux->cnt_storage);
vfree(dvbdemux->filter);
vfree(dvbdemux->feed);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
index a7d876f..297f3df 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.h
+++ b/drivers/media/dvb/dvb-core/dvb_demux.h
@@ -4,6 +4,8 @@
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
* for convergence integrated media GmbH
*
+ * 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
@@ -27,6 +29,7 @@
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
+#include <linux/debugfs.h>
#include "demux.h"
@@ -107,6 +110,10 @@
int (*stop_feed)(struct dvb_demux_feed *feed);
int (*write_to_decoder)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
+ int (*decoder_fullness_init)(struct dvb_demux_feed *feed);
+ int (*decoder_fullness_wait)(struct dvb_demux_feed *feed,
+ size_t required_space);
+ int (*decoder_fullness_abort)(struct dvb_demux_feed *feed);
u32 (*check_crc32)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
@@ -136,6 +143,28 @@
struct timespec speed_last_time; /* for TS speed check */
uint32_t speed_pkts_cnt; /* for TS speed check */
+
+ enum dmx_tsp_format_t tsp_format;
+ enum dmx_tsp_format_t tsp_out_format;
+
+ enum dmx_playback_mode_t playback_mode;
+ int sw_filter_abort;
+
+ struct {
+ dmx_ts_fullness ts;
+ dmx_section_fullness sec;
+ } buffer_ctrl;
+
+ /*
+ * the following is used for debugfs exposing info
+ * about dvb demux performance.
+ */
+#define MAX_DVB_DEMUX_NAME_LEN 10
+ char alias[MAX_DVB_DEMUX_NAME_LEN];
+
+ u32 total_process_time;
+ u32 total_crc_time;
+ struct dentry *debugfs_demux_dir;
};
int dvb_dmx_init(struct dvb_demux *dvbdemux);
@@ -145,5 +174,10 @@
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
size_t count);
+void dvb_dmx_swfilter_format(
+ struct dvb_demux *demux, const u8 *buf,
+ size_t count,
+ enum dmx_tsp_format_t tsp_format);
+
#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index a5712cd..36cc475 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -5,6 +5,8 @@
* Copyright (C) 2003 Oliver Endriss
* Copyright (C) 2004 Andrew de Quincey
*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
* based on code originally found in av7110.c & dvb_ci.c:
* Copyright (C) 1999-2003 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
@@ -37,6 +39,8 @@
#define PKT_READY 0
#define PKT_DISPOSED 1
+#define PKT_PENDING 2
+
void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
@@ -166,6 +170,35 @@
return len;
}
+ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+ const u8 *buf, size_t len)
+{
+ size_t todo = len;
+ size_t split;
+ ssize_t oldpwrite = rbuf->pwrite;
+
+ split = (rbuf->pwrite + len > rbuf->size) ?
+ rbuf->size - rbuf->pwrite :
+ 0;
+
+ if (split > 0) {
+ if (copy_from_user(rbuf->data + rbuf->pwrite, buf, split))
+ return -EFAULT;
+ buf += split;
+ todo -= split;
+ rbuf->pwrite = 0;
+ }
+
+ if (copy_from_user(rbuf->data + rbuf->pwrite, buf, todo)) {
+ rbuf->pwrite = oldpwrite;
+ return -EFAULT;
+ }
+
+ rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+ return len;
+}
+
ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
{
int status;
@@ -180,6 +213,31 @@
return status;
}
+ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf, size_t len)
+{
+ ssize_t oldpwrite = rbuf->pwrite;
+
+ DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
+ DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
+ DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_PENDING);
+
+ return oldpwrite;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_start);
+
+int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx)
+{
+ idx = (idx + 2) % rbuf->size;
+
+ if (rbuf->data[idx] != PKT_PENDING)
+ return -EINVAL;
+
+ rbuf->data[idx] = PKT_READY;
+
+ return 0;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_close);
+
ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8 __user *buf, size_t len)
{
@@ -187,6 +245,9 @@
size_t split;
size_t pktlen;
+ if (DVB_RINGBUFFER_PEEK(rbuf, (idx+2)) != PKT_READY)
+ return -EINVAL;
+
pktlen = rbuf->data[idx] << 8;
pktlen |= rbuf->data[(idx + 1) % rbuf->size];
if (offset > pktlen) return -EINVAL;
@@ -207,6 +268,7 @@
return len;
}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read_user);
ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
int offset, u8* buf, size_t len)
@@ -215,9 +277,13 @@
size_t split;
size_t pktlen;
+ if (rbuf->data[(idx + 2) % rbuf->size] != PKT_READY)
+ return -EINVAL;
+
pktlen = rbuf->data[idx] << 8;
pktlen |= rbuf->data[(idx + 1) % rbuf->size];
if (offset > pktlen) return -EINVAL;
+
if ((offset + len) > pktlen) len = pktlen - offset;
idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
@@ -232,6 +298,7 @@
memcpy(buf, rbuf->data+idx, todo);
return len;
}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_read);
void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
{
@@ -251,6 +318,7 @@
}
}
}
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose);
ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
{
@@ -279,6 +347,9 @@
return idx;
}
+ if (curpktstatus == PKT_PENDING)
+ return -EFAULT;
+
consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
}
@@ -286,8 +357,7 @@
// no packets available
return -1;
}
-
-
+EXPORT_SYMBOL(dvb_ringbuffer_pkt_next);
EXPORT_SYMBOL(dvb_ringbuffer_init);
EXPORT_SYMBOL(dvb_ringbuffer_empty);
@@ -297,3 +367,5 @@
EXPORT_SYMBOL(dvb_ringbuffer_read_user);
EXPORT_SYMBOL(dvb_ringbuffer_read);
EXPORT_SYMBOL(dvb_ringbuffer_write);
+EXPORT_SYMBOL(dvb_ringbuffer_write_user);
+
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
index 41f04da..8b591a6 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
@@ -5,6 +5,8 @@
* Copyright (C) 2003 Oliver Endriss
* Copyright (C) 2004 Andrew de Quincey
*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
* based on code originally found in av7110.c & dvb_ci.c:
* Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
@@ -134,6 +136,8 @@
extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
size_t len);
+extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf,
+ const u8 *buf, size_t len);
/**
* Write a packet into the ringbuffer.
@@ -183,4 +187,30 @@
extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
+/**
+ * Start a new packet that will be written directly by the user to the packet buffer.
+ * The function only writes the header of the packet into the packet buffer,
+ * and the packet is in pending state (can't be read by the reader) until it is
+ * closed using dvb_ringbuffer_pkt_close. You must write the data into the
+ * packet buffer using dvb_ringbuffer_write followed by
+ * dvb_ringbuffer_pkt_close.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <len> Size of the packet's data
+ * returns Index of the packet's header that was started.
+ */
+extern ssize_t dvb_ringbuffer_pkt_start(struct dvb_ringbuffer *rbuf,
+ size_t len);
+
+/**
+ * Close a packet that was started using dvb_ringbuffer_pkt_start.
+ * The packet will be marked as ready to be ready.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <idx> Packet index that was returned by dvb_ringbuffer_pkt_start
+ * returns error status, -EINVAL if the provided index is invalid
+ */
+extern int dvb_ringbuffer_pkt_close(struct dvb_ringbuffer *rbuf, ssize_t idx);
+
+
#endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/media/dvb/mpq/Kconfig b/drivers/media/dvb/mpq/Kconfig
new file mode 100644
index 0000000..868ad8c
--- /dev/null
+++ b/drivers/media/dvb/mpq/Kconfig
@@ -0,0 +1,12 @@
+config DVB_MPQ
+ tristate "Qualcomm Multimedia Processor DVB Adapter"
+ depends on ARCH_MSM && DVB_CORE
+ default n
+
+ help
+ Support for Qualcomm MPQ based DVB adapter.
+ Say Y or M if you own such a device and want to use it.
+
+source "drivers/media/dvb/mpq/demux/Kconfig"
+
+
diff --git a/drivers/media/dvb/mpq/Makefile b/drivers/media/dvb/mpq/Makefile
new file mode 100644
index 0000000..7ccf13e
--- /dev/null
+++ b/drivers/media/dvb/mpq/Makefile
@@ -0,0 +1,5 @@
+
+obj-$(CONFIG_DVB_MPQ) += adapter/
+obj-$(CONFIG_DVB_MPQ_DEMUX) += demux/
+
+
diff --git a/drivers/media/dvb/mpq/adapter/Makefile b/drivers/media/dvb/mpq/adapter/Makefile
new file mode 100644
index 0000000..ed664da
--- /dev/null
+++ b/drivers/media/dvb/mpq/adapter/Makefile
@@ -0,0 +1,8 @@
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/mpq/include/
+
+obj-$(CONFIG_DVB_MPQ) += mpq-adapter.o
+
+mpq-adapter-y := mpq_adapter.o mpq_stream_buffer.o
+
diff --git a/drivers/media/dvb/mpq/adapter/mpq_adapter.c b/drivers/media/dvb/mpq/adapter/mpq_adapter.c
new file mode 100644
index 0000000..9664f04
--- /dev/null
+++ b/drivers/media/dvb/mpq/adapter/mpq_adapter.c
@@ -0,0 +1,212 @@
+/* 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 "mpq_adapter.h"
+#include "mpq_dvb_debug.h"
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/* data-structure holding MPQ adapter information */
+static struct
+{
+ /* MPQ adapter registered to dvb-core */
+ struct dvb_adapter adapter;
+
+ /* mutex protect against the data-structure */
+ struct mutex mutex;
+
+ /* List of stream interfaces registered to the MPQ adapter */
+ struct {
+ /* pointer to the stream buffer using for data tunneling */
+ struct mpq_streambuffer *stream_buffer;
+
+ /* callback triggered when the stream interface is registered */
+ mpq_adapter_stream_if_callback callback;
+
+ /* parameter passed to the callback function */
+ void *user_param;
+ } interfaces[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
+} mpq_info;
+
+
+/**
+ * Initialize MPQ DVB adapter module.
+ *
+ * Return error status
+ */
+static int __init mpq_adapter_init(void)
+{
+ int i;
+ int result;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ mutex_init(&mpq_info.mutex);
+
+ /* reset stream interfaces list */
+ for (i = 0; i < MPQ_ADAPTER_MAX_NUM_OF_INTERFACES; i++) {
+ mpq_info.interfaces[i].stream_buffer = NULL;
+ mpq_info.interfaces[i].callback = NULL;
+ }
+
+ /* regsiter a new dvb-adapter to dvb-core */
+ result = dvb_register_adapter(&mpq_info.adapter,
+ "Qualcomm DVB adapter",
+ THIS_MODULE,
+ NULL,
+ adapter_nr);
+
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: dvb_register_adapter failed, errno %d\n",
+ __func__,
+ result);
+ }
+
+ return result;
+}
+
+
+/**
+ * Cleanup MPQ DVB adapter module.
+ */
+static void __exit mpq_adapter_exit(void)
+{
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /* un-regsiter adapter from dvb-core */
+ dvb_unregister_adapter(&mpq_info.adapter);
+ mutex_destroy(&mpq_info.mutex);
+}
+
+struct dvb_adapter *mpq_adapter_get(void)
+{
+ return &mpq_info.adapter;
+}
+EXPORT_SYMBOL(mpq_adapter_get);
+
+
+int mpq_adapter_register_stream_if(
+ enum mpq_adapter_stream_if interface_id,
+ struct mpq_streambuffer *stream_buffer)
+{
+ int ret;
+
+ if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) {
+ ret = -EINVAL;
+ goto register_failed;
+ }
+
+ if (mutex_lock_interruptible(&mpq_info.mutex)) {
+ ret = -ERESTARTSYS;
+ goto register_failed;
+ }
+
+ if (mpq_info.interfaces[interface_id].stream_buffer != NULL) {
+ /* already registered interface */
+ ret = -EINVAL;
+ goto register_failed_unlock_mutex;
+ }
+
+ mpq_info.interfaces[interface_id].stream_buffer = stream_buffer;
+ mutex_unlock(&mpq_info.mutex);
+
+ /*
+ * If callback is installed, trigger it to notify that
+ * stream interface was registered.
+ */
+ if (mpq_info.interfaces[interface_id].callback != NULL) {
+ mpq_info.interfaces[interface_id].callback(
+ interface_id,
+ mpq_info.interfaces[interface_id].user_param);
+ }
+
+ return 0;
+
+register_failed_unlock_mutex:
+ mutex_unlock(&mpq_info.mutex);
+register_failed:
+ return ret;
+}
+EXPORT_SYMBOL(mpq_adapter_register_stream_if);
+
+
+int mpq_adapter_unregister_stream_if(
+ enum mpq_adapter_stream_if interface_id)
+{
+ if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&mpq_info.mutex))
+ return -ERESTARTSYS;
+
+ /* clear the registered interface */
+ mpq_info.interfaces[interface_id].stream_buffer = NULL;
+
+ mutex_unlock(&mpq_info.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_unregister_stream_if);
+
+
+int mpq_adapter_get_stream_if(
+ enum mpq_adapter_stream_if interface_id,
+ struct mpq_streambuffer **stream_buffer)
+{
+ if ((interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES) ||
+ (stream_buffer == NULL))
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&mpq_info.mutex))
+ return -ERESTARTSYS;
+
+ *stream_buffer = mpq_info.interfaces[interface_id].stream_buffer;
+
+ mutex_unlock(&mpq_info.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_get_stream_if);
+
+
+int mpq_adapter_notify_stream_if(
+ enum mpq_adapter_stream_if interface_id,
+ mpq_adapter_stream_if_callback callback,
+ void *user_param)
+{
+ if (interface_id >= MPQ_ADAPTER_MAX_NUM_OF_INTERFACES)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&mpq_info.mutex))
+ return -ERESTARTSYS;
+
+ mpq_info.interfaces[interface_id].callback = callback;
+ mpq_info.interfaces[interface_id].user_param = user_param;
+
+ mutex_unlock(&mpq_info.mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_adapter_notify_stream_if);
+
+
+module_init(mpq_adapter_init);
+module_exit(mpq_adapter_exit);
+
+MODULE_DESCRIPTION("Qualcomm MPQ adapter");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
new file mode 100644
index 0000000..738d730
--- /dev/null
+++ b/drivers/media/dvb/mpq/adapter/mpq_stream_buffer.c
@@ -0,0 +1,224 @@
+/* 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/sched.h>
+#include <linux/wait.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_stream_buffer.h"
+
+
+void mpq_streambuffer_init(
+ struct mpq_streambuffer *sbuff,
+ void *data_buff, size_t data_buff_len,
+ void *packet_buff, size_t packet_buff_size)
+{
+ dvb_ringbuffer_init(&sbuff->raw_data, data_buff, data_buff_len);
+ dvb_ringbuffer_init(&sbuff->packet_data, packet_buff, packet_buff_size);
+}
+EXPORT_SYMBOL(mpq_streambuffer_init);
+
+
+ssize_t mpq_streambuffer_pkt_next(
+ struct mpq_streambuffer *sbuff,
+ ssize_t idx, size_t *pktlen)
+{
+ return dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen);
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_next);
+
+
+ssize_t mpq_streambuffer_pkt_read(
+ struct mpq_streambuffer *sbuff,
+ size_t idx,
+ struct mpq_streambuffer_packet_header *packet,
+ u8 *user_data)
+{
+ size_t ret;
+ size_t read_len;
+
+ /* read-out the packet header first */
+ ret = dvb_ringbuffer_pkt_read(
+ &sbuff->packet_data, idx, 0,
+ (u8 *)packet,
+ sizeof(struct mpq_streambuffer_packet_header));
+
+ /* verify length, at least packet header should exist */
+ if (ret != sizeof(struct mpq_streambuffer_packet_header))
+ return -EINVAL;
+
+ read_len = ret;
+
+ /* read-out private user-data if there are such */
+ if ((packet->user_data_len) && (user_data != NULL)) {
+ ret = dvb_ringbuffer_pkt_read(
+ &sbuff->packet_data,
+ idx,
+ sizeof(struct mpq_streambuffer_packet_header),
+ user_data,
+ packet->user_data_len);
+
+ if (ret < 0)
+ return ret;
+
+ read_len += ret;
+ }
+
+ return read_len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_read);
+
+
+int mpq_streambuffer_pkt_dispose(
+ struct mpq_streambuffer *sbuff,
+ size_t idx,
+ int dispose_data)
+{
+ int ret;
+ struct mpq_streambuffer_packet_header packet;
+
+ if (dispose_data) {
+ /* read-out the packet header first */
+ ret = dvb_ringbuffer_pkt_read(
+ &sbuff->packet_data,
+ idx,
+ 0,
+ (u8 *)&packet,
+ sizeof(struct mpq_streambuffer_packet_header));
+
+ if (ret != sizeof(struct mpq_streambuffer_packet_header))
+ return -EINVAL;
+
+ /* Advance the read pointer in the raw-data buffer first */
+ ret = mpq_streambuffer_data_read_dispose(
+ sbuff,
+ packet.raw_data_len);
+ if (ret != 0)
+ return ret;
+ }
+
+ /* Now clear the packet from the packet header */
+ dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_dispose);
+
+
+int mpq_streambuffer_pkt_write(
+ struct mpq_streambuffer *sbuff,
+ struct mpq_streambuffer_packet_header *packet,
+ u8 *user_data)
+{
+ ssize_t idx;
+ size_t len;
+
+ len =
+ sizeof(struct mpq_streambuffer_packet_header) +
+ packet->user_data_len;
+
+ /* Make sure enough space available for packet header */
+ if (dvb_ringbuffer_free(&sbuff->packet_data) < len)
+ return -ENOSPC;
+
+ /* Starting writting packet header */
+ idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len);
+
+ /* Write non-user private data header */
+ dvb_ringbuffer_write(
+ &sbuff->packet_data,
+ (u8 *)packet,
+ sizeof(struct mpq_streambuffer_packet_header));
+
+ /* Write user's own private data header */
+ dvb_ringbuffer_write(&sbuff->packet_data,
+ user_data,
+ packet->user_data_len);
+
+ dvb_ringbuffer_pkt_close(&sbuff->packet_data, idx);
+
+ wake_up_all(&sbuff->packet_data.queue);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_pkt_write);
+
+
+ssize_t mpq_streambuffer_data_write(
+ struct mpq_streambuffer *sbuff,
+ const u8 *buf, size_t len)
+{
+ int res;
+
+ if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+ return -ENOSPC;
+
+ res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
+ wake_up_all(&sbuff->raw_data.queue);
+
+ return res;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_write);
+
+
+int mpq_streambuffer_data_write_deposit(
+ struct mpq_streambuffer *sbuff,
+ size_t len)
+{
+ if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+ return -ENOSPC;
+
+ sbuff->raw_data.pwrite =
+ (sbuff->raw_data.pwrite+len) % sbuff->raw_data.size;
+
+ wake_up_all(&sbuff->raw_data.queue);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit);
+
+
+size_t mpq_streambuffer_data_read(
+ struct mpq_streambuffer *sbuff,
+ u8 *buf, size_t len)
+{
+ int actual_len;
+
+ actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
+ if (actual_len < len)
+ len = actual_len;
+
+ if (actual_len)
+ dvb_ringbuffer_read(&sbuff->raw_data, buf, actual_len);
+
+ wake_up_all(&sbuff->raw_data.queue);
+
+ return actual_len;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read);
+
+
+int mpq_streambuffer_data_read_dispose(
+ struct mpq_streambuffer *sbuff,
+ size_t len)
+{
+ if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+ return -EINVAL;
+
+ DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
+
+ wake_up_all(&sbuff->raw_data.queue);
+ return 0;
+}
+EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose);
+
diff --git a/drivers/media/dvb/mpq/demux/Kconfig b/drivers/media/dvb/mpq/demux/Kconfig
new file mode 100644
index 0000000..34961c2
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/Kconfig
@@ -0,0 +1,45 @@
+config DVB_MPQ_DEMUX
+ tristate "DVB Demux Device"
+ depends on DVB_MPQ && ION && ION_MSM
+ default n
+
+ help
+ Support for Qualcomm based dvb demux device.
+ Say Y or M if you own such a device and want to use it.
+
+config DVB_MPQ_NUM_DMX_DEVICES
+ int "Number of demux devices"
+ depends on DVB_MPQ_DEMUX
+ default 4
+ range 1 255
+
+ help
+ Configure number of demux devices. Depends on your use-cases for maximum concurrent stream playback.
+
+choice
+ prompt "Demux Hardware Plugin"
+ depends on DVB_MPQ_DEMUX
+ default DVB_MPQ_TSIF
+ help
+ Enable support of specific demux HW plugin depending on the existing HW support.
+ Depending on the enabled HW, demux may take advantage of HW capbailities to perform some tasks in HW instead of SW.
+
+ config DVB_MPQ_TSPP1
+ bool "TSPPv1 plugin"
+ depends on TSPP
+ help
+ Use this option of your HW has Transport Stream Packet Processor (TSPP) version1 support
+
+ config DVB_MPQ_TSPP2
+ bool "TSPPv2 plugin"
+ depends on TSPP
+ help
+ Use this option of your HW has Transport Stream Packet Processor (TSPP) version2 support
+
+ config DVB_MPQ_TSIF
+ bool "TSIF plugin"
+ depends on TSIF
+ help
+ Use this option of your HW has only TSIF input without any Transport Stream Packet Processor (TSPP) support
+endchoice
+
diff --git a/drivers/media/dvb/mpq/demux/Makefile b/drivers/media/dvb/mpq/demux/Makefile
new file mode 100644
index 0000000..b9310c3
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/Makefile
@@ -0,0 +1,14 @@
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/mpq/include/
+
+obj-$(CONFIG_DVB_MPQ_DEMUX) += mpq-dmx-hw-plugin.o
+
+mpq-dmx-hw-plugin-y := mpq_dmx_plugin_common.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP1) += mpq_dmx_plugin_tspp_v1.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP2) += mpq_dmx_plugin_tspp_v2.o
+
+mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSIF) += mpq_dmx_plugin_tsif.o
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
new file mode 100644
index 0000000..e7bbfcb
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.c
@@ -0,0 +1,1239 @@
+/* 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/vmalloc.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+
+/* Length of mandatory fields that must exist in header of video PES */
+#define PES_MANDATORY_FIELDS_LEN 9
+
+
+/*
+ * 500 PES header packets in the meta-data buffer,
+ * should be more than enough
+ */
+#define VIDEO_NUM_OF_PES_PACKETS 500
+
+#define VIDEO_META_DATA_BUFFER_SIZE \
+ (VIDEO_NUM_OF_PES_PACKETS * \
+ (DVB_RINGBUFFER_PKTHDRSIZE + \
+ sizeof(struct mpq_streambuffer_packet_header) + \
+ sizeof(struct mpq_adapter_video_meta_data)))
+
+/*
+ * The following threshold defines gap from end of ring-buffer
+ * from which new PES payload will not be written to make
+ * sure that the PES payload does not wrap-around at end of the
+ * buffer. Instead, padding will be inserted and the new PES will
+ * be written from the beginning of the buffer.
+ * Setting this to 0 means no padding will be added.
+ */
+#define VIDEO_WRAP_AROUND_THRESHOLD (1024*1024+512*1024)
+
+/*
+ * PCR/STC information length saved in ring-buffer.
+ * PCR / STC are saved in ring-buffer in the following form:
+ * <8 bit flags><64 bits of STC> <64bits of PCR>
+ * STC and PCR values are in 27MHz.
+ * The current flags that are defined:
+ * 0x00000001: discontinuity_indicator
+ */
+#define PCR_STC_LEN 17
+
+
+/* Number of demux devices, has default of linux configuration */
+static int mpq_demux_device_num = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
+module_param(mpq_demux_device_num, int, S_IRUGO);
+
+
+/* Global data-structure for managing demux devices */
+static struct
+{
+ /* ION demux client used for memory allocation */
+ struct ion_client *ion_client;
+
+ /* demux devices array */
+ struct mpq_demux *devices;
+
+ /* Stream buffers objects used for tunneling to decoders */
+ struct mpq_streambuffer
+ decoder_buffers[MPQ_ADAPTER_MAX_NUM_OF_INTERFACES];
+
+ /*
+ * Indicates whether we allow decoder's data to
+ * wrap-around in the output buffer or padding is
+ * inserted in such case.
+ */
+ int decoder_data_wrap;
+} mpq_dmx_info;
+
+
+/* Check that PES header is valid and that it is a video PES */
+static int mpq_dmx_is_valid_video_pes(struct pes_packet_header *pes_header)
+{
+ /* start-code valid? */
+ if ((pes_header->packet_start_code_prefix_1 != 0) ||
+ (pes_header->packet_start_code_prefix_2 != 0) ||
+ (pes_header->packet_start_code_prefix_3 != 1))
+ return -EINVAL;
+
+ /* stream_id is video? */
+ if ((pes_header->stream_id & 0xF0) != 0xE0)
+ return -EINVAL;
+
+ return 0;
+}
+
+
+/* Extend dvb-demux debugfs with HW statistics */
+void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux)
+{
+ /*
+ * Extend dvb-demux debugfs with HW statistics.
+ * Note that destruction of debugfs directory is done
+ * when dvb-demux is terminated.
+ */
+ mpq_demux->hw_notification_count = 0;
+ mpq_demux->hw_notification_rate = 0;
+ mpq_demux->hw_notification_size = 0;
+ mpq_demux->decoder_tsp_drop_count = 0;
+
+ if (mpq_demux->demux.debugfs_demux_dir != NULL) {
+ debugfs_create_u32(
+ "hw_notification_rate",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.debugfs_demux_dir,
+ &mpq_demux->hw_notification_rate);
+
+ debugfs_create_u32(
+ "hw_notification_count",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.debugfs_demux_dir,
+ &mpq_demux->hw_notification_count);
+
+ debugfs_create_u32(
+ "hw_notification_size",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.debugfs_demux_dir,
+ &mpq_demux->hw_notification_size);
+
+ debugfs_create_u32(
+ "decoder_tsp_drop_count",
+ S_IRUGO|S_IWUGO,
+ mpq_demux->demux.debugfs_demux_dir,
+ &mpq_demux->decoder_tsp_drop_count);
+ }
+}
+EXPORT_SYMBOL(mpq_dmx_init_hw_statistics);
+
+
+/* Update dvb-demux debugfs with HW notification statistics */
+void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux)
+{
+ struct timespec curr_time, delta_time;
+ u64 delta_time_ms;
+
+ curr_time = current_kernel_time();
+ if (likely(mpq_demux->hw_notification_count)) {
+ /* calculate time-delta between notifications */
+ delta_time =
+ timespec_sub(
+ curr_time,
+ mpq_demux->last_notification_time);
+
+ delta_time_ms = (u64)timespec_to_ns(&delta_time);
+ delta_time_ms = div64_u64(delta_time_ms, 1000000); /* ns->ms */
+
+ mpq_demux->hw_notification_rate = delta_time_ms;
+ }
+
+ mpq_demux->hw_notification_count++;
+ mpq_demux->last_notification_time = curr_time;
+}
+EXPORT_SYMBOL(mpq_dmx_update_hw_statistics);
+
+
+int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func)
+{
+ int i;
+ int result;
+ struct mpq_demux *mpq_demux;
+ struct dvb_adapter *mpq_adapter;
+
+ MPQ_DVB_DBG_PRINT("%s executed, device num %d\n",
+ __func__,
+ mpq_demux_device_num);
+
+ mpq_adapter = mpq_adapter_get();
+
+ if (mpq_adapter == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_adapter is not valid\n",
+ __func__);
+ result = -EPERM;
+ goto init_failed;
+ }
+
+ if (mpq_demux_device_num == 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_demux_device_num set to 0\n",
+ __func__);
+
+ result = -EPERM;
+ goto init_failed;
+ }
+
+ mpq_dmx_info.devices = NULL;
+ mpq_dmx_info.ion_client = NULL;
+
+ /* TODO: the following should be set based on the decoder */
+ mpq_dmx_info.decoder_data_wrap = 0;
+
+ /* Allocate memory for all MPQ devices */
+ mpq_dmx_info.devices =
+ vmalloc(mpq_demux_device_num*sizeof(struct mpq_demux));
+
+ if (!mpq_dmx_info.devices) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: failed to allocate devices memory\n",
+ __func__);
+
+ result = -ENOMEM;
+ goto init_failed;
+ }
+
+ /* Zero allocated memory */
+ memset(mpq_dmx_info.devices,
+ 0,
+ mpq_demux_device_num*sizeof(struct mpq_demux));
+
+ /*
+ * Create a new ION client used by demux to allocate memory
+ * for decoder's buffers.
+ */
+ mpq_dmx_info.ion_client =
+ msm_ion_client_create(UINT_MAX, "demux client");
+
+ if (IS_ERR_OR_NULL(mpq_dmx_info.ion_client)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: msm_ion_client_create\n",
+ __func__);
+
+ result = PTR_ERR(mpq_dmx_info.ion_client);
+ mpq_dmx_info.ion_client = NULL;
+ goto init_failed_free_demux_devices;
+ }
+
+ /* Initialize and register all demux devices to the system */
+ for (i = 0; i < mpq_demux_device_num; i++) {
+ mpq_demux = mpq_dmx_info.devices+i;
+
+ /* initialize demux source to memory by default */
+ mpq_demux->source = DMX_SOURCE_DVR0 + i;
+
+ /*
+ * Give the plugin pointer to the ion client so
+ * that it can allocate memory from ION if it requires so
+ */
+ mpq_demux->ion_client = mpq_dmx_info.ion_client;
+
+ spin_lock_init(&mpq_demux->feed_lock);
+
+ /*
+ * mpq_demux_plugin_hw_init should be implemented
+ * by the specific plugin
+ */
+ result = dmx_init_func(mpq_adapter, mpq_demux);
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: dmx_init_func (errno=%d)\n",
+ __func__,
+ result);
+
+ goto init_failed_free_demux_devices;
+ }
+
+ mpq_demux->is_initialized = 1;
+
+ /*
+ * Add capability of receiving input from memory.
+ * Every demux in our system may be connected to memory input,
+ * or any live input.
+ */
+ mpq_demux->fe_memory.source = DMX_MEMORY_FE;
+ result =
+ mpq_demux->demux.dmx.add_frontend(
+ &mpq_demux->demux.dmx,
+ &mpq_demux->fe_memory);
+
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: add_frontend (mem) failed (errno=%d)\n",
+ __func__,
+ result);
+
+ goto init_failed_free_demux_devices;
+ }
+ }
+
+ return 0;
+
+init_failed_free_demux_devices:
+ mpq_dmx_plugin_exit();
+init_failed:
+ return result;
+}
+EXPORT_SYMBOL(mpq_dmx_plugin_init);
+
+
+void mpq_dmx_plugin_exit(void)
+{
+ int i;
+ struct mpq_demux *mpq_demux;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ if (mpq_dmx_info.ion_client != NULL) {
+ ion_client_destroy(mpq_dmx_info.ion_client);
+ mpq_dmx_info.ion_client = NULL;
+ }
+
+ if (mpq_dmx_info.devices != NULL) {
+ for (i = 0; i < mpq_demux_device_num; i++) {
+ mpq_demux = mpq_dmx_info.devices+i;
+
+ if (mpq_demux->is_initialized) {
+ mpq_demux->demux.dmx.remove_frontend(
+ &mpq_demux->demux.dmx,
+ &mpq_demux->fe_memory);
+
+ dvb_dmxdev_release(&mpq_demux->dmxdev);
+ dvb_dmx_release(&mpq_demux->demux);
+ }
+ }
+
+ vfree(mpq_dmx_info.devices);
+ mpq_dmx_info.devices = NULL;
+ }
+}
+EXPORT_SYMBOL(mpq_dmx_plugin_exit);
+
+
+int mpq_dmx_set_source(
+ struct dmx_demux *demux,
+ const dmx_source_t *src)
+{
+ int i;
+ int dvr_index;
+ int dmx_index;
+ struct mpq_demux *mpq_demux = (struct mpq_demux *)demux->priv;
+
+ if ((mpq_dmx_info.devices == NULL) || (mpq_demux == NULL)) {
+ MPQ_DVB_ERR_PRINT("%s: invalid parameters\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * For dvr sources,
+ * verify that this source is connected to the respective demux
+ */
+ dmx_index = mpq_demux - mpq_dmx_info.devices;
+
+ if (*src >= DMX_SOURCE_DVR0) {
+ dvr_index = *src - DMX_SOURCE_DVR0;
+
+ if (dvr_index != dmx_index) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: can't connect demux%d to dvr%d\n",
+ __func__,
+ dmx_index,
+ dvr_index);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * For front-end sources,
+ * verify that this source is not already set to different demux
+ */
+ for (i = 0; i < mpq_demux_device_num; i++) {
+ if ((&mpq_dmx_info.devices[i] != mpq_demux) &&
+ (mpq_dmx_info.devices[i].source == *src)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: demux%d source can't be set,\n"
+ "demux%d occupies this source already\n",
+ __func__,
+ dmx_index,
+ i);
+ return -EBUSY;
+ }
+ }
+
+ mpq_demux->source = *src;
+ return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_set_source);
+
+
+int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed)
+{
+ int ret;
+ void *packet_buffer;
+ void *payload_buffer;
+ struct mpq_video_feed_info *feed_data;
+ struct mpq_demux *mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+ struct mpq_streambuffer *stream_buffer;
+ int actual_buffer_size;
+
+ /* Allocate memory for private feed data */
+ feed_data = vmalloc(sizeof(struct mpq_video_feed_info));
+
+ if (feed_data == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to private video feed data\n",
+ __func__);
+
+ ret = -ENOMEM;
+ goto init_failed;
+ }
+
+ /* Allocate packet buffer holding the meta-data */
+ packet_buffer = vmalloc(VIDEO_META_DATA_BUFFER_SIZE);
+
+ if (packet_buffer == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to allocate packets buffer\n",
+ __func__);
+
+ ret = -ENOMEM;
+ goto init_failed_free_priv_data;
+ }
+
+ /*
+ * Allocate payload buffer through ION.
+ * TODO: for scrambling support, need to check if the
+ * stream is scrambled and allocate the buffer with secure
+ * flag set.
+ */
+
+ if (mpq_dmx_info.decoder_data_wrap)
+ actual_buffer_size =
+ feed->buffer_size;
+ else
+ actual_buffer_size =
+ feed->buffer_size + VIDEO_WRAP_AROUND_THRESHOLD;
+
+ actual_buffer_size += (SZ_4K - 1);
+ actual_buffer_size &= ~(SZ_4K - 1);
+
+ feed_data->payload_buff_handle =
+ ion_alloc(mpq_demux->ion_client,
+ actual_buffer_size,
+ SZ_4K,
+ ION_HEAP(ION_CP_MM_HEAP_ID));
+
+ if (IS_ERR_OR_NULL(feed_data->payload_buff_handle)) {
+ ret = PTR_ERR(feed_data->payload_buff_handle);
+
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to allocate payload buffer %d\n",
+ __func__,
+ ret);
+
+ goto init_failed_free_packet_buffer;
+ }
+
+ payload_buffer =
+ ion_map_kernel(mpq_demux->ion_client,
+ feed_data->payload_buff_handle,
+ 0);
+
+ if (IS_ERR_OR_NULL(payload_buffer)) {
+ ret = PTR_ERR(payload_buffer);
+
+ MPQ_DVB_ERR_PRINT(
+ "%s: FAILED to map payload buffer %d\n",
+ __func__,
+ ret);
+
+ goto init_failed_free_payload_buffer;
+ }
+
+ /* Register the new stream-buffer interface to MPQ adapter */
+ switch (feed->pes_type) {
+ case DMX_TS_PES_VIDEO0:
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO0_STREAM_IF;
+ break;
+
+ case DMX_TS_PES_VIDEO1:
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO1_STREAM_IF;
+ break;
+
+ case DMX_TS_PES_VIDEO2:
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO2_STREAM_IF;
+ break;
+
+ case DMX_TS_PES_VIDEO3:
+ feed_data->stream_interface =
+ MPQ_ADAPTER_VIDEO3_STREAM_IF;
+ break;
+
+ default:
+ MPQ_DVB_ERR_PRINT(
+ "%s: Invalid pes type %d\n",
+ __func__,
+ feed->pes_type);
+ ret = -EINVAL;
+ goto init_failed_unmap_payload_buffer;
+ }
+
+ /* make sure not occupied already */
+ stream_buffer = NULL;
+ mpq_adapter_get_stream_if(
+ feed_data->stream_interface,
+ &stream_buffer);
+ if (stream_buffer != NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Video interface %d already occupied!\n",
+ __func__,
+ feed_data->stream_interface);
+ ret = -EBUSY;
+ goto init_failed_unmap_payload_buffer;
+ }
+
+ feed_data->video_buffer =
+ &mpq_dmx_info.decoder_buffers[feed_data->stream_interface];
+
+ mpq_streambuffer_init(
+ feed_data->video_buffer,
+ payload_buffer,
+ actual_buffer_size,
+ packet_buffer,
+ VIDEO_META_DATA_BUFFER_SIZE);
+
+ ret =
+ mpq_adapter_register_stream_if(
+ feed_data->stream_interface,
+ feed_data->video_buffer);
+
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_adapter_register_stream_if failed, "
+ "err = %d\n",
+ __func__,
+ ret);
+ goto init_failed_unmap_payload_buffer;
+ }
+
+ feed->buffer_size = actual_buffer_size;
+ feed_data->pes_payload_address =
+ (u32)feed_data->video_buffer->raw_data.data;
+
+ feed_data->pes_header_left_bytes = PES_MANDATORY_FIELDS_LEN;
+ feed_data->pes_header_offset = 0;
+ feed->pusi_seen = 0;
+ feed->peslen = 0;
+ feed_data->fullness_wait_cancel = 0;
+
+ spin_lock(&mpq_demux->feed_lock);
+ feed->priv = (void *)feed_data;
+ spin_unlock(&mpq_demux->feed_lock);
+
+ return 0;
+
+init_failed_unmap_payload_buffer:
+ ion_unmap_kernel(mpq_demux->ion_client,
+ feed_data->payload_buff_handle);
+init_failed_free_payload_buffer:
+ ion_free(mpq_demux->ion_client,
+ feed_data->payload_buff_handle);
+init_failed_free_packet_buffer:
+ vfree(packet_buffer);
+init_failed_free_priv_data:
+ vfree(feed_data);
+ feed->priv = NULL;
+init_failed:
+
+ return ret;
+}
+EXPORT_SYMBOL(mpq_dmx_init_video_feed);
+
+
+int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed)
+{
+ struct mpq_video_feed_info *feed_data;
+ struct mpq_demux *mpq_demux;
+
+ if (feed->priv == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed, feed->priv is NULL\n",
+ __func__);
+
+ return -EINVAL;
+ }
+
+ mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ feed_data =
+ (struct mpq_video_feed_info *)feed->priv;
+
+ spin_lock(&mpq_demux->feed_lock);
+ feed->priv = NULL;
+ spin_unlock(&mpq_demux->feed_lock);
+
+ wake_up_all(&feed_data->video_buffer->raw_data.queue);
+
+ mpq_adapter_unregister_stream_if(
+ feed_data->stream_interface);
+
+ vfree(feed_data->video_buffer->packet_data.data);
+
+ ion_unmap_kernel(mpq_demux->ion_client,
+ feed_data->payload_buff_handle);
+
+ ion_free(mpq_demux->ion_client,
+ feed_data->payload_buff_handle);
+
+ vfree(feed_data);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_terminate_video_feed);
+
+int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed)
+{
+ struct mpq_demux *mpq_demux;
+
+ mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ if (mpq_dmx_is_video_feed(feed)) {
+ struct mpq_video_feed_info *feed_data;
+
+ spin_lock(&mpq_demux->feed_lock);
+
+ if (feed->priv == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed, feed->priv is NULL\n",
+ __func__);
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+
+ feed_data =
+ (struct mpq_video_feed_info *)feed->priv;
+
+ feed_data->fullness_wait_cancel = 0;
+
+ spin_unlock(&mpq_demux->feed_lock);
+
+ return 0;
+ }
+
+ /* else */
+ MPQ_DVB_DBG_PRINT(
+ "%s: Invalid feed type %d\n",
+ __func__,
+ feed->pes_type);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_decoder_fullness_init);
+
+int mpq_dmx_decoder_fullness_wait(
+ struct dvb_demux_feed *feed,
+ size_t required_space)
+{
+ struct mpq_demux *mpq_demux;
+
+ mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ if (mpq_dmx_is_video_feed(feed)) {
+ int ret;
+ int gap;
+ struct mpq_video_feed_info *feed_data;
+ struct dvb_ringbuffer *video_buff;
+
+ spin_lock(&mpq_demux->feed_lock);
+
+ if (feed->priv == NULL) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+
+ feed_data =
+ (struct mpq_video_feed_info *)feed->priv;
+
+ video_buff =
+ &feed_data->video_buffer->raw_data;
+
+ /*
+ * If we are now starting new PES and the
+ * PES payload may wrap-around, extra padding
+ * needs to be pushed into the buffer.
+ */
+ gap = video_buff->size - video_buff->pwrite;
+ if ((!mpq_dmx_info.decoder_data_wrap) &&
+ (gap < VIDEO_WRAP_AROUND_THRESHOLD))
+ required_space += gap;
+
+ ret = 0;
+ if ((feed_data != NULL) &&
+ (!feed_data->fullness_wait_cancel) &&
+ (dvb_ringbuffer_free(video_buff) < required_space)) {
+ DEFINE_WAIT(__wait);
+ for (;;) {
+ prepare_to_wait(
+ &video_buff->queue,
+ &__wait,
+ TASK_INTERRUPTIBLE);
+
+ if ((feed->priv == NULL) ||
+ (feed_data->fullness_wait_cancel) ||
+ (dvb_ringbuffer_free(video_buff) >=
+ required_space))
+ break;
+
+ if (!signal_pending(current)) {
+ spin_unlock(&mpq_demux->feed_lock);
+ schedule();
+ spin_lock(&mpq_demux->feed_lock);
+ continue;
+ }
+ ret = -ERESTARTSYS;
+ break;
+ }
+ finish_wait(&video_buff->queue, &__wait);
+ }
+
+ if (ret < 0) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return ret;
+ }
+
+ if ((feed->priv == NULL) ||
+ (feed_data->fullness_wait_cancel)) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ /* else */
+ MPQ_DVB_DBG_PRINT(
+ "%s: Invalid feed type %d\n",
+ __func__,
+ feed->pes_type);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_decoder_fullness_wait);
+
+int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed)
+{
+ struct mpq_demux *mpq_demux;
+
+ mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ if (mpq_dmx_is_video_feed(feed)) {
+ struct mpq_video_feed_info *feed_data;
+ struct dvb_ringbuffer *video_buff;
+
+ spin_lock(&mpq_demux->feed_lock);
+
+ if (feed->priv == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed, feed->priv is NULL\n",
+ __func__);
+ spin_unlock(&mpq_demux->feed_lock);
+ return -EINVAL;
+ }
+
+ feed_data =
+ (struct mpq_video_feed_info *)feed->priv;
+
+ video_buff =
+ &feed_data->video_buffer->raw_data;
+
+ feed_data->fullness_wait_cancel = 1;
+ spin_unlock(&mpq_demux->feed_lock);
+
+ wake_up_all(&video_buff->queue);
+
+ return 0;
+ }
+
+ /* else */
+ MPQ_DVB_ERR_PRINT(
+ "%s: Invalid feed type %d\n",
+ __func__,
+ feed->pes_type);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(mpq_dmx_decoder_fullness_abort);
+
+int mpq_dmx_process_video_packet(
+ struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ int bytes_avail;
+ int left_size;
+ int copy_len;
+ u32 ts_payload_offset;
+ struct mpq_video_feed_info *feed_data;
+ const struct ts_packet_header *ts_header;
+ struct mpq_streambuffer *stream_buffer;
+ struct pes_packet_header *pes_header;
+ struct mpq_demux *mpq_demux;
+
+ mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ spin_lock(&mpq_demux->feed_lock);
+
+ feed_data =
+ (struct mpq_video_feed_info *)feed->priv;
+
+ if (unlikely(feed_data == NULL)) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ ts_header = (const struct ts_packet_header *)buf;
+
+ stream_buffer =
+ feed_data->video_buffer;
+
+ pes_header =
+ &feed_data->pes_header;
+
+/* printk("TS packet: %X %X %X %X %X%X %X %X %X\n",
+ ts_header->sync_byte,
+ ts_header->transport_error_indicator,
+ ts_header->payload_unit_start_indicator,
+ ts_header->transport_priority,
+ ts_header->pid_msb,
+ ts_header->pid_lsb,
+ ts_header->transport_scrambling_control,
+ ts_header->adaptation_field_control,
+ ts_header->continuity_counter);*/
+
+ /* Make sure this TS packet has a payload and not scrambled */
+ if ((ts_header->sync_byte != 0x47) ||
+ (ts_header->adaptation_field_control == 0) ||
+ (ts_header->adaptation_field_control == 2) ||
+ (ts_header->transport_scrambling_control)) {
+ /* continue to next packet */
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ if (ts_header->payload_unit_start_indicator) { /* PUSI? */
+ if (feed->pusi_seen) { /* Did we see PUSI before? */
+ struct mpq_streambuffer_packet_header packet;
+ struct mpq_adapter_video_meta_data meta_data;
+
+ /*
+ * Close previous PES.
+ * Push new packet to the meta-data buffer.
+ * Double check that we are not in middle of
+ * previous PES header parsing.
+ */
+
+ if (0 == feed_data->pes_header_left_bytes) {
+ packet.raw_data_addr =
+ feed_data->pes_payload_address;
+
+ packet.raw_data_len = feed->peslen;
+
+ if ((!mpq_dmx_info.decoder_data_wrap) &&
+ ((feed_data->pes_payload_address +
+ feed->peslen) >
+ ((u32)stream_buffer->raw_data.data +
+ stream_buffer->raw_data.size)))
+ MPQ_DVB_ERR_PRINT(
+ "%s: "
+ "Video data has wrapped-around!\n",
+ __func__);
+
+ packet.user_data_len =
+ sizeof(struct
+ mpq_adapter_video_meta_data);
+
+ if ((pes_header->pts_dts_flag == 2) ||
+ (pes_header->pts_dts_flag == 3))
+ meta_data.pts_exist = 1;
+ else
+ meta_data.pts_exist = 0;
+
+ meta_data.pts =
+ ((u64)pes_header->pts_1 << 30) |
+ ((u64)pes_header->pts_2 << 22) |
+ ((u64)pes_header->pts_3 << 15) |
+ ((u64)pes_header->pts_4 << 7) |
+ (u64)pes_header->pts_5;
+
+ if (pes_header->pts_dts_flag == 3)
+ meta_data.dts_exist = 1;
+ else
+ meta_data.dts_exist = 0;
+
+ meta_data.dts =
+ ((u64)pes_header->dts_1 << 30) |
+ ((u64)pes_header->dts_2 << 22) |
+ ((u64)pes_header->dts_3 << 15) |
+ ((u64)pes_header->dts_4 << 7) |
+ (u64)pes_header->dts_5;
+
+ meta_data.is_padding = 0;
+
+ if (mpq_streambuffer_pkt_write(
+ stream_buffer,
+ &packet,
+ (u8 *)&meta_data) < 0)
+ MPQ_DVB_ERR_PRINT(
+ "%s: "
+ "Couldn't write packet. "
+ "Should never happen\n",
+ __func__);
+ } else {
+ MPQ_DVB_ERR_PRINT(
+ "%s: received PUSI"
+ "while handling PES header"
+ "of previous PES\n",
+ __func__);
+ }
+
+ /* Reset PES info */
+ feed_data->pes_payload_address =
+ (u32)stream_buffer->raw_data.data +
+ stream_buffer->raw_data.pwrite;
+
+ feed->peslen = 0;
+ feed_data->pes_header_offset = 0;
+ feed_data->pes_header_left_bytes =
+ PES_MANDATORY_FIELDS_LEN;
+ } else {
+ feed->pusi_seen = 1;
+ }
+ }
+
+ /*
+ * Parse PES data only if PUSI was encountered,
+ * otherwise the data is dropped
+ */
+ if (!feed->pusi_seen) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0; /* drop and wait for next packets */
+ }
+
+ ts_payload_offset = sizeof(struct ts_packet_header);
+
+ /* Skip adaptation field if exists */
+ if (ts_header->adaptation_field_control == 3)
+ ts_payload_offset += buf[ts_payload_offset] + 1;
+
+ bytes_avail = 188 - ts_payload_offset;
+
+ /* Got the mandatory fields of the video PES header? */
+ if (feed_data->pes_header_offset < PES_MANDATORY_FIELDS_LEN) {
+ left_size =
+ PES_MANDATORY_FIELDS_LEN -
+ feed_data->pes_header_offset;
+
+ copy_len = (left_size > bytes_avail) ?
+ bytes_avail :
+ left_size;
+
+ memcpy((u8 *)pes_header+feed_data->pes_header_offset,
+ buf+ts_payload_offset,
+ copy_len);
+
+ feed_data->pes_header_offset += copy_len;
+
+ if (left_size > bytes_avail) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ /* else - we have beginning of PES header */
+ bytes_avail -= left_size;
+ ts_payload_offset += left_size;
+
+ /* Make sure the PES packet is valid */
+ if (mpq_dmx_is_valid_video_pes(pes_header) < 0) {
+ /*
+ * Since the new PES header parsing
+ * failed, reset pusi_seen to drop all
+ * data until next PUSI
+ */
+ feed->pusi_seen = 0;
+ feed_data->pes_header_offset = 0;
+
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid packet\n",
+ __func__);
+
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ feed_data->pes_header_left_bytes =
+ pes_header->pes_header_data_length;
+ }
+
+ /* Remainning header bytes that need to be processed? */
+ if (feed_data->pes_header_left_bytes) {
+ /* Did we capture the PTS value (if exist)? */
+ if ((bytes_avail != 0) &&
+ (feed_data->pes_header_offset <
+ (PES_MANDATORY_FIELDS_LEN+5)) &&
+ ((pes_header->pts_dts_flag == 2) ||
+ (pes_header->pts_dts_flag == 3))) {
+
+ /* 5 more bytes should be there */
+ left_size =
+ PES_MANDATORY_FIELDS_LEN +
+ 5 -
+ feed_data->pes_header_offset;
+
+ copy_len = (left_size > bytes_avail) ?
+ bytes_avail :
+ left_size;
+
+ memcpy((u8 *)pes_header+
+ feed_data->pes_header_offset,
+ buf+ts_payload_offset,
+ copy_len);
+
+ feed_data->pes_header_offset += copy_len;
+ feed_data->pes_header_left_bytes -= copy_len;
+
+ if (left_size > bytes_avail) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ /* else - we have the PTS */
+ bytes_avail -= copy_len;
+ ts_payload_offset += copy_len;
+ }
+
+ /* Did we capture the DTS value (if exist)? */
+ if ((bytes_avail != 0) &&
+ (feed_data->pes_header_offset <
+ (PES_MANDATORY_FIELDS_LEN+10)) &&
+ (pes_header->pts_dts_flag == 3)) {
+
+ /* 5 more bytes should be there */
+ left_size =
+ PES_MANDATORY_FIELDS_LEN +
+ 10 -
+ feed_data->pes_header_offset;
+
+ copy_len = (left_size > bytes_avail) ?
+ bytes_avail :
+ left_size;
+
+ memcpy((u8 *)pes_header+
+ feed_data->pes_header_offset,
+ buf+ts_payload_offset,
+ copy_len);
+
+ feed_data->pes_header_offset += copy_len;
+ feed_data->pes_header_left_bytes -= copy_len;
+
+ if (left_size > bytes_avail) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ /* else - we have the DTS */
+ bytes_avail -= copy_len;
+ ts_payload_offset += copy_len;
+ }
+
+ /* Any more header bytes?! */
+ if (feed_data->pes_header_left_bytes >= bytes_avail) {
+ feed_data->pes_header_left_bytes -= bytes_avail;
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ /* Got PES header, process payload */
+ bytes_avail -= feed_data->pes_header_left_bytes;
+ ts_payload_offset += feed_data->pes_header_left_bytes;
+ feed_data->pes_header_left_bytes = 0;
+ }
+
+ /*
+ * If we reached here,
+ * then we are now at the PES payload data
+ */
+ if (bytes_avail == 0) {
+ spin_unlock(&mpq_demux->feed_lock);
+ return 0;
+ }
+
+ if (feed->peslen == 0) { /* starting new PES */
+ /* gap till end of the buffer */
+ int gap =
+ stream_buffer->raw_data.size -
+ stream_buffer->raw_data.pwrite;
+
+ if ((!mpq_dmx_info.decoder_data_wrap) &&
+ (gap < VIDEO_WRAP_AROUND_THRESHOLD)) {
+ struct mpq_streambuffer_packet_header packet;
+ struct mpq_adapter_video_meta_data meta_data;
+
+ /*
+ * Do not start writting new PES from
+ * this location to prevent possible
+ * wrap-around of the payload, fill padding instead.
+ */
+
+ /* push a packet with padding indication */
+ meta_data.is_padding = 1;
+
+ packet.raw_data_len = gap;
+ packet.user_data_len =
+ sizeof(struct mpq_adapter_video_meta_data);
+ packet.raw_data_addr =
+ feed_data->pes_payload_address;
+
+ if (mpq_streambuffer_data_write_deposit(
+ stream_buffer,
+ gap) < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_streambuffer_data_write_deposit "
+ "failed!\n",
+ __func__);
+ } else if (mpq_streambuffer_pkt_write(
+ stream_buffer,
+ &packet,
+ (u8 *)&meta_data) < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: "
+ "Couldn't write packet. "
+ "Should never happen\n",
+ __func__);
+ } else {
+ feed_data->pes_payload_address =
+ (u32)stream_buffer->raw_data.data +
+ stream_buffer->raw_data.pwrite;
+ }
+ }
+ }
+
+ if (mpq_streambuffer_data_write(
+ stream_buffer,
+ buf+ts_payload_offset,
+ bytes_avail) < 0)
+ mpq_demux->decoder_tsp_drop_count++;
+ else
+ feed->peslen += bytes_avail;
+
+ spin_unlock(&mpq_demux->feed_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_process_video_packet);
+
+
+int mpq_dmx_process_pcr_packet(
+ struct dvb_demux_feed *feed,
+ const u8 *buf)
+{
+ int i;
+ u64 pcr;
+ u64 stc;
+ u8 output[PCR_STC_LEN];
+ struct mpq_demux *mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+ const struct ts_packet_header *ts_header;
+ const struct ts_adaptation_field *adaptation_field;
+
+ /*
+ * When we play from front-end, we configure HW
+ * to output the extra timestamp, if we are playing
+ * from DVR, make sure the format is 192 packet.
+ */
+ if ((mpq_demux->source >= DMX_SOURCE_DVR0) &&
+ (mpq_demux->demux.tsp_format != DMX_TSP_FORMAT_192_TAIL)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid packet format %d for PCR extraction\n",
+ __func__,
+ mpq_demux->demux.tsp_format);
+
+ return -EINVAL;
+ }
+
+ ts_header = (const struct ts_packet_header *)buf;
+
+ /* Make sure this TS packet has a adaptation field */
+ if ((ts_header->sync_byte != 0x47) ||
+ (ts_header->adaptation_field_control == 0) ||
+ (ts_header->adaptation_field_control == 1)) {
+ return 0;
+ }
+
+ adaptation_field = (const struct ts_adaptation_field *)
+ (buf + sizeof(struct ts_packet_header));
+
+ if ((!adaptation_field->adaptation_field_length) ||
+ (!adaptation_field->PCR_flag))
+ return 0; /* 0 adaptation field or no PCR */
+
+ pcr = ((u64)adaptation_field->program_clock_reference_base_1) << 25;
+ pcr += ((u64)adaptation_field->program_clock_reference_base_2) << 17;
+ pcr += ((u64)adaptation_field->program_clock_reference_base_3) << 9;
+ pcr += ((u64)adaptation_field->program_clock_reference_base_4) << 1;
+ pcr += adaptation_field->program_clock_reference_base_5;
+ pcr *= 300;
+ pcr +=
+ (((u64)adaptation_field->program_clock_reference_ext_1) << 8) +
+ adaptation_field->program_clock_reference_ext_2;
+
+ stc = buf[189] << 16;
+ stc += buf[190] << 8;
+ stc += buf[191];
+ stc *= 256; /* convert from 105.47 KHZ to 27MHz */
+
+ output[0] = adaptation_field->discontinuity_indicator;
+
+ for (i = 1; i <= 8; i++)
+ output[i] = (stc >> ((8-i) << 3)) & 0xFF;
+
+ for (i = 9; i <= 16; i++)
+ output[i] = (pcr >> ((16-i) << 3)) & 0xFF;
+
+ feed->cb.ts(output, PCR_STC_LEN,
+ NULL, 0,
+ &feed->feed.ts, DMX_OK);
+ return 0;
+}
+EXPORT_SYMBOL(mpq_dmx_process_pcr_packet);
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
new file mode 100644
index 0000000..d90bd89
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_common.h
@@ -0,0 +1,494 @@
+/* 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 _MPQ_DMX_PLUGIN_COMMON_H
+#define _MPQ_DMX_PLUGIN_COMMON_H
+
+#include <linux/ion.h>
+
+#include "dvbdev.h"
+#include "dmxdev.h"
+#include "demux.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "mpq_adapter.h"
+
+
+/**
+ * Total number of filters per demux,
+ * including section and PES feeds
+ */
+#define MPQ_DMX_MAX_NUM_OF_FILTERS 64
+
+/**
+ * TSIF alias name length
+ */
+#define TSIF_NAME_LENGTH 10
+
+/**
+ * struct mpq_demux - mpq demux information
+ * @demux: The dvb_demux instance used by mpq_demux
+ * @dmxdev: The dmxdev instance used by mpq_demux
+ * @fe_memory: Handle of front-end memory source to mpq_demux
+ * @source: The current source connected to the demux
+ * @is_initialized: Indicates whether this demux device was
+ * initialized or not.
+ * @ion_client: ION demux client used to allocate memory from ION.
+ * @feed_lock: Lock used to protect against private feed data
+ * @hw_notification_rate: Notification rate in msec, exposed in debugfs.
+ * @hw_notification_count: Notification count, exposed in debugfs.
+ * @hw_notification_size: Notification size in bytes, exposed in debugfs.
+ * @decoder_tsp_drop_count: Counter of number of dropped TS packets
+ * due to decoder buffer fullness, exposed in debugfs.
+ * @last_notification_time: Time of last HW notification.
+ */
+struct mpq_demux {
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_memory;
+ dmx_source_t source;
+ int is_initialized;
+ struct ion_client *ion_client;
+ spinlock_t feed_lock;
+
+ /* debug-fs */
+ u32 hw_notification_rate;
+ u32 hw_notification_count;
+ u32 hw_notification_size;
+ u32 decoder_tsp_drop_count;
+ struct timespec last_notification_time;
+};
+
+/**
+ * mpq_dmx_init - initialization and registration function of
+ * single MPQ demux device
+ *
+ * @adapter: The adapter to register mpq_demux to
+ * @mpq_demux: The mpq demux to initialize
+ *
+ * Every HW pluging need to provide implementation of such
+ * function that will be called for each demux device on the
+ * module initialization. The function mpq_demux_plugin_init
+ * should be called during the HW plugin module initialization.
+ */
+typedef int (*mpq_dmx_init)(
+ struct dvb_adapter *mpq_adapter,
+ struct mpq_demux *demux);
+
+/**
+ * struct ts_packet_header - Transport packet header
+ * as defined in MPEG2 transport stream standard.
+ */
+struct ts_packet_header {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ unsigned sync_byte:8;
+ unsigned transport_error_indicator:1;
+ unsigned payload_unit_start_indicator:1;
+ unsigned transport_priority:1;
+ unsigned pid_msb:5;
+ unsigned pid_lsb:8;
+ unsigned transport_scrambling_control:2;
+ unsigned adaptation_field_control:2;
+ unsigned continuity_counter:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned sync_byte:8;
+ unsigned pid_msb:5;
+ unsigned transport_priority:1;
+ unsigned payload_unit_start_indicator:1;
+ unsigned transport_error_indicator:1;
+ unsigned pid_lsb:8;
+ unsigned continuity_counter:4;
+ unsigned adaptation_field_control:2;
+ unsigned transport_scrambling_control:2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+/**
+ * struct ts_adaptation_field - Adaptation field prefix
+ * as defined in MPEG2 transport stream standard.
+ */
+struct ts_adaptation_field {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ unsigned adaptation_field_length:8;
+ unsigned discontinuity_indicator:1;
+ unsigned random_access_indicator:1;
+ unsigned elementary_stream_priority_indicator:1;
+ unsigned PCR_flag:1;
+ unsigned OPCR_flag:1;
+ unsigned splicing_point_flag:1;
+ unsigned transport_private_data_flag:1;
+ unsigned adaptation_field_extension_flag:1;
+ unsigned program_clock_reference_base_1:8;
+ unsigned program_clock_reference_base_2:8;
+ unsigned program_clock_reference_base_3:8;
+ unsigned program_clock_reference_base_4:8;
+ unsigned program_clock_reference_base_5:1;
+ unsigned reserved:6;
+ unsigned program_clock_reference_ext_1:1;
+ unsigned program_clock_reference_ext_2:8;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned adaptation_field_length:8;
+ unsigned adaptation_field_extension_flag:1;
+ unsigned transport_private_data_flag:1;
+ unsigned splicing_point_flag:1;
+ unsigned OPCR_flag:1;
+ unsigned PCR_flag:1;
+ unsigned elementary_stream_priority_indicator:1;
+ unsigned random_access_indicator:1;
+ unsigned discontinuity_indicator:1;
+ unsigned program_clock_reference_base_1:8;
+ unsigned program_clock_reference_base_2:8;
+ unsigned program_clock_reference_base_3:8;
+ unsigned program_clock_reference_base_4:8;
+ unsigned program_clock_reference_ext_1:1;
+ unsigned reserved:6;
+ unsigned program_clock_reference_base_5:1;
+ unsigned program_clock_reference_ext_2:8;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+
+/*
+ * PES packet header containing dts and/or pts values
+ * as defined in MPEG2 transport stream standard.
+ */
+struct pes_packet_header {
+#if defined(__BIG_ENDIAN_BITFIELD)
+ unsigned packet_start_code_prefix_1:8;
+ unsigned packet_start_code_prefix_2:8;
+ unsigned packet_start_code_prefix_3:8;
+ unsigned stream_id:8;
+ unsigned pes_packet_length_msb:8;
+ unsigned pes_packet_length_lsb:8;
+ unsigned reserved_bits0:2;
+ unsigned pes_scrambling_control:2;
+ unsigned pes_priority:1;
+ unsigned data_alignment_indicator:1;
+ unsigned copyright:1;
+ unsigned original_or_copy:1;
+ unsigned pts_dts_flag:2;
+ unsigned escr_flag:1;
+ unsigned es_rate_flag:1;
+ unsigned dsm_trick_mode_flag:1;
+ unsigned additional_copy_info_flag:1;
+ unsigned pes_crc_flag:1;
+ unsigned pes_extension_flag:1;
+ unsigned pes_header_data_length:8;
+ unsigned reserved_bits1:4;
+ unsigned pts_1:3;
+ unsigned marker_bit0:1;
+ unsigned pts_2:8;
+ unsigned pts_3:7;
+ unsigned marker_bit1:1;
+ unsigned pts_4:8;
+ unsigned pts_5:7;
+ unsigned marker_bit2:1;
+ unsigned reserved_bits2:4;
+ unsigned dts_1:3;
+ unsigned marker_bit3:1;
+ unsigned dts_2:8;
+ unsigned dts_3:7;
+ unsigned marker_bit4:1;
+ unsigned dts_4:8;
+ unsigned dts_5:7;
+ unsigned marker_bit5:1;
+ unsigned reserved_bits3:4;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+ unsigned packet_start_code_prefix_1:8;
+ unsigned packet_start_code_prefix_2:8;
+ unsigned packet_start_code_prefix_3:8;
+ unsigned stream_id:8;
+ unsigned pes_packet_length_lsb:8;
+ unsigned pes_packet_length_msb:8;
+ unsigned original_or_copy:1;
+ unsigned copyright:1;
+ unsigned data_alignment_indicator:1;
+ unsigned pes_priority:1;
+ unsigned pes_scrambling_control:2;
+ unsigned reserved_bits0:2;
+ unsigned pes_extension_flag:1;
+ unsigned pes_crc_flag:1;
+ unsigned additional_copy_info_flag:1;
+ unsigned dsm_trick_mode_flag:1;
+ unsigned es_rate_flag:1;
+ unsigned escr_flag:1;
+ unsigned pts_dts_flag:2;
+ unsigned pes_header_data_length:8;
+ unsigned marker_bit0:1;
+ unsigned pts_1:3;
+ unsigned reserved_bits1:4;
+ unsigned pts_2:8;
+ unsigned marker_bit1:1;
+ unsigned pts_3:7;
+ unsigned pts_4:8;
+ unsigned marker_bit2:1;
+ unsigned pts_5:7;
+ unsigned marker_bit3:1;
+ unsigned dts_1:3;
+ unsigned reserved_bits2:4;
+ unsigned dts_2:8;
+ unsigned marker_bit4:1;
+ unsigned dts_3:7;
+ unsigned dts_4:8;
+ unsigned marker_bit5:1;
+ unsigned dts_5:7;
+ unsigned reserved_bits3:4;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} __packed;
+
+/*
+ * mpq_video_feed_info - private data used for video feed.
+ *
+ * @plugin_data: Underlying plugin's own private data.
+ * @video_buffer: Holds the streamer buffer shared with
+ * the decoder for feeds having the data going to the decoder.
+ * @pes_header: Used for feeds that output data to decoder,
+ * holds PES header of current processed PES.
+ * @pes_header_left_bytes: Used for feeds that output data to decoder,
+ * holds remainning PES header bytes of current processed PES.
+ * @pes_header_offset: Holds the offset within the current processed
+ * pes header.
+ * @fullness_wait_cancel: Flag used to signal to abort waiting for
+ * decoder's fullness.
+ * @pes_payload_address: Used for feeds that output data to decoder,
+ * holds current PES payload start address.
+ * @payload_buff_handle: ION handle for the allocated payload buffer
+ * @stream_interface: The ID of the video stream interface registered
+ * with this stream buffer.
+ */
+struct mpq_video_feed_info {
+ void *plugin_data;
+ struct mpq_streambuffer *video_buffer;
+ struct pes_packet_header pes_header;
+ u32 pes_header_left_bytes;
+ u32 pes_header_offset;
+ u32 pes_payload_address;
+ int fullness_wait_cancel;
+ struct ion_handle *payload_buff_handle;
+ enum mpq_adapter_stream_if stream_interface;
+};
+
+/**
+ * mpq_demux_plugin_init - Initialize demux devices and register
+ * them to the dvb adapter.
+ *
+ * @dmx_init_func: Pointer to the function to be used
+ * to initialize demux of the udnerlying HW plugin.
+ *
+ * Return error code
+ *
+ * Should be called at the HW plugin module initialization.
+ */
+int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func);
+
+/**
+ * mpq_demux_plugin_exit - terminate demux devices.
+ *
+ * Should be called at the HW plugin module termination.
+ */
+void mpq_dmx_plugin_exit(void);
+
+/**
+ * mpq_dmx_set_source - implmenetation of set_source routine.
+ *
+ * @demux: The demux device to set its source.
+ * @src: The source to be set.
+ *
+ * Return error code
+ *
+ * Can be used by the underlying plugins to implement kernel
+ * demux API set_source routine.
+ */
+int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src);
+
+/**
+ * mpq_dmx_init_video_feed - Initializes video feed
+ * used to pass data to decoder directly.
+ *
+ * @feed: The feed used for the video TS packets
+ *
+ * Return error code.
+ *
+ * If the underlying plugin wishes to perform SW PES assmebly
+ * for the video data and stream it to the decoder, it should
+ * call this function when video feed is initialized before
+ * using mpq_dmx_process_video_packet.
+ *
+ * The function allocates mpq_video_feed_info and saves in
+ * feed->priv.
+ */
+int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_terminate_video_feed - Free private data of
+ * video feed allocated in mpq_dmx_init_video_feed
+ *
+ * @feed: The feed used for the video TS packets
+ *
+ * Return error code.
+ */
+int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_decoder_fullness_init - Initialize waiting
+ * mechanism on decoder's buffer fullness.
+ *
+ * @feed: The decoder's feed
+ *
+ * Return error code.
+ */
+int mpq_dmx_decoder_fullness_init(
+ struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer
+ * have free space as required, if not, wait for it.
+ *
+ * @feed: The decoder's feed
+ * @required_space: the required free space to wait for
+ *
+ * Return error code.
+ */
+int mpq_dmx_decoder_fullness_wait(
+ struct dvb_demux_feed *feed,
+ size_t required_space);
+
+/**
+ * mpq_dmx_decoder_fullness_abort - Aborts waiting
+ * on decoder's buffer fullness if any waiting is done
+ * now. After calling this, to wait again the user must
+ * call mpq_dmx_decoder_fullness_init.
+ *
+ * @feed: The decoder's feed
+ *
+ * Return error code.
+ */
+int mpq_dmx_decoder_fullness_abort(
+ struct dvb_demux_feed *feed);
+
+/**
+ * mpq_dmx_process_video_packet - Assemble PES data and output it
+ * to the stream-buffer connected to the decoder.
+ *
+ * @feed: The feed used for the video TS packets
+ * @buf: The buffer holding video TS packet.
+ *
+ * Return error code.
+ *
+ * The function assumes it receives buffer with single TS packet
+ * of the relevant PID.
+ * If the output buffer is full while assembly, the function drops
+ * the packet and does not write them to the output buffer.
+ * Scrambled packets are bypassed.
+ */
+int mpq_dmx_process_video_packet(
+ struct dvb_demux_feed *feed,
+ const u8 *buf);
+
+/**
+ * mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from
+ * a 192 bytes packet.
+ *
+ * @feed: The feed used for the PCR TS packets
+ * @buf: The buffer holding pcr/stc packet.
+ *
+ * Return error code.
+ *
+ * The function assumes it receives buffer with single TS packet
+ * of the relevant PID, and that it has 4 bytes
+ * suffix as extra timestamp in the following format:
+ *
+ * Byte3: TSIF flags
+ * Byte0-2: TTS, 0..2^24-1 at 105.47 Khz (27*10^6/256).
+ *
+ * The function callbacks dmxdev after extraction of the pcr/stc
+ * pair.
+ */
+int mpq_dmx_process_pcr_packet(
+ struct dvb_demux_feed *feed,
+ const u8 *buf);
+
+/**
+ * mpq_dmx_is_video_feed - Returns whether the PES feed
+ * is video one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is video feed, 0 otherwise.
+ */
+static inline int mpq_dmx_is_video_feed(struct dvb_demux_feed *feed)
+{
+ if (feed->type != DMX_TYPE_TS)
+ return 0;
+
+ if (feed->ts_type & (~TS_DECODER))
+ return 0;
+
+ if ((feed->pes_type == DMX_TS_PES_VIDEO0) ||
+ (feed->pes_type == DMX_TS_PES_VIDEO1) ||
+ (feed->pes_type == DMX_TS_PES_VIDEO2) ||
+ (feed->pes_type == DMX_TS_PES_VIDEO3))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * mpq_dmx_is_pcr_feed - Returns whether the PES feed
+ * is PCR one.
+ *
+ * @feed: The feed to be checked.
+ *
+ * Return 1 if feed is PCR feed, 0 otherwise.
+ */
+static inline int mpq_dmx_is_pcr_feed(struct dvb_demux_feed *feed)
+{
+ if (feed->type != DMX_TYPE_TS)
+ return 0;
+
+ if (feed->ts_type & (~TS_DECODER))
+ return 0;
+
+ if ((feed->pes_type == DMX_TS_PES_PCR0) ||
+ (feed->pes_type == DMX_TS_PES_PCR1) ||
+ (feed->pes_type == DMX_TS_PES_PCR2) ||
+ (feed->pes_type == DMX_TS_PES_PCR3))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * mpq_dmx_init_hw_statistics -
+ * Extend dvb-demux debugfs with HW statistics.
+ *
+ * @mpq_demux: The mpq_demux device to initialize.
+ */
+void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux);
+
+
+/**
+ * mpq_dmx_update_hw_statistics -
+ * Update dvb-demux debugfs with HW notification statistics.
+ *
+ * @mpq_demux: The mpq_demux device to update.
+ */
+void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux);
+
+#endif /* _MPQ_DMX_PLUGIN_COMMON_H */
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
new file mode 100644
index 0000000..5894a65
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tsif.c
@@ -0,0 +1,747 @@
+/* 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/tsif_api.h>
+#include <linux/workqueue.h>
+#include <linux/moduleparam.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+/* TSIF HW configuration: */
+#define TSIF_COUNT 2
+/* When TSIF driver notifies demux that new packets are received */
+#define DMX_TSIF_PACKETS_IN_CHUNK_DEF 16
+#define DMX_TSIF_CHUNKS_IN_BUF 8
+#define DMX_TSIF_TIME_LIMIT 10000
+/* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 1 normally. */
+#define DMX_TSIF_DRIVER_MODE_DEF 1
+
+
+/* module parameters for load time configuration: */
+static int threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
+static int mode = DMX_TSIF_DRIVER_MODE_DEF;
+module_param(threshold, int, S_IRUGO);
+module_param(mode, int, S_IRUGO);
+
+/*
+ * Work scheduled each time TSIF notifies dmx
+ * of new TS packet
+ */
+struct tsif_work {
+ struct work_struct work;
+ int tsif_id;
+};
+
+
+/*
+ * TSIF driver information
+ */
+struct tsif_driver_info {
+ /* handler to TSIF driver */
+ void *tsif_handler;
+ /* TSIF driver data buffer pointer */
+ void *data_buffer;
+ /* TSIF driver data buffer size, in packets */
+ int buffer_size;
+ /* TSIF driver read pointer */
+ int ri;
+ /* TSIF driver write pointer */
+ int wi;
+ /* TSIF driver state */
+ enum tsif_state state;
+};
+
+
+/*
+ * The following structure hold singelton information
+ * required for dmx implementation on top of TSIF.
+ */
+static struct
+{
+ /* Information for each TSIF input processing */
+ struct {
+ /* work used to submit to workqueue for processing */
+ struct tsif_work work;
+
+ /* workqueue that processes TS packets from specific TSIF */
+ struct workqueue_struct *workqueue;
+
+ /* TSIF alias */
+ char name[TSIF_NAME_LENGTH];
+
+ /* TSIF driver information */
+ struct tsif_driver_info tsif_driver;
+
+ /* TSIF reference count (counts start/stop operations */
+ int ref_count;
+
+ /* Pointer to the demux connected to this TSIF */
+ struct mpq_demux *mpq_demux;
+
+ /* mutex protecting the data-structure */
+ struct mutex mutex;
+ } tsif[TSIF_COUNT];
+} mpq_dmx_tsif_info;
+
+
+/**
+ * Worker function that processes the TS packets notified by the TSIF driver.
+ *
+ * @worker: the executed work
+ */
+static void mpq_dmx_tsif_work(struct work_struct *worker)
+{
+ struct tsif_work *tsif_work =
+ container_of(worker, struct tsif_work, work);
+ struct mpq_demux *mpq_demux;
+ struct tsif_driver_info *tsif_driver;
+ size_t packets = 0;
+ int tsif = tsif_work->tsif_id;
+
+ mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
+ tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+
+ MPQ_DVB_DBG_PRINT(
+ "%s executed, tsif = %d\n",
+ __func__,
+ tsif);
+
+ if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
+ return;
+
+ /* Check if driver handler is still valid */
+ if (tsif_driver->tsif_handler == NULL) {
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ MPQ_DVB_ERR_PRINT("%s: tsif_driver->tsif_handler is NULL!\n",
+ __func__);
+ return;
+ }
+
+ tsif_get_state(tsif_driver->tsif_handler, &(tsif_driver->ri),
+ &(tsif_driver->wi), &(tsif_driver->state));
+
+ if ((tsif_driver->wi == tsif_driver->ri) ||
+ (tsif_driver->state == tsif_state_stopped) ||
+ (tsif_driver->state == tsif_state_error)) {
+
+ mpq_demux->hw_notification_size = 0;
+
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid TSIF state (%d), wi = (%d), ri = (%d)\n",
+ __func__,
+ tsif_driver->state, tsif_driver->wi, tsif_driver->ri);
+ return;
+ }
+
+ if (tsif_driver->wi > tsif_driver->ri) {
+ packets = (tsif_driver->wi - tsif_driver->ri);
+ mpq_demux->hw_notification_size = packets;
+
+ dvb_dmx_swfilter_format(
+ &mpq_demux->demux,
+ (tsif_driver->data_buffer +
+ (tsif_driver->ri * TSIF_PKT_SIZE)),
+ (packets * TSIF_PKT_SIZE),
+ DMX_TSP_FORMAT_192_TAIL);
+
+ tsif_driver->ri =
+ (tsif_driver->ri + packets) % tsif_driver->buffer_size;
+
+ tsif_reclaim_packets(tsif_driver->tsif_handler,
+ tsif_driver->ri);
+ } else {
+ /*
+ * wi < ri, means wraparound on cyclic buffer.
+ * Handle in two stages.
+ */
+ packets = (tsif_driver->buffer_size - tsif_driver->ri);
+ mpq_demux->hw_notification_size = packets;
+
+ dvb_dmx_swfilter_format(
+ &mpq_demux->demux,
+ (tsif_driver->data_buffer +
+ (tsif_driver->ri * TSIF_PKT_SIZE)),
+ (packets * TSIF_PKT_SIZE),
+ DMX_TSP_FORMAT_192_TAIL);
+
+ /* tsif_driver->ri should be 0 after this */
+ tsif_driver->ri =
+ (tsif_driver->ri + packets) % tsif_driver->buffer_size;
+
+ packets = tsif_driver->wi;
+ if (packets > 0) {
+ mpq_demux->hw_notification_size += packets;
+
+ dvb_dmx_swfilter_format(
+ &mpq_demux->demux,
+ (tsif_driver->data_buffer +
+ (tsif_driver->ri * TSIF_PKT_SIZE)),
+ (packets * TSIF_PKT_SIZE),
+ DMX_TSP_FORMAT_192_TAIL);
+
+ tsif_driver->ri =
+ (tsif_driver->ri + packets) %
+ tsif_driver->buffer_size;
+ }
+
+ tsif_reclaim_packets(tsif_driver->tsif_handler,
+ tsif_driver->ri);
+ }
+
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+}
+
+
+/**
+ * Callback function from TSIF driver when new data is ready.
+ *
+ * @user: user-data holding TSIF number
+ */
+static void mpq_tsif_callback(void *user)
+{
+ int tsif = (int)user;
+ struct work_struct *work;
+ struct mpq_demux *mpq_demux;
+
+ MPQ_DVB_DBG_PRINT("%s executed, tsif = %d\n", __func__, tsif);
+
+ /* Save statistics on TSIF notifications */
+ mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
+ mpq_dmx_update_hw_statistics(mpq_demux);
+
+ work = &mpq_dmx_tsif_info.tsif[tsif].work.work;
+
+ /* Scheudle a new work to demux workqueue */
+ if (!work_pending(work))
+ queue_work(mpq_dmx_tsif_info.tsif[tsif].workqueue, work);
+}
+
+
+/**
+ * Attach to TSIF driver and start TSIF operation.
+ *
+ * @mpq_demux: the mpq_demux we are working on.
+ *
+ * Return error code.
+ */
+static int mpq_tsif_dmx_start(struct mpq_demux *mpq_demux)
+{
+ int ret = 0;
+ int tsif;
+ struct tsif_driver_info *tsif_driver;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /* determine the TSIF we are reading from */
+ if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+ tsif = 0;
+ } else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+ tsif = 1;
+ } else {
+ /* invalid source */
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid input source (%d)\n",
+ __func__,
+ mpq_demux->source);
+
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
+ return -ERESTARTSYS;
+
+ if (mpq_dmx_tsif_info.tsif[tsif].ref_count == 0) {
+ tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+
+ /* Attach to TSIF driver */
+
+ tsif_driver->tsif_handler =
+ tsif_attach(tsif, mpq_tsif_callback, (void *)tsif);
+ if (IS_ERR_OR_NULL(tsif_driver->tsif_handler)) {
+ tsif_driver->tsif_handler = NULL;
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ MPQ_DVB_DBG_PRINT("%s: tsif_attach(%d) failed\n",
+ __func__, tsif);
+ return -ENODEV;
+ }
+
+ /* Set TSIF driver mode */
+ ret = tsif_set_mode(tsif_driver->tsif_handler,
+ mode);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT("%s: tsif_set_mode (%d) failed\n",
+ __func__, mode);
+ }
+
+ /* Set TSIF buffer configuration */
+ ret = tsif_set_buf_config(tsif_driver->tsif_handler,
+ threshold,
+ DMX_TSIF_CHUNKS_IN_BUF);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tsif_set_buf_config (%d, %d) failed\n",
+ __func__, threshold,
+ DMX_TSIF_CHUNKS_IN_BUF);
+ MPQ_DVB_ERR_PRINT("Using default TSIF driver values\n");
+ }
+
+
+ /* Set TSIF driver time limit */
+ /* TODO: needed?? */
+/* ret = tsif_set_time_limit(tsif_driver->tsif_handler,
+ DMX_TSIF_TIME_LIMIT);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tsif_set_time_limit (%d) failed\n",
+ __func__, DMX_TSIF_TIME_LIMIT);
+ }
+*/
+
+ /* Start TSIF driver */
+ ret = tsif_start(tsif_driver->tsif_handler);
+ if (ret < 0) {
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ MPQ_DVB_ERR_PRINT("%s: tsif_start failed\n", __func__);
+ return ret;
+ }
+
+ /*
+ * Get data buffer information from TSIF driver
+ * (must be called after tsif_start)
+ */
+ tsif_get_info(tsif_driver->tsif_handler,
+ &(tsif_driver->data_buffer),
+ &(tsif_driver->buffer_size));
+
+ /* save pointer to the mpq_demux we are working on */
+ mpq_dmx_tsif_info.tsif[tsif].mpq_demux = mpq_demux;
+ }
+ mpq_dmx_tsif_info.tsif[tsif].ref_count++;
+
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+
+ return ret;
+}
+
+
+/**
+ * Stop TSIF operation and detach from TSIF driver.
+ *
+ * @mpq_demux: the mpq_demux we are working on.
+ *
+ * Return error code.
+ */
+static int mpq_tsif_dmx_stop(struct mpq_demux *mpq_demux)
+{
+ int tsif;
+ struct tsif_driver_info *tsif_driver;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /* determine the TSIF we are reading from */
+ if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+ tsif = 0;
+ } else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+ tsif = 1;
+ } else {
+ /* invalid source */
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid input source (%d)\n",
+ __func__,
+ mpq_demux->source);
+
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
+ return -ERESTARTSYS;
+
+ mpq_dmx_tsif_info.tsif[tsif].ref_count--;
+
+ if (mpq_dmx_tsif_info.tsif[tsif].ref_count == 0) {
+ tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
+ tsif_stop(tsif_driver->tsif_handler);
+ tsif_detach(tsif_driver->tsif_handler);
+ /*
+ * temporarily release mutex and flush the work queue
+ * before setting tsif_handler to NULL
+ */
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+ flush_workqueue(mpq_dmx_tsif_info.tsif[tsif].workqueue);
+ /* re-acquire mutex */
+ if (mutex_lock_interruptible(
+ &mpq_dmx_tsif_info.tsif[tsif].mutex))
+ return -ERESTARTSYS;
+
+ tsif_driver->tsif_handler = NULL;
+ tsif_driver->data_buffer = NULL;
+ tsif_driver->buffer_size = 0;
+ mpq_dmx_tsif_info.tsif[tsif].mpq_demux = NULL;
+ }
+
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
+
+ return 0;
+}
+
+
+/**
+ * Start filtering according to feed parameter.
+ *
+ * @feed: the feed we are working on.
+ *
+ * Return error code.
+ */
+static int mpq_tsif_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+ int ret = 0;
+ struct mpq_demux *mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s(%d) executed\n",
+ __func__,
+ feed->pid);
+
+ if (mpq_demux == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid mpq_demux handle\n",
+ __func__);
+
+ return -EINVAL;
+ }
+
+ if (mpq_demux->source < DMX_SOURCE_DVR0) {
+ /* Source from TSIF, need to configure TSIF hardware */
+ ret = mpq_tsif_dmx_start(mpq_demux);
+
+ if (ret < 0) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_tsif_dmx_start failed(%d)\n",
+ __func__,
+ ret);
+ return ret;
+ }
+ }
+
+ /* Always feed sections/PES starting from a new one and
+ * do not partial transfer data from older one
+ */
+ feed->pusi_seen = 0;
+
+ /*
+ * For video PES, data is tunneled to the decoder,
+ * initialize tunneling and pes parsing.
+ */
+ if (mpq_dmx_is_video_feed(feed)) {
+ ret = mpq_dmx_init_video_feed(feed);
+
+ if (ret < 0) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_dmx_init_video_feed failed(%d)\n",
+ __func__,
+ ret);
+
+ if (mpq_demux->source < DMX_SOURCE_DVR0)
+ mpq_tsif_dmx_stop(mpq_demux);
+
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+
+/**
+ * Stop filtering according to feed parameter.
+ *
+ * @feed: the feed we are working on.
+ *
+ * Return error code.
+ */
+static int mpq_tsif_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+ int ret = 0;
+ struct mpq_demux *mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s(%d) executed\n",
+ __func__,
+ feed->pid);
+
+ if (mpq_demux == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid mpq_demux handle\n",
+ __func__);
+
+ return -EINVAL;
+ }
+
+ /*
+ * For video PES, data is tunneled to the decoder,
+ * terminate tunnel and pes parsing.
+ */
+ if (mpq_dmx_is_video_feed(feed))
+ mpq_dmx_terminate_video_feed(feed);
+
+ if (mpq_demux->source < DMX_SOURCE_DVR0) {
+ /* Source from TSIF, need to configure TSIF hardware */
+ ret = mpq_tsif_dmx_stop(mpq_demux);
+ }
+
+ return ret;
+}
+
+
+/**
+ * TSIF demux plugin write-to-decoder function.
+ *
+ * @feed: The feed we are working on.
+ * @buf: The data buffer to process.
+ * @len: The data buffer length.
+ *
+ * Return error code
+ */
+static int mpq_tsif_dmx_write_to_decoder(
+ struct dvb_demux_feed *feed,
+ const u8 *buf,
+ size_t len)
+{
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /*
+ * It is assumed that this function is called once for each
+ * TS packet of the relevant feed.
+ */
+ if (len > TSIF_PKT_SIZE)
+ MPQ_DVB_DBG_PRINT(
+ "%s: warnning - len larger than one packet\n",
+ __func__);
+
+ if (mpq_dmx_is_video_feed(feed))
+ return mpq_dmx_process_video_packet(feed, buf);
+
+ if (mpq_dmx_is_pcr_feed(feed))
+ return mpq_dmx_process_pcr_packet(feed, buf);
+
+ return 0;
+}
+
+
+/**
+ * Initialize a single demux device.
+ *
+ * @mpq_adapter: MPQ DVB adapter
+ * @mpq_demux: The demux device to initialize
+ *
+ * Return error code
+ */
+static int mpq_tsif_dmx_init(
+ struct dvb_adapter *mpq_adapter,
+ struct mpq_demux *mpq_demux)
+{
+ int result;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /* Set the kernel-demux object capabilities */
+ mpq_demux->demux.dmx.capabilities =
+ DMX_TS_FILTERING |
+ DMX_PES_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING |
+ DMX_CRC_CHECKING |
+ DMX_TS_DESCRAMBLING;
+
+ /* Set dvb-demux "virtual" function pointers */
+ mpq_demux->demux.priv = (void *)mpq_demux;
+ mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->demux.start_feed = mpq_tsif_dmx_start_filtering;
+ mpq_demux->demux.stop_feed = mpq_tsif_dmx_stop_filtering;
+ mpq_demux->demux.write_to_decoder = mpq_tsif_dmx_write_to_decoder;
+
+ mpq_demux->demux.decoder_fullness_init =
+ mpq_dmx_decoder_fullness_init;
+
+ mpq_demux->demux.decoder_fullness_wait =
+ mpq_dmx_decoder_fullness_wait;
+
+ mpq_demux->demux.decoder_fullness_abort =
+ mpq_dmx_decoder_fullness_abort;
+
+ /* Initialize dvb_demux object */
+ result = dvb_dmx_init(&mpq_demux->demux);
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
+ goto init_failed;
+ }
+
+ /* Now initailize the dmx-dev object */
+ mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+ mpq_demux->dmxdev.capabilities =
+ DMXDEV_CAP_DUPLEX |
+ DMXDEV_CAP_PULL_MODE |
+ DMXDEV_CAP_PCR_EXTRACTION;
+
+ mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+
+ result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
+ __func__,
+ result);
+ goto init_failed_dmx_release;
+ }
+
+ /* Extend dvb-demux debugfs with TSIF statistics. */
+ mpq_dmx_init_hw_statistics(mpq_demux);
+
+ return 0;
+
+init_failed_dmx_release:
+ dvb_dmx_release(&mpq_demux->demux);
+init_failed:
+ return result;
+}
+
+
+/**
+ * Module initialization function.
+ *
+ * Return error code
+ */
+static int __init mpq_dmx_tsif_plugin_init(void)
+{
+ int i;
+ int ret;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /* check module parameters validity */
+ if (threshold < 1) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid threshold parameter, using %d instead\n",
+ __func__, DMX_TSIF_PACKETS_IN_CHUNK_DEF);
+ threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
+ }
+ if ((mode < 1) || (mode > 3)) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid mode parameter, using %d instead\n",
+ __func__, DMX_TSIF_DRIVER_MODE_DEF);
+ mode = DMX_TSIF_DRIVER_MODE_DEF;
+ }
+
+ for (i = 0; i < TSIF_COUNT; i++) {
+ mpq_dmx_tsif_info.tsif[i].work.tsif_id = i;
+
+ INIT_WORK(&mpq_dmx_tsif_info.tsif[i].work.work,
+ mpq_dmx_tsif_work);
+
+ snprintf(mpq_dmx_tsif_info.tsif[i].name,
+ TSIF_NAME_LENGTH,
+ "tsif_%d",
+ i);
+
+ mpq_dmx_tsif_info.tsif[i].workqueue =
+ create_singlethread_workqueue(
+ mpq_dmx_tsif_info.tsif[i].name);
+
+ if (mpq_dmx_tsif_info.tsif[i].workqueue == NULL) {
+ int j;
+
+ for (j = 0; j < i; j++) {
+ destroy_workqueue(
+ mpq_dmx_tsif_info.tsif[j].workqueue);
+ mutex_destroy(&mpq_dmx_tsif_info.tsif[j].mutex);
+ }
+
+ MPQ_DVB_ERR_PRINT(
+ "%s: create_singlethread_workqueue failed\n",
+ __func__);
+
+ return -ENOMEM;
+ }
+
+ mutex_init(&mpq_dmx_tsif_info.tsif[i].mutex);
+
+ mpq_dmx_tsif_info.tsif[i].tsif_driver.tsif_handler = NULL;
+ mpq_dmx_tsif_info.tsif[i].ref_count = 0;
+ }
+
+ ret = mpq_dmx_plugin_init(mpq_tsif_dmx_init);
+
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_plugin_init failed (errno=%d)\n",
+ __func__,
+ ret);
+
+ for (i = 0; i < TSIF_COUNT; i++) {
+ destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+ mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
+ }
+ }
+
+ return ret;
+}
+
+
+/**
+ * Module exit function.
+ */
+static void __exit mpq_dmx_tsif_plugin_exit(void)
+{
+ int i;
+ struct tsif_driver_info *tsif_driver;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ for (i = 0; i < TSIF_COUNT; i++) {
+ mutex_lock(&mpq_dmx_tsif_info.tsif[i].mutex);
+
+ tsif_driver = &(mpq_dmx_tsif_info.tsif[i].tsif_driver);
+ if (mpq_dmx_tsif_info.tsif[i].ref_count > 0) {
+ mpq_dmx_tsif_info.tsif[i].ref_count = 0;
+ if (tsif_driver->tsif_handler)
+ tsif_stop(tsif_driver->tsif_handler);
+ }
+ /* Detach from TSIF driver to avoid further notifications. */
+ if (tsif_driver->tsif_handler)
+ tsif_detach(tsif_driver->tsif_handler);
+
+ /* release mutex to allow work queue to finish scheduled work */
+ mutex_unlock(&mpq_dmx_tsif_info.tsif[i].mutex);
+ /* flush the work queue and destroy it */
+ flush_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+ destroy_workqueue(mpq_dmx_tsif_info.tsif[i].workqueue);
+
+ mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
+ }
+
+ mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_tsif_plugin_init);
+module_exit(mpq_dmx_tsif_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm demux TSIF HW Plugin");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
new file mode 100644
index 0000000..406ae52
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c
@@ -0,0 +1,847 @@
+/* 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/workqueue.h>
+#include <mach/msm_tspp.h>
+#include "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+
+#define TSIF_COUNT 2
+
+#define TSPP_FILTERS_COUNT 16
+
+/* For each TSIF we allocate two pipes, one for PES and one for sections */
+#define TSPP_PES_CHANNEL 0
+#define TSPP_SECTION_CHANNEL 1
+
+/* the channel_id set to TSPP driver based on TSIF number and channel type */
+#define TSPP_CHANNEL_ID(tsif, ch) ((tsif << 1) + ch)
+#define TSPP_IS_PES_CHANNEL(ch_id) ((ch_id & 0x1) == 0)
+#define TSPP_GET_TSIF_NUM(ch_id) (ch_id >> 1)
+
+/* mask that set to care for all bits in pid filter */
+#define TSPP_PID_MASK 0x1FFF
+
+/* dvb-demux defines pid 0x2000 as full capture pid */
+#define TSPP_PASS_THROUGH_PID 0x2000
+
+/* TODO - NEED TO SET THESE PROPERLY
+ * once TSPP driver is ready, reduce TSPP_BUFFER_SIZE
+ * to single packet and set TSPP_BUFFER_COUNT accordingly
+ */
+
+#define TSPP_RAW_TTS_SIZE 192
+
+/* Size of single descriptor */
+#define TSPP_BUFFER_SIZE (TSPP_RAW_TTS_SIZE * 35)
+
+/* Number of descriptors, total size: TSPP_BUFFER_SIZE*TSPP_BUFFER_COUNT */
+#define TSPP_BUFFER_COUNT (16)
+
+/* When TSPP notifies demux that new packets are received */
+#define TSPP_NOTIFICATION_SIZE (TSPP_RAW_TTS_SIZE * 100)
+
+/* Channel timeout in msec */
+#define TSPP_CHANNEL_TIMEOUT 16
+
+
+/*
+ * Work scheduled each time TSPP notifies dmx
+ * of new TS packet in some channel
+ */
+struct tspp_work {
+ struct work_struct work;
+ int channel_id;
+};
+
+/* The following structure hold singelton information
+ * required for dmx implementation on top of TSPP.
+ */
+static struct
+{
+ /* Information for each TSIF input processing */
+ struct {
+ /*
+ * TSPP pipe holding all TS packets with PES data.
+ * The following is reference count for number of feeds
+ * allocated on that pipe.
+ */
+ int pes_channel_ref;
+
+ /* work used to submit to workqueue to process pes channel */
+ struct tspp_work pes_work;
+
+ /*
+ * TSPP pipe holding all TS packets with section data.
+ * The following is reference count for number of feeds
+ * allocated on that pipe.
+ */
+ int section_channel_ref;
+
+ /* work used to submit to workqueue to process pes channel */
+ struct tspp_work section_work;
+
+ /*
+ * Holds PIDs of allocated TSPP filters along with
+ * how many feeds are opened on same PID.
+ */
+ struct {
+ int pid;
+ int ref_count;
+ } filters[TSPP_FILTERS_COUNT];
+
+ /* workqueue that processes TS packets from specific TSIF */
+ struct workqueue_struct *workqueue;
+
+ /* TSIF alias */
+ char name[TSIF_NAME_LENGTH];
+
+ /* Pointer to the demux connected to this TSIF */
+ struct mpq_demux *mpq_demux;
+
+ /* mutex protecting the data-structure */
+ struct mutex mutex;
+ } tsif[TSIF_COUNT];
+} mpq_dmx_tspp_info;
+
+
+/**
+ * Returns a free filter slot that can be used.
+ *
+ * @tsif: The TSIF to allocate filter from
+ * @channel_id: The channel allocating filter to
+ *
+ * Return filter index or -1 if no filters available
+ *
+ * To give priority to PES data, for pes filters
+ * the table is scanned from high to low priority,
+ * and sections from low to high priority. This way TSPP
+ * would get a match on PES data filters faster as they
+ * are scanned first.
+ */
+static int mpq_tspp_get_free_filter_slot(int tsif, int channel_id)
+{
+ int i;
+
+ if (TSPP_IS_PES_CHANNEL(channel_id)) {
+ for (i = 0; i < TSPP_FILTERS_COUNT; i++)
+ if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == -1)
+ return i;
+ } else {
+ for (i = TSPP_FILTERS_COUNT-1; i >= 0; i--)
+ if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == -1)
+ return i;
+ }
+
+ return -ENOMEM;
+}
+
+/**
+ * Returns filter index of specific pid.
+ *
+ * @tsif: The TSIF to which the pid is allocated
+ * @pid: The pid to search for
+ *
+ * Return filter index or -1 if no filter available
+ */
+static int mpq_tspp_get_filter_slot(int tsif, int pid)
+{
+ int i;
+
+ for (i = 0; i < TSPP_FILTERS_COUNT; i++)
+ if (mpq_dmx_tspp_info.tsif[tsif].filters[i].pid == pid)
+ return i;
+
+ return -EINVAL;
+}
+
+/**
+ * Worker function that processes the TS packets notified by TSPP.
+ *
+ * @worker: the executed work
+ */
+static void mpq_dmx_tspp_work(struct work_struct *worker)
+{
+ struct tspp_work *tspp_work =
+ container_of(worker, struct tspp_work, work);
+ struct mpq_demux *mpq_demux;
+ int channel_id = tspp_work->channel_id;
+ int tsif = TSPP_GET_TSIF_NUM(channel_id);
+ const struct tspp_data_descriptor *tspp_data_desc;
+ int ref_count;
+
+ mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+
+ /* Lock against the TSPP filters data-structure */
+ if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
+ return;
+
+ /* Make sure channel is still active */
+ if (TSPP_IS_PES_CHANNEL(channel_id))
+ ref_count = mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+ else
+ ref_count = mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+
+ if (ref_count == 0) {
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return;
+ }
+
+ mpq_demux->hw_notification_size = 0;
+
+ /* Go through all filled descriptors and perform demuxing on them */
+ while ((tspp_data_desc = tspp_get_buffer(0, channel_id)) != NULL) {
+ mpq_demux->hw_notification_size +=
+ (tspp_data_desc->size / TSPP_RAW_TTS_SIZE);
+
+ dvb_dmx_swfilter_format(
+ &mpq_demux->demux,
+ tspp_data_desc->virt_base,
+ tspp_data_desc->size,
+ DMX_TSP_FORMAT_192_TAIL);
+
+ /* Notify TSPP that the buffer is no longer needed */
+ tspp_release_buffer(0, channel_id, tspp_data_desc->id);
+ }
+
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+}
+
+/**
+ * Callback function from TSPP when new data is ready.
+ *
+ * @channel_id: Channel with new TS packets
+ * @user: user-data holding TSIF number
+ */
+static void mpq_tspp_callback(u32 channel_id, void *user)
+{
+ int tsif = (int)user;
+ struct work_struct *work;
+ struct mpq_demux *mpq_demux;
+
+ /* Save statistics on TSPP notifications */
+ mpq_demux = mpq_dmx_tspp_info.tsif[tsif].mpq_demux;
+ mpq_dmx_update_hw_statistics(mpq_demux);
+
+ if (TSPP_IS_PES_CHANNEL(channel_id))
+ work = &mpq_dmx_tspp_info.tsif[tsif].pes_work.work;
+ else
+ work = &mpq_dmx_tspp_info.tsif[tsif].section_work.work;
+
+ /* Scheudle a new work to demux workqueue */
+ if (!work_pending(work))
+ queue_work(mpq_dmx_tspp_info.tsif[tsif].workqueue, work);
+}
+
+/**
+ * Configure TSPP channel to filter the PID of new feed.
+ *
+ * @feed: The feed to configure the channel with
+ *
+ * Return error status
+ *
+ * The function checks if the new PID can be added to an already
+ * allocated channel, if not, a new channel is allocated and configured.
+ */
+static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed)
+{
+ struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+ enum tspp_source tspp_source;
+ struct tspp_filter tspp_filter;
+ int tsif;
+ int ret;
+ int channel_id;
+ int *channel_ref_count;
+
+ /* determine the TSIF we are reading from */
+ if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+ tsif = 0;
+ tspp_source = TSPP_SOURCE_TSIF0;
+ } else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+ tsif = 1;
+ tspp_source = TSPP_SOURCE_TSIF1;
+ } else {
+ /* invalid source */
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid input source (%d)\n",
+ __func__,
+ mpq_demux->source);
+
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
+ return -ERESTARTSYS;
+
+ /*
+ * It is possible that this PID was already requested before.
+ * Can happen if we play and record same PES or PCR
+ * piggypacked on video packet.
+ */
+ ret = mpq_tspp_get_filter_slot(tsif, feed->pid);
+ if (ret >= 0) {
+ /* PID already configured */
+ mpq_dmx_tspp_info.tsif[tsif].filters[ret].ref_count++;
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return 0;
+ }
+
+ /* determine to which pipe the feed should be routed: section or pes */
+ if ((feed->type == DMX_TYPE_PES) || (feed->type == DMX_TYPE_TS)) {
+ channel_id = TSPP_CHANNEL_ID(tsif, TSPP_PES_CHANNEL);
+ channel_ref_count =
+ &mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+ } else {
+ channel_id = TSPP_CHANNEL_ID(tsif, TSPP_SECTION_CHANNEL);
+ channel_ref_count =
+ &mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+ }
+
+ /* check if required TSPP pipe is already allocated or not */
+ if (*channel_ref_count == 0) {
+ ret = tspp_open_channel(0, channel_id);
+
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tspp_open_channel(%d) failed (%d)\n",
+ __func__,
+ channel_id,
+ ret);
+
+ goto add_channel_failed;
+ }
+
+ /* set TSPP source */
+ ret = tspp_open_stream(0, channel_id, tspp_source);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tspp_select_source(%d,%d) failed (%d)\n",
+ __func__,
+ channel_id,
+ tspp_source,
+ ret);
+
+ goto add_channel_close_ch;
+ }
+
+ /* register notification on TS packets */
+ tspp_register_notification(0,
+ channel_id,
+ mpq_tspp_callback,
+ (void *)tsif,
+ TSPP_CHANNEL_TIMEOUT);
+
+ /* TODO: register allocater and provide allocation function
+ * that allocate from continous memory so that we can have
+ * big notification size, smallest descriptor, and still provide
+ * TZ with single big buffer based on notification size.
+ */
+
+ /* set buffer/descriptor size and count */
+ ret = tspp_allocate_buffers(0,
+ channel_id,
+ TSPP_BUFFER_COUNT,
+ TSPP_BUFFER_SIZE,
+ TSPP_NOTIFICATION_SIZE,
+ NULL,
+ NULL);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tspp_allocate_buffers(%d) failed (%d)\n",
+ __func__,
+ channel_id,
+ ret);
+
+ goto add_channel_unregister_notif;
+ }
+
+ mpq_dmx_tspp_info.tsif[tsif].mpq_demux = mpq_demux;
+ }
+
+ /* add new PID to the existing pipe */
+ ret = mpq_tspp_get_free_filter_slot(tsif, channel_id);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_allocate_filter_slot(%d, %d) failed\n",
+ __func__,
+ tsif,
+ channel_id);
+
+ goto add_channel_unregister_notif;
+ }
+
+ mpq_dmx_tspp_info.tsif[tsif].filters[ret].pid = feed->pid;
+ mpq_dmx_tspp_info.tsif[tsif].filters[ret].ref_count++;
+
+ tspp_filter.priority = ret;
+ if (feed->pid == TSPP_PASS_THROUGH_PID) {
+ /* pass all pids */
+ tspp_filter.pid = 0;
+ tspp_filter.mask = 0;
+ } else {
+ tspp_filter.pid = feed->pid;
+ tspp_filter.mask = TSPP_PID_MASK;
+ }
+
+ /*
+ * Include TTS in RAW packets, if you change this to
+ * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE
+ * accordingly.
+ */
+ tspp_filter.mode = TSPP_MODE_RAW;
+ tspp_filter.source = tspp_source;
+ tspp_filter.decrypt = 0;
+ ret = tspp_add_filter(0, channel_id, &tspp_filter);
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: tspp_add_filter(%d) failed (%d)\n",
+ __func__,
+ channel_id,
+ ret);
+
+ goto add_channel_free_filter_slot;
+ }
+
+ (*channel_ref_count)++;
+
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return 0;
+
+add_channel_free_filter_slot:
+ mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].pid = -1;
+ mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].ref_count--;
+add_channel_unregister_notif:
+ tspp_unregister_notification(0, channel_id);
+add_channel_close_ch:
+ tspp_close_channel(0, channel_id);
+add_channel_failed:
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return ret;
+}
+
+/**
+ * Removes filter from TSPP.
+ *
+ * @feed: The feed to remove
+ *
+ * Return error status
+ *
+ * The function checks if this is the only PID allocated within
+ * the channel, if so, the channel is closed as well.
+ */
+static int mpq_tspp_dmx_remove_channel(struct dvb_demux_feed *feed)
+{
+ int tsif;
+ int ret;
+ int channel_id;
+ int *channel_ref_count;
+ struct tspp_filter tspp_filter;
+ struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+
+ /* determine the TSIF we are reading from */
+ if (mpq_demux->source == DMX_SOURCE_FRONT0) {
+ tsif = 0;
+ } else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
+ tsif = 1;
+ } else {
+ /* invalid source */
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid input source (%d)\n",
+ __func__,
+ mpq_demux->source);
+
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex))
+ return -ERESTARTSYS;
+
+ /* determine to which pipe the feed should be routed: section or pes */
+ if ((feed->type == DMX_TYPE_PES) || (feed->type == DMX_TYPE_TS)) {
+ channel_id = TSPP_CHANNEL_ID(tsif, TSPP_PES_CHANNEL);
+ channel_ref_count =
+ &mpq_dmx_tspp_info.tsif[tsif].pes_channel_ref;
+ } else {
+ channel_id = TSPP_CHANNEL_ID(tsif, TSPP_SECTION_CHANNEL);
+ channel_ref_count =
+ &mpq_dmx_tspp_info.tsif[tsif].section_channel_ref;
+ }
+
+ /* check if required TSPP pipe is already allocated or not */
+ if (*channel_ref_count == 0) {
+ /* invalid feed provided as the channel is not allocated */
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid feed (%d)\n",
+ __func__,
+ channel_id);
+
+ ret = -EINVAL;
+ goto remove_channel_failed;
+ }
+
+ tspp_filter.priority = mpq_tspp_get_filter_slot(tsif, feed->pid);
+
+ if (tspp_filter.priority < 0) {
+ /* invalid feed provided as it has no filter allocated */
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_tspp_get_filter_slot failed (%d,%d)\n",
+ __func__,
+ feed->pid,
+ tsif);
+
+ ret = -EINVAL;
+ goto remove_channel_failed;
+ }
+
+ mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].ref_count--;
+
+ if (mpq_dmx_tspp_info.tsif[tsif].
+ filters[tspp_filter.priority].ref_count) {
+ /*
+ * there are still references to this pid, do not
+ * remove the filter yet
+ */
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return 0;
+ }
+
+ ret = tspp_remove_filter(0, channel_id, &tspp_filter);
+ if (ret < 0) {
+ /* invalid feed provided as it has no filter allocated */
+ MPQ_DVB_ERR_PRINT(
+ "%s: tspp_remove_filter failed (%d,%d)\n",
+ __func__,
+ channel_id,
+ tspp_filter.priority);
+
+ goto remove_channel_failed_restore_count;
+ }
+
+ mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].pid = -1;
+ (*channel_ref_count)--;
+
+ if (*channel_ref_count == 0) {
+ /* channel is not used any more, release it */
+ tspp_unregister_notification(0, channel_id);
+ tspp_close_channel(0, channel_id);
+ }
+
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return 0;
+
+remove_channel_failed_restore_count:
+ mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].ref_count++;
+
+remove_channel_failed:
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex);
+ return ret;
+}
+
+static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+ int ret;
+ struct mpq_demux *mpq_demux =
+ (struct mpq_demux *)feed->demux->priv;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s(%d) executed\n",
+ __func__,
+ feed->pid);
+
+ if (mpq_demux == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: invalid mpq_demux handle\n",
+ __func__);
+
+ return -EINVAL;
+ }
+
+ if (mpq_demux->source < DMX_SOURCE_DVR0) {
+ /* source from TSPP, need to configure tspp pipe */
+ ret = mpq_tspp_dmx_add_channel(feed);
+
+ if (ret < 0) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_tspp_dmx_add_channel failed(%d)\n",
+ __func__,
+ ret);
+ return ret;
+ }
+ }
+
+ /*
+ * Always feed sections/PES starting from a new one and
+ * do not partial transfer data from older one
+ */
+ feed->pusi_seen = 0;
+
+ /*
+ * For video PES, data is tunneled to the decoder,
+ * initialize tunneling and pes parsing.
+ */
+ if (mpq_dmx_is_video_feed(feed)) {
+ ret = mpq_dmx_init_video_feed(feed);
+
+ if (ret < 0) {
+ MPQ_DVB_DBG_PRINT(
+ "%s: mpq_dmx_init_video_feed failed(%d)\n",
+ __func__,
+ ret);
+
+ if (mpq_demux->source < DMX_SOURCE_DVR0)
+ mpq_tspp_dmx_remove_channel(feed);
+
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+ int ret = 0;
+ struct mpq_demux *mpq_demux = (struct mpq_demux *)feed->demux->priv;
+
+ MPQ_DVB_DBG_PRINT(
+ "%s(%d) executed\n",
+ __func__,
+ feed->pid);
+
+ /*
+ * For video PES, data is tunneled to the decoder,
+ * terminate tunnel and pes parsing.
+ */
+ if (mpq_dmx_is_video_feed(feed))
+ mpq_dmx_terminate_video_feed(feed);
+
+ if (mpq_demux->source < DMX_SOURCE_DVR0) {
+ /* source from TSPP, need to configure tspp pipe */
+ ret = mpq_tspp_dmx_remove_channel(feed);
+ }
+
+ return ret;
+}
+
+static int mpq_tspp_dmx_write_to_decoder(
+ struct dvb_demux_feed *feed,
+ const u8 *buf,
+ size_t len)
+{
+ /*
+ * It is assumed that this function is called once for each
+ * TS packet of the relevant feed.
+ */
+ if (len > TSPP_RAW_TTS_SIZE)
+ MPQ_DVB_DBG_PRINT(
+ "%s: warnning - len larger than one packet\n",
+ __func__);
+
+ if (mpq_dmx_is_video_feed(feed))
+ return mpq_dmx_process_video_packet(feed, buf);
+
+ if (mpq_dmx_is_pcr_feed(feed))
+ return mpq_dmx_process_pcr_packet(feed, buf);
+
+ return 0;
+}
+
+static int mpq_tspp_dmx_init(
+ struct dvb_adapter *mpq_adapter,
+ struct mpq_demux *mpq_demux)
+{
+ int result;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /* Set the kernel-demux object capabilities */
+ mpq_demux->demux.dmx.capabilities =
+ DMX_TS_FILTERING |
+ DMX_PES_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING |
+ DMX_CRC_CHECKING |
+ DMX_TS_DESCRAMBLING;
+
+ /* Set dvb-demux "virtual" function pointers */
+ mpq_demux->demux.priv = (void *)mpq_demux;
+ mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
+ mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
+ mpq_demux->demux.write_to_decoder = mpq_tspp_dmx_write_to_decoder;
+
+ mpq_demux->demux.decoder_fullness_init =
+ mpq_dmx_decoder_fullness_init;
+
+ mpq_demux->demux.decoder_fullness_wait =
+ mpq_dmx_decoder_fullness_wait;
+
+ mpq_demux->demux.decoder_fullness_abort =
+ mpq_dmx_decoder_fullness_abort;
+
+ /* Initialize dvb_demux object */
+ result = dvb_dmx_init(&mpq_demux->demux);
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
+ goto init_failed;
+ }
+
+ /* Now initailize the dmx-dev object */
+ mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+ mpq_demux->dmxdev.capabilities =
+ DMXDEV_CAP_DUPLEX |
+ DMXDEV_CAP_PULL_MODE |
+ DMXDEV_CAP_PCR_EXTRACTION;
+
+ mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+
+ result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
+ __func__,
+ result);
+ goto init_failed_dmx_release;
+ }
+
+ /* Extend dvb-demux debugfs with TSPP statistics. */
+ mpq_dmx_init_hw_statistics(mpq_demux);
+
+ return 0;
+
+init_failed_dmx_release:
+ dvb_dmx_release(&mpq_demux->demux);
+init_failed:
+ return result;
+}
+
+static int __init mpq_dmx_tspp_plugin_init(void)
+{
+ int i;
+ int j;
+ int ret;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ for (i = 0; i < TSIF_COUNT; i++) {
+ mpq_dmx_tspp_info.tsif[i].pes_channel_ref = 0;
+
+ mpq_dmx_tspp_info.tsif[i].pes_work.channel_id =
+ TSPP_CHANNEL_ID(i, TSPP_PES_CHANNEL);
+
+ INIT_WORK(&mpq_dmx_tspp_info.tsif[i].pes_work.work,
+ mpq_dmx_tspp_work);
+
+ mpq_dmx_tspp_info.tsif[i].section_channel_ref = 0;
+
+ mpq_dmx_tspp_info.tsif[i].section_work.channel_id =
+ TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL);
+
+ INIT_WORK(&mpq_dmx_tspp_info.tsif[i].section_work.work,
+ mpq_dmx_tspp_work);
+
+ for (j = 0; j < TSPP_FILTERS_COUNT; j++) {
+ mpq_dmx_tspp_info.tsif[i].filters[j].pid = -1;
+ mpq_dmx_tspp_info.tsif[i].filters[j].ref_count = 0;
+ }
+
+ snprintf(mpq_dmx_tspp_info.tsif[i].name,
+ TSIF_NAME_LENGTH,
+ "tsif_%d",
+ i);
+
+ mpq_dmx_tspp_info.tsif[i].workqueue =
+ create_singlethread_workqueue(
+ mpq_dmx_tspp_info.tsif[i].name);
+
+ if (mpq_dmx_tspp_info.tsif[i].workqueue == NULL) {
+
+ for (j = 0; j < i; j++) {
+ destroy_workqueue(
+ mpq_dmx_tspp_info.tsif[j].workqueue);
+
+ mutex_destroy(&mpq_dmx_tspp_info.tsif[j].mutex);
+ }
+
+ MPQ_DVB_ERR_PRINT(
+ "%s: create_singlethread_workqueue failed\n",
+ __func__);
+
+ return -ENOMEM;
+ }
+
+ mutex_init(&mpq_dmx_tspp_info.tsif[i].mutex);
+ }
+
+ ret = mpq_dmx_plugin_init(mpq_tspp_dmx_init);
+
+ if (ret < 0) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_dmx_plugin_init failed (errno=%d)\n",
+ __func__,
+ ret);
+
+ for (i = 0; i < TSIF_COUNT; i++) {
+ destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+ mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
+ }
+ }
+
+ return ret;
+}
+
+static void __exit mpq_dmx_tspp_plugin_exit(void)
+{
+ int i;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ for (i = 0; i < TSIF_COUNT; i++) {
+ mutex_lock(&mpq_dmx_tspp_info.tsif[i].mutex);
+
+ if (mpq_dmx_tspp_info.tsif[i].pes_channel_ref) {
+ tspp_unregister_notification(0, TSPP_PES_CHANNEL);
+ tspp_close_channel(0,
+ TSPP_CHANNEL_ID(i, TSPP_PES_CHANNEL));
+ }
+
+ if (mpq_dmx_tspp_info.tsif[i].section_channel_ref) {
+ tspp_unregister_notification(0, TSPP_SECTION_CHANNEL);
+ tspp_close_channel(0,
+ TSPP_CHANNEL_ID(i, TSPP_SECTION_CHANNEL));
+ }
+
+ /* TODO: if we allocate buffer
+ * to TSPP ourself, need to free those as well
+ */
+
+ mutex_unlock(&mpq_dmx_tspp_info.tsif[i].mutex);
+ flush_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+ destroy_workqueue(mpq_dmx_tspp_info.tsif[i].workqueue);
+ mutex_destroy(&mpq_dmx_tspp_info.tsif[i].mutex);
+ }
+
+ mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_tspp_plugin_init);
+module_exit(mpq_dmx_tspp_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm demux TSPP version 1 HW Plugin");
+MODULE_LICENSE("GPL v2");
+
+
diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
new file mode 100644
index 0000000..d3c2c50
--- /dev/null
+++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v2.c
@@ -0,0 +1,132 @@
+/* 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 "mpq_dvb_debug.h"
+#include "mpq_dmx_plugin_common.h"
+
+
+static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
+{
+ MPQ_DVB_DBG_PRINT(
+ "%s(%d) executed\n",
+ __func__,
+ feed->pid);
+
+ /* Always feed sections/PES starting from a new one and
+ * do not partial transfer data from older one
+ */
+ feed->pusi_seen = 0;
+ return 0;
+}
+
+static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed)
+{
+ MPQ_DVB_DBG_PRINT(
+ "%s(%d) executed\n",
+ __func__,
+ feed->pid);
+
+ return 0;
+}
+
+/**
+ * Initialize a single demux device.
+ *
+ * @mpq_adapter: MPQ DVB adapter
+ * @mpq_demux: The demux device to initialize
+ *
+ * Return error code
+ */
+static int mpq_tspp_dmx_init(
+ struct dvb_adapter *mpq_adapter,
+ struct mpq_demux *mpq_demux)
+{
+ int result;
+
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ /* Set the kernel-demux object capabilities */
+ mpq_demux->demux.dmx.capabilities =
+ DMX_TS_FILTERING |
+ DMX_PES_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING |
+ DMX_CRC_CHECKING |
+ DMX_TS_DESCRAMBLING;
+
+ /* Set dvb-demux "virtual" function pointers */
+ mpq_demux->demux.priv = (void *)mpq_demux;
+ mpq_demux->demux.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->demux.feednum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
+ mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
+ mpq_demux->demux.write_to_decoder = NULL;
+ mpq_demux->demux.decoder_fullness_init = NULL;
+ mpq_demux->demux.decoder_fullness_wait = NULL;
+ mpq_demux->demux.decoder_fullness_abort = NULL;
+
+ /* Initialize dvb_demux object */
+ result = dvb_dmx_init(&mpq_demux->demux);
+ if (result < 0) {
+ MPQ_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
+ goto init_failed;
+ }
+
+ /* Now initailize the dmx-dev object */
+ mpq_demux->dmxdev.filternum = MPQ_DMX_MAX_NUM_OF_FILTERS;
+ mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
+ mpq_demux->dmxdev.capabilities =
+ DMXDEV_CAP_DUPLEX |
+ DMXDEV_CAP_PULL_MODE |
+ DMXDEV_CAP_PCR_EXTRACTION;
+
+ mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
+
+ result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
+ if (result < 0) {
+ MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
+ __func__,
+ result);
+
+ goto init_failed_dmx_release;
+ }
+
+ return 0;
+
+init_failed_dmx_release:
+ dvb_dmx_release(&mpq_demux->demux);
+init_failed:
+ return result;
+}
+
+static int __init mpq_dmx_tspp_plugin_init(void)
+{
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+
+ return mpq_dmx_plugin_init(mpq_tspp_dmx_init);
+}
+
+static void __exit mpq_dmx_tspp_plugin_exit(void)
+{
+ MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
+ mpq_dmx_plugin_exit();
+}
+
+
+module_init(mpq_dmx_tspp_plugin_init);
+module_exit(mpq_dmx_tspp_plugin_exit);
+
+MODULE_DESCRIPTION("Qualcomm demux TSPP version2 HW Plugin");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/media/dvb/mpq/include/mpq_adapter.h b/drivers/media/dvb/mpq/include/mpq_adapter.h
new file mode 100644
index 0000000..c720f91
--- /dev/null
+++ b/drivers/media/dvb/mpq/include/mpq_adapter.h
@@ -0,0 +1,146 @@
+/* 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 _MPQ_ADAPTER_H
+#define _MPQ_ADAPTER_H
+
+#include "dvbdev.h"
+#include "mpq_stream_buffer.h"
+
+
+
+/** IDs of interfaces holding stream-buffers */
+enum mpq_adapter_stream_if {
+ /** Interface holding stream-buffer for video0 stream */
+ MPQ_ADAPTER_VIDEO0_STREAM_IF = 0,
+
+ /** Interface holding stream-buffer for video1 stream */
+ MPQ_ADAPTER_VIDEO1_STREAM_IF = 1,
+
+ /** Interface holding stream-buffer for video1 stream */
+ MPQ_ADAPTER_VIDEO2_STREAM_IF = 2,
+
+ /** Interface holding stream-buffer for video1 stream */
+ MPQ_ADAPTER_VIDEO3_STREAM_IF = 3,
+
+ /** Maximum number of interfaces holding stream-buffers */
+ MPQ_ADAPTER_MAX_NUM_OF_INTERFACES,
+};
+
+
+/** The meta-data used for video interface */
+struct mpq_adapter_video_meta_data {
+ /**
+ * Indication whether this packet is just a padding packet.
+ * In this case packet should be just disposed along
+ * with the padding in the raw-data buffer.
+ */
+ int is_padding;
+
+ /** Indication whether PTS exist */
+ int pts_exist;
+
+ /** Indication whether DTS exist */
+ int dts_exist;
+
+ /** PTS value associated with the PES data if any */
+ u64 pts;
+
+ /** DTS value associated with the PES data if any */
+ u64 dts;
+} __packed;
+
+
+/** Callback function to notify on registrations of specific interfaces */
+typedef void (*mpq_adapter_stream_if_callback)(
+ enum mpq_adapter_stream_if interface_id,
+ void *user_param);
+
+
+/**
+ * mpq_adapter_get - Returns pointer to Qualcomm DVB adapter
+ *
+ * Return dvb adapter or NULL if not exist.
+ */
+struct dvb_adapter *mpq_adapter_get(void);
+
+
+/**
+ * mpq_adapter_register_stream_if - Register a stream interface.
+ *
+ * @interface_id: The interface id
+ * @stream_buffer: The buffer used for the interface
+ *
+ * Return error status
+ *
+ * Stream interface used to connect between two units in tunneling
+ * mode using mpq_streambuffer implementation.
+ * The producer of the interface should register the new interface,
+ * consumer may get the interface using mpq_adapter_get_stream_if.
+ *
+ * Note that the function holds a pointer to this interface,
+ * stream_buffer pointer assumed to be valid as long as interface
+ * is active.
+ */
+int mpq_adapter_register_stream_if(
+ enum mpq_adapter_stream_if interface_id,
+ struct mpq_streambuffer *stream_buffer);
+
+
+/**
+ * mpq_adapter_unregister_stream_if - Un-register a stream interface.
+ *
+ * @interface_id: The interface id
+ *
+ * Return error status
+ */
+int mpq_adapter_unregister_stream_if(
+ enum mpq_adapter_stream_if interface_id);
+
+
+/**
+ * mpq_adapter_get_stream_if - Get buffer used for a stream interface.
+ *
+ * @interface_id: The interface id
+ * @stream_buffer: The returned stream buffer
+ *
+ * Return error status
+ */
+int mpq_adapter_get_stream_if(
+ enum mpq_adapter_stream_if interface_id,
+ struct mpq_streambuffer **stream_buffer);
+
+
+/**
+ * mpq_adapter_notify_stream_if - Register notification
+ * to be triggered when a stream interface is registered.
+ *
+ * @interface_id: The interface id
+ * @callback: The callback to be triggered when the interface is registered
+ * @user_param: A parameter that is passed back to the callback function
+ * when triggered.
+ *
+ * Return error status
+ *
+ * Producer may use this to register notification when desired
+ * interface registered in the system and query its information
+ * afterwards using mpq_adapter_get_stream_if.
+ * To remove the callback, this function should be called with NULL
+ * value in callback parameter.
+ */
+int mpq_adapter_notify_stream_if(
+ enum mpq_adapter_stream_if interface_id,
+ mpq_adapter_stream_if_callback callback,
+ void *user_param);
+
+#endif /* _MPQ_ADAPTER_H */
+
diff --git a/drivers/media/dvb/mpq/include/mpq_dvb_debug.h b/drivers/media/dvb/mpq/include/mpq_dvb_debug.h
new file mode 100644
index 0000000..4890b85
--- /dev/null
+++ b/drivers/media/dvb/mpq/include/mpq_dvb_debug.h
@@ -0,0 +1,38 @@
+/* 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 _MPQ_DVB_DEBUG_H
+#define _MPQ_DVB_DEBUG_H
+
+/* Enable this line if you want to output debug printouts */
+#define MPG_DVB_DEBUG_ENABLE
+
+#undef MPQ_DVB_DBG_PRINT /* undef it, just in case */
+
+#ifdef MPG_DVB_DEBUG_ENABLE
+#define MPQ_DVB_DBG_PRINT(fmt, args...) pr_debug(fmt, ## args)
+#define MPQ_DVB_ERR_PRINT(fmt, args...) pr_err(fmt, ## args)
+#else /* MPG_DVB_DEBUG_ENABLE */
+#define MPQ_DVB_DBG_PRINT(fmt, args...)
+#define MPQ_DVB_ERR_PRINT(fmt, args...)
+#endif /* MPG_DVB_DEBUG_ENABLE */
+
+
+/*
+ * The following can be used to disable specific printout
+ * by adding a letter to the end of MPQ_DVB_DBG_PRINT
+ */
+#undef MPQ_DVB_DBG_PRINTT
+#define MPQ_DVB_DBG_PRINTT(fmt, args...)
+
+#endif /* _MPQ_DVB_DEBUG_H */
+
diff --git a/drivers/media/dvb/mpq/include/mpq_stream_buffer.h b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
new file mode 100644
index 0000000..4ea4222
--- /dev/null
+++ b/drivers/media/dvb/mpq/include/mpq_stream_buffer.h
@@ -0,0 +1,269 @@
+/* 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 _MPQ_STREAM_BUFFER_H
+#define _MPQ_STREAM_BUFFER_H
+
+#include "dvb_ringbuffer.h"
+
+
+/**
+ * DOC: MPQ Stream Buffer
+ *
+ * A stream buffer implmenetation used to transfer data between two units
+ * such as demux and decoders. The implementation relies on dvb_ringbuffer
+ * implementation. Refer to dvb_ringbuffer.h for details.
+ *
+ * The implementation uses two dvb_ringbuffers, one to pass the
+ * raw-data (PES payload for example) and the other to pass
+ * meta-data (information from PES header for example).
+ *
+ * The meta-data uses dvb_ringbuffer packet interface. Each meta-data
+ * packet hold the address and size of raw-data described by the
+ * meta-data packet, in addition to user's own parameters if any required.
+ *
+ * Contrary to dvb_ringbuffer implementation, this API makes sure there's
+ * enough data to read/write when making read/write operations.
+ * Users interested to flush/reset specific buffer, check for bytes
+ * ready or space available for write should use the respective services
+ * in dvb_ringbuffer (dvb_ringbuffer_avail, dvb_ringbuffer_free,
+ * dvb_ringbuffer_reset, dvb_ringbuffer_flush,
+ * dvb_ringbuffer_flush_spinlock_wakeup).
+ *
+ * Concurrency protection is handled in the same manner as in
+ * dvb_ringbuffer implementation.
+ *
+ * Typical call flow from producer:
+ *
+ * - Start writting the raw-data of new packet, the following call is
+ * repeated until end of data of the specific packet
+ *
+ * mpq_streambuffer_data_write(...)
+ *
+ * - Now write a new packet describing the new available raw-data
+ * mpq_streambuffer_pkt_write(...)
+ *
+ * Typical call flow from consumer:
+ *
+ * - Poll for next available packet:
+ * mpq_streambuffer_pkt_next(&streambuff,-1)
+ *
+ * In different approach, consumer can wait on event for new data and then
+ * call mpq_streambuffer_pkt_next, waiting for data can be done as follows:
+ *
+ * wait_event_interruptible(
+ * streambuff->packet_data->queue,
+ * !dvb_ringbuffer_empty(&streambuff->packet_data) ||
+ * (streambuff->packet_data.error != 0);
+ *
+ * - Get the new packet information:
+ * mpq_streambuffer_pkt_read(..)
+ *
+ * - Read the raw-data of the new packet. Here you can use two methods:
+ *
+ * 1. Read the data to a user supplied buffer:
+ * mpq_streambuffer_data_read()
+ *
+ * In this case memory copy is done, read pointer is updated in the raw
+ * data buffer, the amount of raw-data is provided part of the
+ * packet's information. User should then call mpq_streambuffer_pkt_dispose
+ * with dispose_data set to 0 as the raw-data was already disposed.
+ *
+ * 2. Access the data directly using the raw-data address. The address
+ * of the raw data is provided part of the packet's information. User
+ * then should call mpq_streambuffer_pkt_dispose with dispose_data set
+ * to 1 to dispose the packet along with it's raw-data.
+ */
+
+/**
+ * struct mpq_streambuffer - mpq stream buffer representation
+ *
+ * @raw_data: The buffer used to hold the raw-data
+ * @packet_data: The buffer user to hold the meta-data
+ */
+struct mpq_streambuffer {
+ struct dvb_ringbuffer raw_data;
+ struct dvb_ringbuffer packet_data;
+};
+
+/**
+ * struct mpq_streambuffer_packet_header - packet header saved in packet buffer
+ * @user_data_len: length of private user (meta) data
+ * @raw_data_addr: raw-data address in the raw-buffer described by the packet
+ * @raw_data_len: size of raw-data in the raw-data buffer (can be 0)
+ *
+ * The packet structure that is saved in each packet-buffer:
+ * user_data_len
+ * raw_data_addr
+ * raw_data_len
+ * private user-data bytes
+ */
+struct mpq_streambuffer_packet_header {
+ u32 user_data_len;
+ u32 raw_data_addr;
+ u32 raw_data_len;
+} __packed;
+
+/**
+ * mpq_streambuffer_init - Initialize a new stream buffer
+ *
+ * @sbuff: The buffer to initialize
+ * @data_buff: The buffer holding raw-data
+ * @data_buff_len: Size of raw-data buffer
+ * @packet_buff: The buffer holding meta-data
+ * @packet_buff_size: Size of meta-data buffer
+ */
+void mpq_streambuffer_init(
+ struct mpq_streambuffer *sbuff,
+ void *data_buff, size_t data_buff_len,
+ void *packet_buff, size_t packet_buff_size);
+
+/**
+ * mpq_streambuffer_packet_next - Returns index of next avaialble packet.
+ *
+ * @sbuff: The stream buffer
+ * @idx: Previous packet index or -1 to return index of the the first
+ * available packet.
+ * @pktlen: The length of the ready packet
+ *
+ * Return index to the packet-buffer, -1 if buffer is empty
+ *
+ * After getting the index, the user of this function can either
+ * access the packet buffer directly using the returned index
+ * or ask to read the data back from the buffer using mpq_ringbuffer_pkt_read
+ */
+ssize_t mpq_streambuffer_pkt_next(
+ struct mpq_streambuffer *sbuff,
+ ssize_t idx, size_t *pktlen);
+
+/**
+ * mpq_streambuffer_pkt_read - Reads out the packet from the provided index.
+ *
+ * @sbuff: The stream buffer
+ * @idx: The index of the packet to be read
+ * @packet: The read packet's header
+ * @user_data: The read private user data
+ *
+ * Return The actual number of bytes read, -EINVAL if the packet is
+ * already disposed or the packet-data is invalid.
+ *
+ * The packet is not disposed after this function is called, to dispose it
+ * along with the raw-data it points to use mpq_streambuffer_pkt_dispose.
+ * If there are no private user-data, the user-data pointer can be NULL.
+ * The caller of this function must make sure that the private user-data
+ * buffer has enough space for the private user-data length
+ */
+ssize_t mpq_streambuffer_pkt_read(
+ struct mpq_streambuffer *sbuff,
+ size_t idx,
+ struct mpq_streambuffer_packet_header *packet,
+ u8 *user_data);
+
+/**
+ * mpq_streambuffer_pkt_dispose - Disposes a packet from the packet buffer
+ *
+ * @sbuff: The stream buffer
+ * @idx: The index of the packet to be disposed
+ * @dispose_data: Indicates whether to update the read pointer inside the
+ * raw-data buffer for the respective data pointed by the packet.
+ *
+ * Return error status, -EINVAL if the packet-data is invalid
+ *
+ * The function updates the read pointer inside the raw-data buffer
+ * for the respective data pointed by the packet if dispose_data is set.
+ */
+int mpq_streambuffer_pkt_dispose(
+ struct mpq_streambuffer *sbuff,
+ size_t idx,
+ int dispose_data);
+
+/**
+ * mpq_streambuffer_pkt_write - Write a new packet to the packet buffer.
+ *
+ * @sbuff: The stream buffer
+ * @packet: The packet header to write
+ * @user_data: The private user-data to be written
+ *
+ * Return error status, -ENOSPC if there's no space to write the packet
+ */
+int mpq_streambuffer_pkt_write(
+ struct mpq_streambuffer *sbuff,
+ struct mpq_streambuffer_packet_header *packet,
+ u8 *user_data);
+
+/**
+ * mpq_streambuffer_data_write - Write data to raw-data buffer
+ *
+ * @sbuff: The stream buffer
+ * @buf: The buffer holding the data to be written
+ * @len: The length of the data buffer
+ *
+ * Return The actual number of bytes written or -ENOSPC if
+ * no space to write the data
+ */
+ssize_t mpq_streambuffer_data_write(
+ struct mpq_streambuffer *sbuff,
+ const u8 *buf, size_t len);
+
+/**
+ * mpq_streambuffer_data_write_deposit - Advances the raw-buffer write pointer.
+ * Assumes the raw-data was written by the user directly
+ *
+ * @sbuff: The stream buffer
+ * @len: The length of the raw-data that was already written
+ *
+ * Return error status
+ */
+int mpq_streambuffer_data_write_deposit(
+ struct mpq_streambuffer *sbuff,
+ size_t len);
+
+/**
+ * mpq_streambuffer_data_read - Reads out raw-data to the provided buffer.
+ *
+ * @sbuff: The stream buffer
+ * @buf: The buffer to read the raw-data data to
+ * @len: The length of the buffer that will hold the raw-data
+ *
+ * Return The actual number of bytes read
+ *
+ * This fucntion copies the data from the ring-buffer to the
+ * provided buf parameter. The user can save the extra copy by accessing
+ * the data pointer directly and reading from it, then update the
+ * read pointer by the amount of data that was read using
+ * mpq_streambuffer_data_read_dispose
+ */
+size_t mpq_streambuffer_data_read(
+ struct mpq_streambuffer *sbuff,
+ u8 *buf, size_t len);
+
+/**
+ * mpq_streambuffer_data_read_dispose - Advances the raw-buffer read pointer.
+ * Assumes the raw-data was read by the user directly.
+ *
+ * @sbuff: The stream buffer
+ * @len: The length of the raw-data to be disposed
+ *
+ * Return error status, -EINVAL if buffer there's no enough data to
+ * be disposed
+ *
+ * The user can instead dipose a packet along with the data in the
+ * raw-data buffer using mpq_streambuffer_pkt_dispose.
+ */
+int mpq_streambuffer_data_read_dispose(
+ struct mpq_streambuffer *sbuff,
+ size_t len);
+
+
+
+#endif /* _MPQ_STREAM_BUFFER_H */
+
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 5508c3d..c07bdc4 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -24,6 +24,17 @@
LIRC daemon handles protocol decoding for IR reception and
encoding for IR transmitting (aka "blasting").
+config USER_RC_INPUT
+ tristate "User Space Input device wrapper for Remote Control"
+ depends on RC_CORE
+
+ ---help---
+ Say Y if you want to report remote control input events
+ from userspace.
+
+ To compile this driver as a module, choose M here: the module will
+ be called user-rc-input.
+
source "drivers/media/rc/keymaps/Kconfig"
config IR_NEC_DECODER
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 523fcd0..b9c1e21 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -11,6 +11,7 @@
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
+obj-$(CONFIG_USER_RC_INPUT) += user-rc-input.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index eee351b..3416c91 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -87,7 +87,7 @@
rcdev->input_name = GPIO_IR_DEVICE_NAME;
rcdev->input_id.bustype = BUS_HOST;
rcdev->driver_name = GPIO_IR_DRIVER_NAME;
- rcdev->map_name = RC_MAP_RC6_PHILIPS;
+ rcdev->map_name = RC_MAP_SAMSUNG_NECX;
gpio_dev->rcdev = rcdev;
gpio_dev->gpio_nr = pdata->gpio_nr;
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 198298b..17aed88 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -84,6 +84,7 @@
rc-trekstor.o \
rc-tt-1500.o \
rc-twinhan1027.o \
+ rc-ue-rf4ce.o \
rc-videomate-m1f.o \
rc-videomate-s350.o \
rc-videomate-tv-pvr.o \
diff --git a/drivers/media/rc/keymaps/rc-ue-rf4ce.c b/drivers/media/rc/keymaps/rc-ue-rf4ce.c
new file mode 100644
index 0000000..af40976
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-ue-rf4ce.c
@@ -0,0 +1,82 @@
+/* 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 <media/rc-map.h>
+
+static struct rc_map_table ue_rf4ce[] = {
+ { 0x0a, KEY_SETUP },
+ { 0x6b, KEY_POWER },
+ { 0x00, KEY_OK },
+ { 0x03, KEY_LEFT },
+ { 0x04, KEY_RIGHT },
+ { 0x01, KEY_UP },
+ { 0x02, KEY_DOWN },
+ { 0x53, KEY_HOMEPAGE },
+ { 0x0d, KEY_EXIT },
+ { 0x72, KEY_TV },
+ { 0x73, KEY_VIDEO },
+ { 0x74, KEY_COMPOSE },
+ { 0x71, KEY_AUX },
+ { 0x45, KEY_STOP },
+ { 0x0b, KEY_LIST },
+ { 0x47, KEY_RECORD },
+ { 0x48, KEY_REWIND },
+ { 0x44, KEY_PLAY },
+ { 0x49, KEY_FASTFORWARD },
+ { 0x4c, KEY_BACK },
+ { 0x46, KEY_PAUSE },
+ { 0x4b, KEY_NEXT },
+ { 0x41, KEY_VOLUMEUP },
+ { 0x42, KEY_VOLUMEDOWN },
+ { 0x32, KEY_LAST },
+ { 0x43, KEY_MUTE },
+ { 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 },
+ { 0x2b, KEY_ENTER },
+};
+
+static struct rc_map_list ue_rf4ce_map = {
+ .map = {
+ .scan = ue_rf4ce,
+ .size = ARRAY_SIZE(ue_rf4ce),
+ .rc_type = RC_TYPE_OTHER,
+ .name = RC_MAP_UE_RF4CE,
+ }
+};
+
+static int __init init_rc_map_ue_rf4ce(void)
+{
+ return rc_map_register(&ue_rf4ce_map);
+}
+
+static void __exit exit_rc_map_ue_rf4ce(void)
+{
+ rc_map_unregister(&ue_rf4ce_map);
+}
+
+module_init(init_rc_map_ue_rf4ce)
+module_exit(exit_rc_map_ue_rf4ce)
+
+MODULE_DESCRIPTION("UE RF4CE Remote Keymap ");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/rc/user-rc-input.c b/drivers/media/rc/user-rc-input.c
new file mode 100644
index 0000000..f1a9334
--- /dev/null
+++ b/drivers/media/rc/user-rc-input.c
@@ -0,0 +1,251 @@
+/* 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/kernel.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/slab.h>
+
+#include <media/rc-core.h>
+#include <media/user-rc-input.h>
+
+#define MAX_RC_DEVICES 1
+#define USER_RC_INPUT_DEV_NAME "user-rc-input"
+#define USER_RC_INPUT_DRV_NAME "rc-user-input"
+
+struct user_rc_input_dev {
+ struct cdev rc_input_cdev;
+ struct class *rc_input_class;
+ struct device *rc_input_dev;
+ struct rc_dev *rcdev;
+ dev_t rc_input_base_dev;
+ struct device *dev;
+ int in_use;
+};
+
+static int user_rc_input_open(struct inode *inode, struct file *file)
+{
+ struct cdev *input_cdev = inode->i_cdev;
+ struct user_rc_input_dev *input_dev =
+ container_of(input_cdev, struct user_rc_input_dev, rc_input_cdev);
+
+ if (input_dev->in_use) {
+ dev_err(input_dev->dev,
+ "Device is already open..only one instance is allowed\n");
+ return -EBUSY;
+ }
+ input_dev->in_use++;
+ file->private_data = input_dev;
+
+ return 0;
+}
+
+static int user_rc_input_release(struct inode *inode, struct file *file)
+{
+ struct user_rc_input_dev *input_dev = file->private_data;
+
+ input_dev->in_use--;
+
+ return 0;
+}
+
+static ssize_t user_rc_input_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ int ret;
+ struct user_rc_input_dev *input_dev = file->private_data;
+ __u8 *buf;
+
+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+ if (!buf) {
+ dev_err(input_dev->dev,
+ "kmalloc failed...Insufficient memory\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ dev_err(input_dev->dev, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ switch (buf[0]) {
+ case USER_CONTROL_PRESSED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " pressed 0x%x\n", buf[1]);
+ rc_keydown(input_dev->rcdev, buf[1], 0);
+ break;
+ case USER_CONTROL_REPEATED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " repeated 0x%x\n", buf[1]);
+ rc_repeat(input_dev->rcdev);
+ break;
+ case USER_CONTROL_RELEASED:
+ dev_dbg(input_dev->dev, "user controlled"
+ " released 0x%x\n", buf[1]);
+ rc_keyup(input_dev->rcdev);
+ break;
+ }
+
+out_free:
+ kfree(buf);
+out:
+ return ret;
+}
+
+const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = user_rc_input_open,
+ .write = user_rc_input_write,
+ .release = user_rc_input_release,
+};
+
+static int __devinit user_rc_input_probe(struct platform_device *pdev)
+{
+ struct user_rc_input_dev *user_rc_dev;
+ struct rc_dev *rcdev;
+ int retval;
+
+ user_rc_dev = kzalloc(sizeof(struct user_rc_input_dev), GFP_KERNEL);
+ if (!user_rc_dev)
+ return -ENOMEM;
+
+ user_rc_dev->rc_input_class = class_create(THIS_MODULE,
+ "user-rc-input-loopback");
+
+ if (IS_ERR(user_rc_dev->rc_input_class)) {
+ retval = PTR_ERR(user_rc_dev->rc_input_class);
+ goto err;
+ }
+
+ retval = alloc_chrdev_region(&user_rc_dev->rc_input_base_dev, 0,
+ MAX_RC_DEVICES, USER_RC_INPUT_DEV_NAME);
+
+ if (retval) {
+ dev_err(&pdev->dev,
+ "alloc_chrdev_region failed\n");
+ goto alloc_chrdev_err;
+ }
+
+ dev_info(&pdev->dev, "User space report key event input "
+ "loopback driver registered, "
+ "major %d\n", MAJOR(user_rc_dev->rc_input_base_dev));
+
+ cdev_init(&user_rc_dev->rc_input_cdev, &fops);
+ retval = cdev_add(&user_rc_dev->rc_input_cdev,
+ user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+ if (retval) {
+ dev_err(&pdev->dev, "cdev_add failed\n");
+ goto cdev_add_err;
+ }
+ user_rc_dev->rc_input_dev =
+ device_create(user_rc_dev->rc_input_class,
+ NULL,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev),
+ 0), NULL, "user-rc-input-dev%d", 0);
+
+ if (IS_ERR(user_rc_dev->rc_input_dev)) {
+ retval = PTR_ERR(user_rc_dev->rc_input_dev);
+ dev_err(&pdev->dev, "device_create failed\n");
+ goto device_create_err;
+ }
+
+ rcdev = rc_allocate_device();
+ if (!rcdev) {
+ dev_err(&pdev->dev, "failed to allocate rc device");
+ retval = -ENOMEM;
+ goto err_allocate_device;
+ }
+
+ rcdev->driver_type = RC_DRIVER_SCANCODE;
+ rcdev->allowed_protos = RC_TYPE_OTHER;
+ rcdev->input_name = USER_RC_INPUT_DEV_NAME;
+ rcdev->input_id.bustype = BUS_HOST;
+ rcdev->driver_name = USER_RC_INPUT_DRV_NAME;
+ rcdev->map_name = RC_MAP_UE_RF4CE;
+
+ retval = rc_register_device(rcdev);
+ if (retval < 0) {
+ dev_err(&pdev->dev, "failed to register rc device\n");
+ goto rc_register_err;
+ }
+ user_rc_dev->rcdev = rcdev;
+ user_rc_dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, user_rc_dev);
+ user_rc_dev->in_use = 0;
+
+ return 0;
+
+rc_register_err:
+ rc_free_device(rcdev);
+err_allocate_device:
+ device_destroy(user_rc_dev->rc_input_class,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+cdev_add_err:
+ unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+device_create_err:
+ cdev_del(&user_rc_dev->rc_input_cdev);
+alloc_chrdev_err:
+ class_destroy(user_rc_dev->rc_input_class);
+err:
+ kfree(user_rc_dev);
+ return retval;
+}
+
+static int __devexit user_rc_input_remove(struct platform_device *pdev)
+{
+ struct user_rc_input_dev *user_rc_dev = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ rc_free_device(user_rc_dev->rcdev);
+ device_destroy(user_rc_dev->rc_input_class,
+ MKDEV(MAJOR(user_rc_dev->rc_input_base_dev), 0));
+ unregister_chrdev_region(user_rc_dev->rc_input_base_dev,
+ MAX_RC_DEVICES);
+ cdev_del(&user_rc_dev->rc_input_cdev);
+ class_destroy(user_rc_dev->rc_input_class);
+ kfree(user_rc_dev);
+
+ return 0;
+}
+
+static struct platform_driver user_rc_input_driver = {
+ .probe = user_rc_input_probe,
+ .remove = __devexit_p(user_rc_input_remove),
+ .driver = {
+ .name = USER_RC_INPUT_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init user_rc_input_init(void)
+{
+ return platform_driver_register(&user_rc_input_driver);
+}
+module_init(user_rc_input_init);
+
+static void __exit user_rc_input_exit(void)
+{
+ platform_driver_unregister(&user_rc_input_driver);
+}
+module_exit(user_rc_input_exit);
+
+MODULE_DESCRIPTION("User RC Input driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 07a31a3..5aaef24 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -572,7 +572,7 @@
config MSM_VCAP
tristate "Qualcomm MSM VCAP"
depends on VIDEO_DEV && VIDEO_V4L2
- default n
+ default y
---help---
Enables VCAP driver. This device allows for video capture and
video processing using the v4l2 api
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index c00f4c6..fbc3a37 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -57,7 +57,7 @@
Say Y here if this is msm7627A variant platform.
config WEBCAM_OV7692_QRD
bool "Sensor OV7692 QRD(VGA YUV)"
- depends on MSM_CAMERA && ARCH_MSM7X27A
+ depends on MSM_CAMERA && (ARCH_MSM7X27A || ARCH_MSM8X60)
default n
---help---
Omni Vision VGA YUV Sensor for QRD Devices
@@ -211,6 +211,18 @@
bool "Qualcomm MSM actuator support"
depends on MSM_CAMERA
+config MSM_EEPROM
+ bool "Qualcomm MSM EEPROM support"
+ depends on MSM_CAMERA
+
+config IMX074_EEPROM
+ bool "IMX074 EEPROM support"
+ depends on MSM_CAMERA
+
+config IMX091_EEPROM
+ bool "IMX091 EEPROM support"
+ depends on MSM_CAMERA
+
config MSM_GEMINI
tristate "Qualcomm MSM Gemini Jpeg Engine support"
depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60 || ARCH_MSM8960)
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index 85157f7..ebfed6c 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -7,10 +7,12 @@
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
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) += sensors/ actuators/ csi/
+ obj-$(CONFIG_MSM_CAMERA) += io/ eeprom/ sensors/ actuators/ csi/
else
obj-$(CONFIG_MSM_CAMERA) += msm_camera.o
endif
diff --git a/drivers/media/video/msm/csi/msm_csid.c b/drivers/media/video/msm/csi/msm_csid.c
index e643def..c04ece2 100644
--- a/drivers/media/video/msm/csi/msm_csid.c
+++ b/drivers/media/video/msm/csi/msm_csid.c
@@ -211,10 +211,11 @@
init_completion(&csid_dev->reset_complete);
- enable_irq(csid_dev->irq->start);
+ rc = request_irq(csid_dev->irq->start, msm_csid_irq,
+ IRQF_TRIGGER_RISING, "csid", csid_dev);
msm_csid_reset(csid_dev);
- return 0;
+ return rc;
clk_enable_failed:
msm_camera_enable_vreg(&csid_dev->pdev->dev, csid_vreg_info,
@@ -230,10 +231,15 @@
static int msm_csid_release(struct v4l2_subdev *sd)
{
+ uint32_t irq;
struct csid_device *csid_dev;
csid_dev = v4l2_get_subdevdata(sd);
- disable_irq(csid_dev->irq->start);
+ irq = msm_camera_io_r(csid_dev->base + CSID_IRQ_STATUS_ADDR);
+ msm_camera_io_w(irq, csid_dev->base + CSID_IRQ_CLEAR_CMD_ADDR);
+ msm_camera_io_w(0, csid_dev->base + CSID_IRQ_MASK_ADDR);
+
+ free_irq(csid_dev->irq->start, csid_dev);
msm_cam_clk_enable(&csid_dev->pdev->dev, csid_clk_info,
csid_dev->csid_clk, ARRAY_SIZE(csid_clk_info), 0);
@@ -328,17 +334,6 @@
goto csid_no_resource;
}
- rc = request_irq(new_csid_dev->irq->start, msm_csid_irq,
- IRQF_TRIGGER_RISING, "csid", new_csid_dev);
- if (rc < 0) {
- release_mem_region(new_csid_dev->mem->start,
- resource_size(new_csid_dev->mem));
- pr_err("%s: irq request fail\n", __func__);
- rc = -EBUSY;
- goto csid_no_resource;
- }
- disable_irq(new_csid_dev->irq->start);
-
new_csid_dev->pdev = pdev;
msm_cam_register_subdev_node(&new_csid_dev->subdev, CSID_DEV, pdev->id);
return 0;
diff --git a/drivers/media/video/msm/eeprom/Makefile b/drivers/media/video/msm/eeprom/Makefile
new file mode 100644
index 0000000..f7b7f5d
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/Makefile
@@ -0,0 +1,5 @@
+GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
+EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+obj-$(CONFIG_MSM_EEPROM) += msm_camera_eeprom.o
+obj-$(CONFIG_IMX074_EEPROM) += imx074_eeprom.o
+obj-$(CONFIG_IMX091_EEPROM) += imx091_eeprom.o
\ No newline at end of file
diff --git a/drivers/media/video/msm/eeprom/imx074_eeprom.c b/drivers/media/video/msm/eeprom/imx074_eeprom.c
new file mode 100644
index 0000000..f46bc94
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/imx074_eeprom.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 "msm_camera_eeprom.h"
+#include "msm_camera_i2c.h"
+
+DEFINE_MUTEX(imx074_eeprom_mutex);
+static struct msm_eeprom_ctrl_t imx074_eeprom_t;
+
+static const struct i2c_device_id imx074_eeprom_i2c_id[] = {
+ {"imx074_eeprom", (kernel_ulong_t)&imx074_eeprom_t},
+ { }
+};
+
+static struct i2c_driver imx074_eeprom_i2c_driver = {
+ .id_table = imx074_eeprom_i2c_id,
+ .probe = msm_eeprom_i2c_probe,
+ .remove = __exit_p(imx074_eeprom_i2c_remove),
+ .driver = {
+ .name = "imx074_eeprom",
+ },
+};
+
+static int __init imx074_eeprom_i2c_add_driver(void)
+{
+ int rc = 0;
+ rc = i2c_add_driver(imx074_eeprom_t.i2c_driver);
+ return rc;
+}
+
+static struct v4l2_subdev_core_ops imx074_eeprom_subdev_core_ops = {
+ .ioctl = msm_eeprom_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops imx074_eeprom_subdev_ops = {
+ .core = &imx074_eeprom_subdev_core_ops,
+};
+
+uint8_t imx074_wbcalib_data[6];
+struct msm_calib_wb imx074_wb_data;
+
+static struct msm_camera_eeprom_info_t imx074_calib_supp_info = {
+ {FALSE, 0, 0, 1},
+ {TRUE, 6, 0, 1024},
+ {FALSE, 0, 0, 1},
+ {FALSE, 0, 0, 1},
+};
+
+static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
+ {0x10, &imx074_wbcalib_data[0], 6, 0},
+};
+
+
+static struct msm_camera_eeprom_data_t imx074_eeprom_data_tbl[] = {
+ {&imx074_wb_data, sizeof(struct msm_calib_wb)},
+};
+
+static void imx074_format_wbdata(void)
+{
+ imx074_wb_data.r_over_g = (uint16_t)(imx074_wbcalib_data[0] << 8) |
+ imx074_wbcalib_data[1];
+ imx074_wb_data.b_over_g = (uint16_t)(imx074_wbcalib_data[2] << 8) |
+ imx074_wbcalib_data[3];
+ imx074_wb_data.gr_over_gb = (uint16_t)(imx074_wbcalib_data[4] << 8) |
+ imx074_wbcalib_data[5];
+}
+
+void imx074_format_calibrationdata(void)
+{
+ imx074_format_wbdata();
+}
+static struct msm_eeprom_ctrl_t imx074_eeprom_t = {
+ .i2c_driver = &imx074_eeprom_i2c_driver,
+ .i2c_addr = 0xA4,
+ .eeprom_v4l2_subdev_ops = &imx074_eeprom_subdev_ops,
+
+ .i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+ },
+
+ .eeprom_mutex = &imx074_eeprom_mutex,
+
+ .func_tbl = {
+ .eeprom_init = NULL,
+ .eeprom_release = NULL,
+ .eeprom_get_info = msm_camera_eeprom_get_info,
+ .eeprom_get_data = msm_camera_eeprom_get_data,
+ .eeprom_set_dev_addr = NULL,
+ .eeprom_format_data = imx074_format_calibrationdata,
+ },
+ .info = &imx074_calib_supp_info,
+ .info_size = sizeof(struct msm_camera_eeprom_info_t),
+ .read_tbl = imx074_eeprom_read_tbl,
+ .read_tbl_size = ARRAY_SIZE(imx074_eeprom_read_tbl),
+ .data_tbl = imx074_eeprom_data_tbl,
+ .data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
+};
+
+subsys_initcall(imx074_eeprom_i2c_add_driver);
+MODULE_DESCRIPTION("IMX074 EEPROM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/eeprom/imx091_eeprom.c b/drivers/media/video/msm/eeprom/imx091_eeprom.c
new file mode 100644
index 0000000..8b34513
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/imx091_eeprom.c
@@ -0,0 +1,126 @@
+/* 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_camera_eeprom.h"
+#include "msm_camera_i2c.h"
+
+DEFINE_MUTEX(imx091_eeprom_mutex);
+static struct msm_eeprom_ctrl_t imx091_eeprom_t;
+
+static const struct i2c_device_id imx091_eeprom_i2c_id[] = {
+ {"imx091_eeprom", (kernel_ulong_t)&imx091_eeprom_t},
+ { }
+};
+
+static struct i2c_driver imx091_eeprom_i2c_driver = {
+ .id_table = imx091_eeprom_i2c_id,
+ .probe = msm_eeprom_i2c_probe,
+ .remove = __exit_p(imx091_eeprom_i2c_remove),
+ .driver = {
+ .name = "imx091_eeprom",
+ },
+};
+
+static int __init imx091_eeprom_i2c_add_driver(void)
+{
+ int rc = 0;
+ rc = i2c_add_driver(imx091_eeprom_t.i2c_driver);
+ return rc;
+}
+
+static struct v4l2_subdev_core_ops imx091_eeprom_subdev_core_ops = {
+ .ioctl = msm_eeprom_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops imx091_eeprom_subdev_ops = {
+ .core = &imx091_eeprom_subdev_core_ops,
+};
+
+uint8_t imx091_wbcalib_data[6];
+uint8_t imx091_afcalib_data[6];
+struct msm_calib_wb imx091_wb_data;
+struct msm_calib_af imx091_af_data;
+
+static struct msm_camera_eeprom_info_t imx091_calib_supp_info = {
+ {TRUE, 6, 1, 1},
+ {TRUE, 6, 0, 32768},
+ {FALSE, 0, 0, 1},
+ {FALSE, 0, 0, 1},
+};
+
+static struct msm_camera_eeprom_read_t imx091_eeprom_read_tbl[] = {
+ {0x05, &imx091_wbcalib_data[0], 6, 0},
+ {0x0B, &imx091_afcalib_data[0], 6, 0},
+};
+
+
+static struct msm_camera_eeprom_data_t imx091_eeprom_data_tbl[] = {
+ {&imx091_wb_data, sizeof(struct msm_calib_wb)},
+ {&imx091_af_data, sizeof(struct msm_calib_af)},
+};
+
+static void imx091_format_wbdata(void)
+{
+ imx091_wb_data.r_over_g = (uint16_t)(imx091_wbcalib_data[1] << 8) |
+ (imx091_wbcalib_data[0] - 0x32);
+ imx091_wb_data.b_over_g = (uint16_t)(imx091_wbcalib_data[3] << 8) |
+ (imx091_wbcalib_data[2] - 0x32);
+ imx091_wb_data.gr_over_gb = (uint16_t)(imx091_wbcalib_data[5] << 8) |
+ (imx091_wbcalib_data[4] - 0x32);
+}
+
+static void imx091_format_afdata(void)
+{
+ imx091_af_data.inf_dac = (uint16_t)(imx091_afcalib_data[1] << 8) |
+ imx091_afcalib_data[0];
+ imx091_af_data.macro_dac = (uint16_t)(imx091_afcalib_data[3] << 8) |
+ imx091_afcalib_data[2];
+ imx091_af_data.start_dac = (uint16_t)(imx091_afcalib_data[5] << 8) |
+ imx091_afcalib_data[4];
+}
+
+void imx091_format_calibrationdata(void)
+{
+ imx091_format_wbdata();
+ imx091_format_afdata();
+}
+static struct msm_eeprom_ctrl_t imx091_eeprom_t = {
+ .i2c_driver = &imx091_eeprom_i2c_driver,
+ .i2c_addr = 0xA1,
+ .eeprom_v4l2_subdev_ops = &imx091_eeprom_subdev_ops,
+
+ .i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
+ },
+
+ .eeprom_mutex = &imx091_eeprom_mutex,
+
+ .func_tbl = {
+ .eeprom_init = NULL,
+ .eeprom_release = NULL,
+ .eeprom_get_info = msm_camera_eeprom_get_info,
+ .eeprom_get_data = msm_camera_eeprom_get_data,
+ .eeprom_set_dev_addr = NULL,
+ .eeprom_format_data = imx091_format_calibrationdata,
+ },
+ .info = &imx091_calib_supp_info,
+ .info_size = sizeof(struct msm_camera_eeprom_info_t),
+ .read_tbl = imx091_eeprom_read_tbl,
+ .read_tbl_size = ARRAY_SIZE(imx091_eeprom_read_tbl),
+ .data_tbl = imx091_eeprom_data_tbl,
+ .data_tbl_size = ARRAY_SIZE(imx091_eeprom_data_tbl),
+};
+
+subsys_initcall(imx091_eeprom_i2c_add_driver);
+MODULE_DESCRIPTION("imx091 EEPROM");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.c b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
new file mode 100644
index 0000000..96a6e04
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.c
@@ -0,0 +1,196 @@
+/* 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 "msm_camera_eeprom.h"
+
+int32_t msm_camera_eeprom_read(struct msm_eeprom_ctrl_t *ectrl,
+ uint32_t reg_addr, void *data, uint32_t num_byte,
+ uint16_t convert_endian)
+{
+ int rc = 0;
+ if (ectrl->func_tbl.eeprom_set_dev_addr != NULL)
+ ectrl->func_tbl.eeprom_set_dev_addr(ectrl, ®_addr);
+
+ if (!convert_endian) {
+ rc = msm_camera_i2c_read_seq(
+ &ectrl->i2c_client, reg_addr, data, num_byte);
+ } else {
+ unsigned char buf[num_byte];
+ uint8_t *data_ptr = (uint8_t *) data;
+ int i;
+ rc = msm_camera_i2c_read_seq(
+ &ectrl->i2c_client, reg_addr, buf, num_byte);
+ for (i = 0; i < num_byte; i += 2) {
+ data_ptr[i] = buf[i+1];
+ data_ptr[i+1] = buf[i];
+ }
+ }
+ return rc;
+}
+
+int32_t msm_camera_eeprom_read_tbl(struct msm_eeprom_ctrl_t *ectrl,
+ struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size)
+{
+ int i, rc = 0;
+ CDBG("%s: open\n", __func__);
+ if (read_tbl == NULL)
+ return rc;
+
+ for (i = 0; i < tbl_size; i++) {
+ rc = msm_camera_eeprom_read
+ (ectrl, read_tbl[i].reg_addr,
+ read_tbl[i].dest_ptr, read_tbl[i].num_byte,
+ read_tbl[i].convert_endian);
+ if (rc < 0) {
+ pr_err("%s: read failed\n", __func__);
+ return rc;
+ }
+ }
+ CDBG("%s: done\n", __func__);
+ return rc;
+}
+
+int32_t msm_camera_eeprom_get_info(struct msm_eeprom_ctrl_t *ectrl,
+ struct msm_camera_eeprom_info_t *einfo)
+{
+ int rc = 0;
+ CDBG("%s: open\n", __func__);
+ memcpy(einfo, ectrl->info, ectrl->info_size);
+ CDBG("%s: done =%d\n", __func__, rc);
+ return rc;
+}
+
+int32_t msm_camera_eeprom_get_data(struct msm_eeprom_ctrl_t *ectrl,
+ struct msm_eeprom_data_t *edata)
+{
+ int rc = 0;
+ if (edata->index >= ectrl->data_tbl_size)
+ return -EFAULT;
+ if (copy_to_user(edata->eeprom_data,
+ ectrl->data_tbl[edata->index].data,
+ ectrl->data_tbl[edata->index].size))
+ rc = -EFAULT;
+ return rc;
+}
+
+int32_t msm_eeprom_config(struct msm_eeprom_ctrl_t *e_ctrl,
+ void __user *argp)
+{
+ struct msm_eeprom_cfg_data cdata;
+ int32_t rc = 0;
+ if (copy_from_user(&cdata,
+ (void *)argp,
+ sizeof(struct msm_eeprom_cfg_data)))
+ return -EFAULT;
+ mutex_lock(e_ctrl->eeprom_mutex);
+
+ switch (cdata.cfgtype) {
+ case CFG_GET_EEPROM_INFO:
+ if (e_ctrl->func_tbl.eeprom_get_info == NULL) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = e_ctrl->func_tbl.eeprom_get_info(e_ctrl,
+ &cdata.cfg.get_info);
+
+ if (copy_to_user((void *)argp,
+ &cdata,
+ sizeof(struct msm_eeprom_cfg_data)))
+ rc = -EFAULT;
+ break;
+ case CFG_GET_EEPROM_DATA:
+ if (e_ctrl->func_tbl.eeprom_get_data == NULL) {
+ rc = -EFAULT;
+ break;
+ }
+ rc = e_ctrl->func_tbl.eeprom_get_data(e_ctrl,
+ &cdata.cfg.get_data);
+
+ if (copy_to_user((void *)argp,
+ &cdata,
+ sizeof(struct msm_eeprom_cfg_data)))
+ rc = -EFAULT;
+ break;
+ default:
+ break;
+ }
+ mutex_unlock(e_ctrl->eeprom_mutex);
+ return rc;
+}
+
+struct msm_eeprom_ctrl_t *get_ectrl(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct msm_eeprom_ctrl_t, sdev);
+}
+
+long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ struct msm_eeprom_ctrl_t *e_ctrl = get_ectrl(sd);
+ void __user *argp = (void __user *)arg;
+ switch (cmd) {
+ case VIDIOC_MSM_EEPROM_CFG:
+ return msm_eeprom_config(e_ctrl, argp);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct msm_eeprom_ctrl_t *e_ctrl_t = NULL;
+ CDBG("%s called\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ pr_err("i2c_check_functionality failed\n");
+ goto probe_failure;
+ }
+
+ e_ctrl_t = (struct msm_eeprom_ctrl_t *)(id->driver_data);
+ e_ctrl_t->i2c_client.client = client;
+
+ if (e_ctrl_t->i2c_addr != 0)
+ e_ctrl_t->i2c_client.client->addr = e_ctrl_t->i2c_addr;
+
+ CDBG("%s client = %x\n", __func__, (unsigned int) client);
+
+ /* Assign name for sub device */
+ snprintf(e_ctrl_t->sdev.name, sizeof(e_ctrl_t->sdev.name),
+ "%s", e_ctrl_t->i2c_driver->driver.name);
+
+ if (e_ctrl_t->func_tbl.eeprom_init != NULL) {
+ rc = e_ctrl_t->func_tbl.eeprom_init(e_ctrl_t,
+ e_ctrl_t->i2c_client.client->adapter);
+ }
+ msm_camera_eeprom_read_tbl(e_ctrl_t,
+ e_ctrl_t->read_tbl,
+ e_ctrl_t->read_tbl_size);
+
+ if (e_ctrl_t->func_tbl.eeprom_format_data != NULL)
+ e_ctrl_t->func_tbl.eeprom_format_data();
+
+ if (e_ctrl_t->func_tbl.eeprom_release != NULL)
+ rc = e_ctrl_t->func_tbl.eeprom_release(e_ctrl_t);
+
+
+ /* Initialize sub device */
+ v4l2_i2c_subdev_init(&e_ctrl_t->sdev,
+ e_ctrl_t->i2c_client.client,
+ e_ctrl_t->eeprom_v4l2_subdev_ops);
+ CDBG("%s success resut=%d\n", __func__, rc);
+ return rc;
+
+probe_failure:
+ pr_err("%s failed! rc = %d\n", __func__, rc);
+ return rc;
+}
diff --git a/drivers/media/video/msm/eeprom/msm_camera_eeprom.h b/drivers/media/video/msm/eeprom/msm_camera_eeprom.h
new file mode 100644
index 0000000..830e5d8
--- /dev/null
+++ b/drivers/media/video/msm/eeprom/msm_camera_eeprom.h
@@ -0,0 +1,82 @@
+/* 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.
+ */
+#ifndef MSM_CAMERA_EEPROM_H
+#define MSM_CAMERA_EEPROM_H
+
+#include <linux/delay.h>
+#include <mach/camera.h>
+#include <media/v4l2-subdev.h>
+#include "msm_camera_i2c.h"
+
+#define TRUE 1
+#define FALSE 0
+
+struct msm_eeprom_ctrl_t;
+
+struct msm_camera_eeprom_fn_t {
+ int32_t (*eeprom_init)
+ (struct msm_eeprom_ctrl_t *ectrl,
+ struct i2c_adapter *adapter);
+ int32_t (*eeprom_release)
+ (struct msm_eeprom_ctrl_t *ectrl);
+ int32_t (*eeprom_get_info)
+ (struct msm_eeprom_ctrl_t *ectrl,
+ struct msm_camera_eeprom_info_t *einfo);
+ int32_t (*eeprom_get_data)
+ (struct msm_eeprom_ctrl_t *ectrl,
+ struct msm_eeprom_data_t *edata);
+ void (*eeprom_set_dev_addr)
+ (struct msm_eeprom_ctrl_t*, uint32_t*);
+ void (*eeprom_format_data)
+ (void);
+};
+
+struct msm_camera_eeprom_read_t {
+ uint32_t reg_addr;
+ void *dest_ptr;
+ uint32_t num_byte;
+ uint16_t convert_endian;
+};
+
+struct msm_camera_eeprom_data_t {
+ void *data;
+ uint16_t size;
+};
+
+struct msm_eeprom_ctrl_t {
+ struct msm_camera_i2c_client i2c_client;
+ uint16_t i2c_addr;
+ struct i2c_driver *i2c_driver;
+ struct mutex *eeprom_mutex;
+ struct v4l2_subdev sdev;
+ struct v4l2_subdev_ops *eeprom_v4l2_subdev_ops;
+ struct msm_camera_eeprom_fn_t func_tbl;
+ struct msm_camera_eeprom_info_t *info;
+ uint16_t info_size;
+ struct msm_camera_eeprom_read_t *read_tbl;
+ uint16_t read_tbl_size;
+ struct msm_camera_eeprom_data_t *data_tbl;
+ uint16_t data_tbl_size;
+};
+
+int32_t msm_camera_eeprom_get_data(struct msm_eeprom_ctrl_t *ectrl,
+ struct msm_eeprom_data_t *edata);
+int32_t msm_camera_eeprom_get_info(struct msm_eeprom_ctrl_t *ectrl,
+ struct msm_camera_eeprom_info_t *einfo);
+int32_t msm_eeprom_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
+long msm_eeprom_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg);
+
+#define VIDIOC_MSM_EEPROM_CFG \
+ _IOWR('V', BASE_VIDIOC_PRIVATE + 12, void __user *)
+#endif
diff --git a/drivers/media/video/msm/gemini/msm_gemini_platform.c b/drivers/media/video/msm/gemini/msm_gemini_platform.c
index 39b135d..1ebc2f1 100644
--- a/drivers/media/video/msm/gemini/msm_gemini_platform.c
+++ b/drivers/media/video/msm/gemini/msm_gemini_platform.c
@@ -159,7 +159,7 @@
if (pgmn_dev->hw_version != GEMINI_7X) {
if (pgmn_dev->gemini_fs == NULL) {
pgmn_dev->gemini_fs =
- regulator_get(&pgmn_dev->pdev->dev, "fs_ijpeg");
+ regulator_get(&pgmn_dev->pdev->dev, "vdd");
if (IS_ERR(pgmn_dev->gemini_fs)) {
pr_err("%s: Regulator FS_ijpeg get failed %ld\n",
__func__, PTR_ERR(pgmn_dev->gemini_fs));
diff --git a/drivers/media/video/msm/io/Makefile b/drivers/media/video/msm/io/Makefile
index dddcbf6..64df7fb 100644
--- a/drivers/media/video/msm/io/Makefile
+++ b/drivers/media/video/msm/io/Makefile
@@ -3,7 +3,7 @@
obj-$(CONFIG_MSM_CAMERA) += msm_camera_io_util.o
EXTRA_CFLAGS += -Idrivers/media/video/msm
ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
- obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o msm_camera_eeprom.o msm_camera_i2c_mux.o
+ obj-$(CONFIG_MSM_CAMERA) += msm_camera_i2c.o 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_eeprom.c b/drivers/media/video/msm/io/msm_camera_eeprom.c
deleted file mode 100644
index 34dba26..0000000
--- a/drivers/media/video/msm/io/msm_camera_eeprom.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/* 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.
- */
-
-#include "msm_camera_eeprom.h"
-
-int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl,
- struct i2c_adapter *adapter)
-{
- CDBG("%s: open", __func__);
- ectrl->i2c_client->client =
- i2c_new_dummy(adapter, ectrl->i2c_addr >> 1);
- if (ectrl->i2c_client->client == NULL) {
- CDBG("%s: eeprom i2c get client failed\n", __func__);
- return -EFAULT;
- }
- ectrl->i2c_client->client->addr = ectrl->i2c_addr;
- CDBG("%s: done", __func__);
- return 0;
-}
-
-int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl)
-{
- if (ectrl->i2c_client->client != NULL) {
- i2c_unregister_device(ectrl->i2c_client->client);
- ectrl->i2c_client->client = NULL;
- }
- return 0;
-}
-
-int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl,
- uint16_t reg_addr, void *data, uint32_t num_byte,
- uint16_t convert_endian)
-{
- int rc = 0;
- if (ectrl->func_tbl.eeprom_set_dev_addr != NULL)
- ectrl->func_tbl.eeprom_set_dev_addr(ectrl, ®_addr);
-
- if (!convert_endian) {
- rc = msm_camera_i2c_read_seq(
- ectrl->i2c_client, reg_addr, data, num_byte);
- } else {
- unsigned char buf[num_byte];
- uint8_t *data_ptr = (uint8_t *) data;
- int i;
- rc = msm_camera_i2c_read_seq(
- ectrl->i2c_client, reg_addr, buf, num_byte);
- for (i = 0; i < num_byte; i++)
- data_ptr[i] = buf[num_byte-i-1];
- }
- return rc;
-}
-
-int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl,
- struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size)
-{
- int i, rc = 0;
- CDBG("%s: open", __func__);
- if (read_tbl == NULL)
- return rc;
-
- for (i = 0; i < tbl_size; i++) {
- rc = msm_camera_eeprom_read
- (ectrl, read_tbl[i].reg_addr,
- read_tbl[i].dest_ptr, read_tbl[i].num_byte,
- read_tbl[i].convert_endian);
- if (rc < 0) {
- CDBG("%s: read failed\n", __func__);
- return rc;
- }
- }
- CDBG("%s: done", __func__);
- return rc;
-}
-
-int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl,
- struct sensor_eeprom_data_t *edata)
-{
- int rc = 0;
- if (edata->index >= ectrl->data_tbl_size)
- return -EFAULT;
- if (copy_to_user(edata->eeprom_data,
- ectrl->data_tbl[edata->index].data,
- ectrl->data_tbl[edata->index].size))
- rc = -EFAULT;
- return rc;
-}
-
diff --git a/drivers/media/video/msm/io/msm_camera_eeprom.h b/drivers/media/video/msm/io/msm_camera_eeprom.h
deleted file mode 100644
index 9dd7b54..0000000
--- a/drivers/media/video/msm/io/msm_camera_eeprom.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* 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.
- */
-
-#include <linux/delay.h>
-#include <mach/camera.h>
-#include "msm_camera_i2c.h"
-
-struct msm_camera_eeprom_client;
-
-struct msm_camera_eeprom_fn_t {
- int32_t (*eeprom_init)
- (struct msm_camera_eeprom_client *ectrl,
- struct i2c_adapter *adapter);
- int32_t (*eeprom_release)
- (struct msm_camera_eeprom_client *ectrl);
- int32_t (*eeprom_get_data)
- (struct msm_camera_eeprom_client *ectrl,
- struct sensor_eeprom_data_t *edata);
- void (*eeprom_set_dev_addr)
- (struct msm_camera_eeprom_client*, uint16_t*);
-};
-
-struct msm_camera_eeprom_read_t {
- uint16_t reg_addr;
- void *dest_ptr;
- uint32_t num_byte;
- uint16_t convert_endian;
-};
-
-struct msm_camera_eeprom_data_t {
- void *data;
- uint16_t size;
-};
-
-struct msm_camera_eeprom_client {
- struct msm_camera_i2c_client *i2c_client;
- uint16_t i2c_addr;
- struct msm_camera_eeprom_fn_t func_tbl;
- struct msm_camera_eeprom_read_t *read_tbl;
- uint16_t read_tbl_size;
- struct msm_camera_eeprom_data_t *data_tbl;
- uint16_t data_tbl_size;
-};
-
-int32_t msm_camera_eeprom_init(struct msm_camera_eeprom_client *ectrl,
- struct i2c_adapter *adapter);
-int32_t msm_camera_eeprom_release(struct msm_camera_eeprom_client *ectrl);
-int32_t msm_camera_eeprom_read(struct msm_camera_eeprom_client *ectrl,
- uint16_t reg_addr, void *data, uint32_t num_byte,
- uint16_t convert_endian);
-int32_t msm_camera_eeprom_read_tbl(struct msm_camera_eeprom_client *ectrl,
- struct msm_camera_eeprom_read_t *read_tbl, uint16_t tbl_size);
-int32_t msm_camera_eeprom_get_data(struct msm_camera_eeprom_client *ectrl,
- struct sensor_eeprom_data_t *edata);
-
-
-
diff --git a/drivers/media/video/msm/io/msm_camera_i2c.c b/drivers/media/video/msm/io/msm_camera_i2c.c
index a3cc012..6f45637 100644
--- a/drivers/media/video/msm/io/msm_camera_i2c.c
+++ b/drivers/media/video/msm/io/msm_camera_i2c.c
@@ -252,7 +252,7 @@
enum msm_camera_i2c_data_type dt;
if (reg_conf_tbl->cmd_type == MSM_CAMERA_I2C_CMD_POLL) {
rc = msm_camera_i2c_poll(client, reg_conf_tbl->reg_addr,
- reg_conf_tbl->reg_addr, reg_conf_tbl->dt);
+ reg_conf_tbl->reg_data, reg_conf_tbl->dt);
} else {
if (reg_conf_tbl->dt == 0)
dt = data_type;
diff --git a/drivers/media/video/msm/io/msm_camera_io_util.c b/drivers/media/video/msm/io/msm_camera_io_util.c
index af60426..4049266 100644
--- a/drivers/media/video/msm/io/msm_camera_io_util.c
+++ b/drivers/media/video/msm/io/msm_camera_io_util.c
@@ -370,7 +370,7 @@
usleep_range(gpio_conf->cam_gpio_set_tbl[i].delay,
gpio_conf->cam_gpio_set_tbl[i].delay + 1000);
}
- } else if (!gpio_conf->gpio_no_mux) {
+ } else {
for (i = gpio_conf->cam_gpio_set_tbl_size - 1; i >= 0; i--) {
if (gpio_conf->cam_gpio_set_tbl[i].flags)
gpio_set_value_cansleep(
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 668fd8e..fa9aace 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -26,6 +26,7 @@
#include "msm_sensor.h"
#include "msm_actuator.h"
#include "msm_vfe32.h"
+#include "msm_camera_eeprom.h"
#define MSM_MAX_CAMERA_SENSORS 5
@@ -560,7 +561,10 @@
ctrlcmd.type = MSM_V4L2_SET_CTRL_CMD;
ctrlcmd.length = cmd_len + value_len;
ctrlcmd.value = (void *)ctrl_data;
- ctrlcmd.timeout_ms = 1000;
+ if (tmp_cmd->timeout_ms > 0)
+ ctrlcmd.timeout_ms = tmp_cmd->timeout_ms;
+ else
+ ctrlcmd.timeout_ms = 1000;
ctrlcmd.vnode_id = pcam->vnode_id;
ctrlcmd.queue_idx = pcam->server_queue_idx;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
@@ -1564,6 +1568,7 @@
struct msm_cam_v4l2_device *pcam = video_drvdata(f);
struct msm_cam_v4l2_dev_inst *pcam_inst;
struct msm_cam_media_controller *pmctl = NULL;
+ struct msm_cam_server_queue *queue = NULL;
D("%s\n", __func__);
@@ -1605,12 +1610,11 @@
pcam->vnode_id, pcam->use_count);
pcam->use_count++;
if (pcam->use_count == 1) {
- struct msm_cam_server_queue *queue;
pcam->server_queue_idx = server_q_idx;
queue = &g_server_dev.server_queue[server_q_idx];
queue->ctrl = NULL;
queue->ctrl_data = kzalloc(sizeof(uint8_t) *
- max_control_command_size, GFP_KERNEL);
+ max_control_command_size, GFP_KERNEL);
msm_queue_init(&queue->ctrl_q, "control");
msm_queue_init(&queue->eventData_q, "eventdata");
queue->queue_active = 1;
@@ -1619,7 +1623,7 @@
if (rc < 0) {
pr_err("%s: cam_server_open_session failed %d\n",
__func__, rc);
- goto err;
+ goto msm_cam_server_open_session_failed;
}
pmctl = msm_camera_get_mctl(pcam->mctl_handle);
@@ -1632,26 +1636,26 @@
/* Should be set to sensor ops if any but right now its OK!! */
if (!pmctl->mctl_open) {
- D("%s: media contoller is not inited\n",
- __func__);
+ D("%s: media contoller is not inited\n", __func__);
rc = -ENODEV;
- goto err;
+ goto mctl_open_failed;
}
/* Now we really have to activate the camera */
D("%s: call mctl_open\n", __func__);
rc = pmctl->mctl_open(pmctl, MSM_APPS_ID_V4L2);
-
if (rc < 0) {
pr_err("%s: HW open failed rc = 0x%x\n", __func__, rc);
- goto err;
+ goto mctl_open_failed;
}
pmctl->pcam_ptr = pcam;
rc = msm_setup_v4l2_event_queue(&pcam_inst->eventHandle,
- pcam->pvdev);
+ pcam->pvdev);
if (rc < 0) {
- goto err;
+ pr_err("%s: msm_setup_v4l2_event_queue failed %d",
+ __func__, rc);
+ goto mctl_event_q_setup_failed;
}
}
pcam_inst->vbqueue_initialized = 0;
@@ -1662,21 +1666,26 @@
D("f->private_data = 0x%x, pcam = 0x%x\n",
(u32)f->private_data, (u32)pcam_inst);
-
if (pcam->use_count == 1) {
rc = msm_send_open_server(pcam);
if (rc < 0) {
- mutex_unlock(&pcam->vid_lock);
- pr_err("%s failed\n", __func__);
- return rc;
+ pr_err("%s: msm_send_open_server failed %d\n",
+ __func__, rc);
+ goto msm_send_open_server_failed;
}
}
mutex_unlock(&pcam->vid_lock);
D("%s: end", __func__);
- /* rc = msm_cam_server_open_session(g_server_dev, pcam);*/
return rc;
-err:
+msm_send_open_server_failed:
+ v4l2_fh_del(&pcam_inst->eventHandle);
+ v4l2_fh_exit(&pcam_inst->eventHandle);
+mctl_event_q_setup_failed:
+ if (pmctl->mctl_release)
+ if (pmctl->mctl_release(pmctl) < 0)
+ pr_err("%s: mctl_release failed\n", __func__);
+mctl_open_failed:
if (pcam->use_count == 1) {
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
if (ion_client_created) {
@@ -1684,6 +1693,20 @@
kref_put(&pmctl->refcount, msm_release_ion_client);
}
#endif
+ if (msm_cam_server_close_session(&g_server_dev, pcam) < 0)
+ pr_err("%s: msm_cam_server_close_session failed\n",
+ __func__);
+ }
+msm_cam_server_open_session_failed:
+ if (pcam->use_count == 1) {
+ queue->queue_active = 0;
+ msm_drain_eventq(&queue->eventData_q);
+ kfree(queue->ctrl_data);
+ queue->ctrl_data = NULL;
+ msm_queue_drain(&queue->ctrl_q, list_control);
+ msm_drain_eventq(&queue->eventData_q);
+ queue = NULL;
+
pcam->dev_inst[i] = NULL;
pcam->use_count = 0;
}
@@ -1905,16 +1928,18 @@
switch (cmd) {
case MSM_CAM_V4L2_IOCTL_GET_CAMERA_INFO:
if (copy_from_user(&temp_cam_info,
- (void __user *)ioctl_ptr->ioctl_ptr,
- sizeof(struct msm_camera_info))) {
+ (void __user *)ioctl_ptr->ioctl_ptr,
+ sizeof(struct msm_camera_info))) {
rc = -EINVAL;
return rc;
}
for (i = 0; i < g_server_dev.camera_info.num_cameras; i++) {
if (copy_to_user((void __user *)
- temp_cam_info.video_dev_name[i],
- g_server_dev.camera_info.video_dev_name[i],
- strlen(g_server_dev.camera_info.video_dev_name[i]))) {
+ temp_cam_info.video_dev_name[i],
+ g_server_dev.camera_info.video_dev_name[i],
+ strnlen(
+ g_server_dev.camera_info.video_dev_name[i],
+ MAX_DEV_NAME_LEN))) {
rc = -EINVAL;
return rc;
}
@@ -2055,6 +2080,7 @@
break;
}
default:
+ pr_err("%s: Invalid IOCTL = %d", __func__, cmd);
break;
}
return rc;
@@ -2148,7 +2174,7 @@
D("%s: cmd %d\n", __func__, _IOC_NR(cmd));
switch (cmd) {
- /* memory management shall be handeld here*/
+ /* memory management shall be handeld here*/
case MSM_CAM_IOCTL_REGISTER_PMEM:
return msm_register_pmem(
&config_cam->p_mctl->stats_info.pmem_stats_list,
@@ -2160,31 +2186,38 @@
&config_cam->p_mctl->stats_info.pmem_stats_list,
(void __user *)arg, config_cam->p_mctl->client);
break;
+
case VIDIOC_SUBSCRIBE_EVENT:
if (copy_from_user(&temp_sub,
(void __user *)arg,
sizeof(struct v4l2_event_subscription))) {
- rc = -EINVAL;
- return rc;
+ rc = -EINVAL;
+ return rc;
}
rc = msm_server_v4l2_subscribe_event
(&config_cam->config_stat_event_queue.eventHandle,
- &temp_sub);
- if (rc < 0)
+ &temp_sub);
+ if (rc < 0) {
+ pr_err("%s: cam_v4l2_subscribe_event failed rc=%d\n",
+ __func__, rc);
return rc;
+ }
break;
case VIDIOC_UNSUBSCRIBE_EVENT:
if (copy_from_user(&temp_sub, (void __user *)arg,
- sizeof(struct v4l2_event_subscription))) {
+ sizeof(struct v4l2_event_subscription))) {
rc = -EINVAL;
return rc;
}
rc = msm_server_v4l2_unsubscribe_event
(&config_cam->config_stat_event_queue.eventHandle,
- &temp_sub);
- if (rc < 0)
+ &temp_sub);
+ if (rc < 0) {
+ pr_err("%s: server_unsubscribe_event failed rc=%d\n",
+ __func__, rc);
return rc;
+ }
break;
case VIDIOC_DQEVENT: {
@@ -2330,8 +2363,8 @@
static int msm_open_config(struct inode *inode, struct file *fp)
{
int rc;
- struct msm_cam_config_dev *config_cam =
- container_of(inode->i_cdev, struct msm_cam_config_dev, config_cdev);
+ struct msm_cam_config_dev *config_cam = container_of(inode->i_cdev,
+ struct msm_cam_config_dev, config_cdev);
D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
@@ -2351,16 +2384,20 @@
spin_lock_init(&config_cam->p_mctl->stats_info.pmem_stats_spinlock);
config_cam->p_mctl->config_device = config_cam;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
kref_get(&config_cam->p_mctl->refcount);
+#endif
fp->private_data = config_cam;
return rc;
}
static int msm_close_config(struct inode *node, struct file *f)
{
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
struct msm_cam_config_dev *config_cam = f->private_data;
D("%s Decrementing ref count of config node ", __func__);
kref_put(&config_cam->p_mctl->refcount, msm_release_ion_client);
+#endif
return 0;
}
@@ -2400,7 +2437,7 @@
};
int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
- struct video_device *pvdev)
+ struct video_device *pvdev)
{
int rc = 0;
/* v4l2_fh support */
@@ -2410,6 +2447,7 @@
rc = v4l2_fh_init(eventHandle, pvdev);
if (rc < 0)
return rc;
+
if (eventHandle->events == NULL) {
rc = v4l2_event_init(eventHandle);
if (rc < 0)
@@ -2423,7 +2461,6 @@
v4l2_fh_add(eventHandle);
return rc;
-
}
static int msm_setup_config_dev(int node, char *device_name)
@@ -2444,8 +2481,8 @@
D("%s\n", __func__);
devno = MKDEV(MAJOR(msm_devno), dev_num+1);
- device_config = device_create(msm_class, NULL, devno, NULL,
- "%s%d", device_name, dev_num);
+ device_config = device_create(msm_class, NULL, devno, NULL, "%s%d",
+ device_name, dev_num);
if (IS_ERR(device_config)) {
rc = PTR_ERR(device_config);
@@ -2453,8 +2490,7 @@
goto config_setup_fail;
}
- cdev_init(&config_cam->config_cdev,
- &msm_fops_config);
+ cdev_init(&config_cam->config_cdev, &msm_fops_config);
config_cam->config_cdev.owner = THIS_MODULE;
rc = cdev_add(&config_cam->config_cdev, devno, 1);
@@ -2463,12 +2499,12 @@
device_destroy(msm_class, devno);
goto config_setup_fail;
}
- g_server_dev.config_info.config_dev_name[dev_num]
- = dev_name(device_config);
+
+ g_server_dev.config_info.config_dev_name[dev_num] =
+ dev_name(device_config);
D("%s Connected config device %s\n", __func__,
g_server_dev.config_info.config_dev_name[dev_num]);
- g_server_dev.config_info.config_dev_id[dev_num]
- = dev_num;
+ g_server_dev.config_info.config_dev_id[dev_num] = dev_num;
config_cam->config_stat_event_queue.pvdev = video_device_alloc();
if (config_cam->config_stat_event_queue.pvdev == NULL) {
@@ -2481,6 +2517,7 @@
config_cam->config_stat_event_queue.pvdev);
if (rc < 0) {
pr_err("%s failed to initialize event queue\n", __func__);
+ video_device_release(config_cam->config_stat_event_queue.pvdev);
goto config_setup_fail;
}
@@ -2489,7 +2526,6 @@
config_setup_fail:
kfree(config_cam);
return rc;
-
}
static void msm_cam_server_subdev_notify(struct v4l2_subdev *sd,
@@ -2693,13 +2729,13 @@
video_set_drvdata(g_server_dev.video_dev, &g_server_dev);
strlcpy(g_server_dev.media_dev.model, "qcamera",
- sizeof(g_server_dev.media_dev.model));
+ sizeof(g_server_dev.media_dev.model));
g_server_dev.media_dev.dev = &pdev->dev;
rc = media_device_register(&g_server_dev.media_dev);
g_server_dev.v4l2_dev.mdev = &g_server_dev.media_dev;
rc = video_register_device(g_server_dev.video_dev,
- VFL_TYPE_GRABBER, 100);
+ VFL_TYPE_GRABBER, 100);
mutex_init(&g_server_dev.server_lock);
mutex_init(&g_server_dev.server_queue_lock);
@@ -2715,8 +2751,11 @@
&g_server_dev.server_command_queue.eventHandle,
g_server_dev.server_command_queue.pvdev);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s failed to initialize event queue\n", __func__);
+ video_device_release(g_server_dev.server_command_queue.pvdev);
+ return rc;
+ }
for (i = 0; i < MAX_NUM_ACTIVE_CAMERA; i++) {
struct msm_cam_server_queue *queue;
@@ -2855,6 +2894,43 @@
return NULL;
}
+static struct v4l2_subdev *msm_eeprom_probe(
+ struct msm_eeprom_info *eeprom_info)
+{
+ struct v4l2_subdev *eeprom_sdev;
+ struct i2c_adapter *adapter = NULL;
+ void *eeprom_client = NULL;
+
+ D("%s called\n", __func__);
+
+ if (!eeprom_info)
+ goto probe_fail;
+
+ adapter = i2c_get_adapter(eeprom_info->bus_id);
+ if (!adapter)
+ goto probe_fail;
+
+ eeprom_client = i2c_new_device(adapter, eeprom_info->board_info);
+ if (!eeprom_client)
+ goto device_fail;
+
+ eeprom_sdev = (struct v4l2_subdev *)i2c_get_clientdata(eeprom_client);
+ if (eeprom_sdev == NULL)
+ goto client_fail;
+
+ return eeprom_sdev;
+client_fail:
+ pr_err("%s client_fail\n", __func__);
+ i2c_unregister_device(eeprom_client);
+device_fail:
+ pr_err("%s device_fail\n", __func__);
+ i2c_put_adapter(adapter);
+ adapter = NULL;
+probe_fail:
+ pr_err("%s probe_fail\n", __func__);
+ return NULL;
+}
+
/* register a msm sensor into the msm device, which will probe the
* sensor HW. if the HW exist then create a video device (/dev/videoX/)
* to represent this sensor */
@@ -2880,6 +2956,7 @@
sdata = (struct msm_camera_sensor_info *) s_ctrl->sensordata;
pcam->act_sdev = msm_actuator_probe(sdata->actuator_info);
+ pcam->eeprom_sdev = msm_eeprom_probe(sdata->eeprom_info);
D("%s: pcam =0x%p\n", __func__, pcam);
@@ -2964,6 +3041,15 @@
}
}
+ if (pcam->eeprom_sdev) {
+ rc = v4l2_device_register_subdev(&pcam->v4l2_dev,
+ pcam->eeprom_sdev);
+ if (rc < 0) {
+ D("%s eeprom sub device register failed\n", __func__);
+ goto failure;
+ }
+ }
+
pcam->vnode_id = vnode_count++;
return rc;
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index fa97e22..04e224c 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -68,6 +68,7 @@
VPE_DEV,
SENSOR_DEV,
ACTUATOR_DEV,
+ EEPROM_DEV,
};
/* msm queue management APIs*/
@@ -243,7 +244,8 @@
struct v4l2_subdev *ispif_sdev; /* ispif sub device */
struct v4l2_subdev *gemini_sdev; /* gemini sub device */
struct v4l2_subdev *vpe_sdev; /* vpe sub device */
- struct v4l2_subdev *axi_sdev; /* vpe sub device */
+ struct v4l2_subdev *axi_sdev; /* axi sub device */
+ struct v4l2_subdev *eeprom_sdev; /* eeprom sub device */
struct msm_isp_ops *isp_sdev; /* isp sub device : camif/VFE */
struct msm_cam_config_dev *config_device;
@@ -355,6 +357,7 @@
struct v4l2_subdev *sensor_sdev; /* sensor sub device */
struct v4l2_subdev *act_sdev; /* actuator sub device */
+ struct v4l2_subdev *eeprom_sdev; /* actuator sub device */
struct msm_camera_sensor_info *sdata;
};
diff --git a/drivers/media/video/msm/msm_isp.c b/drivers/media/video/msm/msm_isp.c
index 5b3101b..d678d86 100644
--- a/drivers/media/video/msm/msm_isp.c
+++ b/drivers/media/video/msm/msm_isp.c
@@ -618,6 +618,8 @@
switch (cfgcmd.cmd_type) {
case CMD_AXI_CFG_PRIM:
case CMD_AXI_CFG_SEC:
+ case CMD_AXI_CFG_ZSL:
+ case CMD_RAW_PICT_AXI_CFG:
case CMD_AXI_CFG_PRIM_ALL_CHNLS:
case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC:
case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS:
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 4a15b7a..e878063 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -36,6 +36,7 @@
#include "msm_actuator.h"
#include "msm_vpe.h"
#include "msm_vfe32.h"
+#include "msm_camera_eeprom.h"
#ifdef CONFIG_MSM_CAMERA_DEBUG
#define D(fmt, args...) pr_debug("msm_mctl: " fmt, ##args)
@@ -311,6 +312,33 @@
break;
}
+ case MSM_CAM_IOCTL_EEPROM_IO_CFG: {
+ struct msm_eeprom_cfg_data eeprom_data;
+ if (p_mctl->eeprom_sdev) {
+ eeprom_data.is_eeprom_supported = 1;
+ rc = v4l2_subdev_call(p_mctl->eeprom_sdev,
+ core, ioctl, VIDIOC_MSM_EEPROM_CFG, argp);
+ } else {
+ rc = copy_from_user(
+ &eeprom_data,
+ (void *)argp,
+ sizeof(struct msm_eeprom_cfg_data));
+ if (rc != 0) {
+ rc = -EFAULT;
+ break;
+ }
+ eeprom_data.is_eeprom_supported = 0;
+ rc = copy_to_user((void *)argp,
+ &eeprom_data,
+ sizeof(struct msm_eeprom_cfg_data));
+ if (rc != 0) {
+ rc = -EFAULT;
+ break;
+ }
+ }
+ break;
+ }
+
case MSM_CAM_IOCTL_GET_KERNEL_SYSTEM_TIME: {
struct timeval timestamp;
if (copy_from_user(×tamp, argp, sizeof(timestamp))) {
@@ -555,23 +583,22 @@
if (rc < 0) {
pr_err("%s: msm_mctl_register_subdevs failed:%d\n",
__func__, rc);
- goto msm_open_done;
+ goto register_sdev_failed;
}
- /* then sensor - move sub dev later*/
+ /* then sensor - move sub dev later */
rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
-
if (rc < 0) {
- pr_err("%s: isp init failed: %d\n", __func__, rc);
- goto msm_open_done;
+ pr_err("%s: sensor powerup failed: %d\n", __func__, rc);
+ goto sensor_sdev_failed;
}
+
if (p_mctl->act_sdev)
rc = v4l2_subdev_call(p_mctl->act_sdev,
- core, s_power, 1);
-
+ core, s_power, 1);
if (rc < 0) {
pr_err("%s: act power failed:%d\n", __func__, rc);
- goto msm_open_done;
+ goto act_power_up_failed;
}
if (camdev->is_csiphy) {
@@ -579,8 +606,8 @@
VIDIOC_MSM_CSIPHY_INIT, NULL);
if (rc < 0) {
pr_err("%s: csiphy initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __func__, rc);
+ goto csiphy_init_failed;
}
}
@@ -589,17 +616,18 @@
VIDIOC_MSM_CSID_INIT, &csid_version);
if (rc < 0) {
pr_err("%s: csid initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __func__, rc);
+ goto csid_init_failed;
}
}
+
if (camdev->is_csic) {
rc = v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
VIDIOC_MSM_CSIC_INIT, &csid_version);
if (rc < 0) {
pr_err("%s: csic initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __func__, rc);
+ goto csic_init_failed;
}
}
@@ -610,7 +638,7 @@
if (rc < 0) {
pr_err("%s: isp init failed: %d\n",
__func__, rc);
- goto msm_open_done;
+ goto isp_open_failed;
}
}
@@ -618,9 +646,9 @@
rc = v4l2_subdev_call(p_mctl->axi_sdev, core, ioctl,
VIDIOC_MSM_AXI_INIT, p_mctl);
if (rc < 0) {
- pr_err("%s: vpe initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ pr_err("%s: axi initialization failed %d\n",
+ __func__, rc);
+ goto axi_init_failed;
}
}
@@ -630,7 +658,7 @@
if (rc < 0) {
pr_err("%s: vpe initialization failed %d\n",
__func__, rc);
- goto msm_open_done;
+ goto vpe_init_failed;
}
}
@@ -639,23 +667,65 @@
VIDIOC_MSM_ISPIF_INIT, &csid_version);
if (rc < 0) {
pr_err("%s: ispif initialization failed %d\n",
- __func__, rc);
- goto msm_open_done;
+ __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_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
pm_qos_update_request(&p_mctl->pm_qos_req_list,
- MSM_V4L2_SWFI_LATENCY);
+ MSM_V4L2_SWFI_LATENCY);
}
p_mctl->apps_id = apps_id;
p_mctl->opencnt++;
+ } else {
+ D("%s: camera is already open", __func__);
}
+ mutex_unlock(&p_mctl->lock);
-msm_open_done:
+ 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,
+ VIDIOC_MSM_AXI_RELEASE, NULL) < 0)
+ 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);
+isp_open_failed:
+ if (camdev->is_csic)
+ 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 (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 (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);
+csiphy_init_failed:
+ if (p_mctl->act_sdev)
+ if (v4l2_subdev_call(p_mctl->act_sdev, core,
+ s_power, 0) < 0)
+ pr_err("%s: act power down failed:%d\n", __func__, rc);
+act_power_up_failed:
+ if (v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0) < 0)
+ pr_err("%s: sensor powerdown failed: %d\n", __func__, rc);
+sensor_sdev_failed:
+register_sdev_failed:
+ wake_unlock(&p_mctl->wake_lock);
mutex_unlock(&p_mctl->lock);
return rc;
}
@@ -815,6 +885,7 @@
spin_lock_init(&pmctl->pp_info.lock);
pmctl->act_sdev = pcam->act_sdev;
+ pmctl->eeprom_sdev = pcam->eeprom_sdev;
pmctl->sensor_sdev = pcam->sensor_sdev;
pmctl->sdata = pcam->sdata;
diff --git a/drivers/media/video/msm/msm_vfe32.c b/drivers/media/video/msm/msm_vfe32.c
index e265b25..becdd95 100644
--- a/drivers/media/video/msm/msm_vfe32.c
+++ b/drivers/media/video/msm/msm_vfe32.c
@@ -4177,16 +4177,18 @@
switch (cmd) {
case VIDIOC_MSM_AXI_INIT:
rc = msm_axi_subdev_init(sd,
- (struct msm_cam_media_controller *)arg);
+ (struct msm_cam_media_controller *)arg);
break;
case VIDIOC_MSM_AXI_CFG:
rc = msm_axi_config(sd, arg);
break;
case VIDIOC_MSM_AXI_IRQ:
msm_axi_process_irq(sd, arg);
+ rc = 0;
break;
case VIDIOC_MSM_AXI_RELEASE:
msm_axi_subdev_release(sd);
+ rc = 0;
break;
default:
pr_err("%s: command not found\n", __func__);
diff --git a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
index 40154ef..dd567d1 100644
--- a/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
+++ b/drivers/media/video/msm/msm_vfe7x27a_v4l2.c
@@ -22,6 +22,7 @@
#include <media/v4l2-subdev.h>
#include <media/msm_isp.h>
#include <mach/msm_adsp.h>
+#include <linux/clk.h>
#include <mach/clk.h>
#include <mach/camera.h>
#include "msm_vfe7x27a_v4l2.h"
@@ -408,7 +409,7 @@
CDBG("%s:id=%d\n", __func__, id);
if (id != VFE_ADSP_EVENT) {
- data = kzalloc(len, GFP_KERNEL);
+ data = kzalloc(len, GFP_ATOMIC);
if (!data) {
pr_err("%s: rp: cannot allocate buffer\n", __func__);
return;
@@ -1729,12 +1730,38 @@
return;
}
+static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+ u32 freq, u32 flags)
+{
+ int rc = 0;
+ int round_rate;
+
+ round_rate = clk_round_rate(vfe2x_ctrl->vfe_clk[0], freq);
+ if (rc < 0) {
+ pr_err("%s: clk_round_rate failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ rc = clk_set_rate(vfe2x_ctrl->vfe_clk[0], round_rate);
+ if (rc < 0)
+ pr_err("%s: clk_set_rate failed %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = {
+ .s_crystal_freq = msm_vfe_subdev_s_crystal_freq,
+};
+
static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
.ioctl = msm_vfe_subdev_ioctl,
};
static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
.core = &msm_vfe_subdev_core_ops,
+ .video = &msm_vfe_subdev_video_ops,
};
static const struct v4l2_subdev_internal_ops msm_vfe_internal_ops;
diff --git a/drivers/media/video/msm/msm_vpe.c b/drivers/media/video/msm/msm_vpe.c
index b7376dc..71c10ad 100644
--- a/drivers/media/video/msm/msm_vpe.c
+++ b/drivers/media/video/msm/msm_vpe.c
@@ -50,10 +50,12 @@
/* enable the frame irq, bit 0 = Display list 0 ROI done */
msm_camera_io_w_mb(1, vpe_ctrl->vpebase + VPE_INTR_ENABLE_OFFSET);
msm_camera_io_dump(vpe_ctrl->vpebase, 0x120);
+ msm_camera_io_dump(vpe_ctrl->vpebase + 0x00400, 0x18);
msm_camera_io_dump(vpe_ctrl->vpebase + 0x10000, 0x250);
msm_camera_io_dump(vpe_ctrl->vpebase + 0x30000, 0x20);
msm_camera_io_dump(vpe_ctrl->vpebase + 0x50000, 0x30);
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();
@@ -756,7 +758,7 @@
}
rc = request_irq(vpe_ctrl->vpeirq->start, vpe_parse_irq,
- IRQF_TRIGGER_RISING, "vfe", 0);
+ IRQF_TRIGGER_RISING, "vpe", 0);
if (rc < 0) {
release_mem_region(vpe_ctrl->vpemem->start,
resource_size(vpe_ctrl->vpemem));
diff --git a/drivers/media/video/msm/msm_vpe.h b/drivers/media/video/msm/msm_vpe.h
index 553ee4f..0d14626 100644
--- a/drivers/media/video/msm/msm_vpe.h
+++ b/drivers/media/video/msm/msm_vpe.h
@@ -60,7 +60,8 @@
#define VPE_SCALE_COEFF_LSP_0_OFFSET 0x50400
#define VPE_SCALE_COEFF_MSP_0_OFFSET 0x50404
-#define VPE_AXI_ARB_2_OFFSET 0x004C
+#define VPE_AXI_ARB_1_OFFSET 0x00408
+#define VPE_AXI_ARB_2_OFFSET 0x0040C
#define VPE_SCALE_COEFF_LSBn(n) (0x50400 + 8 * (n))
#define VPE_SCALE_COEFF_MSBn(n) (0x50404 + 8 * (n))
diff --git a/drivers/media/video/msm/sensors/Makefile b/drivers/media/video/msm/sensors/Makefile
index 07cea70..13dc446 100644
--- a/drivers/media/video/msm/sensors/Makefile
+++ b/drivers/media/video/msm/sensors/Makefile
@@ -1,6 +1,7 @@
GCC_VERSION := $(shell $(CONFIG_SHELL) $(PWD)/scripts/gcc-version.sh $(CROSS_COMPILE)gcc)
EXTRA_CFLAGS += -Idrivers/media/video/msm
EXTRA_CFLAGS += -Idrivers/media/video/msm/io
+EXTRA_CFLAGS += -Idrivers/media/video/msm/eeprom
EXTRA_CFLAGS += -Idrivers/media/video/msm/csi
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
obj-$(CONFIG_OV5647) += ov5647_v4l2.o
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index 67b7140..7e41418 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -224,8 +224,6 @@
.vert_offset = 3,
};
-static struct sensor_calib_data imx074_calib_data;
-
static const struct i2c_device_id imx074_i2c_id[] = {
{SENSOR_NAME, (kernel_ulong_t)&imx074_s_ctrl},
{ }
@@ -243,37 +241,6 @@
.addr_type = MSM_CAMERA_I2C_WORD_ADDR,
};
-static struct msm_camera_i2c_client imx074_eeprom_i2c_client = {
- .addr_type = MSM_CAMERA_I2C_BYTE_ADDR,
-};
-
-static struct msm_camera_eeprom_read_t imx074_eeprom_read_tbl[] = {
- {0x10, &imx074_calib_data.r_over_g, 2, 1},
- {0x12, &imx074_calib_data.b_over_g, 2, 1},
- {0x14, &imx074_calib_data.gr_over_gb, 2, 1},
-};
-
-static struct msm_camera_eeprom_data_t imx074_eeprom_data_tbl[] = {
- {&imx074_calib_data, sizeof(struct sensor_calib_data)},
-};
-
-static struct msm_camera_eeprom_client imx074_eeprom_client = {
- .i2c_client = &imx074_eeprom_i2c_client,
- .i2c_addr = 0xA4,
-
- .func_tbl = {
- .eeprom_set_dev_addr = NULL,
- .eeprom_init = msm_camera_eeprom_init,
- .eeprom_release = msm_camera_eeprom_release,
- .eeprom_get_data = msm_camera_eeprom_get_data,
- },
-
- .read_tbl = imx074_eeprom_read_tbl,
- .read_tbl_size = ARRAY_SIZE(imx074_eeprom_read_tbl),
- .data_tbl = imx074_eeprom_data_tbl,
- .data_tbl_size = ARRAY_SIZE(imx074_eeprom_data_tbl),
-};
-
static int __init msm_sensor_init_module(void)
{
return i2c_add_driver(&imx074_i2c_driver);
@@ -309,6 +276,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
};
static struct msm_sensor_reg_t imx074_regs = {
@@ -333,7 +301,6 @@
.msm_sensor_reg = &imx074_regs,
.sensor_i2c_client = &imx074_sensor_i2c_client,
.sensor_i2c_addr = 0x34,
- .sensor_eeprom_client = &imx074_eeprom_client,
.sensor_output_reg_addr = &imx074_reg_addr,
.sensor_id_info = &imx074_id_info,
.sensor_exp_gain_info = &imx074_exp_gain_info,
diff --git a/drivers/media/video/msm/sensors/imx091.c b/drivers/media/video/msm/sensors/imx091.c
index 62e97ac..70c3f6e 100644
--- a/drivers/media/video/msm/sensors/imx091.c
+++ b/drivers/media/video/msm/sensors/imx091.c
@@ -303,6 +303,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
};
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 cc56ccf..ff5bb49 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -16,6 +16,32 @@
#include "msm_camera_i2c_mux.h"
/*=============================================================*/
+int32_t msm_sensor_adjust_frame_lines(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t res)
+{
+ uint16_t cur_line = 0;
+ uint16_t exp_fl_lines = 0;
+ if (s_ctrl->sensor_exp_gain_info) {
+ msm_camera_i2c_read(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
+ &cur_line,
+ MSM_CAMERA_I2C_WORD_DATA);
+ exp_fl_lines = cur_line +
+ s_ctrl->sensor_exp_gain_info->vert_offset;
+ if (exp_fl_lines > s_ctrl->msm_sensor_reg->
+ output_settings[res].frame_length_lines)
+ msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
+ s_ctrl->sensor_output_reg_addr->
+ frame_length_lines,
+ exp_fl_lines,
+ MSM_CAMERA_I2C_WORD_DATA);
+ CDBG("%s cur_fl_lines %d, exp_fl_lines %d\n", __func__,
+ s_ctrl->msm_sensor_reg->
+ output_settings[res].frame_length_lines,
+ exp_fl_lines);
+ }
+ return 0;
+}
int32_t msm_sensor_write_init_settings(struct msm_sensor_ctrl_t *s_ctrl)
{
@@ -38,6 +64,12 @@
return rc;
rc = msm_sensor_write_output_settings(s_ctrl, res);
+ if (rc < 0)
+ return rc;
+
+ if (s_ctrl->func_tbl->sensor_adjust_frame_lines)
+ rc = s_ctrl->func_tbl->sensor_adjust_frame_lines(s_ctrl, res);
+
return rc;
}
@@ -173,47 +205,6 @@
return 0;
}
-int32_t msm_sensor_setting3(struct msm_sensor_ctrl_t *s_ctrl,
- int update_type, int res)
-{
- int32_t rc = 0;
- static int csi_config;
- if (update_type == MSM_SENSOR_REG_INIT) {
- CDBG("Register INIT\n");
- s_ctrl->curr_csi_params = NULL;
- csi_config = 0;
- msm_camera_i2c_write(
- s_ctrl->sensor_i2c_client,
- 0x0e, 0x08,
- MSM_CAMERA_I2C_BYTE_DATA);
- } else if (update_type == MSM_SENSOR_UPDATE_PERIODIC) {
- CDBG("PERIODIC : %d\n", res);
- if (res == 0)
- return 0;
- if (!csi_config) {
- msm_sensor_write_conf_array(
- s_ctrl->sensor_i2c_client,
- s_ctrl->msm_sensor_reg->mode_settings, res);
- msleep(30);
- 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);
- msm_camera_i2c_write(
- s_ctrl->sensor_i2c_client,
- 0x0e, 0x00,
- MSM_CAMERA_I2C_BYTE_DATA);
- csi_config = 1;
- }
- msleep(50);
- }
- return rc;
-}
-
int32_t msm_sensor_setting1(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res)
{
@@ -500,24 +491,6 @@
rc = -EFAULT;
break;
- case CFG_GET_EEPROM_DATA:
- if (s_ctrl->sensor_eeprom_client == NULL ||
- s_ctrl->sensor_eeprom_client->
- func_tbl.eeprom_get_data == NULL) {
- rc = -EFAULT;
- break;
- }
- rc = s_ctrl->sensor_eeprom_client->
- func_tbl.eeprom_get_data(
- s_ctrl->sensor_eeprom_client,
- &cdata.cfg.eeprom_data);
-
- if (copy_to_user((void *)argp,
- &cdata,
- sizeof(struct sensor_eeprom_data_t)))
- rc = -EFAULT;
- break;
-
default:
rc = -EFAULT;
break;
@@ -614,6 +587,7 @@
msm_sensor_enable_i2c_mux(data->sensor_platform_info->i2c_conf);
return rc;
+
enable_clk_failed:
msm_camera_config_gpio_table(data, 0);
config_gpio_failed:
@@ -670,13 +644,14 @@
s_ctrl->sensor_id_info->sensor_id_reg_addr, &chipid,
MSM_CAMERA_I2C_WORD_DATA);
if (rc < 0) {
- CDBG("%s: read id failed\n", __func__);
+ pr_err("%s: %s: read id failed\n", __func__,
+ s_ctrl->sensordata->sensor_name);
return rc;
}
CDBG("msm_sensor id: %d\n", chipid);
if (chipid != s_ctrl->sensor_id_info->sensor_id) {
- CDBG("msm_sensor_match_id chip id doesnot match\n");
+ pr_err("msm_sensor_match_id chip id doesnot match\n");
return -ENODEV;
}
return rc;
@@ -732,25 +707,6 @@
if (rc < 0)
goto probe_fail;
- if (s_ctrl->sensor_eeprom_client != NULL) {
- struct msm_camera_eeprom_client *eeprom_client =
- s_ctrl->sensor_eeprom_client;
- if (eeprom_client->func_tbl.eeprom_init != NULL &&
- eeprom_client->func_tbl.eeprom_release != NULL) {
- rc = eeprom_client->func_tbl.eeprom_init(
- eeprom_client,
- s_ctrl->sensor_i2c_client->client->adapter);
- if (rc < 0)
- goto probe_fail;
-
- rc = msm_camera_eeprom_read_tbl(eeprom_client,
- eeprom_client->read_tbl, eeprom_client->read_tbl_size);
- eeprom_client->func_tbl.eeprom_release(eeprom_client);
- if (rc < 0)
- goto probe_fail;
- }
- }
-
snprintf(s_ctrl->sensor_v4l2_subdev.name,
sizeof(s_ctrl->sensor_v4l2_subdev.name), "%s", id->name);
v4l2_i2c_subdev_init(&s_ctrl->sensor_v4l2_subdev, client,
@@ -772,10 +728,30 @@
int rc = 0;
struct msm_sensor_ctrl_t *s_ctrl = get_sctrl(sd);
mutex_lock(s_ctrl->msm_sensor_mutex);
- if (on)
+ if (on) {
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
- else
+ if (rc < 0) {
+ pr_err("%s: %s power_up failed rc = %d\n", __func__,
+ s_ctrl->sensordata->sensor_name, rc);
+ } else {
+ if (s_ctrl->func_tbl->sensor_match_id)
+ rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+ else
+ rc = msm_sensor_match_id(s_ctrl);
+ if (rc < 0) {
+ pr_err("%s: %s match_id failed rc=%d\n",
+ __func__,
+ s_ctrl->sensordata->sensor_name, rc);
+ if (s_ctrl->func_tbl->sensor_power_down(s_ctrl)
+ < 0)
+ pr_err("%s: %s power_down failed\n",
+ __func__,
+ s_ctrl->sensordata->sensor_name);
+ }
+ }
+ } else {
rc = s_ctrl->func_tbl->sensor_power_down(s_ctrl);
+ }
mutex_unlock(s_ctrl->msm_sensor_mutex);
return rc;
}
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index 0104b98..22cc05b 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -133,6 +133,8 @@
(struct msm_sensor_ctrl_t *);
int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
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);
};
struct msm_sensor_ctrl_t {
@@ -142,8 +144,6 @@
struct msm_camera_i2c_client *sensor_i2c_client;
uint16_t sensor_i2c_addr;
- struct msm_camera_eeprom_client *sensor_eeprom_client;
-
struct msm_sensor_output_reg_addr_t *sensor_output_reg_addr;
struct msm_sensor_id_info_t *sensor_id_info;
struct msm_sensor_exp_gain_info_t *sensor_exp_gain_info;
@@ -223,6 +223,9 @@
int32_t msm_sensor_write_output_settings(struct msm_sensor_ctrl_t *s_ctrl,
uint16_t res);
+int32_t msm_sensor_adjust_frame_lines(struct msm_sensor_ctrl_t *s_ctrl,
+ uint16_t res);
+
int32_t msm_sensor_setting(struct msm_sensor_ctrl_t *s_ctrl,
int update_type, int res);
@@ -242,7 +245,7 @@
struct msm_sensor_ctrl_t *get_sctrl(struct v4l2_subdev *sd);
-#if (defined CONFIG_WEBCAM_OV7692_QRD || defined CONFIG_OV5647)
+#if defined(CONFIG_OV5647)
extern int lcd_camera_power_onoff(int on);
#endif
diff --git a/drivers/media/video/msm/sensors/ov2720.c b/drivers/media/video/msm/sensors/ov2720.c
index 05556eb..7531a26 100644
--- a/drivers/media/video/msm/sensors/ov2720.c
+++ b/drivers/media/video/msm/sensors/ov2720.c
@@ -261,6 +261,297 @@
{0x3509, 0x20},
};
+static struct msm_camera_i2c_reg_conf ov2720_60fps_settings[] = {
+ {0x3718, 0x10},
+ {0x3702, 0x18},
+ {0x373a, 0x3c},
+ {0x3715, 0x01},
+ {0x3703, 0x1d},
+ {0x3705, 0x0b},
+ {0x3730, 0x1f},
+ {0x3704, 0x3f},
+ {0x3f06, 0x1d},
+ {0x371c, 0x00},
+ {0x371d, 0x83},
+ {0x371e, 0x00},
+ {0x371f, 0xb6},
+ {0x3708, 0x63},
+ {0x3709, 0x52},
+ {0x3800, 0x01},
+ {0x3801, 0x42},
+ {0x3802, 0x00},
+ {0x3803, 0x40},
+ {0x3804, 0x06},
+ {0x3805, 0x61},
+ {0x3806, 0x04},
+ {0x3807, 0x08},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x380c, 0x03},
+ {0x380d, 0x0c},
+ {0x380e, 0x02},
+ {0x380f, 0x00},
+ {0x3810, 0x00},
+ {0x3811, 0x0f},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3820, 0x80},
+ {0x3821, 0x06},
+ {0x3814, 0x31},
+ {0x3815, 0x31},
+ {0x3612, 0x0b},
+ {0x3618, 0x04},
+ {0x3a08, 0x02},
+ {0x3a09, 0x67},
+ {0x3a0a, 0x02},
+ {0x3a0b, 0x00},
+ {0x3a0d, 0x00},
+ {0x3a0e, 0x00},
+ {0x4520, 0x0a},
+ {0x4837, 0x29},
+ {0x3000, 0xff},
+ {0x3001, 0xff},
+ {0x3002, 0xf0},
+ {0x3600, 0x08},
+ {0x3621, 0xc0},
+ {0x3632, 0xd2},
+ {0x3633, 0x23},
+ {0x3634, 0x54},
+ {0x3f01, 0x0c},
+ {0x5001, 0xc1},
+ {0x3614, 0xf0},
+ {0x3630, 0x2d},
+ {0x370b, 0x62},
+ {0x3706, 0x61},
+ {0x4000, 0x02},
+ {0x4002, 0xc5},
+ {0x4005, 0x08},
+ {0x404f, 0x84},
+ {0x4051, 0x00},
+ {0x5000, 0xff},
+ {0x3a18, 0x00},
+ {0x3a19, 0x80},
+ {0x3503, 0x07},
+ {0x4521, 0x00},
+ {0x5183, 0xb0},
+ {0x5184, 0xb0},
+ {0x5185, 0xb0},
+ {0x370c, 0x0c},
+ {0x3035, 0x30},
+ {0x3036, 0x14},
+ {0x3037, 0x21},
+ {0x303e, 0x19},
+ {0x3038, 0x06},
+ {0x3018, 0x04},
+ {0x3000, 0x00},
+ {0x3001, 0x00},
+ {0x3002, 0x00},
+ {0x3a0f, 0x40},
+ {0x3a10, 0x38},
+ {0x3a1b, 0x48},
+ {0x3a1e, 0x30},
+ {0x3a11, 0x90},
+ {0x3a1f, 0x10},
+ {0x3011, 0x22},
+ {0x3a00, 0x58},
+};
+
+static struct msm_camera_i2c_reg_conf ov2720_90fps_settings[] = {
+ {0x3718, 0x10},
+ {0x3702, 0x18},
+ {0x373a, 0x3c},
+ {0x3715, 0x01},
+ {0x3703, 0x1d},
+ {0x3705, 0x0b},
+ {0x3730, 0x1f},
+ {0x3704, 0x3f},
+ {0x3f06, 0x1d},
+ {0x371c, 0x00},
+ {0x371d, 0x83},
+ {0x371e, 0x00},
+ {0x371f, 0xb6},
+ {0x3708, 0x63},
+ {0x3709, 0x52},
+ {0x3800, 0x01},
+ {0x3801, 0x42},
+ {0x3802, 0x00},
+ {0x3803, 0x40},
+ {0x3804, 0x06},
+ {0x3805, 0x61},
+ {0x3806, 0x04},
+ {0x3807, 0x08},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x380c, 0x03},
+ {0x380d, 0x0c},
+ {0x380e, 0x02},
+ {0x380f, 0x00},
+ {0x3810, 0x00},
+ {0x3811, 0x0f},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3820, 0x80},
+ {0x3821, 0x06},
+ {0x3814, 0x31},
+ {0x3815, 0x31},
+ {0x3612, 0x0b},
+ {0x3618, 0x04},
+ {0x3a08, 0x02},
+ {0x3a09, 0x67},
+ {0x3a0a, 0x02},
+ {0x3a0b, 0x00},
+ {0x3a0d, 0x00},
+ {0x3a0e, 0x00},
+ {0x4520, 0x0a},
+ {0x4837, 0x29},
+ {0x3000, 0xff},
+ {0x3001, 0xff},
+ {0x3002, 0xf0},
+ {0x3600, 0x08},
+ {0x3621, 0xc0},
+ {0x3632, 0xd2},
+ {0x3633, 0x23},
+ {0x3634, 0x54},
+ {0x3f01, 0x0c},
+ {0x5001, 0xc1},
+ {0x3614, 0xf0},
+ {0x3630, 0x2d},
+ {0x370b, 0x62},
+ {0x3706, 0x61},
+ {0x4000, 0x02},
+ {0x4002, 0xc5},
+ {0x4005, 0x08},
+ {0x404f, 0x84},
+ {0x4051, 0x00},
+ {0x5000, 0xff},
+ {0x3a18, 0x00},
+ {0x3a19, 0x80},
+ {0x3503, 0x07},
+ {0x4521, 0x00},
+ {0x5183, 0xb0},
+ {0x5184, 0xb0},
+ {0x5185, 0xb0},
+ {0x370c, 0x0c},
+ {0x3035, 0x20},
+ {0x3036, 0x14},
+ {0x3037, 0x21},
+ {0x303e, 0x19},
+ {0x3038, 0x06},
+ {0x3018, 0x04},
+ {0x3000, 0x00},
+ {0x3001, 0x00},
+ {0x3002, 0x00},
+ {0x3a0f, 0x40},
+ {0x3a10, 0x38},
+ {0x3a1b, 0x48},
+ {0x3a1e, 0x30},
+ {0x3a11, 0x90},
+ {0x3a1f, 0x10},
+ {0x3011, 0x22},
+ {0x3a00, 0x58},
+};
+
+static struct msm_camera_i2c_reg_conf ov2720_120fps_settings[] = {
+ {0x3718, 0x10},
+ {0x3702, 0x18},
+ {0x373a, 0x3c},
+ {0x3715, 0x01},
+ {0x3703, 0x1d},
+ {0x3705, 0x0b},
+ {0x3730, 0x1f},
+ {0x3704, 0x3f},
+ {0x3f06, 0x1d},
+ {0x371c, 0x00},
+ {0x371d, 0x83},
+ {0x371e, 0x00},
+ {0x371f, 0xb6},
+ {0x3708, 0x63},
+ {0x3709, 0x52},
+ {0x3800, 0x01},
+ {0x3801, 0x42},
+ {0x3802, 0x00},
+ {0x3803, 0x40},
+ {0x3804, 0x06},
+ {0x3805, 0x61},
+ {0x3806, 0x04},
+ {0x3807, 0x08},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x380c, 0x03},
+ {0x380d, 0x0c},
+ {0x380e, 0x02},
+ {0x380f, 0x00},
+ {0x3810, 0x00},
+ {0x3811, 0x0f},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3820, 0x80},
+ {0x3821, 0x06},
+ {0x3814, 0x31},
+ {0x3815, 0x31},
+ {0x3612, 0x0b},
+ {0x3618, 0x04},
+ {0x3a08, 0x02},
+ {0x3a09, 0x67},
+ {0x3a0a, 0x02},
+ {0x3a0b, 0x00},
+ {0x3a0d, 0x00},
+ {0x3a0e, 0x00},
+ {0x4520, 0x0a},
+ {0x4837, 0x29},
+ {0x3000, 0xff},
+ {0x3001, 0xff},
+ {0x3002, 0xf0},
+ {0x3600, 0x08},
+ {0x3621, 0xc0},
+ {0x3632, 0xd2},
+ {0x3633, 0x23},
+ {0x3634, 0x54},
+ {0x3f01, 0x0c},
+ {0x5001, 0xc1},
+ {0x3614, 0xf0},
+ {0x3630, 0x2d},
+ {0x370b, 0x62},
+ {0x3706, 0x61},
+ {0x4000, 0x02},
+ {0x4002, 0xc5},
+ {0x4005, 0x08},
+ {0x404f, 0x84},
+ {0x4051, 0x00},
+ {0x5000, 0xff},
+ {0x3a18, 0x00},
+ {0x3a19, 0x80},
+ {0x3503, 0x07},
+ {0x4521, 0x00},
+ {0x5183, 0xb0},
+ {0x5184, 0xb0},
+ {0x5185, 0xb0},
+ {0x370c, 0x0c},
+ {0x3035, 0x10},
+ {0x3036, 0x14},
+ {0x3037, 0x21},
+ {0x303e, 0x19},
+ {0x3038, 0x06},
+ {0x3018, 0x04},
+ {0x3000, 0x00},
+ {0x3001, 0x00},
+ {0x3002, 0x00},
+ {0x3a0f, 0x40},
+ {0x3a10, 0x38},
+ {0x3a1b, 0x48},
+ {0x3a1e, 0x30},
+ {0x3a11, 0x90},
+ {0x3a1f, 0x10},
+ {0x3011, 0x22},
+ {0x3a00, 0x58},
+};
+
static struct msm_camera_i2c_reg_conf ov2720_recommend_settings[] = {
{0x0103, 0x01},
{0x3718, 0x10},
@@ -302,6 +593,12 @@
ARRAY_SIZE(ov2720_vga_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
{&ov2720_720_settings[0],
ARRAY_SIZE(ov2720_720_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov2720_60fps_settings[0],
+ ARRAY_SIZE(ov2720_60fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov2720_90fps_settings[0],
+ ARRAY_SIZE(ov2720_90fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov2720_120fps_settings[0],
+ ARRAY_SIZE(ov2720_120fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
static struct msm_sensor_output_info_t ov2720_dimensions[] = {
@@ -332,6 +629,33 @@
.op_pixel_clk = 72000000,
.binning_factor = 1,
},
+ {
+ .x_output = 0x280, /* 640 */
+ .y_output = 0x1E0, /* 480 */
+ .line_length_pclk = 0x30C, /* 780 */
+ .frame_length_lines = 0x200, /* 512 */
+ .vt_pixel_clk = 24000000,
+ .op_pixel_clk = 24000000,
+ .binning_factor = 1,
+ },
+ {
+ .x_output = 0x280, /* 640 */
+ .y_output = 0x1E0, /* 480 */
+ .line_length_pclk = 0x30C, /* 780 */
+ .frame_length_lines = 0x200, /* 512 */
+ .vt_pixel_clk = 36000000,
+ .op_pixel_clk = 36000000,
+ .binning_factor = 1,
+ },
+ {
+ .x_output = 0x280, /* 640 */
+ .y_output = 0x1E0, /* 480 */
+ .line_length_pclk = 0x30C, /* 780 */
+ .frame_length_lines = 0x200, /* 512 */
+ .vt_pixel_clk = 48000000,
+ .op_pixel_clk = 48000000,
+ .binning_factor = 1,
+ },
};
static struct msm_camera_csid_vc_cfg ov2720_cid_cfg[] = {
@@ -357,6 +681,9 @@
&ov2720_csi_params,
&ov2720_csi_params,
&ov2720_csi_params,
+ &ov2720_csi_params,
+ &ov2720_csi_params,
+ &ov2720_csi_params,
};
static struct msm_sensor_output_reg_addr_t ov2720_reg_addr = {
@@ -456,6 +783,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
};
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 ca2bb98..d30d48b 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -32,11 +32,12 @@
};
static struct msm_camera_i2c_reg_conf ov5647_groupon_settings[] = {
- {0x0104, 0x01},
+ {0x3208, 0x0},
};
static struct msm_camera_i2c_reg_conf ov5647_groupoff_settings[] = {
- {0x0104, 0x0},
+ {0x3208, 0x10},
+ {0x3208, 0xa0},
};
static struct msm_camera_i2c_reg_conf ov5647_prev_settings[] = {
@@ -100,6 +101,65 @@
{0x4004, 0x04},
};
+static struct msm_camera_i2c_reg_conf ov5647_video_60fps_settings[] = {
+ {0x3035, 0x21},
+ {0x3036, 0x38},
+ {0x3821, 0x07},
+ {0x3820, 0x41},
+ {0x3612, 0x49},
+ {0x3618, 0x00},
+ {0x380c, 0x07},
+ {0x380d, 0x30},
+ {0x380e, 0x01},
+ {0x380f, 0xf8},
+ {0x3814, 0x71},
+ {0x3815, 0x71},
+ {0x3709, 0x52},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x3800, 0x00},
+ {0x3801, 0x10},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x2f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x4004, 0x02},
+};
+
+static struct msm_camera_i2c_reg_conf ov5647_video_90fps_settings[] = {
+ {0x3035, 0x11},
+ {0x3036, 0x2a},
+ {0x3821, 0x07},
+ {0x3820, 0x41},
+ {0x3612, 0x49},
+ {0x3618, 0x00},
+ {0x380c, 0x07},
+ {0x380d, 0x30},
+ {0x380e, 0x01},
+ {0x380f, 0xf8},
+ {0x3814, 0x71},
+ {0x3815, 0x71},
+ {0x3709, 0x52},
+ {0x3808, 0x02},
+ {0x3809, 0x80},
+ {0x380a, 0x01},
+ {0x380b, 0xe0},
+ {0x3800, 0x00},
+ {0x3801, 0x10},
+ {0x3802, 0x00},
+ {0x3803, 0x00},
+ {0x3804, 0x0a},
+ {0x3805, 0x2f},
+ {0x3806, 0x07},
+ {0x3807, 0x9f},
+ {0x4004, 0x02},
+};
+
+
static struct msm_camera_i2c_reg_conf ov5647_recommend_settings[] = {
{0x3035, 0x11},
{0x303c, 0x11},
@@ -234,6 +294,8 @@
{0x518a, 0x04},
{0x518b, 0x00},
{0x5000, 0x06}, /*No lenc,WBC on*/
+ {0x4005, 0x18},
+ {0x4051, 0x8f},
};
@@ -247,6 +309,10 @@
ARRAY_SIZE(ov5647_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
{&ov5647_prev_settings[0],
ARRAY_SIZE(ov5647_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov5647_video_60fps_settings[0],
+ ARRAY_SIZE(ov5647_video_60fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov5647_video_90fps_settings[0],
+ ARRAY_SIZE(ov5647_video_90fps_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
static struct msm_camera_csi_params ov5647_csi_params = {
@@ -286,6 +352,25 @@
.op_pixel_clk = 159408000,
.binning_factor = 0x0,
},
+ { /* For 60fps */
+ .x_output = 0x280, /*640*/
+ .y_output = 0x1E0, /*480*/
+ .line_length_pclk = 0x73C,
+ .frame_length_lines = 0x1F8,
+ .vt_pixel_clk = 56004480,
+ .op_pixel_clk = 159408000,
+ .binning_factor = 0x0,
+ },
+ { /* For 90fps */
+ .x_output = 0x280, /*640*/
+ .y_output = 0x1E0, /*480*/
+ .line_length_pclk = 0x73C,
+ .frame_length_lines = 0x1F8,
+ .vt_pixel_clk = 56004480,
+ .op_pixel_clk = 159408000,
+ .binning_factor = 0x0,
+ },
+
};
static struct msm_sensor_output_reg_addr_t ov5647_reg_addr = {
@@ -298,6 +383,8 @@
static struct msm_camera_csi_params *ov5647_csi_params_array[] = {
&ov5647_csi_params,
&ov5647_csi_params,
+ &ov5647_csi_params,
+ &ov5647_csi_params,
};
static struct msm_sensor_id_info_t ov5647_id_info = {
@@ -323,7 +410,7 @@
uint16_t gain, uint32_t line)
{
- uint16_t max_line;
+ static uint16_t max_line = 1964;
uint8_t gain_lsb, gain_hsb;
u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
@@ -333,8 +420,8 @@
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) {
- 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,
(uint8_t)((line+4) >> 8),
@@ -344,21 +431,17 @@
s_ctrl->sensor_output_reg_addr->frame_length_lines + 1,
(uint8_t)((line+4) & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
- s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
-
max_line = line + 4;
- } else if (line > 1968) {
- s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
+ } else if (max_line > 1968) {
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)(1968 >> 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)((line+4) & 0x00FF),
+ (uint8_t)(1968 & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
- s_ctrl->func_tbl->sensor_group_hold_off(s_ctrl);
max_line = 1968;
}
@@ -370,8 +453,6 @@
intg_time_lsb = (u8) (line & 0x00FF);
/* FIXME for BLC trigger */
- s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
-
/* Coarse Integration Time */
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_exp_gain_info->coarse_int_time_addr,
@@ -397,7 +478,7 @@
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_exp_gain_info->global_gain_addr + 1,
- gain_lsb-1,
+ gain_lsb^0x1,
MSM_CAMERA_I2C_BYTE_DATA);
/* Coarse Integration Time */
@@ -439,18 +520,20 @@
uint16_t gain, uint32_t line)
{
- uint16_t max_line;
+ static uint16_t max_line = 984;
u8 intg_time_hsb, intg_time_msb, intg_time_lsb;
uint8_t gain_lsb, gain_hsb;
- pr_info(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
+ CDBG(KERN_ERR "preview exposure setting 0x%x, 0x%x, %d",
gain, line, line);
gain_lsb = (uint8_t) (gain);
gain_hsb = (uint8_t)((gain & 0x300)>>8);
+
+ 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,
s_ctrl->sensor_output_reg_addr->frame_length_lines,
(uint8_t)((line+4) >> 8),
@@ -461,7 +544,7 @@
(uint8_t)((line+4) & 0x00FF),
MSM_CAMERA_I2C_BYTE_DATA);
max_line = line + 4;
- } else if (line > 984) {
+ } else if (max_line > 984) {
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
s_ctrl->sensor_output_reg_addr->frame_length_lines,
@@ -481,7 +564,6 @@
intg_time_msb = (u8) ((line & 0xFF00) >> 8);
intg_time_lsb = (u8) (line & 0x00FF);
- s_ctrl->func_tbl->sensor_group_hold_on(s_ctrl);
/* Coarse Integration Time */
msm_camera_i2c_write(s_ctrl->sensor_i2c_client,
@@ -634,12 +716,12 @@
{
int32_t rc = 0;
static int csi_config;
-
s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
if (csi_config == 0 || res == 0)
msleep(66);
else
msleep(266);
+
msm_camera_i2c_write(
s_ctrl->sensor_i2c_client,
0x4800, 0x25,
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
index 9fe2e8a..2324495 100644
--- a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
@@ -13,252 +13,16 @@
#include "msm_sensor.h"
#define SENSOR_NAME "ov7692"
-#define PLATFORM_DRIVER_NAME "msm_camera_ov7692"
-#define ov7692_obj ov7692_##obj
-#define MSB 1
-#define LSB 0
DEFINE_MUTEX(ov7692_mut);
static struct msm_sensor_ctrl_t ov7692_s_ctrl;
-static struct msm_camera_i2c_reg_conf ov7692_prev_settings[] = {
- {0x12, 0x80},
- {0x0e, 0x08},
- {0x69, 0x52},
- {0x1e, 0xb3},
- {0x48, 0x42},
- {0xff, 0x01},
- {0xae, 0xa0},
- {0xa8, 0x26},
- {0xb4, 0xc0},
- {0xb5, 0x40},
- {0xff, 0x00},
- {0x0c, 0x00},
- {0x62, 0x10},
- {0x12, 0x00},
- {0x17, 0x65},
- {0x18, 0xa4},
- {0x19, 0x0a},
- {0x1a, 0xf6},
- {0x3e, 0x30},
- {0x64, 0x0a},
- {0xff, 0x01},
- {0xb4, 0xc0},
- {0xff, 0x00},
- {0x67, 0x20},
- {0x81, 0x3f},
- {0xcc, 0x02},
- {0xcd, 0x80},
- {0xce, 0x01},
- {0xcf, 0xe0},
- {0xc8, 0x02},
- {0xc9, 0x80},
- {0xca, 0x01},
- {0xcb, 0xe0},
- {0xd0, 0x48},
- {0x82, 0x03},
- {0x70, 0x00},
- {0x71, 0x34},
- {0x74, 0x28},
- {0x75, 0x98},
- {0x76, 0x00},
- {0x77, 0x64},
- {0x78, 0x01},
- {0x79, 0xc2},
- {0x7a, 0x4e},
- {0x7b, 0x1f},
- {0x7c, 0x00},
- {0x11, 0x00},
- {0x20, 0x00},
- {0x21, 0x23},
- {0x50, 0x9a},
- {0x51, 0x80},
- {0x4c, 0x7d},
- {0x85, 0x10},
- {0x86, 0x00},
- {0x87, 0x00},
- {0x88, 0x00},
- {0x89, 0x2a},
- {0x8a, 0x26},
- {0x8b, 0x22},
- {0xbb, 0x7a},
- {0xbc, 0x69},
- {0xbd, 0x11},
- {0xbe, 0x13},
- {0xbf, 0x81},
- {0xc0, 0x96},
- {0xc1, 0x1e},
- {0xb7, 0x05},
- {0xb8, 0x09},
- {0xb9, 0x00},
- {0xba, 0x18},
- {0x5a, 0x1f},
- {0x5b, 0x9f},
- {0x5c, 0x6a},
- {0x5d, 0x42},
- {0x24, 0x78},
- {0x25, 0x68},
- {0x26, 0xb3},
- {0xa3, 0x0b},
- {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},
- {0xb2, 0x06},
- {0x8c, 0x5c},
- {0x8d, 0x11},
- {0x8e, 0x12},
- {0x8f, 0x19},
- {0x90, 0x50},
- {0x91, 0x20},
- {0x92, 0x96},
- {0x93, 0x80},
- {0x94, 0x13},
- {0x95, 0x1b},
- {0x96, 0xff},
- {0x97, 0x00},
- {0x98, 0x3d},
- {0x99, 0x36},
- {0x9a, 0x51},
- {0x9b, 0x43},
- {0x9c, 0xf0},
- {0x9d, 0xf0},
- {0x9e, 0xf0},
- {0x9f, 0xff},
- {0xa0, 0x68},
- {0xa1, 0x62},
- {0xa2, 0x0e},
-
+static struct msm_camera_i2c_reg_conf ov7692_start_settings[] = {
+ {0x0e, 0x00},
};
-static struct msm_camera_i2c_reg_conf ov7692_snap_settings[] = {
- {0x12, 0x80},
+static struct msm_camera_i2c_reg_conf ov7692_stop_settings[] = {
{0x0e, 0x08},
- {0x69, 0x52},
- {0x1e, 0xb3},
- {0x48, 0x42},
- {0xff, 0x01},
- {0xae, 0xa0},
- {0xa8, 0x26},
- {0xb4, 0xc0},
- {0xb5, 0x40},
- {0xff, 0x00},
- {0x0c, 0x00},
- {0x62, 0x10},
- {0x12, 0x00},
- {0x17, 0x65},
- {0x18, 0xa4},
- {0x19, 0x0a},
- {0x1a, 0xf6},
- {0x3e, 0x30},
- {0x64, 0x0a},
- {0xff, 0x01},
- {0xb4, 0xc0},
- {0xff, 0x00},
- {0x67, 0x20},
- {0x81, 0x3f},
- {0xcc, 0x02},
- {0xcd, 0x80},
- {0xce, 0x01},
- {0xcf, 0xe0},
- {0xc8, 0x02},
- {0xc9, 0x80},
- {0xca, 0x01},
- {0xcb, 0xe0},
- {0xd0, 0x48},
- {0x82, 0x03},
- {0x70, 0x00},
- {0x71, 0x34},
- {0x74, 0x28},
- {0x75, 0x98},
- {0x76, 0x00},
- {0x77, 0x64},
- {0x78, 0x01},
- {0x79, 0xc2},
- {0x7a, 0x4e},
- {0x7b, 0x1f},
- {0x7c, 0x00},
- {0x11, 0x00},
- {0x20, 0x00},
- {0x21, 0x23},
- {0x50, 0x9a},
- {0x51, 0x80},
- {0x4c, 0x7d},
- {0x85, 0x10},
- {0x86, 0x00},
- {0x87, 0x00},
- {0x88, 0x00},
- {0x89, 0x2a},
- {0x8a, 0x26},
- {0x8b, 0x22},
- {0xbb, 0x7a},
- {0xbc, 0x69},
- {0xbd, 0x11},
- {0xbe, 0x13},
- {0xbf, 0x81},
- {0xc0, 0x96},
- {0xc1, 0x1e},
- {0xb7, 0x05},
- {0xb8, 0x09},
- {0xb9, 0x00},
- {0xba, 0x18},
- {0x5a, 0x1f},
- {0x5b, 0x9f},
- {0x5c, 0x6a},
- {0x5d, 0x42},
- {0x24, 0x78},
- {0x25, 0x68},
- {0x26, 0xb3},
- {0xa3, 0x0b},
- {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},
- {0xb2, 0x06},
- {0x8c, 0x5c},
- {0x8d, 0x11},
- {0x8e, 0x12},
- {0x8f, 0x19},
- {0x90, 0x50},
- {0x91, 0x20},
- {0x92, 0x96},
- {0x93, 0x80},
- {0x94, 0x13},
- {0x95, 0x1b},
- {0x96, 0xff},
- {0x97, 0x00},
- {0x98, 0x3d},
- {0x99, 0x36},
- {0x9a, 0x51},
- {0x9b, 0x43},
- {0x9c, 0xf0},
- {0x9d, 0xf0},
- {0x9e, 0xf0},
- {0x9f, 0xff},
- {0xa0, 0x68},
- {0xa1, 0x62},
- {0xa2, 0x0e},
-
};
static struct msm_camera_i2c_reg_conf ov7692_recommend_settings[] = {
@@ -287,14 +51,6 @@
{0xff, 0x00},
{0x67, 0x20},
{0x81, 0x3f},
- {0xcc, 0x02},
- {0xcd, 0x80},
- {0xce, 0x01},
- {0xcf, 0xe0},
- {0xc8, 0x02},
- {0xc9, 0x80},
- {0xca, 0x01},
- {0xcb, 0xe0},
{0xd0, 0x48},
{0x82, 0x03},
{0x70, 0x00},
@@ -378,7 +134,17 @@
{0xa0, 0x68},
{0xa1, 0x62},
{0xa2, 0x0e},
+};
+static struct msm_camera_i2c_reg_conf ov7692_full_settings[] = {
+ {0xcc, 0x02},
+ {0xcd, 0x80},
+ {0xce, 0x01},
+ {0xcf, 0xe0},
+ {0xc8, 0x02},
+ {0xc9, 0x80},
+ {0xca, 0x01},
+ {0xcb, 0xe0},
};
static struct v4l2_subdev_info ov7692_subdev_info[] = {
@@ -398,10 +164,8 @@
};
static struct msm_camera_i2c_conf_array ov7692_confs[] = {
- {&ov7692_snap_settings[0],
- ARRAY_SIZE(ov7692_snap_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
- {&ov7692_prev_settings[0],
- ARRAY_SIZE(ov7692_prev_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
+ {&ov7692_full_settings[0],
+ ARRAY_SIZE(ov7692_full_settings), 0, MSM_CAMERA_I2C_BYTE_DATA},
};
static struct msm_sensor_output_info_t ov7692_dimensions[] = {
@@ -414,15 +178,6 @@
.op_pixel_clk = 9216000,
.binning_factor = 1,
},
- {
- .x_output = 0x280,
- .y_output = 0x1E0,
- .line_length_pclk = 0x290,
- .frame_length_lines = 0x1EC,
- .vt_pixel_clk = 9216000,
- .op_pixel_clk = 9216000,
- .binning_factor = 1,
- },
};
@@ -436,7 +191,6 @@
static struct msm_camera_csi_params *ov7692_csi_params_array[] = {
&ov7692_csi_params,
- &ov7692_csi_params,
};
static struct msm_sensor_output_reg_addr_t ov7692_reg_addr = {
@@ -451,77 +205,11 @@
.sensor_id = 0x7692,
};
-static struct msm_sensor_exp_gain_info_t ov7692_exp_gain_info = {
- .coarse_int_time_addr = 0x0202,
- .global_gain_addr = 0x0204,
- .vert_offset = 4,
-};
-
-static inline uint8_t ov7692_byte(uint16_t word, uint8_t offset)
-{
- return word >> (offset * BITS_PER_BYTE);
-}
-
-
static const struct i2c_device_id ov7692_i2c_id[] = {
{SENSOR_NAME, (kernel_ulong_t)&ov7692_s_ctrl},
{ }
};
-static int ov7692_pwdn_gpio;
-static int ov7692_reset_gpio;
-static int ov7692_probe_init_gpio(const struct msm_camera_sensor_info *data)
-{
- int rc = 0;
- CDBG("%s: entered\n", __func__);
-
- ov7692_pwdn_gpio = data->sensor_pwd;
- ov7692_reset_gpio = data->sensor_reset ;
-
- CDBG("%s: pwdn_gpio:%d, reset_gpio:%d\n", __func__,
- ov7692_pwdn_gpio, ov7692_reset_gpio);
-
- if (data->sensor_reset_enable)
- gpio_direction_output(data->sensor_reset, 1);
-
- gpio_direction_output(data->sensor_pwd, 1);
-
- return rc;
-
-}
-static void ov7692_power_on(void)
-{
- CDBG("%s\n", __func__);
- gpio_set_value(ov7692_pwdn_gpio, 0);
-}
-
-static void ov7692_power_down(void)
-{
- CDBG("%s\n", __func__);
- gpio_set_value(ov7692_pwdn_gpio, 1);
-}
-
-int32_t ov7692_sensor_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int32_t rc = 0;
- struct msm_sensor_ctrl_t *s_ctrl;
- rc = msm_sensor_i2c_probe(client, id);
-
- ov7692_power_down();
-
- if (client->dev.platform_data == NULL) {
- pr_err("%s: NULL sensor data\n", __func__);
- return -EFAULT;
- }
-
- s_ctrl = client->dev.platform_data;
- if (s_ctrl->sensordata->pmic_gpio_enable)
- lcd_camera_power_onoff(0);
-
- return rc;
-
-}
static struct i2c_driver ov7692_i2c_driver = {
.id_table = ov7692_i2c_id,
@@ -559,152 +247,26 @@
.video = &ov7692_subdev_video_ops,
};
-static int32_t ov7692_i2c_txdata(struct i2c_client *ov7692_client,
- unsigned short saddr,
- unsigned char *txdata, int length)
-{
- struct i2c_msg msg[] = {
- {
- .addr = saddr,
- .flags = 0,
- .len = 2,
- .buf = txdata,
- },
- };
- if (i2c_transfer(ov7692_client->adapter, msg, 1) < 0) {
- CDBG("ov7692_i2c_txdata faild 0x%x\n", ov7692_client->addr);
- return -EIO;
- }
-
- return 0;
-}
-static int32_t ov7692_i2c_write_b_sensor(struct i2c_client *ov7692_client,
- uint8_t waddr,
- uint8_t bdata)
-{
- int32_t rc = -EFAULT;
- unsigned char buf[2];
-
- memset(buf, 0, sizeof(buf));
- buf[0] = waddr;
- buf[1] = bdata;
- CDBG("i2c_write_b addr = 0x%x, val = 0x%x\n", waddr, bdata);
- rc = ov7692_i2c_txdata(ov7692_client, ov7692_client->addr >> 1, buf, 2);
- if (rc < 0)
- CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
- waddr, bdata);
-
- return rc;
-}
-
-static int32_t ov7692_write_exp_gain(struct msm_sensor_ctrl_t *s_ctrl,
- uint16_t gain, uint32_t line)
-{
- CDBG("ov7692_write_exp_gain : Not supported\n");
- return 0;
-}
-
-int32_t ov7692_sensor_set_fps(struct msm_sensor_ctrl_t *s_ctrl,
- struct fps_cfg *fps)
-{
- CDBG("ov7692_sensor_set_fps: Not supported\n");
- return 0;
-}
-
-
-
-static void ov7692_sw_reset(struct msm_sensor_ctrl_t *s_ctrl)
-{
-
- CDBG("%s\n", __func__);
- ov7692_i2c_write_b_sensor(s_ctrl->sensor_i2c_client->client,
- 0x12, 0x80);
-}
-
-static void ov7692_hw_reset(void)
-{
- CDBG("--CAMERA-- %s ... (Start...)\n", __func__);
- gpio_set_value(ov7692_reset_gpio, 1); /*reset camera reset pin*/
- usleep_range(5000, 5100);
- gpio_set_value(ov7692_reset_gpio, 0);
- usleep_range(5000, 5100);
- gpio_set_value(ov7692_reset_gpio, 1);
- usleep_range(1000, 1100);
- CDBG("--CAMERA-- %s ... (End...)\n", __func__);
-}
-
-
-
-int32_t ov7692_sensor_power_up(struct msm_sensor_ctrl_t *s_ctrl)
-{
- int32_t rc = 0;
- struct msm_camera_sensor_info *info = NULL;
-
- CDBG("%s: %d\n", __func__, __LINE__);
-
- rc = msm_sensor_power_up(s_ctrl);
- if (rc < 0) {
- CDBG("%s: msm_sensor_power_up failed\n", __func__);
- return rc;
- }
- info = s_ctrl->sensordata;
-
- rc = ov7692_probe_init_gpio(info);
- if (rc < 0) {
- CDBG("%s: gpio init failed\n", __func__);
- goto power_up_fail;
- }
- /* turn on LDO for PVT */
- if (info->pmic_gpio_enable)
- lcd_camera_power_onoff(1);
-
- ov7692_power_down();
-
- usleep_range(5000, 5100);
-
- ov7692_power_on();
- usleep_range(5000, 5100);
-
- if (info->sensor_reset_enable)
- ov7692_hw_reset();
- else
- ov7692_sw_reset(s_ctrl);
-
- return rc;
-
-power_up_fail:
- CDBG("ov7692_sensor_power_up: OV7692 SENSOR POWER UP FAILS!\n");
- if (info->pmic_gpio_enable)
- lcd_camera_power_onoff(0);
- 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,
- .sensor_group_hold_on = msm_sensor_group_hold_on,
- .sensor_group_hold_off = msm_sensor_group_hold_off,
- .sensor_set_fps = ov7692_sensor_set_fps,
- .sensor_csi_setting = msm_sensor_setting3,
+ .sensor_csi_setting = msm_sensor_setting1,
.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 = ov7692_sensor_power_up,
+ .sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
- .sensor_write_exp_gain = ov7692_write_exp_gain,
- .sensor_write_snapshot_exp_gain = ov7692_write_exp_gain,
};
static struct msm_sensor_reg_t ov7692_regs = {
.default_data_type = MSM_CAMERA_I2C_BYTE_DATA,
- .start_stream_conf_size = 0,
- .stop_stream_conf_size = 0,
- .group_hold_on_conf_size = 0,
- .group_hold_off_conf_size = 0,
+ .start_stream_conf = ov7692_start_settings,
+ .start_stream_conf_size = ARRAY_SIZE(ov7692_start_settings),
+ .stop_stream_conf = ov7692_stop_settings,
+ .stop_stream_conf_size = ARRAY_SIZE(ov7692_stop_settings),
.init_settings = &ov7692_init_conf[0],
.init_size = ARRAY_SIZE(ov7692_init_conf),
.mode_settings = &ov7692_confs[0],
@@ -718,7 +280,6 @@
.sensor_i2c_addr = 0x78,
.sensor_output_reg_addr = &ov7692_reg_addr,
.sensor_id_info = &ov7692_id_info,
- .sensor_exp_gain_info = &ov7692_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
.csic_params = &ov7692_csi_params_array[0],
.msm_sensor_mutex = &ov7692_mut,
@@ -731,5 +292,5 @@
};
module_init(msm_sensor_init_module);
-MODULE_DESCRIPTION("Omni VGA YUV sensor driver");
+MODULE_DESCRIPTION("Omnivision VGA YUV sensor driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/sensors/s5k3l1yx.c b/drivers/media/video/msm/sensors/s5k3l1yx.c
index 8d022b6..debda88 100644
--- a/drivers/media/video/msm/sensors/s5k3l1yx.c
+++ b/drivers/media/video/msm/sensors/s5k3l1yx.c
@@ -652,6 +652,7 @@
.sensor_config = msm_sensor_config,
.sensor_power_up = msm_sensor_power_up,
.sensor_power_down = msm_sensor_power_down,
+ .sensor_adjust_frame_lines = msm_sensor_adjust_frame_lines,
};
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 6671073..2d25824 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -406,6 +406,36 @@
return 0;
}
+int32_t s5k4e1_sensor_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct msm_camera_sensor_info *s_info;
+
+ rc = msm_sensor_i2c_probe(client, id);
+
+ s_info = client->dev.platform_data;
+ if (s_info == NULL) {
+ pr_err("%s %s NULL sensor data\n", __func__, client->name);
+ return -EFAULT;
+ }
+
+ if (s_info->actuator_info->vcm_enable) {
+ rc = gpio_request(s_info->actuator_info->vcm_pwd,
+ "msm_actuator");
+ if (rc < 0)
+ pr_err("%s: gpio_request:msm_actuator %d failed\n",
+ __func__, s_info->actuator_info->vcm_pwd);
+ rc = gpio_direction_output(s_info->actuator_info->vcm_pwd, 0);
+ if (rc < 0)
+ pr_err("%s: gpio:msm_actuator %d direction can't be set\n",
+ __func__, s_info->actuator_info->vcm_pwd);
+ gpio_free(s_info->actuator_info->vcm_pwd);
+ }
+
+ return rc;
+}
+
static const struct i2c_device_id s5k4e1_i2c_id[] = {
{SENSOR_NAME, (kernel_ulong_t)&s5k4e1_s_ctrl},
{ }
@@ -413,7 +443,7 @@
static struct i2c_driver s5k4e1_i2c_driver = {
.id_table = s5k4e1_i2c_id,
- .probe = msm_sensor_i2c_probe,
+ .probe = s5k4e1_sensor_i2c_probe,
.driver = {
.name = SENSOR_NAME,
},
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 0a2b1c1..2242aa8 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -517,8 +517,10 @@
core, ioctl, MDP_DQ_BUFFER, (void *)&obuf_mdp);
if (rc) {
- WFD_MSG_ERR("Either streamoff called or"
- " MDP REPORTED ERROR\n");
+ if (rc != -ENOBUFS)
+ WFD_MSG_ERR("MDP reported err %d\n", rc);
+
+ WFD_MSG_ERR("Streamoff called\n");
break;
} else {
wfd_stats_update(&inst->stats,
diff --git a/drivers/media/video/msm_vidc/msm_smem.c b/drivers/media/video/msm_vidc/msm_smem.c
new file mode 100644
index 0000000..25b5c5c
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.c
@@ -0,0 +1,244 @@
+/* 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 "msm_smem.h"
+
+struct smem_client {
+ int mem_type;
+ void *clnt;
+};
+
+static int ion_user_to_kernel(struct smem_client *client,
+ int fd, u32 offset, struct msm_smem *mem)
+{
+ struct ion_handle *hndl;
+ unsigned long ionflag;
+ size_t len;
+ int rc = 0;
+ hndl = ion_import_fd(client->clnt, fd);
+ if (IS_ERR_OR_NULL(hndl)) {
+ pr_err("Failed to get handle: %p, %d, %d, %p\n",
+ client, fd, offset, hndl);
+ rc = -ENOMEM;
+ goto fail_import_fd;
+ }
+ rc = ion_handle_get_flags(client->clnt, hndl, &ionflag);
+ if (rc) {
+ pr_err("Failed to get ion flags: %d", rc);
+ goto fail_map;
+ }
+ rc = ion_phys(client->clnt, hndl, &mem->paddr, &len);
+ if (rc) {
+ pr_err("Failed to get physical address\n");
+ goto fail_map;
+ }
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl, ionflag);
+ if (!mem->kvaddr) {
+ pr_err("Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+
+ mem->kvaddr += offset;
+ mem->paddr += offset;
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ mem->device_addr = mem->paddr;
+ mem->size = len;
+ return rc;
+fail_map:
+ ion_free(client->clnt, hndl);
+fail_import_fd:
+ return rc;
+}
+
+static int alloc_ion_mem(struct smem_client *client, size_t size,
+ u32 align, u32 flags, struct msm_smem *mem)
+{
+ struct ion_handle *hndl;
+ size_t len;
+ int rc = 0;
+ flags = flags | ION_HEAP(ION_CP_MM_HEAP_ID);
+ hndl = ion_alloc(client->clnt, size, align, flags);
+ if (IS_ERR_OR_NULL(hndl)) {
+ pr_err("Failed to allocate shared memory = %p, %d, %d, 0x%x\n",
+ client, size, align, flags);
+ rc = -ENOMEM;
+ goto fail_shared_mem_alloc;
+ }
+ mem->mem_type = client->mem_type;
+ mem->smem_priv = hndl;
+ if (ion_phys(client->clnt, hndl, &mem->paddr, &len)) {
+ pr_err("Failed to get physical address\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ mem->device_addr = mem->paddr;
+ mem->size = size;
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl, 0);
+ if (!mem->kvaddr) {
+ pr_err("Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ return rc;
+fail_map:
+ ion_free(client->clnt, hndl);
+fail_shared_mem_alloc:
+ return rc;
+}
+
+static void free_ion_mem(struct smem_client *client, struct msm_smem *mem)
+{
+ ion_unmap_kernel(client->clnt, mem->smem_priv);
+ ion_free(client->clnt, mem->smem_priv);
+}
+
+static void *ion_new_client(void)
+{
+ struct ion_client *client = NULL;
+ client = msm_ion_client_create(-1, "video_client");
+ if (!client)
+ pr_err("Failed to create smem client\n");
+ return client;
+};
+
+static void ion_delete_client(struct smem_client *client)
+{
+ ion_client_destroy(client->clnt);
+}
+
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset)
+{
+ struct smem_client *client = clt;
+ int rc = 0;
+ struct msm_smem *mem;
+ if (fd < 0) {
+ pr_err("Invalid fd: %d\n", fd);
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ pr_err("Failed to allocte shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ rc = ion_user_to_kernel(clt, fd, offset, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+void *msm_smem_new_client(enum smem_type mtype)
+{
+ struct smem_client *client = NULL;
+ void *clnt = NULL;
+ switch (mtype) {
+ case SMEM_ION:
+ clnt = ion_new_client();
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ if (clnt) {
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client) {
+ client->mem_type = mtype;
+ client->clnt = clnt;
+ }
+ } else {
+ pr_err("Failed to create new client: mtype = %d\n", mtype);
+ }
+ return client;
+};
+
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags)
+{
+ struct smem_client *client;
+ int rc = 0;
+ struct msm_smem *mem;
+
+ client = clt;
+ if (!client) {
+ pr_err("Invalid client passed\n");
+ return NULL;
+ }
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem) {
+ pr_err("Failed to allocate shared mem\n");
+ return NULL;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ rc = alloc_ion_mem(client, size, align, flags, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ rc = -EINVAL;
+ break;
+ }
+ if (rc) {
+ pr_err("Failed to allocate shared memory\n");
+ kfree(mem);
+ mem = NULL;
+ }
+ return mem;
+}
+
+void msm_smem_free(void *clt, struct msm_smem *mem)
+{
+ struct smem_client *client = clt;
+ if (!client || !mem) {
+ pr_err("Invalid client/handle passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ free_ion_mem(client, mem);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ kfree(mem);
+};
+
+void msm_smem_delete_client(void *clt)
+{
+ struct smem_client *client = clt;
+ if (!client) {
+ pr_err("Invalid client passed\n");
+ return;
+ }
+ switch (client->mem_type) {
+ case SMEM_ION:
+ ion_delete_client(client);
+ break;
+ default:
+ pr_err("Mem type not supported\n");
+ break;
+ }
+ kfree(client);
+}
diff --git a/drivers/media/video/msm_vidc/msm_smem.h b/drivers/media/video/msm_vidc/msm_smem.h
new file mode 100644
index 0000000..84d12cc
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_smem.h
@@ -0,0 +1,38 @@
+/* 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_SMEM_H_
+#define _MSM_SMEM_H_
+
+#include <linux/types.h>
+#include <linux/ion.h>
+
+enum smem_type {
+ SMEM_ION,
+};
+
+struct msm_smem {
+ int mem_type;
+ size_t size;
+ void *kvaddr;
+ unsigned long paddr;
+ unsigned long device_addr;
+ /*Device address and others to follow*/
+ void *smem_priv;
+};
+
+void *msm_smem_new_client(enum smem_type mtype);
+struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags);
+void msm_smem_free(void *clt, struct msm_smem *mem);
+void msm_smem_delete_client(void *clt);
+struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset);
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_v4l2_vidc.c b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
new file mode 100644
index 0000000..f125cdc
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_v4l2_vidc.c
@@ -0,0 +1,505 @@
+/* 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/types.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/version.h>
+#include <linux/slab.h>
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define BASE_DEVICE_NUMBER 32
+
+struct msm_vidc_drv *vidc_driver;
+
+struct buffer_info {
+ struct list_head list;
+ int type;
+ int fd;
+ int buff_off;
+ int size;
+ u32 uvaddr;
+ struct msm_smem *handle;
+};
+
+struct msm_v4l2_vid_inst {
+ void *vidc_inst;
+ void *mem_client;
+ struct list_head registered_bufs;
+};
+
+struct buffer_info *get_registered_buf(struct list_head *list,
+ int fd, u32 buff_off, u32 size)
+{
+ struct buffer_info *temp;
+ struct buffer_info *ret = NULL;
+ if (!list || fd < 0) {
+ pr_err("%s Invalid input\n", __func__);
+ goto err_invalid_input;
+ }
+ if (!list_empty(list)) {
+ list_for_each_entry(temp, list, list) {
+ if (temp && temp->fd == fd &&
+ (CONTAINS(temp->buff_off, temp->size, buff_off)
+ || CONTAINS(buff_off, size, temp->buff_off)
+ || OVERLAPS(buff_off, size,
+ temp->buff_off, temp->size))) {
+ pr_err("This memory region is already mapped\n");
+ ret = temp;
+ break;
+ }
+ }
+ }
+err_invalid_input:
+ return ret;
+}
+
+static int msm_v4l2_open(struct file *filp)
+{
+ int rc = 0;
+ struct video_device *vdev = video_devdata(filp);
+ struct msm_video_device *vid_dev =
+ container_of(vdev, struct msm_video_device, vdev);
+ struct msm_vidc_core *core = video_drvdata(filp);
+ void *inst;
+ struct msm_v4l2_vid_inst *v4l2_inst = kzalloc(sizeof(*v4l2_inst),
+ GFP_KERNEL);
+ if (!v4l2_inst) {
+ pr_err("Failed to allocate memory for this instance\n");
+ rc = -ENOMEM;
+ goto fail_nomem;
+ }
+ v4l2_inst->mem_client = msm_smem_new_client(SMEM_ION);
+ if (!v4l2_inst->mem_client) {
+ pr_err("Failed to create memory client\n");
+ rc = -ENOMEM;
+ goto fail_mem_client;
+ }
+ inst = msm_vidc_open(core->id, vid_dev->type);
+ if (!inst) {
+ pr_err("Failed to create video instance, core: %d, type = %d\n",
+ core->id, vid_dev->type);
+ rc = -ENOMEM;
+ goto fail_open;
+ }
+ INIT_LIST_HEAD(&v4l2_inst->registered_bufs);
+ v4l2_inst->vidc_inst = inst;
+ filp->private_data = v4l2_inst;
+ return rc;
+fail_open:
+ msm_smem_delete_client(v4l2_inst->mem_client);
+fail_mem_client:
+ kfree(v4l2_inst);
+fail_nomem:
+ return rc;
+}
+
+static int msm_v4l2_close(struct file *filp)
+{
+ int rc;
+ struct list_head *ptr, *next;
+ struct buffer_info *binfo;
+ struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+ rc = msm_vidc_close(v4l2_inst->vidc_inst);
+ list_for_each_safe(ptr, next, &v4l2_inst->registered_bufs) {
+ binfo = list_entry(ptr, struct buffer_info, list);
+ list_del(&binfo->list);
+ msm_smem_free(v4l2_inst->mem_client, binfo->handle);
+ kfree(binfo);
+ }
+ msm_smem_delete_client(v4l2_inst->mem_client);
+ kfree(v4l2_inst);
+ return rc;
+}
+
+static int msm_v4l2_querycap(struct file *filp, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+ return msm_vidc_querycap(v4l2_inst->vidc_inst, cap);
+}
+
+int msm_v4l2_enum_fmt(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_enum_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_s_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_s_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_g_fmt(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_g_fmt(v4l2_inst->vidc_inst, f);
+}
+
+int msm_v4l2_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_s_ctrl(v4l2_inst->vidc_inst, a);
+}
+
+int msm_v4l2_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *a)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_g_ctrl(v4l2_inst->vidc_inst, a);
+}
+
+int msm_v4l2_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_reqbufs(v4l2_inst->vidc_inst, b);
+}
+
+int msm_v4l2_prepare_buf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ struct msm_smem *handle;
+ struct buffer_info *binfo;
+ int rc = 0;
+ int i;
+ if (!v4l2_inst->mem_client) {
+ pr_err("Failed to get memory client\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ for (i = 0; i < b->length; ++i) {
+ binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ if (binfo) {
+ pr_err("This memory region has already been prepared\n");
+ rc = -EINVAL;
+ goto exit;
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Out of memory\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+ handle = msm_smem_user_to_kernel(v4l2_inst->mem_client,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1]);
+ if (!handle) {
+ pr_err("Failed to get device buffer address\n");
+ kfree(binfo);
+ goto exit;
+ }
+ binfo->type = b->type;
+ binfo->fd = b->m.planes[i].reserved[0];
+ binfo->buff_off = b->m.planes[i].reserved[1];
+ binfo->size = b->m.planes[i].length;
+ binfo->uvaddr = b->m.planes[i].m.userptr;
+ binfo->handle = handle;
+ pr_debug("Registering buffer: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ list_add_tail(&binfo->list, &v4l2_inst->registered_bufs);
+ b->m.planes[i].m.userptr = handle->device_addr;
+ }
+ rc = msm_vidc_prepare_buf(v4l2_inst->vidc_inst, b);
+exit:
+ return rc;
+}
+
+int msm_v4l2_qbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ struct buffer_info *binfo;
+ int rc = 0;
+ int i;
+ for (i = 0; i < b->length; ++i) {
+ binfo = get_registered_buf(&v4l2_inst->registered_bufs,
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ if (!binfo) {
+ pr_err("This buffer is not registered: %d, %d, %d\n",
+ b->m.planes[i].reserved[0],
+ b->m.planes[i].reserved[1],
+ b->m.planes[i].length);
+ rc = -EINVAL;
+ goto err_invalid_buff;
+ }
+ b->m.planes[i].m.userptr = binfo->handle->device_addr;
+ pr_debug("Queueing device address = %ld\n",
+ binfo->handle->device_addr);
+ }
+ rc = msm_vidc_qbuf(v4l2_inst->vidc_inst, b);
+err_invalid_buff:
+ return rc;
+}
+
+int msm_v4l2_dqbuf(struct file *file, void *fh,
+ struct v4l2_buffer *b)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_dqbuf(v4l2_inst->vidc_inst, b);
+}
+
+int msm_v4l2_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_streamon(v4l2_inst->vidc_inst, i);
+}
+
+int msm_v4l2_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type i)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = file->private_data;
+ return msm_vidc_streamoff(v4l2_inst->vidc_inst, i);
+}
+static const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
+ .vidioc_querycap = msm_v4l2_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
+ .vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
+ .vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
+ .vidioc_reqbufs = msm_v4l2_reqbufs,
+ .vidioc_prepare_buf = msm_v4l2_prepare_buf,
+ .vidioc_qbuf = msm_v4l2_qbuf,
+ .vidioc_dqbuf = msm_v4l2_dqbuf,
+ .vidioc_streamon = msm_v4l2_streamon,
+ .vidioc_streamoff = msm_v4l2_streamoff,
+ .vidioc_s_ctrl = msm_v4l2_s_ctrl,
+ .vidioc_g_ctrl = msm_v4l2_g_ctrl,
+};
+
+static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = {
+};
+
+static unsigned int msm_v4l2_poll(struct file *filp,
+ struct poll_table_struct *pt)
+{
+ struct msm_v4l2_vid_inst *v4l2_inst = filp->private_data;
+ return msm_vidc_poll(v4l2_inst->vidc_inst, filp, pt);
+}
+
+static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
+ .owner = THIS_MODULE,
+ .open = msm_v4l2_open,
+ .release = msm_v4l2_close,
+ .ioctl = video_ioctl2,
+ .poll = msm_v4l2_poll,
+};
+
+void msm_vidc_release_video_device(struct video_device *pvdev)
+{
+}
+
+static int msm_vidc_initialize_core(struct platform_device *pdev,
+ struct msm_vidc_core *core)
+{
+ struct resource *res;
+ int i = 0;
+ if (!core)
+ return -EINVAL;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ pr_err("Failed to get IORESOURCE_MEM\n");
+ return -ENODEV;
+ }
+ core->register_base = res->start;
+ core->register_size = resource_size(res);
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ pr_err("Failed to get IORESOURCE_IRQ\n");
+ return -ENODEV;
+ }
+ core->irq = res->start;
+ INIT_LIST_HEAD(&core->instances);
+ mutex_init(&core->sync_lock);
+ spin_lock_init(&core->lock);
+ core->base_addr = 0x34f00000;
+ core->state = VIDC_CORE_UNINIT;
+ for (i = SYS_MSG_INDEX(SYS_MSG_START);
+ i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
+ init_completion(&core->completions[i]);
+ }
+ return 0;
+}
+
+static int __devinit msm_vidc_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core;
+ unsigned long flags;
+ char debugfs_name[MAX_DEBUGFS_NAME];
+
+ core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core || !vidc_driver) {
+ pr_err("Failed to allocate memory for device core\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ rc = msm_vidc_initialize_core(pdev, core);
+ if (rc) {
+ pr_err("Failed to init core\n");
+ goto err_v4l2_register;
+ }
+ rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
+ if (rc) {
+ pr_err("Failed to register v4l2 device\n");
+ goto err_v4l2_register;
+ }
+ core->vdev[MSM_VIDC_DECODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_DECODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_DECODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_DECODER].type = MSM_VIDC_DECODER;
+ rc = video_register_device(&core->vdev[MSM_VIDC_DECODER].vdev,
+ VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER);
+ if (rc) {
+ pr_err("Failed to register video decoder device");
+ goto err_dec_register;
+ }
+ video_set_drvdata(&core->vdev[MSM_VIDC_DECODER].vdev, core);
+
+ core->vdev[MSM_VIDC_ENCODER].vdev.release =
+ msm_vidc_release_video_device;
+ core->vdev[MSM_VIDC_ENCODER].vdev.fops = &msm_v4l2_vidc_fops;
+ core->vdev[MSM_VIDC_ENCODER].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
+ core->vdev[MSM_VIDC_ENCODER].type = MSM_VIDC_ENCODER;
+ rc = video_register_device(&core->vdev[MSM_VIDC_ENCODER].vdev,
+ VFL_TYPE_GRABBER, BASE_DEVICE_NUMBER + 1);
+ if (rc) {
+ pr_err("Failed to register video encoder device");
+ goto err_enc_register;
+ }
+ video_set_drvdata(&core->vdev[MSM_VIDC_ENCODER].vdev, core);
+ core->device = vidc_hal_add_device(core->id, core->base_addr,
+ core->register_base, core->register_size, core->irq,
+ &handle_cmd_response);
+ if (!core->device) {
+ pr_err("Failed to create interrupt handler");
+ goto err_cores_exceeded;
+ }
+
+ spin_lock_irqsave(&vidc_driver->lock, flags);
+ if (vidc_driver->num_cores + 1 > MSM_VIDC_CORES_MAX) {
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ pr_err("Maximum cores already exist, core_no = %d\n",
+ vidc_driver->num_cores);
+ goto err_cores_exceeded;
+ }
+
+ core->id = vidc_driver->num_cores++;
+ list_add_tail(&core->list, &vidc_driver->cores);
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id);
+ core->debugfs_root = debugfs_create_dir(debugfs_name,
+ vidc_driver->debugfs_root);
+ pdev->dev.platform_data = core;
+ return rc;
+
+err_cores_exceeded:
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+err_enc_register:
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+err_dec_register:
+ v4l2_device_unregister(&core->v4l2_dev);
+err_v4l2_register:
+ kfree(core);
+err_no_mem:
+ return rc;
+}
+
+static int __devexit msm_vidc_remove(struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = pdev->dev.platform_data;
+ vidc_hal_delete_device(core->device);
+ video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
+ video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
+ v4l2_device_unregister(&core->v4l2_dev);
+ kfree(core);
+ return rc;
+}
+static const struct of_device_id msm_vidc_dt_match[] = {
+ {.compatible = "qcom,msm-vidc"},
+};
+
+MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
+
+static struct platform_driver msm_vidc_driver = {
+ .probe = msm_vidc_probe,
+ .remove = msm_vidc_remove,
+ .driver = {
+ .name = "msm_vidc",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_vidc_dt_match,
+ },
+};
+
+static int __init msm_vidc_init(void)
+{
+ int rc = 0;
+ vidc_driver = kzalloc(sizeof(*vidc_driver),
+ GFP_KERNEL);
+ if (!vidc_driver) {
+ pr_err("Failed to allocate memroy for msm_vidc_drv\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&vidc_driver->cores);
+ spin_lock_init(&vidc_driver->lock);
+ vidc_driver->debugfs_root = debugfs_create_dir("msm_vidc", NULL);
+ if (!vidc_driver->debugfs_root)
+ pr_err("Failed to create debugfs for msm_vidc\n");
+
+ rc = platform_driver_register(&msm_vidc_driver);
+ if (rc) {
+ pr_err("Failed to register platform driver\n");
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+ }
+
+ return rc;
+}
+
+static void __exit msm_vidc_exit(void)
+{
+ platform_driver_unregister(&msm_vidc_driver);
+ debugfs_remove_recursive(vidc_driver->debugfs_root);
+ kfree(vidc_driver);
+ vidc_driver = NULL;
+}
+
+module_init(msm_vidc_init);
+module_exit(msm_vidc_exit);
diff --git a/drivers/media/video/msm_vidc/msm_vdec.c b/drivers/media/video/msm_vidc/msm_vdec.c
new file mode 100644
index 0000000..879d324
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.c
@@ -0,0 +1,872 @@
+/* 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 "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
+#define MAX_PLANES 1
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 6
+
+static const char *const mpeg_video_vidc_divx_format[] = {
+ "DIVX Format 4",
+ "DIVX Format 5",
+ "DIVX Format 6",
+ NULL
+};
+static const char *mpeg_video_stream_format[] = {
+ "NAL Format Start Codes",
+ "NAL Format One NAL Per Buffer",
+ "NAL Format One Byte Length",
+ "NAL Format Two Byte Length",
+ "NAL Format Four Byte Length",
+ NULL
+};
+static const char *const mpeg_video_output_order[] = {
+ "Display Order",
+ "Decode Order",
+ NULL
+};
+static const struct msm_vidc_ctrl msm_vdec_ctrls[] = {
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
+ .name = "NAL Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
+ ),
+ .qmenu = mpeg_video_stream_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
+ .name = "Output Order",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
+ ),
+ .qmenu = mpeg_video_output_order,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE,
+ .name = "Picture Type Decoding",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .minimum = 1,
+ .maximum = 15,
+ .default_value = 15,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
+ .name = "Keep Aspect Ratio",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
+ .name = "Deblocker Mode",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
+ .name = "Divx Format",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
+ .default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
+ .menu_skip_mask = ~(
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
+ (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
+ ),
+ .qmenu = mpeg_video_vidc_divx_format,
+ .step = 0,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
+ .name = "MB Error Map Reporting",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+ {
+ .id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
+ .name = "control",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ .step = 1,
+ .menu_skip_mask = 0,
+ .qmenu = NULL,
+ },
+};
+
+#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
+
+static u32 get_frame_size_nv12(int plane,
+ u32 height, u32 width)
+{
+ int stride = (width + 31) & (~31);
+ return height * stride * 3/2;
+}
+static u32 get_frame_size_nv21(int plane,
+ u32 height, u32 width)
+{
+ return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane,
+ u32 height, u32 width)
+{
+ return 0x500000;
+}
+
+static const struct msm_vidc_format vdec_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg2",
+ .description = "Mpeg2 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG2,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "YCrCb Semiplanar 4:2:0",
+ .description = "Y/CrCb 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv21,
+ .type = CAPTURE_PORT,
+ },
+};
+
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamon\n");
+ rc = vb2_streamon(q, i);
+ if (rc)
+ pr_err("streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ unsigned long flags;
+ struct list_head *ptr, *next;
+ struct internal_buf *buf;
+ struct extradata_buf *ebuf;
+
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ list_for_each_safe(ptr, next, &inst->extradatabufs) {
+ ebuf = list_entry(ptr, struct extradata_buf, list);
+ list_del(&ebuf->list);
+ msm_smem_free(inst->mem_client, ebuf->handle);
+ kfree(ebuf);
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+
+ pr_debug("Calling streamoff\n");
+ rc = vb2_streamoff(q, i);
+ if (rc)
+ pr_err("streamoff failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: {
+ struct extradata_buf *binfo;
+ for (i = 0; i < b->length; i++) {
+ pr_err("device_addr = %ld, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Failed to allocate shared mem\n");
+ return -ENOMEM;
+ }
+ binfo->device_addr = b->m.planes[i].m.userptr;
+ rc = msm_comm_allocate_extradata_buffers(inst, binfo);
+ if (rc) {
+ pr_err("msm_comm_allocate_extradata_buffers failed");
+ break;
+ }
+ buffer_info.extradata_size = binfo->handle->size;
+ buffer_info.extradata_addr = binfo->handle->device_addr;
+ rc = vidc_hal_session_set_buffers((void *)inst->session,
+ &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ break;
+ }
+ }
+ break;
+ }
+ default:
+ pr_err("Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_qbuf(q, b);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_dqbuf(q, b, true);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ if (!inst || !b) {
+ pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+
+ rc = vb2_reqbufs(q, b);
+ if (rc)
+ pr_err("Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fmt = inst->fmts[CAPTURE_PORT];
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ fmt = inst->fmts[OUTPUT_PORT];
+
+ if (fmt) {
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.height = inst->height;
+ f->fmt.pix_mp.width = inst->width;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, inst->height, inst->width);
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ inst->width = f->fmt.pix_mp.width;
+ inst->height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (fmt && fmt->type != CAPTURE_PORT) {
+ pr_err("Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (fmt && fmt->type != OUTPUT_PORT) {
+ pr_err("Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto err_invalid_fmt;
+ }
+ }
+
+ if (fmt) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ inst->fmts[fmt->type] = fmt;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ goto err_invalid_fmt;
+ }
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+err_invalid_fmt:
+ return rc;
+}
+
+int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
+ ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ pr_err("No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static int msm_vdec_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned long sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_frame_size frame_sz;
+ unsigned long flags;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ *num_planes = 1;
+ if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+ *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+ *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ pr_debug("Getting bufreqs on capture plane\n");
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ break;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_sz.width = inst->width;
+ frame_sz.height = inst->height;
+ pr_debug("width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ pr_err("Failed to set hal property for framesize\n");
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get buffer requirements: %d\n", rc);
+ break;
+ }
+ *num_planes = 1;
+ spin_lock_irqsave(&inst->lock, flags);
+ *num_buffers = inst->buff_req.buffer[1].buffer_count_actual;
+ spin_unlock_irqrestore(&inst->lock, flags);
+ pr_debug("size = %d, alignment = %d\n",
+ inst->buff_req.buffer[1].buffer_size,
+ inst->buff_req.buffer[1].buffer_alignment);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+
+ break;
+ default:
+ pr_err("Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct vb2_buf_entry *temp;
+ struct list_head *ptr, *next;
+ struct v4l2_control control;
+ struct hal_nal_stream_format_supported stream_format;
+ struct hal_enable_picture enable_picture;
+ struct hal_enable hal_property;
+ struct hal_enable prop;
+ u32 control_idx = 0;
+ enum hal_property property_id = 0;
+ u32 property_val = 0;
+ void *pdata;
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ for (; control_idx < NUM_CTRLS; control_idx++) {
+ control.id = msm_vdec_ctrls[control_idx].id;
+ rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
+ if (rc) {
+ pr_err("Failed to get control value for ID=%d\n",
+ msm_vdec_ctrls[control_idx].id);
+ } else {
+ property_id = 0;
+ switch (control.id) {
+ case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
+ property_id =
+ HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
+ stream_format.nal_stream_format_supported =
+ (0x00000001 << control.value);
+ pdata = &stream_format;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
+ property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE:
+ property_id =
+ HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
+ enable_picture.picture_type = control.value;
+ pdata = &enable_picture;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
+ property_id =
+ HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
+ property_id =
+ HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
+ property_id = HAL_PARAM_DIVX_FORMAT;
+ property_val = control.value;
+ pdata = &property_val;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
+ property_id =
+ HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
+ property_id =
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
+ hal_property.enable = control.value;
+ pdata = &hal_property;
+ break;
+ default:
+ break;
+ }
+ if (property_id) {
+ pr_err("Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
+ property_id,
+ msm_vdec_ctrls[control_idx].id,
+ control.value);
+ rc = vidc_hal_session_set_property((void *)
+ inst->session, property_id,
+ pdata);
+ }
+ if (rc)
+ pr_err("Failed to set hal property for framesize\n");
+ }
+ }
+
+ prop.enable = 1;
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, &prop);
+ if (rc)
+ pr_err("Failed to set smooth streaming\n");
+
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto fail_start;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ pr_err("Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static int msm_vdec_start_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_vdec_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc)
+ pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
+ return rc;
+}
+
+static void msm_vdec_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_vdec_vb2q_ops = {
+ .queue_setup = msm_vdec_queue_setup,
+ .start_streaming = msm_vdec_start_streaming,
+ .buf_queue = msm_vdec_buf_queue,
+ .stop_streaming = msm_vdec_stop_streaming,
+};
+
+const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
+{
+ return &msm_vdec_vb2q_ops;
+}
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ pr_err("Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[OUTPUT_PORT] = &vdec_formats[1];
+ inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
+ inst->height = DEFAULT_HEIGHT;
+ inst->width = DEFAULT_WIDTH;
+ return rc;
+}
+
+static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
+
+ .s_ctrl = msm_vdec_op_s_ctrl,
+ .g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
+};
+
+const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
+{
+ return &msm_vdec_ctrl_ops;
+}
+
+int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_s_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl)
+{
+ return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
+}
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
+{
+ int idx = 0;
+ struct v4l2_ctrl_config ctrl_cfg;
+ int ret_val = 0;
+
+ ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS);
+
+ if (ret_val) {
+ pr_err("CTRL ERR: Control handler init failed, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+ }
+
+ for (; idx < NUM_CTRLS; idx++) {
+ if (IS_PRIV_CTRL(msm_vdec_ctrls[idx].id)) {
+ /*add private control*/
+ ctrl_cfg.def = msm_vdec_ctrls[idx].default_value;
+ ctrl_cfg.flags = 0;
+ ctrl_cfg.id = msm_vdec_ctrls[idx].id;
+ /*ctrl_cfg.is_private =
+ * msm_vdec_ctrls[idx].is_private;
+ * ctrl_cfg.is_volatile =
+ * msm_vdec_ctrls[idx].is_volatile;*/
+ ctrl_cfg.max = msm_vdec_ctrls[idx].maximum;
+ ctrl_cfg.min = msm_vdec_ctrls[idx].minimum;
+ ctrl_cfg.menu_skip_mask =
+ msm_vdec_ctrls[idx].menu_skip_mask;
+ ctrl_cfg.name = msm_vdec_ctrls[idx].name;
+ ctrl_cfg.ops = &msm_vdec_ctrl_ops;
+ ctrl_cfg.step = msm_vdec_ctrls[idx].step;
+ ctrl_cfg.type = msm_vdec_ctrls[idx].type;
+ ctrl_cfg.qmenu = msm_vdec_ctrls[idx].qmenu;
+
+ v4l2_ctrl_new_custom(&inst->ctrl_handler,
+ &ctrl_cfg, NULL);
+ } else {
+ if (msm_vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) {
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].menu_skip_mask,
+ msm_vdec_ctrls[idx].default_value);
+ } else {
+ v4l2_ctrl_new_std(&inst->ctrl_handler,
+ &msm_vdec_ctrl_ops,
+ msm_vdec_ctrls[idx].id,
+ msm_vdec_ctrls[idx].minimum,
+ msm_vdec_ctrls[idx].maximum,
+ msm_vdec_ctrls[idx].step,
+ msm_vdec_ctrls[idx].default_value);
+ }
+ }
+ }
+ ret_val = inst->ctrl_handler.error;
+ if (ret_val)
+ pr_err("CTRL ERR: Error adding ctrls to ctrl handle, %d\n",
+ inst->ctrl_handler.error);
+ return ret_val;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vdec.h b/drivers/media/video/msm_vidc/msm_vdec.h
new file mode 100644
index 0000000..6529065
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vdec.h
@@ -0,0 +1,35 @@
+/* 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_VDEC_H_
+#define _MSM_VDEC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_vdec_inst_init(struct msm_vidc_inst *inst);
+int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
+int msm_vdec_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vdec_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vdec_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vdec_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vdec_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vdec_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_vdec_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_venc.c b/drivers/media/video/msm_vidc/msm_venc.c
new file mode 100644
index 0000000..cae2d6f
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.c
@@ -0,0 +1,522 @@
+/* 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 "msm_vidc_internal.h"
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define MSM_VENC_DVC_NAME "msm_venc_8974"
+#define DEFAULT_HEIGHT 720
+#define DEFAULT_WIDTH 1280
+#define MIN_NUM_OUTPUT_BUFFERS 2
+#define MAX_NUM_OUTPUT_BUFFERS 8
+static u32 get_frame_size_nv12(int plane, u32 height, u32 width)
+{
+ int stride = (width + 31) & (~31);
+ return height * stride * 3/2;
+}
+static u32 get_frame_size_nv21(int plane, u32 height, u32 width)
+{
+ return height * width * 2;
+}
+
+static u32 get_frame_size_compressed(int plane, u32 height, u32 width)
+{
+ return width * height / 2;
+}
+
+static const struct msm_vidc_format venc_formats[] = {
+ {
+ .name = "YCbCr Semiplanar 4:2:0",
+ .description = "Y/CbCr 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv12,
+ .type = OUTPUT_PORT,
+ },
+ {
+ .name = "Mpeg4",
+ .description = "Mpeg4 compressed format",
+ .fourcc = V4L2_PIX_FMT_MPEG4,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H263",
+ .description = "H263 compressed format",
+ .fourcc = V4L2_PIX_FMT_H263,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "H264",
+ .description = "H264 compressed format",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_compressed,
+ .type = CAPTURE_PORT,
+ },
+ {
+ .name = "YCrCb Semiplanar 4:2:0",
+ .description = "Y/CrCb 4:2:0",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .get_frame_size = get_frame_size_nv21,
+ .type = OUTPUT_PORT,
+ },
+};
+
+static int msm_venc_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned long sizes[],
+ void *alloc_ctxs[])
+{
+ int i, rc = 0;
+ struct msm_vidc_inst *inst;
+ struct hal_frame_size frame_sz;
+ unsigned long flags;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ *num_planes = 1;
+ if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
+ *num_buffers > MAX_NUM_OUTPUT_BUFFERS)
+ *num_buffers = MIN_NUM_OUTPUT_BUFFERS;
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[OUTPUT_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ break;
+ }
+ frame_sz.buffer_type = HAL_BUFFER_INPUT;
+ frame_sz.width = inst->width;
+ frame_sz.height = inst->height;
+ pr_debug("width = %d, height = %d\n",
+ frame_sz.width, frame_sz.height);
+ rc = vidc_hal_session_set_property((void *)inst->session,
+ HAL_PARAM_FRAME_SIZE, &frame_sz);
+ if (rc) {
+ pr_err("Failed to set hal property for framesize\n");
+ break;
+ }
+ rc = msm_comm_try_get_bufreqs(inst);
+ if (rc) {
+ pr_err("Failed to get buffer requirements: %d\n", rc);
+ break;
+ }
+ *num_planes = 1;
+ spin_lock_irqsave(&inst->lock, flags);
+ *num_buffers = inst->buff_req.buffer[0].buffer_count_actual;
+ spin_unlock_irqrestore(&inst->lock, flags);
+ pr_debug("size = %d, alignment = %d, count = %d\n",
+ inst->buff_req.buffer[0].buffer_size,
+ inst->buff_req.buffer[0].buffer_alignment,
+ inst->buff_req.buffer[0].buffer_count_actual);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst->fmts[CAPTURE_PORT]->get_frame_size(
+ i, inst->height, inst->width);
+ }
+
+ break;
+ default:
+ pr_err("Invalid q type = %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static inline int start_streaming(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct vb2_buf_entry *temp;
+ struct list_head *ptr, *next;
+ rc = msm_comm_set_scratch_buffers(inst);
+ if (rc) {
+ pr_err("Failed to set scratch buffers: %d\n", rc);
+ goto fail_start;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
+ if (rc) {
+ pr_err("Failed to move inst: %p to start done state\n",
+ inst);
+ goto fail_start;
+ }
+ spin_lock_irqsave(&inst->lock, flags);
+ if (!list_empty(&inst->pendingq)) {
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ temp = list_entry(ptr, struct vb2_buf_entry, list);
+ rc = msm_comm_qbuf(temp->vb);
+ if (rc) {
+ pr_err("Failed to qbuf to hardware\n");
+ break;
+ }
+ list_del(&temp->list);
+ kfree(temp);
+ }
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ return rc;
+fail_start:
+ return rc;
+}
+
+static int msm_venc_start_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamon called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ if (inst->vb2_bufq[CAPTURE_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ if (inst->vb2_bufq[OUTPUT_PORT].streaming)
+ rc = start_streaming(inst);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
+static int msm_venc_stop_streaming(struct vb2_queue *q)
+{
+ struct msm_vidc_inst *inst;
+ int rc = 0;
+ if (!q || !q->drv_priv) {
+ pr_err("Invalid input, q = %p\n", q);
+ return -EINVAL;
+ }
+ inst = q->drv_priv;
+ pr_debug("Streamoff called on: %d capability\n", q->type);
+ switch (q->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
+ break;
+ default:
+ pr_err("Q-type is not supported: %d\n", q->type);
+ rc = -EINVAL;
+ break;
+ }
+ if (rc)
+ pr_err("Failed to move inst: %p, cap = %d to state: %d\n",
+ inst, q->type, MSM_VIDC_CLOSE_DONE);
+ return rc;
+}
+
+static void msm_venc_buf_queue(struct vb2_buffer *vb)
+{
+ int rc;
+ rc = msm_comm_qbuf(vb);
+ if (rc)
+ pr_err("Failed to queue buffer: %d\n", rc);
+}
+
+static const struct vb2_ops msm_venc_vb2q_ops = {
+ .queue_setup = msm_venc_queue_setup,
+ .start_streaming = msm_venc_start_streaming,
+ .buf_queue = msm_venc_buf_queue,
+ .stop_streaming = msm_venc_stop_streaming,
+};
+
+const struct vb2_ops *msm_venc_get_vb2q_ops(void)
+{
+ return &msm_venc_vb2q_ops;
+}
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (!inst) {
+ pr_err("Invalid input = %p\n", inst);
+ return -EINVAL;
+ }
+ inst->fmts[CAPTURE_PORT] = &venc_formats[1];
+ inst->fmts[OUTPUT_PORT] = &venc_formats[0];
+ inst->height = DEFAULT_HEIGHT;
+ inst->width = DEFAULT_WIDTH;
+ return rc;
+}
+
+int msm_venc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
+{
+ if (!inst || !cap) {
+ pr_err("Invalid input, inst = %p, cap = %p\n", inst, cap);
+ return -EINVAL;
+ }
+ strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, MSM_VENC_DVC_NAME, sizeof(cap->card));
+ cap->bus_info[0] = 0;
+ cap->version = MSM_VIDC_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
+ V4L2_CAP_VIDEO_OUTPUT_MPLANE |
+ V4L2_CAP_STREAMING;
+ memset(cap->reserved, 0, sizeof(cap->reserved));
+ return 0;
+}
+
+int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, f = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT);
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_index(venc_formats,
+ ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT);
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ }
+
+ memset(f->reserved, 0 , sizeof(f->reserved));
+ if (fmt) {
+ strlcpy(f->description, fmt->description,
+ sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ } else {
+ pr_err("No more formats found\n");
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ CAPTURE_PORT);
+ if (fmt && fmt->type != CAPTURE_PORT) {
+ pr_err("Format: %d not supported on CAPTURE port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ inst->width = f->fmt.pix_mp.width;
+ inst->height = f->fmt.pix_mp.height;
+ fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats,
+ ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat,
+ OUTPUT_PORT);
+ if (fmt && fmt->type != OUTPUT_PORT) {
+ pr_err("Format: %d not supported on OUTPUT port\n",
+ f->fmt.pix_mp.pixelformat);
+ rc = -EINVAL;
+ goto exit;
+ }
+ }
+
+ if (fmt) {
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, f->fmt.pix_mp.height,
+ f->fmt.pix_mp.width);
+ }
+ inst->fmts[fmt->type] = fmt;
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
+ if (rc) {
+ pr_err("Failed to open instance\n");
+ goto exit;
+ }
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+exit:
+ return rc;
+}
+
+int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
+{
+ const struct msm_vidc_format *fmt = NULL;
+ int rc = 0;
+ int i;
+ if (!inst || !f) {
+ pr_err("Invalid input, inst = %p, format = %p\n", inst, f);
+ return -EINVAL;
+ }
+ if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ fmt = inst->fmts[CAPTURE_PORT];
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ fmt = inst->fmts[OUTPUT_PORT];
+
+ if (fmt) {
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.height = inst->height;
+ f->fmt.pix_mp.width = inst->width;
+ for (i = 0; i < fmt->num_planes; ++i) {
+ f->fmt.pix_mp.plane_fmt[i].sizeimage =
+ fmt->get_frame_size(i, inst->height, inst->width);
+ }
+ } else {
+ pr_err("Buf type not recognized, type = %d\n",
+ f->type);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+int msm_venc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ if (!inst || !b) {
+ pr_err("Invalid input, inst = %p, buffer = %p\n", inst, b);
+ return -EINVAL;
+ }
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+
+ rc = vb2_reqbufs(q, b);
+ if (rc)
+ pr_err("Failed to get reqbufs, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst,
+ struct v4l2_buffer *b)
+{
+ int rc = 0;
+ int i;
+ struct vidc_buffer_addr_info buffer_info;
+
+ switch (b->type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ for (i = 0; i < b->length; i++) {
+ pr_err("device_addr = %ld, size = %d\n",
+ b->m.planes[i].m.userptr,
+ b->m.planes[i].length);
+ buffer_info.buffer_size = b->m.planes[i].length;
+ buffer_info.buffer_type = HAL_BUFFER_OUTPUT;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr =
+ b->m.planes[i].m.userptr;
+ buffer_info.extradata_size = 0;
+ buffer_info.extradata_addr = 0;
+ rc = vidc_hal_session_set_buffers((void *)inst->session,
+ &buffer_info);
+ if (rc)
+ pr_err("vidc_hal_session_set_buffers failed");
+ }
+ break;
+ default:
+ pr_err("Buffer type not recognized: %d\n", b->type);
+ break;
+ }
+ return rc;
+}
+
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_qbuf(q, b);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
+{
+ struct vb2_queue *q = NULL;
+ int rc = 0;
+ q = msm_comm_get_vb2q(inst, b->type);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", b->type);
+ return -EINVAL;
+ }
+ rc = vb2_dqbuf(q, b, true);
+ if (rc)
+ pr_err("Failed to qbuf, %d\n", rc);
+ return rc;
+}
+
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamon\n");
+ rc = vb2_streamon(q, i);
+ if (rc)
+ pr_err("streamon failed on port: %d\n", i);
+ return rc;
+}
+
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ q = msm_comm_get_vb2q(inst, i);
+ if (!q) {
+ pr_err("Failed to find buffer queue for type = %d\n", i);
+ return -EINVAL;
+ }
+ pr_debug("Calling streamoff\n");
+ rc = vb2_streamoff(q, i);
+ if (rc)
+ pr_err("streamoff failed on port: %d\n", i);
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_venc.h b/drivers/media/video/msm_vidc/msm_venc.h
new file mode 100644
index 0000000..4a156dd
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_venc.h
@@ -0,0 +1,35 @@
+/* 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_VENC_H_
+#define _MSM_VENC_H_
+
+#include <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+
+int msm_venc_inst_init(struct msm_vidc_inst *inst);
+int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
+int msm_venc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_venc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_venc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_venc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_venc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_venc_prepare_buf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b);
+int msm_venc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+int msm_venc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i);
+struct vb2_ops *msm_venc_get_vb2q_ops(void);
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc.c b/drivers/media/video/msm_vidc/msm_vidc.c
new file mode 100644
index 0000000..4725f5f
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc.c
@@ -0,0 +1,339 @@
+/* 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 <media/msm_vidc.h>
+#include "msm_vidc_internal.h"
+#include "msm_vdec.h"
+#include "msm_venc.h"
+#include "msm_vidc_common.h"
+#include "msm_smem.h"
+
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *wait)
+{
+ int rc = 0;
+ struct msm_vidc_inst *inst = instance;
+ struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
+ struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
+ struct vb2_buffer *out_vb = NULL;
+ struct vb2_buffer *cap_vb = NULL;
+ unsigned long flags;
+ if (!outq->streaming && !capq->streaming) {
+ pr_err("Returning POLLERR from here: %d, %d\n",
+ outq->streaming, capq->streaming);
+ return POLLERR;
+ }
+ poll_wait(filp, &capq->done_wq, wait);
+ poll_wait(filp, &outq->done_wq, wait);
+ spin_lock_irqsave(&capq->done_lock, flags);
+ if (!list_empty(&capq->done_list))
+ cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
+ done_entry);
+ if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
+ || cap_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLIN | POLLRDNORM;
+ spin_unlock_irqrestore(&capq->done_lock, flags);
+ spin_lock_irqsave(&outq->done_lock, flags);
+ if (!list_empty(&outq->done_list))
+ out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
+ done_entry);
+ if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
+ || out_vb->state == VB2_BUF_STATE_ERROR))
+ rc |= POLLOUT | POLLWRNORM;
+ spin_unlock_irqrestore(&outq->done_lock, flags);
+ return rc;
+}
+
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_querycap(instance, cap);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_querycap(instance, cap);
+ return -EINVAL;
+}
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_enum_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_enum_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_fmt(instance, f);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_s_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_fmt(instance, f);
+ else if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_g_fmt(instance, f);
+ return -EINVAL;
+}
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_s_ctrl(instance, control);
+ return -EINVAL;
+}
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_g_ctrl(instance, control);
+ return -EINVAL;
+}
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_reqbufs(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_reqbufs(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_prepare_buf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_prepare_buf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_qbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_qbuf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_dqbuf(instance, b);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_dqbuf(instance, b);
+ return -EINVAL;
+}
+
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamon(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamon(instance, i);
+ return -EINVAL;
+}
+
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
+{
+ struct msm_vidc_inst *inst = instance;
+ if (inst->session_type == MSM_VIDC_DECODER)
+ return msm_vdec_streamoff(instance, i);
+ if (inst->session_type == MSM_VIDC_ENCODER)
+ return msm_venc_streamoff(instance, i);
+ return -EINVAL;
+}
+
+void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
+ unsigned long size, int write)
+{
+ return NULL;
+}
+
+void vidc_put_userptr(void *buf_priv)
+{
+}
+
+static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
+ .get_userptr = vidc_get_userptr,
+ .put_userptr = vidc_put_userptr,
+};
+
+static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
+ enum v4l2_buf_type type, enum session_type sess)
+{
+ struct vb2_queue *q = NULL;
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ q = &inst->vb2_bufq[CAPTURE_PORT];
+ } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ q = &inst->vb2_bufq[OUTPUT_PORT];
+ } else {
+ pr_err("buf_type = %d not recognised\n", type);
+ return -EINVAL;
+ }
+ q->type = type;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->io_flags = 0;
+ if (sess == MSM_VIDC_DECODER)
+ q->ops = msm_vdec_get_vb2q_ops();
+ else if (sess == MSM_VIDC_ENCODER)
+ q->ops = msm_venc_get_vb2q_ops();
+ q->mem_ops = &msm_vidc_vb2_mem_ops;
+ q->drv_priv = inst;
+ return vb2_queue_init(q);
+}
+
+void *msm_vidc_open(int core_id, int session_type)
+{
+ struct msm_vidc_inst *inst = NULL;
+ struct msm_vidc_core *core = NULL;
+ unsigned long flags;
+ int rc = 0;
+ int i = 0;
+ if (core_id >= MSM_VIDC_CORES_MAX ||
+ session_type >= MSM_VIDC_MAX_DEVICES) {
+ pr_err("Invalid input, core_id = %d, session = %d\n",
+ core_id, session_type);
+ goto err_invalid_core;
+ }
+ core = get_vidc_core(core_id);
+ if (!core) {
+ pr_err("Failed to find core for core_id = %d\n", core_id);
+ goto err_invalid_core;
+ }
+
+ inst = kzalloc(sizeof(*inst), GFP_KERNEL);
+ if (!inst) {
+ pr_err("Unable to allocate video instance\n");
+ goto err_no_mem;
+ }
+ mutex_init(&inst->sync_lock);
+ spin_lock_init(&inst->lock);
+ inst->session_type = session_type;
+ INIT_LIST_HEAD(&inst->pendingq);
+ INIT_LIST_HEAD(&inst->internalbufs);
+ INIT_LIST_HEAD(&inst->extradatabufs);
+ inst->state = MSM_VIDC_CORE_UNINIT_DONE;
+ inst->core = core;
+ for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
+ i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
+ init_completion(&inst->completions[i]);
+ }
+ inst->mem_client = msm_smem_new_client(SMEM_ION);
+ if (!inst->mem_client) {
+ pr_err("Failed to create memory client\n");
+ goto fail_mem_client;
+ }
+ if (session_type == MSM_VIDC_DECODER) {
+ msm_vdec_inst_init(inst);
+ msm_vdec_ctrl_init(inst);
+ } else if (session_type == MSM_VIDC_ENCODER) {
+ msm_venc_inst_init(inst);
+ }
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ session_type);
+ if (rc) {
+ pr_err("Failed to initialize vb2 queue on capture port\n");
+ goto fail_init;
+ }
+ rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ session_type);
+ if (rc) {
+ pr_err("Failed to initialize vb2 queue on capture port\n");
+ goto fail_init;
+ }
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
+ if (rc) {
+ pr_err("Failed to move video instance to init state\n");
+ goto fail_init;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ list_add_tail(&inst->list, &core->instances);
+ spin_unlock_irqrestore(&core->lock, flags);
+ return inst;
+fail_init:
+ msm_smem_delete_client(inst->mem_client);
+fail_mem_client:
+ kfree(inst);
+ inst = NULL;
+err_no_mem:
+err_invalid_core:
+ return inst;
+}
+
+static void cleanup_instance(struct msm_vidc_inst *inst)
+{
+ unsigned long flags;
+ struct list_head *ptr, *next;
+ struct vb2_buf_entry *entry;
+ struct internal_buf *buf;
+ struct extradata_buf *ebuf;
+ if (inst) {
+ spin_lock_irqsave(&inst->lock, flags);
+ list_for_each_safe(ptr, next, &inst->pendingq) {
+ entry = list_entry(ptr, struct vb2_buf_entry, list);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ list_for_each_safe(ptr, next, &inst->internalbufs) {
+ buf = list_entry(ptr, struct internal_buf, list);
+ list_del(&buf->list);
+ msm_smem_free(inst->mem_client, buf->handle);
+ kfree(buf);
+ }
+ list_for_each_safe(ptr, next, &inst->extradatabufs) {
+ ebuf = list_entry(ptr, struct extradata_buf, list);
+ list_del(&ebuf->list);
+ msm_smem_free(inst->mem_client, ebuf->handle);
+ kfree(ebuf);
+ }
+ spin_unlock_irqrestore(&inst->lock, flags);
+ msm_smem_delete_client(inst->mem_client);
+ }
+}
+
+int msm_vidc_close(void *instance)
+{
+ struct msm_vidc_inst *inst = instance;
+ struct msm_vidc_inst *temp;
+ struct msm_vidc_core *core;
+ struct list_head *ptr, *next;
+ int rc = 0;
+ core = inst->core;
+ mutex_lock(&core->sync_lock);
+ list_for_each_safe(ptr, next, &core->instances) {
+ temp = list_entry(ptr, struct msm_vidc_inst, list);
+ if (temp == inst) {
+ list_del(&inst->list);
+ kfree(inst);
+ }
+ }
+ mutex_unlock(&core->sync_lock);
+ rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
+ if (rc)
+ pr_err("Failed to move video instance to init state\n");
+ cleanup_instance(inst);
+ pr_debug("Closed the instance\n");
+ return 0;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.c b/drivers/media/video/msm_vidc/msm_vidc_common.c
new file mode 100644
index 0000000..e889b1c
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.c
@@ -0,0 +1,929 @@
+/* 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/sched.h>
+#include <linux/slab.h>
+
+#include "msm_vidc_common.h"
+#include "vidc_hal_api.h"
+#include "msm_smem.h"
+
+#define HW_RESPONSE_TIMEOUT 5000
+
+#define IS_ALREADY_IN_STATE(__p, __d) ({\
+ int __rc = (__p >= __d);\
+ __rc; \
+})
+
+struct msm_vidc_core *get_vidc_core(int core_id)
+{
+ struct msm_vidc_core *core;
+ int found = 0;
+ unsigned long flags;
+ if (core_id > MSM_VIDC_CORES_MAX) {
+ pr_err("Core id = %d is greater than max = %d\n",
+ core_id, MSM_VIDC_CORES_MAX);
+ return NULL;
+ }
+ spin_lock_irqsave(&vidc_driver->lock, flags);
+ list_for_each_entry(core, &vidc_driver->cores, list) {
+ if (core && core->id == core_id)
+ found = 1;
+ break;
+ }
+ spin_unlock_irqrestore(&vidc_driver->lock, flags);
+ if (found)
+ return core;
+ return NULL;
+}
+
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type)
+{
+ int i, k = 0;
+ if (!fmt || index < 0) {
+ pr_err("Invalid inputs, fmt = %p, index = %d\n",
+ fmt, index);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].type != fmt_type)
+ continue;
+ if (k == index)
+ break;
+ k++;
+ }
+ if (i == size) {
+ pr_err("Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type)
+{
+ int i;
+ if (!fmt) {
+ pr_err("Invalid inputs, fmt = %p\n", fmt);
+ return NULL;
+ }
+ for (i = 0; i < size; i++) {
+ if (fmt[i].fourcc == fourcc)
+ break;
+ }
+ if (i == size) {
+ pr_err("Format not found\n");
+ return NULL;
+ }
+ return &fmt[i];
+}
+
+struct vb2_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type)
+{
+ if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return &inst->vb2_bufq[CAPTURE_PORT];
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ return &inst->vb2_bufq[OUTPUT_PORT];
+ return NULL;
+}
+
+static void handle_sys_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_core *core;
+ struct vidc_hal_sys_init_done *sys_init_msg;
+ int index = SYS_MSG_INDEX(cmd);
+ if (!response) {
+ pr_err("Failed to get valid response for sys init\n");
+ return;
+ }
+ core = get_vidc_core(response->device_id);
+ if (!core) {
+ pr_err("Wrong device_id received\n");
+ return;
+ }
+ pr_debug("index = %d\n", index);
+ pr_debug("ptr = %p\n", &(core->completions[index]));
+ complete(&(core->completions[index]));
+ sys_init_msg = response->data;
+ if (!sys_init_msg) {
+ pr_err("sys_init_done message not proper\n");
+ return;
+ }
+}
+
+static inline void change_inst_state(struct msm_vidc_inst *inst,
+ enum instance_state state)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&inst->lock, flags);
+ pr_debug("Moved inst: %p from state: %d to state: %d\n",
+ inst, inst->state, state);
+ inst->state = state;
+ spin_unlock_irqrestore(&inst->lock, flags);
+}
+
+static int signal_session_msg_receipt(enum command_response cmd,
+ struct msm_vidc_inst *inst)
+{
+ if (!inst) {
+ pr_err("Invalid(%p) instance id\n", inst);
+ return -EINVAL;
+ }
+ complete(&inst->completions[SESSION_MSG_INDEX(cmd)]);
+ return 0;
+}
+
+static int wait_for_sess_signal_receipt(struct msm_vidc_inst *inst,
+ enum command_response cmd)
+{
+ int rc = 0;
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(cmd)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+static int wait_for_state(struct msm_vidc_inst *inst,
+ enum instance_state flipped_state,
+ enum instance_state desired_state,
+ enum command_response hal_cmd)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, desired_state)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto err_same_state;
+ }
+ pr_debug("Waiting for hal_cmd: %d\n", hal_cmd);
+ rc = wait_for_sess_signal_receipt(inst, hal_cmd);
+ if (!rc)
+ change_inst_state(inst, desired_state);
+err_same_state:
+ return rc;
+}
+
+static void handle_session_init_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ return;
+ } else {
+ pr_err("Failed to get valid response for session init\n");
+ }
+}
+
+static void handle_session_prop_info(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ unsigned long flags;
+ if (!response || !response->data) {
+ pr_err("Failed to get valid response for prop info\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ spin_lock_irqsave(&inst->lock, flags);
+ memcpy(&inst->buff_req, response->data,
+ sizeof(struct buffer_requirements));
+ spin_unlock_irqrestore(&inst->lock, flags);
+ signal_session_msg_receipt(cmd, inst);
+}
+
+static void handle_load_resource_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response)
+ inst = (struct msm_vidc_inst *)response->session_id;
+ else
+ pr_err("Failed to get valid response for load resource\n");
+}
+
+static void handle_start_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for start done\n");
+ }
+}
+
+static void handle_stop_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for stop done\n");
+ }
+}
+
+static void handle_release_res_done(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for release"
+ " resource done\n");
+ }
+}
+
+static void handle_session_close(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_cmd_done *response = data;
+ struct msm_vidc_inst *inst;
+ if (response) {
+ inst = (struct msm_vidc_inst *)response->session_id;
+ signal_session_msg_receipt(cmd, inst);
+ } else {
+ pr_err("Failed to get valid response for session close\n");
+ }
+}
+
+static struct vb2_buffer *get_vb_from_device_addr(struct vb2_queue *q,
+ u32 dev_addr)
+{
+ struct vb2_buffer *vb = NULL;
+ int found = 0;
+ if (!q) {
+ pr_err("Invalid parameter\n");
+ return NULL;
+ }
+ list_for_each_entry(vb, &q->queued_list, queued_entry) {
+ if (vb->v4l2_planes[0].m.userptr == dev_addr) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ pr_err("Failed to find the buffer in queued list: %d, %d\n",
+ dev_addr, q->type);
+ vb = NULL;
+ }
+ return vb;
+}
+
+static void handle_ebd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct vb2_buffer *vb;
+ if (!response) {
+ pr_err("Invalid response from vidc_hal\n");
+ return;
+ }
+ vb = response->clnt_data;
+ if (vb)
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+}
+
+static void handle_fbd(enum command_response cmd, void *data)
+{
+ struct msm_vidc_cb_data_done *response = data;
+ struct msm_vidc_inst *inst;
+ struct vb2_buffer *vb;
+ struct vidc_hal_fbd *fill_buf_done;
+ if (!response) {
+ pr_err("Invalid response from vidc_hal\n");
+ return;
+ }
+ inst = (struct msm_vidc_inst *)response->session_id;
+ fill_buf_done = (struct vidc_hal_fbd *)&response->output_done;
+ vb = get_vb_from_device_addr(&inst->vb2_bufq[CAPTURE_PORT],
+ (u32)fill_buf_done->packet_buffer1);
+ if (vb) {
+ vb->v4l2_planes[0].bytesused = fill_buf_done->filled_len1;
+ pr_err("Filled length = %d\n", vb->v4l2_planes[0].bytesused);
+ if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS)
+ vb->v4l2_buf.flags |= V4L2_BUF_FLAG_EOS;
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ }
+}
+
+void handle_cmd_response(enum command_response cmd, void *data)
+{
+ pr_debug("Command response = %d\n", cmd);
+ switch (cmd) {
+ case SYS_INIT_DONE:
+ handle_sys_init_done(cmd, data);
+ break;
+ case SESSION_INIT_DONE:
+ handle_session_init_done(cmd, data);
+ break;
+ case SESSION_PROPERTY_INFO:
+ handle_session_prop_info(cmd, data);
+ break;
+ case SESSION_LOAD_RESOURCE_DONE:
+ handle_load_resource_done(cmd, data);
+ break;
+ case SESSION_START_DONE:
+ handle_start_done(cmd, data);
+ break;
+ case SESSION_ETB_DONE:
+ handle_ebd(cmd, data);
+ break;
+ case SESSION_FTB_DONE:
+ handle_fbd(cmd, data);
+ break;
+ case SESSION_STOP_DONE:
+ handle_stop_done(cmd, data);
+ break;
+ case SESSION_RELEASE_RESOURCE_DONE:
+ handle_release_res_done(cmd, data);
+ break;
+ case SESSION_END_DONE:
+ handle_session_close(cmd, data);
+ break;
+ default:
+ pr_err("response unhandled\n");
+ break;
+ }
+}
+
+static int msm_comm_init_core_done(struct msm_vidc_inst *inst)
+{
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ int rc = 0;
+ mutex_lock(&core->sync_lock);
+ if (core->state >= VIDC_CORE_INIT_DONE) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_inited;
+ }
+ pr_debug("Waiting for SYS_INIT_DONE\n");
+ rc = wait_for_completion_timeout(
+ &core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ goto exit;
+ } else {
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INIT_DONE;
+ spin_unlock_irqrestore(&core->lock, flags);
+ }
+ pr_debug("SYS_INIT_DONE!!!\n");
+core_already_inited:
+ change_inst_state(inst, MSM_VIDC_CORE_INIT_DONE);
+ rc = 0;
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static int msm_comm_init_core(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ mutex_lock(&core->sync_lock);
+ if (core->state >= VIDC_CORE_INIT) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_inited;
+ }
+ init_completion(&core->completions[SYS_MSG_INDEX(SYS_INIT_DONE)]);
+ rc = vidc_hal_core_init(core->device);
+ if (rc) {
+ pr_err("Failed to init core, id = %d\n", core->id);
+ goto exit;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_INIT;
+ spin_unlock_irqrestore(&core->lock, flags);
+core_already_inited:
+ change_inst_state(inst, MSM_VIDC_CORE_INIT);
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static int msm_vidc_deinit_core(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_vidc_core *core = inst->core;
+ unsigned long flags;
+ mutex_lock(&core->sync_lock);
+ if (core->state == VIDC_CORE_UNINIT) {
+ pr_err("Video core: %d is already in state: %d\n",
+ core->id, core->state);
+ goto core_already_uninited;
+ }
+ if (list_empty(&core->instances)) {
+ pr_debug("Calling vidc_hal_core_release\n");
+ rc = vidc_hal_core_release(core->device);
+ if (rc) {
+ pr_err("Failed to release core, id = %d\n", core->id);
+ goto exit;
+ }
+ spin_lock_irqsave(&core->lock, flags);
+ core->state = VIDC_CORE_UNINIT;
+ spin_unlock_irqrestore(&core->lock, flags);
+ }
+core_already_uninited:
+ change_inst_state(inst, MSM_VIDC_CORE_UNINIT);
+exit:
+ mutex_unlock(&core->sync_lock);
+ return rc;
+}
+
+static enum hal_domain get_hal_domain(int session_type)
+{
+ enum hal_domain domain;
+ switch (session_type) {
+ case MSM_VIDC_ENCODER:
+ domain = HAL_VIDEO_DOMAIN_ENCODER;
+ break;
+ case MSM_VIDC_DECODER:
+ domain = HAL_VIDEO_DOMAIN_DECODER;
+ break;
+ default:
+ pr_err("Wrong domain\n");
+ domain = HAL_UNUSED_DOMAIN;
+ break;
+ }
+ return domain;
+}
+
+static enum hal_video_codec get_hal_codec_type(int fourcc)
+{
+ enum hal_video_codec codec;
+ pr_debug("codec in %s is 0x%x", __func__, fourcc);
+ switch (fourcc) {
+ case V4L2_PIX_FMT_H264:
+ case V4L2_PIX_FMT_H264_NO_SC:
+ codec = HAL_VIDEO_CODEC_H264;
+ break;
+ case V4L2_PIX_FMT_H263:
+ codec = HAL_VIDEO_CODEC_H263;
+ break;
+ case V4L2_PIX_FMT_MPEG1:
+ codec = HAL_VIDEO_CODEC_MPEG1;
+ break;
+ case V4L2_PIX_FMT_MPEG2:
+ codec = HAL_VIDEO_CODEC_MPEG2;
+ break;
+ case V4L2_PIX_FMT_MPEG4:
+ codec = HAL_VIDEO_CODEC_MPEG4;
+ break;
+ case V4L2_PIX_FMT_VC1_ANNEX_G:
+ case V4L2_PIX_FMT_VC1_ANNEX_L:
+ codec = HAL_VIDEO_CODEC_VC1;
+ break;
+ /*HAL_VIDEO_CODEC_MVC
+ HAL_VIDEO_CODEC_DIVX_311
+ HAL_VIDEO_CODEC_DIVX
+ HAL_VIDEO_CODEC_SPARK
+ HAL_VIDEO_CODEC_VP6
+ HAL_VIDEO_CODEC_VP7
+ HAL_VIDEO_CODEC_VP8*/
+ default:
+ pr_err("Wrong codec: %d\n", fourcc);
+ codec = HAL_UNUSED_CODEC;
+ }
+ return codec;
+}
+
+static int msm_comm_session_init(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ int fourcc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ if (inst->session_type == MSM_VIDC_DECODER) {
+ fourcc = inst->fmts[OUTPUT_PORT]->fourcc;
+ } else if (inst->session_type == MSM_VIDC_ENCODER) {
+ fourcc = inst->fmts[CAPTURE_PORT]->fourcc;
+ } else {
+ pr_err("Invalid session\n");
+ return -EINVAL;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_INIT_DONE)]);
+ inst->session = vidc_hal_session_init(inst->core->device, (u32) inst,
+ get_hal_domain(inst->session_type),
+ get_hal_codec_type(fourcc));
+ if (!inst->session) {
+ pr_err("Failed to call session init for: %d, %d, %d, %d\n",
+ (int)inst->core->device, (int)inst,
+ inst->session_type, fourcc);
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+ return rc;
+}
+
+static int msm_vidc_load_resources(int flipped_state,
+ struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ rc = vidc_hal_session_load_res((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_LOAD_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_START_DONE)]);
+ rc = vidc_hal_session_start((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_START);
+exit:
+ return rc;
+}
+
+static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send Stop to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_STOP_DONE)]);
+ rc = vidc_hal_session_stop((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send stop\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_STOP);
+exit:
+ return rc;
+}
+
+static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send release res to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_RELEASE_RESOURCE_DONE)]);
+ rc = vidc_hal_session_release_res((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_RELEASE_RESOURCES);
+exit:
+ return rc;
+}
+
+static int msm_comm_session_close(int flipped_state, struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) {
+ pr_err("inst: %p is already in state: %d\n", inst, inst->state);
+ goto exit;
+ }
+ pr_debug("Send session close to hal\n");
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_END_DONE)]);
+ rc = vidc_hal_session_end((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to send load resources\n");
+ goto exit;
+ }
+ change_inst_state(inst, MSM_VIDC_OPEN);
+exit:
+ return rc;
+}
+
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state)
+{
+ int rc = 0;
+ int flipped_state;
+ if (!inst) {
+ pr_err("Invalid instance pointer = %p\n", inst);
+ return -EINVAL;
+ }
+ pr_debug("Trying to move inst: %p from: 0x%x to 0x%x\n",
+ inst, inst->state, state);
+ mutex_lock(&inst->sync_lock);
+ flipped_state = inst->state;
+ if (flipped_state < MSM_VIDC_STOP
+ && state > MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP + (MSM_VIDC_STOP - flipped_state);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ } else if (flipped_state > MSM_VIDC_STOP
+ && state < MSM_VIDC_STOP) {
+ flipped_state = MSM_VIDC_STOP -
+ (flipped_state - MSM_VIDC_STOP + 1);
+ flipped_state &= 0xFFFE;
+ flipped_state = flipped_state - 1;
+ }
+ pr_debug("flipped_state = 0x%x\n", flipped_state);
+ switch (flipped_state) {
+ case MSM_VIDC_CORE_UNINIT_DONE:
+ case MSM_VIDC_CORE_INIT:
+ rc = msm_comm_init_core(inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CORE_INIT_DONE:
+ rc = msm_comm_init_core_done(inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_OPEN:
+ rc = msm_comm_session_init(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_OPEN_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE,
+ SESSION_INIT_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_LOAD_RESOURCES:
+ rc = msm_vidc_load_resources(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_LOAD_RESOURCES_DONE:
+ case MSM_VIDC_START:
+ rc = msm_vidc_start(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_START_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_START_DONE,
+ SESSION_START_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_STOP:
+ rc = msm_vidc_stop(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_STOP_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_STOP_DONE,
+ SESSION_STOP_DONE);
+ if (rc || state <= inst->state)
+ break;
+ pr_debug("Moving to Stop Done state\n");
+ case MSM_VIDC_RELEASE_RESOURCES:
+ rc = msm_vidc_release_res(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_RELEASE_RESOURCES_DONE:
+ rc = wait_for_state(inst, flipped_state,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ SESSION_RELEASE_RESOURCE_DONE);
+ if (rc || state <= inst->state)
+ break;
+ pr_debug("Moving to release resources done state\n");
+ case MSM_VIDC_CLOSE:
+ rc = msm_comm_session_close(flipped_state, inst);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CLOSE_DONE:
+ rc = wait_for_state(inst, flipped_state, MSM_VIDC_CLOSE_DONE,
+ SESSION_END_DONE);
+ if (rc || state <= inst->state)
+ break;
+ case MSM_VIDC_CORE_UNINIT:
+ pr_debug("***************Sending core uninit\n");
+ rc = msm_vidc_deinit_core(inst);
+ if (rc || state == inst->state)
+ break;
+ default:
+ pr_err("State not recognized\n");
+ rc = -EINVAL;
+ break;
+ }
+ mutex_unlock(&inst->sync_lock);
+ if (rc)
+ pr_err("Failed to move from state: %d to %d\n",
+ inst->state, state);
+ return rc;
+}
+
+int msm_comm_qbuf(struct vb2_buffer *vb)
+{
+ int rc = 0;
+ struct vb2_queue *q;
+ struct msm_vidc_inst *inst;
+ unsigned long flags;
+ struct vb2_buf_entry *entry;
+ struct vidc_frame_data frame_data;
+ q = vb->vb2_queue;
+ inst = q->drv_priv;
+
+ if (!inst || !vb) {
+ pr_err("Invalid input: %p, %p\n", inst, vb);
+ return -EINVAL;
+ }
+ if (inst->state != MSM_VIDC_START_DONE) {
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry) {
+ pr_err("Out of memory\n");
+ goto err_no_mem;
+ }
+ entry->vb = vb;
+ pr_debug("Queueing buffer in pendingq\n");
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&entry->list, &inst->pendingq);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ } else {
+ memset(&frame_data, 0 , sizeof(struct vidc_frame_data));
+ frame_data.alloc_len = vb->v4l2_planes[0].length;
+ frame_data.filled_len = vb->v4l2_planes[0].bytesused;
+ frame_data.device_addr = vb->v4l2_planes[0].m.userptr;
+ frame_data.clnt_data = (u32)vb;
+ if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ frame_data.buffer_type = HAL_BUFFER_INPUT;
+ if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_EOS) {
+ frame_data.flags = HAL_BUFFERFLAG_EOS;
+ pr_debug("Received EOS on output capability\n");
+ }
+ pr_debug("Sending etb to hal: Alloc: %d :filled: %d\n",
+ frame_data.alloc_len, frame_data.filled_len);
+ rc = vidc_hal_session_etb((void *) inst->session,
+ &frame_data);
+ pr_debug("Sent etb to HAL\n");
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ struct extradata_buf *addr;
+ struct list_head *ptr, *next;
+ frame_data.filled_len = 0;
+ frame_data.buffer_type = HAL_BUFFER_OUTPUT;
+ frame_data.extradata_addr = 0;
+ list_for_each_safe(ptr, next, &inst->extradatabufs) {
+ addr = list_entry(ptr,
+ struct extradata_buf, list);
+ if (addr->device_addr ==
+ frame_data.device_addr) {
+ frame_data.extradata_addr =
+ addr->handle->device_addr;
+ break;
+ }
+ }
+ pr_debug("Sending ftb to hal...: Alloc: %d :filled: %d"
+ " extradata_addr: %d\n", frame_data.alloc_len,
+ frame_data.filled_len,
+ frame_data.extradata_addr);
+ rc = vidc_hal_session_ftb((void *) inst->session,
+ &frame_data);
+ } else {
+ pr_err("This capability is not supported: %d\n",
+ q->type);
+ rc = -EINVAL;
+ }
+ }
+ if (rc)
+ pr_err("Failed to queue buffer\n");
+err_no_mem:
+ return rc;
+}
+
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ mutex_lock(&inst->sync_lock);
+ init_completion(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)]);
+ rc = vidc_hal_session_get_buf_req((void *) inst->session);
+ if (rc) {
+ pr_err("Failed to get property\n");
+ goto exit;
+ }
+ rc = wait_for_completion_timeout(
+ &inst->completions[SESSION_MSG_INDEX(SESSION_PROPERTY_INFO)],
+ msecs_to_jiffies(HW_RESPONSE_TIMEOUT));
+ if (!rc) {
+ pr_err("Wait interrupted or timeout: %d\n", rc);
+ rc = -EIO;
+ goto exit;
+ }
+ rc = 0;
+exit:
+ mutex_unlock(&inst->sync_lock);
+ return rc;
+}
+
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+ struct extradata_buf *binfo)
+{
+ int rc = 0;
+ unsigned long flags;
+ struct msm_smem *handle;
+ pr_debug("Extradata: num = %d, size = %d, align = %d\n",
+ inst->buff_req.buffer[4].buffer_count_actual,
+ inst->buff_req.buffer[4].buffer_size,
+ inst->buff_req.buffer[4].buffer_alignment);
+ if (!inst->buff_req.buffer[4].buffer_size) {
+ pr_err("invalid size: %d",
+ inst->buff_req.buffer[4].buffer_size);
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ handle = msm_smem_alloc(inst->mem_client,
+ inst->buff_req.buffer[4].buffer_size,
+ inst->buff_req.buffer[4].buffer_alignment, 0);
+ if (!handle) {
+ pr_err("Failed to allocate Extradata memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo->handle = handle;
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->extradatabufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+err_no_mem:
+ return rc;
+}
+
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst)
+{
+ int rc = 0;
+ struct msm_smem *handle;
+ struct internal_buf *binfo;
+ struct vidc_buffer_addr_info buffer_info;
+ unsigned long flags;
+ int i;
+ pr_debug("scratch: num = %d, size = %d\n",
+ inst->buff_req.buffer[6].buffer_count_actual,
+ inst->buff_req.buffer[6].buffer_size);
+ for (i = 0; i < inst->buff_req.buffer[6].buffer_count_actual;
+ i++) {
+ handle = msm_smem_alloc(inst->mem_client,
+ inst->buff_req.buffer[6].buffer_size, 1, 0);
+ if (!handle) {
+ pr_err("Failed to allocate scratch memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
+ if (!binfo) {
+ pr_err("Out of memory\n");
+ rc = -ENOMEM;
+ goto err_no_mem;
+ }
+ binfo->handle = handle;
+ spin_lock_irqsave(&inst->lock, flags);
+ list_add_tail(&binfo->list, &inst->internalbufs);
+ spin_unlock_irqrestore(&inst->lock, flags);
+ buffer_info.buffer_size =
+ inst->buff_req.buffer[6].buffer_size;
+ buffer_info.buffer_type = HAL_BUFFER_INTERNAL_SCRATCH;
+ buffer_info.num_buffers = 1;
+ buffer_info.align_device_addr = handle->device_addr;
+ rc = vidc_hal_session_set_buffers((void *) inst->session,
+ &buffer_info);
+ if (rc) {
+ pr_err("vidc_hal_session_set_buffers failed");
+ break;
+ }
+ }
+err_no_mem:
+ return rc;
+}
diff --git a/drivers/media/video/msm_vidc/msm_vidc_common.h b/drivers/media/video/msm_vidc/msm_vidc_common.h
new file mode 100644
index 0000000..45bfa7b
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_common.h
@@ -0,0 +1,38 @@
+/* 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_VIDC_COMMON_H_
+#define _MSM_VIDC_COMMON_H_
+#include "msm_vidc_internal.h"
+struct vb2_buf_entry {
+ struct list_head list;
+ struct vb2_buffer *vb;
+};
+struct msm_vidc_core *get_vidc_core(int core_id);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_index(
+ const struct msm_vidc_format fmt[], int size, int index, int fmt_type);
+const struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc(
+ const struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type);
+struct vb2_queue *msm_comm_get_vb2q(
+ struct msm_vidc_inst *inst, enum v4l2_buf_type type);
+int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
+int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
+int msm_comm_allocate_extradata_buffers(struct msm_vidc_inst *inst,
+ struct extradata_buf *binfo);
+int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
+int msm_comm_qbuf(struct vb2_buffer *vb);
+#define IS_PRIV_CTRL(idx) (\
+ (V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \
+ V4L2_CTRL_DRIVER_PRIV(idx))
+
+#endif
diff --git a/drivers/media/video/msm_vidc/msm_vidc_internal.h b/drivers/media/video/msm_vidc/msm_vidc_internal.h
new file mode 100644
index 0000000..dce2dee
--- /dev/null
+++ b/drivers/media/video/msm_vidc/msm_vidc_internal.h
@@ -0,0 +1,166 @@
+/* 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_VIDC_INTERNAL_H_
+#define _MSM_VIDC_INTERNAL_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/videobuf2-core.h>
+#include <media/msm_vidc.h>
+
+#include "vidc_hal_api.h"
+
+#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
+#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1);
+#define MAX_DEBUGFS_NAME 50
+#define DEFAULT_TIMEOUT 3
+
+#define SYS_MSG_START VIDC_EVENT_CHANGE
+#define SYS_MSG_END SYS_DEBUG
+#define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE
+#define SESSION_MSG_END SESSION_PROPERTY_INFO
+#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
+#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
+
+enum vidc_ports {
+ OUTPUT_PORT,
+ CAPTURE_PORT,
+ MAX_PORT_NUM
+};
+
+enum vidc_core_state {
+ VIDC_CORE_UNINIT = 0,
+ VIDC_CORE_INIT,
+ VIDC_CORE_INIT_DONE,
+};
+
+/*Donot change the enum values unless
+ * you know what you are doing*/
+enum instance_state {
+ MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
+ MSM_VIDC_CORE_INIT,
+ MSM_VIDC_CORE_INIT_DONE,
+ MSM_VIDC_OPEN,
+ MSM_VIDC_OPEN_DONE,
+ MSM_VIDC_LOAD_RESOURCES,
+ MSM_VIDC_LOAD_RESOURCES_DONE,
+ MSM_VIDC_START,
+ MSM_VIDC_START_DONE,
+ MSM_VIDC_STOP,
+ MSM_VIDC_STOP_DONE,
+ MSM_VIDC_RELEASE_RESOURCES,
+ MSM_VIDC_RELEASE_RESOURCES_DONE,
+ MSM_VIDC_CLOSE,
+ MSM_VIDC_CLOSE_DONE,
+ MSM_VIDC_CORE_UNINIT,
+};
+
+struct buf_info {
+ struct list_head list;
+ struct vb2_buffer *buf;
+};
+
+struct internal_buf {
+ struct list_head list;
+ struct msm_smem *handle;
+};
+
+struct extradata_buf {
+ struct list_head list;
+ struct msm_smem *handle;
+ u32 device_addr;
+};
+
+struct msm_vidc_format {
+ char name[64];
+ u8 description[32];
+ u32 fourcc;
+ int num_planes;
+ int type;
+ u32 (*get_frame_size)(int plane, u32 height, u32 width);
+};
+
+struct msm_vidc_drv {
+ spinlock_t lock;
+ struct list_head cores;
+ int num_cores;
+ struct dentry *debugfs_root;
+};
+
+struct msm_video_device {
+ int type;
+ struct video_device vdev;
+};
+
+struct msm_vidc_core {
+ struct list_head list;
+ struct mutex sync_lock;
+ int id;
+ void *device;
+ struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
+ struct v4l2_device v4l2_dev;
+ spinlock_t lock;
+ struct list_head instances;
+ struct dentry *debugfs_root;
+ u32 base_addr;
+ u32 register_base;
+ u32 register_size;
+ u32 irq;
+ enum vidc_core_state state;
+ struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
+};
+
+struct msm_vidc_inst {
+ struct list_head list;
+ struct mutex sync_lock;
+ struct msm_vidc_core *core;
+ int session_type;
+ void *session;
+ u32 width;
+ u32 height;
+ int state;
+ const struct msm_vidc_format *fmts[MAX_PORT_NUM];
+ struct vb2_queue vb2_bufq[MAX_PORT_NUM];
+ spinlock_t lock;
+ struct list_head pendingq;
+ struct list_head internalbufs;
+ struct list_head extradatabufs;
+ struct buffer_requirements buff_req;
+ void *mem_client;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
+};
+
+extern struct msm_vidc_drv *vidc_driver;
+
+struct msm_vidc_ctrl {
+ u32 id;
+ char name[64];
+ enum v4l2_ctrl_type type;
+ s32 minimum;
+ s32 maximum;
+ s32 default_value;
+ u32 step;
+ u32 menu_skip_mask;
+ const char * const *qmenu;
+};
+
+void handle_cmd_response(enum command_response cmd, void *data);
+#endif
diff --git a/drivers/media/video/vcap_v4l2.c b/drivers/media/video/vcap_v4l2.c
index 670d0f8..219f7a0 100644
--- a/drivers/media/video/vcap_v4l2.c
+++ b/drivers/media/video/vcap_v4l2.c
@@ -537,9 +537,9 @@
.release = video_device_release,
};
-int vcap_reg_powerup(struct vcap_dev *dev)
+int vcap_reg_powerup(struct vcap_dev *dev, struct device *ddev)
{
- dev->fs_vcap = regulator_get(NULL, "fs_vcap");
+ dev->fs_vcap = regulator_get(ddev, "vdd");
if (IS_ERR(dev->fs_vcap)) {
pr_err("%s: Regulator FS_VCAP get failed %ld\n", __func__,
PTR_ERR(dev->fs_vcap));
@@ -715,7 +715,7 @@
{
int rc;
- rc = vcap_reg_powerup(dev);
+ rc = vcap_reg_powerup(dev, ddev);
if (rc < 0)
goto reg_failed;
rc = vcap_clk_powerup(dev, ddev);
diff --git a/drivers/mfd/pm8xxx-misc.c b/drivers/mfd/pm8xxx-misc.c
index a311029..080a87c 100644
--- a/drivers/mfd/pm8xxx-misc.c
+++ b/drivers/mfd/pm8xxx-misc.c
@@ -145,6 +145,11 @@
#define MP3_1_SHIFT 5
#define MP3_2_SHIFT 2
+#define REG_HSED_BIAS0_CNTL2 0xA1
+#define REG_HSED_BIAS1_CNTL2 0x135
+#define REG_HSED_BIAS2_CNTL2 0x138
+#define HSED_EN_MASK 0xC0
+
struct pm8xxx_misc_chip {
struct list_head link;
struct pm8xxx_misc_platform_data pdata;
@@ -1100,6 +1105,52 @@
}
EXPORT_SYMBOL_GPL(pm8xxx_aux_clk_control);
+int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable)
+{
+ struct pm8xxx_misc_chip *chip;
+ unsigned long flags;
+ int rc = 0;
+ u16 addr;
+
+ switch (bias) {
+ case PM8XXX_HSED_BIAS0:
+ addr = REG_HSED_BIAS0_CNTL2;
+ break;
+ case PM8XXX_HSED_BIAS1:
+ addr = REG_HSED_BIAS1_CNTL2;
+ break;
+ case PM8XXX_HSED_BIAS2:
+ addr = REG_HSED_BIAS2_CNTL2;
+ break;
+ default:
+ pr_err("Invalid BIAS line\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&pm8xxx_misc_chips_lock, flags);
+
+ /* Loop over all attached PMICs and call specific functions for them. */
+ list_for_each_entry(chip, &pm8xxx_misc_chips, link) {
+ switch (chip->version) {
+ case PM8XXX_VERSION_8058:
+ case PM8XXX_VERSION_8921:
+ rc = pm8xxx_misc_masked_write(chip, addr,
+ HSED_EN_MASK, enable ? HSED_EN_MASK : 0);
+ if (rc < 0)
+ pr_err("Enable HSED BIAS failed rc=%d\n", rc);
+ break;
+ default:
+ /* Functionality not supported */
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&pm8xxx_misc_chips_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL(pm8xxx_hsed_bias_control);
+
static int __devinit pm8xxx_misc_probe(struct platform_device *pdev)
{
const struct pm8xxx_misc_platform_data *pdata = pdev->dev.platform_data;
diff --git a/drivers/misc/tsif.c b/drivers/misc/tsif.c
index 42faa07..ace5b0c 100644
--- a/drivers/misc/tsif.c
+++ b/drivers/misc/tsif.c
@@ -1,7 +1,7 @@
/*
* TSIF Driver
*
- * 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
@@ -680,7 +680,7 @@
tsif_device->state = tsif_state_flushing;
while (tsif_device->xfer[0].busy ||
tsif_device->xfer[1].busy) {
- msm_dmov_flush(tsif_device->dma);
+ msm_dmov_flush(tsif_device->dma, 1);
msleep(10);
}
}
@@ -760,7 +760,7 @@
offsetof(struct tsif_dmov_cmd, box_ptr));
hdr->complete_func = tsif_dmov_complete_func;
}
- msm_dmov_flush(tsif_device->dma);
+ msm_dmov_flush(tsif_device->dma, 1);
return 0;
err:
dev_err(&tsif_device->pdev->dev, "Failed to allocate DMA buffers\n");
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 92990b9..f9999c5 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -29,6 +29,18 @@
#define SDIO_DEVICE_ID_MSM_WCN1314 0x2881
#endif
+#ifndef SDIO_VENDOR_ID_MSM_QCA
+#define SDIO_VENDOR_ID_MSM_QCA 0x271
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6003_1
+#define SDIO_DEVICE_ID_MSM_QCA_AR6003_1 0x300
+#endif
+
+#ifndef SDIO_DEVICE_ID_MSM_QCA_AR6003_2
+#define SDIO_DEVICE_ID_MSM_QCA_AR6003_2 0x301
+#endif
+
/*
* This hook just adds a quirk for all sdio devices
*/
@@ -51,6 +63,12 @@
SDIO_FIXUP(SDIO_VENDOR_ID_MSM, SDIO_DEVICE_ID_MSM_WCN1314,
remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_1,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 39e6ce3..13fe3e6 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -707,7 +707,7 @@
}
if (!err && host->sdio_irqs)
- mmc_signal_sdio_irq(host);
+ wake_up_process(host->sdio_irq_thread);
mmc_release_host(host);
/*
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 28505636..c442907 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -27,10 +27,23 @@
#include "sdio_ops.h"
-static int process_sdio_pending_irqs(struct mmc_card *card)
+static int process_sdio_pending_irqs(struct mmc_host *host)
{
+ struct mmc_card *card = host->card;
int i, ret, count;
unsigned char pending;
+ struct sdio_func *func;
+
+ /*
+ * Optimization, if there is only 1 function interrupt registered
+ * and we know an IRQ was signaled then call irq handler directly.
+ * Otherwise do the full probe.
+ */
+ func = card->sdio_single_irq;
+ if (func && host->sdio_irq_pending) {
+ func->irq_handler(func);
+ return 1;
+ }
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
if (ret) {
@@ -42,7 +55,7 @@
count = 0;
for (i = 1; i <= 7; i++) {
if (pending & (1 << i)) {
- struct sdio_func *func = card->sdio_func[i - 1];
+ func = card->sdio_func[i - 1];
if (!func) {
printk(KERN_WARNING "%s: pending IRQ for "
"non-existent function\n",
@@ -104,7 +117,8 @@
ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
if (ret)
break;
- ret = process_sdio_pending_irqs(host->card);
+ ret = process_sdio_pending_irqs(host);
+ host->sdio_irq_pending = false;
mmc_release_host(host);
/*
@@ -192,6 +206,24 @@
return 0;
}
+/* If there is only 1 function registered set sdio_single_irq */
+static void sdio_single_irq_set(struct mmc_card *card)
+{
+ struct sdio_func *func;
+ int i;
+
+ card->sdio_single_irq = NULL;
+ if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
+ card->host->sdio_irqs == 1)
+ for (i = 0; i < card->sdio_funcs; i++) {
+ func = card->sdio_func[i];
+ if (func && func->irq_handler) {
+ card->sdio_single_irq = func;
+ break;
+ }
+ }
+}
+
/**
* sdio_claim_irq - claim the IRQ for a SDIO function
* @func: SDIO function
@@ -233,6 +265,7 @@
ret = sdio_card_irq_get(func->card);
if (ret)
func->irq_handler = NULL;
+ sdio_single_irq_set(func->card);
return ret;
}
@@ -257,6 +290,7 @@
if (func->irq_handler) {
func->irq_handler = NULL;
sdio_card_irq_put(func->card);
+ sdio_single_irq_set(func->card);
}
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, ®);
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e458429..0d11dca 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -79,6 +79,9 @@
static int msmsdcc_dbg_init(void);
#endif
+static int msmsdcc_prep_xfer(struct msmsdcc_host *host, struct mmc_data
+ *data);
+
static u64 dma_mask = DMA_BIT_MASK(32);
static unsigned int msmsdcc_pwrsave = 1;
@@ -482,8 +485,9 @@
if (!mrq->data->error)
mrq->data->error = -EIO;
}
- dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
- host->dma.dir);
+ if (!mrq->data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
+ host->dma.num_ents, host->dma.dir);
if (host->curr.user_pages) {
struct scatterlist *sg = host->dma.sg;
@@ -649,9 +653,9 @@
}
/* Unmap sg buffers */
- dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
- host->sps.dir);
-
+ if (!mrq->data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+ host->sps.num_ents, host->sps.dir);
host->sps.sg = NULL;
host->sps.busy = 0;
@@ -720,8 +724,9 @@
mrq->data->error = -EIO;
/* Unmap sg buffers */
- dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
- host->sps.dir);
+ if (!mrq->data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+ host->sps.num_ents, host->sps.dir);
host->sps.sg = NULL;
host->sps.busy = 0;
@@ -816,15 +821,13 @@
else
host->dma.dir = DMA_TO_DEVICE;
- n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
- host->dma.num_ents, host->dma.dir);
-
- if (n != host->dma.num_ents) {
- pr_err("%s: Unable to map in all sg elements\n",
- mmc_hostname(host->mmc));
- host->dma.sg = NULL;
- host->dma.num_ents = 0;
- return -ENOMEM;
+ if (!data->host_cookie) {
+ n = msmsdcc_prep_xfer(host, data);
+ if (unlikely(n < 0)) {
+ host->dma.sg = NULL;
+ host->dma.num_ents = 0;
+ return -ENOMEM;
+ }
}
/* host->curr.user_pages = (data->flags & MMC_DATA_USERPAGE); */
@@ -893,8 +896,9 @@
unmap:
if (err) {
- dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
- host->dma.num_ents, host->dma.dir);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg,
+ host->dma.num_ents, host->dma.dir);
pr_err("%s: cannot do DMA, fall back to PIO mode err=%d\n",
mmc_hostname(host->mmc), err);
}
@@ -902,6 +906,44 @@
return err;
}
+static int msmsdcc_prep_xfer(struct msmsdcc_host *host,
+ struct mmc_data *data)
+{
+ int rc = 0;
+ unsigned int dir;
+
+ /* Prevent memory corruption */
+ BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
+
+ if (data->flags & MMC_DATA_READ)
+ dir = DMA_FROM_DEVICE;
+ else
+ dir = DMA_TO_DEVICE;
+
+ /* Make sg buffers DMA ready */
+ rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ dir);
+
+ if (unlikely(rc != data->sg_len)) {
+ pr_err("%s: Unable to map in all sg elements, rc=%d\n",
+ mmc_hostname(host->mmc), rc);
+ rc = -ENOMEM;
+ goto dma_map_err;
+ }
+
+ pr_debug("%s: %s: %s: sg_len=%d\n",
+ mmc_hostname(host->mmc), __func__,
+ dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
+ data->sg_len);
+
+ goto out;
+
+dma_map_err:
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ data->flags);
+out:
+ return rc;
+}
#ifdef CONFIG_MMC_MSM_SPS_SUPPORT
/**
* Submits data transfer request to SPS driver
@@ -916,7 +958,7 @@
* @return 0 if success else negative value
*/
static int msmsdcc_sps_start_xfer(struct msmsdcc_host *host,
- struct mmc_data *data)
+ struct mmc_data *data)
{
int rc = 0;
u32 flags;
@@ -925,9 +967,6 @@
struct scatterlist *sg = data->sg;
struct sps_pipe *sps_pipe_handle;
- /* Prevent memory corruption */
- BUG_ON(data->sg_len > msmsdcc_get_nr_sg(host));
-
host->sps.sg = data->sg;
host->sps.num_ents = data->sg_len;
host->sps.xfer_req_cnt = 0;
@@ -939,24 +978,15 @@
sps_pipe_handle = host->sps.cons.pipe_handle;
}
- /* Make sg buffers DMA ready */
- rc = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- host->sps.dir);
-
- if (rc != data->sg_len) {
- pr_err("%s: Unable to map in all sg elements, rc=%d\n",
- mmc_hostname(host->mmc), rc);
- host->sps.sg = NULL;
- host->sps.num_ents = 0;
- rc = -ENOMEM;
- goto dma_map_err;
+ if (!data->host_cookie) {
+ rc = msmsdcc_prep_xfer(host, data);
+ if (unlikely(rc < 0)) {
+ host->dma.sg = NULL;
+ host->dma.num_ents = 0;
+ goto out;
+ }
}
- pr_debug("%s: %s: %s: pipe=0x%x, total_xfer=0x%x, sg_len=%d\n",
- mmc_hostname(host->mmc), __func__,
- host->sps.dir == DMA_FROM_DEVICE ? "READ" : "WRITE",
- (u32)sps_pipe_handle, host->curr.xfer_size, data->sg_len);
-
for (i = 0; i < data->sg_len; i++) {
/*
* Check if this is the last buffer to transfer?
@@ -993,8 +1023,9 @@
dma_map_err:
/* unmap sg buffers */
- dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg, host->sps.num_ents,
- host->sps.dir);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), host->sps.sg,
+ host->sps.num_ents, host->sps.dir);
out:
return rc;
}
@@ -1021,11 +1052,8 @@
if (/*interrupt*/0)
*c |= MCI_CPSM_INTERRUPT;
- if (cmd->opcode == MMC_READ_SINGLE_BLOCK ||
- cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
- cmd->opcode == MMC_WRITE_BLOCK ||
- cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
- cmd->opcode == SD_IO_RW_EXTENDED)
+ /* DAT_CMD bit should be set for all ADTC */
+ if (mmc_cmd_type(cmd) == MMC_CMD_ADTC)
*c |= MCI_CSPM_DATCMD;
/* Check if AUTO CMD19 is required or not? */
@@ -1584,8 +1612,7 @@
if (!cmd->data || cmd->error) {
if (host->curr.data && host->dma.sg &&
host->is_dma_mode)
- msm_dmov_stop_cmd(host->dma.channel,
- &host->dma.hdr, 0);
+ msm_dmov_flush(host->dma.channel, 0);
else if (host->curr.data && host->sps.sg &&
host->is_sps_mode){
/* Stop current SPS transfer */
@@ -1738,8 +1765,7 @@
msmsdcc_data_err(host, data, status);
host->curr.data_xfered = 0;
if (host->dma.sg && host->is_dma_mode)
- msm_dmov_stop_cmd(host->dma.channel,
- &host->dma.hdr, 0);
+ msm_dmov_flush(host->dma.channel, 0);
else if (host->sps.sg && host->is_sps_mode) {
/* Stop current SPS transfer */
msmsdcc_sps_exit_curr_xfer(host);
@@ -1836,6 +1862,63 @@
}
static void
+msmsdcc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ bool is_first_request)
+{
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+ int rc = 0;
+
+ if (unlikely(!data)) {
+ pr_err("%s: %s cannot prepare null data\n", mmc_hostname(mmc),
+ __func__);
+ return;
+ }
+ if (unlikely(data->host_cookie)) {
+ /* Very wrong */
+ data->host_cookie = 0;
+ pr_err("%s: %s Request reposted for prepare\n",
+ mmc_hostname(mmc), __func__);
+ return;
+ }
+
+ if (!msmsdcc_is_dma_possible(host, data))
+ return;
+
+ rc = msmsdcc_prep_xfer(host, data);
+ if (unlikely(rc < 0)) {
+ data->host_cookie = 0;
+ return;
+ }
+
+ data->host_cookie = 1;
+}
+
+static void
+msmsdcc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int err)
+{
+ struct msmsdcc_host *host = mmc_priv(mmc);
+ unsigned int dir;
+ struct mmc_data *data = mrq->data;
+
+ if (unlikely(!data)) {
+ pr_err("%s: %s cannot cleanup null data\n", mmc_hostname(mmc),
+ __func__);
+ return;
+ }
+ if (data->flags & MMC_DATA_READ)
+ dir = DMA_FROM_DEVICE;
+ else
+ dir = DMA_TO_DEVICE;
+
+ if (data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, dir);
+
+ data->host_cookie = 0;
+}
+
+static void
msmsdcc_request_start(struct msmsdcc_host *host, struct mmc_request *mrq)
{
if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
@@ -1853,7 +1936,7 @@
msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct msmsdcc_host *host = mmc_priv(mmc);
- unsigned long flags;
+ unsigned long flags, timeout;
/*
* Get the SDIO AL client out of LPM.
@@ -1907,11 +1990,18 @@
mrq->cmd->opcode, host->curr.mrq->cmd->opcode);
/*
- * Kick the software command timeout timer here.
- * Timer expires in 10 secs.
+ * Set timeout value to 10 secs (or more in case of buggy cards)
+ */
+ if ((mmc->card) && (mmc->card->quirks & MMC_QUIRK_INAND_DATA_TIMEOUT))
+ timeout = 20000;
+ else
+ timeout = MSM_MMC_REQ_TIMEOUT;
+ /*
+ * Kick the software request timeout timer here with the timeout
+ * value identified above
*/
mod_timer(&host->req_tout_timer,
- (jiffies + msecs_to_jiffies(MSM_MMC_REQ_TIMEOUT)));
+ (jiffies + msecs_to_jiffies(timeout)));
host->curr.mrq = mrq;
if (mrq->data && (mrq->data->flags & MMC_DATA_WRITE)) {
@@ -3557,6 +3647,8 @@
static const struct mmc_host_ops msmsdcc_ops = {
.enable = msmsdcc_enable,
.disable = msmsdcc_disable,
+ .pre_req = msmsdcc_pre_req,
+ .post_req = msmsdcc_post_req,
.request = msmsdcc_request,
.set_ios = msmsdcc_set_ios,
.get_ro = msmsdcc_get_ro,
@@ -4246,8 +4338,7 @@
mrq->data->error = -ETIMEDOUT;
host->curr.data_xfered = 0;
if (host->dma.sg && host->is_dma_mode) {
- msm_dmov_stop_cmd(host->dma.channel,
- &host->dma.hdr, 0);
+ msm_dmov_flush(host->dma.channel, 0);
} else if (host->sps.sg && host->is_sps_mode) {
/* Stop current SPS transfer */
msmsdcc_sps_exit_curr_xfer(host);
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 718ef43..e6bd16c 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -212,10 +212,7 @@
#define MSM_MMC_IDLE_TIMEOUT 5000 /* msecs */
-/*
- * Set the request timeout to 10secs to allow
- * bad cards/controller to respond.
- */
+/* Set the request timeout to 10secs */
#define MSM_MMC_REQ_TIMEOUT 10000 /* msecs */
#define MSM_MMC_DISABLE_TIMEOUT 200 /* msecs */
diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c
index 0bf972a..31dabd5 100644
--- a/drivers/net/ks8851.c
+++ b/drivers/net/ks8851.c
@@ -622,10 +622,8 @@
netif_dbg(ks, intr, ks->netdev,
"%s: status 0x%04x\n", __func__, status);
- if (status & IRQ_LCI) {
- /* should do something about checking link status */
+ if (status & IRQ_LCI)
handled |= IRQ_LCI;
- }
if (status & IRQ_LDI) {
u16 pmecr = ks8851_rdreg16(ks, KS_PMECR);
@@ -688,6 +686,9 @@
mutex_unlock(&ks->lock);
+ if (status & IRQ_LCI)
+ mii_check_link(&ks->mii);
+
if (status & IRQ_TXI)
netif_wake_queue(ks->netdev);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index b83e871..bb16fbb 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -283,13 +283,15 @@
---help---
A driver for Qualcomm WLAN SDIO Libra chipset.
-config ATH6K_LEGACY
- tristate "QCA AR6003 wlan SDIO driver"
+config ATH6K_LEGACY_EXT
+ tristate "QCA AR6003 wlan SDIO driver - External"
depends on MMC_MSM && WLAN
select WIRELESS_EXT
select WEXT_PRIV
---help---
- This module adds support for wireless adapters based on QCA AR6003 chipset running over SDIO.
+ This module adds support for wireless adapters based on QCA AR6003 chipset
+ running over SDIO. Driver is built outside of kernel tree, this config
+ only enables configurations required for QCA AR6003 wlan driver.
config WCNSS_CORE
tristate "Qualcomm WCNSS CORE driver"
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 9059603..3007662 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -21,8 +21,9 @@
#include <linux/slab.h>
/**
- * of_get_gpio_flags - Get a GPIO number and flags to use with GPIO API
+ * of_get_named_gpio_flags() - Get a GPIO number and flags to use with GPIO API
* @np: device node to get GPIO from
+ * @propname: property name containing gpio specifier(s)
* @index: index of the GPIO
* @flags: a flags pointer to fill in
*
@@ -30,8 +31,8 @@
* value on the error condition. If @flags is not NULL the function also fills
* in flags for the GPIO.
*/
-int of_get_gpio_flags(struct device_node *np, int index,
- enum of_gpio_flags *flags)
+int of_get_named_gpio_flags(struct device_node *np, const char *propname,
+ int index, enum of_gpio_flags *flags)
{
int ret;
struct device_node *gpio_np;
@@ -40,7 +41,7 @@
const void *gpio_spec;
const __be32 *gpio_cells;
- ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
+ ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
&gpio_np, &gpio_spec);
if (ret) {
pr_debug("%s: can't parse gpios property\n", __func__);
@@ -79,7 +80,7 @@
pr_debug("%s exited with status %d\n", __func__, ret);
return ret;
}
-EXPORT_SYMBOL(of_get_gpio_flags);
+EXPORT_SYMBOL(of_get_named_gpio_flags);
/**
* of_gpio_count - Count GPIOs for a device
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index f2981bf..d7edb82 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.c
@@ -20,7 +20,6 @@
#include "bam.h"
#include "sps_bam.h"
-#include "spsi.h"
/**
* Valid BAM Hardware version.
@@ -823,9 +822,46 @@
}
/**
+ * Output BAM register content
+ * including the TEST_BUS register content under
+ * different TEST_BUS_SEL values.
+ */
+static void bam_output_register_content(void *base)
+{
+ u32 num_pipes;
+ u32 test_bus_selection[] = {0x1, 0x2, 0x3, 0x4, 0xD, 0x10,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
+ u32 i;
+ u32 size = sizeof(test_bus_selection) / sizeof(u32);
+
+ for (i = 0; i < size; i++) {
+ bam_write_reg_field(base, TEST_BUS_SEL, BAM_TESTBUS_SEL,
+ test_bus_selection[i]);
+
+ SPS_INFO("sps:bam 0x%x(va);BAM_TEST_BUS_REG is"
+ "0x%x when BAM_TEST_BUS_SEL is 0x%x.",
+ (u32) base, bam_read_reg(base, TEST_BUS_REG),
+ bam_read_reg_field(base, TEST_BUS_SEL,
+ BAM_TESTBUS_SEL));
+ }
+
+ print_bam_reg(base);
+
+ num_pipes = bam_read_reg_field(base, NUM_PIPES,
+ BAM_NUM_PIPES);
+ SPS_INFO("sps:bam 0x%x(va) has %d pipes.",
+ (u32) base, num_pipes);
+
+ for (i = 0; i < num_pipes; i++)
+ print_bam_pipe_reg(base, i);
+
+}
+
+/**
* Get BAM IRQ source and clear global IRQ status
*/
-u32 bam_check_irq_source(void *base, u32 ee, u32 mask)
+u32 bam_check_irq_source(void *base, u32 ee, u32 mask,
+ enum sps_callback_case *cb_case)
{
u32 source = bam_read_reg(base, IRQ_SRCS_EE(ee));
u32 clr = source & (1UL << 31);
@@ -833,19 +869,27 @@
if (clr) {
u32 status = 0;
status = bam_read_reg(base, IRQ_STTS);
+
+ if (status & IRQ_STTS_BAM_ERROR_IRQ) {
+ SPS_ERR("sps:bam 0x%x(va);bam irq status="
+ "0x%x.\nsps: BAM_ERROR_IRQ\n",
+ (u32) base, status);
+ bam_output_register_content(base);
+ *cb_case = SPS_CALLBACK_BAM_ERROR_IRQ;
+ } else if (status & IRQ_STTS_BAM_HRESP_ERR_IRQ) {
+ SPS_ERR("sps:bam 0x%x(va);bam irq status="
+ "0x%x.\nsps: BAM_HRESP_ERR_IRQ\n",
+ (u32) base, status);
+ bam_output_register_content(base);
+ *cb_case = SPS_CALLBACK_BAM_HRESP_ERR_IRQ;
+ } else
+ SPS_INFO("sps:bam 0x%x(va);bam irq status="
+ "0x%x.", (u32) base, status);
+
bam_write_reg(base, IRQ_CLR, status);
- if (printk_ratelimit()) {
- if (status & IRQ_STTS_BAM_ERROR_IRQ)
- SPS_ERR("sps:bam 0x%x(va);bam irq status="
- "0x%x.\nsps: BAM_ERROR_IRQ\n",
- (u32) base, status);
- else
- SPS_INFO("sps:bam 0x%x(va);bam irq status="
- "0x%x.", (u32) base, status);
- }
}
- source &= mask;
+ source &= (mask|(1UL << 31));
return source;
}
diff --git a/drivers/platform/msm/sps/bam.h b/drivers/platform/msm/sps/bam.h
index 789769f..3521ffa 100644
--- a/drivers/platform/msm/sps/bam.h
+++ b/drivers/platform/msm/sps/bam.h
@@ -18,6 +18,7 @@
#include <linux/types.h> /* u32 */
#include <linux/io.h> /* ioread32() */
#include <linux/bitops.h> /* find_first_bit() */
+#include "spsi.h"
/* Pipe mode */
enum bam_pipe_mode {
@@ -166,10 +167,13 @@
*
* @mask - active pipes mask.
*
+ * @case - callback case.
+ *
* @return IRQ status
*
*/
-u32 bam_check_irq_source(void *base, u32 ee, u32 mask);
+u32 bam_check_irq_source(void *base, u32 ee, u32 mask,
+ enum sps_callback_case *cb_case);
/**
* Initialize a BAM pipe
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index 6c8b1f9..0abd739 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.c
@@ -136,13 +136,19 @@
/* Get BAM interrupt source(s) */
if ((dev->state & BAM_STATE_MTI) == 0) {
u32 mask = dev->pipe_active_mask;
- source = bam_check_irq_source(dev->base,
- dev->props.ee,
- mask);
+ enum sps_callback_case cb_case;
+ source = bam_check_irq_source(dev->base, dev->props.ee,
+ mask, &cb_case);
SPS_DBG1("sps:bam_isr:bam=0x%x;source=0x%x;mask=0x%x.",
BAM_ID(dev), source, mask);
+ if ((source & (1UL << 31)) && (dev->props.callback)) {
+ SPS_INFO("sps:bam_isr:bam=0x%x;callback for case %d.",
+ BAM_ID(dev), cb_case);
+ dev->props.callback(cb_case, dev->props.user);
+ }
+
/* Mask any non-local source */
source &= dev->pipe_active_mask;
} else {
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 053b81f..c040fac 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -19,6 +19,7 @@
#include <linux/usb/msm_hsusb.h>
#include <mach/usb_bam.h>
#include <mach/sps.h>
+#include <linux/workqueue.h>
#define USB_SUMMING_THRESHOLD 512
#define CONNECTIONS_NUM 4
@@ -29,11 +30,20 @@
static struct sps_mem_buffer data_mem_buf[CONNECTIONS_NUM][2];
static struct sps_mem_buffer desc_mem_buf[CONNECTIONS_NUM][2];
static struct platform_device *usb_bam_pdev;
+static struct workqueue_struct *usb_bam_wq;
+
+struct usb_bam_wake_event_info {
+ struct sps_register_event event;
+ int (*callback)(void *);
+ void *param;
+ struct work_struct wake_w;
+};
struct usb_bam_connect_info {
u8 idx;
u8 *src_pipe;
u8 *dst_pipe;
+ struct usb_bam_wake_event_info peer_event;
bool enabled;
};
@@ -48,7 +58,7 @@
u8 *usb_pipe_idx)
{
int ret;
- struct sps_pipe *pipe = sps_pipes[connection_idx][pipe_dir];
+ struct sps_pipe **pipe = &sps_pipes[connection_idx][pipe_dir];
struct sps_connect *connection =
&sps_connections[connection_idx][pipe_dir];
struct msm_usb_bam_platform_data *pdata =
@@ -58,13 +68,13 @@
(struct usb_bam_pipe_connect *)(pdata->connections +
bam_offset(pdata) + (2*connection_idx+pipe_dir));
- pipe = sps_alloc_endpoint();
- if (pipe == NULL) {
+ *pipe = sps_alloc_endpoint();
+ if (*pipe == NULL) {
pr_err("%s: sps_alloc_endpoint failed\n", __func__);
return -ENOMEM;
}
- ret = sps_get_config(pipe, connection);
+ ret = sps_get_config(*pipe, connection);
if (ret) {
pr_err("%s: tx get config failed %d\n", __func__, ret);
goto get_config_failed;
@@ -114,7 +124,7 @@
connection->desc = desc_mem_buf[connection_idx][pipe_dir];
connection->event_thresh = 512;
- ret = sps_connect(pipe, connection);
+ ret = sps_connect(*pipe, connection);
if (ret < 0) {
pr_err("%s: tx connect error %d\n", __func__, ret);
goto error;
@@ -122,10 +132,10 @@
return 0;
error:
- sps_disconnect(pipe);
+ sps_disconnect(*pipe);
fifo_setup_error:
get_config_failed:
- sps_free_endpoint(pipe);
+ sps_free_endpoint(*pipe);
return ret;
}
@@ -168,6 +178,58 @@
return 0;
}
+static void usb_bam_wake_work(struct work_struct *w)
+{
+ struct usb_bam_wake_event_info *wake_event_info =
+ container_of(w, struct usb_bam_wake_event_info, wake_w);
+
+ wake_event_info->callback(wake_event_info->param);
+}
+
+static void usb_bam_wake_cb(struct sps_event_notify *notify)
+{
+ struct usb_bam_wake_event_info *wake_event_info =
+ (struct usb_bam_wake_event_info *)notify->user;
+
+ queue_work(usb_bam_wq, &wake_event_info->wake_w);
+}
+
+int usb_bam_register_wake_cb(u8 idx,
+ int (*callback)(void *user), void* param)
+{
+ struct sps_pipe *pipe = sps_pipes[idx][PEER_PERIPHERAL_TO_USB];
+ struct sps_connect *sps_connection =
+ &sps_connections[idx][PEER_PERIPHERAL_TO_USB];
+ struct usb_bam_connect_info *connection = &usb_bam_connections[idx];
+ struct usb_bam_wake_event_info *wake_event_info =
+ &connection->peer_event;
+ int ret;
+
+ wake_event_info->param = param;
+ wake_event_info->callback = callback;
+ wake_event_info->event.mode = SPS_TRIGGER_CALLBACK;
+ wake_event_info->event.xfer_done = NULL;
+ wake_event_info->event.callback = callback ? usb_bam_wake_cb : NULL;
+ wake_event_info->event.user = wake_event_info;
+ wake_event_info->event.options = SPS_O_WAKEUP;
+ ret = sps_register_event(pipe, &wake_event_info->event);
+ if (ret) {
+ pr_err("%s: sps_register_event() failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ sps_connection->options = callback ?
+ (SPS_O_AUTO_ENABLE | SPS_O_WAKEUP | SPS_O_WAKEUP_IS_ONESHOT) :
+ SPS_O_AUTO_ENABLE;
+ ret = sps_set_config(pipe, sps_connection);
+ if (ret) {
+ pr_err("%s: sps_set_config() failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int usb_bam_init(void)
{
u32 h_usb;
@@ -275,8 +337,11 @@
dev_dbg(&pdev->dev, "usb_bam_probe\n");
- for (i = 0; i < CONNECTIONS_NUM; i++)
+ for (i = 0; i < CONNECTIONS_NUM; i++) {
usb_bam_connections[i].enabled = 0;
+ INIT_WORK(&usb_bam_connections[i].peer_event.wake_w,
+ usb_bam_wake_work);
+ }
if (!pdev->dev.platform_data) {
dev_err(&pdev->dev, "missing platform_data\n");
@@ -288,11 +353,26 @@
if (ret)
dev_err(&pdev->dev, "failed to create device file\n");
+ usb_bam_wq = alloc_workqueue("usb_bam_wq",
+ WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!usb_bam_wq) {
+ pr_err("unable to create workqueue usb_bam_wq\n");
+ return -ENOMEM;
+ }
+
return ret;
}
+static int usb_bam_remove(struct platform_device *pdev)
+{
+ destroy_workqueue(usb_bam_wq);
+
+ return 0;
+}
+
static struct platform_driver usb_bam_driver = {
.probe = usb_bam_probe,
+ .remove = usb_bam_remove,
.driver = { .name = "usb_bam", },
};
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index de5e741..e7797b1 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -1863,6 +1863,8 @@
chip->ext_charging = false;
chip->ext_charge_done = false;
bms_notify_check(chip);
+ /* Update battery charging LEDs and user space battery info */
+ power_supply_changed(&chip->batt_psy);
}
static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
@@ -1917,6 +1919,8 @@
/* Start BMS */
schedule_delayed_work(&chip->eoc_work, delay);
wake_lock(&chip->eoc_wake_lock);
+ /* Update battery charging LEDs and user space battery info */
+ power_supply_changed(&chip->batt_psy);
}
static void turn_off_usb_ovp_fet(struct pm8921_chg_chip *chip)
diff --git a/drivers/regulator/qpnp-regulator.c b/drivers/regulator/qpnp-regulator.c
index fe728b2..ddc8589 100644
--- a/drivers/regulator/qpnp-regulator.c
+++ b/drivers/regulator/qpnp-regulator.c
@@ -166,6 +166,13 @@
#define QPNP_BOOST_CURRENT_LIMIT_ENABLE_MASK 0x80
#define QPNP_BOOST_CURRENT_LIMIT_MASK 0x07
+/*
+ * This voltage in uV is returned by get_voltage functions when there is no way
+ * to determine the current voltage level. It is needed because the regulator
+ * framework treats a 0 uV voltage as an error.
+ */
+#define VOLTAGE_UNKNOWN 1
+
struct qpnp_voltage_range {
int min_uV;
int max_uV;
@@ -243,15 +250,18 @@
* properties to hold.
*/
static struct qpnp_voltage_range pldo_ranges[] = {
- VOLTAGE_RANGE(0, 375000, 375000, 1512500, 12500),
- VOLTAGE_RANGE(2, 750000, 1525000, 1537500, 12500),
+ VOLTAGE_RANGE(2, 750000, 750000, 1537500, 12500),
VOLTAGE_RANGE(3, 1500000, 1550000, 3075000, 25000),
VOLTAGE_RANGE(4, 1750000, 3100000, 4900000, 50000),
};
-static struct qpnp_voltage_range nldo_ranges[] = {
- VOLTAGE_RANGE(0, 375000, 375000, 1512500, 12500),
- VOLTAGE_RANGE(2, 750000, 1525000, 1537500, 12500),
+static struct qpnp_voltage_range nldo1_ranges[] = {
+ VOLTAGE_RANGE(2, 750000, 750000, 1537500, 12500),
+};
+
+static struct qpnp_voltage_range nldo2_ranges[] = {
+ VOLTAGE_RANGE(1, 375000, 375000, 768750, 6250),
+ VOLTAGE_RANGE(2, 750000, 775000, 1537500, 12500),
};
static struct qpnp_voltage_range smps_ranges[] = {
@@ -260,7 +270,7 @@
};
static struct qpnp_voltage_range ftsmps_ranges[] = {
- VOLTAGE_RANGE(0, 80000, 80000, 1355000, 5000),
+ VOLTAGE_RANGE(0, 80000, 350000, 1355000, 5000),
VOLTAGE_RANGE(1, 160000, 1360000, 2710000, 10000),
};
@@ -269,7 +279,10 @@
};
static struct qpnp_voltage_set_points pldo_set_points = SET_POINTS(pldo_ranges);
-static struct qpnp_voltage_set_points nldo_set_points = SET_POINTS(nldo_ranges);
+static struct qpnp_voltage_set_points nldo1_set_points
+ = SET_POINTS(nldo1_ranges);
+static struct qpnp_voltage_set_points nldo2_set_points
+ = SET_POINTS(nldo2_ranges);
static struct qpnp_voltage_set_points smps_set_points = SET_POINTS(smps_ranges);
static struct qpnp_voltage_set_points ftsmps_set_points
= SET_POINTS(ftsmps_ranges);
@@ -279,7 +292,8 @@
static struct qpnp_voltage_set_points *all_set_points[] = {
&pldo_set_points,
- &nldo_set_points,
+ &nldo1_set_points,
+ &nldo2_set_points,
&smps_set_points,
&ftsmps_set_points,
&boost_set_points,
@@ -629,7 +643,7 @@
if (!range) {
vreg_err(vreg, "voltage unknown, range %d is invalid\n",
range_sel);
- return -EINVAL;
+ return VOLTAGE_UNKNOWN;
}
return range->step_uV * voltage_sel + range->min_uV;
@@ -949,11 +963,9 @@
static const struct qpnp_regulator_mapping supported_regulators[] = {
QPNP_VREG_MAP(HF_BUCK, GP_CTL, SMPS, smps, smps, 100000),
- QPNP_VREG_MAP(LDO, N50, LDO, ldo, nldo, 5000),
- QPNP_VREG_MAP(LDO, N150, LDO, ldo, nldo, 10000),
- QPNP_VREG_MAP(LDO, N300, LDO, ldo, nldo, 10000),
- QPNP_VREG_MAP(LDO, N600, LDO, ldo, nldo, 10000),
- QPNP_VREG_MAP(LDO, N1200, LDO, ldo, nldo, 10000),
+ QPNP_VREG_MAP(LDO, N300, LDO, ldo, nldo1, 10000),
+ QPNP_VREG_MAP(LDO, N600, LDO, ldo, nldo2, 10000),
+ QPNP_VREG_MAP(LDO, N1200, LDO, ldo, nldo2, 10000),
QPNP_VREG_MAP(LDO, P50, LDO, ldo, pldo, 5000),
QPNP_VREG_MAP(LDO, P150, LDO, ldo, pldo, 10000),
QPNP_VREG_MAP(LDO, P300, LDO, ldo, pldo, 10000),
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 69e0546..2fc95af 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -39,6 +39,7 @@
#include <linux/remote_spinlock.h>
#include <linux/pm_qos_params.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include "spi_qsd.h"
static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
@@ -1076,8 +1077,8 @@
"timeout\n", __func__);
dd->cur_msg->status = -EIO;
if (dd->mode == SPI_DMOV_MODE) {
- msm_dmov_flush(dd->tx_dma_chan);
- msm_dmov_flush(dd->rx_dma_chan);
+ msm_dmov_flush(dd->tx_dma_chan, 1);
+ msm_dmov_flush(dd->rx_dma_chan, 1);
}
break;
}
@@ -1672,8 +1673,8 @@
return;
while (dd->mode == SPI_DMOV_MODE && limit++ < 50) {
- msm_dmov_flush(dd->tx_dma_chan);
- msm_dmov_flush(dd->rx_dma_chan);
+ msm_dmov_flush(dd->tx_dma_chan, 1);
+ msm_dmov_flush(dd->rx_dma_chan, 1);
msleep(10);
}
@@ -1739,8 +1740,8 @@
SPI_INPUT_FIFO;
/* Clear remaining activities on channel */
- msm_dmov_flush(dd->tx_dma_chan);
- msm_dmov_flush(dd->rx_dma_chan);
+ msm_dmov_flush(dd->tx_dma_chan, 1);
+ msm_dmov_flush(dd->rx_dma_chan, 1);
return 0;
}
@@ -1773,6 +1774,7 @@
int clk_enabled = 0;
int pclk_enabled = 0;
struct msm_spi_platform_data *pdata;
+ enum of_gpio_flags flags;
master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
if (!master) {
@@ -1797,9 +1799,35 @@
rc = -ENOMEM;
goto err_probe_exit;
}
+
+ for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
+ dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
+ i, &flags);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+ dd->cs_gpios[i].gpio_num = of_get_named_gpio_flags(
+ pdev->dev.of_node, "cs-gpios",
+ i, &flags);
+ dd->cs_gpios[i].valid = 0;
+ }
} else {
pdata = pdev->dev.platform_data;
dd->qup_ver = SPI_QUP_VERSION_NONE;
+
+ for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
+ resource = platform_get_resource(pdev, IORESOURCE_IO,
+ i);
+ dd->spi_gpios[i] = resource ? resource->start : -1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
+ resource = platform_get_resource(pdev, IORESOURCE_IO,
+ i + ARRAY_SIZE(spi_rsrcs));
+ dd->cs_gpios[i].gpio_num = resource ?
+ resource->start : -1;
+ dd->cs_gpios[i].valid = 0;
+ }
}
dd->pdata = pdata;
@@ -1852,18 +1880,6 @@
}
}
- for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
- resource = platform_get_resource(pdev, IORESOURCE_IO, i);
- dd->spi_gpios[i] = resource ? resource->start : -1;
- }
-
- for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
- resource = platform_get_resource(pdev, IORESOURCE_IO,
- i + ARRAY_SIZE(spi_rsrcs));
- dd->cs_gpios[i].gpio_num = resource ? resource->start : -1;
- dd->cs_gpios[i].valid = 0;
- }
-
rc = msm_spi_request_gpios(dd);
if (rc)
goto err_probe_gpio;
diff --git a/drivers/staging/qcache/fmem.c b/drivers/staging/qcache/fmem.c
index 4250ff5..1f78799 100644
--- a/drivers/staging/qcache/fmem.c
+++ b/drivers/staging/qcache/fmem.c
@@ -60,6 +60,10 @@
{
struct fmem_platform_data *pdata = pdev->dev.platform_data;
+ if (!pdata->phys)
+ pdata->phys = allocate_contiguous_ebi_nomap(pdata->size,
+ pdata->align);
+
#ifdef CONFIG_MEMORY_HOTPLUG
fmem_section_start = pdata->phys >> PA_SECTION_SHIFT;
fmem_section_end = (pdata->phys - 1 + pdata->size) >> PA_SECTION_SHIFT;
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index 32e9dc0..72bc8de 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -626,6 +626,9 @@
unsigned long flags;
unsigned int baud, mr;
+ if (!termios->c_cflag)
+ return;
+
spin_lock_irqsave(&port->lock, flags);
/* calculate and set baud rate */
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 5b0b279..d310381 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -769,8 +769,7 @@
*/
mb();
/* do discard flush */
- msm_dmov_stop_cmd(msm_uport->dma_rx_channel,
- &msm_uport->rx.xfer, 0);
+ msm_dmov_flush(msm_uport->dma_rx_channel, 0);
}
msm_hs_write(uport, UARTDM_IMR_ADDR, msm_uport->imr_reg);
@@ -831,8 +830,7 @@
if (msm_uport->rx.flush == FLUSH_NONE) {
wake_lock(&msm_uport->rx.wake_lock);
/* do discard flush */
- msm_dmov_stop_cmd(msm_uport->dma_rx_channel,
- &msm_uport->rx.xfer, 0);
+ msm_dmov_flush(msm_uport->dma_rx_channel, 0);
}
if (msm_uport->rx.flush != FLUSH_SHUTDOWN)
msm_uport->rx.flush = FLUSH_STOP;
@@ -1427,7 +1425,7 @@
if (rx->flush == FLUSH_NONE) {
rx->flush = FLUSH_DATA_READY;
- msm_dmov_flush(msm_uport->dma_rx_channel);
+ msm_dmov_flush(msm_uport->dma_rx_channel, 1);
}
}
/* tx ready interrupt */
diff --git a/drivers/tty/serial/msm_serial_hs_hwreg.h b/drivers/tty/serial/msm_serial_hs_hwreg.h
index 780a3c2..81f3d54 100644
--- a/drivers/tty/serial/msm_serial_hs_hwreg.h
+++ b/drivers/tty/serial/msm_serial_hs_hwreg.h
@@ -1,6 +1,6 @@
/* drivers/serial/msm_serial_hs_hwreg.h
*
- * Copyright (c) 2007-2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2009, 2012, Code Aurora Forum. All rights reserved.
*
* All source code in this file is licensed under the following license
* except where indicated.
@@ -160,9 +160,12 @@
#define UARTDM_MR1_CTS_CTL_BMSK 0x40
#define UARTDM_MR1_RX_RDY_CTL_BMSK 0x80
-#define UARTDM_MR2_LOOP_MODE_BMSK 0x80
-#define UARTDM_MR2_ERROR_MODE_BMSK 0x40
-#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30
+#define UARTDM_MR2_LOOP_MODE_BMSK 0x80
+#define UARTDM_MR2_ERROR_MODE_BMSK 0x40
+#define UARTDM_MR2_BITS_PER_CHAR_BMSK 0x30
+#define UARTDM_MR2_RX_ZERO_CHAR_OFF 0x100
+#define UARTDM_MR2_RX_ERROR_CHAR_OFF 0x200
+#define UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF 0x100
#define UARTDM_MR2_BITS_PER_CHAR_8 (0x3 << 4)
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 285d1de..62d25cf 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -792,6 +792,9 @@
unsigned int baud, mr;
unsigned int vid;
+ if (!termios->c_cflag)
+ return;
+
spin_lock_irqsave(&port->lock, flags);
/* calculate and set baud rate */
@@ -1170,7 +1173,7 @@
{
struct uart_port *port;
unsigned int vid;
- int baud = 0, flow, bits, parity;
+ int baud = 0, flow, bits, parity, mr2;
int ret;
if (unlikely(co->index >= UART_NR || co->index < 0))
@@ -1205,6 +1208,12 @@
msm_hsl_set_baud_rate(port, baud);
ret = uart_set_options(port, co, baud, parity, bits, flow);
+
+ mr2 = msm_hsl_read(port, regmap[vid][UARTDM_MR2]);
+ mr2 |= UARTDM_MR2_RX_ERROR_CHAR_OFF;
+ mr2 |= UARTDM_MR2_RX_BREAK_ZERO_CHAR_OFF;
+ msm_hsl_write(port, mr2, regmap[vid][UARTDM_MR2]);
+
msm_hsl_reset(port);
/* Enable transmitter */
msm_hsl_write(port, CR_PROTECTION_EN, regmap[vid][UARTDM_CR]);
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index c017859..d74959e 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1679,7 +1679,7 @@
}
/* pm qos request to prevent apps idle power collapse */
- if (pdata->swfi_latency)
+ if (pdata && pdata->swfi_latency)
pm_qos_add_request(&dev->pm_qos_req_dma,
PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
strlcpy(dev->pm_qos, "high", sizeof(dev->pm_qos));
@@ -1700,7 +1700,7 @@
android_destroy_device(dev);
class_destroy(android_class);
usb_composite_unregister(&android_usb_driver);
- if (pdata->swfi_latency)
+ if (pdata && pdata->swfi_latency)
pm_qos_remove_request(&dev->pm_qos_req_dma);
return 0;
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index eeacceb..39d4720 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -65,6 +65,7 @@
struct msm_xo_voter *xo_handle;
struct workqueue_struct *wq;
struct work_struct suspend_w;
+ struct msm_hsic_peripheral_platform_data *pdata;
};
static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
@@ -365,8 +366,10 @@
*/
mb();
- clk_disable(mhsic->iface_clk);
- clk_disable(mhsic->core_clk);
+ if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+ clk_disable(mhsic->iface_clk);
+ clk_disable(mhsic->core_clk);
+ }
clk_disable(mhsic->phy_clk);
clk_disable(mhsic->cal_clk);
@@ -416,8 +419,10 @@
dev_err(mhsic->dev, "%s failed to vote for TCXO %d\n",
__func__, ret);
- clk_enable(mhsic->iface_clk);
- clk_enable(mhsic->core_clk);
+ if (!mhsic->pdata->keep_core_clk_on_suspend_workaround) {
+ clk_enable(mhsic->iface_clk);
+ clk_enable(mhsic->core_clk);
+ }
clk_enable(mhsic->phy_clk);
clk_enable(mhsic->cal_clk);
@@ -611,9 +616,17 @@
struct resource *res;
struct msm_hsic_per *mhsic;
int ret = 0;
+ struct msm_hsic_peripheral_platform_data *pdata;
dev_dbg(&pdev->dev, "msm-hsic probe\n");
+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "No platform data given. Bailing out\n");
+ return -ENODEV;
+ } else {
+ pdata = pdev->dev.platform_data;
+ }
+
mhsic = kzalloc(sizeof(struct msm_hsic_per), GFP_KERNEL);
if (!mhsic) {
dev_err(&pdev->dev, "unable to allocate msm_hsic\n");
@@ -622,6 +635,7 @@
the_mhsic = mhsic;
platform_set_drvdata(pdev, mhsic);
mhsic->dev = &pdev->dev;
+ mhsic->pdata = pdata;
mhsic->irq = platform_get_irq(pdev, 0);
if (mhsic->irq < 0) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index d754a88..b612a0b 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3273,15 +3273,6 @@
udc->gadget.dev.parent = dev;
udc->gadget.dev.release = udc_release;
- retval = hw_device_init(regs);
- if (retval < 0)
- goto free_udc;
-
- for (i = 0; i < hw_ep_max; i++) {
- struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
- INIT_LIST_HEAD(&mEp->ep.ep_list);
- }
-
udc->transceiver = otg_get_transceiver();
if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
@@ -3291,6 +3282,15 @@
}
}
+ retval = hw_device_init(regs);
+ if (retval < 0)
+ goto put_transceiver;
+
+ for (i = 0; i < hw_ep_max; i++) {
+ struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i];
+ INIT_LIST_HEAD(&mEp->ep.ep_list);
+ }
+
if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) {
retval = hw_device_reset(udc);
if (retval)
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 958ed31..fcbc75c 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -414,6 +414,60 @@
kfree(f->name);
}
+static void frmnet_suspend(struct usb_function *f)
+{
+ struct f_rmnet *dev = func_to_rmnet(f);
+ unsigned port_num;
+ enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
+
+ pr_debug("%s: data xport: %s dev: %p portno: %d\n",
+ __func__, xport_to_str(dxport),
+ dev, dev->port_num);
+
+ port_num = rmnet_ports[dev->port_num].data_xport_num;
+ switch (dxport) {
+ case USB_GADGET_XPORT_BAM:
+ break;
+ case USB_GADGET_XPORT_BAM2BAM:
+ gbam_suspend(&dev->port, port_num, dxport);
+ break;
+ case USB_GADGET_XPORT_HSIC:
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %s\n", __func__,
+ xport_to_str(dxport));
+ }
+}
+
+static void frmnet_resume(struct usb_function *f)
+{
+ struct f_rmnet *dev = func_to_rmnet(f);
+ unsigned port_num;
+ enum transport_type dxport = rmnet_ports[dev->port_num].data_xport;
+
+ pr_debug("%s: data xport: %s dev: %p portno: %d\n",
+ __func__, xport_to_str(dxport),
+ dev, dev->port_num);
+
+ port_num = rmnet_ports[dev->port_num].data_xport_num;
+ switch (dxport) {
+ case USB_GADGET_XPORT_BAM:
+ break;
+ case USB_GADGET_XPORT_BAM2BAM:
+ gbam_resume(&dev->port, port_num, dxport);
+ break;
+ case USB_GADGET_XPORT_HSIC:
+ break;
+ case USB_GADGET_XPORT_NONE:
+ break;
+ default:
+ pr_err("%s: Un-supported transport: %s\n", __func__,
+ xport_to_str(dxport));
+ }
+}
+
static void frmnet_disable(struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
@@ -912,6 +966,8 @@
f->disable = frmnet_disable;
f->set_alt = frmnet_set_alt;
f->setup = frmnet_setup;
+ f->suspend = frmnet_suspend;
+ f->resume = frmnet_resume;
dev->port.send_cpkt_response = frmnet_send_cpkt_response;
dev->port.disconnect = frmnet_disconnect;
dev->port.connect = frmnet_connect;
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index 0921b4f..863ddcd 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -1109,6 +1109,7 @@
struct msm_endpoint *ept = ui->ept + bit;
struct msm_request *req;
unsigned long flags;
+ int req_dequeue = 1;
unsigned info;
/*
@@ -1128,12 +1129,23 @@
break;
}
+dequeue:
/* clean speculative fetches on req->item->info */
dma_coherent_post_ops();
info = req->item->info;
/* if the transaction is still in-flight, stop here */
- if (info & INFO_ACTIVE)
- break;
+ if (info & INFO_ACTIVE) {
+ if (req_dequeue) {
+ req_dequeue = 0;
+ ui->dTD_update_fail_count++;
+ ept->dTD_update_fail_count++;
+ udelay(10);
+ goto dequeue;
+ } else {
+ break;
+ }
+ }
+ req_dequeue = 0;
del_timer(&ept->prime_timer);
/* advance ept queue to the next request */
@@ -2289,13 +2301,14 @@
static int msm72k_pullup(struct usb_gadget *_gadget, int is_active)
{
struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
+ struct msm_otg *otg = to_msm_otg(ui->xceiv);
unsigned long flags;
-
atomic_set(&ui->softconnect, is_active);
spin_lock_irqsave(&ui->lock, flags);
- if (ui->usb_state == USB_STATE_NOTATTACHED || ui->driver == NULL) {
+ if (ui->usb_state == USB_STATE_NOTATTACHED || ui->driver == NULL ||
+ atomic_read(&otg->chg_type) == USB_CHG_TYPE__WALLCHARGER) {
spin_unlock_irqrestore(&ui->lock, flags);
return 0;
}
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 3113c45..d379c66 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -1214,3 +1214,49 @@
return ret;
}
+
+static int gbam_wake_cb(void *param)
+{
+ struct gbam_port *port = (struct gbam_port *)param;
+ struct bam_ch_info *d;
+ struct f_rmnet *dev;
+
+ dev = port_to_rmnet(port->gr);
+ d = &port->data_ch;
+
+ pr_debug("%s: woken up by peer\n", __func__);
+
+ return usb_gadget_wakeup(dev->cdev->gadget);
+}
+
+void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans)
+{
+ struct gbam_port *port;
+ struct bam_ch_info *d;
+
+ if (trans != USB_GADGET_XPORT_BAM2BAM)
+ return;
+
+ port = bam2bam_ports[port_num];
+ d = &port->data_ch;
+
+ pr_debug("%s: suspended port %d\n", __func__, port_num);
+
+ usb_bam_register_wake_cb(d->connection_idx, gbam_wake_cb, port);
+}
+
+void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans)
+{
+ struct gbam_port *port;
+ struct bam_ch_info *d;
+
+ if (trans != USB_GADGET_XPORT_BAM2BAM)
+ return;
+
+ port = bam2bam_ports[port_num];
+ d = &port->data_ch;
+
+ pr_debug("%s: resumed port %d\n", __func__, port_num);
+
+ usb_bam_register_wake_cb(d->connection_idx, NULL, NULL);
+}
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index 386101c..0f7c4fb 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.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
@@ -50,6 +50,8 @@
int gbam_connect(struct grmnet *gr, u8 port_num,
enum transport_type trans, u8 connection_idx);
void gbam_disconnect(struct grmnet *gr, u8 port_num, enum transport_type trans);
+void gbam_suspend(struct grmnet *gr, u8 port_num, enum transport_type trans);
+void gbam_resume(struct grmnet *gr, u8 port_num, enum transport_type trans);
int gsmd_ctrl_connect(struct grmnet *gr, int port_num);
void gsmd_ctrl_disconnect(struct grmnet *gr, u8 port_num);
int gsmd_ctrl_setup(unsigned int count);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 0c71c8b..902d07cb 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -889,6 +889,12 @@
pstatus = ehci_readl(ehci,
&ehci->regs->port_status[i]);
+ /*set RS bit in case of remote wakeup*/
+ if (ehci_is_TDI(ehci) && !(cmd & CMD_RUN) &&
+ (pstatus & PORT_SUSPEND))
+ ehci_writel(ehci, cmd | CMD_RUN,
+ &ehci->regs->command);
+
if (pstatus & PORT_OWNER)
continue;
if (!(test_bit(i, &ehci->suspended_ports) &&
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index a83f6d3..5ee1908 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -40,8 +40,6 @@
#include <mach/msm_xo.h>
#include <linux/spinlock.h>
-#define RUNTIME_SUSP_DELAY 500
-
#define MSM_USB_BASE (hcd->regs)
struct msm_hsic_hcd {
@@ -59,7 +57,6 @@
int peripheral_status_irq;
int wakeup_irq;
bool wakeup_irq_enabled;
- bool pm_resume;
uint32_t bus_perf_client;
};
@@ -348,7 +345,9 @@
* mode (LPM). Hence poll for 500 msec and reset the PHY and link
* in failure case.
*/
- val = readl_relaxed(USB_PORTSC) | PORTSC_PHCD;
+ val = readl_relaxed(USB_PORTSC);
+ val &= ~PORT_RWC_BITS;
+ val |= PORTSC_PHCD;
writel_relaxed(val, USB_PORTSC);
while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
@@ -447,7 +446,8 @@
if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD))
goto skip_phy_resume;
- temp = readl_relaxed(USB_PORTSC) & ~PORTSC_PHCD;
+ temp = readl_relaxed(USB_PORTSC);
+ temp &= ~(PORT_RWC_BITS | PORTSC_PHCD);
writel_relaxed(temp, USB_PORTSC);
while (cnt < PHY_RESUME_TIMEOUT_USEC) {
if (!(readl_relaxed(USB_PORTSC) & PORTSC_PHCD) &&
@@ -489,6 +489,7 @@
if (atomic_read(&mehci->in_lpm)) {
disable_irq_nosync(hcd->irq);
+ dev_dbg(mehci->dev, "phy async intr\n");
mehci->async_int = true;
pm_runtime_get(mehci->dev);
return IRQ_HANDLED;
@@ -955,7 +956,6 @@
ehci_hsic_msm_debugfs_cleanup();
device_init_wakeup(&pdev->dev, 0);
- mehci->pm_resume = false;
pm_runtime_set_suspended(&pdev->dev);
usb_remove_hcd(hcd);
@@ -981,8 +981,6 @@
if (device_may_wakeup(dev))
enable_irq_wake(hcd->irq);
- mehci->pm_resume = false;
-
return msm_hsic_suspend(mehci);
}
@@ -1019,8 +1017,6 @@
disable_irq_nosync(mehci->wakeup_irq);
}
- mehci->pm_resume = true;
-
ret = msm_hsic_resume(mehci);
if (ret)
return ret;
@@ -1038,15 +1034,12 @@
static int msm_hsic_runtime_idle(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
dev_dbg(dev, "EHCI runtime idle\n");
- if (mehci->pm_resume) {
- mehci->pm_resume = false;
- pm_schedule_suspend(dev, RUNTIME_SUSP_DELAY);
+ /*don't allow runtime suspend in the middle of remote wakeup*/
+ if (readl_relaxed(USB_PORTSC) & PORT_RESUME)
return -EAGAIN;
- }
return 0;
}
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 9794918..96e5a90 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -88,7 +88,8 @@
return;
}
- cbs->read_complete_cb(cbs->ctxt,
+ if (cbs && cbs->read_complete_cb)
+ cbs->read_complete_cb(cbs->ctxt,
urb->transfer_buffer,
urb->transfer_buffer_length,
urb->status < 0 ? urb->status : urb->actual_length);
@@ -172,7 +173,8 @@
return;
}
- cbs->write_complete_cb(cbs->ctxt,
+ if (cbs && cbs->write_complete_cb)
+ cbs->write_complete_cb(cbs->ctxt,
urb->transfer_buffer,
urb->transfer_buffer_length,
urb->status < 0 ? urb->status : urb->actual_length);
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 2a08101..94de730 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -734,6 +734,10 @@
}
}
+ 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];
@@ -759,9 +763,6 @@
play_delayed(port);
spin_unlock_irq(&intfdata->susp_lock);
}
- spin_lock_irq(&intfdata->susp_lock);
- intfdata->suspended = 0;
- spin_unlock_irq(&intfdata->susp_lock);
err_out:
return err;
}
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 5d12e97..7f603dd 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -2056,6 +2056,7 @@
pinfo->xres = timing->active_h;
pinfo->yres = timing->active_v;
pinfo->clk_rate = timing->pixel_freq*1000;
+ pinfo->frame_rate = 60;
pinfo->lcdc.h_back_porch = timing->back_porch_h;
pinfo->lcdc.h_front_porch = timing->front_porch_h;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index 375f82f..7f6585c 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -4136,6 +4136,8 @@
/* HDMI_USEC_REFTIMER[0x0208] */
HDMI_OUTP(0x0208, 0x0001001B);
+ hdmi_msm_set_mode(TRUE);
+
hdmi_msm_video_setup(external_common_state->video_resolution);
if (!hdmi_msm_is_dvi_mode())
hdmi_msm_audio_setup();
@@ -4152,8 +4154,6 @@
HDMI_OUTP(0x0258, ~(1 << 28) & hpd_ctrl);
HDMI_OUTP(0x0258, (1 << 28) | hpd_ctrl);
- hdmi_msm_set_mode(TRUE);
-
/* Setup HPD IRQ */
HDMI_OUTP(0x0254, 4 | (external_common_state->hpd_state ? 0 : 2));
@@ -4539,7 +4539,6 @@
hdmi_msm_state->hdcp_timer.data = (uint32)NULL;
hdmi_msm_state->hdcp_timer.expires = 0xffffffffL;
- add_timer(&hdmi_msm_state->hdcp_timer);
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_HDCP_SUPPORT */
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT
diff --git a/drivers/video/msm/lcdc_toshiba_fwvga_pt.c b/drivers/video/msm/lcdc_toshiba_fwvga_pt.c
index 3e81471..77606cf 100644
--- a/drivers/video/msm/lcdc_toshiba_fwvga_pt.c
+++ b/drivers/video/msm/lcdc_toshiba_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
@@ -436,7 +436,7 @@
pinfo->bl_max = 100;
pinfo->bl_min = 1;
- if (cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+ if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
pinfo->yres = 320;
pinfo->lcdc.h_back_porch = 10;
pinfo->lcdc.h_front_porch = 21;
diff --git a/drivers/video/msm/lvds.c b/drivers/video/msm/lvds.c
index 8f1e510..18225fb 100644
--- a/drivers/video/msm/lvds.c
+++ b/drivers/video/msm/lvds.c
@@ -143,9 +143,9 @@
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D2_6_TO_4 */
MDP_OUTP(MDP_BASE + 0xc2028, 0x00121314);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_3_TO_0 */
- MDP_OUTP(MDP_BASE + 0xc202c, 0x1706071b);
+ MDP_OUTP(MDP_BASE + 0xc202c, 0x0f16171b);
/* MDP_LCDC_LVDS_MUX_CTL_FOR_D3_6_TO_4 */
- MDP_OUTP(MDP_BASE + 0xc2030, 0x000e0f16);
+ MDP_OUTP(MDP_BASE + 0xc2030, 0x0006070e);
}
if (mfd->panel_info.lvds.channel_mode ==
LVDS_DUAL_CHANNEL_MODE) {
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 2ca9296..471ed4e 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -2071,7 +2071,7 @@
}
disable_irq(mdp_irq);
- footswitch = regulator_get(NULL, "fs_mdp");
+ footswitch = regulator_get(&pdev->dev, "vdd");
if (IS_ERR(footswitch))
footswitch = NULL;
else {
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index 42edecc..34fd399 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -2889,6 +2889,11 @@
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_mixer_stage_up(pipe);
if (pipe->mixer_num == MDP4_MIXER2) {
@@ -2903,7 +2908,6 @@
ctrl->mixer1_played++;
/* enternal interface */
if (ctrl->panel_mode & MDP4_PANEL_DTV) {
- mdp4_overlay_reg_flush(pipe, 0);
mdp4_overlay_dtv_start();
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
if (!mfd->use_ov1_blt)
@@ -2914,7 +2918,6 @@
/* primary interface */
ctrl->mixer0_played++;
if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
- mdp4_overlay_reg_flush(pipe, 0);
if (!mfd->use_ov0_blt)
mdp4_overlay_update_blt_mode(mfd);
mdp4_overlay_lcdc_start();
@@ -2922,7 +2925,6 @@
}
#ifdef CONFIG_FB_MSM_MIPI_DSI
else if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
- mdp4_overlay_reg_flush(pipe, 0);
if (!mfd->use_ov0_blt)
mdp4_overlay_update_blt_mode(mfd);
mdp4_overlay_dsi_video_start();
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index b9760bf..e3917e6 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -470,6 +470,28 @@
mfd->ov_start = true;
}
+static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
+{
+ unsigned long flag;
+
+ if (!dtv_pipe) {
+ pr_debug("%s: no mixer1 base layer pipe allocated!\n",
+ __func__);
+ return;
+ }
+ /* enable irq */
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mdp_enable_irq(MDP_DMA_E_TERM);
+ INIT_COMPLETION(dtv_pipe->comp);
+ mfd->dma->waiting = TRUE;
+ outp32(MDP_INTR_CLEAR, INTR_DMA_E_DONE);
+ mdp_intr_mask |= INTR_DMA_E_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ wait_for_completion_killable(&dtv_pipe->comp);
+ mdp_disable_irq(MDP_DMA_E_TERM);
+}
+
static void mdp4_overlay_dtv_wait4_ov_done(struct msm_fb_data_type *mfd,
struct mdp4_overlay_pipe *pipe)
{
@@ -490,6 +512,9 @@
wait_for_completion_timeout(&dtv_pipe->comp,
msecs_to_jiffies(VSYNC_PERIOD*2));
mdp_disable_irq(MDP_OVERLAY1_TERM);
+
+ if (dtv_pipe->blt_addr)
+ mdp4_overlay_dtv_wait4dmae(mfd);
}
void mdp4_overlay_dtv_start(void)
@@ -601,28 +626,6 @@
mdp_disable_irq(MDP_DMA_E_TERM);
}
-static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
-{
- unsigned long flag;
-
- if (!dtv_pipe) {
- pr_debug("%s: no mixer1 base layer pipe allocated!\n",
- __func__);
- return;
- }
- /* enable irq */
- spin_lock_irqsave(&mdp_spin_lock, flag);
- mdp_enable_irq(MDP_DMA_E_TERM);
- INIT_COMPLETION(dtv_pipe->comp);
- mfd->dma->waiting = TRUE;
- outp32(MDP_INTR_CLEAR, INTR_DMA_E_DONE);
- mdp_intr_mask |= INTR_DMA_E_DONE;
- outp32(MDP_INTR_ENABLE, mdp_intr_mask);
- spin_unlock_irqrestore(&mdp_spin_lock, flag);
- wait_for_completion_killable(&dtv_pipe->comp);
- mdp_disable_irq(MDP_DMA_E_TERM);
-}
-
static void mdp4_dtv_do_blt(struct msm_fb_data_type *mfd, int enable)
{
unsigned long flag;
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index eaf1868..964df4e 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -418,6 +418,7 @@
static char video27[2] = {
0x35, 0x00,
};
+static char config_video_MADCTL[2] = {0x36, 0xC0};
static struct dsi_cmd_desc nt35510_video_display_on_cmds[] = {
{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video0), video0},
{DTYPE_GEN_LWRITE, 1, 0, 0, 50, sizeof(video1), video1},
@@ -453,11 +454,15 @@
display_on},
};
+static struct dsi_cmd_desc nt35510_video_display_on_cmds_rotate[] = {
+ {DTYPE_DCS_WRITE1, 1, 0, 0, 150,
+ sizeof(config_video_MADCTL), config_video_MADCTL},
+};
static int mipi_nt35510_lcd_on(struct platform_device *pdev)
{
struct msm_fb_data_type *mfd;
struct mipi_panel_info *mipi;
-
+ static int rotate;
mfd = platform_get_drvdata(pdev);
if (!mfd)
return -ENODEV;
@@ -467,10 +472,19 @@
mipi = &mfd->panel_info.mipi;
+ if (mipi_nt35510_pdata && mipi_nt35510_pdata->rotate_panel)
+ rotate = mipi_nt35510_pdata->rotate_panel();
+
if (mipi->mode == DSI_VIDEO_MODE) {
mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
nt35510_video_display_on_cmds,
ARRAY_SIZE(nt35510_video_display_on_cmds));
+
+ if (rotate) {
+ mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
+ nt35510_video_display_on_cmds_rotate,
+ ARRAY_SIZE(nt35510_video_display_on_cmds_rotate));
+ }
} else if (mipi->mode == DSI_CMD_MODE) {
mipi_dsi_cmds_tx(mfd, &nt35510_tx_buf,
nt35510_cmd_display_on_cmds,
diff --git a/drivers/video/msm/mipi_chimei_wuxga.c b/drivers/video/msm/mipi_chimei_wuxga.c
index 7abb0d4..6ddf74d 100644
--- a/drivers/video/msm/mipi_chimei_wuxga.c
+++ b/drivers/video/msm/mipi_chimei_wuxga.c
@@ -125,7 +125,7 @@
pinfo->lcdc.hsync_skew = 0;
/* Backlight levels - controled via PMIC pwm gpio */
- pinfo->bl_max = 15;
+ pinfo->bl_max = PWM_LEVEL;
pinfo->bl_min = 1;
/* mipi - general */
diff --git a/drivers/video/msm/mipi_chimei_wxga_pt.c b/drivers/video/msm/mipi_chimei_wxga_pt.c
index 4729d83..1ab50b7 100644
--- a/drivers/video/msm/mipi_chimei_wxga_pt.c
+++ b/drivers/video/msm/mipi_chimei_wxga_pt.c
@@ -121,7 +121,7 @@
pinfo->lcdc.hsync_skew = 0;
/* Backlight levels - controled via PMIC pwm gpio */
- pinfo->bl_max = 15;
+ pinfo->bl_max = PWM_LEVEL;
pinfo->bl_min = 1;
/* mipi - general */
diff --git a/drivers/video/msm/mipi_renesas.c b/drivers/video/msm/mipi_renesas.c
index 6a7027a..c9dc8255 100644
--- a/drivers/video/msm/mipi_renesas.c
+++ b/drivers/video/msm/mipi_renesas.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
@@ -1138,7 +1138,7 @@
mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_display_on_cmds,
ARRAY_SIZE(renesas_display_on_cmds));
- if (cpu_is_msm7x25a() || cpu_is_msm7x25aa()) {
+ if (cpu_is_msm7x25a() || cpu_is_msm7x25aa() || cpu_is_msm7x25ab()) {
mipi_dsi_cmds_tx(mfd, &renesas_tx_buf, renesas_hvga_on_cmds,
ARRAY_SIZE(renesas_hvga_on_cmds));
}
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index 1624534..f7f353f 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -188,12 +188,9 @@
#define DEBUG01 0x05A4 /* LVDS Data */
/* PWM */
-static u32 d2l_pwm_freq_hz = (66*1000);
+static u32 d2l_pwm_freq_hz = (3.921*1000);
-/* 1366x768 uses pwm at 66 KHZ */
-/* 1200x1920 uses pwm at 25 KHZ */
#define PWM_FREQ_HZ (d2l_pwm_freq_hz)
-#define PWM_LEVEL 15
#define PWM_PERIOD_USEC (USEC_PER_SEC / PWM_FREQ_HZ)
#define PWM_DUTY_LEVEL (PWM_PERIOD_USEC / PWM_LEVEL)
@@ -559,10 +556,7 @@
/* Set gpio#4=U/D=0, gpio#3=L/R=1 , gpio#2,1=CABC=0, gpio#0=NA. */
mipi_d2l_write_reg(mfd, GPIOO, d2l_gpio_out_val);
- if (mfd->panel_info.xres == 1366)
- d2l_pwm_freq_hz = (66*1000);
- else
- d2l_pwm_freq_hz = (25*1000);
+ d2l_pwm_freq_hz = (3.921*1000);
if (bl_level == 0)
bl_level = PWM_LEVEL * 2 / 3 ; /* Default ON value */
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.h b/drivers/video/msm/mipi_tc358764_dsi2lvds.h
index 072d1f4..1b949f0 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.h
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.h
@@ -14,6 +14,8 @@
#ifndef MIPI_TC358764_DSI2LVDS_H
#define MIPI_TC358764_DSI2LVDS_H
+#define PWM_LEVEL 255
+
int mipi_tc358764_dsi2lvds_register(struct msm_panel_info *pinfo,
u32 channel_id, u32 panel_id);
#endif /* MIPI_TC358764_DSI2LVDS_H */
diff --git a/drivers/video/msm/mipi_toshiba.h b/drivers/video/msm/mipi_toshiba.h
index 632bbd3..4107161 100644
--- a/drivers/video/msm/mipi_toshiba.h
+++ b/drivers/video/msm/mipi_toshiba.h
@@ -21,9 +21,9 @@
int mipi_toshiba_device_register(struct msm_panel_info *pinfo,
u32 channel, u32 panel);
-#define MIPI_TOSHIBA_PWM_FREQ_HZ 300
+#define MIPI_TOSHIBA_PWM_FREQ_HZ 3921
#define MIPI_TOSHIBA_PWM_PERIOD_USEC (USEC_PER_SEC / MIPI_TOSHIBA_PWM_FREQ_HZ)
-#define MIPI_TOSHIBA_PWM_LEVEL 100
+#define MIPI_TOSHIBA_PWM_LEVEL 255
#define MIPI_TOSHIBA_PWM_DUTY_LEVEL \
(MIPI_TOSHIBA_PWM_PERIOD_USEC / MIPI_TOSHIBA_PWM_LEVEL)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index c6b0440..b4d8db0 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -1194,6 +1194,7 @@
mfd->var_xres = panel_info->xres;
mfd->var_yres = panel_info->yres;
+ mfd->var_frame_rate = panel_info->frame_rate;
var->pixclock = mfd->panel_info.clk_rate;
mfd->var_pixclock = var->pixclock;
@@ -1229,22 +1230,45 @@
/*
* id field for fb app
*/
- id = (int *)&mfd->panel;
+ id = (int *)&mfd->panel;
-#if defined(CONFIG_FB_MSM_MDP22)
- snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP30)
- snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP31)
- snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP40)
- snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
-#elif defined(CONFIG_FB_MSM_MDP_NONE)
- snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id);
-#else
- error CONFIG_FB_MSM_MDP undefined !
-#endif
- fbi->fbops = &msm_fb_ops;
+ switch (mdp_rev) {
+ case MDP_REV_20:
+ snprintf(fix->id, sizeof(fix->id), "msmfb20_%x", (__u32) *id);
+ break;
+ case MDP_REV_22:
+ snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id);
+ break;
+ case MDP_REV_30:
+ snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id);
+ break;
+ case MDP_REV_303:
+ snprintf(fix->id, sizeof(fix->id), "msmfb303_%x", (__u32) *id);
+ break;
+ case MDP_REV_31:
+ snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
+ break;
+ case MDP_REV_40:
+ snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
+ break;
+ case MDP_REV_41:
+ snprintf(fix->id, sizeof(fix->id), "msmfb41_%x", (__u32) *id);
+ break;
+ case MDP_REV_42:
+ snprintf(fix->id, sizeof(fix->id), "msmfb42_%x", (__u32) *id);
+ break;
+ case MDP_REV_43:
+ snprintf(fix->id, sizeof(fix->id), "msmfb43_%x", (__u32) *id);
+ break;
+ case MDP_REV_44:
+ snprintf(fix->id, sizeof(fix->id), "msmfb44_%x", (__u32) *id);
+ break;
+ default:
+ snprintf(fix->id, sizeof(fix->id), "msmfb0_%x", (__u32) *id);
+ break;
+ }
+
+ fbi->fbops = &msm_fb_ops;
fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->pseudo_palette = msm_fb_pseudo_palette;
@@ -1736,6 +1760,27 @@
return 0;
}
+int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd
+ , struct fb_info *info)
+{
+ int panel_height, panel_width, var_frame_rate, fps_mod;
+ struct fb_var_screeninfo *var = &info->var;
+ fps_mod = 0;
+ if ((mfd->panel_info.type == DTV_PANEL) ||
+ (mfd->panel_info.type == HDMI_PANEL)) {
+ panel_height = var->yres + var->upper_margin +
+ var->vsync_len + var->lower_margin;
+ panel_width = var->xres + var->right_margin +
+ var->hsync_len + var->left_margin;
+ var_frame_rate = ((var->pixclock)/(panel_height * panel_width));
+ if (mfd->var_frame_rate != var_frame_rate) {
+ fps_mod = 1;
+ mfd->var_frame_rate = var_frame_rate;
+ }
+ }
+ return fps_mod;
+}
+
static int msm_fb_set_par(struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -1777,7 +1822,8 @@
(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_yres != var->yres) ||
+ (msm_fb_check_frame_rate(mfd, info))))) {
mfd->var_xres = var->xres;
mfd->var_yres = var->yres;
mfd->var_pixclock = var->pixclock;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 3becc46..b63c022 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -148,6 +148,7 @@
__u32 var_xres;
__u32 var_yres;
__u32 var_pixclock;
+ __u32 var_frame_rate;
#ifdef MSM_FB_ENABLE_DBGFS
struct dentry *sub_dir;
@@ -210,5 +211,7 @@
void fill_black_screen(void);
void unfill_black_screen(void);
+int msm_fb_check_frame_rate(struct msm_fb_data_type *mfd,
+ struct fb_info *info);
#endif /* MSM_FB_H */
diff --git a/drivers/video/msm/msm_fb_panel.h b/drivers/video/msm/msm_fb_panel.h
index 7744e7a..9d16b7b 100644
--- a/drivers/video/msm/msm_fb_panel.h
+++ b/drivers/video/msm/msm_fb_panel.h
@@ -164,6 +164,7 @@
__u32 clk_max;
__u32 frame_count;
__u32 is_3d_panel;
+ __u32 frame_rate;
struct mddi_panel_info mddi;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
index 4a952c9..86f282e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl.h
@@ -84,6 +84,8 @@
#define DDL_MAX_NUM_IN_INPUTFRAME_POOL (DDL_MAX_NUM_OF_B_FRAME + 1)
+#define MDP_MIN_TILE_HEIGHT 96
+
enum ddl_mem_area {
DDL_FW_MEM = 0x0,
DDL_MM_MEM = 0x1,
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 2862b00..6d3a05a 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
@@ -655,8 +655,9 @@
ptr = ddl_pmem_alloc(&dec_bufs->context, buf_size.sz_context,
DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
- msm_ion_do_cache_op(ddl_context->video_ion_client,
+ goto fail_free_exit;
+ else
+ msm_ion_do_cache_op(ddl_context->video_ion_client,
dec_bufs->context.alloc_handle,
dec_bufs->context.virtual_base_addr,
dec_bufs->context.buffer_size,
@@ -667,77 +668,77 @@
ptr = ddl_pmem_alloc(&dec_bufs->h264_nb_ip, buf_size.sz_nb_ip,
DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_vert_nb_mv > 0) {
dec_bufs->h264_vert_nb_mv.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->h264_vert_nb_mv,
buf_size.sz_vert_nb_mv, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_nb_dcac > 0) {
dec_bufs->nb_dcac.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->nb_dcac, buf_size.sz_nb_dcac,
DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_upnb_mv > 0) {
dec_bufs->upnb_mv.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->upnb_mv, buf_size.sz_upnb_mv,
DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_sub_anchor_mv > 0) {
dec_bufs->sub_anchor_mv.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->sub_anchor_mv,
buf_size.sz_sub_anchor_mv, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_overlap_xform > 0) {
dec_bufs->overlay_xform.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->overlay_xform,
buf_size.sz_overlap_xform, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_bit_plane3 > 0) {
dec_bufs->bit_plane3.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->bit_plane3,
buf_size.sz_bit_plane3, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_bit_plane2 > 0) {
dec_bufs->bit_plane2.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->bit_plane2,
buf_size.sz_bit_plane2, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_bit_plane1 > 0) {
dec_bufs->bit_plane1.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->bit_plane1,
buf_size.sz_bit_plane1, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_stx_parser > 0) {
dec_bufs->stx_parser.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->stx_parser,
buf_size.sz_stx_parser, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
}
if (buf_size.sz_desc > 0) {
dec_bufs->desc.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&dec_bufs->desc, buf_size.sz_desc,
DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_free_exit;
else {
if (!res_trk_check_for_sec_session()) {
memset(dec_bufs->desc.align_virtual_addr,
@@ -751,8 +752,10 @@
}
}
}
- if (status)
- ddl_free_dec_hw_buffers(ddl);
+ return status;
+fail_free_exit:
+ status = VCD_ERR_ALLOC_FAIL;
+ ddl_free_dec_hw_buffers(ddl);
return status;
}
@@ -880,66 +883,70 @@
ptr = ddl_pmem_alloc(&enc_bufs->mv, buf_size.sz_mv,
DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_enc_free_exit;
}
if (buf_size.sz_col_zero > 0) {
enc_bufs->col_zero.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->col_zero,
buf_size.sz_col_zero, DDL_KILO_BYTE(2));
- if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ if (!ptr)
+ goto fail_enc_free_exit;
}
if (buf_size.sz_md > 0) {
enc_bufs->md.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->md, buf_size.sz_md,
DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_enc_free_exit;
}
if (buf_size.sz_pred > 0) {
enc_bufs->pred.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->pred,
buf_size.sz_pred, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_enc_free_exit;
}
if (buf_size.sz_nbor_info > 0) {
enc_bufs->nbor_info.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->nbor_info,
buf_size.sz_nbor_info, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_enc_free_exit;
}
if (buf_size.sz_acdc_coef > 0) {
enc_bufs->acdc_coef.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->acdc_coef,
buf_size.sz_acdc_coef, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_enc_free_exit;
}
if (buf_size.sz_mb_info > 0) {
enc_bufs->mb_info.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->mb_info,
buf_size.sz_mb_info, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
+ goto fail_enc_free_exit;
}
if (buf_size.sz_context > 0) {
enc_bufs->context.mem_type = DDL_MM_MEM;
ptr = ddl_pmem_alloc(&enc_bufs->context,
buf_size.sz_context, DDL_KILO_BYTE(2));
if (!ptr)
- status = VCD_ERR_ALLOC_FAIL;
- msm_ion_do_cache_op(ddl_context->video_ion_client,
+ goto fail_enc_free_exit;
+ else
+ msm_ion_do_cache_op(
+ ddl_context->video_ion_client,
enc_bufs->context.alloc_handle,
enc_bufs->context.virtual_base_addr,
enc_bufs->context.buffer_size,
ION_IOC_CLEAN_INV_CACHES);
}
- if (status)
- ddl_free_enc_hw_buffers(ddl);
}
return status;
+fail_enc_free_exit:
+ status = VCD_ERR_ALLOC_FAIL;
+ ddl_free_enc_hw_buffers(ddl);
+ return status;
}
void ddl_decoder_chroma_dpb_change(struct ddl_client_context *ddl)
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 a5192b0..363fe53 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -1869,6 +1869,19 @@
input_buf_req = &decoder->actual_input_buf_req;
min_dpb = decoder->min_dpb_num;
y_cb_cr_size = decoder->y_cb_cr_size;
+ if ((decoder->buf_format.buffer_format ==
+ VCD_BUFFER_FORMAT_TILE_4x2) &&
+ (frame_size->height < MDP_MIN_TILE_HEIGHT)) {
+ frame_size->height = MDP_MIN_TILE_HEIGHT;
+ ddl_calculate_stride(frame_size,
+ !decoder->progressive_only);
+ y_cb_cr_size = ddl_get_yuv_buffer_size(
+ frame_size,
+ &decoder->buf_format,
+ (!decoder->progressive_only),
+ decoder->hdr.decoding, NULL);
+ } else
+ y_cb_cr_size = decoder->y_cb_cr_size;
}
memset(output_buf_req, 0,
sizeof(struct vcd_buffer_requirement));
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
index b63bd81..260cd72 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_utils.c
@@ -48,6 +48,9 @@
unsigned long ionflag = 0;
unsigned long flags = 0;
int ret = 0;
+ ion_phys_addr_t phyaddr = 0;
+ size_t len = 0;
+ int rc = 0;
DBG_PMEM("\n%s() IN: Requested alloc size(%u)", __func__, (u32)sz);
if (!addr) {
DDL_MSG_ERROR("\n%s() Invalid Parameters", __func__);
@@ -88,28 +91,42 @@
goto free_ion_alloc;
}
addr->virtual_base_addr = (u8 *) kernel_vaddr;
- ret = ion_map_iommu(ddl_context->video_ion_client,
- addr->alloc_handle,
- VIDEO_DOMAIN,
- VIDEO_MAIN_POOL,
- SZ_4K,
- 0,
- &iova,
- &buffer_size,
- UNCACHED, 0);
- if (ret) {
- DDL_MSG_ERROR("%s():DDL ION ion map iommu failed\n",
- __func__);
- goto unmap_ion_alloc;
+ if (res_trk_check_for_sec_session()) {
+ rc = ion_phys(ddl_context->video_ion_client,
+ addr->alloc_handle, &phyaddr,
+ &len);
+ if (rc || !phyaddr) {
+ DDL_MSG_ERROR(
+ "%s():DDL ION client physical failed\n",
+ __func__);
+ goto unmap_ion_alloc;
+ }
+ addr->alloced_phys_addr = phyaddr;
+ } else {
+ ret = ion_map_iommu(ddl_context->video_ion_client,
+ addr->alloc_handle,
+ VIDEO_DOMAIN,
+ VIDEO_MAIN_POOL,
+ SZ_4K,
+ 0,
+ &iova,
+ &buffer_size,
+ UNCACHED, 0);
+ if (ret) {
+ DDL_MSG_ERROR(
+ "%s():DDL ION ion map iommu failed\n",
+ __func__);
+ goto unmap_ion_alloc;
+ }
+ addr->alloced_phys_addr = (phys_addr_t) iova;
}
- addr->alloced_phys_addr = (phys_addr_t) iova;
if (!addr->alloced_phys_addr) {
DDL_MSG_ERROR("%s():DDL ION client physical failed\n",
__func__);
goto unmap_ion_alloc;
}
addr->mapped_buffer = NULL;
- addr->physical_base_addr = (u8 *) iova;
+ addr->physical_base_addr = (u8 *) addr->alloced_phys_addr;
addr->align_physical_addr = (u8 *) DDL_ALIGN((u32)
addr->physical_base_addr, alignment);
offset = (u32)(addr->align_physical_addr -
@@ -187,10 +204,12 @@
if (!IS_ERR_OR_NULL(addr->alloc_handle)) {
ion_unmap_kernel(ddl_context->video_ion_client,
addr->alloc_handle);
- ion_unmap_iommu(ddl_context->video_ion_client,
+ if (!res_trk_check_for_sec_session()) {
+ ion_unmap_iommu(ddl_context->video_ion_client,
addr->alloc_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
+ }
ion_free(ddl_context->video_ion_client,
addr->alloc_handle);
}
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 e3815e8..e71259a 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
@@ -25,7 +25,7 @@
#include "vidc.h"
#include "vcd_res_tracker.h"
-#define PIL_FW_BASE_ADDR 0xafe00000
+#define PIL_FW_BASE_ADDR 0x9fe00000
#define PIL_FW_SIZE 0x200000
static unsigned int vidc_clk_table[3] = {
@@ -247,10 +247,12 @@
if (addr->physical_base_addr) {
ion_unmap_kernel(resource_context.res_ion_client,
addr->alloc_handle);
- ion_unmap_iommu(resource_context.res_ion_client,
+ if (!res_trk_check_for_sec_session()) {
+ ion_unmap_iommu(resource_context.res_ion_client,
addr->alloc_handle,
VIDEO_DOMAIN,
VIDEO_FIRMWARE_POOL);
+ }
addr->virtual_base_addr = NULL;
addr->physical_base_addr = NULL;
}
@@ -425,7 +427,8 @@
goto bail_out;
}
if (!resource_context.footswitch)
- resource_context.footswitch = regulator_get(NULL, "fs_ved");
+ resource_context.footswitch =
+ regulator_get(resource_context.device, "vdd");
if (IS_ERR(resource_context.footswitch)) {
VCDRES_MSG_ERROR("foot switch get failed\n");
resource_context.footswitch = NULL;
diff --git a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
index fe71dc1..5fa9b09 100644
--- a/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/720p/ddl/vcd_ddl_interrupt_handler.c
@@ -290,6 +290,8 @@
decoder->client_output_buf_req.actual_count
&& decoder->progressive_only)
need_reconfig = false;
+ if (input_vcd_frm->flags & VCD_FRAME_FLAG_EOS)
+ need_reconfig = false;
if ((input_vcd_frm->data_len <= seq_hdr_info.dec_frm_size ||
(input_vcd_frm->flags & VCD_FRAME_FLAG_CODECCONFIG)) &&
(!need_reconfig ||
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index 420fc19..11177b8 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -347,7 +347,7 @@
ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
pmem_fd, kernel_vaddr, buffer_index,
&buff_handle);
- if (ion_flag == CACHED) {
+ if (ion_flag == CACHED && buff_handle) {
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *) kernel_vaddr,
@@ -890,19 +890,35 @@
__func__);
goto import_ion_error;
}
- rc = ion_map_iommu(client_ctx->user_ion_client,
+ if (res_trk_check_for_sec_session()) {
+ rc = ion_phys(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
- VIDEO_DOMAIN, VIDEO_MAIN_POOL,
- SZ_4K, 0, (unsigned long *)&iova,
- (unsigned long *)&buffer_size, UNCACHED, 0);
- if (rc) {
- ERR("%s():get_ION_kernel physical addr fail\n",
- __func__);
- goto ion_map_error;
+ (unsigned long *) (&(vcd_h264_mv_buffer->
+ physical_addr)), &len);
+ if (rc) {
+ ERR("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ goto ion_map_error;
+ }
+ vcd_h264_mv_buffer->client_data = NULL;
+ vcd_h264_mv_buffer->dev_addr = (u8 *)
+ vcd_h264_mv_buffer->physical_addr;
+ } else {
+ rc = ion_map_iommu(client_ctx->user_ion_client,
+ client_ctx->h264_mv_ion_handle,
+ VIDEO_DOMAIN, VIDEO_MAIN_POOL,
+ SZ_4K, 0, (unsigned long *)&iova,
+ (unsigned long *)&buffer_size,
+ UNCACHED, 0);
+ if (rc) {
+ ERR("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ goto ion_map_error;
+ }
+ vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
+ vcd_h264_mv_buffer->client_data = NULL;
+ vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
}
- vcd_h264_mv_buffer->physical_addr = (u8 *) iova;
- vcd_h264_mv_buffer->client_data = NULL;
- vcd_h264_mv_buffer->dev_addr = (u8 *) iova;
}
DBG("Virt: %p, Phys %p, fd: %d", vcd_h264_mv_buffer->
kernel_virtual_addr, vcd_h264_mv_buffer->physical_addr,
@@ -997,10 +1013,12 @@
if (!IS_ERR_OR_NULL(client_ctx->h264_mv_ion_handle)) {
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
- ion_unmap_iommu(client_ctx->user_ion_client,
+ if (!res_trk_check_for_sec_session()) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
+ }
ion_free(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
client_ctx->h264_mv_ion_handle = NULL;
@@ -1252,7 +1270,7 @@
kernel_vaddr,
buffer_index,
&buff_handle);
- if (ion_flag == CACHED) {
+ if (ion_flag == CACHED && buff_handle) {
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *)kernel_vaddr,
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 5542856..1b77b67 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -265,7 +265,7 @@
ion_flag = vidc_get_fd_info(client_ctx, BUFFER_TYPE_OUTPUT,
pmem_fd, kernel_vaddr, buffer_index,
&buff_handle);
- if (ion_flag == CACHED) {
+ if (ion_flag == CACHED && buff_handle) {
msm_ion_do_cache_op(client_ctx->user_ion_client,
buff_handle,
(unsigned long *) kernel_vaddr,
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index ac732c1..bbbe0cf 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -31,6 +31,7 @@
#include <media/msm/vidc_type.h>
#include <media/msm/vcd_api.h>
#include <media/msm/vidc_init.h>
+#include "vcd_res_tracker_api.h"
#include "venc_internal.h"
#if DEBUG
@@ -1687,7 +1688,7 @@
&buff_handle);
if (vcd_input_buffer.data_len > 0) {
- if (ion_flag == CACHED) {
+ if (ion_flag == CACHED && buff_handle) {
msm_ion_do_cache_op(
client_ctx->user_ion_client,
buff_handle,
@@ -1768,6 +1769,8 @@
unsigned long ionflag = 0;
unsigned long iova = 0;
unsigned long buffer_size = 0;
+ size_t ion_len = -1;
+ unsigned long phy_addr;
if (!client_ctx || !venc_recon) {
pr_err("%s() Invalid params", __func__);
@@ -1836,24 +1839,39 @@
__func__);
goto import_ion_error;
}
- rc = ion_map_iommu(client_ctx->user_ion_client,
+ if (res_trk_check_for_sec_session()) {
+ rc = ion_phys(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i],
- VIDEO_DOMAIN,
- VIDEO_MAIN_POOL,
- SZ_4K,
- 0,
- (unsigned long *)&iova,
- (unsigned long *)&buffer_size,
- UNCACHED, 0);
- if (rc) {
- ERR("%s():ION map iommu addr fail\n",
- __func__);
- goto map_ion_error;
+ &phy_addr, &ion_len);
+ if (rc) {
+ ERR("%s():get_ION_kernel physical addr fail\n",
+ __func__);
+ goto map_ion_error;
+ }
+ control->physical_addr = (u8 *) phy_addr;
+ len = (unsigned long) ion_len;
+ control->client_data = NULL;
+ control->dev_addr = (u8 *)control->physical_addr;
+ } else {
+ rc = ion_map_iommu(client_ctx->user_ion_client,
+ client_ctx->recon_buffer_ion_handle[i],
+ VIDEO_DOMAIN,
+ VIDEO_MAIN_POOL,
+ SZ_4K,
+ 0,
+ (unsigned long *)&iova,
+ (unsigned long *)&buffer_size,
+ UNCACHED, 0);
+ if (rc) {
+ ERR("%s():ION map iommu addr fail\n",
+ __func__);
+ goto map_ion_error;
+ }
+ control->physical_addr = (u8 *) iova;
+ len = buffer_size;
+ control->client_data = NULL;
+ control->dev_addr = (u8 *)iova;
}
- control->physical_addr = (u8 *) iova;
- len = buffer_size;
- control->client_data = NULL;
- control->dev_addr = (u8 *)iova;
}
vcd_property_hdr.prop_id = VCD_I_RECON_BUFFERS;
@@ -1922,10 +1940,12 @@
if (client_ctx->recon_buffer_ion_handle[i]) {
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i]);
- ion_unmap_iommu(client_ctx->user_ion_client,
+ if (!res_trk_check_for_sec_session()) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i],
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
+ }
ion_free(client_ctx->user_ion_client,
client_ctx->recon_buffer_ion_handle[i]);
client_ctx->recon_buffer_ion_handle[i] = NULL;
diff --git a/drivers/video/msm/vidc/common/init/vidc_init.c b/drivers/video/msm/vidc/common/init/vidc_init.c
index e641d62..23c990a 100644
--- a/drivers/video/msm/vidc/common/init/vidc_init.c
+++ b/drivers/video/msm/vidc/common/init/vidc_init.c
@@ -432,11 +432,14 @@
ion_unmap_kernel(client_ctx->user_ion_client,
buf_addr_table[i].
buff_ion_handle);
- ion_unmap_iommu(client_ctx->user_ion_client,
+ if (!res_trk_check_for_sec_session()) {
+ ion_unmap_iommu(
+ client_ctx->user_ion_client,
buf_addr_table[i].
buff_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
+ }
ion_free(client_ctx->user_ion_client,
buf_addr_table[i].
buff_ion_handle);
@@ -453,10 +456,12 @@
if (!IS_ERR_OR_NULL(client_ctx->user_ion_client)) {
ion_unmap_kernel(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
- ion_unmap_iommu(client_ctx->user_ion_client,
+ if (!res_trk_check_for_sec_session()) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
+ }
ion_free(client_ctx->user_ion_client,
client_ctx->h264_mv_ion_handle);
client_ctx->h264_mv_ion_handle = NULL;
@@ -565,6 +570,7 @@
unsigned long iova = 0;
int ret = 0;
unsigned long buffer_size = 0;
+ size_t ion_len;
if (!client_ctx || !length)
return false;
@@ -646,23 +652,41 @@
*kernel_vaddr = (unsigned long)NULL;
goto ion_free_error;
}
- ret = ion_map_iommu(client_ctx->user_ion_client,
+ if (res_trk_check_for_sec_session()) {
+ if (ion_phys(client_ctx->user_ion_client,
buff_ion_handle,
- VIDEO_DOMAIN,
- VIDEO_MAIN_POOL,
- SZ_8K,
- length,
- (unsigned long *) &iova,
- (unsigned long *) &buffer_size,
- UNCACHED, ION_IOMMU_UNMAP_DELAYED);
- if (ret) {
- ERR("%s():ION iommu map fail\n",
- __func__);
- goto ion_map_error;
+ &phys_addr, &ion_len)) {
+ ERR("%s():ION physical addr fail\n",
+ __func__);
+ goto ion_map_error;
+ }
+ len = (unsigned long) ion_len;
+ buf_addr_table[*num_of_buffers].client_data =
+ NULL;
+ buf_addr_table[*num_of_buffers].dev_addr =
+ phys_addr;
+ } else {
+ ret = ion_map_iommu(client_ctx->user_ion_client,
+ buff_ion_handle,
+ VIDEO_DOMAIN,
+ VIDEO_MAIN_POOL,
+ SZ_8K,
+ length,
+ (unsigned long *) &iova,
+ (unsigned long *) &buffer_size,
+ UNCACHED,
+ ION_IOMMU_UNMAP_DELAYED);
+ if (ret) {
+ ERR("%s():ION iommu map fail\n",
+ __func__);
+ goto ion_map_error;
+ }
+ phys_addr = iova;
+ buf_addr_table[*num_of_buffers].client_data =
+ NULL;
+ buf_addr_table[*num_of_buffers].dev_addr =
+ iova;
}
- phys_addr = iova;
- buf_addr_table[*num_of_buffers].client_data = NULL;
- buf_addr_table[*num_of_buffers].dev_addr = iova;
}
phys_addr += buffer_addr_offset;
(*kernel_vaddr) += buffer_addr_offset;
@@ -809,10 +833,12 @@
if (buf_addr_table[i].buff_ion_handle) {
ion_unmap_kernel(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle);
- ion_unmap_iommu(client_ctx->user_ion_client,
+ if (!res_trk_check_for_sec_session()) {
+ ion_unmap_iommu(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle,
VIDEO_DOMAIN,
VIDEO_MAIN_POOL);
+ }
ion_free(client_ctx->user_ion_client,
buf_addr_table[i].buff_ion_handle);
buf_addr_table[i].buff_ion_handle = NULL;
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 9576387..49d885c 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_device_sm.c
@@ -954,6 +954,9 @@
u32 rc = VCD_S_SUCCESS;
u32 client_inited = false;
u32 fail_all_open = false;
+ struct ddl_context *ddl_context;
+
+ ddl_context = ddl_get_context();
VCD_MSG_LOW("vcd_dev_cb_in_initing:");
@@ -1027,6 +1030,8 @@
tmp_client = client;
client = client->next;
+ if (tmp_client == dev_ctxt->cctxt_list_head)
+ fail_all_open = true;
vcd_destroy_client_context(tmp_client);
}
@@ -1035,6 +1040,10 @@
if (!client_inited || fail_all_open) {
VCD_MSG_ERROR("All client open requests failed");
+ DDL_IDLE(ddl_context);
+
+ vcd_handle_device_init_failed(drv_ctxt,
+ DEVICE_STATE_EVENT_NUMBER(close));
dev_ctxt->pending_cmd = VCD_CMD_DEVICE_TERM;
} else {
if (vcd_power_event(dev_ctxt, NULL,
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index f078f3a..7f963e6 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -5,6 +5,8 @@
* & Ralph Metzler <ralph@convergence.de>
* for convergence integrated media GmbH
*
+ * 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 Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
@@ -119,6 +121,29 @@
__u32 flags;
};
+struct dmx_buffer_status {
+ /* size of buffer in bytes */
+ unsigned int size;
+
+ /* fullness of buffer in bytes */
+ unsigned int fullness;
+
+ /*
+ * How many bytes are free
+ * It's the same as: size-fullness-1
+ */
+ unsigned int free_bytes;
+
+ /* read pointer offset in bytes */
+ unsigned int read_offset;
+
+ /* write pointer offset in bytes */
+ unsigned int write_offset;
+
+ /* non-zero if data error occured */
+ int error;
+};
+
typedef struct dmx_caps {
__u32 caps;
int num_decoders;
@@ -135,6 +160,34 @@
DMX_SOURCE_DVR3
} dmx_source_t;
+enum dmx_tsp_format_t {
+ DMX_TSP_FORMAT_188 = 0,
+ DMX_TSP_FORMAT_192_TAIL,
+ DMX_TSP_FORMAT_192_HEAD,
+ DMX_TSP_FORMAT_204,
+};
+
+enum dmx_playback_mode_t {
+ /*
+ * In push mode, if one of output buffers
+ * is full, the buffer would overflow
+ * and demux continue processing incoming stream.
+ * This is the default mode. When playing from frontend,
+ * this is the only mode that is allowed.
+ */
+ DMX_PB_MODE_PUSH = 0,
+
+ /*
+ * In pull mode, if one of output buffers
+ * is full, demux stalls waiting for free space,
+ * this would cause DVR input buffer fullness
+ * to accumulate.
+ * This mode is possible only when playing
+ * from DVR.
+ */
+ DMX_PB_MODE_PULL,
+};
+
struct dmx_stc {
unsigned int num; /* input : which STC? 0..N */
unsigned int base; /* output: divisor for stc to get 90 kHz clock */
@@ -153,5 +206,12 @@
#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc)
#define DMX_ADD_PID _IOW('o', 51, __u16)
#define DMX_REMOVE_PID _IOW('o', 52, __u16)
+#define DMX_SET_TS_PACKET_FORMAT _IOW('o', 53, enum dmx_tsp_format_t)
+#define DMX_SET_TS_OUT_FORMAT _IOW('o', 54, enum dmx_tsp_format_t)
+#define DMX_SET_DECODER_BUFFER_SIZE _IO('o', 55)
+#define DMX_GET_BUFFER_STATUS _IOR('o', 56, struct dmx_buffer_status)
+#define DMX_RELEASE_DATA _IO('o', 57)
+#define DMX_FEED_DATA _IO('o', 58)
+#define DMX_SET_PLAYBACK_MODE _IOW('o', 59, enum dmx_playback_mode_t)
#endif /*_DVBDMX_H_*/
diff --git a/include/linux/fmem.h b/include/linux/fmem.h
index 44b7005..e4fa82c 100644
--- a/include/linux/fmem.h
+++ b/include/linux/fmem.h
@@ -22,6 +22,7 @@
unsigned long size;
unsigned long reserved_size_low;
unsigned long reserved_size_high;
+ unsigned long align;
};
struct fmem_data {
diff --git a/include/linux/genlock.h b/include/linux/genlock.h
index 9351a15..587c49d 100644
--- a/include/linux/genlock.h
+++ b/include/linux/genlock.h
@@ -21,7 +21,8 @@
#define GENLOCK_WRLOCK 1
#define GENLOCK_RDLOCK 2
-#define GENLOCK_NOBLOCK (1 << 0)
+#define GENLOCK_NOBLOCK (1 << 0)
+#define GENLOCK_WRITE_TO_READ (1 << 1)
struct genlock_lock {
int fd;
@@ -37,6 +38,8 @@
struct genlock_lock)
#define GENLOCK_IOC_ATTACH _IOW(GENLOCK_IOC_MAGIC, 2, \
struct genlock_lock)
+
+/* Deprecated */
#define GENLOCK_IOC_LOCK _IOW(GENLOCK_IOC_MAGIC, 3, \
struct genlock_lock)
@@ -44,4 +47,6 @@
#define GENLOCK_IOC_RELEASE _IO(GENLOCK_IOC_MAGIC, 4)
#define GENLOCK_IOC_WAIT _IOW(GENLOCK_IOC_MAGIC, 5, \
struct genlock_lock)
+#define GENLOCK_IOC_DREADLOCK _IOW(GENLOCK_IOC_MAGIC, 6, \
+ struct genlock_lock)
#endif
diff --git a/include/linux/ion.h b/include/linux/ion.h
index ae49bce..b5495a0 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -177,6 +177,8 @@
* or not.
* @fixed_position If nonzero, position in the fixed area.
* @virt_addr: Virtual address used when using fmem.
+ * @iommu_map_all: Indicates whether we should map whole heap into IOMMU.
+ * @iommu_2x_map_domain: Indicates the domain to use for overmapping.
* @request_region: function to be called when the number of allocations
* goes from 0 -> 1
* @release_region: function to be called when the number of allocations
@@ -192,6 +194,8 @@
int reusable;
int mem_is_fmem;
enum ion_fixed_position fixed_position;
+ int iommu_map_all;
+ int iommu_2x_map_domain;
ion_virt_addr_t *virt_addr;
int (*request_region)(void *);
int (*release_region)(void *);
diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index 0104abc..7169870 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -43,7 +43,7 @@
if ((cond) || (timeout_us && time_after(jiffies, timeout))) \
break; \
if (sleep_us) \
- usleep_range(1, sleep_us); \
+ usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
} \
(cond) ? 0 : -ETIMEDOUT; \
})
diff --git a/include/linux/mfd/pm8xxx/gpio.h b/include/linux/mfd/pm8xxx/gpio.h
index 9918620..ccd9c10 100644
--- a/include/linux/mfd/pm8xxx/gpio.h
+++ b/include/linux/mfd/pm8xxx/gpio.h
@@ -78,6 +78,16 @@
#define PM8038_GPIO_VIN_L3 5
#define PM8038_GPIO_VIN_L17 6
+/* vin_sel: Voltage Input Select on PM8018*/
+#define PM8018_GPIO_VIN_L4 0
+#define PM8018_GPIO_VIN_L14 1
+#define PM8018_GPIO_VIN_S3 2
+#define PM8018_GPIO_VIN_L6 3
+#define PM8018_GPIO_VIN_L2 4
+#define PM8018_GPIO_VIN_L5 5
+#define PM8018_GPIO_VIN_L8 6
+#define PM8018_GPIO_VIN_VPH 7
+
/* out_strength */
#define PM_GPIO_STRENGTH_NO 0
#define PM_GPIO_STRENGTH_HIGH 1
diff --git a/include/linux/mfd/pm8xxx/misc.h b/include/linux/mfd/pm8xxx/misc.h
index 77683ce..c4b0ea4 100644
--- a/include/linux/mfd/pm8xxx/misc.h
+++ b/include/linux/mfd/pm8xxx/misc.h
@@ -89,6 +89,12 @@
XO_DIV_64,
};
+enum pm8xxx_hsed_bias {
+ PM8XXX_HSED_BIAS0,
+ PM8XXX_HSED_BIAS1,
+ PM8XXX_HSED_BIAS2,
+};
+
#if defined(CONFIG_MFD_PM8XXX_MISC) || defined(CONFIG_MFD_PM8XXX_MISC_MODULE)
/**
@@ -210,6 +216,14 @@
enum pm8xxx_aux_clk_div divider,
bool enable);
+/**
+ * pm8xxx_hsed_bias_control - Control the HSED_BIAS signal
+ * @bias: the bias line to be controlled (of the 3)
+ * @enable: enable/disable the bias line
+ *
+ * RETURNS: an appropriate -ERRNO error value on error, or zero for success.
+ */
+int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias, bool enable);
#else
static inline int pm8xxx_reset_pwr_off(int reset)
@@ -259,6 +273,11 @@
{
return -ENODEV;
}
+static inline int pm8xxx_hsed_bias_control(enum pm8xxx_hsed_bias bias,
+ bool enable)
+{
+ return -ENODEV;
+}
#endif
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 8a0c4d5..aa808dc 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -228,6 +228,7 @@
struct sdio_cccr cccr; /* common card info */
struct sdio_cis cis; /* common tuple info */
struct sdio_func *sdio_func[SDIO_MAX_FUNCS]; /* SDIO functions (devices) */
+ struct sdio_func *sdio_single_irq; /* SDIO function when only one IRQ active */
unsigned num_info; /* number of info strings */
const char **info; /* info strings */
struct sdio_func_tuple *tuples; /* unknown common tuples */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index a2ee306..c9a17de 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -317,6 +317,7 @@
unsigned int sdio_irqs;
struct task_struct *sdio_irq_thread;
+ bool sdio_irq_pending;
atomic_t sdio_irq_thread_abort;
mmc_pm_flag_t pm_flags; /* requested pm features */
@@ -411,6 +412,7 @@
static inline void mmc_signal_sdio_irq(struct mmc_host *host)
{
host->ops->enable_sdio_irq(host, 0);
+ host->sdio_irq_pending = true;
wake_up_process(host->sdio_irq_thread);
}
diff --git a/include/linux/msm_rotator.h b/include/linux/msm_rotator.h
index 02ffd59..0f15a8b 100644
--- a/include/linux/msm_rotator.h
+++ b/include/linux/msm_rotator.h
@@ -52,7 +52,6 @@
unsigned int number_of_clocks;
unsigned int hardware_version_number;
struct msm_rot_clocks *rotator_clks;
- const char *regulator_name;
#ifdef CONFIG_MSM_BUS_SCALING
struct msm_bus_scale_pdata *bus_scale_table;
#endif
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index 6598c04..aec8025 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -46,8 +46,9 @@
return container_of(gc, struct of_mm_gpio_chip, gc);
}
-extern int of_get_gpio_flags(struct device_node *np, int index,
- enum of_gpio_flags *flags);
+extern int of_get_named_gpio_flags(struct device_node *np,
+ const char *list_name, int index, enum of_gpio_flags *flags);
+
extern unsigned int of_gpio_count(struct device_node *np);
extern int of_mm_gpiochip_add(struct device_node *np,
@@ -60,8 +61,8 @@
#else /* CONFIG_OF_GPIO */
/* Drivers may not strictly depend on the GPIO support, so let them link. */
-static inline int of_get_gpio_flags(struct device_node *np, int index,
- enum of_gpio_flags *flags)
+static inline int of_get_named_gpio_flags(struct device_node *np,
+ const char *list_name, int index, enum of_gpio_flags *flags)
{
return -ENOSYS;
}
@@ -77,7 +78,38 @@
#endif /* CONFIG_OF_GPIO */
/**
- * of_get_gpio - Get a GPIO number to use with GPIO API
+ * of_get_gpio_flags() - Get a GPIO number and flags to use with GPIO API
+ * @np: device node to get GPIO from
+ * @index: index of the GPIO
+ * @flags: a flags pointer to fill in
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition. If @flags is not NULL the function also fills
+ * in flags for the GPIO.
+ */
+static inline int of_get_gpio_flags(struct device_node *np, int index,
+ enum of_gpio_flags *flags)
+{
+ return of_get_named_gpio_flags(np, "gpios", index, flags);
+}
+
+/**
+ * of_get_named_gpio() - Get a GPIO number to use with GPIO API
+ * @np: device node to get GPIO from
+ * @propname: Name of property containing gpio specifier(s)
+ * @index: index of the GPIO
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition.
+ */
+static inline int of_get_named_gpio(struct device_node *np,
+ const char *propname, int index)
+{
+ return of_get_named_gpio_flags(np, propname, index, NULL);
+}
+
+/**
+ * of_get_gpio() - Get a GPIO number to use with GPIO API
* @np: device node to get GPIO from
* @index: index of the GPIO
*
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index b920a72..f13b52b 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1370,6 +1370,16 @@
}
#endif /* NET_SKBUFF_DATA_USES_OFFSET */
+static inline void skb_mac_header_rebuild(struct sk_buff *skb)
+{
+ if (skb_mac_header_was_set(skb)) {
+ const unsigned char *old_mac = skb_mac_header(skb);
+
+ skb_set_mac_header(skb, -skb->mac_len);
+ memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+ }
+}
+
static inline int skb_checksum_start_offset(const struct sk_buff *skb)
{
return skb->csum_start - skb_headroom(skb);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 14d49eb..b53d9dd 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -159,19 +159,6 @@
};
/**
- * SPS Pipes direction.
- *
- * USB_TO_PEER_PERIPHERAL USB (as Producer) to other
- * peer peripheral.
- * PEER_PERIPHERAL_TO_USB Other Peripheral to
- * USB (as consumer).
- */
-enum usb_bam_pipe_dir {
- USB_TO_PEER_PERIPHERAL,
- PEER_PERIPHERAL_TO_USB,
-};
-
-/**
* struct msm_otg_platform_data - platform device data
* for msm_otg driver.
* @phy_init_seq: PHY configuration sequence. val, reg pairs
@@ -355,6 +342,10 @@
unsigned int dock_connect_irq;
};
+struct msm_hsic_peripheral_platform_data {
+ bool keep_core_clk_on_suspend_workaround;
+};
+
struct usb_bam_pipe_connect {
u32 src_phy_addr;
int src_pipe_index;
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 147b068..a3b45c9 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -656,6 +656,7 @@
/* Cache handling flags */
#define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800
#define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000
+#define V4L2_BUF_FLAG_EOS 0x2000
/*
* O V E R L A Y P R E V I E W
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index bf02b84..3f647dc 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -187,6 +187,9 @@
#define MSM_CAM_IOCTL_GET_ACTUATOR_INFO \
_IOW(MSM_CAM_IOCTL_MAGIC, 52, struct msm_actuator_cfg_data *)
+#define MSM_CAM_IOCTL_EEPROM_IO_CFG \
+ _IOW(MSM_CAM_IOCTL_MAGIC, 53, struct msm_eeprom_cfg_data *)
+
struct msm_mctl_pp_cmd {
int32_t id;
uint16_t length;
@@ -778,18 +781,19 @@
#define CFG_GET_3D_CALI_DATA 30
#define CFG_GET_CALIB_DATA 31
#define CFG_GET_OUTPUT_INFO 32
-#define CFG_GET_EEPROM_DATA 33
-#define CFG_SET_ACTUATOR_INFO 34
-#define CFG_GET_ACTUATOR_INFO 35
+#define CFG_GET_EEPROM_INFO 33
+#define CFG_GET_EEPROM_DATA 34
+#define CFG_SET_ACTUATOR_INFO 35
+#define CFG_GET_ACTUATOR_INFO 36
/* TBD: QRD */
-#define CFG_SET_SATURATION 36
-#define CFG_SET_SHARPNESS 37
-#define CFG_SET_TOUCHAEC 38
-#define CFG_SET_AUTO_FOCUS 39
-#define CFG_SET_AUTOFLASH 40
-#define CFG_SET_EXPOSURE_COMPENSATION 41
-#define CFG_SET_ISO 42
-#define CFG_MAX 43
+#define CFG_SET_SATURATION 37
+#define CFG_SET_SHARPNESS 38
+#define CFG_SET_TOUCHAEC 39
+#define CFG_SET_AUTO_FOCUS 40
+#define CFG_SET_AUTOFLASH 41
+#define CFG_SET_EXPOSURE_COMPENSATION 42
+#define CFG_SET_ISO 43
+#define CFG_MAX 44
#define MOVE_NEAR 0
@@ -1076,11 +1080,6 @@
uint16_t num_info;
};
-struct sensor_eeprom_data_t {
- void *eeprom_data;
- uint16_t index;
-};
-
struct mirror_flip {
int32_t x_mirror;
int32_t y_flip;
@@ -1091,6 +1090,11 @@
uint32_t y;
};
+struct msm_eeprom_data_t {
+ void *eeprom_data;
+ uint16_t index;
+};
+
struct sensor_cfg_data {
int cfgtype;
int mode;
@@ -1116,7 +1120,7 @@
struct sensor_3d_exp_cfg sensor_3d_exp;
struct sensor_calib_data calib_info;
struct sensor_output_info_t output_info;
- struct sensor_eeprom_data_t eeprom_data;
+ struct msm_eeprom_data_t eeprom_data;
/* QRD */
uint16_t antibanding;
uint8_t contrast;
@@ -1250,6 +1254,60 @@
} cfg;
};
+struct msm_eeprom_support {
+ uint16_t is_supported;
+ uint16_t size;
+ uint16_t index;
+ uint16_t qvalue;
+};
+
+struct msm_calib_wb {
+ uint16_t r_over_g;
+ uint16_t b_over_g;
+ uint16_t gr_over_gb;
+};
+
+struct msm_calib_af {
+ uint16_t macro_dac;
+ uint16_t inf_dac;
+ uint16_t start_dac;
+};
+
+struct msm_calib_lsc {
+ uint16_t r_gain[221];
+ uint16_t b_gain[221];
+ uint16_t gr_gain[221];
+ uint16_t gb_gain[221];
+};
+
+struct pixel_t {
+ int x;
+ int y;
+};
+
+struct msm_calib_dpc {
+ uint16_t validcount;
+ struct pixel_t snapshot_coord[128];
+ struct pixel_t preview_coord[128];
+ struct pixel_t video_coord[128];
+};
+
+struct msm_camera_eeprom_info_t {
+ struct msm_eeprom_support af;
+ struct msm_eeprom_support wb;
+ struct msm_eeprom_support lsc;
+ struct msm_eeprom_support dpc;
+};
+
+struct msm_eeprom_cfg_data {
+ int cfgtype;
+ uint8_t is_eeprom_supported;
+ union {
+ struct msm_eeprom_data_t get_data;
+ struct msm_camera_eeprom_info_t get_info;
+ } cfg;
+};
+
struct sensor_large_data {
int cfgtype;
union {
diff --git a/include/media/msm_vidc.h b/include/media/msm_vidc.h
new file mode 100644
index 0000000..b883ffa
--- /dev/null
+++ b/include/media/msm_vidc.h
@@ -0,0 +1,47 @@
+/* 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_VIDC_H_
+#define _MSM_VIDC_H_
+
+#include <linux/videodev2.h>
+#include <linux/poll.h>
+
+enum core_id {
+ MSM_VIDC_CORE_0 = 0,
+ MSM_VIDC_CORES_MAX,
+};
+
+enum session_type {
+ MSM_VIDC_ENCODER = 0,
+ MSM_VIDC_DECODER,
+ MSM_VIDC_MAX_DEVICES,
+};
+
+void *msm_vidc_open(int core_id, int session_type);
+int msm_vidc_close(void *instance);
+int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
+int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
+int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
+int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
+int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
+int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
+int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
+int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
+int msm_vidc_poll(void *instance, struct file *filp,
+ struct poll_table_struct *pt);
+#endif
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 2114287..d906c9f 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -143,6 +143,7 @@
#define RC_MAP_TREKSTOR "rc-trekstor"
#define RC_MAP_TT_1500 "rc-tt-1500"
#define RC_MAP_TWINHAN_VP1027_DVBS "rc-twinhan1027"
+#define RC_MAP_UE_RF4CE "rc-ue-rf4ce"
#define RC_MAP_VIDEOMATE_M1F "rc-videomate-m1f"
#define RC_MAP_VIDEOMATE_S350 "rc-videomate-s350"
#define RC_MAP_VIDEOMATE_TV_PVR "rc-videomate-tv-pvr"
diff --git a/include/media/user-rc-input.h b/include/media/user-rc-input.h
new file mode 100644
index 0000000..e58e40f
--- /dev/null
+++ b/include/media/user-rc-input.h
@@ -0,0 +1,21 @@
+/* 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 __USER_RC_INPUT_H__
+#define __USER_RC_INPUT_H__
+
+#define USER_CONTROL_PRESSED 0x01
+#define USER_CONTROL_REPEATED 0x02
+#define USER_CONTROL_RELEASED 0x03
+
+#endif /* __USER_RC_INPUT_H__ */
+
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index 0007fd8..134d044 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -352,8 +352,53 @@
u16 reserved;
} __attribute__ ((packed));
+/* Parameter ID used to configure and enable/disable the loopback path. The
+ * difference with respect to the existing API, AFE_PORT_CMD_LOOPBACK, is that
+ * it allows Rx port to be configured as source port in loopback path. Port-id
+ * in AFE_PORT_CMD_SET_PARAM cmd is the source port whcih can be Tx or Rx port.
+ * In addition, we can configure the type of routing mode to handle different
+ * use cases.
+*/
+enum {
+ /* Regular loopback from source to destination port */
+ LB_MODE_DEFAULT = 1,
+ /* Sidetone feed from Tx source to Rx destination port */
+ LB_MODE_SIDETONE,
+ /* Echo canceller reference, voice + audio + DTMF */
+ LB_MODE_EC_REF_VOICE_AUDIO,
+ /* Echo canceller reference, voice alone */
+ LB_MODE_EC_REF_VOICE
+};
+
+#define AFE_PARAM_ID_LOOPBACK_CONFIG 0x0001020B
+#define AFE_API_VERSION_LOOPBACK_CONFIG 0x1
+struct afe_param_loopback_cfg {
+ /* Minor version used for tracking the version of the configuration
+ * interface.
+ */
+ uint32_t loopback_cfg_minor_version;
+
+ /* Destination Port Id. */
+ uint16_t dst_port_id;
+
+ /* Specifies data path type from src to dest port. Supported values:
+ * LB_MODE_DEFAULT
+ * LB_MODE_SIDETONE
+ * LB_MODE_EC_REF_VOICE_AUDIO
+ * LB_MODE_EC_REF_VOICE
+ */
+ uint16_t routing_mode;
+
+ /* Specifies whether to enable (1) or disable (0) an AFE loopback. */
+ uint16_t enable;
+
+ /* Reserved for 32-bit alignment. This field must be set to 0. */
+ uint16_t reserved;
+} __packed;
#define AFE_MODULE_ID_PORT_INFO 0x00010200
+/* Module ID for the loopback-related parameters. */
+#define AFE_MODULE_LOOPBACK 0x00010205
struct afe_param_payload {
u32 module_id;
u32 param_id;
@@ -364,6 +409,7 @@
struct afe_param_sampling_rate sampling_rate;
struct afe_param_channels channels;
struct afe_param_loopback_gain loopback_gain;
+ struct afe_param_loopback_cfg loopback_cfg;
} __attribute__((packed)) param;
} __attribute__ ((packed));
@@ -770,7 +816,10 @@
#define PCM_FORMAT_MAX_NUM_CHANNEL 8
-
+/* Maximum number of channels supported
+ * in ASM_ENCDEC_DEC_CHAN_MAP command
+ */
+#define MAX_CHAN_MAP_CHANNELS 16
/*
* Multiple-channel PCM decoder format block structure used in the
* #ASM_STREAM_CMD_OPEN_WRITE command.
@@ -980,6 +1029,32 @@
u16 sce_right;
};
+struct asm_dec_chan_map {
+ u32 num_channels; /* Number of decoder output
+ * channels. A value of 0
+ * indicates native channel
+ * mapping, which is valid
+ * only for NT mode. This
+ * means the output of the
+ * decoder is to be preserved
+ * as is.
+ */
+
+ u8 channel_mapping[MAX_CHAN_MAP_CHANNELS];/* Channel array of size
+ * num_channels. It can grow
+ * till MAX_CHAN_MAP_CHANNELS.
+ * Channel[i] mapping
+ * describes channel I inside
+ * the decoder output buffer.
+ * Valid channel mapping
+ * values are to be present at
+ * the beginning of the array.
+ * All remaining elements of
+ * the array are to be filled
+ * with PCM_CHANNEL_NULL.
+ */
+};
+
struct asm_encode_cfg_blk {
u32 frames_per_buf;
u32 format_id;
@@ -1132,6 +1207,14 @@
struct asm_dual_mono channel_map;
} __packed;
+#define ASM_ENCDEC_DEC_CHAN_MAP 0x00010D82
+struct asm_stream_cmd_encdec_channelmap {
+ struct apr_hdr hdr;
+ u32 param_id;
+ u32 param_size;
+ struct asm_dec_chan_map chan_map;
+} __packed;
+
#define ASM_STREAM _CMD_ADJUST_SAMPLES 0x00010C0A
struct asm_stream_cmd_adjust_samples{
struct apr_hdr hdr;
diff --git a/include/sound/msm-dai-q6.h b/include/sound/msm-dai-q6.h
index 89a6a47..6328256 100644
--- a/include/sound/msm-dai-q6.h
+++ b/include/sound/msm-dai-q6.h
@@ -32,8 +32,8 @@
int pcm_clk_rate;
};
-struct msm_mi2s_data {
- u32 capability; /* RX or TX */
- u16 sd_lines;
+struct msm_mi2s_pdata {
+ u16 rx_sd_lines;
+ u16 tx_sd_lines;
};
#endif
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
index 9893075..8cdcc18 100644
--- a/include/sound/q6afe.h
+++ b/include/sound/q6afe.h
@@ -74,6 +74,7 @@
int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
int afe_close(int port_id);
int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode);
int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
int afe_loopback_gain(u16 port_id, u16 volume);
int afe_validate_port(u16 port_id);
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index aec4171..968d46e 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -247,6 +247,9 @@
int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
uint16_t sce_left, uint16_t sce_right);
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+ uint32_t num_channels);
+
int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
uint16_t min_rate, uint16_t max_rate,
uint16_t reduced_rate_level, uint16_t rate_modulation_cmd);
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index df80c42..f4ceeea 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -374,13 +374,11 @@
{
struct amp_mgr *mgr;
- read_lock(&_mgr_list_lock);
list_for_each_entry(mgr, &_mgr_list, list) {
if (mgr->discovered)
send_a2mp_cl(mgr, next_ident(mgr),
A2MP_CHANGE_NOTIFY, 0, NULL);
}
- read_unlock(&_mgr_list_lock);
}
static inline int discover_req(struct amp_mgr *mgr, struct sk_buff *skb)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9f9f17d..a7b95d3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -3365,6 +3365,7 @@
break;
case L2CAP_MODE_STREAMING:
+ l2cap_setup_txwin(pi);
rfc.txwin_size = 0;
rfc.max_transmit = 0;
rfc.retrans_timeout = 0;
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
index 6341818..e3db3f9 100644
--- a/net/ipv4/xfrm4_mode_beet.c
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -110,10 +110,7 @@
skb_push(skb, sizeof(*iph));
skb_reset_network_header(skb);
-
- memmove(skb->data - skb->mac_len, skb_mac_header(skb),
- skb->mac_len);
- skb_set_mac_header(skb, -skb->mac_len);
+ skb_mac_header_rebuild(skb);
xfrm4_beet_make_header(skb);
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c
index 534972e..ed4bf11 100644
--- a/net/ipv4/xfrm4_mode_tunnel.c
+++ b/net/ipv4/xfrm4_mode_tunnel.c
@@ -66,7 +66,6 @@
static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
{
- const unsigned char *old_mac;
int err = -EINVAL;
if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP)
@@ -84,10 +83,9 @@
if (!(x->props.flags & XFRM_STATE_NOECN))
ipip_ecn_decapsulate(skb);
- old_mac = skb_mac_header(skb);
- skb_set_mac_header(skb, -skb->mac_len);
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
skb_reset_network_header(skb);
+ skb_mac_header_rebuild(skb);
+
err = 0;
out:
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index 3437d7d..f37cba9 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -80,7 +80,6 @@
static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct ipv6hdr *ip6h;
- const unsigned char *old_mac;
int size = sizeof(struct ipv6hdr);
int err;
@@ -90,10 +89,7 @@
__skb_push(skb, size);
skb_reset_network_header(skb);
-
- old_mac = skb_mac_header(skb);
- skb_set_mac_header(skb, -skb->mac_len);
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
+ skb_mac_header_rebuild(skb);
xfrm6_beet_make_header(skb);
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 4d6edff..23ecd68 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -63,7 +63,6 @@
static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
{
int err = -EINVAL;
- const unsigned char *old_mac;
if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6)
goto out;
@@ -80,10 +79,9 @@
if (!(x->props.flags & XFRM_STATE_NOECN))
ipip6_ecn_decapsulate(skb);
- old_mac = skb_mac_header(skb);
- skb_set_mac_header(skb, -skb->mac_len);
- memmove(skb_mac_header(skb), old_mac, skb->mac_len);
skb_reset_network_header(skb);
+ skb_mac_header_rebuild(skb);
+
err = 0;
out:
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index d3e509e..94dd695 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -824,7 +824,7 @@
#define ALL_INIT_DATA_SECTIONS \
".init.setup$", ".init.rodata$", \
- ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$" \
+ ".devinit.rodata$", ".cpuinit.rodata$", ".meminit.rodata$", \
".init.data$", ".devinit.data$", ".cpuinit.data$", ".meminit.data$"
#define ALL_EXIT_DATA_SECTIONS \
".exit.data$", ".devexit.data$", ".cpuexit.data$", ".memexit.data$"
@@ -1469,6 +1469,13 @@
return 0;
}
+#ifndef R_ARM_CALL
+#define R_ARM_CALL 28
+#endif
+#ifndef R_ARM_JUMP24
+#define R_ARM_JUMP24 29
+#endif
+
static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
{
unsigned int r_typ = ELF_R_TYPE(r->r_info);
@@ -1480,6 +1487,8 @@
(elf->symtab_start + ELF_R_SYM(r->r_info));
break;
case R_ARM_PC24:
+ case R_ARM_CALL:
+ case R_ARM_JUMP24:
/* From ARM ABI: ((S + A) | T) - P */
r->r_addend = (int)(long)(elf->hdr +
sechdr->sh_offset +
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 6b590c9..9041bd7 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -31,6 +31,8 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
+#include <linux/kernel.h>
+#include <linux/gpio.h>
#include "wcd9304.h"
#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
@@ -66,6 +68,21 @@
#define SITAR_FAKE_INS_THRESHOLD_MS 2500
#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
+#define SITAR_MBHC_BUTTON_MIN 0x8000
+#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
+
+#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
+#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
+
+#define MBHC_NUM_DCE_PLUG_DETECT 3
+#define SITAR_MBHC_FAKE_INSERT_LOW 10
+#define SITAR_MBHC_FAKE_INSERT_HIGH 80
+#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
+#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
+#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
+#define NUM_ATTEMPTS_TO_REPORT 5
+#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
+#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
@@ -139,6 +156,21 @@
u8 nbounce_wait;
};
+enum sitar_mbhc_plug_type {
+ PLUG_TYPE_INVALID = -1,
+ PLUG_TYPE_NONE,
+ PLUG_TYPE_HEADSET,
+ PLUG_TYPE_HEADPHONE,
+ PLUG_TYPE_HIGH_HPH,
+};
+
+enum sitar_mbhc_state {
+ MBHC_STATE_NONE = -1,
+ MBHC_STATE_POTENTIAL,
+ MBHC_STATE_POTENTIAL_RECOVERY,
+ MBHC_STATE_RELEASE,
+};
+
struct sitar_priv {
struct snd_soc_codec *codec;
u32 mclk_freq;
@@ -167,15 +199,10 @@
void *calibration;
struct mbhc_internal_cal_data mbhc_data;
- struct snd_soc_jack *headset_jack;
- struct snd_soc_jack *button_jack;
-
struct wcd9xxx_pdata *pdata;
u32 anc_slot;
bool no_mic_headset_override;
- /* Delayed work to report long button press */
- struct delayed_work btn0_dwork;
struct mbhc_micbias_regs mbhc_bias_regs;
u8 cfilt_k_value;
@@ -207,6 +234,23 @@
/* num of slim ports required */
struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
+
+ /* 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;
+
+ struct sitar_mbhc_config mbhc_cfg;
+ bool in_gpio_handler;
+ u8 current_plug;
+ bool lpi_enabled;
+ enum sitar_mbhc_state mbhc_state;
+ struct work_struct hs_correct_plug_work;
+ bool hs_detect_work_stop;
+ struct delayed_work mbhc_btn_dwork;
+ unsigned long mbhc_last_resume; /* in jiffies */
};
#ifdef CONFIG_DEBUG_FS
@@ -734,10 +778,6 @@
SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
};
-static const struct snd_kcontrol_new hphl_switch[] = {
- SOC_DAPM_SINGLE("Switch", SITAR_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
-};
-
static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
{
@@ -910,27 +950,41 @@
return 0;
}
-
-static void sitar_codec_disable_button_presses(struct snd_soc_codec *codec)
-{
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
- snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
-}
-
static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ int mbhc_state = sitar->mbhc_state;
+
+ pr_debug("%s: enter\n", __func__);
+ if (!sitar->mbhc_polling_active) {
+ pr_debug("Polling is not active, do not start polling\n");
+ return;
+ }
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
+
+
+ if (!sitar->no_mic_headset_override) {
+ if (mbhc_state == MBHC_STATE_POTENTIAL) {
+ pr_debug("%s recovering MBHC state macine\n", __func__);
+ sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
+ /* set to max button press threshold */
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
+ 0x7F);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
+ 0xFF);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
+ 0x7F);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
+ 0xFF);
+ /* set to max */
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
+ 0x7F);
+ snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
+ 0xFF);
+ }
+ }
snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
- wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
- if (!sitar->no_mic_headset_override) {
- wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_MBHC_POTENTIAL);
- wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_MBHC_RELEASE);
- } else {
- sitar_codec_disable_button_presses(codec);
- }
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
@@ -940,14 +994,15 @@
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
- if (!sitar->no_mic_headset_override) {
- wcd9xxx_disable_irq(codec->control_data,
- SITAR_IRQ_MBHC_POTENTIAL);
- wcd9xxx_disable_irq(codec->control_data,
- SITAR_IRQ_MBHC_RELEASE);
+ pr_debug("%s: enter\n", __func__);
+ if (!sitar->mbhc_polling_active) {
+ pr_debug("polling not active, nothing to pause\n");
+ return;
}
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
+ pr_debug("%s: leave\n", __func__);
+
}
static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
@@ -966,6 +1021,7 @@
sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
if (cur_mode_val != reg_mode_val) {
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
if (sitar->mbhc_polling_active) {
sitar_codec_pause_hs_polling(codec);
mbhc_was_polling = true;
@@ -974,6 +1030,7 @@
sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
if (mbhc_was_polling)
sitar_codec_start_hs_polling(codec);
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
cur_mode_val, reg_mode_val);
} else {
@@ -1077,10 +1134,10 @@
u8 hph_reg_val = 0;
if (left)
hph_reg_val = snd_soc_read(codec,
- SITAR_A_RX_HPH_L_DAC_CTL);
+ SITAR_A_RX_HPH_L_DAC_CTL);
else
hph_reg_val = snd_soc_read(codec,
- SITAR_A_RX_HPH_R_DAC_CTL);
+ SITAR_A_RX_HPH_R_DAC_CTL);
return (hph_reg_val & 0xC0) ? true : false;
}
@@ -1094,7 +1151,8 @@
switch (vddio_switch) {
case 1:
- if (sitar->mbhc_polling_active) {
+ if (sitar->mbhc_micbias_switched == 0 &&
+ sitar->mbhc_polling_active) {
sitar_codec_pause_hs_polling(codec);
/* Enable Mic Bias switch to VDDIO */
@@ -1176,9 +1234,11 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
/* Decide whether to switch the micbias for MBHC */
- if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
- && sitar->mbhc_micbias_switched)
+ if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
sitar_codec_switch_micbias(codec, 0);
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+ }
snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
@@ -1191,8 +1251,10 @@
case SND_SOC_DAPM_POST_PMU:
if (sitar->mbhc_polling_active &&
sitar->micbias == micb_line) {
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
sitar_codec_pause_hs_polling(codec);
sitar_codec_start_hs_polling(codec);
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
}
break;
case SND_SOC_DAPM_POST_PMD:
@@ -1302,7 +1364,7 @@
}
return 0;
}
-static int sitar_hphr_dac_event(struct snd_soc_dapm_widget *w,
+static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
@@ -1333,18 +1395,22 @@
{
struct snd_soc_codec *codec;
- if (sitar) {
- pr_info("%s: clear ocp status %x\n", __func__, jack_status);
- codec = sitar->codec;
+ if (!sitar) {
+ pr_err("%s: Bad sitar private data\n", __func__);
+ return;
+ }
+
+ pr_info("%s: clear ocp status %x\n", __func__, jack_status);
+ codec = sitar->codec;
+ if (sitar->hph_status & jack_status) {
sitar->hph_status &= ~jack_status;
- if (sitar->headset_jack)
- sitar_snd_soc_jack_report(sitar, sitar->headset_jack,
- sitar->hph_status,
- SITAR_JACK_MASK);
- snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
- 0x00);
- snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
- 0x10);
+ if (sitar->mbhc_cfg.headset_jack)
+ sitar_snd_soc_jack_report(sitar,
+ sitar->mbhc_cfg.headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
/* reset retry counter as PA is turned off signifying
* start of new OCP detection session
*/
@@ -1353,8 +1419,6 @@
else
sitar->hphrocp_cnt = 0;
wcd9xxx_enable_irq(codec->control_data, irq);
- } else {
- pr_err("%s: Bad sitar private data\n", __func__);
}
}
@@ -1385,9 +1449,11 @@
mbhc_micb_ctl_val = snd_soc_read(codec,
sitar->mbhc_bias_regs.ctl_reg);
- if (!(mbhc_micb_ctl_val & 0x80)
- && !sitar->mbhc_micbias_switched)
+ if (!(mbhc_micb_ctl_val & 0x80)) {
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
sitar_codec_switch_micbias(codec, 1);
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+ }
break;
@@ -1413,8 +1479,9 @@
schedule_work(&sitar->hphrocp_work);
}
- if (sitar->mbhc_micbias_switched)
- sitar_codec_switch_micbias(codec, 0);
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+ sitar_codec_switch_micbias(codec, 0);
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
w->name);
@@ -1431,7 +1498,7 @@
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
unsigned int cfilt;
- switch (sitar->micbias) {
+ switch (sitar->mbhc_cfg.micbias) {
case SITAR_MICBIAS1:
cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
@@ -1527,15 +1594,16 @@
SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MIXER("HPHL DAC", SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
- hphl_switch, ARRAY_SIZE(hphl_switch)),
SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
+ sitar_hph_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
- sitar_hphr_dac_event,
+ sitar_hph_dac_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
/* Speaker */
@@ -1708,7 +1776,7 @@
{"HEADPHONE", NULL, "HPHR"},
{"HPHL", NULL, "HPHL DAC"},
- {"HPHL DAC", "Switch", "DAC4 MUX"},
+ {"HPHL DAC", "NULL", "DAC4 MUX"},
{"HPHR", NULL, "HPHR DAC"},
{"HPHR DAC", NULL, "RX3 MIX1"},
@@ -2015,9 +2083,9 @@
static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
{
- if (sitar->mclk_freq == SITAR_MCLK_RATE_12288KHZ)
+ if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
return 0;
- else if (sitar->mclk_freq == SITAR_MCLK_RATE_9600KHZ)
+ else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
return 1;
else {
BUG_ON(1);
@@ -2031,7 +2099,7 @@
struct sitar_mbhc_btn_detect_cfg *btn_det;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
sitar->mbhc_data.v_ins_hu & 0xFF);
@@ -2096,12 +2164,14 @@
substream->name, substream->stream);
}
-int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
+int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
+ if (dapm)
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
if (mclk_enable) {
sitar->mclk_enabled = true;
@@ -2120,6 +2190,8 @@
} else {
if (!sitar->mclk_enabled) {
+ if (dapm)
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
pr_err("Error, MCLK already diabled\n");
return -EINVAL;
}
@@ -2143,6 +2215,8 @@
SITAR_BANDGAP_OFF);
}
}
+ if (dapm)
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
return 0;
}
@@ -2558,13 +2632,25 @@
return bias_value;
}
-static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce)
+static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
+ bool on)
{
- struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
+}
+
+static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+ bool override_bypass, bool noreldetection)
+{
short bias_value;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ if (noreldetection)
+ sitar_turn_onoff_rel_detection(codec, false);
/* Turn on the override */
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
+ if (!override_bypass)
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
if (dce) {
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
@@ -2589,24 +2675,73 @@
snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
}
/* Turn off the override after measuring mic voltage */
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+ if (!override_bypass)
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+
+ if (noreldetection)
+ sitar_turn_onoff_rel_detection(codec, true);
+ wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
return bias_value;
}
+static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
+ bool norel)
+{
+ return __sitar_codec_sta_dce(codec, dce, false, norel);
+}
+
+static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ const struct sitar_mbhc_general_cfg *generic =
+ SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
+
+ if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
+ sitar_codec_enable_config_mode(codec, 1);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
+
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+
+ usleep_range(generic->t_shutdown_plug_rem,
+ generic->t_shutdown_plug_rem);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
+ if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
+ sitar_codec_enable_config_mode(codec, 0);
+
+ snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
+}
+
+static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ sitar_codec_shutdown_hs_removal_detect(codec);
+
+ if (!sitar->mclk_enabled) {
+ sitar_codec_disable_clock_block(codec);
+ sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
+ }
+
+ sitar->mbhc_polling_active = false;
+ sitar->mbhc_state = MBHC_STATE_NONE;
+}
+
+/* called only from interrupt which is under codec_resource_lock acquisition */
static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
short bias_value;
u8 cfilt_mode;
- if (!sitar->calibration) {
+ if (!sitar->mbhc_cfg.calibration) {
pr_err("Error, no sitar calibration\n");
return -ENODEV;
}
- sitar->mbhc_polling_active = true;
-
if (!sitar->mclk_enabled) {
sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
sitar_enable_rx_bias(codec, 1);
@@ -2615,13 +2750,11 @@
snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
- snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
-
/* Make sure CFILT is in fast mode, save current mode */
- cfilt_mode = snd_soc_read(codec,
- sitar->mbhc_bias_regs.cfilt_ctl);
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
- 0x70, 0x00);
+ cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
+
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
@@ -2639,7 +2772,8 @@
sitar_codec_calibrate_hs_polling(codec);
- bias_value = sitar_codec_sta_dce(codec, 0);
+ /* don't flip override */
+ bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
cfilt_mode);
snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
@@ -2647,111 +2781,21 @@
return bias_value;
}
-static int sitar_codec_enable_hs_detect(struct snd_soc_codec *codec,
- int insertion)
+static int sitar_cancel_btn_work(struct sitar_priv *sitar)
{
- struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- int central_bias_enabled = 0;
- const struct sitar_mbhc_general_cfg *generic =
- SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
- const struct sitar_mbhc_plug_detect_cfg *plug_det =
- SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->calibration);
- u8 wg_time;
+ int r = 0;
+ struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
- if (!sitar->calibration) {
- pr_err("Error, no sitar calibration\n");
- return -EINVAL;
+ if (cancel_delayed_work_sync(&sitar->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;
}
-
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0);
-
- if (insertion) {
- /* Make sure mic bias and Mic line schmitt trigger
- * are turned OFF
- */
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
- 0x81, 0x01);
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
- 0x90, 0x00);
- wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
- wg_time += 1;
-
- /* Enable HPH Schmitt Trigger */
- snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x11, 0x11);
- snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x0C,
- plug_det->hph_current << 2);
-
- /* Turn off HPH PAs and DAC's during insertion detection to
- * avoid false insertion interrupts
- */
- if (sitar->mbhc_micbias_switched)
- sitar_codec_switch_micbias(codec, 0);
- snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
- snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
- 0xC0, 0x00);
- snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
- 0xC0, 0x00);
- usleep_range(wg_time * 1000, wg_time * 1000);
-
- /* setup for insetion detection */
- snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x02, 0x02);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
- } else {
- /* Make sure the HPH schmitt trigger is OFF */
- snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12, 0x00);
-
- /* enable the mic line schmitt trigger */
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x60,
- plug_det->mic_current << 5);
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
- 0x80, 0x80);
- usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg,
- 0x10, 0x10);
-
- /* Setup for low power removal detection */
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
- }
-
- if (snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_CTL) & 0x4) {
- if (!(sitar->clock_active)) {
- sitar_codec_enable_config_mode(codec, 1);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
- 0x06, 0);
- usleep_range(generic->t_shutdown_plug_rem,
- generic->t_shutdown_plug_rem);
- sitar_codec_enable_config_mode(codec, 0);
- } else
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL,
- 0x06, 0);
- }
-
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.int_rbias, 0x80, 0);
-
- /* If central bandgap disabled */
- if (!(snd_soc_read(codec, SITAR_A_PIN_CTL_OE1) & 1)) {
- snd_soc_update_bits(codec, SITAR_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, SITAR_A_PIN_CTL_OE0) & 0x80) {
- snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x10, 0);
- snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0x80);
- usleep_range(generic->t_ldoh, generic->t_ldoh);
- snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE0, 0x80, 0);
-
- if (central_bias_enabled)
- snd_soc_update_bits(codec, SITAR_A_PIN_CTL_OE1, 0x1, 0);
- }
-
- wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
- return 0;
+ return r;
}
+
static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
s16 vin_mv)
{
@@ -2783,58 +2827,63 @@
u16 bias_value)
{
struct sitar_priv *sitar;
+ s16 value, z, mb;
s32 mv;
sitar = snd_soc_codec_get_drvdata(codec);
+ value = bias_value;
if (dce) {
- mv = ((s32)bias_value - (s32)sitar->mbhc_data.dce_z) *
- (s32)sitar->mbhc_data.micb_mv /
- (s32)(sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z);
+ z = (sitar->mbhc_data.dce_z);
+ mb = (sitar->mbhc_data.dce_mb);
+ mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
} else {
- mv = ((s32)bias_value - (s32)sitar->mbhc_data.sta_z) *
- (s32)sitar->mbhc_data.micb_mv /
- (s32)(sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z);
+ z = (sitar->mbhc_data.sta_z);
+ mb = (sitar->mbhc_data.sta_mb);
+ mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
}
return mv;
}
-static void btn0_lpress_fn(struct work_struct *work)
+static void btn_lpress_fn(struct work_struct *work)
{
struct delayed_work *delayed_work;
struct sitar_priv *sitar;
short bias_value;
int dce_mv, sta_mv;
- struct sitar *core;
+ struct wcd9xxx *core;
pr_debug("%s:\n", __func__);
delayed_work = to_delayed_work(work);
- sitar = container_of(delayed_work, struct sitar_priv, btn0_dwork);
+ sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
core = dev_get_drvdata(sitar->codec->dev->parent);
if (sitar) {
- if (sitar->button_jack) {
+ if (sitar->mbhc_cfg.button_jack) {
bias_value = sitar_codec_read_sta_result(sitar->codec);
sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
- bias_value);
+ bias_value);
bias_value = sitar_codec_read_dce_result(sitar->codec);
dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
- bias_value);
+ bias_value);
pr_debug("%s: Reporting long button press event"
- " STA: %d, DCE: %d\n", __func__,
- sta_mv, dce_mv);
- sitar_snd_soc_jack_report(sitar, sitar->button_jack,
- SND_JACK_BTN_0,
- SND_JACK_BTN_0);
+ " STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
+ sitar_snd_soc_jack_report(sitar,
+ sitar->mbhc_cfg.button_jack,
+ sitar->buttons_pressed,
+ sitar->buttons_pressed);
}
} else {
pr_err("%s: Bad sitar private data\n", __func__);
}
+ pr_debug("%s: leave\n", __func__);
+ wcd9xxx_unlock_sleep(core);
}
+
void sitar_mbhc_cal(struct snd_soc_codec *codec)
{
struct sitar_priv *sitar;
@@ -2844,24 +2893,29 @@
u32 mclk_rate;
u32 dce_wait, sta_wait;
u8 *n_cic;
+ void *calibration;
sitar = snd_soc_codec_get_drvdata(codec);
+ calibration = sitar->mbhc_cfg.calibration;
+
+ wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ sitar_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 = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
ncic = n_cic[sitar_codec_mclk_index(sitar)];
- nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration)->n_meas;
- navg = SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration)->mbhc_navg;
- mclk_rate = sitar->mclk_freq;
- dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
+ nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
+ navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
+ mclk_rate = sitar->mbhc_cfg.mclk_rate;
+ dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
- sitar->mbhc_data.t_dce = dce_wait;
- sitar->mbhc_data.t_sta = sta_wait;
+ sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
+ sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
/* LDOH and CFILT are already configured during pdata handling.
* Only need to make sure CFILT and bandgap are in Fast mode.
@@ -2876,9 +2930,10 @@
* to perform ADC calibration
*/
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
- sitar->micbias << 5);
+ sitar->mbhc_cfg.micbias << 5);
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
+ snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
/* DCE measurement for 0 volts */
@@ -2925,6 +2980,9 @@
snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
usleep_range(100, 100);
+
+ wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ sitar_turn_onoff_rel_detection(codec, true);
}
void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
@@ -2962,21 +3020,22 @@
int i;
sitar = snd_soc_codec_get_drvdata(codec);
- btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
- plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->calibration);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
+ plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
- if (sitar->mclk_freq == SITAR_MCLK_RATE_12288KHZ) {
+ if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
sitar->mbhc_data.npoll = 9;
sitar->mbhc_data.nbounce_wait = 30;
- } else if (sitar->mclk_freq == SITAR_MCLK_RATE_9600KHZ) {
+ } else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
sitar->mbhc_data.npoll = 7;
sitar->mbhc_data.nbounce_wait = 23;
}
- sitar->mbhc_data.t_sta_dce = ((1000 * 256) / (sitar->mclk_freq / 1000) *
- n_ready[sitar_codec_mclk_index(sitar)]) +
- 10;
+ sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
+ (sitar->mbhc_cfg.mclk_rate / 1000) *
+ n_ready[sitar_codec_mclk_index(sitar)]) +
+ 10;
sitar->mbhc_data.v_ins_hu =
sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
sitar->mbhc_data.v_ins_h =
@@ -2998,7 +3057,7 @@
sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
- sitar->mbhc_data.v_brl = 0xFA55;
+ sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
sitar->mbhc_data.v_no_mic =
sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
@@ -3012,9 +3071,10 @@
int n;
u8 *n_cic, *gain;
+ pr_err("%s(): ENTER\n", __func__);
sitar = snd_soc_codec_get_drvdata(codec);
- generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
- btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->calibration);
+ generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
for (n = 0; n < 8; n++) {
if (n != 7) {
@@ -3049,7 +3109,13 @@
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
btn_det->mbhc_nsc << 3);
+ snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
+ sitar->mbhc_cfg.micbias);
+
snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+
+ snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
+
}
static bool sitar_mbhc_fw_validate(const struct firmware *fw)
@@ -3083,13 +3149,563 @@
return true;
}
+
+
+static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+{
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+}
+
+/* called under codec_resource_lock acquisition */
+void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u8 wg_time;
+
+ wg_time = snd_soc_read(codec, SITAR_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 (sitar_is_hph_pa_on(codec)) {
+ pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
+ set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
+ set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
+ } else {
+ pr_debug("%s PA is off\n", __func__);
+ }
+
+ if (sitar_is_hph_dac_on(codec, 1))
+ set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
+ if (sitar_is_hph_dac_on(codec, 0))
+ set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
+
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0x00);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0x00);
+ usleep_range(wg_time * 1000, wg_time * 1000);
+}
+
+static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
+{
+ bool pa_turned_on = false;
+ struct snd_soc_codec *codec = sitar->codec;
+ u8 wg_time;
+
+ wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
+ wg_time += 1;
+
+ if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+ if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
+ 0xC0, 0xC0);
+ }
+
+ if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
+ 1 << 4);
+ pa_turned_on = true;
+ }
+ if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
+ &sitar->hph_pa_dac_state)) {
+ pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
+ snd_soc_update_bits(sitar->codec, SITAR_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);
+ }
+}
+
+static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
+ enum snd_jack_types jack_type)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ if (!insertion) {
+ /* Report removal */
+ sitar->hph_status &= ~jack_type;
+ if (sitar->mbhc_cfg.headset_jack) {
+ /* cancel possibly scheduled btn work and
+ * report release if we reported button press */
+ if (sitar_cancel_btn_work(sitar)) {
+ pr_debug("%s: button press is canceled\n",
+ __func__);
+ } else if (sitar->buttons_pressed) {
+ pr_debug("%s: Reporting release for reported "
+ "button press %d\n", __func__,
+ jack_type);
+ sitar_snd_soc_jack_report(sitar,
+ sitar->mbhc_cfg.button_jack, 0,
+ sitar->buttons_pressed);
+ sitar->buttons_pressed &=
+ ~SITAR_JACK_BUTTON_MASK;
+ }
+ pr_debug("%s: Reporting removal %d\n", __func__,
+ jack_type);
+ sitar_snd_soc_jack_report(sitar,
+ sitar->mbhc_cfg.headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
+ }
+ sitar_set_and_turnoff_hph_padac(codec);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHR,
+ SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ hphocp_off_report(sitar, SND_JACK_OC_HPHL,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ sitar->current_plug = PLUG_TYPE_NONE;
+ sitar->mbhc_polling_active = false;
+ } else {
+ /* Report insertion */
+ sitar->hph_status |= jack_type;
+
+ if (jack_type == SND_JACK_HEADPHONE)
+ sitar->current_plug = PLUG_TYPE_HEADPHONE;
+ else if (jack_type == SND_JACK_HEADSET) {
+ sitar->mbhc_polling_active = true;
+ sitar->current_plug = PLUG_TYPE_HEADSET;
+ }
+ if (sitar->mbhc_cfg.headset_jack) {
+ pr_debug("%s: Reporting insertion %d\n", __func__,
+ jack_type);
+ sitar_snd_soc_jack_report(sitar,
+ sitar->mbhc_cfg.headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
+ }
+ sitar_clr_and_turnon_hph_padac(sitar);
+ }
+}
+
+
+static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
+{
+ return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
+ sitar->mbhc_cfg.gpio_level_insert);
+}
+
+static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
+ int mic_volt, int mic_volt_prev)
+{
+ int delta = abs(mic_volt - mic_volt_prev);
+ if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
+ pr_debug("%s: volt delta %dmv\n", __func__, delta);
+ return true;
+ }
+ return false;
+}
+
+static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
+ s32 mic_volt)
+{
+ bool invalid = false;
+
+ if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
+ && (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
+ invalid = true;
+ }
+
+ return invalid;
+}
+
+static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
+ s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
+ enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
+{
+ int i;
+ bool r = false;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
+ SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
+
+ for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
+ if (mic_mv[i] < plug_type_ptr->v_no_mic)
+ plug_type[i] = PLUG_TYPE_HEADPHONE;
+ else if (mic_mv[i] < plug_type_ptr->v_hs_max)
+ plug_type[i] = PLUG_TYPE_HEADSET;
+ else if (mic_mv[i] > plug_type_ptr->v_hs_max)
+ plug_type[i] = PLUG_TYPE_HIGH_HPH;
+
+ r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
+ if (!r && i > 0) {
+ if (plug_type[i-1] != plug_type[i])
+ r = true;
+ else
+ r = sitar_is_invalid_insert_delta(codec,
+ mic_mv[i],
+ mic_mv[i - 1]);
+ }
+ }
+
+ return r;
+}
+
+/* called under codec_resource_lock acquisition */
+void sitar_find_plug_and_report(struct snd_soc_codec *codec,
+ enum sitar_mbhc_plug_type plug_type)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ if (plug_type == PLUG_TYPE_HEADPHONE
+ && sitar->current_plug == PLUG_TYPE_NONE) {
+ /* Nothing was reported previously
+ * reporte a headphone
+ */
+ sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+ sitar_codec_cleanup_hs_polling(codec);
+ } else if (plug_type == PLUG_TYPE_HEADSET) {
+ /* If Headphone was reported previously, this will
+ * only report the mic line
+ */
+ sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
+ msleep(100);
+ sitar_codec_start_hs_polling(codec);
+ } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+ if (sitar->current_plug == PLUG_TYPE_NONE)
+ sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+ sitar_codec_cleanup_hs_polling(codec);
+ pr_debug("setup mic trigger for further detection\n");
+ sitar->lpi_enabled = true;
+ /* TODO ::: sitar_codec_enable_hs_detect */
+ pr_err("%s(): High impedence hph not supported\n", __func__);
+ }
+}
+
+/* should be called under interrupt context that hold suspend */
+static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
+{
+ pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
+ sitar->hs_detect_work_stop = false;
+ wcd9xxx_lock_sleep(sitar->codec->control_data);
+ schedule_work(&sitar->hs_correct_plug_work);
+}
+
+/* called under codec_resource_lock acquisition */
+static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
+{
+ pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
+ sitar->hs_detect_work_stop = true;
+ wmb();
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+ if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
+ pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
+ wcd9xxx_unlock_sleep(sitar->codec->control_data);
+ }
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+}
+
+static void sitar_hs_correct_gpio_plug(struct work_struct *work)
+{
+ struct sitar_priv *sitar;
+ struct snd_soc_codec *codec;
+ int retry = 0, i;
+ bool correction = false;
+ s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+ short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+ enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+ unsigned long timeout;
+
+ sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
+ codec = sitar->codec;
+
+ pr_debug("%s: enter\n", __func__);
+ sitar->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.
+ */
+ sitar_turn_onoff_override(codec, true);
+
+ timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
+ while (!time_after(jiffies, timeout)) {
+ ++retry;
+ rmb();
+ if (sitar->hs_detect_work_stop) {
+ pr_debug("%s: stop requested\n", __func__);
+ break;
+ }
+
+ msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
+ if (sitar_hs_gpio_level_remove(sitar)) {
+ pr_debug("%s: GPIO value is low\n", __func__);
+ break;
+ }
+
+ /* can race with removal interrupt */
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+ for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+ mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
+ mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
+ pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
+ __func__, retry, mic_mv[i], mb_v[i]);
+ }
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+
+ if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+ pr_debug("Invalid plug in attempt # %d\n", retry);
+ if (retry == NUM_ATTEMPTS_TO_REPORT &&
+ sitar->current_plug == PLUG_TYPE_NONE) {
+ sitar_codec_report_plug(codec, 1,
+ SND_JACK_HEADPHONE);
+ }
+ } else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
+ plug_type) &&
+ plug_type[0] == PLUG_TYPE_HEADPHONE) {
+ pr_debug("Good headphone detected, continue polling mic\n");
+ if (sitar->current_plug == PLUG_TYPE_NONE) {
+ sitar_codec_report_plug(codec, 1,
+ SND_JACK_HEADPHONE);
+ }
+ } else {
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
+ /* Turn off override */
+ sitar_turn_onoff_override(codec, false);
+ sitar_find_plug_and_report(codec, plug_type[0]);
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
+ pr_debug("Attempt %d found correct plug %d\n", retry,
+ plug_type[0]);
+ correction = true;
+ break;
+ }
+ }
+
+ /* Turn off override */
+ if (!correction)
+ sitar_turn_onoff_override(codec, false);
+
+ sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+ pr_debug("%s: leave\n", __func__);
+ /* unlock sleep */
+ wcd9xxx_unlock_sleep(sitar->codec->control_data);
+}
+
+/* called under codec_resource_lock acquisition */
+static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
+ s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
+ enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
+ int i;
+
+ pr_debug("%s: enter\n", __func__);
+
+ sitar_turn_onoff_override(codec, true);
+ mb_v[0] = sitar_codec_setup_hs_polling(codec);
+ mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
+ pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
+
+ for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+ mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
+ mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
+ pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
+ mic_mv[i]);
+ }
+ sitar_turn_onoff_override(codec, false);
+
+ if (sitar_hs_gpio_level_remove(sitar)) {
+ pr_debug("%s: GPIO value is low when determining plug\n",
+ __func__);
+ return;
+ }
+
+ if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
+ sitar_schedule_hs_detect_plug(sitar);
+ } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
+ sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
+ sitar_schedule_hs_detect_plug(sitar);
+ } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
+ pr_debug("%s: Valid plug found, determine plug type\n",
+ __func__);
+ sitar_find_plug_and_report(codec, plug_type[0]);
+ }
+
+}
+
+/* called under codec_resource_lock acquisition */
+static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ const struct sitar_mbhc_plug_detect_cfg *plug_det =
+ SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
+
+ 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 (sitar_hs_gpio_level_remove(sitar))
+ pr_debug("%s: GPIO value is low when determining "
+ "plug\n", __func__);
+ else
+ sitar_codec_decide_gpio_plug(codec);
+
+ return;
+}
+
+static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
+{
+ bool insert;
+ struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
+ bool is_removed = false;
+
+ pr_debug("%s: enter\n", __func__);
+
+ priv->in_gpio_handler = true;
+ /* Wait here for debounce time */
+ usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
+ SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
+
+ SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
+
+ /* cancel pending button press */
+ if (sitar_cancel_btn_work(priv))
+ pr_debug("%s: button press is canceled\n", __func__);
+
+ insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
+ priv->mbhc_cfg.gpio_level_insert);
+ if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
+ priv->lpi_enabled = false;
+ wmb();
+
+ /* cancel detect plug */
+ sitar_cancel_hs_detect_plug(priv);
+
+ /* Disable Mic Bias pull down and HPH Switch to GND */
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
+ 0x00);
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
+ sitar_codec_detect_plug_type(codec);
+ } else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
+ priv->lpi_enabled = false;
+ wmb();
+
+ /* cancel detect plug */
+ sitar_cancel_hs_detect_plug(priv);
+
+ if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
+ sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
+ is_removed = true;
+ } else if (priv->current_plug == PLUG_TYPE_HEADSET) {
+ sitar_codec_pause_hs_polling(codec);
+ sitar_codec_cleanup_hs_polling(codec);
+ sitar_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,
+ priv->mbhc_bias_regs.ctl_reg, 0x01,
+ 0x01);
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
+ 0x01);
+ /* Make sure mic trigger is turned off */
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.ctl_reg,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec,
+ priv->mbhc_bias_regs.mbhc_reg,
+ 0x90, 0x00);
+ /* Reset MBHC State Machine */
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
+ 0x08, 0x08);
+ snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
+ 0x08, 0x00);
+ /* Turn off override */
+ sitar_turn_onoff_override(codec, false);
+ }
+ }
+
+ priv->in_gpio_handler = false;
+ SITAR_RELEASE_LOCK(priv->codec_resource_lock);
+ pr_debug("%s: leave\n", __func__);
+}
+
+static irqreturn_t sitar_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 {
+ sitar_hs_gpio_handler(codec);
+ wcd9xxx_unlock_sleep(codec->control_data);
+ }
+ return r;
+}
+
+static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
+{
+ int rc = 0;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
+ sitar_mbhc_init(codec);
+ sitar_mbhc_cal(codec);
+ sitar_mbhc_calc_thres(codec);
+ sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
+ sitar_codec_calibrate_hs_polling(codec);
+
+ /* Enable Mic Bias pull down and HPH Switch to GND */
+ snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
+ 0x01, 0x01);
+ snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
+ 0x01, 0x01);
+
+ rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
+ NULL,
+ sitar_mechanical_plug_detect_irq,
+ (IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING),
+ "sitar-hs-gpio", codec);
+
+ if (!IS_ERR_VALUE(rc)) {
+ rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
+ 0x10, 0x10);
+ wcd9xxx_enable_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPL_FAULT);
+ wcd9xxx_enable_irq(codec->control_data,
+ SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ /* Bootup time detection */
+ sitar_hs_gpio_handler(codec);
+ }
+
+ return rc;
+}
+
static void mbhc_fw_read(struct work_struct *work)
{
struct delayed_work *dwork;
struct sitar_priv *sitar;
struct snd_soc_codec *codec;
const struct firmware *fw;
- int ret = -1, retry = 0, rc;
+ int ret = -1, retry = 0;
dwork = to_delayed_work(work);
sitar = container_of(dwork, struct sitar_priv,
@@ -3124,80 +3740,53 @@
sitar->mbhc_fw = fw;
}
- sitar->mclk_cb(codec, 1);
- sitar_mbhc_init(codec);
- sitar_mbhc_cal(codec);
- sitar_mbhc_calc_thres(codec);
- sitar->mclk_cb(codec, 0);
- sitar_codec_calibrate_hs_polling(codec);
- rc = sitar_codec_enable_hs_detect(codec, 1);
-
- if (IS_ERR_VALUE(rc))
- pr_err("%s: Failed to setup MBHC detection\n", __func__);
-
+ sitar_mbhc_init_and_calibrate(codec);
}
int sitar_hs_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *headset_jack,
- struct snd_soc_jack *button_jack,
- void *calibration, enum sitar_micbias_num micbias,
- int (*mclk_cb_fn) (struct snd_soc_codec*, int),
- int read_fw_bin, u32 mclk_rate)
+ const struct sitar_mbhc_config *cfg)
{
struct sitar_priv *sitar;
int rc = 0;
- if (!codec || !calibration) {
+ if (!codec || !cfg->calibration) {
pr_err("Error: no codec or calibration\n");
return -EINVAL;
}
- if (mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
- if (mclk_rate == SITAR_MCLK_RATE_9600KHZ)
+ if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
+ if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
pr_err("Error: clock rate %dHz is not yet supported\n",
- mclk_rate);
+ cfg->mclk_rate);
else
- pr_err("Error: unsupported clock rate %d\n", mclk_rate);
+ pr_err("Error: unsupported clock rate %d\n",
+ cfg->mclk_rate);
return -EINVAL;
}
sitar = snd_soc_codec_get_drvdata(codec);
- sitar->headset_jack = headset_jack;
- sitar->button_jack = button_jack;
- sitar->micbias = micbias;
- sitar->calibration = calibration;
- sitar->mclk_cb = mclk_cb_fn;
- sitar->mclk_freq = mclk_rate;
+ sitar->mbhc_cfg = *cfg;
+ sitar->in_gpio_handler = false;
+ sitar->current_plug = PLUG_TYPE_NONE;
+ sitar->lpi_enabled = false;
sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
/* Put CFILT in fast mode by default */
snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
- 0x40, SITAR_CFILT_FAST_MODE);
+ 0x40, SITAR_CFILT_FAST_MODE);
+
INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
- INIT_DELAYED_WORK(&sitar->btn0_dwork, btn0_lpress_fn);
+ INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
+ INIT_WORK(&sitar->hs_correct_plug_work,
+ sitar_hs_correct_gpio_plug);
- if (!read_fw_bin) {
- sitar->mclk_cb(codec, 1);
- sitar_mbhc_init(codec);
- sitar_mbhc_cal(codec);
- sitar_mbhc_calc_thres(codec);
- sitar->mclk_cb(codec, 0);
- sitar_codec_calibrate_hs_polling(codec);
- rc = sitar_codec_enable_hs_detect(codec, 1);
+ if (!sitar->mbhc_cfg.read_fw_bin) {
+ rc = sitar_mbhc_init_and_calibrate(codec);
} else {
schedule_delayed_work(&sitar->mbhc_firmware_dwork,
- usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
- }
-
- if (!IS_ERR_VALUE(rc)) {
- snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
- 0x10);
- wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPL_FAULT);
- wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_HPH_PA_OCPR_FAULT);
+ usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
}
return rc;
@@ -3211,7 +3800,7 @@
struct sitar_mbhc_btn_detect_cfg *btn_det;
int i, btn = -1;
- btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+ btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
SITAR_BTN_DET_V_BTN_HIGH);
@@ -3261,33 +3850,76 @@
return mask;
}
+
static irqreturn_t sitar_dce_handler(int irq, void *data)
{
int i, mask;
- short bias_value_dce;
- s32 bias_mv_dce;
+ short dce, sta, bias_value_dce;
+ s32 mv, stamv, bias_mv_dce;
int btn = -1, meas = 0;
struct sitar_priv *priv = data;
const struct sitar_mbhc_btn_detect_cfg *d =
- SITAR_MBHC_CAL_BTN_DET_PTR(priv->calibration);
+ SITAR_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, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
+ pr_debug("%s: enter\n", __func__);
- bias_value_dce = sitar_codec_read_dce_result(codec);
- bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
+ SITAR_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 = sitar_codec_read_dce_result(codec);
+ mv = sitar_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;
+ }
+
+ if (mbhc_status != SITAR_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 = sitar_codec_read_sta_result(codec);
+ stamv = sitar_codec_sta_dce_v(codec, 0, sta);
+ btn = sitar_determine_button(priv, mv);
+ if (btn != sitar_determine_button(priv, stamv))
+ btn = -1;
+ goto done;
+ }
+ }
/* determine pressed button */
- btnmeas[meas++] = sitar_determine_button(priv, bias_mv_dce);
+ btnmeas[meas++] = sitar_determine_button(priv, mv);
pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
- meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
- if (d->n_btn_meas == 0)
+ meas - 1, dce, mv, btnmeas[meas - 1]);
+ if (n_btn_meas == 0)
btn = btnmeas[0];
for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
- bias_value_dce = sitar_codec_sta_dce(codec, 1);
+ bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
@@ -3305,147 +3937,133 @@
/* 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 left measurements are less than n_btn_con,
- * it's impossible to find button number */
- if ((d->n_btn_meas - meas) < d->n_btn_con)
- break;
}
if (btn >= 0) {
+ if (priv->in_gpio_handler) {
+ pr_debug("%s: GPIO already triggered, ignore button "
+ "press\n", __func__);
+ goto done;
+ }
mask = sitar_get_button_mask(btn);
priv->buttons_pressed |= mask;
-
- msleep(100);
-
- /* XXX: assuming button 0 has the lowest micbias voltage */
- if (btn == 0) {
- wcd9xxx_lock_sleep(core);
- if (schedule_delayed_work(&priv->btn0_dwork,
- msecs_to_jiffies(400)) == 0) {
- WARN(1, "Button pressed twice without release"
- "event\n");
- wcd9xxx_unlock_sleep(core);
- }
- } else {
- pr_debug("%s: Reporting short button %d(0x%x) press\n",
- __func__, btn, mask);
- sitar_snd_soc_jack_report(priv, priv->button_jack, mask,
- 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__);
+ SITAR_RELEASE_LOCK(priv->codec_resource_lock);
return IRQ_HANDLED;
}
+static int sitar_is_fake_press(struct sitar_priv *priv)
+{
+ int i;
+ int r = 0;
+ struct snd_soc_codec *codec = priv->codec;
+ const int dces = MBHC_NUM_DCE_PLUG_DETECT;
+ short mb_v;
+
+ for (i = 0; i < dces; i++) {
+ usleep_range(10000, 10000);
+ if (i == 0) {
+ mb_v = sitar_codec_sta_dce(codec, 0, true);
+ pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
+ sitar_codec_sta_dce_v(codec, 0, mb_v));
+ if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
+ mb_v > (short)priv->mbhc_data.v_ins_hu) {
+ r = 1;
+ break;
+ }
+ } else {
+ mb_v = sitar_codec_sta_dce(codec, 1, true);
+ pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
+ sitar_codec_sta_dce_v(codec, 1, mb_v));
+ if (mb_v < (short)priv->mbhc_data.v_b1_h ||
+ mb_v > (short)priv->mbhc_data.v_ins_h) {
+ r = 1;
+ break;
+ }
+ }
+ }
+
+ return r;
+}
+
static irqreturn_t sitar_release_handler(int irq, void *data)
{
int ret;
- short mb_v;
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
pr_debug("%s: enter\n", __func__);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
- if (priv->buttons_pressed & SND_JACK_BTN_0) {
- ret = cancel_delayed_work(&priv->btn0_dwork);
+ SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
+ priv->mbhc_state = MBHC_STATE_RELEASE;
+ if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
+ ret = sitar_cancel_btn_work(priv);
if (ret == 0) {
- pr_debug("%s: Reporting long button 0 release event\n",
+ pr_debug("%s: Reporting long button release event\n",
__func__);
- if (priv->button_jack)
+ if (priv->mbhc_cfg.button_jack)
sitar_snd_soc_jack_report(priv,
- priv->button_jack, 0,
- SND_JACK_BTN_0);
+ priv->mbhc_cfg.button_jack, 0,
+ priv->buttons_pressed);
} else {
- /* if scheduled btn0_dwork is canceled from here,
- * we have to unlock from here instead btn0_work */
- wcd9xxx_unlock_sleep(core);
- mb_v = sitar_codec_sta_dce(codec, 0);
- pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
- __func__, mb_v,
- sitar_codec_sta_dce_v(codec, 0, mb_v));
-
- if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
- mb_v > (short)priv->mbhc_data.v_ins_hu)
- pr_debug("%s: Fake buttton press interrupt\n",
+ if (sitar_is_fake_press(priv)) {
+ pr_debug("%s: Fake button press interrupt\n",
__func__);
- else if (priv->button_jack) {
- pr_debug("%s: Reporting short button 0 "
- "press and release\n", __func__);
- sitar_snd_soc_jack_report(priv,
- priv->button_jack,
- SND_JACK_BTN_0,
- SND_JACK_BTN_0);
- sitar_snd_soc_jack_report(priv,
- priv->button_jack, 0,
- SND_JACK_BTN_0);
+ } 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 0 "
+ "press and release\n",
+ __func__);
+ sitar_snd_soc_jack_report(priv,
+ priv->mbhc_cfg.button_jack,
+ priv->buttons_pressed,
+ priv->buttons_pressed);
+ sitar_snd_soc_jack_report(priv,
+ priv->mbhc_cfg.button_jack, 0,
+ priv->buttons_pressed);
+ }
}
}
- priv->buttons_pressed &= ~SND_JACK_BTN_0;
- }
-
- if (priv->buttons_pressed) {
- pr_debug("%s:reporting button release mask 0x%x\n", __func__,
- priv->buttons_pressed);
- sitar_snd_soc_jack_report(priv, priv->button_jack, 0,
- priv->buttons_pressed);
- /* hardware doesn't detect another button press until
- * already pressed button is released.
- * therefore buttons_pressed has only one button's mask. */
priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
}
+ sitar_codec_calibrate_hs_polling(codec);
+
+ if (priv->mbhc_cfg.gpio)
+ msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
+
sitar_codec_start_hs_polling(codec);
+
+ pr_debug("%s: leave\n", __func__);
+ SITAR_RELEASE_LOCK(priv->codec_resource_lock);
+
return IRQ_HANDLED;
}
-static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
-{
- struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- const struct sitar_mbhc_general_cfg *generic =
- SITAR_MBHC_CAL_GENERAL_PTR(sitar->calibration);
-
- if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
- sitar_codec_enable_config_mode(codec, 1);
-
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
-
- snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
-
- usleep_range(generic->t_shutdown_plug_rem,
- generic->t_shutdown_plug_rem);
-
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
- if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
- sitar_codec_enable_config_mode(codec, 0);
-
- snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
-}
-
-static void sitar_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
-{
- struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
-
- sitar_codec_shutdown_hs_removal_detect(codec);
-
- if (!sitar->mclk_enabled) {
- snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0x00);
- sitar_codec_disable_clock_block(codec);
- sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
- }
-
- sitar->mbhc_polling_active = false;
-}
-
static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
{
struct sitar_priv *sitar = data;
@@ -3466,11 +4084,11 @@
SITAR_IRQ_HPH_PA_OCPL_FAULT);
sitar->hphlocp_cnt = 0;
sitar->hph_status |= SND_JACK_OC_HPHL;
- if (sitar->headset_jack)
+ if (sitar->mbhc_cfg.headset_jack)
sitar_snd_soc_jack_report(sitar,
- sitar->headset_jack,
- sitar->hph_status,
- SITAR_JACK_MASK);
+ sitar->mbhc_cfg.headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
}
} else {
pr_err("%s: Bad sitar private data\n", __func__);
@@ -3499,11 +4117,11 @@
SITAR_IRQ_HPH_PA_OCPR_FAULT);
sitar->hphrocp_cnt = 0;
sitar->hph_status |= SND_JACK_OC_HPHR;
- if (sitar->headset_jack)
+ if (sitar->mbhc_cfg.headset_jack)
sitar_snd_soc_jack_report(sitar,
- sitar->headset_jack,
- sitar->hph_status,
- SITAR_JACK_MASK);
+ sitar->mbhc_cfg.headset_jack,
+ sitar->hph_status,
+ SITAR_JACK_MASK);
}
} else {
pr_err("%s: Bad sitar private data\n", __func__);
@@ -3512,252 +4130,131 @@
return IRQ_HANDLED;
}
-static void sitar_sync_hph_state(struct sitar_priv *sitar)
-{
- if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
- &sitar->hph_pa_dac_state)) {
- pr_err("%s: HPHR clear flag and enable PA\n", __func__);
- snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
- 1 << 4);
- }
- if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
- &sitar->hph_pa_dac_state)) {
- pr_err("%s: HPHL clear flag and enable PA\n", __func__);
- snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
- 1 << 5);
- }
-
- if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
- &sitar->hph_pa_dac_state)) {
- pr_err("%s: HPHR clear flag and enable DAC\n", __func__);
- snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
- 0xC0, 0xC0);
- }
- if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
- &sitar->hph_pa_dac_state)) {
- pr_err("%s: HPHL clear flag and enable DAC\n", __func__);
- snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
- 0xC0, 0xC0);
- }
-}
-
static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
{
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- const struct sitar_mbhc_plug_detect_cfg *plug_det =
- SITAR_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
- int ldo_h_on, micb_cfilt_on;
- short mb_v;
- u8 is_removal;
- int mic_mv;
pr_debug("%s: enter\n", __func__);
+ SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
- is_removal = snd_soc_read(codec, SITAR_A_CDC_MBHC_INT_CTL) & 0x02;
snd_soc_update_bits(codec, SITAR_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, SITAR_A_MBHC_HPH, 0x13, 0x00);
+ snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
- if (priv->mbhc_fake_ins_start &&
- time_after(jiffies, priv->mbhc_fake_ins_start +
- msecs_to_jiffies(SITAR_FAKE_INS_THRESHOLD_MS))) {
- pr_debug("%s: fake context interrupt, reset insertion\n",
- __func__);
- priv->mbhc_fake_ins_start = 0;
- sitar_codec_shutdown_hs_polling(codec);
- sitar_codec_enable_hs_detect(codec, 1);
- return IRQ_HANDLED;
- }
+ pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
- ldo_h_on = snd_soc_read(codec, SITAR_A_LDO_H_MODE_1) & 0x80;
- micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
- & 0x80;
+ rmb();
+ if (priv->lpi_enabled)
+ msleep(100);
- if (!ldo_h_on)
- snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
- if (!micb_cfilt_on)
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
- 0x80, 0x80);
- 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 (!ldo_h_on)
- snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x0);
- if (!micb_cfilt_on)
- snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
- 0x80, 0x0);
-
- if (is_removal) {
- /*
- * If headphone is removed while playback is in progress,
- * it is possible that micbias will be switched to VDDIO.
- */
- if (priv->mbhc_micbias_switched)
- sitar_codec_switch_micbias(codec, 0);
- priv->hph_status &= ~SND_JACK_HEADPHONE;
-
- /* If headphone PA is on, check if userspace receives
- * removal event to sync-up PA's state */
- if (sitar_is_hph_pa_on(codec)) {
- set_bit(SITAR_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
- set_bit(SITAR_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
- }
-
- if (sitar_is_hph_dac_on(codec, 1))
- set_bit(SITAR_HPHL_DAC_OFF_ACK,
- &priv->hph_pa_dac_state);
- if (sitar_is_hph_dac_on(codec, 0))
- set_bit(SITAR_HPHR_DAC_OFF_ACK,
- &priv->hph_pa_dac_state);
-
- if (priv->headset_jack) {
- pr_err("%s: Reporting removal\n", __func__);
- sitar_snd_soc_jack_report(priv, priv->headset_jack,
- priv->hph_status,
- SITAR_JACK_MASK);
- }
- sitar_codec_shutdown_hs_removal_detect(codec);
- sitar_codec_enable_hs_detect(codec, 1);
- return IRQ_HANDLED;
- }
-
- mb_v = sitar_codec_setup_hs_polling(codec);
- mic_mv = sitar_codec_sta_dce_v(codec, 0, mb_v);
-
- if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
- pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
- "STA : %d,%d\n", __func__,
- (priv->mbhc_fake_ins_start ?
- jiffies_to_msecs(jiffies -
- priv->mbhc_fake_ins_start) :
- 0),
- mb_v, mic_mv);
- if (time_after(jiffies,
- priv->mbhc_fake_ins_start +
- msecs_to_jiffies(SITAR_FAKE_INS_THRESHOLD_MS))) {
- /* Disable HPH trigger and enable MIC line trigger */
- snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x12,
- 0x00);
- snd_soc_update_bits(codec,
- priv->mbhc_bias_regs.mbhc_reg, 0x60,
- plug_det->mic_current << 5);
- snd_soc_update_bits(codec,
- priv->mbhc_bias_regs.mbhc_reg,
- 0x80, 0x80);
- usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
- snd_soc_update_bits(codec,
- priv->mbhc_bias_regs.mbhc_reg,
- 0x10, 0x10);
- } else {
- if (priv->mbhc_fake_ins_start == 0)
- priv->mbhc_fake_ins_start = jiffies;
- /* Setup normal insert detection
- * Enable HPH Schmitt Trigger
- */
- snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
- 0x13 | 0x0C,
- 0x13 | plug_det->hph_current << 2);
- }
- /* Setup for insertion detection */
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x2, 0);
- wcd9xxx_enable_irq(codec->control_data,
- SITAR_IRQ_MBHC_INSERTION);
- snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
-
- } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
- pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
- __func__, mb_v, mic_mv);
- priv->mbhc_fake_ins_start = 0;
- priv->hph_status |= SND_JACK_HEADPHONE;
- if (priv->headset_jack) {
- pr_debug("%s: Reporting insertion %d\n", __func__,
- SND_JACK_HEADPHONE);
- sitar_snd_soc_jack_report(priv, priv->headset_jack,
- priv->hph_status,
- SITAR_JACK_MASK);
- }
- sitar_codec_shutdown_hs_polling(codec);
- sitar_codec_enable_hs_detect(codec, 0);
- sitar_sync_hph_state(priv);
+ 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__);
+ sitar_codec_decide_gpio_plug(codec);
} else {
- pr_debug("%s: Headset detected, mb_v: %d,%d\n",
- __func__, mb_v, mic_mv);
- priv->mbhc_fake_ins_start = 0;
- priv->hph_status |= SND_JACK_HEADSET;
- if (priv->headset_jack) {
- pr_debug("%s: Reporting insertion %d\n", __func__,
- SND_JACK_HEADSET);
- sitar_snd_soc_jack_report(priv, priv->headset_jack,
- priv->hph_status,
- SITAR_JACK_MASK);
+ pr_debug("%s: Invalid insertion, "
+ "stop plug detection\n", __func__);
+ }
+ SITAR_RELEASE_LOCK(priv->codec_resource_lock);
+ return IRQ_HANDLED;
+}
+
+static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
+{
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ struct sitar_mbhc_plug_type_cfg *plug_type =
+ SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
+
+ return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
+ && mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
+ && (mic_mv > plug_type->v_no_mic)
+ && (mic_mv < plug_type->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 sitar_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 sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
+ while (!(timedout = time_after(jiffies, timeout))) {
+ retry++;
+ if (sitar_hs_gpio_level_remove(sitar)) {
+ pr_debug("%s: GPIO indicates removal\n", __func__);
+ break;
}
- /* avoid false button press detect */
- msleep(50);
- sitar_codec_start_hs_polling(codec);
- sitar_sync_hph_state(priv);
+
+ if (retry > 1)
+ msleep(250);
+ else
+ msleep(50);
+
+ if (sitar_hs_gpio_level_remove(sitar)) {
+ pr_debug("%s: GPIO indicates removal\n", __func__);
+ break;
+ }
+
+ sitar_turn_onoff_override(codec, true);
+ for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
+ mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
+ mic_mv[i] = sitar_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]);
+ }
+ sitar_turn_onoff_override(codec, false);
+
+ if (sitar_hs_gpio_level_remove(sitar)) {
+ pr_debug("%s: GPIO indicates removal\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;
+ }
}
- return IRQ_HANDLED;
+ if (timedout)
+ pr_debug("%s: Microphone did not settle in %d seconds\n",
+ __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
+ return settled;
}
static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
{
- short bias_value;
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
- const struct sitar_mbhc_general_cfg *generic =
- SITAR_MBHC_CAL_GENERAL_PTR(priv->calibration);
- int fake_removal = 0;
- int min_us = SITAR_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
pr_debug("%s: enter, removal interrupt\n", __func__);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
- usleep_range(generic->t_shutdown_plug_rem,
- generic->t_shutdown_plug_rem);
-
- do {
- bias_value = sitar_codec_sta_dce(codec, 1);
- pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
- sitar_codec_sta_dce_v(codec, 1, bias_value), min_us);
- if (bias_value < (short)priv->mbhc_data.v_ins_h) {
- fake_removal = 1;
- break;
- }
- min_us -= priv->mbhc_data.t_dce;
- } while (min_us > 0);
-
- if (fake_removal) {
- pr_debug("False alarm, headset not actually removed\n");
+ SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
+ if (sitar_hs_remove_settle(codec))
sitar_codec_start_hs_polling(codec);
- } else {
- /*
- * If this removal is not false, first check the micbias
- * switch status and switch it to LDOH if it is already
- * switched to VDDIO.
- */
- if (priv->mbhc_micbias_switched)
- sitar_codec_switch_micbias(codec, 0);
- priv->hph_status &= ~SND_JACK_HEADSET;
- if (priv->headset_jack) {
- pr_err("%s: Reporting removal\n", __func__);
- sitar_snd_soc_jack_report(priv, priv->headset_jack, 0,
- SITAR_JACK_MASK);
- }
- sitar_codec_shutdown_hs_polling(codec);
+ pr_debug("%s: remove settle done\n", __func__);
- sitar_codec_enable_hs_detect(codec, 1);
- }
-
+ SITAR_RELEASE_LOCK(priv->codec_resource_lock);
return IRQ_HANDLED;
}
@@ -4015,7 +4512,10 @@
sitar->config_mode_active = false;
sitar->mbhc_polling_active = false;
sitar->no_mic_headset_override = false;
+ mutex_init(&sitar->codec_resource_lock);
sitar->codec = codec;
+ sitar->mbhc_state = MBHC_STATE_NONE;
+ sitar->mbhc_last_resume = 0;
sitar->pdata = dev_get_platdata(codec->dev->parent);
sitar_update_reg_defaults(codec);
sitar_codec_init_reg(codec);
@@ -4057,7 +4557,6 @@
SITAR_IRQ_MBHC_REMOVAL);
goto err_remove_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
sitar_dce_handler, "DC Estimation detect", sitar);
@@ -4066,7 +4565,6 @@
SITAR_IRQ_MBHC_POTENTIAL);
goto err_potential_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
sitar_release_handler, "Button Release detect", sitar);
@@ -4075,7 +4573,6 @@
SITAR_IRQ_MBHC_RELEASE);
goto err_release_irq;
}
- wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
sitar_slimbus_irq, "SLIMBUS Slave", sitar);
@@ -4151,6 +4648,7 @@
SITAR_IRQ_MBHC_INSERTION, sitar);
err_insert_irq:
err_pdata:
+ mutex_destroy(&sitar->codec_resource_lock);
kfree(sitar);
return ret;
}
@@ -4163,12 +4661,15 @@
wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
+ SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
sitar_codec_disable_clock_block(codec);
+ SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
if (sitar->mbhc_fw)
release_firmware(sitar->mbhc_fw);
for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
kfree(sitar->dai[i].ch_num);
+ mutex_destroy(&sitar->codec_resource_lock);
kfree(sitar);
return 0;
}
@@ -4232,7 +4733,10 @@
static int sitar_resume(struct device *dev)
{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sitar_priv *sitar = platform_get_drvdata(pdev);
dev_dbg(dev, "%s: system resume\n", __func__);
+ sitar->mbhc_last_resume = jiffies;
return 0;
}
diff --git a/sound/soc/codecs/wcd9304.h b/sound/soc/codecs/wcd9304.h
index cfe839b..70b3f0b 100644
--- a/sound/soc/codecs/wcd9304.h
+++ b/sound/soc/codecs/wcd9304.h
@@ -156,12 +156,29 @@
u16 _beta[3];
} __packed;
+struct sitar_mbhc_config {
+ struct snd_soc_jack *headset_jack;
+ struct snd_soc_jack *button_jack;
+ bool read_fw_bin;
+ /* void* calibration contains:
+ * struct tabla_mbhc_general_cfg generic;
+ * struct tabla_mbhc_plug_detect_cfg plug_det;
+ * struct tabla_mbhc_plug_type_cfg plug_type;
+ * struct tabla_mbhc_btn_detect_cfg btn_det;
+ * struct tabla_mbhc_imped_detect_cfg imped_det;
+ * Note: various size depends on btn_det->num_btn
+ */
+ void *calibration;
+ enum sitar_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;
+};
+
extern int sitar_hs_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *headset_jack,
- struct snd_soc_jack *button_jack,
- void *calibration, enum sitar_micbias_num micbis,
- int (*mclk_cb_fn) (struct snd_soc_codec*, int),
- int read_fw_bin, u32 mclk_rate);
+ const struct sitar_mbhc_config *cfg);
#ifndef anc_header_dec
struct anc_header {
@@ -171,7 +188,8 @@
#define anc_header_dec
#endif
-extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
+extern int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable,
+ bool dapm);
extern void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg
*btn_det,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index d2f58a5..2d5eab2 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -66,8 +66,9 @@
#define AIF1_CAP 2
#define AIF2_PB 3
#define AIF2_CAP 4
+#define AIF3_CAP 5
-#define NUM_CODEC_DAIS 4
+#define NUM_CODEC_DAIS 5
#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
struct tabla_codec_dai_data {
@@ -3038,12 +3039,26 @@
{"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"},
@@ -3059,6 +3074,13 @@
{"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"},
@@ -3776,7 +3798,8 @@
tabla->dai[dai->id - 1].ch_act = 0;
tabla->dai[dai->id - 1].ch_tot = rx_num;
}
- } else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP) {
+ } else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP ||
+ dai->id == AIF3_CAP) {
for (i = 0; i < tx_num; i++) {
tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
tabla->dai[dai->id - 1].ch_act = 0;
@@ -3828,8 +3851,11 @@
*tx_num = tabla_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[3 + cnt];
- tx_slot[3] = tx_ch[5 + cnt];
+ tx_slot[2] = tx_ch[5 + cnt];
+ } else if (dai->id == AIF3_CAP) {
+ *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
+ tx_slot[cnt] = tx_ch[2 + cnt];
+ tx_slot[cnt + 1] = tx_ch[4 + cnt];
}
return 0;
@@ -3891,7 +3917,8 @@
* 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)) {
+ if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP) ||
+ (dai->id == AIF3_CAP)) {
tx_state = snd_soc_read(codec,
TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
@@ -4054,6 +4081,20 @@
},
.ops = &tabla_dai_ops,
},
+ {
+ .name = "tabla_tx3",
+ .id = AIF3_CAP,
+ .capture = {
+ .stream_name = "AIF3 Capture",
+ .rates = WCD9310_RATES,
+ .formats = TABLA_FORMATS,
+ .rate_max = 48000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &tabla_dai_ops,
+ },
};
static struct snd_soc_dai_driver tabla_i2s_dai[] = {
@@ -4104,7 +4145,8 @@
case SND_SOC_DAPM_POST_PMU:
for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
if ((tabla_dai[j].id == AIF1_CAP) ||
- (tabla_dai[j].id == AIF2_CAP))
+ (tabla_dai[j].id == AIF2_CAP) ||
+ (tabla_dai[j].id == AIF3_CAP))
continue;
if (!strncmp(w->sname,
tabla_dai[j].playback.stream_name, 13)) {
@@ -4121,7 +4163,8 @@
case SND_SOC_DAPM_POST_PMD:
for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
if ((tabla_dai[j].id == AIF1_CAP) ||
- (tabla_dai[j].id == AIF2_CAP))
+ (tabla_dai[j].id == AIF2_CAP) ||
+ (tabla_dai[j].id == AIF3_CAP))
continue;
if (!strncmp(w->sname,
tabla_dai[j].playback.stream_name, 13)) {
@@ -4521,17 +4564,17 @@
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", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
0, tabla_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,
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
0, tabla_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", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
+ SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
0, tabla_codec_enable_slimtx,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -7406,6 +7449,9 @@
case AIF2_CAP:
ch_cnt = tabla_dai[i].capture.channels_max;
break;
+ case AIF3_CAP:
+ ch_cnt = tabla_dai[i].capture.channels_max;
+ break;
default:
continue;
}
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 392e05d..c8ef419 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -62,7 +62,9 @@
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
- SLIM_2_RX_1 = 147, /* HDMI 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_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 */
@@ -80,6 +82,7 @@
static int msm_ext_top_spk_pamp;
static int msm_slim_0_rx_ch = 1;
static int msm_slim_0_tx_ch = 1;
+static int msm_slim_3_rx_ch = 1;
static int msm_btsco_rate = BTSCO_RATE_8KHZ;
static int msm_btsco_ch = 1;
@@ -442,7 +445,7 @@
SND_SOC_DAPM_MIC("Digital Mic6", NULL),
};
-static const struct snd_soc_dapm_route apq8064_audio_map[] = {
+static const struct snd_soc_dapm_route apq8064_common_audio_map[] = {
{"RX_BIAS", NULL, "MCLK"},
{"LDO_H", NULL, "MCLK"},
@@ -457,13 +460,6 @@
{"Ext Spk Top Neg", NULL, "LINEOUT4"},
/************ Analog MIC Paths ************/
- /**
- * Analog mic7 (Front Top Mic) on Liquid.
- * Used as Handset mic on CDP.
- * Not there on MTP.
- */
- {"AMIC1", NULL, "MIC BIAS1 External"},
- {"MIC BIAS1 External", NULL, "Analog mic7"},
/* Headset Mic */
{"AMIC2", NULL, "MIC BIAS2 External"},
@@ -475,6 +471,59 @@
{"AMIC4", NULL, "MIC BIAS1 Internal2"},
{"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
+};
+
+static const struct snd_soc_dapm_route apq8064_mtp_audio_map[] = {
+
+ /************ Digital MIC Paths ************/
+
+ /*
+ * Digital Mic1 (Front bottom Left) on MTP.
+ * Conncted to DMIC1 Input on Tabla codec.
+ */
+ {"DMIC1", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic1"},
+
+ /**
+ * Digital Mic2 (Front bottom right) on MTP.
+ * Conncted to DMIC2 Input on Tabla codec.
+ */
+ {"DMIC2", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Digital Mic2"},
+
+ /**
+ * Digital Mic3 (Back bottom) on MTP.
+ * Conncted to DMIC3 Input on Tabla codec.
+ */
+ {"DMIC3", NULL, "MIC BIAS3 External"},
+ {"MIC BIAS3 External", NULL, "Digital Mic3"},
+
+ /**
+ * Digital Mic4 (Back top) on MTP.
+ * Conncted to DMIC4 Input on Tabla codec.
+ */
+ {"DMIC4", NULL, "MIC BIAS3 External"},
+ {"MIC BIAS3 External", NULL, "Digital Mic4"},
+
+ /**
+ * Digital Mic5 (Top front Mic) on MTP.
+ * Conncted to DMIC6 Input on Tabla codec.
+ */
+ {"DMIC6", NULL, "MIC BIAS4 External"},
+ {"MIC BIAS4 External", NULL, "Digital Mic5"},
+
+};
+
+static const struct snd_soc_dapm_route apq8064_liquid_cdp_audio_map[] = {
+
+ /************ Analog MIC Paths ************/
+ /**
+ * Analog mic7 (Front Top Mic) on Liquid.
+ * Used as Handset mic on CDP.
+ * Not there on MTP.
+ */
+ {"AMIC1", NULL, "MIC BIAS1 External"},
+ {"MIC BIAS1 External", NULL, "Analog mic7"},
/************ Digital MIC Paths ************/
@@ -590,6 +639,25 @@
return 1;
}
+static int msm_slim_3_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+ msm_slim_3_rx_ch);
+ ucontrol->value.integer.value[0] = msm_slim_3_rx_ch - 1;
+ return 0;
+}
+
+static int msm_slim_3_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_slim_3_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_slim_3_rx_ch = %d\n", __func__,
+ msm_slim_3_rx_ch);
+ return 1;
+}
+
static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -667,6 +735,24 @@
return 0;
}
+static const struct snd_kcontrol_new slim_3_mixer_controls[] = {
+ SOC_ENUM_EXT("SLIM_3_RX Channels", msm_enum[1],
+ msm_slim_3_rx_ch_get, msm_slim_3_rx_ch_put),
+};
+
+static int msm_slim_3_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int err = 0;
+ struct snd_soc_platform *platform = rtd->platform;
+
+ err = snd_soc_add_platform_controls(platform,
+ slim_3_mixer_controls,
+ ARRAY_SIZE(slim_3_mixer_controls));
+ if (err < 0)
+ return err;
+ return 0;
+}
+
static int msm_incall_rec_init(struct snd_soc_pcm_runtime *rtd)
{
int err = 0;
@@ -799,6 +885,13 @@
user_set_tx_ch = msm_slim_0_tx_ch;
else if (codec_dai->id == 4)
user_set_tx_ch = params_channels(params);
+ 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;
+ }
pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__,
codec_dai->name, codec_dai->id, user_set_tx_ch);
@@ -873,6 +966,35 @@
return ret;
}
+static int msm_slimbus_3_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 *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[2] = {SLIM_3_RX_1, SLIM_3_RX_2};
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: slim_3_rx_ch %d, sch %d %d\n",
+ __func__, msm_slim_3_rx_ch,
+ rx_ch[0], rx_ch[1]);
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_3_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: Erorr %d setting SLIM_3 RX channel map\n",
+ __func__, ret);
+
+ goto end;
+ }
+ } else {
+ pr_err("%s: SLIMBUS_3_TX not defined for this DAI\n", __func__);
+ }
+
+end:
+ return ret;
+}
+
static int msm_slimbus_4_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -940,8 +1062,16 @@
snd_soc_dapm_new_controls(dapm, apq8064_dapm_widgets,
ARRAY_SIZE(apq8064_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, apq8064_audio_map,
- ARRAY_SIZE(apq8064_audio_map));
+ snd_soc_dapm_add_routes(dapm, apq8064_common_audio_map,
+ ARRAY_SIZE(apq8064_common_audio_map));
+
+ if (machine_is_apq8064_mtp()) {
+ snd_soc_dapm_add_routes(dapm, apq8064_mtp_audio_map,
+ ARRAY_SIZE(apq8064_mtp_audio_map));
+ } else {
+ snd_soc_dapm_add_routes(dapm, apq8064_liquid_cdp_audio_map,
+ ARRAY_SIZE(apq8064_liquid_cdp_audio_map));
+ }
snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
@@ -1039,6 +1169,22 @@
return 0;
}
+static int msm_slim_3_rx_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 = msm_slim_3_rx_ch;
+
+ return 0;
+}
+
static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1203,6 +1349,12 @@
.shutdown = msm_shutdown,
};
+static struct snd_soc_ops msm_slimbus_3_be_ops = {
+ .startup = msm_startup,
+ .hw_params = msm_slimbus_3_hw_params,
+ .shutdown = msm_shutdown,
+};
+
static struct snd_soc_ops msm_slimbus_4_be_ops = {
.startup = msm_startup,
.hw_params = msm_slimbus_4_hw_params,
@@ -1451,7 +1603,7 @@
.codec_name = "tabla_codec",
.codec_dai_name = "tabla_rx2",
.no_pcm = 1,
- /* .be_id = do not care */
+ .be_id = MSM_BACKEND_DAI_EXTPROC_RX,
.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
.init = &msm_stubrx_init,
.ops = &msm_be_ops,
@@ -1464,7 +1616,7 @@
.codec_name = "tabla_codec",
.codec_dai_name = "tabla_tx1",
.no_pcm = 1,
- /* .be_id = do not care */
+ .be_id = MSM_BACKEND_DAI_EXTPROC_TX,
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm_be_ops,
},
@@ -1500,6 +1652,7 @@
.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,
},
@@ -1533,6 +1686,36 @@
.init = &msm_incall_rec_init,
.ops = &msm_slimbus_4_be_ops,
},
+ {
+ .name = LPASS_BE_STUB_1_TX,
+ .stream_name = "Stub1 Capture",
+ .cpu_dai_name = "msm-dai-stub",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tabla_codec",
+ .codec_dai_name = "tabla_tx3",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_EXTPROC_EC_TX,
+ /* This BE 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.
+ */
+ .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ },
+ {
+
+ .name = LPASS_BE_SLIMBUS_3_RX,
+ .stream_name = "Slimbus3 Playback",
+ .cpu_dai_name = "msm-dai-q6.16390",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-rx",
+ .init = &msm_slim_3_init,
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ .be_hw_params_fixup = msm_slim_3_rx_be_hw_params_fixup,
+ .ops = &msm_slimbus_3_be_ops,
+ },
};
struct snd_soc_card snd_soc_card_msm = {
diff --git a/sound/soc/msm/mpq8064.c b/sound/soc/msm/mpq8064.c
index c32527c..50f527f 100644
--- a/sound/soc/msm/mpq8064.c
+++ b/sound/soc/msm/mpq8064.c
@@ -1331,7 +1331,7 @@
{
.name = LPASS_BE_MI2S_TX,
.stream_name = "MI2S Capture",
- .cpu_dai_name = "msm-dai-q6.7",
+ .cpu_dai_name = "msm-dai-q6-mi2s",
.platform_name = "msm-pcm-routing",
.codec_name = "msm-stub-codec.1",
.codec_dai_name = "msm-stub-tx",
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 69d7185..fb7756c 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -36,9 +36,17 @@
DECLARE_BITMAP(status_mask, STATUS_MAX);
u32 rate;
u32 channels;
+ u32 bitwidth;
union afe_port_config port_config;
};
+struct msm_dai_q6_mi2s_dai_data {
+ struct msm_dai_q6_dai_data tx_dai;
+ struct msm_dai_q6_dai_data rx_dai;
+ struct snd_pcm_hw_constraint_list rate_constraint;
+ struct snd_pcm_hw_constraint_list bitwidth_constraint;
+};
+
static struct clk *pcm_clk;
static DEFINE_MUTEX(aux_pcm_mutex);
static int aux_pcm_count;
@@ -106,6 +114,316 @@
return num_bits_set;
}
+static int msm_dai_q6_mi2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+
+ dev_dbg(dai->dev, "%s: cnst list %p\n", __func__,
+ mi2s_dai_data->rate_constraint.list);
+
+ if (mi2s_dai_data->rate_constraint.list) {
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &mi2s_dai_data->rate_constraint);
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+ &mi2s_dai_data->bitwidth_constraint);
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+
+ dai_data->channels = params_channels(params);
+ switch (dai_data->channels) {
+ case 2:
+ dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
+ break;
+ case 1:
+ dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
+ break;
+ default:
+ pr_warn("greater than stereo has not been validated");
+ break;
+ }
+ dai_data->rate = params_rate(params);
+ dai_data->port_config.mi2s.bitwidth = 16;
+ dai_data->bitwidth = 16;
+ if (!mi2s_dai_data->rate_constraint.list) {
+ mi2s_dai_data->rate_constraint.list = &dai_data->rate;
+ mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
+ }
+ return 0;
+}
+
+static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
+ unsigned int *ch_cnt)
+{
+ u8 num_of_sd_lines;
+
+ num_of_sd_lines = num_of_bits_set(sd_lines);
+
+ switch (num_of_sd_lines) {
+ case 0:
+ pr_debug("%s: no line is assigned\n", __func__);
+ break;
+ case 1:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0:
+ *config_ptr = AFE_I2S_SD0;
+ break;
+ case MSM_MI2S_SD1:
+ *config_ptr = AFE_I2S_SD1;
+ break;
+ case MSM_MI2S_SD2:
+ *config_ptr = AFE_I2S_SD2;
+ break;
+ case MSM_MI2S_SD3:
+ *config_ptr = AFE_I2S_SD3;
+ break;
+ default:
+ pr_err("%s: invalid SD line\n",
+ __func__);
+ goto error_invalid_data;
+ }
+ break;
+ case 2:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0 | MSM_MI2S_SD1:
+ *config_ptr = AFE_I2S_QUAD01;
+ break;
+ case MSM_MI2S_SD2 | MSM_MI2S_SD3:
+ *config_ptr = AFE_I2S_QUAD23;
+ break;
+ default:
+ pr_err("%s: invalid SD line\n",
+ __func__);
+ goto error_invalid_data;
+ }
+ break;
+ case 3:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
+ *config_ptr = AFE_I2S_6CHS;
+ break;
+ default:
+ pr_err("%s: invalid SD lines\n",
+ __func__);
+ goto error_invalid_data;
+ }
+ break;
+ case 4:
+ switch (sd_lines) {
+ case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
+ *config_ptr = AFE_I2S_8CHS;
+ break;
+ default:
+ pr_err("%s: invalid SD lines\n",
+ __func__);
+ goto error_invalid_data;
+ }
+ break;
+ default:
+ pr_err("%s: invalid SD lines\n", __func__);
+ goto error_invalid_data;
+ }
+
+ *ch_cnt = num_of_sd_lines;
+
+ return 0;
+
+error_invalid_data:
+ return -EINVAL;
+}
+
+static int msm_dai_q6_mi2s_platform_data_validation(
+ struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
+{
+ struct msm_dai_q6_mi2s_dai_data *dai_data = dev_get_drvdata(&pdev->dev);
+ struct msm_mi2s_pdata *mi2s_pdata =
+ (struct msm_mi2s_pdata *) pdev->dev.platform_data;
+ u16 sdline_config;
+ unsigned int ch_cnt;
+ int rc = 0;
+
+ if ((mi2s_pdata->rx_sd_lines & mi2s_pdata->tx_sd_lines) ||
+ (!mi2s_pdata->rx_sd_lines && !mi2s_pdata->tx_sd_lines)) {
+ dev_err(&pdev->dev,
+ "error sd line conflict or no line assigned\n");
+ rc = -EINVAL;
+ goto rtn;
+ }
+
+ rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->rx_sd_lines,
+ &sdline_config, &ch_cnt);
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&pdev->dev, "invalid MI2S RX sd line config\n");
+ goto rtn;
+ }
+
+ if (ch_cnt) {
+ dai_data->rx_dai.port_config.mi2s.line = sdline_config;
+ dai_driver->playback.channels_min = 1;
+ dai_driver->playback.channels_max = ch_cnt << 1;
+ } else {
+ dai_driver->playback.channels_min = 0;
+ dai_driver->playback.channels_max = 0;
+ }
+ rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->tx_sd_lines,
+ &sdline_config, &ch_cnt);
+
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(&pdev->dev, "invalid MI2S TX sd line config\n");
+ goto rtn;
+ }
+
+ if (ch_cnt) {
+ dai_data->tx_dai.port_config.mi2s.line = sdline_config;
+ dai_driver->capture.channels_min = 1;
+ dai_driver->capture.channels_max = ch_cnt << 1;
+ } else {
+ dai_driver->capture.channels_min = 0;
+ dai_driver->capture.channels_max = 0;
+ }
+
+ dev_info(&pdev->dev, "%s: playback sdline %x capture sdline %x\n",
+ __func__, dai_data->rx_dai.port_config.mi2s.line,
+ dai_data->tx_dai.port_config.mi2s.line);
+ dev_info(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
+ __func__, dai_driver->playback.channels_max,
+ dai_driver->capture.channels_max);
+rtn:
+ return rc;
+}
+
+static int msm_dai_q6_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+
+ if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) ||
+ test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+ dev_err(dai->dev, "%s: err chg i2s mode while dai running",
+ __func__);
+ return -EPERM;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ mi2s_dai_data->rx_dai.port_config.mi2s.ws = 1;
+ mi2s_dai_data->tx_dai.port_config.mi2s.ws = 1;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ mi2s_dai_data->rx_dai.port_config.mi2s.ws = 0;
+ mi2s_dai_data->tx_dai.port_config.mi2s.ws = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_mi2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ int rc = 0;
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ /* PORT START should be set if prepare called in active state */
+ rc = afe_q6_interface_prepare();
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to open AFE APR\n");
+ }
+ return rc;
+}
+
+static int msm_dai_q6_mi2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ MI2S_RX : MI2S_TX);
+ int rc = 0;
+
+ dev_dbg(dai->dev, "%s: cmd:%d dai_data->status_mask = %ld",
+ __func__, cmd, *dai_data->status_mask);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ afe_port_start_nowait(port_id,
+ &dai_data->port_config, dai_data->rate);
+ set_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ afe_port_stop_nowait(port_id);
+ clear_bit(STATUS_PORT_STARTED,
+ dai_data->status_mask);
+ }
+ break;
+
+ default:
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct msm_dai_q6_dai_data *dai_data =
+ (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
+ u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ MI2S_RX : MI2S_TX);
+ int rc = 0;
+
+ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ rc = afe_close(port_id);
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close AFE port\n");
+ clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+ }
+
+ if (!test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) &&
+ !test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+ mi2s_dai_data->rate_constraint.list = NULL;
+ mi2s_dai_data->bitwidth_constraint.list = NULL;
+ }
+
+}
+
static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai, int stream)
{
@@ -134,121 +452,6 @@
return 0;
}
-static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai, int stream)
-{
- struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
- struct msm_mi2s_data *mi2s_pdata =
- (struct msm_mi2s_data *) dai->dev->platform_data;
-
- dai_data->channels = params_channels(params);
- if (num_of_bits_set(mi2s_pdata->sd_lines) == 1) {
- switch (dai_data->channels) {
- case 2:
- dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
- break;
- case 1:
- dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
- break;
- default:
- pr_warn("greater than stereo has not been validated");
- break;
- }
- }
- dai_data->rate = params_rate(params);
- /* Q6 only supports 16 as now */
- dai_data->port_config.mi2s.bitwidth = 16;
-
- pr_debug("%s: format = %d, channel = %d, line = %d\n",
- __func__, dai_data->port_config.mi2s.format,
- dai_data->port_config.mi2s.channel,
- dai_data->port_config.mi2s.line);
- return 0;
-}
-
-static int msm_dai_q6_mi2s_platform_data_validation(
- struct snd_soc_dai *dai)
-{
- u8 num_of_sd_lines;
- struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
- struct msm_mi2s_data *mi2s_pdata =
- (struct msm_mi2s_data *)dai->dev->platform_data;
- struct snd_soc_dai_driver *dai_driver =
- (struct snd_soc_dai_driver *)dai->driver;
-
- num_of_sd_lines = num_of_bits_set(mi2s_pdata->sd_lines);
-
- switch (num_of_sd_lines) {
- case 1:
- switch (mi2s_pdata->sd_lines) {
- case MSM_MI2S_SD0:
- dai_data->port_config.mi2s.line = AFE_I2S_SD0;
- break;
- case MSM_MI2S_SD1:
- dai_data->port_config.mi2s.line = AFE_I2S_SD1;
- break;
- case MSM_MI2S_SD2:
- dai_data->port_config.mi2s.line = AFE_I2S_SD2;
- break;
- case MSM_MI2S_SD3:
- dai_data->port_config.mi2s.line = AFE_I2S_SD3;
- break;
- default:
- pr_err("%s: invalid SD line\n",
- __func__);
- goto error_invalid_data;
- }
- break;
- case 2:
- switch (mi2s_pdata->sd_lines) {
- case MSM_MI2S_SD0 | MSM_MI2S_SD1:
- dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
- break;
- case MSM_MI2S_SD2 | MSM_MI2S_SD3:
- dai_data->port_config.mi2s.line = AFE_I2S_QUAD23;
- break;
- default:
- pr_err("%s: invalid SD line\n",
- __func__);
- goto error_invalid_data;
- }
- break;
- case 3:
- switch (mi2s_pdata->sd_lines) {
- case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
- dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
- break;
- default:
- pr_err("%s: invalid SD lines\n",
- __func__);
- goto error_invalid_data;
- }
- break;
- case 4:
- switch (mi2s_pdata->sd_lines) {
- case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
- dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
- break;
- default:
- pr_err("%s: invalid SD lines\n",
- __func__);
- goto error_invalid_data;
- }
- break;
- default:
- pr_err("%s: invalid SD lines\n", __func__);
- goto error_invalid_data;
- }
- if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
- dai_driver->playback.channels_max = num_of_sd_lines << 1;
- else if (mi2s_pdata->capability == MSM_MI2S_CAP_TX)
- dai_driver->capture.channels_max = num_of_sd_lines << 1;
- return 0;
-
-error_invalid_data:
- return -EINVAL;
-}
-
static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
@@ -384,12 +587,10 @@
case SECONDARY_I2S_RX:
rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
break;
- case MI2S_RX:
- case MI2S_TX:
- rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
- break;
+
case SLIMBUS_0_RX:
case SLIMBUS_1_RX:
+ case SLIMBUS_3_RX:
case SLIMBUS_0_TX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
@@ -766,43 +967,68 @@
return 0;
}
+
static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
{
- struct msm_dai_q6_dai_data *dai_data;
- struct msm_mi2s_data *mi2s_pdata =
- (struct msm_mi2s_data *)dai->dev->platform_data;
- const struct snd_kcontrol_new *kcontrol;
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ struct snd_kcontrol *kcontrol = NULL;
int rc = 0;
- dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
- GFP_KERNEL);
+ if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
+ kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
+ &mi2s_dai_data->rx_dai);
+ rc = snd_ctl_add(dai->card->snd_card, kcontrol);
- if (!dai_data) {
- dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
- dai->id);
- rc = -ENOMEM;
- goto rtn;
- } else
- dev_set_drvdata(dai->dev, dai_data);
-
- rc = msm_dai_q6_mi2s_platform_data_validation(dai);
- if (rc != 0) {
- pr_err("%s: The msm_dai_q6_mi2s_platform_data_validation failed\n",
- __func__);
- kfree(dai_data);
- goto rtn;
+ if (IS_ERR_VALUE(rc)) {
+ dev_err(dai->dev, "%s: err add RX fmt ctl\n", __func__);
+ goto rtn;
+ }
}
- if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
- kcontrol = &mi2s_config_controls[0];
- else
- kcontrol = &mi2s_config_controls[2];
- rc = snd_ctl_add(dai->card->snd_card,
- snd_ctl_new1(kcontrol, dai_data));
+ if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
+ rc = snd_ctl_add(dai->card->snd_card,
+ snd_ctl_new1(&mi2s_config_controls[2],
+ &mi2s_dai_data->tx_dai));
+
+ if (IS_ERR_VALUE(rc)) {
+ if (kcontrol)
+ snd_ctl_remove(dai->card->snd_card, kcontrol);
+ dev_err(dai->dev, "%s: err add TX fmt ctl\n", __func__);
+ }
+ }
+
rtn:
return rc;
}
+static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
+{
+ struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
+ dev_get_drvdata(dai->dev);
+ int rc;
+
+ /* If AFE port is still up, close it */
+ if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
+ rc = afe_close(MI2S_RX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close MI2S_RX port\n");
+ clear_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->rx_dai.status_mask);
+ }
+ if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
+ rc = afe_close(MI2S_TX); /* can block */
+ if (IS_ERR_VALUE(rc))
+ dev_err(dai->dev, "fail to close MI2S_TX port\n");
+ clear_bit(STATUS_PORT_STARTED,
+ mi2s_dai_data->tx_dai.status_mask);
+ }
+ kfree(mi2s_dai_data);
+ snd_soc_unregister_dai(dai->dev);
+
+ return 0;
+}
+
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
{
struct msm_dai_q6_dai_data *dai_data;
@@ -866,8 +1092,6 @@
switch (dai->id) {
case PRIMARY_I2S_TX:
case PRIMARY_I2S_RX:
- case MI2S_RX:
- case MI2S_TX:
case SECONDARY_I2S_RX:
rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
break;
@@ -894,6 +1118,7 @@
switch (dai->id) {
case SLIMBUS_0_RX:
case SLIMBUS_1_RX:
+ case SLIMBUS_3_RX:
case SLIMBUS_4_RX:
/* channel number to be between 128 and 255. For RX port
* use channel numbers from 138 to 144, for TX port
@@ -947,6 +1172,15 @@
return rc;
}
+static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
+ .startup = msm_dai_q6_mi2s_startup,
+ .prepare = msm_dai_q6_mi2s_prepare,
+ .trigger = msm_dai_q6_mi2s_trigger,
+ .hw_params = msm_dai_q6_mi2s_hw_params,
+ .shutdown = msm_dai_q6_mi2s_shutdown,
+ .set_fmt = msm_dai_q6_mi2s_set_fmt,
+};
+
static struct snd_soc_dai_ops msm_dai_q6_ops = {
.prepare = msm_dai_q6_prepare,
.trigger = msm_dai_q6_trigger,
@@ -1169,32 +1403,25 @@
.remove = msm_dai_q6_dai_auxpcm_remove,
};
-static struct snd_soc_dai_driver msm_dai_q6_mi2s_rx_dai = {
+/* Channel min and max are initialized base on platform data */
+static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
.playback = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .channels_min = 1,
.rate_min = 8000,
.rate_max = 48000,
},
- .ops = &msm_dai_q6_ops,
- .probe = msm_dai_q6_dai_mi2s_probe,
- .remove = msm_dai_q6_dai_probe,
-};
-
-static struct snd_soc_dai_driver msm_dai_q6_mi2s_tx_dai = {
.capture = {
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
- .channels_min = 1,
- .rate_min = 8000,
- .rate_max = 48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
},
- .ops = &msm_dai_q6_ops,
+ .ops = &msm_dai_q6_mi2s_ops,
.probe = msm_dai_q6_dai_mi2s_probe,
- .remove = msm_dai_q6_dai_remove,
+ .remove = msm_dai_q6_dai_mi2s_remove,
};
static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
@@ -1241,6 +1468,21 @@
.remove = msm_dai_q6_dai_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_slimbus_3_rx_dai = {
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
+ SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
/* To do: change to register DAIs as batch */
static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
{
@@ -1264,14 +1506,7 @@
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_aux_pcm_tx_dai);
break;
- case MI2S_RX:
- rc = snd_soc_register_dai(&pdev->dev,
- &msm_dai_q6_mi2s_rx_dai);
- break;
- case MI2S_TX:
- rc = snd_soc_register_dai(&pdev->dev,
- &msm_dai_q6_mi2s_tx_dai);
- break;
+
case SLIMBUS_0_RX:
case SLIMBUS_4_RX:
rc = snd_soc_register_dai(&pdev->dev,
@@ -1294,6 +1529,10 @@
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_slimbus_2_tx_dai);
break;
+ case SLIMBUS_3_RX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_slimbus_3_rx_dai);
+ break;
case INT_BT_SCO_RX:
rc = snd_soc_register_dai(&pdev->dev,
&msm_dai_q6_bt_sco_rx_dai);
@@ -1338,6 +1577,49 @@
return 0;
}
+static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
+{
+ struct msm_dai_q6_mi2s_dai_data *dai_data;
+ int rc = 0;
+
+ dev_dbg(&pdev->dev, "%s: pdev %p dev %p\n", __func__, pdev, &pdev->dev);
+
+ dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
+ GFP_KERNEL);
+
+ if (!dai_data) {
+ dev_err(&pdev->dev, "fail to allocate dai data\n");
+ rc = -ENOMEM;
+ goto rtn;
+ } else
+ dev_set_drvdata(&pdev->dev, dai_data);
+
+ rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
+ &msm_dai_q6_mi2s_dai);
+ if (IS_ERR_VALUE(rc))
+ goto err_pdata;
+
+ dai_data->rate_constraint.count = 1;
+ dai_data->bitwidth_constraint.count = 1;
+ rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_mi2s_dai);
+
+ if (IS_ERR_VALUE(rc))
+ goto err_pdata;
+
+ return 0;
+
+err_pdata:
+ kfree(dai_data);
+rtn:
+ return rc;
+}
+
+static __devexit int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_dai(&pdev->dev);
+ return 0;
+}
+
static struct platform_driver msm_dai_q6_driver = {
.probe = msm_dai_q6_dev_probe,
.remove = msm_dai_q6_dev_remove,
@@ -1347,9 +1629,30 @@
},
};
+static struct platform_driver msm_dai_q6_mi2s_driver = {
+ .probe = msm_dai_q6_mi2s_dev_probe,
+ .remove = msm_dai_q6_mi2s_dev_remove,
+ .driver = {
+ .name = "msm-dai-q6-mi2s",
+ .owner = THIS_MODULE,
+ },
+};
+
static int __init msm_dai_q6_init(void)
{
- return platform_driver_register(&msm_dai_q6_driver);
+ int rc1, rc2;
+
+ rc1 = platform_driver_register(&msm_dai_q6_mi2s_driver);
+
+ if (IS_ERR_VALUE(rc1))
+ pr_err("%s: fail to register mi2s dai driver\n", __func__);
+
+ rc2 = platform_driver_register(&msm_dai_q6_driver);
+
+ if (IS_ERR_VALUE(rc2))
+ pr_err("%s: fail to register mi2s dai driver\n", __func__);
+
+ return (IS_ERR_VALUE(rc1) && IS_ERR_VALUE(rc2)) ? -1 : 0;
}
module_init(msm_dai_q6_init);
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 39ce436..ec0d947 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -333,21 +333,20 @@
kfree(prtd);
return -ENOMEM;
}
+
+ pr_debug("%s: session ID %d\n", __func__,
+ prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
+ prtd->cmd_ack = 1;
+
}
/* Capture path */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
runtime->hw = msm_pcm_hardware_capture;
}
- pr_debug("%s: session ID %d\n", __func__, prtd->audio_client->session);
-
- prtd->session_id = prtd->audio_client->session;
- msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
- prtd->session_id, substream->stream);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- prtd->cmd_ack = 1;
-
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
&constraints_sample_rates);
@@ -619,6 +618,7 @@
struct snd_pcm_runtime *runtime = substream->runtime;
struct msm_audio *prtd = runtime->private_data;
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+ struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct audio_buffer *buf;
int dir, ret;
int format = FORMAT_LINEAR_PCM;
@@ -641,6 +641,12 @@
kfree(prtd);
return -ENOMEM;
}
+
+ pr_debug("%s: session ID %d\n", __func__,
+ prtd->audio_client->session);
+ prtd->session_id = prtd->audio_client->session;
+ msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+ prtd->session_id, substream->stream);
}
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index 4f0e952..02cc6ce 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -134,6 +134,9 @@
{ SLIMBUS_1_TX, 0, 0, 0, 0, 0},
{ 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_EXTPROC_RX, 0, 0, 0, 0, 0},
+ { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
{ SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
};
@@ -150,6 +153,16 @@
{INVALID_SESSION, INVALID_SESSION},
};
+static uint8_t is_be_dai_extproc(int be_dai)
+{
+ if (be_dai == MSM_BACKEND_DAI_EXTPROC_RX ||
+ be_dai == MSM_BACKEND_DAI_EXTPROC_TX ||
+ be_dai == MSM_BACKEND_DAI_EXTPROC_EC_TX)
+ return 1;
+ else
+ return 0;
+}
+
static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
int path_type)
{
@@ -161,7 +174,7 @@
MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
@@ -200,7 +213,7 @@
fe_dai_map[fedai_id][session_type] = dspst_id;
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
@@ -243,7 +256,7 @@
if (eq_data[fedai_id].enable)
msm_send_eq_values(fedai_id);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
@@ -296,7 +309,7 @@
mutex_lock(&routing_lock);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
- if ((i != MSM_BACKEND_DAI_EXTPROC_RX) &&
+ if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
(test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
@@ -1166,6 +1179,12 @@
msm_routing_put_voice_stub_mixer),
};
+static const struct snd_kcontrol_new slimbus_3_rx_mixer_controls[] = {
+ SOC_SINGLE_EXT("Voice Stub", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ 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 tx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("PRI_TX_Voice", MSM_BACKEND_DAI_PRI_I2S_TX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@@ -1227,7 +1246,7 @@
};
static const struct snd_kcontrol_new tx_voice_stub_mixer_controls[] = {
- SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_RX,
+ SOC_SINGLE_EXT("STUB_TX_HL", MSM_BACKEND_DAI_EXTPROC_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
SOC_SINGLE_EXT("INTERNAL_BT_SCO_TX", MSM_BACKEND_DAI_INT_BT_SCO_TX,
@@ -1236,6 +1255,9 @@
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_SLIMBUS_1_TX,
MSM_FRONTEND_DAI_VOICE_STUB, 1, 0, msm_routing_get_voice_stub_mixer,
msm_routing_put_voice_stub_mixer),
+ SOC_SINGLE_EXT("STUB_1_TX_HL", MSM_BACKEND_DAI_EXTPROC_EC_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[] = {
@@ -1268,6 +1290,11 @@
msm_routing_put_port_mixer),
};
+static const struct snd_kcontrol_new sbus_3_rx_port_mixer_controls[] = {
+ SOC_SINGLE_EXT("INTERNAL_BT_SCO_RX", MSM_BACKEND_DAI_SLIMBUS_3_RX,
+ MSM_BACKEND_DAI_INT_BT_SCO_RX, 1, 0, msm_routing_get_port_mixer,
+ msm_routing_put_port_mixer),
+};
static const struct snd_kcontrol_new bt_sco_rx_port_mixer_controls[] = {
SOC_SINGLE_EXT("SLIM_1_TX", MSM_BACKEND_DAI_INT_BT_SCO_RX,
MSM_BACKEND_DAI_SLIMBUS_1_TX, 1, 0, msm_routing_get_port_mixer,
@@ -1580,6 +1607,8 @@
SND_SOC_DAPM_AIF_IN("STUB_TX", "Stub Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0),
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),
/* Switch Definitions */
SND_SOC_DAPM_SWITCH("SLIMBUS_DL_HL", SND_SOC_NOPM, 0, 0,
@@ -1659,6 +1688,8 @@
stub_rx_mixer_controls, ARRAY_SIZE(stub_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIMBUS_1_RX Mixer", SND_SOC_NOPM, 0, 0,
slimbus_1_rx_mixer_controls, ARRAY_SIZE(slimbus_1_rx_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_3_RX_Voice Mixer", SND_SOC_NOPM, 0, 0,
+ slimbus_3_rx_mixer_controls, ARRAY_SIZE(slimbus_3_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Port Mixer",
SND_SOC_NOPM, 0, 0, sbus_0_rx_port_mixer_controls,
ARRAY_SIZE(sbus_0_rx_port_mixer_controls)),
@@ -1680,6 +1711,9 @@
SND_SOC_DAPM_MIXER("SEC_I2S_RX Port Mixer",
SND_SOC_NOPM, 0, 0, sec_i2s_rx_port_mixer_controls,
ARRAY_SIZE(sec_i2s_rx_port_mixer_controls)),
+ SND_SOC_DAPM_MIXER("SLIMBUS_3_RX Port Mixer",
+ SND_SOC_NOPM, 0, 0, sbus_3_rx_port_mixer_controls,
+ ARRAY_SIZE(sbus_3_rx_port_mixer_controls)),
};
static const struct snd_soc_dapm_route intercon[] = {
@@ -1845,6 +1879,7 @@
{"Voice Stub Tx Mixer", "STUB_TX_HL", "STUB_TX"},
{"Voice Stub Tx Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"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_UL", NULL, "Voice Stub Tx Mixer"},
{"STUB_RX Mixer", "Voice Stub", "VOICE_STUB_DL"},
@@ -1853,10 +1888,16 @@
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Mixer"},
{"INTERNAL_BT_SCO_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"},
+
{"SLIMBUS_1_RX Port Mixer", "INTERNAL_BT_SCO_TX", "INT_BT_SCO_TX"},
{"SLIMBUS_1_RX", NULL, "SLIMBUS_1_RX Port Mixer"},
{"INTERNAL_BT_SCO_RX Port Mixer", "SLIM_1_TX", "SLIMBUS_1_TX"},
{"INT_BT_SCO_RX", NULL, "INTERNAL_BT_SCO_RX Port Mixer"},
+ {"SLIMBUS_3_RX Port Mixer", "INTERNAL_BT_SCO_RX", "INT_BT_SCO_RX"},
+ {"SLIMBUS_3_RX", NULL, "SLIMBUS_3_RX Port Mixer"},
+
{"HDMI_RX Port Mixer", "MI2S_TX", "MI2S_TX"},
{"HDMI", NULL, "HDMI_RX Port Mixer"},
diff --git a/sound/soc/msm/msm-pcm-routing.h b/sound/soc/msm/msm-pcm-routing.h
index b7c7631..5f5c12a 100644
--- a/sound/soc/msm/msm-pcm-routing.h
+++ b/sound/soc/msm/msm-pcm-routing.h
@@ -37,7 +37,8 @@
#define LPASS_BE_STUB_TX "(Backend) STUB_TX"
#define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
#define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
-
+#define LPASS_BE_STUB_1_TX "(Backend) STUB_1_TX"
+#define LPASS_BE_SLIMBUS_3_RX "(Backend) SLIMBUS_3_RX"
#define LPASS_BE_SLIMBUS_4_RX "(Backend) SLIMBUS_4_RX"
#define LPASS_BE_SLIMBUS_4_TX "(Backend) SLIMBUS_4_TX"
@@ -88,7 +89,10 @@
MSM_BACKEND_DAI_SLIMBUS_1_TX,
MSM_BACKEND_DAI_SLIMBUS_4_RX,
MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ MSM_BACKEND_DAI_SLIMBUS_3_RX,
MSM_BACKEND_DAI_EXTPROC_RX,
+ MSM_BACKEND_DAI_EXTPROC_TX,
+ MSM_BACKEND_DAI_EXTPROC_EC_TX,
MSM_BACKEND_DAI_MAX,
};
diff --git a/sound/soc/msm/msm7201.c b/sound/soc/msm/msm7201.c
index a6a3266..2a73fd6 100644
--- a/sound/soc/msm/msm7201.c
+++ b/sound/soc/msm/msm7201.c
@@ -48,6 +48,7 @@
unsigned long vers;
unsigned long vers2;
unsigned long rpc_set_snd_device;
+ unsigned long rpc_set_device_vol;
int device;
};
@@ -125,6 +126,7 @@
* index for snd_set_device
*/
snd_rpc_ids.rpc_set_snd_device = 2;
+ snd_rpc_ids.rpc_set_device_vol = 3;
return 0;
}
@@ -235,6 +237,67 @@
return rc;
}
+static int snd_msm_device_vol_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2; /* Device/Volume */
+
+ /*
+ * The number of devices supported is 37 (0 to 36)
+ */
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 36;
+ return 0;
+}
+
+static int snd_msm_device_vol_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_vol_req {
+ struct rpc_request_hdr hdr;
+ uint32_t device;
+ uint32_t method;
+ uint32_t volume;
+ uint32_t cb_func;
+ uint32_t client_data;
+ } req;
+
+ snd_rpc_ids.device = (int)ucontrol->value.integer.value[0];
+
+ if ((ucontrol->value.integer.value[1] < 0) ||
+ (ucontrol->value.integer.value[1] > 6)) {
+ pr_err("Device volume should be in range of 1 to 6\n");
+ return -EINVAL;
+ }
+ if ((ucontrol->value.integer.value[0] > 36) ||
+ (ucontrol->value.integer.value[0] < 0)) {
+ pr_err("Device range supported is 0 to 36\n");
+ return -EINVAL;
+ }
+
+ req.device = cpu_to_be32((int)ucontrol->value.integer.value[0]);
+ req.method = cpu_to_be32(0);
+ req.volume = cpu_to_be32((int)ucontrol->value.integer.value[1]);
+ req.cb_func = -1;
+ req.client_data = cpu_to_be32(0);
+
+ rc = msm_rpc_call(snd_ep, snd_rpc_ids.rpc_set_device_vol ,
+ &req, sizeof(req), 5 * HZ);
+
+ if (rc < 0) {
+ printk(KERN_ERR "%s: snd rpc call failed! rc = %d\n",
+ __func__, rc);
+ } else {
+ printk(KERN_ERR "%s: device [%d] volume set to [%d]\n",
+ __func__, (int)ucontrol->value.integer.value[0],
+ (int)ucontrol->value.integer.value[1]);
+ }
+
+ return rc;
+}
+
/* Supported range -50dB to 18dB */
static const DECLARE_TLV_DB_LINEAR(db_scale_linear, -5000, 1800);
@@ -262,6 +325,8 @@
snd_msm_volume_get, snd_msm_volume_put, 0, db_scale_linear),
MSM_EXT("device", 0, snd_msm_device_info, snd_msm_device_get, \
snd_msm_device_put, 0),
+ MSM_EXT("Device Volume", 0, snd_msm_device_vol_info, NULL, \
+ snd_msm_device_vol_put, 0),
};
static int msm_new_mixer(struct snd_soc_codec *codec)
diff --git a/sound/soc/msm/msm8660-apq-wm8903.c b/sound/soc/msm/msm8660-apq-wm8903.c
index 15a01d7..e697c3f 100644
--- a/sound/soc/msm/msm8660-apq-wm8903.c
+++ b/sound/soc/msm/msm8660-apq-wm8903.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
@@ -188,7 +188,7 @@
return ret;
}
- wm8903_mclk = clk_get(NULL, "i2s_mic_osr_clk");
+ wm8903_mclk = clk_get_sys(NULL, "i2s_mic_osr_clk");
if (IS_ERR(wm8903_mclk)) {
pr_err("Failed to get i2s_mic_osr_clk\n");
gpio_free(MSM_CDC_MIC_I2S_MCLK);
@@ -308,7 +308,7 @@
pr_err("cpu_dai set_fmt error\n");
return ret;
}
- spkr_osr_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+ spkr_osr_clk = clk_get_sys(NULL, "i2s_spkr_osr_clk");
if (IS_ERR(spkr_osr_clk)) {
pr_err("Failed to get i2s_spkr_osr_clk\n");
return PTR_ERR(spkr_osr_clk);
@@ -320,7 +320,7 @@
clk_put(spkr_osr_clk);
return ret;
}
- spkr_bit_clk = clk_get(NULL, "i2s_spkr_bit_clk");
+ spkr_bit_clk = clk_get_sys(NULL, "i2s_spkr_bit_clk");
if (IS_ERR(spkr_bit_clk)) {
pr_err("Failed to get i2s_spkr_bit_clk\n");
clk_disable_unprepare(spkr_osr_clk);
@@ -351,7 +351,7 @@
return ret;
}
- mic_bit_clk = clk_get(NULL, "i2s_mic_bit_clk");
+ mic_bit_clk = clk_get_sys(NULL, "i2s_mic_bit_clk");
if (IS_ERR(mic_bit_clk)) {
pr_err("Failed to get i2s_mic_bit_clk\n");
return PTR_ERR(mic_bit_clk);
diff --git a/sound/soc/msm/msm8930.c b/sound/soc/msm/msm8930.c
index 04b0fb0..3f7e399 100644
--- a/sound/soc/msm/msm8930.c
+++ b/sound/soc/msm/msm8930.c
@@ -13,7 +13,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio.h>
-#include <linux/mfd/pm8xxx/misc.h>
+#include <linux/mfd/pm8xxx/spk.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -36,6 +36,8 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+#define SPK_AMP_POS 0x1
+#define SPK_AMP_NEG 0x2
#define SITAR_EXT_CLK_RATE 12288000
#define SITAR_MBHC_DEF_BUTTONS 3
@@ -45,6 +47,7 @@
static int msm8930_slim_0_rx_ch = 1;
static int msm8930_slim_0_tx_ch = 1;
+static int msm8930_ext_spk_pamp;
static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
static int msm8930_btsco_ch = 1;
@@ -55,7 +58,24 @@
static struct snd_soc_jack hs_jack;
static struct snd_soc_jack button_jack;
-static void *sitar_mbhc_cal;
+
+static int msm8930_enable_codec_ext_clk(
+ struct snd_soc_codec *codec, int enable,
+ bool dapm);
+
+static struct sitar_mbhc_config mbhc_cfg = {
+ .headset_jack = &hs_jack,
+ .button_jack = &button_jack,
+ .read_fw_bin = false,
+ .calibration = NULL,
+ .micbias = SITAR_MICBIAS2,
+ .mclk_cb_fn = msm8930_enable_codec_ext_clk,
+ .mclk_rate = SITAR_EXT_CLK_RATE,
+ .gpio = 0,
+ .gpio_irq = 0,
+ .gpio_level_insert = 1,
+};
+
static void msm8930_ext_control(struct snd_soc_codec *codec)
{
@@ -94,16 +114,87 @@
return 1;
}
+static void msm8960_ext_spk_power_amp_on(u32 spk)
+{
+ if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+ if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+ (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+ pr_debug("%s() External Bottom Speaker Ampl already "
+ "turned on. spk = 0x%08x\n", __func__, spk);
+ return;
+ }
+
+ msm8930_ext_spk_pamp |= spk;
+
+ if ((msm8930_ext_spk_pamp & SPK_AMP_POS) &&
+ (msm8930_ext_spk_pamp & SPK_AMP_NEG)) {
+
+ pm8xxx_spk_enable(MSM8930_SPK_ON);
+ pr_debug("%s: slepping 4 ms after turning on external "
+ " Left Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+ }
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
+static void msm8960_ext_spk_power_amp_off(u32 spk)
+{
+ if (spk & (SPK_AMP_POS | SPK_AMP_NEG)) {
+ if (!msm8930_ext_spk_pamp)
+ return;
+
+ pm8xxx_spk_enable(MSM8930_SPK_OFF);
+ msm8930_ext_spk_pamp = 0;
+ pr_debug("%s: slepping 4 ms after turning on external "
+ " Left Speaker Ampl\n", __func__);
+ usleep_range(4000, 4000);
+
+ } else {
+
+ pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
+ __func__, spk);
+ return;
+ }
+}
+
static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
- /* TODO: add external speaker power amps support */
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+ msm8960_ext_spk_power_amp_on(SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+ msm8960_ext_spk_power_amp_on(SPK_AMP_NEG);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ } else {
+ if (!strncmp(w->name, "Ext Spk Left Pos", 17))
+ msm8960_ext_spk_power_amp_off(SPK_AMP_POS);
+ else if (!strncmp(w->name, "Ext Spk Left Neg", 17))
+ msm8960_ext_spk_power_amp_off(SPK_AMP_NEG);
+ else {
+ pr_err("%s() Invalid Speaker Widget = %s\n",
+ __func__, w->name);
+ return -EINVAL;
+ }
+ }
return 0;
}
-int msm8930_enable_codec_ext_clk(
- struct snd_soc_codec *codec, int enable)
+static int msm8930_enable_codec_ext_clk(
+ struct snd_soc_codec *codec, int enable,
+ bool dapm)
{
pr_debug("%s: enable = %d\n", __func__, enable);
if (enable) {
@@ -115,7 +206,7 @@
if (codec_clk) {
clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
clk_prepare_enable(codec_clk);
- sitar_mclk_enable(codec, 1);
+ sitar_mclk_enable(codec, 1, dapm);
} else {
pr_err("%s: Error setting Sitar MCLK\n", __func__);
clk_users--;
@@ -129,7 +220,7 @@
if (!clk_users) {
pr_debug("%s: disabling MCLK. clk_users = %d\n",
__func__, clk_users);
- sitar_mclk_enable(codec, 0);
+ sitar_mclk_enable(codec, 0, dapm);
clk_disable_unprepare(codec_clk);
}
}
@@ -143,9 +234,9 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
- return msm8930_enable_codec_ext_clk(w->codec, 1);
+ return msm8930_enable_codec_ext_clk(w->codec, 1, true);
case SND_SOC_DAPM_POST_PMD:
- return msm8930_enable_codec_ext_clk(w->codec, 0);
+ return msm8930_enable_codec_ext_clk(w->codec, 0, true);
}
return 0;
}
@@ -156,7 +247,7 @@
msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
- SND_SOC_DAPM_SPK("Ext Spk Left Neg", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk Left Neg", msm8930_spkramp_event),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Digital Mic1", NULL),
@@ -520,6 +611,10 @@
}
codec_clk = clk_get(cpu_dai->dev, "osr_clk");
+ mbhc_cfg.gpio = 37;
+ mbhc_cfg.gpio_irq = gpio_to_irq(mbhc_cfg.gpio);
+ sitar_hs_detect(codec, &mbhc_cfg);
+
return 0;
}
@@ -978,8 +1073,8 @@
pr_err("%s: Not the right machine type\n", __func__);
return -ENODEV ;
}
- sitar_mbhc_cal = def_sitar_mbhc_cal();
- if (!sitar_mbhc_cal) {
+ mbhc_cfg.calibration = def_sitar_mbhc_cal();
+ if (!mbhc_cfg.calibration) {
pr_err("Calibration data allocation failed\n");
return -ENOMEM;
}
@@ -987,7 +1082,7 @@
msm8930_snd_device = platform_device_alloc("soc-audio", 0);
if (!msm8930_snd_device) {
pr_err("Platform device allocation failed\n");
- kfree(sitar_mbhc_cal);
+ kfree(mbhc_cfg.calibration);
return -ENOMEM;
}
@@ -995,7 +1090,7 @@
ret = platform_device_add(msm8930_snd_device);
if (ret) {
platform_device_put(msm8930_snd_device);
- kfree(sitar_mbhc_cal);
+ kfree(mbhc_cfg.calibration);
return ret;
}
@@ -1018,7 +1113,7 @@
}
msm8930_free_headset_mic_gpios();
platform_device_unregister(msm8930_snd_device);
- kfree(sitar_mbhc_cal);
+ kfree(mbhc_cfg.calibration);
}
module_exit(msm8930_audio_exit);
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 40f81e8..f78f58d 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1370,6 +1370,7 @@
.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,
},
@@ -1410,6 +1411,7 @@
.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,
},
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index dc120b08..9f058b9 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -147,6 +147,7 @@
case HDMI_RX:
case SLIMBUS_0_RX:
case SLIMBUS_1_RX:
+ case SLIMBUS_3_RX:
case INT_BT_SCO_RX:
case INT_BT_A2DP_RX:
case INT_FM_RX:
@@ -206,6 +207,7 @@
case SLIMBUS_1_RX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
case INT_BT_SCO_RX:
case INT_BT_SCO_TX:
case INT_BT_A2DP_RX:
@@ -271,6 +273,7 @@
case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+ case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
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;
@@ -305,6 +308,7 @@
case SLIMBUS_1_RX:
case SLIMBUS_1_TX:
case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
case SLIMBUS_4_RX:
case SLIMBUS_4_TX:
ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
@@ -676,7 +680,7 @@
return ret;
}
-int afe_loopback(u16 enable, u16 rx_port, u16 tx_port)
+int afe_loopback(u16 enable, u16 dst_port, u16 src_port)
{
struct afe_loopback_command lb_cmd;
int ret = 0;
@@ -685,6 +689,11 @@
if (ret != 0)
return ret;
+ if ((afe_get_port_type(dst_port) == MSM_AFE_PORT_TYPE_RX) &&
+ (afe_get_port_type(src_port) == MSM_AFE_PORT_TYPE_RX))
+ return afe_loopback_cfg(enable, dst_port, src_port,
+ LB_MODE_EC_REF_VOICE_AUDIO);
+
lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(20), APR_PKT_VER);
lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
@@ -693,8 +702,8 @@
lb_cmd.hdr.dest_port = 0;
lb_cmd.hdr.token = 0;
lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
- lb_cmd.tx_port_id = tx_port;
- lb_cmd.rx_port_id = rx_port;
+ lb_cmd.tx_port_id = src_port;
+ lb_cmd.rx_port_id = dst_port;
lb_cmd.mode = 0xFFFF;
lb_cmd.enable = (enable ? 1 : 0);
atomic_set(&this_afe.state, 1);
@@ -716,6 +725,63 @@
return ret;
}
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode)
+{
+ struct afe_port_cmd_set_param lp_cfg;
+ int ret = 0;
+
+ ret = afe_q6_interface_prepare();
+ if (ret != 0)
+ return ret;
+
+ pr_debug("%s: src_port %d, dst_port %d\n",
+ __func__, src_port, dst_port);
+
+ lp_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ lp_cfg.hdr.pkt_size = sizeof(lp_cfg);
+ lp_cfg.hdr.src_port = 0;
+ lp_cfg.hdr.dest_port = 0;
+ lp_cfg.hdr.token = 0;
+ lp_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+
+ lp_cfg.port_id = src_port;
+ lp_cfg.payload_size = sizeof(struct afe_param_payload);
+ lp_cfg.payload_address = 0;
+
+ lp_cfg.payload.module_id = AFE_MODULE_LOOPBACK;
+ lp_cfg.payload.param_id = AFE_PARAM_ID_LOOPBACK_CONFIG;
+ lp_cfg.payload.param_size = sizeof(struct afe_param_loopback_cfg);
+ lp_cfg.payload.reserved = 0;
+
+ lp_cfg.payload.param.loopback_cfg.loopback_cfg_minor_version =
+ AFE_API_VERSION_LOOPBACK_CONFIG;
+ lp_cfg.payload.param.loopback_cfg.dst_port_id = dst_port;
+ lp_cfg.payload.param.loopback_cfg.routing_mode = mode;
+ lp_cfg.payload.param.loopback_cfg.enable = enable;
+ lp_cfg.payload.param.loopback_cfg.reserved = 0;
+
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lp_cfg);
+ if (ret < 0) {
+ pr_err("%s: AFE loopback config failed for src_port %d, dst_port %d\n",
+ __func__, src_port, dst_port);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+
+ ret = wait_event_timeout(this_afe.wait,
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (ret < 0) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return ret;
+}
int afe_loopback_gain(u16 port_id, u16 volume)
{
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index f3a2383..ba5c79d 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1791,6 +1791,67 @@
return -EINVAL;
}
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+ uint32_t num_channels)
+{
+ struct asm_stream_cmd_encdec_channelmap chan_map;
+ u8 *channel_mapping;
+
+ int rc = 0;
+
+ pr_debug("%s: Session %d, num_channels = %d\n",
+ __func__, ac->session, num_channels);
+
+ q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
+
+ chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+ chan_map.param_id = ASM_ENCDEC_DEC_CHAN_MAP;
+ chan_map.param_size = sizeof(struct asm_dec_chan_map);
+ chan_map.chan_map.num_channels = num_channels;
+
+ channel_mapping =
+ chan_map.chan_map.channel_mapping;
+
+ memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
+ if (num_channels == 1) {
+ channel_mapping[0] = PCM_CHANNEL_FL;
+ } else if (num_channels == 2) {
+ channel_mapping[0] = PCM_CHANNEL_FL;
+ channel_mapping[1] = PCM_CHANNEL_FR;
+ } else if (num_channels == 6) {
+ channel_mapping[0] = PCM_CHANNEL_FC;
+ channel_mapping[1] = PCM_CHANNEL_FL;
+ channel_mapping[2] = PCM_CHANNEL_FR;
+ channel_mapping[3] = PCM_CHANNEL_LB;
+ channel_mapping[4] = PCM_CHANNEL_RB;
+ channel_mapping[5] = PCM_CHANNEL_LFE;
+ } else {
+ pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+ num_channels);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
+ if (rc < 0) {
+ pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+ __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+ ASM_ENCDEC_DEC_CHAN_MAP);
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s:timeout opcode[0x%x]\n", __func__,
+ chan_map.hdr.opcode);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+
int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
uint16_t min_rate, uint16_t max_rate,
uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index f4b4dd1..18a1f43 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -2217,14 +2217,8 @@
mvm_set_voice_timing.hdr.opcode = VSS_ICOMMON_CMD_SET_VOICE_TIMING;
mvm_set_voice_timing.timing.mode = 0;
mvm_set_voice_timing.timing.enc_offset = 8000;
- if (machine_is_apq8064_sim()) {
- pr_debug("%s: Machine is apq8064 sim\n", __func__);
- mvm_set_voice_timing.timing.dec_req_offset = 0;
- mvm_set_voice_timing.timing.dec_offset = 18000;
- } else {
- mvm_set_voice_timing.timing.dec_req_offset = 3300;
- mvm_set_voice_timing.timing.dec_offset = 8300;
- }
+ mvm_set_voice_timing.timing.dec_req_offset = 3300;
+ mvm_set_voice_timing.timing.dec_offset = 8300;
v->mvm_state = CMD_STATUS_FAIL;