Merge "vidc: Enable error concealment in video core" into msm-3.0
diff --git a/Documentation/devicetree/bindings/spmi/msm-spmi.txt b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
index fa91514..8fe415b 100644
--- a/Documentation/devicetree/bindings/spmi/msm-spmi.txt
+++ b/Documentation/devicetree/bindings/spmi/msm-spmi.txt
@@ -25,8 +25,8 @@
Second level
Required properties :
- - spmi-dev-container: Used by the parser to understand that this is the second
- level of the tree.
+ - spmi-slave-container: Used by the parser to understand that this is the
+ second level of the tree.
- reg: <a b> where a is < 65536 and b is a size. Each device supports an
arbitrary number of address ranges.
- compatible : "qcom," prefixed string to match against the driver.
@@ -50,7 +50,7 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0xd>;
- spmi-dev-container;
+ spmi-slave-container;
coincell@2800 {
compatible = "qcom,qpnp-coincell";
diff --git a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
index 8cc3c54..b5ca08e 100644
--- a/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
+++ b/Documentation/devicetree/bindings/spmi/spmi-pmic-arb.txt
@@ -17,6 +17,13 @@
Up to a maximum of 256 peripherals are supported and the mapping is target
specific.
+Data format of pmic-arb-ppid-map:
+<0x13100001>
+value is 32 bit.
+MSB 12 bits are the PPID
+12 bits padding
+LSB 8 bit are the APID
+
Example:
qcom,spmi@fc4c0000 {
@@ -27,6 +34,8 @@
interrupts = <0>;
qcom,pmic-arb-ee = <0>;
qcom,pmic-arb-channel = <0>;
- qcom,pmic-arb-ppid-map = <0x130 0x00>, /* PPID 0x130, APID 0 */
- <0x131 0x01>; /* PPID 0x131, APID 1 */
+ qcom,pmic-arb-ppid-map = <0x13000000>, /* PPID 0x130, APID 0 */
+ <0x13100001>, /* PPID 0x131, APID 1 */
};
+
+
diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt
new file mode 100644
index 0000000..7b590ed
--- /dev/null
+++ b/Documentation/usb/dwc3.txt
@@ -0,0 +1,45 @@
+
+ TODO
+~~~~~~
+Please pick something while reading :)
+
+- Convert interrupt handler to per-ep-thread-irq
+
+ As it turns out some DWC3-commands ~1ms to complete. Currently we spin
+ until the command completes which is bad.
+
+ Implementation idea:
+ - dwc core implements a demultiplexing irq chip for interrupts per
+ endpoint. The interrupt numbers are allocated during probe and belong
+ to the device. If MSI provides per-endpoint interrupt this dummy
+ interrupt chip can be replaced with "real" interrupts.
+ - interrupts are requested / allocated on usb_ep_enable() and removed on
+ usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
+ for ep0/1.
+ - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
+ until the command completes.
+ - the interrupt handler is split into the following pieces:
+ - primary handler of the device
+ goes through every event and calls generic_handle_irq() for event
+ it. On return from generic_handle_irq() in acknowledges the event
+ counter so interrupt goes away (eventually).
+
+ - threaded handler of the device
+ none
+
+ - primary handler of the EP-interrupt
+ reads the event and tries to process it. Everything that requries
+ sleeping is handed over to the Thread. The event is saved in an
+ per-endpoint data-structure.
+ We probably have to pay attention not to process events once we
+ handed something to thread so we don't process event X prio Y
+ where X > Y.
+
+ - threaded handler of the EP-interrupt
+ handles the remaining EP work which might sleep such as waiting
+ for command completion.
+
+ Latency:
+ There should be no increase in latency since the interrupt-thread has a
+ high priority and will be run before an average task in user land
+ (except the user changed priorities).
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0a7fe5f..f5046dc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -131,7 +131,7 @@
config GENERIC_LOCKBREAK
bool
- default y
+ default y if !ARM_TICKET_LOCKS
depends on SMP && PREEMPT
config ARM_TICKET_LOCKS
@@ -140,7 +140,7 @@
Enable ticket locks, which help preserve fairness among
contended locks and prevent livelock in multicore systems.
Say 'y' if system stability is important.
- default y if ARCH_MSM_SCORPIONMP
+ default y if ARCH_MSM_SCORPIONMP || ARCH_MSM_KRAITMP
depends on SMP
config RWSEM_GENERIC_SPINLOCK
diff --git a/arch/arm/boot/dts/msmcopper.dts b/arch/arm/boot/dts/msmcopper.dts
index 725971d..b9179a3 100644
--- a/arch/arm/boot/dts/msmcopper.dts
+++ b/arch/arm/boot/dts/msmcopper.dts
@@ -80,7 +80,7 @@
spi@f9924000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9924000 0x1000>;
- interrupts = <96>;
+ interrupts = <0 96 0>;
spi-max-frequency = <24000000>;
};
@@ -94,93 +94,96 @@
interrupts = <0 190 0 0 187 0>;
qcom,pmic-arb-ee = <0>;
qcom,pmic-arb-channel = <0>;
- qcom,pmic-arb-ppid-map = <0x130 0x00>, /* PM8941_LDO1 */
- <0x131 0x01>, /* PM8941_LDO2 */
- <0x132 0x02>, /* PM8941_LDO3 */
- <0x133 0x03>, /* PM8941_LDO4 */
- <0x134 0x04>, /* PM8941_LDO5 */
- <0x135 0x05>, /* PM8941_LDO6 */
- <0x136 0x06>, /* PM8941_LDO7 */
- <0x137 0x07>, /* PM8941_LDO8 */
- <0x138 0x08>, /* PM8941_LDO9 */
- <0x139 0x09>, /* PM8941_LDO10 */
- <0x13a 0x0a>, /* PM8941_LDO11 */
- <0x13b 0x0b>, /* PM8941_LDO12 */
- <0x13c 0x0c>, /* PM8941_LDO13 */
- <0x13d 0x0d>, /* PM8941_LDO14 */
- <0x13e 0x0e>, /* PM8941_LDO15 */
- <0x13f 0x0f>, /* PM8941_LDO16 */
- <0x140 0x10>, /* PM8941_LDO17 */
- <0x141 0x11>, /* PM8941_LDO18 */
- <0x142 0x12>, /* PM8941_LDO19 */
- <0x143 0x13>, /* PM8941_LDO20 */
- <0x144 0x14>, /* PM8941_LDO21 */
- <0x145 0x15>, /* PM8941_LDO22 */
- <0x146 0x16>, /* PM8941_LDO23 */
- <0x147 0x17>, /* PM8941_LDO24 */
- <0x148 0x18>, /* PM8941_LDO25 */
- <0x149 0x19>, /* PM8941_LDO26 */
- <0x0c0 0x1a>, /* PM8941_GPIO1 */
- <0x0c1 0x1b>, /* PM8941_GPIO2 */
- <0x0c2 0x1c>, /* PM8941_GPIO3 */
- <0x0c3 0x1d>, /* PM8941_GPIO4 */
- <0x0c4 0x1e>, /* PM8941_GPIO5 */
- <0x0c5 0x1f>, /* PM8941_GPIO6 */
- <0x0c6 0x20>, /* PM8941_GPIO7 */
- <0x0c7 0x21>, /* PM8941_GPIO8 */
- <0x0c8 0x22>, /* PM8941_GPIO9 */
- <0x0c9 0x23>, /* PM8941_GPIO10 */
- <0x0ca 0x24>, /* PM8941_GPIO11 */
- <0x0cb 0x25>, /* PM8941_GPIO12 */
- <0x0cc 0x26>, /* PM8941_GPIO13 */
- <0x0cd 0x27>, /* PM8941_GPIO14 */
- <0x0ce 0x28>, /* PM8941_GPIO15 */
- <0x0cf 0x29>, /* PM8941_GPIO16 */
- <0x0d0 0x2a>, /* PM8941_GPIO17 */
- <0x0d1 0x2b>, /* PM8941_GPIO18 */
- <0x0d2 0x2c>, /* PM8941_GPIO19 */
- <0x0d3 0x2d>, /* PM8941_GPIO20 */
- <0x0d4 0x2e>, /* PM8941_GPIO21 */
- <0x0d5 0x2f>, /* PM8941_GPIO22 */
- <0x0d6 0x30>, /* PM8941_GPIO23 */
- <0x0d7 0x31>, /* PM8941_GPIO24 */
- <0x0d8 0x32>, /* PM8941_GPIO25 */
- <0x0d9 0x33>, /* PM8941_GPIO26 */
- <0x0da 0x34>, /* PM8941_GPIO27 */
- <0x0db 0x35>, /* PM8941_GPIO28 */
- <0x0dc 0x36>, /* PM8941_GPIO29 */
- <0x0dd 0x37>, /* PM8941_GPIO30 */
- <0x0de 0x38>, /* PM8941_GPIO31 */
- <0x0df 0x39>, /* PM8941_GPIO32 */
- <0x0e0 0x3a>, /* PM8941_GPIO33 */
- <0x0e1 0x3b>, /* PM8941_GPIO34 */
- <0x0e2 0x3c>, /* PM8941_GPIO35 */
- <0x0e3 0x3d>, /* PM8941_GPIO36 */
- <0x028 0x3e>, /* COINCELL */
- <0x005 0x3f>, /* INTERRUPT */
- <0x001 0x40>, /* PM8941_0 */
- <0x201 0x41>, /* PM8841_0 */
- <0x101 0x42>, /* PM8941_1 */
- <0x301 0x43>, /* PM8841_1 */
- <0x008 0x44>, /* PON0 */
- <0x208 0x45>, /* PON1 */
- <0x110 0x46>, /* PM8941_SMPS1 */
- <0x111 0x47>, /* PM8941_SMPS2 */
- <0x112 0x48>, /* PM8941_SMPS3 */
- <0x310 0x49>, /* PM8841_SMPS1 */
- <0x311 0x4a>, /* PM8841_SMPS2 */
- <0x312 0x4b>, /* PM8841_SMPS3 */
- <0x313 0x4c>, /* PM8841_SMPS4 */
- <0x314 0x4d>, /* PM8841_SMPS5 */
- <0x315 0x4e>, /* PM8841_SMPS6 */
- <0x316 0x4f>, /* PM8841_SMPS7 */
- <0x317 0x50>, /* PM8841_SMPS8 */
- <0x050 0x51>, /* SHARED_XO */
- <0x051 0x52>, /* BB_CLK1 */
- <0x052 0x53>, /* BB_CLK2 */
- <0x059 0x54>, /* SLEEP_CLK */
- <0x010 0x55>, /* SMBC_OVP */
- <0x011 0x56>, /* SMBC_CHG */
- <0x012 0x57>; /* SMBC_BIF */
+ qcom,pmic-arb-ppid-map = <0x13000000>, /* PM8941_LDO1 */
+ <0x13100001>, /* PM8941_LDO2 */
+ <0x13200002>, /* PM8941_LDO3 */
+ <0x13300003>, /* PM8941_LDO4 */
+ <0x13400004>, /* PM8941_LDO5 */
+ <0x13500005>, /* PM8941_LDO6 */
+ <0x13600006>, /* PM8941_LDO7 */
+ <0x13700007>, /* PM8941_LDO8 */
+ <0x13800008>, /* PM8941_LDO9 */
+ <0x13900009>, /* PM8941_LDO10 */
+ <0x13a0000a>, /* PM8941_LDO11 */
+ <0x13b0000b>, /* PM8941_LDO12 */
+ <0x13c0000c>, /* PM8941_LDO13 */
+ <0x13d0000d>, /* PM8941_LDO14 */
+ <0x13e0000e>, /* PM8941_LDO15 */
+ <0x13f0000f>, /* PM8941_LDO16 */
+ <0x14000010>, /* PM8941_LDO17 */
+ <0x14100011>, /* PM8941_LDO18 */
+ <0x14200012>, /* PM8941_LDO19 */
+ <0x14300013>, /* PM8941_LDO20 */
+ <0x14400014>, /* PM8941_LDO21 */
+ <0x14500015>, /* PM8941_LDO22 */
+ <0x14600016>, /* PM8941_LDO23 */
+ <0x14700017>, /* PM8941_LDO24 */
+ <0x14800018>, /* PM8941_LDO25 */
+ <0x14900019>, /* PM8941_LDO26 */
+ <0x0c00001a>, /* PM8941_GPIO1 */
+ <0x0c10001b>, /* PM8941_GPIO2 */
+ <0x0c20001c>, /* PM8941_GPIO3 */
+ <0x0c30001d>, /* PM8941_GPIO4 */
+ <0x0c40001e>, /* PM8941_GPIO5 */
+ <0x0c50001f>, /* PM8941_GPIO6 */
+ <0x0c600020>, /* PM8941_GPIO7 */
+ <0x0c700021>, /* PM8941_GPIO8 */
+ <0x0c800022>, /* PM8941_GPIO9 */
+ <0x0c900023>, /* PM8941_GPIO10 */
+ <0x0ca00024>, /* PM8941_GPIO11 */
+ <0x0cb00025>, /* PM8941_GPIO12 */
+ <0x0cc00026>, /* PM8941_GPIO13 */
+ <0x0cd00027>, /* PM8941_GPIO14 */
+ <0x0ce00028>, /* PM8941_GPIO15 */
+ <0x0cf00029>, /* PM8941_GPIO16 */
+ <0x0d00002a>, /* PM8941_GPIO17 */
+ <0x0d10002b>, /* PM8941_GPIO18 */
+ <0x0d20002c>, /* PM8941_GPIO19 */
+ <0x0d30002d>, /* PM8941_GPIO20 */
+ <0x0d40002e>, /* PM8941_GPIO21 */
+ <0x0d50002f>, /* PM8941_GPIO22 */
+ <0x0d600030>, /* PM8941_GPIO23 */
+ <0x0d700031>, /* PM8941_GPIO24 */
+ <0x0d800032>, /* PM8941_GPIO25 */
+ <0x0d900033>, /* PM8941_GPIO26 */
+ <0x0da00034>, /* PM8941_GPIO27 */
+ <0x0db00035>, /* PM8941_GPIO28 */
+ <0x0dc00036>, /* PM8941_GPIO29 */
+ <0x0dd00037>, /* PM8941_GPIO30 */
+ <0x0de00038>, /* PM8941_GPIO31 */
+ <0x0df00039>, /* PM8941_GPIO32 */
+ <0x0e00003a>, /* PM8941_GPIO33 */
+ <0x0e10003b>, /* PM8941_GPIO34 */
+ <0x0e20003c>, /* PM8941_GPIO35 */
+ <0x0e30003d>, /* PM8941_GPIO36 */
+ <0x0280003e>, /* COINCELL */
+ <0x0100003f>, /* SMBC_OVP */
+ <0x01100040>, /* SMBC_CHG */
+ <0x01200041>, /* SMBC_BIF */
+ <0x00500042>, /* INTERRUPT */
+ <0x00100043>, /* PM8941_0 */
+ <0x20100044>, /* PM8841_0 */
+ <0x10100045>, /* PM8941_1 */
+ <0x30100046>, /* PM8841_1 */
+ <0x00800047>, /* PON0 */
+ <0x20800048>, /* PON1 */
+ <0x11000049>, /* PM8941_SMPS1 */
+ <0x1110004a>, /* PM8941_SMPS2 */
+ <0x1120004b>, /* PM8941_SMPS3 */
+ <0x3100004c>, /* PM8841_SMPS1 */
+ <0x3110004d>, /* PM8841_SMPS2 */
+ <0x3120004e>, /* PM8841_SMPS3 */
+ <0x3130004f>, /* PM8841_SMPS4 */
+ <0x31400050>, /* PM8841_SMPS5 */
+ <0x31500051>, /* PM8841_SMPS6 */
+ <0x31600052>, /* PM8841_SMPS7 */
+ <0x31700053>, /* PM8841_SMPS8 */
+ <0x05000054>, /* SHARED_XO */
+ <0x05100055>, /* BB_CLK1 */
+ <0x05200056>, /* BB_CLK2 */
+ <0x05900057>, /* SLEEP_CLK */
+ <0x07000058>, /* PBS_CORE */
+ <0x07100059>, /* PBS_CLIENT1 */
+ <0x0720005a>; /* PBS_CLIENT2 */
};
};
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 3d4b37d..c671d32 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -114,7 +114,6 @@
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
# CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_PMIC8058 is not set
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index ebff2d2..80252d8 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -112,7 +112,6 @@
CONFIG_INPUT_EVDEV=y
CONFIG_INPUT_EVBUG=m
# CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_KEYBOARD_PMIC8058 is not set
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_MISC=y
CONFIG_INPUT_UINPUT=y
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 58aece2..0b89d45 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -37,6 +37,10 @@
CONFIG_CPU_HAS_L2_PMU=y
# CONFIG_MSM_FIQ_SUPPORT is not set
# CONFIG_MSM_PROC_COMM is not set
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_PKG4=y
+CONFIG_MSM_IPC_ROUTER=y
+CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
# CONFIG_MSM_HW3D is not set
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_NO_HZ=y
@@ -102,6 +106,8 @@
# CONFIG_MFD_SUPPORT is not set
CONFIG_ION=y
CONFIG_ION_MSM=y
+CONFIG_FB=y
+CONFIG_FB_VIRTUAL=y
# CONFIG_HID_SUPPORT is not set
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_CI13XXX_MSM=y
@@ -168,13 +174,3 @@
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRC_CCITT=y
CONFIG_LIBCRC32C=y
-CONFIG_MSM_SMD=y
-CONFIG_MSM_SMD_PKG4=y
-CONFIG_MSM_SMD_PKT=y
-CONFIG_MSM_SMD_DEBUG=y
-CONFIG_MSM_SMD_TTY=y
-CONFIG_MSM_N_WAY_SMD=y
-CONFIG_MSM_N_WAY_SMSM=y
-CONFIG_MSM_SMD_LOGGING=y
-CONFIG_MSM_IPC_ROUTER=y
-CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
diff --git a/arch/arm/configs/msm7627a-perf_defconfig b/arch/arm/configs/msm7627a-perf_defconfig
index 446423d..2af5ce4 100644
--- a/arch/arm/configs/msm7627a-perf_defconfig
+++ b/arch/arm/configs/msm7627a-perf_defconfig
@@ -19,6 +19,7 @@
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
@@ -327,14 +328,13 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_SHIRQ=y
# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
-# CONFIG_FTRACE is not set
+CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index 642d843..0bbad62 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -19,6 +19,7 @@
CONFIG_SLAB=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
@@ -45,7 +46,6 @@
# CONFIG_MSM_HW3D is not set
CONFIG_MSM7X27A_AUDIO=y
CONFIG_MSM_DMA_TEST=y
-# CONFIG_MSM_JTAG_V7 is not set
CONFIG_MSM_SLEEP_STATS_DEVICE=y
CONFIG_BT_MSM_PINTEST=y
CONFIG_MSM_RPC_VIBRATOR=y
@@ -235,6 +235,7 @@
# CONFIG_MT9T013 is not set
# CONFIG_MT9D112 is not set
CONFIG_OV5640=y
+CONFIG_OV5647=y
CONFIG_WEBCAM_OV7692_QRD=y
CONFIG_WEBCAM_OV9726=y
# CONFIG_MT9P012 is not set
@@ -327,12 +328,11 @@
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DEBUG_SHIRQ=y
-# CONFIG_SCHED_DEBUG is not set
CONFIG_LOCKUP_DETECTOR=y
CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_SCHED_DEBUG is not set
CONFIG_TIMER_STATS=y
CONFIG_DEBUG_SLAB=y
CONFIG_DEBUG_SLAB_LEAK=y
@@ -342,9 +342,8 @@
CONFIG_DEBUG_STACK_USAGE=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_LIST=y
-CONFIG_LATENCYTOP=y
CONFIG_DEBUG_PAGEALLOC=y
-# CONFIG_FTRACE is not set
+CONFIG_ENABLE_DEFAULT_TRACERS=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_LL=y
@@ -352,4 +351,3 @@
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRC_CCITT=y
-CONFIG_OV5647=y
diff --git a/arch/arm/configs/msm7630-perf_defconfig b/arch/arm/configs/msm7630-perf_defconfig
index e319f0d..5466498 100644
--- a/arch/arm/configs/msm7630-perf_defconfig
+++ b/arch/arm/configs/msm7630-perf_defconfig
@@ -40,7 +40,6 @@
CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-# CONFIG_MSM_JTAG_V7 is not set
CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
@@ -223,7 +222,6 @@
CONFIG_INPUT_EVBUG=m
# CONFIG_KEYBOARD_ATKBD is not set
CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_MSM=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index b4babeb..1a70816 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -40,7 +40,6 @@
CONFIG_MSM_MEMORY_LOW_POWER_MODE_IDLE_RETENTION=y
CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN=y
CONFIG_MSM_IDLE_WAIT_ON_MODEM=2000
-# CONFIG_MSM_JTAG_V7 is not set
CONFIG_MSM_STANDALONE_POWER_COLLAPSE=y
CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
@@ -224,7 +223,6 @@
CONFIG_INPUT_EVBUG=m
# CONFIG_KEYBOARD_ATKBD is not set
CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_MSM=y
@@ -371,7 +369,6 @@
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
-# CONFIG_SCHED_DEBUG is not set
CONFIG_LOCKUP_DETECTOR=y
CONFIG_DETECT_HUNG_TASK=y
# CONFIG_SCHED_DEBUG is not set
@@ -380,7 +377,6 @@
CONFIG_DEBUG_SLAB=y
CONFIG_DEBUG_SLAB_LEAK=y
# CONFIG_DEBUG_PREEMPT is not set
-CONFIG_DEBUG_SPINLOCK=y
CONFIG_PROVE_LOCKING=y
CONFIG_DEBUG_SPINLOCK_SLEEP=y
CONFIG_DEBUG_STACK_USAGE=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index b3a45d2..13656418 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -70,7 +70,6 @@
CONFIG_MSM_RPM_STATS_LOG=y
CONFIG_MSM_WATCHDOG=y
CONFIG_MSM_DLOAD_MODE=y
-# CONFIG_MSM_JTAG_V7 is not set
CONFIG_MSM_ETM=y
CONFIG_MSM_SLEEP_STATS=y
CONFIG_MSM_GSBI9_UART=y
@@ -272,7 +271,6 @@
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_MATRIX=y
CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
@@ -299,7 +297,6 @@
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_SX150X=y
-# CONFIG_MPP_PMIC8901 is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_BATTERY_MSM is not set
CONFIG_BATTERY_MSM8X60=y
@@ -324,9 +321,9 @@
CONFIG_VIDEO_DEV=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_USB_VIDEO_CLASS=y
+CONFIG_IMX074=y
CONFIG_WEBCAM_OV9726=y
CONFIG_MT9E013=y
-CONFIG_IMX074=y
CONFIG_MSM_GEMINI=y
CONFIG_RADIO_TAVARUA=y
CONFIG_ION=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 1f511bb..fa4ba4e 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -271,7 +271,6 @@
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_MATRIX=y
CONFIG_KEYBOARD_PMIC8XXX=y
-# CONFIG_KEYBOARD_PMIC8058 is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH=y
@@ -299,7 +298,6 @@
CONFIG_DEBUG_GPIO=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_SX150X=y
-# CONFIG_MPP_PMIC8901 is not set
CONFIG_POWER_SUPPLY=y
# CONFIG_BATTERY_MSM is not set
CONFIG_BATTERY_MSM8X60=y
@@ -324,9 +322,9 @@
CONFIG_VIDEO_DEV=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
CONFIG_USB_VIDEO_CLASS=y
+CONFIG_IMX074=y
CONFIG_WEBCAM_OV9726=y
CONFIG_MT9E013=y
-CONFIG_IMX074=y
CONFIG_MSM_GEMINI=y
CONFIG_RADIO_TAVARUA=y
CONFIG_ION=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 152cb86..d14757b 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -191,8 +191,10 @@
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_MANGLE=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
@@ -227,7 +229,7 @@
CONFIG_BLK_DEV_RAM=y
CONFIG_HAPTIC_ISA1200=y
CONFIG_PMIC8XXX_VIBRATOR=y
-CONFIG_TZCOM=y
+CONFIG_QSEECOM=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -311,14 +313,13 @@
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
CONFIG_MT9M114=y
+CONFIG_IMX074_ACT=y
CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
-CONFIG_IMX074=y
-CONFIG_IMX074_ACT=y
-CONFIG_OV2720=y
-CONFIG_S5K3L1YX=y
CONFIG_MSM_GEMINI=y
CONFIG_S5K3L1YX=y
CONFIG_RADIO_IRIS=y
@@ -337,9 +338,8 @@
CONFIG_FB_MSM_OVERLAY=y
CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
CONFIG_FB_MSM_OVERLAY1_WRITEBACK=y
-CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
-CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
+CONFIG_FB_MSM_LVDS_MIPI_PANEL_DETECT=y
CONFIG_FB_MSM_HDMI_MSM_PANEL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index a326de6..dafaffc 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -193,8 +193,10 @@
CONFIG_IP_NF_ARPTABLES=y
CONFIG_IP_NF_ARPFILTER=y
CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
CONFIG_IP6_NF_IPTABLES=y
CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
CONFIG_IP6_NF_MANGLE=y
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_HTB=y
@@ -229,7 +231,7 @@
CONFIG_BLK_DEV_RAM=y
CONFIG_HAPTIC_ISA1200=y
CONFIG_PMIC8XXX_VIBRATOR=y
-CONFIG_TZCOM=y
+CONFIG_QSEECOM=y
CONFIG_SCSI=y
CONFIG_SCSI_TGT=y
CONFIG_BLK_DEV_SD=y
@@ -311,15 +313,15 @@
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_MSM_CAMERA_V4L2=y
+CONFIG_IMX074=y
CONFIG_MT9M114=y
+CONFIG_IMX074_ACT=y
CONFIG_MSM_CAMERA_FLASH_SC628A=y
+CONFIG_OV2720=y
CONFIG_MSM_CAMERA_SENSOR=y
CONFIG_MSM_ACTUATOR=y
-CONFIG_IMX074=y
-CONFIG_IMX074_ACT=y
-CONFIG_OV2720=y
-CONFIG_S5K3L1YX=y
CONFIG_MSM_GEMINI=y
+CONFIG_S5K3L1YX=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 7ba17e6..d4552f8 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -70,6 +70,7 @@
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
index 65c3f24..4e25f18 100644
--- a/arch/arm/include/asm/assembler.h
+++ b/arch/arm/include/asm/assembler.h
@@ -137,6 +137,11 @@
disable_irq
.endm
+ .macro save_and_disable_irqs_notrace, oldcpsr
+ mrs \oldcpsr, cpsr
+ disable_irq_notrace
+ .endm
+
/*
* Restore interrupt state previously stored in a register. We don't
* guarantee that this will preserve the flags.
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 0083033..de314ea 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -763,6 +763,7 @@
break;
case 0x0490: /* 8960 sim */
case 0x04D0: /* 8960 */
+ case 0x06F0: /* 8064 */
armpmu = armv7_krait_pmu_init();
krait_l2_pmu_init();
break;
diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c
index 1ce4dd6..09cc127d 100644
--- a/arch/arm/kernel/perf_event_msm_krait.c
+++ b/arch/arm/kernel/perf_event_msm_krait.c
@@ -280,9 +280,9 @@
u32 v_orig_val;
u32 f_orig_val;
- /* CPACR Enable CP10 access */
+ /* CPACR Enable CP10 and CP11 access */
v_orig_val = get_copro_access();
- venum_new_val = v_orig_val | CPACC_SVC(10);
+ venum_new_val = v_orig_val | CPACC_SVC(10) | CPACC_SVC(11);
set_copro_access(venum_new_val);
/* Store orig venum val */
__get_cpu_var(venum_orig_val) = v_orig_val;
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 18fbcf6..1004683 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -222,6 +222,7 @@
select MSM_SPM_V2
select MSM_L2_SPM
select MSM_PM8X60 if PM
+ select CPU_HAS_L2_PMU
config ARCH_MSMCOPPER
bool "MSM Copper"
@@ -477,6 +478,22 @@
help
Support for the Qualcomm MSM8625 RUMI3 Emulation Platform.
+config MACH_MSM8625_SURF
+ depends on ARCH_MSM8625
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM8625 SURF"
+ help
+ Support for the Qualcomm MSM8625 SURF.
+
+config MACH_MSM8625_EVB
+ depends on ARCH_MSM8625
+ depends on !MSM_STACKED_MEMORY
+ default y
+ bool "MSM8625 EVB"
+ help
+ Support for the Qualcomm MSM8625 Reference Design.
+
config MACH_MSM7X30_SURF
depends on ARCH_MSM7X30
depends on !MSM_STACKED_MEMORY
@@ -2082,6 +2099,7 @@
config MSM_RTB_SEPARATE_CPUS
bool "Separate entries for each cpu"
depends on MSM_RTB
+ depends on SMP
help
Under some circumstances, it may be beneficial to give dedicated space
for each cpu to log accesses. Selecting this option will log each cpu
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 8347a25..525dce4 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -23,7 +23,7 @@
obj-y += acpuclock.o
obj-$(CONFIG_ARCH_MSM7X01A) += acpuclock-7201.o
obj-$(CONFIG_ARCH_MSM7X25) += acpuclock-7201.o
-obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7201.o
+obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7201.o clock-pll.o
obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o
obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o
@@ -54,7 +54,7 @@
msm-etm-objs := etm.o
obj-$(CONFIG_MSM_ETM) += msm-etm.o
-obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-ptm.o
+obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-etm.o
quiet_cmd_mkrpcsym = MKCAP $@
cmd_mkrpcsym = $(PERL) $(srctree)/$(src)/mkrpcsym.pl $< $@
@@ -221,14 +221,18 @@
obj-$(CONFIG_MACH_MSM7X27_SURF) += board-msm7x27.o devices-msm7x27.o
obj-$(CONFIG_MACH_MSM7X27_FFA) += board-msm7x27.o devices-msm7x27.o
obj-$(CONFIG_ARCH_MSM7X27A) += clock-pcom-lookup.o devices-msm7x27a.o
-obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7627A_QRD3) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
-obj-$(CONFIG_MACH_MSM7627A_EVB) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o board-msm7627a-display.o board-msm7627a-wlan.o
+board-7627a-all-objs += board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+board-7627a-all-objs += board-msm7627a-display.o board-msm7627a-wlan.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_QRD3) += board-qrd7627a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM7627A_EVB) += board-qrd7627a.o board-7627a-all.o
obj-$(CONFIG_ARCH_MSM8625) += devices-msm7x27a.o clock-pcom-lookup.o
obj-$(CONFIG_MACH_MSM8625_RUMI3) += board-msm7x27a.o
+obj-$(CONFIG_MACH_MSM8625_SURF) += board-msm7x27a.o board-7627a-all.o
+obj-$(CONFIG_MACH_MSM8625_EVB) += board-qrd7627a.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
obj-$(CONFIG_MACH_MSM7X25_SURF) += board-msm7x27.o devices-msm7x25.o
diff --git a/arch/arm/mach-msm/acpuclock-7201.c b/arch/arm/mach-msm/acpuclock-7201.c
index 5a21407..ae4b084 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -27,7 +27,6 @@
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/sort.h>
-#include <linux/remote_spinlock.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include <asm/mach-types.h>
@@ -39,36 +38,36 @@
#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
-#define PLLn_MODE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
-#define PLLn_L_VAL(n) (MSM_CLK_CTL_BASE + 0x304 + 28 * (n))
-#define PLL4_MODE (MSM_CLK_CTL_BASE + 0x374)
-#define PLL4_L_VAL (MSM_CLK_CTL_BASE + 0x378)
#define POWER_COLLAPSE_KHZ 19200
/* Max CPU frequency allowed by hardware while in standby waiting for an irq. */
#define MAX_WAIT_FOR_IRQ_KHZ 128000
+/**
+ * enum - For acpuclock PLL IDs
+ */
enum {
- ACPU_PLL_TCXO = -1,
ACPU_PLL_0 = 0,
ACPU_PLL_1,
ACPU_PLL_2,
ACPU_PLL_3,
ACPU_PLL_4,
+ ACPU_PLL_TCXO,
ACPU_PLL_END,
};
-static const struct pll {
- void __iomem *mod_reg;
- const uint32_t l_val_mask;
-} soc_pll[ACPU_PLL_END] = {
- [ACPU_PLL_0] = {PLLn_MODE(ACPU_PLL_0), 0x3f},
- [ACPU_PLL_1] = {PLLn_MODE(ACPU_PLL_1), 0x3f},
- [ACPU_PLL_2] = {PLLn_MODE(ACPU_PLL_2), 0x3f},
- [ACPU_PLL_3] = {PLLn_MODE(ACPU_PLL_3), 0x3f},
- [ACPU_PLL_4] = {PLL4_MODE, 0x3ff},
+struct acpu_clk_src {
+ struct clk *clk;
+ const char *name;
+};
+
+static struct acpu_clk_src pll_clk[ACPU_PLL_END] = {
+ [ACPU_PLL_0] = { .name = "pll0_clk" },
+ [ACPU_PLL_1] = { .name = "pll1_clk" },
+ [ACPU_PLL_2] = { .name = "pll2_clk" },
+ [ACPU_PLL_4] = { .name = "pll4_clk" },
};
struct clock_state {
@@ -78,24 +77,6 @@
struct clk *ebi1_clk;
};
-#define PLL_BASE 7
-
-struct shared_pll_control {
- uint32_t version;
- struct {
- /* Denotes if the PLL is ON. Technically, this can be read
- * directly from the PLL registers, but this feild is here,
- * so let's use it.
- */
- uint32_t on;
- /* One bit for each processor core. The application processor
- * is allocated bit position 1. All other bits should be
- * considered as votes from other processors.
- */
- uint32_t votes;
- } pll[PLL_BASE + ACPU_PLL_END];
-};
-
struct clkctl_acpu_speed {
unsigned int use_for_scaling;
unsigned int a11clk_khz;
@@ -106,14 +87,11 @@
unsigned int ahbclk_div;
int vdd;
unsigned int axiclk_khz;
- unsigned long lpj; /* loops_per_jiffy */
/* Pointers in acpu_freq_tbl[] for max up/down steppings. */
struct clkctl_acpu_speed *down[ACPU_PLL_END];
struct clkctl_acpu_speed *up[ACPU_PLL_END];
};
-static remote_spinlock_t pll_lock;
-static struct shared_pll_control *pll_control;
static struct clock_state drv_state = { 0 };
static struct clkctl_acpu_speed *acpu_freq_tbl;
@@ -136,7 +114,7 @@
{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627 with CDMA capable modem */
@@ -150,7 +128,7 @@
{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 200000, 2, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627 with GSM capable modem - PLL2 @ 800 */
@@ -164,7 +142,7 @@
{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627 with CDMA capable modem - PLL2 @ 800 */
@@ -178,7 +156,7 @@
{ 0, 400000, ACPU_PLL_2, 2, 1, 133333, 2, 5, 160000 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 160000, 2, 6, 160000 },
{ 1, 800000, ACPU_PLL_2, 2, 0, 200000, 3, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627a PLL2 @ 1200MHz with GSM capable modem */
@@ -193,7 +171,7 @@
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627a PLL2 @ 1200MHz with CDMA capable modem */
@@ -208,7 +186,7 @@
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627aa PLL4 @ 1008MHz with GSM capable modem */
@@ -223,7 +201,7 @@
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
@@ -238,7 +216,7 @@
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7625a PLL2 @ 1200MHz with GSM capable modem */
@@ -252,7 +230,7 @@
{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627a PLL2 @ 1200MHz with GSM capable modem */
@@ -267,7 +245,7 @@
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627a PLL2 @ 1200MHz with CDMA capable modem */
@@ -282,7 +260,7 @@
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 120000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 800000, ACPU_PLL_4, 6, 0, 100000, 3, 7, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627aa PLL4 @ 1008MHz with GSM capable modem */
@@ -297,7 +275,7 @@
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
@@ -312,7 +290,7 @@
{ 0, 504000, ACPU_PLL_4, 6, 1, 63000, 3, 6, 200000 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
{ 1, 1008000, ACPU_PLL_4, 6, 0, 126000, 3, 7, 200000},
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
/* 7625a PLL2 @ 1200MHz with GSM capable modem */
@@ -326,29 +304,19 @@
{ 0, 400000, ACPU_PLL_2, 2, 2, 50000, 3, 4, 122880 },
{ 1, 480000, ACPU_PLL_0, 4, 1, 60000, 3, 5, 122880 },
{ 1, 600000, ACPU_PLL_2, 2, 1, 75000, 3, 6, 200000 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
};
-#define PLL_0_MHZ 0
-#define PLL_196_MHZ 10
-#define PLL_245_MHZ 12
-#define PLL_589_MHZ 30
-#define PLL_737_MHZ 38
-#define PLL_800_MHZ 41
-#define PLL_960_MHZ 50
-#define PLL_1008_MHZ 52
-#define PLL_1200_MHZ 62
-
#define PLL_CONFIG(m0, m1, m2, m4) { \
- PLL_##m0##_MHZ, PLL_##m1##_MHZ, PLL_##m2##_MHZ, PLL_##m4##_MHZ, \
+ m0, m1, m2, m4, \
pll0_##m0##_pll1_##m1##_pll2_##m2##_pll4_##m4 \
}
struct pll_freq_tbl_map {
- unsigned int pll0_l;
- unsigned int pll1_l;
- unsigned int pll2_l;
- unsigned int pll4_l;
+ unsigned int pll0_rate;
+ unsigned int pll1_rate;
+ unsigned int pll2_rate;
+ unsigned int pll4_rate;
struct clkctl_acpu_speed *tbl;
};
@@ -405,59 +373,6 @@
}
#endif
-static void pll_enable(void __iomem *addr, unsigned on)
-{
- if (on) {
- writel_relaxed(2, addr);
- mb();
- udelay(5);
- writel_relaxed(6, addr);
- mb();
- udelay(50);
- writel_relaxed(7, addr);
- } else {
- writel_relaxed(0, addr);
- }
-}
-
-static int pc_pll_request(unsigned id, unsigned on)
-{
- int res = 0;
- on = !!on;
-
- if (on)
- pr_debug("Enabling PLL %d\n", id);
- else
- pr_debug("Disabling PLL %d\n", id);
-
- if (id >= ACPU_PLL_END)
- return -EINVAL;
-
- remote_spin_lock(&pll_lock);
- if (on) {
- pll_control->pll[PLL_BASE + id].votes |= 2;
- if (!pll_control->pll[PLL_BASE + id].on) {
- pll_enable(soc_pll[id].mod_reg, 1);
- pll_control->pll[PLL_BASE + id].on = 1;
- }
- } else {
- pll_control->pll[PLL_BASE + id].votes &= ~2;
- if (pll_control->pll[PLL_BASE + id].on
- && !pll_control->pll[PLL_BASE + id].votes) {
- pll_enable(soc_pll[id].mod_reg, 0);
- pll_control->pll[PLL_BASE + id].on = 0;
- }
- }
- remote_spin_unlock(&pll_lock);
-
- if (on)
- pr_debug("PLL enabled\n");
- else
- pr_debug("PLL disabled\n");
-
- return res;
-}
-
static int acpuclk_set_vdd_level(int vdd)
{
uint32_t current_vdd;
@@ -576,7 +491,7 @@
if (reason == SETRATE_CPUFREQ) {
if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) {
- rc = pc_pll_request(tgt_s->pll, 1);
+ rc = clk_prepare_enable(pll_clk[tgt_s->pll].clk);
if (rc < 0) {
pr_err("PLL%d enable failed (%d)\n",
tgt_s->pll, rc);
@@ -651,7 +566,7 @@
if (cur_s->pll != ACPU_PLL_TCXO
&& !(plls_enabled & (1 << cur_s->pll))) {
- rc = pc_pll_request(cur_s->pll, 1);
+ rc = clk_prepare_enable(pll_clk[cur_s->pll].clk);
if (rc < 0) {
pr_err("PLL%d enable failed (%d)\n",
cur_s->pll, rc);
@@ -662,8 +577,6 @@
acpuclk_set_div(cur_s);
drv_state.current_speed = cur_s;
- /* Re-adjust lpj for the new clock speed. */
- loops_per_jiffy = cur_s->lpj;
mb();
udelay(50);
}
@@ -684,12 +597,8 @@
if (tgt_s->pll != ACPU_PLL_TCXO)
plls_enabled &= ~(1 << tgt_s->pll);
for (pll = ACPU_PLL_0; pll < ACPU_PLL_END; pll++)
- if (plls_enabled & (1 << pll)) {
- res = pc_pll_request(pll, 0);
- if (res < 0)
- pr_warning("PLL%d disable failed (%d)\n",
- pll, res);
- }
+ if (plls_enabled & (1 << pll))
+ clk_disable_unprepare(pll_clk[pll].clk);
/* Nothing else to do for power collapse. */
if (reason == SETRATE_PC)
@@ -742,9 +651,10 @@
}
drv_state.current_speed = speed;
- if (speed->pll != ACPU_PLL_TCXO)
- if (pc_pll_request(speed->pll, 1))
+ if (speed->pll != ACPU_PLL_TCXO) {
+ if (clk_prepare_enable(pll_clk[speed->pll].clk))
pr_warning("Failed to vote for boot PLL\n");
+ }
/* Fix div2 to 2 for 7x27/5a(aa) targets */
if (!cpu_is_msm7x27()) {
@@ -777,64 +687,52 @@
/*----------------------------------------------------------------------------
* Clock driver initialization
*---------------------------------------------------------------------------*/
-
-static void __init acpu_freq_tbl_fixup(void)
+#define MHZ 1000000
+static void __init select_freq_plan(void)
{
- unsigned long pll0_l, pll1_l, pll2_l, pll4_l;
- struct pll_freq_tbl_map *lst;
+ unsigned long pll_mhz[ACPU_PLL_END];
+ struct pll_freq_tbl_map *t;
+ int i;
- /* Wait for the PLLs to be initialized and then read their frequency.
- */
- do {
- pll0_l = readl_relaxed(PLLn_L_VAL(0)) &
- soc_pll[ACPU_PLL_0].l_val_mask;
- cpu_relax();
- udelay(50);
- } while (pll0_l == 0);
- do {
- pll1_l = readl_relaxed(PLLn_L_VAL(1)) &
- soc_pll[ACPU_PLL_1].l_val_mask;
- cpu_relax();
- udelay(50);
- } while (pll1_l == 0);
- do {
- pll2_l = readl_relaxed(PLLn_L_VAL(2)) &
- soc_pll[ACPU_PLL_2].l_val_mask;
- cpu_relax();
- udelay(50);
- } while (pll2_l == 0);
-
- pr_info("L val: PLL0: %d, PLL1: %d, PLL2: %d\n",
- (int)pll0_l, (int)pll1_l, (int)pll2_l);
-
- if (!cpu_is_msm7x27() && !cpu_is_msm7x25a()) {
- do {
- pll4_l = readl_relaxed(PLL4_L_VAL) &
- soc_pll[ACPU_PLL_4].l_val_mask;
- cpu_relax();
- udelay(50);
- } while (pll4_l == 0);
- pr_info("L val: PLL4: %d\n", (int)pll4_l);
- } else {
- pll4_l = 0;
+ /* Get PLL clocks */
+ for (i = 0; i < ACPU_PLL_END; i++) {
+ if (pll_clk[i].name) {
+ pll_clk[i].clk = clk_get_sys("acpu", pll_clk[i].name);
+ if (IS_ERR(pll_clk[i].clk)) {
+ pll_mhz[i] = 0;
+ continue;
+ }
+ /* Get PLL's Rate */
+ pll_mhz[i] = clk_get_rate(pll_clk[i].clk)/MHZ;
+ }
}
- /* Fix the tables for 7x25a variant to not conflict with 7x27 ones */
+ /*
+ * For the pll configuration used in acpuclock table e.g.
+ * pll0_960_pll1_245_pll2_1200" is same for 7627 and
+ * 7625a (as pll0,pll1,pll2) having same rates, but frequency
+ * table is different for both targets.
+ *
+ * Hence below for loop will not be able to select correct
+ * table based on PLL rates as rates are same. Hence we need
+ * to add this cpu check for selecting the correct acpuclock table.
+ */
if (cpu_is_msm7x25a()) {
- if (pll1_l == PLL_245_MHZ) {
+ if (pll_mhz[ACPU_PLL_1] == 245) {
acpu_freq_tbl =
pll0_960_pll1_245_pll2_1200_25a;
- } else if (pll1_l == PLL_737_MHZ) {
+ } else if (pll_mhz[ACPU_PLL_1] == 737) {
acpu_freq_tbl =
pll0_960_pll1_737_pll2_1200_25a;
}
} else {
/* Select the right table to use. */
- for (lst = acpu_freq_tbl_list; lst->tbl != 0; lst++) {
- if (lst->pll0_l == pll0_l && lst->pll1_l == pll1_l
- && lst->pll2_l == pll2_l
- && lst->pll4_l == pll4_l) {
- acpu_freq_tbl = lst->tbl;
+ for (t = acpu_freq_tbl_list; t->tbl != 0; t++) {
+ if (t->pll0_rate == pll_mhz[ACPU_PLL_0]
+ && t->pll1_rate == pll_mhz[ACPU_PLL_1]
+ && t->pll2_rate == pll_mhz[ACPU_PLL_2]
+ && t->pll4_rate == pll_mhz[ACPU_PLL_4]) {
+ acpu_freq_tbl = t->tbl;
break;
}
}
@@ -862,18 +760,6 @@
return found_khz;
}
-/* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
-{
- int i;
- const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
- for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
- acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
- base_clk->a11clk_khz,
- acpu_freq_tbl[i].a11clk_khz);
- }
-}
-
static void __init precompute_stepping(void)
{
int i, step_idx;
@@ -945,33 +831,6 @@
}
}
-static void shared_pll_control_init(void)
-{
-#define PLL_REMOTE_SPINLOCK_ID "S:7"
- unsigned smem_size;
-
- remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
- pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
-
- if (!pll_control) {
- pr_err("Can't find shared PLL control data structure!\n");
- BUG();
- /* There might be more PLLs than what the application processor knows
- * about. But the index used for each PLL is guaranteed to remain the
- * same. */
- } else if (smem_size < sizeof(struct shared_pll_control)) {
- pr_err("Shared PLL control data"
- "structure too small!\n");
- BUG();
- } else if (pll_control->version != 0xCCEE0001) {
- pr_err("Shared PLL control version mismatch!\n");
- BUG();
- } else {
- pr_info("Shared PLL control available.\n");
- return;
- }
-
-}
static struct acpuclk_data acpuclk_7627_data = {
.set_rate = acpuclk_7627_set_rate,
@@ -988,13 +847,11 @@
BUG_ON(IS_ERR(drv_state.ebi1_clk));
mutex_init(&drv_state.lock);
- shared_pll_control_init();
drv_state.max_speed_delta_khz = soc_data->max_speed_delta_khz;
- acpu_freq_tbl_fixup();
+ select_freq_plan();
acpuclk_7627_data.wait_for_irq_khz = find_wait_for_irq_khz();
precompute_stepping();
acpuclk_hw_init();
- lpj_init();
print_acpu_freq_tbl();
acpuclk_register(&acpuclk_7627_data);
diff --git a/arch/arm/mach-msm/acpuclock-7x30.c b/arch/arm/mach-msm/acpuclock-7x30.c
index 7ee4e5b..f2fb292 100644
--- a/arch/arm/mach-msm/acpuclock-7x30.c
+++ b/arch/arm/mach-msm/acpuclock-7x30.c
@@ -1,7 +1,7 @@
/*
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-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
@@ -76,7 +76,6 @@
unsigned int vdd_mv;
unsigned int vdd_raw;
struct pll *pll_rate;
- unsigned long lpj; /* loops_per_jiffy */
};
static struct clock_state drv_state = { 0 };
@@ -259,7 +258,6 @@
/* Perform the frequency switch */
acpuclk_set_src(tgt_s);
drv_state.current_speed = tgt_s;
- loops_per_jiffy = tgt_s->lpj;
if (tgt_s->src == PLL_2 && strt_s->src == PLL_2)
clk_disable(acpuclk_sources[backup_s->src]);
@@ -392,19 +390,6 @@
return;
}
-/* Initalize the lpj field in the acpu_freq_tbl. */
-static void __init lpj_init(void)
-{
- int i;
- const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
-
- for (i = 0; acpu_freq_tbl[i].acpu_clk_khz; i++) {
- acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
- base_clk->acpu_clk_khz,
- acpu_freq_tbl[i].acpu_clk_khz);
- }
-}
-
#ifdef CONFIG_CPU_FREQ_MSM
static struct cpufreq_frequency_table cpufreq_tbl[ARRAY_SIZE(acpu_freq_tbl)];
@@ -479,7 +464,6 @@
pll2_fixup();
populate_plls();
acpuclk_hw_init();
- lpj_init();
setup_cpufreq_table();
acpuclk_register(&acpuclk_7x30_data);
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index 99c3d78..8d35148 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -194,7 +194,7 @@
.hfpll_base = MSM_HFPLL_BASE + 0x200,
.aux_clk_sel = MSM_ACC0_BASE + 0x014,
.l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait0", 1150000 },
+ .vreg[VREG_CORE] = { "krait0", 1300000 },
.vreg[VREG_MEM] = { "krait0_mem", 1150000,
RPM_VREG_VOTER1,
RPM_VREG_ID_PM8921_L24 },
@@ -209,7 +209,7 @@
.hfpll_base = MSM_HFPLL_BASE + 0x240,
.aux_clk_sel = MSM_ACC1_BASE + 0x014,
.l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait1", 1150000 },
+ .vreg[VREG_CORE] = { "krait1", 1300000 },
.vreg[VREG_MEM] = { "krait1_mem", 1150000,
RPM_VREG_VOTER2,
RPM_VREG_ID_PM8921_L24 },
@@ -224,7 +224,7 @@
.hfpll_base = MSM_HFPLL_BASE + 0x280,
.aux_clk_sel = MSM_ACC2_BASE + 0x014,
.l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait2", 1150000 },
+ .vreg[VREG_CORE] = { "krait2", 1300000 },
.vreg[VREG_MEM] = { "krait2_mem", 1150000,
RPM_VREG_VOTER4,
RPM_VREG_ID_PM8921_L24 },
@@ -239,7 +239,7 @@
.hfpll_base = MSM_HFPLL_BASE + 0x2C0,
.aux_clk_sel = MSM_ACC3_BASE + 0x014,
.l2cpmr_iaddr = L2CPUCPMR_IADDR,
- .vreg[VREG_CORE] = { "krait3", 1150000 },
+ .vreg[VREG_CORE] = { "krait3", 1300000 },
.vreg[VREG_MEM] = { "krait3_mem", 1150000,
RPM_VREG_VOTER5,
RPM_VREG_ID_PM8921_L24 },
@@ -375,6 +375,7 @@
[4] = BW_MBPS(3200), /* At least 400 MHz on bus. */
[5] = BW_MBPS(3600), /* At least 450 MHz on bus. */
[6] = BW_MBPS(3936), /* At least 492 MHz on bus. */
+ [7] = BW_MBPS(4264), /* At least 533 MHz on bus. */
};
static struct msm_bus_scale_pdata bus_client_pdata = {
@@ -546,47 +547,48 @@
#define L2(x) (&l2_freq_tbl_8064[(x)])
static struct l2_level l2_freq_tbl_8064[] = {
[0] = { {STBY_KHZ, QSB, 0, 0, 0x00 }, 1050000, 1050000, 0 },
- [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 0 },
- [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 1 },
- [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 1 },
- [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 1 },
+ [1] = { { 384000, PLL_8, 0, 2, 0x00 }, 1050000, 1050000, 1 },
+ [2] = { { 432000, HFPLL, 2, 0, 0x20 }, 1050000, 1050000, 2 },
+ [3] = { { 486000, HFPLL, 2, 0, 0x24 }, 1050000, 1050000, 2 },
+ [4] = { { 540000, HFPLL, 2, 0, 0x28 }, 1050000, 1050000, 2 },
[5] = { { 594000, HFPLL, 1, 0, 0x16 }, 1050000, 1050000, 2 },
- [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 2 },
- [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 2 },
- [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 3 },
- [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 3 },
- [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 3 },
- [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 3 },
- [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 3 },
- [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 3 },
- [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 4 },
- [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 4 },
- [16] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 4 },
- [17] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 4 },
- [18] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 4 },
- [19] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 4 },
- [20] = { { 1404000, HFPLL, 1, 0, 0x34 }, 1150000, 1150000, 4 },
- [21] = { { 1458000, HFPLL, 1, 0, 0x36 }, 1150000, 1150000, 5 },
- [22] = { { 1512000, HFPLL, 1, 0, 0x38 }, 1150000, 1150000, 5 },
- [23] = { { 1566000, HFPLL, 1, 0, 0x3A }, 1150000, 1150000, 5 },
- [24] = { { 1620000, HFPLL, 1, 0, 0x3C }, 1150000, 1150000, 5 },
- [25] = { { 1674000, HFPLL, 1, 0, 0x3E }, 1150000, 1150000, 5 },
+ [6] = { { 648000, HFPLL, 1, 0, 0x18 }, 1050000, 1050000, 4 },
+ [7] = { { 702000, HFPLL, 1, 0, 0x1A }, 1050000, 1050000, 4 },
+ [8] = { { 756000, HFPLL, 1, 0, 0x1C }, 1150000, 1150000, 4 },
+ [9] = { { 810000, HFPLL, 1, 0, 0x1E }, 1150000, 1150000, 4 },
+ [10] = { { 864000, HFPLL, 1, 0, 0x20 }, 1150000, 1150000, 4 },
+ [11] = { { 918000, HFPLL, 1, 0, 0x22 }, 1150000, 1150000, 7 },
+ [12] = { { 972000, HFPLL, 1, 0, 0x24 }, 1150000, 1150000, 7 },
+ [13] = { { 1026000, HFPLL, 1, 0, 0x26 }, 1150000, 1150000, 7 },
+ [14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 7 },
+ [15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 7 },
};
/* TODO: Update core voltages when data is available. */
static struct acpu_level acpu_freq_tbl_8064[] = {
- { 0, {STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 1050000 },
- { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 1050000 },
- { 1, { 432000, HFPLL, 2, 0, 0x20 }, L2(2), 1050000 },
- { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(3), 1050000 },
- { 1, { 540000, HFPLL, 2, 0, 0x28 }, L2(4), 1050000 },
- { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(5), 1050000 },
- { 1, { 648000, HFPLL, 1, 0, 0x18 }, L2(6), 1050000 },
- { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 1050000 },
- { 1, { 756000, HFPLL, 1, 0, 0x1C }, L2(8), 1150000 },
- { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(9), 1150000 },
- { 1, { 864000, HFPLL, 1, 0, 0x20 }, L2(10), 1150000 },
- { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(11), 1150000 },
+ { 0, { STBY_KHZ, QSB, 0, 0, 0x00 }, L2(0), 950000 },
+ { 1, { 384000, PLL_8, 0, 2, 0x00 }, L2(1), 950000 },
+ { 0, { 432000, HFPLL, 2, 0, 0x20 }, L2(7), 975000 },
+ { 1, { 486000, HFPLL, 2, 0, 0x24 }, L2(7), 975000 },
+ { 0, { 540000, HFPLL, 2, 0, 0x28 }, L2(7), 1000000 },
+ { 1, { 594000, HFPLL, 1, 0, 0x16 }, L2(7), 1000000 },
+ { 0, { 648000, HFPLL, 1, 0, 0x18 }, L2(7), 1025000 },
+ { 1, { 702000, HFPLL, 1, 0, 0x1A }, L2(7), 1025000 },
+ { 0, { 756000, HFPLL, 1, 0, 0x1C }, L2(7), 1075000 },
+ { 1, { 810000, HFPLL, 1, 0, 0x1E }, L2(7), 1075000 },
+ { 0, { 864000, HFPLL, 1, 0, 0x20 }, L2(7), 1100000 },
+ { 1, { 918000, HFPLL, 1, 0, 0x22 }, L2(7), 1100000 },
+ { 0, { 972000, HFPLL, 1, 0, 0x24 }, L2(7), 1125000 },
+ { 1, { 1026000, HFPLL, 1, 0, 0x26 }, L2(7), 1125000 },
+ { 0, { 1080000, HFPLL, 1, 0, 0x28 }, L2(15), 1175000 },
+ { 1, { 1134000, HFPLL, 1, 0, 0x2A }, L2(15), 1175000 },
+ { 0, { 1188000, HFPLL, 1, 0, 0x2C }, L2(15), 1200000 },
+ { 1, { 1242000, HFPLL, 1, 0, 0x2E }, L2(15), 1200000 },
+ { 0, { 1296000, HFPLL, 1, 0, 0x30 }, L2(15), 1225000 },
+ { 1, { 1350000, HFPLL, 1, 0, 0x32 }, L2(15), 1225000 },
+ { 0, { 1404000, HFPLL, 1, 0, 0x34 }, L2(15), 1237500 },
+ { 1, { 1458000, HFPLL, 1, 0, 0x36 }, L2(15), 1237500 },
+ { 1, { 1512000, HFPLL, 1, 0, 0x38 }, L2(15), 1250000 },
{ 0, { 0 } }
};
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index 5bef079..97f8722 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -556,8 +556,7 @@
if (!a2_pc_disabled) {
a2_pc_disabled = 1;
- schedule_delayed_work(&ul_timeout_work,
- msecs_to_jiffies(UL_TIMEOUT_DELAY));
+ ul_wakeup();
}
handle_bam_mux_cmd_open(rx_hdr);
diff --git a/arch/arm/mach-msm/board-8064-camera.c b/arch/arm/mach-msm/board-8064-camera.c
index 486ebd3..f23bf2a 100644
--- a/arch/arm/mach-msm/board-8064-camera.c
+++ b/arch/arm/mach-msm/board-8064-camera.c
@@ -102,6 +102,13 @@
static struct msm_gpiomux_config apq8064_cam_common_configs[] = {
{
+ .gpio = 1,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
+ [GPIOMUX_SUSPENDED] = &cam_settings[0],
+ },
+ },
+ {
.gpio = 2,
.settings = {
[GPIOMUX_ACTIVE] = &cam_settings[12],
@@ -111,7 +118,7 @@
{
.gpio = 3,
.settings = {
- [GPIOMUX_ACTIVE] = &cam_settings[1],
+ [GPIOMUX_ACTIVE] = &cam_settings[2],
[GPIOMUX_SUSPENDED] = &cam_settings[0],
},
},
@@ -173,6 +180,16 @@
},
};
+
+#define VFE_CAMIF_TIMER1_GPIO 3
+#define VFE_CAMIF_TIMER2_GPIO 1
+
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+ ._fsrc.ext_driver_src.led_en = VFE_CAMIF_TIMER1_GPIO,
+ ._fsrc.ext_driver_src.led_flash_en = VFE_CAMIF_TIMER2_GPIO,
+};
+
static struct msm_gpiomux_config apq8064_cam_2d_configs[] = {
};
@@ -419,7 +436,8 @@
};
static struct msm_camera_sensor_flash_data flash_imx074 = {
- .flash_type = MSM_CAMERA_FLASH_NONE,
+ .flash_type = MSM_CAMERA_FLASH_LED,
+ .flash_src = &msm_flash_src
};
static struct msm_camera_sensor_platform_info sensor_board_info_imx074 = {
@@ -518,6 +536,9 @@
I2C_BOARD_INFO("ov2720", 0x6C),
.platform_data = &msm_camera_sensor_ov2720_data,
},
+ {
+ I2C_BOARD_INFO("sc628a", 0x6E),
+ },
};
struct msm_camera_board_info apq8064_camera_board_info = {
diff --git a/arch/arm/mach-msm/board-8064-display.c b/arch/arm/mach-msm/board-8064-display.c
index 604769d..a5376e3 100644
--- a/arch/arm/mach-msm/board-8064-display.c
+++ b/arch/arm/mach-msm/board-8064-display.c
@@ -23,6 +23,7 @@
#include <mach/gpiomux.h>
#include <mach/ion.h>
#include <mach/msm_bus_board.h>
+#include <mach/socinfo.h>
#include "devices.h"
#include "board-8064.h"
@@ -66,7 +67,6 @@
}
};
-#define PANEL_NAME_MAX_LEN 30
#define LVDS_CHIMEI_PANEL_NAME "lvds_chimei_wxga"
#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
#define MIPI_VIDEO_CHIMEI_WXGA_PANEL_NAME "mipi_video_chimei_wxga"
@@ -528,8 +528,21 @@
return 0;
}
+static int lvds_pixel_remap(void)
+{
+ if (machine_is_apq8064_cdp() ||
+ machine_is_apq8064_liquid()) {
+ u32 ver = socinfo_get_platform_version();
+ if ((SOCINFO_VERSION_MAJOR(ver) == 1) &&
+ (SOCINFO_VERSION_MINOR(ver) == 0))
+ return 1;
+ }
+ return 0;
+}
+
static struct lcdc_platform_data lvds_pdata = {
.lcdc_power_save = lvds_panel_power,
+ .lvds_pixel_remap = lvds_pixel_remap
};
#define LPM_CHANNEL 2
diff --git a/arch/arm/mach-msm/board-8064-gpu.c b/arch/arm/mach-msm/board-8064-gpu.c
index e9b497b..9fbb1c7 100644
--- a/arch/arm/mach-msm/board-8064-gpu.c
+++ b/arch/arm/mach-msm/board-8064-gpu.c
@@ -151,17 +151,17 @@
.pwrlevel = {
{
.gpu_freq = 400000000,
- .bus_freq = 4,
+ .bus_freq = 3,
.io_fraction = 0,
},
{
.gpu_freq = 320000000,
- .bus_freq = 3,
+ .bus_freq = 2,
.io_fraction = 33,
},
{
.gpu_freq = 1920000000,
- .bus_freq = 2,
+ .bus_freq = 1,
.io_fraction = 100,
},
{
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index bd5f703..f4650a9 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -141,6 +141,8 @@
/* External 5V regulator enable; shared by HDMI and USB_OTG switches. */
PM8921_MPP_INIT(7, D_OUTPUT, PM8921_MPP_DIG_LEVEL_VPH, DOUT_CTRL_LOW),
PM8921_MPP_INIT(8, D_OUTPUT, PM8921_MPP_DIG_LEVEL_S4, DOUT_CTRL_LOW),
+ /*MPP9 is used to detect docking station connection/removal on Liquid*/
+ PM8921_MPP_INIT(9, D_INPUT, PM8921_MPP_DIG_LEVEL_S4, DIN_TO_INT),
};
void __init apq8064_pm8xxx_gpio_mpp_init(void)
@@ -310,8 +312,8 @@
static struct pm8xxx_irq_platform_data
apq8064_pm8921_irq_pdata __devinitdata = {
.irq_base = PM8921_IRQ_BASE,
- .devirq = PM8921_USR_IRQ_N,
- .irq_trigger_flag = IRQF_TRIGGER_HIGH,
+ .devirq = MSM_GPIO_TO_INT(74),
+ .irq_trigger_flag = IRQF_TRIGGER_LOW,
.dev_id = 0,
};
diff --git a/arch/arm/mach-msm/board-8064-regulator.c b/arch/arm/mach-msm/board-8064-regulator.c
index 247b230..e25f418 100644
--- a/arch/arm/mach-msm/board-8064-regulator.c
+++ b/arch/arm/mach-msm/board-8064-regulator.c
@@ -226,6 +226,7 @@
};
VREG_CONSUMERS(EXT_MPP8) = {
REGULATOR_SUPPLY("ext_mpp8", NULL),
+ REGULATOR_SUPPLY("vbus", "msm_ehci_host.1"),
};
VREG_CONSUMERS(EXT_3P3V) = {
REGULATOR_SUPPLY("ext_3p3v", NULL),
@@ -469,15 +470,15 @@
/* SAW regulator constraints */
struct regulator_init_data msm8064_saw_regulator_pdata_8921_s5 =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(S5, "8921_s5", 950000, 1150000);
+ SAW_VREG_INIT(S5, "8921_s5", 950000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8921_s6 =
- SAW_VREG_INIT(S6, "8921_s6", 950000, 1150000);
+ SAW_VREG_INIT(S6, "8921_s6", 950000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8821_s0 =
/* ID vreg_name min_uV max_uV */
- SAW_VREG_INIT(8821_S0, "8821_s0", 950000, 1150000);
+ SAW_VREG_INIT(8821_S0, "8821_s0", 950000, 1300000);
struct regulator_init_data msm8064_saw_regulator_pdata_8821_s1 =
- SAW_VREG_INIT(8821_S1, "8821_s1", 950000, 1150000);
+ SAW_VREG_INIT(8821_S1, "8821_s1", 950000, 1300000);
/* PM8921 regulator constraints */
struct pm8xxx_regulator_platform_data
diff --git a/arch/arm/mach-msm/board-8064-storage.c b/arch/arm/mach-msm/board-8064-storage.c
index 41be3e7..e9c455d 100644
--- a/arch/arm/mach-msm/board-8064-storage.c
+++ b/arch/arm/mach-msm/board-8064-storage.c
@@ -210,6 +210,8 @@
#endif
.sup_clk_table = sdc1_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc1_sup_clk_rates),
+ .pclk_src_dfab = 1,
+ .nonremovable = 1,
.pin_data = &mmc_slot_pin_data[SDCC1],
.vreg_data = &mmc_slot_vreg_data[SDCC1],
};
@@ -228,6 +230,7 @@
.mmc_bus_width = MMC_CAP_4_BIT_DATA,
.sup_clk_table = sdc3_sup_clk_rates,
.sup_clk_cnt = ARRAY_SIZE(sdc3_sup_clk_rates),
+ .pclk_src_dfab = 1,
.pin_data = &mmc_slot_pin_data[SDCC3],
.vreg_data = &mmc_slot_vreg_data[SDCC3],
.status_gpio = 26,
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 3848262..2358645 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -54,10 +54,12 @@
#include <linux/bootmem.h>
#include <asm/setup.h>
#include <mach/dma.h>
+#include <mach/msm_dsps.h>
#include <mach/msm_bus_board.h>
#include <mach/cpuidle.h>
#include <mach/mdm2.h>
#include <linux/msm_tsens.h>
+#include <mach/msm_xo.h>
#include "msm_watchdog.h"
#include "board-8064.h"
@@ -467,24 +469,75 @@
},
};
+/* Bandwidth requests (zero) if no vote placed */
+static struct msm_bus_vectors usb_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+/* Bus bandwidth requests in Bytes/sec */
+static struct msm_bus_vectors usb_max_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_SPS,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 60000000, /* At least 480Mbps on bus. */
+ .ib = 960000000, /* MAX bursts rate */
+ },
+};
+
+static struct msm_bus_paths usb_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(usb_init_vectors),
+ usb_init_vectors,
+ },
+ {
+ ARRAY_SIZE(usb_max_vectors),
+ usb_max_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata usb_bus_scale_pdata = {
+ usb_bus_scale_usecases,
+ ARRAY_SIZE(usb_bus_scale_usecases),
+ .name = "usb",
+};
+
static struct msm_otg_platform_data msm_otg_pdata = {
.mode = USB_OTG,
.otg_control = OTG_PMIC_CONTROL,
.phy_type = SNPS_28NM_INTEGRATED_PHY,
.pmic_id_irq = PM8921_USB_ID_IN_IRQ(PM8921_IRQ_BASE),
.power_budget = 750,
+ .bus_scale_table = &usb_bus_scale_pdata,
};
-static struct msm_usb_host_platform_data msm_ehci_host_pdata = {
+static struct msm_usb_host_platform_data msm_ehci_host_pdata3 = {
.power_budget = 500,
};
+#ifdef CONFIG_USB_EHCI_MSM_HOST4
+static struct msm_usb_host_platform_data msm_ehci_host_pdata4;
+#endif
+
static void __init apq8064_ehci_host_init(void)
{
if (machine_is_apq8064_liquid()) {
+ msm_ehci_host_pdata3.dock_connect_irq =
+ PM8921_MPP_IRQ(PM8921_IRQ_BASE, 9);
+
apq8064_device_ehci_host3.dev.platform_data =
- &msm_ehci_host_pdata;
+ &msm_ehci_host_pdata3;
platform_device_register(&apq8064_device_ehci_host3);
+
+#ifdef CONFIG_USB_EHCI_MSM_HOST4
+ apq8064_device_ehci_host4.dev.platform_data =
+ &msm_ehci_host_pdata4;
+ platform_device_register(&apq8064_device_ehci_host4);
+#endif
}
}
@@ -1143,56 +1196,62 @@
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
- 100, 8000, 100000, 1,
+ 100, 650, 801, 200,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
- 2000, 6000, 60100000, 3000,
+ 2000, 200, 576000, 2000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
false,
- 4200, 5000, 60350000, 3500,
+ 8500, 51, 1122000, 8500,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
false,
- 6300, 4500, 65350000, 4800,
+ 9000, 51, 1130300, 9000,
+ },
+ {
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
+ MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
+ false,
+ 10000, 51, 1130300, 10000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
false,
- 11700, 2500, 67850000, 5500,
+ 12000, 14, 2205900, 12000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
false,
- 13800, 2000, 71850000, 6800,
+ 18000, 12, 2364250, 18000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
false,
- 29700, 500, 75850000, 8800,
+ 23500, 10, 2667000, 23500,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
false,
- 29700, 0, 76350000, 9800,
+ 29700, 5, 2867000, 30000,
},
};
@@ -1846,6 +1905,18 @@
},
};
+/* Sensors DSPS platform data */
+#define DSPS_PIL_GENERIC_NAME "dsps"
+static void __init apq8064_init_dsps(void)
+{
+ struct msm_dsps_platform_data *pdata =
+ msm_dsps_device_8064.dev.platform_data;
+ pdata->pil_name = DSPS_PIL_GENERIC_NAME;
+ pdata->gpios = NULL;
+ pdata->gpios_num = 0;
+
+ platform_device_register(&msm_dsps_device_8064);
+}
static void __init apq8064_clock_init(void)
{
@@ -1939,6 +2010,8 @@
BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
regulator_suppress_info_printing();
platform_device_register(&apq8064_device_rpm_regulator);
+ if (msm_xo_init())
+ pr_err("Failed to initialize XO votes\n");
apq8064_clock_init();
apq8064_init_gpiomux();
apq8064_i2c_init();
@@ -1967,6 +2040,7 @@
platform_device_register(&apq8064_slim_ctrl);
slim_register_board_info(apq8064_slim_devices,
ARRAY_SIZE(apq8064_slim_devices));
+ apq8064_init_dsps();
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
acpuclk_init(&acpuclk_8064_soc_data);
msm_spm_l2_init(msm_spm_l2_data);
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index a840877..2f188970 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -68,7 +68,6 @@
#define MDP_VSYNC_GPIO 0
-#define PANEL_NAME_MAX_LEN 30
#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME "mipi_cmd_novatek_qhd"
#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME "mipi_video_novatek_qhd"
#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
@@ -781,8 +780,7 @@
platform_device_register(&mipi_dsi_novatek_panel_device);
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
- if (!cpu_is_msm8930())
- platform_device_register(&hdmi_msm_device);
+ platform_device_register(&hdmi_msm_device);
#endif
platform_device_register(&mipi_dsi_toshiba_panel_device);
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index dee1e98..26211bf 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -52,7 +52,7 @@
.name = "sdc_vdd",
.high_vol_level = 2950000,
.low_vol_level = 2950000,
- .hpm_uA = 600000, /* 600mA */
+ .hpm_uA = 800000, /* 800mA */
}
};
@@ -122,8 +122,8 @@
static struct msm_mmc_pad_pull sdc1_pad_pull_off_cfg[] = {
{TLMM_PULL_SDC1_CLK, GPIO_CFG_NO_PULL},
- {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_DOWN},
- {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_DOWN}
+ {TLMM_PULL_SDC1_CMD, GPIO_CFG_PULL_UP},
+ {TLMM_PULL_SDC1_DATA, GPIO_CFG_PULL_UP}
};
/* SDC3 pad data */
@@ -208,11 +208,11 @@
};
static unsigned int sdc1_sup_clk_rates[] = {
- 400000, 24000000, 48000000
+ 400000, 24000000, 48000000,
};
static unsigned int sdc3_sup_clk_rates[] = {
- 400000, 24000000, 48000000, 96000000
+ 400000, 24000000, 48000000, 96000000, 192000000,
};
#ifdef CONFIG_MMC_MSM_SDC1_SUPPORT
@@ -264,7 +264,7 @@
.xpc_cap = 1,
.uhs_caps = (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 |
- MMC_CAP_MAX_CURRENT_600),
+ MMC_CAP_UHS_SDR104 | MMC_CAP_MAX_CURRENT_800),
};
#endif
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 278c08c..2c81e66 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -1938,62 +1938,62 @@
MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
- 100, 8000, 100000, 1,
+ 100, 650, 801, 200,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE,
MSM_RPMRS_LIMITS(ON, ACTIVE, MAX, ACTIVE),
true,
- 2000, 6000, 60100000, 3000,
+ 2000, 200, 576000, 2000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, GDHS, MAX, ACTIVE),
false,
- 4200, 5000, 60350000, 3500,
+ 8500, 51, 1122000, 8500,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, HSFS_OPEN, MAX, ACTIVE),
false,
- 6300, 4500, 65350000, 4800,
+ 9000, 51, 1130300, 9000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(ON, HSFS_OPEN, ACTIVE, RET_HIGH),
false,
- 7000, 3500, 66600000, 5150,
+ 10000, 51, 1130300, 10000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, GDHS, MAX, ACTIVE),
false,
- 11700, 2500, 67850000, 5500,
+ 12000, 14, 2205900, 12000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, MAX, ACTIVE),
false,
- 13800, 2000, 71850000, 6800,
+ 18000, 12, 2364250, 18000,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, ACTIVE, RET_HIGH),
false,
- 29700, 500, 75850000, 8800,
+ 23500, 10, 2667000, 23500,
},
{
MSM_PM_SLEEP_MODE_POWER_COLLAPSE,
MSM_RPMRS_LIMITS(OFF, HSFS_OPEN, RET_HIGH, RET_LOW),
false,
- 29700, 0, 76350000, 9800,
+ 29700, 5, 2867000, 30000,
},
};
diff --git a/arch/arm/mach-msm/board-8960-display.c b/arch/arm/mach-msm/board-8960-display.c
index 37a988a..7e92266 100644
--- a/arch/arm/mach-msm/board-8960-display.c
+++ b/arch/arm/mach-msm/board-8960-display.c
@@ -46,13 +46,8 @@
#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
#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
#define MSM_FB_OVERLAY0_WRITEBACK_SIZE roundup((1920 * 1200 * 3 * 2), 4096)
@@ -68,7 +63,6 @@
#define MDP_VSYNC_GPIO 0
-#define PANEL_NAME_MAX_LEN 30
#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME "mipi_cmd_novatek_qhd"
#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME "mipi_video_novatek_qhd"
#define MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME "mipi_video_toshiba_wsvga"
@@ -77,9 +71,17 @@
#define MIPI_VIDEO_CHIMEI_WUXGA_PANEL_NAME "mipi_video_chimei_wuxga"
#define MIPI_VIDEO_SIMULATOR_VGA_PANEL_NAME "mipi_video_simulator_vga"
#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME "mipi_cmd_renesas_fwvga"
+#define MIPI_VIDEO_ORISE_720P_PANEL_NAME "mipi_video_orise_720p"
+#define MIPI_CMD_ORISE_720P_PANEL_NAME "mipi_cmd_orise_720p"
#define HDMI_PANEL_NAME "hdmi_msm"
#define TVOUT_PANEL_NAME "tvout_msm"
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+unsigned char hdmi_is_primary = 1;
+#else
+unsigned char hdmi_is_primary;
+#endif
+
static struct resource msm_fb_resources[] = {
{
.flags = IORESOURCE_DMA,
@@ -139,6 +141,16 @@
set_mdp_clocks_for_wuxga();
return 0;
}
+
+ if (!strncmp(name, MIPI_VIDEO_ORISE_720P_PANEL_NAME,
+ strnlen(MIPI_VIDEO_ORISE_720P_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
+
+ if (!strncmp(name, MIPI_CMD_ORISE_720P_PANEL_NAME,
+ strnlen(MIPI_CMD_ORISE_720P_PANEL_NAME,
+ PANEL_NAME_MAX_LEN)))
+ return 0;
#endif
}
@@ -624,29 +636,16 @@
#endif
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static int mdp_core_clk_rate_table[] = {
- 200000000,
- 200000000,
- 200000000,
- 200000000,
-};
-#else
static int mdp_core_clk_rate_table[] = {
85330000,
128000000,
160000000,
200000000,
};
-#endif
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- .mdp_core_clk_rate = 200000000,
-#else
.mdp_core_clk_rate = 85330000,
-#endif
.mdp_core_clk_table = mdp_core_clk_rate_table,
.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
#ifdef CONFIG_MSM_BUS_SCALING
@@ -670,6 +669,12 @@
mdp_ui_vectors[0].ab = 2000000000;
mdp_ui_vectors[0].ib = 2000000000;
+ mdp_vga_vectors[0].ab = 2000000000;
+ mdp_vga_vectors[0].ib = 2000000000;
+ mdp_720p_vectors[0].ab = 2000000000;
+ mdp_720p_vectors[0].ib = 2000000000;
+ mdp_1080p_vectors[0].ab = 2000000000;
+ mdp_1080p_vectors[0].ib = 2000000000;
mdp_pdata.mdp_core_clk_rate = 200000000;
@@ -762,6 +767,11 @@
.dev.platform_data = &mipi_dsi2lvds_pdata,
};
+static struct platform_device mipi_dsi_orise_panel_device = {
+ .name = "mipi_orise",
+ .id = 0,
+};
+
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
static struct resource hdmi_msm_resources[] = {
{
@@ -827,16 +837,6 @@
},
};
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors dtv_bus_def_vectors[] = {
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 2000000000,
- .ib = 2000000000,
- },
-};
-#else
static struct msm_bus_vectors dtv_bus_def_vectors[] = {
{
.src = MSM_BUS_MASTER_MDP_PORT0,
@@ -845,7 +845,6 @@
.ib = 707616000 * 2,
},
};
-#endif
static struct msm_bus_paths dtv_bus_scale_usecases[] = {
{
@@ -1068,6 +1067,7 @@
if (!machine_is_msm8960_sim() && !machine_is_msm8960_rumi3()) {
platform_device_register(&mipi_dsi_novatek_panel_device);
+ platform_device_register(&mipi_dsi_orise_panel_device);
#ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
platform_device_register(&hdmi_msm_device);
@@ -1102,3 +1102,27 @@
pr_info("allocating %lu bytes at %p (%lx physical) for fb\n",
size, addr, __pa(addr));
}
+
+void __init msm8960_set_display_params(char *prim_panel, char *ext_panel)
+{
+ if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+ strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+ PANEL_NAME_MAX_LEN);
+ pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+ msm_fb_pdata.prim_panel_name);
+
+ if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+ HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME,
+ PANEL_NAME_MAX_LEN))) {
+ pr_debug("HDMI is the primary display by"
+ " boot parameter\n");
+ hdmi_is_primary = 1;
+ }
+ }
+ if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+ strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+ PANEL_NAME_MAX_LEN);
+ pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+ msm_fb_pdata.ext_panel_name);
+ }
+}
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index d98ae56..9c1a439 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -221,7 +221,6 @@
};
VREG_CONSUMERS(USB_OTG) = {
REGULATOR_SUPPLY("8921_usb_otg", NULL),
- REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
};
VREG_CONSUMERS(HDMI_MVS) = {
REGULATOR_SUPPLY("8921_hdmi_mvs", NULL),
@@ -245,12 +244,12 @@
};
VREG_CONSUMERS(EXT_OTG_SW) = {
REGULATOR_SUPPLY("ext_otg_sw", NULL),
+ REGULATOR_SUPPLY("vbus_otg", "msm_otg"),
};
#define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
_apply_uV, _pull_down, _always_on, _supply_regulator, \
- _system_uA, _enable_time, _reg_id, _ocp_enable, \
- _ocp_enable_time) \
+ _system_uA, _enable_time, _reg_id) \
{ \
.init_data = { \
.constraints = { \
@@ -272,8 +271,6 @@
.pull_down_enable = _pull_down, \
.system_uA = _system_uA, \
.enable_time = _enable_time, \
- .ocp_enable = _ocp_enable, \
- .ocp_enable_time = _ocp_enable_time, \
}
#define PM8XXX_LDO(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
@@ -282,7 +279,7 @@
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
#define PM8XXX_NLDO1200(_id, _name, _always_on, _pull_down, _min_uV, \
_max_uV, _enable_time, _supply_regulator, _system_uA, _reg_id) \
@@ -290,7 +287,7 @@
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
#define PM8XXX_SMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
_enable_time, _supply_regulator, _system_uA, _reg_id) \
@@ -298,32 +295,32 @@
| REGULATOR_MODE_IDLE, REGULATOR_CHANGE_VOLTAGE | \
REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE | \
REGULATOR_CHANGE_DRMS, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
#define PM8XXX_FTSMPS(_id, _name, _always_on, _pull_down, _min_uV, _max_uV, \
_enable_time, _supply_regulator, _system_uA, _reg_id) \
PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, REGULATOR_MODE_NORMAL, \
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS \
| REGULATOR_CHANGE_MODE, 0, _pull_down, _always_on, \
- _supply_regulator, _system_uA, _enable_time, _reg_id, 0, 0)
+ _supply_regulator, _system_uA, _enable_time, _reg_id)
#define PM8XXX_VS(_id, _name, _always_on, _pull_down, _enable_time, \
- _ocp_enable, _ocp_enable_time, _supply_regulator, _reg_id) \
+ _supply_regulator, _reg_id) \
PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
- _reg_id, _ocp_enable, _ocp_enable_time)
+ _reg_id)
#define PM8XXX_VS300(_id, _name, _always_on, _pull_down, _enable_time, \
- _ocp_enable, _ocp_enable_time, _supply_regulator, _reg_id) \
+ _supply_regulator, _reg_id) \
PM8XXX_VREG_INIT(_id, _name, 0, 0, 0, REGULATOR_CHANGE_STATUS, 0, \
_pull_down, _always_on, _supply_regulator, 0, _enable_time, \
- _reg_id, _ocp_enable, _ocp_enable_time)
+ _reg_id)
#define PM8XXX_NCP(_id, _name, _always_on, _min_uV, _max_uV, _enable_time, \
_supply_regulator, _reg_id) \
PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, 0, \
REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, 0, 0, \
- _always_on, _supply_regulator, 0, _enable_time, _reg_id, 0, 0)
+ _always_on, _supply_regulator, 0, _enable_time, _reg_id)
/* Pin control initialization */
#define PM8XXX_PC(_id, _name, _always_on, _pin_fn, _pin_ctrl, \
@@ -472,7 +469,7 @@
GPIO_VREG(EXT_3P3V, "ext_3p3v", "ext_3p3v_en",
PM8921_GPIO_PM_TO_SYS(17), NULL),
GPIO_VREG(EXT_OTG_SW, "ext_otg_sw", "ext_otg_sw_en",
- PM8921_GPIO_PM_TO_SYS(42), "ext_5v"),
+ PM8921_GPIO_PM_TO_SYS(42), "8921_usb_otg"),
};
/* SAW regulator constraints */
@@ -498,13 +495,9 @@
PM8XXX_LDO(L29, "8921_l29", 0, 1, 2050000, 2100000, 200, "8921_s8",
0, 4),
- /*
- * ID name always_on pd en_t ocp ocp_t supply
- * reg_ID
- */
- PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 0, 0, 1, 500, "ext_otg_sw",
- 5),
- PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0, 0, 0, "ext_5v", 6),
+ /* ID name always_on pd en_t supply reg_ID */
+ PM8XXX_VS300(USB_OTG, "8921_usb_otg", 0, 1, 0, "ext_5v", 5),
+ PM8XXX_VS300(HDMI_MVS, "8921_hdmi_mvs", 0, 1, 0, "ext_5v", 6),
};
static struct rpm_regulator_init_data
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 7fd6820..3b0f8be 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -131,12 +131,9 @@
#define MSM_PMEM_ADSP_SIZE 0x7800000
#define MSM_PMEM_AUDIO_SIZE 0x2B4000
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
-#else
#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
-#endif
#define MSM_LIQUID_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#define MSM_HDMI_PRIM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x280000
@@ -148,7 +145,9 @@
#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)
-static unsigned int msm_ion_cp_mm_size = MSM_ION_MM_SIZE;
+#define MSM_LIQUID_ION_SF_SIZE MSM_LIQUID_PMEM_SIZE
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SIZE
+static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
#else
#define MSM_PMEM_KERNEL_EBI1_SIZE 0x110C000
#define MSM_ION_HEAP_NUM 1
@@ -308,8 +307,13 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
android_pmem_adsp_pdata.size = pmem_adsp_size;
- if (!pmem_param_set && machine_is_msm8960_liquid())
- pmem_size = MSM_LIQUID_PMEM_SIZE;
+ if (!pmem_param_set) {
+ if (machine_is_msm8960_liquid())
+ pmem_size = MSM_LIQUID_PMEM_SIZE;
+ if (hdmi_is_primary)
+ pmem_size = MSM_HDMI_PRIM_PMEM_SIZE;
+ }
+
android_pmem_pdata.size = pmem_size;
#endif
android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
@@ -463,14 +467,22 @@
{
unsigned int i;
- if (!pmem_param_set && machine_is_msm8960_liquid()) {
- msm_ion_cp_mm_size = MSM_LIQUID_ION_MM_SIZE;
- for (i = 0; i < ion_pdata.nr; i++) {
- if (ion_pdata.heaps[i].id == ION_CP_MM_HEAP_ID) {
- ion_pdata.heaps[i].size = msm_ion_cp_mm_size;
- pr_debug("msm_ion_cp_mm_size 0x%x\n",
- msm_ion_cp_mm_size);
- break;
+ if (!pmem_param_set) {
+ if (machine_is_msm8960_liquid())
+ msm_ion_sf_size = MSM_LIQUID_ION_SF_SIZE;
+
+ if (hdmi_is_primary)
+ msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
+
+ if (machine_is_msm8960_liquid() || hdmi_is_primary) {
+ for (i = 0; i < ion_pdata.nr; i++) {
+ if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) {
+ ion_pdata.heaps[i].size =
+ msm_ion_sf_size;
+ pr_debug("msm_ion_sf_size 0x%x\n",
+ msm_ion_sf_size);
+ break;
+ }
}
}
}
@@ -633,8 +645,27 @@
place_movable_zone();
}
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+ if (strnlen(param, PANEL_NAME_MAX_LEN))
+ strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+ return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+ if (strnlen(param, PANEL_NAME_MAX_LEN))
+ strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+ return 0;
+}
+early_param("ext_display", ext_display_setup);
+
static void __init msm8960_reserve(void)
{
+ msm8960_set_display_params(prim_panel_name, ext_panel_name);
msm_reserve();
fmem_pdata.phys = reserve_memory_for_fmem(fmem_pdata.size);
}
@@ -1884,6 +1915,7 @@
.variant_id = 0x0,
.version = 0x10,
.build = 0xAA,
+ .bootldr_id = MXT_BOOTLOADER_ID_1386,
},
{
.config = mxt1386e_config_data_v1_0,
@@ -1892,6 +1924,8 @@
.variant_id = 0x2,
.version = 0x10,
.build = 0xAA,
+ .bootldr_id = MXT_BOOTLOADER_ID_1386E,
+ .fw_name = "atmel_8960_liquid_v2_1_AA.hex",
},
{
.config = mxt1386e_config_data_v2_1,
@@ -1900,6 +1934,7 @@
.variant_id = 0x7,
.version = 0x21,
.build = 0xAA,
+ .bootldr_id = MXT_BOOTLOADER_ID_1386E,
},
};
@@ -2080,8 +2115,8 @@
&msm_device_saw_core0,
&msm_device_saw_core1,
&msm8960_device_ext_5v_vreg,
- &msm8960_device_ext_otg_sw_vreg,
&msm8960_device_ssbi_pmic,
+ &msm8960_device_ext_otg_sw_vreg,
&msm8960_device_qup_spi_gsbi1,
&msm8960_device_qup_i2c_gsbi3,
&msm8960_device_qup_i2c_gsbi4,
@@ -2119,6 +2154,14 @@
&msm_device_bam_dmux,
&msm_fm_platform_init,
+#if defined(CONFIG_TSIF) || defined(CONFIG_TSIF_MODULE)
+#ifdef CONFIG_MSM_USE_TSIF1
+ &msm_device_tsif[1],
+#else
+ &msm_device_tsif[0],
+#endif
+#endif
+
#ifdef CONFIG_HW_RANDOM_MSM
&msm_device_rng,
#endif
diff --git a/arch/arm/mach-msm/board-8960.h b/arch/arm/mach-msm/board-8960.h
index 20af7b8..dc63fee 100644
--- a/arch/arm/mach-msm/board-8960.h
+++ b/arch/arm/mach-msm/board-8960.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* 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
@@ -73,12 +73,15 @@
extern struct sx150x_platform_data msm8960_sx150x_data[];
extern struct msm_camera_board_info msm8960_camera_board_info;
+extern unsigned char hdmi_is_primary;
+
void msm8960_init_cam(void);
void msm8960_init_fb(void);
void msm8960_init_pmic(void);
void msm8960_init_mmc(void);
int msm8960_init_gpiomux(void);
void msm8960_allocate_fb_region(void);
+void msm8960_set_display_params(char *prim_panel, char *ext_panel);
void msm8960_pm8921_gpio_mpp_init(void);
void msm8960_mdp_writeback(struct memtype_reserve *reserve_table);
uint32_t msm_rpm_get_swfi_latency(void);
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index dc26d72..c30be16 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -37,6 +37,7 @@
#endif
#include <mach/msm_memtypes.h>
#include <mach/msm_smd.h>
+#include <mach/qpnp-int.h>
#include "clock.h"
#define MSM_KERNEL_EBI1_MEM_SIZE 0x280000
@@ -361,6 +362,7 @@
static struct of_device_id irq_match[] __initdata = {
{ .compatible = "qcom,msm-qgic2", .data = gic_of_init, },
{ .compatible = "qcom,msm-gpio", .data = msm_gpio_of_init, },
+ { .compatible = "qcom,spmi-pmic-arb", .data = qpnpint_of_init, },
{}
};
diff --git a/arch/arm/mach-msm/board-msm7627a-bt.c b/arch/arm/mach-msm/board-msm7627a-bt.c
index c70b30e..a8ab81a 100644
--- a/arch/arm/mach-msm/board-msm7627a-bt.c
+++ b/arch/arm/mach-msm/board-msm7627a-bt.c
@@ -32,7 +32,7 @@
{"bt", 21, 2900000, 3300000, 1, NULL}
};
-struct platform_device msm_bt_power_device = {
+static struct platform_device msm_bt_power_device = {
.name = "bt_power",
};
@@ -100,7 +100,7 @@
{
if (machine_is_msm7627a_qrd1())
gpio_bt_sys_rest_en = 114;
- if (machine_is_msm7627a_evb())
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
gpio_bt_sys_rest_en = 16;
}
@@ -109,14 +109,36 @@
int rc = 0;
struct marimba config = { .mod_id = SLAVE_ID_BAHAMA};
+ pr_debug("%s: Setting SYS_RST_PIN(%d) to %d\n",
+ __func__, gpio_bt_sys_rest_en, on);
if (on) {
- rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+
+ if (machine_is_msm7627a_evb()) {
+ rc = gpio_tlmm_config(GPIO_CFG(gpio_bt_sys_rest_en, 0,
+ GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
+ GPIO_CFG_2MA),
+ GPIO_CFG_ENABLE);
+
+ gpio_set_value(gpio_bt_sys_rest_en, 1);
+ } else {
+ rc = gpio_direction_output(gpio_bt_sys_rest_en, 1);
+ }
msleep(100);
} else {
+
if (!marimba_get_fm_status(&config) &&
!marimba_get_bt_status(&config)) {
- gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
- rc = gpio_direction_input(gpio_bt_sys_rest_en);
+ if (machine_is_msm7627a_evb()) {
+ gpio_set_value(gpio_bt_sys_rest_en, 0);
+ rc = gpio_tlmm_config(GPIO_CFG(
+ gpio_bt_sys_rest_en, 0,
+ GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN,
+ GPIO_CFG_2MA),
+ GPIO_CFG_ENABLE);
+ } else {
+ gpio_set_value_cansleep(gpio_bt_sys_rest_en, 0);
+ rc = gpio_direction_input(gpio_bt_sys_rest_en);
+ }
msleep(100);
}
}
@@ -324,7 +346,8 @@
int pin, rc = 0;
if (mode == FM_I2S_ON) {
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+ || machine_is_msm8625_surf())
config_pcm_i2s_mode(0);
pr_err("%s mode = FM_I2S_ON", __func__);
@@ -367,7 +390,8 @@
int pin, rc = 0;
if (mode == BT_PCM_ON) {
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+ || machine_is_msm8625_surf())
config_pcm_i2s_mode(1);
pr_err("%s mode =BT_PCM_ON", __func__);
rc = switch_pcm_i2s_reg_mode(1);
@@ -940,9 +964,20 @@
gpio_bt_config();
- i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- bahama_devices,
- ARRAY_SIZE(bahama_devices));
+ rc = i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
+ bahama_devices,
+ ARRAY_SIZE(bahama_devices));
+ if (rc < 0) {
+ pr_err("%s: I2C Register failed\n", __func__);
+ return;
+ }
+
+ rc = platform_device_register(&msm_bt_power_device);
+ if (rc < 0) {
+ pr_err("%s: device register failed\n", __func__);
+ return;
+ }
+
dev = &msm_bt_power_device.dev;
for (i = 0; i < ARRAY_SIZE(bt_vregs); i++) {
@@ -964,6 +999,6 @@
regulator_put(bt_vregs[i].reg);
bt_vregs[i].reg = NULL;
}
- return;
+ platform_device_unregister(&msm_bt_power_device);
}
#endif
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
index 06fbb7b..7b075cd 100644
--- a/arch/arm/mach-msm/board-msm7627a-camera.c
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -1041,7 +1041,7 @@
pr_debug("msm7627a_camera_init Entered\n");
/* LCD and camera power (VREG & LDO) init */
- if (machine_is_msm7627a_evb())
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
lcd_camera_power_init();
#ifndef CONFIG_MSM_CAMERA_V4L2
@@ -1049,7 +1049,7 @@
qrd1_camera_gpio_cfg();
platform_add_devices(camera_devices_qrd,
ARRAY_SIZE(camera_devices_qrd));
- } else if (machine_is_msm7627a_evb()) {
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
evb_camera_gpio_cfg();
platform_add_devices(camera_devices_evb,
ARRAY_SIZE(camera_devices_evb));
@@ -1059,7 +1059,8 @@
platform_add_devices(camera_devices_msm,
ARRAY_SIZE(camera_devices_msm));
#endif
- if (!machine_is_msm7627a_qrd1() || !machine_is_msm7627a_evb())
+ if (!machine_is_msm7627a_qrd1() || !machine_is_msm7627a_evb()
+ || !machine_is_msm8625_evb())
register_i2c_devices();
rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
@@ -1083,7 +1084,7 @@
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()) {
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
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 4e856b1..b1fe0c7 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -208,7 +208,6 @@
}
};
-#define PANEL_NAME_MAX_LEN 30
#define LCDC_TOSHIBA_FWVGA_PANEL_NAME "lcdc_toshiba_fwvga_pt"
#define MIPI_CMD_RENESAS_FWVGA_PANEL_NAME "mipi_cmd_renesas_fwvga"
@@ -216,7 +215,8 @@
{
int ret = -ENODEV;
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+ machine_is_msm8625_surf()) {
if (!strncmp(name, "lcdc_toshiba_fwvga_pt", 21) ||
!strncmp(name, "mipi_cmd_renesas_fwvga", 22))
ret = 0;
@@ -226,7 +226,7 @@
} else if (machine_is_msm7627a_qrd1()) {
if (!strncmp(name, "mipi_video_truly_wvga", 21))
ret = 0;
- } else if (machine_is_msm7627a_evb()) {
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
if (!strncmp(name, "mipi_cmd_nt35510_wvga", 21))
ret = 0;
}
@@ -235,7 +235,8 @@
!defined(CONFIG_FB_MSM_MIPI_PANEL_AUTO_DETECT) && \
!defined(CONFIG_FB_MSM_LCDC_MIPI_PANEL_AUTO_DETECT)
if (machine_is_msm7x27a_surf() ||
- machine_is_msm7625a_surf()) {
+ machine_is_msm7625a_surf() ||
+ machine_is_msm8625_surf()) {
if (!strncmp(name, LCDC_TOSHIBA_FWVGA_PANEL_NAME,
strnlen(LCDC_TOSHIBA_FWVGA_PANEL_NAME,
PANEL_NAME_MAX_LEN)))
@@ -427,7 +428,8 @@
gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 0);
if (!rc) {
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+ || machine_is_msm8625_surf()) {
lcdc_reset_ptr = ioremap_nocache(LCDC_RESET_PHYS,
sizeof(uint32_t));
@@ -555,7 +557,7 @@
if (machine_is_msm7627a_qrd1())
rc = msm_fb_dsi_client_qrd1_reset();
- else if (machine_is_msm7627a_evb())
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
rc = msm_fb_dsi_client_qrd3_reset();
else
rc = msm_fb_dsi_client_msm_reset();
@@ -586,7 +588,8 @@
return rc;
}
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()
+ || machine_is_msm8625_surf()) {
rc = gpio_direction_output(GPIO_DISPLAY_PWR_EN, 1);
if (rc < 0) {
pr_err("failed to enable display pwr\n");
@@ -625,7 +628,8 @@
dsi_gpio_initialized = 1;
}
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf()) {
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+ machine_is_msm8625_surf()) {
gpio_set_value_cansleep(GPIO_DISPLAY_PWR_EN, on);
gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, on);
} else if (machine_is_msm7x27a_ffa() ||
@@ -649,7 +653,8 @@
gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 0);
if (machine_is_msm7x27a_surf() ||
- machine_is_msm7625a_surf()) {
+ machine_is_msm7625a_surf() ||
+ machine_is_msm8625_surf()) {
lcdc_reset_cfg = readl_relaxed(lcdc_reset_ptr);
rmb();
lcdc_reset_cfg &= ~1;
@@ -817,7 +822,7 @@
if (machine_is_msm7627a_qrd1())
rc = mipi_dsi_panel_qrd1_power(on);
- else if (machine_is_msm7627a_evb())
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
rc = mipi_dsi_panel_qrd3_power(on);
else
rc = mipi_dsi_panel_msm_power(on);
@@ -840,7 +845,7 @@
if (machine_is_msm7627a_qrd1())
platform_add_devices(qrd_fb_devices,
ARRAY_SIZE(qrd_fb_devices));
- else if (machine_is_msm7627a_evb())
+ else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
platform_add_devices(evb_fb_devices,
ARRAY_SIZE(evb_fb_devices));
else if (machine_is_msm7627a_qrd3())
@@ -850,7 +855,8 @@
ARRAY_SIZE(msm_fb_devices));
msm_fb_register_device("mdp", &mdp_pdata);
- if (machine_is_msm7625a_surf() || machine_is_msm7x27a_surf())
+ if (machine_is_msm7625a_surf() || machine_is_msm7x27a_surf() ||
+ machine_is_msm8625_surf())
msm_fb_register_device("lcdc", &lcdc_pdata);
#ifdef CONFIG_FB_MSM_MDP303
msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
diff --git a/arch/arm/mach-msm/board-msm7627a-storage.c b/arch/arm/mach-msm/board-msm7627a-storage.c
index 3bb9c8b..e4ee52e 100644
--- a/arch/arm/mach-msm/board-msm7627a-storage.c
+++ b/arch/arm/mach-msm/board-msm7627a-storage.c
@@ -150,7 +150,8 @@
static int gpio_sdc1_hw_det = 85;
static void gpio_sdc1_config(void)
{
- if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb())
+ if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+ || machine_is_msm8625_evb())
gpio_sdc1_hw_det = 42;
}
@@ -251,7 +252,8 @@
status = gpio_direction_input(gpio_sdc1_hw_det);
if (!status) {
if (machine_is_msm7627a_qrd1() ||
- machine_is_msm7627a_evb())
+ machine_is_msm7627a_evb() ||
+ machine_is_msm8625_evb())
status = !gpio_get_value(gpio_sdc1_hw_det);
else
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 6df7626..53d3c56 100644
--- a/arch/arm/mach-msm/board-msm7627a-wlan.c
+++ b/arch/arm/mach-msm/board-msm7627a-wlan.c
@@ -48,7 +48,8 @@
int gpio_wlan_sys_rest_en = 134;
static void gpio_wlan_config(void)
{
- if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb())
+ if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+ || machine_is_msm8625_evb())
gpio_wlan_sys_rest_en = 124;
}
@@ -229,7 +230,8 @@
* gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
* EVB1.0 and QRD8625,so the below step is required for those devices.
*/
- if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()) {
+ if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+ || machine_is_msm8625_evb()) {
rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA), GPIO_CFG_ENABLE);
@@ -302,7 +304,8 @@
* gpio_wlan_sys_rest_en is not from the GPIO expander for QRD7627a,
* EVB1.0 and QRD8625,so the below step is required for those devices.
*/
- if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()) {
+ if (machine_is_msm7627a_qrd1() || machine_is_msm7627a_evb()
+ || machine_is_msm8625_evb()) {
rc = gpio_tlmm_config(GPIO_CFG(gpio_wlan_sys_rest_en, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_2MA), GPIO_CFG_ENABLE);
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index dfd013c..bde9b61 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.h
@@ -66,6 +66,7 @@
QRD_GPIO_CAM_GP_CAMIF_RESET,
};
+#define ADSP_RPC_PROG 0x3000000a
#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
#define FPGA_MSM_CNTRL_REG2 0x90008010
@@ -98,8 +99,6 @@
struct regulator *reg;
};
-extern struct platform_device msm_bt_power_device;
-
void __init msm7627a_bt_power_init(void);
#endif
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index d1c68f3..b44b03f 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -14,6 +14,7 @@
#include <linux/gpio_event.h>
#include <linux/memblock.h>
#include <asm/mach-types.h>
+#include <linux/memblock.h>
#include <asm/mach/arch.h>
#include <asm/hardware/gic.h>
#include <mach/board.h>
@@ -60,7 +61,6 @@
#define PMEM_KERNEL_EBI1_SIZE 0x3A000
#define MSM_PMEM_AUDIO_SIZE 0x5B000
-#define ADSP_RPC_PROG 0x3000000a
#if defined(CONFIG_GPIO_SX150X)
enum {
@@ -94,7 +94,8 @@
static void __init register_i2c_devices(void)
{
- if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
+ if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf() ||
+ machine_is_msm8625_surf())
sx150x_data[SX150X_CORE].io_open_drain_ena = 0xe0f0;
core_exp_i2c_info[0].platform_data =
@@ -154,10 +155,6 @@
.msm_i2c_config_gpio = gsbi_qup_i2c_gpio_config,
};
-static struct msm_i2c_platform_data msm8625_gsbi0_qup_i2c_pdata = {
- .clk_freq = 100000,
-};
-
#ifdef CONFIG_ARCH_MSM7X27A
#define MSM_PMEM_MDP_SIZE 0x2300000
#define MSM7x25A_MSM_PMEM_MDP_SIZE 0x1500000
@@ -387,6 +384,72 @@
.p_addr = 0,
};
+/* 8625 PM platform data */
+static struct msm_pm_platform_data msm8625_pm_data[MSM_PM_SLEEP_MODE_NR * 2] = {
+ /* CORE0 entries */
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ .latency = 16000,
+ .residency = 20000,
+ },
+
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ .latency = 12000,
+ .residency = 20000,
+ },
+
+ /* picked latency & redisdency values from 7x30 */
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ .latency = 500,
+ .residency = 6000,
+ },
+
+ [MSM_PM_MODE(0, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 1,
+ .suspend_enabled = 1,
+ .latency = 2,
+ .residency = 10,
+ },
+
+ /* picked latency & redisdency values from 7x30 */
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 0,
+ .suspend_enabled = 0,
+ .latency = 500,
+ .residency = 6000,
+ },
+
+ [MSM_PM_MODE(1, MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)] = {
+ .idle_supported = 1,
+ .suspend_supported = 1,
+ .idle_enabled = 1,
+ .suspend_enabled = 1,
+ .latency = 2,
+ .residency = 10,
+ },
+
+};
+
+static struct msm_pm_boot_platform_data msm_pm_8625_boot_pdata __initdata = {
+ .mode = MSM_PM_BOOT_CONFIG_REMAP_BOOT_ADDR,
+ .v_addr = MSM_CFG_CTL_BASE,
+};
+
static struct android_pmem_platform_data android_pmem_adsp_pdata = {
.name = "pmem_adsp",
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
@@ -718,37 +781,51 @@
static struct platform_device *msm8625_rumi3_devices[] __initdata = {
&msm8625_device_dmov,
+ &msm8625_device_smd,
&msm8625_device_uart1,
- &msm8625_device_qup_i2c_gsbi0,
+ &msm8625_gsbi0_qup_i2c_device,
};
-static struct platform_device *surf_ffa_devices[] __initdata = {
+static struct platform_device *msm7627a_surf_ffa_devices[] __initdata = {
&msm_device_dmov,
&msm_device_smd,
&msm_device_uart1,
&msm_device_uart_dm1,
&msm_device_uart_dm2,
- &msm_device_nand,
&msm_gsbi0_qup_i2c_device,
&msm_gsbi1_qup_i2c_device,
&msm_device_otg,
&msm_device_gadget_peripheral,
- &fmem_device,
+ &smsc911x_device,
+ &msm_kgsl_3d0,
+};
+
+static struct platform_device *common_devices[] __initdata = {
&android_usb_device,
&android_pmem_device,
&android_pmem_adsp_device,
&android_pmem_audio_device,
+ &fmem_device,
+ &msm_device_nand,
&msm_device_snd,
&msm_device_adspdec,
- &msm_batt_device,
- &smsc911x_device,
- &msm_kgsl_3d0,
-#ifdef CONFIG_BT
- &msm_bt_power_device,
-#endif
&asoc_msm_pcm,
&asoc_msm_dai0,
&asoc_msm_dai1,
+ &msm_batt_device,
+};
+
+static struct platform_device *msm8625_surf_devices[] __initdata = {
+ &msm8625_device_dmov,
+ &msm8625_device_uart1,
+ &msm8625_device_uart_dm1,
+ &msm8625_device_uart_dm2,
+ &msm8625_gsbi0_qup_i2c_device,
+ &msm8625_gsbi1_qup_i2c_device,
+ &msm8625_device_smd,
+ &msm8625_device_otg,
+ &msm8625_device_gadget_peripheral,
+ &msm8625_kgsl_3d0,
};
static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
@@ -870,21 +947,25 @@
static void __init msm8625_reserve(void)
{
+ msm7x27a_reserve();
memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+ msm_pm_8625_boot_pdata.p_addr = memblock_alloc(SZ_8, SZ_64K);
}
-static void __init msm_device_i2c_init(void)
+static void __init msm7x27a_device_i2c_init(void)
{
- if (machine_is_msm8625_rumi3()) {
- msm8625_device_qup_i2c_gsbi0.dev.platform_data =
- &msm8625_gsbi0_qup_i2c_pdata;
- return;
- }
-
msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata;
msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata;
}
+static void __init msm8625_device_i2c_init(void)
+{
+ msm8625_gsbi0_qup_i2c_device.dev.platform_data =
+ &msm_gsbi0_qup_i2c_pdata;
+ msm8625_gsbi1_qup_i2c_device.dev.platform_data =
+ &msm_gsbi1_qup_i2c_pdata;
+}
+
#define MSM_EBI2_PHYS 0xa0d00000
#define MSM_EBI2_XMEM_CS2_CFG1 0xa0d10030
@@ -899,7 +980,7 @@
ebi2_cfg = readl(ebi2_cfg_ptr);
if (machine_is_msm7x27a_rumi3() || machine_is_msm7x27a_surf() ||
- machine_is_msm7625a_surf())
+ machine_is_msm7625a_surf() || machine_is_msm8625_surf())
ebi2_cfg |= (1 << 4); /* CS2 */
writel(ebi2_cfg, ebi2_cfg_ptr);
@@ -1147,7 +1228,11 @@
return;
}
rpc_adsp_pdev->prog = ADSP_RPC_PROG;
- rpc_adsp_pdev->pdev = msm_adsp_device;
+
+ if (cpu_is_msm8625())
+ rpc_adsp_pdev->pdev = msm8625_device_adsp;
+ else
+ rpc_adsp_pdev->pdev = msm_adsp_device;
rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
if (rc < 0) {
pr_err("%s: return val: %d\n", __func__, rc);
@@ -1155,25 +1240,6 @@
}
}
-static void msm_adsp_8625_add_pdev(void)
-{
- int rc = 0;
- struct rpc_board_dev *rpc_adsp_pdev;
-
- rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
- if (rpc_adsp_pdev == NULL) {
- pr_err("%s: Memory Allocation failure\n", __func__);
- return;
- }
- rpc_adsp_pdev->prog = ADSP_RPC_PROG;
- rpc_adsp_pdev->pdev = msm8625_device_adsp;
- rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
- if (rc < 0) {
- pr_err("%s: return val: %d\n", __func__, rc);
- kfree(rpc_adsp_pdev);
- }
-}
-
static void __init msm7627a_rumi3_init(void)
{
msm7x27a_init_ebi2();
@@ -1184,10 +1250,15 @@
static void __init msm8625_rumi3_init(void)
{
msm7x2x_misc_init();
- msm_adsp_8625_add_pdev();
- msm_device_i2c_init();
+ msm_adsp_add_pdev();
+ msm8625_device_i2c_init();
platform_add_devices(msm8625_rumi3_devices,
ARRAY_SIZE(msm8625_rumi3_devices));
+
+ msm_pm_set_platform_data(msm8625_pm_data,
+ ARRAY_SIZE(msm8625_pm_data));
+ BUG_ON(msm_pm_boot_init(&msm_pm_8625_boot_pdata));
+ msm8x25_spm_device_init();
}
#define LED_GPIO_PDM 96
@@ -1211,56 +1282,56 @@
__func__, rc);
}
-static void __init msm7x2x_init(void)
+static void __init msm7x27a_add_footswitch_devices(void)
{
- msm7x2x_misc_init();
-
- /* Initialize regulators first so that other devices can use them */
- msm7x27a_init_regulators();
-
- /* Common functions for SURF/FFA/RUMI3 */
- msm_adsp_add_pdev();
- msm_device_i2c_init();
- msm7x27a_init_ebi2();
- msm7x27a_cfg_uart2dm_serial();
-#ifdef CONFIG_SERIAL_MSM_HS
- msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
- msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
-#endif
-
-#ifdef CONFIG_USB_MSM_OTG_72K
- msm_otg_pdata.swfi_latency =
- msm7x27a_pm_data
- [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
- msm_device_otg.dev.platform_data = &msm_otg_pdata;
-#endif
- msm_device_gadget_peripheral.dev.platform_data =
- &msm_gadget_pdata;
- msm7x27a_cfg_smsc911x();
platform_add_devices(msm_footswitch_devices,
msm_num_footswitch_devices);
- platform_add_devices(surf_ffa_devices,
- ARRAY_SIZE(surf_ffa_devices));
- /* Ensure ar6000pm device is registered before MMC/SDC */
- msm7x27a_init_ar6000pm();
-#ifdef CONFIG_MMC_MSM
- msm7627a_init_mmc();
-#endif
- msm_fb_add_devices();
-#ifdef CONFIG_USB_EHCI_MSM_72K
- msm7x2x_init_host();
-#endif
+}
- msm_pm_set_platform_data(msm7x27a_pm_data,
- ARRAY_SIZE(msm7x27a_pm_data));
- BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+static void __init msm7x27a_add_platform_devices(void)
+{
+ if (machine_is_msm8625_surf()) {
+ platform_add_devices(msm8625_surf_devices,
+ ARRAY_SIZE(msm8625_surf_devices));
+ } else {
+ platform_add_devices(msm7627a_surf_ffa_devices,
+ ARRAY_SIZE(msm7627a_surf_ffa_devices));
+ }
-#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
- register_i2c_devices();
-#endif
-#if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
- msm7627a_bt_power_init();
-#endif
+ platform_add_devices(common_devices,
+ ARRAY_SIZE(common_devices));
+}
+
+static void __init msm7x27a_uartdm_config(void)
+{
+ msm7x27a_cfg_uart2dm_serial();
+ msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
+ if (cpu_is_msm8625())
+ msm8625_device_uart_dm1.dev.platform_data =
+ &msm_uart_dm1_pdata;
+ else
+ msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+}
+
+static void __init msm7x27a_otg_gadget(void)
+{
+ msm_otg_pdata.swfi_latency =
+ msm7x27a_pm_data[
+ MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+ if (cpu_is_msm8625()) {
+ msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
+ msm8625_device_gadget_peripheral.dev.platform_data =
+ &msm_gadget_pdata;
+ } else {
+ msm_device_otg.dev.platform_data = &msm_otg_pdata;
+ msm_device_gadget_peripheral.dev.platform_data =
+ &msm_gadget_pdata;
+ }
+}
+
+static void __init msm7x27a_add_io_devices(void)
+{
+ /* touchscreen */
if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
atmel_ts_pdata.min_x = 0;
atmel_ts_pdata.max_x = 480;
@@ -1269,16 +1340,15 @@
}
i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
- atmel_ts_i2c_info,
- ARRAY_SIZE(atmel_ts_i2c_info));
-
-#if defined(CONFIG_MSM_CAMERA)
- msm7627a_camera_init();
-#endif
+ atmel_ts_i2c_info,
+ ARRAY_SIZE(atmel_ts_i2c_info));
+ /* keypad */
platform_device_register(&kp_pdev);
+
+ /* headset */
platform_device_register(&hs_pdev);
- /* configure it as a pdm function*/
+ /* LED: configure it as a pdm function */
if (gpio_tlmm_config(GPIO_CFG(LED_GPIO_PDM, 3,
GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
GPIO_CFG_8MA), GPIO_CFG_ENABLE))
@@ -1287,10 +1357,50 @@
else
platform_device_register(&led_pdev);
-#ifdef CONFIG_MSM_RPC_VIBRATOR
+ /* Vibrator */
if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
msm_init_pmic_vibrator();
-#endif
+}
+
+static void __init msm7x27a_pm_init(void)
+{
+ if (machine_is_msm8625_surf())
+ return;
+
+ msm_pm_set_platform_data(msm7x27a_pm_data,
+ ARRAY_SIZE(msm7x27a_pm_data));
+ BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+}
+
+static void __init msm7x2x_init(void)
+{
+ msm7x2x_misc_init();
+
+ /* Initialize regulators first so that other devices can use them */
+ msm7x27a_init_regulators();
+ msm_adsp_add_pdev();
+ if (cpu_is_msm8625())
+ msm8625_device_i2c_init();
+ else
+ msm7x27a_device_i2c_init();
+ msm7x27a_init_ebi2();
+ msm7x27a_uartdm_config();
+
+ msm7x27a_otg_gadget();
+ msm7x27a_cfg_smsc911x();
+
+ msm7x27a_add_footswitch_devices();
+ msm7x27a_add_platform_devices();
+ /* Ensure ar6000pm device is registered before MMC/SDC */
+ msm7x27a_init_ar6000pm();
+ msm7627a_init_mmc();
+ msm_fb_add_devices();
+ msm7x2x_init_host();
+ msm7x27a_pm_init();
+ register_i2c_devices();
+ msm7627a_bt_power_init();
+ msm7627a_camera_init();
+ msm7x27a_add_io_devices();
/*7x25a kgsl initializations*/
msm7x25a_kgsl_3d0_init();
}
@@ -1359,3 +1469,13 @@
.timer = &msm_timer,
.handle_irq = gic_handle_irq,
MACHINE_END
+MACHINE_START(MSM8625_SURF, "QCT MSM8625 SURF")
+ .boot_params = PHYS_OFFSET + 0x100,
+ .map_io = msm8625_map_io,
+ .reserve = msm8625_reserve,
+ .init_irq = msm8625_init_irq,
+ .init_machine = msm7x2x_init,
+ .timer = &msm_timer,
+ .init_early = msm7x2x_init_early,
+ .handle_irq = gic_handle_irq,
+MACHINE_END
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index 260c880..9f7104f 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -5236,7 +5236,8 @@
&msm_batt_device,
&msm_adc_device,
&msm_ebi0_thermal,
- &msm_ebi1_thermal
+ &msm_ebi1_thermal,
+ &msm_adsp_device
};
static struct msm_gpio msm_i2c_gpios_hw[] = {
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index e3fc97f..9b5e1e2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -119,7 +119,6 @@
#define LCDC_AUO_SPI_DEVICE_NAME "lcdc_auo_nt35582"
#define LCDC_NT35582_PANEL_NAME "lcdc_nt35582_wvga"
-#define PANEL_NAME_MAX_LEN 30
#define MIPI_CMD_NOVATEK_QHD_PANEL_NAME "mipi_cmd_novatek_qhd"
#define MIPI_VIDEO_NOVATEK_QHD_PANEL_NAME "mipi_video_novatek_qhd"
#define MIPI_VIDEO_TOSHIBA_WVGA_PANEL_NAME "mipi_video_toshiba_wvga"
@@ -2660,19 +2659,17 @@
#define MSM_FB_EXT_BUFT_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 + \
MSM_FB_DSUB_PMEM_ADDER, 4096)
-#endif
+
+#define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
+#define MSM_HDMI_PRIM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-#define MSM_PMEM_SF_SIZE 0x8000000 /* 128 Mbytes */
+unsigned char hdmi_is_primary = 1;
#else
-#define MSM_PMEM_SF_SIZE 0x4000000 /* 64 Mbytes */
+unsigned char hdmi_is_primary;
#endif
#ifdef CONFIG_FB_MSM_OVERLAY0_WRITEBACK
@@ -2712,6 +2709,8 @@
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
#define MSM_ION_HEAP_NUM 9
+#define MSM_HDMI_PRIM_ION_SF_SIZE MSM_HDMI_PRIM_PMEM_SF_SIZE
+static unsigned msm_ion_sf_size = MSM_ION_SF_SIZE;
#else
#define MSM_ION_HEAP_NUM 1
#endif
@@ -3159,7 +3158,11 @@
void *addr;
unsigned long size;
- size = MSM_FB_SIZE;
+ if (hdmi_is_primary)
+ size = roundup((1920 * 1088 * 4 * 2), 4096);
+ else
+ size = MSM_FB_SIZE;
+
addr = alloc_bootmem_align(size, 0x1000);
msm_fb_resources[0].start = __pa(addr);
msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
@@ -3168,6 +3171,30 @@
}
+void __init msm8x60_set_display_params(char *prim_panel, char *ext_panel)
+{
+ if (strnlen(prim_panel, PANEL_NAME_MAX_LEN)) {
+ strlcpy(msm_fb_pdata.prim_panel_name, prim_panel,
+ PANEL_NAME_MAX_LEN);
+ pr_debug("msm_fb_pdata.prim_panel_name %s\n",
+ msm_fb_pdata.prim_panel_name);
+
+ if (!strncmp((char *)msm_fb_pdata.prim_panel_name,
+ HDMI_PANEL_NAME, strnlen(HDMI_PANEL_NAME,
+ PANEL_NAME_MAX_LEN))) {
+ pr_debug("HDMI is the primary display by"
+ " boot parameter\n");
+ hdmi_is_primary = 1;
+ }
+ }
+ if (strnlen(ext_panel, PANEL_NAME_MAX_LEN)) {
+ strlcpy(msm_fb_pdata.ext_panel_name, ext_panel,
+ PANEL_NAME_MAX_LEN);
+ pr_debug("msm_fb_pdata.ext_panel_name %s\n",
+ msm_fb_pdata.ext_panel_name);
+ }
+}
+
#if defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C) || \
defined(CONFIG_TOUCHSCREEN_CYTTSP_I2C_MODULE)
/*virtual key support */
@@ -5410,7 +5437,21 @@
static void reserve_ion_memory(void)
{
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
- msm8x60_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+ unsigned int i;
+
+ if (hdmi_is_primary) {
+ msm_ion_sf_size = MSM_HDMI_PRIM_ION_SF_SIZE;
+ for (i = 0; i < ion_pdata.nr; i++) {
+ if (ion_pdata.heaps[i].id == ION_SF_HEAP_ID) {
+ ion_pdata.heaps[i].size = msm_ion_sf_size;
+ pr_debug("msm_ion_sf_size 0x%x\n",
+ msm_ion_sf_size);
+ break;
+ }
+ }
+ }
+
+ msm8x60_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_FW_SIZE;
msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MM_SIZE;
msm8x60_reserve_table[MEMTYPE_SMI].size += MSM_ION_MFC_SIZE;
@@ -5426,6 +5467,9 @@
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
android_pmem_adsp_pdata.size = pmem_adsp_size;
android_pmem_smipool_pdata.size = MSM_PMEM_SMIPOOL_SIZE;
+
+ if (hdmi_is_primary)
+ pmem_sf_size = MSM_HDMI_PRIM_PMEM_SF_SIZE;
android_pmem_pdata.size = pmem_sf_size;
#endif
android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
@@ -5475,8 +5519,27 @@
.paddr_to_memtype = msm8x60_paddr_to_memtype,
};
+static char prim_panel_name[PANEL_NAME_MAX_LEN];
+static char ext_panel_name[PANEL_NAME_MAX_LEN];
+static int __init prim_display_setup(char *param)
+{
+ if (strnlen(param, PANEL_NAME_MAX_LEN))
+ strlcpy(prim_panel_name, param, PANEL_NAME_MAX_LEN);
+ return 0;
+}
+early_param("prim_display", prim_display_setup);
+
+static int __init ext_display_setup(char *param)
+{
+ if (strnlen(param, PANEL_NAME_MAX_LEN))
+ strlcpy(ext_panel_name, param, PANEL_NAME_MAX_LEN);
+ return 0;
+}
+early_param("ext_display", ext_display_setup);
+
static void __init msm8x60_reserve(void)
{
+ msm8x60_set_display_params(prim_panel_name, ext_panel_name);
reserve_info = &msm8x60_reserve_info;
msm_reserve();
}
@@ -9422,26 +9485,7 @@
.ib = 0,
},
};
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
-static struct msm_bus_vectors dtv_bus_def_vectors[] = {
- /* For now, 0th array entry is reserved.
- * Please leave 0 as is and don't use it
- */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_SMI,
- .ab = 2000000000,
- .ib = 2000000000,
- },
- /* Master and slaves can be from different fabrics */
- {
- .src = MSM_BUS_MASTER_MDP_PORT0,
- .dst = MSM_BUS_SLAVE_EBI_CH0,
- .ab = 2000000000,
- .ib = 2000000000,
- },
-};
-#else
+
static struct msm_bus_vectors dtv_bus_def_vectors[] = {
/* For now, 0th array entry is reserved.
* Please leave 0 as is and don't use it
@@ -9460,7 +9504,26 @@
.ib = 707616000,
},
};
-#endif
+
+static struct msm_bus_vectors dtv_bus_hdmi_prim_vectors[] = {
+ /* For now, 0th array entry is reserved.
+ * Please leave 0 as is and don't use it
+ */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 2000000000,
+ .ib = 2000000000,
+ },
+ /* Master and slaves can be from different fabrics */
+ {
+ .src = MSM_BUS_MASTER_MDP_PORT0,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 2000000000,
+ .ib = 2000000000,
+ },
+};
+
static struct msm_bus_paths dtv_bus_scale_usecases[] = {
{
ARRAY_SIZE(dtv_bus_init_vectors),
@@ -9471,6 +9534,7 @@
dtv_bus_def_vectors,
},
};
+
static struct msm_bus_scale_pdata dtv_bus_scale_pdata = {
dtv_bus_scale_usecases,
ARRAY_SIZE(dtv_bus_scale_usecases),
@@ -9480,6 +9544,27 @@
static struct lcdc_platform_data dtv_pdata = {
.bus_scale_table = &dtv_bus_scale_pdata,
};
+
+static struct msm_bus_paths dtv_hdmi_prim_bus_scale_usecases[] = {
+ {
+ ARRAY_SIZE(dtv_bus_init_vectors),
+ dtv_bus_init_vectors,
+ },
+ {
+ ARRAY_SIZE(dtv_bus_hdmi_prim_vectors),
+ dtv_bus_hdmi_prim_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata dtv_hdmi_prim_bus_scale_pdata = {
+ dtv_hdmi_prim_bus_scale_usecases,
+ ARRAY_SIZE(dtv_hdmi_prim_bus_scale_usecases),
+ .name = "dtv",
+};
+
+static struct lcdc_platform_data dtv_hdmi_prim_pdata = {
+ .bus_scale_table = &dtv_hdmi_prim_bus_scale_pdata,
+};
#endif
@@ -9601,13 +9686,6 @@
160000000,
200000000,
};
-#elif defined(CONFIG_FB_MSM_HDMI_AS_PRIMARY)
-int mdp_core_clk_rate_table[] = {
- 200000000,
- 200000000,
- 200000000,
- 200000000,
-};
#else
int mdp_core_clk_rate_table[] = {
59080000,
@@ -9619,11 +9697,7 @@
static struct msm_panel_common_pdata mdp_pdata = {
.gpio = MDP_VSYNC_GPIO,
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- .mdp_core_clk_rate = 200000000,
-#else
.mdp_core_clk_rate = 59080000,
-#endif
.mdp_core_clk_table = mdp_core_clk_rate_table,
.num_mdp_clk = ARRAY_SIZE(mdp_core_clk_rate_table),
#ifdef CONFIG_MSM_BUS_SCALING
@@ -9729,7 +9803,10 @@
msm_fb_register_device("lcdc", &lcdc_pdata);
msm_fb_register_device("mipi_dsi", &mipi_dsi_pdata);
#ifdef CONFIG_MSM_BUS_SCALING
- msm_fb_register_device("dtv", &dtv_pdata);
+ if (hdmi_is_primary)
+ msm_fb_register_device("dtv", &dtv_hdmi_prim_pdata);
+ else
+ msm_fb_register_device("dtv", &dtv_pdata);
#endif
#ifdef CONFIG_FB_MSM_TVOUT
msm_fb_register_device("tvenc", &atv_pdata);
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 0427632..ac590d3 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -28,9 +28,11 @@
#include <linux/input/rmi_i2c.h>
#include <linux/i2c/atmel_mxt_ts.h>
#include <linux/regulator/consumer.h>
+#include <linux/memblock.h>
#include <asm/mach/mmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
#include <mach/board.h>
#include <mach/msm_iomap.h>
#include <mach/msm_hsusb.h>
@@ -659,7 +661,20 @@
.dev.platform_data = &msm_psy_batt_data,
};
-static struct platform_device *qrd_common_devices[] __initdata = {
+static struct platform_device *common_devices[] __initdata = {
+ &android_usb_device,
+ &android_pmem_device,
+ &android_pmem_adsp_device,
+ &android_pmem_audio_device,
+ &msm_batt_device,
+ &msm_device_adspdec,
+ &msm_device_snd,
+ &asoc_msm_pcm,
+ &asoc_msm_dai0,
+ &asoc_msm_dai1,
+};
+
+static struct platform_device *qrd7627a_devices[] __initdata = {
&msm_device_dmov,
&msm_device_smd,
&msm_device_uart1,
@@ -668,26 +683,24 @@
&msm_gsbi1_qup_i2c_device,
&msm_device_otg,
&msm_device_gadget_peripheral,
- &android_usb_device,
- &android_pmem_device,
- &android_pmem_adsp_device,
- &android_pmem_audio_device,
- &msm_device_snd,
- &msm_device_adspdec,
- &msm_batt_device,
&msm_kgsl_3d0,
-#ifdef CONFIG_BT
- &msm_bt_power_device,
-#endif
- &asoc_msm_pcm,
- &asoc_msm_dai0,
- &asoc_msm_dai1,
};
static struct platform_device *qrd3_devices[] __initdata = {
&msm_device_nand,
};
+static struct platform_device *msm8625_evb_devices[] __initdata = {
+ &msm8625_device_dmov,
+ &msm8625_device_smd,
+ &msm8625_gsbi0_qup_i2c_device,
+ &msm8625_gsbi1_qup_i2c_device,
+ &msm8625_device_uart1,
+ &msm8625_device_otg,
+ &msm8625_device_gadget_peripheral,
+ &msm8625_kgsl_3d0,
+};
+
static unsigned pmem_kernel_ebi1_size = PMEM_KERNEL_EBI1_SIZE;
static int __init pmem_kernel_ebi1_size_setup(char *p)
{
@@ -762,12 +775,49 @@
msm_reserve();
}
-static void __init msm_device_i2c_init(void)
+static void __init msm8625_reserve(void)
+{
+ memblock_remove(MSM8625_SECONDARY_PHYS, SZ_8);
+ msm7627a_reserve();
+}
+
+static void msmqrd_adsp_add_pdev(void)
+{
+ int rc = 0;
+ struct rpc_board_dev *rpc_adsp_pdev;
+
+ rpc_adsp_pdev = kzalloc(sizeof(struct rpc_board_dev), GFP_KERNEL);
+ if (rpc_adsp_pdev == NULL) {
+ pr_err("%s: Memory Allocation failure\n", __func__);
+ return;
+ }
+ rpc_adsp_pdev->prog = ADSP_RPC_PROG;
+
+ if (cpu_is_msm8625())
+ rpc_adsp_pdev->pdev = msm8625_device_adsp;
+ else
+ rpc_adsp_pdev->pdev = msm_adsp_device;
+ rc = msm_rpc_add_board_dev(rpc_adsp_pdev, 1);
+ if (rc < 0) {
+ pr_err("%s: return val: %d\n", __func__, rc);
+ kfree(rpc_adsp_pdev);
+ }
+}
+
+static void __init msm7627a_device_i2c_init(void)
{
msm_gsbi0_qup_i2c_device.dev.platform_data = &msm_gsbi0_qup_i2c_pdata;
msm_gsbi1_qup_i2c_device.dev.platform_data = &msm_gsbi1_qup_i2c_pdata;
}
+static void __init msm8625_device_i2c_init(void)
+{
+ msm8625_gsbi0_qup_i2c_device.dev.platform_data
+ = &msm_gsbi0_qup_i2c_pdata;
+ msm8625_gsbi1_qup_i2c_device.dev.platform_data
+ = &msm_gsbi1_qup_i2c_pdata;
+}
+
static struct msm_handset_platform_data hs_platform_data = {
.hs_name = "7k_handset",
.pwr_key_delay_ms = 500, /* 0 will disable end key */
@@ -958,7 +1008,7 @@
i2c_register_board_info(MSM_GSBI1_QUP_I2C_BUS_ID,
synaptic_i2c_clearpad3k,
ARRAY_SIZE(synaptic_i2c_clearpad3k));
- } else if (machine_is_msm7627a_evb()) {
+ } else if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
rc = gpio_tlmm_config(GPIO_CFG(MXT_TS_IRQ_GPIO, 0,
GPIO_CFG_INPUT, GPIO_CFG_PULL_UP,
GPIO_CFG_8MA), GPIO_CFG_ENABLE);
@@ -989,11 +1039,11 @@
#endif
/* keypad */
- if (machine_is_msm7627a_evb())
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb())
platform_device_register(&kp_pdev_8625);
/* leds */
- if (machine_is_msm7627a_evb()) {
+ if (machine_is_msm7627a_evb() || machine_is_msm8625_evb()) {
rc = gpio_tlmm_config(GPIO_CFG(LED_RED_GPIO_8625, 0,
GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
GPIO_CFG_16MA), GPIO_CFG_ENABLE);
@@ -1022,32 +1072,63 @@
static void add_platform_devices(void)
{
- platform_add_devices(qrd_common_devices,
- ARRAY_SIZE(qrd_common_devices));
-
- if (machine_is_msm7627a_qrd3())
- platform_add_devices(qrd3_devices,
- ARRAY_SIZE(qrd3_devices));
+ if (machine_is_msm8625_evb())
+ platform_add_devices(msm8625_evb_devices,
+ ARRAY_SIZE(msm8625_evb_devices));
+ else {
+ platform_add_devices(qrd7627a_devices,
+ ARRAY_SIZE(qrd7627a_devices));
+ if (machine_is_msm7627a_qrd3())
+ platform_add_devices(qrd3_devices,
+ ARRAY_SIZE(qrd3_devices));
+ }
+ platform_add_devices(common_devices,
+ ARRAY_SIZE(common_devices));
}
#define UART1DM_RX_GPIO 45
+static void __init qrd7627a_uart1dm_config(void)
+{
+ msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
+ if (cpu_is_msm8625())
+ msm8625_device_uart_dm1.dev.platform_data =
+ &msm_uart_dm1_pdata;
+ else
+ msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
+}
+
+static void __init qrd7627a_otg_gadget(void)
+{
+ msm_otg_pdata.swfi_latency = msm7627a_pm_data
+ [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
+
+ if (cpu_is_msm8625()) {
+ msm8625_device_otg.dev.platform_data = &msm_otg_pdata;
+ msm8625_device_gadget_peripheral.dev.platform_data =
+ &msm_gadget_pdata;
+
+ } else {
+ msm_device_otg.dev.platform_data = &msm_otg_pdata;
+ msm_device_gadget_peripheral.dev.platform_data =
+ &msm_gadget_pdata;
+ }
+}
+
static void __init msm_qrd_init(void)
{
msm7x2x_misc_init();
msm7627a_init_regulators();
- msm_device_i2c_init();
-#ifdef CONFIG_SERIAL_MSM_HS
- msm_uart_dm1_pdata.wakeup_irq = gpio_to_irq(UART1DM_RX_GPIO);
- msm_device_uart_dm1.dev.platform_data = &msm_uart_dm1_pdata;
-#endif
+ msmqrd_adsp_add_pdev();
-#ifdef CONFIG_USB_MSM_OTG_72K
- msm_otg_pdata.swfi_latency = msm7627a_pm_data
- [MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT].latency;
- msm_device_otg.dev.platform_data = &msm_otg_pdata;
-#endif
- msm_device_gadget_peripheral.dev.platform_data =
- &msm_gadget_pdata;
+ if (cpu_is_msm8625())
+ msm8625_device_i2c_init();
+ else
+ msm7627a_device_i2c_init();
+
+ /* uart1dm*/
+ qrd7627a_uart1dm_config();
+ /*OTG gadget*/
+ qrd7627a_otg_gadget();
add_platform_devices();
@@ -1058,9 +1139,11 @@
#ifdef CONFIG_USB_EHCI_MSM_72K
msm7627a_init_host();
#endif
- msm_pm_set_platform_data(msm7627a_pm_data,
+ if (!machine_is_msm8625_evb()) {
+ msm_pm_set_platform_data(msm7627a_pm_data,
ARRAY_SIZE(msm7627a_pm_data));
- BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+ BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+ }
msm_fb_add_devices();
@@ -1069,8 +1152,8 @@
#endif
msm7627a_camera_init();
-
msm7627a_add_io_devices();
+ msm7x25a_kgsl_3d0_init();
}
static void __init qrd7627a_init_early(void)
@@ -1108,3 +1191,13 @@
.init_early = qrd7627a_init_early,
.handle_irq = vic_handle_irq,
MACHINE_END
+MACHINE_START(MSM8625_EVB, "QRD MSM8625 EVB")
+ .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 5996388..a2e2c4c 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -365,9 +365,6 @@
};
#define PLL_RATE(l, m, n, v, d, i) { l, m, n, v, (d>>1), i }
-static int rpm_vreg_id_vdd_dig;
-static int rpm_vreg_id_vdd_sr2_pll;
-
enum vdd_dig_levels {
VDD_DIG_NONE,
VDD_DIG_LOW,
@@ -375,7 +372,7 @@
VDD_DIG_HIGH
};
-static int set_vdd_dig(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_dig_8960(struct clk_vdd_class *vdd_class, int level)
{
static const int vdd_uv[] = {
[VDD_DIG_NONE] = 0,
@@ -383,11 +380,23 @@
[VDD_DIG_NOMINAL] = 1050000,
[VDD_DIG_HIGH] = 1150000
};
- return rpm_vreg_set_voltage(rpm_vreg_id_vdd_dig, RPM_VREG_VOTER3,
+ return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S3, RPM_VREG_VOTER3,
vdd_uv[level], 1150000, 1);
}
-static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig);
+static DEFINE_VDD_CLASS(vdd_dig, set_vdd_dig_8960);
+
+static int set_vdd_dig_8930(struct clk_vdd_class *vdd_class, int level)
+{
+ static const int vdd_uv[] = {
+ [VDD_DIG_NONE] = 0,
+ [VDD_DIG_LOW] = 945000,
+ [VDD_DIG_NOMINAL] = 1050000,
+ [VDD_DIG_HIGH] = 1150000
+ };
+ return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_S1, RPM_VREG_VOTER3,
+ vdd_uv[level], 1150000, 1);
+}
#define VDD_DIG_FMAX_MAP1(l1, f1) \
.vdd_class = &vdd_dig, \
@@ -407,49 +416,53 @@
VDD_SR2_PLL_ON
};
-static int set_vdd_sr2_pll(struct clk_vdd_class *vdd_class, int level)
+static int set_vdd_sr2_pll_8960(struct clk_vdd_class *vdd_class, int level)
{
int rc = 0;
- if (cpu_is_msm8960()) {
- if (level == VDD_SR2_PLL_OFF) {
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
- RPM_VREG_VOTER3, 0, 0, 1);
- if (rc)
- return rc;
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
- RPM_VREG_VOTER3, 0, 0, 1);
- if (rc)
- rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
- RPM_VREG_VOTER3, 1800000, 1800000, 1);
- } else {
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
- RPM_VREG_VOTER3, 2100000, 2100000, 1);
- if (rc)
- return rc;
- rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
- RPM_VREG_VOTER3, 1800000, 1800000, 1);
- if (rc)
- rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
- RPM_VREG_VOTER3, 0, 0, 1);
- }
+
+ if (level == VDD_SR2_PLL_OFF) {
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ if (rc)
+ return rc;
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+ RPM_VREG_VOTER3, 0, 0, 1);
+ if (rc)
+ rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+ RPM_VREG_VOTER3, 1800000, 1800000, 1);
} else {
- if (level == VDD_SR2_PLL_OFF) {
- rc = rpm_vreg_set_voltage(rpm_vreg_id_vdd_sr2_pll,
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
+ RPM_VREG_VOTER3, 2100000, 2100000, 1);
+ if (rc)
+ return rc;
+ rc = rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_L23,
+ RPM_VREG_VOTER3, 1800000, 1800000, 1);
+ if (rc)
+ rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_S8,
RPM_VREG_VOTER3, 0, 0, 1);
- if (rc)
- return rc;
- } else {
- rc = rpm_vreg_set_voltage(rpm_vreg_id_vdd_sr2_pll,
- RPM_VREG_VOTER3, 1800000, 1800000, 1);
- if (rc)
- return rc;
- }
}
return rc;
}
-static DEFINE_VDD_CLASS(vdd_sr2_pll, set_vdd_sr2_pll);
+static DEFINE_VDD_CLASS(vdd_sr2_pll, set_vdd_sr2_pll_8960);
+
+static int sr2_lreg_uv[] = {
+ [VDD_SR2_PLL_OFF] = 0,
+ [VDD_SR2_PLL_ON] = 1800000,
+};
+
+static int set_vdd_sr2_pll_8064(struct clk_vdd_class *vdd_class, int level)
+{
+ return rpm_vreg_set_voltage(RPM_VREG_ID_PM8921_LVS7, RPM_VREG_VOTER3,
+ sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
+}
+
+static int set_vdd_sr2_pll_8930(struct clk_vdd_class *vdd_class, int level)
+{
+ return rpm_vreg_set_voltage(RPM_VREG_ID_PM8038_L23, RPM_VREG_VOTER3,
+ sr2_lreg_uv[level], sr2_lreg_uv[level], 1);
+}
/*
* Clock Descriptions
@@ -4461,6 +4474,9 @@
DEFINE_CLK_RPM(sfab_clk, sfab_a_clk, SYSTEM_FABRIC, NULL);
DEFINE_CLK_RPM(sfpb_clk, sfpb_a_clk, SFPB, NULL);
+static DEFINE_CLK_VOTER(sfab_msmbus_a_clk, &sfab_a_clk.c);
+static DEFINE_CLK_VOTER(sfab_tmr_a_clk, &sfab_a_clk.c);
+
static DEFINE_CLK_VOTER(dfab_dsps_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_usb_hs_clk, &dfab_clk.c);
static DEFINE_CLK_VOTER(dfab_usb_hs3_clk, &dfab_clk.c);
@@ -4898,7 +4914,7 @@
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
- CLK_LOOKUP("bus_a_clk", sfab_a_clk.c, "msm_sys_fab"),
+ CLK_LOOKUP("bus_a_clk", sfab_msmbus_a_clk.c, "msm_sys_fab"),
CLK_LOOKUP("bus_clk", sfpb_clk.c, "msm_sys_fpb"),
CLK_LOOKUP("bus_a_clk", sfpb_a_clk.c, "msm_sys_fpb"),
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
@@ -5045,7 +5061,7 @@
CLK_LOOKUP("tv_clk", mdp_tv_clk.c, "footswitch-8x60.4"),
CLK_LOOKUP("hdmi_clk", hdmi_tv_clk.c, ""),
CLK_LOOKUP("core_clk", hdmi_app_clk.c, ""),
- CLK_LOOKUP("vpe_clk", vpe_clk.c, ""),
+ CLK_LOOKUP("vpe_clk", vpe_clk.c, "msm_vpe.0"),
CLK_LOOKUP("core_clk", vpe_clk.c, "footswitch-8x60.9"),
CLK_LOOKUP("vfe_clk", vfe_clk.c, "msm_vfe.0"),
CLK_LOOKUP("core_clk", vfe_clk.c, "footswitch-8x60.8"),
@@ -5082,7 +5098,7 @@
CLK_LOOKUP("iface_clk", vcodec_p_clk.c, "footswitch-8x60.7"),
CLK_LOOKUP("vfe_pclk", vfe_p_clk.c, "msm_vfe.0"),
CLK_LOOKUP("iface_clk", vfe_p_clk.c, "footswitch-8x60.8"),
- CLK_LOOKUP("vpe_pclk", vpe_p_clk.c, ""),
+ 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"),
@@ -5175,7 +5191,7 @@
CLK_LOOKUP("bus_clk", cfpb_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_a_clk", cfpb_a_clk.c, "msm_cpss_fpb"),
CLK_LOOKUP("bus_clk", sfab_clk.c, "msm_sys_fab"),
- CLK_LOOKUP("bus_a_clk", sfab_a_clk.c, "msm_sys_fab"),
+ CLK_LOOKUP("bus_a_clk", sfab_msmbus_a_clk.c, "msm_sys_fab"),
CLK_LOOKUP("bus_clk", sfpb_clk.c, "msm_sys_fpb"),
CLK_LOOKUP("bus_a_clk", sfpb_a_clk.c, "msm_sys_fpb"),
CLK_LOOKUP("bus_clk", mmfab_clk.c, "msm_mm_fab"),
@@ -5676,16 +5692,11 @@
static void __init msm8960_clock_init(void)
{
- if (cpu_is_msm8960()) {
- rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
- } else if (cpu_is_apq8064()) {
- rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8921_S3;
- rpm_vreg_id_vdd_sr2_pll = RPM_VREG_ID_PM8921_LVS7;
+ if (cpu_is_apq8064()) {
+ vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8064;
} else if (cpu_is_msm8930() || cpu_is_msm8627()) {
- rpm_vreg_id_vdd_dig = RPM_VREG_ID_PM8038_S1;
- rpm_vreg_id_vdd_sr2_pll = RPM_VREG_ID_PM8038_L23;
- } else {
- BUG();
+ vdd_dig.set_vdd = set_vdd_dig_8930;
+ vdd_sr2_pll.set_vdd = set_vdd_sr2_pll_8930;
}
xo_pxo = msm_xo_get(MSM_XO_PXO, "clock-8960");
@@ -5763,6 +5774,14 @@
rcg_clk_disable(&tssc_clk.c);
clk_enable(&usb_hsic_hsic_clk.c);
clk_disable(&usb_hsic_hsic_clk.c);
+
+ /*
+ * Keep sfab floor @ 54MHz so that Krait AHB is at least 27MHz at all
+ * times when Apps CPU is active. This ensures the timer's requirement
+ * of Krait AHB running 4 times as fast as the timer itself.
+ */
+ clk_set_rate(&sfab_tmr_a_clk.c, 54000000);
+ clk_enable(&sfab_tmr_a_clk.c);
}
static int __init msm8960_clock_late_init(void)
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index d3f5396..9ab3de8 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3765,6 +3765,12 @@
CLK_LOOKUP("core_clk", gfx2d0_clk.c, "msm_iommu.10"),
CLK_LOOKUP("core_clk", gfx2d1_clk.c, "msm_iommu.11"),
+ CLK_LOOKUP("mdp_iommu_clk", mdp_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("rot_iommu_clk", rot_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("vcodec_iommu0_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("vcodec_iommu1_clk", vcodec_axi_clk.c, "msm_vidc.0"),
+ CLK_LOOKUP("smmu_iface_clk", smmu_p_clk.c, "msm_vidc.0"),
+
CLK_LOOKUP("dfab_dsps_clk", dfab_dsps_clk.c, NULL),
CLK_LOOKUP("core_clk", dfab_usb_hs_clk.c, "msm_otg"),
CLK_LOOKUP("bus_clk", dfab_sdc1_clk.c, "msm_sdcc.1"),
diff --git a/arch/arm/mach-msm/clock-pcom-lookup.c b/arch/arm/mach-msm/clock-pcom-lookup.c
index 200cbfe..c20b7e4 100644
--- a/arch/arm/mach-msm/clock-pcom-lookup.c
+++ b/arch/arm/mach-msm/clock-pcom-lookup.c
@@ -11,9 +11,16 @@
*/
#include "clock.h"
+#include "clock-pll.h"
#include "clock-pcom.h"
#include "clock-voter.h"
+#include <mach/msm_iomap.h>
+#include <mach/socinfo.h>
+
+#define PLLn_MODE(n) (MSM_CLK_CTL_BASE + 0x300 + 28 * (n))
+#define PLL4_MODE (MSM_CLK_CTL_BASE + 0x374)
+
static DEFINE_CLK_PCOM(adm_clk, ADM_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(adsp_clk, ADSP_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(ahb_m_clk, AHB_M_CLK, CLKFLAG_SKIP_AUTO_OFF);
@@ -28,6 +35,46 @@
static DEFINE_CLK_PCOM(csi1_p_clk, CSI1_P_CLK, CLKFLAG_SKIP_AUTO_OFF);
static DEFINE_CLK_PCOM(csi1_vfe_clk, CSI1_VFE_CLK, CLKFLAG_SKIP_AUTO_OFF);
+static struct pll_shared_clk pll0_clk = {
+ .id = PLL_0,
+ .mode_reg = PLLn_MODE(0),
+ .c = {
+ .ops = &clk_pll_ops,
+ .dbg_name = "pll0_clk",
+ CLK_INIT(pll0_clk.c),
+ },
+};
+
+static struct pll_shared_clk pll1_clk = {
+ .id = PLL_1,
+ .mode_reg = PLLn_MODE(1),
+ .c = {
+ .ops = &clk_pll_ops,
+ .dbg_name = "pll1_clk",
+ CLK_INIT(pll1_clk.c),
+ },
+};
+
+static struct pll_shared_clk pll2_clk = {
+ .id = PLL_2,
+ .mode_reg = PLLn_MODE(2),
+ .c = {
+ .ops = &clk_pll_ops,
+ .dbg_name = "pll2_clk",
+ CLK_INIT(pll2_clk.c),
+ },
+};
+
+static struct pll_shared_clk pll4_clk = {
+ .id = PLL_4,
+ .mode_reg = PLL4_MODE,
+ .c = {
+ .ops = &clk_pll_ops,
+ .dbg_name = "pll4_clk",
+ CLK_INIT(pll4_clk.c),
+ },
+};
+
static struct pcom_clk dsi_byte_clk = {
.id = P_DSI_BYTE_CLK,
.c = {
@@ -251,14 +298,20 @@
CLK_LOOKUP("core_clk", ebi_usb_clk.c, "msm_otg"),
CLK_LOOKUP("ebi1_vfe_clk", ebi_vfe_clk.c, NULL),
CLK_LOOKUP("mem_clk", ebi_adm_clk.c, "msm_dmov"),
+
+ CLK_LOOKUP("pll0_clk", pll0_clk.c, "acpu"),
+ CLK_LOOKUP("pll1_clk", pll1_clk.c, "acpu"),
+ CLK_LOOKUP("pll2_clk", pll2_clk.c, "acpu"),
};
struct clock_init_data msm7x27_clock_init_data __initdata = {
.table = msm_clocks_7x27,
.size = ARRAY_SIZE(msm_clocks_7x27),
+ .init = msm_shared_pll_control_init,
};
-static struct clk_lookup msm_clocks_7x27a[] = {
+/* Clock table for common clocks between 7627a and 7625a */
+static struct clk_lookup msm_cmn_clk_7625a_7627a[] __initdata = {
CLK_LOOKUP("core_clk", adm_clk.c, "msm_dmov"),
CLK_LOOKUP("adsp_clk", adsp_clk.c, NULL),
CLK_LOOKUP("ahb_m_clk", ahb_m_clk.c, NULL),
@@ -340,11 +393,41 @@
CLK_LOOKUP("ebi1_mddi_clk", ebi_mddi_clk.c, NULL),
CLK_LOOKUP("ebi1_vfe_clk", ebi_vfe_clk.c, NULL),
CLK_LOOKUP("mem_clk", ebi_adm_clk.c, "msm_dmov"),
+
+ CLK_LOOKUP("pll0_clk", pll0_clk.c, "acpu"),
+ CLK_LOOKUP("pll1_clk", pll1_clk.c, "acpu"),
+ CLK_LOOKUP("pll2_clk", pll2_clk.c, "acpu"),
+
};
+/* PLL 4 clock is available for 7627a target. */
+static struct clk_lookup msm_clk_7627a[] __initdata = {
+ CLK_LOOKUP("pll4_clk", pll4_clk.c, "acpu"),
+};
+
+static struct clk_lookup msm_clk_7627a_7625a[ARRAY_SIZE(msm_cmn_clk_7625a_7627a)
+ + ARRAY_SIZE(msm_clk_7627a)];
+
+static void __init msm7627a_clock_init(void)
+{
+ int size = ARRAY_SIZE(msm_cmn_clk_7625a_7627a);
+
+ /* Intialize shared PLL control structure */
+ msm_shared_pll_control_init();
+
+ memcpy(&msm_clk_7627a_7625a, &msm_cmn_clk_7625a_7627a,
+ sizeof(msm_cmn_clk_7625a_7627a));
+ if (!cpu_is_msm7x25a()) {
+ memcpy(&msm_clk_7627a_7625a[size],
+ &msm_clk_7627a, sizeof(msm_clk_7627a));
+ size += ARRAY_SIZE(msm_clk_7627a);
+ }
+ msm7x27a_clock_init_data.size = size;
+}
+
struct clock_init_data msm7x27a_clock_init_data __initdata = {
- .table = msm_clocks_7x27a,
- .size = ARRAY_SIZE(msm_clocks_7x27a),
+ .table = msm_clk_7627a_7625a,
+ .init = msm7627a_clock_init,
};
static struct clk_lookup msm_clocks_8x50[] = {
diff --git a/arch/arm/mach-msm/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
new file mode 100644
index 0000000..f6b2b45
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/remote_spinlock.h>
+
+#include <mach/socinfo.h>
+#include <mach/msm_iomap.h>
+
+#include "clock.h"
+#include "clock-pll.h"
+#include "smd_private.h"
+
+struct pll_rate {
+ unsigned int lvalue;
+ unsigned long rate;
+};
+
+static struct pll_rate pll_l_rate[] = {
+ {10, 196000000},
+ {12, 245760000},
+ {30, 589820000},
+ {38, 737280000},
+ {41, 800000000},
+ {50, 960000000},
+ {52, 1008000000},
+ {62, 1200000000},
+ {0, 0},
+};
+
+#define PLL_BASE 7
+
+struct shared_pll_control {
+ uint32_t version;
+ struct {
+ /*
+ * Denotes if the PLL is ON. Technically, this can be read
+ * directly from the PLL registers, but this feild is here,
+ * so let's use it.
+ */
+ uint32_t on;
+ /*
+ * One bit for each processor core. The application processor
+ * is allocated bit position 1. All other bits should be
+ * considered as votes from other processors.
+ */
+ uint32_t votes;
+ } pll[PLL_BASE + PLL_END];
+};
+
+static remote_spinlock_t pll_lock;
+static struct shared_pll_control *pll_control;
+
+void __init msm_shared_pll_control_init(void)
+{
+#define PLL_REMOTE_SPINLOCK_ID "S:7"
+ unsigned smem_size;
+
+ remote_spin_lock_init(&pll_lock, PLL_REMOTE_SPINLOCK_ID);
+
+ pll_control = smem_get_entry(SMEM_CLKREGIM_SOURCES, &smem_size);
+ if (!pll_control) {
+ pr_err("Can't find shared PLL control data structure!\n");
+ BUG();
+ /*
+ * There might be more PLLs than what the application processor knows
+ * about. But the index used for each PLL is guaranteed to remain the
+ * same.
+ */
+ } else if (smem_size < sizeof(struct shared_pll_control)) {
+ pr_err("Shared PLL control data"
+ "structure too small!\n");
+ BUG();
+ } else if (pll_control->version != 0xCCEE0001) {
+ pr_err("Shared PLL control version mismatch!\n");
+ BUG();
+ } else {
+ pr_info("Shared PLL control available.\n");
+ return;
+ }
+
+}
+
+static void pll_enable(void __iomem *addr, unsigned on)
+{
+ if (on) {
+ writel_relaxed(2, addr);
+ mb();
+ udelay(5);
+ writel_relaxed(6, addr);
+ mb();
+ udelay(50);
+ writel_relaxed(7, addr);
+ } else {
+ writel_relaxed(0, addr);
+ }
+}
+
+static int pll_clk_enable(struct clk *clk)
+{
+ struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+ unsigned int pll_id = pll->id;
+
+ remote_spin_lock(&pll_lock);
+
+ pll_control->pll[PLL_BASE + pll_id].votes |= BIT(1);
+ if (!pll_control->pll[PLL_BASE + pll_id].on) {
+ pll_enable(pll->mode_reg, 1);
+ pll_control->pll[PLL_BASE + pll_id].on = 1;
+ }
+
+ remote_spin_unlock(&pll_lock);
+ return 0;
+}
+
+static void pll_clk_disable(struct clk *clk)
+{
+ struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+ unsigned int pll_id = pll->id;
+
+ remote_spin_lock(&pll_lock);
+
+ pll_control->pll[PLL_BASE + pll_id].votes &= ~BIT(1);
+ if (pll_control->pll[PLL_BASE + pll_id].on
+ && !pll_control->pll[PLL_BASE + pll_id].votes) {
+ pll_enable(pll->mode_reg, 0);
+ pll_control->pll[PLL_BASE + pll_id].on = 0;
+ }
+
+ remote_spin_unlock(&pll_lock);
+}
+
+static int pll_clk_is_enabled(struct clk *clk)
+{
+ struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+
+ return readl_relaxed(pll->mode_reg) & BIT(0);
+}
+
+static bool pll_clk_is_local(struct clk *clk)
+{
+ return true;
+}
+
+static int pll_clk_handoff(struct clk *clk)
+{
+ struct pll_shared_clk *pll = to_pll_shared_clk(clk);
+ unsigned int pll_lval;
+ struct pll_rate *l;
+
+ /*
+ * Wait for the PLLs to be initialized and then read their frequency.
+ */
+ do {
+ pll_lval = readl_relaxed(pll->mode_reg + 4) & 0x3ff;
+ cpu_relax();
+ udelay(50);
+ } while (pll_lval == 0);
+
+ /* Convert PLL L values to PLL Output rate */
+ for (l = pll_l_rate; l->rate != 0; l++) {
+ if (l->lvalue == pll_lval) {
+ clk->rate = l->rate;
+ break;
+ }
+ }
+
+ if (!clk->rate) {
+ pr_crit("Unknown PLL's L value!\n");
+ BUG();
+ }
+
+ return 0;
+}
+
+struct clk_ops clk_pll_ops = {
+ .enable = pll_clk_enable,
+ .disable = pll_clk_disable,
+ .handoff = pll_clk_handoff,
+ .is_local = pll_clk_is_local,
+ .is_enabled = pll_clk_is_enabled,
+};
diff --git a/arch/arm/mach-msm/clock-pll.h b/arch/arm/mach-msm/clock-pll.h
new file mode 100644
index 0000000..ae0ca17
--- /dev/null
+++ b/arch/arm/mach-msm/clock-pll.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ */
+
+/**
+ * enum - For PLL IDs
+ */
+enum {
+ PLL_TCXO = -1,
+ PLL_0 = 0,
+ PLL_1,
+ PLL_2,
+ PLL_3,
+ PLL_4,
+ PLL_END,
+};
+
+/**
+ * struct pll_shared_clk - PLL shared with other processors without
+ * any HW voting
+ * @id: PLL ID
+ * @mode_reg: enable register
+ * @parent: clock source
+ * @c: clk
+ */
+struct pll_shared_clk {
+ unsigned int id;
+ void __iomem *const mode_reg;
+ struct clk c;
+};
+
+extern struct clk_ops clk_pll_ops;
+
+static inline struct pll_shared_clk *to_pll_shared_clk(struct clk *clk)
+{
+ return container_of(clk, struct pll_shared_clk, c);
+}
+
+/**
+ * msm_shared_pll_control_init() - Initialize shared pll control structure
+ */
+void msm_shared_pll_control_init(void);
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index ca85a0a..657751b 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -23,11 +23,13 @@
#include <mach/usbdiag.h>
#include <mach/msm_sps.h>
#include <mach/dma.h>
+#include <mach/msm_dsps.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
#include <mach/msm_bus_board.h>
#include <mach/rpm.h>
#include <mach/mdm2.h>
+#include <mach/msm_smd.h>
#include <linux/ion.h>
#include "clock.h"
#include "devices.h"
@@ -72,6 +74,11 @@
#define MSM_HSUSB3_PHYS 0x12520000
#define MSM_HSUSB3_SIZE SZ_4K
+/* Address of HS USB4 */
+#define MSM_HSUSB4_PHYS 0x12530000
+#define MSM_HSUSB4_SIZE SZ_4K
+
+
static struct msm_watchdog_pdata msm_watchdog_pdata = {
.pet_time = 10000,
.bark_time = 11000,
@@ -678,6 +685,30 @@
},
};
+static struct resource resources_ehci_host4[] = {
+{
+ .start = MSM_HSUSB4_PHYS,
+ .end = MSM_HSUSB4_PHYS + MSM_HSUSB4_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = USB4_HS_IRQ,
+ .end = USB4_HS_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device apq8064_device_ehci_host4 = {
+ .name = "msm_ehci_host",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(resources_ehci_host4),
+ .resource = resources_ehci_host4,
+ .dev = {
+ .dma_mask = &dma_mask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+};
+
/* MSM Video core device */
#ifdef CONFIG_MSM_BUS_SCALING
static struct msm_bus_vectors vidc_init_vectors[] = {
@@ -1217,9 +1248,157 @@
.dev.platform_data = &msm_sps_pdata,
};
+static struct resource smd_resource[] = {
+ {
+ .name = "a9_m2a_0",
+ .start = INT_A9_M2A_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "a9_m2a_5",
+ .start = INT_A9_M2A_5,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_a11",
+ .start = INT_ADSP_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_a11_smsm",
+ .start = INT_ADSP_A11_SMSM,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "dsps_a11",
+ .start = INT_DSPS_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "dsps_a11_smsm",
+ .start = INT_DSPS_A11_SMSM,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "wcnss_a11",
+ .start = INT_WCNSS_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "wcnss_a11_smsm",
+ .start = INT_WCNSS_A11_SMSM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+ {
+ .irq_config_id = SMD_MODEM,
+ .subsys_name = "gss",
+ .edge = SMD_APPS_MODEM,
+
+ .smd_int.irq_name = "a9_m2a_0",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 3,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "a9_m2a_5",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 4,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_Q6,
+ .subsys_name = "q6",
+ .edge = SMD_APPS_QDSP,
+
+ .smd_int.irq_name = "adsp_a11",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 15,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "adsp_a11_smsm",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 14,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_DSPS,
+ .subsys_name = "dsps",
+ .edge = SMD_APPS_DSPS,
+
+ .smd_int.irq_name = "dsps_a11",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1,
+ .smd_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+ .smd_int.out_offset = 0x4080,
+
+ .smsm_int.irq_name = "dsps_a11_smsm",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1,
+ .smsm_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+ .smsm_int.out_offset = 0x4094,
+ },
+ {
+ .irq_config_id = SMD_WCNSS,
+ .subsys_name = "wcnss",
+ .edge = SMD_APPS_WCNSS,
+
+ .smd_int.irq_name = "wcnss_a11",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 25,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "wcnss_a11_smsm",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 23,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+};
+
+static struct smd_platform smd_platform_data = {
+ .num_ss_configs = ARRAY_SIZE(smd_config_list),
+ .smd_ss_configs = smd_config_list,
+};
+
struct platform_device msm_device_smd_apq8064 = {
.name = "msm_smd",
.id = -1,
+ .resource = smd_resource,
+ .num_resources = ARRAY_SIZE(smd_resource),
+ .dev = {
+ .platform_data = &smd_platform_data,
+ },
};
#ifdef CONFIG_HW_RANDOM_MSM
@@ -1752,6 +1931,53 @@
},
};
+/* Sensors DSPS platform data */
+
+#define PPSS_REG_PHYS_BASE 0x12080000
+
+static struct dsps_clk_info dsps_clks[] = {};
+static struct dsps_regulator_info dsps_regs[] = {};
+
+/*
+ * Note: GPIOs field is intialized in run-time at the function
+ * apq8064_init_dsps().
+ */
+
+struct msm_dsps_platform_data msm_dsps_pdata_8064 = {
+ .clks = dsps_clks,
+ .clks_num = ARRAY_SIZE(dsps_clks),
+ .gpios = NULL,
+ .gpios_num = 0,
+ .regs = dsps_regs,
+ .regs_num = ARRAY_SIZE(dsps_regs),
+ .dsps_pwr_ctl_en = 1,
+ .signature = DSPS_SIGNATURE,
+};
+
+static struct resource msm_dsps_resources[] = {
+ {
+ .start = PPSS_REG_PHYS_BASE,
+ .end = PPSS_REG_PHYS_BASE + SZ_8K - 1,
+ .name = "ppss_reg",
+ .flags = IORESOURCE_MEM,
+ },
+
+ {
+ .start = PPSS_WDOG_TIMER_IRQ,
+ .end = PPSS_WDOG_TIMER_IRQ,
+ .name = "ppss_wdog",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_dsps_device_8064 = {
+ .name = "msm_dsps",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_dsps_resources),
+ .resource = msm_dsps_resources,
+ .dev.platform_data = &msm_dsps_pdata_8064,
+};
+
#ifdef CONFIG_MSM_MPM
static uint16_t msm_mpm_irqs_m2a[MSM_MPM_NR_MPM_IRQS] __initdata = {
[1] = MSM_GPIO_TO_INT(26),
@@ -1891,4 +2117,3 @@
.num_resources = ARRAY_SIZE(mdm_resources),
.resource = mdm_resources,
};
-
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 19a8db7..718cfb1 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -30,8 +30,10 @@
#include <mach/rpm.h>
#include <mach/msm_bus_board.h>
#include <mach/msm_memtypes.h>
+#include <mach/msm_smd.h>
#include <sound/msm-dai-q6.h>
#include <sound/apr_audio.h>
+#include <mach/msm_tsif.h>
#include "clock.h"
#include "devices.h"
#include "devices-msm8x60.h"
@@ -950,9 +952,158 @@
.id = -1,
};
+static struct resource smd_resource[] = {
+ {
+ .name = "a9_m2a_0",
+ .start = INT_A9_M2A_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "a9_m2a_5",
+ .start = INT_A9_M2A_5,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_a11",
+ .start = INT_ADSP_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "adsp_a11_smsm",
+ .start = INT_ADSP_A11_SMSM,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "dsps_a11",
+ .start = INT_DSPS_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "dsps_a11_smsm",
+ .start = INT_DSPS_A11_SMSM,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "wcnss_a11",
+ .start = INT_WCNSS_A11,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "wcnss_a11_smsm",
+ .start = INT_WCNSS_A11_SMSM,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct smd_subsystem_config smd_config_list[] = {
+ {
+ .irq_config_id = SMD_MODEM,
+ .subsys_name = "modem",
+ .edge = SMD_APPS_MODEM,
+
+ .smd_int.irq_name = "a9_m2a_0",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 3,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "a9_m2a_5",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 4,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_Q6,
+ .subsys_name = "q6",
+ .edge = SMD_APPS_QDSP,
+
+ .smd_int.irq_name = "adsp_a11",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 15,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "adsp_a11_smsm",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 14,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+ {
+ .irq_config_id = SMD_DSPS,
+ .subsys_name = "dsps",
+ .edge = SMD_APPS_DSPS,
+
+ .smd_int.irq_name = "dsps_a11",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1,
+ .smd_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+ .smd_int.out_offset = 0x4080,
+
+ .smsm_int.irq_name = "dsps_a11_smsm",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1,
+ .smsm_int.out_base = (void __iomem *)MSM_SIC_NON_SECURE_BASE,
+ .smsm_int.out_offset = 0x4094,
+ },
+ {
+ .irq_config_id = SMD_WCNSS,
+ .subsys_name = "wcnss",
+ .edge = SMD_APPS_WCNSS,
+
+ .smd_int.irq_name = "wcnss_a11",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+ .smd_int.out_bit_pos = 1 << 25,
+ .smd_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smd_int.out_offset = 0x8,
+
+ .smsm_int.irq_name = "wcnss_a11_smsm",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smd_smsm",
+ .smsm_int.dev_id = 0,
+ .smsm_int.out_bit_pos = 1 << 23,
+ .smsm_int.out_base = (void __iomem *)MSM_APCS_GCC_BASE,
+ .smsm_int.out_offset = 0x8,
+ },
+};
+
+static struct smd_platform smd_platform_data = {
+ .num_ss_configs = ARRAY_SIZE(smd_config_list),
+ .smd_ss_configs = smd_config_list,
+};
+
+
struct platform_device msm_device_smd = {
.name = "msm_smd",
.id = -1,
+ .resource = smd_resource,
+ .num_resources = ARRAY_SIZE(smd_resource),
+ .dev = {
+ .platform_data = &smd_platform_data,
+ },
};
struct platform_device msm_device_bam_dmux = {
@@ -1355,6 +1506,111 @@
};
#endif
+#define MSM_TSIF0_PHYS (0x18200000)
+#define MSM_TSIF1_PHYS (0x18201000)
+#define MSM_TSIF_SIZE (0x200)
+
+#define TSIF_0_CLK GPIO_CFG(75, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_EN GPIO_CFG(76, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_DATA GPIO_CFG(77, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_0_SYNC GPIO_CFG(82, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_CLK GPIO_CFG(79, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_EN GPIO_CFG(80, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_DATA GPIO_CFG(81, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+#define TSIF_1_SYNC GPIO_CFG(78, 1, GPIO_CFG_INPUT, \
+ GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA)
+
+static const struct msm_gpio tsif0_gpios[] = {
+ { .gpio_cfg = TSIF_0_CLK, .label = "tsif_clk", },
+ { .gpio_cfg = TSIF_0_EN, .label = "tsif_en", },
+ { .gpio_cfg = TSIF_0_DATA, .label = "tsif_data", },
+ { .gpio_cfg = TSIF_0_SYNC, .label = "tsif_sync", },
+};
+
+static const struct msm_gpio tsif1_gpios[] = {
+ { .gpio_cfg = TSIF_1_CLK, .label = "tsif_clk", },
+ { .gpio_cfg = TSIF_1_EN, .label = "tsif_en", },
+ { .gpio_cfg = TSIF_1_DATA, .label = "tsif_data", },
+ { .gpio_cfg = TSIF_1_SYNC, .label = "tsif_sync", },
+};
+
+struct msm_tsif_platform_data tsif1_platform_data = {
+ .num_gpios = ARRAY_SIZE(tsif1_gpios),
+ .gpios = tsif1_gpios,
+ .tsif_pclk = "tsif_pclk",
+ .tsif_ref_clk = "tsif_ref_clk",
+};
+
+struct resource tsif1_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ .start = TSIF2_IRQ,
+ .end = TSIF2_IRQ,
+ },
+ [1] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF1_PHYS,
+ .end = MSM_TSIF1_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [2] = {
+ .flags = IORESOURCE_DMA,
+ .start = DMOV_TSIF_CHAN,
+ .end = DMOV_TSIF_CRCI,
+ },
+};
+
+struct msm_tsif_platform_data tsif0_platform_data = {
+ .num_gpios = ARRAY_SIZE(tsif0_gpios),
+ .gpios = tsif0_gpios,
+ .tsif_pclk = "tsif_pclk",
+ .tsif_ref_clk = "tsif_ref_clk",
+};
+struct resource tsif0_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ .start = TSIF1_IRQ,
+ .end = TSIF1_IRQ,
+ },
+ [1] = {
+ .flags = IORESOURCE_MEM,
+ .start = MSM_TSIF0_PHYS,
+ .end = MSM_TSIF0_PHYS + MSM_TSIF_SIZE - 1,
+ },
+ [2] = {
+ .flags = IORESOURCE_DMA,
+ .start = DMOV_TSIF_CHAN,
+ .end = DMOV_TSIF_CRCI,
+ },
+};
+
+struct platform_device msm_device_tsif[2] = {
+ {
+ .name = "msm_tsif",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(tsif0_resources),
+ .resource = tsif0_resources,
+ .dev = {
+ .platform_data = &tsif0_platform_data
+ },
+ },
+ {
+ .name = "msm_tsif",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(tsif1_resources),
+ .resource = tsif1_resources,
+ .dev = {
+ .platform_data = &tsif1_platform_data
+ },
+ }
+};
+
static struct resource resources_ssbi_pmic[] = {
{
.start = MSM_PMIC1_SSBI_CMD_PHYS,
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index cc1e7c5..c19c133 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.c
@@ -33,6 +33,7 @@
#include "devices-msm7x2xa.h"
#include "footswitch.h"
#include "acpuclock.h"
+#include "spm.h"
/* Address of GSBI blocks */
#define MSM_GSBI0_PHYS 0xA1200000
@@ -210,6 +211,63 @@
.id = -1,
};
+static struct resource smd_8625_resource[] = {
+ {
+ .name = "a9_m2a_0",
+ .start = MSM8625_INT_A9_M2A_0,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "a9_m2a_5",
+ .start = MSM8625_INT_A9_M2A_5,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct smd_subsystem_config smd_8625_config_list[] = {
+ {
+ .irq_config_id = SMD_MODEM,
+ .subsys_name = "modem",
+ .edge = SMD_APPS_MODEM,
+
+ .smd_int.irq_name = "a9_m2a_0",
+ .smd_int.flags = IRQF_TRIGGER_RISING,
+ .smd_int.irq_id = -1,
+ .smd_int.device_name = "smd_dev",
+ .smd_int.dev_id = 0,
+
+ .smd_int.out_bit_pos = 1,
+ .smd_int.out_base = (void __iomem *)MSM_CSR_BASE,
+ .smd_int.out_offset = 0x400 + (0) * 4,
+
+ .smsm_int.irq_name = "a9_m2a_5",
+ .smsm_int.flags = IRQF_TRIGGER_RISING,
+ .smsm_int.irq_id = -1,
+ .smsm_int.device_name = "smsm_dev",
+ .smsm_int.dev_id = 0,
+
+ .smsm_int.out_bit_pos = 1,
+ .smsm_int.out_base = (void __iomem *)MSM_CSR_BASE,
+ .smsm_int.out_offset = 0x400 + (5) * 4,
+
+ }
+};
+
+static struct smd_platform smd_8625_platform_data = {
+ .num_ss_configs = ARRAY_SIZE(smd_8625_config_list),
+ .smd_ss_configs = smd_8625_config_list,
+};
+
+struct platform_device msm8625_device_smd = {
+ .name = "msm_smd",
+ .id = -1,
+ .resource = smd_8625_resource,
+ .num_resources = ARRAY_SIZE(smd_8625_resource),
+ .dev = {
+ .platform_data = &smd_8625_platform_data,
+ }
+};
+
static struct resource resources_adsp[] = {
{
.start = INT_ADSP_A9_A11,
@@ -584,6 +642,55 @@
#endif
+/* Command sequence for simple WFI */
+static uint8_t spm_wfi_cmd_sequence[] __initdata = {
+ 0x00, 0x40, 0x40, 0x03,
+ 0x00, 0x40, 0x40, 0x0f,
+};
+
+/* Command sequence for GDFS, this won't send any interrupt to the modem */
+static uint8_t spm_pc_without_modem[] __initdata = {
+ 0x20, 0x00, 0x30, 0x10,
+ 0x40, 0x40, 0x03, 0x10,
+ 0x00, 0x30, 0x2E, 0x40,
+ 0x40, 0x0f,
+};
+
+static struct msm_spm_seq_entry msm_spm_seq_list[] __initdata = {
+ [0] = {
+ .mode = MSM_SPM_MODE_CLOCK_GATING,
+ .notify_rpm = false,
+ .cmd = spm_wfi_cmd_sequence,
+ },
+ [1] = {
+ .mode = MSM_SPM_MODE_POWER_COLLAPSE,
+ .notify_rpm = false,
+ .cmd = spm_pc_without_modem,
+ },
+};
+
+static struct msm_spm_platform_data msm_spm_data[] __initdata = {
+ [0] = {
+ .reg_base_addr = MSM_SAW0_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+ .num_modes = ARRAY_SIZE(msm_spm_seq_list),
+ .modes = msm_spm_seq_list,
+ },
+ [1] = {
+ .reg_base_addr = MSM_SAW1_BASE,
+ .reg_init_values[MSM_SPM_REG_SAW2_CFG] = 0x0,
+ .reg_init_values[MSM_SPM_REG_SAW2_SPM_CTL] = 0x01,
+ .num_modes = ARRAY_SIZE(msm_spm_seq_list),
+ .modes = msm_spm_seq_list,
+ },
+};
+
+void __init msm8x25_spm_device_init(void)
+{
+ msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
+}
+
#define MDP_BASE 0xAA200000
#define MIPI_DSI_HW_BASE 0xA1100000
@@ -690,7 +797,9 @@
kgsl_3d0_pdata.pwrlevel[0].bus_freq = 160000000;
kgsl_3d0_pdata.pwrlevel[1].gpu_freq = 96000000;
kgsl_3d0_pdata.pwrlevel[1].bus_freq = 0;
- }
+ } else if (cpu_is_msm8625())
+ /* msm8625 has an idle_timout of 50 hours */
+ kgsl_3d0_pdata.idle_timeout = 18000000;
}
static void __init msm_register_device(struct platform_device *pdev, void *data)
@@ -917,7 +1026,7 @@
};
/* Use GSBI0 QUP for /dev/i2c-0 */
-struct platform_device msm8625_device_qup_i2c_gsbi0 = {
+struct platform_device msm8625_gsbi0_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI0_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi0_msm8625_qup_resources),
@@ -946,7 +1055,7 @@
};
/* Use GSBI1 QUP for /dev/i2c-1 */
-struct platform_device msm8625_device_qup_i2c_gsbi1 = {
+struct platform_device msm8625_gsbi1_qup_i2c_device = {
.name = "qup_i2c",
.id = MSM_GSBI1_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi1_qup_i2c_resources),
@@ -1431,7 +1540,7 @@
}
msm_clock_init(&msm7x27a_clock_init_data);
- if (cpu_is_msm7x27aa())
+ if (cpu_is_msm7x27aa() || cpu_is_msm8625())
acpuclk_init(&acpuclk_7x27aa_soc_data);
else
acpuclk_init(&acpuclk_7x27a_soc_data);
diff --git a/arch/arm/mach-msm/devices-msm7x2xa.h b/arch/arm/mach-msm/devices-msm7x2xa.h
index c2383c6..3c81ccf 100644
--- a/arch/arm/mach-msm/devices-msm7x2xa.h
+++ b/arch/arm/mach-msm/devices-msm7x2xa.h
@@ -30,4 +30,5 @@
void __init msm8625_init_irq(void);
void __init msm8625_map_io(void);
int ar600x_wlan_power(bool on);
+void __init msm8x25_spm_device_init(void);
#endif
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index e9b94f6..89c8aaf 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -74,6 +74,20 @@
.resource = msm_ebi1_thermal_resources
};
+static struct resource resources_adsp[] = {
+{
+ .start = INT_ADSP_A9_A11,
+ .end = INT_ADSP_A9_A11,
+ .flags = IORESOURCE_IRQ,
+},
+};
+
+struct platform_device msm_adsp_device = {
+ .name = "msm_adsp",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(resources_adsp),
+ .resource = resources_adsp,
+};
static struct resource resources_uart1[] = {
{
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index ed48659..4371c23 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -112,6 +112,7 @@
extern struct platform_device apq8064_device_hsusb_host;
extern struct platform_device apq8064_device_hsic_host;
extern struct platform_device apq8064_device_ehci_host3;
+extern struct platform_device apq8064_device_ehci_host4;
extern struct platform_device msm_device_i2c;
@@ -128,8 +129,8 @@
extern struct platform_device msm_gsbi9_qup_i2c_device;
extern struct platform_device msm_gsbi12_qup_i2c_device;
-extern struct platform_device msm8625_device_qup_i2c_gsbi0;
-extern struct platform_device msm8625_device_qup_i2c_gsbi1;
+extern struct platform_device msm8625_gsbi0_qup_i2c_device;
+extern struct platform_device msm8625_gsbi1_qup_i2c_device;
extern struct platform_device msm8625_device_uart_dm1;
extern struct platform_device msm8625_device_uart_dm2;
extern struct platform_device msm8625_device_sdc1;
@@ -149,6 +150,7 @@
extern struct platform_device msm_device_bam_dmux;
extern struct platform_device msm_device_smd;
extern struct platform_device msm_device_smd_apq8064;
+extern struct platform_device msm8625_device_smd;
extern struct platform_device msm_device_dmov;
extern struct platform_device msm8960_device_dmov;
extern struct platform_device apq8064_device_dmov;
@@ -322,3 +324,5 @@
extern struct platform_device msm_bus_8064_cpss_fpb;
extern struct platform_device mdm_8064_device;
+
+extern struct platform_device msm_dsps_device_8064;
diff --git a/arch/arm/mach-msm/idle.h b/arch/arm/mach-msm/idle.h
index 830e36b..6311b3c 100644
--- a/arch/arm/mach-msm/idle.h
+++ b/arch/arm/mach-msm/idle.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007-2009,2011 Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2007-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,6 +28,15 @@
{
/* empty */
}
+static inline void msm_pm_boot_entry(void)
+{
+ /* empty */
+}
+static inline void msm_pm_write_boot_vector(unsigned int cpu,
+ unsigned long address)
+{
+ /* empty */
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 96b0083..a87a759 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -367,6 +367,7 @@
#ifdef CONFIG_MSM_BUS_SCALING
struct msm_bus_scale_pdata *bus_scale_table;
#endif
+ int (*lvds_pixel_remap)(void);
};
struct tvenc_platform_data {
@@ -417,10 +418,13 @@
int *gpio;
};
+#define PANEL_NAME_MAX_LEN 50
struct msm_fb_platform_data {
int (*detect_client)(const char *name);
int mddi_prescan;
int (*allow_set_offset)(void);
+ char prim_panel_name[PANEL_NAME_MAX_LEN];
+ char ext_panel_name[PANEL_NAME_MAX_LEN];
};
struct msm_hdmi_platform_data {
diff --git a/arch/arm/mach-msm/include/mach/diag_bridge.h b/arch/arm/mach-msm/include/mach/diag_bridge.h
index a39ed25..b06f020 100644
--- a/arch/arm/mach-msm/include/mach/diag_bridge.h
+++ b/arch/arm/mach-msm/include/mach/diag_bridge.h
@@ -19,6 +19,8 @@
int buf_size, int actual);
void (*write_complete_cb)(void *ctxt, char *buf,
int buf_size, int actual);
+ int (*suspend)(void *ctxt);
+ void (*resume)(void *ctxt);
};
#if defined(CONFIG_USB_QCOM_DIAG_BRIDGE) \
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 3cb79b7..d170f5f 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -177,6 +177,9 @@
#define DMOV_CE_OUT_CHAN 1
#define DMOV_CE_OUT_CRCI 3
+#define DMOV_TSIF_CHAN 2
+#define DMOV_TSIF_CRCI 11
+
#define DMOV_HSUART_GSBI6_TX_CHAN 7
#define DMOV_HSUART_GSBI6_TX_CRCI 6
diff --git a/arch/arm/mach-msm/include/mach/irqs-copper.h b/arch/arm/mach-msm/include/mach/irqs-copper.h
index 821eaeb..c961804 100644
--- a/arch/arm/mach-msm/include/mach/irqs-copper.h
+++ b/arch/arm/mach-msm/include/mach/irqs-copper.h
@@ -36,7 +36,8 @@
#define NR_MSM_IRQS 1020 /* Should be 256 - but higher due to bug in sim */
#define NR_GPIO_IRQS 156
-#define NR_BOARD_IRQS 100
+#define NR_QPNP_IRQS 32768 /* SPARSE_IRQ is required to support this */
+#define NR_BOARD_IRQS NR_QPNP_IRQS
#define NR_TLMM_MSM_DIR_CONN_IRQ 8
#define NR_MSM_GPIOS NR_GPIO_IRQS
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
index 6311dbe..b560276 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-copper.h
@@ -34,7 +34,7 @@
#define COPPER_APCS_GCC_PHYS 0xF9011000
#define COPPER_APCS_GCC_SIZE SZ_4K
-#define COPPER_TLMM_PHYS 0xFD400000
+#define COPPER_TLMM_PHYS 0xFD510000
#define COPPER_TLMM_SIZE SZ_16K
#ifdef CONFIG_DEBUG_MSMCOPPER_UART
diff --git a/arch/arm/mach-msm/include/mach/msm_smd.h b/arch/arm/mach-msm/include/mach/msm_smd.h
index 4be6d9ea..8d3e640 100644
--- a/arch/arm/mach-msm/include/mach/msm_smd.h
+++ b/arch/arm/mach-msm/include/mach/msm_smd.h
@@ -236,6 +236,22 @@
*/
int smd_write_end(smd_channel_t *ch);
+/*
+ * Returns a pointer to the subsystem name or NULL if no
+ * subsystem name is available.
+ *
+ * @type - Edge definition
+ */
+const char *smd_edge_to_subsystem(uint32_t type);
+
+/*
+ * Returns a pointer to the subsystem name given the
+ * remote processor ID.
+ *
+ * @pid Remote processor ID
+ * @returns Pointer to subsystem name or NULL if not found
+ */
+const char *smd_pid_to_subsystem(uint32_t pid);
#else
static inline int smd_open(const char *name, smd_channel_t **ch, void *priv,
@@ -337,6 +353,16 @@
{
return -ENODEV;
}
+
+static inline const char *smd_edge_to_subsystem(uint32_t type)
+{
+ return NULL;
+}
+
+static inline const char *smd_pid_to_subsystem(uint32_t pid)
+{
+ return NULL;
+}
#endif
#endif
diff --git a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
index 71f2bd9..20c6fc4 100644
--- a/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
+++ b/arch/arm/mach-msm/include/mach/qdsp6v2/audio_dev_ctl.h
@@ -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
@@ -96,6 +96,8 @@
int msm_reset_all_device(void);
+int reset_device(void);
+
int msm_clear_all_session(void);
struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id);
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index 6aa944f..af4691a 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.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
@@ -22,6 +22,7 @@
#define SCM_SVC_FUSE 0x8
#define SCM_SVC_PWR 0x9
#define SCM_SVC_CP 0xC
+#define SCM_SVC_DCVS 0xD
#define SCM_SVC_TZSCHEDULER 0xFC
#ifdef CONFIG_MSM_SCM
@@ -30,6 +31,8 @@
extern s32 scm_call_atomic1(u32 svc, u32 cmd, u32 arg1);
extern s32 scm_call_atomic2(u32 svc, u32 cmd, u32 arg1, u32 arg2);
+extern s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2, u32 arg3,
+ u32 arg4, u32 *ret1, u32 *ret2);
#define SCM_VERSION(major, minor) (((major) << 16) | ((minor) & 0xFF))
@@ -54,6 +57,12 @@
return 0;
}
+static inline s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
+ u32 arg3, u32 arg4, u32 *ret1, u32 *ret2)
+{
+ return 0;
+}
+
static inline u32 scm_get_version(void)
{
return 0;
diff --git a/arch/arm/mach-msm/include/mach/timex.h b/arch/arm/mach-msm/include/mach/timex.h
index 61f1996..ca7c4c7 100644
--- a/arch/arm/mach-msm/include/mach/timex.h
+++ b/arch/arm/mach-msm/include/mach/timex.h
@@ -18,8 +18,6 @@
#define CLOCK_TICK_RATE 1000000
-#ifdef CONFIG_MSM_SMP
#define ARCH_HAS_READ_CURRENT_TIMER
-#endif
#endif
diff --git a/arch/arm/mach-msm/io.c b/arch/arm/mach-msm/io.c
index c8bf194..a643c68 100644
--- a/arch/arm/mach-msm/io.c
+++ b/arch/arm/mach-msm/io.c
@@ -420,6 +420,7 @@
MSM_CHIP_DEVICE(SAW0, MSM8625),
MSM_CHIP_DEVICE(SAW1, MSM8625),
MSM_CHIP_DEVICE(AD5, MSM7XXX),
+ MSM_CHIP_DEVICE(MDC, MSM7XXX),
#if defined(CONFIG_DEBUG_MSM_UART1) || defined(CONFIG_DEBUG_MSM_UART2) || \
defined(CONFIG_DEBUG_MSM_UART3)
MSM_CHIP_DEVICE(DEBUG_UART, MSM7XXX),
diff --git a/arch/arm/mach-msm/mdm_common.c b/arch/arm/mach-msm/mdm_common.c
index 7445a61..04c29cc 100644
--- a/arch/arm/mach-msm/mdm_common.c
+++ b/arch/arm/mach-msm/mdm_common.c
@@ -242,6 +242,8 @@
static int mdm_subsys_powerup(const struct subsys_data *crashed_subsys)
{
+ gpio_direction_output(mdm_drv->ap2mdm_errfatal_gpio, 0);
+ gpio_direction_output(mdm_drv->ap2mdm_status_gpio, 1);
mdm_drv->ops->power_on_mdm_cb(mdm_drv);
mdm_drv->boot_type = CHARM_NORMAL_BOOT;
complete(&mdm_needs_reload);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index feabe04..56aba3e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -9,6 +9,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_config.c b/arch/arm/mach-msm/msm_bus/msm_bus_config.c
index 7d9d18f..28f3073 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_config.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_config.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
@@ -9,6 +9,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.c b/arch/arm/mach-msm/msm_bus/msm_bus_core.c
index 9fe05b7..4d73b03 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.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
@@ -9,6 +9,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_core.h b/arch/arm/mach-msm/msm_bus/msm_bus_core.h
index 50afa81..e35130e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_core.h
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_core.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
@@ -20,22 +20,14 @@
#include <mach/msm_bus_board.h>
#include <mach/msm_bus.h>
-#if defined DEBUG
-
#define MSM_BUS_DBG(msg, ...) \
- printk(KERN_DEBUG "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
-
-#else
-#define MSM_BUS_DBG(msg, ...) no_printk("AXI")
-#endif
-
+ pr_debug(msg, ## __VA_ARGS__)
#define MSM_BUS_ERR(msg, ...) \
- printk(KERN_ERR "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
+ pr_err(msg, ## __VA_ARGS__)
#define MSM_BUS_WARN(msg, ...) \
- printk(KERN_WARNING "AXI: %s(): " msg, __func__, ## __VA_ARGS__)
+ pr_warn(msg, ## __VA_ARGS__)
#define MSM_FAB_ERR(msg, ...) \
- dev_err(&fabric->fabdev.dev, "AXI: %s(): " msg, __func__, ## \
- __VA_ARGS__)
+ dev_err(&fabric->fabdev.dev, msg, ## __VA_ARGS__)
enum msm_bus_dbg_op_type {
MSM_BUS_DBG_UNREGISTER = -2,
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
index abd986b..e63df1b 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_dbg.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_dbg.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
@@ -10,6 +10,9 @@
* GNU General Public License for more details.
*
*/
+
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
index 3b178b5..2c69914 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_fabric.c
@@ -10,6 +10,8 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
index a8dc7c8..b13037e 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_rpm.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_rpm.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
@@ -11,6 +11,8 @@
*
*/
+#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
@@ -342,7 +344,7 @@
fab_pdata->nmasters) + 1);
ret = memcmp(cd1->arb, cd2->arb, n);
if (ret) {
- MSM_BUS_DBG("Commit Data arb[%d] not equal\n", i);
+ MSM_BUS_DBG("Commit Data arb[%d] not equal\n", n);
return ret;
}
diff --git a/arch/arm/mach-msm/msm_watchdog.c b/arch/arm/mach-msm/msm_watchdog.c
index 5bff832..28b5995 100644
--- a/arch/arm/mach-msm/msm_watchdog.c
+++ b/arch/arm/mach-msm/msm_watchdog.c
@@ -304,6 +304,9 @@
static void init_watchdog_work(struct work_struct *work)
{
u64 timeout = (bark_time * WDT_HZ)/1000;
+
+ configure_bark_dump();
+
__raw_writel(timeout, msm_tmr0_base + WDT0_BARK_TIME);
__raw_writel(timeout + 3*WDT_HZ, msm_tmr0_base + WDT0_BITE_TIME);
@@ -366,8 +369,6 @@
if (pdata->needs_expired_enable)
__raw_writel(0x1, MSM_CLK_CTL_BASE + 0x3820);
- configure_bark_dump();
-
delay_time = msecs_to_jiffies(pdata->pet_time);
schedule_work_on(0, &init_dogwork_struct);
return 0;
diff --git a/arch/arm/mach-msm/msm_xo.c b/arch/arm/mach-msm/msm_xo.c
index 74c64c1..f7d2bcb 100644
--- a/arch/arm/mach-msm/msm_xo.c
+++ b/arch/arm/mach-msm/msm_xo.c
@@ -237,13 +237,6 @@
unsigned long flags;
struct msm_xo_voter *xo_voter;
- /*
- * TODO: Remove early return for 8064 once RPM XO voting support
- * is available.
- */
- if (cpu_is_apq8064())
- return NULL;
-
if (xo_id >= NUM_MSM_XO_IDS) {
ret = -EINVAL;
goto err;
diff --git a/arch/arm/mach-msm/peripheral-loader.c b/arch/arm/mach-msm/peripheral-loader.c
index 1004e01..6d1a5f0 100644
--- a/arch/arm/mach-msm/peripheral-loader.c
+++ b/arch/arm/mach-msm/peripheral-loader.c
@@ -20,9 +20,11 @@
#include <linux/mutex.h>
#include <linux/memblock.h>
#include <linux/slab.h>
+#include <linux/atomic.h>
#include <asm/uaccess.h>
#include <asm/setup.h>
+#include <mach/peripheral-loader.h>
#include "peripheral-loader.h"
@@ -30,34 +32,35 @@
struct pil_desc *desc;
int count;
struct mutex lock;
- struct list_head list;
+ struct device dev;
+ struct module *owner;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
};
-static DEFINE_MUTEX(pil_list_lock);
-static LIST_HEAD(pil_list);
+#define to_pil_device(d) container_of(d, struct pil_device, dev)
-static struct pil_device *__find_peripheral(const char *str)
+struct bus_type pil_bus_type = {
+ .name = "pil",
+};
+
+static int __find_peripheral(struct device *dev, void *data)
{
- struct pil_device *dev;
-
- list_for_each_entry(dev, &pil_list, list)
- if (!strcmp(dev->desc->name, str))
- return dev;
- return NULL;
+ struct pil_device *pdev = to_pil_device(dev);
+ return !strncmp(pdev->desc->name, data, INT_MAX);
}
static struct pil_device *find_peripheral(const char *str)
{
- struct pil_device *dev;
+ struct device *dev;
if (!str)
return NULL;
- mutex_lock(&pil_list_lock);
- dev = __find_peripheral(str);
- mutex_unlock(&pil_list_lock);
-
- return dev;
+ dev = bus_find_device(&pil_bus_type, NULL, (void *)str,
+ __find_peripheral);
+ return dev ? to_pil_device(dev) : NULL;
}
#define IOMAP_SIZE SZ_4M
@@ -71,24 +74,23 @@
const u8 *data;
if (memblock_is_region_memory(phdr->p_paddr, phdr->p_memsz)) {
- dev_err(pil->desc->dev, "Kernel memory would be overwritten");
+ dev_err(&pil->dev, "Kernel memory would be overwritten");
return -EPERM;
}
if (phdr->p_filesz) {
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d",
pil->desc->name, num);
- ret = request_firmware(&fw, fw_name, pil->desc->dev);
+ ret = request_firmware(&fw, fw_name, &pil->dev);
if (ret) {
- dev_err(pil->desc->dev, "Failed to locate blob %s\n",
+ dev_err(&pil->dev, "Failed to locate blob %s\n",
fw_name);
return ret;
}
if (fw->size != phdr->p_filesz) {
- dev_err(pil->desc->dev,
- "Blob size %u doesn't match %u\n", fw->size,
- phdr->p_filesz);
+ dev_err(&pil->dev, "Blob size %u doesn't match %u\n",
+ fw->size, phdr->p_filesz);
ret = -EPERM;
goto release_fw;
}
@@ -105,7 +107,7 @@
size = min_t(size_t, IOMAP_SIZE, count);
buf = ioremap(paddr, size);
if (!buf) {
- dev_err(pil->desc->dev, "Failed to map memory\n");
+ dev_err(&pil->dev, "Failed to map memory\n");
ret = -ENOMEM;
goto release_fw;
}
@@ -126,7 +128,7 @@
size = min_t(size_t, IOMAP_SIZE, count);
buf = ioremap(paddr, size);
if (!buf) {
- dev_err(pil->desc->dev, "Failed to map memory\n");
+ dev_err(&pil->dev, "Failed to map memory\n");
ret = -ENOMEM;
goto release_fw;
}
@@ -140,7 +142,7 @@
ret = pil->desc->ops->verify_blob(pil->desc, phdr->p_paddr,
phdr->p_memsz);
if (ret)
- dev_err(pil->desc->dev, "Blob %u failed verification\n", num);
+ dev_err(&pil->dev, "Blob %u failed verification\n", num);
release_fw:
release_firmware(fw);
@@ -163,40 +165,40 @@
const struct firmware *fw;
snprintf(fw_name, sizeof(fw_name), "%s.mdt", pil->desc->name);
- ret = request_firmware(&fw, fw_name, pil->desc->dev);
+ ret = request_firmware(&fw, fw_name, &pil->dev);
if (ret) {
- dev_err(pil->desc->dev, "Failed to locate %s\n", fw_name);
+ dev_err(&pil->dev, "Failed to locate %s\n", fw_name);
goto out;
}
if (fw->size < sizeof(*ehdr)) {
- dev_err(pil->desc->dev, "Not big enough to be an elf header\n");
+ dev_err(&pil->dev, "Not big enough to be an elf header\n");
ret = -EIO;
goto release_fw;
}
ehdr = (struct elf32_hdr *)fw->data;
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
- dev_err(pil->desc->dev, "Not an elf header\n");
+ dev_err(&pil->dev, "Not an elf header\n");
ret = -EIO;
goto release_fw;
}
if (ehdr->e_phnum == 0) {
- dev_err(pil->desc->dev, "No loadable segments\n");
+ dev_err(&pil->dev, "No loadable segments\n");
ret = -EIO;
goto release_fw;
}
if (sizeof(struct elf32_phdr) * ehdr->e_phnum +
sizeof(struct elf32_hdr) > fw->size) {
- dev_err(pil->desc->dev, "Program headers not within mdt\n");
+ dev_err(&pil->dev, "Program headers not within mdt\n");
ret = -EIO;
goto release_fw;
}
ret = pil->desc->ops->init_image(pil->desc, fw->data, fw->size);
if (ret) {
- dev_err(pil->desc->dev, "Invalid firmware metadata\n");
+ dev_err(&pil->dev, "Invalid firmware metadata\n");
goto release_fw;
}
@@ -207,7 +209,7 @@
ret = load_segment(phdr, i, pil);
if (ret) {
- dev_err(pil->desc->dev, "Failed to load segment %d\n",
+ dev_err(&pil->dev, "Failed to load segment %d\n",
i);
goto release_fw;
}
@@ -215,10 +217,10 @@
ret = pil->desc->ops->auth_and_reset(pil->desc);
if (ret) {
- dev_err(pil->desc->dev, "Failed to bring out of reset\n");
+ dev_err(&pil->dev, "Failed to bring out of reset\n");
goto release_fw;
}
- dev_info(pil->desc->dev, "brought out of reset\n");
+ dev_info(&pil->dev, "brought %s out of reset\n", pil->desc->name);
release_fw:
release_firmware(fw);
@@ -242,33 +244,41 @@
struct pil_device *pil_d;
void *retval;
+ if (!name)
+ return NULL;
+
pil = retval = find_peripheral(name);
if (!pil)
return ERR_PTR(-ENODEV);
+ if (!try_module_get(pil->owner)) {
+ put_device(&pil->dev);
+ return ERR_PTR(-ENODEV);
+ }
- pil_d = find_peripheral(pil->desc->depends_on);
- if (pil_d) {
- void *p = pil_get(pil_d->desc->name);
- if (IS_ERR(p))
- return p;
+ pil_d = pil_get(pil->desc->depends_on);
+ if (IS_ERR(pil_d)) {
+ retval = pil_d;
+ goto err_depends;
}
mutex_lock(&pil->lock);
- if (pil->count) {
- pil->count++;
- goto unlock;
+ if (!pil->count++) {
+ ret = load_image(pil);
+ if (ret) {
+ retval = ERR_PTR(ret);
+ goto err_load;
+ }
}
-
- ret = load_image(pil);
- if (ret) {
- retval = ERR_PTR(ret);
- goto unlock;
- }
-
- pil->count++;
-unlock:
mutex_unlock(&pil->lock);
+out:
return retval;
+err_load:
+ mutex_unlock(&pil->lock);
+ pil_put(pil_d);
+err_depends:
+ put_device(&pil->dev);
+ module_put(pil->owner);
+ goto out;
}
EXPORT_SYMBOL(pil_get);
@@ -281,22 +291,29 @@
*/
void pil_put(void *peripheral_handle)
{
- struct pil_device *pil_d;
- struct pil_device *pil = peripheral_handle;
- if (!pil || IS_ERR(pil))
+ struct pil_device *pil_d, *pil = peripheral_handle;
+
+ if (IS_ERR_OR_NULL(pil))
return;
mutex_lock(&pil->lock);
- WARN(!pil->count, "%s: Reference count mismatch\n", __func__);
- if (pil->count)
- pil->count--;
- if (pil->count == 0)
+ if (WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
+ goto err_out;
+ if (!--pil->count)
pil->desc->ops->shutdown(pil->desc);
mutex_unlock(&pil->lock);
pil_d = find_peripheral(pil->desc->depends_on);
- if (pil_d)
+ module_put(pil->owner);
+ if (pil_d) {
pil_put(pil_d);
+ put_device(&pil_d->dev);
+ }
+ put_device(&pil->dev);
+ return;
+err_out:
+ mutex_unlock(&pil->lock);
+ return;
}
EXPORT_SYMBOL(pil_put);
@@ -312,6 +329,7 @@
if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
pil->desc->ops->shutdown(pil->desc);
mutex_unlock(&pil->lock);
+ put_device(&pil->dev);
}
EXPORT_SYMBOL(pil_force_shutdown);
@@ -328,13 +346,14 @@
if (!WARN(!pil->count, "%s: Reference count mismatch\n", __func__))
ret = load_image(pil);
mutex_unlock(&pil->lock);
+ put_device(&pil->dev);
return ret;
}
EXPORT_SYMBOL(pil_force_boot);
#ifdef CONFIG_DEBUG_FS
-int msm_pil_debugfs_open(struct inode *inode, struct file *filp)
+static int msm_pil_debugfs_open(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private;
return 0;
@@ -384,7 +403,7 @@
static struct dentry *pil_base_dir;
-static int msm_pil_debugfs_init(void)
+static int __init msm_pil_debugfs_init(void)
{
pil_base_dir = debugfs_create_dir("pil", NULL);
if (!pil_base_dir) {
@@ -394,52 +413,119 @@
return 0;
}
-arch_initcall(msm_pil_debugfs_init);
+
+static void __exit msm_pil_debugfs_exit(void)
+{
+ debugfs_remove_recursive(pil_base_dir);
+}
static int msm_pil_debugfs_add(struct pil_device *pil)
{
if (!pil_base_dir)
return -ENOMEM;
- if (!debugfs_create_file(pil->desc->name, S_IRUGO | S_IWUSR,
- pil_base_dir, pil, &msm_pil_debugfs_fops))
- return -ENOMEM;
- return 0;
+ pil->dentry = debugfs_create_file(pil->desc->name, S_IRUGO | S_IWUSR,
+ pil_base_dir, pil, &msm_pil_debugfs_fops);
+ return !pil->dentry ? -ENOMEM : 0;
+}
+
+static void msm_pil_debugfs_remove(struct pil_device *pil)
+{
+ debugfs_remove(pil->dentry);
}
#else
+static int __init msm_pil_debugfs_init(void) { return 0; };
+static void __exit msm_pil_debugfs_exit(void) { return 0; };
static int msm_pil_debugfs_add(struct pil_device *pil) { return 0; }
+static void msm_pil_debugfs_remove(struct pil_device *pil) { }
#endif
+static int __msm_pil_shutdown(struct device *dev, void *data)
+{
+ struct pil_device *pil = to_pil_device(dev);
+ pil->desc->ops->shutdown(pil->desc);
+ return 0;
+}
+
static int msm_pil_shutdown_at_boot(void)
{
- struct pil_device *pil;
-
- mutex_lock(&pil_list_lock);
- list_for_each_entry(pil, &pil_list, list)
- pil->desc->ops->shutdown(pil->desc);
- mutex_unlock(&pil_list_lock);
-
- return 0;
+ return bus_for_each_dev(&pil_bus_type, NULL, NULL, __msm_pil_shutdown);
}
late_initcall(msm_pil_shutdown_at_boot);
-int msm_pil_register(struct pil_desc *desc)
+static void pil_device_release(struct device *dev)
{
+ struct pil_device *pil = to_pil_device(dev);
+ mutex_destroy(&pil->lock);
+ kfree(pil);
+}
+
+struct pil_device *msm_pil_register(struct pil_desc *desc)
+{
+ int err;
+ static atomic_t pil_count = ATOMIC_INIT(-1);
struct pil_device *pil = kzalloc(sizeof(*pil), GFP_KERNEL);
+
if (!pil)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
mutex_init(&pil->lock);
- INIT_LIST_HEAD(&pil->list);
pil->desc = desc;
+ pil->owner = desc->owner;
+ pil->dev.parent = desc->dev;
+ pil->dev.bus = &pil_bus_type;
+ pil->dev.release = pil_device_release;
- mutex_lock(&pil_list_lock);
- list_add(&pil->list, &pil_list);
- mutex_unlock(&pil_list_lock);
+ dev_set_name(&pil->dev, "pil%d", atomic_inc_return(&pil_count));
+ err = device_register(&pil->dev);
+ if (err) {
+ put_device(&pil->dev);
+ mutex_destroy(&pil->lock);
+ kfree(pil);
+ return ERR_PTR(err);
+ }
- return msm_pil_debugfs_add(pil);
+ err = msm_pil_debugfs_add(pil);
+ if (err) {
+ device_unregister(&pil->dev);
+ return ERR_PTR(err);
+ }
+
+ return pil;
}
EXPORT_SYMBOL(msm_pil_register);
+void msm_pil_unregister(struct pil_device *pil)
+{
+ if (IS_ERR_OR_NULL(pil))
+ return;
+
+ if (get_device(&pil->dev)) {
+ mutex_lock(&pil->lock);
+ WARN_ON(pil->count);
+ msm_pil_debugfs_remove(pil);
+ device_unregister(&pil->dev);
+ mutex_unlock(&pil->lock);
+ put_device(&pil->dev);
+ }
+}
+EXPORT_SYMBOL(msm_pil_unregister);
+
+static int __init msm_pil_init(void)
+{
+ int ret = msm_pil_debugfs_init();
+ if (ret)
+ return ret;
+ return bus_register(&pil_bus_type);
+}
+subsys_initcall(msm_pil_init);
+
+static void __exit msm_pil_exit(void)
+{
+ bus_unregister(&pil_bus_type);
+ msm_pil_debugfs_exit();
+}
+module_exit(msm_pil_exit);
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Load peripheral images and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/peripheral-loader.h b/arch/arm/mach-msm/peripheral-loader.h
index 3d4b4b2..cc00446 100644
--- a/arch/arm/mach-msm/peripheral-loader.h
+++ b/arch/arm/mach-msm/peripheral-loader.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
@@ -13,12 +13,14 @@
#define __MSM_PERIPHERAL_LOADER_H
struct device;
+struct module;
struct pil_desc {
const char *name;
const char *depends_on;
struct device *dev;
const struct pil_reset_ops *ops;
+ struct module *owner;
};
struct pil_reset_ops {
@@ -29,6 +31,9 @@
int (*shutdown)(struct pil_desc *pil);
};
-extern int msm_pil_register(struct pil_desc *desc);
+struct pil_device;
+
+extern struct pil_device *msm_pil_register(struct pil_desc *desc);
+extern void msm_pil_unregister(struct pil_device *pil);
#endif
diff --git a/arch/arm/mach-msm/peripheral-reset-8960.c b/arch/arm/mach-msm/peripheral-reset-8960.c
index 6fd8464..7965193 100644
--- a/arch/arm/mach-msm/peripheral-reset-8960.c
+++ b/arch/arm/mach-msm/peripheral-reset-8960.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
@@ -91,6 +91,7 @@
.name = "dsps",
.dev = &pil_dsps.dev,
.ops = &pil_dsps_ops,
+ .owner = THIS_MODULE,
};
static void __init use_secure_pil(void)
@@ -114,8 +115,8 @@
use_secure_pil();
BUG_ON(platform_device_register(&pil_dsps));
- BUG_ON(msm_pil_register(&pil_dsps_desc));
+ BUG_ON(IS_ERR(msm_pil_register(&pil_dsps_desc)));
return 0;
}
-arch_initcall(msm_peripheral_reset_init);
+module_init(msm_peripheral_reset_init);
diff --git a/arch/arm/mach-msm/peripheral-reset.c b/arch/arm/mach-msm/peripheral-reset.c
index 88b07a5..45617e3 100644
--- a/arch/arm/mach-msm/peripheral-reset.c
+++ b/arch/arm/mach-msm/peripheral-reset.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
@@ -101,6 +101,7 @@
.name = "dsps",
.dev = &pil_dsps.dev,
.ops = &pil_dsps_ops,
+ .owner = THIS_MODULE,
};
static int __init msm_peripheral_reset_init(void)
@@ -114,12 +115,12 @@
if (machine_is_msm8x60_fluid())
pil_dsps_desc.name = "dsps_fluid";
BUG_ON(platform_device_register(&pil_dsps));
- BUG_ON(msm_pil_register(&pil_dsps_desc));
+ BUG_ON(IS_ERR(msm_pil_register(&pil_dsps_desc)));
return 0;
}
-arch_initcall(msm_peripheral_reset_init);
+module_init(msm_peripheral_reset_init);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Validate and bring peripherals out of reset");
diff --git a/arch/arm/mach-msm/pil-gss.c b/arch/arm/mach-msm/pil-gss.c
index 26b97fa..c4477ff 100644
--- a/arch/arm/mach-msm/pil-gss.c
+++ b/arch/arm/mach-msm/pil-gss.c
@@ -64,6 +64,7 @@
unsigned long start_addr;
struct delayed_work work;
struct clk *xo;
+ struct pil_device *pil;
};
static int nop_verify_blob(struct pil_desc *pil, u32 phy_addr, size_t size)
@@ -329,7 +330,6 @@
struct gss_data *drv;
struct resource *res;
struct pil_desc *desc;
- int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -363,6 +363,7 @@
desc->name = "gss";
desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
if (pas_supported(PAS_GSS) > 0) {
desc->ops = &pil_gss_ops_trusted;
@@ -374,17 +375,19 @@
INIT_DELAYED_WORK(&drv->work, remove_gss_proxy_votes);
- ret = msm_pil_register(desc);
- if (ret) {
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil)) {
flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
+ return PTR_ERR(drv->pil);
}
- return ret;
+ return 0;
}
static int __devexit pil_gss_remove(struct platform_device *pdev)
{
struct gss_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
return 0;
diff --git a/arch/arm/mach-msm/pil-modem.c b/arch/arm/mach-msm/pil-modem.c
index 1d13508..a85d13c 100644
--- a/arch/arm/mach-msm/pil-modem.c
+++ b/arch/arm/mach-msm/pil-modem.c
@@ -53,6 +53,7 @@
struct modem_data {
void __iomem *base;
unsigned long start_addr;
+ struct pil_device *pil;
struct clk *xo;
struct delayed_work work;
};
@@ -277,7 +278,6 @@
struct modem_data *drv;
struct resource *res;
struct pil_desc *desc;
- int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -303,6 +303,7 @@
desc->name = "modem";
desc->depends_on = "q6";
desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
if (pas_supported(PAS_MODEM) > 0) {
desc->ops = &pil_modem_ops_trusted;
@@ -313,17 +314,19 @@
}
INIT_DELAYED_WORK(&drv->work, remove_modem_proxy_votes);
- ret = msm_pil_register(desc);
- if (ret) {
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil)) {
flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
+ return PTR_ERR(drv->pil);
}
- return ret;
+ return 0;
}
static int __devexit pil_modem_driver_exit(struct platform_device *pdev)
{
struct modem_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
return 0;
diff --git a/arch/arm/mach-msm/pil-q6v3.c b/arch/arm/mach-msm/pil-q6v3.c
index 06b98e5..54356b8 100644
--- a/arch/arm/mach-msm/pil-q6v3.c
+++ b/arch/arm/mach-msm/pil-q6v3.c
@@ -66,6 +66,7 @@
struct q6v3_data {
void __iomem *base;
unsigned long start_addr;
+ struct pil_device *pil;
struct clk *pll;
struct delayed_work work;
};
@@ -260,6 +261,7 @@
desc->name = "q6";
desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
if (pas_supported(PAS_Q6) > 0) {
desc->ops = &pil_q6v3_ops_trusted;
@@ -271,9 +273,10 @@
INIT_DELAYED_WORK(&drv->work, q6v3_remove_proxy_votes);
- if (msm_pil_register(desc)) {
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil)) {
flush_delayed_work_sync(&drv->work);
- return -EINVAL;
+ return PTR_ERR(drv->pil);
}
return 0;
}
@@ -281,6 +284,7 @@
static int __devexit pil_q6v3_driver_exit(struct platform_device *pdev)
{
struct q6v3_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
flush_delayed_work_sync(&drv->work);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-q6v4.c b/arch/arm/mach-msm/pil-q6v4.c
index b0bce02..17f5a41 100644
--- a/arch/arm/mach-msm/pil-q6v4.c
+++ b/arch/arm/mach-msm/pil-q6v4.c
@@ -71,6 +71,7 @@
bool vreg_enabled;
struct clk *xo;
struct delayed_work work;
+ struct pil_device *pil;
};
static int pil_q6v4_init_image(struct pil_desc *pil, const u8 *metadata,
@@ -421,6 +422,7 @@
desc->name = pdata->name;
desc->depends_on = pdata->depends;
desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
if (pas_supported(pdata->pas_id) > 0) {
desc->ops = &pil_q6v4_ops_trusted;
@@ -443,9 +445,11 @@
}
INIT_DELAYED_WORK(&drv->work, pil_q6v4_remove_proxy_votes);
- ret = msm_pil_register(desc);
- if (ret)
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil)) {
+ ret = PTR_ERR(drv->pil);
goto err_pil;
+ }
return 0;
err_pil:
flush_delayed_work_sync(&drv->work);
@@ -464,6 +468,7 @@
clk_put(drv->xo);
regulator_put(drv->vreg);
regulator_put(drv->pll_supply);
+ msm_pil_unregister(drv->pil);
return 0;
}
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index bd49fc0..198572c 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.c
@@ -86,6 +86,7 @@
bool use_cxo;
struct delayed_work work;
struct regulator *pll_supply;
+ struct pil_device *pil;
};
static int pil_riva_make_proxy_votes(struct device *dev)
@@ -390,6 +391,7 @@
desc->name = "wcnss";
desc->dev = &pdev->dev;
+ desc->owner = THIS_MODULE;
if (pas_supported(PAS_RIVA) > 0) {
desc->ops = &pil_riva_ops_trusted;
@@ -406,9 +408,11 @@
}
INIT_DELAYED_WORK(&drv->work, pil_riva_remove_proxy_votes);
- ret = msm_pil_register(desc);
- if (ret)
+ drv->pil = msm_pil_register(desc);
+ if (IS_ERR(drv->pil)) {
+ ret = PTR_ERR(drv->pil);
goto err_register;
+ }
return 0;
err_register:
flush_delayed_work_sync(&drv->work);
@@ -421,6 +425,7 @@
static int __devexit pil_riva_remove(struct platform_device *pdev)
{
struct riva_data *drv = platform_get_drvdata(pdev);
+ msm_pil_unregister(drv->pil);
flush_delayed_work_sync(&drv->work);
clk_put(drv->xo);
regulator_put(drv->pll_supply);
diff --git a/arch/arm/mach-msm/pil-tzapps.c b/arch/arm/mach-msm/pil-tzapps.c
index 90ac1d9..b6e5343e 100644
--- a/arch/arm/mach-msm/pil-tzapps.c
+++ b/arch/arm/mach-msm/pil-tzapps.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
@@ -50,6 +50,7 @@
static int __devinit pil_tzapps_driver_probe(struct platform_device *pdev)
{
struct pil_desc *desc;
+ struct pil_device *pil;
if (pas_supported(PAS_TZAPPS) < 0)
return -ENOSYS;
@@ -61,13 +62,18 @@
desc->name = "tzapps";
desc->dev = &pdev->dev;
desc->ops = &pil_tzapps_ops;
- if (msm_pil_register(desc))
- return -EINVAL;
+ desc->owner = THIS_MODULE;
+ pil = msm_pil_register(desc);
+ if (IS_ERR(pil))
+ return PTR_ERR(pil);
+ platform_set_drvdata(pdev, pil);
return 0;
}
static int __devexit pil_tzapps_driver_exit(struct platform_device *pdev)
{
+ struct pil_device *pil = platform_get_drvdata(pdev);
+ msm_pil_unregister(pil);
return 0;
}
diff --git a/arch/arm/mach-msm/platsmp-8625.c b/arch/arm/mach-msm/platsmp-8625.c
index 8081b45..3c46d0f 100644
--- a/arch/arm/mach-msm/platsmp-8625.c
+++ b/arch/arm/mach-msm/platsmp-8625.c
@@ -62,6 +62,10 @@
void __cpuinit platform_secondary_init(unsigned int cpu)
{
+ pr_debug("CPU%u: Booted secondary processor\n", cpu);
+
+ WARN_ON(msm_platform_secondary_init(cpu));
+
/*
* if any interrupts are already enabled for the primary
* core (e.g. timer irq), then they will not have been enabled
diff --git a/arch/arm/mach-msm/pm-boot.c b/arch/arm/mach-msm/pm-boot.c
index ce09f9f..f4536f7 100644
--- a/arch/arm/mach-msm/pm-boot.c
+++ b/arch/arm/mach-msm/pm-boot.c
@@ -101,6 +101,7 @@
int __init msm_pm_boot_init(struct msm_pm_boot_platform_data *pdata)
{
int ret = 0;
+ unsigned long entry;
switch (pdata->mode) {
case MSM_PM_BOOT_CONFIG_TZ:
@@ -130,15 +131,44 @@
if (!pdata->p_addr || !pdata->v_addr)
return -ENODEV;
- __raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
- pdata->v_addr);
-
ret = msm_pm_boot_reset_vector_init(__va(pdata->p_addr));
- msm_pm_boot_before_pc
- = msm_pm_config_rst_vector_before_pc;
- msm_pm_boot_after_pc
- = msm_pm_config_rst_vector_after_pc;
+ if (!cpu_is_msm8625()) {
+ __raw_writel((pdata->p_addr | BOOT_REMAP_ENABLE),
+ pdata->v_addr);
+
+ msm_pm_boot_before_pc
+ = msm_pm_config_rst_vector_before_pc;
+ msm_pm_boot_after_pc
+ = msm_pm_config_rst_vector_after_pc;
+ } else {
+ entry = virt_to_phys(msm_pm_boot_entry);
+
+ msm_pm_reset_vector[0] = 0xE51FF004; /* ldr pc, 4 */
+ msm_pm_reset_vector[1] = entry;
+
+ /* Here upper 16bits[16:31] used by CORE1
+ * lower 16bits[0:15] used by CORE0
+ */
+ entry = (pdata->p_addr) |
+ ((pdata->p_addr & 0xFFFF0000) >> 16);
+
+ /* write 'entry' to boot remapper register */
+ __raw_writel(entry, (pdata->v_addr +
+ MPA5_BOOT_REMAP_ADDR));
+
+ /* Enable boot remapper for C0 [bit:25th] */
+ __raw_writel(readl_relaxed(pdata->v_addr +
+ MPA5_CFG_CTL_REG) | BIT(25),
+ pdata->v_addr + MPA5_CFG_CTL_REG);
+
+ /* Enable boot remapper for C1 [bit:26th] */
+ __raw_writel(readl_relaxed(pdata->v_addr +
+ MPA5_CFG_CTL_REG) | BIT(26),
+ pdata->v_addr + MPA5_CFG_CTL_REG);
+
+ msm_pm_boot_before_pc = msm_pm_write_boot_vector;
+ }
break;
default:
__WARN();
diff --git a/arch/arm/mach-msm/pm-boot.h b/arch/arm/mach-msm/pm-boot.h
index 185d542..30b67c21 100644
--- a/arch/arm/mach-msm/pm-boot.h
+++ b/arch/arm/mach-msm/pm-boot.h
@@ -13,6 +13,11 @@
#ifndef _ARCH_ARM_MACH_MSM_PM_BOOT_H
#define _ARCH_ARM_MACH_MSM_PM_BOOT_H
+/* 8x25 specific macros */
+#define MPA5_CFG_CTL_REG 0x30
+#define MPA5_BOOT_REMAP_ADDR 0x34
+/* end */
+
enum {
MSM_PM_BOOT_CONFIG_TZ = 0,
MSM_PM_BOOT_CONFIG_RESET_VECTOR_PHYS = 1,
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 7977d22..4d63b6d 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -48,6 +48,7 @@
#ifdef CONFIG_MSM_MEMORY_LOW_POWER_MODE_SUSPEND_DEEP_POWER_DOWN
#include <mach/msm_migrate_pages.h>
#endif
+#include <mach/socinfo.h>
#include "smd_private.h"
#include "smd_rpcrouter.h"
@@ -68,13 +69,14 @@
*****************************************************************************/
enum {
- MSM_PM_DEBUG_SUSPEND = 1U << 0,
- MSM_PM_DEBUG_POWER_COLLAPSE = 1U << 1,
- MSM_PM_DEBUG_STATE = 1U << 2,
- MSM_PM_DEBUG_CLOCK = 1U << 3,
- MSM_PM_DEBUG_RESET_VECTOR = 1U << 4,
- MSM_PM_DEBUG_SMSM_STATE = 1U << 5,
- MSM_PM_DEBUG_IDLE = 1U << 6,
+ MSM_PM_DEBUG_SUSPEND = BIT(0),
+ MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
+ MSM_PM_DEBUG_STATE = BIT(2),
+ MSM_PM_DEBUG_CLOCK = BIT(3),
+ MSM_PM_DEBUG_RESET_VECTOR = BIT(4),
+ MSM_PM_DEBUG_SMSM_STATE = BIT(5),
+ MSM_PM_DEBUG_IDLE = BIT(6),
+ MSM_PM_DEBUG_HOTPLUG = BIT(7),
};
static int msm_pm_debug_mask;
@@ -142,7 +144,6 @@
static char *msm_pm_sleep_mode_labels[MSM_PM_SLEEP_MODE_NR] = {
[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_SUSPEND] = " ",
[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = "power_collapse",
- [MSM_PM_SLEEP_MODE_APPS_SLEEP] = "apps_sleep",
[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT] =
"ramp_down_and_wfi",
[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT] = "wfi",
@@ -682,8 +683,6 @@
MSM_PM_STAT_IDLE_WFI,
MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE,
MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE,
- MSM_PM_STAT_IDLE_SLEEP,
- MSM_PM_STAT_IDLE_FAILED_SLEEP,
MSM_PM_STAT_IDLE_POWER_COLLAPSE,
MSM_PM_STAT_IDLE_FAILED_POWER_COLLAPSE,
MSM_PM_STAT_SUSPEND,
@@ -1008,6 +1007,13 @@
memset(msm_pm_smem_data, 0, sizeof(*msm_pm_smem_data));
+ if (cpu_is_msm8625()) {
+ /* Program the SPM */
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE,
+ false);
+ WARN_ON(ret);
+ }
+
msm_irq_enter_sleep1(true, from_idle, &msm_pm_smem_data->irq_mask);
msm_sirc_enter_sleep();
msm_gpio_enter_sleep(from_idle);
@@ -1210,6 +1216,13 @@
MSM_PM_DEBUG_PRINT_STATE("msm_pm_power_collapse(): RUN");
smd_sleep_exit();
+
+ if (cpu_is_msm8625()) {
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+ false);
+ WARN_ON(ret);
+ }
+
return 0;
power_collapse_early_exit:
@@ -1263,6 +1276,12 @@
smd_sleep_exit();
power_collapse_bail:
+ if (cpu_is_msm8625()) {
+ ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_CLOCK_GATING,
+ false);
+ WARN_ON(ret);
+ }
+
return ret;
}
@@ -1272,10 +1291,11 @@
* Return value:
* 0: success
*/
-static int msm_pm_power_collapse_standalone(void)
+static int msm_pm_power_collapse_standalone(bool from_idle)
{
int collapsed = 0;
int ret;
+ void *entry;
MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
KERN_INFO, "%s()\n", __func__);
@@ -1283,21 +1303,26 @@
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_COLLAPSE, false);
WARN_ON(ret);
+ entry = (!smp_processor_id() || from_idle) ?
+ msm_pm_collapse_exit : msm_secondary_startup;
+
msm_pm_boot_config_before_pc(smp_processor_id(),
- virt_to_phys(msm_pm_collapse_exit));
+ virt_to_phys(entry));
#ifdef CONFIG_VFP
vfp_flush_context();
#endif
#ifdef CONFIG_CACHE_L2X0
- l2x0_suspend();
+ if (!cpu_is_msm8625())
+ l2x0_suspend();
#endif
collapsed = msm_pm_collapse();
#ifdef CONFIG_CACHE_L2X0
- l2x0_resume(collapsed);
+ if (!cpu_is_msm8625())
+ l2x0_resume(collapsed);
#endif
msm_pm_boot_config_after_pc(smp_processor_id());
@@ -1321,18 +1346,6 @@
}
/*
- * Apps-sleep the Apps processor. This function execute the handshake
- * protocol with Modem.
- *
- * Return value:
- * -ENOSYS: function not implemented yet
- */
-static int msm_pm_apps_sleep(uint32_t sleep_delay, uint32_t sleep_limit)
-{
- return -ENOSYS;
-}
-
-/*
* Bring the Apps processor to SWFI.
*
* Return value:
@@ -1353,7 +1366,9 @@
return -EIO;
}
- msm_pm_config_hw_before_swfi();
+ if (!cpu_is_msm8625())
+ msm_pm_config_hw_before_swfi();
+
msm_arch_idle();
if (ramp_acpu) {
@@ -1395,7 +1410,7 @@
int64_t t1;
static int64_t t2;
int exit_stat;
- #endif /* CONFIG_MSM_IDLE_STATS */
+ #endif
if (!atomic_read(&msm_pm_init_done))
return;
@@ -1412,19 +1427,19 @@
exit_stat = MSM_PM_STAT_IDLE_SPIN;
low_power = 0;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
for (i = 0; i < ARRAY_SIZE(allow); i++)
allow[i] = true;
- if ((timer_expiration < msm_pm_idle_sleep_min_time) ||
+ if (num_online_cpus() > 1 ||
+ (timer_expiration < msm_pm_idle_sleep_min_time) ||
#ifdef CONFIG_HAS_WAKELOCK
has_wake_lock(WAKE_LOCK_IDLE) ||
#endif
!msm_irq_idle_sleep_allowed()) {
allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] = false;
allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN] = false;
- allow[MSM_PM_SLEEP_MODE_APPS_SLEEP] = false;
}
for (i = 0; i < ARRAY_SIZE(allow); i++) {
@@ -1493,32 +1508,15 @@
exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
msm_pm_sleep_limit = sleep_limit;
}
-#endif /* CONFIG_MSM_IDLE_STATS */
- } else if (allow[MSM_PM_SLEEP_MODE_APPS_SLEEP]) {
- uint32_t sleep_delay;
-
- sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
- timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
- if (sleep_delay == 0) /* 0 would mean infinite time */
- sleep_delay = 1;
-
- ret = msm_pm_apps_sleep(sleep_delay, sleep_limit);
- low_power = 0;
-
-#ifdef CONFIG_MSM_IDLE_STATS
- if (ret)
- exit_stat = MSM_PM_STAT_IDLE_FAILED_SLEEP;
- else
- exit_stat = MSM_PM_STAT_IDLE_SLEEP;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
- ret = msm_pm_power_collapse_standalone();
+ ret = msm_pm_power_collapse_standalone(true);
low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = ret ?
MSM_PM_STAT_IDLE_FAILED_STANDALONE_POWER_COLLAPSE :
MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
ret = msm_pm_swfi(true);
if (ret)
@@ -1527,20 +1525,20 @@
low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = ret ? MSM_PM_STAT_IDLE_SPIN : MSM_PM_STAT_IDLE_WFI;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
msm_pm_swfi(false);
low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_WFI;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
} else {
while (!msm_irq_pending())
udelay(1);
low_power = 0;
#ifdef CONFIG_MSM_IDLE_STATS
exit_stat = MSM_PM_STAT_IDLE_SPIN;
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
}
msm_timer_exit_idle(low_power);
@@ -1548,13 +1546,14 @@
#ifdef CONFIG_MSM_IDLE_STATS
t2 = ktime_to_ns(ktime_get());
msm_pm_add_stat(exit_stat, t2 - t1);
-#endif /* CONFIG_MSM_IDLE_STATS */
+#endif
}
/*
* Suspend the Apps processor.
*
* Return value:
+ * -EPERM: Suspend happened by a not permitted core
* -EAGAIN: modem reset occurred or early exit from suspend
* -EBUSY: modem not ready for our suspend
* -EINVAL: invalid sleep mode
@@ -1566,13 +1565,20 @@
{
bool allow[MSM_PM_SLEEP_MODE_NR];
uint32_t sleep_limit = SLEEP_LIMIT_NONE;
- int ret;
+ int ret = -EPERM;
int i;
-
#ifdef CONFIG_MSM_IDLE_STATS
int64_t period = 0;
int64_t time = 0;
+#endif
+ /* Must executed by CORE0 */
+ if (smp_processor_id()) {
+ __WARN();
+ goto suspend_exit;
+ }
+
+#ifdef CONFIG_MSM_IDLE_STATS
time = msm_timer_get_sclk_time(&period);
#endif
@@ -1589,8 +1595,6 @@
allow[i] = false;
}
- ret = 0;
-
if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE] ||
allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_NO_XO_SHUTDOWN]) {
#ifdef CONFIG_MSM_IDLE_STATS
@@ -1647,7 +1651,7 @@
msm_pm_add_stat(id, time);
#endif
} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
- ret = msm_pm_power_collapse_standalone();
+ ret = msm_pm_power_collapse_standalone(false);
} else if (allow[MSM_PM_SLEEP_MODE_RAMP_DOWN_AND_WAIT_FOR_INTERRUPT]) {
ret = msm_pm_swfi(true);
if (ret)
@@ -1657,6 +1661,7 @@
msm_pm_swfi(false);
}
+suspend_exit:
MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND, KERN_INFO,
"%s(): return %d\n", __func__, ret);
@@ -1673,7 +1678,27 @@
*/
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
{
- return;
+ bool allow[MSM_PM_SLEEP_MODE_NR];
+ int i;
+
+ for (i = 0; i < MSM_PM_SLEEP_MODE_NR; i++) {
+ struct msm_pm_platform_data *mode;
+
+ mode = &msm_pm_modes[MSM_PM_MODE(cpu, i)];
+ allow[i] = mode->suspend_supported && mode->suspend_enabled;
+ }
+
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
+ "CPU%u: %s: shutting down cpu\n", cpu, __func__);
+
+ if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+ msm_pm_power_collapse_standalone(false);
+ } else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+ msm_pm_swfi(false);
+ } else {
+ MSM_PM_DPRINTK(MSM_PM_DEBUG_HOTPLUG, KERN_INFO,
+ "CPU%u: %s: shutting down failed!!!\n", cpu, __func__);
+ }
}
/******************************************************************************
@@ -1725,10 +1750,6 @@
};
-/******************************************************************************
- *
- *****************************************************************************/
-
/*
* Initialize the power management subsystem.
*
@@ -1748,6 +1769,8 @@
pmd_t *pmd;
unsigned long pmdval;
+ if (cpu_is_msm8625())
+ return 0;
/* Page table for cores to come back up safely. */
pc_pgd = pgd_alloc(&init_mm);
if (!pc_pgd)
@@ -1837,15 +1860,6 @@
first_bucket_time =
CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
- stats[MSM_PM_STAT_IDLE_SLEEP].name = "idle-sleep";
- stats[MSM_PM_STAT_IDLE_SLEEP].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
- stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].name =
- "idle-failed-sleep";
- stats[MSM_PM_STAT_IDLE_FAILED_SLEEP].first_bucket_time =
- CONFIG_MSM_IDLE_STATS_FIRST_BUCKET;
-
stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].name =
"idle-power-collapse";
stats[MSM_PM_STAT_IDLE_POWER_COLLAPSE].first_bucket_time =
diff --git a/arch/arm/mach-msm/qdsp5/audio_voicememo.c b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
index 7a962b2..2011c42 100644
--- a/arch/arm/mach-msm/qdsp5/audio_voicememo.c
+++ b/arch/arm/mach-msm/qdsp5/audio_voicememo.c
@@ -4,7 +4,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 code is based in part on arch/arm/mach-msm/qdsp5/audio_mp3.c
*
@@ -836,6 +836,7 @@
file->private_data = audio;
audio->opened = 1;
+ audio->stopped = 0;
rc = 0;
done:
mutex_unlock(&audio->lock);
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.c b/arch/arm/mach-msm/qdsp5v2/adsp.c
index b7b56c8..acd9c4c 100644
--- a/arch/arm/mach-msm/qdsp5v2/adsp.c
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.c
@@ -2,7 +2,7 @@
* Register/Interrupt access for userspace aDSP library.
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2008-2009,2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2009,2011-2012 Code Aurora Forum. All rights reserved.
* Author: Iliyan Malchev <ibm@android.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -46,8 +46,6 @@
static int wdump, rdump;
#endif /* CONFIG_DEBUG_FS */
-#define INT_ADSP INT_ADSP_A9_A11
-
static struct adsp_info adsp_info;
static struct msm_adsp_module *adsp_modules;
static int adsp_open_count;
@@ -889,7 +887,7 @@
mutex_lock(&adsp_open_lock);
if (adsp_open_count++ == 0)
- enable_irq(INT_ADSP);
+ enable_irq(adsp_info.int_adsp);
mutex_unlock(&adsp_open_lock);
break;
case ADSP_STATE_ENABLING:
@@ -944,7 +942,7 @@
mutex_unlock(&module->lock);
mutex_lock(&adsp_open_lock);
if (--adsp_open_count == 0) {
- disable_irq(INT_ADSP);
+ disable_irq(adsp_info.int_adsp);
MM_INFO("disable interrupt\n");
}
mutex_unlock(&adsp_open_lock);
@@ -959,6 +957,12 @@
unsigned count;
int rc, i;
+ adsp_info.int_adsp = platform_get_irq(pdev, 0);
+ if (adsp_info.int_adsp < 0) {
+ MM_ERR("no irq resource?\n");
+ return -ENODEV;
+ }
+
adsp_info.init_info_ptr = kzalloc(
(sizeof(struct adsp_rtos_mp_mtoa_init_info_type)), GFP_KERNEL);
if (!adsp_info.init_info_ptr)
@@ -996,11 +1000,11 @@
spin_lock_init(&adsp_cmd_lock);
spin_lock_init(&adsp_write_lock);
- rc = request_irq(INT_ADSP, adsp_irq_handler,
+ rc = request_irq(adsp_info.int_adsp, adsp_irq_handler,
IRQF_TRIGGER_RISING, "adsp", 0);
if (rc < 0)
goto fail_request_irq;
- disable_irq(INT_ADSP);
+ disable_irq(adsp_info.int_adsp);
for (i = 0; i < count; i++) {
struct msm_adsp_module *mod = adsp_modules + i;
@@ -1056,8 +1060,8 @@
daldevice_detach(adsp_info.handle);
adsp_info.handle = NULL;
fail_dal_attach:
- enable_irq(INT_ADSP);
- free_irq(INT_ADSP, 0);
+ enable_irq(adsp_info.int_adsp);
+ free_irq(adsp_info.int_adsp, 0);
fail_request_irq:
kfree(adsp_modules);
kfree(adsp_info.init_info_ptr);
@@ -1187,11 +1191,6 @@
},
};
-struct platform_device msm_adsp_device = {
- .name = "msm_adsp",
- .id = -1,
-};
-
static char msm_adsp_driver_name[] = "msm_adsp";
#ifdef CONFIG_DEBUG_FS
@@ -1218,7 +1217,6 @@
#endif /* CONFIG_DEBUG_FS */
msm_adsp_driver.driver.name = msm_adsp_driver_name;
- rc = platform_device_register(&msm_adsp_device);
rc = platform_driver_register(&msm_adsp_driver);
MM_INFO("%s -- %d\n", msm_adsp_driver_name, rc);
return rc;
diff --git a/arch/arm/mach-msm/qdsp5v2/adsp.h b/arch/arm/mach-msm/qdsp5v2/adsp.h
index 18f4046..5aceff9 100644
--- a/arch/arm/mach-msm/qdsp5v2/adsp.h
+++ b/arch/arm/mach-msm/qdsp5v2/adsp.h
@@ -229,6 +229,9 @@
void *handle;
void *cb_handle;
+
+ /* Interrupt value */
+ int int_adsp;
};
#define ADSP_STATE_DISABLED 0
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index ce5d084..9b03985 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -15,7 +15,7 @@
#include <linux/miscdevice.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
-#include <linux/android_pmem.h>
+#include <linux/ion.h>
#include <linux/mm.h>
#include <mach/qdsp6v2/audio_acdb.h>
@@ -62,13 +62,13 @@
/* Sidetone Cal */
struct sidetone_atomic_cal sidetone_cal;
- /* PMEM information */
- atomic_t pmem_fd;
+ /* Allocation information */
+ struct ion_client *ion_client;
+ struct ion_handle *ion_handle;
+ atomic_t map_handle;
atomic64_t paddr;
atomic64_t kvaddr;
- atomic64_t pmem_len;
- struct file *file;
-
+ atomic64_t mem_len;
};
static struct acdb_data acdb_data;
@@ -200,10 +200,10 @@
{
pr_debug("%s,\n", __func__);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
goto done;
}
@@ -221,10 +221,10 @@
{
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
goto done;
}
if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
@@ -271,10 +271,10 @@
{
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
@@ -321,10 +321,10 @@
{
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
@@ -371,10 +371,10 @@
{
pr_debug("%s, path = %d\n", __func__, path);
- if (cal_block->cal_offset > atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_block->cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
goto done;
}
if (path >= MAX_AUDPROC_TYPES) {
@@ -432,10 +432,10 @@
atomic_set(&acdb_data.vocproc_total_cal_size, 0);
for (i = 0; i < len; i++) {
if (cal_blocks[i].cal_offset >
- atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_blocks[i].cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
atomic_set(&acdb_data.vocproc_cal[i].cal_size, 0);
} else {
atomic_add(cal_blocks[i].cal_size,
@@ -484,10 +484,10 @@
atomic_set(&acdb_data.vocstrm_total_cal_size, 0);
for (i = 0; i < len; i++) {
if (cal_blocks[i].cal_offset >
- atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_blocks[i].cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
atomic_set(&acdb_data.vocstrm_cal[i].cal_size, 0);
} else {
atomic_add(cal_blocks[i].cal_size,
@@ -536,10 +536,10 @@
atomic_set(&acdb_data.vocvol_total_cal_size, 0);
for (i = 0; i < len; i++) {
if (cal_blocks[i].cal_offset >
- atomic64_read(&acdb_data.pmem_len)) {
- pr_err("%s: offset %d is > pmem_len %ld\n",
+ atomic64_read(&acdb_data.mem_len)) {
+ pr_err("%s: offset %d is > mem_len %ld\n",
__func__, cal_blocks[i].cal_offset,
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
atomic_set(&acdb_data.vocvol_cal[i].cal_size, 0);
} else {
atomic_add(cal_blocks[i].cal_size,
@@ -603,8 +603,9 @@
s32 result = 0;
pr_debug("%s\n", __func__);
- if (atomic_read(&acdb_data.pmem_fd)) {
- pr_debug("%s: ACDB opened but PMEM allocated, using existing PMEM!\n",
+ if (atomic64_read(&acdb_data.mem_len)) {
+ pr_debug("%s: ACDB opened but memory allocated, "
+ "using existing allocation!\n",
__func__);
}
@@ -612,46 +613,74 @@
return result;
}
-static int deregister_pmem(void)
+static int deregister_memory(void)
{
- if (atomic_read(&acdb_data.pmem_fd)) {
+ if (atomic64_read(&acdb_data.mem_len)) {
mutex_lock(&acdb_data.acdb_mutex);
- put_pmem_file(acdb_data.file);
+ ion_unmap_kernel(acdb_data.ion_client, acdb_data.ion_handle);
+ ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+ ion_client_destroy(acdb_data.ion_client);
mutex_unlock(&acdb_data.acdb_mutex);
- atomic_set(&acdb_data.pmem_fd, 0);
+ atomic64_set(&acdb_data.mem_len, 0);
}
return 0;
}
-static int register_pmem(void)
+static int register_memory(void)
{
- int result;
- unsigned long paddr;
- unsigned long kvaddr;
- unsigned long pmem_len;
+ int result;
+ unsigned long paddr;
+ unsigned long kvaddr;
+ unsigned long mem_len;
mutex_lock(&acdb_data.acdb_mutex);
- result = get_pmem_file(atomic_read(&acdb_data.pmem_fd),
- &paddr, &kvaddr, &pmem_len,
- &acdb_data.file);
- mutex_unlock(&acdb_data.acdb_mutex);
- if (result != 0) {
- atomic_set(&acdb_data.pmem_fd, 0);
- atomic64_set(&acdb_data.pmem_len, 0);
- pr_err("%s: Could not register PMEM!!!\n", __func__);
- goto done;
+ acdb_data.ion_client =
+ msm_ion_client_create(UINT_MAX, "audio_acdb_client");
+ if (IS_ERR_OR_NULL(acdb_data.ion_client)) {
+ pr_err("%s: Could not register ION client!!!\n", __func__);
+ goto err;
}
+ acdb_data.ion_handle = ion_import_fd(acdb_data.ion_client,
+ atomic_read(&acdb_data.map_handle));
+ if (IS_ERR_OR_NULL(acdb_data.ion_handle)) {
+ pr_err("%s: Could not import map handle!!!\n", __func__);
+ goto err_ion_client;
+ }
+
+ result = ion_phys(acdb_data.ion_client, acdb_data.ion_handle,
+ &paddr, (size_t *)&mem_len);
+ if (result != 0) {
+ pr_err("%s: Could not get phys addr!!!\n", __func__);
+ goto err_ion_handle;
+ }
+
+ kvaddr = (unsigned long)ion_map_kernel(acdb_data.ion_client,
+ acdb_data.ion_handle, 0);
+ if (IS_ERR_OR_NULL(&kvaddr)) {
+ pr_err("%s: Could not get kernel virt addr!!!\n", __func__);
+ goto err_ion_handle;
+ }
+ mutex_unlock(&acdb_data.acdb_mutex);
+
atomic64_set(&acdb_data.paddr, paddr);
atomic64_set(&acdb_data.kvaddr, kvaddr);
- atomic64_set(&acdb_data.pmem_len, pmem_len);
- pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
+ atomic64_set(&acdb_data.mem_len, mem_len);
+ pr_debug("%s done! paddr = 0x%lx, "
"kvaddr = 0x%lx, len = x%lx\n",
+ __func__,
(long)atomic64_read(&acdb_data.paddr),
(long)atomic64_read(&acdb_data.kvaddr),
- (long)atomic64_read(&acdb_data.pmem_len));
+ (long)atomic64_read(&acdb_data.mem_len));
-done:
+ return result;
+err_ion_handle:
+ ion_free(acdb_data.ion_client, acdb_data.ion_handle);
+err_ion_client:
+ ion_client_destroy(acdb_data.ion_client);
+err:
+ atomic64_set(&acdb_data.mem_len, 0);
+ mutex_unlock(&acdb_data.acdb_mutex);
return result;
}
static long acdb_ioctl(struct file *f,
@@ -659,7 +688,7 @@
{
int32_t result = 0;
int32_t size;
- int32_t pmem_fd;
+ int32_t map_fd;
uint32_t topology;
struct cal_block data[MAX_NETWORKS];
pr_debug("%s\n", __func__);
@@ -667,23 +696,23 @@
switch (cmd) {
case AUDIO_REGISTER_PMEM:
pr_debug("AUDIO_REGISTER_PMEM\n");
- if (atomic_read(&acdb_data.pmem_fd)) {
- deregister_pmem();
- pr_debug("Remove the existing PMEM\n");
+ if (atomic_read(&acdb_data.mem_len)) {
+ deregister_memory();
+ pr_debug("Remove the existing memory\n");
}
- if (copy_from_user(&pmem_fd, (void *)arg, sizeof(pmem_fd))) {
- pr_err("%s: fail to copy pmem handle!\n", __func__);
+ if (copy_from_user(&map_fd, (void *)arg, sizeof(map_fd))) {
+ pr_err("%s: fail to copy memory handle!\n", __func__);
result = -EFAULT;
} else {
- atomic_set(&acdb_data.pmem_fd, pmem_fd);
- result = register_pmem();
+ atomic_set(&acdb_data.map_handle, map_fd);
+ result = register_memory();
}
goto done;
case AUDIO_DEREGISTER_PMEM:
pr_debug("AUDIO_DEREGISTER_PMEM\n");
- deregister_pmem();
+ deregister_memory();
goto done;
case AUDIO_SET_VOICE_RX_TOPOLOGY:
if (copy_from_user(&topology, (void *)arg,
@@ -835,8 +864,8 @@
pr_debug("%s\n", __func__);
- if (atomic_read(&acdb_data.pmem_fd)) {
- if (size <= atomic64_read(&acdb_data.pmem_len)) {
+ if (atomic64_read(&acdb_data.mem_len)) {
+ if (size <= atomic64_read(&acdb_data.mem_len)) {
vma->vm_page_prot = pgprot_noncached(
vma->vm_page_prot);
result = remap_pfn_range(vma,
@@ -845,11 +874,11 @@
size,
vma->vm_page_prot);
} else {
- pr_err("%s: Not enough PMEM memory!\n", __func__);
+ pr_err("%s: Not enough memory!\n", __func__);
result = -ENOMEM;
}
} else {
- pr_err("%s: PMEM is not allocated, yet!\n", __func__);
+ pr_err("%s: memory is not allocated, yet!\n", __func__);
result = -ENODEV;
}
@@ -869,7 +898,7 @@
if (atomic_read(&usage_count) >= 1)
result = -EBUSY;
else
- result = deregister_pmem();
+ result = deregister_memory();
return result;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
index 0a5acce..aaae776 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/sched.h>
+#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <mach/qdsp6v2/audio_dev_ctl.h>
@@ -31,6 +32,9 @@
static DEFINE_MUTEX(session_lock);
+static struct workqueue_struct *msm_reset_device_work_queue;
+static void reset_device_work(struct work_struct *work);
+static DECLARE_WORK(msm_reset_device_work, reset_device_work);
struct audio_dev_ctrl_state {
struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
@@ -119,6 +123,18 @@
}
EXPORT_SYMBOL(msm_reset_all_device);
+static void reset_device_work(struct work_struct *work)
+{
+ msm_reset_all_device();
+}
+
+int reset_device(void)
+{
+ queue_work(msm_reset_device_work_queue, &msm_reset_device_work);
+ return 0;
+}
+EXPORT_SYMBOL(reset_device);
+
int msm_set_copp_id(int session_id, int copp_id)
{
int rc = 0;
@@ -1686,7 +1702,9 @@
init_waitqueue_head(&audio_dev_ctrl.wait);
event.cb = NULL;
-
+ msm_reset_device_work_queue = create_workqueue("reset_device");
+ if (msm_reset_device_work_queue == NULL)
+ return -ENOMEM;
atomic_set(&audio_dev_ctrl.opened, 0);
audio_dev_ctrl.num_dev = 0;
audio_dev_ctrl.voice_tx_dev = NULL;
@@ -1704,6 +1722,7 @@
static void __exit audio_dev_ctrl_exit(void)
{
+ destroy_workqueue(msm_reset_device_work_queue);
}
module_init(audio_dev_ctrl_init);
module_exit(audio_dev_ctrl_exit);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
index 599198e..41a7387 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -28,8 +28,8 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/earlysuspend.h>
+#include <linux/ion.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
#include <asm/atomic.h>
#include <asm/ioctls.h>
@@ -88,10 +88,10 @@
int event_type;
union msm_audio_event_payload payload;
};
-
-struct audlpa_pmem_region {
+struct audlpa_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
+ struct ion_client *client;
int fd;
void *vaddr;
unsigned long paddr;
@@ -115,12 +115,13 @@
static void audlpa_post_event(struct audio *audio, int type,
union msm_audio_event_payload payload);
-static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
unsigned long len, int ref_up);
+static void audlpa_unmap_ion_region(struct audio *audio);
static void audlpa_async_send_data(struct audio *audio, unsigned needed,
uint32_t token);
static int audlpa_pause(struct audio *audio);
-static void audlpa_unmap_pmem_region(struct audio *audio);
static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static int audlpa_set_pcm_params(void *data);
@@ -422,7 +423,7 @@
drv_evt->event_type == AUDIO_EVENT_READ_DONE)) {
pr_debug("%s: AUDIO_EVENT_WRITE_DONE completing\n", __func__);
mutex_lock(&audio->lock);
- audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audlpa_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0);
mutex_unlock(&audio->lock);
}
@@ -432,38 +433,41 @@
return rc;
}
-static int audlpa_pmem_check(struct audio *audio,
- void *vaddr, unsigned long len)
+static int audlpa_ion_check(struct audio *audio,
+ void *vaddr, unsigned long len)
{
- struct audlpa_pmem_region *region_elt;
- struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+ struct audlpa_ion_region *region_elt;
+ struct audlpa_ion_region t = {.vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
- pr_err("%s: region (vaddr %p len %ld)"
- " clashes with registered region"
- " (vaddr %p paddr %p len %ld)\n",
- __func__, vaddr, len,
- region_elt->vaddr,
- (void *)region_elt->paddr,
- region_elt->len);
+ pr_err("%s[%p]:region (vaddr %p len %ld)"
+ " clashes with registered region"
+ " (vaddr %p paddr %p len %ld)\n",
+ __func__, audio, vaddr, len,
+ region_elt->vaddr,
+ (void *)region_elt->paddr, region_elt->len);
return -EINVAL;
}
}
return 0;
}
-
-static int audlpa_pmem_add(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_add(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audlpa_pmem_region *region;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audlpa_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ struct ion_client *client;
+ unsigned long ionflag;
+ void *temp_ptr;
- pr_debug("%s:\n", __func__);
+ pr_debug("%s[%p]:\n", __func__, audio);
region = kmalloc(sizeof(*region), GFP_KERNEL);
if (!region) {
@@ -471,61 +475,105 @@
goto end;
}
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- goto end;
+ client = msm_ion_client_create(UINT_MAX, "Audio_LPA_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
+ goto client_error;
}
- rc = audlpa_pmem_check(audio, info->vaddr, len);
+ handle = ion_import_fd(client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
+ }
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+
+ temp_ptr = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR_OR_NULL(temp_ptr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ kvaddr = (unsigned long) temp_ptr;
+
+ rc = ion_phys(client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+
+ rc = audlpa_ion_check(audio, info->vaddr, len);
if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- goto end;
+ pr_err("%s: audlpa_ion_check failed\n", __func__);
+ goto ion_error;
}
+ region->client = client;
+ region->handle = handle;
region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
- pr_debug("%s: add region paddr %lx vaddr %p, len %lu\n", __func__,
- region->paddr, region->vaddr,
- region->len);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
+ pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+ __func__, audio,
+ region->paddr, region->vaddr, region->len, region->kvaddr);
+ list_add_tail(®ion->list, &audio->ion_region_queue);
+
rc = q6asm_memory_map(audio->ac, (uint32_t)paddr, IN, (uint32_t)len, 1);
- if (rc < 0)
- pr_err("%s: memory map failed\n", __func__);
+ if (rc < 0) {
+ pr_err("%s[%p]: memory map failed\n", __func__, audio);
+ goto ion_error;
+ } else {
+ goto end;
+ }
+
+ion_error:
+ ion_unmap_kernel(client, handle);
+map_error:
+ ion_free(client, handle);
+flag_error:
+import_error:
+ ion_client_destroy(client);
+client_error:
+ kfree(region);
end:
return rc;
}
-static int audlpa_pmem_remove(struct audio *audio,
- struct msm_audio_pmem_info *info)
+static int audlpa_ion_remove(struct audio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
- if ((region != NULL) && (region->fd == info->fd) &&
- (region->vaddr == info->vaddr)) {
+ if (region != NULL && (region->fd == info->fd) &&
+ (region->vaddr == info->vaddr)) {
if (region->ref_cnt) {
- pr_debug("%s: region %p in use ref_cnt %d\n",
- __func__, region, region->ref_cnt);
+ pr_debug("%s[%p]:region %p in use ref_cnt %d\n",
+ __func__, audio, region,
+ region->ref_cnt);
break;
}
rc = q6asm_memory_unmap(audio->ac,
- (uint32_t)region->paddr,
- IN);
+ (uint32_t) region->paddr, IN);
if (rc < 0)
- pr_err("%s: memory unmap failed\n", __func__);
+ pr_err("%s[%p]: memory unmap failed\n",
+ __func__, audio);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(region->client, region->handle);
+ ion_free(region->client, region->handle);
+ ion_client_destroy(region->client);
kfree(region);
rc = 0;
break;
@@ -535,24 +583,21 @@
return rc;
}
-static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
- unsigned long len, struct audlpa_pmem_region **region)
+static int audlpa_ion_lookup_vaddr(struct audio *audio, void *addr,
+ unsigned long len, struct audlpa_ion_region **region)
{
- struct audlpa_pmem_region *region_elt;
-
+ struct audlpa_ion_region *region_elt;
int match_count = 0;
-
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
- list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
- addr < region_elt->vaddr + region_elt->len &&
- addr + len <= region_elt->vaddr + region_elt->len) {
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
- */
+ * ion buffer
+ */
match_count++;
if (!*region)
@@ -561,32 +606,33 @@
}
if (match_count > 1) {
- pr_err("%s: multiple hits for vaddr %p, len %ld\n", __func__,
- addr, len);
- list_for_each_entry(region_elt,
- &audio->pmem_region_queue, list) {
- if (addr >= region_elt->vaddr &&
- addr < region_elt->vaddr + region_elt->len &&
- addr + len <= region_elt->vaddr + region_elt->len)
- pr_err("%s: \t%p, %ld --> %p\n", __func__,
- region_elt->vaddr, region_elt->len,
- (void *)region_elt->paddr);
+ pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
+ __func__, audio, addr, len);
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
+ list) {
+ if (addr >= region_elt->vaddr &&
+ addr < region_elt->vaddr + region_elt->len &&
+ addr + len <= region_elt->vaddr + region_elt->len)
+ pr_err("\t%s[%p]:%p, %ld --> %p\n",
+ __func__, audio,
+ region_elt->vaddr,
+ region_elt->len,
+ (void *)region_elt->paddr);
}
}
-
return *region ? 0 : -1;
}
-
-unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
- unsigned long len, int ref_up)
+static unsigned long audlpa_ion_fixup(struct audio *audio, void *addr,
+ unsigned long len, int ref_up)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
unsigned long paddr;
int ret;
- ret = audlpa_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audlpa_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
- pr_err("%s: lookup (%p, %ld) failed\n", __func__, addr, len);
+ pr_err("%s[%p]:lookup (%p, %ld) failed\n",
+ __func__, audio, addr, len);
return 0;
}
if (ref_up)
@@ -613,7 +659,7 @@
return -EFAULT;
}
- buf_node->paddr = audlpa_pmem_fixup(
+ buf_node->paddr = audlpa_ion_fixup(
audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1);
if (dir) {
@@ -669,6 +715,9 @@
break;
case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
break;
+ case RESET_EVENTS:
+ reset_device();
+ break;
default:
break;
}
@@ -918,25 +967,26 @@
}
break;
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- pr_debug("%s: AUDIO_REGISTER_PMEM\n", __func__);
- if (copy_from_user(&info, (void *) arg, sizeof(info)))
- rc = -EFAULT;
- else
- rc = audlpa_pmem_add(audio, &info);
- break;
- }
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ pr_debug("%s: AUDIO_REGISTER_ION\n", __func__);
+ if (copy_from_user(&info, (void *)arg, sizeof(info)))
+ rc = -EFAULT;
+ else
+ rc = audlpa_ion_add(audio, &info);
+ break;
+ }
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- pr_debug("%s: AUDIO_DEREGISTER_PMEM\n", __func__);
- if (copy_from_user(&info, (void *) arg, sizeof(info)))
- rc = -EFAULT;
- else
- rc = audlpa_pmem_remove(audio, &info);
- break;
- }
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
+ pr_debug("%s: AUDIO_DEREGISTER_ION\n", __func__);
+ if (copy_from_user(&info, (void *)arg, sizeof(info)))
+ rc = -EFAULT;
+ else
+ rc = audlpa_ion_remove(audio, &info);
+ break;
+ }
+
case AUDIO_ASYNC_WRITE:
pr_debug("%s: AUDIO_ASYNC_WRITE\n", __func__);
if (audio->drv_status & ADRV_STATUS_FSYNC)
@@ -1035,34 +1085,37 @@
return audlpa_async_fsync(audio);
}
-static void audlpa_reset_pmem_region(struct audio *audio)
+void audlpa_reset_ion_region(struct audio *audio)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(region->client, region->handle);
+ ion_free(region->client, region->handle);
+ ion_client_destroy(region->client);
kfree(region);
}
return;
}
-static void audlpa_unmap_pmem_region(struct audio *audio)
+static void audlpa_unmap_ion_region(struct audio *audio)
{
- struct audlpa_pmem_region *region;
+ struct audlpa_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
- pr_debug("%s:\n", __func__);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audlpa_pmem_region, list);
- pr_debug("%s: phy_address = 0x%lx\n", __func__, region->paddr);
+ pr_debug("%s[%p]:\n", __func__, audio);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audlpa_ion_region, list);
+ pr_debug("%s[%p]: phy_address = 0x%lx\n",
+ __func__, audio, region->paddr);
if (region != NULL) {
rc = q6asm_memory_unmap(audio->ac,
- (uint32_t)region->paddr, IN);
+ (uint32_t)region->paddr, IN);
if (rc < 0)
pr_err("%s: memory unmap failed\n", __func__);
}
@@ -1081,12 +1134,12 @@
if (audio->out_enabled)
audlpa_async_flush(audio);
audio->wflush = 0;
- audlpa_unmap_pmem_region(audio);
+ audlpa_unmap_ion_region(audio);
audio_disable(audio);
msm_clear_session_id(audio->ac->session);
auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
q6asm_audio_client_free(audio->ac);
- audlpa_reset_pmem_region(audio);
+ audlpa_reset_ion_region(audio);
#ifdef CONFIG_HAS_EARLYSUSPEND
unregister_early_suspend(&audio->suspend_ctl.node);
#endif
@@ -1096,7 +1149,6 @@
audio->event_abort = 1;
wake_up(&audio->event_wait);
audlpa_reset_event_queue(audio);
- pmem_kfree(audio->phys);
if (audio->stopped == 0)
audlpa_allow_sleep(audio);
wake_lock_destroy(&audio->wakelock);
@@ -1274,7 +1326,7 @@
spin_lock_init(&audio->dsp_lock);
init_waitqueue_head(&audio->write_wait);
INIT_LIST_HEAD(&audio->out_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
init_waitqueue_head(&audio->wait);
@@ -1339,7 +1391,6 @@
return rc;
err:
q6asm_audio_client_free(audio->ac);
- pmem_kfree(audio->phys);
kfree(audio);
return rc;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.h b/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
index ffc27ade..34b53f2 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.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
@@ -88,7 +88,7 @@
uint32_t device_events;
- struct list_head pmem_region_queue; /* protected by lock */
+ struct list_head ion_region_queue; /* protected by lock */
int eq_enable;
int eq_needs_commit;
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index c1b5e8b..d2557ca 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -1,6 +1,6 @@
/* 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
@@ -129,23 +129,23 @@
}
}
-static int audio_aio_pmem_lookup_vaddr(struct q6audio_aio *audio, void *addr,
+static int audio_aio_ion_lookup_vaddr(struct q6audio_aio *audio, void *addr,
unsigned long len,
- struct audio_aio_pmem_region **region)
+ struct audio_aio_ion_region **region)
{
- struct audio_aio_pmem_region *region_elt;
+ struct audio_aio_ion_region *region_elt;
int match_count = 0;
*region = NULL;
/* returns physical address or zero */
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
addr + len <= region_elt->vaddr + region_elt->len) {
/* offset since we could pass vaddr inside a registerd
- * pmem buffer
+ * ion buffer
*/
match_count++;
@@ -157,7 +157,7 @@
if (match_count > 1) {
pr_err("%s[%p]:multiple hits for vaddr %p, len %ld\n",
__func__, audio, addr, len);
- list_for_each_entry(region_elt, &audio->pmem_region_queue,
+ list_for_each_entry(region_elt, &audio->ion_region_queue,
list) {
if (addr >= region_elt->vaddr &&
addr < region_elt->vaddr + region_elt->len &&
@@ -173,14 +173,14 @@
return *region ? 0 : -1;
}
-static unsigned long audio_aio_pmem_fixup(struct q6audio_aio *audio, void *addr,
+static unsigned long audio_aio_ion_fixup(struct q6audio_aio *audio, void *addr,
unsigned long len, int ref_up, void **kvaddr)
{
- struct audio_aio_pmem_region *region;
+ struct audio_aio_ion_region *region;
unsigned long paddr;
int ret;
- ret = audio_aio_pmem_lookup_vaddr(audio, addr, len, ®ion);
+ ret = audio_aio_ion_lookup_vaddr(audio, addr, len, ®ion);
if (ret) {
pr_err("%s[%p]:lookup (%p, %ld) failed\n",
__func__, audio, addr, len);
@@ -519,15 +519,17 @@
return rc;
}
-void audio_aio_reset_pmem_region(struct q6audio_aio *audio)
+void audio_aio_reset_ion_region(struct q6audio_aio *audio)
{
- struct audio_aio_pmem_region *region;
+ struct audio_aio_ion_region *region;
struct list_head *ptr, *next;
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audio_aio_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audio_aio_ion_region, list);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(region->client, region->handle);
+ ion_free(region->client, region->handle);
+ ion_client_destroy(region->client);
kfree(region);
}
@@ -558,15 +560,15 @@
return;
}
-static void audio_aio_unmap_pmem_region(struct q6audio_aio *audio)
+static void audio_aio_unmap_ion_region(struct q6audio_aio *audio)
{
- struct audio_aio_pmem_region *region;
+ struct audio_aio_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
pr_debug("%s[%p]:\n", __func__, audio);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audio_aio_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audio_aio_ion_region, list);
pr_debug("%s[%p]: phy_address = 0x%lx\n",
__func__, audio, region->paddr);
if (region != NULL) {
@@ -590,9 +592,9 @@
audio->wflush = 0;
audio->drv_ops.out_flush(audio);
audio->drv_ops.in_flush(audio);
- audio_aio_unmap_pmem_region(audio);
+ audio_aio_unmap_ion_region(audio);
audio_aio_disable(audio);
- audio_aio_reset_pmem_region(audio);
+ audio_aio_reset_ion_region(audio);
audio->event_abort = 1;
wake_up(&audio->event_wait);
audio_aio_reset_event_queue(audio);
@@ -746,14 +748,14 @@
pr_debug("%s[%p]:posted AUDIO_EVENT_WRITE_DONE to user\n",
__func__, audio);
mutex_lock(&audio->write_lock);
- audio_aio_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0, 0);
mutex_unlock(&audio->write_lock);
} else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
pr_debug("%s[%p]:posted AUDIO_EVENT_READ_DONE to user\n",
__func__, audio);
mutex_lock(&audio->read_lock);
- audio_aio_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+ audio_aio_ion_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
drv_evt->payload.aio_buf.buf_len, 0, 0);
mutex_unlock(&audio->read_lock);
}
@@ -773,13 +775,13 @@
return rc;
}
-static int audio_aio_pmem_check(struct q6audio_aio *audio,
+static int audio_aio_ion_check(struct q6audio_aio *audio,
void *vaddr, unsigned long len)
{
- struct audio_aio_pmem_region *region_elt;
- struct audio_aio_pmem_region t = {.vaddr = vaddr, .len = len };
+ struct audio_aio_ion_region *region_elt;
+ struct audio_aio_ion_region t = {.vaddr = vaddr, .len = len };
- list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+ list_for_each_entry(region_elt, &audio->ion_region_queue, list) {
if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
OVERLAPS(region_elt, &t)) {
pr_err("%s[%p]:region (vaddr %p len %ld)"
@@ -795,13 +797,18 @@
return 0;
}
-static int audio_aio_pmem_add(struct q6audio_aio *audio,
- struct msm_audio_pmem_info *info)
+static int audio_aio_ion_add(struct q6audio_aio *audio,
+ struct msm_audio_ion_info *info)
{
- unsigned long paddr, kvaddr, len;
- struct file *file;
- struct audio_aio_pmem_region *region;
+ ion_phys_addr_t paddr;
+ size_t len;
+ unsigned long kvaddr;
+ struct audio_aio_ion_region *region;
int rc = -EINVAL;
+ struct ion_handle *handle;
+ struct ion_client *client;
+ unsigned long ionflag;
+ void *temp_ptr;
pr_debug("%s[%p]:\n", __func__, audio);
region = kmalloc(sizeof(*region), GFP_KERNEL);
@@ -811,50 +818,89 @@
goto end;
}
- if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
- kfree(region);
- goto end;
+ client = msm_ion_client_create(UINT_MAX, "Audio_Dec_Client");
+ if (IS_ERR_OR_NULL(client)) {
+ pr_err("Unable to create ION client\n");
+ goto client_error;
}
- rc = audio_aio_pmem_check(audio, info->vaddr, len);
+ handle = ion_import_fd(client, info->fd);
+ if (IS_ERR_OR_NULL(handle)) {
+ pr_err("%s: could not get handle of the given fd\n", __func__);
+ goto import_error;
+ }
+
+ rc = ion_handle_get_flags(client, handle, &ionflag);
+ if (rc) {
+ pr_err("%s: could not get flags for the handle\n", __func__);
+ goto flag_error;
+ }
+
+ temp_ptr = ion_map_kernel(client, handle, ionflag);
+ if (IS_ERR_OR_NULL(temp_ptr)) {
+ pr_err("%s: could not get virtual address\n", __func__);
+ goto map_error;
+ }
+ kvaddr = (unsigned long)temp_ptr;
+
+ rc = ion_phys(client, handle, &paddr, &len);
+ if (rc) {
+ pr_err("%s: could not get physical address\n", __func__);
+ goto ion_error;
+ }
+
+ rc = audio_aio_ion_check(audio, info->vaddr, len);
if (rc < 0) {
- put_pmem_file(file);
- kfree(region);
- goto end;
+ pr_err("%s: audio_aio_ion_check failed\n", __func__);
+ goto ion_error;
}
+ region->client = client;
+ region->handle = handle;
region->vaddr = info->vaddr;
region->fd = info->fd;
region->paddr = paddr;
region->kvaddr = kvaddr;
region->len = len;
- region->file = file;
region->ref_cnt = 0;
pr_debug("%s[%p]:add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
__func__, audio,
region->paddr, region->vaddr, region->len, region->kvaddr);
- list_add_tail(®ion->list, &audio->pmem_region_queue);
-
+ list_add_tail(®ion->list, &audio->ion_region_queue);
rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
1);
- if (rc < 0)
+ if (rc < 0) {
pr_err("%s[%p]: memory map failed\n", __func__, audio);
+ goto ion_error;
+ } else {
+ goto end;
+ }
+
+ion_error:
+ ion_unmap_kernel(client, handle);
+map_error:
+ ion_free(client, handle);
+flag_error:
+import_error:
+ ion_client_destroy(client);
+client_error:
+ kfree(region);
end:
return rc;
}
-static int audio_aio_pmem_remove(struct q6audio_aio *audio,
- struct msm_audio_pmem_info *info)
+static int audio_aio_ion_remove(struct q6audio_aio *audio,
+ struct msm_audio_ion_info *info)
{
- struct audio_aio_pmem_region *region;
+ struct audio_aio_ion_region *region;
struct list_head *ptr, *next;
int rc = -EINVAL;
pr_debug("%s[%p]:info fd %d vaddr %p\n",
__func__, audio, info->fd, info->vaddr);
- list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
- region = list_entry(ptr, struct audio_aio_pmem_region, list);
+ list_for_each_safe(ptr, next, &audio->ion_region_queue) {
+ region = list_entry(ptr, struct audio_aio_ion_region, list);
if ((region->fd == info->fd) &&
(region->vaddr == info->vaddr)) {
@@ -873,7 +919,9 @@
__func__, audio);
list_del(®ion->list);
- put_pmem_file(region->file);
+ ion_unmap_kernel(region->client, region->handle);
+ ion_free(region->client, region->handle);
+ ion_client_destroy(region->client);
kfree(region);
rc = 0;
break;
@@ -989,8 +1037,7 @@
pr_debug("%s[%p]:node %p dir %x buf_addr %p buf_len %d data_len \
%d\n", __func__, audio, buf_node, dir, buf_node->buf.buf_addr,
buf_node->buf.buf_len, buf_node->buf.data_len);
-
- buf_node->paddr = audio_aio_pmem_fixup(audio, buf_node->buf.buf_addr,
+ buf_node->paddr = audio_aio_ion_fixup(audio, buf_node->buf.buf_addr,
buf_node->buf.buf_len, 1,
&buf_node->kvaddr);
if (dir) {
@@ -1125,7 +1172,7 @@
init_waitqueue_head(&audio->event_wait);
INIT_LIST_HEAD(&audio->out_queue);
INIT_LIST_HEAD(&audio->in_queue);
- INIT_LIST_HEAD(&audio->pmem_region_queue);
+ INIT_LIST_HEAD(&audio->ion_region_queue);
INIT_LIST_HEAD(&audio->free_event_queue);
INIT_LIST_HEAD(&audio->event_queue);
@@ -1281,25 +1328,25 @@
mutex_unlock(&audio->lock);
break;
}
- case AUDIO_REGISTER_PMEM: {
- struct msm_audio_pmem_info info;
- pr_debug("%s[%p]:AUDIO_REGISTER_PMEM\n", __func__, audio);
+ case AUDIO_REGISTER_ION: {
+ struct msm_audio_ion_info info;
+ pr_debug("%s[%p]:AUDIO_REGISTER_ION\n", __func__, audio);
mutex_lock(&audio->lock);
if (copy_from_user(&info, (void *)arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audio_aio_pmem_add(audio, &info);
+ rc = audio_aio_ion_add(audio, &info);
mutex_unlock(&audio->lock);
break;
}
- case AUDIO_DEREGISTER_PMEM: {
- struct msm_audio_pmem_info info;
+ case AUDIO_DEREGISTER_ION: {
+ struct msm_audio_ion_info info;
mutex_lock(&audio->lock);
- pr_debug("%s[%p]:AUDIO_DEREGISTER_PMEM\n", __func__, audio);
+ pr_debug("%s[%p]:AUDIO_DEREGISTER_ION\n", __func__, audio);
if (copy_from_user(&info, (void *)arg, sizeof(info)))
rc = -EFAULT;
else
- rc = audio_aio_pmem_remove(audio, &info);
+ rc = audio_aio_ion_remove(audio, &info);
mutex_unlock(&audio->lock);
break;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
index ebf3668..a25ca4d 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.h
@@ -1,6 +1,6 @@
/* 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
@@ -23,15 +23,13 @@
#include <linux/msm_audio.h>
#include <linux/debugfs.h>
#include <linux/list.h>
-#include <linux/android_pmem.h>
#include <linux/slab.h>
+#include <linux/ion.h>
#include <asm/ioctls.h>
#include <asm/atomic.h>
#include <sound/q6asm.h>
#include <sound/apr_audio.h>
-
-
#define TUNNEL_MODE 0x0000
#define NON_TUNNEL_MODE 0x0001
@@ -114,9 +112,10 @@
#define FRAME_NUM (2)
#define FRAME_SIZE ((4*1536) + sizeof(struct dec_meta_in))
-struct audio_aio_pmem_region {
+struct audio_aio_ion_region {
struct list_head list;
- struct file *file;
+ struct ion_handle *handle;
+ struct ion_client *client;
int fd;
void *vaddr;
unsigned long paddr;
@@ -174,7 +173,7 @@
struct list_head in_queue; /* queue to retain input buffers */
struct list_head free_event_queue;
struct list_head event_queue;
- struct list_head pmem_region_queue; /* protected by lock */
+ struct list_head ion_region_queue; /* protected by lock */
struct audio_aio_drv_operations drv_ops;
union msm_audio_event_payload eos_write_payload;
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in.c b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
index 1f20aa7..667628c 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_in.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2009 Google, Inc.
* Copyright (C) 2009 HTC Corporation
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-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
@@ -72,6 +72,9 @@
case ASM_DATA_EVENT_READ_DONE:
pcm_in_get_dsp_buffers(pcm, token, payload);
break;
+ case RESET_EVENTS:
+ reset_device();
+ break;
default:
break;
}
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_out.c b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
index a4a6b728..733d5e3 100644
--- a/arch/arm/mach-msm/qdsp6v2/pcm_out.c
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2009 Google, Inc.
- * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
* Author: Brian Swetland <swetland@google.com>
*
* This software is licensed under the terms of the GNU General Public
@@ -66,6 +66,9 @@
atomic_inc(&pcm->out_count);
wake_up(&pcm->write_wait);
break;
+ case RESET_EVENTS:
+ reset_device();
+ break;
default:
break;
}
diff --git a/arch/arm/mach-msm/qdss-ptm.c b/arch/arm/mach-msm/qdss-etm.c
similarity index 100%
rename from arch/arm/mach-msm/qdss-ptm.c
rename to arch/arm/mach-msm/qdss-etm.c
diff --git a/arch/arm/mach-msm/scm.c b/arch/arm/mach-msm/scm.c
index 6794a88..cdb0cbe 100644
--- a/arch/arm/mach-msm/scm.c
+++ b/arch/arm/mach-msm/scm.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
@@ -333,6 +333,38 @@
}
EXPORT_SYMBOL(scm_call_atomic2);
+s32 scm_call_atomic4_3(u32 svc, u32 cmd, u32 arg1, u32 arg2,
+ u32 arg3, u32 arg4, u32 *ret1, u32 *ret2)
+{
+ int ret;
+ int context_id;
+ register u32 r0 asm("r0") = SCM_ATOMIC(svc, cmd, 4);
+ register u32 r1 asm("r1") = (u32)&context_id;
+ register u32 r2 asm("r2") = arg1;
+ register u32 r3 asm("r3") = arg2;
+ register u32 r4 asm("r4") = arg3;
+ register u32 r5 asm("r5") = arg4;
+
+ asm volatile(
+ __asmeq("%0", "r0")
+ __asmeq("%1", "r1")
+ __asmeq("%2", "r2")
+ __asmeq("%3", "r0")
+ __asmeq("%4", "r1")
+ __asmeq("%5", "r2")
+ __asmeq("%6", "r3")
+ "smc #0 @ switch to secure world\n"
+ : "=r" (r0), "=r" (r1), "=r" (r2)
+ : "r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5));
+ ret = r0;
+ if (ret1)
+ *ret1 = r1;
+ if (ret2)
+ *ret2 = r2;
+ return r0;
+}
+EXPORT_SYMBOL(scm_call_atomic4_3);
+
u32 scm_get_version(void)
{
int context_id;
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index bca1e0c..9321b40 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -72,6 +72,7 @@
MSM_SMSM_DEBUG = 1U << 1,
MSM_SMD_INFO = 1U << 2,
MSM_SMSM_INFO = 1U << 3,
+ MSM_SMx_POWER_INFO = 1U << 4,
};
struct smsm_shared_info {
@@ -117,29 +118,34 @@
};
static irqreturn_t smd_modem_irq_handler(int irq, void *data);
+static irqreturn_t smsm_modem_irq_handler(int irq, void *data);
static irqreturn_t smd_dsp_irq_handler(int irq, void *data);
+static irqreturn_t smsm_dsp_irq_handler(int irq, void *data);
static irqreturn_t smd_dsps_irq_handler(int irq, void *data);
+static irqreturn_t smsm_dsps_irq_handler(int irq, void *data);
static irqreturn_t smd_wcnss_irq_handler(int irq, void *data);
+static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data);
static irqreturn_t smsm_irq_handler(int irq, void *data);
static struct interrupt_config private_intr_config[NUM_SMD_SUBSYSTEMS] = {
[SMD_MODEM] = {
.smd.irq_handler = smd_modem_irq_handler,
- .smsm.irq_handler = smsm_irq_handler,
+ .smsm.irq_handler = smsm_modem_irq_handler,
},
[SMD_Q6] = {
.smd.irq_handler = smd_dsp_irq_handler,
- .smsm.irq_handler = smsm_irq_handler,
+ .smsm.irq_handler = smsm_dsp_irq_handler,
},
[SMD_DSPS] = {
.smd.irq_handler = smd_dsps_irq_handler,
- .smsm.irq_handler = smsm_irq_handler,
+ .smsm.irq_handler = smsm_dsps_irq_handler,
},
[SMD_WCNSS] = {
.smd.irq_handler = smd_wcnss_irq_handler,
- .smsm.irq_handler = smsm_irq_handler,
+ .smsm.irq_handler = smsm_wcnss_irq_handler,
},
};
+struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
#define SMSM_STATE_ADDR(entry) (smsm_info.state + entry)
#define SMSM_INTR_MASK_ADDR(entry, host) (smsm_info.intr_mask + \
@@ -175,11 +181,16 @@
if (msm_smd_debug_mask & MSM_SMSM_INFO) \
printk(KERN_INFO x); \
} while (0)
+#define SMx_POWER_INFO(x...) do { \
+ if (msm_smd_debug_mask & MSM_SMx_POWER_INFO) \
+ printk(KERN_INFO x); \
+ } while (0)
#else
#define SMD_DBG(x...) do { } while (0)
#define SMSM_DBG(x...) do { } while (0)
#define SMD_INFO(x...) do { } while (0)
#define SMSM_INFO(x...) do { } while (0)
+#define SMx_POWER_INFO(x...) do { } while (0)
#endif
static unsigned last_heap_free = 0xffffffff;
@@ -214,24 +225,6 @@
#define MSM_TRIG_A2DSPS_SMSM_INT
#define MSM_TRIG_A2WCNSS_SMD_INT
#define MSM_TRIG_A2WCNSS_SMSM_INT
-#elif defined(CONFIG_ARCH_MSM8960) || defined(CONFIG_ARCH_MSM8930) || \
- defined(CONFIG_ARCH_APQ8064)
-#define MSM_TRIG_A2M_SMD_INT \
- (smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMD_INT \
- (smd_write_intr(1 << 15, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2M_SMSM_INT \
- (smd_write_intr(1 << 4, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2Q6_SMSM_INT \
- (smd_write_intr(1 << 14, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2DSPS_SMD_INT \
- (smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4080))
-#define MSM_TRIG_A2DSPS_SMSM_INT \
- (smd_write_intr(1, MSM_SIC_NON_SECURE_BASE + 0x4094))
-#define MSM_TRIG_A2WCNSS_SMD_INT \
- (smd_write_intr(1 << 25, MSM_APCS_GCC_BASE + 0x8))
-#define MSM_TRIG_A2WCNSS_SMSM_INT \
- (smd_write_intr(1 << 23, MSM_APCS_GCC_BASE + 0x8))
#elif defined(CONFIG_ARCH_MSM9615)
#define MSM_TRIG_A2M_SMD_INT \
(smd_write_intr(1 << 3, MSM_APCS_GCC_BASE + 0x8))
@@ -258,15 +251,33 @@
#define MSM_TRIG_A2DSPS_SMSM_INT
#define MSM_TRIG_A2WCNSS_SMD_INT
#define MSM_TRIG_A2WCNSS_SMSM_INT
-#else
+#elif defined(CONFIG_ARCH_MSM7X01A) || defined(CONFIG_ARCH_MSM7x25)
#define MSM_TRIG_A2M_SMD_INT \
(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
-#define MSM_TRIG_A2Q6_SMD_INT \
- (smd_write_intr(1, MSM_CSR_BASE + 0x400 + (8) * 4))
+#define MSM_TRIG_A2Q6_SMD_INT
#define MSM_TRIG_A2M_SMSM_INT \
(smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
-#define MSM_TRIG_A2Q6_SMSM_INT \
- (smd_write_intr(1, MSM_CSR_BASE + 0x400 + (8) * 4))
+#define MSM_TRIG_A2Q6_SMSM_INT
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#elif defined(CONFIG_ARCH_MSM7X27) || defined(CONFIG_ARCH_MSM7X27A)
+#define MSM_TRIG_A2M_SMD_INT \
+ (smd_write_intr(1, MSM_CSR_BASE + 0x400 + (0) * 4))
+#define MSM_TRIG_A2Q6_SMD_INT
+#define MSM_TRIG_A2M_SMSM_INT \
+ (smd_write_intr(1, MSM_CSR_BASE + 0x400 + (5) * 4))
+#define MSM_TRIG_A2Q6_SMSM_INT
+#define MSM_TRIG_A2DSPS_SMD_INT
+#define MSM_TRIG_A2DSPS_SMSM_INT
+#define MSM_TRIG_A2WCNSS_SMD_INT
+#define MSM_TRIG_A2WCNSS_SMSM_INT
+#else /* use platform device / device tree configuration */
+#define MSM_TRIG_A2M_SMD_INT
+#define MSM_TRIG_A2Q6_SMD_INT
+#define MSM_TRIG_A2M_SMSM_INT
+#define MSM_TRIG_A2Q6_SMSM_INT
#define MSM_TRIG_A2DSPS_SMD_INT
#define MSM_TRIG_A2DSPS_SMSM_INT
#define MSM_TRIG_A2WCNSS_SMD_INT
@@ -349,33 +360,42 @@
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_MODEM].smd;
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_MODEM].smd_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_MODEM].smd_out_hardcode_count;
MSM_TRIG_A2M_SMD_INT;
+ }
}
static inline void notify_dsp_smd(void)
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_Q6].smd;
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_Q6].smd_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_Q6].smd_out_hardcode_count;
MSM_TRIG_A2Q6_SMD_INT;
+ }
}
static inline void notify_dsps_smd(void)
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_DSPS].smd;
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_DSPS].smd_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_DSPS].smd_out_hardcode_count;
MSM_TRIG_A2DSPS_SMD_INT;
+ }
}
static inline void notify_wcnss_smd(void)
@@ -384,44 +404,56 @@
= &private_intr_config[SMD_WCNSS].smd;
wakeup_v1_riva();
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_WCNSS].smd_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_WCNSS].smd_out_hardcode_count;
MSM_TRIG_A2WCNSS_SMD_INT;
+ }
}
static inline void notify_modem_smsm(void)
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_MODEM].smsm;
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_MODEM].smsm_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_MODEM].smsm_out_hardcode_count;
MSM_TRIG_A2M_SMSM_INT;
+ }
}
static inline void notify_dsp_smsm(void)
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_Q6].smsm;
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_Q6].smsm_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_Q6].smsm_out_hardcode_count;
MSM_TRIG_A2Q6_SMSM_INT;
+ }
}
static inline void notify_dsps_smsm(void)
{
static const struct interrupt_config_item *intr
= &private_intr_config[SMD_DSPS].smsm;
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_DSPS].smsm_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_DSPS].smsm_out_hardcode_count;
MSM_TRIG_A2DSPS_SMSM_INT;
+ }
}
static inline void notify_wcnss_smsm(void)
@@ -430,11 +462,14 @@
= &private_intr_config[SMD_WCNSS].smsm;
wakeup_v1_riva();
- if (intr->out_base)
+ if (intr->out_base) {
+ ++interrupt_stats[SMD_WCNSS].smsm_out_config_count;
smd_write_intr(intr->out_bit_pos,
intr->out_base + intr->out_offset);
- else
+ } else {
+ ++interrupt_stats[SMD_WCNSS].smsm_out_hardcode_count;
MSM_TRIG_A2WCNSS_SMSM_INT;
+ }
}
static void notify_other_smsm(uint32_t smsm_entry, uint32_t notify_mask)
@@ -589,27 +624,28 @@
struct edge_to_pid {
uint32_t local_pid;
uint32_t remote_pid;
+ char subsys_name[SMD_MAX_CH_NAME_LEN];
};
/**
* Maps edge type to local and remote processor ID's.
*/
static struct edge_to_pid edge_to_pids[] = {
- [SMD_APPS_MODEM] = {SMSM_APPS, SMSM_MODEM},
- [SMD_APPS_QDSP] = {SMSM_APPS, SMSM_Q6},
- [SMD_MODEM_QDSP] = {SMSM_MODEM, SMSM_Q6},
- [SMD_APPS_DSPS] = {SMSM_APPS, SMSM_DSPS},
- [SMD_MODEM_DSPS] = {SMSM_MODEM, SMSM_DSPS},
- [SMD_QDSP_DSPS] = {SMSM_Q6, SMSM_DSPS},
- [SMD_APPS_WCNSS] = {SMSM_APPS, SMSM_WCNSS},
- [SMD_MODEM_WCNSS] = {SMSM_MODEM, SMSM_WCNSS},
- [SMD_QDSP_WCNSS] = {SMSM_Q6, SMSM_WCNSS},
- [SMD_DSPS_WCNSS] = {SMSM_DSPS, SMSM_WCNSS},
- [SMD_APPS_Q6FW] = {SMSM_APPS, SMD_MODEM_Q6_FW},
- [SMD_MODEM_Q6FW] = {SMSM_MODEM, SMD_MODEM_Q6_FW},
- [SMD_QDSP_Q6FW] = {SMSM_Q6, SMD_MODEM_Q6_FW},
- [SMD_DSPS_Q6FW] = {SMSM_DSPS, SMD_MODEM_Q6_FW},
- [SMD_WCNSS_Q6FW] = {SMSM_WCNSS, SMD_MODEM_Q6_FW},
+ [SMD_APPS_MODEM] = {SMD_APPS, SMD_MODEM, "modem"},
+ [SMD_APPS_QDSP] = {SMD_APPS, SMD_Q6, "q6"},
+ [SMD_MODEM_QDSP] = {SMD_MODEM, SMD_Q6},
+ [SMD_APPS_DSPS] = {SMD_APPS, SMD_DSPS, "dsps"},
+ [SMD_MODEM_DSPS] = {SMD_MODEM, SMD_DSPS},
+ [SMD_QDSP_DSPS] = {SMD_Q6, SMD_DSPS},
+ [SMD_APPS_WCNSS] = {SMD_APPS, SMD_WCNSS, "wcnss"},
+ [SMD_MODEM_WCNSS] = {SMD_MODEM, SMD_WCNSS},
+ [SMD_QDSP_WCNSS] = {SMD_Q6, SMD_WCNSS},
+ [SMD_DSPS_WCNSS] = {SMD_DSPS, SMD_WCNSS},
+ [SMD_APPS_Q6FW] = {SMD_APPS, SMD_MODEM_Q6_FW},
+ [SMD_MODEM_Q6FW] = {SMD_MODEM, SMD_MODEM_Q6_FW},
+ [SMD_QDSP_Q6FW] = {SMD_Q6, SMD_MODEM_Q6_FW},
+ [SMD_DSPS_Q6FW] = {SMD_DSPS, SMD_MODEM_Q6_FW},
+ [SMD_WCNSS_Q6FW] = {SMD_WCNSS, SMD_MODEM_Q6_FW},
};
struct restart_notifier_block {
@@ -721,6 +757,50 @@
return ret;
}
+/*
+ * Returns a pointer to the subsystem name or NULL if no
+ * subsystem name is available.
+ *
+ * @type - Edge definition
+ */
+const char *smd_edge_to_subsystem(uint32_t type)
+{
+ const char *subsys = NULL;
+
+ if (type < ARRAY_SIZE(edge_to_pids)) {
+ subsys = edge_to_pids[type].subsys_name;
+ if (subsys[0] == 0x0)
+ subsys = NULL;
+ }
+ return subsys;
+}
+EXPORT_SYMBOL(smd_edge_to_subsystem);
+
+/*
+ * Returns a pointer to the subsystem name given the
+ * remote processor ID.
+ *
+ * @pid Remote processor ID
+ * @returns Pointer to subsystem name or NULL if not found
+ */
+const char *smd_pid_to_subsystem(uint32_t pid)
+{
+ const char *subsys = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(edge_to_pids); ++i) {
+ if (pid == edge_to_pids[i].remote_pid &&
+ edge_to_pids[i].subsys_name[0] != 0x0
+ ) {
+ subsys = edge_to_pids[i].subsys_name;
+ break;
+ }
+ }
+
+ return subsys;
+}
+EXPORT_SYMBOL(smd_pid_to_subsystem);
+
static void smd_reset_edge(struct smd_half_channel *ch, unsigned new_state)
{
if (ch->state != SMD_SS_CLOSED) {
@@ -796,9 +876,10 @@
/* notify SMSM processors */
smsm_irq_handler(0, 0);
- MSM_TRIG_A2M_SMSM_INT;
- MSM_TRIG_A2Q6_SMSM_INT;
- MSM_TRIG_A2DSPS_SMSM_INT;
+ notify_modem_smsm();
+ notify_dsp_smsm();
+ notify_dsps_smsm();
+ notify_wcnss_smsm();
}
/* change all remote states to CLOSING */
@@ -1110,15 +1191,24 @@
}
tmp = ch->recv->state;
if (tmp != ch->last_state) {
+ SMx_POWER_INFO("SMD ch%d '%s' State change %d->%d\n",
+ ch->n, ch->name, ch->last_state, tmp);
smd_state_change(ch, ch->last_state, tmp);
state_change = 1;
}
- if (ch_flags) {
+ if (ch_flags & 0x3) {
ch->update_state(ch);
+ SMx_POWER_INFO("SMD ch%d '%s' Data event r%d/w%d\n",
+ ch->n, ch->name,
+ ch->read_avail(ch),
+ ch->fifo_size - ch->write_avail(ch));
ch->notify(ch->priv, SMD_EVENT_DATA);
}
- if (ch_flags & 0x4 && !state_change)
+ if (ch_flags & 0x4 && !state_change) {
+ SMx_POWER_INFO("SMD ch%d '%s' State update\n",
+ ch->n, ch->name);
ch->notify(ch->priv, SMD_EVENT_STATUS);
+ }
}
spin_unlock_irqrestore(&smd_lock, flags);
do_smd_probe();
@@ -1126,6 +1216,8 @@
static irqreturn_t smd_modem_irq_handler(int irq, void *data)
{
+ SMx_POWER_INFO("SMD Int Modem->Apps\n");
+ ++interrupt_stats[SMD_MODEM].smd_in_count;
handle_smd_irq(&smd_ch_list_modem, notify_modem_smd);
handle_smd_irq_closing_list();
return IRQ_HANDLED;
@@ -1133,6 +1225,8 @@
static irqreturn_t smd_dsp_irq_handler(int irq, void *data)
{
+ SMx_POWER_INFO("SMD Int LPASS->Apps\n");
+ ++interrupt_stats[SMD_Q6].smd_in_count;
handle_smd_irq(&smd_ch_list_dsp, notify_dsp_smd);
handle_smd_irq_closing_list();
return IRQ_HANDLED;
@@ -1140,6 +1234,8 @@
static irqreturn_t smd_dsps_irq_handler(int irq, void *data)
{
+ SMx_POWER_INFO("SMD Int DSPS->Apps\n");
+ ++interrupt_stats[SMD_DSPS].smd_in_count;
handle_smd_irq(&smd_ch_list_dsps, notify_dsps_smd);
handle_smd_irq_closing_list();
return IRQ_HANDLED;
@@ -1147,6 +1243,8 @@
static irqreturn_t smd_wcnss_irq_handler(int irq, void *data)
{
+ SMx_POWER_INFO("SMD Int WCNSS->Apps\n");
+ ++interrupt_stats[SMD_WCNSS].smd_in_count;
handle_smd_irq(&smd_ch_list_wcnss, notify_wcnss_smd);
handle_smd_irq_closing_list();
return IRQ_HANDLED;
@@ -2286,6 +2384,34 @@
return IRQ_HANDLED;
}
+static irqreturn_t smsm_modem_irq_handler(int irq, void *data)
+{
+ SMx_POWER_INFO("SMSM Int Modem->Apps\n");
+ ++interrupt_stats[SMD_MODEM].smsm_in_count;
+ return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_dsp_irq_handler(int irq, void *data)
+{
+ SMx_POWER_INFO("SMSM Int LPASS->Apps\n");
+ ++interrupt_stats[SMD_Q6].smsm_in_count;
+ return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_dsps_irq_handler(int irq, void *data)
+{
+ SMx_POWER_INFO("SMSM Int DSPS->Apps\n");
+ ++interrupt_stats[SMD_DSPS].smsm_in_count;
+ return smsm_irq_handler(irq, data);
+}
+
+static irqreturn_t smsm_wcnss_irq_handler(int irq, void *data)
+{
+ SMx_POWER_INFO("SMSM Int WCNSS->Apps\n");
+ ++interrupt_stats[SMD_WCNSS].smsm_in_count;
+ return smsm_irq_handler(irq, data);
+}
+
int smsm_change_intr_mask(uint32_t smsm_entry,
uint32_t clear_mask, uint32_t set_mask)
{
@@ -2417,6 +2543,9 @@
state_changes = state_info->last_value ^ new_state;
if (state_changes) {
+ SMx_POWER_INFO("SMSM Change %d: %08x->%08x\n",
+ n, state_info->last_value,
+ new_state);
list_for_each_entry(cb_info,
&state_info->callbacks, cb_list) {
@@ -2567,7 +2696,7 @@
pr_err("smd_core_init: "
"enable_irq_wake failed for INT_A9_M2A_0\n");
- r = request_irq(INT_A9_M2A_5, smsm_irq_handler,
+ r = request_irq(INT_A9_M2A_5, smsm_modem_irq_handler,
flags, "smsm_dev", 0);
if (r < 0) {
free_irq(INT_A9_M2A_0, 0);
@@ -2590,8 +2719,8 @@
return r;
}
- r = request_irq(INT_ADSP_A11_SMSM, smsm_irq_handler,
- flags, "smsm_dev", smsm_irq_handler);
+ r = request_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler,
+ flags, "smsm_dev", smsm_dsp_irq_handler);
if (r < 0) {
free_irq(INT_A9_M2A_0, 0);
free_irq(INT_A9_M2A_5, 0);
@@ -2620,7 +2749,7 @@
free_irq(INT_A9_M2A_0, 0);
free_irq(INT_A9_M2A_5, 0);
free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
- free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+ free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
return r;
}
@@ -2637,7 +2766,7 @@
free_irq(INT_A9_M2A_0, 0);
free_irq(INT_A9_M2A_5, 0);
free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
- free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+ free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
return r;
}
@@ -2647,13 +2776,13 @@
pr_err("smd_core_init: "
"enable_irq_wake failed for INT_WCNSS_A11\n");
- r = request_irq(INT_WCNSS_A11_SMSM, smsm_irq_handler,
- flags, "smsm_dev", smsm_irq_handler);
+ r = request_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler,
+ flags, "smsm_dev", smsm_wcnss_irq_handler);
if (r < 0) {
free_irq(INT_A9_M2A_0, 0);
free_irq(INT_A9_M2A_5, 0);
free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
- free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+ free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
return r;
@@ -2666,16 +2795,16 @@
#endif
#if defined(CONFIG_DSPS_SMSM)
- r = request_irq(INT_DSPS_A11_SMSM, smsm_irq_handler,
- flags, "smsm_dev", smsm_irq_handler);
+ r = request_irq(INT_DSPS_A11_SMSM, smsm_dsps_irq_handler,
+ flags, "smsm_dev", smsm_dsps_irq_handler);
if (r < 0) {
free_irq(INT_A9_M2A_0, 0);
free_irq(INT_A9_M2A_5, 0);
free_irq(INT_ADSP_A11, smd_dsp_irq_handler);
- free_irq(INT_ADSP_A11_SMSM, smsm_irq_handler);
+ free_irq(INT_ADSP_A11_SMSM, smsm_dsp_irq_handler);
free_irq(INT_DSPS_A11, smd_dsps_irq_handler);
free_irq(INT_WCNSS_A11, smd_wcnss_irq_handler);
- free_irq(INT_WCNSS_A11_SMSM, smsm_irq_handler);
+ free_irq(INT_WCNSS_A11_SMSM, smsm_wcnss_irq_handler);
return r;
}
@@ -2770,6 +2899,9 @@
cfg->smsm_int.irq_name);
break;
}
+
+ strncpy(edge_to_pids[cfg->edge].subsys_name,
+ cfg->subsys_name, SMD_MAX_CH_NAME_LEN);
}
if (err_ret < 0) {
diff --git a/arch/arm/mach-msm/smd_debug.c b/arch/arm/mach-msm/smd_debug.c
index b95a35c..764102d 100644
--- a/arch/arm/mach-msm/smd_debug.c
+++ b/arch/arm/mach-msm/smd_debug.c
@@ -95,6 +95,61 @@
return max;
}
+static int debug_int_stats(char *buf, int max)
+{
+ int i = 0;
+ int subsys;
+ struct interrupt_stat *stats = interrupt_stats;
+ const char *subsys_name;
+
+ i += scnprintf(buf + i, max - i,
+ " Subsystem | In | Out (Hardcoded) |"
+ " Out (Configured) |\n");
+
+ for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
+ subsys_name = smd_pid_to_subsystem(subsys);
+ if (subsys_name) {
+ i += scnprintf(buf + i, max - i,
+ "%-10s %4s | %9u | %9u | %9u |\n",
+ smd_pid_to_subsystem(subsys), "smd",
+ stats->smd_in_count,
+ stats->smd_out_hardcode_count,
+ stats->smd_out_config_count);
+
+ i += scnprintf(buf + i, max - i,
+ "%-10s %4s | %9u | %9u | %9u |\n",
+ smd_pid_to_subsystem(subsys), "smsm",
+ stats->smsm_in_count,
+ stats->smsm_out_hardcode_count,
+ stats->smsm_out_config_count);
+ }
+ ++stats;
+ }
+
+ return i;
+}
+
+static int debug_int_stats_reset(char *buf, int max)
+{
+ int i = 0;
+ int subsys;
+ struct interrupt_stat *stats = interrupt_stats;
+
+ i += scnprintf(buf + i, max - i, "Resetting interrupt stats.\n");
+
+ for (subsys = 0; subsys < NUM_SMD_SUBSYSTEMS; ++subsys) {
+ stats->smd_in_count = 0;
+ stats->smd_out_hardcode_count = 0;
+ stats->smd_out_config_count = 0;
+ stats->smsm_in_count = 0;
+ stats->smsm_out_hardcode_count = 0;
+ stats->smsm_out_config_count = 0;
+ ++stats;
+ }
+
+ return i;
+}
+
static int debug_diag(char *buf, int max)
{
int i = 0;
@@ -694,6 +749,8 @@
debug_create("modem_err_f3", 0444, dent, debug_modem_err_f3);
debug_create("print_diag", 0444, dent, debug_diag);
debug_create("print_f3", 0444, dent, debug_f3);
+ debug_create("int_stats", 0444, dent, debug_int_stats);
+ debug_create("int_stats_reset", 0444, dent, debug_int_stats_reset);
/* NNV: this is google only stuff */
debug_create("build", 0444, dent, debug_read_build_id);
diff --git a/arch/arm/mach-msm/smd_pkt.c b/arch/arm/mach-msm/smd_pkt.c
index aeffbfd..542d224 100644
--- a/arch/arm/mach-msm/smd_pkt.c
+++ b/arch/arm/mach-msm/smd_pkt.c
@@ -607,7 +607,7 @@
{
int r = 0;
struct smd_pkt_dev *smd_pkt_devp;
- char *peripheral = NULL;
+ const char *peripheral = NULL;
smd_pkt_devp = container_of(inode->i_cdev, struct smd_pkt_dev, cdev);
@@ -622,17 +622,25 @@
mutex_lock(&smd_pkt_devp->ch_lock);
if (smd_pkt_devp->ch == 0) {
+ init_completion(&smd_pkt_devp->ch_allocated);
+ smd_pkt_devp->driver.probe = smd_pkt_dummy_probe;
+ smd_pkt_devp->driver.driver.name =
+ smd_ch_name[smd_pkt_devp->i];
+ smd_pkt_devp->driver.driver.owner = THIS_MODULE;
+ r = platform_driver_register(&smd_pkt_devp->driver);
+ if (r) {
+ pr_err("%s: %s Platform driver reg. failed\n",
+ __func__, smd_ch_name[smd_pkt_devp->i]);
+ goto out;
+ }
- if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_MODEM)
- peripheral = "modem";
- else if (smd_ch_edge[smd_pkt_devp->i] == SMD_APPS_QDSP)
- peripheral = "q6";
-
+ peripheral = smd_edge_to_subsystem(
+ smd_ch_edge[smd_pkt_devp->i]);
if (peripheral) {
smd_pkt_devp->pil = pil_get(peripheral);
if (IS_ERR(smd_pkt_devp->pil)) {
r = PTR_ERR(smd_pkt_devp->pil);
- goto out;
+ goto release_pd;
}
/* Wait for the modem SMSM to be inited for the SMD
@@ -701,6 +709,10 @@
release_pil:
if (peripheral && (r < 0))
pil_put(smd_pkt_devp->pil);
+
+release_pd:
+ if (r < 0)
+ platform_driver_unregister(&smd_pkt_devp->driver);
out:
mutex_unlock(&smd_pkt_devp->ch_lock);
@@ -726,6 +738,7 @@
smd_pkt_devp->ch = 0;
smd_pkt_devp->blocking_write = 0;
smd_pkt_devp->poll_mode = 0;
+ platform_driver_unregister(&smd_pkt_devp->driver);
if (smd_pkt_devp->pil)
pil_put(smd_pkt_devp->pil);
}
@@ -802,7 +815,6 @@
mutex_init(&smd_pkt_devp[i]->ch_lock);
mutex_init(&smd_pkt_devp[i]->rx_lock);
mutex_init(&smd_pkt_devp[i]->tx_lock);
- init_completion(&smd_pkt_devp[i]->ch_allocated);
cdev_init(&smd_pkt_devp[i]->cdev, &smd_pkt_fops);
smd_pkt_devp[i]->cdev.owner = THIS_MODULE;
@@ -843,13 +855,6 @@
&dev_attr_open_timeout))
pr_err("%s: unable to create device attr on #%d\n",
__func__, i);
-
- smd_pkt_devp[i]->driver.probe = smd_pkt_dummy_probe;
- smd_pkt_devp[i]->driver.driver.name = smd_ch_name[i];
- smd_pkt_devp[i]->driver.driver.owner = THIS_MODULE;
- r = platform_driver_register(&smd_pkt_devp[i]->driver);
- if (r)
- goto error2;
}
INIT_DELAYED_WORK(&loopback_work, loopback_probe_worker);
@@ -860,7 +865,6 @@
error2:
if (i > 0) {
while (--i >= 0) {
- platform_driver_unregister(&smd_pkt_devp[i]->driver);
cdev_del(&smd_pkt_devp[i]->cdev);
kfree(smd_pkt_devp[i]);
device_destroy(smd_pkt_classp,
@@ -880,7 +884,6 @@
int i;
for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
- platform_driver_unregister(&smd_pkt_devp[i]->driver);
cdev_del(&smd_pkt_devp[i]->cdev);
kfree(smd_pkt_devp[i]);
device_destroy(smd_pkt_classp,
diff --git a/arch/arm/mach-msm/smd_private.h b/arch/arm/mach-msm/smd_private.h
index a4c60e8..e39c57b 100644
--- a/arch/arm/mach-msm/smd_private.h
+++ b/arch/arm/mach-msm/smd_private.h
@@ -1,7 +1,7 @@
/* arch/arm/mach-msm/smd_private.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-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
@@ -19,6 +19,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <mach/msm_smsm.h>
+#include <mach/msm_smd.h>
#define PC_APPS 0
#define PC_MODEM 1
@@ -208,4 +209,15 @@
void smd_diag(void);
+struct interrupt_stat {
+ uint32_t smd_in_count;
+ uint32_t smd_out_hardcode_count;
+ uint32_t smd_out_config_count;
+
+ uint32_t smsm_in_count;
+ uint32_t smsm_out_hardcode_count;
+ uint32_t smsm_out_config_count;
+};
+extern struct interrupt_stat interrupt_stats[NUM_SMD_SUBSYSTEMS];
+
#endif
diff --git a/arch/arm/mach-msm/smd_tty.c b/arch/arm/mach-msm/smd_tty.c
index 4248be4..d856024 100644
--- a/arch/arm/mach-msm/smd_tty.c
+++ b/arch/arm/mach-msm/smd_tty.c
@@ -235,7 +235,7 @@
int res = 0;
unsigned int n = tty->index;
struct smd_tty_info *info;
- char *peripheral = NULL;
+ const char *peripheral = NULL;
if (n >= MAX_SMD_TTYS || !smd_tty[n].smd)
@@ -247,9 +247,7 @@
tty->driver_data = info;
if (info->open_count++ == 0) {
- if (smd_tty[n].smd->edge == SMD_APPS_MODEM)
- peripheral = "modem";
-
+ peripheral = smd_edge_to_subsystem(smd_tty[n].smd->edge);
if (peripheral) {
info->pil = pil_get(peripheral);
if (IS_ERR(info->pil)) {
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 883dec1..1f85194 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.c
@@ -169,11 +169,7 @@
reg = saw_bases[cpu];
- if (cpu_is_msm8960() || cpu_is_msm8930()) {
- val = 0xB0;
- reg += 0x14;
- timeout = 512;
- } else if (cpu_is_apq8064()) {
+ if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_apq8064()) {
val = 0xA4;
reg += 0x14;
timeout = 512;
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 0bc080c..2dfde6f 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1123,11 +1123,8 @@
}
msm_sched_clock_init();
- if (is_smp()) {
- __raw_writel(1,
- msm_clocks[MSM_CLOCK_DGT].regbase + TIMER_ENABLE);
- set_delay_fn(read_current_timer_delay_loop);
- }
+ __raw_writel(1, msm_clocks[MSM_CLOCK_DGT].regbase + TIMER_ENABLE);
+ set_delay_fn(read_current_timer_delay_loop);
}
#ifdef CONFIG_SMP
diff --git a/arch/arm/mach-msm/wcnss-ssr-8960.c b/arch/arm/mach-msm/wcnss-ssr-8960.c
index 9970c90..1bdec12 100644
--- a/arch/arm/mach-msm/wcnss-ssr-8960.c
+++ b/arch/arm/mach-msm/wcnss-ssr-8960.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
@@ -35,6 +35,7 @@
static void riva_fatal_fn(struct work_struct *);
static DECLARE_WORK(riva_fatal_work, riva_fatal_fn);
+static struct delayed_work cancel_vote_work;
static void *riva_ramdump_dev;
static int riva_crash;
static int ss_restart_inprogress;
@@ -51,6 +52,9 @@
static void smsm_state_cb_hdlr(void *data, uint32_t old_state,
uint32_t new_state)
{
+ if (!(new_state & SMSM_RESET))
+ return;
+
riva_crash = true;
pr_err("%s: smsm state changed to smsm reset\n", MODULE_NAME);
@@ -59,10 +63,8 @@
MODULE_NAME);
return;
}
- if (new_state & SMSM_RESET) {
- ss_restart_inprogress = true;
- schedule_work(&riva_smsm_cb_work);
- }
+ ss_restart_inprogress = true;
+ schedule_work(&riva_smsm_cb_work);
}
static void riva_fatal_fn(struct work_struct *work)
@@ -97,20 +99,24 @@
smsm_change_state(SMSM_APPS_STATE, SMSM_RESET, SMSM_RESET);
}
-/* Subsystem handlers */
-static int riva_shutdown(const struct subsys_data *subsys)
+static void riva_post_bootup(struct work_struct *work)
{
struct platform_device *pdev = wcnss_get_platform_device();
struct wcnss_wlan_config *pwlanconfig = wcnss_get_wlan_config();
- int ret = -1;
+ pr_debug(MODULE_NAME ": Cancel APPS vote for Iris & Riva\n");
+
+ wcnss_wlan_power(&pdev->dev, pwlanconfig,
+ WCNSS_WLAN_SWITCH_OFF);
+}
+
+/* Subsystem handlers */
+static int riva_shutdown(const struct subsys_data *subsys)
+{
pil_force_shutdown("wcnss");
+ flush_delayed_work(&cancel_vote_work);
- /* proxy vote on behalf of Riva */
- if (pdev && pwlanconfig)
- ret = wcnss_wlan_power(&pdev->dev, pwlanconfig,
- WCNSS_WLAN_SWITCH_OFF);
- return ret;
+ return 0;
}
static int riva_powerup(const struct subsys_data *subsys)
@@ -131,6 +137,7 @@
}
ss_restart_inprogress = false;
enable_irq(RIVA_APSS_WDOG_BITE_RESET_RDY_IRQ);
+ schedule_delayed_work(&cancel_vote_work, msecs_to_jiffies(5000));
return ret;
}
@@ -222,6 +229,8 @@
ret = -ENOMEM;
goto out;
}
+ INIT_DELAYED_WORK(&cancel_vote_work, riva_post_bootup);
+
pr_info("%s: module initialized\n", MODULE_NAME);
out:
return ret;
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index 3bce534..f748109 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -55,7 +55,7 @@
cmp r1, #2 @ see what cache we have at this level
blt skip @ skip if no cache, or just i-cache
#ifdef CONFIG_PREEMPT
- save_and_disable_irqs r9 @ make cssr&csidr read atomic
+ save_and_disable_irqs_notrace r9 @ make cssr&csidr read atomic
#endif
mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
isb @ isb to sych the new cssr&csidr
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 321abe8..edede47 100755
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -1140,3 +1140,4 @@
mpq8064_dtv MACH_MPQ8064_DTV MPQ8064_DTV 3995
msm7627a_qrd3 MACH_MSM7627A_QRD3 MSM7627A_QRD3 4005
msm8625_surf MACH_MSM8625_SURF MSM8625_SURF 4037
+msm8625_evb MACH_MSM8625_EVB MSM8625_EVB 4042
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 371d319..228c77fb 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -23,6 +23,7 @@
#include <asm/mach-types.h>
/* Size of the USB buffers used for read and write*/
#define USB_MAX_OUT_BUF 4096
+#define APPS_BUF_SIZE 2000
#define IN_BUF_SIZE 16384
#define MAX_IN_BUF_SIZE 32768
#define MAX_SYNC_OBJ_NAME_SIZE 32
@@ -50,6 +51,9 @@
#define USER_SPACE_DATA 8000
#define PKT_SIZE 4096
#define MAX_EQUIP_ID 12
+#define DIAG_CTRL_MSG_LOG_MASK 9
+#define DIAG_CTRL_MSG_EVENT_MASK 10
+#define DIAG_CTRL_MSG_F3_MASK 11
/* Maximum number of pkt reg supported at initialization*/
extern unsigned int diag_max_reg;
@@ -130,6 +134,7 @@
int num_clients;
int polling_reg_flag;
struct diag_write_device *buf_tbl;
+ int use_device_tree;
/* Memory pool parameters */
unsigned int itemsize;
@@ -148,7 +153,10 @@
int count_hdlc_pool;
int count_write_struct_pool;
int used;
-
+ /* Buffers for masks */
+ struct diag_ctrl_event_mask *event_mask;
+ struct diag_ctrl_log_mask *log_mask;
+ struct diag_ctrl_msg_mask *msg_mask;
/* State for diag forwarding */
unsigned char *buf_in_1;
unsigned char *buf_in_2;
@@ -161,6 +169,10 @@
unsigned char *usb_buf_out;
unsigned char *apps_rsp_buf;
unsigned char *user_space_data;
+ /* buffer for updating mask to peripherals */
+ unsigned char *buf_msg_mask_update;
+ unsigned char *buf_log_mask_update;
+ unsigned char *buf_event_mask_update;
smd_channel_t *ch;
smd_channel_t *ch_cntl;
smd_channel_t *chqdsp;
@@ -190,6 +202,13 @@
struct work_struct diag_read_smd_qdsp_cntl_work;
struct work_struct diag_read_smd_wcnss_work;
struct work_struct diag_read_smd_wcnss_cntl_work;
+ struct workqueue_struct *diag_cntl_wq;
+ struct work_struct diag_msg_mask_update_work;
+ struct work_struct diag_log_mask_update_work;
+ struct work_struct diag_event_mask_update_work;
+ struct work_struct diag_modem_mask_update_work;
+ struct work_struct diag_qdsp_mask_update_work;
+ struct work_struct diag_wcnss_mask_update_work;
uint8_t *msg_masks;
uint8_t *log_masks;
int log_masks_length;
@@ -228,6 +247,7 @@
int hsic_ch;
int hsic_device_enabled;
int hsic_device_opened;
+ int hsic_suspend;
int read_len_mdm;
int in_busy_hsic_read_on_mdm;
int in_busy_hsic_write_on_mdm;
@@ -238,6 +258,8 @@
struct workqueue_struct *diag_hsic_wq;
struct work_struct diag_read_mdm_work;
struct work_struct diag_read_hsic_work;
+ struct work_struct diag_disconnect_work;
+ struct work_struct diag_usb_read_complete_work;
struct diag_request *usb_read_mdm_ptr;
struct diag_request *write_ptr_mdm;
#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index efba92b..d9f12ac 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -48,7 +48,7 @@
};
/* The following variables can be specified by module options */
/* for copy buffer */
-static unsigned int itemsize = 2048; /*Size of item in the mempool */
+static unsigned int itemsize = 4096; /*Size of item in the mempool */
static unsigned int poolsize = 10; /*Number of items in the mempool */
/* for hdlc buffer */
static unsigned int itemsize_hdlc = 8192; /*Size of item in the mempool */
@@ -768,6 +768,14 @@
return 0;
}
+ if (payload_size > itemsize) {
+ pr_err("diag: Dropping packet, packet payload size crosses"
+ "4KB limit. Current payload size %d\n",
+ payload_size);
+ driver->dropped_count++;
+ return -EBADMSG;
+ }
+
buf_copy = diagmem_alloc(driver, payload_size, POOL_TYPE_COPY);
if (!buf_copy) {
driver->dropped_count++;
diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c
index 7f268563..f16aa0c 100644
--- a/drivers/char/diag/diagfwd.c
+++ b/drivers/char/diag/diagfwd.c
@@ -21,6 +21,7 @@
#include <linux/diagchar.h>
#include <linux/delay.h>
#include <linux/reboot.h>
+#include <linux/of.h>
#ifdef CONFIG_DIAG_OVER_USB
#include <mach/usbdiag.h>
#endif
@@ -43,8 +44,15 @@
static unsigned int buf_tbl_size = 8; /*Number of entries in table of buffers */
struct diag_master_table entry;
smd_channel_t *ch_temp, *chqdsp_temp, *ch_wcnss_temp;
+int diag_event_num_bytes;
+int diag_event_config;
struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 };
struct diag_hdlc_dest_type enc = { NULL, NULL, 0 };
+struct mask_info {
+ int equip_id;
+ int num_items;
+ int index;
+};
#define ENCODE_RSP_AND_SEND(buf_length) \
do { \
@@ -54,7 +62,7 @@
send.terminate = 1; \
if (!driver->in_busy_1) { \
enc.dest = driver->buf_in_1; \
- enc.dest_last = (void *)(driver->buf_in_1 + 499); \
+ enc.dest_last = (void *)(driver->buf_in_1 + APPS_BUF_SIZE - 1);\
diag_hdlc_encode(&send, &enc); \
driver->write_ptr_1->buf = driver->buf_in_1; \
driver->write_ptr_1->length = (int)(enc.dest - \
@@ -62,55 +70,80 @@
driver->in_busy_1 = 1; \
diag_device_write(driver->buf_in_1, MODEM_DATA, \
driver->write_ptr_1); \
- memset(driver->apps_rsp_buf, '\0', 500); \
+ memset(driver->apps_rsp_buf, '\0', APPS_BUF_SIZE); \
} \
} while (0)
#define CHK_OVERFLOW(bufStart, start, end, length) \
((bufStart <= start) && (end - start >= length)) ? 1 : 0
+/* Determine if this device uses a device tree */
+#ifdef CONFIG_OF
+static int has_device_tree(void)
+{
+ struct device_node *node;
+
+ node = of_find_node_by_path("/");
+ if (node) {
+ of_node_put(node);
+ return 1;
+ }
+ return 0;
+}
+#else
+static int has_device_tree(void)
+{
+ return 0;
+}
+#endif
+
int chk_config_get_id(void)
{
/* For all Fusion targets, Modem will always be present */
if (machine_is_msm8x60_fusion() || machine_is_msm8x60_fusn_ffa())
return 0;
- switch (socinfo_get_id()) {
- case APQ8060_MACHINE_ID:
- case MSM8660_MACHINE_ID:
- return APQ8060_TOOLS_ID;
- case AO8960_MACHINE_ID:
- case MSM8260A_MACHINE_ID:
- return AO8960_TOOLS_ID;
- case APQ8064_MACHINE_ID:
- return APQ8064_TOOLS_ID;
- case MSM8930_MACHINE_ID:
- return MSM8930_TOOLS_ID;
- case MSM8974_MACHINE_ID:
- return MSM8974_TOOLS_ID;
- default:
- return 0;
+ if (driver->use_device_tree) {
+ if (machine_is_copper())
+ return MSM8974_TOOLS_ID;
+ else
+ return 0;
+ } else {
+ switch (socinfo_get_msm_cpu()) {
+ case MSM_CPU_8X60:
+ return APQ8060_TOOLS_ID;
+ case MSM_CPU_8960:
+ return AO8960_TOOLS_ID;
+ case MSM_CPU_8064:
+ return APQ8064_TOOLS_ID;
+ case MSM_CPU_8930:
+ return MSM8930_TOOLS_ID;
+ case MSM_CPU_COPPER:
+ return MSM8974_TOOLS_ID;
+ case MSM_CPU_8625:
+ return MSM8625_TOOLS_ID;
+ default:
+ return 0;
+ }
}
}
/*
- * This will return TRUE for targets which support apps only mode.
+ * This will return TRUE for targets which support apps only mode and hence SSR.
* This applies to 8960 and newer targets.
*/
int chk_apps_only(void)
{
- switch (socinfo_get_id()) {
- case AO8960_MACHINE_ID:
- case APQ8064_MACHINE_ID:
- case MSM8930_MACHINE_ID:
- case MSM8630_MACHINE_ID:
- case MSM8230_MACHINE_ID:
- case APQ8030_MACHINE_ID:
- case MSM8627_MACHINE_ID:
- case MSM8227_MACHINE_ID:
- case MSM8974_MACHINE_ID:
- case MDM9615_MACHINE_ID:
- case MSM8260A_MACHINE_ID:
+ if (driver->use_device_tree)
+ return 1;
+
+ switch (socinfo_get_msm_cpu()) {
+ case MSM_CPU_8960:
+ case MSM_CPU_8064:
+ case MSM_CPU_8930:
+ case MSM_CPU_8627:
+ case MSM_CPU_9615:
+ case MSM_CPU_COPPER:
return 1;
default:
return 0;
@@ -124,8 +157,28 @@
*/
int chk_apps_master(void)
{
- if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
- cpu_is_apq8064() || cpu_is_msm8627())
+ if (driver->use_device_tree)
+ return 1;
+ else if (cpu_is_msm8960() || cpu_is_msm8930() || cpu_is_msm9615() ||
+ cpu_is_apq8064() || cpu_is_msm8627())
+ return 1;
+ else
+ return 0;
+}
+
+inline int chk_polling_response(void)
+{
+ if (!(driver->polling_reg_flag) && chk_apps_master())
+ /*
+ * If the apps processor is master and no other processor
+ * has registered to respond for polling
+ */
+ return 1;
+ else if (!(driver->ch) && !(chk_apps_master()))
+ /*
+ * If the apps processor is not the master and the modem
+ * is not up
+ */
return 1;
else
return 0;
@@ -400,8 +453,8 @@
uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
mutex_lock(&driver->diagchar_mutex);
- /* First SSID can be zero : So check that last is non-zero */
+ /* First SSID can be zero : So check that last is non-zero */
while (*(uint32_t *)(ptr + 4)) {
first = *(uint32_t *)ptr;
ptr += 4;
@@ -446,7 +499,7 @@
}
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bits)
+static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
{
uint8_t *ptr = driver->event_masks;
uint8_t *temp = buf + 2;
@@ -456,9 +509,8 @@
memset(ptr, 0 , EVENT_MASK_SIZE);
else
if (CHK_OVERFLOW(ptr, ptr,
- ptr+EVENT_MASK_SIZE,
- num_bits/8 + 1))
- memcpy(ptr, temp , num_bits/8 + 1);
+ ptr+EVENT_MASK_SIZE, num_bytes))
+ memcpy(ptr, temp , num_bytes);
else
printk(KERN_CRIT "Not enough buffer space "
"for EVENT_MASK\n");
@@ -468,10 +520,6 @@
static void diag_update_log_mask(int equip_id, uint8_t *buf, int num_items)
{
uint8_t *temp = buf;
- struct mask_info {
- int equip_id;
- int index;
- };
int i = 0;
unsigned char *ptr_data;
int offset = 8*MAX_EQUIP_ID;
@@ -485,8 +533,9 @@
break;
}
if ((ptr->equip_id == 0) && (ptr->index == 0)) {
- /*Reached a null entry */
+ /* Reached a null entry */
ptr->equip_id = equip_id;
+ ptr->num_items = num_items;
ptr->index = driver->log_masks_length;
offset = driver->log_masks_length;
driver->log_masks_length += ((num_items+7)/8);
@@ -571,6 +620,123 @@
}
}
+void diag_modem_mask_update_fn(struct work_struct *work)
+{
+ diag_send_msg_mask_update(driver->ch_cntl);
+ diag_send_log_mask_update(driver->ch_cntl);
+ diag_send_event_mask_update(driver->ch_cntl, diag_event_num_bytes);
+}
+
+void diag_qdsp_mask_update_fn(struct work_struct *work)
+{
+ diag_send_msg_mask_update(driver->chqdsp_cntl);
+ diag_send_log_mask_update(driver->chqdsp_cntl);
+ diag_send_event_mask_update(driver->chqdsp_cntl, diag_event_num_bytes);
+}
+
+void diag_wcnss_mask_update_fn(struct work_struct *work)
+{
+ diag_send_msg_mask_update(driver->ch_wcnss_cntl);
+ diag_send_log_mask_update(driver->ch_wcnss_cntl);
+ diag_send_event_mask_update(driver->ch_wcnss_cntl,
+ diag_event_num_bytes);
+}
+
+void diag_msg_mask_update_fn(struct work_struct *work)
+{
+ diag_send_msg_mask_update(driver->ch_cntl);
+ diag_send_msg_mask_update(driver->chqdsp_cntl);
+ diag_send_msg_mask_update(driver->ch_wcnss_cntl);
+}
+
+void diag_log_mask_update_fn(struct work_struct *work)
+{
+ diag_send_log_mask_update(driver->ch_cntl);
+ diag_send_log_mask_update(driver->chqdsp_cntl);
+ diag_send_log_mask_update(driver->ch_wcnss_cntl);
+}
+
+void diag_send_log_mask_update(smd_channel_t *ch)
+{
+ 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 = (driver->log_mask->num_items+7)/8;
+
+ for (i = 0; i < MAX_EQUIP_ID; i++) {
+ /* reached null entry */
+ if ((ptr->equip_id == 0) && (ptr->index == 0))
+ break;
+ driver->log_mask->cmd_type = DIAG_CTRL_MSG_LOG_MASK;
+ driver->log_mask->num_items = ptr->num_items;
+ driver->log_mask->data_len = 11 + size;
+ driver->log_mask->stream_id = 1; /* 2, if dual stream */
+ driver->log_mask->status = 3; /* status for valid mask */
+ driver->log_mask->equip_id = ptr->equip_id;
+ driver->log_mask->log_mask_size = size;
+ memcpy(buf, driver->log_mask, header_size);
+ memcpy(buf+header_size, driver->log_masks+ptr->index, size);
+ msleep(100);
+ if (ch)
+ smd_write(ch, buf, header_size + size);
+ ptr++;
+ }
+}
+
+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);
+
+ /* send event mask update */
+ driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
+ driver->event_mask->data_len = 7 + num_bytes;
+ driver->event_mask->stream_id = 1; /* 2, if dual stream */
+ driver->event_mask->status = 3; /* status for valid mask */
+ driver->event_mask->event_config = diag_event_config; /* event config */
+ driver->event_mask->event_mask_size = num_bytes;
+ memcpy(buf, driver->event_mask, header_size);
+ memcpy(buf+header_size, driver->event_masks, num_bytes);
+ msleep(100);
+ if (ch)
+ smd_write(ch, buf, header_size + num_bytes);
+}
+
+void diag_send_msg_mask_update(smd_channel_t *ch)
+{
+ void *buf = driver->buf_msg_mask_update;
+ int first, last;
+ int header_size = sizeof(struct diag_ctrl_msg_mask);
+ uint8_t *ptr = driver->msg_masks;
+
+ while (*(uint32_t *)(ptr + 4)) {
+ first = *(uint32_t *)ptr;
+ ptr += 4;
+ last = *(uint32_t *)ptr;
+ ptr += 4;
+ /* send event mask update */
+ driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+ driver->msg_mask->msg_mask_size = last - first + 1;
+ driver->msg_mask->data_len = 11 +
+ 4 * (driver->msg_mask->msg_mask_size);
+ driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+ driver->msg_mask->status = 3; /* status for valid mask */
+ driver->msg_mask->msg_mode = 0; /* Legcay mode */
+ driver->msg_mask->ssid_first = first;
+ driver->msg_mask->ssid_last = last;
+ memcpy(buf, driver->msg_mask, header_size);
+ memcpy(buf+header_size, ptr,
+ 4 * (driver->msg_mask->msg_mask_size));
+ /* since mask updates are slow, so sleep needed as to
+ prevent modem running out of DSM items */
+ msleep(100);
+ if (ch)
+ smd_write(ch, buf,
+ header_size + 4*(driver->msg_mask->msg_mask_size));
+ ptr += ((last - first) + 1)*4;
+ }
+}
+
static int diag_process_apps_pkt(unsigned char *buf, int len)
{
uint16_t subsys_cmd_code;
@@ -583,6 +749,93 @@
unsigned char *ptr;
#endif
+ /* Set log masks */
+ if (*buf == 0x73 && *(int *)(buf+4) == 3) {
+ buf += 8;
+ /* Read Equip ID and pass as first param below*/
+ diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
+ diag_update_userspace_clients(LOG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x73;
+ *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
+ *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
+ payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
+ for (i = 0; i < payload_length; i++)
+ *(int *)(driver->apps_rsp_buf+12+i) = *(buf+i);
+ queue_work(driver->diag_cntl_wq,
+ &(driver->diag_log_mask_update_work));
+ ENCODE_RSP_AND_SEND(12 + payload_length - 1);
+ return 0;
+ } else
+ buf = temp;
+#endif
+ } /* Check for set message mask */
+ else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
+ ssid_first = *(uint16_t *)(buf + 2);
+ ssid_last = *(uint16_t *)(buf + 4);
+ ssid_range = 4 * (ssid_last - ssid_first + 1);
+ diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
+ diag_update_userspace_clients(MSG_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ for (i = 0; i < 8 + ssid_range; i++)
+ *(driver->apps_rsp_buf + i) = *(buf+i);
+ *(driver->apps_rsp_buf + 6) = 0x1;
+ queue_work(driver->diag_cntl_wq,
+ &(driver->diag_msg_mask_update_work));
+ ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
+ return 0;
+ } else
+ buf = temp;
+#endif
+ } else if (*buf == 0x82) { /* event mask change */
+ buf += 4;
+ diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
+ diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+ diag_update_userspace_clients(EVENT_MASKS_TYPE);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x82;
+ driver->apps_rsp_buf[1] = 0x0;
+ *(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
+ *(uint16_t *)(driver->apps_rsp_buf + 4) =
+ EVENT_LAST_ID + 1;
+ for (i = 0; i < EVENT_LAST_ID/8 + 1; i++)
+ *(unsigned char *)(driver->apps_rsp_buf + 6 + i)
+ = 0x0;
+ /* cannot do this on work queue, as each event update
+ needs a num_bytes variable. Each queue_work call will
+ overwrite the previous input, as its the same struct */
+ diag_send_event_mask_update(driver->ch_cntl,
+ diag_event_num_bytes);
+ diag_send_event_mask_update(driver->chqdsp_cntl,
+ diag_event_num_bytes);
+ diag_send_event_mask_update(driver->ch_wcnss_cntl,
+ diag_event_num_bytes);
+ ENCODE_RSP_AND_SEND(6 + EVENT_LAST_ID/8);
+ return 0;
+ } else
+ buf = temp;
+#endif
+ } else if (*buf == 0x60) {
+ diag_event_config = *(buf+1);
+#if defined(CONFIG_DIAG_OVER_USB)
+ if (chk_apps_only()) {
+ driver->apps_rsp_buf[0] = 0x60;
+ driver->apps_rsp_buf[1] = 0x0;
+ driver->apps_rsp_buf[2] = 0x0;
+ diag_send_event_mask_update(driver->ch_cntl,
+ diag_event_num_bytes);
+ diag_send_event_mask_update(driver->chqdsp_cntl,
+ diag_event_num_bytes);
+ diag_send_event_mask_update(driver->ch_wcnss_cntl,
+ diag_event_num_bytes);
+ ENCODE_RSP_AND_SEND(2);
+ return 0;
+ }
+#endif
+ }
/* Check for registered clients and forward packet to apropriate proc */
cmd_code = (int)(*(char *)buf);
temp++;
@@ -632,70 +885,9 @@
}
}
}
- /* set event mask */
- if (*buf == 0x82) {
- buf += 4;
- diag_update_event_mask(buf, 1, *(uint16_t *)buf);
- diag_update_userspace_clients(EVENT_MASKS_TYPE);
- }
- /* event mask change */
- else if ((*buf == 0x60) && (*(buf+1) == 0x0)) {
- diag_update_event_mask(buf+1, 0, 0);
- diag_update_userspace_clients(EVENT_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- /* Check for Apps Only */
- if (!(driver->ch) && chk_apps_only()) {
- /* echo response back for apps only DIAG */
- driver->apps_rsp_buf[0] = 0x60;
- driver->apps_rsp_buf[1] = 0x0;
- driver->apps_rsp_buf[2] = 0x0;
- ENCODE_RSP_AND_SEND(2);
- return 0;
- }
-#endif
- }
- /* Set log masks */
- else if (*buf == 0x73 && *(int *)(buf+4) == 3) {
- buf += 8;
- /* Read Equip ID and pass as first param below*/
- diag_update_log_mask(*(int *)buf, buf+8, *(int *)(buf+4));
- diag_update_userspace_clients(LOG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- /* Check for Apps Only */
- if (!(driver->ch) && chk_apps_only()) {
- /* echo response back for Apps only DIAG */
- driver->apps_rsp_buf[0] = 0x73;
- *(int *)(driver->apps_rsp_buf + 4) = 0x3; /* op. ID */
- *(int *)(driver->apps_rsp_buf + 8) = 0x0; /* success */
- payload_length = 8 + ((*(int *)(buf + 4)) + 7)/8;
- for (i = 0; i < payload_length; i++)
- *(int *)(driver->apps_rsp_buf+12+i) =
- *(buf+8+i);
- ENCODE_RSP_AND_SEND(12 + payload_length - 1);
- return 0;
- }
-#endif
- }
- /* Check for set message mask */
- else if ((*buf == 0x7d) && (*(buf+1) == 0x4)) {
- ssid_first = *(uint16_t *)(buf + 2);
- ssid_last = *(uint16_t *)(buf + 4);
- ssid_range = 4 * (ssid_last - ssid_first + 1);
- diag_update_msg_mask(ssid_first, ssid_last , buf + 8);
- diag_update_userspace_clients(MSG_MASKS_TYPE);
-#if defined(CONFIG_DIAG_OVER_USB)
- if (!(driver->ch) && chk_apps_only()) {
- /* echo response back for apps only DIAG */
- for (i = 0; i < 8 + ssid_range; i++)
- *(driver->apps_rsp_buf + i) = *(buf+i);
- ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
- return 0;
- }
-#endif
- }
#if defined(CONFIG_DIAG_OVER_USB)
/* Check for Apps Only & get event mask request */
- else if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
+ if (!(driver->ch) && chk_apps_only() && *buf == 0x81) {
driver->apps_rsp_buf[0] = 0x81;
driver->apps_rsp_buf[1] = 0x0;
*(uint16_t *)(driver->apps_rsp_buf + 2) = 0x0;
@@ -776,7 +968,15 @@
*(uint16_t *)(driver->apps_rsp_buf + 78) = MSG_SSID_17_LAST;
*(uint16_t *)(driver->apps_rsp_buf + 80) = MSG_SSID_18;
*(uint16_t *)(driver->apps_rsp_buf + 82) = MSG_SSID_18_LAST;
- ENCODE_RSP_AND_SEND(83);
+ *(uint16_t *)(driver->apps_rsp_buf + 84) = MSG_SSID_19;
+ *(uint16_t *)(driver->apps_rsp_buf + 86) = MSG_SSID_19_LAST;
+ *(uint16_t *)(driver->apps_rsp_buf + 88) = MSG_SSID_20;
+ *(uint16_t *)(driver->apps_rsp_buf + 90) = MSG_SSID_20_LAST;
+ *(uint16_t *)(driver->apps_rsp_buf + 92) = MSG_SSID_21;
+ *(uint16_t *)(driver->apps_rsp_buf + 94) = MSG_SSID_21_LAST;
+ *(uint16_t *)(driver->apps_rsp_buf + 96) = MSG_SSID_22;
+ *(uint16_t *)(driver->apps_rsp_buf + 98) = MSG_SSID_22_LAST;
+ ENCODE_RSP_AND_SEND(99);
return 0;
}
/* Check for Apps Only Respond to Get Subsys Build mask */
@@ -871,6 +1071,22 @@
for (i = 0; i < ssid_range; i += 4)
*(int *)(ptr + i) = msg_bld_masks_18[i/4];
break;
+ case MSG_SSID_19:
+ for (i = 0; i < ssid_range; i += 4)
+ *(int *)(ptr + i) = msg_bld_masks_19[i/4];
+ break;
+ case MSG_SSID_20:
+ for (i = 0; i < ssid_range; i += 4)
+ *(int *)(ptr + i) = msg_bld_masks_20[i/4];
+ break;
+ case MSG_SSID_21:
+ for (i = 0; i < ssid_range; i += 4)
+ *(int *)(ptr + i) = msg_bld_masks_21[i/4];
+ break;
+ case MSG_SSID_22:
+ for (i = 0; i < ssid_range; i += 4)
+ *(int *)(ptr + i) = msg_bld_masks_22[i/4];
+ break;
}
ENCODE_RSP_AND_SEND(8 + ssid_range - 1);
return 0;
@@ -892,7 +1108,7 @@
else if ((*buf == 0x4b) && (*(buf+1) == 0x32) &&
(*(buf+2) == 0x03)) {
/* If no one has registered for polling */
- if (!(driver->polling_reg_flag)) {
+ if (chk_polling_response()) {
/* Respond to polling for Apps only DIAG */
for (i = 0; i < 3; i++)
driver->apps_rsp_buf[i] = *(buf+i);
@@ -904,7 +1120,7 @@
}
}
/* Check for ID for NO MODEM present */
- else if (!(driver->polling_reg_flag)) {
+ else if (chk_polling_response()) {
/* respond to 0x0 command */
if (*buf == 0x00) {
for (i = 0; i < 55; i++)
@@ -1311,6 +1527,26 @@
{
diag_debug_buf_idx = 0;
driver->read_len_legacy = 0;
+ driver->use_device_tree = has_device_tree();
+
+ if (driver->event_mask == NULL) {
+ driver->event_mask = kzalloc(sizeof(
+ struct diag_ctrl_event_mask), GFP_KERNEL);
+ if (driver->event_mask == NULL)
+ goto err;
+ }
+ if (driver->msg_mask == NULL) {
+ driver->msg_mask = kzalloc(sizeof(
+ struct diag_ctrl_msg_mask), GFP_KERNEL);
+ if (driver->msg_mask == NULL)
+ goto err;
+ }
+ if (driver->log_mask == NULL) {
+ driver->log_mask = kzalloc(sizeof(
+ struct diag_ctrl_log_mask), GFP_KERNEL);
+ if (driver->log_mask == NULL)
+ goto err;
+ }
if (driver->buf_in_1 == NULL) {
driver->buf_in_1 = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
if (driver->buf_in_1 == NULL)
@@ -1336,6 +1572,24 @@
if (driver->buf_in_wcnss == NULL)
goto err;
}
+ if (driver->buf_msg_mask_update == NULL) {
+ driver->buf_msg_mask_update = kzalloc(APPS_BUF_SIZE,
+ GFP_KERNEL);
+ if (driver->buf_msg_mask_update == NULL)
+ goto err;
+ }
+ if (driver->buf_log_mask_update == NULL) {
+ driver->buf_log_mask_update = kzalloc(APPS_BUF_SIZE,
+ GFP_KERNEL);
+ if (driver->buf_log_mask_update == NULL)
+ goto err;
+ }
+ if (driver->buf_event_mask_update == NULL) {
+ driver->buf_event_mask_update = kzalloc(APPS_BUF_SIZE,
+ GFP_KERNEL);
+ if (driver->buf_event_mask_update == NULL)
+ goto err;
+ }
if (driver->usb_buf_out == NULL &&
(driver->usb_buf_out = kzalloc(USB_MAX_OUT_BUF,
GFP_KERNEL)) == NULL)
@@ -1419,7 +1673,7 @@
GFP_KERNEL)) == NULL)
goto err;
if (driver->apps_rsp_buf == NULL) {
- driver->apps_rsp_buf = kzalloc(500, GFP_KERNEL);
+ driver->apps_rsp_buf = kzalloc(APPS_BUF_SIZE, GFP_KERNEL);
if (driver->apps_rsp_buf == NULL)
goto err;
}
@@ -1427,6 +1681,16 @@
#ifdef CONFIG_DIAG_OVER_USB
INIT_WORK(&(driver->diag_proc_hdlc_work), diag_process_hdlc_fn);
INIT_WORK(&(driver->diag_read_work), diag_read_work_fn);
+ INIT_WORK(&(driver->diag_msg_mask_update_work),
+ diag_msg_mask_update_fn);
+ INIT_WORK(&(driver->diag_log_mask_update_work),
+ diag_log_mask_update_fn);
+ INIT_WORK(&(driver->diag_modem_mask_update_work),
+ diag_modem_mask_update_fn);
+ INIT_WORK(&(driver->diag_qdsp_mask_update_work),
+ diag_qdsp_mask_update_fn);
+ INIT_WORK(&(driver->diag_wcnss_mask_update_work),
+ diag_wcnss_mask_update_fn);
driver->legacy_ch = usb_diag_open(DIAG_LEGACY, driver,
diag_usb_legacy_notifier);
if (IS_ERR(driver->legacy_ch)) {
@@ -1440,11 +1704,17 @@
return;
err:
pr_err("diag: Could not initialize diag buffers");
+ kfree(driver->event_mask);
+ kfree(driver->log_mask);
+ kfree(driver->msg_mask);
kfree(driver->buf_in_1);
kfree(driver->buf_in_2);
kfree(driver->buf_in_qdsp_1);
kfree(driver->buf_in_qdsp_2);
kfree(driver->buf_in_wcnss);
+ kfree(driver->buf_msg_mask_update);
+ kfree(driver->buf_log_mask_update);
+ kfree(driver->buf_event_mask_update);
kfree(driver->usb_buf_out);
kfree(driver->hdlc_buf);
kfree(driver->msg_masks);
@@ -1482,11 +1752,17 @@
#endif
platform_driver_unregister(&msm_smd_ch1_driver);
platform_driver_unregister(&diag_smd_lite_driver);
+ kfree(driver->event_mask);
+ kfree(driver->log_mask);
+ kfree(driver->msg_mask);
kfree(driver->buf_in_1);
kfree(driver->buf_in_2);
kfree(driver->buf_in_qdsp_1);
kfree(driver->buf_in_qdsp_2);
kfree(driver->buf_in_wcnss);
+ kfree(driver->buf_msg_mask_update);
+ kfree(driver->buf_log_mask_update);
+ kfree(driver->buf_event_mask_update);
kfree(driver->usb_buf_out);
kfree(driver->hdlc_buf);
kfree(driver->msg_masks);
diff --git a/drivers/char/diag/diagfwd.h b/drivers/char/diag/diagfwd.h
index 6dacab7..9ef0199 100644
--- a/drivers/char/diag/diagfwd.h
+++ b/drivers/char/diag/diagfwd.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,9 @@
int mask_request_validate(unsigned char mask_buf[]);
void diag_clear_reg(int);
int chk_apps_only(void);
+void diag_send_event_mask_update(smd_channel_t *, int num_bytes);
+void diag_send_msg_mask_update(smd_channel_t *);
+void diag_send_log_mask_update(smd_channel_t *);
/* State for diag forwarding */
#ifdef CONFIG_DIAG_OVER_USB
int diagfwd_connect(void);
@@ -35,5 +38,5 @@
#endif
extern int diag_debug_buf_idx;
extern unsigned char diag_debug_buf[1024];
-
+extern int diag_event_num_bytes;
#endif
diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c
index 2c3dc54..01ed28d 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -36,6 +36,10 @@
else
pr_debug("diag: incomplete pkt on Modem CNTL ch\n");
break;
+ case SMD_EVENT_OPEN:
+ queue_work(driver->diag_cntl_wq,
+ &(driver->diag_modem_mask_update_work));
+ break;
}
}
@@ -56,6 +60,10 @@
else
pr_debug("diag: incomplete pkt on LPASS CNTL ch\n");
break;
+ case SMD_EVENT_OPEN:
+ queue_work(driver->diag_cntl_wq,
+ &(driver->diag_qdsp_mask_update_work));
+ break;
}
}
@@ -76,6 +84,10 @@
else
pr_debug("diag: incomplete pkt on WCNSS CNTL ch\n");
break;
+ case SMD_EVENT_OPEN:
+ queue_work(driver->diag_cntl_wq,
+ &(driver->diag_wcnss_mask_update_work));
+ break;
}
}
@@ -259,6 +271,7 @@
void diagfwd_cntl_init(void)
{
driver->polling_reg_flag = 0;
+ driver->diag_cntl_wq = create_singlethread_workqueue("diag_cntl_wq");
if (driver->buf_in_cntl == NULL) {
driver->buf_in_cntl = kzalloc(IN_BUF_SIZE, GFP_KERNEL);
if (driver->buf_in_cntl == NULL)
@@ -283,6 +296,8 @@
kfree(driver->buf_in_cntl);
kfree(driver->buf_in_qdsp_cntl);
kfree(driver->buf_in_wcnss_cntl);
+ if (driver->diag_cntl_wq)
+ destroy_workqueue(driver->diag_cntl_wq);
}
void diagfwd_cntl_exit(void)
@@ -293,6 +308,7 @@
driver->ch_cntl = 0;
driver->chqdsp_cntl = 0;
driver->ch_wcnss_cntl = 0;
+ destroy_workqueue(driver->diag_cntl_wq);
platform_driver_unregister(&msm_smd_ch1_cntl_driver);
platform_driver_unregister(&diag_smd_lite_cntl_driver);
diff --git a/drivers/char/diag/diagfwd_cntl.h b/drivers/char/diag/diagfwd_cntl.h
index a76d36d..ad1fec9 100644
--- a/drivers/char/diag/diagfwd_cntl.h
+++ b/drivers/char/diag/diagfwd_cntl.h
@@ -21,10 +21,6 @@
#define DIAG_CTRL_MSG_DIAGMODE 3
/* Diag data based on "light" diag mask */
#define DIAG_CTRL_MSG_DIAGDATA 4
-/* Deprecated */
-#define DIAG_CTRL_MSG_LOG_MASK 5
-#define DIAG_CTRL_MSG_EVENT_MASK 6
-#define DIAG_CTRL_MSG_F3_MASK 7
/* Send diag internal feature mask 'diag_int_feature_mask' */
#define DIAG_CTRL_MSG_FEATURE 8
/* Send Diag log mask for a particular equip id */
@@ -48,6 +44,39 @@
uint16_t port;
};
+struct diag_ctrl_event_mask {
+ uint32_t cmd_type;
+ uint32_t data_len;
+ uint8_t stream_id;
+ uint8_t status;
+ uint8_t event_config;
+ uint32_t event_mask_size;
+ /* Copy event mask here */
+} __packed;
+
+struct diag_ctrl_log_mask {
+ uint32_t cmd_type;
+ uint32_t data_len;
+ uint8_t stream_id;
+ uint8_t status;
+ uint8_t equip_id;
+ uint32_t num_items; /* Last log code for this equip_id */
+ uint32_t log_mask_size; /* Size of log mask stored in log_mask[] */
+ /* Copy log mask here */
+} __packed;
+
+struct diag_ctrl_msg_mask {
+ uint32_t cmd_type;
+ uint32_t data_len;
+ uint8_t stream_id;
+ uint8_t status;
+ uint8_t msg_mode;
+ uint16_t ssid_first; /* Start of range of supported SSIDs */
+ uint16_t ssid_last; /* Last SSID in range */
+ uint32_t msg_mask_size; /* ssid_last - ssid_first + 1 */
+ /* Copy msg mask here */
+} __packed;
+
void diagfwd_cntl_init(void);
void diagfwd_cntl_exit(void);
void diag_read_smd_cntl_work_fn(struct work_struct *);
diff --git a/drivers/char/diag/diagfwd_hsic.c b/drivers/char/diag/diagfwd_hsic.c
index ac5722f..b2080b3 100644
--- a/drivers/char/diag/diagfwd_hsic.c
+++ b/drivers/char/diag/diagfwd_hsic.c
@@ -102,14 +102,16 @@
driver->write_ptr_mdm);
}
} else {
- pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
+ pr_debug("%s: actual_size: %d\n", __func__, actual_size);
}
/*
* If for some reason there was no hsic data to write to the
* mdm channel, set up another read
*/
- if (!driver->in_busy_hsic_write_on_mdm)
+ if (!driver->in_busy_hsic_write_on_mdm &&
+ driver->usb_mdm_connected &&
+ !driver->hsic_suspend)
queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
}
@@ -127,13 +129,34 @@
if (actual_size < 0)
pr_err("DIAG in %s: actual_size: %d\n", __func__, actual_size);
- queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+ if (driver->usb_mdm_connected)
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_mdm_work);
+}
+
+static int diag_hsic_suspend(void *ctxt)
+{
+ if (driver->in_busy_hsic_write)
+ return -EBUSY;
+
+ driver->hsic_suspend = 1;
+
+ return 0;
+}
+
+static void diag_hsic_resume(void *ctxt)
+{
+ driver->hsic_suspend = 0;
+
+ if (!driver->in_busy_hsic_write_on_mdm && driver->usb_mdm_connected)
+ queue_work(driver->diag_hsic_wq, &driver->diag_read_hsic_work);
}
static struct diag_bridge_ops hsic_diag_bridge_ops = {
.ctxt = NULL,
.read_complete_cb = diag_hsic_read_complete_callback,
.write_complete_cb = diag_hsic_write_complete_callback,
+ .suspend = diag_hsic_suspend,
+ .resume = diag_hsic_resume,
};
static int diag_hsic_close(void)
@@ -177,11 +200,11 @@
pr_err("DIAG: HSIC channel open error: %d\n",
err);
} else {
- pr_info("DIAG: opened HSIC channel\n");
+ pr_debug("DIAG: opened HSIC channel\n");
driver->hsic_device_opened = 1;
}
} else {
- pr_info("DIAG: HSIC channel already open\n");
+ pr_debug("DIAG: HSIC channel already open\n");
}
/*
@@ -220,9 +243,7 @@
driver->in_busy_hsic_read = 1;
/* Turn off communication over usb mdm and hsic */
- driver->hsic_ch = 0;
-
- return 0;
+ return diag_hsic_close();
}
/*
@@ -311,10 +332,11 @@
diagfwd_connect_hsic();
break;
case USB_DIAG_DISCONNECT:
- diagfwd_disconnect_hsic();
+ queue_work(driver->diag_hsic_wq, &driver->diag_disconnect_work);
break;
case USB_DIAG_READ_DONE:
- diagfwd_read_complete_hsic(d_req);
+ queue_work(driver->diag_hsic_wq,
+ &driver->diag_usb_read_complete_work);
break;
case USB_DIAG_WRITE_DONE:
diagfwd_write_complete_hsic();
@@ -326,6 +348,16 @@
}
}
+static void diag_usb_read_complete_fn(struct work_struct *w)
+{
+ diagfwd_read_complete_hsic(driver->usb_read_mdm_ptr);
+}
+
+static void diag_disconnect_work_fn(struct work_struct *w)
+{
+ diagfwd_disconnect_hsic();
+}
+
static void diag_read_mdm_work_fn(struct work_struct *work)
{
if (!driver->hsic_ch) {
@@ -380,7 +412,6 @@
sizeof(struct diag_request), GFP_KERNEL);
if (driver->usb_read_mdm_ptr == NULL)
goto err;
- driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
#ifdef CONFIG_DIAG_OVER_USB
INIT_WORK(&(driver->diag_read_mdm_work), diag_read_mdm_work_fn);
#endif
@@ -413,23 +444,22 @@
}
}
- /* The hsic (diag_bridge) platform device driver is enabled */
- err = diag_bridge_open(&hsic_diag_bridge_ops);
- if (err) {
- pr_err("DIAG could not open HSIC channel, err: %d\n", err);
- driver->hsic_device_opened = 0;
- return err;
- }
-
- pr_info("DIAG opened HSIC channel\n");
- driver->hsic_device_opened = 1;
-
/*
* The probe function was called after the usb was connected
* on the legacy channel. Communication over usb mdm and hsic
* needs to be turned on.
*/
- if (driver->usb_connected) {
+ if (driver->usb_mdm_connected) {
+ /* The hsic (diag_bridge) platform device driver is enabled */
+ err = diag_bridge_open(&hsic_diag_bridge_ops);
+ if (err) {
+ pr_err("DIAG could not open HSIC, err: %d\n", err);
+ driver->hsic_device_opened = 0;
+ return err;
+ }
+
+ pr_debug("DIAG opened HSIC channel\n");
+ driver->hsic_device_opened = 1;
driver->hsic_ch = 1;
driver->in_busy_hsic_write_on_mdm = 0;
driver->in_busy_hsic_read_on_mdm = 0;
@@ -448,7 +478,7 @@
static int diag_hsic_remove(struct platform_device *pdev)
{
- pr_info("DIAG: %s called\n", __func__);
+ pr_debug("DIAG: %s called\n", __func__);
diag_hsic_close();
return 0;
}
@@ -487,6 +517,11 @@
pr_debug("DIAG in %s\n", __func__);
+ driver->diag_hsic_wq = create_singlethread_workqueue("diag_hsic_wq");
+ INIT_WORK(&(driver->diag_disconnect_work), diag_disconnect_work_fn);
+ INIT_WORK(&(driver->diag_usb_read_complete_work),
+ diag_usb_read_complete_fn);
+
#ifdef CONFIG_DIAG_OVER_USB
driver->mdm_ch = usb_diag_open(DIAG_MDM, driver, diagfwd_hsic_notifier);
if (IS_ERR(driver->mdm_ch)) {
diff --git a/drivers/char/msm_rotator.c b/drivers/char/msm_rotator.c
index bd48925..3d9c9d1 100644
--- a/drivers/char/msm_rotator.c
+++ b/drivers/char/msm_rotator.c
@@ -749,7 +749,8 @@
}
static int get_img(struct msmfb_data *fbd, unsigned long *start,
- unsigned long *len, struct file **p_file, struct ion_handle **p_ihdl)
+ unsigned long *len, struct file **p_file, int *p_need,
+ struct ion_handle **p_ihdl)
{
int ret = 0;
#ifdef CONFIG_FB
@@ -760,6 +761,8 @@
unsigned long vstart;
#endif
+ *p_need = 0;
+
#ifdef CONFIG_FB
if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
file = fget_light(fbd->memory_id, &put_needed);
@@ -770,8 +773,10 @@
fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
if (get_fb_phys_info(start, len, fb_num))
ret = -1;
- else
+ else {
*p_file = file;
+ *p_need = put_needed;
+ }
} else
ret = -1;
if (ret)
@@ -822,6 +827,7 @@
struct file *srcp1_file = NULL, *dstp1_file = NULL;
struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
+ int ps0_need, p_need;
unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
unsigned int in_chroma2_paddr = 0;
struct msm_rotator_img_info *img_info;
@@ -872,8 +878,9 @@
goto do_rotate_unlock_mutex;
}
+
rc = get_img(&info.src, (unsigned long *)&in_paddr,
- (unsigned long *)&src_len, &srcp0_file, &srcp0_ihdl);
+ (unsigned long *)&src_len, &srcp0_file, &ps0_need, &srcp0_ihdl);
if (rc) {
pr_err("%s: in get_img() failed id=0x%08x\n",
DRIVER_NAME, info.src.memory_id);
@@ -881,7 +888,7 @@
}
rc = get_img(&info.dst, (unsigned long *)&out_paddr,
- (unsigned long *)&dst_len, &dstp0_file, &dstp0_ihdl);
+ (unsigned long *)&dst_len, &dstp0_file, &p_need, &dstp0_ihdl);
if (rc) {
pr_err("%s: out get_img() failed id=0x%08x\n",
DRIVER_NAME, info.dst.memory_id);
@@ -911,7 +918,7 @@
rc = get_img(&info.src_chroma,
(unsigned long *)&in_chroma_paddr,
- (unsigned long *)&src_len, &srcp1_file,
+ (unsigned long *)&src_len, &srcp1_file, &p_need,
&srcp1_ihdl);
if (rc) {
pr_err("%s: in chroma get_img() failed id=0x%08x\n",
@@ -921,7 +928,7 @@
rc = get_img(&info.dst_chroma,
(unsigned long *)&out_chroma_paddr,
- (unsigned long *)&dst_len, &dstp1_file,
+ (unsigned long *)&dst_len, &dstp1_file, &p_need,
&dstp1_ihdl);
if (rc) {
pr_err("%s: out chroma get_img() failed id=0x%08x\n",
@@ -1089,7 +1096,12 @@
put_img(dstp1_file, dstp1_ihdl);
put_img(srcp1_file, srcp1_ihdl);
put_img(dstp0_file, dstp0_ihdl);
- put_img(srcp0_file, srcp0_ihdl);
+
+ /* only source may use frame buffer */
+ if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
+ fput_light(srcp0_file, ps0_need);
+ else
+ put_img(srcp0_file, srcp0_ihdl);
mutex_unlock(&msm_rotator_dev->rotator_lock);
dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
__func__, rc);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index ff15497..36375c05 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -273,8 +273,10 @@
trace_cpu_frequency(freqs->new, freqs->cpu);
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
- if (likely(policy) && likely(policy->cpu == freqs->cpu))
+ if (likely(policy) && likely(policy->cpu == freqs->cpu)) {
policy->cur = freqs->new;
+ sysfs_notify(&policy->kobj, NULL, "scaling_cur_freq");
+ }
break;
}
}
diff --git a/drivers/crypto/msm/qce40.c b/drivers/crypto/msm/qce40.c
index 5276bcc..0d3c4c39 100644
--- a/drivers/crypto/msm/qce40.c
+++ b/drivers/crypto/msm/qce40.c
@@ -155,10 +155,14 @@
ret = readl_relaxed(pce_dev->iobase + CRYPTO_CONFIG_REG);
if (ret) {
- val = (CRYPTO_REQ_SIZE_ENUM_64_BYTES <<
- CRYPTO_REQ_SIZE) |
- (CRYPTO_FIFO_ENUM_64_BYTES <<
- CRYPTO_FIFO_THRESHOLD);
+ val = BIT(CRYPTO_MASK_DOUT_INTR) |
+ BIT(CRYPTO_MASK_DIN_INTR) |
+ BIT(CRYPTO_MASK_OP_DONE_INTR) |
+ BIT(CRYPTO_MASK_ERR_INTR) |
+ (CRYPTO_REQ_SIZE_ENUM_64_BYTES <<
+ CRYPTO_REQ_SIZE) |
+ (CRYPTO_FIFO_ENUM_64_BYTES <<
+ CRYPTO_FIFO_THRESHOLD);
writel_relaxed(val, pce_dev->iobase +
CRYPTO_CONFIG_REG);
@@ -183,24 +187,6 @@
return 0;
};
-static void config_ce_engine(struct qce_device *pce_dev)
-{
- unsigned int val = 0;
- unsigned int ret = 0;
-
- /* Crypto config register returns a 0 when it is XPU protected. */
- ret = readl_relaxed(pce_dev->iobase + CRYPTO_CONFIG_REG);
-
- /* Configure the crypto register if it is not XPU protected. */
- if (ret) {
- val = BIT(CRYPTO_MASK_DOUT_INTR) |
- BIT(CRYPTO_MASK_DIN_INTR) |
- BIT(CRYPTO_MASK_OP_DONE_INTR) |
- BIT(CRYPTO_MASK_ERR_INTR);
-
- writel_relaxed(val, pce_dev->iobase + CRYPTO_CONFIG_REG);
- }
-}
static void _check_probe_done_call_back(struct msm_dmov_cmd *cmd_ptr,
unsigned int result, struct msm_dmov_errdata *err)
@@ -234,9 +220,6 @@
*/
mb();
- /* Configure the CE Engine */
- config_ce_engine(pce_dev);
-
/*
* Clear ACCESS_VIOL bit in CRYPTO_STATUS REGISTER
*/
@@ -2622,4 +2605,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Crypto Engine driver");
-MODULE_VERSION("2.15");
+MODULE_VERSION("2.16");
diff --git a/drivers/crypto/msm/qcedev.c b/drivers/crypto/msm/qcedev.c
index c1a65fc..fff494c 100644
--- a/drivers/crypto/msm/qcedev.c
+++ b/drivers/crypto/msm/qcedev.c
@@ -1,6 +1,6 @@
/* Qualcomm CE device driver.
*
- * 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
@@ -172,7 +172,7 @@
#endif
}
-static int qcedev_ce_high_bw_req(struct qcedev_control *podev,
+static void qcedev_ce_high_bw_req(struct qcedev_control *podev,
bool high_bw_req)
{
int ret = 0;
@@ -180,18 +180,22 @@
mutex_lock(&sent_bw_req);
if (high_bw_req) {
if (podev->high_bw_req_count == 0)
- msm_bus_scale_client_update_request(
+ ret = msm_bus_scale_client_update_request(
podev->bus_scale_handle, 1);
+ if (ret)
+ pr_err("%s Unable to set to high bandwidth\n",
+ __func__);
podev->high_bw_req_count++;
} else {
if (podev->high_bw_req_count == 1)
- msm_bus_scale_client_update_request(
+ ret = msm_bus_scale_client_update_request(
podev->bus_scale_handle, 0);
+ if (ret)
+ pr_err("%s Unable to set to low bandwidth\n",
+ __func__);
podev->high_bw_req_count--;
}
mutex_unlock(&sent_bw_req);
-
- return ret;
}
@@ -331,7 +335,7 @@
handle->cntl = podev;
file->private_data = handle;
if (podev->platform_support.bus_scale_table != NULL)
- return qcedev_ce_high_bw_req(podev, true);
+ qcedev_ce_high_bw_req(podev, true);
return 0;
}
@@ -349,7 +353,7 @@
kzfree(handle);
file->private_data = NULL;
if (podev->platform_support.bus_scale_table != NULL)
- return qcedev_ce_high_bw_req(podev, false);
+ qcedev_ce_high_bw_req(podev, false);
return 0;
}
@@ -2218,7 +2222,7 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm DEV Crypto driver");
-MODULE_VERSION("1.25");
+MODULE_VERSION("1.26");
module_init(qcedev_init);
module_exit(qcedev_exit);
diff --git a/drivers/crypto/msm/qcrypto.c b/drivers/crypto/msm/qcrypto.c
index 3fff05c..21c3aff 100644
--- a/drivers/crypto/msm/qcrypto.c
+++ b/drivers/crypto/msm/qcrypto.c
@@ -1,6 +1,6 @@
/* Qualcomm Crypto driver
*
- * 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
@@ -329,7 +329,7 @@
}
}
-static int qcrypto_ce_high_bw_req(struct crypto_priv *cp, bool high_bw_req)
+static void qcrypto_ce_high_bw_req(struct crypto_priv *cp, bool high_bw_req)
{
int ret = 0;
@@ -338,16 +338,20 @@
if (cp->high_bw_req_count == 0)
ret = msm_bus_scale_client_update_request(
cp->bus_scale_handle, 1);
+ if (ret)
+ pr_err("%s Unable to set to high bandwidth\n",
+ __func__);
cp->high_bw_req_count++;
} else {
if (cp->high_bw_req_count == 1)
ret = msm_bus_scale_client_update_request(
cp->bus_scale_handle, 0);
+ if (ret)
+ pr_err("%s Unable to set to low bandwidth\n",
+ __func__);
cp->high_bw_req_count--;
}
mutex_unlock(&sent_bw_req);
-
- return ret;
}
static void _start_qcrypto_process(struct crypto_priv *cp);
@@ -403,7 +407,7 @@
/* random first IV */
get_random_bytes(ctx->iv, QCRYPTO_MAX_IV_LENGTH);
if (ctx->cp->platform_support.bus_scale_table != NULL)
- return qcrypto_ce_high_bw_req(ctx->cp, true);
+ qcrypto_ce_high_bw_req(ctx->cp, true);
return 0;
};
@@ -440,7 +444,7 @@
sha_ctx->ahash_req = NULL;
if (sha_ctx->cp->platform_support.bus_scale_table != NULL)
- return qcrypto_ce_high_bw_req(sha_ctx->cp, true);
+ qcrypto_ce_high_bw_req(sha_ctx->cp, true);
return 0;
};
@@ -3359,4 +3363,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Mona Hossain <mhossain@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm Crypto driver");
-MODULE_VERSION("1.20");
+MODULE_VERSION("1.21");
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index a6c36c8..9b1e548 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -613,6 +613,11 @@
struct ion_iommu_map *iommu_map;
int ret = 0;
+ if (ION_IS_CACHED(flags)) {
+ pr_err("%s: Cannot map iommu as cached.\n", __func__);
+ return -EINVAL;
+ }
+
mutex_lock(&client->lock);
if (!ion_handle_validate(client, handle)) {
pr_err("%s: invalid handle passed to map_kernel.\n",
@@ -631,11 +636,6 @@
goto out;
}
- if (ion_validate_buffer_flags(buffer, flags)) {
- ret = -EEXIST;
- goto out;
- }
-
/*
* If clients don't want a custom iova length, just use whatever
* the buffer size is
@@ -882,7 +882,7 @@
return ret;
}
-static int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
void *uaddr, unsigned long offset, unsigned long len,
unsigned int cmd)
{
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 1d40aef..36758fa 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -271,4 +271,23 @@
void *ion_map_fmem_buffer(struct ion_buffer *buffer, unsigned long phys_base,
void *virt_base, unsigned long flags);
+/**
+ * ion_do_cache_op - do cache operations.
+ *
+ * @client - pointer to ION client.
+ * @handle - pointer to buffer handle.
+ * @uaddr - virtual address to operate on.
+ * @offset - offset from physical address.
+ * @len - Length of data to do cache operation on.
+ * @cmd - Cache operation to perform:
+ * ION_IOC_CLEAN_CACHES
+ * ION_IOC_INV_CACHES
+ * ION_IOC_CLEAN_INV_CACHES
+ *
+ * Returns 0 on success
+ */
+int ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+ void *uaddr, unsigned long offset, unsigned long len,
+ unsigned int cmd);
+
#endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index a81dbd3..203b41a 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.c
@@ -43,6 +43,13 @@
}
EXPORT_SYMBOL(msm_ion_unsecure_heap);
+int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+ void *vaddr, unsigned long len, unsigned int cmd)
+{
+ return ion_do_cache_op(client, handle, vaddr, 0, len, cmd);
+}
+EXPORT_SYMBOL(msm_ion_do_cache_op);
+
static unsigned long msm_ion_get_base(unsigned long size, int memory_type,
unsigned int align)
{
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 73d00b3..0cadc33 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -136,6 +136,9 @@
{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
512, 384, 3},
+ { ADRENO_REV_A203, 0, 1, 1, ANY_ID,
+ "yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
+ 512, 384, 3},
{ ADRENO_REV_A205, 0, 1, 0, ANY_ID,
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
512, 384, 3},
@@ -400,11 +403,14 @@
/* 8x50 returns 0 for patch release, but it should be 1 */
/* 8960v3 returns 5 for patch release, but it should be 6 */
+ /* 8x25 returns 0 for minor id, but it should be 1 */
if (cpu_is_qsd8x50())
patchid = 1;
else if (cpu_is_msm8960() &&
SOCINFO_VERSION_MAJOR(soc_platform_version) == 3)
patchid = 6;
+ else if (cpu_is_msm8625() && minorid == 0)
+ minorid = 1;
chipid |= (minorid << 8) | patchid;
@@ -604,6 +610,8 @@
unsigned int soptimestamp;
unsigned int eoptimestamp;
struct adreno_context *drawctxt;
+ struct kgsl_context *context;
+ int next = 0;
KGSL_DRV_ERR(device, "Starting recovery from 3D GPU hang....\n");
rb_buffer = vmalloc(rb->buffer_desc.size);
@@ -672,6 +680,24 @@
drawctxt->flags |= CTXT_FLAGS_GPU_HANG;
+ /*
+ * Set the reset status of all contexts to
+ * INNOCENT_CONTEXT_RESET_EXT except for the bad context
+ * since thats the guilty party
+ */
+ while ((context = idr_get_next(&device->context_idr, &next))) {
+ if (KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT !=
+ context->reset_status) {
+ if (context->devctxt != drawctxt)
+ context->reset_status =
+ KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT;
+ else
+ context->reset_status =
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
+ }
+ next = next + 1;
+ }
+
/* Restore valid commands in ringbuffer */
adreno_ringbuffer_restore(rb, rb_buffer, num_rb_contents);
rb->timestamp = timestamp;
@@ -967,8 +993,7 @@
if (!kgsl_mmu_pt_equal(priv->pagetable, pt_base))
continue;
spin_lock(&priv->mem_lock);
- entry = kgsl_sharedmem_find_region(priv, gpuaddr,
- sizeof(unsigned int));
+ entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
if (entry) {
result = &entry->memdesc;
spin_unlock(&priv->mem_lock);
@@ -1248,7 +1273,7 @@
default:
KGSL_DRV_INFO(dev_priv->device,
"invalid ioctl code %08x\n", cmd);
- result = -EINVAL;
+ result = -ENOIOCTLCMD;
break;
}
return result;
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 9498b80..74f36c3 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -44,6 +44,7 @@
enum adreno_gpurev {
ADRENO_REV_UNKNOWN = 0,
ADRENO_REV_A200 = 200,
+ ADRENO_REV_A203 = 203,
ADRENO_REV_A205 = 205,
ADRENO_REV_A220 = 220,
ADRENO_REV_A225 = 225,
@@ -129,15 +130,19 @@
return (adreno_dev->gpurev == ADRENO_REV_A200);
}
+static inline int adreno_is_a203(struct adreno_device *adreno_dev)
+{
+ return (adreno_dev->gpurev == ADRENO_REV_A203);
+}
+
static inline int adreno_is_a205(struct adreno_device *adreno_dev)
{
- return (adreno_dev->gpurev == ADRENO_REV_A200);
+ return (adreno_dev->gpurev == ADRENO_REV_A205);
}
static inline int adreno_is_a20x(struct adreno_device *adreno_dev)
{
- return (adreno_dev->gpurev == ADRENO_REV_A200 ||
- adreno_dev->gpurev == ADRENO_REV_A205);
+ return (adreno_dev->gpurev <= 209);
}
static inline int adreno_is_a220(struct adreno_device *adreno_dev)
diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c
index b53ca8f..68299cf 100644
--- a/drivers/gpu/msm/adreno_debugfs.c
+++ b/drivers/gpu/msm/adreno_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2008-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -23,7 +23,8 @@
#include "a2xx_reg.h"
unsigned int kgsl_cff_dump_enable;
-int kgsl_pm_regs_enabled;
+int adreno_pm_regs_enabled;
+int adreno_pm_ib_enabled;
static struct dentry *pm_d_debugfs;
@@ -46,20 +47,37 @@
static int pm_regs_enabled_set(void *data, u64 val)
{
- kgsl_pm_regs_enabled = val ? 1 : 0;
+ adreno_pm_regs_enabled = val ? 1 : 0;
return 0;
}
static int pm_regs_enabled_get(void *data, u64 *val)
{
- *val = kgsl_pm_regs_enabled;
+ *val = adreno_pm_regs_enabled;
return 0;
}
+static int pm_ib_enabled_set(void *data, u64 val)
+{
+ adreno_pm_ib_enabled = val ? 1 : 0;
+ return 0;
+}
+
+static int pm_ib_enabled_get(void *data, u64 *val)
+{
+ *val = adreno_pm_ib_enabled;
+ return 0;
+}
+
+
DEFINE_SIMPLE_ATTRIBUTE(pm_regs_enabled_fops,
pm_regs_enabled_get,
pm_regs_enabled_set, "%llu\n");
+DEFINE_SIMPLE_ATTRIBUTE(pm_ib_enabled_fops,
+ pm_ib_enabled_get,
+ pm_ib_enabled_set, "%llu\n");
+
static int kgsl_cff_dump_enable_set(void *data, u64 val)
{
@@ -358,4 +376,6 @@
&pm_dump_fops);
debugfs_create_file("regs_enabled", 0644, pm_d_debugfs, device,
&pm_regs_enabled_fops);
+ debugfs_create_file("ib_enabled", 0644, pm_d_debugfs, device,
+ &pm_ib_enabled_fops);
}
diff --git a/drivers/gpu/msm/adreno_debugfs.h b/drivers/gpu/msm/adreno_debugfs.h
index 0356ac6e..5f8d89a 100644
--- a/drivers/gpu/msm/adreno_debugfs.h
+++ b/drivers/gpu/msm/adreno_debugfs.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2008-2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -17,11 +17,17 @@
int adreno_debugfs_init(struct kgsl_device *device);
-extern int kgsl_pm_regs_enabled;
+extern int adreno_pm_regs_enabled;
+extern int adreno_pm_ib_enabled;
-static inline int kgsl_pmregs_enabled(void)
+static inline int is_adreno_pm_regs_enabled(void)
{
- return kgsl_pm_regs_enabled;
+ return adreno_pm_regs_enabled;
+}
+
+static inline int is_adreno_pm_ib_enabled(void)
+{
+ return adreno_pm_ib_enabled;
}
#else
diff --git a/drivers/gpu/msm/adreno_pm4types.h b/drivers/gpu/msm/adreno_pm4types.h
index f99462e..75512d0 100644
--- a/drivers/gpu/msm/adreno_pm4types.h
+++ b/drivers/gpu/msm/adreno_pm4types.h
@@ -209,4 +209,14 @@
/* gmem command buffer length */
#define CP_REG(reg) ((0x4 << 16) | (SUBBLOCK_OFFSET(reg)))
+
+/* Return 1 if the command is an indirect buffer of any kind */
+static inline int adreno_cmd_is_ib(unsigned int cmd)
+{
+ return (cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2) ||
+ cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2) ||
+ cmd == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFE, 2) ||
+ cmd == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFD, 2));
+}
+
#endif /* __ADRENO_PM4TYPES_H */
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 7902f305..e4bc470 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -201,7 +201,7 @@
for (i = 0; i+3 < ib1_size; ) {
value = ib1_addr[i++];
- if (value == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+ if (adreno_cmd_is_ib(value)) {
uint32_t ib2_base = ib1_addr[i++];
uint32_t ib2_size = ib1_addr[i++];
@@ -294,15 +294,6 @@
}
}
-static bool adreno_ib_dump_enabled(void)
-{
-#ifdef CONFIG_MSM_KGSL_PSTMRTMDMP_NO_IB_DUMP
- return 0;
-#else
- return 1;
-#endif
-}
-
struct log_field {
bool show;
const char *display;
@@ -778,7 +769,7 @@
i = 0;
for (read_idx = 0; read_idx < num_item; ) {
uint32_t this_cmd = rb_copy[read_idx++];
- if (this_cmd == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2)) {
+ if (adreno_cmd_is_ib(this_cmd)) {
uint32_t ib_addr = rb_copy[read_idx++];
uint32_t ib_size = rb_copy[read_idx++];
dump_ib1(device, cur_pt_base, (read_idx-3)<<2, ib_addr,
@@ -817,12 +808,11 @@
cp_rb_base, cp_rb_rptr, cp_rb_wptr, read_idx);
adreno_dump_rb(device, rb_copy, num_item<<2, read_idx, rb_count);
- if (adreno_ib_dump_enabled()) {
+ if (is_adreno_pm_ib_enabled()) {
for (read_idx = NUM_DWORDS_OF_RINGBUFFER_HISTORY;
read_idx >= 0; --read_idx) {
uint32_t this_cmd = rb_copy[read_idx];
- if (this_cmd == cp_type3_packet(
- CP_INDIRECT_BUFFER_PFD, 2)) {
+ if (adreno_cmd_is_ib(this_cmd)) {
uint32_t ib_addr = rb_copy[read_idx+1];
uint32_t ib_size = rb_copy[read_idx+2];
if (ib_size && cp_ib1_base == ib_addr) {
@@ -849,16 +839,17 @@
}
/* Dump the registers if the user asked for it */
-
- if (adreno_is_a20x(adreno_dev))
- adreno_dump_regs(device, a200_registers,
- a200_registers_count);
- else if (adreno_is_a22x(adreno_dev))
- adreno_dump_regs(device, a220_registers,
- a220_registers_count);
- else if (adreno_is_a3xx(adreno_dev))
- adreno_dump_regs(device, a3xx_registers,
- a3xx_registers_count);
+ if (is_adreno_pm_regs_enabled()) {
+ if (adreno_is_a20x(adreno_dev))
+ adreno_dump_regs(device, a200_registers,
+ a200_registers_count);
+ else if (adreno_is_a22x(adreno_dev))
+ adreno_dump_regs(device, a220_registers,
+ a220_registers_count);
+ else if (adreno_is_a3xx(adreno_dev))
+ adreno_dump_regs(device, a3xx_registers,
+ a3xx_registers_count);
+ }
error_vfree:
vfree(rb_copy);
diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c
index a4899a2..9836043 100644
--- a/drivers/gpu/msm/adreno_snapshot.c
+++ b/drivers/gpu/msm/adreno_snapshot.c
@@ -104,15 +104,6 @@
return 0;
}
-/* Return 1 if the packet starting at ptr is an indirect buffer of any kind */
-static inline int packet_is_buffer(unsigned int *ptr)
-{
- return (*ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFE, 2) ||
- *ptr == cp_type3_packet(CP_INDIRECT_BUFFER_PFD, 2) ||
- *ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFE, 2) ||
- *ptr == cp_type3_packet(CP_COND_INDIRECT_BUFFER_PFD, 2));
-}
-
/* Snapshot the istore memory */
static int snapshot_istore(struct kgsl_device *device, void *snapshot,
int remain, void *priv)
@@ -258,7 +249,7 @@
if (index == rptr)
parse_ibs = 0;
- if (parse_ibs && packet_is_buffer(&rbptr[index]))
+ if (parse_ibs && adreno_cmd_is_ib(rbptr[index]))
push_object(device, SNAPSHOT_OBJ_TYPE_IB, ptbase,
rbptr[index + 1], rbptr[index + 2]);
@@ -312,7 +303,7 @@
*dst = *src;
/* If another IB is discovered, then push it on the list too */
- if (packet_is_buffer(src))
+ if (adreno_cmd_is_ib(*src))
push_object(device, SNAPSHOT_OBJ_TYPE_IB, obj->ptbase,
*(src + 1), *(src + 2));
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 9333dca..b7356ac 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -789,6 +789,40 @@
break;
}
+ case KGSL_PROP_GPU_RESET_STAT:
+ {
+ /* Return reset status of given context and clear it */
+ uint32_t id;
+ struct kgsl_context *context;
+
+ if (param->sizebytes != sizeof(unsigned int)) {
+ result = -EINVAL;
+ break;
+ }
+ /* We expect the value passed in to contain the context id */
+ if (copy_from_user(&id, param->value,
+ sizeof(unsigned int))) {
+ result = -EFAULT;
+ break;
+ }
+ context = kgsl_find_context(dev_priv, id);
+ if (!context) {
+ result = -EINVAL;
+ break;
+ }
+ /*
+ * Copy the reset status to value which also serves as
+ * the out parameter
+ */
+ if (copy_to_user(param->value, &(context->reset_status),
+ sizeof(unsigned int))) {
+ result = -EFAULT;
+ break;
+ }
+ /* Clear reset status once its been queried */
+ context->reset_status = KGSL_CTX_STAT_NO_ERROR;
+ break;
+ }
default:
result = dev_priv->device->ftbl->getproperty(
dev_priv->device, param->type,
@@ -990,6 +1024,7 @@
spin_lock(&entry->priv->mem_lock);
list_del(&entry->list);
spin_unlock(&entry->priv->mem_lock);
+ trace_kgsl_mem_timestamp_free(entry, timestamp);
kgsl_mem_entry_put(entry);
}
@@ -1000,12 +1035,18 @@
int result = 0;
struct kgsl_cmdstream_freememontimestamp *param = data;
struct kgsl_mem_entry *entry = NULL;
+ struct kgsl_device *device = dev_priv->device;
+ unsigned int cur;
spin_lock(&dev_priv->process_priv->mem_lock);
entry = kgsl_sharedmem_find(dev_priv->process_priv, param->gpuaddr);
spin_unlock(&dev_priv->process_priv->mem_lock);
if (entry) {
+ cur = device->ftbl->readtimestamp(device,
+ KGSL_TIMESTAMP_RETIRED);
+
+ trace_kgsl_mem_timestamp_queue(entry, cur);
result = kgsl_add_event(dev_priv->device, param->timestamp,
kgsl_freemem_event_cb, entry, dev_priv);
} else {
@@ -1084,6 +1125,7 @@
spin_unlock(&private->mem_lock);
if (entry) {
+ trace_kgsl_mem_free(entry);
kgsl_mem_entry_put(entry);
} else {
KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
@@ -1184,6 +1226,7 @@
kgsl_mem_entry_attach_process(entry, private);
+ trace_kgsl_mem_alloc(entry);
/* Process specific statistics */
kgsl_process_add_stats(private, entry->memtype, len);
@@ -1618,6 +1661,7 @@
kgsl_process_add_stats(private, entry->memtype, param->len);
kgsl_mem_entry_attach_process(entry, private);
+ trace_kgsl_mem_map(entry, param->fd);
kgsl_check_idle(dev_priv->device);
return result;
@@ -1684,6 +1728,7 @@
param->gpuaddr = entry->memdesc.gpuaddr;
kgsl_process_add_stats(private, entry->memtype, param->size);
+ trace_kgsl_mem_alloc(entry);
} else
kfree(entry);
@@ -1930,7 +1975,7 @@
if (!func) {
KGSL_DRV_INFO(dev_priv->device,
"invalid ioctl code %08x\n", cmd);
- ret = -EINVAL;
+ ret = -ENOIOCTLCMD;
goto done;
}
lock = 1;
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 2fb1e43..06432f9 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -197,6 +197,11 @@
/* Pointer to the device specific context information */
void *devctxt;
+ /*
+ * Status indicating whether a gpu reset occurred and whether this
+ * context was responsible for causing it
+ */
+ unsigned int reset_status;
};
struct kgsl_process_private {
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 389ed6d..7264c25 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -150,7 +150,7 @@
#endif
MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, user),
#ifdef CONFIG_ION
- MEM_ENTRY_STAT(KGSL_MEM_ENTRY_USER, ion),
+ MEM_ENTRY_STAT(KGSL_MEM_ENTRY_ION, ion),
#endif
};
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index de39ee4..93fdc087 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -10,7 +10,6 @@
* GNU General Public License for more details.
*/
-#include <linux/vmalloc.h>
#include <linux/time.h>
#include <linux/sysfs.h>
#include <linux/utsname.h>
@@ -299,6 +298,10 @@
/* Freeze the snapshot on a hang until it gets read */
device->snapshot_frozen = (hang) ? 1 : 0;
+ /* log buffer info to aid in ramdump recovery */
+ KGSL_DRV_ERR(device, "snapshot created at va %p pa %lx size %d\n",
+ device->snapshot, __pa(device->snapshot),
+ device->snapshot_size);
return 0;
}
EXPORT_SYMBOL(kgsl_device_snapshot);
@@ -448,7 +451,7 @@
int ret;
if (device->snapshot == NULL)
- device->snapshot = vmalloc(KGSL_SNAPSHOT_MEMSIZE);
+ device->snapshot = kzalloc(KGSL_SNAPSHOT_MEMSIZE, GFP_KERNEL);
if (device->snapshot == NULL)
return -ENOMEM;
@@ -491,7 +494,7 @@
kobject_put(&device->snapshot_kobj);
- vfree(device->snapshot);
+ kfree(device->snapshot);
device->snapshot = NULL;
device->snapshot_maxsize = 0;
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 86a9adc..22bc576 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.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
@@ -257,6 +257,122 @@
TP_ARGS(device, state)
);
+TRACE_EVENT(kgsl_mem_alloc,
+
+ TP_PROTO(struct kgsl_mem_entry *mem_entry),
+
+ TP_ARGS(mem_entry),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, gpuaddr)
+ __field(unsigned int, size)
+ ),
+
+ TP_fast_assign(
+ __entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+ __entry->size = mem_entry->memdesc.size;
+ ),
+
+ TP_printk(
+ "gpuaddr=0x%08x size=%d",
+ __entry->gpuaddr, __entry->size
+ )
+);
+
+TRACE_EVENT(kgsl_mem_map,
+
+ TP_PROTO(struct kgsl_mem_entry *mem_entry, int fd),
+
+ TP_ARGS(mem_entry, fd),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, gpuaddr)
+ __field(unsigned int, size)
+ __field(int, fd)
+ __field(int, type)
+ ),
+
+ TP_fast_assign(
+ __entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+ __entry->size = mem_entry->memdesc.size;
+ __entry->fd = fd;
+ __entry->type = mem_entry->memtype;
+ ),
+
+ TP_printk(
+ "gpuaddr=0x%08x size=%d type=%d fd=%d",
+ __entry->gpuaddr, __entry->size,
+ __entry->type, __entry->fd
+ )
+);
+
+TRACE_EVENT(kgsl_mem_free,
+
+ TP_PROTO(struct kgsl_mem_entry *mem_entry),
+
+ TP_ARGS(mem_entry),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, gpuaddr)
+ __field(unsigned int, size)
+ __field(int, type)
+ __field(int, fd)
+ ),
+
+ TP_fast_assign(
+ __entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+ __entry->size = mem_entry->memdesc.size;
+ __entry->type = mem_entry->memtype;
+ ),
+
+ TP_printk(
+ "gpuaddr=0x%08x size=%d type=%d",
+ __entry->gpuaddr, __entry->size, __entry->type
+ )
+);
+
+DECLARE_EVENT_CLASS(kgsl_mem_timestamp_template,
+
+ TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int curr_ts),
+
+ TP_ARGS(mem_entry, curr_ts),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, gpuaddr)
+ __field(unsigned int, size)
+ __field(int, type)
+ __field(unsigned int, drawctxt_id)
+ __field(unsigned int, curr_ts)
+ __field(unsigned int, free_ts)
+ ),
+
+ TP_fast_assign(
+ __entry->gpuaddr = mem_entry->memdesc.gpuaddr;
+ __entry->size = mem_entry->memdesc.size;
+ __entry->drawctxt_id = 1337;
+ __entry->type = mem_entry->memtype;
+ __entry->curr_ts = curr_ts;
+ __entry->free_ts = mem_entry->free_timestamp;
+ ),
+
+ TP_printk(
+ "gpuaddr=0x%08x size=%d type=%d ctx=%u curr_ts=0x%08x free_ts=0x%08x",
+ __entry->gpuaddr, __entry->size, __entry->type,
+ __entry->drawctxt_id, __entry->curr_ts, __entry->free_ts
+ )
+);
+
+DEFINE_EVENT(kgsl_mem_timestamp_template, kgsl_mem_timestamp_queue,
+ TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int curr_ts),
+ TP_ARGS(mem_entry, curr_ts)
+);
+
+DEFINE_EVENT(kgsl_mem_timestamp_template, kgsl_mem_timestamp_free,
+ TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned int curr_ts),
+ TP_ARGS(mem_entry, curr_ts)
+);
+
+
#endif /* _KGSL_TRACE_H */
/* This part must be outside protection */
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index cb3da90..6c43a75 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -339,13 +339,15 @@
*p++ = ADDR_VGV3_LAST << 24;
}
-static void z180_cmdstream_start(struct kgsl_device *device)
+static void z180_cmdstream_start(struct kgsl_device *device, int init_ram)
{
struct z180_device *z180_dev = Z180_DEVICE(device);
unsigned int cmd = VGV3_NEXTCMD_JUMP << VGV3_NEXTCMD_NEXTCMD_FSHIFT;
- z180_dev->timestamp = 0;
- z180_dev->current_timestamp = 0;
+ if (init_ram) {
+ z180_dev->timestamp = 0;
+ z180_dev->current_timestamp = 0;
+ }
addmarker(&z180_dev->ringbuffer, 0);
@@ -566,7 +568,7 @@
if (status)
goto error_clk_off;
- z180_cmdstream_start(device);
+ z180_cmdstream_start(device, init_ram);
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 40aae69..f5bfc7b 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -25,6 +25,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/regulator/consumer.h>
+#include <linux/string.h>
#if defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
@@ -42,15 +43,32 @@
#define MXT_VER_21 21
#define MXT_VER_22 22
-/* Slave addresses */
-#define MXT_APP_LOW 0x4a
-#define MXT_APP_HIGH 0x4b
-#define MXT_BOOT_LOW 0x24
-#define MXT_BOOT_HIGH 0x25
+/* I2C slave address pairs */
+struct mxt_address_pair {
+ int bootloader;
+ int application;
+};
+
+static const struct mxt_address_pair mxt_slave_addresses[] = {
+ { 0x24, 0x4a },
+ { 0x25, 0x4b },
+ { 0x25, 0x4b },
+ { 0x26, 0x4c },
+ { 0x27, 0x4d },
+ { 0x34, 0x5a },
+ { 0x35, 0x5b },
+ { 0 },
+};
+
+enum mxt_device_state { INIT, APPMODE, BOOTLOADER };
/* Firmware */
#define MXT_FW_NAME "maxtouch.fw"
+/* Firmware frame size including frame data and CRC */
+#define MXT_SINGLE_FW_MAX_FRAME_SIZE 278
+#define MXT_CHIPSET_FW_MAX_FRAME_SIZE 534
+
/* Registers */
#define MXT_FAMILY_ID 0x00
#define MXT_VARIANT_ID 0x01
@@ -215,7 +233,7 @@
#define MXT_RESET_TIME 250 /* msec */
#define MXT_RESET_NOCHGREAD 400 /* msec */
-#define MXT_FWRESET_TIME 175 /* msec */
+#define MXT_FWRESET_TIME 1000 /* msec */
#define MXT_WAKE_TIME 25
@@ -231,6 +249,8 @@
#define MXT_FRAME_CRC_PASS 0x04
#define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */
#define MXT_BOOT_STATUS_MASK 0x3f
+#define MXT_BOOT_EXTENDED_ID (1 << 5)
+#define MXT_BOOT_ID_MASK 0x1f
/* Touch status */
#define MXT_SUPPRESS (1 << 1)
@@ -299,6 +319,7 @@
struct input_dev *input_dev;
const struct mxt_platform_data *pdata;
const struct mxt_config_info *config_info;
+ enum mxt_device_state state;
struct mxt_object *object_table;
struct mxt_info info;
struct mxt_finger finger[MXT_MAX_FINGER];
@@ -323,6 +344,7 @@
u8 t15_min_reportid;
u8 curr_cfg_version;
int cfg_version_idx;
+ const char *fw_name;
};
static struct dentry *debug_base;
@@ -409,8 +431,116 @@
dev_dbg(dev, "checksum:\t0x%x\n", message->checksum);
}
+static int mxt_switch_to_bootloader_address(struct mxt_data *data)
+{
+ int i;
+ struct i2c_client *client = data->client;
+
+ if (data->state == BOOTLOADER) {
+ dev_err(&client->dev, "Already in BOOTLOADER state\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
+ if (mxt_slave_addresses[i].application == client->addr) {
+ dev_info(&client->dev, "Changing to bootloader address: "
+ "%02x -> %02x",
+ client->addr,
+ mxt_slave_addresses[i].bootloader);
+
+ client->addr = mxt_slave_addresses[i].bootloader;
+ data->state = BOOTLOADER;
+ return 0;
+ }
+ }
+
+ dev_err(&client->dev, "Address 0x%02x not found in address table",
+ client->addr);
+ return -EINVAL;
+}
+
+static int mxt_switch_to_appmode_address(struct mxt_data *data)
+{
+ int i;
+ struct i2c_client *client = data->client;
+
+ if (data->state == APPMODE) {
+ dev_err(&client->dev, "Already in APPMODE state\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; mxt_slave_addresses[i].application != 0; i++) {
+ if (mxt_slave_addresses[i].bootloader == client->addr) {
+ dev_info(&client->dev,
+ "Changing to application mode address: "
+ "0x%02x -> 0x%02x",
+ client->addr,
+ mxt_slave_addresses[i].application);
+
+ client->addr = mxt_slave_addresses[i].application;
+ data->state = APPMODE;
+ return 0;
+ }
+ }
+
+ dev_err(&client->dev, "Address 0x%02x not found in address table",
+ client->addr);
+ return -EINVAL;
+}
+
+static int mxt_get_bootloader_version(struct i2c_client *client, u8 val)
+{
+ u8 buf[3];
+
+ if (val | MXT_BOOT_EXTENDED_ID) {
+ dev_dbg(&client->dev,
+ "Retrieving extended mode ID information");
+
+ if (i2c_master_recv(client, &buf[0], 3) != 3) {
+ dev_err(&client->dev, "%s: i2c recv failed\n",
+ __func__);
+ return -EIO;
+ }
+
+ dev_info(&client->dev, "Bootloader ID:%d Version:%d",
+ buf[1], buf[2]);
+
+ return buf[0];
+ } else {
+ dev_info(&client->dev, "Bootloader ID:%d",
+ val & MXT_BOOT_ID_MASK);
+
+ return val;
+ }
+}
+
+static int mxt_get_bootloader_id(struct i2c_client *client)
+{
+ u8 val;
+ u8 buf[3];
+
+ if (i2c_master_recv(client, &val, 1) != 1) {
+ dev_err(&client->dev, "%s: i2c recv failed\n", __func__);
+ return -EIO;
+ }
+
+ if (val | MXT_BOOT_EXTENDED_ID) {
+ if (i2c_master_recv(client, &buf[0], 3) != 3) {
+ dev_err(&client->dev, "%s: i2c recv failed\n",
+ __func__);
+ return -EIO;
+ }
+ return buf[1];
+ } else {
+ dev_info(&client->dev, "Bootloader ID:%d",
+ val & MXT_BOOT_ID_MASK);
+
+ return val & MXT_BOOT_ID_MASK;
+ }
+}
+
static int mxt_check_bootloader(struct i2c_client *client,
- unsigned int state)
+ unsigned int state)
{
u8 val;
@@ -422,19 +552,28 @@
switch (state) {
case MXT_WAITING_BOOTLOAD_CMD:
+ val = mxt_get_bootloader_version(client, val);
+ val &= ~MXT_BOOT_STATUS_MASK;
+ break;
case MXT_WAITING_FRAME_DATA:
+ case MXT_APP_CRC_FAIL:
val &= ~MXT_BOOT_STATUS_MASK;
break;
case MXT_FRAME_CRC_PASS:
if (val == MXT_FRAME_CRC_CHECK)
goto recheck;
+ if (val == MXT_FRAME_CRC_FAIL) {
+ dev_err(&client->dev, "Bootloader CRC fail\n");
+ return -EINVAL;
+ }
break;
default:
return -EINVAL;
}
if (val != state) {
- dev_err(&client->dev, "Unvalid bootloader mode state\n");
+ dev_err(&client->dev, "Invalid bootloader mode state %X\n",
+ val);
return -EINVAL;
}
@@ -457,7 +596,7 @@
}
static int mxt_fw_write(struct i2c_client *client,
- const u8 *data, unsigned int frame_size)
+ const u8 *data, unsigned int frame_size)
{
if (i2c_master_send(client, data, frame_size) != frame_size) {
dev_err(&client->dev, "%s: i2c send failed\n", __func__);
@@ -735,6 +874,11 @@
int id;
u8 reportid;
+ if (data->state != APPMODE) {
+ dev_err(dev, "Ignoring IRQ - not in APPMODE state\n");
+ return IRQ_HANDLED;
+ }
+
do {
if (mxt_read_message(data, &message)) {
dev_err(dev, "Failed to read message\n");
@@ -921,11 +1065,13 @@
if (data->curr_cfg_version == cfg_version ||
!version_match) {
data->config_info = cfg_info;
+ data->fw_name = pdata->config_array[i].fw_name;
return 0;
}
}
}
+ data->fw_name = NULL;
dev_info(&data->client->dev,
"Config not found: F: %d, V: %d, FW: %d.%d.%d, CFG: %d\n",
info->family_id, info->variant_id,
@@ -1003,8 +1149,30 @@
struct mxt_object *t15_object;
error = mxt_get_info(data);
- if (error)
- return error;
+ if (error) {
+ /* Try bootloader mode */
+ error = mxt_switch_to_bootloader_address(data);
+ if (error)
+ return error;
+
+ error = mxt_check_bootloader(client, MXT_APP_CRC_FAIL);
+ if (error)
+ return error;
+
+ dev_err(&client->dev, "Application CRC failure\n");
+ data->state = BOOTLOADER;
+
+ return 0;
+ }
+
+ dev_info(&client->dev,
+ "Family ID: %d Variant ID: %d Version: %d.%d "
+ "Build: 0x%02X Object Num: %d\n",
+ info->family_id, info->variant_id,
+ info->version >> 4, info->version & 0xf,
+ info->build, info->object_num);
+
+ data->state = APPMODE;
data->object_table = kcalloc(info->object_num,
sizeof(struct mxt_object),
@@ -1112,14 +1280,8 @@
info->matrix_ysize = val;
dev_info(&client->dev,
- "Family ID: %d Variant ID: %d Version: %d Build: %d\n",
- info->family_id, info->variant_id, info->version,
- info->build);
-
- dev_info(&client->dev,
- "Matrix X Size: %d Matrix Y Size: %d Object Num: %d\n",
- info->matrix_xsize, info->matrix_ysize,
- info->object_num);
+ "Matrix X Size: %d Matrix Y Size: %d\n",
+ info->matrix_xsize, info->matrix_ysize);
return 0;
@@ -1175,108 +1337,230 @@
return count;
}
+static int strtobyte(const char *data, u8 *value)
+{
+ char str[3];
+
+ str[0] = data[0];
+ str[1] = data[1];
+ str[2] = '\0';
+
+ return kstrtou8(str, 16, value);
+}
+
static int mxt_load_fw(struct device *dev, const char *fn)
{
struct mxt_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
const struct firmware *fw = NULL;
unsigned int frame_size;
+ unsigned int retry = 0;
unsigned int pos = 0;
- int ret;
+ int ret, i, max_frame_size;
+ u8 *frame;
- ret = request_firmware(&fw, fn, dev);
- if (ret) {
- dev_err(dev, "Unable to open firmware %s\n", fn);
- return ret;
+ switch (data->info.family_id) {
+ case MXT224_ID:
+ max_frame_size = MXT_SINGLE_FW_MAX_FRAME_SIZE;
+ break;
+ case MXT1386_ID:
+ max_frame_size = MXT_CHIPSET_FW_MAX_FRAME_SIZE;
+ break;
+ default:
+ return -EINVAL;
}
- /* Change to the bootloader mode */
- mxt_write_object(data, MXT_GEN_COMMAND_T6,
- MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+ frame = kmalloc(max_frame_size, GFP_KERNEL);
+ if (!frame) {
+ dev_err(dev, "Unable to allocate memory for frame data\n");
+ return -ENOMEM;
+ }
- mxt_reset_delay(data);
+ ret = request_firmware(&fw, fn, dev);
+ if (ret < 0) {
+ dev_err(dev, "Unable to open firmware %s\n", fn);
+ goto free_frame;
+ }
- /* Change to slave address of bootloader */
- if (client->addr == MXT_APP_LOW)
- client->addr = MXT_BOOT_LOW;
- else
- client->addr = MXT_BOOT_HIGH;
+ if (data->state != BOOTLOADER) {
+ /* Change to the bootloader mode */
+ mxt_write_object(data, MXT_GEN_COMMAND_T6,
+ MXT_COMMAND_RESET, MXT_BOOT_VALUE);
+ mxt_reset_delay(data);
+
+ ret = mxt_switch_to_bootloader_address(data);
+ if (ret)
+ goto release_firmware;
+ }
ret = mxt_check_bootloader(client, MXT_WAITING_BOOTLOAD_CMD);
- if (ret)
- goto out;
+ if (ret) {
+ /* Bootloader may still be unlocked from previous update
+ * attempt */
+ ret = mxt_check_bootloader(client,
+ MXT_WAITING_FRAME_DATA);
- /* Unlock bootloader */
- mxt_unlock_bootloader(client);
+ if (ret)
+ goto return_to_app_mode;
+ } else {
+ dev_info(dev, "Unlocking bootloader\n");
+ /* Unlock bootloader */
+ mxt_unlock_bootloader(client);
+ }
while (pos < fw->size) {
ret = mxt_check_bootloader(client,
MXT_WAITING_FRAME_DATA);
if (ret)
- goto out;
+ goto release_firmware;
- frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
+ /* Get frame length MSB */
+ ret = strtobyte(fw->data + pos, frame);
+ if (ret)
+ goto release_firmware;
+
+ /* Get frame length LSB */
+ ret = strtobyte(fw->data + pos + 2, frame + 1);
+ if (ret)
+ goto release_firmware;
+
+ frame_size = ((*frame << 8) | *(frame + 1));
/* We should add 2 at frame size as the the firmware data is not
* included the CRC bytes.
*/
frame_size += 2;
+ if (frame_size > max_frame_size) {
+ dev_err(dev, "Invalid frame size - %d\n", frame_size);
+ ret = -EINVAL;
+ goto release_firmware;
+ }
+
+ /* Convert frame data and CRC from hex to binary */
+ for (i = 2; i < frame_size; i++) {
+ ret = strtobyte(fw->data + pos + i * 2, frame + i);
+ if (ret)
+ goto release_firmware;
+ }
+
/* Write one frame to device */
- mxt_fw_write(client, fw->data + pos, frame_size);
+ mxt_fw_write(client, frame, frame_size);
ret = mxt_check_bootloader(client,
MXT_FRAME_CRC_PASS);
- if (ret)
- goto out;
+ if (ret) {
+ retry++;
- pos += frame_size;
+ /* Back off by 20ms per retry */
+ msleep(retry * 20);
- dev_dbg(dev, "Updated %d bytes / %zd bytes\n", pos, fw->size);
+ if (retry > 20)
+ goto release_firmware;
+ } else {
+ retry = 0;
+ pos += frame_size * 2;
+ dev_dbg(dev, "Updated %d/%zd bytes\n", pos, fw->size);
+ }
}
-out:
+return_to_app_mode:
+ mxt_switch_to_appmode_address(data);
+release_firmware:
release_firmware(fw);
-
- /* Change to slave address of application */
- if (client->addr == MXT_BOOT_LOW)
- client->addr = MXT_APP_LOW;
- else
- client->addr = MXT_APP_HIGH;
+free_frame:
+ kfree(frame);
return ret;
}
+static const char *
+mxt_search_fw_name(struct mxt_data *data, u8 bootldr_id)
+{
+ const struct mxt_platform_data *pdata = data->pdata;
+ const struct mxt_config_info *cfg_info;
+ const char *fw_name = NULL;
+ int i;
+
+ for (i = 0; i < pdata->config_array_size; i++) {
+ cfg_info = &pdata->config_array[i];
+ if (bootldr_id == cfg_info->bootldr_id && cfg_info->fw_name) {
+ data->config_info = cfg_info;
+ data->info.family_id = cfg_info->family_id;
+ fw_name = cfg_info->fw_name;
+ }
+ }
+
+ return fw_name;
+}
+
static ssize_t mxt_update_fw_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct mxt_data *data = dev_get_drvdata(dev);
int error;
+ const char *fw_name;
+ u8 bootldr_id;
+
+ /* If fw_name is set, then the existing firmware has an upgrade */
+ if (!data->fw_name) {
+ /*
+ * If the device boots up in the bootloader mode, check if
+ * there is a firmware to upgrade.
+ */
+ if (data->state == BOOTLOADER) {
+ bootldr_id = mxt_get_bootloader_id(data->client);
+ if (bootldr_id <= 0) {
+ dev_err(dev,
+ "Unable to retrieve bootloader id\n");
+ return -EINVAL;
+ }
+ fw_name = mxt_search_fw_name(data, bootldr_id);
+ if (fw_name == NULL) {
+ dev_err(dev,
+ "Unable to find fw from bootloader id\n");
+ return -EINVAL;
+ }
+ } else {
+ /* In APPMODE, if the f/w name does not exist, quit */
+ dev_err(dev,
+ "Firmware name not specified in platform data\n");
+ return -EINVAL;
+ }
+ } else {
+ fw_name = data->fw_name;
+ }
+
+ dev_info(dev, "Upgrading the firmware file to %s\n", fw_name);
disable_irq(data->irq);
- error = mxt_load_fw(dev, MXT_FW_NAME);
+ error = mxt_load_fw(dev, fw_name);
if (error) {
dev_err(dev, "The firmware update failed(%d)\n", error);
count = error;
} else {
- dev_dbg(dev, "The firmware update succeeded\n");
+ dev_info(dev, "The firmware update succeeded\n");
/* Wait for reset */
msleep(MXT_FWRESET_TIME);
+ data->state = INIT;
kfree(data->object_table);
data->object_table = NULL;
+ data->cfg_version_idx = 0;
mxt_initialize(data);
}
- enable_irq(data->irq);
+ if (data->state == APPMODE) {
+ enable_irq(data->irq);
- error = mxt_make_highchg(data);
- if (error)
- return error;
+ error = mxt_make_highchg(data);
+ if (error)
+ return error;
+ }
return count;
}
@@ -1345,10 +1629,12 @@
struct mxt_data *data = input_get_drvdata(dev);
int error;
- error = mxt_start(data);
- if (error < 0) {
- dev_err(&data->client->dev, "mxt_start failed in input_open\n");
- return error;
+ if (data->state == APPMODE) {
+ error = mxt_start(data);
+ if (error < 0) {
+ dev_err(&data->client->dev, "mxt_start failed in input_open\n");
+ return error;
+ }
}
return 0;
@@ -1359,10 +1645,11 @@
struct mxt_data *data = input_get_drvdata(dev);
int error;
- error = mxt_stop(data);
- if (error < 0)
- dev_err(&data->client->dev, "mxt_stop failed in input_close\n");
-
+ if (data->state == APPMODE) {
+ error = mxt_stop(data);
+ if (error < 0)
+ dev_err(&data->client->dev, "mxt_stop failed in input_close\n");
+ }
}
static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
@@ -1818,6 +2105,7 @@
goto err_free_mem;
}
+ data->state = INIT;
input_dev->name = "atmel_mxt_ts";
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
@@ -1941,9 +2229,13 @@
goto err_free_object;
}
- error = mxt_make_highchg(data);
- if (error)
- goto err_free_irq;
+ if (data->state == APPMODE) {
+ error = mxt_make_highchg(data);
+ if (error) {
+ dev_err(&client->dev, "Failed to make high CHG\n");
+ goto err_free_irq;
+ }
+ }
error = input_register_device(input_dev);
if (error)
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 84d441d..78c474e 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -163,6 +163,10 @@
if (!rc)
rc = -ETIMEDOUT;
if (rc < 0) {
+ rcmd = msm_dequeue(queue, list_control);
+ if (!rcmd)
+ free_qcmd(rcmd);
+ kfree(isp_event);
pr_err("%s: wait_event error %d\n", __func__, rc);
return rc;
}
@@ -518,6 +522,7 @@
ctrlcmd.value = (void *)ctrl_data;
memcpy(ctrlcmd.value, ctrl, ctrlcmd.length);
ctrlcmd.timeout_ms = 1000;
+ ctrlcmd.vnode_id = pcam->vnode_id;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in usersspace, and get return value */
@@ -543,6 +548,7 @@
ctrlcmd.value = (void *)ctrl_data;
memcpy(ctrlcmd.value, queryctrl, ctrlcmd.length);
ctrlcmd.timeout_ms = 1000;
+ ctrlcmd.vnode_id = pcam->vnode_id;
ctrlcmd.config_ident = g_server_dev.config_info.config_dev_id[0];
/* send command to config thread in userspace, and get return value */
@@ -943,7 +949,8 @@
not in use when we free the buffers */
mutex_lock(&pcam->vid_lock);
pcam_inst->streamon = 0;
- rc = msm_server_streamoff(pcam, pcam_inst->my_index);
+ if (g_server_dev.use_count > 0)
+ rc = msm_server_streamoff(pcam, pcam_inst->my_index);
mutex_unlock(&pcam->vid_lock);
if (rc < 0)
pr_err("%s: hw failed to stop streaming\n", __func__);
@@ -1448,6 +1455,7 @@
}
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
pcam->mctl.client = msm_ion_client_create(-1, "camera");
+ kref_init(&pcam->mctl.refcount);
#endif
/* Should be set to sensor ops if any but right now its OK!! */
if (!pcam->mctl.mctl_open) {
@@ -1502,6 +1510,7 @@
if (pcam->use_count == 1) {
+ msm_queue_init(&g_server_dev.ctrl_q, "control");
rc = msm_send_open_server(pcam->vnode_id);
if (rc < 0) {
mutex_unlock(&pcam->vid_lock);
@@ -1573,6 +1582,14 @@
return rc;
}
+void msm_release_ion_client(struct kref *ref)
+{
+ struct msm_cam_media_controller *mctl = container_of(ref,
+ struct msm_cam_media_controller, refcount);
+ pr_err("%s Calling ion_client_destroy ", __func__);
+ ion_client_destroy(mctl->client);
+}
+
static int msm_close(struct file *f)
{
int rc = 0;
@@ -1581,13 +1598,11 @@
pcam_inst = container_of(f->private_data,
struct msm_cam_v4l2_dev_inst, eventHandle);
pcam = pcam_inst->pcam;
- D("%s\n", __func__);
if (!pcam) {
pr_err("%s NULL pointer of camera device!\n", __func__);
return -EINVAL;
}
-
mutex_lock(&pcam->vid_lock);
pcam_inst->streamon = 0;
pcam->use_count--;
@@ -1610,17 +1625,21 @@
if (rc < 0)
pr_err("msm_cam_server_close_session fails %d\n", rc);
- rc = msm_send_close_server(pcam->vnode_id);
- if (rc < 0)
- pr_err("msm_send_close_server failed %d\n", rc);
+ if (g_server_dev.use_count > 0) {
+ rc = msm_send_close_server(pcam->vnode_id);
+ if (rc < 0)
+ pr_err("msm_send_close_server failed %d\n", rc);
+ }
if (pcam->mctl.mctl_release) {
rc = pcam->mctl.mctl_release(&(pcam->mctl));
if (rc < 0)
pr_err("mctl_release fails %d\n", rc);
}
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- ion_client_destroy(pcam->mctl.client);
+ kref_put(&pcam->mctl.refcount, msm_release_ion_client);
#endif
+ if (g_server_dev.use_count == 0)
+ mutex_unlock(&g_server_dev.server_lock);
}
mutex_unlock(&pcam->vid_lock);
return rc;
@@ -1879,16 +1898,17 @@
{
int rc;
D("%s: open %s\n", __func__, fp->f_path.dentry->d_name.name);
-
+ mutex_lock(&g_server_dev.server_lock);
rc = nonseekable_open(inode, fp);
if (rc < 0) {
pr_err("%s: nonseekable_open error %d\n", __func__, rc);
+ mutex_unlock(&g_server_dev.server_lock);
return rc;
}
g_server_dev.use_count++;
if (g_server_dev.use_count == 1)
msm_queue_init(&g_server_dev.ctrl_q, "control");
-
+ mutex_unlock(&g_server_dev.server_lock);
return rc;
}
@@ -1909,6 +1929,29 @@
return rc;
}
+static int msm_close_server(struct inode *inode, struct file *fp)
+{
+ mutex_lock(&g_server_dev.server_lock);
+ if (g_server_dev.use_count > 0)
+ g_server_dev.use_count--;
+ mutex_unlock(&g_server_dev.server_lock);
+ if (g_server_dev.use_count == 0) {
+ if (g_server_dev.pcam_active) {
+ struct v4l2_event v4l2_ev;
+ mutex_lock(&g_server_dev.server_lock);
+
+ v4l2_ev.type = V4L2_EVENT_PRIVATE_START
+ + MSM_CAM_APP_NOTIFY_ERROR_EVENT;
+ ktime_get_ts(&v4l2_ev.timestamp);
+ v4l2_event_queue(
+ g_server_dev.pcam_active->pvdev, &v4l2_ev);
+ }
+ msm_queue_drain(&g_server_dev.ctrl_q, list_control);
+ }
+ return 0;
+}
+
+
static long msm_v4l2_evt_notify(struct msm_cam_media_controller *mctl,
unsigned int cmd, unsigned long evt)
{
@@ -2147,10 +2190,19 @@
spin_lock_init(&config_cam->p_mctl->sync.pmem_stats_spinlock);
config_cam->p_mctl->config_device = config_cam;
+ kref_get(&config_cam->p_mctl->refcount);
fp->private_data = config_cam;
return rc;
}
+static int msm_close_config(struct inode *node, struct file *f)
+{
+ 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);
+ return 0;
+}
+
static struct v4l2_file_operations g_msm_fops = {
.owner = THIS_MODULE,
.open = msm_open,
@@ -2169,6 +2221,7 @@
.open = msm_open_server,
.poll = msm_poll_server,
.unlocked_ioctl = msm_ioctl_server,
+ .release = msm_close_server,
};
static const struct file_operations msm_fops_config = {
@@ -2177,6 +2230,7 @@
.poll = msm_poll_config,
.unlocked_ioctl = msm_ioctl_config,
.mmap = msm_mmap_config,
+ .release = msm_close_config,
};
int msm_setup_v4l2_event_queue(struct v4l2_fh *eventHandle,
@@ -2294,6 +2348,7 @@
return rc;
}
+ mutex_init(&g_server_dev.server_lock);
g_server_dev.pcam_active = NULL;
g_server_dev.camera_info.num_cameras = 0;
atomic_set(&g_server_dev.number_pcam_active, 0);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 55c0da1..c90ab44 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -239,6 +239,7 @@
struct pm_qos_request_list pm_qos_req_list;
struct msm_mctl_pp_info pp_info;
struct ion_client *client;
+ struct kref refcount;
/* VFE output mode.
* Used to interpret the Primary/Secondary messages
* to preview/video/main/thumbnail image types*/
@@ -409,6 +410,7 @@
struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];
/* info of MCTL nodes successfully probed*/
struct msm_mctl_node_info mctl_node_info;
+ struct mutex server_lock;
};
/* camera server related functions */
@@ -525,6 +527,7 @@
int image_mode, struct msm_frame_buffer *buf);
int msm_mctl_pp_mctl_divert_done(struct msm_cam_media_controller *p_mctl,
void __user *arg);
+void msm_release_ion_client(struct kref *ref);
#endif /* __KERNEL__ */
#endif /* _MSM_H */
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 54458d1..492bcce 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -890,7 +890,7 @@
return rc;
}
pcam_inst->vbqueue_initialized = 0;
-
+ kref_get(&pcam->mctl.refcount);
f->private_data = &pcam_inst->eventHandle;
D("f->private_data = 0x%x, pcam = 0x%x\n",
@@ -961,6 +961,7 @@
v4l2_fh_exit(&pcam_inst->eventHandle);
kfree(pcam_inst);
+ kref_put(&pcam->mctl.refcount, msm_release_ion_client);
f->private_data = NULL;
mutex_unlock(&pcam->mctl_node.dev_lock);
D("%s : X ", __func__);
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
index 6c52e21..31b8239 100644
--- a/drivers/media/video/msm/wfd/enc-subdev.c
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -334,16 +334,26 @@
struct vcd_buffer_requirement buf_req;
struct venc_inst *inst = sd->dev_priv;
struct video_client_ctx *client_ctx = &inst->venc_client;
+ int aligned_width, aligned_height;
if (!client_ctx) {
WFD_MSG_ERR("Invalid client context");
rc = -EINVAL;
goto err;
}
+ aligned_width = ALIGN(b->width, 16);
+ aligned_height = ALIGN(b->height, 16);
+
+ if (aligned_width != b->width) {
+ WFD_MSG_ERR("Width not 16 byte aligned\n");
+ rc = -EINVAL;
+ goto err;
+ }
+
buf_req.actual_count = b->count;
buf_req.min_count = b->count;
buf_req.max_count = b->count;
- buf_req.sz = (((b->height * b->width) + 2047) & (~2047))
- + (((b->height * b->width * 1/2) + 2047) & (~2047));
+ buf_req.sz = ALIGN(aligned_height * aligned_width, SZ_2K)
+ + ALIGN(aligned_height * aligned_width * 1/2, SZ_2K);
buf_req.align = 0;
inst->width = b->width;
inst->height = b->height;
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.c b/drivers/media/video/msm/wfd/vsg-subdev.c
index 96a48f26..8e385a4 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.c
+++ b/drivers/media/video/msm/wfd/vsg-subdev.c
@@ -76,10 +76,29 @@
}
}
+static void vsg_encode_helper_func(struct work_struct *task)
+{
+ struct vsg_encode_work *work =
+ container_of(task, struct vsg_encode_work, work);
+
+ /*
+ * Note: don't need to lock for context below as we only
+ * access fields that are "static".
+ */
+ int rc = vsg_encode_frame(work->context, work->buf);
+ if (rc < 0) {
+ mutex_lock(&work->context->mutex);
+ work->context->state = VSG_STATE_ERROR;
+ mutex_unlock(&work->context->mutex);
+ }
+ kfree(work);
+}
+
static void vsg_work_func(struct work_struct *task)
{
struct vsg_work *work =
container_of(task, struct vsg_work, work);
+ struct vsg_encode_work *encode_work;
struct vsg_context *context = work->context;
struct vsg_buf_info *buf_info = NULL, *temp = NULL;
int rc = 0;
@@ -88,8 +107,9 @@
if (list_empty(&context->free_queue.node)) {
WFD_MSG_DBG("%s: queue empty doing nothing\n", __func__);
goto err_skip_encode;
- } else if (context->stopped) {
- WFD_MSG_DBG("%s: vsg is stopped doing nothing\n", __func__);
+ } else if (context->state != VSG_STATE_STARTED) {
+ WFD_MSG_DBG("%s: vsg is stopped or in error state "
+ "doing nothing\n", __func__);
goto err_skip_encode;
}
@@ -114,15 +134,19 @@
}
}
- buf_info->flags |= VSG_BUF_BEING_ENCODED;
- mutex_unlock(&context->mutex);
- rc = vsg_encode_frame(context, buf_info);
- if (rc < 0) {
- WFD_MSG_ERR("frame encode failed");
- goto err_encode_fail;
+ encode_work = kmalloc(sizeof(*encode_work), GFP_KERNEL);
+ encode_work->buf = buf_info;
+ encode_work->context = context;
+ INIT_WORK(&encode_work->work, vsg_encode_helper_func);
+ rc = queue_work(context->work_queue, &encode_work->work);
+ if (!rc) {
+ WFD_MSG_ERR("Queueing buffer for encode failed\n");
+ kfree(encode_work);
+ encode_work = NULL;
+ goto err_queue_encode_fail;
}
- mutex_lock(&context->mutex);
+ buf_info->flags |= VSG_BUF_BEING_ENCODED;
if (!(buf_info->flags & VSG_NEVER_SET_LAST_BUFFER)) {
bool is_same_buffer = context->last_buffer &&
mdp_buf_info_equals(
@@ -149,7 +173,7 @@
list_add_tail(&buf_info->node, &context->busy_queue.node);
err_skip_encode:
mutex_unlock(&context->mutex);
-err_encode_fail:
+err_queue_encode_fail:
kfree(work);
}
@@ -163,7 +187,7 @@
mutex_lock(&context->mutex);
- if (context->stopped)
+ if (context->state != VSG_STATE_STARTED)
goto err_locked;
if (list_empty(&context->free_queue.node)
@@ -280,7 +304,7 @@
context->last_buffer = context->regen_buffer = NULL;
context->send_regen_buffer = false;
context->mode = DEFAULT_MODE;
- context->stopped = false;
+ context->state = VSG_STATE_NONE;
mutex_init(&context->mutex);
sd->dev_priv = context;
@@ -311,6 +335,16 @@
}
context = (struct vsg_context *)sd->dev_priv;
+
+ if (context->state == VSG_STATE_STARTED) {
+ WFD_MSG_ERR("VSG not stopped, start not allowed\n");
+ return -EINPROGRESS;
+ } else if (context->state == VSG_STATE_ERROR) {
+ WFD_MSG_ERR("VSG in error state, not allowed to restart\n");
+ return -ENOTRECOVERABLE;
+ }
+
+ context->state = VSG_STATE_STARTED;
mod_timer(&context->threshold_timer, jiffies +
nsecs_to_jiffies(context->max_frame_interval));
return 0;
@@ -328,7 +362,7 @@
context = (struct vsg_context *)sd->dev_priv;
mutex_lock(&context->mutex);
- context->stopped = true;
+ context->state = VSG_STATE_STOPPED;
{ /*delete pending buffers as we're not going to encode them*/
struct list_head *pos, *next;
list_for_each_safe(pos, next, &context->free_queue.node) {
diff --git a/drivers/media/video/msm/wfd/vsg-subdev.h b/drivers/media/video/msm/wfd/vsg-subdev.h
index e6c731f..826105c 100644
--- a/drivers/media/video/msm/wfd/vsg-subdev.h
+++ b/drivers/media/video/msm/wfd/vsg-subdev.h
@@ -34,6 +34,13 @@
VSG_MODE_VFR,
};
+enum vsg_states {
+ VSG_STATE_NONE,
+ VSG_STATE_STARTED,
+ VSG_STATE_STOPPED,
+ VSG_STATE_ERROR
+};
+
struct vsg_buf_info {
struct mdp_buf_info mdp_buf_info;
struct timespec time;
@@ -59,7 +66,7 @@
struct vsg_buf_info *last_buffer, *regen_buffer;
bool send_regen_buffer;
int mode;
- bool stopped;
+ int state;
};
struct vsg_work {
@@ -67,6 +74,12 @@
struct work_struct work;
};
+struct vsg_encode_work {
+ struct vsg_buf_info *buf;
+ struct vsg_context *context;
+ struct work_struct work;
+};
+
#define VSG_OPEN _IO(VSG_MAGIC_IOCTL, 1)
#define VSG_CLOSE _IO(VSG_MAGIC_IOCTL, 2)
#define VSG_START _IO(VSG_MAGIC_IOCTL, 3)
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index ce81746..e38bb80 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.c
@@ -561,6 +561,11 @@
"V4L2_PIX_FMT_H264 are supported\n");
return -EINVAL;
}
+
+ if (fmt->fmt.pix.width % 16) {
+ WFD_MSG_ERR("Only 16 byte aligned widths are supported\n");
+ return -ENOTSUPP;
+ }
rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, SET_FORMAT,
(void *)fmt);
if (rc) {
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
index 17b518e..ac39e80 100644
--- a/drivers/mfd/pm8xxx-irq.c
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -449,7 +449,7 @@
return chip;
}
-int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+int pm8xxx_irq_exit(struct pm_irq_chip *chip)
{
irq_set_chained_handler(chip->devirq, NULL);
kfree(chip);
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index 191e079..022cfb6 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -1364,7 +1364,7 @@
{
const struct pm8xxx_pwm_platform_data *pdata = pdev->dev.platform_data;
struct pm8xxx_pwm_chip *chip;
- int i;
+ int i, dtest_channel;
enum pm8xxx_version version;
chip = kzalloc(sizeof *chip, GFP_KERNEL);
@@ -1373,6 +1373,11 @@
return -ENOMEM;
}
+ if (pdata != NULL)
+ dtest_channel = pdata->dtest_channel;
+ else
+ dtest_channel = -1;
+
mutex_init(&chip->pwm_mutex);
chip->dev = &pdev->dev;
@@ -1413,7 +1418,7 @@
for (i = 0; i < chip->pwm_channels; i++) {
chip->pwm_dev[i].pwm_id = i;
chip->pwm_dev[i].chip = chip;
- if (i == pdata->dtest_channel)
+ if (i == dtest_channel)
chip->pwm_dev[i].dtest_mode_supported = 1;
}
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index e4c3152..a8f9f35 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -199,7 +199,7 @@
};
static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
- struct qseecom_register_listener_req svc)
+ struct qseecom_register_listener_req *svc)
{
struct qseecom_registered_listener_list *ptr;
int unique = 1;
@@ -207,7 +207,7 @@
spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
- if (ptr->svc.listener_id == svc.listener_id) {
+ if (ptr->svc.listener_id == svc->listener_id) {
pr_err("Service id: %u is already registered\n",
ptr->svc.listener_id);
unique = 0;
@@ -333,16 +333,12 @@
pr_err("copy_from_user failed\n");
return ret;
}
-
- if (!__qseecom_is_svc_unique(data, rcvd_lstnr)) {
+ data->listener.id = 0;
+ data->service = true;
+ if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
pr_err("Service is not unique and is already registered\n");
- return ret;
- }
-
- ret = copy_to_user(argp, &rcvd_lstnr, sizeof(rcvd_lstnr));
- if (ret) {
- pr_err("copy_to_user failed\n");
- return ret;
+ data->released = true;
+ return -EBUSY;
}
new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
@@ -360,13 +356,14 @@
kzfree(new_entry);
return -ENOMEM;
}
+
data->listener.id = rcvd_lstnr.listener_id;
- data->service = true;
init_waitqueue_head(&new_entry->rcv_req_wq);
spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+
return ret;
}
@@ -743,6 +740,7 @@
break;
} else {
ptr_app->ref_cnt--;
+ data->released = true;
break;
}
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 03be6d0..122ffb5 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -299,10 +299,11 @@
mmc_card_ddr_mode(card) ? "DDR " : "",
type);
} else {
- printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
+ pr_info("%s: new %s%s%s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_sd_card_uhs(card) ? "ultra high speed " :
(mmc_card_highspeed(card) ? "high speed " : ""),
+ (mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_ddr_mode(card) ? "DDR " : "",
type, card->rca);
}
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 998797e..c1b0405 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -113,6 +113,9 @@
case MMC_TIMING_SD_HS:
str = "sd high-speed";
break;
+ case MMC_TIMING_MMC_HS200:
+ str = "mmc high-speed SDR200";
+ break;
default:
str = "invalid";
break;
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 0c70d4a..b7b899e6 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -283,6 +283,27 @@
}
card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+ case EXT_CSD_CARD_TYPE_SDR_ALL:
+ case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
+ case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
+ case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
+ card->ext_csd.hs_max_dtr = 200000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
+ break;
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
+ case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
+ card->ext_csd.hs_max_dtr = 200000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
+ break;
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
+ case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
+ card->ext_csd.hs_max_dtr = 200000000;
+ card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
+ break;
case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
EXT_CSD_CARD_TYPE_26:
card->ext_csd.hs_max_dtr = 52000000;
@@ -645,6 +666,79 @@
}
/*
+ * Selects the desired buswidth and switch to the HS200 mode
+ * if bus width set without error
+ */
+static int mmc_select_hs200(struct mmc_card *card)
+{
+ int idx, err = 0;
+ struct mmc_host *host;
+ static unsigned ext_csd_bits[] = {
+ EXT_CSD_BUS_WIDTH_4,
+ EXT_CSD_BUS_WIDTH_8,
+ };
+ static unsigned bus_widths[] = {
+ MMC_BUS_WIDTH_4,
+ MMC_BUS_WIDTH_8,
+ };
+
+ BUG_ON(!card);
+
+ host = card->host;
+
+ if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
+ host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
+ if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
+ err = mmc_set_signal_voltage(host,
+ MMC_SIGNAL_VOLTAGE_180, 0);
+
+ /* If fails try again during next card power cycle */
+ if (err)
+ goto err;
+
+ idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
+
+ /*
+ * Unlike SD, MMC cards dont have a configuration register to notify
+ * supported bus width. So bus test command should be run to identify
+ * the supported bus width or compare the ext csd values of current
+ * bus width and ext csd values of 1 bit mode read earlier.
+ */
+ for (; idx >= 0; idx--) {
+
+ /*
+ * Host is capable of 8bit transfer, then switch
+ * the device to work in 8bit transfer mode. If the
+ * mmc switch command returns error then switch to
+ * 4bit transfer mode. On success set the corresponding
+ * bus width on the host.
+ */
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_BUS_WIDTH,
+ ext_csd_bits[idx],
+ card->ext_csd.generic_cmd6_time);
+ if (err)
+ continue;
+
+ mmc_set_bus_width(card->host, bus_widths[idx]);
+
+ if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
+ err = mmc_compare_ext_csds(card, bus_widths[idx]);
+ else
+ err = mmc_bus_test(card, bus_widths[idx]);
+ if (!err)
+ break;
+ }
+
+ /* switch to HS200 mode if bus width set successfully */
+ if (!err)
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, 2, 0);
+err:
+ return err;
+}
+
+/*
* Handle the detection and initialisation of a card.
*
* In the case of a resume, "oldcard" will contain the card
@@ -848,11 +942,16 @@
/*
* Activate high speed (if supported)
*/
- if ((card->ext_csd.hs_max_dtr != 0) &&
- (host->caps & MMC_CAP_MMC_HIGHSPEED)) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HS_TIMING, 1,
- card->ext_csd.generic_cmd6_time);
+ if (card->ext_csd.hs_max_dtr != 0) {
+ err = 0;
+ if (card->ext_csd.hs_max_dtr > 52000000 &&
+ host->caps2 & MMC_CAP2_HS200)
+ err = mmc_select_hs200(card);
+ else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HS_TIMING, 1,
+ card->ext_csd.generic_cmd6_time);
+
if (err && err != -EBADMSG)
goto free_card;
@@ -861,33 +960,24 @@
mmc_hostname(card->host));
err = 0;
} else {
- mmc_card_set_highspeed(card);
- mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+ if (card->ext_csd.hs_max_dtr > 52000000 &&
+ host->caps2 & MMC_CAP2_HS200) {
+ mmc_card_set_hs200(card);
+ mmc_set_timing(card->host,
+ MMC_TIMING_MMC_HS200);
+ } else {
+ mmc_card_set_highspeed(card);
+ mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+ }
}
}
/*
- * Enable HPI feature (if supported)
- */
- if (card->ext_csd.hpi) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HPI_MGMT, 1, 0);
- if (err && err != -EBADMSG)
- goto free_card;
- if (err) {
- pr_warning("%s: Enabling HPI failed\n",
- mmc_hostname(card->host));
- err = 0;
- } else
- card->ext_csd.hpi_en = 1;
- }
-
- /*
* Compute bus speed.
*/
max_dtr = (unsigned int)-1;
- if (mmc_card_highspeed(card)) {
+ if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
if (max_dtr > card->ext_csd.hs_max_dtr)
max_dtr = card->ext_csd.hs_max_dtr;
} else if (max_dtr > card->csd.max_dtr) {
@@ -913,9 +1003,51 @@
}
/*
+ * Indicate HS200 SDR mode (if supported).
+ */
+ if (mmc_card_hs200(card)) {
+ u32 ext_csd_bits;
+ u32 bus_width = card->host->ios.bus_width;
+
+ /*
+ * For devices supporting HS200 mode, the bus width has
+ * to be set before executing the tuning function. If
+ * set before tuning, then device will respond with CRC
+ * errors for responses on CMD line. So for HS200 the
+ * sequence will be
+ * 1. set bus width 4bit / 8 bit (1 bit not supported)
+ * 2. switch to HS200 mode
+ * 3. set the clock to > 52Mhz <=200MHz and
+ * 4. execute tuning for HS200
+ */
+ if ((host->caps2 & MMC_CAP2_HS200) &&
+ card->host->ops->execute_tuning) {
+ mmc_host_clk_hold(card->host);
+ err = card->host->ops->execute_tuning(card->host,
+ MMC_SEND_TUNING_BLOCK_HS200);
+ mmc_host_clk_release(card->host);
+ }
+ if (err) {
+ pr_warning("%s: tuning execution failed\n",
+ mmc_hostname(card->host));
+ goto err;
+ }
+
+ ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
+ EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
+ err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+ if (err) {
+ pr_err("%s: power class selection to bus width %d failed\n",
+ mmc_hostname(card->host), 1 << bus_width);
+ goto err;
+ }
+ }
+
+ /*
* Activate wide bus and DDR (if supported).
*/
- if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
+ if (!mmc_card_hs200(card) &&
+ (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
static unsigned ext_csd_bits[][2] = {
{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
@@ -1014,6 +1146,23 @@
}
/*
+ * Enable HPI feature (if supported)
+ */
+ if (card->ext_csd.hpi) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_HPI_MGMT, 1,
+ card->ext_csd.generic_cmd6_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ if (err) {
+ pr_warning("%s: Enabling HPI failed\n",
+ mmc_hostname(card->host));
+ err = 0;
+ } else
+ card->ext_csd.hpi_en = 1;
+ }
+
+ /*
* If cache size is higher than 0, this indicates
* the existence of cache and it can be turned on.
*/
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6522efb..cd0eb4e 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -651,7 +651,8 @@
/* SPI mode doesn't define CMD19 */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
mmc_host_clk_hold(card->host);
- err = card->host->ops->execute_tuning(card->host);
+ err = card->host->ops->execute_tuning(card->host,
+ MMC_SEND_TUNING_BLOCK);
mmc_host_clk_release(card->host);
}
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 8ac2e59..1d6cf1d 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -14,6 +14,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e364eac..a1ad63e 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -134,6 +134,7 @@
u32 c);
static inline void msmsdcc_delay(struct msmsdcc_host *host);
static void msmsdcc_dump_sdcc_state(struct msmsdcc_host *host);
+static void msmsdcc_sg_start(struct msmsdcc_host *host);
static inline unsigned short msmsdcc_get_nr_sg(struct msmsdcc_host *host)
{
@@ -1076,21 +1077,15 @@
/* Is data transfer in PIO mode required? */
if (!(datactrl & MCI_DPSM_DMAENABLE)) {
- unsigned int sg_miter_flags = SG_MITER_ATOMIC;
-
if (data->flags & MMC_DATA_READ) {
- sg_miter_flags |= SG_MITER_TO_SG;
pio_irqmask = MCI_RXFIFOHALFFULLMASK;
if (host->curr.xfer_remain < MCI_FIFOSIZE)
pio_irqmask |= MCI_RXDATAAVLBLMASK;
- } else {
- sg_miter_flags |= SG_MITER_FROM_SG;
+ } else
pio_irqmask = MCI_TXFIFOHALFEMPTYMASK |
MCI_TXFIFOEMPTYMASK;
- }
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len,
- sg_miter_flags);
+ msmsdcc_sg_start(host);
}
if (data->flags & MMC_DATA_READ)
@@ -1250,6 +1245,144 @@
return ptr - buffer;
}
+/*
+ * Copy up to a word (4 bytes) between a scatterlist
+ * and a temporary bounce buffer when the word lies across
+ * two pages. The temporary buffer can then be read to/
+ * written from the FIFO once.
+ */
+static void _msmsdcc_sg_consume_word(struct msmsdcc_host *host)
+{
+ struct msmsdcc_pio_data *pio = &host->pio;
+ unsigned int bytes_avail;
+
+ if (host->curr.data->flags & MMC_DATA_READ)
+ memcpy(pio->sg_miter.addr, pio->bounce_buf,
+ pio->bounce_buf_len);
+ else
+ memcpy(pio->bounce_buf, pio->sg_miter.addr,
+ pio->bounce_buf_len);
+
+ while (pio->bounce_buf_len != 4) {
+ if (!sg_miter_next(&pio->sg_miter))
+ break;
+ bytes_avail = min_t(unsigned int, pio->sg_miter.length,
+ 4 - pio->bounce_buf_len);
+ if (host->curr.data->flags & MMC_DATA_READ)
+ memcpy(pio->sg_miter.addr,
+ &pio->bounce_buf[pio->bounce_buf_len],
+ bytes_avail);
+ else
+ memcpy(&pio->bounce_buf[pio->bounce_buf_len],
+ pio->sg_miter.addr, bytes_avail);
+
+ pio->sg_miter.consumed = bytes_avail;
+ pio->bounce_buf_len += bytes_avail;
+ }
+}
+
+/*
+ * Use sg_miter_next to return as many 4-byte aligned
+ * chunks as possible, using a temporary 4 byte buffer
+ * for alignment if necessary
+ */
+static int msmsdcc_sg_next(struct msmsdcc_host *host, char **buf, int *len)
+{
+ struct msmsdcc_pio_data *pio = &host->pio;
+ unsigned int length, rlength;
+ char *buffer;
+
+ if (!sg_miter_next(&pio->sg_miter))
+ return 0;
+
+ buffer = pio->sg_miter.addr;
+ length = pio->sg_miter.length;
+
+ if (length < host->curr.xfer_remain) {
+ rlength = round_down(length, 4);
+ if (rlength) {
+ /*
+ * We have a 4-byte aligned chunk.
+ * The rounding will be reflected by
+ * a call to msmsdcc_sg_consumed
+ */
+ length = rlength;
+ goto sg_next_end;
+ }
+ /*
+ * We have a length less than 4 bytes. Check to
+ * see if more buffer is available, and combine
+ * to make 4 bytes if possible.
+ */
+ pio->bounce_buf_len = length;
+ memset(pio->bounce_buf, 0, 4);
+
+ /*
+ * On a read, get 4 bytes from FIFO, and distribute
+ * (4-bouce_buf_len) bytes into consecutive
+ * sgl buffers when msmsdcc_sg_consumed is called
+ */
+ if (host->curr.data->flags & MMC_DATA_READ) {
+ buffer = pio->bounce_buf;
+ length = 4;
+ goto sg_next_end;
+ } else {
+ _msmsdcc_sg_consume_word(host);
+ buffer = pio->bounce_buf;
+ length = pio->bounce_buf_len;
+ }
+ }
+
+sg_next_end:
+ *buf = buffer;
+ *len = length;
+ return 1;
+}
+
+/*
+ * Update sg_miter.consumed based on how many bytes were
+ * consumed. If the bounce buffer was used to read from FIFO,
+ * redistribute into sgls.
+ */
+static void msmsdcc_sg_consumed(struct msmsdcc_host *host,
+ unsigned int length)
+{
+ struct msmsdcc_pio_data *pio = &host->pio;
+
+ if (host->curr.data->flags & MMC_DATA_READ) {
+ if (length > pio->sg_miter.consumed)
+ /*
+ * consumed 4 bytes, but sgl
+ * describes < 4 bytes
+ */
+ _msmsdcc_sg_consume_word(host);
+ else
+ pio->sg_miter.consumed = length;
+ } else
+ if (length < pio->sg_miter.consumed)
+ pio->sg_miter.consumed = length;
+}
+
+static void msmsdcc_sg_start(struct msmsdcc_host *host)
+{
+ unsigned int sg_miter_flags = SG_MITER_ATOMIC;
+
+ host->pio.bounce_buf_len = 0;
+
+ if (host->curr.data->flags & MMC_DATA_READ)
+ sg_miter_flags |= SG_MITER_TO_SG;
+ else
+ sg_miter_flags |= SG_MITER_FROM_SG;
+
+ sg_miter_start(&host->pio.sg_miter, host->curr.data->sg,
+ host->curr.data->sg_len, sg_miter_flags);
+}
+
+static void msmsdcc_sg_stop(struct msmsdcc_host *host)
+{
+ sg_miter_stop(&host->pio.sg_miter);
+}
+
static irqreturn_t
msmsdcc_pio_irq(int irq, void *dev_id)
{
@@ -1257,6 +1390,8 @@
void __iomem *base = host->base;
uint32_t status;
unsigned long flags;
+ unsigned int remain;
+ char *buffer;
spin_lock(&host->lock);
@@ -1267,45 +1402,43 @@
spin_unlock(&host->lock);
return IRQ_NONE;
}
-
#if IRQ_DEBUG
msmsdcc_print_status(host, "irq1-r", status);
#endif
local_irq_save(flags);
- while (sg_miter_next(&host->sg_miter)) {
-
- unsigned int remain, len;
- char *buffer;
+ do {
+ unsigned int len;
if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_TXFIFOEMPTY
| MCI_RXDATAAVLBL)))
break;
- buffer = host->sg_miter.addr;
- remain = host->sg_miter.length;
+ if (!msmsdcc_sg_next(host, &buffer, &remain))
+ break;
len = 0;
if (status & MCI_RXACTIVE)
len = msmsdcc_pio_read(host, buffer, remain);
if (status & MCI_TXACTIVE)
len = msmsdcc_pio_write(host, buffer, remain);
+
/* len might have aligned to 32bits above */
if (len > remain)
len = remain;
- host->sg_miter.consumed = len;
host->curr.xfer_remain -= len;
host->curr.data_xfered += len;
remain -= len;
+ msmsdcc_sg_consumed(host, len);
if (remain) /* Done with this page? */
break; /* Nope */
status = readl_relaxed(base + MMCISTATUS);
- }
+ } while (1);
- sg_miter_stop(&host->sg_miter);
+ msmsdcc_sg_stop(host);
local_irq_restore(flags);
if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) {
@@ -2877,15 +3010,22 @@
* Select the 3/4 of the range and configure the DLL with the
* selected DLL clock output phase.
*/
-static u8 find_most_appropriate_phase(struct msmsdcc_host *host,
+static int find_most_appropriate_phase(struct msmsdcc_host *host,
u8 *phase_table, u8 total_phases)
{
- u8 ret, ranges[16][16] = { {0}, {0} };
+ int ret;
+ u8 ranges[16][16] = { {0}, {0} };
u8 phases_per_row[16] = {0};
int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
bool phase_0_found = false, phase_15_found = false;
+ if (total_phases > 16) {
+ pr_err("%s: %s: invalid argument: total_phases=%d\n",
+ mmc_hostname(host->mmc), __func__, total_phases);
+ return -EINVAL;
+ }
+
for (cnt = 0; cnt < total_phases; cnt++) {
ranges[row_index][col_index] = phase_table[cnt];
phases_per_row[row_index] += 1;
@@ -2943,12 +3083,12 @@
}
i = ((curr_max * 3) / 4) - 1;
- ret = ranges[selected_row_index][i];
+ ret = (int)ranges[selected_row_index][i];
return ret;
}
-static int msmsdcc_execute_tuning(struct mmc_host *mmc)
+static int msmsdcc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
int rc = 0;
struct msmsdcc_host *host = mmc_priv(mmc);
@@ -3022,8 +3162,13 @@
} while (++phase < 16);
if (tuned_phase_cnt) {
- phase = find_most_appropriate_phase(host, tuned_phases,
+ rc = find_most_appropriate_phase(host, tuned_phases,
tuned_phase_cnt);
+ if (rc < 0)
+ goto kfree;
+ else
+ phase = (u8)rc;
+
/*
* Finally set the selected phase in delay
* line hw block.
diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h
index 319d721..8a728f2 100644
--- a/drivers/mmc/host/msm_sdcc.h
+++ b/drivers/mmc/host/msm_sdcc.h
@@ -281,9 +281,10 @@
};
struct msmsdcc_pio_data {
- struct scatterlist *sg;
- unsigned int sg_len;
- unsigned int sg_off;
+ struct sg_mapping_iter sg_miter;
+ char bounce_buf[4];
+ /* valid bytes in bounce_buf */
+ int bounce_buf_len;
};
struct msmsdcc_curr_req {
@@ -361,7 +362,7 @@
struct msmsdcc_sps_data sps;
bool is_dma_mode;
bool is_sps_mode;
- struct sg_mapping_iter sg_miter;
+ struct msmsdcc_pio_data pio;
#ifdef CONFIG_HAS_EARLYSUSPEND
struct early_suspend early_suspend;
diff --git a/drivers/mtd/devices/msm_nand.c b/drivers/mtd/devices/msm_nand.c
index 5ced423..2479a11 100644
--- a/drivers/mtd/devices/msm_nand.c
+++ b/drivers/mtd/devices/msm_nand.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google, Inc.
- * 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
@@ -6718,7 +6718,7 @@
supported_flash.pagesize = 1024 << (devcfg & 0x3);
supported_flash.blksize = (64 * 1024) <<
((devcfg >> 4) & 0x3);
- supported_flash.oobsize = (8 << ((devcfg >> 2) & 1)) *
+ supported_flash.oobsize = (8 << ((devcfg >> 2) & 0x3)) *
(supported_flash.pagesize >> 9);
} else {
supported_flash.flash_id = flash_id;
diff --git a/drivers/net/usb/rmnet_usb_ctrl.c b/drivers/net/usb/rmnet_usb_ctrl.c
index b693b18..5a016bb 100644
--- a/drivers/net/usb/rmnet_usb_ctrl.c
+++ b/drivers/net/usb/rmnet_usb_ctrl.c
@@ -264,19 +264,10 @@
{
int retval = 0;
- retval = usb_autopm_get_interface(dev->intf);
- if (retval < 0) {
- dev_err(dev->devicep, "%s Resumption fail\n", __func__);
- goto done_nopm;
- }
-
retval = usb_submit_urb(dev->inturb, GFP_KERNEL);
if (retval < 0)
dev_err(dev->devicep, "%s Intr submit %d\n", __func__, retval);
- usb_autopm_put_interface(dev->intf);
-
-done_nopm:
return retval;
}
@@ -342,35 +333,19 @@
}
static int rmnet_usb_ctrl_write_cmd(struct rmnet_ctrl_dev *dev)
{
- int retval = 0;
struct usb_device *udev;
if (!is_dev_connected(dev))
return -ENODEV;
udev = interface_to_usbdev(dev->intf);
- retval = usb_autopm_get_interface(dev->intf);
- if (retval < 0) {
- dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
- __func__, retval);
-
- /*
- * Revisit if (retval == -EPERM)
- * rmnet_usb_suspend(dev->intf, PMSG_SUSPEND);
- */
-
- return retval;
- }
dev->set_ctrl_line_state_cnt++;
- retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_CDC_REQ_SET_CONTROL_LINE_STATE,
(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE),
dev->cbits_tomdm,
dev->intf->cur_altsetting->desc.bInterfaceNumber,
NULL, 0, USB_CTRL_SET_TIMEOUT);
- usb_autopm_put_interface(dev->intf);
-
- return retval;
}
static void ctrl_write_callback(struct urb *urb)
@@ -428,7 +403,7 @@
(unsigned char *)out_ctlreq, (void *)buf, size,
ctrl_write_callback, dev);
- result = usb_autopm_get_interface_async(dev->intf);
+ result = usb_autopm_get_interface(dev->intf);
if (result < 0) {
dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
__func__, result);
@@ -450,7 +425,7 @@
dev_err(dev->devicep, "%s: Submit URB error %d\n",
__func__, result);
dev->snd_encap_cmd_cnt--;
- usb_autopm_put_interface_async(dev->intf);
+ usb_autopm_put_interface(dev->intf);
usb_unanchor_urb(sndurb);
usb_free_urb(sndurb);
kfree(out_ctlreq);
@@ -573,7 +548,7 @@
ctrl_read:
if (!is_dev_connected(dev)) {
- dev_err(dev->devicep, "%s: Device not connected\n",
+ dev_dbg(dev->devicep, "%s: Device not connected\n",
__func__);
return -ENETRESET;
}
@@ -662,6 +637,8 @@
static int rmnet_ctrl_tiocmset(struct rmnet_ctrl_dev *dev, unsigned int set,
unsigned int clear)
{
+ int retval;
+
mutex_lock(&dev->dev_lock);
if (set & TIOCM_DTR)
dev->cbits_tomdm |= ACM_CTRL_DTR;
@@ -681,7 +658,17 @@
mutex_unlock(&dev->dev_lock);
- return rmnet_usb_ctrl_write_cmd(dev);
+ retval = usb_autopm_get_interface(dev->intf);
+ if (retval < 0) {
+ dev_err(dev->devicep, "%s: Unable to resume interface: %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ retval = rmnet_usb_ctrl_write_cmd(dev);
+
+ usb_autopm_put_interface(dev->intf);
+ return retval;
}
static int rmnet_ctrl_tiocmget(struct rmnet_ctrl_dev *dev)
@@ -774,6 +761,10 @@
dev->tx_ctrl_err_cnt = 0;
dev->set_ctrl_line_state_cnt = 0;
+ ret = rmnet_usb_ctrl_write_cmd(dev);
+ if (ret < 0)
+ return ret;
+
dev->inturb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->inturb) {
dev_err(dev->devicep, "Error allocating int urb\n");
@@ -799,19 +790,15 @@
dev->intf->cur_altsetting->desc.bInterfaceNumber;
dev->in_ctlreq->wLength = cpu_to_le16(DEFAULT_READ_URB_LENGTH);
- interval =
- max((int)int_in->desc.bInterval,
- (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL : FS_LS_INTERVAL);
+ interval = max((int)int_in->desc.bInterval,
+ (udev->speed == USB_SPEED_HIGH) ? HS_INTERVAL
+ : FS_LS_INTERVAL);
usb_fill_int_urb(dev->inturb, udev,
dev->int_pipe,
dev->intbuf, wMaxPacketSize,
notification_available_cb, dev, interval);
- ret = rmnet_usb_ctrl_write_cmd(dev);
- if (ret < 0)
- return ret;
-
return rmnet_usb_ctrl_start_rx(dev);
}
@@ -828,6 +815,8 @@
dev->intf = NULL;
mutex_unlock(&dev->dev_lock);
+ wake_up(&dev->read_wait_queue);
+
usb_free_urb(dev->inturb);
dev->inturb = NULL;
diff --git a/drivers/net/usb/rmnet_usb_data.c b/drivers/net/usb/rmnet_usb_data.c
index 658b393..1eb6845 100644
--- a/drivers/net/usb/rmnet_usb_data.c
+++ b/drivers/net/usb/rmnet_usb_data.c
@@ -148,7 +148,6 @@
retval = usbnet_resume(iface);
if (!retval) {
-
if (oldstate & PM_EVENT_SUSPEND)
retval = rmnet_usb_ctrl_start(dev);
}
@@ -260,6 +259,12 @@
return 1;
}
+static int rmnet_usb_manage_power(struct usbnet *dev, int on)
+{
+ dev->intf->needs_remote_wakeup = on;
+ return 0;
+}
+
static int rmnet_change_mtu(struct net_device *dev, int new_mtu)
{
if (0 > new_mtu || RMNET_DATA_LEN < new_mtu)
@@ -501,6 +506,7 @@
.bind = rmnet_usb_bind,
.tx_fixup = rmnet_usb_tx_fixup,
.rx_fixup = rmnet_usb_rx_fixup,
+ .manage_power = rmnet_usb_manage_power,
.data = PID9034_IFACE_MASK,
};
@@ -509,6 +515,7 @@
.bind = rmnet_usb_bind,
.tx_fixup = rmnet_usb_tx_fixup,
.rx_fixup = rmnet_usb_rx_fixup,
+ .manage_power = rmnet_usb_manage_power,
.data = PID9048_IFACE_MASK,
};
@@ -517,6 +524,7 @@
.bind = rmnet_usb_bind,
.tx_fixup = rmnet_usb_tx_fixup,
.rx_fixup = rmnet_usb_rx_fixup,
+ .manage_power = rmnet_usb_manage_power,
.data = PID904C_IFACE_MASK,
};
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index c3a756d..2620108e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ctype.h>
@@ -332,7 +333,9 @@
usb_free_urb (urb);
return -ENOMEM;
}
- skb_reserve (skb, NET_IP_ALIGN);
+
+ if (dev->net->type != ARPHRD_RAWIP)
+ skb_reserve(skb, NET_IP_ALIGN);
entry = (struct skb_data *) skb->cb;
entry->urb = urb;
diff --git a/drivers/net/wireless/libra/libra_sdioif.c b/drivers/net/wireless/libra/libra_sdioif.c
index 3955642..3421f84 100644
--- a/drivers/net/wireless/libra/libra_sdioif.c
+++ b/drivers/net/wireless/libra/libra_sdioif.c
@@ -29,6 +29,37 @@
static suspend_handler_t *libra_suspend_hldr;
static resume_handler_t *libra_resume_hldr;
+int libra_enable_sdio_irq_in_chip(struct sdio_func *func, u8 enable)
+{
+ unsigned char reg = 0;
+ int err = 0;
+
+ sdio_claim_host(func);
+
+ /* Read the value into reg */
+ libra_sdiocmd52(func, SDIO_CCCR_IENx, ®, 0, &err);
+ if (err)
+ printk(KERN_ERR "%s: Could not read SDIO_CCCR_IENx register "
+ "err=%d\n", __func__, err);
+
+ if (libra_mmc_host) {
+ if (enable) {
+ reg |= 1 << func->num;
+ reg |= 1;
+ } else {
+ reg &= ~(1 << func->num);
+ }
+ libra_sdiocmd52(func, SDIO_CCCR_IENx, ®, 1, &err);
+ if (err)
+ printk(KERN_ERR "%s: Could not enable/disable irq "
+ "err=%d\n", __func__, err);
+ }
+ sdio_release_host(func);
+
+ return err;
+}
+EXPORT_SYMBOL(libra_enable_sdio_irq_in_chip);
+
/**
* libra_sdio_configure() - Function to configure the SDIO device param
* @libra_sdio_rxhandler Rx handler
@@ -89,6 +120,8 @@
goto cfg_error;
}
+ libra_enable_sdio_irq_in_chip(func, 0);
+
sdio_release_host(func);
return 0;
diff --git a/drivers/net/wireless/libra/qcomwlan_pwrif.c b/drivers/net/wireless/libra/qcomwlan_pwrif.c
index 6a0c78f..94ea0b3 100644
--- a/drivers/net/wireless/libra/qcomwlan_pwrif.c
+++ b/drivers/net/wireless/libra/qcomwlan_pwrif.c
@@ -154,7 +154,7 @@
/* WLAN VREG settings */
for (i = 0; i < ARRAY_SIZE(vregs_qwlan_name); i++) {
- if (vregs_qwlan[i] == NULL) {
+ if (on && !wlan_on) {
vregs_qwlan[i] = regulator_get(NULL,
vregs_qwlan_name[i]);
if (IS_ERR(vregs_qwlan[i])) {
@@ -187,8 +187,7 @@
goto vreg_fail;
}
}
- }
- if (on && !wlan_on) {
+
if (vregs_qwlan_peek_current[i]) {
rc = regulator_set_optimum_mode(vregs_qwlan[i],
vregs_qwlan_peek_current[i]);
diff --git a/drivers/net/wireless/wcnss/wcnss_riva.c b/drivers/net/wireless/wcnss/wcnss_riva.c
index 0939dd8..23365ff 100644
--- a/drivers/net/wireless/wcnss/wcnss_riva.c
+++ b/drivers/net/wireless/wcnss/wcnss_riva.c
@@ -61,7 +61,6 @@
};
static struct vregs_info iris_vregs[] = {
- {"iris_vddio", VREG_NULL_CONFIG, 1800000, 0, 1800000, 4000, NULL},
{"iris_vddxo", VREG_NULL_CONFIG, 1800000, 0, 1800000, 10000, NULL},
{"iris_vddrfa", VREG_NULL_CONFIG, 1300000, 0, 1300000, 100000, NULL},
{"iris_vddpa", VREG_NULL_CONFIG, 2900000, 0, 3000000, 515000, NULL},
diff --git a/drivers/of/of_spmi.c b/drivers/of/of_spmi.c
index 9f2a396..2032b46 100644
--- a/drivers/of/of_spmi.c
+++ b/drivers/of/of_spmi.c
@@ -19,62 +19,93 @@
#include <linux/slab.h>
#include <linux/module.h>
-/**
- * Allocate resources for a child of a spmi-container node.
- */
-static int of_spmi_allocate_resources(struct spmi_controller *ctrl,
- struct spmi_boardinfo *info,
- struct device_node *node,
- uint32_t num_reg)
+struct of_spmi_dev_info {
+ struct spmi_controller *ctrl;
+ struct spmi_boardinfo b_info;
+};
+
+struct of_spmi_res_info {
+ struct device_node *node;
+ uint32_t num_reg;
+ uint32_t num_irq;
+};
+
+static void of_spmi_sum_resources(struct of_spmi_res_info *r_info, bool has_reg)
{
- int i, num_irq = 0;
+ struct of_irq oirq;
uint64_t size;
uint32_t flags;
+
+ while (of_irq_map_one(r_info->node, r_info->num_irq, &oirq) == 0)
+ r_info->num_irq++;
+
+ if (!has_reg)
+ return;
+
+ /*
+ * We can't use of_address_to_resource here since it includes
+ * address translation; and address translation assumes that no
+ * parent buses have a size-cell of 0. But SPMI does have a
+ * size-cell of 0.
+ */
+ while (of_get_address(r_info->node, r_info->num_reg,
+ &size, &flags) != NULL)
+ r_info->num_reg++;
+}
+
+/**
+ * Allocate resources for a child of a spmi-slave node.
+ */
+static int of_spmi_allocate_resources(struct of_spmi_dev_info *d_info,
+ struct of_spmi_res_info *r_info)
+
+{
+ uint32_t num_irq = r_info->num_irq, num_reg = r_info->num_reg;
+ int i;
struct resource *res;
const __be32 *addrp;
- struct of_irq oirq;
-
- while (of_irq_map_one(node, num_irq, &oirq) == 0)
- num_irq++;
+ uint64_t size;
+ uint32_t flags;
if (num_irq || num_reg) {
res = kzalloc(sizeof(*res) * (num_irq + num_reg), GFP_KERNEL);
if (!res)
return -ENOMEM;
- info->num_resources = num_reg + num_irq;
- info->resource = res;
+ d_info->b_info.num_resources = num_reg + num_irq;
+ d_info->b_info.resource = res;
for (i = 0; i < num_reg; i++, res++) {
/* Addresses are always 16 bits */
- addrp = of_get_address(node, i, &size, &flags);
+ addrp = of_get_address(r_info->node, i, &size, &flags);
BUG_ON(!addrp);
res->start = be32_to_cpup(addrp);
res->end = res->start + size - 1;
res->flags = flags;
}
- WARN_ON(of_irq_to_resource_table(node, res, num_irq) !=
+ WARN_ON(of_irq_to_resource_table(r_info->node, res, num_irq) !=
num_irq);
}
return 0;
}
-static int of_spmi_create_device(struct spmi_controller *ctrl,
- struct spmi_boardinfo *info,
- struct device_node *node)
+static int of_spmi_create_device(struct of_spmi_dev_info *d_info,
+ struct device_node *node)
{
+ struct spmi_controller *ctrl = d_info->ctrl;
+ struct spmi_boardinfo *b_info = &d_info->b_info;
void *result;
int rc;
- rc = of_modalias_node(node, info->name, sizeof(info->name));
+ rc = of_modalias_node(node, b_info->name, sizeof(b_info->name));
if (rc < 0) {
dev_err(&ctrl->dev, "of_spmi modalias failure on %s\n",
node->full_name);
return rc;
}
- info->of_node = of_node_get(node);
- result = spmi_new_device(ctrl, info);
+ b_info->of_node = of_node_get(node);
+ result = spmi_new_device(ctrl, b_info);
if (result == NULL) {
dev_err(&ctrl->dev, "of_spmi: Failure registering %s\n",
@@ -86,32 +117,26 @@
return 0;
}
-static void of_spmi_walk_container_children(struct spmi_controller *ctrl,
- struct spmi_boardinfo *info,
- struct device_node *container)
+static void of_spmi_walk_slave_container(struct of_spmi_dev_info *d_info,
+ struct device_node *container)
{
+ struct spmi_controller *ctrl = d_info->ctrl;
struct device_node *node;
- uint64_t size;
- uint32_t flags, num_reg = 0;
int rc;
for_each_child_of_node(container, node) {
- /*
- * We can't use of_address_to_resource here since it includes
- * address translation; and address translation assumes that no
- * parent buses have a size-cell of 0. But SPMI does have a
- * size-cell of 0.
- */
- while (of_get_address(node, num_reg, &size, &flags) != NULL)
- num_reg++;
+ struct of_spmi_res_info r_info;
- rc = of_spmi_allocate_resources(ctrl, info, node, num_reg);
+ r_info.node = node;
+ of_spmi_sum_resources(&r_info, 1);
+
+ rc = of_spmi_allocate_resources(d_info, &r_info);
if (rc) {
dev_err(&ctrl->dev, "%s: unable to allocate"
" resources\n", __func__);
return;
}
- rc = of_spmi_create_device(ctrl, info, node);
+ rc = of_spmi_create_device(d_info, node);
if (rc) {
dev_err(&ctrl->dev, "%s: unable to create device for"
" node %s\n", __func__, node->full_name);
@@ -129,7 +154,7 @@
return -ENODEV;
for_each_child_of_node(ctrl->dev.of_node, node) {
- struct spmi_boardinfo info = {};
+ struct of_spmi_dev_info d_info = {};
const __be32 *slave_id;
int len, rc;
@@ -140,16 +165,21 @@
continue;
}
- info.slave_id = be32_to_cpup(slave_id);
+ d_info.b_info.slave_id = be32_to_cpup(slave_id);
+ d_info.ctrl = ctrl;
- if (of_get_property(node, "spmi-dev-container", NULL)) {
- of_spmi_walk_container_children(ctrl, &info, node);
+ if (of_get_property(node, "spmi-slave-container", NULL)) {
+ of_spmi_walk_slave_container(&d_info, node);
continue;
} else {
- rc = of_spmi_allocate_resources(ctrl, &info, node, 0);
+ struct of_spmi_res_info r_info;
+
+ r_info.node = node;
+ of_spmi_sum_resources(&r_info, 0);
+ rc = of_spmi_allocate_resources(&d_info, &r_info);
if (rc)
continue;
- of_spmi_create_device(ctrl, &info, node);
+ of_spmi_create_device(&d_info, node);
}
}
diff --git a/drivers/platform/msm/sps/bam.c b/drivers/platform/msm/sps/bam.c
index 4279603..edef402 100644
--- a/drivers/platform/msm/sps/bam.c
+++ b/drivers/platform/msm/sps/bam.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
@@ -20,6 +20,7 @@
#include "bam.h"
#include "sps_bam.h"
+#include "spsi.h"
/**
* Valid BAM Hardware version.
@@ -740,8 +741,11 @@
return -ENODEV;
}
- if (num_pipes > BAM_MAX_PIPES)
+ if (num_pipes > BAM_MAX_PIPES) {
+ SPS_ERR("sps:bam 0x%x(va) the number of pipes is more than "
+ "the maximum number allowed.", (u32) base);
return -ENODEV;
+ }
for (pipe = 0, mask = 1; pipe < num_pipes; pipe++, mask <<= 1)
if ((mask & pipe_mask) != 0)
@@ -764,8 +768,11 @@
{
u32 ver = 0;
- if (!bam_read_reg_field(base, CTRL, BAM_EN))
+ if (!bam_read_reg_field(base, CTRL, BAM_EN)) {
+ SPS_ERR("sps:%s:bam 0x%x(va) is not enabled.\n",
+ __func__, (u32) base);
return -ENODEV;
+ }
ver = bam_read_reg(base, REVISION) & BAM_REVISION;
@@ -778,8 +785,8 @@
/* Check BAM version */
if ((ver < BAM_MIN_VERSION) || (ver > BAM_MAX_VERSION)) {
- SPS_ERR("sps:bam 0x%x(va) Invalid BAM version 0x%x.\n",
- (u32) base, ver);
+ SPS_ERR("sps:%s:bam 0x%x(va) Invalid BAM version 0x%x.\n",
+ __func__, (u32) base, ver);
return -ENODEV;
}
@@ -866,7 +873,7 @@
bam_write_reg(base, P_EVNT_DEST_ADDR(pipe), peer_dest_addr);
- SPS_DBG("sps:bam=0x%x(va).pipe=%d.peer_bam=0x%x."
+ SPS_DBG2("sps:bam=0x%x(va).pipe=%d.peer_bam=0x%x."
"peer_pipe=%d.\n",
(u32) base, pipe,
(u32) param->peer_phys_addr,
@@ -1051,3 +1058,206 @@
{
return bam_read_reg(base, P_TIMER(pipe));
}
+
+#ifdef CONFIG_DEBUG_FS
+/* output the content of BAM-level registers */
+void print_bam_reg(void *virt_addr)
+{
+ int i, n;
+ u32 *bam = (u32 *) virt_addr;
+ u32 ctrl;
+ u32 ver;
+ u32 pipes;
+
+ if (bam == NULL)
+ return;
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ ctrl = bam[0x0 / 4];
+ ver = bam[0x4 / 4];
+ pipes = bam[0x3c / 4];
+#else
+ ctrl = bam[0xf80 / 4];
+ ver = bam[0xf84 / 4];
+ pipes = bam[0xfbc / 4];
+#endif
+
+ SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+
+ SPS_INFO("BAM_CTRL: 0x%x.\n", ctrl);
+ SPS_INFO("BAM_REVISION: 0x%x.\n", ver);
+ SPS_INFO("NUM_PIPES: 0x%x.\n", pipes);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ for (i = 0x0; i < 0x80; i += 0x10)
+#else
+ for (i = 0xf80; i < 0x1000; i += 0x10)
+#endif
+ SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+ bam[i / 4], bam[(i / 4) + 1],
+ bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ for (i = 0x800, n = 0; n++ < 8; i += 0x80)
+#else
+ for (i = 0x1800, n = 0; n++ < 4; i += 0x80)
+#endif
+ SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+ bam[i / 4], bam[(i / 4) + 1],
+ bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+ SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+}
+
+/* output the content of BAM pipe registers */
+void print_bam_pipe_reg(void *virt_addr, u32 pipe_index)
+{
+ int i;
+ u32 *bam = (u32 *) virt_addr;
+ u32 pipe = pipe_index;
+
+ if (bam == NULL)
+ return;
+
+ SPS_INFO("\nsps:----- Content of Pipe %d registers <begin> -----\n",
+ pipe);
+
+ SPS_INFO("-- Pipe Management Registers --\n");
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ for (i = 0x1000 + 0x1000 * pipe; i < 0x1000 + 0x1000 * pipe + 0x80;
+ i += 0x10)
+#else
+ for (i = 0x0000 + 0x80 * pipe; i < 0x0000 + 0x80 * (pipe + 1);
+ i += 0x10)
+#endif
+ SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+ bam[i / 4], bam[(i / 4) + 1],
+ bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+ SPS_INFO("-- Pipe Configuration and Internal State Registers --\n");
+
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ for (i = 0x1800 + 0x1000 * pipe; i < 0x1800 + 0x1000 * pipe + 0x40;
+ i += 0x10)
+#else
+ for (i = 0x1000 + 0x40 * pipe; i < 0x1000 + 0x40 * (pipe + 1);
+ i += 0x10)
+#endif
+ SPS_INFO("bam addr 0x%x: 0x%x,0x%x,0x%x,0x%x.\n", i,
+ bam[i / 4], bam[(i / 4) + 1],
+ bam[(i / 4) + 2], bam[(i / 4) + 3]);
+
+ SPS_INFO("\nsps:----- Content of Pipe %d registers <end> -----\n",
+ pipe);
+}
+
+/* output the content of selected BAM-level registers */
+void print_bam_selected_reg(void *virt_addr)
+{
+ void *base = virt_addr;
+
+ if (base == NULL)
+ return;
+
+ SPS_INFO("\nsps:----- Content of BAM-level registers <begin> -----\n");
+
+ SPS_INFO("BAM_CTRL: 0x%x\n"
+ "BAM_REVISION: 0x%x\n"
+ "BAM_NUM_EES: %d\n"
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ "BAM_CMD_DESC_EN: 0x%x\n"
+#endif
+ "BAM_NUM_PIPES: %d\n"
+ "BAM_DESC_CNT_TRSHLD: 0x%x (%d)\n"
+ "BAM_IRQ_SRCS: 0x%x\n"
+ "BAM_IRQ_SRCS_MSK: 0x%x\n"
+ "BAM_EE: %d\n"
+ "BAM_CNFG_BITS: 0x%x\n",
+ bam_read_reg(base, CTRL),
+ bam_read_reg_field(base, REVISION, BAM_REVISION),
+ bam_read_reg_field(base, REVISION, BAM_NUM_EES),
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ bam_read_reg_field(base, REVISION, BAM_CMD_DESC_EN),
+#endif
+ bam_read_reg_field(base, NUM_PIPES, BAM_NUM_PIPES),
+ bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
+ bam_read_reg_field(base, DESC_CNT_TRSHLD, BAM_DESC_CNT_TRSHLD),
+ bam_read_reg(base, IRQ_SRCS),
+ bam_read_reg(base, IRQ_SRCS_MSK),
+ bam_read_reg_field(base, TRUST_REG, BAM_EE),
+ bam_read_reg(base, CNFG_BITS));
+
+ SPS_INFO("\nsps:----- Content of BAM-level registers <end> -----\n");
+}
+
+/* output the content of selected BAM pipe registers */
+void print_bam_pipe_selected_reg(void *virt_addr, u32 pipe_index)
+{
+ void *base = virt_addr;
+ u32 pipe = pipe_index;
+
+ if (base == NULL)
+ return;
+
+ SPS_INFO("\nsps:----- Registers of Pipe %d -----\n", pipe);
+
+ SPS_INFO("BAM_P_CTRL: 0x%x\n"
+ "BAM_P_SYS_MODE: %d\n"
+ "BAM_P_DIRECTION: %d\n"
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ "BAM_P_LOCK_GROUP: 0x%x (%d)\n"
+#endif
+ "BAM_P_EE: %d\n"
+ "BAM_P_IRQ_STTS: 0x%x\n"
+ "BAM_P_IRQ_STTS_P_TRNSFR_END_IRQ: 0x%x\n"
+ "BAM_P_IRQ_STTS_P_PRCSD_DESC_IRQ: 0x%x\n"
+ "BAM_P_IRQ_EN: %d\n"
+ "BAM_P_PRDCR_SDBNDn_BAM_P_BYTES_FREE: 0x%x (%d)\n"
+ "BAM_P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL: 0x%x (%d)\n"
+ "BAM_P_SW_DESC_OFST: 0x%x\n"
+ "BAM_P_DESC_FIFO_PEER_OFST: 0x%x\n"
+ "BAM_P_EVNT_DEST_ADDR: 0x%x\n"
+ "BAM_P_DESC_FIFO_ADDR: 0x%x\n"
+ "BAM_P_DESC_FIFO_SIZE: 0x%x (%d)\n"
+ "BAM_P_DATA_FIFO_ADDR: 0x%x\n"
+ "BAM_P_DATA_FIFO_SIZE: 0x%x (%d)\n"
+ "BAM_P_EVNT_GEN_TRSHLD: 0x%x (%d)\n",
+ bam_read_reg(base, P_CTRL(pipe)),
+ bam_read_reg_field(base, P_CTRL(pipe), P_SYS_MODE),
+ bam_read_reg_field(base, P_CTRL(pipe), P_DIRECTION),
+#ifdef CONFIG_SPS_SUPPORT_NDP_BAM
+ bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
+ bam_read_reg_field(base, P_CTRL(pipe), P_LOCK_GROUP),
+#endif
+ bam_read_reg_field(base, P_TRUST_REG(pipe), BAM_P_EE),
+ bam_read_reg(base, P_IRQ_STTS(pipe)),
+ bam_read_reg_field(base, P_IRQ_STTS(pipe),
+ P_IRQ_STTS_P_TRNSFR_END_IRQ),
+ bam_read_reg_field(base, P_IRQ_STTS(pipe),
+ P_IRQ_STTS_P_PRCSD_DESC_IRQ),
+ bam_read_reg(base, P_IRQ_EN(pipe)),
+ bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+ P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
+ bam_read_reg_field(base, P_PRDCR_SDBND(pipe),
+ P_PRDCR_SDBNDn_BAM_P_BYTES_FREE),
+ bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
+ bam_read_reg_field(base, P_CNSMR_SDBND(pipe),
+ P_CNSMR_SDBNDn_BAM_P_BYTES_AVAIL),
+ bam_read_reg_field(base, P_SW_OFSTS(pipe), SW_DESC_OFST),
+ bam_read_reg_field(base, P_EVNT_REG(pipe),
+ P_DESC_FIFO_PEER_OFST),
+ bam_read_reg(base, P_EVNT_DEST_ADDR(pipe)),
+ bam_read_reg(base, P_DESC_FIFO_ADDR(pipe)),
+ bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
+ bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DESC_FIFO_SIZE),
+ bam_read_reg(base, P_DATA_FIFO_ADDR(pipe)),
+ bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
+ bam_read_reg_field(base, P_FIFO_SIZES(pipe), P_DATA_FIFO_SIZE),
+ bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
+ P_EVNT_GEN_TRSHLD_P_TRSHLD),
+ bam_read_reg_field(base, P_EVNT_GEN_TRSHLD(pipe),
+ P_EVNT_GEN_TRSHLD_P_TRSHLD));
+}
+#endif
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index c17da9b..b876d2d 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.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
@@ -82,18 +82,31 @@
static void sps_device_de_init(void);
#ifdef CONFIG_DEBUG_FS
-#define MAX_OUTPUT_MAGIC_NUM 777
-u32 sps_debugfs_enabled;
-u32 detailed_debug_on;
+u8 debugfs_record_enabled;
+u8 logging_option;
+u8 debug_level_option;
+u8 print_limit_option;
+u8 reg_dump_option;
+
static char *debugfs_buf;
-static int debugfs_buf_size;
-static int debugfs_buf_used;
+static u32 debugfs_buf_size;
+static u32 debugfs_buf_used;
static int wraparound;
+struct dentry *dent;
+struct dentry *dfile_info;
+struct dentry *dfile_logging_option;
+struct dentry *dfile_debug_level_option;
+struct dentry *dfile_print_limit_option;
+struct dentry *dfile_reg_dump_option;
+struct dentry *dfile_bam_addr;
+
+static struct sps_bam *phy2bam(u32 phys_addr);
+
/* record debug info for debugfs */
void sps_debugfs_record(const char *msg)
{
- if (sps_debugfs_enabled) {
+ if (debugfs_record_enabled) {
if (debugfs_buf_used + MAX_MSG_LEN >= debugfs_buf_size) {
debugfs_buf_used = 0;
wraparound = true;
@@ -112,30 +125,33 @@
static ssize_t sps_read_info(struct file *file, char __user *ubuf,
size_t count, loff_t *ppos)
{
- int ret;
+ int ret = 0;
int size;
- if (wraparound)
- size = debugfs_buf_size - MAX_MSG_LEN;
- else
- size = debugfs_buf_used;
+ if (debugfs_record_enabled) {
+ if (wraparound)
+ size = debugfs_buf_size - MAX_MSG_LEN;
+ else
+ size = debugfs_buf_used;
- ret = simple_read_from_buffer(ubuf, count, ppos,
- debugfs_buf, size);
+ ret = simple_read_from_buffer(ubuf, count, ppos,
+ debugfs_buf, size);
+ }
return ret;
}
/*
* set the buffer size (in KB) for debug info
- * if input is 0, then stop recording debug info into buffer
*/
static ssize_t sps_set_info(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long missing;
- static char str[5];
- int i, buf_size_kb = 0;
+ char str[MAX_MSG_LEN];
+ int i;
+ u32 buf_size_kb = 0;
+ u32 new_buf_size;
memset(str, 0, sizeof(str));
missing = copy_from_user(str, buf, sizeof(str));
@@ -145,37 +161,53 @@
for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
buf_size_kb = (buf_size_kb * 10) + (str[i] - '0');
- pr_info("sps:debugfs buffer size is %dKB\n", buf_size_kb);
+ pr_info("sps:debugfs: input buffer size is %dKB\n", buf_size_kb);
- if (sps_debugfs_enabled && (buf_size_kb == 0)) {
- sps_debugfs_enabled = false;
- detailed_debug_on = false;
- kfree(debugfs_buf);
- debugfs_buf = NULL;
- debugfs_buf_used = 0;
- debugfs_buf_size = 0;
- wraparound = false;
- } else if (!sps_debugfs_enabled && (buf_size_kb > 0)) {
- debugfs_buf_size = buf_size_kb * SZ_1K;
+ if ((logging_option == 0) || (logging_option == 2)) {
+ pr_info("sps:debugfs: need to first turn on recording.\n");
+ return -EFAULT;
+ }
- debugfs_buf = kzalloc(sizeof(char) * debugfs_buf_size,
- GFP_KERNEL);
- if (!debugfs_buf) {
- debugfs_buf_size = 0;
- pr_err("sps:fail to allocate memory for debug_fs.\n");
- return -ENOMEM;
+ if (buf_size_kb < 1) {
+ pr_info("sps:debugfs: buffer size should be "
+ "no less than 1KB.\n");
+ return -EFAULT;
+ }
+
+ new_buf_size = buf_size_kb * SZ_1K;
+
+ if (debugfs_record_enabled) {
+ if (debugfs_buf_size == new_buf_size) {
+ /* need do nothing */
+ pr_info("sps:debugfs: input buffer size "
+ "is the same as before.\n");
+ return count;
+ } else {
+ /* release the current buffer */
+ debugfs_record_enabled = false;
+ debugfs_buf_used = 0;
+ wraparound = false;
+ kfree(debugfs_buf);
+ debugfs_buf = NULL;
}
+ }
- if (buf_size_kb == MAX_OUTPUT_MAGIC_NUM)
- detailed_debug_on = true;
- sps_debugfs_enabled = true;
- debugfs_buf_used = 0;
- wraparound = false;
- } else if (sps_debugfs_enabled && (buf_size_kb > 0))
- pr_info("sps:should disable debugfs before change "
- "buffer size.\n");
+ /* allocate new buffer */
+ debugfs_buf_size = new_buf_size;
- return sps_debugfs_enabled;
+ debugfs_buf = kzalloc(sizeof(char) * debugfs_buf_size,
+ GFP_KERNEL);
+ if (!debugfs_buf) {
+ debugfs_buf_size = 0;
+ pr_err("sps:fail to allocate memory for debug_fs.\n");
+ return -ENOMEM;
+ }
+
+ debugfs_buf_used = 0;
+ wraparound = false;
+ debugfs_record_enabled = true;
+
+ return count;
}
const struct file_operations sps_info_ops = {
@@ -183,12 +215,136 @@
.write = sps_set_info,
};
-struct dentry *dent;
-struct dentry *dfile;
+/* return the current logging option to userspace */
+static ssize_t sps_read_logging_option(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char value[MAX_MSG_LEN];
+ int nbytes;
+
+ nbytes = snprintf(value, MAX_MSG_LEN, "%d\n", logging_option);
+
+ return simple_read_from_buffer(ubuf, count, ppos, value, nbytes);
+}
+
+/*
+ * set the logging option
+ */
+static ssize_t sps_set_logging_option(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ char str[MAX_MSG_LEN];
+ int i;
+ u8 option = 0;
+
+ memset(str, 0, sizeof(str));
+ missing = copy_from_user(str, buf, sizeof(str));
+ if (missing)
+ return -EFAULT;
+
+ for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
+ option = (option * 10) + (str[i] - '0');
+
+ pr_info("sps:debugfs: try to change logging option to %d\n", option);
+
+ if (option > 3) {
+ pr_err("sps:debugfs: invalid logging option:%d\n", option);
+ return count;
+ }
+
+ if (((option == 0) || (option == 2)) &&
+ ((logging_option == 1) || (logging_option == 3))) {
+ debugfs_record_enabled = false;
+ kfree(debugfs_buf);
+ debugfs_buf = NULL;
+ debugfs_buf_used = 0;
+ debugfs_buf_size = 0;
+ wraparound = false;
+ }
+
+ logging_option = option;
+
+ return count;
+}
+
+const struct file_operations sps_logging_option_ops = {
+ .read = sps_read_logging_option,
+ .write = sps_set_logging_option,
+};
+
+/*
+ * input the bam physical address
+ */
+static ssize_t sps_set_bam_addr(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long missing;
+ char str[MAX_MSG_LEN];
+ u32 i;
+ u32 bam_addr = 0;
+ struct sps_bam *bam;
+ u32 num_pipes = 0;
+ void *vir_addr;
+
+ memset(str, 0, sizeof(str));
+ missing = copy_from_user(str, buf, sizeof(str));
+ if (missing)
+ return -EFAULT;
+
+ for (i = 0; i < sizeof(str) && (str[i] >= '0') && (str[i] <= '9'); ++i)
+ bam_addr = (bam_addr * 10) + (str[i] - '0');
+
+ pr_info("sps:debugfs:input BAM physical address:0x%x\n", bam_addr);
+
+ bam = phy2bam(bam_addr);
+
+ if (bam == NULL) {
+ pr_err("sps:debugfs:BAM 0x%x is not registered.", bam_addr);
+ return count;
+ } else {
+ vir_addr = bam->base;
+ num_pipes = bam->props.num_pipes;
+ }
+
+ switch (reg_dump_option) {
+ case 1: /* output all registers of this BAM */
+ print_bam_reg(vir_addr);
+ for (i = 0; i < num_pipes; i++)
+ print_bam_pipe_reg(vir_addr, i);
+ break;
+ case 2: /* output BAM-level registers */
+ print_bam_reg(vir_addr);
+ break;
+ case 3: /* output selected BAM-level registers */
+ print_bam_selected_reg(vir_addr);
+ break;
+ case 4: /* output selected registers of all pipes */
+ for (i = 0; i < num_pipes; i++)
+ print_bam_pipe_selected_reg(vir_addr, i);
+ break;
+ case 5: /* output selected registers of some pipes */
+ print_bam_pipe_selected_reg(vir_addr, 4);
+ print_bam_pipe_selected_reg(vir_addr, 5);
+ break;
+ default:
+ pr_info("sps:no dump option is chosen yet.");
+ }
+
+ return count;
+}
+
+const struct file_operations sps_bam_addr_ops = {
+ .write = sps_set_bam_addr,
+};
+
static void sps_debugfs_init(void)
{
- sps_debugfs_enabled = false;
- detailed_debug_on = false;
+ debugfs_record_enabled = false;
+ logging_option = 0;
+ debug_level_option = 0;
+ print_limit_option = 0;
+ reg_dump_option = 0;
debugfs_buf_size = 0;
debugfs_buf_used = 0;
wraparound = false;
@@ -199,19 +355,83 @@
return;
}
- dfile = debugfs_create_file("info", 0444, dent, 0,
+ dfile_info = debugfs_create_file("info", 0666, dent, 0,
&sps_info_ops);
- if (!dfile || IS_ERR(dfile)) {
- pr_err("sps:fail to create the file for debug_fs.\n");
- debugfs_remove(dent);
- return;
+ if (!dfile_info || IS_ERR(dfile_info)) {
+ pr_err("sps:fail to create the file for debug_fs info.\n");
+ goto info_err;
}
+
+ dfile_logging_option = debugfs_create_file("logging_option", 0666,
+ dent, 0, &sps_logging_option_ops);
+ if (!dfile_logging_option || IS_ERR(dfile_logging_option)) {
+ pr_err("sps:fail to create the file for debug_fs "
+ "logging_option.\n");
+ goto logging_option_err;
+ }
+
+ dfile_debug_level_option = debugfs_create_u8("debug_level_option",
+ 0666, dent, &debug_level_option);
+ if (!dfile_debug_level_option || IS_ERR(dfile_debug_level_option)) {
+ pr_err("sps:fail to create the file for debug_fs "
+ "debug_level_option.\n");
+ goto debug_level_option_err;
+ }
+
+ dfile_print_limit_option = debugfs_create_u8("print_limit_option",
+ 0666, dent, &print_limit_option);
+ if (!dfile_print_limit_option || IS_ERR(dfile_print_limit_option)) {
+ pr_err("sps:fail to create the file for debug_fs "
+ "print_limit_option.\n");
+ goto print_limit_option_err;
+ }
+
+ dfile_reg_dump_option = debugfs_create_u8("reg_dump_option", 0666,
+ dent, ®_dump_option);
+ if (!dfile_reg_dump_option || IS_ERR(dfile_reg_dump_option)) {
+ pr_err("sps:fail to create the file for debug_fs "
+ "reg_dump_option.\n");
+ goto reg_dump_option_err;
+ }
+
+ dfile_bam_addr = debugfs_create_file("bam_addr", 0666,
+ dent, 0, &sps_bam_addr_ops);
+ if (!dfile_bam_addr || IS_ERR(dfile_bam_addr)) {
+ pr_err("sps:fail to create the file for debug_fs "
+ "bam_addr.\n");
+ goto bam_addr_err;
+ }
+
+ return;
+
+bam_addr_err:
+ debugfs_remove(dfile_reg_dump_option);
+reg_dump_option_err:
+ debugfs_remove(dfile_print_limit_option);
+print_limit_option_err:
+ debugfs_remove(dfile_debug_level_option);
+debug_level_option_err:
+ debugfs_remove(dfile_logging_option);
+logging_option_err:
+ debugfs_remove(dfile_info);
+info_err:
+ debugfs_remove(dent);
}
static void sps_debugfs_exit(void)
{
- if (dfile)
- debugfs_remove(dfile);
+ if (dfile_info)
+ debugfs_remove(dfile_info);
+ if (dfile_logging_option)
+ debugfs_remove(dfile_logging_option);
+ if (dfile_debug_level_option)
+ debugfs_remove(dfile_debug_level_option);
+ if (dfile_print_limit_option)
+ debugfs_remove(dfile_print_limit_option);
+ if (dfile_reg_dump_option)
+ debugfs_remove(dfile_reg_dump_option);
+ if (dfile_bam_addr)
+ debugfs_remove(dfile_bam_addr);
if (dent)
debugfs_remove(dent);
kfree(debugfs_buf);
@@ -235,13 +455,13 @@
struct sps_bam_props bamdma_props = {0};
#endif
- SPS_DBG("sps_device_init");
+ SPS_DBG("sps:sps_device_init");
success = false;
result = sps_mem_init(sps->pipemem_phys_base, sps->pipemem_size);
if (result) {
- SPS_ERR("SPS memory init failed");
+ SPS_ERR("sps:SPS memory init failed");
goto exit_err;
}
@@ -249,13 +469,13 @@
mutex_init(&sps->lock);
if (sps_rm_init(&sps->connection_ctrl, sps->options)) {
- SPS_ERR("Failed to init SPS resource manager");
+ SPS_ERR("sps:Fail to init SPS resource manager");
goto exit_err;
}
result = sps_bam_driver_init(sps->options);
if (result) {
- SPS_ERR("SPS BAM driver init failed");
+ SPS_ERR("sps:SPS BAM driver init failed");
goto exit_err;
}
@@ -266,11 +486,11 @@
sps->bamdma_bam_size);
if (!bamdma_props.virt_addr) {
- SPS_ERR("sps:Failed to IO map BAM-DMA BAM registers.\n");
+ SPS_ERR("sps:Fail to IO map BAM-DMA BAM registers.\n");
goto exit_err;
}
- SPS_DBG("sps:bamdma_bam.phys=0x%x.virt=0x%x.",
+ SPS_DBG2("sps:bamdma_bam.phys=0x%x.virt=0x%x.",
bamdma_props.phys_addr,
(u32) bamdma_props.virt_addr);
@@ -280,11 +500,11 @@
sps->bamdma_dma_size);
if (!bamdma_props.periph_virt_addr) {
- SPS_ERR("sps:Failed to IO map BAM-DMA peripheral reg.\n");
+ SPS_ERR("sps:Fail to IO map BAM-DMA peripheral reg.\n");
goto exit_err;
}
- SPS_DBG("sps:bamdma_dma.phys=0x%x.virt=0x%x.",
+ SPS_DBG2("sps:bamdma_dma.phys=0x%x.virt=0x%x.",
bamdma_props.periph_phys_addr,
(u32) bamdma_props.periph_virt_addr);
@@ -298,14 +518,14 @@
result = sps_dma_init(&bamdma_props);
if (result) {
- SPS_ERR("SPS BAM DMA driver init failed");
+ SPS_ERR("sps:SPS BAM DMA driver init failed");
goto exit_err;
}
#endif /* CONFIG_SPS_SUPPORT_BAMDMA */
result = sps_map_init(NULL, sps->options);
if (result) {
- SPS_ERR("SPS connection mapping init failed");
+ SPS_ERR("sps:SPS connection mapping init failed");
goto exit_err;
}
@@ -331,7 +551,7 @@
*/
static void sps_device_de_init(void)
{
- SPS_DBG("%s.", __func__);
+ SPS_DBG2("sps:%s.", __func__);
if (sps != NULL) {
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
@@ -339,7 +559,7 @@
#endif
/* Are there any remaining BAM registrations? */
if (!list_empty(&sps->bams_q))
- SPS_ERR("SPS de-init: BAMs are still registered");
+ SPS_ERR("sps:SPS de-init: BAMs are still registered");
sps_map_de_init();
@@ -390,7 +610,7 @@
static int sps_client_de_init(struct sps_pipe *client)
{
if (client->client_state != SPS_STATE_DISCONNECT) {
- SPS_ERR("De-init client in connected state: 0x%x",
+ SPS_ERR("sps:De-init client in connected state: 0x%x",
client->client_state);
return SPS_ERROR;
}
@@ -449,7 +669,7 @@
}
}
- SPS_INFO("sps: BAM device 0x%x is not registered yet.\n", phys_addr);
+ SPS_ERR("sps: BAM device 0x%x is not registered yet.\n", phys_addr);
return -ENODEV;
}
@@ -472,14 +692,16 @@
int sps_setup_bam2bam_fifo(struct sps_mem_buffer *mem_buffer,
u32 addr, u32 size, int use_offset)
{
- if ((mem_buffer == NULL) || (size == 0))
+ if ((mem_buffer == NULL) || (size == 0)) {
+ SPS_ERR("sps:invalid buffer address or size.");
return SPS_ERROR;
+ }
if (use_offset) {
if ((addr + size) <= sps->pipemem_size)
mem_buffer->phys_base = sps->pipemem_phys_base + addr;
else {
- SPS_ERR("sps: requested mem is out of "
+ SPS_ERR("sps:requested mem is out of "
"pipe mem range.\n");
return SPS_ERROR;
}
@@ -489,7 +711,7 @@
+ sps->pipemem_size))
mem_buffer->phys_base = addr;
else {
- SPS_ERR("sps: requested mem is out of "
+ SPS_ERR("sps:requested mem is out of "
"pipe mem range.\n");
return SPS_ERROR;
}
@@ -527,7 +749,7 @@
return bam;
}
- SPS_ERR("Can't find BAM device for handle 0x%x.", h);
+ SPS_ERR("sps:Can't find BAM device for handle 0x%x.", h);
return NULL;
}
@@ -549,7 +771,7 @@
bam = pipe->bam;
if (bam == NULL) {
- SPS_ERR("Connection not in connected state");
+ SPS_ERR("sps:Connection is not in connected state.");
return NULL;
}
@@ -559,7 +781,7 @@
pipe_index = pipe->pipe_index;
if (pipe_index >= bam->props.num_pipes ||
pipe != bam->pipes[pipe_index]) {
- SPS_ERR("Client not owner of BAM 0x%x pipe: %d (max %d)",
+ SPS_ERR("sps:Client not owner of BAM 0x%x pipe: %d (max %d)",
bam->props.phys_addr, pipe_index,
bam->props.num_pipes);
spin_unlock_irqrestore(&bam->connection_lock,
@@ -598,7 +820,7 @@
return -ENODEV;
if (!sps->is_ready) {
- SPS_ERR("sps_connect.sps driver not ready.\n");
+ SPS_ERR("sps:sps_connect:sps driver is not ready.\n");
return -EAGAIN;
}
@@ -614,12 +836,12 @@
bam = sps_h2bam(dev);
if (bam == NULL) {
- SPS_ERR("Invalid BAM device handle: 0x%x", dev);
+ SPS_ERR("sps:Invalid BAM device handle: 0x%x", dev);
result = SPS_ERROR;
goto exit_err;
}
- SPS_DBG("sps_connect: bam 0x%x src 0x%x dest 0x%x mode %s",
+ SPS_DBG2("sps:sps_connect: bam 0x%x src 0x%x dest 0x%x mode %s",
BAM_ID(bam),
connect->source,
connect->destination,
@@ -674,14 +896,18 @@
struct sps_bam *bam;
int result;
- if (pipe == NULL)
+ if (pipe == NULL) {
+ SPS_ERR("sps:Invalid pipe.");
return SPS_ERROR;
+ }
bam = pipe->bam;
- if (bam == NULL)
+ if (bam == NULL) {
+ SPS_ERR("sps:BAM device of this pipe is NULL.");
return SPS_ERROR;
+ }
- SPS_DBG("sps_disconnect: bam 0x%x src 0x%x dest 0x%x mode %s",
+ SPS_DBG2("sps:sps_disconnect: bam 0x%x src 0x%x dest 0x%x mode %s",
BAM_ID(bam),
pipe->connect.source,
pipe->connect.destination,
@@ -695,7 +921,7 @@
check = pipe->map->client_dest;
if (check != pipe) {
- SPS_ERR("Client context is corrupt");
+ SPS_ERR("sps:Client context is corrupt");
goto exit_err;
}
@@ -725,13 +951,13 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG2("sps:%s.", __func__);
if (sps == NULL)
return -ENODEV;
if (!sps->is_ready) {
- SPS_ERR("sps_connect.sps driver not ready.\n");
+ SPS_ERR("sps:sps_connect:sps driver not ready.\n");
return -EAGAIN;
}
@@ -742,7 +968,7 @@
result = sps_bam_pipe_reg_event(bam, pipe->pipe_index, reg);
sps_bam_unlock(bam);
if (result)
- SPS_ERR("Failed to register event for BAM 0x%x pipe %d",
+ SPS_ERR("sps:Fail to register event for BAM 0x%x pipe %d",
pipe->bam->props.phys_addr, pipe->pipe_index);
return result;
@@ -759,7 +985,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG2("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -783,7 +1009,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG2("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -807,7 +1033,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -832,7 +1058,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -857,7 +1083,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -880,7 +1106,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -903,7 +1129,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -925,13 +1151,13 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s: dev = 0x%x", __func__, dev);
+ SPS_DBG2("sps:%s: dev = 0x%x", __func__, dev);
mutex_lock(&sps->lock);
/* Search for the target BAM device */
bam = sps_h2bam(dev);
if (bam == NULL) {
- SPS_ERR("Invalid BAM device handle: 0x%x", dev);
+ SPS_ERR("sps:Invalid BAM device handle: 0x%x", dev);
result = SPS_ERROR;
goto exit_err;
}
@@ -940,7 +1166,7 @@
result = sps_bam_reset(bam);
mutex_unlock(&bam->lock);
if (result) {
- SPS_ERR("Failed to reset BAM device: 0x%x", dev);
+ SPS_ERR("sps:Fail to reset BAM device: 0x%x", dev);
goto exit_err;
}
@@ -960,7 +1186,7 @@
struct sps_pipe *pipe = h;
if (config == NULL) {
- SPS_ERR("Config pointer is NULL");
+ SPS_ERR("sps:Config pointer is NULL");
return SPS_ERROR;
}
@@ -981,7 +1207,7 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -1009,7 +1235,7 @@
int result;
if (owner != SPS_OWNER_REMOTE) {
- SPS_ERR("Unsupported ownership state: %d", owner);
+ SPS_ERR("sps:Unsupported ownership state: %d", owner);
return SPS_ERROR;
}
@@ -1053,16 +1279,20 @@
return -ENODEV;
if (!sps->is_ready) {
- SPS_ERR("sps_alloc_mem.sps driver not ready.\n");
+ SPS_ERR("sps:sps_alloc_mem:sps driver is not ready.");
return -EAGAIN;
}
- if (mem_buffer == NULL || mem_buffer->size == 0)
+ if (mem_buffer == NULL || mem_buffer->size == 0) {
+ SPS_ERR("sps:invalid memory buffer address or size");
return SPS_ERROR;
+ }
mem_buffer->phys_base = sps_mem_alloc_io(mem_buffer->size);
- if (mem_buffer->phys_base == SPS_ADDR_INVALID)
+ if (mem_buffer->phys_base == SPS_ADDR_INVALID) {
+ SPS_ERR("sps:invalid address of allocated memory");
return SPS_ERROR;
+ }
mem_buffer->base = spsi_get_mem_ptr(mem_buffer->phys_base);
@@ -1076,8 +1306,10 @@
*/
int sps_free_mem(struct sps_pipe *h, struct sps_mem_buffer *mem_buffer)
{
- if (mem_buffer == NULL || mem_buffer->phys_base == SPS_ADDR_INVALID)
+ if (mem_buffer == NULL || mem_buffer->phys_base == SPS_ADDR_INVALID) {
+ SPS_ERR("sps:invalid memory to free");
return SPS_ERROR;
+ }
sps_mem_free_io(mem_buffer->phys_base, mem_buffer->size);
@@ -1103,7 +1335,7 @@
/* BAM-DMA is registered internally during power-up */
if ((!sps->is_ready) && !(bam_props->options & SPS_BAM_OPT_BAMDMA)) {
- SPS_ERR("sps_register_bam_device.sps driver not ready.\n");
+ SPS_ERR("sps:sps_register_bam_device:sps driver not ready.\n");
return -EAGAIN;
}
@@ -1114,7 +1346,7 @@
manage = bam_props->manage & SPS_BAM_MGR_ACCESS_MASK;
if (manage != SPS_BAM_MGR_NONE) {
if (bam_props->virt_addr == NULL && bam_props->virt_size == 0) {
- SPS_ERR("Invalid properties for BAM: %x",
+ SPS_ERR("sps:Invalid properties for BAM: %x",
bam_props->phys_addr);
return SPS_ERROR;
}
@@ -1122,8 +1354,8 @@
if ((bam_props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
/* BAM global is configured by local processor */
if (bam_props->summing_threshold == 0) {
- SPS_ERR("Invalid device ctrl properties for BAM: %x",
- bam_props->phys_addr);
+ SPS_ERR("sps:Invalid device ctrl properties for "
+ "BAM: %x", bam_props->phys_addr);
return SPS_ERROR;
}
}
@@ -1139,7 +1371,8 @@
bam = phy2bam(bam_props->phys_addr);
if (bam != NULL) {
mutex_unlock(&sps->lock);
- SPS_ERR("BAM already registered: %x", bam->props.phys_addr);
+ SPS_ERR("sps:BAM is already registered: %x",
+ bam->props.phys_addr);
result = -EEXIST;
bam = NULL; /* Avoid error clean-up kfree(bam) */
goto exit_err;
@@ -1151,7 +1384,7 @@
/* Map the memory region */
virt_addr = ioremap(bam_props->phys_addr, bam_props->virt_size);
if (virt_addr == NULL) {
- SPS_ERR("Unable to map BAM IO memory: %x %x",
+ SPS_ERR("sps:Unable to map BAM IO mem:0x%x size:0x%x",
bam_props->phys_addr, bam_props->virt_size);
goto exit_err;
}
@@ -1159,7 +1392,7 @@
bam = kzalloc(sizeof(*bam), GFP_KERNEL);
if (bam == NULL) {
- SPS_ERR("Unable to allocate BAM device state: size 0x%x",
+ SPS_ERR("sps:Unable to allocate BAM device state: size 0x%x",
sizeof(*bam));
goto exit_err;
}
@@ -1181,7 +1414,7 @@
* to a non-zero value to insure EE zero globals are not
* modified.
*/
- SPS_INFO("Setting EE for BAM %x to non-zero",
+ SPS_DBG2("sps:Setting EE for BAM %x to non-zero",
bam_props->phys_addr);
bam->props.ee = 1;
}
@@ -1189,7 +1422,7 @@
ok = sps_bam_device_init(bam);
mutex_unlock(&bam->lock);
if (ok) {
- SPS_ERR("Failed to init BAM device: phys 0x%0x",
+ SPS_ERR("sps:Fail to init BAM device: phys 0x%0x",
bam->props.phys_addr);
goto exit_err;
}
@@ -1218,14 +1451,14 @@
if (sps_dma_device_init((u32) bam)) {
bam->props.options &= ~SPS_BAM_OPT_BAMDMA;
sps_deregister_bam_device((u32) bam);
- SPS_ERR("Failed to init BAM-DMA device: BAM phys 0x%0x",
+ SPS_ERR("sps:Fail to init BAM-DMA BAM: phys 0x%0x",
bam->props.phys_addr);
return SPS_ERROR;
}
}
#endif /* CONFIG_SPS_SUPPORT_BAMDMA */
- SPS_DBG("SPS registered BAM: phys 0x%x.", bam->props.phys_addr);
+ SPS_INFO("sps:BAM 0x%x is registered.", bam->props.phys_addr);
return 0;
}
@@ -1240,10 +1473,12 @@
struct sps_bam *bam;
bam = sps_h2bam(dev_handle);
- if (bam == NULL)
+ if (bam == NULL) {
+ SPS_ERR("sps:did not find a BAM for this handle");
return SPS_ERROR;
+ }
- SPS_DBG("SPS deregister BAM: phys 0x%x.", bam->props.phys_addr);
+ SPS_DBG2("sps:SPS deregister BAM: phys 0x%x.", bam->props.phys_addr);
/* If this BAM is attached to a BAM-DMA, init the BAM-DMA device */
#ifdef CONFIG_SPS_SUPPORT_BAMDMA
@@ -1283,10 +1518,12 @@
struct sps_bam *bam;
int result;
- if (h == NULL || iovec == NULL)
+ if (h == NULL || iovec == NULL) {
+ SPS_ERR("sps:invalid pipe or iovec");
return SPS_ERROR;
+ }
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -1312,10 +1549,12 @@
struct sps_bam *bam;
int result;
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
- if (h == NULL || timer_ctrl == NULL)
+ if (h == NULL || timer_ctrl == NULL) {
+ SPS_ERR("sps:invalid pipe or timer ctrl");
return SPS_ERROR;
+ }
bam = sps_bam_lock(pipe);
if (bam == NULL)
@@ -1340,7 +1579,7 @@
ctx = kzalloc(sizeof(struct sps_pipe), GFP_KERNEL);
if (ctx == NULL) {
- SPS_ERR("Allocate pipe context fail.");
+ SPS_ERR("sps:Fail to allocate pipe context.");
return NULL;
}
@@ -1439,9 +1678,10 @@
if (of_property_read_u32((&pdev->dev)->of_node,
"qcom,bam-dma-res-pipes",
- &sps->bamdma_restricted_pipes))
+ &sps->bamdma_restricted_pipes)) {
+ SPS_ERR("sps:Fail to get restricted bamdma pipes.\n");
return -EINVAL;
- else
+ } else
SPS_DBG("sps:bamdma_restricted_pipes=0x%x.",
sps->bamdma_restricted_pipes);
@@ -1489,17 +1729,19 @@
SPS_DBG("sps:msm_sps_probe.");
if (pdev->dev.of_node) {
- SPS_DBG("sps:get data from device tree.");
- ret = get_device_tree_data(pdev);
-
+ if (get_device_tree_data(pdev)) {
+ SPS_ERR("sps:Fail to get data from device tree.");
+ return -ENODEV;
+ } else
+ SPS_DBG("sps:get data from device tree.");
} else {
- SPS_DBG("sps:get platform data.");
- ret = get_platform_data(pdev);
+ if (get_platform_data(pdev)) {
+ SPS_ERR("sps:Fail to get platform data.");
+ return -ENODEV;
+ } else
+ SPS_DBG("sps:get platform data.");
}
- if (ret)
- return -ENODEV;
-
/* Create Device */
sps->dev_class = class_create(THIS_MODULE, SPS_DRV_NAME);
@@ -1574,7 +1816,7 @@
#endif
sps->is_ready = true;
- SPS_INFO("sps is ready.");
+ SPS_INFO("sps:sps is ready.");
return 0;
clk_err:
@@ -1590,7 +1832,7 @@
static int __devexit msm_sps_remove(struct platform_device *pdev)
{
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
device_destroy(sps->dev_class, sps->dev_num);
unregister_chrdev_region(sps->dev_num, 1);
@@ -1631,7 +1873,7 @@
sps_debugfs_init();
#endif
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
/* Allocate the SPS driver state struct */
sps = kzalloc(sizeof(*sps), GFP_KERNEL);
@@ -1650,7 +1892,7 @@
*/
static void __exit sps_exit(void)
{
- SPS_DBG("%s.", __func__);
+ SPS_DBG("sps:%s.", __func__);
platform_driver_unregister(&msm_sps_driver);
diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c
index cb5a0ee..e48f59b 100644
--- a/drivers/platform/msm/sps/sps_bam.c
+++ b/drivers/platform/msm/sps/sps_bam.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
@@ -102,7 +102,7 @@
for (n = 0; n < ARRAY_SIZE(opt_event_table); n++) {
if ((u32)opt_event_table[n].option !=
(u32)opt_event_table[n].pipe_irq) {
- SPS_ERR("SPS_O 0x%x != HAL IRQ 0x%x",
+ SPS_ERR("sps:SPS_O 0x%x != HAL IRQ 0x%x",
opt_event_table[n].option,
opt_event_table[n].pipe_irq);
return SPS_ERROR;
@@ -138,7 +138,7 @@
dev->props.ee,
mask);
- SPS_DBG("sps:bam_isr:bam=0x%x;source=0x%x;mask=0x%x.",
+ SPS_DBG1("sps:bam_isr:bam=0x%x;source=0x%x;mask=0x%x.",
BAM_ID(dev), source, mask);
/* Mask any non-local source */
@@ -146,6 +146,9 @@
} else {
/* If MTIs are used, must poll each active pipe */
source = dev->pipe_active_mask;
+
+ SPS_DBG1("sps:bam_isr for MTI:bam=0x%x;source=0x%x.",
+ BAM_ID(dev), source);
}
/* Process active pipe sources */
@@ -164,7 +167,7 @@
/* Process any inactive pipe sources */
if (source) {
- SPS_ERR("IRQ from BAM 0x%x inactive pipe(s) 0x%x",
+ SPS_ERR("sps:IRQ from BAM 0x%x inactive pipe(s) 0x%x",
BAM_ID(dev), source);
dev->irq_from_disabled_pipe++;
}
@@ -191,7 +194,7 @@
/* Is there any access to this BAM? */
if ((dev->props.manage & SPS_BAM_MGR_ACCESS_MASK) == SPS_BAM_MGR_NONE) {
- SPS_ERR("No local access to BAM 0x%x", BAM_ID(dev));
+ SPS_ERR("sps:No local access to BAM 0x%x", BAM_ID(dev));
return SPS_ERROR;
}
@@ -209,7 +212,7 @@
IRQF_TRIGGER_HIGH, "sps", dev);
if (result) {
- SPS_ERR("Failed to register BAM 0x%x IRQ %d",
+ SPS_ERR("sps:Failed to register BAM 0x%x IRQ %d",
BAM_ID(dev), dev->props.irq);
return SPS_ERROR;
}
@@ -223,11 +226,14 @@
result = enable_irq_wake(dev->props.irq);
if (result) {
- SPS_ERR("Failed to enable wakeup irq "
+ SPS_ERR("sps:Fail to enable wakeup irq "
"BAM 0x%x IRQ %d",
BAM_ID(dev), dev->props.irq);
return SPS_ERROR;
- }
+ } else
+ SPS_DBG2("sps:Enable wakeup irq for "
+ "BAM 0x%x IRQ %d",
+ BAM_ID(dev), dev->props.irq);
}
}
@@ -245,7 +251,7 @@
rc = bam_check(dev->base, &dev->version, &num_pipes);
if (rc) {
- SPS_ERR("Failed to init BAM 0x%x IRQ %d",
+ SPS_ERR("sps:Fail to init BAM 0x%x IRQ %d",
BAM_ID(dev), dev->props.irq);
return SPS_ERROR;
}
@@ -264,7 +270,7 @@
* must use MTI. Thus, force EE index to a non-zero value to
* insure that EE zero globals can't be modified.
*/
- SPS_ERR("sps: EE for satellite BAM must be set to non-zero");
+ SPS_ERR("sps:EE for satellite BAM must be set to non-zero.");
return SPS_ERROR;
}
@@ -278,7 +284,7 @@
MTIenabled) {
if (dev->props.irq_gen_addr == 0 ||
dev->props.irq_gen_addr == SPS_ADDR_INVALID) {
- SPS_ERR("MTI destination address not specified "
+ SPS_ERR("sps:MTI destination address not specified "
"for BAM 0x%x", BAM_ID(dev));
return SPS_ERROR;
}
@@ -287,13 +293,14 @@
if (num_pipes) {
dev->props.num_pipes = num_pipes;
- SPS_DBG("BAM 0x%x number of pipes reported by hw: %d",
+ SPS_DBG1("sps:BAM 0x%x number of pipes reported by hw: %d",
BAM_ID(dev), dev->props.num_pipes);
}
/* Check EE index */
if (!MTIenabled && dev->props.ee >= SPS_BAM_NUM_EES) {
- SPS_ERR("Invalid EE BAM 0x%x: %d", BAM_ID(dev), dev->props.ee);
+ SPS_ERR("sps:Invalid EE BAM 0x%x: %d", BAM_ID(dev),
+ dev->props.ee);
return SPS_ERROR;
}
@@ -305,7 +312,7 @@
struct sps_bam_sec_config_props *p_sec =
dev->props.p_sec_config_props;
if (p_sec == NULL) {
- SPS_ERR("EE config table is not specified for "
+ SPS_ERR("sps:EE config table is not specified for "
"BAM 0x%x", BAM_ID(dev));
return SPS_ERROR;
}
@@ -333,7 +340,7 @@
for (i = n + 1; i < SPS_BAM_NUM_EES; i++) {
if ((p_sec->ees[n].pipe_mask &
p_sec->ees[i].pipe_mask) != 0) {
- SPS_ERR("Overlapping pipe "
+ SPS_ERR("sps:Overlapping pipe "
"assignments for BAM "
"0x%x: EEs %d and %d",
BAM_ID(dev), n, i);
@@ -385,7 +392,7 @@
}
dev->state |= BAM_STATE_ENABLED;
- SPS_DBG("BAM 0x%x enabled: ver: %d, number of pipes: %d",
+ SPS_DBG2("sps:BAM 0x%x enabled: ver: %d, number of pipes: %d",
BAM_ID(dev), dev->version, dev->props.num_pipes);
return 0;
}
@@ -401,7 +408,7 @@
/* Is there any access to this BAM? */
if ((dev->props.manage & SPS_BAM_MGR_ACCESS_MASK) == SPS_BAM_MGR_NONE) {
- SPS_ERR("No local access to BAM 0x%x", BAM_ID(dev));
+ SPS_ERR("sps:No local access to BAM 0x%x", BAM_ID(dev));
return SPS_ERROR;
}
@@ -425,7 +432,7 @@
dev->state &= ~BAM_STATE_ENABLED;
- SPS_DBG("BAM 0x%x disabled", BAM_ID(dev));
+ SPS_DBG2("sps:BAM 0x%x disabled", BAM_ID(dev));
return 0;
}
@@ -436,7 +443,7 @@
int sps_bam_device_init(struct sps_bam *dev)
{
if (dev->props.virt_addr == NULL) {
- SPS_ERR("NULL BAM virtual address");
+ SPS_ERR("sps:NULL BAM virtual address");
return SPS_ERROR;
}
dev->base = (void *) dev->props.virt_addr;
@@ -444,7 +451,7 @@
if (dev->props.num_pipes == 0) {
/* Assume max number of pipes until BAM registers can be read */
dev->props.num_pipes = BAM_MAX_PIPES;
- SPS_DBG("BAM 0x%x: assuming max number of pipes: %d",
+ SPS_DBG2("sps:BAM 0x%x: assuming max number of pipes: %d",
BAM_ID(dev), dev->props.num_pipes);
}
@@ -459,10 +466,13 @@
spin_lock_init(&dev->connection_lock);
if ((dev->props.options & SPS_BAM_OPT_ENABLE_AT_BOOT))
- if (sps_bam_enable(dev))
+ if (sps_bam_enable(dev)) {
+ SPS_ERR("sps:Fail to enable bam device");
return SPS_ERROR;
+ }
- SPS_DBG("BAM device: phys 0x%x IRQ %d", BAM_ID(dev), dev->props.irq);
+ SPS_DBG2("sps:BAM device: phys 0x%x IRQ %d",
+ BAM_ID(dev), dev->props.irq);
return 0;
}
@@ -475,7 +485,7 @@
{
int result;
- SPS_DBG("BAM device DEINIT: phys 0x%x IRQ %d",
+ SPS_DBG2("sps:BAM device DEINIT: phys 0x%x IRQ %d",
BAM_ID(dev), dev->props.irq);
result = sps_bam_disable(dev);
@@ -493,7 +503,7 @@
u32 pipe_index;
int result;
- SPS_DBG("BAM device RESET: phys 0x%x IRQ %d",
+ SPS_DBG2("sps:BAM device RESET: phys 0x%x IRQ %d",
BAM_ID(dev), dev->props.irq);
/* If BAM is enabled, then disable */
@@ -504,7 +514,7 @@
pipe_index++) {
pipe = dev->pipes[pipe_index];
if (BAM_PIPE_IS_ASSIGNED(pipe)) {
- SPS_ERR("BAM device 0x%x RESET failed: "
+ SPS_ERR("sps:BAM device 0x%x RESET failed: "
"pipe %d in use",
BAM_ID(dev), pipe_index);
result = SPS_ERROR;
@@ -557,8 +567,8 @@
if (pipe_index == SPS_BAM_PIPE_INVALID) {
/* Allocate a pipe from the BAM */
if ((dev->props.manage & SPS_BAM_MGR_PIPE_NO_ALLOC)) {
- SPS_ERR("Restricted from allocating pipes on BAM 0x%x",
- BAM_ID(dev));
+ SPS_ERR("sps:Restricted from allocating pipes "
+ "on BAM 0x%x", BAM_ID(dev));
return SPS_BAM_PIPE_INVALID;
}
for (pipe_index = 0, pipe_mask = 1;
@@ -571,24 +581,24 @@
break; /* Found an available pipe */
}
if (pipe_index >= dev->props.num_pipes) {
- SPS_ERR("Failed to allocate pipe on BAM 0x%x",
+ SPS_ERR("sps:Fail to allocate pipe on BAM 0x%x",
BAM_ID(dev));
return SPS_BAM_PIPE_INVALID;
}
} else {
/* Check that client-specified pipe is available */
if (pipe_index >= dev->props.num_pipes) {
- SPS_ERR("Invalid pipe %d for allocate on BAM 0x%x",
+ SPS_ERR("sps:Invalid pipe %d for allocate on BAM 0x%x",
pipe_index, BAM_ID(dev));
return SPS_BAM_PIPE_INVALID;
}
if ((dev->props.restricted_pipes & (1UL << pipe_index))) {
- SPS_ERR("BAM 0x%x pipe %d is not local",
+ SPS_ERR("sps:BAM 0x%x pipe %d is not local",
BAM_ID(dev), pipe_index);
return SPS_BAM_PIPE_INVALID;
}
if (dev->pipes[pipe_index] != NULL) {
- SPS_ERR("Pipe %d already allocated on BAM 0x%x",
+ SPS_ERR("sps:Pipe %d already allocated on BAM 0x%x",
pipe_index, BAM_ID(dev));
return SPS_BAM_PIPE_INVALID;
}
@@ -609,7 +619,8 @@
struct sps_pipe *pipe;
if (pipe_index >= dev->props.num_pipes) {
- SPS_ERR("Invalid BAM 0x%x pipe: %d", BAM_ID(dev), pipe_index);
+ SPS_ERR("sps:Invalid BAM 0x%x pipe: %d", BAM_ID(dev),
+ pipe_index);
return;
}
@@ -619,8 +630,8 @@
/* Is the pipe currently allocated? */
if (pipe == NULL) {
- SPS_ERR("Attempt to free unallocated pipe %d on BAM 0x%x",
- pipe_index, BAM_ID(dev));
+ SPS_ERR("sps:Attempt to free unallocated pipe %d on "
+ "BAM 0x%x", pipe_index, BAM_ID(dev));
return;
}
@@ -631,7 +642,7 @@
if (!list_empty(&pipe->sys.events_q)) {
struct sps_q_event *sps_event;
- SPS_ERR("Disconnect BAM 0x%x pipe %d with events pending",
+ SPS_ERR("sps:Disconnect BAM 0x%x pipe %d with events pending",
BAM_ID(dev), pipe_index);
sps_event = list_entry((&pipe->sys.events_q)->next,
@@ -695,7 +706,8 @@
dev = map_pipe->bam;
pipe_index = map_pipe->pipe_index;
if (pipe_index >= dev->props.num_pipes) {
- SPS_ERR("Invalid BAM 0x%x pipe: %d", BAM_ID(dev), pipe_index);
+ SPS_ERR("sps:Invalid BAM 0x%x pipe: %d", BAM_ID(dev),
+ pipe_index);
return SPS_ERROR;
}
hw_params.event_threshold = (u16) map_pipe->event_threshold;
@@ -704,14 +716,14 @@
/* Verify that control of this pipe is allowed */
if ((dev->props.manage & SPS_BAM_MGR_PIPE_NO_CTRL) ||
(dev->props.restricted_pipes & (1UL << pipe_index))) {
- SPS_ERR("BAM 0x%x pipe %d is not local",
+ SPS_ERR("sps:BAM 0x%x pipe %d is not local",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
/* Control without configuration permission is not supported yet */
if ((dev->props.manage & SPS_BAM_MGR_PIPE_NO_CONFIG)) {
- SPS_ERR("BAM 0x%x pipe %d remote config is not supported",
+ SPS_ERR("sps:BAM 0x%x pipe %d remote config is not supported",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
@@ -729,8 +741,8 @@
if (map->desc.phys_base == SPS_ADDR_INVALID ||
map->data.phys_base == SPS_ADDR_INVALID ||
map->desc.size == 0 || map->data.size == 0) {
- SPS_ERR("FIFO buffers are not allocated for BAM 0x%x "
- "pipe %d", BAM_ID(dev), pipe_index);
+ SPS_ERR("sps:FIFO buffers are not allocated for BAM "
+ "0x%x pipe %d.", BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
hw_params.data_base = map->data.phys_base;
@@ -754,7 +766,7 @@
/* Get virtual address for descriptor FIFO */
if (map->desc.phys_base != SPS_ADDR_INVALID) {
if (map->desc.size < (2 * sizeof(struct sps_iovec))) {
- SPS_ERR("Invalid descriptor FIFO size "
+ SPS_ERR("sps:Invalid descriptor FIFO size "
"for BAM 0x%x pipe %d: %d",
BAM_ID(dev), pipe_index, map->desc.size);
return SPS_ERROR;
@@ -788,19 +800,19 @@
/* Check pipe allocation */
if (dev->pipes[pipe_index] != BAM_PIPE_UNASSIGNED) {
- SPS_ERR("Invalid pipe %d on BAM 0x%x for connect",
+ SPS_ERR("sps:Invalid pipe %d on BAM 0x%x for connect",
pipe_index, BAM_ID(dev));
goto exit_err;
}
if (bam_pipe_is_enabled(dev->base, pipe_index)) {
- SPS_ERR("BAM 0x%x pipe %d sharing violation",
+ SPS_ERR("sps:BAM 0x%x pipe %d sharing violation",
BAM_ID(dev), pipe_index);
goto exit_err;
}
if (bam_pipe_init(dev->base, pipe_index, &hw_params, dev->props.ee)) {
- SPS_ERR("BAM 0x%x pipe %d init error",
+ SPS_ERR("sps:BAM 0x%x pipe %d init error",
BAM_ID(dev), pipe_index);
goto exit_err;
}
@@ -870,7 +882,8 @@
int result;
if (pipe_index >= dev->props.num_pipes) {
- SPS_ERR("Invalid BAM 0x%x pipe: %d", BAM_ID(dev), pipe_index);
+ SPS_ERR("sps:Invalid BAM 0x%x pipe: %d", BAM_ID(dev),
+ pipe_index);
return SPS_ERROR;
}
@@ -895,7 +908,7 @@
}
if (result)
- SPS_ERR("BAM 0x%x pipe %d already disconnected",
+ SPS_ERR("sps:BAM 0x%x pipe %d already disconnected",
BAM_ID(dev), pipe_index);
return result;
@@ -938,7 +951,7 @@
irq_enable = BAM_DISABLE;
pipe->polled = true;
if (poll == 0 && pipe->irq_mask)
- SPS_INFO("BAM 0x%x pipe %d forced to use polling",
+ SPS_DBG2("sps:BAM 0x%x pipe %d forced to use polling",
BAM_ID(dev), pipe_index);
}
if ((pipe->state & BAM_STATE_MTI) == 0)
@@ -984,7 +997,7 @@
if (pipe->sys.desc_wr_count > 0 &&
(no_queue != pipe->sys.no_queue
|| ack_xfers != pipe->sys.ack_xfers)) {
- SPS_ERR("Queue/ack mode change after transfer: "
+ SPS_ERR("sps:Queue/ack mode change after transfer: "
"BAM 0x%x pipe %d opt 0x%x",
BAM_ID(dev), pipe_index, options);
return SPS_ERROR;
@@ -994,7 +1007,7 @@
/* Is client setting invalid options for a BAM-to-BAM connection? */
if ((pipe->state & BAM_STATE_BAM2BAM) &&
(options & BAM2BAM_O_INVALID)) {
- SPS_ERR("Invalid option for BAM-to-BAM: BAM 0x%x pipe %d "
+ SPS_ERR("sps:Invalid option for BAM-to-BAM: BAM 0x%x pipe %d "
"opt 0x%x", BAM_ID(dev), pipe_index, options);
return SPS_ERROR;
}
@@ -1008,7 +1021,7 @@
kzalloc(pipe->desc_size + size, GFP_KERNEL);
if (pipe->sys.desc_cache == NULL) {
/*** MUST BE LAST POINT OF FAILURE (see below) *****/
- SPS_ERR("Desc cache error: BAM 0x%x pipe %d: %d",
+ SPS_ERR("sps:Desc cache error: BAM 0x%x pipe %d: %d",
BAM_ID(dev), pipe_index,
pipe->desc_size + size);
return SPS_ERROR;
@@ -1079,7 +1092,7 @@
if (pipe->sys.no_queue && reg->xfer_done != NULL &&
reg->mode != SPS_TRIGGER_CALLBACK) {
- SPS_ERR("Only callback events support for NO_Q: "
+ SPS_ERR("sps:Only callback events support for NO_Q: "
"BAM 0x%x pipe %d mode %d",
BAM_ID(dev), pipe_index, reg->mode);
return SPS_ERROR;
@@ -1094,7 +1107,7 @@
index = SPS_EVENT_INDEX(opt_event_table[n].event_id);
if (index < 0)
- SPS_ERR("Negative event index: "
+ SPS_ERR("sps:Negative event index: "
"BAM 0x%x pipe %d mode %d",
BAM_ID(dev), pipe_index, reg->mode);
else {
@@ -1124,7 +1137,7 @@
/* Is this a BAM-to-BAM or satellite connection? */
if ((pipe->state & (BAM_STATE_BAM2BAM | BAM_STATE_REMOTE))) {
- SPS_ERR("Transfer on BAM-to-BAM: BAM 0x%x pipe %d",
+ SPS_ERR("sps:Transfer on BAM-to-BAM: BAM 0x%x pipe %d",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
@@ -1134,7 +1147,7 @@
* SPS_O_NO_Q option.
*/
if (pipe->sys.no_queue && user != NULL) {
- SPS_ERR("User pointer arg non-NULL: BAM 0x%x pipe %d",
+ SPS_ERR("sps:User pointer arg non-NULL: BAM 0x%x pipe %d",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
@@ -1153,13 +1166,13 @@
if (!pipe->sys.ack_xfers && pipe->polled) {
pipe_handler_eot(dev, pipe);
if (next_write == pipe->sys.acked_offset) {
- SPS_DBG("Descriptor FIFO is full for "
- "BAM 0x%x pipe %d",
+ SPS_DBG2("sps:Descriptor FIFO is full for BAM "
+ "0x%x pipe %d after pipe_handler_eot",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
} else {
- SPS_DBG("Descriptor FIFO is full for "
+ SPS_DBG2("sps:Descriptor FIFO is full for "
"BAM 0x%x pipe %d", BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
@@ -1236,14 +1249,14 @@
int result;
if (transfer->iovec_count == 0) {
- SPS_ERR("iovec count zero: BAM 0x%x pipe %d",
+ SPS_ERR("sps:iovec count zero: BAM 0x%x pipe %d",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
sps_bam_get_free_count(dev, pipe_index, &count);
if (count < transfer->iovec_count) {
- SPS_ERR("Insufficient free desc: BAM 0x%x pipe %d: %d",
+ SPS_ERR("sps:Insufficient free desc: BAM 0x%x pipe %d: %d",
BAM_ID(dev), pipe_index, count);
return SPS_ERROR;
}
@@ -1669,7 +1682,7 @@
struct sps_q_event *event_queue;
if (pipe->sys.no_queue) {
- SPS_ERR("Invalid connection for event: "
+ SPS_ERR("sps:Invalid connection for event: "
"BAM 0x%x pipe %d context 0x%x",
BAM_ID(dev), pipe_index, (u32) pipe);
notify->event_id = SPS_EVENT_INVALID;
@@ -1774,7 +1787,7 @@
/* Is this a satellite connection? */
if ((pipe->state & BAM_STATE_REMOTE)) {
- SPS_ERR("Is empty on remote: BAM 0x%x pipe %d",
+ SPS_ERR("sps:Is empty on remote: BAM 0x%x pipe %d",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
@@ -1813,8 +1826,8 @@
/* Is this a BAM-to-BAM or satellite connection? */
if ((pipe->state & (BAM_STATE_BAM2BAM | BAM_STATE_REMOTE))) {
- SPS_ERR("Free count on BAM-to-BAM or remote: BAM 0x%x pipe %d",
- BAM_ID(dev), pipe_index);
+ SPS_ERR("sps:Free count on BAM-to-BAM or remote: BAM "
+ "0x%x pipe %d", BAM_ID(dev), pipe_index);
*count = 0;
return SPS_ERROR;
}
@@ -1849,14 +1862,14 @@
*/
if ((dev->props.manage & SPS_BAM_MGR_MULTI_EE) == 0 ||
(dev->props.manage & SPS_BAM_MGR_DEVICE_REMOTE)) {
- SPS_ERR("Cannot grant satellite control to BAM 0x%x pipe %d",
- BAM_ID(dev), pipe_index);
+ SPS_ERR("sps:Cannot grant satellite control to BAM 0x%x "
+ "pipe %d", BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
/* Is this pipe locally controlled? */
if ((dev->pipe_active_mask & (1UL << pipe_index)) == 0) {
- SPS_ERR("BAM 0x%x pipe %d not local and active",
+ SPS_ERR("sps:BAM 0x%x pipe %d not local and active",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
@@ -1904,7 +1917,7 @@
/* Is this pipe locally controlled? */
if ((dev->pipe_active_mask & (1UL << pipe_index)) == 0) {
- SPS_ERR("BAM 0x%x pipe %d not local and active",
+ SPS_ERR("sps:BAM 0x%x pipe %d not local and active",
BAM_ID(dev), pipe_index);
return SPS_ERROR;
}
diff --git a/drivers/platform/msm/sps/sps_bam.h b/drivers/platform/msm/sps/sps_bam.h
index 3af891e..70e7898 100644
--- a/drivers/platform/msm/sps/sps_bam.h
+++ b/drivers/platform/msm/sps/sps_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
@@ -26,7 +26,6 @@
#include "spsi.h"
-#define BAM_MAX_PIPES 31
#define BAM_HANDLE_INVALID 0
enum bam_irq {
diff --git a/drivers/platform/msm/sps/sps_dma.c b/drivers/platform/msm/sps/sps_dma.c
index 48c7ffd..bfb5981 100644
--- a/drivers/platform/msm/sps/sps_dma.c
+++ b/drivers/platform/msm/sps/sps_dma.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
@@ -65,7 +65,7 @@
static inline void dma_write_reg(void *base, u32 offset, u32 val)
{
iowrite32(val, base + offset);
- SPS_DBG("bamdma: write reg 0x%x w_val 0x%x.", offset, val);
+ SPS_DBG("sps:bamdma: write reg 0x%x w_val 0x%x.", offset, val);
}
/**
@@ -86,7 +86,7 @@
tmp &= ~mask; /* clear written bits */
val = tmp | (val << shift);
iowrite32(val, base + offset);
- SPS_DBG("bamdma: write reg 0x%x w_val 0x%x.", offset, val);
+ SPS_DBG("sps:bamdma: write reg 0x%x w_val 0x%x.", offset, val);
}
/* Round max number of pipes to nearest multiple of 2 */
@@ -210,7 +210,8 @@
/* Enable BAM device */
if (sps_bam_enable(dev->bam)) {
- SPS_ERR("Failed to enable BAM DMA's BAM: %x", dev->phys_addr);
+ SPS_ERR("sps:Failed to enable BAM DMA's BAM: %x",
+ dev->phys_addr);
return SPS_ERROR;
}
@@ -243,7 +244,7 @@
}
if (pipe_index < dev->num_pipes) {
- SPS_ERR("Failed to disable BAM-DMA %x: channels are active",
+ SPS_ERR("sps:Fail to disable BAM-DMA %x:channels are active",
dev->phys_addr);
return SPS_ERROR;
}
@@ -252,7 +253,7 @@
/* Disable BAM device */
if (sps_bam_disable(dev->bam)) {
- SPS_ERR("Failed to disable BAM-DMA %x BAM", dev->phys_addr);
+ SPS_ERR("sps:Fail to disable BAM-DMA BAM:%x", dev->phys_addr);
return SPS_ERROR;
}
@@ -280,7 +281,7 @@
/* Find a free BAM-DMA device slot */
dev = NULL;
if (bam_dma_dev[0].bam != NULL) {
- SPS_ERR("BAM-DMA BAM device already initialized.");
+ SPS_ERR("sps:BAM-DMA BAM device is already initialized.");
goto exit_err;
} else {
dev = &bam_dma_dev[0];
@@ -292,7 +293,8 @@
dev->bam = sps_h2bam(h);
if (dev->bam == NULL) {
- SPS_ERR("BAM-DMA BAM device is not found from the handle.");
+ SPS_ERR("sps:BAM-DMA BAM device is not found "
+ "from the handle.");
goto exit_err;
}
@@ -304,7 +306,7 @@
dev->virtual_mapped = false;
} else {
if (props->periph_virt_size == 0) {
- SPS_ERR("Unable to map BAM DMA IO memory: %x %x",
+ SPS_ERR("sps:Unable to map BAM DMA IO memory: %x %x",
dev->phys_addr, props->periph_virt_size);
goto exit_err;
}
@@ -312,7 +314,7 @@
dev->virt_addr = ioremap(dev->phys_addr,
props->periph_virt_size);
if (dev->virt_addr == NULL) {
- SPS_ERR("Unable to map BAM DMA IO memory: %x %x",
+ SPS_ERR("sps:Unable to map BAM DMA IO memory: %x %x",
dev->phys_addr, props->periph_virt_size);
goto exit_err;
}
@@ -322,11 +324,11 @@
/* Is the BAM-DMA device locally controlled? */
if ((props->manage & SPS_BAM_MGR_DEVICE_REMOTE) == 0) {
- SPS_DBG("BAM-DMA is controlled locally: %x",
+ SPS_DBG2("sps:BAM-DMA is controlled locally: %x",
dev->phys_addr);
dev->local = true;
} else {
- SPS_DBG("BAM-DMA is controlled remotely: %x",
+ SPS_DBG2("sps:BAM-DMA is controlled remotely: %x",
dev->phys_addr);
dev->local = false;
}
@@ -379,7 +381,7 @@
dev = sps_dma_find_device(h);
if (dev == NULL) {
- SPS_ERR("BAM-DMA: not registered: %x", h);
+ SPS_ERR("sps:BAM-DMA: not registered: %x", h);
result = SPS_ERROR;
goto exit_err;
}
@@ -387,14 +389,15 @@
/* Check for channel leaks */
for (chan = 0; chan < dev->num_pipes / 2; chan++) {
if (dev->chans[chan].state != DMA_CHAN_STATE_FREE) {
- SPS_ERR("BAM-DMA: channel not free: %d", chan);
+ SPS_ERR("sps:BAM-DMA: channel not free: %d", chan);
result = SPS_ERROR;
dev->chans[chan].state = DMA_CHAN_STATE_FREE;
}
}
for (pipe_index = 0; pipe_index < dev->num_pipes; pipe_index++) {
if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
- SPS_ERR("BAM-DMA: pipe not inactive: %d", pipe_index);
+ SPS_ERR("sps:BAM-DMA: pipe not inactive: %d",
+ pipe_index);
result = SPS_ERROR;
dev->pipes[pipe_index] = PIPE_INACTIVE;
}
@@ -446,7 +449,7 @@
bam_reg = bam_props;
if ((bam_props->options & SPS_BAM_OPT_BAMDMA) &&
(bam_props->manage & SPS_BAM_MGR_MULTI_EE) == 0) {
- SPS_DBG("Setting multi-EE options for BAM-DMA: %x",
+ SPS_DBG("sps:Setting multi-EE options for BAM-DMA: %x",
bam_props->phys_addr);
props = *bam_props;
props.manage |= SPS_BAM_MGR_MULTI_EE;
@@ -455,7 +458,7 @@
/* Register the BAM */
if (sps_register_bam_device(bam_reg, &h)) {
- SPS_ERR("Failed to register BAM-DMA BAM device: "
+ SPS_ERR("sps:Fail to register BAM-DMA BAM device: "
"phys 0x%0x", bam_props->phys_addr);
return SPS_ERROR;
}
@@ -465,11 +468,12 @@
bam_handles[num_bams] = h;
num_bams++;
} else {
- SPS_ERR("BAM-DMA: BAM limit exceeded: %d", num_bams);
+ SPS_ERR("sps:BAM-DMA: BAM limit exceeded: %d",
+ num_bams);
return SPS_ERROR;
}
} else {
- SPS_ERR("BAM-DMA phys_addr is zero.");
+ SPS_ERR("sps:BAM-DMA phys_addr is zero.");
return SPS_ERROR;
}
@@ -510,7 +514,7 @@
int result = SPS_ERROR;
if (alloc == NULL || chan_info == NULL) {
- SPS_ERR("sps_alloc_dma_chan. invalid parameters");
+ SPS_ERR("sps:sps_alloc_dma_chan. invalid parameters");
return SPS_ERROR;
}
@@ -529,7 +533,7 @@
weight = alloc->priority;
if ((u32)alloc->priority > (u32)BAM_DMA_WEIGHT_HIGH) {
- SPS_ERR("BAM-DMA: invalid priority: %x", alloc->priority);
+ SPS_ERR("sps:BAM-DMA: invalid priority: %x", alloc->priority);
return SPS_ERROR;
}
@@ -537,7 +541,7 @@
dev = sps_dma_find_device(alloc->dev);
if (dev == NULL) {
- SPS_ERR("BAM-DMA: invalid BAM handle: %x", alloc->dev);
+ SPS_ERR("sps:BAM-DMA: invalid BAM handle: %x", alloc->dev);
goto exit_err;
}
@@ -548,7 +552,8 @@
/* Just check pipes for safety */
if (dev->pipes[pipe_index] != PIPE_INACTIVE ||
dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
- SPS_ERR("BAM-DMA: channel %d state error:%d %d",
+ SPS_ERR("sps:BAM-DMA: channel %d state "
+ "error:%d %d",
pipe_index / 2, dev->pipes[pipe_index],
dev->pipes[pipe_index + 1]);
goto exit_err;
@@ -558,7 +563,7 @@
}
if (pipe_index >= dev->num_pipes) {
- SPS_ERR("BAM-DMA: no free channel. num_pipes = %d",
+ SPS_ERR("sps:BAM-DMA: no free channel. num_pipes = %d",
dev->num_pipes);
goto exit_err;
}
@@ -572,7 +577,7 @@
chan->priority = alloc->priority;
chan->weight = weight;
- SPS_DBG("sps_alloc_dma_chan. pipe %d.\n", pipe_index);
+ SPS_DBG2("sps:sps_alloc_dma_chan. pipe %d.\n", pipe_index);
/* Report allocated pipes to client */
chan_info->dev = dev->h;
@@ -600,7 +605,7 @@
int result = 0;
if (chan == NULL) {
- SPS_ERR("sps_free_dma_chan. chan is NULL");
+ SPS_ERR("sps:sps_free_dma_chan. chan is NULL");
return SPS_ERROR;
}
@@ -608,7 +613,7 @@
dev = sps_dma_find_device(chan->dev);
if (dev == NULL) {
- SPS_ERR("BAM-DMA: invalid BAM handle: %x", chan->dev);
+ SPS_ERR("sps:BAM-DMA: invalid BAM handle: %x", chan->dev);
result = SPS_ERROR;
goto exit_err;
}
@@ -617,8 +622,8 @@
pipe_index = chan->dest_pipe_index;
if (pipe_index >= dev->num_pipes || ((pipe_index & 1)) ||
(pipe_index + 1) != chan->src_pipe_index) {
- SPS_ERR("sps_free_dma_chan. Invalid pipe indices");
- SPS_DBG("num_pipes=%d.dest=%d.src=%d.",
+ SPS_ERR("sps:sps_free_dma_chan. Invalid pipe indices."
+ "num_pipes=%d.dest=%d.src=%d.",
dev->num_pipes,
chan->dest_pipe_index,
chan->src_pipe_index);
@@ -630,7 +635,7 @@
if (dev->chans[pipe_index / 2].state != DMA_CHAN_STATE_ALLOC_EXT ||
dev->pipes[pipe_index] != PIPE_INACTIVE ||
dev->pipes[pipe_index + 1] != PIPE_INACTIVE) {
- SPS_ERR("BAM-DMA: attempt to free active chan %d: %d %d",
+ SPS_ERR("sps:BAM-DMA: attempt to free active chan %d: %d %d",
pipe_index / 2, dev->pipes[pipe_index],
dev->pipes[pipe_index + 1]);
result = SPS_ERROR;
@@ -695,14 +700,14 @@
int result = SPS_ERROR;
if (bam == NULL) {
- SPS_ERR("BAM context is NULL");
+ SPS_ERR("sps:BAM context is NULL");
return SPS_ERROR;
}
/* Check pipe direction */
if ((DMA_PIPE_IS_DEST(pipe_index) && dir != SPS_MODE_DEST) ||
(DMA_PIPE_IS_SRC(pipe_index) && dir != SPS_MODE_SRC)) {
- SPS_ERR("BAM-DMA: wrong direction for BAM %x pipe %d",
+ SPS_ERR("sps:BAM-DMA: wrong direction for BAM %x pipe %d",
bam->props.phys_addr, pipe_index);
return SPS_ERROR;
}
@@ -711,17 +716,17 @@
dev = sps_dma_find_device((u32) bam);
if (dev == NULL) {
- SPS_ERR("BAM-DMA: invalid BAM: %x",
+ SPS_ERR("sps:BAM-DMA: invalid BAM: %x",
bam->props.phys_addr);
goto exit_err;
}
if (pipe_index >= dev->num_pipes) {
- SPS_ERR("BAM-DMA: BAM %x invalid pipe: %d",
+ SPS_ERR("sps:BAM-DMA: BAM %x invalid pipe: %d",
bam->props.phys_addr, pipe_index);
goto exit_err;
}
if (dev->pipes[pipe_index] != PIPE_INACTIVE) {
- SPS_ERR("BAM-DMA: BAM %x pipe %d already active",
+ SPS_ERR("sps:BAM-DMA: BAM %x pipe %d already active",
bam->props.phys_addr, pipe_index);
goto exit_err;
}
@@ -756,22 +761,22 @@
u32 channel;
int result = SPS_ERROR;
- SPS_DBG("sps_dma_pipe_enable.pipe %d", pipe_index);
+ SPS_DBG2("sps:sps_dma_pipe_enable.pipe %d", pipe_index);
mutex_lock(&bam_dma_lock);
dev = sps_dma_find_device((u32) bam);
if (dev == NULL) {
- SPS_ERR("BAM-DMA: invalid BAM");
+ SPS_ERR("sps:BAM-DMA: invalid BAM");
goto exit_err;
}
if (pipe_index >= dev->num_pipes) {
- SPS_ERR("BAM-DMA: BAM %x invalid pipe: %d",
+ SPS_ERR("sps:BAM-DMA: BAM %x invalid pipe: %d",
bam->props.phys_addr, pipe_index);
goto exit_err;
}
if (dev->pipes[pipe_index] != PIPE_ACTIVE) {
- SPS_ERR("BAM-DMA: BAM %x pipe %d not active",
+ SPS_ERR("sps:BAM-DMA: BAM %x pipe %d not active",
bam->props.phys_addr, pipe_index);
goto exit_err;
}
@@ -836,7 +841,7 @@
if (dev->pipes[pipe_index] != PIPE_ACTIVE)
return SPS_ERROR; /* Pipe is not active */
- SPS_DBG("BAM-DMA: deactivate pipe %d", pipe_index);
+ SPS_DBG2("sps:BAM-DMA: deactivate pipe %d", pipe_index);
/* Mark pipe inactive */
dev->pipes[pipe_index] = PIPE_INACTIVE;
@@ -873,7 +878,7 @@
dev = sps_dma_find_device((u32) bam);
if (dev == NULL) {
- SPS_ERR("BAM-DMA: invalid BAM");
+ SPS_ERR("sps:BAM-DMA: invalid BAM");
result = SPS_ERROR;
goto exit_err;
}
diff --git a/drivers/platform/msm/sps/sps_map.c b/drivers/platform/msm/sps/sps_map.c
index 16d5065..d98a8b1 100644
--- a/drivers/platform/msm/sps/sps_map.c
+++ b/drivers/platform/msm/sps/sps_map.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
@@ -50,7 +50,7 @@
maps->src.periph_phy_addr == SPS_ADDR_INVALID)
break;
- SPS_DBG("SPS driver: %d mappings", sps_maps.num_maps);
+ SPS_DBG("sps: %d mappings", sps_maps.num_maps);
return 0;
}
@@ -96,7 +96,7 @@
*/
desc = spsi_get_mem_ptr(map->desc_base);
if (desc == NULL) {
- SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+ SPS_ERR("sps:Cannot get virt addr for I/O buffer: 0x%x",
map->desc_base);
return SPS_ERROR;
}
@@ -104,7 +104,7 @@
if (map->data_size > 0 && map->data_base != SPS_ADDR_INVALID) {
data = spsi_get_mem_ptr(map->data_base);
if (data == NULL) {
- SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+ SPS_ERR("sps:Can't get virt addr for I/O buffer: 0x%x",
map->data_base);
return SPS_ERROR;
}
diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c
index 358dbd3..1b19b12 100644
--- a/drivers/platform/msm/sps/sps_mem.c
+++ b/drivers/platform/msm/sps/sps_mem.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
@@ -74,7 +74,7 @@
return SPS_ADDR_INVALID;
}
- SPS_DBG("sps:sps_mem_alloc_io.phys=0x%x.virt=0x%x.size=0x%x.",
+ SPS_DBG2("sps:sps_mem_alloc_io.phys=0x%x.virt=0x%x.size=0x%x.",
phys_addr, virt_addr, bytes);
return phys_addr;
@@ -91,7 +91,7 @@
iomem_offset = phys_addr - iomem_phys;
virt_addr = (u32) iomem_virt + iomem_offset;
- SPS_DBG("sps:sps_mem_free_io.phys=0x%x.virt=0x%x.size=0x%x.",
+ SPS_DBG2("sps:sps_mem_free_io.phys=0x%x.virt=0x%x.size=0x%x.",
phys_addr, virt_addr, bytes);
gen_pool_free(pool, virt_addr, bytes);
diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c
index ac1f4d1..75194e0 100644
--- a/drivers/platform/msm/sps/sps_rm.c
+++ b/drivers/platform/msm/sps/sps_rm.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
@@ -70,7 +70,7 @@
map->refs--;
if (map->refs <= 0) {
if (map->client_src != NULL || map->client_dest != NULL)
- SPS_ERR("Failed to allocate connection struct");
+ SPS_ERR("sps:Failed to allocate connection struct");
list_del(&map->list);
kfree(map);
@@ -179,14 +179,17 @@
/* Check ownership and BAM */
if ((cfg->mode == SPS_MODE_SRC && map->client_src != NULL) ||
- (cfg->mode != SPS_MODE_SRC && map->client_dest != NULL))
- /* The end point is already connected */
+ (cfg->mode != SPS_MODE_SRC && map->client_dest != NULL)) {
+ SPS_ERR("sps:The end point is already connected.\n");
return SPS_ERROR;
+ }
/* Check whether this end point is a BAM (not memory) */
if ((cfg->mode == SPS_MODE_SRC && map->src.bam == NULL) ||
- (cfg->mode != SPS_MODE_SRC && map->dest.bam == NULL))
+ (cfg->mode != SPS_MODE_SRC && map->dest.bam == NULL)) {
+ SPS_ERR("sps:The end point is empty.\n");
return SPS_ERROR;
+ }
/* Record the connection assignment */
if (cfg->mode == SPS_MODE_SRC) {
@@ -355,7 +358,7 @@
/* Allocate new connection */
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (map == NULL) {
- SPS_ERR("Failed to allocate connection struct");
+ SPS_ERR("sps:Failed to allocate connection struct");
return NULL;
}
@@ -369,7 +372,7 @@
map->src.bam = sps_h2bam(map->src.dev);
if (map->src.bam == NULL) {
if (map->src.dev != SPS_DEV_HANDLE_MEM) {
- SPS_ERR("Invalid BAM handle: 0x%x", map->src.dev);
+ SPS_ERR("sps:Invalid BAM handle: 0x%x", map->src.dev);
goto exit_err;
}
map->src.pipe_index = SPS_BAM_PIPE_INVALID;
@@ -377,7 +380,7 @@
map->dest.bam = sps_h2bam(map->dest.dev);
if (map->dest.bam == NULL) {
if (map->dest.dev != SPS_DEV_HANDLE_MEM) {
- SPS_ERR("Invalid BAM handle: 0x%x", map->dest.dev);
+ SPS_ERR("sps:Invalid BAM handle: 0x%x", map->dest.dev);
goto exit_err;
}
map->dest.pipe_index = SPS_BAM_PIPE_INVALID;
@@ -386,7 +389,7 @@
/* Check the BAM device for the pipe */
if ((dir == SPS_MODE_SRC && map->src.bam == NULL) ||
(dir != SPS_MODE_SRC && map->dest.bam == NULL)) {
- SPS_ERR("Invalid BAM endpt: dir %d src 0x%x dest 0x%x",
+ SPS_ERR("sps:Invalid BAM endpt: dir %d src 0x%x dest 0x%x",
dir, map->src.dev, map->dest.dev);
goto exit_err;
}
@@ -409,7 +412,7 @@
rc = sps_dma_pipe_alloc(bam, map->src.pipe_index,
SPS_MODE_SRC);
if (rc) {
- SPS_ERR("Failed to alloc BAM-DMA pipe: %d",
+ SPS_ERR("sps:Failed to alloc BAM-DMA pipe: %d",
map->src.pipe_index);
goto exit_err;
}
@@ -436,7 +439,7 @@
rc = sps_dma_pipe_alloc(bam, map->dest.pipe_index,
SPS_MODE_DEST);
if (rc) {
- SPS_ERR("Failed to alloc BAM-DMA pipe: %d",
+ SPS_ERR("sps:Failed to alloc BAM-DMA pipe: %d",
map->dest.pipe_index);
goto exit_err;
}
@@ -474,12 +477,12 @@
map->data.size = 0;
}
if (map->desc.size > SPSRM_MAX_DESC_FIFO_SIZE) {
- SPS_ERR("Invalid desc FIFO size: 0x%x", map->desc.size);
+ SPS_ERR("sps:Invalid desc FIFO size: 0x%x", map->desc.size);
goto exit_err;
}
if (map->src.bam != NULL && map->dest.bam != NULL &&
map->data.size > SPSRM_MAX_DATA_FIFO_SIZE) {
- SPS_ERR("Invalid data FIFO size: 0x%x", map->data.size);
+ SPS_ERR("sps:Invalid data FIFO size: 0x%x", map->data.size);
goto exit_err;
}
@@ -487,14 +490,14 @@
if (map->desc.size && map->desc.phys_base == SPS_ADDR_INVALID) {
map->alloc_desc_base = sps_mem_alloc_io(map->desc.size);
if (map->alloc_desc_base == SPS_ADDR_INVALID) {
- SPS_ERR("I/O memory allocation failure: 0x%x",
+ SPS_ERR("sps:I/O memory allocation failure:0x%x",
map->desc.size);
goto exit_err;
}
map->desc.phys_base = map->alloc_desc_base;
map->desc.base = spsi_get_mem_ptr(map->desc.phys_base);
if (map->desc.base == NULL) {
- SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+ SPS_ERR("sps:Cannot get virt addr for I/O buffer:0x%x",
map->desc.phys_base);
goto exit_err;
}
@@ -504,22 +507,24 @@
if (map->data.size && map->data.phys_base == SPS_ADDR_INVALID) {
map->alloc_data_base = sps_mem_alloc_io(map->data.size);
if (map->alloc_data_base == SPS_ADDR_INVALID) {
- SPS_ERR("I/O memory allocation failure: 0x%x",
+ SPS_ERR("sps:I/O memory allocation failure:0x%x",
map->data.size);
goto exit_err;
}
map->data.phys_base = map->alloc_data_base;
map->data.base = spsi_get_mem_ptr(map->data.phys_base);
if (map->data.base == NULL) {
- SPS_ERR("Cannot get virt addr for I/O buffer: 0x%x",
+ SPS_ERR("sps:Cannot get virt addr for I/O buffer:0x%x",
map->data.phys_base);
goto exit_err;
}
}
/* Attempt to assign this connection to the client */
- if (sps_rm_assign(pipe, map))
+ if (sps_rm_assign(pipe, map)) {
+ SPS_ERR("sps:failed to assign a connection to the client.\n");
goto exit_err;
+ }
/* Initialization was successful */
success = true;
@@ -611,7 +616,7 @@
*/
if (pipe->connect.config != SPS_CONFIG_DEFAULT) {
if (sps_map_find(&pipe->connect)) {
- SPS_ERR("Failed to find connection mapping");
+ SPS_ERR("sps:Failed to find connection mapping");
return SPS_ERROR;
}
}
@@ -619,7 +624,7 @@
mutex_lock(&sps_rm->lock);
/* Check client state */
if (IS_SPS_STATE_OK(pipe)) {
- SPS_ERR("Client connection already allocated");
+ SPS_ERR("sps:Client connection already allocated");
goto exit_err;
}
@@ -636,7 +641,7 @@
if (map == NULL) {
map = sps_rm_create(pipe);
if (map == NULL) {
- SPS_ERR("Failed to allocate connection");
+ SPS_ERR("sps:Failed to allocate connection");
goto exit_err;
}
list_add_tail(&map->list, &sps_rm->connections_q);
@@ -692,8 +697,12 @@
/* Allocate the pipe */
if (pipe->client_state == SPS_STATE_DISCONNECT &&
state == SPS_STATE_ALLOCATE) {
- if (sps_rm_alloc(pipe))
+ if (sps_rm_alloc(pipe)) {
+ SPS_ERR("sps:Fail to allocate resource for"
+ " BAM 0x%x pipe %d",
+ (u32) pipe->bam, pipe->pipe_index);
return SPS_ERROR;
+ }
}
/* Configure the pipe */
@@ -710,7 +719,7 @@
}
result = sps_bam_pipe_connect(pipe, ¶ms);
if (result) {
- SPS_ERR("Failed to connect BAM 0x%x pipe %d",
+ SPS_ERR("sps:Failed to connect BAM 0x%x pipe %d",
(u32) pipe->bam, pipe->pipe_index);
return SPS_ERROR;
}
@@ -733,7 +742,7 @@
|| (pipe->connect.options & SPS_O_AUTO_ENABLE))) {
result = sps_bam_pipe_enable(pipe->bam, pipe->pipe_index);
if (result) {
- SPS_ERR("Failed to set BAM 0x%x pipe %d flow on",
+ SPS_ERR("sps:Failed to set BAM 0x%x pipe %d flow on",
pipe->bam->props.phys_addr,
pipe->pipe_index);
return SPS_ERROR;
@@ -746,8 +755,8 @@
result = sps_dma_pipe_enable(pipe->bam,
pipe->pipe_index);
if (result) {
- SPS_ERR("Failed to activate BAM-DMA pipe: %d",
- pipe->pipe_index);
+ SPS_ERR("sps:Failed to activate BAM-DMA"
+ " pipe: %d", pipe->pipe_index);
return SPS_ERROR;
}
}
@@ -760,7 +769,7 @@
(state == SPS_STATE_DISABLE || state == SPS_STATE_DISCONNECT)) {
result = sps_bam_pipe_disable(pipe->bam, pipe->pipe_index);
if (result) {
- SPS_ERR("Failed to set BAM 0x%x pipe %d flow off",
+ SPS_ERR("sps:Failed to set BAM 0x%x pipe %d flow off",
pipe->bam->props.phys_addr,
pipe->pipe_index);
return SPS_ERROR;
@@ -782,7 +791,7 @@
result = sps_bam_pipe_disconnect(pipe->bam, pipe_index);
if (result) {
- SPS_ERR("Failed to disconnect BAM 0x%x pipe %d",
+ SPS_ERR("sps:Failed to disconnect BAM 0x%x pipe %d",
pipe->bam->props.phys_addr,
pipe->pipe_index);
return SPS_ERROR;
diff --git a/drivers/platform/msm/sps/spsi.h b/drivers/platform/msm/sps/spsi.h
index 4de70ab..4126999 100644
--- a/drivers/platform/msm/sps/spsi.h
+++ b/drivers/platform/msm/sps/spsi.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
@@ -21,11 +21,14 @@
#include <linux/list.h> /* list_head */
#include <linux/kernel.h> /* pr_info() */
#include <linux/compiler.h>
+#include <linux/ratelimit.h>
#include <mach/sps.h>
#include "sps_map.h"
+#define BAM_MAX_PIPES 31
+
/* Adjust for offset of struct sps_q_event */
#define SPS_EVENT_INDEX(e) ((e) - 1)
#define SPS_ERROR -1
@@ -34,33 +37,85 @@
#define BAM_ID(dev) ((dev)->props.phys_addr)
#ifdef CONFIG_DEBUG_FS
-extern u32 sps_debugfs_enabled;
-extern u32 detailed_debug_on;
+extern u8 debugfs_record_enabled;
+extern u8 logging_option;
+extern u8 debug_level_option;
+extern u8 print_limit_option;
+
#define MAX_MSG_LEN 80
#define SPS_DEBUGFS(msg, args...) do { \
- char buf[MAX_MSG_LEN]; \
- snprintf(buf, MAX_MSG_LEN, msg"\n", ##args); \
- sps_debugfs_record(buf); \
- } while (0)
+ char buf[MAX_MSG_LEN]; \
+ snprintf(buf, MAX_MSG_LEN, msg"\n", ##args); \
+ sps_debugfs_record(buf); \
+ } while (0)
#define SPS_ERR(msg, args...) do { \
+ if (unlikely(print_limit_option > 2)) \
+ pr_err_ratelimited(msg, ##args); \
+ else \
pr_err(msg, ##args); \
- if (unlikely(sps_debugfs_enabled)) \
- SPS_DEBUGFS(msg, ##args); \
- } while (0)
+ if (unlikely(debugfs_record_enabled)) \
+ SPS_DEBUGFS(msg, ##args); \
+ } while (0)
#define SPS_INFO(msg, args...) do { \
+ if (unlikely(print_limit_option > 1)) \
+ pr_info_ratelimited(msg, ##args); \
+ else \
pr_info(msg, ##args); \
- if (unlikely(sps_debugfs_enabled)) \
- SPS_DEBUGFS(msg, ##args); \
- } while (0)
+ if (unlikely(debugfs_record_enabled)) \
+ SPS_DEBUGFS(msg, ##args); \
+ } while (0)
#define SPS_DBG(msg, args...) do { \
- if (unlikely(detailed_debug_on)) \
- pr_info(msg, ##args); \
+ if ((unlikely(logging_option > 1)) \
+ && (unlikely(debug_level_option > 3))) {\
+ if (unlikely(print_limit_option > 0)) \
+ pr_info_ratelimited(msg, ##args); \
else \
- pr_debug(msg, ##args); \
- if (unlikely(sps_debugfs_enabled)) \
- SPS_DEBUGFS(msg, ##args); \
- } while (0)
+ pr_info(msg, ##args); \
+ } else \
+ pr_debug(msg, ##args); \
+ if (unlikely(debugfs_record_enabled)) \
+ SPS_DEBUGFS(msg, ##args); \
+ } while (0)
+#define SPS_DBG1(msg, args...) do { \
+ if ((unlikely(logging_option > 1)) \
+ && (unlikely(debug_level_option > 2))) {\
+ if (unlikely(print_limit_option > 0)) \
+ pr_info_ratelimited(msg, ##args); \
+ else \
+ pr_info(msg, ##args); \
+ } else \
+ pr_debug(msg, ##args); \
+ if (unlikely(debugfs_record_enabled)) \
+ SPS_DEBUGFS(msg, ##args); \
+ } while (0)
+#define SPS_DBG2(msg, args...) do { \
+ if ((unlikely(logging_option > 1)) \
+ && (unlikely(debug_level_option > 1))) {\
+ if (unlikely(print_limit_option > 0)) \
+ pr_info_ratelimited(msg, ##args); \
+ else \
+ pr_info(msg, ##args); \
+ } else \
+ pr_debug(msg, ##args); \
+ if (unlikely(debugfs_record_enabled)) \
+ SPS_DEBUGFS(msg, ##args); \
+ } while (0)
+#define SPS_DBG3(msg, args...) do { \
+ if ((unlikely(logging_option > 1)) \
+ && (unlikely(debug_level_option > 0))) {\
+ if (unlikely(print_limit_option > 0)) \
+ pr_info_ratelimited(msg, ##args); \
+ else \
+ pr_info(msg, ##args); \
+ } else \
+ pr_debug(msg, ##args); \
+ if (unlikely(debugfs_record_enabled)) \
+ SPS_DEBUGFS(msg, ##args); \
+ } while (0)
#else
+#define SPS_DBG3(x...) pr_debug(x)
+#define SPS_DBG2(x...) pr_debug(x)
+#define SPS_DBG1(x...) pr_debug(x)
#define SPS_DBG(x...) pr_debug(x)
#define SPS_INFO(x...) pr_info(x)
#define SPS_ERR(x...) pr_err(x)
@@ -121,6 +176,18 @@
#ifdef CONFIG_DEBUG_FS
/* record debug info for debugfs */
void sps_debugfs_record(const char *);
+
+/* output the content of BAM-level registers */
+void print_bam_reg(void *);
+
+/* output the content of BAM pipe registers */
+void print_bam_pipe_reg(void *, u32);
+
+/* output the content of selected BAM-level registers */
+void print_bam_selected_reg(void *);
+
+/* output the content of selected BAM pipe registers */
+void print_bam_pipe_selected_reg(void *, u32);
#endif
/**
diff --git a/drivers/slimbus/slim-msm-ctrl.c b/drivers/slimbus/slim-msm-ctrl.c
index 22297be..420c93c 100644
--- a/drivers/slimbus/slim-msm-ctrl.c
+++ b/drivers/slimbus/slim-msm-ctrl.c
@@ -821,7 +821,7 @@
timeout = wait_for_completion_timeout(&dev->reconf, HZ);
dev->reconf_busy = false;
if (timeout) {
- clk_disable(dev->rclk);
+ clk_disable_unprepare(dev->rclk);
disable_irq(dev->irq);
}
}
@@ -880,7 +880,7 @@
{
struct msm_slim_ctrl *dev = slim_get_ctrldata(ctrl);
enable_irq(dev->irq);
- clk_enable(dev->rclk);
+ clk_prepare_enable(dev->rclk);
writel_relaxed(1, dev->base + FRM_WAKEUP);
/* Make sure framer wakeup write goes through before exiting function */
mb();
@@ -1913,7 +1913,7 @@
goto err_clk_get_failed;
}
clk_set_rate(dev->rclk, SLIM_ROOT_FREQ);
- clk_enable(dev->rclk);
+ clk_prepare_enable(dev->rclk);
/* Component register initialization */
writel_relaxed(1, dev->base + COMP_CFG);
diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig
index 7768eeda..6d12c7e 100644
--- a/drivers/spmi/Kconfig
+++ b/drivers/spmi/Kconfig
@@ -25,5 +25,13 @@
bool "MSM QPNP"
help
Say 'y' here to include support for the Qualcomm QPNP
+
+config MSM_QPNP_INT
+ depends on SPARSE_IRQ
+ depends on ARCH_MSMCOPPER
+ depends on OF_SPMI
+ bool "MSM QPNP INT"
+ help
+ Say 'y' here to include support for the Qualcomm QPNP interrupt
support. QPNP is a SPMI based PMIC implementation.
endif
diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile
index 659e886..d59a610 100644
--- a/drivers/spmi/Makefile
+++ b/drivers/spmi/Makefile
@@ -4,3 +4,4 @@
obj-$(CONFIG_SPMI) += spmi.o
obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o
obj-$(CONFIG_MSM_QPNP) += qpnp.o
+obj-$(CONFIG_MSM_QPNP_INT) += qpnp-int.o
diff --git a/drivers/spmi/qpnp-int.c b/drivers/spmi/qpnp-int.c
new file mode 100644
index 0000000..2998c01
--- /dev/null
+++ b/drivers/spmi/qpnp-int.c
@@ -0,0 +1,510 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/spmi.h>
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
+#include <linux/printk.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <mach/qpnp-int.h>
+
+#define QPNPINT_MAX_BUSSES 1
+
+/* 16 slave_ids, 256 per_ids per slave, and 8 ints per per_id */
+#define QPNPINT_NR_IRQS (16 * 256 * 8)
+
+enum qpnpint_regs {
+ QPNPINT_REG_RT_STS = 0x10,
+ QPNPINT_REG_SET_TYPE = 0x11,
+ QPNPINT_REG_POLARITY_HIGH = 0x12,
+ QPNPINT_REG_POLARITY_LOW = 0x13,
+ QPNPINT_REG_LATCHED_CLR = 0x14,
+ QPNPINT_REG_EN_SET = 0x15,
+ QPNPINT_REG_EN_CLR = 0x16,
+ QPNPINT_REG_LATCHED_STS = 0x18,
+};
+
+struct q_perip_data {
+ uint8_t type; /* bitmap */
+ uint8_t pol_high; /* bitmap */
+ uint8_t pol_low; /* bitmap */
+ uint8_t int_en; /* bitmap */
+ uint8_t use_count;
+};
+
+struct q_irq_data {
+ uint32_t priv_d; /* data to optimize arbiter interactions */
+ struct q_chip_data *chip_d;
+ struct q_perip_data *per_d;
+ uint8_t mask_shift;
+ uint8_t spmi_slave;
+ uint16_t spmi_offset;
+};
+
+struct q_chip_data {
+ int bus_nr;
+ struct irq_domain domain;
+ struct qpnp_local_int cb;
+ struct spmi_controller *spmi_ctrl;
+ struct radix_tree_root per_tree;
+};
+
+static struct q_chip_data chip_data[QPNPINT_MAX_BUSSES] __read_mostly;
+
+/**
+ * qpnpint_encode_hwirq - translate between qpnp_irq_spec and
+ * hwirq representation.
+ *
+ * slave_offset = (addr->slave * 256 * 8);
+ * perip_offset = slave_offset + (addr->perip * 8);
+ * return perip_offset + addr->irq;
+ */
+static inline int qpnpint_encode_hwirq(struct qpnp_irq_spec *spec)
+{
+ uint32_t hwirq;
+
+ if (spec->slave > 15 || spec->irq > 7)
+ return -EINVAL;
+
+ hwirq = (spec->slave << 11);
+ hwirq |= (spec->per << 3);
+ hwirq |= spec->irq;
+
+ return hwirq;
+}
+/**
+ * qpnpint_decode_hwirq - translate between hwirq and
+ * qpnp_irq_spec representation.
+ */
+static inline int qpnpint_decode_hwirq(unsigned long hwirq,
+ struct qpnp_irq_spec *spec)
+{
+ if (hwirq > 65535)
+ return -EINVAL;
+
+ spec->slave = (hwirq >> 11) & 0xF;
+ spec->per = (hwirq >> 3) & 0xFF;
+ spec->irq = hwirq & 0x7;
+ return 0;
+}
+
+static int qpnpint_spmi_write(struct q_irq_data *irq_d, uint8_t reg,
+ void *buf, uint32_t len)
+{
+ struct q_chip_data *chip_d = irq_d->chip_d;
+ int rc;
+
+ if (!chip_d->spmi_ctrl)
+ return -ENODEV;
+
+ rc = spmi_ext_register_writel(chip_d->spmi_ctrl, irq_d->spmi_slave,
+ irq_d->spmi_offset + reg, buf, len);
+ return rc;
+}
+
+static void qpnpint_irq_mask(struct irq_data *d)
+{
+ struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+ struct q_chip_data *chip_d = irq_d->chip_d;
+ struct q_perip_data *per_d = irq_d->per_d;
+ struct qpnp_irq_spec q_spec;
+ int rc;
+
+ pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+ if (chip_d->cb.mask) {
+ rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
+ if (rc)
+ pr_err("%s: decode failed on hwirq %lu\n",
+ __func__, d->hwirq);
+ else
+ chip_d->cb.mask(chip_d->spmi_ctrl, &q_spec,
+ irq_d->priv_d);
+ }
+
+ per_d->int_en &= ~irq_d->mask_shift;
+
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
+ (u8 *)&irq_d->mask_shift, 1);
+ if (rc)
+ pr_err("%s: spmi failure on irq %d\n",
+ __func__, d->irq);
+}
+
+static void qpnpint_irq_mask_ack(struct irq_data *d)
+{
+ struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+ struct q_chip_data *chip_d = irq_d->chip_d;
+ struct q_perip_data *per_d = irq_d->per_d;
+ struct qpnp_irq_spec q_spec;
+ int rc;
+
+ pr_debug("hwirq %lu irq: %d mask: 0x%x\n", d->hwirq, d->irq,
+ irq_d->mask_shift);
+
+ if (chip_d->cb.mask) {
+ rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
+ if (rc)
+ pr_err("%s: decode failed on hwirq %lu\n",
+ __func__, d->hwirq);
+ else
+ chip_d->cb.mask(chip_d->spmi_ctrl, &q_spec,
+ irq_d->priv_d);
+ }
+
+ per_d->int_en &= ~irq_d->mask_shift;
+
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_CLR,
+ &irq_d->mask_shift, 1);
+ if (rc)
+ pr_err("%s: spmi failure on irq %d\n",
+ __func__, d->irq);
+
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_LATCHED_CLR,
+ &irq_d->mask_shift, 1);
+ if (rc)
+ pr_err("%s: spmi failure on irq %d\n",
+ __func__, d->irq);
+}
+
+static void qpnpint_irq_unmask(struct irq_data *d)
+{
+ struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+ struct q_chip_data *chip_d = irq_d->chip_d;
+ struct q_perip_data *per_d = irq_d->per_d;
+ struct qpnp_irq_spec q_spec;
+ int rc;
+
+ pr_debug("hwirq %lu irq: %d\n", d->hwirq, d->irq);
+
+ if (chip_d->cb.unmask) {
+ rc = qpnpint_decode_hwirq(d->hwirq, &q_spec);
+ if (rc)
+ pr_err("%s: decode failed on hwirq %lu\n",
+ __func__, d->hwirq);
+ else
+ chip_d->cb.unmask(chip_d->spmi_ctrl, &q_spec,
+ irq_d->priv_d);
+ }
+
+ per_d->int_en |= irq_d->mask_shift;
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_EN_SET,
+ &irq_d->mask_shift, 1);
+ if (rc)
+ pr_err("%s: spmi failure on irq %d\n",
+ __func__, d->irq);
+}
+
+static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct q_irq_data *irq_d = irq_data_get_irq_chip_data(d);
+ struct q_perip_data *per_d = irq_d->per_d;
+ int rc;
+ u8 buf[3];
+
+ pr_debug("hwirq %lu irq: %d flow: 0x%x\n", d->hwirq,
+ d->irq, flow_type);
+
+ per_d->pol_high &= ~irq_d->mask_shift;
+ per_d->pol_low &= ~irq_d->mask_shift;
+ if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ per_d->type |= irq_d->mask_shift; /* edge trig */
+ if (flow_type & IRQF_TRIGGER_RISING)
+ per_d->pol_high |= irq_d->mask_shift;
+ if (flow_type & IRQF_TRIGGER_FALLING)
+ per_d->pol_low |= irq_d->mask_shift;
+ } else {
+ if ((flow_type & IRQF_TRIGGER_HIGH) &&
+ (flow_type & IRQF_TRIGGER_LOW))
+ return -EINVAL;
+ per_d->type &= ~irq_d->mask_shift; /* level trig */
+ if (flow_type & IRQF_TRIGGER_HIGH)
+ per_d->pol_high |= irq_d->mask_shift;
+ else
+ per_d->pol_high &= ~irq_d->mask_shift;
+ }
+
+ buf[0] = per_d->type;
+ buf[1] = per_d->pol_high;
+ buf[2] = per_d->pol_low;
+
+ rc = qpnpint_spmi_write(irq_d, QPNPINT_REG_SET_TYPE, &buf, 3);
+ if (rc)
+ pr_err("%s: spmi failure on irq %d\n",
+ __func__, d->irq);
+ return rc;
+}
+
+static struct irq_chip qpnpint_chip = {
+ .name = "qpnp-int",
+ .irq_mask = qpnpint_irq_mask,
+ .irq_mask_ack = qpnpint_irq_mask_ack,
+ .irq_unmask = qpnpint_irq_unmask,
+ .irq_set_type = qpnpint_irq_set_type,
+};
+
+static int qpnpint_init_irq_data(struct q_chip_data *chip_d,
+ struct q_irq_data *irq_d,
+ unsigned long hwirq)
+{
+ struct qpnp_irq_spec q_spec;
+ int rc;
+
+ irq_d->mask_shift = 1 << (hwirq & 0x7);
+ rc = qpnpint_decode_hwirq(hwirq, &q_spec);
+ if (rc < 0)
+ return rc;
+ irq_d->spmi_slave = q_spec.slave;
+ irq_d->spmi_offset = q_spec.per << 8;
+ irq_d->per_d->use_count++;
+ irq_d->chip_d = chip_d;
+
+ if (chip_d->cb.register_priv_data)
+ rc = chip_d->cb.register_priv_data(chip_d->spmi_ctrl, &q_spec,
+ &irq_d->priv_d);
+ return rc;
+}
+
+static struct q_irq_data *qpnpint_alloc_irq_data(
+ struct q_chip_data *chip_d,
+ unsigned long hwirq)
+{
+ struct q_irq_data *irq_d;
+ struct q_perip_data *per_d;
+
+ irq_d = kzalloc(sizeof(struct q_irq_data), GFP_KERNEL);
+ if (!irq_d)
+ return ERR_PTR(-ENOMEM);
+
+ /**
+ * The Peripheral Tree is keyed from the slave + per_id. We're
+ * ignoring the irq bits here since this peripheral structure
+ * should be common for all irqs on the same peripheral.
+ */
+ per_d = radix_tree_lookup(&chip_d->per_tree, (hwirq & ~0x7));
+ if (!per_d) {
+ per_d = kzalloc(sizeof(struct q_perip_data), GFP_KERNEL);
+ if (!per_d)
+ return ERR_PTR(-ENOMEM);
+ radix_tree_insert(&chip_d->per_tree,
+ (hwirq & ~0x7), per_d);
+ }
+ irq_d->per_d = per_d;
+
+ return irq_d;
+}
+
+static int qpnpint_register_int(uint32_t busno, unsigned long hwirq)
+{
+ int irq, rc;
+ struct irq_domain *domain;
+ struct q_irq_data *irq_d;
+
+ pr_debug("busno = %u hwirq = %lu\n", busno, hwirq);
+
+ if (hwirq < 0 || hwirq >= 32768) {
+ pr_err("%s: hwirq %lu out of qpnp interrupt bounds\n",
+ __func__, hwirq);
+ return -EINVAL;
+ }
+
+ if (busno < 0 || busno > QPNPINT_MAX_BUSSES) {
+ pr_err("%s: invalid bus number %d\n", __func__, busno);
+ return -EINVAL;
+ }
+
+ domain = &chip_data[busno].domain;
+ irq = irq_domain_to_irq(domain, hwirq);
+
+ rc = irq_alloc_desc_at(irq, numa_node_id());
+ if (rc < 0) {
+ if (rc != -EEXIST)
+ pr_err("%s: failed to alloc irq at %d with "
+ "rc %d\n", __func__, irq, rc);
+ return rc;
+ }
+ irq_d = qpnpint_alloc_irq_data(&chip_data[busno], hwirq);
+ if (IS_ERR(irq_d)) {
+ pr_err("%s: failed to alloc irq data %d with "
+ "rc %d\n", __func__, irq, rc);
+ rc = PTR_ERR(irq_d);
+ goto register_err_cleanup;
+ }
+ rc = qpnpint_init_irq_data(&chip_data[busno], irq_d, hwirq);
+ if (rc) {
+ pr_err("%s: failed to init irq data %d with "
+ "rc %d\n", __func__, irq, rc);
+ goto register_err_cleanup;
+ }
+
+ irq_domain_register_irq(domain, hwirq);
+
+ irq_set_chip_and_handler(irq,
+ &qpnpint_chip,
+ handle_level_irq);
+ irq_set_chip_data(irq, irq_d);
+#ifdef CONFIG_ARM
+ set_irq_flags(irq, IRQF_VALID);
+#else
+ irq_set_noprobe(irq);
+#endif
+ return 0;
+
+register_err_cleanup:
+ irq_free_desc(irq);
+ if (!IS_ERR(irq_d)) {
+ if (irq_d->per_d->use_count == 1)
+ kfree(irq_d->per_d);
+ else
+ irq_d->per_d->use_count--;
+ kfree(irq_d);
+ }
+ return rc;
+}
+
+static int qpnpint_irq_domain_dt_translate(struct irq_domain *d,
+ struct device_node *controller,
+ const u32 *intspec, unsigned int intsize,
+ unsigned long *out_hwirq,
+ unsigned int *out_type)
+{
+ struct qpnp_irq_spec addr;
+ struct q_chip_data *chip_d = d->priv;
+ int ret;
+
+ pr_debug("%s: intspec[0] 0x%x intspec[1] 0x%x intspec[2] 0x%x\n",
+ __func__, intspec[0], intspec[1], intspec[2]);
+
+ if (d->of_node != controller)
+ return -EINVAL;
+ if (intsize != 3)
+ return -EINVAL;
+
+ addr.irq = intspec[2] & 0x7;
+ addr.per = intspec[1] & 0xFF;
+ addr.slave = intspec[0] & 0xF;
+
+ ret = qpnpint_encode_hwirq(&addr);
+ if (ret < 0) {
+ pr_err("%s: invalid intspec\n", __func__);
+ return ret;
+ }
+ *out_hwirq = ret;
+ *out_type = IRQ_TYPE_NONE;
+
+ /**
+ * Register the interrupt if it's not already registered.
+ * This implies that mapping a qpnp interrupt allocates
+ * resources.
+ */
+ ret = qpnpint_register_int(chip_d->bus_nr, *out_hwirq);
+ if (ret && ret != -EEXIST) {
+ pr_err("%s: Cannot register hwirq %lu\n", __func__, *out_hwirq);
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct irq_domain_ops qpnpint_irq_domain_ops = {
+ .dt_translate = qpnpint_irq_domain_dt_translate,
+};
+
+int qpnpint_register_controller(unsigned int busno,
+ struct qpnp_local_int *li_cb)
+{
+ if (busno >= QPNPINT_MAX_BUSSES)
+ return -EINVAL;
+ chip_data[busno].cb = *li_cb;
+ chip_data[busno].spmi_ctrl = spmi_busnum_to_ctrl(busno);
+ if (!chip_data[busno].spmi_ctrl)
+ return -ENOENT;
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnpint_register_controller);
+
+int qpnpint_handle_irq(struct spmi_controller *spmi_ctrl,
+ struct qpnp_irq_spec *spec)
+{
+ struct irq_domain *domain;
+ unsigned long hwirq, busno;
+ int irq;
+
+ pr_debug("spec slave = %u per = %u irq = %u\n",
+ spec->slave, spec->per, spec->irq);
+
+ if (!spec || !spmi_ctrl)
+ return -EINVAL;
+
+ busno = spmi_ctrl->nr;
+ if (busno >= QPNPINT_MAX_BUSSES)
+ return -EINVAL;
+
+ hwirq = qpnpint_encode_hwirq(spec);
+ if (hwirq < 0) {
+ pr_err("%s: invalid irq spec passed\n", __func__);
+ return -EINVAL;
+ }
+
+ domain = &chip_data[busno].domain;
+ irq = irq_domain_to_irq(domain, hwirq);
+
+ generic_handle_irq(irq);
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnpint_handle_irq);
+
+/**
+ * This assumes that there's a relationship between the order of the interrupt
+ * controllers specified to of_irq_match() is the SPMI device topology. If
+ * this ever turns out to be a bad assumption, then of_irq_init_cb_t should
+ * be modified to pass a parameter to this function.
+ */
+static int qpnpint_cnt __initdata;
+
+int __init qpnpint_of_init(struct device_node *node, struct device_node *parent)
+{
+ struct q_chip_data *chip_d = &chip_data[qpnpint_cnt];
+ struct irq_domain *domain = &chip_d->domain;
+
+ INIT_RADIX_TREE(&chip_d->per_tree, GFP_ATOMIC);
+
+ domain->irq_base = irq_domain_find_free_range(0, QPNPINT_NR_IRQS);
+ domain->nr_irq = QPNPINT_NR_IRQS;
+ domain->of_node = of_node_get(node);
+ domain->priv = chip_d;
+ domain->ops = &qpnpint_irq_domain_ops;
+ irq_domain_add(domain);
+
+ pr_info("irq_base = %d\n", domain->irq_base);
+
+ qpnpint_cnt++;
+
+ return 0;
+}
+EXPORT_SYMBOL(qpnpint_of_init);
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index e5a9d40..632db71 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -78,8 +78,14 @@
#define PMIC_ARB_MAX_PERIPHS 256
#define PMIC_ARB_PERIPH_ID_VALID (1 << 15)
#define PMIC_ARB_TIMEOUT_US 100
-#define PMIC_ARB_APID_MASK 0xFF
-#define PMIC_ARB_PPID_MASK 0xFFF
+
+#define PMIC_ARB_APID_MASK 0xFF
+#define PMIC_ARB_PPID_MASK 0xFFF
+/* extract PPID and APID from interrupt map in .dts config file format */
+#define PMIC_ARB_DEV_TRE_2_PPID(MAP_COMPRS_VAL) \
+ ((MAP_COMPRS_VAL) >> (20))
+#define PMIC_ARB_DEV_TRE_2_APID(MAP_COMPRS_VAL) \
+ ((MAP_COMPRS_VAL) & PMIC_ARB_APID_MASK)
/**
* base - base address of the PMIC Arbiter core registers.
@@ -504,7 +510,7 @@
int ret;
int map_size;
u32 *map_data;
- const int map_width = 2 * sizeof(*map_data);
+ const int map_width = sizeof(*map_data);
const struct device_node *of_node = pdev->dev.of_node;
/* Get size of the mapping table (in bytes) */
@@ -514,8 +520,7 @@
}
/* Map size can't exceed the maximum number of peripherals */
- if (map_size == 0 || map_size % map_width ||
- map_size > map_width * PMIC_ARB_MAX_PERIPHS) {
+ if (map_size == 0 || map_size > map_width * PMIC_ARB_MAX_PERIPHS) {
dev_err(&pdev->dev, "map size of %d is not valid\n", map_size);
return -ENODEV;
}
@@ -538,20 +543,9 @@
/* Build the mapping table from the data */
for (i = 0; i < map_size/sizeof(u32);) {
- u32 ppid = map_data[i++];
- u32 apid = map_data[i++];
-
- if (apid > PMIC_ARB_APID_MASK) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "invalid APID: 0x%x\n", apid);
- goto err;
- }
-
- if (ppid > PMIC_ARB_PPID_MASK) {
- ret = -ENODEV;
- dev_err(&pdev->dev, "invalid PPID: 0x%x\n", ppid);
- goto err;
- }
+ u32 map_compressed_val = map_data[i++];
+ u32 ppid = PMIC_ARB_DEV_TRE_2_PPID(map_compressed_val) ;
+ u32 apid = PMIC_ARB_DEV_TRE_2_APID(map_compressed_val) ;
if (pmic_arb->periph_id_map[apid] & PMIC_ARB_PERIPH_ID_VALID)
dev_warn(&pdev->dev, "duplicate APID 0x%x\n", apid);
diff --git a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c b/drivers/staging/westbridge/astoria/gadget/cyasgadget.c
index be851ca..2ec93d2 100644
--- a/drivers/staging/westbridge/astoria/gadget/cyasgadget.c
+++ b/drivers/staging/westbridge/astoria/gadget/cyasgadget.c
@@ -1595,12 +1595,18 @@
return 0;
}
+static int cyasgadget_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int cyasgadget_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops cyasgadget_ops = {
.get_frame = cyasgadget_get_frame,
.wakeup = cyasgadget_wakeup,
.set_selfpowered = cyasgadget_set_selfpowered,
.pullup = cyasgadget_pullup,
.ioctl = cyasgadget_ioctl,
+ .start = cyasgadget_start,
+ .stop = cyasgadget_stop,
};
@@ -1883,7 +1889,7 @@
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int cyasgadget_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
cyasgadget *dev = cy_as_gadget_controller;
@@ -1938,7 +1944,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
static void cyasgadget_nuke(
cyasgadget_ep *an_ep
@@ -2011,7 +2016,7 @@
#endif
}
-int usb_gadget_unregister_driver(
+static int cyasgadget_stop(
struct usb_gadget_driver *driver
)
{
@@ -2040,7 +2045,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
static void cyas_gadget_release(
struct device *_dev
@@ -2071,6 +2075,7 @@
#endif
return;
}
+ usb_del_gadget_udc(&cy_as_dev->gadget);
if (cy_as_dev->driver) {
/* should have been done already by driver model core */
@@ -2131,6 +2136,19 @@
/* We are done now */
cy_as_gadget_controller = cy_as_dev;
+
+ /*
+ * We actually want to use "cy_as_dev->gadget.dev.parent", but we just
+ * don't have a parent in this driver implementation. Therefore, in
+ * order to still allow calling to usb_add_gadget_udc, we send for now
+ * &cy_as_dev->gadget.dev, so the parent of the udc-core will be
+ * actually the usb_gadget it holds.
+ */
+ retval = usb_add_gadget_udc(&cy_as_dev->gadget.dev, &cy_as_dev->gadget);
+ if (retval)
+ goto done;
+
+
return 0;
/*
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index f49769d..04dd590 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -639,7 +639,7 @@
/* enable TX & RX */
msm_hsl_write(port, data, regmap[vid][UARTDM_CR]);
- msm_hsl_write(port, RESET_STALE_INT, UARTDM_CR_ADDR);
+ msm_hsl_write(port, RESET_STALE_INT, regmap[vid][UARTDM_CR]);
/* turn on RX and CTS interrupts */
msm_hsl_port->imr = UARTDM_ISR_RXSTALE_BMSK
| UARTDM_ISR_DELTA_CTS_BMSK | UARTDM_ISR_RXLEV_BMSK;
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 48f1781..288b570 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -110,6 +110,8 @@
source "drivers/usb/core/Kconfig"
+source "drivers/usb/dwc3/Kconfig"
+
source "drivers/usb/mon/Kconfig"
source "drivers/usb/wusbcore/Kconfig"
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index ef69048..0fd0bbd 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,6 +6,8 @@
obj-$(CONFIG_USB) += core/
+obj-$(CONFIG_USB_DWC3) += dwc3/
+
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_OTG_UTILS) += otg/
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 97c5690..5cd6bb1 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1285,10 +1285,20 @@
struct usb_bus *bus =
container_of(work, struct usb_bus, hnp_polling.work);
struct usb_device *udev = bus->root_hub->children[bus->otg_port - 1];
- u8 *status = kmalloc(sizeof(*status), GFP_KERNEL);
+ u8 *status = NULL;
+ /*
+ * The OTG-B device must hand back the host role to OTG PET
+ * within 100 msec irrespective of host_request flag.
+ */
+ if (bus->quick_hnp) {
+ bus->quick_hnp = 0;
+ goto start_hnp;
+ }
+
+ status = kmalloc(sizeof(*status), GFP_KERNEL);
if (!status)
- return;
+ goto reschedule;
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE,
@@ -1300,17 +1310,20 @@
goto out;
}
- /* Spec says host must suspend the bus with in 2 sec. */
- if (*status & (1 << HOST_REQUEST_FLAG)) {
- do_unbind_rebind(udev, DO_UNBIND);
- udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
- ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
- if (ret)
- dev_info(&udev->dev, "suspend failed\n");
- } else {
- schedule_delayed_work(&bus->hnp_polling,
- msecs_to_jiffies(THOST_REQ_POLL));
- }
+ if (!(*status & (1 << HOST_REQUEST_FLAG)))
+ goto reschedule;
+
+start_hnp:
+ do_unbind_rebind(udev, DO_UNBIND);
+ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+ ret = usb_suspend_both(udev, PMSG_USER_SUSPEND);
+ if (ret)
+ dev_info(&udev->dev, "suspend failed\n");
+ goto out;
+
+reschedule:
+ schedule_delayed_work(&bus->hnp_polling,
+ msecs_to_jiffies(THOST_REQ_POLL));
out:
kfree(status);
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5442297..7347c3d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1690,7 +1690,7 @@
#ifdef CONFIG_USB_OTG
if (udev->bus->hnp_support && udev->portnum == udev->bus->otg_port) {
- cancel_delayed_work(&udev->bus->hnp_polling);
+ cancel_delayed_work_sync(&udev->bus->hnp_polling);
udev->bus->hnp_support = 0;
}
#endif
@@ -1778,6 +1778,7 @@
int err = 0;
#ifdef CONFIG_USB_OTG
+ bool old_otg = false;
/*
* OTG-aware devices on OTG-capable root hubs may be able to use SRP,
* to wake us after we've powered off VBUS; and HNP, switching roles
@@ -1811,7 +1812,10 @@
* compliant to revision 2.0 or subsequent
* versions.
*/
- if (le16_to_cpu(desc->bcdOTG) >= 0x0200)
+
+ if ((le16_to_cpu(desc->bLength) ==
+ USB_DT_OTG_SIZE) &&
+ le16_to_cpu(desc->bcdOTG) >= 0x0200)
goto out;
/* Legacy B-device i.e compliant to spec
@@ -1819,6 +1823,7 @@
* a_hnp_support or b_hnp_enable before
* selecting configuration.
*/
+ old_otg = true;
/* enable HNP before suspend, it's simpler */
err = usb_control_msg(udev,
@@ -1839,6 +1844,14 @@
}
}
out:
+ if ((udev->quirks & USB_QUIRK_OTG_PET)) {
+ if (le16_to_cpu(udev->descriptor.bcdDevice) &
+ OTG_TTST_VBUS_OFF)
+ udev->bus->otg_vbus_off = 1;
+ if (udev->bus->is_b_host || old_otg)
+ udev->bus->quick_hnp = 1;
+ }
+
if (!is_targeted(udev)) {
otg_send_event(OTG_EVENT_DEV_NOT_SUPPORTED);
@@ -1859,8 +1872,12 @@
* re-armed if device returns STALL. B-Host also perform
* HNP polling.
*/
- schedule_delayed_work(&udev->bus->hnp_polling,
- msecs_to_jiffies(THOST_REQ_POLL));
+ if (udev->bus->quick_hnp)
+ schedule_delayed_work(&udev->bus->hnp_polling,
+ msecs_to_jiffies(OTG_TTST_SUSP));
+ else
+ schedule_delayed_work(&udev->bus->hnp_polling,
+ msecs_to_jiffies(THOST_REQ_POLL));
}
#endif
return err;
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index cec4167..7bb6747 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -59,6 +59,11 @@
le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
return 0;
+ /* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
+ return 1;
+
/* NOTE: can't use usb_match_id() since interface caches
* aren't set up yet. this is cut/paste from that code.
*/
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 81ce6a8..d5a29b3 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -96,6 +96,9 @@
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Protocol and OTG Electrical Test Device */
+ { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_OTG_PET },
+
{ } /* terminating entry must be last */
};
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
new file mode 100644
index 0000000..3c1d67d
--- /dev/null
+++ b/drivers/usb/dwc3/Kconfig
@@ -0,0 +1,25 @@
+config USB_DWC3
+ tristate "DesignWare USB3 DRD Core Support"
+ depends on (USB || USB_GADGET)
+ select USB_OTG_UTILS
+ help
+ Say Y or M here if your system has a Dual Role SuperSpeed
+ USB controller based on the DesignWare USB3 IP Core.
+
+ If you choose to build this driver is a dynamically linked
+ module, the module will be called dwc3.ko.
+
+if USB_DWC3
+
+config USB_DWC3_DEBUG
+ bool "Enable Debugging Messages"
+ help
+ Say Y here to enable debugging messages on DWC3 Driver.
+
+config USB_DWC3_VERBOSE
+ bool "Enable Verbose Debugging Messages"
+ depends on USB_DWC3_DEBUG
+ help
+ Say Y here to enable verbose debugging messages on DWC3 Driver.
+
+endif
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
new file mode 100644
index 0000000..593d1dbc
--- /dev/null
+++ b/drivers/usb/dwc3/Makefile
@@ -0,0 +1,36 @@
+ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
+ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC3) += dwc3.o
+
+dwc3-y := core.o
+
+ifneq ($(CONFIG_USB_GADGET_DWC3),)
+ dwc3-y += gadget.o ep0.o
+endif
+
+ifneq ($(CONFIG_DEBUG_FS),)
+ dwc3-y += debugfs.o
+endif
+
+##
+# Platform-specific glue layers go here
+#
+# NOTICE: Make sure your glue layer doesn't depend on anything
+# which is arch-specific and that it compiles on all situations.
+#
+# We want to keep this requirement in order to be able to compile
+# the entire driver (with all its glue layers) on several architectures
+# and make sure it compiles fine. This will also help with allmodconfig
+# and allyesconfig builds.
+#
+# The only exception is the PCI glue layer, but that's only because
+# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
+##
+
+obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
+
+ifneq ($(CONFIG_PCI),)
+ obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
+endif
+
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
new file mode 100644
index 0000000..717ebc9
--- /dev/null
+++ b/drivers/usb/dwc3/core.c
@@ -0,0 +1,484 @@
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/module.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "debug.h"
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+static void dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ /* Before Resetting PHY, put Core in Reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg |= DWC3_GCTL_CORESOFTRESET;
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ /* Assert USB3 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+ /* Assert USB2 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ mdelay(100);
+
+ /* Clear USB3 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+ /* Clear USB2 PHY reset */
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+ /* After PHYs are stable we can take Core out of reset state */
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg &= ~DWC3_GCTL_CORESOFTRESET;
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+/**
+ * dwc3_free_one_event_buffer - Frees one event buffer
+ * @dwc: Pointer to our controller context structure
+ * @evt: Pointer to event buffer to be freed
+ */
+static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
+ struct dwc3_event_buffer *evt)
+{
+ dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
+ kfree(evt);
+}
+
+/**
+ * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * @dwc: Pointer to our controller context structure
+ * @length: size of the event buffer
+ *
+ * Returns a pointer to the allocated event buffer structure on succes
+ * otherwise ERR_PTR(errno).
+ */
+static struct dwc3_event_buffer *__devinit
+dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
+{
+ struct dwc3_event_buffer *evt;
+
+ evt = kzalloc(sizeof(*evt), GFP_KERNEL);
+ if (!evt)
+ return ERR_PTR(-ENOMEM);
+
+ evt->dwc = dwc;
+ evt->length = length;
+ evt->buf = dma_alloc_coherent(dwc->dev, length,
+ &evt->dma, GFP_KERNEL);
+ if (!evt->buf) {
+ kfree(evt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return evt;
+}
+
+/**
+ * dwc3_free_event_buffers - frees all allocated event buffers
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_free_event_buffers(struct dwc3 *dwc)
+{
+ struct dwc3_event_buffer *evt;
+ int i;
+
+ for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+ evt = dwc->ev_buffs[i];
+ if (evt) {
+ dwc3_free_one_event_buffer(dwc, evt);
+ dwc->ev_buffs[i] = NULL;
+ }
+ }
+}
+
+/**
+ * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
+ * @dwc: Pointer to out controller context structure
+ * @num: number of event buffers to allocate
+ * @length: size of event buffer
+ *
+ * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * may contain some buffers allocated but not all which were requested.
+ */
+static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
+ unsigned length)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ struct dwc3_event_buffer *evt;
+
+ evt = dwc3_alloc_one_event_buffer(dwc, length);
+ if (IS_ERR(evt)) {
+ dev_err(dwc->dev, "can't allocate event buffer\n");
+ return PTR_ERR(evt);
+ }
+ dwc->ev_buffs[i] = evt;
+ }
+
+ return 0;
+}
+
+/**
+ * dwc3_event_buffers_setup - setup our allocated event buffers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
+{
+ struct dwc3_event_buffer *evt;
+ int n;
+
+ for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+ evt = dwc->ev_buffs[n];
+ dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
+ evt->buf, (unsigned long long) evt->dma,
+ evt->length);
+
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
+ lower_32_bits(evt->dma));
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
+ upper_32_bits(evt->dma));
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
+ evt->length & 0xffff);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+ }
+
+ return 0;
+}
+
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+{
+ struct dwc3_event_buffer *evt;
+ int n;
+
+ for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+ evt = dwc->ev_buffs[n];
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+ }
+}
+
+static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
+{
+ struct dwc3_hwparams *parms = &dwc->hwparams;
+
+ parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
+ parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
+ parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
+ parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
+ parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
+ parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
+ parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+ parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
+ parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+}
+
+/**
+ * dwc3_core_init - Low-level initialization of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_core_init(struct dwc3 *dwc)
+{
+ unsigned long timeout;
+ u32 reg;
+ int ret;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+ /* This should read as U3 followed by revision number */
+ if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
+ dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+ ret = -ENODEV;
+ goto err0;
+ }
+ dwc->revision = reg & DWC3_GSNPSREV_MASK;
+
+ dwc3_core_soft_reset(dwc);
+
+ /* issue device SoftReset too */
+ timeout = jiffies + msecs_to_jiffies(500);
+ dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (!(reg & DWC3_DCTL_CSFTRST))
+ break;
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(dwc->dev, "Reset Timed Out\n");
+ ret = -ETIMEDOUT;
+ goto err0;
+ }
+
+ cpu_relax();
+ } while (true);
+
+ ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
+ DWC3_EVENT_BUFFERS_SIZE);
+ if (ret) {
+ dev_err(dwc->dev, "failed to allocate event buffers\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ ret = dwc3_event_buffers_setup(dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to setup event buffers\n");
+ goto err1;
+ }
+
+ dwc3_cache_hwparams(dwc);
+
+ return 0;
+
+err1:
+ dwc3_free_event_buffers(dwc);
+
+err0:
+ return ret;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+ dwc3_event_buffers_cleanup(dwc);
+ dwc3_free_event_buffers(dwc);
+}
+
+#define DWC3_ALIGN_MASK (16 - 1)
+
+static int __devinit dwc3_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct resource *res;
+ struct dwc3 *dwc;
+ void __iomem *regs;
+ unsigned int features = id->driver_data;
+ int ret = -ENOMEM;
+ int irq;
+ void *mem;
+
+ mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+ if (!mem) {
+ dev_err(&pdev->dev, "not enough memory\n");
+ goto err0;
+ }
+ dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
+ dwc->mem = mem;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing resource\n");
+ goto err1;
+ }
+
+ res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "can't request mem region\n");
+ goto err1;
+ }
+
+ regs = ioremap(res->start, resource_size(res));
+ if (!regs) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ goto err2;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "missing IRQ\n");
+ goto err3;
+ }
+
+ spin_lock_init(&dwc->lock);
+ platform_set_drvdata(pdev, dwc);
+
+ dwc->regs = regs;
+ dwc->regs_size = resource_size(res);
+ dwc->dev = &pdev->dev;
+ dwc->irq = irq;
+
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_forbid(&pdev->dev);
+
+ ret = dwc3_core_init(dwc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize core\n");
+ goto err3;
+ }
+
+ if (features & DWC3_HAS_PERIPHERAL) {
+ ret = dwc3_gadget_init(dwc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialized gadget\n");
+ goto err4;
+ }
+ }
+
+ ret = dwc3_debugfs_init(dwc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize debugfs\n");
+ goto err5;
+ }
+
+ pm_runtime_allow(&pdev->dev);
+
+ return 0;
+
+err5:
+ if (features & DWC3_HAS_PERIPHERAL)
+ dwc3_gadget_exit(dwc);
+
+err4:
+ dwc3_core_exit(dwc);
+
+err3:
+ iounmap(regs);
+
+err2:
+ release_mem_region(res->start, resource_size(res));
+
+err1:
+ kfree(dwc->mem);
+
+err0:
+ return ret;
+}
+
+static int __devexit dwc3_remove(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct dwc3 *dwc = platform_get_drvdata(pdev);
+ struct resource *res;
+ unsigned int features = id->driver_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ dwc3_debugfs_exit(dwc);
+
+ if (features & DWC3_HAS_PERIPHERAL)
+ dwc3_gadget_exit(dwc);
+
+ dwc3_core_exit(dwc);
+ release_mem_region(res->start, resource_size(res));
+ iounmap(dwc->regs);
+ kfree(dwc->mem);
+
+ return 0;
+}
+
+static const struct platform_device_id dwc3_id_table[] __devinitconst = {
+ {
+ .name = "dwc3-omap",
+ .driver_data = (DWC3_HAS_PERIPHERAL
+ | DWC3_HAS_XHCI
+ | DWC3_HAS_OTG),
+ },
+ {
+ .name = "dwc3-pci",
+ .driver_data = DWC3_HAS_PERIPHERAL,
+ },
+ { }, /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, dwc3_id_table);
+
+static struct platform_driver dwc3_driver = {
+ .probe = dwc3_probe,
+ .remove = __devexit_p(dwc3_remove),
+ .driver = {
+ .name = "dwc3",
+ },
+ .id_table = dwc3_id_table,
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
+
+static int __devinit dwc3_init(void)
+{
+ return platform_driver_register(&dwc3_driver);
+}
+module_init(dwc3_init);
+
+static void __exit dwc3_exit(void)
+{
+ platform_driver_unregister(&dwc3_driver);
+}
+module_exit(dwc3_exit);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
new file mode 100644
index 0000000..29a8e16
--- /dev/null
+++ b/drivers/usb/dwc3/core.h
@@ -0,0 +1,768 @@
+/**
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Global constants */
+#define DWC3_ENDPOINTS_NUM 32
+
+#define DWC3_EVENT_BUFFERS_NUM 2
+#define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE
+#define DWC3_EVENT_TYPE_MASK 0xfe
+
+#define DWC3_EVENT_TYPE_DEV 0
+#define DWC3_EVENT_TYPE_CARKIT 3
+#define DWC3_EVENT_TYPE_I2C 4
+
+#define DWC3_DEVICE_EVENT_DISCONNECT 0
+#define DWC3_DEVICE_EVENT_RESET 1
+#define DWC3_DEVICE_EVENT_CONNECT_DONE 2
+#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE 3
+#define DWC3_DEVICE_EVENT_WAKEUP 4
+#define DWC3_DEVICE_EVENT_EOPF 6
+#define DWC3_DEVICE_EVENT_SOF 7
+#define DWC3_DEVICE_EVENT_ERRATIC_ERROR 9
+#define DWC3_DEVICE_EVENT_CMD_CMPL 10
+#define DWC3_DEVICE_EVENT_OVERFLOW 11
+
+#define DWC3_GEVNTCOUNT_MASK 0xfffc
+#define DWC3_GSNPSID_MASK 0xffff0000
+#define DWC3_GSNPSREV_MASK 0xffff
+
+/* Global Registers */
+#define DWC3_GSBUSCFG0 0xc100
+#define DWC3_GSBUSCFG1 0xc104
+#define DWC3_GTXTHRCFG 0xc108
+#define DWC3_GRXTHRCFG 0xc10c
+#define DWC3_GCTL 0xc110
+#define DWC3_GEVTEN 0xc114
+#define DWC3_GSTS 0xc118
+#define DWC3_GSNPSID 0xc120
+#define DWC3_GGPIO 0xc124
+#define DWC3_GUID 0xc128
+#define DWC3_GUCTL 0xc12c
+#define DWC3_GBUSERRADDR0 0xc130
+#define DWC3_GBUSERRADDR1 0xc134
+#define DWC3_GPRTBIMAP0 0xc138
+#define DWC3_GPRTBIMAP1 0xc13c
+#define DWC3_GHWPARAMS0 0xc140
+#define DWC3_GHWPARAMS1 0xc144
+#define DWC3_GHWPARAMS2 0xc148
+#define DWC3_GHWPARAMS3 0xc14c
+#define DWC3_GHWPARAMS4 0xc150
+#define DWC3_GHWPARAMS5 0xc154
+#define DWC3_GHWPARAMS6 0xc158
+#define DWC3_GHWPARAMS7 0xc15c
+#define DWC3_GDBGFIFOSPACE 0xc160
+#define DWC3_GDBGLTSSM 0xc164
+#define DWC3_GPRTBIMAP_HS0 0xc180
+#define DWC3_GPRTBIMAP_HS1 0xc184
+#define DWC3_GPRTBIMAP_FS0 0xc188
+#define DWC3_GPRTBIMAP_FS1 0xc18c
+
+#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
+#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
+
+#define DWC3_GUSB2PHYACC(n) (0xc280 + (n * 0x04))
+
+#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + (n * 0x04))
+
+#define DWC3_GTXFIFOSIZ(n) (0xc300 + (n * 0x04))
+#define DWC3_GRXFIFOSIZ(n) (0xc380 + (n * 0x04))
+
+#define DWC3_GEVNTADRLO(n) (0xc400 + (n * 0x10))
+#define DWC3_GEVNTADRHI(n) (0xc404 + (n * 0x10))
+#define DWC3_GEVNTSIZ(n) (0xc408 + (n * 0x10))
+#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
+
+#define DWC3_GHWPARAMS8 0xc600
+
+/* Device Registers */
+#define DWC3_DCFG 0xc700
+#define DWC3_DCTL 0xc704
+#define DWC3_DEVTEN 0xc708
+#define DWC3_DSTS 0xc70c
+#define DWC3_DGCMDPAR 0xc710
+#define DWC3_DGCMD 0xc714
+#define DWC3_DALEPENA 0xc720
+#define DWC3_DEPCMDPAR2(n) (0xc800 + (n * 0x10))
+#define DWC3_DEPCMDPAR1(n) (0xc804 + (n * 0x10))
+#define DWC3_DEPCMDPAR0(n) (0xc808 + (n * 0x10))
+#define DWC3_DEPCMD(n) (0xc80c + (n * 0x10))
+
+/* OTG Registers */
+#define DWC3_OCFG 0xcc00
+#define DWC3_OCTL 0xcc04
+#define DWC3_OEVTEN 0xcc08
+#define DWC3_OSTS 0xcc0C
+
+/* Bit fields */
+
+/* Global Configuration Register */
+#define DWC3_GCTL_PWRDNSCALE(n) (n << 19)
+#define DWC3_GCTL_U2RSTECN (1 << 16)
+#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_CLK_BUS (0)
+#define DWC3_GCTL_CLK_PIPE (1)
+#define DWC3_GCTL_CLK_PIPEHALF (2)
+#define DWC3_GCTL_CLK_MASK (3)
+
+#define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
+#define DWC3_GCTL_PRTCAP_HOST 1
+#define DWC3_GCTL_PRTCAP_DEVICE 2
+#define DWC3_GCTL_PRTCAP_OTG 3
+
+#define DWC3_GCTL_CORESOFTRESET (1 << 11)
+#define DWC3_GCTL_SCALEDOWN(n) (n << 4)
+#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
+#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+
+/* Global HWPARAMS1 Register */
+#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
+#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
+
+/* Device Configuration Register */
+#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
+#define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f)
+
+#define DWC3_DCFG_SPEED_MASK (7 << 0)
+#define DWC3_DCFG_SUPERSPEED (4 << 0)
+#define DWC3_DCFG_HIGHSPEED (0 << 0)
+#define DWC3_DCFG_FULLSPEED2 (1 << 0)
+#define DWC3_DCFG_LOWSPEED (2 << 0)
+#define DWC3_DCFG_FULLSPEED1 (3 << 0)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP (1 << 31)
+#define DWC3_DCTL_CSFTRST (1 << 30)
+#define DWC3_DCTL_LSFTRST (1 << 29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n) (((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
+
+#define DWC3_DCTL_APPL1RES (1 << 23)
+
+#define DWC3_DCTL_INITU2ENA (1 << 12)
+#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
+#define DWC3_DCTL_INITU1ENA (1 << 10)
+#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
+#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
+
+#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
+#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
+
+#define DWC3_DCTL_ULSTCHNG_NO_ACTION (DWC3_DCTL_ULSTCHNGREQ(0))
+#define DWC3_DCTL_ULSTCHNG_SS_DISABLED (DWC3_DCTL_ULSTCHNGREQ(4))
+#define DWC3_DCTL_ULSTCHNG_RX_DETECT (DWC3_DCTL_ULSTCHNGREQ(5))
+#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE (DWC3_DCTL_ULSTCHNGREQ(6))
+#define DWC3_DCTL_ULSTCHNG_RECOVERY (DWC3_DCTL_ULSTCHNGREQ(8))
+#define DWC3_DCTL_ULSTCHNG_COMPLIANCE (DWC3_DCTL_ULSTCHNGREQ(10))
+#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
+
+/* Device Event Enable Register */
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11)
+#define DWC3_DEVTEN_CMDCMPLTEN (1 << 10)
+#define DWC3_DEVTEN_ERRTICERREN (1 << 9)
+#define DWC3_DEVTEN_SOFEN (1 << 7)
+#define DWC3_DEVTEN_EOPFEN (1 << 6)
+#define DWC3_DEVTEN_WKUPEVTEN (1 << 4)
+#define DWC3_DEVTEN_ULSTCNGEN (1 << 3)
+#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2)
+#define DWC3_DEVTEN_USBRSTEN (1 << 1)
+#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0)
+
+/* Device Status Register */
+#define DWC3_DSTS_PWRUPREQ (1 << 24)
+#define DWC3_DSTS_COREIDLE (1 << 23)
+#define DWC3_DSTS_DEVCTRLHLT (1 << 22)
+
+#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY (1 << 17)
+
+#define DWC3_DSTS_SOFFN_MASK (0x3ff << 3)
+#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
+
+#define DWC3_DSTS_CONNECTSPD (7 << 0)
+
+#define DWC3_DSTS_SUPERSPEED (4 << 0)
+#define DWC3_DSTS_HIGHSPEED (0 << 0)
+#define DWC3_DSTS_FULLSPEED2 (1 << 0)
+#define DWC3_DSTS_LOWSPEED (2 << 0)
+#define DWC3_DSTS_FULLSPEED1 (3 << 0)
+
+/* Device Generic Command Register */
+#define DWC3_DGCMD_SET_LMP 0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR 0x02
+#define DWC3_DGCMD_XMIT_FUNCTION 0x03
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH 0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH 0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
+
+/* Device Endpoint Command Register */
+#define DWC3_DEPCMD_PARAM_SHIFT 16
+#define DWC3_DEPCMD_PARAM(x) (x << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x) ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
+#define DWC3_DEPCMD_STATUS(x) ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
+#define DWC3_DEPCMD_CMDACT (1 << 10)
+#define DWC3_DEPCMD_CMDIOC (1 << 8)
+
+#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0)
+#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0)
+#define DWC3_DEPCMD_UPDATETRANSFER (0x07 << 0)
+#define DWC3_DEPCMD_STARTTRANSFER (0x06 << 0)
+#define DWC3_DEPCMD_CLEARSTALL (0x05 << 0)
+#define DWC3_DEPCMD_SETSTALL (0x04 << 0)
+#define DWC3_DEPCMD_GETSEQNUMBER (0x03 << 0)
+#define DWC3_DEPCMD_SETTRANSFRESOURCE (0x02 << 0)
+#define DWC3_DEPCMD_SETEPCONFIG (0x01 << 0)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n) (1 << n)
+
+#define DWC3_DEPCMD_TYPE_CONTROL 0
+#define DWC3_DEPCMD_TYPE_ISOC 1
+#define DWC3_DEPCMD_TYPE_BULK 2
+#define DWC3_DEPCMD_TYPE_INTR 3
+
+/* Structures */
+
+struct dwc3_trb_hw;
+
+/**
+ * struct dwc3_event_buffer - Software event buffer representation
+ * @list: a list of event buffers
+ * @buf: _THE_ buffer
+ * @length: size of this buffer
+ * @dma: dma_addr_t
+ * @dwc: pointer to DWC controller
+ */
+struct dwc3_event_buffer {
+ void *buf;
+ unsigned length;
+ unsigned int lpos;
+
+ dma_addr_t dma;
+
+ struct dwc3 *dwc;
+};
+
+#define DWC3_EP_FLAG_STALLED (1 << 0)
+#define DWC3_EP_FLAG_WEDGED (1 << 1)
+
+#define DWC3_EP_DIRECTION_TX true
+#define DWC3_EP_DIRECTION_RX false
+
+#define DWC3_TRB_NUM 32
+#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1)
+
+/**
+ * struct dwc3_ep - device side endpoint representation
+ * @endpoint: usb endpoint
+ * @request_list: list of requests for this endpoint
+ * @req_queued: list of requests on this ep which have TRBs setup
+ * @trb_pool: array of transaction buffers
+ * @trb_pool_dma: dma address of @trb_pool
+ * @free_slot: next slot which is going to be used
+ * @busy_slot: first slot which is owned by HW
+ * @desc: usb_endpoint_descriptor pointer
+ * @dwc: pointer to DWC controller
+ * @flags: endpoint flags (wedged, stalled, ...)
+ * @current_trb: index of current used trb
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @res_trans_idx: Resource transfer index
+ * @interval: the intervall on which the ISOC transfer is started
+ * @name: a human readable name e.g. ep1out-bulk
+ * @direction: true for TX, false for RX
+ * @stream_capable: true when streams are enabled
+ */
+struct dwc3_ep {
+ struct usb_ep endpoint;
+ struct list_head request_list;
+ struct list_head req_queued;
+
+ struct dwc3_trb_hw *trb_pool;
+ dma_addr_t trb_pool_dma;
+ u32 free_slot;
+ u32 busy_slot;
+ const struct usb_endpoint_descriptor *desc;
+ struct dwc3 *dwc;
+
+ unsigned flags;
+#define DWC3_EP_ENABLED (1 << 0)
+#define DWC3_EP_STALL (1 << 1)
+#define DWC3_EP_WEDGE (1 << 2)
+#define DWC3_EP_BUSY (1 << 4)
+#define DWC3_EP_PENDING_REQUEST (1 << 5)
+
+ /* This last one is specific to EP0 */
+#define DWC3_EP0_DIR_IN (1 << 31)
+
+ unsigned current_trb;
+
+ u8 number;
+ u8 type;
+ u8 res_trans_idx;
+ u32 interval;
+
+ char name[20];
+
+ unsigned direction:1;
+ unsigned stream_capable:1;
+};
+
+enum dwc3_phy {
+ DWC3_PHY_UNKNOWN = 0,
+ DWC3_PHY_USB3,
+ DWC3_PHY_USB2,
+};
+
+enum dwc3_ep0_next {
+ DWC3_EP0_UNKNOWN = 0,
+ DWC3_EP0_COMPLETE,
+ DWC3_EP0_NRDY_SETUP,
+ DWC3_EP0_NRDY_DATA,
+ DWC3_EP0_NRDY_STATUS,
+};
+
+enum dwc3_ep0_state {
+ EP0_UNCONNECTED = 0,
+ EP0_SETUP_PHASE,
+ EP0_DATA_PHASE,
+ EP0_STATUS_PHASE,
+};
+
+enum dwc3_link_state {
+ /* In SuperSpeed */
+ DWC3_LINK_STATE_U0 = 0x00, /* in HS, means ON */
+ DWC3_LINK_STATE_U1 = 0x01,
+ DWC3_LINK_STATE_U2 = 0x02, /* in HS, means SLEEP */
+ DWC3_LINK_STATE_U3 = 0x03, /* in HS, means SUSPEND */
+ DWC3_LINK_STATE_SS_DIS = 0x04,
+ DWC3_LINK_STATE_RX_DET = 0x05, /* in HS, means Early Suspend */
+ DWC3_LINK_STATE_SS_INACT = 0x06,
+ DWC3_LINK_STATE_POLL = 0x07,
+ DWC3_LINK_STATE_RECOV = 0x08,
+ DWC3_LINK_STATE_HRESET = 0x09,
+ DWC3_LINK_STATE_CMPLY = 0x0a,
+ DWC3_LINK_STATE_LPBK = 0x0b,
+ DWC3_LINK_STATE_MASK = 0x0f,
+};
+
+enum dwc3_device_state {
+ DWC3_DEFAULT_STATE,
+ DWC3_ADDRESS_STATE,
+ DWC3_CONFIGURED_STATE,
+};
+
+/**
+ * struct dwc3_trb - transfer request block
+ * @bpl: lower 32bit of the buffer
+ * @bph: higher 32bit of the buffer
+ * @length: buffer size (up to 16mb - 1)
+ * @pcm1: packet count m1
+ * @trbsts: trb status
+ * 0 = ok
+ * 1 = missed isoc
+ * 2 = setup pending
+ * @hwo: hardware owner of descriptor
+ * @lst: last trb
+ * @chn: chain buffers
+ * @csp: continue on short packets (only supported on isoc eps)
+ * @trbctl: trb control
+ * 1 = normal
+ * 2 = control-setup
+ * 3 = control-status-2
+ * 4 = control-status-3
+ * 5 = control-data (first trb of data stage)
+ * 6 = isochronous-first (first trb of service interval)
+ * 7 = isochronous
+ * 8 = link trb
+ * others = reserved
+ * @isp_imi: interrupt on short packet / interrupt on missed isoc
+ * @ioc: interrupt on complete
+ * @sid_sofn: Stream ID / SOF Number
+ */
+struct dwc3_trb {
+ u64 bplh;
+
+ union {
+ struct {
+ u32 length:24;
+ u32 pcm1:2;
+ u32 reserved27_26:2;
+ u32 trbsts:4;
+#define DWC3_TRB_STS_OKAY 0
+#define DWC3_TRB_STS_MISSED_ISOC 1
+#define DWC3_TRB_STS_SETUP_PENDING 2
+ };
+ u32 len_pcm;
+ };
+
+ union {
+ struct {
+ u32 hwo:1;
+ u32 lst:1;
+ u32 chn:1;
+ u32 csp:1;
+ u32 trbctl:6;
+ u32 isp_imi:1;
+ u32 ioc:1;
+ u32 reserved13_12:2;
+ u32 sid_sofn:16;
+ u32 reserved31_30:2;
+ };
+ u32 control;
+ };
+} __packed;
+
+/**
+ * struct dwc3_trb_hw - transfer request block (hw format)
+ * @bpl: DW0-3
+ * @bph: DW4-7
+ * @size: DW8-B
+ * @trl: DWC-F
+ */
+struct dwc3_trb_hw {
+ __le32 bpl;
+ __le32 bph;
+ __le32 size;
+ __le32 ctrl;
+} __packed;
+
+static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
+{
+ hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
+ hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
+ hw->size = cpu_to_le32p(&nat->len_pcm);
+ /* HWO is written last */
+ hw->ctrl = cpu_to_le32p(&nat->control);
+}
+
+static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
+{
+ u64 bplh;
+
+ bplh = le32_to_cpup(&hw->bpl);
+ bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
+ nat->bplh = bplh;
+
+ nat->len_pcm = le32_to_cpup(&hw->size);
+ nat->control = le32_to_cpup(&hw->ctrl);
+}
+
+/**
+ * dwc3_hwparams - copy of HWPARAMS registers
+ * @hwparams0 - GHWPARAMS0
+ * @hwparams1 - GHWPARAMS1
+ * @hwparams2 - GHWPARAMS2
+ * @hwparams3 - GHWPARAMS3
+ * @hwparams4 - GHWPARAMS4
+ * @hwparams5 - GHWPARAMS5
+ * @hwparams6 - GHWPARAMS6
+ * @hwparams7 - GHWPARAMS7
+ * @hwparams8 - GHWPARAMS8
+ */
+struct dwc3_hwparams {
+ u32 hwparams0;
+ u32 hwparams1;
+ u32 hwparams2;
+ u32 hwparams3;
+ u32 hwparams4;
+ u32 hwparams5;
+ u32 hwparams6;
+ u32 hwparams7;
+ u32 hwparams8;
+};
+
+/**
+ * struct dwc3 - representation of our controller
+ * @ctrl_req: usb control request which is used for ep0
+ * @ep0_trb: trb which is used for the ctrl_req
+ * @ep0_bounce: bounce buffer for ep0
+ * @setup_buf: used while precessing STD USB requests
+ * @ctrl_req_addr: dma address of ctrl_req
+ * @ep0_trb: dma address of ep0_trb
+ * @ep0_usb_req: dummy req used while handling STD USB requests
+ * @setup_buf_addr: dma address of setup_buf
+ * @ep0_bounce_addr: dma address of ep0_bounce
+ * @lock: for synchronizing
+ * @dev: pointer to our struct device
+ * @event_buffer_list: a list of event buffers
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @irq: IRQ number
+ * @revision: revision register contents
+ * @is_selfpowered: true when we are selfpowered
+ * @three_stage_setup: set if we perform a three phase setup
+ * @ep0_status_pending: ep0 status response without a req is pending
+ * @ep0_bounced: true when we used bounce buffer
+ * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @start_config_issued: true when StartConfig command has been issued
+ * @ep0_next_event: hold the next expected event
+ * @ep0state: state of endpoint zero
+ * @link_state: link state
+ * @speed: device speed (super, high, full, low)
+ * @mem: points to start of memory which is used for this struct.
+ * @hwparams: copy of hwparams registers
+ * @root: debugfs root folder pointer
+ */
+struct dwc3 {
+ struct usb_ctrlrequest *ctrl_req;
+ struct dwc3_trb_hw *ep0_trb;
+ void *ep0_bounce;
+ u8 *setup_buf;
+ dma_addr_t ctrl_req_addr;
+ dma_addr_t ep0_trb_addr;
+ dma_addr_t setup_buf_addr;
+ dma_addr_t ep0_bounce_addr;
+ struct usb_request ep0_usb_req;
+ /* device lock */
+ spinlock_t lock;
+ struct device *dev;
+
+ struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
+ struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM];
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *gadget_driver;
+
+ void __iomem *regs;
+ size_t regs_size;
+
+ int irq;
+
+ u32 revision;
+
+#define DWC3_REVISION_173A 0x5533173a
+#define DWC3_REVISION_175A 0x5533175a
+#define DWC3_REVISION_180A 0x5533180a
+#define DWC3_REVISION_183A 0x5533183a
+#define DWC3_REVISION_185A 0x5533185a
+#define DWC3_REVISION_188A 0x5533188a
+#define DWC3_REVISION_190A 0x5533190a
+
+ unsigned is_selfpowered:1;
+ unsigned three_stage_setup:1;
+ unsigned ep0_status_pending:1;
+ unsigned ep0_bounced:1;
+ unsigned ep0_expect_in:1;
+ unsigned start_config_issued:1;
+
+ enum dwc3_ep0_next ep0_next_event;
+ enum dwc3_ep0_state ep0state;
+ enum dwc3_link_state link_state;
+ enum dwc3_device_state dev_state;
+
+ u8 speed;
+ void *mem;
+
+ struct dwc3_hwparams hwparams;
+ struct dentry *root;
+};
+
+/* -------------------------------------------------------------------------- */
+
+#define DWC3_TRBSTS_OK 0
+#define DWC3_TRBSTS_MISSED_ISOC 1
+#define DWC3_TRBSTS_SETUP_PENDING 2
+
+#define DWC3_TRBCTL_NORMAL 1
+#define DWC3_TRBCTL_CONTROL_SETUP 2
+#define DWC3_TRBCTL_CONTROL_STATUS2 3
+#define DWC3_TRBCTL_CONTROL_STATUS3 4
+#define DWC3_TRBCTL_CONTROL_DATA 5
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6
+#define DWC3_TRBCTL_ISOCHRONOUS 7
+#define DWC3_TRBCTL_LINK_TRB 8
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_event_type {
+ u32 is_devspec:1;
+ u32 type:6;
+ u32 reserved8_31:25;
+} __packed;
+
+#define DWC3_DEPEVT_XFERCOMPLETE 0x01
+#define DWC3_DEPEVT_XFERINPROGRESS 0x02
+#define DWC3_DEPEVT_XFERNOTREADY 0x03
+#define DWC3_DEPEVT_RXTXFIFOEVT 0x04
+#define DWC3_DEPEVT_STREAMEVT 0x06
+#define DWC3_DEPEVT_EPCMDCMPLT 0x07
+
+/**
+ * struct dwc3_event_depvt - Device Endpoint Events
+ * @one_bit: indicates this is an endpoint event (not used)
+ * @endpoint_number: number of the endpoint
+ * @endpoint_event: The event we have:
+ * 0x00 - Reserved
+ * 0x01 - XferComplete
+ * 0x02 - XferInProgress
+ * 0x03 - XferNotReady
+ * 0x04 - RxTxFifoEvt (IN->Underrun, OUT->Overrun)
+ * 0x05 - Reserved
+ * 0x06 - StreamEvt
+ * 0x07 - EPCmdCmplt
+ * @reserved11_10: Reserved, don't use.
+ * @status: Indicates the status of the event. Refer to databook for
+ * more information.
+ * @parameters: Parameters of the current event. Refer to databook for
+ * more information.
+ */
+struct dwc3_event_depevt {
+ u32 one_bit:1;
+ u32 endpoint_number:5;
+ u32 endpoint_event:4;
+ u32 reserved11_10:2;
+ u32 status:4;
+#define DEPEVT_STATUS_BUSERR (1 << 0)
+#define DEPEVT_STATUS_SHORT (1 << 1)
+#define DEPEVT_STATUS_IOC (1 << 2)
+#define DEPEVT_STATUS_LST (1 << 3)
+
+/* Stream event only */
+#define DEPEVT_STREAMEVT_FOUND 1
+#define DEPEVT_STREAMEVT_NOTFOUND 2
+
+/* Control-only Status */
+#define DEPEVT_STATUS_CONTROL_SETUP 0
+#define DEPEVT_STATUS_CONTROL_DATA 1
+#define DEPEVT_STATUS_CONTROL_STATUS 2
+
+ u32 parameters:16;
+} __packed;
+
+/**
+ * struct dwc3_event_devt - Device Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's a device event. Should read as 0x00
+ * @type: indicates the type of device event.
+ * 0 - DisconnEvt
+ * 1 - USBRst
+ * 2 - ConnectDone
+ * 3 - ULStChng
+ * 4 - WkUpEvt
+ * 5 - Reserved
+ * 6 - EOPF
+ * 7 - SOF
+ * 8 - Reserved
+ * 9 - ErrticErr
+ * 10 - CmdCmplt
+ * 11 - EvntOverflow
+ * 12 - VndrDevTstRcved
+ * @reserved15_12: Reserved, not used
+ * @event_info: Information about this event
+ * @reserved31_24: Reserved, not used
+ */
+struct dwc3_event_devt {
+ u32 one_bit:1;
+ u32 device_event:7;
+ u32 type:4;
+ u32 reserved15_12:4;
+ u32 event_info:8;
+ u32 reserved31_24:8;
+} __packed;
+
+/**
+ * struct dwc3_event_gevt - Other Core Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
+ * @phy_port_number: self-explanatory
+ * @reserved31_12: Reserved, not used.
+ */
+struct dwc3_event_gevt {
+ u32 one_bit:1;
+ u32 device_event:7;
+ u32 phy_port_number:4;
+ u32 reserved31_12:20;
+} __packed;
+
+/**
+ * union dwc3_event - representation of Event Buffer contents
+ * @raw: raw 32-bit event
+ * @type: the type of the event
+ * @depevt: Device Endpoint Event
+ * @devt: Device Event
+ * @gevt: Global Event
+ */
+union dwc3_event {
+ u32 raw;
+ struct dwc3_event_type type;
+ struct dwc3_event_depevt depevt;
+ struct dwc3_event_devt devt;
+ struct dwc3_event_gevt gevt;
+};
+
+/*
+ * DWC3 Features to be used as Driver Data
+ */
+
+#define DWC3_HAS_PERIPHERAL BIT(0)
+#define DWC3_HAS_XHCI BIT(1)
+#define DWC3_HAS_OTG BIT(3)
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
new file mode 100644
index 0000000..5894ee8
--- /dev/null
+++ b/drivers/usb/dwc3/debug.h
@@ -0,0 +1,50 @@
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_DEBUG_FS
+extern int dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline int dwc3_debugfs_init(struct dwc3 *d)
+{ return 0; }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{ }
+#endif
+
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
new file mode 100644
index 0000000..da1ad77
--- /dev/null
+++ b/drivers/usb/dwc3/debugfs.c
@@ -0,0 +1,441 @@
+/**
+ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+struct dwc3_register {
+ const char *name;
+ u32 offset;
+};
+
+#define dump_register(nm) \
+{ \
+ .name = __stringify(nm), \
+ .offset = DWC3_ ##nm, \
+}
+
+static const struct dwc3_register dwc3_regs[] = {
+ dump_register(GSBUSCFG0),
+ dump_register(GSBUSCFG1),
+ dump_register(GTXTHRCFG),
+ dump_register(GRXTHRCFG),
+ dump_register(GCTL),
+ dump_register(GEVTEN),
+ dump_register(GSTS),
+ dump_register(GSNPSID),
+ dump_register(GGPIO),
+ dump_register(GUID),
+ dump_register(GUCTL),
+ dump_register(GBUSERRADDR0),
+ dump_register(GBUSERRADDR1),
+ dump_register(GPRTBIMAP0),
+ dump_register(GPRTBIMAP1),
+ dump_register(GHWPARAMS0),
+ dump_register(GHWPARAMS1),
+ dump_register(GHWPARAMS2),
+ dump_register(GHWPARAMS3),
+ dump_register(GHWPARAMS4),
+ dump_register(GHWPARAMS5),
+ dump_register(GHWPARAMS6),
+ dump_register(GHWPARAMS7),
+ dump_register(GDBGFIFOSPACE),
+ dump_register(GDBGLTSSM),
+ dump_register(GPRTBIMAP_HS0),
+ dump_register(GPRTBIMAP_HS1),
+ dump_register(GPRTBIMAP_FS0),
+ dump_register(GPRTBIMAP_FS1),
+
+ dump_register(GUSB2PHYCFG(0)),
+ dump_register(GUSB2PHYCFG(1)),
+ dump_register(GUSB2PHYCFG(2)),
+ dump_register(GUSB2PHYCFG(3)),
+ dump_register(GUSB2PHYCFG(4)),
+ dump_register(GUSB2PHYCFG(5)),
+ dump_register(GUSB2PHYCFG(6)),
+ dump_register(GUSB2PHYCFG(7)),
+ dump_register(GUSB2PHYCFG(8)),
+ dump_register(GUSB2PHYCFG(9)),
+ dump_register(GUSB2PHYCFG(10)),
+ dump_register(GUSB2PHYCFG(11)),
+ dump_register(GUSB2PHYCFG(12)),
+ dump_register(GUSB2PHYCFG(13)),
+ dump_register(GUSB2PHYCFG(14)),
+ dump_register(GUSB2PHYCFG(15)),
+
+ dump_register(GUSB2I2CCTL(0)),
+ dump_register(GUSB2I2CCTL(1)),
+ dump_register(GUSB2I2CCTL(2)),
+ dump_register(GUSB2I2CCTL(3)),
+ dump_register(GUSB2I2CCTL(4)),
+ dump_register(GUSB2I2CCTL(5)),
+ dump_register(GUSB2I2CCTL(6)),
+ dump_register(GUSB2I2CCTL(7)),
+ dump_register(GUSB2I2CCTL(8)),
+ dump_register(GUSB2I2CCTL(9)),
+ dump_register(GUSB2I2CCTL(10)),
+ dump_register(GUSB2I2CCTL(11)),
+ dump_register(GUSB2I2CCTL(12)),
+ dump_register(GUSB2I2CCTL(13)),
+ dump_register(GUSB2I2CCTL(14)),
+ dump_register(GUSB2I2CCTL(15)),
+
+ dump_register(GUSB2PHYACC(0)),
+ dump_register(GUSB2PHYACC(1)),
+ dump_register(GUSB2PHYACC(2)),
+ dump_register(GUSB2PHYACC(3)),
+ dump_register(GUSB2PHYACC(4)),
+ dump_register(GUSB2PHYACC(5)),
+ dump_register(GUSB2PHYACC(6)),
+ dump_register(GUSB2PHYACC(7)),
+ dump_register(GUSB2PHYACC(8)),
+ dump_register(GUSB2PHYACC(9)),
+ dump_register(GUSB2PHYACC(10)),
+ dump_register(GUSB2PHYACC(11)),
+ dump_register(GUSB2PHYACC(12)),
+ dump_register(GUSB2PHYACC(13)),
+ dump_register(GUSB2PHYACC(14)),
+ dump_register(GUSB2PHYACC(15)),
+
+ dump_register(GUSB3PIPECTL(0)),
+ dump_register(GUSB3PIPECTL(1)),
+ dump_register(GUSB3PIPECTL(2)),
+ dump_register(GUSB3PIPECTL(3)),
+ dump_register(GUSB3PIPECTL(4)),
+ dump_register(GUSB3PIPECTL(5)),
+ dump_register(GUSB3PIPECTL(6)),
+ dump_register(GUSB3PIPECTL(7)),
+ dump_register(GUSB3PIPECTL(8)),
+ dump_register(GUSB3PIPECTL(9)),
+ dump_register(GUSB3PIPECTL(10)),
+ dump_register(GUSB3PIPECTL(11)),
+ dump_register(GUSB3PIPECTL(12)),
+ dump_register(GUSB3PIPECTL(13)),
+ dump_register(GUSB3PIPECTL(14)),
+ dump_register(GUSB3PIPECTL(15)),
+
+ dump_register(GTXFIFOSIZ(0)),
+ dump_register(GTXFIFOSIZ(1)),
+ dump_register(GTXFIFOSIZ(2)),
+ dump_register(GTXFIFOSIZ(3)),
+ dump_register(GTXFIFOSIZ(4)),
+ dump_register(GTXFIFOSIZ(5)),
+ dump_register(GTXFIFOSIZ(6)),
+ dump_register(GTXFIFOSIZ(7)),
+ dump_register(GTXFIFOSIZ(8)),
+ dump_register(GTXFIFOSIZ(9)),
+ dump_register(GTXFIFOSIZ(10)),
+ dump_register(GTXFIFOSIZ(11)),
+ dump_register(GTXFIFOSIZ(12)),
+ dump_register(GTXFIFOSIZ(13)),
+ dump_register(GTXFIFOSIZ(14)),
+ dump_register(GTXFIFOSIZ(15)),
+ dump_register(GTXFIFOSIZ(16)),
+ dump_register(GTXFIFOSIZ(17)),
+ dump_register(GTXFIFOSIZ(18)),
+ dump_register(GTXFIFOSIZ(19)),
+ dump_register(GTXFIFOSIZ(20)),
+ dump_register(GTXFIFOSIZ(21)),
+ dump_register(GTXFIFOSIZ(22)),
+ dump_register(GTXFIFOSIZ(23)),
+ dump_register(GTXFIFOSIZ(24)),
+ dump_register(GTXFIFOSIZ(25)),
+ dump_register(GTXFIFOSIZ(26)),
+ dump_register(GTXFIFOSIZ(27)),
+ dump_register(GTXFIFOSIZ(28)),
+ dump_register(GTXFIFOSIZ(29)),
+ dump_register(GTXFIFOSIZ(30)),
+ dump_register(GTXFIFOSIZ(31)),
+
+ dump_register(GRXFIFOSIZ(0)),
+ dump_register(GRXFIFOSIZ(1)),
+ dump_register(GRXFIFOSIZ(2)),
+ dump_register(GRXFIFOSIZ(3)),
+ dump_register(GRXFIFOSIZ(4)),
+ dump_register(GRXFIFOSIZ(5)),
+ dump_register(GRXFIFOSIZ(6)),
+ dump_register(GRXFIFOSIZ(7)),
+ dump_register(GRXFIFOSIZ(8)),
+ dump_register(GRXFIFOSIZ(9)),
+ dump_register(GRXFIFOSIZ(10)),
+ dump_register(GRXFIFOSIZ(11)),
+ dump_register(GRXFIFOSIZ(12)),
+ dump_register(GRXFIFOSIZ(13)),
+ dump_register(GRXFIFOSIZ(14)),
+ dump_register(GRXFIFOSIZ(15)),
+ dump_register(GRXFIFOSIZ(16)),
+ dump_register(GRXFIFOSIZ(17)),
+ dump_register(GRXFIFOSIZ(18)),
+ dump_register(GRXFIFOSIZ(19)),
+ dump_register(GRXFIFOSIZ(20)),
+ dump_register(GRXFIFOSIZ(21)),
+ dump_register(GRXFIFOSIZ(22)),
+ dump_register(GRXFIFOSIZ(23)),
+ dump_register(GRXFIFOSIZ(24)),
+ dump_register(GRXFIFOSIZ(25)),
+ dump_register(GRXFIFOSIZ(26)),
+ dump_register(GRXFIFOSIZ(27)),
+ dump_register(GRXFIFOSIZ(28)),
+ dump_register(GRXFIFOSIZ(29)),
+ dump_register(GRXFIFOSIZ(30)),
+ dump_register(GRXFIFOSIZ(31)),
+
+ dump_register(GEVNTADRLO(0)),
+ dump_register(GEVNTADRHI(0)),
+ dump_register(GEVNTSIZ(0)),
+ dump_register(GEVNTCOUNT(0)),
+
+ dump_register(GHWPARAMS8),
+ dump_register(DCFG),
+ dump_register(DCTL),
+ dump_register(DEVTEN),
+ dump_register(DSTS),
+ dump_register(DGCMDPAR),
+ dump_register(DGCMD),
+ dump_register(DALEPENA),
+
+ dump_register(DEPCMDPAR2(0)),
+ dump_register(DEPCMDPAR2(1)),
+ dump_register(DEPCMDPAR2(2)),
+ dump_register(DEPCMDPAR2(3)),
+ dump_register(DEPCMDPAR2(4)),
+ dump_register(DEPCMDPAR2(5)),
+ dump_register(DEPCMDPAR2(6)),
+ dump_register(DEPCMDPAR2(7)),
+ dump_register(DEPCMDPAR2(8)),
+ dump_register(DEPCMDPAR2(9)),
+ dump_register(DEPCMDPAR2(10)),
+ dump_register(DEPCMDPAR2(11)),
+ dump_register(DEPCMDPAR2(12)),
+ dump_register(DEPCMDPAR2(13)),
+ dump_register(DEPCMDPAR2(14)),
+ dump_register(DEPCMDPAR2(15)),
+ dump_register(DEPCMDPAR2(16)),
+ dump_register(DEPCMDPAR2(17)),
+ dump_register(DEPCMDPAR2(18)),
+ dump_register(DEPCMDPAR2(19)),
+ dump_register(DEPCMDPAR2(20)),
+ dump_register(DEPCMDPAR2(21)),
+ dump_register(DEPCMDPAR2(22)),
+ dump_register(DEPCMDPAR2(23)),
+ dump_register(DEPCMDPAR2(24)),
+ dump_register(DEPCMDPAR2(25)),
+ dump_register(DEPCMDPAR2(26)),
+ dump_register(DEPCMDPAR2(27)),
+ dump_register(DEPCMDPAR2(28)),
+ dump_register(DEPCMDPAR2(29)),
+ dump_register(DEPCMDPAR2(30)),
+ dump_register(DEPCMDPAR2(31)),
+
+ dump_register(DEPCMDPAR1(0)),
+ dump_register(DEPCMDPAR1(1)),
+ dump_register(DEPCMDPAR1(2)),
+ dump_register(DEPCMDPAR1(3)),
+ dump_register(DEPCMDPAR1(4)),
+ dump_register(DEPCMDPAR1(5)),
+ dump_register(DEPCMDPAR1(6)),
+ dump_register(DEPCMDPAR1(7)),
+ dump_register(DEPCMDPAR1(8)),
+ dump_register(DEPCMDPAR1(9)),
+ dump_register(DEPCMDPAR1(10)),
+ dump_register(DEPCMDPAR1(11)),
+ dump_register(DEPCMDPAR1(12)),
+ dump_register(DEPCMDPAR1(13)),
+ dump_register(DEPCMDPAR1(14)),
+ dump_register(DEPCMDPAR1(15)),
+ dump_register(DEPCMDPAR1(16)),
+ dump_register(DEPCMDPAR1(17)),
+ dump_register(DEPCMDPAR1(18)),
+ dump_register(DEPCMDPAR1(19)),
+ dump_register(DEPCMDPAR1(20)),
+ dump_register(DEPCMDPAR1(21)),
+ dump_register(DEPCMDPAR1(22)),
+ dump_register(DEPCMDPAR1(23)),
+ dump_register(DEPCMDPAR1(24)),
+ dump_register(DEPCMDPAR1(25)),
+ dump_register(DEPCMDPAR1(26)),
+ dump_register(DEPCMDPAR1(27)),
+ dump_register(DEPCMDPAR1(28)),
+ dump_register(DEPCMDPAR1(29)),
+ dump_register(DEPCMDPAR1(30)),
+ dump_register(DEPCMDPAR1(31)),
+
+ dump_register(DEPCMDPAR0(0)),
+ dump_register(DEPCMDPAR0(1)),
+ dump_register(DEPCMDPAR0(2)),
+ dump_register(DEPCMDPAR0(3)),
+ dump_register(DEPCMDPAR0(4)),
+ dump_register(DEPCMDPAR0(5)),
+ dump_register(DEPCMDPAR0(6)),
+ dump_register(DEPCMDPAR0(7)),
+ dump_register(DEPCMDPAR0(8)),
+ dump_register(DEPCMDPAR0(9)),
+ dump_register(DEPCMDPAR0(10)),
+ dump_register(DEPCMDPAR0(11)),
+ dump_register(DEPCMDPAR0(12)),
+ dump_register(DEPCMDPAR0(13)),
+ dump_register(DEPCMDPAR0(14)),
+ dump_register(DEPCMDPAR0(15)),
+ dump_register(DEPCMDPAR0(16)),
+ dump_register(DEPCMDPAR0(17)),
+ dump_register(DEPCMDPAR0(18)),
+ dump_register(DEPCMDPAR0(19)),
+ dump_register(DEPCMDPAR0(20)),
+ dump_register(DEPCMDPAR0(21)),
+ dump_register(DEPCMDPAR0(22)),
+ dump_register(DEPCMDPAR0(23)),
+ dump_register(DEPCMDPAR0(24)),
+ dump_register(DEPCMDPAR0(25)),
+ dump_register(DEPCMDPAR0(26)),
+ dump_register(DEPCMDPAR0(27)),
+ dump_register(DEPCMDPAR0(28)),
+ dump_register(DEPCMDPAR0(29)),
+ dump_register(DEPCMDPAR0(30)),
+ dump_register(DEPCMDPAR0(31)),
+
+ dump_register(DEPCMD(0)),
+ dump_register(DEPCMD(1)),
+ dump_register(DEPCMD(2)),
+ dump_register(DEPCMD(3)),
+ dump_register(DEPCMD(4)),
+ dump_register(DEPCMD(5)),
+ dump_register(DEPCMD(6)),
+ dump_register(DEPCMD(7)),
+ dump_register(DEPCMD(8)),
+ dump_register(DEPCMD(9)),
+ dump_register(DEPCMD(10)),
+ dump_register(DEPCMD(11)),
+ dump_register(DEPCMD(12)),
+ dump_register(DEPCMD(13)),
+ dump_register(DEPCMD(14)),
+ dump_register(DEPCMD(15)),
+ dump_register(DEPCMD(16)),
+ dump_register(DEPCMD(17)),
+ dump_register(DEPCMD(18)),
+ dump_register(DEPCMD(19)),
+ dump_register(DEPCMD(20)),
+ dump_register(DEPCMD(21)),
+ dump_register(DEPCMD(22)),
+ dump_register(DEPCMD(23)),
+ dump_register(DEPCMD(24)),
+ dump_register(DEPCMD(25)),
+ dump_register(DEPCMD(26)),
+ dump_register(DEPCMD(27)),
+ dump_register(DEPCMD(28)),
+ dump_register(DEPCMD(29)),
+ dump_register(DEPCMD(30)),
+ dump_register(DEPCMD(31)),
+
+ dump_register(OCFG),
+ dump_register(OCTL),
+ dump_register(OEVTEN),
+ dump_register(OSTS),
+};
+
+static int dwc3_regdump_show(struct seq_file *s, void *unused)
+{
+ struct dwc3 *dwc = s->private;
+ int i;
+
+ seq_printf(s, "DesignWare USB3 Core Register Dump\n");
+
+ for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++) {
+ seq_printf(s, "%-20s : %08x\n", dwc3_regs[i].name,
+ dwc3_readl(dwc->regs, dwc3_regs[i].offset));
+ }
+
+ return 0;
+}
+
+static int dwc3_regdump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_regdump_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_regdump_fops = {
+ .open = dwc3_regdump_open,
+ .read = seq_read,
+ .release = single_release,
+};
+
+int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
+{
+ struct dentry *root;
+ struct dentry *file;
+ int ret;
+
+ root = debugfs_create_dir(dev_name(dwc->dev), NULL);
+ if (IS_ERR(root)){
+ ret = PTR_ERR(root);
+ goto err0;
+ }
+
+ dwc->root = root;
+
+ file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
+ &dwc3_regdump_fops);
+ if (IS_ERR(file)) {
+ ret = PTR_ERR(file);
+ goto err1;
+ }
+ return 0;
+
+err1:
+ debugfs_remove_recursive(root);
+
+err0:
+ return ret;
+}
+
+void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
+{
+ debugfs_remove_recursive(dwc->root);
+ dwc->root = NULL;
+}
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
new file mode 100644
index 0000000..062552b
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -0,0 +1,401 @@
+/**
+ * dwc3-omap.c - OMAP Specific Glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-omap.h>
+#include <linux/dma-mapping.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include "io.h"
+
+/*
+ * All these registers belong to OMAP's Wrapper around the
+ * DesignWare USB3 Core.
+ */
+
+#define USBOTGSS_REVISION 0x0000
+#define USBOTGSS_SYSCONFIG 0x0010
+#define USBOTGSS_IRQ_EOI 0x0020
+#define USBOTGSS_IRQSTATUS_RAW_0 0x0024
+#define USBOTGSS_IRQSTATUS_0 0x0028
+#define USBOTGSS_IRQENABLE_SET_0 0x002c
+#define USBOTGSS_IRQENABLE_CLR_0 0x0030
+#define USBOTGSS_IRQSTATUS_RAW_1 0x0034
+#define USBOTGSS_IRQSTATUS_1 0x0038
+#define USBOTGSS_IRQENABLE_SET_1 0x003c
+#define USBOTGSS_IRQENABLE_CLR_1 0x0040
+#define USBOTGSS_UTMI_OTG_CTRL 0x0080
+#define USBOTGSS_UTMI_OTG_STATUS 0x0084
+#define USBOTGSS_MMRAM_OFFSET 0x0100
+#define USBOTGSS_FLADJ 0x0104
+#define USBOTGSS_DEBUG_CFG 0x0108
+#define USBOTGSS_DEBUG_DATA 0x010c
+
+/* SYSCONFIG REGISTER */
+#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
+#define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4)
+
+#define USBOTGSS_STANDBYMODE_FORCE_STANDBY 0
+#define USBOTGSS_STANDBYMODE_NO_STANDBY 1
+#define USBOTGSS_STANDBYMODE_SMART_STANDBY 2
+#define USBOTGSS_STANDBYMODE_SMART_WAKEUP 3
+
+#define USBOTGSS_STANDBYMODE_MASK (0x03 << 4)
+
+#define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2)
+
+#define USBOTGSS_IDLEMODE_FORCE_IDLE 0
+#define USBOTGSS_IDLEMODE_NO_IDLE 1
+#define USBOTGSS_IDLEMODE_SMART_IDLE 2
+#define USBOTGSS_IDLEMODE_SMART_WAKEUP 3
+
+#define USBOTGSS_IDLEMODE_MASK (0x03 << 2)
+
+/* IRQ_EOI REGISTER */
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
+
+/* IRQS0 BITS */
+#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
+
+/* IRQ1 BITS */
+#define USBOTGSS_IRQ1_DMADISABLECLR (1 << 17)
+#define USBOTGSS_IRQ1_OEVT (1 << 16)
+#define USBOTGSS_IRQ1_DRVVBUS_RISE (1 << 13)
+#define USBOTGSS_IRQ1_CHRGVBUS_RISE (1 << 12)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE (1 << 11)
+#define USBOTGSS_IRQ1_IDPULLUP_RISE (1 << 8)
+#define USBOTGSS_IRQ1_DRVVBUS_FALL (1 << 5)
+#define USBOTGSS_IRQ1_CHRGVBUS_FALL (1 << 4)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL (1 << 3)
+#define USBOTGSS_IRQ1_IDPULLUP_FALL (1 << 0)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS (1 << 5)
+#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS (1 << 4)
+#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS (1 << 3)
+#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP (1 << 0)
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE (1 << 31)
+#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT (1 << 9)
+#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
+#define USBOTGSS_UTMI_OTG_STATUS_IDDIG (1 << 4)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSEND (1 << 3)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID (1 << 2)
+#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID (1 << 1)
+
+struct dwc3_omap {
+ /* device lock */
+ spinlock_t lock;
+
+ struct platform_device *dwc3;
+ struct device *dev;
+
+ int irq;
+ void __iomem *base;
+
+ void *context;
+ u32 resource_size;
+
+ u32 dma_status:1;
+};
+
+static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+ struct dwc3_omap *omap = _omap;
+ u32 reg;
+
+ spin_lock(&omap->lock);
+
+ reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+
+ if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
+ dev_dbg(omap->dev, "DMA Disable was Cleared\n");
+ omap->dma_status = false;
+ }
+
+ if (reg & USBOTGSS_IRQ1_OEVT)
+ dev_dbg(omap->dev, "OTG Event\n");
+
+ if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE)
+ dev_dbg(omap->dev, "DRVVBUS Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE)
+ dev_dbg(omap->dev, "CHRGVBUS Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE)
+ dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE)
+ dev_dbg(omap->dev, "IDPULLUP Rise\n");
+
+ if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL)
+ dev_dbg(omap->dev, "DRVVBUS Fall\n");
+
+ if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL)
+ dev_dbg(omap->dev, "CHRGVBUS Fall\n");
+
+ if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL)
+ dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
+
+ if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
+ dev_dbg(omap->dev, "IDPULLUP Fall\n");
+
+ dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+
+ reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+ dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+
+ spin_unlock(&omap->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit dwc3_omap_probe(struct platform_device *pdev)
+{
+ struct dwc3_omap_data *pdata = pdev->dev.platform_data;
+ struct platform_device *dwc3;
+ struct dwc3_omap *omap;
+ struct resource *res;
+
+ int ret = -ENOMEM;
+ int irq;
+
+ u32 reg;
+
+ void __iomem *base;
+ void *context;
+
+ omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+ if (!omap) {
+ dev_err(&pdev->dev, "not enough memory\n");
+ goto err0;
+ }
+
+ platform_set_drvdata(pdev, omap);
+
+ irq = platform_get_irq(pdev, 1);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "missing IRQ resource\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "missing memory base resource\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ base = ioremap_nocache(res->start, resource_size(res));
+ if (!base) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ goto err1;
+ }
+
+ dwc3 = platform_device_alloc("dwc3-omap", -1);
+ if (!dwc3) {
+ dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+ goto err2;
+ }
+
+ context = kzalloc(resource_size(res), GFP_KERNEL);
+ if (!context) {
+ dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
+ goto err3;
+ }
+
+ spin_lock_init(&omap->lock);
+ dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+ dwc3->dev.parent = &pdev->dev;
+ dwc3->dev.dma_mask = pdev->dev.dma_mask;
+ dwc3->dev.dma_parms = pdev->dev.dma_parms;
+ omap->resource_size = resource_size(res);
+ omap->context = context;
+ omap->dev = &pdev->dev;
+ omap->irq = irq;
+ omap->base = base;
+ omap->dwc3 = dwc3;
+
+ reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
+
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "missing platform data\n");
+ } else {
+ switch (pdata->utmi_mode) {
+ case DWC3_OMAP_UTMI_MODE_SW:
+ reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ case DWC3_OMAP_UTMI_MODE_HW:
+ reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ default:
+ dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
+ pdata->utmi_mode);
+ }
+ }
+
+ dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+
+ /* check the DMA Status */
+ reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+ omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
+
+ /* Set No-Idle and No-Standby */
+ reg &= ~(USBOTGSS_STANDBYMODE_MASK
+ | USBOTGSS_IDLEMODE_MASK);
+
+ reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
+ | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
+
+ dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+
+ ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+ "dwc3-omap", omap);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+ omap->irq, ret);
+ goto err4;
+ }
+
+ /* enable all IRQs */
+ reg = USBOTGSS_IRQO_COREIRQ_ST;
+ dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+
+ reg = (USBOTGSS_IRQ1_OEVT |
+ USBOTGSS_IRQ1_DRVVBUS_RISE |
+ USBOTGSS_IRQ1_CHRGVBUS_RISE |
+ USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+ USBOTGSS_IRQ1_IDPULLUP_RISE |
+ USBOTGSS_IRQ1_DRVVBUS_FALL |
+ USBOTGSS_IRQ1_CHRGVBUS_FALL |
+ USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+ USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+ dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+
+ ret = platform_device_add_resources(dwc3, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+ goto err5;
+ }
+
+ ret = platform_device_add(dwc3);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register dwc3 device\n");
+ goto err5;
+ }
+
+ return 0;
+
+err5:
+ free_irq(omap->irq, omap);
+
+err4:
+ kfree(omap->context);
+
+err3:
+ platform_device_put(dwc3);
+
+err2:
+ iounmap(base);
+
+err1:
+ kfree(omap);
+
+err0:
+ return ret;
+}
+
+static int __devexit dwc3_omap_remove(struct platform_device *pdev)
+{
+ struct dwc3_omap *omap = platform_get_drvdata(pdev);
+
+ platform_device_unregister(omap->dwc3);
+
+ free_irq(omap->irq, omap);
+ iounmap(omap->base);
+
+ kfree(omap->context);
+ kfree(omap);
+
+ return 0;
+}
+
+static const struct of_device_id of_dwc3_matach[] = {
+ {
+ "ti,dwc3",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_matach);
+
+static struct platform_driver dwc3_omap_driver = {
+ .probe = dwc3_omap_probe,
+ .remove = __devexit_p(dwc3_omap_remove),
+ .driver = {
+ .name = "omap-dwc3",
+ .of_match_table = of_dwc3_matach,
+ },
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
+
+static int __devinit dwc3_omap_init(void)
+{
+ return platform_driver_register(&dwc3_omap_driver);
+}
+module_init(dwc3_omap_init);
+
+static void __exit dwc3_omap_exit(void)
+{
+ platform_driver_unregister(&dwc3_omap_driver);
+}
+module_exit(dwc3_omap_exit);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
new file mode 100644
index 0000000..f77c000
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -0,0 +1,219 @@
+/**
+ * dwc3-pci.c - PCI Specific glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+/* FIXME define these in <linux/pci_ids.h> */
+#define PCI_VENDOR_ID_SYNOPSYS 0x16c3
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
+
+#define DWC3_PCI_DEVS_POSSIBLE 32
+
+struct dwc3_pci {
+ struct device *dev;
+ struct platform_device *dwc3;
+};
+
+static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+
+static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
+{
+ int id;
+
+again:
+ id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+ if (id < DWC3_PCI_DEVS_POSSIBLE) {
+ int old;
+
+ old = test_and_set_bit(id, dwc3_pci_devs);
+ if (old)
+ goto again;
+ } else {
+ dev_err(glue->dev, "no space for new device\n");
+ id = -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
+{
+ int ret;
+
+ if (id < 0)
+ return;
+
+ ret = test_bit(id, dwc3_pci_devs);
+ WARN(!ret, "Device: %s\nID %d not in use\n",
+ dev_driver_string(glue->dev), id);
+ clear_bit(id, dwc3_pci_devs);
+}
+
+static int __devinit dwc3_pci_probe(struct pci_dev *pci,
+ const struct pci_device_id *id)
+{
+ struct resource res[2];
+ struct platform_device *dwc3;
+ struct dwc3_pci *glue;
+ int ret = -ENOMEM;
+ int devid;
+
+ glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pci->dev, "not enough memory\n");
+ goto err0;
+ }
+
+ glue->dev = &pci->dev;
+
+ ret = pci_enable_device(pci);
+ if (ret) {
+ dev_err(&pci->dev, "failed to enable pci device\n");
+ goto err1;
+ }
+
+ pci_set_power_state(pci, PCI_D0);
+ pci_set_master(pci);
+
+ devid = dwc3_pci_get_device_id(glue);
+ if (devid < 0)
+ goto err2;
+
+ dwc3 = platform_device_alloc("dwc3-pci", devid);
+ if (!dwc3) {
+ dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
+ goto err3;
+ }
+
+ memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+ res[0].start = pci_resource_start(pci, 0);
+ res[0].end = pci_resource_end(pci, 0);
+ res[0].name = "dwc_usb3";
+ res[0].flags = IORESOURCE_MEM;
+
+ res[1].start = pci->irq;
+ res[1].name = "dwc_usb3";
+ res[1].flags = IORESOURCE_IRQ;
+
+ ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
+ if (ret) {
+ dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
+ goto err4;
+ }
+
+ pci_set_drvdata(pci, glue);
+
+ dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+
+ dwc3->dev.dma_mask = pci->dev.dma_mask;
+ dwc3->dev.dma_parms = pci->dev.dma_parms;
+ dwc3->dev.parent = &pci->dev;
+ glue->dwc3 = dwc3;
+
+ ret = platform_device_add(dwc3);
+ if (ret) {
+ dev_err(&pci->dev, "failed to register dwc3 device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ pci_set_drvdata(pci, NULL);
+ platform_device_put(dwc3);
+
+err3:
+ dwc3_pci_put_device_id(glue, devid);
+
+err2:
+ pci_disable_device(pci);
+
+err1:
+ kfree(pci);
+
+err0:
+ return ret;
+}
+
+static void __devexit dwc3_pci_remove(struct pci_dev *pci)
+{
+ struct dwc3_pci *glue = pci_get_drvdata(pci);
+
+ dwc3_pci_put_device_id(glue, glue->dwc3->id);
+ platform_device_unregister(glue->dwc3);
+ pci_set_drvdata(pci, NULL);
+ pci_disable_device(pci);
+ kfree(glue);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+ PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
+ },
+ { } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+
+static struct pci_driver dwc3_pci_driver = {
+ .name = "pci-dwc3",
+ .id_table = dwc3_pci_id_table,
+ .probe = dwc3_pci_probe,
+ .remove = __devexit_p(dwc3_pci_remove),
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
+
+static int __devinit dwc3_pci_init(void)
+{
+ return pci_register_driver(&dwc3_pci_driver);
+}
+module_init(dwc3_pci_init);
+
+static void __exit dwc3_pci_exit(void)
+{
+ pci_unregister_driver(&dwc3_pci_driver);
+}
+module_exit(dwc3_pci_exit);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
new file mode 100644
index 0000000..69a4e43
--- /dev/null
+++ b/drivers/usb/dwc3/ep0.c
@@ -0,0 +1,804 @@
+/**
+ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event);
+
+static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
+{
+ switch (state) {
+ case EP0_UNCONNECTED:
+ return "Unconnected";
+ case EP0_SETUP_PHASE:
+ return "Setup Phase";
+ case EP0_DATA_PHASE:
+ return "Data Phase";
+ case EP0_STATUS_PHASE:
+ return "Status Phase";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
+ u32 len, u32 type)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3_trb_hw *trb_hw;
+ struct dwc3_trb trb;
+ struct dwc3_ep *dep;
+
+ int ret;
+
+ dep = dwc->eps[epnum];
+ if (dep->flags & DWC3_EP_BUSY) {
+ dev_vdbg(dwc->dev, "%s: still busy\n", dep->name);
+ return 0;
+ }
+
+ trb_hw = dwc->ep0_trb;
+ memset(&trb, 0, sizeof(trb));
+
+ trb.trbctl = type;
+ trb.bplh = buf_dma;
+ trb.length = len;
+
+ trb.hwo = 1;
+ trb.lst = 1;
+ trb.ioc = 1;
+ trb.isp_imi = 1;
+
+ dwc3_trb_to_hw(&trb, trb_hw);
+
+ memset(¶ms, 0, sizeof(params));
+ params.param0 = upper_32_bits(dwc->ep0_trb_addr);
+ params.param1 = lower_32_bits(dwc->ep0_trb_addr);
+
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_STARTTRANSFER, ¶ms);
+ if (ret < 0) {
+ dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+ return ret;
+ }
+
+ dep->flags |= DWC3_EP_BUSY;
+ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+ dep->number);
+
+ dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+ return 0;
+}
+
+static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
+ struct dwc3_request *req)
+{
+ int ret = 0;
+
+ req->request.actual = 0;
+ req->request.status = -EINPROGRESS;
+ req->epnum = dep->number;
+
+ list_add_tail(&req->list, &dep->request_list);
+
+ /*
+ * Gadget driver might not be quick enough to queue a request
+ * before we get a Transfer Not Ready event on this endpoint.
+ *
+ * In that case, we will set DWC3_EP_PENDING_REQUEST. When that
+ * flag is set, it's telling us that as soon as Gadget queues the
+ * required request, we should kick the transfer here because the
+ * IRQ we were waiting for is long gone.
+ */
+ if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+ struct dwc3 *dwc = dep->dwc;
+ unsigned direction;
+ u32 type;
+
+ direction = !!(dep->flags & DWC3_EP0_DIR_IN);
+
+ if (dwc->ep0state == EP0_STATUS_PHASE) {
+ type = dwc->three_stage_setup
+ ? DWC3_TRBCTL_CONTROL_STATUS3
+ : DWC3_TRBCTL_CONTROL_STATUS2;
+ } else if (dwc->ep0state == EP0_DATA_PHASE) {
+ type = DWC3_TRBCTL_CONTROL_DATA;
+ } else {
+ /* should never happen */
+ WARN_ON(1);
+ return 0;
+ }
+
+ ret = dwc3_ep0_start_trans(dwc, direction,
+ req->request.dma, req->request.length, type);
+ dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
+ DWC3_EP0_DIR_IN);
+ }
+
+ return ret;
+}
+
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+
+ int ret;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ if (!dep->desc) {
+ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+ request, dep->name);
+ ret = -ESHUTDOWN;
+ goto out;
+ }
+
+ /* we share one TRB for ep0/1 */
+ if (!list_empty(&dwc->eps[0]->request_list) ||
+ !list_empty(&dwc->eps[1]->request_list) ||
+ dwc->ep0_status_pending) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n",
+ request, dep->name, request->length,
+ dwc3_ep0_state_string(dwc->ep0state));
+
+ ret = __dwc3_gadget_ep0_queue(dep, req);
+
+out:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep = dwc->eps[0];
+
+ /* stall is always issued on EP0 */
+ __dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
+ dwc->eps[0]->flags = DWC3_EP_ENABLED;
+
+ if (!list_empty(&dep->request_list)) {
+ struct dwc3_request *req;
+
+ req = next_request(&dep->request_list);
+ dwc3_gadget_giveback(dep, req, -ECONNRESET);
+ }
+
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+}
+
+void dwc3_ep0_out_start(struct dwc3 *dwc)
+{
+ int ret;
+
+ ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
+ DWC3_TRBCTL_CONTROL_SETUP);
+ WARN_ON(ret < 0);
+}
+
+static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
+{
+ struct dwc3_ep *dep;
+ u32 windex = le16_to_cpu(wIndex_le);
+ u32 epnum;
+
+ epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
+ if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+ epnum |= 1;
+
+ dep = dwc->eps[epnum];
+ if (dep->flags & DWC3_EP_ENABLED)
+ return dep;
+
+ return NULL;
+}
+
+static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
+{
+ dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr,
+ dwc->ep0_usb_req.length,
+ DWC3_TRBCTL_CONTROL_DATA);
+}
+
+/*
+ * ch 9.4.5
+ */
+static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ struct dwc3_ep *dep;
+ u32 recip;
+ u16 usb_status = 0;
+ __le16 *response_pkt;
+
+ recip = ctrl->bRequestType & USB_RECIP_MASK;
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ /*
+ * We are self-powered. U1/U2/LTM will be set later
+ * once we handle this states. RemoteWakeup is 0 on SS
+ */
+ usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+ break;
+
+ case USB_RECIP_INTERFACE:
+ /*
+ * Function Remote Wake Capable D0
+ * Function Remote Wakeup D1
+ */
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+ if (!dep)
+ return -EINVAL;
+
+ if (dep->flags & DWC3_EP_STALL)
+ usb_status = 1 << USB_ENDPOINT_HALT;
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ response_pkt = (__le16 *) dwc->setup_buf;
+ *response_pkt = cpu_to_le16(usb_status);
+ dwc->ep0_usb_req.length = sizeof(*response_pkt);
+ dwc->ep0_status_pending = 1;
+
+ return 0;
+}
+
+static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+ struct usb_ctrlrequest *ctrl, int set)
+{
+ struct dwc3_ep *dep;
+ u32 recip;
+ u32 wValue;
+ u32 wIndex;
+ u32 reg;
+ int ret;
+ u32 mode;
+
+ wValue = le16_to_cpu(ctrl->wValue);
+ wIndex = le16_to_cpu(ctrl->wIndex);
+ recip = ctrl->bRequestType & USB_RECIP_MASK;
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+
+ /*
+ * 9.4.1 says only only for SS, in AddressState only for
+ * default control pipe
+ */
+ switch (wValue) {
+ case USB_DEVICE_U1_ENABLE:
+ case USB_DEVICE_U2_ENABLE:
+ case USB_DEVICE_LTM_ENABLE:
+ if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+ return -EINVAL;
+ if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+ return -EINVAL;
+ }
+
+ /* XXX add U[12] & LTM */
+ switch (wValue) {
+ case USB_DEVICE_REMOTE_WAKEUP:
+ break;
+ case USB_DEVICE_U1_ENABLE:
+ break;
+ case USB_DEVICE_U2_ENABLE:
+ break;
+ case USB_DEVICE_LTM_ENABLE:
+ break;
+
+ case USB_DEVICE_TEST_MODE:
+ if ((wIndex & 0xff) != 0)
+ return -EINVAL;
+ if (!set)
+ return -EINVAL;
+
+ mode = wIndex >> 8;
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+ switch (mode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ reg |= mode << 1;
+ break;
+ default:
+ return -EINVAL;
+ }
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case USB_RECIP_INTERFACE:
+ switch (wValue) {
+ case USB_INTRF_FUNC_SUSPEND:
+ if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
+ /* XXX enable Low power suspend */
+ ;
+ if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
+ /* XXX enable remote wakeup */
+ ;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ switch (wValue) {
+ case USB_ENDPOINT_HALT:
+
+ dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+ if (!dep)
+ return -EINVAL;
+ ret = __dwc3_gadget_ep_set_halt(dep, set);
+ if (ret)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ };
+
+ return 0;
+}
+
+static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ u32 addr;
+ u32 reg;
+
+ addr = le16_to_cpu(ctrl->wValue);
+ if (addr > 127)
+ return -EINVAL;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+ reg |= DWC3_DCFG_DEVADDR(addr);
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ if (addr)
+ dwc->dev_state = DWC3_ADDRESS_STATE;
+ else
+ dwc->dev_state = DWC3_DEFAULT_STATE;
+
+ return 0;
+}
+
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ int ret;
+
+ spin_unlock(&dwc->lock);
+ ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+ spin_lock(&dwc->lock);
+ return ret;
+}
+
+static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ u32 cfg;
+ int ret;
+
+ dwc->start_config_issued = false;
+ cfg = le16_to_cpu(ctrl->wValue);
+
+ switch (dwc->dev_state) {
+ case DWC3_DEFAULT_STATE:
+ return -EINVAL;
+ break;
+
+ case DWC3_ADDRESS_STATE:
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ /* if the cfg matches and the cfg is non zero */
+ if (!ret && cfg)
+ dwc->dev_state = DWC3_CONFIGURED_STATE;
+ break;
+
+ case DWC3_CONFIGURED_STATE:
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ if (!cfg)
+ dwc->dev_state = DWC3_ADDRESS_STATE;
+ break;
+ }
+ return 0;
+}
+
+static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+ int ret;
+
+ switch (ctrl->bRequest) {
+ case USB_REQ_GET_STATUS:
+ dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
+ ret = dwc3_ep0_handle_status(dwc, ctrl);
+ break;
+ case USB_REQ_CLEAR_FEATURE:
+ dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
+ ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
+ break;
+ case USB_REQ_SET_FEATURE:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
+ ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
+ break;
+ case USB_REQ_SET_ADDRESS:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
+ ret = dwc3_ep0_set_address(dwc, ctrl);
+ break;
+ case USB_REQ_SET_CONFIGURATION:
+ dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
+ ret = dwc3_ep0_set_config(dwc, ctrl);
+ break;
+ default:
+ dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+ break;
+ };
+
+ return ret;
+}
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
+ int ret;
+ u32 len;
+
+ if (!dwc->gadget_driver)
+ goto err;
+
+ len = le16_to_cpu(ctrl->wLength);
+ if (!len) {
+ dwc->three_stage_setup = false;
+ dwc->ep0_expect_in = false;
+ dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+ } else {
+ dwc->three_stage_setup = true;
+ dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN);
+ dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
+ }
+
+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+ ret = dwc3_ep0_std_request(dwc, ctrl);
+ else
+ ret = dwc3_ep0_delegate_req(dwc, ctrl);
+
+ if (ret >= 0)
+ return;
+
+err:
+ dwc3_ep0_stall_and_restart(dwc);
+}
+
+static void dwc3_ep0_complete_data(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_request *r = NULL;
+ struct usb_request *ur;
+ struct dwc3_trb trb;
+ struct dwc3_ep *dep;
+ u32 transferred;
+ u8 epnum;
+
+ epnum = event->endpoint_number;
+ dep = dwc->eps[epnum];
+
+ dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+
+ if (!dwc->ep0_status_pending) {
+ r = next_request(&dwc->eps[0]->request_list);
+ ur = &r->request;
+ } else {
+ ur = &dwc->ep0_usb_req;
+ dwc->ep0_status_pending = 0;
+ }
+
+ dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+
+ if (dwc->ep0_bounced) {
+ struct dwc3_ep *ep0 = dwc->eps[0];
+
+ transferred = min_t(u32, ur->length,
+ ep0->endpoint.maxpacket - trb.length);
+ memcpy(ur->buf, dwc->ep0_bounce, transferred);
+ dwc->ep0_bounced = false;
+ } else {
+ transferred = ur->length - trb.length;
+ ur->actual += transferred;
+ }
+
+ if ((epnum & 1) && ur->actual < ur->length) {
+ /* for some reason we did not get everything out */
+
+ dwc3_ep0_stall_and_restart(dwc);
+ } else {
+ /*
+ * handle the case where we have to send a zero packet. This
+ * seems to be case when req.length > maxpacket. Could it be?
+ */
+ if (r)
+ dwc3_gadget_giveback(dep, r, 0);
+ }
+}
+
+static void dwc3_ep0_complete_req(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_request *r;
+ struct dwc3_ep *dep;
+
+ dep = dwc->eps[0];
+
+ if (!list_empty(&dep->request_list)) {
+ r = next_request(&dep->request_list);
+
+ dwc3_gadget_giveback(dep, r, 0);
+ }
+
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
+
+ dep->flags &= ~DWC3_EP_BUSY;
+
+ switch (dwc->ep0state) {
+ case EP0_SETUP_PHASE:
+ dev_vdbg(dwc->dev, "Inspecting Setup Bytes\n");
+ dwc3_ep0_inspect_setup(dwc, event);
+ break;
+
+ case EP0_DATA_PHASE:
+ dev_vdbg(dwc->dev, "Data Phase\n");
+ dwc3_ep0_complete_data(dwc, event);
+ break;
+
+ case EP0_STATUS_PHASE:
+ dev_vdbg(dwc->dev, "Status Phase\n");
+ dwc3_ep0_complete_req(dwc, event);
+ break;
+ default:
+ WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
+ }
+}
+
+static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_ep *dep;
+ struct dwc3_request *req;
+ int ret;
+
+ dep = dwc->eps[0];
+ dwc->ep0state = EP0_DATA_PHASE;
+
+ if (dwc->ep0_status_pending) {
+ dwc3_ep0_send_status_response(dwc);
+ return;
+ }
+
+ if (list_empty(&dep->request_list)) {
+ dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+
+ if (event->endpoint_number)
+ dep->flags |= DWC3_EP0_DIR_IN;
+ return;
+ }
+
+ req = next_request(&dep->request_list);
+ req->direction = !!event->endpoint_number;
+
+ dwc->ep0state = EP0_DATA_PHASE;
+ if (req->request.length == 0) {
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ dwc->ctrl_req_addr, 0,
+ DWC3_TRBCTL_CONTROL_DATA);
+ } else if ((req->request.length % dep->endpoint.maxpacket)
+ && (event->endpoint_number == 0)) {
+ dwc3_map_buffer_to_dma(req);
+
+ WARN_ON(req->request.length > dep->endpoint.maxpacket);
+
+ dwc->ep0_bounced = true;
+
+ /*
+ * REVISIT in case request length is bigger than EP0
+ * wMaxPacketSize, we will need two chained TRBs to handle
+ * the transfer.
+ */
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
+ DWC3_TRBCTL_CONTROL_DATA);
+ } else {
+ dwc3_map_buffer_to_dma(req);
+
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ req->request.dma, req->request.length,
+ DWC3_TRBCTL_CONTROL_DATA);
+ }
+
+ WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ u32 type;
+ int ret;
+
+ dwc->ep0state = EP0_STATUS_PHASE;
+
+ type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
+ : DWC3_TRBCTL_CONTROL_STATUS2;
+
+ ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+ dwc->ctrl_req_addr, 0, type);
+
+ WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ switch (event->status) {
+ case DEPEVT_STATUS_CONTROL_SETUP:
+ dev_vdbg(dwc->dev, "Control Setup\n");
+ dwc3_ep0_do_control_setup(dwc, event);
+ break;
+
+ case DEPEVT_STATUS_CONTROL_DATA:
+ dev_vdbg(dwc->dev, "Control Data\n");
+
+ if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
+ dev_vdbg(dwc->dev, "Expected %d got %d\n",
+ dwc->ep0_next_event,
+ DWC3_EP0_NRDY_DATA);
+
+ dwc3_ep0_stall_and_restart(dwc);
+ return;
+ }
+
+ /*
+ * One of the possible error cases is when Host _does_
+ * request for Data Phase, but it does so on the wrong
+ * direction.
+ *
+ * Here, we already know ep0_next_event is DATA (see above),
+ * so we only need to check for direction.
+ */
+ if (dwc->ep0_expect_in != event->endpoint_number) {
+ dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
+ dwc3_ep0_stall_and_restart(dwc);
+ return;
+ }
+
+ dwc3_ep0_do_control_data(dwc, event);
+ break;
+
+ case DEPEVT_STATUS_CONTROL_STATUS:
+ dev_vdbg(dwc->dev, "Control Status\n");
+
+ if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
+ dev_vdbg(dwc->dev, "Expected %d got %d\n",
+ dwc->ep0_next_event,
+ DWC3_EP0_NRDY_STATUS);
+
+ dwc3_ep0_stall_and_restart(dwc);
+ return;
+ }
+ dwc3_ep0_do_control_status(dwc, event);
+ }
+}
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+ const const struct dwc3_event_depevt *event)
+{
+ u8 epnum = event->endpoint_number;
+
+ dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
+ dwc3_ep_event_string(event->endpoint_event),
+ epnum >> 1, (epnum & 1) ? "in" : "out",
+ dwc3_ep0_state_string(dwc->ep0state));
+
+ switch (event->endpoint_event) {
+ case DWC3_DEPEVT_XFERCOMPLETE:
+ dwc3_ep0_xfer_complete(dwc, event);
+ break;
+
+ case DWC3_DEPEVT_XFERNOTREADY:
+ dwc3_ep0_xfernotready(dwc, event);
+ break;
+
+ case DWC3_DEPEVT_XFERINPROGRESS:
+ case DWC3_DEPEVT_RXTXFIFOEVT:
+ case DWC3_DEPEVT_STREAMEVT:
+ case DWC3_DEPEVT_EPCMDCMPLT:
+ break;
+ }
+}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
new file mode 100644
index 0000000..fa824cf
--- /dev/null
+++ b/drivers/usb/dwc3/gadget.c
@@ -0,0 +1,2104 @@
+/**
+ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+{
+ struct dwc3 *dwc = req->dep->dwc;
+
+ if (req->request.length == 0) {
+ /* req->request.dma = dwc->setup_buf_addr; */
+ return;
+ }
+
+ if (req->request.dma == DMA_ADDR_INVALID) {
+ req->request.dma = dma_map_single(dwc->dev, req->request.buf,
+ req->request.length, req->direction
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = true;
+ }
+}
+
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+{
+ struct dwc3 *dwc = req->dep->dwc;
+
+ if (req->request.length == 0) {
+ req->request.dma = DMA_ADDR_INVALID;
+ return;
+ }
+
+ if (req->mapped) {
+ dma_unmap_single(dwc->dev, req->request.dma,
+ req->request.length, req->direction
+ ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ req->mapped = 0;
+ req->request.dma = DMA_ADDR_INVALID;
+ }
+}
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+ int status)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ if (req->queued) {
+ dep->busy_slot++;
+ /*
+ * Skip LINK TRB. We can't use req->trb and check for
+ * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
+ * completed (not the LINK TRB).
+ */
+ if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->desc))
+ dep->busy_slot++;
+ }
+ list_del(&req->list);
+
+ if (req->request.status == -EINPROGRESS)
+ req->request.status = status;
+
+ dwc3_unmap_buffer_from_dma(req);
+
+ dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
+ req, dep->name, req->request.actual,
+ req->request.length, status);
+
+ spin_unlock(&dwc->lock);
+ req->request.complete(&req->dep->endpoint, &req->request);
+ spin_lock(&dwc->lock);
+}
+
+static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+ switch (cmd) {
+ case DWC3_DEPCMD_DEPSTARTCFG:
+ return "Start New Configuration";
+ case DWC3_DEPCMD_ENDTRANSFER:
+ return "End Transfer";
+ case DWC3_DEPCMD_UPDATETRANSFER:
+ return "Update Transfer";
+ case DWC3_DEPCMD_STARTTRANSFER:
+ return "Start Transfer";
+ case DWC3_DEPCMD_CLEARSTALL:
+ return "Clear Stall";
+ case DWC3_DEPCMD_SETSTALL:
+ return "Set Stall";
+ case DWC3_DEPCMD_GETSEQNUMBER:
+ return "Get Data Sequence Number";
+ case DWC3_DEPCMD_SETTRANSFRESOURCE:
+ return "Set Endpoint Transfer Resource";
+ case DWC3_DEPCMD_SETEPCONFIG:
+ return "Set Endpoint Configuration";
+ default:
+ return "UNKNOWN command";
+ }
+}
+
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+ struct dwc3_ep *dep = dwc->eps[ep];
+ u32 timeout = 500;
+ u32 reg;
+
+ dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
+ dep->name,
+ dwc3_gadget_ep_cmd_string(cmd), params->param0,
+ params->param1, params->param2);
+
+ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
+ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
+ dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
+
+ dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
+ if (!(reg & DWC3_DEPCMD_CMDACT)) {
+ dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+ DWC3_DEPCMD_STATUS(reg));
+ return 0;
+ }
+
+ /*
+ * We can't sleep here, because it is also called from
+ * interrupt context.
+ */
+ timeout--;
+ if (!timeout)
+ return -ETIMEDOUT;
+
+ udelay(1);
+ } while (1);
+}
+
+static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+ struct dwc3_trb_hw *trb)
+{
+ u32 offset = (char *) trb - (char *) dep->trb_pool;
+
+ return dep->trb_pool_dma + offset;
+}
+
+static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ if (dep->trb_pool)
+ return 0;
+
+ if (dep->number == 0 || dep->number == 1)
+ return 0;
+
+ dep->trb_pool = dma_alloc_coherent(dwc->dev,
+ sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+ &dep->trb_pool_dma, GFP_KERNEL);
+ if (!dep->trb_pool) {
+ dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+ dep->name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+{
+ struct dwc3 *dwc = dep->dwc;
+
+ dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+ dep->trb_pool, dep->trb_pool_dma);
+
+ dep->trb_pool = NULL;
+ dep->trb_pool_dma = 0;
+}
+
+static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ u32 cmd;
+
+ memset(¶ms, 0x00, sizeof(params));
+
+ if (dep->number != 1) {
+ cmd = DWC3_DEPCMD_DEPSTARTCFG;
+ /* XferRscIdx == 0 for ep0 and 2 for the remaining */
+ if (dep->number > 1) {
+ if (dwc->start_config_issued)
+ return 0;
+ dwc->start_config_issued = true;
+ cmd |= DWC3_DEPCMD_PARAM(2);
+ }
+
+ return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, ¶ms);
+ }
+
+ return 0;
+}
+
+static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+
+ memset(¶ms, 0x00, sizeof(params));
+
+ params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
+ | DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
+ | DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst);
+
+ params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
+ | DWC3_DEPCFG_XFER_NOT_READY_EN;
+
+ if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
+ params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
+ | DWC3_DEPCFG_STREAM_EVENT_EN;
+ dep->stream_capable = true;
+ }
+
+ if (usb_endpoint_xfer_isoc(desc))
+ params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
+
+ /*
+ * We are doing 1:1 mapping for endpoints, meaning
+ * Physical Endpoints 2 maps to Logical Endpoint 2 and
+ * so on. We consider the direction bit as part of the physical
+ * endpoint number. So USB endpoint 0x81 is 0x03.
+ */
+ params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
+
+ /*
+ * We must use the lower 16 TX FIFOs even though
+ * HW might have more
+ */
+ if (dep->direction)
+ params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
+
+ if (desc->bInterval) {
+ params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
+ dep->interval = 1 << (desc->bInterval - 1);
+ }
+
+ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_SETEPCONFIG, ¶ms);
+}
+
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+
+ memset(¶ms, 0x00, sizeof(params));
+
+ params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
+
+ return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_SETTRANSFRESOURCE, ¶ms);
+}
+
+/**
+ * __dwc3_gadget_ep_enable - Initializes a HW endpoint
+ * @dep: endpoint to be initialized
+ * @desc: USB Endpoint Descriptor
+ *
+ * Caller should take care of locking
+ */
+static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct dwc3 *dwc = dep->dwc;
+ u32 reg;
+ int ret = -ENOMEM;
+
+ if (!(dep->flags & DWC3_EP_ENABLED)) {
+ ret = dwc3_gadget_start_config(dwc, dep);
+ if (ret)
+ return ret;
+ }
+
+ ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
+ if (ret)
+ return ret;
+
+ if (!(dep->flags & DWC3_EP_ENABLED)) {
+ struct dwc3_trb_hw *trb_st_hw;
+ struct dwc3_trb_hw *trb_link_hw;
+ struct dwc3_trb trb_link;
+
+ ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+ if (ret)
+ return ret;
+
+ dep->desc = desc;
+ dep->type = usb_endpoint_type(desc);
+ dep->flags |= DWC3_EP_ENABLED;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+ reg |= DWC3_DALEPENA_EP(dep->number);
+ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+ if (!usb_endpoint_xfer_isoc(desc))
+ return 0;
+
+ memset(&trb_link, 0, sizeof(trb_link));
+
+ /* Link TRB for ISOC. The HWO but is never reset */
+ trb_st_hw = &dep->trb_pool[0];
+
+ trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
+ trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
+ trb_link.hwo = true;
+
+ trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
+ dwc3_trb_to_hw(&trb_link, trb_link_hw);
+ }
+
+ return 0;
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
+static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+ struct dwc3_request *req;
+
+ if (!list_empty(&dep->req_queued))
+ dwc3_stop_active_transfer(dwc, dep->number);
+
+ while (!list_empty(&dep->request_list)) {
+ req = next_request(&dep->request_list);
+
+ dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+ }
+}
+
+/**
+ * __dwc3_gadget_ep_disable - Disables a HW endpoint
+ * @dep: the endpoint to disable
+ *
+ * This function also removes requests which are currently processed ny the
+ * hardware and those which are not yet scheduled.
+ * Caller should take care of locking.
+ */
+static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+{
+ struct dwc3 *dwc = dep->dwc;
+ u32 reg;
+
+ dwc3_remove_requests(dwc, dep);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+ reg &= ~DWC3_DALEPENA_EP(dep->number);
+ dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+ dep->stream_capable = false;
+ dep->desc = NULL;
+ dep->type = 0;
+ dep->flags = 0;
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ return -EINVAL;
+}
+
+static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
+{
+ return -EINVAL;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct dwc3_ep *dep;
+ struct dwc3 *dwc;
+ unsigned long flags;
+ int ret;
+
+ if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+ pr_debug("dwc3: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ if (!desc->wMaxPacketSize) {
+ pr_debug("dwc3: missing wMaxPacketSize\n");
+ return -EINVAL;
+ }
+
+ dep = to_dwc3_ep(ep);
+ dwc = dep->dwc;
+
+ switch (usb_endpoint_type(desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ strncat(dep->name, "-control", sizeof(dep->name));
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ strncat(dep->name, "-isoc", sizeof(dep->name));
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ strncat(dep->name, "-bulk", sizeof(dep->name));
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ strncat(dep->name, "-int", sizeof(dep->name));
+ break;
+ default:
+ dev_err(dwc->dev, "invalid endpoint transfer type\n");
+ }
+
+ if (dep->flags & DWC3_EP_ENABLED) {
+ dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
+ dep->name);
+ return 0;
+ }
+
+ dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep_enable(dep, desc);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+{
+ struct dwc3_ep *dep;
+ struct dwc3 *dwc;
+ unsigned long flags;
+ int ret;
+
+ if (!ep) {
+ pr_debug("dwc3: invalid parameters\n");
+ return -EINVAL;
+ }
+
+ dep = to_dwc3_ep(ep);
+ dwc = dep->dwc;
+
+ if (!(dep->flags & DWC3_EP_ENABLED)) {
+ dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
+ dep->name);
+ return 0;
+ }
+
+ snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+ dep->number >> 1,
+ (dep->number & 1) ? "in" : "out");
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep_disable(dep);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags)
+{
+ struct dwc3_request *req;
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+ if (!req) {
+ dev_err(dwc->dev, "not enough memory\n");
+ return NULL;
+ }
+
+ req->epnum = dep->number;
+ req->dep = dep;
+ req->request.dma = DMA_ADDR_INVALID;
+
+ return &req->request;
+}
+
+static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+
+ kfree(req);
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @dep: endpoint for which requests are being prepared
+ * @starting: true if the endpoint is idle and no requests are queued.
+ *
+ * The functions goes through the requests list and setups TRBs for the
+ * transfers. The functions returns once there are not more TRBs available or
+ * it run out of requests.
+ */
+static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
+ bool starting)
+{
+ struct dwc3_request *req, *n, *ret = NULL;
+ struct dwc3_trb_hw *trb_hw;
+ struct dwc3_trb trb;
+ u32 trbs_left;
+
+ BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+
+ /* the first request must not be queued */
+ trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+ /*
+ * if busy & slot are equal than it is either full or empty. If we are
+ * starting to proceed requests then we are empty. Otherwise we ar
+ * full and don't do anything
+ */
+ if (!trbs_left) {
+ if (!starting)
+ return NULL;
+ trbs_left = DWC3_TRB_NUM;
+ /*
+ * In case we start from scratch, we queue the ISOC requests
+ * starting from slot 1. This is done because we use ring
+ * buffer and have no LST bit to stop us. Instead, we place
+ * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+ * after the first request so we start at slot 1 and have
+ * 7 requests proceed before we hit the first IOC.
+ * Other transfer types don't use the ring buffer and are
+ * processed from the first TRB until the last one. Since we
+ * don't wrap around we have to start at the beginning.
+ */
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dep->busy_slot = 1;
+ dep->free_slot = 1;
+ } else {
+ dep->busy_slot = 0;
+ dep->free_slot = 0;
+ }
+ }
+
+ /* The last TRB is a link TRB, not used for xfer */
+ if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+ return NULL;
+
+ list_for_each_entry_safe(req, n, &dep->request_list, list) {
+ unsigned int last_one = 0;
+ unsigned int cur_slot;
+
+ trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ cur_slot = dep->free_slot;
+ dep->free_slot++;
+
+ /* Skip the LINK-TRB on ISOC */
+ if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+ usb_endpoint_xfer_isoc(dep->desc))
+ continue;
+
+ dwc3_gadget_move_request_queued(req);
+ memset(&trb, 0, sizeof(trb));
+ trbs_left--;
+
+ /* Is our TRB pool empty? */
+ if (!trbs_left)
+ last_one = 1;
+ /* Is this the last request? */
+ if (list_empty(&dep->request_list))
+ last_one = 1;
+
+ /*
+ * FIXME we shouldn't need to set LST bit always but we are
+ * facing some weird problem with the Hardware where it doesn't
+ * complete even though it has been previously started.
+ *
+ * While we're debugging the problem, as a workaround to
+ * multiple TRBs handling, use only one TRB at a time.
+ */
+ last_one = 1;
+
+ req->trb = trb_hw;
+ if (!ret)
+ ret = req;
+
+ trb.bplh = req->request.dma;
+
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ trb.isp_imi = true;
+ trb.csp = true;
+ } else {
+ trb.lst = last_one;
+ }
+
+ if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+ trb.sid_sofn = req->request.stream_id;
+
+ switch (usb_endpoint_type(dep->desc)) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+ break;
+
+ case USB_ENDPOINT_XFER_ISOC:
+ trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+
+ /* IOC every DWC3_TRB_NUM / 4 so we can refill */
+ if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+ trb.ioc = last_one;
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ trb.trbctl = DWC3_TRBCTL_NORMAL;
+ break;
+ default:
+ /*
+ * This is only possible with faulty memory because we
+ * checked it already :)
+ */
+ BUG();
+ }
+
+ trb.length = req->request.length;
+ trb.hwo = true;
+
+ dwc3_trb_to_hw(&trb, trb_hw);
+ req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+
+ if (last_one)
+ break;
+ }
+
+ return ret;
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+ int start_new)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3_request *req;
+ struct dwc3 *dwc = dep->dwc;
+ int ret;
+ u32 cmd;
+
+ if (start_new && (dep->flags & DWC3_EP_BUSY)) {
+ dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+ return -EBUSY;
+ }
+ dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+
+ /*
+ * If we are getting here after a short-out-packet we don't enqueue any
+ * new requests as we try to set the IOC bit only on the last request.
+ */
+ if (start_new) {
+ if (list_empty(&dep->req_queued))
+ dwc3_prepare_trbs(dep, start_new);
+
+ /* req points to the first request which will be sent */
+ req = next_request(&dep->req_queued);
+ } else {
+ /*
+ * req points to the first request where HWO changed
+ * from 0 to 1
+ */
+ req = dwc3_prepare_trbs(dep, start_new);
+ }
+ if (!req) {
+ dep->flags |= DWC3_EP_PENDING_REQUEST;
+ return 0;
+ }
+
+ memset(¶ms, 0, sizeof(params));
+ params.param0 = upper_32_bits(req->trb_dma);
+ params.param1 = lower_32_bits(req->trb_dma);
+
+ if (start_new)
+ cmd = DWC3_DEPCMD_STARTTRANSFER;
+ else
+ cmd = DWC3_DEPCMD_UPDATETRANSFER;
+
+ cmd |= DWC3_DEPCMD_PARAM(cmd_param);
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
+ if (ret < 0) {
+ dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+
+ /*
+ * FIXME we need to iterate over the list of requests
+ * here and stop, unmap, free and del each of the linked
+ * requests instead of we do now.
+ */
+ dwc3_unmap_buffer_from_dma(req);
+ list_del(&req->list);
+ return ret;
+ }
+
+ dep->flags |= DWC3_EP_BUSY;
+ dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+ dep->number);
+ if (!dep->res_trans_idx)
+ printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
+ return 0;
+}
+
+static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+ req->request.actual = 0;
+ req->request.status = -EINPROGRESS;
+ req->direction = dep->direction;
+ req->epnum = dep->number;
+
+ /*
+ * We only add to our list of requests now and
+ * start consuming the list once we get XferNotReady
+ * IRQ.
+ *
+ * That way, we avoid doing anything that we don't need
+ * to do now and defer it until the point we receive a
+ * particular token from the Host side.
+ *
+ * This will also avoid Host cancelling URBs due to too
+ * many NACKs.
+ */
+ dwc3_map_buffer_to_dma(req);
+ list_add_tail(&req->list, &dep->request_list);
+
+ /*
+ * There is one special case: XferNotReady with
+ * empty list of requests. We need to kick the
+ * transfer here in that situation, otherwise
+ * we will be NAKing forever.
+ *
+ * If we get XferNotReady before gadget driver
+ * has a chance to queue a request, we will ACK
+ * the IRQ but won't be able to receive the data
+ * until the next request is queued. The following
+ * code is handling exactly that.
+ */
+ if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+ int ret;
+ int start_trans;
+
+ start_trans = 1;
+ if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+ dep->flags & DWC3_EP_BUSY)
+ start_trans = 0;
+
+ ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+ if (ret && ret != -EBUSY) {
+ struct dwc3 *dwc = dep->dwc;
+
+ dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+ dep->name);
+ }
+ };
+
+ return 0;
+}
+
+static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+
+ int ret;
+
+ if (!dep->desc) {
+ dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+ request, ep->name);
+ return -ESHUTDOWN;
+ }
+
+ dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
+ request, ep->name, request->length);
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ ret = __dwc3_gadget_ep_queue(dep, req);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
+ struct usb_request *request)
+{
+ struct dwc3_request *req = to_dwc3_request(request);
+ struct dwc3_request *r = NULL;
+
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ list_for_each_entry(r, &dep->request_list, list) {
+ if (r == req)
+ break;
+ }
+
+ if (r != req) {
+ list_for_each_entry(r, &dep->req_queued, list) {
+ if (r == req)
+ break;
+ }
+ if (r == req) {
+ /* wait until it is processed */
+ dwc3_stop_active_transfer(dwc, dep->number);
+ goto out0;
+ }
+ dev_err(dwc->dev, "request %p was not queued to %s\n",
+ request, ep->name);
+ ret = -EINVAL;
+ goto out0;
+ }
+
+ /* giveback the request */
+ dwc3_gadget_giveback(dep, req, -ECONNRESET);
+
+out0:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3 *dwc = dep->dwc;
+ int ret;
+
+ memset(¶ms, 0x00, sizeof(params));
+
+ if (value) {
+ if (dep->number == 0 || dep->number == 1) {
+ /*
+ * Whenever EP0 is stalled, we will restart
+ * the state machine, thus moving back to
+ * Setup Phase
+ */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ }
+
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_SETSTALL, ¶ms);
+ if (ret)
+ dev_err(dwc->dev, "failed to %s STALL on %s\n",
+ value ? "set" : "clear",
+ dep->name);
+ else
+ dep->flags |= DWC3_EP_STALL;
+ } else {
+ if (dep->flags & DWC3_EP_WEDGE)
+ return 0;
+
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_CLEARSTALL, ¶ms);
+ if (ret)
+ dev_err(dwc->dev, "failed to %s STALL on %s\n",
+ value ? "set" : "clear",
+ dep->name);
+ else
+ dep->flags &= ~DWC3_EP_STALL;
+ }
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+
+ unsigned long flags;
+
+ int ret;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = __dwc3_gadget_ep_set_halt(dep, value);
+out:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+ struct dwc3_ep *dep = to_dwc3_ep(ep);
+
+ dep->flags |= DWC3_EP_WEDGE;
+
+ return dwc3_gadget_ep_set_halt(ep, 1);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
+ .enable = dwc3_gadget_ep0_enable,
+ .disable = dwc3_gadget_ep0_disable,
+ .alloc_request = dwc3_gadget_ep_alloc_request,
+ .free_request = dwc3_gadget_ep_free_request,
+ .queue = dwc3_gadget_ep0_queue,
+ .dequeue = dwc3_gadget_ep_dequeue,
+ .set_halt = dwc3_gadget_ep_set_halt,
+ .set_wedge = dwc3_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep_ops = {
+ .enable = dwc3_gadget_ep_enable,
+ .disable = dwc3_gadget_ep_disable,
+ .alloc_request = dwc3_gadget_ep_alloc_request,
+ .free_request = dwc3_gadget_ep_free_request,
+ .queue = dwc3_gadget_ep_queue,
+ .dequeue = dwc3_gadget_ep_dequeue,
+ .set_halt = dwc3_gadget_ep_set_halt,
+ .set_wedge = dwc3_gadget_ep_set_wedge,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_get_frame(struct usb_gadget *g)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ return DWC3_DSTS_SOFFN(reg);
+}
+
+static int dwc3_gadget_wakeup(struct usb_gadget *g)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+
+ unsigned long timeout;
+ unsigned long flags;
+
+ u32 reg;
+
+ int ret = 0;
+
+ u8 link_state;
+ u8 speed;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ /*
+ * According to the Databook Remote wakeup request should
+ * be issued only when the device is in early suspend state.
+ *
+ * We can check that via USB Link State bits in DSTS register.
+ */
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+ speed = reg & DWC3_DSTS_CONNECTSPD;
+ if (speed == DWC3_DSTS_SUPERSPEED) {
+ dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ link_state = DWC3_DSTS_USBLNKST(reg);
+
+ switch (link_state) {
+ case DWC3_LINK_STATE_RX_DET: /* in HS, means Early Suspend */
+ case DWC3_LINK_STATE_U3: /* in HS, means SUSPEND */
+ break;
+ default:
+ dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
+ link_state);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+
+ /*
+ * Switch link state to Recovery. In HS/FS/LS this means
+ * RemoteWakeup Request
+ */
+ reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ /* wait for at least 2000us */
+ usleep_range(2000, 2500);
+
+ /* write zeroes to Link Change Request */
+ reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ /* pool until Link State change to ON */
+ timeout = jiffies + msecs_to_jiffies(100);
+
+ while (!(time_after(jiffies, timeout))) {
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+ /* in HS, means ON */
+ if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
+ break;
+ }
+
+ if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
+ dev_err(dwc->dev, "failed to send remote wakeup\n");
+ ret = -EINVAL;
+ }
+
+out:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
+ int is_selfpowered)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+
+ dwc->is_selfpowered = !!is_selfpowered;
+
+ return 0;
+}
+
+static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+{
+ u32 reg;
+ u32 timeout = 500;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ if (is_on)
+ reg |= DWC3_DCTL_RUN_STOP;
+ else
+ reg &= ~DWC3_DCTL_RUN_STOP;
+
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ do {
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ if (is_on) {
+ if (!(reg & DWC3_DSTS_DEVCTRLHLT))
+ break;
+ } else {
+ if (reg & DWC3_DSTS_DEVCTRLHLT)
+ break;
+ }
+ timeout--;
+ if (!timeout)
+ break;
+ udelay(1);
+ } while (1);
+
+ dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+ dwc->gadget_driver
+ ? dwc->gadget_driver->function : "no-function",
+ is_on ? "connect" : "disconnect");
+}
+
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
+
+ is_on = !!is_on;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_run_stop(dwc, is_on);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+
+static int dwc3_gadget_start(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ struct dwc3_ep *dep;
+ unsigned long flags;
+ int ret = 0;
+ u32 reg;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ if (dwc->gadget_driver) {
+ dev_err(dwc->dev, "%s is already bound to %s\n",
+ dwc->gadget.name,
+ dwc->gadget_driver->driver.name);
+ ret = -EBUSY;
+ goto err0;
+ }
+
+ dwc->gadget_driver = driver;
+ dwc->gadget.dev.driver = &driver->driver;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+
+ reg &= ~DWC3_GCTL_SCALEDOWN(3);
+ reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG);
+ reg &= ~DWC3_GCTL_DISSCRAMBLE;
+ reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+
+ switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) {
+ case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+ reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+ break;
+ default:
+ dev_dbg(dwc->dev, "No power optimization available\n");
+ }
+
+ /*
+ * WORKAROUND: DWC3 revisions <1.90a have a bug
+ * when The device fails to connect at SuperSpeed
+ * and falls back to high-speed mode which causes
+ * the device to enter in a Connect/Disconnect loop
+ */
+ if (dwc->revision < DWC3_REVISION_190A)
+ reg |= DWC3_GCTL_U2RSTECN;
+
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+ reg |= DWC3_DCFG_SUPERSPEED;
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ dwc->start_config_issued = false;
+
+ /* Start with SuperSpeed Default */
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ goto err0;
+ }
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ goto err1;
+ }
+
+ /* begin to receive SETUP packets */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+
+err1:
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return ret;
+}
+
+static int dwc3_gadget_stop(struct usb_gadget *g,
+ struct usb_gadget_driver *driver)
+{
+ struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+ __dwc3_gadget_ep_disable(dwc->eps[1]);
+
+ dwc->gadget_driver = NULL;
+ dwc->gadget.dev.driver = NULL;
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
+}
+static const struct usb_gadget_ops dwc3_gadget_ops = {
+ .get_frame = dwc3_gadget_get_frame,
+ .wakeup = dwc3_gadget_wakeup,
+ .set_selfpowered = dwc3_gadget_set_selfpowered,
+ .pullup = dwc3_gadget_pullup,
+ .udc_start = dwc3_gadget_start,
+ .udc_stop = dwc3_gadget_stop,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ u8 epnum;
+
+ INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+ for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+ if (!dep) {
+ dev_err(dwc->dev, "can't allocate endpoint %d\n",
+ epnum);
+ return -ENOMEM;
+ }
+
+ dep->dwc = dwc;
+ dep->number = epnum;
+ dwc->eps[epnum] = dep;
+
+ snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
+ (epnum & 1) ? "in" : "out");
+ dep->endpoint.name = dep->name;
+ dep->direction = (epnum & 1);
+
+ if (epnum == 0 || epnum == 1) {
+ dep->endpoint.maxpacket = 512;
+ dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+ if (!epnum)
+ dwc->gadget.ep0 = &dep->endpoint;
+ } else {
+ int ret;
+
+ dep->endpoint.maxpacket = 1024;
+ dep->endpoint.ops = &dwc3_gadget_ep_ops;
+ list_add_tail(&dep->endpoint.ep_list,
+ &dwc->gadget.ep_list);
+
+ ret = dwc3_alloc_trb_pool(dep);
+ if (ret) {
+ dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
+ return ret;
+ }
+ }
+ INIT_LIST_HEAD(&dep->request_list);
+ INIT_LIST_HEAD(&dep->req_queued);
+ }
+
+ return 0;
+}
+
+static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ u8 epnum;
+
+ for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ dep = dwc->eps[epnum];
+ dwc3_free_trb_pool(dep);
+
+ if (epnum != 0 && epnum != 1)
+ list_del(&dep->endpoint.ep_list);
+
+ kfree(dep);
+ }
+}
+
+static void dwc3_gadget_release(struct device *dev)
+{
+ dev_dbg(dev, "%s\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event, int status)
+{
+ struct dwc3_request *req;
+ struct dwc3_trb trb;
+ unsigned int count;
+ unsigned int s_pkt = 0;
+
+ do {
+ req = next_request(&dep->req_queued);
+ if (!req)
+ break;
+
+ dwc3_trb_to_nat(req->trb, &trb);
+
+ if (trb.hwo && status != -ESHUTDOWN)
+ /*
+ * We continue despite the error. There is not much we
+ * can do. If we don't clean in up we loop for ever. If
+ * we skip the TRB than it gets overwritten reused after
+ * a while since we use them in a ring buffer. a BUG()
+ * would help. Lets hope that if this occures, someone
+ * fixes the root cause instead of looking away :)
+ */
+ dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
+ dep->name, req->trb);
+ count = trb.length;
+
+ if (dep->direction) {
+ if (count) {
+ dev_err(dwc->dev, "incomplete IN transfer %s\n",
+ dep->name);
+ status = -ECONNRESET;
+ }
+ } else {
+ if (count && (event->status & DEPEVT_STATUS_SHORT))
+ s_pkt = 1;
+ }
+
+ /*
+ * We assume here we will always receive the entire data block
+ * which we should receive. Meaning, if we program RX to
+ * receive 4K but we receive only 2K, we assume that's all we
+ * should receive and we simply bounce the request back to the
+ * gadget driver for further processing.
+ */
+ req->request.actual += req->request.length - count;
+ dwc3_gadget_giveback(dep, req, status);
+ if (s_pkt)
+ break;
+ if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+ break;
+ if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ break;
+ } while (1);
+
+ if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ return 0;
+ return 1;
+}
+
+static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
+ struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
+ int start_new)
+{
+ unsigned status = 0;
+ int clean_busy;
+
+ if (event->status & DEPEVT_STATUS_BUSERR)
+ status = -ECONNRESET;
+
+ clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+ if (clean_busy) {
+ dep->flags &= ~DWC3_EP_BUSY;
+ dep->res_trans_idx = 0;
+ }
+}
+
+static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
+ struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+ u32 uf;
+
+ if (list_empty(&dep->request_list)) {
+ dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
+ dep->name);
+ return;
+ }
+
+ if (event->parameters) {
+ u32 mask;
+
+ mask = ~(dep->interval - 1);
+ uf = event->parameters & mask;
+ /* 4 micro frames in the future */
+ uf += dep->interval * 4;
+ } else {
+ uf = 0;
+ }
+
+ __dwc3_gadget_kick_transfer(dep, uf, 1);
+}
+
+static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3 *dwc = dep->dwc;
+ struct dwc3_event_depevt mod_ev = *event;
+
+ /*
+ * We were asked to remove one requests. It is possible that this
+ * request and a few other were started together and have the same
+ * transfer index. Since we stopped the complete endpoint we don't
+ * know how many requests were already completed (and not yet)
+ * reported and how could be done (later). We purge them all until
+ * the end of the list.
+ */
+ mod_ev.status = DEPEVT_STATUS_LST;
+ dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
+ dep->flags &= ~DWC3_EP_BUSY;
+ /* pending requets are ignored and are queued on XferNotReady */
+}
+
+static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
+ const struct dwc3_event_depevt *event)
+{
+ u32 param = event->parameters;
+ u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
+
+ switch (cmd_type) {
+ case DWC3_DEPCMD_ENDTRANSFER:
+ dwc3_process_ep_cmd_complete(dep, event);
+ break;
+ case DWC3_DEPCMD_STARTTRANSFER:
+ dep->res_trans_idx = param & 0x7f;
+ break;
+ default:
+ printk(KERN_ERR "%s() unknown /unexpected type: %d\n",
+ __func__, cmd_type);
+ break;
+ };
+}
+
+static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+ const struct dwc3_event_depevt *event)
+{
+ struct dwc3_ep *dep;
+ u8 epnum = event->endpoint_number;
+
+ dep = dwc->eps[epnum];
+
+ dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
+ dwc3_ep_event_string(event->endpoint_event));
+
+ if (epnum == 0 || epnum == 1) {
+ dwc3_ep0_interrupt(dwc, event);
+ return;
+ }
+
+ switch (event->endpoint_event) {
+ case DWC3_DEPEVT_XFERCOMPLETE:
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
+ dep->name);
+ return;
+ }
+
+ dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
+ break;
+ case DWC3_DEPEVT_XFERINPROGRESS:
+ if (!usb_endpoint_xfer_isoc(dep->desc)) {
+ dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
+ dep->name);
+ return;
+ }
+
+ dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
+ break;
+ case DWC3_DEPEVT_XFERNOTREADY:
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ dwc3_gadget_start_isoc(dwc, dep, event);
+ } else {
+ int ret;
+
+ dev_vdbg(dwc->dev, "%s: reason %s\n",
+ dep->name, event->status
+ ? "Transfer Active"
+ : "Transfer Not Active");
+
+ ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
+ if (!ret || ret == -EBUSY)
+ return;
+
+ dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+ dep->name);
+ }
+
+ break;
+ case DWC3_DEPEVT_STREAMEVT:
+ if (!usb_endpoint_xfer_bulk(dep->desc)) {
+ dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
+ dep->name);
+ return;
+ }
+
+ switch (event->status) {
+ case DEPEVT_STREAMEVT_FOUND:
+ dev_vdbg(dwc->dev, "Stream %d found and started\n",
+ event->parameters);
+
+ break;
+ case DEPEVT_STREAMEVT_NOTFOUND:
+ /* FALLTHROUGH */
+ default:
+ dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
+ }
+ break;
+ case DWC3_DEPEVT_RXTXFIFOEVT:
+ dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
+ break;
+ case DWC3_DEPEVT_EPCMDCMPLT:
+ dwc3_ep_cmd_compl(dep, event);
+ break;
+ }
+}
+
+static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+{
+ if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
+ spin_unlock(&dwc->lock);
+ dwc->gadget_driver->disconnect(&dwc->gadget);
+ spin_lock(&dwc->lock);
+ }
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+{
+ struct dwc3_ep *dep;
+ struct dwc3_gadget_ep_cmd_params params;
+ u32 cmd;
+ int ret;
+
+ dep = dwc->eps[epnum];
+
+ WARN_ON(!dep->res_trans_idx);
+ if (dep->res_trans_idx) {
+ cmd = DWC3_DEPCMD_ENDTRANSFER;
+ cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+ cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
+ memset(¶ms, 0, sizeof(params));
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms);
+ WARN_ON_ONCE(ret);
+ dep->res_trans_idx = 0;
+ }
+}
+
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+ u32 epnum;
+
+ for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ struct dwc3_ep *dep;
+
+ dep = dwc->eps[epnum];
+ if (!(dep->flags & DWC3_EP_ENABLED))
+ continue;
+
+ dwc3_remove_requests(dwc, dep);
+ }
+}
+
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
+{
+ u32 epnum;
+
+ for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+ struct dwc3_ep *dep;
+ struct dwc3_gadget_ep_cmd_params params;
+ int ret;
+
+ dep = dwc->eps[epnum];
+
+ if (!(dep->flags & DWC3_EP_STALL))
+ continue;
+
+ dep->flags &= ~DWC3_EP_STALL;
+
+ memset(¶ms, 0, sizeof(params));
+ ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+ DWC3_DEPCMD_CLEARSTALL, ¶ms);
+ WARN_ON_ONCE(ret);
+ }
+}
+
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
+{
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+#if 0
+ XXX
+ U1/U2 is powersave optimization. Skip it for now. Anyway we need to
+ enable it before we can disable it.
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_INITU1ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ reg &= ~DWC3_DCTL_INITU2ENA;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+#endif
+
+ dwc3_stop_active_transfers(dwc);
+ dwc3_disconnect_gadget(dwc);
+ dwc->start_config_issued = false;
+
+ dwc->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+ if (on)
+ reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+ else
+ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+}
+
+static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
+{
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+ if (on)
+ reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+ else
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
+static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+{
+ u32 reg;
+
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+
+ /* Enable PHYs */
+ dwc3_gadget_usb2_phy_power(dwc, true);
+ dwc3_gadget_usb3_phy_power(dwc, true);
+
+ if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
+ dwc3_disconnect_gadget(dwc);
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ dwc3_stop_active_transfers(dwc);
+ dwc3_clear_stall_all_ep(dwc);
+ dwc->start_config_issued = false;
+
+ /* Reset device address to zero */
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
+{
+ u32 reg;
+ u32 usb30_clock = DWC3_GCTL_CLK_BUS;
+
+ /*
+ * We change the clock only at SS but I dunno why I would want to do
+ * this. Maybe it becomes part of the power saving plan.
+ */
+
+ if (speed != DWC3_DSTS_SUPERSPEED)
+ return;
+
+ /*
+ * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
+ * each time on Connect Done.
+ */
+ if (!usb30_clock)
+ return;
+
+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+ reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock);
+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
+{
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ dwc3_gadget_usb2_phy_power(dwc, false);
+ break;
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ case USB_SPEED_LOW:
+ dwc3_gadget_usb3_phy_power(dwc, false);
+ break;
+ }
+}
+
+static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+{
+ struct dwc3_gadget_ep_cmd_params params;
+ struct dwc3_ep *dep;
+ int ret;
+ u32 reg;
+ u8 speed;
+
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+
+ memset(¶ms, 0x00, sizeof(params));
+
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ speed = reg & DWC3_DSTS_CONNECTSPD;
+ dwc->speed = speed;
+
+ dwc3_update_ram_clk_sel(dwc, speed);
+
+ switch (speed) {
+ case DWC3_DCFG_SUPERSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+ dwc->gadget.ep0->maxpacket = 512;
+ dwc->gadget.speed = USB_SPEED_SUPER;
+ break;
+ case DWC3_DCFG_HIGHSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ dwc->gadget.ep0->maxpacket = 64;
+ dwc->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case DWC3_DCFG_FULLSPEED2:
+ case DWC3_DCFG_FULLSPEED1:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+ dwc->gadget.ep0->maxpacket = 64;
+ dwc->gadget.speed = USB_SPEED_FULL;
+ break;
+ case DWC3_DCFG_LOWSPEED:
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+ dwc->gadget.ep0->maxpacket = 8;
+ dwc->gadget.speed = USB_SPEED_LOW;
+ break;
+ }
+
+ /* Disable unneded PHY */
+ dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ return;
+ }
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ return;
+ }
+
+ /*
+ * Configure PHY via GUSB3PIPECTLn if required.
+ *
+ * Update GTXFIFOSIZn
+ *
+ * In both cases reset values should be sufficient.
+ */
+}
+
+static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+{
+ dev_vdbg(dwc->dev, "%s\n", __func__);
+
+ /*
+ * TODO take core out of low power mode when that's
+ * implemented.
+ */
+
+ dwc->gadget_driver->resume(&dwc->gadget);
+}
+
+static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
+ unsigned int evtinfo)
+{
+ /* The fith bit says SuperSpeed yes or no. */
+ dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
+
+ dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
+}
+
+static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+ const struct dwc3_event_devt *event)
+{
+ switch (event->type) {
+ case DWC3_DEVICE_EVENT_DISCONNECT:
+ dwc3_gadget_disconnect_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_RESET:
+ dwc3_gadget_reset_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_CONNECT_DONE:
+ dwc3_gadget_conndone_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_WAKEUP:
+ dwc3_gadget_wakeup_interrupt(dwc);
+ break;
+ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+ dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
+ break;
+ case DWC3_DEVICE_EVENT_EOPF:
+ dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+ break;
+ case DWC3_DEVICE_EVENT_SOF:
+ dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+ break;
+ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+ dev_vdbg(dwc->dev, "Erratic Error\n");
+ break;
+ case DWC3_DEVICE_EVENT_CMD_CMPL:
+ dev_vdbg(dwc->dev, "Command Complete\n");
+ break;
+ case DWC3_DEVICE_EVENT_OVERFLOW:
+ dev_vdbg(dwc->dev, "Overflow\n");
+ break;
+ default:
+ dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+ }
+}
+
+static void dwc3_process_event_entry(struct dwc3 *dwc,
+ const union dwc3_event *event)
+{
+ /* Endpoint IRQ, handle it and return early */
+ if (event->type.is_devspec == 0) {
+ /* depevt */
+ return dwc3_endpoint_interrupt(dwc, &event->depevt);
+ }
+
+ switch (event->type.type) {
+ case DWC3_EVENT_TYPE_DEV:
+ dwc3_gadget_interrupt(dwc, &event->devt);
+ break;
+ /* REVISIT what to do with Carkit and I2C events ? */
+ default:
+ dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
+ }
+}
+
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+{
+ struct dwc3_event_buffer *evt;
+ int left;
+ u32 count;
+
+ count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
+ count &= DWC3_GEVNTCOUNT_MASK;
+ if (!count)
+ return IRQ_NONE;
+
+ evt = dwc->ev_buffs[buf];
+ left = count;
+
+ while (left > 0) {
+ union dwc3_event event;
+
+ memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+ dwc3_process_event_entry(dwc, &event);
+ /*
+ * XXX we wrap around correctly to the next entry as almost all
+ * entries are 4 bytes in size. There is one entry which has 12
+ * bytes which is a regular entry followed by 8 bytes data. ATM
+ * I don't know how things are organized if were get next to the
+ * a boundary so I worry about that once we try to handle that.
+ */
+ evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+ left -= 4;
+
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+{
+ struct dwc3 *dwc = _dwc;
+ int i;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&dwc->lock);
+
+ for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+ irqreturn_t status;
+
+ status = dwc3_process_event_buf(dwc, i);
+ if (status == IRQ_HANDLED)
+ ret = status;
+ }
+
+ spin_unlock(&dwc->lock);
+
+ return ret;
+}
+
+/**
+ * dwc3_gadget_init - Initializes gadget related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int __devinit dwc3_gadget_init(struct dwc3 *dwc)
+{
+ u32 reg;
+ int ret;
+ int irq;
+
+ dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ &dwc->ctrl_req_addr, GFP_KERNEL);
+ if (!dwc->ctrl_req) {
+ dev_err(dwc->dev, "failed to allocate ctrl request\n");
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ &dwc->ep0_trb_addr, GFP_KERNEL);
+ if (!dwc->ep0_trb) {
+ dev_err(dwc->dev, "failed to allocate ep0 trb\n");
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ dwc->setup_buf = dma_alloc_coherent(dwc->dev,
+ sizeof(*dwc->setup_buf) * 2,
+ &dwc->setup_buf_addr, GFP_KERNEL);
+ if (!dwc->setup_buf) {
+ dev_err(dwc->dev, "failed to allocate setup buffer\n");
+ ret = -ENOMEM;
+ goto err2;
+ }
+
+ dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
+ 512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+ if (!dwc->ep0_bounce) {
+ dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
+ ret = -ENOMEM;
+ goto err3;
+ }
+
+ dev_set_name(&dwc->gadget.dev, "gadget");
+
+ dwc->gadget.ops = &dwc3_gadget_ops;
+ dwc->gadget.is_dualspeed = true;
+ dwc->gadget.speed = USB_SPEED_UNKNOWN;
+ dwc->gadget.dev.parent = dwc->dev;
+
+ dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
+
+ dwc->gadget.dev.dma_parms = dwc->dev->dma_parms;
+ dwc->gadget.dev.dma_mask = dwc->dev->dma_mask;
+ dwc->gadget.dev.release = dwc3_gadget_release;
+ dwc->gadget.name = "dwc3-gadget";
+
+ /*
+ * REVISIT: Here we should clear all pending IRQs to be
+ * sure we're starting from a well known location.
+ */
+
+ ret = dwc3_gadget_init_endpoints(dwc);
+ if (ret)
+ goto err4;
+
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+ ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
+ "dwc3", dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+ irq, ret);
+ goto err5;
+ }
+
+ /* Enable all but Start and End of Frame IRQs */
+ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+ DWC3_DEVTEN_EVNTOVERFLOWEN |
+ DWC3_DEVTEN_CMDCMPLTEN |
+ DWC3_DEVTEN_ERRTICERREN |
+ DWC3_DEVTEN_WKUPEVTEN |
+ DWC3_DEVTEN_ULSTCNGEN |
+ DWC3_DEVTEN_CONNECTDONEEN |
+ DWC3_DEVTEN_USBRSTEN |
+ DWC3_DEVTEN_DISCONNEVTEN);
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+ ret = device_register(&dwc->gadget.dev);
+ if (ret) {
+ dev_err(dwc->dev, "failed to register gadget device\n");
+ put_device(&dwc->gadget.dev);
+ goto err6;
+ }
+
+ ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+ if (ret) {
+ dev_err(dwc->dev, "failed to register udc\n");
+ goto err7;
+ }
+
+ return 0;
+
+err7:
+ device_unregister(&dwc->gadget.dev);
+
+err6:
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+ free_irq(irq, dwc);
+
+err5:
+ dwc3_gadget_free_endpoints(dwc);
+
+err4:
+ dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+ dwc->ep0_bounce_addr);
+
+err3:
+ dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+ dwc->setup_buf, dwc->setup_buf_addr);
+
+err2:
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ dwc->ep0_trb, dwc->ep0_trb_addr);
+
+err1:
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ dwc->ctrl_req, dwc->ctrl_req_addr);
+
+err0:
+ return ret;
+}
+
+void dwc3_gadget_exit(struct dwc3 *dwc)
+{
+ int irq;
+ int i;
+
+ usb_del_gadget_udc(&dwc->gadget);
+ irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+ dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+ free_irq(irq, dwc);
+
+ for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
+ __dwc3_gadget_ep_disable(dwc->eps[i]);
+
+ dwc3_gadget_free_endpoints(dwc);
+
+ dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+ dwc->ep0_bounce_addr);
+
+ dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+ dwc->setup_buf, dwc->setup_buf_addr);
+
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+ dwc->ep0_trb, dwc->ep0_trb_addr);
+
+ dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+ dwc->ctrl_req, dwc->ctrl_req_addr);
+
+ device_unregister(&dwc->gadget.dev);
+}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
new file mode 100644
index 0000000..71145a44
--- /dev/null
+++ b/drivers/usb/dwc3/gadget.h
@@ -0,0 +1,211 @@
+/**
+ * gadget.h - DesignWare USB3 DRD Gadget Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_GADGET_H
+#define __DRIVERS_USB_DWC3_GADGET_H
+
+#include <linux/list.h>
+#include <linux/usb/gadget.h>
+#include "io.h"
+
+struct dwc3;
+#define to_dwc3_ep(ep) (container_of(ep, struct dwc3_ep, endpoint))
+#define gadget_to_dwc(g) (container_of(g, struct dwc3, gadget))
+
+/* DEPCFG parameter 1 */
+#define DWC3_DEPCFG_INT_NUM(n) ((n) << 0)
+#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
+#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
+#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
+#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
+#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
+#define DWC3_DEPCFG_BINTERVAL_M1(n) ((n) << 16)
+#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
+#define DWC3_DEPCFG_EP_NUMBER(n) ((n) << 25)
+#define DWC3_DEPCFG_BULK_BASED (1 << 30)
+#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
+
+/* DEPCFG parameter 0 */
+#define DWC3_DEPCFG_EP_TYPE(n) ((n) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n) ((n) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n) ((n) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n) ((n) << 22)
+#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
+#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
+
+/* DEPXFERCFG parameter 0 */
+#define DWC3_DEPXFERCFG_NUM_XFER_RES(n) ((n) & 0xffff)
+
+struct dwc3_gadget_ep_cmd_params {
+ u32 param2;
+ u32 param1;
+ u32 param0;
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_request {
+ struct usb_request request;
+ struct list_head list;
+ struct dwc3_ep *dep;
+
+ u8 epnum;
+ struct dwc3_trb_hw *trb;
+ dma_addr_t trb_dma;
+
+ unsigned direction:1;
+ unsigned mapped:1;
+ unsigned queued:1;
+};
+#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
+
+static inline struct dwc3_request *next_request(struct list_head *list)
+{
+ if (list_empty(list))
+ return NULL;
+
+ return list_first_entry(list, struct dwc3_request, list);
+}
+
+static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
+{
+ struct dwc3_ep *dep = req->dep;
+
+ req->queued = true;
+ list_move_tail(&req->list, &dep->req_queued);
+}
+
+#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+ return 0;
+}
+#endif
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+ int status);
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
+void dwc3_ep0_out_start(struct dwc3 *dwc);
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+ gfp_t gfp_flags);
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+ unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
+void dwc3_map_buffer_to_dma(struct dwc3_request *req);
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
+
+/**
+ * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
+ * @dwc: DesignWare USB3 Pointer
+ * @number: DWC endpoint number
+ *
+ * Caller should take care of locking
+ */
+static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
+{
+ u32 res_id;
+
+ res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
+
+ return DWC3_DEPCMD_GET_RSC_IDX(res_id);
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_string(u8 event)
+{
+ switch (event) {
+ case DWC3_DEVICE_EVENT_DISCONNECT:
+ return "Disconnect";
+ case DWC3_DEVICE_EVENT_RESET:
+ return "Reset";
+ case DWC3_DEVICE_EVENT_CONNECT_DONE:
+ return "Connection Done";
+ case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+ return "Link Status Change";
+ case DWC3_DEVICE_EVENT_WAKEUP:
+ return "WakeUp";
+ case DWC3_DEVICE_EVENT_EOPF:
+ return "End-Of-Frame";
+ case DWC3_DEVICE_EVENT_SOF:
+ return "Start-Of-Frame";
+ case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+ return "Erratic Error";
+ case DWC3_DEVICE_EVENT_CMD_CMPL:
+ return "Command Complete";
+ case DWC3_DEVICE_EVENT_OVERFLOW:
+ return "Overflow";
+ }
+
+ return "UNKNOWN";
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(u8 event)
+{
+ switch (event) {
+ case DWC3_DEPEVT_XFERCOMPLETE:
+ return "Transfer Complete";
+ case DWC3_DEPEVT_XFERINPROGRESS:
+ return "Transfer In-Progress";
+ case DWC3_DEPEVT_XFERNOTREADY:
+ return "Transfer Not Ready";
+ case DWC3_DEPEVT_RXTXFIFOEVT:
+ return "FIFO";
+ case DWC3_DEPEVT_STREAMEVT:
+ return "Stream";
+ case DWC3_DEPEVT_EPCMDCMPLT:
+ return "Endpoint Command Complete";
+ }
+
+ return "UNKNOWN";
+}
+
+#endif /* __DRIVERS_USB_DWC3_GADGET_H */
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
new file mode 100644
index 0000000..bc957db
--- /dev/null
+++ b/drivers/usb/dwc3/io.h
@@ -0,0 +1,54 @@
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ * Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <asm/io.h>
+
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+ return readl(base + offset);
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+ writel(value, base + offset);
+}
+
+#endif /* __DRIVERS_USB_DWC3_IO_H */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 97e7aa4..092e115 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -386,6 +386,18 @@
default USB_GADGET
select USB_GADGET_SELECTED
+config USB_GADGET_DWC3
+ tristate "DesignWare USB3.0 (DRD) Controller"
+ depends on USB_DWC3
+ select USB_GADGET_DUALSPEED
+ select USB_GADGET_SUPERSPEED
+ help
+ DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+ which can be configured for peripheral-only, host-only, hub-only
+ and Dual-Role operation. This Controller was first integrated into
+ the OMAP5 series of processors. More information about the OMAP5
+ version of this controller, refer to http://www.ti.com/omap5.
+
#
# Controllers available in both integrated and discrete versions
#
@@ -673,6 +685,12 @@
bool
depends on USB_GADGET
+# Selected by UDC drivers that support super-speed opperation
+config USB_GADGET_SUPERSPEED
+ bool
+ depends on USB_GADGET
+ depends on USB_GADGET_DUALSPEED
+
#
# USB Gadget Drivers
#
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 141f649..655a7ee 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -3,6 +3,7 @@
#
ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
+obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 95e8138..70f2b37 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1438,10 +1438,15 @@
return 0;
}
+static int amd5536_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int amd5536_stop(struct usb_gadget_driver *driver);
/* gadget operations */
static const struct usb_gadget_ops udc_ops = {
.wakeup = udc_wakeup,
.get_frame = udc_get_frame,
+ .start = amd5536_start,
+ .stop = amd5536_stop,
};
/* Setups endpoint parameters, adds endpoints to linked list */
@@ -1955,7 +1960,7 @@
}
/* Called by gadget driver to register itself */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int amd5536_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct udc *dev = udc;
@@ -2002,7 +2007,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
/* shutdown requests and disconnect from gadget */
static void
@@ -2027,7 +2031,7 @@
}
/* Called by gadget driver to unregister itself */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int amd5536_stop(struct usb_gadget_driver *driver)
{
struct udc *dev = udc;
unsigned long flags;
@@ -2057,8 +2061,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
/* Clear pending NAK bits */
static void udc_process_cnak_queue(struct udc *dev)
@@ -3134,6 +3136,7 @@
dev = pci_get_drvdata(pdev);
+ usb_del_gadget_udc(&udc->gadget);
/* gadget driver must not be registered */
BUG_ON(dev->driver != NULL);
@@ -3382,8 +3385,13 @@
"driver version: %s(for Geode5536 B1)\n", tmp);
udc = dev;
+ retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
+ if (retval)
+ goto finished;
+
retval = device_register(&dev->gadget.dev);
if (retval) {
+ usb_del_gadget_udc(&dev->gadget);
put_device(&dev->gadget.dev);
goto finished;
}
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index c0c6c1e..7e731de 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -1388,6 +1388,7 @@
.dev = &device_desc,
.strings = dev_strings,
.unbind = android_usb_unbind,
+ .max_speed = USB_SPEED_SUPER
};
static int
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index f4690ff..98cbc06c 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -985,12 +985,18 @@
return 0;
}
+static int at91_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int at91_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops at91_udc_ops = {
.get_frame = at91_get_frame,
.wakeup = at91_wakeup,
.set_selfpowered = at91_set_selfpowered,
.vbus_session = at91_vbus_session,
.pullup = at91_pullup,
+ .start = at91_start,
+ .stop = at91_stop,
/*
* VBUS-powered devices may also also want to support bigger
@@ -1628,7 +1634,7 @@
schedule_work(&udc->vbus_timer_work);
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int at91_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct at91_udc *udc = &controller;
@@ -1672,9 +1678,8 @@
DBG("bound to %s\n", driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int at91_stop(struct usb_gadget_driver *driver)
{
struct at91_udc *udc = &controller;
unsigned long flags;
@@ -1696,7 +1701,6 @@
DBG("unbound from %s\n", driver->driver.name);
return 0;
}
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
/*-------------------------------------------------------------------------*/
@@ -1854,13 +1858,18 @@
DBG("no VBUS detection, assuming always-on\n");
udc->vbus = 1;
}
+ retval = usb_add_gadget_udc(dev, &udc->gadget);
+ if (retval)
+ goto fail4;
dev_set_drvdata(dev, udc);
device_init_wakeup(dev, 1);
create_debug_file(udc);
INFO("%s version %s\n", driver_name, DRIVER_VERSION);
return 0;
-
+fail4:
+ if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled)
+ free_irq(udc->board.vbus_pin, udc);
fail3:
if (udc->board.vbus_pin > 0)
gpio_free(udc->board.vbus_pin);
@@ -1887,6 +1896,7 @@
DBG("remove\n");
+ usb_del_gadget_udc(&udc->gadget);
if (udc->driver)
return -EBUSY;
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index db1a659..e6b970a 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1007,10 +1007,16 @@
return 0;
}
+static int atmel_usba_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int atmel_usba_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops usba_udc_ops = {
.get_frame = usba_udc_get_frame,
.wakeup = usba_udc_wakeup,
.set_selfpowered = usba_udc_set_selfpowered,
+ .start = atmel_usba_start,
+ .stop = atmel_usba_stop,
};
static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1789,7 +1795,7 @@
return IRQ_HANDLED;
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int atmel_usba_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct usba_udc *udc = &the_udc;
@@ -1842,9 +1848,8 @@
udc->gadget.dev.driver = NULL;
return ret;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int atmel_usba_stop(struct usb_gadget_driver *driver)
{
struct usba_udc *udc = &the_udc;
unsigned long flags;
@@ -1880,7 +1885,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
static int __init usba_udc_probe(struct platform_device *pdev)
{
@@ -2021,12 +2025,24 @@
}
}
+ ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ if (ret)
+ goto err_add_udc;
+
usba_init_debugfs(udc);
for (i = 1; i < pdata->num_ep; i++)
usba_ep_init_debugfs(udc, &usba_ep[i]);
return 0;
+err_add_udc:
+ if (gpio_is_valid(pdata->vbus_pin)) {
+ free_irq(gpio_to_irq(udc->vbus_pin), udc);
+ gpio_free(udc->vbus_pin);
+ }
+
+ device_unregister(&udc->gadget.dev);
+
err_device_add:
free_irq(irq, udc);
err_request_irq:
@@ -2053,6 +2069,8 @@
udc = platform_get_drvdata(pdev);
+ usb_del_gadget_udc(&udc->gadget);
+
for (i = 1; i < pdata->num_ep; i++)
usba_ep_cleanup_debugfs(&usba_ep[i]);
usba_cleanup_debugfs(udc);
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
index 93b999e..9d89ae47 100644
--- a/drivers/usb/gadget/audio.c
+++ b/drivers/usb/gadget/audio.c
@@ -165,6 +165,7 @@
.name = "g_audio",
.dev = &device_desc,
.strings = audio_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(audio_unbind),
};
diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c
index 2720ab0..b1c1afb 100644
--- a/drivers/usb/gadget/cdc2.c
+++ b/drivers/usb/gadget/cdc2.c
@@ -244,6 +244,7 @@
.name = "g_cdc",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(cdc_unbind),
};
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index ff4bbad..0fc9a03 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2485,6 +2485,7 @@
} while (mEp->dir != direction);
mEp->desc = NULL;
+ mEp->ep.desc = NULL;
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
@@ -2857,7 +2858,9 @@
return 0;
}
-
+static int ci13xxx_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int ci13xxx_stop(struct usb_gadget_driver *driver);
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
@@ -2868,17 +2871,19 @@
.wakeup = ci13xxx_wakeup,
.vbus_draw = ci13xxx_vbus_draw,
.pullup = ci13xxx_pullup,
+ .start = ci13xxx_start,
+ .stop = ci13xxx_stop,
};
/**
- * usb_gadget_probe_driver: register a gadget driver
+ * ci13xxx_start: register a gadget driver
* @driver: the driver being registered
* @bind: the driver's bind callback
*
- * Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details.
+ * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
* Interrupts are enabled here.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int ci13xxx_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct ci13xxx *udc = _udc;
@@ -2960,10 +2965,12 @@
if (retval)
goto done;
spin_unlock_irqrestore(udc->lock, flags);
- retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
+ udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
+ retval = usb_ep_enable(&udc->ep0out.ep);
if (retval)
return retval;
- retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
+ udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
+ retval = usb_ep_enable(&udc->ep0in.ep);
if (retval)
return retval;
spin_lock_irqsave(udc->lock, flags);
@@ -3008,14 +3015,13 @@
pm_runtime_put_sync(&udc->gadget.dev);
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
/**
- * usb_gadget_unregister_driver: unregister a gadget driver
+ * ci13xxx_stop: unregister a gadget driver
*
* Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
*/
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int ci13xxx_stop(struct usb_gadget_driver *driver)
{
struct ci13xxx *udc = _udc;
unsigned long i, flags;
@@ -3074,7 +3080,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/******************************************************************************
* BUS block
@@ -3249,12 +3254,23 @@
if (retval)
goto remove_dbg;
}
+
+ retval = usb_add_gadget_udc(dev, &udc->gadget);
+ if (retval)
+ goto remove_trans;
+
pm_runtime_no_callbacks(&udc->gadget.dev);
pm_runtime_enable(&udc->gadget.dev);
_udc = udc;
return retval;
+remove_trans:
+ if (udc->transceiver) {
+ otg_set_peripheral(udc->transceiver, &udc->gadget);
+ otg_put_transceiver(udc->transceiver);
+ }
+
err("error = %i", retval);
remove_dbg:
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -3284,6 +3300,7 @@
err("EINVAL");
return;
}
+ usb_del_gadget_udc(&udc->gadget);
if (udc->transceiver) {
otg_set_peripheral(udc->transceiver, &udc->gadget);
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 4c33695..c9d9c07 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -27,7 +27,7 @@
#include <linux/utsname.h>
#include <linux/usb/composite.h>
-
+#include <asm/unaligned.h>
/*
* The code in this file is utility code, used to build a gadget driver
@@ -74,6 +74,130 @@
static char composite_manufacturer[50];
/*-------------------------------------------------------------------------*/
+/**
+ * next_ep_desc() - advance to the next EP descriptor
+ * @t: currect pointer within descriptor array
+ *
+ * Return: next EP descriptor or NULL
+ *
+ * Iterate over @t until either EP descriptor found or
+ * NULL (that indicates end of list) encountered
+ */
+static struct usb_descriptor_header**
+next_ep_desc(struct usb_descriptor_header **t)
+{
+ for (; *t; t++) {
+ if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
+ return t;
+ }
+ return NULL;
+}
+
+/*
+ * for_each_ep_desc()- iterate over endpoint descriptors in the
+ * descriptors list
+ * @start: pointer within descriptor array.
+ * @ep_desc: endpoint descriptor to use as the loop cursor
+ */
+#define for_each_ep_desc(start, ep_desc) \
+ for (ep_desc = next_ep_desc(start); \
+ ep_desc; ep_desc = next_ep_desc(ep_desc+1))
+
+/**
+ * config_ep_by_speed() - configures the given endpoint
+ * according to gadget speed.
+ * @g: pointer to the gadget
+ * @f: usb function
+ * @_ep: the endpoint to configure
+ *
+ * Return: error code, 0 on success
+ *
+ * This function chooses the right descriptors for a given
+ * endpoint according to gadget speed and saves it in the
+ * endpoint desc field. If the endpoint already has a descriptor
+ * assigned to it - overwrites it with currently corresponding
+ * descriptor. The endpoint maxpacket field is updated according
+ * to the chosen descriptor.
+ * Note: the supplied function should hold all the descriptors
+ * for supported speeds
+ */
+int config_ep_by_speed(struct usb_gadget *g,
+ struct usb_function *f,
+ struct usb_ep *_ep)
+{
+ struct usb_endpoint_descriptor *chosen_desc = NULL;
+ struct usb_descriptor_header **speed_desc = NULL;
+
+ struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+ int want_comp_desc = 0;
+
+ struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+
+ if (!g || !f || !_ep)
+ return -EIO;
+
+ /* select desired speed */
+ switch (g->speed) {
+ case USB_SPEED_SUPER:
+ if (gadget_is_superspeed(g)) {
+ speed_desc = f->ss_descriptors;
+ want_comp_desc = 1;
+ break;
+ }
+ /* else: Fall trough */
+ case USB_SPEED_HIGH:
+ if (gadget_is_dualspeed(g)) {
+ speed_desc = f->hs_descriptors;
+ break;
+ }
+ /* else: fall through */
+ default:
+ speed_desc = f->descriptors;
+ }
+ /* find descriptors */
+ for_each_ep_desc(speed_desc, d_spd) {
+ chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
+ if (chosen_desc->bEndpointAddress == _ep->address)
+ goto ep_found;
+ }
+ return -EIO;
+
+ep_found:
+ /* commit results */
+ _ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+ _ep->desc = chosen_desc;
+ _ep->comp_desc = NULL;
+ _ep->maxburst = 0;
+ _ep->mult = 0;
+ if (!want_comp_desc)
+ return 0;
+
+ /*
+ * Companion descriptor should follow EP descriptor
+ * USB 3.0 spec, #9.6.7
+ */
+ comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
+ if (!comp_desc ||
+ (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
+ return -EIO;
+ _ep->comp_desc = comp_desc;
+ if (g->speed == USB_SPEED_SUPER) {
+ switch (usb_endpoint_type(_ep->desc)) {
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ _ep->maxburst = comp_desc->bMaxBurst;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ /* mult: bits 1:0 of bmAttributes */
+ _ep->mult = comp_desc->bmAttributes & 0x3;
+ break;
+ default:
+ /* Do nothing for control endpoints */
+ break;
+ }
+ }
+ return 0;
+}
/**
* usb_add_function() - add a function to a configuration
@@ -123,6 +247,8 @@
config->fullspeed = true;
if (!config->highspeed && function->hs_descriptors)
config->highspeed = true;
+ if (!config->superspeed && function->ss_descriptors)
+ config->superspeed = true;
done:
if (value)
@@ -266,10 +392,17 @@
list_for_each_entry(f, &config->functions, list) {
struct usb_descriptor_header **descriptors;
- if (speed == USB_SPEED_HIGH)
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ descriptors = f->ss_descriptors;
+ break;
+ case USB_SPEED_HIGH:
descriptors = f->hs_descriptors;
- else
+ break;
+ default:
descriptors = f->descriptors;
+ }
+
if (!descriptors)
continue;
status = usb_descriptor_fillbuf(next, len,
@@ -292,9 +425,10 @@
u8 type = w_value >> 8;
enum usb_device_speed speed = USB_SPEED_UNKNOWN;
- if (gadget_is_dualspeed(gadget)) {
- int hs = 0;
-
+ if (gadget->speed == USB_SPEED_SUPER)
+ speed = gadget->speed;
+ else if (gadget_is_dualspeed(gadget)) {
+ int hs = 0;
if (gadget->speed == USB_SPEED_HIGH)
hs = 1;
if (type == USB_DT_OTHER_SPEED_CONFIG)
@@ -308,13 +442,20 @@
w_value &= 0xff;
list_for_each_entry(c, &cdev->configs, list) {
/* ignore configs that won't work at this speed */
- if (speed == USB_SPEED_HIGH) {
+ switch (speed) {
+ case USB_SPEED_SUPER:
+ if (!c->superspeed)
+ continue;
+ break;
+ case USB_SPEED_HIGH:
if (!c->highspeed)
continue;
- } else {
+ break;
+ default:
if (!c->fullspeed)
continue;
}
+
if (w_value == 0)
return config_buf(c, speed, cdev->req->buf, type);
w_value--;
@@ -328,16 +469,22 @@
struct usb_configuration *c;
unsigned count = 0;
int hs = 0;
+ int ss = 0;
if (gadget_is_dualspeed(gadget)) {
if (gadget->speed == USB_SPEED_HIGH)
hs = 1;
+ if (gadget->speed == USB_SPEED_SUPER)
+ ss = 1;
if (type == USB_DT_DEVICE_QUALIFIER)
hs = !hs;
}
list_for_each_entry(c, &cdev->configs, list) {
/* ignore configs that won't work at this speed */
- if (hs) {
+ if (ss) {
+ if (!c->superspeed)
+ continue;
+ } else if (hs) {
if (!c->highspeed)
continue;
} else {
@@ -349,6 +496,71 @@
return count;
}
+/**
+ * bos_desc() - prepares the BOS descriptor.
+ * @cdev: pointer to usb_composite device to generate the bos
+ * descriptor for
+ *
+ * This function generates the BOS (Binary Device Object)
+ * descriptor and its device capabilities descriptors. The BOS
+ * descriptor should be supported by a SuperSpeed device.
+ */
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+ struct usb_ext_cap_descriptor *usb_ext;
+ struct usb_ss_cap_descriptor *ss_cap;
+ struct usb_dcd_config_params dcd_config_params;
+ struct usb_bos_descriptor *bos = cdev->req->buf;
+
+ bos->bLength = USB_DT_BOS_SIZE;
+ bos->bDescriptorType = USB_DT_BOS;
+
+ bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+ bos->bNumDeviceCaps = 0;
+
+ /*
+ * A SuperSpeed device shall include the USB2.0 extension descriptor
+ * and shall support LPM when operating in USB2.0 HS mode.
+ */
+ usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+ bos->bNumDeviceCaps++;
+ le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+ usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+ usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+ usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+ usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+
+ /*
+ * The Superspeed USB Capability descriptor shall be implemented by all
+ * SuperSpeed devices.
+ */
+ ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+ bos->bNumDeviceCaps++;
+ le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+ ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+ ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+ ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+ ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+ ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+ USB_FULL_SPEED_OPERATION |
+ USB_HIGH_SPEED_OPERATION |
+ USB_5GBPS_OPERATION);
+ ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+ /* Get Controller configuration */
+ if (cdev->gadget->ops->get_config_params)
+ cdev->gadget->ops->get_config_params(&dcd_config_params);
+ else {
+ dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
+ dcd_config_params.bU2DevExitLat =
+ cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
+ }
+ ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+ ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+
+ return le16_to_cpu(bos->wTotalLength);
+}
+
static void device_qual(struct usb_composite_dev *cdev)
{
struct usb_qualifier_descriptor *qual = cdev->req->buf;
@@ -361,7 +573,7 @@
qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
/* ASSUME same EP0 fifo size at both speeds */
- qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0;
+ qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
qual->bRESERVED = 0;
}
@@ -392,28 +604,46 @@
unsigned power = gadget_is_otg(gadget) ? 8 : 100;
int tmp;
- if (cdev->config)
- reset_config(cdev);
-
if (number) {
list_for_each_entry(c, &cdev->configs, list) {
if (c->bConfigurationValue == number) {
+ /*
+ * We disable the FDs of the previous
+ * configuration only if the new configuration
+ * is a valid one
+ */
+ if (cdev->config)
+ reset_config(cdev);
result = 0;
break;
}
}
if (result < 0)
goto done;
- } else
+ } else { /* Zero configuration value - need to reset the config */
+ if (cdev->config)
+ reset_config(cdev);
result = 0;
+ }
INFO(cdev, "%s speed config #%d: %s\n",
({ char *speed;
switch (gadget->speed) {
- case USB_SPEED_LOW: speed = "low"; break;
- case USB_SPEED_FULL: speed = "full"; break;
- case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
+ case USB_SPEED_LOW:
+ speed = "low";
+ break;
+ case USB_SPEED_FULL:
+ speed = "full";
+ break;
+ case USB_SPEED_HIGH:
+ speed = "high";
+ break;
+ case USB_SPEED_SUPER:
+ speed = "super";
+ break;
+ default:
+ speed = "?";
+ break;
} ; speed; }), number, c ? c->label : "unconfigured");
if (!c)
@@ -435,10 +665,16 @@
* function's setup callback instead of the current
* configuration's setup callback.
*/
- if (gadget->speed == USB_SPEED_HIGH)
+ switch (gadget->speed) {
+ case USB_SPEED_SUPER:
+ descriptors = f->ss_descriptors;
+ break;
+ case USB_SPEED_HIGH:
descriptors = f->hs_descriptors;
- else
+ break;
+ default:
descriptors = f->descriptors;
+ }
for (; *descriptors; ++descriptors) {
struct usb_endpoint_descriptor *ep;
@@ -533,8 +769,9 @@
} else {
unsigned i;
- DBG(cdev, "cfg %d/%p speeds:%s%s\n",
+ DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
config->bConfigurationValue, config,
+ config->superspeed ? " super" : "",
config->highspeed ? " high" : "",
config->fullspeed
? (gadget_is_dualspeed(cdev->gadget)
@@ -852,12 +1089,14 @@
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
+ int status = 0;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u8 intf = w_index & 0xFF;
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
struct usb_function *f = NULL;
u8 endp;
+ struct usb_configuration *c;
if (w_length > USB_BUFSIZ)
@@ -883,18 +1122,29 @@
case USB_DT_DEVICE:
cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE);
+ cdev->desc.bMaxPacketSize0 =
+ cdev->gadget->ep0->maxpacket;
+ if (gadget_is_superspeed(gadget)) {
+ if (gadget->speed >= USB_SPEED_SUPER)
+ cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+ else
+ cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+ }
+
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget_is_dualspeed(gadget) ||
+ gadget->speed >= USB_SPEED_SUPER)
break;
device_qual(cdev);
value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor));
break;
case USB_DT_OTHER_SPEED_CONFIG:
- if (!gadget_is_dualspeed(gadget))
+ if (!gadget_is_dualspeed(gadget) ||
+ gadget->speed >= USB_SPEED_SUPER)
break;
/* FALLTHROUGH */
case USB_DT_CONFIG:
@@ -902,12 +1152,28 @@
if (value >= 0)
value = min(w_length, (u16) value);
break;
+ case USB_DT_OTG:
+ if (!gadget_is_otg(gadget))
+ break;
+ c = list_first_entry(&cdev->configs,
+ struct usb_configuration, list);
+ if (c && c->descriptors)
+ value = usb_find_descriptor_fillbuf(req->buf,
+ USB_BUFSIZ, c->descriptors,
+ USB_DT_OTG);
+ break;
case USB_DT_STRING:
value = get_string(cdev, req->buf,
w_index, w_value & 0xff);
if (value >= 0)
value = min(w_length, (u16) value);
break;
+ case USB_DT_BOS:
+ if (gadget_is_superspeed(gadget)) {
+ value = bos_desc(cdev);
+ value = min(w_length, (u16) value);
+ }
+ break;
}
break;
@@ -975,6 +1241,61 @@
*((u8 *)req->buf) = value;
value = min(w_length, (u16) 1);
break;
+
+ /*
+ * USB 3.0 additions:
+ * Function driver should handle get_status request. If such cb
+ * wasn't supplied we respond with default value = 0
+ * Note: function driver should supply such cb only for the first
+ * interface of the function
+ */
+ case USB_REQ_GET_STATUS:
+ if (!gadget_is_superspeed(gadget))
+ goto unknown;
+ if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
+ goto unknown;
+ value = 2; /* This is the length of the get_status reply */
+ put_unaligned_le16(0, req->buf);
+ if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+ break;
+ f = cdev->config->interface[intf];
+ if (!f)
+ break;
+ status = f->get_status ? f->get_status(f) : 0;
+ if (status < 0)
+ break;
+ put_unaligned_le16(status & 0x0000ffff, req->buf);
+ break;
+ /*
+ * Function drivers should handle SetFeature/ClearFeature
+ * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
+ * only for the first interface of the function
+ */
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ if (!gadget_is_superspeed(gadget))
+ goto unknown;
+ if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+ goto unknown;
+ switch (w_value) {
+ case USB_INTRF_FUNC_SUSPEND:
+ if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+ break;
+ f = cdev->config->interface[intf];
+ if (!f)
+ break;
+ value = 0;
+ if (f->func_suspend)
+ value = f->func_suspend(f, w_index >> 8);
+ if (value < 0) {
+ ERROR(cdev,
+ "func_suspend() returned error %d\n",
+ value);
+ value = 0;
+ }
+ break;
+ }
+ break;
default:
unknown:
VDBG(cdev,
@@ -1166,7 +1487,6 @@
goto fail;
cdev->desc = *composite->dev;
- cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
/* standardized runtime overrides for device ID data */
if (idVendor)
@@ -1273,7 +1593,11 @@
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver composite_driver = {
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+ .speed = USB_SPEED_SUPER,
+#else
.speed = USB_SPEED_HIGH,
+#endif
.unbind = composite_unbind,
@@ -1319,6 +1643,8 @@
driver->iProduct = driver->name;
composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name;
+ composite_driver.speed = min((u8)composite_driver.speed,
+ (u8)driver->max_speed);
composite = driver;
composite_gadget_bind = bind;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 09084fd..870e662 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -28,6 +28,40 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+/**
+ * usb_find_descriptor_fillbuf - fill buffer with the requested descriptor
+ * @buf: Buffer to be filled
+ * @buflen: Size of buf
+ * @src: Array of descriptor pointers, terminated by null pointer.
+ * @desc_type: bDescriptorType field of the requested descriptor.
+ *
+ * Copies the requested descriptor into the buffer, returning the length
+ * or a negative error code if it is not found or can't be copied. Useful
+ * when DT_OTG descriptor is requested.
+ */
+int
+usb_find_descriptor_fillbuf(void *buf, unsigned buflen,
+ const struct usb_descriptor_header **src, u8 desc_type)
+{
+ if (!src)
+ return -EINVAL;
+
+ for (; NULL != *src; src++) {
+ unsigned len;
+
+ if ((*src)->bDescriptorType != desc_type)
+ continue;
+
+ len = (*src)->bLength;
+ if (len > buflen)
+ return -EINVAL;
+
+ memcpy(buf, *src, len);
+ return len;
+ }
+
+ return -ENOENT;
+}
/**
* usb_descriptor_fillbuf - fill buffer with descriptors
@@ -164,29 +198,3 @@
return ret;
}
-
-/**
- * usb_find_endpoint - find a copy of an endpoint descriptor
- * @src: original vector of descriptors
- * @copy: copy of @src
- * @match: endpoint descriptor found in @src
- *
- * This returns the copy of the @match descriptor made for @copy. Its
- * intended use is to help remembering the endpoint descriptor to use
- * when enabling a given endpoint.
- */
-struct usb_endpoint_descriptor *
-usb_find_endpoint(
- struct usb_descriptor_header **src,
- struct usb_descriptor_header **copy,
- struct usb_endpoint_descriptor *match
-)
-{
- while (*src) {
- if (*src == (void *) match)
- return (void *)*copy;
- src++;
- copy++;
- }
- return NULL;
-}
diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
index dbe92ee..8beefdd 100644
--- a/drivers/usb/gadget/dbgp.c
+++ b/drivers/usb/gadget/dbgp.c
@@ -173,7 +173,9 @@
static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
{
- int err = usb_ep_enable(ep, desc);
+ int err;
+ ep->desc = desc;
+ err = usb_ep_enable(ep);
ep->driver_data = dbgp.gadget;
return err;
}
@@ -268,8 +270,8 @@
dbgp.serial->in = dbgp.i_ep;
dbgp.serial->out = dbgp.o_ep;
- dbgp.serial->in_desc = &i_desc;
- dbgp.serial->out_desc = &o_desc;
+ dbgp.serial->in->desc = &i_desc;
+ dbgp.serial->out->desc = &o_desc;
if (gserial_setup(gadget, 1) < 0) {
stp = 3;
@@ -312,7 +314,6 @@
dbgp.req->length = DBGP_REQ_EP0_LEN;
gadget->ep0->driver_data = gadget;
- device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
#ifdef CONFIG_USB_G_DBGP_SERIAL
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
@@ -363,6 +364,7 @@
dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
len = sizeof device_desc;
data = &device_desc;
+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
break;
case USB_DT_DEBUG:
dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index d3dcabc..cbcb4c7 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -425,10 +425,18 @@
(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
({ char *val;
switch (desc->bmAttributes & 0x03) {
- case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
- case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
- case USB_ENDPOINT_XFER_INT: val = "intr"; break;
- default: val = "ctrl"; break;
+ case USB_ENDPOINT_XFER_BULK:
+ val = "bulk";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ val = "iso";
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ val = "intr";
+ break;
+ default:
+ val = "ctrl";
+ break;
}; val; }),
max);
@@ -710,11 +718,17 @@
return 0;
}
+static int dummy_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int dummy_udc_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops dummy_ops = {
.get_frame = dummy_g_get_frame,
.wakeup = dummy_wakeup,
.set_selfpowered = dummy_set_selfpowered,
.pullup = dummy_pullup,
+ .start = dummy_udc_start,
+ .stop = dummy_udc_stop,
};
/*-------------------------------------------------------------------------*/
@@ -747,8 +761,7 @@
* for each driver that registers: just add to a big root hub.
*/
-int
-usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int dummy_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct dummy *dum = the_controller;
@@ -812,10 +825,8 @@
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int
-usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int dummy_udc_stop(struct usb_gadget_driver *driver)
{
struct dummy *dum = the_controller;
unsigned long flags;
@@ -845,7 +856,6 @@
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
}
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
#undef is_enabled
@@ -892,11 +902,20 @@
return rc;
}
+ rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
+ if (rc < 0)
+ goto err_udc;
+
rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
if (rc < 0)
- device_unregister (&dum->gadget.dev);
- else
- platform_set_drvdata(pdev, dum);
+ goto err_dev;
+ platform_set_drvdata(pdev, dum);
+ return rc;
+
+err_dev:
+ usb_del_gadget_udc(&dum->gadget);
+err_udc:
+ device_unregister(&dum->gadget.dev);
return rc;
}
@@ -904,6 +923,7 @@
{
struct dummy *dum = platform_get_drvdata (pdev);
+ usb_del_gadget_udc(&dum->gadget);
platform_set_drvdata (pdev, NULL);
device_remove_file (&dum->gadget.dev, &dev_attr_function);
device_unregister (&dum->gadget.dev);
@@ -1786,18 +1806,34 @@
urb,
({ char *s;
switch (urb->dev->speed) {
- case USB_SPEED_LOW: s = "ls"; break;
- case USB_SPEED_FULL: s = "fs"; break;
- case USB_SPEED_HIGH: s = "hs"; break;
- default: s = "?"; break;
+ case USB_SPEED_LOW:
+ s = "ls";
+ break;
+ case USB_SPEED_FULL:
+ s = "fs";
+ break;
+ case USB_SPEED_HIGH:
+ s = "hs";
+ break;
+ default:
+ s = "?";
+ break;
}; s; }),
ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
({ char *s; \
switch (usb_pipetype (urb->pipe)) { \
- case PIPE_CONTROL: s = ""; break; \
- case PIPE_BULK: s = "-bulk"; break; \
- case PIPE_INTERRUPT: s = "-int"; break; \
- default: s = "-iso"; break; \
+ case PIPE_CONTROL: \
+ s = ""; \
+ break; \
+ case PIPE_BULK: \
+ s = "-bulk"; \
+ break; \
+ case PIPE_INTERRUPT: \
+ s = "-int"; \
+ break; \
+ default: \
+ s = "-iso"; \
+ break; \
}; s;}),
urb->actual_length, urb->transfer_buffer_length);
}
@@ -1863,7 +1899,6 @@
dum = hcd_to_dummy (hcd);
device_remove_file (dummy_dev(dum), &dev_attr_urbs);
- usb_gadget_unregister_driver (dum->driver);
dev_info (dummy_dev(dum), "stopped\n");
}
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 9b7360f..2fcfb9b 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -63,13 +63,16 @@
ep_matches (
struct usb_gadget *gadget,
struct usb_ep *ep,
- struct usb_endpoint_descriptor *desc
+ struct usb_endpoint_descriptor *desc,
+ struct usb_ss_ep_comp_descriptor *ep_comp
)
{
u8 type;
const char *tmp;
u16 max;
+ int num_req_streams = 0;
+
/* endpoint already claimed? */
if (NULL != ep->driver_data)
return 0;
@@ -129,6 +132,19 @@
}
/*
+ * Get the number of required streams from the EP companion
+ * descriptor and see if the EP matches it
+ */
+ if (usb_endpoint_xfer_bulk(desc)) {
+ if (ep_comp) {
+ num_req_streams = ep_comp->bmAttributes & 0x1f;
+ if (num_req_streams > ep->max_streams)
+ return 0;
+ }
+
+ }
+
+ /*
* If the protocol driver hasn't yet decided on wMaxPacketSize
* and wants to know the maximum possible, provide the info.
*/
@@ -142,13 +158,13 @@
max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
switch (type) {
case USB_ENDPOINT_XFER_INT:
- /* INT: limit 64 bytes full speed, 1024 high speed */
+ /* INT: limit 64 bytes full speed, 1024 high/super speed */
if (!gadget->is_dualspeed && max > 64)
return 0;
/* FALLTHROUGH */
case USB_ENDPOINT_XFER_ISOC:
- /* ISO: limit 1023 bytes full speed, 1024 high speed */
+ /* ISO: limit 1023 bytes full speed, 1024 high/super speed */
if (ep->maxpacket < max)
return 0;
if (!gadget->is_dualspeed && max > 1023)
@@ -183,7 +199,7 @@
}
/* report (variable) full speed bulk maxpacket */
- if (USB_ENDPOINT_XFER_BULK == type) {
+ if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
int size = ep->maxpacket;
/* min() doesn't work on bitfields with gcc-3.5 */
@@ -191,6 +207,7 @@
size = 64;
desc->wMaxPacketSize = cpu_to_le16(size);
}
+ ep->address = desc->bEndpointAddress;
return 1;
}
@@ -207,7 +224,120 @@
}
/**
- * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ * initialized. For periodic transfers, the maximum packet
+ * size must also be initialized. This is modified on
+ * success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ * number of streams. Will be modified when the chosen EP
+ * supports a different number of streams.
+ *
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers. The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware. This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claim it by
+ * assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig_ss(
+ struct usb_gadget *gadget,
+ struct usb_endpoint_descriptor *desc,
+ struct usb_ss_ep_comp_descriptor *ep_comp
+)
+{
+ struct usb_ep *ep;
+ u8 type;
+
+ type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+ /* First, apply chip-specific "best usage" knowledge.
+ * This might make a good usb_gadget_ops hook ...
+ */
+ if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
+ /* ep-e, ep-f are PIO with only 64 byte fifos */
+ ep = find_ep (gadget, "ep-e");
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ return ep;
+ ep = find_ep (gadget, "ep-f");
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ return ep;
+
+ } else if (gadget_is_goku (gadget)) {
+ if (USB_ENDPOINT_XFER_INT == type) {
+ /* single buffering is enough */
+ ep = find_ep(gadget, "ep3-bulk");
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ return ep;
+ } else if (USB_ENDPOINT_XFER_BULK == type
+ && (USB_DIR_IN & desc->bEndpointAddress)) {
+ /* DMA may be available */
+ ep = find_ep(gadget, "ep2-bulk");
+ if (ep && ep_matches(gadget, ep, desc,
+ ep_comp))
+ return ep;
+ }
+
+#ifdef CONFIG_BLACKFIN
+ } else if (gadget_is_musbhdrc(gadget)) {
+ if ((USB_ENDPOINT_XFER_BULK == type) ||
+ (USB_ENDPOINT_XFER_ISOC == type)) {
+ if (USB_DIR_IN & desc->bEndpointAddress)
+ ep = find_ep (gadget, "ep5in");
+ else
+ ep = find_ep (gadget, "ep6out");
+ } else if (USB_ENDPOINT_XFER_INT == type) {
+ if (USB_DIR_IN & desc->bEndpointAddress)
+ ep = find_ep(gadget, "ep1in");
+ else
+ ep = find_ep(gadget, "ep2out");
+ } else
+ ep = NULL;
+ if (ep && ep_matches(gadget, ep, desc, ep_comp))
+ return ep;
+#endif
+ }
+
+ /* Second, look at endpoints until an unclaimed one looks usable */
+ list_for_each_entry (ep, &gadget->ep_list, ep_list) {
+ if (ep_matches(gadget, ep, desc, ep_comp))
+ return ep;
+ }
+
+ /* Fail */
+ return NULL;
+}
+
+/**
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
* @gadget: The device to which the endpoint must belong.
* @desc: Endpoint descriptor, with endpoint direction and transfer mode
* initialized. For periodic transfers, the maximum packet
@@ -236,72 +366,15 @@
*
* On failure, this returns a null endpoint descriptor.
*/
-struct usb_ep *usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig(
struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc
)
{
- struct usb_ep *ep;
- u8 type;
-
- type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
-
- /* First, apply chip-specific "best usage" knowledge.
- * This might make a good usb_gadget_ops hook ...
- */
- if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
- /* ep-e, ep-f are PIO with only 64 byte fifos */
- ep = find_ep (gadget, "ep-e");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
- ep = find_ep (gadget, "ep-f");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
-
- } else if (gadget_is_goku (gadget)) {
- if (USB_ENDPOINT_XFER_INT == type) {
- /* single buffering is enough */
- ep = find_ep (gadget, "ep3-bulk");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
- } else if (USB_ENDPOINT_XFER_BULK == type
- && (USB_DIR_IN & desc->bEndpointAddress)) {
- /* DMA may be available */
- ep = find_ep (gadget, "ep2-bulk");
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
- }
-
-#ifdef CONFIG_BLACKFIN
- } else if (gadget_is_musbhdrc(gadget)) {
- if ((USB_ENDPOINT_XFER_BULK == type) ||
- (USB_ENDPOINT_XFER_ISOC == type)) {
- if (USB_DIR_IN & desc->bEndpointAddress)
- ep = find_ep (gadget, "ep5in");
- else
- ep = find_ep (gadget, "ep6out");
- } else if (USB_ENDPOINT_XFER_INT == type) {
- if (USB_DIR_IN & desc->bEndpointAddress)
- ep = find_ep(gadget, "ep1in");
- else
- ep = find_ep(gadget, "ep2out");
- } else
- ep = NULL;
- if (ep && ep_matches (gadget, ep, desc))
- return ep;
-#endif
- }
-
- /* Second, look at endpoints until an unclaimed one looks usable */
- list_for_each_entry (ep, &gadget->ep_list, ep_list) {
- if (ep_matches (gadget, ep, desc))
- return ep;
- }
-
- /* Fail */
- return NULL;
+ return usb_ep_autoconfig_ss(gadget, desc, NULL);
}
+
/**
* usb_ep_autoconfig_reset - reset endpoint autoconfig state
* @gadget: device for which autoconfig state will be reset
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 1690c9d..ac41858 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -401,6 +401,7 @@
.name = "g_ether",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(eth_unbind),
};
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 05e65e5..0187b69 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -686,17 +686,33 @@
int ret;
DBG(cdev, "acc_function_set_alt intf: %d alt: %d\n", intf, alt);
- ret = usb_ep_enable(dev->ep_in,
- ep_choose(cdev->gadget,
- &acc_highspeed_in_desc,
- &acc_fullspeed_in_desc));
- if (ret)
- return ret;
- ret = usb_ep_enable(dev->ep_out,
- ep_choose(cdev->gadget,
- &acc_highspeed_out_desc,
- &acc_fullspeed_out_desc));
+
+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
if (ret) {
+ dev->ep_in->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->ep_in->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->ep_in);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ dev->ep_in->name, ret);
+ return ret;
+ }
+
+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
+ if (ret) {
+ dev->ep_out->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->ep_out->name, ret);
+ usb_ep_disable(dev->ep_in);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->ep_out);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ dev->ep_out->name, ret);
usb_ep_disable(dev->ep_in);
return ret;
}
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 380ef87..8e542a4 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -42,12 +42,6 @@
* descriptors (roughly equivalent to CDC Unions) may sometimes help.
*/
-struct acm_ep_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
- struct usb_endpoint_descriptor *notify;
-};
-
struct f_acm {
struct gserial port;
u8 ctrl_id, data_id;
@@ -62,11 +56,7 @@
*/
spinlock_t lock;
- struct acm_ep_descs fs;
- struct acm_ep_descs hs;
-
struct usb_ep *notify;
- struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req;
struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
@@ -497,10 +487,10 @@
} else {
VDBG(cdev, "init acm ctrl interface %d\n", intf);
}
- acm->notify_desc = ep_choose(cdev->gadget,
- acm->hs.notify,
- acm->fs.notify);
- usb_ep_enable(acm->notify, acm->notify_desc);
+ if (config_ep_by_speed(cdev->gadget, f, acm->notify))
+ return -EINVAL;
+
+ usb_ep_enable(acm->notify);
acm->notify->driver_data = acm;
} else if (intf == acm->data_id) {
@@ -510,10 +500,15 @@
} else {
DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
}
- acm->port.in_desc = ep_choose(cdev->gadget,
- acm->hs.in, acm->fs.in);
- acm->port.out_desc = ep_choose(cdev->gadget,
- acm->hs.out, acm->fs.out);
+ if (config_ep_by_speed(cdev->gadget, f,
+ acm->port.in) ||
+ config_ep_by_speed(cdev->gadget, f,
+ acm->port.out)) {
+ acm->port.in->desc = NULL;
+ acm->port.out->desc = NULL;
+ return -EINVAL;
+ }
+
acm_port_connect(acm);
} else
@@ -729,18 +724,11 @@
acm->notify_req->complete = acm_cdc_notify_complete;
acm->notify_req->context = acm;
- /* copy descriptors, and track endpoint copies */
+ /* copy descriptors */
f->descriptors = usb_copy_descriptors(acm_fs_function);
if (!f->descriptors)
goto fail;
- acm->fs.in = usb_find_endpoint(acm_fs_function,
- f->descriptors, &acm_fs_in_desc);
- acm->fs.out = usb_find_endpoint(acm_fs_function,
- f->descriptors, &acm_fs_out_desc);
- acm->fs.notify = usb_find_endpoint(acm_fs_function,
- f->descriptors, &acm_fs_notify_desc);
-
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
@@ -753,17 +741,10 @@
acm_hs_notify_desc.bEndpointAddress =
acm_fs_notify_desc.bEndpointAddress;
- /* copy descriptors, and track endpoint copies */
+ /* copy descriptors */
f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
if (!f->hs_descriptors)
goto fail;
-
- acm->hs.in = usb_find_endpoint(acm_hs_function,
- f->hs_descriptors, &acm_hs_in_desc);
- acm->hs.out = usb_find_endpoint(acm_hs_function,
- f->hs_descriptors, &acm_hs_out_desc);
- acm->hs.notify = usb_find_endpoint(acm_hs_function,
- f->hs_descriptors, &acm_hs_notify_desc);
}
DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index cae0136..0cf6d48 100644
--- a/drivers/usb/gadget/f_adb.c
+++ b/drivers/usb/gadget/f_adb.c
@@ -510,17 +510,33 @@
int ret;
DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt);
- ret = usb_ep_enable(dev->ep_in,
- ep_choose(cdev->gadget,
- &adb_highspeed_in_desc,
- &adb_fullspeed_in_desc));
- if (ret)
- return ret;
- ret = usb_ep_enable(dev->ep_out,
- ep_choose(cdev->gadget,
- &adb_highspeed_out_desc,
- &adb_fullspeed_out_desc));
+
+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
if (ret) {
+ dev->ep_in->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->ep_in->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->ep_in);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ dev->ep_in->name, ret);
+ return ret;
+ }
+
+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
+ if (ret) {
+ dev->ep_out->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->ep_out->name, ret);
+ usb_ep_disable(dev->ep_in);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->ep_out);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ dev->ep_out->name, ret);
usb_ep_disable(dev->ep_in);
return ret;
}
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 8ee330a..02a0270 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -279,7 +279,6 @@
/* endpoints handle full and/or high speeds */
struct usb_ep *out_ep;
- struct usb_endpoint_descriptor *out_desc;
spinlock_t lock;
struct f_audio_buf *copy_buf;
@@ -575,7 +574,7 @@
if (intf == 1) {
if (alt == 1) {
- usb_ep_enable(out_ep, audio->out_desc);
+ usb_ep_enable(out_ep);
out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
if (IS_ERR(audio->copy_buf))
@@ -677,6 +676,7 @@
if (!ep)
goto fail;
audio->out_ep = ep;
+ audio->out_ep->desc = &as_out_ep_desc;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
@@ -776,7 +776,6 @@
audio->card.func.set_alt = f_audio_set_alt;
audio->card.func.setup = f_audio_setup;
audio->card.func.disable = f_audio_disable;
- audio->out_desc = &as_out_ep_desc;
control_selector_init(audio);
diff --git a/drivers/usb/gadget/f_ccid.c b/drivers/usb/gadget/f_ccid.c
index a11f439..c8f144a 100644
--- a/drivers/usb/gadget/f_ccid.c
+++ b/drivers/usb/gadget/f_ccid.c
@@ -33,12 +33,6 @@
/* number of tx requests to allocate */
#define TX_REQ_MAX 4
-struct ccid_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
- struct usb_endpoint_descriptor *notify;
-};
-
struct ccid_ctrl_dev {
atomic_t opened;
struct list_head tx_q;
@@ -64,16 +58,10 @@
int ifc_id;
spinlock_t lock;
atomic_t online;
- /* usb descriptors */
- struct ccid_descs fs;
- struct ccid_descs hs;
/* usb eps*/
struct usb_ep *notify;
struct usb_ep *in;
struct usb_ep *out;
- struct usb_endpoint_descriptor *in_desc;
- struct usb_endpoint_descriptor *out_desc;
- struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req;
struct ccid_ctrl_dev ctrl_dev;
struct ccid_bulk_dev bulk_dev;
@@ -436,10 +424,14 @@
}
/* choose the descriptors and enable endpoints */
- ccid_dev->notify_desc = ep_choose(cdev->gadget,
- ccid_dev->hs.notify,
- ccid_dev->fs.notify);
- ret = usb_ep_enable(ccid_dev->notify, ccid_dev->notify_desc);
+ ret = config_ep_by_speed(cdev->gadget, f, ccid_dev->notify);
+ if (ret) {
+ ccid_dev->notify->desc = NULL;
+ pr_err("%s: config_ep_by_speed failed for ep#%s, err#%d\n",
+ __func__, ccid_dev->notify->name, ret);
+ goto free_bulk_in;
+ }
+ ret = usb_ep_enable(ccid_dev->notify);
if (ret) {
pr_err("%s: usb ep#%s enable failed, err#%d\n",
__func__, ccid_dev->notify->name, ret);
@@ -447,18 +439,28 @@
}
ccid_dev->notify->driver_data = ccid_dev;
- ccid_dev->in_desc = ep_choose(cdev->gadget,
- ccid_dev->hs.in, ccid_dev->fs.in);
- ret = usb_ep_enable(ccid_dev->in, ccid_dev->in_desc);
+ ret = config_ep_by_speed(cdev->gadget, f, ccid_dev->in);
+ if (ret) {
+ ccid_dev->in->desc = NULL;
+ pr_err("%s: config_ep_by_speed failed for ep#%s, err#%d\n",
+ __func__, ccid_dev->in->name, ret);
+ goto disable_ep_notify;
+ }
+ ret = usb_ep_enable(ccid_dev->in);
if (ret) {
pr_err("%s: usb ep#%s enable failed, err#%d\n",
__func__, ccid_dev->in->name, ret);
goto disable_ep_notify;
}
- ccid_dev->out_desc = ep_choose(cdev->gadget,
- ccid_dev->hs.out, ccid_dev->fs.out);
- ret = usb_ep_enable(ccid_dev->out, ccid_dev->out_desc);
+ ret = config_ep_by_speed(cdev->gadget, f, ccid_dev->out);
+ if (ret) {
+ ccid_dev->out->desc = NULL;
+ pr_err("%s: config_ep_by_speed failed for ep#%s, err#%d\n",
+ __func__, ccid_dev->out->name, ret);
+ goto disable_ep_in;
+ }
+ ret = usb_ep_enable(ccid_dev->out);
if (ret) {
pr_err("%s: usb ep#%s enable failed, err#%d\n",
__func__, ccid_dev->out->name, ret);
@@ -538,16 +540,6 @@
if (!f->descriptors)
goto ep_auto_out_fail;
- ccid_dev->fs.in = usb_find_endpoint(ccid_fs_descs,
- f->descriptors,
- &ccid_fs_in_desc);
- ccid_dev->fs.out = usb_find_endpoint(ccid_fs_descs,
- f->descriptors,
- &ccid_fs_out_desc);
- ccid_dev->fs.notify = usb_find_endpoint(ccid_fs_descs,
- f->descriptors,
- &ccid_fs_notify_desc);
-
if (gadget_is_dualspeed(cdev->gadget)) {
ccid_hs_in_desc.bEndpointAddress =
ccid_fs_in_desc.bEndpointAddress;
@@ -560,13 +552,6 @@
f->hs_descriptors = usb_copy_descriptors(ccid_hs_descs);
if (!f->hs_descriptors)
goto ep_auto_out_fail;
-
- ccid_dev->hs.in = usb_find_endpoint(ccid_hs_descs,
- f->hs_descriptors, &ccid_hs_in_desc);
- ccid_dev->hs.out = usb_find_endpoint(ccid_hs_descs,
- f->hs_descriptors, &ccid_hs_out_desc);
- ccid_dev->hs.notify = usb_find_endpoint(ccid_hs_descs,
- f->hs_descriptors, &ccid_hs_notify_desc);
}
pr_debug("%s: CCID %s Speed, IN:%s OUT:%s\n", __func__,
diff --git a/drivers/usb/gadget/f_diag.c b/drivers/usb/gadget/f_diag.c
index 987ae65..c4c7941 100644
--- a/drivers/usb/gadget/f_diag.c
+++ b/drivers/usb/gadget/f_diag.c
@@ -108,8 +108,6 @@
struct usb_function function;
struct usb_ep *out;
struct usb_ep *in;
- struct usb_endpoint_descriptor *in_desc;
- struct usb_endpoint_descriptor *out_desc;
struct list_head read_pool;
struct list_head write_pool;
struct work_struct config_work;
@@ -514,21 +512,22 @@
unsigned long flags;
int rc = 0;
- dev->in_desc = ep_choose(cdev->gadget,
- (struct usb_endpoint_descriptor *)f->hs_descriptors[1],
- (struct usb_endpoint_descriptor *)f->descriptors[1]);
- dev->out_desc = ep_choose(cdev->gadget,
- (struct usb_endpoint_descriptor *)f->hs_descriptors[2],
- (struct usb_endpoint_descriptor *)f->descriptors[2]);
+ if (config_ep_by_speed(cdev->gadget, f, dev->in) ||
+ config_ep_by_speed(cdev->gadget, f, dev->out)) {
+ dev->in->desc = NULL;
+ dev->out->desc = NULL;
+ return -EINVAL;
+ }
+
dev->in->driver_data = dev;
- rc = usb_ep_enable(dev->in, dev->in_desc);
+ rc = usb_ep_enable(dev->in);
if (rc) {
ERROR(dev->cdev, "can't enable %s, result %d\n",
dev->in->name, rc);
return rc;
}
dev->out->driver_data = dev;
- rc = usb_ep_enable(dev->out, dev->out_desc);
+ rc = usb_ep_enable(dev->out);
if (rc) {
ERROR(dev->cdev, "can't enable %s, result %d\n",
dev->out->name, rc);
@@ -630,7 +629,7 @@
/* claim the channel for this USB interface */
_ch->priv_usb = dev;
- dev->update_pid_and_serial_num = update_pid;
+ dev->update_pid_and_serial_num = update_pid;
dev->cdev = c->cdev;
dev->function.name = _ch->name;
dev->function.descriptors = fs_diag_desc;
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 544257a8..ddedbc83 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -46,11 +46,6 @@
* and also means that a get_alt() method is required.
*/
-struct ecm_ep_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
- struct usb_endpoint_descriptor *notify;
-};
enum ecm_notify_state {
ECM_NOTIFY_NONE, /* don't notify */
@@ -64,11 +59,7 @@
char ethaddr[14];
- struct ecm_ep_descs fs;
- struct ecm_ep_descs hs;
-
struct usb_ep *notify;
- struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req;
u8 notify_state;
bool is_open;
@@ -464,13 +455,13 @@
if (ecm->notify->driver_data) {
VDBG(cdev, "reset ecm control %d\n", intf);
usb_ep_disable(ecm->notify);
- } else {
- VDBG(cdev, "init ecm ctrl %d\n", intf);
- ecm->notify_desc = ep_choose(cdev->gadget,
- ecm->hs.notify,
- ecm->fs.notify);
}
- usb_ep_enable(ecm->notify, ecm->notify_desc);
+ if (!(ecm->notify->desc)) {
+ VDBG(cdev, "init ecm ctrl %d\n", intf);
+ if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
+ goto fail;
+ }
+ usb_ep_enable(ecm->notify);
ecm->notify->driver_data = ecm;
/* Data interface has two altsettings, 0 and 1 */
@@ -483,12 +474,17 @@
gether_disconnect(&ecm->port);
}
- if (!ecm->port.in) {
+ if (!ecm->port.in_ep->desc ||
+ !ecm->port.out_ep->desc) {
DBG(cdev, "init ecm\n");
- ecm->port.in = ep_choose(cdev->gadget,
- ecm->hs.in, ecm->fs.in);
- ecm->port.out = ep_choose(cdev->gadget,
- ecm->hs.out, ecm->fs.out);
+ if (config_ep_by_speed(cdev->gadget, f,
+ ecm->port.in_ep) ||
+ config_ep_by_speed(cdev->gadget, f,
+ ecm->port.out_ep)) {
+ ecm->port.in_ep->desc = NULL;
+ ecm->port.out_ep->desc = NULL;
+ goto fail;
+ }
}
/* CDC Ethernet only sends data in non-default altsettings.
@@ -549,7 +545,7 @@
if (ecm->notify->driver_data) {
usb_ep_disable(ecm->notify);
ecm->notify->driver_data = NULL;
- ecm->notify_desc = NULL;
+ ecm->notify->desc = NULL;
}
}
@@ -665,13 +661,6 @@
if (!f->descriptors)
goto fail;
- ecm->fs.in = usb_find_endpoint(ecm_fs_function,
- f->descriptors, &fs_ecm_in_desc);
- ecm->fs.out = usb_find_endpoint(ecm_fs_function,
- f->descriptors, &fs_ecm_out_desc);
- ecm->fs.notify = usb_find_endpoint(ecm_fs_function,
- f->descriptors, &fs_ecm_notify_desc);
-
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
@@ -688,13 +677,6 @@
f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
if (!f->hs_descriptors)
goto fail;
-
- ecm->hs.in = usb_find_endpoint(ecm_hs_function,
- f->hs_descriptors, &hs_ecm_in_desc);
- ecm->hs.out = usb_find_endpoint(ecm_hs_function,
- f->hs_descriptors, &hs_ecm_out_desc);
- ecm->hs.notify = usb_find_endpoint(ecm_hs_function,
- f->hs_descriptors, &hs_ecm_notify_desc);
}
/* NOTE: all that is done without knowing or caring about
@@ -723,9 +705,9 @@
/* we might as well release our claims on endpoints */
if (ecm->notify)
ecm->notify->driver_data = NULL;
- if (ecm->port.out)
+ if (ecm->port.out_ep->desc)
ecm->port.out_ep->driver_data = NULL;
- if (ecm->port.in)
+ if (ecm->port.in_ep->desc)
ecm->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c
index b3c3042..3e41274 100644
--- a/drivers/usb/gadget/f_eem.c
+++ b/drivers/usb/gadget/f_eem.c
@@ -35,17 +35,9 @@
* Ethernet link.
*/
-struct eem_ep_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
-};
-
struct f_eem {
struct gether port;
u8 ctrl_id;
-
- struct eem_ep_descs fs;
- struct eem_ep_descs hs;
};
static inline struct f_eem *func_to_eem(struct usb_function *f)
@@ -176,12 +168,16 @@
gether_disconnect(&eem->port);
}
- if (!eem->port.in) {
+ if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
DBG(cdev, "init eem\n");
- eem->port.in = ep_choose(cdev->gadget,
- eem->hs.in, eem->fs.in);
- eem->port.out = ep_choose(cdev->gadget,
- eem->hs.out, eem->fs.out);
+ if (config_ep_by_speed(cdev->gadget, f,
+ eem->port.in_ep) ||
+ config_ep_by_speed(cdev->gadget, f,
+ eem->port.out_ep)) {
+ eem->port.in_ep->desc = NULL;
+ eem->port.out_ep->desc = NULL;
+ goto fail;
+ }
}
/* zlps should not occur because zero-length EEM packets
@@ -253,11 +249,6 @@
if (!f->descriptors)
goto fail;
- eem->fs.in = usb_find_endpoint(eem_fs_function,
- f->descriptors, &eem_fs_in_desc);
- eem->fs.out = usb_find_endpoint(eem_fs_function,
- f->descriptors, &eem_fs_out_desc);
-
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
@@ -272,11 +263,6 @@
f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
if (!f->hs_descriptors)
goto fail;
-
- eem->hs.in = usb_find_endpoint(eem_hs_function,
- f->hs_descriptors, &eem_hs_in_desc);
- eem->hs.out = usb_find_endpoint(eem_hs_function,
- f->hs_descriptors, &eem_hs_out_desc);
}
DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
@@ -289,9 +275,9 @@
usb_free_descriptors(f->descriptors);
/* we might as well release our claims on endpoints */
- if (eem->port.out)
+ if (eem->port.out_ep->desc)
eem->port.out_ep->driver_data = NULL;
- if (eem->port.in)
+ if (eem->port.in_ep->desc)
eem->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index 19fffcc..c161a9a 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1544,7 +1544,8 @@
ds = ep->descs[ep->descs[1] ? 1 : 0];
ep->ep->driver_data = ep;
- ret = usb_ep_enable(ep->ep, ds);
+ ep->ep->desc = ds;
+ ret = usb_ep_enable(ep->ep);
if (likely(!ret)) {
epfile->ep = ep;
epfile->in = usb_endpoint_dir_in(ds);
diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c
index 598e7e2..403a48b 100644
--- a/drivers/usb/gadget/f_hid.c
+++ b/drivers/usb/gadget/f_hid.c
@@ -59,8 +59,6 @@
struct cdev cdev;
struct usb_function func;
struct usb_ep *in_ep;
- struct usb_endpoint_descriptor *fs_in_ep_desc;
- struct usb_endpoint_descriptor *hs_in_ep_desc;
};
static inline struct f_hidg *func_to_hidg(struct usb_function *f)
@@ -416,7 +414,6 @@
{
struct usb_composite_dev *cdev = f->config->cdev;
struct f_hidg *hidg = func_to_hidg(f);
- const struct usb_endpoint_descriptor *ep_desc;
int status = 0;
VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
@@ -426,9 +423,13 @@
if (hidg->in_ep->driver_data != NULL)
usb_ep_disable(hidg->in_ep);
- ep_desc = ep_choose(f->config->cdev->gadget,
- hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
- status = usb_ep_enable(hidg->in_ep, ep_desc);
+ status = config_ep_by_speed(f->config->cdev->gadget, f,
+ hidg->in_ep);
+ if (status) {
+ ERROR(cdev, "config_ep_by_speed FAILED!\n");
+ goto fail;
+ }
+ status = usb_ep_enable(hidg->in_ep);
if (status < 0) {
ERROR(cdev, "Enable endpoint FAILED!\n");
goto fail;
@@ -498,21 +499,12 @@
if (!f->descriptors)
goto fail;
- hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
- f->descriptors,
- &hidg_fs_in_ep_desc);
-
if (gadget_is_dualspeed(c->cdev->gadget)) {
hidg_hs_in_ep_desc.bEndpointAddress =
hidg_fs_in_ep_desc.bEndpointAddress;
f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
if (!f->hs_descriptors)
goto fail;
- hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
- f->hs_descriptors,
- &hidg_hs_in_ep_desc);
- } else {
- hidg->hs_in_ep_desc = NULL;
}
mutex_init(&hidg->lock);
diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c
index b37960f..3756326 100644
--- a/drivers/usb/gadget/f_loopback.c
+++ b/drivers/usb/gadget/f_loopback.c
@@ -250,26 +250,27 @@
enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
{
int result = 0;
- const struct usb_endpoint_descriptor *src, *sink;
struct usb_ep *ep;
struct usb_request *req;
unsigned i;
- src = ep_choose(cdev->gadget,
- &hs_loop_source_desc, &fs_loop_source_desc);
- sink = ep_choose(cdev->gadget,
- &hs_loop_sink_desc, &fs_loop_sink_desc);
-
/* one endpoint writes data back IN to the host */
ep = loop->in_ep;
- result = usb_ep_enable(ep, src);
+ result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+ if (result)
+ return result;
+ result = usb_ep_enable(ep);
if (result < 0)
return result;
ep->driver_data = loop;
/* one endpoint just reads OUT packets */
ep = loop->out_ep;
- result = usb_ep_enable(ep, sink);
+ result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+ if (result)
+ goto fail0;
+
+ result = usb_ep_enable(ep);
if (result < 0) {
fail0:
ep = loop->in_ep;
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 55d9a307..3d35c78 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -112,8 +112,7 @@
* is not loaded (an empty string as "filename" in the fsg_config
* structure causes error). The CD-ROM emulation includes a single
* data track and no audio tracks; hence there need be only one
- * backing file per LUN. Note also that the CD-ROM block length is
- * set to 512 rather than the more common value 2048.
+ * backing file per LUN.
*
*
* MSF includes support for module parameters. If gadget using it
@@ -749,7 +748,6 @@
u32 amount_left;
loff_t file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nread;
#ifdef CONFIG_USB_MSC_PROFILING
ktime_t start, diff;
@@ -778,7 +776,7 @@
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- file_offset = ((loff_t) lba) << 9;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Carry out the file reads */
amount_left = common->data_size_from_cmnd;
@@ -791,18 +789,10 @@
* Try to read the remaining amount.
* But don't read more than the buffer size.
* And don't try to read past the end of the file.
- * Finally, if we're not at a page boundary, don't read past
- * the next page.
- * If this means reading 0 then we were asked to read past
- * the end of file.
*/
amount = min(amount_left, FSG_BUFLEN);
amount = min((loff_t)amount,
curlun->file_length - file_offset);
- partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
- partial_page);
/* Wait for the next buffer to become available */
bh = common->next_buffhd_to_fill;
@@ -819,7 +809,8 @@
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
@@ -851,18 +842,25 @@
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int)nread, amount);
- nread -= (nread & 511); /* Round down to a block */
+ nread = round_down(nread, curlun->blksize);
}
file_offset += nread;
amount_left -= nread;
common->residue -= nread;
+
+ /*
+ * Except at the end of the transfer, nread will be
+ * equal to the buffer size, which is divisible by the
+ * bulk-in maxpacket size.
+ */
bh->inreq->length = nread;
bh->state = BUF_STATE_FULL;
/* If an error occurred, report it and its position */
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -893,7 +891,6 @@
u32 amount_left_to_req, amount_left_to_write;
loff_t usb_offset, file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nwritten;
int rc;
@@ -944,7 +941,7 @@
/* Carry out the file writes */
get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << 9;
+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = common->data_size_from_cmnd;
amount_left_to_write = common->data_size_from_cmnd;
@@ -956,41 +953,21 @@
/*
* Figure out how much we want to get:
- * Try to get the remaining amount.
- * But don't get more than the buffer size.
- * And don't try to go past the end of the file.
- * If we're not at a page boundary,
- * don't go past the next page.
- * If this means getting 0, then we were asked
- * to write past the end of file.
- * Finally, round down to a block boundary.
+ * Try to get the remaining amount,
+ * but not more than the buffer size.
*/
amount = min(amount_left_to_req, FSG_BUFLEN);
- amount = min((loff_t)amount,
- curlun->file_length - usb_offset);
- partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount,
- (unsigned int)PAGE_CACHE_SIZE - partial_page);
- if (amount == 0) {
+ /* Beyond the end of the backing file? */
+ if (usb_offset >= curlun->file_length) {
get_some_more = 0;
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = usb_offset >> 9;
+ curlun->sense_data_info =
+ usb_offset >> curlun->blkbits;
curlun->info_valid = 1;
continue;
}
- amount -= amount & 511;
- if (amount == 0) {
-
- /*
- * Why were we were asked to transfer a
- * partial block?
- */
- get_some_more = 0;
- continue;
- }
/* Get the next buffer */
usb_offset += amount;
@@ -1000,12 +977,11 @@
get_some_more = 0;
/*
- * amount is always divisible by 512, hence by
- * the bulk-out maxpacket size
+ * Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
*/
- bh->outreq->length = amount;
- bh->bulk_out_intended_length = amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(common, bh, amount);
if (!start_out_transfer(common, bh))
/* Dunno what to do if common->fsg is NULL */
return -EIO;
@@ -1035,7 +1011,8 @@
/* Did something go wrong with the transfer? */
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1049,6 +1026,16 @@
amount = curlun->file_length - file_offset;
}
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+
+ /* Don't write a partial block */
+ amount = round_down(amount, curlun->blksize);
+ if (amount == 0)
+ goto empty_write;
+
/* Perform the write */
file_offset_tmp = file_offset;
#ifdef CONFIG_USB_MSC_PROFILING
@@ -1075,8 +1062,7 @@
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int)nwritten, amount);
- nwritten -= (nwritten & 511);
- /* Round down to a block */
+ nwritten = round_down(nwritten, curlun->blksize);
}
file_offset += nwritten;
amount_left_to_write -= nwritten;
@@ -1085,7 +1071,8 @@
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
#ifdef CONFIG_USB_CSW_HACK
write_error_after_csw_sent = 1;
@@ -1117,8 +1104,10 @@
}
}
#endif
+
+ empty_write:
/* Did the host decide to stop early? */
- if (bh->outreq->actual != bh->outreq->length) {
+ if (bh->outreq->actual < bh->bulk_out_intended_length) {
common->short_packet_received = 1;
break;
}
@@ -1198,8 +1187,8 @@
return -EIO; /* No default reply */
/* Prepare to carry out the file verify */
- amount_left = verification_length << 9;
- file_offset = ((loff_t) lba) << 9;
+ amount_left = verification_length << curlun->blkbits;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub(curlun);
@@ -1217,8 +1206,6 @@
* Try to read the remaining amount, but not more than
* the buffer size.
* And don't try to read past the end of the file.
- * If this means reading 0 then we were asked to read
- * past the end of file.
*/
amount = min(amount_left, FSG_BUFLEN);
amount = min((loff_t)amount,
@@ -1226,7 +1213,8 @@
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1248,11 +1236,12 @@
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int)nread, amount);
- nread -= nread & 511; /* Round down to a sector */
+ nread = round_down(nread, curlun->blksize);
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info =
+ file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1358,7 +1347,7 @@
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
return 8;
}
@@ -1595,7 +1584,7 @@
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@@ -1675,7 +1664,7 @@
common->next_buffhd_to_drain = bh->next;
/* A short packet or an error ends everything */
- if (bh->outreq->actual != bh->outreq->length ||
+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
bh->outreq->status != 0) {
raise_exception(common,
FSG_STATE_ABORT_BULK_OUT);
@@ -1691,12 +1680,11 @@
amount = min(common->usb_amount_left, FSG_BUFLEN);
/*
- * amount is always divisible by 512, hence by
+ * Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
* the bulk-out maxpacket size.
*/
- bh->outreq->length = amount;
- bh->bulk_out_intended_length = amount;
- bh->outreq->short_not_ok = 1;
+ set_bulk_out_req_length(common, bh, amount);
if (!start_out_transfer(common, bh))
/* Dunno what to do if common->fsg is NULL */
return -EIO;
@@ -2103,7 +2091,8 @@
case READ_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+ common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)");
@@ -2113,7 +2102,8 @@
case READ_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
+ get_unaligned_be16(&common->cmnd[7]) <<
+ common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)");
@@ -2123,7 +2113,8 @@
case READ_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
+ get_unaligned_be32(&common->cmnd[6]) <<
+ common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)");
@@ -2223,7 +2214,8 @@
case WRITE_6:
i = common->cmnd[4];
- common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+ common->curlun->blkbits;
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)");
@@ -2233,7 +2225,8 @@
case WRITE_10:
common->data_size_from_cmnd =
- get_unaligned_be16(&common->cmnd[7]) << 9;
+ get_unaligned_be16(&common->cmnd[7]) <<
+ common->curlun->blkbits;
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)");
@@ -2243,7 +2236,8 @@
case WRITE_12:
common->data_size_from_cmnd =
- get_unaligned_be32(&common->cmnd[6]) << 9;
+ get_unaligned_be32(&common->cmnd[6]) <<
+ common->curlun->blkbits;
reply = check_command(common, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)");
@@ -2378,7 +2372,6 @@
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
- bh->outreq->short_not_ok = 1;
if (!start_out_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
return -EIO;
@@ -2405,18 +2398,6 @@
/*-------------------------------------------------------------------------*/
-static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
- const struct usb_endpoint_descriptor *d)
-{
- int rc;
-
- ep->driver_data = common;
- rc = usb_ep_enable(ep, d);
- if (rc)
- ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
- return rc;
-}
-
static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
struct usb_request **preq)
{
@@ -2466,7 +2447,6 @@
common->fsg = new_fsg;
fsg = common->fsg;
-
/* Allocate the requests */
for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
struct fsg_buffhd *bh = &common->buffhds[i];
@@ -2496,31 +2476,37 @@
{
struct fsg_dev *fsg = fsg_from_func(f);
struct fsg_common *common = fsg->common;
- const struct usb_endpoint_descriptor *d;
int rc;
/* Enable the endpoints */
- d = fsg_ep_desc(common->gadget,
- &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
- rc = enable_endpoint(common, fsg->bulk_in, d);
+ rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
if (rc)
return rc;
+ rc = usb_ep_enable(fsg->bulk_in);
+ if (rc)
+ return rc;
+ fsg->bulk_in->driver_data = common;
fsg->bulk_in_enabled = 1;
- d = fsg_ep_desc(common->gadget,
- &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
- rc = enable_endpoint(common, fsg->bulk_out, d);
- if (rc) {
- usb_ep_disable(fsg->bulk_in);
- fsg->bulk_in_enabled = 0;
- return rc;
- }
+ rc = config_ep_by_speed(common->gadget, &(fsg->function),
+ fsg->bulk_out);
+ if (rc)
+ goto reset_bulk_int;
+ rc = usb_ep_enable(fsg->bulk_out);
+ if (rc)
+ goto reset_bulk_int;
+ fsg->bulk_out->driver_data = common;
fsg->bulk_out_enabled = 1;
- common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+ common->bulk_out_maxpacket = le16_to_cpu(fsg->bulk_in->desc->wMaxPacketSize);
clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
fsg->common->new_fsg = fsg;
raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE);
return USB_GADGET_DELAYED_STATUS;
+
+reset_bulk_int:
+ usb_ep_disable(fsg->bulk_in);
+ fsg->bulk_in_enabled = 0;
+ return rc;
}
static void fsg_disable(struct usb_function *f)
@@ -3087,6 +3073,7 @@
fsg_common_put(common);
usb_free_descriptors(fsg->function.descriptors);
usb_free_descriptors(fsg->function.hs_descriptors);
+ usb_free_descriptors(fsg->function.ss_descriptors);
kfree(fsg);
}
@@ -3137,6 +3124,28 @@
}
}
+ if (gadget_is_superspeed(gadget)) {
+ unsigned max_burst;
+
+ /* Calculate bMaxBurst, we know packet size is 1024 */
+ max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+ fsg_ss_bulk_in_desc.bEndpointAddress =
+ fsg_fs_bulk_in_desc.bEndpointAddress;
+ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+ fsg_ss_bulk_out_desc.bEndpointAddress =
+ fsg_fs_bulk_out_desc.bEndpointAddress;
+ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+
+ f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+ if (unlikely(!f->ss_descriptors)) {
+ usb_free_descriptors(f->hs_descriptors);
+ usb_free_descriptors(f->descriptors);
+ return -ENOMEM;
+ }
+ }
+
return 0;
autoconf_fail:
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 2829231..c85d499 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -410,15 +410,6 @@
ep->driver_data = dev; /* claim the endpoint */
dev->ep_out = ep;
- ep = usb_ep_autoconfig(cdev->gadget, out_desc);
- if (!ep) {
- DBG(cdev, "usb_ep_autoconfig for ep_out failed\n");
- return -ENODEV;
- }
- DBG(cdev, "usb_ep_autoconfig for mtp ep_out got %s\n", ep->name);
- ep->driver_data = dev; /* claim the endpoint */
- dev->ep_out = ep;
-
ep = usb_ep_autoconfig(cdev->gadget, intr_desc);
if (!ep) {
DBG(cdev, "usb_ep_autoconfig for ep_intr failed\n");
@@ -1132,21 +1123,38 @@
int ret;
DBG(cdev, "mtp_function_set_alt intf: %d alt: %d\n", intf, alt);
- ret = usb_ep_enable(dev->ep_in,
- ep_choose(cdev->gadget,
- &mtp_highspeed_in_desc,
- &mtp_fullspeed_in_desc));
- if (ret)
- return ret;
- ret = usb_ep_enable(dev->ep_out,
- ep_choose(cdev->gadget,
- &mtp_highspeed_out_desc,
- &mtp_fullspeed_out_desc));
+
+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
if (ret) {
+ dev->ep_in->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->ep_in->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->ep_in);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ dev->ep_in->name, ret);
+ return ret;
+ }
+
+ ret = config_ep_by_speed(cdev->gadget, f, dev->ep_out);
+ if (ret) {
+ dev->ep_out->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->ep_out->name, ret);
usb_ep_disable(dev->ep_in);
return ret;
}
- ret = usb_ep_enable(dev->ep_intr, &mtp_intr_desc);
+ ret = usb_ep_enable(dev->ep_out);
+ if (ret) {
+ ERROR(cdev, "failed to enable ep %s, result %d\n",
+ dev->ep_out->name, ret);
+ usb_ep_disable(dev->ep_in);
+ return ret;
+ }
+ dev->ep_intr->desc = &mtp_intr_desc;
+ ret = usb_ep_enable(dev->ep_intr);
if (ret) {
usb_ep_disable(dev->ep_out);
usb_ep_disable(dev->ep_in);
diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c
index 86902a6..ae69ed7 100644
--- a/drivers/usb/gadget/f_ncm.c
+++ b/drivers/usb/gadget/f_ncm.c
@@ -48,12 +48,6 @@
#define NCM_NDP_HDR_CRC 0x01000000
#define NCM_NDP_HDR_NOCRC 0x00000000
-struct ncm_ep_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
- struct usb_endpoint_descriptor *notify;
-};
-
enum ncm_notify_state {
NCM_NOTIFY_NONE, /* don't notify */
NCM_NOTIFY_CONNECT, /* issue CONNECT next */
@@ -66,11 +60,7 @@
char ethaddr[14];
- struct ncm_ep_descs fs;
- struct ncm_ep_descs hs;
-
struct usb_ep *notify;
- struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req;
u8 notify_state;
bool is_open;
@@ -802,13 +792,14 @@
if (ncm->notify->driver_data) {
DBG(cdev, "reset ncm control %d\n", intf);
usb_ep_disable(ncm->notify);
- } else {
- DBG(cdev, "init ncm ctrl %d\n", intf);
- ncm->notify_desc = ep_choose(cdev->gadget,
- ncm->hs.notify,
- ncm->fs.notify);
}
- usb_ep_enable(ncm->notify, ncm->notify_desc);
+
+ if (!(ncm->notify->desc)) {
+ DBG(cdev, "init ncm ctrl %d\n", intf);
+ if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
+ goto fail;
+ }
+ usb_ep_enable(ncm->notify);
ncm->notify->driver_data = ncm;
/* Data interface has two altsettings, 0 and 1 */
@@ -829,14 +820,17 @@
if (alt == 1) {
struct net_device *net;
- if (!ncm->port.in) {
+ if (!ncm->port.in_ep->desc ||
+ !ncm->port.out_ep->desc) {
DBG(cdev, "init ncm\n");
- ncm->port.in = ep_choose(cdev->gadget,
- ncm->hs.in,
- ncm->fs.in);
- ncm->port.out = ep_choose(cdev->gadget,
- ncm->hs.out,
- ncm->fs.out);
+ if (config_ep_by_speed(cdev->gadget, f,
+ ncm->port.in_ep) ||
+ config_ep_by_speed(cdev->gadget, f,
+ ncm->port.out_ep)) {
+ ncm->port.in_ep->desc = NULL;
+ ncm->port.out_ep->desc = NULL;
+ goto fail;
+ }
}
/* TODO */
@@ -1111,7 +1105,7 @@
if (ncm->notify->driver_data) {
usb_ep_disable(ncm->notify);
ncm->notify->driver_data = NULL;
- ncm->notify_desc = NULL;
+ ncm->notify->desc = NULL;
}
}
@@ -1228,13 +1222,6 @@
if (!f->descriptors)
goto fail;
- ncm->fs.in = usb_find_endpoint(ncm_fs_function,
- f->descriptors, &fs_ncm_in_desc);
- ncm->fs.out = usb_find_endpoint(ncm_fs_function,
- f->descriptors, &fs_ncm_out_desc);
- ncm->fs.notify = usb_find_endpoint(ncm_fs_function,
- f->descriptors, &fs_ncm_notify_desc);
-
/*
* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
@@ -1252,13 +1239,6 @@
f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
if (!f->hs_descriptors)
goto fail;
-
- ncm->hs.in = usb_find_endpoint(ncm_hs_function,
- f->hs_descriptors, &hs_ncm_in_desc);
- ncm->hs.out = usb_find_endpoint(ncm_hs_function,
- f->hs_descriptors, &hs_ncm_out_desc);
- ncm->hs.notify = usb_find_endpoint(ncm_hs_function,
- f->hs_descriptors, &hs_ncm_notify_desc);
}
/*
@@ -1288,9 +1268,9 @@
/* we might as well release our claims on endpoints */
if (ncm->notify)
ncm->notify->driver_data = NULL;
- if (ncm->port.out)
+ if (ncm->port.out_ep->desc)
ncm->port.out_ep->driver_data = NULL;
- if (ncm->port.in)
+ if (ncm->port.in_ep->desc)
ncm->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c
index 8f8c643..394502a 100644
--- a/drivers/usb/gadget/f_obex.c
+++ b/drivers/usb/gadget/f_obex.c
@@ -39,20 +39,12 @@
* ready to handle the commands.
*/
-struct obex_ep_descs {
- struct usb_endpoint_descriptor *obex_in;
- struct usb_endpoint_descriptor *obex_out;
-};
-
struct f_obex {
struct gserial port;
u8 ctrl_id;
u8 data_id;
u8 port_num;
u8 can_activate;
-
- struct obex_ep_descs fs;
- struct obex_ep_descs hs;
};
static inline struct f_obex *func_to_obex(struct usb_function *f)
@@ -227,12 +219,16 @@
gserial_disconnect(&obex->port);
}
- if (!obex->port.in_desc) {
+ if (!obex->port.in->desc || !obex->port.out->desc) {
DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
- obex->port.in_desc = ep_choose(cdev->gadget,
- obex->hs.obex_in, obex->fs.obex_in);
- obex->port.out_desc = ep_choose(cdev->gadget,
- obex->hs.obex_out, obex->fs.obex_out);
+ if (config_ep_by_speed(cdev->gadget, f,
+ obex->port.in) ||
+ config_ep_by_speed(cdev->gadget, f,
+ obex->port.out)) {
+ obex->port.out->desc = NULL;
+ obex->port.in->desc = NULL;
+ goto fail;
+ }
}
if (alt == 1) {
@@ -346,11 +342,6 @@
/* copy descriptors, and track endpoint copies */
f->descriptors = usb_copy_descriptors(fs_function);
- obex->fs.obex_in = usb_find_endpoint(fs_function,
- f->descriptors, &obex_fs_ep_in_desc);
- obex->fs.obex_out = usb_find_endpoint(fs_function,
- f->descriptors, &obex_fs_ep_out_desc);
-
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
@@ -364,11 +355,6 @@
/* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(hs_function);
-
- obex->hs.obex_in = usb_find_endpoint(hs_function,
- f->hs_descriptors, &obex_hs_ep_in_desc);
- obex->hs.obex_out = usb_find_endpoint(hs_function,
- f->hs_descriptors, &obex_hs_ep_out_desc);
}
/* Avoid letting this gadget enumerate until the userspace
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 5e14950..0d6d260 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -427,17 +427,16 @@
spin_lock(&port->lock);
__pn_reset(f);
if (alt == 1) {
- struct usb_endpoint_descriptor *out, *in;
int i;
- out = ep_choose(gadget,
- &pn_hs_sink_desc,
- &pn_fs_sink_desc);
- in = ep_choose(gadget,
- &pn_hs_source_desc,
- &pn_fs_source_desc);
- usb_ep_enable(fp->out_ep, out);
- usb_ep_enable(fp->in_ep, in);
+ if (config_ep_by_speed(gadget, f, fp->in_ep) ||
+ config_ep_by_speed(gadget, f, fp->out_ep)) {
+ fp->in_ep->desc = NULL;
+ fp->out_ep->desc = NULL;
+ return -EINVAL;
+ }
+ usb_ep_enable(fp->out_ep);
+ usb_ep_enable(fp->in_ep);
port->usb = fp;
fp->out_ep->driver_data = fp;
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index d846c4e..cc26c85 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -25,11 +25,6 @@
#define RMNET_NOTIFY_INTERVAL 5
#define RMNET_MAX_NOTIFY_SIZE sizeof(struct usb_cdc_notification)
-struct rmnet_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
- struct usb_endpoint_descriptor *notify;
-};
#define ACM_CTRL_DTR (1 << 0)
@@ -46,13 +41,8 @@
spinlock_t lock;
- /* usb descriptors */
- struct rmnet_descs fs;
- struct rmnet_descs hs;
-
/* usb eps*/
struct usb_ep *notify;
- struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req;
/* control info */
@@ -481,10 +471,16 @@
pr_debug("%s: reset port:%d\n", __func__, dev->port_num);
usb_ep_disable(dev->notify);
}
- dev->notify_desc = ep_choose(cdev->gadget,
- dev->hs.notify,
- dev->fs.notify);
- ret = usb_ep_enable(dev->notify, dev->notify_desc);
+
+ ret = config_ep_by_speed(cdev->gadget, f, dev->notify);
+ if (ret) {
+ dev->notify->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->notify->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->notify);
+
if (ret) {
pr_err("%s: usb ep#%s enable failed, err#%d\n",
__func__, dev->notify->name, ret);
@@ -497,10 +493,12 @@
gport_rmnet_disconnect(dev);
}
- dev->port.in_desc = ep_choose(cdev->gadget,
- dev->hs.in, dev->fs.in);
- dev->port.out_desc = ep_choose(cdev->gadget,
- dev->hs.out, dev->fs.out);
+ if (config_ep_by_speed(cdev->gadget, f, dev->port.in) ||
+ config_ep_by_speed(cdev->gadget, f, dev->port.out)) {
+ dev->port.in->desc = NULL;
+ dev->port.out->desc = NULL;
+ return -EINVAL;
+ }
ret = gport_rmnet_connect(dev);
@@ -854,16 +852,6 @@
if (!f->descriptors)
goto fail;
- dev->fs.in = usb_find_endpoint(rmnet_fs_function,
- f->descriptors,
- &rmnet_fs_in_desc);
- dev->fs.out = usb_find_endpoint(rmnet_fs_function,
- f->descriptors,
- &rmnet_fs_out_desc);
- dev->fs.notify = usb_find_endpoint(rmnet_fs_function,
- f->descriptors,
- &rmnet_fs_notify_desc);
-
if (gadget_is_dualspeed(cdev->gadget)) {
rmnet_hs_in_desc.bEndpointAddress =
rmnet_fs_in_desc.bEndpointAddress;
@@ -877,13 +865,6 @@
if (!f->hs_descriptors)
goto fail;
-
- dev->hs.in = usb_find_endpoint(rmnet_hs_function,
- f->hs_descriptors, &rmnet_hs_in_desc);
- dev->hs.out = usb_find_endpoint(rmnet_hs_function,
- f->hs_descriptors, &rmnet_hs_out_desc);
- dev->hs.notify = usb_find_endpoint(rmnet_hs_function,
- f->hs_descriptors, &rmnet_hs_notify_desc);
}
pr_info("%s: RmNet(%d) %s Speed, IN:%s OUT:%s\n",
diff --git a/drivers/usb/gadget/f_rmnet_sdio.c b/drivers/usb/gadget/f_rmnet_sdio.c
index f63d939..8019356 100644
--- a/drivers/usb/gadget/f_rmnet_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_sdio.c
@@ -1255,17 +1255,58 @@
struct usb_composite_dev *cdev = dev->cdev;
int ret = 0;
+ /* Enable epin */
dev->epin->driver_data = dev;
- usb_ep_enable(dev->epin, ep_choose(cdev->gadget,
- &rmnet_sdio_hs_in_desc,
- &rmnet_sdio_fs_in_desc));
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epin);
+ if (ret) {
+ dev->epin->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->epin->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epin);
+ if (ret) {
+ ERROR(cdev, "can't enable %s, result %d\n",
+ dev->epin->name, ret);
+ return ret;
+ }
+
+ /* Enable epout */
dev->epout->driver_data = dev;
- usb_ep_enable(dev->epout, ep_choose(cdev->gadget,
- &rmnet_sdio_hs_out_desc,
- &rmnet_sdio_fs_out_desc));
- usb_ep_enable(dev->epnotify, ep_choose(cdev->gadget,
- &rmnet_sdio_hs_notify_desc,
- &rmnet_sdio_fs_notify_desc));
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epout);
+ if (ret) {
+ dev->epout->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->epout->name, ret);
+ usb_ep_disable(dev->epin);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epout);
+ if (ret) {
+ ERROR(cdev, "can't enable %s, result %d\n",
+ dev->epout->name, ret);
+ usb_ep_disable(dev->epin);
+ return ret;
+ }
+
+ /* Enable epnotify */
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epnotify);
+ if (ret) {
+ dev->epnotify->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->epnotify->name, ret);
+ usb_ep_disable(dev->epin);
+ usb_ep_disable(dev->epout);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epnotify);
+ if (ret) {
+ ERROR(cdev, "can't enable %s, result %d\n",
+ dev->epnotify->name, ret);
+ usb_ep_disable(dev->epin);
+ usb_ep_disable(dev->epout);
+ return ret;
+ }
/* allocate notification */
dev->notify_req = rmnet_sdio_alloc_req(dev->epnotify,
diff --git a/drivers/usb/gadget/f_rmnet_smd.c b/drivers/usb/gadget/f_rmnet_smd.c
index 2049dc0..b71f646 100644
--- a/drivers/usb/gadget/f_rmnet_smd.c
+++ b/drivers/usb/gadget/f_rmnet_smd.c
@@ -956,17 +956,32 @@
struct usb_composite_dev *cdev = dev->cdev;
int ret = 0;
- ret = usb_ep_enable(dev->epin, ep_choose(cdev->gadget,
- &rmnet_smd_hs_in_desc,
- &rmnet_smd_fs_in_desc));
+ /* Enable epin endpoint */
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epin);
+ if (ret) {
+ dev->epin->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n",
+ dev->epin->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epin);
if (ret) {
ERROR(cdev, "can't enable %s, result %d\n",
dev->epin->name, ret);
return ret;
}
- ret = usb_ep_enable(dev->epout, ep_choose(cdev->gadget,
- &rmnet_smd_hs_out_desc,
- &rmnet_smd_fs_out_desc));
+
+ /* Enable epout endpoint */
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epout);
+ if (ret) {
+ dev->epout->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n",
+ dev->epout->name, ret);
+ usb_ep_disable(dev->epin);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epout);
+
if (ret) {
ERROR(cdev, "can't enable %s, result %d\n",
dev->epout->name, ret);
@@ -974,9 +989,17 @@
return ret;
}
- ret = usb_ep_enable(dev->epnotify, ep_choose(cdev->gadget,
- &rmnet_smd_hs_notify_desc,
- &rmnet_smd_fs_notify_desc));
+ /* Enable epnotify endpoint */
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epnotify);
+ if (ret) {
+ dev->epnotify->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failed for ep %s, result %d\n",
+ dev->epnotify->name, ret);
+ usb_ep_disable(dev->epin);
+ usb_ep_disable(dev->epout);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epnotify);
if (ret) {
ERROR(cdev, "can't enable %s, result %d\n",
dev->epnotify->name, ret);
diff --git a/drivers/usb/gadget/f_rmnet_smd_sdio.c b/drivers/usb/gadget/f_rmnet_smd_sdio.c
index e39125d..175afe3 100644
--- a/drivers/usb/gadget/f_rmnet_smd_sdio.c
+++ b/drivers/usb/gadget/f_rmnet_smd_sdio.c
@@ -1354,6 +1354,7 @@
function);
struct rmnet_mux_sdio_dev *sdio_dev = &dev->sdio_dev;
struct usb_composite_dev *cdev = dev->cdev;
+ int ret = 0;
/* allocate notification */
dev->notify_req = rmnet_mux_alloc_req(dev->epnotify,
@@ -1365,18 +1366,59 @@
dev->notify_req->complete = rmnet_mux_notify_complete;
dev->notify_req->context = dev;
dev->notify_req->length = RMNET_MUX_SDIO_MAX_NFY_SZE;
- usb_ep_enable(dev->epnotify, ep_choose(cdev->gadget,
- &rmnet_mux_hs_notify_desc,
- &rmnet_mux_fs_notify_desc));
+ /* Enable epin */
dev->epin->driver_data = dev;
- usb_ep_enable(dev->epin, ep_choose(cdev->gadget,
- &rmnet_mux_hs_in_desc,
- &rmnet_mux_fs_in_desc));
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epin);
+ if (ret) {
+ dev->epin->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->epin->name, ret);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epin);
+ if (ret) {
+ ERROR(cdev, "can't enable %s, result %d\n",
+ dev->epin->name, ret);
+ return ret;
+ }
+
+ /* Enable epout */
dev->epout->driver_data = dev;
- usb_ep_enable(dev->epout, ep_choose(cdev->gadget,
- &rmnet_mux_hs_out_desc,
- &rmnet_mux_fs_out_desc));
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epout);
+ if (ret) {
+ dev->epout->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->epout->name, ret);
+ usb_ep_disable(dev->epin);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epout);
+ if (ret) {
+ ERROR(cdev, "can't enable %s, result %d\n",
+ dev->epout->name, ret);
+ usb_ep_disable(dev->epin);
+ return ret;
+ }
+
+ /* Enable epnotify */
+ ret = config_ep_by_speed(cdev->gadget, f, dev->epnotify);
+ if (ret) {
+ dev->epnotify->desc = NULL;
+ ERROR(cdev, "config_ep_by_speed failes for ep %s, result %d\n",
+ dev->epnotify->name, ret);
+ usb_ep_disable(dev->epin);
+ usb_ep_disable(dev->epout);
+ return ret;
+ }
+ ret = usb_ep_enable(dev->epnotify);
+ if (ret) {
+ ERROR(cdev, "can't enable %s, result %d\n",
+ dev->epnotify->name, ret);
+ usb_ep_disable(dev->epin);
+ usb_ep_disable(dev->epout);
+ return ret;
+ }
dev->dpkts_tolaptop = 0;
dev->cpkts_tolaptop = 0;
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index d03b11b..4a74dcf 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -76,12 +76,6 @@
* - MS-Windows drivers sometimes emit undocumented requests.
*/
-struct rndis_ep_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
- struct usb_endpoint_descriptor *notify;
-};
-
struct f_rndis {
struct gether port;
u8 ctrl_id, data_id;
@@ -90,12 +84,7 @@
const char *manufacturer;
int config;
-
- struct rndis_ep_descs fs;
- struct rndis_ep_descs hs;
-
struct usb_ep *notify;
- struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req;
atomic_t notify_count;
};
@@ -486,13 +475,13 @@
if (rndis->notify->driver_data) {
VDBG(cdev, "reset rndis control %d\n", intf);
usb_ep_disable(rndis->notify);
- } else {
- VDBG(cdev, "init rndis ctrl %d\n", intf);
}
- rndis->notify_desc = ep_choose(cdev->gadget,
- rndis->hs.notify,
- rndis->fs.notify);
- usb_ep_enable(rndis->notify, rndis->notify_desc);
+ if (!rndis->notify->desc) {
+ VDBG(cdev, "init rndis ctrl %d\n", intf);
+ if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+ goto fail;
+ }
+ usb_ep_enable(rndis->notify);
rndis->notify->driver_data = rndis;
} else if (intf == rndis->data_id) {
@@ -503,13 +492,17 @@
gether_disconnect(&rndis->port);
}
- if (!rndis->port.in) {
+ if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
DBG(cdev, "init rndis\n");
+ if (config_ep_by_speed(cdev->gadget, f,
+ rndis->port.in_ep) ||
+ config_ep_by_speed(cdev->gadget, f,
+ rndis->port.out_ep)) {
+ rndis->port.in_ep->desc = NULL;
+ rndis->port.out_ep->desc = NULL;
+ goto fail;
+ }
}
- rndis->port.in = ep_choose(cdev->gadget,
- rndis->hs.in, rndis->fs.in);
- rndis->port.out = ep_choose(cdev->gadget,
- rndis->hs.out, rndis->fs.out);
/* Avoid ZLPs; they can be troublesome. */
rndis->port.is_zlp_ok = false;
@@ -664,13 +657,6 @@
if (!f->descriptors)
goto fail;
- rndis->fs.in = usb_find_endpoint(eth_fs_function,
- f->descriptors, &fs_in_desc);
- rndis->fs.out = usb_find_endpoint(eth_fs_function,
- f->descriptors, &fs_out_desc);
- rndis->fs.notify = usb_find_endpoint(eth_fs_function,
- f->descriptors, &fs_notify_desc);
-
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
@@ -688,13 +674,6 @@
if (!f->hs_descriptors)
goto fail;
-
- rndis->hs.in = usb_find_endpoint(eth_hs_function,
- f->hs_descriptors, &hs_in_desc);
- rndis->hs.out = usb_find_endpoint(eth_hs_function,
- f->hs_descriptors, &hs_out_desc);
- rndis->hs.notify = usb_find_endpoint(eth_hs_function,
- f->hs_descriptors, &hs_notify_desc);
}
rndis->port.open = rndis_open;
@@ -737,9 +716,9 @@
/* we might as well release our claims on endpoints */
if (rndis->notify)
rndis->notify->driver_data = NULL;
- if (rndis->port.out)
+ if (rndis->port.out_ep->desc)
rndis->port.out_ep->driver_data = NULL;
- if (rndis->port.in)
+ if (rndis->port.in_ep->desc)
rndis->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index de8c8ed..8d9f090 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -29,21 +29,12 @@
*/
#define GSERIAL_NO_PORTS 2
-struct gser_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
-#ifdef CONFIG_MODEM_SUPPORT
- struct usb_endpoint_descriptor *notify;
-#endif
-};
struct f_gser {
struct gserial port;
u8 data_id;
u8 port_num;
- struct gser_descs fs;
- struct gser_descs hs;
u8 online;
enum transport_type transport;
@@ -51,7 +42,6 @@
u8 pending;
spinlock_t lock;
struct usb_ep *notify;
- struct usb_endpoint_descriptor *notify_desc;
struct usb_request *notify_req;
struct usb_cdc_line_coding port_line_coding;
@@ -478,10 +468,15 @@
DBG(cdev, "reset generic ctl ttyGS%d\n", gser->port_num);
usb_ep_disable(gser->notify);
}
- gser->notify_desc = ep_choose(cdev->gadget,
- gser->hs.notify,
- gser->fs.notify);
- rc = usb_ep_enable(gser->notify, gser->notify_desc);
+
+ if (!gser->notify->desc) {
+ if (config_ep_by_speed(cdev->gadget, f, gser->notify)) {
+ gser->notify->desc = NULL;
+ return -EINVAL;
+ }
+ }
+ rc = usb_ep_enable(gser->notify);
+
if (rc) {
ERROR(cdev, "can't enable %s, result %d\n",
gser->notify->name, rc);
@@ -493,13 +488,16 @@
if (gser->port.in->driver_data) {
DBG(cdev, "reset generic data ttyGS%d\n", gser->port_num);
gport_disconnect(gser);
- } else {
- DBG(cdev, "activate generic data ttyGS%d\n", gser->port_num);
}
- gser->port.in_desc = ep_choose(cdev->gadget,
- gser->hs.in, gser->fs.in);
- gser->port.out_desc = ep_choose(cdev->gadget,
- gser->hs.out, gser->fs.out);
+ if (!gser->port.in->desc || !gser->port.out->desc) {
+ DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
+ if (config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
+ config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
+ gser->port.in->desc = NULL;
+ gser->port.out->desc = NULL;
+ return -EINVAL;
+ }
+ }
gport_connect(gser);
@@ -744,16 +742,6 @@
if (!f->descriptors)
goto fail;
- gser->fs.in = usb_find_endpoint(gser_fs_function,
- f->descriptors, &gser_fs_in_desc);
- gser->fs.out = usb_find_endpoint(gser_fs_function,
- f->descriptors, &gser_fs_out_desc);
-#ifdef CONFIG_MODEM_SUPPORT
- gser->fs.notify = usb_find_endpoint(gser_fs_function,
- f->descriptors, &gser_fs_notify_desc);
-#endif
-
-
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
@@ -774,14 +762,6 @@
if (!f->hs_descriptors)
goto fail;
- gser->hs.in = usb_find_endpoint(gser_hs_function,
- f->hs_descriptors, &gser_hs_in_desc);
- gser->hs.out = usb_find_endpoint(gser_hs_function,
- f->hs_descriptors, &gser_hs_out_desc);
-#ifdef CONFIG_MODEM_SUPPORT
- gser->hs.notify = usb_find_endpoint(gser_hs_function,
- f->hs_descriptors, &gser_hs_notify_desc);
-#endif
}
DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c
index e403a53..caf2f95 100644
--- a/drivers/usb/gadget/f_sourcesink.c
+++ b/drivers/usb/gadget/f_sourcesink.c
@@ -343,15 +343,14 @@
enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
{
int result = 0;
- const struct usb_endpoint_descriptor *src, *sink;
struct usb_ep *ep;
- src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
- sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
-
/* one endpoint writes (sources) zeroes IN (to the host) */
ep = ss->in_ep;
- result = usb_ep_enable(ep, src);
+ result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+ if (result)
+ return result;
+ result = usb_ep_enable(ep);
if (result < 0)
return result;
ep->driver_data = ss;
@@ -367,7 +366,10 @@
/* one endpoint reads (sinks) anything OUT (from the host) */
ep = ss->out_ep;
- result = usb_ep_enable(ep, sink);
+ result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+ if (result)
+ goto fail;
+ result = usb_ep_enable(ep);
if (result < 0)
goto fail;
ep->driver_data = ss;
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index 8675ca4..93bf676 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -57,18 +57,10 @@
* caring about specific product and vendor IDs.
*/
-struct geth_descs {
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
-};
-
struct f_gether {
struct gether port;
char ethaddr[14];
-
- struct geth_descs fs;
- struct geth_descs hs;
};
static inline struct f_gether *func_to_geth(struct usb_function *f)
@@ -243,10 +235,12 @@
}
DBG(cdev, "init + activate cdc subset\n");
- geth->port.in = ep_choose(cdev->gadget,
- geth->hs.in, geth->fs.in);
- geth->port.out = ep_choose(cdev->gadget,
- geth->hs.out, geth->fs.out);
+ if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
+ config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
+ geth->port.in_ep->desc = NULL;
+ geth->port.out_ep->desc = NULL;
+ return -EINVAL;
+ }
net = gether_connect(&geth->port);
return IS_ERR(net) ? PTR_ERR(net) : 0;
@@ -297,12 +291,6 @@
/* copy descriptors, and track endpoint copies */
f->descriptors = usb_copy_descriptors(fs_eth_function);
- geth->fs.in = usb_find_endpoint(fs_eth_function,
- f->descriptors, &fs_subset_in_desc);
- geth->fs.out = usb_find_endpoint(fs_eth_function,
- f->descriptors, &fs_subset_out_desc);
-
-
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
@@ -315,11 +303,6 @@
/* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
-
- geth->hs.in = usb_find_endpoint(hs_eth_function,
- f->hs_descriptors, &hs_subset_in_desc);
- geth->hs.out = usb_find_endpoint(hs_eth_function,
- f->hs_descriptors, &hs_subset_out_desc);
}
/* NOTE: all that is done without knowing or caring about
@@ -334,9 +317,9 @@
fail:
/* we might as well release our claims on endpoints */
- if (geth->port.out)
+ if (geth->port.out_ep->desc)
geth->port.out_ep->driver_data = NULL;
- if (geth->port.in)
+ if (geth->port.in_ep->desc)
geth->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
diff --git a/drivers/usb/gadget/f_uvc.c b/drivers/usb/gadget/f_uvc.c
index be446b7..df74d03 100644
--- a/drivers/usb/gadget/f_uvc.c
+++ b/drivers/usb/gadget/f_uvc.c
@@ -262,8 +262,10 @@
if (uvc->state != UVC_STATE_CONNECTED)
return 0;
- if (uvc->video.ep)
- usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
+ if (uvc->video.ep) {
+ uvc->video.ep->desc = &uvc_streaming_ep;
+ usb_ep_enable(uvc->video.ep);
+ }
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_STREAMON;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 0360f56..b17ecd8 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -69,8 +69,7 @@
* each LUN would be settable independently as a disk drive or a CD-ROM
* drive, but currently all LUNs have to be the same type. The CD-ROM
* emulation includes a single data track and no audio tracks; hence there
- * need be only one backing file per LUN. Note also that the CD-ROM block
- * length is set to 512 rather than the more common value 2048.
+ * need be only one backing file per LUN.
*
* Requirements are modest; only a bulk-in and a bulk-out endpoint are
* needed (an interrupt-out endpoint is also needed for CBI). The memory
@@ -533,6 +532,18 @@
/*-------------------------------------------------------------------------*/
+/* Maxpacket and other transfer characteristics vary by speed. */
+static struct usb_endpoint_descriptor *
+fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+ struct usb_endpoint_descriptor *hs)
+{
+ if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ return hs;
+ return fs;
+}
+
+/*-------------------------------------------------------------------------*/
+
/*
* DESCRIPTORS ... most are static, but strings and (full) configuration
* descriptors are built on demand. Also the (static) config and interface
@@ -586,7 +597,19 @@
.bNumConfigurations = 1,
};
+static int populate_bos(struct fsg_dev *fsg, u8 *buf)
+{
+ memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
+ buf += USB_DT_BOS_SIZE;
+ memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
+ buf += USB_DT_USB_EXT_CAP_SIZE;
+
+ memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
+
+ return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
+ + USB_DT_USB_EXT_CAP_SIZE;
+}
/*
* Config descriptors must agree with the code that sets configurations
@@ -929,20 +952,28 @@
case USB_DT_DEVICE:
VDBG(fsg, "get device descriptor\n");
+ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
value = sizeof device_desc;
memcpy(req->buf, &device_desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
VDBG(fsg, "get device qualifier\n");
- if (!gadget_is_dualspeed(fsg->gadget))
+ if (!gadget_is_dualspeed(fsg->gadget) ||
+ fsg->gadget->speed == USB_SPEED_SUPER)
break;
+ /*
+ * Assume ep0 uses the same maxpacket value for both
+ * speeds
+ */
+ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
value = sizeof dev_qualifier;
memcpy(req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
VDBG(fsg, "get other-speed config descriptor\n");
- if (!gadget_is_dualspeed(fsg->gadget))
+ if (!gadget_is_dualspeed(fsg->gadget) ||
+ fsg->gadget->speed == USB_SPEED_SUPER)
break;
goto get_config;
case USB_DT_CONFIG:
@@ -961,7 +992,15 @@
value = usb_gadget_get_string(&fsg_stringtab,
w_value & 0xff, req->buf);
break;
+
+ case USB_DT_BOS:
+ VDBG(fsg, "get bos descriptor\n");
+
+ if (gadget_is_superspeed(fsg->gadget))
+ value = populate_bos(fsg, req->buf);
+ break;
}
+
break;
/* One config, two speeds */
@@ -1130,7 +1169,6 @@
u32 amount_left;
loff_t file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nread;
/* Get the starting Logical Block Address and check that it's
@@ -1152,7 +1190,7 @@
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
}
- file_offset = ((loff_t) lba) << 9;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Carry out the file reads */
amount_left = fsg->data_size_from_cmnd;
@@ -1165,17 +1203,10 @@
* Try to read the remaining amount.
* But don't read more than the buffer size.
* And don't try to read past the end of the file.
- * Finally, if we're not at a page boundary, don't read past
- * the next page.
- * If this means reading 0 then we were asked to read past
- * the end of file. */
+ */
amount = min((unsigned int) amount_left, mod_data.buflen);
amount = min((loff_t) amount,
curlun->file_length - file_offset);
- partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
- partial_page);
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
@@ -1190,7 +1221,7 @@
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
@@ -1215,18 +1246,23 @@
} else if (nread < amount) {
LDBG(curlun, "partial file read: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); // Round down to a block
+ nread = round_down(nread, curlun->blksize);
}
file_offset += nread;
amount_left -= nread;
fsg->residue -= nread;
+
+ /* Except at the end of the transfer, nread will be
+ * equal to the buffer size, which is divisible by the
+ * bulk-in maxpacket size.
+ */
bh->inreq->length = nread;
bh->state = BUF_STATE_FULL;
/* If an error occurred, report it and its position */
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1256,7 +1292,6 @@
u32 amount_left_to_req, amount_left_to_write;
loff_t usb_offset, file_offset, file_offset_tmp;
unsigned int amount;
- unsigned int partial_page;
ssize_t nwritten;
int rc;
@@ -1297,7 +1332,7 @@
/* Carry out the file writes */
get_some_more = 1;
- file_offset = usb_offset = ((loff_t) lba) << 9;
+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
while (amount_left_to_write > 0) {
@@ -1307,38 +1342,20 @@
if (bh->state == BUF_STATE_EMPTY && get_some_more) {
/* Figure out how much we want to get:
- * Try to get the remaining amount.
- * But don't get more than the buffer size.
- * And don't try to go past the end of the file.
- * If we're not at a page boundary,
- * don't go past the next page.
- * If this means getting 0, then we were asked
- * to write past the end of file.
- * Finally, round down to a block boundary. */
+ * Try to get the remaining amount,
+ * but not more than the buffer size.
+ */
amount = min(amount_left_to_req, mod_data.buflen);
- amount = min((loff_t) amount, curlun->file_length -
- usb_offset);
- partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
- if (partial_page > 0)
- amount = min(amount,
- (unsigned int) PAGE_CACHE_SIZE - partial_page);
- if (amount == 0) {
+ /* Beyond the end of the backing file? */
+ if (usb_offset >= curlun->file_length) {
get_some_more = 0;
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = usb_offset >> 9;
+ curlun->sense_data_info = usb_offset >> curlun->blkbits;
curlun->info_valid = 1;
continue;
}
- amount -= (amount & 511);
- if (amount == 0) {
-
- /* Why were we were asked to transfer a
- * partial block? */
- get_some_more = 0;
- continue;
- }
/* Get the next buffer */
usb_offset += amount;
@@ -1347,11 +1364,11 @@
if (amount_left_to_req == 0)
get_some_more = 0;
- /* amount is always divisible by 512, hence by
- * the bulk-out maxpacket size */
- bh->outreq->length = bh->bulk_out_intended_length =
- amount;
- bh->outreq->short_not_ok = 1;
+ /* Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
+ */
+ set_bulk_out_req_length(fsg, bh, amount);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
fsg->next_buffhd_to_fill = bh->next;
@@ -1370,7 +1387,7 @@
/* Did something go wrong with the transfer? */
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1384,6 +1401,16 @@
amount = curlun->file_length - file_offset;
}
+ /* Don't accept excess data. The spec doesn't say
+ * what to do in this case. We'll ignore the error.
+ */
+ amount = min(amount, bh->bulk_out_intended_length);
+
+ /* Don't write a partial block */
+ amount = round_down(amount, curlun->blksize);
+ if (amount == 0)
+ goto empty_write;
+
/* Perform the write */
file_offset_tmp = file_offset;
nwritten = vfs_write(curlun->filp,
@@ -1402,8 +1429,7 @@
} else if (nwritten < amount) {
LDBG(curlun, "partial file write: %d/%u\n",
(int) nwritten, amount);
- nwritten -= (nwritten & 511);
- // Round down to a block
+ nwritten = round_down(nwritten, curlun->blksize);
}
file_offset += nwritten;
amount_left_to_write -= nwritten;
@@ -1412,13 +1438,14 @@
/* If an error occurred, report it and its position */
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
+ empty_write:
/* Did the host decide to stop early? */
- if (bh->outreq->actual != bh->outreq->length) {
+ if (bh->outreq->actual < bh->bulk_out_intended_length) {
fsg->short_packet_received = 1;
break;
}
@@ -1494,8 +1521,8 @@
return -EIO; // No default reply
/* Prepare to carry out the file verify */
- amount_left = verification_length << 9;
- file_offset = ((loff_t) lba) << 9;
+ amount_left = verification_length << curlun->blkbits;
+ file_offset = ((loff_t) lba) << curlun->blkbits;
/* Write out all the dirty buffers before invalidating them */
fsg_lun_fsync_sub(curlun);
@@ -1513,15 +1540,14 @@
* Try to read the remaining amount, but not more than
* the buffer size.
* And don't try to read past the end of the file.
- * If this means reading 0 then we were asked to read
- * past the end of file. */
+ */
amount = min((unsigned int) amount_left, mod_data.buflen);
amount = min((loff_t) amount,
curlun->file_length - file_offset);
if (amount == 0) {
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1544,11 +1570,11 @@
} else if (nread < amount) {
LDBG(curlun, "partial file verify: %d/%u\n",
(int) nread, amount);
- nread -= (nread & 511); // Round down to a sector
+ nread = round_down(nread, curlun->blksize);
}
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
- curlun->sense_data_info = file_offset >> 9;
+ curlun->sense_data_info = file_offset >> curlun->blkbits;
curlun->info_valid = 1;
break;
}
@@ -1662,7 +1688,7 @@
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
return 8;
}
@@ -1884,7 +1910,7 @@
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
- put_unaligned_be32(512, &buf[4]); /* Block length */
+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@@ -1963,7 +1989,7 @@
fsg->next_buffhd_to_drain = bh->next;
/* A short packet or an error ends everything */
- if (bh->outreq->actual != bh->outreq->length ||
+ if (bh->outreq->actual < bh->bulk_out_intended_length ||
bh->outreq->status != 0) {
raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
return -EINTR;
@@ -1977,11 +2003,11 @@
amount = min(fsg->usb_amount_left,
(u32) mod_data.buflen);
- /* amount is always divisible by 512, hence by
- * the bulk-out maxpacket size */
- bh->outreq->length = bh->bulk_out_intended_length =
- amount;
- bh->outreq->short_not_ok = 1;
+ /* Except at the end of the transfer, amount will be
+ * equal to the buffer size, which is divisible by
+ * the bulk-out maxpacket size.
+ */
+ set_bulk_out_req_length(fsg, bh, amount);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
fsg->next_buffhd_to_fill = bh->next;
@@ -2409,7 +2435,7 @@
case READ_6:
i = fsg->cmnd[4];
- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
(7<<1) | (1<<4), 1,
"READ(6)")) == 0)
@@ -2418,7 +2444,7 @@
case READ_10:
fsg->data_size_from_cmnd =
- get_unaligned_be16(&fsg->cmnd[7]) << 9;
+ get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)")) == 0)
@@ -2427,7 +2453,7 @@
case READ_12:
fsg->data_size_from_cmnd =
- get_unaligned_be32(&fsg->cmnd[6]) << 9;
+ get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)")) == 0)
@@ -2513,7 +2539,7 @@
case WRITE_6:
i = fsg->cmnd[4];
- fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+ fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
(7<<1) | (1<<4), 1,
"WRITE(6)")) == 0)
@@ -2522,7 +2548,7 @@
case WRITE_10:
fsg->data_size_from_cmnd =
- get_unaligned_be16(&fsg->cmnd[7]) << 9;
+ get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)")) == 0)
@@ -2531,7 +2557,7 @@
case WRITE_12:
fsg->data_size_from_cmnd =
- get_unaligned_be32(&fsg->cmnd[6]) << 9;
+ get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)")) == 0)
@@ -2660,7 +2686,6 @@
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
- bh->outreq->short_not_ok = 1;
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
@@ -2713,7 +2738,8 @@
int rc;
ep->driver_data = fsg;
- rc = usb_ep_enable(ep, d);
+ ep->desc = d;
+ rc = usb_ep_enable(ep);
if (rc)
ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
return rc;
@@ -2784,13 +2810,15 @@
/* Enable the endpoints */
d = fsg_ep_desc(fsg->gadget,
- &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
+ &fsg_ss_bulk_in_desc);
if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
goto reset;
fsg->bulk_in_enabled = 1;
d = fsg_ep_desc(fsg->gadget,
- &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
+ &fsg_ss_bulk_out_desc);
if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
goto reset;
fsg->bulk_out_enabled = 1;
@@ -2799,7 +2827,8 @@
if (transport_is_cbi()) {
d = fsg_ep_desc(fsg->gadget,
- &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc);
+ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
+ &fsg_ss_intr_in_desc);
if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
goto reset;
fsg->intr_in_enabled = 1;
@@ -3416,7 +3445,6 @@
}
/* Fix up the descriptors */
- device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
device_desc.idVendor = cpu_to_le16(mod_data.vendor);
device_desc.idProduct = cpu_to_le16(mod_data.product);
device_desc.bcdDevice = cpu_to_le16(mod_data.release);
@@ -3430,9 +3458,6 @@
if (gadget_is_dualspeed(gadget)) {
fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
- /* Assume ep0 uses the same maxpacket value for both speeds */
- dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
-
/* Assume endpoint addresses are the same for both speeds */
fsg_hs_bulk_in_desc.bEndpointAddress =
fsg_fs_bulk_in_desc.bEndpointAddress;
@@ -3442,6 +3467,24 @@
fsg_fs_intr_in_desc.bEndpointAddress;
}
+ if (gadget_is_superspeed(gadget)) {
+ unsigned max_burst;
+
+ fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+
+ /* Calculate bMaxBurst, we know packet size is 1024 */
+ max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
+
+ /* Assume endpoint addresses are the same for both speeds */
+ fsg_ss_bulk_in_desc.bEndpointAddress =
+ fsg_fs_bulk_in_desc.bEndpointAddress;
+ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+ fsg_ss_bulk_out_desc.bEndpointAddress =
+ fsg_fs_bulk_out_desc.bEndpointAddress;
+ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+ }
+
if (gadget_is_otg(gadget))
fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
@@ -3556,11 +3599,7 @@
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver fsg_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- .speed = USB_SPEED_HIGH,
-#else
- .speed = USB_SPEED_FULL,
-#endif
+ .speed = USB_SPEED_SUPER,
.function = (char *) fsg_string_product,
.unbind = fsg_unbind,
.disconnect = fsg_disconnect,
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 3a68e09..3bf872e 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -1927,6 +1927,10 @@
return -ENOTSUPP;
}
+static int fsl_qe_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int fsl_qe_stop(struct usb_gadget_driver *driver);
+
/* defined in usb_gadget.h */
static struct usb_gadget_ops qe_gadget_ops = {
.get_frame = qe_get_frame,
@@ -1935,6 +1939,8 @@
.vbus_session = qe_vbus_session,
.vbus_draw = qe_vbus_draw,
.pullup = qe_pullup,
+ .start = fsl_qe_start,
+ .stop = fsl_qe_stop,
};
/*-------------------------------------------------------------------------
@@ -2320,7 +2326,7 @@
/*-------------------------------------------------------------------------
Gadget driver probe and unregister.
--------------------------------------------------------------------------*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fsl_qe_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
int retval;
@@ -2369,9 +2375,8 @@
udc_controller->gadget.name, driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fsl_qe_stop(struct usb_gadget_driver *driver)
{
struct qe_ep *loop_ep;
unsigned long flags;
@@ -2411,7 +2416,6 @@
driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/* udc structure's alloc and setup, include ep-param alloc */
static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev)
@@ -2662,11 +2666,17 @@
if (ret)
goto err6;
+ ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget);
+ if (ret)
+ goto err7;
+
dev_info(udc_controller->dev,
"%s USB controller initialized as device\n",
(udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
return 0;
+err7:
+ device_unregister(&udc_controller->gadget.dev);
err6:
free_irq(udc_controller->usb_irq, udc_controller);
err5:
@@ -2721,6 +2731,8 @@
if (!udc_controller)
return -ENODEV;
+ usb_del_gadget_udc(&udc_controller->gadget);
+
udc_controller->done = &done;
tasklet_disable(&udc_controller->rx_tasklet);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 4e48331..4763cc3 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1244,6 +1244,9 @@
return 0;
}
+static int fsl_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int fsl_stop(struct usb_gadget_driver *driver);
/* defined in gadget.h */
static struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
@@ -1252,6 +1255,8 @@
.vbus_session = fsl_vbus_session,
.vbus_draw = fsl_vbus_draw,
.pullup = fsl_pullup,
+ .start = fsl_start,
+ .stop = fsl_stop,
};
/* Set protocol stall on ep0, protocol stall will automatically be cleared
@@ -1927,7 +1932,7 @@
* Hook to gadget drivers
* Called by initialization code of gadget drivers
*----------------------------------------------------------------*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fsl_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
int retval = -ENODEV;
@@ -1995,10 +2000,9 @@
retval);
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
/* Disconnect from gadget driver */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fsl_stop(struct usb_gadget_driver *driver)
{
struct fsl_ep *loop_ep;
unsigned long flags;
@@ -2041,7 +2045,6 @@
driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/*-------------------------------------------------------------------------
PROC File System Support
@@ -2590,9 +2593,16 @@
ret = -ENOMEM;
goto err_unregister;
}
+
+ ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
+ if (ret)
+ goto err_del_udc;
+
create_proc_file();
return 0;
+err_del_udc:
+ dma_pool_destroy(udc_controller->td_pool);
err_unregister:
device_unregister(&udc_controller->gadget.dev);
err_free_irq:
@@ -2624,6 +2634,8 @@
if (!udc_controller)
return -ENODEV;
+
+ usb_del_gadget_udc(&udc_controller->gadget);
udc_controller->done = &done;
fsl_udc_clk_release();
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 763d462..9cf53c6 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -1500,7 +1500,7 @@
/*------------------------------------------------------------------------*/
static struct fusb300 *the_controller;
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fusb300_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct fusb300 *fusb300 = the_controller;
@@ -1544,9 +1544,8 @@
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fusb300_udc_stop(struct usb_gadget_driver *driver)
{
struct fusb300 *fusb300 = the_controller;
@@ -1562,7 +1561,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/*--------------------------------------------------------------------------*/
static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
@@ -1572,12 +1570,15 @@
static struct usb_gadget_ops fusb300_gadget_ops = {
.pullup = fusb300_udc_pullup,
+ .start = fusb300_udc_start,
+ .stop = fusb300_udc_stop,
};
static int __exit fusb300_remove(struct platform_device *pdev)
{
struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev);
+ usb_del_gadget_udc(&fusb300->gadget);
iounmap(fusb300->reg);
free_irq(platform_get_irq(pdev, 0), fusb300);
@@ -1702,9 +1703,15 @@
goto clean_up3;
init_controller(fusb300);
+ ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
+ if (ret)
+ goto err_add_udc;
+
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0;
+err_add_udc:
+ fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
clean_up3:
free_irq(ires->start, fusb300);
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index ebf6970..704c280 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -162,6 +162,7 @@
.name = DRIVER_NAME,
.dev = &gfs_dev_desc,
.strings = gfs_dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = gfs_unbind,
.iProduct = DRIVER_DESC,
};
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index da312d4..7a9d57d 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -120,6 +120,12 @@
#define gadget_is_ci13xxx_pci(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_DWC3
+#define gadget_is_dwc3(g) (!strcmp("dwc3-gadget", (g)->name))
+#else
+#define gadget_is_dwc3(g) 0
+#endif
+
#ifdef CONFIG_USB_GADGET_MSM_72K
#define gadget_is_msm72k(g) !strcmp("msm72k_udc", (g)->name)
#else
@@ -240,6 +246,8 @@
return 0x31;
else if (gadget_is_ci13xxx_msm_hsic(gadget))
return 0x32;
+ else if (gadget_is_dwc3(gadget))
+ return 0x33;
return -ENOENT;
}
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 47b86b9..8b9220e 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -537,14 +537,16 @@
struct usb_ep *ep;
unsigned i;
- err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
+ dev->in_ep->desc = &bulk_in_desc;
+ err = usb_ep_enable(dev->in_ep);
if (err) {
ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
goto fail;
}
dev->in_ep->driver_data = dev;
- err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
+ dev->out_ep->desc = &bulk_out_desc;
+ err = usb_ep_enable(dev->out_ep);
if (err) {
ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
goto fail;
@@ -693,6 +695,7 @@
switch (w_value >> 8) {
case USB_DT_DEVICE:
+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
value = min(w_length, (u16) sizeof(device_desc));
memcpy(req->buf, &device_desc, value);
break;
@@ -1247,8 +1250,6 @@
dev->req->complete = gmidi_setup_complete;
- device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-
gadget->ep0->driver_data = dev;
INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index bf6e11c..7f87805 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -996,8 +996,14 @@
return -EOPNOTSUPP;
}
+static int goku_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int goku_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops goku_ops = {
.get_frame = goku_get_frame,
+ .start = goku_start,
+ .stop = goku_stop,
// no remote wakeup
// not selfpowered
};
@@ -1344,7 +1350,7 @@
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int goku_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct goku_udc *dev = the_controller;
@@ -1382,7 +1388,6 @@
DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
static void
stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
@@ -1408,7 +1413,7 @@
udc_enable(dev);
}
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int goku_stop(struct usb_gadget_driver *driver)
{
struct goku_udc *dev = the_controller;
unsigned long flags;
@@ -1429,8 +1434,6 @@
DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
/*-------------------------------------------------------------------------*/
@@ -1730,6 +1733,8 @@
DBG(dev, "%s\n", __func__);
+ usb_del_gadget_udc(&dev->gadget);
+
BUG_ON(dev->driver);
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -1854,6 +1859,10 @@
goto err;
}
dev->registered = 1;
+ retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ if (retval)
+ goto err;
+
return 0;
err:
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index 2523e54..9fb5750 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -255,6 +255,7 @@
.name = "g_hid",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(hid_unbind),
};
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index ade4006..692fd9b 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1237,9 +1237,14 @@
*******************************************************************************
*/
+static int imx_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int imx_udc_stop(struct usb_gadget_driver *driver);
static const struct usb_gadget_ops imx_udc_ops = {
.get_frame = imx_udc_get_frame,
.wakeup = imx_udc_wakeup,
+ .start = imx_udc_start,
+ .stop = imx_udc_stop,
};
static struct imx_udc_struct controller = {
@@ -1324,7 +1329,7 @@
* USB gadget driver functions
*******************************************************************************
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int imx_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct imx_udc_struct *imx_usb = &controller;
@@ -1368,9 +1373,8 @@
imx_usb->gadget.dev.driver = NULL;
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int imx_udc_stop(struct usb_gadget_driver *driver)
{
struct imx_udc_struct *imx_usb = &controller;
@@ -1394,7 +1398,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/*******************************************************************************
* Module functions
@@ -1504,8 +1507,14 @@
imx_usb->timer.function = handle_config;
imx_usb->timer.data = (unsigned long)imx_usb;
- return 0;
+ ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
+ if (ret)
+ goto fail4;
+ return 0;
+fail4:
+ for (i = 0; i < IMX_USB_NB_EP + 1; i++)
+ free_irq(imx_usb->usbd_int[i], imx_usb);
fail3:
clk_put(clk);
clk_disable(clk);
@@ -1525,6 +1534,7 @@
struct imxusb_platform_data *pdata = pdev->dev.platform_data;
int i;
+ usb_del_gadget_udc(&imx_usb->gadget);
imx_udc_disable(imx_usb);
del_timer(&imx_usb->timer);
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index a56876a..1b24099 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -832,14 +832,16 @@
switch (data->dev->gadget->speed) {
case USB_SPEED_LOW:
case USB_SPEED_FULL:
- value = usb_ep_enable (ep, &data->desc);
+ ep->desc = &data->desc;
+ value = usb_ep_enable(ep);
if (value == 0)
data->state = STATE_EP_ENABLED;
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_SPEED_HIGH:
/* fails if caller didn't provide that descriptor... */
- value = usb_ep_enable (ep, &data->hs_desc);
+ ep->desc = &data->hs_desc;
+ value = usb_ep_enable(ep);
if (value == 0)
data->state = STATE_EP_ENABLED;
break;
@@ -1345,7 +1347,7 @@
qual.bDeviceProtocol = desc->bDeviceProtocol;
/* assumes ep0 uses the same value for both speeds ... */
- qual.bMaxPacketSize0 = desc->bMaxPacketSize0;
+ qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
qual.bNumConfigurations = 1;
qual.bRESERVED = 0;
@@ -1402,7 +1404,6 @@
}
dev->state = STATE_DEV_CONNECTED;
- dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
INFO (dev, "connected\n");
event = next_event (dev, GADGETFS_CONNECT);
@@ -1430,6 +1431,7 @@
case USB_DT_DEVICE:
value = min (w_length, (u16) sizeof *dev->dev);
+ dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
req->buf = dev->dev;
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -1710,7 +1712,6 @@
set_gadget_data (gadget, dev);
dev->gadget = gadget;
gadget->ep0->driver_data = dev;
- dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
/* preallocate control response and buffer */
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index 9cee88a..d8403ae 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -1321,7 +1321,9 @@
return 0;
}
-
+static int langwell_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int langwell_stop(struct usb_gadget_driver *driver);
/* device controller usb_gadget_ops structure */
static const struct usb_gadget_ops langwell_ops = {
@@ -1342,6 +1344,9 @@
/* D+ pullup, software-controlled connect/disconnect to USB host */
.pullup = langwell_pullup,
+
+ .start = langwell_start,
+ .stop = langwell_stop,
};
@@ -1852,7 +1857,7 @@
* the driver might get unbound.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int langwell_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct langwell_udc *dev = the_controller;
@@ -1914,11 +1919,9 @@
dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-
/* unregister gadget driver */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int langwell_stop(struct usb_gadget_driver *driver)
{
struct langwell_udc *dev = the_controller;
unsigned long flags;
@@ -1965,8 +1968,6 @@
dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
/*-------------------------------------------------------------------------*/
@@ -3373,6 +3374,10 @@
if (retval)
goto error;
+ retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ if (retval)
+ goto error;
+
retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
if (retval)
goto error;
@@ -3403,6 +3408,7 @@
dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
+ usb_del_gadget_udc(&dev->gadget);
/* disable interrupt and set controller to stop state */
langwell_udc_stop(dev);
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 084aa08..11d3782 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1454,7 +1454,7 @@
/*-------------------------------------------------------------------------*/
static struct m66592 *the_controller;
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int m66592_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct m66592 *m66592 = the_controller;
@@ -1506,9 +1506,8 @@
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int m66592_stop(struct usb_gadget_driver *driver)
{
struct m66592 *m66592 = the_controller;
unsigned long flags;
@@ -1533,7 +1532,6 @@
m66592->driver = NULL;
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/*-------------------------------------------------------------------------*/
static int m66592_get_frame(struct usb_gadget *_gadget)
@@ -1544,12 +1542,16 @@
static struct usb_gadget_ops m66592_gadget_ops = {
.get_frame = m66592_get_frame,
+ .start = m66592_start,
+ .stop = m66592_stop,
};
static int __exit m66592_remove(struct platform_device *pdev)
{
struct m66592 *m66592 = dev_get_drvdata(&pdev->dev);
+ usb_del_gadget_udc(&m66592->gadget);
+
del_timer_sync(&m66592->timer);
iounmap(m66592->reg);
free_irq(platform_get_irq(pdev, 0), m66592);
@@ -1691,9 +1693,16 @@
init_controller(m66592);
+ ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
+ if (ret)
+ goto err_add_udc;
+
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0;
+err_add_udc:
+ m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+
clean_up3:
#ifdef CONFIG_HAVE_CLK
if (m66592->pdata->on_chip) {
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index 0182242..1b2d135 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -169,6 +169,7 @@
.name = "g_mass_storage",
.dev = &msg_device_desc,
.iProduct = DRIVER_DESC,
+ .max_speed = USB_SPEED_SUPER,
.needs_serial = 1,
};
diff --git a/drivers/usb/gadget/msm72k_udc.c b/drivers/usb/gadget/msm72k_udc.c
index ea62262..28e217b 100644
--- a/drivers/usb/gadget/msm72k_udc.c
+++ b/drivers/usb/gadget/msm72k_udc.c
@@ -1453,7 +1453,10 @@
static int usb_free(struct usb_info *ui, int ret)
{
- dev_dbg(&ui->pdev->dev, "usb_free(%d)\n", ret);
+ if (ret)
+ dev_dbg(&ui->pdev->dev, "usb_free(%d)\n", ret);
+
+ usb_del_gadget_udc(&ui->gadget);
if (ui->xceiv)
otg_put_transceiver(ui->xceiv);
@@ -2385,6 +2388,11 @@
}
+static int msm72k_gadget_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int msm72k_gadget_stop(struct usb_gadget_driver *driver);
+
+
static const struct usb_gadget_ops msm72k_ops = {
.get_frame = msm72k_get_frame,
.vbus_session = msm72k_udc_vbus_session,
@@ -2392,6 +2400,8 @@
.pullup = msm72k_pullup,
.wakeup = msm72k_wakeup,
.set_selfpowered = msm72k_set_selfpowered,
+ .start = msm72k_gadget_start,
+ .stop = msm72k_gadget_stop
};
static void usb_do_remote_wakeup(struct work_struct *w)
@@ -2585,6 +2595,10 @@
ui->gadget.is_otg = 1;
#endif
+ retval = usb_add_gadget_udc(&pdev->dev, &ui->gadget);
+ if (retval)
+ return usb_free(ui, retval);
+
ui->sdev.name = DRIVER_NAME;
ui->sdev.print_name = print_switch_name;
ui->sdev.print_state = print_switch_state;
@@ -2629,7 +2643,7 @@
return 0;
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int msm72k_gadget_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct usb_info *ui = the_usb_info;
@@ -2715,9 +2729,8 @@
ui->gadget.dev.driver = NULL;
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int msm72k_gadget_stop(struct usb_gadget_driver *driver)
{
struct usb_info *dev = the_usb_info;
@@ -2754,7 +2767,6 @@
"unregistered gadget driver '%s'\n", driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
static int msm72k_udc_runtime_suspend(struct device *dev)
@@ -2781,8 +2793,16 @@
.runtime_idle = msm72k_udc_runtime_idle
};
+static int __exit msm72k_remove(struct platform_device *pdev)
+{
+ struct usb_info *ui = container_of(&pdev, struct usb_info, pdev);
+
+ return usb_free(ui, 0);
+}
+
static struct platform_driver usb_driver = {
.probe = msm72k_probe,
+ .remove = msm72k_remove,
.driver = { .name = "msm_hsusb",
.pm = &msm72k_udc_dev_pm_ops, },
};
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index d9feced..8c7b747 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -351,6 +351,7 @@
.name = "g_multi",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(multi_unbind),
.iProduct = DRIVER_DESC,
.needs_serial = 1,
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index b1a8146..6adf38c 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -1128,6 +1128,9 @@
return 0;
}
+static int mv_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int mv_udc_stop(struct usb_gadget_driver *driver);
/* device controller usb_gadget_ops structure */
static const struct usb_gadget_ops mv_ops = {
@@ -1139,6 +1142,8 @@
/* D+ pullup, software-controlled connect/disconnect to USB host */
.pullup = mv_udc_pullup,
+ .start = mv_udc_start,
+ .stop = mv_udc_stop,
};
static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter)
@@ -1230,7 +1235,7 @@
}
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int mv_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct mv_udc *udc = the_controller;
@@ -1270,9 +1275,8 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int mv_udc_stop(struct usb_gadget_driver *driver)
{
struct mv_udc *udc = the_controller;
unsigned long flags;
@@ -1296,7 +1300,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
static int
udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
@@ -1880,9 +1883,10 @@
static int mv_udc_remove(struct platform_device *dev)
{
struct mv_udc *udc = the_controller;
-
DECLARE_COMPLETION(done);
+ usb_del_gadget_udc(&udc->gadget);
+
udc->done = &done;
/* free memory allocated in probe */
@@ -2074,11 +2078,12 @@
the_controller = udc;
- goto out;
+ retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
+ if (!retval)
+ return retval;
error:
if (udc)
mv_udc_remove(udc->dev);
-out:
return retval;
}
diff --git a/drivers/usb/gadget/ncm.c b/drivers/usb/gadget/ncm.c
index 99c179a..62ee508 100644
--- a/drivers/usb/gadget/ncm.c
+++ b/drivers/usb/gadget/ncm.c
@@ -228,6 +228,7 @@
.name = "g_ncm",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(gncm_unbind),
};
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 476d88e..1e6ea6f 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1410,11 +1410,17 @@
return 0;
}
+static int net2280_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int net2280_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops net2280_ops = {
.get_frame = net2280_get_frame,
.wakeup = net2280_wakeup,
.set_selfpowered = net2280_set_selfpowered,
.pullup = net2280_pullup,
+ .start = net2280_start,
+ .stop = net2280_stop,
};
/*-------------------------------------------------------------------------*/
@@ -1930,7 +1936,7 @@
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int net2280_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct net2280 *dev = the_controller;
@@ -1994,7 +2000,6 @@
dev->driver = NULL;
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
static void
stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
@@ -2022,7 +2027,7 @@
usb_reinit (dev);
}
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int net2280_stop(struct usb_gadget_driver *driver)
{
struct net2280 *dev = the_controller;
unsigned long flags;
@@ -2049,8 +2054,6 @@
DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
return 0;
}
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
-
/*-------------------------------------------------------------------------*/
@@ -2732,6 +2735,8 @@
{
struct net2280 *dev = pci_get_drvdata (pdev);
+ usb_del_gadget_udc(&dev->gadget);
+
BUG_ON(dev->driver);
/* then clean up the resources we allocated during probe() */
@@ -2916,6 +2921,9 @@
retval = device_create_file (&pdev->dev, &dev_attr_registers);
if (retval) goto done;
+ retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ if (retval)
+ goto done;
return 0;
done:
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
index 55ca63ad3..c7fb772 100644
--- a/drivers/usb/gadget/nokia.c
+++ b/drivers/usb/gadget/nokia.c
@@ -241,6 +241,7 @@
.name = "g_nokia",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = __exit_p(nokia_unbind),
};
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 82fd249..740c7da 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -1375,6 +1375,10 @@
return 0;
}
+static int omap_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int omap_udc_stop(struct usb_gadget_driver *driver);
+
static struct usb_gadget_ops omap_gadget_ops = {
.get_frame = omap_get_frame,
.wakeup = omap_wakeup,
@@ -1382,6 +1386,8 @@
.vbus_session = omap_vbus_session,
.vbus_draw = omap_vbus_draw,
.pullup = omap_pullup,
+ .start = omap_udc_start,
+ .stop = omap_udc_stop,
};
/*-------------------------------------------------------------------------*/
@@ -2102,7 +2108,7 @@
);
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int omap_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
int status = -ENODEV;
@@ -2186,9 +2192,8 @@
omap_udc_enable_clock(0);
return status;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int omap_udc_stop(struct usb_gadget_driver *driver)
{
unsigned long flags;
int status = -ENODEV;
@@ -2222,8 +2227,6 @@
DBG("unregistered driver '%s'\n", driver->driver.name);
return status;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
/*-------------------------------------------------------------------------*/
@@ -2991,9 +2994,16 @@
create_proc_file();
status = device_add(&udc->gadget.dev);
+ if (status)
+ goto cleanup4;
+
+ status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
if (!status)
return status;
/* If fail, fall through */
+cleanup4:
+ remove_proc_file();
+
#ifdef USE_ISO
cleanup3:
free_irq(pdev->resource[2].start, udc);
@@ -3029,6 +3039,8 @@
if (!udc)
return -ENODEV;
+
+ usb_del_gadget_udc(&udc->gadget);
if (udc->driver)
return -EBUSY;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 68dbcc3..f96615a 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -1176,6 +1176,9 @@
return -EOPNOTSUPP;
}
+static int pch_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int pch_udc_stop(struct usb_gadget_driver *driver);
static const struct usb_gadget_ops pch_udc_ops = {
.get_frame = pch_udc_pcd_get_frame,
.wakeup = pch_udc_pcd_wakeup,
@@ -1183,6 +1186,8 @@
.pullup = pch_udc_pcd_pullup,
.vbus_session = pch_udc_pcd_vbus_session,
.vbus_draw = pch_udc_pcd_vbus_draw,
+ .start = pch_udc_start,
+ .stop = pch_udc_stop,
};
/**
@@ -2690,7 +2695,7 @@
return 0;
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pch_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct pch_udc_dev *dev = pch_udc;
@@ -2733,9 +2738,8 @@
dev->connected = 1;
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pch_udc_stop(struct usb_gadget_driver *driver)
{
struct pch_udc_dev *dev = pch_udc;
@@ -2761,7 +2765,6 @@
pch_udc_set_disconnect(dev);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
static void pch_udc_shutdown(struct pci_dev *pdev)
{
@@ -2778,6 +2781,8 @@
{
struct pch_udc_dev *dev = pci_get_drvdata(pdev);
+ usb_del_gadget_udc(&dev->gadget);
+
/* gadget driver must not be registered */
if (dev->driver)
dev_err(&pdev->dev,
@@ -2953,6 +2958,9 @@
/* Put the device in disconnected state till a driver is bound */
pch_udc_set_disconnect(dev);
+ retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ if (retval)
+ goto finished;
return 0;
finished:
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 271ef94..d5df8dd 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -89,8 +89,7 @@
u8 config;
s8 interface;
struct usb_ep *in_ep, *out_ep;
- const struct usb_endpoint_descriptor
- *in, *out;
+
struct list_head rx_reqs; /* List of free RX structs */
struct list_head rx_reqs_active; /* List of Active RX xfers */
struct list_head rx_buffers; /* List of completed xfers */
@@ -895,19 +894,20 @@
{
int result = 0;
- dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+ dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
dev->in_ep->driver_data = dev;
- dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
+ dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
+ &fs_ep_out_desc);
dev->out_ep->driver_data = dev;
- result = usb_ep_enable(dev->in_ep, dev->in);
+ result = usb_ep_enable(dev->in_ep);
if (result != 0) {
DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
goto done;
}
- result = usb_ep_enable(dev->out_ep, dev->out);
+ result = usb_ep_enable(dev->out_ep);
if (result != 0) {
DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
goto done;
@@ -918,8 +918,8 @@
if (result != 0) {
(void) usb_ep_disable(dev->in_ep);
(void) usb_ep_disable(dev->out_ep);
- dev->in = NULL;
- dev->out = NULL;
+ dev->in_ep->desc = NULL;
+ dev->out_ep->desc = NULL;
}
/* caller is responsible for cleanup on error */
@@ -933,12 +933,14 @@
DBG(dev, "%s\n", __func__);
- if (dev->in)
+ if (dev->in_ep->desc)
usb_ep_disable(dev->in_ep);
- if (dev->out)
+ if (dev->out_ep->desc)
usb_ep_disable(dev->out_ep);
+ dev->in_ep->desc = NULL;
+ dev->out_ep->desc = NULL;
dev->interface = -1;
}
@@ -1104,9 +1106,9 @@
list_add(&req->list, &dev->tx_reqs);
}
- if (usb_ep_enable(dev->in_ep, dev->in))
+ if (usb_ep_enable(dev->in_ep))
DBG(dev, "Failed to enable USB in_ep\n");
- if (usb_ep_enable(dev->out_ep, dev->out))
+ if (usb_ep_enable(dev->out_ep))
DBG(dev, "Failed to enable USB out_ep\n");
wake_up_interruptible(&dev->rx_wait);
@@ -1146,6 +1148,8 @@
switch (wValue >> 8) {
case USB_DT_DEVICE:
+ device_desc.bMaxPacketSize0 =
+ gadget->ep0->maxpacket;
value = min(wLength, (u16) sizeof device_desc);
memcpy(req->buf, &device_desc, value);
break;
@@ -1153,6 +1157,12 @@
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
break;
+ /*
+ * assumes ep0 uses the same value for both
+ * speeds
+ */
+ dev_qualifier.bMaxPacketSize0 =
+ gadget->ep0->maxpacket;
value = min(wLength,
(u16) sizeof dev_qualifier);
memcpy(req->buf, &dev_qualifier, value);
@@ -1448,15 +1458,11 @@
out_ep->driver_data = out_ep; /* claim */
#ifdef CONFIG_USB_GADGET_DUALSPEED
- /* assumes ep0 uses the same value for both speeds ... */
- dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
-
- /* and that all endpoints are dual-speed */
+ /* assumes that all endpoints are dual-speed */
hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
#endif /* DUALSPEED */
- device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
usb_gadget_set_selfpowered(gadget);
if (gadget->is_otg) {
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 7745454..e4e59b4 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -1011,12 +1011,18 @@
return -EOPNOTSUPP;
}
+static int pxa25x_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int pxa25x_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops pxa25x_udc_ops = {
.get_frame = pxa25x_udc_get_frame,
.wakeup = pxa25x_udc_wakeup,
.vbus_session = pxa25x_udc_vbus_session,
.pullup = pxa25x_udc_pullup,
.vbus_draw = pxa25x_udc_vbus_draw,
+ .start = pxa25x_start,
+ .stop = pxa25x_stop,
};
/*-------------------------------------------------------------------------*/
@@ -1263,7 +1269,7 @@
* disconnect is reported. then a host may connect again, or
* the driver might get unbound.
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pxa25x_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct pxa25x_udc *dev = the_controller;
@@ -1322,7 +1328,6 @@
bind_fail:
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
static void
stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
@@ -1351,7 +1356,7 @@
udc_reinit(dev);
}
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pxa25x_stop(struct usb_gadget_driver *driver)
{
struct pxa25x_udc *dev = the_controller;
@@ -1379,8 +1384,6 @@
dump_state(dev);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
/*-------------------------------------------------------------------------*/
@@ -2231,8 +2234,11 @@
#endif
create_debug_files(dev);
- return 0;
+ retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+ if (!retval)
+ return retval;
+ remove_debug_files(dev);
#ifdef CONFIG_ARCH_LUBBOCK
lubbock_fail0:
free_irq(LUBBOCK_USB_DISC_IRQ, dev);
@@ -2261,6 +2267,7 @@
{
struct pxa25x_udc *dev = platform_get_drvdata(pdev);
+ usb_del_gadget_udc(&dev->gadget);
if (dev->driver)
return -EBUSY;
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 5760769..85b68c7 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1680,12 +1680,18 @@
return -EOPNOTSUPP;
}
+static int pxa27x_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int pxa27x_udc_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops pxa_udc_ops = {
.get_frame = pxa_udc_get_frame,
.wakeup = pxa_udc_wakeup,
.pullup = pxa_udc_pullup,
.vbus_session = pxa_udc_vbus_session,
.vbus_draw = pxa_udc_vbus_draw,
+ .start = pxa27x_udc_start,
+ .stop = pxa27x_udc_stop,
};
/**
@@ -1791,7 +1797,7 @@
}
/**
- * usb_gadget_probe_driver - Register gadget driver
+ * pxa27x_start - Register gadget driver
* @driver: gadget driver
* @bind: bind function
*
@@ -1805,7 +1811,7 @@
*
* Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pxa27x_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct pxa_udc *udc = the_controller;
@@ -1860,8 +1866,6 @@
udc->gadget.dev.driver = NULL;
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-
/**
* stop_activity - Stops udc endpoints
@@ -1888,12 +1892,12 @@
}
/**
- * usb_gadget_unregister_driver - Unregister the gadget driver
+ * pxa27x_udc_stop - Unregister the gadget driver
* @driver: gadget driver
*
* Returns 0 if no error, -ENODEV, -EINVAL otherwise
*/
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
{
struct pxa_udc *udc = the_controller;
@@ -1917,7 +1921,6 @@
return otg_set_peripheral(udc->transceiver, NULL);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/**
* handle_ep0_ctrl_req - handle control endpoint control request
@@ -2516,9 +2519,14 @@
driver_name, IRQ_USB, retval);
goto err_irq;
}
+ retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ if (retval)
+ goto err_add_udc;
pxa_init_debugfs(udc);
return 0;
+err_add_udc:
+ free_irq(udc->irq, udc);
err_irq:
iounmap(udc->regs);
err_map:
@@ -2537,6 +2545,7 @@
struct pxa_udc *udc = platform_get_drvdata(_dev);
int gpio = udc->mach->gpio_pullup;
+ usb_del_gadget_udc(&udc->gadget);
usb_gadget_unregister_driver(udc->driver);
free_irq(udc->irq, udc);
pxa_cleanup_debugfs(udc);
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index 6dcc1f6..51b655f 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1410,7 +1410,7 @@
/*-------------------------------------------------------------------------*/
static struct r8a66597 *the_controller;
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int r8a66597_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct r8a66597 *r8a66597 = the_controller;
@@ -1462,9 +1462,8 @@
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int r8a66597_stop(struct usb_gadget_driver *driver)
{
struct r8a66597 *r8a66597 = the_controller;
unsigned long flags;
@@ -1488,7 +1487,6 @@
r8a66597->driver = NULL;
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/*-------------------------------------------------------------------------*/
static int r8a66597_get_frame(struct usb_gadget *_gadget)
@@ -1499,12 +1497,15 @@
static struct usb_gadget_ops r8a66597_gadget_ops = {
.get_frame = r8a66597_get_frame,
+ .start = r8a66597_start,
+ .stop = r8a66597_stop,
};
static int __exit r8a66597_remove(struct platform_device *pdev)
{
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
+ usb_del_gadget_udc(&r8a66597->gadget);
del_timer_sync(&r8a66597->timer);
iounmap(r8a66597->reg);
free_irq(platform_get_irq(pdev, 0), r8a66597);
@@ -1647,9 +1648,15 @@
init_controller(r8a66597);
+ ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget);
+ if (ret)
+ goto err_add_udc;
+
dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
return 0;
+err_add_udc:
+ r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
clean_up3:
free_irq(irq, r8a66597);
clean_up2:
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 0dfee28..8bdee67c 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -2574,7 +2574,7 @@
return 0;
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c_hsotg_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct s3c_hsotg *hsotg = our_hsotg;
@@ -2745,9 +2745,8 @@
hsotg->gadget.dev.driver = NULL;
return ret;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
{
struct s3c_hsotg *hsotg = our_hsotg;
int ep;
@@ -2775,7 +2774,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
{
@@ -2784,6 +2782,8 @@
static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
.get_frame = s3c_hsotg_gadget_getframe,
+ .start = s3c_hsotg_start,
+ .stop = s3c_hsotg_stop,
};
/**
@@ -3403,6 +3403,10 @@
for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
+ ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
+ if (ret)
+ goto err_add_udc;
+
s3c_hsotg_create_debug(hsotg);
s3c_hsotg_dump(hsotg);
@@ -3410,6 +3414,11 @@
our_hsotg = hsotg;
return 0;
+err_add_udc:
+ s3c_hsotg_gate(pdev, false);
+ clk_disable(hsotg->clk);
+ clk_put(hsotg->clk);
+
err_regs:
iounmap(hsotg->regs);
@@ -3427,6 +3436,8 @@
{
struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
+ usb_del_gadget_udc(&hsotg->gadget);
+
s3c_hsotg_delete_debug(hsotg);
usb_gadget_unregister_driver(hsotg->driver);
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index d5e3e1e..dc9f428 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -1133,7 +1133,7 @@
return IRQ_HANDLED;
}
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c_hsudc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct s3c_hsudc *hsudc = the_controller;
@@ -1181,9 +1181,8 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
{
struct s3c_hsudc *hsudc = the_controller;
unsigned long flags;
@@ -1210,7 +1209,6 @@
driver->driver.name);
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc)
{
@@ -1224,6 +1222,8 @@
static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
.get_frame = s3c_hsudc_gadget_getframe,
+ .start = s3c_hsudc_start,
+ .stop = s3c_hsudc_stop,
};
static int s3c_hsudc_probe(struct platform_device *pdev)
@@ -1311,7 +1311,15 @@
disable_irq(hsudc->irq);
local_irq_enable();
+
+ ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
+ if (ret)
+ goto err_add_udc;
+
return 0;
+err_add_udc:
+ clk_disable(hsudc->uclk);
+ clk_put(hsudc->uclk);
err_clk:
free_irq(hsudc->irq, hsudc);
err_irq:
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 100f263..1c19cd3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1552,6 +1552,10 @@
return -ENOTSUPP;
}
+static int s3c2410_udc_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int s3c2410_udc_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops s3c2410_ops = {
.get_frame = s3c2410_udc_get_frame,
.wakeup = s3c2410_udc_wakeup,
@@ -1559,6 +1563,8 @@
.pullup = s3c2410_udc_pullup,
.vbus_session = s3c2410_udc_vbus_session,
.vbus_draw = s3c2410_vbus_draw,
+ .start = s3c2410_udc_start,
+ .stop = s3c2410_udc_stop,
};
static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
@@ -1672,10 +1678,7 @@
s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
}
-/*
- * usb_gadget_probe_driver
- */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c2410_udc_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct s3c2410_udc *udc = the_controller;
@@ -1730,12 +1733,8 @@
udc->gadget.dev.driver = NULL;
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-/*
- * usb_gadget_unregister_driver
- */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c2410_udc_stop(struct usb_gadget_driver *driver)
{
struct s3c2410_udc *udc = the_controller;
@@ -1955,6 +1954,10 @@
goto err_vbus_irq;
}
+ retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+ if (retval)
+ goto err_add_udc;
+
if (s3c2410_udc_debugfs_root) {
udc->regs_info = debugfs_create_file("registers", S_IRUGO,
s3c2410_udc_debugfs_root,
@@ -1967,6 +1970,10 @@
return 0;
+err_add_udc:
+ if (udc_info && !udc_info->udc_command &&
+ gpio_is_valid(udc_info->pullup_pin))
+ gpio_free(udc_info->pullup_pin);
err_vbus_irq:
if (udc_info && udc_info->vbus_pin > 0)
free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
@@ -1992,6 +1999,8 @@
unsigned int irq;
dev_dbg(&pdev->dev, "%s()\n", __func__);
+
+ usb_del_gadget_udc(&udc->gadget);
if (udc->driver)
return -EBUSY;
@@ -2105,8 +2114,6 @@
debugfs_remove(s3c2410_udc_debugfs_root);
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
module_init(udc_init);
module_exit(udc_exit);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 1ac57a9..ed1b816 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -242,6 +242,7 @@
.name = "g_serial",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
};
static int __init init(void)
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 1505967..43a54f1 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -247,6 +247,8 @@
u32 sense_data_info;
u32 unit_attention_data;
+ unsigned int blkbits; /* Bits of logical block size of bound block device */
+ unsigned int blksize; /* logical block size of bound block device */
struct device dev;
#ifdef CONFIG_USB_MSC_PROFILING
spinlock_t lock;
@@ -509,12 +511,128 @@
NULL,
};
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {
+ .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /*.bMaxBurst = DYNAMIC, */
+};
+
+static struct usb_endpoint_descriptor
+fsg_ss_bulk_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {
+ .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ /*.bMaxBurst = DYNAMIC, */
+};
+
+#ifndef FSG_NO_INTR_EP
+
+static struct usb_endpoint_descriptor
+fsg_ss_intr_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = cpu_to_le16(2),
+ .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */
+};
+
+static struct usb_ss_ep_comp_descriptor fsg_ss_intr_in_comp_desc = {
+ .bLength = sizeof(fsg_ss_bulk_in_comp_desc),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+
+ .wBytesPerInterval = cpu_to_le16(2),
+};
+
+#ifndef FSG_NO_OTG
+# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 2
+#else
+# define FSG_SS_FUNCTION_PRE_EP_ENTRIES 1
+#endif
+
+#endif
+
+static __maybe_unused struct usb_ext_cap_descriptor fsg_ext_cap_desc = {
+ .bLength = USB_DT_USB_EXT_CAP_SIZE,
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_CAP_TYPE_EXT,
+
+ .bmAttributes = cpu_to_le32(USB_LPM_SUPPORT),
+};
+
+static __maybe_unused struct usb_ss_cap_descriptor fsg_ss_cap_desc = {
+ .bLength = USB_DT_USB_SS_CAP_SIZE,
+ .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
+ .bDevCapabilityType = USB_SS_CAP_TYPE,
+
+ /* .bmAttributes = LTM is not supported yet */
+
+ .wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION
+ | USB_FULL_SPEED_OPERATION
+ | USB_HIGH_SPEED_OPERATION
+ | USB_5GBPS_OPERATION),
+ .bFunctionalitySupport = USB_LOW_SPEED_OPERATION,
+ .bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT,
+ .bU2DevExitLat = USB_DEFAULT_U2_DEV_EXIT_LAT,
+};
+
+static __maybe_unused struct usb_bos_descriptor fsg_bos_desc = {
+ .bLength = USB_DT_BOS_SIZE,
+ .bDescriptorType = USB_DT_BOS,
+
+ .wTotalLength = USB_DT_BOS_SIZE
+ + USB_DT_USB_EXT_CAP_SIZE
+ + USB_DT_USB_SS_CAP_SIZE,
+
+ .bNumDeviceCaps = 2,
+};
+
+static struct usb_descriptor_header *fsg_ss_function[] = {
+#ifndef FSG_NO_OTG
+ (struct usb_descriptor_header *) &fsg_otg_desc,
+#endif
+ (struct usb_descriptor_header *) &fsg_intf_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_out_desc,
+ (struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,
+#ifndef FSG_NO_INTR_EP
+ (struct usb_descriptor_header *) &fsg_ss_intr_in_desc,
+ (struct usb_descriptor_header *) &fsg_ss_intr_in_comp_desc,
+#endif
+ NULL,
+};
+
/* Maxpacket and other transfer characteristics vary by speed. */
-static struct usb_endpoint_descriptor *
+static __maybe_unused struct usb_endpoint_descriptor *
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
- struct usb_endpoint_descriptor *hs)
+ struct usb_endpoint_descriptor *hs,
+ struct usb_endpoint_descriptor *ss)
{
- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+ if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+ return ss;
+ else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
@@ -596,13 +714,24 @@
rc = (int) size;
goto out;
}
- num_sectors = size >> 9; /* File size in 512-byte blocks */
+
+ if (curlun->cdrom) {
+ curlun->blksize = 2048;
+ curlun->blkbits = 11;
+ } else if (inode->i_bdev) {
+ curlun->blksize = bdev_logical_block_size(inode->i_bdev);
+ curlun->blkbits = blksize_bits(curlun->blksize);
+ } else {
+ curlun->blksize = 512;
+ curlun->blkbits = 9;
+ }
+
+ num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */
min_sectors = 1;
if (curlun->cdrom) {
- num_sectors &= ~3; /* Reduce to a multiple of 2048 */
- min_sectors = 300*4; /* Smallest track is 300 frames */
- if (num_sectors >= 256*60*75*4) {
- num_sectors = (256*60*75 - 1) * 4;
+ min_sectors = 300; /* Smallest track is 300 frames */
+ if (num_sectors >= 256*60*75) {
+ num_sectors = 256*60*75 - 1;
LINFO(curlun, "file too big: %s\n", filename);
LINFO(curlun, "using only first %d blocks\n",
(int) num_sectors);
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 6299cdd..36270d4 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -704,7 +704,7 @@
int ret;
unsigned long flags;
- ret = usb_ep_enable(port->gr->in, port->gr->in_desc);
+ ret = usb_ep_enable(port->gr->in);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
__func__, port->gr->in);
@@ -712,7 +712,7 @@
}
port->gr->in->driver_data = port;
- ret = usb_ep_enable(port->gr->out, port->gr->out_desc);
+ ret = usb_ep_enable(port->gr->out);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
__func__, port->gr->out);
@@ -1125,7 +1125,7 @@
d = &port->data_ch;
if (trans == USB_GADGET_XPORT_BAM) {
- ret = usb_ep_enable(gr->in, gr->in_desc);
+ ret = usb_ep_enable(gr->in);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
__func__, gr->in);
@@ -1133,7 +1133,7 @@
}
gr->in->driver_data = port;
- ret = usb_ep_enable(gr->out, gr->out_desc);
+ ret = usb_ep_enable(gr->out);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
__func__, gr->out);
diff --git a/drivers/usb/gadget/u_data_hsic.c b/drivers/usb/gadget/u_data_hsic.c
index 818e2a6..abf147a 100644
--- a/drivers/usb/gadget/u_data_hsic.c
+++ b/drivers/usb/gadget/u_data_hsic.c
@@ -754,8 +754,6 @@
struct gdata_port *port;
struct gserial *gser;
struct grmnet *gr;
- struct usb_endpoint_descriptor *in_desc;
- struct usb_endpoint_descriptor *out_desc;
unsigned long flags;
int ret = 0;
@@ -788,8 +786,6 @@
port->rx_q_size = ghsic_data_serial_rx_q_size;
gser->in->driver_data = port;
gser->out->driver_data = port;
- in_desc = gser->in_desc;
- out_desc = gser->out_desc;
} else {
gr = gptr;
@@ -805,18 +801,16 @@
port->rx_q_size = ghsic_data_rmnet_rx_q_size;
gr->in->driver_data = port;
gr->out->driver_data = port;
- in_desc = gr->in_desc;
- out_desc = gr->out_desc;
}
- ret = usb_ep_enable(port->in, in_desc);
+ ret = usb_ep_enable(port->in);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
__func__, port->in);
goto fail;
}
- ret = usb_ep_enable(port->out, out_desc);
+ ret = usb_ep_enable(port->out);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
__func__, port->out);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index b5a30fe..39c53da 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -693,8 +693,8 @@
usb_ep_disable(link->out_ep);
if (netif_carrier_ok(net)) {
DBG(dev, "host still using in/out endpoints\n");
- usb_ep_enable(link->in_ep, link->in);
- usb_ep_enable(link->out_ep, link->out);
+ usb_ep_enable(link->in_ep);
+ usb_ep_enable(link->out_ep);
}
}
spin_unlock_irqrestore(&dev->lock, flags);
@@ -891,7 +891,7 @@
return ERR_PTR(-EINVAL);
link->in_ep->driver_data = dev;
- result = usb_ep_enable(link->in_ep, link->in);
+ result = usb_ep_enable(link->in_ep);
if (result != 0) {
DBG(dev, "enable %s --> %d\n",
link->in_ep->name, result);
@@ -899,7 +899,7 @@
}
link->out_ep->driver_data = dev;
- result = usb_ep_enable(link->out_ep, link->out);
+ result = usb_ep_enable(link->out_ep);
if (result != 0) {
DBG(dev, "enable %s --> %d\n",
link->out_ep->name, result);
@@ -988,7 +988,7 @@
}
spin_unlock(&dev->req_lock);
link->in_ep->driver_data = NULL;
- link->in = NULL;
+ link->in_ep->desc = NULL;
usb_ep_disable(link->out_ep);
spin_lock(&dev->req_lock);
@@ -1003,7 +1003,7 @@
}
spin_unlock(&dev->req_lock);
link->out_ep->driver_data = NULL;
- link->out = NULL;
+ link->out_ep->desc = NULL;
/* finish forgetting about this USB link episode */
dev->header_len = 0;
diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h
index 64b65f9..4677241 100644
--- a/drivers/usb/gadget/u_ether.h
+++ b/drivers/usb/gadget/u_ether.h
@@ -52,10 +52,6 @@
struct usb_ep *in_ep;
struct usb_ep *out_ep;
- /* descriptors match device speed at gether_connect() time */
- struct usb_endpoint_descriptor *in;
- struct usb_endpoint_descriptor *out;
-
bool is_zlp_ok;
u16 cdc_filter;
diff --git a/drivers/usb/gadget/u_rmnet.h b/drivers/usb/gadget/u_rmnet.h
index fd1e124f..386101c 100644
--- a/drivers/usb/gadget/u_rmnet.h
+++ b/drivers/usb/gadget/u_rmnet.h
@@ -29,8 +29,6 @@
struct usb_ep *in;
struct usb_ep *out;
- struct usb_endpoint_descriptor *in_desc;
- struct usb_endpoint_descriptor *out_desc;
/* to usb host, aka laptop, windows pc etc. Will
* be filled by usb driver of rmnet functionality
diff --git a/drivers/usb/gadget/u_sdio.c b/drivers/usb/gadget/u_sdio.c
index 9bd4370..14dc73a 100644
--- a/drivers/usb/gadget/u_sdio.c
+++ b/drivers/usb/gadget/u_sdio.c
@@ -931,7 +931,7 @@
gser->notify_modem = gsdio_ctrl_notify_modem;
spin_unlock_irqrestore(&port->port_lock, flags);
- ret = usb_ep_enable(gser->in, gser->in_desc);
+ ret = usb_ep_enable(gser->in);
if (ret) {
pr_err("%s: failed to enable in ep w/ err:%d\n",
__func__, ret);
@@ -940,7 +940,7 @@
}
gser->in->driver_data = port;
- ret = usb_ep_enable(gser->out, gser->out_desc);
+ ret = usb_ep_enable(gser->out);
if (ret) {
pr_err("%s: failed to enable in ep w/ err:%d\n",
__func__, ret);
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index ca5f11b..10a255d 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -1524,12 +1524,12 @@
port = ports[port_num].port;
/* activate the endpoints */
- status = usb_ep_enable(gser->in, gser->in_desc);
+ status = usb_ep_enable(gser->in);
if (status < 0)
return status;
gser->in->driver_data = port;
- status = usb_ep_enable(gser->out, gser->out_desc);
+ status = usb_ep_enable(gser->out);
if (status < 0)
goto fail_out;
gser->out->driver_data = port;
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index c937006..dadc507 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -35,8 +35,6 @@
struct usb_ep *in;
struct usb_ep *out;
- struct usb_endpoint_descriptor *in_desc;
- struct usb_endpoint_descriptor *out_desc;
/* REVISIT avoid this CDC-ACM support harder ... */
struct usb_cdc_line_coding port_line_coding; /* 9600-8-N-1 etc */
diff --git a/drivers/usb/gadget/u_smd.c b/drivers/usb/gadget/u_smd.c
index 95adf5d..0e9ad48 100644
--- a/drivers/usb/gadget/u_smd.c
+++ b/drivers/usb/gadget/u_smd.c
@@ -660,7 +660,7 @@
port->nbytes_tolaptop = 0;
spin_unlock_irqrestore(&port->port_lock, flags);
- ret = usb_ep_enable(gser->in, gser->in_desc);
+ ret = usb_ep_enable(gser->in);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
__func__, gser->in);
@@ -669,7 +669,7 @@
}
gser->in->driver_data = port;
- ret = usb_ep_enable(gser->out, gser->out_desc);
+ ret = usb_ep_enable(gser->out);
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
__func__, gser->out);
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
new file mode 100644
index 0000000..2f77e469
--- /dev/null
+++ b/drivers/usb/gadget/udc-core.c
@@ -0,0 +1,485 @@
+/**
+ * udc.c - Core UDC Framework
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/**
+ * struct usb_udc - describes one usb device controller
+ * @driver - the gadget driver pointer. For use by the class code
+ * @dev - the child device to the actual controller
+ * @gadget - the gadget. For use by the class code
+ * @list - for use by the udc class driver
+ *
+ * This represents the internal data structure which is used by the UDC-class
+ * to hold information about udc driver and gadget together.
+ */
+struct usb_udc {
+ struct usb_gadget_driver *driver;
+ struct usb_gadget *gadget;
+ struct device dev;
+ struct list_head list;
+};
+
+static struct class *udc_class;
+static struct device_type udc_device_type;
+static LIST_HEAD(udc_list);
+static DEFINE_MUTEX(udc_lock);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_start - tells usb device controller to start up
+ * @gadget: The gadget we want to get started
+ * @driver: The driver we want to bind to @gadget
+ * @bind: The bind function for @driver
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ return gadget->ops->start(driver, bind);
+}
+
+/**
+ * usb_gadget_udc_start - tells usb device controller to start up
+ * @gadget: The gadget we want to get started
+ * @driver: The driver we want to bind to @gadget
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ return gadget->ops->udc_start(gadget, driver);
+}
+
+/**
+ * usb_gadget_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ gadget->ops->stop(driver);
+}
+
+/**
+ * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_udc_stop(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ gadget->ops->udc_stop(gadget, driver);
+}
+
+/**
+ * usb_udc_release - release the usb_udc struct
+ * @dev: the dev member within usb_udc
+ *
+ * This is called by driver's core in order to free memory once the last
+ * reference is released.
+ */
+static void usb_udc_release(struct device *dev)
+{
+ struct usb_udc *udc;
+
+ udc = container_of(dev, struct usb_udc, dev);
+ dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+ kfree(udc);
+}
+
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+ struct usb_udc *udc;
+ int ret = -ENOMEM;
+
+ udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+ if (!udc)
+ goto err1;
+
+ device_initialize(&udc->dev);
+ udc->dev.release = usb_udc_release;
+ udc->dev.class = udc_class;
+ udc->dev.parent = parent;
+ ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
+ if (ret)
+ goto err2;
+
+ udc->gadget = gadget;
+
+ mutex_lock(&udc_lock);
+ list_add_tail(&udc->list, &udc_list);
+
+ ret = device_add(&udc->dev);
+ if (ret)
+ goto err3;
+
+ mutex_unlock(&udc_lock);
+
+ return 0;
+err3:
+ list_del(&udc->list);
+ mutex_unlock(&udc_lock);
+
+err2:
+ put_device(&udc->dev);
+
+err1:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
+
+static int udc_is_newstyle(struct usb_udc *udc)
+{
+ if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop)
+ return 1;
+ return 0;
+}
+
+
+static void usb_gadget_remove_driver(struct usb_udc *udc)
+{
+ dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
+ udc->gadget->name);
+
+ kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+
+ if (udc_is_newstyle(udc)) {
+ udc->driver->disconnect(udc->gadget);
+ udc->driver->unbind(udc->gadget);
+ usb_gadget_udc_stop(udc->gadget, udc->driver);
+ usb_gadget_disconnect(udc->gadget);
+ } else {
+ usb_gadget_stop(udc->gadget, udc->driver);
+ }
+
+ udc->driver = NULL;
+ udc->dev.driver = NULL;
+}
+
+/**
+ * usb_del_gadget_udc - deletes @udc from udc_list
+ * @gadget: the gadget to be removed.
+ *
+ * This, will call usb_gadget_unregister_driver() if
+ * the @udc is still busy.
+ */
+void usb_del_gadget_udc(struct usb_gadget *gadget)
+{
+ struct usb_udc *udc = NULL;
+
+ mutex_lock(&udc_lock);
+ list_for_each_entry(udc, &udc_list, list)
+ if (udc->gadget == gadget)
+ goto found;
+
+ dev_err(gadget->dev.parent, "gadget not registered.\n");
+ mutex_unlock(&udc_lock);
+
+ return;
+
+found:
+ dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
+
+ list_del(&udc->list);
+ mutex_unlock(&udc_lock);
+
+ if (udc->driver)
+ usb_gadget_remove_driver(udc);
+
+ kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+ device_unregister(&udc->dev);
+}
+EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
+
+/* ------------------------------------------------------------------------- */
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *))
+{
+ struct usb_udc *udc = NULL;
+ int ret;
+
+ if (!driver || !bind || !driver->setup)
+ return -EINVAL;
+
+ mutex_lock(&udc_lock);
+ list_for_each_entry(udc, &udc_list, list) {
+ /* For now we take the first one */
+ if (!udc->driver)
+ goto found;
+ }
+
+ pr_debug("couldn't find an available UDC\n");
+ mutex_unlock(&udc_lock);
+ return -ENODEV;
+
+found:
+ dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
+ driver->function);
+
+ udc->driver = driver;
+ udc->dev.driver = &driver->driver;
+
+ if (udc_is_newstyle(udc)) {
+ ret = bind(udc->gadget);
+ if (ret)
+ goto err1;
+ ret = usb_gadget_udc_start(udc->gadget, driver);
+ if (ret) {
+ driver->unbind(udc->gadget);
+ goto err1;
+ }
+ usb_gadget_connect(udc->gadget);
+ } else {
+
+ ret = usb_gadget_start(udc->gadget, driver, bind);
+ if (ret)
+ goto err1;
+
+ }
+
+ kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+ mutex_unlock(&udc_lock);
+ return 0;
+
+err1:
+ dev_err(&udc->dev, "failed to start %s: %d\n",
+ udc->driver->function, ret);
+ udc->driver = NULL;
+ udc->dev.driver = NULL;
+ mutex_unlock(&udc_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct usb_udc *udc = NULL;
+ int ret = -ENODEV;
+
+ if (!driver || !driver->unbind)
+ return -EINVAL;
+
+ mutex_lock(&udc_lock);
+ list_for_each_entry(udc, &udc_list, list)
+ if (udc->driver == driver) {
+ usb_gadget_remove_driver(udc);
+ ret = 0;
+ break;
+ }
+
+ mutex_unlock(&udc_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
+
+/* ------------------------------------------------------------------------- */
+
+static ssize_t usb_udc_srp_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t n)
+{
+ struct usb_udc *udc = dev_get_drvdata(dev);
+
+ if (sysfs_streq(buf, "1"))
+ usb_gadget_wakeup(udc->gadget);
+
+ return n;
+}
+static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
+
+static ssize_t usb_udc_softconn_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t n)
+{
+ struct usb_udc *udc = dev_get_drvdata(dev);
+
+ if (sysfs_streq(buf, "connect")) {
+ usb_gadget_connect(udc->gadget);
+ } else if (sysfs_streq(buf, "disconnect")) {
+ usb_gadget_disconnect(udc->gadget);
+ } else {
+ dev_err(dev, "unsupported command '%s'\n", buf);
+ return -EINVAL;
+ }
+
+ return n;
+}
+static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
+
+static ssize_t usb_udc_speed_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct usb_udc *udc = dev_get_drvdata(dev);
+ struct usb_gadget *gadget = udc->gadget;
+
+ switch (gadget->speed) {
+ case USB_SPEED_LOW:
+ return snprintf(buf, PAGE_SIZE, "low-speed\n");
+ case USB_SPEED_FULL:
+ return snprintf(buf, PAGE_SIZE, "full-speed\n");
+ case USB_SPEED_HIGH:
+ return snprintf(buf, PAGE_SIZE, "high-speed\n");
+ case USB_SPEED_WIRELESS:
+ return snprintf(buf, PAGE_SIZE, "wireless\n");
+ case USB_SPEED_SUPER:
+ return snprintf(buf, PAGE_SIZE, "super-speed\n");
+ case USB_SPEED_UNKNOWN: /* FALLTHROUGH */
+ default:
+ return snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+ }
+}
+static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL);
+
+#define USB_UDC_ATTR(name) \
+ssize_t usb_udc_##name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+{ \
+ struct usb_udc *udc = dev_get_drvdata(dev); \
+ struct usb_gadget *gadget = udc->gadget; \
+ \
+ return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \
+} \
+static DEVICE_ATTR(name, S_IRUSR, usb_udc_##name##_show, NULL)
+
+static USB_UDC_ATTR(is_dualspeed);
+static USB_UDC_ATTR(is_otg);
+static USB_UDC_ATTR(is_a_peripheral);
+static USB_UDC_ATTR(b_hnp_enable);
+static USB_UDC_ATTR(a_hnp_support);
+static USB_UDC_ATTR(a_alt_hnp_support);
+
+static struct attribute *usb_udc_attrs[] = {
+ &dev_attr_srp.attr,
+ &dev_attr_soft_connect.attr,
+ &dev_attr_speed.attr,
+
+ &dev_attr_is_dualspeed.attr,
+ &dev_attr_is_otg.attr,
+ &dev_attr_is_a_peripheral.attr,
+ &dev_attr_b_hnp_enable.attr,
+ &dev_attr_a_hnp_support.attr,
+ &dev_attr_a_alt_hnp_support.attr,
+ NULL,
+};
+
+static const struct attribute_group usb_udc_attr_group = {
+ .attrs = usb_udc_attrs,
+};
+
+static const struct attribute_group *usb_udc_attr_groups[] = {
+ &usb_udc_attr_group,
+ NULL,
+};
+
+static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
+ int ret;
+
+ ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name);
+ if (ret) {
+ dev_err(dev, "failed to add uevent USB_UDC_NAME\n");
+ return ret;
+ }
+
+ if (udc->driver) {
+ ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
+ udc->driver->function);
+ if (ret) {
+ dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __init usb_udc_init(void)
+{
+ udc_class = class_create(THIS_MODULE, "udc");
+ if (IS_ERR(udc_class)) {
+ pr_err("failed to create udc class --> %ld\n",
+ PTR_ERR(udc_class));
+ return PTR_ERR(udc_class);
+ }
+
+ udc_class->dev_uevent = usb_udc_uevent;
+ udc_device_type.groups = usb_udc_attr_groups;
+
+ return 0;
+}
+subsys_initcall(usb_udc_init);
+
+static void __exit usb_udc_exit(void)
+{
+ class_destroy(udc_class);
+}
+module_exit(usb_udc_exit);
+
+MODULE_DESCRIPTION("UDC Framework");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/gadget/webcam.c b/drivers/usb/gadget/webcam.c
index a5a0fdb..df6882d 100644
--- a/drivers/usb/gadget/webcam.c
+++ b/drivers/usb/gadget/webcam.c
@@ -373,6 +373,7 @@
.name = "g_webcam",
.dev = &webcam_device_descriptor,
.strings = webcam_device_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = webcam_unbind,
};
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 6d16db9..af7e7c3 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -340,6 +340,7 @@
.name = "zero",
.dev = &device_desc,
.strings = dev_strings,
+ .max_speed = USB_SPEED_HIGH,
.unbind = zero_unbind,
.suspend = zero_suspend,
.resume = zero_resume,
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index ece6785..bda6745 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -189,6 +189,13 @@
for chip-to-chip interconnect (having maximum circuit length of
10cm) as it removes the analog transceivers.
+config USB_EHCI_MSM_HOST4
+ bool "Support for MSM on-chip EHCI USB controller# 4"
+ depends on USB_EHCI_HCD && ARCH_MSM && ARCH_APQ8064
+ ---help---
+ Enables support for the EHCI Compliant USB Host controller# 4
+ present on the Qualcomm chipsets.
+
config USB_EHCI_TEGRA
boolean "NVIDIA Tegra HCD support"
depends on USB_EHCI_HCD && ARCH_TEGRA
diff --git a/drivers/usb/host/ehci-msm2.c b/drivers/usb/host/ehci-msm2.c
index 4f6fe3e..4318efb 100644
--- a/drivers/usb/host/ehci-msm2.c
+++ b/drivers/usb/host/ehci-msm2.c
@@ -48,6 +48,7 @@
struct regulator *hsusb_1p8;
struct regulator *vbus;
bool async_int;
+ bool vbus_on;
atomic_t in_lpm;
struct wake_lock wlock;
};
@@ -174,17 +175,24 @@
}
#ifdef CONFIG_PM_SLEEP
-#define HSUSB_PHY_SUSP_DIG_VOL 500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P50 500000
+#define HSUSB_PHY_SUSP_DIG_VOL_P75 750000
static int msm_ehci_config_vddcx(struct msm_hcd *mhcd, int high)
{
+ struct msm_usb_host_platform_data *pdata;
int max_vol = HSUSB_PHY_VDD_DIG_VOL_MAX;
int min_vol;
int ret;
+ pdata = mhcd->dev->platform_data;
+
if (high)
min_vol = HSUSB_PHY_VDD_DIG_VOL_MIN;
+ else if (pdata && pdata->dock_connect_irq &&
+ !irq_read_line(pdata->dock_connect_irq))
+ min_vol = HSUSB_PHY_SUSP_DIG_VOL_P75;
else
- min_vol = HSUSB_PHY_SUSP_DIG_VOL;
+ min_vol = HSUSB_PHY_SUSP_DIG_VOL_P50;
ret = regulator_set_voltage(mhcd->hsusb_vddcx, min_vol, max_vol);
if (ret) {
@@ -205,29 +213,6 @@
}
#endif
-static int msm_ehci_init_vbus(struct msm_hcd *mhcd, int init)
-{
- struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
- struct msm_usb_host_platform_data *pdata;
-
- if (!init) {
- regulator_put(mhcd->vbus);
- return 0;
- }
-
- mhcd->vbus = regulator_get(mhcd->dev, "vbus");
- if (IS_ERR(mhcd->vbus)) {
- pr_err("Unable to get vbus\n");
- return -ENODEV;
- }
-
- pdata = mhcd->dev->platform_data;
- if (pdata)
- hcd->power_budget = pdata->power_budget;
-
- return 0;
-}
-
static void msm_ehci_vbus_power(struct msm_hcd *mhcd, bool on)
{
int ret;
@@ -236,21 +221,86 @@
pr_err("vbus is NULL.");
return;
}
+
+ if (mhcd->vbus_on == on)
+ return;
+
if (on) {
ret = regulator_enable(mhcd->vbus);
if (ret) {
pr_err("unable to enable vbus\n");
return;
}
+ mhcd->vbus_on = true;
} else {
ret = regulator_disable(mhcd->vbus);
if (ret) {
pr_err("unable to disable vbus\n");
return;
}
+ mhcd->vbus_on = false;
}
}
+static irqreturn_t msm_ehci_dock_connect_irq(int irq, void *data)
+{
+ const struct msm_usb_host_platform_data *pdata;
+ struct msm_hcd *mhcd = data;
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+
+ pdata = mhcd->dev->platform_data;
+
+ if (atomic_read(&mhcd->in_lpm))
+ usb_hcd_resume_root_hub(hcd);
+
+ if (irq_read_line(pdata->dock_connect_irq)) {
+ dev_dbg(mhcd->dev, "%s:Dock removed disable vbus\n", __func__);
+ msm_ehci_vbus_power(mhcd, 0);
+ } else {
+ dev_dbg(mhcd->dev, "%s:Dock connected enable vbus\n", __func__);
+ msm_ehci_vbus_power(mhcd, 1);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int msm_ehci_init_vbus(struct msm_hcd *mhcd, int init)
+{
+ int rc = 0;
+ struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
+ const struct msm_usb_host_platform_data *pdata;
+
+ pdata = mhcd->dev->platform_data;
+
+ if (!init) {
+ regulator_put(mhcd->vbus);
+ if (pdata && pdata->dock_connect_irq)
+ free_irq(pdata->dock_connect_irq, mhcd);
+ return rc;
+ }
+
+ mhcd->vbus = regulator_get(mhcd->dev, "vbus");
+ if (IS_ERR(mhcd->vbus)) {
+ pr_err("Unable to get vbus\n");
+ return -ENODEV;
+ }
+
+ if (pdata) {
+ hcd->power_budget = pdata->power_budget;
+
+ if (pdata->dock_connect_irq) {
+ rc = request_threaded_irq(pdata->dock_connect_irq, NULL,
+ msm_ehci_dock_connect_irq,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT, "msm_ehci_host", mhcd);
+ if (!rc)
+ enable_irq_wake(pdata->dock_connect_irq);
+ }
+ }
+ return rc;
+}
+
static int msm_ehci_ldo_enable(struct msm_hcd *mhcd, int on)
{
int ret = 0;
@@ -772,6 +822,7 @@
struct usb_hcd *hcd;
struct resource *res;
struct msm_hcd *mhcd;
+ const struct msm_usb_host_platform_data *pdata;
int ret;
dev_dbg(&pdev->dev, "ehci_msm2 probe\n");
@@ -859,8 +910,10 @@
goto vbus_deinit;
}
- /*TBD:for now enable vbus here*/
- msm_ehci_vbus_power(mhcd, 1);
+ pdata = mhcd->dev->platform_data;
+ if (pdata && (!pdata->dock_connect_irq ||
+ !irq_read_line(pdata->dock_connect_irq)))
+ msm_ehci_vbus_power(mhcd, 1);
device_init_wakeup(&pdev->dev, 1);
wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
@@ -903,6 +956,7 @@
pm_runtime_set_suspended(&pdev->dev);
usb_remove_hcd(hcd);
+
msm_ehci_vbus_power(mhcd, 0);
msm_ehci_init_vbus(mhcd, 0);
msm_ehci_ldo_enable(mhcd, 0);
diff --git a/drivers/usb/misc/diag_bridge.c b/drivers/usb/misc/diag_bridge.c
index 5ab987e..9794918 100644
--- a/drivers/usb/misc/diag_bridge.c
+++ b/drivers/usb/misc/diag_bridge.c
@@ -82,6 +82,7 @@
urb->status, urb->actual_length);
if (urb->status == -EPROTO) {
+ dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
/* save error so that subsequent read/write returns ESHUTDOWN */
dev->err = urb->status;
return;
@@ -119,27 +120,36 @@
if (dev->err)
return -ESHUTDOWN;
- urb = usb_alloc_urb(0, GFP_ATOMIC);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
dev_err(&dev->udev->dev, "unable to allocate urb\n");
return -ENOMEM;
}
+ ret = usb_autopm_get_interface(dev->ifc);
+ if (ret < 0) {
+ dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
+ usb_free_urb(urb);
+ return ret;
+ }
+
pipe = usb_rcvbulkpipe(dev->udev, dev->in_epAddr);
usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
diag_bridge_read_cb, dev);
usb_anchor_urb(urb, &dev->submitted);
dev->pending_reads++;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
+ ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
dev->pending_reads--;
usb_unanchor_urb(urb);
usb_free_urb(urb);
+ usb_autopm_put_interface(dev->ifc);
return ret;
}
+ usb_autopm_put_interface(dev->ifc);
usb_free_urb(urb);
return 0;
@@ -153,7 +163,10 @@
dev_dbg(&dev->udev->dev, "%s:\n", __func__);
+ usb_autopm_put_interface_async(dev->ifc);
+
if (urb->status == -EPROTO) {
+ dev_err(&dev->udev->dev, "%s: proto error\n", __func__);
/* save error so that subsequent read/write returns ESHUTDOWN */
dev->err = urb->status;
return;
@@ -191,24 +204,32 @@
if (dev->err)
return -ESHUTDOWN;
- urb = usb_alloc_urb(0, GFP_ATOMIC);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
err("unable to allocate urb");
return -ENOMEM;
}
+ ret = usb_autopm_get_interface(dev->ifc);
+ if (ret < 0) {
+ dev_err(&dev->udev->dev, "autopm_get failed:%d\n", ret);
+ usb_free_urb(urb);
+ return ret;
+ }
+
pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
diag_bridge_write_cb, dev);
usb_anchor_urb(urb, &dev->submitted);
dev->pending_writes++;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
+ ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret) {
dev_err(&dev->udev->dev, "submitting urb failed err:%d\n", ret);
dev->pending_writes--;
usb_unanchor_urb(urb);
usb_free_urb(urb);
+ usb_autopm_put_interface(dev->ifc);
return ret;
}
@@ -381,6 +402,37 @@
usb_set_intfdata(ifc, NULL);
}
+static int diag_bridge_suspend(struct usb_interface *ifc, pm_message_t message)
+{
+ struct diag_bridge *dev = usb_get_intfdata(ifc);
+ struct diag_bridge_ops *cbs = dev->ops;
+ int ret = 0;
+
+ if (cbs && cbs->suspend) {
+ ret = cbs->suspend(cbs->ctxt);
+ if (ret) {
+ dev_dbg(&dev->udev->dev,
+ "%s: diag veto'd suspend\n", __func__);
+ return ret;
+ }
+
+ usb_kill_anchored_urbs(&dev->submitted);
+ }
+
+ return ret;
+}
+
+static int diag_bridge_resume(struct usb_interface *ifc)
+{
+ struct diag_bridge *dev = usb_get_intfdata(ifc);
+ struct diag_bridge_ops *cbs = dev->ops;
+
+
+ if (cbs && cbs->resume)
+ cbs->resume(cbs->ctxt);
+
+ return 0;
+}
#define VALID_INTERFACE_NUM 0
static const struct usb_device_id diag_bridge_ids[] = {
@@ -401,7 +453,10 @@
.name = "diag_bridge",
.probe = diag_bridge_probe,
.disconnect = diag_bridge_disconnect,
+ .suspend = diag_bridge_suspend,
+ .resume = diag_bridge_resume,
.id_table = diag_bridge_ids,
+ .supports_autosuspend = 1,
};
static int __init diag_bridge_init(void)
@@ -410,8 +465,7 @@
ret = usb_register(&diag_bridge_driver);
if (ret) {
- err("%s: unable to register diag driver",
- __func__);
+ err("%s: unable to register diag driver", __func__);
return ret;
}
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c
index a77d98f..cce819f 100644
--- a/drivers/usb/misc/mdm_data_bridge.c
+++ b/drivers/usb/misc/mdm_data_bridge.c
@@ -1013,6 +1013,7 @@
#define PID9001_IFACE_MASK 0xC
#define PID9034_IFACE_MASK 0xC
#define PID9048_IFACE_MASK 0x18
+#define PID904C_IFACE_MASK 0x28
static const struct usb_device_id bridge_ids[] = {
{ USB_DEVICE(0x5c6, 0x9001),
@@ -1024,6 +1025,9 @@
{ USB_DEVICE(0x5c6, 0x9048),
.driver_info = PID9048_IFACE_MASK,
},
+ { USB_DEVICE(0x5c6, 0x904c),
+ .driver_info = PID904C_IFACE_MASK,
+ },
{ } /* Terminating entry */
};
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 548338c..784910a 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1715,6 +1715,10 @@
return 0;
}
+static int musb_gadget_start(struct usb_gadget_driver *driver,
+ int (*bind)(struct usb_gadget *));
+static int musb_gadget_stop(struct usb_gadget_driver *driver);
+
static const struct usb_gadget_ops musb_gadget_operations = {
.get_frame = musb_gadget_get_frame,
.wakeup = musb_gadget_wakeup,
@@ -1722,6 +1726,8 @@
/* .vbus_session = musb_gadget_vbus_session, */
.vbus_draw = musb_gadget_vbus_draw,
.pullup = musb_gadget_pullup,
+ .start = musb_gadget_start,
+ .stop = musb_gadget_stop,
};
/* ----------------------------------------------------------------------- */
@@ -1846,7 +1852,16 @@
if (status != 0) {
put_device(&musb->g.dev);
the_gadget = NULL;
+ return status;
}
+ status = usb_add_gadget_udc(musb->controller, &musb->g);
+ if (status)
+ goto err;
+
+ return 0;
+err:
+ device_unregister(&musb->g.dev);
+ the_gadget = NULL;
return status;
}
@@ -1855,6 +1870,7 @@
if (musb != the_gadget)
return;
+ usb_del_gadget_udc(&musb->g);
device_unregister(&musb->g.dev);
the_gadget = NULL;
}
@@ -1871,7 +1887,7 @@
* @param bind the driver's bind function
* @return <0 if error, 0 if everything is fine
*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int musb_gadget_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct musb *musb = the_gadget;
@@ -1973,7 +1989,6 @@
err0:
return retval;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver)
{
@@ -2023,7 +2038,7 @@
*
* @param driver the gadget driver to unregister
*/
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int musb_gadget_stop(struct usb_gadget_driver *driver)
{
struct musb *musb = the_gadget;
unsigned long flags;
@@ -2082,8 +2097,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
/* ----------------------------------------------------------------------- */
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 6964835..dd07d4e 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -67,6 +67,7 @@
static DECLARE_COMPLETION(pmic_vbus_init);
static struct msm_otg *the_msm_otg;
static bool debug_aca_enabled;
+static bool debug_bus_voting_enabled;
/* Prevent idle power collapse(pc) while operating in peripheral mode */
static void otg_pm_qos_update_latency(struct msm_otg *dev, int vote)
@@ -1155,7 +1156,7 @@
*/
otg_pm_qos_update_latency(motg, 1);
/* Configure BUS performance parameters for MAX bandwidth */
- if (motg->bus_perf_client) {
+ if (motg->bus_perf_client && debug_bus_voting_enabled) {
ret = msm_bus_scale_client_update_request(
motg->bus_perf_client, 1);
if (ret)
@@ -2232,13 +2233,64 @@
.release = single_release,
};
+static int msm_otg_bus_show(struct seq_file *s, void *unused)
+{
+ if (debug_bus_voting_enabled)
+ seq_printf(s, "enabled\n");
+ else
+ seq_printf(s, "disabled\n");
+
+ return 0;
+}
+
+static int msm_otg_bus_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, msm_otg_bus_show, inode->i_private);
+}
+
+static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ char buf[8];
+ int ret;
+ struct seq_file *s = file->private_data;
+ struct msm_otg *motg = s->private;
+
+ memset(buf, 0x00, sizeof(buf));
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "enable", 6)) {
+ /* Do not vote here. Let OTG statemachine decide when to vote */
+ debug_bus_voting_enabled = true;
+ } else {
+ debug_bus_voting_enabled = false;
+ if (motg->bus_perf_client) {
+ ret = msm_bus_scale_client_update_request(
+ motg->bus_perf_client, 0);
+ if (ret)
+ dev_err(motg->otg.dev, "%s: Failed to devote "
+ "for bus bw %d\n", __func__, ret);
+ }
+ }
+
+ return count;
+}
+
+const struct file_operations msm_otg_bus_fops = {
+ .open = msm_otg_bus_open,
+ .read = seq_read,
+ .write = msm_otg_bus_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static struct dentry *msm_otg_dbg_root;
-static struct dentry *msm_otg_dbg_mode;
-static struct dentry *msm_otg_chg_type;
-static struct dentry *msm_otg_dbg_aca;
static int msm_otg_debugfs_init(struct msm_otg *motg)
{
+ struct dentry *msm_otg_dentry;
msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
@@ -2248,35 +2300,43 @@
if (motg->pdata->mode == USB_OTG &&
motg->pdata->otg_control == OTG_USER_CONTROL) {
- msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO |
+ msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
S_IWUSR, msm_otg_dbg_root, motg,
&msm_otg_mode_fops);
- if (!msm_otg_dbg_mode) {
+ if (!msm_otg_dentry) {
debugfs_remove(msm_otg_dbg_root);
msm_otg_dbg_root = NULL;
return -ENODEV;
}
}
- msm_otg_chg_type = debugfs_create_file("chg_type", S_IRUGO,
+ msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
msm_otg_dbg_root, motg,
&msm_otg_chg_fops);
- if (!msm_otg_chg_type) {
+ if (!msm_otg_dentry) {
debugfs_remove_recursive(msm_otg_dbg_root);
return -ENODEV;
}
- msm_otg_dbg_aca = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
+ msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
msm_otg_dbg_root, motg,
&msm_otg_aca_fops);
- if (!msm_otg_dbg_aca) {
+ if (!msm_otg_dentry) {
debugfs_remove_recursive(msm_otg_dbg_root);
return -ENODEV;
}
+ msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
+ msm_otg_dbg_root, motg,
+ &msm_otg_bus_fops);
+
+ if (!msm_otg_dentry) {
+ debugfs_remove_recursive(msm_otg_dbg_root);
+ return -ENODEV;
+ }
return 0;
}
@@ -2642,6 +2702,8 @@
if (!motg->bus_perf_client)
dev_err(motg->otg.dev, "%s: Failed to register BUS "
"scaling client!!\n", __func__);
+ else
+ debug_bus_voting_enabled = true;
}
return 0;
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 547486c..486d129 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -1179,7 +1179,7 @@
*
*/
struct usbhsg_gpriv *the_controller;
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int usbhsg_gadget_start(struct usb_gadget_driver *driver,
int (*bind)(struct usb_gadget *))
{
struct usbhsg_gpriv *gpriv = the_controller;
@@ -1229,9 +1229,8 @@
return ret;
}
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int usbhsg_gadget_stop(struct usb_gadget_driver *driver)
{
struct usbhsg_gpriv *gpriv = the_controller;
struct usbhs_priv *priv;
@@ -1260,7 +1259,6 @@
return 0;
}
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
/*
* usb gadget ops
@@ -1275,6 +1273,8 @@
static struct usb_gadget_ops usbhsg_gadget_ops = {
.get_frame = usbhsg_get_frame,
+ .start = usbhsg_gadget_start,
+ .stop = usbhsg_gadget_stop,
};
static int usbhsg_start(struct usbhs_priv *priv)
@@ -1294,6 +1294,7 @@
struct device *dev = usbhs_priv_to_dev(priv);
int pipe_size = usbhs_get_dparam(priv, pipe_size);
int i;
+ int ret;
gpriv = kzalloc(sizeof(struct usbhsg_gpriv), GFP_KERNEL);
if (!gpriv) {
@@ -1304,6 +1305,7 @@
uep = kzalloc(sizeof(struct usbhsg_uep) * pipe_size, GFP_KERNEL);
if (!uep) {
dev_err(dev, "Could not allocate ep\n");
+ ret = -ENOMEM;
goto usbhs_mod_gadget_probe_err_gpriv;
}
@@ -1366,20 +1368,28 @@
the_controller = gpriv;
+ ret = usb_add_gadget_udc(dev, &gpriv->gadget);
+ if (ret)
+ goto err_add_udc;
+
+
dev_info(dev, "gadget probed\n");
return 0;
+err_add_udc:
+ kfree(gpriv->uep);
usbhs_mod_gadget_probe_err_gpriv:
kfree(gpriv);
- return -ENOMEM;
+ return ret;
}
void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv)
{
struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv);
+ usb_del_gadget_udc(&gpriv->gadget);
kfree(gpriv->uep);
kfree(gpriv);
}
diff --git a/drivers/usb/serial/csvt.c b/drivers/usb/serial/csvt.c
index 5bfb2dc..28eba8a 100644
--- a/drivers/usb/serial/csvt.c
+++ b/drivers/usb/serial/csvt.c
@@ -46,7 +46,7 @@
};
static const struct usb_device_id id_table[] = {
- { USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0x00, 0xff)},
+ { USB_DEVICE_AND_INTERFACE_INFO(0x05c6 , 0x904c, 0xff, 0xfe, 0xff)},
{}, /* terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 44e887cb..ef022c1 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -1,7 +1,7 @@
/*
* Qualcomm Serial USB driver
*
- * Copyright (c) 2008, 2012 QUALCOMM Incorporated.
+ * Copyright (c) 2008, 2012 Code Aurora Forum. All rights reserved.
* Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de>
* Copyright (c) 2009 Novell Inc.
*
diff --git a/drivers/video/msm/Kconfig b/drivers/video/msm/Kconfig
index 0110df9..032cdfe 100644
--- a/drivers/video/msm/Kconfig
+++ b/drivers/video/msm/Kconfig
@@ -178,6 +178,11 @@
bool
select FB_MSM_MIPI_DSI
+config FB_MSM_MIPI_DSI_ORISE
+ bool
+ select FB_MSM_MIPI_DSI
+ default n
+
config FB_MSM_MIPI_DSI_TC358764_DSI2LVDS
bool
select FB_MSM_MIPI_DSI
@@ -285,6 +290,16 @@
select FB_MSM_MIPI_DSI_NOVATEK
default n
+config FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+ bool
+ select FB_MSM_MIPI_DSI_ORISE
+ default n
+
+config FB_MSM_MIPI_ORISE_CMD_720P_PT
+ bool
+ select FB_MSM_MIPI_DSI_ORISE
+ default n
+
config FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT
bool
select FB_MSM_MIPI_DSI_RENESAS
@@ -459,6 +474,8 @@
select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT
select FB_MSM_MIPI_NT35510_CMD_WVGA_PT
+ select FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+ select FB_MSM_MIPI_ORISE_CMD_720P_PT
select FB_MSM_MIPI_SIMULATOR_VIDEO
select FB_MSM_MIPI_CHIMEI_WXGA
select FB_MSM_MIPI_CHIMEI_WUXGA
@@ -514,6 +531,8 @@
select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
select FB_MSM_MIPI_NT35510_VIDEO_WVGA_PT
select FB_MSM_MIPI_NT35510_CMD_WVGA_PT
+ select FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+ select FB_MSM_MIPI_ORISE_CMD_720P_PT
select FB_MSM_MIPI_SIMULATOR_VIDEO
select FB_MSM_MIPI_CHIMEI_WXGA
select FB_MSM_MIPI_CHIMEI_WUXGA
@@ -570,6 +589,14 @@
bool "MIPI NOVATEK CMD QHD PT Panel"
select FB_MSM_MIPI_NOVATEK_CMD_QHD_PT
+config FB_MSM_MIPI_ORISE_VIDEO_720P_PT_PANEL
+ bool "MIPI ORISE VIDEO 720P PT Panel"
+ select FB_MSM_MIPI_ORISE_VIDEO_720P_PT
+
+config FB_MSM_MIPI_ORISE_CMD_720P_PT_PANEL
+ bool "MIPI ORISE CMD 720P PT Panel"
+ select FB_MSM_MIPI_ORISE_CMD_720P_PT
+
config FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT_PANEL
bool "MIPI Renesas Video FWVGA PT Panel"
select FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT
@@ -609,6 +636,7 @@
Support for EBI2 TMD QVGA (240x320) and Epson QCIF (176x220) panel
config FB_MSM_HDMI_AS_PRIMARY
+ depends on FB_MSM_HDMI_COMMON
bool "Use HDMI as primary panel"
---help---
Support for using HDMI as primary
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
index 2bdab74..eae79a2 100644
--- a/drivers/video/msm/Makefile
+++ b/drivers/video/msm/Makefile
@@ -74,6 +74,7 @@
# MIPI manufacture
obj-$(CONFIG_FB_MSM_MIPI_DSI_TOSHIBA) += mipi_toshiba.o
obj-$(CONFIG_FB_MSM_MIPI_DSI_NOVATEK) += mipi_novatek.o
+obj-$(CONFIG_FB_MSM_MIPI_DSI_ORISE) += mipi_orise.o
obj-$(CONFIG_FB_MSM_MIPI_DSI_RENESAS) += mipi_renesas.o
obj-$(CONFIG_FB_MSM_MIPI_DSI_TRULY) += mipi_truly.o
obj-$(CONFIG_FB_MSM_MIPI_DSI_NT35510) += mipi_NT35510.o
@@ -116,6 +117,7 @@
ifeq ($(CONFIG_FB_MSM_MIPI_PANEL_DETECT),y)
obj-y += mipi_toshiba_video_wvga_pt.o mipi_toshiba_video_wsvga_pt.o mipi_toshiba_video_wuxga.o
obj-y += mipi_novatek_video_qhd_pt.o mipi_novatek_cmd_qhd_pt.o
+obj-y += mipi_orise_video_720p_pt.o mipi_orise_cmd_720p_pt.o
obj-y += mipi_renesas_video_fwvga_pt.o mipi_renesas_cmd_fwvga_pt.o
obj-y += mipi_NT35510_video_wvga_pt.o mipi_NT35510_cmd_wvga_pt.o
obj-y += mipi_chimei_wxga_pt.o
@@ -126,6 +128,8 @@
obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WSVGA_PT) += mipi_toshiba_video_wsvga_pt.o
obj-$(CONFIG_FB_MSM_MIPI_TOSHIBA_VIDEO_WUXGA) += mipi_toshiba_video_wuxga.o
obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_VIDEO_QHD_PT) += mipi_novatek_video_qhd_pt.o
+obj-$(CONFIG_FB_MSM_MIPI_ORISE_VIDEO_720P_PT) += mipi_orise_video_720p_pt.o
+obj-$(CONFIG_FB_MSM_MIPI_ORISE_CMD_720P_PT) += mipi_orise_cmd_720p_pt.o
obj-$(CONFIG_FB_MSM_MIPI_NOVATEK_CMD_QHD_PT) += mipi_novatek_cmd_qhd_pt.o
obj-$(CONFIG_FB_MSM_MIPI_RENESAS_VIDEO_FWVGA_PT) += mipi_renesas_video_fwvga_pt.o
obj-$(CONFIG_FB_MSM_MIPI_RENESAS_CMD_FWVGA_PT) += mipi_renesas_cmd_fwvga_pt.o
diff --git a/drivers/video/msm/external_common.c b/drivers/video/msm/external_common.c
index 0a86a50..d6f59aa 100644
--- a/drivers/video/msm/external_common.c
+++ b/drivers/video/msm/external_common.c
@@ -347,11 +347,12 @@
struct device_attribute *attr, const char *buf, size_t count)
{
ssize_t ret = strnlen(buf, PAGE_SIZE);
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- int hpd = 1;
-#else
- int hpd = atoi(buf);
-#endif
+ int hpd;
+ if (hdmi_prim_display)
+ hpd = 1;
+ else
+ hpd = atoi(buf);
+
if (external_common_state->hpd_feature) {
if (hpd == 0 && external_common_state->hpd_feature_on) {
external_common_state->hpd_feature(0);
@@ -652,6 +653,14 @@
return ret;
}
+static ssize_t hdmi_common_rda_hdmi_primary(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ hdmi_prim_display);
+ DEV_DBG("%s: '%d'\n", __func__, hdmi_prim_display);
+ return ret;
+}
static DEVICE_ATTR(video_mode, S_IRUGO | S_IWUGO,
external_common_rda_video_mode, external_common_wta_video_mode);
@@ -671,6 +680,7 @@
static DEVICE_ATTR(format_3d, S_IRUGO | S_IWUGO, hdmi_3d_rda_format_3d,
hdmi_3d_wta_format_3d);
#endif
+static DEVICE_ATTR(hdmi_primary, S_IRUGO, hdmi_common_rda_hdmi_primary, NULL);
static struct attribute *external_common_fs_attrs[] = {
&dev_attr_video_mode.attr,
@@ -693,6 +703,7 @@
&dev_attr_cec_rd_frame.attr,
&dev_attr_cec_wr_frame.attr,
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL_CEC_SUPPORT */
+ &dev_attr_hdmi_primary.attr,
NULL,
};
static struct attribute_group external_common_fs_attr_group = {
@@ -1567,11 +1578,10 @@
pinfo->pdest = DISPLAY_2;
pinfo->wait_cycle = 0;
pinfo->bpp = 24;
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- pinfo->fb_num = 2;
-#else
- pinfo->fb_num = 1;
-#endif
+ if (hdmi_prim_display)
+ pinfo->fb_num = 2;
+ else
+ pinfo->fb_num = 1;
/* blk */
pinfo->lcdc.border_clr = 0;
diff --git a/drivers/video/msm/hdmi_msm.c b/drivers/video/msm/hdmi_msm.c
index ef357db..1c47d89 100644
--- a/drivers/video/msm/hdmi_msm.c
+++ b/drivers/video/msm/hdmi_msm.c
@@ -2475,12 +2475,6 @@
goto error;
}
- /*
- * A small delay is needed here to avoid device crash observed
- * during reauthentication in MSM8960
- */
- msleep(20);
-
/* 0x0168 HDCP_RCVPORT_DATA12
[23:8] BSTATUS
[7:0] BCAPS */
@@ -4518,12 +4512,13 @@
{
int rc;
- if (cpu_is_msm8930())
- return 0;
-
if (msm_fb_detect_client("hdmi_msm"))
return 0;
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+ hdmi_prim_display = 1;
+#endif
+
hdmi_msm_setup_video_mode_lut();
hdmi_msm_state = kzalloc(sizeof(*hdmi_msm_state), GFP_KERNEL);
if (!hdmi_msm_state) {
diff --git a/drivers/video/msm/mdp.h b/drivers/video/msm/mdp.h
index 6c5a9f9..6dcc293 100644
--- a/drivers/video/msm/mdp.h
+++ b/drivers/video/msm/mdp.h
@@ -87,6 +87,7 @@
extern struct mdp_ccs mdp_ccs_yuv2rgb ;
extern struct mdp_ccs mdp_ccs_rgb2yuv ;
+extern unsigned char hdmi_prim_display;
/*
* MDP Image Structure
@@ -738,6 +739,11 @@
#ifdef CONFIG_MSM_BUS_SCALING
int mdp_bus_scale_update_request(uint32_t index);
+#else
+static inline int mdp_bus_scale_update_request(uint32_t index)
+{
+ return 0;
+}
#endif
#ifdef MDP_HW_VSYNC
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index f7f48e4..c4f6a04 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -445,14 +445,7 @@
}
#endif
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
void mdp4_dtv_set_black_screen(void);
-#else
-static inline void mdp4_dtv_set_black_screen(void)
-{
- /* empty */
-}
-#endif
static inline int mdp4_overlay_borderfill_supported(void)
{
diff --git a/drivers/video/msm/mdp4_dtv.c b/drivers/video/msm/mdp4_dtv.c
index ba774b9..09bc9c2 100644
--- a/drivers/video/msm/mdp4_dtv.c
+++ b/drivers/video/msm/mdp4_dtv.c
@@ -225,11 +225,11 @@
* get/set panel specific fb info
*/
mfd->panel_info = pdata->panel_info;
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
-#else
- mfd->fb_imgType = MDP_RGB_565;
-#endif
+ if (hdmi_prim_display)
+ mfd->fb_imgType = MSMFB_DEFAULT_TYPE;
+ else
+ mfd->fb_imgType = MDP_RGB_565;
+
fbi = mfd->fbi;
fbi->var.pixclock = mfd->panel_info.clk_rate;
fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index c020755..033a73c 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -402,7 +402,8 @@
pipe->op_mode |= MDP4_OP_SCALEY_EN;
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
- if (pipe->alpha_enable && pipe->dst_h > pipe->src_h)
+ if (pipe->flags & MDP_BACKEND_COMPOSITION &&
+ pipe->alpha_enable && pipe->dst_h > pipe->src_h)
pipe->op_mode |= MDP4_OP_SCALEY_PIXEL_RPT;
else if (pipe->dst_h <= (pipe->src_h / 4))
pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE;
@@ -424,7 +425,8 @@
pipe->op_mode |= MDP4_OP_SCALEX_EN;
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
- if (pipe->alpha_enable && pipe->dst_w > pipe->src_w)
+ if (pipe->flags & MDP_BACKEND_COMPOSITION &&
+ pipe->alpha_enable && pipe->dst_w > pipe->src_w)
pipe->op_mode |= MDP4_OP_SCALEX_PIXEL_RPT;
else if (pipe->dst_w <= (pipe->src_w / 4))
pipe->op_mode |= MDP4_OP_SCALEX_MN_PHASE;
@@ -1385,14 +1387,8 @@
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
- if (data) {
- if (pipe_cnt == 1) {
- mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
-#ifdef CONFIG_MSM_BUS_SCALING
- mdp_bus_scale_update_request(2);
-#endif
- }
- }
+ if (data && pipe_cnt == 1)
+ mdp4_update_perf_level(OVERLAY_PERF_LEVEL4);
}
void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
@@ -1891,7 +1887,7 @@
static int get_img(struct msmfb_data *img, struct fb_info *info,
unsigned long *start, unsigned long *len, struct file **srcp_file,
- struct ion_handle **srcp_ihdl)
+ int *p_need, struct ion_handle **srcp_ihdl)
{
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
@@ -1901,6 +1897,8 @@
#ifdef CONFIG_ANDROID_PMEM
unsigned long vstart;
#endif
+ *p_need = 0;
+
if (img->flags & MDP_BLIT_SRC_GEM) {
*srcp_file = NULL;
return kgsl_gem_obj_addr(img->memory_id, (int) img->priv,
@@ -1916,8 +1914,10 @@
fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
if (get_fb_phys_info(start, len, fb_num))
ret = -1;
- else
+ else {
*srcp_file = file;
+ *p_need = put_needed;
+ }
} else
ret = -1;
if (ret)
@@ -2034,9 +2034,7 @@
#define OVERLAY_720P_TILE_SIZE 0x0E6000
#define OVERLAY_WSVGA_SIZE 0x98000 /* 1024x608, align 600 to 32bit */
-#ifdef CONFIG_MSM_BUS_SCALING
#define OVERLAY_BUS_SCALE_TABLE_BASE 6
-#endif
static int mdp4_overlay_is_rgb_type(int format)
{
@@ -2058,7 +2056,7 @@
static uint32 mdp4_overlay_get_perf_level(struct mdp_overlay *req,
struct msm_fb_data_type *mfd)
{
- int is_fg;
+ int is_fg, i, cnt;
if (req->is_fg && ((req->alpha & 0x0ff) == 0xff))
is_fg = 1;
@@ -2069,9 +2067,10 @@
if (req->flags & MDP_DEINTERLACE)
return OVERLAY_PERF_LEVEL1;
- if (ctrl->plist[OVERLAY_PIPE_VG1].pipe_used &&
- ctrl->plist[OVERLAY_PIPE_VG2].pipe_used)
- return OVERLAY_PERF_LEVEL1;
+ for (i = 0, cnt = 0; i < OVERLAY_PIPE_MAX; i++) {
+ if (ctrl->plist[i].pipe_used && ++cnt > 2)
+ return OVERLAY_PERF_LEVEL1;
+ }
if (mdp4_overlay_is_rgb_type(req->src.format) && is_fg &&
((req->src.width * req->src.height) <= OVERLAY_WSVGA_SIZE))
@@ -2114,6 +2113,8 @@
if (old_perf_level != cur_perf_level) {
mdp_set_core_clk(cur_perf_level);
old_perf_level = cur_perf_level;
+ mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
+ - cur_perf_level);
}
}
@@ -2140,6 +2141,21 @@
mfd->ov0_blt_state = mfd->use_ov0_blt;
}
+static void mdp4_overlay1_update_blt_mode(struct msm_fb_data_type *mfd)
+{
+ if (mfd->ov1_blt_state == mfd->use_ov1_blt)
+ return;
+ if (mfd->use_ov1_blt) {
+ mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
+ mdp4_dtv_overlay_blt_start(mfd);
+ pr_debug("%s overlay1 writeback is enabled\n", __func__);
+ } else {
+ mdp4_dtv_overlay_blt_stop(mfd);
+ pr_debug("%s overlay1 writeback is disabled\n", __func__);
+ }
+ mfd->ov1_blt_state = mfd->use_ov1_blt;
+}
+
static u32 mdp4_overlay_blt_enable(struct mdp_overlay *req,
struct msm_fb_data_type *mfd, uint32 perf_level)
{
@@ -2150,7 +2166,8 @@
clk_rate = (&mfd->panel_info.mipi)->dsi_pclk_rate;
if ((mfd->panel_info.type == LCDC_PANEL) ||
- (mfd->panel_info.type == MIPI_VIDEO_PANEL))
+ (mfd->panel_info.type == MIPI_VIDEO_PANEL) ||
+ (mfd->panel_info.type == DTV_PANEL))
pull_mode = 1;
if (pull_mode && (req->src_rect.h > req->dst_rect.h ||
@@ -2169,7 +2186,8 @@
if (req->dst_rect.x != 0)
use_blt = 1;
}
- if (mfd->panel_info.xres > 1280)
+ if ((mfd->panel_info.xres > 1280) &&
+ (mfd->panel_info.type != DTV_PANEL))
use_blt = 1;
}
return use_blt;
@@ -2197,8 +2215,6 @@
return -EINTR;
}
- perf_level = mdp4_overlay_get_perf_level(req, mfd);
-
mixer = mfd->panel_info.pdest; /* DISPLAY_1 or DISPLAY_2 */
ret = mdp4_overlay_req2pipe(req, mixer, &pipe, mfd);
@@ -2209,6 +2225,8 @@
return ret;
}
+ perf_level = mdp4_overlay_get_perf_level(req, mfd);
+
if (mixer == MDP4_MIXER0) {
u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
mfd->use_ov0_blt &= ~(1 << (pipe->pipe_ndx-1));
@@ -2252,8 +2270,12 @@
}
if (ctrl->panel_mode & MDP4_PANEL_DTV &&
- pipe->mixer_num == MDP4_MIXER1)
+ pipe->mixer_num == MDP4_MIXER1) {
+ u32 use_blt = mdp4_overlay_blt_enable(req, mfd, perf_level);
mdp4_overlay_dtv_set(mfd, pipe);
+ mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
+ mfd->use_ov1_blt |= (use_blt << (pipe->pipe_ndx-1));
+ }
if (new_perf_level != perf_level) {
u32 old_level = new_perf_level;
@@ -2282,13 +2304,6 @@
}
mutex_unlock(&mfd->dma->ov_mutex);
-#ifdef CONFIG_MSM_BUS_SCALING
- if (pipe->mixer_num == MDP4_MIXER0) {
- mdp_bus_scale_update_request(OVERLAY_BUS_SCALE_TABLE_BASE
- - perf_level);
- }
-#endif
-
return 0;
}
@@ -2368,8 +2383,14 @@
if (!mfd->use_ov0_blt)
mdp4_free_writeback_buf(mfd, MDP4_MIXER0);
} else { /* mixer1, DTV, ATV */
- if (ctrl->panel_mode & MDP4_PANEL_DTV)
+ if (ctrl->panel_mode & MDP4_PANEL_DTV) {
mdp4_overlay_dtv_unset(mfd, pipe);
+ mfd->use_ov1_blt &= ~(1 << (pipe->pipe_ndx-1));
+ mdp4_overlay1_update_blt_mode(mfd);
+ if (!mfd->use_ov1_blt)
+ mdp4_free_writeback_buf(mfd,
+ MDP4_MIXER1);
+ }
}
}
@@ -2386,8 +2407,6 @@
mdp4_overlay_pipe_free(pipe);
- mdp4_set_perf_level();
-
mutex_unlock(&mfd->dma->ov_mutex);
return 0;
@@ -2448,6 +2467,9 @@
mdp4_mixer_stage_commit(pipe->mixer_num);
+ if (mfd->use_ov1_blt)
+ mdp4_overlay1_update_blt_mode(mfd);
+
mdp4_overlay_dtv_wait_for_ov(mfd, pipe);
mutex_unlock(&mfd->dma->ov_mutex);
@@ -2465,6 +2487,7 @@
struct file *srcp1_file = NULL, *srcp2_file = NULL;
struct ion_handle *srcp0_ihdl = NULL;
struct ion_handle *srcp1_ihdl = NULL, *srcp2_ihdl = NULL;
+ int ps0_need, p_need;
uint32_t overlay_version = 0;
int ret = 0;
@@ -2484,7 +2507,7 @@
return -EINTR;
img = &req->data;
- get_img(img, info, &start, &len, &srcp0_file, &srcp0_ihdl);
+ get_img(img, info, &start, &len, &srcp0_file, &ps0_need, &srcp0_ihdl);
if (len == 0) {
mutex_unlock(&mfd->dma->ov_mutex);
pr_err("%s: pmem Error\n", __func__);
@@ -2503,7 +2526,7 @@
if (overlay_version > 0) {
img = &req->plane1_data;
get_img(img, info, &start, &len, &srcp1_file,
- &srcp1_ihdl);
+ &p_need, &srcp1_ihdl);
if (len == 0) {
mutex_unlock(&mfd->dma->ov_mutex);
pr_err("%s: Error to get plane1\n", __func__);
@@ -2535,7 +2558,7 @@
if (overlay_version > 0) {
img = &req->plane1_data;
get_img(img, info, &start, &len, &srcp1_file,
- &srcp1_ihdl);
+ &p_need, &srcp1_ihdl);
if (len == 0) {
mutex_unlock(&mfd->dma->ov_mutex);
pr_err("%s: Error to get plane1\n", __func__);
@@ -2546,7 +2569,7 @@
img = &req->plane2_data;
get_img(img, info, &start, &len, &srcp2_file,
- &srcp2_ihdl);
+ &p_need, &srcp2_ihdl);
if (len == 0) {
mutex_unlock(&mfd->dma->ov_mutex);
pr_err("%s: Error to get plane2\n", __func__);
@@ -2589,6 +2612,9 @@
if (mfd->use_ov0_blt)
mdp4_overlay_update_blt_mode(mfd);
+ if (mfd->use_ov1_blt)
+ mdp4_overlay1_update_blt_mode(mfd);
+
if (pipe->pipe_type == OVERLAY_TYPE_VIDEO) {
mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
} else {
@@ -2614,8 +2640,11 @@
} else if (pipe->mixer_num == MDP4_MIXER1) {
ctrl->mixer1_played++;
/* enternal interface */
- if (ctrl->panel_mode & MDP4_PANEL_DTV)
+ if (ctrl->panel_mode & MDP4_PANEL_DTV) {
mdp4_overlay_dtv_ov_done_push(mfd, pipe);
+ if (!mfd->use_ov1_blt)
+ mdp4_overlay1_update_blt_mode(mfd);
+ }
} else {
/* primary interface */
@@ -2668,9 +2697,13 @@
if (srcp2_file)
put_pmem_file(srcp2_file);
#endif
+ /* only source may use frame buffer */
+ if (img->flags & MDP_MEMORY_ID_TYPE_FB)
+ fput_light(srcp0_file, ps0_need);
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
- if (!IS_ERR_OR_NULL(srcp0_ihdl))
+ else if (!IS_ERR_OR_NULL(srcp0_ihdl))
ion_free(mfd->iclient, srcp0_ihdl);
+
if (!IS_ERR_OR_NULL(srcp1_ihdl))
ion_free(mfd->iclient, srcp1_ihdl);
if (!IS_ERR_OR_NULL(srcp2_ihdl))
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 635b104..0b86028 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -102,12 +102,12 @@
var = &fbi->var;
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- if (is_mdp4_hw_reset()) {
- mdp4_hw_init();
- outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+ if (hdmi_prim_display) {
+ if (is_mdp4_hw_reset()) {
+ mdp4_hw_init();
+ outpdw(MDP_BASE + 0x0038, mdp4_display_intf);
+ }
}
-#endif
mdp4_overlay_dmae_cfg(mfd, 0);
/*
@@ -301,7 +301,7 @@
/* MSP_BORDER_COLOR */
MDP_OUTP(MDP_BASE + MDP4_OVERLAYPROC1_BASE + 0x5008,
(0x0 & 0xFFF)); /* 12-bit R */
- mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
} else {
switch (mfd->ibuf.bpp) {
case 2:
@@ -312,11 +312,10 @@
break;
case 4:
default:
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- pipe->src_format = MSMFB_DEFAULT_TYPE;
-#else
- pipe->src_format = MDP_ARGB_8888;
-#endif
+ if (hdmi_prim_display)
+ pipe->src_format = MSMFB_DEFAULT_TYPE;
+ else
+ pipe->src_format = MDP_ARGB_8888;
break;
}
}
@@ -355,7 +354,7 @@
if (pipe != NULL && pipe->mixer_stage == MDP4_MIXER_STAGE_BASE &&
pipe->pipe_type == OVERLAY_TYPE_RGB)
dtv_pipe = pipe; /* keep it */
- else if (mdp4_overlay_borderfill_supported())
+ else if (!hdmi_prim_display && mdp4_overlay_borderfill_supported())
mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_BF);
else
mdp4_overlay_dtv_alloc_pipe(mfd, OVERLAY_TYPE_RGB);
@@ -512,7 +511,6 @@
complete_all(&dtv_pipe->comp);
}
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
void mdp4_dtv_set_black_screen(void)
{
char *rgb_base;
@@ -520,8 +518,9 @@
uint32 color = 0x00000000;
uint32 temp_src_format;
- if (!dtv_pipe) {
- pr_err("dtv_pipe is not configured yet\n");
+ if (!dtv_pipe || !hdmi_prim_display) {
+ pr_err("dtv_pipe/hdmi as primary are not"
+ " configured yet\n");
return;
}
rgb_base = MDP_BASE + MDP4_RGB_BASE;
@@ -540,7 +539,6 @@
mdp4_mixer_stage_up(dtv_pipe);
mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
}
-#endif
static void mdp4_overlay_dtv_wait4dmae(struct msm_fb_data_type *mfd)
{
@@ -596,13 +594,11 @@
void mdp4_dtv_overlay_blt_start(struct msm_fb_data_type *mfd)
{
- mdp4_allocate_writeback_buf(mfd, MDP4_MIXER1);
mdp4_dtv_do_blt(mfd, 1);
}
void mdp4_dtv_overlay_blt_stop(struct msm_fb_data_type *mfd)
{
- mdp4_free_writeback_buf(mfd, MDP4_MIXER1);
mdp4_dtv_do_blt(mfd, 0);
}
diff --git a/drivers/video/msm/mipi_dsi.h b/drivers/video/msm/mipi_dsi.h
index 4fbb044..8a86fd2 100644
--- a/drivers/video/msm/mipi_dsi.h
+++ b/drivers/video/msm/mipi_dsi.h
@@ -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
@@ -51,7 +51,8 @@
#define MIPI_DSI_PANEL_QHD_PT 5
#define MIPI_DSI_PANEL_WXGA 6
#define MIPI_DSI_PANEL_WUXGA 7
-#define DSI_PANEL_MAX 7
+#define MIPI_DSI_PANEL_720P_PT 8
+#define DSI_PANEL_MAX 8
enum { /* mipi dsi panel */
DSI_VIDEO_MODE,
diff --git a/drivers/video/msm/mipi_orise.c b/drivers/video/msm/mipi_orise.c
new file mode 100644
index 0000000..2afbb9b6
--- /dev/null
+++ b/drivers/video/msm/mipi_orise.c
@@ -0,0 +1,194 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "msm_fb.h"
+#include "mipi_dsi.h"
+#include "mipi_orise.h"
+#include "mdp4.h"
+
+
+static struct mipi_dsi_panel_platform_data *mipi_orise_pdata;
+
+static struct dsi_buf orise_tx_buf;
+static struct dsi_buf orise_rx_buf;
+
+static char enter_sleep[2] = {0x10, 0x00}; /* DTYPE_DCS_WRITE */
+static char exit_sleep[2] = {0x11, 0x00}; /* DTYPE_DCS_WRITE */
+static char display_off[2] = {0x28, 0x00}; /* DTYPE_DCS_WRITE */
+static char display_on[2] = {0x29, 0x00}; /* DTYPE_DCS_WRITE */
+
+static struct dsi_cmd_desc orise_video_on_cmds[] = {
+ {DTYPE_DCS_WRITE, 1, 0, 0, 10,
+ sizeof(exit_sleep), exit_sleep},
+ {DTYPE_DCS_WRITE, 1, 0, 0, 10,
+ sizeof(display_on), display_on},
+};
+
+static struct dsi_cmd_desc orise_cmd_on_cmds[] = {
+ {DTYPE_DCS_WRITE, 1, 0, 0, 10,
+ sizeof(exit_sleep), exit_sleep},
+ {DTYPE_DCS_WRITE, 1, 0, 0, 10,
+ sizeof(display_on), display_on},
+};
+
+static struct dsi_cmd_desc orise_display_off_cmds[] = {
+ {DTYPE_DCS_WRITE, 1, 0, 0, 10,
+ sizeof(display_off), display_off},
+ {DTYPE_DCS_WRITE, 1, 0, 0, 120,
+ sizeof(enter_sleep), enter_sleep}
+};
+
+static int mipi_orise_lcd_on(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct mipi_panel_info *mipi;
+ struct msm_panel_info *pinfo;
+
+ mfd = platform_get_drvdata(pdev);
+ if (!mfd)
+ return -ENODEV;
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ pinfo = &mfd->panel_info;
+ mipi = &mfd->panel_info.mipi;
+
+ if (mipi->mode == DSI_VIDEO_MODE) {
+ mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_video_on_cmds,
+ ARRAY_SIZE(orise_video_on_cmds));
+ } else {
+ mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_cmd_on_cmds,
+ ARRAY_SIZE(orise_cmd_on_cmds));
+
+ mipi_dsi_cmd_bta_sw_trigger(); /* clean up ack_err_status */
+ }
+
+ return 0;
+}
+
+static int mipi_orise_lcd_off(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ mipi_dsi_cmds_tx(mfd, &orise_tx_buf, orise_display_off_cmds,
+ ARRAY_SIZE(orise_display_off_cmds));
+
+ return 0;
+}
+
+
+
+static int __devinit mipi_orise_lcd_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct mipi_panel_info *mipi;
+ struct platform_device *current_pdev;
+ static struct mipi_dsi_phy_ctrl *phy_settings;
+
+ if (pdev->id == 0) {
+ mipi_orise_pdata = pdev->dev.platform_data;
+
+ if (mipi_orise_pdata
+ && mipi_orise_pdata->phy_ctrl_settings) {
+ phy_settings = (mipi_orise_pdata->phy_ctrl_settings);
+ }
+
+ return 0;
+ }
+
+ current_pdev = msm_fb_add_device(pdev);
+
+ if (current_pdev) {
+ mfd = platform_get_drvdata(current_pdev);
+ if (!mfd)
+ return -ENODEV;
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ mipi = &mfd->panel_info.mipi;
+
+ if (phy_settings != NULL)
+ mipi->dsi_phy_db = phy_settings;
+ }
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = mipi_orise_lcd_probe,
+ .driver = {
+ .name = "mipi_orise",
+ },
+};
+
+static struct msm_fb_panel_data orise_panel_data = {
+ .on = mipi_orise_lcd_on,
+ .off = mipi_orise_lcd_off,
+};
+
+static int ch_used[3];
+
+int mipi_orise_device_register(struct msm_panel_info *pinfo,
+ u32 channel, u32 panel)
+{
+ struct platform_device *pdev = NULL;
+ int ret;
+
+ if ((channel >= 3) || ch_used[channel])
+ return -ENODEV;
+
+ ch_used[channel] = TRUE;
+
+ pdev = platform_device_alloc("mipi_orise", (panel << 8)|channel);
+ if (!pdev)
+ return -ENOMEM;
+
+ orise_panel_data.panel_info = *pinfo;
+
+ ret = platform_device_add_data(pdev, &orise_panel_data,
+ sizeof(orise_panel_data));
+ if (ret) {
+ printk(KERN_ERR
+ "%s: platform_device_add_data failed!\n", __func__);
+ goto err_device_put;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: platform_device_register failed!\n", __func__);
+ goto err_device_put;
+ }
+
+ return 0;
+
+err_device_put:
+ platform_device_put(pdev);
+ return ret;
+}
+
+static int __init mipi_orise_lcd_init(void)
+{
+ mipi_dsi_buf_alloc(&orise_tx_buf, DSI_BUF_SIZE);
+ mipi_dsi_buf_alloc(&orise_rx_buf, DSI_BUF_SIZE);
+
+ return platform_driver_register(&this_driver);
+}
+
+module_init(mipi_orise_lcd_init);
diff --git a/drivers/video/msm/mipi_orise.h b/drivers/video/msm/mipi_orise.h
new file mode 100644
index 0000000..1659479
--- /dev/null
+++ b/drivers/video/msm/mipi_orise.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 MIPI_ORISE_H
+#define MIPI_ORISE_H
+
+int mipi_orise_device_register(struct msm_panel_info *pinfo,
+ u32 channel, u32 panel);
+
+#endif /* MIPI_ORISE_H */
diff --git a/drivers/video/msm/mipi_orise_cmd_720p_pt.c b/drivers/video/msm/mipi_orise_cmd_720p_pt.c
new file mode 100644
index 0000000..c2a158d
--- /dev/null
+++ b/drivers/video/msm/mipi_orise_cmd_720p_pt.c
@@ -0,0 +1,96 @@
+/* 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_fb.h"
+#include "mipi_dsi.h"
+#include "mipi_orise.h"
+
+static struct msm_panel_info pinfo;
+
+static struct mipi_dsi_phy_ctrl dsi_cmd_mode_phy_db = {
+/* DSI_BIT_CLK at 507MHz, 4 lane, RGB888 */
+ {0x03, 0x0a, 0x04, 0x00, 0x20},
+ /* timing */
+ {0x8c, 0x34, 0x15, 0x00, 0x46, 0x50, 0x1a, 0x38,
+ 0x24, 0x03, 0x04, 0xa0},
+ /* phy ctrl */
+ {0x5f, 0x00, 0x00, 0x10},
+ /* strength */
+ {0xff, 0x00, 0x06, 0x00},
+ /* pll control */
+ {0x0, 0xf9, 0x30, 0xda, 0x00, 0x40, 0x03, 0x62,
+ 0x40, 0x07, 0x03,
+ 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 },
+};
+
+static int __init mipi_cmd_orise_720p_pt_init(void)
+{
+ int ret;
+
+ if (msm_fb_detect_client("mipi_cmd_orise_720p"))
+ return 0;
+
+ pinfo.xres = 720;
+ pinfo.yres = 1280;
+ pinfo.type = MIPI_CMD_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 24;
+ pinfo.lcdc.h_back_porch = 160;
+ pinfo.lcdc.h_front_porch = 160;
+ pinfo.lcdc.h_pulse_width = 8;
+ pinfo.lcdc.v_back_porch = 32;
+ pinfo.lcdc.v_front_porch = 32;
+ pinfo.lcdc.v_pulse_width = 1;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+ pinfo.bl_max = 200;
+ pinfo.bl_min = 1;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 507000000;
+ pinfo.lcd.vsync_enable = TRUE;
+ pinfo.lcd.hw_vsync_mode = TRUE;
+ pinfo.lcd.refx100 = 6000; /* adjust refx100 to prevent tearing */
+ pinfo.lcd.v_back_porch = 32;
+ pinfo.lcd.v_front_porch = 32;
+ pinfo.lcd.v_pulse_width = 1;
+
+ pinfo.mipi.mode = DSI_CMD_MODE;
+ pinfo.mipi.dst_format = DSI_CMD_DST_FORMAT_RGB888;
+ pinfo.mipi.vc = 0;
+ pinfo.mipi.data_lane0 = TRUE;
+ pinfo.mipi.data_lane1 = TRUE;
+ pinfo.mipi.data_lane2 = TRUE;
+ pinfo.mipi.data_lane3 = TRUE;
+ pinfo.mipi.t_clk_post = 0x04;
+ pinfo.mipi.t_clk_pre = 0x1e;
+ pinfo.mipi.stream = 0; /* dma_p */
+ pinfo.mipi.mdp_trigger = DSI_CMD_TRIGGER_NONE;
+ pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
+ pinfo.mipi.te_sel = 1; /* TE from vsycn gpio */
+ pinfo.mipi.interleave_max = 1;
+ pinfo.mipi.insert_dcs_cmd = TRUE;
+ pinfo.mipi.wr_mem_continue = 0x3c;
+ pinfo.mipi.wr_mem_start = 0x2c;
+ pinfo.mipi.dsi_phy_db = &dsi_cmd_mode_phy_db;
+
+ ret = mipi_orise_device_register(&pinfo, MIPI_DSI_PRIM,
+ MIPI_DSI_PANEL_720P_PT);
+ if (ret)
+ pr_err("%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(mipi_cmd_orise_720p_pt_init);
diff --git a/drivers/video/msm/mipi_orise_video_720p_pt.c b/drivers/video/msm/mipi_orise_video_720p_pt.c
new file mode 100644
index 0000000..629ff10
--- /dev/null
+++ b/drivers/video/msm/mipi_orise_video_720p_pt.c
@@ -0,0 +1,97 @@
+/* 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_fb.h"
+#include "mipi_dsi.h"
+#include "mipi_orise.h"
+
+static struct msm_panel_info pinfo;
+
+static struct mipi_dsi_phy_ctrl dsi_video_mode_phy_db = {
+ /* regulator */
+ {0x03, 0x0a, 0x04, 0x00, 0x20},
+ /* timing */
+ {0x83, 0x31, 0x13, 0x00, 0x42, 0x4d, 0x18, 0x35,
+ 0x21, 0x03, 0x04, 0xa0},
+ /* phy ctrl */
+ {0x5f, 0x00, 0x00, 0x10},
+ /* strength */
+ {0xff, 0x00, 0x06, 0x00},
+ /* pll control */
+ {0x0, 0x0e, 0x30, 0xc0, 0x00, 0x40, 0x03, 0x62,
+ 0x40, 0x07, 0x07,
+ 0x00, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x20, 0x00, 0x01 },
+};
+
+static int __init mipi_video_orise_720p_pt_init(void)
+{
+ int ret;
+
+ if (msm_fb_detect_client("mipi_video_orise_720p"))
+ return 0;
+
+ pinfo.xres = 720;
+ pinfo.yres = 1280;
+ pinfo.lcdc.xres_pad = 0;
+ pinfo.lcdc.yres_pad = 0;
+
+ pinfo.type = MIPI_VIDEO_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 24;
+ pinfo.lcdc.h_back_porch = 160;
+ pinfo.lcdc.h_front_porch = 160;
+ pinfo.lcdc.h_pulse_width = 8;
+ pinfo.lcdc.v_back_porch = 32;
+ pinfo.lcdc.v_front_porch = 32;
+ pinfo.lcdc.v_pulse_width = 1;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+ pinfo.bl_max = 200;
+ pinfo.bl_min = 1;
+ pinfo.fb_num = 2;
+
+ pinfo.mipi.mode = DSI_VIDEO_MODE;
+ pinfo.mipi.pulse_mode_hsa_he = TRUE;
+ pinfo.mipi.hfp_power_stop = TRUE;
+ pinfo.mipi.hbp_power_stop = TRUE;
+ pinfo.mipi.hsa_power_stop = FALSE;
+ pinfo.mipi.eof_bllp_power_stop = TRUE;
+ pinfo.mipi.bllp_power_stop = TRUE;
+ pinfo.mipi.traffic_mode = DSI_NON_BURST_SYNCH_EVENT;
+ pinfo.mipi.dst_format = DSI_VIDEO_DST_FORMAT_RGB888;
+ pinfo.mipi.vc = 0;
+ pinfo.mipi.rgb_swap = DSI_RGB_SWAP_RGB;
+ pinfo.mipi.data_lane0 = TRUE;
+ pinfo.mipi.data_lane1 = TRUE;
+ pinfo.mipi.data_lane2 = TRUE;
+ pinfo.mipi.data_lane3 = TRUE;
+ pinfo.mipi.t_clk_post = 0x04;
+ pinfo.mipi.t_clk_pre = 0x1c;
+ pinfo.mipi.stream = 0; /* dma_p */
+ pinfo.mipi.mdp_trigger = 0;
+ pinfo.mipi.dma_trigger = DSI_CMD_TRIGGER_SW;
+ pinfo.mipi.frame_rate = 55;
+ pinfo.mipi.dsi_phy_db = &dsi_video_mode_phy_db;
+ pinfo.mipi.tx_eot_append = TRUE;
+
+ ret = mipi_orise_device_register(&pinfo, MIPI_DSI_PRIM,
+ MIPI_DSI_PANEL_720P_PT);
+ if (ret)
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(mipi_video_orise_720p_pt_init);
diff --git a/drivers/video/msm/mipi_tc358764_dsi2lvds.c b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
index fcb5163..1624534 100644
--- a/drivers/video/msm/mipi_tc358764_dsi2lvds.c
+++ b/drivers/video/msm/mipi_tc358764_dsi2lvds.c
@@ -226,10 +226,14 @@
static u32 d2l_3d_gpio_enable;
static u32 d2l_3d_gpio_mode;
static int d2l_enable_3d;
+static struct i2c_client *d2l_i2c_client;
+static struct i2c_driver d2l_i2c_slave_driver;
static int mipi_d2l_init(void);
static int mipi_d2l_enable_3d(struct msm_fb_data_type *mfd,
bool enable, bool mode);
+static u32 d2l_i2c_read_reg(struct i2c_client *client, u16 reg);
+static u32 d2l_i2c_write_reg(struct i2c_client *client, u16 reg, u32 val);
/**
* Read a bridge register
@@ -296,6 +300,20 @@
mipi_d2l_read_reg(mfd, SYSSTAT); /* 0x500 */
}
+static void mipi_d2l_read_status_via_i2c(struct i2c_client *client)
+{
+ u32 tmp = 0;
+
+ tmp = d2l_i2c_read_reg(client, DSIERRCNT);
+ d2l_i2c_write_reg(client, DSIERRCNT, 0xFFFF0000);
+
+ d2l_i2c_read_reg(client, DSI_LANESTATUS0); /* 0x214 */
+ d2l_i2c_read_reg(client, DSI_LANESTATUS1); /* 0x218 */
+ d2l_i2c_read_reg(client, DSI_INTSTATUS); /* 0x220 */
+ d2l_i2c_read_reg(client, SYSSTAT); /* 0x500 */
+
+ d2l_i2c_write_reg(client, DSIERRCNT, tmp);
+}
/**
* Init the D2L bridge via the DSI interface for Video.
*
@@ -315,12 +333,19 @@
u32 vpctrl;
u32 htime1;
u32 vtime1;
+ u32 htime2;
+ u32 vtime2;
u32 ppi_tx_rx_ta; /* BTA Bus-Turn-Around */
u32 lvcfg;
u32 hbpr; /* Horizontal Back Porch */
u32 hpw; /* Horizontal Pulse Width */
u32 vbpr; /* Vertical Back Porch */
u32 vpw; /* Vertical Pulse Width */
+
+ u32 hfpr; /* Horizontal Front Porch */
+ u32 hsize; /* Horizontal Active size */
+ u32 vfpr; /* Vertical Front Porch */
+ u32 vsize; /* Vertical Active size */
bool vesa_rgb888 = false;
lanes_enable = 0x01; /* clock-lane enable */
@@ -345,8 +370,12 @@
return -EINVAL;
}
- pr_debug("%s.xres=%d.yres=%d.\n",
- __func__, mfd->panel_info.xres, mfd->panel_info.yres);
+ pr_debug("%s.xres=%d.yres=%d.fps=%d.dst_format=%d.\n",
+ __func__,
+ mfd->panel_info.xres,
+ mfd->panel_info.yres,
+ mfd->panel_info.mipi.frame_rate,
+ mfd->panel_info.mipi.dst_format);
hbpr = mfd->panel_info.lcdc.h_back_porch;
hpw = mfd->panel_info.lcdc.h_pulse_width;
@@ -355,6 +384,15 @@
htime1 = (hbpr << 16) + hpw;
vtime1 = (vbpr << 16) + vpw;
+
+ hfpr = mfd->panel_info.lcdc.h_front_porch;
+ hsize = mfd->panel_info.xres;
+ vfpr = mfd->panel_info.lcdc.v_front_porch;
+ vsize = mfd->panel_info.yres;
+
+ htime2 = (hfpr << 16) + hsize;
+ vtime2 = (vfpr << 16) + vsize;
+
lvcfg = 0x0003; /* PCLK=DCLK/3, Dual Link, LVEN */
vpctrl = 0x01000120; /* Output RGB888 , Event-Mode , */
ppi_tx_rx_ta = 0x00040004;
@@ -403,6 +441,8 @@
mipi_d2l_write_reg(mfd, VPCTRL, vpctrl); /* RGB888 + Event mode */
mipi_d2l_write_reg(mfd, HTIM1, htime1);
mipi_d2l_write_reg(mfd, VTIM1, vtime1);
+ mipi_d2l_write_reg(mfd, HTIM2, htime2);
+ mipi_d2l_write_reg(mfd, VTIM2, vtime2);
mipi_d2l_write_reg(mfd, VFUEN, 0x00000001);
mipi_d2l_write_reg(mfd, LVCFG, lvcfg); /* Enables LVDS tx */
@@ -539,6 +579,9 @@
mipi_d2l_enable_3d(mfd, false, false);
+ /* Add I2C driver only after DSI-CLK is running */
+ i2c_add_driver(&d2l_i2c_slave_driver);
+
pr_info("%s.ret=%d.\n", __func__, ret);
return ret;
@@ -589,6 +632,103 @@
.set_backlight = mipi_d2l_set_backlight,
};
+static u32 d2l_i2c_read_reg(struct i2c_client *client, u16 reg)
+{
+ int rc;
+ u32 val = 0;
+ u8 buf[6];
+
+ if (client == NULL) {
+ pr_err("%s.invalid i2c client.\n", __func__);
+ return -EINVAL;
+ }
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xFF;
+
+ rc = i2c_master_send(client, buf, sizeof(reg));
+ rc = i2c_master_recv(client, buf, 4);
+
+ if (rc >= 0) {
+ val = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24);
+ pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val);
+ } else
+ pr_err("%s.fail.reg=0x%x.\n", __func__, reg);
+
+ return val;
+}
+
+static u32 d2l_i2c_write_reg(struct i2c_client *client, u16 reg, u32 val)
+{
+ int rc;
+ u8 buf[6];
+
+ if (client == NULL) {
+ pr_err("%s.invalid i2c client.\n", __func__);
+ return -EINVAL;
+ }
+
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xFF;
+
+ buf[2] = (val >> 0) & 0xFF;
+ buf[3] = (val >> 8) & 0xFF;
+ buf[4] = (val >> 16) & 0xFF;
+ buf[5] = (val >> 24) & 0xFF;
+
+ rc = i2c_master_send(client, buf, sizeof(buf));
+
+ if (rc >= 0)
+ pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val);
+ else
+ pr_err("%s.fail.reg=0x%x.\n", __func__, reg);
+
+ return val;
+}
+
+static int __devinit d2l_i2c_slave_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ static const u32 i2c_funcs = I2C_FUNC_I2C;
+
+ d2l_i2c_client = client;
+
+ if (!i2c_check_functionality(client->adapter, i2c_funcs)) {
+ pr_err("%s.i2c_check_functionality failed.\n", __func__);
+ return -ENOSYS;
+ } else {
+ pr_debug("%s.i2c_check_functionality OK.\n", __func__);
+ }
+
+ d2l_i2c_read_reg(client, IDREG);
+
+ mipi_d2l_read_status_via_i2c(d2l_i2c_client);
+
+ return 0;
+}
+
+static __devexit int d2l_i2c_slave_remove(struct i2c_client *client)
+{
+ d2l_i2c_client = NULL;
+
+ return 0;
+}
+
+static const struct i2c_device_id d2l_i2c_id[] = {
+ {"tc358764-i2c", 0},
+ {}
+};
+
+static struct i2c_driver d2l_i2c_slave_driver = {
+ .driver = {
+ .name = "tc358764-i2c",
+ .owner = THIS_MODULE
+ },
+ .probe = d2l_i2c_slave_probe,
+ .remove = __devexit_p(d2l_i2c_slave_remove),
+ .id_table = d2l_i2c_id,
+};
+
static int mipi_d2l_enable_3d(struct msm_fb_data_type *mfd,
bool enable, bool mode)
{
@@ -630,6 +770,8 @@
mipi_d2l_enable_3d(d2l_mfd, true, false);
else if (data == 0)
mipi_d2l_enable_3d(d2l_mfd, false, false);
+ else if (data == 9)
+ mipi_d2l_read_status_via_i2c(d2l_i2c_client);
else
pr_err("%s.Invalid value=%d.\n", __func__, data);
}
diff --git a/drivers/video/msm/msm_dss_io_8960.c b/drivers/video/msm/msm_dss_io_8960.c
index 3b000ec..0f40c77 100644
--- a/drivers/video/msm/msm_dss_io_8960.c
+++ b/drivers/video/msm/msm_dss_io_8960.c
@@ -11,6 +11,7 @@
*
*/
#include <linux/clk.h>
+#include <mach/clk.h>
#include "msm_fb.h"
#include "mdp.h"
#include "mdp4.h"
@@ -634,6 +635,10 @@
hdmi_msm_clk(0);
udelay(5);
hdmi_msm_clk(1);
+
+ clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_ASSERT);
+ udelay(20);
+ clk_reset(hdmi_msm_state->hdmi_app_clk, CLK_RESET_DEASSERT);
}
void hdmi_msm_init_phy(int video_format)
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 593f10b..8ff1c75 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -188,12 +188,8 @@
};
#endif
-#define PANEL_NAME_MAX_LEN 30
static struct msm_fb_platform_data *msm_fb_pdata;
-static char prim_panel_name[PANEL_NAME_MAX_LEN];
-static char ext_panel_name[PANEL_NAME_MAX_LEN];
-module_param_string(prim_display, prim_panel_name, sizeof(prim_panel_name) , 0);
-module_param_string(ext_display, ext_panel_name, sizeof(ext_panel_name) , 0);
+unsigned char hdmi_prim_display;
int msm_fb_detect_client(const char *name)
{
@@ -202,19 +198,28 @@
#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
u32 id;
#endif
+ if (!msm_fb_pdata)
+ return -EPERM;
+
len = strnlen(name, PANEL_NAME_MAX_LEN);
- if (strnlen(prim_panel_name, PANEL_NAME_MAX_LEN)) {
- MSM_FB_DEBUG("\n name = %s, prim_display = %s",
- name, prim_panel_name);
- if (!strncmp((char *)prim_panel_name, name, len))
+ if (strnlen(msm_fb_pdata->prim_panel_name, PANEL_NAME_MAX_LEN)) {
+ pr_err("\n name = %s, prim_display = %s",
+ name, msm_fb_pdata->prim_panel_name);
+ if (!strncmp((char *)msm_fb_pdata->prim_panel_name,
+ name, len)) {
+ if (!strncmp((char *)msm_fb_pdata->prim_panel_name,
+ "hdmi_msm", len))
+ hdmi_prim_display = 1;
return 0;
- else
+ } else {
ret = -EPERM;
+ }
}
- if (strnlen(ext_panel_name, PANEL_NAME_MAX_LEN)) {
- MSM_FB_DEBUG("\n name = %s, ext_display = %s",
- name, ext_panel_name);
- if (!strncmp((char *)ext_panel_name, name, len))
+
+ if (strnlen(msm_fb_pdata->ext_panel_name, PANEL_NAME_MAX_LEN)) {
+ pr_err("\n name = %s, ext_display = %s",
+ name, msm_fb_pdata->ext_panel_name);
+ if (!strncmp((char *)msm_fb_pdata->ext_panel_name, name, len))
return 0;
else
ret = -EPERM;
@@ -1549,6 +1554,7 @@
static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int hole_offset;
if (var->rotate != FB_ROTATE_UR)
return -EINVAL;
@@ -1643,7 +1649,20 @@
if (var->xoffset > (var->xres_virtual - var->xres))
return -EINVAL;
- if (var->yoffset > (var->yres_virtual - var->yres))
+ if (!mfd->panel_info.mode2_yres)
+ hole_offset = (mfd->fbi->fix.line_length *
+ mfd->panel_info.yres) % PAGE_SIZE;
+ else
+ hole_offset = (mfd->fbi->fix.line_length *
+ mfd->panel_info.mode2_yres) % PAGE_SIZE;
+
+ if (!hole_offset) {
+ hole_offset = PAGE_SIZE - hole_offset;
+ hole_offset = hole_offset/mfd->fbi->fix.line_length;
+ }
+
+ if (var->yoffset > (var->yres_virtual - var->yres + (hole_offset *
+ (mfd->fb_page - 1))))
return -EINVAL;
return 0;
@@ -3375,11 +3394,10 @@
*/
if (type == HDMI_PANEL || type == DTV_PANEL ||
type == TV_PANEL || type == WRITEBACK_PANEL) {
-#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
- pdata->panel_info.fb_num = 2;
-#else
- pdata->panel_info.fb_num = 1;
-#endif
+ if (hdmi_prim_display)
+ pdata->panel_info.fb_num = 2;
+ else
+ pdata->panel_info.fb_num = 1;
}
else
pdata->panel_info.fb_num = MSM_FB_NUM;
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 9837f07..a4b46ea 100644
--- a/drivers/video/msm/msm_fb.h
+++ b/drivers/video/msm/msm_fb.h
@@ -177,6 +177,7 @@
u32 mem_hid;
u32 mdp_rev;
u32 use_ov0_blt, ov0_blt_state;
+ u32 use_ov1_blt, ov1_blt_state;
u32 writeback_state;
};
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
index 3f54756..267e924 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_metadata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 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
@@ -246,6 +246,8 @@
DDL_METADATA_ALIGNSIZE(suffix);
encoder->suffix = suffix;
encoder->output_buf_req.sz += suffix;
+ encoder->output_buf_req.sz =
+ DDL_ALIGN(encoder->output_buf_req.sz, DDL_KILO_BYTE(4));
}
u32 ddl_set_metadata_params(struct ddl_client_context *ddl,
@@ -454,6 +456,7 @@
return;
}
out_frame->flags |= VCD_FRAME_FLAG_EXTRADATA;
+ DDL_MSG_LOW("processing metadata for encoder");
start_addr = (u32) ((u8 *)out_frame->virtual + out_frame->offset);
qfiller = (u32 *)((out_frame->data_len +
start_addr + 3) & ~3);
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 51a72c8..444db9f 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_properties.c
@@ -915,10 +915,15 @@
}
case VCD_I_METADATA_ENABLE:
case VCD_I_METADATA_HEADER:
- DDL_MSG_ERROR("Meta Data Interface is Requested");
- vcd_status = ddl_set_metadata_params(ddl, property_hdr,
- property_value);
- vcd_status = VCD_S_SUCCESS;
+ DDL_MSG_LOW("Meta Data Interface is Requested");
+ if (!res_trk_check_for_sec_session()) {
+ vcd_status = ddl_set_metadata_params(ddl,
+ property_hdr, property_value);
+ } else {
+ DDL_MSG_ERROR("Meta Data Interface is not "
+ "supported in secure session");
+ vcd_status = VCD_ERR_ILLEGAL_OP;
+ }
break;
case VCD_I_META_BUFFER_MODE:
vcd_status = VCD_S_SUCCESS;
@@ -1836,8 +1841,16 @@
/*original_buf_req->align <= req_buf_req->align,*/
original_buf_req->sz <= req_buf_req->sz)
status = true;
- else
+ else {
DDL_MSG_ERROR("ddl_valid_buf_req:Failed");
+ DDL_MSG_ERROR("codec_buf_req: min_cnt=%d, mx_cnt=%d, "
+ "align=%d, sz=%d\n", original_buf_req->min_count,
+ original_buf_req->max_count, original_buf_req->align,
+ original_buf_req->sz);
+ DDL_MSG_ERROR("client_buffs: actual_count=%d, align=%d, "
+ "sz=%d\n", req_buf_req->actual_count,
+ req_buf_req->align, req_buf_req->sz);
+ }
return status;
}
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 8851b52..2f26e01 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
@@ -740,16 +740,26 @@
mutex_unlock(&resource_context.secure_lock);
return rc;
}
+
+void res_trk_secure_unset(void)
+{
+ mutex_lock(&resource_context.secure_lock);
+ resource_context.secure_session = 0;
+ mutex_unlock(&resource_context.secure_lock);
+}
+
+void res_trk_secure_set(void)
+{
+ mutex_lock(&resource_context.secure_lock);
+ resource_context.secure_session = 1;
+ mutex_unlock(&resource_context.secure_lock);
+}
+
int res_trk_open_secure_session()
{
int rc;
mutex_lock(&resource_context.secure_lock);
- if (resource_context.secure_session) {
- pr_err("Secure session already open");
- rc = -EBUSY;
- goto error_open;
- }
- resource_context.secure_session = 1;
+
rc = res_trk_enable_iommu_clocks();
if (rc) {
pr_err("IOMMU clock enabled failed while open");
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
index f91ddb5..9975573 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker_api.h
@@ -40,4 +40,6 @@
int res_trk_check_for_sec_session(void);
int res_trk_open_secure_session(void);
int res_trk_close_secure_session(void);
+void res_trk_secure_set(void);
+void res_trk_secure_unset(void);
#endif
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
index 86bf397..bd0d94e 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker.c
@@ -734,6 +734,16 @@
return 0;
}
+void res_trk_secure_unset(void)
+{
+ return;
+}
+
+void res_trk_secure_set(void)
+{
+ return;
+}
+
int res_trk_open_secure_session()
{
return -EINVAL;
diff --git a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
index 237d143..898195a 100644
--- a/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
+++ b/drivers/video/msm/vidc/720p/resource_tracker/vcd_res_tracker_api.h
@@ -35,4 +35,6 @@
int res_trk_check_for_sec_session(void);
int res_trk_open_secure_session(void);
int res_trk_close_secure_session(void);
+void res_trk_secure_set(void);
+void res_trk_secure_unset(void);
#endif
diff --git a/drivers/video/msm/vidc/common/dec/vdec.c b/drivers/video/msm/vidc/common/dec/vdec.c
index f685cd5..cffb0a9 100644
--- a/drivers/video/msm/vidc/common/dec/vdec.c
+++ b/drivers/video/msm/vidc/common/dec/vdec.c
@@ -2073,19 +2073,24 @@
mutex_unlock(&vid_dec_device_p->lock);
return -ENODEV;
}
- if (res_trk_open_secure_session()) {
- ERR("Secure session operation failure\n");
- mutex_unlock(&vid_dec_device_p->lock);
- return -ENODEV;
- }
+ res_trk_secure_set();
file->private_data = vid_dec_open_client();
if (!file->private_data) {
- res_trk_close_secure_session();
- mutex_unlock(&vid_dec_device_p->lock);
- return -ENODEV;
+ goto error;
+ }
+
+ if (res_trk_open_secure_session()) {
+ ERR("Secure session operation failure\n");
+ goto error;
}
mutex_unlock(&vid_dec_device_p->lock);
return 0;
+
+error:
+ res_trk_secure_unset();
+ mutex_unlock(&vid_dec_device_p->lock);
+ return -ENODEV;
+
}
static int vid_dec_open(struct inode *inode, struct file *file)
@@ -2113,8 +2118,8 @@
INFO("msm_vidc_dec: Inside %s()", __func__);
vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT);
vidc_cleanup_addr_table(client_ctx, BUFFER_TYPE_INPUT);
- vid_dec_close_client(client_ctx);
res_trk_close_secure_session();
+ vid_dec_close_client(client_ctx);
vidc_release_firmware();
#ifndef USE_RES_TRACKER
vidc_disable_clk();
diff --git a/drivers/video/msm/vidc/common/enc/venc.c b/drivers/video/msm/vidc/common/enc/venc.c
index 6d6dcdc..3c25751fa 100644
--- a/drivers/video/msm/vidc/common/enc/venc.c
+++ b/drivers/video/msm/vidc/common/enc/venc.c
@@ -1575,6 +1575,34 @@
}
break;
}
+ case VEN_IOCTL_SET_EXTRADATA:
+ case VEN_IOCTL_GET_EXTRADATA:
+ {
+ u32 extradata_flag;
+ DBG("VEN_IOCTL_(G)SET_EXTRADATA\n");
+ if (copy_from_user(&venc_msg, arg, sizeof(venc_msg)))
+ return -EFAULT;
+ if (cmd == VEN_IOCTL_SET_EXTRADATA) {
+ if (copy_from_user(&extradata_flag, venc_msg.in,
+ sizeof(u32)))
+ return -EFAULT;
+ result = vid_enc_set_get_extradata(client_ctx,
+ &extradata_flag, true);
+ } else {
+ result = vid_enc_set_get_extradata(client_ctx,
+ &extradata_flag, false);
+ if (result) {
+ if (copy_to_user(venc_msg.out, &extradata_flag,
+ sizeof(u32)))
+ return -EFAULT;
+ }
+ }
+ if (!result) {
+ ERR("setting VEN_IOCTL_(G)SET_LIVE_MODE failed\n");
+ return -EIO;
+ }
+ break;
+ }
case VEN_IOCTL_SET_AC_PREDICTION:
case VEN_IOCTL_GET_AC_PREDICTION:
case VEN_IOCTL_SET_RVLC:
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index f362f7b..cac5dc4 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.c
@@ -316,6 +316,42 @@
return true;
}
+u32 vid_enc_set_get_extradata(struct video_client_ctx *client_ctx,
+ u32 *extradata_flag, u32 set_flag)
+{
+ struct vcd_property_hdr vcd_property_hdr;
+ struct vcd_property_meta_data_enable vcd_meta_data;
+ u32 vcd_status = VCD_ERR_FAIL;
+ if (!client_ctx || !extradata_flag)
+ return false;
+ vcd_property_hdr.prop_id = VCD_I_METADATA_ENABLE;
+ vcd_property_hdr.sz = sizeof(struct vcd_property_meta_data_enable);
+ if (set_flag) {
+ DBG("vcd_set_property: VCD_I_METADATA_ENABLE = %d\n",
+ *extradata_flag);
+ vcd_meta_data.meta_data_enable_flag = *extradata_flag;
+ vcd_status = vcd_set_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_meta_data);
+ if (vcd_status) {
+ ERR("%s(): Set VCD_I_METADATA_ENABLE Failed\n",
+ __func__);
+ return false;
+ }
+ } else {
+ vcd_status = vcd_get_property(client_ctx->vcd_handle,
+ &vcd_property_hdr, &vcd_meta_data);
+ if (vcd_status) {
+ ERR("%s(): Get VCD_I_METADATA_ENABLE Failed\n",
+ __func__);
+ return false;
+ }
+ *extradata_flag = vcd_meta_data.meta_data_enable_flag;
+ DBG("vcd_get_property: VCD_I_METADATA_ENABLE = %d\n",
+ *extradata_flag);
+ }
+ return true;
+}
+
u32 vid_enc_set_get_framerate(struct video_client_ctx *client_ctx,
struct venc_framerate *frame_rate, u32 set_flag)
{
@@ -1494,6 +1530,11 @@
venc_buf_req->alignment = buffer_req.align;
venc_buf_req->bufpoolid = buffer_req.buf_pool_id;
venc_buf_req->suffixsize = 0;
+ DBG("%s: actual_count=%d, align=%d, sz=%d, min_count=%d, "
+ "max_count=%d, buf_pool_id=%d\n", __func__,
+ buffer_req.actual_count, buffer_req.align,
+ buffer_req.sz, buffer_req.min_count,
+ buffer_req.max_count, buffer_req.buf_pool_id);
}
return status;
}
@@ -1521,6 +1562,11 @@
buffer_req.align = venc_buf_req->alignment;
buffer_req.buf_pool_id = 0;
+ DBG("%s: actual_count=%d, align=%d, sz=%d, min_count=%d, "
+ "max_count=%d, buf_pool_id=%d\n", __func__,
+ buffer_req.actual_count, buffer_req.align, buffer_req.sz,
+ buffer_req.min_count, buffer_req.max_count,
+ buffer_req.buf_pool_id);
vcd_status = vcd_set_buffer_requirements(client_ctx->vcd_handle,
buffer, &buffer_req);
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.h b/drivers/video/msm/vidc/common/enc/venc_internal.h
index a07f7ab..8a07fdb 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.h
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.h
@@ -68,6 +68,9 @@
u32 vid_enc_set_get_live_mode(struct video_client_ctx *client_ctx,
struct venc_switch *encoder_switch, u32 set_flag);
+u32 vid_enc_set_get_extradata(struct video_client_ctx *client_ctx,
+ u32 *extradata_flag, u32 set_flag);
+
u32 vid_enc_set_get_short_header(struct video_client_ctx *client_ctx,
struct venc_switch *encoder_switch, u32 set_flag);
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index 1cb5401..5d3a6a1 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -36,23 +36,11 @@
#define DIAG_IOCTL_GET_DELAYED_RSP_ID 8
#define DIAG_IOCTL_LSM_DEINIT 9
-/* Machine ID and corresponding PC Tools IDs */
-#define APQ8060_MACHINE_ID 86
-#define AO8960_MACHINE_ID 87
-#define MSM8660_MACHINE_ID 71
-#define MDM9615_MACHINE_ID 104
-#define APQ8064_MACHINE_ID 109
-#define MSM8930_MACHINE_ID 116
-#define MSM8630_MACHINE_ID 117
-#define MSM8230_MACHINE_ID 118
-#define APQ8030_MACHINE_ID 119
-#define MSM8627_MACHINE_ID 120
-#define MSM8227_MACHINE_ID 121
-#define MSM8260A_MACHINE_ID 123
-#define MSM8974_MACHINE_ID 126
+/* PC Tools IDs */
#define APQ8060_TOOLS_ID 4062
#define AO8960_TOOLS_ID 4064
#define APQ8064_TOOLS_ID 4072
+#define MSM8625_TOOLS_ID 4075
#define MSM8930_TOOLS_ID 4076
#define MSM8630_TOOLS_ID 4077
#define MSM8230_TOOLS_ID 4078
@@ -114,11 +102,11 @@
/* This needs to be modified manually now, when we add
a new RANGE of SSIDs to the msg_mask_tbl */
-#define MSG_MASK_TBL_CNT 19
+#define MSG_MASK_TBL_CNT 23
#define EVENT_LAST_ID 0x083F
#define MSG_SSID_0 0
-#define MSG_SSID_0_LAST 68
+#define MSG_SSID_0_LAST 90
#define MSG_SSID_1 500
#define MSG_SSID_1_LAST 506
#define MSG_SSID_2 1000
@@ -126,19 +114,19 @@
#define MSG_SSID_3 2000
#define MSG_SSID_3_LAST 2008
#define MSG_SSID_4 3000
-#define MSG_SSID_4_LAST 3012
+#define MSG_SSID_4_LAST 3014
#define MSG_SSID_5 4000
#define MSG_SSID_5_LAST 4010
#define MSG_SSID_6 4500
#define MSG_SSID_6_LAST 4526
#define MSG_SSID_7 4600
-#define MSG_SSID_7_LAST 4611
+#define MSG_SSID_7_LAST 4612
#define MSG_SSID_8 5000
-#define MSG_SSID_8_LAST 5024
+#define MSG_SSID_8_LAST 5029
#define MSG_SSID_9 5500
-#define MSG_SSID_9_LAST 5514
+#define MSG_SSID_9_LAST 5516
#define MSG_SSID_10 6000
-#define MSG_SSID_10_LAST 6050
+#define MSG_SSID_10_LAST 6072
#define MSG_SSID_11 6500
#define MSG_SSID_11_LAST 6521
#define MSG_SSID_12 7000
@@ -155,6 +143,14 @@
#define MSG_SSID_17_LAST 9008
#define MSG_SSID_18 9500
#define MSG_SSID_18_LAST 9509
+#define MSG_SSID_19 10200
+#define MSG_SSID_19_LAST 10210
+#define MSG_SSID_20 10251
+#define MSG_SSID_20_LAST 10255
+#define MSG_SSID_21 10300
+#define MSG_SSID_21_LAST 10300
+#define MSG_SSID_22 10350
+#define MSG_SSID_22_LAST 10361
struct diagpkt_delay_params {
void *rsp_ptr;
@@ -249,6 +245,28 @@
MSG_LVL_MED,
MSG_LVL_LOW,
MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
+ MSG_LVL_MED,
+ MSG_LVL_LOW|MSG_LVL_MED|MSG_LVL_HIGH|MSG_LVL_ERROR|MSG_LVL_FATAL,
+ MSG_LVL_LOW,
+ MSG_LVL_MED,
+ MSG_LVL_LOW
};
static const uint32_t msg_bld_masks_1[] = {
@@ -258,7 +276,7 @@
MSG_LVL_LOW,
MSG_LVL_HIGH,
MSG_LVL_HIGH,
- MSG_LVL_HIGH,
+ MSG_LVL_HIGH
};
static const uint32_t msg_bld_masks_2[] = {
@@ -297,7 +315,9 @@
MSG_LVL_HIGH,
MSG_LVL_HIGH,
MSG_LVL_HIGH,
- MSG_LVL_HIGH
+ MSG_LVL_HIGH,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW
};
static const uint32_t msg_bld_masks_5[] = {
@@ -310,7 +330,8 @@
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
- MSG_LVL_MED,
+ MSG_LVL_MED|MSG_LVL_MED|MSG_MASK_5|MSG_MASK_6|MSG_MASK_7| \
+ MSG_MASK_8|MSG_MASK_9,
MSG_LVL_MED
};
@@ -357,6 +378,7 @@
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
+ MSG_LVL_LOW
};
static const uint32_t msg_bld_masks_8[] = {
@@ -385,6 +407,11 @@
MSG_LVL_MED,
MSG_LVL_MED,
MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED
};
static const uint32_t msg_bld_masks_9[] = {
@@ -403,6 +430,8 @@
MSG_LVL_MED|MSG_MASK_5,
MSG_LVL_MED|MSG_MASK_5,
MSG_LVL_MED|MSG_MASK_5,
+ MSG_LVL_MED|MSG_MASK_5,
+ MSG_LVL_MED|MSG_MASK_5
};
static const uint32_t msg_bld_masks_10[] = {
@@ -462,6 +491,28 @@
MSG_LVL_LOW,
MSG_LVL_LOW,
MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_MED,
+ MSG_LVL_LOW
};
static const uint32_t msg_bld_masks_11[] = {
@@ -584,6 +635,47 @@
MSG_LVL_LOW
};
+static const uint32_t msg_bld_masks_19[] = {
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW
+};
+
+static const uint32_t msg_bld_masks_20[] = {
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW,
+ MSG_LVL_LOW
+};
+
+static const uint32_t msg_bld_masks_21[] = {
+ MSG_LVL_HIGH
+};
+
+static const uint32_t msg_bld_masks_22[] = {
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH,
+ MSG_LVL_HIGH
+};
+
/* LOG CODES */
#define LOG_0 0x0
diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/i2c/atmel_mxt_ts.h
index 500ee6b..a2391e3 100644
--- a/include/linux/i2c/atmel_mxt_ts.h
+++ b/include/linux/i2c/atmel_mxt_ts.h
@@ -29,6 +29,12 @@
/* MXT_TOUCH_KEYARRAY_T15 */
#define MXT_KEYARRAY_MAX_KEYS 32
+/* Bootoader IDs */
+#define MXT_BOOTLOADER_ID_224 0x0A
+#define MXT_BOOTLOADER_ID_224E 0x06
+#define MXT_BOOTLOADER_ID_1386 0x01
+#define MXT_BOOTLOADER_ID_1386E 0x10
+
/* Config data for a given maXTouch controller with a specific firmware */
struct mxt_config_info {
const u8 *config;
@@ -37,6 +43,9 @@
u8 variant_id;
u8 version;
u8 build;
+ u8 bootldr_id;
+ /* Points to the firmware name to be upgraded to */
+ const char *fw_name;
};
/* The platform data for the Atmel maXTouch touchscreen driver */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index caed2a2..ca1f198f 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -493,6 +493,23 @@
*/
int msm_ion_unsecure_heap(int heap_id);
+/**
+ * msm_ion_do_cache_op - do cache operations.
+ *
+ * @client - pointer to ION client.
+ * @handle - pointer to buffer handle.
+ * @vaddr - virtual address to operate on.
+ * @len - Length of data to do cache operation on.
+ * @cmd - Cache operation to perform:
+ * ION_IOC_CLEAN_CACHES
+ * ION_IOC_INV_CACHES
+ * ION_IOC_CLEAN_INV_CACHES
+ *
+ * Returns 0 on success
+ */
+int msm_ion_do_cache_op(struct ion_client *client, struct ion_handle *handle,
+ void *vaddr, unsigned long len, unsigned int cmd);
+
#else
static inline struct ion_client *ion_client_create(struct ion_device *dev,
unsigned int heap_mask, const char *name)
@@ -604,6 +621,14 @@
{
return -ENODEV;
}
+
+static inline int msm_ion_do_cache_op(struct ion_client *client,
+ struct ion_handle *handle, void *vaddr,
+ unsigned long len, unsigned int cmd)
+{
+ return -ENODEV;
+}
+
#endif /* CONFIG_ION */
#endif /* __KERNEL__ */
diff --git a/include/linux/libra_sdioif.h b/include/linux/libra_sdioif.h
index 965e2b5..08be83a 100644
--- a/include/linux/libra_sdioif.h
+++ b/include/linux/libra_sdioif.h
@@ -35,6 +35,7 @@
typedef int (suspend_handler_t)(struct sdio_func *);
typedef void (resume_handler_t)(struct sdio_func *);
+int libra_enable_sdio_irq_in_chip(struct sdio_func *func, u8 enable);
int libra_sdio_configure(sdio_irq_handler_t libra_sdio_rxhandler,
void (*func_drv_fn)(int *status),
u32 funcdrv_timeout, u32 blksize);
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
index 1e1fe6c..78fbed3 100644
--- a/include/linux/mfd/pm8xxx/irq.h
+++ b/include/linux/mfd/pm8xxx/irq.h
@@ -39,21 +39,20 @@
#ifdef CONFIG_MFD_PM8XXX_IRQ
int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq);
-struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
+struct pm_irq_chip *pm8xxx_irq_init(struct device *dev,
const struct pm8xxx_irq_platform_data *pdata);
-int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip);
+int pm8xxx_irq_exit(struct pm_irq_chip *chip);
#else
static inline int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
{
return -ENXIO;
}
-static inline struct pm_irq_chip * __devinit pm8xxx_irq_init(
- const struct device *dev,
+static inline struct pm_irq_chip *pm8xxx_irq_init(const struct device *dev,
const struct pm8xxx_irq_platform_data *pdata)
{
return ERR_PTR(-ENXIO);
}
-static inline int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+static inline int pm8xxx_irq_exit(struct pm_irq_chip *chip)
{
return -ENXIO;
}
diff --git a/include/linux/mfd/wcd9xxx/wcd9310_registers.h b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
index d2736ea..67c2a6b 100644
--- a/include/linux/mfd/wcd9xxx/wcd9310_registers.h
+++ b/include/linux/mfd/wcd9xxx/wcd9310_registers.h
@@ -897,6 +897,38 @@
#define TABLA_A_CDC_DEBUG_B5_CTL__POR (0x00000000)
#define TABLA_A_CDC_DEBUG_B6_CTL (0x0000036D)
#define TABLA_A_CDC_DEBUG_B6_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B1_CTL (0x00000370)
+#define TABLA_A_CDC_COMP1_B1_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B2_CTL (0x00000371)
+#define TABLA_A_CDC_COMP1_B2_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B3_CTL (0x00000372)
+#define TABLA_A_CDC_COMP1_B3_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B4_CTL (0x00000373)
+#define TABLA_A_CDC_COMP1_B4_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B5_CTL (0x00000374)
+#define TABLA_A_CDC_COMP1_B5_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_B6_CTL (0x00000375)
+#define TABLA_A_CDC_COMP1_B6_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS (0x00000376)
+#define TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS__POR (0x00000000)
+#define TABLA_A_CDC_COMP1_FS_CFG (0x00000377)
+#define TABLA_A_CDC_COMP1_FS_CFG__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B1_CTL (0x00000378)
+#define TABLA_A_CDC_COMP2_B1_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B2_CTL (0x00000379)
+#define TABLA_A_CDC_COMP2_B2_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B3_CTL (0x0000037A)
+#define TABLA_A_CDC_COMP2_B3_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B4_CTL (0x0000037B)
+#define TABLA_A_CDC_COMP2_B4_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B5_CTL (0x0000037C)
+#define TABLA_A_CDC_COMP2_B5_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_B6_CTL (0x0000037D)
+#define TABLA_A_CDC_COMP2_B6_CTL__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS (0x0000037E)
+#define TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS__POR (0x00000000)
+#define TABLA_A_CDC_COMP2_FS_CFG (0x0000037F)
+#define TABLA_A_CDC_COMP2_FS_CFG__POR (0x00000000)
#define TABLA_A_CDC_CONN_RX1_B1_CTL (0x00000380)
#define TABLA_A_CDC_CONN_RX1_B1_CTL__POR (0x00000000)
#define TABLA_A_CDC_CONN_RX1_B2_CTL (0x00000381)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index ff53742..dedbe5c 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -190,6 +190,7 @@
#define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */
#define MMC_CARD_SDXC (1<<6) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */
+#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
@@ -328,6 +329,7 @@
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_hs200(c) ((c)->state & MMC_STATE_HIGHSPEED_200)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
@@ -337,6 +339,7 @@
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_hs200(c) ((c)->state |= MMC_STATE_HIGHSPEED_200)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 35137d6..73a68c9 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -56,12 +56,15 @@
#define MMC_TIMING_UHS_SDR50 3
#define MMC_TIMING_UHS_SDR104 4
#define MMC_TIMING_UHS_DDR50 5
+#define MMC_TIMING_MMC_HS200 6
unsigned char ddr; /* dual data rate used */
#define MMC_SDR_MODE 0
#define MMC_1_2V_DDR_MODE 1
#define MMC_1_8V_DDR_MODE 2
+#define MMC_1_2V_SDR_MODE 3
+#define MMC_1_8V_SDR_MODE 4
unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */
@@ -147,7 +150,9 @@
void (*init_card)(struct mmc_host *host, struct mmc_card *card);
int (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
- int (*execute_tuning)(struct mmc_host *host);
+
+ /* The tuning command opcode value is different for SD and eMMC cards */
+ int (*execute_tuning)(struct mmc_host *host, u32 opcode);
void (*enable_preset_value)(struct mmc_host *host, bool enable);
void (*hw_reset)(struct mmc_host *host);
};
@@ -239,7 +244,10 @@
#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */
#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff supported */
#define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */
-
+#define MMC_CAP2_HS200_1_8V_SDR (1 << 5) /* can support */
+#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
+#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
+ MMC_CAP2_HS200_1_2V_SDR)
mmc_pm_flag_t pm_caps; /* supported pm features */
unsigned int power_notify_type;
#define MMC_HOST_PW_NOTIFY_NONE 0
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 0a72bf8..e124fbe 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -51,6 +51,7 @@
#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
#define MMC_SEND_TUNING_BLOCK 19 /* adtc R1 */
+#define MMC_SEND_TUNING_BLOCK_HS200 21 /* adtc R1 */
/* class 3 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
@@ -331,13 +332,76 @@
#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK 0xF /* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_MASK 0x3F /* Mask out reserved bits */
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V)
+#define EXT_CSD_CARD_TYPE_SDR_1_8V (1<<4) /* Card can run at 200MHz */
+#define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at 200MHz */
+ /* SDR mode @1.2V I/O */
+
+#define EXT_CSD_CARD_TYPE_SDR_200 (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+ EXT_CSD_CARD_TYPE_SDR_1_2V)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL (EXT_CSD_CARD_TYPE_SDR_200 | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_ALL (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_ALL (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+ EXT_CSD_CARD_TYPE_DDR_1_8V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+ EXT_CSD_CARD_TYPE_DDR_1_8V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+ EXT_CSD_CARD_TYPE_DDR_1_2V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+ EXT_CSD_CARD_TYPE_DDR_1_2V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_2V | \
+ EXT_CSD_CARD_TYPE_DDR_52 | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52 (EXT_CSD_CARD_TYPE_SDR_1_8V | \
+ EXT_CSD_CARD_TYPE_DDR_52 | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V (EXT_CSD_CARD_TYPE_SDR_200 | \
+ EXT_CSD_CARD_TYPE_DDR_1_8V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V (EXT_CSD_CARD_TYPE_SDR_200 | \
+ EXT_CSD_CARD_TYPE_DDR_1_2V | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
+
+#define EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52 (EXT_CSD_CARD_TYPE_SDR_200 | \
+ EXT_CSD_CARD_TYPE_DDR_52 | \
+ EXT_CSD_CARD_TYPE_52 | \
+ EXT_CSD_CARD_TYPE_26)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
diff --git a/include/linux/msm_audio.h b/include/linux/msm_audio.h
index 30d74ce..8a35ca0 100644
--- a/include/linux/msm_audio.h
+++ b/include/linux/msm_audio.h
@@ -90,6 +90,9 @@
#define AUDIO_GET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 96, \
struct msm_acdb_cmd_device)
+#define AUDIO_REGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 97, unsigned)
+#define AUDIO_DEREGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 98, unsigned)
+
#define AUDIO_MAX_COMMON_IOCTL_NUM 100
@@ -166,6 +169,11 @@
uint32_t unused[2];
};
+struct msm_audio_ion_info {
+ int fd;
+ void *vaddr;
+};
+
struct msm_audio_pmem_info {
int fd;
void *vaddr;
diff --git a/include/linux/msm_kgsl.h b/include/linux/msm_kgsl.h
index 5e39f89..69ff05b 100644
--- a/include/linux/msm_kgsl.h
+++ b/include/linux/msm_kgsl.h
@@ -34,6 +34,16 @@
#define KGSL_CLK_MEM_IFACE 0x00000010
#define KGSL_CLK_AXI 0x00000020
+/*
+ * Reset status values for context
+ */
+enum kgsl_ctx_reset_stat {
+ KGSL_CTX_STAT_NO_ERROR = 0x00000000,
+ KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT = 0x00000001,
+ KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT = 0x00000002,
+ KGSL_CTX_STAT_UNKNOWN_CONTEXT_RESET_EXT = 0x00000003
+};
+
#define KGSL_MAX_PWRLEVELS 5
#define KGSL_CONVERT_TO_MBPS(val) \
@@ -110,6 +120,7 @@
KGSL_PROP_MMU_ENABLE = 0x00000006,
KGSL_PROP_INTERRUPT_WAITS = 0x00000007,
KGSL_PROP_VERSION = 0x00000008,
+ KGSL_PROP_GPU_RESET_STAT = 0x00000009
};
struct kgsl_shadowprop {
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 07d5af65..6442faa 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -140,6 +140,7 @@
#define MDP_OV_PLAY_NOWAIT 0x00200000
#define MDP_SOURCE_ROTATED_90 0x00100000
#define MDP_DPP_HSIC 0x00080000
+#define MDP_BACKEND_COMPOSITION 0x00040000
#define MDP_BORDERFILL_SUPPORTED 0x00010000
#define MDP_SECURE_OVERLAY_SESSION 0x00008000
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
diff --git a/include/linux/msm_vidc_enc.h b/include/linux/msm_vidc_enc.h
index 1f264e9..bf149eb 100644
--- a/include/linux/msm_vidc_enc.h
+++ b/include/linux/msm_vidc_enc.h
@@ -52,6 +52,11 @@
#define VEN_BUFFLAG_EXTRADATA 0x00000040
#define VEN_BUFFLAG_CODECCONFIG 0x00000080
+/*Post processing flags bit masks*/
+#define VEN_EXTRADATA_NONE 0x001
+#define VEN_EXTRADATA_QCOMFILLER 0x002
+#define VEN_EXTRADATA_SLICEINFO 0x100
+
/*ENCODER CONFIGURATION CONSTANTS*/
/*Encoded video frame types*/
@@ -257,6 +262,8 @@
#define VEN_IOCTL_GET_RECON_BUFFER_SIZE \
_IOW(VEN_IOCTLBASE_NENC, 22, struct venc_ioctl_msg)
+
+
/*ENCODER PROPERTY CONFIGURATION & CAPABILITY IOCTLs*/
/*IOCTL params:SET: InputData - venc_basecfg, OutputData - NULL
@@ -439,6 +446,14 @@
#define VEN_IOCTL_SET_METABUFFER_MODE \
_IOW(VEN_IOCTLBASE_ENC, 47, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - unsigned int, OutputData - NULL.*/
+#define VEN_IOCTL_SET_EXTRADATA \
+ _IOW(VEN_IOCTLBASE_ENC, 48, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - unsigned int.*/
+#define VEN_IOCTL_GET_EXTRADATA \
+ _IOR(VEN_IOCTLBASE_ENC, 49, struct venc_ioctl_msg)
+
struct venc_switch{
unsigned char status;
};
diff --git a/include/linux/platform_data/dwc3-omap.h b/include/linux/platform_data/dwc3-omap.h
new file mode 100644
index 0000000..ada4012
--- /dev/null
+++ b/include/linux/platform_data/dwc3-omap.h
@@ -0,0 +1,47 @@
+/**
+ * dwc3-omap.h - OMAP Specific Glue layer, header.
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ * All rights reserved.
+ *
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+enum dwc3_omap_utmi_mode {
+ DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
+ DWC3_OMAP_UTMI_MODE_HW,
+ DWC3_OMAP_UTMI_MODE_SW,
+};
+
+struct dwc3_omap_data {
+ enum dwc3_omap_utmi_mode utmi_mode;
+};
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 583ceb8..60decb6 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -322,6 +322,13 @@
unsigned is_b_host:1; /* true during some HNP roleswitches */
unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
unsigned hnp_support:1; /* OTG: HNP is supported on OTG port */
+ unsigned quick_hnp:1; /* OTG: Indiacates if hnp is required
+ irrespective of host_request flag
+ */
+ unsigned otg_vbus_off:1; /* OTG: OTG test device feature bit that
+ * tells A-device to turn off VBUS after
+ * B-device is disconnected.
+ */
struct delayed_work hnp_polling;/* OTG: HNP polling work */
unsigned sg_tablesize; /* 0 or largest number of sg list entries */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 736203b..8f60c34 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -34,6 +34,7 @@
#define __LINUX_USB_CH9_H
#include <linux/types.h> /* __u8 etc */
+#include <asm/byteorder.h> /* le16_to_cpu */
/*-------------------------------------------------------------------------*/
@@ -133,6 +134,12 @@
#define TEST_PACKET 4
#define TEST_FORCE_EN 5
+/* OTG test mode feature bits
+ * See ECN OTG2.0 spec Table 6-8
+ */
+#define TEST_OTG_SRP_REQD 6
+#define TEST_OTG_HNP_REQD 7
+
/*
* New Feature Selectors as added by USB 3.0
* See USB 3.0 spec Table 9-6
@@ -143,12 +150,20 @@
#define USB_INTRF_FUNC_SUSPEND 0 /* function suspend */
#define USB_INTR_FUNC_SUSPEND_OPT_MASK 0xFF00
+/*
+ * Suspend Options, Table 9-7 USB 3.0 spec
+ */
+#define USB_INTRF_FUNC_SUSPEND_LP (1 << (8 + 0))
+#define USB_INTRF_FUNC_SUSPEND_RW (1 << (8 + 1))
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
-#define OTG_STATUS_SELECTOR 0xF000
-#define THOST_REQ_POLL 2000 /* msec */
-#define HOST_REQUEST_FLAG 0
+#define OTG_STATUS_SELECTOR 0xF000
+#define HOST_REQUEST_FLAG 0
+#define THOST_REQ_POLL 1500 /* msec (1000 - 2000) */
+#define OTG_TTST_SUSP 70 /* msec (0 - 100) */
+
+#define OTG_TTST_VBUS_OFF 1
/* Bit array elements as returned by the USB_REQ_GET_STATUS request. */
#define USB_DEV_STAT_U1_ENABLED 2 /* transition into U1 state */
@@ -574,6 +589,17 @@
return usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd);
}
+/**
+ * usb_endpoint_maxp - get endpoint's max packet size
+ * @epd: endpoint to be checked
+ *
+ * Returns @epd's max packet
+ */
+static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd)
+{
+ return __le16_to_cpu(epd->wMaxPacketSize);
+}
+
/*-------------------------------------------------------------------------*/
/* USB_DT_SS_ENDPOINT_COMP: SuperSpeed Endpoint Companion descriptor */
@@ -617,8 +643,10 @@
__u8 bDescriptorType;
__u8 bmAttributes; /* support for HNP, SRP, etc */
+ __le16 bcdOTG;
} __attribute__ ((packed));
+#define USB_DT_OTG_SIZE 5
/* from usb_otg_descriptor.bmAttributes */
#define USB_OTG_SRP (1 << 0)
#define USB_OTG_HNP (1 << 1) /* swap host/device roles */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 66a29a9..6938a86 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -59,6 +59,10 @@
* @hs_descriptors: Table of high speed descriptors, using interface and
* string identifiers assigned during @bind(). If this pointer is null,
* the function will not be available at high speed.
+ * @ss_descriptors: Table of super speed descriptors, using interface and
+ * string identifiers assigned during @bind(). If this
+ * pointer is null after initiation, the function will not
+ * be available at super speed.
* @config: assigned when @usb_add_function() is called; this is the
* configuration with which this function is associated.
* @bind: Before the gadget can register, all of its functions bind() to the
@@ -77,6 +81,10 @@
* @setup: Used for interface-specific control requests.
* @suspend: Notifies functions when the host stops sending USB traffic.
* @resume: Notifies functions when the host restarts USB traffic.
+ * @get_status: Returns function status as a reply to
+ * GetStatus() request when the recepient is Interface.
+ * @func_suspend: callback to be called when
+ * SetFeature(FUNCTION_SUSPEND) is reseived
*
* A single USB function uses one or more interfaces, and should in most
* cases support operation at both full and high speeds. Each function is
@@ -106,6 +114,7 @@
struct usb_gadget_strings **strings;
struct usb_descriptor_header **descriptors;
struct usb_descriptor_header **hs_descriptors;
+ struct usb_descriptor_header **ss_descriptors;
struct usb_configuration *config;
@@ -132,6 +141,10 @@
void (*suspend)(struct usb_function *);
void (*resume)(struct usb_function *);
+ /* USB 3.0 additions */
+ int (*get_status)(struct usb_function *);
+ int (*func_suspend)(struct usb_function *,
+ u8 suspend_opt);
/* private: */
/* internals */
struct list_head list;
@@ -145,20 +158,8 @@
int usb_interface_id(struct usb_configuration *, struct usb_function *);
-/**
- * ep_choose - select descriptor endpoint at current device speed
- * @g: gadget, connected and running at some speed
- * @hs: descriptor to use for high speed operation
- * @fs: descriptor to use for full or low speed operation
- */
-static inline struct usb_endpoint_descriptor *
-ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
- struct usb_endpoint_descriptor *fs)
-{
- if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
- return hs;
- return fs;
-}
+int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
+ struct usb_ep *_ep);
#define MAX_CONFIG_INTERFACES 16 /* arbitrary; max 255 */
@@ -231,6 +232,7 @@
struct list_head list;
struct list_head functions;
u8 next_interface_id;
+ unsigned superspeed:1;
unsigned highspeed:1;
unsigned fullspeed:1;
struct usb_function *interface[MAX_CONFIG_INTERFACES];
@@ -255,6 +257,7 @@
* identifiers.
* @strings: tables of strings, keyed by identifiers assigned during bind()
* and language IDs provided in control requests
+ * @max_speed: Highest speed the driver supports.
* @needs_serial: set to 1 if the gadget needs userspace to provide
* a serial number. If one is not provided, warning will be printed.
* @unbind: Reverses bind; called as a side effect of unregistering
@@ -282,6 +285,7 @@
const char *iManufacturer;
const struct usb_device_descriptor *dev;
struct usb_gadget_strings **strings;
+ enum usb_device_speed max_speed;
unsigned needs_serial:1;
int (*unbind)(struct usb_composite_dev *);
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 47e8427..0dbc671 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -27,6 +27,7 @@
* field, and the usb controller needs one, it is responsible
* for mapping and unmapping the buffer.
* @length: Length of that data
+ * @stream_id: The stream id, when USB3.0 bulk streams are being used
* @no_interrupt: If true, hints that no completion irq is needed.
* Helpful sometimes with deep request queues that are handled
* directly by DMA controllers.
@@ -82,6 +83,7 @@
unsigned length;
dma_addr_t dma;
+ unsigned stream_id:16;
unsigned no_interrupt:1;
unsigned zero:1;
unsigned short_not_ok:1;
@@ -132,8 +134,17 @@
* @maxpacket:The maximum packet size used on this endpoint. The initial
* value can sometimes be reduced (hardware allowing), according to
* the endpoint descriptor used to configure the endpoint.
- * @driver_data:for use by the gadget driver. all other fields are
- * read-only to gadget drivers.
+ * @max_streams: The maximum number of streams supported
+ * by this EP (0 - 16, actual number is 2^n)
+ * @mult: multiplier, 'mult' value for SS Isoc EPs
+ * @maxburst: the maximum number of bursts supported by this EP (for usb3)
+ * @driver_data:for use by the gadget driver.
+ * @address: used to identify the endpoint when finding descriptor that
+ * matches connection speed
+ * @desc: endpoint descriptor. This pointer is set before the endpoint is
+ * enabled and remains valid until the endpoint is disabled.
+ * @comp_desc: In case of SuperSpeed support, this is the endpoint companion
+ * descriptor that is used to configure the endpoint
*
* the bus controller driver lists all the general purpose endpoints in
* gadget->ep_list. the control endpoint (gadget->ep0) is not in that list,
@@ -146,6 +157,12 @@
const struct usb_ep_ops *ops;
struct list_head ep_list;
unsigned maxpacket:16;
+ unsigned max_streams:16;
+ unsigned mult:2;
+ unsigned maxburst:4;
+ u8 address;
+ const struct usb_endpoint_descriptor *desc;
+ const struct usb_ss_ep_comp_descriptor *comp_desc;
};
/*-------------------------------------------------------------------------*/
@@ -154,11 +171,8 @@
* usb_ep_enable - configure endpoint, making it usable
* @ep:the endpoint being configured. may not be the endpoint named "ep0".
* drivers discover endpoints through the ep_list of a usb_gadget.
- * @desc:descriptor for desired behavior. caller guarantees this pointer
- * remains valid until the endpoint is disabled; the data byte order
- * is little-endian (usb-standard).
*
- * when configurations are set, or when interface settings change, the driver
+ * When configurations are set, or when interface settings change, the driver
* will enable or disable the relevant endpoints. while it is enabled, an
* endpoint may be used for i/o until the driver receives a disconnect() from
* the host or until the endpoint is disabled.
@@ -173,10 +187,9 @@
*
* returns zero, or a negative error code.
*/
-static inline int usb_ep_enable(struct usb_ep *ep,
- const struct usb_endpoint_descriptor *desc)
+static inline int usb_ep_enable(struct usb_ep *ep)
{
- return ep->ops->enable(ep, desc);
+ return ep->ops->enable(ep, ep->desc);
}
/**
@@ -417,7 +430,16 @@
/*-------------------------------------------------------------------------*/
+struct usb_dcd_config_params {
+ __u8 bU1devExitLat; /* U1 Device exit Latency */
+#define USB_DEFAULT_U1_DEV_EXIT_LAT 0x01 /* Less then 1 microsec */
+ __le16 bU2DevExitLat; /* U2 Device exit Latency */
+#define USB_DEFAULT_U2_DEV_EXIT_LAT 0x1F4 /* Less then 500 microsec */
+};
+
+
struct usb_gadget;
+struct usb_gadget_driver;
/* the rest of the api to the controller hardware: device operations,
* which don't involve endpoints (or i/o).
@@ -431,6 +453,16 @@
int (*pullup) (struct usb_gadget *, int is_on);
int (*ioctl)(struct usb_gadget *,
unsigned code, unsigned long param);
+ void (*get_config_params)(struct usb_dcd_config_params *);
+ int (*udc_start)(struct usb_gadget *,
+ struct usb_gadget_driver *);
+ int (*udc_stop)(struct usb_gadget *,
+ struct usb_gadget_driver *);
+
+ /* Those two are deprecated */
+ int (*start)(struct usb_gadget_driver *,
+ int (*bind)(struct usb_gadget *));
+ int (*stop)(struct usb_gadget_driver *);
};
/**
@@ -453,6 +485,9 @@
* only supports HNP on a different root port.
* @b_hnp_enable: OTG device feature flag, indicating that the A-Host
* enabled HNP support.
+ * @host_request: A flag set by user when wishes to take up host role.
+ * @otg_srp_reqd: OTG test mode feature to initiate SRP after the end of
+ * current session.
* @name: Identifies the controller hardware type. Used in diagnostics
* and sometimes configuration.
* @dev: Driver model state for this abstract device.
@@ -488,6 +523,7 @@
unsigned a_hnp_support:1;
unsigned a_alt_hnp_support:1;
unsigned host_request:1;
+ unsigned otg_srp_reqd:1;
const char *name;
struct device dev;
};
@@ -523,6 +559,24 @@
}
/**
+ * gadget_is_superspeed() - return true if the hardware handles
+ * supperspeed
+ * @g: controller that might support supper speed
+ */
+static inline int gadget_is_superspeed(struct usb_gadget *g)
+{
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+ /*
+ * runtime test would check "g->is_superspeed" ... that might be
+ * useful to work around hardware bugs, but is mostly pointless
+ */
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+/**
* gadget_is_otg - return true iff the hardware is OTG-ready
* @g: controller that might have a Mini-AB connector
*
@@ -823,6 +877,9 @@
*/
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
+extern int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget);
+extern void usb_del_gadget_udc(struct usb_gadget *gadget);
+
/*-------------------------------------------------------------------------*/
/* utility to simplify dealing with string descriptors */
@@ -860,6 +917,11 @@
/* utility to simplify managing config descriptors */
+/* Find and fill the requested descriptor into buffer */
+int
+usb_find_descriptor_fillbuf(void *, unsigned,
+ const struct usb_descriptor_header **, u8);
+
/* write vector of descriptors into buffer */
int usb_descriptor_fillbuf(void *, unsigned,
const struct usb_descriptor_header **);
@@ -872,12 +934,6 @@
struct usb_descriptor_header **usb_copy_descriptors(
struct usb_descriptor_header **);
-/* return copy of endpoint descriptor given original descriptor set */
-struct usb_endpoint_descriptor *usb_find_endpoint(
- struct usb_descriptor_header **src,
- struct usb_descriptor_header **copy,
- struct usb_endpoint_descriptor *match);
-
/**
* usb_free_descriptors - free descriptors returned by usb_copy_descriptors()
* @v: vector of descriptors
@@ -894,6 +950,11 @@
extern struct usb_ep *usb_ep_autoconfig(struct usb_gadget *,
struct usb_endpoint_descriptor *);
+
+extern struct usb_ep *usb_ep_autoconfig_ss(struct usb_gadget *,
+ struct usb_endpoint_descriptor *,
+ struct usb_ss_ep_comp_descriptor *);
+
extern void usb_ep_autoconfig_reset(struct usb_gadget *);
#endif /* __LINUX_USB_GADGET_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 79fb177..f2ad7e1 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -279,6 +279,7 @@
struct msm_usb_host_platform_data {
unsigned int power_budget;
+ unsigned int dock_connect_irq;
};
struct usb_bam_pipe_connect {
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 3e93de7..fb1ca8c 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -30,4 +30,6 @@
descriptor */
#define USB_QUIRK_DELAY_INIT 0x00000040
+#define USB_QUIRK_OTG_PET 0x00000080
+
#endif /* __LINUX_USB_QUIRKS_H */
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index 867bd8a..6a7f99b 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -342,6 +342,7 @@
#define MSM_CAM_RESP_MAX 8
#define MSM_CAM_APP_NOTIFY_EVENT 0
+#define MSM_CAM_APP_NOTIFY_ERROR_EVENT 1
/* this one is used to send ctrl/status up to config thread */
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 164d3b4..3ca14ff 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -570,7 +570,7 @@
struct hci_conn *hci_le_conn_add(struct hci_dev *hdev, bdaddr_t *dst,
__u8 addr_type);
int hci_conn_del(struct hci_conn *conn);
-void hci_conn_hash_flush(struct hci_dev *hdev);
+void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process);
void hci_conn_check_pending(struct hci_dev *hdev);
struct hci_chan *hci_chan_add(struct hci_dev *hdev);
@@ -751,7 +751,8 @@
int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
int (*connect_cfm) (struct hci_conn *conn, __u8 status);
int (*disconn_ind) (struct hci_conn *conn);
- int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
+ int (*disconn_cfm) (struct hci_conn *conn, __u8 reason,
+ __u8 is_process);
int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
@@ -808,17 +809,18 @@
return reason;
}
-static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
+static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason,
+ __u8 is_process)
{
register struct hci_proto *hp;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->disconn_cfm)
- hp->disconn_cfm(conn, reason);
+ hp->disconn_cfm(conn, reason, is_process);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->disconn_cfm)
- hp->disconn_cfm(conn, reason);
+ hp->disconn_cfm(conn, reason, is_process);
if (conn->disconn_cfm_cb)
conn->disconn_cfm_cb(conn, reason);
@@ -1049,6 +1051,7 @@
int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3]);
int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
u16 sub_ver);
+int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8]);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 9e79fb3..3e8de2c 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -355,3 +355,9 @@
__u16 manufacturer;
__u16 lmp_subver;
} __packed;
+
+#define MGMT_EV_REMOTE_FEATURES 0x0019
+struct mgmt_ev_remote_features {
+ bdaddr_t bdaddr;
+ uint8_t features[8];
+} __packed;
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index d08f528..0fabc5b 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -15,6 +15,9 @@
#include <mach/qdsp6v2/apr.h>
#include <mach/msm_subsystem_map.h>
#include <sound/apr_audio.h>
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#include <linux/ion.h>
+#endif
#define IN 0x000
#define OUT 0x001
@@ -94,10 +97,15 @@
struct audio_buffer {
dma_addr_t phys;
void *data;
- struct msm_mapped_buffer *mem_buffer;
uint32_t used;
uint32_t size;/* size of buffer */
uint32_t actual_size; /* actual number of bytes read by DSP */
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ struct ion_handle *handle;
+ struct ion_client *client;
+#else
+ struct msm_mapped_buffer *mem_buffer;
+#endif
};
struct audio_aio_write_param {
diff --git a/kernel/power/fbearlysuspend.c b/kernel/power/fbearlysuspend.c
index 1513765..4877372 100644
--- a/kernel/power/fbearlysuspend.c
+++ b/kernel/power/fbearlysuspend.c
@@ -19,7 +19,10 @@
#include "power.h"
+#define MAX_BUF 100
+
static wait_queue_head_t fb_state_wq;
+static int display = 1;
static DEFINE_SPINLOCK(fb_state_lock);
static enum {
FB_STATE_STOPPED_DRAWING,
@@ -71,10 +74,16 @@
ret = wait_event_interruptible(fb_state_wq,
fb_state != FB_STATE_DRAWING_OK);
- if (ret && fb_state == FB_STATE_DRAWING_OK)
+ if (ret && fb_state == FB_STATE_DRAWING_OK) {
return ret;
- else
+ } else {
s += sprintf(buf, "sleeping");
+ if (display == 1) {
+ display = 0;
+ sysfs_notify(power_kobj, NULL, "wait_for_fb_status");
+ }
+ }
+
return s - buf;
}
@@ -96,28 +105,47 @@
fb_state == FB_STATE_DRAWING_OK);
if (ret && fb_state != FB_STATE_DRAWING_OK)
return ret;
- else
+ else {
s += sprintf(buf, "awake");
-
+ if (display == 0) {
+ display = 1;
+ sysfs_notify(power_kobj, NULL, "wait_for_fb_status");
+ }
+ }
return s - buf;
}
-#define power_ro_attr(_name) \
-static struct kobj_attribute _name##_attr = { \
- .attr = { \
- .name = __stringify(_name), \
- .mode = 0444, \
- }, \
- .show = _name##_show, \
- .store = NULL, \
+static ssize_t wait_for_fb_status_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ int ret = 0;
+
+ if (display == 1)
+ ret = snprintf(buf, strnlen("on", MAX_BUF) + 1, "on");
+ else
+ ret = snprintf(buf, strnlen("off", MAX_BUF) + 1, "off");
+
+ return ret;
}
+#define power_ro_attr(_name) \
+ static struct kobj_attribute _name##_attr = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0444, \
+ }, \
+ .show = _name##_show, \
+ .store = NULL, \
+ }
+
power_ro_attr(wait_for_fb_sleep);
power_ro_attr(wait_for_fb_wake);
+power_ro_attr(wait_for_fb_status);
static struct attribute *g[] = {
&wait_for_fb_sleep_attr.attr,
&wait_for_fb_wake_attr.attr,
+ &wait_for_fb_status_attr.attr,
NULL,
};
diff --git a/kernel/power/main.c b/kernel/power/main.c
index ff29679..6aeabf9 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -15,6 +15,8 @@
#include "power.h"
+#define MAX_BUF 100
+
DEFINE_MUTEX(pm_mutex);
#ifdef CONFIG_PM_SLEEP
@@ -23,6 +25,10 @@
static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
+static struct hrtimer in_ev_timer;
+static int input_processed;
+static ktime_t touch_evt_timer_val;
+
int register_pm_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&pm_chain_head, nb);
@@ -67,6 +73,72 @@
power_attr(pm_async);
+static ssize_t
+touch_event_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ if (input_processed == 0)
+ return snprintf(buf, strnlen("touch_event", MAX_BUF) + 1,
+ "touch_event");
+ else
+ return snprintf(buf, strnlen("null", MAX_BUF) + 1,
+ "null");
+}
+
+static ssize_t
+touch_event_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+
+ hrtimer_cancel(&in_ev_timer);
+ input_processed = 0;
+
+ /* set a timer to notify the userspace to stop processing
+ * touch event
+ */
+ hrtimer_start(&in_ev_timer, touch_evt_timer_val, HRTIMER_MODE_REL);
+
+ /* wakeup the userspace poll */
+ sysfs_notify(kobj, NULL, "touch_event");
+
+ return n;
+}
+
+power_attr(touch_event);
+
+static ssize_t
+touch_event_timer_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return snprintf(buf, MAX_BUF, "%lld", touch_evt_timer_val.tv64);
+}
+
+static ssize_t
+touch_event_timer_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+
+ touch_evt_timer_val = ktime_set(0, val*1000);
+
+ return n;
+}
+
+power_attr(touch_event_timer);
+
+static enum hrtimer_restart input_event_stop(struct hrtimer *hrtimer)
+{
+ /* wakeup the userspace poll */
+ input_processed = 1;
+ sysfs_notify(power_kobj, NULL, "touch_event");
+ return HRTIMER_NORESTART;
+}
+
#ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE;
@@ -313,7 +385,9 @@
power_attr(wake_unlock);
#endif
-static struct attribute * g[] = {
+static struct attribute *g[] = {
+ &touch_event_attr.attr,
+ &touch_event_timer_attr.attr,
&state_attr.attr,
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
@@ -358,6 +432,11 @@
return error;
hibernate_image_size_init();
hibernate_reserved_size_init();
+
+ touch_evt_timer_val = ktime_set(2, 0);
+ hrtimer_init(&in_ev_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ in_ev_timer.function = &input_event_stop;
+
power_kobj = kobject_create_and_add("power", NULL);
if (!power_kobj)
return -ENOMEM;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 899c538..ca33664 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -728,7 +728,7 @@
{
BT_DBG("conn %p", conn);
- hci_proto_disconn_cfm(conn, reason);
+ hci_proto_disconn_cfm(conn, reason, 0);
}
EXPORT_SYMBOL(hci_disconnect);
@@ -1027,7 +1027,7 @@
EXPORT_SYMBOL(hci_chan_modify);
/* Drop all connection on the device */
-void hci_conn_hash_flush(struct hci_dev *hdev)
+void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
@@ -1043,7 +1043,7 @@
c->state = BT_CLOSED;
- hci_proto_disconn_cfm(c, 0x16);
+ hci_proto_disconn_cfm(c, 0x16, is_process);
hci_conn_del(c);
}
}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 4c2bd37..c0eb50c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -626,7 +626,7 @@
return ret;
}
-static int hci_dev_do_close(struct hci_dev *hdev)
+static int hci_dev_do_close(struct hci_dev *hdev, u8 is_process)
{
unsigned long keepflags = 0;
@@ -647,7 +647,7 @@
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
+ hci_conn_hash_flush(hdev, is_process);
hci_dev_unlock_bh(hdev);
hci_notify(hdev, HCI_DEV_DOWN);
@@ -714,7 +714,7 @@
hdev = hci_dev_get(dev);
if (!hdev)
return -ENODEV;
- err = hci_dev_do_close(hdev);
+ err = hci_dev_do_close(hdev, 1);
hci_dev_put(hdev);
return err;
}
@@ -740,7 +740,7 @@
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
- hci_conn_hash_flush(hdev);
+ hci_conn_hash_flush(hdev, 0);
hci_dev_unlock_bh(hdev);
if (hdev->flush)
@@ -953,7 +953,7 @@
if (!blocked)
return 0;
- hci_dev_do_close(hdev);
+ hci_dev_do_close(hdev, 0);
return 0;
}
@@ -1563,7 +1563,7 @@
list_del(&hdev->list);
write_unlock_bh(&hci_dev_list_lock);
- hci_dev_do_close(hdev);
+ hci_dev_do_close(hdev, 0);
for (i = 0; i < NUM_REASSEMBLY; i++)
kfree_skb(hdev->reassembly[i]);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index fec6f32..154dc58 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1106,9 +1106,25 @@
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn) {
- if (status && conn->state == BT_CONFIG) {
- hci_proto_connect_cfm(conn, status);
- hci_conn_put(conn);
+ if (status) {
+ mgmt_auth_failed(hdev->id, &conn->dst, status);
+ clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
+
+ if (conn->state == BT_CONFIG) {
+ conn->state = BT_CONNECTED;
+ hci_proto_connect_cfm(conn, status);
+ hci_conn_put(conn);
+ } else {
+ hci_auth_cfm(conn, status);
+ hci_conn_hold(conn);
+ conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+ hci_conn_put(conn);
+ }
+
+ if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
+ clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
+ hci_encrypt_cfm(conn, status, 0x00);
+ }
}
conn->auth_initiator = 1;
}
@@ -1748,7 +1764,7 @@
if (conn->type == LE_LINK)
del_timer(&conn->smp_timer);
- hci_proto_disconn_cfm(conn, ev->reason);
+ hci_proto_disconn_cfm(conn, ev->reason, 0);
hci_conn_del(conn);
unlock:
@@ -1924,8 +1940,10 @@
if (!conn)
goto unlock;
- if (!ev->status)
+ if (!ev->status) {
memcpy(conn->features, ev->features, 8);
+ mgmt_remote_features(hdev->id, &conn->dst, ev->features);
+ }
if (conn->state != BT_CONFIG)
goto unlock;
@@ -3289,7 +3307,7 @@
if (conn) {
conn->state = BT_CLOSED;
- hci_proto_disconn_cfm(conn, ev->reason);
+ hci_proto_disconn_cfm(conn, ev->reason, 0);
hci_conn_del(conn);
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9662795..6a95c79 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -89,7 +89,7 @@
static int l2cap_create_cfm(struct hci_chan *chan, u8 status);
static int l2cap_deaggregate(struct hci_chan *chan, struct l2cap_pinfo *pi);
static void l2cap_chan_ready(struct sock *sk);
-static void l2cap_conn_del(struct hci_conn *hcon, int err);
+static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process);
static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l);
static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to);
@@ -569,7 +569,7 @@
struct hci_chan *ampchan = l2cap_pi(sk)->ampchan;
l2cap_pi(sk)->ampchan = NULL;
if (!hci_chan_put(ampchan))
- l2cap_deaggregate(l2cap_pi(sk)->ampchan, l2cap_pi(sk));
+ l2cap_deaggregate(ampchan, l2cap_pi(sk));
}
sk->sk_state = BT_CLOSED;
@@ -1160,7 +1160,7 @@
return conn;
}
-static void l2cap_conn_del(struct hci_conn *hcon, int err)
+static void l2cap_conn_del(struct hci_conn *hcon, int err, u8 is_process)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct sock *sk;
@@ -1181,9 +1181,15 @@
BT_DBG("ampcon %p", l2cap_pi(sk)->ampcon);
if ((conn->hcon == hcon) || (l2cap_pi(sk)->ampcon == hcon)) {
next = l2cap_pi(sk)->next_c;
- bh_lock_sock(sk);
+ if (is_process)
+ lock_sock(sk);
+ else
+ bh_lock_sock(sk);
l2cap_chan_del(sk, err);
- bh_unlock_sock(sk);
+ if (is_process)
+ release_sock(sk);
+ else
+ bh_unlock_sock(sk);
l2cap_sock_kill(sk);
sk = next;
} else
@@ -7332,7 +7338,7 @@
case L2CAP_CID_SMP:
if (smp_sig_channel(conn, skb))
- l2cap_conn_del(conn->hcon, EACCES);
+ l2cap_conn_del(conn->hcon, EACCES, 0);
break;
default:
@@ -7407,7 +7413,7 @@
if (conn)
l2cap_conn_ready(conn);
} else
- l2cap_conn_del(hcon, bt_err(status));
+ l2cap_conn_del(hcon, bt_err(status), 0);
return 0;
}
@@ -7424,14 +7430,14 @@
return conn->disc_reason;
}
-static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
+static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason, u8 is_process)
{
BT_DBG("hcon %p reason %d", hcon, reason);
if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
return -EINVAL;
- l2cap_conn_del(hcon, bt_err(reason));
+ l2cap_conn_del(hcon, bt_err(reason), is_process);
return 0;
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 910ef77..64d478b 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -2672,8 +2672,11 @@
if ((conn->auth_type & HCI_AT_DEDICATED_BONDING) &&
conn->auth_initiator && rem_cap == 0x03)
ev.auto_confirm = 1;
- else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03))
+ else if (loc_cap == 0x01 && (rem_cap == 0x00 || rem_cap == 0x03)) {
+ if (!loc_mitm && !rem_mitm)
+ value = 0;
goto no_auto_confirm;
+ }
if ((!loc_mitm || rem_cap == 0x03) && (!rem_mitm || loc_cap == 0x03))
@@ -2929,3 +2932,16 @@
return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
}
+
+int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
+{
+ struct mgmt_ev_remote_features ev;
+
+ memset(&ev, 0, sizeof(ev));
+
+ bacpy(&ev.bdaddr, bdaddr);
+ memcpy(ev.features, features, sizeof(ev.features));
+
+ return mgmt_event(MGMT_EV_REMOTE_FEATURES, index, &ev, sizeof(ev),
+ NULL);
+}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 99c4559..f8c3bba 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -62,7 +62,7 @@
static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
static void sco_chan_del(struct sock *sk, int err);
-static int sco_conn_del(struct hci_conn *conn, int err);
+static int sco_conn_del(struct hci_conn *conn, int err, u8 is_process);
static void sco_sock_close(struct sock *sk);
static void sco_sock_kill(struct sock *sk);
@@ -135,7 +135,7 @@
return sk;
}
-static int sco_conn_del(struct hci_conn *hcon, int err)
+static int sco_conn_del(struct hci_conn *hcon, int err, u8 is_process)
{
struct sco_conn *conn = hcon->sco_data;
struct sock *sk;
@@ -148,10 +148,16 @@
/* Kill socket */
sk = sco_chan_get(conn);
if (sk) {
- bh_lock_sock(sk);
+ if (is_process)
+ lock_sock(sk);
+ else
+ bh_lock_sock(sk);
sco_sock_clear_timer(sk);
sco_chan_del(sk, err);
- bh_unlock_sock(sk);
+ if (is_process)
+ release_sock(sk);
+ else
+ bh_unlock_sock(sk);
sco_sock_kill(sk);
}
@@ -952,19 +958,19 @@
if (conn)
sco_conn_ready(conn);
} else
- sco_conn_del(hcon, bt_err(status));
+ sco_conn_del(hcon, bt_err(status), 0);
return 0;
}
-static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
+static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason, __u8 is_process)
{
BT_DBG("hcon %p reason %d", hcon, reason);
if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
return -EINVAL;
- sco_conn_del(hcon, bt_err(reason));
+ sco_conn_del(hcon, bt_err(reason), is_process);
return 0;
}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0d41625..4396b07 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -8,9 +8,10 @@
use strict;
use constant BEFORE_SHORTTEXT => 0;
-use constant IN_SHORTTEXT => 1;
-use constant AFTER_SHORTTEXT => 2;
-use constant CHECK_NEXT_SHORTTEXT => 3;
+use constant IN_SHORTTEXT_BLANKLINE => 1;
+use constant IN_SHORTTEXT => 2;
+use constant AFTER_SHORTTEXT => 3;
+use constant CHECK_NEXT_SHORTTEXT => 4;
use constant SHORTTEXT_LIMIT => 75;
my $P = $0;
@@ -1233,6 +1234,7 @@
my $shorttext = BEFORE_SHORTTEXT;
my $shorttext_exspc = 0;
+ my $commit_text_present = 0;
sanitise_line_reset();
cleanup_continuation_headers();
@@ -1416,8 +1418,24 @@
my $hereprev = "$here\n$prevrawline\n$rawline\n";
if ($shorttext != AFTER_SHORTTEXT) {
+ if ($shorttext == IN_SHORTTEXT_BLANKLINE && $line=~/\S/) {
+ # the subject line was just processed,
+ # a blank line must be next
+ WARN("non-blank line after summary line\n" . $herecurr);
+ $shorttext = IN_SHORTTEXT;
+ # this non-blank line may or may not be commit text -
+ # a warning has been generated so assume it is commit
+ # text and move on
+ $commit_text_present = 1;
+ # fall through and treat this line as IN_SHORTTEXT
+ }
if ($shorttext == IN_SHORTTEXT) {
if ($line=~/^---/ || $line=~/^diff.*/) {
+ if ($commit_text_present == 0) {
+ WARN("please add commit text explaining " .
+ "*why* the change is needed\n" .
+ $herecurr);
+ }
$shorttext = AFTER_SHORTTEXT;
} elsif (length($line) > (SHORTTEXT_LIMIT +
$shorttext_exspc)
@@ -1427,7 +1445,25 @@
WARN("commit text line over " .
SHORTTEXT_LIMIT .
" characters\n" . $herecurr);
+ } elsif ($line=~/^\s*change-id:/i ||
+ $line=~/^\s*signed-off-by:/i ||
+ $line=~/^\s*crs-fixed:/i ||
+ $line=~/^\s*acked-by:/i) {
+ # this is a tag, there must be commit
+ # text by now
+ if ($commit_text_present == 0) {
+ WARN("please add commit text explaining " .
+ "*why* the change is needed\n" .
+ $herecurr);
+ # prevent duplicate warnings
+ $commit_text_present = 1;
+ }
+ } elsif ($line=~/\S/) {
+ $commit_text_present = 1;
}
+ } elsif ($shorttext == IN_SHORTTEXT_BLANKLINE) {
+ # case of non-blank line in this state handled above
+ $shorttext = IN_SHORTTEXT;
} elsif ($shorttext == CHECK_NEXT_SHORTTEXT) {
# The Subject line doesn't have to be the last header in the patch.
# Avoid moving to the IN_SHORTTEXT state until clear of all headers.
@@ -1435,16 +1471,25 @@
# text which looks like a header is definitely a header.
if ($line!~/^[\x21-\x39\x3b-\x7e]+:/) {
$shorttext = IN_SHORTTEXT;
-# Check for Subject line followed by a blank line.
+ # Check for Subject line followed by a blank line.
if (length($line) != 0) {
WARN("non-blank line after " .
"summary line\n" .
$sublinenr . $here .
"\n" . $subjectline .
"\n" . $line . "\n");
+ # this non-blank line may or may not
+ # be commit text - a warning has been
+ # generated so assume it is commit
+ # text and move on
+ $commit_text_present = 1;
}
}
+ # The next two cases are BEFORE_SHORTTEXT.
} elsif ($line=~/^Subject: \[[^\]]*\] (.*)/) {
+ # This is the subject line. Go to
+ # CHECK_NEXT_SHORTTEXT to wait for the commit
+ # text to show up.
$shorttext = CHECK_NEXT_SHORTTEXT;
$subjectline = $line;
$sublinenr = "#$linenr & ";
@@ -1455,7 +1500,10 @@
" characters\n" . $herecurr);
}
} elsif ($line=~/^ (.*)/) {
- $shorttext = IN_SHORTTEXT;
+ # Indented format, this must be the summary
+ # line (i.e. git show). There will be no more
+ # headers so we are now in the shorttext.
+ $shorttext = IN_SHORTTEXT_BLANKLINE;
$shorttext_exspc = 4;
if (length($1) > SHORTTEXT_LIMIT) {
WARN("summary line over " .
diff --git a/scripts/setlocalversion b/scripts/setlocalversion
index 4d40384..2c52866 100755
--- a/scripts/setlocalversion
+++ b/scripts/setlocalversion
@@ -55,16 +55,17 @@
echo "+"
return
fi
- # If we are past a tagged commit (like
- # "v2.6.30-rc5-302-g72357d5"), we pretty print it.
- if atag="`git describe 2>/dev/null`"; then
- echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}'
-
- # If we don't have a tag at all we print -g{commitish}.
- else
- printf '%s%s' -g $head
- fi
fi
+ # If we are past a tagged commit (like
+ # "v2.6.30-rc5-302-g72357d5"), we pretty print it but strip
+ # off the v2.6.30-rc5 part because that's in the Makefile.
+ if atag="`git describe 2>/dev/null`"; then
+ atag="-${atag/v$KERNELVERSION-/}"
+ # If we don't have a tag at all we print -g{commitish}.
+ else
+ atag="-g$head"
+ fi
+ printf '%s' "$atag"
# Is this git on svn?
if git config --get svn-remote.svn.url >/dev/null; then
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index 1d93d7a..65fe16d 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -30,6 +30,7 @@
#include <sound/tlv.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include "wcd9304.h"
#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
@@ -1888,6 +1889,10 @@
static int sitar_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
+ if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
+ (wcd9xxx->dev->parent != NULL))
+ pm_runtime_get_sync(wcd9xxx->dev->parent);
pr_err("%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
@@ -1897,6 +1902,12 @@
static void sitar_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
+ if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
+ (wcd9xxx->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
+ pm_runtime_put(wcd9xxx->dev->parent);
+ }
pr_err("%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
}
@@ -2539,26 +2550,6 @@
return 0;
}
-
-static void sitar_lock_sleep(struct sitar_priv *sitar)
-{
- int ret;
- while (!(ret = wait_event_timeout(sitar->pm_wq,
- atomic_inc_not_zero(&sitar->pm_cnt),
- 2 * HZ))) {
- pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
- __func__, ret, atomic_read(&sitar->pm_cnt));
- WARN_ON_ONCE(1);
- }
-}
-
-static void sitar_unlock_sleep(struct sitar_priv *sitar)
-{
- atomic_dec(&sitar->pm_cnt);
- wake_up(&sitar->pm_wq);
-}
-
-
static void btn0_lpress_fn(struct work_struct *work)
{
struct delayed_work *delayed_work;
@@ -2581,7 +2572,6 @@
pr_err("%s: Bad sitar private data\n", __func__);
}
- sitar_unlock_sleep(sitar);
}
int sitar_hs_detect(struct snd_soc_codec *codec,
@@ -2628,10 +2618,10 @@
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
short bias_value;
+ struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
- sitar_lock_sleep(priv);
bias_value = sitar_codec_read_dce_result(codec);
pr_err("%s: button press interrupt, bias value(DCE Read)=%d\n",
@@ -2648,10 +2638,11 @@
msleep(100);
+ 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");
- sitar_unlock_sleep(priv);
+ wcd9xxx_unlock_sleep(core);
}
return IRQ_HANDLED;
@@ -2662,10 +2653,10 @@
struct sitar_priv *priv = data;
struct snd_soc_codec *codec = priv->codec;
int ret, mic_voltage;
+ struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
pr_err("%s\n", __func__);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE);
- sitar_lock_sleep(priv);
mic_voltage = sitar_codec_read_dce_result(codec);
pr_err("%s: Microphone Voltage on release(DCE Read) = %d\n",
@@ -2687,7 +2678,7 @@
} else {
/* if scheduled btn0_dwork is canceled from here,
* we have to unlock from here instead btn0_work */
- sitar_unlock_sleep(priv);
+ wcd9xxx_unlock_sleep(core);
mic_voltage =
sitar_codec_measure_micbias_voltage(codec, 0);
pr_err("%s: Mic Voltage on release(new STA) = %d\n",
@@ -2716,7 +2707,6 @@
}
sitar_codec_start_hs_polling(codec);
- sitar_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -2860,7 +2850,6 @@
pr_err("%s\n", __func__);
wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
- sitar_lock_sleep(priv);
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);
@@ -2930,7 +2919,6 @@
}
sitar_codec_shutdown_hs_removal_detect(codec);
sitar_codec_enable_hs_detect(codec, 1);
- sitar_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -2988,7 +2976,6 @@
sitar_sync_hph_state(priv);
}
- sitar_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3001,7 +2988,6 @@
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);
- sitar_lock_sleep(priv);
usleep_range(priv->calibration->shutdown_plug_removal,
priv->calibration->shutdown_plug_removal);
@@ -3031,7 +3017,6 @@
sitar_codec_enable_hs_detect(codec, 1);
}
- sitar_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3045,7 +3030,6 @@
int i, j;
u8 val;
- sitar_lock_sleep(priv);
for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
@@ -3064,7 +3048,6 @@
SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
}
- sitar_unlock_sleep(priv);
return IRQ_HANDLED;
}
@@ -3486,53 +3469,14 @@
#ifdef CONFIG_PM
static int sitar_suspend(struct device *dev)
{
- int ret = 0, cnt;
- struct platform_device *pdev = to_platform_device(dev);
- struct sitar_priv *sitar = platform_get_drvdata(pdev);
-
- cnt = atomic_read(&sitar->pm_cnt);
- if (cnt > 0) {
- if (wait_event_timeout(sitar->pm_wq,
- (atomic_cmpxchg(&sitar->pm_cnt, 1, 0)
- == 1), 5 * HZ)) {
- dev_dbg(dev, "system suspend pm_cnt %d\n",
- atomic_read(&sitar->pm_cnt));
- } else {
- dev_err(dev, "%s timed out pm_cnt = %d\n",
- __func__, atomic_read(&sitar->pm_cnt));
- WARN_ON_ONCE(1);
- ret = -EBUSY;
- }
- } else if (cnt == 0)
- dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
- atomic_read(&sitar->pm_cnt));
- else {
- WARN(1, "unexpected pm_cnt %d\n", cnt);
- ret = -EFAULT;
- }
-
- return ret;
+ dev_dbg(dev, "%s: system suspend\n", __func__);
+ return 0;
}
static int sitar_resume(struct device *dev)
{
- int ret = 0, cnt;
- struct platform_device *pdev = to_platform_device(dev);
- struct sitar_priv *sitar = platform_get_drvdata(pdev);
-
- cnt = atomic_cmpxchg(&sitar->pm_cnt, 0, 1);
- if (cnt == 0) {
- dev_dbg(dev, "system resume, pm_cnt %d\n",
- atomic_read(&sitar->pm_cnt));
- wake_up_all(&sitar->pm_wq);
- } else if (cnt > 0)
- dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
- else {
- WARN(1, "unexpected pm_cnt %d\n", cnt);
- ret = -EFAULT;
- }
-
- return ret;
+ dev_dbg(dev, "%s: system resume\n", __func__);
+ return 0;
}
static const struct dev_pm_ops sitar_pm_ops = {
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
index e0ad541..2cba59d 100644
--- a/sound/soc/codecs/wcd9310-tables.c
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -451,6 +451,22 @@
[TABLA_A_CDC_DEBUG_B4_CTL] = 1,
[TABLA_A_CDC_DEBUG_B5_CTL] = 1,
[TABLA_A_CDC_DEBUG_B6_CTL] = 1,
+ [TABLA_A_CDC_COMP1_B1_CTL] = 1,
+ [TABLA_A_CDC_COMP1_B2_CTL] = 1,
+ [TABLA_A_CDC_COMP1_B3_CTL] = 1,
+ [TABLA_A_CDC_COMP1_B4_CTL] = 1,
+ [TABLA_A_CDC_COMP1_B5_CTL] = 1,
+ [TABLA_A_CDC_COMP1_B6_CTL] = 1,
+ [TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS] = 1,
+ [TABLA_A_CDC_COMP1_FS_CFG] = 1,
+ [TABLA_A_CDC_COMP2_B1_CTL] = 1,
+ [TABLA_A_CDC_COMP2_B2_CTL] = 1,
+ [TABLA_A_CDC_COMP2_B3_CTL] = 1,
+ [TABLA_A_CDC_COMP2_B4_CTL] = 1,
+ [TABLA_A_CDC_COMP2_B5_CTL] = 1,
+ [TABLA_A_CDC_COMP2_B6_CTL] = 1,
+ [TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS] = 1,
+ [TABLA_A_CDC_COMP2_FS_CFG] = 1,
[TABLA_A_CDC_CONN_RX1_B1_CTL] = 1,
[TABLA_A_CDC_CONN_RX1_B2_CTL] = 1,
[TABLA_A_CDC_CONN_RX1_B3_CTL] = 1,
@@ -993,6 +1009,24 @@
[TABLA_A_CDC_DEBUG_B4_CTL] = TABLA_A_CDC_DEBUG_B4_CTL__POR,
[TABLA_A_CDC_DEBUG_B5_CTL] = TABLA_A_CDC_DEBUG_B5_CTL__POR,
[TABLA_A_CDC_DEBUG_B6_CTL] = TABLA_A_CDC_DEBUG_B6_CTL__POR,
+ [TABLA_A_CDC_COMP1_B1_CTL] = TABLA_A_CDC_COMP1_B1_CTL__POR,
+ [TABLA_A_CDC_COMP1_B2_CTL] = TABLA_A_CDC_COMP1_B2_CTL__POR,
+ [TABLA_A_CDC_COMP1_B3_CTL] = TABLA_A_CDC_COMP1_B3_CTL__POR,
+ [TABLA_A_CDC_COMP1_B4_CTL] = TABLA_A_CDC_COMP1_B4_CTL__POR,
+ [TABLA_A_CDC_COMP1_B5_CTL] = TABLA_A_CDC_COMP1_B5_CTL__POR,
+ [TABLA_A_CDC_COMP1_B6_CTL] = TABLA_A_CDC_COMP1_B6_CTL__POR,
+ [TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+ TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+ [TABLA_A_CDC_COMP1_FS_CFG] = TABLA_A_CDC_COMP1_FS_CFG__POR,
+ [TABLA_A_CDC_COMP2_B1_CTL] = TABLA_A_CDC_COMP2_B1_CTL__POR,
+ [TABLA_A_CDC_COMP2_B2_CTL] = TABLA_A_CDC_COMP2_B2_CTL__POR,
+ [TABLA_A_CDC_COMP2_B3_CTL] = TABLA_A_CDC_COMP2_B3_CTL__POR,
+ [TABLA_A_CDC_COMP2_B4_CTL] = TABLA_A_CDC_COMP2_B4_CTL__POR,
+ [TABLA_A_CDC_COMP2_B5_CTL] = TABLA_A_CDC_COMP2_B5_CTL__POR,
+ [TABLA_A_CDC_COMP2_B6_CTL] = TABLA_A_CDC_COMP2_B6_CTL__POR,
+ [TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS] =
+ TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
+ [TABLA_A_CDC_COMP2_FS_CFG] = TABLA_A_CDC_COMP2_FS_CFG__POR,
[TABLA_A_CDC_CONN_RX1_B1_CTL] = TABLA_A_CDC_CONN_RX1_B1_CTL__POR,
[TABLA_A_CDC_CONN_RX1_B2_CTL] = TABLA_A_CDC_CONN_RX1_B2_CTL__POR,
[TABLA_A_CDC_CONN_RX1_B3_CTL] = TABLA_A_CDC_CONN_RX1_B3_CTL__POR,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index a5427ed..0ae9680 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -29,6 +29,7 @@
#include <sound/tlv.h>
#include <linux/bitops.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include "wcd9310.h"
#define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
@@ -52,6 +53,7 @@
#define AIF1_CAP 2
#define AIF2_PB 3
#define NUM_CODEC_DAIS 3
+#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
struct tabla_codec_dai_data {
u32 rate;
@@ -102,6 +104,20 @@
BAND_MAX,
};
+enum {
+ COMPANDER_1 = 0,
+ COMPANDER_2,
+ COMPANDER_MAX,
+};
+
+enum {
+ COMPANDER_FS_8KHZ = 0,
+ COMPANDER_FS_16KHZ,
+ COMPANDER_FS_32KHZ,
+ COMPANDER_FS_48KHZ,
+ COMPANDER_FS_MAX,
+};
+
/* Flags to track of PA and DAC state.
* PA and DAC should be tracked separately as AUXPGA loopback requires
* only PA to be turned on without DAC being on. */
@@ -112,6 +128,13 @@
TABLA_HPHR_DAC_OFF_ACK
};
+
+struct comp_sample_dependent_params {
+ u32 peak_det_timeout;
+ u32 rms_meter_div_fact;
+ u32 rms_meter_resamp_fact;
+};
+
/* Data used by MBHC */
struct mbhc_internal_cal_data {
u16 dce_z;
@@ -209,12 +232,56 @@
/* num of slim ports required */
struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
+
+ /*compander*/
+ int comp_enabled[COMPANDER_MAX];
+ u32 comp_fs[COMPANDER_MAX];
};
#ifdef CONFIG_DEBUG_FS
struct tabla_priv *debug_tabla_priv;
#endif
+static const u32 comp_shift[] = {
+ 0,
+ 2,
+};
+
+static const int comp_rx_path[] = {
+ COMPANDER_1,
+ COMPANDER_1,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_2,
+ COMPANDER_MAX,
+};
+
+static const struct comp_sample_dependent_params comp_samp_params[] = {
+ {
+ .peak_det_timeout = 0x2,
+ .rms_meter_div_fact = 0x8 << 4,
+ .rms_meter_resamp_fact = 0x21,
+ },
+ {
+ .peak_det_timeout = 0x3,
+ .rms_meter_div_fact = 0x9 << 4,
+ .rms_meter_resamp_fact = 0x28,
+ },
+
+ {
+ .peak_det_timeout = 0x5,
+ .rms_meter_div_fact = 0xB << 4,
+ .rms_meter_resamp_fact = 0x28,
+ },
+
+ {
+ .peak_det_timeout = 0x5,
+ .rms_meter_div_fact = 0xB << 4,
+ .rms_meter_resamp_fact = 0x28,
+ },
+};
+
static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -478,6 +545,192 @@
return 0;
}
+static int tabla_compander_gain_offset(
+ struct snd_soc_codec *codec, u32 enable,
+ unsigned int reg, int mask, int event)
+{
+ int pa_mode = snd_soc_read(codec, reg) & mask;
+ int gain_offset = 0;
+ /* if PMU && enable is 1-> offset is 3
+ * if PMU && enable is 0-> offset is 0
+ * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
+ * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
+ */
+
+ if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
+ gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
+ if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
+ gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
+ return gain_offset;
+}
+
+
+static int tabla_config_gain_compander(
+ struct snd_soc_codec *codec,
+ u32 compander, u32 enable, int event)
+{
+ int value = 0;
+ int mask = 1 << 4;
+ int gain = 0;
+ int gain_offset;
+ if (compander >= COMPANDER_MAX) {
+ pr_err("%s: Error, invalid compander channel\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
+ value = 1 << 4;
+
+ if (compander == COMPANDER_1) {
+ gain_offset = tabla_compander_gain_offset(codec, enable,
+ TABLA_A_RX_HPH_L_GAIN, mask, event);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
+ gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = tabla_compander_gain_offset(codec, enable,
+ TABLA_A_RX_HPH_R_GAIN, mask, event);
+ snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
+ gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ } else if (compander == COMPANDER_2) {
+ gain_offset = tabla_compander_gain_offset(codec, enable,
+ TABLA_A_RX_LINE_1_GAIN, mask, event);
+ snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
+ gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = tabla_compander_gain_offset(codec, enable,
+ TABLA_A_RX_LINE_3_GAIN, mask, event);
+ snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
+ gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = tabla_compander_gain_offset(codec, enable,
+ TABLA_A_RX_LINE_2_GAIN, mask, event);
+ snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
+ gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ gain_offset = tabla_compander_gain_offset(codec, enable,
+ TABLA_A_RX_LINE_4_GAIN, mask, event);
+ snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
+ gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
+ snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
+ 0xFF, gain - gain_offset);
+ }
+ return 0;
+}
+static int tabla_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->max;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
+
+ return 0;
+}
+
+static int tabla_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->max;
+ int value = ucontrol->value.integer.value[0];
+
+ if (value == tabla->comp_enabled[comp]) {
+ pr_debug("%s: compander #%d enable %d no change\n",
+ __func__, comp, value);
+ return 0;
+ }
+ tabla->comp_enabled[comp] = value;
+ return 0;
+}
+
+
+static int tabla_config_compander(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ u32 rate = tabla->comp_fs[w->shift];
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (tabla->comp_enabled[w->shift] != 0) {
+ /* Enable both L/R compander clocks */
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_RX_B2_CTL,
+ 0x03 << comp_shift[w->shift],
+ 0x03 << comp_shift[w->shift]);
+ /* Clar the HALT for the compander*/
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 0);
+ /* Toggle compander reset bits*/
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_OTHR_RESET_CTL,
+ 0x03 << comp_shift[w->shift],
+ 0x03 << comp_shift[w->shift]);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_CLK_OTHR_RESET_CTL,
+ 0x03 << comp_shift[w->shift], 0);
+ tabla_config_gain_compander(codec, w->shift, 1, event);
+ /* Update the RMS meter resampling*/
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_COMP1_B3_CTL +
+ w->shift * 8, 0xFF, 0x01);
+ /* Wait for 1ms*/
+ usleep_range(1000, 1000);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* Set sample rate dependent paramater*/
+ if (tabla->comp_enabled[w->shift] != 0) {
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
+ w->shift * 8, 0x03, rate);
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0x0F,
+ comp_samp_params[rate].peak_det_timeout);
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0xF0,
+ comp_samp_params[rate].rms_meter_div_fact);
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
+ w->shift * 8, 0xFF,
+ comp_samp_params[rate].rms_meter_resamp_fact);
+ /* Compander enable -> 0x370/0x378*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x03);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ /* Halt the compander*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 1 << 2);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* Restore the gain */
+ tabla_config_gain_compander(codec, w->shift,
+ tabla->comp_enabled[w->shift], event);
+ /* Disable the compander*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x00);
+ /* Turn off the clock for compander in pair*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
+ 0x03 << comp_shift[w->shift], 0);
+ break;
+ }
+ return 0;
+}
+
static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
static const struct soc_enum tabla_ear_pa_gain_enum[] = {
SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
@@ -695,6 +948,10 @@
tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
+ SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
+ tabla_get_compander, tabla_set_compander),
+ SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
+ tabla_get_compander, tabla_set_compander),
};
static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
@@ -2074,6 +2331,12 @@
{"LINEOUT4 DAC", NULL, "RX_BIAS"},
{"LINEOUT5 DAC", NULL, "RX_BIAS"},
+ {"RX1 MIX1", NULL, "COMP1_CLK"},
+ {"RX2 MIX1", NULL, "COMP1_CLK"},
+ {"RX3 MIX1", NULL, "COMP2_CLK"},
+ {"RX5 MIX1", NULL, "COMP2_CLK"},
+
+
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
@@ -2547,8 +2810,13 @@
static int tabla_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
pr_debug("%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
+ if ((tabla_core != NULL) &&
+ (tabla_core->dev != NULL) &&
+ (tabla_core->dev->parent != NULL))
+ pm_runtime_get_sync(tabla_core->dev->parent);
return 0;
}
@@ -2556,8 +2824,15 @@
static void tabla_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+ struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
pr_debug("%s(): substream = %s stream = %d\n" , __func__,
substream->name, substream->stream);
+ if ((tabla_core != NULL) &&
+ (tabla_core->dev != NULL) &&
+ (tabla_core->dev->parent != NULL)) {
+ pm_runtime_mark_last_busy(tabla_core->dev->parent);
+ pm_runtime_put(tabla_core->dev->parent);
+ }
}
int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
@@ -2735,6 +3010,7 @@
u8 path, shift;
u16 tx_fs_reg, rx_fs_reg;
u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
+ u32 compander_fs;
pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
params_rate(params));
@@ -2743,18 +3019,22 @@
case 8000:
tx_fs_rate = 0x00;
rx_fs_rate = 0x00;
+ compander_fs = COMPANDER_FS_8KHZ;
break;
case 16000:
tx_fs_rate = 0x01;
rx_fs_rate = 0x20;
+ compander_fs = COMPANDER_FS_16KHZ;
break;
case 32000:
tx_fs_rate = 0x02;
rx_fs_rate = 0x40;
+ compander_fs = COMPANDER_FS_32KHZ;
break;
case 48000:
tx_fs_rate = 0x03;
rx_fs_rate = 0x60;
+ compander_fs = COMPANDER_FS_48KHZ;
break;
default:
pr_err("%s: Invalid sampling rate %d\n", __func__,
@@ -2832,6 +3112,9 @@
+ (BITS_PER_REG*(path-1));
snd_soc_update_bits(codec, rx_fs_reg,
0xE0, rx_fs_rate);
+ if (comp_rx_path[shift] < COMPANDER_MAX)
+ tabla->comp_fs[comp_rx_path[shift]]
+ = compander_fs;
}
}
if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
@@ -3216,6 +3499,13 @@
SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
+ tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
+ tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+
SND_SOC_DAPM_INPUT("AMIC1"),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
@@ -4976,6 +5266,10 @@
tabla->mbhc_fake_ins_start = 0;
tabla->no_mic_headset_override = false;
tabla->codec = codec;
+ for (i = 0; i < COMPANDER_MAX; i++) {
+ tabla->comp_enabled[i] = 0;
+ tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
+ }
tabla->pdata = dev_get_platdata(codec->dev->parent);
tabla->intf_type = wcd9xxx_get_intf_type();
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index bcf6784..ae4e403 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -727,6 +727,13 @@
return ret;
}
+static int msm_stubrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ rtd->pmdown_time = 0;
+
+ return 0;
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -1253,6 +1260,7 @@
.no_pcm = 1,
/* .be_id = do not care */
.be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
+ .init = &msm_stubrx_init,
.ops = &msm_be_ops,
},
{
@@ -1270,7 +1278,7 @@
};
struct snd_soc_card snd_soc_card_msm = {
- .name = "msm-snd-card",
+ .name = "apq8064-tabla-snd-card",
.dai_link = msm_dai,
.num_links = ARRAY_SIZE(msm_dai),
};
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index b01c22c..14da1ba 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -254,6 +254,23 @@
mutex_unlock(&routing_lock);
}
+/* Check if FE/BE route is set */
+static bool msm_pcm_routing_route_is_set(u16 be_id, u16 fe_id)
+{
+ bool rc = false;
+
+ if (be_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+ /* recheck FE ID in the mixer control defined in this file */
+ pr_err("%s: bad MM ID\n", __func__);
+ return rc;
+ }
+
+ if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions))
+ rc = true;
+
+ return rc;
+}
+
static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
{
int session_type, path_type;
@@ -350,10 +367,12 @@
(struct soc_mixer_control *)kcontrol->private_value;
- if (ucontrol->value.integer.value[0]) {
+ if (ucontrol->value.integer.value[0] &&
+ msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false) {
msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
snd_soc_dapm_mixer_update_power(widget, kcontrol, 1);
- } else {
+ } else if (!ucontrol->value.integer.value[0] &&
+ msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true) {
msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
snd_soc_dapm_mixer_update_power(widget, kcontrol, 0);
}
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 471284b..5a0f27a 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.c
@@ -217,6 +217,26 @@
return 0;
}
+static int msm_voice_rx_device_mute_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] =
+ voc_get_rx_device_mute(voc_get_session_id(VOICE_SESSION_NAME));
+ return 0;
+}
+
+static int msm_voice_rx_device_mute_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int mute = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: mute=%d\n", __func__, mute);
+
+ voc_set_rx_device_mute(voc_get_session_id(VOICE_SESSION_NAME), mute);
+
+ return 0;
+}
+
static const char const *tty_mode[] = {"OFF", "HCO", "VCO", "FULL"};
static const struct soc_enum msm_tty_mode_enum[] = {
SOC_ENUM_SINGLE_EXT(4, tty_mode),
@@ -308,6 +328,9 @@
}
static struct snd_kcontrol_new msm_voice_controls[] = {
+ SOC_SINGLE_EXT("Voice Rx Device Mute", SND_SOC_NOPM, 0, 1, 0,
+ msm_voice_rx_device_mute_get,
+ msm_voice_rx_device_mute_put),
SOC_SINGLE_EXT("Voice Tx Mute", SND_SOC_NOPM, 0, 1, 0,
msm_voice_mute_get, msm_voice_mute_put),
SOC_SINGLE_EXT("Voice Rx Volume", SND_SOC_NOPM, 0, 5, 0,
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index d822af5c..fe31b27 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -240,6 +240,13 @@
while (cnt >= 0) {
if (port->buf[cnt].data) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_kernel(port->buf[cnt].client,
+ port->buf[cnt].handle);
+ ion_free(port->buf[cnt].client,
+ port->buf[cnt].handle);
+ ion_client_destroy(port->buf[cnt].client);
+#else
pr_debug("%s:data[%p]phys[%p][%p] cnt[%d]"
"mem_buffer[%p]\n",
__func__, (void *)port->buf[cnt].data,
@@ -259,6 +266,7 @@
free_contiguous_memory_by_paddr(
port->buf[cnt].phys);
+#endif
port->buf[cnt].data = NULL;
port->buf[cnt].phys = 0;
--(port->max_buf_cnt);
@@ -295,6 +303,19 @@
}
if (port->buf[0].data) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ ion_unmap_kernel(port->buf[0].client, port->buf[0].handle);
+ ion_free(port->buf[0].client, port->buf[0].handle);
+ ion_client_destroy(port->buf[0].client);
+ pr_debug("%s:data[%p]phys[%p][%p]"
+ ", client[%p] handle[%p]\n",
+ __func__,
+ (void *)port->buf[0].data,
+ (void *)port->buf[0].phys,
+ (void *)&port->buf[0].phys,
+ (void *)port->buf[0].client,
+ (void *)port->buf[0].handle);
+#else
pr_debug("%s:data[%p]phys[%p][%p]"
"mem_buffer[%p]\n",
__func__,
@@ -313,6 +334,7 @@
" failed\n", __func__);
}
free_contiguous_memory_by_paddr(port->buf[0].phys);
+#endif
}
while (cnt >= 0) {
@@ -465,6 +487,9 @@
int cnt = 0;
int rc = 0;
struct audio_buffer *buf;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ int len;
+#endif
if (!(ac) || ((dir != IN) && (dir != OUT)))
return -EINVAL;
@@ -494,6 +519,50 @@
while (cnt < bufcnt) {
if (bufsz > 0) {
if (!buf[cnt].data) {
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ buf[cnt].client = msm_ion_client_create
+ (UINT_MAX, "audio_client");
+ if (IS_ERR_OR_NULL((void *)
+ buf[cnt].client)) {
+ pr_err("%s: ION create client"
+ " for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+ buf[cnt].handle = ion_alloc
+ (buf[cnt].client, bufsz, SZ_4K,
+ (0x1 << ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL((void *)
+ buf[cnt].handle)) {
+ pr_err("%s: ION memory"
+ " allocation for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+
+ rc = ion_phys(buf[cnt].client,
+ buf[cnt].handle,
+ (ion_phys_addr_t *)
+ &buf[cnt].phys,
+ (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION Get Physical"
+ " for AUDIO failed, rc = %d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ buf[cnt].data = ion_map_kernel
+ (buf[cnt].client, buf[cnt].handle,
+ 0);
+ if (IS_ERR_OR_NULL((void *)
+ buf[cnt].data)) {
+ pr_err("%s: ION memory"
+ " mapping for AUDIO failed\n", __func__);
+ goto fail;
+ }
+ memset((void *)buf[cnt].data, 0, bufsz);
+#else
unsigned int flags = 0;
buf[cnt].phys =
allocate_contiguous_ebi_nomap(bufsz,
@@ -526,16 +595,15 @@
mutex_unlock(&ac->cmd_lock);
goto fail;
}
+#endif
buf[cnt].used = 1;
buf[cnt].size = bufsz;
buf[cnt].actual_size = bufsz;
- pr_debug("%s data[%p]phys[%p][%p]"
- "mem_buffer[%p]\n",
+ pr_debug("%s data[%p]phys[%p][%p]\n",
__func__,
(void *)buf[cnt].data,
(void *)buf[cnt].phys,
- (void *)&buf[cnt].phys,
- (void *)buf[cnt].mem_buffer);
+ (void *)&buf[cnt].phys);
cnt++;
}
}
@@ -562,9 +630,12 @@
{
int cnt = 0;
int rc = 0;
- int flags = 0;
struct audio_buffer *buf;
-
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ int len;
+#else
+ int flags = 0;
+#endif
if (!(ac) || ((dir != IN) && (dir != OUT)))
return -EINVAL;
@@ -590,6 +661,35 @@
ac->port[dir].buf = buf;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+ buf[0].client = msm_ion_client_create(UINT_MAX, "audio_client");
+ if (IS_ERR_OR_NULL((void *)buf[0].client)) {
+ pr_err("%s: ION create client for AUDIO failed\n", __func__);
+ goto fail;
+ }
+ buf[0].handle = ion_alloc(buf[0].client, bufsz * bufcnt, SZ_4K,
+ (0x1 << ION_AUDIO_HEAP_ID));
+ if (IS_ERR_OR_NULL((void *) buf[0].handle)) {
+ pr_err("%s: ION memory allocation for AUDIO failed\n",
+ __func__);
+ goto fail;
+ }
+
+ rc = ion_phys(buf[0].client, buf[0].handle,
+ (ion_phys_addr_t *)&buf[0].phys, (size_t *)&len);
+ if (rc) {
+ pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
+ __func__, rc);
+ goto fail;
+ }
+
+ buf[0].data = ion_map_kernel(buf[0].client, buf[0].handle, 0);
+ if (IS_ERR_OR_NULL((void *) buf[0].data)) {
+ pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
+ goto fail;
+ }
+ memset((void *)buf[0].data, 0, (bufsz * bufcnt));
+#else
buf[0].phys = allocate_contiguous_ebi_nomap(bufsz * bufcnt,
SZ_4K);
if (!buf[0].phys) {
@@ -612,6 +712,7 @@
goto fail;
}
buf[0].data = buf[0].mem_buffer->vaddr;
+#endif
if (!buf[0].data) {
pr_err("%s:invalid vaddr,"
" iomap failed\n", __func__);
@@ -726,6 +827,9 @@
if (data->opcode == RESET_EVENTS) {
pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
data->reset_event, data->reset_proc, ac->apr);
+ if (ac->cb)
+ ac->cb(data->opcode, data->token,
+ (uint32_t *)data->payload, ac->priv);
apr_reset(ac->apr);
return 0;
}
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index f0f833c..0376f34 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.c
@@ -2282,6 +2282,51 @@
return -EINVAL;
}
+static int voice_send_rx_device_mute_cmd(struct voice_data *v)
+{
+ struct cvp_set_mute_cmd cvp_mute_cmd;
+ int ret = 0;
+ void *apr_cvp;
+ u16 cvp_handle;
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+ return -EINVAL;
+ }
+ apr_cvp = common.apr_q6_cvp;
+
+ if (!apr_cvp) {
+ pr_err("%s: apr_cvp is NULL.\n", __func__);
+ return -EINVAL;
+ }
+ cvp_handle = voice_get_cvp_handle(v);
+
+ cvp_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvp_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvp_mute_cmd) - APR_HDR_SIZE);
+ cvp_mute_cmd.hdr.src_port = v->session_id;
+ cvp_mute_cmd.hdr.dest_port = cvp_handle;
+ cvp_mute_cmd.hdr.token = 0;
+ cvp_mute_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_MUTE;
+ cvp_mute_cmd.cvp_set_mute.direction = 1;
+ cvp_mute_cmd.cvp_set_mute.mute_flag = v->dev_rx.mute;
+ v->cvp_state = CMD_STATUS_FAIL;
+ ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_mute_cmd);
+ if (ret < 0) {
+ pr_err("Fail in sending RX device mute cmd\n");
+ return -EINVAL;
+ }
+ ret = wait_event_timeout(v->cvp_wait,
+ (v->cvp_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int voice_send_vol_index_cmd(struct voice_data *v)
{
struct cvp_set_rx_volume_index_cmd cvp_vol_cmd;
@@ -2883,6 +2928,49 @@
return ret;
}
+int voc_set_rx_device_mute(uint16_t session_id, uint32_t mute)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ v->dev_rx.mute = mute;
+
+ if (v->voc_state == VOC_RUN)
+ ret = voice_send_rx_device_mute_cmd(v);
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
+int voc_get_rx_device_mute(uint16_t session_id)
+{
+ struct voice_data *v = voice_get_session(session_id);
+ int ret = 0;
+
+ if (v == NULL) {
+ pr_err("%s: invalid session_id 0x%x\n", __func__, session_id);
+
+ return -EINVAL;
+ }
+
+ mutex_lock(&v->lock);
+
+ ret = v->dev_rx.mute;
+
+ mutex_unlock(&v->lock);
+
+ return ret;
+}
+
int voc_set_tty_mode(uint16_t session_id, uint8_t tty_mode)
{
struct voice_data *v = voice_get_session(session_id);
@@ -3571,6 +3659,7 @@
/* initialize dev_rx and dev_tx */
common.voice[i].dev_rx.volume = common.default_vol_val;
+ common.voice[i].dev_rx.mute = 0;
common.voice[i].dev_tx.mute = common.default_mute_val;
common.voice[i].dev_tx.port_id = 1;
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index 1a24b9c..0edf1c9 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.h
@@ -637,6 +637,8 @@
#define VSS_MEDIA_ID_G729 0x00010FD0
/* G.729AB (contains two 10ms vocoder frames. */
+#define VSS_IVOCPROC_CMD_SET_MUTE 0x000110EF
+
#define VOICE_CMD_SET_PARAM 0x00011006
#define VOICE_CMD_GET_PARAM 0x00011007
#define VOICE_EVT_GET_PARAM_ACK 0x00011008
@@ -729,6 +731,22 @@
/* Size of the volume calibration table in bytes. */
} __packed;
+struct vss_ivocproc_cmd_set_mute_t {
+ uint16_t direction;
+ /*
+ * 0 : TX only.
+ * 1 : RX only.
+ * 2 : TX and Rx.
+ */
+ uint16_t mute_flag;
+ /*
+ * Mute, un-mute.
+ *
+ * 0 : Disable.
+ * 1 : Enable.
+ */
+} __packed;
+
struct cvp_create_full_ctl_session_cmd {
struct apr_hdr hdr;
struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
@@ -770,6 +788,11 @@
struct apr_hdr hdr;
} __packed;
+struct cvp_set_mute_cmd {
+ struct apr_hdr hdr;
+ struct vss_ivocproc_cmd_set_mute_t cvp_set_mute;
+} __packed;
+
/* CB for up-link packets. */
typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
uint32_t pkt_len,
@@ -904,6 +927,8 @@
uint32_t dev_type);
int voc_set_rx_vol_index(uint16_t session_id, uint32_t dir, uint32_t voc_idx);
int voc_set_tx_mute(uint16_t session_id, uint32_t dir, uint32_t mute);
+int voc_set_rx_device_mute(uint16_t session_id, uint32_t mute);
+int voc_get_rx_device_mute(uint16_t session_id);
int voc_disable_cvp(uint16_t session_id);
int voc_enable_cvp(uint16_t session_id);
int voc_set_route_flag(uint16_t session_id, uint8_t path_dir, uint8_t set);
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index d528f4b..76091e3 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1144,6 +1144,11 @@
struct snd_soc_codec *codec;
int i;
+ if (!card->instantiated) {
+ dev_dbg(card->dev, "uninsantiated card found card->name = %s\n",
+ card->name);
+ return 0;
+ }
/* If the initialization of this soc device failed, there is no codec
* associated with it. Just bail out in this case.
*/
@@ -1397,6 +1402,11 @@
struct snd_soc_card *card = dev_get_drvdata(dev);
int i, ac97_control = 0;
+ if (!card->instantiated) {
+ dev_dbg(card->dev, "uninsantiated card found card->name = %s\n",
+ card->name);
+ return 0;
+ }
/* AC97 devices might have other drivers hanging off them so
* need to resume immediately. Other drivers don't have that
* problem and may take a substantial amount of time to resume