Merge changes Icc72e27b,I4bdddb5d into msm-3.0

* changes:
  thermal: tsens: Change the TSENS min threshold
  thermal: tsens: Add tsens notify callback
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
new file mode 100644
index 0000000..8516401
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -0,0 +1,3366 @@
+  <section id="control">
+    <title>User Controls</title>
+
+    <para>Devices typically have a number of user-settable controls
+such as brightness, saturation and so on, which would be presented to
+the user on a graphical user interface. But, different devices
+will have different controls available, and furthermore, the range of
+possible values, and the default value will vary from device to
+device. The control ioctls provide the information and a mechanism to
+create a nice user interface for these controls that will work
+correctly with any device.</para>
+
+    <para>All controls are accessed using an ID value. V4L2 defines
+several IDs for specific purposes. Drivers can also implement their
+own custom controls using <constant>V4L2_CID_PRIVATE_BASE</constant>
+and higher values. The pre-defined control IDs have the prefix
+<constant>V4L2_CID_</constant>, and are listed in <xref
+linkend="control-id" />. The ID is used when querying the attributes of
+a control, and when getting or setting the current value.</para>
+
+    <para>Generally applications should present controls to the user
+without assumptions about their purpose. Each control comes with a
+name string the user is supposed to understand. When the purpose is
+non-intuitive the driver writer should provide a user manual, a user
+interface plug-in or a driver specific panel application. Predefined
+IDs were introduced to change a few controls programmatically, for
+example to mute a device during a channel switch.</para>
+
+    <para>Drivers may enumerate different controls after switching
+the current video input or output, tuner or modulator, or audio input
+or output. Different in the sense of other bounds, another default and
+current value, step size or other menu items. A control with a certain
+<emphasis>custom</emphasis> ID can also change name and
+type.<footnote>
+	<para>It will be more convenient for applications if drivers
+make use of the <constant>V4L2_CTRL_FLAG_DISABLED</constant> flag, but
+that was never required.</para>
+      </footnote> Control values are stored globally, they do not
+change when switching except to stay within the reported bounds. They
+also do not change &eg; when the device is opened or closed, when the
+tuner radio frequency is changed or generally never without
+application request. Since V4L2 specifies no event mechanism, panel
+applications intended to cooperate with other panel applications (be
+they built into a larger application, as a TV viewer) may need to
+regularly poll control values to update their user
+interface.<footnote>
+	<para>Applications could call an ioctl to request events.
+After another process called &VIDIOC-S-CTRL; or another ioctl changing
+shared properties the &func-select; function would indicate
+readability until any ioctl (querying the properties) is
+called.</para>
+      </footnote></para>
+
+    <para>
+      All controls use machine endianness.
+    </para>
+
+    <table pgwide="1" frame="none" id="control-id">
+      <title>Control IDs</title>
+      <tgroup cols="3">
+	&cs-def;
+	<thead>
+	  <row>
+	    <entry>ID</entry>
+	    <entry>Type</entry>
+	    <entry>Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>V4L2_CID_BASE</constant></entry>
+	    <entry></entry>
+	    <entry>First predefined ID, equal to
+<constant>V4L2_CID_BRIGHTNESS</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_USER_BASE</constant></entry>
+	    <entry></entry>
+	    <entry>Synonym of <constant>V4L2_CID_BASE</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_BRIGHTNESS</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Picture brightness, or more precisely, the black
+level.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_CONTRAST</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Picture contrast or luma gain.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_SATURATION</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Picture color saturation or chroma gain.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_HUE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Hue or color balance.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUDIO_VOLUME</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Overall audio volume. Note some drivers also
+provide an OSS or ALSA mixer interface.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUDIO_BALANCE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Audio stereo balance. Minimum corresponds to all
+the way left, maximum to right.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUDIO_BASS</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Audio bass adjustment.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUDIO_TREBLE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Audio treble adjustment.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUDIO_MUTE</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Mute audio, &ie; set the volume to zero, however
+without affecting <constant>V4L2_CID_AUDIO_VOLUME</constant>. Like
+ALSA drivers, V4L2 drivers must mute at load time to avoid excessive
+noise. Actually the entire device should be reset to a low power
+consumption state.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUDIO_LOUDNESS</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Loudness mode (bass boost).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_BLACK_LEVEL</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Another name for brightness (not a synonym of
+<constant>V4L2_CID_BRIGHTNESS</constant>). This control is deprecated
+and should not be used in new drivers and applications.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUTO_WHITE_BALANCE</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Automatic white balance (cameras).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_DO_WHITE_BALANCE</constant></entry>
+	    <entry>button</entry>
+	    <entry>This is an action control. When set (the value is
+ignored), the device will do a white balance and then hold the current
+setting. Contrast this with the boolean
+<constant>V4L2_CID_AUTO_WHITE_BALANCE</constant>, which, when
+activated, keeps adjusting the white balance.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_RED_BALANCE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Red chroma balance.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_BLUE_BALANCE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Blue chroma balance.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_GAMMA</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Gamma adjust.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_WHITENESS</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Whiteness for grey-scale devices. This is a synonym
+for <constant>V4L2_CID_GAMMA</constant>. This control is deprecated
+and should not be used in new drivers and applications.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_EXPOSURE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Exposure (cameras). [Unit?]</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_AUTOGAIN</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Automatic gain/exposure control.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_GAIN</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Gain control.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_HFLIP</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Mirror the picture horizontally.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_VFLIP</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Mirror the picture vertically.</entry>
+	  </row>
+	<row>
+	  <entry><constant>V4L2_CID_HCENTER_DEPRECATED</constant> (formerly <constant>V4L2_CID_HCENTER</constant>)</entry>
+	    <entry>integer</entry>
+	    <entry>Horizontal image centering. This control is
+deprecated. New drivers and applications should use the <link
+linkend="camera-controls">Camera class controls</link>
+<constant>V4L2_CID_PAN_ABSOLUTE</constant>,
+<constant>V4L2_CID_PAN_RELATIVE</constant> and
+<constant>V4L2_CID_PAN_RESET</constant> instead.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_VCENTER_DEPRECATED</constant>
+	    (formerly <constant>V4L2_CID_VCENTER</constant>)</entry>
+	    <entry>integer</entry>
+	    <entry>Vertical image centering. Centering is intended to
+<emphasis>physically</emphasis> adjust cameras. For image cropping see
+<xref linkend="crop" />, for clipping <xref linkend="overlay" />. This
+control is deprecated. New drivers and applications should use the
+<link linkend="camera-controls">Camera class controls</link>
+<constant>V4L2_CID_TILT_ABSOLUTE</constant>,
+<constant>V4L2_CID_TILT_RELATIVE</constant> and
+<constant>V4L2_CID_TILT_RESET</constant> instead.</entry>
+	  </row>
+	  <row id="v4l2-power-line-frequency">
+	    <entry><constant>V4L2_CID_POWER_LINE_FREQUENCY</constant></entry>
+	    <entry>enum</entry>
+	    <entry>Enables a power line frequency filter to avoid
+flicker. Possible values for <constant>enum v4l2_power_line_frequency</constant> are:
+<constant>V4L2_CID_POWER_LINE_FREQUENCY_DISABLED</constant> (0),
+<constant>V4L2_CID_POWER_LINE_FREQUENCY_50HZ</constant> (1) and
+<constant>V4L2_CID_POWER_LINE_FREQUENCY_60HZ</constant> (2).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_HUE_AUTO</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Enables automatic hue control by the device. The
+effect of setting <constant>V4L2_CID_HUE</constant> while automatic
+hue control is enabled is undefined, drivers should ignore such
+request.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_WHITE_BALANCE_TEMPERATURE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>This control specifies the white balance settings
+as a color temperature in Kelvin. A driver should have a minimum of
+2800 (incandescent) to 6500 (daylight). For more information about
+color temperature see <ulink
+url="http://en.wikipedia.org/wiki/Color_temperature">Wikipedia</ulink>.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_SHARPNESS</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Adjusts the sharpness filters in a camera. The
+minimum value disables the filters, higher values give a sharper
+picture.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_BACKLIGHT_COMPENSATION</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Adjusts the backlight compensation in a camera. The
+minimum value disables backlight compensation.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_CHROMA_AGC</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Chroma automatic gain control.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_CHROMA_GAIN</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Adjusts the Chroma gain control (for use when chroma AGC
+	    is disabled).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_COLOR_KILLER</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Enable the color killer (&ie; force a black &amp; white image in case of a weak video signal).</entry>
+	  </row>
+	  <row id="v4l2-colorfx">
+	    <entry><constant>V4L2_CID_COLORFX</constant></entry>
+	    <entry>enum</entry>
+	    <entry>Selects a color effect. Possible values for
+<constant>enum v4l2_colorfx</constant> are:
+<constant>V4L2_COLORFX_NONE</constant> (0),
+<constant>V4L2_COLORFX_BW</constant> (1),
+<constant>V4L2_COLORFX_SEPIA</constant> (2),
+<constant>V4L2_COLORFX_NEGATIVE</constant> (3),
+<constant>V4L2_COLORFX_EMBOSS</constant> (4),
+<constant>V4L2_COLORFX_SKETCH</constant> (5),
+<constant>V4L2_COLORFX_SKY_BLUE</constant> (6),
+<constant>V4L2_COLORFX_GRASS_GREEN</constant> (7),
+<constant>V4L2_COLORFX_SKIN_WHITEN</constant> (8) and
+<constant>V4L2_COLORFX_VIVID</constant> (9).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_ROTATE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Rotates the image by specified angle. Common angles are 90,
+	    270 and 180. Rotating the image to 90 and 270 will reverse the height
+	    and width of the display window. It is necessary to set the new height and
+	    width of the picture using the &VIDIOC-S-FMT; ioctl according to
+	    the rotation angle selected.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_BG_COLOR</constant></entry>
+	    <entry>integer</entry>
+	    <entry>Sets the background color on the current output device.
+	    Background color needs to be specified in the RGB24 format. The
+	    supplied 32 bit value is interpreted as bits 0-7 Red color information,
+	    bits 8-15 Green color information, bits 16-23 Blue color
+	    information and bits 24-31 must be zero.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_ILLUMINATORS_1</constant>
+		<constant>V4L2_CID_ILLUMINATORS_2</constant></entry>
+	    <entry>boolean</entry>
+	    <entry>Switch on or off the illuminator 1 or 2 of the device
+		(usually a microscope).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_LASTP1</constant></entry>
+	    <entry></entry>
+	    <entry>End of the predefined control IDs (currently
+<constant>V4L2_CID_ILLUMINATORS_2</constant> + 1).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_CAPTURE</constant></entry>
+	    <entry>integer</entry>
+	    <entry>This is a read-only control that can be read by the application
+and used as a hint to determine the number of CAPTURE buffers to pass to REQBUFS.
+The value is the minimum number of CAPTURE buffers that is necessary for hardware
+to work.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_MIN_BUFFERS_FOR_OUTPUT</constant></entry>
+	    <entry>integer</entry>
+	    <entry>This is a read-only control that can be read by the application
+and used as a hint to determine the number of OUTPUT buffers to pass to REQBUFS.
+The value is the minimum number of OUTPUT buffers that is necessary for hardware
+to work.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_CID_PRIVATE_BASE</constant></entry>
+	    <entry></entry>
+	    <entry>ID of the first custom (driver specific) control.
+Applications depending on particular custom controls should check the
+driver name and version, see <xref linkend="querycap" />.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <para>Applications can enumerate the available controls with the
+&VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls, get and set a
+control value with the &VIDIOC-G-CTRL; and &VIDIOC-S-CTRL; ioctls.
+Drivers must implement <constant>VIDIOC_QUERYCTRL</constant>,
+<constant>VIDIOC_G_CTRL</constant> and
+<constant>VIDIOC_S_CTRL</constant> when the device has one or more
+controls, <constant>VIDIOC_QUERYMENU</constant> when it has one or
+more menu type controls.</para>
+
+    <example>
+      <title>Enumerating all controls</title>
+
+      <programlisting>
+&v4l2-queryctrl; queryctrl;
+&v4l2-querymenu; querymenu;
+
+static void
+enumerate_menu (void)
+{
+	printf ("  Menu items:\n");
+
+	memset (&amp;querymenu, 0, sizeof (querymenu));
+	querymenu.id = queryctrl.id;
+
+	for (querymenu.index = queryctrl.minimum;
+	     querymenu.index &lt;= queryctrl.maximum;
+	      querymenu.index++) {
+		if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &amp;querymenu)) {
+			printf ("  %s\n", querymenu.name);
+		}
+	}
+}
+
+memset (&amp;queryctrl, 0, sizeof (queryctrl));
+
+for (queryctrl.id = V4L2_CID_BASE;
+     queryctrl.id &lt; V4L2_CID_LASTP1;
+     queryctrl.id++) {
+	if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+		if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
+			continue;
+
+		printf ("Control %s\n", queryctrl.name);
+
+		if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+			enumerate_menu ();
+	} else {
+		if (errno == EINVAL)
+			continue;
+
+		perror ("VIDIOC_QUERYCTRL");
+		exit (EXIT_FAILURE);
+	}
+}
+
+for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
+     queryctrl.id++) {
+	if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+		if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED)
+			continue;
+
+		printf ("Control %s\n", queryctrl.name);
+
+		if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+			enumerate_menu ();
+	} else {
+		if (errno == EINVAL)
+			break;
+
+		perror ("VIDIOC_QUERYCTRL");
+		exit (EXIT_FAILURE);
+	}
+}
+</programlisting>
+    </example>
+
+    <example>
+      <title>Changing controls</title>
+
+      <programlisting>
+&v4l2-queryctrl; queryctrl;
+&v4l2-control; control;
+
+memset (&amp;queryctrl, 0, sizeof (queryctrl));
+queryctrl.id = V4L2_CID_BRIGHTNESS;
+
+if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;queryctrl)) {
+	if (errno != EINVAL) {
+		perror ("VIDIOC_QUERYCTRL");
+		exit (EXIT_FAILURE);
+	} else {
+		printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+	}
+} else if (queryctrl.flags &amp; V4L2_CTRL_FLAG_DISABLED) {
+	printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+} else {
+	memset (&amp;control, 0, sizeof (control));
+	control.id = V4L2_CID_BRIGHTNESS;
+	control.value = queryctrl.default_value;
+
+	if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)) {
+		perror ("VIDIOC_S_CTRL");
+		exit (EXIT_FAILURE);
+	}
+}
+
+memset (&amp;control, 0, sizeof (control));
+control.id = V4L2_CID_CONTRAST;
+
+if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &amp;control)) {
+	control.value += 1;
+
+	/* The driver may clamp the value or return ERANGE, ignored here */
+
+	if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &amp;control)
+	    &amp;&amp; errno != ERANGE) {
+		perror ("VIDIOC_S_CTRL");
+		exit (EXIT_FAILURE);
+	}
+/* Ignore if V4L2_CID_CONTRAST is unsupported */
+} else if (errno != EINVAL) {
+	perror ("VIDIOC_G_CTRL");
+	exit (EXIT_FAILURE);
+}
+
+control.id = V4L2_CID_AUDIO_MUTE;
+control.value = TRUE; /* silence */
+
+/* Errors ignored */
+ioctl (fd, VIDIOC_S_CTRL, &amp;control);
+</programlisting>
+    </example>
+  </section>
+
+  <section id="extended-controls">
+    <title>Extended Controls</title>
+
+    <section>
+      <title>Introduction</title>
+
+      <para>The control mechanism as originally designed was meant
+to be used for user settings (brightness, saturation, etc). However,
+it turned out to be a very useful model for implementing more
+complicated driver APIs where each driver implements only a subset of
+a larger API.</para>
+
+      <para>The MPEG encoding API was the driving force behind
+designing and implementing this extended control mechanism: the MPEG
+standard is quite large and the currently supported hardware MPEG
+encoders each only implement a subset of this standard. Further more,
+many parameters relating to how the video is encoded into an MPEG
+stream are specific to the MPEG encoding chip since the MPEG standard
+only defines the format of the resulting MPEG stream, not how the
+video is actually encoded into that format.</para>
+
+      <para>Unfortunately, the original control API lacked some
+features needed for these new uses and so it was extended into the
+(not terribly originally named) extended control API.</para>
+
+      <para>Even though the MPEG encoding API was the first effort
+to use the Extended Control API, nowadays there are also other classes
+of Extended Controls, such as Camera Controls and FM Transmitter Controls.
+The Extended Controls API as well as all Extended Controls classes are
+described in the following text.</para>
+    </section>
+
+    <section>
+      <title>The Extended Control API</title>
+
+      <para>Three new ioctls are available: &VIDIOC-G-EXT-CTRLS;,
+&VIDIOC-S-EXT-CTRLS; and &VIDIOC-TRY-EXT-CTRLS;. These ioctls act on
+arrays of controls (as opposed to the &VIDIOC-G-CTRL; and
+&VIDIOC-S-CTRL; ioctls that act on a single control). This is needed
+since it is often required to atomically change several controls at
+once.</para>
+
+      <para>Each of the new ioctls expects a pointer to a
+&v4l2-ext-controls;. This structure contains a pointer to the control
+array, a count of the number of controls in that array and a control
+class. Control classes are used to group similar controls into a
+single class. For example, control class
+<constant>V4L2_CTRL_CLASS_USER</constant> contains all user controls
+(&ie; all controls that can also be set using the old
+<constant>VIDIOC_S_CTRL</constant> ioctl). Control class
+<constant>V4L2_CTRL_CLASS_MPEG</constant> contains all controls
+relating to MPEG encoding, etc.</para>
+
+      <para>All controls in the control array must belong to the
+specified control class. An error is returned if this is not the
+case.</para>
+
+      <para>It is also possible to use an empty control array (count
+== 0) to check whether the specified control class is
+supported.</para>
+
+      <para>The control array is a &v4l2-ext-control; array. The
+<structname>v4l2_ext_control</structname> structure is very similar to
+&v4l2-control;, except for the fact that it also allows for 64-bit
+values and pointers to be passed.</para>
+
+      <para>It is important to realize that due to the flexibility of
+controls it is necessary to check whether the control you want to set
+actually is supported in the driver and what the valid range of values
+is. So use the &VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls to
+check this. Also note that it is possible that some of the menu
+indices in a control of type <constant>V4L2_CTRL_TYPE_MENU</constant>
+may not be supported (<constant>VIDIOC_QUERYMENU</constant> will
+return an error). A good example is the list of supported MPEG audio
+bitrates. Some drivers only support one or two bitrates, others
+support a wider range.</para>
+
+      <para>
+	All controls use machine endianness.
+      </para>
+    </section>
+
+    <section>
+      <title>Enumerating Extended Controls</title>
+
+      <para>The recommended way to enumerate over the extended
+controls is by using &VIDIOC-QUERYCTRL; in combination with the
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag:</para>
+
+      <informalexample>
+	<programlisting>
+&v4l2-queryctrl; qctrl;
+
+qctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
+	/* ... */
+	qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
+</programlisting>
+      </informalexample>
+
+      <para>The initial control ID is set to 0 ORed with the
+<constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant> flag. The
+<constant>VIDIOC_QUERYCTRL</constant> ioctl will return the first
+control with a higher ID than the specified one. When no such controls
+are found an error is returned.</para>
+
+      <para>If you want to get all controls within a specific control
+class, then you can set the initial
+<structfield>qctrl.id</structfield> value to the control class and add
+an extra check to break out of the loop when a control of another
+control class is found:</para>
+
+      <informalexample>
+	<programlisting>
+qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &amp;qctrl)) {
+	if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
+		break;
+		/* ... */
+		qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+	}
+</programlisting>
+      </informalexample>
+
+      <para>The 32-bit <structfield>qctrl.id</structfield> value is
+subdivided into three bit ranges: the top 4 bits are reserved for
+flags (&eg; <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>) and are not
+actually part of the ID. The remaining 28 bits form the control ID, of
+which the most significant 12 bits define the control class and the
+least significant 16 bits identify the control within the control
+class. It is guaranteed that these last 16 bits are always non-zero
+for controls. The range of 0x1000 and up are reserved for
+driver-specific controls. The macro
+<constant>V4L2_CTRL_ID2CLASS(id)</constant> returns the control class
+ID based on a control ID.</para>
+
+      <para>If the driver does not support extended controls, then
+<constant>VIDIOC_QUERYCTRL</constant> will fail when used in
+combination with <constant>V4L2_CTRL_FLAG_NEXT_CTRL</constant>. In
+that case the old method of enumerating control should be used (see
+1.8). But if it is supported, then it is guaranteed to enumerate over
+all controls, including driver-private controls.</para>
+    </section>
+
+    <section>
+      <title>Creating Control Panels</title>
+
+      <para>It is possible to create control panels for a graphical
+user interface where the user can select the various controls.
+Basically you will have to iterate over all controls using the method
+described above. Each control class starts with a control of type
+<constant>V4L2_CTRL_TYPE_CTRL_CLASS</constant>.
+<constant>VIDIOC_QUERYCTRL</constant> will return the name of this
+control class which can be used as the title of a tab page within a
+control panel.</para>
+
+      <para>The flags field of &v4l2-queryctrl; also contains hints on
+the behavior of the control. See the &VIDIOC-QUERYCTRL; documentation
+for more details.</para>
+    </section>
+
+    <section id="mpeg-controls">
+      <title>MPEG Control Reference</title>
+
+      <para>Below all controls within the MPEG control class are
+described. First the generic controls, then controls specific for
+certain hardware.</para>
+
+      <section>
+	<title>Generic MPEG Controls</title>
+
+	<table pgwide="1" frame="none" id="mpeg-control-id">
+	  <title>MPEG Control IDs</title>
+	  <tgroup cols="4">
+	    <colspec colname="c1" colwidth="1*" />
+	    <colspec colname="c2" colwidth="6*" />
+	    <colspec colname="c3" colwidth="2*" />
+	    <colspec colname="c4" colwidth="6*" />
+	    <spanspec namest="c1" nameend="c2" spanname="id" />
+	    <spanspec namest="c2" nameend="c4" spanname="descr" />
+	    <thead>
+	      <row>
+		<entry spanname="id" align="left">ID</entry>
+		<entry align="left">Type</entry>
+	      </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	      </row>
+	    </thead>
+	    <tbody valign="top">
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CLASS</constant>&nbsp;</entry>
+		<entry>class</entry>
+	      </row><row><entry spanname="descr">The MPEG class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class. This description can be used as the
+caption of a Tab page in a GUI, for example.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-stream-type">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_TYPE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_stream_type</entry>
+	      </row><row><entry spanname="descr">The MPEG-1, -2 or -4
+output stream type. One cannot assume anything here. Each hardware
+MPEG encoder tends to support different subsets of the available MPEG
+stream types. This control is specific to multiplexed MPEG streams.
+The currently defined stream types are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_PS</constant>&nbsp;</entry>
+		      <entry>MPEG-2 program stream</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_TS</constant>&nbsp;</entry>
+		      <entry>MPEG-2 transport stream</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_SS</constant>&nbsp;</entry>
+		      <entry>MPEG-1 system stream</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_DVD</constant>&nbsp;</entry>
+		      <entry>MPEG-2 DVD-compatible stream</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_VCD</constant>&nbsp;</entry>
+		      <entry>MPEG-1 VCD-compatible stream</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD</constant>&nbsp;</entry>
+		      <entry>MPEG-2 SVCD-compatible stream</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PMT</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Program Map Table
+Packet ID for the MPEG transport stream (default 16)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_AUDIO</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Audio Packet ID for
+the MPEG transport stream (default 256)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_VIDEO</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Video Packet ID for
+the MPEG transport stream (default 260)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PID_PCR</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Packet ID for the
+MPEG transport stream carrying PCR fields (default 259)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_AUDIO</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Audio ID for MPEG
+PES</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_PES_ID_VIDEO</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Video ID for MPEG
+PES</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-stream-vbi-fmt">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_STREAM_VBI_FMT</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_stream_vbi_fmt</entry>
+	      </row><row><entry spanname="descr">Some cards can embed
+VBI data (&eg; Closed Caption, Teletext) into the MPEG stream. This
+control selects whether VBI data should be embedded, and if so, what
+embedding method should be used. The list of possible VBI formats
+depends on the driver. The currently defined VBI format types
+are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_NONE</constant>&nbsp;</entry>
+		      <entry>No VBI in the MPEG stream</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant>&nbsp;</entry>
+		      <entry>VBI in private packets, IVTV format (documented
+in the kernel sources in the file <filename>Documentation/video4linux/cx2341x/README.vbi</filename>)</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-sampling-freq">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_sampling_freq</entry>
+	      </row><row><entry spanname="descr">MPEG Audio sampling
+frequency. Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100</constant>&nbsp;</entry>
+		      <entry>44.1 kHz</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000</constant>&nbsp;</entry>
+		      <entry>48 kHz</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000</constant>&nbsp;</entry>
+		      <entry>32 kHz</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-encoding">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_ENCODING</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_encoding</entry>
+	      </row><row><entry spanname="descr">MPEG Audio encoding.
+This control is specific to multiplexed MPEG streams.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_1</constant>&nbsp;</entry>
+		      <entry>MPEG-1/2 Layer I encoding</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_2</constant>&nbsp;</entry>
+		      <entry>MPEG-1/2 Layer II encoding</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_3</constant>&nbsp;</entry>
+		      <entry>MPEG-1/2 Layer III encoding</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant>&nbsp;</entry>
+		      <entry>MPEG-2/4 AAC (Advanced Audio Coding)</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant>&nbsp;</entry>
+		      <entry>AC-3 aka ATSC A/52 encoding</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-l1-bitrate">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L1_BITRATE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_l1_bitrate</entry>
+	      </row><row><entry spanname="descr">MPEG-1/2 Layer I bitrate.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_32K</constant>&nbsp;</entry>
+		      <entry>32 kbit/s</entry></row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_64K</constant>&nbsp;</entry>
+		      <entry>64 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_96K</constant>&nbsp;</entry>
+		      <entry>96 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_128K</constant>&nbsp;</entry>
+		      <entry>128 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_160K</constant>&nbsp;</entry>
+		      <entry>160 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_192K</constant>&nbsp;</entry>
+		      <entry>192 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_224K</constant>&nbsp;</entry>
+		      <entry>224 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_256K</constant>&nbsp;</entry>
+		      <entry>256 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_288K</constant>&nbsp;</entry>
+		      <entry>288 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_320K</constant>&nbsp;</entry>
+		      <entry>320 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_352K</constant>&nbsp;</entry>
+		      <entry>352 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_384K</constant>&nbsp;</entry>
+		      <entry>384 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_416K</constant>&nbsp;</entry>
+		      <entry>416 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_448K</constant>&nbsp;</entry>
+		      <entry>448 kbit/s</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-l2-bitrate">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L2_BITRATE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_l2_bitrate</entry>
+	      </row><row><entry spanname="descr">MPEG-1/2 Layer II bitrate.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_32K</constant>&nbsp;</entry>
+		      <entry>32 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_48K</constant>&nbsp;</entry>
+		      <entry>48 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_56K</constant>&nbsp;</entry>
+		      <entry>56 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_64K</constant>&nbsp;</entry>
+		      <entry>64 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_80K</constant>&nbsp;</entry>
+		      <entry>80 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_96K</constant>&nbsp;</entry>
+		      <entry>96 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_112K</constant>&nbsp;</entry>
+		      <entry>112 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_128K</constant>&nbsp;</entry>
+		      <entry>128 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_160K</constant>&nbsp;</entry>
+		      <entry>160 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_192K</constant>&nbsp;</entry>
+		      <entry>192 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_224K</constant>&nbsp;</entry>
+		      <entry>224 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_256K</constant>&nbsp;</entry>
+		      <entry>256 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_320K</constant>&nbsp;</entry>
+		      <entry>320 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_384K</constant>&nbsp;</entry>
+		      <entry>384 kbit/s</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-l3-bitrate">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_L3_BITRATE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_l3_bitrate</entry>
+	      </row><row><entry spanname="descr">MPEG-1/2 Layer III bitrate.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_32K</constant>&nbsp;</entry>
+		      <entry>32 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_40K</constant>&nbsp;</entry>
+		      <entry>40 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_48K</constant>&nbsp;</entry>
+		      <entry>48 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_56K</constant>&nbsp;</entry>
+		      <entry>56 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_64K</constant>&nbsp;</entry>
+		      <entry>64 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_80K</constant>&nbsp;</entry>
+		      <entry>80 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_96K</constant>&nbsp;</entry>
+		      <entry>96 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_112K</constant>&nbsp;</entry>
+		      <entry>112 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_128K</constant>&nbsp;</entry>
+		      <entry>128 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_160K</constant>&nbsp;</entry>
+		      <entry>160 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_192K</constant>&nbsp;</entry>
+		      <entry>192 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_224K</constant>&nbsp;</entry>
+		      <entry>224 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_256K</constant>&nbsp;</entry>
+		      <entry>256 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_320K</constant>&nbsp;</entry>
+		      <entry>320 kbit/s</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AAC_BITRATE</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">AAC bitrate in bits per second.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-ac3-bitrate">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_AC3_BITRATE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_ac3_bitrate</entry>
+	      </row><row><entry spanname="descr">AC-3 bitrate.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_32K</constant>&nbsp;</entry>
+		      <entry>32 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_40K</constant>&nbsp;</entry>
+		      <entry>40 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_48K</constant>&nbsp;</entry>
+		      <entry>48 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_56K</constant>&nbsp;</entry>
+		      <entry>56 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_64K</constant>&nbsp;</entry>
+		      <entry>64 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_80K</constant>&nbsp;</entry>
+		      <entry>80 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_96K</constant>&nbsp;</entry>
+		      <entry>96 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_112K</constant>&nbsp;</entry>
+		      <entry>112 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_128K</constant>&nbsp;</entry>
+		      <entry>128 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_160K</constant>&nbsp;</entry>
+		      <entry>160 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_192K</constant>&nbsp;</entry>
+		      <entry>192 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_224K</constant>&nbsp;</entry>
+		      <entry>224 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_256K</constant>&nbsp;</entry>
+		      <entry>256 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_320K</constant>&nbsp;</entry>
+		      <entry>320 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_384K</constant>&nbsp;</entry>
+		      <entry>384 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_448K</constant>&nbsp;</entry>
+		      <entry>448 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_512K</constant>&nbsp;</entry>
+		      <entry>512 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_576K</constant>&nbsp;</entry>
+		      <entry>576 kbit/s</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_640K</constant>&nbsp;</entry>
+		      <entry>640 kbit/s</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-mode">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_mode</entry>
+	      </row><row><entry spanname="descr">MPEG Audio mode.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_STEREO</constant>&nbsp;</entry>
+		      <entry>Stereo</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_JOINT_STEREO</constant>&nbsp;</entry>
+		      <entry>Joint Stereo</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_DUAL</constant>&nbsp;</entry>
+		      <entry>Bilingual</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_MONO</constant>&nbsp;</entry>
+		      <entry>Mono</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-mode-extension">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MODE_EXTENSION</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_mode_extension</entry>
+	      </row><row><entry spanname="descr">Joint Stereo
+audio mode extension. In Layer I and II they indicate which subbands
+are in intensity stereo. All other subbands are coded in stereo. Layer
+III is not (yet) supported. Possible values
+are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4</constant>&nbsp;</entry>
+		      <entry>Subbands 4-31 in intensity stereo</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8</constant>&nbsp;</entry>
+		      <entry>Subbands 8-31 in intensity stereo</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12</constant>&nbsp;</entry>
+		      <entry>Subbands 12-31 in intensity stereo</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16</constant>&nbsp;</entry>
+		      <entry>Subbands 16-31 in intensity stereo</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-emphasis">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_EMPHASIS</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_emphasis</entry>
+	      </row><row><entry spanname="descr">Audio Emphasis.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_NONE</constant>&nbsp;</entry>
+		      <entry>None</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS</constant>&nbsp;</entry>
+		      <entry>50/15 microsecond emphasis</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17</constant>&nbsp;</entry>
+		      <entry>CCITT J.17</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-audio-crc">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_CRC</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_audio_crc</entry>
+	      </row><row><entry spanname="descr">CRC method. Possible
+values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_CRC_NONE</constant>&nbsp;</entry>
+		      <entry>None</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_AUDIO_CRC_CRC16</constant>&nbsp;</entry>
+		      <entry>16 bit parity check</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_AUDIO_MUTE</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Mutes the audio when
+capturing. This is not done by muting audio hardware, which can still
+produce a slight hiss, but in the encoder itself, guaranteeing a fixed
+and reproducible audio bitstream. 0 = unmuted, 1 = muted.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-video-encoding">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ENCODING</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_video_encoding</entry>
+	      </row><row><entry spanname="descr">MPEG Video encoding
+method. This control is specific to multiplexed MPEG streams.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_1</constant>&nbsp;</entry>
+		      <entry>MPEG-1 Video encoding</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_2</constant>&nbsp;</entry>
+		      <entry>MPEG-2 Video encoding</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant>&nbsp;</entry>
+		      <entry>MPEG-4 AVC (H.264) Video encoding</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-video-aspect">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_ASPECT</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_video_aspect</entry>
+	      </row><row><entry spanname="descr">Video aspect.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_ASPECT_1x1</constant>&nbsp;</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_ASPECT_4x3</constant>&nbsp;</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_ASPECT_16x9</constant>&nbsp;</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_ASPECT_221x100</constant>&nbsp;</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_B_FRAMES</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Number of B-Frames
+(default 2)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_SIZE</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">GOP size (default
+12)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_GOP_CLOSURE</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">GOP closure (default
+1)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_PULLDOWN</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Enable 3:2 pulldown
+(default 0)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-video-bitrate-mode">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_video_bitrate_mode</entry>
+	      </row><row><entry spanname="descr">Video bitrate mode.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_VBR</constant>&nbsp;</entry>
+		      <entry>Variable bitrate</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_CBR</constant>&nbsp;</entry>
+		      <entry>Constant bitrate</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Video bitrate in bits
+per second.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE_PEAK</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Peak video bitrate in
+bits per second. Must be larger or equal to the average video bitrate.
+It is ignored if the video bitrate mode is set to constant
+bitrate.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">For every captured
+frame, skip this many subsequent frames (default 0).</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">"Mutes" the video to a
+fixed color when capturing. This is useful for testing, to produce a
+fixed video bitstream. 0 = unmuted, 1 = muted.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MUTE_YUV</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Sets the "mute" color
+of the video. The supplied 32-bit integer is interpreted as follows (bit
+0 = least significant bit):</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry>Bit 0:7</entry>
+		      <entry>V chrominance information</entry>
+		    </row>
+		    <row>
+		      <entry>Bit 8:15</entry>
+		      <entry>U chrominance information</entry>
+		    </row>
+		    <row>
+		      <entry>Bit 16:23</entry>
+		      <entry>Y luminance information</entry>
+		    </row>
+		    <row>
+		      <entry>Bit 24:31</entry>
+		      <entry>Must be zero.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">If enabled the decoder expects to receive a single slice per buffer, otherwise
+the decoder expects a single frame in per buffer. Applicable to the decoder, all codecs.
+</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">Enable writing sample aspect ratio in the Video Usability Information.
+Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_video_h264_vui_sar_idc</entry>
+	      </row>
+	      <row><entry spanname="descr">VUI sample aspect ratio indicator for H.264 encoding. The value
+is defined in the table E-1 in the standard. Applicable to the H264 encoder.</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED</constant>&nbsp;</entry>
+			  <entry>Unspecified</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1</constant>&nbsp;</entry>
+			  <entry>1x1</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11</constant>&nbsp;</entry>
+			  <entry>12x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11</constant>&nbsp;</entry>
+			  <entry>10x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11</constant>&nbsp;</entry>
+			  <entry>16x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33</constant>&nbsp;</entry>
+			  <entry>40x33</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11</constant>&nbsp;</entry>
+			  <entry>24x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11</constant>&nbsp;</entry>
+			  <entry>20x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11</constant>&nbsp;</entry>
+			  <entry>32x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33</constant>&nbsp;</entry>
+			  <entry>80x33</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11</constant>&nbsp;</entry>
+			  <entry>18x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11</constant>&nbsp;</entry>
+			  <entry>15x11</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33</constant>&nbsp;</entry>
+			  <entry>64x33</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99</constant>&nbsp;</entry>
+			  <entry>160x99</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3</constant>&nbsp;</entry>
+			  <entry>4x3</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2</constant>&nbsp;</entry>
+			  <entry>3x2</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1</constant>&nbsp;</entry>
+			  <entry>2x1</entry>
+			</row>
+			<row>
+			  <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED</constant>&nbsp;</entry>
+			  <entry>Extended SAR</entry>
+			</row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Extended sample aspect ratio width for H.264 VUI encoding.
+Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Extended sample aspect ratio height for H.264 VUI encoding.
+Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LEVEL</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_video_h264_level</entry>
+	      </row>
+	      <row><entry spanname="descr">The level information for the H264 video elementary stream.
+Applicable to the H264 encoder.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_0</constant>&nbsp;</entry>
+		      <entry>Level 1.0</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1B</constant>&nbsp;</entry>
+		      <entry>Level 1B</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_1</constant>&nbsp;</entry>
+		      <entry>Level 1.1</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_2</constant>&nbsp;</entry>
+		      <entry>Level 1.2</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_3</constant>&nbsp;</entry>
+		      <entry>Level 1.3</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_0</constant>&nbsp;</entry>
+		      <entry>Level 2.0</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_1</constant>&nbsp;</entry>
+		      <entry>Level 2.1</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_2</constant>&nbsp;</entry>
+		      <entry>Level 2.2</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_0</constant>&nbsp;</entry>
+		      <entry>Level 3.0</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_1</constant>&nbsp;</entry>
+		      <entry>Level 3.1</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_2</constant>&nbsp;</entry>
+		      <entry>Level 3.2</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_0</constant>&nbsp;</entry>
+		      <entry>Level 4.0</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_1</constant>&nbsp;</entry>
+		      <entry>Level 4.1</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_2</constant>&nbsp;</entry>
+		      <entry>Level 4.2</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_0</constant>&nbsp;</entry>
+		      <entry>Level 5.0</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_1</constant>&nbsp;</entry>
+		      <entry>Level 5.1</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_video_mpeg4_level</entry>
+	      </row>
+	      <row><entry spanname="descr">The level information for the MPEG4 elementary stream.
+Applicable to the MPEG4 encoder.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0</constant>&nbsp;</entry>
+		      <entry>Level 0</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0B</constant>&nbsp;</entry>
+		      <entry>Level 0b</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_1</constant>&nbsp;</entry>
+		      <entry>Level 1</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_2</constant>&nbsp;</entry>
+		      <entry>Level 2</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3</constant>&nbsp;</entry>
+		      <entry>Level 3</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3B</constant>&nbsp;</entry>
+		      <entry>Level 3b</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_4</constant>&nbsp;</entry>
+		      <entry>Level 4</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_LEVEL_5</constant>&nbsp;</entry>
+		      <entry>Level 5</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_PROFILE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_h264_profile</entry>
+	      </row>
+	      <row><entry spanname="descr">The profile information for H264.
+Applicable to the H264 encoder.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE</constant>&nbsp;</entry>
+		      <entry>Baseline profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE</constant>&nbsp;</entry>
+		      <entry>Constrained Baseline profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MAIN</constant>&nbsp;</entry>
+		      <entry>Main profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED</constant>&nbsp;</entry>
+		      <entry>Extended profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH</constant>&nbsp;</entry>
+		      <entry>High profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10</constant>&nbsp;</entry>
+		      <entry>High 10 profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422</constant>&nbsp;</entry>
+		      <entry>High 422 profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE</constant>&nbsp;</entry>
+		      <entry>High 444 Predictive profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA</constant>&nbsp;</entry>
+		      <entry>High 10 Intra profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA</constant>&nbsp;</entry>
+		      <entry>High 422 Intra profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA</constant>&nbsp;</entry>
+		      <entry>High 444 Intra profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA</constant>&nbsp;</entry>
+		      <entry>CAVLC 444 Intra profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE</constant>&nbsp;</entry>
+		      <entry>Scalable Baseline profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH</constant>&nbsp;</entry>
+		      <entry>Scalable High profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA</constant>&nbsp;</entry>
+		      <entry>Scalable High Intra profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH</constant>&nbsp;</entry>
+		      <entry>Stereo High profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH</constant>&nbsp;</entry>
+		      <entry>Multiview High profile</entry>
+		    </row>
+
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_mpeg4_profile</entry>
+	      </row>
+	      <row><entry spanname="descr">The profile information for MPEG4.
+Applicable to the MPEG4 encoder.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE</constant>&nbsp;</entry>
+		      <entry>Simple profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_SIMPLE</constant>&nbsp;</entry>
+		      <entry>Advanced Simple profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_PROFILE_CORE</constant>&nbsp;</entry>
+		      <entry>Core profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE_SCALABLE</constant>&nbsp;</entry>
+		      <entry>Simple Scalable profile</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_CODING_EFFICIENCY</constant>&nbsp;</entry>
+		      <entry></entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MAX_REF_PIC</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">The maximum number of reference pictures used for encoding.
+Applicable to the encoder.
+</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_multi_slice_mode</entry>
+	      </row>
+	      <row><entry spanname="descr">Determines how the encoder should handle division of frame into slices.
+Applicable to the encoder.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE</constant>&nbsp;</entry>
+		      <entry>Single slice per frame.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>&nbsp;</entry>
+		      <entry>Multiple slices with set maximum number of macroblocks per slice.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>&nbsp;</entry>
+		      <entry>Multiple slice with set maximum size in bytes per slice.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">The maximum number of macroblocks in a slice. Used when
+<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant>.
+Applicable to the encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">The maximum size of a slice in bytes. Used when
+<constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> is set to <constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES</constant>.
+Applicable to the encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_h264_loop_filter_mode</entry>
+	      </row>
+	      <row><entry spanname="descr">Loop filter mode for H264 encoder.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED</constant>&nbsp;</entry>
+		      <entry>Loop filter is enabled.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED</constant>&nbsp;</entry>
+		      <entry>Loop filter is disabled.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY</constant>&nbsp;</entry>
+		      <entry>Loop filter is disabled at the slice boundary.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Loop filter alpha coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Loop filter beta coefficient, defined in the H264 standard.
+Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_h264_symbol_mode</entry>
+	      </row>
+	      <row><entry spanname="descr">Entropy coding mode for H264 - CABAC/CAVALC.
+Applicable to the H264 encoder.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC</constant>&nbsp;</entry>
+		      <entry>Use CAVLC entropy coding.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC</constant>&nbsp;</entry>
+		      <entry>Use CABAC entropy coding.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">Enable 8X8 transform for H264. Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Cyclic intra macroblock refresh. This is the number of continuous macroblocks
+refreshed every frame. Each frame a succesive set of macroblocks is refreshed until the cycle completes and starts from the
+top of the frame. Applicable to H264, H263 and MPEG4 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">Frame level rate control enable.
+If this control is disabled then the quantization parameter for each frame type is constant and set with appropriate controls
+(e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>).
+If frame rate control is enabled then quantization parameter is adjusted to meet the chosen bitrate. Minimum and maximum value
+for the quantization parameter can be set with appropriate controls (e.g. <constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>).
+Applicable to encoders.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">Macroblock level rate control enable.
+Applicable to the MPEG4 and H264 encoders.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_QPEL</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">Quarter pixel motion estimation for MPEG4. Applicable to the MPEG4 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an I frame for H263. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MIN_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Minimum quantization parameter for H263. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_MAX_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Maximum quantization parameter for H263. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an P frame for H263. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an B frame for H263. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an I frame for H264. Valid range: from 0 to 51.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MIN_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Minimum quantization parameter for H264. Valid range: from 0 to 51.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_MAX_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Maximum quantization parameter for H264. Valid range: from 0 to 51.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an P frame for H264. Valid range: from 0 to 51.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an B frame for H264. Valid range: from 0 to 51.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an I frame for MPEG4. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Minimum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Maximum quantization parameter for MPEG4. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an P frame for MPEG4. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Quantization parameter for an B frame for MPEG4. Valid range: from 1 to 31.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VBV_SIZE</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">The Video Buffer Verifier size in kilobytes, it is used as a limitation of frame skip.
+The VBV is defined in the standard as a mean to verify that the produced stream will be succesfully decoded.
+The standard describes it as "Part of a hypothetical decoder that is conceptually connected to the
+output of the encoder. Its purpose is to provide a constraint on the variability of the data rate that an
+encoder or editing process may produce.".
+Applicable to the MPEG1, MPEG2, MPEG4 encoders.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">The Coded Picture Buffer size in kilobytes, it is used as a limitation of frame skip.
+The CPB is defined in the H264 standard as a mean to verify that the produced stream will be succesfully decoded.
+Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_I_PERIOD</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row>
+	      <row><entry spanname="descr">Period between I-frames in the open GOP for H264. In case of an open GOP
+this is the period between two I-frames. The period between IDR (Instantaneous Decoding Refresh) frames is taken from the GOP_SIZE control.
+An IDR frame, which stands for Instantaneous Decoding Refresh is an I-frame after which no prior frames are
+referenced. This means that a stream can be restarted from an IDR frame without the need to store or decode any
+previous frames. Applicable to the H264 encoder.</entry>
+	      </row>
+
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_HEADER_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_header_mode</entry>
+	      </row>
+	      <row><entry spanname="descr">Determines whether the header is returned as the first buffer or is
+it returned together with the first frame. Applicable to encoders.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE</constant>&nbsp;</entry>
+		      <entry>The stream header is returned separately in the first buffer.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME</constant>&nbsp;</entry>
+		      <entry>The stream header is returned together with the first encoded frame.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Enabled the deblocking post processing filter for MPEG4 decoder.
+Applicable to the MPEG4 decoder.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_RES</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">vop_time_increment_resolution value for MPEG4. Applicable to the MPEG4 encoder.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_VOP_TIME_INC</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">vop_time_increment value for MPEG4. Applicable to the MPEG4 encoder.</entry>
+	      </row>
+
+	    </tbody>
+	  </tgroup>
+	</table>
+      </section>
+
+      <section>
+	<title>MFC 5.1 MPEG Controls</title>
+
+	<para>The following MPEG class controls deal with MPEG
+decoding and encoding settings that are specific to the Multi Format Codec 5.1 device present
+in the S5P family of SoCs by Samsung.
+</para>
+
+	<table pgwide="1" frame="none" id="mfc51-control-id">
+	  <title>MFC 5.1 Control IDs</title>
+	  <tgroup cols="4">
+	    <colspec colname="c1" colwidth="1*" />
+	    <colspec colname="c2" colwidth="6*" />
+	    <colspec colname="c3" colwidth="2*" />
+	    <colspec colname="c4" colwidth="6*" />
+	    <spanspec namest="c1" nameend="c2" spanname="id" />
+	    <spanspec namest="c2" nameend="c4" spanname="descr" />
+	    <thead>
+	      <row>
+		<entry spanname="id" align="left">ID</entry>
+		<entry align="left">Type</entry>
+	      </row><row><entry spanname="descr" align="left">Description</entry>
+	      </row>
+	    </thead>
+	    <tbody valign="top">
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">If the display delay is enabled then the decoder has to return a
+CAPTURE buffer after processing a certain number of OUTPUT buffers. If this number is low, then it may result in
+buffers not being dequeued in display order. In addition hardware may still use those buffers as reference, thus
+application should not write to those buffers. This feature can be used for example for generating thumbnails of videos.
+Applicable to the H264 decoder.
+	      </entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Display delay value for H264 decoder.
+The decoder is forced to return a decoded frame after the set 'display delay' number of frames. If this number is
+low it may result in frames returned out of dispaly order, in addition the hardware may still be using the returned buffer
+as a reference picture for subsequent frames.
+</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">The number of reference pictures used for encoding a P picture.
+Applicable to the H264 encoder.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Padding enable in the encoder - use a color instead of repeating border pixels.
+Applicable to encoders.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Padding color in the encoder. Applicable to encoders. The supplied 32-bit integer is interpreted as follows (bit
+0 = least significant bit):</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry>Bit 0:7</entry>
+		      <entry>V chrominance information</entry>
+		    </row>
+		    <row>
+		      <entry>Bit 8:15</entry>
+		      <entry>U chrominance information</entry>
+		    </row>
+		    <row>
+		      <entry>Bit 16:23</entry>
+		      <entry>Y luminance information</entry>
+		    </row>
+		    <row>
+		      <entry>Bit 24:31</entry>
+		      <entry>Must be zero.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Reaction coefficient for MFC rate control. Applicable to encoders.
+<para>Note 1: Valid only when the frame level RC is enabled.</para>
+<para>Note 2: For tight CBR, this field must be small (ex. 2 ~ 10).
+For VBR, this field must be large (ex. 100 ~ 1000).</para>
+<para>Note 3: It is not recommended to use the greater number than FRAME_RATE * (10^9 / BIT_RATE).</para>
+</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Adaptive rate control for dark region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Adaptive rate control for smooth region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Adaptive rate control for static region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row><row><entry spanname="descr">Adaptive rate control for activity region.
+Valid only when H.264 and macroblock level RC is enabled (<constant>V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE</constant>).
+Applicable to the H264 encoder.</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_mfc51_frame_skip_mode</entry>
+	      </row>
+	      <row><entry spanname="descr">
+Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then
+a chosen data limit then the frame will be skipped.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_DISABLED</constant>&nbsp;</entry>
+		      <entry>Frame skip mode is disabled.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_LEVEL_LIMIT</constant>&nbsp;</entry>
+		      <entry>Frame skip mode enabled and buffer limit is set by the chosen level and is defined by the standard.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_BUF_LIMIT</constant>&nbsp;</entry>
+		      <entry>Frame skip mode enabled and buffer limit is set by the VBV (MPEG1/2/4) or CPB (H264) buffer size control.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT</constant>&nbsp;</entry>
+		<entry>integer</entry>
+	      </row><row><entry spanname="descr">Enable rate-control with fixed target bit.
+If this setting is enabled, then the rate control logic of the encoder will calculate the average bitrate
+for a GOP and keep it below or equal the set bitrate target. Otherwise the rate control logic calculates the
+overall average bitrate for the stream and keeps it below or equal to the set bitrate. In the first case
+the average bitrate for the whole stream will be smaller then the set bitrate. This is caused because the
+average is calculated for smaller number of frames, on the other hand enabling this setting will ensure that
+the stream will meet tight bandwidth contraints. Applicable to encoders.
+</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_mfc51_force_frame_type</entry>
+	      </row>
+	      <row><entry spanname="descr">Force a frame type for the next queued buffer. Applicable to encoders.
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_DISABLED</constant>&nbsp;</entry>
+		      <entry>Forcing a specific frame type disabled.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_I_FRAME</constant>&nbsp;</entry>
+		      <entry>Force an I-frame.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_NOT_CODED</constant>&nbsp;</entry>
+		      <entry>Force a non-coded frame.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	    </tbody>
+	  </tgroup>
+	</table>
+      </section>
+
+      <section>
+	<title>CX2341x MPEG Controls</title>
+
+	<para>The following MPEG class controls deal with MPEG
+encoding settings that are specific to the Conexant CX23415 and
+CX23416 MPEG encoding chips.</para>
+
+	<table pgwide="1" frame="none" id="cx2341x-control-id">
+	  <title>CX2341x Control IDs</title>
+	  <tgroup cols="4">
+	    <colspec colname="c1" colwidth="1*" />
+	    <colspec colname="c2" colwidth="6*" />
+	    <colspec colname="c3" colwidth="2*" />
+	    <colspec colname="c4" colwidth="6*" />
+	    <spanspec namest="c1" nameend="c2" spanname="id" />
+	    <spanspec namest="c2" nameend="c4" spanname="descr" />
+	    <thead>
+	      <row>
+		<entry spanname="id" align="left">ID</entry>
+		<entry align="left">Type</entry>
+	      </row><row><entry spanname="descr" align="left">Description</entry>
+	      </row>
+	    </thead>
+	    <tbody valign="top">
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-cx2341x-video-spatial-filter-mode">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_cx2341x_video_spatial_filter_mode</entry>
+	      </row><row><entry spanname="descr">Sets the Spatial
+Filter mode (default <constant>MANUAL</constant>). Possible values
+are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
+		      <entry>Choose the filter manually</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
+		      <entry>Choose the filter automatically</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER</constant>&nbsp;</entry>
+		<entry>integer&nbsp;(0-15)</entry>
+	      </row><row><entry spanname="descr">The setting for the
+Spatial Filter. 0 = off, 15 = maximum. (Default is 0.)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="luma-spatial-filter-type">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_cx2341x_video_luma_spatial_filter_type</entry>
+	      </row><row><entry spanname="descr">Select the algorithm
+to use for the Luma Spatial Filter (default
+<constant>1D_HOR</constant>). Possible values:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+		      <entry>No filter</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
+		      <entry>One-dimensional horizontal</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT</constant>&nbsp;</entry>
+		      <entry>One-dimensional vertical</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE</constant>&nbsp;</entry>
+		      <entry>Two-dimensional separable</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE</constant>&nbsp;</entry>
+		      <entry>Two-dimensional symmetrical
+non-separable</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="chroma-spatial-filter-type">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type</entry>
+	      </row><row><entry spanname="descr">Select the algorithm
+for the Chroma Spatial Filter (default <constant>1D_HOR</constant>).
+Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+		      <entry>No filter</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR</constant>&nbsp;</entry>
+		      <entry>One-dimensional horizontal</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-cx2341x-video-temporal-filter-mode">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_cx2341x_video_temporal_filter_mode</entry>
+	      </row><row><entry spanname="descr">Sets the Temporal
+Filter mode (default <constant>MANUAL</constant>). Possible values
+are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL</constant>&nbsp;</entry>
+		      <entry>Choose the filter manually</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO</constant>&nbsp;</entry>
+		      <entry>Choose the filter automatically</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER</constant>&nbsp;</entry>
+		<entry>integer&nbsp;(0-31)</entry>
+	      </row><row><entry spanname="descr">The setting for the
+Temporal Filter. 0 = off, 31 = maximum. (Default is 8 for full-scale
+capturing and 0 for scaled capturing.)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row id="v4l2-mpeg-cx2341x-video-median-filter-type">
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE</constant>&nbsp;</entry>
+		<entry>enum&nbsp;v4l2_mpeg_cx2341x_video_median_filter_type</entry>
+	      </row><row><entry spanname="descr">Median Filter Type
+(default <constant>OFF</constant>). Possible values are:</entry>
+	      </row>
+	      <row>
+		<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF</constant>&nbsp;</entry>
+		      <entry>No filter</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR</constant>&nbsp;</entry>
+		      <entry>Horizontal filter</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT</constant>&nbsp;</entry>
+		      <entry>Vertical filter</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT</constant>&nbsp;</entry>
+		      <entry>Horizontal and vertical filter</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG</constant>&nbsp;</entry>
+		      <entry>Diagonal filter</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
+		<entry>integer&nbsp;(0-255)</entry>
+	      </row><row><entry spanname="descr">Threshold above which
+the luminance median filter is enabled (default 0)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
+		<entry>integer&nbsp;(0-255)</entry>
+	      </row><row><entry spanname="descr">Threshold below which
+the luminance median filter is enabled (default 255)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM</constant>&nbsp;</entry>
+		<entry>integer&nbsp;(0-255)</entry>
+	      </row><row><entry spanname="descr">Threshold above which
+the chroma median filter is enabled (default 0)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP</constant>&nbsp;</entry>
+		<entry>integer&nbsp;(0-255)</entry>
+	      </row><row><entry spanname="descr">Threshold below which
+the chroma median filter is enabled (default 255)</entry>
+	      </row>
+	      <row><entry></entry></row>
+	      <row>
+		<entry spanname="id"><constant>V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS</constant>&nbsp;</entry>
+		<entry>boolean</entry>
+	      </row>
+	      <row><entry spanname="descr">The CX2341X MPEG encoder
+can insert one empty MPEG-2 PES packet into the stream between every
+four video frames. The packet size is 2048 bytes, including the
+packet_start_code_prefix and stream_id fields. The stream_id is 0xBF
+(private stream 2). The payload consists of 0x00 bytes, to be filled
+in by the application. 0 = do not insert, 1 = insert packets.</entry>
+	      </row>
+	    </tbody>
+	  </tgroup>
+	</table>
+      </section>
+    </section>
+
+    <section id="camera-controls">
+      <title>Camera Control Reference</title>
+
+      <para>The Camera class includes controls for mechanical (or
+equivalent digital) features of a device such as controllable lenses
+or sensors.</para>
+
+    <table pgwide="1" frame="none" id="camera-control-id">
+      <title>Camera Control IDs</title>
+      <tgroup cols="4">
+	<colspec colname="c1" colwidth="1*" />
+	<colspec colname="c2" colwidth="6*" />
+	<colspec colname="c3" colwidth="2*" />
+	<colspec colname="c4" colwidth="6*" />
+	<spanspec namest="c1" nameend="c2" spanname="id" />
+	<spanspec namest="c2" nameend="c4" spanname="descr" />
+	<thead>
+	  <row>
+	    <entry spanname="id" align="left">ID</entry>
+	    <entry align="left">Type</entry>
+	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row><entry></entry></row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_CAMERA_CLASS</constant>&nbsp;</entry>
+	    <entry>class</entry>
+	  </row><row><entry spanname="descr">The Camera class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row id="v4l2-exposure-auto-type">
+	    <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO</constant>&nbsp;</entry>
+	    <entry>enum&nbsp;v4l2_exposure_auto_type</entry>
+	  </row><row><entry spanname="descr">Enables automatic
+adjustments of the exposure time and/or iris aperture. The effect of
+manual changes of the exposure time or iris aperture while these
+features are enabled is undefined, drivers should ignore such
+requests. Possible values are:</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_EXPOSURE_AUTO</constant>&nbsp;</entry>
+		      <entry>Automatic exposure time, automatic iris
+aperture.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_EXPOSURE_MANUAL</constant>&nbsp;</entry>
+		  <entry>Manual exposure time, manual iris.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_EXPOSURE_SHUTTER_PRIORITY</constant>&nbsp;</entry>
+		  <entry>Manual exposure time, auto iris.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_EXPOSURE_APERTURE_PRIORITY</constant>&nbsp;</entry>
+		  <entry>Auto exposure time, manual iris.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_EXPOSURE_ABSOLUTE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">Determines the exposure
+time of the camera sensor. The exposure time is limited by the frame
+interval. Drivers should interpret the values as 100 &micro;s units,
+where the value 1 stands for 1/10000th of a second, 10000 for 1 second
+and 100000 for 10 seconds.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_EXPOSURE_AUTO_PRIORITY</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row><row><entry spanname="descr">When
+<constant>V4L2_CID_EXPOSURE_AUTO</constant> is set to
+<constant>AUTO</constant> or <constant>APERTURE_PRIORITY</constant>,
+this control determines if the device may dynamically vary the frame
+rate. By default this feature is disabled (0) and the frame rate must
+remain constant.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PAN_RELATIVE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control turns the
+camera horizontally by the specified amount. The unit is undefined. A
+positive value moves the camera to the right (clockwise when viewed
+from above), a negative value to the left. A value of zero does not
+cause motion. This is a write-only control.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_TILT_RELATIVE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control turns the
+camera vertically by the specified amount. The unit is undefined. A
+positive value moves the camera up, a negative value down. A value of
+zero does not cause motion. This is a write-only control.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PAN_RESET</constant>&nbsp;</entry>
+	    <entry>button</entry>
+	  </row><row><entry spanname="descr">When this control is set,
+the camera moves horizontally to the default position.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_TILT_RESET</constant>&nbsp;</entry>
+	    <entry>button</entry>
+	  </row><row><entry spanname="descr">When this control is set,
+the camera moves vertically to the default position.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PAN_ABSOLUTE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control
+turns the camera horizontally to the specified position. Positive
+values move the camera to the right (clockwise when viewed from above),
+negative values to the left. Drivers should interpret the values as arc
+seconds, with valid values between -180 * 3600 and +180 * 3600
+inclusive.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_TILT_ABSOLUTE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control
+turns the camera vertically to the specified position. Positive values
+move the camera up, negative values down. Drivers should interpret the
+values as arc seconds, with valid values between -180 * 3600 and +180
+* 3600 inclusive.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FOCUS_ABSOLUTE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control sets the
+focal point of the camera to the specified position. The unit is
+undefined. Positive values set the focus closer to the camera,
+negative values towards infinity.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FOCUS_RELATIVE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control moves the
+focal point of the camera by the specified amount. The unit is
+undefined. Positive values move the focus closer to the camera,
+negative values towards infinity. This is a write-only control.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FOCUS_AUTO</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row><row><entry spanname="descr">Enables automatic focus
+adjustments. The effect of manual focus adjustments while this feature
+is enabled is undefined, drivers should ignore such requests.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_ZOOM_ABSOLUTE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">Specify the objective lens
+focal length as an absolute value. The zoom unit is driver-specific and its
+value should be a positive integer.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_ZOOM_RELATIVE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">Specify the objective lens
+focal length relatively to the current value. Positive values move the zoom
+lens group towards the telephoto direction, negative values towards the
+wide-angle direction. The zoom unit is driver-specific. This is a write-only control.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_ZOOM_CONTINUOUS</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">Move the objective lens group
+at the specified speed until it reaches physical device limits or until an
+explicit request to stop the movement. A positive value moves the zoom lens
+group towards the telephoto direction. A value of zero stops the zoom lens
+group movement. A negative value moves the zoom lens group towards the
+wide-angle direction. The zoom speed unit is driver-specific.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IRIS_ABSOLUTE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control sets the
+camera's aperture to the specified value. The unit is undefined.
+Larger values open the iris wider, smaller values close it.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_IRIS_RELATIVE</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">This control modifies the
+camera's aperture by the specified amount. The unit is undefined.
+Positive values open the iris one step further, negative values close
+it one step further. This is a write-only control.</entry>
+	  </row>
+	  <row><entry></entry></row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PRIVACY</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row><row><entry spanname="descr">Prevent video from being acquired
+by the camera. When this control is set to <constant>TRUE</constant> (1), no
+image can be captured by the camera. Common means to enforce privacy are
+mechanical obturation of the sensor and firmware image processing, but the
+device is not restricted to these methods. Devices that implement the privacy
+control must support read access and may support write access.</entry>
+	  </row>
+
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_BAND_STOP_FILTER</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row><row><entry spanname="descr">Switch the band-stop filter of a
+camera sensor on or off, or specify its strength. Such band-stop filters can
+be used, for example, to filter out the fluorescent light component.</entry>
+	  </row>
+	  <row><entry></entry></row>
+	</tbody>
+      </tgroup>
+    </table>
+  </section>
+
+    <section id="fm-tx-controls">
+      <title>FM Transmitter Control Reference</title>
+
+      <para>The FM Transmitter (FM_TX) class includes controls for common features of
+FM transmissions capable devices. Currently this class includes parameters for audio
+compression, pilot tone generation, audio deviation limiter, RDS transmission and
+tuning power features.</para>
+
+      <table pgwide="1" frame="none" id="fm-tx-control-id">
+      <title>FM_TX Control IDs</title>
+
+      <tgroup cols="4">
+	<colspec colname="c1" colwidth="1*" />
+	<colspec colname="c2" colwidth="6*" />
+	<colspec colname="c3" colwidth="2*" />
+	<colspec colname="c4" colwidth="6*" />
+	<spanspec namest="c1" nameend="c2" spanname="id" />
+	<spanspec namest="c2" nameend="c4" spanname="descr" />
+	<thead>
+	  <row>
+	    <entry spanname="id" align="left">ID</entry>
+	    <entry align="left">Type</entry>
+	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row><entry></entry></row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FM_TX_CLASS</constant>&nbsp;</entry>
+	    <entry>class</entry>
+	  </row><row><entry spanname="descr">The FM_TX class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_DEVIATION</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Configures RDS signal frequency deviation level in Hz.
+The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_PI</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the RDS Programme Identification field
+for transmission.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_PTY</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the RDS Programme Type field for transmission.
+This encodes up to 31 pre-defined programme types.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_PS_NAME</constant>&nbsp;</entry>
+	    <entry>string</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Programme Service name (PS_NAME) for transmission.
+It is intended for static display on a receiver. It is the primary aid to listeners in programme service
+identification and selection.  In Annex E of <xref linkend="en50067" />, the RDS specification,
+there is a full description of the correct character encoding for Programme Service name strings.
+Also from RDS specification, PS is usually a single eight character text. However, it is also possible
+to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
+with steps of 8 characters. The result is it must always contain a string with size multiple of 8.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_RADIO_TEXT</constant>&nbsp;</entry>
+	    <entry>string</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Radio Text info for transmission. It is a textual description of
+what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
+programme-related information or any other text. In these cases, RadioText should be used in addition to
+<constant>V4L2_CID_RDS_TX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
+in Annex E of <xref linkend="en50067" />. The length of Radio Text strings depends on which RDS Block is being
+used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
+to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
+with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_ENABLED</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Enables or disables the audio deviation limiter feature.
+The limiter is useful when trying to maximize the audio volume, minimize receiver-generated
+distortion and prevent overmodulation.
+</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_RELEASE_TIME</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the audio deviation limiter feature release time.
+Unit is in useconds. Step and range are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_DEVIATION</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Configures audio frequency deviation level in Hz.
+The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ENABLED</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Enables or disables the audio compression feature.
+This feature amplifies signals below the threshold by a fixed gain and compresses audio
+signals above the threshold by the ratio of Threshold/(Gain + Threshold).</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_GAIN</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the gain for audio compression feature. It is
+a dB value. The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_THRESHOLD</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the threshold level for audio compression freature.
+It is a dB value. The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the attack time for audio compression feature.
+It is a useconds value. The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the release time for audio compression feature.
+It is a useconds value. The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_ENABLED</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Enables or disables the pilot tone generation feature.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_DEVIATION</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Configures pilot tone frequency deviation level. Unit is
+in Hz. The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_PILOT_TONE_FREQUENCY</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Configures pilot tone frequency value. Unit is
+in Hz. The range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_TUNE_PREEMPHASIS</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row id="v4l2-preemphasis"><entry spanname="descr">Configures the pre-emphasis value for broadcasting.
+A pre-emphasis filter is applied to the broadcast to accentuate the high audio frequencies.
+Depending on the region, a time constant of either 50 or 75 useconds is used. The enum&nbsp;v4l2_preemphasis
+defines possible values for pre-emphasis. Here they are:</entry>
+	</row><row>
+	<entrytbl spanname="descr" cols="2">
+		  <tbody valign="top">
+		    <row>
+		      <entry><constant>V4L2_PREEMPHASIS_DISABLED</constant>&nbsp;</entry>
+		      <entry>No pre-emphasis is applied.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_PREEMPHASIS_50_uS</constant>&nbsp;</entry>
+		      <entry>A pre-emphasis of 50 uS is used.</entry>
+		    </row>
+		    <row>
+		      <entry><constant>V4L2_PREEMPHASIS_75_uS</constant>&nbsp;</entry>
+		      <entry>A pre-emphasis of 75 uS is used.</entry>
+		    </row>
+		  </tbody>
+		</entrytbl>
+
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_TUNE_POWER_LEVEL</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the output power level for signal transmission.
+Unit is in dBuV. Range and step are driver-specific.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_TUNE_ANTENNA_CAPACITOR</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">This selects the value of antenna tuning capacitor
+manually or automatically if set to zero. Unit, range and step are driver-specific.</entry>
+	  </row>
+	  <row><entry></entry></row>
+	</tbody>
+      </tgroup>
+      </table>
+
+<para>For more details about RDS specification, refer to
+<xref linkend="en50067" /> document, from CENELEC.</para>
+    </section>
+
+    <section id="flash-controls">
+      <title>Flash Control Reference</title>
+
+      <note>
+	<title>Experimental</title>
+
+	<para>This is an <link linkend="experimental">experimental</link>
+interface and may change in the future.</para>
+      </note>
+
+      <para>
+	The V4L2 flash controls are intended to provide generic access
+	to flash controller devices. Flash controller devices are
+	typically used in digital cameras.
+      </para>
+
+      <para>
+	The interface can support both LED and xenon flash devices. As
+	of writing this, there is no xenon flash driver using this
+	interface.
+      </para>
+
+      <section id="flash-controls-use-cases">
+	<title>Supported use cases</title>
+
+	<section>
+	  <title>Unsynchronised LED flash (software strobe)</title>
+
+	  <para>
+	    Unsynchronised LED flash is controlled directly by the
+	    host as the sensor. The flash must be enabled by the host
+	    before the exposure of the image starts and disabled once
+	    it ends. The host is fully responsible for the timing of
+	    the flash.
+	  </para>
+
+	  <para>Example of such device: Nokia N900.</para>
+	</section>
+
+	<section>
+	  <title>Synchronised LED flash (hardware strobe)</title>
+
+	  <para>
+	    The synchronised LED flash is pre-programmed by the host
+	    (power and timeout) but controlled by the sensor through a
+	    strobe signal from the sensor to the flash.
+	  </para>
+
+	  <para>
+	    The sensor controls the flash duration and timing. This
+	    information typically must be made available to the
+	    sensor.
+	  </para>
+
+	</section>
+
+	<section>
+	  <title>LED flash as torch</title>
+
+	  <para>
+	    LED flash may be used as torch in conjunction with another
+	    use case involving camera or individually.
+	  </para>
+
+	</section>
+
+      </section>
+
+      <table pgwide="1" frame="none" id="flash-control-id">
+      <title>Flash Control IDs</title>
+
+      <tgroup cols="4">
+	<colspec colname="c1" colwidth="1*" />
+	<colspec colname="c2" colwidth="6*" />
+	<colspec colname="c3" colwidth="2*" />
+	<colspec colname="c4" colwidth="6*" />
+	<spanspec namest="c1" nameend="c2" spanname="id" />
+	<spanspec namest="c2" nameend="c4" spanname="descr" />
+	<thead>
+	  <row>
+	    <entry spanname="id" align="left">ID</entry>
+	    <entry align="left">Type</entry>
+	  </row><row rowsep="1"><entry spanname="descr" align="left">Description</entry>
+	  </row>
+	</thead>
+	<tbody valign="top">
+	  <row><entry></entry></row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_CLASS</constant></entry>
+	    <entry>class</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">The FLASH class descriptor.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_LED_MODE</constant></entry>
+	    <entry>menu</entry>
+	  </row>
+	  <row id="v4l2-flash-led-mode">
+	    <entry spanname="descr">Defines the mode of the flash LED,
+	    the high-power white LED attached to the flash controller.
+	    Setting this control may not be possible in presence of
+	    some faults. See V4L2_CID_FLASH_FAULT.</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_FLASH_LED_MODE_NONE</constant></entry>
+		  <entry>Off.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_FLASH_LED_MODE_FLASH</constant></entry>
+		  <entry>Flash mode.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_FLASH_LED_MODE_TORCH</constant></entry>
+		  <entry>Torch mode. See V4L2_CID_FLASH_TORCH_INTENSITY.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_SOURCE</constant></entry>
+	    <entry>menu</entry>
+	  </row>
+	  <row id="v4l2-flash-strobe-source"><entry
+	  spanname="descr">Defines the source of the flash LED
+	  strobe.</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_FLASH_STROBE_SOURCE_SOFTWARE</constant></entry>
+		  <entry>The flash strobe is triggered by using
+		  the V4L2_CID_FLASH_STROBE control.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_FLASH_STROBE_SOURCE_EXTERNAL</constant></entry>
+		  <entry>The flash strobe is triggered by an
+		  external source. Typically this is a sensor,
+		  which makes it possible to synchronises the
+		  flash strobe start to exposure start.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE</constant></entry>
+	    <entry>button</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Strobe flash. Valid when
+	    V4L2_CID_FLASH_LED_MODE is set to
+	    V4L2_FLASH_LED_MODE_FLASH and V4L2_CID_FLASH_STROBE_SOURCE
+	    is set to V4L2_FLASH_STROBE_SOURCE_SOFTWARE. Setting this
+	    control may not be possible in presence of some faults.
+	    See V4L2_CID_FLASH_FAULT.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STOP</constant></entry>
+	    <entry>button</entry>
+	  </row>
+	  <row><entry spanname="descr">Stop flash strobe immediately.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_STROBE_STATUS</constant></entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Strobe status: whether the flash
+	    is strobing at the moment or not. This is a read-only
+	    control.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_TIMEOUT</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Hardware timeout for flash. The
+	    flash strobe is stopped after this period of time has
+	    passed from the start of the strobe.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_INTENSITY</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Intensity of the flash strobe when
+	    the flash LED is in flash mode
+	    (V4L2_FLASH_LED_MODE_FLASH). The unit should be milliamps
+	    (mA) if possible.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_TORCH_INTENSITY</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Intensity of the flash LED in
+	    torch mode (V4L2_FLASH_LED_MODE_TORCH). The unit should be
+	    milliamps (mA) if possible. Setting this control may not
+	    be possible in presence of some faults. See
+	    V4L2_CID_FLASH_FAULT.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_INDICATOR_INTENSITY</constant></entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Intensity of the indicator LED.
+	    The indicator LED may be fully independent of the flash
+	    LED. The unit should be microamps (uA) if possible.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_FAULT</constant></entry>
+	    <entry>bitmask</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Faults related to the flash. The
+	    faults tell about specific problems in the flash chip
+	    itself or the LEDs attached to it. Faults may prevent
+	    further use of some of the flash controls. In particular,
+	    V4L2_CID_FLASH_LED_MODE is set to V4L2_FLASH_LED_MODE_NONE
+	    if the fault affects the flash LED. Exactly which faults
+	    have such an effect is chip dependent. Reading the faults
+	    resets the control and returns the chip to a usable state
+	    if possible.</entry>
+	  </row>
+	  <row>
+	    <entrytbl spanname="descr" cols="2">
+	      <tbody valign="top">
+		<row>
+		  <entry><constant>V4L2_FLASH_FAULT_OVER_VOLTAGE</constant></entry>
+		  <entry>Flash controller voltage to the flash LED
+		  has exceeded the limit specific to the flash
+		  controller.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_FLASH_FAULT_TIMEOUT</constant></entry>
+		  <entry>The flash strobe was still on when
+		  the timeout set by the user ---
+		  V4L2_CID_FLASH_TIMEOUT control --- has expired.
+		  Not all flash controllers may set this in all
+		  such conditions.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_FLASH_FAULT_OVER_TEMPERATURE</constant></entry>
+		  <entry>The flash controller has overheated.</entry>
+		</row>
+		<row>
+		  <entry><constant>V4L2_FLASH_FAULT_SHORT_CIRCUIT</constant></entry>
+		  <entry>The short circuit protection of the flash
+		  controller has been triggered.</entry>
+		</row>
+	      </tbody>
+	    </entrytbl>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_CHARGE</constant></entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Enable or disable charging of the xenon
+	  flash capacitor.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_FLASH_READY</constant></entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row>
+	    <entry spanname="descr">Is the flash ready to strobe?
+	    Xenon flashes require their capacitors charged before
+	    strobing. LED flashes often require a cooldown period
+	    after strobe during which another strobe will not be
+	    possible. This is a read-only control.</entry>
+	  </row>
+	  <row><entry></entry></row>
+	</tbody>
+      </tgroup>
+      </table>
+
+    </section>
+</section>
+
+  <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "common.sgml"
+indent-tabs-mode: nil
+End:
+  -->
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index a6b5d0b..0455878 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -788,7 +788,7 @@
 {
 	struct gic_chip_data *gic;
 	struct irq_domain *domain;
-	int gic_irqs;
+	int gic_irqs, rc;
 
 	BUG_ON(gic_nr >= MAX_GIC_NR);
 
@@ -801,11 +801,8 @@
 		gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
 		gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
 		if (WARN_ON(!gic->dist_base.percpu_base ||
-			    !gic->cpu_base.percpu_base)) {
-			free_percpu(gic->dist_base.percpu_base);
-			free_percpu(gic->cpu_base.percpu_base);
-			return;
-		}
+			    !gic->cpu_base.percpu_base))
+			goto init_bases_err;
 
 		for_each_possible_cpu(cpu) {
 			unsigned long offset = percpu_offset * cpu_logical_map(cpu);
@@ -857,12 +854,23 @@
 	}
 	domain->priv = gic;
 	domain->ops = &gic_irq_domain_ops;
-	irq_domain_add(domain);
+	rc = irq_domain_add(domain);
+	if (rc) {
+		WARN(1, "Unable to create irq_domain\n");
+		goto init_bases_err;
+	}
+	irq_domain_register(domain);
 
 	gic_chip.flags |= gic_arch_extn.flags;
 	gic_dist_init(gic);
 	gic_cpu_init(gic);
 	gic_pm_init(gic);
+
+	return;
+
+init_bases_err:
+	free_percpu(gic->dist_base.percpu_base);
+	free_percpu(gic->cpu_base.percpu_base);
 }
 
 void __cpuinit gic_secondary_init(unsigned int gic_nr)
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 92d401c..3d4b37d 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -34,7 +34,7 @@
 # CONFIG_MSM_HW3D is not set
 # CONFIG_QSD_AUDIO is not set
 # CONFIG_SURF_FFA_GPIO_KEYPAD is not set
-CONFIG_MSM_JTAG_V7=y
+CONFIG_MSM_JTAG=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_VMSPLIT_2G=y
diff --git a/arch/arm/configs/msm-copper_defconfig b/arch/arm/configs/msm-copper_defconfig
index 1379334..d69305c 100644
--- a/arch/arm/configs/msm-copper_defconfig
+++ b/arch/arm/configs/msm-copper_defconfig
@@ -94,6 +94,8 @@
 CONFIG_DCC_TTY=y
 CONFIG_DEBUG_GPIO=y
 CONFIG_GPIO_SYSFS=y
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
 # CONFIG_HWMON is not set
 # CONFIG_MFD_SUPPORT is not set
 # CONFIG_HID_SUPPORT is not set
diff --git a/arch/arm/configs/msm7627a_defconfig b/arch/arm/configs/msm7627a_defconfig
index eb9cd7c..cfa06a8 100644
--- a/arch/arm/configs/msm7627a_defconfig
+++ b/arch/arm/configs/msm7627a_defconfig
@@ -13,6 +13,7 @@
 CONFIG_RT_GROUP_SCHED=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
 CONFIG_ASHMEM=y
 CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
@@ -57,6 +58,7 @@
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_CMDLINE="init=/sbin/init root=/dev/ram rw initrd=0x11000000,16M console=ttyDCC0 mem=88M"
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_STAT_DETAILS=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
 CONFIG_CPU_FREQ_GOV_ONDEMAND=y
@@ -208,6 +210,7 @@
 CONFIG_SERIAL_MSM_CONSOLE=y
 CONFIG_SERIAL_MSM_HS=y
 # CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
+CONFIG_DIAG_CHAR=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_DCC_TTY=y
 CONFIG_I2C=y
@@ -258,8 +261,9 @@
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_72K=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
@@ -276,6 +280,9 @@
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -317,9 +324,12 @@
 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_TIMER_STATS=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_DEBUG_SLAB_LEAK=y
 CONFIG_DEBUG_SPINLOCK=y
 CONFIG_DEBUG_MUTEXES=y
 CONFIG_DEBUG_SPINLOCK_SLEEP=y
diff --git a/arch/arm/configs/msm7630_defconfig b/arch/arm/configs/msm7630_defconfig
index 388bb69..b4babeb 100644
--- a/arch/arm/configs/msm7630_defconfig
+++ b/arch/arm/configs/msm7630_defconfig
@@ -40,6 +40,8 @@
 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
 CONFIG_HIGH_RES_TIMERS=y
@@ -237,6 +239,7 @@
 # CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_HS=y
+CONFIG_DIAG_CHAR=y
 # CONFIG_HW_RANDOM is not set
 CONFIG_DCC_TTY=y
 CONFIG_I2C=y
@@ -259,6 +262,14 @@
 # CONFIG_MFD_PM8XXX_DEBUG is not set
 # CONFIG_MFD_PM8XXX_PWM is not set
 # CONFIG_MFD_PM8XXX_MISC is not set
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_VIDEO_DEV=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_WEBCAM_OV9726=y
+CONFIG_MT9E013=y
+CONFIG_MSM_GEMINI=y
+CONFIG_RADIO_TAVARUA=y
 CONFIG_MSM_KGSL=y
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
@@ -289,8 +300,9 @@
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_EHSET=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-CONFIG_USB_EHCI_MSM=y
+CONFIG_USB_EHCI_MSM_72K=y
 CONFIG_USB_ACM=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DATAFAB=y
@@ -307,6 +319,10 @@
 CONFIG_USB_EHSET_TEST_FIXTURE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_MSM_72K=y
+CONFIG_USB_G_ANDROID=y
+CONFIG_RMNET_SMD_CTL_CHANNEL="DATA40_CNTL"
+CONFIG_RMNET_SMD_DATA_CHANNEL="DATA40"
+CONFIG_RMNET_SDIO_SMD_DATA_CHANNEL=""
 CONFIG_USB_MSM_ACA=y
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
@@ -322,6 +338,7 @@
 CONFIG_MMC_MSM_SDC2_8_BIT_SUPPORT=y
 CONFIG_MMC_MSM_SDC3_SUPPORT=y
 CONFIG_MMC_MSM_SDC4_SUPPORT=y
+CONFIG_LEDS_PMIC8058=y
 CONFIG_SWITCH=y
 CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_CLASS=y
@@ -354,11 +371,16 @@
 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
 CONFIG_SCHEDSTATS=y
 CONFIG_TIMER_STATS=y
+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 84cd633..cc9a1b7 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -332,6 +332,7 @@
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 50b4b08..eb34964 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -332,6 +332,7 @@
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
 CONFIG_VIDEO_OUTPUT_CONTROL=y
 CONFIG_FB=y
 CONFIG_FB_MSM=y
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index 9feca99..0780d20 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -257,6 +257,7 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_HS=y
 # CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
@@ -309,6 +310,7 @@
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
 CONFIG_FB=y
 CONFIG_FB_VIRTUAL=y
 CONFIG_FB_MSM=y
@@ -319,6 +321,7 @@
 CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
 CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index e4257a4..bd92fe3 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -75,6 +75,7 @@
 CONFIG_MSM_WATCHDOG=y
 CONFIG_MSM_DLOAD_MODE=y
 CONFIG_MSM_QDSS=y
+CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE=y
 CONFIG_MSM_SLEEP_STATS=y
 CONFIG_STRICT_MEMORY_RWX=y
 CONFIG_NO_HZ=y
@@ -259,6 +260,7 @@
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_UINPUT=y
 CONFIG_INPUT_PMIC8XXX_PWRKEY=y
+# CONFIG_LEGACY_PTYS is not set
 CONFIG_SERIAL_MSM=y
 CONFIG_SERIAL_MSM_HS=y
 # CONFIG_SERIAL_MSM_CLOCK_CONTROL is not set
@@ -311,6 +313,7 @@
 CONFIG_ION_MSM=y
 CONFIG_MSM_KGSL=y
 CONFIG_KGSL_PER_PROCESS_PAGE_TABLE=y
+CONFIG_MSM_KGSL_PAGE_TABLE_COUNT=16
 CONFIG_FB=y
 CONFIG_FB_VIRTUAL=y
 CONFIG_FB_MSM=y
@@ -321,6 +324,7 @@
 CONFIG_FB_MSM_OVERLAY0_WRITEBACK=y
 CONFIG_FB_MSM_MIPI_PANEL_DETECT=y
 CONFIG_FB_MSM_HDMI_MSM_PANEL=y
+CONFIG_FB_MSM_WRITEBACK_MSM_PANEL=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 CONFIG_SOUND=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index d65c368..d34f5df 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -168,6 +168,8 @@
 CONFIG_USB_G_ANDROID=y
 CONFIG_RMNET_SMD_CTL_CHANNEL="DATA36_CNTL"
 CONFIG_RMNET_SMD_DATA_CHANNEL="DATA36"
+CONFIG_POWER_SUPPLY=y
+# CONFIG_BATTERY_MSM is not set
 CONFIG_MMC=y
 CONFIG_MMC_PERF_PROFILING=y
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -228,3 +230,5 @@
 CONFIG_CRYPTO_DEV_QCEDEV=m
 CONFIG_CRC_CCITT=y
 CONFIG_LIBCRC32C=y
+CONFIG_MSM_RPM_LOG=y
+CONFIG_MSM_RPM_STATS_LOG=y
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index bb0d03d..ed9ce4e 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -35,15 +35,6 @@
 #define HARDIRQ_BITS	8
 #endif
 
-/*
- * The hardirq mask has to be large enough to have space
- * for potentially all IRQ sources in the system nesting
- * on a single CPU:
- */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
-# error HARDIRQ_BITS is too low!
-#endif
-
 #define __ARCH_IRQ_EXIT_IRQS_DISABLED	1
 
 #endif /* __ASM_HARDIRQ_H */
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 76f86d7..738a166 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -266,6 +266,7 @@
 {
 	struct thread_info *thread = current_thread_info();
 	int ret;
+	enum bug_trap_type bug_type = BUG_TRAP_TYPE_NONE;
 
 	oops_enter();
 
@@ -273,7 +274,9 @@
 	console_verbose();
 	bust_spinlocks(1);
 	if (!user_mode(regs))
-		report_bug(regs->ARM_pc, regs);
+		bug_type = report_bug(regs->ARM_pc, regs);
+	if (bug_type != BUG_TRAP_TYPE_NONE)
+		str = "Oops - BUG";
 	ret = __die(str, err, thread, regs);
 
 	if (regs && kexec_should_crash(thread->task))
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index c793e1d..ee9b2de 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -30,6 +30,8 @@
 	select REGULATOR
 	select MULTI_IRQ_HANDLER
 	select MSM_PROC_COMM_REGULATOR
+	select CLEANCACHE
+	select QCACHE
 
 config ARCH_MSM7X30
 	bool "MSM7x30"
@@ -138,7 +140,6 @@
 	select MSM_AUDIO_QDSP6 if SND_SOC
 	select CPU_HAS_L2_PMU
 	select MSM_SPM_V2
-	select HAS_QDSS
 	select MSM_L2_SPM
 	select MSM_NATIVE_RESTART
 	select DONT_MAP_HOLE_AFTER_MEMBANK0
@@ -1814,44 +1815,31 @@
 		make the kernel reboot on a kernel panic - that must be
 		enabled via another mechanism.
 
-config HAS_QDSS
-	bool "QDSS Present"
+config MSM_JTAG
+        bool "JTAG debug and trace support"
 	help
-	 Select this if the chip has Qualcomm Debug Subsystem implemented.
-
-config MSM_DEBUG_ACROSS_PC
-	bool "Debug support across power collapse"
-	help
-	  Enables debug state to be saved and restored across power collapse.
-
-config MSM_JTAG_V7
-	depends on CPU_V7 && !HAS_QDSS
-	default y if DEBUG_KERNEL
-	bool "JTAG debug support"
-	select MSM_DEBUG_ACROSS_PC
-	help
-          Add additional support for JTAG kernel debugging.
-
-config MSM_TRACE_ACROSS_PC
-	bool "Trace support across power collapse"
-	help
-	  Enables trace state to be saved and restored across power collapse.
+          Add additional support for JTAG kernel debugging and tracing.
 
 config MSM_ETM
 	tristate "Enable MSM ETM and ETB"
-	depends on ARCH_MSM8X60 && !HAS_QDSS
-	select MSM_TRACE_ACROSS_PC
+	depends on ARCH_MSM8X60
+	select MSM_JTAG
 	help
-	  Enables embedded trace collection on Qualcomm v7 CPUs.
+	  Enables embedded trace collection on MSM8660
 
 config MSM_QDSS
 	bool "Qualcomm Debug Subsystem"
-	depends on HAS_QDSS
-	select MSM_DEBUG_ACROSS_PC
-	select MSM_TRACE_ACROSS_PC
+	select MSM_JTAG
 	help
 	  Enables support for Qualcomm Debug Subsystem.
 
+config MSM_QDSS_ETM_DEFAULT_ENABLE
+	bool "Turn on QDSS ETM Tracing by Default"
+	depends on MSM_QDSS
+	help
+	  Turns on QDSS ETM tracing by default. Otherwise, tracing is
+	  disabled by default but can be enabled by other means.
+
 config MSM_SLEEP_STATS
 	bool "Enable exporting of MSM sleep stats to userspace"
 	depends on CPU_IDLE
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 95f2535..bae4678 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -45,17 +45,11 @@
 obj-$(CONFIG_MSM_AVS_HW) += avs_hw.o
 obj-$(CONFIG_CPU_V6) += idle-v6.o
 obj-$(CONFIG_CPU_V7) += idle-v7.o
-obj-$(CONFIG_MSM_JTAG_V7) += jtag-v7.o
+obj-$(CONFIG_MSM_JTAG) += jtag.o
 
-msm-etm-objs := cp14.o etm.o
+msm-etm-objs := etm.o
 obj-$(CONFIG_MSM_ETM) += msm-etm.o
-
-ifdef CONFIG_MSM_QDSS
-	obj-y += qdss-debug.o
-	obj-y += qdss-etb.o qdss-tpiu.o
-	obj-y += qdss-funnel.o
-	obj-y += qdss-ptm.o
-endif
+obj-$(CONFIG_MSM_QDSS) += qdss.o qdss-etb.o qdss-tpiu.o qdss-funnel.o qdss-ptm.o
 
 quiet_cmd_mkrpcsym = MKCAP   $@
       cmd_mkrpcsym = $(PERL) $(srctree)/$(src)/mkrpcsym.pl $< $@
@@ -225,10 +219,10 @@
 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
-obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
-obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o
-obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o
+obj-$(CONFIG_MACH_MSM7X27A_RUMI3) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+obj-$(CONFIG_MACH_MSM7X27A_SURF) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+obj-$(CONFIG_MACH_MSM7X27A_FFA) += board-msm7x27a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.o
+obj-$(CONFIG_MACH_MSM7627A_QRD1) += board-qrd7627a.o board-msm7627a-storage.o board-msm7627a-bt.o board-msm7627a-camera.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 2fece29..23d03ef 100644
--- a/arch/arm/mach-msm/acpuclock-7201.c
+++ b/arch/arm/mach-msm/acpuclock-7201.c
@@ -125,35 +125,7 @@
  * largest frequency jump that's less than max_speed_delta_khz on each PLL.
  */
 
-/* 7x27 normal with GSM capable modem */
-static struct clkctl_acpu_speed pll0_245_pll1_960_pll2_1200_pll4_0[] = {
-	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
-	{ 0, 120000, ACPU_PLL_1, 1, 7,  60000, 1, 3,  61440 },
-	{ 1, 122880, ACPU_PLL_0, 4, 1,  61440, 1, 3,  61440 },
-	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  61440 },
-	{ 1, 245760, ACPU_PLL_0, 4, 0, 122880, 1, 4,  61440 },
-	{ 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 160000 },
-	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
-	{ 1, 480000, ACPU_PLL_1, 1, 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} }
-};
-
-/* 7x27 normal with CDMA-only modem */
-static struct clkctl_acpu_speed pll0_196_pll1_960_pll2_1200_pll4_0[] = {
-	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
-	{ 1,  98304, ACPU_PLL_0, 4, 1,  98304, 0, 3,  49152 },
-	{ 0, 120000, ACPU_PLL_1, 1, 7,  60000, 1, 3,  49152 },
-	{ 1, 196608, ACPU_PLL_0, 4, 0,  65536, 2, 4,  98304 },
-	{ 0, 200000, ACPU_PLL_2, 2, 5,  66667, 2, 4,  98304 },
-	{ 1, 320000, ACPU_PLL_1, 1, 2, 160000, 1, 5, 160000 },
-	{ 0, 400000, ACPU_PLL_2, 2, 2, 133333, 2, 5, 160000 },
-	{ 1, 480000, ACPU_PLL_1, 1, 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} }
-};
-
-/* 7x27 normal with GSM capable modem - PLL0 and PLL1 swapped */
+/* 7627 with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_0[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
 	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  61440 },
@@ -167,7 +139,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27 normal with CDMA-only modem - PLL0 and PLL1 swapped */
+/* 7627 with CDMA capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_0[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
 	{ 1,  98304, ACPU_PLL_1, 1, 1,  98304, 0, 3,  49152 },
@@ -181,7 +153,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27 normal with GSM capable modem - PLL0 and PLL1 swapped and pll2 @ 800 */
+/* 7627 with GSM capable modem - PLL2 @ 800 */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_800_pll4_0[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 30720 },
 	{ 0, 120000, ACPU_PLL_0, 4, 7,  60000, 1, 3,  61440 },
@@ -195,7 +167,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27 normal with CDMA-only modem - PLL0 and PLL1 swapped and pll2 @ 800 */
+/* 7627 with CDMA capable modem - PLL2 @ 800 */
 static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_800_pll4_0[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, 0, 24576 },
 	{ 1,  98304, ACPU_PLL_1, 1, 1,  98304, 0, 3,  49152 },
@@ -209,7 +181,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27a pll2 at 1200mhz with GSM capable modem */
+/* 7627a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_800[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
@@ -224,7 +196,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27a pll2 at 1200mhz with CDMA only modem */
+/* 7627a PLL2 @ 1200MHz with CDMA capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_800[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
 	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1,  49152 },
@@ -239,7 +211,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27aa pll4 at 1008mhz with GSM capable modem */
+/* 7627aa PLL4 @ 1008MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_pll4_1008[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1, 61440 },
@@ -254,7 +226,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27aa pll4 at 1008mhz with CDMA capable modem */
+/* 7627aa PLL4 @ 1008MHz with CDMA capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_196_pll2_1200_pll4_1008[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
 	{ 0, 65536, ACPU_PLL_1, 1, 3,  8192, 3, 1, 49152 },
@@ -269,7 +241,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x25a pll2 at 1200mhz with GSM capable modem */
+/* 7625a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_245_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 3,  7680, 3, 1,  61440 },
@@ -283,7 +255,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27a pll2 at 1200mhz with GSM capable modem */
+/* 7627a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_800[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
@@ -298,7 +270,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27a pll2 at 1200mhz with CDMA only modem */
+/* 7627a PLL2 @ 1200MHz with CDMA capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_800[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
 	{ 0, 65536, ACPU_PLL_1, 1, 8,  8192, 3, 1,  49152 },
@@ -313,7 +285,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27aa pll4 at 1008mhz with GSM capable modem */
+/* 7627aa PLL4 @ 1008MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_pll4_1008[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1, 61440 },
@@ -328,7 +300,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x27aa pll4 at 1008mhz with CDMA capable modem */
+/* 7x27aa PLL4 @ 1008MHz with CDMA capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_589_pll2_1200_pll4_1008[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 24576 },
 	{ 0, 65536, ACPU_PLL_1, 1, 8,  8192, 3, 1, 49152 },
@@ -343,7 +315,7 @@
 	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0} }
 };
 
-/* 7x25a pll2 at 1200mhz with GSM capable modem */
+/* 7x25a PLL2 @ 1200MHz with GSM capable modem */
 static struct clkctl_acpu_speed pll0_960_pll1_737_pll2_1200_25a[] = {
 	{ 0, 19200, ACPU_PLL_TCXO, 0, 0, 2400, 3, 0, 30720 },
 	{ 0, 61440, ACPU_PLL_1, 1, 11,  7680, 3, 1,  61440 },
@@ -381,8 +353,6 @@
 };
 
 static struct pll_freq_tbl_map acpu_freq_tbl_list[] = {
-	PLL_CONFIG(196, 960, 1200, 0),
-	PLL_CONFIG(245, 960, 1200, 0),
 	PLL_CONFIG(960, 196, 1200, 0),
 	PLL_CONFIG(960, 245, 1200, 0),
 	PLL_CONFIG(960, 196, 800, 0),
@@ -869,12 +839,6 @@
 		pr_crit("Unknown PLL configuration!\n");
 		BUG();
 	}
-
-	/* The default 7x27 ACPU clock plan supports running the AXI bus at
-	 * 200 MHz. So we don't classify it as Turbo mode.
-	 */
-	if (cpu_is_msm7x27())
-		return;
 }
 
 /*
diff --git a/arch/arm/mach-msm/acpuclock-8960.c b/arch/arm/mach-msm/acpuclock-8960.c
index c15c34e..87c5047 100644
--- a/arch/arm/mach-msm/acpuclock-8960.c
+++ b/arch/arm/mach-msm/acpuclock-8960.c
@@ -458,86 +458,89 @@
 	[14] = { { 1080000, HFPLL, 1, 0, 0x28 }, 1150000, 1150000, 6 },
 	[15] = { { 1134000, HFPLL, 1, 0, 0x2A }, 1150000, 1150000, 6 },
 	[16] = { { 1188000, HFPLL, 1, 0, 0x2C }, 1150000, 1150000, 6 },
+	[17] = { { 1242000, HFPLL, 1, 0, 0x2E }, 1150000, 1150000, 6 },
+	[18] = { { 1296000, HFPLL, 1, 0, 0x30 }, 1150000, 1150000, 6 },
+	[19] = { { 1350000, HFPLL, 1, 0, 0x32 }, 1150000, 1150000, 6 },
 };
 
 static struct acpu_level acpu_freq_tbl_8960_kraitv2_slow[] = {
-	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   975000 },
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   975000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),  1000000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),  1000000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),  1025000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),  1025000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1050000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1050000 },
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   950000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   950000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   975000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   975000 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),  1000000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),  1000000 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1025000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1025000 },
 	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11), 1075000 },
 	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1075000 },
 	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1100000 },
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1100000 },
 	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1125000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1125000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1225000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1225000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1250000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1250000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1275000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1275000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1287500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1287500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1300000 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1175000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1175000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1200000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1200000 },
+	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1225000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1225000 },
+	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1237500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1237500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1250000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_8960_kraitv2_nom[] = {
-	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   925000 },
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   925000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   950000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   950000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   975000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   975000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),  1000000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),  1000000 },
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   900000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   900000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   925000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   925000 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   950000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   950000 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   975000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),   975000 },
 	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11), 1025000 },
 	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11), 1025000 },
 	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1050000 },
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1050000 },
 	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1075000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1075000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1175000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1175000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1200000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1200000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1225000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1225000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1237500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1237500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1250000 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1125000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1125000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1150000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1150000 },
+	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1175000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1175000 },
+	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1187500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1187500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1200000 },
 	{ 0, { 0 } }
 };
 
 static struct acpu_level acpu_freq_tbl_8960_kraitv2_fast[] = {
-	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   875000 },
-	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   875000 },
-	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   900000 },
-	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   900000 },
-	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   925000 },
-	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   925000 },
-	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   950000 },
-	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),   950000 },
+	{ 0, { STBY_KHZ, QSB,   0, 0, 0x00 }, L2(0),   850000 },
+	{ 1, {   384000, PLL_8, 0, 2, 0x00 }, L2(1),   850000 },
+	{ 1, {   432000, HFPLL, 2, 0, 0x20 }, L2(6),   875000 },
+	{ 1, {   486000, HFPLL, 2, 0, 0x24 }, L2(6),   875000 },
+	{ 1, {   540000, HFPLL, 2, 0, 0x28 }, L2(6),   900000 },
+	{ 1, {   594000, HFPLL, 1, 0, 0x16 }, L2(6),   900000 },
+	{ 1, {   648000, HFPLL, 1, 0, 0x18 }, L2(6),   925000 },
+	{ 1, {   702000, HFPLL, 1, 0, 0x1A }, L2(6),   925000 },
 	{ 1, {   756000, HFPLL, 1, 0, 0x1C }, L2(11),  975000 },
 	{ 1, {   810000, HFPLL, 1, 0, 0x1E }, L2(11),  975000 },
 	{ 1, {   864000, HFPLL, 1, 0, 0x20 }, L2(11), 1000000 },
 	{ 1, {   918000, HFPLL, 1, 0, 0x22 }, L2(11), 1000000 },
 	{ 1, {   972000, HFPLL, 1, 0, 0x24 }, L2(16), 1025000 },
 	{ 1, {  1026000, HFPLL, 1, 0, 0x26 }, L2(16), 1025000 },
-	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1125000 },
-	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1125000 },
-	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1150000 },
-	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(16), 1150000 },
-	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(16), 1175000 },
-	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(16), 1175000 },
-	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(16), 1187500 },
-	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(16), 1187500 },
-	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(16), 1200000 },
+	{ 1, {  1080000, HFPLL, 1, 0, 0x28 }, L2(16), 1075000 },
+	{ 1, {  1134000, HFPLL, 1, 0, 0x2A }, L2(16), 1075000 },
+	{ 1, {  1188000, HFPLL, 1, 0, 0x2C }, L2(16), 1100000 },
+	{ 1, {  1242000, HFPLL, 1, 0, 0x2E }, L2(19), 1100000 },
+	{ 1, {  1296000, HFPLL, 1, 0, 0x30 }, L2(19), 1125000 },
+	{ 1, {  1350000, HFPLL, 1, 0, 0x32 }, L2(19), 1125000 },
+	{ 1, {  1404000, HFPLL, 1, 0, 0x34 }, L2(19), 1137500 },
+	{ 1, {  1458000, HFPLL, 1, 0, 0x36 }, L2(19), 1137500 },
+	{ 1, {  1512000, HFPLL, 1, 0, 0x38 }, L2(19), 1150000 },
 	{ 0, { 0 } }
 };
 
@@ -1328,6 +1331,18 @@
 	.notifier_call = acpuclock_cpu_callback,
 };
 
+static const int krait_needs_vmin(void)
+{
+	switch (read_cpuid_id()) {
+	case 0x511F04D0:
+	case 0x511F04D1:
+	case 0x510F06F0:
+		return 1;
+	default:
+		return 0;
+	};
+}
+
 static void kraitv2_apply_vmin(struct acpu_level *tbl)
 {
 	for (; tbl->speed.khz != 0; tbl++)
@@ -1380,7 +1395,6 @@
 			l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv1);
 		} else {
 			acpu_freq_tbl = v2;
-			kraitv2_apply_vmin(acpu_freq_tbl);
 			l2_freq_tbl = l2_freq_tbl_8960_kraitv2;
 			l2_freq_tbl_size = ARRAY_SIZE(l2_freq_tbl_8960_kraitv2);
 		}
@@ -1402,6 +1416,8 @@
 	} else {
 		BUG();
 	}
+	if (krait_needs_vmin())
+		kraitv2_apply_vmin(acpu_freq_tbl);
 
 	/* Find the max supported scaling frequency. */
 	for (l = acpu_freq_tbl; l->speed.khz != 0; l++)
diff --git a/arch/arm/mach-msm/acpuclock-9615.c b/arch/arm/mach-msm/acpuclock-9615.c
index 1f112f6..35eb52b 100644
--- a/arch/arm/mach-msm/acpuclock-9615.c
+++ b/arch/arm/mach-msm/acpuclock-9615.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -98,6 +98,7 @@
 	[2] =  BW_MBPS(552), /* At least  69 MHz on bus. */
 	[3] =  BW_MBPS(736), /* At least  92 MHz on bus. */
 	[4] = BW_MBPS(1064), /* At least 133 MHz on bus. */
+	[5] = BW_MBPS(1536), /* At least 192 MHz on bus. */
 };
 
 static struct msm_bus_scale_pdata bus_client_pdata = {
@@ -114,6 +115,7 @@
 	{ 1, 138000, SRC_PLL0, 6, 1,  950000, 1050000, 2 },
 	{ 1, 276000, SRC_PLL0, 6, 0, 1050000, 1050000, 2 },
 	{ 1, 384000, SRC_PLL8, 3, 0, 1150000, 1150000, 4 },
+	/* The row below may be changed at runtime depending on hw rev. */
 	{ 1, 440000, SRC_PLL9, 2, 0, 1150000, 1150000, 4 },
 	{ 0 }
 };
@@ -324,6 +326,15 @@
 		}
 	}
 
+	/* Determine the rate of PLL9 and fixup tables accordingly */
+	if (clk_get_rate(clocks[SRC_PLL9].clk) == 550000000) {
+		for (i = 0; i < ARRAY_SIZE(acpu_freq_tbl); i++)
+			if (acpu_freq_tbl[i].src == SRC_PLL9) {
+				acpu_freq_tbl[i].khz = 550000;
+				acpu_freq_tbl[i].bw_level = 5;
+			}
+	}
+
 	/* Improve boot time by ramping up CPU immediately. */
 	for (i = 0; acpu_freq_tbl[i].khz != 0; i++)
 		max_cpu_khz = acpu_freq_tbl[i].khz;
diff --git a/arch/arm/mach-msm/bam_dmux.c b/arch/arm/mach-msm/bam_dmux.c
index e6d9447..bfe4f81 100644
--- a/arch/arm/mach-msm/bam_dmux.c
+++ b/arch/arm/mach-msm/bam_dmux.c
@@ -26,6 +26,7 @@
 #include <linux/debugfs.h>
 #include <linux/clk.h>
 #include <linux/wakelock.h>
+#include <linux/kfifo.h>
 
 #include <mach/sps.h>
 #include <mach/bam_dmux.h>
@@ -39,9 +40,11 @@
 
 #define BAM_MUX_HDR_MAGIC_NO    0x33fc
 
-#define BAM_MUX_HDR_CMD_DATA    0
-#define BAM_MUX_HDR_CMD_OPEN    1
-#define BAM_MUX_HDR_CMD_CLOSE   2
+#define BAM_MUX_HDR_CMD_DATA		0
+#define BAM_MUX_HDR_CMD_OPEN		1
+#define BAM_MUX_HDR_CMD_CLOSE		2
+#define BAM_MUX_HDR_CMD_STATUS		3 /* unused */
+#define BAM_MUX_HDR_CMD_OPEN_NO_A2_PC	4
 
 #define POLLING_MIN_SLEEP	950	/* 0.95 ms */
 #define POLLING_MAX_SLEEP	1050	/* 1.05 ms */
@@ -119,6 +122,8 @@
 	uint32_t len;
 	struct work_struct work;
 	struct list_head list_node;
+	unsigned ts_sec;
+	unsigned long ts_nsec;
 };
 
 struct rx_pkt_info {
@@ -185,6 +190,8 @@
 static void vote_dfab(void);
 static void unvote_dfab(void);
 static void kickoff_ul_wakeup_func(struct work_struct *work);
+static void grab_wakelock(void);
+static void release_wakelock(void);
 
 static int bam_is_connected;
 static DEFINE_MUTEX(wakeup_lock);
@@ -198,6 +205,14 @@
 static int bam_connection_is_active;
 static int wait_for_ack;
 static struct wake_lock bam_wakelock;
+static int a2_pc_disabled;
+static DEFINE_MUTEX(dfab_status_lock);
+static int dfab_is_on;
+static int wait_for_dfab;
+static struct completion dfab_unvote_completion;
+static DEFINE_SPINLOCK(wakelock_reference_lock);
+static int wakelock_reference_count;
+static struct delayed_work msm9615_bam_init_work;
 /* End A2 power collaspe */
 
 /* subsystem restart */
@@ -223,6 +238,119 @@
 #define bam_ch_is_in_reset(x)			\
 	(bam_ch[(x)].status & BAM_CH_IN_RESET)
 
+#define LOG_MESSAGE_MAX_SIZE 80
+struct kfifo bam_dmux_state_log;
+static uint32_t bam_dmux_state_logging_disabled;
+static DEFINE_SPINLOCK(bam_dmux_logging_spinlock);
+static int bam_dmux_uplink_vote;
+static int bam_dmux_power_state;
+
+
+#define DMUX_LOG_KERR(fmt...) \
+do { \
+	bam_dmux_log(fmt); \
+	pr_err(fmt); \
+} while (0)
+
+/**
+ * Log a state change along with a small message.
+ *
+ * Complete size of messsage is limited to @todo.
+ */
+static void bam_dmux_log(const char *fmt, ...)
+{
+	char buff[LOG_MESSAGE_MAX_SIZE];
+	unsigned long flags;
+	va_list arg_list;
+	unsigned long long t_now;
+	unsigned long nanosec_rem;
+	int len = 0;
+
+	if (bam_dmux_state_logging_disabled)
+		return;
+
+	t_now = sched_clock();
+	nanosec_rem = do_div(t_now, 1000000000U);
+
+	/*
+	 * States
+	 * D: 1 = Power collapse disabled
+	 * R: 1 = in global reset
+	 * P: 1 = BAM is powered up
+	 * A: 1 = BAM initialized and ready for data
+	 *
+	 * V: 1 = Uplink vote for power
+	 * U: 1 = Uplink active
+	 * W: 1 = Uplink Wait-for-ack
+	 * A: 1 = Uplink ACK received
+	 */
+	len += scnprintf(buff, sizeof(buff),
+		"<DMUX> %u.%09lu %c%c%c%c %c%c%c%c ",
+		(unsigned)t_now, nanosec_rem,
+		a2_pc_disabled ? 'D' : 'd',
+		in_global_reset ? 'R' : 'r',
+		bam_dmux_power_state ? 'P' : 'p',
+		bam_connection_is_active ? 'A' : 'a',
+		bam_dmux_uplink_vote ? 'V' : 'v',
+		bam_is_connected ?  'U' : 'u',
+		wait_for_ack ? 'W' : 'w',
+		ul_wakeup_ack_completion.done ? 'A' : 'a'
+		);
+
+	va_start(arg_list, fmt);
+	len += vscnprintf(buff + len, sizeof(buff) - len, fmt, arg_list);
+	va_end(arg_list);
+	memset(buff + len, 0x0, sizeof(buff) - len);
+
+	spin_lock_irqsave(&bam_dmux_logging_spinlock, flags);
+	if (kfifo_avail(&bam_dmux_state_log) < LOG_MESSAGE_MAX_SIZE) {
+		char junk[LOG_MESSAGE_MAX_SIZE];
+		int ret;
+
+		ret = kfifo_out(&bam_dmux_state_log, junk, sizeof(junk));
+		if (ret != LOG_MESSAGE_MAX_SIZE) {
+			pr_err("%s: unable to empty log %d\n", __func__, ret);
+			spin_unlock_irqrestore(&bam_dmux_logging_spinlock,
+					flags);
+			return;
+		}
+	}
+	kfifo_in(&bam_dmux_state_log, buff, sizeof(buff));
+	spin_unlock_irqrestore(&bam_dmux_logging_spinlock, flags);
+}
+
+static inline void set_tx_timestamp(struct tx_pkt_info *pkt)
+{
+	unsigned long long t_now;
+
+	t_now = sched_clock();
+	pkt->ts_nsec = do_div(t_now, 1000000000U);
+	pkt->ts_sec = (unsigned)t_now;
+}
+
+static inline void verify_tx_queue_is_empty(const char *func)
+{
+	unsigned long flags;
+	struct tx_pkt_info *info;
+	int reported = 0;
+
+	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
+	list_for_each_entry(info, &bam_tx_pool, list_node) {
+		if (!reported) {
+			bam_dmux_log("%s: tx pool not empty\n", func);
+			if (!in_global_reset)
+				pr_err("%s: tx pool not empty\n", func);
+			reported = 1;
+		}
+		bam_dmux_log("%s: node=%p ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
+		if (!in_global_reset)
+			pr_err("%s: node=%p ts=%u.%09lu\n", __func__,
+			&info->list_node, info->ts_sec, info->ts_nsec);
+	}
+	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
+}
+
 static void queue_rx(void)
 {
 	void *ptr;
@@ -286,13 +414,28 @@
 	queue_rx();
 }
 
+static inline void handle_bam_mux_cmd_open(struct bam_mux_hdr *rx_hdr)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
+	bam_ch[rx_hdr->ch_id].status |= BAM_CH_REMOTE_OPEN;
+	bam_ch[rx_hdr->ch_id].num_tx_pkts = 0;
+	spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
+	queue_rx();
+	ret = platform_device_add(bam_ch[rx_hdr->ch_id].pdev);
+	if (ret)
+		pr_err("%s: platform_device_add() error: %d\n",
+				__func__, ret);
+}
+
 static void handle_bam_mux_cmd(struct work_struct *work)
 {
 	unsigned long flags;
 	struct bam_mux_hdr *rx_hdr;
 	struct rx_pkt_info *info;
 	struct sk_buff *rx_skb;
-	int ret;
 
 	info = container_of(work, struct rx_pkt_info, work);
 	rx_skb = info->skb;
@@ -306,7 +449,8 @@
 			rx_hdr->magic_num, rx_hdr->reserved, rx_hdr->cmd,
 			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
 	if (rx_hdr->magic_num != BAM_MUX_HDR_MAGIC_NO) {
-		pr_err("%s: dropping invalid hdr. magic %x reserved %d cmd %d"
+		DMUX_LOG_KERR("%s: dropping invalid hdr. magic %x"
+			" reserved %d cmd %d"
 			" pad %d ch %d len %d\n", __func__,
 			rx_hdr->magic_num, rx_hdr->reserved, rx_hdr->cmd,
 			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
@@ -316,7 +460,8 @@
 	}
 
 	if (rx_hdr->ch_id >= BAM_DMUX_NUM_CHANNELS) {
-		pr_err("%s: dropping invalid LCID %d reserved %d cmd %d"
+		DMUX_LOG_KERR("%s: dropping invalid LCID %d"
+			" reserved %d cmd %d"
 			" pad %d ch %d len %d\n", __func__,
 			rx_hdr->ch_id, rx_hdr->reserved, rx_hdr->cmd,
 			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
@@ -331,19 +476,28 @@
 		bam_mux_process_data(rx_skb);
 		break;
 	case BAM_MUX_HDR_CMD_OPEN:
-		spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
-		bam_ch[rx_hdr->ch_id].status |= BAM_CH_REMOTE_OPEN;
-		bam_ch[rx_hdr->ch_id].num_tx_pkts = 0;
-		spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
-		queue_rx();
-		ret = platform_device_add(bam_ch[rx_hdr->ch_id].pdev);
-		if (ret)
-			pr_err("%s: platform_device_add() error: %d\n",
-					__func__, ret);
+		bam_dmux_log("%s: opening cid %d PC enabled\n", __func__,
+				rx_hdr->ch_id);
+		handle_bam_mux_cmd_open(rx_hdr);
+		dev_kfree_skb_any(rx_skb);
+		break;
+	case BAM_MUX_HDR_CMD_OPEN_NO_A2_PC:
+		bam_dmux_log("%s: opening cid %d PC disabled\n", __func__,
+				rx_hdr->ch_id);
+
+		if (!a2_pc_disabled) {
+			a2_pc_disabled = 1;
+			schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(UL_TIMEOUT_DELAY));
+		}
+
+		handle_bam_mux_cmd_open(rx_hdr);
 		dev_kfree_skb_any(rx_skb);
 		break;
 	case BAM_MUX_HDR_CMD_CLOSE:
 		/* probably should drop pending write */
+		bam_dmux_log("%s: closing cid %d\n", __func__,
+				rx_hdr->ch_id);
 		spin_lock_irqsave(&bam_ch[rx_hdr->ch_id].lock, flags);
 		bam_ch[rx_hdr->ch_id].status &= ~BAM_CH_REMOTE_OPEN;
 		spin_unlock_irqrestore(&bam_ch[rx_hdr->ch_id].lock, flags);
@@ -356,10 +510,11 @@
 		dev_kfree_skb_any(rx_skb);
 		break;
 	default:
-		pr_err("%s: dropping invalid hdr. magic %x reserved %d cmd %d"
-			" pad %d ch %d len %d\n", __func__,
-			rx_hdr->magic_num, rx_hdr->reserved, rx_hdr->cmd,
-			rx_hdr->pad_len, rx_hdr->ch_id, rx_hdr->pkt_len);
+		DMUX_LOG_KERR("%s: dropping invalid hdr. magic %x"
+			   " reserved %d cmd %d pad %d ch %d len %d\n",
+			__func__, rx_hdr->magic_num, rx_hdr->reserved,
+			rx_hdr->cmd, rx_hdr->pad_len, rx_hdr->ch_id,
+			rx_hdr->pkt_len);
 		dev_kfree_skb_any(rx_skb);
 		queue_rx();
 		return;
@@ -392,6 +547,7 @@
 	pkt->len = len;
 	pkt->dma_address = dma_address;
 	pkt->is_cmd = 1;
+	set_tx_timestamp(pkt);
 	INIT_WORK(&pkt->work, bam_mux_write_done);
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	list_add_tail(&pkt->list_node, &bam_tx_pool);
@@ -429,12 +585,20 @@
 	info_expected = list_first_entry(&bam_tx_pool,
 			struct tx_pkt_info, list_node);
 	if (unlikely(info != info_expected)) {
-		struct list_head *node;
+		struct tx_pkt_info *errant_pkt;
 
-		pr_err("%s: bam_tx_pool mismatch .next=%p, list_node=%p\n",
-				__func__, bam_tx_pool.next, &info->list_node);
-		list_for_each(node, &bam_tx_pool)
-			pr_err("%s: node=%p\n", __func__, node);
+		DMUX_LOG_KERR("%s: bam_tx_pool mismatch .next=%p,"
+				" list_node=%p, ts=%u.%09lu\n",
+				__func__, bam_tx_pool.next, &info->list_node,
+				info->ts_sec, info->ts_nsec
+				);
+
+		list_for_each_entry(errant_pkt, &bam_tx_pool, list_node) {
+			DMUX_LOG_KERR("%s: node=%p ts=%u.%09lu\n", __func__,
+			&errant_pkt->list_node, errant_pkt->ts_sec,
+			errant_pkt->ts_nsec);
+
+		}
 		spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
 		BUG();
 	}
@@ -550,6 +714,7 @@
 	pkt->skb = skb;
 	pkt->dma_address = dma_address;
 	pkt->is_cmd = 0;
+	set_tx_timestamp(pkt);
 	INIT_WORK(&pkt->work, bam_mux_write_done);
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	list_add_tail(&pkt->list_node, &bam_tx_pool);
@@ -779,6 +944,7 @@
 		goto fail;
 	}
 	polling_mode = 0;
+	release_wakelock();
 
 	/* handle any rx packets before interrupt was enabled */
 	while (bam_connection_is_active && !polling_mode) {
@@ -908,6 +1074,7 @@
 					" not disabled\n", __func__, ret);
 				break;
 			}
+			grab_wakelock();
 			polling_mode = 1;
 			queue_work(bam_mux_rx_workqueue, &rx_timer_work);
 		}
@@ -966,6 +1133,58 @@
 	return i;
 }
 
+static int debug_log(char *buff, int max, loff_t *ppos)
+{
+	unsigned long flags;
+	int i = 0;
+
+	if (bam_dmux_state_logging_disabled) {
+		i += scnprintf(buff - i, max - i, "Logging disabled\n");
+		return i;
+	}
+
+	if (*ppos == 0) {
+		i += scnprintf(buff - i, max - i,
+			"<DMUX> timestamp FLAGS [Message]\n"
+			"FLAGS:\n"
+			"\tD: 1 = Power collapse disabled\n"
+			"\tR: 1 = in global reset\n"
+			"\tP: 1 = BAM is powered up\n"
+			"\tA: 1 = BAM initialized and ready for data\n"
+			"\n"
+			"\tV: 1 = Uplink vote for power\n"
+			"\tU: 1 = Uplink active\n"
+			"\tW: 1 = Uplink Wait-for-ack\n"
+			"\tA: 1 = Uplink ACK received\n"
+				);
+		buff += i;
+	}
+
+	spin_lock_irqsave(&bam_dmux_logging_spinlock, flags);
+	while (kfifo_len(&bam_dmux_state_log)
+			&& (i + LOG_MESSAGE_MAX_SIZE) < max) {
+		int k_len;
+		k_len = kfifo_out(&bam_dmux_state_log,
+				buff, LOG_MESSAGE_MAX_SIZE);
+		if (k_len != LOG_MESSAGE_MAX_SIZE) {
+			pr_err("%s: retrieve failure %d\n", __func__, k_len);
+			break;
+		}
+
+		/* keep non-null portion of string and add line break */
+		k_len = strnlen(buff, LOG_MESSAGE_MAX_SIZE);
+		buff += k_len;
+		i += k_len;
+		if (k_len && *(buff - 1) != '\n') {
+			*buff++ = '\n';
+			++i;
+		}
+	}
+	spin_unlock_irqrestore(&bam_dmux_logging_spinlock, flags);
+
+	return i;
+}
+
 #define DEBUG_BUFMAX 4096
 static char debug_buffer[DEBUG_BUFMAX];
 
@@ -977,6 +1196,30 @@
 	return simple_read_from_buffer(buf, count, ppos, debug_buffer, bsize);
 }
 
+static ssize_t debug_read_multiple(struct file *file, char __user *buff,
+				size_t count, loff_t *ppos)
+{
+	int (*util_func)(char *buf, int max, loff_t *) = file->private_data;
+	char *buffer;
+	int bsize;
+
+	buffer = kmalloc(count, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	bsize = util_func(buffer, count, ppos);
+
+	if (bsize >= 0) {
+		if (copy_to_user(buff, buffer, bsize)) {
+			kfree(buffer);
+			return -EFAULT;
+		}
+		*ppos += bsize;
+	}
+	kfree(buffer);
+	return bsize;
+}
+
 static int debug_open(struct inode *inode, struct file *file)
 {
 	file->private_data = inode->i_private;
@@ -989,6 +1232,11 @@
 	.open = debug_open,
 };
 
+static const struct file_operations debug_ops_multiple = {
+	.read = debug_read_multiple,
+	.open = debug_open,
+};
+
 static void debug_create(const char *name, mode_t mode,
 				struct dentry *dent,
 				int (*fill)(char *buf, int max))
@@ -1003,8 +1251,11 @@
 	int i;
 
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
-		if (bam_ch_is_open(i))
+		if (bam_ch_is_open(i)) {
 			bam_ch[i].notify(bam_ch[i].priv, event, data);
+			bam_dmux_log("%s: cid=%d, event=%d, data=%lu\n",
+					__func__, i, event, data);
+		}
 	}
 }
 
@@ -1026,6 +1277,51 @@
 	queue_work(bam_mux_tx_workqueue, &kickoff_ul_wakeup);
 }
 
+static void power_vote(int vote)
+{
+	bam_dmux_log("%s: curr=%d, vote=%d\n", __func__,
+			bam_dmux_uplink_vote, vote);
+
+	if (bam_dmux_uplink_vote == vote)
+		bam_dmux_log("%s: warning - duplicate power vote\n", __func__);
+
+	bam_dmux_uplink_vote = vote;
+	if (vote)
+		smsm_change_state(SMSM_APPS_STATE, 0, SMSM_A2_POWER_CONTROL);
+	else
+		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
+}
+
+/*
+ * @note:  Must be called with ul_wakeup_lock locked.
+ */
+static inline void ul_powerdown(void)
+{
+	bam_dmux_log("%s: powerdown\n", __func__);
+	verify_tx_queue_is_empty(__func__);
+
+	if (a2_pc_disabled) {
+		wait_for_dfab = 1;
+		INIT_COMPLETION(dfab_unvote_completion);
+		release_wakelock();
+	} else {
+		wait_for_ack = 1;
+		INIT_COMPLETION(ul_wakeup_ack_completion);
+		power_vote(0);
+	}
+	bam_is_connected = 0;
+	notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
+}
+
+static inline void ul_powerdown_finish(void)
+{
+	if (a2_pc_disabled && wait_for_dfab) {
+		unvote_dfab();
+		complete_all(&dfab_unvote_completion);
+		wait_for_dfab = 0;
+	}
+}
+
 static void ul_timeout(struct work_struct *work)
 {
 	unsigned long flags;
@@ -1039,51 +1335,78 @@
 				msecs_to_jiffies(UL_TIMEOUT_DELAY));
 		return;
 	}
-	if (ul_packet_written) {
-		pr_info("%s: packet written\n", __func__);
-		ul_packet_written = 0;
-		schedule_delayed_work(&ul_timeout_work,
-				msecs_to_jiffies(UL_TIMEOUT_DELAY));
-	} else {
-		pr_info("%s: powerdown\n", __func__);
-		wait_for_ack = 1;
-		INIT_COMPLETION(ul_wakeup_ack_completion);
-		smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
-		bam_is_connected = 0;
-		notify_all(BAM_DMUX_UL_DISCONNECTED, (unsigned long)(NULL));
+	if (bam_is_connected) {
+		if (ul_packet_written) {
+			bam_dmux_log("%s: packet written\n", __func__);
+			ul_packet_written = 0;
+			schedule_delayed_work(&ul_timeout_work,
+					msecs_to_jiffies(UL_TIMEOUT_DELAY));
+		} else {
+			ul_powerdown();
+		}
 	}
 	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
 }
 static void ul_wakeup(void)
 {
 	int ret;
+	static int called_before;
 
 	mutex_lock(&wakeup_lock);
 	if (bam_is_connected) { /* bam got connected before lock grabbed */
+		bam_dmux_log("%s Already awake\n", __func__);
 		mutex_unlock(&wakeup_lock);
 		return;
 	}
-	pr_info("%s\n", __func__);
+
+	if (a2_pc_disabled) {
+		/*
+		 * don't grab the wakelock the first time because it is
+		 * already grabbed when a2 powers on
+		 */
+		if (likely(called_before))
+			grab_wakelock();
+		else
+			called_before = 1;
+		if (wait_for_dfab) {
+			ret = wait_for_completion_interruptible_timeout(
+					&dfab_unvote_completion, HZ);
+			BUG_ON(ret == 0);
+		}
+		vote_dfab();
+		schedule_delayed_work(&ul_timeout_work,
+				msecs_to_jiffies(UL_TIMEOUT_DELAY));
+		bam_is_connected = 1;
+		mutex_unlock(&wakeup_lock);
+		return;
+	}
+
 	/*
 	 * must wait for the previous power down request to have been acked
 	 * chances are it already came in and this will just fall through
 	 * instead of waiting
 	 */
 	if (wait_for_ack) {
+		bam_dmux_log("%s waiting for previous ack\n", __func__);
 		ret = wait_for_completion_interruptible_timeout(
 					&ul_wakeup_ack_completion, HZ);
 		BUG_ON(ret == 0);
+		wait_for_ack = 0;
 	}
 	INIT_COMPLETION(ul_wakeup_ack_completion);
-	smsm_change_state(SMSM_APPS_STATE, 0, SMSM_A2_POWER_CONTROL);
+	power_vote(1);
+	bam_dmux_log("%s waiting for wakeup ack\n", __func__);
 	ret = wait_for_completion_interruptible_timeout(
 						&ul_wakeup_ack_completion, HZ);
 	BUG_ON(ret == 0);
+	bam_dmux_log("%s waiting completion\n", __func__);
 	ret = wait_for_completion_interruptible_timeout(
 						&bam_connection_completion, HZ);
 	BUG_ON(ret == 0);
 
 	bam_is_connected = 1;
+	bam_dmux_log("%s complete\n", __func__);
 	schedule_delayed_work(&ul_timeout_work,
 				msecs_to_jiffies(UL_TIMEOUT_DELAY));
 	mutex_unlock(&wakeup_lock);
@@ -1127,8 +1450,20 @@
 {
 	struct list_head *node;
 	struct rx_pkt_info *info;
+	unsigned long flags;
 
 	bam_connection_is_active = 0;
+
+	/* handle disconnect during active UL */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		bam_dmux_log("%s: UL active - forcing powerdown\n", __func__);
+		ul_powerdown();
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+
+	/* tear down BAM connection */
 	INIT_COMPLETION(bam_connection_completion);
 	sps_disconnect(bam_tx_pipe);
 	sps_disconnect(bam_rx_pipe);
@@ -1147,20 +1482,74 @@
 		kfree(info);
 	}
 	mutex_unlock(&bam_rx_pool_mutexlock);
+
+	verify_tx_queue_is_empty(__func__);
 }
 
 static void vote_dfab(void)
 {
 	int rc;
 
+	bam_dmux_log("%s\n", __func__);
+	mutex_lock(&dfab_status_lock);
+	if (dfab_is_on) {
+		bam_dmux_log("%s: dfab is already on\n", __func__);
+		mutex_unlock(&dfab_status_lock);
+		return;
+	}
 	rc = clk_enable(dfab_clk);
 	if (rc)
-		pr_err("bam_dmux vote for dfab failed rc = %d\n", rc);
+		DMUX_LOG_KERR("bam_dmux vote for dfab failed rc = %d\n", rc);
+	dfab_is_on = 1;
+	mutex_unlock(&dfab_status_lock);
 }
 
 static void unvote_dfab(void)
 {
+	bam_dmux_log("%s\n", __func__);
+	mutex_lock(&dfab_status_lock);
+	if (!dfab_is_on) {
+		DMUX_LOG_KERR("%s: dfab is already off\n", __func__);
+		dump_stack();
+		mutex_unlock(&dfab_status_lock);
+		return;
+	}
 	clk_disable(dfab_clk);
+	dfab_is_on = 0;
+	mutex_unlock(&dfab_status_lock);
+}
+
+/* reference counting wrapper around wakelock */
+static void grab_wakelock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wakelock_reference_lock, flags);
+	bam_dmux_log("%s: ref count = %d\n", __func__,
+						wakelock_reference_count);
+	if (wakelock_reference_count == 0)
+		wake_lock(&bam_wakelock);
+	++wakelock_reference_count;
+	spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+}
+
+static void release_wakelock(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&wakelock_reference_lock, flags);
+	if (wakelock_reference_count == 0) {
+		DMUX_LOG_KERR("%s: bam_dmux wakelock not locked\n", __func__);
+		dump_stack();
+		spin_unlock_irqrestore(&wakelock_reference_lock, flags);
+		return;
+	}
+	bam_dmux_log("%s: ref count = %d\n", __func__,
+						wakelock_reference_count);
+	--wakelock_reference_count;
+	if (wakelock_reference_count == 0)
+		wake_unlock(&bam_wakelock);
+	spin_unlock_irqrestore(&wakelock_reference_lock, flags);
 }
 
 static int restart_notifier_cb(struct notifier_block *this,
@@ -1176,7 +1565,20 @@
 	if (code != SUBSYS_AFTER_SHUTDOWN)
 		return NOTIFY_DONE;
 
+	bam_dmux_log("%s: begin\n", __func__);
 	in_global_reset = 1;
+
+	/* Handle uplink Powerdown */
+	write_lock_irqsave(&ul_wakeup_lock, flags);
+	if (bam_is_connected) {
+		ul_powerdown();
+		wait_for_ack = 0;
+	}
+	write_unlock_irqrestore(&ul_wakeup_lock, flags);
+	ul_powerdown_finish();
+	a2_pc_disabled = 0;
+
+	/* Cleanup Channel States */
 	for (i = 0; i < BAM_DMUX_NUM_CHANNELS; ++i) {
 		temp_remote_status = bam_ch_is_remote_open(i);
 		bam_ch[i].status &= ~BAM_CH_REMOTE_OPEN;
@@ -1189,7 +1591,8 @@
 						bam_ch[i].name, 2);
 		}
 	}
-	/*cleanup UL*/
+
+	/* Cleanup pending UL data */
 	spin_lock_irqsave(&bam_tx_pool_spinlock, flags);
 	while (!list_empty(&bam_tx_pool)) {
 		node = bam_tx_pool.next;
@@ -1210,8 +1613,8 @@
 		kfree(info);
 	}
 	spin_unlock_irqrestore(&bam_tx_pool_spinlock, flags);
-	smsm_change_state(SMSM_APPS_STATE, SMSM_A2_POWER_CONTROL, 0);
 
+	bam_dmux_log("%s: complete\n", __func__);
 	return NOTIFY_DONE;
 }
 
@@ -1370,7 +1773,6 @@
 tx_mem_failed:
 	sps_deregister_bam_device(h);
 register_bam_failed:
-	iounmap(a2_virt_addr);
 ioremap_failed:
 	/*destroy_workqueue(bam_mux_workqueue);*/
 	return ret;
@@ -1409,15 +1811,29 @@
 	return 0;
 
 register_bam_failed:
-	iounmap(a2_virt_addr);
 ioremap_failed:
 	return ret;
 }
 
+static void msm9615_bam_init(struct work_struct *work)
+{
+	int ret = 0;
+
+	ret = bam_init();
+	if (ret) {
+		ret = bam_init_fallback();
+		if (ret)
+			pr_err("%s: bam init fallback failed: %d",
+					__func__, ret);
+	}
+}
+
 static void toggle_apps_ack(void)
 {
 	static unsigned int clear_bit; /* 0 = set the bit, else clear bit */
-	pr_info("%s: clear bit: %d\n", __func__, clear_bit);
+
+	bam_dmux_log("%s: apps ack %d->%d\n", __func__,
+			clear_bit & 0x1, ~clear_bit & 0x1);
 	smsm_change_state(SMSM_APPS_STATE,
 				clear_bit & SMSM_A2_POWER_CONTROL_ACK,
 				~clear_bit & SMSM_A2_POWER_CONTROL_ACK);
@@ -1426,29 +1842,37 @@
 
 static void bam_dmux_smsm_cb(void *priv, uint32_t old_state, uint32_t new_state)
 {
-	int ret = 0;
-	pr_info("%s: smsm activity 0x%08x -> 0x%08x\n", __func__, old_state,
-							new_state);
+	bam_dmux_power_state = new_state & SMSM_A2_POWER_CONTROL ? 1 : 0;
+	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+			new_state);
+
 	if (bam_mux_initialized && new_state & SMSM_A2_POWER_CONTROL) {
-		pr_info("%s: reconnect\n", __func__);
-		wake_lock(&bam_wakelock);
+		bam_dmux_log("%s: reconnect\n", __func__);
+		grab_wakelock();
 		reconnect_to_bam();
 	} else if (bam_mux_initialized &&
 					!(new_state & SMSM_A2_POWER_CONTROL)) {
-		pr_info("%s: disconnect\n", __func__);
+		bam_dmux_log("%s: disconnect\n", __func__);
 		disconnect_to_bam();
-		wake_unlock(&bam_wakelock);
+		release_wakelock();
 	} else if (new_state & SMSM_A2_POWER_CONTROL) {
-		pr_info("%s: init\n", __func__);
-		wake_lock(&bam_wakelock);
-		ret = bam_init();
-		if (ret) {
-			ret = bam_init_fallback();
-			if (ret)
-				pr_err("%s: bam init fallback failed: %d",
-						__func__, ret);
+		bam_dmux_log("%s: init\n", __func__);
+		grab_wakelock();
+		if (cpu_is_msm9615()) {
+			/*
+			 * even though a2 has signaled it is ready via the
+			 * SMSM_A2_POWER_CONTROL bit, it has not yet
+			 * enabled the pipes as needed by sps_connect
+			 * in satallite mode.  Add a short delay to give modem
+			 * time to enable the pipes.
+			 */
+			schedule_delayed_work(&msm9615_bam_init_work,
+						msecs_to_jiffies(100));
+		} else {
+			bam_init();
 		}
 	} else {
+		bam_dmux_log("%s: bad state change\n", __func__);
 		pr_err("%s: unsupported state change\n", __func__);
 	}
 
@@ -1457,7 +1881,8 @@
 static void bam_dmux_smsm_ack_cb(void *priv, uint32_t old_state,
 						uint32_t new_state)
 {
-	pr_info("%s: 0x%08x -> 0x%08x\n", __func__, old_state, new_state);
+	bam_dmux_log("%s: 0x%08x -> 0x%08x\n", __func__, old_state,
+			new_state);
 	complete_all(&ul_wakeup_ack_completion);
 }
 
@@ -1505,7 +1930,9 @@
 
 	init_completion(&ul_wakeup_ack_completion);
 	init_completion(&bam_connection_completion);
+	init_completion(&dfab_unvote_completion);
 	INIT_DELAYED_WORK(&ul_timeout_work, ul_timeout);
+	INIT_DELAYED_WORK(&msm9615_bam_init_work, msm9615_bam_init);
 	wake_lock_init(&bam_wakelock, WAKE_LOCK_SUSPEND, "bam_dmux_wakelock");
 
 	rc = smsm_state_cb_register(SMSM_MODEM_STATE, SMSM_A2_POWER_CONTROL,
@@ -1550,6 +1977,7 @@
 
 static int __init bam_dmux_init(void)
 {
+	int ret;
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *dent;
 
@@ -1558,8 +1986,16 @@
 		debug_create("tbl", 0444, dent, debug_tbl);
 		debug_create("ul_pkt_cnt", 0444, dent, debug_ul_pkt_cnt);
 		debug_create("stats", 0444, dent, debug_stats);
+		debugfs_create_file("log", 0444, dent, debug_log,
+				&debug_ops_multiple);
 	}
 #endif
+	ret = kfifo_alloc(&bam_dmux_state_log, PAGE_SIZE, GFP_KERNEL);
+	if (ret) {
+		pr_err("%s: failed to allocate log %d\n", __func__, ret);
+		bam_dmux_state_logging_disabled = 1;
+	}
+
 	subsys_notif_register_notifier("modem", &restart_notifier);
 	return platform_driver_register(&bam_dmux_driver);
 }
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index 9f66e5d..1aedd55 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -22,6 +22,7 @@
 #include <linux/spi/spi.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/qcom_crypto_device.h>
+#include <linux/ion.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/hardware/gic.h>
@@ -29,6 +30,7 @@
 
 #include <mach/board.h>
 #include <mach/msm_iomap.h>
+#include <mach/ion.h>
 #include <linux/usb/msm_hsusb.h>
 #include <linux/usb/android.h>
 #include <mach/socinfo.h>
@@ -37,7 +39,9 @@
 #include "devices.h"
 #include <mach/gpio.h>
 #include <mach/gpiomux.h>
+#ifdef CONFIG_ANDROID_PMEM
 #include <linux/android_pmem.h>
+#endif
 #include <mach/msm_memtypes.h>
 #include <linux/bootmem.h>
 #include <asm/setup.h>
@@ -46,27 +50,36 @@
 #include "msm_watchdog.h"
 #include "board-8064.h"
 
-#define MSM_PMEM_KERNEL_EBI1_SIZE  0x600000
-#define MSM_PMEM_ADSP_SIZE         0x3800000
+#define MSM_PMEM_ADSP_SIZE         0x7800000
 #define MSM_PMEM_AUDIO_SIZE        0x2B4000
-#define MSM_PMEM_SIZE 0x1800000 /* 24 Mbytes */
+#ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
+#define MSM_PMEM_SIZE 0x4000000 /* 64 Mbytes */
+#else
+#define MSM_PMEM_SIZE 0x2800000 /* 40 Mbytes */
+#endif
 
-static struct memtype_reserve apq8064_reserve_table[] __initdata = {
-	[MEMTYPE_SMI] = {
-	},
-	[MEMTYPE_EBI0] = {
-		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
-	},
-	[MEMTYPE_EBI1] = {
-		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
-	},
-};
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
+#define MSM_ION_SF_SIZE		MSM_PMEM_SIZE
+#define MSM_ION_MM_SIZE		MSM_PMEM_ADSP_SIZE
+#define MSM_ION_MFC_SIZE	SZ_8K
+#define MSM_ION_HEAP_NUM	5
+#else
+#define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
+#define MSM_ION_HEAP_NUM	1
+#endif
 
-static int apq8064_paddr_to_memtype(unsigned int paddr)
+#ifdef CONFIG_KERNEL_PMEM_EBI_REGION
+static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
+static int __init pmem_kernel_ebi1_size_setup(char *p)
 {
-	return MEMTYPE_EBI1;
+	pmem_kernel_ebi1_size = memparse(p, NULL);
+	return 0;
 }
+early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
+#endif
 
+#ifdef CONFIG_ANDROID_PMEM
 static unsigned pmem_size = MSM_PMEM_SIZE;
 static int __init pmem_size_setup(char *p)
 {
@@ -92,7 +105,10 @@
 	return 0;
 }
 early_param("pmem_audio_size", pmem_audio_size_setup);
+#endif
 
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 static struct android_pmem_platform_data android_pmem_pdata = {
 	.name = "pmem",
 	.allocator_type = PMEM_ALLOCATORTYPE_ALLORNOTHING,
@@ -112,20 +128,12 @@
 	.cached = 0,
 	.memory_type = MEMTYPE_EBI1,
 };
-
-static unsigned pmem_kernel_ebi1_size = MSM_PMEM_KERNEL_EBI1_SIZE;
-static int __init pmem_kernel_ebi1_size_setup(char *p)
-{
-	pmem_kernel_ebi1_size = memparse(p, NULL);
-	return 0;
-}
-early_param("pmem_kernel_ebi1_size", pmem_kernel_ebi1_size_setup);
-
 static struct platform_device android_pmem_adsp_device = {
 	.name = "android_pmem",
 	.id = 2,
 	.dev = { .platform_data = &android_pmem_adsp_pdata },
 };
+#endif
 
 static struct android_pmem_platform_data android_pmem_audio_pdata = {
 	.name = "pmem_audio",
@@ -139,12 +147,28 @@
 	.id = 4,
 	.dev = { .platform_data = &android_pmem_audio_pdata },
 };
+#endif
+
+static struct memtype_reserve apq8064_reserve_table[] __initdata = {
+	[MEMTYPE_SMI] = {
+	},
+	[MEMTYPE_EBI0] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+	[MEMTYPE_EBI1] = {
+		.flags	=	MEMTYPE_FLAGS_1M_ALIGN,
+	},
+};
 
 static void __init size_pmem_devices(void)
 {
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	android_pmem_adsp_pdata.size = pmem_adsp_size;
 	android_pmem_pdata.size = pmem_size;
+#endif
 	android_pmem_audio_pdata.size = MSM_PMEM_AUDIO_SIZE;
+#endif
 }
 
 static void __init reserve_memory_for(struct android_pmem_platform_data *p)
@@ -154,16 +178,97 @@
 
 static void __init reserve_pmem_memory(void)
 {
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	reserve_memory_for(&android_pmem_adsp_pdata);
 	reserve_memory_for(&android_pmem_pdata);
+#endif
 	reserve_memory_for(&android_pmem_audio_pdata);
 	apq8064_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
+#endif
+}
+
+static int apq8064_paddr_to_memtype(unsigned int paddr)
+{
+	return MEMTYPE_EBI1;
+}
+
+#ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+};
+#endif
+static struct ion_platform_data ion_pdata = {
+	.nr = MSM_ION_HEAP_NUM,
+	.heaps = {
+		{
+			.id	= ION_SYSTEM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_SYSTEM,
+			.name	= ION_VMALLOC_HEAP_NAME,
+		},
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+		{
+			.id	= ION_SF_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.name	= ION_SF_HEAP_NAME,
+			.size	= MSM_ION_SF_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &co_ion_pdata,
+		},
+		{
+			.id	= ION_CP_MM_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MM_HEAP_NAME,
+			.size	= MSM_ION_MM_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mm_ion_pdata,
+		},
+		{
+			.id	= ION_CP_MFC_HEAP_ID,
+			.type	= ION_HEAP_TYPE_CP,
+			.name	= ION_MFC_HEAP_NAME,
+			.size	= MSM_ION_MFC_SIZE,
+			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mfc_ion_pdata,
+		},
+		{
+			.id	= ION_IOMMU_HEAP_ID,
+			.type	= ION_HEAP_TYPE_IOMMU,
+			.name	= ION_IOMMU_HEAP_NAME,
+		},
+#endif
+	}
+};
+
+static struct platform_device ion_dev = {
+	.name = "ion-msm",
+	.id = 1,
+	.dev = { .platform_data = &ion_pdata },
+};
+#endif
+
+static void reserve_ion_memory(void)
+{
+#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
+	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MM_SIZE;
+	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_SF_SIZE;
+	apq8064_reserve_table[MEMTYPE_EBI1].size += MSM_ION_MFC_SIZE;
+#endif
 }
 
 static void __init apq8064_calculate_reserve_sizes(void)
 {
 	size_pmem_devices();
 	reserve_pmem_memory();
+	reserve_ion_memory();
 }
 
 static struct reserve_info apq8064_reserve_info __initdata = {
@@ -464,9 +569,16 @@
 	&apq8064_device_otg,
 	&apq8064_device_gadget_peripheral,
 	&android_usb_device,
+#ifdef CONFIG_ANDROID_PMEM
+#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
 	&android_pmem_device,
 	&android_pmem_adsp_device,
+#endif
 	&android_pmem_audio_device,
+#endif
+#ifdef CONFIG_ION_MSM
+	&ion_dev,
+#endif
 	&msm8064_device_watchdog,
 	&msm8064_device_saw_regulator_core0,
 	&msm8064_device_saw_regulator_core1,
diff --git a/arch/arm/mach-msm/board-8930-display.c b/arch/arm/mach-msm/board-8930-display.c
index afd79f4..23c94c4 100644
--- a/arch/arm/mach-msm/board-8930-display.c
+++ b/arch/arm/mach-msm/board-8930-display.c
@@ -90,8 +90,8 @@
 
 static int msm_fb_detect_panel(const char *name)
 {
-	if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
-			strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+	if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+			strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
 				PANEL_NAME_MAX_LEN)))
 		return 0;
 
@@ -101,8 +101,8 @@
 				PANEL_NAME_MAX_LEN)))
 		return 0;
 
-	if (!strncmp(name, MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
-			strnlen(MIPI_CMD_NOVATEK_QHD_PANEL_NAME,
+	if (!strncmp(name, MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
+			strnlen(MIPI_VIDEO_TOSHIBA_WSVGA_PANEL_NAME,
 				PANEL_NAME_MAX_LEN)))
 		return 0;
 
@@ -150,11 +150,10 @@
  * available, replace mipi_dsi_cdp_panel_power with
  * appropriate function.
  */
-#ifndef MSM8930_PHASE_2
+#define DISP_RST_GPIO 58
 static int mipi_dsi_cdp_panel_power(int on)
 {
 	static struct regulator *reg_l8, *reg_l23, *reg_l2;
-	static int gpio43;
 	int rc;
 
 	pr_info("%s: state : %d\n", __func__, on);
@@ -164,21 +163,21 @@
 		reg_l8 = regulator_get(&msm_mipi_dsi1_device.dev,
 				"dsi_vdc");
 		if (IS_ERR(reg_l8)) {
-			pr_err("could not get 8921_l8, rc = %ld\n",
+			pr_err("could not get 8038_l8, rc = %ld\n",
 				PTR_ERR(reg_l8));
 			return -ENODEV;
 		}
 		reg_l23 = regulator_get(&msm_mipi_dsi1_device.dev,
 				"dsi_vddio");
 		if (IS_ERR(reg_l23)) {
-			pr_err("could not get 8921_l23, rc = %ld\n",
+			pr_err("could not get 8038_l23, rc = %ld\n",
 				PTR_ERR(reg_l23));
 			return -ENODEV;
 		}
 		reg_l2 = regulator_get(&msm_mipi_dsi1_device.dev,
 				"dsi_vdda");
 		if (IS_ERR(reg_l2)) {
-			pr_err("could not get 8921_l2, rc = %ld\n",
+			pr_err("could not get 8038_l2, rc = %ld\n",
 				PTR_ERR(reg_l2));
 			return -ENODEV;
 		}
@@ -197,10 +196,11 @@
 			pr_err("set_voltage l2 failed, rc=%d\n", rc);
 			return -EINVAL;
 		}
-		gpio43 = PM8921_GPIO_PM_TO_SYS(43);
-		rc = gpio_request(gpio43, "disp_rst_n");
+		rc = gpio_request(DISP_RST_GPIO, "disp_rst_n");
 		if (rc) {
-			pr_err("request gpio 43 failed, rc=%d\n", rc);
+			pr_err("request gpio DISP_RST_GPIO failed, rc=%d\n",
+				rc);
+			gpio_free(DISP_RST_GPIO);
 			return -ENODEV;
 		}
 		dsi_power_on = true;
@@ -236,8 +236,11 @@
 			pr_err("enable l2 failed, rc=%d\n", rc);
 			return -ENODEV;
 		}
-		gpio_set_value_cansleep(gpio43, 1);
+		gpio_set_value(DISP_RST_GPIO, 1);
 	} else {
+
+		gpio_set_value(DISP_RST_GPIO, 0);
+
 		rc = regulator_disable(reg_l2);
 		if (rc) {
 			pr_err("disable reg_l2 failed, rc=%d\n", rc);
@@ -268,11 +271,9 @@
 			pr_err("set_optimum_mode l2 failed, rc=%d\n", rc);
 			return -EINVAL;
 		}
-		gpio_set_value_cansleep(gpio43, 0);
 	}
 	return 0;
 }
-#endif
 
 static int mipi_dsi_panel_power(int on)
 {
@@ -612,31 +613,30 @@
 #ifdef CONFIG_FB_MSM_HDMI_MSM_PANEL
 static int hdmi_enable_5v(int on)
 {
-	/* TBD: PM8921 regulator instead of 8901 */
-	static struct regulator *reg_8921_hdmi_mvs;	/* HDMI_5V */
+	static struct regulator *reg_ext_5v;	/* HDMI_5V */
 	static int prev_on;
 	int rc;
 
 	if (on == prev_on)
 		return 0;
 
-	if (!reg_8921_hdmi_mvs)
-		reg_8921_hdmi_mvs = regulator_get(&hdmi_msm_device.dev,
+	if (!reg_ext_5v)
+		reg_ext_5v = regulator_get(&hdmi_msm_device.dev,
 			"hdmi_mvs");
 
 	if (on) {
-		rc = regulator_enable(reg_8921_hdmi_mvs);
+		rc = regulator_enable(reg_ext_5v);
 		if (rc) {
 			pr_err("'%s' regulator enable failed, rc=%d\n",
-				"8921_hdmi_mvs", rc);
+				"reg_ext_5v", rc);
 			return rc;
 		}
 		pr_debug("%s(on): success\n", __func__);
 	} else {
-		rc = regulator_disable(reg_8921_hdmi_mvs);
+		rc = regulator_disable(reg_ext_5v);
 		if (rc)
 			pr_warning("'%s' regulator disable failed, rc=%d\n",
-				"8921_hdmi_mvs", rc);
+				"reg_ext_5v", rc);
 		pr_debug("%s(off): success\n", __func__);
 	}
 
@@ -647,59 +647,40 @@
 
 static int hdmi_core_power(int on, int show)
 {
-	static struct regulator *reg_8921_l23, *reg_8921_s4;
+	/* Both HDMI "avdd" and "vcc" are powered by 8038_l23 regulator */
+	static struct regulator *reg_8038_l23;
 	static int prev_on;
 	int rc;
 
 	if (on == prev_on)
 		return 0;
 
-	/* TBD: PM8921 regulator instead of 8901 */
-	if (!reg_8921_l23) {
-		reg_8921_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd");
-		if (IS_ERR(reg_8921_l23)) {
-			pr_err("could not get reg_8921_l23, rc = %ld\n",
-				PTR_ERR(reg_8921_l23));
+	if (!reg_8038_l23) {
+		reg_8038_l23 = regulator_get(&hdmi_msm_device.dev, "hdmi_avdd");
+		if (IS_ERR(reg_8038_l23)) {
+			pr_err("could not get reg_8038_l23, rc = %ld\n",
+				PTR_ERR(reg_8038_l23));
 			return -ENODEV;
 		}
-		rc = regulator_set_voltage(reg_8921_l23, 1800000, 1800000);
+		rc = regulator_set_voltage(reg_8038_l23, 1800000, 1800000);
 		if (rc) {
 			pr_err("set_voltage failed for 8921_l23, rc=%d\n", rc);
 			return -EINVAL;
 		}
 	}
-	if (!reg_8921_s4) {
-		reg_8921_s4 = regulator_get(&hdmi_msm_device.dev, "hdmi_vcc");
-		if (IS_ERR(reg_8921_s4)) {
-			pr_err("could not get reg_8921_s4, rc = %ld\n",
-				PTR_ERR(reg_8921_s4));
-			return -ENODEV;
-		}
-		rc = regulator_set_voltage(reg_8921_s4, 1800000, 1800000);
-		if (rc) {
-			pr_err("set_voltage failed for 8921_s4, rc=%d\n", rc);
-			return -EINVAL;
-		}
-	}
 
 	if (on) {
-		rc = regulator_set_optimum_mode(reg_8921_l23, 100000);
+		rc = regulator_set_optimum_mode(reg_8038_l23, 100000);
 		if (rc < 0) {
 			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
 			return -EINVAL;
 		}
-		rc = regulator_enable(reg_8921_l23);
+		rc = regulator_enable(reg_8038_l23);
 		if (rc) {
 			pr_err("'%s' regulator enable failed, rc=%d\n",
 				"hdmi_avdd", rc);
 			return rc;
 		}
-		rc = regulator_enable(reg_8921_s4);
-		if (rc) {
-			pr_err("'%s' regulator enable failed, rc=%d\n",
-				"hdmi_vcc", rc);
-			return rc;
-		}
 		rc = gpio_request(100, "HDMI_DDC_CLK");
 		if (rc) {
 			pr_err("'%s'(%d) gpio_request failed, rc=%d\n",
@@ -724,17 +705,12 @@
 		gpio_free(101);
 		gpio_free(102);
 
-		rc = regulator_disable(reg_8921_l23);
+		rc = regulator_disable(reg_8038_l23);
 		if (rc) {
-			pr_err("disable reg_8921_l23 failed, rc=%d\n", rc);
+			pr_err("disable reg_8038_l23 failed, rc=%d\n", rc);
 			return -ENODEV;
 		}
-		rc = regulator_disable(reg_8921_s4);
-		if (rc) {
-			pr_err("disable reg_8921_s4 failed, rc=%d\n", rc);
-			return -ENODEV;
-		}
-		rc = regulator_set_optimum_mode(reg_8921_l23, 100);
+		rc = regulator_set_optimum_mode(reg_8038_l23, 100);
 		if (rc < 0) {
 			pr_err("set_optimum_mode l23 failed, rc=%d\n", rc);
 			return -EINVAL;
@@ -751,8 +727,7 @@
 error2:
 	gpio_free(100);
 error1:
-	regulator_disable(reg_8921_l23);
-	regulator_disable(reg_8921_s4);
+	regulator_disable(reg_8038_l23);
 	return rc;
 }
 
diff --git a/arch/arm/mach-msm/board-8930-gpiomux.c b/arch/arm/mach-msm/board-8930-gpiomux.c
index 476ab93..fc64ed2 100644
--- a/arch/arm/mach-msm/board-8930-gpiomux.c
+++ b/arch/arm/mach-msm/board-8930-gpiomux.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
@@ -631,6 +631,29 @@
 };
 #endif
 
+#ifdef MSM8930_PHASE_2
+static struct gpiomux_setting haptics_suspend_cfg = {
+	.func = GPIOMUX_FUNC_GPIO,
+	.drv = GPIOMUX_DRV_8MA,
+	.pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm8930_haptics_configs[] __initdata = {
+	{
+		.gpio = 77,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
+		},
+	},
+	{
+		.gpio = 78,
+		.settings = {
+			[GPIOMUX_SUSPENDED] = &haptics_suspend_cfg,
+		},
+	},
+};
+#endif
+
 int __init msm8930_init_gpiomux(void)
 {
 	int rc = msm_gpiomux_init(NR_GPIO_IRQS);
@@ -676,6 +699,12 @@
 		msm_gpiomux_install(mdm_configs,
 			ARRAY_SIZE(mdm_configs));
 
+#ifdef MSM8930_PHASE_2
+	if (machine_is_msm8930_mtp() || machine_is_msm8930_fluid())
+		msm_gpiomux_install(msm8930_haptics_configs,
+			ARRAY_SIZE(msm8930_haptics_configs));
+#endif
+
 #ifdef CONFIG_USB_EHCI_MSM_HSIC
 	if ((SOCINFO_VERSION_MAJOR(socinfo_get_version()) != 1) &&
 			!machine_is_msm8930_mtp() &&
diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c
index b9ac4b8..6cb69f6 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.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
@@ -87,7 +87,13 @@
 			PM_GPIO_FUNC_NORMAL, 0, 0)
 
 /* Initial pm8038 GPIO configurations */
-static struct pm8xxx_gpio_init pm8038_gpios[] __initdata = {};
+static struct pm8xxx_gpio_init pm8038_gpios[] __initdata = {
+	/* keys GPIOs */
+	PM8XXX_GPIO_INPUT(3, PM_GPIO_PULL_UP_1P5),
+	PM8XXX_GPIO_INPUT(8, PM_GPIO_PULL_UP_1P5),
+	PM8XXX_GPIO_INPUT(10, PM_GPIO_PULL_UP_1P5),
+	PM8XXX_GPIO_INPUT(11, PM_GPIO_PULL_UP_1P5),
+};
 
 /* Initial pm8038 MPP configurations */
 static struct pm8xxx_mpp_init pm8038_mpps[] __initdata = {
@@ -188,7 +194,7 @@
 
 static struct pm8xxx_pwrkey_platform_data pm8xxx_pwrkey_pdata = {
 	.pull_up		= 1,
-	.kpd_trigger_delay_us	= 970,
+	.kpd_trigger_delay_us	= 15625,
 	.wakeup			= 1,
 };
 
diff --git a/arch/arm/mach-msm/board-8930-regulator.c b/arch/arm/mach-msm/board-8930-regulator.c
index d3e19a0..cf7d6a9 100644
--- a/arch/arm/mach-msm/board-8930-regulator.c
+++ b/arch/arm/mach-msm/board-8930-regulator.c
@@ -24,9 +24,12 @@
  */
 VREG_CONSUMERS(L1) = {
 	REGULATOR_SUPPLY("8038_l1",		NULL),
+	REGULATOR_SUPPLY("iris_vddrfa",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L2) = {
 	REGULATOR_SUPPLY("8038_l2",		NULL),
+	REGULATOR_SUPPLY("iris_vdddig",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("dsi_vdda",		"mipi_dsi.1"),
 };
 VREG_CONSUMERS(L3) = {
 	REGULATOR_SUPPLY("8038_l3",		NULL),
@@ -35,6 +38,7 @@
 VREG_CONSUMERS(L4) = {
 	REGULATOR_SUPPLY("8038_l4",		NULL),
 	REGULATOR_SUPPLY("HSUSB_1p8",		"msm_otg"),
+	REGULATOR_SUPPLY("iris_vddxo",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L5) = {
 	REGULATOR_SUPPLY("8038_l5",		NULL),
@@ -47,15 +51,22 @@
 };
 VREG_CONSUMERS(L8) = {
 	REGULATOR_SUPPLY("8038_l8",		NULL),
+	REGULATOR_SUPPLY("dsi_vdc",		"mipi_dsi.1"),
 };
 VREG_CONSUMERS(L9) = {
 	REGULATOR_SUPPLY("8038_l9",		NULL),
+	REGULATOR_SUPPLY("vdd_ana",		"3-004a"),
+	REGULATOR_SUPPLY("vdd",			"3-0024"),
 };
 VREG_CONSUMERS(L10) = {
 	REGULATOR_SUPPLY("8038_l10",		NULL),
+	REGULATOR_SUPPLY("iris_vddpa",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L11) = {
 	REGULATOR_SUPPLY("8038_l11",		NULL),
+	REGULATOR_SUPPLY("vdd_dig",		"3-004a"),
+	REGULATOR_SUPPLY("iris_vddio",		"wcnss_wlan.0"),
+	REGULATOR_SUPPLY("riva_vddpx",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L12) = {
 	REGULATOR_SUPPLY("8038_l12",		NULL),
@@ -91,9 +102,13 @@
 };
 VREG_CONSUMERS(L23) = {
 	REGULATOR_SUPPLY("8038_l23",		NULL),
+	REGULATOR_SUPPLY("dsi_vddio",		"mipi_dsi.1"),
+	REGULATOR_SUPPLY("hdmi_avdd",		"hdmi_msm.0"),
+	REGULATOR_SUPPLY("hdmi_vcc",		"hdmi_msm.0"),
 };
 VREG_CONSUMERS(L24) = {
 	REGULATOR_SUPPLY("8038_l24",		NULL),
+	REGULATOR_SUPPLY("riva_vddmx",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(L26) = {
 	REGULATOR_SUPPLY("8038_l26",		NULL),
@@ -105,6 +120,7 @@
 VREG_CONSUMERS(S1) = {
 	REGULATOR_SUPPLY("8038_s1",		NULL),
 	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
+	REGULATOR_SUPPLY("riva_vddcx",		"wcnss_wlan.0"),
 };
 VREG_CONSUMERS(S2) = {
 	REGULATOR_SUPPLY("8038_s2",		NULL),
@@ -128,13 +144,17 @@
 };
 VREG_CONSUMERS(LVS2) = {
 	REGULATOR_SUPPLY("8038_lvs2",		NULL),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-004a"),
+	REGULATOR_SUPPLY("vcc_i2c",		"3-0024"),
+	REGULATOR_SUPPLY("vddp",		"12-0048"),
 };
 VREG_CONSUMERS(EXT_5V) = {
 	REGULATOR_SUPPLY("ext_5v",		NULL),
+	REGULATOR_SUPPLY("hdmi_mvs",		"hdmi_msm.0"),
 };
 VREG_CONSUMERS(EXT_OTG_SW) = {
 	REGULATOR_SUPPLY("ext_otg_sw",		NULL),
-	REGULATOR_SUPPLY("vbus_otg",          "msm_otg"),
+	REGULATOR_SUPPLY("vbus_otg",		"msm_otg"),
 };
 
 #define PM8XXX_VREG_INIT(_id, _name, _min_uV, _max_uV, _modes, _ops, \
diff --git a/arch/arm/mach-msm/board-8930-storage.c b/arch/arm/mach-msm/board-8930-storage.c
index e38f877..d655ead 100644
--- a/arch/arm/mach-msm/board-8930-storage.c
+++ b/arch/arm/mach-msm/board-8930-storage.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -261,11 +261,12 @@
 	.status_irq	= PM8921_GPIO_IRQ(PM8921_IRQ_BASE, 26),
 #endif
 	.irq_flags	= IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+	.is_status_gpio_active_low = true,
 #endif
 	.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_MAX_CURRENT_600),
 };
 #endif
 
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 53f8621..533d4f7 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -40,6 +40,7 @@
 #include <linux/msm_tsens.h>
 #include <linux/ks8851.h>
 #include <linux/i2c/isa1200.h>
+#include <linux/gpio_keys.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -81,8 +82,8 @@
 #include "devices.h"
 #include "devices-msm8x60.h"
 #include "spm.h"
-#include "pm.h"
-#include "cpuidle.h"
+#include <mach/pm.h>
+#include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include "mpm.h"
 #include "acpuclock.h"
@@ -281,6 +282,17 @@
 }
 
 #ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+};
+static struct ion_co_heap_pdata co_ion_pdata = {
+};
+#endif
 static struct ion_platform_data ion_pdata = {
 	.nr = MSM_ION_HEAP_NUM,
 	.heaps = {
@@ -296,20 +308,23 @@
 			.name	= ION_SF_HEAP_NAME,
 			.size	= MSM_ION_SF_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = &co_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MM_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MM_HEAP_NAME,
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mm_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MFC_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MFC_HEAP_NAME,
 			.size	= MSM_ION_MFC_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mfc_ion_pdata,
 		},
 		{
 			.id	= ION_IOMMU_HEAP_ID,
@@ -992,12 +1007,19 @@
 #ifndef MSM8930_PHASE_2
 #define PM_HAP_EN_GPIO		PM8921_GPIO_PM_TO_SYS(33)
 #define PM_HAP_LEN_GPIO		PM8921_GPIO_PM_TO_SYS(20)
+#else
+#define ISA1200_HAP_EN_GPIO	77
+#define ISA1200_HAP_LEN_GPIO	78
+#define ISA1200_HAP_CLK		PM8038_GPIO_PM_TO_SYS(7)
 #endif
 
+#ifndef MSM8930_PHASE_2
 static struct msm_xo_voter *xo_handle_d1;
+#endif
 
 static int isa1200_power(int on)
 {
+#ifndef MSM8930_PHASE_2
 	int rc = 0;
 
 	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !!on);
@@ -1015,12 +1037,19 @@
 err_xo_vote:
 	gpio_set_value(HAP_SHIFT_LVL_OE_GPIO, !on);
 	return rc;
+#else
+	gpio_set_value_cansleep(ISA1200_HAP_CLK, !!on);
+
+	return 0;
+#endif
+
 }
 
 static int isa1200_dev_setup(bool enable)
 {
 	int rc = 0;
 
+#ifndef MSM8930_PHASE_2
 	struct pm_gpio hap_gpio_config = {
 		.direction      = PM_GPIO_DIR_OUT,
 		.pull           = PM_GPIO_PULL_NO,
@@ -1080,23 +1109,78 @@
 free_gpio:
 	gpio_free(HAP_SHIFT_LVL_OE_GPIO);
 	return rc;
+#else
+	struct pm_gpio hap_clk_gpio_config = {
+		.direction      = PM_GPIO_DIR_OUT,
+		.pull           = PM_GPIO_PULL_NO,
+		.out_strength   = PM_GPIO_STRENGTH_HIGH,
+		.function       = PM_GPIO_FUNC_1,
+		.inv_int_pol    = 0,
+		.vin_sel        = PM_GPIO_VIN_S4,
+		.output_buffer  = PM_GPIO_OUT_BUF_CMOS,
+		.output_value   = 0,
+	};
+
+	rc = pm8xxx_gpio_config(ISA1200_HAP_CLK, &hap_clk_gpio_config);
+	if (rc) {
+		pr_err("%s: pm8038 gpio %d config failed(%d)\n",
+				__func__, ISA1200_HAP_CLK, rc);
+		return rc;
+	}
+
+	rc = gpio_request(ISA1200_HAP_CLK, "haptics_clk");
+	if (rc) {
+		pr_err("%s: gpio_request for %d gpio failed rc(%d)\n",
+					__func__, ISA1200_HAP_CLK, rc);
+		goto fail_gpio_req;
+	}
+
+	rc = gpio_direction_output(ISA1200_HAP_CLK, 0);
+	if (rc) {
+		pr_err("%s: gpio_direction_output failed for %d gpio rc(%d)\n",
+						__func__, ISA1200_HAP_CLK, rc);
+		goto fail_gpio_dir;
+	}
+
+	return 0;
+
+fail_gpio_dir:
+	gpio_free(ISA1200_HAP_CLK);
+fail_gpio_req:
+	return rc;
+
+#endif
 }
 
 static struct isa1200_regulator isa1200_reg_data[] = {
+#ifndef MSM8930_PHASE_2
 	{
 		.name = "vcc_i2c",
 		.min_uV = ISA_I2C_VTG_MIN_UV,
 		.max_uV = ISA_I2C_VTG_MAX_UV,
 		.load_uA = ISA_I2C_CURR_UA,
 	},
+#else
+	{
+		.name = "vddp",
+		.min_uV = ISA_I2C_VTG_MIN_UV,
+		.max_uV = ISA_I2C_VTG_MAX_UV,
+		.load_uA = ISA_I2C_CURR_UA,
+	},
+#endif
 };
 
 static struct isa1200_platform_data isa1200_1_pdata = {
 	.name = "vibrator",
 	.dev_setup = isa1200_dev_setup,
 	.power_on = isa1200_power,
+#ifndef MSM8930_PHASE_2
 	.hap_en_gpio = PM_HAP_EN_GPIO,
 	.hap_len_gpio = PM_HAP_LEN_GPIO,
+#else
+	.hap_en_gpio = ISA1200_HAP_EN_GPIO,
+	.hap_len_gpio = ISA1200_HAP_LEN_GPIO,
+#endif
 	.max_timeout = 15000,
 	.mode_ctrl = PWM_GEN_MODE,
 	.pwm_fd = {
@@ -1338,6 +1422,9 @@
 	.x_size			= 1067,
 	.y_size			= 566,
 	.irqflags		= IRQF_TRIGGER_FALLING,
+#ifdef MSM8930_PHASE_2
+	.digital_pwr_regulator	= true,
+#endif
 	.i2c_pull_up		= true,
 	.reset_gpio		= MXT_TS_RESET_GPIO,
 	.irq_gpio		= MXT_TS_GPIO_IRQ,
@@ -1351,6 +1438,63 @@
 	},
 };
 
+#ifdef MSM8930_PHASE_2
+
+#define GPIO_VOLUME_UP		PM8038_GPIO_PM_TO_SYS(3)
+#define GPIO_VOLUME_DOWN	PM8038_GPIO_PM_TO_SYS(8)
+#define GPIO_CAMERA_SNAPSHOT	PM8038_GPIO_PM_TO_SYS(10)
+#define GPIO_CAMERA_FOCUS	PM8038_GPIO_PM_TO_SYS(11)
+
+static struct gpio_keys_button keys_8930[] = {
+	{
+		.code = KEY_VOLUMEUP,
+		.type = EV_KEY,
+		.desc = "volume_up",
+		.gpio = GPIO_VOLUME_UP,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+	{
+		.code = KEY_VOLUMEDOWN,
+		.type = EV_KEY,
+		.desc = "volume_down",
+		.gpio = GPIO_VOLUME_DOWN,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+	{
+		.code = KEY_CAMERA_FOCUS,
+		.type = EV_KEY,
+		.desc = "camera_focus",
+		.gpio = GPIO_CAMERA_FOCUS,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+	{
+		.code = KEY_CAMERA_SNAPSHOT,
+		.type = EV_KEY,
+		.desc = "camera_snapshot",
+		.gpio = GPIO_CAMERA_SNAPSHOT,
+		.wakeup = 1,
+		.active_low = 1,
+	},
+};
+
+/* Add GPIO keys for 8930 */
+static struct gpio_keys_platform_data gpio_keys_8930_pdata = {
+	.buttons = keys_8930,
+	.nbuttons = 4,
+};
+
+static struct platform_device gpio_keys_8930 = {
+	.name		= "gpio-keys",
+	.id		= -1,
+	.dev		= {
+		.platform_data  = &gpio_keys_8930_pdata,
+	},
+};
+#endif /* MSM8930_PHASE_2 */
+
 static struct msm_i2c_platform_data msm8960_i2c_qup_gsbi4_pdata = {
 	.clk_freq = 100000,
 	.src_clk_rate = 24000000,
@@ -1593,11 +1737,13 @@
 	&msm_etb_device,
 	&msm_tpiu_device,
 	&msm_funnel_device,
-	&msm_debug_device,
 	&msm_ptm_device,
 #endif
 	&msm_device_dspcrashd_8960,
 	&msm8960_device_watchdog,
+#ifdef MSM8930_PHASE_2
+	&gpio_keys_8930,
+#endif
 };
 
 static struct platform_device *cdp_devices[] __initdata = {
@@ -1870,12 +2016,21 @@
 		cyttsp_info,
 		ARRAY_SIZE(cyttsp_info),
 	},
+#ifndef MSM8930_PHASE_2
 	{
 		I2C_LIQUID,
 		MSM_8930_GSBI10_QUP_I2C_BUS_ID,
 		msm_isa1200_board_info,
 		ARRAY_SIZE(msm_isa1200_board_info),
 	},
+#else
+	{
+		I2C_FFA | I2C_FLUID,
+		MSM_8930_GSBI10_QUP_I2C_BUS_ID,
+		msm_isa1200_board_info,
+		ARRAY_SIZE(msm_isa1200_board_info),
+	},
+#endif
 	{
 		I2C_SURF,
 		MSM_8930_GSBI3_QUP_I2C_BUS_ID,
diff --git a/arch/arm/mach-msm/board-8960-gpiomux.c b/arch/arm/mach-msm/board-8960-gpiomux.c
index 71713829..0dfa1c6 100644
--- a/arch/arm/mach-msm/board-8960-gpiomux.c
+++ b/arch/arm/mach-msm/board-8960-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 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
@@ -84,7 +84,7 @@
 	{
 		.func = GPIOMUX_FUNC_GPIO,
 		.drv = GPIOMUX_DRV_2MA,
-		.pull = GPIOMUX_PULL_NONE,
+		.pull = GPIOMUX_PULL_DOWN,
 	},
 	/* Active state */
 	{
diff --git a/arch/arm/mach-msm/board-8960-regulator.c b/arch/arm/mach-msm/board-8960-regulator.c
index f6212af..f36c3a1 100644
--- a/arch/arm/mach-msm/board-8960-regulator.c
+++ b/arch/arm/mach-msm/board-8960-regulator.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -499,7 +499,7 @@
 	RPM_SMPS(S1,	 1, 1, 0, 1225000, 1225000, NULL, 100000, 3p20),
 	RPM_SMPS(S2,	 0, 1, 0, 1300000, 1300000, NULL, 0,	  1p60),
 	RPM_SMPS(S3,	 0, 1, 1,  500000, 1150000, NULL, 100000, 4p80),
-	RPM_SMPS(S4,	 1, 1, 0, 1800000, 1800000, NULL, 100000, 3p20),
+	RPM_SMPS(S4,	 1, 1, 0, 1800000, 1800000, NULL, 100000, 1p60),
 	RPM_SMPS(S7,	 0, 1, 0, 1150000, 1150000, NULL, 100000, 3p20),
 	RPM_SMPS(S8,	 1, 1, 1, 2100000, 2100000, NULL, 100000, 1p60),
 
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 15a3829..b19445d 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -87,8 +87,8 @@
 #include "devices-msm8x60.h"
 #include "spm.h"
 #include "board-8960.h"
-#include "pm.h"
-#include "cpuidle.h"
+#include <mach/pm.h>
+#include <mach/cpuidle.h>
 #include "rpm_resources.h"
 #include "mpm.h"
 #include "acpuclock.h"
@@ -141,7 +141,7 @@
 
 #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0xB0C000
-#define MSM_ION_SF_SIZE		0x1800000 /* 24MB */
+#define MSM_ION_SF_SIZE		0x2800000 /* (40MB) */
 #define MSM_ION_MM_SIZE		0x4000000 /* (64MB) */
 #define MSM_ION_MFC_SIZE	SZ_8K
 #define MSM_ION_HEAP_NUM	5
@@ -309,6 +309,19 @@
 }
 
 #ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+};
+#endif
+
 static struct ion_platform_data ion_pdata = {
 	.nr = MSM_ION_HEAP_NUM,
 	.heaps = {
@@ -324,20 +337,23 @@
 			.name	= ION_SF_HEAP_NAME,
 			.size	= MSM_ION_SF_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = &co_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MM_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MM_HEAP_NAME,
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mm_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MFC_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MFC_HEAP_NAME,
 			.size	= MSM_ION_MFC_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_mfc_ion_pdata,
 		},
 		{
 			.id	= ION_IOMMU_HEAP_ID,
@@ -1362,6 +1378,8 @@
 	/* T15 Object */
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	0,
+	/* T18 Object */
+	0, 0,
 	/* T22 Object */
 	5, 0, 0, 0, 0, 0, 0, 0, 30, 0,
 	0, 0, 5, 8, 10, 13, 0,
@@ -1473,6 +1491,12 @@
 	.msm_apps_ipc_rpm_val = 4,
 };
 
+static struct msm_pm_sleep_status_data msm_pm_slp_sts_data = {
+	.base_addr = MSM_ACC0_BASE + 0x08,
+	.cpu_offset = MSM_ACC1_BASE - MSM_ACC0_BASE,
+	.mask = 1UL << 13,
+};
+
 static struct ks8851_pdata spi_eth_pdata = {
 	.irq_gpio = KS8851_IRQ_GPIO,
 	.rst_gpio = KS8851_RST_GPIO,
@@ -1657,7 +1681,6 @@
 	&msm_etb_device,
 	&msm_tpiu_device,
 	&msm_funnel_device,
-	&msm_debug_device,
 	&msm_ptm_device,
 #endif
 	&msm_device_dspcrashd_8960,
@@ -2150,6 +2173,7 @@
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
 }
 
 static void __init msm8960_rumi3_init(void)
@@ -2181,6 +2205,7 @@
 	msm_cpuidle_set_states(msm_cstates, ARRAY_SIZE(msm_cstates),
 				msm_pm_data);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
 }
 
 static void __init msm8960_cdp_init(void)
@@ -2256,6 +2281,7 @@
 				msm_pm_data);
 	change_memory_power = &msm8960_change_memory_power;
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
+	msm_pm_init_sleep_status_data(&msm_pm_slp_sts_data);
 	if (PLATFORM_IS_CHARM25())
 		platform_add_devices(mdm_devices, ARRAY_SIZE(mdm_devices));
 }
diff --git a/arch/arm/mach-msm/board-9615-regulator.c b/arch/arm/mach-msm/board-9615-regulator.c
index 4859f18..95a1347 100644
--- a/arch/arm/mach-msm/board-9615-regulator.c
+++ b/arch/arm/mach-msm/board-9615-regulator.c
@@ -69,6 +69,7 @@
 VREG_CONSUMERS(S1) = {
 	REGULATOR_SUPPLY("8018_s1",		NULL),
 	REGULATOR_SUPPLY("HSUSB_VDDCX",		"msm_otg"),
+	REGULATOR_SUPPLY("HSIC_VDDCX",		"msm_hsic_peripheral"),
 };
 VREG_CONSUMERS(S2) = {
 	REGULATOR_SUPPLY("8018_s2",		NULL),
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 93e8fdf..f708b11 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -33,8 +33,8 @@
 #include "timer.h"
 #include "devices.h"
 #include "board-9615.h"
-#include "cpuidle.h"
-#include "pm.h"
+#include <mach/cpuidle.h>
+#include <mach/pm.h>
 #include "acpuclock.h"
 #include "pm-boot.h"
 
@@ -385,6 +385,7 @@
 	&msm_device_charger,
 #endif
 	&msm_device_otg,
+	&msm_device_hsic_peripheral,
 	&msm_device_gadget_peripheral,
 	&msm_device_hsusb_host,
 	&msm_device_usb_bam,
diff --git a/arch/arm/mach-msm/board-copper.c b/arch/arm/mach-msm/board-copper.c
index f4fcb75..a372eb6 100644
--- a/arch/arm/mach-msm/board-copper.c
+++ b/arch/arm/mach-msm/board-copper.c
@@ -70,9 +70,10 @@
 	CLK_DUMMY("iface_clk",	SDC1_P_CLK,	NULL,			OFF),
 	CLK_DUMMY("core_clk",	SDC3_CLK,	NULL,			OFF),
 	CLK_DUMMY("iface_clk",	SDC3_P_CLK,	NULL,			OFF),
-	CLK_DUMMY("usb_phy_clk", NULL, NULL, OFF),
-	CLK_DUMMY("usb_hs_clk", NULL, NULL, OFF),
-	CLK_DUMMY("usb_hs_pclk", NULL, NULL, OFF),
+	CLK_DUMMY("phy_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("alt_core_clk", NULL, "msm_otg", OFF),
+	CLK_DUMMY("iface_clk", NULL, "msm_otg", OFF),
 	CLK_DUMMY("dfab_clk",	DFAB_CLK,	NULL, 0),
 	CLK_DUMMY("dma_bam_pclk",	DMA_BAM_P_CLK,	NULL, 0),
 	CLK_DUMMY("mem_clk",	NULL,	NULL, 0),
@@ -86,6 +87,8 @@
 static struct of_dev_auxdata msm_copper_auxdata_lookup[] __initdata = {
 	OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
 			"msm_serial_hsl.0", NULL),
+	OF_DEV_AUXDATA("qcom,hsusb-otg", 0xF9A55000, \
+			"msm_otg", NULL),
 	{}
 };
 
diff --git a/arch/arm/mach-msm/board-fsm9xxx.c b/arch/arm/mach-msm/board-fsm9xxx.c
index 87fea3f..36ab719 100644
--- a/arch/arm/mach-msm/board-fsm9xxx.c
+++ b/arch/arm/mach-msm/board-fsm9xxx.c
@@ -38,7 +38,7 @@
 #include "devices.h"
 #include "timer.h"
 #include "acpuclock.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "spm.h"
 #include <linux/regulator/consumer.h>
 #include <linux/regulator/machine.h>
diff --git a/arch/arm/mach-msm/board-msm7627a-camera.c b/arch/arm/mach-msm/board-msm7627a-camera.c
new file mode 100644
index 0000000..a3c2da3
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm7627a-camera.c
@@ -0,0 +1,541 @@
+/* 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/i2c.h>
+#include <linux/i2c/sx150x.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <asm/mach-types.h>
+#include <mach/msm_iomap.h>
+#include <mach/board.h>
+#include <mach/irqs-7xxx.h>
+#include "devices-msm7x2xa.h"
+#include "board-msm7627a.h"
+
+static uint32_t camera_off_gpio_table[] = {
+	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+static uint32_t camera_on_gpio_table[] = {
+	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
+};
+
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
+	._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
+};
+#endif
+
+static struct regulator_bulk_data regs_camera[] = {
+	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
+	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
+	{ .supply = "usb2",  .min_uV = 1800000, .max_uV = 1800000 },
+};
+
+static void qrd1_camera_gpio_cfg(void)
+{
+
+	int rc = 0;
+
+	rc = gpio_request(QRD_GPIO_CAM_5MP_SHDN_EN, "ov5640");
+	if (rc < 0)
+		pr_err("%s: gpio_request---GPIO_CAM_5MP_SHDN_EN failed!",
+				__func__);
+
+
+	rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_5MP_SHDN_EN, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable Power Down gpio for main"
+				"camera!\n", __func__);
+		gpio_free(QRD_GPIO_CAM_5MP_SHDN_EN);
+	}
+
+
+	rc = gpio_request(QRD_GPIO_CAM_5MP_RESET, "ov5640");
+	if (rc < 0) {
+		pr_err("%s: gpio_request---GPIO_CAM_5MP_RESET failed!",
+				__func__);
+		gpio_free(QRD_GPIO_CAM_5MP_SHDN_EN);
+	}
+
+
+	rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_5MP_RESET, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable reset gpio for main camera!\n",
+				__func__);
+		gpio_free(QRD_GPIO_CAM_5MP_RESET);
+	}
+
+	rc = gpio_request(QRD_GPIO_CAM_3MP_PWDN, "ov7692");
+	if (rc < 0)
+		pr_err("%s: gpio_request---GPIO_CAM_3MP_PWDN failed!",
+				__func__);
+
+	rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_CAM_3MP_PWDN, 0,
+				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
+				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
+	if (rc < 0) {
+		pr_err("%s: unable to enable Power Down gpio for front"
+				"camera!\n", __func__);
+		gpio_free(QRD_GPIO_CAM_3MP_PWDN);
+	}
+
+	gpio_direction_output(QRD_GPIO_CAM_5MP_SHDN_EN, 1);
+	gpio_direction_output(QRD_GPIO_CAM_5MP_RESET, 1);
+	gpio_direction_output(QRD_GPIO_CAM_3MP_PWDN, 1);
+}
+
+static void msm_camera_vreg_config(int vreg_en)
+{
+	int rc = vreg_en ?
+		regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
+		regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
+
+	if (rc)
+		pr_err("%s: could not %sable regulators: %d\n",
+				__func__, vreg_en ? "en" : "dis", rc);
+}
+
+static int config_gpio_table(uint32_t *table, int len)
+{
+	int rc = 0, i = 0;
+
+	for (i = 0; i < len; i++) {
+		rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
+		if (rc) {
+			pr_err("%s not able to get gpio\n", __func__);
+			for (i--; i >= 0; i--)
+				gpio_tlmm_config(camera_off_gpio_table[i],
+							GPIO_CFG_ENABLE);
+			break;
+		}
+	}
+	return rc;
+}
+
+static int config_camera_on_gpios_rear(void)
+{
+	int rc = 0;
+
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1())
+		msm_camera_vreg_config(1);
+
+	rc = config_gpio_table(camera_on_gpio_table,
+			ARRAY_SIZE(camera_on_gpio_table));
+	if (rc < 0) {
+		pr_err("%s: CAMSENSOR gpio table request"
+		"failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void config_camera_off_gpios_rear(void)
+{
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1())
+		msm_camera_vreg_config(0);
+
+	config_gpio_table(camera_off_gpio_table,
+			ARRAY_SIZE(camera_off_gpio_table));
+}
+
+static int config_camera_on_gpios_front(void)
+{
+	int rc = 0;
+
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1())
+		msm_camera_vreg_config(1);
+
+	rc = config_gpio_table(camera_on_gpio_table,
+			ARRAY_SIZE(camera_on_gpio_table));
+	if (rc < 0) {
+		pr_err("%s: CAMSENSOR gpio table request"
+			"failed\n", __func__);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void config_camera_off_gpios_front(void)
+{
+	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa()
+				|| machine_is_msm7627a_qrd1())
+		msm_camera_vreg_config(0);
+
+	config_gpio_table(camera_off_gpio_table,
+			ARRAY_SIZE(camera_off_gpio_table));
+}
+
+struct msm_camera_device_platform_data msm_camera_device_data_rear = {
+	.camera_gpio_on		= config_camera_on_gpios_rear,
+	.camera_gpio_off	= config_camera_off_gpios_rear,
+	.ioext.csiphy		= 0xA1000000,
+	.ioext.csisz		= 0x00100000,
+	.ioext.csiirq		= INT_CSI_IRQ_1,
+	.ioclk.mclk_clk_rate	= 24000000,
+	.ioclk.vfe_clk_rate	= 192000000,
+	.ioext.appphy		= MSM_CLK_CTL_PHYS,
+	.ioext.appsz		= MSM_CLK_CTL_SIZE,
+};
+
+struct msm_camera_device_platform_data msm_camera_device_data_front = {
+	.camera_gpio_on		= config_camera_on_gpios_front,
+	.camera_gpio_off	= config_camera_off_gpios_front,
+	.ioext.csiphy		= 0xA0F00000,
+	.ioext.csisz		= 0x00100000,
+	.ioext.csiirq		= INT_CSI_IRQ_0,
+	.ioclk.mclk_clk_rate	= 24000000,
+	.ioclk.vfe_clk_rate	= 192000000,
+	.ioext.appphy		= MSM_CLK_CTL_PHYS,
+	.ioext.appsz		= MSM_CLK_CTL_SIZE,
+};
+
+#ifdef CONFIG_S5K4E1
+static struct msm_camera_sensor_platform_info s5k4e1_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_s5k4e1 = {
+	.flash_type	     = MSM_CAMERA_FLASH_LED,
+	.flash_src	      = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
+	.sensor_name		= "s5k4e1",
+	.sensor_reset_enable	= 1,
+	.sensor_reset		= GPIO_CAM_GP_CAMIF_RESET_N,
+	.sensor_pwd	     = 85,
+	.vcm_pwd		= GPIO_CAM_GP_CAM_PWDN,
+	.vcm_enable	     = 1,
+	.pdata			= &msm_camera_device_data_rear,
+	.flash_data	     = &flash_s5k4e1,
+	.sensor_platform_info   = &s5k4e1_sensor_7627a_info,
+	.csi_if			= 1
+};
+
+static struct platform_device msm_camera_sensor_s5k4e1 = {
+	.name   = "msm_camera_s5k4e1",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_s5k4e1_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_IMX072
+static struct msm_camera_sensor_platform_info imx072_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_imx072 = {
+	.flash_type	     = MSM_CAMERA_FLASH_LED,
+	.flash_src	      = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx072_data = {
+	.sensor_name		= "imx072",
+	.sensor_reset_enable	= 1,
+	.sensor_reset		= GPIO_CAM_GP_CAMIF_RESET_N, /* TODO 106,*/
+	.sensor_pwd	     = 85,
+	.vcm_pwd		= GPIO_CAM_GP_CAM_PWDN,
+	.vcm_enable	     = 1,
+	.pdata			= &msm_camera_device_data_rear,
+	.flash_data	     = &flash_imx072,
+	.sensor_platform_info	= &imx072_sensor_7627a_info,
+	.csi_if			= 1
+};
+
+static struct platform_device msm_camera_sensor_imx072 = {
+	.name   = "msm_camera_imx072",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_imx072_data,
+	},
+};
+#endif
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data;
+#ifdef CONFIG_WEBCAM_OV9726
+static struct msm_camera_sensor_platform_info ov9726_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_ov9726 = {
+	.flash_type	     = MSM_CAMERA_FLASH_NONE,
+	.flash_src	      = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
+	.sensor_name		= "ov9726",
+	.sensor_reset_enable	= 0,
+	.sensor_reset		= GPIO_CAM_GP_CAM1MP_XCLR,
+	.sensor_pwd	     = 85,
+	.vcm_pwd		= 1,
+	.vcm_enable	     = 0,
+	.pdata			= &msm_camera_device_data_front,
+	.flash_data	     = &flash_ov9726,
+	.sensor_platform_info   = &ov9726_sensor_7627a_info,
+	.csi_if			= 1
+};
+
+static struct platform_device msm_camera_sensor_ov9726 = {
+	.name   = "msm_camera_ov9726",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_ov9726_data,
+	},
+};
+#else
+static inline void msm_camera_vreg_init(void) { }
+#endif
+
+#ifdef CONFIG_MT9E013
+static struct msm_camera_sensor_platform_info mt9e013_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_mt9e013 = {
+	.flash_type = MSM_CAMERA_FLASH_LED,
+	.flash_src  = &msm_flash_src
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
+	.sensor_name		= "mt9e013",
+	.sensor_reset		= 0,
+	.sensor_reset_enable	= 1,
+	.sensor_pwd		= 85,
+	.vcm_pwd		= 1,
+	.vcm_enable		= 0,
+	.pdata		= &msm_camera_device_data_rear,
+	.flash_data		= &flash_mt9e013,
+	.sensor_platform_info   = &mt9e013_sensor_7627a_info,
+	.csi_if		= 1
+};
+
+static struct platform_device msm_camera_sensor_mt9e013 = {
+	.name      = "msm_camera_mt9e013",
+	.dev       = {
+		.platform_data = &msm_camera_sensor_mt9e013_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_OV5640
+static struct msm_camera_sensor_platform_info ov5640_sensor_info = {
+	.mount_angle    = 90
+};
+
+static struct msm_camera_sensor_flash_src msm_flash_src_ov5640 = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
+	._fsrc.led_src.led_name = "flashlight",
+	._fsrc.led_src.led_name_len = 10,
+};
+
+static struct msm_camera_sensor_flash_data flash_ov5640 = {
+	.flash_type     = MSM_CAMERA_FLASH_LED,
+	.flash_src      = &msm_flash_src_ov5640,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov5640_data = {
+	.sensor_name	    = "ov5640",
+	.sensor_reset_enable    = 1,
+	.sensor_reset	   = QRD_GPIO_CAM_5MP_RESET,
+	.sensor_pwd	     = QRD_GPIO_CAM_5MP_SHDN_EN,
+	.vcm_pwd		= 0,
+	.vcm_enable	     = 0,
+	.pdata			= &msm_camera_device_data_rear,
+	.flash_data	     = &flash_ov5640,
+	.sensor_platform_info   = &ov5640_sensor_info,
+	.csi_if		 = 1,
+};
+
+static struct platform_device msm_camera_sensor_ov5640 = {
+	.name   = "msm_camera_ov5640",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_ov5640_data,
+	},
+};
+#endif
+
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+static struct msm_camera_sensor_platform_info ov7692_sensor_7627a_info = {
+	.mount_angle = 90
+};
+
+static struct msm_camera_sensor_flash_data flash_ov7692 = {
+	.flash_type     = MSM_CAMERA_FLASH_NONE,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
+	.sensor_name	    = "ov7692",
+	.sensor_reset_enable    = 0,
+	.sensor_reset	   = 0,
+	.sensor_pwd	     = QRD_GPIO_CAM_3MP_PWDN,
+	.vcm_pwd		= 0,
+	.vcm_enable	     = 0,
+	.pdata			= &msm_camera_device_data_front,
+	.flash_data	     = &flash_ov7692,
+	.sensor_platform_info   = &ov7692_sensor_7627a_info,
+	.csi_if		 = 1,
+};
+
+static struct platform_device msm_camera_sensor_ov7692 = {
+	.name   = "msm_camera_ov7692",
+	.dev    = {
+		.platform_data = &msm_camera_sensor_ov7692_data,
+	},
+};
+#endif
+
+enum {
+	SX150X_CAM,
+};
+
+static struct sx150x_platform_data sx150x_data[] __initdata = {
+	[SX150X_CAM]    = {
+		.gpio_base	      = GPIO_CAM_EXPANDER_BASE,
+		.oscio_is_gpo	   = false,
+		.io_pullup_ena	  = 0,
+		.io_pulldn_ena	  = 0,
+		.io_open_drain_ena      = 0x23,
+		.irq_summary	    = -1,
+	},
+};
+
+static struct i2c_board_info cam_exp_i2c_info[] __initdata = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data  = &sx150x_data[SX150X_CAM],
+	},
+};
+
+static struct i2c_board_info i2c_camera_devices[] = {
+	#ifdef CONFIG_S5K4E1
+	{
+		I2C_BOARD_INFO("s5k4e1", 0x36),
+	},
+	{
+		I2C_BOARD_INFO("s5k4e1_af", 0x8c >> 1),
+	},
+	#endif
+	#ifdef CONFIG_WEBCAM_OV9726
+	{
+		I2C_BOARD_INFO("ov9726", 0x10),
+	},
+	#endif
+	#ifdef CONFIG_IMX072
+	{
+		I2C_BOARD_INFO("imx072", 0x34),
+	},
+	#endif
+	#ifdef CONFIG_MT9E013
+	{
+		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
+	},
+	#endif
+	{
+		I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+};
+
+static struct i2c_board_info i2c_camera_devices_qrd[] = {
+	#ifdef CONFIG_OV5640
+	{
+		I2C_BOARD_INFO("ov5640", 0x78 >> 1),
+	},
+	#endif
+	#ifdef CONFIG_WEBCAM_OV7692_QRD
+	{
+		I2C_BOARD_INFO("ov7692", 0x78),
+	},
+	#endif
+};
+
+static struct platform_device *camera_devices_msm[] __initdata = {
+#ifdef CONFIG_S5K4E1
+	&msm_camera_sensor_s5k4e1,
+#endif
+#ifdef CONFIG_IMX072
+	&msm_camera_sensor_imx072,
+#endif
+#ifdef CONFIG_WEBCAM_OV9726
+	&msm_camera_sensor_ov9726,
+#endif
+#ifdef CONFIG_MT9E013
+	&msm_camera_sensor_mt9e013,
+#endif
+};
+
+static struct platform_device *camera_devices_qrd[] __initdata = {
+#ifdef CONFIG_OV5640
+	&msm_camera_sensor_ov5640,
+#endif
+#ifdef CONFIG_WEBCAM_OV7692_QRD
+	&msm_camera_sensor_ov7692,
+#endif
+};
+
+static void __init register_i2c_devices(void)
+{
+	i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+				cam_exp_i2c_info,
+				ARRAY_SIZE(cam_exp_i2c_info));
+}
+
+void __init msm7627a_camera_init(void)
+{
+	int rc;
+
+	if (machine_is_msm7627a_qrd1()) {
+		qrd1_camera_gpio_cfg();
+		platform_add_devices(camera_devices_qrd,
+				ARRAY_SIZE(camera_devices_qrd));
+	} else
+		platform_add_devices(camera_devices_msm,
+				ARRAY_SIZE(camera_devices_msm));
+
+	if (!machine_is_msm7627a_qrd1())
+		register_i2c_devices();
+
+	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
+
+	if (rc) {
+		pr_err("%s: could not get regulators: %d\n", __func__, rc);
+		return;
+	}
+
+	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
+
+	if (rc) {
+		pr_err("%s: could not set voltages: %d\n", __func__, rc);
+		return;
+	}
+
+	if (machine_is_msm7627a_qrd1())
+		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+				i2c_camera_devices_qrd,
+				ARRAY_SIZE(i2c_camera_devices_qrd));
+	else
+		i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
+				i2c_camera_devices,
+				ARRAY_SIZE(i2c_camera_devices));
+}
diff --git a/arch/arm/mach-msm/board-msm7627a.h b/arch/arm/mach-msm/board-msm7627a.h
index 4680a31..7d7da4f 100644
--- a/arch/arm/mach-msm/board-msm7627a.h
+++ b/arch/arm/mach-msm/board-msm7627a.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
@@ -15,6 +15,53 @@
 
 void __init msm7627a_init_mmc(void);
 
+enum {
+	GPIO_EXPANDER_IRQ_BASE  = NR_MSM_IRQS + NR_GPIO_IRQS,
+	GPIO_EXPANDER_GPIO_BASE = NR_MSM_GPIOS,
+	/* SURF expander */
+	GPIO_CORE_EXPANDER_BASE = GPIO_EXPANDER_GPIO_BASE,
+	GPIO_BT_SYS_REST_EN     = GPIO_CORE_EXPANDER_BASE,
+	GPIO_WLAN_EXT_POR_N,
+	GPIO_DISPLAY_PWR_EN,
+	GPIO_BACKLIGHT_EN,
+	GPIO_PRESSURE_XCLR,
+	GPIO_VREG_S3_EXP,
+	GPIO_UBM2M_PWRDWN,
+	GPIO_ETM_MODE_CS_N,
+	GPIO_HOST_VBUS_EN,
+	GPIO_SPI_MOSI,
+	GPIO_SPI_MISO,
+	GPIO_SPI_CLK,
+	GPIO_SPI_CS0_N,
+	GPIO_CORE_EXPANDER_IO13,
+	GPIO_CORE_EXPANDER_IO14,
+	GPIO_CORE_EXPANDER_IO15,
+	/* Camera expander */
+	GPIO_CAM_EXPANDER_BASE  = GPIO_CORE_EXPANDER_BASE + 16,
+	GPIO_CAM_GP_STROBE_READY	= GPIO_CAM_EXPANDER_BASE,
+	GPIO_CAM_GP_AFBUSY,
+	GPIO_CAM_GP_CAM_PWDN,
+	GPIO_CAM_GP_CAM1MP_XCLR,
+	GPIO_CAM_GP_CAMIF_RESET_N,
+	GPIO_CAM_GP_STROBE_CE,
+	GPIO_CAM_GP_LED_EN1,
+	GPIO_CAM_GP_LED_EN2,
+};
+
+enum {
+	QRD_GPIO_HOST_VBUS_EN       = 107,
+	QRD_GPIO_BT_SYS_REST_EN     = 114,
+	QRD_GPIO_WAKE_ON_WIRELESS,
+	QRD_GPIO_BACKLIGHT_EN,
+	QRD_GPIO_NC,
+	QRD_GPIO_CAM_3MP_PWDN,      /* CAM_VGA */
+	QRD_GPIO_WLAN_EN,
+	QRD_GPIO_CAM_5MP_SHDN_EN,
+	QRD_GPIO_CAM_5MP_RESET,
+	QRD_GPIO_TP,
+	QRD_GPIO_CAM_GP_CAMIF_RESET,
+};
+
 #if defined(CONFIG_BT) && defined(CONFIG_MARIMBA_CORE)
 
 #define FPGA_MSM_CNTRL_REG2 0x90008010
@@ -30,7 +77,7 @@
 #define FM_I2S_WS_MODE    0x8F
 #define FM_I2S_SCK_MODE   0x90
 #define I2C_PIN_CTL       0x15
-#define I2C_NORMAL        0x40
+#define I2C_NORMAL	  0x40
 
 struct bahama_config_register {
 	u8 reg;
@@ -52,4 +99,6 @@
 void __init msm7627a_bt_power_init(void);
 #endif
 
+void __init msm7627a_camera_init(void);
+
 #endif
diff --git a/arch/arm/mach-msm/board-msm7x27.c b/arch/arm/mach-msm/board-msm7x27.c
index e84417c..9385a58 100644
--- a/arch/arm/mach-msm/board-msm7x27.c
+++ b/arch/arm/mach-msm/board-msm7x27.c
@@ -68,7 +68,7 @@
 #include "clock.h"
 #include "acpuclock.h"
 #include "msm-keypad-devices.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "pm-boot.h"
 
 #ifdef CONFIG_ARCH_MSM7X25
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 9a6f1e1..5bcd749 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -49,7 +49,7 @@
 #include "timer.h"
 #include "board-msm7x27a-regulator.h"
 #include "devices-msm7x2xa.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include <mach/rpc_server_handset.h>
 #include <mach/socinfo.h>
 #include "pm-boot.h"
@@ -58,43 +58,9 @@
 #define PMEM_KERNEL_EBI1_SIZE	0x3A000
 #define MSM_PMEM_AUDIO_SIZE	0x5B000
 
-enum {
-	GPIO_EXPANDER_IRQ_BASE	= NR_MSM_IRQS + NR_GPIO_IRQS,
-	GPIO_EXPANDER_GPIO_BASE	= NR_MSM_GPIOS,
-	/* SURF expander */
-	GPIO_CORE_EXPANDER_BASE	= GPIO_EXPANDER_GPIO_BASE,
-	GPIO_BT_SYS_REST_EN	= GPIO_CORE_EXPANDER_BASE,
-	GPIO_WLAN_EXT_POR_N,
-	GPIO_DISPLAY_PWR_EN,
-	GPIO_BACKLIGHT_EN,
-	GPIO_PRESSURE_XCLR,
-	GPIO_VREG_S3_EXP,
-	GPIO_UBM2M_PWRDWN,
-	GPIO_ETM_MODE_CS_N,
-	GPIO_HOST_VBUS_EN,
-	GPIO_SPI_MOSI,
-	GPIO_SPI_MISO,
-	GPIO_SPI_CLK,
-	GPIO_SPI_CS0_N,
-	GPIO_CORE_EXPANDER_IO13,
-	GPIO_CORE_EXPANDER_IO14,
-	GPIO_CORE_EXPANDER_IO15,
-	/* Camera expander */
-	GPIO_CAM_EXPANDER_BASE	= GPIO_CORE_EXPANDER_BASE + 16,
-	GPIO_CAM_GP_STROBE_READY	= GPIO_CAM_EXPANDER_BASE,
-	GPIO_CAM_GP_AFBUSY,
-	GPIO_CAM_GP_CAM_PWDN,
-	GPIO_CAM_GP_CAM1MP_XCLR,
-	GPIO_CAM_GP_CAMIF_RESET_N,
-	GPIO_CAM_GP_STROBE_CE,
-	GPIO_CAM_GP_LED_EN1,
-	GPIO_CAM_GP_LED_EN2,
-};
-
 #if defined(CONFIG_GPIO_SX150X)
 enum {
 	SX150X_CORE,
-	SX150X_CAM,
 };
 
 static struct sx150x_platform_data sx150x_data[] __initdata = {
@@ -106,14 +72,6 @@
 		.io_open_drain_ena	= 0xfef8,
 		.irq_summary		= -1,
 	},
-	[SX150X_CAM]	= {
-		.gpio_base		= GPIO_CAM_EXPANDER_BASE,
-		.oscio_is_gpo		= false,
-		.io_pullup_ena		= 0,
-		.io_pulldn_ena		= 0,
-		.io_open_drain_ena	= 0x23,
-		.irq_summary		= -1,
-	},
 };
 #endif
 
@@ -129,22 +87,9 @@
 		I2C_BOARD_INFO("sx1509q", 0x3e),
 	},
 };
-static struct i2c_board_info cam_exp_i2c_info[] __initdata = {
-	{
-		I2C_BOARD_INFO("sx1508q", 0x22),
-		.platform_data	= &sx150x_data[SX150X_CAM],
-	},
-};
-#endif
 
-#if defined(CONFIG_I2C) && defined(CONFIG_GPIO_SX150X)
 static void __init register_i2c_devices(void)
 {
-
-	i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
-				cam_exp_i2c_info,
-				ARRAY_SIZE(cam_exp_i2c_info));
-
 	if (machine_is_msm7x27a_surf() || machine_is_msm7625a_surf())
 		sx150x_data[SX150X_CORE].io_open_drain_ena = 0xe0f0;
 
@@ -209,7 +154,7 @@
 #define MSM_PMEM_MDP_SIZE       0x2300000
 #define MSM7x25A_MSM_PMEM_MDP_SIZE       0x1500000
 
-#define MSM_PMEM_ADSP_SIZE      0x1000000
+#define MSM_PMEM_ADSP_SIZE      0x1100000
 #define MSM7x25A_MSM_PMEM_ADSP_SIZE      0xB91000
 
 
@@ -953,311 +898,6 @@
 	gpio_set_value(ETH_FIFO_SEL_GPIO, 0);
 }
 
-#ifdef CONFIG_MSM_CAMERA
-static uint32_t camera_off_gpio_table[] = {
-	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static uint32_t camera_on_gpio_table[] = {
-	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-#ifdef CONFIG_MSM_CAMERA_FLASH
-static struct msm_camera_sensor_flash_src msm_flash_src = {
-	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
-	._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
-	._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
-};
-#endif
-
-static struct regulator_bulk_data regs_camera[] = {
-	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
-	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
-	{ .supply = "usb2",  .min_uV = 1800000, .max_uV = 1800000 },
-};
-
-static void __init msm_camera_vreg_init(void)
-{
-	int rc;
-
-	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
-
-	if (rc) {
-		pr_err("%s: could not get regulators: %d\n", __func__, rc);
-		return;
-	}
-
-	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
-
-	if (rc) {
-		pr_err("%s: could not set voltages: %d\n", __func__, rc);
-		return;
-	}
-}
-
-static void msm_camera_vreg_config(int vreg_en)
-{
-	int rc = vreg_en ?
-		regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
-		regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
-
-	if (rc)
-		pr_err("%s: could not %sable regulators: %d\n",
-				__func__, vreg_en ? "en" : "dis", rc);
-}
-
-static int config_gpio_table(uint32_t *table, int len)
-{
-	int rc = 0, i = 0;
-
-	for (i = 0; i < len; i++) {
-		rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
-		if (rc) {
-			pr_err("%s not able to get gpio\n", __func__);
-			for (i--; i >= 0; i--)
-				gpio_tlmm_config(camera_off_gpio_table[i],
-							GPIO_CFG_ENABLE);
-			break;
-		}
-	}
-	return rc;
-}
-
-static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data;
-static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data;
-static int config_camera_on_gpios_rear(void)
-{
-	int rc = 0;
-
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(1);
-
-	rc = config_gpio_table(camera_on_gpio_table,
-			ARRAY_SIZE(camera_on_gpio_table));
-	if (rc < 0) {
-		pr_err("%s: CAMSENSOR gpio table request"
-		"failed\n", __func__);
-		return rc;
-	}
-
-	return rc;
-}
-
-static void config_camera_off_gpios_rear(void)
-{
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(0);
-
-	config_gpio_table(camera_off_gpio_table,
-			ARRAY_SIZE(camera_off_gpio_table));
-}
-
-static int config_camera_on_gpios_front(void)
-{
-	int rc = 0;
-
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(1);
-
-	rc = config_gpio_table(camera_on_gpio_table,
-			ARRAY_SIZE(camera_on_gpio_table));
-	if (rc < 0) {
-		pr_err("%s: CAMSENSOR gpio table request"
-			"failed\n", __func__);
-		return rc;
-	}
-
-	return rc;
-}
-
-static void config_camera_off_gpios_front(void)
-{
-	if (machine_is_msm7x27a_ffa() || machine_is_msm7625a_ffa())
-		msm_camera_vreg_config(0);
-
-	config_gpio_table(camera_off_gpio_table,
-			ARRAY_SIZE(camera_off_gpio_table));
-}
-
-struct msm_camera_device_platform_data msm_camera_device_data_rear = {
-	.camera_gpio_on  = config_camera_on_gpios_rear,
-	.camera_gpio_off = config_camera_off_gpios_rear,
-	.ioext.csiphy = 0xA1000000,
-	.ioext.csisz  = 0x00100000,
-	.ioext.csiirq = INT_CSI_IRQ_1,
-	.ioclk.mclk_clk_rate = 24000000,
-	.ioclk.vfe_clk_rate  = 192000000,
-	.ioext.appphy = MSM_CLK_CTL_PHYS,
-	.ioext.appsz  = MSM_CLK_CTL_SIZE,
-};
-
-struct msm_camera_device_platform_data msm_camera_device_data_front = {
-	.camera_gpio_on  = config_camera_on_gpios_front,
-	.camera_gpio_off = config_camera_off_gpios_front,
-	.ioext.csiphy = 0xA0F00000,
-	.ioext.csisz  = 0x00100000,
-	.ioext.csiirq = INT_CSI_IRQ_0,
-	.ioclk.mclk_clk_rate = 24000000,
-	.ioclk.vfe_clk_rate  = 192000000,
-	.ioext.appphy = MSM_CLK_CTL_PHYS,
-	.ioext.appsz  = MSM_CLK_CTL_SIZE,
-};
-
-#ifdef CONFIG_S5K4E1
-static struct msm_camera_sensor_platform_info s5k4e1_sensor_7627a_info = {
-	.mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_s5k4e1 = {
-	.flash_type             = MSM_CAMERA_FLASH_LED,
-	.flash_src              = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_s5k4e1_data = {
-	.sensor_name    = "s5k4e1",
-	.sensor_reset_enable = 1,
-	.sensor_reset   = GPIO_CAM_GP_CAMIF_RESET_N,
-	.sensor_pwd             = 85,
-	.vcm_pwd                = GPIO_CAM_GP_CAM_PWDN,
-	.vcm_enable             = 1,
-	.pdata                  = &msm_camera_device_data_rear,
-	.flash_data             = &flash_s5k4e1,
-	.sensor_platform_info   = &s5k4e1_sensor_7627a_info,
-	.csi_if                 = 1
-};
-
-static struct platform_device msm_camera_sensor_s5k4e1 = {
-	.name   = "msm_camera_s5k4e1",
-	.dev    = {
-		.platform_data = &msm_camera_sensor_s5k4e1_data,
-	},
-};
-#endif
-
-#ifdef CONFIG_IMX072
-static struct msm_camera_sensor_platform_info imx072_sensor_7627a_info = {
-	.mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_imx072 = {
-	.flash_type             = MSM_CAMERA_FLASH_LED,
-	.flash_src              = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_imx072_data = {
-	.sensor_name    = "imx072",
-	.sensor_reset_enable = 1,
-	.sensor_reset   = GPIO_CAM_GP_CAMIF_RESET_N, /* TODO 106,*/
-	.sensor_pwd             = 85,
-	.vcm_pwd                = GPIO_CAM_GP_CAM_PWDN,
-	.vcm_enable             = 1,
-	.pdata                  = &msm_camera_device_data_rear,
-	.flash_data             = &flash_imx072,
-	.sensor_platform_info = &imx072_sensor_7627a_info,
-	.csi_if                 = 1
-};
-
-static struct platform_device msm_camera_sensor_imx072 = {
-	.name   = "msm_camera_imx072",
-	.dev    = {
-		.platform_data = &msm_camera_sensor_imx072_data,
-	},
-};
-#endif
-
-#ifdef CONFIG_WEBCAM_OV9726
-static struct msm_camera_sensor_platform_info ov9726_sensor_7627a_info = {
-	.mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_ov9726 = {
-	.flash_type             = MSM_CAMERA_FLASH_NONE,
-	.flash_src              = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_ov9726_data = {
-	.sensor_name    = "ov9726",
-	.sensor_reset_enable = 0,
-	.sensor_reset   = GPIO_CAM_GP_CAM1MP_XCLR,
-	.sensor_pwd             = 85,
-	.vcm_pwd                = 1,
-	.vcm_enable             = 0,
-	.pdata                  = &msm_camera_device_data_front,
-	.flash_data             = &flash_ov9726,
-	.sensor_platform_info   = &ov9726_sensor_7627a_info,
-	.csi_if                 = 1
-};
-
-static struct platform_device msm_camera_sensor_ov9726 = {
-	.name   = "msm_camera_ov9726",
-	.dev    = {
-		.platform_data = &msm_camera_sensor_ov9726_data,
-	},
-};
-#else
-static inline void msm_camera_vreg_init(void) { }
-#endif
-
-#ifdef CONFIG_MT9E013
-static struct msm_camera_sensor_platform_info mt9e013_sensor_7627a_info = {
-	.mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_mt9e013 = {
-	.flash_type = MSM_CAMERA_FLASH_LED,
-	.flash_src  = &msm_flash_src
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_mt9e013_data = {
-	.sensor_name    = "mt9e013",
-	.sensor_reset   = 0,
-	.sensor_reset_enable = 1,
-	.sensor_pwd     = 85,
-	.vcm_pwd        = 1,
-	.vcm_enable     = 0,
-	.pdata          = &msm_camera_device_data_rear,
-	.flash_data     = &flash_mt9e013,
-	.sensor_platform_info   = &mt9e013_sensor_7627a_info,
-	.csi_if         = 1
-};
-
-static struct platform_device msm_camera_sensor_mt9e013 = {
-	.name      = "msm_camera_mt9e013",
-	.dev       = {
-		.platform_data = &msm_camera_sensor_mt9e013_data,
-	},
-};
-#endif
-
-static struct i2c_board_info i2c_camera_devices[] = {
-	#ifdef CONFIG_S5K4E1
-	{
-		I2C_BOARD_INFO("s5k4e1", 0x36),
-	},
-	{
-		I2C_BOARD_INFO("s5k4e1_af", 0x8c >> 1),
-	},
-	#endif
-	#ifdef CONFIG_WEBCAM_OV9726
-	{
-		I2C_BOARD_INFO("ov9726", 0x10),
-	},
-	#endif
-	#ifdef CONFIG_IMX072
-	{
-		I2C_BOARD_INFO("imx072", 0x34),
-	},
-	#endif
-	#ifdef CONFIG_MT9E013
-	{
-		I2C_BOARD_INFO("mt9e013", 0x6C >> 2),
-	},
-	#endif
-	{
-		I2C_BOARD_INFO("sc628a", 0x6E),
-	},
-};
-#endif
 #if defined(CONFIG_SERIAL_MSM_HSL_CONSOLE) \
 		&& defined(CONFIG_MSM_SHARED_GPIO_FOR_UART2DM)
 static struct msm_gpio uart2dm_gpios[] = {
@@ -1315,18 +955,6 @@
 	&lcdc_toshiba_panel_device,
 	&msm_batt_device,
 	&smsc911x_device,
-#ifdef CONFIG_S5K4E1
-	&msm_camera_sensor_s5k4e1,
-#endif
-#ifdef CONFIG_IMX072
-	&msm_camera_sensor_imx072,
-#endif
-#ifdef CONFIG_WEBCAM_OV9726
-	&msm_camera_sensor_ov9726,
-#endif
-#ifdef CONFIG_MT9E013
-	&msm_camera_sensor_mt9e013,
-#endif
 #ifdef CONFIG_FB_MSM_MIPI_DSI
 	&mipi_dsi_renesas_panel_device,
 #endif
@@ -1595,6 +1223,8 @@
 					__func__, rc);
 			goto fail_vreg;
 		}
+		if (pmapp_disp_backlight_set_brightness(100))
+			pr_err("backlight set brightness failed\n");
 
 		dsi_gpio_initialized = 1;
 	}
@@ -1638,9 +1268,6 @@
 			msleep(20);
 			gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1);
 		}
-
-		if (pmapp_disp_backlight_set_brightness(100))
-			pr_err("backlight set brightness failed\n");
 	} else {
 		gpio_set_value_cansleep(GPIO_LCDC_BRDG_PD, 1);
 
@@ -2027,10 +1654,7 @@
 		ARRAY_SIZE(atmel_ts_i2c_info));
 
 #if defined(CONFIG_MSM_CAMERA)
-	msm_camera_vreg_init();
-	i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID,
-			i2c_camera_devices,
-			ARRAY_SIZE(i2c_camera_devices));
+	msm7627a_camera_init();
 #endif
 	platform_device_register(&kp_pdev);
 	platform_device_register(&hs_pdev);
diff --git a/arch/arm/mach-msm/board-msm7x30.c b/arch/arm/mach-msm/board-msm7x30.c
index a3f9ccd..bd570cf 100644
--- a/arch/arm/mach-msm/board-msm7x30.c
+++ b/arch/arm/mach-msm/board-msm7x30.c
@@ -78,7 +78,7 @@
 #include <linux/usb/android.h>
 #include <mach/usbdiag.h>
 #endif
-#include "pm.h"
+#include <mach/pm.h>
 #include "pm-boot.h"
 #include "spm.h"
 #include "acpuclock.h"
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 11b70ee..df04bb2 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -88,8 +88,8 @@
 
 #include "devices.h"
 #include "devices-msm8x60.h"
-#include "cpuidle.h"
-#include "pm.h"
+#include <mach/cpuidle.h>
+#include <mach/pm.h>
 #include "mpm.h"
 #include "spm.h"
 #include "rpm_log.h"
@@ -5239,6 +5239,28 @@
 };
 
 #ifdef CONFIG_ION_MSM
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+static struct ion_cp_heap_pdata cp_mm_ion_pdata = {
+	.permission_type = IPT_TYPE_MM_CARVEOUT,
+	.request_region = request_smi_region,
+	.release_region = release_smi_region,
+	.setup_region = setup_smi_region,
+};
+
+static struct ion_cp_heap_pdata cp_mfc_ion_pdata = {
+	.permission_type = IPT_TYPE_MFC_SHAREDMEM,
+	.request_region = request_smi_region,
+	.release_region = release_smi_region,
+	.setup_region = setup_smi_region,
+};
+
+static struct ion_cp_heap_pdata cp_wb_ion_pdata = {
+	.permission_type = IPT_TYPE_MDP_WRITEBACK,
+};
+
+static struct ion_co_heap_pdata co_ion_pdata = {
+};
+#endif
 static struct ion_platform_data ion_pdata = {
 	.nr = MSM_ION_HEAP_NUM,
 	.heaps = {
@@ -5254,16 +5276,15 @@
 			.name	= ION_SF_HEAP_NAME,
 			.size	= MSM_ION_SF_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = &co_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MM_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MM_HEAP_NAME,
 			.size	= MSM_ION_MM_SIZE,
 			.memory_type = ION_SMI_TYPE,
-			.request_region = request_smi_region,
-			.release_region = release_smi_region,
-			.setup_region = setup_smi_region,
+			.extra_data = (void *) &cp_mm_ion_pdata,
 		},
 		{
 			.id	= ION_CAMERA_HEAP_ID,
@@ -5271,23 +5292,23 @@
 			.name	= ION_CAMERA_HEAP_NAME,
 			.size	= MSM_ION_CAMERA_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = &co_ion_pdata,
 		},
 		{
 			.id	= ION_CP_MFC_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_MFC_HEAP_NAME,
 			.size	= MSM_ION_MFC_SIZE,
 			.memory_type = ION_SMI_TYPE,
-			.request_region = request_smi_region,
-			.release_region = release_smi_region,
-			.setup_region = setup_smi_region,
+			.extra_data = (void *) &cp_mfc_ion_pdata,
 		},
 		{
 			.id	= ION_CP_WB_HEAP_ID,
-			.type	= ION_HEAP_TYPE_CARVEOUT,
+			.type	= ION_HEAP_TYPE_CP,
 			.name	= ION_WB_HEAP_NAME,
 			.size	= MSM_ION_WB_SIZE,
 			.memory_type = ION_EBI_TYPE,
+			.extra_data = (void *) &cp_wb_ion_pdata,
 		},
 #endif
 	}
diff --git a/arch/arm/mach-msm/board-qrd7627a.c b/arch/arm/mach-msm/board-qrd7627a.c
index 8a7fe5b..9d4818a 100644
--- a/arch/arm/mach-msm/board-qrd7627a.c
+++ b/arch/arm/mach-msm/board-qrd7627a.c
@@ -48,7 +48,7 @@
 #include "board-msm7x27a-regulator.h"
 #include "devices.h"
 #include "devices-msm7x2xa.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "timer.h"
 #include "pm-boot.h"
 #include "board-msm7x27a-regulator.h"
@@ -68,20 +68,6 @@
 #define I2C_PIN_CTL       0x15
 #define I2C_NORMAL        0x40
 
-enum {
-	GPIO_HOST_VBUS_EN	= 107,
-	GPIO_BT_SYS_REST_EN	= 114,
-	GPIO_WAKE_ON_WIRELESS,
-	GPIO_BACKLIGHT_EN,
-	GPIO_NC,
-	GPIO_CAM_3MP_PWDN,	/* CAM_VGA */
-	GPIO_WLAN_EN,
-	GPIO_CAM_5MP_SHDN_EN,
-	GPIO_CAM_5MP_RESET,
-	GPIO_TP,
-	GPIO_CAM_GP_CAMIF_RESET,
-};
-
 static struct platform_device msm_wlan_ar6000_pm_device = {
 	.name           = "wlan_ar6000_pm_dev",
 	.id             = -1,
@@ -295,7 +281,7 @@
 	int rc = 0;
 	unsigned gpio;
 
-	gpio = GPIO_HOST_VBUS_EN;
+	gpio = QRD_GPIO_HOST_VBUS_EN;
 
 	rc = gpio_request(gpio,	"i2c_host_vbus_en");
 	if (rc < 0) {
@@ -517,7 +503,7 @@
 
 static int mipi_truly_set_bl(int on)
 {
-	gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, !!on);
+	gpio_set_value_cansleep(QRD_GPIO_BACKLIGHT_EN, !!on);
 
 	return 1;
 }
@@ -739,275 +725,6 @@
 	.dev.platform_data  = &msm_psy_batt_data,
 };
 
-#ifdef CONFIG_MSM_CAMERA
-static uint32_t camera_off_gpio_table[] = {
-	GPIO_CFG(15, 0, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static uint32_t camera_on_gpio_table[] = {
-	GPIO_CFG(15, 1, GPIO_CFG_OUTPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
-};
-
-static void qrd1_camera_gpio_cfg(void)
-{
-
-	int rc = 0;
-
-	rc = gpio_request(GPIO_CAM_5MP_SHDN_EN, "ov5640");
-	if (rc < 0)
-		pr_err("%s: gpio_request---GPIO_CAM_5MP_SHDN_EN failed!",
-				__func__);
-
-
-	rc = gpio_tlmm_config(GPIO_CFG(GPIO_CAM_5MP_SHDN_EN, 0,
-				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
-				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-	if (rc < 0) {
-		pr_err("%s: unable to enable Power Down gpio for main"
-				"camera!\n", __func__);
-		gpio_free(GPIO_CAM_5MP_SHDN_EN);
-	}
-
-
-	rc = gpio_request(GPIO_CAM_5MP_RESET, "ov5640");
-	if (rc < 0) {
-		pr_err("%s: gpio_request---GPIO_CAM_5MP_RESET failed!",
-				__func__);
-		gpio_free(GPIO_CAM_5MP_SHDN_EN);
-	}
-
-
-	rc = gpio_tlmm_config(GPIO_CFG(GPIO_CAM_5MP_RESET, 0,
-				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
-				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-	if (rc < 0) {
-		pr_err("%s: unable to enable reset gpio for main camera!\n",
-				__func__);
-		gpio_free(GPIO_CAM_5MP_RESET);
-	}
-
-	rc = gpio_request(GPIO_CAM_3MP_PWDN, "ov7692");
-	if (rc < 0)
-		pr_err("%s: gpio_request---GPIO_CAM_3MP_PWDN failed!",
-				__func__);
-
-	rc = gpio_tlmm_config(GPIO_CFG(GPIO_CAM_3MP_PWDN, 0,
-				GPIO_CFG_OUTPUT, GPIO_CFG_PULL_UP,
-				GPIO_CFG_2MA), GPIO_CFG_ENABLE);
-	if (rc < 0) {
-		pr_err("%s: unable to enable Power Down gpio for front"
-				"camera!\n", __func__);
-		gpio_free(GPIO_CAM_3MP_PWDN);
-	}
-
-	gpio_direction_output(GPIO_CAM_5MP_SHDN_EN, 1);
-	gpio_direction_output(GPIO_CAM_5MP_RESET, 1);
-	gpio_direction_output(GPIO_CAM_3MP_PWDN, 1);
-}
-
-#endif
-static struct regulator_bulk_data regs_camera[] = {
-	{ .supply = "msme1", .min_uV = 1800000, .max_uV = 1800000 },
-	{ .supply = "gp2",   .min_uV = 2850000, .max_uV = 2850000 },
-	{ .supply = "usb2",  .min_uV = 1800000, .max_uV = 1800000 },
-};
-
-static void __init msm_camera_vreg_init(void)
-{
-	int rc;
-
-	rc = regulator_bulk_get(NULL, ARRAY_SIZE(regs_camera), regs_camera);
-	if (rc) {
-		pr_err("%s: could not get regulators: %d\n", __func__, rc);
-		return;
-	}
-
-	rc = regulator_bulk_set_voltage(ARRAY_SIZE(regs_camera), regs_camera);
-	if (rc) {
-		pr_err("%s: could not set voltages: %d\n", __func__, rc);
-		return;
-	}
-}
-
-static void msm_camera_vreg_config(int vreg_en)
-{
-	int rc = vreg_en ?
-		regulator_bulk_enable(ARRAY_SIZE(regs_camera), regs_camera) :
-		regulator_bulk_disable(ARRAY_SIZE(regs_camera), regs_camera);
-
-	if (rc)
-		pr_err("%s: could not %sable regulators: %d\n",
-				__func__, vreg_en ? "en" : "dis", rc);
-}
-static int config_gpio_table(uint32_t *table, int len)
-{
-	int rc = 0, i = 0;
-
-	for (i = 0; i < len; i++) {
-		rc = gpio_tlmm_config(table[i], GPIO_CFG_ENABLE);
-		if (rc) {
-			pr_err("%s not able to get gpio\n", __func__);
-			for (i--; i >= 0; i--)
-				gpio_tlmm_config(camera_off_gpio_table[i],
-							GPIO_CFG_ENABLE);
-			break;
-		}
-	}
-	return rc;
-}
-
-static int config_camera_on_gpios_rear(void)
-{
-	int rc = 0;
-
-	msm_camera_vreg_config(1);
-
-	rc = config_gpio_table(camera_on_gpio_table,
-			ARRAY_SIZE(camera_on_gpio_table));
-	if (rc < 0) {
-		pr_err("%s: CAMSENSOR gpio table request"
-		"failed\n", __func__);
-		return rc;
-	}
-
-	return rc;
-}
-
-static void config_camera_off_gpios_rear(void)
-{
-	msm_camera_vreg_config(0);
-	config_gpio_table(camera_off_gpio_table,
-			ARRAY_SIZE(camera_off_gpio_table));
-}
-
-static int config_camera_on_gpios_front(void)
-{
-	int rc = 0;
-
-	msm_camera_vreg_config(1);
-
-	rc = config_gpio_table(camera_on_gpio_table,
-			ARRAY_SIZE(camera_on_gpio_table));
-	if (rc < 0) {
-		pr_err("%s: CAMSENSOR gpio table request"
-			"failed\n", __func__);
-		return rc;
-	}
-
-	return rc;
-}
-
-static void config_camera_off_gpios_front(void)
-{
-	msm_camera_vreg_config(0);
-
-	config_gpio_table(camera_off_gpio_table,
-			ARRAY_SIZE(camera_off_gpio_table));
-}
-
-struct msm_camera_device_platform_data msm_camera_data_rear = {
-	.camera_gpio_on		= config_camera_on_gpios_rear,
-	.camera_gpio_off	= config_camera_off_gpios_rear,
-	.ioext.csiphy		= 0xA1000000,
-	.ioext.csisz		= 0x00100000,
-	.ioext.csiirq		= INT_CSI_IRQ_1,
-	.ioclk.mclk_clk_rate	= 24000000,
-	.ioclk.vfe_clk_rate	= 192000000,
-	.ioext.appphy		= MSM_CLK_CTL_PHYS,
-	.ioext.appsz		= MSM_CLK_CTL_SIZE,
-};
-
-struct msm_camera_device_platform_data msm_camera_data_front = {
-	.camera_gpio_on		= config_camera_on_gpios_front,
-	.camera_gpio_off	= config_camera_off_gpios_front,
-	.ioext.csiphy		= 0xA0F00000,
-	.ioext.csisz		= 0x00100000,
-	.ioext.csiirq		= INT_CSI_IRQ_0,
-	.ioclk.mclk_clk_rate	= 24000000,
-	.ioclk.vfe_clk_rate	= 192000000,
-	.ioext.appphy		= MSM_CLK_CTL_PHYS,
-	.ioext.appsz		= MSM_CLK_CTL_SIZE,
-};
-
-#ifdef CONFIG_OV5640
-static struct msm_camera_sensor_platform_info ov5640_sensor_info = {
-	.mount_angle	= 90
-};
-
-static struct msm_camera_sensor_flash_src msm_flash_src_ov5640 = {
-	.flash_sr_type = MSM_CAMERA_FLASH_SRC_LED,
-	._fsrc.led_src.led_name = "flashlight",
-	._fsrc.led_src.led_name_len = 10,
-};
-
-static struct msm_camera_sensor_flash_data flash_ov5640 = {
-	.flash_type	= MSM_CAMERA_FLASH_LED,
-	.flash_src	= &msm_flash_src_ov5640,
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_ov5640_data = {
-	.sensor_name		= "ov5640",
-	.sensor_reset_enable	= 1,
-	.sensor_reset		= GPIO_CAM_5MP_RESET,
-	.sensor_pwd		= GPIO_CAM_5MP_SHDN_EN,
-	.vcm_pwd		= 0,
-	.vcm_enable		= 0,
-	.pdata			= &msm_camera_data_rear,
-	.flash_data		= &flash_ov5640,
-	.sensor_platform_info	= &ov5640_sensor_info,
-	.csi_if			= 1,
-};
-
-static struct platform_device msm_camera_sensor_ov5640 = {
-	.name	= "msm_camera_ov5640",
-	.dev	= {
-		.platform_data = &msm_camera_sensor_ov5640_data,
-	},
-};
-#endif
-
-#ifdef CONFIG_WEBCAM_OV7692_QRD
-static struct msm_camera_sensor_platform_info ov7692_sensor_7627a_info = {
-	.mount_angle = 90
-};
-
-static struct msm_camera_sensor_flash_data flash_ov7692 = {
-	.flash_type	= MSM_CAMERA_FLASH_NONE,
-};
-
-static struct msm_camera_sensor_info msm_camera_sensor_ov7692_data = {
-	.sensor_name		= "ov7692",
-	.sensor_reset_enable	= 0,
-	.sensor_reset		= 0,
-	.sensor_pwd		= GPIO_CAM_3MP_PWDN,
-	.vcm_pwd		= 0,
-	.vcm_enable		= 0,
-	.pdata			= &msm_camera_data_front,
-	.flash_data		= &flash_ov7692,
-	.sensor_platform_info   = &ov7692_sensor_7627a_info,
-	.csi_if			= 1,
-};
-
-static struct platform_device msm_camera_sensor_ov7692 = {
-	.name	= "msm_camera_ov7692",
-	.dev	= {
-		.platform_data = &msm_camera_sensor_ov7692_data,
-	},
-};
-#endif
-
-static struct i2c_board_info i2c_camera_devices[] = {
-	#ifdef CONFIG_OV5640
-	{
-		I2C_BOARD_INFO("ov5640", 0x78 >> 1),
-	},
-	#endif
-	#ifdef CONFIG_WEBCAM_OV7692_QRD
-	{
-		I2C_BOARD_INFO("ov7692", 0x78),
-	},
-	#endif
-};
 static struct platform_device *qrd1_devices[] __initdata = {
 	&msm_device_dmov,
 	&msm_device_smd,
@@ -1025,12 +742,6 @@
 	&msm_device_snd,
 	&msm_device_adspdec,
 	&msm_batt_device,
-#ifdef CONFIG_OV5640
-	&msm_camera_sensor_ov5640,
-#endif
-#ifdef CONFIG_WEBCAM_OV7692_QRD
-	&msm_camera_sensor_ov7692,
-#endif
 	&msm_kgsl_3d0,
 #ifdef CONFIG_BT
 	&msm_bt_power_device,
@@ -1183,11 +894,11 @@
 	int rc = 0;
 
 	if (!dsi_gpio_initialized) {
-		rc = gpio_request(GPIO_BACKLIGHT_EN, "gpio_bkl_en");
+		rc = gpio_request(QRD_GPIO_BACKLIGHT_EN, "gpio_bkl_en");
 		if (rc < 0)
 			return rc;
 
-		rc = gpio_tlmm_config(GPIO_CFG(GPIO_BACKLIGHT_EN, 0,
+		rc = gpio_tlmm_config(GPIO_CFG(QRD_GPIO_BACKLIGHT_EN, 0,
 			GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_2MA),
 			GPIO_CFG_ENABLE);
 		if (rc < 0) {
@@ -1195,16 +906,16 @@
 			return rc;
 		}
 
-		rc = gpio_direction_output(GPIO_BACKLIGHT_EN, 1);
+		rc = gpio_direction_output(QRD_GPIO_BACKLIGHT_EN, 1);
 		if (rc < 0) {
 			pr_err("failed to enable backlight\n");
-			gpio_free(GPIO_BACKLIGHT_EN);
+			gpio_free(QRD_GPIO_BACKLIGHT_EN);
 			return rc;
 		}
 		dsi_gpio_initialized = 1;
 	}
 
-	gpio_set_value_cansleep(GPIO_BACKLIGHT_EN, !!on);
+	gpio_set_value_cansleep(QRD_GPIO_BACKLIGHT_EN, !!on);
 
 	if (!on) {
 		gpio_set_value_cansleep(GPIO_LCDC_BRDG_RESET_N, 1);
@@ -1331,7 +1042,6 @@
 	msm7x2x_misc_init();
 	msm7627a_init_regulators();
 	msm_device_i2c_init();
-	qrd1_camera_gpio_cfg();
 #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;
@@ -1361,9 +1071,7 @@
 	msm7627a_bt_power_init();
 #endif
 
-	msm_camera_vreg_init();
-	i2c_register_board_info(MSM_GSBI0_QUP_I2C_BUS_ID, i2c_camera_devices,
-			ARRAY_SIZE(i2c_camera_devices));
+	msm7627a_camera_init();
 
 #if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C) || \
 	defined(CONFIG_TOUCHSCREEN_SYNAPTICS_RMI4_I2C_MODULE)
diff --git a/arch/arm/mach-msm/board-qsd8x50.c b/arch/arm/mach-msm/board-qsd8x50.c
index 5a77333..65aaa9a 100644
--- a/arch/arm/mach-msm/board-qsd8x50.c
+++ b/arch/arm/mach-msm/board-qsd8x50.c
@@ -54,7 +54,7 @@
 #include "timer.h"
 #include "msm-keypad-devices.h"
 #include "acpuclock.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "pm-boot.h"
 #include "proc_comm.h"
 #ifdef CONFIG_USB_ANDROID
diff --git a/arch/arm/mach-msm/clock-8960.c b/arch/arm/mach-msm/clock-8960.c
index 8152ff2..295c7d9 100644
--- a/arch/arm/mach-msm/clock-8960.c
+++ b/arch/arm/mach-msm/clock-8960.c
@@ -91,22 +91,6 @@
 #define BB_PLL14_STATUS_REG			REG(0x31D8)
 #define PLLTEST_PAD_CFG_REG			REG(0x2FA4)
 #define PMEM_ACLK_CTL_REG			REG(0x25A0)
-#define QDSS_AT_CLK_SRC0_NS_REG			REG(0x2180)
-#define QDSS_AT_CLK_SRC1_NS_REG			REG(0x2184)
-#define QDSS_AT_CLK_SRC_CTL_REG			REG(0x2188)
-#define QDSS_AT_CLK_NS_REG			REG(0x218C)
-#define QDSS_HCLK_CTL_REG			REG(0x22A0)
-#define QDSS_RESETS_REG				REG(0x2260)
-#define QDSS_STM_CLK_CTL_REG			REG(0x2060)
-#define QDSS_TRACECLKIN_CLK_SRC0_NS_REG		REG(0x21A0)
-#define QDSS_TRACECLKIN_CLK_SRC1_NS_REG		REG(0x21A4)
-#define QDSS_TRACECLKIN_CLK_SRC_CTL_REG		REG(0x21A8)
-#define QDSS_TRACECLKIN_CTL_REG			REG(0x21AC)
-#define QDSS_TSCTR_CLK_SRC0_NS_REG		REG(0x21C0)
-#define QDSS_TSCTR_CLK_SRC1_NS_REG		REG(0x21C4)
-#define QDSS_TSCTR_CLK_SRC_CTL_REG		REG(0x21C8)
-#define QDSS_TSCTR_CLK_SRC_CTL_REG		REG(0x21C8)
-#define QDSS_TSCTR_CTL_REG			REG(0x21CC)
 #define RINGOSC_NS_REG				REG(0x2DC0)
 #define RINGOSC_STATUS_REG			REG(0x2DCC)
 #define RINGOSC_TCXO_CTL_REG			REG(0x2DC4)
@@ -1435,279 +1419,6 @@
 static CLK_GSBI_QUP(gsbi11_qup, 11, CLK_HALT_CFPB_STATEC_REG, 15);
 static CLK_GSBI_QUP(gsbi12_qup, 12, CLK_HALT_CFPB_STATEC_REG, 11);
 
-#define F_QDSS(f, s, d) \
-	{ \
-		.freq_hz = f, \
-		.src_clk = &s##_clk.c, \
-		.ns_val = NS_DIVSRC(6, 3, d, 2, 0, s##_to_bb_mux), \
-	}
-static struct clk_freq_tbl clk_tbl_qdss[] = {
-	F_QDSS( 27000000, pxo,  1),
-	F_QDSS(128000000, pll8, 3),
-	F_QDSS(300000000, pll3, 4),
-	F_END
-};
-
-struct qdss_bank {
-	const u32 bank_sel_mask;
-	void __iomem *const ns_reg;
-	const u32 ns_mask;
-};
-
-#define QDSS_CLK_ROOT_ENA BIT(1)
-
-static int qdss_clk_handoff(struct clk *c)
-{
-	struct rcg_clk *clk = to_rcg_clk(c);
-	const struct qdss_bank *bank = clk->bank_info;
-	u32 reg, ns_val, bank_sel;
-	struct clk_freq_tbl *freq;
-
-	reg = readl_relaxed(clk->ns_reg);
-	if (!(reg & QDSS_CLK_ROOT_ENA))
-		return 0;
-
-	bank_sel = reg & bank->bank_sel_mask;
-	/* Force bank 1 to PXO if bank 0 is in use */
-	if (bank_sel == 0)
-		writel_relaxed(0, bank->ns_reg);
-	ns_val = readl_relaxed(bank->ns_reg) & bank->ns_mask;
-	for (freq = clk->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
-		if ((freq->ns_val & bank->ns_mask) == ns_val) {
-			pr_info("%s rate=%d\n", clk->c.dbg_name, freq->freq_hz);
-			break;
-		}
-	}
-	if (freq->freq_hz == FREQ_END)
-		return 0;
-
-	clk->current_freq = freq;
-
-	return 1;
-}
-
-static void set_rate_qdss(struct rcg_clk *clk, struct clk_freq_tbl *nf)
-{
-	const struct qdss_bank *bank = clk->bank_info;
-	u32 reg, bank_sel_mask = bank->bank_sel_mask;
-
-	/* Switch to bank 0 (always sourced from PXO) */
-	reg = readl_relaxed(clk->ns_reg);
-	reg &= ~bank_sel_mask;
-	writel_relaxed(reg, clk->ns_reg);
-	/*
-	 * Wait at least 6 cycles of slowest bank's clock for the glitch-free
-	 * MUX to fully switch sources.
-	 */
-	mb();
-	udelay(1);
-
-	/* Set source and divider */
-	reg = readl_relaxed(bank->ns_reg);
-	reg &= ~bank->ns_mask;
-	reg |= nf->ns_val;
-	writel_relaxed(reg, bank->ns_reg);
-
-	/* Switch to reprogrammed bank */
-	reg = readl_relaxed(clk->ns_reg);
-	reg |= bank_sel_mask;
-	writel_relaxed(reg, clk->ns_reg);
-	/*
-	 * Wait at least 6 cycles of slowest bank's clock for the glitch-free
-	 * MUX to fully switch sources.
-	 */
-	mb();
-	udelay(1);
-}
-
-static int qdss_clk_enable(struct clk *c)
-{
-	struct rcg_clk *clk = to_rcg_clk(c);
-	const struct qdss_bank *bank = clk->bank_info;
-	u32 reg, bank_sel_mask = bank->bank_sel_mask;
-	int ret;
-
-	/* Switch to bank 1 */
-	reg = readl_relaxed(clk->ns_reg);
-	reg |= bank_sel_mask;
-	writel_relaxed(reg, clk->ns_reg);
-
-	ret = rcg_clk_enable(c);
-	if (ret) {
-		/* Switch to bank 0 */
-		reg &= ~bank_sel_mask;
-		writel_relaxed(reg, clk->ns_reg);
-	}
-	return ret;
-}
-
-static void qdss_clk_disable(struct clk *c)
-{
-	struct rcg_clk *clk = to_rcg_clk(c);
-	const struct qdss_bank *bank = clk->bank_info;
-	u32 reg, bank_sel_mask = bank->bank_sel_mask;
-
-	rcg_clk_disable(c);
-	/* Switch to bank 0 */
-	reg = readl_relaxed(clk->ns_reg);
-	reg &= ~bank_sel_mask;
-	writel_relaxed(reg, clk->ns_reg);
-}
-
-static void qdss_clk_auto_off(struct clk *c)
-{
-	struct rcg_clk *clk = to_rcg_clk(c);
-	const struct qdss_bank *bank = clk->bank_info;
-	u32 reg, bank_sel_mask = bank->bank_sel_mask;
-
-	rcg_clk_disable(c);
-	/* Switch to bank 0 */
-	reg = readl_relaxed(clk->ns_reg);
-	reg &= ~bank_sel_mask;
-	writel_relaxed(reg, clk->ns_reg);
-}
-
-static struct clk_ops clk_ops_qdss = {
-	.enable = qdss_clk_enable,
-	.disable = qdss_clk_disable,
-	.auto_off = qdss_clk_auto_off,
-	.handoff = qdss_clk_handoff,
-	.set_rate = rcg_clk_set_rate,
-	.get_rate = rcg_clk_get_rate,
-	.list_rate = rcg_clk_list_rate,
-	.is_enabled = rcg_clk_is_enabled,
-	.round_rate = rcg_clk_round_rate,
-	.reset = rcg_clk_reset,
-	.is_local = local_clk_is_local,
-	.get_parent = rcg_clk_get_parent,
-};
-
-static struct qdss_bank bdiv_info_qdss = {
-	.bank_sel_mask = BIT(0),
-	.ns_reg = QDSS_AT_CLK_SRC1_NS_REG,
-	.ns_mask = BM(6, 0),
-};
-
-static struct rcg_clk qdss_at_clk = {
-	.b = {
-		.ctl_reg = QDSS_AT_CLK_NS_REG,
-		.reset_reg = QDSS_RESETS_REG,
-		.reset_mask = BIT(0),
-		.halt_check = NOCHECK,
-	},
-	.ns_reg = QDSS_AT_CLK_SRC_CTL_REG,
-	.set_rate = set_rate_qdss,
-	.freq_tbl = clk_tbl_qdss,
-	.bank_info = &bdiv_info_qdss,
-	.current_freq = &rcg_dummy_freq,
-	.c = {
-		.dbg_name = "qdss_at_clk",
-		.ops = &clk_ops_qdss,
-		VDD_DIG_FMAX_MAP2(LOW, 150000000, NOMINAL, 300000000),
-		CLK_INIT(qdss_at_clk.c),
-	},
-};
-
-static struct branch_clk qdss_pclkdbg_clk = {
-	.b = {
-		.ctl_reg = QDSS_AT_CLK_NS_REG,
-		.en_mask = BIT(4),
-		.reset_reg = QDSS_RESETS_REG,
-		.reset_mask = BIT(0),
-		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
-		.halt_bit = 9,
-		.halt_check = HALT_VOTED
-	},
-	.parent = &qdss_at_clk.c,
-	.c = {
-		.dbg_name = "qdss_pclkdbg_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(qdss_pclkdbg_clk.c),
-	},
-};
-
-static struct qdss_bank bdiv_info_qdss_trace = {
-	.bank_sel_mask = BIT(0),
-	.ns_reg = QDSS_TRACECLKIN_CLK_SRC1_NS_REG,
-	.ns_mask = BM(6, 0),
-};
-
-static struct rcg_clk qdss_traceclkin_clk = {
-	.b = {
-		.ctl_reg = QDSS_TRACECLKIN_CTL_REG,
-		.en_mask = BIT(4),
-		.reset_reg = QDSS_RESETS_REG,
-		.reset_mask = BIT(0),
-		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
-		.halt_bit = 8,
-		.halt_check = HALT_VOTED,
-	},
-	.ns_reg = QDSS_TRACECLKIN_CLK_SRC_CTL_REG,
-	.set_rate = set_rate_qdss,
-	.freq_tbl = clk_tbl_qdss,
-	.bank_info = &bdiv_info_qdss_trace,
-	.current_freq = &rcg_dummy_freq,
-	.c = {
-		.dbg_name = "qdss_traceclkin_clk",
-		.ops = &clk_ops_qdss,
-		VDD_DIG_FMAX_MAP2(LOW, 150000000, NOMINAL, 300000000),
-		CLK_INIT(qdss_traceclkin_clk.c),
-	},
-};
-
-static struct clk_freq_tbl clk_tbl_qdss_tsctr[] = {
-	F_QDSS( 27000000, pxo,  1),
-	F_QDSS(200000000, pll3, 6),
-	F_QDSS(400000000, pll3, 3),
-	F_END
-};
-
-static struct qdss_bank bdiv_info_qdss_tsctr = {
-	.bank_sel_mask = BIT(0),
-	.ns_reg = QDSS_TSCTR_CLK_SRC1_NS_REG,
-	.ns_mask = BM(6, 0),
-};
-
-static struct rcg_clk qdss_tsctr_clk = {
-	.b = {
-		.ctl_reg = QDSS_TSCTR_CTL_REG,
-		.en_mask = BIT(4),
-		.reset_reg = QDSS_RESETS_REG,
-		.reset_mask = BIT(3),
-		.halt_reg = CLK_HALT_MSS_SMPSS_MISC_STATE_REG,
-		.halt_bit = 7,
-		.halt_check = HALT_VOTED,
-	},
-	.ns_reg = QDSS_TSCTR_CLK_SRC_CTL_REG,
-	.set_rate = set_rate_qdss,
-	.freq_tbl = clk_tbl_qdss_tsctr,
-	.bank_info = &bdiv_info_qdss_tsctr,
-	.current_freq = &rcg_dummy_freq,
-	.c = {
-		.dbg_name = "qdss_tsctr_clk",
-		.ops = &clk_ops_qdss,
-		VDD_DIG_FMAX_MAP2(LOW, 200000000, NOMINAL, 400000000),
-		CLK_INIT(qdss_tsctr_clk.c),
-	},
-};
-
-static struct branch_clk qdss_stm_clk = {
-	.b = {
-		.ctl_reg = QDSS_STM_CLK_CTL_REG,
-		.en_mask = BIT(4),
-		.reset_reg = QDSS_RESETS_REG,
-		.reset_mask = BIT(1),
-		.halt_reg = CLK_HALT_AFAB_SFAB_STATEB_REG,
-		.halt_bit = 20,
-		.halt_check = HALT_VOTED,
-	},
-	.c = {
-		.dbg_name = "qdss_stm_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(qdss_stm_clk.c),
-	},
-};
-
 #define F_PDM(f, s, d) \
 	{ \
 		.freq_hz = f, \
@@ -2505,23 +2216,6 @@
 	},
 };
 
-static struct branch_clk qdss_p_clk = {
-	.b = {
-		.ctl_reg = QDSS_HCLK_CTL_REG,
-		.en_mask = BIT(4),
-		.halt_reg = CLK_HALT_SFPB_MISC_STATE_REG,
-		.halt_bit = 11,
-		.halt_check = HALT_VOTED,
-		.reset_reg = QDSS_RESETS_REG,
-		.reset_mask = BIT(2),
-	},
-	.c = {
-		.dbg_name = "qdss_p_clk",
-		.ops = &clk_ops_branch,
-		CLK_INIT(qdss_p_clk.c),
-	}
-};
-
 static struct branch_clk sata_phy_cfg_clk = {
 	.b = {
 		.ctl_reg = SATA_PHY_CFG_CLK_CTL_REG,
@@ -4776,7 +4470,6 @@
 static DEFINE_CLK_MEASURE(q6_func_clk);
 
 static struct measure_sel measure_mux[] = {
-	{ TEST_PER_LS(0x05), &qdss_p_clk.c },
 	{ TEST_PER_LS(0x08), &slimbus_xo_src_clk.c },
 	{ TEST_PER_LS(0x12), &sdc1_p_clk.c },
 	{ TEST_PER_LS(0x13), &sdc1_clk.c },
@@ -4877,11 +4570,6 @@
 	{ TEST_PER_HS(0x2A), &adm0_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_a_clk.c },
-	{ TEST_PER_HS(0x48), &qdss_at_clk.c },
-	{ TEST_PER_HS(0x49), &qdss_pclkdbg_clk.c },
-	{ TEST_PER_HS(0x4A), &qdss_traceclkin_clk.c },
-	{ TEST_PER_HS(0x4B), &qdss_tsctr_clk.c },
-	{ TEST_PER_HS(0x4F), &qdss_stm_clk.c },
 	{ TEST_PER_HS(0x50), &usb_hsic_hsic_clk.c },
 
 	{ TEST_MM_LS(0x00), &dsi1_byte_clk.c },
@@ -5090,6 +4778,12 @@
 	struct measure_clk *clk = to_measure_clk(c);
 	unsigned ret;
 
+	ret = clk_enable(&cxo_clk.c);
+	if (ret) {
+		pr_warning("CXO clock failed to enable. Can't measure\n");
+		return 0;
+	}
+
 	spin_lock_irqsave(&local_clock_reg_lock, flags);
 
 	/* Enable CXO/4 and RINGOSC branch and root. */
@@ -5127,6 +4821,8 @@
 	writel_relaxed(0x38F8, PLLTEST_PAD_CFG_REG);
 	spin_unlock_irqrestore(&local_clock_reg_lock, flags);
 
+	clk_disable(&cxo_clk.c);
+
 	return ret;
 }
 #else /* !CONFIG_DEBUG_FS */
@@ -5537,12 +5233,6 @@
 	CLK_LOOKUP("vsync_clk",		mdp_vsync_clk.c, "footswitch-8x60.4"),
 	CLK_LOOKUP("lut_mdp",		lut_mdp_clk.c,		NULL),
 	CLK_LOOKUP("lut_clk",		lut_mdp_clk.c,	"footswitch-8x60.4"),
-	CLK_LOOKUP("qdss_pclk",		qdss_p_clk.c,		NULL),
-	CLK_LOOKUP("qdss_at_clk",	qdss_at_clk.c,		NULL),
-	CLK_LOOKUP("qdss_pclkdbg_clk",	qdss_pclkdbg_clk.c,	NULL),
-	CLK_LOOKUP("qdss_traceclkin_clk", qdss_traceclkin_clk.c, NULL),
-	CLK_LOOKUP("qdss_tsctr_clk",	qdss_tsctr_clk.c,	NULL),
-	CLK_LOOKUP("qdss_stm_clk",	qdss_stm_clk.c,		NULL),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"msm_rotator.0"),
 	CLK_LOOKUP("core_clk",		rot_clk.c,	"footswitch-8x60.6"),
 	CLK_LOOKUP("tv_src_clk",	tv_src_clk.c,		NULL),
diff --git a/arch/arm/mach-msm/clock-9615.c b/arch/arm/mach-msm/clock-9615.c
index 76219ab..c33daf7 100644
--- a/arch/arm/mach-msm/clock-9615.c
+++ b/arch/arm/mach-msm/clock-9615.c
@@ -121,6 +121,7 @@
 #define SLIMBUS_XO_SRC_CLK_CTL_REG		REG(0x2628)
 
 /* Low-power Audio clock registers. */
+#define LCC_CLK_HS_DEBUG_CFG_REG		REG_LPA(0x00A4)
 #define LCC_CLK_LS_DEBUG_CFG_REG		REG_LPA(0x00A8)
 #define LCC_CODEC_I2S_MIC_MD_REG		REG_LPA(0x0064)
 #define LCC_CODEC_I2S_MIC_NS_REG		REG_LPA(0x0060)
@@ -164,12 +165,14 @@
 #define TEST_TYPE_PER_LS	1
 #define TEST_TYPE_PER_HS	2
 #define TEST_TYPE_LPA		5
+#define TEST_TYPE_LPA_HS	6
 #define TEST_TYPE_SHIFT		24
 #define TEST_CLK_SEL_MASK	BM(23, 0)
 #define TEST_VECTOR(s, t)	(((t) << TEST_TYPE_SHIFT) | BVAL(23, 0, (s)))
 #define TEST_PER_LS(s)		TEST_VECTOR((s), TEST_TYPE_PER_LS)
 #define TEST_PER_HS(s)		TEST_VECTOR((s), TEST_TYPE_PER_HS)
 #define TEST_LPA(s)		TEST_VECTOR((s), TEST_TYPE_LPA)
+#define TEST_LPA_HS(s)		TEST_VECTOR((s), TEST_TYPE_LPA_HS)
 
 #define MN_MODE_DUAL_EDGE 0x2
 
@@ -370,33 +373,12 @@
 	},
 };
 
-static unsigned int soft_vote_pll9;
-
-static struct pll_vote_clk pll9_clk = {
+static struct pll_clk pll9_acpu_clk = {
 	.rate = 440000000,
-	.en_reg = BB_PLL_ENA_SC0_REG,
-	.en_mask = BIT(9),
-	.status_reg = SC_PLL0_STATUS_REG,
-	.parent = &cxo_clk.c,
-	.soft_vote = &soft_vote_pll9,
-	.soft_vote_mask = PLL_SOFT_VOTE_PRIMARY,
-	.c = {
-		.dbg_name = "pll9_clk",
-		.ops = &clk_ops_pll_acpu_vote,
-		CLK_INIT(pll9_clk.c),
-	},
-};
-
-static struct pll_vote_clk pll9_acpu_clk = {
-	.rate = 440000000,
-	.en_reg = BB_PLL_ENA_SC0_REG,
-	.en_mask = BIT(9),
-	.soft_vote = &soft_vote_pll9,
-	.soft_vote_mask = PLL_SOFT_VOTE_ACPU,
-	.status_reg = SC_PLL0_STATUS_REG,
+	.mode_reg = SC_PLL0_MODE_REG,
 	.c = {
 		.dbg_name = "pll9_acpu_clk",
-		.ops = &clk_ops_pll_acpu_vote,
+		.ops = &clk_ops_pll,
 		CLK_INIT(pll9_acpu_clk.c),
 	},
 };
@@ -1402,6 +1384,10 @@
 	struct clk *clk;
 };
 
+static DEFINE_CLK_MEASURE(q6sw_clk);
+static DEFINE_CLK_MEASURE(q6fw_clk);
+static DEFINE_CLK_MEASURE(q6_func_clk);
+
 static struct measure_sel measure_mux[] = {
 	{ TEST_PER_LS(0x08), &slimbus_xo_src_clk.c },
 	{ TEST_PER_LS(0x12), &sdc1_p_clk.c },
@@ -1449,6 +1435,8 @@
 	{ TEST_PER_LS(0x92), &ce1_p_clk.c },
 	{ TEST_PER_HS(0x18), &sfab_clk.c },
 	{ TEST_PER_HS(0x18), &sfab_a_clk.c },
+	{ TEST_PER_HS(0x26), &q6sw_clk },
+	{ TEST_PER_HS(0x27), &q6fw_clk },
 	{ TEST_PER_LS(0xA4), &ce1_core_clk.c },
 	{ TEST_PER_HS(0x2A), &adm0_clk.c },
 	{ TEST_PER_HS(0x34), &ebi1_clk.c },
@@ -1461,6 +1449,7 @@
 	{ TEST_LPA(0x13), &spare_i2s_spkr_bit_clk.c },
 	{ TEST_LPA(0x14), &pcm_clk.c },
 	{ TEST_LPA(0x1D), &audio_slimbus_clk.c },
+	{ TEST_LPA_HS(0x00), &q6_func_clk },
 };
 
 static struct measure_sel *find_measure_sel(struct clk *clk)
@@ -1509,6 +1498,11 @@
 		writel_relaxed(BVAL(6, 1, clk_sel)|BIT(0),
 				LCC_CLK_LS_DEBUG_CFG_REG);
 		break;
+	case TEST_TYPE_LPA_HS:
+		writel_relaxed(0x402BC00, CLK_TEST_REG);
+		writel_relaxed(BVAL(2, 1, clk_sel)|BIT(0),
+				LCC_CLK_HS_DEBUG_CFG_REG);
+		break;
 	default:
 		ret = -EPERM;
 	}
@@ -1623,7 +1617,6 @@
 	CLK_LOOKUP("cxo",	cxo_clk.c,	NULL),
 	CLK_LOOKUP("pll0",	pll0_clk.c,	NULL),
 	CLK_LOOKUP("pll8",	pll8_clk.c,	NULL),
-	CLK_LOOKUP("pll9",	pll9_clk.c,	NULL),
 	CLK_LOOKUP("pll14",	pll14_clk.c,	NULL),
 
 	CLK_LOOKUP("pll0", pll0_acpu_clk.c, "acpu"),
@@ -1714,6 +1707,10 @@
 	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qce.0"),
 	CLK_LOOKUP("core_clk",		ce1_core_clk.c,		"qcrypto.0"),
 
+	CLK_LOOKUP("q6sw_clk",		q6sw_clk, NULL),
+	CLK_LOOKUP("q6fw_clk",		q6fw_clk, NULL),
+	CLK_LOOKUP("q6_func_clk",	q6_func_clk, NULL),
+
 	/* TODO: Make this real when RPM's ready. */
 	CLK_DUMMY("ebi1_msmbus_clk",	ebi1_msmbus_clk.c, NULL, OFF),
 	CLK_DUMMY("mem_clk",		ebi1_adm_clk.c, "msm_dmov", OFF),
@@ -1748,7 +1745,7 @@
  */
 static void __init reg_init(void)
 {
-	u32 regval, is_pll_enabled;
+	u32 regval, is_pll_enabled, pll9_lval;
 
 	/* Enable PDM CXO source. */
 	regval = readl_relaxed(PDM_CLK_NS_REG);
@@ -1784,33 +1781,6 @@
 		set_fsm_mode(BB_PLL0_MODE_REG);
 	}
 
-	/* Check if PLL9 (SC_PLL0) is enabled in FSM mode */
-	is_pll_enabled  = readl_relaxed(SC_PLL0_STATUS_REG) & BIT(16);
-
-	if (!is_pll_enabled) {
-		writel_relaxed(0x16, SC_PLL0_L_VAL_REG);
-		writel_relaxed(0xB, SC_PLL0_M_VAL_REG);
-		writel_relaxed(0xC, SC_PLL0_N_VAL_REG);
-
-		regval = readl_relaxed(SC_PLL0_CONFIG_REG);
-
-		/* Enable main output and the MN accumulator */
-		regval |= BIT(23) | BIT(22);
-
-		/* Set pre-divider and post-divider values to 1 and 1 */
-		regval &= ~BIT(19);
-		regval &= ~BM(21, 20);
-
-		/* Set VCO frequency */
-		regval &= ~BM(17, 16);
-
-		writel_relaxed(regval, SC_PLL0_CONFIG_REG);
-
-		set_fsm_mode(SC_PLL0_MODE_REG);
-
-	} else if (!(readl_relaxed(SC_PLL0_MODE_REG) & BIT(20)))
-		WARN(1, "PLL9 enabled in non-FSM mode!\n");
-
 	/* Check if PLL14 is enabled in FSM mode */
 	is_pll_enabled  = readl_relaxed(BB_PLL14_STATUS_REG) & BIT(16);
 
@@ -1838,6 +1808,12 @@
 	} else if (!(readl_relaxed(BB_PLL14_MODE_REG) & BIT(20)))
 		WARN(1, "PLL14 enabled in non-FSM mode!\n");
 
+	/* Detect PLL9 rate and fixup structure accordingly */
+	pll9_lval = readl_relaxed(SC_PLL0_L_VAL_REG);
+
+	if (pll9_lval == 0x1C)
+		pll9_acpu_clk.rate = 550000000;
+
 	/* Enable PLL4 source on the LPASS Primary PLL Mux */
 	regval = readl_relaxed(LCC_PRI_PLL_CLK_CTL_REG);
 	writel_relaxed(regval | BIT(0), LCC_PRI_PLL_CLK_CTL_REG);
diff --git a/arch/arm/mach-msm/cp14.S b/arch/arm/mach-msm/cp14.S
deleted file mode 100644
index 94c74d3..0000000
--- a/arch/arm/mach-msm/cp14.S
+++ /dev/null
@@ -1,669 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/threads.h>
-
-#if (NR_CPUS > 2)
-#error code only tested for 1 or 2 CPUs.
-#endif
-
-/* Add 1 slot to store the register count for ETM state */
-#define MAX_ETM_REGS (56 + 1)
-#define MAX_ETM_STATE_SIZE (MAX_ETM_REGS * 4)
-
-.global etm_read_reg
-etm_read_reg:
-    cmp     r0, #0x7F
-    bhi     read_high
-    ldr     r2, =read_table
-    add     r2, r2, r0, lsl #3
-    mov     pc, r2
-
-read_high:
-    cmp     r0, #0xC1
-    beq     read_c1
-    cmp     r0, #0xC4
-    beq     read_c4
-    cmp     r0, #0xC5
-    beq     read_c5
-    mov     r0, #0
-    bx      lr
-
-read_c1:
-    mrc     p14, 1, r0, c1,  c1, 4  // register 0xC1 (OS Lock Status Reg)
-    bx      lr
-
-read_c4:
-    mrc     p14, 1, r0, c1,  c4, 4  // register 0xC4 (Powerdown Ctl Reg)
-    bx      lr
-
-read_c5:
-    mrc     p14, 1, r0, c1,  c5, 4  // register 0xC5 (Powerdown Status Reg)
-    bx      lr
-
-read_table:
-    mrc     p14, 1, r0, c0,  c0, 0  // register 0x00
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 0  // register 0x01
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 0  // register 0x02
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 0  // register 0x03
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 0  // register 0x04
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 0  // register 0x05
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 0  // register 0x06
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 0  // register 0x07
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 0  // register 0x08
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 0  // register 0x09
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 0  // register 0x0A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 0  // register 0x0B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 0  // register 0x0C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 0  // register 0x0D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 0  // register 0x0E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 0  // register 0x0F
-    bx      lr
-    mrc     p14, 1, r0, c0,  c0, 1  // register 0x10
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 1  // register 0x11
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 1  // register 0x12
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 1  // register 0x13
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 1  // register 0x14
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 1  // register 0x15
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 1  // register 0x16
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 1  // register 0x17
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 1  // register 0x18
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 1  // register 0x19
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 1  // register 0x1A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 1  // register 0x1B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 1  // register 0x1C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 1  // register 0x1D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 1  // register 0x1E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 1  // register 0x1F
-    bx      lr
-    mrc     p14, 1, r0, c0,  c0, 2  // register 0x20
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 2  // register 0x21
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 2  // register 0x22
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 2  // register 0x23
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 2  // register 0x24
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 2  // register 0x25
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 2  // register 0x26
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 2  // register 0x27
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 2  // register 0x28
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 2  // register 0x29
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 2  // register 0x2A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 2  // register 0x2B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 2  // register 0x2C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 2  // register 0x2D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 2  // register 0x2E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 2  // register 0x2F
-    bx      lr
-    mrc     p14, 1, r0, c0,  c0, 3  // register 0x30
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 3  // register 0x31
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 3  // register 0x32
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 3  // register 0x33
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 3  // register 0x34
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 3  // register 0x35
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 3  // register 0x36
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 3  // register 0x37
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 3  // register 0x38
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 3  // register 0x39
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 3  // register 0x3A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 3  // register 0x3B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 3  // register 0x3C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 3  // register 0x3D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 3  // register 0x3E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 3  // register 0x3F
-    bx      lr
-    mrc     p14, 1, r0, c0,  c0, 4  // register 0x40
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 4  // register 0x41
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 4  // register 0x42
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 4  // register 0x43
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 4  // register 0x44
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 4  // register 0x45
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 4  // register 0x46
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 4  // register 0x47
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 4  // register 0x48
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 4  // register 0x49
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 4  // register 0x4A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 4  // register 0x4B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 4  // register 0x4C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 4  // register 0x4D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 4  // register 0x4E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 4  // register 0x4F
-    bx      lr
-    mrc     p14, 1, r0, c0,  c0, 5  // register 0x50
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 5  // register 0x51
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 5  // register 0x52
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 5  // register 0x53
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 5  // register 0x54
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 5  // register 0x55
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 5  // register 0x56
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 5  // register 0x57
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 5  // register 0x58
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 5  // register 0x59
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 5  // register 0x5A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 5  // register 0x5B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 5  // register 0x5C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 5  // register 0x5D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 5  // register 0x5E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 5  // register 0x5F
-    bx      lr
-    mrc     p14, 1, r0, c0,  c0, 6  // register 0x60
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 6  // register 0x61
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 6  // register 0x62
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 6  // register 0x63
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 6  // register 0x64
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 6  // register 0x65
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 6  // register 0x66
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 6  // register 0x67
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 6  // register 0x68
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 6  // register 0x69
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 6  // register 0x6A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 6  // register 0x6B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 6  // register 0x6C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 6  // register 0x6D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 6  // register 0x6E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 6  // register 0x6F
-    bx      lr
-    mrc     p14, 1, r0, c0,  c0, 7  // register 0x70
-    bx      lr
-    mrc     p14, 1, r0, c0,  c1, 7  // register 0x71
-    bx      lr
-    mrc     p14, 1, r0, c0,  c2, 7  // register 0x72
-    bx      lr
-    mrc     p14, 1, r0, c0,  c3, 7  // register 0x73
-    bx      lr
-    mrc     p14, 1, r0, c0,  c4, 7  // register 0x74
-    bx      lr
-    mrc     p14, 1, r0, c0,  c5, 7  // register 0x75
-    bx      lr
-    mrc     p14, 1, r0, c0,  c6, 7  // register 0x76
-    bx      lr
-    mrc     p14, 1, r0, c0,  c7, 7  // register 0x77
-    bx      lr
-    mrc     p14, 1, r0, c0,  c8, 7  // register 0x78
-    bx      lr
-    mrc     p14, 1, r0, c0,  c9, 7  // register 0x79
-    bx      lr
-    mrc     p14, 1, r0, c0, c10, 7  // register 0x7A
-    bx      lr
-    mrc     p14, 1, r0, c0, c11, 7  // register 0x7B
-    bx      lr
-    mrc     p14, 1, r0, c0, c12, 7  // register 0x7C
-    bx      lr
-    mrc     p14, 1, r0, c0, c13, 7  // register 0x7D
-    bx      lr
-    mrc     p14, 1, r0, c0, c14, 7  // register 0x7E
-    bx      lr
-    mrc     p14, 1, r0, c0, c15, 7  // register 0x7F
-    bx      lr
-
-.global etm_write_reg
-etm_write_reg:
-    cmp     r0, #0x7F
-    bhi     write_high
-    ldr     r2, =write_table
-    add     r2, r2, r0, lsl #3
-    mov     pc, r2
-
-write_high:
-    cmp     r0, #0xC0
-    beq     write_c0
-    cmp     r0, #0xC4
-    beq     write_c4
-    bx      lr
-
-write_c0:
-    mcr     p14, 1, r1, c1,  c0, 4  // register 0xC0 (OS Lock Access Reg)
-    bx      lr
-
-write_c4:
-    mcr     p14, 1, r1, c1,  c4, 4  // register 0xC4 (Powerdown Ctl Reg)
-    bx      lr
-
-write_table:
-    mcr     p14, 1, r1, c0,  c0, 0  // register 0x00
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 0  // register 0x01
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 0  // register 0x02
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 0  // register 0x03
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 0  // register 0x04
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 0  // register 0x05
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 0  // register 0x06
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 0  // register 0x07
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 0  // register 0x08
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 0  // register 0x09
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 0  // register 0x0A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 0  // register 0x0B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 0  // register 0x0C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 0  // register 0x0D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 0  // register 0x0E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 0  // register 0x0F
-    bx      lr
-    mcr     p14, 1, r1, c0,  c0, 1  // register 0x10
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 1  // register 0x11
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 1  // register 0x12
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 1  // register 0x13
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 1  // register 0x14
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 1  // register 0x15
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 1  // register 0x16
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 1  // register 0x17
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 1  // register 0x18
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 1  // register 0x19
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 1  // register 0x1A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 1  // register 0x1B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 1  // register 0x1C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 1  // register 0x1D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 1  // register 0x1E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 1  // register 0x1F
-    bx      lr
-    mcr     p14, 1, r1, c0,  c0, 2  // register 0x20
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 2  // register 0x21
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 2  // register 0x22
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 2  // register 0x23
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 2  // register 0x24
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 2  // register 0x25
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 2  // register 0x26
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 2  // register 0x27
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 2  // register 0x28
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 2  // register 0x29
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 2  // register 0x2A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 2  // register 0x2B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 2  // register 0x2C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 2  // register 0x2D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 2  // register 0x2E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 2  // register 0x2F
-    bx      lr
-    mcr     p14, 1, r1, c0,  c0, 3  // register 0x30
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 3  // register 0x31
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 3  // register 0x32
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 3  // register 0x33
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 3  // register 0x34
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 3  // register 0x35
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 3  // register 0x36
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 3  // register 0x37
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 3  // register 0x38
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 3  // register 0x39
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 3  // register 0x3A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 3  // register 0x3B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 3  // register 0x3C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 3  // register 0x3D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 3  // register 0x3E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 3  // register 0x3F
-    bx      lr
-    mcr     p14, 1, r1, c0,  c0, 4  // register 0x40
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 4  // register 0x41
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 4  // register 0x42
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 4  // register 0x43
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 4  // register 0x44
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 4  // register 0x45
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 4  // register 0x46
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 4  // register 0x47
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 4  // register 0x48
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 4  // register 0x49
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 4  // register 0x4A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 4  // register 0x4B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 4  // register 0x4C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 4  // register 0x4D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 4  // register 0x4E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 4  // register 0x4F
-    bx      lr
-    mcr     p14, 1, r1, c0,  c0, 5  // register 0x50
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 5  // register 0x51
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 5  // register 0x52
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 5  // register 0x53
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 5  // register 0x54
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 5  // register 0x55
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 5  // register 0x56
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 5  // register 0x57
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 5  // register 0x58
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 5  // register 0x59
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 5  // register 0x5A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 5  // register 0x5B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 5  // register 0x5C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 5  // register 0x5D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 5  // register 0x5E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 5  // register 0x5F
-    bx      lr
-    mcr     p14, 1, r1, c0,  c0, 6  // register 0x60
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 6  // register 0x61
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 6  // register 0x62
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 6  // register 0x63
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 6  // register 0x64
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 6  // register 0x65
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 6  // register 0x66
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 6  // register 0x67
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 6  // register 0x68
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 6  // register 0x69
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 6  // register 0x6A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 6  // register 0x6B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 6  // register 0x6C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 6  // register 0x6D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 6  // register 0x6E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 6  // register 0x6F
-    bx      lr
-    mcr     p14, 1, r1, c0,  c0, 7  // register 0x70
-    bx      lr
-    mcr     p14, 1, r1, c0,  c1, 7  // register 0x71
-    bx      lr
-    mcr     p14, 1, r1, c0,  c2, 7  // register 0x72
-    bx      lr
-    mcr     p14, 1, r1, c0,  c3, 7  // register 0x73
-    bx      lr
-    mcr     p14, 1, r1, c0,  c4, 7  // register 0x74
-    bx      lr
-    mcr     p14, 1, r1, c0,  c5, 7  // register 0x75
-    bx      lr
-    mcr     p14, 1, r1, c0,  c6, 7  // register 0x76
-    bx      lr
-    mcr     p14, 1, r1, c0,  c7, 7  // register 0x77
-    bx      lr
-    mcr     p14, 1, r1, c0,  c8, 7  // register 0x78
-    bx      lr
-    mcr     p14, 1, r1, c0,  c9, 7  // register 0x79
-    bx      lr
-    mcr     p14, 1, r1, c0, c10, 7  // register 0x7A
-    bx      lr
-    mcr     p14, 1, r1, c0, c11, 7  // register 0x7B
-    bx      lr
-    mcr     p14, 1, r1, c0, c12, 7  // register 0x7C
-    bx      lr
-    mcr     p14, 1, r1, c0, c13, 7  // register 0x7D
-    bx      lr
-    mcr     p14, 1, r1, c0, c14, 7  // register 0x7E
-    bx      lr
-    mcr     p14, 1, r1, c0, c15, 7  // register 0x7F
-    bx      lr
-
-.global l2tevselr0_write
-l2tevselr0_write:
-    mcr     p15, 3, r0, c15, c5, 2
-    bx      lr
-
-.global etm_save_reg
-etm_save_reg:
-	ldr     r3, =etm_state        /* store state at etm_state */
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r2, c0, c0, 5 /* MPIDR */
-	and	r2, r2, #15	      /* What CPU am I */
-	ldr     r1, =MAX_ETM_STATE_SIZE
-	mul     r2, r2, r1
-	add	r3, r3, r2
-#endif
-
-	/* save etm state */
-	mrc	p14, 1, r0, c1, c5, 4 /* read ETM PDSR to clear sticky bit */
-	isb
-	ldr     r1, =0xc5ACCE55       /* set ETMOSLAR lock */
-	mcr     p14, 1, r1, c1, c0, 4
-	isb
-
-	mrc     p14, 1, r1, c1, c2, 4 /* ETMOSSRR state register count */
-	cmp     r1, #(MAX_ETM_REGS)   /* check for state overflow */
-	movgt   r1, #0                /* if not enough space, don't save */
-	str     r1,[r3],#4            /* save count for restore */
-
-1:	cmp     r1, #0
-	mrcne   p14, 1, r2, c1, c2, 4 /* ETMOSSRR state value */
-	strne   r2, [r3], #4          /* push value */
-	subne   r1, r1, #1
-	bne     1b
-
-	mcr     p14, 1, r1, c1, c0, 4 /* r1 = 0, unlock ETMOSLAR */
-	isb
-
-	bx      lr
-
-.global etm_restore_reg
-etm_restore_reg:
-	/* restore debug registers after power collapse  */
-	ldr     r3, =etm_state        /* load state from etm_state */
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r2, c0, c0, 5 /* MPIDR */
-	and	r2, r2, #15	      /* What CPU am I */
-	ldr     r1, =MAX_ETM_STATE_SIZE
-	mul     r2, r2, r1
-	add	r3, r3, r2
-#endif
-
-	/* restore etm state */
-	mrc	p14, 1, r0, c1, c5, 4 /* read ETM PDSR to clear sticky bit */
-	isb
-	ldr     r1, =0xc5ACCE55       /* set ETMOSLAR lock */
-	mcr     p14, 1, r1, c1, c0, 4
-	isb
-
-	mrc     p14, 1, r1, c1, c2, 4 /* ETMOSSRR dummy read (required)*/
-	ldr     r1, [r3], #4          /* load saved count */
-	cmp     r1, #0                /* skip if none stored */
-	beq     end_etm_restore_reg
-
-1:	ldr     r2,[r3],#4
-	mcr     p14, 1, r2, c1, c2, 4 /* ETMOSSRR write state value */
-	subs    r1, r1, #1
-	bne     1b
-end_etm_restore_reg:
-	mcr     p14, 1, r1, c1, c0, 4 /* r1 = 0, unlock ETMOSLAR */
-	isb
-
-	bx      lr
-
-
-	.data
-
-etm_state:
-	.space	MAX_ETM_STATE_SIZE * NR_CPUS
diff --git a/arch/arm/mach-msm/cp14.h b/arch/arm/mach-msm/cp14.h
index 0946e07..9f7241e 100644
--- a/arch/arm/mach-msm/cp14.h
+++ b/arch/arm/mach-msm/cp14.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
@@ -10,10 +10,531 @@
  * GNU General Public License for more details.
  */
 
+#ifndef _ARCH_ARM_MACH_MSM_CP14_H_
+#define _ARCH_ARM_MACH_MSM_CP14_H_
+
 #include <linux/types.h>
 
-uint32_t etm_read_reg(uint32_t reg);
-void   etm_write_reg(uint32_t reg, uint32_t val);
-void   l2tevselr0_write(uint32_t val);
-void etm_save_reg(void);
-void etm_restore_reg(void);
+/* Accessors for CP14 registers */
+#define dbg_read(reg)			RCP14_##reg()
+#define dbg_write(val, reg)		WCP14_##reg(val)
+#define etm_read(reg)			RCP14_##reg()
+#define etm_write(val, reg)		WCP14_##reg(val)
+
+/* MRC14 and MCR14 */
+#define MRC14(op1, crn, crm, op2)					\
+({									\
+uint32_t val;								\
+asm volatile("mrc p14, "#op1", %0, "#crn", "#crm", "#op2 : "=r" (val));	\
+val;									\
+})
+
+#define MCR14(val, op1, crn, crm, op2)					\
+({									\
+asm volatile("mcr p14, "#op1", %0, "#crn", "#crm", "#op2 : : "r" (val));\
+})
+
+/* Debug Registers
+ *
+ * Available only in DBGv7
+ * DBGECR, DBGDSCCR, DBGDSMCR, DBGDRCR
+ *
+ * Available only in DBGv7.1
+ * DBGBXVRm, DBGOSDLR, DBGDEVID2, DBGDEVID1
+ *
+ * Read only
+ * DBGDIDR, DBGDSCRint, DBGDTRRXint, DBGDRAR, DBGOSLSR, DBGOSSRR, DBGPRSR,
+ * DBGPRSR, DBGDSAR, DBGAUTHSTATUS, DBGDEVID2, DBGDEVID1, DBGDEVID
+ *
+ * Write only
+ * DBGDTRTXint, DBGOSLAR
+ */
+#define RCP14_DBGDIDR()			MRC14(0, c0, c0, 0)
+#define RCP14_DBGDSCRint()		MRC14(0, c0, c1, 0)
+#define RCP14_DBGDTRRXint()		MRC14(0, c0, c5, 0)
+#define RCP14_DBGWFAR()			MRC14(0, c0, c6, 0)
+#define RCP14_DBGVCR()			MRC14(0, c0, c7, 0)
+#define RCP14_DBGECR()			MRC14(0, c0, c9, 0)
+#define RCP14_DBGDSCCR()		MRC14(0, c0, c10, 0)
+#define RCP14_DBGDSMCR()		MRC14(0, c0, c11, 0)
+#define RCP14_DBGDTRRXext()		MRC14(0, c0, c0, 2)
+#define RCP14_DBGDSCRext()		MRC14(0, c0, c2, 2)
+#define RCP14_DBGDTRTXext()		MRC14(0, c0, c3, 2)
+#define RCP14_DBGDRCR()			MRC14(0, c0, c4, 2)
+#define RCP14_DBGBVR0()			MRC14(0, c0, c0, 4)
+#define RCP14_DBGBVR1()			MRC14(0, c0, c1, 4)
+#define RCP14_DBGBVR2()			MRC14(0, c0, c2, 4)
+#define RCP14_DBGBVR3()			MRC14(0, c0, c3, 4)
+#define RCP14_DBGBVR4()			MRC14(0, c0, c4, 4)
+#define RCP14_DBGBVR5()			MRC14(0, c0, c5, 4)
+#define RCP14_DBGBVR6()			MRC14(0, c0, c6, 4)
+#define RCP14_DBGBVR7()			MRC14(0, c0, c7, 4)
+#define RCP14_DBGBVR8()			MRC14(0, c0, c8, 4)
+#define RCP14_DBGBVR9()			MRC14(0, c0, c9, 4)
+#define RCP14_DBGBVR10()		MRC14(0, c0, c10, 4)
+#define RCP14_DBGBVR11()		MRC14(0, c0, c11, 4)
+#define RCP14_DBGBVR12()		MRC14(0, c0, c12, 4)
+#define RCP14_DBGBVR13()		MRC14(0, c0, c13, 4)
+#define RCP14_DBGBVR14()		MRC14(0, c0, c14, 4)
+#define RCP14_DBGBVR15()		MRC14(0, c0, c15, 4)
+#define RCP14_DBGBCR0()			MRC14(0, c0, c0, 5)
+#define RCP14_DBGBCR1()			MRC14(0, c0, c1, 5)
+#define RCP14_DBGBCR2()			MRC14(0, c0, c2, 5)
+#define RCP14_DBGBCR3()			MRC14(0, c0, c3, 5)
+#define RCP14_DBGBCR4()			MRC14(0, c0, c4, 5)
+#define RCP14_DBGBCR5()			MRC14(0, c0, c5, 5)
+#define RCP14_DBGBCR6()			MRC14(0, c0, c6, 5)
+#define RCP14_DBGBCR7()			MRC14(0, c0, c7, 5)
+#define RCP14_DBGBCR8()			MRC14(0, c0, c8, 5)
+#define RCP14_DBGBCR9()			MRC14(0, c0, c9, 5)
+#define RCP14_DBGBCR10()		MRC14(0, c0, c10, 5)
+#define RCP14_DBGBCR11()		MRC14(0, c0, c11, 5)
+#define RCP14_DBGBCR12()		MRC14(0, c0, c12, 5)
+#define RCP14_DBGBCR13()		MRC14(0, c0, c13, 5)
+#define RCP14_DBGBCR14()		MRC14(0, c0, c14, 5)
+#define RCP14_DBGBCR15()		MRC14(0, c0, c15, 5)
+#define RCP14_DBGWVR0()			MRC14(0, c0, c0, 6)
+#define RCP14_DBGWVR1()			MRC14(0, c0, c1, 6)
+#define RCP14_DBGWVR2()			MRC14(0, c0, c2, 6)
+#define RCP14_DBGWVR3()			MRC14(0, c0, c3, 6)
+#define RCP14_DBGWVR4()			MRC14(0, c0, c4, 6)
+#define RCP14_DBGWVR5()			MRC14(0, c0, c5, 6)
+#define RCP14_DBGWVR6()			MRC14(0, c0, c6, 6)
+#define RCP14_DBGWVR7()			MRC14(0, c0, c7, 6)
+#define RCP14_DBGWVR8()			MRC14(0, c0, c8, 6)
+#define RCP14_DBGWVR9()			MRC14(0, c0, c9, 6)
+#define RCP14_DBGWVR10()		MRC14(0, c0, c10, 6)
+#define RCP14_DBGWVR11()		MRC14(0, c0, c11, 6)
+#define RCP14_DBGWVR12()		MRC14(0, c0, c12, 6)
+#define RCP14_DBGWVR13()		MRC14(0, c0, c13, 6)
+#define RCP14_DBGWVR14()		MRC14(0, c0, c14, 6)
+#define RCP14_DBGWVR15()		MRC14(0, c0, c15, 6)
+#define RCP14_DBGWCR0()			MRC14(0, c0, c0, 7)
+#define RCP14_DBGWCR1()			MRC14(0, c0, c1, 7)
+#define RCP14_DBGWCR2()			MRC14(0, c0, c2, 7)
+#define RCP14_DBGWCR3()			MRC14(0, c0, c3, 7)
+#define RCP14_DBGWCR4()			MRC14(0, c0, c4, 7)
+#define RCP14_DBGWCR5()			MRC14(0, c0, c5, 7)
+#define RCP14_DBGWCR6()			MRC14(0, c0, c6, 7)
+#define RCP14_DBGWCR7()			MRC14(0, c0, c7, 7)
+#define RCP14_DBGWCR8()			MRC14(0, c0, c8, 7)
+#define RCP14_DBGWCR9()			MRC14(0, c0, c9, 7)
+#define RCP14_DBGWCR10()		MRC14(0, c0, c10, 7)
+#define RCP14_DBGWCR11()		MRC14(0, c0, c11, 7)
+#define RCP14_DBGWCR12()		MRC14(0, c0, c12, 7)
+#define RCP14_DBGWCR13()		MRC14(0, c0, c13, 7)
+#define RCP14_DBGWCR14()		MRC14(0, c0, c14, 7)
+#define RCP14_DBGWCR15()		MRC14(0, c0, c15, 7)
+#define RCP14_DBGDRAR()			MRC14(0, c1, c0, 0)
+#define RCP14_DBGBXVR0()		MRC14(0, c1, c0, 1)
+#define RCP14_DBGBXVR1()		MRC14(0, c1, c1, 1)
+#define RCP14_DBGBXVR2()		MRC14(0, c1, c2, 1)
+#define RCP14_DBGBXVR3()		MRC14(0, c1, c3, 1)
+#define RCP14_DBGBXVR4()		MRC14(0, c1, c4, 1)
+#define RCP14_DBGBXVR5()		MRC14(0, c1, c5, 1)
+#define RCP14_DBGBXVR6()		MRC14(0, c1, c6, 1)
+#define RCP14_DBGBXVR7()		MRC14(0, c1, c7, 1)
+#define RCP14_DBGBXVR8()		MRC14(0, c1, c8, 1)
+#define RCP14_DBGBXVR9()		MRC14(0, c1, c9, 1)
+#define RCP14_DBGBXVR10()		MRC14(0, c1, c10, 1)
+#define RCP14_DBGBXVR11()		MRC14(0, c1, c11, 1)
+#define RCP14_DBGBXVR12()		MRC14(0, c1, c12, 1)
+#define RCP14_DBGBXVR13()		MRC14(0, c1, c13, 1)
+#define RCP14_DBGBXVR14()		MRC14(0, c1, c14, 1)
+#define RCP14_DBGBXVR15()		MRC14(0, c1, c15, 1)
+#define RCP14_DBGOSLSR()		MRC14(0, c1, c1, 4)
+#define RCP14_DBGOSSRR()		MRC14(0, c1, c2, 4)
+#define RCP14_DBGOSDLR()		MRC14(0, c1, c3, 4)
+#define RCP14_DBGPRCR()			MRC14(0, c1, c4, 4)
+#define RCP14_DBGPRSR()			MRC14(0, c1, c5, 4)
+#define RCP14_DBGDSAR()			MRC14(0, c2, c0, 0)
+#define RCP14_DBGITCTRL()		MRC14(0, c7, c0, 4)
+#define RCP14_DBGCLAIMSET()		MRC14(0, c7, c8, 6)
+#define RCP14_DBGCLAIMCLR()		MRC14(0, c7, c9, 6)
+#define RCP14_DBGAUTHSTATUS()		MRC14(0, c7, c14, 6)
+#define RCP14_DBGDEVID2()		MRC14(0, c7, c0, 7)
+#define RCP14_DBGDEVID1()		MRC14(0, c7, c1, 7)
+#define RCP14_DBGDEVID()		MRC14(0, c7, c2, 7)
+
+#define WCP14_DBGDTRTXint(val)		MCR14(val, 0, c0, c5, 0)
+#define WCP14_DBGWFAR(val)		MCR14(val, 0, c0, c6, 0)
+#define WCP14_DBGVCR(val)		MCR14(val, 0, c0, c7, 0)
+#define WCP14_DBGECR(val)		MCR14(val, 0, c0, c9, 0)
+#define WCP14_DBGDSCCR(val)		MCR14(val, 0, c0, c10, 0)
+#define WCP14_DBGDSMCR(val)		MCR14(val, 0, c0, c11, 0)
+#define WCP14_DBGDTRRXext(val)		MCR14(val, 0, c0, c0, 2)
+#define WCP14_DBGDSCRext(val)		MCR14(val, 0, c0, c2, 2)
+#define WCP14_DBGDTRTXext(val)		MCR14(val, 0, c0, c3, 2)
+#define WCP14_DBGDRCR(val)		MCR14(val, 0, c0, c4, 2)
+#define WCP14_DBGBVR0(val)		MCR14(val, 0, c0, c0, 4)
+#define WCP14_DBGBVR1(val)		MCR14(val, 0, c0, c1, 4)
+#define WCP14_DBGBVR2(val)		MCR14(val, 0, c0, c2, 4)
+#define WCP14_DBGBVR3(val)		MCR14(val, 0, c0, c3, 4)
+#define WCP14_DBGBVR4(val)		MCR14(val, 0, c0, c4, 4)
+#define WCP14_DBGBVR5(val)		MCR14(val, 0, c0, c5, 4)
+#define WCP14_DBGBVR6(val)		MCR14(val, 0, c0, c6, 4)
+#define WCP14_DBGBVR7(val)		MCR14(val, 0, c0, c7, 4)
+#define WCP14_DBGBVR8(val)		MCR14(val, 0, c0, c8, 4)
+#define WCP14_DBGBVR9(val)		MCR14(val, 0, c0, c9, 4)
+#define WCP14_DBGBVR10(val)		MCR14(val, 0, c0, c10, 4)
+#define WCP14_DBGBVR11(val)		MCR14(val, 0, c0, c11, 4)
+#define WCP14_DBGBVR12(val)		MCR14(val, 0, c0, c12, 4)
+#define WCP14_DBGBVR13(val)		MCR14(val, 0, c0, c13, 4)
+#define WCP14_DBGBVR14(val)		MCR14(val, 0, c0, c14, 4)
+#define WCP14_DBGBVR15(val)		MCR14(val, 0, c0, c15, 4)
+#define WCP14_DBGBCR0(val)		MCR14(val, 0, c0, c0, 5)
+#define WCP14_DBGBCR1(val)		MCR14(val, 0, c0, c1, 5)
+#define WCP14_DBGBCR2(val)		MCR14(val, 0, c0, c2, 5)
+#define WCP14_DBGBCR3(val)		MCR14(val, 0, c0, c3, 5)
+#define WCP14_DBGBCR4(val)		MCR14(val, 0, c0, c4, 5)
+#define WCP14_DBGBCR5(val)		MCR14(val, 0, c0, c5, 5)
+#define WCP14_DBGBCR6(val)		MCR14(val, 0, c0, c6, 5)
+#define WCP14_DBGBCR7(val)		MCR14(val, 0, c0, c7, 5)
+#define WCP14_DBGBCR8(val)		MCR14(val, 0, c0, c8, 5)
+#define WCP14_DBGBCR9(val)		MCR14(val, 0, c0, c9, 5)
+#define WCP14_DBGBCR10(val)		MCR14(val, 0, c0, c10, 5)
+#define WCP14_DBGBCR11(val)		MCR14(val, 0, c0, c11, 5)
+#define WCP14_DBGBCR12(val)		MCR14(val, 0, c0, c12, 5)
+#define WCP14_DBGBCR13(val)		MCR14(val, 0, c0, c13, 5)
+#define WCP14_DBGBCR14(val)		MCR14(val, 0, c0, c14, 5)
+#define WCP14_DBGBCR15(val)		MCR14(val, 0, c0, c15, 5)
+#define WCP14_DBGWVR0(val)		MCR14(val, 0, c0, c0, 6)
+#define WCP14_DBGWVR1(val)		MCR14(val, 0, c0, c1, 6)
+#define WCP14_DBGWVR2(val)		MCR14(val, 0, c0, c2, 6)
+#define WCP14_DBGWVR3(val)		MCR14(val, 0, c0, c3, 6)
+#define WCP14_DBGWVR4(val)		MCR14(val, 0, c0, c4, 6)
+#define WCP14_DBGWVR5(val)		MCR14(val, 0, c0, c5, 6)
+#define WCP14_DBGWVR6(val)		MCR14(val, 0, c0, c6, 6)
+#define WCP14_DBGWVR7(val)		MCR14(val, 0, c0, c7, 6)
+#define WCP14_DBGWVR8(val)		MCR14(val, 0, c0, c8, 6)
+#define WCP14_DBGWVR9(val)		MCR14(val, 0, c0, c9, 6)
+#define WCP14_DBGWVR10(val)		MCR14(val, 0, c0, c10, 6)
+#define WCP14_DBGWVR11(val)		MCR14(val, 0, c0, c11, 6)
+#define WCP14_DBGWVR12(val)		MCR14(val, 0, c0, c12, 6)
+#define WCP14_DBGWVR13(val)		MCR14(val, 0, c0, c13, 6)
+#define WCP14_DBGWVR14(val)		MCR14(val, 0, c0, c14, 6)
+#define WCP14_DBGWVR15(val)		MCR14(val, 0, c0, c15, 6)
+#define WCP14_DBGWCR0(val)		MCR14(val, 0, c0, c0, 7)
+#define WCP14_DBGWCR1(val)		MCR14(val, 0, c0, c1, 7)
+#define WCP14_DBGWCR2(val)		MCR14(val, 0, c0, c2, 7)
+#define WCP14_DBGWCR3(val)		MCR14(val, 0, c0, c3, 7)
+#define WCP14_DBGWCR4(val)		MCR14(val, 0, c0, c4, 7)
+#define WCP14_DBGWCR5(val)		MCR14(val, 0, c0, c5, 7)
+#define WCP14_DBGWCR6(val)		MCR14(val, 0, c0, c6, 7)
+#define WCP14_DBGWCR7(val)		MCR14(val, 0, c0, c7, 7)
+#define WCP14_DBGWCR8(val)		MCR14(val, 0, c0, c8, 7)
+#define WCP14_DBGWCR9(val)		MCR14(val, 0, c0, c9, 7)
+#define WCP14_DBGWCR10(val)		MCR14(val, 0, c0, c10, 7)
+#define WCP14_DBGWCR11(val)		MCR14(val, 0, c0, c11, 7)
+#define WCP14_DBGWCR12(val)		MCR14(val, 0, c0, c12, 7)
+#define WCP14_DBGWCR13(val)		MCR14(val, 0, c0, c13, 7)
+#define WCP14_DBGWCR14(val)		MCR14(val, 0, c0, c14, 7)
+#define WCP14_DBGWCR15(val)		MCR14(val, 0, c0, c15, 7)
+#define WCP14_DBGBXVR0(val)		MCR14(val, 0, c1, c0, 1)
+#define WCP14_DBGBXVR1(val)		MCR14(val, 0, c1, c1, 1)
+#define WCP14_DBGBXVR2(val)		MCR14(val, 0, c1, c2, 1)
+#define WCP14_DBGBXVR3(val)		MCR14(val, 0, c1, c3, 1)
+#define WCP14_DBGBXVR4(val)		MCR14(val, 0, c1, c4, 1)
+#define WCP14_DBGBXVR5(val)		MCR14(val, 0, c1, c5, 1)
+#define WCP14_DBGBXVR6(val)		MCR14(val, 0, c1, c6, 1)
+#define WCP14_DBGBXVR7(val)		MCR14(val, 0, c1, c7, 1)
+#define WCP14_DBGBXVR8(val)		MCR14(val, 0, c1, c8, 1)
+#define WCP14_DBGBXVR9(val)		MCR14(val, 0, c1, c9, 1)
+#define WCP14_DBGBXVR10(val)		MCR14(val, 0, c1, c10, 1)
+#define WCP14_DBGBXVR11(val)		MCR14(val, 0, c1, c11, 1)
+#define WCP14_DBGBXVR12(val)		MCR14(val, 0, c1, c12, 1)
+#define WCP14_DBGBXVR13(val)		MCR14(val, 0, c1, c13, 1)
+#define WCP14_DBGBXVR14(val)		MCR14(val, 0, c1, c14, 1)
+#define WCP14_DBGBXVR15(val)		MCR14(val, 0, c1, c15, 1)
+#define WCP14_DBGOSLAR(val)		MCR14(val, 0, c1, c0, 4)
+#define WCP14_DBGOSSRR(val)		MCR14(val, 0, c1, c2, 4)
+#define WCP14_DBGOSDLR(val)		MCR14(val, 0, c1, c3, 4)
+#define WCP14_DBGPRCR(val)		MCR14(val, 0, c1, c4, 4)
+#define WCP14_DBGITCTRL(val)		MCR14(val, 0, c7, c0, 4)
+#define WCP14_DBGCLAIMSET(val)		MCR14(val, 0, c7, c8, 6)
+#define WCP14_DBGCLAIMCLR(val)		MCR14(val, 0, c7, c9, 6)
+
+/* ETM Registers
+ *
+ * Available only in ETMv3.3, 3.4, 3.5
+ * ETMASICCR, ETMTECR2, ETMFFRR, ETMVDEVR, ETMVDCR1, ETMVDCR2, ETMVDCR3,
+ * ETMDCVRn, ETMDCMRn
+ *
+ * Available only in ETMv3.5 as read only
+ * ETMIDR2
+ *
+ * Available only in ETMv3.5, PFTv1.0, 1.1
+ * ETMTSEVR, ETMVMIDCVR, ETMPDCR
+ *
+ * Read only
+ * ETMCCR, ETMSCR, ETMIDR, ETMCCER, ETMOSLSR
+ * ETMLSR, ETMAUTHSTATUS, ETMDEVID, ETMDEVTYPE, ETMPIDR4, ETMPIDR5, ETMPIDR6,
+ * ETMPIDR7, ETMPIDR0, ETMPIDR1, ETMPIDR2, ETMPIDR2, ETMPIDR3, ETMCIDR0,
+ * ETMCIDR1, ETMCIDR2, ETMCIDR3
+ *
+ * Write only
+ * ETMOSLAR, ETMLAR
+ * Note: ETMCCER[11] controls WO nature of certain regs. Refer ETM arch spec.
+ */
+#define RCP14_ETMCR()			MRC14(1, c0, c0, 0)
+#define RCP14_ETMCCR()			MRC14(1, c0, c1, 0)
+#define RCP14_ETMTRIGGER()		MRC14(1, c0, c2, 0)
+#define RCP14_ETMASICCR()		MRC14(1, c0, c3, 0)
+#define RCP14_ETMSR()			MRC14(1, c0, c4, 0)
+#define RCP14_ETMSCR()			MRC14(1, c0, c5, 0)
+#define RCP14_ETMTSSCR()		MRC14(1, c0, c6, 0)
+#define RCP14_ETMTECR2()		MRC14(1, c0, c7, 0)
+#define RCP14_ETMTEEVR()		MRC14(1, c0, c8, 0)
+#define RCP14_ETMTECR1()		MRC14(1, c0, c9, 0)
+#define RCP14_ETMFFRR()			MRC14(1, c0, c10, 0)
+#define RCP14_ETMFFLR()			MRC14(1, c0, c11, 0)
+#define RCP14_ETMVDEVR()		MRC14(1, c0, c12, 0)
+#define RCP14_ETMVDCR1()		MRC14(1, c0, c13, 0)
+#define RCP14_ETMVDCR2()		MRC14(1, c0, c14, 0)
+#define RCP14_ETMVDCR3()		MRC14(1, c0, c15, 0)
+#define RCP14_ETMACVR0()		MRC14(1, c0, c0, 1)
+#define RCP14_ETMACVR1()		MRC14(1, c0, c1, 1)
+#define RCP14_ETMACVR2()		MRC14(1, c0, c2, 1)
+#define RCP14_ETMACVR3()		MRC14(1, c0, c3, 1)
+#define RCP14_ETMACVR4()		MRC14(1, c0, c4, 1)
+#define RCP14_ETMACVR5()		MRC14(1, c0, c5, 1)
+#define RCP14_ETMACVR6()		MRC14(1, c0, c6, 1)
+#define RCP14_ETMACVR7()		MRC14(1, c0, c7, 1)
+#define RCP14_ETMACVR8()		MRC14(1, c0, c8, 1)
+#define RCP14_ETMACVR9()		MRC14(1, c0, c9, 1)
+#define RCP14_ETMACVR10()		MRC14(1, c0, c10, 1)
+#define RCP14_ETMACVR11()		MRC14(1, c0, c11, 1)
+#define RCP14_ETMACVR12()		MRC14(1, c0, c12, 1)
+#define RCP14_ETMACVR13()		MRC14(1, c0, c13, 1)
+#define RCP14_ETMACVR14()		MRC14(1, c0, c14, 1)
+#define RCP14_ETMACVR15()		MRC14(1, c0, c15, 1)
+#define RCP14_ETMACTR0()		MRC14(1, c0, c0, 2)
+#define RCP14_ETMACTR1()		MRC14(1, c0, c1, 2)
+#define RCP14_ETMACTR2()		MRC14(1, c0, c2, 2)
+#define RCP14_ETMACTR3()		MRC14(1, c0, c3, 2)
+#define RCP14_ETMACTR4()		MRC14(1, c0, c4, 2)
+#define RCP14_ETMACTR5()		MRC14(1, c0, c5, 2)
+#define RCP14_ETMACTR6()		MRC14(1, c0, c6, 2)
+#define RCP14_ETMACTR7()		MRC14(1, c0, c7, 2)
+#define RCP14_ETMACTR8()		MRC14(1, c0, c8, 2)
+#define RCP14_ETMACTR9()		MRC14(1, c0, c9, 2)
+#define RCP14_ETMACTR10()		MRC14(1, c0, c10, 2)
+#define RCP14_ETMACTR11()		MRC14(1, c0, c11, 2)
+#define RCP14_ETMACTR12()		MRC14(1, c0, c12, 2)
+#define RCP14_ETMACTR13()		MRC14(1, c0, c13, 2)
+#define RCP14_ETMACTR14()		MRC14(1, c0, c14, 2)
+#define RCP14_ETMACTR15()		MRC14(1, c0, c15, 2)
+#define RCP14_ETMDCVR0()		MRC14(1, c0, c0, 3)
+#define RCP14_ETMDCVR1()		MRC14(1, c0, c1, 3)
+#define RCP14_ETMDCVR2()		MRC14(1, c0, c2, 3)
+#define RCP14_ETMDCVR3()		MRC14(1, c0, c3, 3)
+#define RCP14_ETMDCVR4()		MRC14(1, c0, c4, 3)
+#define RCP14_ETMDCVR5()		MRC14(1, c0, c5, 3)
+#define RCP14_ETMDCVR6()		MRC14(1, c0, c6, 3)
+#define RCP14_ETMDCVR7()		MRC14(1, c0, c7, 3)
+#define RCP14_ETMDCMR0()		MRC14(1, c0, c0, 4)
+#define RCP14_ETMDCMR1()		MRC14(1, c0, c1, 4)
+#define RCP14_ETMDCMR2()		MRC14(1, c0, c2, 4)
+#define RCP14_ETMDCMR3()		MRC14(1, c0, c3, 4)
+#define RCP14_ETMDCMR4()		MRC14(1, c0, c4, 4)
+#define RCP14_ETMDCMR5()		MRC14(1, c0, c5, 4)
+#define RCP14_ETMDCMR6()		MRC14(1, c0, c6, 4)
+#define RCP14_ETMDCMR7()		MRC14(1, c0, c7, 4)
+#define RCP14_ETMCNTRLDVR0()		MRC14(1, c0, c0, 5)
+#define RCP14_ETMCNTRLDVR1()		MRC14(1, c0, c1, 5)
+#define RCP14_ETMCNTRLDVR2()		MRC14(1, c0, c2, 5)
+#define RCP14_ETMCNTRLDVR3()		MRC14(1, c0, c3, 5)
+#define RCP14_ETMCNTENR0()		MRC14(1, c0, c4, 5)
+#define RCP14_ETMCNTENR1()		MRC14(1, c0, c5, 5)
+#define RCP14_ETMCNTENR2()		MRC14(1, c0, c6, 5)
+#define RCP14_ETMCNTENR3()		MRC14(1, c0, c7, 5)
+#define RCP14_ETMCNTRLDEVR0()		MRC14(1, c0, c8, 5)
+#define RCP14_ETMCNTRLDEVR1()		MRC14(1, c0, c9, 5)
+#define RCP14_ETMCNTRLDEVR2()		MRC14(1, c0, c10, 5)
+#define RCP14_ETMCNTRLDEVR3()		MRC14(1, c0, c11, 5)
+#define RCP14_ETMCNTVR0()		MRC14(1, c0, c12, 5)
+#define RCP14_ETMCNTVR1()		MRC14(1, c0, c13, 5)
+#define RCP14_ETMCNTVR2()		MRC14(1, c0, c14, 5)
+#define RCP14_ETMCNTVR3()		MRC14(1, c0, c15, 5)
+#define RCP14_ETMSQ12EVR()		MRC14(1, c0, c0, 6)
+#define RCP14_ETMSQ21EVR()		MRC14(1, c0, c1, 6)
+#define RCP14_ETMSQ23EVR()		MRC14(1, c0, c2, 6)
+#define RCP14_ETMSQ31EVR()		MRC14(1, c0, c3, 6)
+#define RCP14_ETMSQ32EVR()		MRC14(1, c0, c4, 6)
+#define RCP14_ETMSQ13EVR()		MRC14(1, c0, c5, 6)
+#define RCP14_ETMSQR()			MRC14(1, c0, c7, 6)
+#define RCP14_ETMEXTOUTEVR0()		MRC14(1, c0, c8, 6)
+#define RCP14_ETMEXTOUTEVR1()		MRC14(1, c0, c9, 6)
+#define RCP14_ETMEXTOUTEVR2()		MRC14(1, c0, c10, 6)
+#define RCP14_ETMEXTOUTEVR3()		MRC14(1, c0, c11, 6)
+#define RCP14_ETMCIDCVR0()		MRC14(1, c0, c12, 6)
+#define RCP14_ETMCIDCVR1()		MRC14(1, c0, c13, 6)
+#define RCP14_ETMCIDCVR2()		MRC14(1, c0, c14, 6)
+#define RCP14_ETMCIDCMR()		MRC14(1, c0, c15, 6)
+#define RCP14_ETMIMPSPEC0()		MRC14(1, c0, c0, 7)
+#define RCP14_ETMIMPSPEC1()		MRC14(1, c0, c1, 7)
+#define RCP14_ETMIMPSPEC2()		MRC14(1, c0, c2, 7)
+#define RCP14_ETMIMPSPEC3()		MRC14(1, c0, c3, 7)
+#define RCP14_ETMIMPSPEC4()		MRC14(1, c0, c4, 7)
+#define RCP14_ETMIMPSPEC5()		MRC14(1, c0, c5, 7)
+#define RCP14_ETMIMPSPEC6()		MRC14(1, c0, c6, 7)
+#define RCP14_ETMIMPSPEC7()		MRC14(1, c0, c7, 7)
+#define RCP14_ETMSYNCFR()		MRC14(1, c0, c8, 7)
+#define RCP14_ETMIDR()			MRC14(1, c0, c9, 7)
+#define RCP14_ETMCCER()			MRC14(1, c0, c10, 7)
+#define RCP14_ETMEXTINSELR()		MRC14(1, c0, c11, 7)
+#define RCP14_ETMTESSEICR()		MRC14(1, c0, c12, 7)
+#define RCP14_ETMEIBCR()		MRC14(1, c0, c13, 7)
+#define RCP14_ETMTSEVR()		MRC14(1, c0, c14, 7)
+#define RCP14_ETMAUXCR()		MRC14(1, c0, c15, 7)
+#define RCP14_ETMTRACEIDR()		MRC14(1, c1, c0, 0)
+#define RCP14_ETMIDR2()			MRC14(1, c1, c2, 0)
+#define RCP14_ETMVMIDCVR()		MRC14(1, c1, c1, 0)
+#define RCP14_ETMOSLSR()		MRC14(1, c1, c1, 4)
+/* not available in PFTv1.1 */
+#define RCP14_ETMOSSRR()		MRC14(1, c1, c2, 4)
+#define RCP14_ETMPDCR()			MRC14(1, c1, c4, 4)
+#define RCP14_ETMPDSR()			MRC14(1, c1, c5, 4)
+#define RCP14_ETMITCTRL()		MRC14(1, c7, c0, 4)
+#define RCP14_ETMCLAIMSET()		MRC14(1, c7, c8, 6)
+#define RCP14_ETMCLAIMCLR()		MRC14(1, c7, c9, 6)
+#define RCP14_ETMLSR()			MRC14(1, c7, c13, 6)
+#define RCP14_ETMAUTHSTATUS()		MRC14(1, c7, c14, 6)
+#define RCP14_ETMDEVID()		MRC14(1, c7, c2, 7)
+#define RCP14_ETMDEVTYPE()		MRC14(1, c7, c3, 7)
+#define RCP14_ETMPIDR4()		MRC14(1, c7, c4, 7)
+#define RCP14_ETMPIDR5()		MRC14(1, c7, c5, 7)
+#define RCP14_ETMPIDR6()		MRC14(1, c7, c6, 7)
+#define RCP14_ETMPIDR7()		MRC14(1, c7, c7, 7)
+#define RCP14_ETMPIDR0()		MRC14(1, c7, c8, 7)
+#define RCP14_ETMPIDR1()		MRC14(1, c7, c9, 7)
+#define RCP14_ETMPIDR2()		MRC14(1, c7, c10, 7)
+#define RCP14_ETMPIDR3()		MRC14(1, c7, c11, 7)
+#define RCP14_ETMCIDR0()		MRC14(1, c7, c12, 7)
+#define RCP14_ETMCIDR1()		MRC14(1, c7, c13, 7)
+#define RCP14_ETMCIDR2()		MRC14(1, c7, c14, 7)
+#define RCP14_ETMCIDR3()		MRC14(1, c7, c15, 7)
+
+#define WCP14_ETMCR(val)		MCR14(val, 1, c0, c0, 0)
+#define WCP14_ETMTRIGGER(val)		MCR14(val, 1, c0, c2, 0)
+#define WCP14_ETMASICCR(val)		MCR14(val, 1, c0, c3, 0)
+#define WCP14_ETMSR(val)		MCR14(val, 1, c0, c4, 0)
+#define WCP14_ETMTSSCR(val)		MCR14(val, 1, c0, c6, 0)
+#define WCP14_ETMTECR2(val)		MCR14(val, 1, c0, c7, 0)
+#define WCP14_ETMTEEVR(val)		MCR14(val, 1, c0, c8, 0)
+#define WCP14_ETMTECR1(val)		MCR14(val, 1, c0, c9, 0)
+#define WCP14_ETMFFRR(val)		MCR14(val, 1, c0, c10, 0)
+#define WCP14_ETMFFLR(val)		MCR14(val, 1, c0, c11, 0)
+#define WCP14_ETMVDEVR(val)		MCR14(val, 1, c0, c12, 0)
+#define WCP14_ETMVDCR1(val)		MCR14(val, 1, c0, c13, 0)
+#define WCP14_ETMVDCR2(val)		MCR14(val, 1, c0, c14, 0)
+#define WCP14_ETMVDCR3(val)		MCR14(val, 1, c0, c15, 0)
+#define WCP14_ETMACVR0(val)		MCR14(val, 1, c0, c0, 1)
+#define WCP14_ETMACVR1(val)		MCR14(val, 1, c0, c1, 1)
+#define WCP14_ETMACVR2(val)		MCR14(val, 1, c0, c2, 1)
+#define WCP14_ETMACVR3(val)		MCR14(val, 1, c0, c3, 1)
+#define WCP14_ETMACVR4(val)		MCR14(val, 1, c0, c4, 1)
+#define WCP14_ETMACVR5(val)		MCR14(val, 1, c0, c5, 1)
+#define WCP14_ETMACVR6(val)		MCR14(val, 1, c0, c6, 1)
+#define WCP14_ETMACVR7(val)		MCR14(val, 1, c0, c7, 1)
+#define WCP14_ETMACVR8(val)		MCR14(val, 1, c0, c8, 1)
+#define WCP14_ETMACVR9(val)		MCR14(val, 1, c0, c9, 1)
+#define WCP14_ETMACVR10(val)		MCR14(val, 1, c0, c10, 1)
+#define WCP14_ETMACVR11(val)		MCR14(val, 1, c0, c11, 1)
+#define WCP14_ETMACVR12(val)		MCR14(val, 1, c0, c12, 1)
+#define WCP14_ETMACVR13(val)		MCR14(val, 1, c0, c13, 1)
+#define WCP14_ETMACVR14(val)		MCR14(val, 1, c0, c14, 1)
+#define WCP14_ETMACVR15(val)		MCR14(val, 1, c0, c15, 1)
+#define WCP14_ETMACTR0(val)		MCR14(val, 1, c0, c0, 2)
+#define WCP14_ETMACTR1(val)		MCR14(val, 1, c0, c1, 2)
+#define WCP14_ETMACTR2(val)		MCR14(val, 1, c0, c2, 2)
+#define WCP14_ETMACTR3(val)		MCR14(val, 1, c0, c3, 2)
+#define WCP14_ETMACTR4(val)		MCR14(val, 1, c0, c4, 2)
+#define WCP14_ETMACTR5(val)		MCR14(val, 1, c0, c5, 2)
+#define WCP14_ETMACTR6(val)		MCR14(val, 1, c0, c6, 2)
+#define WCP14_ETMACTR7(val)		MCR14(val, 1, c0, c7, 2)
+#define WCP14_ETMACTR8(val)		MCR14(val, 1, c0, c8, 2)
+#define WCP14_ETMACTR9(val)		MCR14(val, 1, c0, c9, 2)
+#define WCP14_ETMACTR10(val)		MCR14(val, 1, c0, c10, 2)
+#define WCP14_ETMACTR11(val)		MCR14(val, 1, c0, c11, 2)
+#define WCP14_ETMACTR12(val)		MCR14(val, 1, c0, c12, 2)
+#define WCP14_ETMACTR13(val)		MCR14(val, 1, c0, c13, 2)
+#define WCP14_ETMACTR14(val)		MCR14(val, 1, c0, c14, 2)
+#define WCP14_ETMACTR15(val)		MCR14(val, 1, c0, c15, 2)
+#define WCP14_ETMDCVR0(val)		MCR14(val, 1, c0, c0, 3)
+#define WCP14_ETMDCVR1(val)		MCR14(val, 1, c0, c1, 3)
+#define WCP14_ETMDCVR2(val)		MCR14(val, 1, c0, c2, 3)
+#define WCP14_ETMDCVR3(val)		MCR14(val, 1, c0, c3, 3)
+#define WCP14_ETMDCVR4(val)		MCR14(val, 1, c0, c4, 3)
+#define WCP14_ETMDCVR5(val)		MCR14(val, 1, c0, c5, 3)
+#define WCP14_ETMDCVR6(val)		MCR14(val, 1, c0, c6, 3)
+#define WCP14_ETMDCVR7(val)		MCR14(val, 1, c0, c7, 3)
+#define WCP14_ETMDCMR0(val)		MCR14(val, 1, c0, c0, 4)
+#define WCP14_ETMDCMR1(val)		MCR14(val, 1, c0, c1, 4)
+#define WCP14_ETMDCMR2(val)		MCR14(val, 1, c0, c2, 4)
+#define WCP14_ETMDCMR3(val)		MCR14(val, 1, c0, c3, 4)
+#define WCP14_ETMDCMR4(val)		MCR14(val, 1, c0, c4, 4)
+#define WCP14_ETMDCMR5(val)		MCR14(val, 1, c0, c5, 4)
+#define WCP14_ETMDCMR6(val)		MCR14(val, 1, c0, c6, 4)
+#define WCP14_ETMDCMR7(val)		MCR14(val, 1, c0, c7, 4)
+#define WCP14_ETMCNTRLDVR0(val)		MCR14(val, 1, c0, c0, 5)
+#define WCP14_ETMCNTRLDVR1(val)		MCR14(val, 1, c0, c1, 5)
+#define WCP14_ETMCNTRLDVR2(val)		MCR14(val, 1, c0, c2, 5)
+#define WCP14_ETMCNTRLDVR3(val)		MCR14(val, 1, c0, c3, 5)
+#define WCP14_ETMCNTENR0(val)		MCR14(val, 1, c0, c4, 5)
+#define WCP14_ETMCNTENR1(val)		MCR14(val, 1, c0, c5, 5)
+#define WCP14_ETMCNTENR2(val)		MCR14(val, 1, c0, c6, 5)
+#define WCP14_ETMCNTENR3(val)		MCR14(val, 1, c0, c7, 5)
+#define WCP14_ETMCNTRLDEVR0(val)	MCR14(val, 1, c0, c8, 5)
+#define WCP14_ETMCNTRLDEVR1(val)	MCR14(val, 1, c0, c9, 5)
+#define WCP14_ETMCNTRLDEVR2(val)	MCR14(val, 1, c0, c10, 5)
+#define WCP14_ETMCNTRLDEVR3(val)	MCR14(val, 1, c0, c11, 5)
+#define WCP14_ETMCNTVR0(val)		MCR14(val, 1, c0, c12, 5)
+#define WCP14_ETMCNTVR1(val)		MCR14(val, 1, c0, c13, 5)
+#define WCP14_ETMCNTVR2(val)		MCR14(val, 1, c0, c14, 5)
+#define WCP14_ETMCNTVR3(val)		MCR14(val, 1, c0, c15, 5)
+#define WCP14_ETMSQ12EVR(val)		MCR14(val, 1, c0, c0, 6)
+#define WCP14_ETMSQ21EVR(val)		MCR14(val, 1, c0, c1, 6)
+#define WCP14_ETMSQ23EVR(val)		MCR14(val, 1, c0, c2, 6)
+#define WCP14_ETMSQ31EVR(val)		MCR14(val, 1, c0, c3, 6)
+#define WCP14_ETMSQ32EVR(val)		MCR14(val, 1, c0, c4, 6)
+#define WCP14_ETMSQ13EVR(val)		MCR14(val, 1, c0, c5, 6)
+#define WCP14_ETMSQR(val)		MCR14(val, 1, c0, c7, 6)
+#define WCP14_ETMEXTOUTEVR0(val)	MCR14(val, 1, c0, c8, 6)
+#define WCP14_ETMEXTOUTEVR1(val)	MCR14(val, 1, c0, c9, 6)
+#define WCP14_ETMEXTOUTEVR2(val)	MCR14(val, 1, c0, c10, 6)
+#define WCP14_ETMEXTOUTEVR3(val)	MCR14(val, 1, c0, c11, 6)
+#define WCP14_ETMCIDCVR0(val)		MCR14(val, 1, c0, c12, 6)
+#define WCP14_ETMCIDCVR1(val)		MCR14(val, 1, c0, c13, 6)
+#define WCP14_ETMCIDCVR2(val)		MCR14(val, 1, c0, c14, 6)
+#define WCP14_ETMCIDCMR(val)		MCR14(val, 1, c0, c15, 6)
+#define WCP14_ETMIMPSPEC0(val)		MCR14(val, 1, c0, c0, 7)
+#define WCP14_ETMIMPSPEC1(val)		MCR14(val, 1, c0, c1, 7)
+#define WCP14_ETMIMPSPEC2(val)		MCR14(val, 1, c0, c2, 7)
+#define WCP14_ETMIMPSPEC3(val)		MCR14(val, 1, c0, c3, 7)
+#define WCP14_ETMIMPSPEC4(val)		MCR14(val, 1, c0, c4, 7)
+#define WCP14_ETMIMPSPEC5(val)		MCR14(val, 1, c0, c5, 7)
+#define WCP14_ETMIMPSPEC6(val)		MCR14(val, 1, c0, c6, 7)
+#define WCP14_ETMIMPSPEC7(val)		MCR14(val, 1, c0, c7, 7)
+/* can be read only in ETMv3.4, ETMv3.5 */
+#define WCP14_ETMSYNCFR(val)		MCR14(val, 1, c0, c8, 7)
+#define WCP14_ETMEXTINSELR(val)		MCR14(val, 1, c0, c11, 7)
+#define WCP14_ETMTESSEICR(val)		MCR14(val, 1, c0, c12, 7)
+#define WCP14_ETMEIBCR(val)		MCR14(val, 1, c0, c13, 7)
+#define WCP14_ETMTSEVR(val)		MCR14(val, 1, c0, c14, 7)
+#define WCP14_ETMAUXCR(val)		MCR14(val, 1, c0, c15, 7)
+#define WCP14_ETMTRACEIDR(val)		MCR14(val, 1, c1, c0, 0)
+#define WCP14_ETMIDR2(val)		MCR14(val, 1, c1, c2, 0)
+#define WCP14_ETMVMIDCVR(val)		MCR14(val, 1, c1, c1, 0)
+#define WCP14_ETMOSLAR(val)		MCR14(val, 1, c1, c0, 4)
+/* not available in PFTv1.1 */
+#define WCP14_ETMOSSRR(val)		MCR14(val, 1, c1, c2, 4)
+#define WCP14_ETMPDCR(val)		MCR14(val, 1, c1, c4, 4)
+#define WCP14_ETMPDSR(val)		MCR14(val, 1, c1, c5, 4)
+#define WCP14_ETMITCTRL(val)		MCR14(val, 1, c7, c0, 4)
+#define WCP14_ETMCLAIMSET(val)		MCR14(val, 1, c7, c8, 6)
+#define WCP14_ETMCLAIMCLR(val)		MCR14(val, 1, c7, c9, 6)
+/* writes to this from CP14 interface are ignored */
+#define WCP14_ETMLAR(val)		MCR14(val, 1, c7, c12, 6)
+
+#endif
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 6738955..abaa925 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -16,8 +16,8 @@
 #include <linux/cpuidle.h>
 #include <linux/cpu_pm.h>
 
-#include "cpuidle.h"
-#include "pm.h"
+#include <mach/cpuidle.h>
+#include <mach/pm.h>
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuidle_device, msm_cpuidle_devs);
 static struct cpuidle_driver msm_cpuidle_driver = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index 7f92bbe..4fa3e92 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -2597,7 +2597,6 @@
 #define MSM_ETB_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1000)
 #define MSM_TPIU_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x3000)
 #define MSM_FUNNEL_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x4000)
-#define MSM_DEBUG_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x10000)
 #define MSM_PTM_PHYS_BASE		(MSM_QDSS_PHYS_BASE + 0x1C000)
 
 static struct resource msm_etb_resources[] = {
@@ -2645,26 +2644,6 @@
 	.resource      = msm_funnel_resources,
 };
 
-static struct resource msm_debug_resources[] = {
-	{
-		.start = MSM_DEBUG_PHYS_BASE,
-		.end   = MSM_DEBUG_PHYS_BASE + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-	{
-		.start = MSM_DEBUG_PHYS_BASE + (SZ_4K * 2),
-		.end   = MSM_DEBUG_PHYS_BASE + (SZ_4K * 2) + SZ_4K - 1,
-		.flags = IORESOURCE_MEM,
-	},
-};
-
-struct platform_device msm_debug_device = {
-	.name          = "msm_debug",
-	.id            = 0,
-	.num_resources = ARRAY_SIZE(msm_debug_resources),
-	.resource      = msm_debug_resources,
-};
-
 static struct resource msm_ptm_resources[] = {
 	{
 		.start = MSM_PTM_PHYS_BASE,
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index b3541d5..314d064 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.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
@@ -33,7 +33,7 @@
 #include "devices.h"
 #include "mpm.h"
 #include "spm.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "rpm_resources.h"
 #include "msm_watchdog.h"
 
@@ -170,6 +170,29 @@
 	},
 };
 
+static struct resource resources_hsic_peripheral[] = {
+	{
+		.start	= MSM9615_HSIC_PHYS,
+		.end	= MSM9615_HSIC_PHYS + MSM9615_HSIC_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= USB_HSIC_IRQ,
+		.end	= USB_HSIC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device msm_device_hsic_peripheral = {
+	.name		= "msm_hsic_peripheral",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(resources_hsic_peripheral),
+	.resource	= resources_hsic_peripheral,
+	.dev		= {
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
+	},
+};
+
 static struct resource resources_hsusb_host[] = {
 	{
 		.start  = MSM9615_HSUSB_PHYS,
diff --git a/arch/arm/mach-msm/devices-msm7x27.c b/arch/arm/mach-msm/devices-msm7x27.c
index 0fb64dc..cdb43ad 100644
--- a/arch/arm/mach-msm/devices-msm7x27.c
+++ b/arch/arm/mach-msm/devices-msm7x27.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 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
@@ -18,6 +18,7 @@
 #include <linux/msm_kgsl.h>
 #include <linux/regulator/machine.h>
 #include <linux/dma-mapping.h>
+#include <linux/init.h>
 #include <asm/clkdev.h>
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
@@ -839,3 +840,29 @@
 	FS_PCOM(FS_GFX3D,  "fs_gfx3d"),
 };
 unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct resource gpio_resources[] = {
+	{
+		.start  = INT_GPIO_GROUP1,
+		.flags  = IORESOURCE_IRQ,
+	},
+	{
+		.start  = INT_GPIO_GROUP2,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_device_gpio = {
+	.name	   = "msmgpio",
+	.id	     = -1,
+	.resource       = gpio_resources,
+	.num_resources  = ARRAY_SIZE(gpio_resources),
+};
+
+static int __init msm7627_init_gpio(void)
+{
+	platform_device_register(&msm_device_gpio);
+	return 0;
+}
+
+postcore_initcall(msm7627_init_gpio);
diff --git a/arch/arm/mach-msm/devices-msm7x27a.c b/arch/arm/mach-msm/devices-msm7x27a.c
index 8a090f8..97cb263 100644
--- a/arch/arm/mach-msm/devices-msm7x27a.c
+++ b/arch/arm/mach-msm/devices-msm7x27a.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
@@ -15,6 +15,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/msm_kgsl.h>
 #include <linux/regulator/machine.h>
+#include <linux/init.h>
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
 #include <mach/board.h>
@@ -594,12 +595,16 @@
 			.bus_freq = 200000000,
 		},
 		{
+			.gpu_freq = 192000000,
+			.bus_freq = 160000000,
+		},
+		{
 			.gpu_freq = 133330000,
 			.bus_freq = 0,
 		},
 	},
 	.init_level = 0,
-	.num_levels = 2,
+	.num_levels = 3,
 	.set_grp_async = set_grp_xbar_async,
 	.idle_timeout = HZ/5,
 	.nap_allowed = false,
@@ -696,6 +701,31 @@
 	.id     = 0,
 };
 
+static struct resource gpio_resources[] = {
+	{
+		.start	= INT_GPIO_GROUP1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_GPIO_GROUP2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_device_gpio = {
+	.name		= "msmgpio",
+	.id		= -1,
+	.resource	= gpio_resources,
+	.num_resources	= ARRAY_SIZE(gpio_resources),
+};
+
+static int msm7627a_init_gpio(void)
+{
+	platform_device_register(&msm_device_gpio);
+	return 0;
+}
+postcore_initcall(msm7627a_init_gpio);
+
 int __init msm7x2x_misc_init(void)
 {
 	msm_clock_init(&msm7x27a_clock_init_data);
diff --git a/arch/arm/mach-msm/devices-msm7x30.c b/arch/arm/mach-msm/devices-msm7x30.c
index 2c21f57..db656f3 100644
--- a/arch/arm/mach-msm/devices-msm7x30.c
+++ b/arch/arm/mach-msm/devices-msm7x30.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 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
@@ -20,6 +20,7 @@
 #include <linux/msm_kgsl.h>
 #include <linux/android_pmem.h>
 #include <linux/regulator/machine.h>
+#include <linux/init.h>
 #include <mach/irqs.h>
 #include <mach/msm_iomap.h>
 #include <mach/dma.h>
@@ -1187,3 +1188,29 @@
 	FS_PCOM(FS_VPE,    "fs_vpe"),
 };
 unsigned msm_num_footswitch_devices = ARRAY_SIZE(msm_footswitch_devices);
+
+static struct resource gpio_resources[] = {
+	{
+		.start	= INT_GPIO_GROUP1,
+		.flags	= IORESOURCE_IRQ,
+	},
+	{
+		.start	= INT_GPIO_GROUP2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device msm_device_gpio = {
+	.name		= "msmgpio",
+	.id		= -1,
+	.resource	= gpio_resources,
+	.num_resources	= ARRAY_SIZE(gpio_resources),
+};
+
+static int __init msm7630_init_gpio(void)
+{
+	platform_device_register(&msm_device_gpio);
+	return 0;
+}
+
+postcore_initcall(msm7630_init_gpio);
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8a9c9fc..33a543d 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/devices.h
  *
  * Copyright (C) 2008 Google, Inc.
- * 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
@@ -94,7 +94,7 @@
 extern struct platform_device msm_device_hsic_host;
 
 extern struct platform_device msm_device_otg;
-
+extern struct platform_device msm_device_hsic_peripheral;
 extern struct platform_device msm8960_device_otg;
 extern struct platform_device msm8960_device_gadget_peripheral;
 
@@ -262,6 +262,5 @@
 extern struct platform_device msm_etb_device;
 extern struct platform_device msm_tpiu_device;
 extern struct platform_device msm_funnel_device;
-extern struct platform_device msm_debug_device;
 extern struct platform_device msm_ptm_device;
 #endif
diff --git a/arch/arm/mach-msm/dfe-fsm9xxx.c b/arch/arm/mach-msm/dfe-fsm9xxx.c
index d372171..1a956e3 100644
--- a/arch/arm/mach-msm/dfe-fsm9xxx.c
+++ b/arch/arm/mach-msm/dfe-fsm9xxx.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
@@ -159,9 +159,6 @@
 		(struct hh_dev_file_info *) file->private_data;
 
 	switch (cmd) {
-	case DFE_IOCTL_IS_UMTS:
-		return __raw_readl(MSM_TCSR_BASE + 0x0008) & 0x01;
-
 	case DFE_IOCTL_READ_REGISTER:
 		{
 			unsigned int offset, value;
diff --git a/arch/arm/mach-msm/etm.c b/arch/arm/mach-msm/etm.c
index 81c0478..bee0975 100644
--- a/arch/arm/mach-msm/etm.c
+++ b/arch/arm/mach-msm/etm.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
@@ -28,8 +28,6 @@
 #include "cp14.h"
 
 #define LOG_BUF_LEN			32768
-#define ETM_NUM_REGS			128
-#define ETB_NUM_REGS			9
 /* each slot is 4 bytes, 8kb total */
 #define ETB_RAM_SLOTS			2048
 
@@ -37,14 +35,16 @@
 #define ETM_DUMP_MSG_ID			0x000A6960
 #define ETB_DUMP_MSG_ID			0x000A6961
 
-/* ETM Registers */
-#define ETM_REG_CONTROL			0x00
-#define ETM_REG_STATUS			0x04
-#define ETB_REG_CONTROL			0x71
-#define ETB_REG_STATUS			0x72
-#define ETB_REG_COUNT			0x73
-#define ETB_REG_ADDRESS			0x74
-#define ETB_REG_DATA			0x75
+/* ETB Registers */
+#define ETB_REG_CONTROL			ETMIMPSPEC1
+#define ETB_REG_STATUS			ETMIMPSPEC2
+#define ETB_REG_COUNT			ETMIMPSPEC3
+#define ETB_REG_ADDRESS			ETMIMPSPEC4
+#define ETB_REG_DATA			ETMIMPSPEC5
+
+/* Having etb macro accessors allows macro expansion for ETB reg defines */
+#define etb_read(reg)			etm_read(reg)
+#define etb_write(val, reg)		etm_write(val, reg)
 
 /* Bitmasks for the ETM control register */
 #define ETM_CONTROL_POWERDOWN		0x00000001
@@ -186,6 +186,41 @@
 	.etb_init_ptr                   = 0x00000010,
 };
 
+/* ETM clock is derived from the processor clock and gets enabled on a
+ * logical OR of below items on Scorpion:
+ * 1.CPMR[ETMCLKEN] is set
+ * 2.ETM is not idle. Also means ETMCR[PD] is 0
+ * 3.Reset is asserted (core or debug)
+ * 4.MRC/MCR to ETM reg (CP14 access)
+ * 5.Debugger access to a ETM register in the core power domain
+ *
+ * 1. and 2. above are permanent enables whereas 3., 4. and 5. are
+ * temporary enables
+ *
+ * We rely on 4. to be able to access ETMCR and then use 2. above for ETM
+ * clock vote in the driver and the save-restore code uses 1. above
+ * for its vote.
+ */
+static inline void __cpu_set_etm_pwrdwn(void)
+{
+	uint32_t etm_control;
+
+	isb();
+	etm_control = etm_read(ETMCR);
+	etm_control |= ETM_CONTROL_POWERDOWN;
+	etm_write(etm_control, ETMCR);
+}
+
+static inline void __cpu_clear_etm_pwrdwn(void)
+{
+	uint32_t etm_control;
+
+	etm_control = etm_read(ETMCR);
+	etm_control &= ~ETM_CONTROL_POWERDOWN;
+	etm_write(etm_control, ETMCR);
+	isb();
+}
+
 static void emit_log_char(uint8_t c)
 {
 	int this_cpu = get_cpu();
@@ -211,21 +246,21 @@
 
 	/* enable auto-increment on reads and writes */
 	etb_control = AIR | AIW;
-	etm_write_reg(ETB_REG_CONTROL, etb_control);
+	etb_write(etb_control, ETB_REG_CONTROL);
 
 	/* write tags to the slots before the write pointer so we can
 	 * detect overflow */
-	etm_write_reg(ETB_REG_ADDRESS, 0x00000000);
+	etb_write(0x00000000, ETB_REG_ADDRESS);
 	for (i = 0; i < (etm_config.etb_init_ptr >> 2); i++)
-		etm_write_reg(ETB_REG_DATA, 0xDEADBEEF);
+		etb_write(0xDEADBEEF, ETB_REG_DATA);
 
-	etm_write_reg(ETB_REG_STATUS, 0x00000000);
+	etb_write(0x00000000, ETB_REG_STATUS);
 
 	/* initialize write pointer */
-	etm_write_reg(ETB_REG_ADDRESS, etm_config.etb_init_ptr);
+	etb_write(etm_config.etb_init_ptr, ETB_REG_ADDRESS);
 
 	/* multiple of 16 */
-	etm_write_reg(ETB_REG_COUNT, etm_config.etb_trig_cnt & 0xFFFFFFF0);
+	etb_write(etm_config.etb_trig_cnt & 0xFFFFFFF0, ETB_REG_COUNT);
 
 	/* Enable ETB and enable the trigger counter as appropriate. A
 	 * trigger count of 0 will be used to signify that the user wants to
@@ -236,15 +271,15 @@
 	etb_control |= CPTEN;
 	if (etm_config.etb_trig_cnt)
 		etb_control |= CPTM;
-	etm_write_reg(ETB_REG_CONTROL, etb_control);
+	etb_write(etb_control, ETB_REG_CONTROL);
 }
 
 static void __cpu_disable_etb(void)
 {
 	uint32_t etb_control;
-	etb_control = etm_read_reg(ETB_REG_CONTROL);
+	etb_control = etb_read(ETB_REG_CONTROL);
 	etb_control &= ~CPTEN;
-	etm_write_reg(ETB_REG_CONTROL, etb_control);
+	etb_write(etb_control, ETB_REG_CONTROL);
 }
 
 static void __cpu_enable_etm(void)
@@ -252,11 +287,11 @@
 	uint32_t etm_control;
 	unsigned long timeout = jiffies + msecs_to_jiffies(PROG_TIMEOUT_MS);
 
-	etm_control = etm_read_reg(ETM_REG_CONTROL);
+	etm_control = etm_read(ETMCR);
 	etm_control &= ~ETM_CONTROL_PROGRAM;
-	etm_write_reg(ETM_REG_CONTROL, etm_control);
+	etm_write(etm_control, ETMCR);
 
-	while ((etm_read_reg(ETM_REG_STATUS) & ETM_STATUS_PROGRAMMING) == 1) {
+	while ((etm_read(ETMSR) & ETM_STATUS_PROGRAMMING) == 1) {
 		cpu_relax();
 		if (time_after(jiffies, timeout)) {
 			pr_err("etm: timeout while clearing prog bit\n");
@@ -270,11 +305,11 @@
 	uint32_t etm_control;
 	unsigned long timeout = jiffies + msecs_to_jiffies(PROG_TIMEOUT_MS);
 
-	etm_control = etm_read_reg(ETM_REG_CONTROL);
+	etm_control = etm_read(ETMCR);
 	etm_control |= ETM_CONTROL_PROGRAM;
-	etm_write_reg(ETM_REG_CONTROL, etm_control);
+	etm_write(etm_control, ETMCR);
 
-	while ((etm_read_reg(ETM_REG_STATUS) & ETM_STATUS_PROGRAMMING) == 0) {
+	while ((etm_read(ETMSR) & ETM_STATUS_PROGRAMMING) == 0) {
 		cpu_relax();
 		if (time_after(jiffies, timeout)) {
 			pr_err("etm: timeout while setting prog bit\n");
@@ -291,14 +326,14 @@
 
 	get_cpu();
 
-	etm_read_reg(0xC5); /* clear sticky bit in PDSR */
-
 	__cpu_disable_etb();
+	/* vote for ETM power/clock enable */
+	__cpu_clear_etm_pwrdwn();
 	__cpu_disable_etm();
 
 	etm_control = (etm_config.etm_00_control & ~ETM_CONTROL_POWERDOWN)
 						| ETM_CONTROL_PROGRAM;
-	etm_write_reg(0x00, etm_control);
+	etm_write(etm_control, ETMCR);
 
 	etm_trigger = etm_config.etm_02_trigger_event;
 	etm_external_output = 0x406F; /* always FALSE */
@@ -314,53 +349,53 @@
 		etm_external_output = etm_trigger;
 	}
 
-	etm_write_reg(0x02, etm_trigger);
-	etm_write_reg(0x06, etm_config.etm_06_te_start_stop);
-	etm_write_reg(0x07, etm_config.etm_07_te_single_addr_comp);
-	etm_write_reg(0x08, etm_config.etm_08_te_event);
-	etm_write_reg(0x09, etm_config.etm_09_te_control);
-	etm_write_reg(0x0a, etm_config.etm_0a_fifofull_region);
-	etm_write_reg(0x0b, etm_config.etm_0b_fifofull_level);
-	etm_write_reg(0x0c, etm_config.etm_0c_vd_event);
-	etm_write_reg(0x0d, etm_config.etm_0d_vd_single_addr_comp);
-	etm_write_reg(0x0e, etm_config.etm_0e_vd_mmd);
-	etm_write_reg(0x0f, etm_config.etm_0f_vd_control);
-	etm_write_reg(0x10, etm_config.etm_addr_comp_value[0]);
-	etm_write_reg(0x11, etm_config.etm_addr_comp_value[1]);
-	etm_write_reg(0x12, etm_config.etm_addr_comp_value[2]);
-	etm_write_reg(0x13, etm_config.etm_addr_comp_value[3]);
-	etm_write_reg(0x14, etm_config.etm_addr_comp_value[4]);
-	etm_write_reg(0x15, etm_config.etm_addr_comp_value[5]);
-	etm_write_reg(0x16, etm_config.etm_addr_comp_value[6]);
-	etm_write_reg(0x17, etm_config.etm_addr_comp_value[7]);
-	etm_write_reg(0x20, etm_config.etm_addr_access_type[0]);
-	etm_write_reg(0x21, etm_config.etm_addr_access_type[1]);
-	etm_write_reg(0x22, etm_config.etm_addr_access_type[2]);
-	etm_write_reg(0x23, etm_config.etm_addr_access_type[3]);
-	etm_write_reg(0x24, etm_config.etm_addr_access_type[4]);
-	etm_write_reg(0x25, etm_config.etm_addr_access_type[5]);
-	etm_write_reg(0x26, etm_config.etm_addr_access_type[6]);
-	etm_write_reg(0x27, etm_config.etm_addr_access_type[7]);
-	etm_write_reg(0x30, etm_config.etm_data_comp_value[0]);
-	etm_write_reg(0x32, etm_config.etm_data_comp_value[1]);
-	etm_write_reg(0x40, etm_config.etm_data_comp_mask[0]);
-	etm_write_reg(0x42, etm_config.etm_data_comp_mask[1]);
-	etm_write_reg(0x50, etm_config.etm_counter_reload_value[0]);
-	etm_write_reg(0x51, etm_config.etm_counter_reload_value[1]);
-	etm_write_reg(0x54, etm_config.etm_counter_enable[0]);
-	etm_write_reg(0x55, etm_config.etm_counter_enable[1]);
-	etm_write_reg(0x58, etm_config.etm_counter_reload_event[0]);
-	etm_write_reg(0x59, etm_config.etm_counter_reload_event[1]);
-	etm_write_reg(0x60, etm_config.etm_60_seq_event_1_to_2);
-	etm_write_reg(0x61, etm_config.etm_61_seq_event_2_to_1);
-	etm_write_reg(0x62, etm_config.etm_62_seq_event_2_to_3);
-	etm_write_reg(0x63, etm_config.etm_63_seq_event_3_to_1);
-	etm_write_reg(0x64, etm_config.etm_64_seq_event_3_to_2);
-	etm_write_reg(0x65, etm_config.etm_65_seq_event_1_to_3);
-	etm_write_reg(0x68, etm_external_output);
-	etm_write_reg(0x6c, etm_config.etm_6c_cid_comp_value_1);
-	etm_write_reg(0x6f, etm_config.etm_6f_cid_comp_mask);
-	etm_write_reg(0x78, etm_config.etm_78_sync_freq);
+	etm_write(etm_trigger, ETMTRIGGER);
+	etm_write(etm_config.etm_06_te_start_stop, ETMTSSCR);
+	etm_write(etm_config.etm_07_te_single_addr_comp, ETMTECR2);
+	etm_write(etm_config.etm_08_te_event, ETMTEEVR);
+	etm_write(etm_config.etm_09_te_control, ETMTECR1);
+	etm_write(etm_config.etm_0a_fifofull_region, ETMFFRR);
+	etm_write(etm_config.etm_0b_fifofull_level, ETMFFLR);
+	etm_write(etm_config.etm_0c_vd_event, ETMVDEVR);
+	etm_write(etm_config.etm_0d_vd_single_addr_comp, ETMVDCR1);
+	etm_write(etm_config.etm_0e_vd_mmd, ETMVDCR2);
+	etm_write(etm_config.etm_0f_vd_control, ETMVDCR3);
+	etm_write(etm_config.etm_addr_comp_value[0], ETMACVR0);
+	etm_write(etm_config.etm_addr_comp_value[1], ETMACVR1);
+	etm_write(etm_config.etm_addr_comp_value[2], ETMACVR2);
+	etm_write(etm_config.etm_addr_comp_value[3], ETMACVR3);
+	etm_write(etm_config.etm_addr_comp_value[4], ETMACVR4);
+	etm_write(etm_config.etm_addr_comp_value[5], ETMACVR5);
+	etm_write(etm_config.etm_addr_comp_value[6], ETMACVR6);
+	etm_write(etm_config.etm_addr_comp_value[7], ETMACVR7);
+	etm_write(etm_config.etm_addr_access_type[0], ETMACTR0);
+	etm_write(etm_config.etm_addr_access_type[1], ETMACTR1);
+	etm_write(etm_config.etm_addr_access_type[2], ETMACTR2);
+	etm_write(etm_config.etm_addr_access_type[3], ETMACTR3);
+	etm_write(etm_config.etm_addr_access_type[4], ETMACTR4);
+	etm_write(etm_config.etm_addr_access_type[5], ETMACTR5);
+	etm_write(etm_config.etm_addr_access_type[6], ETMACTR6);
+	etm_write(etm_config.etm_addr_access_type[7], ETMACTR7);
+	etm_write(etm_config.etm_data_comp_value[0], ETMDCVR0);
+	etm_write(etm_config.etm_data_comp_value[1], ETMDCVR1);
+	etm_write(etm_config.etm_data_comp_mask[0], ETMDCMR0);
+	etm_write(etm_config.etm_data_comp_mask[1], ETMDCMR1);
+	etm_write(etm_config.etm_counter_reload_value[0], ETMCNTRLDVR0);
+	etm_write(etm_config.etm_counter_reload_value[1], ETMCNTRLDVR1);
+	etm_write(etm_config.etm_counter_enable[0], ETMCNTENR0);
+	etm_write(etm_config.etm_counter_enable[1], ETMCNTENR1);
+	etm_write(etm_config.etm_counter_reload_event[0], ETMCNTRLDEVR0);
+	etm_write(etm_config.etm_counter_reload_event[1], ETMCNTRLDEVR1);
+	etm_write(etm_config.etm_60_seq_event_1_to_2, ETMSQ12EVR);
+	etm_write(etm_config.etm_61_seq_event_2_to_1, ETMSQ21EVR);
+	etm_write(etm_config.etm_62_seq_event_2_to_3, ETMSQ23EVR);
+	etm_write(etm_config.etm_63_seq_event_3_to_1, ETMSQ31EVR);
+	etm_write(etm_config.etm_64_seq_event_3_to_2, ETMSQ32EVR);
+	etm_write(etm_config.etm_65_seq_event_1_to_3, ETMSQ13EVR);
+	etm_write(etm_external_output, ETMEXTOUTEVR0);
+	etm_write(etm_config.etm_6c_cid_comp_value_1, ETMCIDCVR0);
+	etm_write(etm_config.etm_6f_cid_comp_mask, ETMCIDCMR);
+	etm_write(etm_config.etm_78_sync_freq, ETMSYNCFR);
 
 	/* Note that we must enable the ETB before we enable the ETM if we
 	 * want to capture the "always true" trigger event. */
@@ -373,20 +408,14 @@
 
 static void __cpu_disable_trace(void *unused)
 {
-	uint32_t etm_control;
-
 	get_cpu();
-	etm_read_reg(0xC5); /* clear sticky bit in PDSR */
 
 	__cpu_disable_etm();
 
 	/* program trace enable to be low by using always false event */
-	etm_write_reg(0x08, 0x6F | BIT(14));
-
-	/* set the powerdown bit */
-	etm_control = etm_read_reg(ETM_REG_CONTROL);
-	etm_control |= ETM_CONTROL_POWERDOWN;
-	etm_write_reg(ETM_REG_CONTROL, etm_control);
+	etm_write(0x6F | BIT(14), ETMTEEVR);
+	/* vote for ETM power/clock disable */
+	__cpu_set_etm_pwrdwn();
 
 	__cpu_disable_etb();
 
@@ -402,7 +431,8 @@
 		/* This register is accessible from either core.
 		 * CPU1_extout[0] -> CPU0_extin[0]
 		 * CPU_extout[0] -> CPU1_extin[0] */
-		l2tevselr0_write(0x00000001);
+		asm volatile("mcr p15, 3, %0, c15, c5, 2" : : "r" (0x1));
+		asm volatile("isb");
 	}
 
 	get_cpu();
@@ -456,14 +486,14 @@
 	uint32_t prim_len;
 	uint32_t uptime = 0;
 
-	etb_control = etm_read_reg(ETB_REG_CONTROL);
+	etb_control = etb_read(ETB_REG_CONTROL);
 	etb_control |= AIR;
-	etm_write_reg(ETB_REG_CONTROL, etb_control);
+	etb_write(etb_control, ETB_REG_CONTROL);
 
-	if (etm_read_reg(ETB_REG_STATUS) & OV)
+	if (etb_read(ETB_REG_STATUS) & OV)
 		full_slots = ETB_RAM_SLOTS;
 	else
-		full_slots = etm_read_reg(ETB_REG_ADDRESS) >> 2;
+		full_slots = etb_read(ETB_REG_ADDRESS) >> 2;
 
 	prim_len = 28 + (full_slots * 4);
 
@@ -473,23 +503,24 @@
 	emit_log_char((prim_len >> 0) & 0xFF);
 	emit_log_word(uptime);
 	emit_log_word(ETB_DUMP_MSG_ID);
-	emit_log_word(etm_read_reg(ETM_REG_CONTROL));
+	emit_log_word(etm_read(ETMCR));
 	emit_log_word(etm_config.etb_init_ptr >> 2);
-	emit_log_word(etm_read_reg(ETB_REG_ADDRESS) >> 2);
-	emit_log_word((etm_read_reg(ETB_REG_STATUS) & OV) >> 21);
+	emit_log_word(etb_read(ETB_REG_ADDRESS) >> 2);
+	emit_log_word((etb_read(ETB_REG_STATUS) & OV) >> 21);
 
-	etm_write_reg(ETB_REG_ADDRESS, 0x00000000);
+	etb_write(0x00000000, ETB_REG_ADDRESS);
 	for (i = 0; i < full_slots; i++)
-		emit_log_word(etm_read_reg(ETB_REG_DATA));
+		emit_log_word(etb_read(ETB_REG_DATA));
 }
 
+/* This should match the number of ETM registers being dumped below */
+#define ETM_NUM_REGS_TO_DUMP	54
 static void generate_etm_dump(void)
 {
-	uint32_t i;
 	uint32_t prim_len;
 	uint32_t uptime = 0;
 
-	prim_len = 12 + (4 * ETM_NUM_REGS);
+	prim_len = 12 + (4 * ETM_NUM_REGS_TO_DUMP);
 
 	emit_log_char((DATALOG_SYNC >> 8) & 0xFF);
 	emit_log_char((DATALOG_SYNC >> 0) & 0xFF);
@@ -498,19 +529,65 @@
 	emit_log_word(uptime);
 	emit_log_word(ETM_DUMP_MSG_ID);
 
-	/* do not disturb ETB_REG_ADDRESS by reading ETB_REG_DATA */
-	for (i = 0; i < ETM_NUM_REGS; i++)
-		if (i == ETB_REG_DATA)
-			emit_log_word(0);
-		else
-			emit_log_word(etm_read_reg(i));
+	emit_log_word(etm_read(ETMCR));
+	emit_log_word(etm_read(ETMSR));
+	emit_log_word(etb_read(ETB_REG_CONTROL));
+	emit_log_word(etb_read(ETB_REG_STATUS));
+	emit_log_word(etb_read(ETB_REG_COUNT));
+	emit_log_word(etb_read(ETB_REG_ADDRESS));
+	emit_log_word(0); /* don't read ETB_REG_DATA, changes ETB_REG_ADDRESS */
+	emit_log_word(etm_read(ETMTRIGGER));
+	emit_log_word(etm_read(ETMTSSCR));
+	emit_log_word(etm_read(ETMTECR2));
+	emit_log_word(etm_read(ETMTEEVR));
+	emit_log_word(etm_read(ETMTECR1));
+	emit_log_word(etm_read(ETMFFRR));
+	emit_log_word(etm_read(ETMFFLR));
+	emit_log_word(etm_read(ETMVDEVR));
+	emit_log_word(etm_read(ETMVDCR1));
+	emit_log_word(etm_read(ETMVDCR2));
+	emit_log_word(etm_read(ETMVDCR3));
+	emit_log_word(etm_read(ETMACVR0));
+	emit_log_word(etm_read(ETMACVR1));
+	emit_log_word(etm_read(ETMACVR2));
+	emit_log_word(etm_read(ETMACVR3));
+	emit_log_word(etm_read(ETMACVR4));
+	emit_log_word(etm_read(ETMACVR5));
+	emit_log_word(etm_read(ETMACVR6));
+	emit_log_word(etm_read(ETMACVR7));
+	emit_log_word(etm_read(ETMACTR0));
+	emit_log_word(etm_read(ETMACTR1));
+	emit_log_word(etm_read(ETMACTR2));
+	emit_log_word(etm_read(ETMACTR3));
+	emit_log_word(etm_read(ETMACTR4));
+	emit_log_word(etm_read(ETMACTR5));
+	emit_log_word(etm_read(ETMACTR6));
+	emit_log_word(etm_read(ETMACTR7));
+	emit_log_word(etm_read(ETMDCVR0));
+	emit_log_word(etm_read(ETMDCVR1));
+	emit_log_word(etm_read(ETMDCMR0));
+	emit_log_word(etm_read(ETMDCMR1));
+	emit_log_word(etm_read(ETMCNTRLDVR0));
+	emit_log_word(etm_read(ETMCNTRLDVR1));
+	emit_log_word(etm_read(ETMCNTENR0));
+	emit_log_word(etm_read(ETMCNTENR1));
+	emit_log_word(etm_read(ETMCNTRLDEVR0));
+	emit_log_word(etm_read(ETMCNTRLDEVR1));
+	emit_log_word(etm_read(ETMSQ12EVR));
+	emit_log_word(etm_read(ETMSQ21EVR));
+	emit_log_word(etm_read(ETMSQ23EVR));
+	emit_log_word(etm_read(ETMSQ31EVR));
+	emit_log_word(etm_read(ETMSQ32EVR));
+	emit_log_word(etm_read(ETMSQ13EVR));
+	emit_log_word(etm_read(ETMEXTOUTEVR0));
+	emit_log_word(etm_read(ETMCIDCVR0));
+	emit_log_word(etm_read(ETMCIDCMR));
+	emit_log_word(etm_read(ETMSYNCFR));
 }
 
 static void dump_all(void *unused)
 {
 	get_cpu();
-	etm_read_reg(0xC5); /* clear sticky bit in PDSR in case
-			     * trace hasn't been enabled yet. */
 	__cpu_disable_etb();
 	generate_etm_dump();
 	generate_etb_dump();
@@ -900,34 +977,10 @@
 	.fops = &etm_dev_fops,
 };
 
-/* etm_save_reg_check and etm_restore_reg_check should be fast
- *
- * These functions will be called either from:
- * 1. per_cpu idle thread context for idle power collapses.
- * 2. per_cpu idle thread context for hotplug/suspend power collapse for
- *    nonboot cpus.
- * 3. suspend thread context for core0.
- *
- * In all cases we are guaranteed to be running on the same cpu for the
- * entire duration.
- *
- * Another assumption is that etm registers won't change after trace_enabled
- * is set. Current usage model guarantees this doesn't happen.
- *
- * Also disabling all types of power_collapses when enabling and disabling
- * trace provides mutual exclusion to be able to safely access
- * ptm.trace_enabled here.
- */
-void etm_save_reg_check(void)
+static void __cpu_clear_sticky(void *unused)
 {
-	if (trace_enabled)
-		etm_save_reg();
-}
-
-void etm_restore_reg_check(void)
-{
-	if (trace_enabled)
-		etm_restore_reg();
+	etm_read(ETMPDSR); /* clear sticky bit in PDSR */
+	isb();
 }
 
 static int __init etm_init(void)
@@ -949,6 +1002,12 @@
 	pm_qos_add_request(&etm_qos_req, PM_QOS_CPU_DMA_LATENCY,
 						PM_QOS_DEFAULT_VALUE);
 
+	/* No need to explicity turn on ETM clock since CP14 access go
+	 * through via the autoclock turn on/off
+	 */
+	__cpu_clear_sticky(NULL);
+	smp_call_function(__cpu_clear_sticky, NULL, 1);
+
 	cpu_to_dump = next_cpu_to_dump = 0;
 
 	pr_info("ETM/ETB intialized.\n");
diff --git a/arch/arm/mach-msm/gpio.c b/arch/arm/mach-msm/gpio.c
index a942862..ea9e0d5 100644
--- a/arch/arm/mach-msm/gpio.c
+++ b/arch/arm/mach-msm/gpio.c
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/gpio.c
  *
  * Copyright (C) 2007 Google, Inc.
- * 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
@@ -20,6 +20,7 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 #include <asm/mach/irq.h>
 #include <mach/gpiomux.h>
 #include "gpio_hw.h"
@@ -486,37 +487,6 @@
 	}
 }
 
-static int __init msm_init_gpio(void)
-{
-	int i, j = 0;
-
-	for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
-		if (i - FIRST_GPIO_IRQ >=
-			msm_gpio_chips[j].chip.base +
-			msm_gpio_chips[j].chip.ngpio)
-			j++;
-		irq_set_chip_data(i, &msm_gpio_chips[j]);
-		irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
-					 handle_edge_irq);
-		set_irq_flags(i, IRQF_VALID);
-	}
-
-	irq_set_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
-	irq_set_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
-
-	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
-		spin_lock_init(&msm_gpio_chips[i].lock);
-		__raw_writel(0, msm_gpio_chips[i].regs.int_en);
-		gpiochip_add(&msm_gpio_chips[i].chip);
-	}
-
-	mb();
-	irq_set_irq_wake(INT_GPIO_GROUP1, 1);
-	irq_set_irq_wake(INT_GPIO_GROUP2, 2);
-	return 0;
-}
-
-postcore_initcall(msm_init_gpio);
 
 int gpio_tlmm_config(unsigned config, unsigned disable)
 {
@@ -643,3 +613,52 @@
 	*out = msm_chip->regs.out;
 	*offset = gpio - msm_chip->chip.base;
 }
+
+static int __devinit msm_gpio_probe(struct platform_device *dev)
+{
+	int i, j = 0;
+	int grp_irq;
+
+	for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+		if (i - FIRST_GPIO_IRQ >=
+			msm_gpio_chips[j].chip.base +
+			msm_gpio_chips[j].chip.ngpio)
+			j++;
+		irq_set_chip_data(i, &msm_gpio_chips[j]);
+		irq_set_chip_and_handler(i, &msm_gpio_irq_chip,
+					 handle_edge_irq);
+		set_irq_flags(i, IRQF_VALID);
+	}
+
+	for (i = 0; i < dev->num_resources; i++) {
+		grp_irq = platform_get_irq(dev, i);
+		if (grp_irq < 0)
+			return -ENXIO;
+
+		irq_set_chained_handler(grp_irq, msm_gpio_irq_handler);
+		irq_set_irq_wake(grp_irq, (i + 1));
+	}
+
+	for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+		spin_lock_init(&msm_gpio_chips[i].lock);
+		__raw_writel(0, msm_gpio_chips[i].regs.int_en);
+		gpiochip_add(&msm_gpio_chips[i].chip);
+	}
+
+	mb();
+	return 0;
+}
+
+static struct platform_driver msm_gpio_driver = {
+	.probe = msm_gpio_probe,
+	.driver = {
+		.name = "msmgpio",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init msm_gpio_init(void)
+{
+	return platform_driver_register(&msm_gpio_driver);
+}
+postcore_initcall(msm_gpio_init);
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index 86a2374..743e3de 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -13,9 +13,10 @@
 #include <asm/cacheflush.h>
 #include <asm/vfp.h>
 
+#include <mach/pm.h>
+
 #include "qdss.h"
 #include "spm.h"
-#include "pm.h"
 
 extern volatile int pen_release;
 
@@ -113,8 +114,7 @@
 		init_completion(&dev->cpu_killed);
 		return 0;
 	}
-	etm_restore_reg_check();
-	msm_restore_jtag_debug();
+	msm_jtag_restore_state();
 #ifdef CONFIG_VFP
 	vfp_reinit();
 #endif
diff --git a/arch/arm/mach-msm/idle-v7.S b/arch/arm/mach-msm/idle-v7.S
index e855357..660884c 100644
--- a/arch/arm/mach-msm/idle-v7.S
+++ b/arch/arm/mach-msm/idle-v7.S
@@ -2,7 +2,7 @@
  * Idle processing for ARMv7-based Qualcomm SoCs.
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2009, 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -82,11 +82,8 @@
 	stmia   r0!, {r1-r3}
 #endif
 
-#ifdef CONFIG_MSM_DEBUG_ACROSS_PC
-	bl      msm_save_jtag_debug
-#endif
-#ifdef CONFIG_MSM_TRACE_ACROSS_PC
-	bl      etm_save_reg_check
+#ifdef CONFIG_MSM_JTAG
+	bl      msm_jtag_save_state
 #endif
 
 	ldr	r0, =msm_pm_flush_l2_flag
@@ -128,11 +125,8 @@
 #if defined(CONFIG_MSM_FIQ_SUPPORT)
 	cpsie   f
 #endif
-#ifdef CONFIG_MSM_TRACE_ACROSS_PC
-	bl	etm_restore_reg_check
-#endif
-#ifdef CONFIG_MSM_DEBUG_ACROSS_PC
-	bl	msm_restore_jtag_debug
+#ifdef CONFIG_MSM_JTAG
+	bl	msm_jtag_restore_state
 #endif
 	ldr     r0, =saved_state        /* restore registers */
 #if (NR_CPUS >= 2)
@@ -225,11 +219,8 @@
 #endif
 	stmfd   sp!, {lr}
 	bl      v7_flush_kern_cache_all
-#ifdef CONFIG_MSM_TRACE_ACROSS_PC
-	bl      etm_restore_reg_check
-#endif
-#ifdef CONFIG_MSM_DEBUG_ACROSS_PC
-	bl      msm_restore_jtag_debug
+#ifdef CONFIG_MSM_JTAG
+	bl      msm_jtag_restore_state
 #endif
 	ldmfd   sp!, {lr}
 	mov     r0, #1
diff --git a/arch/arm/mach-msm/idle_stats.c b/arch/arm/mach-msm/idle_stats.c
index 6f80e32..f4d3a27 100644
--- a/arch/arm/mach-msm/idle_stats.c
+++ b/arch/arm/mach-msm/idle_stats.c
@@ -27,7 +27,7 @@
 #include <asm/uaccess.h>
 
 #include "idle_stats.h"
-#include "cpuidle.h"
+#include <mach/cpuidle.h>
 
 /******************************************************************************
  * Debug Definitions
diff --git a/arch/arm/mach-msm/idle_stats_device.c b/arch/arm/mach-msm/idle_stats_device.c
index 5118672..5c4b6a3 100644
--- a/arch/arm/mach-msm/idle_stats_device.c
+++ b/arch/arm/mach-msm/idle_stats_device.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
@@ -43,8 +43,8 @@
 	return ret;
 }
 
-static void update_event
-	(struct msm_idle_stats_device *device, __u32 event)
+void msm_idle_stats_update_event(struct msm_idle_stats_device *device,
+	__u32 event)
 {
 	__u32 wake_up = !device->stats->event;
 
@@ -52,6 +52,7 @@
 	if (wake_up)
 		wake_up_interruptible(&device->wait);
 }
+EXPORT_SYMBOL(msm_idle_stats_update_event);
 
 static enum hrtimer_restart msm_idle_stats_busy_timer(struct hrtimer *timer)
 {
@@ -64,7 +65,8 @@
 	 * assured that we have exclusive access to the event at this time.
 	 */
 	hrtimer_set_expires(&device->busy_timer, us_to_ktime(0));
-	update_event(device, MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED);
+	msm_idle_stats_update_event(device,
+		MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED);
 	return HRTIMER_NORESTART;
 }
 
@@ -108,10 +110,11 @@
 	device->stats->nr_collected++;
 
 	if (device->stats->nr_collected == MSM_IDLE_STATS_NR_MAX_INTERVALS) {
-		update_event(device, MSM_IDLE_STATS_EVENT_COLLECTION_FULL);
+		msm_idle_stats_update_event(device,
+			MSM_IDLE_STATS_EVENT_COLLECTION_FULL);
 	} else if (device->stats->nr_collected ==
 				((MSM_IDLE_STATS_NR_MAX_INTERVALS * 3) / 4)) {
-		update_event(device,
+		msm_idle_stats_update_event(device,
 			MSM_IDLE_STATS_EVENT_COLLECTION_NEARLY_FULL);
 	}
 }
@@ -233,7 +236,7 @@
 			MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED) {
 			device->stats->event &=
 				~MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED;
-			update_event(device,
+			msm_idle_stats_update_event(device,
 				MSM_IDLE_STATS_EVENT_BUSY_TIMER_EXPIRED_RESET);
 		} else if (ktime_to_us(device->busy_timer_interval) > 0) {
 			ktime_t busy_timer = device->busy_timer_interval;
diff --git a/arch/arm/mach-msm/cpuidle.h b/arch/arm/mach-msm/include/mach/cpuidle.h
similarity index 98%
rename from arch/arm/mach-msm/cpuidle.h
rename to arch/arm/mach-msm/include/mach/cpuidle.h
index 37b8d00..b0aa902 100644
--- a/arch/arm/mach-msm/cpuidle.h
+++ b/arch/arm/mach-msm/include/mach/cpuidle.h
@@ -15,7 +15,7 @@
 #define __ARCH_ARM_MACH_MSM_CPUIDLE_H
 
 #include <linux/notifier.h>
-#include "pm.h"
+#include <mach/pm.h>
 
 struct msm_cpuidle_state {
 	unsigned int cpu;
diff --git a/arch/arm/mach-msm/include/mach/ion.h b/arch/arm/mach-msm/include/mach/ion.h
index 4d12249..9fbc720 100644
--- a/arch/arm/mach-msm/include/mach/ion.h
+++ b/arch/arm/mach-msm/include/mach/ion.h
@@ -1,6 +1,6 @@
 /**
  *
- * 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,4 +20,10 @@
 	ION_SMI_TYPE,
 };
 
+enum ion_permission_type {
+	IPT_TYPE_MM_CARVEOUT = 0,
+	IPT_TYPE_MFC_SHAREDMEM = 1,
+	IPT_TYPE_MDP_WRITEBACK = 2,
+};
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-9615.h b/arch/arm/mach-msm/include/mach/irqs-9615.h
index 74e5847..5fba24e 100644
--- a/arch/arm/mach-msm/include/mach/irqs-9615.h
+++ b/arch/arm/mach-msm/include/mach/irqs-9615.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
@@ -179,8 +179,9 @@
 #define TLMM_MSM_DIR_CONN_IRQ_21		(GIC_SPI_START + 224)
 #define MSM_SPARE0_IRQ				(GIC_SPI_START + 225)
 #define PMIC_SEC_IRQ_N				(GIC_SPI_START + 226)
+#define USB_HSIC_IRQ				(GIC_SPI_START + 232)
 
-#define NR_MSM_IRQS 256
+#define NR_MSM_IRQS 288
 #define NR_GPIO_IRQS 88
 #define NR_PM8018_IRQS 256
 #define NR_BOARD_IRQS NR_PM8018_IRQS
diff --git a/arch/arm/mach-msm/include/mach/msm_bus_board.h b/arch/arm/mach-msm/include/mach/msm_bus_board.h
index ddbf959..1a87d9c 100644
--- a/arch/arm/mach-msm/include/mach/msm_bus_board.h
+++ b/arch/arm/mach-msm/include/mach/msm_bus_board.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
@@ -237,6 +237,7 @@
 	MSM_BUS_MMSS_SLAVE_FAB_APPS,
 	MSM_BUS_MMSS_SLAVE_FAB_APPS_1,
 	MSM_BUS_SLAVE_MM_IMEM,
+	MSM_BUS_SLAVE_CRYPTO,
 
 	MSM_BUS_SLAVE_SPDM,
 	MSM_BUS_SLAVE_RPM,
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-9615.h b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
index dda5f50..fc9b198 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap-9615.h
@@ -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.
  * Author: Brian Swetland <swetland@google.com>
  *
  * This software is licensed under the terms of the GNU General Public
@@ -77,6 +77,9 @@
 #define MSM9615_HSUSB_PHYS		0x12500000
 #define MSM9615_HSUSB_SIZE		SZ_4K
 
+#define MSM9615_HSIC_PHYS		0x12540000
+#define MSM9615_HSIC_SIZE		SZ_4K
+
 #define MSM9615_QFPROM_PHYS		0x00700000
 #define MSM9615_QFPROM_SIZE		SZ_4K
 
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/include/mach/pm.h
similarity index 92%
rename from arch/arm/mach-msm/pm.h
rename to arch/arm/mach-msm/include/mach/pm.h
index 813ece1..689cd17 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/include/mach/pm.h
@@ -51,11 +51,19 @@
 				staying in the low power mode saves power */
 };
 
+struct msm_pm_sleep_status_data {
+	void *base_addr;
+	uint32_t cpu_offset;
+	uint32_t mask;
+};
+
 void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
 int msm_pm_idle_prepare(struct cpuidle_device *dev);
 int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
 void msm_pm_cpu_enter_lowpower(unsigned int cpu);
 
+void __init msm_pm_init_sleep_status_data(
+		struct msm_pm_sleep_status_data *sleep_data);
 #ifdef CONFIG_PM
 void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
 #else
diff --git a/arch/arm/mach-msm/include/mach/rpm-9615.h b/arch/arm/mach-msm/include/mach/rpm-9615.h
index f6a0e16..68fd6ce 100644
--- a/arch/arm/mach-msm/include/mach/rpm-9615.h
+++ b/arch/arm/mach-msm/include/mach/rpm-9615.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
@@ -191,17 +191,17 @@
 /* VDD values are in microvolts */
 #define MSM_RPMRS_VDD_MASK  0x7fffff
 enum {
-	MSM_RPMRS_VDD_MEM_RET_LOW = 750500,
-	MSM_RPMRS_VDD_MEM_RET_HIGH = 1050000,
-	MSM_RPMRS_VDD_MEM_ACTIVE = 1050000,
-	MSM_RPMRS_VDD_MEM_MAX = 1250000,
+	MSM_RPMRS_VDD_MEM_RET_LOW	=  750000,
+	MSM_RPMRS_VDD_MEM_RET_HIGH	=  750000,
+	MSM_RPMRS_VDD_MEM_ACTIVE	= 1050000,
+	MSM_RPMRS_VDD_MEM_MAX		= 1150000,
 };
 
 enum {
-	MSM_RPMRS_VDD_DIG_RET_LOW = 537500,
-	MSM_RPMRS_VDD_DIG_RET_HIGH = 950000,
-	MSM_RPMRS_VDD_DIG_ACTIVE = 1050000,
-	MSM_RPMRS_VDD_DIG_MAX = 1250000,
+	MSM_RPMRS_VDD_DIG_RET_LOW	=  500000,
+	MSM_RPMRS_VDD_DIG_RET_HIGH	=  750000,
+	MSM_RPMRS_VDD_DIG_ACTIVE	=  950000,
+	MSM_RPMRS_VDD_DIG_MAX		= 1150000,
 };
 
 /* RPM status ID enum */
diff --git a/arch/arm/mach-msm/include/mach/scm.h b/arch/arm/mach-msm/include/mach/scm.h
index a332b67..6aa944f 100644
--- a/arch/arm/mach-msm/include/mach/scm.h
+++ b/arch/arm/mach-msm/include/mach/scm.h
@@ -21,6 +21,7 @@
 #define SCM_SVC_SSD			0x7
 #define SCM_SVC_FUSE			0x8
 #define SCM_SVC_PWR			0x9
+#define SCM_SVC_CP			0xC
 #define SCM_SVC_TZSCHEDULER		0xFC
 
 #ifdef CONFIG_MSM_SCM
diff --git a/arch/arm/mach-msm/jtag-v7.S b/arch/arm/mach-msm/jtag-v7.S
deleted file mode 100644
index 975ddf7..0000000
--- a/arch/arm/mach-msm/jtag-v7.S
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Copyright (c) 2009, 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.
- *
- */
-
-/*
- * JTAG support functions for ARMv7-based Qualcomm SoCs.
- */
-#include <linux/linkage.h>
-#include <asm/assembler.h>
-#include <linux/threads.h>
-
-#if (NR_CPUS > 2)
-#error code only tested for 1 or 2 CPUs.
-#endif
-
-/* Add 1 slot to store the register count for JTAG state */
-#define MAX_JTAG_REGS (32 + 1)
-#define MAX_DEBUG_STATE_SIZE (MAX_JTAG_REGS * 4)
-
-ENTRY(msm_save_jtag_debug)
-	ldr     r3, =dbg_state        /* store state at dbg_state */
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r2, c0, c0, 5 /* MPIDR */
-	and	r2, r2, #15	      /* What CPU am I */
-	ldr     r1, =MAX_DEBUG_STATE_SIZE
-	mul     r2, r2, r1
-	add	r3, r3, r2
-#endif
-
-	/* save jtag state */
-	ldr     r1, =0xc5ACCE55       /* set DBGOSLAR lock */
-	mcr     p14, 0, r1, c1, c0, 4
-	isb
-
-	mrc     p14, 0, r1, c1, c2, 4 /* DBGOSSRR state register count */
-	cmp     r1, #(MAX_JTAG_REGS)  /* check for state overflow */
-	movgt   r1, #0                /* if not enough space, don't save */
-	str     r1, [r3], #4          /* save count for restore */
-
-1:	cmp     r1, #0
-	mrcne   p14, 0, r2, c1, c2, 4 /* DBGOSSRR state value */
-	strne   r2, [r3], #4          /* push value */
-	subne   r1, r1, #1
-	bne     1b
-
-	mcr     p14, 0, r1, c1, c0, 4 /* unlock DBGOSLAR */
-	isb
-
-	bx      lr
-
-ENTRY(msm_restore_jtag_debug)
-	/* restore debug registers after power collapse  */
-	ldr     r3, =dbg_state        /* load state from dbg_state */
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r2, c0, c0, 5 /* MPIDR */
-	and	r2, r2, #15	      /* What CPU am I */
-	ldr     r1, =MAX_DEBUG_STATE_SIZE
-	mul     r2, r2, r1
-	add	r3, r3, r2
-#endif
-
-	/* restore jtag state */
-	mrc     p14, 0, r1, c1, c5, 4 /* clear sticky power down bit */
-	isb
-	ldr     r1, =0xc5ACCE55       /* set DBGOSLAR lock */
-	mcr     p14, 0, r1, c1, c0, 4
-	isb
-
-	mrc     p14, 0, r1, c1, c2, 4 /* DBGOSSRR dummy read (required)*/
-	ldr     r1, [r3], #4          /* load saved count */
-	cmp     r1, #0                /* skip if none stored */
-	beq     msm_pm_dbg_restore_end
-
-	/* restores debug state except DBGDSCR */
-1:	ldr     r2, [r3], #4
-	cmp     r1, #0x10             /* DBGDSCR special case */
-	biceq   r2, r2, #0xc000       /* DBGDSCR = DBGDSCR & ~0xc000 */
-	mcr     p14, 0, r2, c1, c2, 4 /* DBGOSSRR write state value */
-	subs    r1, r1, #1
-	bne     1b
-
-	ldr     r3, =dbg_state        /* load state from dbg_state */
-#if (NR_CPUS >= 2)
-	mrc	p15, 0, r2, c0, c0, 5 /* MPIDR */
-	and	r2, r2, #15	      /* What CPU am I */
-	ldr     r1, =MAX_DEBUG_STATE_SIZE
-	mul     r2, r2, r1
-	add	r3, r3, r2
-#endif
-	ldr     r1, =0xc5ACCE55       /* set DBGOSLAR lock */
-	mcr     p14, 0, r1, c1, c0, 4
-	isb
-
-	mrc     p14, 0, r1, c1, c2, 4 /* DBGOSSRR dummy read (required)*/
-	ldr     r1, [r3], #4          /* load saved count */
-	cmp     r1, #0                /* skip if none stored */
-	beq     msm_pm_dbg_restore_end
-
-	/* second pass to restore debug state including DBGDSCR */
-1:	ldr     r2, [r3], #4
-	mcr     p14, 0, r2, c1, c2, 4 /* DBGOSSRR write state value */
-	subs    r1,r1,#1
-	bne     1b
-msm_pm_dbg_restore_end:
-	mcr     p14, 0, r1, c1, c0, 4 /* unlock DBGOSLAR */
-	isb
-
-	bx      lr
-
-
-	.data
-
-dbg_state:
-	.space	MAX_DEBUG_STATE_SIZE * NR_CPUS
diff --git a/arch/arm/mach-msm/jtag.c b/arch/arm/mach-msm/jtag.c
new file mode 100644
index 0000000..f720fa9
--- /dev/null
+++ b/arch/arm/mach-msm/jtag.c
@@ -0,0 +1,1108 @@
+/* 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/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+
+#include "qdss.h"
+#include "cp14.h"
+
+#define MAX_DBG_REGS		(90)
+#define MAX_DBG_STATE_SIZE	(MAX_DBG_REGS * num_possible_cpus())
+#define MAX_ETM_REGS		(78)
+#define MAX_ETM_STATE_SIZE	(MAX_ETM_REGS * num_possible_cpus())
+
+#define DBGDSCR_MASK		(0x6C30FC3C)
+#define CPMR_ETMCLKEN		(0x8)
+
+
+struct dbg_ctx {
+	uint8_t		arch;
+	bool		arch_supported;
+	uint8_t		nr_wp;
+	uint8_t		nr_bp;
+	uint8_t		nr_ctx_cmp;
+	uint32_t	*state;
+};
+static struct dbg_ctx dbg;
+
+struct etm_ctx {
+	uint8_t		arch;
+	bool		arch_supported;
+	uint8_t		nr_addr_cmp;
+	uint8_t		nr_cntr;
+	uint8_t		nr_ext_inp;
+	uint8_t		nr_ext_out;
+	uint8_t		nr_ctxid_cmp;
+	uint32_t	*state;
+};
+static struct etm_ctx etm;
+
+static int dbg_read_bxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_read(DBGBVR0);
+		state[i++] = dbg_read(DBGBCR0);
+		break;
+	case 1:
+		state[i++] = dbg_read(DBGBVR1);
+		state[i++] = dbg_read(DBGBCR1);
+		break;
+	case 2:
+		state[i++] = dbg_read(DBGBVR2);
+		state[i++] = dbg_read(DBGBCR2);
+		break;
+	case 3:
+		state[i++] = dbg_read(DBGBVR3);
+		state[i++] = dbg_read(DBGBVR3);
+		break;
+	case 4:
+		state[i++] = dbg_read(DBGBVR4);
+		state[i++] = dbg_read(DBGBCR4);
+		break;
+	case 5:
+		state[i++] = dbg_read(DBGBVR5);
+		state[i++] = dbg_read(DBGBVR5);
+		break;
+	case 6:
+		state[i++] = dbg_read(DBGBVR6);
+		state[i++] = dbg_read(DBGBCR6);
+		break;
+	case 7:
+		state[i++] = dbg_read(DBGBVR7);
+		state[i++] = dbg_read(DBGBCR7);
+		break;
+	case 8:
+		state[i++] = dbg_read(DBGBVR8);
+		state[i++] = dbg_read(DBGBCR8);
+		break;
+	case 9:
+		state[i++] = dbg_read(DBGBVR9);
+		state[i++] = dbg_read(DBGBCR9);
+		break;
+	case 10:
+		state[i++] = dbg_read(DBGBVR10);
+		state[i++] = dbg_read(DBGBCR10);
+		break;
+	case 11:
+		state[i++] = dbg_read(DBGBVR11);
+		state[i++] = dbg_read(DBGBCR11);
+		break;
+	case 12:
+		state[i++] = dbg_read(DBGBVR12);
+		state[i++] = dbg_read(DBGBCR12);
+		break;
+	case 13:
+		state[i++] = dbg_read(DBGBVR13);
+		state[i++] = dbg_read(DBGBCR13);
+		break;
+	case 14:
+		state[i++] = dbg_read(DBGBVR14);
+		state[i++] = dbg_read(DBGBCR14);
+		break;
+	case 15:
+		state[i++] = dbg_read(DBGBVR15);
+		state[i++] = dbg_read(DBGBCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_bxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGBVR0);
+		dbg_write(state[i++], DBGBCR0);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGBVR1);
+		dbg_write(state[i++], DBGBCR1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGBVR2);
+		dbg_write(state[i++], DBGBCR2);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGBVR3);
+		dbg_write(state[i++], DBGBVR3);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGBVR4);
+		dbg_write(state[i++], DBGBCR4);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGBVR5);
+		dbg_write(state[i++], DBGBVR5);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGBVR6);
+		dbg_write(state[i++], DBGBCR6);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGBVR7);
+		dbg_write(state[i++], DBGBCR7);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGBVR8);
+		dbg_write(state[i++], DBGBCR8);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGBVR9);
+		dbg_write(state[i++], DBGBCR9);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGBVR10);
+		dbg_write(state[i++], DBGBCR10);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGBVR11);
+		dbg_write(state[i++], DBGBCR11);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGBVR12);
+		dbg_write(state[i++], DBGBCR12);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGBVR13);
+		dbg_write(state[i++], DBGBCR13);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGBVR14);
+		dbg_write(state[i++], DBGBCR14);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGBVR15);
+		dbg_write(state[i++], DBGBCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_read_wxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = dbg_read(DBGWVR0);
+		state[i++] = dbg_read(DBGWCR0);
+		break;
+	case 1:
+		state[i++] = dbg_read(DBGWVR1);
+		state[i++] = dbg_read(DBGWCR1);
+		break;
+	case 2:
+		state[i++] = dbg_read(DBGWVR2);
+		state[i++] = dbg_read(DBGWCR2);
+		break;
+	case 3:
+		state[i++] = dbg_read(DBGWVR3);
+		state[i++] = dbg_read(DBGWCR3);
+		break;
+	case 4:
+		state[i++] = dbg_read(DBGWVR4);
+		state[i++] = dbg_read(DBGWCR4);
+		break;
+	case 5:
+		state[i++] = dbg_read(DBGWVR5);
+		state[i++] = dbg_read(DBGWCR5);
+		break;
+	case 6:
+		state[i++] = dbg_read(DBGWVR6);
+		state[i++] = dbg_read(DBGWCR6);
+		break;
+	case 7:
+		state[i++] = dbg_read(DBGWVR7);
+		state[i++] = dbg_read(DBGWCR7);
+		break;
+	case 8:
+		state[i++] = dbg_read(DBGWVR8);
+		state[i++] = dbg_read(DBGWCR8);
+		break;
+	case 9:
+		state[i++] = dbg_read(DBGWVR9);
+		state[i++] = dbg_read(DBGWCR9);
+		break;
+	case 10:
+		state[i++] = dbg_read(DBGWVR10);
+		state[i++] = dbg_read(DBGWCR10);
+		break;
+	case 11:
+		state[i++] = dbg_read(DBGWVR11);
+		state[i++] = dbg_read(DBGWCR11);
+		break;
+	case 12:
+		state[i++] = dbg_read(DBGWVR12);
+		state[i++] = dbg_read(DBGWCR12);
+		break;
+	case 13:
+		state[i++] = dbg_read(DBGWVR13);
+		state[i++] = dbg_read(DBGWCR13);
+		break;
+	case 14:
+		state[i++] = dbg_read(DBGWVR14);
+		state[i++] = dbg_read(DBGWCR14);
+		break;
+	case 15:
+		state[i++] = dbg_read(DBGWVR15);
+		state[i++] = dbg_read(DBGWCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int dbg_write_wxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		dbg_write(state[i++], DBGWVR0);
+		dbg_write(state[i++], DBGWCR0);
+		break;
+	case 1:
+		dbg_write(state[i++], DBGWVR1);
+		dbg_write(state[i++], DBGWCR1);
+		break;
+	case 2:
+		dbg_write(state[i++], DBGWVR2);
+		dbg_write(state[i++], DBGWCR2);
+		break;
+	case 3:
+		dbg_write(state[i++], DBGWVR3);
+		dbg_write(state[i++], DBGWCR3);
+		break;
+	case 4:
+		dbg_write(state[i++], DBGWVR4);
+		dbg_write(state[i++], DBGWCR4);
+		break;
+	case 5:
+		dbg_write(state[i++], DBGWVR5);
+		dbg_write(state[i++], DBGWCR5);
+		break;
+	case 6:
+		dbg_write(state[i++], DBGWVR6);
+		dbg_write(state[i++], DBGWCR6);
+		break;
+	case 7:
+		dbg_write(state[i++], DBGWVR7);
+		dbg_write(state[i++], DBGWCR7);
+		break;
+	case 8:
+		dbg_write(state[i++], DBGWVR8);
+		dbg_write(state[i++], DBGWCR8);
+		break;
+	case 9:
+		dbg_write(state[i++], DBGWVR9);
+		dbg_write(state[i++], DBGWCR9);
+		break;
+	case 10:
+		dbg_write(state[i++], DBGWVR10);
+		dbg_write(state[i++], DBGWCR10);
+		break;
+	case 11:
+		dbg_write(state[i++], DBGWVR11);
+		dbg_write(state[i++], DBGWCR11);
+		break;
+	case 12:
+		dbg_write(state[i++], DBGWVR12);
+		dbg_write(state[i++], DBGWCR12);
+		break;
+	case 13:
+		dbg_write(state[i++], DBGWVR13);
+		dbg_write(state[i++], DBGWCR13);
+		break;
+	case 14:
+		dbg_write(state[i++], DBGWVR14);
+		dbg_write(state[i++], DBGWCR14);
+		break;
+	case 15:
+		dbg_write(state[i++], DBGWVR15);
+		dbg_write(state[i++], DBGWCR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline bool dbg_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case ARM_DEBUG_ARCH_V7_1:
+	case ARM_DEBUG_ARCH_V7:
+	case ARM_DEBUG_ARCH_V7B:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+
+static inline void dbg_save_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V7_1:
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving debug registers. It prevents accidental
+		 * modification of the debug regs by the external debugger.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		/* We skip saving DBGBXVRn since not supported on Krait */
+
+		dbg.state[i++] = dbg_read(DBGWFAR);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_read_bxr(dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_read_wxr(dbg.state, i, j);
+		dbg.state[i++] = dbg_read(DBGVCR);
+		dbg.state[i++] = dbg_read(DBGCLAIMCLR);
+		dbg.state[i++] = dbg_read(DBGDTRTXext);
+		dbg.state[i++] = dbg_read(DBGDTRRXext);
+		dbg.state[i++] = dbg_read(DBGDSCRext);
+
+		/* Set the OS double lock */
+		isb();
+		dbg_write(0x1, DBGOSDLR);
+		isb();
+		break;
+	case ARM_DEBUG_ARCH_V7B:
+	case ARM_DEBUG_ARCH_V7:
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving dbg registers. It prevents accidental
+		 * modification of the dbg regs by the external debugger
+		 * and resets the internal counter.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		cnt = dbg_read(DBGOSSRR); /* save count for restore */
+		/* MAX_DBG_REGS = no of dbg regs + 1 (for storing the reg count)
+		 * check for state overflow, if not enough space, don't save
+		 */
+		if (cnt >= MAX_DBG_REGS)
+			cnt = 0;
+		dbg.state[i++] = cnt;
+		for (j = 0; j < cnt; j++)
+			dbg.state[i++] = dbg_read(DBGOSSRR);
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+								__func__);
+	}
+}
+
+static inline void dbg_restore_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_DBG_REGS;
+
+	switch (dbg.arch) {
+	case ARM_DEBUG_ARCH_V7_1:
+		/* Clear the OS double lock */
+		isb();
+		dbg_write(0x0, DBGOSDLR);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is included to ensure it is set.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		/* We skip restoring DBGBXVRn since not supported on Krait */
+
+		dbg_write(dbg.state[i++], DBGWFAR);
+		for (j = 0; j < dbg.nr_bp; j++)
+			i = dbg_write_bxr(dbg.state, i, j);
+		for (j = 0; j < dbg.nr_wp; j++)
+			i = dbg_write_wxr(dbg.state, i, j);
+		dbg_write(dbg.state[i++], DBGVCR);
+		dbg_write(dbg.state[i++], DBGCLAIMSET);
+		dbg_write(dbg.state[i++], DBGDTRTXext);
+		dbg_write(dbg.state[i++], DBGDTRRXext);
+		dbg_write(dbg.state[i++] & DBGDSCR_MASK, DBGDSCRext);
+
+		isb();
+		dbg_write(0x0, DBGOSLAR);
+		isb();
+		break;
+	case ARM_DEBUG_ARCH_V7B:
+	case ARM_DEBUG_ARCH_V7:
+		/* Clear sticky bit */
+		dbg_read(DBGPRSR);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is required to reset the internal counter used
+		 * for DBG state restore.
+		 */
+		dbg_write(OSLOCK_MAGIC, DBGOSLAR);
+		isb();
+
+		dbg_read(DBGOSSRR); /* dummy read of OSSRR */
+		cnt = dbg.state[i++];
+		for (j = 0; j < cnt; j++) {
+			/* DBGDSCR special case
+			 * DBGDSCR = DBGDSCR & DBGDSCR_MASK
+			 */
+			if (j == 20)
+				dbg_write(dbg.state[i++] & DBGDSCR_MASK,
+								DBGOSSRR);
+			else
+				dbg_write(dbg.state[i++], DBGOSSRR);
+		}
+
+		/* Clear the OS lock */
+		isb();
+		dbg_write(0x0, DBGOSLAR);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported dbg arch %d in %s\n", dbg.arch,
+								__func__);
+	}
+
+}
+
+static int etm_read_acxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMACVR0);
+		state[i++] = etm_read(ETMACTR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMACVR1);
+		state[i++] = etm_read(ETMACTR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMACVR2);
+		state[i++] = etm_read(ETMACTR2);
+		break;
+	case 3:
+		state[i++] = etm_read(ETMACVR3);
+		state[i++] = etm_read(ETMACTR3);
+		break;
+	case 4:
+		state[i++] = etm_read(ETMACVR4);
+		state[i++] = etm_read(ETMACTR4);
+		break;
+	case 5:
+		state[i++] = etm_read(ETMACVR5);
+		state[i++] = etm_read(ETMACTR5);
+		break;
+	case 6:
+		state[i++] = etm_read(ETMACVR6);
+		state[i++] = etm_read(ETMACTR6);
+		break;
+	case 7:
+		state[i++] = etm_read(ETMACVR7);
+		state[i++] = etm_read(ETMACTR7);
+		break;
+	case 8:
+		state[i++] = etm_read(ETMACVR8);
+		state[i++] = etm_read(ETMACTR8);
+		break;
+	case 9:
+		state[i++] = etm_read(ETMACVR9);
+		state[i++] = etm_read(ETMACTR9);
+		break;
+	case 10:
+		state[i++] = etm_read(ETMACVR10);
+		state[i++] = etm_read(ETMACTR10);
+		break;
+	case 11:
+		state[i++] = etm_read(ETMACVR11);
+		state[i++] = etm_read(ETMACTR11);
+		break;
+	case 12:
+		state[i++] = etm_read(ETMACVR12);
+		state[i++] = etm_read(ETMACTR12);
+		break;
+	case 13:
+		state[i++] = etm_read(ETMACVR13);
+		state[i++] = etm_read(ETMACTR13);
+		break;
+	case 14:
+		state[i++] = etm_read(ETMACVR14);
+		state[i++] = etm_read(ETMACTR14);
+		break;
+	case 15:
+		state[i++] = etm_read(ETMACVR15);
+		state[i++] = etm_read(ETMACTR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_acxr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMACVR0);
+		etm_write(state[i++], ETMACTR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMACVR1);
+		etm_write(state[i++], ETMACTR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMACVR2);
+		etm_write(state[i++], ETMACTR2);
+		break;
+	case 3:
+		etm_write(state[i++], ETMACVR3);
+		etm_write(state[i++], ETMACTR3);
+		break;
+	case 4:
+		etm_write(state[i++], ETMACVR4);
+		etm_write(state[i++], ETMACTR4);
+		break;
+	case 5:
+		etm_write(state[i++], ETMACVR5);
+		etm_write(state[i++], ETMACTR5);
+		break;
+	case 6:
+		etm_write(state[i++], ETMACVR6);
+		etm_write(state[i++], ETMACTR6);
+		break;
+	case 7:
+		etm_write(state[i++], ETMACVR7);
+		etm_write(state[i++], ETMACTR7);
+		break;
+	case 8:
+		etm_write(state[i++], ETMACVR8);
+		etm_write(state[i++], ETMACTR8);
+		break;
+	case 9:
+		etm_write(state[i++], ETMACVR9);
+		etm_write(state[i++], ETMACTR9);
+		break;
+	case 10:
+		etm_write(state[i++], ETMACVR10);
+		etm_write(state[i++], ETMACTR10);
+		break;
+	case 11:
+		etm_write(state[i++], ETMACVR11);
+		etm_write(state[i++], ETMACTR11);
+		break;
+	case 12:
+		etm_write(state[i++], ETMACVR12);
+		etm_write(state[i++], ETMACTR12);
+		break;
+	case 13:
+		etm_write(state[i++], ETMACVR13);
+		etm_write(state[i++], ETMACTR13);
+		break;
+	case 14:
+		etm_write(state[i++], ETMACVR14);
+		etm_write(state[i++], ETMACTR14);
+		break;
+	case 15:
+		etm_write(state[i++], ETMACVR15);
+		etm_write(state[i++], ETMACTR15);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_cntx(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMCNTRLDVR0);
+		state[i++] = etm_read(ETMCNTENR0);
+		state[i++] = etm_read(ETMCNTRLDEVR0);
+		state[i++] = etm_read(ETMCNTVR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMCNTRLDVR1);
+		state[i++] = etm_read(ETMCNTENR1);
+		state[i++] = etm_read(ETMCNTRLDEVR1);
+		state[i++] = etm_read(ETMCNTVR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMCNTRLDVR2);
+		state[i++] = etm_read(ETMCNTENR2);
+		state[i++] = etm_read(ETMCNTRLDEVR2);
+		state[i++] = etm_read(ETMCNTVR2);
+		break;
+	case 3:
+		state[i++] = etm_read(ETMCNTRLDVR3);
+		state[i++] = etm_read(ETMCNTENR3);
+		state[i++] = etm_read(ETMCNTRLDEVR3);
+		state[i++] = etm_read(ETMCNTVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_cntx(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMCNTRLDVR0);
+		etm_write(state[i++], ETMCNTENR0);
+		etm_write(state[i++], ETMCNTRLDEVR0);
+		etm_write(state[i++], ETMCNTVR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMCNTRLDVR1);
+		etm_write(state[i++], ETMCNTENR1);
+		etm_write(state[i++], ETMCNTRLDEVR1);
+		etm_write(state[i++], ETMCNTVR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMCNTRLDVR2);
+		etm_write(state[i++], ETMCNTENR2);
+		etm_write(state[i++], ETMCNTRLDEVR2);
+		etm_write(state[i++], ETMCNTVR2);
+		break;
+	case 3:
+		etm_write(state[i++], ETMCNTRLDVR3);
+		etm_write(state[i++], ETMCNTENR3);
+		etm_write(state[i++], ETMCNTRLDEVR3);
+		etm_write(state[i++], ETMCNTVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_extoutevr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMEXTOUTEVR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMEXTOUTEVR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMEXTOUTEVR2);
+		break;
+	case 3:
+		state[i++] = etm_read(ETMEXTOUTEVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_extoutevr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMEXTOUTEVR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMEXTOUTEVR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMEXTOUTEVR2);
+		break;
+	case 3:
+		etm_write(state[i++], ETMEXTOUTEVR3);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_read_cidcvr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		state[i++] = etm_read(ETMCIDCVR0);
+		break;
+	case 1:
+		state[i++] = etm_read(ETMCIDCVR1);
+		break;
+	case 2:
+		state[i++] = etm_read(ETMCIDCVR2);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static int etm_write_cidcvr(uint32_t *state, int i, int j)
+{
+	switch (j) {
+	case 0:
+		etm_write(state[i++], ETMCIDCVR0);
+		break;
+	case 1:
+		etm_write(state[i++], ETMCIDCVR1);
+		break;
+	case 2:
+		etm_write(state[i++], ETMCIDCVR2);
+		break;
+	default:
+		pr_err_ratelimited("idx %d out of bounds in %s\n", j, __func__);
+	}
+	return i;
+}
+
+static inline void etm_clk_disable(void)
+{
+	uint32_t cpmr;
+
+	isb();
+	asm volatile("mrc p15, 7, %0, c15, c0, 5" : "=r" (cpmr));
+	cpmr  &= ~CPMR_ETMCLKEN;
+	asm volatile("mcr p15, 7, %0, c15, c0, 5" : : "r" (cpmr));
+}
+
+static inline void etm_clk_enable(void)
+{
+	uint32_t cpmr;
+
+	asm volatile("mrc p15, 7, %0, c15, c0, 5" : "=r" (cpmr));
+	cpmr  |= CPMR_ETMCLKEN;
+	asm volatile("mcr p15, 7, %0, c15, c0, 5" : : "r" (cpmr));
+	isb();
+}
+
+static inline bool etm_arch_supported(uint8_t arch)
+{
+	switch (arch) {
+	case ETM_ARCH_V3_3:
+	case PFT_ARCH_V1_1:
+		break;
+	default:
+		return false;
+	}
+	return true;
+}
+
+static inline void etm_save_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_ETM_REGS;
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	switch (etm.arch) {
+	case PFT_ARCH_V1_1:
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving etm registers. It prevents accidental
+		 * modification of the etm regs by the external debugger.
+		 *
+		 * We don't poll for ETMSR[1] since it doesn't get set
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		etm.state[i++] = etm_read(ETMCR);
+		etm.state[i++] = etm_read(ETMTRIGGER);
+		etm.state[i++] = etm_read(ETMSR);
+		etm.state[i++] = etm_read(ETMTSSCR);
+		etm.state[i++] = etm_read(ETMTEEVR);
+		etm.state[i++] = etm_read(ETMTECR1);
+		etm.state[i++] = etm_read(ETMFFLR);
+		for (j = 0; j < etm.nr_addr_cmp; j++)
+			i = etm_read_acxr(etm.state, i, j);
+		for (j = 0; j < etm.nr_cntr; j++)
+			i = etm_read_cntx(etm.state, i, j);
+		etm.state[i++] = etm_read(ETMSQ12EVR);
+		etm.state[i++] = etm_read(ETMSQ21EVR);
+		etm.state[i++] = etm_read(ETMSQ23EVR);
+		etm.state[i++] = etm_read(ETMSQ31EVR);
+		etm.state[i++] = etm_read(ETMSQ32EVR);
+		etm.state[i++] = etm_read(ETMSQ13EVR);
+		etm.state[i++] = etm_read(ETMSQR);
+		for (j = 0; j < etm.nr_ext_out; j++)
+			i = etm_read_extoutevr(etm.state, i, j);
+		for (j = 0; j < etm.nr_ctxid_cmp; j++)
+			i = etm_read_cidcvr(etm.state, i, j);
+		etm.state[i++] = etm_read(ETMCIDCMR);
+		etm.state[i++] = etm_read(ETMSYNCFR);
+		etm.state[i++] = etm_read(ETMEXTINSELR);
+		etm.state[i++] = etm_read(ETMTSEVR);
+		etm.state[i++] = etm_read(ETMAUXCR);
+		etm.state[i++] = etm_read(ETMTRACEIDR);
+		etm.state[i++] = etm_read(ETMVMIDCVR);
+		etm.state[i++] = etm_read(ETMCLAIMCLR);
+		break;
+	case ETM_ARCH_V3_3:
+		/* In ETMv3.3, it is possible for the coresight lock to be
+		 * implemented for CP14 interface but we currently assume that
+		 * it is not, so no need to unlock and lock coresight lock
+		 * (ETMLAR).
+		 *
+		 * Also since save and restore is not conditional i.e. always
+		 * occurs when enabled, there is no need to clear the sticky
+		 * PDSR bit while saving. It will be cleared during boot up/init
+		 * and then by the restore procedure.
+		 */
+
+		/* Set OS lock to inform the debugger that the OS is in the
+		 * process of saving etm registers. It prevents accidental
+		 * modification of the etm regs by the external debugger
+		 * and resets the internal counter.
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		cnt = etm_read(ETMOSSRR); /* save count for restore */
+		/* MAX_ETM_REGS = no of etm regs + 1 (for storing the reg count)
+		 * check for state overflow, if not enough space, don't save
+		 */
+		if (cnt >= MAX_ETM_REGS)
+			cnt = 0;
+		etm.state[i++] = cnt;
+		for (j = 0; j < cnt; j++)
+			etm.state[i++] = etm_read(ETMOSSRR);
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
+								__func__);
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+}
+
+static inline void etm_restore_state(int cpu)
+{
+	int i, j, cnt;
+
+	i = cpu * MAX_ETM_REGS;
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	switch (etm.arch) {
+	case PFT_ARCH_V1_1:
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is included to ensure it is set.
+		 *
+		 * We don't poll for ETMSR[1] since it doesn't get set
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		etm_write(etm.state[i++], ETMCR);
+		etm_write(etm.state[i++], ETMTRIGGER);
+		etm_write(etm.state[i++], ETMSR);
+		etm_write(etm.state[i++], ETMTSSCR);
+		etm_write(etm.state[i++], ETMTEEVR);
+		etm_write(etm.state[i++], ETMTECR1);
+		etm_write(etm.state[i++], ETMFFLR);
+		for (j = 0; j < etm.nr_addr_cmp; j++)
+			i = etm_write_acxr(etm.state, i, j);
+		for (j = 0; j < etm.nr_cntr; j++)
+			i = etm_write_cntx(etm.state, i, j);
+		etm_write(etm.state[i++], ETMSQ12EVR);
+		etm_write(etm.state[i++], ETMSQ21EVR);
+		etm_write(etm.state[i++], ETMSQ23EVR);
+		etm_write(etm.state[i++], ETMSQ32EVR);
+		etm_write(etm.state[i++], ETMSQ13EVR);
+		etm_write(etm.state[i++], ETMSQ31EVR);
+		etm_write(etm.state[i++], ETMSQR);
+		for (j = 0; j < etm.nr_ext_out; j++)
+			i = etm_write_extoutevr(etm.state, i, j);
+		for (j = 0; j < etm.nr_ctxid_cmp; j++)
+			i = etm_write_cidcvr(etm.state, i, j);
+		etm_write(etm.state[i++], ETMCIDCMR);
+		etm_write(etm.state[i++], ETMSYNCFR);
+		etm_write(etm.state[i++], ETMEXTINSELR);
+		etm_write(etm.state[i++], ETMTSEVR);
+		etm_write(etm.state[i++], ETMAUXCR);
+		etm_write(etm.state[i++], ETMTRACEIDR);
+		etm_write(etm.state[i++], ETMVMIDCVR);
+		etm_write(etm.state[i++], ETMCLAIMSET);
+
+		/* Clear the OS lock */
+		isb();
+		etm_write(0x0, ETMOSLAR);
+		isb();
+		break;
+	case ETM_ARCH_V3_3:
+		/* In ETMv3.3, it is possible for the coresight lock to be
+		 * implemented for CP14 interface but we currently assume that
+		 * it is not, so no need to unlock and lock coresight lock
+		 * (ETMLAR).
+		 */
+
+		/* Clear sticky bit */
+		etm_read(ETMPDSR);
+		isb();
+
+		/* Set OS lock. Lock will already be set after power collapse
+		 * but this write is required to reset the internal counter used
+		 * for ETM state restore.
+		 */
+		etm_write(OSLOCK_MAGIC, ETMOSLAR);
+		isb();
+
+		etm_read(ETMOSSRR); /* dummy read of OSSRR */
+		cnt = etm.state[i++];
+		for (j = 0; j < cnt; j++)
+			etm_write(etm.state[i++], ETMOSSRR);
+
+		/* Clear the OS lock */
+		isb();
+		etm_write(0x0, ETMOSLAR);
+		isb();
+		break;
+	default:
+		pr_err_ratelimited("unsupported etm arch %d in %s\n", etm.arch,
+								__func__);
+	}
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+}
+
+/* msm_jtag_save_state and msm_jtag_restore_state should be fast
+ *
+ * These functions will be called either from:
+ * 1. per_cpu idle thread context for idle power collapses.
+ * 2. per_cpu idle thread context for hotplug/suspend power collapse for
+ *    nonboot cpus.
+ * 3. suspend thread context for core0.
+ *
+ * In all cases we are guaranteed to be running on the same cpu for the
+ * entire duration.
+ */
+void msm_jtag_save_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	if (dbg.arch_supported)
+		dbg_save_state(cpu);
+	if (etm.arch_supported)
+		etm_save_state(cpu);
+}
+
+void msm_jtag_restore_state(void)
+{
+	int cpu;
+
+	cpu = raw_smp_processor_id();
+
+	if (dbg.arch_supported)
+		dbg_restore_state(cpu);
+	if (etm.arch_supported)
+		etm_restore_state(cpu);
+}
+
+static int __init msm_jtag_dbg_init(void)
+{
+	int ret;
+	uint32_t dbgdidr;
+
+	/* This will run on core0 so use it to populate parameters */
+
+	/* Populate dbg_ctx data */
+	dbgdidr = dbg_read(DBGDIDR);
+	dbg.arch = BMVAL(dbgdidr, 16, 19);
+	dbg.arch_supported = dbg_arch_supported(dbg.arch);
+	if (!dbg.arch_supported) {
+		pr_info("dbg arch %u not supported\n", dbg.arch);
+		goto dbg_out;
+	}
+	dbg.nr_ctx_cmp = BMVAL(dbgdidr, 20, 23);
+	dbg.nr_bp = BMVAL(dbgdidr, 24, 27);
+	dbg.nr_wp = BMVAL(dbgdidr, 28, 31);
+
+	/* Allocate dbg state save space */
+	dbg.state = kzalloc(MAX_DBG_STATE_SIZE * sizeof(uint32_t), GFP_KERNEL);
+	if (!dbg.state) {
+		ret = -ENOMEM;
+		goto dbg_err;
+	}
+dbg_out:
+	return 0;
+dbg_err:
+	return ret;
+}
+arch_initcall(msm_jtag_dbg_init);
+
+static int __init msm_jtag_etm_init(void)
+{
+	int ret;
+	uint32_t etmidr;
+	uint32_t etmccr;
+
+	/* Vote for ETM power/clock enable */
+	etm_clk_enable();
+
+	/* Clear sticky bit in PDSR - required for ETMv3.3 (8660) */
+	etm_read(ETMPDSR);
+	isb();
+
+	/* Populate etm_ctx data */
+	etmidr = etm_read(ETMIDR);
+	etm.arch = BMVAL(etmidr, 4, 11);
+	etm.arch_supported = etm_arch_supported(etm.arch);
+	if (!etm.arch_supported) {
+		pr_info("etm arch %u not supported\n", etm.arch);
+		goto etm_out;
+	}
+	etmccr = etm_read(ETMCCR);
+	etm.nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+	etm.nr_cntr = BMVAL(etmccr, 13, 15);
+	etm.nr_ext_inp = BMVAL(etmccr, 17, 19);
+	etm.nr_ext_out = BMVAL(etmccr, 20, 22);
+	etm.nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+
+	/* Vote for ETM power/clock disable */
+	etm_clk_disable();
+
+	/* Allocate etm state save space */
+	etm.state = kzalloc(MAX_ETM_STATE_SIZE * sizeof(uint32_t), GFP_KERNEL);
+	if (!etm.state) {
+		ret = -ENOMEM;
+		goto etm_err;
+	}
+etm_out:
+	return 0;
+etm_err:
+	return ret;
+}
+arch_initcall(msm_jtag_etm_init);
diff --git a/arch/arm/mach-msm/lpass-8960.c b/arch/arm/mach-msm/lpass-8960.c
index 294e9c0..11b9092 100644
--- a/arch/arm/mach-msm/lpass-8960.c
+++ b/arch/arm/mach-msm/lpass-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
@@ -17,6 +17,7 @@
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/err.h>
 
 #include <mach/irqs.h>
 #include <mach/scm.h>
@@ -26,6 +27,7 @@
 
 #include "smd_private.h"
 #include "ramdump.h"
+#include "sysmon.h"
 
 #define SCM_Q6_NMI_CMD                  0x1
 #define MODULE_NAME			"lpass_8960"
@@ -42,6 +44,28 @@
 static struct lpass_ssr lpass_ssr_8960;
 static int q6_crash_shutdown;
 
+static int riva_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *ss_handle)
+{
+	int ret;
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("%s: R-Notify: Shutdown started\n", __func__);
+		ret = sysmon_send_event(SYSMON_SS_LPASS, "wcnss",
+				SUBSYS_BEFORE_SHUTDOWN);
+		if (ret < 0)
+			pr_err("%s: sysmon_send_event error %d", __func__,
+				ret);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static void *ssr_notif_hdle;
+static struct notifier_block rnb = {
+	.notifier_call = riva_notifier_cb,
+};
+
 static void lpass_fatal_fn(struct work_struct *work)
 {
 	pr_err("%s %s: Watchdog bite received from Q6!\n", MODULE_NAME,
@@ -178,6 +202,17 @@
 		ret = -ENOMEM;
 		goto out;
 	}
+	ssr_notif_hdle = subsys_notif_register_notifier("riva",
+							&rnb);
+	if (IS_ERR(ssr_notif_hdle) < 0) {
+		ret = PTR_ERR(ssr_notif_hdle);
+		pr_err("%s: subsys_register_notifier for Riva: err = %d\n",
+			__func__, ret);
+		iounmap(q6_wakeup_intr);
+		free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
+		goto out;
+	}
+
 	pr_info("%s: lpass SSR driver init'ed.\n", __func__);
 out:
 	return ret;
@@ -185,6 +220,7 @@
 
 static void __exit lpass_fatal_exit(void)
 {
+	subsys_notif_unregister_notifier(ssr_notif_hdle, &rnb);
 	iounmap(q6_wakeup_intr);
 	free_irq(LPASS_Q6SS_WDOG_EXPIRED, NULL);
 }
diff --git a/arch/arm/mach-msm/msm_bus/Makefile b/arch/arm/mach-msm/msm_bus/Makefile
index c1155c9..018e2a6 100644
--- a/arch/arm/mach-msm/msm_bus/Makefile
+++ b/arch/arm/mach-msm/msm_bus/Makefile
@@ -5,4 +5,5 @@
 obj-$(CONFIG_ARCH_MSM8X60) += msm_bus_board_8660.o
 obj-$(CONFIG_ARCH_MSM8960) += msm_bus_board_8960.o
 obj-$(CONFIG_ARCH_MSM9615) += msm_bus_board_9615.o
+obj-$(CONFIG_ARCH_APQ8064) += msm_bus_board_8064.o
 obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
new file mode 100644
index 0000000..d05eaea
--- /dev/null
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_board_8064.c
@@ -0,0 +1,973 @@
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#include <mach/board.h>
+#include <mach/rpm.h>
+#include "msm_bus_core.h"
+
+#define NMASTERS 54
+#define NSLAVES 75
+#define NFAB_8064 5
+
+enum msm_bus_fabric_tiered_slave_type {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0 = 1,
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_1,
+	MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,
+
+	MSM_BUS_TIERED_SLAVE_MM_IMEM = 1,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_1,
+
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0 = 1,
+	MSM_BUS_TIERED_SLAVE_EBI1_CH1,
+	MSM_BUS_TIERED_SLAVE_KMPSS_L2,
+};
+
+enum msm_bus_8064_master_ports_type {
+	MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB = 0,
+	MSM_BUS_MASTER_PORT_SPS,
+	MSM_BUS_MASTER_PORT_ADM_PORT0,
+	MSM_BUS_MASTER_PORT_ADM_PORT1,
+	MSM_BUS_MASTER_PORT_LPASS_PROC,
+	MSM_BUS_MASTER_PORT_GSS_NAV,
+	MSM_BUS_MASTER_PORT_PCIE,
+	MSM_BUS_MASTER_PORT_RIVA,
+	MSM_BUS_MASTER_PORT_SATA,
+	MSM_BUS_MASTER_PORT_LPASS,
+	MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,
+	MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,
+	MSM_BUS_SYSTEM_MASTER_PORT_CRYPTO,
+
+	MSM_BUS_MASTER_PORT_MDP_PORT0 = 0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+	MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,
+	MSM_BUS_MASTER_PORT_ROTATOR,
+	MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT1,
+	MSM_BUS_MASTER_PORT_JPEG_DEC,
+	MSM_BUS_MASTER_PORT_VIDEO_CAP,
+	MSM_BUS_MASTER_PORT_VFE,
+	MSM_BUS_MASTER_PORT_VPE,
+	MSM_BUS_MASTER_PORT_JPEG_ENC,
+	MSM_BUS_MASTER_PORT_VIDEO_DEC,
+	MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,
+	MSM_BUS_MASTER_PORT_VIDEO_ENC,
+
+	MSM_BUS_MASTER_PORT_KMPSS_M0 = 0,
+	MSM_BUS_MASTER_PORT_KMPSS_M1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_1,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_1,
+
+};
+
+enum msm_bus_8064_slave_ports_type {
+	MSM_BUS_SLAVE_PORT_MM_IMEM = 0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_1,
+
+	MSM_BUS_SLAVE_PORT_EBI1_CH0 = 0,
+	MSM_BUS_SLAVE_PORT_EBI1_CH1,
+	MSM_BUS_SLAVE_PORT_KMPSS_L2,
+	MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,
+	MSM_BUS_SLAVE_PORT_SYSTEM_FAB,
+
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0 = 0,
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_1,
+	MSM_BUS_SLAVE_PORT_SPS,
+	MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,
+	MSM_BUS_SLAVE_PORT_CORESIGHT,
+	MSM_BUS_SLAVE_PORT_PCIE,
+	MSM_BUS_SLAVE_PORT_KMPSS,
+	MSM_BUS_SLAVE_PORT_GSS,
+	MSM_BUS_SLAVE_PORT_LPASS,
+	MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,
+	MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,
+	MSM_BUS_SLAVE_PORT_RIVA,
+	MSM_BUS_SLAVE_PORT_SATA,
+	MSM_BUS_SLAVE_PORT_CRYPTO,
+};
+
+static int tier2[] = {MSM_BUS_BW_TIER2,};
+static uint32_t master_iids[NMASTERS];
+static uint32_t slave_iids[NSLAVES];
+
+static int mport_kmpss_m0[] = {MSM_BUS_MASTER_PORT_KMPSS_M0,};
+static int mport_kmpss_m1[] = {MSM_BUS_MASTER_PORT_KMPSS_M1,};
+
+static int mmss_mport_apps_fab[] = {MSM_BUS_MMSS_MASTER_PORT_APPS_FAB,};
+static int system_mport_appss_fab[] = {MSM_BUS_SYSTEM_MASTER_PORT_APPSS_FAB,};
+static int sport_ebi1_ch0[] = {
+	MSM_BUS_SLAVE_PORT_EBI1_CH0,
+	MSM_BUS_SLAVE_PORT_EBI1_CH1,
+};
+static int sport_ebi1_ch1[] = {MSM_BUS_SLAVE_PORT_EBI1_CH1,};
+static int sport_kmpss_l2[] = {MSM_BUS_SLAVE_PORT_KMPSS_L2,};
+static int appss_sport_mmss_fab[] = {MSM_BUS_APPSS_SLAVE_PORT_MMSS_FAB,};
+static int sport_system_fab[] = {MSM_BUS_SLAVE_PORT_SYSTEM_FAB,};
+
+static int tiered_slave_ebi1_ch0[] = {
+	MSM_BUS_TIERED_SLAVE_EBI1_CH0,
+	MSM_BUS_TIERED_SLAVE_EBI1_CH1,
+};
+static int tiered_slave_ebi1_ch1[] = {MSM_BUS_TIERED_SLAVE_EBI1_CH1,};
+
+static int tiered_slave_kmpss[] = {MSM_BUS_TIERED_SLAVE_KMPSS_L2,};
+
+static struct msm_bus_node_info apps_fabric_info[] = {
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M0,
+		.masterp = mport_kmpss_m0,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_AMPSS_M1,
+		.masterp = mport_kmpss_m1,
+		.num_mports = ARRAY_SIZE(mport_kmpss_m1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH0,
+		.slavep = sport_ebi1_ch0,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch0),
+		.tier = tiered_slave_ebi1_ch0,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch0),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI_CH1,
+		.slavep = sport_ebi1_ch1,
+		.num_sports = ARRAY_SIZE(sport_ebi1_ch1),
+		.tier = tiered_slave_ebi1_ch1,
+		.num_tiers = ARRAY_SIZE(tiered_slave_ebi1_ch1),
+		.buswidth = 8,
+		.slaveclk[DUAL_CTX] = "mem_clk",
+		.slaveclk[ACTIVE_CTX] = "mem_a_clk",
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS_L2,
+		.slavep = sport_kmpss_l2,
+		.num_sports = ARRAY_SIZE(sport_kmpss_l2),
+		.tier = tiered_slave_kmpss,
+		.num_tiers = ARRAY_SIZE(tiered_slave_kmpss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_MMSS,
+		.gateway = 1,
+		.slavep = appss_sport_mmss_fab,
+		.num_sports = ARRAY_SIZE(appss_sport_mmss_fab),
+		.masterp = mmss_mport_apps_fab,
+		.num_mports = ARRAY_SIZE(mmss_mport_apps_fab),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = sport_system_fab,
+		.num_sports = ARRAY_SIZE(sport_system_fab),
+		.masterp = system_mport_appss_fab,
+		.num_mports = ARRAY_SIZE(system_mport_appss_fab),
+		.buswidth = 8,
+	},
+};
+
+static int mport_sps[] = {MSM_BUS_MASTER_PORT_SPS,};
+static int mport_adm_port0[] = {MSM_BUS_MASTER_PORT_ADM_PORT0,};
+static int mport_adm_port1[] = {MSM_BUS_MASTER_PORT_ADM_PORT1,};
+static int mport_gss_nav[] = {MSM_BUS_MASTER_PORT_GSS_NAV,};
+static int mport_pcie[] = {MSM_BUS_MASTER_PORT_PCIE,};
+static int mport_lpass_proc[] = {MSM_BUS_MASTER_PORT_LPASS_PROC,};
+static int mport_sata[] = {MSM_BUS_MASTER_PORT_SATA,};
+
+static int mport_riva[] = {MSM_BUS_MASTER_PORT_RIVA,};
+static int mport_crypto[] = {MSM_BUS_SYSTEM_MASTER_PORT_CRYPTO,};
+static int mport_lpass[] = {MSM_BUS_MASTER_PORT_LPASS,};
+static int system_mport_mmss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_MMSS_FPB,};
+static int system_mport_adm_ahb_ci[] = {MSM_BUS_SYSTEM_MASTER_PORT_ADM_AHB_CI,};
+static int appss_mport_fab_system[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_SYSTEM_1
+};
+static int mport_system_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_SYSTEM_FPB,};
+static int system_mport_cpss_fpb[] = {MSM_BUS_SYSTEM_MASTER_PORT_CPSS_FPB,};
+
+static int system_sport_appss_fab[] = {
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_0,
+	MSM_BUS_SYSTEM_SLAVE_PORT_APPSS_FAB_1
+};
+static int system_sport_system_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_SYSTEM_FPB,};
+static int system_sport_cpss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_CPSS_FPB,};
+static int sport_sps[] = {MSM_BUS_SLAVE_PORT_SPS,};
+static int sport_system_imem[] = {MSM_BUS_SLAVE_PORT_SYSTEM_IMEM,};
+static int sport_coresight[] = {MSM_BUS_SLAVE_PORT_CORESIGHT,};
+static int sport_crypto[] = {MSM_BUS_SLAVE_PORT_CRYPTO,};
+static int sport_riva[] = {MSM_BUS_SLAVE_PORT_RIVA,};
+static int sport_sata[] = {MSM_BUS_SLAVE_PORT_SATA,};
+static int sport_kmpss[] = {MSM_BUS_SLAVE_PORT_KMPSS,};
+static int sport_gss[] = {MSM_BUS_SLAVE_PORT_GSS,};
+static int sport_lpass[] = {MSM_BUS_SLAVE_PORT_LPASS,};
+static int sport_mmss_fpb[] = {MSM_BUS_SYSTEM_SLAVE_PORT_MMSS_FPB,};
+
+static int tiered_slave_system_imem[] = {MSM_BUS_TIERED_SLAVE_SYSTEM_IMEM,};
+static int system_tiered_slave_fab_appss[] = {
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_0,
+	MSM_BUS_SYSTEM_TIERED_SLAVE_FAB_APPSS_1,
+};
+
+static struct msm_bus_node_info system_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_SPS,
+		.masterp = mport_sps,
+		.num_mports = ARRAY_SIZE(mport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT0,
+		.masterp = mport_adm_port0,
+		.num_mports = ARRAY_SIZE(mport_adm_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM_PORT1,
+		.masterp = mport_adm_port1,
+		.num_mports = ARRAY_SIZE(mport_adm_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS_PROC,
+		.masterp = mport_lpass_proc,
+		.num_mports = ARRAY_SIZE(mport_lpass_proc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GSS_NAV,
+		.masterp = mport_gss_nav,
+		.num_mports = ARRAY_SIZE(mport_gss_nav),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_PCIE,
+		.masterp = mport_pcie,
+		.num_mports = ARRAY_SIZE(mport_pcie),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RIVA,
+		.masterp = mport_riva,
+		.num_mports = ARRAY_SIZE(mport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_SATA,
+		.masterp = mport_sata,
+		.num_mports = ARRAY_SIZE(mport_sata),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_CRYPTO,
+		.masterp = mport_crypto,
+		.num_mports = ARRAY_SIZE(mport_crypto),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_LPASS,
+		.masterp = mport_lpass,
+		.num_mports = ARRAY_SIZE(mport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SYSTEM_MASTER_MMSS_FPB,
+		.masterp = system_mport_mmss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ADM0_CI,
+		.masterp = system_mport_adm_ahb_ci,
+		.num_mports = ARRAY_SIZE(system_mport_adm_ahb_ci),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = system_sport_appss_fab,
+		.num_sports = ARRAY_SIZE(system_sport_appss_fab),
+		.masterp = appss_mport_fab_system,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_system),
+		.tier = system_tiered_slave_fab_appss,
+		.num_tiers = ARRAY_SIZE(system_tiered_slave_fab_appss),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_FAB_SYSTEM_FPB,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_FAB_CPSS_FPB,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPS,
+		.slavep = sport_sps,
+		.num_sports = ARRAY_SIZE(sport_sps),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SYSTEM_IMEM,
+		.slavep = sport_system_imem,
+		.num_sports = ARRAY_SIZE(sport_system_imem),
+		.tier = tiered_slave_system_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_system_imem),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CORESIGHT,
+		.slavep = sport_coresight,
+		.num_sports = ARRAY_SIZE(sport_coresight),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_CRYPTO,
+		.slavep = sport_crypto,
+		.num_sports = ARRAY_SIZE(sport_crypto),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RIVA,
+		.slavep = sport_riva,
+		.num_sports = ARRAY_SIZE(sport_riva),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_SATA,
+		.slavep = sport_sata,
+		.num_sports = ARRAY_SIZE(sport_sata),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_AMPSS,
+		.slavep = sport_kmpss,
+		.num_sports = ARRAY_SIZE(sport_kmpss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSS,
+		.slavep = sport_gss,
+		.num_sports = ARRAY_SIZE(sport_gss),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SLAVE_LPASS,
+		.slavep = sport_lpass,
+		.num_sports = ARRAY_SIZE(sport_lpass),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+	{
+		.id = MSM_BUS_SYSTEM_SLAVE_MMSS_FPB,
+		.slavep = sport_mmss_fpb,
+		.num_sports = ARRAY_SIZE(sport_mmss_fpb),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+		.buswidth = 8,
+	},
+};
+
+static int mport_mdp[] = {
+	MSM_BUS_MASTER_PORT_MDP_PORT0,
+	MSM_BUS_MASTER_PORT_MDP_PORT1,
+};
+static int mport_mdp1[] = {MSM_BUS_MASTER_PORT_MDP_PORT1,};
+static int mport_rotator[] = {MSM_BUS_MASTER_PORT_ROTATOR,};
+static int mport_graphics_3d_port0[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT0,};
+static int mport_graphics_3d_port1[] = {MSM_BUS_MASTER_PORT_GRAPHICS_3D_PORT1,};
+static int mport_jpeg_dec[] = {MSM_BUS_MASTER_PORT_JPEG_DEC,};
+static int mport_video_cap[] = {MSM_BUS_MASTER_PORT_VIDEO_CAP,};
+static int mport_vfe[] = {MSM_BUS_MASTER_PORT_VFE,};
+static int mport_vpe[] = {MSM_BUS_MASTER_PORT_VPE,};
+static int mport_jpeg_enc[] = {MSM_BUS_MASTER_PORT_JPEG_ENC,};
+static int mport_video_enc[] = {MSM_BUS_MASTER_PORT_VIDEO_ENC,};
+static int mport_video_dec[] = {MSM_BUS_MASTER_PORT_VIDEO_DEC,};
+static int appss_mport_fab_mmss[] = {
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_0,
+	MSM_BUS_APPSS_MASTER_PORT_FAB_MMSS_1
+};
+
+static int mmss_sport_apps_fab[] = {
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_0,
+	MSM_BUS_MMSS_SLAVE_PORT_APPS_FAB_1
+};
+static int sport_mm_imem[] = {MSM_BUS_SLAVE_PORT_MM_IMEM,};
+
+static int mmss_tiered_slave_fab_apps[] = {
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_0,
+	MSM_BUS_MMSS_TIERED_SLAVE_FAB_APPS_1,
+};
+static int tiered_slave_mm_imem[] = {MSM_BUS_TIERED_SLAVE_MM_IMEM,};
+
+
+static struct msm_bus_node_info mmss_fabric_info[]  = {
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT0,
+		.masterp = mport_mdp,
+		.num_mports = ARRAY_SIZE(mport_mdp),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_MDP_PORT1,
+		.masterp = mport_mdp1,
+		.num_mports = ARRAY_SIZE(mport_mdp1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_ROTATOR,
+		.masterp = mport_rotator,
+		.num_mports = ARRAY_SIZE(mport_rotator),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D,
+		.masterp = mport_graphics_3d_port0,
+		.num_mports = ARRAY_SIZE(mport_graphics_3d_port0),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_GRAPHICS_3D_PORT1,
+		.masterp = mport_graphics_3d_port1,
+		.num_mports = ARRAY_SIZE(mport_graphics_3d_port1),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_DEC,
+		.masterp = mport_jpeg_dec,
+		.num_mports = ARRAY_SIZE(mport_jpeg_dec),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VIDEO_CAP,
+		.masterp = mport_video_cap,
+		.num_mports = ARRAY_SIZE(mport_video_cap),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VIDEO_ENC,
+		.masterp = mport_video_enc,
+		.num_mports = ARRAY_SIZE(mport_video_enc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VFE,
+		.masterp = mport_vfe,
+		.num_mports = ARRAY_SIZE(mport_vfe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_VPE,
+		.masterp = mport_vpe,
+		.num_mports = ARRAY_SIZE(mport_vpe),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_JPEG_ENC,
+		.masterp = mport_jpeg_enc,
+		.num_mports = ARRAY_SIZE(mport_jpeg_enc),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	/* This port has been added for V2. It is absent in V1 */
+	{
+		.id = MSM_BUS_MASTER_VIDEO_DEC,
+		.masterp = mport_video_dec,
+		.num_mports = ARRAY_SIZE(mport_video_dec),
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_FAB_APPSS,
+		.gateway = 1,
+		.slavep = mmss_sport_apps_fab,
+		.num_sports = ARRAY_SIZE(mmss_sport_apps_fab),
+		.masterp = appss_mport_fab_mmss,
+		.num_mports = ARRAY_SIZE(appss_mport_fab_mmss),
+		.tier = mmss_tiered_slave_fab_apps,
+		.num_tiers = ARRAY_SIZE(mmss_tiered_slave_fab_apps),
+		.buswidth = 16,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MM_IMEM,
+		.slavep = sport_mm_imem,
+		.num_sports = ARRAY_SIZE(sport_mm_imem),
+		.tier = tiered_slave_mm_imem,
+		.num_tiers = ARRAY_SIZE(tiered_slave_mm_imem),
+		.buswidth = 8,
+	},
+};
+
+static struct msm_bus_node_info sys_fpb_fabric_info[]  = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_system_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_system_fpb),
+		.masterp = mport_system_fpb,
+		.num_mports = ARRAY_SIZE(mport_system_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_MASTER_SPDM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_MASTER_RPM,
+		.ahb = 1,
+		.tier = tier2,
+		.num_tiers = ARRAY_SIZE(tier2),
+	},
+	{
+		.id = MSM_BUS_SLAVE_SPDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_RPM_MSG_RAM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MPM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_B,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC1_SSBI1_C,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_A,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_PMIC2_SSBI2_B,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static struct msm_bus_node_info cpss_fpb_fabric_info[] = {
+	{
+		.id = MSM_BUS_FAB_SYSTEM,
+		.gateway = 1,
+		.slavep = system_sport_cpss_fpb,
+		.num_sports = ARRAY_SIZE(system_sport_cpss_fpb),
+		.masterp = system_mport_cpss_fpb,
+		.num_mports = ARRAY_SIZE(system_mport_cpss_fpb),
+		.buswidth = 4,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_UART,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI1_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI2_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI3_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI4_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI5_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI6_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI7_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI8_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI9_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI10_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI11_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_GSBI12_QUP,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_NAND,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS0,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS3,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS4,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_EBI2_CS5,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS1,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_USB_FS2,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_TSIF,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TSSC,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PDM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_DIMEM,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_TCSR,
+		.buswidth = 8,
+		.ahb = 1,
+	},
+	{
+		.id = MSM_BUS_SLAVE_MSM_PRNG,
+		.buswidth = 4,
+		.ahb = 1,
+	},
+};
+
+static void msm_bus_board_assign_iids(struct msm_bus_fabric_registration
+	*fabreg, int fabid)
+{
+	int i;
+	for (i = 0; i < fabreg->len; i++) {
+		if (!fabreg->info[i].gateway) {
+			fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
+			if (fabreg->info[i].id < SLAVE_ID_KEY) {
+				WARN(fabreg->info[i].id >= NMASTERS,
+					"id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				master_iids[fabreg->info[i].id] =
+					fabreg->info[i].priv_id;
+			} else {
+				WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
+					NSLAVES, "id %d exceeds array size!\n",
+					fabreg->info[i].id);
+				slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
+					= fabreg->info[i].priv_id;
+			}
+		} else
+			fabreg->info[i].priv_id = fabreg->info[i].id;
+	}
+}
+
+static int msm_bus_board_8064_get_iid(int id)
+{
+	if ((id < SLAVE_ID_KEY && id >= NMASTERS) ||
+		id >= (SLAVE_ID_KEY + NSLAVES)) {
+		MSM_BUS_ERR("Cannot get iid. Invalid id %d passed\n", id);
+		return -EINVAL;
+	}
+
+	return CHECK_ID(((id < SLAVE_ID_KEY) ? master_iids[id] :
+		slave_iids[id - SLAVE_ID_KEY]), id);
+}
+
+static struct msm_bus_board_algorithm msm_bus_board_algo = {
+	.board_nfab = NFAB_8064,
+	.get_iid = msm_bus_board_8064_get_iid,
+	.assign_iids = msm_bus_board_assign_iids,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_apps_fabric_pdata = {
+	.id = MSM_BUS_FAB_APPSS,
+	.name = "msm_apps_fab",
+	.info = apps_fabric_info,
+	.len = ARRAY_SIZE(apps_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_APPS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_APPS_FABRIC_ARB_0,
+	.nmasters = 6,
+	.nslaves = 5,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_sys_fabric_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM,
+	.name = "msm_sys_fab",
+	system_fabric_info,
+	ARRAY_SIZE(system_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_SYS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_SYSTEM_FABRIC_ARB_0,
+	.nmasters = 15,
+	.nslaves = 15,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_mm_fabric_pdata = {
+	.id = MSM_BUS_FAB_MMSS,
+	.name = "msm_mm_fab",
+	mmss_fabric_info,
+	ARRAY_SIZE(mmss_fabric_info),
+	.ahb = 0,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.haltid = MSM_RPM_ID_MMSS_FABRIC_CFG_HALT_0,
+	.offset = MSM_RPM_ID_MM_FABRIC_ARB_0,
+	.nmasters = 13,
+	.nslaves = 3,
+	.ntieredslaves = 3,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_sys_fpb_pdata = {
+	.id = MSM_BUS_FAB_SYSTEM_FPB,
+	.name = "msm_sys_fpb",
+	sys_fpb_fabric_info,
+	ARRAY_SIZE(sys_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
+
+struct msm_bus_fabric_registration msm_bus_8064_cpss_fpb_pdata = {
+	.id = MSM_BUS_FAB_CPSS_FPB,
+	.name = "msm_cpss_fpb",
+	cpss_fpb_fabric_info,
+	ARRAY_SIZE(cpss_fpb_fabric_info),
+	.ahb = 1,
+	.fabclk[DUAL_CTX] = "bus_clk",
+	.fabclk[ACTIVE_CTX] = "bus_a_clk",
+	.nmasters = 0,
+	.nslaves = 0,
+	.ntieredslaves = 0,
+	.board_algo = &msm_bus_board_algo,
+};
diff --git a/arch/arm/mach-msm/msm_dsps.c b/arch/arm/mach-msm/msm_dsps.c
index 4e487a7..efb2bf6 100644
--- a/arch/arm/mach-msm/msm_dsps.c
+++ b/arch/arm/mach-msm/msm_dsps.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
@@ -39,8 +39,10 @@
 #include <mach/subsystem_restart.h>
 #include <mach/subsystem_notif.h>
 
+#include <timer.h>
+
 #define DRV_NAME	"msm_dsps"
-#define DRV_VERSION	"3.01"
+#define DRV_VERSION	"3.02"
 
 #define PPSS_PAUSE_REG	0x1804
 
@@ -146,9 +148,9 @@
 {
 	u32 val;
 
-	val = readl_relaxed(drv->ppss_base + PPSS_TIMER0_32KHZ_REG);
-	rmb(); /* order reads from the user output buffer */
-
+	/* Read the timer value from the MSM sclk. The MSM slow clock & DSPS
+	 * timers are in sync, so these are the same value */
+	val = msm_timer_get_sclk_ticks();
 	pr_debug("%s.count=%d.\n", __func__, val);
 
 	return val;
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index 366b282..f51286f 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -13,9 +13,9 @@
 
 #include <linux/module.h>
 
-#include "cpuidle.h"
+#include <mach/cpuidle.h>
 #include "idle.h"
-#include "pm.h"
+#include <mach/pm.h>
 
 void arch_idle(void)
 { }
diff --git a/arch/arm/mach-msm/pil-riva.c b/arch/arm/mach-msm/pil-riva.c
index de61041..6848c59 100644
--- a/arch/arm/mach-msm/pil-riva.c
+++ b/arch/arm/mach-msm/pil-riva.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,10 @@
 #define RIVA_PMU_CFG_IRIS_XO_MODE	0x6
 #define RIVA_PMU_CFG_IRIS_XO_MODE_48	(3 << 1)
 
+#define RIVA_PMU_OVRD_EN		0x2C
+#define RIVA_PMU_OVRD_EN_CCPU_RESET	BIT(0)
+#define RIVA_PMU_OVRD_EN_CCPU_CLK	BIT(1)
+
 #define RIVA_PMU_OVRD_VAL		0x30
 #define RIVA_PMU_OVRD_VAL_CCPU_RESET	BIT(0)
 #define RIVA_PMU_OVRD_VAL_CCPU_CLK	BIT(1)
@@ -57,6 +61,7 @@
 #define RIVA_PLL_N_VAL			(MSM_CLK_CTL_BASE + 0x31Ac)
 #define RIVA_PLL_CONFIG			(MSM_CLK_CTL_BASE + 0x31B4)
 #define RIVA_PLL_STATUS			(MSM_CLK_CTL_BASE + 0x31B8)
+#define RIVA_RESET			(MSM_CLK_CTL_BASE + 0x35E0)
 
 #define RIVA_PMU_ROOT_CLK_SEL		0xC8
 #define RIVA_PMU_ROOT_CLK_SEL_3		BIT(2)
@@ -230,9 +235,23 @@
 	struct riva_data *drv = dev_get_drvdata(pil->dev);
 	u32 reg;
 
+	/* Put cCPU and cCPU clock into reset */
 	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_VAL);
 	reg &= ~(RIVA_PMU_OVRD_VAL_CCPU_RESET | RIVA_PMU_OVRD_VAL_CCPU_CLK);
 	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_VAL);
+	reg = readl_relaxed(drv->base + RIVA_PMU_OVRD_EN);
+	reg |= RIVA_PMU_OVRD_EN_CCPU_RESET | RIVA_PMU_OVRD_EN_CCPU_CLK;
+	writel_relaxed(reg, drv->base + RIVA_PMU_OVRD_EN);
+	mb();
+
+	/* Assert reset to Riva */
+	writel_relaxed(1, RIVA_RESET);
+	mb();
+	usleep_range(1000, 2000);
+
+	/* Deassert reset to Riva */
+	writel_relaxed(0, RIVA_RESET);
+	mb();
 
 	pil_riva_remove_xo_proxy_votes_now(pil->dev);
 
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 6dfb354..d73d4a0 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -25,8 +25,9 @@
 #include <mach/hardware.h>
 #include <mach/msm_iomap.h>
 
-#include "pm.h"
+#include <mach/pm.h>
 #include "scm-boot.h"
+#include "spm.h"
 
 int pen_release = -1;
 
@@ -90,6 +91,8 @@
 	if (!base_ptr)
 		return -ENODEV;
 
+	msm_spm_turn_on_cpu_rail(cpu);
+
 	writel_relaxed(0x109, base_ptr+0x04);
 	writel_relaxed(0x101, base_ptr+0x04);
 	ndelay(300);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index adf5471..754d76f 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -27,6 +27,7 @@
 #include <linux/tick.h>
 #include <linux/uaccess.h>
 #include <linux/wakelock.h>
+#include <linux/delay.h>
 #include <mach/msm_iomap.h>
 #include <mach/system.h>
 #include <asm/cacheflush.h>
@@ -41,9 +42,9 @@
 #include "acpuclock.h"
 #include "clock.h"
 #include "avs.h"
-#include "cpuidle.h"
+#include <mach/cpuidle.h>
 #include "idle.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "rpm_resources.h"
 #include "scm-boot.h"
 #include "spm.h"
@@ -55,6 +56,7 @@
  * Debug Definitions
  *****************************************************************************/
 
+
 enum {
 	MSM_PM_DEBUG_SUSPEND = BIT(0),
 	MSM_PM_DEBUG_POWER_COLLAPSE = BIT(1),
@@ -953,6 +955,23 @@
 	return 0;
 }
 
+static struct msm_pm_sleep_status_data *msm_pm_slp_sts;
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(enum msm_pm_sleep_mode,
+		msm_pm_last_slp_mode);
+
+bool msm_pm_verify_cpu_pc(unsigned int cpu)
+{
+	enum msm_pm_sleep_mode mode = per_cpu(msm_pm_last_slp_mode, cpu);
+
+	if (msm_pm_slp_sts)
+		if ((mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) ||
+			(mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE))
+			return true;
+
+	return false;
+}
+
 void msm_pm_cpu_enter_lowpower(unsigned int cpu)
 {
 	int i;
@@ -968,14 +987,50 @@
 	if (MSM_PM_DEBUG_HOTPLUG & msm_pm_debug_mask)
 		pr_notice("CPU%u: %s: shutting down cpu\n", cpu, __func__);
 
-	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE])
+	if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_POWER_COLLAPSE;
 		msm_pm_power_collapse(false);
-	else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE])
+	} else if (allow[MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
 		msm_pm_power_collapse_standalone(false);
-	else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT])
+	} else if (allow[MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT]) {
+		per_cpu(msm_pm_last_slp_mode, cpu)
+			= MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE;
 		msm_pm_swfi();
+	} else
+		per_cpu(msm_pm_last_slp_mode, cpu) = MSM_PM_SLEEP_MODE_NR;
+}
 
+int msm_pm_wait_cpu_shutdown(unsigned int cpu)
+{
 
+	int timeout = 10;
+
+	if (!msm_pm_slp_sts)
+		return 0;
+
+	while (timeout--) {
+
+		/*
+		 * Check for the SPM of the core being hotplugged to set
+		 * its sleep state.The SPM sleep state indicates that the
+		 * core has been power collapsed.
+		 */
+
+		int acc_sts = __raw_readl(msm_pm_slp_sts->base_addr
+					+ cpu * msm_pm_slp_sts->cpu_offset);
+		mb();
+
+		if (acc_sts & msm_pm_slp_sts->mask)
+			return 0;
+
+		usleep(100);
+	}
+	pr_warn("%s(): Timed out waiting for CPU %u SPM to enter sleep state",
+			__func__, cpu);
+	return -EBUSY;
 }
 
 static int msm_pm_enter(suspend_state_t state)
@@ -1085,10 +1140,14 @@
 	.valid = suspend_valid_only_mem,
 };
 
-
 /******************************************************************************
  * Initialization routine
  *****************************************************************************/
+void __init msm_pm_init_sleep_status_data(
+		struct msm_pm_sleep_status_data *data)
+{
+	msm_pm_slp_sts = data;
+}
 
 static int __init msm_pm_init(void)
 {
diff --git a/arch/arm/mach-msm/pm.c b/arch/arm/mach-msm/pm.c
index d684a5a..3dcbfb3 100644
--- a/arch/arm/mach-msm/pm.c
+++ b/arch/arm/mach-msm/pm.c
@@ -44,7 +44,7 @@
 #include "irq.h"
 #include "gpio.h"
 #include "timer.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "pm-boot.h"
 
 enum {
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index 4cdd7ae..0518ea2 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -58,7 +58,7 @@
 #include "irq.h"
 #include "gpio.h"
 #include "timer.h"
-#include "pm.h"
+#include <mach/pm.h>
 #include "spm.h"
 #include "sirc.h"
 #include "pm-boot.h"
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
index 2ad7f86..37a6900 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.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
@@ -589,19 +589,11 @@
 
 static int deregister_pmem(void)
 {
-	int result;
-
-	result = adm_memory_unmap_regions((uint32_t *)&acdb_data.paddr,
-			(uint32_t *)&acdb_data.pmem_len, 1);
-
-	if (result < 0)
-		pr_err("Audcal unmap did not work!\n");
-
 	if (acdb_data.pmem_fd) {
 		put_pmem_file(acdb_data.file);
 		acdb_data.pmem_fd = 0;
 	}
-	return result;
+	return 0;
 }
 
 static int register_pmem(void)
@@ -620,11 +612,6 @@
 	pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
 		"kvaddr = 0x%lx, len = x%lx\n", acdb_data.paddr,
 		acdb_data.kvaddr, acdb_data.pmem_len);
-	result = adm_memory_map_regions((uint32_t *)&acdb_data.paddr, 0,
-			(uint32_t *)&acdb_data.pmem_len, 1);
-	if (result < 0)
-		pr_err("Audcal mmap did not work!\n");
-	goto done;
 
 done:
 	return result;
diff --git a/arch/arm/mach-msm/qdss-debug.c b/arch/arm/mach-msm/qdss-debug.c
deleted file mode 100644
index b2d38b1..0000000
--- a/arch/arm/mach-msm/qdss-debug.c
+++ /dev/null
@@ -1,285 +0,0 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/smp.h>
-
-#include "qdss.h"
-
-#define debug_writel(debug, cpu, val, off)	\
-			__raw_writel((val), debug.base[cpu] + off)
-#define debug_readl(debug, cpu, off)		\
-			__raw_readl(debug.base[cpu] + off)
-
-#define DBGDIDR			(0x000)
-#define DBGWFAR			(0x018)
-#define DBGVCR			(0x01C)
-#define DBGECR			(0x024)
-#define DBGDTRRX		(0x080)
-#define DBGITR			(0x084)
-#define DBGDSCR			(0x088)
-#define DBGDTRTX		(0x08C)
-#define DBGDRCR			(0x090)
-#define DBGEACR			(0x094)
-#define DBGPCSR			(0x0A0)
-#define DBGCIDSR		(0x0A4)
-#define DBGVIDSR		(0x0A8)
-#define DBGBVRm(n)		(0x100 + (n * 4))
-#define DBGBCRm(n)		(0x140 + (n * 4))
-#define DBGWVRm(n)		(0x180 + (n * 4))
-#define DBGWCRm(n)		(0x1C0 + (n * 4))
-#define DBGBXVRm(n)		(0x240 + (n * 4))
-#define DBGOSLAR		(0x300)
-#define DBGOSLSR		(0x304)
-#define DBGPRCR			(0x310)
-#define DBGPRSR			(0x314)
-
-
-#define DEBUG_LOCK(cpu)							\
-do {									\
-	mb();								\
-	debug_writel(debug, cpu, MAGIC2, CS_LAR);			\
-} while (0)
-#define DEBUG_UNLOCK(cpu)						\
-do {									\
-	debug_writel(debug, cpu, MAGIC1, CS_LAR);			\
-	mb();								\
-} while (0)
-
-#define DEBUG_OS_LOCK(cpu)						\
-do {									\
-	debug_writel(debug, cpu, MAGIC1, DBGOSLAR);			\
-	mb();								\
-} while (0)
-#define DEBUG_OS_UNLOCK(cpu)						\
-do {									\
-	mb();								\
-	debug_writel(debug, cpu, MAGIC2, DBGOSLAR);			\
-	mb();								\
-} while (0)
-
-#define MAX_DEBUG_REGS		(90)
-#define MAX_STATE_SIZE		(MAX_DEBUG_REGS * num_possible_cpus())
-#define DBGDSCR_MASK		(0x6C30FC3C)
-
-struct debug_config {
-	/* read only config register */
-	uint32_t	dbg_id;
-	/* derived values */
-	uint8_t		nr_watch_pts;
-	uint8_t		nr_brk_pts;
-	uint8_t		nr_ctx_comp;
-};
-
-struct debug_ctx {
-	struct debug_config		cfg;
-	void __iomem			**base;
-	uint32_t			*state;
-	struct device			*dev;
-};
-
-static struct debug_ctx debug;
-
-static void debug_save_reg(int cpu)
-{
-	uint32_t i;
-	int j;
-
-	DEBUG_UNLOCK(cpu);
-	DEBUG_OS_LOCK(cpu);
-
-	i = cpu * MAX_DEBUG_REGS;
-
-	debug.state[i++] = debug_readl(debug, cpu, DBGWFAR);
-	for (j = 0; j < debug.cfg.nr_brk_pts; j++) {
-		debug.state[i++] = debug_readl(debug, cpu, DBGBCRm(j));
-		debug.state[i++] = debug_readl(debug, cpu, DBGBVRm(j));
-	}
-	for (j = 0; j < debug.cfg.nr_ctx_comp; j++)
-		debug.state[i++] = debug_readl(debug, cpu, DBGBXVRm(j));
-	for (j = 0; j < debug.cfg.nr_watch_pts; j++) {
-		debug.state[i++] = debug_readl(debug, cpu, DBGWVRm(j));
-		debug.state[i++] = debug_readl(debug, cpu, DBGWCRm(j));
-	}
-	debug.state[i++] = debug_readl(debug, cpu, DBGVCR);
-	debug.state[i++] = debug_readl(debug, cpu, CS_CLAIMSET);
-	debug.state[i++] = debug_readl(debug, cpu, CS_CLAIMCLR);
-	debug.state[i++] = debug_readl(debug, cpu, DBGDTRTX);
-	debug.state[i++] = debug_readl(debug, cpu, DBGDTRRX);
-	debug.state[i++] = debug_readl(debug, cpu, DBGDSCR);
-
-	DEBUG_LOCK(cpu);
-}
-
-static void debug_restore_reg(int cpu)
-{
-	uint32_t i;
-	int j;
-
-	DEBUG_UNLOCK(cpu);
-	DEBUG_OS_LOCK(cpu);
-
-	i = cpu * MAX_DEBUG_REGS;
-
-	debug_writel(debug, cpu, debug.state[i++], DBGWFAR);
-	for (j = 0; j < debug.cfg.nr_brk_pts; j++) {
-		debug_writel(debug, cpu, debug.state[i++], DBGBCRm(j));
-		debug_writel(debug, cpu, debug.state[i++], DBGBVRm(j));
-	}
-	for (j = 0; j < debug.cfg.nr_ctx_comp; j++)
-		debug_writel(debug, cpu, debug.state[i++], DBGBXVRm(j));
-	for (j = 0; j < debug.cfg.nr_watch_pts; j++) {
-		debug_writel(debug, cpu, debug.state[i++], DBGWVRm(j));
-		debug_writel(debug, cpu, debug.state[i++], DBGWCRm(j));
-	}
-	debug_writel(debug, cpu, debug.state[i++], DBGVCR);
-	debug_writel(debug, cpu, debug.state[i++], CS_CLAIMSET);
-	debug_writel(debug, cpu, debug.state[i++], CS_CLAIMCLR);
-	debug_writel(debug, cpu, debug.state[i++], DBGDTRTX);
-	debug_writel(debug, cpu, debug.state[i++], DBGDTRRX);
-	debug_writel(debug, cpu, debug.state[i++] & DBGDSCR_MASK, DBGDSCR);
-
-	DEBUG_OS_UNLOCK(cpu);
-	DEBUG_LOCK(cpu);
-}
-
-/* msm_save_jtag_debug and msm_restore_jtag_debug should be fast
- *
- * These functions will be called either from:
- * 1. per_cpu idle thread context for idle power collapses.
- * 2. per_cpu idle thread context for hotplug/suspend power collapse for
- *    nonboot cpus.
- * 3. suspend thread context for core0.
- *
- * In all cases we are guaranteed to be running on the same cpu for the
- * entire duration.
- */
-void msm_save_jtag_debug(void)
-{
-	int cpu = smp_processor_id();
-	debug_save_reg(cpu);
-}
-
-void msm_restore_jtag_debug(void)
-{
-	int cpu = smp_processor_id();
-	debug_restore_reg(cpu);
-}
-
-static void debug_cfg_ro_init(void)
-{
-	/* use cpu 0 for setup */
-	int cpu = 0;
-
-	DEBUG_UNLOCK(cpu);
-
-	debug.cfg.dbg_id = debug_readl(debug, cpu, DBGDIDR);
-	debug.cfg.nr_ctx_comp = BMVAL(debug.cfg.dbg_id, 20, 23) + 1;
-	debug.cfg.nr_brk_pts = BMVAL(debug.cfg.dbg_id, 24, 27) + 1;
-	debug.cfg.nr_watch_pts = BMVAL(debug.cfg.dbg_id, 28, 31) + 1;
-
-	DEBUG_LOCK(cpu);
-}
-
-static int __devinit debug_probe(struct platform_device *pdev)
-{
-	int i, ret;
-	struct resource *res;
-
-	debug.base = kzalloc(pdev->num_resources * sizeof(void *), GFP_KERNEL);
-	if (!debug.base) {
-		ret = -ENOMEM;
-		goto err_base_kzalloc;
-	}
-
-	for (i = 0; i < pdev->num_resources; i++) {
-		res = platform_get_resource(pdev, IORESOURCE_MEM, i);
-		if (!res) {
-			ret = -EINVAL;
-			goto err_res;
-		}
-
-		debug.base[i] = ioremap_nocache(res->start, resource_size(res));
-		if (!debug.base[i]) {
-			ret = -EINVAL;
-			goto err_ioremap;
-		}
-	}
-
-	debug.dev = &pdev->dev;
-
-	debug.state = kzalloc(MAX_STATE_SIZE * sizeof(uint32_t), GFP_KERNEL);
-	if (!debug.state) {
-		ret = -ENOMEM;
-		goto err_state_kzalloc;
-	}
-
-	debug_cfg_ro_init();
-
-	dev_info(debug.dev, "Debug intialized.\n");
-
-	return 0;
-
-err_state_kzalloc:
-err_ioremap:
-err_res:
-	while (i) {
-		iounmap(debug.base[i-1]);
-		i--;
-	}
-	kfree(debug.base);
-err_base_kzalloc:
-	return ret;
-}
-
-static int __devexit debug_remove(struct platform_device *pdev)
-{
-	int i;
-
-	kfree(debug.state);
-	for (i = pdev->num_resources; i > 0; i--)
-		iounmap(debug.base[i-1]);
-	kfree(debug.base);
-
-	return 0;
-}
-
-static struct platform_driver debug_driver = {
-	.probe          = debug_probe,
-	.remove         = __devexit_p(debug_remove),
-	.driver         = {
-		.name   = "msm_debug",
-	},
-};
-
-static int __init debug_init(void)
-{
-	return platform_driver_register(&debug_driver);
-}
-module_init(debug_init);
-
-static void __exit debug_exit(void)
-{
-	platform_driver_unregister(&debug_driver);
-}
-module_exit(debug_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Coresight Debug driver");
diff --git a/arch/arm/mach-msm/qdss-etb.c b/arch/arm/mach-msm/qdss-etb.c
index 16f8a5b..39b7670 100644
--- a/arch/arm/mach-msm/qdss-etb.c
+++ b/arch/arm/mach-msm/qdss-etb.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
@@ -56,11 +56,11 @@
 #define ETB_LOCK()							\
 do {									\
 	mb();								\
-	etb_writel(etb, MAGIC2, CS_LAR);				\
+	etb_writel(etb, 0x0, CS_LAR);					\
 } while (0)
 #define ETB_UNLOCK()							\
 do {									\
-	etb_writel(etb, MAGIC1, CS_LAR);				\
+	etb_writel(etb, CS_UNLOCK_MAGIC, CS_LAR);			\
 	mb();								\
 } while (0)
 
@@ -296,7 +296,7 @@
 	return ret;
 }
 
-static int __devexit etb_remove(struct platform_device *pdev)
+static int etb_remove(struct platform_device *pdev)
 {
 	if (etb.enabled)
 		etb_disable();
@@ -310,23 +310,18 @@
 
 static struct platform_driver etb_driver = {
 	.probe          = etb_probe,
-	.remove         = __devexit_p(etb_remove),
+	.remove         = etb_remove,
 	.driver         = {
 		.name   = "msm_etb",
 	},
 };
 
-static int __init etb_init(void)
+int __init etb_init(void)
 {
 	return platform_driver_register(&etb_driver);
 }
-module_init(etb_init);
 
-static void __exit etb_exit(void)
+void etb_exit(void)
 {
 	platform_driver_unregister(&etb_driver);
 }
-module_exit(etb_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Coresight Embedded Trace Buffer");
diff --git a/arch/arm/mach-msm/qdss-funnel.c b/arch/arm/mach-msm/qdss-funnel.c
index 290b418..dd61c15 100644
--- a/arch/arm/mach-msm/qdss-funnel.c
+++ b/arch/arm/mach-msm/qdss-funnel.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
@@ -37,11 +37,11 @@
 #define FUNNEL_LOCK(id)							\
 do {									\
 	mb();								\
-	funnel_writel(funnel, id, MAGIC2, CS_LAR);			\
+	funnel_writel(funnel, id, 0x0, CS_LAR);				\
 } while (0)
 #define FUNNEL_UNLOCK(id)						\
 do {									\
-	funnel_writel(funnel, id, MAGIC1, CS_LAR);			\
+	funnel_writel(funnel, id, CS_UNLOCK_MAGIC, CS_LAR);		\
 	mb();								\
 } while (0)
 
@@ -129,7 +129,7 @@
 	return ret;
 }
 
-static int __devexit funnel_remove(struct platform_device *pdev)
+static int funnel_remove(struct platform_device *pdev)
 {
 	if (funnel.enabled)
 		funnel_disable(0x0, 0xFF);
@@ -140,23 +140,18 @@
 
 static struct platform_driver funnel_driver = {
 	.probe          = funnel_probe,
-	.remove         = __devexit_p(funnel_remove),
+	.remove         = funnel_remove,
 	.driver         = {
 		.name   = "msm_funnel",
 	},
 };
 
-static int __init funnel_init(void)
+int __init funnel_init(void)
 {
 	return platform_driver_register(&funnel_driver);
 }
-module_init(funnel_init);
 
-static void __exit funnel_exit(void)
+void funnel_exit(void)
 {
 	platform_driver_unregister(&funnel_driver);
 }
-module_exit(funnel_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Coresight Funnel");
diff --git a/arch/arm/mach-msm/qdss-ptm.c b/arch/arm/mach-msm/qdss-ptm.c
index 205e2b8..96a727a 100644
--- a/arch/arm/mach-msm/qdss-ptm.c
+++ b/arch/arm/mach-msm/qdss-ptm.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
@@ -26,7 +26,6 @@
 #include <linux/smp.h>
 #include <linux/wakelock.h>
 #include <linux/pm_qos_params.h>
-#include <linux/clk.h>
 #include <asm/atomic.h>
 
 #include "qdss.h"
@@ -100,37 +99,26 @@
 #define ETMPDCR			(0x310)
 #define ETMPDSR			(0x314)
 
-
 #define PTM_LOCK(cpu)							\
 do {									\
 	mb();								\
-	ptm_writel(ptm, cpu, MAGIC2, CS_LAR);				\
+	ptm_writel(ptm, cpu, 0x0, CS_LAR);				\
 } while (0)
 #define PTM_UNLOCK(cpu)							\
 do {									\
-	ptm_writel(ptm, cpu, MAGIC1, CS_LAR);				\
+	ptm_writel(ptm, cpu, CS_UNLOCK_MAGIC, CS_LAR);			\
 	mb();								\
 } while (0)
 
-#define PTM_OS_LOCK(cpu)						\
-do {									\
-	ptm_writel(ptm, cpu, MAGIC1, ETMOSLAR);				\
-	mb();								\
-} while (0)
-#define PTM_OS_UNLOCK(cpu)						\
-do {									\
-	mb();								\
-	ptm_writel(ptm, cpu, MAGIC2, ETMOSLAR);				\
-	mb();								\
-} while (0)
-
-#define MAX_TRACE_REGS		(78)
-#define MAX_STATE_SIZE		(MAX_TRACE_REGS * num_possible_cpus())
 
 /* Forward declarations */
 static void ptm_cfg_rw_init(void);
 
+#ifdef CONFIG_MSM_QDSS_ETM_DEFAULT_ENABLE
+static int trace_on_boot = 1;
+#else
 static int trace_on_boot;
+#endif
 module_param_named(
 	trace_on_boot, trace_on_boot, int, S_IRUGO
 );
@@ -189,77 +177,31 @@
 struct ptm_ctx {
 	struct ptm_config		cfg;
 	void __iomem			*base;
-	uint32_t			*state;
 	bool				trace_enabled;
 	struct wake_lock		wake_lock;
 	struct pm_qos_request_list	qos_req;
 	atomic_t			in_use;
 	struct device			*dev;
-	struct clk			*qdss_at_clk;
-	struct clk			*qdss_pclkdbg_clk;
-	struct clk			*qdss_pclk;
-	struct clk			*qdss_traceclkin_clk;
-	struct clk			*qdss_tsctr_clk;
 };
 
 static struct ptm_ctx ptm;
 
-/* Memory mapped writes to clear os lock don't work */
-static void ptm_os_unlock(void *unused)
-{
-	unsigned long value = 0x0;
 
-	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
-	asm("isb\n\t");
-}
-
-static int ptm_clock_enable(void)
-{
-	int ret;
-
-	ret = clk_enable(ptm.qdss_at_clk);
-	if (WARN(ret, "qdss_at_clk not enabled (%d)\n", ret))
-		goto err;
-
-	ret = clk_enable(ptm.qdss_pclkdbg_clk);
-	if (WARN(ret, "qdss_pclkdbg_clk not enabled (%d)\n", ret))
-		goto err_pclkdbg;
-
-	ret = clk_enable(ptm.qdss_pclk);
-	if (WARN(ret, "qdss_pclk not enabled (%d)\n", ret))
-		goto err_pclk;
-
-	ret = clk_enable(ptm.qdss_traceclkin_clk);
-	if (WARN(ret, "qdss_traceclkin_clk not enabled (%d)\n", ret))
-		goto err_traceclkin;
-
-	ret = clk_enable(ptm.qdss_tsctr_clk);
-	if (WARN(ret, "qdss_tsctr_clk not enabled (%d)\n", ret))
-		goto err_tsctr;
-
-	return 0;
-
-err_tsctr:
-	clk_disable(ptm.qdss_traceclkin_clk);
-err_traceclkin:
-	clk_disable(ptm.qdss_pclk);
-err_pclk:
-	clk_disable(ptm.qdss_pclkdbg_clk);
-err_pclkdbg:
-	clk_disable(ptm.qdss_at_clk);
-err:
-	return ret;
-}
-
-static void ptm_clock_disable(void)
-{
-	clk_disable(ptm.qdss_tsctr_clk);
-	clk_disable(ptm.qdss_traceclkin_clk);
-	clk_disable(ptm.qdss_pclk);
-	clk_disable(ptm.qdss_pclkdbg_clk);
-	clk_disable(ptm.qdss_at_clk);
-}
-
+/* ETM clock is derived from the processor clock and gets enabled on a
+ * logical OR of below items on Krait (pass2 onwards):
+ * 1.CPMR[ETMCLKEN] is 1
+ * 2.ETMCR[PD] is 0
+ * 3.ETMPDCR[PU] is 1
+ * 4.Reset is asserted (core or debug)
+ * 5.APB memory mapped requests (eg. EDAP access)
+ *
+ * 1., 2. and 3. above are permanent enables whereas 4. and 5. are temporary
+ * enables
+ *
+ * We rely on 5. to be able to access ETMCR and then use 2. above for ETM
+ * clock vote in the driver and the save-restore code uses 1. above
+ * for its vote
+ */
 static void ptm_set_powerdown(int cpu)
 {
 	uint32_t etmcr;
@@ -308,68 +250,65 @@
 	WARN(count == 0, "timeout while clearing prog bit\n");
 }
 
-static void __ptm_trace_enable(void)
+static void __ptm_trace_enable(int cpu)
 {
-	int i, cpu;
+	int i;
 
-	for_each_online_cpu(cpu) {
-		PTM_UNLOCK(cpu);
-		ptm_clear_powerdown(cpu);
-		ptm_set_prog(cpu);
+	PTM_UNLOCK(cpu);
+	/* Vote for ETM power/clock enable */
+	ptm_clear_powerdown(cpu);
+	ptm_set_prog(cpu);
 
-		ptm_writel(ptm, cpu, ptm.cfg.main_control | BIT(10), ETMCR);
-		ptm_writel(ptm, cpu, ptm.cfg.trigger_event, ETMTRIGGER);
-		ptm_writel(ptm, cpu, ptm.cfg.te_start_stop_control, ETMTSSCR);
-		ptm_writel(ptm, cpu, ptm.cfg.te_event, ETMTEEVR);
-		ptm_writel(ptm, cpu, ptm.cfg.te_control, ETMTECR1);
-		ptm_writel(ptm, cpu, ptm.cfg.fifofull_level, ETMFFLR);
-		for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
-			ptm_writel(ptm, cpu, ptm.cfg.addr_comp_value[i],
-							ETMACVRn(i));
-			ptm_writel(ptm, cpu, ptm.cfg.addr_comp_access_type[i],
+	ptm_writel(ptm, cpu, ptm.cfg.main_control | BIT(10), ETMCR);
+	ptm_writel(ptm, cpu, ptm.cfg.trigger_event, ETMTRIGGER);
+	ptm_writel(ptm, cpu, ptm.cfg.te_start_stop_control, ETMTSSCR);
+	ptm_writel(ptm, cpu, ptm.cfg.te_event, ETMTEEVR);
+	ptm_writel(ptm, cpu, ptm.cfg.te_control, ETMTECR1);
+	ptm_writel(ptm, cpu, ptm.cfg.fifofull_level, ETMFFLR);
+	for (i = 0; i < ptm.cfg.nr_addr_comp; i++) {
+		ptm_writel(ptm, cpu, ptm.cfg.addr_comp_value[i], ETMACVRn(i));
+		ptm_writel(ptm, cpu, ptm.cfg.addr_comp_access_type[i],
 							ETMACTRn(i));
-		}
-		for (i = 0; i < ptm.cfg.nr_cntr; i++) {
-			ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_value[i],
-							ETMCNTRLDVRn(i));
-			ptm_writel(ptm, cpu, ptm.cfg.cntr_enable_event[i],
-							ETMCNTENRn(i));
-			ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_event[i],
-							ETMCNTRLDEVRn(i));
-			ptm_writel(ptm, cpu, ptm.cfg.cntr_value[i],
-							ETMCNTVRn(i));
-		}
-		ptm_writel(ptm, cpu, ptm.cfg.seq_state_12_event, ETMSQ12EVR);
-		ptm_writel(ptm, cpu, ptm.cfg.seq_state_21_event, ETMSQ21EVR);
-		ptm_writel(ptm, cpu, ptm.cfg.seq_state_23_event, ETMSQ23EVR);
-		ptm_writel(ptm, cpu, ptm.cfg.seq_state_32_event, ETMSQ32EVR);
-		ptm_writel(ptm, cpu, ptm.cfg.seq_state_13_event, ETMSQ13EVR);
-		ptm_writel(ptm, cpu, ptm.cfg.seq_state_31_event, ETMSQ31EVR);
-		ptm_writel(ptm, cpu, ptm.cfg.current_seq_state, ETMSQR);
-		for (i = 0; i < ptm.cfg.nr_ext_output; i++)
-			ptm_writel(ptm, cpu, ptm.cfg.ext_output_event[i],
-							ETMEXTOUTEVRn(i));
-		for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
-			ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_value[i],
-							ETMCIDCVRn(i));
-		ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_mask, ETMCIDCMR);
-		ptm_writel(ptm, cpu, ptm.cfg.sync_freq, ETMSYNCFR);
-		ptm_writel(ptm, cpu, ptm.cfg.extnd_ext_input_sel, ETMEXTINSELR);
-		ptm_writel(ptm, cpu, ptm.cfg.ts_event, ETMTSEVR);
-		ptm_writel(ptm, cpu, ptm.cfg.aux_control, ETMAUXCR);
-		ptm_writel(ptm, cpu, cpu+1, ETMTRACEIDR);
-		ptm_writel(ptm, cpu, ptm.cfg.vmid_comp_value, ETMVMIDCVR);
-
-		ptm_clear_prog(cpu);
-		PTM_LOCK(cpu);
 	}
+	for (i = 0; i < ptm.cfg.nr_cntr; i++) {
+		ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_value[i],
+							ETMCNTRLDVRn(i));
+		ptm_writel(ptm, cpu, ptm.cfg.cntr_enable_event[i],
+							ETMCNTENRn(i));
+		ptm_writel(ptm, cpu, ptm.cfg.cntr_reload_event[i],
+							ETMCNTRLDEVRn(i));
+		ptm_writel(ptm, cpu, ptm.cfg.cntr_value[i], ETMCNTVRn(i));
+	}
+	ptm_writel(ptm, cpu, ptm.cfg.seq_state_12_event, ETMSQ12EVR);
+	ptm_writel(ptm, cpu, ptm.cfg.seq_state_21_event, ETMSQ21EVR);
+	ptm_writel(ptm, cpu, ptm.cfg.seq_state_23_event, ETMSQ23EVR);
+	ptm_writel(ptm, cpu, ptm.cfg.seq_state_32_event, ETMSQ32EVR);
+	ptm_writel(ptm, cpu, ptm.cfg.seq_state_13_event, ETMSQ13EVR);
+	ptm_writel(ptm, cpu, ptm.cfg.seq_state_31_event, ETMSQ31EVR);
+	ptm_writel(ptm, cpu, ptm.cfg.current_seq_state, ETMSQR);
+	for (i = 0; i < ptm.cfg.nr_ext_output; i++)
+		ptm_writel(ptm, cpu, ptm.cfg.ext_output_event[i],
+							ETMEXTOUTEVRn(i));
+	for (i = 0; i < ptm.cfg.nr_context_id_comp; i++)
+		ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_value[i],
+							ETMCIDCVRn(i));
+	ptm_writel(ptm, cpu, ptm.cfg.context_id_comp_mask, ETMCIDCMR);
+	ptm_writel(ptm, cpu, ptm.cfg.sync_freq, ETMSYNCFR);
+	ptm_writel(ptm, cpu, ptm.cfg.extnd_ext_input_sel, ETMEXTINSELR);
+	ptm_writel(ptm, cpu, ptm.cfg.ts_event, ETMTSEVR);
+	ptm_writel(ptm, cpu, ptm.cfg.aux_control, ETMAUXCR);
+	ptm_writel(ptm, cpu, cpu+1, ETMTRACEIDR);
+	ptm_writel(ptm, cpu, ptm.cfg.vmid_comp_value, ETMVMIDCVR);
+
+	ptm_clear_prog(cpu);
+	PTM_LOCK(cpu);
 }
 
 static int ptm_trace_enable(void)
 {
-	int ret;
+	int ret, cpu;
 
-	ret = ptm_clock_enable();
+	ret = qdss_clk_enable();
 	if (ret)
 		return ret;
 
@@ -388,9 +327,8 @@
 	/* enable ETB first to avoid loosing any trace data */
 	etb_enable();
 	funnel_enable(0x0, 0x3);
-	ptm_os_unlock(NULL);
-	smp_call_function(ptm_os_unlock, NULL, 1);
-	__ptm_trace_enable();
+	for_each_online_cpu(cpu)
+		__ptm_trace_enable(cpu);
 
 	ptm.trace_enabled = true;
 
@@ -400,24 +338,23 @@
 	return 0;
 }
 
-static void __ptm_trace_disable(void)
+static void __ptm_trace_disable(int cpu)
 {
-	int cpu;
+	PTM_UNLOCK(cpu);
+	ptm_set_prog(cpu);
 
-	for_each_online_cpu(cpu) {
-		PTM_UNLOCK(cpu);
-		ptm_set_prog(cpu);
+	/* program trace enable to low by using always false event */
+	ptm_writel(ptm, cpu, 0x6F | BIT(14), ETMTEEVR);
 
-		/* program trace enable to low by using always false event */
-		ptm_writel(ptm, cpu, 0x6F | BIT(14), ETMTEEVR);
-
-		ptm_set_powerdown(cpu);
-		PTM_LOCK(cpu);
-	}
+	/* Vote for ETM power/clock disable */
+	ptm_set_powerdown(cpu);
+	PTM_LOCK(cpu);
 }
 
 static void ptm_trace_disable(void)
 {
+	int cpu;
+
 	wake_lock(&ptm.wake_lock);
 	/* 1. causes all online cpus to come out of idle PC
 	 * 2. prevents idle PC until save restore flag is disabled atomically
@@ -428,7 +365,8 @@
 	 */
 	pm_qos_update_request(&ptm.qos_req, 0);
 
-	__ptm_trace_disable();
+	for_each_online_cpu(cpu)
+		__ptm_trace_disable(cpu);
 	etb_dump();
 	etb_disable();
 	funnel_disable(0x0, 0x3);
@@ -438,7 +376,7 @@
 	pm_qos_update_request(&ptm.qos_req, PM_QOS_DEFAULT_VALUE);
 	wake_unlock(&ptm.wake_lock);
 
-	ptm_clock_disable();
+	qdss_clk_disable();
 }
 
 static int ptm_open(struct inode *inode, struct file *file)
@@ -597,151 +535,6 @@
 	.fops =		&ptm_fops,
 };
 
-static void ptm_save_reg(int cpu)
-{
-	uint32_t i;
-	int j;
-
-	PTM_UNLOCK(cpu);
-
-	i = cpu * MAX_TRACE_REGS;
-
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMCR);
-	ptm_set_prog(cpu);
-
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMTRIGGER);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMTSSCR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMTEEVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMTECR1);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMFFLR);
-	for (j = 0; j < ptm.cfg.nr_addr_comp; j++) {
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMACVRn(j));
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMACTRn(j));
-	}
-	for (j = 0; j < ptm.cfg.nr_cntr; j++) {
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMCNTRLDVRn(j));
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMCNTENRn(j));
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMCNTRLDEVRn(j));
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMCNTVRn(j));
-	}
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSQ12EVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSQ21EVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSQ23EVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSQ32EVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSQ13EVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSQ31EVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSQR);
-	for (j = 0; j < ptm.cfg.nr_ext_output; j++)
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMEXTOUTEVRn(j));
-	for (j = 0; j < ptm.cfg.nr_context_id_comp; j++)
-		ptm.state[i++] = ptm_readl(ptm, cpu, ETMCIDCVRn(j));
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMCIDCMR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMSYNCFR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMEXTINSELR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMTSEVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMAUXCR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMTRACEIDR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, ETMVMIDCVR);
-	ptm.state[i++] = ptm_readl(ptm, cpu, CS_CLAIMSET);
-	ptm.state[i++] = ptm_readl(ptm, cpu, CS_CLAIMCLR);
-
-	PTM_LOCK(cpu);
-}
-
-static void ptm_restore_reg(int cpu)
-{
-	uint32_t i;
-	int j;
-
-	ptm_os_unlock(NULL);
-	PTM_UNLOCK(cpu);
-
-	i = cpu * MAX_TRACE_REGS;
-
-	ptm_clear_powerdown(cpu);
-	ptm_set_prog(cpu);
-	/* Ensure prog bit doesn't get cleared since we have set it above.
-	 * Power down bit should already be clear in the saved state.
-	 */
-	ptm_writel(ptm, cpu, ptm.state[i++] | BIT(10), ETMCR);
-
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMTRIGGER);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMTSSCR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMTEEVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMTECR1);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMFFLR);
-	for (j = 0; j < ptm.cfg.nr_addr_comp; j++) {
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMACVRn(j));
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMACTRn(j));
-	}
-	for (j = 0; j < ptm.cfg.nr_cntr; j++) {
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMCNTRLDVRn(j));
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMCNTENRn(j));
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMCNTRLDEVRn(j));
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMCNTVRn(j));
-	}
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSQ12EVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSQ21EVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSQ23EVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSQ32EVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSQ13EVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSQ31EVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSQR);
-	for (j = 0; j < ptm.cfg.nr_ext_output; j++)
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMEXTOUTEVRn(j));
-	for (j = 0; j < ptm.cfg.nr_context_id_comp; j++)
-		ptm_writel(ptm, cpu, ptm.state[i++], ETMCIDCVRn(j));
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMCIDCMR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMSYNCFR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMEXTINSELR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMTSEVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMAUXCR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMTRACEIDR);
-	ptm_writel(ptm, cpu, ptm.state[i++], ETMVMIDCVR);
-	ptm_writel(ptm, cpu, ptm.state[i++], CS_CLAIMSET);
-	ptm_writel(ptm, cpu, ptm.state[i++], CS_CLAIMCLR);
-
-	ptm_clear_prog(cpu);
-
-	PTM_LOCK(cpu);
-}
-
-/* etm_save_reg_check and etm_restore_reg_check should be fast
- *
- * These functions will be called either from:
- * 1. per_cpu idle thread context for idle power collapses.
- * 2. per_cpu idle thread context for hotplug/suspend power collapse for
- *    nonboot cpus.
- * 3. suspend thread context for core0.
- *
- * In all cases we are guaranteed to be running on the same cpu for the
- * entire duration.
- *
- * Another assumption is that etm registers won't change after trace_enabled
- * is set. Current usage model guarantees this doesn't happen.
- *
- * Also disabling all types of power_collapses when enabling and disabling
- * trace provides mutual exclusion to be able to safely access
- * ptm.trace_enabled here.
- */
-void etm_save_reg_check(void)
-{
-	if (ptm.trace_enabled) {
-		int cpu = smp_processor_id();
-		ptm_save_reg(cpu);
-	}
-}
-
-void etm_restore_reg_check(void)
-{
-	if (ptm.trace_enabled) {
-		int cpu = smp_processor_id();
-		ptm_restore_reg(cpu);
-	}
-}
-
 static void ptm_cfg_rw_init(void)
 {
 	int i;
@@ -781,14 +574,25 @@
 	ptm.cfg.vmid_comp_value =			0x00000000;
 }
 
+/* Memory mapped writes to clear os lock not supported */
+static void ptm_os_unlock(void *unused)
+{
+	unsigned long value = 0x0;
+
+	asm("mcr p14, 1, %0, c1, c0, 4\n\t" : : "r" (value));
+	asm("isb\n\t");
+}
+
 static void ptm_cfg_ro_init(void)
 {
 	/* use cpu 0 for setup */
 	int cpu = 0;
 
+	/* Unlock OS lock first to allow memory mapped reads and writes */
 	ptm_os_unlock(NULL);
 	smp_call_function(ptm_os_unlock, NULL, 1);
 	PTM_UNLOCK(cpu);
+	/* Vote for ETM power/clock enable */
 	ptm_clear_powerdown(cpu);
 	ptm_set_prog(cpu);
 
@@ -809,6 +613,7 @@
 	ptm.cfg.fifofull_supported =	BVAL(ptm.cfg.system_config, 8);
 	ptm.cfg.nr_procs_supported =	BMVAL(ptm.cfg.system_config, 12, 14);
 
+	/* Vote for ETM power/clock disable */
 	ptm_set_powerdown(cpu);
 	PTM_LOCK(cpu);
 }
@@ -832,71 +637,13 @@
 
 	ptm.dev = &pdev->dev;
 
-	ptm.state = kzalloc(MAX_STATE_SIZE * sizeof(uint32_t), GFP_KERNEL);
-	if (!ptm.state) {
-		ret = -ENOMEM;
-		goto err_kzalloc;
-	}
-
 	ret = misc_register(&ptm_misc);
 	if (ret)
 		goto err_misc;
 
-	ptm.qdss_at_clk = clk_get(NULL, "qdss_at_clk");
-	if (IS_ERR(ptm.qdss_at_clk)) {
-		ret = PTR_ERR(ptm.qdss_at_clk);
-		goto err_at;
-	}
-	ret = clk_set_rate(ptm.qdss_at_clk, 300000000);
+	ret = qdss_clk_enable();
 	if (ret)
-		goto err_at_rate;
-	ret = clk_enable(ptm.qdss_at_clk);
-	if (ret)
-		goto err_at_enable;
-
-	ptm.qdss_pclkdbg_clk = clk_get(NULL, "qdss_pclkdbg_clk");
-	if (IS_ERR(ptm.qdss_pclkdbg_clk)) {
-		ret = PTR_ERR(ptm.qdss_pclkdbg_clk);
-		goto err_pclkdbg;
-	}
-	ret = clk_enable(ptm.qdss_pclkdbg_clk);
-	if (ret)
-		goto err_pclkdbg_enable;
-
-	ptm.qdss_pclk = clk_get(NULL, "qdss_pclk");
-	if (IS_ERR(ptm.qdss_pclk)) {
-		ret = PTR_ERR(ptm.qdss_pclk);
-		goto err_pclk;
-	}
-
-	ret = clk_enable(ptm.qdss_pclk);
-	if (ret)
-		goto err_pclk_enable;
-
-	ptm.qdss_traceclkin_clk = clk_get(NULL, "qdss_traceclkin_clk");
-	if (IS_ERR(ptm.qdss_traceclkin_clk)) {
-		ret = PTR_ERR(ptm.qdss_traceclkin_clk);
-		goto err_traceclkin;
-	}
-	ret = clk_set_rate(ptm.qdss_traceclkin_clk, 300000000);
-	if (ret)
-		goto err_traceclkin_rate;
-	ret = clk_enable(ptm.qdss_traceclkin_clk);
-	if (ret)
-		goto err_traceclkin_enable;
-
-	ptm.qdss_tsctr_clk = clk_get(NULL, "qdss_tsctr_clk");
-	if (IS_ERR(ptm.qdss_tsctr_clk)) {
-		ret = PTR_ERR(ptm.qdss_tsctr_clk);
-		goto err_tsctr;
-	}
-	ret = clk_set_rate(ptm.qdss_tsctr_clk, 400000000);
-	if (ret)
-		goto err_tsctr_rate;
-
-	ret = clk_enable(ptm.qdss_tsctr_clk);
-	if (ret)
-		goto err_tsctr_enable;
+		goto err_clk;
 
 	ptm_cfg_ro_init();
 	ptm_cfg_rw_init();
@@ -908,11 +655,7 @@
 						PM_QOS_DEFAULT_VALUE);
 	atomic_set(&ptm.in_use, 0);
 
-	clk_disable(ptm.qdss_tsctr_clk);
-	clk_disable(ptm.qdss_traceclkin_clk);
-	clk_disable(ptm.qdss_pclk);
-	clk_disable(ptm.qdss_pclkdbg_clk);
-	clk_disable(ptm.qdss_at_clk);
+	qdss_clk_disable();
 
 	dev_info(ptm.dev, "PTM intialized.\n");
 
@@ -925,51 +668,22 @@
 
 	return 0;
 
-err_tsctr_enable:
-err_tsctr_rate:
-	clk_put(ptm.qdss_tsctr_clk);
-err_tsctr:
-	clk_disable(ptm.qdss_traceclkin_clk);
-err_traceclkin_enable:
-err_traceclkin_rate:
-	clk_put(ptm.qdss_traceclkin_clk);
-err_traceclkin:
-	clk_disable(ptm.qdss_pclk);
-err_pclk_enable:
-	clk_put(ptm.qdss_pclk);
-err_pclk:
-	clk_disable(ptm.qdss_pclkdbg_clk);
-err_pclkdbg_enable:
-	clk_put(ptm.qdss_pclkdbg_clk);
-err_pclkdbg:
-	clk_disable(ptm.qdss_at_clk);
-err_at_enable:
-err_at_rate:
-	clk_put(ptm.qdss_at_clk);
-err_at:
+err_clk:
 	misc_deregister(&ptm_misc);
 err_misc:
-	kfree(ptm.state);
-err_kzalloc:
 	iounmap(ptm.base);
 err_ioremap:
 err_res:
 	return ret;
 }
 
-static int __devexit ptm_remove(struct platform_device *pdev)
+static int ptm_remove(struct platform_device *pdev)
 {
 	if (ptm.trace_enabled)
 		ptm_trace_disable();
 	pm_qos_remove_request(&ptm.qos_req);
 	wake_lock_destroy(&ptm.wake_lock);
-	clk_put(ptm.qdss_tsctr_clk);
-	clk_put(ptm.qdss_traceclkin_clk);
-	clk_put(ptm.qdss_pclk);
-	clk_put(ptm.qdss_pclkdbg_clk);
-	clk_put(ptm.qdss_at_clk);
 	misc_deregister(&ptm_misc);
-	kfree(ptm.state);
 	iounmap(ptm.base);
 
 	return 0;
@@ -977,23 +691,18 @@
 
 static struct platform_driver ptm_driver = {
 	.probe          = ptm_probe,
-	.remove         = __devexit_p(ptm_remove),
+	.remove         = ptm_remove,
 	.driver         = {
 		.name   = "msm_ptm",
 	},
 };
 
-static int __init ptm_init(void)
+int __init ptm_init(void)
 {
 	return platform_driver_register(&ptm_driver);
 }
-module_init(ptm_init);
 
-static void __exit ptm_exit(void)
+void ptm_exit(void)
 {
 	platform_driver_unregister(&ptm_driver);
 }
-module_exit(ptm_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Coresight Program Flow Trace driver");
diff --git a/arch/arm/mach-msm/qdss-tpiu.c b/arch/arm/mach-msm/qdss-tpiu.c
index 60a8dd2..e4a61de 100644
--- a/arch/arm/mach-msm/qdss-tpiu.c
+++ b/arch/arm/mach-msm/qdss-tpiu.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
@@ -47,11 +47,11 @@
 #define TPIU_LOCK()							\
 do {									\
 	mb();								\
-	tpiu_writel(tpiu, MAGIC2, CS_LAR);				\
+	tpiu_writel(tpiu, 0x0, CS_LAR);					\
 } while (0)
 #define TPIU_UNLOCK()							\
 do {									\
-	tpiu_writel(tpiu, MAGIC1, CS_LAR);				\
+	tpiu_writel(tpiu, CS_UNLOCK_MAGIC, CS_LAR);			\
 	mb();								\
 } while (0)
 
@@ -106,7 +106,7 @@
 	return ret;
 }
 
-static int __devexit tpiu_remove(struct platform_device *pdev)
+static int tpiu_remove(struct platform_device *pdev)
 {
 	if (tpiu.enabled)
 		tpiu_disable();
@@ -117,23 +117,18 @@
 
 static struct platform_driver tpiu_driver = {
 	.probe          = tpiu_probe,
-	.remove         = __devexit_p(tpiu_remove),
+	.remove         = tpiu_remove,
 	.driver         = {
 		.name   = "msm_tpiu",
 	},
 };
 
-static int __init tpiu_init(void)
+int __init tpiu_init(void)
 {
 	return platform_driver_register(&tpiu_driver);
 }
-module_init(tpiu_init);
 
-static void __exit tpiu_exit(void)
+void tpiu_exit(void)
 {
 	platform_driver_unregister(&tpiu_driver);
 }
-module_exit(tpiu_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Coresight Trace Port Interface Unit");
diff --git a/arch/arm/mach-msm/qdss.c b/arch/arm/mach-msm/qdss.c
new file mode 100644
index 0000000..55d14cd
--- /dev/null
+++ b/arch/arm/mach-msm/qdss.c
@@ -0,0 +1,101 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <mach/rpm.h>
+
+#include "rpm_resources.h"
+#include "qdss.h"
+
+enum {
+	QDSS_CLK_OFF,
+	QDSS_CLK_ON_DBG,
+	QDSS_CLK_ON_HSDBG,
+};
+
+
+int qdss_clk_enable(void)
+{
+	int ret;
+
+	struct msm_rpm_iv_pair iv;
+	iv.id = MSM_RPM_ID_QDSS_CLK;
+	iv.value = QDSS_CLK_ON_DBG;
+	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
+	if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
+		goto err_clk;
+
+	return 0;
+
+err_clk:
+	return ret;
+}
+
+void qdss_clk_disable(void)
+{
+	int ret;
+	struct msm_rpm_iv_pair iv;
+
+	iv.id = MSM_RPM_ID_QDSS_CLK;
+	iv.value = QDSS_CLK_OFF;
+	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
+	WARN(ret, "qdss clks not disabled (%d)\n", ret);
+}
+
+static int __init qdss_init(void)
+{
+	int ret;
+
+	ret = etb_init();
+	if (ret)
+		goto err_etb;
+	ret = tpiu_init();
+	if (ret)
+		goto err_tpiu;
+	ret = funnel_init();
+	if (ret)
+		goto err_funnel;
+	ret = ptm_init();
+	if (ret)
+		goto err_ptm;
+
+	return 0;
+
+err_ptm:
+	funnel_exit();
+err_funnel:
+	tpiu_exit();
+err_tpiu:
+	etb_exit();
+err_etb:
+	return ret;
+}
+module_init(qdss_init);
+
+static void __exit qdss_exit(void)
+{
+	ptm_exit();
+	funnel_exit();
+	tpiu_exit();
+	etb_exit();
+}
+module_exit(qdss_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm Debug SubSystem Driver");
diff --git a/arch/arm/mach-msm/qdss.h b/arch/arm/mach-msm/qdss.h
index 8d346c4..199222a 100644
--- a/arch/arm/mach-msm/qdss.h
+++ b/arch/arm/mach-msm/qdss.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
@@ -15,7 +15,10 @@
 
 #include <linux/bitops.h>
 
-/* Coresight management registers (0xF00-0xFCC) */
+/* Coresight management registers (0xF00-0xFCC)
+ * 0xFA0 - 0xFA4: Management	registers in PFTv1.0
+ *		  Trace		registers in PFTv1.1
+ */
 #define CS_ITCTRL		(0xF00)
 #define CS_CLAIMSET		(0xFA0)
 #define CS_CLAIMCLR		(0xFA4)
@@ -39,36 +42,46 @@
 #define CS_CIDR2		(0xFF8)
 #define CS_CIDR3		(0xFFC)
 
+/* DBGv7 with baseline CP14 registers implemented */
+#define ARM_DEBUG_ARCH_V7B	(0x3)
+/* DBGv7 with all CP14 registers implemented */
+#define ARM_DEBUG_ARCH_V7	(0x4)
+#define ARM_DEBUG_ARCH_V7_1	(0x5)
+#define ETM_ARCH_V3_3		(0x23)
+#define PFT_ARCH_V1_1		(0x31)
 
-#define TIMEOUT_US		100
-#define MAGIC1			0xC5ACCE55
-#define MAGIC2			0x0
+#define TIMEOUT_US		(100)
+#define OSLOCK_MAGIC		(0xC5ACCE55)
+#define CS_UNLOCK_MAGIC		(0xC5ACCE55)
 
 #define BM(lsb, msb)		((BIT(msb) - BIT(lsb)) + BIT(msb))
 #define BMVAL(val, lsb, msb)	((val & BM(lsb, msb)) >> lsb)
 #define BVAL(val, n)		((val & BIT(n)) >> n)
 
-/* TODO: clean this up */
+int etb_init(void);
+void etb_exit(void);
+int tpiu_init(void);
+void tpiu_exit(void);
+int funnel_init(void);
+void funnel_exit(void);
+int ptm_init(void);
+void ptm_exit(void);
+
 void etb_enable(void);
 void etb_disable(void);
 void etb_dump(void);
 void tpiu_disable(void);
 void funnel_enable(uint8_t id, uint32_t port_mask);
 void funnel_disable(uint8_t id, uint32_t port_mask);
+int qdss_clk_enable(void);
+void qdss_clk_disable(void);
 
-#ifdef CONFIG_MSM_DEBUG_ACROSS_PC
-extern void msm_save_jtag_debug(void);
-extern void msm_restore_jtag_debug(void);
+#ifdef CONFIG_MSM_JTAG
+extern void msm_jtag_save_state(void);
+extern void msm_jtag_restore_state(void);
 #else
-static inline void msm_save_jtag_debug(void) {}
-static inline void msm_restore_jtag_debug(void) {}
-#endif
-#ifdef CONFIG_MSM_TRACE_ACROSS_PC
-extern void etm_save_reg_check(void);
-extern void etm_restore_reg_check(void);
-#else
-static inline void etm_save_reg_check(void) {}
-static inline void etm_restore_reg_check(void) {}
+static inline void msm_jtag_save_state(void) {}
+static inline void msm_jtag_restore_state(void) {}
 #endif
 
 #endif
diff --git a/arch/arm/mach-msm/rfic-fsm9xxx.c b/arch/arm/mach-msm/rfic-fsm9xxx.c
index 68147c6..32b654b 100644
--- a/arch/arm/mach-msm/rfic-fsm9xxx.c
+++ b/arch/arm/mach-msm/rfic-fsm9xxx.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -158,9 +158,6 @@
 	pdev = ftr_dev_info + pdfi->ftrId;
 
 	switch (cmd) {
-	case RFIC_IOCTL_IS_UMTS:
-		return __raw_readl(MSM_TCSR_BASE + 0x0008) & 0x01;
-
 	case RFIC_IOCTL_READ_REGISTER:
 		{
 			int ret;
diff --git a/arch/arm/mach-msm/rpm_resources.h b/arch/arm/mach-msm/rpm_resources.h
index 572fb34..e849208 100644
--- a/arch/arm/mach-msm/rpm_resources.h
+++ b/arch/arm/mach-msm/rpm_resources.h
@@ -15,7 +15,7 @@
 #define __ARCH_ARM_MACH_MSM_RPM_RESOURCES_H
 
 #include <mach/rpm.h>
-#include "pm.h"
+#include <mach/pm.h>
 
 
 struct msm_rpmrs_limits {
diff --git a/arch/arm/mach-msm/scm-pas.c b/arch/arm/mach-msm/scm-pas.c
index 0a9b27c..747b585 100644
--- a/arch/arm/mach-msm/scm-pas.c
+++ b/arch/arm/mach-msm/scm-pas.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
@@ -94,7 +94,7 @@
 {
 	int ret = 0;
 
-	if (!scm_perf_client || scm_bus_clk)
+	if (!scm_perf_client || !scm_bus_clk)
 		return -EINVAL;
 
 	mutex_lock(&scm_pas_bw_mutex);
diff --git a/arch/arm/mach-msm/smd.c b/arch/arm/mach-msm/smd.c
index b31550a..514f817 100644
--- a/arch/arm/mach-msm/smd.c
+++ b/arch/arm/mach-msm/smd.c
@@ -667,7 +667,8 @@
 		/* restart SMSM init handshake */
 		if (restart_pid == SMSM_MODEM) {
 			smsm_change_state(SMSM_APPS_STATE,
-					SMSM_INIT | SMSM_SMD_LOOPBACK, 0);
+				SMSM_INIT | SMSM_SMD_LOOPBACK | SMSM_RESET,
+				0);
 		}
 
 		/* notify SMSM processors */
diff --git a/arch/arm/mach-msm/socinfo.c b/arch/arm/mach-msm/socinfo.c
index 0c2d4f7..9a8ab43 100644
--- a/arch/arm/mach-msm/socinfo.c
+++ b/arch/arm/mach-msm/socinfo.c
@@ -213,6 +213,8 @@
 	/* 9x15 ID */
 	[104] = MSM_CPU_9615,
 	[105] = MSM_CPU_9615,
+	[106] = MSM_CPU_9615,
+	[107] = MSM_CPU_9615,
 
 	/* 8064 IDs */
 	[109] = MSM_CPU_8064,
diff --git a/arch/arm/mach-msm/spm.h b/arch/arm/mach-msm/spm.h
index 5825bcf..78fd922 100644
--- a/arch/arm/mach-msm/spm.h
+++ b/arch/arm/mach-msm/spm.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
@@ -110,6 +110,7 @@
 void msm_spm_reinit(void);
 void msm_spm_allow_x_cpu_set_vdd(bool allowed);
 int msm_spm_init(struct msm_spm_platform_data *data, int nr_devs);
+int msm_spm_turn_on_cpu_rail(unsigned int cpu);
 
 #if defined(CONFIG_MSM_L2_SPM)
 int msm_spm_l2_set_low_power_mode(unsigned int mode, bool notify_rpm);
@@ -148,6 +149,10 @@
 	/* empty */
 }
 
+static inline int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+	return -ENOSYS;
+}
 #endif  /*defined(CONFIG_MSM_SPM_V1) || defined (CONFIG_MSM_SPM_V2) */
 
 #endif  /* __ARCH_ARM_MACH_MSM_SPM_H */
diff --git a/arch/arm/mach-msm/spm_devices.c b/arch/arm/mach-msm/spm_devices.c
index 6ea9327..326faef 100644
--- a/arch/arm/mach-msm/spm_devices.c
+++ b/arch/arm/mach-msm/spm_devices.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
@@ -162,6 +162,40 @@
 	return ret;
 }
 
+int msm_spm_turn_on_cpu_rail(unsigned int cpu)
+{
+	uint32_t val = 0;
+	uint32_t timeout = 0;
+	void *reg = NULL;
+
+	if (cpu >= num_possible_cpus())
+		return -EINVAL;
+
+	switch (cpu) {
+	case 1:
+		reg = MSM_SAW1_BASE;
+		break;
+	case 0:
+	default:
+		return -EFAULT;
+	}
+
+	if (cpu_is_msm8960() || cpu_is_msm8930()) {
+		val = 0xB0;
+		reg += 0x14;
+		timeout = 512;
+	} else {
+		return -ENOSYS;
+	}
+
+	writel_relaxed(val, reg);
+	mb();
+	udelay(timeout);
+
+	return 0;
+}
+EXPORT_SYMBOL(msm_spm_turn_on_cpu_rail);
+
 #if defined(CONFIG_MSM_L2_SPM)
 static struct msm_spm_device msm_spm_l2_device;
 
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index 61e65d2..67b1f7b 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -405,11 +405,7 @@
  */
 static void (*msm_timer_sync_timeout)(void);
 #if defined(CONFIG_MSM_DIRECT_SCLK_ACCESS)
-static uint32_t msm_timer_do_sync_to_sclk(
-	void (*time_start)(struct msm_timer_sync_data_t *data),
-	bool (*time_expired)(struct msm_timer_sync_data_t *data),
-	void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
-	struct msm_timer_sync_data_t *data)
+uint32_t msm_timer_get_sclk_ticks(void)
 {
 	uint32_t t1, t2;
 	int loop_count = 10;
@@ -442,7 +438,18 @@
 		return 0;
 	}
 
-	if (update != NULL)
+	return t1;
+}
+
+static uint32_t msm_timer_do_sync_to_sclk(
+	void (*time_start)(struct msm_timer_sync_data_t *data),
+	bool (*time_expired)(struct msm_timer_sync_data_t *data),
+	void (*update)(struct msm_timer_sync_data_t *, uint32_t, uint32_t),
+	struct msm_timer_sync_data_t *data)
+{
+	unsigned t1 = msm_timer_get_sclk_ticks();
+
+	if (t1 && update != NULL)
 		update(data, t1, sclk_hz);
 	return t1;
 }
diff --git a/arch/arm/mach-msm/timer.h b/arch/arm/mach-msm/timer.h
index 545675c..caef19d 100644
--- a/arch/arm/mach-msm/timer.h
+++ b/arch/arm/mach-msm/timer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2009, 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -20,5 +20,6 @@
 int64_t msm_timer_enter_idle(void);
 void msm_timer_exit_idle(int low_power);
 int64_t msm_timer_get_sclk_time(int64_t *period);
+uint32_t msm_timer_get_sclk_ticks(void);
 int msm_timer_init_time_sync(void (*timeout)(void));
 #endif
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index f493f79..a9faff0 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -204,6 +204,7 @@
 	struct diag_request *write_ptr_qdsp_2;
 	struct diag_request *write_ptr_wcnss;
 	int logging_mode;
+	int mask_check;
 	int logging_process_id;
 #ifdef CONFIG_DIAG_SDIO_PIPE
 	unsigned char *buf_in_sdio;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 799be72..a703148 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -369,8 +369,12 @@
 		mutex_lock(&driver->diagchar_mutex);
 		temp = driver->logging_mode;
 		driver->logging_mode = (int)ioarg;
-		if (driver->logging_mode == UART_MODE)
+		if (driver->logging_mode == MEMORY_DEVICE_MODE)
+			driver->mask_check = 1;
+		if (driver->logging_mode == UART_MODE) {
+			driver->mask_check = 0;
 			driver->logging_mode = MEMORY_DEVICE_MODE;
+		}
 		driver->logging_process_id = current->tgid;
 		mutex_unlock(&driver->diagchar_mutex);
 		if (temp == MEMORY_DEVICE_MODE && driver->logging_mode
@@ -693,7 +697,7 @@
 		err = copy_from_user(driver->user_space_data, buf + 4,
 							 payload_size);
 		/* Check masks for On-Device logging */
-		if (pkt_type == USER_SPACE_LOG_TYPE) {
+		if (driver->mask_check) {
 			if (!mask_request_validate(driver->user_space_data)) {
 				pr_alert("diag: mask request Invalid\n");
 				return -EFAULT;
@@ -1018,6 +1022,7 @@
 		driver->poolsize_write_struct = poolsize_write_struct;
 		driver->num_clients = max_clients;
 		driver->logging_mode = USB_MODE;
+		driver->mask_check = 0;
 		mutex_init(&driver->diagchar_mutex);
 		init_waitqueue_head(&driver->wait_q);
 		INIT_WORK(&(driver->diag_drain_work), diag_drain_work_fn);
diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile
index 3911950..c9e8a94 100644
--- a/drivers/gpu/ion/Makefile
+++ b/drivers/gpu/ion/Makefile
@@ -1,3 +1,3 @@
-obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o
+obj-$(CONFIG_ION) +=	ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o ion_iommu_heap.o ion_cp_heap.o
 obj-$(CONFIG_ION_TEGRA) += tegra/
 obj-$(CONFIG_ION_MSM) += msm/
diff --git a/drivers/gpu/ion/ion.c b/drivers/gpu/ion/ion.c
index 1428315..d436ef4 100644
--- a/drivers/gpu/ion/ion.c
+++ b/drivers/gpu/ion/ion.c
@@ -2,6 +2,7 @@
  * drivers/gpu/ion/ion.c
  *
  * Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -363,6 +364,7 @@
 	struct ion_handle *handle;
 	struct ion_device *dev = client->dev;
 	struct ion_buffer *buffer = NULL;
+	unsigned long secure_allocation = flags & ION_SECURE;
 
 	/*
 	 * traverse the list of heaps available in this system in priority
@@ -379,6 +381,9 @@
 		/* if the caller didn't specify this heap type */
 		if (!((1 << heap->id) & flags))
 			continue;
+		/* Do not allow un-secure heap if secure is specified */
+		if (secure_allocation && (heap->type != ION_HEAP_TYPE_CP))
+			continue;
 		buffer = ion_buffer_create(heap, dev, len, align, flags);
 		if (!IS_ERR_OR_NULL(buffer))
 			break;
@@ -1350,7 +1355,7 @@
 					     data.flags);
 
 		if (IS_ERR_OR_NULL(data.handle))
-			return PTR_ERR(data.handle);
+			return -ENOMEM;
 
 		if (copy_to_user((void __user *)arg, &data, sizeof(data)))
 			return -EFAULT;
@@ -1571,6 +1576,22 @@
 		seq_printf(s, "total heap size: %lx\n",
 			heap->ops->get_total(heap));
 	}
+	if (heap->ops->get_alloc_cnt) {
+		seq_printf(s, "allocation count: %lx\n",
+			heap->ops->get_alloc_cnt(heap));
+	}
+	if (heap->ops->get_umap_cnt) {
+		seq_printf(s, "umapping count: %lx\n",
+			heap->ops->get_umap_cnt(heap));
+	}
+	if (heap->ops->get_kmap_cnt) {
+		seq_printf(s, "kmapping count: %lx\n",
+			heap->ops->get_kmap_cnt(heap));
+	}
+	if (heap->ops->get_secured) {
+		seq_printf(s, "secured heap: %s\n",
+			heap->ops->get_secured(heap) ? "Yes" : "No");
+	}
 	return 0;
 }
 
@@ -1617,6 +1638,60 @@
 	mutex_unlock(&dev->lock);
 }
 
+int ion_secure_heap(struct ion_device *dev, int heap_id)
+{
+	struct rb_node *n;
+	int ret_val = 0;
+
+	/*
+	 * traverse the list of heaps available in this system
+	 * and find the heap that is specified.
+	 */
+	mutex_lock(&dev->lock);
+	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
+		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
+		if (heap->type != ION_HEAP_TYPE_CP)
+			continue;
+		if (ION_HEAP(heap->id) != heap_id)
+			continue;
+		if (heap->ops->secure_heap)
+			ret_val = heap->ops->secure_heap(heap);
+		else
+			ret_val = -EINVAL;
+		break;
+	}
+	mutex_unlock(&dev->lock);
+	return ret_val;
+}
+EXPORT_SYMBOL(ion_secure_heap);
+
+int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+{
+	struct rb_node *n;
+	int ret_val = 0;
+
+	/*
+	 * traverse the list of heaps available in this system
+	 * and find the heap that is specified.
+	 */
+	mutex_lock(&dev->lock);
+	for (n = rb_first(&dev->heaps); n != NULL; n = rb_next(n)) {
+		struct ion_heap *heap = rb_entry(n, struct ion_heap, node);
+		if (heap->type != ION_HEAP_TYPE_CP)
+			continue;
+		if (ION_HEAP(heap->id) != heap_id)
+			continue;
+		if (heap->ops->secure_heap)
+			ret_val = heap->ops->unsecure_heap(heap);
+		else
+			ret_val = -EINVAL;
+		break;
+	}
+	mutex_unlock(&dev->lock);
+	return ret_val;
+}
+EXPORT_SYMBOL(ion_unsecure_heap);
+
 static int ion_debug_leak_show(struct seq_file *s, void *unused)
 {
 	struct ion_device *dev = s->private;
diff --git a/drivers/gpu/ion/ion_carveout_heap.c b/drivers/gpu/ion/ion_carveout_heap.c
index f1d40ef..1c35f5c 100644
--- a/drivers/gpu/ion/ion_carveout_heap.c
+++ b/drivers/gpu/ion/ion_carveout_heap.c
@@ -2,7 +2,7 @@
  * drivers/gpu/ion/ion_carveout_heap.c
  *
  * Copyright (C) 2011 Google, Inc.
- * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -401,6 +401,7 @@
 	ret = gen_pool_add(carveout_heap->pool, carveout_heap->base,
 			heap_data->size, -1);
 	if (ret < 0) {
+		gen_pool_destroy(carveout_heap->pool);
 		kfree(carveout_heap);
 		return ERR_PTR(-EINVAL);
 	}
@@ -408,13 +409,20 @@
 	carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
 	carveout_heap->allocated_bytes = 0;
 	carveout_heap->total_size = heap_data->size;
-	if (heap_data->setup_region)
-		carveout_heap->bus_id = heap_data->setup_region();
-	if (heap_data->request_region)
-		carveout_heap->request_region = heap_data->request_region;
-	if (heap_data->release_region)
-		carveout_heap->release_region = heap_data->release_region;
 
+	if (heap_data->extra_data) {
+		struct ion_co_heap_pdata *extra_data =
+				heap_data->extra_data;
+
+		if (extra_data->setup_region)
+			carveout_heap->bus_id = extra_data->setup_region();
+		if (extra_data->request_region)
+			carveout_heap->request_region =
+					extra_data->request_region;
+		if (extra_data->release_region)
+			carveout_heap->release_region =
+					extra_data->release_region;
+	}
 	return &carveout_heap->heap;
 }
 
diff --git a/drivers/gpu/ion/ion_cp_heap.c b/drivers/gpu/ion/ion_cp_heap.c
new file mode 100644
index 0000000..5737d21
--- /dev/null
+++ b/drivers/gpu/ion/ion_cp_heap.c
@@ -0,0 +1,694 @@
+/*
+ * drivers/gpu/ion/ion_cp_heap.c
+ *
+ * Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/spinlock.h>
+
+#include <linux/err.h>
+#include <linux/genalloc.h>
+#include <linux/io.h>
+#include <linux/ion.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/memory_alloc.h>
+#include <mach/msm_memtypes.h>
+#include <mach/scm.h>
+#include "ion_priv.h"
+
+#include <asm/mach/map.h>
+
+/**
+ * struct ion_cp_heap - container for the heap and shared heap data
+
+ * @heap:	the heap information structure
+ * @pool:	memory pool to allocate from.
+ * @base:	the base address of the memory pool.
+ * @permission_type:	Identifier for the memory used by SCM for protecting
+ *			and unprotecting memory.
+ * @lock:	mutex to protect shared access.
+ * @heap_secured:	Identifies the heap_id as secure or not.
+ * @allocated_bytes:	the total number of allocated bytes from the pool.
+ * @total_size:	the total size of the memory pool.
+ * @request_region:	function pointer to call when first mapping of memory
+ *			occurs.
+ * @release_region:	function pointer to call when last mapping of memory
+ *			unmapped.
+ * @bus_id: token used with request/release region.
+ * @kmap_count:	the total number of times this heap has been mapped in
+ *		kernel space.
+ * @umap_count:	the total number of times this heap has been mapped in
+ *		user space.
+ * @alloc_count:the total number of times this heap has been allocated
+ */
+struct ion_cp_heap {
+	struct ion_heap heap;
+	struct gen_pool *pool;
+	ion_phys_addr_t base;
+	unsigned int permission_type;
+	struct mutex lock;
+	unsigned int heap_secured;
+	unsigned long allocated_bytes;
+	unsigned long total_size;
+	int (*request_region)(void *);
+	int (*release_region)(void *);
+	void *bus_id;
+	unsigned long kmap_count;
+	unsigned long umap_count;
+	unsigned long alloc_count;
+};
+
+enum {
+	NON_SECURED_HEAP = 0,
+	SECURED_HEAP = 1,
+};
+
+static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+			unsigned int permission_type);
+
+static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+				unsigned int permission_type);
+
+
+/**
+ * Protects memory if heap is unsecured heap.
+ * Must be called with heap->lock locked.
+ */
+static int ion_cp_protect(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	int ret_value = 0;
+
+	if (cp_heap->heap_secured == NON_SECURED_HEAP) {
+		int ret_value = ion_cp_protect_mem(cp_heap->base,
+				cp_heap->total_size, cp_heap->permission_type);
+		if (ret_value) {
+			pr_err("Failed to protect memory for heap %s - "
+				"error code: %d", heap->name, ret_value);
+		} else {
+			cp_heap->heap_secured = SECURED_HEAP;
+			pr_debug("Protected heap %s @ 0x%x",
+				heap->name, (unsigned int) cp_heap->base);
+		}
+	}
+	return ret_value;
+}
+
+/**
+ * Unprotects memory if heap is secure heap.
+ * Must be called with heap->lock locked.
+ */
+static void ion_cp_unprotect(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+
+	if (cp_heap->heap_secured == SECURED_HEAP) {
+		int error_code = ion_cp_unprotect_mem(
+			cp_heap->base, cp_heap->total_size,
+			cp_heap->permission_type);
+		if (error_code) {
+			pr_err("Failed to un-protect memory for heap %s - "
+				"error code: %d", heap->name, error_code);
+		} else  {
+			cp_heap->heap_secured = NON_SECURED_HEAP;
+			pr_debug("Un-protected heap %s @ 0x%x", heap->name,
+				(unsigned int) cp_heap->base);
+		}
+	}
+}
+
+ion_phys_addr_t ion_cp_allocate(struct ion_heap *heap,
+				      unsigned long size,
+				      unsigned long align,
+				      unsigned long flags)
+{
+	unsigned long offset;
+	unsigned long secure_allocation = flags & ION_SECURE;
+
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+
+	mutex_lock(&cp_heap->lock);
+
+	if (!secure_allocation && cp_heap->heap_secured == SECURED_HEAP) {
+		mutex_unlock(&cp_heap->lock);
+		pr_err("ION cannot allocate un-secure memory from protected"
+			" heap %s", heap->name);
+		return ION_CP_ALLOCATE_FAIL;
+	}
+
+	if (secure_allocation && cp_heap->umap_count > 0) {
+		mutex_unlock(&cp_heap->lock);
+		pr_err("ION cannot allocate secure memory from heap with "
+			"outstanding user space mappings for heap %s",
+			heap->name);
+		return ION_CP_ALLOCATE_FAIL;
+	}
+
+	if (secure_allocation && ion_cp_protect(heap)) {
+		mutex_unlock(&cp_heap->lock);
+		return ION_CP_ALLOCATE_FAIL;
+	}
+
+	cp_heap->allocated_bytes += size;
+	++cp_heap->alloc_count;
+	mutex_unlock(&cp_heap->lock);
+
+	offset = gen_pool_alloc_aligned(cp_heap->pool,
+					size, ilog2(align));
+
+	if (!offset) {
+		mutex_lock(&cp_heap->lock);
+		if ((cp_heap->total_size -
+		      cp_heap->allocated_bytes) > size)
+			pr_debug("%s: heap %s has enough memory (%lx) but"
+				" the allocation of size %lx still failed."
+				" Memory is probably fragmented.",
+				__func__, heap->name,
+				cp_heap->total_size -
+				cp_heap->allocated_bytes, size);
+
+		cp_heap->allocated_bytes -= size;
+		--cp_heap->alloc_count;
+
+		if (cp_heap->alloc_count == 0)
+			ion_cp_unprotect(heap);
+
+		mutex_unlock(&cp_heap->lock);
+
+		return ION_CP_ALLOCATE_FAIL;
+	}
+
+	return offset;
+}
+
+void ion_cp_free(struct ion_heap *heap, ion_phys_addr_t addr,
+		       unsigned long size)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+
+	if (addr == ION_CP_ALLOCATE_FAIL)
+		return;
+	gen_pool_free(cp_heap->pool, addr, size);
+
+	mutex_lock(&cp_heap->lock);
+
+	cp_heap->allocated_bytes -= size;
+	--cp_heap->alloc_count;
+
+	if (cp_heap->alloc_count == 0)
+		ion_cp_unprotect(heap);
+	mutex_unlock(&cp_heap->lock);
+}
+
+static int ion_cp_heap_phys(struct ion_heap *heap,
+				  struct ion_buffer *buffer,
+				  ion_phys_addr_t *addr, size_t *len)
+{
+	*addr = buffer->priv_phys;
+	*len = buffer->size;
+	return 0;
+}
+
+static int ion_cp_heap_allocate(struct ion_heap *heap,
+				      struct ion_buffer *buffer,
+				      unsigned long size, unsigned long align,
+				      unsigned long flags)
+{
+	buffer->priv_phys = ion_cp_allocate(heap, size, align, flags);
+	return buffer->priv_phys == ION_CP_ALLOCATE_FAIL ? -ENOMEM : 0;
+}
+
+static void ion_cp_heap_free(struct ion_buffer *buffer)
+{
+	struct ion_heap *heap = buffer->heap;
+
+	ion_cp_free(heap, buffer->priv_phys, buffer->size);
+	buffer->priv_phys = ION_CP_ALLOCATE_FAIL;
+}
+
+
+/**
+ * Checks if user space mapping is allowed.
+ * NOTE: Will increment the mapping count if
+ * mapping is allowed.
+ * Will fail mapping if heap is secured.
+ */
+static unsigned int is_user_mapping_allowed(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+
+	mutex_lock(&cp_heap->lock);
+
+	if (cp_heap->heap_secured == SECURED_HEAP) {
+		mutex_unlock(&cp_heap->lock);
+		return 0;
+	}
+	++cp_heap->umap_count;
+
+	mutex_unlock(&cp_heap->lock);
+	return 1;
+}
+
+struct scatterlist *ion_cp_heap_map_dma(struct ion_heap *heap,
+					      struct ion_buffer *buffer)
+{
+	struct scatterlist *sglist;
+	struct page *page = phys_to_page(buffer->priv_phys);
+
+	if (page == NULL)
+		return NULL;
+
+	sglist = vmalloc(sizeof(*sglist));
+	if (!sglist)
+		return ERR_PTR(-ENOMEM);
+
+	sg_init_table(sglist, 1);
+	sg_set_page(sglist, page, buffer->size, 0);
+
+	return sglist;
+}
+
+void ion_cp_heap_unmap_dma(struct ion_heap *heap,
+				 struct ion_buffer *buffer)
+{
+	if (buffer->sglist)
+		vfree(buffer->sglist);
+}
+
+/**
+ * Call request region for SMI memory of this is the first mapping.
+ */
+static int ion_cp_request_region(struct ion_cp_heap *cp_heap)
+{
+	int ret_value = 0;
+	if ((cp_heap->umap_count+cp_heap->kmap_count) == 1)
+		if (cp_heap->request_region)
+			ret_value = cp_heap->request_region(cp_heap->bus_id);
+	return ret_value;
+}
+
+/**
+ * Call release region for SMI memory of this is the last un-mapping.
+ */
+static int ion_cp_release_region(struct ion_cp_heap *cp_heap)
+{
+	int ret_value = 0;
+	if ((cp_heap->umap_count + cp_heap->kmap_count) == 0)
+		if (cp_heap->release_region)
+			ret_value = cp_heap->release_region(cp_heap->bus_id);
+	return ret_value;
+}
+
+void *ion_cp_heap_map_kernel(struct ion_heap *heap,
+				   struct ion_buffer *buffer,
+				   unsigned long flags)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	void *ret_value;
+
+	mutex_lock(&cp_heap->lock);
+
+	if (cp_heap->heap_secured == SECURED_HEAP && ION_IS_CACHED(flags)) {
+		pr_err("Unable to map secured heap %s as cached", heap->name);
+		mutex_unlock(&cp_heap->lock);
+		return NULL;
+	}
+
+	++cp_heap->kmap_count;
+
+	if (ion_cp_request_region(cp_heap)) {
+		--cp_heap->kmap_count;
+		mutex_unlock(&cp_heap->lock);
+		return NULL;
+	}
+	mutex_unlock(&cp_heap->lock);
+
+	if (ION_IS_CACHED(flags))
+		ret_value = ioremap_cached(buffer->priv_phys, buffer->size);
+	else
+		ret_value = ioremap(buffer->priv_phys, buffer->size);
+
+	if (!ret_value) {
+		mutex_lock(&cp_heap->lock);
+		--cp_heap->kmap_count;
+		ion_cp_release_region(cp_heap);
+		mutex_unlock(&cp_heap->lock);
+	}
+	return ret_value;
+}
+
+void ion_cp_heap_unmap_kernel(struct ion_heap *heap,
+				    struct ion_buffer *buffer)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+
+	__arch_iounmap(buffer->vaddr);
+	buffer->vaddr = NULL;
+
+	mutex_lock(&cp_heap->lock);
+	--cp_heap->kmap_count;
+	ion_cp_release_region(cp_heap);
+	mutex_unlock(&cp_heap->lock);
+
+	return;
+}
+
+int ion_cp_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
+			struct vm_area_struct *vma, unsigned long flags)
+{
+	int ret_value = -EAGAIN;
+	if (is_user_mapping_allowed(heap)) {
+
+		struct ion_cp_heap *cp_heap =
+			container_of(heap, struct ion_cp_heap, heap);
+
+		mutex_lock(&cp_heap->lock);
+		if (ion_cp_request_region(cp_heap)) {
+			mutex_unlock(&cp_heap->lock);
+			return -EINVAL;
+		}
+		mutex_unlock(&cp_heap->lock);
+
+		 if (ION_IS_CACHED(flags))
+			ret_value =  remap_pfn_range(vma, vma->vm_start,
+				__phys_to_pfn(buffer->priv_phys) +
+				vma->vm_pgoff,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot);
+		else
+			ret_value = remap_pfn_range(vma, vma->vm_start,
+				__phys_to_pfn(buffer->priv_phys) +
+				vma->vm_pgoff,
+				vma->vm_end - vma->vm_start,
+				pgprot_noncached(vma->vm_page_prot));
+
+		 if (ret_value) {
+			mutex_lock(&cp_heap->lock);
+			--cp_heap->umap_count;
+			ion_cp_release_region(cp_heap);
+			mutex_unlock(&cp_heap->lock);
+		}
+	}
+	return ret_value;
+}
+
+void ion_cp_heap_unmap_user(struct ion_heap *heap,
+			struct ion_buffer *buffer)
+{
+	struct ion_cp_heap *cp_heap =
+			container_of(heap, struct ion_cp_heap, heap);
+
+	mutex_lock(&cp_heap->lock);
+	--cp_heap->umap_count;
+	ion_cp_release_region(cp_heap);
+	mutex_unlock(&cp_heap->lock);
+}
+
+int ion_cp_cache_ops(struct ion_heap *heap, struct ion_buffer *buffer,
+			void *vaddr, unsigned int offset, unsigned int length,
+			unsigned int cmd)
+{
+	unsigned long vstart, pstart;
+
+	pstart = buffer->priv_phys + offset;
+	vstart = (unsigned long)vaddr;
+
+	switch (cmd) {
+	case ION_IOC_CLEAN_CACHES:
+		clean_caches(vstart, length, pstart);
+		break;
+	case ION_IOC_INV_CACHES:
+		invalidate_caches(vstart, length, pstart);
+		break;
+	case ION_IOC_CLEAN_INV_CACHES:
+		clean_and_invalidate_caches(vstart, length, pstart);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned long ion_cp_get_allocated(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	unsigned long allocated_bytes;
+
+	mutex_lock(&cp_heap->lock);
+	allocated_bytes = cp_heap->allocated_bytes;
+	mutex_unlock(&cp_heap->lock);
+
+	return allocated_bytes;
+}
+
+static unsigned long ion_cp_get_total(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+
+	return cp_heap->total_size;
+}
+
+static unsigned long ion_cp_get_umap_count(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	unsigned long umap_count;
+
+	mutex_lock(&cp_heap->lock);
+	umap_count = cp_heap->umap_count;
+	mutex_unlock(&cp_heap->lock);
+
+	return umap_count;
+}
+
+static unsigned long ion_cp_get_kmap_count(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	unsigned long kmap_count;
+
+	mutex_lock(&cp_heap->lock);
+	kmap_count = cp_heap->kmap_count;
+	mutex_unlock(&cp_heap->lock);
+
+	return kmap_count;
+}
+
+static unsigned long ion_cp_get_alloc_count(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	unsigned long alloc_count;
+
+	mutex_lock(&cp_heap->lock);
+	alloc_count = cp_heap->alloc_count;
+	mutex_unlock(&cp_heap->lock);
+
+	return alloc_count;
+}
+
+static unsigned long ion_cp_get_secured(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	unsigned long secured_heap = 0;
+
+	mutex_lock(&cp_heap->lock);
+	secured_heap = cp_heap->heap_secured == SECURED_HEAP;
+	mutex_unlock(&cp_heap->lock);
+
+	return secured_heap;
+}
+
+int ion_cp_secure_heap(struct ion_heap *heap)
+{
+	int ret_value;
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	mutex_lock(&cp_heap->lock);
+	ret_value = ion_cp_protect(heap);
+	mutex_unlock(&cp_heap->lock);
+	return ret_value;
+}
+
+int ion_cp_unsecure_heap(struct ion_heap *heap)
+{
+	int ret_value = 0;
+	struct ion_cp_heap *cp_heap =
+		container_of(heap, struct ion_cp_heap, heap);
+	mutex_lock(&cp_heap->lock);
+	ion_cp_unprotect(heap);
+	mutex_unlock(&cp_heap->lock);
+	return ret_value;
+}
+
+
+static struct ion_heap_ops cp_heap_ops = {
+	.allocate = ion_cp_heap_allocate,
+	.free = ion_cp_heap_free,
+	.phys = ion_cp_heap_phys,
+	.map_user = ion_cp_heap_map_user,
+	.unmap_user = ion_cp_heap_unmap_user,
+	.map_kernel = ion_cp_heap_map_kernel,
+	.unmap_kernel = ion_cp_heap_unmap_kernel,
+	.map_dma = ion_cp_heap_map_dma,
+	.unmap_dma = ion_cp_heap_unmap_dma,
+	.cache_op = ion_cp_cache_ops,
+	.get_allocated = ion_cp_get_allocated,
+	.get_total = ion_cp_get_total,
+	.get_umap_cnt = ion_cp_get_umap_count,
+	.get_kmap_cnt = ion_cp_get_kmap_count,
+	.get_alloc_cnt = ion_cp_get_alloc_count,
+	.get_secured = ion_cp_get_secured,
+	.secure_heap = ion_cp_secure_heap,
+	.unsecure_heap = ion_cp_unsecure_heap,
+};
+
+static unsigned long ion_cp_get_base(unsigned long size, int memory_type)
+{
+	switch (memory_type) {
+	case ION_EBI_TYPE:
+		return allocate_contiguous_ebi_nomap(size, PAGE_SIZE);
+		break;
+	case ION_SMI_TYPE:
+		return allocate_contiguous_memory_nomap(size, MEMTYPE_SMI,
+							PAGE_SIZE);
+		break;
+	default:
+		return 0;
+	}
+}
+
+
+struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *heap_data)
+{
+	struct ion_cp_heap *cp_heap;
+	int ret;
+
+	cp_heap = kzalloc(sizeof(*cp_heap), GFP_KERNEL);
+	if (!cp_heap)
+		return ERR_PTR(-ENOMEM);
+
+	heap_data->base = ion_cp_get_base(heap_data->size,
+					heap_data->memory_type);
+	if (!heap_data->base) {
+		pr_err("%s: could not get memory for heap %s"
+			" (id %x)\n", __func__, heap_data->name,
+			heap_data->id);
+		goto free_heap;
+	}
+
+	mutex_init(&cp_heap->lock);
+
+	cp_heap->pool = gen_pool_create(12, -1);
+	if (!cp_heap->pool)
+		goto free_heap;
+
+	cp_heap->base = heap_data->base;
+	ret = gen_pool_add(cp_heap->pool, cp_heap->base, heap_data->size, -1);
+	if (ret < 0)
+		goto destroy_pool;
+
+	cp_heap->allocated_bytes = 0;
+	cp_heap->alloc_count = 0;
+	cp_heap->umap_count = 0;
+	cp_heap->kmap_count = 0;
+	cp_heap->total_size = heap_data->size;
+	cp_heap->heap.ops = &cp_heap_ops;
+	cp_heap->heap.type = ION_HEAP_TYPE_CP;
+	cp_heap->heap_secured = NON_SECURED_HEAP;
+	if (heap_data->extra_data) {
+		struct ion_cp_heap_pdata *extra_data =
+				heap_data->extra_data;
+		cp_heap->permission_type = extra_data->permission_type;
+		if (extra_data->setup_region)
+			cp_heap->bus_id = extra_data->setup_region();
+		if (extra_data->request_region)
+			cp_heap->request_region = extra_data->request_region;
+		if (extra_data->release_region)
+			cp_heap->release_region = extra_data->release_region;
+	}
+	return &cp_heap->heap;
+
+destroy_pool:
+	gen_pool_destroy(cp_heap->pool);
+
+free_heap:
+	kfree(cp_heap);
+
+	return ERR_PTR(-ENOMEM);
+}
+
+void ion_cp_heap_destroy(struct ion_heap *heap)
+{
+	struct ion_cp_heap *cp_heap =
+	     container_of(heap, struct  ion_cp_heap, heap);
+
+	gen_pool_destroy(cp_heap->pool);
+	kfree(cp_heap);
+	cp_heap = NULL;
+}
+
+
+/*  SCM related code for locking down memory for content protection */
+
+#define SCM_CP_LOCK_CMD_ID	0x1
+#define SCM_CP_PROTECT		0x1
+#define SCM_CP_UNPROTECT	0x0
+
+struct cp_lock_msg {
+	unsigned int start;
+	unsigned int end;
+	unsigned int permission_type;
+	unsigned char lock;
+};
+
+
+static int ion_cp_protect_mem(unsigned int phy_base, unsigned int size,
+			      unsigned int permission_type)
+{
+	struct cp_lock_msg cmd;
+	cmd.start = phy_base;
+	cmd.end = phy_base + size;
+	cmd.permission_type = permission_type;
+	cmd.lock = SCM_CP_PROTECT;
+
+	return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+			&cmd, sizeof(cmd), NULL, 0);
+}
+
+static int ion_cp_unprotect_mem(unsigned int phy_base, unsigned int size,
+				unsigned int permission_type)
+{
+	struct cp_lock_msg cmd;
+	cmd.start = phy_base;
+	cmd.end = phy_base + size;
+	cmd.permission_type = permission_type;
+	cmd.lock = SCM_CP_UNPROTECT;
+
+	return scm_call(SCM_SVC_CP, SCM_CP_LOCK_CMD_ID,
+			&cmd, sizeof(cmd), NULL, 0);
+}
diff --git a/drivers/gpu/ion/ion_heap.c b/drivers/gpu/ion/ion_heap.c
index 900f445..6ea49db 100644
--- a/drivers/gpu/ion/ion_heap.c
+++ b/drivers/gpu/ion/ion_heap.c
@@ -2,6 +2,7 @@
  * drivers/gpu/ion/ion_heap.c
  *
  * Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -35,6 +36,9 @@
 	case ION_HEAP_TYPE_IOMMU:
 		heap = ion_iommu_heap_create(heap_data);
 		break;
+	case ION_HEAP_TYPE_CP:
+		heap = ion_cp_heap_create(heap_data);
+		break;
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
 		       heap_data->type);
@@ -68,6 +72,12 @@
 	case ION_HEAP_TYPE_CARVEOUT:
 		ion_carveout_heap_destroy(heap);
 		break;
+	case ION_HEAP_TYPE_IOMMU:
+		ion_iommu_heap_destroy(heap);
+		break;
+	case ION_HEAP_TYPE_CP:
+		ion_cp_heap_destroy(heap);
+		break;
 	default:
 		pr_err("%s: Invalid heap type %d\n", __func__,
 		       heap->type);
diff --git a/drivers/gpu/ion/ion_priv.h b/drivers/gpu/ion/ion_priv.h
index 77b73e2..98709b6 100644
--- a/drivers/gpu/ion/ion_priv.h
+++ b/drivers/gpu/ion/ion_priv.h
@@ -2,6 +2,7 @@
  * drivers/gpu/ion/ion_priv.h
  *
  * Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -148,7 +149,12 @@
 				unsigned long iova_length,
 				unsigned long flags);
 	void (*unmap_iommu)(struct ion_iommu_map *data);
-
+	unsigned long (*get_umap_cnt)(struct ion_heap *heap);
+	unsigned long (*get_kmap_cnt)(struct ion_heap *heap);
+	unsigned long (*get_alloc_cnt)(struct ion_heap *heap);
+	unsigned long (*get_secured)(struct ion_heap *heap);
+	int (*secure_heap)(struct ion_heap *heap);
+	int (*unsecure_heap)(struct ion_heap *heap);
 };
 
 /**
@@ -226,6 +232,9 @@
 struct ion_heap *ion_iommu_heap_create(struct ion_platform_heap *);
 void ion_iommu_heap_destroy(struct ion_heap *);
 
+struct ion_heap *ion_cp_heap_create(struct ion_platform_heap *);
+void ion_cp_heap_destroy(struct ion_heap *);
+
 /**
  * kernel api to allocate/free from carveout -- used when carveout is
  * used to back an architecture specific custom heap
@@ -238,9 +247,10 @@
 
 struct ion_heap *msm_get_contiguous_heap(void);
 /**
- * The carveout heap returns physical addresses, since 0 may be a valid
+ * The carveout/cp heap returns physical addresses, since 0 may be a valid
  * physical address, this is used to indicate allocation failed
  */
 #define ION_CARVEOUT_ALLOCATE_FAIL -1
+#define ION_CP_ALLOCATE_FAIL -1
 
 #endif /* _ION_PRIV_H */
diff --git a/drivers/gpu/ion/msm/msm_ion.c b/drivers/gpu/ion/msm/msm_ion.c
index 0c96eaf..3df2b53 100644
--- a/drivers/gpu/ion/msm/msm_ion.c
+++ b/drivers/gpu/ion/msm/msm_ion.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
@@ -30,6 +30,18 @@
 }
 EXPORT_SYMBOL(msm_ion_client_create);
 
+int msm_ion_secure_heap(int heap_id)
+{
+	return ion_secure_heap(idev, heap_id);
+}
+EXPORT_SYMBOL(msm_ion_secure_heap);
+
+int msm_ion_unsecure_heap(int heap_id)
+{
+	return ion_unsecure_heap(idev, heap_id);
+}
+EXPORT_SYMBOL(msm_ion_unsecure_heap);
+
 static unsigned long msm_ion_get_base(unsigned long size, int memory_type)
 {
 	switch (memory_type) {
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index faf589b..03e447b 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -202,7 +202,7 @@
 	}
 
 	/* Reset the time-out in our idle timer */
-	mod_timer(&device->idle_timer,
+	mod_timer_pending(&device->idle_timer,
 		jiffies + device->pwrctrl.interval_timeout);
 	return result;
 }
@@ -585,6 +585,7 @@
 	adreno_gmeminit(adreno_dev);
 
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+	device->ftbl->irqctrl(device, 1);
 
 	status = adreno_ringbuffer_start(&adreno_dev->ringbuffer, init_ram);
 	if (status != 0)
@@ -612,8 +613,7 @@
 
 	kgsl_mmu_stop(device);
 
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
-	del_timer_sync(&device->idle_timer);
+	device->ftbl->irqctrl(device, 0);
 
 	/* Power down the device */
 	kgsl_pwrctrl_disable(device);
@@ -863,8 +863,8 @@
 	 */
 retry:
 	if (rb->flags & KGSL_FLAGS_STARTED) {
+		adreno_poke(device);
 		do {
-			adreno_poke(device);
 			GSL_RB_GET_READPTR(rb, &rb->rptr);
 			if (time_after(jiffies, wait_time)) {
 				KGSL_DRV_ERR(device, "rptr: %x, wptr: %x\n",
diff --git a/drivers/gpu/msm/adreno_postmortem.c b/drivers/gpu/msm/adreno_postmortem.c
index 40dfb30..7f054b1 100644
--- a/drivers/gpu/msm/adreno_postmortem.c
+++ b/drivers/gpu/msm/adreno_postmortem.c
@@ -706,7 +706,6 @@
 
 int adreno_postmortem_dump(struct kgsl_device *device, int manual)
 {
-	bool saved_nap;
 	struct kgsl_pwrctrl *pwr = &device->pwrctrl;
 
 	BUG_ON(device == NULL);
@@ -738,28 +737,17 @@
 	KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
 		kgsl_get_clkrate(pwr->ebi1_clk));
 
-	/* Disable the idle timer so we don't get interrupted */
-	del_timer_sync(&device->idle_timer);
-	mutex_unlock(&device->mutex);
-	flush_workqueue(device->work_queue);
-	mutex_lock(&device->mutex);
-
-	/* Turn off napping to make sure we have the clocks full
-	   attention through the following process */
-	saved_nap = device->pwrctrl.nap_allowed;
-	device->pwrctrl.nap_allowed = false;
+	/*
+	 * Disable the irq, idle timer, and workqueue so we don't
+	 * get interrupted
+	 */
+	kgsl_pwrctrl_stop_work(device);
 
 	/* Force on the clocks */
-	kgsl_pwrctrl_wake(device);
-
-	/* Disable the irq */
-	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+	kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
 
 	adreno_dump(device);
 
-	/* Restore nap mode */
-	device->pwrctrl.nap_allowed = saved_nap;
-
 	/* On a manual trigger, turn on the interrupts and put
 	   the clocks to sleep.  They will recover themselves
 	   on the next event.  For a hang, leave things as they
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 3207040..e9c3f08 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -403,8 +403,6 @@
 		wait_for_completion(&device->suspend_gate);
 		mutex_lock(&device->mutex);
 	}
-	/* Don't let the timer wake us during suspended sleep. */
-	del_timer_sync(&device->idle_timer);
 	switch (device->state) {
 		case KGSL_STATE_INIT:
 			break;
@@ -416,6 +414,7 @@
 			/* Get the completion ready to be waited upon. */
 			INIT_COMPLETION(device->hwaccess_gate);
 			device->ftbl->suspend_context(device);
+			kgsl_pwrctrl_stop_work(device);
 			device->ftbl->stop(device);
 			kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
 			break;
@@ -499,6 +498,7 @@
 	KGSL_PWR_WARN(device, "early suspend start\n");
 	mutex_lock(&device->mutex);
 	kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
+	kgsl_pwrctrl_stop_work(device);
 	kgsl_pwrctrl_sleep(device);
 	mutex_unlock(&device->mutex);
 	KGSL_PWR_WARN(device, "early suspend end\n");
@@ -644,6 +644,7 @@
 
 	device->open_count--;
 	if (device->open_count == 0) {
+		kgsl_pwrctrl_stop_work(device);
 		result = device->ftbl->stop(device);
 		kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
 	}
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index f4abf99..c29da39 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.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
@@ -362,6 +362,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL(kgsl_pwrctrl_clk);
 
 void kgsl_pwrctrl_axi(struct kgsl_device *device, int state)
 {
@@ -427,13 +428,11 @@
 			&pwr->power_flags)) {
 			trace_kgsl_irq(device, state);
 			enable_irq(pwr->interrupt_num);
-			device->ftbl->irqctrl(device, 1);
 		}
 	} else if (state == KGSL_PWRFLAGS_OFF) {
 		if (test_and_clear_bit(KGSL_PWRFLAGS_IRQ_ON,
 			&pwr->power_flags)) {
 			trace_kgsl_irq(device, state);
-			device->ftbl->irqctrl(device, 0);
 			if (in_interrupt())
 				disable_irq_nosync(pwr->interrupt_num);
 			else
@@ -622,7 +621,7 @@
 	struct kgsl_device *device = (struct kgsl_device *) data;
 
 	KGSL_PWR_INFO(device, "idle timer expired device %d\n", device->id);
-	if (device->requested_state != KGSL_STATE_SUSPEND) {
+	if (device->requested_state == KGSL_STATE_NONE) {
 		kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
 		/* Have work run in a non-interrupt context. */
 		queue_work(device->work_queue, &device->idle_check_ws);
@@ -851,6 +850,16 @@
 }
 EXPORT_SYMBOL(kgsl_pwrctrl_disable);
 
+void kgsl_pwrctrl_stop_work(struct kgsl_device *device)
+{
+	del_timer_sync(&device->idle_timer);
+	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
+	mutex_unlock(&device->mutex);
+	flush_workqueue(device->work_queue);
+	mutex_lock(&device->mutex);
+}
+EXPORT_SYMBOL(kgsl_pwrctrl_stop_work);
+
 void kgsl_pwrctrl_set_state(struct kgsl_device *device, unsigned int state)
 {
 	trace_kgsl_pwr_set_state(device, state);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h
index 8ec41be..23e2bd1 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.h
+++ b/drivers/gpu/msm/kgsl_pwrctrl.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
@@ -58,6 +58,7 @@
 };
 
 void kgsl_pwrctrl_irq(struct kgsl_device *device, int state);
+void kgsl_pwrctrl_clk(struct kgsl_device *device, int state);
 int kgsl_pwrctrl_init(struct kgsl_device *device);
 void kgsl_pwrctrl_close(struct kgsl_device *device);
 void kgsl_timer(unsigned long data);
@@ -72,6 +73,7 @@
 void kgsl_pwrctrl_uninit_sysfs(struct kgsl_device *device);
 void kgsl_pwrctrl_enable(struct kgsl_device *device);
 void kgsl_pwrctrl_disable(struct kgsl_device *device);
+void kgsl_pwrctrl_stop_work(struct kgsl_device *device);
 static inline unsigned long kgsl_get_clkrate(struct clk *clk)
 {
 	return (clk != NULL) ? clk_get_rate(clk) : 0;
diff --git a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c b/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
index d5fa84e..2976b0b 100644
--- a/drivers/gpu/msm/kgsl_pwrscale_idlestats.c
+++ b/drivers/gpu/msm/kgsl_pwrscale_idlestats.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
@@ -73,7 +73,7 @@
 	/* If the GPU is asleep, don't wake it up - assume that we
 	   are idle */
 
-	if (!(device->state & (KGSL_STATE_SLEEP | KGSL_STATE_NAP))) {
+	if (device->state == KGSL_STATE_ACTIVE) {
 		device->ftbl->power_stats(device, &stats);
 		pulse->busy_start_time = pwr->time - stats.busy_time;
 		pulse->busy_interval = stats.busy_time;
@@ -149,7 +149,8 @@
 			struct kgsl_pwrscale *pwrscale)
 {
 	struct idlestats_priv *priv = pwrscale->priv;
-	priv->idledev.stats->event |= MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED;
+	msm_idle_stats_update_event(&priv->idledev,
+		MSM_IDLE_STATS_EVENT_IDLE_TIMER_EXPIRED);
 }
 
 static int idlestats_init(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/z180.c b/drivers/gpu/msm/z180.c
index de7d1be..718fac9 100644
--- a/drivers/gpu/msm/z180.c
+++ b/drivers/gpu/msm/z180.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2002,2007-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
@@ -251,7 +251,7 @@
 		kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
 		queue_work(device->work_queue, &device->idle_check_ws);
 	}
-	mod_timer(&device->idle_timer,
+	mod_timer_pending(&device->idle_timer,
 			jiffies + device->pwrctrl.interval_timeout);
 
 	return result;
@@ -570,6 +570,7 @@
 
 	mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
 	kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+	device->ftbl->irqctrl(device, 1);
 	return 0;
 
 error_clk_off:
@@ -580,10 +581,9 @@
 
 static int z180_stop(struct kgsl_device *device)
 {
+	device->ftbl->irqctrl(device, 0);
 	z180_idle(device, KGSL_TIMEOUT_DEFAULT);
 
-	del_timer_sync(&device->idle_timer);
-
 	kgsl_mmu_stop(device);
 
 	/* Disable the clocks before the power rail. */
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 5b594bc..3c98a75 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2010 Samsung Electronics Co.Ltd
  * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- * 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 as published by the
@@ -598,7 +598,8 @@
 		input_report_abs(input_dev, ABS_MT_POSITION_Y,
 				finger[id].y);
 		input_report_abs(input_dev, ABS_MT_PRESSURE,
-					finger[id].pressure);
+				finger[id].status != MXT_RELEASE ?
+				finger[id].pressure : 0);
 		input_mt_sync(input_dev);
 
 		if (finger[id].status == MXT_RELEASE)
@@ -1749,6 +1750,12 @@
 	else
 		mxt_regulator_configure(data, false);
 
+	if (gpio_is_valid(data->pdata->reset_gpio))
+		gpio_free(data->pdata->reset_gpio);
+
+	if (gpio_is_valid(data->pdata->irq_gpio))
+		gpio_free(data->pdata->irq_gpio);
+
 	kfree(data->object_table);
 	kfree(data);
 
diff --git a/drivers/media/radio/radio-iris.c b/drivers/media/radio/radio-iris.c
index 59f915e..835f8c4 100644
--- a/drivers/media/radio/radio-iris.c
+++ b/drivers/media/radio/radio-iris.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
@@ -419,6 +419,13 @@
 	.minimum	=	0,
 	.maximum	=	1,
 	},
+	{
+	.id     =       V4L2_CID_PRIVATE_IRIS_GET_SINR,
+	.type   =       V4L2_CTRL_TYPE_INTEGER,
+	.name   =       "GET SINR",
+	.minimum        =       -128,
+	.maximum        =       127,
+	},
 };
 
 static void iris_q_event(struct iris_device *radio,
@@ -1908,7 +1915,7 @@
 		if (i >= IRIS_BUF_RT_RDS)
 			kfifo_reset(&radio->data_buf[i]);
 	}
-	if (radio->fm_st_rsp.station_rsp.rssi)
+	if (radio->fm_st_rsp.station_rsp.serv_avble)
 		iris_q_event(radio, IRIS_EVT_ABOVE_TH);
 	else
 		iris_q_event(radio, IRIS_EVT_BELOW_TH);
@@ -2027,10 +2034,8 @@
 
 	iris_q_event(radio, IRIS_EVT_NEW_RT_RDS);
 
-	while (skb->data[len+RDS_OFFSET] != 0x0d)
+	while ((skb->data[len+RDS_OFFSET] != 0x0d) && (len < RX_RT_DATA_LENGTH))
 		len++;
-	len++;
-
 	data = kmalloc(len+RDS_OFFSET, GFP_ATOMIC);
 	if (!data) {
 		FMDERR("Failed to allocate memory");
@@ -2499,6 +2504,20 @@
 	case V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION:
 		retval = iris_do_calibration(radio);
 		break;
+	case V4L2_CID_PRIVATE_IRIS_GET_SINR:
+		if (radio->mode == FM_RECV) {
+			retval = hci_cmd(HCI_FM_GET_STATION_PARAM_CMD,
+						 radio->fm_hdev);
+			if (retval < 0) {
+				FMDERR("Get SINR Failed");
+				return retval;
+			}
+			ctrl->value = radio->fm_st_rsp.station_rsp.sinr;
+
+		} else
+			retval = -EINVAL;
+
+		break;
 	default:
 		retval = -EINVAL;
 	}
@@ -2609,9 +2628,8 @@
 				hci_fm_set_cal_req_proc,
 				(unsigned long)&proc_cal_req,
 				 RADIO_HCI_TIMEOUT);
-		if (retval < 0) {
+		if (retval < 0)
 			FMDERR("Set Process calibration failed %d", retval);
-		}
 		break;
 	default:
 		FMDBG("Shouldn't reach here\n");
@@ -3235,7 +3253,7 @@
 		if ((i == IRIS_BUF_RAW_RDS) || (i == IRIS_BUF_PEEK))
 			kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
 				rds_buf*3, GFP_KERNEL);
-		else if (i == IRIS_BUF_CAL_DATA)
+		else if ((i == IRIS_BUF_CAL_DATA) || (i == IRIS_BUF_RT_RDS))
 			kfifo_alloc_rc = kfifo_alloc(&radio->data_buf[i],
 				STD_BUF_SIZE*2, GFP_KERNEL);
 		else
diff --git a/drivers/media/radio/radio-tavarua.c b/drivers/media/radio/radio-tavarua.c
index 393e30e..8f09b6a 100644
--- a/drivers/media/radio/radio-tavarua.c
+++ b/drivers/media/radio/radio-tavarua.c
@@ -2107,7 +2107,7 @@
 			 1, internal_vreg_ctl[index][0]);
 		if (retval < 0) {
 			printk(KERN_ERR "%s:0xF0 write failed\n", __func__);
-			return retval;
+			goto exit;
 		}
 		/* actual value itself used as mask*/
 		retval = marimba_write_bit_mask(radio->marimba,
@@ -2115,7 +2115,7 @@
 			1, internal_vreg_ctl[index][1]);
 		if (retval < 0) {
 			printk(KERN_ERR "%s:0xF4 write failed\n", __func__);
-			return retval;
+			goto exit;
 		}
 	} else    {
 		/* disable fm core */
@@ -2127,8 +2127,9 @@
 							&value, 1, FM_ENABLE);
 	if (retval < 0) {
 		printk(KERN_ERR "%s:XO_BUFF_CNTRL write failed\n", __func__);
-		return retval;
+		goto exit;
 	}
+exit:
 	FMDBG("%s, Calling fm_shutdown\n", __func__);
 	/* teardown gpio and pmic */
 
@@ -2139,7 +2140,7 @@
 	radio->handle_irq = 1;
 	atomic_inc(&radio->users);
 	radio->marimba->mod_id = SLAVE_ID_BAHAMA;
-	return 0;
+	return retval;
 }
 
 /*
@@ -2864,6 +2865,7 @@
 	unsigned char value;
 	unsigned char xfr_buf[XFR_REG_NUM];
 	unsigned char tx_data[XFR_REG_NUM];
+	unsigned char dis_buf[XFR_REG_NUM];
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
@@ -2915,20 +2917,26 @@
 		/* check if off */
 		else if ((ctrl->value == FM_OFF) && radio->registers[RDCTRL]) {
 			FMDBG("turning off...\n");
-			retval = tavarua_write_register(radio, RDCTRL,
-							ctrl->value);
-			/*Make it synchronous
-			Block it till READY interrupt
-			Wait for interrupt i.e.
-			complete(&radio->sync_req_done)
-			*/
+			tavarua_write_register(radio, RDCTRL, ctrl->value);
+			/* flush the event and work queues */
+			kfifo_reset(&radio->data_buf[TAVARUA_BUF_EVENTS]);
+			flush_workqueue(radio->wqueue);
+			/*
+			 * queue the READY event from the host side
+			 * in case of FM off
+			 */
+			tavarua_q_event(radio, TAVARUA_EVT_RADIO_READY);
 
-			if (retval >= 0) {
-
-				if (!wait_for_completion_timeout(
-					&radio->sync_req_done,
-					msecs_to_jiffies(wait_timeout)))
-					FMDBG("turning off timedout...\n");
+			FMDBG("%s, Disable All Interrupts\n", __func__);
+			/* disable irq */
+			dis_buf[STATUS_REG1] = 0x00;
+			dis_buf[STATUS_REG2] = 0x00;
+			dis_buf[STATUS_REG3] = TRANSFER;
+			retval = sync_write_xfr(radio, INT_CTRL, dis_buf);
+			if (retval < 0) {
+				pr_err("%s: failed to disable"
+						"Interrupts\n", __func__);
+				return retval;
 			}
 		}
 		break;
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 8df6243..363e437 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.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
@@ -674,14 +674,12 @@
 static int msm_camera_v4l2_querycap(struct file *f, void *pctx,
 				struct v4l2_capability *pcaps)
 {
-	struct msm_cam_v4l2_device *pcam  = video_drvdata(f);
 
 	D("%s\n", __func__);
 	WARN_ON(pctx != f->private_data);
 
 	/* some other day, some other time */
 	/*cap->version = LINUX_VERSION_CODE; */
-	strlcpy(pcaps->driver, pcam->pdev->name, sizeof(pcaps->driver));
 	pcaps->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 	return 0;
 }
diff --git a/drivers/media/video/msm/msm_camera.c b/drivers/media/video/msm/msm_camera.c
index e401a7a..65b33c2 100644
--- a/drivers/media/video/msm/msm_camera.c
+++ b/drivers/media/video/msm/msm_camera.c
@@ -1010,7 +1010,7 @@
 		qcmd_resp = __msm_control_nb(sync, qcmd);
 		goto end;
 	}
-
+	msm_queue_drain(&ctrl_pmsm->ctrl_q, list_control);
 	qcmd_resp = __msm_control(sync,
 				  &ctrl_pmsm->ctrl_q,
 				  qcmd, msecs_to_jiffies(10000));
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index 759ac47..e13dd62 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.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
@@ -76,6 +76,22 @@
 	.colorspace = V4L2_COLORSPACE_JPEG,
 	},
 	{
+	.name	   = "NV16BAYER",
+	.depth	  = 8,
+	.bitsperpxl = 8,
+	.fourcc	 = V4L2_PIX_FMT_NV16,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
+	.name	   = "NV61BAYER",
+	.depth	  = 8,
+	.bitsperpxl = 8,
+	.fourcc	 = V4L2_PIX_FMT_NV61,
+	.pxlcode	= V4L2_MBUS_FMT_SBGGR10_1X10, /* Bayer sensor */
+	.colorspace = V4L2_COLORSPACE_JPEG,
+	},
+	{
 	.name	   = "YU12BAYER",
 	.depth	  = 8,
 	.bitsperpxl = 8,
diff --git a/drivers/media/video/msm/wfd/Makefile b/drivers/media/video/msm/wfd/Makefile
index e1484aa..7ea9db3 100644
--- a/drivers/media/video/msm/wfd/Makefile
+++ b/drivers/media/video/msm/wfd/Makefile
@@ -1,4 +1,5 @@
 #obj-$(CONFIG_MSM_WFD_V4L2) += wfd-ioctl.o
 #obj-$(CONFIG_MSM_WFD_V4L2) += enc-subdev.o
 obj-y += mdp-subdev.o
+obj-y += enc-subdev.o
 obj-y += wfd-ioctl.o
diff --git a/drivers/media/video/msm/wfd/enc-subdev.c b/drivers/media/video/msm/wfd/enc-subdev.c
new file mode 100644
index 0000000..abba5d4
--- /dev/null
+++ b/drivers/media/video/msm/wfd/enc-subdev.c
@@ -0,0 +1,1355 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include <media/v4l2-subdev.h>
+
+#include "enc-subdev.h"
+#include "wfd-util.h"
+#include <media/msm/vcd_api.h>
+#include <media/msm/vidc_init.h>
+#include <media/msm/vcd_property.h>
+#include <linux/time.h>
+#include <linux/ktime.h>
+
+#define VID_ENC_MAX_ENCODER_CLIENTS 1
+#define MAX_NUM_CTRLS 20
+
+struct venc_inst {
+	struct video_client_ctx venc_client;
+	void *cbdata;
+	void (*op_buffer_done)(void *cookie, u32 status,
+			struct vb2_buffer *buf);
+	void (*ip_buffer_done)(void *cookie, u32 status,
+			struct mem_region *mregion);
+	u32 width;
+	u32 height;
+};
+
+struct venc {
+	s32 device_handle;
+	void *virt_base;
+	struct venc_inst venc_clients[VID_ENC_MAX_ENCODER_CLIENTS];
+	struct mutex lock;
+	struct ion_client *iclient;
+};
+
+static struct venc venc_p;
+
+static void *venc_map_dev_base_addr(void *device_name)
+{
+		return venc_p.virt_base;
+}
+
+static void venc_interrupt_deregister(void)
+{
+}
+
+static void venc_interrupt_register(void *device_name)
+{
+}
+
+static void venc_interrupt_clear(void)
+{
+}
+
+int venc_load_fw(struct v4l2_subdev *sd)
+{
+	return !vidc_load_firmware();
+}
+
+static u32 venc_get_empty_client_index(void)
+{
+	u32 i;
+	u32 found = false;
+
+	for (i = 0; i < VIDC_MAX_NUM_CLIENTS; i++) {
+		if (!venc_p.venc_clients[i].venc_client.vcd_handle) {
+			found = true;
+			break;
+		}
+	}
+	if (!found) {
+		WFD_MSG_ERR("%s():ERROR No space for new client\n",
+				__func__);
+		return -ENOMEM;
+	}
+	WFD_MSG_INFO("%s(): available client index = %u\n",
+				__func__, i);
+	return i;
+}
+
+int venc_init(struct v4l2_subdev *sd, u32 val)
+{
+	struct vcd_init_config vcd_init_config;
+	mutex_init(&venc_p.lock);
+	venc_p.virt_base = vidc_get_ioaddr();
+	vcd_init_config.device_name = "VIDC";
+	vcd_init_config.map_dev_base_addr = venc_map_dev_base_addr;
+	vcd_init_config.interrupt_clr = venc_interrupt_clear;
+	vcd_init_config.register_isr = venc_interrupt_register;
+	vcd_init_config.deregister_isr = venc_interrupt_deregister;
+	vcd_init(&vcd_init_config, &venc_p.device_handle);
+	return 0;
+}
+
+static void venc_notify_client(struct video_client_ctx *client_ctx)
+{
+	if (client_ctx)
+		complete(&client_ctx->event);
+}
+
+static void venc_open_done(struct video_client_ctx *client_ctx,
+	struct vcd_handle_container *handle_container)
+{
+	if (client_ctx) {
+		if (handle_container)
+			client_ctx->vcd_handle = handle_container->handle;
+		else
+			WFD_MSG_ERR("handle_container is NULL\n");
+		venc_notify_client(client_ctx);
+	} else
+		WFD_MSG_ERR("ERROR. client_ctx is NULL");
+}
+
+static void venc_start_done(struct video_client_ctx *client_ctx, u32 status)
+{
+	if (client_ctx)
+		venc_notify_client(client_ctx);
+	else
+		WFD_MSG_ERR("ERROR. client_ctx is NULL");
+}
+
+static void venc_stop_done(struct video_client_ctx *client_ctx, u32 status)
+{
+	WFD_MSG_DBG("Inside venc_stop_done: E\n");
+	if (client_ctx)
+		venc_notify_client(client_ctx);
+	else
+		WFD_MSG_ERR("ERROR. client_ctx is NULL");
+	WFD_MSG_DBG("Inside venc_stop_done: X\n");
+}
+
+static void venc_cb(u32 event, u32 status, void *info, u32 size, void *handle,
+		void *const client_data)
+{
+	struct venc_inst *inst = client_data;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct vb2_buffer *vbuf;
+	struct mem_region *mregion;
+	struct vcd_frame_data *frame_data = (struct vcd_frame_data *)info;
+	struct timespec ts;
+
+	if (!client_ctx) {
+		WFD_MSG_ERR("Client context is NULL\n");
+		return;
+	}
+	client_ctx->event_status = status;
+	switch (event) {
+	case VCD_EVT_RESP_OPEN:
+		WFD_MSG_DBG("EVENT: open done = %d\n", event);
+		venc_open_done(client_ctx,
+				(struct vcd_handle_container *)info);
+		break;
+	case VCD_EVT_RESP_INPUT_DONE:
+	case VCD_EVT_RESP_INPUT_FLUSHED:
+		WFD_MSG_DBG("EVENT: input done = %d\n", event);
+		mregion = (struct mem_region *)
+			frame_data->frm_clnt_data;
+		inst->ip_buffer_done(inst->cbdata, status, mregion);
+		break;
+	case VCD_EVT_RESP_OUTPUT_DONE:
+	case VCD_EVT_RESP_OUTPUT_FLUSHED:
+		WFD_MSG_DBG("EVENT: output done = %d\n", event);
+		vbuf = (struct vb2_buffer *)
+			frame_data->frm_clnt_data;
+		vbuf->v4l2_planes[0].bytesused =
+			frame_data->data_len;
+
+		switch (frame_data->frame) {
+		case VCD_FRAME_I:
+		case VCD_FRAME_IDR:
+			vbuf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+			break;
+		case VCD_FRAME_P:
+			vbuf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+			break;
+		case VCD_FRAME_B:
+			vbuf->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME;
+			break;
+		default:
+			break;
+		}
+
+		ktime_get_ts(&ts);
+		vbuf->v4l2_buf.timestamp.tv_sec = ts.tv_sec;
+		vbuf->v4l2_buf.timestamp.tv_usec = ts.tv_nsec/1000;
+
+		WFD_MSG_DBG("bytes used %d, ts: %d.%d, frame type is %d\n",
+				frame_data->data_len,
+				(int)vbuf->v4l2_buf.timestamp.tv_sec,
+				(int)vbuf->v4l2_buf.timestamp.tv_usec,
+				frame_data->frame);
+
+		inst->op_buffer_done(inst->cbdata, status, vbuf);
+		break;
+	case VCD_EVT_RESP_START:
+		WFD_MSG_DBG("EVENT: start done = %d\n", event);
+		venc_start_done(client_ctx, status);
+		/*TODO: should wait for this event*/
+		break;
+	case VCD_EVT_RESP_STOP:
+		WFD_MSG_DBG("EVENT: not expected = %d\n", event);
+		venc_stop_done(client_ctx, status);
+		break;
+	case VCD_EVT_RESP_PAUSE:
+	case VCD_EVT_RESP_FLUSH_INPUT_DONE:
+	case VCD_EVT_RESP_FLUSH_OUTPUT_DONE:
+	case VCD_EVT_IND_OUTPUT_RECONFIG:
+		WFD_MSG_DBG("EVENT: not expected = %d\n", event);
+		break;
+	case VCD_EVT_IND_HWERRFATAL:
+	case VCD_EVT_IND_RESOURCES_LOST:
+		WFD_MSG_DBG("EVENT: error = %d\n", event);
+		break;
+	default:
+		WFD_MSG_ERR("Invalid event type = %u\n", event);
+		break;
+	}
+}
+
+static long venc_open(struct v4l2_subdev *sd, void *arg)
+{
+	u32 client_index;
+	int rc = 0;
+	struct venc_inst *inst;
+	struct video_client_ctx *client_ctx;
+	struct venc_msg_ops *vmops  =  arg;
+	mutex_lock(&venc_p.lock);
+	client_index = venc_get_empty_client_index();
+	if (client_index < 0) {
+		WFD_MSG_ERR("No free clients, client_index = %d\n",
+				client_index);
+		rc = -ENODEV;
+		goto no_free_client;
+	}
+	inst = &venc_p.venc_clients[client_index];
+	client_ctx = &inst->venc_client;
+	init_completion(&client_ctx->event);
+	mutex_init(&client_ctx->msg_queue_lock);
+	mutex_init(&client_ctx->enrty_queue_lock);
+	INIT_LIST_HEAD(&client_ctx->msg_queue);
+	init_waitqueue_head(&client_ctx->msg_wait);
+	inst->op_buffer_done = vmops->op_buffer_done;
+	inst->ip_buffer_done = vmops->ip_buffer_done;
+	inst->cbdata = vmops->cbdata;
+
+	if (vcd_get_ion_status()) {
+		client_ctx->user_ion_client = vcd_get_ion_client();
+		if (!client_ctx->user_ion_client) {
+			WFD_MSG_ERR("vcd_open ion get client failed");
+			return -EFAULT;
+		}
+	}
+
+	rc = vcd_open(venc_p.device_handle, false, venc_cb,
+					inst);
+	if (rc) {
+		WFD_MSG_ERR("vcd_open failed, rc = %d\n", rc);
+		goto no_free_client;
+	}
+	wait_for_completion(&client_ctx->event);
+	if (client_ctx->event_status) {
+		WFD_MSG_ERR("callback for vcd_open returned error: %u",
+				client_ctx->event_status);
+		goto no_free_client;
+	}
+	WFD_MSG_ERR("NOTE: client_ctx = %p\n", client_ctx);
+	vmops->cookie = inst;
+	sd->dev_priv = inst;
+no_free_client:
+	mutex_unlock(&venc_p.lock);
+	return rc;
+}
+
+static long venc_close(struct v4l2_subdev *sd, void *arg)
+{
+	long rc = 0;
+	struct venc_inst *inst;
+	struct video_client_ctx *client_ctx = NULL;
+	mutex_lock(&venc_p.lock);
+	inst = sd->dev_priv;
+	client_ctx = &inst->venc_client;
+	if (!client_ctx || !client_ctx->vcd_handle) {
+		WFD_MSG_ERR("Invalid client context in close\n");
+		rc = -ENODEV;
+		goto end;
+	}
+	rc = vcd_close(client_ctx->vcd_handle);
+	if (rc) {
+		WFD_MSG_ERR("Failed to close encoder subdevice\n");
+		goto end;
+	}
+	memset((void *)client_ctx, 0,
+			sizeof(struct video_client_ctx));
+end:
+	mutex_unlock(&venc_p.lock);
+	return rc;
+}
+
+static long venc_get_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct v4l2_requestbuffers *b = arg;
+	struct vcd_buffer_requirement buf_req;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid client context");
+		rc = -EINVAL;
+		goto err;
+	}
+	rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_OUTPUT, &buf_req);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get out buf reqs rc = %d", rc);
+		goto err;
+	}
+	b->count = buf_req.actual_count;
+err:
+	return rc;
+}
+
+static long venc_set_buffer_req(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct bufreq *b = arg;
+	struct vcd_buffer_requirement buf_req;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	if (!client_ctx) {
+		WFD_MSG_ERR("Invalid client context");
+		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.align = 0;
+	inst->width = b->width;
+	inst->height = b->height;
+	rc = vcd_set_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_INPUT, &buf_req);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get out buf reqs rc = %d", rc);
+		goto err;
+	}
+	b->size = buf_req.sz;
+err:
+	return rc;
+}
+
+static long venc_start(struct v4l2_subdev *sd)
+{
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	int rc;
+	if (!client_ctx) {
+		WFD_MSG_ERR("Client context is NULL");
+		return -EINVAL;
+	}
+	rc = vcd_encode_start(client_ctx->vcd_handle);
+	if (rc) {
+		WFD_MSG_ERR("vcd_encode_start failed, rc = %d\n", rc);
+		goto err;
+	}
+	wait_for_completion(&client_ctx->event);
+	if (client_ctx->event_status)
+		WFD_MSG_ERR("callback for vcd_encode_start returned error: %u",
+				client_ctx->event_status);
+err:
+	return rc;
+}
+
+static long venc_stop(struct v4l2_subdev *sd)
+{
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	int rc;
+	if (!client_ctx) {
+		WFD_MSG_ERR("Client context is NULL");
+		return -EINVAL;
+	}
+	rc = vcd_stop(client_ctx->vcd_handle);
+	wait_for_completion(&client_ctx->event);
+	return rc;
+}
+
+static long venc_set_codec(struct video_client_ctx *client_ctx, __s32 codec)
+{
+	struct vcd_property_codec vcd_property_codec;
+	struct vcd_property_hdr vcd_property_hdr;
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+	vcd_property_codec.codec = VCD_CODEC_H264;
+	switch (codec) {
+	case V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC:
+		vcd_property_codec.codec = VCD_CODEC_H264;
+		break;
+	case V4L2_MPEG_VIDEO_ENCODING_MPEG_1:
+		vcd_property_codec.codec = VCD_CODEC_MPEG4;
+		break;
+	default:
+		WFD_MSG_ERR("Codec not supported, defaulting to h264\n");
+		break;
+	}
+	return vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+}
+
+static long venc_get_codec(struct video_client_ctx *client_ctx, __s32 *codec)
+{
+	struct vcd_property_codec vcd_property_codec;
+	struct vcd_property_hdr vcd_property_hdr;
+	int rc = 0;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Failed to get codec property");
+		return rc;
+	}
+
+	switch (vcd_property_codec.codec) {
+	case VCD_CODEC_H264:
+		*codec = V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC;
+		break;
+	case VCD_CODEC_MPEG4:
+		*codec = V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+		break;
+	default:
+		WFD_MSG_ERR("Unrecognized codec");
+		return -EINVAL;
+		break;
+	}
+
+	return rc;
+}
+
+static long venc_set_codec_level(struct video_client_ctx *client_ctx,
+					__s32 codec, __s32 level)
+{
+	struct vcd_property_level vcd_property_level;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec vcd_property_codec;
+
+	int rc = 0;
+	int mpeg4_base = VCD_LEVEL_MPEG4_0;
+	int h264_base = VCD_LEVEL_H264_1;
+
+	/* Validate params */
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting codec property");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (!((vcd_property_codec.codec == VCD_CODEC_H264
+		&& codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) ||
+		(vcd_property_codec.codec == VCD_CODEC_MPEG4
+		&& codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL))) {
+		WFD_MSG_ERR("Attempting to set %d for codec type %d",
+			codec, vcd_property_codec.codec);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	/* Set property */
+	vcd_property_hdr.prop_id = VCD_I_LEVEL;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_level);
+
+	if (codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL) {
+		vcd_property_level.level = mpeg4_base + level;
+
+		if (vcd_property_level.level < VCD_LEVEL_MPEG4_0
+			|| vcd_property_level.level > VCD_LEVEL_MPEG4_X) {
+			WFD_MSG_ERR("Level (%d) out of range"
+					"for codec (%d)\n", level, codec);
+
+			rc = -EINVAL;
+			goto err;
+		}
+	} else if (codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
+		vcd_property_level.level = h264_base + level;
+
+		if (vcd_property_level.level < VCD_LEVEL_H264_1
+			|| vcd_property_level.level > VCD_LEVEL_H264_5p1) {
+			WFD_MSG_ERR("Level (%d) out of range"
+					"for codec (%d)\n", level, codec);
+
+			rc = -EINVAL;
+			goto err;
+		}
+	} else {
+		WFD_MSG_ERR("Codec (%d) not supported, not setting level (%d)",
+				codec, level);
+		rc = -ENOTSUPP;
+		goto err;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_level);
+err:
+	return rc;
+}
+
+static long venc_get_codec_level(struct video_client_ctx *client_ctx,
+					__s32 codec, __s32 *level)
+{
+	struct vcd_property_level vcd_property_level;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec vcd_property_codec;
+
+	int rc = 0;
+	int mpeg4_base = VCD_LEVEL_MPEG4_0;
+	int h264_base = VCD_LEVEL_H264_1;
+
+	/* Validate params */
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting codec property");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (!((vcd_property_codec.codec == VCD_CODEC_H264
+		&& codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) ||
+		(vcd_property_codec.codec == VCD_CODEC_MPEG4
+		&& codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL))) {
+		WFD_MSG_ERR("Attempting to get %d for codec type %d",
+			codec, vcd_property_codec.codec);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_LEVEL;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_level);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_level);
+	if (rc < 0) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (codec == V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL) {
+		*level = vcd_property_level.level - mpeg4_base;
+	} else if (codec == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
+		*level = vcd_property_level.level - h264_base;
+	} else {
+		WFD_MSG_ERR("Codec (%d) not supported", codec);
+		rc = -ENOTSUPP;
+		goto err;
+	}
+
+err:
+	return rc;
+}
+
+static long venc_set_codec_profile(struct video_client_ctx *client_ctx,
+					__s32 codec, __s32 profile)
+{
+	struct vcd_property_profile vcd_property_profile;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec vcd_property_codec;
+	int rc = 0;
+
+	/* Validate params */
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting codec property");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (!((vcd_property_codec.codec == VCD_CODEC_H264
+		&& codec == V4L2_CID_MPEG_VIDEO_H264_PROFILE) ||
+		(vcd_property_codec.codec == VCD_CODEC_MPEG4
+		&& codec == V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE))) {
+		WFD_MSG_ERR("Attempting to set %d for codec type %d",
+			codec, vcd_property_codec.codec);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	/* Set property */
+	vcd_property_hdr.prop_id = VCD_I_PROFILE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_profile);
+
+	if (codec == V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE) {
+		switch (profile) {
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
+			vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
+			break;
+		case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
+			vcd_property_profile.profile = VCD_PROFILE_MPEG4_ASP;
+			break;
+		default:
+			WFD_MSG_ERR("Profile %d not supported,"
+					"defaulting to simple (%d)",
+					profile, VCD_PROFILE_MPEG4_SP);
+			vcd_property_profile.profile = VCD_PROFILE_MPEG4_SP;
+			break;
+		}
+	} else if (codec == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
+		switch (profile) {
+		case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+			vcd_property_profile.profile =
+				VCD_PROFILE_H264_BASELINE;
+			break;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+			vcd_property_profile.profile = VCD_PROFILE_H264_MAIN;
+			break;
+		case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+			vcd_property_profile.profile = VCD_PROFILE_H264_HIGH;
+			break;
+		default:
+			WFD_MSG_ERR("Profile %d not supported,"
+					"defaulting to baseline (%d)",
+					profile, VCD_PROFILE_H264_BASELINE);
+			vcd_property_profile.profile =
+				VCD_PROFILE_H264_BASELINE;
+			break;
+		}
+	} else {
+		WFD_MSG_ERR("Codec (%d) not supported,"
+				"not setting profile (%d)",
+				codec, profile);
+		rc = -ENOTSUPP;
+		goto err;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_profile);
+err:
+	return rc;
+}
+
+static long venc_get_codec_profile(struct video_client_ctx *client_ctx,
+		__s32 codec, __s32 *profile)
+{
+	struct vcd_property_profile vcd_property_profile;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_codec vcd_property_codec;
+	int rc = 0;
+
+	/* Validate params */
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting codec property");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	if (!((vcd_property_codec.codec == VCD_CODEC_H264
+		&& codec == V4L2_CID_MPEG_VIDEO_H264_PROFILE) ||
+		(vcd_property_codec.codec == VCD_CODEC_MPEG4
+		&& codec == V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE))) {
+		WFD_MSG_ERR("Attempting to set %d for codec type %d",
+			codec, vcd_property_codec.codec);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	/* Set property */
+	vcd_property_hdr.prop_id = VCD_I_PROFILE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_profile);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_profile);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Unable to get property");
+		rc = -EINVAL;
+		goto err;
+	}
+
+	switch (vcd_property_profile.profile) {
+	case VCD_PROFILE_MPEG4_SP:
+		*profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE;
+		break;
+	case VCD_PROFILE_MPEG4_ASP:
+		*profile = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE;
+		break;
+	case VCD_PROFILE_H264_BASELINE:
+		*profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
+		break;
+	case VCD_PROFILE_H264_MAIN:
+		*profile = V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
+		break;
+	case VCD_PROFILE_H264_HIGH:
+		*profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+		break;
+	default:
+		WFD_MSG_ERR("Unexpected profile");
+		rc = -EINVAL;
+		goto err;
+		break;
+	}
+err:
+	return rc;
+}
+
+static long venc_set_h264_intra_period(struct video_client_ctx *client_ctx,
+		__s32 period) {
+	struct vcd_property_i_period vcd_property_i_period;
+	struct vcd_property_codec vcd_property_codec;
+	struct vcd_property_hdr vcd_property_hdr;
+	int rc = 0;
+
+	vcd_property_hdr.prop_id = VCD_I_CODEC;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_codec);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_codec);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error getting codec property\n");
+		goto err;
+	}
+
+	if (vcd_property_codec.codec != VCD_CODEC_H264) {
+		rc = -ENOTSUPP;
+		WFD_MSG_ERR("Control not supported for non H264 codec\n");
+		goto err;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_INTRA_PERIOD;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_i_period);
+
+	vcd_property_i_period.p_frames = period - 1;
+	vcd_property_i_period.b_frames = 1;
+
+	rc = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_i_period);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Error setting intra period\n");
+		goto err;
+	}
+
+err:
+	return rc;
+}
+
+static long venc_request_frame(struct video_client_ctx *client_ctx, __s32 type)
+{
+	struct vcd_property_req_i_frame vcd_property_req_i_frame;
+	struct vcd_property_hdr vcd_property_hdr;
+
+	int rc = 0;
+	switch (type) {
+	case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED:
+		/*So...nothing to do?*/
+		break;
+	case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME:
+		vcd_property_hdr.prop_id = VCD_I_REQ_IFRAME;
+		vcd_property_hdr.sz = sizeof(struct vcd_property_req_i_frame);
+		vcd_property_req_i_frame.req_i_frame = 1;
+
+		rc = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &vcd_property_req_i_frame);
+		break;
+	case V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED:
+	default:
+		rc = -ENOTSUPP;
+	}
+
+	return rc;
+}
+
+static long venc_set_bitrate(struct video_client_ctx *client_ctx,
+			__s32 bitrate)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_target_bitrate bit_rate;
+	if (!client_ctx || !bitrate)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_TARGET_BITRATE;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_target_bitrate);
+	bit_rate.target_bitrate = bitrate;
+	return vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &bit_rate);
+}
+
+static long venc_get_bitrate(struct video_client_ctx *client_ctx,
+			__s32 *bitrate)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_target_bitrate bit_rate;
+	int rc = 0;
+
+	if (!client_ctx || !bitrate)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_TARGET_BITRATE;
+	vcd_property_hdr.sz =
+			sizeof(struct vcd_property_target_bitrate);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &bit_rate);
+
+	if (rc < 0) {
+		WFD_MSG_ERR("Failed getting property for bitrate");
+		return rc;
+	}
+
+	*bitrate = bit_rate.target_bitrate;
+	return rc;
+}
+
+static long venc_set_bitrate_mode(struct video_client_ctx *client_ctx,
+			__s32 mode)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_rate_control rate_control;
+	int rc = 0;
+
+	if (!client_ctx) {
+		rc = -EINVAL;
+		goto err;
+	}
+
+	vcd_property_hdr.prop_id = VCD_I_RATE_CONTROL;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_rate_control);
+	/*
+	 * XXX: V4L doesn't seem have a control to toggle between CFR
+	 * and VFR, so assuming worse case VFR.
+	 */
+	switch (mode) {
+	case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+		rate_control.rate_control = VCD_RATE_CONTROL_VBR_VFR;
+		break;
+	case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+		rate_control.rate_control = VCD_RATE_CONTROL_CBR_VFR;
+		break;
+	default:
+		WFD_MSG_ERR("unknown bitrate mode %d", mode);
+		rc = -EINVAL;
+		goto err;
+	}
+
+	rc = vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &rate_control);
+err:
+	return rc;
+}
+
+static long venc_get_bitrate_mode(struct video_client_ctx *client_ctx,
+			__s32 *mode)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_rate_control rate_control;
+	int rc = 0;
+
+	if (!client_ctx)
+		return -EINVAL;
+
+	vcd_property_hdr.prop_id = VCD_I_RATE_CONTROL;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_rate_control);
+	rc = vcd_get_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &rate_control);
+
+	switch (rate_control.rate_control) {
+	case VCD_RATE_CONTROL_CBR_VFR:
+	case VCD_RATE_CONTROL_CBR_CFR:
+		*mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+		break;
+	case VCD_RATE_CONTROL_VBR_VFR:
+	case VCD_RATE_CONTROL_VBR_CFR:
+		*mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
+		break;
+	default:
+		WFD_MSG_ERR("unknown bitrate mode %d",
+				rate_control.rate_control);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static long venc_set_frame_size(struct video_client_ctx *client_ctx,
+				u32 height, u32 width)
+{
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_size frame_size;
+	vcd_property_hdr.prop_id = VCD_I_FRAME_SIZE;
+	vcd_property_hdr.sz =
+		sizeof(struct vcd_property_frame_size);
+	frame_size.height = height;
+	frame_size.width = width;
+	return vcd_set_property(client_ctx->vcd_handle,
+				&vcd_property_hdr, &frame_size);
+}
+
+static long venc_set_format(struct v4l2_subdev *sd, void *arg)
+{
+	struct venc_inst *inst;
+	struct video_client_ctx *client_ctx;
+	struct v4l2_format *fmt = arg;
+	struct vcd_buffer_requirement buf_req;
+	int rc = 0;
+
+	inst = sd->dev_priv;
+	client_ctx = &inst->venc_client;
+	if (!inst || !client_ctx || !fmt) {
+		WFD_MSG_ERR("Invalid parameters\n");
+		return -EINVAL;
+	}
+	rc = venc_set_frame_size(client_ctx, fmt->fmt.pix.height,
+				fmt->fmt.pix.width);
+	if (rc) {
+		WFD_MSG_ERR("Failed to set frame size, rc = %d\n", rc);
+		goto err;
+	}
+	rc = vcd_get_buffer_requirements(client_ctx->vcd_handle,
+			VCD_BUFFER_OUTPUT, &buf_req);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get buf requrements, rc = %d\n", rc);
+		goto err;
+	}
+	fmt->fmt.pix.sizeimage = buf_req.sz;
+err:
+	return rc;
+}
+
+static long venc_set_framerate(struct v4l2_subdev *sd,
+				void *arg)
+{
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct v4l2_fract *frate = arg;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_frame_rate vcd_frame_rate;
+	int rc;
+	vcd_property_hdr.prop_id = VCD_I_FRAME_RATE;
+	vcd_property_hdr.sz =
+				sizeof(struct vcd_property_frame_rate);
+	vcd_frame_rate.fps_denominator = frate->denominator;
+	vcd_frame_rate.fps_numerator = frate->numerator;
+	rc = vcd_set_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &vcd_frame_rate);
+	if (rc)
+		WFD_MSG_ERR("Failed to set frame rate, rc = %d\n", rc);
+	return rc;
+}
+
+static long venc_alloc_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	struct mem_region *mregion = arg;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	int rc = 0;
+	if (!client_ctx || !mregion) {
+		WFD_MSG_ERR("Invalid input\n");
+		return -EINVAL;
+	}
+	rc = vcd_allocate_buffer(client_ctx->vcd_handle,
+		VCD_BUFFER_INPUT, mregion->size,
+		&mregion->kvaddr, &mregion->paddr);
+	if (rc)
+		WFD_MSG_ERR("Failed to allocate input buffer\n");
+	return rc;
+}
+
+static long venc_set_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct mem_region *mregion = arg;
+	if (!client_ctx || !mregion) {
+		WFD_MSG_ERR("Invalid input\n");
+		return -EINVAL;
+	}
+	WFD_MSG_DBG("size = %u, offset = %u fd = %d\n", mregion->size,
+				mregion->offset, mregion->fd);
+	rc = vidc_insert_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+					mregion->cookie,
+					(unsigned long *)&mregion->kvaddr,
+					mregion->fd,
+					mregion->offset,
+					32,
+					mregion->size);
+	if (!rc) {
+		WFD_MSG_ERR("Failed to insert outbuf in table\n");
+		goto err;
+	}
+	WFD_MSG_DBG("size = %u, %p\n", mregion->size, mregion->kvaddr);
+
+	rc = vcd_set_buffer(client_ctx->vcd_handle,
+				    VCD_BUFFER_OUTPUT, (u8 *) mregion->kvaddr,
+				    mregion->size);
+	if (rc)
+		WFD_MSG_ERR("Failed to set outbuf on encoder\n");
+err:
+	return rc;
+}
+
+static long venc_fill_outbuf(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct mem_region *mregion = arg;
+	struct vcd_frame_data vcd_frame = {0};
+	unsigned long kernel_vaddr, phy_addr, user_vaddr;
+	int pmem_fd;
+	struct file *file;
+	s32 buffer_index = -1;
+
+	user_vaddr = mregion->cookie;
+	rc = vidc_lookup_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+			true, &user_vaddr,
+			&kernel_vaddr, &phy_addr, &pmem_fd, &file,
+			&buffer_index);
+	if (!rc) {
+		WFD_MSG_ERR("Address lookup failed\n");
+		goto err;
+	}
+	vcd_frame.virtual = (u8 *) kernel_vaddr;
+	vcd_frame.frm_clnt_data = mregion->cookie;
+	vcd_frame.alloc_len = mregion->size;
+
+	rc = vcd_fill_output_buffer(client_ctx->vcd_handle,	&vcd_frame);
+	if (rc)
+		WFD_MSG_ERR("Failed to fill output buffer on encoder");
+err:
+	return rc;
+}
+
+static long venc_encode_frame(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct mem_region *mregion = arg;
+	struct vcd_frame_data vcd_input_buffer = {0};
+
+	vcd_input_buffer.virtual = mregion->kvaddr;
+	vcd_input_buffer.frm_clnt_data = (u32)mregion;
+	vcd_input_buffer.ip_frm_tag = (u32)mregion;
+	vcd_input_buffer.data_len = mregion->size;
+	vcd_input_buffer.time_stamp = 0; /*TODO: Need to fix this*/
+	vcd_input_buffer.offset = 0;
+
+	rc = vcd_encode_frame(client_ctx->vcd_handle,
+			&vcd_input_buffer);
+
+	if (rc)
+		WFD_MSG_ERR("encode frame failed\n");
+	return rc;
+}
+
+static long venc_alloc_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct vcd_property_hdr vcd_property_hdr;
+	struct vcd_property_buffer_size control;
+	struct vcd_property_enc_recon_buffer *ctrl = NULL;
+	unsigned long phy_addr;
+	int i = 0;
+	u32 len;
+	control.width = inst->width;
+	control.height = inst->height;
+	vcd_property_hdr.prop_id = VCD_I_GET_RECON_BUFFER_SIZE;
+	vcd_property_hdr.sz = sizeof(struct vcd_property_buffer_size);
+
+	rc = vcd_get_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, &control);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get recon buf size\n");
+		goto err;
+	}
+
+	if (vcd_get_ion_status()) {
+		for (i = 0; i < 4; ++i) {
+			ctrl = &client_ctx->recon_buffer[i];
+			ctrl->buffer_size = control.size;
+			ctrl->pmem_fd = 0;
+			ctrl->offset = 0;
+			ctrl->user_virtual_addr = (void *)i;
+			client_ctx->recon_buffer_ion_handle[i]
+				= ion_alloc(client_ctx->user_ion_client,
+			control.size, SZ_8K, (0x1<<ION_CP_MM_HEAP_ID));
+			ctrl->kernel_virtual_addr = ion_map_kernel(
+				client_ctx->user_ion_client,
+				client_ctx->recon_buffer_ion_handle[i],	0);
+
+			rc = ion_phys(client_ctx->user_ion_client,
+				client_ctx->recon_buffer_ion_handle[i],
+				&phy_addr, &len);
+			if (rc) {
+				WFD_MSG_ERR("Failed to allo recon buffers\n");
+				break;
+			}
+			ctrl->physical_addr =  (u8 *) phy_addr;
+			ctrl->dev_addr = ctrl->physical_addr;
+			vcd_property_hdr.prop_id = VCD_I_RECON_BUFFERS;
+			vcd_property_hdr.sz =
+				sizeof(struct vcd_property_enc_recon_buffer);
+			rc = vcd_set_property(client_ctx->vcd_handle,
+					&vcd_property_hdr, ctrl);
+			if (rc) {
+				WFD_MSG_ERR("Failed to set recon buffers\n");
+				break;
+			}
+		}
+	} else {
+		WFD_MSG_ERR("PMEM not suported\n");
+		return -ENOMEM;
+	}
+err:
+	return rc;
+}
+
+static long venc_free_output_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct mem_region *mregion = arg;
+	unsigned long kernel_vaddr, user_vaddr;
+
+	if (!client_ctx || !mregion) {
+		WFD_MSG_ERR("Invalid input\n");
+		return -EINVAL;
+	}
+
+	user_vaddr = mregion->cookie;
+	rc = vidc_delete_addr_table(client_ctx, BUFFER_TYPE_OUTPUT,
+				user_vaddr,
+				&kernel_vaddr);
+	if (!rc) {
+		WFD_MSG_ERR("Failed to delete buf from address table\n");
+		return -EINVAL;
+	}
+	return vcd_free_buffer(client_ctx->vcd_handle, VCD_BUFFER_OUTPUT,
+					 (u8 *)kernel_vaddr);
+}
+
+static long venc_free_input_buffer(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct mem_region *mregion = arg;
+	if (!client_ctx || !mregion) {
+		WFD_MSG_ERR("Invalid input\n");
+		return -EINVAL;
+	}
+	rc = vcd_free_buffer(client_ctx->vcd_handle, VCD_BUFFER_INPUT,
+					 mregion->kvaddr);
+	if (rc)
+		WFD_MSG_ERR("Failed to free input buffer\n");
+	return rc;
+}
+
+static long venc_free_recon_buffers(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	struct vcd_property_hdr vcd_property_hdr;
+	int i;
+
+	if (vcd_get_ion_status()) {
+		for (i = 0; i < 4; i++) {
+			vcd_property_hdr.prop_id = VCD_I_FREE_RECON_BUFFERS;
+			vcd_property_hdr.sz =
+				sizeof(struct vcd_property_buffer_size);
+			rc = vcd_set_property(client_ctx->vcd_handle,
+			&vcd_property_hdr, &client_ctx->recon_buffer[i]);
+			if (rc)
+				WFD_MSG_ERR("Failed to free recon buffer\n");
+
+			if (client_ctx->recon_buffer_ion_handle[i]) {
+				ion_unmap_kernel(client_ctx->user_ion_client,
+					client_ctx->recon_buffer_ion_handle[i]);
+				ion_free(client_ctx->user_ion_client,
+					client_ctx->recon_buffer_ion_handle[i]);
+				client_ctx->recon_buffer_ion_handle[i] = NULL;
+			}
+		}
+	}
+	return rc;
+}
+
+static long venc_set_property(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct v4l2_control *ctrl = arg;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		rc = venc_set_bitrate(client_ctx, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		rc = venc_set_bitrate_mode(client_ctx, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		rc = venc_set_codec(client_ctx, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
+		rc = venc_set_h264_intra_period(client_ctx, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		rc = venc_set_codec_level(client_ctx, ctrl->id, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		rc = venc_set_codec_profile(client_ctx, ctrl->id, ctrl->value);
+		break;
+	case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
+		rc = venc_request_frame(client_ctx, ctrl->value);
+		break;
+	default:
+		WFD_MSG_ERR("Set property not suported: %d\n", ctrl->id);
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+static long venc_get_property(struct v4l2_subdev *sd, void *arg)
+{
+	int rc = 0;
+	struct venc_inst *inst = sd->dev_priv;
+	struct v4l2_control *ctrl = arg;
+	struct video_client_ctx *client_ctx = &inst->venc_client;
+
+	switch (ctrl->id) {
+	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		rc = venc_get_bitrate(client_ctx, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		rc = venc_get_bitrate_mode(client_ctx, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_ENCODING:
+		rc = venc_get_codec(client_ctx, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
+		rc = venc_get_codec_level(client_ctx, ctrl->id, &ctrl->value);
+		break;
+	case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
+		rc = venc_get_codec_profile(client_ctx, ctrl->id, &ctrl->value);
+		break;
+	default:
+		WFD_MSG_ERR("Get property not suported: %d\n", ctrl->id);
+		rc = -ENOTSUPP;
+		break;
+	}
+	return rc;
+}
+
+long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+	long rc = 0;
+	switch (cmd) {
+	case OPEN:
+		rc = venc_open(sd, arg);
+		break;
+	case CLOSE:
+		rc = venc_close(sd, arg);
+		break;
+	case ENCODE_START:
+		rc = venc_start(sd);
+		break;
+	case ENCODE_FRAME:
+		venc_encode_frame(sd, arg);
+		break;
+	case ENCODE_STOP:
+		rc = venc_stop(sd);
+		break;
+	case SET_PROP:
+		rc = venc_set_property(sd, arg);
+		break;
+	case GET_PROP:
+		rc = venc_get_property(sd, arg);
+		break;
+	case GET_BUFFER_REQ:
+		rc = venc_get_buffer_req(sd, arg);
+		break;
+	case SET_BUFFER_REQ:
+		rc = venc_set_buffer_req(sd, arg);
+		break;
+	case FREE_BUFFER:
+		break;
+	case FILL_OUTPUT_BUFFER:
+		rc = venc_fill_outbuf(sd, arg);
+		break;
+	case SET_FORMAT:
+		rc = venc_set_format(sd, arg);
+		break;
+	case SET_FRAMERATE:
+		rc = venc_set_framerate(sd, arg);
+		break;
+	case ALLOC_INPUT_BUFFER:
+		rc = venc_alloc_input_buffer(sd, arg);
+		break;
+	case SET_OUTPUT_BUFFER:
+		rc = venc_set_output_buffer(sd, arg);
+		break;
+	case ALLOC_RECON_BUFFERS:
+		rc = venc_alloc_recon_buffers(sd, arg);
+		break;
+	case FREE_OUTPUT_BUFFER:
+		rc = venc_free_output_buffer(sd, arg);
+		break;
+	case FREE_INPUT_BUFFER:
+		rc = venc_free_input_buffer(sd, arg);
+		break;
+	case FREE_RECON_BUFFERS:
+		rc = venc_free_recon_buffers(sd, arg);
+		break;
+	default:
+		rc = -1;
+		break;
+	}
+	return rc;
+}
diff --git a/drivers/media/video/msm/wfd/enc-subdev.h b/drivers/media/video/msm/wfd/enc-subdev.h
new file mode 100644
index 0000000..890c973
--- /dev/null
+++ b/drivers/media/video/msm/wfd/enc-subdev.h
@@ -0,0 +1,68 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 and
+* only version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+* GNU General Public License for more details.
+*
+*/
+
+#include <media/v4l2-subdev.h>
+#include <media/videobuf2-core.h>
+#define VENC_MAGIC_IOCTL 'V'
+
+struct mem_region {
+	struct list_head list;
+	u8 *kvaddr;
+	u8 *paddr;
+	u32 size;
+	u32 offset;
+	u32 fd;
+	u32 cookie;
+};
+struct bufreq {
+	u32 count;
+	u32 height;
+	u32 width;
+	u32 size;
+};
+struct venc_msg_ops {
+	void *cookie;
+	void *cbdata;
+	void (*op_buffer_done)(void *cookie, u32 status,
+			struct vb2_buffer *buf);
+	void (*ip_buffer_done)(void *cookie, u32 status,
+			struct mem_region *mregion);
+};
+
+#define OPEN  _IOR('V', 1, void *)
+#define CLOSE  _IO('V', 2)
+#define ENCODE_START  _IO('V', 3)
+#define ENCODE_FRAME  _IO('V', 4)
+#define PAUSE  _IO('V', 5)
+#define RESUME  _IO('V', 6)
+#define FLUSH  _IO('V', 7)
+#define ENCODE_STOP  _IO('V', 8)
+#define SET_PROP  _IO('V', 9)
+#define GET_PROP  _IO('V', 10)
+#define SET_BUFFER_REQ  _IOWR('V', 11, struct v4l2_requestbuffers *)
+#define GET_BUFFER_REQ  _IOWR('V', 12, struct v4l2_requestbuffers *)
+#define ALLOCATE_BUFFER  _IO('V', 13)
+#define FREE_BUFFER  _IO('V', 14)
+#define FILL_OUTPUT_BUFFER  _IO('V', 15)
+#define SET_FORMAT _IOW('V', 16, struct v4l2_format *)
+#define SET_FRAMERATE _IOW('V', 17, struct v4l2_fract *)
+#define ALLOC_INPUT_BUFFER _IOWR('V', 18, struct mem_region *)
+#define SET_OUTPUT_BUFFER _IOWR('V', 19, struct mem_region *)
+#define ALLOC_RECON_BUFFERS _IO('V', 20)
+#define FREE_OUTPUT_BUFFER _IOWR('V', 21, struct mem_region *)
+#define FREE_INPUT_BUFFER _IOWR('V', 22, struct mem_region *)
+#define FREE_RECON_BUFFERS _IO('V', 23)
+
+extern int venc_init(struct v4l2_subdev *sd, u32 val);
+extern int venc_load_fw(struct v4l2_subdev *sd);
+extern long venc_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.c b/drivers/media/video/msm/wfd/mdp-subdev.c
index ed72ca8..9fd8a8e 100644
--- a/drivers/media/video/msm/wfd/mdp-subdev.c
+++ b/drivers/media/video/msm/wfd/mdp-subdev.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
@@ -67,6 +67,11 @@
 	int rc = 0;
 	struct fb_info *fbi = NULL;
 	if (inst) {
+		rc = msm_fb_writeback_start(inst->mdp);
+		if (rc) {
+			WFD_MSG_ERR("Failed to start MDP mode\n");
+			goto exit;
+		}
 		fbi = msm_fb_get_writeback_fb();
 		if (!fbi) {
 			WFD_MSG_ERR("Failed to acquire mdp instance\n");
@@ -86,6 +91,11 @@
 	int rc = 0;
 	struct fb_info *fbi = NULL;
 	if (inst) {
+		rc = msm_fb_writeback_stop(inst->mdp);
+		if (rc) {
+			WFD_MSG_ERR("Failed to stop writeback mode\n");
+			return rc;
+		}
 		fbi = (struct fb_info *)inst->mdp;
 		rc = kobject_uevent(&fbi->dev->kobj, KOBJ_OFFLINE);
 		if (rc) {
@@ -112,16 +122,17 @@
 	struct mdp_buf_info *binfo = arg;
 	struct msmfb_data fbdata;
 	struct mdp_instance *inst;
-	if (!binfo || !binfo->inst || !binfo->b) {
+	if (!binfo || !binfo->inst || !binfo->cookie) {
 		WFD_MSG_ERR("Invalid argument\n");
 		return -EINVAL;
 	}
 	inst = binfo->inst;
 	fbdata.offset = binfo->offset;
 	fbdata.memory_id = binfo->fd;
+	fbdata.iova = binfo->paddr;
 	fbdata.id = 0;
 	fbdata.flags = 0;
-	fbdata.priv = (uint32_t)binfo->b;
+	fbdata.priv = (uint32_t)binfo->cookie;
 
 	WFD_MSG_INFO("queue buffer to mdp with offset = %u,"
 			"fd = %u, priv = %u\n",
@@ -150,45 +161,9 @@
 		WFD_MSG_ERR("Failed to dequeue buffer\n");
 		return rc;
 	}
-	WFD_MSG_INFO("dequeue buffer from mdp with offset = %u,"
-			"fd = %u, priv = %u\n",
-			fbdata.offset, fbdata.memory_id, fbdata.priv);
-	obuf->b = (struct vb2_buffer *)fbdata.priv;
-	return rc;
-}
-int mdp_prepare_buffer(struct v4l2_subdev *sd, void *arg)
-{
-	int rc = 0;
-	struct mdp_buf_info *binfo = arg;
-	struct msmfb_writeback_data wbdata;
-	struct mdp_instance *inst;
-
-	if (!binfo || !binfo->inst || !binfo->b) {
-		WFD_MSG_ERR("Invalid argument\n");
-		return -EINVAL;
-	}
-
-	inst = binfo->inst;
-	wbdata.buf_info.offset = binfo->offset;
-	wbdata.buf_info.memory_id = binfo->fd;
-	wbdata.buf_info.id = 0;
-	wbdata.buf_info.flags = 0;
-	wbdata.buf_info.priv = (uint32_t)binfo->b;
-
-	wbdata.img.width = inst->width;
-	wbdata.img.height = inst->height;
-	wbdata.img.format = MDP_RGB_565;
-	WFD_MSG_DBG("offset = %u, fd = %u, width = %u, height = %u,"
-			"uaddr = %u\n", wbdata.buf_info.offset,
-			wbdata.buf_info.memory_id,
-			wbdata.img.width, wbdata.img.height,
-			wbdata.buf_info.priv);
-
-	rc = msm_fb_writeback_register_buffer(inst->mdp, &wbdata);
-	if (rc) {
-		WFD_MSG_ERR("Failed to register buffer\n");
-		return -EIO;
-	}
+	WFD_MSG_DBG("dequeue buf from mdp with priv = %u\n",
+			fbdata.priv);
+	obuf->cookie = (void *)fbdata.priv;
 	return rc;
 }
 int mdp_set_prop(struct v4l2_subdev *sd, void *arg)
@@ -203,34 +178,6 @@
 	inst->width = prop->width;
 	return 0;
 }
-int mdp_release_buffer(struct v4l2_subdev *sd, void *arg)
-{
-	int rc = 0;
-	struct mdp_buf_info *binfo = arg;
-	struct msmfb_writeback_data wbdata;
-	struct mdp_instance *inst;
-	if (!binfo || !binfo->inst || !binfo->b) {
-		WFD_MSG_ERR("Invalid argument\n");
-		return -EINVAL;
-	}
-	inst = binfo->inst;
-
-	wbdata.buf_info.offset = binfo->offset;
-	wbdata.buf_info.memory_id = binfo->fd;
-	wbdata.buf_info.id = 0;
-	wbdata.buf_info.flags = 0;
-	wbdata.buf_info.priv = (uint32_t)binfo->b;
-
-	wbdata.img.width = inst->width;
-	wbdata.img.height = inst->height;
-	wbdata.img.format = MDP_RGB_565;
-
-	rc = msm_fb_writeback_unregister_buffer(inst->mdp, &wbdata);
-
-	if (rc)
-		WFD_MSG_ERR("Failed to unregister buffer\n");
-	return rc;
-}
 long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	int rc = 0;
@@ -245,9 +192,6 @@
 	case MDP_DQ_BUFFER:
 		rc = mdp_dq_buffer(sd, arg);
 		break;
-	case MDP_PREPARE_BUF:
-		rc = mdp_prepare_buffer(sd, arg);
-		break;
 	case MDP_OPEN:
 		rc = mdp_open(sd, arg);
 		break;
@@ -260,9 +204,6 @@
 	case MDP_SET_PROP:
 		rc = mdp_set_prop(sd, arg);
 		break;
-	case MDP_RELEASE_BUF:
-		rc = mdp_release_buffer(sd, arg);
-		break;
 	case MDP_CLOSE:
 		rc = mdp_close(sd, arg);
 		break;
diff --git a/drivers/media/video/msm/wfd/mdp-subdev.h b/drivers/media/video/msm/wfd/mdp-subdev.h
index fe8963a..a6b3bc4 100644
--- a/drivers/media/video/msm/wfd/mdp-subdev.h
+++ b/drivers/media/video/msm/wfd/mdp-subdev.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
@@ -18,9 +18,11 @@
 
 struct mdp_buf_info {
 	void *inst;
-	struct vb2_buffer *b;
+	void *cookie;
 	u32 fd;
 	u32 offset;
+	u32 kvaddr;
+	u32 paddr;
 };
 
 struct mdp_prop {
@@ -30,12 +32,10 @@
 };
 #define MDP_Q_BUFFER  _IOW(MDP_MAGIC_IOCTL, 1, struct mdp_buf_info *)
 #define MDP_DQ_BUFFER  _IOR(MDP_MAGIC_IOCTL, 2, struct mdp_out_buf *)
-#define MDP_PREPARE_BUF  _IOW(MDP_MAGIC_IOCTL, 3, struct  mdp_buf_info *)
-#define MDP_OPEN  _IOR(MDP_MAGIC_IOCTL, 4, void **)
-#define MDP_SET_PROP  _IOW(MDP_MAGIC_IOCTL, 5, struct mdp_prop *)
-#define MDP_RELEASE_BUF  _IOW(MDP_MAGIC_IOCTL, 6, struct mdp_buf_info *)
-#define MDP_CLOSE  _IOR(MDP_MAGIC_IOCTL, 7, void *)
-#define MDP_START  _IOR(MDP_MAGIC_IOCTL, 8, void *)
-#define MDP_STOP  _IOR(MDP_MAGIC_IOCTL, 9, void *)
+#define MDP_OPEN  _IOR(MDP_MAGIC_IOCTL, 3, void **)
+#define MDP_SET_PROP  _IOW(MDP_MAGIC_IOCTL, 4, struct mdp_prop *)
+#define MDP_CLOSE  _IOR(MDP_MAGIC_IOCTL, 5, void *)
+#define MDP_START  _IOR(MDP_MAGIC_IOCTL, 6, void *)
+#define MDP_STOP  _IOR(MDP_MAGIC_IOCTL, 7, void *)
 extern int mdp_init(struct v4l2_subdev *sd, u32 val);
 extern long mdp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/msm/wfd/wfd-ioctl.c b/drivers/media/video/msm/wfd/wfd-ioctl.c
index 9db5b54..27a8888 100644
--- a/drivers/media/video/msm/wfd/wfd-ioctl.c
+++ b/drivers/media/video/msm/wfd/wfd-ioctl.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
@@ -30,17 +30,20 @@
 #include <media/videobuf2-msm-mem.h>
 #include "wfd-util.h"
 #include "mdp-subdev.h"
+#include "enc-subdev.h"
 
 #define WFD_VERSION KERNEL_VERSION(0, 0, 1)
 #define DEFAULT_WFD_WIDTH 640
 #define DEFAULT_WFD_HEIGHT 480
 #define MIN_BUF_COUNT 2
+#define VENC_INPUT_BUFFERS 3
 
 struct wfd_device {
 	struct platform_device *pdev;
 	struct v4l2_device v4l2_dev;
 	struct video_device *pvdev;
 	struct v4l2_subdev mdp_sdev;
+	struct v4l2_subdev enc_sdev;
 };
 
 struct mem_info {
@@ -48,18 +51,27 @@
 	u32 offset;
 };
 
+struct mem_info_entry {
+	struct list_head list;
+	unsigned long userptr;
+	struct mem_info minfo;
+};
 struct wfd_inst {
 	struct vb2_queue vid_bufq;
-	spinlock_t buflock;
 	spinlock_t inst_lock;
 	u32 buf_count;
 	struct task_struct *mdp_task;
 	void *mdp_inst;
+	void *venc_inst;
 	u32 height;
 	u32 width;
 	u32 pixelformat;
-	struct mem_info **minfo;
+	struct list_head minfo_list;
 	bool streamoff;
+	u32 input_bufs_allocated;
+	u32 input_buf_size;
+	u32 out_buf_size;
+	struct list_head input_mem_list;
 };
 
 struct wfd_vid_buffer {
@@ -70,15 +82,22 @@
 		unsigned int *num_buffers, unsigned int *num_planes,
 		unsigned long sizes[], void *alloc_ctxs[])
 {
-	WFD_MSG_DBG("In %s\n", __func__);
+	struct file *priv_data = (struct file *)(q->drv_priv);
+	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
+	unsigned long flags;
+	int i;
 
+	WFD_MSG_DBG("In %s\n", __func__);
 	if (num_buffers == NULL || num_planes == NULL)
 		return -EINVAL;
 
 	*num_planes = 1;
-	/*MDP outputs in RGB for now;i
-	 * make sure it's smaller than VIDEO_MAX_PLANES*/
-	sizes[0] = 800*480*2;
+	spin_lock_irqsave(&inst->inst_lock, flags);
+	for (i = 0; i < *num_planes; ++i) {
+		sizes[i] = inst->out_buf_size;
+		alloc_ctxs[i] = inst;
+	}
+	spin_unlock_irqrestore(&inst->inst_lock, flags);
 
 	return 0;
 }
@@ -90,6 +109,135 @@
 {
 }
 
+int wfd_allocate_input_buffers(struct wfd_device *wfd_dev,
+			struct wfd_inst *inst)
+{
+	int i;
+	struct mem_region *mregion;
+	int rc;
+	unsigned long flags;
+	struct mdp_buf_info buf = {0};
+	spin_lock_irqsave(&inst->inst_lock, flags);
+	if (inst->input_bufs_allocated) {
+		spin_unlock_irqrestore(&inst->inst_lock, flags);
+		return 0;
+	}
+	inst->input_bufs_allocated = true;
+	spin_unlock_irqrestore(&inst->inst_lock, flags);
+
+	for (i = 0; i < VENC_INPUT_BUFFERS; ++i) {
+		mregion = kzalloc(sizeof(struct mem_region), GFP_KERNEL);
+		mregion->size = inst->input_buf_size;
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+				ALLOC_INPUT_BUFFER, (void *)mregion);
+		if (rc) {
+			WFD_MSG_ERR("Failed to allocate input memory."
+				" This error causes memory leak!!!\n");
+			break;
+		}
+		WFD_MSG_DBG("NOTE: paddr = %p, kvaddr = %p\n", mregion->paddr,
+					mregion->kvaddr);
+		list_add_tail(&mregion->list, &inst->input_mem_list);
+		buf.inst = inst->mdp_inst;
+		buf.cookie = mregion;
+		buf.kvaddr = (u32) mregion->kvaddr;
+		buf.paddr = (u32) mregion->paddr;
+		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+				MDP_Q_BUFFER, (void *)&buf);
+		if (rc) {
+			WFD_MSG_ERR("Unable to queue the buffer to mdp\n");
+			break;
+		}
+	}
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			ALLOC_RECON_BUFFERS, NULL);
+	if (rc)
+		WFD_MSG_ERR("Failed to allocate recon buffers\n");
+
+	return rc;
+}
+void wfd_free_input_buffers(struct wfd_device *wfd_dev,
+			struct wfd_inst *inst)
+{
+	struct list_head *ptr, *next;
+	struct mem_region *mregion;
+	unsigned long flags;
+	int rc = 0;
+	spin_lock_irqsave(&inst->inst_lock, flags);
+	if (!inst->input_bufs_allocated) {
+		spin_unlock_irqrestore(&inst->inst_lock, flags);
+		return;
+	}
+	inst->input_bufs_allocated = false;
+	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	if (!list_empty(&inst->input_mem_list)) {
+		list_for_each_safe(ptr, next,
+				&inst->input_mem_list) {
+			mregion = list_entry(ptr, struct mem_region,
+						list);
+			rc = v4l2_subdev_call(&wfd_dev->enc_sdev,
+					core, ioctl, FREE_INPUT_BUFFER,
+					(void *)mregion);
+			if (rc)
+				WFD_MSG_ERR("TODO: SOMETHING IS WRONG!!!\n");
+
+			list_del(&mregion->list);
+			kfree(mregion);
+		}
+	}
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			FREE_RECON_BUFFERS, NULL);
+	if (rc)
+		WFD_MSG_ERR("Failed to free recon buffers\n");
+}
+
+struct mem_info *wfd_get_mem_info(struct wfd_inst *inst,
+			unsigned long userptr)
+{
+	struct mem_info_entry *temp;
+	struct mem_info *ret = NULL;
+	unsigned long flags;
+	spin_lock_irqsave(&inst->inst_lock, flags);
+	if (!list_empty(&inst->minfo_list)) {
+		list_for_each_entry(temp, &inst->minfo_list, list) {
+			if (temp && temp->userptr == userptr) {
+				ret = &temp->minfo;
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	return ret;
+}
+void wfd_put_mem_info(struct wfd_inst *inst,
+			struct mem_info *minfo)
+{
+	struct list_head *ptr, *next;
+	struct mem_info_entry *temp;
+	unsigned long flags;
+	spin_lock_irqsave(&inst->inst_lock, flags);
+	if (!list_empty(&inst->minfo_list)) {
+		list_for_each_safe(ptr, next,
+				&inst->minfo_list) {
+			temp = list_entry(ptr, struct mem_info_entry,
+						list);
+			if (temp && (&temp->minfo == minfo)) {
+				list_del(&temp->list);
+				kfree(temp);
+			}
+		}
+	}
+	spin_unlock_irqrestore(&inst->inst_lock, flags);
+}
+static void wfd_unregister_out_buf(struct wfd_inst *inst,
+		struct mem_info *minfo)
+{
+	if (!minfo || !inst) {
+		WFD_MSG_ERR("Invalid arguments\n");
+		return;
+	}
+	wfd_put_mem_info(inst, minfo);
+}
 int wfd_vidbuf_buf_init(struct vb2_buffer *vb)
 {
 	int rc = 0;
@@ -98,20 +246,32 @@
 	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
 	struct wfd_device *wfd_dev =
 		(struct wfd_device *)video_drvdata(priv_data);
-	struct mdp_buf_info buf = {
-					inst->mdp_inst,
-					vb,
-					inst->minfo[vb->v4l2_buf.index]->fd,
-					inst->minfo[vb->v4l2_buf.index]->offset
-					};
+	struct mem_info *minfo = vb2_plane_cookie(vb, 0);
+	struct mem_region mregion;
+	mregion.fd = minfo->fd;
+	mregion.offset = minfo->offset;
+	mregion.cookie = (u32)vb;
+	/*TODO: should be fixed in kernel 3.2*/
+	mregion.size =  inst->out_buf_size;
 
 	if (inst && !inst->vid_bufq.streaming) {
-		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
-				ioctl, MDP_PREPARE_BUF, (void *)&buf);
-		if (rc)
-			WFD_MSG_ERR("Unable to prepare/register the buffer\n");
+		rc = wfd_allocate_input_buffers(wfd_dev, inst);
+		if (rc) {
+			WFD_MSG_ERR("Failed to allocate input buffers\n");
+			goto err;
+		}
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+				SET_OUTPUT_BUFFER, (void *)&mregion);
+		if (rc) {
+			WFD_MSG_ERR("Failed to set output buffer\n");
+			goto free_input_bufs;
+		}
 	}
 	return rc;
+free_input_bufs:
+	wfd_free_input_buffers(wfd_dev, inst);
+err:
+	return rc;
 }
 
 int wfd_vidbuf_buf_prepare(struct vb2_buffer *vb)
@@ -132,17 +292,48 @@
 	struct wfd_device *wfd_dev =
 		(struct wfd_device *)video_drvdata(priv_data);
 	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
-	struct mdp_buf_info buf = {
-					inst->mdp_inst,
-					vb,
-					inst->minfo[vb->v4l2_buf.index]->fd,
-					inst->minfo[vb->v4l2_buf.index]->offset
-					};
-	WFD_MSG_DBG("Releasing buffer\n");
-	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
-			 MDP_RELEASE_BUF, (void *)&buf);
+	struct mem_info *minfo = vb2_plane_cookie(vb, 0);
+	struct mem_region mregion;
+	mregion.fd = minfo->fd;
+	mregion.offset = minfo->offset;
+	mregion.cookie = (u32)vb;
+	mregion.size =  inst->out_buf_size;
+
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			FREE_OUTPUT_BUFFER, (void *)&mregion);
 	if (rc)
-		WFD_MSG_ERR("Failed to release the buffer\n");
+		WFD_MSG_ERR("Failed to free output buffer\n");
+	wfd_unregister_out_buf(inst, minfo);
+	wfd_free_input_buffers(wfd_dev, inst);
+}
+static int mdp_output_thread(void *data)
+{
+	int rc = 0;
+	struct file *filp = (struct file *)data;
+	struct wfd_inst *inst = filp->private_data;
+	struct wfd_device *wfd_dev =
+		(struct wfd_device *)video_drvdata(filp);
+	struct mdp_buf_info obuf = {inst->mdp_inst, 0, 0, 0};
+	while (!kthread_should_stop()) {
+		WFD_MSG_DBG("waiting for mdp output\n");
+		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
+			core, ioctl, MDP_DQ_BUFFER, (void *)&obuf);
+
+		if (rc) {
+			WFD_MSG_ERR("Either streamoff called or"
+						" MDP REPORTED ERROR\n");
+			break;
+		}
+
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			ENCODE_FRAME, obuf.cookie);
+		if (rc) {
+			WFD_MSG_ERR("Failed to encode frame\n");
+			break;
+		}
+	}
+	WFD_MSG_DBG("Exiting the thread\n");
+	return rc;
 }
 
 int wfd_vidbuf_start_streaming(struct vb2_queue *q)
@@ -152,11 +343,25 @@
 		(struct wfd_device *)video_drvdata(priv_data);
 	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
 	int rc = 0;
+
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			ENCODE_START, (void *)inst->venc_inst);
+	if (rc) {
+		WFD_MSG_ERR("Failed to start encoder\n");
+		goto err;
+	}
+
+	inst->mdp_task = kthread_run(mdp_output_thread, priv_data,
+				"mdp_output_thread");
+	if (IS_ERR(inst->mdp_task)) {
+		rc = PTR_ERR(inst->mdp_task);
+		goto err;
+	}
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 			 MDP_START, (void *)inst->mdp_inst);
 	if (rc)
 		WFD_MSG_ERR("Failed to start MDP\n");
-
+err:
 	return rc;
 }
 
@@ -172,6 +377,12 @@
 	if (rc)
 		WFD_MSG_ERR("Failed to stop MDP\n");
 
+	kthread_stop(inst->mdp_task);
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			ENCODE_STOP, (void *)inst->venc_inst);
+	if (rc)
+		WFD_MSG_ERR("Failed to stop encoder\n");
+
 	return rc;
 }
 
@@ -183,18 +394,17 @@
 	struct wfd_device *wfd_dev =
 		(struct wfd_device *)video_drvdata(priv_data);
 	struct wfd_inst *inst = (struct wfd_inst *)priv_data->private_data;
-	struct mdp_buf_info buf = {
-					inst->mdp_inst,
-					vb,
-					inst->minfo[vb->v4l2_buf.index]->fd,
-					inst->minfo[vb->v4l2_buf.index]->offset
-					};
-
-	WFD_MSG_DBG("Inside wfd_vidbuf_queue\n");
-	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
-			MDP_Q_BUFFER, (void *)&buf);
-	if (rc)
-		WFD_MSG_ERR("Failed to call fill this buffer\n");
+	struct mem_region mregion;
+	struct mem_info *minfo = vb2_plane_cookie(vb, 0);
+	mregion.fd = minfo->fd;
+	mregion.offset = minfo->offset;
+	mregion.cookie = (u32)vb;
+	mregion.size =  inst->out_buf_size;
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			FILL_OUTPUT_BUFFER, (void *)&mregion);
+	if (rc) {
+		WFD_MSG_ERR("Failed to fill output buffer\n");
+	}
 }
 
 static struct vb2_ops wfd_vidbuf_ops = {
@@ -212,16 +422,27 @@
 	.stop_streaming = wfd_vidbuf_stop_streaming,
 
 	.buf_queue = wfd_vidbuf_buf_queue,
-
 };
 
 static const struct v4l2_subdev_core_ops mdp_subdev_core_ops = {
 	.init = mdp_init,
 	.ioctl = mdp_ioctl,
 };
+
 static const struct v4l2_subdev_ops mdp_subdev_ops = {
 	.core = &mdp_subdev_core_ops,
 };
+
+static const struct v4l2_subdev_core_ops enc_subdev_core_ops = {
+	.init = venc_init,
+	.load_fw = venc_load_fw,
+	.ioctl = venc_ioctl,
+};
+
+static const struct v4l2_subdev_ops enc_subdev_ops = {
+	.core = &enc_subdev_core_ops,
+}
+;
 static int wfdioc_querycap(struct file *filp, void *fh,
 		struct v4l2_capability *cap) {
 	WFD_MSG_DBG("wfdioc_querycap: E\n");
@@ -250,12 +471,7 @@
 	fmt->fmt.pix.width = inst->width;
 	fmt->fmt.pix.height = inst->height;
 	fmt->fmt.pix.pixelformat = inst->pixelformat;
-	fmt->fmt.pix.sizeimage = inst->width * inst->height * 2;
-	fmt->fmt.pix.bytesperline = inst->width * 2; /*TODO: Needs
-							discussion */
-	fmt->fmt.pix.field = V4L2_FIELD_NONE;
-	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; /*TODO: Needs
-							discussion*/
+	fmt->fmt.pix.sizeimage = inst->out_buf_size;
 	fmt->fmt.pix.priv = 0;
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 	return 0;
@@ -268,126 +484,124 @@
 	struct wfd_device *wfd_dev = video_drvdata(filp);
 	struct mdp_prop prop;
 	unsigned long flags;
+	struct bufreq breq;
 	if (!fmt) {
 		WFD_MSG_ERR("Invalid argument\n");
 		return -EINVAL;
 	}
-
 	if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
-		fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_RGB565) {
+		fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_NV12) {
 		WFD_MSG_ERR("Only V4L2_BUF_TYPE_VIDEO_CAPTURE and "
-				"V4L2_PIX_FMT_RGB565 are supported\n");
+				"V4L2_PIX_FMT_NV12 are supported\n");
 		return -EINVAL;
 	}
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, SET_FORMAT,
+				(void *)fmt);
+	if (rc) {
+		WFD_MSG_ERR("Failed to set format on encoder, rc = %d\n", rc);
+		goto err;
+	}
+	breq.count = VENC_INPUT_BUFFERS;
+	breq.height = fmt->fmt.pix.height;
+	breq.width = fmt->fmt.pix.width;
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			SET_BUFFER_REQ, (void *)&breq);
+	if (rc) {
+		WFD_MSG_ERR("Failed to set buffer reqs on encoder\n");
+		goto err;
+	}
 	spin_lock_irqsave(&inst->inst_lock, flags);
+	inst->input_buf_size = breq.size;
+	inst->out_buf_size = fmt->fmt.pix.sizeimage;
 	prop.height = inst->height = fmt->fmt.pix.height;
 	prop.width = inst->width = fmt->fmt.pix.width;
 	prop.inst = inst->mdp_inst;
-	fmt->fmt.pix.sizeimage = inst->height * inst->width * 2;
-	fmt->fmt.pix.field = V4L2_FIELD_NONE;
-	fmt->fmt.pix.bytesperline = inst->width * 2; /*TODO: Needs
-							 discussion */
-	fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; /*TODO: Needs
-						      discussion*/
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_SET_PROP,
 				(void *)&prop);
 	if (rc)
 		WFD_MSG_ERR("Failed to set height/width property on mdp\n");
+err:
 	return rc;
 }
 static int wfdioc_reqbufs(struct file *filp, void *fh,
 		struct v4l2_requestbuffers *b)
 {
-	int rc = 0;
 	struct wfd_inst *inst = filp->private_data;
+	struct wfd_device *wfd_dev = video_drvdata(filp);
 	unsigned long flags;
-	int i;
+	int rc = 0;
+
 	if (b->type != V4L2_CAP_VIDEO_CAPTURE ||
 		b->memory != V4L2_MEMORY_USERPTR) {
 		WFD_MSG_ERR("Only V4L2_CAP_VIDEO_CAPTURE and "
-		"V4L2_CAP_VIDEO_CAPTURE are supported\n");
+		"V4L2_MEMORY_USERPTR are supported\n");
 		return -EINVAL;
 	}
-	if (b->count < MIN_BUF_COUNT)
-		b->count = MIN_BUF_COUNT;
-	spin_lock_irqsave(&inst->inst_lock, flags);
-	if (inst->minfo) {
-		for (i = 0; i < inst->buf_count; ++i)
-			kfree(inst->minfo[i]);
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+			GET_BUFFER_REQ, (void *)b);
+	if (rc) {
+		WFD_MSG_ERR("Failed to get buf reqs from encoder\n");
+		goto err;
 	}
-	kfree(inst->minfo);
+	spin_lock_irqsave(&inst->inst_lock, flags);
 	inst->buf_count = b->count;
-	inst->minfo = kzalloc(sizeof(struct mem_info *) * inst->buf_count,
-						GFP_KERNEL);
-	for (i = 0; i < inst->buf_count; ++i)
-		inst->minfo[i] = kzalloc(sizeof(struct mem_info), GFP_KERNEL);
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
 	rc = vb2_reqbufs(&inst->vid_bufq, b);
-	if (rc) {
-		WFD_MSG_ERR("Failed in videobuf_reqbufs, rc = %d\n", rc);
-		spin_lock_irqsave(&inst->inst_lock, flags);
-		if (inst->minfo) {
-			for (i = 0; i < inst->buf_count; ++i)
-				kfree(inst->minfo[i]);
-		}
-		kfree(inst->minfo);
-		inst->minfo = NULL;
-		spin_unlock_irqrestore(&inst->inst_lock, flags);
-	}
+err:
 	return rc;
 }
+static int wfd_register_out_buf(struct wfd_inst *inst,
+		struct v4l2_buffer *b)
+{
+	struct mem_info_entry *minfo_entry;
+	struct mem_info *minfo;
+	unsigned long flags;
+	if (!b || !inst || !b->reserved) {
+		WFD_MSG_ERR("Invalid arguments\n");
+		return -EINVAL;
+	}
+	minfo = wfd_get_mem_info(inst, b->m.userptr);
+	if (!minfo) {
+		minfo_entry = kzalloc(sizeof(struct mem_info_entry),
+				GFP_KERNEL);
+		if (copy_from_user(&minfo_entry->minfo, (void *)b->reserved,
+					sizeof(struct mem_info))) {
+			WFD_MSG_ERR(" copy_from_user failed. Populate"
+					" v4l2_buffer->reserved with meminfo\n");
+			return -EINVAL;
+		}
+		minfo_entry->userptr = b->m.userptr;
+		spin_lock_irqsave(&inst->inst_lock, flags);
+		list_add_tail(&minfo_entry->list, &inst->minfo_list);
+		spin_unlock_irqrestore(&inst->inst_lock, flags);
+	} else
+		WFD_MSG_INFO("Buffer already registered\n");
+
+	return 0;
+}
 static int wfdioc_qbuf(struct file *filp, void *fh,
 		struct v4l2_buffer *b)
 {
 	int rc = 0;
 	struct wfd_inst *inst = filp->private_data;
-
-	if (!inst || !b || !b->reserved ||
+	if (!inst || !b ||
 			(b->index < 0 || b->index >= inst->buf_count)) {
 		WFD_MSG_ERR("Invalid input parameters to QBUF IOCTL\n");
 		return -EINVAL;
 	}
-	if (!inst->vid_bufq.streaming) {
-		if (copy_from_user(inst->minfo[b->index], (void *)b->reserved,
-				sizeof(struct mem_info))) {
-			WFD_MSG_ERR(" copy_from_user failed. Populate"
-						" v4l2_buffer->reserved with meminfo\n");
-			return -EINVAL;
-		}
+	rc = wfd_register_out_buf(inst, b);
+	if (rc) {
+		WFD_MSG_ERR("Failed to register buffer\n");
+		goto err;
 	}
 	rc = vb2_qbuf(&inst->vid_bufq, b);
 	if (rc)
 		WFD_MSG_ERR("Failed to queue buffer\n");
+err:
 	return rc;
 }
-static int mdp_output_thread(void *data)
-{
-	int rc = 0;
-	struct file *filp = (struct file *)data;
-	struct wfd_inst *inst = filp->private_data;
-	struct wfd_device *wfd_dev =
-		(struct wfd_device *)video_drvdata(filp);
-	struct vb2_buffer *vbuf = NULL;
-	struct mdp_buf_info obuf = {inst->mdp_inst, vbuf, 0, 0};
-	while (!kthread_should_stop()) {
-		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev,
-			core, ioctl, MDP_DQ_BUFFER, (void *)&obuf);
 
-		if (rc) {
-			WFD_MSG_ERR("Either streamoff called or"
-						" MDP REPORTED ERROR\n");
-			break;
-		} else
-			WFD_MSG_DBG("Dequeued buffer successfully\n");
-
-		vbuf = obuf.b;
-		vb2_buffer_done(vbuf,
-			rc ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
-	}
-	WFD_MSG_DBG("Exiting the thread\n");
-	return rc;
-}
 static int wfdioc_streamon(struct file *filp, void *fh,
 		enum v4l2_buf_type i)
 {
@@ -403,22 +617,16 @@
 	spin_lock_irqsave(&inst->inst_lock, flags);
 	inst->streamoff = false;
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
-	/*TODO: Do we need to lock the instance here*/
+
 	rc = vb2_streamon(&inst->vid_bufq, i);
 	if (rc) {
 		WFD_MSG_ERR("videobuf_streamon failed with err = %d\n", rc);
 		goto vidbuf_streamon_failed;
 	}
-	inst->mdp_task = kthread_run(mdp_output_thread, filp,
-				"mdp_output_thread");
-	if (IS_ERR(inst->mdp_task)) {
-		rc = PTR_ERR(inst->mdp_task);
-		goto mdp_task_failed;
-	}
 	return rc;
-mdp_task_failed:
-	vb2_streamoff(&inst->vid_bufq, i);
+
 vidbuf_streamon_failed:
+	vb2_streamoff(&inst->vid_bufq, i);
 	return rc;
 }
 static int wfdioc_streamoff(struct file *filp, void *fh,
@@ -441,8 +649,6 @@
 	}
 	WFD_MSG_DBG("Calling videobuf_streamoff\n");
 	vb2_streamoff(&inst->vid_bufq, i);
-	vb2_queue_release(&inst->vid_bufq);
-	kthread_stop(inst->mdp_task);
 	return 0;
 }
 static int wfdioc_dqbuf(struct file *filp, void *fh,
@@ -452,6 +658,28 @@
 	WFD_MSG_INFO("Waiting to dequeue buffer\n");
 	return vb2_dqbuf(&inst->vid_bufq, b, 0);
 }
+static int wfdioc_g_ctrl(struct file *filp, void *fh,
+					struct v4l2_control *a)
+{
+	int rc = 0;
+	struct wfd_device *wfd_dev = video_drvdata(filp);
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+			ioctl, GET_PROP, a);
+	if (rc)
+		WFD_MSG_ERR("Failed to get encoder property\n");
+	return rc;
+}
+static int wfdioc_s_ctrl(struct file *filp, void *fh,
+					struct v4l2_control *a)
+{
+	int rc = 0;
+	struct wfd_device *wfd_dev = video_drvdata(filp);
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core,
+			ioctl, SET_PROP, a);
+	if (rc)
+		WFD_MSG_ERR("Failed to set encoder property\n");
+	return rc;
+}
 static const struct v4l2_ioctl_ops g_wfd_ioctl_ops = {
 	.vidioc_querycap = wfdioc_querycap,
 	.vidioc_s_fmt_vid_cap = wfdioc_s_fmt,
@@ -461,36 +689,106 @@
 	.vidioc_streamon = wfdioc_streamon,
 	.vidioc_streamoff = wfdioc_streamoff,
 	.vidioc_dqbuf = wfdioc_dqbuf,
+	.vidioc_g_ctrl = wfdioc_g_ctrl,
+	.vidioc_s_ctrl = wfdioc_s_ctrl,
+
 };
-static int wfd_set_default_properties(struct wfd_inst *inst)
+static int wfd_set_default_properties(struct file *filp)
 {
 	unsigned long flags;
+	struct v4l2_format fmt;
+	struct wfd_inst *inst = filp->private_data;
 	if (!inst) {
 		WFD_MSG_ERR("Invalid argument\n");
 		return -EINVAL;
 	}
 	spin_lock_irqsave(&inst->inst_lock, flags);
-	inst->height = DEFAULT_WFD_HEIGHT;
-	inst->width = DEFAULT_WFD_WIDTH;
-	inst->pixelformat = V4L2_PIX_FMT_RGB565;
+	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	fmt.fmt.pix.height = inst->height = DEFAULT_WFD_HEIGHT;
+	fmt.fmt.pix.width = inst->width = DEFAULT_WFD_WIDTH;
+	fmt.fmt.pix.pixelformat = inst->pixelformat
+			= V4L2_PIX_FMT_NV12;
 	spin_unlock_irqrestore(&inst->inst_lock, flags);
+	wfdioc_s_fmt(filp, filp->private_data, &fmt);
 	return 0;
 }
+void venc_op_buffer_done(void *cookie, u32 status,
+			struct vb2_buffer *buf)
+{
+	WFD_MSG_DBG("yay!! got callback\n");
+	vb2_buffer_done(buf, VB2_BUF_STATE_DONE);
+}
+void venc_ip_buffer_done(void *cookie, u32 status,
+			struct mem_region *mregion)
+{
+	struct file *filp = cookie;
+	struct wfd_inst *inst = filp->private_data;
+	struct mdp_buf_info buf = {0};
+	struct wfd_device *wfd_dev =
+		(struct wfd_device *)video_drvdata(filp);
+	int rc = 0;
+	WFD_MSG_DBG("yay!! got ip callback\n");
+	buf.inst = inst->mdp_inst;
+	buf.cookie = mregion;
+	buf.kvaddr = (u32) mregion->kvaddr;
+	buf.paddr = (u32) mregion->paddr;
+	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core,
+			ioctl, MDP_Q_BUFFER, (void *)&buf);
+	if (rc)
+		WFD_MSG_ERR("Failed to Q buffer to mdp\n");
+
+}
+void *wfd_vb2_mem_ops_get_userptr(void *alloc_ctx, unsigned long vaddr,
+					unsigned long size, int write)
+{
+	return wfd_get_mem_info(alloc_ctx, vaddr);
+}
+
+void wfd_vb2_mem_ops_put_userptr(void *buf_priv)
+{
+	/*TODO: Free the list*/
+}
+
+void *wfd_vb2_mem_ops_cookie(void *buf_priv)
+{
+	return buf_priv;
+}
+
+
+static struct vb2_mem_ops wfd_vb2_mem_ops = {
+	.get_userptr = wfd_vb2_mem_ops_get_userptr,
+	.put_userptr = wfd_vb2_mem_ops_put_userptr,
+	.cookie = wfd_vb2_mem_ops_cookie,
+};
+
+int wfd_initialize_vb2_queue(struct vb2_queue *q, void *priv)
+{
+	q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	q->io_modes = VB2_USERPTR;
+	q->ops = &wfd_vidbuf_ops;
+	q->mem_ops = &wfd_vb2_mem_ops;
+	q->drv_priv = priv;
+	return vb2_queue_init(q);
+}
+
 static int wfd_open(struct file *filp)
 {
 	int rc = 0;
 	struct wfd_inst *inst;
 	struct wfd_device *wfd_dev;
+	struct venc_msg_ops vmops;
 	WFD_MSG_DBG("wfd_open: E\n");
+	wfd_dev = video_drvdata(filp);
 	inst = kzalloc(sizeof(struct wfd_inst), GFP_KERNEL);
-	if (!inst) {
+	if (!inst || !wfd_dev) {
 		WFD_MSG_ERR("Could not allocate memory for "
 			"wfd instance\n");
 		return -ENOMEM;
 	}
+	filp->private_data = inst;
 	spin_lock_init(&inst->inst_lock);
-	spin_lock_init(&inst->buflock);
-	wfd_dev = video_drvdata(filp);
+	INIT_LIST_HEAD(&inst->input_mem_list);
+	INIT_LIST_HEAD(&inst->minfo_list);
 	rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl, MDP_OPEN,
 				(void *)&inst->mdp_inst);
 	if (rc) {
@@ -498,43 +796,55 @@
 		goto err_mdp_open;
 	}
 
-	videobuf2_queue_pmem_contig_init(&inst->vid_bufq,
-				V4L2_BUF_TYPE_VIDEO_CAPTURE,
-				&wfd_vidbuf_ops,
-				sizeof(struct wfd_vid_buffer),
-				filp);  /*TODO: Check if it needs to be freed*/
-	wfd_set_default_properties(inst);
-	filp->private_data = inst;
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, load_fw);
+	if (rc) {
+		WFD_MSG_ERR("Failed to load video encoder firmware: %d\n", rc);
+		goto err_venc;
+	}
+	vmops.op_buffer_done = venc_op_buffer_done;
+	vmops.ip_buffer_done = venc_ip_buffer_done;
+	vmops.cbdata = filp;
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl, OPEN,
+				(void *)&vmops);
+	if (rc || !vmops.cookie) {
+		WFD_MSG_ERR("Failed to open encoder subdevice: %d\n", rc);
+		goto err_venc;
+	}
+	inst->venc_inst = vmops.cookie;
+
+	wfd_initialize_vb2_queue(&inst->vid_bufq, filp);
+	wfd_set_default_properties(filp);
 	WFD_MSG_DBG("wfd_open: X\n");
 	return rc;
+err_venc:
+	v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
+				MDP_CLOSE, (void *)inst->mdp_inst);
 err_mdp_open:
 	kfree(inst);
 	return rc;
 }
+
 static int wfd_close(struct file *filp)
 {
 	struct wfd_inst *inst;
 	struct wfd_device *wfd_dev;
 	int rc = 0;
-	int k;
-	unsigned long flags;
 	wfd_dev = video_drvdata(filp);
 	WFD_MSG_DBG("wfd_close: E\n");
 	inst = filp->private_data;
 	if (inst) {
 		wfdioc_streamoff(filp, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+		vb2_queue_release(&inst->vid_bufq);
 		rc = v4l2_subdev_call(&wfd_dev->mdp_sdev, core, ioctl,
 				MDP_CLOSE, (void *)inst->mdp_inst);
 		if (rc)
 			WFD_MSG_ERR("Failed to CLOSE mdp subdevice: %d\n", rc);
-		spin_lock_irqsave(&inst->inst_lock, flags);
-		if (inst->minfo) {
-			for (k = 0; k < inst->buf_count; ++k)
-				kfree(inst->minfo[k]);
-		}
-		kfree(inst->minfo);
-		inst->minfo = NULL;
-		spin_unlock_irqrestore(&inst->inst_lock, flags);
+
+		rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, ioctl,
+				CLOSE, (void *)inst->venc_inst);
+		if (rc)
+			WFD_MSG_ERR("Failed to CLOSE enc subdev: %d\n", rc);
+
 		kfree(inst);
 	}
 	WFD_MSG_DBG("wfd_close: X\n");
@@ -555,7 +865,7 @@
 	int rc = 0;
 	struct wfd_device *wfd_dev;
 	WFD_MSG_DBG("__wfd_probe: E\n");
-	wfd_dev = kzalloc(sizeof(*wfd_dev), GFP_KERNEL);  /*TODO: Free it*/
+	wfd_dev = kzalloc(sizeof(*wfd_dev), GFP_KERNEL);
 	if (!wfd_dev) {
 		WFD_MSG_ERR("Could not allocate memory for "
 				"wfd device\n");
@@ -592,8 +902,28 @@
 		WFD_MSG_ERR("Failed to register mdp subdevice: %d\n", rc);
 		goto err_mdp_register_subdev;
 	}
+
+	v4l2_subdev_init(&wfd_dev->enc_sdev, &enc_subdev_ops);
+	strncpy(wfd_dev->enc_sdev.name, "wfd-venc", V4L2_SUBDEV_NAME_SIZE);
+	rc = v4l2_device_register_subdev(&wfd_dev->v4l2_dev,
+						&wfd_dev->enc_sdev);
+	if (rc) {
+		WFD_MSG_ERR("Failed to register encoder subdevice: %d\n", rc);
+		goto err_venc_register_subdev;
+	}
+	rc = v4l2_subdev_call(&wfd_dev->enc_sdev, core, init, 0);
+	if (rc) {
+		WFD_MSG_ERR("Failed to initiate encoder device %d\n", rc);
+		goto err_venc_init;
+	}
+
 	WFD_MSG_DBG("__wfd_probe: X\n");
 	return rc;
+
+err_venc_init:
+	v4l2_device_unregister_subdev(&wfd_dev->enc_sdev);
+err_venc_register_subdev:
+	v4l2_device_unregister_subdev(&wfd_dev->mdp_sdev);
 err_mdp_register_subdev:
 	video_unregister_device(wfd_dev->pvdev);
 err_video_register_device:
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index fa7e3fd..37b935b 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-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.
  *
  * Based on videobuf-dma-contig.c,
  * (c) 2008 Magnus Damm
@@ -45,17 +45,51 @@
 #define D(fmt, args...) do {} while (0)
 #endif
 
-static int32_t msm_mem_allocate(const size_t size)
+static int32_t msm_mem_allocate(struct videobuf2_contig_pmem *mem)
 {
 	int32_t phyaddr;
-	phyaddr = allocate_contiguous_ebi_nomap(size, SZ_4K);
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	int rc, len;
+	mem->client = msm_ion_client_create(-1, "camera");
+	if (IS_ERR((void *)mem->client)) {
+		pr_err("%s Could not create client\n", __func__);
+		goto client_failed;
+	}
+	mem->ion_handle = ion_alloc(mem->client, mem->size, SZ_4K,
+		(0x1 << ION_CP_MM_HEAP_ID | 0x1 << ION_IOMMU_HEAP_ID));
+	if (IS_ERR((void *)mem->ion_handle)) {
+		pr_err("%s Could not allocate\n", __func__);
+		goto alloc_failed;
+	}
+	rc = ion_phys(mem->client, mem->ion_handle, (ion_phys_addr_t *)&phyaddr,
+		 (size_t *)&len);
+	if (rc < 0) {
+		pr_err("%s Could not get physical address\n", __func__);
+		goto phys_failed;
+	}
+#else
+	phyaddr = allocate_contiguous_ebi_nomap(mem->size, SZ_4K);
+#endif
 	return phyaddr;
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+phys_failed:
+	ion_free(mem->client, mem->ion_handle);
+alloc_failed:
+	ion_client_destroy(mem->client);
+client_failed:
+	return 0;
+#endif
 }
 
-static int32_t msm_mem_free(const int32_t phyaddr)
+static int32_t msm_mem_free(struct videobuf2_contig_pmem *mem)
 {
 	int32_t rc = 0;
-	free_contiguous_memory_by_paddr(phyaddr);
+#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
+	ion_free(mem->client, mem->ion_handle);
+	ion_client_destroy(mem->client);
+#else
+	free_contiguous_memory_by_paddr(mem->phyaddr);
+#endif
 	return rc;
 }
 
@@ -92,7 +126,7 @@
 	mem->size =  PAGE_ALIGN(size);
 	mem->alloc_ctx = alloc_ctx;
 	mem->is_userptr = 0;
-	mem->phyaddr = msm_mem_allocate(mem->size);
+	mem->phyaddr = msm_mem_allocate(mem);
 	if (!mem->phyaddr) {
 		pr_err("%s : pmem memory allocation failed\n", __func__);
 		kfree(mem);
@@ -105,7 +139,7 @@
 	if (IS_ERR((void *)mem->msm_buffer)) {
 		pr_err("%s: msm_subsystem_map_buffer failed\n", __func__);
 		rc = PTR_ERR((void *)mem->msm_buffer);
-		msm_mem_free(mem->phyaddr);
+		msm_mem_free(mem);
 		kfree(mem);
 		return ERR_PTR(-ENOMEM);
 	}
@@ -119,7 +153,7 @@
 		D("%s Freeing memory ", __func__);
 		if (msm_subsystem_unmap_buffer(mem->msm_buffer) < 0)
 			D("%s unmapped memory\n", __func__);
-		msm_mem_free(mem->phyaddr);
+		msm_mem_free(mem);
 	}
 	kfree(mem);
 }
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index f65a183..523d3b6 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.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
@@ -141,16 +141,16 @@
  * T = Pre-divide * 2^m, where m = 0..7 (exponent)
  *
  * This is the formula to figure out m for the best pre-divide and clock:
- * (PWM Period / N) / 2^m = (Pre-divide * Clock Period)
+ * (PWM Period / N) = (Pre-divide * Clock Period) * 2^m
  */
 #define NUM_CLOCKS	3
 
-#define NSEC_1000HZ	(NSEC_PER_SEC / 1000)
+#define NSEC_1024HZ	(NSEC_PER_SEC / 1024)
 #define NSEC_32768HZ	(NSEC_PER_SEC / 32768)
 #define NSEC_19P2MHZ	(NSEC_PER_SEC / 19200000)
 
 #define CLK_PERIOD_MIN	NSEC_19P2MHZ
-#define CLK_PERIOD_MAX	NSEC_1000HZ
+#define CLK_PERIOD_MAX	NSEC_1024HZ
 
 #define NUM_LPG_PRE_DIVIDE	3  /* No default support for pre-divide = 6 */
 #define NUM_PWM_PRE_DIVIDE	2
@@ -163,23 +163,20 @@
 #define PRE_DIVIDE_MAX		PRE_DIVIDE_2
 
 static unsigned int pt_t[NUM_LPG_PRE_DIVIDE][NUM_CLOCKS] = {
-	{	PRE_DIVIDE_0 * NSEC_1000HZ,
+	{	PRE_DIVIDE_0 * NSEC_1024HZ,
 		PRE_DIVIDE_0 * NSEC_32768HZ,
 		PRE_DIVIDE_0 * NSEC_19P2MHZ,
 	},
-	{	PRE_DIVIDE_1 * NSEC_1000HZ,
+	{	PRE_DIVIDE_1 * NSEC_1024HZ,
 		PRE_DIVIDE_1 * NSEC_32768HZ,
 		PRE_DIVIDE_1 * NSEC_19P2MHZ,
 	},
-	{	PRE_DIVIDE_2 * NSEC_1000HZ,
+	{	PRE_DIVIDE_2 * NSEC_1024HZ,
 		PRE_DIVIDE_2 * NSEC_32768HZ,
 		PRE_DIVIDE_2 * NSEC_19P2MHZ,
 	},
 };
 
-#define MIN_MPT	((PRE_DIVIDE_MIN * CLK_PERIOD_MIN) << PM8XXX_PWM_M_MIN)
-#define MAX_MPT	((PRE_DIVIDE_MAX * CLK_PERIOD_MAX) << PM8XXX_PWM_M_MAX)
-
 /* Private data */
 struct pm8xxx_pwm_chip;
 
@@ -338,67 +335,46 @@
 {
 	int	n, m, clk, div;
 	int	best_m, best_div, best_clk;
-	int	last_err, cur_err, better_err, better_m;
-	unsigned int	tmp_p, last_p, min_err, period_n;
+	unsigned int	last_err, cur_err, min_err;
+	unsigned int	tmp_p, period_n;
 
 	/* PWM Period / N */
-	if (period_us < (40 * USEC_PER_SEC)) {  /* ~6-bit max */
+	if (period_us < ((unsigned)(-1) / NSEC_PER_USEC)) {
 		period_n = (period_us * NSEC_PER_USEC) >> 6;
 		n = 6;
-	} else if (period_us < (274 * USEC_PER_SEC)) { /* overflow threshold */
-		period_n = (period_us >> 6) * NSEC_PER_USEC;
-		if (period_n >= MAX_MPT) {
-			n = 9;
-			period_n >>= 3;
-		} else {
-			n = 6;
-		}
 	} else {
 		period_n = (period_us >> 9) * NSEC_PER_USEC;
 		n = 9;
 	}
 
-	min_err = MAX_MPT;
+	min_err = last_err = (unsigned)(-1);
 	best_m = 0;
 	best_clk = 0;
 	best_div = 0;
 	for (clk = 0; clk < NUM_CLOCKS; clk++) {
 		for (div = 0; div < pwm_chip->pwm_total_pre_divs; div++) {
-			tmp_p = period_n;
-			last_p = tmp_p;
+			/* period_n = (PWM Period / N) */
+			/* tmp_p = (Pre-divide * Clock Period) * 2^m */
+			tmp_p = pt_t[div][clk];
 			for (m = 0; m <= PM8XXX_PWM_M_MAX; m++) {
-				if (tmp_p <= pt_t[div][clk]) {
-					/* Found local best */
-					if (!m) {
-						better_err = pt_t[div][clk] -
-							tmp_p;
-						better_m = m;
-					} else {
-						last_err = last_p -
-							pt_t[div][clk];
-						cur_err = pt_t[div][clk] -
-							tmp_p;
+				if (period_n > tmp_p)
+					cur_err = period_n - tmp_p;
+				else
+					cur_err = tmp_p - period_n;
 
-						if (cur_err < last_err) {
-							better_err = cur_err;
-							better_m = m;
-						} else {
-							better_err = last_err;
-							better_m = m - 1;
-						}
-					}
-
-					if (better_err < min_err) {
-						min_err = better_err;
-						best_m = better_m;
-						best_clk = clk;
-						best_div = div;
-					}
-					break;
-				} else {
-					last_p = tmp_p;
-					tmp_p >>= 1;
+				if (cur_err < min_err) {
+					min_err = cur_err;
+					best_m = m;
+					best_clk = clk;
+					best_div = div;
 				}
+
+				if (m && cur_err > last_err)
+					/* Break for bigger cur_err */
+					break;
+
+				last_err = cur_err;
+				tmp_p <<= 1;
 			}
 		}
 	}
diff --git a/drivers/misc/tzcom.c b/drivers/misc/tzcom.c
index ba03064..e662f43 100644
--- a/drivers/misc/tzcom.c
+++ b/drivers/misc/tzcom.c
@@ -1,6 +1,6 @@
 /* Qualcomm TrustZone communicator driver
  *
- * 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
@@ -28,6 +28,7 @@
 #include <linux/mutex.h>
 #include <linux/android_pmem.h>
 #include <linux/io.h>
+#include <linux/ion.h>
 #include <mach/scm.h>
 #include <mach/peripheral-loader.h>
 #include <linux/tzcom.h>
@@ -53,7 +54,7 @@
 static struct class *driver_class;
 static dev_t tzcom_device_no;
 static struct cdev tzcom_cdev;
-
+struct ion_client *ion_clnt;
 static u8 *sb_in_virt;
 static s32 sb_in_phys;
 static size_t sb_in_length = 20 * SZ_1K;
@@ -280,13 +281,13 @@
  *      _________________________________________________________
  *                              OUTPUT SHARED BUFFER
  */
-static int tzcom_send_cmd(struct tzcom_data_t *data, void __user *argp)
+static int __tzcom_send_cmd(struct tzcom_data_t *data,
+			struct tzcom_send_cmd_op_req *req)
 {
 	int ret = 0;
 	unsigned long flags;
 	u32 reqd_len_sb_in = 0;
 	u32 reqd_len_sb_out = 0;
-	struct tzcom_send_cmd_op_req req;
 	struct tzcom_command cmd;
 	struct tzcom_response resp;
 	struct tzcom_callback *next_callback;
@@ -296,30 +297,24 @@
 	size_t new_entry_len = 0;
 	struct tzcom_registered_svc_list *ptr_svc;
 
-	ret = copy_from_user(&req, argp, sizeof(req));
-	if (ret) {
-		PERR("copy_from_user failed");
-		return ret;
-	}
-
-	if (req.cmd_buf == NULL || req.resp_buf == NULL) {
+	if (req->cmd_buf == NULL || req->resp_buf == NULL) {
 		PERR("cmd buffer or response buffer is null");
 		return -EINVAL;
 	}
 
-	if (req.cmd_len <= 0 || req.resp_len <= 0 ||
-		req.cmd_len > sb_in_length || req.resp_len > sb_in_length) {
+	if (req->cmd_len <= 0 || req->resp_len <= 0 ||
+		req->cmd_len > sb_in_length || req->resp_len > sb_in_length) {
 		PERR("cmd buffer length or "
 				"response buffer length not valid");
 		return -EINVAL;
 	}
 	PDEBUG("received cmd_req.req: 0x%p",
-				req.cmd_buf);
+				req->cmd_buf);
 	PDEBUG("received cmd_req.rsp size: %u, ptr: 0x%p",
-			req.resp_len,
-			req.resp_buf);
+			req->resp_len,
+			req->resp_buf);
 
-	reqd_len_sb_in = req.cmd_len + req.resp_len;
+	reqd_len_sb_in = req->cmd_len + req->resp_len;
 	if (reqd_len_sb_in > sb_in_length) {
 		PDEBUG("Not enough memory to fit cmd_buf and "
 				"resp_buf. Required: %u, Available: %u",
@@ -327,23 +322,25 @@
 		return -ENOMEM;
 	}
 
-	/* Copy req.cmd_buf to SB in and set req.resp_buf to SB in + cmd_len */
+	/* Copy req->cmd_buf to SB in and set
+	 * req->resp_buf to SB in + cmd_len
+	 */
 	mutex_lock(&sb_in_lock);
 	PDEBUG("Before memcpy on sb_in");
-	memcpy(sb_in_virt, req.cmd_buf, req.cmd_len);
+	memcpy(sb_in_virt, req->cmd_buf, req->cmd_len);
 	PDEBUG("After memcpy on sb_in");
 
 	/* cmd_type will always be a new here */
 	cmd.cmd_type = TZ_SCHED_CMD_NEW;
 	cmd.sb_in_cmd_addr = (u8 *) tzcom_virt_to_phys(sb_in_virt);
-	cmd.sb_in_cmd_len = req.cmd_len;
+	cmd.sb_in_cmd_len = req->cmd_len;
 
 	resp.cmd_status = TZ_SCHED_STATUS_INCOMPLETE;
 	resp.sb_in_rsp_addr = (u8 *) tzcom_virt_to_phys(sb_in_virt +
-			req.cmd_len);
-	resp.sb_in_rsp_len = req.resp_len;
+			req->cmd_len);
+	resp.sb_in_rsp_len = req->resp_len;
 
-	PDEBUG("before call tzcom_scm_call, cmd_id = : %u", req.cmd_id);
+	PDEBUG("before call tzcom_scm_call, cmd_id = : %u", req->cmd_id);
 	PDEBUG("before call tzcom_scm_call, sizeof(cmd) = : %u", sizeof(cmd));
 
 	ret = tzcom_scm_call((const void *) &cmd, sizeof(cmd),
@@ -442,13 +439,31 @@
 
 	mutex_lock(&sb_in_lock);
 	resp.sb_in_rsp_addr = sb_in_virt + cmd.sb_in_cmd_len;
-	resp.sb_in_rsp_len = req.resp_len;
-	memcpy(req.resp_buf, resp.sb_in_rsp_addr, resp.sb_in_rsp_len);
+	resp.sb_in_rsp_len = req->resp_len;
+	memcpy(req->resp_buf, resp.sb_in_rsp_addr, resp.sb_in_rsp_len);
 	/* Zero out memory for security purpose */
 	memset(sb_in_virt, 0, reqd_len_sb_in);
 	mutex_unlock(&sb_in_lock);
 
-	PDEBUG("sending cmd_req.rsp "
+	return ret;
+}
+
+
+static int tzcom_send_cmd(struct tzcom_data_t *data, void __user *argp)
+{
+	int ret = 0;
+	struct tzcom_send_cmd_op_req req;
+
+	ret = copy_from_user(&req, argp, sizeof(req));
+	if (ret) {
+		PERR("copy_from_user failed");
+		return ret;
+	}
+	ret = __tzcom_send_cmd(data, &req);
+	if (ret)
+		return ret;
+
+	PDEBUG("sending cmd_req->rsp "
 			"size: %u, ptr: 0x%p", req.resp_len,
 			req.resp_buf);
 	ret = copy_to_user(argp, &req, sizeof(req));
@@ -456,7 +471,99 @@
 		PDEBUG("copy_to_user failed");
 		return ret;
 	}
+	return ret;
+}
 
+static int __tzcom_send_cmd_req_clean_up(
+			struct tzcom_send_cmd_fd_op_req *req)
+{
+	char *field;
+	uint32_t *update;
+	int ret = 0;
+	int i = 0;
+
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (req->ifd_data[i].fd != 0) {
+			field = (char *)req->cmd_buf +
+					req->ifd_data[i].cmd_buf_offset;
+			update = (uint32_t *) field;
+			*update = 0;
+		}
+	}
+	return ret;
+}
+
+static int __tzcom_update_with_phy_addr(
+			struct tzcom_send_cmd_fd_op_req *req)
+{
+	struct ion_handle *ihandle;
+	char *field;
+	uint32_t *update;
+	ion_phys_addr_t pa;
+	int ret = 0;
+	int i = 0;
+	uint32_t length;
+
+	for (i = 0; i < MAX_ION_FD; i++) {
+		if (req->ifd_data[i].fd != 0) {
+			/* Get the handle of the shared fd */
+			ihandle = ion_import_fd(ion_clnt, req->ifd_data[i].fd);
+			if (ihandle == NULL) {
+				PERR("Ion client can't retrieve the handle\n");
+				return -ENOMEM;
+			}
+			field = (char *) req->cmd_buf +
+						req->ifd_data[i].cmd_buf_offset;
+			update = (uint32_t *) field;
+
+			/* Populate the cmd data structure with the phys_addr */
+			ret = ion_phys(ion_clnt, ihandle, &pa, &length);
+			if (ret)
+				return -ENOMEM;
+
+			*update = (uint32_t)pa;
+			ion_free(ion_clnt, ihandle);
+		}
+	}
+	return ret;
+}
+
+static int tzcom_send_cmd_with_fd(struct tzcom_data_t *data,
+					void __user *argp)
+{
+	int ret = 0;
+	struct tzcom_send_cmd_fd_op_req req;
+	struct tzcom_send_cmd_op_req send_cmd_req;
+
+	ret = copy_from_user(&req, argp, sizeof(req));
+	if (ret) {
+		PERR("copy_from_user failed");
+		return ret;
+	}
+
+	send_cmd_req.cmd_id = req.cmd_id;
+	send_cmd_req.cmd_buf = req.cmd_buf;
+	send_cmd_req.cmd_len = req.cmd_len;
+	send_cmd_req.resp_buf = req.resp_buf;
+	send_cmd_req.resp_len = req.resp_len;
+
+	ret = __tzcom_update_with_phy_addr(&req);
+	if (ret)
+		return ret;
+	ret = __tzcom_send_cmd(data, &send_cmd_req);
+	__tzcom_send_cmd_req_clean_up(&req);
+
+	if (ret)
+		return ret;
+
+	PDEBUG("sending cmd_req->rsp "
+			"size: %u, ptr: 0x%p", req.resp_len,
+			req.resp_buf);
+	ret = copy_to_user(argp, &req, sizeof(req));
+	if (ret) {
+		PDEBUG("copy_to_user failed");
+		return ret;
+	}
 	return ret;
 }
 
@@ -713,6 +820,19 @@
 			PERR("failed tzcom_send_cmd: %d", ret);
 		break;
 	}
+	case TZCOM_IOCTL_SEND_CMD_FD_REQ: {
+		PDEBUG("ioctl send_cmd_req()");
+		/* Only one client allowed here at a time */
+		mutex_lock(&send_cmd_lock);
+		atomic_inc(&tzcom_data->ioctl_count);
+		ret = tzcom_send_cmd_with_fd(tzcom_data, argp);
+		atomic_dec(&tzcom_data->ioctl_count);
+		wake_up_interruptible(&tzcom_data->abort_wq);
+		mutex_unlock(&send_cmd_lock);
+		if (ret)
+			PERR("failed tzcom_send_cmd: %d", ret);
+		break;
+	}
 	case TZCOM_IOCTL_READ_NEXT_CMD_REQ: {
 		PDEBUG("ioctl read_next_cmd_req()");
 		atomic_inc(&tzcom_data->ioctl_count);
@@ -971,7 +1091,7 @@
 	}
 	PDEBUG("sb_out virt address: %p, phys address: 0x%x",
 			sb_out_virt, tzcom_virt_to_phys(sb_out_virt));
-
+	ion_clnt = msm_ion_client_create(0x03, "tzcom");
 	/* Initialized in tzcom_open */
 	pil = NULL;
 
@@ -1012,6 +1132,7 @@
 	device_destroy(driver_class, tzcom_device_no);
 	class_destroy(driver_class);
 	unregister_chrdev_region(tzcom_device_no, 1);
+	ion_client_destroy(ion_clnt);
 }
 
 
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index e853699..57e5696 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2007 Google Inc,
  *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- *  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 as
@@ -477,11 +477,7 @@
 			goto out;
 		}
 		msmsdcc_stop_data(host);
-
-		if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
-				|| !mrq->sbc)) {
-			msmsdcc_start_command(host, mrq->data->stop, 0);
-		} else if (!mrq->data->stop || mrq->cmd->error ||
+		if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
 			host->curr.mrq = NULL;
 			host->curr.cmd = NULL;
@@ -491,6 +487,9 @@
 
 			mmc_request_done(host->mmc, mrq);
 			return;
+		} else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+				|| !mrq->sbc)) {
+			msmsdcc_start_command(host, mrq->data->stop, 0);
 		}
 	}
 
@@ -635,10 +634,7 @@
 			return;
 		}
 		msmsdcc_stop_data(host);
-		if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
-				|| !mrq->sbc)) {
-			msmsdcc_start_command(host, mrq->data->stop, 0);
-		} else if (!mrq->data->stop || mrq->cmd->error ||
+		if (!mrq->data->stop || mrq->cmd->error ||
 			(mrq->sbc && !mrq->data->error)) {
 			host->curr.mrq = NULL;
 			host->curr.cmd = NULL;
@@ -648,6 +644,9 @@
 
 			mmc_request_done(host->mmc, mrq);
 			return;
+		} else if (mrq->data->stop && ((mrq->sbc && mrq->data->error)
+				|| !mrq->sbc)) {
+			msmsdcc_start_command(host, mrq->data->stop, 0);
 		}
 	}
 	spin_unlock_irqrestore(&host->lock, flags);
@@ -944,7 +943,7 @@
 msmsdcc_start_command_deferred(struct msmsdcc_host *host,
 				struct mmc_command *cmd, u32 *c)
 {
-	DBG(host, "op %d arg %08x flags %08x\n",
+	DBG(host, "op %02x arg %08x flags %08x\n",
 	    cmd->opcode, cmd->arg, cmd->flags);
 
 	*c |= (cmd->opcode | MCI_CPSM_ENABLE);
@@ -1393,16 +1392,9 @@
 		else if (host->curr.data) { /* Non DMA */
 			msmsdcc_reset_and_restore(host);
 			msmsdcc_stop_data(host);
-			if (cmd->data && cmd->data->stop)
-				msmsdcc_start_command(host,
-						cmd->data->stop, 0);
-			else
-				msmsdcc_request_end(host, cmd->mrq);
+			msmsdcc_request_end(host, cmd->mrq);
 		} else { /* host->data == NULL */
-			if (cmd->data && cmd->data->stop) {
-				msmsdcc_start_command(host,
-						cmd->data->stop, 0);
-			} else if (!cmd->error && host->prog_enable) {
+			if (!cmd->error && host->prog_enable) {
 				if (status & MCI_PROGDONE) {
 					host->prog_enable = 0;
 					msmsdcc_request_end(host, cmd->mrq);
@@ -3014,8 +3006,11 @@
 			mmc_hostname(host->mmc), __func__, gpio_no);
 	} else {
 		status = gpio_direction_input(gpio_no);
-		if (!status)
+		if (!status) {
 			status = gpio_get_value_cansleep(gpio_no);
+			if (host->plat->is_status_gpio_active_low)
+				status = !status;
+		}
 		gpio_free(gpio_no);
 	}
 	return status;
@@ -3028,17 +3023,12 @@
 	unsigned int status;
 
 	if (host->plat->status || host->plat->status_gpio) {
-		if (host->plat->status) {
+		if (host->plat->status)
 			status = host->plat->status(mmc_dev(host->mmc));
-			host->eject = !status;
-		} else {
+		else
 			status = msmsdcc_slot_status(host);
 
-			if (host->plat->is_status_gpio_active_low)
-				host->eject = status;
-			else
-				host->eject = !status;
-		}
+		host->eject = !status;
 
 		if (status ^ host->oldstat) {
 			if (host->plat->status)
@@ -4188,17 +4178,12 @@
 	 */
 
 	if (plat->status || plat->status_gpio) {
-		if (plat->status) {
+		if (plat->status)
 			host->oldstat = plat->status(mmc_dev(host->mmc));
-			host->eject = !host->oldstat;
-		} else {
+		else
 			host->oldstat = msmsdcc_slot_status(host);
 
-			if (host->plat->is_status_gpio_active_low)
-				host->eject = host->oldstat;
-			else
-				host->eject = !host->oldstat;
-		}
+		host->eject = !host->oldstat;
 	}
 
 	if (plat->status_irq) {
diff --git a/drivers/power/isl9519q.c b/drivers/power/isl9519q.c
index e4729f2..7ebbf46 100644
--- a/drivers/power/isl9519q.c
+++ b/drivers/power/isl9519q.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,7 @@
  * GNU General Public License for more details.
  *
  */
+#define pr_fmt(fmt)	"%s: " fmt, __func__
 
 #include <linux/i2c.h>
 #include <linux/gpio.h>
@@ -20,7 +21,7 @@
 #include <linux/workqueue.h>
 #include <linux/interrupt.h>
 #include <linux/msm-charger.h>
-#include <linux/mfd/pm8xxx/pm8921-charger.h>
+#include <linux/power_supply.h>
 #include <linux/slab.h>
 #include <linux/i2c/isl9519.h>
 #include <linux/msm_adc.h>
@@ -54,7 +55,7 @@
 	struct msm_hardware_charger	adapter_hw_chg;
 	int				suspended;
 	int				charge_at_resume;
-	struct ext_chg_pm8921		ext_chg;
+	struct power_supply		dc_psy;
 	spinlock_t			lock;
 	bool				notify_by_pmic;
 	bool				trickle;
@@ -75,10 +76,11 @@
 		dev_err(&isl_chg->client->dev,
 			"i2c read fail: can't read from %02x: %d\n", reg, ret);
 		return -EAGAIN;
-	} else
+	} else {
 		*val = ret;
+	}
 
-	pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, *val);
+	pr_debug("reg=0x%x.val=0x%x.\n", reg, *val);
 
 	return 0;
 }
@@ -89,7 +91,7 @@
 	int ret;
 	struct isl9519q_struct *isl_chg;
 
-	pr_debug("%s.reg=0x%x.val=0x%x.\n", __func__, reg, val);
+	pr_debug("reg=0x%x.val=0x%x.\n", reg, val);
 
 	isl_chg = i2c_get_clientdata(client);
 	ret = i2c_smbus_write_word_data(isl_chg->client, reg, val);
@@ -118,44 +120,41 @@
 	struct adc_chan_result adc_chan_result;
 	struct completion  conv_complete_evt;
 
-	pr_debug("%s: called for %d\n", __func__, channel);
+	pr_debug("called for %d\n", channel);
 	ret = adc_channel_open(channel, &h);
 	if (ret) {
-		pr_err("%s: couldnt open channel %d ret=%d\n",
-					__func__, channel, ret);
+		pr_err("couldnt open channel %d ret=%d\n", channel, ret);
 		goto out;
 	}
 	init_completion(&conv_complete_evt);
 	ret = adc_channel_request_conv(h, &conv_complete_evt);
 	if (ret) {
-		pr_err("%s: couldnt request conv channel %d ret=%d\n",
-						__func__, channel, ret);
+		pr_err("couldnt request conv channel %d ret=%d\n",
+						channel, ret);
 		goto out;
 	}
 	ret = wait_for_completion_interruptible(&conv_complete_evt);
 	if (ret) {
-		pr_err("%s: wait interrupted channel %d ret=%d\n",
-						__func__, channel, ret);
+		pr_err("wait interrupted channel %d ret=%d\n", channel, ret);
 		goto out;
 	}
 	ret = adc_channel_read_result(h, &adc_chan_result);
 	if (ret) {
-		pr_err("%s: couldnt read result channel %d ret=%d\n",
-						__func__, channel, ret);
+		pr_err("couldnt read result channel %d ret=%d\n",
+						channel, ret);
 		goto out;
 	}
 	ret = adc_channel_close(h);
 	if (ret)
-		pr_err("%s: couldnt close channel %d ret=%d\n",
-					__func__, channel, ret);
+		pr_err("couldnt close channel %d ret=%d\n", channel, ret);
 	if (mv_reading)
 		*mv_reading = (int)adc_chan_result.measurement;
 
-	pr_debug("%s: done for %d\n", __func__, channel);
+	pr_debug("done for %d\n", channel);
 	return adc_chan_result.physical;
 out:
 	*mv_reading = 0;
-	pr_debug("%s: done with error for %d\n", __func__, channel);
+	pr_debug("done with error for %d\n", channel);
 
 	return -EINVAL;
 }
@@ -168,7 +167,7 @@
 	ret = isl9519q_read_reg(isl_chg->client, CONTROL_REG, &ctrl);
 
 	if (!ret) {
-		pr_debug("%s.control_reg=0x%x.\n", __func__, ctrl);
+		pr_debug("control_reg=0x%x.\n", ctrl);
 	} else {
 		dev_err(&isl_chg->client->dev,
 			"%s couldnt read cntrl reg\n", __func__);
@@ -220,7 +219,7 @@
 	dev_dbg(&isl_chg->client->dev, "%s\n", __func__);
 
 	if (!isl_chg->charging) {
-		pr_info("%s.stop charging.\n", __func__);
+		pr_debug("stop charging.\n");
 		isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG, 0);
 		return; /* Stop periodic worker */
 	}
@@ -241,17 +240,15 @@
 static int isl9519q_start_charging(struct isl9519q_struct *isl_chg,
 				   int chg_voltage, int chg_current)
 {
-	int ret = 0;
-
-	pr_info("%s.\n", __func__);
+	pr_debug("\n");
 
 	if (isl_chg->charging) {
-		pr_warn("%s.already charging.\n", __func__);
+		pr_warn("already charging.\n");
 		return 0;
 	}
 
 	if (isl_chg->suspended) {
-		pr_warn("%s.suspended - can't start charging.\n", __func__);
+		pr_warn("suspended - can't start charging.\n");
 		isl_chg->charge_at_resume = 1;
 		return 0;
 	}
@@ -268,15 +265,15 @@
 
 	isl_chg->charging = true;
 
-	return ret;
+	return 0;
 }
 
 static int isl9519q_stop_charging(struct isl9519q_struct *isl_chg)
 {
-	pr_info("%s.\n", __func__);
+	pr_debug("\n");
 
 	if (!(isl_chg->charging)) {
-		pr_warn("%s.already not charging.\n", __func__);
+		pr_warn("already not charging.\n");
 		return 0;
 	}
 
@@ -298,39 +295,6 @@
 	return 0;
 }
 
-static int isl_ext_start_charging(void *ctx)
-{
-	int rc;
-	struct isl9519q_struct *isl_chg = ctx;
-	unsigned long flags;
-
-	spin_lock_irqsave(&isl_chg->lock, flags);
-	rc = isl9519q_start_charging(isl_chg, 0, isl_chg->chgcurrent);
-	spin_unlock_irqrestore(&isl_chg->lock, flags);
-
-	return rc;
-}
-
-static int isl_ext_stop_charging(void *ctx)
-{
-	int rc;
-	struct isl9519q_struct *isl_chg = ctx;
-	unsigned long flags;
-
-	spin_lock_irqsave(&isl_chg->lock, flags);
-	rc = isl9519q_stop_charging(isl_chg);
-	spin_unlock_irqrestore(&isl_chg->lock, flags);
-
-	return rc;
-}
-
-static bool isl_ext_is_trickle(void *ctx)
-{
-	struct isl9519q_struct *isl_chg = ctx;
-
-	return isl_chg->trickle;
-}
-
 static int isl_adapter_start_charging(struct msm_hardware_charger *hw_chg,
 				      int chg_voltage, int chg_current)
 {
@@ -396,6 +360,114 @@
 	return IRQ_HANDLED;
 }
 
+static enum power_supply_property pm_power_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CHARGE_TYPE,
+};
+
+static char *pm_power_supplied_to[] = {
+	"battery",
+};
+
+static int get_prop_charge_type(struct isl9519q_struct *isl_chg)
+{
+	if (!isl_chg->present)
+		return POWER_SUPPLY_CHARGE_TYPE_NONE;
+
+	if (isl_chg->trickle)
+		return POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+
+	if (isl_chg->charging)
+		return POWER_SUPPLY_CHARGE_TYPE_FAST;
+
+	return POWER_SUPPLY_CHARGE_TYPE_NONE;
+}
+static int pm_power_get_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  union power_supply_propval *val)
+{
+	struct isl9519q_struct *isl_chg = container_of(psy,
+						struct isl9519q_struct,
+						dc_psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		val->intval = isl_chg->chgcurrent;
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = (int)isl_chg->present;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		val->intval = get_prop_charge_type(isl_chg);
+		break;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int pm_power_set_property(struct power_supply *psy,
+				  enum power_supply_property psp,
+				  const union power_supply_propval *val)
+{
+	struct isl9519q_struct *isl_chg = container_of(psy,
+						struct isl9519q_struct,
+						dc_psy);
+	unsigned long flags;
+	int rc;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		if (val->intval) {
+			isl_chg->present = val->intval;
+		} else {
+			isl_chg->present = 0;
+			if (isl_chg->charging)
+				goto stop_charging;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_MAX:
+		if (val->intval) {
+			if (isl_chg->chgcurrent != val->intval)
+				return -EINVAL;
+		}
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		if (val->intval && isl_chg->present) {
+			if (val->intval == POWER_SUPPLY_CHARGE_TYPE_FAST)
+				goto start_charging;
+			if (val->intval == POWER_SUPPLY_CHARGE_TYPE_NONE)
+				goto stop_charging;
+		} else {
+			return -EINVAL;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+	power_supply_changed(&isl_chg->dc_psy);
+	return 0;
+
+start_charging:
+	spin_lock_irqsave(&isl_chg->lock, flags);
+	rc = isl9519q_start_charging(isl_chg, 0, isl_chg->chgcurrent);
+	if (rc)
+		pr_err("Failed to start charging rc=%d\n", rc);
+	spin_unlock_irqrestore(&isl_chg->lock, flags);
+	power_supply_changed(&isl_chg->dc_psy);
+	return rc;
+
+stop_charging:
+	spin_lock_irqsave(&isl_chg->lock, flags);
+	rc = isl9519q_stop_charging(isl_chg);
+	if (rc)
+		pr_err("Failed to start charging rc=%d\n", rc);
+	spin_unlock_irqrestore(&isl_chg->lock, flags);
+	power_supply_changed(&isl_chg->dc_psy);
+	return rc;
+}
+
 #define MAX_VOLTAGE_REG_MASK  0x3FF0
 #define MIN_VOLTAGE_REG_MASK  0x3F00
 #define DEFAULT_MAX_VOLTAGE_REG_VALUE	0x1070
@@ -404,8 +476,8 @@
 static int __devinit isl9519q_init_adapter(struct isl9519q_struct *isl_chg)
 {
 	int ret;
-	struct isl_platform_data *pdata = isl_chg->client->dev.platform_data;
 	struct i2c_client *client = isl_chg->client;
+	struct isl_platform_data *pdata = client->dev.platform_data;
 
 	isl_chg->adapter_hw_chg.type = CHG_TYPE_AC;
 	isl_chg->adapter_hw_chg.rating = 2;
@@ -473,15 +545,18 @@
 {
 	int ret;
 
-	isl_chg->ext_chg.name = "isl9519q";
-	isl_chg->ext_chg.ctx = isl_chg;
-	isl_chg->ext_chg.start_charging = isl_ext_start_charging;
-	isl_chg->ext_chg.stop_charging = isl_ext_stop_charging;
-	isl_chg->ext_chg.is_trickle = isl_ext_is_trickle;
-	ret = register_external_dc_charger(&isl_chg->ext_chg);
+	isl_chg->dc_psy.name = "dc";
+	isl_chg->dc_psy.type = POWER_SUPPLY_TYPE_MAINS;
+	isl_chg->dc_psy.supplied_to = pm_power_supplied_to;
+	isl_chg->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
+	isl_chg->dc_psy.properties = pm_power_props;
+	isl_chg->dc_psy.num_properties = ARRAY_SIZE(pm_power_props);
+	isl_chg->dc_psy.get_property = pm_power_get_property;
+	isl_chg->dc_psy.set_property = pm_power_set_property;
+
+	ret = power_supply_register(&isl_chg->client->dev, &isl_chg->dc_psy);
 	if (ret) {
-		pr_err("%s.failed to register external dc charger.ret=%d.\n",
-		       __func__, ret);
+		pr_err("failed to register dc charger.ret=%d.\n", ret);
 		return ret;
 	}
 
@@ -553,6 +628,36 @@
 		debugfs_remove_recursive(isl_chg->dent);
 }
 
+static int __devinit isl9519q_hwinit(struct isl9519q_struct *isl_chg)
+{
+	int ret;
+
+	ret = isl9519q_write_reg(isl_chg->client, MAX_SYS_VOLTAGE_REG,
+			isl_chg->max_system_voltage);
+	if (ret) {
+		pr_err("Failed to set MAX_SYS_VOLTAGE rc=%d\n", ret);
+		return ret;
+	}
+
+	ret = isl9519q_write_reg(isl_chg->client, MIN_SYS_VOLTAGE_REG,
+			isl_chg->min_system_voltage);
+	if (ret) {
+		pr_err("Failed to set MIN_SYS_VOLTAGE rc=%d\n", ret);
+		return ret;
+	}
+
+	if (isl_chg->input_current) {
+		ret = isl9519q_write_reg(isl_chg->client,
+				INPUT_CURRENT_REG,
+				isl_chg->input_current);
+		if (ret) {
+			pr_err("Failed to set INPUT_CURRENT rc=%d\n", ret);
+			return ret;
+		}
+	}
+	return 0;
+}
+
 static int __devinit isl9519q_probe(struct i2c_client *client,
 				    const struct i2c_device_id *id)
 {
@@ -563,7 +668,7 @@
 	ret = 0;
 	pdata = client->dev.platform_data;
 
-	pr_info("%s.\n", __func__);
+	pr_debug("\n");
 
 	if (pdata == NULL) {
 		dev_err(&client->dev, "%s no platform data\n", __func__);
@@ -623,24 +728,10 @@
 	if (isl_chg->min_system_voltage == 0)
 		isl_chg->min_system_voltage = DEFAULT_MIN_VOLTAGE_REG_VALUE;
 
-	ret = isl9519q_write_reg(isl_chg->client, MAX_SYS_VOLTAGE_REG,
-			isl_chg->max_system_voltage);
+	ret = isl9519q_hwinit(isl_chg);
 	if (ret)
 		goto free_isl_chg;
 
-	ret = isl9519q_write_reg(isl_chg->client, MIN_SYS_VOLTAGE_REG,
-			isl_chg->min_system_voltage);
-	if (ret)
-		goto free_isl_chg;
-
-	if (isl_chg->input_current) {
-		ret = isl9519q_write_reg(isl_chg->client,
-				INPUT_CURRENT_REG,
-				isl_chg->input_current);
-		if (ret)
-			goto free_isl_chg;
-	}
-
 	if (isl_chg->notify_by_pmic)
 		ret = isl9519q_init_ext_chg(isl_chg);
 	else
@@ -652,7 +743,7 @@
 	the_isl_chg = isl_chg;
 	create_debugfs_entries(isl_chg);
 
-	pr_info("%s OK.\n", __func__);
+	pr_info("OK.\n");
 
 	return 0;
 
@@ -671,8 +762,13 @@
 	gpio_free(pdata->valid_n_gpio);
 	free_irq(client->irq, client);
 	cancel_delayed_work_sync(&isl_chg->charge_work);
-	msm_charger_notify_event(&isl_chg->adapter_hw_chg, CHG_REMOVED_EVENT);
-	msm_charger_unregister(&isl_chg->adapter_hw_chg);
+	if (isl_chg->notify_by_pmic) {
+		power_supply_unregister(&isl_chg->dc_psy);
+	} else {
+		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
+							CHG_REMOVED_EVENT);
+		msm_charger_unregister(&isl_chg->adapter_hw_chg);
+	}
 	remove_debugfs_entries(isl_chg);
 	the_isl_chg = NULL;
 	kfree(isl_chg);
@@ -736,8 +832,6 @@
 
 static int __init isl9519q_init(void)
 {
-	pr_info("%s. isl9519q SW rev 1.01\n", __func__);
-
 	return i2c_add_driver(&isl9519q_driver);
 }
 
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 5bb76e7..293c25d 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -475,8 +475,6 @@
 	}
 	*result = msw << 16 | lsw;
 	pr_debug("msw = %04x lsw = %04x cc = %d\n", msw, lsw, *result);
-	pr_debug("cc = %d after subtracting %d\n",
-					*result, chip->cc_reading_at_100);
 	return 0;
 }
 
@@ -923,14 +921,15 @@
  * RETURNS: in val pointer coulumb counter based charger in uAh
  *          (micro Amp hour)
  */
-static void calculate_cc_uah(struct pm8921_bms_chip *chip, int cc, int *val,
-			int *coulumb_counter)
+static void calculate_cc_uah(struct pm8921_bms_chip *chip, int cc, int *val)
 {
 	int64_t cc_voltage_uv, cc_nvh, cc_uah;
 
-	*coulumb_counter = cc;
-	*coulumb_counter -= chip->cc_reading_at_100;
-	cc_voltage_uv = (int64_t)*coulumb_counter;
+	cc_voltage_uv = cc;
+	cc_voltage_uv -= chip->cc_reading_at_100;
+	pr_debug("cc = %d. after subtracting %d cc = %lld\n",
+					cc, chip->cc_reading_at_100,
+					cc_voltage_uv);
 	cc_voltage_uv = cc_to_microvolt(chip, cc_voltage_uv);
 	cc_voltage_uv = pm8xxx_cc_adjust_for_gain(cc_voltage_uv);
 	pr_debug("cc_voltage_uv = %lld microvolts\n", cc_voltage_uv);
@@ -1002,7 +1001,6 @@
 						int *remaining_charge_uah,
 						int *cc_uah)
 {
-	int coulumb_counter;
 	unsigned long flags;
 
 	*fcc_uah = calculate_fcc_uah(chip, batt_temp, chargecycles);
@@ -1021,9 +1019,11 @@
 	pr_debug("RC = %uuAh\n", *remaining_charge_uah);
 
 	/* calculate cc micro_volt_hour */
-	calculate_cc_uah(chip, raw->cc, cc_uah, &coulumb_counter);
-	pr_debug("cc_uah = %duAh raw->cc = %x cc = %x\n",
-					*cc_uah, raw->cc, coulumb_counter);
+	calculate_cc_uah(chip, raw->cc, cc_uah);
+	pr_debug("cc_uah = %duAh raw->cc = %x cc = %lld after subtracting %d\n",
+				*cc_uah, raw->cc,
+				(int64_t)raw->cc - chip->cc_reading_at_100,
+				chip->cc_reading_at_100);
 	spin_unlock_irqrestore(&chip->bms_100_lock, flags);
 }
 
@@ -1270,7 +1270,7 @@
 
 void pm8921_bms_charging_began(void)
 {
-	int batt_temp, coulumb_counter, rc;
+	int batt_temp, rc;
 	struct pm8xxx_adc_chan_result result;
 	struct pm8921_soc_params raw;
 
@@ -1290,7 +1290,7 @@
 					batt_temp, last_chargecycles);
 	bms_start_percent = the_chip->start_percent;
 	bms_start_ocv_uv = raw.last_good_ocv_uv;
-	calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah, &coulumb_counter);
+	calculate_cc_uah(the_chip, raw.cc, &bms_start_cc_uah);
 
 	pr_debug("start_percent = %u%%\n", the_chip->start_percent);
 }
@@ -1299,7 +1299,7 @@
 #define DELTA_FCC_PERCENT	3
 void pm8921_bms_charging_end(int is_battery_full)
 {
-	int batt_temp, coulumb_counter, rc;
+	int batt_temp, rc;
 	struct pm8xxx_adc_chan_result result;
 	struct pm8921_soc_params raw;
 
@@ -1355,7 +1355,7 @@
 
 	bms_end_percent = the_chip->end_percent;
 	bms_end_ocv_uv = raw.last_good_ocv_uv;
-	calculate_cc_uah(the_chip, raw.cc, &bms_end_cc_uah, &coulumb_counter);
+	calculate_cc_uah(the_chip, raw.cc, &bms_end_cc_uah);
 
 	if (the_chip->end_percent > the_chip->start_percent) {
 		last_charge_increase =
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index c169025..22d53e9 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -80,6 +80,8 @@
 
 /* check EOC every 10 seconds */
 #define EOC_CHECK_PERIOD_MS	10000
+/* check for USB unplug every 200 msecs */
+#define UNPLUG_CHECK_WAIT_PERIOD_MS 200
 
 enum chg_fsm_state {
 	FSM_STATE_OFF_0 = 0,
@@ -233,11 +235,10 @@
 	unsigned int			batt_temp_channel;
 	unsigned int			batt_id_channel;
 	struct power_supply		usb_psy;
-	struct power_supply		dc_psy;
+	struct power_supply		*ext_psy;
 	struct power_supply		batt_psy;
 	struct dentry			*dent;
 	struct bms_notify		bms_notify;
-	struct ext_chg_pm8921		*ext;
 	bool				keep_btm_on_suspend;
 	bool				ext_charging;
 	bool				ext_charge_done;
@@ -254,6 +255,9 @@
 	int				thermal_levels;
 	struct delayed_work		update_heartbeat_work;
 	struct delayed_work		eoc_work;
+	struct delayed_work		unplug_wrkarnd_restore_work;
+	struct delayed_work		unplug_check_work;
+	struct wake_lock		unplug_wrkarnd_restore_wake_lock;
 	struct wake_lock		eoc_wake_lock;
 	enum pm8921_chg_cold_thr	cold_thr;
 	enum pm8921_chg_hot_thr		hot_thr;
@@ -391,6 +395,14 @@
 				disable ? CHG_CHARGE_DIS_BIT : 0);
 }
 
+static bool pm_is_chg_charge_dis_bit_set(struct pm8921_chg_chip *chip)
+{
+	u8 temp = 0;
+
+	pm8xxx_readb(chip->dev->parent, CHG_CNTRL, &temp);
+	return !!(temp & CHG_CHARGE_DIS_BIT);
+}
+
 #define PM8921_CHG_V_MIN_MV	3240
 #define PM8921_CHG_V_STEP_MV	20
 #define PM8921_CHG_VDDMAX_MAX	4500
@@ -478,6 +490,20 @@
 									temp);
 }
 
+static int pm_chg_vinmin_get(struct pm8921_chg_chip *chip)
+{
+	u8 temp;
+	int rc, voltage_mv;
+
+	rc = pm8xxx_readb(chip->dev->parent, CHG_VIN_MIN, &temp);
+	temp &= PM8921_CHG_VINMIN_MASK;
+
+	voltage_mv = PM8921_CHG_VINMIN_MIN_MV +
+			(int)temp * PM8921_CHG_VINMIN_STEP_MV;
+
+	return voltage_mv;
+}
+
 #define PM8921_CHG_IBATMAX_MIN	325
 #define PM8921_CHG_IBATMAX_MAX	2000
 #define PM8921_CHG_I_MIN_MA	225
@@ -791,6 +817,11 @@
 	}
 }
 
+static int pm8921_chg_is_enabled(struct pm8921_chg_chip *chip, int interrupt)
+{
+	return test_bit(interrupt, chip->enabled_irqs);
+}
+
 static int pm_chg_get_rt_status(struct pm8921_chg_chip *chip, int irq_id)
 {
 	return pm8xxx_read_irq_stat(chip->dev->parent,
@@ -811,21 +842,29 @@
 
 static bool is_ext_charging(struct pm8921_chg_chip *chip)
 {
-	if (chip->ext == NULL)
-		return false;
+	union power_supply_propval ret = {0,};
 
-	if (chip->ext_charging)
-		return true;
+	if (!chip->ext_psy)
+		return false;
+	if (chip->ext_psy->get_property(chip->ext_psy,
+					POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
+		return false;
+	if (ret.intval > POWER_SUPPLY_CHARGE_TYPE_NONE)
+		return ret.intval;
 
 	return false;
 }
 
 static bool is_ext_trickle_charging(struct pm8921_chg_chip *chip)
 {
-	if (chip->ext == NULL)
-		return false;
+	union power_supply_propval ret = {0,};
 
-	if (chip->ext->is_trickle(chip->ext->ctx))
+	if (!chip->ext_psy)
+		return false;
+	if (chip->ext_psy->get_property(chip->ext_psy,
+					POWER_SUPPLY_PROP_CHARGE_TYPE, &ret))
+		return false;
+	if (ret.intval == POWER_SUPPLY_CHARGE_TYPE_TRICKLE)
 		return true;
 
 	return false;
@@ -890,18 +929,16 @@
 	switch (psp) {
 	case POWER_SUPPLY_PROP_PRESENT:
 	case POWER_SUPPLY_PROP_ONLINE:
-		if (psy->type == POWER_SUPPLY_TYPE_MAINS) {
-			chip = container_of(psy, struct pm8921_chg_chip,
-							dc_psy);
-			val->intval = is_dc_chg_plugged_in(chip);
-		}
 		if (psy->type == POWER_SUPPLY_TYPE_USB ||
 			psy->type == POWER_SUPPLY_TYPE_USB_DCP ||
 			psy->type == POWER_SUPPLY_TYPE_USB_CDP ||
 			psy->type == POWER_SUPPLY_TYPE_USB_ACA) {
 			chip = container_of(psy, struct pm8921_chg_chip,
 							usb_psy);
-			val->intval = is_usb_chg_plugged_in(chip);
+			if (pm_is_chg_charge_dis_bit_set(chip))
+				val->intval = 0;
+			else
+				val->intval = is_usb_chg_plugged_in(chip);
 		}
 		break;
 	default:
@@ -1047,7 +1084,7 @@
 	int fsm_state = pm_chg_get_fsm_state(chip);
 	int i;
 
-	if (chip->ext) {
+	if (chip->ext_psy) {
 		if (chip->ext_charge_done)
 			return POWER_SUPPLY_STATUS_FULL;
 		if (chip->ext_charging)
@@ -1061,7 +1098,8 @@
 	if (fsm_state == FSM_STATE_ON_CHG_HIGHI_1) {
 		if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
 			|| !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
-			|| !pm_chg_get_rt_status(chip, CHGHOT_IRQ))
+			|| pm_chg_get_rt_status(chip, CHGHOT_IRQ)
+			|| pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
 
 			batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
 	}
@@ -1334,11 +1372,18 @@
 
 int pm8921_regulate_input_voltage(int voltage)
 {
+	int rc;
+
 	if (!the_chip) {
 		pr_err("called before init\n");
 		return -EINVAL;
 	}
-	return pm_chg_vinmin_set(the_chip, voltage);
+	rc = pm_chg_vinmin_set(the_chip, voltage);
+
+	if (rc == 0)
+		the_chip->vin_min = voltage;
+
+	return rc;
 }
 
 #define USB_OV_THRESHOLD_MASK  0x60
@@ -1479,12 +1524,17 @@
 		power_supply_changed(&chip->usb_psy);
 		power_supply_changed(&chip->batt_psy);
 	}
+	if (usb_present) {
+		schedule_delayed_work(&chip->unplug_check_work,
+			round_jiffies_relative(msecs_to_jiffies
+				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+	}
 	bms_notify_check(chip);
 }
 
 static void handle_stop_ext_chg(struct pm8921_chg_chip *chip)
 {
-	if (chip->ext == NULL) {
+	if (!chip->ext_psy) {
 		pr_debug("external charger not registered.\n");
 		return;
 	}
@@ -1494,9 +1544,12 @@
 		return;
 	}
 
-	chip->ext->stop_charging(chip->ext->ctx);
+	power_supply_set_charge_type(chip->ext_psy,
+					POWER_SUPPLY_CHARGE_TYPE_NONE);
+	pm8921_disable_source_current(false); /* release BATFET */
 	chip->ext_charging = false;
 	chip->ext_charge_done = false;
+	bms_notify_check(chip);
 }
 
 static void handle_start_ext_chg(struct pm8921_chg_chip *chip)
@@ -1505,11 +1558,10 @@
 	int batt_present;
 	int batt_temp_ok;
 	int vbat_ov;
-	int batfet;
 	unsigned long delay =
 		round_jiffies_relative(msecs_to_jiffies(EOC_CHECK_PERIOD_MS));
 
-	if (chip->ext == NULL) {
+	if (!chip->ext_psy) {
 		pr_debug("external charger not registered.\n");
 		return;
 	}
@@ -1519,11 +1571,9 @@
 		return;
 	}
 
-	dc_present = is_dc_chg_plugged_in(chip);
+	dc_present = is_dc_chg_plugged_in(the_chip);
 	batt_present = pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ);
 	batt_temp_ok = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
-	vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
-	batfet = pm_chg_get_rt_status(chip, BATFET_IRQ);
 
 	if (!dc_present) {
 		pr_warn("%s. dc not present.\n", __func__);
@@ -1537,36 +1587,44 @@
 		pr_warn("%s. battery temperature not ok.\n", __func__);
 		return;
 	}
+	pm8921_disable_source_current(true); /* Force BATFET=ON */
+	vbat_ov = pm_chg_get_rt_status(chip, VBAT_OV_IRQ);
 	if (vbat_ov) {
 		pr_warn("%s. battery over voltage.\n", __func__);
 		return;
 	}
-	if (!batfet) {
-		pr_warn("%s. battery FET not closed.\n", __func__);
-		return;
-	}
 
-	chip->ext->start_charging(chip->ext->ctx);
+	power_supply_set_charge_type(chip->ext_psy,
+					POWER_SUPPLY_CHARGE_TYPE_FAST);
 	chip->ext_charging = true;
 	chip->ext_charge_done = false;
+	bms_notify_check(chip);
 	/* Start BMS */
 	schedule_delayed_work(&chip->eoc_work, delay);
 	wake_lock(&chip->eoc_wake_lock);
 }
 
-static void handle_dc_removal_insertion(struct pm8921_chg_chip *chip)
+#define WRITE_BANK_4		0xC0
+static void unplug_wrkarnd_restore_worker(struct work_struct *work)
 {
-	int dc_present;
+	u8 temp;
+	int rc;
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct pm8921_chg_chip *chip = container_of(dwork,
+				struct pm8921_chg_chip,
+				unplug_wrkarnd_restore_work);
 
-	dc_present = is_dc_chg_plugged_in(chip);
-	if (chip->dc_present ^ dc_present) {
-		chip->dc_present = dc_present;
-		power_supply_changed(&chip->dc_psy);
-		power_supply_changed(&chip->batt_psy);
+	pr_debug("restoring vin_min to %d mV\n", chip->vin_min);
+	rc = pm_chg_vinmin_set(the_chip, chip->vin_min);
+
+	temp = WRITE_BANK_4 | 0xA;
+	rc = pm8xxx_writeb(chip->dev->parent, CHG_BUCK_CTRL_TEST3, temp);
+	if (rc) {
+		pr_err("Error %d writing %d to addr %d\n", rc,
+					temp, CHG_BUCK_CTRL_TEST3);
 	}
-	bms_notify_check(chip);
+	wake_unlock(&chip->unplug_wrkarnd_restore_wake_lock);
 }
-
 static irqreturn_t usbin_valid_irq_handler(int irq, void *data)
 {
 	handle_usb_insertion_removal(data);
@@ -1611,12 +1669,13 @@
 	if (high_transition) {
 		/* enable auto charging */
 		pm_chg_auto_enable(chip, !charging_disabled);
+		pr_info("batt fell below resume voltage %s\n",
+			charging_disabled ? "" : "charger enabled");
 	}
 	pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
 
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
 
 	return IRQ_HANDLED;
 }
@@ -1668,7 +1727,6 @@
 
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
 
 	bms_notify_check(chip);
 
@@ -1691,7 +1749,6 @@
 
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
 	return IRQ_HANDLED;
 }
 
@@ -1702,16 +1759,77 @@
 	pr_debug("state_changed_to=%d\n", pm_chg_get_fsm_state(data));
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
 
 	bms_notify_check(chip);
 
 	return IRQ_HANDLED;
 }
 
+#define VIN_ACTIVE_BIT BIT(0)
+#define UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US 200
+#define VIN_MIN_INCREASE_MV 100
+static void unplug_check_worker(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct pm8921_chg_chip *chip = container_of(dwork,
+				struct pm8921_chg_chip, unplug_check_work);
+	u8 reg_loop;
+	int ibat, usb_chg_plugged_in;
+
+	usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
+	if (!usb_chg_plugged_in) {
+		pr_debug("Stopping Unplug Check Worker since USB is removed"
+			"reg_loop = %d, fsm = %d ibat = %d\n",
+			pm_chg_get_regulation_loop(chip),
+			pm_chg_get_fsm_state(chip),
+			get_prop_batt_current(chip)
+			);
+		return;
+	}
+	reg_loop = pm_chg_get_regulation_loop(chip);
+	pr_debug("reg_loop=0x%x\n", reg_loop);
+
+	if (reg_loop & VIN_ACTIVE_BIT) {
+		ibat = get_prop_batt_current(chip);
+
+		pr_debug("ibat = %d fsm = %d reg_loop = 0x%x\n",
+				ibat, pm_chg_get_fsm_state(chip), reg_loop);
+		if (ibat > 0) {
+			int err;
+			u8 temp;
+
+			temp = WRITE_BANK_4 | 0xE;
+			err = pm8xxx_writeb(chip->dev->parent,
+						CHG_BUCK_CTRL_TEST3, temp);
+			if (err) {
+				pr_err("Error %d writing %d to addr %d\n", err,
+						temp, CHG_BUCK_CTRL_TEST3);
+			}
+
+			pm_chg_vinmin_set(chip,
+					chip->vin_min + VIN_MIN_INCREASE_MV);
+
+			wake_lock(&chip->unplug_wrkarnd_restore_wake_lock);
+			schedule_delayed_work(
+				&chip->unplug_wrkarnd_restore_work,
+				round_jiffies_relative(usecs_to_jiffies
+				(UNPLUG_WRKARND_RESTORE_WAIT_PERIOD_US)));
+		}
+	}
+
+	schedule_delayed_work(&chip->unplug_check_work,
+		      round_jiffies_relative(msecs_to_jiffies
+				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+}
+
 static irqreturn_t loop_change_irq_handler(int irq, void *data)
 {
-	pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
+	struct pm8921_chg_chip *chip = data;
+
+	pr_debug("fsm_state=%d reg_loop=0x%x\n",
+		pm_chg_get_fsm_state(data),
+		pm_chg_get_regulation_loop(data));
+	unplug_check_worker(&(chip->unplug_check_work.work));
 	return IRQ_HANDLED;
 }
 
@@ -1769,7 +1887,7 @@
 	pr_debug("Chg hot fsm_state=%d\n", pm_chg_get_fsm_state(data));
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
+	handle_stop_ext_chg(chip);
 	return IRQ_HANDLED;
 }
 
@@ -1782,7 +1900,6 @@
 
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
 	return IRQ_HANDLED;
 }
 
@@ -1793,7 +1910,6 @@
 	pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
 	return IRQ_HANDLED;
 }
 /*
@@ -1824,7 +1940,6 @@
 
 	power_supply_changed(&chip->batt_psy);
 	power_supply_changed(&chip->usb_psy);
-	power_supply_changed(&chip->dc_psy);
 	bms_notify_check(chip);
 	return IRQ_HANDLED;
 }
@@ -1865,11 +1980,16 @@
 static irqreturn_t dcin_valid_irq_handler(int irq, void *data)
 {
 	struct pm8921_chg_chip *chip = data;
+	int dc_present;
 
-	pm8921_disable_source_current(true); /* Force BATFET=ON */
-
-	handle_dc_removal_insertion(chip);
-	handle_start_ext_chg(chip);
+	dc_present = pm_chg_get_rt_status(chip, DCIN_VALID_IRQ);
+	if (chip->ext_psy)
+		power_supply_set_online(chip->ext_psy, dc_present);
+	chip->dc_present = dc_present;
+	if (dc_present)
+		handle_start_ext_chg(chip);
+	else
+		handle_stop_ext_chg(chip);
 	return IRQ_HANDLED;
 }
 
@@ -1877,9 +1997,6 @@
 {
 	struct pm8921_chg_chip *chip = data;
 
-	pm8921_disable_source_current(false); /* release BATFET */
-
-	handle_dc_removal_insertion(chip);
 	handle_stop_ext_chg(chip);
 	return IRQ_HANDLED;
 }
@@ -1888,12 +2005,41 @@
 {
 	struct pm8921_chg_chip *chip = data;
 
-	pm8921_disable_source_current(false); /* release BATFET */
 	handle_stop_ext_chg(chip);
 
 	return IRQ_HANDLED;
 }
 
+static int __pm_batt_external_power_changed_work(struct device *dev, void *data)
+{
+	struct power_supply *psy = &the_chip->batt_psy;
+	struct power_supply *epsy = dev_get_drvdata(dev);
+	int i, dcin_irq;
+
+	/* Only search for external supply if none is registered */
+	if (!the_chip->ext_psy) {
+		dcin_irq = the_chip->pmic_chg_irq[DCIN_VALID_IRQ];
+		for (i = 0; i < epsy->num_supplicants; i++) {
+			if (!strncmp(epsy->supplied_to[i], psy->name, 7)) {
+				if (!strncmp(epsy->name, "dc", 2)) {
+					the_chip->ext_psy = epsy;
+					dcin_valid_irq_handler(dcin_irq,
+							the_chip);
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static void pm_batt_external_power_changed(struct power_supply *psy)
+{
+	/* Only look for an external supply if it hasn't been registered */
+	if (!the_chip->ext_psy)
+		class_for_each_device(power_supply_class, NULL, psy,
+					 __pm_batt_external_power_changed_work);
+}
+
 /**
  * update_heartbeat - internal function to update userspace
  *		per update_time minutes
@@ -1911,6 +2057,110 @@
 						     (chip->update_time)));
 }
 
+enum {
+	CHG_IN_PROGRESS,
+	CHG_NOT_IN_PROGRESS,
+	CHG_FINISHED,
+};
+
+#define VBAT_TOLERANCE_MV	70
+#define CHG_DISABLE_MSLEEP	100
+static int is_charging_finished(struct pm8921_chg_chip *chip)
+{
+	int vbat_meas_uv, vbat_meas_mv, vbat_programmed, vbatdet_low;
+	int ichg_meas_ma, iterm_programmed;
+	int regulation_loop, fast_chg, vcp;
+	int rc;
+	static int last_vbat_programmed = -EINVAL;
+
+	if (!is_ext_charging(chip)) {
+		/* return if the battery is not being fastcharged */
+		fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
+		pr_debug("fast_chg = %d\n", fast_chg);
+		if (fast_chg == 0)
+			return CHG_NOT_IN_PROGRESS;
+
+		vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
+		pr_debug("vcp = %d\n", vcp);
+		if (vcp == 1)
+			return CHG_IN_PROGRESS;
+
+		vbatdet_low = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
+		pr_debug("vbatdet_low = %d\n", vbatdet_low);
+		if (vbatdet_low == 1)
+			return CHG_IN_PROGRESS;
+
+		/* reset count if battery is hot/cold */
+		rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
+		pr_debug("batt_temp_ok = %d\n", rc);
+		if (rc == 0)
+			return CHG_IN_PROGRESS;
+
+		/* reset count if battery voltage is less than vddmax */
+		vbat_meas_uv = get_prop_battery_uvolts(chip);
+		if (vbat_meas_uv < 0)
+			return CHG_IN_PROGRESS;
+		vbat_meas_mv = vbat_meas_uv / 1000;
+
+		rc = pm_chg_vddmax_get(chip, &vbat_programmed);
+		if (rc) {
+			pr_err("couldnt read vddmax rc = %d\n", rc);
+			return CHG_IN_PROGRESS;
+		}
+		pr_debug("vddmax = %d vbat_meas_mv=%d\n",
+			 vbat_programmed, vbat_meas_mv);
+		if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
+			return CHG_IN_PROGRESS;
+
+		if (last_vbat_programmed == -EINVAL)
+			last_vbat_programmed = vbat_programmed;
+		if (last_vbat_programmed !=  vbat_programmed) {
+			/* vddmax changed, reset and check again */
+			pr_debug("vddmax = %d last_vdd_max=%d\n",
+				 vbat_programmed, last_vbat_programmed);
+			last_vbat_programmed = vbat_programmed;
+			return CHG_IN_PROGRESS;
+		}
+
+		/*
+		 * TODO if charging from an external charger
+		 * check SOC instead of regulation loop
+		 */
+		regulation_loop = pm_chg_get_regulation_loop(chip);
+		if (regulation_loop < 0) {
+			pr_err("couldnt read the regulation loop err=%d\n",
+				regulation_loop);
+			return CHG_IN_PROGRESS;
+		}
+		pr_debug("regulation_loop=%d\n", regulation_loop);
+
+		if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
+			return CHG_IN_PROGRESS;
+	} /* !is_ext_charging */
+
+	/* reset count if battery chg current is more than iterm */
+	rc = pm_chg_iterm_get(chip, &iterm_programmed);
+	if (rc) {
+		pr_err("couldnt read iterm rc = %d\n", rc);
+		return CHG_IN_PROGRESS;
+	}
+
+	ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
+	pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
+				iterm_programmed, ichg_meas_ma);
+	/*
+	 * ichg_meas_ma < 0 means battery is drawing current
+	 * ichg_meas_ma > 0 means battery is providing current
+	 */
+	if (ichg_meas_ma > 0)
+		return CHG_IN_PROGRESS;
+
+	if (ichg_meas_ma * -1 > iterm_programmed)
+		return CHG_IN_PROGRESS;
+
+	return CHG_FINISHED;
+}
+
 /**
  * eoc_worker - internal function to check if battery EOC
  *		has happened
@@ -1923,105 +2173,27 @@
  * happened
  */
 #define CONSECUTIVE_COUNT	3
-#define VBAT_TOLERANCE_MV	70
-#define CHG_DISABLE_MSLEEP	100
 static void eoc_worker(struct work_struct *work)
 {
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct pm8921_chg_chip *chip = container_of(dwork,
 				struct pm8921_chg_chip, eoc_work);
-	int vbat_meas_uv, vbat_meas_mv, vbat_programmed;
-	int ichg_meas_ma, iterm_programmed;
-	int regulation_loop, fast_chg, vcp;
-	int rc;
 	static int count;
-	static int last_vbat_programmed = -EINVAL;
+	int end = is_charging_finished(chip);
 
-	if (!is_ext_charging(chip)) {
-		/* return if the battery is not being fastcharged */
-		fast_chg = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
-		pr_debug("fast_chg = %d\n", fast_chg);
-		if (fast_chg == 0) {
+	if (end == CHG_NOT_IN_PROGRESS) {
 			/* enable fastchg irq */
 			count = 0;
 			wake_unlock(&chip->eoc_wake_lock);
 			return;
-		}
-
-		vcp = pm_chg_get_rt_status(chip, VCP_IRQ);
-		pr_debug("vcp = %d\n", vcp);
-		if (vcp == 1)
-			goto reset_and_reschedule;
-
-		/* reset count if battery is hot/cold */
-		rc = pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ);
-		pr_debug("batt_temp_ok = %d\n", rc);
-		if (rc == 0)
-			goto reset_and_reschedule;
-
-		/* reset count if battery voltage is less than vddmax */
-		vbat_meas_uv = get_prop_battery_uvolts(chip);
-		if (vbat_meas_uv < 0)
-			goto reset_and_reschedule;
-		vbat_meas_mv = vbat_meas_uv / 1000;
-
-		rc = pm_chg_vddmax_get(chip, &vbat_programmed);
-		if (rc) {
-			pr_err("couldnt read vddmax rc = %d\n", rc);
-			goto reset_and_reschedule;
-		}
-		pr_debug("vddmax = %d vbat_meas_mv=%d\n",
-			 vbat_programmed, vbat_meas_mv);
-		if (vbat_meas_mv < vbat_programmed - VBAT_TOLERANCE_MV)
-			goto reset_and_reschedule;
-
-		if (last_vbat_programmed == -EINVAL)
-			last_vbat_programmed = vbat_programmed;
-		if (last_vbat_programmed !=  vbat_programmed) {
-			/* vddmax changed, reset and check again */
-			pr_debug("vddmax = %d last_vdd_max=%d\n",
-				 vbat_programmed, last_vbat_programmed);
-			last_vbat_programmed = vbat_programmed;
-			goto reset_and_reschedule;
-		}
-
-		/*
-		 * TODO if charging from an external charger
-		 * check SOC instead of regulation loop
-		 */
-		regulation_loop = pm_chg_get_regulation_loop(chip);
-		if (regulation_loop < 0) {
-			pr_err("couldnt read the regulation loop err=%d\n",
-				regulation_loop);
-			goto reset_and_reschedule;
-		}
-		pr_debug("regulation_loop=%d\n", regulation_loop);
-
-		if (regulation_loop != 0 && regulation_loop != VDD_LOOP)
-			goto reset_and_reschedule;
-	} /* !is_ext_charging */
-
-	/* reset count if battery chg current is more than iterm */
-	rc = pm_chg_iterm_get(chip, &iterm_programmed);
-	if (rc) {
-		pr_err("couldnt read iterm rc = %d\n", rc);
-		goto reset_and_reschedule;
 	}
 
-	ichg_meas_ma = (get_prop_batt_current(chip)) / 1000;
-	pr_debug("iterm_programmed = %d ichg_meas_ma=%d\n",
-				iterm_programmed, ichg_meas_ma);
-	/*
-	 * ichg_meas_ma < 0 means battery is drawing current
-	 * ichg_meas_ma > 0 means battery is providing current
-	 */
-	if (ichg_meas_ma > 0)
-		goto reset_and_reschedule;
+	if (end == CHG_FINISHED) {
+		count++;
+	} else {
+		count = 0;
+	}
 
-	if (ichg_meas_ma * -1 > iterm_programmed)
-		goto reset_and_reschedule;
-
-	count++;
 	if (count == CONSECUTIVE_COUNT) {
 		count = 0;
 		pr_info("End of Charging\n");
@@ -2038,18 +2210,12 @@
 		/* declare end of charging by invoking chgdone interrupt */
 		chgdone_irq_handler(chip->pmic_chg_irq[CHGDONE_IRQ], chip);
 		wake_unlock(&chip->eoc_wake_lock);
-		return;
 	} else {
 		pr_debug("EOC count = %d\n", count);
-		goto reschedule;
-	}
-
-reset_and_reschedule:
-	count = 0;
-reschedule:
-	schedule_delayed_work(&chip->eoc_work,
+		schedule_delayed_work(&chip->eoc_work,
 			      round_jiffies_relative(msecs_to_jiffies
 						     (EOC_CHECK_PERIOD_MS)));
+	}
 }
 
 static void btm_configure_work(struct work_struct *work)
@@ -2150,36 +2316,6 @@
 	return rc;
 }
 
-int register_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
-	if (the_chip == NULL) {
-		pr_err("called too early\n");
-		return -EINVAL;
-	}
-	/* TODO check function pointers */
-	the_chip->ext = ext;
-	the_chip->ext_charging = false;
-
-	if (is_dc_chg_plugged_in(the_chip))
-		pm8921_disable_source_current(true); /* Force BATFET=ON */
-
-	handle_start_ext_chg(the_chip);
-
-	return 0;
-}
-EXPORT_SYMBOL(register_external_dc_charger);
-
-void unregister_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
-	if (the_chip == NULL) {
-		pr_err("called too early\n");
-		return;
-	}
-	handle_stop_ext_chg(the_chip);
-	the_chip->ext = NULL;
-}
-EXPORT_SYMBOL(unregister_external_dc_charger);
-
 /**
  * set_disable_status_param -
  *
@@ -2258,7 +2394,7 @@
 		}
 }
 
-/* determines the initial present states and notifies msm_charger */
+/* determines the initial present states */
 static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
 {
 	unsigned long flags;
@@ -2268,6 +2404,11 @@
 	chip->usb_present = !!is_usb_chg_plugged_in(chip);
 
 	notify_usb_of_the_plugin_event(chip->usb_present);
+	if (chip->usb_present) {
+		schedule_delayed_work(&chip->unplug_check_work,
+			round_jiffies_relative(msecs_to_jiffies
+				(UNPLUG_CHECK_WAIT_PERIOD_MS)));
+	}
 
 	pm8921_chg_enable_irq(chip, DCIN_VALID_IRQ);
 	pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
@@ -2499,6 +2640,8 @@
 							chip->vin_min, rc);
 			return rc;
 		}
+	} else {
+		chip->vin_min = pm_chg_vinmin_get(chip);
 	}
 
 	rc = pm_chg_disable_wd(chip);
@@ -2790,6 +2933,10 @@
 		if (rc)
 			pr_err("couldn't restart btm rc=%d\n", rc);
 	}
+	if (pm8921_chg_is_enabled(chip, LOOP_CHANGE_IRQ)) {
+		disable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
+		pm8921_chg_disable_irq(chip, LOOP_CHANGE_IRQ);
+	}
 	return 0;
 }
 
@@ -2804,6 +2951,11 @@
 		if (rc)
 			pr_err("Failed to disable BTM on suspend rc=%d\n", rc);
 	}
+
+	if (is_usb_chg_plugged_in(chip)) {
+		pm8921_chg_enable_irq(chip, LOOP_CHANGE_IRQ);
+		enable_irq_wake(chip->pmic_chg_irq[LOOP_CHANGE_IRQ]);
+	}
 	return 0;
 }
 static int __devinit pm8921_charger_probe(struct platform_device *pdev)
@@ -2872,43 +3024,34 @@
 	chip->usb_psy.num_properties = ARRAY_SIZE(pm_power_props),
 	chip->usb_psy.get_property = pm_power_get_property,
 
-	chip->dc_psy.name = "ac",
-	chip->dc_psy.type = POWER_SUPPLY_TYPE_MAINS,
-	chip->dc_psy.supplied_to = pm_power_supplied_to,
-	chip->dc_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to),
-	chip->dc_psy.properties = pm_power_props,
-	chip->dc_psy.num_properties = ARRAY_SIZE(pm_power_props),
-	chip->dc_psy.get_property = pm_power_get_property,
-
 	chip->batt_psy.name = "battery",
 	chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY,
 	chip->batt_psy.properties = msm_batt_power_props,
 	chip->batt_psy.num_properties = ARRAY_SIZE(msm_batt_power_props),
 	chip->batt_psy.get_property = pm_batt_power_get_property,
-
+	chip->batt_psy.external_power_changed = pm_batt_external_power_changed,
 	rc = power_supply_register(chip->dev, &chip->usb_psy);
 	if (rc < 0) {
 		pr_err("power_supply_register usb failed rc = %d\n", rc);
 		goto free_chip;
 	}
 
-	rc = power_supply_register(chip->dev, &chip->dc_psy);
-	if (rc < 0) {
-		pr_err("power_supply_register dc failed rc = %d\n", rc);
-		goto unregister_usb;
-	}
-
 	rc = power_supply_register(chip->dev, &chip->batt_psy);
 	if (rc < 0) {
 		pr_err("power_supply_register batt failed rc = %d\n", rc);
-		goto unregister_dc;
+		goto unregister_usb;
 	}
 
 	platform_set_drvdata(pdev, chip);
 	the_chip = chip;
 
 	wake_lock_init(&chip->eoc_wake_lock, WAKE_LOCK_SUSPEND, "pm8921_eoc");
+	wake_lock_init(&chip->unplug_wrkarnd_restore_wake_lock,
+			WAKE_LOCK_SUSPEND, "pm8921_unplug_wrkarnd");
 	INIT_DELAYED_WORK(&chip->eoc_work, eoc_worker);
+	INIT_DELAYED_WORK(&chip->unplug_wrkarnd_restore_work,
+					unplug_wrkarnd_restore_worker);
+	INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
 
 	rc = request_irqs(chip, pdev);
 	if (rc) {
@@ -2954,8 +3097,6 @@
 	free_irqs(chip);
 unregister_batt:
 	power_supply_unregister(&chip->batt_psy);
-unregister_dc:
-	power_supply_unregister(&chip->dc_psy);
 unregister_usb:
 	power_supply_unregister(&chip->usb_psy);
 free_chip:
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index a184ab6..fc5970c 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -47,11 +47,11 @@
 EXPORT_SYMBOL_GPL(power_supply_set_current_limit);
 
 /**
- * power_supply_set_charging_by - set charging state of the charger
+ * power_supply_set_online - set online state of the power supply
  * @psy:	the power supply to control
- * @enable:	enables or disables the charger
+ * @enable:	sets online property of power supply
  */
-int power_supply_set_charging_by(struct power_supply *psy, bool enable)
+int power_supply_set_online(struct power_supply *psy, bool enable)
 {
 	const union power_supply_propval ret = {enable,};
 
@@ -61,7 +61,24 @@
 
 	return -ENXIO;
 }
-EXPORT_SYMBOL_GPL(power_supply_set_charging_by);
+EXPORT_SYMBOL_GPL(power_supply_set_online);
+
+/**
+ * power_supply_set_charge_type - set charge type of the power supply
+ * @psy:	the power supply to control
+ * @enable:	sets charge type property of power supply
+ */
+int power_supply_set_charge_type(struct power_supply *psy, int charge_type)
+{
+	const union power_supply_propval ret = {charge_type,};
+
+	if (psy->set_property)
+		return psy->set_property(psy, POWER_SUPPLY_PROP_CHARGE_TYPE,
+								&ret);
+
+	return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(power_supply_set_charge_type);
 
 static int __power_supply_changed_work(struct device *dev, void *data)
 {
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index aaeb790..17b9f0d 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -38,608 +38,49 @@
 #include <linux/gpio.h>
 #include <linux/remote_spinlock.h>
 #include <linux/pm_qos_params.h>
+#include <linux/of.h>
+#include "spi_qsd.h"
 
-#define SPI_DRV_NAME                  "spi_qsd"
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
-
-#define QSD_REG(x) (x)
-#define QUP_REG(x)
-
-#define SPI_FIFO_WORD_CNT             0x0048
-
-#elif defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
-
-#define QSD_REG(x)
-#define QUP_REG(x) (x)
-
-#define QUP_CONFIG                    0x0000 /* N & NO_INPUT/NO_OUPUT bits */
-#define QUP_ERROR_FLAGS               0x0308
-#define QUP_ERROR_FLAGS_EN            0x030C
-#define QUP_ERR_MASK                  0x3
-#define SPI_OUTPUT_FIFO_WORD_CNT      0x010C
-#define SPI_INPUT_FIFO_WORD_CNT       0x0214
-#define QUP_MX_WRITE_COUNT            0x0150
-#define QUP_MX_WRITE_CNT_CURRENT      0x0154
-
-#define QUP_CONFIG_SPI_MODE           0x0100
-
-#define GSBI_CTRL_REG                 0x0
-#define GSBI_SPI_CONFIG               0x30
-#endif
-
-#define SPI_CONFIG                    QSD_REG(0x0000) QUP_REG(0x0300)
-#define SPI_IO_CONTROL                QSD_REG(0x0004) QUP_REG(0x0304)
-#define SPI_IO_MODES                  QSD_REG(0x0008) QUP_REG(0x0008)
-#define SPI_SW_RESET                  QSD_REG(0x000C) QUP_REG(0x000C)
-#define SPI_TIME_OUT                  QSD_REG(0x0010) QUP_REG(0x0010)
-#define SPI_TIME_OUT_CURRENT          QSD_REG(0x0014) QUP_REG(0x0014)
-#define SPI_MX_OUTPUT_COUNT           QSD_REG(0x0018) QUP_REG(0x0100)
-#define SPI_MX_OUTPUT_CNT_CURRENT     QSD_REG(0x001C) QUP_REG(0x0104)
-#define SPI_MX_INPUT_COUNT            QSD_REG(0x0020) QUP_REG(0x0200)
-#define SPI_MX_INPUT_CNT_CURRENT      QSD_REG(0x0024) QUP_REG(0x0204)
-#define SPI_MX_READ_COUNT             QSD_REG(0x0028) QUP_REG(0x0208)
-#define SPI_MX_READ_CNT_CURRENT       QSD_REG(0x002C) QUP_REG(0x020C)
-#define SPI_OPERATIONAL               QSD_REG(0x0030) QUP_REG(0x0018)
-#define SPI_ERROR_FLAGS               QSD_REG(0x0034) QUP_REG(0x001C)
-#define SPI_ERROR_FLAGS_EN            QSD_REG(0x0038) QUP_REG(0x0020)
-#define SPI_DEASSERT_WAIT             QSD_REG(0x003C) QUP_REG(0x0310)
-#define SPI_OUTPUT_DEBUG              QSD_REG(0x0040) QUP_REG(0x0108)
-#define SPI_INPUT_DEBUG               QSD_REG(0x0044) QUP_REG(0x0210)
-#define SPI_TEST_CTRL                 QSD_REG(0x004C) QUP_REG(0x0024)
-#define SPI_OUTPUT_FIFO               QSD_REG(0x0100) QUP_REG(0x0110)
-#define SPI_INPUT_FIFO                QSD_REG(0x0200) QUP_REG(0x0218)
-#define SPI_STATE                     QSD_REG(SPI_OPERATIONAL) QUP_REG(0x0004)
-
-/* SPI_CONFIG fields */
-#define SPI_CFG_INPUT_FIRST           0x00000200
-#define SPI_NO_INPUT                  0x00000080
-#define SPI_NO_OUTPUT                 0x00000040
-#define SPI_CFG_LOOPBACK              0x00000100
-#define SPI_CFG_N                     0x0000001F
-
-/* SPI_IO_CONTROL fields */
-#define SPI_IO_C_CLK_IDLE_HIGH        0x00000400
-#define SPI_IO_C_MX_CS_MODE           0x00000100
-#define SPI_IO_C_CS_N_POLARITY        0x000000F0
-#define SPI_IO_C_CS_N_POLARITY_0      0x00000010
-#define SPI_IO_C_CS_SELECT            0x0000000C
-#define SPI_IO_C_TRISTATE_CS          0x00000002
-#define SPI_IO_C_NO_TRI_STATE         0x00000001
-
-/* SPI_IO_MODES fields */
-#define SPI_IO_M_OUTPUT_BIT_SHIFT_EN  QSD_REG(0x00004000) QUP_REG(0x00010000)
-#define SPI_IO_M_PACK_EN              QSD_REG(0x00002000) QUP_REG(0x00008000)
-#define SPI_IO_M_UNPACK_EN            QSD_REG(0x00001000) QUP_REG(0x00004000)
-#define SPI_IO_M_INPUT_MODE           QSD_REG(0x00000C00) QUP_REG(0x00003000)
-#define SPI_IO_M_OUTPUT_MODE          QSD_REG(0x00000300) QUP_REG(0x00000C00)
-#define SPI_IO_M_INPUT_FIFO_SIZE      QSD_REG(0x000000C0) QUP_REG(0x00000380)
-#define SPI_IO_M_INPUT_BLOCK_SIZE     QSD_REG(0x00000030) QUP_REG(0x00000060)
-#define SPI_IO_M_OUTPUT_FIFO_SIZE     QSD_REG(0x0000000C) QUP_REG(0x0000001C)
-#define SPI_IO_M_OUTPUT_BLOCK_SIZE    QSD_REG(0x00000003) QUP_REG(0x00000003)
-
-#define INPUT_BLOCK_SZ_SHIFT          QSD_REG(4)          QUP_REG(5)
-#define INPUT_FIFO_SZ_SHIFT           QSD_REG(6)          QUP_REG(7)
-#define OUTPUT_BLOCK_SZ_SHIFT         QSD_REG(0)          QUP_REG(0)
-#define OUTPUT_FIFO_SZ_SHIFT          QSD_REG(2)          QUP_REG(2)
-#define OUTPUT_MODE_SHIFT             QSD_REG(8)          QUP_REG(10)
-#define INPUT_MODE_SHIFT              QSD_REG(10)         QUP_REG(12)
-
-/* SPI_OPERATIONAL fields */
-#define SPI_OP_MAX_INPUT_DONE_FLAG    0x00000800
-#define SPI_OP_MAX_OUTPUT_DONE_FLAG   0x00000400
-#define SPI_OP_INPUT_SERVICE_FLAG     0x00000200
-#define SPI_OP_OUTPUT_SERVICE_FLAG    0x00000100
-#define SPI_OP_INPUT_FIFO_FULL        0x00000080
-#define SPI_OP_OUTPUT_FIFO_FULL       0x00000040
-#define SPI_OP_IP_FIFO_NOT_EMPTY      0x00000020
-#define SPI_OP_OP_FIFO_NOT_EMPTY      0x00000010
-#define SPI_OP_STATE_VALID            0x00000004
-#define SPI_OP_STATE                  0x00000003
-
-#define SPI_OP_STATE_CLEAR_BITS       0x2
-enum msm_spi_state {
-	SPI_OP_STATE_RESET = 0x00000000,
-	SPI_OP_STATE_RUN   = 0x00000001,
-	SPI_OP_STATE_PAUSE = 0x00000003,
-};
-
-/* SPI_ERROR_FLAGS fields */
-#define SPI_ERR_OUTPUT_OVER_RUN_ERR   0x00000020
-#define SPI_ERR_INPUT_UNDER_RUN_ERR   0x00000010
-#define SPI_ERR_OUTPUT_UNDER_RUN_ERR  0x00000008
-#define SPI_ERR_INPUT_OVER_RUN_ERR    0x00000004
-#define SPI_ERR_CLK_OVER_RUN_ERR      0x00000002
-#define SPI_ERR_CLK_UNDER_RUN_ERR     0x00000001
-
-/* We don't allow transactions larger than 4K-64 or 64K-64 due to
-   mx_input/output_cnt register size */
-#define SPI_MAX_TRANSFERS             QSD_REG(0xFC0) QUP_REG(0xFC0)
-#define SPI_MAX_LEN                   (SPI_MAX_TRANSFERS * dd->bytes_per_word)
-
-#define SPI_NUM_CHIPSELECTS           4
-#define SPI_SUPPORTED_MODES  (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP)
-
-#define SPI_DELAY_THRESHOLD           1
-/* Default timeout is 10 milliseconds */
-#define SPI_DEFAULT_TIMEOUT           10
-/* 250 microseconds */
-#define SPI_TRYLOCK_DELAY             250
-
-/* Data Mover burst size */
-#define DM_BURST_SIZE                 16
-/* Data Mover commands should be aligned to 64 bit(8 bytes) */
-#define DM_BYTE_ALIGN                 8
-
-static char const * const spi_rsrcs[] = {
-	"spi_clk",
-	"spi_miso",
-	"spi_mosi"
-};
-
-static char const * const spi_cs_rsrcs[] = {
-	"spi_cs",
-	"spi_cs1",
-	"spi_cs2",
-	"spi_cs3",
-};
-
-enum msm_spi_mode {
-	SPI_FIFO_MODE  = 0x0,  /* 00 */
-	SPI_BLOCK_MODE = 0x1,  /* 01 */
-	SPI_DMOV_MODE  = 0x2,  /* 10 */
-	SPI_MODE_NONE  = 0xFF, /* invalid value */
-};
-
-/* Structure for SPI CS GPIOs */
-struct spi_cs_gpio {
-	int  gpio_num;
-	bool valid;
-};
-
-/* Structures for Data Mover */
-struct spi_dmov_cmd {
-	dmov_box box;      /* data aligned to max(dm_burst_size, block_size)
-							   (<= fifo_size) */
-	dmov_s single_pad; /* data unaligned to max(dm_burst_size, block_size)
-			      padded to fit */
-	dma_addr_t cmd_ptr;
-};
-
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION("0.3");
-MODULE_ALIAS("platform:"SPI_DRV_NAME);
-
-static struct pm_qos_request_list qos_req_list;
-
-#ifdef CONFIG_DEBUG_FS
-/* Used to create debugfs entries */
-static const struct {
-	const char *name;
-	mode_t mode;
-	int offset;
-} debugfs_spi_regs[] = {
-	{"config",                S_IRUGO | S_IWUSR, SPI_CONFIG},
-	{"io_control",            S_IRUGO | S_IWUSR, SPI_IO_CONTROL},
-	{"io_modes",              S_IRUGO | S_IWUSR, SPI_IO_MODES},
-	{"sw_reset",                        S_IWUSR, SPI_SW_RESET},
-	{"time_out",              S_IRUGO | S_IWUSR, SPI_TIME_OUT},
-	{"time_out_current",      S_IRUGO,           SPI_TIME_OUT_CURRENT},
-	{"mx_output_count",       S_IRUGO | S_IWUSR, SPI_MX_OUTPUT_COUNT},
-	{"mx_output_cnt_current", S_IRUGO,           SPI_MX_OUTPUT_CNT_CURRENT},
-	{"mx_input_count",        S_IRUGO | S_IWUSR, SPI_MX_INPUT_COUNT},
-	{"mx_input_cnt_current",  S_IRUGO,           SPI_MX_INPUT_CNT_CURRENT},
-	{"mx_read_count",         S_IRUGO | S_IWUSR, SPI_MX_READ_COUNT},
-	{"mx_read_cnt_current",   S_IRUGO,           SPI_MX_READ_CNT_CURRENT},
-	{"operational",           S_IRUGO | S_IWUSR, SPI_OPERATIONAL},
-	{"error_flags",           S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS},
-	{"error_flags_en",        S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS_EN},
-	{"deassert_wait",         S_IRUGO | S_IWUSR, SPI_DEASSERT_WAIT},
-	{"output_debug",          S_IRUGO,           SPI_OUTPUT_DEBUG},
-	{"input_debug",           S_IRUGO,           SPI_INPUT_DEBUG},
-	{"test_ctrl",             S_IRUGO | S_IWUSR, SPI_TEST_CTRL},
-	{"output_fifo",                     S_IWUSR, SPI_OUTPUT_FIFO},
-	{"input_fifo" ,           S_IRUSR,           SPI_INPUT_FIFO},
-	{"spi_state",             S_IRUGO | S_IWUSR, SPI_STATE},
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
-	{"fifo_word_cnt",         S_IRUGO,           SPI_FIFO_WORD_CNT},
-#elif defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
-	{"qup_config",            S_IRUGO | S_IWUSR, QUP_CONFIG},
-	{"qup_error_flags",       S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS},
-	{"qup_error_flags_en",    S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS_EN},
-	{"mx_write_cnt",          S_IRUGO | S_IWUSR, QUP_MX_WRITE_COUNT},
-	{"mx_write_cnt_current",  S_IRUGO,           QUP_MX_WRITE_CNT_CURRENT},
-	{"output_fifo_word_cnt",  S_IRUGO,           SPI_OUTPUT_FIFO_WORD_CNT},
-	{"input_fifo_word_cnt",   S_IRUGO,           SPI_INPUT_FIFO_WORD_CNT},
-#endif
-};
-#endif
-
-struct msm_spi {
-	u8                      *read_buf;
-	const u8                *write_buf;
-	void __iomem            *base;
-	void __iomem            *gsbi_base;
-	struct device           *dev;
-	spinlock_t               queue_lock;
-	struct mutex             core_lock;
-	struct list_head         queue;
-	struct workqueue_struct *workqueue;
-	struct work_struct       work_data;
-	struct spi_message      *cur_msg;
-	struct spi_transfer     *cur_transfer;
-	struct completion        transfer_complete;
-	struct clk              *clk;
-	struct clk              *pclk;
-	unsigned long            mem_phys_addr;
-	size_t                   mem_size;
-	unsigned long            gsbi_mem_phys_addr;
-	size_t                   gsbi_mem_size;
-	int                      input_fifo_size;
-	int                      output_fifo_size;
-	u32                      rx_bytes_remaining;
-	u32                      tx_bytes_remaining;
-	u32                      clock_speed;
-	int                      irq_in;
-	int                      read_xfr_cnt;
-	int                      write_xfr_cnt;
-	int                      write_len;
-	int                      read_len;
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
-	int                      irq_out;
-	int                      irq_err;
-#endif
-	int                      bytes_per_word;
-	bool                     suspended;
-	bool                     transfer_pending;
-	wait_queue_head_t        continue_suspend;
-	/* DMA data */
-	enum msm_spi_mode        mode;
-	bool                     use_dma;
-	int                      tx_dma_chan;
-	int                      tx_dma_crci;
-	int                      rx_dma_chan;
-	int                      rx_dma_crci;
-	/* Data Mover Commands */
-	struct spi_dmov_cmd      *tx_dmov_cmd;
-	struct spi_dmov_cmd      *rx_dmov_cmd;
-	/* Physical address of the tx dmov box command */
-	dma_addr_t               tx_dmov_cmd_dma;
-	dma_addr_t               rx_dmov_cmd_dma;
-	struct msm_dmov_cmd      tx_hdr;
-	struct msm_dmov_cmd      rx_hdr;
-	int                      input_block_size;
-	int                      output_block_size;
-	int                      burst_size;
-	atomic_t                 rx_irq_called;
-	/* Used to pad messages unaligned to block size */
-	u8                       *tx_padding;
-	dma_addr_t               tx_padding_dma;
-	u8                       *rx_padding;
-	dma_addr_t               rx_padding_dma;
-	u32                      unaligned_len;
-	/* DMA statistics */
-	int                      stat_dmov_tx_err;
-	int                      stat_dmov_rx_err;
-	int                      stat_rx;
-	int                      stat_dmov_rx;
-	int                      stat_tx;
-	int                      stat_dmov_tx;
-#ifdef CONFIG_DEBUG_FS
-	struct dentry *dent_spi;
-	struct dentry *debugfs_spi_regs[ARRAY_SIZE(debugfs_spi_regs)];
-#endif
-	struct msm_spi_platform_data *pdata; /* Platform data */
-	/* Remote Spinlock Data */
-	bool                     use_rlock;
-	remote_mutex_t           r_lock;
-	uint32_t                 pm_lat;
-	/* When set indicates multiple transfers in a single message */
-	bool                     multi_xfr;
-	bool                     done;
-	u32                      cur_msg_len;
-	/* Used in FIFO mode to keep track of the transfer being processed */
-	struct spi_transfer     *cur_tx_transfer;
-	struct spi_transfer     *cur_rx_transfer;
-	/* Temporary buffer used for WR-WR or WR-RD transfers */
-	u8                      *temp_buf;
-	/* GPIO pin numbers for SPI clk, miso and mosi */
-	int                      spi_gpios[ARRAY_SIZE(spi_rsrcs)];
-	/* SPI CS GPIOs for each slave */
-	struct spi_cs_gpio       cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
-};
-
-/* Forward declaration */
-static irqreturn_t msm_spi_input_irq(int irq, void *dev_id);
-static irqreturn_t msm_spi_output_irq(int irq, void *dev_id);
-static irqreturn_t msm_spi_error_irq(int irq, void *dev_id);
-static inline int msm_spi_set_state(struct msm_spi *dd,
-				    enum msm_spi_state state);
-static void msm_spi_write_word_to_fifo(struct msm_spi *dd);
-static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd);
-
-#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
-/* Interrupt Handling */
-static inline int msm_spi_get_irq_data(struct msm_spi *dd,
-				       struct platform_device *pdev)
-{
-	dd->irq_in  = platform_get_irq_byname(pdev, "spi_irq_in");
-	dd->irq_out = platform_get_irq_byname(pdev, "spi_irq_out");
-	dd->irq_err = platform_get_irq_byname(pdev, "spi_irq_err");
-	if ((dd->irq_in < 0) || (dd->irq_out < 0) || (dd->irq_err < 0))
-		return -1;
-	return 0;
-}
-
-static inline int msm_spi_get_gsbi_resource(struct msm_spi *dd,
-					    struct platform_device *pdev)
-{
-	return 0;
-}
-
-static inline int msm_spi_request_gsbi(struct msm_spi *dd) { return 0; }
-static inline void msm_spi_release_gsbi(struct msm_spi *dd) {}
-static inline void msm_spi_init_gsbi(struct msm_spi *dd) {}
-
-static inline void msm_spi_disable_irqs(struct msm_spi *dd)
-{
-	disable_irq(dd->irq_in);
-	disable_irq(dd->irq_out);
-	disable_irq(dd->irq_err);
-}
-
-static inline void msm_spi_enable_irqs(struct msm_spi *dd)
-{
-	enable_irq(dd->irq_in);
-	enable_irq(dd->irq_out);
-	enable_irq(dd->irq_err);
-}
-
-static inline int msm_spi_request_irq(struct msm_spi *dd,
-				      const char *name,
-				      struct spi_master *master)
-{
-	int rc;
-	rc = request_irq(dd->irq_in, msm_spi_input_irq, IRQF_TRIGGER_RISING,
-			   name, dd);
-	if (rc)
-		goto error_irq1;
-	rc = request_irq(dd->irq_out, msm_spi_output_irq, IRQF_TRIGGER_RISING,
-			   name, dd);
-	if (rc)
-		goto error_irq2;
-	rc = request_irq(dd->irq_err, msm_spi_error_irq, IRQF_TRIGGER_RISING,
-			   name, master);
-	if (rc)
-		goto error_irq3;
-	return 0;
-
-error_irq3:
-	free_irq(dd->irq_out, dd);
-error_irq2:
-	free_irq(dd->irq_in, dd);
-error_irq1:
-	return rc;
-}
-
-static inline void msm_spi_free_irq(struct msm_spi *dd,
-				    struct spi_master *master)
-{
-	free_irq(dd->irq_err, master);
-	free_irq(dd->irq_out, dd);
-	free_irq(dd->irq_in, dd);
-}
-
-static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err) {}
-static inline void msm_spi_ack_clk_err(struct msm_spi *dd) {}
-static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw) {}
-
-static inline int msm_spi_prepare_for_write(struct msm_spi *dd) { return 0; }
-static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
-{
-	msm_spi_write_word_to_fifo(dd);
-}
-static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) {}
-
-static inline void msm_spi_complete(struct msm_spi *dd)
-{
-	complete(&dd->transfer_complete);
-}
-
-static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
-{
-	writel_relaxed(0x0000007B, dd->base + SPI_ERROR_FLAGS_EN);
-}
-
-static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
-{
-	writel_relaxed(0x0000007F, dd->base + SPI_ERROR_FLAGS);
-}
-
-#elif defined(CONFIG_SPI_QUP) || defined(CONFIG_SPI_QUP_MODULE)
-
-/* Interrupt Handling */
-/* In QUP the same interrupt line is used for intput, output and error*/
-static inline int msm_spi_get_irq_data(struct msm_spi *dd,
-				       struct platform_device *pdev)
-{
-	dd->irq_in  = platform_get_irq_byname(pdev, "spi_irq_in");
-	if (dd->irq_in < 0)
-		return -1;
-	return 0;
-}
-
-static inline int msm_spi_get_gsbi_resource(struct msm_spi *dd,
-				       struct platform_device *pdev)
+static inline int msm_spi_configure_gsbi(struct msm_spi *dd,
+					struct platform_device *pdev)
 {
 	struct resource *resource;
+	unsigned long   gsbi_mem_phys_addr;
+	size_t          gsbi_mem_size;
+	void __iomem    *gsbi_base;
 
-	resource  = platform_get_resource_byname(pdev,
-						 IORESOURCE_MEM, "gsbi_base");
+	resource  = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	if (!resource)
+		return 0;
+
+	gsbi_mem_phys_addr = resource->start;
+	gsbi_mem_size = resource_size(resource);
+	if (!devm_request_mem_region(&pdev->dev, gsbi_mem_phys_addr,
+					gsbi_mem_size, SPI_DRV_NAME))
 		return -ENXIO;
-	dd->gsbi_mem_phys_addr = resource->start;
-	dd->gsbi_mem_size = resource_size(resource);
+
+	gsbi_base = devm_ioremap(&pdev->dev, gsbi_mem_phys_addr,
+					gsbi_mem_size);
+	if (!gsbi_base)
+		return -ENXIO;
+
+	/* Set GSBI to SPI mode */
+	writel_relaxed(GSBI_SPI_CONFIG, gsbi_base + GSBI_CTRL_REG);
 
 	return 0;
 }
 
-static inline void msm_spi_release_gsbi(struct msm_spi *dd)
+static inline void msm_spi_register_init(struct msm_spi *dd)
 {
-	iounmap(dd->gsbi_base);
-	release_mem_region(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size);
+	writel_relaxed(0x00000001, dd->base + SPI_SW_RESET);
+	msm_spi_set_state(dd, SPI_OP_STATE_RESET);
+	writel_relaxed(0x00000000, dd->base + SPI_OPERATIONAL);
+	writel_relaxed(0x00000000, dd->base + SPI_CONFIG);
+	writel_relaxed(0x00000000, dd->base + SPI_IO_MODES);
+	if (dd->qup_ver)
+		writel_relaxed(0x00000000, dd->base + QUP_OPERATIONAL_MASK);
 }
 
-static inline int msm_spi_request_gsbi(struct msm_spi *dd)
-{
-	if (!request_mem_region(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size,
-				SPI_DRV_NAME)) {
-		return -ENXIO;
-	}
-	dd->gsbi_base = ioremap(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size);
-	if (!dd->gsbi_base) {
-		release_mem_region(dd->gsbi_mem_phys_addr, dd->gsbi_mem_size);
-		return -ENXIO;
-	}
-	return 0;
-}
-
-static inline void msm_spi_init_gsbi(struct msm_spi *dd)
-{
-	/* Set GSBI to SPI mode, and CRCI_MUX_CTRL to SPI CRCI ports */
-	writel_relaxed(GSBI_SPI_CONFIG, dd->gsbi_base + GSBI_CTRL_REG);
-}
-
-/* Figure which irq occured and call the relevant functions */
-static irqreturn_t msm_spi_qup_irq(int irq, void *dev_id)
-{
-	u32 op, ret = IRQ_NONE;
-	struct msm_spi *dd = dev_id;
-
-	if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
-	    readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
-		struct spi_master *master = dev_get_drvdata(dd->dev);
-		ret |= msm_spi_error_irq(irq, master);
-	}
-
-	op = readl_relaxed(dd->base + SPI_OPERATIONAL);
-	if (op & SPI_OP_INPUT_SERVICE_FLAG) {
-		writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG,
-			       dd->base + SPI_OPERATIONAL);
-		/*
-		 * Ensure service flag was cleared before further
-		 * processing of interrupt.
-		 */
-		mb();
-		ret |= msm_spi_input_irq(irq, dev_id);
-	}
-
-	if (op & SPI_OP_OUTPUT_SERVICE_FLAG) {
-		writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG,
-			       dd->base + SPI_OPERATIONAL);
-		/*
-		 * Ensure service flag was cleared before further
-		 * processing of interrupt.
-		 */
-		mb();
-		ret |= msm_spi_output_irq(irq, dev_id);
-	}
-
-	if (dd->done) {
-		complete(&dd->transfer_complete);
-		dd->done = 0;
-	}
-	return ret;
-}
-
-static inline int msm_spi_request_irq(struct msm_spi *dd,
-				      const char *name,
-				      struct spi_master *master)
-{
-	return request_irq(dd->irq_in, msm_spi_qup_irq, IRQF_TRIGGER_HIGH,
-			   name, dd);
-}
-
-static inline void msm_spi_free_irq(struct msm_spi *dd,
-				    struct spi_master *master)
-{
-	free_irq(dd->irq_in, dd);
-}
-
-static inline void msm_spi_free_output_irq(struct msm_spi *dd) { }
-static inline void msm_spi_free_error_irq(struct msm_spi *dd,
-					  struct spi_master *master) { }
-
-static inline void msm_spi_disable_irqs(struct msm_spi *dd)
-{
-	disable_irq(dd->irq_in);
-}
-
-static inline void msm_spi_enable_irqs(struct msm_spi *dd)
-{
-	enable_irq(dd->irq_in);
-}
-
-static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err)
-{
-	*spi_err = readl_relaxed(dd->base + QUP_ERROR_FLAGS);
-}
-
-static inline void msm_spi_ack_clk_err(struct msm_spi *dd)
-{
-	writel_relaxed(QUP_ERR_MASK, dd->base + QUP_ERROR_FLAGS);
-}
-
-static inline void msm_spi_add_configs(struct msm_spi *dd, u32 *config, int n);
-
-/* QUP has no_input, no_output, and N bits at QUP_CONFIG */
-static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw)
-{
-	u32 qup_config = readl_relaxed(dd->base + QUP_CONFIG);
-
-	msm_spi_add_configs(dd, &qup_config, bpw-1);
-	writel_relaxed(qup_config | QUP_CONFIG_SPI_MODE,
-		       dd->base + QUP_CONFIG);
-}
-
-static inline int msm_spi_prepare_for_write(struct msm_spi *dd)
-{
-	if (msm_spi_set_state(dd, SPI_OP_STATE_RUN))
-		return -1;
-	if (msm_spi_set_state(dd, SPI_OP_STATE_PAUSE))
-		return -1;
-	return 0;
-}
-
-static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
-{
-	if (read_count <= dd->input_fifo_size)
-		msm_spi_write_rmn_to_fifo(dd);
-	else
-		msm_spi_write_word_to_fifo(dd);
-}
-
-static inline void msm_spi_set_write_count(struct msm_spi *dd, int val)
-{
-	writel_relaxed(val, dd->base + QUP_MX_WRITE_COUNT);
-}
-
-static inline void msm_spi_complete(struct msm_spi *dd)
-{
-	dd->done = 1;
-}
-
-static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
-{
-	writel_relaxed(0x00000078, dd->base + SPI_ERROR_FLAGS_EN);
-}
-
-static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
-{
-	writel_relaxed(0x0000007C, dd->base + SPI_ERROR_FLAGS);
-}
-
-#endif
-
 static inline int msm_spi_request_gpios(struct msm_spi *dd)
 {
 	int i;
@@ -710,8 +151,9 @@
 		words = 8; /* 32 bytes */
 		break;
 	default:
-		return -1;
+		return -EINVAL;
 	}
+
 	switch (mult) {
 	case 0:
 		*fifo_size = words * 2;
@@ -726,8 +168,9 @@
 		*fifo_size = words * 16;
 		break;
 	default:
-		return -1;
+		return -EINVAL;
 	}
+
 	*block_size = words * sizeof(u32); /* in bytes */
 	return 0;
 }
@@ -781,8 +224,7 @@
 
 fifo_size_err:
 	dd->use_dma = 0;
-	printk(KERN_WARNING "%s: invalid FIFO size, SPI_IO_MODES=0x%x\n",
-	       __func__, spi_iom);
+	pr_err("%s: invalid FIFO size, SPI_IO_MODES=0x%x\n", __func__, spi_iom);
 	return;
 }
 
@@ -812,6 +254,7 @@
 		else
 			dd->rx_bytes_remaining = 0;
 	}
+
 	dd->read_xfr_cnt++;
 	if (dd->multi_xfr) {
 		if (!dd->rx_bytes_remaining)
@@ -889,7 +332,7 @@
 {
 	enum msm_spi_state cur_state;
 	if (msm_spi_wait_valid(dd))
-		return -1;
+		return -EIO;
 	cur_state = readl_relaxed(dd->base + SPI_STATE);
 	/* Per spec:
 	   For PAUSE_STATE to RESET_STATE, two writes of (10) are required */
@@ -902,7 +345,7 @@
 		       dd->base + SPI_STATE);
 	}
 	if (msm_spi_wait_valid(dd))
-		return -1;
+		return -EIO;
 
 	return 0;
 }
@@ -1121,6 +564,48 @@
 	mb();
 }
 
+/* Figure which irq occured and call the relevant functions */
+static inline irqreturn_t msm_spi_qup_irq(int irq, void *dev_id)
+{
+	u32 op, ret = IRQ_NONE;
+	struct msm_spi *dd = dev_id;
+
+	if (readl_relaxed(dd->base + SPI_ERROR_FLAGS) ||
+	    readl_relaxed(dd->base + QUP_ERROR_FLAGS)) {
+		struct spi_master *master = dev_get_drvdata(dd->dev);
+		ret |= msm_spi_error_irq(irq, master);
+	}
+
+	op = readl_relaxed(dd->base + SPI_OPERATIONAL);
+	if (op & SPI_OP_INPUT_SERVICE_FLAG) {
+		writel_relaxed(SPI_OP_INPUT_SERVICE_FLAG,
+			       dd->base + SPI_OPERATIONAL);
+		/*
+		 * Ensure service flag was cleared before further
+		 * processing of interrupt.
+		 */
+		mb();
+		ret |= msm_spi_input_irq(irq, dev_id);
+	}
+
+	if (op & SPI_OP_OUTPUT_SERVICE_FLAG) {
+		writel_relaxed(SPI_OP_OUTPUT_SERVICE_FLAG,
+			       dd->base + SPI_OPERATIONAL);
+		/*
+		 * Ensure service flag was cleared before further
+		 * processing of interrupt.
+		 */
+		mb();
+		ret |= msm_spi_output_irq(irq, dev_id);
+	}
+
+	if (dd->done) {
+		complete(&dd->transfer_complete);
+		dd->done = 0;
+	}
+	return ret;
+}
+
 static irqreturn_t msm_spi_input_irq(int irq, void *dev_id)
 {
 	struct msm_spi	       *dd = dev_id;
@@ -1490,14 +975,14 @@
 	if (int_loopback && dd->multi_xfr &&
 			(read_count > dd->input_fifo_size)) {
 		if (dd->read_len && dd->write_len)
-			printk(KERN_WARNING
-			"%s:Internal Loopback does not support > fifo size\
-			for write-then-read transactions\n",
+			pr_err(
+			"%s:Internal Loopback does not support > fifo size"
+			"for write-then-read transactions\n",
 			__func__);
 		else if (dd->write_len && !dd->read_len)
-			printk(KERN_WARNING
-			"%s:Internal Loopback does not support > fifo size\
-			for write-then-write transactions\n",
+			pr_err(
+			"%s:Internal Loopback does not support > fifo size"
+			"for write-then-write transactions\n",
 			__func__);
 		return;
 	}
@@ -1692,43 +1177,84 @@
 		dd->cs_gpios[cs_num].valid = 1;
 	}
 
-	dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
-					    struct spi_transfer,
-					    transfer_list);
-	get_transfer_length(dd);
-	if (dd->multi_xfr && !dd->read_len && !dd->write_len) {
-		/* Handling of multi-transfers. FIFO mode is used by default */
+	if (dd->qup_ver) {
 		list_for_each_entry(dd->cur_transfer,
-				    &dd->cur_msg->transfers,
-				    transfer_list) {
-			if (!dd->cur_transfer->len)
-				goto error;
-			if (xfrs_grped) {
-				xfrs_grped--;
-				continue;
-			} else {
-				dd->read_len = dd->write_len = 0;
-				xfrs_grped = combine_transfers(dd);
+				&dd->cur_msg->transfers,
+				transfer_list) {
+			u32 spi_ioc;
+			u32 spi_ioc_orig;
+			struct spi_transfer *t = dd->cur_transfer;
+			struct spi_transfer *nxt;
+
+			if (t->transfer_list.next != &dd->cur_msg->transfers) {
+				nxt = list_entry(t->transfer_list.next,
+						struct spi_transfer,
+						transfer_list);
+
+				spi_ioc = readl_relaxed(dd->base +
+							SPI_IO_CONTROL);
+				spi_ioc_orig = spi_ioc;
+				if (t->cs_change == nxt->cs_change)
+					spi_ioc |= SPI_IO_C_FORCE_CS;
+				else
+					spi_ioc &= ~SPI_IO_C_FORCE_CS;
+
+				if (spi_ioc != spi_ioc_orig) {
+					writel_relaxed(spi_ioc,
+						dd->base + SPI_IO_CONTROL);
+				}
 			}
+
+			dd->cur_msg_len = dd->cur_transfer->len;
+			msm_spi_process_transfer(dd);
+		}
+	} else {
+		dd->cur_transfer = list_first_entry(&dd->cur_msg->transfers,
+						    struct spi_transfer,
+						    transfer_list);
+		get_transfer_length(dd);
+		if (dd->multi_xfr && !dd->read_len && !dd->write_len) {
+			/*
+			 * Handling of multi-transfers.
+			 * FIFO mode is used by default
+			 */
+			list_for_each_entry(dd->cur_transfer,
+					    &dd->cur_msg->transfers,
+					    transfer_list) {
+				if (!dd->cur_transfer->len)
+					goto error;
+				if (xfrs_grped) {
+					xfrs_grped--;
+					continue;
+				} else {
+					dd->read_len = dd->write_len = 0;
+					xfrs_grped = combine_transfers(dd);
+				}
+
+				dd->cur_tx_transfer = dd->cur_transfer;
+				dd->cur_rx_transfer = dd->cur_transfer;
+				msm_spi_process_transfer(dd);
+				xfrs_grped--;
+			}
+		} else {
+			/* Handling of a single transfer or
+			 * WR-WR or WR-RD transfers
+			 */
+			if ((!dd->cur_msg->is_dma_mapped) &&
+			    (msm_use_dm(dd, dd->cur_transfer,
+					dd->cur_transfer->bits_per_word))) {
+				/* Mapping of DMA buffers */
+				int ret = msm_spi_map_dma_buffers(dd);
+				if (ret < 0) {
+					dd->cur_msg->status = ret;
+					goto error;
+				}
+			}
+
 			dd->cur_tx_transfer = dd->cur_transfer;
 			dd->cur_rx_transfer = dd->cur_transfer;
 			msm_spi_process_transfer(dd);
-			xfrs_grped--;
 		}
-	} else {
-		/* Handling of a single transfer or WR-WR or WR-RD transfers */
-		if ((!dd->cur_msg->is_dma_mapped) &&
-		    (msm_use_dm(dd, dd->cur_transfer,
-				dd->cur_transfer->bits_per_word))) {
-			/* Mapping of DMA buffers */
-			int ret = msm_spi_map_dma_buffers(dd);
-			if (ret < 0) {
-				dd->cur_msg->status = ret;
-				goto error;
-			}
-		}
-		dd->cur_tx_transfer = dd->cur_rx_transfer = dd->cur_transfer;
-		msm_spi_process_transfer(dd);
 	}
 
 	return;
@@ -1939,6 +1465,7 @@
 	dd->dent_spi = debugfs_create_dir(dev_name(dd->dev), NULL);
 	if (dd->dent_spi) {
 		int i;
+
 		for (i = 0; i < ARRAY_SIZE(debugfs_spi_regs); i++) {
 			dd->debugfs_spi_regs[i] =
 			   debugfs_create_file(
@@ -1955,6 +1482,7 @@
 {
 	if (dd->dent_spi) {
 		int i;
+
 		debugfs_remove_recursive(dd->dent_spi);
 		dd->dent_spi = NULL;
 		for (i = 0; i < ARRAY_SIZE(debugfs_spi_regs); i++)
@@ -2210,6 +1738,23 @@
 	return 0;
 }
 
+struct msm_spi_platform_data *msm_spi_dt_to_pdata(struct platform_device *pdev)
+{
+	struct device_node *node = pdev->dev.of_node;
+	struct msm_spi_platform_data *pdata;
+
+	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata) {
+		pr_err("Unable to allocate platform data\n");
+		return NULL;
+	}
+
+	of_property_read_u32(node, "spi-max-frequency",
+			&pdata->max_clock_speed);
+
+	return pdata;
+}
+
 static int __init msm_spi_probe(struct platform_device *pdev)
 {
 	struct spi_master      *master;
@@ -2220,7 +1765,7 @@
 	int                     i = 0;
 	int                     clk_enabled = 0;
 	int                     pclk_enabled = 0;
-	struct msm_spi_platform_data *pdata = pdev->dev.platform_data;
+	struct msm_spi_platform_data *pdata;
 
 	master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
 	if (!master) {
@@ -2237,23 +1782,29 @@
 	platform_set_drvdata(pdev, master);
 	dd = spi_master_get_devdata(master);
 
+	if (pdev->dev.of_node) {
+		dd->qup_ver = SPI_QUP_VERSION_BFAM;
+		master->dev.of_node = pdev->dev.of_node;
+		pdata = msm_spi_dt_to_pdata(pdev);
+		if (!pdata) {
+			rc = -ENOMEM;
+			goto err_probe_exit;
+		}
+	} else {
+		pdata = pdev->dev.platform_data;
+		dd->qup_ver = SPI_QUP_VERSION_NONE;
+	}
+
 	dd->pdata = pdata;
-	rc = msm_spi_get_irq_data(dd, pdev);
-	if (rc)
-		goto err_probe_res;
-	resource = platform_get_resource_byname(pdev,
-						 IORESOURCE_MEM, "spi_base");
+	resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!resource) {
 		rc = -ENXIO;
 		goto err_probe_res;
 	}
+
 	dd->mem_phys_addr = resource->start;
 	dd->mem_size = resource_size(resource);
 
-	rc = msm_spi_get_gsbi_resource(dd, pdev);
-	if (rc)
-		goto err_probe_res2;
-
 	if (pdata) {
 		if (pdata->dma_config) {
 			rc = pdata->dma_config();
@@ -2265,20 +1816,17 @@
 				goto skip_dma_resources;
 			}
 		}
-		resource = platform_get_resource_byname(pdev,
-							IORESOURCE_DMA,
-							"spidm_channels");
+		resource = platform_get_resource(pdev, IORESOURCE_DMA, 0);
 		if (resource) {
 			dd->rx_dma_chan = resource->start;
 			dd->tx_dma_chan = resource->end;
-
-			resource = platform_get_resource_byname(pdev,
-							IORESOURCE_DMA,
-							"spidm_crci");
+			resource = platform_get_resource(pdev, IORESOURCE_DMA,
+							1);
 			if (!resource) {
 				rc = -ENXIO;
 				goto err_probe_res;
 			}
+
 			dd->rx_dma_crci = resource->start;
 			dd->tx_dma_crci = resource->end;
 			dd->use_dma = 1;
@@ -2298,14 +1846,13 @@
 	}
 
 	for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
-		resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
-							spi_rsrcs[i]);
+		resource = platform_get_resource(pdev, IORESOURCE_IO, i);
 		dd->spi_gpios[i] = resource ? resource->start : -1;
 	}
 
 	for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
-		resource = platform_get_resource_byname(pdev, IORESOURCE_IO,
-							spi_cs_rsrcs[i]);
+		resource = platform_get_resource(pdev, IORESOURCE_IO,
+				i + ARRAY_SIZE(spi_rsrcs));
 		dd->cs_gpios[i].gpio_num = resource ? resource->start : -1;
 		dd->cs_gpios[i].valid = 0;
 	}
@@ -2320,22 +1867,22 @@
 	INIT_WORK(&dd->work_data, msm_spi_workq);
 	init_waitqueue_head(&dd->continue_suspend);
 	dd->workqueue = create_singlethread_workqueue(
-		dev_name(master->dev.parent));
+			dev_name(master->dev.parent));
 	if (!dd->workqueue)
 		goto err_probe_workq;
 
-	if (!request_mem_region(dd->mem_phys_addr, dd->mem_size,
-				SPI_DRV_NAME)) {
+	if (!devm_request_mem_region(&pdev->dev, dd->mem_phys_addr,
+					dd->mem_size, SPI_DRV_NAME)) {
 		rc = -ENXIO;
 		goto err_probe_reqmem;
 	}
 
-	dd->base = ioremap(dd->mem_phys_addr, dd->mem_size);
-	if (!dd->base)
-		goto err_probe_ioremap;
-	rc = msm_spi_request_gsbi(dd);
-	if (rc)
-		goto err_probe_ioremap2;
+	dd->base = devm_ioremap(&pdev->dev, dd->mem_phys_addr, dd->mem_size);
+	if (!dd->base) {
+		rc = -ENOMEM;
+		goto err_probe_reqmem;
+	}
+
 	if (pdata && pdata->rsl_id) {
 		struct remote_mutex_id rmid;
 		rmid.r_spinlock_id = pdata->rsl_id;
@@ -2348,16 +1895,18 @@
 				__func__, rc);
 			goto err_probe_rlock_init;
 		}
+
 		dd->use_rlock = 1;
 		dd->pm_lat = pdata->pm_lat;
 		pm_qos_add_request(&qos_req_list, PM_QOS_CPU_DMA_LATENCY, 
 					    	 PM_QOS_DEFAULT_VALUE);
 	}
+
 	mutex_lock(&dd->core_lock);
 	if (dd->use_rlock)
 		remote_mutex_lock(&dd->r_lock);
-	locked = 1;
 
+	locked = 1;
 	dd->dev = &pdev->dev;
 	dd->clk = clk_get(&pdev->dev, "core_clk");
 	if (IS_ERR(dd->clk)) {
@@ -2382,16 +1931,20 @@
 			__func__);
 		goto err_probe_clk_enable;
 	}
-	clk_enabled = 1;
 
+	clk_enabled = 1;
 	rc = clk_enable(dd->pclk);
 	if (rc) {
 		dev_err(&pdev->dev, "%s: unable to enable iface_clk\n",
 		__func__);
 		goto err_probe_pclk_enable;
 	}
+
 	pclk_enabled = 1;
-	msm_spi_init_gsbi(dd);
+	rc = msm_spi_configure_gsbi(dd, pdev);
+	if (rc)
+		goto err_probe_gsbi;
+
 	msm_spi_calculate_fifo_size(dd);
 	if (dd->use_dma) {
 		rc = msm_spi_init_dma(dd);
@@ -2399,13 +1952,7 @@
 			goto err_probe_dma;
 	}
 
-	/* Initialize registers */
-	writel_relaxed(0x00000001, dd->base + SPI_SW_RESET);
-	msm_spi_set_state(dd, SPI_OP_STATE_RESET);
-
-	writel_relaxed(0x00000000, dd->base + SPI_OPERATIONAL);
-	writel_relaxed(0x00000000, dd->base + SPI_CONFIG);
-	writel_relaxed(0x00000000, dd->base + SPI_IO_MODES);
+	msm_spi_register_init(dd);
 	/*
 	 * The SPI core generates a bogus input overrun error on some targets,
 	 * when a transition from run to reset state occurs and if the FIFO has
@@ -2429,7 +1976,7 @@
 	dd->multi_xfr = 0;
 	dd->mode = SPI_MODE_NONE;
 
-	rc = msm_spi_request_irq(dd, pdev->name, master);
+	rc = msm_spi_request_irq(dd, pdev, master);
 	if (rc)
 		goto err_probe_irq;
 
@@ -2451,16 +1998,16 @@
 	}
 
 	spi_debugfs_init(dd);
-
 	return 0;
 
 err_attrs:
+	spi_unregister_master(master);
 err_probe_reg_master:
-	msm_spi_free_irq(dd, master);
 err_probe_irq:
 err_probe_state:
 	msm_spi_teardown_dma(dd);
 err_probe_dma:
+err_probe_gsbi:
 	if (pclk_enabled)
 		clk_disable(dd->pclk);
 err_probe_pclk_enable:
@@ -2474,14 +2021,10 @@
 	if (locked) {
 		if (dd->use_rlock)
 			remote_mutex_unlock(&dd->r_lock);
+
 		mutex_unlock(&dd->core_lock);
 	}
 err_probe_rlock_init:
-	msm_spi_release_gsbi(dd);
-err_probe_ioremap2:
-	iounmap(dd->base);
-err_probe_ioremap:
-	release_mem_region(dd->mem_phys_addr, dd->mem_size);
 err_probe_reqmem:
 	destroy_workqueue(dd->workqueue);
 err_probe_workq:
@@ -2489,7 +2032,6 @@
 err_probe_gpio:
 	if (pdata && pdata->gpio_release)
 		pdata->gpio_release();
-err_probe_res2:
 err_probe_res:
 	spi_master_put(master);
 err_probe_exit:
@@ -2553,16 +2095,11 @@
 	spi_debugfs_exit(dd);
 	sysfs_remove_group(&pdev->dev.kobj, &dev_attr_grp);
 
-	msm_spi_free_irq(dd, master);
 	msm_spi_teardown_dma(dd);
-
 	if (pdata && pdata->gpio_release)
 		pdata->gpio_release();
 
 	msm_spi_free_gpios(dd);
-	iounmap(dd->base);
-	release_mem_region(dd->mem_phys_addr, dd->mem_size);
-	msm_spi_release_gsbi(dd);
 	clk_put(dd->clk);
 	clk_put(dd->pclk);
 	destroy_workqueue(dd->workqueue);
@@ -2573,10 +2110,18 @@
 	return 0;
 }
 
+static struct of_device_id msm_spi_dt_match[] = {
+	{
+		.compatible = "qcom,spi-qup-v2",
+	},
+	{}
+};
+
 static struct platform_driver msm_spi_driver = {
 	.driver		= {
 		.name	= SPI_DRV_NAME,
 		.owner	= THIS_MODULE,
+		.of_match_table = msm_spi_dt_match,
 	},
 	.suspend        = msm_spi_suspend,
 	.resume         = msm_spi_resume,
@@ -2594,3 +2139,7 @@
 	platform_driver_unregister(&msm_spi_driver);
 }
 module_exit(msm_spi_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.4");
+MODULE_ALIAS("platform:"SPI_DRV_NAME);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
new file mode 100644
index 0000000..bda9e17
--- /dev/null
+++ b/drivers/spi/spi_qsd.h
@@ -0,0 +1,492 @@
+/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _SPI_QSD_H
+#define _SPI_QSD_H
+
+#define SPI_DRV_NAME                  "spi_qsd"
+
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+
+#define QSD_REG(x) (x)
+#define QUP_REG(x)
+
+#define SPI_FIFO_WORD_CNT             0x0048
+
+#else
+
+#define QSD_REG(x)
+#define QUP_REG(x) (x)
+
+#define QUP_CONFIG                    0x0000 /* N & NO_INPUT/NO_OUPUT bits */
+#define QUP_ERROR_FLAGS_EN            0x030C
+#define QUP_ERR_MASK                  0x3
+#define SPI_OUTPUT_FIFO_WORD_CNT      0x010C
+#define SPI_INPUT_FIFO_WORD_CNT       0x0214
+#define QUP_MX_WRITE_COUNT            0x0150
+#define QUP_MX_WRITE_CNT_CURRENT      0x0154
+
+#define QUP_CONFIG_SPI_MODE           0x0100
+#endif
+
+#define GSBI_CTRL_REG                 0x0
+#define GSBI_SPI_CONFIG               0x30
+#define QUP_HARDWARE_VER              0x0030
+#define QUP_OPERATIONAL_MASK          0x0028
+#define QUP_ERROR_FLAGS               0x0308
+
+#define SPI_CONFIG                    QSD_REG(0x0000) QUP_REG(0x0300)
+#define SPI_IO_CONTROL                QSD_REG(0x0004) QUP_REG(0x0304)
+#define SPI_IO_MODES                  QSD_REG(0x0008) QUP_REG(0x0008)
+#define SPI_SW_RESET                  QSD_REG(0x000C) QUP_REG(0x000C)
+#define SPI_TIME_OUT_CURRENT          QSD_REG(0x0014) QUP_REG(0x0014)
+#define SPI_MX_OUTPUT_COUNT           QSD_REG(0x0018) QUP_REG(0x0100)
+#define SPI_MX_OUTPUT_CNT_CURRENT     QSD_REG(0x001C) QUP_REG(0x0104)
+#define SPI_MX_INPUT_COUNT            QSD_REG(0x0020) QUP_REG(0x0200)
+#define SPI_MX_INPUT_CNT_CURRENT      QSD_REG(0x0024) QUP_REG(0x0204)
+#define SPI_MX_READ_COUNT             QSD_REG(0x0028) QUP_REG(0x0208)
+#define SPI_MX_READ_CNT_CURRENT       QSD_REG(0x002C) QUP_REG(0x020C)
+#define SPI_OPERATIONAL               QSD_REG(0x0030) QUP_REG(0x0018)
+#define SPI_ERROR_FLAGS               QSD_REG(0x0034) QUP_REG(0x001C)
+#define SPI_ERROR_FLAGS_EN            QSD_REG(0x0038) QUP_REG(0x0020)
+#define SPI_DEASSERT_WAIT             QSD_REG(0x003C) QUP_REG(0x0310)
+#define SPI_OUTPUT_DEBUG              QSD_REG(0x0040) QUP_REG(0x0108)
+#define SPI_INPUT_DEBUG               QSD_REG(0x0044) QUP_REG(0x0210)
+#define SPI_TEST_CTRL                 QSD_REG(0x004C) QUP_REG(0x0024)
+#define SPI_OUTPUT_FIFO               QSD_REG(0x0100) QUP_REG(0x0110)
+#define SPI_INPUT_FIFO                QSD_REG(0x0200) QUP_REG(0x0218)
+#define SPI_STATE                     QSD_REG(SPI_OPERATIONAL) QUP_REG(0x0004)
+
+/* SPI_CONFIG fields */
+#define SPI_CFG_INPUT_FIRST           0x00000200
+#define SPI_NO_INPUT                  0x00000080
+#define SPI_NO_OUTPUT                 0x00000040
+#define SPI_CFG_LOOPBACK              0x00000100
+#define SPI_CFG_N                     0x0000001F
+
+/* SPI_IO_CONTROL fields */
+#define SPI_IO_C_FORCE_CS             0x00000800
+#define SPI_IO_C_CLK_IDLE_HIGH        0x00000400
+#define SPI_IO_C_MX_CS_MODE           0x00000100
+#define SPI_IO_C_CS_N_POLARITY        0x000000F0
+#define SPI_IO_C_CS_N_POLARITY_0      0x00000010
+#define SPI_IO_C_CS_SELECT            0x0000000C
+#define SPI_IO_C_TRISTATE_CS          0x00000002
+#define SPI_IO_C_NO_TRI_STATE         0x00000001
+
+/* SPI_IO_MODES fields */
+#define SPI_IO_M_OUTPUT_BIT_SHIFT_EN  QSD_REG(0x00004000) QUP_REG(0x00010000)
+#define SPI_IO_M_PACK_EN              QSD_REG(0x00002000) QUP_REG(0x00008000)
+#define SPI_IO_M_UNPACK_EN            QSD_REG(0x00001000) QUP_REG(0x00004000)
+#define SPI_IO_M_INPUT_MODE           QSD_REG(0x00000C00) QUP_REG(0x00003000)
+#define SPI_IO_M_OUTPUT_MODE          QSD_REG(0x00000300) QUP_REG(0x00000C00)
+#define SPI_IO_M_INPUT_FIFO_SIZE      QSD_REG(0x000000C0) QUP_REG(0x00000380)
+#define SPI_IO_M_INPUT_BLOCK_SIZE     QSD_REG(0x00000030) QUP_REG(0x00000060)
+#define SPI_IO_M_OUTPUT_FIFO_SIZE     QSD_REG(0x0000000C) QUP_REG(0x0000001C)
+#define SPI_IO_M_OUTPUT_BLOCK_SIZE    QSD_REG(0x00000003) QUP_REG(0x00000003)
+
+#define INPUT_BLOCK_SZ_SHIFT          QSD_REG(4)          QUP_REG(5)
+#define INPUT_FIFO_SZ_SHIFT           QSD_REG(6)          QUP_REG(7)
+#define OUTPUT_BLOCK_SZ_SHIFT         QSD_REG(0)          QUP_REG(0)
+#define OUTPUT_FIFO_SZ_SHIFT          QSD_REG(2)          QUP_REG(2)
+#define OUTPUT_MODE_SHIFT             QSD_REG(8)          QUP_REG(10)
+#define INPUT_MODE_SHIFT              QSD_REG(10)         QUP_REG(12)
+
+/* SPI_OPERATIONAL fields */
+#define SPI_OP_MAX_INPUT_DONE_FLAG    0x00000800
+#define SPI_OP_MAX_OUTPUT_DONE_FLAG   0x00000400
+#define SPI_OP_INPUT_SERVICE_FLAG     0x00000200
+#define SPI_OP_OUTPUT_SERVICE_FLAG    0x00000100
+#define SPI_OP_INPUT_FIFO_FULL        0x00000080
+#define SPI_OP_OUTPUT_FIFO_FULL       0x00000040
+#define SPI_OP_IP_FIFO_NOT_EMPTY      0x00000020
+#define SPI_OP_OP_FIFO_NOT_EMPTY      0x00000010
+#define SPI_OP_STATE_VALID            0x00000004
+#define SPI_OP_STATE                  0x00000003
+
+#define SPI_OP_STATE_CLEAR_BITS       0x2
+enum msm_spi_state {
+	SPI_OP_STATE_RESET = 0x00000000,
+	SPI_OP_STATE_RUN   = 0x00000001,
+	SPI_OP_STATE_PAUSE = 0x00000003,
+};
+
+/* SPI_ERROR_FLAGS fields */
+#define SPI_ERR_OUTPUT_OVER_RUN_ERR   0x00000020
+#define SPI_ERR_INPUT_UNDER_RUN_ERR   0x00000010
+#define SPI_ERR_OUTPUT_UNDER_RUN_ERR  0x00000008
+#define SPI_ERR_INPUT_OVER_RUN_ERR    0x00000004
+#define SPI_ERR_CLK_OVER_RUN_ERR      0x00000002
+#define SPI_ERR_CLK_UNDER_RUN_ERR     0x00000001
+
+/* We don't allow transactions larger than 4K-64 or 64K-64 due to
+   mx_input/output_cnt register size */
+#define SPI_MAX_TRANSFERS             QSD_REG(0xFC0) QUP_REG(0xFC0)
+#define SPI_MAX_LEN                   (SPI_MAX_TRANSFERS * dd->bytes_per_word)
+
+#define SPI_NUM_CHIPSELECTS           4
+#define SPI_SUPPORTED_MODES  (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP)
+
+#define SPI_DELAY_THRESHOLD           1
+/* Default timeout is 10 milliseconds */
+#define SPI_DEFAULT_TIMEOUT           10
+/* 250 microseconds */
+#define SPI_TRYLOCK_DELAY             250
+
+/* Data Mover burst size */
+#define DM_BURST_SIZE                 16
+/* Data Mover commands should be aligned to 64 bit(8 bytes) */
+#define DM_BYTE_ALIGN                 8
+
+#define SPI_QUP_VERSION_NONE      0x0
+#define SPI_QUP_VERSION_BFAM      0x2
+
+static char const * const spi_rsrcs[] = {
+	"spi_clk",
+	"spi_miso",
+	"spi_mosi"
+};
+
+static char const * const spi_cs_rsrcs[] = {
+	"spi_cs",
+	"spi_cs1",
+	"spi_cs2",
+	"spi_cs3",
+};
+
+enum msm_spi_mode {
+	SPI_FIFO_MODE  = 0x0,  /* 00 */
+	SPI_BLOCK_MODE = 0x1,  /* 01 */
+	SPI_DMOV_MODE  = 0x2,  /* 10 */
+	SPI_BAM_MODE   = 0x3,  /* 11 */
+	SPI_MODE_NONE  = 0xFF, /* invalid value */
+};
+
+/* Structure for SPI CS GPIOs */
+struct spi_cs_gpio {
+	int  gpio_num;
+	bool valid;
+};
+
+/* Structures for Data Mover */
+struct spi_dmov_cmd {
+	dmov_box box;      /* data aligned to max(dm_burst_size, block_size)
+							   (<= fifo_size) */
+	dmov_s single_pad; /* data unaligned to max(dm_burst_size, block_size)
+			      padded to fit */
+	dma_addr_t cmd_ptr;
+};
+
+static struct pm_qos_request_list qos_req_list;
+
+#ifdef CONFIG_DEBUG_FS
+/* Used to create debugfs entries */
+static const struct {
+	const char *name;
+	mode_t mode;
+	int offset;
+} debugfs_spi_regs[] = {
+	{"config",                S_IRUGO | S_IWUSR, SPI_CONFIG},
+	{"io_control",            S_IRUGO | S_IWUSR, SPI_IO_CONTROL},
+	{"io_modes",              S_IRUGO | S_IWUSR, SPI_IO_MODES},
+	{"sw_reset",                        S_IWUSR, SPI_SW_RESET},
+	{"time_out_current",      S_IRUGO,           SPI_TIME_OUT_CURRENT},
+	{"mx_output_count",       S_IRUGO | S_IWUSR, SPI_MX_OUTPUT_COUNT},
+	{"mx_output_cnt_current", S_IRUGO,           SPI_MX_OUTPUT_CNT_CURRENT},
+	{"mx_input_count",        S_IRUGO | S_IWUSR, SPI_MX_INPUT_COUNT},
+	{"mx_input_cnt_current",  S_IRUGO,           SPI_MX_INPUT_CNT_CURRENT},
+	{"mx_read_count",         S_IRUGO | S_IWUSR, SPI_MX_READ_COUNT},
+	{"mx_read_cnt_current",   S_IRUGO,           SPI_MX_READ_CNT_CURRENT},
+	{"operational",           S_IRUGO | S_IWUSR, SPI_OPERATIONAL},
+	{"error_flags",           S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS},
+	{"error_flags_en",        S_IRUGO | S_IWUSR, SPI_ERROR_FLAGS_EN},
+	{"deassert_wait",         S_IRUGO | S_IWUSR, SPI_DEASSERT_WAIT},
+	{"output_debug",          S_IRUGO,           SPI_OUTPUT_DEBUG},
+	{"input_debug",           S_IRUGO,           SPI_INPUT_DEBUG},
+	{"test_ctrl",             S_IRUGO | S_IWUSR, SPI_TEST_CTRL},
+	{"output_fifo",                     S_IWUSR, SPI_OUTPUT_FIFO},
+	{"input_fifo" ,           S_IRUSR,           SPI_INPUT_FIFO},
+	{"spi_state",             S_IRUGO | S_IWUSR, SPI_STATE},
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+	{"fifo_word_cnt",         S_IRUGO,           SPI_FIFO_WORD_CNT},
+#else
+	{"qup_config",            S_IRUGO | S_IWUSR, QUP_CONFIG},
+	{"qup_error_flags",       S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS},
+	{"qup_error_flags_en",    S_IRUGO | S_IWUSR, QUP_ERROR_FLAGS_EN},
+	{"mx_write_cnt",          S_IRUGO | S_IWUSR, QUP_MX_WRITE_COUNT},
+	{"mx_write_cnt_current",  S_IRUGO,           QUP_MX_WRITE_CNT_CURRENT},
+	{"output_fifo_word_cnt",  S_IRUGO,           SPI_OUTPUT_FIFO_WORD_CNT},
+	{"input_fifo_word_cnt",   S_IRUGO,           SPI_INPUT_FIFO_WORD_CNT},
+#endif
+};
+#endif
+
+struct msm_spi {
+	u8                      *read_buf;
+	const u8                *write_buf;
+	void __iomem            *base;
+	struct device           *dev;
+	spinlock_t               queue_lock;
+	struct mutex             core_lock;
+	struct list_head         queue;
+	struct workqueue_struct *workqueue;
+	struct work_struct       work_data;
+	struct spi_message      *cur_msg;
+	struct spi_transfer     *cur_transfer;
+	struct completion        transfer_complete;
+	struct clk              *clk;
+	struct clk              *pclk;
+	unsigned long            mem_phys_addr;
+	size_t                   mem_size;
+	int                      input_fifo_size;
+	int                      output_fifo_size;
+	u32                      rx_bytes_remaining;
+	u32                      tx_bytes_remaining;
+	u32                      clock_speed;
+	int                      irq_in;
+	int                      read_xfr_cnt;
+	int                      write_xfr_cnt;
+	int                      write_len;
+	int                      read_len;
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+	int                      irq_out;
+	int                      irq_err;
+#endif
+	int                      bytes_per_word;
+	bool                     suspended;
+	bool                     transfer_pending;
+	wait_queue_head_t        continue_suspend;
+	/* DMA data */
+	enum msm_spi_mode        mode;
+	bool                     use_dma;
+	int                      tx_dma_chan;
+	int                      tx_dma_crci;
+	int                      rx_dma_chan;
+	int                      rx_dma_crci;
+	/* Data Mover Commands */
+	struct spi_dmov_cmd      *tx_dmov_cmd;
+	struct spi_dmov_cmd      *rx_dmov_cmd;
+	/* Physical address of the tx dmov box command */
+	dma_addr_t               tx_dmov_cmd_dma;
+	dma_addr_t               rx_dmov_cmd_dma;
+	struct msm_dmov_cmd      tx_hdr;
+	struct msm_dmov_cmd      rx_hdr;
+	int                      input_block_size;
+	int                      output_block_size;
+	int                      burst_size;
+	atomic_t                 rx_irq_called;
+	/* Used to pad messages unaligned to block size */
+	u8                       *tx_padding;
+	dma_addr_t               tx_padding_dma;
+	u8                       *rx_padding;
+	dma_addr_t               rx_padding_dma;
+	u32                      unaligned_len;
+	/* DMA statistics */
+	int                      stat_dmov_tx_err;
+	int                      stat_dmov_rx_err;
+	int                      stat_rx;
+	int                      stat_dmov_rx;
+	int                      stat_tx;
+	int                      stat_dmov_tx;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dent_spi;
+	struct dentry *debugfs_spi_regs[ARRAY_SIZE(debugfs_spi_regs)];
+#endif
+	struct msm_spi_platform_data *pdata; /* Platform data */
+	/* Remote Spinlock Data */
+	bool                     use_rlock;
+	remote_mutex_t           r_lock;
+	uint32_t                 pm_lat;
+	/* When set indicates multiple transfers in a single message */
+	bool                     multi_xfr;
+	bool                     done;
+	u32                      cur_msg_len;
+	/* Used in FIFO mode to keep track of the transfer being processed */
+	struct spi_transfer     *cur_tx_transfer;
+	struct spi_transfer     *cur_rx_transfer;
+	/* Temporary buffer used for WR-WR or WR-RD transfers */
+	u8                      *temp_buf;
+	/* GPIO pin numbers for SPI clk, miso and mosi */
+	int                      spi_gpios[ARRAY_SIZE(spi_rsrcs)];
+	/* SPI CS GPIOs for each slave */
+	struct spi_cs_gpio       cs_gpios[ARRAY_SIZE(spi_cs_rsrcs)];
+	int                      qup_ver;
+};
+
+/* Forward declaration */
+static irqreturn_t msm_spi_input_irq(int irq, void *dev_id);
+static irqreturn_t msm_spi_output_irq(int irq, void *dev_id);
+static irqreturn_t msm_spi_error_irq(int irq, void *dev_id);
+static inline int msm_spi_set_state(struct msm_spi *dd,
+				    enum msm_spi_state state);
+static void msm_spi_write_word_to_fifo(struct msm_spi *dd);
+static inline void msm_spi_write_rmn_to_fifo(struct msm_spi *dd);
+static irqreturn_t msm_spi_qup_irq(int irq, void *dev_id);
+
+#if defined(CONFIG_SPI_QSD) || defined(CONFIG_SPI_QSD_MODULE)
+static inline void msm_spi_disable_irqs(struct msm_spi *dd)
+{
+	disable_irq(dd->irq_in);
+	disable_irq(dd->irq_out);
+	disable_irq(dd->irq_err);
+}
+
+static inline void msm_spi_enable_irqs(struct msm_spi *dd)
+{
+	enable_irq(dd->irq_in);
+	enable_irq(dd->irq_out);
+	enable_irq(dd->irq_err);
+}
+
+static inline int msm_spi_request_irq(struct msm_spi *dd,
+				struct platform_device *pdev,
+				struct spi_master *master)
+{
+	int rc;
+
+	dd->irq_in  = platform_get_irq(pdev, 0);
+	dd->irq_out = platform_get_irq(pdev, 1);
+	dd->irq_err = platform_get_irq(pdev, 2);
+	if ((dd->irq_in < 0) || (dd->irq_out < 0) || (dd->irq_err < 0))
+		return -EINVAL;
+
+	rc = devm_request_irq(dd->dev, dd->irq_in, msm_spi_input_irq,
+		IRQF_TRIGGER_RISING, pdev->name, dd);
+	if (rc)
+		goto error_irq;
+
+	rc = devm_request_irq(dd->dev, dd->irq_out, msm_spi_output_irq,
+		IRQF_TRIGGER_RISING, pdev->name, dd);
+	if (rc)
+		goto error_irq;
+
+	rc = devm_request_irq(dd->dev, dd->irq_err, msm_spi_error_irq,
+		IRQF_TRIGGER_RISING, pdev->name, master);
+	if (rc)
+		goto error_irq;
+
+error_irq:
+	return rc;
+}
+
+static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err) {}
+static inline void msm_spi_ack_clk_err(struct msm_spi *dd) {}
+static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw) {}
+
+static inline int msm_spi_prepare_for_write(struct msm_spi *dd) { return 0; }
+static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
+{
+	msm_spi_write_word_to_fifo(dd);
+}
+static inline void msm_spi_set_write_count(struct msm_spi *dd, int val) {}
+
+static inline void msm_spi_complete(struct msm_spi *dd)
+{
+	complete(&dd->transfer_complete);
+}
+
+static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
+{
+	writel_relaxed(0x0000007B, dd->base + SPI_ERROR_FLAGS_EN);
+}
+
+static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
+{
+	writel_relaxed(0x0000007F, dd->base + SPI_ERROR_FLAGS);
+}
+
+#else
+/* In QUP the same interrupt line is used for input, output and error*/
+static inline int msm_spi_request_irq(struct msm_spi *dd,
+				struct platform_device *pdev,
+				struct spi_master *master)
+{
+	dd->irq_in  = platform_get_irq(pdev, 0);
+	if (dd->irq_in < 0)
+		return -EINVAL;
+
+	return devm_request_irq(dd->dev, dd->irq_in, msm_spi_qup_irq,
+		IRQF_TRIGGER_HIGH, pdev->name, dd);
+}
+
+static inline void msm_spi_disable_irqs(struct msm_spi *dd)
+{
+	disable_irq(dd->irq_in);
+}
+
+static inline void msm_spi_enable_irqs(struct msm_spi *dd)
+{
+	enable_irq(dd->irq_in);
+}
+
+static inline void msm_spi_get_clk_err(struct msm_spi *dd, u32 *spi_err)
+{
+	*spi_err = readl_relaxed(dd->base + QUP_ERROR_FLAGS);
+}
+
+static inline void msm_spi_ack_clk_err(struct msm_spi *dd)
+{
+	writel_relaxed(QUP_ERR_MASK, dd->base + QUP_ERROR_FLAGS);
+}
+
+static inline void msm_spi_add_configs(struct msm_spi *dd, u32 *config, int n);
+
+/* QUP has no_input, no_output, and N bits at QUP_CONFIG */
+static inline void msm_spi_set_qup_config(struct msm_spi *dd, int bpw)
+{
+	u32 qup_config = readl_relaxed(dd->base + QUP_CONFIG);
+
+	msm_spi_add_configs(dd, &qup_config, bpw-1);
+	writel_relaxed(qup_config | QUP_CONFIG_SPI_MODE,
+		       dd->base + QUP_CONFIG);
+}
+
+static inline int msm_spi_prepare_for_write(struct msm_spi *dd)
+{
+	if (msm_spi_set_state(dd, SPI_OP_STATE_RUN))
+		return -EINVAL;
+	if (msm_spi_set_state(dd, SPI_OP_STATE_PAUSE))
+		return -EINVAL;
+	return 0;
+}
+
+static inline void msm_spi_start_write(struct msm_spi *dd, u32 read_count)
+{
+	if (read_count <= dd->input_fifo_size)
+		msm_spi_write_rmn_to_fifo(dd);
+	else
+		msm_spi_write_word_to_fifo(dd);
+}
+
+static inline void msm_spi_set_write_count(struct msm_spi *dd, int val)
+{
+	writel_relaxed(val, dd->base + QUP_MX_WRITE_COUNT);
+}
+
+static inline void msm_spi_complete(struct msm_spi *dd)
+{
+	dd->done = 1;
+}
+
+static inline void msm_spi_enable_error_flags(struct msm_spi *dd)
+{
+	writel_relaxed(0x00000078, dd->base + SPI_ERROR_FLAGS_EN);
+}
+
+static inline void msm_spi_clear_error_flags(struct msm_spi *dd)
+{
+	writel_relaxed(0x0000007C, dd->base + SPI_ERROR_FLAGS);
+}
+
+#endif
+#endif
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index 9e1e388..6e3982e 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -2,7 +2,7 @@
  * drivers/serial/msm_serial.c - driver for msm7k serial device and console
  *
  * Copyright (C) 2007 Google, Inc.
- * 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
@@ -1007,6 +1007,10 @@
 		break;
 	case 3:
 		clk_en(port, 0);
+		ret = clk_set_rate(msm_hsl_port->clk, 0);
+		if (ret)
+			pr_err("%s(): Error setting UART clock rate to zero.\n",
+								__func__);
 		break;
 	default:
 		pr_err("%s(): msm_serial_hsl: Unknown PM state %d\n",
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 94ed950..97e7aa4 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -594,6 +594,24 @@
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
+config USB_GADGET_CI13XXX_MSM_HSIC
+	boolean "MIPS HSIC CI13xxx for MSM"
+	depends on ARCH_MSM
+	select USB_GADGET_DUALSPEED
+	help
+	  MSM SoC has chipidea USB controller.  This driver uses
+	  ci13xxx_udc core. Support USB-HSIC core.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "ci13xxx_msm_hsic" and force all
+	  gadget drivers to also be dynamically linked.
+
+config USB_CI13XXX_MSM_HSIC
+	tristate
+	depends on USB_GADGET_CI13XXX_MSM_HSIC
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 #
 # LAST -- dummy/emulated controller
 #
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 064960c..141f649 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -27,6 +27,7 @@
 obj-$(CONFIG_USB_EG20T)		+= pch_udc.o
 obj-$(CONFIG_USB_PXA_U2O)	+= mv_udc.o
 mv_udc-y			:= mv_udc_core.o mv_udc_phy.o
+obj-$(CONFIG_USB_CI13XXX_MSM_HSIC)	+= ci13xxx_msm_hsic.o
 obj-$(CONFIG_USB_CI13XXX_MSM)	+= ci13xxx_msm.o
 obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o
 obj-$(CONFIG_USB_MSM_72K)	+= msm72k_udc.o
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
new file mode 100644
index 0000000..135c84d
--- /dev/null
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -0,0 +1,484 @@
+/* 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/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/usb.h>
+
+#include <linux/usb/gadget.h>
+#include <linux/usb/msm_hsusb_hw.h>
+#include <linux/usb/msm_hsusb.h>
+
+#include <mach/clk.h>
+#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
+
+#include "ci13xxx_udc.c"
+
+#define MSM_USB_BASE	(mhsic->regs)
+
+#define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
+#define USB_PHY_VDD_DIG_VOL_MIN		1045000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_MAX		1320000 /* uV */
+#define USB_PHY_VDD_DIG_LOAD		49360	/* uA */
+#define LINK_RESET_TIMEOUT_USEC		(250 * 1000)
+#define HSIC_CFG_REG 0x30
+#define HSIC_IO_CAL_PER_REG 0x33
+#define HSIC_DBG1_REG 0x38
+
+struct msm_hsic_per *the_mhsic;
+
+struct msm_hsic_per {
+	struct device		*dev;
+	struct clk			*iface_clk;
+	struct clk			*core_clk;
+	struct clk			*alt_core_clk;
+	struct clk			*phy_clk;
+	struct clk			*cal_clk;
+	struct regulator	*hsic_vddcx;
+	bool				async_int;
+	void __iomem		*regs;
+	int					irq;
+};
+
+static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
+{
+	int ret = 0;
+
+	if (!init)
+		goto disable_reg;
+
+	mhsic->hsic_vddcx = regulator_get(mhsic->dev, "HSIC_VDDCX");
+	if (IS_ERR(mhsic->hsic_vddcx)) {
+		dev_err(mhsic->dev, "unable to get hsic vddcx\n");
+		return PTR_ERR(mhsic->hsic_vddcx);
+	}
+
+	ret = regulator_set_voltage(mhsic->hsic_vddcx,
+			USB_PHY_VDD_DIG_VOL_MIN,
+			USB_PHY_VDD_DIG_VOL_MAX);
+	if (ret) {
+		dev_err(mhsic->dev, "unable to set the voltage"
+				"for hsic vddcx\n");
+		goto reg_set_voltage_err;
+	}
+
+	ret = regulator_set_optimum_mode(mhsic->hsic_vddcx,
+				USB_PHY_VDD_DIG_LOAD);
+	if (ret < 0) {
+		pr_err("%s: Unable to set optimum mode of the regulator:"
+					"VDDCX\n", __func__);
+		goto reg_optimum_mode_err;
+	}
+
+	ret = regulator_enable(mhsic->hsic_vddcx);
+	if (ret) {
+		dev_err(mhsic->dev, "unable to enable hsic vddcx\n");
+		goto reg_enable_err;
+	}
+
+	return 0;
+
+disable_reg:
+	regulator_disable(mhsic->hsic_vddcx);
+reg_enable_err:
+	regulator_set_optimum_mode(mhsic->hsic_vddcx, 0);
+reg_optimum_mode_err:
+	regulator_set_voltage(mhsic->hsic_vddcx, 0,
+				USB_PHY_VDD_DIG_VOL_MIN);
+reg_set_voltage_err:
+	regulator_put(mhsic->hsic_vddcx);
+
+	return ret;
+
+}
+
+static int ulpi_write(struct msm_hsic_per *mhsic, u32 val, u32 reg)
+{
+	int cnt = 0;
+
+	/* initiate write operation */
+	writel_relaxed(ULPI_RUN | ULPI_WRITE |
+	       ULPI_ADDR(reg) | ULPI_DATA(val),
+	       USB_ULPI_VIEWPORT);
+
+	/* wait for completion */
+	while (cnt < ULPI_IO_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN))
+			break;
+		udelay(1);
+		cnt++;
+	}
+
+	if (cnt >= ULPI_IO_TIMEOUT_USEC) {
+		dev_err(mhsic->dev, "ulpi_write: timeout\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int msm_hsic_phy_clk_reset(struct msm_hsic_per *mhsic)
+{
+	int ret;
+
+	ret = clk_reset(mhsic->core_clk, CLK_RESET_ASSERT);
+	if (ret) {
+		clk_disable(mhsic->alt_core_clk);
+		dev_err(mhsic->dev, "usb phy clk assert failed\n");
+		return ret;
+	}
+	usleep_range(10000, 12000);
+	clk_disable(mhsic->alt_core_clk);
+
+	ret = clk_reset(mhsic->core_clk, CLK_RESET_DEASSERT);
+	if (ret)
+		dev_err(mhsic->dev, "usb phy clk deassert failed\n");
+
+	return ret;
+}
+
+static int msm_hsic_phy_reset(struct msm_hsic_per *mhsic)
+{
+	u32 val;
+	int ret;
+
+	ret = msm_hsic_phy_clk_reset(mhsic);
+	if (ret)
+		return ret;
+
+	val = readl_relaxed(USB_PORTSC) & ~PORTSC_PTS_MASK;
+	writel_relaxed(val | PORTSC_PTS_ULPI, USB_PORTSC);
+
+	/*
+	 * Ensure that RESET operation is completed before
+	 * turning off clock.
+	 */
+	mb();
+	dev_dbg(mhsic->dev, "phy_reset: success\n");
+
+	return 0;
+}
+
+static int msm_hsic_enable_clocks(struct platform_device *pdev,
+				struct msm_hsic_per *mhsic, bool enable)
+{
+	int ret = 0;
+
+	if (!enable)
+		goto put_clocks;
+
+	mhsic->iface_clk = clk_get(&pdev->dev, "iface_clk");
+	if (IS_ERR(mhsic->iface_clk)) {
+		dev_err(mhsic->dev, "failed to get iface_clk\n");
+		ret = PTR_ERR(mhsic->iface_clk);
+		goto put_iface_clk;
+	}
+
+	mhsic->core_clk = clk_get(&pdev->dev, "core_clk");
+	if (IS_ERR(mhsic->core_clk)) {
+		dev_err(mhsic->dev, "failed to get core_clk\n");
+		ret = PTR_ERR(mhsic->core_clk);
+		goto put_core_clk;
+	}
+
+	mhsic->phy_clk = clk_get(&pdev->dev, "phy_clk");
+	if (IS_ERR(mhsic->phy_clk)) {
+		dev_err(mhsic->dev, "failed to get phy_clk\n");
+		ret = PTR_ERR(mhsic->phy_clk);
+		goto put_phy_clk;
+	}
+
+	mhsic->alt_core_clk = clk_get(&pdev->dev, "alt_core_clk");
+	if (IS_ERR(mhsic->alt_core_clk)) {
+		dev_err(mhsic->dev, "failed to get alt_core_clk\n");
+		ret = PTR_ERR(mhsic->alt_core_clk);
+		goto put_alt_core_clk;
+	}
+
+	mhsic->cal_clk = clk_get(&pdev->dev, "cal_clk");
+	if (IS_ERR(mhsic->cal_clk)) {
+		dev_err(mhsic->dev, "failed to get cal_clk\n");
+		ret = PTR_ERR(mhsic->cal_clk);
+		goto put_cal_clk;
+	}
+
+	clk_enable(mhsic->iface_clk);
+	clk_enable(mhsic->core_clk);
+	clk_enable(mhsic->phy_clk);
+	clk_enable(mhsic->alt_core_clk);
+	clk_enable(mhsic->cal_clk);
+
+	return 0;
+
+put_clocks:
+	clk_disable(mhsic->iface_clk);
+	clk_disable(mhsic->core_clk);
+	clk_disable(mhsic->phy_clk);
+	clk_disable(mhsic->alt_core_clk);
+	clk_disable(mhsic->cal_clk);
+put_cal_clk:
+	clk_put(mhsic->cal_clk);
+put_alt_core_clk:
+	clk_put(mhsic->alt_core_clk);
+put_phy_clk:
+	clk_put(mhsic->phy_clk);
+put_core_clk:
+	clk_put(mhsic->core_clk);
+put_iface_clk:
+	clk_put(mhsic->iface_clk);
+
+	return ret;
+}
+
+static int msm_hsic_reset(struct msm_hsic_per *mhsic)
+{
+	int cnt = 0;
+	int ret;
+
+	ret = msm_hsic_phy_reset(mhsic);
+	if (ret) {
+		dev_err(mhsic->dev, "phy_reset failed\n");
+		return ret;
+	}
+
+	writel_relaxed(USBCMD_RESET, USB_USBCMD);
+	while (cnt < LINK_RESET_TIMEOUT_USEC) {
+		if (!(readl_relaxed(USB_USBCMD) & USBCMD_RESET))
+			break;
+		udelay(1);
+		cnt++;
+	}
+	if (cnt >= LINK_RESET_TIMEOUT_USEC)
+		return -ETIMEDOUT;
+
+	/* Reset PORTSC and select ULPI phy */
+	writel_relaxed(0x80000000, USB_PORTSC);
+	return 0;
+}
+
+static void msm_hsic_start(void)
+{
+	int ret;
+
+	/* programmable length of connect signaling (33.2ns) */
+	ret = ulpi_write(the_mhsic, 3, HSIC_DBG1_REG);
+	if (ret) {
+		pr_err("%s: Unable to program length of connect signaling\n",
+			    __func__);
+	}
+
+	/*set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
+	ret = ulpi_write(the_mhsic, 0xFF, HSIC_IO_CAL_PER_REG);
+
+	if (ret) {
+		pr_err("%s: Unable to set periodic calibration interval\n",
+			    __func__);
+	}
+
+	/* Enable periodic IO calibration in HSIC_CFG register */
+	ret = ulpi_write(the_mhsic, 0xE9, HSIC_CFG_REG);
+	if (ret) {
+		pr_err("%s: Unable to enable periodic IO calibration\n",
+			    __func__);
+	}
+}
+
+/**
+ * Dummy match function - will be called only for HSIC msm
+ * device (msm_device_gadget_hsic_peripheral).
+ */
+static inline int __match(struct device *dev, void *data) { return 1; }
+
+static void msm_hsic_connect_peripheral(struct device *msm_udc_dev)
+{
+	struct device *dev;
+	struct usb_gadget *gadget;
+
+	dev = device_find_child(msm_udc_dev, NULL, __match);
+	gadget = dev_to_usb_gadget(dev);
+	usb_gadget_vbus_connect(gadget);
+}
+
+static irqreturn_t msm_udc_hsic_irq(int irq, void *data)
+{
+	return udc_irq();
+}
+
+static void ci13xxx_msm_hsic_notify_event(struct ci13xxx *udc, unsigned event)
+{
+	struct device *dev = udc->gadget.dev.parent;
+	struct msm_hsic_per *mhsic = the_mhsic;
+
+	switch (event) {
+	case CI13XXX_CONTROLLER_RESET_EVENT:
+		dev_dbg(dev, "CI13XXX_CONTROLLER_RESET_EVENT received\n");
+		writel_relaxed(0, USB_AHBBURST);
+		writel_relaxed(0, USB_AHBMODE);
+		break;
+	case CI13XXX_CONTROLLER_CONNECT_EVENT:
+		dev_dbg(dev, "CI13XXX_CONTROLLER_CONNECT_EVENT received\n");
+		msm_hsic_start();
+		break;
+	default:
+		dev_dbg(dev, "unknown ci13xxx_udc event\n");
+		break;
+	}
+}
+
+static struct ci13xxx_udc_driver ci13xxx_msm_udc_hsic_driver = {
+	.name			= "ci13xxx_msm_hsic",
+	.flags			= CI13XXX_REGS_SHARED |
+				  CI13XXX_PULLUP_ON_VBUS |
+				  CI13XXX_DISABLE_STREAMING |
+				  CI13XXX_ZERO_ITC,
+
+	.notify_event		= ci13xxx_msm_hsic_notify_event,
+};
+
+static int __devinit msm_hsic_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct msm_hsic_per *mhsic;
+	int ret = 0;
+
+	dev_dbg(&pdev->dev, "msm-hsic probe\n");
+
+	mhsic = kzalloc(sizeof(struct msm_hsic_per), GFP_KERNEL);
+	if (!mhsic) {
+		dev_err(&pdev->dev, "unable to allocate msm_hsic\n");
+		return -ENOMEM;
+	}
+	the_mhsic = mhsic;
+	platform_set_drvdata(pdev, mhsic);
+	mhsic->dev = &pdev->dev;
+
+	mhsic->irq = platform_get_irq(pdev, 0);
+	if (mhsic->irq < 0) {
+		dev_err(&pdev->dev, "Unable to get IRQ resource\n");
+		ret = mhsic->irq;
+		goto error;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Unable to get memory resource\n");
+		ret = -ENODEV;
+		goto error;
+	}
+	mhsic->regs = ioremap(res->start, resource_size(res));
+	if (!mhsic->regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		ret = -ENOMEM;
+		goto unmap;
+	}
+	dev_info(&pdev->dev, "HSIC Peripheral regs = %p\n", mhsic->regs);
+
+	ret = msm_hsic_enable_clocks(pdev, mhsic, true);
+
+	if (ret) {
+		dev_err(&pdev->dev, "msm_hsic_enable_clocks failed\n");
+		ret = -ENODEV;
+		goto deinit_clocks;
+	}
+	ret = msm_hsic_init_vddcx(mhsic, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to initialize VDDCX\n");
+		ret = -ENODEV;
+		goto deinit_vddcx;
+	}
+
+	ret = msm_hsic_reset(mhsic);
+	if (ret) {
+		dev_err(&pdev->dev, "msm_hsic_reset failed\n");
+		ret = -ENODEV;
+		goto deinit_vddcx;
+	}
+
+	ret = udc_probe(&ci13xxx_msm_udc_hsic_driver, &pdev->dev, mhsic->regs);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "udc_probe failed\n");
+		ret = -ENODEV;
+		goto deinit_vddcx;
+	}
+
+	msm_hsic_connect_peripheral(&pdev->dev);
+
+	ret = request_irq(mhsic->irq, msm_udc_hsic_irq,
+					  IRQF_SHARED, pdev->name, pdev);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "request_irq failed\n");
+		ret = -ENODEV;
+		goto udc_remove;
+	}
+
+	pm_runtime_no_callbacks(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
+	return 0;
+udc_remove:
+	udc_remove();
+deinit_vddcx:
+	msm_hsic_init_vddcx(mhsic, 0);
+deinit_clocks:
+	msm_hsic_enable_clocks(pdev, mhsic, 0);
+unmap:
+	iounmap(mhsic->regs);
+error:
+	kfree(mhsic);
+	return ret;
+}
+
+static int __devexit hsic_msm_remove(struct platform_device *pdev)
+{
+	struct msm_hsic_per *mhsic = platform_get_drvdata(pdev);
+
+	device_init_wakeup(&pdev->dev, 0);
+	msm_hsic_init_vddcx(mhsic, 0);
+	msm_hsic_enable_clocks(pdev, mhsic, 0);
+	udc_remove();
+	iounmap(mhsic->regs);
+	kfree(mhsic);
+
+	return 0;
+}
+static struct platform_driver msm_hsic_peripheral_driver = {
+	.probe	= msm_hsic_probe,
+	.remove	= __devexit_p(hsic_msm_remove),
+	.driver = {
+		.name = "msm_hsic_peripheral",
+	},
+};
+
+static int __init msm_hsic_peripheral_init(void)
+{
+	return platform_driver_probe(&msm_hsic_peripheral_driver,
+								msm_hsic_probe);
+}
+
+static void __exit msm_hsic_peripheral_exit(void)
+{
+	platform_driver_unregister(&msm_hsic_peripheral_driver);
+}
+
+module_init(msm_hsic_peripheral_init);
+module_exit(msm_hsic_peripheral_exit);
+
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 703494a..35327cc 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2816,8 +2816,12 @@
 	}
 	spin_unlock_irqrestore(udc->lock, flags);
 
-	if (is_active)
+	if (is_active) {
 		hw_device_state(udc->ep0out.qh.dma);
+		if (udc->udc_driver->notify_event)
+			udc->udc_driver->notify_event(udc,
+				CI13XXX_CONTROLLER_CONNECT_EVENT);
+	}
 	else
 		hw_device_state(0);
 
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 35b0712..fce611a 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -127,6 +127,7 @@
 #define CI13XXX_ZERO_ITC		BIT(4)
 
 #define CI13XXX_CONTROLLER_RESET_EVENT		0
+#define CI13XXX_CONTROLLER_CONNECT_EVENT	1
 	void	(*notify_event) (struct ci13xxx *udc, unsigned event);
 };
 
@@ -233,7 +234,10 @@
 			   "[%s] " format "\n", __func__, ## args); \
 } while (0)
 
+#ifndef err
 #define err(format, args...)    ci13xxx_printk(KERN_ERR, format, ## args)
+#endif
+
 #define warn(format, args...)   ci13xxx_printk(KERN_WARNING, format, ## args)
 #define info(format, args...)   ci13xxx_printk(KERN_INFO, format, ## args)
 
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 05692bb..da312d4 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -160,6 +160,13 @@
 #define gadget_is_ci13xxx_msm(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_CI13XXX_MSM_HSIC
+#define gadget_is_ci13xxx_msm_hsic(g)	\
+		(!strncmp("ci13xxx_msm_hsic", (g)->name, 16))
+#else
+#define gadget_is_ci13xxx_msm_hsic(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_RENESAS_USBHS
 #define	gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
 #else
@@ -231,6 +238,8 @@
 		return 0x30;
 	else if (gadget_is_msm72k(gadget))
 		return 0x31;
+	else if (gadget_is_ci13xxx_msm_hsic(gadget))
+		return 0x32;
 
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index fb850b0..13965de 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -34,6 +34,7 @@
 static struct workqueue_struct *gbam_wq;
 static int n_bam_ports;
 static int n_bam2bam_ports;
+static unsigned n_tx_req_queued;
 static unsigned bam_ch_ids[] = { 8 };
 
 static const char *bam_ch_names[] = { "bam_dmux_ch_8" };
@@ -50,6 +51,8 @@
 #define BAM_MUX_TX_Q_SIZE			200
 #define BAM_MUX_RX_REQ_SIZE			(2048 - BAM_MUX_HDR)
 
+#define DL_INTR_THRESHOLD			20
+
 unsigned int bam_mux_tx_pkt_drop_thld = BAM_MUX_TX_PKT_DROP_THRESHOLD;
 module_param(bam_mux_tx_pkt_drop_thld, uint, S_IRUGO | S_IWUSR);
 
@@ -71,6 +74,9 @@
 unsigned int bam_mux_rx_req_size = BAM_MUX_RX_REQ_SIZE;
 module_param(bam_mux_rx_req_size, uint, S_IRUGO | S_IWUSR);
 
+unsigned int dl_intr_threshold = DL_INTR_THRESHOLD;
+module_param(dl_intr_threshold, uint, S_IRUGO | S_IWUSR);
+
 #define BAM_CH_OPENED	BIT(0)
 #define BAM_CH_READY	BIT(1)
 #define SPS_PARAMS_PIPE_ID_MASK		(0x1F)
@@ -90,6 +96,7 @@
 
 	struct gbam_port	*port;
 	struct work_struct	write_tobam_w;
+	struct work_struct	write_tohost_w;
 
 	struct usb_request	*rx_req;
 	struct usb_request	*tx_req;
@@ -110,7 +117,8 @@
 
 struct gbam_port {
 	unsigned		port_num;
-	spinlock_t		port_lock;
+	spinlock_t		port_lock_ul;
+	spinlock_t		port_lock_dl;
 
 	struct grmnet		*port_usb;
 	struct grmnet		*gr;
@@ -169,18 +177,22 @@
 /*--------------------------------------------- */
 
 /*------------data_path----------------------------*/
-static void gbam_write_data_tohost(struct gbam_port *port)
+static void gbam_write_data_tohost(struct work_struct *w)
 {
 	unsigned long			flags;
-	struct bam_ch_info		*d = &port->data_ch;
+	struct bam_ch_info	*d;
+	struct gbam_port	*port;
 	struct sk_buff			*skb;
 	int				ret;
 	struct usb_request		*req;
 	struct usb_ep			*ep;
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	d = container_of(w, struct bam_ch_info, write_tohost_w);
+	port = d->port;
+
+	spin_lock_irqsave(&port->port_lock_dl, flags);
 	if (!port->port_usb) {
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
 		return;
 	}
 
@@ -189,7 +201,7 @@
 	while (!list_empty(&d->tx_idle)) {
 		skb = __skb_dequeue(&d->tx_skb_q);
 		if (!skb) {
-			spin_unlock_irqrestore(&port->port_lock, flags);
+			spin_unlock_irqrestore(&port->port_lock_dl, flags);
 			return;
 		}
 		req = list_first_entry(&d->tx_idle,
@@ -198,12 +210,19 @@
 		req->context = skb;
 		req->buf = skb->data;
 		req->length = skb->len;
+		n_tx_req_queued++;
+		if (n_tx_req_queued == dl_intr_threshold) {
+			req->no_interrupt = 0;
+			n_tx_req_queued = 0;
+		} else {
+			req->no_interrupt = 1;
+		}
 
 		list_del(&req->list);
 
-		spin_unlock(&port->port_lock);
+		spin_unlock(&port->port_lock_dl);
 		ret = usb_ep_queue(ep, req, GFP_ATOMIC);
-		spin_lock(&port->port_lock);
+		spin_lock(&port->port_lock_dl);
 		if (ret) {
 			pr_err("%s: usb epIn failed\n", __func__);
 			list_add(&req->list, &d->tx_idle);
@@ -212,7 +231,7 @@
 		}
 		d->to_host++;
 	}
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
 }
 
 void gbam_data_recv_cb(void *p, struct sk_buff *skb)
@@ -227,9 +246,9 @@
 	pr_debug("%s: p:%p#%d d:%p skb_len:%d\n", __func__,
 			port, port->port_num, d, skb->len);
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
 	if (!port->port_usb) {
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
 		dev_kfree_skb_any(skb);
 		return;
 	}
@@ -239,15 +258,15 @@
 		if (printk_ratelimit())
 			pr_err("%s: tx pkt dropped: tx_drop_cnt:%u\n",
 					__func__, d->tohost_drp_cnt);
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
 		dev_kfree_skb_any(skb);
 		return;
 	}
 
 	__skb_queue_tail(&d->tx_skb_q, skb);
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
 
-	gbam_write_data_tohost(port);
+	queue_work(gbam_wq, &d->write_tohost_w);
 }
 
 void gbam_data_write_done(void *p, struct sk_buff *skb)
@@ -261,7 +280,7 @@
 
 	dev_kfree_skb_any(skb);
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
 
 	d->pending_with_bam--;
 
@@ -269,7 +288,7 @@
 			port, d, d->to_modem,
 			d->pending_with_bam, port->port_num);
 
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 	queue_work(gbam_wq, &d->write_tobam_w);
 }
@@ -286,9 +305,9 @@
 	d = container_of(w, struct bam_ch_info, write_tobam_w);
 	port = d->port;
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
 	if (!port->port_usb) {
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 		return;
 	}
 
@@ -304,9 +323,9 @@
 				port, d, d->to_modem, d->pending_with_bam,
 				port->port_num);
 
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 		ret = msm_bam_dmux_write(d->id, skb);
-		spin_lock_irqsave(&port->port_lock, flags);
+		spin_lock_irqsave(&port->port_lock_ul, flags);
 		if (ret) {
 			pr_debug("%s: write error:%d\n", __func__, ret);
 			d->pending_with_bam--;
@@ -319,7 +338,7 @@
 
 	qlen = d->rx_skb_q.qlen;
 
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 	if (qlen < BAM_MUX_RX_PKT_FCTRL_DIS_TSHOLD)
 		gbam_start_rx(port);
@@ -351,12 +370,12 @@
 	if (!port)
 		return;
 
-	spin_lock(&port->port_lock);
+	spin_lock(&port->port_lock_dl);
 	d = &port->data_ch;
 	list_add_tail(&req->list, &d->tx_idle);
-	spin_unlock(&port->port_lock);
+	spin_unlock(&port->port_lock_dl);
 
-	gbam_write_data_tohost(port);
+	queue_work(gbam_wq, &d->write_tohost_w);
 }
 
 static void
@@ -389,7 +408,7 @@
 		break;
 	}
 
-	spin_lock(&port->port_lock);
+	spin_lock(&port->port_lock_ul);
 	if (queue) {
 		__skb_queue_tail(&d->rx_skb_q, skb);
 		queue_work(gbam_wq, &d->write_tobam_w);
@@ -402,16 +421,16 @@
 		d->rx_skb_q.qlen >= bam_mux_rx_fctrl_en_thld) {
 
 		list_add_tail(&req->list, &d->rx_idle);
-		spin_unlock(&port->port_lock);
+		spin_unlock(&port->port_lock_ul);
 		return;
 	}
-	spin_unlock(&port->port_lock);
+	spin_unlock(&port->port_lock_ul);
 
 	skb = alloc_skb(bam_mux_rx_req_size + BAM_MUX_HDR, GFP_ATOMIC);
 	if (!skb) {
-		spin_lock(&port->port_lock);
+		spin_lock(&port->port_lock_ul);
 		list_add_tail(&req->list, &d->rx_idle);
-		spin_unlock(&port->port_lock);
+		spin_unlock(&port->port_lock_ul);
 		return;
 	}
 	skb_reserve(skb, BAM_MUX_HDR);
@@ -428,9 +447,9 @@
 			pr_err("%s: data rx enqueue err %d\n",
 					__func__, status);
 
-		spin_lock(&port->port_lock);
+		spin_lock(&port->port_lock_ul);
 		list_add_tail(&req->list, &d->rx_idle);
-		spin_unlock(&port->port_lock);
+		spin_unlock(&port->port_lock_ul);
 	}
 }
 
@@ -457,9 +476,9 @@
 	int				ret;
 	struct sk_buff			*skb;
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
 	if (!port->port_usb) {
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 		return;
 	}
 
@@ -484,9 +503,9 @@
 		req->length = bam_mux_rx_req_size;
 		req->context = skb;
 
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 		ret = usb_ep_queue(ep, req, GFP_ATOMIC);
-		spin_lock_irqsave(&port->port_lock, flags);
+		spin_lock_irqsave(&port->port_lock_ul, flags);
 		if (ret) {
 			dev_kfree_skb_any(skb);
 
@@ -500,7 +519,7 @@
 			break;
 		}
 	}
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 }
 
 static void gbam_start_endless_rx(struct gbam_port *port)
@@ -532,9 +551,9 @@
 
 	pr_debug("%s: port:%p\n", __func__, port);
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
 	if (!port->port_usb) {
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 		return;
 	}
 
@@ -547,6 +566,8 @@
 		return;
 	}
 
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
 	ep = port->port_usb->in;
 	ret = gbam_alloc_requests(ep, &d->tx_idle, bam_mux_tx_q_size,
 			gbam_epin_complete, GFP_ATOMIC);
@@ -556,7 +577,7 @@
 		return;
 	}
 
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
 
 	/* queue out requests */
 	gbam_start_rx(port);
@@ -580,7 +601,8 @@
 	unsigned long		flags;
 	struct bam_ch_info	*d;
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
 
 	if (!port || !port->port_usb)
 		goto free_buf_out;
@@ -597,7 +619,8 @@
 		dev_kfree_skb_any(skb);
 
 free_buf_out:
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 }
 
 static void gbam_disconnect_work(struct work_struct *w)
@@ -619,9 +642,11 @@
 			container_of(w, struct gbam_port, disconnect_w);
 	unsigned long		flags;
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
 	port->port_usb = 0;
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 	/* disable endpoints */
 	usb_ep_disable(port->gr->out);
@@ -636,12 +661,15 @@
 	int ret;
 	unsigned long flags;
 
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
 	if (!port->port_usb) {
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 		return;
 	}
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 	if (!test_bit(BAM_CH_READY, &d->flags))
 		return;
@@ -683,9 +711,11 @@
 		return;
 	}
 	port->gr->out->driver_data = port;
-	spin_lock_irqsave(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
 	port->port_usb = port->gr;
-	spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 	ret = usb_bam_connect(d->connection_idx, &d->src_pipe_idx,
 						  &d->dst_pipe_idx);
@@ -742,10 +772,12 @@
 			set_bit(BAM_CH_READY, &d->flags);
 
 			/* if usb is online, try opening bam_ch */
-			spin_lock_irqsave(&port->port_lock, flags);
+			spin_lock_irqsave(&port->port_lock_ul, flags);
+			spin_lock_irqsave(&port->port_lock_dl, flags);
 			if (port->port_usb)
 				queue_work(gbam_wq, &port->connect_w);
-			spin_unlock_irqrestore(&port->port_lock, flags);
+			spin_unlock_irqrestore(&port->port_lock_dl, flags);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 			break;
 		}
@@ -772,12 +804,14 @@
 			port = bam_ports[i].port;
 			d = &port->data_ch;
 
-			spin_lock_irqsave(&port->port_lock, flags);
+			spin_lock_irqsave(&port->port_lock_ul, flags);
+			spin_lock_irqsave(&port->port_lock_dl, flags);
 			if (port->port_usb) {
 				ep_in = port->port_usb->in;
 				ep_out = port->port_usb->out;
 			}
-			spin_unlock_irqrestore(&port->port_lock, flags);
+			spin_unlock_irqrestore(&port->port_lock_dl, flags);
+			spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 			if (ep_in)
 				usb_ep_fifo_flush(ep_in);
@@ -788,6 +822,9 @@
 
 			msm_bam_dmux_close(d->id);
 
+			/* bam dmux will free all pending skbs */
+			d->pending_with_bam = 0;
+
 			clear_bit(BAM_CH_READY, &d->flags);
 			clear_bit(BAM_CH_OPENED, &d->flags);
 		}
@@ -827,7 +864,8 @@
 	port->port_num = portno;
 
 	/* port initialization */
-	spin_lock_init(&port->port_lock);
+	spin_lock_init(&port->port_lock_ul);
+	spin_lock_init(&port->port_lock_dl);
 	INIT_WORK(&port->connect_w, gbam_connect_work);
 	INIT_WORK(&port->disconnect_w, gbam_disconnect_work);
 
@@ -837,6 +875,7 @@
 	INIT_LIST_HEAD(&d->tx_idle);
 	INIT_LIST_HEAD(&d->rx_idle);
 	INIT_WORK(&d->write_tobam_w, gbam_data_write_tobam);
+	INIT_WORK(&d->write_tohost_w, gbam_write_data_tohost);
 	skb_queue_head_init(&d->tx_skb_q);
 	skb_queue_head_init(&d->rx_skb_q);
 	d->id = bam_ch_ids[portno];
@@ -867,7 +906,8 @@
 	port->port_num = portno;
 
 	/* port initialization */
-	spin_lock_init(&port->port_lock);
+	spin_lock_init(&port->port_lock_ul);
+	spin_lock_init(&port->port_lock_dl);
 
 	INIT_WORK(&port->connect_w, gbam2bam_connect_work);
 	INIT_WORK(&port->disconnect_w, gbam2bam_disconnect_work);
@@ -903,7 +943,8 @@
 		port = bam_ports[i].port;
 		if (!port)
 			continue;
-		spin_lock_irqsave(&port->port_lock, flags);
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		spin_lock_irqsave(&port->port_lock_dl, flags);
 
 		d = &port->data_ch;
 
@@ -926,7 +967,8 @@
 				test_bit(BAM_CH_OPENED, &d->flags),
 				test_bit(BAM_CH_READY, &d->flags));
 
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 	}
 
 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, temp);
@@ -949,7 +991,8 @@
 		if (!port)
 			continue;
 
-		spin_lock_irqsave(&port->port_lock, flags);
+		spin_lock_irqsave(&port->port_lock_ul, flags);
+		spin_lock_irqsave(&port->port_lock_dl, flags);
 
 		d = &port->data_ch;
 
@@ -959,7 +1002,8 @@
 		d->tohost_drp_cnt = 0;
 		d->tomodem_drp_cnt = 0;
 
-		spin_unlock_irqrestore(&port->port_lock, flags);
+		spin_unlock_irqrestore(&port->port_lock_dl, flags);
+		spin_unlock_irqrestore(&port->port_lock_ul, flags);
 	}
 	return count;
 }
@@ -1024,9 +1068,12 @@
 	if (trans == USB_GADGET_XPORT_BAM) {
 		gbam_free_buffers(port);
 
-		spin_lock_irqsave(&port->port_lock, flags);
-		port->port_usb = 0;
-		spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	port->port_usb = 0;
+	n_tx_req_queued = 0;
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 
 		/* disable endpoints */
 		usb_ep_disable(gr->out);
@@ -1086,15 +1133,17 @@
 		}
 		gr->out->driver_data = port;
 
-		spin_lock_irqsave(&port->port_lock, flags);
-		port->port_usb = gr;
+	spin_lock_irqsave(&port->port_lock_ul, flags);
+	spin_lock_irqsave(&port->port_lock_dl, flags);
+	port->port_usb = gr;
 
 		d->to_host = 0;
 		d->to_modem = 0;
 		d->pending_with_bam = 0;
 		d->tohost_drp_cnt = 0;
 		d->tomodem_drp_cnt = 0;
-		spin_unlock_irqrestore(&port->port_lock, flags);
+	spin_unlock_irqrestore(&port->port_lock_dl, flags);
+	spin_unlock_irqrestore(&port->port_lock_ul, flags);
 	}
 
 	if (trans == USB_GADGET_XPORT_BAM2BAM) {
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index f2279be..1066f38 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -38,6 +38,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/pm_qos_params.h>
+#include <linux/power_supply.h>
 
 #include <mach/clk.h>
 #include <mach/msm_xo.h>
@@ -838,6 +839,35 @@
 }
 #endif
 
+static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
+{
+	struct power_supply *psy;
+
+	psy = power_supply_get_by_name("usb");
+	if (!psy)
+		goto psy_not_supported;
+
+	if (motg->cur_power == 0 && mA > 0) {
+		/* Enable charging */
+		if (power_supply_set_online(psy, true))
+			goto psy_not_supported;
+	} else if (motg->cur_power > 0 && mA == 0) {
+		/* Disable charging */
+		if (power_supply_set_online(psy, false))
+			goto psy_not_supported;
+		return 0;
+	}
+	/* Set max current limit */
+	if (power_supply_set_current_limit(psy, 1000*mA))
+		goto psy_not_supported;
+
+	return 0;
+
+psy_not_supported:
+	dev_dbg(motg->otg.dev, "Power Supply doesn't support USB charger\n");
+	return -ENXIO;
+}
+
 static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
 {
 	if ((motg->chg_type == USB_ACA_DOCK_CHARGER ||
@@ -851,7 +881,14 @@
 		return;
 
 	dev_info(motg->otg.dev, "Avail curr from USB = %u\n", mA);
-	pm8921_charger_vbus_draw(mA);
+
+	/*
+	 *  Use Power Supply API if supported, otherwise fallback
+	 *  to legacy pm8921 API.
+	 */
+	if (msm_otg_notify_power_supply(motg, mA))
+		pm8921_charger_vbus_draw(mA);
+
 	motg->cur_power = mA;
 }
 
@@ -970,6 +1007,11 @@
 		return;
 	}
 
+	/*
+	 * if entering host mode tell the charger to not draw any current
+	 * from usb - if exiting host mode let the charger draw current
+	 */
+	pm8921_disable_source_current(on);
 	if (on) {
 		ret = regulator_enable(vbus_otg);
 		if (ret) {
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c
index 0317857..db60546 100644
--- a/drivers/video/msm/mdp.c
+++ b/drivers/video/msm/mdp.c
@@ -49,7 +49,7 @@
 static struct clk *mdp_pclk;
 static struct clk *mdp_lut_clk;
 int mdp_rev;
-
+static boolean mdp_hist_force_stop = FALSE;
 static struct regulator *footswitch;
 static unsigned int mdp_footswitch_on;
 
@@ -200,6 +200,7 @@
 static int mdp_lut_update_lcdc(struct fb_info *info, struct fb_cmap *cmap)
 {
 	int ret;
+	uint32_t out;
 
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 	ret = mdp_lut_hw_update(cmap);
@@ -209,7 +210,9 @@
 		return ret;
 	}
 
-	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x17);
+	/*mask off non LUT select bits*/
+	out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
+	MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | out);
 	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 	mdp_lut_i = (mdp_lut_i + 1)%2;
 
@@ -218,11 +221,13 @@
 
 static void mdp_lut_enable(void)
 {
+	uint32_t out;
 	if (mdp_lut_push) {
 		mutex_lock(&mdp_lut_push_sem);
 		mdp_lut_push = 0;
+		out = inpdw(MDP_BASE + 0x90070) & ~(0x1 << 10);
 		MDP_OUTP(MDP_BASE + 0x90070,
-				(mdp_lut_push_i << 10) | 0x17);
+				(mdp_lut_push_i << 10) | out);
 		mutex_unlock(&mdp_lut_push_sem);
 	}
 }
@@ -255,14 +260,14 @@
 		hist_base = 0x94000;
 
 	if (en == TRUE) {
-		if (mdp_is_hist_start)
+		if (mdp_is_hist_data)
 			return -EINVAL;
 
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
 		mdp_hist_frame_cnt = 1;
 		mdp_enable_irq(MDP_HISTOGRAM_TERM);
 		spin_lock_irqsave(&mdp_spin_lock, flag);
-		if (mdp_is_hist_start == FALSE && mdp_rev >= MDP_REV_40) {
+		if (mdp_rev >= MDP_REV_40) {
 			MDP_OUTP(MDP_BASE + hist_base + 0x10, 1);
 			MDP_OUTP(MDP_BASE + hist_base + 0x1c, INTR_HIST_DONE);
 		}
@@ -272,7 +277,7 @@
 		mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
 		mdp_is_hist_data = TRUE;
 	} else {
-		if (!mdp_is_hist_start && !mdp_is_hist_data)
+		if (!mdp_is_hist_data)
 			return -EINVAL;
 
 		mdp_is_hist_data = FALSE;
@@ -299,7 +304,8 @@
 {
 	int ret = 0;
 	mutex_lock(&mdp_hist_mutex);
-	ret = _mdp_histogram_ctrl(en);
+	if (mdp_is_hist_start)
+		ret = _mdp_histogram_ctrl(en);
 	mutex_unlock(&mdp_hist_mutex);
 	return ret;
 }
@@ -423,6 +429,11 @@
 		goto error;
 	}
 
+	if (mdp_hist_force_stop && (mdp_rev == MDP_REV_303)) {
+		ret = -EINVAL;
+		goto error;
+	}
+
 	if (!mdp_is_hist_start) {
 		printk(KERN_ERR "%s histogram not started\n", __func__);
 		ret = -EPERM;
@@ -436,8 +447,14 @@
 	wait_for_completion_killable(&mdp_hist_comp);
 
 	mutex_lock(&mdp_hist_mutex);
-	if (mdp_is_hist_data)
+	if (mdp_is_hist_data) {
+		if (mdp_hist_force_stop && (mdp_rev == MDP_REV_303)) {
+			pr_debug("%s histogram stopped\n", __func__);
+			ret = -EINVAL;
+			goto error;
+		}
 		ret =  _mdp_copy_hist_data(hist);
+	}
 error:
 	mutex_unlock(&mdp_hist_mutex);
 	return ret;
@@ -723,6 +740,12 @@
 		if ((mdp_all_blocks_off) && (mdp_current_clk_on)) {
 			mutex_lock(&mdp_suspend_mutex);
 			if (block == MDP_MASTER_BLOCK || mdp_suspended) {
+				if ((mdp_prim_panel_type == MIPI_CMD_PANEL) &&
+					(mdp_rev == MDP_REV_303)) {
+					mdp_hist_force_stop = TRUE;
+					complete(&mdp_hist_comp);
+				}
+
 				mdp_current_clk_on = FALSE;
 				mb();
 				/* turn off MDP clks */
@@ -897,6 +920,7 @@
 				dma->busy = FALSE;
 				mdp_pipe_ctrl(MDP_DMA2_BLOCK,
 					MDP_BLOCK_POWER_OFF, TRUE);
+				mdp_hist_force_stop = FALSE;
 				complete(&dma->comp);
 			}
 #endif
@@ -1618,8 +1642,8 @@
 			if (mdp_version < 0x04030303) {
 				pr_err("%s: writeback panel not supprted\n",
 					 __func__);
-				rc = -ENODEV;
-				goto mdp_probe_err;
+				platform_device_put(msm_fb_dev);
+				return -ENODEV;
 			}
 			pdata->on = mdp4_overlay_writeback_on;
 			pdata->off = mdp4_overlay_writeback_off;
diff --git a/drivers/video/msm/mdp4.h b/drivers/video/msm/mdp4.h
index 630de1d..1a4ce91 100644
--- a/drivers/video/msm/mdp4.h
+++ b/drivers/video/msm/mdp4.h
@@ -400,6 +400,7 @@
 void mdp4_vg_qseed_init(int vg_num);
 void mdp4_vg_csc_setup(int vp_num);
 void mdp4_mixer_csc_setup(uint32 mixer);
+void mdp4_dmap_csc_setup(void);
 void mdp4_vg_csc_update(struct mdp_csc *p);
 irqreturn_t mdp4_isr(int irq, void *ptr);
 void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
@@ -414,6 +415,10 @@
 			struct mdp4_overlay_pipe *pipe);
 void mdp4_overlay_dtv_wait_for_ov(struct msm_fb_data_type *mfd,
 	struct mdp4_overlay_pipe *pipe);
+int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd,
+			struct mdp4_overlay_pipe *pipe);
+int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
+			struct mdp4_overlay_pipe *pipe);
 #else
 static inline void mdp4_overlay_dtv_vsync_push(struct msm_fb_data_type *mfd,
 	struct mdp4_overlay_pipe *pipe)
@@ -430,6 +435,16 @@
 {
 	/* empty */
 }
+static inline int mdp4_overlay_dtv_set(struct msm_fb_data_type *mfd,
+			struct mdp4_overlay_pipe *pipe)
+{
+	return 0;
+}
+static inline int mdp4_overlay_dtv_unset(struct msm_fb_data_type *mfd,
+			struct mdp4_overlay_pipe *pipe)
+{
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_FB_MSM_HDMI_AS_PRIMARY
@@ -509,7 +524,6 @@
 void mdp4_overlay_lcdc_wait4vsync(struct msm_fb_data_type *mfd);
 void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd);
 void mdp4_update_perf_level(u32 perf_level);
 void mdp4_set_perf_level(void);
 void mdp4_mddi_overlay_dmas_restore(void);
@@ -620,7 +634,6 @@
 void mdp4_dsi_blt_dmap_busy_wait(struct msm_fb_data_type *mfd);
 void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
 				struct mdp4_overlay_pipe *pipe);
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd);
 #else
 static inline void mdp4_dsi_cmd_dma_busy_wait(struct msm_fb_data_type *mfd)
 {
@@ -635,11 +648,6 @@
 {
 	/* empty */
 }
-static inline void mdp4_overlay_dsi_video_set_perf(
-				struct msm_fb_data_type *mfd)
-{
-	/* empty */
-}
 #endif /* MIPI_DSI */
 
 void mdp4_dsi_cmd_kickoff_ui(struct msm_fb_data_type *mfd,
@@ -680,10 +688,8 @@
 void mdp4_writeback_dma_busy_wait(struct msm_fb_data_type *mfd);
 void mdp4_overlay1_done_writeback(struct mdp_dma_data *dma);
 
-int mdp4_writeback_register_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data);
-int mdp4_writeback_unregister_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data);
+int mdp4_writeback_start(struct fb_info *info);
+int mdp4_writeback_stop(struct fb_info *info);
 int mdp4_writeback_dequeue_buffer(struct fb_info *info,
 		struct msmfb_data *data);
 int mdp4_writeback_queue_buffer(struct fb_info *info,
@@ -694,6 +700,7 @@
 
 void mdp4_hsic_set(struct mdp4_overlay_pipe *pipe, struct dpp_ctrl *ctrl);
 void mdp4_hsic_update(struct mdp4_overlay_pipe *pipe);
+int mdp4_csc_config(struct mdp_csc_cfg_data *config);
 
 u32  mdp4_allocate_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
 void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num);
diff --git a/drivers/video/msm/mdp4_overlay.c b/drivers/video/msm/mdp4_overlay.c
index a53102a..645a0c3 100644
--- a/drivers/video/msm/mdp4_overlay.c
+++ b/drivers/video/msm/mdp4_overlay.c
@@ -535,11 +535,6 @@
 	dst_xy = ((pipe->dst_y << 16) | pipe->dst_x);
 
 	ptype = mdp4_overlay_format2type(pipe->src_format);
-	if (pipe->src_format == MDP_Y_CR_CB_GH2V2) {
-		frame_size = ((pipe->src_height << 16) |
-					ALIGN(pipe->src_width, 16));
-		src_size = ((pipe->src_h << 16) | ALIGN(pipe->src_w, 16));
-	}
 	format = mdp4_overlay_format(pipe);
 	pattern = mdp4_overlay_unpack_pattern(pipe);
 
@@ -2205,18 +2200,21 @@
 		mdp4_overlay_dtv_set(mfd, pipe);
 
 	if (new_perf_level != perf_level) {
+		u32 old_level = new_perf_level;
 		mdp4_update_perf_level(perf_level);
 
 		/* change clck base on perf level */
 		if (pipe->mixer_num == MDP4_MIXER0) {
 			if (ctrl->panel_mode & MDP4_PANEL_DSI_VIDEO) {
-				mdp4_overlay_dsi_video_set_perf(mfd);
+				if (old_level > perf_level)
+					mdp4_set_perf_level();
 			} else if (ctrl->panel_mode & MDP4_PANEL_DSI_CMD) {
 				mdp4_dsi_cmd_dma_busy_wait(mfd);
 				mdp4_dsi_blt_dmap_busy_wait(mfd);
 				mdp4_set_perf_level();
 			} else if (ctrl->panel_mode & MDP4_PANEL_LCDC) {
-				mdp4_overlay_lcdc_set_perf(mfd);
+				if (old_level > perf_level)
+					mdp4_set_perf_level();
 			} else if (ctrl->panel_mode & MDP4_PANEL_MDDI) {
 				mdp4_mddi_dma_busy_wait(mfd);
 				mdp4_set_perf_level();
diff --git a/drivers/video/msm/mdp4_overlay_dsi_video.c b/drivers/video/msm/mdp4_overlay_dsi_video.c
index c5d1b0c..88582e4 100644
--- a/drivers/video/msm/mdp4_overlay_dsi_video.c
+++ b/drivers/video/msm/mdp4_overlay_dsi_video.c
@@ -465,13 +465,6 @@
 	pr_debug("%s: done pid=%d\n", __func__, current->pid);
 }
 
-void mdp4_overlay_dsi_video_set_perf(struct msm_fb_data_type *mfd)
-{
-	mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
-	/* change mdp clk while mdp is idle */
-	mdp4_set_perf_level();
-}
-
 void mdp4_overlay_dsi_video_vsync_push(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe)
 {
@@ -499,9 +492,10 @@
 		mb();
 		mdp4_overlay_dsi_video_wait4event(mfd, INTR_DMA_P_DONE);
 	} else {
-
 		mdp4_overlay_dsi_video_wait4event(mfd, INTR_PRIMARY_VSYNC);
 	}
+
+	mdp4_set_perf_level();
 }
 
 /*
diff --git a/drivers/video/msm/mdp4_overlay_dtv.c b/drivers/video/msm/mdp4_overlay_dtv.c
index 592febe..f2065fd 100644
--- a/drivers/video/msm/mdp4_overlay_dtv.c
+++ b/drivers/video/msm/mdp4_overlay_dtv.c
@@ -358,6 +358,12 @@
 
 	mdp4_overlay_dmae_xy(pipe);	/* dma_e */
 	mdp4_overlayproc_cfg(pipe);
+
+	if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
+		pipe->srcp0_addr = (uint32) mfd->ibuf.buf;
+		mdp4_overlay_rgb_setup(pipe);
+	}
+
 	mdp4_mixer_stage_up(pipe);
 
 	dtv_pipe = pipe; /* keep it */
diff --git a/drivers/video/msm/mdp4_overlay_lcdc.c b/drivers/video/msm/mdp4_overlay_lcdc.c
index bef988c..a905ec0 100644
--- a/drivers/video/msm/mdp4_overlay_lcdc.c
+++ b/drivers/video/msm/mdp4_overlay_lcdc.c
@@ -385,13 +385,6 @@
 	pr_debug("%s: done pid=%d\n", __func__, current->pid);
 }
 
-void mdp4_overlay_lcdc_set_perf(struct msm_fb_data_type *mfd)
-{
-	mdp4_overlay_lcdc_wait4event(mfd, INTR_DMA_P_DONE);
-	/* change mdp clk while mdp is idle */
-	mdp4_set_perf_level();
-}
-
 void mdp4_overlay_lcdc_vsync_push(struct msm_fb_data_type *mfd,
 			struct mdp4_overlay_pipe *pipe)
 {
@@ -421,6 +414,7 @@
 	} else {
 		mdp4_overlay_lcdc_wait4event(mfd, INTR_PRIMARY_VSYNC);
 	}
+	mdp4_set_perf_level();
 }
 
 /*
diff --git a/drivers/video/msm/mdp4_overlay_writeback.c b/drivers/video/msm/mdp4_overlay_writeback.c
index 8f68e11..cd4afd0 100644
--- a/drivers/video/msm/mdp4_overlay_writeback.c
+++ b/drivers/video/msm/mdp4_overlay_writeback.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
@@ -33,6 +33,12 @@
 #include "msm_fb.h"
 #include "mdp4.h"
 enum {
+	WB_OPEN,
+	WB_START,
+	WB_STOPING,
+	WB_STOP
+};
+enum {
 	REGISTERED,
 	IN_FREE_QUEUE,
 	IN_BUSY_QUEUE,
@@ -370,80 +376,48 @@
 	return 0;
 }
 static struct msmfb_writeback_data_list *get_if_registered(
-			struct msm_fb_data_type *mfd, uint32 fd, uint32 offset)
+			struct msm_fb_data_type *mfd, struct msmfb_data *data)
 {
 	struct msmfb_writeback_data_list *temp;
 	bool found = false;
 	if (!list_empty(&mfd->writeback_register_queue)) {
-		list_for_each_entry(temp, &mfd->writeback_register_queue,
-					registered_entry) {
-			if (temp && temp->buf_info.memory_id == fd
-					&& temp->buf_info.offset == offset) {
+		list_for_each_entry(temp,
+				&mfd->writeback_register_queue,
+				registered_entry) {
+			if (temp && temp->buf_info.iova == data->iova) {
 				found = true;
 				break;
 			}
 		}
 	}
-	if (found)
-		return temp;
-	return NULL;
+	if (!found) {
+		temp = kzalloc(sizeof(struct msmfb_writeback_data_list),
+				GFP_KERNEL);
+		if (temp == NULL) {
+			pr_err("Out of memory\n");
+			goto err;
+		}
+
+		temp->addr = (void *)(data->iova + data->offset);
+		memcpy(&temp->buf_info, data, sizeof(struct msmfb_data));
+		if (mdp4_overlay_writeback_register_buffer(mfd, temp)) {
+			pr_err("Error registering node\n");
+			kfree(temp);
+			temp = NULL;
+		}
+	}
+err:
+	return temp;
 }
-int mdp4_writeback_register_buffer(
-		struct fb_info *info, struct msmfb_writeback_data *data)
+int mdp4_writeback_start(
+		struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	struct msmfb_writeback_data_list *node = NULL;
-	unsigned long pmem_phys_addr, virtual_addr, len;
-	struct file *pmem_file;
-	int rv = 0;
-	if (!data || data->img.format != MDP_RGB_565) {
-		pr_err("Invalid input parameters\n");
-		return -EINVAL;
-	}
-
 	mutex_lock(&mfd->writeback_mutex);
-	node = get_if_registered(mfd, data->buf_info.memory_id,
-			data->buf_info.offset);
-	if (node) {
-		pr_err("Re-registering the same node\n");
-		rv = -EINVAL;
-		goto exit;
-	}
-
-	rv = get_pmem_file(data->buf_info.memory_id, &pmem_phys_addr,
-					&virtual_addr, &len, &pmem_file);
-
-	if (rv)
-		goto exit;
-
-	/* buffer big enough? */
-	if (len - data->buf_info.offset <
-			data->img.height * data->img.width * 2) {
-		rv = -ENOMEM;
-		goto post_get_pmem_failure;
-	}
-
-	node = kzalloc(sizeof(struct msmfb_writeback_data_list), GFP_KERNEL);
-	if (node == NULL) {
-		rv = -ENOMEM;
-		goto post_get_pmem_failure;
-	}
-
-	node->pmem_file = pmem_file;
-	node->addr = (void *)(pmem_phys_addr + node->buf_info.offset);
-	node->buf_info = data->buf_info;
-	node->img.width = data->img.width;
-	node->img.height = data->img.height;
-
-	rv = mdp4_overlay_writeback_register_buffer(mfd, node);
-post_get_pmem_failure:
-	put_pmem_file(pmem_file);
-exit:
+	mfd->writeback_state = WB_START;
 	mutex_unlock(&mfd->writeback_mutex);
-	if (rv)
-		kfree(node);
-
-	return rv;
+	wake_up(&mfd->wait_q);
+	return 0;
 }
 
 int mdp4_writeback_queue_buffer(struct fb_info *info, struct msmfb_data *data)
@@ -453,7 +427,7 @@
 	int rv = 0;
 
 	mutex_lock(&mfd->writeback_mutex);
-	node = get_if_registered(mfd, data->memory_id, data->offset);
+	node = get_if_registered(mfd, data);
 	if (!node || node->state == IN_BUSY_QUEUE ||
 		node->state == IN_FREE_QUEUE) {
 		pr_err("memory not registered or Buffer already with us\n");
@@ -472,8 +446,8 @@
 {
 	int rc;
 	mutex_lock(&mfd->writeback_mutex);
-	rc = list_empty(&mfd->writeback_register_queue)
-			|| !list_empty(&mfd->writeback_busy_queue);
+	rc = !list_empty(&mfd->writeback_busy_queue) ||
+			(mfd->writeback_state == WB_STOPING);
 	mutex_unlock(&mfd->writeback_mutex);
 	return rc;
 }
@@ -489,7 +463,8 @@
 		return -ENOBUFS;
 	}
 	mutex_lock(&mfd->writeback_mutex);
-	if (list_empty(&mfd->writeback_register_queue)) {
+	if (mfd->writeback_state == WB_STOPING) {
+		mfd->writeback_state = WB_STOP;
 		mutex_unlock(&mfd->writeback_mutex);
 		return -ENOBUFS;
 	} else	if (!list_empty(&mfd->writeback_busy_queue)) {
@@ -508,46 +483,12 @@
 	return rc;
 }
 
-int mdp4_writeback_unregister_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data)
+int mdp4_writeback_stop(struct fb_info *info)
 {
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
-	struct msmfb_writeback_data_list *node = NULL;
-	struct list_head *ptr, *next;
-	struct msmfb_writeback_data_list *temp;
-	mutex_lock(&mfd->unregister_mutex);
 	mutex_lock(&mfd->writeback_mutex);
-	node = get_if_registered(mfd, data->buf_info.memory_id,
-			data->buf_info.offset);
-	if (!node) {
-		pr_err("trying to unregister an "
-			"already unregistered buffer\n");
-	} else {
-		list_del(&node->registered_entry);
-		if (!list_empty(&mfd->writeback_free_queue)) {
-			list_for_each_safe(ptr, next,
-					&mfd->writeback_free_queue) {
-				temp = list_entry(ptr,
-					struct msmfb_writeback_data_list,
-					active_entry);
-				if (temp == node)
-					list_del(&node->active_entry);
-			}
-		}
-		if (!list_empty(&mfd->writeback_busy_queue)) {
-			list_for_each_safe(ptr, next,
-						&mfd->writeback_busy_queue) {
-				temp = list_entry(ptr,
-					struct msmfb_writeback_data_list,
-					active_entry);
-				if (temp == node)
-					list_del(&node->active_entry);
-			}
-		}
-		kfree(node);
-	}
+	mfd->writeback_state = WB_STOPING;
 	mutex_unlock(&mfd->writeback_mutex);
-	mutex_unlock(&mfd->unregister_mutex);
 	wake_up(&mfd->wait_q);
 	return 0;
 }
@@ -559,14 +500,31 @@
 	INIT_LIST_HEAD(&mfd->writeback_free_queue);
 	INIT_LIST_HEAD(&mfd->writeback_busy_queue);
 	INIT_LIST_HEAD(&mfd->writeback_register_queue);
+	mfd->writeback_state = WB_OPEN;
 	init_waitqueue_head(&mfd->wait_q);
 	return 0;
 }
 int mdp4_writeback_terminate(struct fb_info *info)
 {
+	struct list_head *ptr, *next;
+	struct msmfb_writeback_data_list *temp;
 	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+	mutex_lock(&mfd->unregister_mutex);
+	mutex_lock(&mfd->writeback_mutex);
+	if (!list_empty(&mfd->writeback_register_queue)) {
+		list_for_each_safe(ptr, next,
+				&mfd->writeback_register_queue) {
+			temp = list_entry(ptr,
+					struct msmfb_writeback_data_list,
+					registered_entry);
+			list_del(&temp->registered_entry);
+			kfree(temp);
+		}
+	}
 	INIT_LIST_HEAD(&mfd->writeback_register_queue);
 	INIT_LIST_HEAD(&mfd->writeback_busy_queue);
 	INIT_LIST_HEAD(&mfd->writeback_free_queue);
+	mutex_unlock(&mfd->writeback_mutex);
+	mutex_unlock(&mfd->unregister_mutex);
 	return 0;
 }
diff --git a/drivers/video/msm/mdp4_util.c b/drivers/video/msm/mdp4_util.c
index e30f76a..bd8ec55 100644
--- a/drivers/video/msm/mdp4_util.c
+++ b/drivers/video/msm/mdp4_util.c
@@ -275,6 +275,7 @@
 	mdp4_vg_csc_setup(1);
 	mdp4_mixer_csc_setup(1);
 	mdp4_mixer_csc_setup(2);
+	mdp4_dmap_csc_setup();
 
 	if (mdp_rev <= MDP_REV_41) {
 		mdp4_mixer_gc_lut_setup(0);
@@ -1238,7 +1239,7 @@
 uint32 csc_post_bv[3];
 uint32 csc_pre_lv[6];
 uint32 csc_post_lv[6];
-} csc_matrix[2] = {
+} csc_matrix[3] = {
 	{
 		{
 			0x0254, 0x0000, 0x0331,
@@ -1277,6 +1278,25 @@
 			0, 0xff, 0, 0xff, 0, 0xff,
 		},
 	},
+	{
+		{
+			0x0200, 0x0000, 0x0000,
+			0x0000, 0x0200, 0x0000,
+			0x0000, 0x0000, 0x0200,
+		},
+		{
+			0x0, 0x0, 0x0,
+		},
+		{
+			0, 0, 0,
+		},
+		{
+			0, 0xff, 0, 0xff, 0, 0xff,
+		},
+		{
+			0, 0xff, 0, 0xff, 0, 0xff,
+		},
+	},
 };
 
 
@@ -1529,6 +1549,91 @@
 	}
 }
 
+#define DMA_P_BASE 0x90000
+void mdp4_dmap_csc_mv_setup(void)
+{
+	uint32 *off;
+	int i;
+
+	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3400);
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < 9; i++) {
+		outpdw(off, csc_matrix[2].csc_mv[i]);
+		off++;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+void mdp4_dmap_csc_pre_bv_setup(void)
+{
+	uint32 *off;
+	int i;
+
+	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3500);
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < 3; i++) {
+		outpdw(off, csc_matrix[2].csc_pre_bv[i]);
+		off++;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+void mdp4_dmap_csc_post_bv_setup(void)
+{
+	uint32 *off;
+	int i;
+
+	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3580);
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < 3; i++) {
+		outpdw(off, csc_matrix[2].csc_post_bv[i]);
+		off++;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+void mdp4_dmap_csc_pre_lv_setup(void)
+{
+	uint32 *off;
+	int i;
+
+	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3600);
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < 6; i++) {
+		outpdw(off, csc_matrix[2].csc_pre_lv[i]);
+		off++;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+void mdp4_dmap_csc_post_lv_setup(void)
+{
+	uint32 *off;
+	int i;
+
+	off = (uint32 *)(MDP_BASE + DMA_P_BASE + 0x3680);
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	for (i = 0; i < 6; i++) {
+		outpdw(off, csc_matrix[2].csc_post_lv[i]);
+		off++;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+void mdp4_dmap_csc_setup(void)
+{
+	mdp4_dmap_csc_mv_setup();
+	mdp4_dmap_csc_pre_bv_setup();
+	mdp4_dmap_csc_post_bv_setup();
+	mdp4_dmap_csc_pre_lv_setup();
+	mdp4_dmap_csc_post_lv_setup();
+}
+
 char gc_lut[] = {
 	0x0, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x6,
 	0x6, 0x7, 0x8, 0x9, 0xA, 0xA, 0xB, 0xC,
@@ -2226,6 +2331,108 @@
 	return out;
 }
 
+static uint32_t mdp4_csc_block2base(uint32_t block)
+{
+	uint32_t base = 0x0;
+	switch (block) {
+	case MDP_BLOCK_OVERLAY_1:
+		base = 0x1A000;
+		break;
+	case MDP_BLOCK_VG_1:
+		base = 0x24000;
+		break;
+	case MDP_BLOCK_VG_2:
+		base = 0x34000;
+		break;
+	case MDP_BLOCK_DMA_P:
+		base = 0x93000;
+		break;
+	default:
+		break;
+	}
+	return base;
+}
+
+static int mdp4_csc_enable(struct mdp_csc_cfg_data *config)
+{
+	uint32_t output, base, temp, mask;
+
+	switch (config->block) {
+	case MDP_BLOCK_DMA_P:
+		base = 0x90070;
+		output = (config->csc_data.flags << 3) & (0x08);
+		temp = (config->csc_data.flags << 10) & (0x1800);
+		output |= temp;
+		mask = 0x08 | 0x1800;
+		break;
+	case MDP_BLOCK_VG_1:
+	case MDP_BLOCK_VG_2:
+	case MDP_BLOCK_OVERLAY_1:
+	default:
+		pr_err("%s - CSC block does not exist on MDP_BLOCK = %d\n",
+						__func__, config->block);
+		return -EINVAL;
+	}
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	temp = inpdw(MDP_BASE + base) & ~mask;
+	output |= temp;
+	outpdw(MDP_BASE + base, output);
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+	return 0;
+}
+
+#define CSC_MV_OFF	0x400
+#define CSC_BV_OFF	0x500
+#define CSC_LV_OFF	0x600
+#define CSC_POST_OFF	0x80
+
+int mdp4_csc_config(struct mdp_csc_cfg_data *config)
+{
+	int ret = 0;
+	int i;
+	uint32_t base, *off;
+
+	base = mdp4_csc_block2base(config->block);
+	if (!base)
+		return -EINVAL;
+
+	/* TODO: implement other CSC block support */
+	if (config->block != MDP_BLOCK_DMA_P) {
+		pr_warn("%s: Only DMA_P currently supported by CSC.\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+	off = (uint32_t *) (MDP_BASE + base + CSC_MV_OFF);
+	for (i = 0; i < 9; i++) {
+		outpdw(off, config->csc_data.csc_mv[i]);
+		off++;
+	}
+
+	off = (uint32_t *) (MDP_BASE + base + CSC_BV_OFF);
+	for (i = 0; i < 3; i++) {
+		outpdw(off, config->csc_data.csc_pre_bv[i]);
+		outpdw((uint32_t *)((uint32_t)off + CSC_POST_OFF),
+					config->csc_data.csc_post_bv[i]);
+		off++;
+	}
+
+	off = (uint32_t *) (MDP_BASE + base + CSC_LV_OFF);
+	for (i = 0; i < 6; i++) {
+		outpdw(off, config->csc_data.csc_pre_lv[i]);
+		outpdw((uint32_t *)((uint32_t)off + CSC_POST_OFF),
+					config->csc_data.csc_post_lv[i]);
+		off++;
+	}
+	mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+	ret = mdp4_csc_enable(config);
+
+	return ret;
+}
+
 void mdp4_init_writeback_buf(struct msm_fb_data_type *mfd, u32 mix_num)
 {
 	struct mdp_buf_type *buf;
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
index 8845fa2..6025139 100644
--- a/drivers/video/msm/msm_fb.c
+++ b/drivers/video/msm/msm_fb.c
@@ -2641,43 +2641,31 @@
 {
 	return mdp4_writeback_init(info);
 }
-static int msmfb_overlay_ioctl_writeback_register_buffer(
-		struct fb_info *info, unsigned long *argp)
+static int msmfb_overlay_ioctl_writeback_start(
+		struct fb_info *info)
 {
 	int ret = 0;
-	struct msmfb_writeback_data data;
-
-	ret = copy_from_user(&data, argp, sizeof(data));
-	if (ret)
-		goto error;
-
-	ret = mdp4_writeback_register_buffer(info, &data);
+	ret = mdp4_writeback_start(info);
 	if (ret)
 		goto error;
 error:
 	if (ret)
-		pr_err("%s:msmfb_writeback_register_buffer "
+		pr_err("%s:msmfb_writeback_start "
 				" ioctl failed\n", __func__);
 	return ret;
 }
 
-static int msmfb_overlay_ioctl_writeback_unregister_buffer(
-		struct fb_info *info, unsigned long *argp)
+static int msmfb_overlay_ioctl_writeback_stop(
+		struct fb_info *info)
 {
 	int ret = 0;
-	struct msmfb_writeback_data data;
-
-	ret = copy_from_user(&data, argp, sizeof(data));
-	if (ret)
-		goto error;
-
-	ret = mdp4_writeback_unregister_buffer(info, &data);
+	ret = mdp4_writeback_stop(info);
 	if (ret)
 		goto error;
 
 error:
 	if (ret)
-		pr_err("%s:msmfb_writeback_unregister_buffer ioctl failed\n",
+		pr_err("%s:msmfb_writeback_stop ioctl failed\n",
 				__func__);
 	return ret;
 }
@@ -2737,14 +2725,14 @@
 {
 	return -ENOTSUPP;
 }
-static int msmfb_overlay_ioctl_writeback_register_buffer(
-		struct fb_info *info, unsigned long *argp)
+static int msmfb_overlay_ioctl_writeback_start(
+		struct fb_info *info)
 {
 	return -ENOTSUPP;
 }
 
-static int msmfb_overlay_ioctl_writeback_unregister_buffer(
-		struct fb_info *info, unsigned long *argp)
+static int msmfb_overlay_ioctl_writeback_stop(
+		struct fb_info *info)
 {
 	return -ENOTSUPP;
 }
@@ -2949,13 +2937,13 @@
 	case MSMFB_WRITEBACK_INIT:
 		ret = msmfb_overlay_ioctl_writeback_init(info);
 		break;
-	case MSMFB_WRITEBACK_REGISTER_BUFFER:
-		ret = msmfb_overlay_ioctl_writeback_register_buffer(
-				info, argp);
+	case MSMFB_WRITEBACK_START:
+		ret = msmfb_overlay_ioctl_writeback_start(
+				info);
 		break;
-	case MSMFB_WRITEBACK_UNREGISTER_BUFFER:
-		ret = msmfb_overlay_ioctl_writeback_unregister_buffer(
-				info, argp);
+	case MSMFB_WRITEBACK_STOP:
+		ret = msmfb_overlay_ioctl_writeback_stop(
+				info);
 		break;
 	case MSMFB_WRITEBACK_QUEUE_BUFFER:
 		ret = msmfb_overlay_ioctl_writeback_queue_buffer(
@@ -3172,13 +3160,18 @@
 		if (ret)
 			return ret;
 
-		switch (mdp_pp.op) { /*Add PCC, CSC, and LUT op handling here*/
+		switch (mdp_pp.op) { /*Add PCC and LUT op handling here*/
 #ifdef CONFIG_FB_MSM_MDP40
 		case mdp_op_csc_cfg:
+			ret = mdp4_csc_config((struct mdp_csc_cfg_data *)
+					&(mdp_pp.data));
+			break;
 		case mdp_op_pcc_cfg:
 		case mdp_op_lut_cfg:
 #endif
 		default:
+			pr_warn("%s: Only CSC supported by MDP_PP IOCTL.\n",
+					__func__);
 			ret = -EINVAL;
 			break;
 		}
@@ -3213,12 +3206,11 @@
 }
 EXPORT_SYMBOL(msm_fb_get_writeback_fb);
 
-int msm_fb_writeback_register_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data)
+int msm_fb_writeback_start(struct fb_info *info)
 {
-	return mdp4_writeback_register_buffer(info, data);
+	return mdp4_writeback_start(info);
 }
-EXPORT_SYMBOL(msm_fb_writeback_register_buffer);
+EXPORT_SYMBOL(msm_fb_writeback_start);
 
 int msm_fb_writeback_queue_buffer(struct fb_info *info,
 		struct msmfb_data *data)
@@ -3234,12 +3226,11 @@
 }
 EXPORT_SYMBOL(msm_fb_writeback_dequeue_buffer);
 
-int msm_fb_writeback_unregister_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data)
+int msm_fb_writeback_stop(struct fb_info *info)
 {
-	return mdp4_writeback_unregister_buffer(info, data);
+	return mdp4_writeback_stop(info);
 }
-EXPORT_SYMBOL(msm_fb_writeback_unregister_buffer);
+EXPORT_SYMBOL(msm_fb_writeback_stop);
 int msm_fb_writeback_init(struct fb_info *info)
 {
 	return mdp4_writeback_init(info);
diff --git a/drivers/video/msm/msm_fb.h b/drivers/video/msm/msm_fb.h
index 8c48a73..9837f07 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 writeback_state;
 };
 
 struct dentry *msm_fb_get_debugfs_root(void);
@@ -187,14 +188,12 @@
 struct platform_device *msm_fb_add_device(struct platform_device *pdev);
 struct fb_info *msm_fb_get_writeback_fb(void);
 int msm_fb_writeback_init(struct fb_info *info);
-int msm_fb_writeback_register_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data);
+int msm_fb_writeback_start(struct fb_info *info);
 int msm_fb_writeback_queue_buffer(struct fb_info *info,
 		struct msmfb_data *data);
 int msm_fb_writeback_dequeue_buffer(struct fb_info *info,
 		struct msmfb_data *data);
-int msm_fb_writeback_unregister_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data);
+int msm_fb_writeback_stop(struct fb_info *info);
 int msm_fb_writeback_terminate(struct fb_info *info);
 int msm_fb_detect_client(const char *name);
 
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
index e9c5193..a0d30b6 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.h
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_core.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
@@ -63,6 +63,7 @@
 #define DDL_FW_AUX_HOST_CMD_SPACE_SIZE         (DDL_KILO_BYTE(8))
 #define DDL_FW_INST_GLOBAL_CONTEXT_SPACE_SIZE  (DDL_KILO_BYTE(800))
 #define DDL_FW_H264DEC_CONTEXT_SPACE_SIZE      (DDL_KILO_BYTE(800))
+#define DDL_FW_H264ENC_CONTEXT_SPACE_SIZE      (DDL_KILO_BYTE(20))
 #define DDL_FW_OTHER_CONTEXT_SPACE_SIZE        (DDL_KILO_BYTE(10))
 
 #define VCD_DEC_CPB_SIZE         (DDL_KILO_BYTE(512))
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
index b3790a5..d54c01e 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_helper.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
@@ -751,6 +751,7 @@
 		sz_cur_c = sz_dpb_c;
 	} else
 		status = VCD_ERR_NOT_SUPPORTED;
+	sz_context = DDL_FW_OTHER_CONTEXT_SPACE_SIZE;
 	if (!status) {
 		sz_strm = DDL_ALIGN(ddl_get_yuv_buf_size(width, height,
 			DDL_YUV_BUF_TYPE_LINEAR) + ddl_get_yuv_buf_size(width,
@@ -768,6 +769,7 @@
 		} else if (codec == VCD_CODEC_H264) {
 			sz_md = DDL_ALIGN(mb_x * 48, DDL_KILO_BYTE(2));
 			sz_pred = DDL_ALIGN(2 * 8 * 1024, DDL_KILO_BYTE(2));
+			sz_context = DDL_FW_H264ENC_CONTEXT_SPACE_SIZE;
 			if (ddl) {
 				if (ddl->codec_data.encoder.
 					entropy_control.entropy_sel ==
@@ -792,7 +794,6 @@
 			sz_mb_info = DDL_ALIGN(mb_x * mb_y * 6 * 8,
 					DDL_KILO_BYTE(2));
 		}
-		sz_context = DDL_FW_OTHER_CONTEXT_SPACE_SIZE;
 		if (buf_size) {
 			buf_size->sz_cur_y      = sz_cur_y;
 			buf_size->sz_cur_c      = sz_cur_c;
diff --git a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
index cc35ea3..8eba8bd 100644
--- a/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
+++ b/drivers/video/msm/vidc/1080p/ddl/vcd_ddl_interrupt_handler.c
@@ -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
@@ -15,6 +15,7 @@
 #include "vcd_ddl.h"
 #include "vcd_ddl_shared_mem.h"
 #include "vcd_ddl_metadata.h"
+#include "vcd_res_tracker_api.h"
 #include <linux/delay.h>
 
 static void ddl_decoder_input_done_callback(
@@ -254,6 +255,13 @@
 		DDL_MSG_LOW("HEADER_DONE");
 		vidc_1080p_get_decode_seq_start_result(&seq_hdr_info);
 		parse_hdr_size_data(ddl, &seq_hdr_info);
+		if (res_trk_get_disable_fullhd() &&
+			(seq_hdr_info.img_size_x * seq_hdr_info.img_size_y >
+				1280 * 720)) {
+			DDL_MSG_ERROR("FATAL:Resolution greater than 720P HD");
+			ddl_client_fatal_cb(ddl);
+			return process_further;
+		}
 		if (!seq_hdr_info.img_size_x || !seq_hdr_info.img_size_y) {
 			DDL_MSG_ERROR("FATAL:ZeroImageSize");
 			ddl_client_fatal_cb(ddl);
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 3a86afc..9c2e5d1 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
@@ -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
@@ -441,6 +441,8 @@
 			}
 			resource_context.disable_dmx =
 			resource_context.vidc_platform_data->disable_dmx;
+			resource_context.disable_fullhd =
+			resource_context.vidc_platform_data->disable_fullhd;
 #ifdef CONFIG_MSM_BUS_SCALING
 			resource_context.vidc_bus_client_pdata =
 			resource_context.vidc_platform_data->
@@ -485,7 +487,7 @@
 	case DDL_MM_MEM:
 		return resource_context.memtype;
 	case DDL_CMD_MEM:
-		return resource_context.cmd_mem_type;
+		return resource_context.memtype;
 	default:
 		return 0;
 	}
@@ -513,3 +515,8 @@
 	resource_context.res_mem_type = mem_type;
 	return;
 }
+
+u32 res_trk_get_disable_fullhd(void)
+{
+	return resource_context.disable_fullhd;
+}
diff --git a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
index 7283991..be5045f 100644
--- a/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
+++ b/drivers/video/msm/vidc/1080p/resource_tracker/vcd_res_tracker.h
@@ -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 @@
 	struct ddl_buf_addr firmware_addr;
 	struct ion_client *res_ion_client;
 	u32 disable_dmx;
+	u32 disable_fullhd;
 	enum ddl_mem_area res_mem_type;
 };
 
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 47fa363..fd4ca3e 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
@@ -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
@@ -31,6 +31,7 @@
 u32 res_trk_get_firmware_addr(struct ddl_buf_addr *firm_addr);
 u32 res_trk_get_mem_type(void);
 u32 res_trk_get_enable_ion(void);
+u32 res_trk_get_disable_fullhd(void);
 struct ion_client *res_trk_get_ion_client(void);
 u32 res_trk_get_disable_dmx(void);
 void res_trk_set_mem_type(enum ddl_mem_area mem_type);
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 0172427..ee76ff1 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
@@ -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
@@ -723,3 +723,8 @@
 {
 	return;
 }
+
+u32 res_trk_get_disable_fullhd(void)
+{
+	return 0;
+}
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 fbc91e2..34f2103 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
@@ -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
@@ -28,6 +28,7 @@
 u32 res_trk_download_firmware(void);
 u32 res_trk_get_core_type(void);
 u32 res_trk_get_mem_type(void);
+u32 res_trk_get_disable_fullhd(void);
 u32 res_trk_get_enable_ion(void);
 struct ion_client *res_trk_get_ion_client(void);
 void res_trk_set_mem_type(enum ddl_mem_area mem_type);
diff --git a/drivers/video/msm/vidc/common/enc/venc_internal.c b/drivers/video/msm/vidc/common/enc/venc_internal.c
index 47f2db5..1dbd170 100644
--- a/drivers/video/msm/vidc/common/enc/venc_internal.c
+++ b/drivers/video/msm/vidc/common/enc/venc_internal.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
@@ -1745,7 +1745,7 @@
 	} else {
 		client_ctx->recon_buffer_ion_handle[i] = ion_import_fd(
 				client_ctx->user_ion_client, control->pmem_fd);
-		if (!client_ctx->recon_buffer_ion_handle[i]) {
+		if (IS_ERR_OR_NULL(client_ctx->recon_buffer_ion_handle[i])) {
 			ERR("%s(): get_ION_handle failed\n", __func__);
 			goto ion_error;
 		}
diff --git a/drivers/video/msm/vidc/common/vcd/vcd_sub.c b/drivers/video/msm/vidc/common/vcd/vcd_sub.c
index 77affcd..bb3e652 100644
--- a/drivers/video/msm/vidc/common/vcd/vcd_sub.c
+++ b/drivers/video/msm/vidc/common/vcd/vcd_sub.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
@@ -2812,7 +2812,12 @@
 	u32 rc;
 	u32 frm_p_units;
 	(void)frm_size;
-
+	if (res_trk_get_disable_fullhd() && frm_size &&
+		(frm_size->width * frm_size->height > 1280 * 720)) {
+		VCD_MSG_ERROR("Frame size = %dX%d greater than 1280X720 not"
+			"supported", frm_size->width, frm_size->height);
+		return VCD_ERR_FAIL;
+	}
 	prop_hdr.prop_id = DDL_I_FRAME_PROC_UNITS;
 	prop_hdr.sz = sizeof(frm_p_units);
 	rc = ddl_get_property(cctxt->ddl_handle, &prop_hdr, &frm_p_units);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 7213b52..b9d46fa 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -107,6 +107,28 @@
 }
 #endif
 
+/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
+static inline int clk_prepare_enable(struct clk *clk)
+{
+	int ret;
+
+	ret = clk_prepare(clk);
+	if (ret)
+		return ret;
+	ret = clk_enable(clk);
+	if (ret)
+		clk_unprepare(clk);
+
+	return ret;
+}
+
+/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
+static inline void clk_disable_unprepare(struct clk *clk)
+{
+	clk_disable(clk);
+	clk_unprepare(clk);
+}
+
 /**
  * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
  *		  This is only valid once the clock source has been enabled.
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 8d0ca45..97f1ca7 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -134,7 +134,6 @@
 
 extern void get_online_cpus(void);
 extern void put_online_cpus(void);
-extern bool cpu_hotplug_inprogress(void);
 #define hotcpu_notifier(fn, pri)	cpu_notifier(fn, pri)
 #define register_hotcpu_notifier(nb)	register_cpu_notifier(nb)
 #define unregister_hotcpu_notifier(nb)	unregister_cpu_notifier(nb)
diff --git a/include/linux/fsm_dfe_hh.h b/include/linux/fsm_dfe_hh.h
index 5f09f1e..7938518 100644
--- a/include/linux/fsm_dfe_hh.h
+++ b/include/linux/fsm_dfe_hh.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
@@ -60,9 +60,6 @@
 };
 
 #define DFE_IOCTL_MAGIC				'h'
-#define DFE_IOCTL_IS_UMTS \
-	_IOC(_IOC_READ, DFE_IOCTL_MAGIC, 0x00, \
-		0)
 #define DFE_IOCTL_READ_REGISTER \
 	_IOC(_IOC_READ, DFE_IOCTL_MAGIC, 0x01, \
 		sizeof(unsigned int *))
diff --git a/include/linux/fsm_rfic_ftr.h b/include/linux/fsm_rfic_ftr.h
index 5e8cd89..18b7947 100644
--- a/include/linux/fsm_rfic_ftr.h
+++ b/include/linux/fsm_rfic_ftr.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
@@ -52,9 +52,6 @@
 };
 
 #define RFIC_IOCTL_MAGIC				'f'
-#define RFIC_IOCTL_IS_UMTS \
-	_IOC(_IOC_READ, RFIC_IOCTL_MAGIC, 0x00, \
-		0)
 #define RFIC_IOCTL_READ_REGISTER \
 	_IOC(_IOC_READ, RFIC_IOCTL_MAGIC, 0x01, \
 		sizeof(unsigned int *))
diff --git a/include/linux/idle_stats_device.h b/include/linux/idle_stats_device.h
index 7906d18..a531b7a 100644
--- a/include/linux/idle_stats_device.h
+++ b/include/linux/idle_stats_device.h
@@ -72,6 +72,8 @@
 void msm_idle_stats_idle_start(struct msm_idle_stats_device *device);
 void msm_idle_stats_idle_end(struct msm_idle_stats_device *device,
 				struct msm_idle_pulse *pulse);
+void msm_idle_stats_update_event(struct msm_idle_stats_device *device,
+				__u32 event);
 #endif
 
 #endif  /* __ARCH_ARM_MACH_MSM_IDLE_STATS_DEVICE_H */
diff --git a/include/linux/ion.h b/include/linux/ion.h
index 4f8756a..fa5017a 100644
--- a/include/linux/ion.h
+++ b/include/linux/ion.h
@@ -2,6 +2,7 @@
  * include/linux/ion.h
  *
  * Copyright (C) 2011 Google, Inc.
+ * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -29,13 +30,18 @@
  * @ION_HEAP_TYPE_CARVEOUT:	 memory allocated from a prereserved
  * 				 carveout heap, allocations are physically
  * 				 contiguous
- * @ION_HEAP_END:		 helper for iterating over heaps
+ * @ION_HEAP_TYPE_IOMMU: IOMMU memory
+ * @ION_HEAP_TYPE_CP:	 memory allocated from a prereserved
+ *				carveout heap, allocations are physically
+ *				contiguous. Used for content protection.
+ * @ION_HEAP_END:		helper for iterating over heaps
  */
 enum ion_heap_type {
 	ION_HEAP_TYPE_SYSTEM,
 	ION_HEAP_TYPE_SYSTEM_CONTIG,
 	ION_HEAP_TYPE_CARVEOUT,
 	ION_HEAP_TYPE_IOMMU,
+	ION_HEAP_TYPE_CP,
 	ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
 				 are at the end of this enum */
 	ION_NUM_HEAPS,
@@ -44,6 +50,7 @@
 #define ION_HEAP_SYSTEM_MASK		(1 << ION_HEAP_TYPE_SYSTEM)
 #define ION_HEAP_SYSTEM_CONTIG_MASK	(1 << ION_HEAP_TYPE_SYSTEM_CONTIG)
 #define ION_HEAP_CARVEOUT_MASK		(1 << ION_HEAP_TYPE_CARVEOUT)
+#define ION_HEAP_CP_MASK		(1 << ION_HEAP_TYPE_CP)
 
 
 /**
@@ -120,6 +127,8 @@
  * @name:	used for debug purposes
  * @base:	base address of heap in physical memory if applicable
  * @size:	size of the heap in bytes if applicable
+ * @memory_type:	Memory type used for the heap
+ * @ion_memory_id:		Memory ID used to identify the memory to TZ
  * @request_region: function to be called when the number of allocations goes
  *						from 0 -> 1
  * @release_region: function to be called when the number of allocations goes
@@ -135,6 +144,17 @@
 	ion_phys_addr_t base;
 	size_t size;
 	enum ion_memory_types memory_type;
+	void *extra_data;
+};
+
+struct ion_cp_heap_pdata {
+	enum ion_permission_type permission_type;
+	int (*request_region)(void *);
+	int (*release_region)(void *);
+	void *(*setup_region)(void);
+};
+
+struct ion_co_heap_pdata {
 	int (*request_region)(void *);
 	int (*release_region)(void *);
 	void *(*setup_region)(void);
@@ -386,6 +406,48 @@
 			int domain_num, int partition_num);
 
 
+/**
+ * ion_secure_heap - secure a heap
+ *
+ * @client - a client that has allocated from the heap heap_id
+ * @heap_id - heap id to secure.
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int ion_secure_heap(struct ion_device *dev, int heap_id);
+
+/**
+ * ion_unsecure_heap - un-secure a heap
+ *
+ * @client - a client that has allocated from the heap heap_id
+ * @heap_id - heap id to un-secure.
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int ion_unsecure_heap(struct ion_device *dev, int heap_id);
+
+/**
+ * msm_ion_secure_heap - secure a heap. Wrapper around ion_secure_heap.
+ *
+  * @heap_id - heap id to secure.
+ *
+ * Secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_secure_heap(int heap_id);
+
+/**
+ * msm_ion_unsecure_heap - unsecure a heap. Wrapper around ion_unsecure_heap.
+ *
+  * @heap_id - heap id to secure.
+ *
+ * Un-secure a heap
+ * Returns 0 on success
+ */
+int msm_ion_unsecure_heap(int heap_id);
+
 #else
 static inline struct ion_client *ion_client_create(struct ion_device *dev,
 				     unsigned int heap_mask, const char *name)
@@ -475,7 +537,27 @@
 	return;
 }
 
+static inline int ion_secure_heap(struct ion_device *dev, int heap_id)
+{
+	return -ENODEV;
 
+}
+
+static inline int ion_unsecure_heap(struct ion_device *dev, int heap_id)
+{
+	return -ENODEV;
+}
+
+static inline int msm_ion_secure_heap(int heap_id)
+{
+	return -ENODEV;
+
+}
+
+static inline int msm_ion_unsecure_heap(int heap_id)
+{
+	return -ENODEV;
+}
 #endif /* CONFIG_ION */
 #endif /* __KERNEL__ */
 
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 99834e58..60ee260 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -89,8 +89,14 @@
 	     hw < d->hwirq_base + d->nr_irq; \
 	     hw++, irq = irq_domain_to_irq(d, hw))
 
-extern void irq_domain_add(struct irq_domain *domain);
+extern int irq_domain_add(struct irq_domain *domain);
 extern void irq_domain_del(struct irq_domain *domain);
+extern void irq_domain_register(struct irq_domain *domain);
+extern void irq_domain_register_irq(struct irq_domain *domain, int hwirq);
+extern void irq_domain_unregister(struct irq_domain *domain);
+extern void irq_domain_unregister_irq(struct irq_domain *domain, int hwirq);
+extern int irq_domain_find_free_range(unsigned int from, unsigned int cnt);
+
 #endif /* CONFIG_IRQ_DOMAIN */
 
 #if defined(CONFIG_IRQ_DOMAIN) && defined(CONFIG_OF_IRQ)
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index 3e574ff..a954364 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -137,26 +137,6 @@
 	PM8921_CHG_SRC_DC,
 };
 
-/**
- * struct ext_chg_pm8921 -
- * @name:		name of the external charger
- * @ctx:		client context.
- * @start_charging:	callback to start charging. Can be called from an
- *			interrupt context
- * @stop_charging:	callback to stop charging. Can be called from an
- *			interrupt context
- * @is_trickle:		callback to check if trickle charging.
- *			Can be called from an interrupt context
- *
- */
-struct ext_chg_pm8921 {
-	const char	*name;
-	void		*ctx;
-	int		(*start_charging) (void *ctx);
-	int		(*stop_charging) (void *ctx);
-	bool		(*is_trickle) (void *ctx);
-};
-
 #if defined(CONFIG_PM8921_CHARGER) || defined(CONFIG_PM8921_CHARGER_MODULE)
 void pm8921_charger_vbus_draw(unsigned int mA);
 int pm8921_charger_register_vbus_sn(void (*callback)(int));
@@ -253,28 +233,6 @@
  */
 int pm8921_batt_temperature(void);
 /**
- * register_external_dc_charger -
- * @ext:	The structure representing an external charger
- *
- * RETURNS:	Negative error code is there was a problem. Zero for sucess
- *
- * The charger callbacks might be called even before this function
- * completes. The external charger driver should be ready to handle
- * it.
- */
-int register_external_dc_charger(struct ext_chg_pm8921 *ext);
-
-/**
- * unregister_external_dc_charger -
- * @ext:	The structure representing an external charger
- *
- * The charger callbacks might be called even before this function
- * completes. The external charger driver should be ready to handle
- * it.
- */
-void unregister_external_dc_charger(struct ext_chg_pm8921 *ext);
-
-/**
  * pm8921_usb_ovp_set_threshold -
  * Set the usb threshold as defined in by
  * enum usb_ov_threshold
@@ -355,15 +313,6 @@
 {
 	return -ENXIO;
 }
-static inline int register_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
-	pr_err("%s.not implemented.\n", __func__);
-	return -ENODEV;
-}
-static inline void unregister_external_dc_charger(struct ext_chg_pm8921 *ext)
-{
-	pr_err("%s.not implemented.\n", __func__);
-}
 static inline int pm8921_usb_ovp_set_threshold(enum pm8921_usb_ov_threshold ov)
 {
 	return -ENXIO;
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index f3ef5e2..cac7758 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -55,10 +55,8 @@
 #define MSMFB_OVERLAY_PLAY_WAIT _IOWR(MSMFB_IOCTL_MAGIC, 149, \
 						struct msmfb_overlay_data)
 #define MSMFB_WRITEBACK_INIT _IO(MSMFB_IOCTL_MAGIC, 150)
-#define MSMFB_WRITEBACK_REGISTER_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 151, \
-						struct msmfb_writeback_data)
-#define MSMFB_WRITEBACK_UNREGISTER_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 152, \
-						struct msmfb_writeback_data)
+#define MSMFB_WRITEBACK_START _IO(MSMFB_IOCTL_MAGIC, 151)
+#define MSMFB_WRITEBACK_STOP _IO(MSMFB_IOCTL_MAGIC, 152)
 #define MSMFB_WRITEBACK_QUEUE_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 153, \
 						struct msmfb_data)
 #define MSMFB_WRITEBACK_DEQUEUE_BUFFER _IOW(MSMFB_IOCTL_MAGIC, 154, \
@@ -229,6 +227,7 @@
 	int id;
 	uint32_t flags;
 	uint32_t priv;
+	uint32_t iova;
 };
 
 #define MSMFB_NEW_REQUEST -1
@@ -446,14 +445,12 @@
 int get_fb_phys_info(unsigned long *start, unsigned long *len, int fb_num);
 struct fb_info *msm_fb_get_writeback_fb(void);
 int msm_fb_writeback_init(struct fb_info *info);
-int msm_fb_writeback_register_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data);
+int msm_fb_writeback_start(struct fb_info *info);
 int msm_fb_writeback_queue_buffer(struct fb_info *info,
 		struct msmfb_data *data);
 int msm_fb_writeback_dequeue_buffer(struct fb_info *info,
 		struct msmfb_data *data);
-int msm_fb_writeback_unregister_buffer(struct fb_info *info,
-		struct msmfb_writeback_data *data);
+int msm_fb_writeback_stop(struct fb_info *info);
 int msm_fb_writeback_terminate(struct fb_info *info);
 #endif
 
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index cab042b..b4dcecb 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -157,8 +157,6 @@
 				     enum power_supply_property psp);
 	void (*external_power_changed)(struct power_supply *psy);
 	void (*set_charged)(struct power_supply *psy);
-	int (*set_current_limit)(struct power_supply *psy, int limit);
-	int (*set_charging_by)(struct power_supply *psy, bool enable);
 
 	/* For APM emulation, think legacy userspace. */
 	int use_for_apm;
@@ -208,7 +206,8 @@
 extern int power_supply_am_i_supplied(struct power_supply *psy);
 extern int power_supply_set_battery_charged(struct power_supply *psy);
 extern int power_supply_set_current_limit(struct power_supply *psy, int limit);
-extern int power_supply_set_charging_by(struct power_supply *psy, bool enable);
+extern int power_supply_set_online(struct power_supply *psy, bool enable);
+extern int power_supply_set_charge_type(struct power_supply *psy, int type);
 
 #if defined(CONFIG_POWER_SUPPLY) || defined(CONFIG_POWER_SUPPLY_MODULE)
 extern int power_supply_is_system_supplied(void);
diff --git a/include/linux/tzcom.h b/include/linux/tzcom.h
index a1b3dfc..448ab2a 100644
--- a/include/linux/tzcom.h
+++ b/include/linux/tzcom.h
@@ -6,6 +6,7 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 
+#define MAX_ION_FD  4
 /**
  * struct tzcom_register_svc_op_req - for register service ioctl request
  * @svc_id - service id (shared between userspace and TZ)
@@ -49,6 +50,8 @@
 /**
  * struct tzcom_send_cmd_op_req - for send command ioctl request
  * @cmd_id - command to execute on TZBSP side
+ * @ifd_data_fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
  * @cmd_len - command buffer length
  * @cmd_buf - command buffer
  * @resp_len - response buffer length
@@ -63,6 +66,34 @@
 };
 
 /**
+ * struct tzcom_ion_fd_info - ion fd handle data information
+ * @fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ */
+struct tzcom_ion_fd_info {
+	int32_t fd;
+	uint32_t cmd_buf_offset;
+};
+
+/**
+ * struct tzcom_send_cmd_op_req - for send command ioctl request
+ * @cmd_id - command to execute on TZBSP side
+ * @ifd_data_fd - ion handle to some memory allocated in user space
+ * @cmd_buf_offset - command buffer offset
+ * @cmd_len - command buffer length
+ * @cmd_buf - command buffer
+ * @resp_len - response buffer length
+ * @resp_buf - response buffer
+ */
+struct tzcom_send_cmd_fd_op_req {
+	uint32_t cmd_id; /* in */
+	struct tzcom_ion_fd_info ifd_data[MAX_ION_FD];
+	unsigned int cmd_len; /* in */
+	void *cmd_buf; /* in */
+	unsigned int resp_len; /* in/out */
+	void *resp_buf; /* in/out */
+};
+/**
  * struct tzcom_cont_cmd_op_req - for continue command ioctl request. used
  * as a trigger from HLOS service to notify TZCOM that it's done with its
  * operation and provide the response for TZCOM can continue the incomplete
@@ -99,5 +130,7 @@
 	_IOWR(TZCOM_IOC_MAGIC, 5, struct tzcom_cont_cmd_op_req)
 
 #define TZCOM_IOCTL_ABORT_REQ _IO(TZCOM_IOC_MAGIC, 6)
-
+/* For TZ service */
+#define TZCOM_IOCTL_SEND_CMD_FD_REQ \
+	_IOWR(TZCOM_IOC_MAGIC, 7, struct tzcom_send_cmd_fd_op_req)
 #endif /* __TZCOM_H_ */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 8a4c309..75fa487 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -1144,8 +1144,13 @@
 #define V4L2_CID_ILLUMINATORS_1			(V4L2_CID_BASE+37)
 #define V4L2_CID_ILLUMINATORS_2			(V4L2_CID_BASE+38)
 
+#define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE	(V4L2_CID_BASE+39)
+#define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT		(V4L2_CID_BASE+40)
+
 /* last CID + 1 */
-#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+39)
+#define V4L2_CID_LASTP1                         (V4L2_CID_BASE+41)
+
+/* Minimum number of buffer neede by the device */
 
 /*  MPEG-class control IDs defined by V4L2 */
 #define V4L2_CID_MPEG_BASE 			(V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1317,6 +1322,141 @@
 #define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
 #define V4L2_CID_MPEG_VIDEO_MUTE 		(V4L2_CID_MPEG_BASE+210)
 #define V4L2_CID_MPEG_VIDEO_MUTE_YUV 		(V4L2_CID_MPEG_BASE+211)
+#define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE		(V4L2_CID_MPEG_BASE+212)
+#define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER	(V4L2_CID_MPEG_BASE+213)
+#define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB		(V4L2_CID_MPEG_BASE+214)
+#define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE			(V4L2_CID_MPEG_BASE+215)
+#define V4L2_CID_MPEG_VIDEO_HEADER_MODE				(V4L2_CID_MPEG_BASE+216)
+enum v4l2_mpeg_video_header_mode {
+	V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE			= 0,
+	V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME	= 1,
+
+};
+#define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC			(V4L2_CID_MPEG_BASE+217)
+#define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE		(V4L2_CID_MPEG_BASE+218)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES	(V4L2_CID_MPEG_BASE+219)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB		(V4L2_CID_MPEG_BASE+220)
+#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE		(V4L2_CID_MPEG_BASE+221)
+enum v4l2_mpeg_video_multi_slice_mode {
+	V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE		= 0,
+	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB		= 1,
+	V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_VBV_SIZE			(V4L2_CID_MPEG_BASE+222)
+#define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP		(V4L2_CID_MPEG_BASE+300)
+#define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP		(V4L2_CID_MPEG_BASE+301)
+#define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP		(V4L2_CID_MPEG_BASE+302)
+#define V4L2_CID_MPEG_VIDEO_H263_MIN_QP			(V4L2_CID_MPEG_BASE+303)
+#define V4L2_CID_MPEG_VIDEO_H263_MAX_QP			(V4L2_CID_MPEG_BASE+304)
+#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP		(V4L2_CID_MPEG_BASE+350)
+#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP		(V4L2_CID_MPEG_BASE+351)
+#define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP		(V4L2_CID_MPEG_BASE+352)
+#define V4L2_CID_MPEG_VIDEO_H264_MIN_QP			(V4L2_CID_MPEG_BASE+353)
+#define V4L2_CID_MPEG_VIDEO_H264_MAX_QP			(V4L2_CID_MPEG_BASE+354)
+#define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM		(V4L2_CID_MPEG_BASE+355)
+#define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE		(V4L2_CID_MPEG_BASE+356)
+#define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE		(V4L2_CID_MPEG_BASE+357)
+enum v4l2_mpeg_video_h264_entropy_mode {
+	V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC	= 0,
+	V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC	= 1,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD		(V4L2_CID_MPEG_BASE+358)
+#define V4L2_CID_MPEG_VIDEO_H264_LEVEL			(V4L2_CID_MPEG_BASE+359)
+enum v4l2_mpeg_video_h264_level {
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_0	= 0,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1B	= 1,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_1	= 2,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_2	= 3,
+	V4L2_MPEG_VIDEO_H264_LEVEL_1_3	= 4,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_0	= 5,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_1	= 6,
+	V4L2_MPEG_VIDEO_H264_LEVEL_2_2	= 7,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_0	= 8,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_1	= 9,
+	V4L2_MPEG_VIDEO_H264_LEVEL_3_2	= 10,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_0	= 11,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_1	= 12,
+	V4L2_MPEG_VIDEO_H264_LEVEL_4_2	= 13,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_0	= 14,
+	V4L2_MPEG_VIDEO_H264_LEVEL_5_1	= 15,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA	(V4L2_CID_MPEG_BASE+360)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA	(V4L2_CID_MPEG_BASE+361)
+#define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE	(V4L2_CID_MPEG_BASE+362)
+enum v4l2_mpeg_video_h264_loop_filter_mode {
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED				= 0,
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED				= 1,
+	V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY	= 2,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_PROFILE		(V4L2_CID_MPEG_BASE+363)
+enum v4l2_mpeg_video_h264_profile {
+	V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE			= 0,
+	V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE	= 1,
+	V4L2_MPEG_VIDEO_H264_PROFILE_MAIN			= 2,
+	V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED			= 3,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH			= 4,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10			= 5,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422			= 6,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE	= 7,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA		= 8,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA		= 9,
+	V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA		= 10,
+	V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA		= 11,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE		= 12,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH		= 13,
+	V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA	= 14,
+	V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH		= 15,
+	V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH		= 16,
+};
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT	(V4L2_CID_MPEG_BASE+364)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH	(V4L2_CID_MPEG_BASE+365)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE		(V4L2_CID_MPEG_BASE+366)
+#define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC		(V4L2_CID_MPEG_BASE+367)
+enum v4l2_mpeg_video_h264_vui_sar_idc {
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED	= 0,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1		= 1,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11		= 2,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11		= 3,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11		= 4,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33		= 5,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11		= 6,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11		= 7,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11		= 8,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33		= 9,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11		= 10,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11		= 11,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33		= 12,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99		= 13,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3		= 14,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2		= 15,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1		= 16,
+	V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED	= 17,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP	(V4L2_CID_MPEG_BASE+400)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP	(V4L2_CID_MPEG_BASE+401)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP	(V4L2_CID_MPEG_BASE+402)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP	(V4L2_CID_MPEG_BASE+403)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP	(V4L2_CID_MPEG_BASE+404)
+#define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL		(V4L2_CID_MPEG_BASE+405)
+enum v4l2_mpeg_video_mpeg4_level {
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0	= 0,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B	= 1,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_1	= 2,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_2	= 3,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_3	= 4,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B	= 5,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_4	= 6,
+	V4L2_MPEG_VIDEO_MPEG4_LEVEL_5	= 7,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE	(V4L2_CID_MPEG_BASE+406)
+enum v4l2_mpeg_video_mpeg4_profile {
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE				= 0,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE			= 1,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE				= 2,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE			= 3,
+	V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY	= 4,
+};
+#define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL		(V4L2_CID_MPEG_BASE+407)
 
 /*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
 #define V4L2_CID_MPEG_CX2341X_BASE 				(V4L2_CTRL_CLASS_MPEG | 0x1000)
@@ -1359,6 +1499,33 @@
 #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP 	(V4L2_CID_MPEG_CX2341X_BASE+10)
 #define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS 	(V4L2_CID_MPEG_CX2341X_BASE+11)
 
+/*  MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */
+#define V4L2_CID_MPEG_MFC51_BASE				(V4L2_CTRL_CLASS_MPEG | 0x1100)
+
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY		(V4L2_CID_MPEG_MFC51_BASE+0)
+#define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE	(V4L2_CID_MPEG_MFC51_BASE+1)
+#define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE			(V4L2_CID_MPEG_MFC51_BASE+2)
+enum v4l2_mpeg_mfc51_video_frame_skip_mode {
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED		= 0,
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT	= 1,
+	V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT		= 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE			(V4L2_CID_MPEG_MFC51_BASE+3)
+enum v4l2_mpeg_mfc51_video_force_frame_type {
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED		= 0,
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME		= 1,
+	V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED	= 2,
+};
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING				(V4L2_CID_MPEG_MFC51_BASE+4)
+#define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV				(V4L2_CID_MPEG_MFC51_BASE+5)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT			(V4L2_CID_MPEG_MFC51_BASE+6)
+#define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF			(V4L2_CID_MPEG_MFC51_BASE+7)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY		(V4L2_CID_MPEG_MFC51_BASE+50)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK			(V4L2_CID_MPEG_MFC51_BASE+51)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH		(V4L2_CID_MPEG_MFC51_BASE+52)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC		(V4L2_CID_MPEG_MFC51_BASE+53)
+#define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P		(V4L2_CID_MPEG_MFC51_BASE+54)
+
 /*  Camera class control IDs */
 #define V4L2_CID_CAMERA_CLASS_BASE 	(V4L2_CTRL_CLASS_CAMERA | 0x900)
 #define V4L2_CID_CAMERA_CLASS 		(V4L2_CTRL_CLASS_CAMERA | 1)
diff --git a/include/media/msm/vidc_init.h b/include/media/msm/vidc_init.h
index 677a918..60cc35f 100644
--- a/include/media/msm/vidc_init.h
+++ b/include/media/msm/vidc_init.h
@@ -43,6 +43,7 @@
 	struct buf_addr_table output_buf_addr_table[MAX_VIDEO_NUM_OF_BUFF];
 	struct list_head msg_queue;
 	struct mutex msg_queue_lock;
+	struct mutex enrty_queue_lock;
 	wait_queue_head_t msg_wait;
 	struct completion event;
 	struct vcd_property_h264_mv_buffer vcd_h264_mv_buffer;
diff --git a/include/media/radio-iris.h b/include/media/radio-iris.h
index 489c248..8b753bd 100644
--- a/include/media/radio-iris.h
+++ b/include/media/radio-iris.h
@@ -1,6 +1,6 @@
 /*
  *
- * Copyright (c) 2011 Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2011-2012 Code Aurora Forum. All rights reserved.
  *
  * This file is based on include/net/bluetooth/hci_core.h
  *
@@ -354,6 +354,8 @@
 	__u8    stereo_prg;
 	__u8    rds_sync_status;
 	__u8    mute_mode;
+	char    sinr;
+	__u8	intf_det_th;
 } __packed;
 
 struct hci_ev_rds_rx_data {
@@ -548,6 +550,7 @@
 	V4L2_CID_PRIVATE_IRIS_SET_AUDIO_PATH, /* TAVARUA specific command */
 	V4L2_CID_PRIVATE_IRIS_DO_CALIBRATION,
 	V4L2_CID_PRIVATE_IRIS_SRCH_ALGORITHM, /* TAVARUA specific command */
+	V4L2_CID_PRIVATE_IRIS_GET_SINR,
 
 	/*using private CIDs under userclass*/
 	V4L2_CID_PRIVATE_IRIS_READ_DEFAULT = 0x00980928,
@@ -687,7 +690,7 @@
 #define MAX_PS_LENGTH	(96)
 #define MAX_RT_LENGTH	(64)
 #define RDS_GRP_CNTR_LEN (36)
-
+#define RX_RT_DATA_LENGTH (63)
 /* Search direction */
 #define SRCH_DIR_UP		(0)
 #define SRCH_DIR_DOWN		(1)
diff --git a/include/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 916c458..0c7cf8c 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.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
@@ -60,6 +60,7 @@
 	int subsys_id;
 	unsigned long mapped_phyaddr;
 	struct ion_handle *ion_handle;
+	struct ion_client *client;
 };
 void videobuf2_queue_pmem_contig_init(struct vb2_queue *q,
 					enum v4l2_buf_type type,
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 155c6fd..7e9f5f4 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum.  All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -65,6 +65,7 @@
 #define BT_SECURITY_HIGH	3
 
 #define BT_DEFER_SETUP	7
+#define BT_FLUSHABLE	8
 
 #define BT_POWER	9
 struct bt_power {
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 744eb72..cd85855 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum. All rights reserved.
+   Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -700,6 +700,12 @@
 	__le16   voice_setting;
 } __packed;
 
+#define HCI_OP_WRITE_AUTOMATIC_FLUSH_TIMEOUT	0x0c28
+struct hci_cp_write_automatic_flush_timeout {
+	__le16   handle;
+	__le16   timeout;
+} __packed;
+
 #define HCI_OP_HOST_BUFFER_SIZE		0x0c33
 struct hci_cp_host_buffer_size {
 	__le16   acl_mtu;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 5339785..857f654 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2011, Code Aurora Forum. All rights reserved.
+   Copyright (c) 2000-2001, 2010-2012, Code Aurora Forum. All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -240,8 +240,11 @@
 	rwlock_t		adv_entries_lock;
 	struct timer_list	adv_timer;
 
-	struct timer_list	disc_timer;
-	struct timer_list	disc_le_timer;
+	struct timer_list	disco_timer;
+	struct timer_list	disco_le_timer;
+	__u8			disco_state;
+	int			disco_int_phase;
+	int			disco_int_count;
 
 	struct hci_dev_stats	stat;
 
@@ -1037,6 +1040,8 @@
 int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 status, u8 *name);
 void mgmt_inquiry_started(u16 index);
 void mgmt_inquiry_complete_evt(u16 index, u8 status);
+void mgmt_disco_timeout(unsigned long data);
+void mgmt_disco_le_timeout(unsigned long data);
 int mgmt_encrypt_change(u16 index, bdaddr_t *bdaddr, u8 status);
 
 /* LE SMP Management interface */
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index b98af28..30536a2 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum.  All rights reserved.
    Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
    Copyright (C) 2010 Google Inc.
 
@@ -32,6 +32,7 @@
 #define L2CAP_DEFAULT_MIN_MTU		48
 #define L2CAP_DEFAULT_MAX_SDU_SIZE	0xffff
 #define L2CAP_DEFAULT_FLUSH_TO		0xffff
+#define L2CAP_MAX_FLUSH_TO		0x7ff
 #define L2CAP_DEFAULT_TX_WINDOW		63
 #define L2CAP_DEFAULT_MAX_TX		3
 #define L2CAP_DEFAULT_RETRANS_TO	2000    /* 2 seconds */
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 2fcde6f..3fffcc5 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -896,6 +896,7 @@
 	struct snd_pcm_runtime *runtime;
 	struct snd_pcm_hw_params params;
 	int runtime_update;
+	bool hwparam_set;
 };
 
 /* SoC machine DAI configuration, glues a codec and cpu DAI together */
diff --git a/kernel/cpu.c b/kernel/cpu.c
index ad7eaf2..4047707 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -123,14 +123,6 @@
 	mutex_unlock(&cpu_hotplug.lock);
 }
 
-bool cpu_hotplug_inprogress(void)
-{
-	if (cpu_hotplug.active_writer)
-		return true;
-
-	return false;
-}
-
 #else /* #if CONFIG_HOTPLUG_CPU */
 static void cpu_hotplug_begin(void) {}
 static void cpu_hotplug_done(void) {}
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 200ce83..3b5340b 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -13,20 +13,51 @@
  * irq_domain_add() - Register an irq_domain
  * @domain: ptr to initialized irq_domain structure
  *
- * Registers an irq_domain structure.  The irq_domain must at a minimum be
+ * Adds a irq_domain structure.  The irq_domain must at a minimum be
+ * initialized with an ops structure pointer, and either a ->to_irq hook or
+ * a valid irq_base value.  The irq range must be mutually exclusive with
+ * domains already registered. Everything else is optional.
+ */
+int irq_domain_add(struct irq_domain *domain)
+{
+	struct irq_domain *curr;
+	uint32_t d_highirq = domain->irq_base + domain->nr_irq - 1;
+
+	if (!domain->nr_irq)
+		return -EINVAL;
+
+	mutex_lock(&irq_domain_mutex);
+	/* insert in ascending order of domain->irq_base */
+	list_for_each_entry(curr, &irq_domain_list, list) {
+		uint32_t c_highirq = curr->irq_base + curr->nr_irq - 1;
+		if (domain->irq_base < curr->irq_base &&
+		    d_highirq < curr->irq_base) {
+			break;
+		}
+		if (d_highirq <= c_highirq) {
+			mutex_unlock(&irq_domain_mutex);
+			return -EINVAL;
+		}
+	}
+	list_add_tail(&domain->list, &curr->list);
+	mutex_unlock(&irq_domain_mutex);
+
+	return 0;
+}
+
+/**
+ * irq_domain_register() - Register an entire irq_domain
+ * @domain: ptr to initialized irq_domain structure
+ *
+ * Registers the entire irq_domain.  The irq_domain must at a minimum be
  * initialized with an ops structure pointer, and either a ->to_irq hook or
  * a valid irq_base value.  Everything else is optional.
  */
-void irq_domain_add(struct irq_domain *domain)
+void irq_domain_register(struct irq_domain *domain)
 {
 	struct irq_data *d;
 	int hwirq, irq;
 
-	/*
-	 * This assumes that the irq_domain owner has already allocated
-	 * the irq_descs.  This block will be removed when support for dynamic
-	 * allocation of irq_descs is added to irq_domain.
-	 */
 	irq_domain_for_each_irq(domain, hwirq, irq) {
 		d = irq_get_irq_data(irq);
 		if (!d) {
@@ -41,24 +72,55 @@
 		d->domain = domain;
 		d->hwirq = hwirq;
 	}
-
-	mutex_lock(&irq_domain_mutex);
-	list_add(&domain->list, &irq_domain_list);
-	mutex_unlock(&irq_domain_mutex);
 }
 
 /**
- * irq_domain_del() - Unregister an irq_domain
+ * irq_domain_register_irq() - Register an irq_domain
+ * @domain: ptr to initialized irq_domain structure
+ * @hwirq: irq_domain hwirq to register
+ *
+ * Registers a specific hwirq within the irq_domain.  The irq_domain
+ * must at a minimum be initialized with an ops structure pointer, and
+ * either a ->to_irq hook or a valid irq_base value.  Everything else is
+ * optional.
+ */
+void irq_domain_register_irq(struct irq_domain *domain, int hwirq)
+{
+	struct irq_data *d;
+
+	d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+	if (!d) {
+		WARN(1, "error: assigning domain to non existant irq_desc");
+		return;
+	}
+	if (d->domain) {
+		/* things are broken; just report, don't clean up */
+		WARN(1, "error: irq_desc already assigned to a domain");
+		return;
+	}
+	d->domain = domain;
+	d->hwirq = hwirq;
+}
+
+/**
+ * irq_domain_del() - Removes a irq_domain from the system
  * @domain: ptr to registered irq_domain.
  */
 void irq_domain_del(struct irq_domain *domain)
 {
-	struct irq_data *d;
-	int hwirq, irq;
-
 	mutex_lock(&irq_domain_mutex);
 	list_del(&domain->list);
 	mutex_unlock(&irq_domain_mutex);
+}
+
+/**
+ * irq_domain_unregister() - Unregister an irq_domain
+ * @domain: ptr to registered irq_domain.
+ */
+void irq_domain_unregister(struct irq_domain *domain)
+{
+	struct irq_data *d;
+	int hwirq, irq;
 
 	/* Clear the irq_domain assignments */
 	irq_domain_for_each_irq(domain, hwirq, irq) {
@@ -67,6 +129,60 @@
 	}
 }
 
+/**
+ * irq_domain_unregister_irq() - Unregister a hwirq within a irq_domain
+ * @domain: ptr to registered irq_domain.
+ * @hwirq: irq_domain hwirq to unregister.
+ */
+void irq_domain_unregister_irq(struct irq_domain *domain, int hwirq)
+{
+	struct irq_data *d;
+
+	/* Clear the irq_domain assignment */
+	d = irq_get_irq_data(irq_domain_to_irq(domain, hwirq));
+	d->domain = NULL;
+}
+
+/**
+ * irq_domain_find_free_range() - Find an available irq range
+ * @from: lowest logical irq number to request from
+ * @cnt: number of interrupts to search for
+ *
+ * Finds an available logical irq range from the domains specified
+ * on the system. The from parameter can be used to allocate a range
+ * at least as great as the specified irq number.
+ */
+int irq_domain_find_free_range(unsigned int from, unsigned int cnt)
+{
+	struct irq_domain *curr, *prev = NULL;
+
+	if (list_empty(&irq_domain_list))
+		return from;
+
+	list_for_each_entry(curr, &irq_domain_list, list) {
+		if (prev == NULL) {
+			if ((from + cnt - 1) < curr->irq_base)
+				return from;
+		} else {
+			uint32_t p_next_irq = prev->irq_base + prev->nr_irq;
+			uint32_t start_irq;
+			if (from >= curr->irq_base)
+				continue;
+			if (from < p_next_irq)
+				start_irq = p_next_irq;
+			else
+				start_irq = from;
+			if ((curr->irq_base - start_irq) >= cnt)
+				return p_next_irq;
+		}
+		prev = curr;
+	}
+	curr = list_entry(curr->list.prev, struct irq_domain, list);
+
+	return from > curr->irq_base + curr->nr_irq ?
+	       from : curr->irq_base + curr->nr_irq;
+}
+
 #if defined(CONFIG_OF_IRQ)
 /**
  * irq_create_of_mapping() - Map a linux irq number from a DT interrupt spec
@@ -91,6 +207,7 @@
 	list_for_each_entry(domain, &irq_domain_list, list) {
 		if (!domain->ops->dt_translate)
 			continue;
+
 		rc = domain->ops->dt_translate(domain, controller,
 					intspec, intsize, &hwirq, &type);
 		if (rc == 0)
@@ -154,6 +271,7 @@
 void irq_domain_add_simple(struct device_node *controller, int irq_base)
 {
 	struct irq_domain *domain;
+	int rc;
 
 	domain = kzalloc(sizeof(*domain), GFP_KERNEL);
 	if (!domain) {
@@ -164,7 +282,12 @@
 	domain->irq_base = irq_base;
 	domain->of_node = of_node_get(controller);
 	domain->ops = &irq_domain_simple_ops;
-	irq_domain_add(domain);
+	rc = irq_domain_add(domain);
+	if (rc) {
+		WARN(1, "Unable to create irq domain\n");
+		return;
+	}
+	irq_domain_register(domain);
 }
 EXPORT_SYMBOL_GPL(irq_domain_add_simple);
 
diff --git a/kernel/printk.c b/kernel/printk.c
index b790764..dbaa948 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -813,11 +813,6 @@
  */
 static inline int can_use_console(unsigned int cpu)
 {
-#ifdef CONFIG_HOTPLUG_CPU
-	if (!cpu_active(cpu) && cpu_hotplug_inprogress())
-		return 0;
-#endif
-
 	return cpu_online(cpu) || have_callable_console();
 }
 
diff --git a/kernel/sched.c b/kernel/sched.c
index 232c1c0..b85f675 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -7653,7 +7653,6 @@
 {
 	int i, j, n;
 	int new_topology;
-	cpumask_var_t doms_temp;
 
 	mutex_lock(&sched_domains_mutex);
 
@@ -7663,20 +7662,14 @@
 	/* Let architecture update cpu core mappings. */
 	new_topology = arch_update_cpu_topology();
 
-	cpumask_andnot(doms_temp, cpu_active_mask, cpu_isolated_map);
-
 	n = doms_new ? ndoms_new : 0;
 
 	/* Destroy deleted domains */
 	for (i = 0; i < ndoms_cur; i++) {
-		if (!new_topology) {
-			if ((n == 0) && cpumask_subset(doms_cur[i], doms_temp))
+		for (j = 0; j < n && !new_topology; j++) {
+			if (cpumask_equal(doms_cur[i], doms_new[j])
+			    && dattrs_equal(dattr_cur, i, dattr_new, j))
 				goto match1;
-			for (j = 0; j < n; j++) {
-				if (cpumask_equal(doms_cur[i], doms_new[j])
-				    && dattrs_equal(dattr_cur, i, dattr_new, j))
-					goto match1;
-			}
 		}
 		/* no match - a current sched domain not in new doms_new[] */
 		detach_destroy_domains(doms_cur[i]);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index e54ba63..e8f9cce 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -807,8 +807,7 @@
 		update_process_times(user_mode(regs));
 		profile_tick(CPU_PROFILING);
 
-
-		if ((rq_info.init == 1) && (cpu == 0)) {
+		if ((rq_info.init == 1) && (tick_do_timer_cpu == cpu)) {
 
 			/*
 			 * update run queue statistics
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 1f06468..6fd4ffd 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -59,18 +59,19 @@
 			continue;
 		}
 
+		fmt = NULL;
 		tb_fmt = kmalloc(sizeof(*tb_fmt), GFP_KERNEL);
-		if (tb_fmt)
+		if (tb_fmt) {
 			fmt = kmalloc(strlen(*iter) + 1, GFP_KERNEL);
-		if (tb_fmt && fmt) {
-			list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
-			strcpy(fmt, *iter);
-			tb_fmt->fmt = fmt;
-			*iter = tb_fmt->fmt;
-		} else {
-			kfree(tb_fmt);
-			*iter = NULL;
+			if (fmt) {
+				list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
+				strcpy(fmt, *iter);
+				tb_fmt->fmt = fmt;
+			} else
+				kfree(tb_fmt);
 		}
+		*iter = fmt;
+
 	}
 	mutex_unlock(&btrace_mutex);
 }
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 53a9cac..ccf3623 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum.  All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -430,9 +430,10 @@
 
 	BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
 
+	/* Make sure no timers are running */
 	del_timer(&conn->idle_timer);
-
 	del_timer(&conn->disc_timer);
+	del_timer(&conn->smp_timer);
 
 	if (conn->type == ACL_LINK) {
 		struct hci_conn *sco = conn->link;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index dd1d6e8..47bfde5 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum.  All rights reserved.
 
    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
 
@@ -1464,6 +1464,10 @@
 	skb_queue_head_init(&hdev->raw_q);
 
 	setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev);
+	setup_timer(&hdev->disco_timer, mgmt_disco_timeout,
+						(unsigned long) hdev);
+	setup_timer(&hdev->disco_le_timer, mgmt_disco_le_timeout,
+						(unsigned long) hdev);
 
 	for (i = 0; i < NUM_REASSEMBLY; i++)
 		hdev->reassembly[i] = NULL;
@@ -1571,8 +1575,12 @@
 
 	hci_unregister_sysfs(hdev);
 
+	/* Disable all timers */
 	hci_del_off_timer(hdev);
 	del_timer(&hdev->adv_timer);
+	del_timer(&hdev->cmd_timer);
+	del_timer(&hdev->disco_timer);
+	del_timer(&hdev->disco_le_timer);
 
 	destroy_workqueue(hdev->workqueue);
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index f311e10..cf6cf59 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1,6 +1,6 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
-   Copyright (c) 2000-2001, 2010-2011 Code Aurora Forum.  All rights reserved.
+   Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum.  All rights reserved.
    Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
    Copyright (C) 2010 Google Inc.
 
@@ -90,6 +90,8 @@
 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 u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l);
+static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to);
 
 /* ---- L2CAP channels ---- */
 static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
@@ -519,6 +521,11 @@
 		l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING;
 		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
 	}
+
+	if (l2cap_get_smallest_flushto(l) > l2cap_pi(sk)->flush_to) {
+		/*if flush timeout of the channel is lesser than existing */
+		l2cap_set_acl_flushto(conn->hcon, l2cap_pi(sk)->flush_to);
+	}
 	/* Otherwise, do not set scid/dcid/omtu.  These will be set up
 	 * by l2cap_fixed_channel_config()
 	 */
@@ -538,11 +545,18 @@
 	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
 
 	if (conn) {
+		struct l2cap_chan_list *l = &conn->chan_list;
 		/* Unlink from channel list */
-		l2cap_chan_unlink(&conn->chan_list, sk);
+		l2cap_chan_unlink(l, sk);
 		l2cap_pi(sk)->conn = NULL;
 		if (!l2cap_pi(sk)->fixed_channel)
 			hci_conn_put(conn->hcon);
+
+		read_lock(&l->lock);
+		if (l2cap_pi(sk)->flush_to < l2cap_get_smallest_flushto(l))
+			l2cap_set_acl_flushto(conn->hcon,
+				l2cap_get_smallest_flushto(l));
+		read_unlock(&l->lock);
 	}
 
 	if (l2cap_pi(sk)->ampcon) {
@@ -7590,6 +7604,33 @@
 	return 0;
 }
 
+static void l2cap_set_acl_flushto(struct hci_conn *hcon, u16 flush_to)
+{
+	struct hci_cp_write_automatic_flush_timeout flush_tm;
+	if (hcon && hcon->hdev) {
+		flush_tm.handle = hcon->handle;
+		if (flush_to == L2CAP_DEFAULT_FLUSH_TO)
+			flush_to = 0;
+		flush_tm.timeout = (flush_to < L2CAP_MAX_FLUSH_TO) ?
+				flush_to : L2CAP_MAX_FLUSH_TO;
+		hci_send_cmd(hcon->hdev,
+			HCI_OP_WRITE_AUTOMATIC_FLUSH_TIMEOUT,
+			4, &(flush_tm));
+	}
+}
+
+static u16 l2cap_get_smallest_flushto(struct l2cap_chan_list *l)
+{
+	int ret_flush_to = L2CAP_DEFAULT_FLUSH_TO;
+	struct sock *s;
+	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+		if (l2cap_pi(s)->flush_to > 0 &&
+				l2cap_pi(s)->flush_to < ret_flush_to)
+			ret_flush_to = l2cap_pi(s)->flush_to;
+	}
+	return ret_flush_to;
+}
+
 static int l2cap_debugfs_show(struct seq_file *f, void *p)
 {
 	struct sock *sk;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 9beea74..93e7b04 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -626,6 +626,7 @@
 		l2cap_pi(sk)->fcs  = opts.fcs;
 		l2cap_pi(sk)->max_tx = opts.max_tx;
 		l2cap_pi(sk)->tx_win = opts.txwin_size;
+		l2cap_pi(sk)->flush_to = opts.flush_to;
 		break;
 
 	case L2CAP_LM:
@@ -766,6 +767,15 @@
 
 		break;
 
+	case BT_FLUSHABLE:
+		if (get_user(opt, (u32 __user *) optval)) {
+			err = -EFAULT;
+			break;
+		}
+		l2cap_pi(sk)->flushable = opt;
+
+		break;
+
 	default:
 		err = -ENOPROTOOPT;
 		break;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 7f2cff8..67a2900 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1,6 +1,7 @@
 /*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2010  Nokia Corporation
+   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 as
@@ -34,18 +35,9 @@
 #define MGMT_VERSION	0
 #define MGMT_REVISION	1
 
-enum scan_mode {
-	SCAN_IDLE,
-	SCAN_LE,
-	SCAN_BR
-};
-
-struct disco_interleave {
-	u16			index;
-	enum scan_mode		mode;
-	int			int_phase;
-	int			int_count;
-};
+#define SCAN_IDLE	0x00
+#define SCAN_LE		0x01
+#define SCAN_BR		0x02
 
 struct pending_cmd {
 	struct list_head list;
@@ -1571,8 +1563,8 @@
 	if (!hdev)
 		goto not_found;
 
-	del_timer_sync(&hdev->disc_le_timer);
-	del_timer_sync(&hdev->disc_timer);
+	del_timer(&hdev->disco_le_timer);
+	del_timer(&hdev->disco_timer);
 	hci_dev_put(hdev);
 
 not_found:
@@ -1858,8 +1850,8 @@
 		if (cmd->opcode == MGMT_OP_STOP_DISCOVERY) {
 			struct hci_dev *hdev = hci_dev_get(cmd->index);
 			if (hdev) {
-				del_timer_sync(&hdev->disc_le_timer);
-				del_timer_sync(&hdev->disc_timer);
+				del_timer(&hdev->disco_le_timer);
+				del_timer(&hdev->disco_timer);
 				hci_dev_put(hdev);
 			}
 		}
@@ -1883,7 +1875,7 @@
 {
 	struct hci_dev *hdev;
 	struct hci_cp_le_set_scan_enable le_cp = {1, 0};
-	struct pending_cmd *cmd;
+	struct mgmt_mode cp = {0};
 	int err = -1;
 
 	BT_DBG("");
@@ -1891,7 +1883,6 @@
 	hdev = hci_dev_get(index);
 
 	if (!hdev || !lmp_le_capable(hdev)) {
-		struct mgmt_mode cp = {0};
 
 		mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
 						discovery_terminated, NULL);
@@ -1904,20 +1895,20 @@
 			return;
 	}
 
-	cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
-	if (cmd && cmd->param) {
-		struct disco_interleave *ilp = cmd->param;
-
+	if (hdev->disco_state != SCAN_IDLE) {
 		err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
 						sizeof(le_cp), &le_cp);
-		if (err >= 0 && hdev) {
-			mod_timer(&hdev->disc_le_timer, jiffies +
-				msecs_to_jiffies(ilp->int_phase * 1000));
-			ilp->mode = SCAN_LE;
+		if (err >= 0) {
+			mod_timer(&hdev->disco_le_timer, jiffies +
+				msecs_to_jiffies(hdev->disco_int_phase * 1000));
+			hdev->disco_state = SCAN_LE;
 		} else
-			ilp->mode = SCAN_IDLE;
+			hdev->disco_state = SCAN_IDLE;
 	}
 
+	if (hdev->disco_state == SCAN_IDLE)
+		mgmt_event(MGMT_EV_DISCOVERING, index, &cp, sizeof(cp), NULL);
+
 	if (err < 0)
 		mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
 						discovery_terminated, NULL);
@@ -1926,82 +1917,74 @@
 	hci_dev_put(hdev);
 }
 
-static void disco_to(unsigned long data)
+void mgmt_disco_timeout(unsigned long data)
 {
-	struct disco_interleave *ilp = (void *)data;
-	struct hci_dev *hdev;
+	struct hci_dev *hdev = (void *) data;
 	struct pending_cmd *cmd;
+	struct mgmt_mode cp = {0};
 
-	BT_DBG("hci%d", ilp->index);
+	BT_DBG("hci%d", hdev->id);
 
-	hdev = hci_dev_get(ilp->index);
+	hdev = hci_dev_get(hdev->id);
 
-	if (hdev) {
-		hci_dev_lock_bh(hdev);
-		del_timer_sync(&hdev->disc_le_timer);
+	if (!hdev)
+		return;
 
-		cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
+	hci_dev_lock_bh(hdev);
+	del_timer(&hdev->disco_le_timer);
 
-		if (ilp->mode != SCAN_IDLE) {
-			struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+	if (hdev->disco_state != SCAN_IDLE) {
+		struct hci_cp_le_set_scan_enable le_cp = {0, 0};
 
-			if (ilp->mode == SCAN_LE)
-				hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
-							sizeof(le_cp), &le_cp);
-			else
-				hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
-								0, NULL);
-
-			ilp->mode = SCAN_IDLE;
-		}
-
-		if (cmd) {
-			struct mgmt_mode cp = {0};
-
-			mgmt_event(MGMT_EV_DISCOVERING, ilp->index, &cp,
-							sizeof(cp), NULL);
-			mgmt_pending_remove(cmd);
-		}
-
-		hci_dev_unlock_bh(hdev);
-		hci_dev_put(hdev);
-	}
-}
-
-static void disco_le_to(unsigned long data)
-{
-	struct disco_interleave *ilp = (void *)data;
-	struct hci_dev *hdev;
-	struct pending_cmd *cmd;
-	struct hci_cp_le_set_scan_enable le_cp = {0, 0};
-
-	BT_DBG("hci%d", ilp->index);
-
-	hdev = hci_dev_get(ilp->index);
-
-	if (hdev) {
-		hci_dev_lock_bh(hdev);
-
-		cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, ilp->index);
-
-		if (ilp->mode == SCAN_LE)
+		if (hdev->disco_state == SCAN_LE)
 			hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
 							sizeof(le_cp), &le_cp);
+		else
+			hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
 
-		/* re-start BR scan */
-		if (cmd) {
-			struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
-			ilp->int_phase *= 2;
-			ilp->int_count = 0;
-			cp.num_rsp = (u8) ilp->int_phase;
-			hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
-			ilp->mode = SCAN_BR;
-		} else
-			ilp->mode = SCAN_IDLE;
-
-		hci_dev_unlock_bh(hdev);
-		hci_dev_put(hdev);
+		hdev->disco_state = SCAN_IDLE;
 	}
+
+	mgmt_event(MGMT_EV_DISCOVERING, hdev->id, &cp, sizeof(cp), NULL);
+
+	cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev->id);
+	if (cmd)
+		mgmt_pending_remove(cmd);
+
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
+}
+
+void mgmt_disco_le_timeout(unsigned long data)
+{
+	struct hci_dev *hdev = (void *)data;
+	struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+
+	BT_DBG("hci%d", hdev->id);
+
+	hdev = hci_dev_get(hdev->id);
+
+	if (!hdev)
+		return;
+
+	hci_dev_lock_bh(hdev);
+
+	if (hdev->disco_state == SCAN_LE)
+		hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
+				sizeof(le_cp), &le_cp);
+
+	/* re-start BR scan */
+	if (hdev->disco_state != SCAN_IDLE) {
+		struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
+		hdev->disco_int_phase *= 2;
+		hdev->disco_int_count = 0;
+		cp.num_rsp = (u8) hdev->disco_int_phase;
+		hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+		hdev->disco_state = SCAN_BR;
+	}
+
+	hci_dev_unlock_bh(hdev);
+	hci_dev_put(hdev);
 }
 
 static int start_discovery(struct sock *sk, u16 index)
@@ -2019,6 +2002,11 @@
 
 	hci_dev_lock_bh(hdev);
 
+	if (hdev->disco_state && timer_pending(&hdev->disco_timer)) {
+		err = -EBUSY;
+		goto failed;
+	}
+
 	cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
 	if (!cmd) {
 		err = -ENOMEM;
@@ -2052,30 +2040,23 @@
 	if (err < 0)
 		mgmt_pending_remove(cmd);
 	else if (lmp_le_capable(hdev)) {
-		struct disco_interleave il, *ilp;
-
-		il.int_phase = 1;
-		il.int_count = 0;
-		il.index = index;
-		il.mode = SCAN_BR;
-		mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, &il,
-					sizeof(struct disco_interleave));
-		cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
-		if (cmd) {
-			ilp = cmd->param;
-			setup_timer(&hdev->disc_le_timer, disco_le_to,
-							(unsigned long) ilp);
-			setup_timer(&hdev->disc_timer, disco_to,
-							(unsigned long) ilp);
-			mod_timer(&hdev->disc_timer,
-					jiffies + msecs_to_jiffies(20000));
-		}
+		hdev->disco_int_phase = 1;
+		hdev->disco_int_count = 0;
+		hdev->disco_state = SCAN_BR;
+		mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
+		del_timer(&hdev->disco_le_timer);
+		del_timer(&hdev->disco_timer);
+		mod_timer(&hdev->disco_timer,
+				jiffies + msecs_to_jiffies(20000));
 	}
 
 failed:
 	hci_dev_unlock_bh(hdev);
 	hci_dev_put(hdev);
 
+	if (err < 0)
+		return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, -err);
+
 	return err;
 }
 
@@ -2083,10 +2064,10 @@
 {
 	struct hci_cp_le_set_scan_enable le_cp = {0, 0};
 	struct mgmt_mode mode_cp = {0};
-	struct disco_interleave *ilp = NULL;
 	struct hci_dev *hdev;
 	struct pending_cmd *cmd = NULL;
 	int err = -EPERM;
+	u8 state;
 
 	BT_DBG("");
 
@@ -2096,38 +2077,32 @@
 
 	hci_dev_lock_bh(hdev);
 
-	if (lmp_le_capable(hdev)) {
-		cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
-		if (!cmd) {
-			err = -ENOMEM;
-			goto failed;
-		}
+	state = hdev->disco_state;
+	hdev->disco_state = SCAN_IDLE;
+	del_timer(&hdev->disco_le_timer);
+	del_timer(&hdev->disco_timer);
 
-		ilp = cmd->param;
-	}
-
-	if (lmp_le_capable(hdev) && ilp && (ilp->mode == SCAN_LE))
+	if (state == SCAN_LE) {
 		err = hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
 							sizeof(le_cp), &le_cp);
+		if (err >= 0) {
+			mgmt_pending_foreach(MGMT_OP_STOP_DISCOVERY, index,
+						discovery_terminated, NULL);
 
-	if (err < 0) {
-		if (!ilp || (ilp->mode == SCAN_BR))
-			err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL,
-								0, NULL);
+			err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
+								NULL, 0);
+		}
 	}
 
-	if (ilp) {
-		ilp->mode = SCAN_IDLE;
-		del_timer_sync(&hdev->disc_le_timer);
-		del_timer_sync(&hdev->disc_timer);
-	}
+	if (err < 0)
+		err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
 
+	cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
 	if (err < 0 && cmd)
 		mgmt_pending_remove(cmd);
 
 	mgmt_event(MGMT_EV_DISCOVERING, index, &mode_cp, sizeof(mode_cp), NULL);
 
-failed:
 	hci_dev_unlock_bh(hdev);
 	hci_dev_put(hdev);
 
@@ -2822,7 +2797,7 @@
 			u8 *dev_class, s8 rssi, u8 eir_len, u8 *eir)
 {
 	struct mgmt_ev_device_found ev;
-	struct pending_cmd *cmd;
+	struct hci_dev *hdev;
 	int err;
 
 	BT_DBG("le: %d", le);
@@ -2845,36 +2820,38 @@
 	if (err < 0)
 		return err;
 
-	cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, index);
-	if (cmd) {
-		struct disco_interleave *ilp = cmd->param;
-		struct hci_dev *hdev = hci_dev_get(index);
+	hdev = hci_dev_get(index);
 
-		ilp->int_count++;
-		if (hdev && ilp->int_count >= ilp->int_phase) {
-			/* Inquiry scan for General Discovery LAP */
-			struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
-			struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+	if (!hdev)
+		return 0;
 
-			ilp->int_phase *= 2;
-			ilp->int_count = 0;
-			if (ilp->mode == SCAN_LE) {
-				/* cancel LE scan */
-				hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
-							sizeof(le_cp), &le_cp);
-				/* start BR scan */
-				cp.num_rsp = (u8) ilp->int_phase;
-				hci_send_cmd(hdev, HCI_OP_INQUIRY,
-							sizeof(cp), &cp);
-				ilp->mode = SCAN_BR;
-				del_timer_sync(&hdev->disc_le_timer);
-			}
+	if (hdev->disco_state == SCAN_IDLE)
+		goto done;
+
+	hdev->disco_int_count++;
+
+	if (hdev->disco_int_count >= hdev->disco_int_phase) {
+		/* Inquiry scan for General Discovery LAP */
+		struct hci_cp_inquiry cp = {{0x33, 0x8b, 0x9e}, 4, 0};
+		struct hci_cp_le_set_scan_enable le_cp = {0, 0};
+
+		hdev->disco_int_phase *= 2;
+		hdev->disco_int_count = 0;
+		if (hdev->disco_state == SCAN_LE) {
+			/* cancel LE scan */
+			hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE,
+					sizeof(le_cp), &le_cp);
+			/* start BR scan */
+			cp.num_rsp = (u8) hdev->disco_int_phase;
+			hci_send_cmd(hdev, HCI_OP_INQUIRY,
+					sizeof(cp), &cp);
+			hdev->disco_state = SCAN_BR;
+			del_timer_sync(&hdev->disco_le_timer);
 		}
-
-		if (hdev)
-			hci_dev_put(hdev);
 	}
 
+done:
+	hci_dev_put(hdev);
 	return 0;
 }
 
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 1f4b2f8..0d41625 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2791,6 +2791,12 @@
 		WARN("Non gpiomux board file cannot have a gpiomux config declarations. Please declare gpiomux configs in board-*-gpiomux.c file.\n" . $herecurr);
 	}
 
+# MSM - check if vreg_xxx function are used
+	if ($line =~ /\b(vreg_(get|put|set_level|enable|disable))\b/) {
+		WARN("Use of $1 API is deprecated: " .
+			"use regulator APIs\n" . $herecurr);
+	}
+
 # unbounded string functions are overflow risks
 		my %str_fns = (
 			"sprintf" => "snprintf",
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 33afdc9..472fcae 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -48,6 +48,11 @@
 
 #define TABLA_OCP_ATTEMPT 1
 
+#define TABLA_MCLK_RATE_12288KHZ 12288000
+#define TABLA_MCLK_RATE_9600KHZ 9600000
+
+#define TABLA_FAKE_INS_THRESHOLD_MS 2500
+
 static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
 static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
 static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
@@ -93,8 +98,31 @@
 	TABLA_HPHR_DAC_OFF_ACK
 };
 
+/* Data used by MBHC */
+struct mbhc_internal_cal_data {
+	u16 dce_z;
+	u16 dce_mb;
+	u16 sta_z;
+	u16 sta_mb;
+	u32 t_dce;
+	u32 t_sta;
+	u32 micb_mv;
+	u16 v_ins_hu;
+	u16 v_ins_h;
+	u16 v_b1_hu;
+	u16 v_b1_h;
+	u16 v_b1_huc;
+	u16 v_brh;
+	u16 v_brl;
+	u16 v_no_mic;
+	u8 nready;
+	u8 npoll;
+	u8 nbounce_wait;
+};
+
 struct tabla_priv {
 	struct snd_soc_codec *codec;
+	u32 mclk_freq;
 	u32 adc_count;
 	u32 cfilt1_cnt;
 	u32 cfilt2_cnt;
@@ -105,10 +133,20 @@
 	bool clock_active;
 	bool config_mode_active;
 	bool mbhc_polling_active;
-	bool fake_insert_context;
+	unsigned long mbhc_fake_ins_start;
 	int buttons_pressed;
 
-	struct tabla_mbhc_calibration *calibration;
+	enum tabla_micbias_num micbias;
+	/* void* calibration contains:
+	 *  struct tabla_mbhc_general_cfg generic;
+	 *  struct tabla_mbhc_plug_detect_cfg plug_det;
+	 *  struct tabla_mbhc_plug_type_cfg plug_type;
+	 *  struct tabla_mbhc_btn_detect_cfg btn_det;
+	 *  struct tabla_mbhc_imped_detect_cfg imped_det;
+	 * Note: various size depends on btn_det->num_btn
+	 */
+	void *calibration;
+	struct mbhc_internal_cal_data mbhc_data;
 
 	struct snd_soc_jack *headset_jack;
 	struct snd_soc_jack *button_jack;
@@ -145,6 +183,9 @@
 
 	u8 hphlocp_cnt; /* headphone left ocp retry */
 	u8 hphrocp_cnt; /* headphone right ocp retry */
+
+	/* Callback function to enable MCLK */
+	int (*mclk_cb) (struct snd_soc_codec*, int);
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -778,6 +819,14 @@
 	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
 			sb_tx7_to_tx10_mux_text);
 
+static const struct soc_enum sb_tx9_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
+			sb_tx7_to_tx10_mux_text);
+
+static const struct soc_enum sb_tx10_mux_enum =
+	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
+			sb_tx7_to_tx10_mux_text);
+
 static const struct soc_enum sb_tx1_mux_enum =
 	SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
 
@@ -883,6 +932,12 @@
 static const struct snd_kcontrol_new sb_tx8_mux =
 	SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
 
+static const struct snd_kcontrol_new sb_tx9_mux =
+	SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
+
+static const struct snd_kcontrol_new sb_tx10_mux =
+	SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
+
 static const struct snd_kcontrol_new sb_tx1_mux =
 	SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
 
@@ -1409,7 +1464,7 @@
 		if (tabla->mbhc_polling_active) {
 
 			tabla_codec_pause_hs_polling(codec);
-			/* Enable Mic Bias switch to VDDIO */
+			/* VDDIO switch enabled */
 			tabla->cfilt_k_value = snd_soc_read(codec,
 					tabla->mbhc_bias_regs.cfilt_val);
 			cfilt_k_val = tabla_find_k_value(
@@ -1425,8 +1480,7 @@
 			tabla_codec_start_hs_polling(codec);
 
 			tabla->mbhc_micbias_switched = true;
-			pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
-				__func__);
+			pr_debug("%s: VDDIO switch enabled\n", __func__);
 		}
 		break;
 
@@ -1436,7 +1490,7 @@
 				tabla_codec_pause_hs_polling(codec);
 				mbhc_was_polling = true;
 			}
-			/* Disable Mic Bias switch to VDDIO */
+			/* VDDIO switch disabled */
 			if (tabla->cfilt_k_value != 0)
 				snd_soc_update_bits(codec,
 					tabla->mbhc_bias_regs.cfilt_val, 0XFC,
@@ -1450,8 +1504,7 @@
 				tabla_codec_start_hs_polling(codec);
 
 			tabla->mbhc_micbias_switched = false;
-			pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
-				__func__);
+			pr_debug("%s: VDDIO switch disabled\n", __func__);
 		}
 		break;
 	}
@@ -1516,7 +1569,7 @@
 		break;
 	case SND_SOC_DAPM_POST_PMU:
 		if (tabla->mbhc_polling_active &&
-			(tabla->calibration->bias == micb_line)) {
+		    tabla->micbias == micb_line) {
 			tabla_codec_pause_hs_polling(codec);
 			tabla_codec_start_hs_polling(codec);
 		}
@@ -1673,10 +1726,8 @@
 			tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
 						  tabla->hph_status,
 						  TABLA_JACK_MASK);
-		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
-		0x00);
-		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
-		0x10);
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
+		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
 		/* reset retry counter as PA is turned off signifying
 		 * start of new OCP detection session
 		 */
@@ -1761,10 +1812,9 @@
 		struct mbhc_micbias_regs *micbias_regs)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	struct tabla_mbhc_calibration *calibration = tabla->calibration;
 	unsigned int cfilt;
 
-	switch (calibration->bias) {
+	switch (tabla->micbias) {
 	case TABLA_MICBIAS1:
 		cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
 		micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
@@ -1801,14 +1851,17 @@
 	case TABLA_CFILT1_SEL:
 		micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
 		micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
+		tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
 		break;
 	case TABLA_CFILT2_SEL:
 		micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
 		micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
+		tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
 		break;
 	case TABLA_CFILT3_SEL:
 		micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
 		micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
+		tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
 		break;
 	}
 }
@@ -2104,6 +2157,14 @@
 	SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
 			0, 0),
 
+	SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
+	SND_SOC_DAPM_AIF_OUT("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
+			0, 0),
+
+	SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
+	SND_SOC_DAPM_AIF_OUT("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
+			0, 0),
+
 	/* Digital Mic Inputs */
 	SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
 		tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
@@ -2179,6 +2240,31 @@
 	{"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
 	{"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
 
+	{"SLIM TX9", NULL, "SLIM TX9 MUX"},
+	{"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
+	{"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
+	{"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
+	{"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
+	{"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
+	{"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
+	{"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
+	{"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
+
+	{"SLIM TX10", NULL, "SLIM TX10 MUX"},
+	{"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
+	{"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
+	{"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
+	{"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
+	{"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
+	{"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
+	{"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
+	{"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
+	{"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
+	{"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
+
+
 	/* Earpiece (RX MIX1) */
 	{"EAR", NULL, "EAR PA"},
 	{"EAR PA", NULL, "DAC1"},
@@ -2612,24 +2698,46 @@
 
 static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
 {
-	/* TODO store register values in calibration */
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
+	u8 *n_cic;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
 
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
+		      tabla->mbhc_data.v_ins_hu & 0xFF);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
+		      (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
 
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
-	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
-	snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
+		      tabla->mbhc_data.v_b1_hu & 0xFF);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
+		      (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
+
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
+		      tabla->mbhc_data.v_b1_h & 0xFF);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
+		      (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
+
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
+		      tabla->mbhc_data.v_brh & 0xFF);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
+		      (tabla->mbhc_data.v_brh >> 8) & 0xFF);
+
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
+		      tabla->mbhc_data.v_brl & 0xFF);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
+		      (tabla->mbhc_data.v_brl >> 8) & 0xFF);
+
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
+		      tabla->mbhc_data.nready);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
+		      tabla->mbhc_data.npoll);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
+		      tabla->mbhc_data.nbounce_wait);
+
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, n_cic[0]);
 }
 
 static int tabla_startup(struct snd_pcm_substream *substream,
@@ -2884,7 +2992,7 @@
 			.rate_max = 48000,
 			.rate_min = 8000,
 			.channels_min = 1,
-			.channels_max = 2,
+			.channels_max = 4,
 		},
 		.ops = &tabla_dai_ops,
 	},
@@ -2956,42 +3064,47 @@
 	return bias_value;
 }
 
-static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
-	int dce)
+static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
 {
+	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
 	short bias_value;
 
+	/* Turn on the override */
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
 	if (dce) {
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
 		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
-		usleep_range(60000, 60000);
+		usleep_range(tabla->mbhc_data.t_dce,
+			     tabla->mbhc_data.t_dce);
 		bias_value = tabla_codec_read_dce_result(codec);
 	} else {
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
-		usleep_range(5000, 5000);
-		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
 		usleep_range(50, 50);
+		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
+		usleep_range(tabla->mbhc_data.t_sta,
+			     tabla->mbhc_data.t_sta);
 		bias_value = tabla_codec_read_sta_result(codec);
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 		snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
 	}
+	/* Turn off the override after measuring mic voltage */
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
 
-	pr_debug("read microphone bias value %x\n", bias_value);
+	pr_debug("read microphone bias value %04x\n", bias_value);
 	return bias_value;
 }
 
 static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	struct tabla_mbhc_calibration *calibration = tabla->calibration;
 	short bias_value;
 	u8 cfilt_mode;
 
-	if (!calibration) {
+	if (!tabla->calibration) {
 		pr_err("Error, no tabla calibration\n");
 		return -ENODEV;
 	}
@@ -3009,13 +3122,10 @@
 	snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
 
 	/* Make sure CFILT is in fast mode, save current mode */
-	cfilt_mode = snd_soc_read(codec,
-		tabla->mbhc_bias_regs.cfilt_ctl);
-	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
-		0x70, 0x00);
+	cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
 
-	snd_soc_update_bits(codec,
-		tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
 
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
 	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
@@ -3028,14 +3138,14 @@
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
 
-	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
 
 	tabla_codec_calibrate_hs_polling(codec);
 
-	bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
-	snd_soc_update_bits(codec,
-		tabla->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
+	bias_value = tabla_codec_sta_dce(codec, 0);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
+			    cfilt_mode);
 	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
 
 	return bias_value;
@@ -3045,11 +3155,14 @@
 		int insertion)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	struct tabla_mbhc_calibration *calibration = tabla->calibration;
 	int central_bias_enabled = 0;
+	const struct tabla_mbhc_general_cfg *generic =
+	    TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
+	const struct tabla_mbhc_plug_detect_cfg *plug_det =
+	    TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
 	u8 wg_time;
 
-	if (!calibration) {
+	if (!tabla->calibration) {
 		pr_err("Error, no tabla calibration\n");
 		return -EINVAL;
 	}
@@ -3070,7 +3183,7 @@
 		/* Enable HPH Schmitt Trigger */
 		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
 		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
-			calibration->hph_current << 2);
+				    plug_det->hph_current << 2);
 
 		/* Turn off HPH PAs and DAC's during insertion detection to
 		 * avoid false insertion interrupts
@@ -3079,9 +3192,9 @@
 			tabla_codec_switch_micbias(codec, 0);
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
-			0xC0, 0x00);
+				    0xC0, 0x00);
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
-			0xC0, 0x00);
+				    0xC0, 0x00);
 		usleep_range(wg_time * 1000, wg_time * 1000);
 
 		/* setup for insetion detection */
@@ -3093,10 +3206,10 @@
 
 		/* enable the mic line schmitt trigger */
 		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
-			calibration->mic_current << 5);
+				    plug_det->mic_current << 5);
 		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
 			0x80, 0x80);
-		usleep_range(calibration->mic_pid, calibration->mic_pid);
+		usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
 		snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
 			0x10, 0x10);
 
@@ -3109,8 +3222,8 @@
 			tabla_codec_enable_config_mode(codec, 1);
 			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
 				0x06, 0);
-			usleep_range(calibration->shutdown_plug_removal,
-				calibration->shutdown_plug_removal);
+			usleep_range(generic->t_shutdown_plug_rem,
+				     generic->t_shutdown_plug_rem);
 			tabla_codec_enable_config_mode(codec, 0);
 		} else
 			snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
@@ -3122,8 +3235,8 @@
 	/* If central bandgap disabled */
 	if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
 		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
-		usleep_range(calibration->bg_fast_settle,
-			calibration->bg_fast_settle);
+		usleep_range(generic->t_bg_fast_settle,
+			     generic->t_bg_fast_settle);
 		central_bias_enabled = 1;
 	}
 
@@ -3131,14 +3244,14 @@
 	if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
 		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
 		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
-		usleep_range(calibration->tldoh, calibration->tldoh);
+		usleep_range(generic->t_ldoh, generic->t_ldoh);
 		snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
 
 		if (central_bias_enabled)
 			snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
 	}
 
-	snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
+	snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, tabla->micbias);
 
 	tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
@@ -3163,10 +3276,60 @@
 	wake_up(&tabla->pm_wq);
 }
 
+static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
+				 s16 vin_mv)
+{
+	short diff, zero;
+	struct tabla_priv *tabla;
+	u32 mb_mv, in;
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+	mb_mv = tabla->mbhc_data.micb_mv;
+
+	if (mb_mv == 0) {
+		pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
+		return -EINVAL;
+	}
+
+	if (dce) {
+		diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
+		zero = tabla->mbhc_data.dce_z;
+	} else {
+		diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
+		zero = tabla->mbhc_data.sta_z;
+	}
+	in = (u32) diff * vin_mv;
+
+	return (u16) (in / mb_mv) + zero;
+}
+
+static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
+				 u16 bias_value)
+{
+	struct tabla_priv *tabla;
+	s32 mv;
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+
+	if (dce) {
+		mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
+		     (s32)tabla->mbhc_data.micb_mv /
+		     (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
+	} else {
+		mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
+		     (s32)tabla->mbhc_data.micb_mv /
+		     (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
+	}
+
+	return mv;
+}
+
 static void btn0_lpress_fn(struct work_struct *work)
 {
 	struct delayed_work *delayed_work;
 	struct tabla_priv *tabla;
+	short bias_value;
+	int dce_mv, sta_mv;
 
 	pr_debug("%s:\n", __func__);
 
@@ -3175,8 +3338,15 @@
 
 	if (tabla) {
 		if (tabla->button_jack) {
-			pr_debug("%s: Reporting long button press event\n",
-					__func__);
+			bias_value = tabla_codec_read_sta_result(tabla->codec);
+			sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
+						       bias_value);
+			bias_value = tabla_codec_read_dce_result(tabla->codec);
+			dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
+						       bias_value);
+			pr_debug("%s: Reporting long button press event"
+				 " STA: %d, DCE: %d\n", __func__,
+				 sta_mv, dce_mv);
 			tabla_snd_soc_jack_report(tabla, tabla->button_jack,
 						  SND_JACK_BTN_0,
 						  SND_JACK_BTN_0);
@@ -3188,9 +3358,246 @@
 	tabla_unlock_sleep(tabla);
 }
 
+void tabla_mbhc_cal(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+	u8 cfilt_mode, bg_mode;
+	u8 ncic, nmeas, navg;
+	u32 mclk_rate;
+	u32 dce_wait, sta_wait;
+	u8 *n_cic;
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+
+	/* First compute the DCE / STA wait times
+	 * depending on tunable parameters.
+	 * The value is computed in microseconds
+	 */
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
+	ncic = n_cic[0];
+	nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
+	navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
+	mclk_rate = tabla->mclk_freq;
+	dce_wait = (1000 * 512 * ncic * nmeas) / (mclk_rate / 1000);
+	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
+		dce_wait = dce_wait + 10000;
+	else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
+		dce_wait = dce_wait + 9810;
+	else
+		WARN(1, "Unsupported mclk freq %d\n", tabla->mclk_freq);
+
+	sta_wait = (1000 * 128 * navg) / (mclk_rate / 1000);
+
+	/* Add 10 microseconds to handle error margin */
+	dce_wait = dce_wait + 10;
+	sta_wait = sta_wait + 10;
+
+	tabla->mbhc_data.t_dce = dce_wait;
+	tabla->mbhc_data.t_sta = sta_wait;
+
+	/* LDOH and CFILT are already configured during pdata handling.
+	 * Only need to make sure CFILT and bandgap are in Fast mode.
+	 * Need to restore defaults once calculation is done.
+	 */
+	cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
+	bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
+				      0x02);
+
+	/* Micbias, CFILT, LDOH, MBHC MUX mode settings
+	 * to perform ADC calibration
+	 */
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
+			    tabla->micbias << 5);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
+	snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
+	snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
+
+	/* DCE measurement for 0 volts */
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
+	usleep_range(100, 100);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+	usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
+	tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
+
+	/* DCE measurment for MB voltage */
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
+	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
+	usleep_range(100, 100);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
+	usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
+	tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
+
+	/* Sta measuremnt for 0 volts */
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
+	usleep_range(100, 100);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+	usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
+	tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
+
+	/* STA Measurement for MB Voltage */
+	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
+	usleep_range(100, 100);
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
+	usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
+	tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
+
+	/* Restore default settings. */
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
+			    cfilt_mode);
+	snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
+
+	snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
+	usleep_range(100, 100);
+}
+
+void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
+				const enum tabla_mbhc_btn_det_mem mem)
+{
+	void *ret = &btn_det->_v_btn_low;
+
+	switch (mem) {
+	case TABLA_BTN_DET_GAIN:
+		ret += sizeof(btn_det->_n_cic);
+	case TABLA_BTN_DET_N_CIC:
+		ret += sizeof(btn_det->_n_ready);
+	case TABLA_BTN_DET_V_N_READY:
+		ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
+	case TABLA_BTN_DET_V_BTN_HIGH:
+		ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
+	case TABLA_BTN_DET_V_BTN_LOW:
+		/* do nothing */
+		break;
+	default:
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla;
+	s16 btn_mv = 0, btn_delta_mv;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+	struct tabla_mbhc_plug_type_cfg *plug_type;
+	u16 *btn_high;
+	int i;
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+	plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
+
+	if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
+		tabla->mbhc_data.nready = 3;
+		tabla->mbhc_data.npoll = 9;
+		tabla->mbhc_data.nbounce_wait = 30;
+	} else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
+		tabla->mbhc_data.nready = 2;
+		tabla->mbhc_data.npoll = 7;
+		tabla->mbhc_data.nbounce_wait = 23;
+	}
+
+	tabla->mbhc_data.v_ins_hu =
+	    tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
+	tabla->mbhc_data.v_ins_h =
+	    tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
+
+	btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
+	for (i = 0; i < btn_det->num_btn; i++)
+		btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
+
+	tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
+	btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
+
+	tabla->mbhc_data.v_b1_hu =
+	    tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
+
+	btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
+
+	tabla->mbhc_data.v_b1_huc =
+	    tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
+
+	tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
+	tabla->mbhc_data.v_brl = 0xFA55;
+
+	tabla->mbhc_data.v_no_mic =
+	    tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
+}
+
+void tabla_mbhc_init(struct snd_soc_codec *codec)
+{
+	struct tabla_priv *tabla;
+	struct tabla_mbhc_general_cfg *generic;
+	struct tabla_mbhc_btn_detect_cfg *btn_det;
+	int n;
+	u8 tabla_ver;
+	u8 *n_cic, *gain;
+
+	tabla = snd_soc_codec_get_drvdata(codec);
+	generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
+	btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
+
+	tabla_ver = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
+	tabla_ver &= 0x1F;
+
+	for (n = 0; n < 8; n++) {
+		if ((tabla_ver != TABLA_VERSION_1_0 &&
+		     tabla_ver != TABLA_VERSION_1_1) || n != 7) {
+			snd_soc_update_bits(codec,
+					    TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
+					    0x07, n);
+			snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
+				      btn_det->c[n]);
+		}
+	}
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
+			    btn_det->nc);
+
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
+			    n_cic[0]);
+
+	gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78, gain[0] << 3);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
+			    generic->mbhc_nsa << 4);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
+			    btn_det->n_meas);
+
+	snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
+			    btn_det->mbhc_nsc << 3);
+
+	snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x03, TABLA_MICBIAS2);
+
+	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
+}
+
 int tabla_hs_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
-	struct tabla_mbhc_calibration *calibration)
+		    struct snd_soc_jack *headset_jack,
+		    struct snd_soc_jack *button_jack,
+		    void *calibration, enum tabla_micbias_num micbias,
+		    int (*mclk_cb_fn) (struct snd_soc_codec*, int),
+		    int read_fw_bin, u32 mclk_rate)
 {
 	struct tabla_priv *tabla;
 	int rc;
@@ -3202,7 +3609,10 @@
 	tabla = snd_soc_codec_get_drvdata(codec);
 	tabla->headset_jack = headset_jack;
 	tabla->button_jack = button_jack;
+	tabla->micbias = micbias;
 	tabla->calibration = calibration;
+	tabla->mclk_cb = mclk_cb_fn;
+	tabla->mclk_freq = mclk_rate;
 	tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
 
 	/* Put CFILT in fast mode by default */
@@ -3212,7 +3622,19 @@
 	INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
 	INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
 	INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
-	rc =  tabla_codec_enable_hs_detect(codec, 1);
+
+	if (!read_fw_bin) {
+		tabla->mclk_cb(codec, 1);
+		tabla_mbhc_init(codec);
+		tabla_mbhc_cal(codec);
+		tabla_mbhc_calc_thres(codec);
+		tabla->mclk_cb(codec, 0);
+		tabla_codec_calibrate_hs_polling(codec);
+		rc =  tabla_codec_enable_hs_detect(codec, 1);
+	} else {
+		pr_err("%s: MBHC firmware read not supported\n", __func__);
+		rc = -EINVAL;
+	}
 
 	if (!IS_ERR_VALUE(rc)) {
 		snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
@@ -3238,12 +3660,14 @@
 	tabla_lock_sleep(priv);
 
 	bias_value = tabla_codec_read_dce_result(codec);
-	pr_debug("%s: button press interrupt, bias value(DCE Read)=%d\n",
-			__func__, bias_value);
+	pr_debug("%s: button press interrupt, DCE: %d,%d\n",
+		 __func__, bias_value,
+		 tabla_codec_sta_dce_v(codec, 1, bias_value));
 
 	bias_value = tabla_codec_read_sta_result(codec);
-	pr_debug("%s: button press interrupt, bias value(STA Read)=%d\n",
-			__func__, bias_value);
+	pr_debug("%s: button press interrupt, STA: %d,%d\n",
+		 __func__, bias_value,
+		 tabla_codec_sta_dce_v(codec, 0, bias_value));
 	/*
 	 * TODO: If button pressed is not button 0,
 	 * report the button press event immediately.
@@ -3265,54 +3689,44 @@
 {
 	struct tabla_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
-	int ret, mic_voltage;
+	int ret, mb_v;
 
 	pr_debug("%s\n", __func__);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 	tabla_lock_sleep(priv);
 
-	mic_voltage = tabla_codec_read_dce_result(codec);
-	pr_debug("%s: Microphone Voltage on release(DCE Read) = %d\n",
-		__func__, mic_voltage);
-
 	if (priv->buttons_pressed & SND_JACK_BTN_0) {
 		ret = cancel_delayed_work(&priv->btn0_dwork);
 
 		if (ret == 0) {
-
 			pr_debug("%s: Reporting long button release event\n",
 					__func__);
-			if (priv->button_jack) {
+			if (priv->button_jack)
 				tabla_snd_soc_jack_report(priv,
 							  priv->button_jack, 0,
 							  SND_JACK_BTN_0);
-			}
-
 		} else {
 			/* if scheduled btn0_dwork is canceled from here,
 			 * we have to unlock from here instead btn0_work */
 			tabla_unlock_sleep(priv);
-			mic_voltage =
-				tabla_codec_measure_micbias_voltage(codec, 0);
-			pr_debug("%s: Mic Voltage on release(new STA) = %d\n",
-						__func__, mic_voltage);
+			mb_v = tabla_codec_sta_dce(codec, 0);
+			pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
+				 __func__, mb_v,
+				 tabla_codec_sta_dce_v(codec, 0, mb_v));
 
-			if (mic_voltage < -2000 || mic_voltage > -670) {
+			if (mb_v < -2000 || mb_v > -670)
 				pr_debug("%s: Fake buttton press interrupt\n",
 						__func__);
-			} else {
-
-				if (priv->button_jack) {
-					pr_debug("%s:reporting short button press and release\n",
-							__func__);
-
-					tabla_snd_soc_jack_report(priv,
-							      priv->button_jack,
-						SND_JACK_BTN_0, SND_JACK_BTN_0);
-					tabla_snd_soc_jack_report(priv,
-							     priv->button_jack,
-							     0, SND_JACK_BTN_0);
-				}
+			else if (priv->button_jack) {
+				pr_debug("%s:reporting short button "
+					 "press and release\n", __func__);
+				tabla_snd_soc_jack_report(priv,
+							  priv->button_jack,
+							  SND_JACK_BTN_0,
+							  SND_JACK_BTN_0);
+				tabla_snd_soc_jack_report(priv,
+							  priv->button_jack,
+							  0, SND_JACK_BTN_0);
 			}
 		}
 
@@ -3327,7 +3741,8 @@
 static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
 {
 	struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
-	struct tabla_mbhc_calibration *calibration = tabla->calibration;
+	const struct tabla_mbhc_general_cfg *generic =
+	    TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
 
 	if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
 		tabla_codec_enable_config_mode(codec, 1);
@@ -3335,10 +3750,10 @@
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
 
-	snd_soc_update_bits(codec,
-		tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
-	usleep_range(calibration->shutdown_plug_removal,
-		calibration->shutdown_plug_removal);
+	snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
+
+	usleep_range(generic->t_shutdown_plug_rem,
+		     generic->t_shutdown_plug_rem);
 
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
 	if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
@@ -3461,13 +3876,14 @@
 {
 	struct tabla_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
+	const struct tabla_mbhc_plug_detect_cfg *plug_det =
+	    TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
 	int ldo_h_on, micb_cfilt_on;
-	short mic_voltage;
-	short threshold_no_mic = 0xF7F6;
-	short threshold_fake_insert = 0xFD30;
+	short mb_v;
 	u8 is_removal;
+	int mic_mv;
 
-	pr_debug("%s\n", __func__);
+	pr_debug("%s: enter\n", __func__);
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 	tabla_lock_sleep(priv);
 
@@ -3475,38 +3891,40 @@
 	snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
 
 	/* Turn off both HPH and MIC line schmitt triggers */
-	snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
-			0x90, 0x00);
+	snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
 	snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
 
-	if (priv->fake_insert_context) {
+	if (priv->mbhc_fake_ins_start &&
+	    time_after(jiffies, priv->mbhc_fake_ins_start +
+		       msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
 		pr_debug("%s: fake context interrupt, reset insertion\n",
-			__func__);
-		priv->fake_insert_context = false;
+			 __func__);
+		priv->mbhc_fake_ins_start = 0;
 		tabla_codec_shutdown_hs_polling(codec);
 		tabla_codec_enable_hs_detect(codec, 1);
 		return IRQ_HANDLED;
 	}
 
-
 	ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
-	micb_cfilt_on = snd_soc_read(codec,
-					priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
+	micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
+			    & 0x80;
 
 	if (!ldo_h_on)
 		snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
 	if (!micb_cfilt_on)
 		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
-							0x80, 0x80);
-
-	usleep_range(priv->calibration->setup_plug_removal_delay,
-		priv->calibration->setup_plug_removal_delay);
+				    0x80, 0x80);
+	if (plug_det->t_ins_complete > 20)
+		msleep(plug_det->t_ins_complete);
+	else
+		usleep_range(plug_det->t_ins_complete * 1000,
+			     plug_det->t_ins_complete * 1000);
 
 	if (!ldo_h_on)
 		snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
 	if (!micb_cfilt_on)
 		snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
-							0x80, 0x0);
+				    0x80, 0x0);
 
 	if (is_removal) {
 		/*
@@ -3543,37 +3961,56 @@
 		return IRQ_HANDLED;
 	}
 
-	mic_voltage = tabla_codec_setup_hs_polling(codec);
+	mb_v = tabla_codec_setup_hs_polling(codec);
+	mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
 
-	if (mic_voltage > threshold_fake_insert) {
-		pr_debug("%s: Fake insertion interrupt, mic_voltage = %x\n",
-			__func__, mic_voltage);
-
-		/* Disable HPH trigger and enable MIC line trigger */
-		snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
-
-		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
-			priv->calibration->mic_current << 5);
-		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
-			0x80, 0x80);
-		usleep_range(priv->calibration->mic_pid,
-			priv->calibration->mic_pid);
-		snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
-			0x10, 0x10);
-
+	if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
+		pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
+			 "STA : %d,%d\n", __func__,
+			 (priv->mbhc_fake_ins_start ?
+			     jiffies_to_msecs(jiffies -
+					      priv->mbhc_fake_ins_start) :
+			     0),
+			 mb_v, mic_mv);
+		if (time_after(jiffies,
+			       priv->mbhc_fake_ins_start +
+			       msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
+			/* Disable HPH trigger and enable MIC line trigger */
+			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
+					    0x00);
+			snd_soc_update_bits(codec,
+					    priv->mbhc_bias_regs.mbhc_reg, 0x60,
+					    plug_det->mic_current << 5);
+			snd_soc_update_bits(codec,
+					    priv->mbhc_bias_regs.mbhc_reg,
+					    0x80, 0x80);
+			usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
+			snd_soc_update_bits(codec,
+					    priv->mbhc_bias_regs.mbhc_reg,
+					    0x10, 0x10);
+		} else {
+			if (priv->mbhc_fake_ins_start == 0)
+				priv->mbhc_fake_ins_start = jiffies;
+			/* Setup normal insert detection
+			 * Enable HPH Schmitt Trigger
+			 */
+			snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
+					    0x13 | 0x0C,
+					    0x13 | plug_det->hph_current << 2);
+		}
 		/* Setup for insertion detection */
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
-		priv->fake_insert_context = true;
 		tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
 		snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
 
-	} else if (mic_voltage < threshold_no_mic) {
-		pr_debug("%s: Headphone Detected, mic_voltage = %x\n",
-			__func__, mic_voltage);
+	} else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
+		pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
+			 __func__, mb_v, mic_mv);
+		priv->mbhc_fake_ins_start = 0;
 		priv->hph_status |= SND_JACK_HEADPHONE;
 		if (priv->headset_jack) {
 			pr_debug("%s: Reporting insertion %d\n", __func__,
-				SND_JACK_HEADPHONE);
+				 SND_JACK_HEADPHONE);
 			tabla_snd_soc_jack_report(priv, priv->headset_jack,
 						  priv->hph_status,
 						  TABLA_JACK_MASK);
@@ -3582,16 +4019,19 @@
 		tabla_codec_enable_hs_detect(codec, 0);
 		tabla_sync_hph_state(priv);
 	} else {
-		pr_debug("%s: Headset detected, mic_voltage = %x\n",
-			__func__, mic_voltage);
+		pr_debug("%s: Headset detected, mb_v: %d,%d\n",
+			__func__, mb_v, mic_mv);
+		priv->mbhc_fake_ins_start = 0;
 		priv->hph_status |= SND_JACK_HEADSET;
 		if (priv->headset_jack) {
 			pr_debug("%s: Reporting insertion %d\n", __func__,
-				SND_JACK_HEADSET);
+				 SND_JACK_HEADSET);
 			tabla_snd_soc_jack_report(priv, priv->headset_jack,
 						  priv->hph_status,
 						  TABLA_JACK_MASK);
 		}
+		/* avoid false button press detect */
+		msleep(50);
 		tabla_codec_start_hs_polling(codec);
 		tabla_sync_hph_state(priv);
 	}
@@ -3604,6 +4044,8 @@
 {
 	struct tabla_priv *priv = data;
 	struct snd_soc_codec *codec = priv->codec;
+	const struct tabla_mbhc_general_cfg *generic =
+	    TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
 	short bias_value;
 
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
@@ -3611,13 +4053,14 @@
 	tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
 	tabla_lock_sleep(priv);
 
-	usleep_range(priv->calibration->shutdown_plug_removal,
-		priv->calibration->shutdown_plug_removal);
+	usleep_range(generic->t_shutdown_plug_rem,
+		     generic->t_shutdown_plug_rem);
 
-	bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
-	pr_debug("removal interrupt, bias value is %d\n", bias_value);
+	bias_value = tabla_codec_sta_dce(codec, 1);
+	pr_debug("removal interrupt, DCE: %d,%d\n",
+		 bias_value, tabla_codec_sta_dce_v(codec, 1, bias_value));
 
-	if (bias_value < -90) {
+	if (bias_value < (short) priv->mbhc_data.v_ins_h) {
 		pr_debug("False alarm, headset not actually removed\n");
 		tabla_codec_start_hs_polling(codec);
 	} else {
@@ -3940,6 +4383,11 @@
 	tabla->cfilt_k_value = 0;
 	tabla->mbhc_micbias_switched = false;
 
+	/* Make sure mbhc intenal calibration data is zeroed out */
+	memset(&tabla->mbhc_data, 0,
+		sizeof(struct mbhc_internal_cal_data));
+	tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
+	tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
 	snd_soc_codec_set_drvdata(codec, tabla);
 
 	tabla->mclk_enabled = false;
@@ -3947,7 +4395,7 @@
 	tabla->clock_active = false;
 	tabla->config_mode_active = false;
 	tabla->mbhc_polling_active = false;
-	tabla->fake_insert_context = false;
+	tabla->mbhc_fake_ins_start = 0;
 	tabla->no_mic_headset_override = false;
 	tabla->codec = codec;
 	tabla->pdata = dev_get_platdata(codec->dev->parent);
@@ -3981,7 +4429,8 @@
 	snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
 
 	tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
-	pr_info("%s : Tabla version reg 0x%2x\n", __func__, (u32)tabla_version);
+	pr_info("%s : Tabla version reg 0x%2x\n", __func__,
+			(u32)tabla_version);
 
 	tabla_version &=  0x1F;
 	pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 32fc48f..66c3e39 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.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
@@ -9,7 +9,6 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
-
 #include <sound/soc.h>
 
 #define TABLA_VERSION_1_0	0
@@ -22,6 +21,13 @@
 
 #define TABLA_REG_VAL(reg, val)		{reg, 0, val}
 
+
+#define DEFAULT_DCE_WAIT 60000
+#define DEFAULT_STA_WAIT 5000
+
+#define STA 0
+#define DCE 1
+
 extern const u8 tabla_reg_readable[TABLA_CACHE_SIZE];
 extern const u8 tabla_reg_defaults[TABLA_CACHE_SIZE];
 
@@ -39,26 +45,116 @@
 	TABLA_PID_MIC_20_UA,
 };
 
-struct tabla_mbhc_calibration {
-	enum tabla_micbias_num bias;
-	int tldoh;
-	int bg_fast_settle;
-	enum tabla_pid_current mic_current;
-	int mic_pid;
-	enum tabla_pid_current hph_current;
-	int setup_plug_removal_delay;
-	int shutdown_plug_removal;
-};
-
 struct tabla_reg_mask_val {
 	u16	reg;
 	u8	mask;
 	u8	val;
 };
 
+enum tabla_mbhc_clk_freq {
+	TABLA_MCLK_12P2MHZ = 0,
+	TABLA_MCLK_9P6MHZ,
+	TABLA_NUM_CLK_FREQS,
+};
+
+enum tabla_mbhc_analog_pwr_cfg {
+	TABLA_ANALOG_PWR_COLLAPSED = 0,
+	TABLA_ANALOG_PWR_ON,
+	TABLA_NUM_ANALOG_PWR_CONFIGS,
+};
+
+enum tabla_mbhc_btn_det_mem {
+	TABLA_BTN_DET_V_BTN_LOW,
+	TABLA_BTN_DET_V_BTN_HIGH,
+	TABLA_BTN_DET_V_N_READY,
+	TABLA_BTN_DET_N_CIC,
+	TABLA_BTN_DET_GAIN
+};
+
+struct tabla_mbhc_general_cfg {
+	u8 t_ldoh;
+	u8 t_bg_fast_settle;
+	u8 t_shutdown_plug_rem;
+	u8 mbhc_nsa;
+	u8 mbhc_navg;
+	u8 v_micbias_l;
+	u8 v_micbias;
+	u8 mbhc_reserved;
+	u16 settle_wait;
+	u16 t_micbias_rampup;
+	u16 t_micbias_rampdown;
+	u16 t_supply_bringup;
+} __packed;
+
+struct tabla_mbhc_plug_detect_cfg {
+	u32 mic_current;
+	u32 hph_current;
+	u16 t_mic_pid;
+	u16 t_ins_complete;
+	u16 t_ins_retry;
+	u16 v_removal_delta;
+	u8 micbias_slow_ramp;
+	u8 reserved0;
+	u8 reserved1;
+	u8 reserved2;
+} __packed;
+
+struct tabla_mbhc_plug_type_cfg {
+	u8 av_detect;
+	u8 mono_detect;
+	u8 num_ins_tries;
+	u8 reserved0;
+	s16 v_no_mic;
+	s16 v_av_min;
+	s16 v_av_max;
+	s16 v_hs_min;
+	s16 v_hs_max;
+	u16 reserved1;
+} __packed;
+
+
+struct tabla_mbhc_btn_detect_cfg {
+	s8 c[8];
+	u8 nc;
+	u8 n_meas;
+	u8 mbhc_nsc;
+	u8 n_btn_meas;
+	u8 n_btn_con;
+	u8 num_btn;
+	u8 reserved0;
+	u8 reserved1;
+	u16 t_poll;
+	u16 t_bounce_wait;
+	u16 t_rel_timeout;
+	s16 v_btn_press_delta_sta;
+	s16 v_btn_press_delta_cic;
+	u16 t_btn0_timeout;
+	s16 _v_btn_low[0]; /* v_btn_low[num_btn] */
+	s16 _v_btn_high[0]; /* v_btn_high[num_btn] */
+	u8 _n_ready[TABLA_NUM_CLK_FREQS];
+	u8 _n_cic[TABLA_NUM_CLK_FREQS];
+	u8 _gain[TABLA_NUM_CLK_FREQS];
+} __packed;
+
+struct tabla_mbhc_imped_detect_cfg {
+	u8 _hs_imped_detect;
+	u8 _n_rload;
+	u8 _hph_keep_on;
+	u8 _repeat_rload_calc;
+	u16 _t_dac_ramp_time;
+	u16 _rhph_high;
+	u16 _rhph_low;
+	u16 _rload[0]; /* rload[n_rload] */
+	u16 _alpha[0]; /* alpha[n_rload] */
+	u16 _beta[3];
+} __packed;
+
 extern int tabla_hs_detect(struct snd_soc_codec *codec,
-	struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
-	struct tabla_mbhc_calibration *calibration);
+			   struct snd_soc_jack *headset_jack,
+			   struct snd_soc_jack *button_jack,
+			   void *calibration, enum tabla_micbias_num micbis,
+			   int (*mclk_cb_fn) (struct snd_soc_codec*, int),
+			   int read_fw_bin, u32 mclk_rate);
 
 struct anc_header {
 	u32 reserved[3];
@@ -66,3 +162,38 @@
 };
 
 extern int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
+
+extern void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg
+				       *btn_det,
+				       const enum tabla_mbhc_btn_det_mem mem);
+
+#define TABLA_MBHC_CAL_SIZE(buttons, rload) ( \
+	sizeof(enum tabla_micbias_num) + \
+	sizeof(struct tabla_mbhc_general_cfg) + \
+	sizeof(struct tabla_mbhc_plug_detect_cfg) + \
+	    ((sizeof(s16) + sizeof(s16)) * buttons) + \
+	sizeof(struct tabla_mbhc_plug_type_cfg) + \
+	sizeof(struct tabla_mbhc_btn_detect_cfg) + \
+	sizeof(struct tabla_mbhc_imped_detect_cfg) + \
+	    ((sizeof(u16) + sizeof(u16)) * rload) \
+	)
+
+#define TABLA_MBHC_CAL_GENERAL_PTR(cali) ( \
+	    (struct tabla_mbhc_general_cfg *) cali)
+#define TABLA_MBHC_CAL_PLUG_DET_PTR(cali) ( \
+	    (struct tabla_mbhc_plug_detect_cfg *) \
+	    &(TABLA_MBHC_CAL_GENERAL_PTR(cali)[1]))
+#define TABLA_MBHC_CAL_PLUG_TYPE_PTR(cali) ( \
+	    (struct tabla_mbhc_plug_type_cfg *) \
+	    &(TABLA_MBHC_CAL_PLUG_DET_PTR(cali)[1]))
+#define TABLA_MBHC_CAL_BTN_DET_PTR(cali) ( \
+	    (struct tabla_mbhc_btn_detect_cfg *) \
+	    &(TABLA_MBHC_CAL_PLUG_TYPE_PTR(cali)[1]))
+#define TABLA_MBHC_CAL_IMPED_DET_PTR(cali) ( \
+	    (struct tabla_mbhc_imped_detect_cfg *) \
+	    (((void *)&TABLA_MBHC_CAL_BTN_DET_PTR(cali)[1]) + \
+	     (TABLA_MBHC_CAL_BTN_DET_PTR(cali)->num_btn * \
+	      (sizeof(TABLA_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_low[0]) + \
+	       sizeof(TABLA_MBHC_CAL_BTN_DET_PTR(cali)->_v_btn_high[0])))) \
+	)
+
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index 870bd20..bd41e0b 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -52,6 +53,11 @@
 #define GPIO_AUX_PCM_SYNC 45
 #define GPIO_AUX_PCM_CLK 46
 
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 3
+#define TABLA_MBHC_DEF_RLOADS 5
+
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
 static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
 static int msm_spk_control;
@@ -63,17 +69,6 @@
 static int msm_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm_btsco_ch = 1;
 
-struct tabla_mbhc_calibration tabla_calib = {
-	.bias = TABLA_MICBIAS2,
-	.tldoh = 100,
-	.bg_fast_settle = 100,
-	.mic_current = TABLA_PID_MIC_5_UA,
-	.mic_pid = 100,
-	.hph_current = TABLA_PID_MIC_5_UA,
-	.setup_plug_removal_delay = 1000000,
-	.shutdown_plug_removal = 100000,
-};
-
 static struct clk *codec_clk;
 static int clk_users;
 
@@ -82,6 +77,8 @@
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
+static void *tabla_mbhc_cal;
+
 static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
 {
 	int ret = 0;
@@ -303,6 +300,42 @@
 	return 0;
 }
 
+int msm_enable_codec_ext_clk(
+		struct snd_soc_codec *codec, int enable)
+{
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	if (enable) {
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users != 1)
+			return 0;
+
+		codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+		if (codec_clk) {
+			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+			clk_enable(codec_clk);
+			tabla_mclk_enable(codec, 1);
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+	} else {
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users == 0)
+			return 0;
+		clk_users--;
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					 __func__, clk_users);
+			clk_disable(codec_clk);
+			clk_put(codec_clk);
+			tabla_mclk_enable(codec, 0);
+		}
+	}
+	return 0;
+}
+
 static int msm_mclk_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
 {
@@ -570,6 +603,74 @@
 	return 0;
 }
 
+static void *def_tabla_mbhc_cal(void)
+{
+	void *tabla_cal;
+	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_cic, *gain;
+
+	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+						TABLA_MBHC_DEF_RLOADS),
+			    GFP_KERNEL);
+	if (!tabla_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 4);
+	S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+	S(mic_current, TABLA_PID_MIC_5_UA);
+	S(hph_current, TABLA_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 1000);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 1450);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+	S(c[0], 6);
+	S(c[1], 10);
+	S(c[2], 10);
+	S(c[3], 14);
+	S(c[4], 14);
+	S(c[5], 16);
+	S(c[6], 0);
+	S(c[7], 0);
+	S(nc, 5);
+	S(n_meas, 11);
+	S(mbhc_nsc, 11);
+	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
+	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
+	btn_low[0] = 0;
+	btn_high[0] = 40;
+	btn_low[1] = 60;
+	btn_high[1] = 140;
+	btn_low[2] = 160;
+	btn_high[2] = 240;
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+	n_cic[0] = 120;
+	n_cic[1] = 94;
+	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 9;
+
+	return tabla_cal;
+}
+
 static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -618,7 +719,9 @@
 		return err;
 	}
 
-	tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_calib);
+	tabla_hs_detect(codec, &hs_jack, &button_jack, tabla_mbhc_cal,
+			TABLA_MICBIAS2, msm_enable_codec_ext_clk, 0,
+			TABLA_EXT_CLK_RATE);
 
 	return 0;
 }
@@ -1122,9 +1225,16 @@
 		return -ENODEV;
 	}
 
+	tabla_mbhc_cal = def_tabla_mbhc_cal();
+	if (!tabla_mbhc_cal) {
+		pr_err("Calibration data allocation failed\n");
+		return -ENOMEM;
+	}
+
 	msm_snd_device = platform_device_alloc("soc-audio", 0);
 	if (!msm_snd_device) {
 		pr_err("Platform device allocation failed\n");
+		kfree(tabla_mbhc_cal);
 		return -ENOMEM;
 	}
 
@@ -1132,6 +1242,7 @@
 	ret = platform_device_add(msm_snd_device);
 	if (ret) {
 		platform_device_put(msm_snd_device);
+		kfree(tabla_mbhc_cal);
 		return ret;
 	}
 
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index b2adf5d..96260ab 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.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
@@ -237,26 +237,49 @@
 {
 	struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
 	u8 pgd_la, inf_la;
+	u16 *slave_port_mapping;
 
 	memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
 		sizeof(dai_data->port_config.slimbus.slave_port_mapping));
 
 	dai_data->channels = params_channels(params);
+
+	slave_port_mapping = dai_data->port_config.slimbus.slave_port_mapping;
+
 	switch (dai_data->channels) {
+	case 4:
+		if (dai->id == SLIMBUS_0_TX) {
+			slave_port_mapping[0] = 7;
+			slave_port_mapping[1] = 8;
+			slave_port_mapping[2] = 9;
+			slave_port_mapping[3] = 10;
+		} else {
+			return -EINVAL;
+		}
+		break;
+	case 3:
+		if (dai->id == SLIMBUS_0_TX) {
+			slave_port_mapping[0] = 7;
+			slave_port_mapping[1] = 8;
+			slave_port_mapping[2] = 9;
+		} else {
+			return -EINVAL;
+		}
+		break;
 	case 2:
 		if (dai->id == SLIMBUS_0_RX) {
-			dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
-			dai_data->port_config.slimbus.slave_port_mapping[1] = 2;
+			slave_port_mapping[0] = 1;
+			slave_port_mapping[1] = 2;
 		} else {
-			dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
-			dai_data->port_config.slimbus.slave_port_mapping[1] = 8;
+			slave_port_mapping[0] = 7;
+			slave_port_mapping[1] = 8;
 		}
 		break;
 	case 1:
 		if (dai->id == SLIMBUS_0_RX)
-			dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
+			slave_port_mapping[0] = 1;
 		else
-			dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
+			slave_port_mapping[0] = 7;
 		break;
 	default:
 		return -EINVAL;
@@ -829,7 +852,7 @@
 		SNDRV_PCM_RATE_16000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		.channels_min = 1,
-		.channels_max = 2,
+		.channels_max = 4,
 		.rate_min =     8000,
 		.rate_max =	48000,
 	},
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index 738e024..ed880e8 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.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
@@ -39,6 +39,11 @@
 	struct snd_pcm *pcm;
 };
 
+#define PLAYBACK_NUM_PERIODS	8
+#define PLAYBACK_PERIOD_SIZE	2048
+#define CAPTURE_NUM_PERIODS	16
+#define CAPTURE_PERIOD_SIZE	320
+
 static struct snd_pcm_hardware msm_pcm_hardware_capture = {
 	.info =                 (SNDRV_PCM_INFO_MMAP |
 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -51,11 +56,11 @@
 	.rate_max =             48000,
 	.channels_min =         1,
 	.channels_max =         2,
-	.buffer_bytes_max =     320 * 8,
-	.period_bytes_min =	320,
-	.period_bytes_max =     320,
-	.periods_min =          8,
-	.periods_max =          8,
+	.buffer_bytes_max =     CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
+	.period_bytes_min =	CAPTURE_PERIOD_SIZE,
+	.period_bytes_max =     CAPTURE_PERIOD_SIZE,
+	.periods_min =          CAPTURE_NUM_PERIODS,
+	.periods_max =          CAPTURE_NUM_PERIODS,
 	.fifo_size =            0,
 };
 
@@ -71,11 +76,11 @@
 	.rate_max =             48000,
 	.channels_min =         1,
 	.channels_max =         2,
-	.buffer_bytes_max =     2048 * 8,
-	.period_bytes_min =	2048,
-	.period_bytes_max =     2048,
-	.periods_min =          8,
-	.periods_max =          8,
+	.buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
+	.period_bytes_min =	PLAYBACK_PERIOD_SIZE,
+	.period_bytes_max =     PLAYBACK_PERIOD_SIZE,
+	.periods_min =          PLAYBACK_NUM_PERIODS,
+	.periods_max =          PLAYBACK_NUM_PERIODS,
 	.fifo_size =            0,
 };
 
@@ -84,7 +89,7 @@
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
 };
 
-static uint32_t in_frame_info[8][2];
+static uint32_t in_frame_info[CAPTURE_NUM_PERIODS][2];
 
 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
 	.count = ARRAY_SIZE(supported_sample_rates),
diff --git a/sound/soc/msm/msm-pcm-voice.c b/sound/soc/msm/msm-pcm-voice.c
index 5b50509..eafe0f9 100644
--- a/sound/soc/msm/msm-pcm-voice.c
+++ b/sound/soc/msm/msm-pcm-voice.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
@@ -270,8 +270,8 @@
 
 	pr_debug("%s: st enable=%d\n", __func__, st_enable);
 
-	voc_set_slowtalk_enable(voc_get_session_id(VOICE_SESSION_NAME),
-				st_enable);
+	voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+			MODULE_ID_VOICE_MODULE_ST, st_enable);
 
 	return 0;
 }
@@ -280,7 +280,30 @@
 			struct snd_ctl_elem_value *ucontrol)
 {
 	ucontrol->value.integer.value[0] =
-		voc_get_slowtalk_enable(voc_get_session_id(VOICE_SESSION_NAME));
+		voc_get_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+				MODULE_ID_VOICE_MODULE_ST);
+	return 0;
+}
+
+static int msm_voice_fens_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	int fens_enable = ucontrol->value.integer.value[0];
+
+	pr_debug("%s: fens enable=%d\n", __func__, fens_enable);
+
+	voc_set_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+			MODULE_ID_VOICE_MODULE_FENS, fens_enable);
+
+	return 0;
+}
+
+static int msm_voice_fens_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] =
+		voc_get_pp_enable(voc_get_session_id(VOICE_SESSION_NAME),
+				MODULE_ID_VOICE_MODULE_FENS);
 	return 0;
 }
 
@@ -295,6 +318,8 @@
 			msm_voice_widevoice_get, msm_voice_widevoice_put),
 	SOC_SINGLE_EXT("Slowtalk Enable", SND_SOC_NOPM, 0, 1, 0,
 				msm_voice_slowtalk_get, msm_voice_slowtalk_put),
+	SOC_SINGLE_EXT("FENS Enable", SND_SOC_NOPM, 0, 1, 0,
+				msm_voice_fens_get, msm_voice_fens_put),
 };
 
 static struct snd_pcm_ops msm_pcm_ops = {
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 2e98627..60fa5f3 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
@@ -17,6 +17,7 @@
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/soc-dapm.h>
@@ -52,6 +53,11 @@
 #define GPIO_AUX_PCM_SYNC 65
 #define GPIO_AUX_PCM_CLK 66
 
+#define TABLA_EXT_CLK_RATE 12288000
+
+#define TABLA_MBHC_DEF_BUTTONS 3
+#define TABLA_MBHC_DEF_RLOADS 5
+
 static u32 top_spk_pamp_gpio  = PM8921_GPIO_PM_TO_SYS(18);
 static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
 static int msm8960_spk_control;
@@ -63,17 +69,6 @@
 static int msm8960_btsco_rate = BTSCO_RATE_8KHZ;
 static int msm8960_btsco_ch = 1;
 
-struct tabla_mbhc_calibration tabla_cal = {
-	.bias = TABLA_MICBIAS2,
-	.tldoh = 100,
-	.bg_fast_settle = 100,
-	.mic_current = TABLA_PID_MIC_5_UA,
-	.mic_pid = 100,
-	.hph_current = TABLA_PID_MIC_5_UA,
-	.setup_plug_removal_delay = 1000000,
-	.shutdown_plug_removal = 100000,
-};
-
 static struct clk *codec_clk;
 static int clk_users;
 
@@ -82,6 +77,8 @@
 static struct snd_soc_jack hs_jack;
 static struct snd_soc_jack button_jack;
 
+static void *tabla_mbhc_cal;
+
 static void msm8960_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
 {
 	int ret = 0;
@@ -302,6 +299,41 @@
 	}
 	return 0;
 }
+int msm8960_enable_codec_ext_clk(
+		struct snd_soc_codec *codec, int enable)
+{
+	pr_debug("%s: enable = %d\n", __func__, enable);
+	if (enable) {
+		clk_users++;
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users != 1)
+			return 0;
+
+		codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+		if (codec_clk) {
+			clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
+			clk_enable(codec_clk);
+			tabla_mclk_enable(codec, 1);
+		} else {
+			pr_err("%s: Error setting Tabla MCLK\n", __func__);
+			clk_users--;
+			return -EINVAL;
+		}
+	} else {
+		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+		if (clk_users == 0)
+			return 0;
+		clk_users--;
+		if (!clk_users) {
+			pr_debug("%s: disabling MCLK. clk_users = %d\n",
+					 __func__, clk_users);
+			clk_disable(codec_clk);
+			clk_put(codec_clk);
+			tabla_mclk_enable(codec, 0);
+		}
+	}
+	return 0;
+}
 
 static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
 		struct snd_kcontrol *kcontrol, int event)
@@ -310,43 +342,9 @@
 
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
-
-		clk_users++;
-		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
-
-		if (clk_users != 1)
-			return 0;
-
-		codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
-		if (codec_clk) {
-			clk_set_rate(codec_clk, 12288000);
-			clk_enable(codec_clk);
-			tabla_mclk_enable(w->codec, 1);
-
-		} else {
-			pr_err("%s: Error setting Tabla MCLK\n", __func__);
-			clk_users--;
-			return -EINVAL;
-		}
-		break;
+		return msm8960_enable_codec_ext_clk(w->codec, 1);
 	case SND_SOC_DAPM_POST_PMD:
-
-		pr_debug("%s: clk_users = %d\n", __func__, clk_users);
-
-		if (clk_users == 0)
-			return 0;
-
-		clk_users--;
-
-		if (!clk_users) {
-			pr_debug("%s: disabling MCLK. clk_users = %d\n",
-					__func__, clk_users);
-
-			clk_disable(codec_clk);
-			clk_put(codec_clk);
-			tabla_mclk_enable(w->codec, 0);
-		}
-		break;
+		return msm8960_enable_codec_ext_clk(w->codec, 0);
 	}
 	return 0;
 }
@@ -481,7 +479,7 @@
 	struct snd_ctl_elem_value *ucontrol)
 {
 	pr_debug("%s: msm8960_slim_0_rx_ch  = %d\n", __func__,
-			msm8960_slim_0_rx_ch);
+		 msm8960_slim_0_rx_ch);
 	ucontrol->value.integer.value[0] = msm8960_slim_0_rx_ch - 1;
 	return 0;
 }
@@ -492,7 +490,7 @@
 	msm8960_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
 
 	pr_debug("%s: msm8960_slim_0_rx_ch = %d\n", __func__,
-			msm8960_slim_0_rx_ch);
+		 msm8960_slim_0_rx_ch);
 	return 1;
 }
 
@@ -500,7 +498,7 @@
 	struct snd_ctl_elem_value *ucontrol)
 {
 	pr_debug("%s: msm8960_slim_0_tx_ch  = %d\n", __func__,
-			msm8960_slim_0_tx_ch);
+		 msm8960_slim_0_tx_ch);
 	ucontrol->value.integer.value[0] = msm8960_slim_0_tx_ch - 1;
 	return 0;
 }
@@ -511,15 +509,14 @@
 	msm8960_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
 
 	pr_debug("%s: msm8960_slim_0_tx_ch = %d\n", __func__,
-			msm8960_slim_0_tx_ch);
+		 msm8960_slim_0_tx_ch);
 	return 1;
 }
 
 static int msm8960_btsco_rate_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
-	pr_debug("%s: msm8960_btsco_rate  = %d", __func__,
-					msm8960_btsco_rate);
+	pr_debug("%s: msm8960_btsco_rate  = %d", __func__, msm8960_btsco_rate);
 	ucontrol->value.integer.value[0] = msm8960_btsco_rate;
 	return 0;
 }
@@ -538,8 +535,7 @@
 		msm8960_btsco_rate = BTSCO_RATE_8KHZ;
 		break;
 	}
-	pr_debug("%s: msm8960_btsco_rate = %d\n", __func__,
-					msm8960_btsco_rate);
+	pr_debug("%s: msm8960_btsco_rate = %d\n", __func__, msm8960_btsco_rate);
 	return 0;
 }
 
@@ -570,6 +566,74 @@
 	return 0;
 }
 
+static void *def_tabla_mbhc_cal(void)
+{
+	void *tabla_cal;
+	struct tabla_mbhc_btn_detect_cfg *btn_cfg;
+	u16 *btn_low, *btn_high;
+	u8 *n_cic, *gain;
+
+	tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
+						TABLA_MBHC_DEF_RLOADS),
+			    GFP_KERNEL);
+	if (!tabla_cal) {
+		pr_err("%s: out of memory\n", __func__);
+		return NULL;
+	}
+
+#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
+	S(t_ldoh, 100);
+	S(t_bg_fast_settle, 100);
+	S(t_shutdown_plug_rem, 255);
+	S(mbhc_nsa, 4);
+	S(mbhc_navg, 4);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
+	S(mic_current, TABLA_PID_MIC_5_UA);
+	S(hph_current, TABLA_PID_MIC_5_UA);
+	S(t_mic_pid, 100);
+	S(t_ins_complete, 250);
+	S(t_ins_retry, 200);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
+	S(v_no_mic, 30);
+	S(v_hs_max, 1450);
+#undef S
+#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
+	S(c[0], 6);
+	S(c[1], 10);
+	S(c[2], 10);
+	S(c[3], 14);
+	S(c[4], 14);
+	S(c[5], 16);
+	S(c[6], 0);
+	S(c[7], 0);
+	S(nc, 5);
+	S(n_meas, 11);
+	S(mbhc_nsc, 11);
+	S(num_btn, TABLA_MBHC_DEF_BUTTONS);
+	S(v_btn_press_delta_sta, 100);
+	S(v_btn_press_delta_cic, 50);
+#undef S
+	btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
+	btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
+	btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
+	btn_low[0] = 0;
+	btn_high[0] = 40;
+	btn_low[1] = 60;
+	btn_high[1] = 140;
+	btn_low[2] = 160;
+	btn_high[2] = 240;
+	n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
+	n_cic[0] = 120;
+	n_cic[1] = 94;
+	gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
+	gain[0] = 11;
+	gain[1] = 9;
+
+	return tabla_cal;
+}
+
 static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
 {
 	int err;
@@ -618,7 +682,9 @@
 		return err;
 	}
 
-	tabla_hs_detect(codec, &hs_jack, &button_jack, &tabla_cal);
+	tabla_hs_detect(codec, &hs_jack, &button_jack, tabla_mbhc_cal,
+			TABLA_MICBIAS2, msm8960_enable_codec_ext_clk, 0,
+			TABLA_EXT_CLK_RATE);
 
 	return 0;
 }
@@ -702,6 +768,21 @@
 	return 0;
 }
 
+static int msm8960_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_interval *rate = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_RATE);
+
+	struct snd_interval *channels = hw_param_interval(params,
+					SNDRV_PCM_HW_PARAM_CHANNELS);
+
+	rate->min = rate->max = 48000;
+	channels->min = channels->max = 2;
+
+	return 0;
+}
+
 static int msm8960_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 					struct snd_pcm_hw_params *params)
 {
@@ -1012,7 +1093,7 @@
 		.no_pcm = 1,
 		.no_codec = 1,
 		.be_id = MSM_BACKEND_DAI_HDMI_RX,
-		.be_hw_params_fixup = msm8960_be_hw_params_fixup,
+		.be_hw_params_fixup = msm8960_hdmi_be_hw_params_fixup,
 	},
 	/* Backend AFE DAI Links */
 	{
@@ -1169,9 +1250,17 @@
 		pr_err("%s: Not the right machine type\n", __func__);
 		return -ENODEV ;
 	}
+
+	tabla_mbhc_cal = def_tabla_mbhc_cal();
+	if (!tabla_mbhc_cal) {
+		pr_err("Calibration data allocation failed\n");
+		return -ENOMEM;
+	}
+
 	msm8960_snd_device = platform_device_alloc("soc-audio", 0);
 	if (!msm8960_snd_device) {
 		pr_err("Platform device allocation failed\n");
+		kfree(tabla_mbhc_cal);
 		return -ENOMEM;
 	}
 
@@ -1179,6 +1268,7 @@
 	ret = platform_device_add(msm8960_snd_device);
 	if (ret) {
 		platform_device_put(msm8960_snd_device);
+		kfree(tabla_mbhc_cal);
 		return ret;
 	}
 
@@ -1201,6 +1291,7 @@
 	}
 	msm8960_free_headset_mic_gpios();
 	platform_device_unregister(msm8960_snd_device);
+	kfree(tabla_mbhc_cal);
 }
 module_exit(msm8960_audio_exit);
 
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index 68cb2b4..18dfc01 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.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
@@ -40,6 +40,9 @@
 	wait_queue_head_t wait;
 };
 
+static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
+static struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
+
 static struct adm_ctl			this_adm;
 
 static int32_t adm_callback(struct apr_client_data *data, void *priv)
@@ -130,7 +133,7 @@
 	return 0;
 }
 
-int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
 {
 	s32				result = 0;
 	struct adm_set_params_command	adm_params;
@@ -186,8 +189,9 @@
 	return result;
 }
 
-void send_adm_cal(int port_id, int path)
+static void send_adm_cal(int port_id, int path)
 {
+	int			result = 0;
 	s32			acdb_path;
 	struct acdb_cal_block	aud_cal;
 
@@ -198,20 +202,58 @@
 
 	pr_debug("%s: Sending audproc cal\n", __func__);
 	get_audproc_cal(acdb_path, &aud_cal);
+
+	/* map & cache buffers used */
+	if ((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+		(aud_cal.cal_size > 0)) {
+		if (mem_addr_audproc[acdb_path].cal_paddr != 0)
+			adm_memory_unmap_regions(
+				&mem_addr_audproc[acdb_path].cal_paddr,
+				&mem_addr_audproc[acdb_path].cal_size, 1);
+
+		result = adm_memory_map_regions(&aud_cal.cal_paddr, 0,
+					&aud_cal.cal_size, 1);
+		if (result < 0)
+			pr_err("ADM audproc mmap did not work! path = %d, "
+				"addr = 0x%x, size = %d\n", acdb_path,
+				aud_cal.cal_paddr, aud_cal.cal_size);
+		else
+			mem_addr_audproc[acdb_path] = aud_cal;
+	}
+
 	if (!send_adm_cal_block(port_id, &aud_cal))
-		pr_info("%s: Audproc cal sent for port id: %d, path %d\n",
+		pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
 			__func__, port_id, acdb_path);
 	else
-		pr_info("%s: Audproc cal not sent for port id: %d, path %d\n",
+		pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
 			__func__, port_id, acdb_path);
 
 	pr_debug("%s: Sending audvol cal\n", __func__);
 	get_audvol_cal(acdb_path, &aud_cal);
+
+	/* map & cache buffers used */
+	if ((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+		(aud_cal.cal_size > 0)) {
+		if (mem_addr_audvol[acdb_path].cal_paddr != 0)
+			adm_memory_unmap_regions(
+				&mem_addr_audvol[acdb_path].cal_paddr,
+				&mem_addr_audvol[acdb_path].cal_size, 1);
+
+		result = adm_memory_map_regions(&aud_cal.cal_paddr, 0,
+					&aud_cal.cal_size, 1);
+		if (result < 0)
+			pr_err("ADM audvol mmap did not work! path = %d, "
+				"addr = 0x%x, size = %d\n", acdb_path,
+				aud_cal.cal_paddr, aud_cal.cal_size);
+		else
+			mem_addr_audvol[acdb_path] = aud_cal;
+	}
+
 	if (!send_adm_cal_block(port_id, &aud_cal))
-		pr_info("%s: Audvol cal sent for port id: %d, path %d\n",
+		pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
 			__func__, port_id, acdb_path);
 	else
-		pr_info("%s: Audvol cal not sent for port id: %d, path %d\n",
+		pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
 			__func__, port_id, acdb_path);
 }
 
diff --git a/sound/soc/msm/qdsp6/q6voice.c b/sound/soc/msm/qdsp6/q6voice.c
index de63fa0..2acf59e 100644
--- a/sound/soc/msm/qdsp6/q6voice.c
+++ b/sound/soc/msm/qdsp6/q6voice.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
@@ -52,8 +52,8 @@
 static int voice_send_cvp_register_vol_cal_table_cmd(struct voice_data *v);
 static int voice_send_cvp_deregister_vol_cal_table_cmd(struct voice_data *v);
 static int voice_send_set_widevoice_enable_cmd(struct voice_data *v);
-static int voice_send_set_slowtalk_enable_cmd(struct voice_data *v);
-
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+					uint32_t module_id, int enable);
 static int voice_cvs_stop_playback(struct voice_data *v);
 static int voice_cvs_start_playback(struct voice_data *v);
 static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode);
@@ -1764,9 +1764,10 @@
 	return -EINVAL;
 }
 
-static int voice_send_set_slowtalk_enable_cmd(struct voice_data *v)
+static int voice_send_set_pp_enable_cmd(struct voice_data *v,
+					uint32_t module_id, int enable)
 {
-	struct cvs_set_slowtalk_enable_cmd cvs_set_st_cmd;
+	struct cvs_set_pp_enable_cmd cvs_set_pp_cmd;
 	int ret = 0;
 	void *apr_cvs;
 	u16 cvs_handle;
@@ -1784,24 +1785,26 @@
 	cvs_handle = voice_get_cvs_handle(v);
 
 	/* fill in the header */
-	cvs_set_st_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+	cvs_set_pp_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
 				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
-	cvs_set_st_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
-				sizeof(cvs_set_st_cmd) - APR_HDR_SIZE);
-	cvs_set_st_cmd.hdr.src_port = v->session_id;
-	cvs_set_st_cmd.hdr.dest_port = cvs_handle;
-	cvs_set_st_cmd.hdr.token = 0;
-	cvs_set_st_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
+	cvs_set_pp_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_set_pp_cmd) - APR_HDR_SIZE);
+	cvs_set_pp_cmd.hdr.src_port = v->session_id;
+	cvs_set_pp_cmd.hdr.dest_port = cvs_handle;
+	cvs_set_pp_cmd.hdr.token = 0;
+	cvs_set_pp_cmd.hdr.opcode = VSS_ICOMMON_CMD_SET_UI_PROPERTY;
 
-	cvs_set_st_cmd.vss_set_st.module_id = MODULE_ID_VOICE_MODULE_ST;
-	cvs_set_st_cmd.vss_set_st.param_id = VOICE_PARAM_MOD_ENABLE;
-	cvs_set_st_cmd.vss_set_st.param_size = MOD_ENABLE_PARAM_LEN;
-	cvs_set_st_cmd.vss_set_st.reserved = 0;
-	cvs_set_st_cmd.vss_set_st.enable = v->st_enable;
-	cvs_set_st_cmd.vss_set_st.reserved_field = 0;
+	cvs_set_pp_cmd.vss_set_pp.module_id = module_id;
+	cvs_set_pp_cmd.vss_set_pp.param_id = VOICE_PARAM_MOD_ENABLE;
+	cvs_set_pp_cmd.vss_set_pp.param_size = MOD_ENABLE_PARAM_LEN;
+	cvs_set_pp_cmd.vss_set_pp.reserved = 0;
+	cvs_set_pp_cmd.vss_set_pp.enable = enable;
+	cvs_set_pp_cmd.vss_set_pp.reserved_field = 0;
+	pr_debug("voice_send_set_pp_enable_cmd, module_id=%d, enable=%d\n",
+		module_id, enable);
 
 	v->cvs_state = CMD_STATUS_FAIL;
-	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_st_cmd);
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_pp_cmd);
 	if (ret < 0) {
 		pr_err("Fail: sending cvs set slowtalk enable,\n");
 		goto fail;
@@ -1918,7 +1921,11 @@
 
 	/* enable slowtalk if st_enable is set */
 	if (v->st_enable)
-		voice_send_set_slowtalk_enable_cmd(v);
+		voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_ST,
+					v->st_enable);
+	if (v->fens_enable)
+		voice_send_set_pp_enable_cmd(v, MODULE_ID_VOICE_MODULE_FENS,
+					v->fens_enable);
 
 	if (is_voip_session(v->session_id))
 		voice_send_netid_timing_cmd(v);
@@ -2836,7 +2843,14 @@
 
 		/* enable slowtalk */
 		if (v->st_enable)
-			voice_send_set_slowtalk_enable_cmd(v);
+			voice_send_set_pp_enable_cmd(v,
+						MODULE_ID_VOICE_MODULE_ST,
+						v->st_enable);
+		/* enable FENS */
+		if (v->fens_enable)
+			voice_send_set_pp_enable_cmd(v,
+						MODULE_ID_VOICE_MODULE_FENS,
+						v->fens_enable);
 
 		get_sidetone_cal(&sidetone_cal_data);
 		if (v->dev_tx.port_id != RT_PROXY_PORT_001_TX &&
@@ -2973,7 +2987,7 @@
 	return ret;
 }
 
-int voc_set_slowtalk_enable(uint16_t session_id, uint32_t st_enable)
+int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable)
 {
 	struct voice_data *v = voice_get_session(session_id);
 	int ret = 0;
@@ -2985,18 +2999,27 @@
 	}
 
 	mutex_lock(&v->lock);
+	if (module_id == MODULE_ID_VOICE_MODULE_ST)
+		v->st_enable = enable;
+	else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
+		v->fens_enable = enable;
 
-	v->st_enable = st_enable;
-
-	if (v->voc_state == VOC_RUN)
-		ret = voice_send_set_slowtalk_enable_cmd(v);
-
+	if (v->voc_state == VOC_RUN) {
+		if (module_id == MODULE_ID_VOICE_MODULE_ST)
+			ret = voice_send_set_pp_enable_cmd(v,
+						MODULE_ID_VOICE_MODULE_ST,
+						enable);
+		else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
+			ret = voice_send_set_pp_enable_cmd(v,
+						MODULE_ID_VOICE_MODULE_FENS,
+						enable);
+	}
 	mutex_unlock(&v->lock);
 
 	return ret;
 }
 
-uint32_t voc_get_slowtalk_enable(uint16_t session_id)
+int voc_get_pp_enable(uint16_t session_id, uint32_t module_id)
 {
 	struct voice_data *v = voice_get_session(session_id);
 	int ret = 0;
@@ -3008,8 +3031,10 @@
 	}
 
 	mutex_lock(&v->lock);
-
-	ret = v->st_enable;
+	if (module_id == MODULE_ID_VOICE_MODULE_ST)
+		ret = v->st_enable;
+	else if (module_id == MODULE_ID_VOICE_MODULE_FENS)
+		ret = v->fens_enable;
 
 	mutex_unlock(&v->lock);
 
diff --git a/sound/soc/msm/qdsp6/q6voice.h b/sound/soc/msm/qdsp6/q6voice.h
index d330ada..2dc08d6 100644
--- a/sound/soc/msm/qdsp6/q6voice.h
+++ b/sound/soc/msm/qdsp6/q6voice.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
@@ -323,6 +323,7 @@
 #define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE		0x0001101D
 /* Set encoder DTX mode. */
 
+#define MODULE_ID_VOICE_MODULE_FENS			0x00010EEB
 #define MODULE_ID_VOICE_MODULE_ST			0x00010EE3
 #define VOICE_PARAM_MOD_ENABLE				0x00010E00
 #define MOD_ENABLE_PARAM_LEN				4
@@ -501,7 +502,7 @@
 	/* Size of the calibration data in bytes. */
 };
 
-struct vss_icommon_cmd_set_ui_property_st_enable_t {
+struct vss_icommon_cmd_set_ui_property_enable_t {
 	uint32_t module_id;
 	/* Unique ID of the module. */
 	uint32_t param_id;
@@ -573,9 +574,9 @@
 	struct apr_hdr hdr;
 } __packed;
 
-struct cvs_set_slowtalk_enable_cmd {
+struct cvs_set_pp_enable_cmd {
 	struct apr_hdr hdr;
-	struct vss_icommon_cmd_set_ui_property_st_enable_t vss_set_st;
+	struct vss_icommon_cmd_set_ui_property_enable_t vss_set_pp;
 } __packed;
 struct cvs_start_record_cmd {
 	struct apr_hdr hdr;
@@ -832,6 +833,8 @@
 	uint8_t wv_enable;
 	/* slowtalk enable value */
 	uint32_t st_enable;
+	/* FENC enable value */
+	uint32_t fens_enable;
 
 	struct voice_dev_route_state voc_route_state;
 
@@ -886,8 +889,8 @@
 };
 
 /* called  by alsa driver */
-int voc_set_slowtalk_enable(uint16_t session_id, uint32_t st_enable);
-uint32_t voc_get_slowtalk_enable(uint16_t session_id);
+int voc_set_pp_enable(uint16_t session_id, uint32_t module_id, uint32_t enable);
+int voc_get_pp_enable(uint16_t session_id, uint32_t module_id);
 int voc_set_widevoice_enable(uint16_t session_id, uint32_t wv_enable);
 uint32_t voc_get_widevoice_enable(uint16_t session_id);
 uint8_t voc_get_tty_mode(uint16_t session_id);
diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c
index 706954b..6d4f178 100644
--- a/sound/soc/soc-dsp.c
+++ b/sound/soc/soc-dsp.c
@@ -176,6 +176,12 @@
 	if (!paths)
 		goto out;
 
+	if (list == NULL) {
+		pr_err("%s:Widget list is not configured. paths=%d",
+		__func__, paths);
+		goto out;
+	}
+
 	/* find BE DAI widgets and and connect the to FE */
 	for (i = 0; i < list->num_widgets; i++) {
 
@@ -497,6 +503,7 @@
 			dsp_params->fe->dai_link->name);
 
 		soc_pcm_close(be_substream);
+		dsp_params->be->dsp[stream].hwparam_set = false;
 		be_substream->runtime = NULL;
 	}
 	return 0;
@@ -551,7 +558,8 @@
 			continue;
 
 		/* first time the dsp_params is open ? */
-		if (dsp_params->be->dsp[stream].users != 1)
+		if ((dsp_params->be->dsp[stream].users != 1) &&
+		    (dsp_params->be->dsp[stream].hwparam_set == true))
 			continue;
 
 		dev_dbg(&dsp_params->be->dev, "dsp: hw_params BE %s\n",
@@ -577,6 +585,7 @@
 			dev_err(&dsp_params->be->dev, "dsp: hw_params BE failed %d\n", ret);
 			return ret;
 		}
+		dsp_params->be->dsp[stream].hwparam_set = true;
 	}
 	return 0;
 }
@@ -852,6 +861,7 @@
 			dsp_params->fe->dai_link->name);
 
 		soc_pcm_hw_free(be_substream);
+		dsp_params->be->dsp[stream].hwparam_set = false;
 	}
 
 	return 0;