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 ⪚ 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 & 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 (&querymenu, 0, sizeof (querymenu));
+ querymenu.id = queryctrl.id;
+
+ for (querymenu.index = queryctrl.minimum;
+ querymenu.index <= queryctrl.maximum;
+ querymenu.index++) {
+ if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &querymenu)) {
+ printf (" %s\n", querymenu.name);
+ }
+ }
+}
+
+memset (&queryctrl, 0, sizeof (queryctrl));
+
+for (queryctrl.id = V4L2_CID_BASE;
+ queryctrl.id < V4L2_CID_LASTP1;
+ queryctrl.id++) {
+ if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (queryctrl.flags & 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;, &queryctrl)) {
+ if (queryctrl.flags & 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 (&queryctrl, 0, sizeof (queryctrl));
+queryctrl.id = V4L2_CID_BRIGHTNESS;
+
+if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (errno != EINVAL) {
+ perror ("VIDIOC_QUERYCTRL");
+ exit (EXIT_FAILURE);
+ } else {
+ printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+ }
+} else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
+ printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+} else {
+ memset (&control, 0, sizeof (control));
+ control.id = V4L2_CID_BRIGHTNESS;
+ control.value = queryctrl.default_value;
+
+ if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &control)) {
+ perror ("VIDIOC_S_CTRL");
+ exit (EXIT_FAILURE);
+ }
+}
+
+memset (&control, 0, sizeof (control));
+control.id = V4L2_CID_CONTRAST;
+
+if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &control)) {
+ control.value += 1;
+
+ /* The driver may clamp the value or return ERANGE, ignored here */
+
+ if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &control)
+ && 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, &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;, &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;, &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 (⪚ <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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>MPEG-2 program stream</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_TS</constant> </entry>
+ <entry>MPEG-2 transport stream</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_SS</constant> </entry>
+ <entry>MPEG-1 system stream</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_DVD</constant> </entry>
+ <entry>MPEG-2 DVD-compatible stream</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG1_VCD</constant> </entry>
+ <entry>MPEG-1 VCD-compatible stream</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD</constant> </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> </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> </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> </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> </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> </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> </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> </entry>
+ <entry>enum v4l2_mpeg_stream_vbi_fmt</entry>
+ </row><row><entry spanname="descr">Some cards can embed
+VBI data (⪚ 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> </entry>
+ <entry>No VBI in the MPEG stream</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_STREAM_VBI_FMT_IVTV</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>44.1 kHz</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000</constant> </entry>
+ <entry>48 kHz</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>MPEG-1/2 Layer I encoding</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_2</constant> </entry>
+ <entry>MPEG-1/2 Layer II encoding</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_ENCODING_LAYER_3</constant> </entry>
+ <entry>MPEG-1/2 Layer III encoding</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AAC</constant> </entry>
+ <entry>MPEG-2/4 AAC (Advanced Audio Coding)</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_ENCODING_AC3</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>32 kbit/s</entry></row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_64K</constant> </entry>
+ <entry>64 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_96K</constant> </entry>
+ <entry>96 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_128K</constant> </entry>
+ <entry>128 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_160K</constant> </entry>
+ <entry>160 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_192K</constant> </entry>
+ <entry>192 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_224K</constant> </entry>
+ <entry>224 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_256K</constant> </entry>
+ <entry>256 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_288K</constant> </entry>
+ <entry>288 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_320K</constant> </entry>
+ <entry>320 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_352K</constant> </entry>
+ <entry>352 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_384K</constant> </entry>
+ <entry>384 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_416K</constant> </entry>
+ <entry>416 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L1_BITRATE_448K</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>32 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_48K</constant> </entry>
+ <entry>48 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_56K</constant> </entry>
+ <entry>56 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_64K</constant> </entry>
+ <entry>64 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_80K</constant> </entry>
+ <entry>80 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_96K</constant> </entry>
+ <entry>96 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_112K</constant> </entry>
+ <entry>112 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_128K</constant> </entry>
+ <entry>128 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_160K</constant> </entry>
+ <entry>160 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_192K</constant> </entry>
+ <entry>192 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_224K</constant> </entry>
+ <entry>224 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_256K</constant> </entry>
+ <entry>256 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_320K</constant> </entry>
+ <entry>320 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L2_BITRATE_384K</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>32 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_40K</constant> </entry>
+ <entry>40 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_48K</constant> </entry>
+ <entry>48 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_56K</constant> </entry>
+ <entry>56 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_64K</constant> </entry>
+ <entry>64 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_80K</constant> </entry>
+ <entry>80 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_96K</constant> </entry>
+ <entry>96 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_112K</constant> </entry>
+ <entry>112 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_128K</constant> </entry>
+ <entry>128 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_160K</constant> </entry>
+ <entry>160 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_192K</constant> </entry>
+ <entry>192 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_224K</constant> </entry>
+ <entry>224 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_256K</constant> </entry>
+ <entry>256 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_L3_BITRATE_320K</constant> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>32 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_40K</constant> </entry>
+ <entry>40 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_48K</constant> </entry>
+ <entry>48 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_56K</constant> </entry>
+ <entry>56 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_64K</constant> </entry>
+ <entry>64 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_80K</constant> </entry>
+ <entry>80 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_96K</constant> </entry>
+ <entry>96 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_112K</constant> </entry>
+ <entry>112 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_128K</constant> </entry>
+ <entry>128 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_160K</constant> </entry>
+ <entry>160 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_192K</constant> </entry>
+ <entry>192 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_224K</constant> </entry>
+ <entry>224 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_256K</constant> </entry>
+ <entry>256 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_320K</constant> </entry>
+ <entry>320 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_384K</constant> </entry>
+ <entry>384 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_448K</constant> </entry>
+ <entry>448 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_512K</constant> </entry>
+ <entry>512 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_576K</constant> </entry>
+ <entry>576 kbit/s</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_AC3_BITRATE_640K</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Stereo</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_MODE_JOINT_STEREO</constant> </entry>
+ <entry>Joint Stereo</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_MODE_DUAL</constant> </entry>
+ <entry>Bilingual</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_MODE_MONO</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Subbands 4-31 in intensity stereo</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8</constant> </entry>
+ <entry>Subbands 8-31 in intensity stereo</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12</constant> </entry>
+ <entry>Subbands 12-31 in intensity stereo</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>None</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS</constant> </entry>
+ <entry>50/15 microsecond emphasis</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>None</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_AUDIO_CRC_CRC16</constant> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>MPEG-1 Video encoding</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_2</constant> </entry>
+ <entry>MPEG-2 Video encoding</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_ASPECT_4x3</constant> </entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_ASPECT_16x9</constant> </entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_ASPECT_221x100</constant> </entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_B_FRAMES</constant> </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> </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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Variable bitrate</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_BITRATE_MODE_CBR</constant> </entry>
+ <entry>Constant bitrate</entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_BITRATE</constant> </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> </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> </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> </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> </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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Unspecified</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1</constant> </entry>
+ <entry>1x1</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11</constant> </entry>
+ <entry>12x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11</constant> </entry>
+ <entry>10x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11</constant> </entry>
+ <entry>16x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33</constant> </entry>
+ <entry>40x33</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11</constant> </entry>
+ <entry>24x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11</constant> </entry>
+ <entry>20x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11</constant> </entry>
+ <entry>32x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33</constant> </entry>
+ <entry>80x33</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11</constant> </entry>
+ <entry>18x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11</constant> </entry>
+ <entry>15x11</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33</constant> </entry>
+ <entry>64x33</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99</constant> </entry>
+ <entry>160x99</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3</constant> </entry>
+ <entry>4x3</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2</constant> </entry>
+ <entry>3x2</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1</constant> </entry>
+ <entry>2x1</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED</constant> </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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Level 1.0</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1B</constant> </entry>
+ <entry>Level 1B</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_1</constant> </entry>
+ <entry>Level 1.1</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_2</constant> </entry>
+ <entry>Level 1.2</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_1_3</constant> </entry>
+ <entry>Level 1.3</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_0</constant> </entry>
+ <entry>Level 2.0</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_1</constant> </entry>
+ <entry>Level 2.1</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_2_2</constant> </entry>
+ <entry>Level 2.2</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_0</constant> </entry>
+ <entry>Level 3.0</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_1</constant> </entry>
+ <entry>Level 3.1</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_3_2</constant> </entry>
+ <entry>Level 3.2</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_0</constant> </entry>
+ <entry>Level 4.0</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_1</constant> </entry>
+ <entry>Level 4.1</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_4_2</constant> </entry>
+ <entry>Level 4.2</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_0</constant> </entry>
+ <entry>Level 5.0</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LEVEL_5_1</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Level 0</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_LEVEL_0B</constant> </entry>
+ <entry>Level 0b</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_LEVEL_1</constant> </entry>
+ <entry>Level 1</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_LEVEL_2</constant> </entry>
+ <entry>Level 2</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3</constant> </entry>
+ <entry>Level 3</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_LEVEL_3B</constant> </entry>
+ <entry>Level 3b</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_LEVEL_4</constant> </entry>
+ <entry>Level 4</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_LEVEL_5</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Baseline profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE</constant> </entry>
+ <entry>Constrained Baseline profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MAIN</constant> </entry>
+ <entry>Main profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED</constant> </entry>
+ <entry>Extended profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH</constant> </entry>
+ <entry>High profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10</constant> </entry>
+ <entry>High 10 profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422</constant> </entry>
+ <entry>High 422 profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE</constant> </entry>
+ <entry>High 444 Predictive profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA</constant> </entry>
+ <entry>High 10 Intra profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA</constant> </entry>
+ <entry>High 422 Intra profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA</constant> </entry>
+ <entry>High 444 Intra profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA</constant> </entry>
+ <entry>CAVLC 444 Intra profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE</constant> </entry>
+ <entry>Scalable Baseline profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH</constant> </entry>
+ <entry>Scalable High profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA</constant> </entry>
+ <entry>Scalable High Intra profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH</constant> </entry>
+ <entry>Stereo High profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Simple profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_SIMPLE</constant> </entry>
+ <entry>Advanced Simple profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_PROFILE_CORE</constant> </entry>
+ <entry>Core profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_PROFILE_SIMPLE_SCALABLE</constant> </entry>
+ <entry>Simple Scalable profile</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_PROFILE_ADVANCED_CODING_EFFICIENCY</constant> </entry>
+ <entry></entry>
+ </row>
+ </tbody>
+ </entrytbl>
+ </row>
+
+ <row><entry></entry></row>
+ <row>
+ <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MAX_REF_PIC</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Single slice per frame.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB</constant> </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> </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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Loop filter is enabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED</constant> </entry>
+ <entry>Loop filter is disabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY</constant> </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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Use CAVLC entropy coding.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC</constant> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </entry>
+ <entry>enum 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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Frame skip mode is disabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_MFC51_FRAME_SKIP_MODE_LEVEL_LIMIT</constant> </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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Forcing a specific frame type disabled.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_I_FRAME</constant> </entry>
+ <entry>Force an I-frame.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_MFC51_FORCE_FRAME_TYPE_NOT_CODED</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Choose the filter manually</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO</constant> </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> </entry>
+ <entry>integer (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> </entry>
+ <entry>enum 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> </entry>
+ <entry>No filter</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR</constant> </entry>
+ <entry>One-dimensional horizontal</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT</constant> </entry>
+ <entry>One-dimensional vertical</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE</constant> </entry>
+ <entry>Two-dimensional separable</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>No filter</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR</constant> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Choose the filter manually</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO</constant> </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> </entry>
+ <entry>integer (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> </entry>
+ <entry>enum 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> </entry>
+ <entry>No filter</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR</constant> </entry>
+ <entry>Horizontal filter</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT</constant> </entry>
+ <entry>Vertical filter</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT</constant> </entry>
+ <entry>Horizontal and vertical filter</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG</constant> </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> </entry>
+ <entry>integer (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> </entry>
+ <entry>integer (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> </entry>
+ <entry>integer (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> </entry>
+ <entry>integer (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> </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> </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> </entry>
+ <entry>enum 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> </entry>
+ <entry>Automatic exposure time, automatic iris
+aperture.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_MANUAL</constant> </entry>
+ <entry>Manual exposure time, manual iris.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_SHUTTER_PRIORITY</constant> </entry>
+ <entry>Manual exposure time, auto iris.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_EXPOSURE_APERTURE_PRIORITY</constant> </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> </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 µ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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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 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> </entry>
+ <entry>No pre-emphasis is applied.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_PREEMPHASIS_50_uS</constant> </entry>
+ <entry>A pre-emphasis of 50 uS is used.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_PREEMPHASIS_75_uS</constant> </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> </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> </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;